@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.
Files changed (50) hide show
  1. package/README.md +32 -19
  2. package/dist/agent-ours/bridge.d.ts +3 -0
  3. package/dist/agent-ours/bridge.js +169 -0
  4. package/dist/agent-ours/controller.d.ts +14 -0
  5. package/dist/agent-ours/controller.js +60 -0
  6. package/dist/agent-ours/file-rpc.d.ts +23 -0
  7. package/dist/agent-ours/file-rpc.js +123 -0
  8. package/dist/agent-ours/harness.d.ts +14 -0
  9. package/dist/agent-ours/harness.js +64 -0
  10. package/dist/agent-ours/mcp-endpoint.d.ts +15 -0
  11. package/dist/agent-ours/mcp-endpoint.js +111 -0
  12. package/dist/agent-ours/runtime.d.ts +53 -0
  13. package/dist/agent-ours/runtime.js +247 -0
  14. package/dist/agent-ours/service.d.ts +23 -0
  15. package/dist/agent-ours/service.js +352 -0
  16. package/dist/agent-ours/state.d.ts +45 -0
  17. package/dist/agent-ours/state.js +95 -0
  18. package/dist/agent-ours/wire.d.ts +14 -0
  19. package/dist/agent-ours/wire.js +55 -0
  20. package/dist/briefing.js +10 -59
  21. package/dist/build-info.json +5 -4
  22. package/dist/capabilities.d.ts +2 -1
  23. package/dist/capabilities.js +2 -0
  24. package/dist/cli.js +15 -2
  25. package/dist/client-profile.d.ts +1 -0
  26. package/dist/client-profile.js +18 -3
  27. package/dist/creation.d.ts +1 -1
  28. package/dist/creation.js +3 -14
  29. package/dist/docs.d.ts +1 -1
  30. package/dist/docs.js +15 -20
  31. package/dist/doctor.d.ts +1 -1
  32. package/dist/doctor.js +28 -9
  33. package/dist/fleet-command-audit.js +1 -1
  34. package/dist/harness/agent-session.d.ts +2 -0
  35. package/dist/harness/claude-code-session.js +4 -2
  36. package/dist/harness/codex-session.js +9 -2
  37. package/dist/harness/hermes-session.js +7 -1
  38. package/dist/rooms-tasks/cowork-adapter.js +9 -2
  39. package/dist/rooms-tasks/cowork-http.d.ts +3 -0
  40. package/dist/rooms-tasks/cowork-http.js +70 -0
  41. package/dist/rooms-tasks/provision.js +9 -2
  42. package/dist/runner.d.ts +4 -0
  43. package/dist/runner.js +522 -492
  44. package/dist/session/codex-app-server-transport.js +1 -1
  45. package/dist/spawn.js +12 -16
  46. package/dist/temp-supervisor-recovery.d.ts +3 -0
  47. package/dist/temp-supervisor-recovery.js +46 -0
  48. package/dist/watchdog/briefing.js +3 -16
  49. package/dist/watchdog/run.js +19 -5
  50. 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, daemonIdentityProvisioner, ensureIdentity, provenanceOf, withCreationTransaction, writeProvenance, writeRoleFile, } from './creation.js';
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
- // Establish the identity BEFORE the service is enabled, and record
243
- // what was actually guaranteed so the briefing can say something true.
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 guarantee = await ensureIdentity(effectiveIdentity(o), { bio: prepared.role.bio, persona: prepared.role.persona }, creation.identityProvisioner ?? deps.identityProvisioner ?? daemonIdentityProvisioner(), deps.log);
246
- creation.onStage?.('checking_identity', {
247
- result: guarantee.evidence, guarantee: guarantee.state,
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,3 @@
1
+ export declare const TEMP_RECYCLE_EXIT = 75;
2
+ /** Keep the service's main process alive while replacing a PID-scoped worker. */
3
+ export declare function runTempSupervisor(name: string, entrypoint: string, initial?: () => Promise<void>): Promise<void>;
@@ -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
- const L = ['', heading];
9
- L.push(`Call the **${v.bindTool}** tool with name "${wd.identity}" force=true (search the`);
10
- L.push('deferred tool registry first if needed).');
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
@@ -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 { daemonIdentityInventoryProvisioner, ensureIdentity, } from '../creation.js';
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 = await ensureIdentity(wd.identity, {}, deps.identityProvisioner ?? daemonIdentityInventoryProvisioner(), deps.log);
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 = await ensureIdentity(wd.identity, {}, deps.identityProvisioner ?? daemonIdentityInventoryProvisioner(), deps.log);
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
- await runOnce(name, { temp: true });
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",
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.7",
45
- "@ours.network/sdk": "3.8.1-nightly.9",
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
  }