@ours.network/fleet 1.2.0-nightly.3 → 1.2.0-nightly.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 +32 -19
- package/dist/agent-ours/bridge.d.ts +3 -0
- package/dist/agent-ours/bridge.js +169 -0
- package/dist/agent-ours/controller.d.ts +14 -0
- package/dist/agent-ours/controller.js +60 -0
- package/dist/agent-ours/file-rpc.d.ts +23 -0
- package/dist/agent-ours/file-rpc.js +123 -0
- package/dist/agent-ours/harness.d.ts +14 -0
- package/dist/agent-ours/harness.js +64 -0
- package/dist/agent-ours/mcp-endpoint.d.ts +15 -0
- package/dist/agent-ours/mcp-endpoint.js +111 -0
- package/dist/agent-ours/runtime.d.ts +53 -0
- package/dist/agent-ours/runtime.js +247 -0
- package/dist/agent-ours/service.d.ts +23 -0
- package/dist/agent-ours/service.js +352 -0
- package/dist/agent-ours/state.d.ts +45 -0
- package/dist/agent-ours/state.js +95 -0
- package/dist/agent-ours/wire.d.ts +14 -0
- package/dist/agent-ours/wire.js +55 -0
- package/dist/briefing.js +10 -59
- package/dist/build-info.json +5 -4
- package/dist/capabilities.d.ts +2 -1
- package/dist/capabilities.js +2 -0
- package/dist/cli.js +15 -2
- package/dist/client-profile.d.ts +1 -0
- package/dist/client-profile.js +18 -3
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +3 -14
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +15 -20
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +28 -9
- package/dist/fleet-command-audit.js +1 -1
- package/dist/harness/agent-session.d.ts +2 -0
- package/dist/harness/claude-code-session.js +4 -2
- package/dist/harness/codex-session.js +9 -2
- package/dist/harness/hermes-session.js +7 -1
- package/dist/rooms-tasks/cowork-adapter.js +9 -2
- package/dist/rooms-tasks/cowork-http.d.ts +3 -0
- package/dist/rooms-tasks/cowork-http.js +70 -0
- package/dist/rooms-tasks/provision.js +9 -2
- package/dist/runner.d.ts +4 -0
- package/dist/runner.js +522 -492
- package/dist/session/codex-app-server-transport.js +1 -1
- package/dist/spawn.js +12 -16
- package/dist/temp-supervisor-recovery.d.ts +3 -0
- package/dist/temp-supervisor-recovery.js +46 -0
- package/dist/watchdog/briefing.js +3 -16
- package/dist/watchdog/run.js +19 -5
- package/package.json +6 -5
|
@@ -55,7 +55,7 @@ export class CodexAppServerTransport {
|
|
|
55
55
|
throw new Error('Codex app-server command is empty');
|
|
56
56
|
const child = spawn(options.argv[0], options.argv.slice(1), {
|
|
57
57
|
cwd: options.cwd,
|
|
58
|
-
env: { ...process.env, ...options.env },
|
|
58
|
+
env: { ...(options.env?.FLEET_OURS_MANAGED === '1' ? {} : process.env), ...options.env },
|
|
59
59
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
60
60
|
});
|
|
61
61
|
// `pid` is assigned synchronously on a successful local spawn. Checking it
|
package/dist/spawn.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { storeRoomSecret, storeTemporaryLaunch, preparePermanentAssignment } from './agent-ours/service.js';
|
|
1
3
|
import { spawn as spawnChild } from 'node:child_process';
|
|
2
4
|
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
5
|
import { join } from 'node:path';
|
|
@@ -7,7 +9,7 @@ import { validateIsolationConfig } from './isolation/policy.js';
|
|
|
7
9
|
import { loadConfig, findRole, splitRootFor, validateMonitorConfig, } from './config.js';
|
|
8
10
|
import { applyRole, up } from './ops.js';
|
|
9
11
|
import { START_STAGGER_FILE } from './runner.js';
|
|
10
|
-
import { buildProvenance,
|
|
12
|
+
import { buildProvenance, provenanceOf, withCreationTransaction, writeProvenance, writeRoleFile, } from './creation.js';
|
|
11
13
|
import { VERSION } from './version.js';
|
|
12
14
|
import { recordGeneratedAgentSource } from './generated-agent-source.js';
|
|
13
15
|
import './harness/claude-code.js';
|
|
@@ -239,22 +241,12 @@ export async function spawnPermanent(o, deps, creation = {}) {
|
|
|
239
241
|
return withCreationTransaction({ role: o.name, identity: effectiveIdentity(o) }, async (tx) => {
|
|
240
242
|
assertNameFree(o);
|
|
241
243
|
const cfg = loadConfig(o.configPath);
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
+
// Pin an existing assignment without binding; the supervisor provisions
|
|
245
|
+
// a missing role identity before starting its harness.
|
|
244
246
|
creation.onStage?.('checking_identity');
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
});
|
|
249
|
-
if (guarantee.state === 'created')
|
|
250
|
-
// We minted it; a failed creation must not leave an orphan identity
|
|
251
|
-
// behind. Only ever removes an identity THIS transaction created.
|
|
252
|
-
tx.record({
|
|
253
|
-
stage: `ours identity ${effectiveIdentity(o)}`,
|
|
254
|
-
undo: async () => {
|
|
255
|
-
await creation.identityProvisioner?.remove?.(effectiveIdentity(o));
|
|
256
|
-
},
|
|
257
|
-
});
|
|
247
|
+
const assignment = await preparePermanentAssignment(prepared.role);
|
|
248
|
+
const guarantee = { state: assignment, evidence: assignment === 'verified' ? 'verified' : 'missing' };
|
|
249
|
+
creation.onStage?.('checking_identity', { result: guarantee.evidence, guarantee: guarantee.state });
|
|
258
250
|
const agentRoot = join(splitRootFor(o.configPath ?? defaultConfigPath()), 'agents');
|
|
259
251
|
mkdirSync(agentRoot, { recursive: true });
|
|
260
252
|
creation.onStage?.('writing_role');
|
|
@@ -354,6 +346,10 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
|
|
|
354
346
|
temporaryLoopSource: o.loopSource ?? (temporaryLoops?.length ? 'agent-template' : 'omitted'),
|
|
355
347
|
roomMemberStartup: o.roomMemberStartup,
|
|
356
348
|
};
|
|
349
|
+
storeTemporaryLaunch(role, o.creationActionId ?? randomUUID());
|
|
350
|
+
storeRoomSecret(role);
|
|
351
|
+
if (role.roomMemberStartup)
|
|
352
|
+
role.roomMemberStartup = { ...role.roomMemberStartup, invite: '' };
|
|
357
353
|
onStage?.('writing_role');
|
|
358
354
|
const dir = applyRole(role, { temp: true, identityGuarantee: 'unverified' });
|
|
359
355
|
const provenance = buildProvenance({
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { runTemp, SupervisorRecycleRequiredError } from './runner.js';
|
|
3
|
+
export const TEMP_RECYCLE_EXIT = 75;
|
|
4
|
+
/** Keep the service's main process alive while replacing a PID-scoped worker. */
|
|
5
|
+
export async function runTempSupervisor(name, entrypoint, initial = () => runTemp(name)) {
|
|
6
|
+
try {
|
|
7
|
+
await initial();
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (!(error instanceof SupervisorRecycleRequiredError))
|
|
12
|
+
throw error;
|
|
13
|
+
}
|
|
14
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
15
|
+
const child = spawn(process.execPath, [entrypoint, '_run-temp-worker', name], {
|
|
16
|
+
stdio: 'inherit',
|
|
17
|
+
env: process.env,
|
|
18
|
+
});
|
|
19
|
+
let stopping = false;
|
|
20
|
+
const term = () => {
|
|
21
|
+
stopping = true;
|
|
22
|
+
child.kill('SIGTERM');
|
|
23
|
+
}, interrupt = () => {
|
|
24
|
+
stopping = true;
|
|
25
|
+
child.kill('SIGINT');
|
|
26
|
+
};
|
|
27
|
+
process.on('SIGTERM', term);
|
|
28
|
+
process.on('SIGINT', interrupt);
|
|
29
|
+
let code;
|
|
30
|
+
try {
|
|
31
|
+
code = await new Promise((resolve, reject) => {
|
|
32
|
+
child.once('error', reject);
|
|
33
|
+
child.once('exit', resolve);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
process.off('SIGTERM', term);
|
|
38
|
+
process.off('SIGINT', interrupt);
|
|
39
|
+
}
|
|
40
|
+
if (code === 0 || stopping)
|
|
41
|
+
return;
|
|
42
|
+
if (code !== TEMP_RECYCLE_EXIT)
|
|
43
|
+
throw Error(`Temporary supervisor replacement exited with ${code}`);
|
|
44
|
+
}
|
|
45
|
+
throw Error('Temporary supervisor recycle limit reached; identity retained for explicit recovery');
|
|
46
|
+
}
|
|
@@ -5,22 +5,9 @@ import { formatDuration } from '../duration.js';
|
|
|
5
5
|
* wasn't verified when configured, fall back to createTool on first run.
|
|
6
6
|
*/
|
|
7
7
|
function bindSection(heading, wd, v, guarantee) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (guarantee === 'unverified') {
|
|
12
|
-
L.push(`- This identity was NOT verified when this watchdog was configured, so it may not`);
|
|
13
|
-
L.push(` exist yet. If binding reports no such identity, call **${v.createTool}** name`);
|
|
14
|
-
L.push(` "${wd.identity}" once to mint it on this first run, then you are bound. Re-binding`);
|
|
15
|
-
L.push(' your OWN identity is always allowed.');
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
L.push(`- It was ${guarantee === 'created' ? 'created' : 'verified to exist'} when this`);
|
|
19
|
-
L.push(' watchdog was configured, so binding should succeed. If it unexpectedly reports no');
|
|
20
|
-
L.push(` such identity, call **${v.createTool}** name "${wd.identity}" once and report the`);
|
|
21
|
-
L.push(' discrepancy — something removed it since.');
|
|
22
|
-
}
|
|
23
|
-
return L;
|
|
8
|
+
return ['', '## Assigned identity',
|
|
9
|
+
`Your supervisor has bound your identity **${wd.identity}**. The ours tools are ready.`,
|
|
10
|
+
'No identity setup or skill reading is required.'];
|
|
24
11
|
}
|
|
25
12
|
/**
|
|
26
13
|
* Render a watchdog run's fixed contract (briefing.md-equivalent for a one-shot clean-context
|
package/dist/watchdog/run.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { preparePermanentAssignment, releaseManagedAgent } from '../agent-ours/service.js';
|
|
1
2
|
import { closeSync, existsSync, openSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync, } from 'node:fs';
|
|
2
3
|
import { spawn as spawnChild } from 'node:child_process';
|
|
3
4
|
import { join } from 'node:path';
|
|
@@ -7,8 +8,7 @@ import { acquireRunLock, formatRunId, pruneReports, releaseRunLock, writeReport
|
|
|
7
8
|
import { generateNotifierBriefing, generateWatchdogBriefing } from './briefing.js';
|
|
8
9
|
import { computeDigest, reconcileLedger, readLedger, writeLedger } from './alerts.js';
|
|
9
10
|
import { applyRole } from '../ops.js';
|
|
10
|
-
import {
|
|
11
|
-
import { runOnce, START_STAGGER_FILE } from '../runner.js';
|
|
11
|
+
import { runOnce, loadTempRole, START_STAGGER_FILE } from '../runner.js';
|
|
12
12
|
import { agentDir, tmpRoot } from '../paths.js';
|
|
13
13
|
import { loadConfig, ROLE_NAME_RE, } from '../config.js';
|
|
14
14
|
import { getAdapter } from '../harness/registry.js';
|
|
@@ -53,6 +53,7 @@ async function killIfNeeded(reason, child, roleName, sleep) {
|
|
|
53
53
|
if (reason === 'stable')
|
|
54
54
|
await sleep(HARVEST_GRACE_MS);
|
|
55
55
|
child.kill();
|
|
56
|
+
await child.exited;
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
function defaultLaunchChild(binPath, roleName, runDir) {
|
|
@@ -139,7 +140,7 @@ export async function executeWatchdogRun(wd, deps) {
|
|
|
139
140
|
rmSync(runDir, { recursive: true, force: true });
|
|
140
141
|
let report;
|
|
141
142
|
try {
|
|
142
|
-
const guarantee =
|
|
143
|
+
const guarantee = { state: 'unverified' }; // The child supervisor provisions before its harness starts.
|
|
143
144
|
const cfg = deps.cfg ?? loadConfig();
|
|
144
145
|
const discovered = wd.watchExplicit
|
|
145
146
|
? []
|
|
@@ -272,7 +273,7 @@ export async function executeNotifierRun(wd, text, deps) {
|
|
|
272
273
|
// A crashed previous run can leave the temp dir behind; start clean.
|
|
273
274
|
if (existsSync(runDir))
|
|
274
275
|
rmSync(runDir, { recursive: true, force: true });
|
|
275
|
-
const guarantee =
|
|
276
|
+
const guarantee = { state: 'unverified' }; // The child supervisor provisions before its harness starts.
|
|
276
277
|
const cfg = deps.cfg ?? loadConfig();
|
|
277
278
|
const role = buildWatchdogRole(wd, cfg);
|
|
278
279
|
const dir = applyRole(role, { temp: true, identityGuarantee: guarantee.state });
|
|
@@ -317,5 +318,18 @@ export async function executeNotifierRun(wd, text, deps) {
|
|
|
317
318
|
}
|
|
318
319
|
/** What `_run-watchdog` calls: one supervised session, no cleanup — the parent harvests. */
|
|
319
320
|
export async function runWatchdogAgent(name) {
|
|
320
|
-
|
|
321
|
+
const role = loadTempRole(name);
|
|
322
|
+
await preparePermanentAssignment(role);
|
|
323
|
+
let stopping = false;
|
|
324
|
+
const stop = () => { stopping = true; };
|
|
325
|
+
process.on('SIGTERM', stop);
|
|
326
|
+
process.on('SIGINT', stop);
|
|
327
|
+
try {
|
|
328
|
+
await runOnce(name, { temp: true, identityLifetime: 'permanent' }, { shouldStop: () => stopping });
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
process.off('SIGTERM', stop);
|
|
332
|
+
process.off('SIGINT', stop);
|
|
333
|
+
await releaseManagedAgent(role);
|
|
334
|
+
}
|
|
321
335
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "1.2.0-nightly.
|
|
3
|
+
"version": "1.2.0-nightly.5",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, managed native/ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
@@ -41,8 +41,9 @@
|
|
|
41
41
|
"@agentclientprotocol/sdk": "^1.3.0",
|
|
42
42
|
"@fastify/static": "^10.1.2",
|
|
43
43
|
"@fastify/websocket": "^11.2.0",
|
|
44
|
-
"@ours.network/cli": "2.8.1-nightly.
|
|
45
|
-
"@ours.network/
|
|
44
|
+
"@ours.network/cli": "2.8.1-nightly.8",
|
|
45
|
+
"@ours.network/mcp": "1.2.0-nightly.6",
|
|
46
|
+
"@ours.network/sdk": "3.8.1-nightly.10",
|
|
46
47
|
"commander": "^12.1.0",
|
|
47
48
|
"fastify": "^5.4.0",
|
|
48
49
|
"react": "^19.1.1",
|
|
@@ -56,6 +57,7 @@
|
|
|
56
57
|
"@agentclientprotocol/codex-acp": "1.10.0"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
60
|
+
"@ours.network/daemon": "3.8.1-nightly.2",
|
|
59
61
|
"@playwright/test": "^1.54.1",
|
|
60
62
|
"@types/node": "^20.14.0",
|
|
61
63
|
"@types/react": "^19.1.9",
|
|
@@ -63,7 +65,6 @@
|
|
|
63
65
|
"@types/ws": "^8.18.1",
|
|
64
66
|
"typescript": "^5.5.0",
|
|
65
67
|
"vite": "^7.0.6",
|
|
66
|
-
"vitest": "^2.0.0"
|
|
67
|
-
"@ours.network/daemon": "3.8.1-nightly.1"
|
|
68
|
+
"vitest": "^2.0.0"
|
|
68
69
|
}
|
|
69
70
|
}
|