@gobing-ai/ts-ai-runner 0.5.3 → 0.5.5
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/agent-spec.d.ts +7 -0
- package/dist/agent-spec.d.ts.map +1 -1
- package/dist/agent-spec.js +12 -0
- package/dist/agents/shims.d.ts.map +1 -1
- package/dist/agents/shims.js +8 -4
- package/dist/decision/decision-maker.d.ts +8 -0
- package/dist/decision/decision-maker.d.ts.map +1 -1
- package/dist/decision/decision-maker.js +24 -12
- package/dist/identity.d.ts +2 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +4 -3
- package/package.json +4 -4
- package/src/agent-spec.ts +15 -0
- package/src/agents/shims.ts +8 -5
- package/src/decision/decision-maker.ts +33 -12
- package/src/identity.ts +4 -3
package/dist/agent-spec.d.ts
CHANGED
|
@@ -23,6 +23,13 @@ export declare class ValueError extends Error {
|
|
|
23
23
|
}
|
|
24
24
|
/** Validate that `id` matches the agent ID format: 2-64 chars, lowercase alphanumeric with `_` or `-`. Returns the id on success, throws `ValueError` otherwise. */
|
|
25
25
|
export declare function validateAgentId(id: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Validate a caller-supplied session id before it is used in a filesystem path
|
|
28
|
+
* (task 0086 R15): 1-128 chars, starting alphanumeric, then alnum/`.`/`_`/`-`,
|
|
29
|
+
* and never containing `..`. Returns the id on success, throws `ValueError`
|
|
30
|
+
* otherwise — failing closed beats sanitizing attacker-controlled path input.
|
|
31
|
+
*/
|
|
32
|
+
export declare function assertSafeSessionId(id: string): string;
|
|
26
33
|
/** Load and validate all YAML agent spec files from `configDir`. Throws `ValueError` on parse failures or duplicate IDs. */
|
|
27
34
|
export declare function loadAgentSpecs(configDir: string, fs?: FileSystem): Promise<AgentSpec[]>;
|
|
28
35
|
/** Serialize `spec` to YAML and write it to `configDir/<id>.yaml`. Creates the directory if missing. */
|
package/dist/agent-spec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-spec.d.ts","sourceRoot":"","sources":["../src/agent-spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,UAAU,EAIlB,MAAM,uBAAuB,CAAC;AAE/B,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,4EAA4E;AAC5E,qBAAa,UAAW,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAI9B;AAED,oKAAoK;AACpK,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,4HAA4H;AAC5H,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,GAAE,UAAmC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAcrH;AAED,wGAAwG;AACxG,wBAAsB,aAAa,CAC/B,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,MAAM,EACjB,EAAE,GAAE,UAAmC,GACxC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,oGAAoG;AACpG,wBAAsB,eAAe,CACjC,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,EAAE,GAAE,UAAmC,GACxC,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
1
|
+
{"version":3,"file":"agent-spec.d.ts","sourceRoot":"","sources":["../src/agent-spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,UAAU,EAIlB,MAAM,uBAAuB,CAAC;AAE/B,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,4EAA4E;AAC5E,qBAAa,UAAW,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAI9B;AAED,oKAAoK;AACpK,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED,4HAA4H;AAC5H,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,GAAE,UAAmC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAcrH;AAED,wGAAwG;AACxG,wBAAsB,aAAa,CAC/B,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,MAAM,EACjB,EAAE,GAAE,UAAmC,GACxC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,oGAAoG;AACpG,wBAAsB,eAAe,CACjC,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,EAAE,GAAE,UAAmC,GACxC,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
package/dist/agent-spec.js
CHANGED
|
@@ -13,6 +13,18 @@ export function validateAgentId(id) {
|
|
|
13
13
|
}
|
|
14
14
|
return id;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Validate a caller-supplied session id before it is used in a filesystem path
|
|
18
|
+
* (task 0086 R15): 1-128 chars, starting alphanumeric, then alnum/`.`/`_`/`-`,
|
|
19
|
+
* and never containing `..`. Returns the id on success, throws `ValueError`
|
|
20
|
+
* otherwise — failing closed beats sanitizing attacker-controlled path input.
|
|
21
|
+
*/
|
|
22
|
+
export function assertSafeSessionId(id) {
|
|
23
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(id) || id.includes('..')) {
|
|
24
|
+
throw new ValueError(`Invalid session id "${id}": expected 1-128 chars (alphanumeric, ".", "_", "-", starting alphanumeric) without path separators or ".."`);
|
|
25
|
+
}
|
|
26
|
+
return id;
|
|
27
|
+
}
|
|
16
28
|
/** Load and validate all YAML agent spec files from `configDir`. Throws `ValueError` on parse failures or duplicate IDs. */
|
|
17
29
|
export async function loadAgentSpecs(configDir, fs = createNodeFileSystem()) {
|
|
18
30
|
const entries = (await safeReadDir(configDir, fs))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shims.d.ts","sourceRoot":"","sources":["../../src/agents/shims.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shims.d.ts","sourceRoot":"","sources":["../../src/agents/shims.ts"],"names":[],"mappings":"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"}
|
package/dist/agents/shims.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getLogger } from '@gobing-ai/ts-infra';
|
|
2
2
|
import { joinPath } from '@gobing-ai/ts-runtime';
|
|
3
|
+
import { assertSafeSessionId } from '../agent-spec.js';
|
|
3
4
|
/** pi-family rpc dialect (pi docs/rpc.md): one JSON object per line. */
|
|
4
5
|
const piRpcFrame = (input) => `${JSON.stringify({ type: 'prompt', message: input })}\n`;
|
|
5
6
|
/** claude stream-json input dialect: one user-message JSONL envelope per line. */
|
|
@@ -353,15 +354,18 @@ const fmShim = {
|
|
|
353
354
|
// and suppress any unscoped continue. `continue` alone degrades to a
|
|
354
355
|
// fresh call — fm has no implicit last-session flag.
|
|
355
356
|
if (options.sessionId !== undefined) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
357
|
+
// Task 0086 R15: sessionId lands in a filesystem path — validate it
|
|
358
|
+
// before it can escape sessionDir via separators or traversal.
|
|
359
|
+
const id = assertSafeSessionId(options.sessionId);
|
|
360
|
+
const file = options.sessionDir !== undefined ? joinPath(options.sessionDir, `${id}.json`) : `${id}.json`;
|
|
359
361
|
args.push('--resume', file, '--save-transcript', file);
|
|
360
362
|
}
|
|
361
363
|
else if (options.sessionDir !== undefined) {
|
|
362
364
|
args.push('--save-transcript', joinPath(options.sessionDir, 'fm-session.json'));
|
|
363
365
|
}
|
|
364
|
-
|
|
366
|
+
// Task 0086 R4: `--` pins the input as a positional, so dash-leading
|
|
367
|
+
// prompts (--help, -n) are never reparsed as fm flags.
|
|
368
|
+
args.push('--', options.input ?? '');
|
|
365
369
|
return { command: 'fm', args };
|
|
366
370
|
},
|
|
367
371
|
getAuthCommand: () => ({ command: 'fm', args: ['available', '--model', 'system'] }),
|
|
@@ -40,6 +40,14 @@ export interface DecisionMakerOptions {
|
|
|
40
40
|
fetch?: typeof fetch;
|
|
41
41
|
[key: string]: unknown;
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* @internal Exported for task 0086 R9 branch tests: `importModule` lets tests
|
|
45
|
+
* simulate package-import failures that cannot occur in-workspace (workspace
|
|
46
|
+
* links always resolve).
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveLayaDriver(options: DecisionMakerOptions, importModule?: (specifier: string) => Promise<unknown>): Promise<DecisionDriver>;
|
|
49
|
+
/** @internal Exported for task 0086 R9 branch tests; see {@link resolveLayaDriver}. */
|
|
50
|
+
export declare function resolveFmDriver(options: DecisionMakerOptions, importModule?: (specifier: string) => Promise<unknown>): Promise<DecisionDriver>;
|
|
43
51
|
/**
|
|
44
52
|
* Build a DecisionMaker. `options.driver` wins when supplied; otherwise `options.backend`
|
|
45
53
|
* resolves the driver (default `'typesafe'`). The driver is constructed lazily on first use.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decision-maker.d.ts","sourceRoot":"","sources":["../../src/decision/decision-maker.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACR,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,WAAW,EACd,MAAM,SAAS,CAAC;AAKjB,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE;QAC/C,KAAK,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,CAAC,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,yEAAyE;IACzE,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EACzB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GACxB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,gFAAgF;IAChF,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1G,wEAAwE;IACxE,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,IAAI,CAAC;QAAC,EAAE,CAAC,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACxG;AAED,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,CAAC;AAErE,qFAAqF;AACrF,MAAM,WAAW,oBAAoB;IACjC,oHAAoH;IACpH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,4GAA4G;IAC5G,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"decision-maker.d.ts","sourceRoot":"","sources":["../../src/decision/decision-maker.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACR,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,WAAW,EACd,MAAM,SAAS,CAAC;AAKjB,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE;QAC/C,KAAK,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,CAAC,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,yEAAyE;IACzE,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EACzB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GACxB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,gFAAgF;IAChF,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1G,wEAAwE;IACxE,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,IAAI,CAAC;QAAC,EAAE,CAAC,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACxG;AAED,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,CAAC;AAErE,qFAAqF;AACrF,MAAM,WAAW,oBAAoB;IACjC,oHAAoH;IACpH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,4GAA4G;IAC5G,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAoBD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACnC,OAAO,EAAE,oBAAoB,EAC7B,YAAY,GAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAoC,GACzF,OAAO,CAAC,cAAc,CAAC,CAuBzB;AAID,uFAAuF;AACvF,wBAAsB,eAAe,CACjC,OAAO,EAAE,oBAAoB,EAC7B,YAAY,GAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAoC,GACzF,OAAO,CAAC,cAAc,CAAC,CAkBzB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAwDrF"}
|
|
@@ -22,30 +22,42 @@ function resolveApiKey(options) {
|
|
|
22
22
|
return apiKey;
|
|
23
23
|
}
|
|
24
24
|
const LAYA_DRIVER_PACKAGE = '@gobing-ai/ts-laya-mlx';
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* @internal Exported for task 0086 R9 branch tests: `importModule` lets tests
|
|
27
|
+
* simulate package-import failures that cannot occur in-workspace (workspace
|
|
28
|
+
* links always resolve).
|
|
29
|
+
*/
|
|
30
|
+
export async function resolveLayaDriver(options, importModule = (specifier) => import(specifier)) {
|
|
31
|
+
// Task 0086 R9: only the IMPORT is translated to the install-hint error;
|
|
32
|
+
// construction errors from the factory itself propagate unchanged so the
|
|
33
|
+
// caller sees the real cause instead of a misleading install message.
|
|
34
|
+
let mod;
|
|
26
35
|
try {
|
|
27
|
-
|
|
28
|
-
if (typeof mod.createLayaDriver !== 'function') {
|
|
29
|
-
throw new Error(`Module '${LAYA_DRIVER_PACKAGE}' does not export createLayaDriver`);
|
|
30
|
-
}
|
|
31
|
-
return mod.createLayaDriver(options);
|
|
36
|
+
mod = (await importModule(LAYA_DRIVER_PACKAGE));
|
|
32
37
|
}
|
|
33
38
|
catch (cause) {
|
|
34
39
|
throw new DecisionConfigError(`The 'laya-local' backend requires '${LAYA_DRIVER_PACKAGE}' to be installed; install it with 'bun add ${LAYA_DRIVER_PACKAGE}'`, 'LAYA_BACKEND', { cause });
|
|
35
40
|
}
|
|
41
|
+
if (typeof mod.createLayaDriver !== 'function') {
|
|
42
|
+
throw new DecisionConfigError(`Module '${LAYA_DRIVER_PACKAGE}' does not export createLayaDriver`, 'LAYA_BACKEND');
|
|
43
|
+
}
|
|
44
|
+
return mod.createLayaDriver(options);
|
|
36
45
|
}
|
|
37
46
|
const FM_DRIVER_PACKAGE = '@gobing-ai/ts-decision-fm';
|
|
38
|
-
|
|
47
|
+
/** @internal Exported for task 0086 R9 branch tests; see {@link resolveLayaDriver}. */
|
|
48
|
+
export async function resolveFmDriver(options, importModule = (specifier) => import(specifier)) {
|
|
49
|
+
// Task 0086 R9: same import/construction split as laya above.
|
|
50
|
+
let mod;
|
|
39
51
|
try {
|
|
40
|
-
|
|
41
|
-
if (typeof mod.createFmDriver !== 'function') {
|
|
42
|
-
throw new Error(`Module '${FM_DRIVER_PACKAGE}' does not export createFmDriver`);
|
|
43
|
-
}
|
|
44
|
-
return mod.createFmDriver(options);
|
|
52
|
+
mod = (await importModule(FM_DRIVER_PACKAGE));
|
|
45
53
|
}
|
|
46
54
|
catch (cause) {
|
|
47
55
|
throw new DecisionConfigError(`The 'fm-local' backend requires '${FM_DRIVER_PACKAGE}' to be installed; install it with 'bun add ${FM_DRIVER_PACKAGE}'`, 'FM_BACKEND', { cause });
|
|
48
56
|
}
|
|
57
|
+
if (typeof mod.createFmDriver !== 'function') {
|
|
58
|
+
throw new DecisionConfigError(`Module '${FM_DRIVER_PACKAGE}' does not export createFmDriver`, 'FM_BACKEND');
|
|
59
|
+
}
|
|
60
|
+
return mod.createFmDriver(options);
|
|
49
61
|
}
|
|
50
62
|
/**
|
|
51
63
|
* Build a DecisionMaker. `options.driver` wins when supplied; otherwise `options.backend`
|
package/dist/identity.d.ts
CHANGED
|
@@ -32,7 +32,8 @@ export declare function getGitContext(workspacePath: string, executor?: ProcessE
|
|
|
32
32
|
* Query git for the current branch name and dirty file count synchronously.
|
|
33
33
|
*
|
|
34
34
|
* @deprecated Use the async {@link getGitContext} instead. Kept for one release for sync callers.
|
|
35
|
-
* Defaults to
|
|
35
|
+
* Defaults to {@link NodeSyncProcessExecutor} (task 0087 R7 migrated the default off the
|
|
36
|
+
* deprecated BunSyncProcessExecutor).
|
|
36
37
|
*/
|
|
37
38
|
export declare function getGitContextSync(workspacePath: string, executor?: SyncProcessExecutor): string | null;
|
|
38
39
|
//# sourceMappingURL=identity.d.ts.map
|
package/dist/identity.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAC3B,MAAM,uBAAuB,CAAC;AAE/B,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,8HAA8H;AAC9H,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CA8ClE;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAC/B,aAAa,EAAE,MAAM,EACrB,QAAQ,GAAE,eAAwD,GACnE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB;AAED
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAC3B,MAAM,uBAAuB,CAAC;AAE/B,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,8HAA8H;AAC9H,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CA8ClE;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAC/B,aAAa,EAAE,MAAM,EACrB,QAAQ,GAAE,eAAwD,GACnE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC7B,aAAa,EAAE,MAAM,EACrB,QAAQ,GAAE,mBAAmD,GAC9D,MAAM,GAAG,IAAI,CASf"}
|
package/dist/identity.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NodeSyncProcessExecutor, nodeBunFactory, } from '@gobing-ai/ts-runtime';
|
|
2
2
|
/** Build a human-readable identity preamble string that describes the agent, its task, peers, guardrails, and git context. */
|
|
3
3
|
export function buildIdentityPreamble(ctx) {
|
|
4
4
|
const sections = [
|
|
@@ -52,9 +52,10 @@ export async function getGitContext(workspacePath, executor = nodeBunFactory.cre
|
|
|
52
52
|
* Query git for the current branch name and dirty file count synchronously.
|
|
53
53
|
*
|
|
54
54
|
* @deprecated Use the async {@link getGitContext} instead. Kept for one release for sync callers.
|
|
55
|
-
* Defaults to
|
|
55
|
+
* Defaults to {@link NodeSyncProcessExecutor} (task 0087 R7 migrated the default off the
|
|
56
|
+
* deprecated BunSyncProcessExecutor).
|
|
56
57
|
*/
|
|
57
|
-
export function getGitContextSync(workspacePath, executor = new
|
|
58
|
+
export function getGitContextSync(workspacePath, executor = new NodeSyncProcessExecutor()) {
|
|
58
59
|
const branch = runGitSync(executor, ['-C', workspacePath, 'branch', '--show-current']);
|
|
59
60
|
if (branch === null || branch === '')
|
|
60
61
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/ts-ai-runner",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "@gobing-ai/ts-ai-runner — Coding-agent shims, detection, doctor checks, and prompt execution.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
"release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-ai-runner-v<version> && git push --tags' && exit 1"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@gobing-ai/ts-infra": "^0.5.
|
|
51
|
-
"@gobing-ai/ts-runtime": "^0.5.
|
|
50
|
+
"@gobing-ai/ts-infra": "^0.5.5",
|
|
51
|
+
"@gobing-ai/ts-runtime": "^0.5.5",
|
|
52
52
|
"@typesafe-ai/sdk": "0.6.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/bun": "1.3.14",
|
|
56
|
-
"@gobing-ai/ts-db": "^0.5.
|
|
56
|
+
"@gobing-ai/ts-db": "^0.5.5"
|
|
57
57
|
},
|
|
58
58
|
"publishConfig": {
|
|
59
59
|
"access": "public"
|
package/src/agent-spec.ts
CHANGED
|
@@ -42,6 +42,21 @@ export function validateAgentId(id: string): string {
|
|
|
42
42
|
return id;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Validate a caller-supplied session id before it is used in a filesystem path
|
|
47
|
+
* (task 0086 R15): 1-128 chars, starting alphanumeric, then alnum/`.`/`_`/`-`,
|
|
48
|
+
* and never containing `..`. Returns the id on success, throws `ValueError`
|
|
49
|
+
* otherwise — failing closed beats sanitizing attacker-controlled path input.
|
|
50
|
+
*/
|
|
51
|
+
export function assertSafeSessionId(id: string): string {
|
|
52
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(id) || id.includes('..')) {
|
|
53
|
+
throw new ValueError(
|
|
54
|
+
`Invalid session id "${id}": expected 1-128 chars (alphanumeric, ".", "_", "-", starting alphanumeric) without path separators or ".."`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return id;
|
|
58
|
+
}
|
|
59
|
+
|
|
45
60
|
/** Load and validate all YAML agent spec files from `configDir`. Throws `ValueError` on parse failures or duplicate IDs. */
|
|
46
61
|
export async function loadAgentSpecs(configDir: string, fs: FileSystem = createNodeFileSystem()): Promise<AgentSpec[]> {
|
|
47
62
|
const entries = (await safeReadDir(configDir, fs))
|
package/src/agents/shims.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getLogger } from '@gobing-ai/ts-infra';
|
|
2
2
|
import { joinPath } from '@gobing-ai/ts-runtime';
|
|
3
|
+
import { assertSafeSessionId } from '../agent-spec';
|
|
3
4
|
|
|
4
5
|
/** Identifier for one supported coding agent (canonical id). */
|
|
5
6
|
export type AgentName =
|
|
@@ -459,15 +460,17 @@ const fmShim: AgentShim = {
|
|
|
459
460
|
// and suppress any unscoped continue. `continue` alone degrades to a
|
|
460
461
|
// fresh call — fm has no implicit last-session flag.
|
|
461
462
|
if (options.sessionId !== undefined) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
463
|
+
// Task 0086 R15: sessionId lands in a filesystem path — validate it
|
|
464
|
+
// before it can escape sessionDir via separators or traversal.
|
|
465
|
+
const id = assertSafeSessionId(options.sessionId);
|
|
466
|
+
const file = options.sessionDir !== undefined ? joinPath(options.sessionDir, `${id}.json`) : `${id}.json`;
|
|
466
467
|
args.push('--resume', file, '--save-transcript', file);
|
|
467
468
|
} else if (options.sessionDir !== undefined) {
|
|
468
469
|
args.push('--save-transcript', joinPath(options.sessionDir, 'fm-session.json'));
|
|
469
470
|
}
|
|
470
|
-
|
|
471
|
+
// Task 0086 R4: `--` pins the input as a positional, so dash-leading
|
|
472
|
+
// prompts (--help, -n) are never reparsed as fm flags.
|
|
473
|
+
args.push('--', options.input ?? '');
|
|
471
474
|
return { command: 'fm', args };
|
|
472
475
|
},
|
|
473
476
|
getAuthCommand: () => ({ command: 'fm', args: ['available', '--model', 'system'] }),
|
|
@@ -83,15 +83,23 @@ function resolveApiKey(options: DecisionMakerOptions): string {
|
|
|
83
83
|
|
|
84
84
|
const LAYA_DRIVER_PACKAGE = '@gobing-ai/ts-laya-mlx';
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
/**
|
|
87
|
+
* @internal Exported for task 0086 R9 branch tests: `importModule` lets tests
|
|
88
|
+
* simulate package-import failures that cannot occur in-workspace (workspace
|
|
89
|
+
* links always resolve).
|
|
90
|
+
*/
|
|
91
|
+
export async function resolveLayaDriver(
|
|
92
|
+
options: DecisionMakerOptions,
|
|
93
|
+
importModule: (specifier: string) => Promise<unknown> = (specifier) => import(specifier),
|
|
94
|
+
): Promise<DecisionDriver> {
|
|
95
|
+
// Task 0086 R9: only the IMPORT is translated to the install-hint error;
|
|
96
|
+
// construction errors from the factory itself propagate unchanged so the
|
|
97
|
+
// caller sees the real cause instead of a misleading install message.
|
|
98
|
+
let mod: { createLayaDriver?: (opts?: unknown) => DecisionDriver };
|
|
87
99
|
try {
|
|
88
|
-
|
|
100
|
+
mod = (await importModule(LAYA_DRIVER_PACKAGE)) as {
|
|
89
101
|
createLayaDriver?: (opts?: unknown) => DecisionDriver;
|
|
90
102
|
};
|
|
91
|
-
if (typeof mod.createLayaDriver !== 'function') {
|
|
92
|
-
throw new Error(`Module '${LAYA_DRIVER_PACKAGE}' does not export createLayaDriver`);
|
|
93
|
-
}
|
|
94
|
-
return mod.createLayaDriver(options);
|
|
95
103
|
} catch (cause) {
|
|
96
104
|
throw new DecisionConfigError(
|
|
97
105
|
`The 'laya-local' backend requires '${LAYA_DRIVER_PACKAGE}' to be installed; install it with 'bun add ${LAYA_DRIVER_PACKAGE}'`,
|
|
@@ -99,19 +107,28 @@ async function resolveLayaDriver(options: DecisionMakerOptions): Promise<Decisio
|
|
|
99
107
|
{ cause },
|
|
100
108
|
);
|
|
101
109
|
}
|
|
110
|
+
if (typeof mod.createLayaDriver !== 'function') {
|
|
111
|
+
throw new DecisionConfigError(
|
|
112
|
+
`Module '${LAYA_DRIVER_PACKAGE}' does not export createLayaDriver`,
|
|
113
|
+
'LAYA_BACKEND',
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return mod.createLayaDriver(options);
|
|
102
117
|
}
|
|
103
118
|
|
|
104
119
|
const FM_DRIVER_PACKAGE = '@gobing-ai/ts-decision-fm';
|
|
105
120
|
|
|
106
|
-
|
|
121
|
+
/** @internal Exported for task 0086 R9 branch tests; see {@link resolveLayaDriver}. */
|
|
122
|
+
export async function resolveFmDriver(
|
|
123
|
+
options: DecisionMakerOptions,
|
|
124
|
+
importModule: (specifier: string) => Promise<unknown> = (specifier) => import(specifier),
|
|
125
|
+
): Promise<DecisionDriver> {
|
|
126
|
+
// Task 0086 R9: same import/construction split as laya above.
|
|
127
|
+
let mod: { createFmDriver?: (opts?: unknown) => DecisionDriver };
|
|
107
128
|
try {
|
|
108
|
-
|
|
129
|
+
mod = (await importModule(FM_DRIVER_PACKAGE)) as {
|
|
109
130
|
createFmDriver?: (opts?: unknown) => DecisionDriver;
|
|
110
131
|
};
|
|
111
|
-
if (typeof mod.createFmDriver !== 'function') {
|
|
112
|
-
throw new Error(`Module '${FM_DRIVER_PACKAGE}' does not export createFmDriver`);
|
|
113
|
-
}
|
|
114
|
-
return mod.createFmDriver(options);
|
|
115
132
|
} catch (cause) {
|
|
116
133
|
throw new DecisionConfigError(
|
|
117
134
|
`The 'fm-local' backend requires '${FM_DRIVER_PACKAGE}' to be installed; install it with 'bun add ${FM_DRIVER_PACKAGE}'`,
|
|
@@ -119,6 +136,10 @@ async function resolveFmDriver(options: DecisionMakerOptions): Promise<DecisionD
|
|
|
119
136
|
{ cause },
|
|
120
137
|
);
|
|
121
138
|
}
|
|
139
|
+
if (typeof mod.createFmDriver !== 'function') {
|
|
140
|
+
throw new DecisionConfigError(`Module '${FM_DRIVER_PACKAGE}' does not export createFmDriver`, 'FM_BACKEND');
|
|
141
|
+
}
|
|
142
|
+
return mod.createFmDriver(options);
|
|
122
143
|
}
|
|
123
144
|
|
|
124
145
|
/**
|
package/src/identity.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
NodeSyncProcessExecutor,
|
|
3
3
|
nodeBunFactory,
|
|
4
4
|
type ProcessExecutor,
|
|
5
5
|
type SyncProcessExecutor,
|
|
@@ -95,11 +95,12 @@ export async function getGitContext(
|
|
|
95
95
|
* Query git for the current branch name and dirty file count synchronously.
|
|
96
96
|
*
|
|
97
97
|
* @deprecated Use the async {@link getGitContext} instead. Kept for one release for sync callers.
|
|
98
|
-
* Defaults to
|
|
98
|
+
* Defaults to {@link NodeSyncProcessExecutor} (task 0087 R7 migrated the default off the
|
|
99
|
+
* deprecated BunSyncProcessExecutor).
|
|
99
100
|
*/
|
|
100
101
|
export function getGitContextSync(
|
|
101
102
|
workspacePath: string,
|
|
102
|
-
executor: SyncProcessExecutor = new
|
|
103
|
+
executor: SyncProcessExecutor = new NodeSyncProcessExecutor(),
|
|
103
104
|
): string | null {
|
|
104
105
|
const branch = runGitSync(executor, ['-C', workspacePath, 'branch', '--show-current']);
|
|
105
106
|
if (branch === null || branch === '') return null;
|