@gobing-ai/ts-ai-runner 0.2.3 → 0.2.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-detector.js +1 -1
- package/dist/doctor-runner.d.ts +2 -0
- package/dist/doctor-runner.d.ts.map +1 -1
- package/dist/doctor-runner.js +19 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/slash-command.d.ts +16 -0
- package/dist/slash-command.d.ts.map +1 -0
- package/dist/slash-command.js +39 -0
- package/package.json +2 -2
- package/src/agent-detector.ts +1 -1
- package/src/doctor-runner.ts +20 -3
- package/src/index.ts +1 -0
- package/src/slash-command.ts +42 -0
package/dist/agent-detector.js
CHANGED
package/dist/doctor-runner.d.ts
CHANGED
|
@@ -44,5 +44,7 @@ export declare class DoctorRunner {
|
|
|
44
44
|
runOne(agent: string): Promise<DoctorResult>;
|
|
45
45
|
private buildResult;
|
|
46
46
|
private checkAuth;
|
|
47
|
+
/** True when the path exists and has a non-zero size. */
|
|
48
|
+
private hasNonEmptyFile;
|
|
47
49
|
}
|
|
48
50
|
//# sourceMappingURL=doctor-runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-runner.d.ts","sourceRoot":"","sources":["../src/doctor-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAsB,MAAM,kBAAkB,CAAC;AAErE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,gDAAgD;AAChD,MAAM,WAAW,YAAY;IACzB,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+CAA+C;IAC/C,aAAa,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,MAAM,EAAE,OAAO,CAAC;IAChB,oEAAoE;IACpE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;IACZ,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IAChC,uBAAuB;IACvB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,qBAAqB;IACrB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC5C;
|
|
1
|
+
{"version":3,"file":"doctor-runner.d.ts","sourceRoot":"","sources":["../src/doctor-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAsB,MAAM,kBAAkB,CAAC;AAErE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,gDAAgD;AAChD,MAAM,WAAW,YAAY;IACzB,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+CAA+C;IAC/C,aAAa,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,MAAM,EAAE,OAAO,CAAC;IAChB,oEAAoE;IACpE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;IACZ,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IAChC,uBAAuB;IACvB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,qBAAqB;IACrB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC5C;AASD,4EAA4E;AAC5E,qBAAa,YAAY;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAqC;IACzD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAwB;gBAE/B,OAAO,GAAE,mBAAwB;IAO7C,kDAAkD;IAC5C,MAAM,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAKvC,uCAAuC;IACjC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;YAIpC,WAAW;YAgBX,SAAS;IAmBvB,yDAAyD;YAC3C,eAAe;CAKhC"}
|
package/dist/doctor-runner.js
CHANGED
|
@@ -5,6 +5,10 @@ import { AgentDetector } from './agent-detector.js';
|
|
|
5
5
|
import { isAgentName, TIER2_AGENTS } from './agents/shims.js';
|
|
6
6
|
import { AiRunner } from './ai-runner.js';
|
|
7
7
|
const DEFAULT_TIMEOUT_MS = 5_000;
|
|
8
|
+
/** True when a value is a defined, non-blank string. */
|
|
9
|
+
function isNonEmpty(value) {
|
|
10
|
+
return value !== undefined && value.trim().length > 0;
|
|
11
|
+
}
|
|
8
12
|
/** Runs installation and auth health checks for supported coding agents. */
|
|
9
13
|
export class DoctorRunner {
|
|
10
14
|
detector;
|
|
@@ -42,11 +46,16 @@ export class DoctorRunner {
|
|
|
42
46
|
};
|
|
43
47
|
}
|
|
44
48
|
async checkAuth(agent) {
|
|
49
|
+
// gemini/codex expose no auth-status command; treat a non-empty credential
|
|
50
|
+
// file as authenticated. An empty/zero-byte file is a stale-credential
|
|
51
|
+
// false positive, so existence alone is insufficient.
|
|
45
52
|
if (agent === 'gemini')
|
|
46
|
-
return this.
|
|
47
|
-
if (agent === 'codex' && (await this.
|
|
53
|
+
return this.hasNonEmptyFile(join(homedir(), '.gemini', 'settings.json'));
|
|
54
|
+
if (agent === 'codex' && (await this.hasNonEmptyFile(join(homedir(), '.codex', 'auth.json'))))
|
|
48
55
|
return true;
|
|
49
|
-
|
|
56
|
+
// pi reads provider keys from the environment; require a non-empty value
|
|
57
|
+
// rather than mere presence (an empty export is not a usable credential).
|
|
58
|
+
if (agent === 'pi' && (isNonEmpty(this.env.GOOGLE_API_KEY) || isNonEmpty(this.env.ANTHROPIC_API_KEY)))
|
|
50
59
|
return true;
|
|
51
60
|
const command = this.runner.runAuthCommand(agent, { timeout: this.timeout });
|
|
52
61
|
if (command === null)
|
|
@@ -55,4 +64,11 @@ export class DoctorRunner {
|
|
|
55
64
|
return (result.exitCode === 0 &&
|
|
56
65
|
!/not authenticated|not logged|unauthenticated/i.test(`${result.stdout}\n${result.stderr}`));
|
|
57
66
|
}
|
|
67
|
+
/** True when the path exists and has a non-zero size. */
|
|
68
|
+
async hasNonEmptyFile(path) {
|
|
69
|
+
const stat = await this.fs.stat(path);
|
|
70
|
+
if (stat === null)
|
|
71
|
+
return false;
|
|
72
|
+
return stat.isFile() && stat.size > 0;
|
|
73
|
+
}
|
|
58
74
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentName } from './agents/shims';
|
|
2
|
+
/** Whether the input is a Claude-style `/plugin:command` slash command. */
|
|
3
|
+
export declare function isClaudeStyleSlashCommand(input: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Translate a Claude-style `/plugin:command args` into the target agent's
|
|
6
|
+
* slash-command dialect. Non-slash-command input is returned unchanged.
|
|
7
|
+
*
|
|
8
|
+
* | Agent | `/plugin:command args` becomes |
|
|
9
|
+
* |------------|---------------------------------------|
|
|
10
|
+
* | claude | `/plugin:command args` (pass-through) |
|
|
11
|
+
* | codex | `$plugin-command args` |
|
|
12
|
+
* | pi | `/skill:plugin-command args` |
|
|
13
|
+
* | all others | `/plugin-command args` |
|
|
14
|
+
*/
|
|
15
|
+
export declare function translateSlashCommand(agent: AgentName, input: string): string;
|
|
16
|
+
//# sourceMappingURL=slash-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slash-command.d.ts","sourceRoot":"","sources":["../src/slash-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAShD,2EAA2E;AAC3E,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAgB7E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matches a Claude-style slash command: `/plugin:command [args]`.
|
|
3
|
+
*
|
|
4
|
+
* Captures the plugin namespace, the command, and any trailing argument text.
|
|
5
|
+
*/
|
|
6
|
+
const SLASH_COMMAND_RE = /^\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]+)(\s.*)?$/;
|
|
7
|
+
/** Whether the input is a Claude-style `/plugin:command` slash command. */
|
|
8
|
+
export function isClaudeStyleSlashCommand(input) {
|
|
9
|
+
return SLASH_COMMAND_RE.test(input);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Translate a Claude-style `/plugin:command args` into the target agent's
|
|
13
|
+
* slash-command dialect. Non-slash-command input is returned unchanged.
|
|
14
|
+
*
|
|
15
|
+
* | Agent | `/plugin:command args` becomes |
|
|
16
|
+
* |------------|---------------------------------------|
|
|
17
|
+
* | claude | `/plugin:command args` (pass-through) |
|
|
18
|
+
* | codex | `$plugin-command args` |
|
|
19
|
+
* | pi | `/skill:plugin-command args` |
|
|
20
|
+
* | all others | `/plugin-command args` |
|
|
21
|
+
*/
|
|
22
|
+
export function translateSlashCommand(agent, input) {
|
|
23
|
+
const match = SLASH_COMMAND_RE.exec(input);
|
|
24
|
+
if (!match)
|
|
25
|
+
return input;
|
|
26
|
+
const [, plugin, command, rest = ''] = match;
|
|
27
|
+
const args = rest.trimStart();
|
|
28
|
+
const suffix = args.length > 0 ? ` ${args}` : '';
|
|
29
|
+
switch (agent) {
|
|
30
|
+
case 'claude':
|
|
31
|
+
return `/${plugin}:${command}${suffix}`;
|
|
32
|
+
case 'codex':
|
|
33
|
+
return `$${plugin}-${command}${suffix}`;
|
|
34
|
+
case 'pi':
|
|
35
|
+
return `/skill:${plugin}-${command}${suffix}`;
|
|
36
|
+
default:
|
|
37
|
+
return `/${plugin}-${command}${suffix}`;
|
|
38
|
+
}
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/ts-ai-runner",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.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,7 +47,7 @@
|
|
|
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-runtime": "^0.2.
|
|
50
|
+
"@gobing-ai/ts-runtime": "^0.2.5"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/bun": "1.3.14"
|
package/src/agent-detector.ts
CHANGED
package/src/doctor-runner.ts
CHANGED
|
@@ -39,6 +39,11 @@ export interface DoctorRunnerOptions {
|
|
|
39
39
|
|
|
40
40
|
const DEFAULT_TIMEOUT_MS = 5_000;
|
|
41
41
|
|
|
42
|
+
/** True when a value is a defined, non-blank string. */
|
|
43
|
+
function isNonEmpty(value: string | undefined): boolean {
|
|
44
|
+
return value !== undefined && value.trim().length > 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
/** Runs installation and auth health checks for supported coding agents. */
|
|
43
48
|
export class DoctorRunner {
|
|
44
49
|
private readonly detector: AgentDetector;
|
|
@@ -82,9 +87,14 @@ export class DoctorRunner {
|
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
private async checkAuth(agent: AgentName): Promise<boolean> {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
// gemini/codex expose no auth-status command; treat a non-empty credential
|
|
91
|
+
// file as authenticated. An empty/zero-byte file is a stale-credential
|
|
92
|
+
// false positive, so existence alone is insufficient.
|
|
93
|
+
if (agent === 'gemini') return this.hasNonEmptyFile(join(homedir(), '.gemini', 'settings.json'));
|
|
94
|
+
if (agent === 'codex' && (await this.hasNonEmptyFile(join(homedir(), '.codex', 'auth.json')))) return true;
|
|
95
|
+
// pi reads provider keys from the environment; require a non-empty value
|
|
96
|
+
// rather than mere presence (an empty export is not a usable credential).
|
|
97
|
+
if (agent === 'pi' && (isNonEmpty(this.env.GOOGLE_API_KEY) || isNonEmpty(this.env.ANTHROPIC_API_KEY)))
|
|
88
98
|
return true;
|
|
89
99
|
const command = this.runner.runAuthCommand(agent, { timeout: this.timeout });
|
|
90
100
|
if (command === null) return false;
|
|
@@ -94,4 +104,11 @@ export class DoctorRunner {
|
|
|
94
104
|
!/not authenticated|not logged|unauthenticated/i.test(`${result.stdout}\n${result.stderr}`)
|
|
95
105
|
);
|
|
96
106
|
}
|
|
107
|
+
|
|
108
|
+
/** True when the path exists and has a non-zero size. */
|
|
109
|
+
private async hasNonEmptyFile(path: string): Promise<boolean> {
|
|
110
|
+
const stat = await this.fs.stat(path);
|
|
111
|
+
if (stat === null) return false;
|
|
112
|
+
return stat.isFile() && stat.size > 0;
|
|
113
|
+
}
|
|
97
114
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { AgentName } from './agents/shims';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Matches a Claude-style slash command: `/plugin:command [args]`.
|
|
5
|
+
*
|
|
6
|
+
* Captures the plugin namespace, the command, and any trailing argument text.
|
|
7
|
+
*/
|
|
8
|
+
const SLASH_COMMAND_RE = /^\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]+)(\s.*)?$/;
|
|
9
|
+
|
|
10
|
+
/** Whether the input is a Claude-style `/plugin:command` slash command. */
|
|
11
|
+
export function isClaudeStyleSlashCommand(input: string): boolean {
|
|
12
|
+
return SLASH_COMMAND_RE.test(input);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Translate a Claude-style `/plugin:command args` into the target agent's
|
|
17
|
+
* slash-command dialect. Non-slash-command input is returned unchanged.
|
|
18
|
+
*
|
|
19
|
+
* | Agent | `/plugin:command args` becomes |
|
|
20
|
+
* |------------|---------------------------------------|
|
|
21
|
+
* | claude | `/plugin:command args` (pass-through) |
|
|
22
|
+
* | codex | `$plugin-command args` |
|
|
23
|
+
* | pi | `/skill:plugin-command args` |
|
|
24
|
+
* | all others | `/plugin-command args` |
|
|
25
|
+
*/
|
|
26
|
+
export function translateSlashCommand(agent: AgentName, input: string): string {
|
|
27
|
+
const match = SLASH_COMMAND_RE.exec(input);
|
|
28
|
+
if (!match) return input;
|
|
29
|
+
const [, plugin, command, rest = ''] = match;
|
|
30
|
+
const args = rest.trimStart();
|
|
31
|
+
const suffix = args.length > 0 ? ` ${args}` : '';
|
|
32
|
+
switch (agent) {
|
|
33
|
+
case 'claude':
|
|
34
|
+
return `/${plugin}:${command}${suffix}`;
|
|
35
|
+
case 'codex':
|
|
36
|
+
return `$${plugin}-${command}${suffix}`;
|
|
37
|
+
case 'pi':
|
|
38
|
+
return `/skill:${plugin}-${command}${suffix}`;
|
|
39
|
+
default:
|
|
40
|
+
return `/${plugin}-${command}${suffix}`;
|
|
41
|
+
}
|
|
42
|
+
}
|