@mmnto/cli 0.18.0 → 0.20.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/LICENSE +190 -21
- package/dist/commands/compile.d.ts.map +1 -1
- package/dist/commands/compile.js +15 -0
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/docs.d.ts +6 -1
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +58 -5
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/docs.test.js +141 -89
- package/dist/commands/docs.test.js.map +1 -1
- package/dist/commands/extract.d.ts +1 -0
- package/dist/commands/extract.d.ts.map +1 -1
- package/dist/commands/extract.js +15 -5
- package/dist/commands/extract.js.map +1 -1
- package/dist/commands/extract.test.js +54 -1
- package/dist/commands/extract.test.js.map +1 -1
- package/dist/commands/shield.d.ts.map +1 -1
- package/dist/commands/shield.js +3 -1
- package/dist/commands/shield.js.map +1 -1
- package/dist/commands/wrap.js +1 -1
- package/dist/commands/wrap.js.map +1 -1
- package/dist/commands/wrap.test.js +2 -2
- package/dist/commands/wrap.test.js.map +1 -1
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +35 -24
- package/dist/git.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/orchestrators/anthropic-orchestrator.d.ts +9 -0
- package/dist/orchestrators/anthropic-orchestrator.d.ts.map +1 -0
- package/dist/orchestrators/anthropic-orchestrator.js +62 -0
- package/dist/orchestrators/anthropic-orchestrator.js.map +1 -0
- package/dist/orchestrators/anthropic-orchestrator.test.d.ts +2 -0
- package/dist/orchestrators/anthropic-orchestrator.test.d.ts.map +1 -0
- package/dist/orchestrators/anthropic-orchestrator.test.js +109 -0
- package/dist/orchestrators/anthropic-orchestrator.test.js.map +1 -0
- package/dist/orchestrators/gemini-orchestrator.d.ts +9 -0
- package/dist/orchestrators/gemini-orchestrator.d.ts.map +1 -0
- package/dist/orchestrators/gemini-orchestrator.js +58 -0
- package/dist/orchestrators/gemini-orchestrator.js.map +1 -0
- package/dist/orchestrators/gemini-orchestrator.test.d.ts +2 -0
- package/dist/orchestrators/gemini-orchestrator.test.d.ts.map +1 -0
- package/dist/orchestrators/gemini-orchestrator.test.js +120 -0
- package/dist/orchestrators/gemini-orchestrator.test.js.map +1 -0
- package/dist/orchestrators/orchestrator.d.ts +56 -0
- package/dist/orchestrators/orchestrator.d.ts.map +1 -0
- package/dist/orchestrators/orchestrator.js +96 -0
- package/dist/orchestrators/orchestrator.js.map +1 -0
- package/dist/orchestrators/orchestrator.test.d.ts.map +1 -0
- package/dist/orchestrators/orchestrator.test.js +222 -0
- package/dist/orchestrators/orchestrator.test.js.map +1 -0
- package/dist/orchestrators/shell-orchestrator.d.ts +16 -0
- package/dist/orchestrators/shell-orchestrator.d.ts.map +1 -0
- package/dist/orchestrators/shell-orchestrator.js +131 -0
- package/dist/orchestrators/shell-orchestrator.js.map +1 -0
- package/dist/orchestrators/shell-orchestrator.test.d.ts +2 -0
- package/dist/orchestrators/shell-orchestrator.test.d.ts.map +1 -0
- package/dist/orchestrators/shell-orchestrator.test.js +267 -0
- package/dist/orchestrators/shell-orchestrator.test.js.map +1 -0
- package/dist/utils.d.ts +1 -18
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +31 -146
- package/dist/utils.js.map +1 -1
- package/dist/utils.test.js +183 -82
- package/dist/utils.test.js.map +1 -1
- package/package.json +17 -3
- package/dist/orchestrator.test.d.ts.map +0 -1
- package/dist/orchestrator.test.js +0 -130
- package/dist/orchestrator.test.js.map +0 -1
- /package/dist/{orchestrator.test.d.ts → orchestrators/orchestrator.test.d.ts} +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { invokeGeminiOrchestrator } from './gemini-orchestrator.js';
|
|
3
|
+
// ─── Mock SDK ───────────────────────────────────────
|
|
4
|
+
const { mockGenerateContent } = vi.hoisted(() => ({
|
|
5
|
+
mockGenerateContent: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
vi.mock('@google/genai', () => ({
|
|
8
|
+
GoogleGenAI: class {
|
|
9
|
+
models = { generateContent: mockGenerateContent };
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
vi.mock('../ui.js', () => ({
|
|
13
|
+
log: { info: vi.fn(), success: vi.fn(), warn: vi.fn(), error: vi.fn(), dim: vi.fn() },
|
|
14
|
+
}));
|
|
15
|
+
// ─── Tests ──────────────────────────────────────────
|
|
16
|
+
describe('invokeGeminiOrchestrator', () => {
|
|
17
|
+
const baseOpts = {
|
|
18
|
+
prompt: 'test prompt',
|
|
19
|
+
model: 'gemini-2.5-flash',
|
|
20
|
+
cwd: '.',
|
|
21
|
+
tag: 'Test',
|
|
22
|
+
totemDir: '.totem',
|
|
23
|
+
};
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.clearAllMocks();
|
|
26
|
+
process.env['GEMINI_API_KEY'] = 'test-key';
|
|
27
|
+
});
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
delete process.env['GEMINI_API_KEY'];
|
|
30
|
+
delete process.env['GOOGLE_API_KEY'];
|
|
31
|
+
});
|
|
32
|
+
it('returns structured result from Gemini API', async () => {
|
|
33
|
+
mockGenerateContent.mockResolvedValueOnce({
|
|
34
|
+
text: 'Hello from Gemini',
|
|
35
|
+
usageMetadata: { promptTokenCount: 100, candidatesTokenCount: 50 },
|
|
36
|
+
candidates: [{ finishReason: 'STOP' }],
|
|
37
|
+
});
|
|
38
|
+
const result = await invokeGeminiOrchestrator(baseOpts);
|
|
39
|
+
expect(result.content).toBe('Hello from Gemini');
|
|
40
|
+
expect(result.inputTokens).toBe(100);
|
|
41
|
+
expect(result.outputTokens).toBe(50);
|
|
42
|
+
expect(result.finishReason).toBe('STOP');
|
|
43
|
+
expect(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
44
|
+
});
|
|
45
|
+
it('passes model and prompt to the SDK', async () => {
|
|
46
|
+
mockGenerateContent.mockResolvedValueOnce({
|
|
47
|
+
text: 'ok',
|
|
48
|
+
usageMetadata: {},
|
|
49
|
+
candidates: [],
|
|
50
|
+
});
|
|
51
|
+
await invokeGeminiOrchestrator(baseOpts);
|
|
52
|
+
expect(mockGenerateContent).toHaveBeenCalledWith(expect.objectContaining({
|
|
53
|
+
model: 'gemini-2.5-flash',
|
|
54
|
+
contents: 'test prompt',
|
|
55
|
+
}));
|
|
56
|
+
});
|
|
57
|
+
it('falls back to GOOGLE_API_KEY when GEMINI_API_KEY is not set', async () => {
|
|
58
|
+
delete process.env['GEMINI_API_KEY'];
|
|
59
|
+
process.env['GOOGLE_API_KEY'] = 'google-key';
|
|
60
|
+
mockGenerateContent.mockResolvedValueOnce({
|
|
61
|
+
text: 'ok',
|
|
62
|
+
usageMetadata: {},
|
|
63
|
+
candidates: [],
|
|
64
|
+
});
|
|
65
|
+
// Should not throw — GOOGLE_API_KEY is accepted
|
|
66
|
+
await invokeGeminiOrchestrator(baseOpts);
|
|
67
|
+
});
|
|
68
|
+
it('throws when no API key is set', async () => {
|
|
69
|
+
delete process.env['GEMINI_API_KEY'];
|
|
70
|
+
delete process.env['GOOGLE_API_KEY'];
|
|
71
|
+
await expect(invokeGeminiOrchestrator(baseOpts)).rejects.toThrow('No Gemini API key found');
|
|
72
|
+
});
|
|
73
|
+
it('converts 429 status errors to QuotaError', async () => {
|
|
74
|
+
const rateLimitErr = Object.assign(new Error('Resource exhausted'), { status: 429 });
|
|
75
|
+
mockGenerateContent.mockRejectedValueOnce(rateLimitErr);
|
|
76
|
+
try {
|
|
77
|
+
await invokeGeminiOrchestrator(baseOpts);
|
|
78
|
+
expect.fail('Should have thrown');
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
expect(err.name).toBe('QuotaError');
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
it('converts quota keyword errors to QuotaError', async () => {
|
|
85
|
+
mockGenerateContent.mockRejectedValueOnce(new Error('quota exceeded for model'));
|
|
86
|
+
try {
|
|
87
|
+
await invokeGeminiOrchestrator(baseOpts);
|
|
88
|
+
expect.fail('Should have thrown');
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
expect(err.name).toBe('QuotaError');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
it('wraps other API errors with [Totem Error] prefix', async () => {
|
|
95
|
+
mockGenerateContent.mockRejectedValueOnce(new Error('Model not found'));
|
|
96
|
+
await expect(invokeGeminiOrchestrator(baseOpts)).rejects.toThrow('[Totem Error] Gemini API call failed');
|
|
97
|
+
});
|
|
98
|
+
it('handles missing usageMetadata gracefully', async () => {
|
|
99
|
+
mockGenerateContent.mockResolvedValueOnce({
|
|
100
|
+
text: 'response',
|
|
101
|
+
candidates: [],
|
|
102
|
+
});
|
|
103
|
+
const result = await invokeGeminiOrchestrator(baseOpts);
|
|
104
|
+
expect(result.content).toBe('response');
|
|
105
|
+
expect(result.inputTokens).toBeNull();
|
|
106
|
+
expect(result.outputTokens).toBeNull();
|
|
107
|
+
expect(result.finishReason).toBeUndefined();
|
|
108
|
+
});
|
|
109
|
+
it('handles undefined text as empty string', async () => {
|
|
110
|
+
mockGenerateContent.mockResolvedValueOnce({
|
|
111
|
+
text: undefined,
|
|
112
|
+
usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 0 },
|
|
113
|
+
candidates: [{ finishReason: 'SAFETY' }],
|
|
114
|
+
});
|
|
115
|
+
const result = await invokeGeminiOrchestrator(baseOpts);
|
|
116
|
+
expect(result.content).toBe('');
|
|
117
|
+
expect(result.finishReason).toBe('SAFETY');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
//# sourceMappingURL=gemini-orchestrator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini-orchestrator.test.js","sourceRoot":"","sources":["../../src/orchestrators/gemini-orchestrator.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Orchestrator as OrchestratorConfig } from '@mmnto/totem';
|
|
2
|
+
export interface OrchestratorResult {
|
|
3
|
+
content: string;
|
|
4
|
+
inputTokens: number | null;
|
|
5
|
+
outputTokens: number | null;
|
|
6
|
+
durationMs: number;
|
|
7
|
+
finishReason?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface OrchestratorInvokeOptions {
|
|
10
|
+
prompt: string;
|
|
11
|
+
model: string;
|
|
12
|
+
cwd: string;
|
|
13
|
+
tag: string;
|
|
14
|
+
totemDir: string;
|
|
15
|
+
}
|
|
16
|
+
/** A provider-bound function that invokes an LLM and returns the result. */
|
|
17
|
+
export type InvokeOrchestrator = (options: OrchestratorInvokeOptions) => Promise<OrchestratorResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Detect the active package manager from the `npm_config_user_agent` env var
|
|
20
|
+
* (set by npm, pnpm, yarn, and bun when running scripts). Falls back to `npm`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function detectPackageManager(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Detect whether an error is a rate-limit / quota-exhaustion response.
|
|
25
|
+
* Used by both Gemini and Anthropic orchestrators to normalize QuotaError.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isQuotaError(err: unknown): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Parse a `provider:model` string into its components.
|
|
30
|
+
* If the prefix before the first colon is a known provider, splits it out.
|
|
31
|
+
* Otherwise, returns the full string as the model with the default provider.
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseModelString(value: string, defaultProvider: string): {
|
|
34
|
+
provider: string;
|
|
35
|
+
model: string;
|
|
36
|
+
};
|
|
37
|
+
export interface ResolvedOrchestrator {
|
|
38
|
+
parsed: {
|
|
39
|
+
provider: string;
|
|
40
|
+
model: string;
|
|
41
|
+
};
|
|
42
|
+
invoke: InvokeOrchestrator;
|
|
43
|
+
qualifiedModel: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Parse and validate a model string, resolve cross-provider routing,
|
|
47
|
+
* and return the appropriate invoker. Centralizes the validation logic
|
|
48
|
+
* to guarantee symmetric validation across primary and fallback paths.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveOrchestrator(rawModel: string, baseProvider: string, baseInvoke: InvokeOrchestrator): ResolvedOrchestrator;
|
|
51
|
+
/**
|
|
52
|
+
* Create an orchestrator invoker bound to the given provider config.
|
|
53
|
+
* Mirrors the `createEmbedder()` pattern from `packages/core/src/embedders/`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createOrchestrator(config: OrchestratorConfig): InvokeOrchestrator;
|
|
56
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/orchestrators/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAMvE,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,MAAM,kBAAkB,GAAG,CAC/B,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAIjC;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAM7C;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAUlD;AAMD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,GACtB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CASrC;AAOD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,MAAM,EAAE,kBAAkB,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,kBAAkB,GAC7B,oBAAoB,CA8BtB;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,kBAAkB,CAejF"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { invokeShellOrchestrator } from './shell-orchestrator.js';
|
|
2
|
+
// ─── Package manager detection (#236) ───────────────
|
|
3
|
+
/**
|
|
4
|
+
* Detect the active package manager from the `npm_config_user_agent` env var
|
|
5
|
+
* (set by npm, pnpm, yarn, and bun when running scripts). Falls back to `npm`.
|
|
6
|
+
*/
|
|
7
|
+
export function detectPackageManager() {
|
|
8
|
+
const ua = process.env['npm_config_user_agent'] ?? '';
|
|
9
|
+
if (ua.startsWith('pnpm'))
|
|
10
|
+
return 'pnpm';
|
|
11
|
+
if (ua.startsWith('yarn'))
|
|
12
|
+
return 'yarn';
|
|
13
|
+
if (ua.startsWith('bun'))
|
|
14
|
+
return 'bun';
|
|
15
|
+
return 'npm';
|
|
16
|
+
}
|
|
17
|
+
// ─── Quota detection (shared) ────────────────────────
|
|
18
|
+
/**
|
|
19
|
+
* Detect whether an error is a rate-limit / quota-exhaustion response.
|
|
20
|
+
* Used by both Gemini and Anthropic orchestrators to normalize QuotaError.
|
|
21
|
+
*/
|
|
22
|
+
export function isQuotaError(err) {
|
|
23
|
+
if (!(err instanceof Error))
|
|
24
|
+
return false;
|
|
25
|
+
if ('status' in err && err.status === 429)
|
|
26
|
+
return true;
|
|
27
|
+
const msg = err.message.toLowerCase();
|
|
28
|
+
return (msg.includes('429') ||
|
|
29
|
+
msg.includes('quota') ||
|
|
30
|
+
msg.includes('rate limit') ||
|
|
31
|
+
msg.includes('too many requests'));
|
|
32
|
+
}
|
|
33
|
+
// ─── Model string parsing (#243) ─────────────────────
|
|
34
|
+
const KNOWN_PROVIDERS = ['gemini', 'anthropic', 'shell'];
|
|
35
|
+
/**
|
|
36
|
+
* Parse a `provider:model` string into its components.
|
|
37
|
+
* If the prefix before the first colon is a known provider, splits it out.
|
|
38
|
+
* Otherwise, returns the full string as the model with the default provider.
|
|
39
|
+
*/
|
|
40
|
+
export function parseModelString(value, defaultProvider) {
|
|
41
|
+
const colonIdx = value.indexOf(':');
|
|
42
|
+
if (colonIdx > 0) {
|
|
43
|
+
const prefix = value.slice(0, colonIdx);
|
|
44
|
+
if (KNOWN_PROVIDERS.includes(prefix)) {
|
|
45
|
+
return { provider: prefix, model: value.slice(colonIdx + 1) };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { provider: defaultProvider, model: value };
|
|
49
|
+
}
|
|
50
|
+
// ─── Centralized model resolution (#248) ────────────
|
|
51
|
+
/** Characters allowed in model names — restricts shell metacharacters. */
|
|
52
|
+
const MODEL_NAME_RE = /^[\w./:_-]+$/;
|
|
53
|
+
/**
|
|
54
|
+
* Parse and validate a model string, resolve cross-provider routing,
|
|
55
|
+
* and return the appropriate invoker. Centralizes the validation logic
|
|
56
|
+
* to guarantee symmetric validation across primary and fallback paths.
|
|
57
|
+
*/
|
|
58
|
+
export function resolveOrchestrator(rawModel, baseProvider, baseInvoke) {
|
|
59
|
+
if (rawModel.startsWith('-') || !MODEL_NAME_RE.test(rawModel)) {
|
|
60
|
+
throw new Error(`[Totem Error] Invalid model name '${rawModel}'. Model names may only contain word characters, dots, slashes, colons, underscores, and hyphens.`);
|
|
61
|
+
}
|
|
62
|
+
const parsed = parseModelString(rawModel, baseProvider);
|
|
63
|
+
if (parsed.provider === 'shell' && baseProvider !== 'shell') {
|
|
64
|
+
throw new Error(`[Totem Error] Cannot route to 'shell' provider from a '${baseProvider}' config.\n` +
|
|
65
|
+
`The shell provider requires a 'command' template in the orchestrator config.`);
|
|
66
|
+
}
|
|
67
|
+
if (!parsed.model || parsed.model.startsWith('-')) {
|
|
68
|
+
throw new Error(`[Totem Error] Invalid model name in '${rawModel}'. The model portion must not be empty or start with a hyphen.`);
|
|
69
|
+
}
|
|
70
|
+
const invoke = parsed.provider === baseProvider
|
|
71
|
+
? baseInvoke
|
|
72
|
+
: createOrchestrator({ provider: parsed.provider });
|
|
73
|
+
return { parsed, invoke, qualifiedModel: rawModel };
|
|
74
|
+
}
|
|
75
|
+
// ─── Factory ─────────────────────────────────────────
|
|
76
|
+
/**
|
|
77
|
+
* Create an orchestrator invoker bound to the given provider config.
|
|
78
|
+
* Mirrors the `createEmbedder()` pattern from `packages/core/src/embedders/`.
|
|
79
|
+
*/
|
|
80
|
+
export function createOrchestrator(config) {
|
|
81
|
+
switch (config.provider) {
|
|
82
|
+
case 'shell':
|
|
83
|
+
return (opts) => invokeShellOrchestrator({ ...opts, command: config.command });
|
|
84
|
+
case 'gemini':
|
|
85
|
+
return async (opts) => {
|
|
86
|
+
const { invokeGeminiOrchestrator } = await import('./gemini-orchestrator.js');
|
|
87
|
+
return invokeGeminiOrchestrator(opts);
|
|
88
|
+
};
|
|
89
|
+
case 'anthropic':
|
|
90
|
+
return async (opts) => {
|
|
91
|
+
const { invokeAnthropicOrchestrator } = await import('./anthropic-orchestrator.js');
|
|
92
|
+
return invokeAnthropicOrchestrator(opts);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/orchestrators/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.test.d.ts","sourceRoot":"","sources":["../../src/orchestrators/orchestrator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { createOrchestrator, detectPackageManager, isQuotaError, parseModelString, resolveOrchestrator, } from './orchestrator.js';
|
|
3
|
+
// ─── Mock provider modules ──────────────────────────
|
|
4
|
+
vi.mock('./gemini-orchestrator.js', () => ({
|
|
5
|
+
invokeGeminiOrchestrator: vi.fn().mockResolvedValue({
|
|
6
|
+
content: 'gemini result',
|
|
7
|
+
inputTokens: 100,
|
|
8
|
+
outputTokens: 50,
|
|
9
|
+
durationMs: 1000,
|
|
10
|
+
}),
|
|
11
|
+
}));
|
|
12
|
+
vi.mock('./anthropic-orchestrator.js', () => ({
|
|
13
|
+
invokeAnthropicOrchestrator: vi.fn().mockResolvedValue({
|
|
14
|
+
content: 'anthropic result',
|
|
15
|
+
inputTokens: 200,
|
|
16
|
+
outputTokens: 75,
|
|
17
|
+
durationMs: 2000,
|
|
18
|
+
}),
|
|
19
|
+
}));
|
|
20
|
+
// ─── Tests ──────────────────────────────────────────
|
|
21
|
+
describe('createOrchestrator', () => {
|
|
22
|
+
it('returns a function for shell provider', () => {
|
|
23
|
+
const config = {
|
|
24
|
+
provider: 'shell',
|
|
25
|
+
command: 'echo {file}',
|
|
26
|
+
};
|
|
27
|
+
const invoke = createOrchestrator(config);
|
|
28
|
+
expect(typeof invoke).toBe('function');
|
|
29
|
+
});
|
|
30
|
+
it('returns a function for gemini provider', () => {
|
|
31
|
+
const config = {
|
|
32
|
+
provider: 'gemini',
|
|
33
|
+
defaultModel: 'gemini-2.5-flash',
|
|
34
|
+
};
|
|
35
|
+
const invoke = createOrchestrator(config);
|
|
36
|
+
expect(typeof invoke).toBe('function');
|
|
37
|
+
});
|
|
38
|
+
it('returns a function for anthropic provider', () => {
|
|
39
|
+
const config = {
|
|
40
|
+
provider: 'anthropic',
|
|
41
|
+
defaultModel: 'claude-sonnet-4-5-20250514',
|
|
42
|
+
};
|
|
43
|
+
const invoke = createOrchestrator(config);
|
|
44
|
+
expect(typeof invoke).toBe('function');
|
|
45
|
+
});
|
|
46
|
+
it('gemini invoker dispatches to gemini-orchestrator module', async () => {
|
|
47
|
+
const config = { provider: 'gemini' };
|
|
48
|
+
const invoke = createOrchestrator(config);
|
|
49
|
+
const result = await invoke({
|
|
50
|
+
prompt: 'test',
|
|
51
|
+
model: 'gemini-2.5-flash',
|
|
52
|
+
cwd: '.',
|
|
53
|
+
tag: 'Test',
|
|
54
|
+
totemDir: '.totem',
|
|
55
|
+
});
|
|
56
|
+
expect(result.content).toBe('gemini result');
|
|
57
|
+
expect(result.inputTokens).toBe(100);
|
|
58
|
+
});
|
|
59
|
+
it('anthropic invoker dispatches to anthropic-orchestrator module', async () => {
|
|
60
|
+
const config = { provider: 'anthropic' };
|
|
61
|
+
const invoke = createOrchestrator(config);
|
|
62
|
+
const result = await invoke({
|
|
63
|
+
prompt: 'test',
|
|
64
|
+
model: 'claude-sonnet-4-5-20250514',
|
|
65
|
+
cwd: '.',
|
|
66
|
+
tag: 'Test',
|
|
67
|
+
totemDir: '.totem',
|
|
68
|
+
});
|
|
69
|
+
expect(result.content).toBe('anthropic result');
|
|
70
|
+
expect(result.inputTokens).toBe(200);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
// ─── detectPackageManager ───────────────────────────
|
|
74
|
+
describe('detectPackageManager', () => {
|
|
75
|
+
const originalUa = process.env['npm_config_user_agent'];
|
|
76
|
+
afterEach(() => {
|
|
77
|
+
if (originalUa !== undefined) {
|
|
78
|
+
process.env['npm_config_user_agent'] = originalUa;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
delete process.env['npm_config_user_agent'];
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
it('detects pnpm', () => {
|
|
85
|
+
process.env['npm_config_user_agent'] = 'pnpm/9.15.0 npm/? node/v22.0.0';
|
|
86
|
+
expect(detectPackageManager()).toBe('pnpm');
|
|
87
|
+
});
|
|
88
|
+
it('detects yarn', () => {
|
|
89
|
+
process.env['npm_config_user_agent'] = 'yarn/4.0.0 npm/? node/v22.0.0';
|
|
90
|
+
expect(detectPackageManager()).toBe('yarn');
|
|
91
|
+
});
|
|
92
|
+
it('detects bun', () => {
|
|
93
|
+
process.env['npm_config_user_agent'] = 'bun/1.0.0';
|
|
94
|
+
expect(detectPackageManager()).toBe('bun');
|
|
95
|
+
});
|
|
96
|
+
it('defaults to npm when env var is missing', () => {
|
|
97
|
+
delete process.env['npm_config_user_agent'];
|
|
98
|
+
expect(detectPackageManager()).toBe('npm');
|
|
99
|
+
});
|
|
100
|
+
it('defaults to npm for unknown user agent', () => {
|
|
101
|
+
process.env['npm_config_user_agent'] = 'npm/10.0.0 node/v22.0.0';
|
|
102
|
+
expect(detectPackageManager()).toBe('npm');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
// ─── isQuotaError ───────────────────────────────────
|
|
106
|
+
describe('isQuotaError', () => {
|
|
107
|
+
it('detects 429 status errors', () => {
|
|
108
|
+
const err = Object.assign(new Error('rate limit'), { status: 429 });
|
|
109
|
+
expect(isQuotaError(err)).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
it('detects quota keyword in message', () => {
|
|
112
|
+
expect(isQuotaError(new Error('quota exceeded'))).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
it('detects rate limit keyword in message', () => {
|
|
115
|
+
expect(isQuotaError(new Error('rate limit reached'))).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
it('detects too many requests keyword', () => {
|
|
118
|
+
expect(isQuotaError(new Error('Too Many Requests'))).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
it('returns false for non-quota errors', () => {
|
|
121
|
+
expect(isQuotaError(new Error('Model not found'))).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
it('returns false for non-Error values', () => {
|
|
124
|
+
expect(isQuotaError('some string')).toBe(false);
|
|
125
|
+
expect(isQuotaError(null)).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
// ─── resolveOrchestrator (#248) ─────────────────────
|
|
129
|
+
describe('resolveOrchestrator', () => {
|
|
130
|
+
const mockInvoke = vi.fn().mockResolvedValue({
|
|
131
|
+
content: 'mock result',
|
|
132
|
+
inputTokens: 100,
|
|
133
|
+
outputTokens: 50,
|
|
134
|
+
durationMs: 500,
|
|
135
|
+
});
|
|
136
|
+
it('reuses baseInvoke for same-provider resolution', () => {
|
|
137
|
+
const result = resolveOrchestrator('gemini-3-flash-preview', 'gemini', mockInvoke);
|
|
138
|
+
expect(result.invoke).toBe(mockInvoke);
|
|
139
|
+
expect(result.parsed).toEqual({ provider: 'gemini', model: 'gemini-3-flash-preview' });
|
|
140
|
+
expect(result.qualifiedModel).toBe('gemini-3-flash-preview');
|
|
141
|
+
});
|
|
142
|
+
it('creates new invoker for cross-provider resolution', () => {
|
|
143
|
+
const result = resolveOrchestrator('anthropic:claude-sonnet-4-20250514', 'gemini', mockInvoke);
|
|
144
|
+
expect(result.invoke).not.toBe(mockInvoke);
|
|
145
|
+
expect(result.parsed).toEqual({ provider: 'anthropic', model: 'claude-sonnet-4-20250514' });
|
|
146
|
+
expect(result.qualifiedModel).toBe('anthropic:claude-sonnet-4-20250514');
|
|
147
|
+
});
|
|
148
|
+
it('throws on empty model string (provider:)', () => {
|
|
149
|
+
expect(() => resolveOrchestrator('anthropic:', 'gemini', mockInvoke)).toThrow('must not be empty or start with a hyphen');
|
|
150
|
+
});
|
|
151
|
+
it('throws on model starting with hyphen', () => {
|
|
152
|
+
expect(() => resolveOrchestrator('anthropic:-bad', 'gemini', mockInvoke)).toThrow('must not be empty or start with a hyphen');
|
|
153
|
+
});
|
|
154
|
+
it('throws when cross-routing to shell from API provider', () => {
|
|
155
|
+
expect(() => resolveOrchestrator('shell:my-model', 'gemini', mockInvoke)).toThrow("Cannot route to 'shell' provider");
|
|
156
|
+
});
|
|
157
|
+
it('allows shell-to-shell routing', () => {
|
|
158
|
+
const result = resolveOrchestrator('shell:my-model', 'shell', mockInvoke);
|
|
159
|
+
expect(result.invoke).toBe(mockInvoke);
|
|
160
|
+
expect(result.parsed).toEqual({ provider: 'shell', model: 'my-model' });
|
|
161
|
+
});
|
|
162
|
+
it('preserves provider:model as qualifiedModel for cross-route', () => {
|
|
163
|
+
const result = resolveOrchestrator('gemini:gemini-3.1-pro-preview', 'anthropic', mockInvoke);
|
|
164
|
+
expect(result.qualifiedModel).toBe('gemini:gemini-3.1-pro-preview');
|
|
165
|
+
});
|
|
166
|
+
it('rejects model names with shell metacharacters', () => {
|
|
167
|
+
expect(() => resolveOrchestrator('$(touch /tmp/pwned)', 'shell', mockInvoke)).toThrow('Invalid model name');
|
|
168
|
+
expect(() => resolveOrchestrator('model;rm -rf /', 'shell', mockInvoke)).toThrow('Invalid model name');
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
// ─── parseModelString (#243) ────────────────────────
|
|
172
|
+
describe('parseModelString', () => {
|
|
173
|
+
it('parses anthropic:model into provider and model', () => {
|
|
174
|
+
expect(parseModelString('anthropic:claude-sonnet-4-20250514', 'gemini')).toEqual({
|
|
175
|
+
provider: 'anthropic',
|
|
176
|
+
model: 'claude-sonnet-4-20250514',
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
it('parses gemini:model into provider and model', () => {
|
|
180
|
+
expect(parseModelString('gemini:gemini-3.1-pro-preview', 'anthropic')).toEqual({
|
|
181
|
+
provider: 'gemini',
|
|
182
|
+
model: 'gemini-3.1-pro-preview',
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
it('parses shell:model into provider and model', () => {
|
|
186
|
+
expect(parseModelString('shell:my-model', 'gemini')).toEqual({
|
|
187
|
+
provider: 'shell',
|
|
188
|
+
model: 'my-model',
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
it('returns default provider for plain model string', () => {
|
|
192
|
+
expect(parseModelString('gemini-3-flash-preview', 'gemini')).toEqual({
|
|
193
|
+
provider: 'gemini',
|
|
194
|
+
model: 'gemini-3-flash-preview',
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
it('returns default provider for unknown prefix (not a known provider)', () => {
|
|
198
|
+
expect(parseModelString('unknown:my-model:v1', 'gemini')).toEqual({
|
|
199
|
+
provider: 'gemini',
|
|
200
|
+
model: 'unknown:my-model:v1',
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
it('returns default provider for org/namespace:model patterns', () => {
|
|
204
|
+
expect(parseModelString('myorg/namespace:model-v1', 'anthropic')).toEqual({
|
|
205
|
+
provider: 'anthropic',
|
|
206
|
+
model: 'myorg/namespace:model-v1',
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
it('parses empty model after colon (caller should validate)', () => {
|
|
210
|
+
expect(parseModelString('anthropic:', 'gemini')).toEqual({
|
|
211
|
+
provider: 'anthropic',
|
|
212
|
+
model: '',
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
it('does not split on leading colon', () => {
|
|
216
|
+
expect(parseModelString(':some-model', 'gemini')).toEqual({
|
|
217
|
+
provider: 'gemini',
|
|
218
|
+
model: ':some-model',
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
//# sourceMappingURL=orchestrator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.test.js","sourceRoot":"","sources":["../../src/orchestrators/orchestrator.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OrchestratorInvokeOptions, OrchestratorResult } from './orchestrator.js';
|
|
2
|
+
/**
|
|
3
|
+
* Try to parse Gemini CLI JSON output. Returns extracted data or null if
|
|
4
|
+
* the output is not valid Gemini JSON (e.g. raw text from a non-Gemini orchestrator).
|
|
5
|
+
*/
|
|
6
|
+
export declare function tryParseGeminiJson(raw: string): {
|
|
7
|
+
content: string;
|
|
8
|
+
inputTokens: number;
|
|
9
|
+
outputTokens: number;
|
|
10
|
+
latencyMs: number | null;
|
|
11
|
+
} | null;
|
|
12
|
+
export interface ShellOrchestratorOptions extends OrchestratorInvokeOptions {
|
|
13
|
+
command: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function invokeShellOrchestrator(opts: ShellOrchestratorOptions): Promise<OrchestratorResult>;
|
|
16
|
+
//# sourceMappingURL=shell-orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-orchestrator.d.ts","sourceRoot":"","sources":["../../src/orchestrators/shell-orchestrator.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAwBvF;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,GACV;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAwBjG;AAID,MAAM,WAAW,wBAAyB,SAAQ,yBAAyB;IACzE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,kBAAkB,CAAC,CAoG7B"}
|