Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function getPluginStatus(parsed: ParsedPluginSource): PluginStatus {
// Check if cached
const cachePath =
parsed.owner && parsed.repo
? getPluginCachePath(parsed.owner, parsed.repo)
? getPluginCachePath(parsed.owner, parsed.repo, parsed.branch)
: '';
const available = cachePath ? existsSync(cachePath) : false;

Expand Down
2 changes: 2 additions & 0 deletions src/utils/plugin-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface ParsedPluginSource {
normalized: string;
owner?: string;
repo?: string;
branch?: string;
}

/**
Expand Down Expand Up @@ -282,6 +283,7 @@ export function parsePluginSource(
normalized: source,
...(parsed?.owner && { owner: parsed.owner }),
...(parsed?.repo && { repo: parsed.repo }),
...(parsed?.branch && { branch: parsed.branch }),
};
}

Expand Down
33 changes: 33 additions & 0 deletions tests/unit/core/status-both-scopes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,37 @@ describe('workspace status - both scopes', () => {

await rm(separateHome, { recursive: true, force: true });
});

it('should mark GitHub plugin as cached when cache is branch-qualified', async () => {
// Regression: `skills add <github-blob-url>` clones into `<owner>-<repo>@<branch>`,
// but `workspace status` looked up `<owner>-<repo>` and reported "not cached".
const homeDir = await mkdtemp(join(tmpdir(), 'allagents-status-home-'));
process.env.HOME = homeDir;

const branchedCache = join(
homeDir,
'.allagents',
'plugins',
'marketplaces',
'NousResearch-hermes-agent@main',
);
await mkdir(branchedCache, { recursive: true });

await writeProjectConfig({
repositories: [],
plugins: [
'https://github.com/NousResearch/hermes-agent/blob/main/skills/research/llm-wiki',
],
clients: ['claude'],
});

const result = await getWorkspaceStatus(testDir);
expect(result.success).toBe(true);
expect(result.plugins.length).toBe(1);
expect(result.plugins[0]?.type).toBe('github');
expect(result.plugins[0]?.available).toBe(true);
expect(result.plugins[0]?.path).toBe(branchedCache);

await rm(homeDir, { recursive: true, force: true });
});
});
19 changes: 19 additions & 0 deletions tests/unit/utils/plugin-path.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,28 @@ describe('parsePluginSource', () => {
expect(result.type).toBe('github');
expect(result.owner).toBe('owner');
expect(result.repo).toBe('repo');
expect(result.branch).toBeUndefined();
expect(result.original).toBe('https://github.com/owner/repo');
});

it('should preserve branch from /blob/ URLs so the cache lookup is branch-qualified', () => {
const result = parsePluginSource(
'https://github.com/owner/repo/blob/main/skills/research/llm-wiki',
);
expect(result.type).toBe('github');
expect(result.owner).toBe('owner');
expect(result.repo).toBe('repo');
expect(result.branch).toBe('main');
});

it('should preserve branch from owner/repo@ref shorthand', () => {
const result = parsePluginSource('owner/repo@v1.2.0');
expect(result.type).toBe('github');
expect(result.owner).toBe('owner');
expect(result.repo).toBe('repo');
expect(result.branch).toBe('v1.2.0');
});

it('should parse local absolute paths', () => {
const result = parsePluginSource('/absolute/path');
expect(result.type).toBe('local');
Expand Down