@scanton/phase2s 1.0.0 → 1.8.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/README.md +18 -1
- package/dist/src/cli/doctor.d.ts +39 -0
- package/dist/src/cli/doctor.d.ts.map +1 -0
- package/dist/src/cli/doctor.js +244 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/goal.d.ts +38 -1
- package/dist/src/cli/goal.d.ts.map +1 -1
- package/dist/src/cli/goal.js +274 -23
- package/dist/src/cli/goal.js.map +1 -1
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +116 -9
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/init.d.ts +73 -0
- package/dist/src/cli/init.d.ts.map +1 -0
- package/dist/src/cli/init.js +366 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/lint.d.ts +32 -0
- package/dist/src/cli/lint.d.ts.map +1 -0
- package/dist/src/cli/lint.js +140 -0
- package/dist/src/cli/lint.js.map +1 -0
- package/dist/src/cli/report.d.ts +62 -0
- package/dist/src/cli/report.d.ts.map +1 -0
- package/dist/src/cli/report.js +188 -0
- package/dist/src/cli/report.js.map +1 -0
- package/dist/src/cli/upgrade.d.ts +35 -0
- package/dist/src/cli/upgrade.d.ts.map +1 -0
- package/dist/src/cli/upgrade.js +126 -0
- package/dist/src/cli/upgrade.js.map +1 -0
- package/dist/src/core/config.d.ts +60 -8
- package/dist/src/core/config.d.ts.map +1 -1
- package/dist/src/core/config.js +31 -1
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/notify.d.ts +41 -0
- package/dist/src/core/notify.d.ts.map +1 -0
- package/dist/src/core/notify.js +153 -0
- package/dist/src/core/notify.js.map +1 -0
- package/dist/src/core/run-logger.d.ts +83 -0
- package/dist/src/core/run-logger.d.ts.map +1 -0
- package/dist/src/core/run-logger.js +70 -0
- package/dist/src/core/run-logger.js.map +1 -0
- package/dist/src/core/state.d.ts +74 -0
- package/dist/src/core/state.d.ts.map +1 -0
- package/dist/src/core/state.js +132 -0
- package/dist/src/core/state.js.map +1 -0
- package/dist/src/mcp/server.d.ts +17 -0
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +243 -4
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/providers/gemini.d.ts +29 -0
- package/dist/src/providers/gemini.d.ts.map +1 -0
- package/dist/src/providers/gemini.js +47 -0
- package/dist/src/providers/gemini.js.map +1 -0
- package/dist/src/providers/index.d.ts +2 -0
- package/dist/src/providers/index.d.ts.map +1 -1
- package/dist/src/providers/index.js +8 -0
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/openrouter.d.ts +25 -0
- package/dist/src/providers/openrouter.d.ts.map +1 -0
- package/dist/src/providers/openrouter.js +43 -0
- package/dist/src/providers/openrouter.js.map +1 -0
- package/dist/src/tools/registry.d.ts +5 -3
- package/dist/src/tools/registry.d.ts.map +1 -1
- package/dist/src/tools/registry.js +35 -12
- package/dist/src/tools/registry.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { OpenAIProvider } from "./openai.js";
|
|
3
|
+
/**
|
|
4
|
+
* Google Gemini provider.
|
|
5
|
+
*
|
|
6
|
+
* Gemini exposes an OpenAI-compatible REST API at:
|
|
7
|
+
* https://generativelanguage.googleapis.com/v1beta/openai/
|
|
8
|
+
*
|
|
9
|
+
* This means we can reuse OpenAIProvider's full streaming tool-call logic
|
|
10
|
+
* — same composition pattern as OpenRouter. No additional SDK dependency.
|
|
11
|
+
*
|
|
12
|
+
* Model names are Gemini model slugs without provider prefix:
|
|
13
|
+
* gemini-2.0-flash (default), gemini-2.5-pro, gemini-1.5-pro
|
|
14
|
+
*
|
|
15
|
+
* Get an API key (including free tier) at: https://aistudio.google.com/apikey
|
|
16
|
+
* Keys start with "AIza".
|
|
17
|
+
*
|
|
18
|
+
* Set GEMINI_API_KEY environment variable or geminiApiKey in .phase2s.yaml.
|
|
19
|
+
* Optional: override base URL with geminiBaseUrl for custom endpoints.
|
|
20
|
+
*/
|
|
21
|
+
export class GeminiProvider {
|
|
22
|
+
name = "gemini";
|
|
23
|
+
inner;
|
|
24
|
+
constructor(config, client) {
|
|
25
|
+
if (!client && !config.geminiApiKey) {
|
|
26
|
+
throw new Error("Gemini API key is required for the gemini provider. " +
|
|
27
|
+
"Set GEMINI_API_KEY environment variable or geminiApiKey in .phase2s.yaml. " +
|
|
28
|
+
"Get a free key at https://aistudio.google.com/apikey");
|
|
29
|
+
}
|
|
30
|
+
// Ensure baseURL has a trailing slash — OpenAI SDK path joins require it.
|
|
31
|
+
const rawBaseURL = config.geminiBaseUrl ?? "https://generativelanguage.googleapis.com/v1beta/openai/";
|
|
32
|
+
const baseURL = rawBaseURL.endsWith("/") ? rawBaseURL : `${rawBaseURL}/`;
|
|
33
|
+
const resolvedClient = client ??
|
|
34
|
+
new OpenAI({
|
|
35
|
+
apiKey: config.geminiApiKey,
|
|
36
|
+
baseURL,
|
|
37
|
+
});
|
|
38
|
+
// OpenAIProvider is always given an already-constructed client here, so its
|
|
39
|
+
// config.apiKey validation guard (!client && !config.apiKey) never fires.
|
|
40
|
+
// Pass config as-is — no need to alias the Gemini key into the OpenAI field.
|
|
41
|
+
this.inner = new OpenAIProvider(config, resolvedClient);
|
|
42
|
+
}
|
|
43
|
+
async *chatStream(messages, tools, options) {
|
|
44
|
+
yield* this.inner.chatStream(messages, tools, options);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/providers/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAI5B,OAAO,EAAE,cAAc,EAAyB,MAAM,aAAa,CAAC;AAEpE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,cAAc;IACzB,IAAI,GAAG,QAAQ,CAAC;IACR,KAAK,CAAiB;IAE9B,YAAY,MAAc,EAAE,MAAyB;QACnD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACb,sDAAsD;gBACpD,4EAA4E;gBAC5E,sDAAsD,CACzD,CAAC;QACJ,CAAC;QAED,0EAA0E;QAC1E,MAAM,UAAU,GACd,MAAM,CAAC,aAAa,IAAI,0DAA0D,CAAC;QACrF,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC;QAEzE,MAAM,cAAc,GAClB,MAAM;YACL,IAAI,MAAM,CAAC;gBACV,MAAM,EAAE,MAAM,CAAC,YAAY;gBAC3B,OAAO;aACR,CAAiC,CAAC;QAErC,4EAA4E;QAC5E,0EAA0E;QAC1E,6EAA6E;QAC7E,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,CAAC,UAAU,CACf,QAAmB,EACnB,KAA0B,EAC1B,OAA2B;QAE3B,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;CACF"}
|
|
@@ -3,4 +3,6 @@ import type { Provider } from "./types.js";
|
|
|
3
3
|
export declare function createProvider(config: Config): Provider;
|
|
4
4
|
export type { Provider, Message, ToolCall, ProviderEvent } from "./types.js";
|
|
5
5
|
export type { OpenAIClientLike } from "./openai.js";
|
|
6
|
+
export { OpenRouterProvider } from "./openrouter.js";
|
|
7
|
+
export { GeminiProvider } from "./gemini.js";
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAQ3C,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAiBvD;AAED,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC7E,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -2,6 +2,8 @@ import { CodexProvider } from "./codex.js";
|
|
|
2
2
|
import { OpenAIProvider } from "./openai.js";
|
|
3
3
|
import { AnthropicProvider } from "./anthropic.js";
|
|
4
4
|
import { createOllamaProvider } from "./ollama.js";
|
|
5
|
+
import { OpenRouterProvider } from "./openrouter.js";
|
|
6
|
+
import { GeminiProvider } from "./gemini.js";
|
|
5
7
|
export function createProvider(config) {
|
|
6
8
|
switch (config.provider) {
|
|
7
9
|
case "codex-cli":
|
|
@@ -12,8 +14,14 @@ export function createProvider(config) {
|
|
|
12
14
|
return new AnthropicProvider(config);
|
|
13
15
|
case "ollama":
|
|
14
16
|
return createOllamaProvider(config);
|
|
17
|
+
case "openrouter":
|
|
18
|
+
return new OpenRouterProvider(config);
|
|
19
|
+
case "gemini":
|
|
20
|
+
return new GeminiProvider(config);
|
|
15
21
|
default:
|
|
16
22
|
throw new Error(`Unknown provider: ${config.provider}`);
|
|
17
23
|
}
|
|
18
24
|
}
|
|
25
|
+
export { OpenRouterProvider } from "./openrouter.js";
|
|
26
|
+
export { GeminiProvider } from "./gemini.js";
|
|
19
27
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,WAAW;YACd,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,YAAY;YACf,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,KAAK,WAAW;YACd,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACvC,KAAK,QAAQ;YACX,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;QACtC,KAAK,YAAY;YACf,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACxC,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAID,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Config } from "../core/config.js";
|
|
2
|
+
import type { Provider, Message, ProviderEvent, ChatStreamOptions } from "./types.js";
|
|
3
|
+
import type { OpenAIFunctionDef } from "../tools/types.js";
|
|
4
|
+
import { type OpenAIClientLike } from "./openai.js";
|
|
5
|
+
/**
|
|
6
|
+
* OpenRouter provider.
|
|
7
|
+
*
|
|
8
|
+
* OpenRouter is an OpenAI-compatible API gateway that routes requests to
|
|
9
|
+
* 50+ models including Claude, GPT-4o, Gemini, and Llama — all under a
|
|
10
|
+
* single API key. Model names use provider-prefixed slugs:
|
|
11
|
+
* openai/gpt-4o, anthropic/claude-3-5-sonnet, google/gemini-pro-1.5
|
|
12
|
+
*
|
|
13
|
+
* Implemented via composition with OpenAIProvider: the same streaming
|
|
14
|
+
* tool-call logic applies, just pointed at a different base URL.
|
|
15
|
+
*
|
|
16
|
+
* Set OPENROUTER_API_KEY or openrouterApiKey in .phase2s.yaml.
|
|
17
|
+
* Optional: override the base URL with openrouterBaseUrl for custom deployments.
|
|
18
|
+
*/
|
|
19
|
+
export declare class OpenRouterProvider implements Provider {
|
|
20
|
+
name: string;
|
|
21
|
+
private inner;
|
|
22
|
+
constructor(config: Config, client?: OpenAIClientLike);
|
|
23
|
+
chatStream(messages: Message[], tools: OpenAIFunctionDef[], options?: ChatStreamOptions): AsyncIterable<ProviderEvent>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=openrouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/providers/openrouter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpE;;;;;;;;;;;;;GAaG;AACH,qBAAa,kBAAmB,YAAW,QAAQ;IACjD,IAAI,SAAgB;IACpB,OAAO,CAAC,KAAK,CAAiB;gBAElB,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB;IA4B9C,UAAU,CACf,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,iBAAiB,EAAE,EAC1B,OAAO,CAAC,EAAE,iBAAiB,GAC1B,aAAa,CAAC,aAAa,CAAC;CAGhC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { OpenAIProvider } from "./openai.js";
|
|
3
|
+
/**
|
|
4
|
+
* OpenRouter provider.
|
|
5
|
+
*
|
|
6
|
+
* OpenRouter is an OpenAI-compatible API gateway that routes requests to
|
|
7
|
+
* 50+ models including Claude, GPT-4o, Gemini, and Llama — all under a
|
|
8
|
+
* single API key. Model names use provider-prefixed slugs:
|
|
9
|
+
* openai/gpt-4o, anthropic/claude-3-5-sonnet, google/gemini-pro-1.5
|
|
10
|
+
*
|
|
11
|
+
* Implemented via composition with OpenAIProvider: the same streaming
|
|
12
|
+
* tool-call logic applies, just pointed at a different base URL.
|
|
13
|
+
*
|
|
14
|
+
* Set OPENROUTER_API_KEY or openrouterApiKey in .phase2s.yaml.
|
|
15
|
+
* Optional: override the base URL with openrouterBaseUrl for custom deployments.
|
|
16
|
+
*/
|
|
17
|
+
export class OpenRouterProvider {
|
|
18
|
+
name = "openrouter";
|
|
19
|
+
inner;
|
|
20
|
+
constructor(config, client) {
|
|
21
|
+
if (!client && !config.openrouterApiKey) {
|
|
22
|
+
throw new Error("OpenRouter API key is required for the openrouter provider. " +
|
|
23
|
+
"Set OPENROUTER_API_KEY environment variable or openrouterApiKey in .phase2s.yaml");
|
|
24
|
+
}
|
|
25
|
+
const resolvedClient = client ??
|
|
26
|
+
new OpenAI({
|
|
27
|
+
apiKey: config.openrouterApiKey,
|
|
28
|
+
baseURL: config.openrouterBaseUrl ?? "https://openrouter.ai/api/v1",
|
|
29
|
+
defaultHeaders: {
|
|
30
|
+
// Recommended by OpenRouter for attribution and analytics.
|
|
31
|
+
"HTTP-Referer": "https://github.com/scanton/phase-2-s",
|
|
32
|
+
"X-Title": "Phase2S",
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
// OpenAIProvider validates config.apiKey, so pass the openrouter key there.
|
|
36
|
+
// The real client is already constructed above — OpenAIProvider uses it directly.
|
|
37
|
+
this.inner = new OpenAIProvider({ ...config, apiKey: config.openrouterApiKey ?? "" }, resolvedClient);
|
|
38
|
+
}
|
|
39
|
+
async *chatStream(messages, tools, options) {
|
|
40
|
+
yield* this.inner.chatStream(messages, tools, options);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=openrouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAI5B,OAAO,EAAE,cAAc,EAAyB,MAAM,aAAa,CAAC;AAEpE;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,kBAAkB;IAC7B,IAAI,GAAG,YAAY,CAAC;IACZ,KAAK,CAAiB;IAE9B,YAAY,MAAc,EAAE,MAAyB;QACnD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CACb,8DAA8D;gBAC5D,kFAAkF,CACrF,CAAC;QACJ,CAAC;QAED,MAAM,cAAc,GAClB,MAAM;YACL,IAAI,MAAM,CAAC;gBACV,MAAM,EAAE,MAAM,CAAC,gBAAgB;gBAC/B,OAAO,EAAE,MAAM,CAAC,iBAAiB,IAAI,8BAA8B;gBACnE,cAAc,EAAE;oBACd,2DAA2D;oBAC3D,cAAc,EAAE,sCAAsC;oBACtD,SAAS,EAAE,SAAS;iBACrB;aACF,CAAiC,CAAC;QAErC,4EAA4E;QAC5E,kFAAkF;QAClF,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAC7B,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,gBAAgB,IAAI,EAAE,EAAE,EACpD,cAAc,CACf,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,CAAC,UAAU,CACf,QAAmB,EACnB,KAA0B,EAC1B,OAA2B;QAE3B,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;CACF"}
|
|
@@ -12,11 +12,13 @@ export declare class ToolRegistry {
|
|
|
12
12
|
* allow/deny configuration.
|
|
13
13
|
*
|
|
14
14
|
* Rules (applied in order):
|
|
15
|
-
* 1. If `allow` is provided, only tools whose names
|
|
16
|
-
* 2. If `deny` is provided, any tool whose name
|
|
15
|
+
* 1. If `allow` is provided, only tools whose names match a pattern in `allow` are kept.
|
|
16
|
+
* 2. If `deny` is provided, any tool whose name matches a pattern in `deny` is removed.
|
|
17
17
|
* 3. `deny` always overrides `allow` — it is a security control.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
19
|
+
* Patterns support `*` as a wildcard: `file_*` matches `file_read` and `file_write`.
|
|
20
|
+
* Exact names (no `*`) are matched as-is. Patterns that match no registered tools
|
|
21
|
+
* produce a console warning so typos are visible.
|
|
20
22
|
*/
|
|
21
23
|
allowed(allow?: string[], deny?: string[]): ToolRegistry;
|
|
22
24
|
/** Execute a tool by name with parsed arguments */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/tools/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAgB,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/tools/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAgB,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAuB9F,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAqC;IAElD,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAIpC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI7C,IAAI,IAAI,cAAc,EAAE;IAIxB,KAAK,IAAI,MAAM,EAAE;IAIjB,mDAAmD;IACnD,QAAQ,IAAI,iBAAiB,EAAE;IAI/B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY;IA2BxD,mDAAmD;IAE7C,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;CA6BhE"}
|
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import { toolToOpenAI } from "./types.js";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Glob pattern matching
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
/**
|
|
6
|
+
* Returns true if `name` matches `pattern`.
|
|
7
|
+
* Supports `*` as a wildcard matching any sequence of characters.
|
|
8
|
+
* With no `*`, falls back to exact string equality.
|
|
9
|
+
*
|
|
10
|
+
* Examples:
|
|
11
|
+
* matchesPattern("file_read", "file_*") → true
|
|
12
|
+
* matchesPattern("shell", "file_*") → false
|
|
13
|
+
* matchesPattern("shell", "*") → true
|
|
14
|
+
* matchesPattern("shell", "shell") → true
|
|
15
|
+
*/
|
|
16
|
+
function matchesPattern(name, pattern) {
|
|
17
|
+
if (!pattern.includes("*"))
|
|
18
|
+
return name === pattern;
|
|
19
|
+
const regex = new RegExp(`^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`);
|
|
20
|
+
return regex.test(name);
|
|
21
|
+
}
|
|
2
22
|
export class ToolRegistry {
|
|
3
23
|
tools = new Map();
|
|
4
24
|
register(tool) {
|
|
@@ -22,32 +42,35 @@ export class ToolRegistry {
|
|
|
22
42
|
* allow/deny configuration.
|
|
23
43
|
*
|
|
24
44
|
* Rules (applied in order):
|
|
25
|
-
* 1. If `allow` is provided, only tools whose names
|
|
26
|
-
* 2. If `deny` is provided, any tool whose name
|
|
45
|
+
* 1. If `allow` is provided, only tools whose names match a pattern in `allow` are kept.
|
|
46
|
+
* 2. If `deny` is provided, any tool whose name matches a pattern in `deny` is removed.
|
|
27
47
|
* 3. `deny` always overrides `allow` — it is a security control.
|
|
28
48
|
*
|
|
29
|
-
*
|
|
49
|
+
* Patterns support `*` as a wildcard: `file_*` matches `file_read` and `file_write`.
|
|
50
|
+
* Exact names (no `*`) are matched as-is. Patterns that match no registered tools
|
|
51
|
+
* produce a console warning so typos are visible.
|
|
30
52
|
*/
|
|
31
53
|
allowed(allow, deny) {
|
|
32
54
|
const allNames = this.names();
|
|
33
|
-
// Warn on
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
// Warn on patterns that match no registered tool — catches typos in both exact
|
|
56
|
+
// names and glob patterns.
|
|
57
|
+
for (const pattern of allow ?? []) {
|
|
58
|
+
if (!allNames.some((n) => matchesPattern(n, pattern))) {
|
|
59
|
+
console.warn(`Warning: pattern '${pattern}' in tools (allow) list matches no known tools`);
|
|
37
60
|
}
|
|
38
61
|
}
|
|
39
|
-
for (const
|
|
40
|
-
if (!allNames.
|
|
41
|
-
console.warn(`Warning:
|
|
62
|
+
for (const pattern of deny ?? []) {
|
|
63
|
+
if (!allNames.some((n) => matchesPattern(n, pattern))) {
|
|
64
|
+
console.warn(`Warning: pattern '${pattern}' in deny list matches no known tools`);
|
|
42
65
|
}
|
|
43
66
|
}
|
|
44
67
|
const filtered = new ToolRegistry();
|
|
45
68
|
for (const tool of this.list()) {
|
|
46
69
|
// Step 1: apply allow-list (if provided)
|
|
47
|
-
if (allow && allow.length > 0 && !allow.
|
|
70
|
+
if (allow && allow.length > 0 && !allow.some((p) => matchesPattern(tool.name, p)))
|
|
48
71
|
continue;
|
|
49
72
|
// Step 2: apply deny-list (deny overrides allow)
|
|
50
|
-
if (deny && deny.
|
|
73
|
+
if (deny && deny.some((p) => matchesPattern(tool.name, p)))
|
|
51
74
|
continue;
|
|
52
75
|
filtered.register(tool);
|
|
53
76
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/tools/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,YAAY,EAA0B,MAAM,YAAY,CAAC;AAE9F,MAAM,OAAO,YAAY;IACf,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAElD,QAAQ,CAAC,IAAoB;QAC3B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,KAAK;QACH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,mDAAmD;IACnD,QAAQ;QACN,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACvC,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/tools/registry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scanton/phase2s",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "AI coding assistant with 29 built-in skills, ChatGPT subscription support, and autonomous spec execution",
|
|
5
5
|
"author": "Scott Canton",
|
|
6
6
|
"homepage": "https://github.com/scanton/phase-2-s",
|