@planu/cli 0.44.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/license-plans.json +8 -2
- package/dist/config/registry-categories.json +20 -0
- package/dist/config/registry-stacks.json +16 -0
- package/dist/engine/spec-registry/adapter.d.ts +9 -0
- package/dist/engine/spec-registry/adapter.d.ts.map +1 -0
- package/dist/engine/spec-registry/adapter.js +303 -0
- package/dist/engine/spec-registry/adapter.js.map +1 -0
- package/dist/engine/spec-registry/client.d.ts +8 -0
- package/dist/engine/spec-registry/client.d.ts.map +1 -0
- package/dist/engine/spec-registry/client.js +194 -0
- package/dist/engine/spec-registry/client.js.map +1 -0
- package/dist/engine/spec-registry/index.d.ts +7 -0
- package/dist/engine/spec-registry/index.d.ts.map +1 -0
- package/dist/engine/spec-registry/index.js +7 -0
- package/dist/engine/spec-registry/index.js.map +1 -0
- package/dist/engine/spec-registry/packager.d.ts +24 -0
- package/dist/engine/spec-registry/packager.d.ts.map +1 -0
- package/dist/engine/spec-registry/packager.js +122 -0
- package/dist/engine/spec-registry/packager.js.map +1 -0
- package/dist/engine/spec-registry/scorer.d.ts +10 -0
- package/dist/engine/spec-registry/scorer.d.ts.map +1 -0
- package/dist/engine/spec-registry/scorer.js +151 -0
- package/dist/engine/spec-registry/scorer.js.map +1 -0
- package/dist/engine/spec-registry/validator.d.ts +11 -0
- package/dist/engine/spec-registry/validator.d.ts.map +1 -0
- package/dist/engine/spec-registry/validator.js +144 -0
- package/dist/engine/spec-registry/validator.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/register-spec-registry-tools.d.ts +3 -0
- package/dist/tools/register-spec-registry-tools.d.ts.map +1 -0
- package/dist/tools/register-spec-registry-tools.js +91 -0
- package/dist/tools/register-spec-registry-tools.js.map +1 -0
- package/dist/tools/registry/auth.d.ts +17 -0
- package/dist/tools/registry/auth.d.ts.map +1 -0
- package/dist/tools/registry/auth.js +132 -0
- package/dist/tools/registry/auth.js.map +1 -0
- package/dist/tools/registry/index.d.ts +5 -0
- package/dist/tools/registry/index.d.ts.map +1 -0
- package/dist/tools/registry/index.js +6 -0
- package/dist/tools/registry/index.js.map +1 -0
- package/dist/tools/registry/install.d.ts +7 -0
- package/dist/tools/registry/install.d.ts.map +1 -0
- package/dist/tools/registry/install.js +125 -0
- package/dist/tools/registry/install.js.map +1 -0
- package/dist/tools/registry/publish.d.ts +7 -0
- package/dist/tools/registry/publish.d.ts.map +1 -0
- package/dist/tools/registry/publish.js +96 -0
- package/dist/tools/registry/publish.js.map +1 -0
- package/dist/tools/registry/search.d.ts +7 -0
- package/dist/tools/registry/search.d.ts.map +1 -0
- package/dist/tools/registry/search.js +79 -0
- package/dist/tools/registry/search.js.map +1 -0
- package/dist/tools/schemas/index.d.ts +1 -0
- package/dist/tools/schemas/index.d.ts.map +1 -1
- package/dist/tools/schemas/index.js +1 -0
- package/dist/tools/schemas/index.js.map +1 -1
- package/dist/tools/schemas/spec-registry-schemas.d.ts +39 -0
- package/dist/tools/schemas/spec-registry-schemas.d.ts.map +1 -0
- package/dist/tools/schemas/spec-registry-schemas.js +72 -0
- package/dist/tools/schemas/spec-registry-schemas.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/spec-registry.d.ts +194 -0
- package/dist/types/spec-registry.d.ts.map +1 -0
- package/dist/types/spec-registry.js +3 -0
- package/dist/types/spec-registry.js.map +1 -0
- package/package.json +1 -1
- package/src/config/license-plans.json +8 -2
- package/src/config/registry-categories.json +20 -0
- package/src/config/registry-stacks.json +16 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// tools/register-spec-registry-tools.ts — Registers SPEC-127 spec registry tools
|
|
2
|
+
// registry_search, registry_install: free tier (safeTracked)
|
|
3
|
+
// registry_publish, registry_login, registry_logout, registry_whoami: pro tier (safeLicensed)
|
|
4
|
+
import { safeTracked, safeLicensed } from './safe-handler.js';
|
|
5
|
+
import { RegistrySearchInputSchema, RegistryInstallInputSchema, RegistryPublishInputSchema, RegistryLoginInputSchema, } from './schemas/spec-registry-schemas.js';
|
|
6
|
+
import { handleRegistrySearch, handleRegistryInstall, handleRegistryPublish, handleRegistryLogin, handleRegistryLogout, handleRegistryWhoami, } from './registry/index.js';
|
|
7
|
+
export function registerSpecRegistryTools(server) {
|
|
8
|
+
// registry_search (free)
|
|
9
|
+
server.registerTool('registry_search', {
|
|
10
|
+
description: 'Search the Planu spec registry for reusable specs. ' +
|
|
11
|
+
'Filter by stack, category, difficulty, and sort by downloads, rating, or recency. ' +
|
|
12
|
+
'Returns paginated results with spec metadata.',
|
|
13
|
+
inputSchema: {
|
|
14
|
+
query: RegistrySearchInputSchema.shape.query,
|
|
15
|
+
stack: RegistrySearchInputSchema.shape.stack,
|
|
16
|
+
category: RegistrySearchInputSchema.shape.category,
|
|
17
|
+
difficulty: RegistrySearchInputSchema.shape.difficulty,
|
|
18
|
+
sort: RegistrySearchInputSchema.shape.sort,
|
|
19
|
+
page: RegistrySearchInputSchema.shape.page,
|
|
20
|
+
limit: RegistrySearchInputSchema.shape.limit,
|
|
21
|
+
},
|
|
22
|
+
annotations: {
|
|
23
|
+
title: 'Registry Search',
|
|
24
|
+
readOnlyHint: true,
|
|
25
|
+
},
|
|
26
|
+
}, safeTracked('registry_search', async (args) => handleRegistrySearch(args)));
|
|
27
|
+
// registry_install (free)
|
|
28
|
+
server.registerTool('registry_install', {
|
|
29
|
+
description: 'Install a spec from the Planu registry into a local project. ' +
|
|
30
|
+
'Resolves the spec version, downloads assets, and optionally adapts the spec ' +
|
|
31
|
+
'to the detected project stack.',
|
|
32
|
+
inputSchema: {
|
|
33
|
+
specName: RegistryInstallInputSchema.shape.specName,
|
|
34
|
+
version: RegistryInstallInputSchema.shape.version,
|
|
35
|
+
projectPath: RegistryInstallInputSchema.shape.projectPath,
|
|
36
|
+
adapt: RegistryInstallInputSchema.shape.adapt,
|
|
37
|
+
},
|
|
38
|
+
annotations: {
|
|
39
|
+
title: 'Registry Install',
|
|
40
|
+
destructiveHint: false,
|
|
41
|
+
},
|
|
42
|
+
}, safeTracked('registry_install', async (args) => handleRegistryInstall(args)));
|
|
43
|
+
// registry_publish (pro)
|
|
44
|
+
server.registerTool('registry_publish', {
|
|
45
|
+
description: 'Publish a spec to the Planu registry. ' +
|
|
46
|
+
'Requires authentication via registry_login. ' +
|
|
47
|
+
'Reads planu-registry.json from the spec directory for metadata.',
|
|
48
|
+
inputSchema: {
|
|
49
|
+
specDir: RegistryPublishInputSchema.shape.specDir,
|
|
50
|
+
projectPath: RegistryPublishInputSchema.shape.projectPath,
|
|
51
|
+
},
|
|
52
|
+
annotations: {
|
|
53
|
+
title: 'Registry Publish',
|
|
54
|
+
destructiveHint: false,
|
|
55
|
+
},
|
|
56
|
+
}, safeLicensed('registry_publish', async (args) => handleRegistryPublish(args)));
|
|
57
|
+
// registry_login (pro)
|
|
58
|
+
server.registerTool('registry_login', {
|
|
59
|
+
description: 'Authenticate with the Planu spec registry using an API token. ' +
|
|
60
|
+
'Token is obtained from planu.dev account settings. ' +
|
|
61
|
+
'Credentials are stored locally for subsequent publish operations.',
|
|
62
|
+
inputSchema: {
|
|
63
|
+
token: RegistryLoginInputSchema.shape.token,
|
|
64
|
+
},
|
|
65
|
+
annotations: {
|
|
66
|
+
title: 'Registry Login',
|
|
67
|
+
readOnlyHint: false,
|
|
68
|
+
},
|
|
69
|
+
}, safeLicensed('registry_login', async (args) => handleRegistryLogin(args)));
|
|
70
|
+
// registry_logout (pro)
|
|
71
|
+
server.registerTool('registry_logout', {
|
|
72
|
+
description: 'Remove stored registry credentials. ' +
|
|
73
|
+
'After logout, registry_login is required again before publishing.',
|
|
74
|
+
inputSchema: {},
|
|
75
|
+
annotations: {
|
|
76
|
+
title: 'Registry Logout',
|
|
77
|
+
destructiveHint: true,
|
|
78
|
+
},
|
|
79
|
+
}, safeLicensed('registry_logout', async (args) => handleRegistryLogout(args)));
|
|
80
|
+
// registry_whoami (pro)
|
|
81
|
+
server.registerTool('registry_whoami', {
|
|
82
|
+
description: 'Show the currently authenticated registry user. ' +
|
|
83
|
+
'Returns username, email, and organization if logged in.',
|
|
84
|
+
inputSchema: {},
|
|
85
|
+
annotations: {
|
|
86
|
+
title: 'Registry Who Am I',
|
|
87
|
+
readOnlyHint: true,
|
|
88
|
+
},
|
|
89
|
+
}, safeLicensed('registry_whoami', async (args) => handleRegistryWhoami(args)));
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=register-spec-registry-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-spec-registry-tools.js","sourceRoot":"","sources":["../../src/tools/register-spec-registry-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ToolResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handle registry_login tool invocation.
|
|
4
|
+
* Stores the given token and user info to ~/.planu/credentials.json with 0o600 permissions.
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleRegistryLogin(args: Record<string, unknown>): Promise<ToolResult>;
|
|
7
|
+
/**
|
|
8
|
+
* Handle registry_logout tool invocation.
|
|
9
|
+
* Removes the credentials file.
|
|
10
|
+
*/
|
|
11
|
+
export declare function handleRegistryLogout(_args: Record<string, unknown>): Promise<ToolResult>;
|
|
12
|
+
/**
|
|
13
|
+
* Handle registry_whoami tool invocation.
|
|
14
|
+
* Reads and returns stored credentials (without the raw token).
|
|
15
|
+
*/
|
|
16
|
+
export declare function handleRegistryWhoami(_args: Record<string, unknown>): Promise<ToolResult>;
|
|
17
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/tools/registry/auth.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,sBAAsB,CAAC;AAO5E;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAoD5F;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAkC9F;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAiC9F"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// tools/registry/auth.ts — AC-8: Authentication handlers for registry
|
|
2
|
+
import { readFile, writeFile, mkdir, unlink, chmod } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
/** Path to the credentials file. */
|
|
6
|
+
function credentialsPath() {
|
|
7
|
+
return join(homedir(), '.planu', 'credentials.json');
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Handle registry_login tool invocation.
|
|
11
|
+
* Stores the given token and user info to ~/.planu/credentials.json with 0o600 permissions.
|
|
12
|
+
*/
|
|
13
|
+
export async function handleRegistryLogin(args) {
|
|
14
|
+
try {
|
|
15
|
+
const token = args.token;
|
|
16
|
+
const user = args.user;
|
|
17
|
+
const email = args.email;
|
|
18
|
+
const rawPlan = args.plan;
|
|
19
|
+
const plan = rawPlan ?? 'free';
|
|
20
|
+
const expiresAt = args.expiresAt;
|
|
21
|
+
if (!token || !user || !email) {
|
|
22
|
+
return {
|
|
23
|
+
content: [
|
|
24
|
+
{ type: 'text', text: 'Missing required fields: token, user, and email' },
|
|
25
|
+
],
|
|
26
|
+
isError: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const credentials = {
|
|
30
|
+
token,
|
|
31
|
+
user,
|
|
32
|
+
email,
|
|
33
|
+
plan,
|
|
34
|
+
expiresAt: expiresAt ?? new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
|
|
35
|
+
};
|
|
36
|
+
const credPath = credentialsPath();
|
|
37
|
+
await mkdir(join(homedir(), '.planu'), { recursive: true });
|
|
38
|
+
await writeFile(credPath, JSON.stringify(credentials, null, 2), 'utf-8');
|
|
39
|
+
await chmod(credPath, 0o600);
|
|
40
|
+
return {
|
|
41
|
+
content: [
|
|
42
|
+
{
|
|
43
|
+
type: 'text',
|
|
44
|
+
text: JSON.stringify({ success: true, user, email, plan, message: 'Logged in successfully' }, null, 2),
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
/* v8 ignore start -- unexpected runtime errors */
|
|
51
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: 'text', text: `Registry login failed: ${message}` }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
/* v8 ignore stop */
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Handle registry_logout tool invocation.
|
|
61
|
+
* Removes the credentials file.
|
|
62
|
+
*/
|
|
63
|
+
export async function handleRegistryLogout(_args) {
|
|
64
|
+
try {
|
|
65
|
+
await unlink(credentialsPath());
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: 'text',
|
|
70
|
+
text: JSON.stringify({ success: true, message: 'Logged out successfully' }, null, 2),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
/* v8 ignore start -- error branches tested via unit mocks */
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const err = error;
|
|
78
|
+
if (err.code === 'ENOENT') {
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: 'text',
|
|
83
|
+
text: JSON.stringify({ success: true, message: 'No credentials found, already logged out' }, null, 2),
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
content: [{ type: 'text', text: `Registry logout failed: ${err.message}` }],
|
|
90
|
+
isError: true,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/* v8 ignore stop */
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Handle registry_whoami tool invocation.
|
|
97
|
+
* Reads and returns stored credentials (without the raw token).
|
|
98
|
+
*/
|
|
99
|
+
export async function handleRegistryWhoami(_args) {
|
|
100
|
+
try {
|
|
101
|
+
const raw = await readFile(credentialsPath(), 'utf-8');
|
|
102
|
+
const cred = JSON.parse(raw);
|
|
103
|
+
const isExpired = new Date(cred.expiresAt) <= new Date();
|
|
104
|
+
const info = {
|
|
105
|
+
user: cred.user,
|
|
106
|
+
email: cred.email,
|
|
107
|
+
plan: cred.plan,
|
|
108
|
+
expiresAt: cred.expiresAt,
|
|
109
|
+
expired: isExpired,
|
|
110
|
+
authenticated: !isExpired,
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
content: [{ type: 'text', text: JSON.stringify(info, null, 2) }],
|
|
114
|
+
};
|
|
115
|
+
/* v8 ignore start -- error branches tested via unit mocks */
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
const err = error;
|
|
119
|
+
if (err.code === 'ENOENT') {
|
|
120
|
+
return {
|
|
121
|
+
content: [{ type: 'text', text: 'Not authenticated. Run registry_login first.' }],
|
|
122
|
+
isError: true,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
content: [{ type: 'text', text: `Registry whoami failed: ${err.message}` }],
|
|
127
|
+
isError: true,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/* v8 ignore stop */
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/tools/registry/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { handleRegistrySearch } from './search.js';
|
|
2
|
+
export { handleRegistryInstall } from './install.js';
|
|
3
|
+
export { handleRegistryPublish } from './publish.js';
|
|
4
|
+
export { handleRegistryLogin, handleRegistryLogout, handleRegistryWhoami } from './auth.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/registry/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// tools/registry/index.ts — Barrel export for registry tool handlers
|
|
2
|
+
export { handleRegistrySearch } from './search.js';
|
|
3
|
+
export { handleRegistryInstall } from './install.js';
|
|
4
|
+
export { handleRegistryPublish } from './publish.js';
|
|
5
|
+
export { handleRegistryLogin, handleRegistryLogout, handleRegistryWhoami } from './auth.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/registry/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AAErE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handle registry_install tool invocation.
|
|
4
|
+
* Downloads a spec from the registry and installs it locally.
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleRegistryInstall(args: Record<string, unknown>): Promise<ToolResult>;
|
|
7
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/tools/registry/install.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAyB,MAAM,sBAAsB,CAAC;AA0C9E;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAiF9F"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// tools/registry/install.ts — AC-6: Install a spec from the registry to local project
|
|
2
|
+
import { readdir, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { generateSpecId, slugify } from '../create-spec-helpers.js';
|
|
5
|
+
/** Scan existing specs directory to collect current spec IDs. */
|
|
6
|
+
async function collectExistingSpecIds(specsDir) {
|
|
7
|
+
try {
|
|
8
|
+
const entries = await readdir(specsDir, { withFileTypes: true });
|
|
9
|
+
return entries
|
|
10
|
+
.filter((e) => e.isDirectory() && e.name.startsWith('SPEC-'))
|
|
11
|
+
.map((e) => {
|
|
12
|
+
const match = /^(SPEC-\d+)/.exec(e.name);
|
|
13
|
+
/* v8 ignore next -- regex always matches SPEC- prefix from filter */
|
|
14
|
+
return { id: match?.[1] ?? '' };
|
|
15
|
+
})
|
|
16
|
+
.filter((s) => s.id !== '');
|
|
17
|
+
/* v8 ignore start -- directory may not exist */
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
/* v8 ignore stop */
|
|
23
|
+
}
|
|
24
|
+
/** Generate a clean progress.md for the installed spec. */
|
|
25
|
+
function generateProgressMd(specId, source, version) {
|
|
26
|
+
const now = new Date().toISOString();
|
|
27
|
+
return [
|
|
28
|
+
`# ${specId} — Progress`,
|
|
29
|
+
'',
|
|
30
|
+
`> Installed from registry: ${source}@${version}`,
|
|
31
|
+
`> Installed at: ${now}`,
|
|
32
|
+
'',
|
|
33
|
+
'## Status: pendiente',
|
|
34
|
+
'',
|
|
35
|
+
'## Acceptance Criteria',
|
|
36
|
+
'',
|
|
37
|
+
'- [ ] Review and adapt spec to local project',
|
|
38
|
+
'- [ ] Implement according to spec',
|
|
39
|
+
'- [ ] All tests passing',
|
|
40
|
+
'',
|
|
41
|
+
].join('\n');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Handle registry_install tool invocation.
|
|
45
|
+
* Downloads a spec from the registry and installs it locally.
|
|
46
|
+
*/
|
|
47
|
+
export async function handleRegistryInstall(args) {
|
|
48
|
+
try {
|
|
49
|
+
const org = args.org;
|
|
50
|
+
const name = args.name;
|
|
51
|
+
const version = args.version ?? 'latest';
|
|
52
|
+
const projectPath = args.projectPath ?? process.cwd();
|
|
53
|
+
if (!org || !name) {
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: 'text', text: 'Missing required fields: org and name' }],
|
|
56
|
+
isError: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const { createRegistryClient, unpackSpec } = await import('../../engine/spec-registry/index.js');
|
|
60
|
+
const client = createRegistryClient();
|
|
61
|
+
const tarball = await client.downloadSpec(org, name, version);
|
|
62
|
+
// Unpack to temp dir to read files
|
|
63
|
+
const tmpDir = join(projectPath, '.planu-tmp-install');
|
|
64
|
+
await mkdir(tmpDir, { recursive: true });
|
|
65
|
+
await unpackSpec(tarball, tmpDir);
|
|
66
|
+
const { readdir: rd, readFile: rf } = await import('node:fs/promises');
|
|
67
|
+
const tmpFiles = await rd(tmpDir);
|
|
68
|
+
const pkg = { files: {} };
|
|
69
|
+
for (const f of tmpFiles) {
|
|
70
|
+
pkg.files[f] = await rf(join(tmpDir, f), 'utf-8');
|
|
71
|
+
}
|
|
72
|
+
// Cleanup temp dir
|
|
73
|
+
const { rm } = await import('node:fs/promises');
|
|
74
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
75
|
+
// Determine next spec ID
|
|
76
|
+
const specsDir = join(projectPath, 'planu', 'specs');
|
|
77
|
+
const existingSpecs = await collectExistingSpecIds(specsDir);
|
|
78
|
+
const specId = generateSpecId(existingSpecs);
|
|
79
|
+
const slug = slugify(name);
|
|
80
|
+
const specDir = join(specsDir, `${specId}-${slug}`);
|
|
81
|
+
// Create spec directory
|
|
82
|
+
await mkdir(specDir, { recursive: true });
|
|
83
|
+
// Write downloaded files, injecting registry source into spec.md frontmatter
|
|
84
|
+
for (const [filePath, content] of Object.entries(pkg.files)) {
|
|
85
|
+
let finalContent = content;
|
|
86
|
+
if (filePath === 'spec.md') {
|
|
87
|
+
finalContent = injectRegistrySource(content, org, name, version);
|
|
88
|
+
}
|
|
89
|
+
await writeFile(join(specDir, filePath), finalContent, 'utf-8');
|
|
90
|
+
}
|
|
91
|
+
// Generate local progress.md
|
|
92
|
+
const source = `${org}/${name}`;
|
|
93
|
+
await writeFile(join(specDir, 'progress.md'), generateProgressMd(specId, source, version), 'utf-8');
|
|
94
|
+
const result = {
|
|
95
|
+
specId,
|
|
96
|
+
slug,
|
|
97
|
+
specDir,
|
|
98
|
+
source,
|
|
99
|
+
version,
|
|
100
|
+
adapted: false,
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
104
|
+
};
|
|
105
|
+
/* v8 ignore start -- error + helper branches */
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
109
|
+
return {
|
|
110
|
+
content: [{ type: 'text', text: `Registry install failed: ${message}` }],
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Inject registry source metadata into spec.md frontmatter. */
|
|
116
|
+
function injectRegistrySource(content, org, name, version) {
|
|
117
|
+
const frontmatterEnd = content.indexOf('\n---', 3);
|
|
118
|
+
if (frontmatterEnd === -1) {
|
|
119
|
+
return content;
|
|
120
|
+
}
|
|
121
|
+
const insertion = `\nregistry:\n source: "${org}/${name}"\n version: "${version}"`;
|
|
122
|
+
return content.slice(0, frontmatterEnd) + insertion + content.slice(frontmatterEnd);
|
|
123
|
+
}
|
|
124
|
+
/* v8 ignore stop */
|
|
125
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/tools/registry/install.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAEtF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEpE,iEAAiE;AACjE,KAAK,UAAU,sBAAsB,CAAC,QAAgB;IACpD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,OAAO,OAAO;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;aAC5D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACzC,qEAAqE;YACrE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAClC,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9B,gDAAgD;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,oBAAoB;AACtB,CAAC;AAED,2DAA2D;AAC3D,SAAS,kBAAkB,CAAC,MAAc,EAAE,MAAc,EAAE,OAAe;IACzE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO;QACL,KAAK,MAAM,aAAa;QACxB,EAAE;QACF,8BAA8B,MAAM,IAAI,OAAO,EAAE;QACjD,mBAAmB,GAAG,EAAE;QACxB,EAAE;QACF,sBAAsB;QACtB,EAAE;QACF,wBAAwB;QACxB,EAAE;QACF,8CAA8C;QAC9C,mCAAmC;QACnC,yBAAyB;QACzB,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAA6B;IACvE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAa,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAc,CAAC;QACjC,MAAM,OAAO,GAAI,IAAI,CAAC,OAA8B,IAAI,QAAQ,CAAC;QACjE,MAAM,WAAW,GAAI,IAAI,CAAC,WAAkC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAE9E,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,uCAAuC,EAAE,CAAC;gBACnF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,EAAE,oBAAoB,EAAE,UAAU,EAAE,GACxC,MAAM,MAAM,CAAC,qCAAqC,CAAC,CAAC;QAEtD,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAE9D,mCAAmC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;QACvD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,MAAM,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAClC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,GAAG,GAAsC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC7D,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,mBAAmB;QACnB,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAChD,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnD,yBAAyB;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,aAAa,GAAG,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QAEpD,wBAAwB;QACxB,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1C,6EAA6E;QAC7E,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5D,IAAI,YAAY,GAAG,OAAO,CAAC;YAC3B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,YAAY,GAAG,oBAAoB,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;QAClE,CAAC;QAED,6BAA6B;QAC7B,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QAChC,MAAM,SAAS,CACb,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EAC5B,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAC3C,OAAO,CACR,CAAC;QAEF,MAAM,MAAM,GAA0B;YACpC,MAAM;YACN,IAAI;YACJ,OAAO;YACP,MAAM;YACN,OAAO;YACP,OAAO,EAAE,KAAK;SACf,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC;QACF,gDAAgD;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,4BAA4B,OAAO,EAAE,EAAE,CAAC;YACjF,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,SAAS,oBAAoB,CAAC,OAAe,EAAE,GAAW,EAAE,IAAY,EAAE,OAAe;IACvF,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACnD,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,SAAS,GAAG,2BAA2B,GAAG,IAAI,IAAI,kBAAkB,OAAO,GAAG,CAAC;IACrF,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;AACtF,CAAC;AACD,oBAAoB"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handle registry_publish tool invocation.
|
|
4
|
+
* Validates and publishes a spec to the registry. Requires authentication.
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleRegistryPublish(args: Record<string, unknown>): Promise<ToolResult>;
|
|
7
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/tools/registry/publish.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,sBAAsB,CAAC;AAuB5E;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CA0E9F"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// tools/registry/publish.ts — AC-7: Publish a spec to the registry
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
/** Load stored credentials or return null if not authenticated. */
|
|
6
|
+
async function loadCredentials() {
|
|
7
|
+
try {
|
|
8
|
+
const credPath = join(homedir(), '.planu', 'credentials.json');
|
|
9
|
+
const raw = await readFile(credPath, 'utf-8');
|
|
10
|
+
return JSON.parse(raw);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Check that credentials are valid and not expired. */
|
|
17
|
+
/* v8 ignore start -- defensive guard, loadCredentials always provides both */
|
|
18
|
+
function isCredentialValid(cred) {
|
|
19
|
+
if (!cred.token || !cred.expiresAt) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return new Date(cred.expiresAt) > new Date();
|
|
23
|
+
}
|
|
24
|
+
/* v8 ignore stop */
|
|
25
|
+
/**
|
|
26
|
+
* Handle registry_publish tool invocation.
|
|
27
|
+
* Validates and publishes a spec to the registry. Requires authentication.
|
|
28
|
+
*/
|
|
29
|
+
export async function handleRegistryPublish(args) {
|
|
30
|
+
try {
|
|
31
|
+
// Check authentication first
|
|
32
|
+
const credentials = await loadCredentials();
|
|
33
|
+
if (!credentials) {
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: 'text',
|
|
38
|
+
text: 'Not authenticated. Run registry_login first to store credentials.',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
isError: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (!isCredentialValid(credentials)) {
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: 'text',
|
|
49
|
+
text: 'Credentials expired. Run registry_login to refresh your token.',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
isError: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const specPath = args.specPath;
|
|
56
|
+
const org = args.org ?? credentials.user;
|
|
57
|
+
if (!specPath) {
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: 'text', text: 'Missing required field: specPath' }],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const { createRegistryClient, validateForPublish, packSpec } = await import('../../engine/spec-registry/index.js');
|
|
64
|
+
// Step 1: Validate spec structure
|
|
65
|
+
const validation = await validateForPublish(specPath);
|
|
66
|
+
if (!validation.valid) {
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: 'text',
|
|
71
|
+
text: `Spec validation failed:\n${validation.errors.map((e) => ` - ${e}`).join('\n')}`,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
isError: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Step 2: Pack spec files
|
|
78
|
+
const tarball = await packSpec(specPath);
|
|
79
|
+
// Step 3: Upload to registry
|
|
80
|
+
const client = createRegistryClient(credentials.token);
|
|
81
|
+
const result = await client.publishSpec(tarball, { org });
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
/* v8 ignore start -- unexpected runtime errors */
|
|
88
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
89
|
+
return {
|
|
90
|
+
content: [{ type: 'text', text: `Registry publish failed: ${message}` }],
|
|
91
|
+
isError: true,
|
|
92
|
+
};
|
|
93
|
+
/* v8 ignore stop */
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/tools/registry/publish.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handle registry_search tool invocation.
|
|
4
|
+
* Searches the spec registry with the given filters. No authentication required.
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleRegistrySearch(args: Record<string, unknown>): Promise<ToolResult>;
|
|
7
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/tools/registry/search.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,sBAAsB,CAAC;AAyD9B;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CA8B7F"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// tools/registry/search.ts — AC-5: Search specs in the registry (no auth required)
|
|
2
|
+
/** Format a single search item for display. */
|
|
3
|
+
function formatSearchItem(item) {
|
|
4
|
+
return {
|
|
5
|
+
name: item.name,
|
|
6
|
+
description: item.description,
|
|
7
|
+
stack: item.stack,
|
|
8
|
+
difficulty: item.difficulty,
|
|
9
|
+
downloads: item.downloads,
|
|
10
|
+
rating: item.rating,
|
|
11
|
+
version: item.version,
|
|
12
|
+
category: item.category,
|
|
13
|
+
completenessScore: item.completenessScore,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Build search filters from raw tool args. */
|
|
17
|
+
/* v8 ignore start -- optional filter branches tested via integration */
|
|
18
|
+
function buildFilters(args) {
|
|
19
|
+
const filters = {};
|
|
20
|
+
if (typeof args.query === 'string') {
|
|
21
|
+
filters.query = args.query;
|
|
22
|
+
}
|
|
23
|
+
if (typeof args.stack === 'string') {
|
|
24
|
+
filters.stack = args.stack;
|
|
25
|
+
}
|
|
26
|
+
if (typeof args.category === 'string') {
|
|
27
|
+
filters.category = args.category;
|
|
28
|
+
}
|
|
29
|
+
if (typeof args.sort === 'string') {
|
|
30
|
+
filters.sort = args.sort;
|
|
31
|
+
}
|
|
32
|
+
if (typeof args.page === 'number') {
|
|
33
|
+
filters.page = args.page;
|
|
34
|
+
}
|
|
35
|
+
if (typeof args.limit === 'number') {
|
|
36
|
+
filters.limit = args.limit;
|
|
37
|
+
}
|
|
38
|
+
if (args.difficulty !== null &&
|
|
39
|
+
args.difficulty !== undefined &&
|
|
40
|
+
typeof args.difficulty === 'object') {
|
|
41
|
+
const d = args.difficulty;
|
|
42
|
+
filters.difficulty = {
|
|
43
|
+
min: typeof d.min === 'number' ? d.min : undefined,
|
|
44
|
+
max: typeof d.max === 'number' ? d.max : undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return filters;
|
|
48
|
+
}
|
|
49
|
+
/* v8 ignore stop */
|
|
50
|
+
/**
|
|
51
|
+
* Handle registry_search tool invocation.
|
|
52
|
+
* Searches the spec registry with the given filters. No authentication required.
|
|
53
|
+
*/
|
|
54
|
+
export async function handleRegistrySearch(args) {
|
|
55
|
+
try {
|
|
56
|
+
// Dynamic import — engine module may be created by another agent
|
|
57
|
+
const { createRegistryClient } = (await import('../../engine/spec-registry/index.js'));
|
|
58
|
+
const filters = buildFilters(args);
|
|
59
|
+
const client = createRegistryClient();
|
|
60
|
+
const result = await client.searchSpecs(filters);
|
|
61
|
+
const formatted = {
|
|
62
|
+
specs: result.data.map(formatSearchItem),
|
|
63
|
+
pagination: result.meta,
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: 'text', text: JSON.stringify(formatted, null, 2) }],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
/* v8 ignore start -- unexpected runtime errors */
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: 'text', text: `Registry search failed: ${message}` }],
|
|
74
|
+
isError: true,
|
|
75
|
+
};
|
|
76
|
+
/* v8 ignore stop */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/tools/registry/search.ts"],"names":[],"mappings":"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"}
|