@ours.network/fleet 0.9.3 → 0.9.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/README.md +52 -30
- package/dist/cli.js +153 -15
- package/dist/config.d.ts +24 -0
- package/dist/config.js +79 -1
- package/dist/docs.d.ts +7 -0
- package/dist/docs.js +177 -0
- package/dist/doctor.js +50 -6
- package/dist/harness/acp-agent.d.ts +11 -0
- package/dist/harness/acp-agent.js +27 -0
- package/dist/harness/claude-code.js +31 -1
- package/dist/harness/codex.js +40 -2
- package/dist/harness/types.d.ts +12 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +3 -1
- package/dist/monitor.d.ts +35 -5
- package/dist/monitor.js +187 -33
- package/dist/runner.js +73 -18
- package/dist/session/acp.d.ts +49 -0
- package/dist/session/acp.js +280 -0
- package/dist/session/control.d.ts +41 -0
- package/dist/session/control.js +218 -0
- package/dist/session/events.d.ts +14 -0
- package/dist/session/events.js +67 -0
- package/dist/session/tmux.d.ts +20 -0
- package/dist/session/tmux.js +46 -0
- package/dist/session/types.d.ts +47 -0
- package/dist/session/types.js +1 -0
- package/dist/spawn.d.ts +5 -0
- package/dist/spawn.js +24 -1
- package/package.json +7 -2
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { SessionBackendId } from '../config.js';
|
|
2
|
+
export type SessionReadiness = 'starting' | 'idle' | 'running' | 'awaiting_permission' | 'failed';
|
|
3
|
+
export interface TurnResult {
|
|
4
|
+
accepted: boolean;
|
|
5
|
+
outcome: 'completed' | 'refused' | 'cancelled' | 'failed' | 'inconclusive';
|
|
6
|
+
detail?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SessionSnapshot {
|
|
9
|
+
backend: SessionBackendId;
|
|
10
|
+
alive: boolean;
|
|
11
|
+
readiness: SessionReadiness;
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
lastError?: string;
|
|
14
|
+
pendingPermissionId?: string;
|
|
15
|
+
}
|
|
16
|
+
export type SessionEventKind = 'state' | 'agent_text' | 'thought' | 'tool_call' | 'tool_update' | 'permission' | 'turn_stop' | 'error';
|
|
17
|
+
export interface SessionEvent {
|
|
18
|
+
version: 1;
|
|
19
|
+
seq: number;
|
|
20
|
+
at: string;
|
|
21
|
+
kind: SessionEventKind;
|
|
22
|
+
turnId?: string;
|
|
23
|
+
toolCallId?: string;
|
|
24
|
+
permissionId?: string;
|
|
25
|
+
text?: string;
|
|
26
|
+
title?: string;
|
|
27
|
+
status?: string;
|
|
28
|
+
stopReason?: string;
|
|
29
|
+
options?: Array<{
|
|
30
|
+
optionId: string;
|
|
31
|
+
name: string;
|
|
32
|
+
kind: string;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
export interface SessionHandle {
|
|
36
|
+
readonly backend: SessionBackendId;
|
|
37
|
+
readonly pid: number;
|
|
38
|
+
isAlive(): boolean;
|
|
39
|
+
snapshot(): SessionSnapshot;
|
|
40
|
+
submitPrompt(text: string): Promise<TurnResult>;
|
|
41
|
+
interrupt(): Promise<void>;
|
|
42
|
+
respondPermission(permissionId: string, optionId: string): boolean;
|
|
43
|
+
eventsSince(seq: number): SessionEvent[];
|
|
44
|
+
subscribe(listener: (event: SessionEvent) => void): () => void;
|
|
45
|
+
setControllerAttached(attached: boolean): void;
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/spawn.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import { type ApprovalMode, type FilesystemMode, type SessionBackendId, type UnattendedMode } from './config.js';
|
|
1
2
|
import { type OpsDeps } from './ops.js';
|
|
2
3
|
export interface SpawnOpts {
|
|
3
4
|
name: string;
|
|
4
5
|
temp?: boolean;
|
|
5
6
|
harness?: string;
|
|
7
|
+
session?: SessionBackendId;
|
|
6
8
|
mission?: string;
|
|
7
9
|
identity?: string;
|
|
8
10
|
cwd?: string;
|
|
9
11
|
coordinator?: string;
|
|
10
12
|
model?: string;
|
|
11
13
|
permissionMode?: string;
|
|
14
|
+
approval?: ApprovalMode;
|
|
15
|
+
filesystem?: FilesystemMode;
|
|
16
|
+
unattended?: UnattendedMode;
|
|
12
17
|
sandbox?: string;
|
|
13
18
|
profile?: string;
|
|
14
19
|
launcher?: string;
|
package/dist/spawn.js
CHANGED
|
@@ -3,13 +3,15 @@ import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from 'no
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { stringify } from 'yaml';
|
|
5
5
|
import { agentDir, fleetDDir } from './paths.js';
|
|
6
|
-
import { loadConfig, resolveMonitorConfig } from './config.js';
|
|
6
|
+
import { loadConfig, resolveMonitorConfig, resolvePermissions, } from './config.js';
|
|
7
7
|
import { applyRole, up } from './ops.js';
|
|
8
8
|
import { START_STAGGER_FILE } from './runner.js';
|
|
9
9
|
function roleFromOpts(o, defaultHarness) {
|
|
10
10
|
const r = {};
|
|
11
11
|
if (o.harness)
|
|
12
12
|
r.harness = o.harness;
|
|
13
|
+
if (o.session)
|
|
14
|
+
r.session = o.session;
|
|
13
15
|
if (o.identity)
|
|
14
16
|
r.identity = o.identity;
|
|
15
17
|
if (o.cwd)
|
|
@@ -40,12 +42,29 @@ function roleFromOpts(o, defaultHarness) {
|
|
|
40
42
|
harnessOptions.monitor = true;
|
|
41
43
|
if (Object.keys(harnessOptions).length)
|
|
42
44
|
r.harness_options = harnessOptions;
|
|
45
|
+
if (o.approval || o.filesystem || o.unattended) {
|
|
46
|
+
r.permissions = {
|
|
47
|
+
...(o.approval ? { approval: o.approval } : {}),
|
|
48
|
+
...(o.filesystem ? { filesystem: o.filesystem } : {}),
|
|
49
|
+
...(o.unattended ? { unattended: o.unattended } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
43
52
|
if (o.bioFile)
|
|
44
53
|
r.bio = readFileSync(o.bioFile, 'utf8').trim();
|
|
45
54
|
if (o.personaFile)
|
|
46
55
|
r.persona = readFileSync(o.personaFile, 'utf8').trim();
|
|
47
56
|
return r;
|
|
48
57
|
}
|
|
58
|
+
function validateSpawnOpts(o) {
|
|
59
|
+
if (o.session && !['tmux', 'acp'].includes(o.session))
|
|
60
|
+
throw new Error(`invalid --session '${o.session}'; allowed: tmux, acp`);
|
|
61
|
+
if (o.approval && !['ask', 'allow', 'deny'].includes(o.approval))
|
|
62
|
+
throw new Error(`invalid --approval '${o.approval}'; allowed: ask, allow, deny`);
|
|
63
|
+
if (o.filesystem && !['read-only', 'workspace', 'unrestricted'].includes(o.filesystem))
|
|
64
|
+
throw new Error(`invalid --filesystem '${o.filesystem}'; allowed: read-only, workspace, unrestricted`);
|
|
65
|
+
if (o.unattended && !['deny', 'wait'].includes(o.unattended))
|
|
66
|
+
throw new Error(`invalid --unattended '${o.unattended}'; allowed: deny, wait`);
|
|
67
|
+
}
|
|
49
68
|
function assertNameFree(o) {
|
|
50
69
|
const cfg = loadConfig(o.configPath);
|
|
51
70
|
if (cfg.roles.some(r => r.name === o.name))
|
|
@@ -55,6 +74,7 @@ function assertNameFree(o) {
|
|
|
55
74
|
}
|
|
56
75
|
/** Permanent spawn: persist to ~/fleet.d/<Name>.yaml, then bring it up. */
|
|
57
76
|
export async function spawnPermanent(o, deps) {
|
|
77
|
+
validateSpawnOpts(o);
|
|
58
78
|
assertNameFree(o);
|
|
59
79
|
const cfg = loadConfig(o.configPath);
|
|
60
80
|
mkdirSync(fleetDDir(), { recursive: true });
|
|
@@ -76,6 +96,7 @@ const detachedSupervisor = (binPath, args, dir) => {
|
|
|
76
96
|
};
|
|
77
97
|
/** Temp spawn: state under ~/.ours-fleet/tmp, plain tmux, auto-clean on exit. */
|
|
78
98
|
export async function spawnTemp(o, binPath, launch = detachedSupervisor) {
|
|
99
|
+
validateSpawnOpts(o);
|
|
79
100
|
assertNameFree(o);
|
|
80
101
|
const cfg = loadConfig(o.configPath);
|
|
81
102
|
const defaultHarness = cfg.defaults.harness;
|
|
@@ -88,9 +109,11 @@ export async function spawnTemp(o, binPath, launch = detachedSupervisor) {
|
|
|
88
109
|
...fromOpts,
|
|
89
110
|
name: o.name,
|
|
90
111
|
harness: o.harness ?? defaultHarness ?? 'claude-code',
|
|
112
|
+
session: o.session ?? cfg.defaults.session ?? 'tmux',
|
|
91
113
|
identity: o.identity ?? o.name,
|
|
92
114
|
model: o.model?.trim() || cfg.defaults.model,
|
|
93
115
|
harness_options: Object.keys(mergedHarnessOptions).length ? mergedHarnessOptions : undefined,
|
|
116
|
+
permissions: resolvePermissions(cfg.defaults.permissions, fromOpts.permissions),
|
|
94
117
|
// Temp agents inherit the fleet-wide monitor defaults via the snapshot (design §2).
|
|
95
118
|
monitor: resolveMonitorConfig(cfg.defaults.monitor, fromOpts.monitor),
|
|
96
119
|
sourceFile: '(temp)',
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, tmux
|
|
3
|
+
"version": "0.9.5",
|
|
4
|
+
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, tmux or ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -26,9 +26,14 @@
|
|
|
26
26
|
"prepublishOnly": "npm run build && npm test"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@agentclientprotocol/sdk": "^1.3.0",
|
|
29
30
|
"commander": "^12.1.0",
|
|
30
31
|
"yaml": "^2.5.0"
|
|
31
32
|
},
|
|
33
|
+
"optionalDependencies": {
|
|
34
|
+
"@agentclientprotocol/claude-agent-acp": "^0.63.0",
|
|
35
|
+
"@agentclientprotocol/codex-acp": "^1.1.7"
|
|
36
|
+
},
|
|
32
37
|
"devDependencies": {
|
|
33
38
|
"@types/node": "^20.14.0",
|
|
34
39
|
"typescript": "^5.5.0",
|