@gobing-ai/ts-ai-runner 0.2.8 → 0.3.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 +150 -2
- package/dist/agent-detector.d.ts.map +1 -1
- package/dist/agent-detector.js +11 -38
- package/dist/agent-spec.d.ts +19 -0
- package/dist/agent-spec.d.ts.map +1 -0
- package/dist/agent-spec.js +96 -0
- package/dist/agents/shims.d.ts +14 -0
- package/dist/agents/shims.d.ts.map +1 -1
- package/dist/ai-runner.d.ts +1 -0
- package/dist/ai-runner.d.ts.map +1 -1
- package/dist/ai-runner.js +25 -1
- package/dist/identity.d.ts +21 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +50 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/message-service.d.ts +13 -0
- package/dist/message-service.d.ts.map +1 -0
- package/dist/message-service.js +27 -0
- package/dist/team-agent-process.d.ts +36 -0
- package/dist/team-agent-process.d.ts.map +1 -0
- package/dist/team-agent-process.js +125 -0
- package/dist/team-orchestrator.d.ts +36 -0
- package/dist/team-orchestrator.d.ts.map +1 -0
- package/dist/team-orchestrator.js +131 -0
- package/package.json +4 -2
- package/src/agent-detector.ts +11 -38
- package/src/agent-spec.ts +128 -0
- package/src/agents/shims.ts +10 -0
- package/src/ai-runner.ts +38 -1
- package/src/identity.ts +86 -0
- package/src/index.ts +5 -0
- package/src/message-service.ts +33 -0
- package/src/team-agent-process.ts +133 -0
- package/src/team-orchestrator.ts +148 -0
package/README.md
CHANGED
|
@@ -13,6 +13,11 @@ Coding-agent command shims, installation detection, doctor checks, slash-command
|
|
|
13
13
|
| `DoctorRunner` | Combines installation and authentication checks into a usability report |
|
|
14
14
|
| `getAgentShim()` | Returns the pure command builder for one supported agent |
|
|
15
15
|
| `translateSlashCommand()` | Converts Claude-style `/plugin:command` inputs to each agent's dialect |
|
|
16
|
+
| `buildIdentityPreamble()` | Builds team-mode identity and communication context for prompts |
|
|
17
|
+
| `loadAgentSpecs()` / `saveAgentSpec()` | Persist agent definitions as YAML-compatible config |
|
|
18
|
+
| `MessageService` | Thin service wrapper around `@gobing-ai/ts-db/inbox` |
|
|
19
|
+
| `TeamAgentProcess` | Manages a long-running agent subprocess with pipe-mode stdin/stdout |
|
|
20
|
+
| `TeamOrchestrator` | Loads specs, starts/stops agents, and routes durable/live messages |
|
|
16
21
|
|
|
17
22
|
Supported agent identifiers are `claude`, `codex`, `gemini`, `pi`, `opencode`, `antigravity`, and `openclaw`.
|
|
18
23
|
|
|
@@ -22,7 +27,7 @@ Supported agent identifiers are `claude`, `codex`, `gemini`, `pi`, `opencode`, `
|
|
|
22
27
|
bun add @gobing-ai/ts-ai-runner
|
|
23
28
|
```
|
|
24
29
|
|
|
25
|
-
The package depends on `@gobing-ai/ts-runtime` for process execution. The target agent CLIs are not bundled; install them separately in the host environment.
|
|
30
|
+
The package depends on `@gobing-ai/ts-runtime` for process execution and `@gobing-ai/ts-db` for team-mode inbox types. The target agent CLIs are not bundled; install them separately in the host environment.
|
|
26
31
|
|
|
27
32
|
## Detect Installed Agents
|
|
28
33
|
|
|
@@ -73,6 +78,41 @@ console.log(result.stdout);
|
|
|
73
78
|
|
|
74
79
|
`AiRunner` captures `stdout`, `stderr`, `exitCode`, optional termination `signal`, and `durationMs`. It does not throw on non-zero agent exits; callers decide how to handle failures.
|
|
75
80
|
|
|
81
|
+
### Team identity preambles
|
|
82
|
+
|
|
83
|
+
`PromptOptions` accepts optional team-mode fields. When any of `purpose`, `systemPrompt`, `taskId`,
|
|
84
|
+
or non-empty `peers` is supplied, `AiRunner` prepends an identity preamble before dispatching the
|
|
85
|
+
prompt through the selected agent shim. Existing callers that only pass `input`, `continue`, `model`,
|
|
86
|
+
or `mode` are unchanged.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
await runner.runPromptCommand('codex', {
|
|
90
|
+
input: 'Implement the inbox DAO tests',
|
|
91
|
+
taskId: '0005',
|
|
92
|
+
purpose: 'Implement scoped code changes',
|
|
93
|
+
systemPrompt: 'Follow repository AGENTS.md rules.',
|
|
94
|
+
peers: [{ id: 'planner', type: 'claude', purpose: 'Plan implementation work' }],
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Use `buildIdentityPreamble()` directly when a host app needs to preview or inject the same context
|
|
99
|
+
outside `AiRunner`:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { buildIdentityPreamble } from '@gobing-ai/ts-ai-runner';
|
|
103
|
+
|
|
104
|
+
const preamble = buildIdentityPreamble({
|
|
105
|
+
agentId: 'coder',
|
|
106
|
+
agentType: 'codex',
|
|
107
|
+
workspace: '/workspace/spur',
|
|
108
|
+
taskId: '0005',
|
|
109
|
+
taskTitle: 'Implement team mode primitives',
|
|
110
|
+
purpose: 'Make focused code changes',
|
|
111
|
+
peers: [{ id: 'reviewer', type: 'claude', purpose: 'Review correctness and risk' }],
|
|
112
|
+
guardrails: ['Do not commit without operator approval.'],
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
76
116
|
## Inject a Process Executor
|
|
77
117
|
|
|
78
118
|
For tests, dry runs, or sandboxed launchers, inject a `ProcessExecutor` from `@gobing-ai/ts-runtime`:
|
|
@@ -159,9 +199,117 @@ console.log(command.command, command.args);
|
|
|
159
199
|
|
|
160
200
|
This is the right layer for UI previews, audit logging, and custom launchers.
|
|
161
201
|
|
|
202
|
+
## Team Mode Primitives
|
|
203
|
+
|
|
204
|
+
The team-mode APIs are intentionally small building blocks. They do not implement an HTTP API,
|
|
205
|
+
dashboard, or product workflow; downstream apps compose them into their own orchestration layer.
|
|
206
|
+
|
|
207
|
+
### Agent specs
|
|
208
|
+
|
|
209
|
+
Agent specs define agents as config. The built-in parser supports the repository's constrained YAML
|
|
210
|
+
subset: scalars, arrays, nested objects, and no anchors/tags/multiline scalars.
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { loadAgentSpecs, saveAgentSpec } from '@gobing-ai/ts-ai-runner';
|
|
214
|
+
|
|
215
|
+
await saveAgentSpec(
|
|
216
|
+
{
|
|
217
|
+
id: 'coder',
|
|
218
|
+
name: 'Coder',
|
|
219
|
+
type: 'codex',
|
|
220
|
+
workspace: '/workspace/spur',
|
|
221
|
+
purpose: 'Implement scoped code changes',
|
|
222
|
+
tags: ['code'],
|
|
223
|
+
config: { model: 'gpt-5', systemPrompt: 'Follow repository rules.' },
|
|
224
|
+
autoStart: true,
|
|
225
|
+
},
|
|
226
|
+
'./agents',
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const specs = loadAgentSpecs('./agents');
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`validateAgentId()` enforces lowercase agent ids with alphanumeric, `_`, and `-` characters.
|
|
233
|
+
|
|
234
|
+
### Durable messages
|
|
235
|
+
|
|
236
|
+
`MessageService` wraps `InboxMessageDao` from `@gobing-ai/ts-db/inbox`. It owns no subprocess
|
|
237
|
+
behavior; it only persists, drains, marks delivery/failure, and formats messages.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
import { InboxMessageDao } from '@gobing-ai/ts-db/inbox';
|
|
241
|
+
import { MessageService } from '@gobing-ai/ts-ai-runner';
|
|
242
|
+
|
|
243
|
+
const messages = new MessageService(new InboxMessageDao(adapter));
|
|
244
|
+
|
|
245
|
+
const id = await messages.enqueue(null, 'coder', 'Review the runtime process seam');
|
|
246
|
+
const pending = await messages.drain('coder');
|
|
247
|
+
|
|
248
|
+
for (const msg of pending) {
|
|
249
|
+
console.log(MessageService.formatMessage(msg));
|
|
250
|
+
await messages.deliver(msg.id);
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Persistent agent processes
|
|
255
|
+
|
|
256
|
+
`TeamAgentProcess` wraps a long-running agent subprocess using the runtime pipe-process seam. It
|
|
257
|
+
supports start/stop, stdin sends, stdout/stderr subscriptions, status, pid, and exit-code queries.
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
import { TeamAgentProcess, type AgentSpec } from '@gobing-ai/ts-ai-runner';
|
|
261
|
+
|
|
262
|
+
const spec: AgentSpec = {
|
|
263
|
+
id: 'coder',
|
|
264
|
+
name: 'Coder',
|
|
265
|
+
type: 'codex',
|
|
266
|
+
workspace: '/workspace/spur',
|
|
267
|
+
purpose: 'Implement scoped code changes',
|
|
268
|
+
tags: [],
|
|
269
|
+
config: {},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const process = new TeamAgentProcess({
|
|
273
|
+
spec,
|
|
274
|
+
command: ['codex', 'exec', 'You are coder. Wait for inbox messages.'],
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const unsubscribe = process.subscribe((chunk) => {
|
|
278
|
+
console.log(chunk.toString());
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
await process.start();
|
|
282
|
+
await process.send('[task from=operator id=msg-1] Inspect packages/db');
|
|
283
|
+
await process.stop();
|
|
284
|
+
unsubscribe();
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Team orchestrator
|
|
288
|
+
|
|
289
|
+
`TeamOrchestrator` connects specs, shims, processes, and messages. On start it loads an agent spec,
|
|
290
|
+
builds the agent command through the matching shim, starts the process, drains pending inbox messages,
|
|
291
|
+
and injects them live. `sendMessage()` always persists first, then injects immediately when the target
|
|
292
|
+
agent is running.
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
import { InboxMessageDao } from '@gobing-ai/ts-db/inbox';
|
|
296
|
+
import { MessageService, TeamOrchestrator } from '@gobing-ai/ts-ai-runner';
|
|
297
|
+
|
|
298
|
+
const messages = new MessageService(new InboxMessageDao(adapter));
|
|
299
|
+
const team = new TeamOrchestrator('./agents', messages);
|
|
300
|
+
|
|
301
|
+
await team.startAgent('coder');
|
|
302
|
+
await team.sendMessage(null, 'coder', 'Please implement task 0005');
|
|
303
|
+
|
|
304
|
+
console.log(team.getAgentStatus('coder')); // running
|
|
305
|
+
|
|
306
|
+
await team.stopAll();
|
|
307
|
+
```
|
|
308
|
+
|
|
162
309
|
## Boundary Notes
|
|
163
310
|
|
|
164
311
|
- This package is a command adapter, not an agent orchestration framework.
|
|
165
312
|
- It does not install agent CLIs or manage credentials.
|
|
166
313
|
- It does not parse agent responses beyond process result capture.
|
|
167
|
-
- It keeps subprocess launching behind `ProcessExecutor`, so tests can stay deterministic.
|
|
314
|
+
- It keeps subprocess launching behind `ProcessExecutor` / `PipeProcessSpawner`, so tests can stay deterministic.
|
|
315
|
+
- Team-mode persistence is delegated to `@gobing-ai/ts-db/inbox`; host apps own migrations and adapter lifecycle.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-detector.d.ts","sourceRoot":"","sources":["../src/agent-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA4C,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EAAuB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5D,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC1B,wBAAwB;IACxB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACzB,wEAAwE;IACxE,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,wCAAwC;IACxC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACjC,gCAAgC;IAChC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,6EAA6E;AAC7E,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,GAAE,oBAAyB;IAK9C,iDAAiD;IAC3C,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAI3C,+BAA+B;IACzB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-detector.d.ts","sourceRoot":"","sources":["../src/agent-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA4C,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EAAuB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5D,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC1B,wBAAwB;IACxB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACzB,wEAAwE;IACxE,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,wCAAwC;IACxC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACjC,gCAAgC;IAChC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,6EAA6E;AAC7E,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,GAAE,oBAAyB;IAK9C,iDAAiD;IAC3C,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAI3C,+BAA+B;IACzB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAStD,OAAO,CAAC,WAAW;CAyBtB"}
|
package/dist/agent-detector.js
CHANGED
|
@@ -16,20 +16,13 @@ export class AgentDetector {
|
|
|
16
16
|
}
|
|
17
17
|
/** Probe one agent by name. */
|
|
18
18
|
async detectOne(agent) {
|
|
19
|
-
if (!isAgentName(agent))
|
|
20
|
-
return
|
|
21
|
-
}
|
|
19
|
+
if (!isAgentName(agent))
|
|
20
|
+
return unavailable(agent, `Unknown agent: ${agent}`);
|
|
22
21
|
try {
|
|
23
22
|
return this.parseResult(agent, await this.runner.runVersionCommand(agent, { timeout: this.timeout }));
|
|
24
23
|
}
|
|
25
24
|
catch (error) {
|
|
26
|
-
return
|
|
27
|
-
name: agent,
|
|
28
|
-
installed: false,
|
|
29
|
-
version: null,
|
|
30
|
-
channels: [],
|
|
31
|
-
error: error instanceof Error ? error.message : String(error),
|
|
32
|
-
};
|
|
25
|
+
return unavailable(agent, error instanceof Error ? error.message : String(error));
|
|
33
26
|
}
|
|
34
27
|
}
|
|
35
28
|
parseResult(agent, result) {
|
|
@@ -37,41 +30,17 @@ export class AgentDetector {
|
|
|
37
30
|
const output = `${result.stdout}\n${result.stderr}`.trim();
|
|
38
31
|
const lower = output.toLowerCase();
|
|
39
32
|
if (lower.includes('command not found') || lower.includes('enoent') || lower.includes('not recognized')) {
|
|
40
|
-
return {
|
|
41
|
-
name: agent,
|
|
42
|
-
installed: false,
|
|
43
|
-
version: null,
|
|
44
|
-
channels: [],
|
|
45
|
-
error: `${command}: command not found`,
|
|
46
|
-
};
|
|
33
|
+
return unavailable(agent, `${command}: command not found`);
|
|
47
34
|
}
|
|
48
35
|
if (result.signal !== undefined || result.exitCode === null) {
|
|
49
|
-
return
|
|
50
|
-
name: agent,
|
|
51
|
-
installed: false,
|
|
52
|
-
version: null,
|
|
53
|
-
channels: [],
|
|
54
|
-
error: result.signal ?? 'Process timed out',
|
|
55
|
-
};
|
|
36
|
+
return unavailable(agent, result.signal ?? 'Process timed out');
|
|
56
37
|
}
|
|
57
38
|
if (result.exitCode !== 0) {
|
|
58
|
-
return {
|
|
59
|
-
name: agent,
|
|
60
|
-
installed: false,
|
|
61
|
-
version: null,
|
|
62
|
-
channels: [],
|
|
63
|
-
error: `Non-zero exit code ${result.exitCode}: ${result.stderr.slice(0, 200)}`,
|
|
64
|
-
};
|
|
39
|
+
return unavailable(agent, `Non-zero exit code ${result.exitCode}: ${result.stderr.slice(0, 200)}`);
|
|
65
40
|
}
|
|
66
41
|
const match = VERSION_PATTERN.exec(output);
|
|
67
42
|
if (match?.groups?.version === undefined) {
|
|
68
|
-
return
|
|
69
|
-
name: agent,
|
|
70
|
-
installed: false,
|
|
71
|
-
version: null,
|
|
72
|
-
channels: [],
|
|
73
|
-
error: 'Could not parse version output',
|
|
74
|
-
};
|
|
43
|
+
return unavailable(agent, 'Could not parse version output');
|
|
75
44
|
}
|
|
76
45
|
return {
|
|
77
46
|
name: agent,
|
|
@@ -82,3 +51,7 @@ export class AgentDetector {
|
|
|
82
51
|
};
|
|
83
52
|
}
|
|
84
53
|
}
|
|
54
|
+
/** Build an "unavailable" detection result for an agent with the given error. */
|
|
55
|
+
function unavailable(name, error) {
|
|
56
|
+
return { name, installed: false, version: null, channels: [], error };
|
|
57
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type SyncFileSystem } from '@gobing-ai/ts-runtime';
|
|
2
|
+
export interface AgentSpec {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
type: string;
|
|
6
|
+
workspace: string;
|
|
7
|
+
purpose: string;
|
|
8
|
+
tags: string[];
|
|
9
|
+
config: Record<string, unknown>;
|
|
10
|
+
autoStart?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class ValueError extends Error {
|
|
13
|
+
constructor(message: string);
|
|
14
|
+
}
|
|
15
|
+
export declare function validateAgentId(id: string): string;
|
|
16
|
+
export declare function loadAgentSpecs(configDir: string, fs?: SyncFileSystem): AgentSpec[];
|
|
17
|
+
export declare function saveAgentSpec(spec: AgentSpec, configDir: string, fs?: SyncFileSystem): Promise<void>;
|
|
18
|
+
export declare function deleteAgentSpec(id: string, configDir: string, fs?: SyncFileSystem): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=agent-spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-spec.d.ts","sourceRoot":"","sources":["../src/agent-spec.ts"],"names":[],"mappings":"AACA,OAAO,EAAuC,KAAK,cAAc,EAAuB,MAAM,uBAAuB,CAAC;AAEtH,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,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,qBAAa,UAAW,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAI9B;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,GAAE,cAAyC,GAAG,SAAS,EAAE,CAY5G;AAED,wBAAsB,aAAa,CAC/B,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,MAAM,EACjB,EAAE,GAAE,cAAyC,GAC9C,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,eAAe,CACjC,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,EAAE,GAAE,cAAyC,GAC9C,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { basename, join } from 'node:path';
|
|
2
|
+
import { NodeSyncFileSystem, parseYamlObject, stringifyYamlObject } from '@gobing-ai/ts-runtime';
|
|
3
|
+
export class ValueError extends Error {
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'ValueError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function validateAgentId(id) {
|
|
10
|
+
if (!/^[a-z][a-z0-9_-]{1,63}$/.test(id)) {
|
|
11
|
+
throw new ValueError(`Invalid agent id "${id}": expected 2-64 chars, lowercase alphanumeric, "_" or "-"`);
|
|
12
|
+
}
|
|
13
|
+
return id;
|
|
14
|
+
}
|
|
15
|
+
export function loadAgentSpecs(configDir, fs = new NodeSyncFileSystem()) {
|
|
16
|
+
const entries = safeReadDir(configDir, fs)
|
|
17
|
+
.filter((entry) => entry.endsWith('.yaml') || entry.endsWith('.yml'))
|
|
18
|
+
.sort();
|
|
19
|
+
const specs = entries.map((entry) => parseAgentSpec(fs.readFile(join(configDir, entry)), entry));
|
|
20
|
+
const seen = new Set();
|
|
21
|
+
for (const spec of specs) {
|
|
22
|
+
validateAgentId(spec.id);
|
|
23
|
+
if (seen.has(spec.id))
|
|
24
|
+
throw new ValueError(`Duplicate agent id "${spec.id}" in ${configDir}`);
|
|
25
|
+
seen.add(spec.id);
|
|
26
|
+
}
|
|
27
|
+
return specs;
|
|
28
|
+
}
|
|
29
|
+
export async function saveAgentSpec(spec, configDir, fs = new NodeSyncFileSystem()) {
|
|
30
|
+
validateAgentId(spec.id);
|
|
31
|
+
fs.mkdir(configDir);
|
|
32
|
+
fs.writeFile(join(configDir, `${spec.id}.yaml`), serializeAgentSpec(spec));
|
|
33
|
+
}
|
|
34
|
+
export async function deleteAgentSpec(id, configDir, fs = new NodeSyncFileSystem()) {
|
|
35
|
+
validateAgentId(id);
|
|
36
|
+
fs.unlink(join(configDir, `${id}.yaml`));
|
|
37
|
+
}
|
|
38
|
+
function safeReadDir(configDir, fs = new NodeSyncFileSystem()) {
|
|
39
|
+
try {
|
|
40
|
+
return fs.readDir(configDir);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function parseAgentSpec(source, fileName) {
|
|
50
|
+
const parsed = parseYamlObject(source);
|
|
51
|
+
const spec = {
|
|
52
|
+
id: requireString(parsed, 'id', fileName),
|
|
53
|
+
name: requireString(parsed, 'name', fileName),
|
|
54
|
+
type: requireString(parsed, 'type', fileName),
|
|
55
|
+
workspace: requireString(parsed, 'workspace', fileName),
|
|
56
|
+
purpose: requireString(parsed, 'purpose', fileName),
|
|
57
|
+
tags: requireStringArray(parsed, 'tags', fileName),
|
|
58
|
+
config: requireRecord(parsed, 'config', fileName),
|
|
59
|
+
...(typeof parsed.autoStart === 'boolean' ? { autoStart: parsed.autoStart } : {}),
|
|
60
|
+
};
|
|
61
|
+
return spec;
|
|
62
|
+
}
|
|
63
|
+
function serializeAgentSpec(spec) {
|
|
64
|
+
const record = {
|
|
65
|
+
id: spec.id,
|
|
66
|
+
name: spec.name,
|
|
67
|
+
type: spec.type,
|
|
68
|
+
workspace: spec.workspace,
|
|
69
|
+
purpose: spec.purpose,
|
|
70
|
+
tags: spec.tags,
|
|
71
|
+
...(spec.autoStart !== undefined ? { autoStart: spec.autoStart } : {}),
|
|
72
|
+
config: spec.config,
|
|
73
|
+
};
|
|
74
|
+
return stringifyYamlObject(record);
|
|
75
|
+
}
|
|
76
|
+
function requireString(source, key, fileName) {
|
|
77
|
+
const value = source[key];
|
|
78
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
79
|
+
throw new ValueError(`${basename(fileName)}: "${key}" must be a non-empty string`);
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
function requireStringArray(source, key, fileName) {
|
|
84
|
+
const value = source[key];
|
|
85
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== 'string')) {
|
|
86
|
+
throw new ValueError(`${basename(fileName)}: "${key}" must be a string array`);
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
function requireRecord(source, key, fileName) {
|
|
91
|
+
const value = source[key];
|
|
92
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
93
|
+
throw new ValueError(`${basename(fileName)}: "${key}" must be an object`);
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
package/dist/agents/shims.d.ts
CHANGED
|
@@ -19,6 +19,20 @@ export interface PromptOptions {
|
|
|
19
19
|
model?: string;
|
|
20
20
|
/** Output mode passed through to the agent CLI. */
|
|
21
21
|
mode?: OutputMode;
|
|
22
|
+
/** Team-mode purpose included in the identity preamble. */
|
|
23
|
+
purpose?: string;
|
|
24
|
+
/** Caller-defined prompt tags. */
|
|
25
|
+
tags?: string[];
|
|
26
|
+
/** Additional system prompt rendered in the identity preamble. */
|
|
27
|
+
systemPrompt?: string;
|
|
28
|
+
/** Current task identifier included in the identity preamble. */
|
|
29
|
+
taskId?: string;
|
|
30
|
+
/** Peer agents included in the identity preamble. */
|
|
31
|
+
peers?: Array<{
|
|
32
|
+
id: string;
|
|
33
|
+
type: string;
|
|
34
|
+
purpose?: string;
|
|
35
|
+
}>;
|
|
22
36
|
}
|
|
23
37
|
/** Pure command builder for one coding-agent CLI. */
|
|
24
38
|
export interface AgentShim {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shims.d.ts","sourceRoot":"","sources":["../../src/agents/shims.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,IAAI,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;AAEvG,0CAA0C;AAC1C,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzC,mEAAmE;AACnE,MAAM,WAAW,WAAW;IACxB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC1B,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,IAAI,CAAC,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"shims.d.ts","sourceRoot":"","sources":["../../src/agents/shims.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,IAAI,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;AAEvG,0CAA0C;AAC1C,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzC,mEAAmE;AACnE,MAAM,WAAW,WAAW;IACxB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC1B,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE;AAED,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;IACrB,oCAAoC;IACpC,cAAc,IAAI,WAAW,CAAC;IAC9B,yCAAyC;IACzC,iBAAiB,IAAI,WAAW,CAAC;IACjC,yCAAyC;IACzC,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,WAAW,CAAC;IACtD,8DAA8D;IAC9D,cAAc,IAAI,WAAW,GAAG,IAAI,CAAC;CACxC;AA0GD,mDAAmD;AACnD,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAQ9D,CAAC;AAEF,sCAAsC;AACtC,eAAO,MAAM,cAAc,EAAE,SAAS,SAAS,EAAoD,CAAC;AAEpG,kDAAkD;AAClD,eAAO,MAAM,aAAa,EAAE,SAAS,SAAS,EAQ7C,CAAC;AAEF,6CAA6C;AAC7C,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,SAAS,CAAwC,CAAC;AAEzF,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,SAAS,CAE7D;AAED,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAExD"}
|
package/dist/ai-runner.d.ts
CHANGED
|
@@ -44,5 +44,6 @@ export declare class AiRunner {
|
|
|
44
44
|
/** Run an agent authentication command, or return null when unsupported. */
|
|
45
45
|
runAuthCommand(agent: AgentName, options?: AgentRunOptions): Promise<AgentRunResult> | null;
|
|
46
46
|
private invoke;
|
|
47
|
+
private withIdentityPreamble;
|
|
47
48
|
}
|
|
48
49
|
//# sourceMappingURL=ai-runner.d.ts.map
|
package/dist/ai-runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-runner.d.ts","sourceRoot":"","sources":["../src/ai-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,eAAe,EAAsB,MAAM,uBAAuB,CAAC;AACtG,OAAO,EAAE,KAAK,SAAS,EAAgB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-runner.d.ts","sourceRoot":"","sources":["../src/ai-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,eAAe,EAAsB,MAAM,uBAAuB,CAAC;AACtG,OAAO,EAAE,KAAK,SAAS,EAAgB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGlF,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC3B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC5B,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wCAAwC;AACxC,MAAM,WAAW,eAAe;IAC5B,4DAA4D;IAC5D,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,uEAAuE;AACvE,qBAAa,QAAQ;IACjB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;gBAExC,OAAO,GAAE,eAAoB;IAMzC,iCAAiC;IACjC,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAIxF,oCAAoC;IACpC,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAI3F,mCAAmC;IACnC,gBAAgB,CACZ,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,aAAa,EAC5B,OAAO,GAAE,eAAoB,GAC9B,OAAO,CAAC,cAAc,CAAC;IAW1B,4EAA4E;IAC5E,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;YAKjF,MAAM;IAyBpB,OAAO,CAAC,oBAAoB;CAmB/B"}
|
package/dist/ai-runner.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NodeProcessExecutor } from '@gobing-ai/ts-runtime';
|
|
2
2
|
import { getAgentShim } from './agents/shims.js';
|
|
3
|
+
import { buildIdentityPreamble } from './identity.js';
|
|
3
4
|
/** Dispatches coding-agent CLI commands through pure command shims. */
|
|
4
5
|
export class AiRunner {
|
|
5
6
|
processExecutor;
|
|
@@ -20,7 +21,8 @@ export class AiRunner {
|
|
|
20
21
|
}
|
|
21
22
|
/** Run an agent prompt command. */
|
|
22
23
|
runPromptCommand(agent, promptOptions, options = {}) {
|
|
23
|
-
|
|
24
|
+
const enrichedPromptOptions = this.withIdentityPreamble(agent, promptOptions, options);
|
|
25
|
+
return this.invoke(agent, 'prompt', getAgentShim(agent).getPromptCommand(enrichedPromptOptions), options, false);
|
|
24
26
|
}
|
|
25
27
|
/** Run an agent authentication command, or return null when unsupported. */
|
|
26
28
|
runAuthCommand(agent, options = {}) {
|
|
@@ -45,4 +47,26 @@ export class AiRunner {
|
|
|
45
47
|
durationMs: result.durationMs,
|
|
46
48
|
};
|
|
47
49
|
}
|
|
50
|
+
withIdentityPreamble(agent, promptOptions, options) {
|
|
51
|
+
if (!hasIdentityOptions(promptOptions))
|
|
52
|
+
return promptOptions;
|
|
53
|
+
const workspace = options.cwd ?? this.defaultCwd ?? process.cwd();
|
|
54
|
+
const preamble = buildIdentityPreamble({
|
|
55
|
+
agentId: agent,
|
|
56
|
+
agentType: agent,
|
|
57
|
+
workspace,
|
|
58
|
+
purpose: promptOptions.purpose,
|
|
59
|
+
systemPrompt: promptOptions.systemPrompt,
|
|
60
|
+
taskId: promptOptions.taskId,
|
|
61
|
+
peers: promptOptions.peers,
|
|
62
|
+
});
|
|
63
|
+
const input = promptOptions.input === undefined ? preamble : `${preamble}\n${promptOptions.input}`;
|
|
64
|
+
return { ...promptOptions, input };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function hasIdentityOptions(options) {
|
|
68
|
+
return (options.purpose !== undefined ||
|
|
69
|
+
options.systemPrompt !== undefined ||
|
|
70
|
+
options.taskId !== undefined ||
|
|
71
|
+
(options.peers !== undefined && options.peers.length > 0));
|
|
48
72
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type SyncProcessExecutor } from '@gobing-ai/ts-runtime';
|
|
2
|
+
export interface IdentityContext {
|
|
3
|
+
agentId: string;
|
|
4
|
+
agentType: string;
|
|
5
|
+
workspace: string;
|
|
6
|
+
purpose?: string;
|
|
7
|
+
taskId?: string;
|
|
8
|
+
taskTitle?: string;
|
|
9
|
+
systemPrompt?: string;
|
|
10
|
+
peers?: Array<{
|
|
11
|
+
id: string;
|
|
12
|
+
type: string;
|
|
13
|
+
purpose?: string;
|
|
14
|
+
}>;
|
|
15
|
+
gitBranch?: string;
|
|
16
|
+
gitDirty?: boolean;
|
|
17
|
+
guardrails?: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function buildIdentityPreamble(ctx: IdentityContext): string;
|
|
20
|
+
export declare function getGitContext(workspacePath: string, executor?: SyncProcessExecutor): string | null;
|
|
21
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEzF,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,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CA8ClE;AAED,wBAAgB,aAAa,CACzB,aAAa,EAAE,MAAM,EACrB,QAAQ,GAAE,mBAAkD,GAC7D,MAAM,GAAG,IAAI,CAYf"}
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { BunSyncProcessExecutor } from '@gobing-ai/ts-runtime';
|
|
2
|
+
export function buildIdentityPreamble(ctx) {
|
|
3
|
+
const sections = [
|
|
4
|
+
`You are agent \`${ctx.agentId}\` (${ctx.agentType}) in workspace \`${ctx.workspace}\`.`,
|
|
5
|
+
];
|
|
6
|
+
if (ctx.taskId !== undefined) {
|
|
7
|
+
const title = ctx.taskTitle === undefined ? '' : ` — ${ctx.taskTitle}`;
|
|
8
|
+
sections.push(`Your current task: #${ctx.taskId}${title}.`);
|
|
9
|
+
}
|
|
10
|
+
if (ctx.purpose !== undefined && ctx.purpose.trim() !== '')
|
|
11
|
+
sections.push(`Your purpose: ${ctx.purpose}.`);
|
|
12
|
+
if (ctx.systemPrompt !== undefined && ctx.systemPrompt.trim() !== '')
|
|
13
|
+
sections.push(ctx.systemPrompt);
|
|
14
|
+
if ((ctx.peers?.length ?? 0) > 0) {
|
|
15
|
+
sections.push([
|
|
16
|
+
'Peer agents in this workspace:',
|
|
17
|
+
...(ctx.peers ?? []).map((peer) => `- \`${peer.id}\` (${peer.type}) — ${peer.purpose ?? '(no purpose set)'}`),
|
|
18
|
+
].join('\n'));
|
|
19
|
+
}
|
|
20
|
+
sections.push([
|
|
21
|
+
'Communication:',
|
|
22
|
+
'- Send a message with: spur message send --to <agent-id> "<message>"',
|
|
23
|
+
'- Reply to a message with: spur message reply <msg-id> "<response>"',
|
|
24
|
+
'- Read pending messages with: spur message inbox',
|
|
25
|
+
].join('\n'));
|
|
26
|
+
if (ctx.gitBranch !== undefined) {
|
|
27
|
+
sections.push(['Git context:', `branch: ${ctx.gitBranch}`, `dirty: ${ctx.gitDirty === true ? 'true' : 'false'}`].join('\n'));
|
|
28
|
+
}
|
|
29
|
+
if ((ctx.guardrails?.length ?? 0) > 0) {
|
|
30
|
+
sections.push(['Guardrails:', ...(ctx.guardrails ?? []).map((guardrail) => `- ${guardrail}`)].join('\n'));
|
|
31
|
+
}
|
|
32
|
+
return `${sections.join('\n\n')}\n`;
|
|
33
|
+
}
|
|
34
|
+
export function getGitContext(workspacePath, executor = new BunSyncProcessExecutor()) {
|
|
35
|
+
const git = Bun.which('git');
|
|
36
|
+
if (git === null)
|
|
37
|
+
return null;
|
|
38
|
+
const branch = runGit(executor, git, ['-C', workspacePath, 'branch', '--show-current']);
|
|
39
|
+
if (branch === null || branch === '')
|
|
40
|
+
return null;
|
|
41
|
+
const status = runGit(executor, git, ['-C', workspacePath, 'status', '--porcelain']);
|
|
42
|
+
const dirtyCount = status === null || status === '' ? 0 : status.split('\n').filter(Boolean).length;
|
|
43
|
+
return ['Git context:', `branch: ${branch}`, `dirty: ${dirtyCount === 0 ? 'false' : `${dirtyCount} files`}`].join('\n');
|
|
44
|
+
}
|
|
45
|
+
function runGit(executor, command, args) {
|
|
46
|
+
const result = executor.runSync({ command, args, rejectOnError: false, forceBuffered: true });
|
|
47
|
+
if (result.exitCode !== 0)
|
|
48
|
+
return null;
|
|
49
|
+
return result.stdout.trim();
|
|
50
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export * from './agent-detector';
|
|
2
|
+
export * from './agent-spec';
|
|
2
3
|
export * from './agents/shims';
|
|
3
4
|
export * from './ai-runner';
|
|
4
5
|
export * from './doctor-runner';
|
|
6
|
+
export * from './identity';
|
|
7
|
+
export * from './message-service';
|
|
5
8
|
export * from './slash-command';
|
|
9
|
+
export * from './team-agent-process';
|
|
10
|
+
export * from './team-orchestrator';
|
|
6
11
|
//# sourceMappingURL=index.d.ts.map
|
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;AAChC,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export * from './agent-detector.js';
|
|
2
|
+
export * from './agent-spec.js';
|
|
2
3
|
export * from './agents/shims.js';
|
|
3
4
|
export * from './ai-runner.js';
|
|
4
5
|
export * from './doctor-runner.js';
|
|
6
|
+
export * from './identity.js';
|
|
7
|
+
export * from './message-service.js';
|
|
5
8
|
export * from './slash-command.js';
|
|
9
|
+
export * from './team-agent-process.js';
|
|
10
|
+
export * from './team-orchestrator.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { InboxMessage, InboxMessageDao } from '@gobing-ai/ts-db/inbox';
|
|
2
|
+
export declare class MessageService {
|
|
3
|
+
private readonly dao;
|
|
4
|
+
constructor(dao: InboxMessageDao);
|
|
5
|
+
enqueue(fromId: string | null, toId: string, body: string, inReplyTo?: string): Promise<string>;
|
|
6
|
+
drain(toId: string): Promise<InboxMessage[]>;
|
|
7
|
+
deliver(msgId: string): Promise<void>;
|
|
8
|
+
fail(msgId: string, error: string): Promise<void>;
|
|
9
|
+
inbox(toId: string, limit?: number, offset?: number): Promise<InboxMessage[]>;
|
|
10
|
+
countPending(toId: string): Promise<number>;
|
|
11
|
+
static formatMessage(msg: InboxMessage): string;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=message-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-service.d.ts","sourceRoot":"","sources":["../src/message-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE5E,qBAAa,cAAc;IACX,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,eAAe;IAEjD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI/F,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAI5C,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAI7E,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI3C,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;CAGlD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class MessageService {
|
|
2
|
+
dao;
|
|
3
|
+
constructor(dao) {
|
|
4
|
+
this.dao = dao;
|
|
5
|
+
}
|
|
6
|
+
enqueue(fromId, toId, body, inReplyTo) {
|
|
7
|
+
return this.dao.enqueue(fromId, toId, body, inReplyTo);
|
|
8
|
+
}
|
|
9
|
+
drain(toId) {
|
|
10
|
+
return this.dao.drainPending(toId);
|
|
11
|
+
}
|
|
12
|
+
deliver(msgId) {
|
|
13
|
+
return this.dao.markDelivered(msgId);
|
|
14
|
+
}
|
|
15
|
+
fail(msgId, error) {
|
|
16
|
+
return this.dao.markFailed(msgId, error);
|
|
17
|
+
}
|
|
18
|
+
inbox(toId, limit, offset) {
|
|
19
|
+
return this.dao.inbox(toId, limit, offset);
|
|
20
|
+
}
|
|
21
|
+
countPending(toId) {
|
|
22
|
+
return this.dao.countPending(toId);
|
|
23
|
+
}
|
|
24
|
+
static formatMessage(msg) {
|
|
25
|
+
return `[task from=${msg.fromId ?? 'operator'} id=${msg.id}] ${msg.body}`;
|
|
26
|
+
}
|
|
27
|
+
}
|