@ours.network/fleet 1.1.0-nightly.1 → 1.1.0-nightly.3
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 +76 -93
- package/dist/application/role-creation-service.d.ts +2 -21
- package/dist/application/role-creation-service.js +15 -64
- package/dist/application/role-removal-service.js +6 -3
- package/dist/application/task-room-service.js +7 -2
- package/dist/application/types.d.ts +1 -1
- package/dist/briefing.js +5 -5
- package/dist/build-info.json +4 -4
- package/dist/cli.js +48 -38
- package/dist/config.d.ts +65 -2
- package/dist/config.js +337 -25
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +2 -2
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +48 -97
- package/dist/doctor.js +4 -4
- package/dist/fleet-proxy.js +30 -8
- package/dist/generated-agent-source.d.ts +9 -0
- package/dist/generated-agent-source.js +53 -0
- package/dist/harness/agent-session.d.ts +13 -0
- package/dist/harness/claude-code-session.d.ts +4 -0
- package/dist/harness/claude-code-session.js +4 -0
- package/dist/harness/claude-code.js +10 -0
- package/dist/harness/codex-session.d.ts +4 -0
- package/dist/harness/codex-session.js +4 -0
- package/dist/harness/codex.js +14 -0
- package/dist/harness/registry.js +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/init-guidance.d.ts +1 -0
- package/dist/init-guidance.js +5 -0
- package/dist/model-env.d.ts +2 -3
- package/dist/model-env.js +3 -5
- package/dist/ops.js +4 -2
- package/dist/owner-channel/commands.js +2 -1
- package/dist/resolved-plan.d.ts +3 -2
- package/dist/resolved-plan.js +21 -5
- package/dist/rooms-tasks/cli.js +2 -1
- package/dist/rooms-tasks/config.js +24 -9
- package/dist/rooms-tasks/provision.js +71 -36
- package/dist/rooms-tasks/templates.js +6 -6
- package/dist/rooms-tasks/types.d.ts +8 -15
- package/dist/rooms-tasks/types.js +1 -4
- package/dist/sensitive-config.d.ts +2 -0
- package/dist/sensitive-config.js +4 -0
- package/dist/spawn.d.ts +8 -33
- package/dist/spawn.js +52 -211
- package/dist/watchdog/config.d.ts +10 -7
- package/dist/watchdog/config.js +29 -19
- package/dist/watchdog/run.js +4 -13
- package/dist/web/fleet-config-service.d.ts +11 -8
- package/dist/web/fleet-config-service.js +383 -183
- package/dist/web/topology-promote.js +25 -15
- package/dist/web/topology.js +2 -2
- package/dist/web/yaml-document-edit.js +2 -0
- package/dist/web-app/assets/index-BbTc5KtZ.js +10 -0
- package/dist/web-app/index.html +1 -1
- package/examples/fleet/agents/Alice.yaml +11 -0
- package/examples/fleet/agents/FleetCoordinator.yaml +7 -0
- package/examples/fleet/brains/claude-default.yaml +5 -0
- package/examples/fleet/roles/coordinator.yaml +5 -0
- package/examples/fleet/roles/developer.yaml +3 -0
- package/examples/fleet.yaml +74 -0
- package/package.json +2 -1
- package/dist/web-app/assets/index-DhMDVRU1.js +0 -10
package/dist/watchdog/config.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { isAbsolute } from 'node:path';
|
|
3
3
|
import { parseDuration } from '../duration.js';
|
|
4
|
-
import { ConfigError, ROLE_NAME_RE
|
|
5
|
-
import { validateIsolationConfig } from '../isolation/policy.js';
|
|
4
|
+
import { ConfigError, ROLE_NAME_RE } from '../config.js';
|
|
6
5
|
const WATCHDOG_KEYS = [
|
|
7
|
-
'coordinator', 'enabled', 'interval', 'watch', '
|
|
8
|
-
'identity', 'timeout', 'keep_reports', 'alert_cooldown', 'prompt_file',
|
|
6
|
+
'coordinator', 'enabled', 'interval', 'watch', 'agent',
|
|
7
|
+
'identity', 'timeout', 'keep_reports', 'alert_cooldown', 'prompt_file',
|
|
9
8
|
];
|
|
10
9
|
export const WATCHDOG_DEFAULT_INTERVAL_MS = 600_000;
|
|
11
10
|
export const WATCHDOG_MIN_INTERVAL_MS = 60_000;
|
|
@@ -21,7 +20,7 @@ function deepSub(v, vars) {
|
|
|
21
20
|
return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, deepSub(x, vars)]));
|
|
22
21
|
return v;
|
|
23
22
|
}
|
|
24
|
-
export function resolveWatchdogs(baseDoc, baseFile, roles, vars,
|
|
23
|
+
export function resolveWatchdogs(baseDoc, baseFile, roles, vars, agentDefinitions, resolveInline) {
|
|
25
24
|
const block = baseDoc.watchdogs;
|
|
26
25
|
if (block === undefined || block === null)
|
|
27
26
|
return [];
|
|
@@ -42,6 +41,9 @@ export function resolveWatchdogs(baseDoc, baseFile, roles, vars, defaults) {
|
|
|
42
41
|
if (roleNames.has(name))
|
|
43
42
|
throw new ConfigError(`${baseFile}: watchdog '${name}' collides with a role name`);
|
|
44
43
|
const w = deepSub(rawEntry ?? {}, vars);
|
|
44
|
+
const legacy = ['harness', 'model', 'session', 'isolation'].filter(key => Object.hasOwn(w, key));
|
|
45
|
+
if (legacy.length)
|
|
46
|
+
throw new ConfigError(`${where}: E_LEGACY Brain/Agent-owned field(s) ${legacy.join(', ')} are unsupported; select a canonical Agent with agent`);
|
|
45
47
|
const bad = Object.keys(w).filter(k => !WATCHDOG_KEYS.includes(k));
|
|
46
48
|
if (bad.length)
|
|
47
49
|
throw new ConfigError(`${where} has unknown key(s) ${bad.join(', ')}; allowed: ${WATCHDOG_KEYS.join(', ')}`);
|
|
@@ -60,23 +62,29 @@ export function resolveWatchdogs(baseDoc, baseFile, roles, vars, defaults) {
|
|
|
60
62
|
if (collidingWatchdog !== undefined)
|
|
61
63
|
throw new ConfigError(`${where}: identity '${identity}' collides with watchdog '${collidingWatchdog}'`);
|
|
62
64
|
watchdogIdentities.set(identity, name);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (
|
|
68
|
-
|
|
65
|
+
if (!w.agent || typeof w.agent !== 'object' || Array.isArray(w.agent))
|
|
66
|
+
throw new ConfigError(`${where}: agent is required (Agent ref or canonical Agent definition)`);
|
|
67
|
+
let agentDefinition;
|
|
68
|
+
let resolvedAgent;
|
|
69
|
+
if ('ref' in w.agent) {
|
|
70
|
+
const ref = w.agent.ref;
|
|
71
|
+
if (typeof ref !== 'string' || !ref)
|
|
72
|
+
throw new ConfigError(`${where}: agent.ref must be a declared Agent ID`);
|
|
73
|
+
agentDefinition = agentDefinitions[ref];
|
|
74
|
+
resolvedAgent = roles.find(role => role.name === ref);
|
|
75
|
+
if (!agentDefinition || !resolvedAgent)
|
|
76
|
+
throw new ConfigError(`${where}: Agent ref '${ref}' was not found`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
agentDefinition = structuredClone(w.agent);
|
|
80
|
+
resolvedAgent = resolveInline(name, agentDefinition);
|
|
81
|
+
}
|
|
69
82
|
if (w.prompt_file !== undefined) {
|
|
70
83
|
if (typeof w.prompt_file !== 'string' || !isAbsolute(w.prompt_file))
|
|
71
84
|
throw new ConfigError(`${where}: prompt_file must be an absolute path`);
|
|
72
85
|
if (!existsSync(w.prompt_file))
|
|
73
86
|
throw new ConfigError(`${where}: prompt_file not found: ${w.prompt_file}`);
|
|
74
87
|
}
|
|
75
|
-
if (w.isolation !== undefined) {
|
|
76
|
-
const problems = validateIsolationConfig(w.isolation);
|
|
77
|
-
if (problems.length)
|
|
78
|
-
throw new ConfigError(`${where} ${problems.join('; ')}`);
|
|
79
|
-
}
|
|
80
88
|
const dur = (v, key, fallback, minMs) => {
|
|
81
89
|
if (v === undefined)
|
|
82
90
|
return fallback;
|
|
@@ -96,13 +104,15 @@ export function resolveWatchdogs(baseDoc, baseFile, roles, vars, defaults) {
|
|
|
96
104
|
name, coordinator: w.coordinator.trim(),
|
|
97
105
|
enabled: w.enabled ?? true,
|
|
98
106
|
intervalMs: dur(w.interval, 'interval', WATCHDOG_DEFAULT_INTERVAL_MS, WATCHDOG_MIN_INTERVAL_MS),
|
|
99
|
-
watch, watchExplicit: w.watch !== undefined,
|
|
100
|
-
|
|
107
|
+
watch, watchExplicit: w.watch !== undefined,
|
|
108
|
+
agentDefinition: structuredClone(agentDefinition), resolvedAgent: structuredClone(resolvedAgent),
|
|
109
|
+
harness: resolvedAgent.harness, session: resolvedAgent.session,
|
|
110
|
+
model: resolvedAgent.model, isolation: resolvedAgent.isolation,
|
|
101
111
|
identity,
|
|
102
112
|
timeoutMs: dur(w.timeout, 'timeout', WATCHDOG_DEFAULT_TIMEOUT_MS),
|
|
103
113
|
keepReports,
|
|
104
114
|
alertCooldownMs: dur(w.alert_cooldown, 'alert_cooldown', WATCHDOG_DEFAULT_COOLDOWN_MS),
|
|
105
|
-
promptFile: w.prompt_file,
|
|
115
|
+
promptFile: w.prompt_file, sourceFile: baseFile,
|
|
106
116
|
});
|
|
107
117
|
}
|
|
108
118
|
return out;
|
package/dist/watchdog/run.js
CHANGED
|
@@ -10,7 +10,7 @@ import { applyRole } from '../ops.js';
|
|
|
10
10
|
import { daemonIdentityInventoryProvisioner, ensureIdentity, } from '../creation.js';
|
|
11
11
|
import { runOnce, START_STAGGER_FILE } from '../runner.js';
|
|
12
12
|
import { agentDir, tmpRoot } from '../paths.js';
|
|
13
|
-
import { loadConfig,
|
|
13
|
+
import { loadConfig, ROLE_NAME_RE, } from '../config.js';
|
|
14
14
|
import { getAdapter } from '../harness/registry.js';
|
|
15
15
|
import { redactLogLine } from '../application/log-service.js';
|
|
16
16
|
import { controlRequest, controlSocketPath } from '../session/control.js';
|
|
@@ -84,19 +84,10 @@ function readTail(runDir) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
/** The temp role every watchdog-family run launches under. Isolation is opt-in. */
|
|
87
|
-
function buildWatchdogRole(wd,
|
|
87
|
+
function buildWatchdogRole(wd, _cfg) {
|
|
88
88
|
return {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
identity: wd.identity, model: wd.model,
|
|
92
|
-
// Watchdogs are observe-only by contract, but their sanctioned status commands
|
|
93
|
-
// must reach host control sockets. Keep approvals/unattended escalation denied
|
|
94
|
-
// while disabling the harness's native filesystem/network sandbox.
|
|
95
|
-
permissions: { approval: 'deny', filesystem: 'unrestricted', unattended: 'deny' },
|
|
96
|
-
permissionsDeclared: true,
|
|
97
|
-
monitor: resolveMonitorConfig(cfg.defaults.monitor, undefined),
|
|
98
|
-
worklog: resolveWorklogPolicy(cfg.defaults.worklog, undefined),
|
|
99
|
-
isolation: wd.isolation,
|
|
89
|
+
...structuredClone(wd.resolvedAgent),
|
|
90
|
+
name: wd.identity, sourceFile: '(watchdog)', identity: wd.identity,
|
|
100
91
|
};
|
|
101
92
|
}
|
|
102
93
|
/** Discover temporary sessions that are live now, not merely stale dirs on disk. */
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { PrereqReport } from '../harness/types.js';
|
|
2
2
|
export declare const REDACTED_ENV_VALUE = "__OURS_FLEET_SECRET_REDACTED__";
|
|
3
|
-
export
|
|
3
|
+
export interface EditableFleetModel {
|
|
4
|
+
manifest: Record<string, unknown>;
|
|
5
|
+
agents: Record<string, Record<string, unknown>>;
|
|
6
|
+
}
|
|
4
7
|
export interface ConfigReadResult {
|
|
5
8
|
path: string;
|
|
6
|
-
exists:
|
|
7
|
-
firstRun:
|
|
9
|
+
exists: true;
|
|
10
|
+
firstRun: false;
|
|
8
11
|
revision: string;
|
|
9
12
|
model: EditableFleetModel;
|
|
10
13
|
redactions: string[];
|
|
@@ -33,15 +36,15 @@ export interface ConfigWriteResult extends ConfigPreviewResult {
|
|
|
33
36
|
export interface FleetConfigServiceOptions {
|
|
34
37
|
configPath?: string;
|
|
35
38
|
preflight?(configPath: string): Promise<PrereqReport>;
|
|
39
|
+
/** Fault-injection seam; called under lock immediately before each mutation. */
|
|
40
|
+
beforeMutation?(relativePath: string, index: number): void;
|
|
36
41
|
}
|
|
37
42
|
export declare class FleetConfigService {
|
|
38
43
|
readonly path: string;
|
|
39
44
|
private readonly preflight;
|
|
45
|
+
private readonly beforeMutation?;
|
|
40
46
|
constructor(options?: FleetConfigServiceOptions);
|
|
41
47
|
read(): ConfigReadResult;
|
|
42
|
-
preview(baseRevision: string,
|
|
43
|
-
write(baseRevision: string,
|
|
44
|
-
private readSource;
|
|
45
|
-
private assertRevision;
|
|
46
|
-
private validateCandidate;
|
|
48
|
+
preview(baseRevision: string, input: unknown): Promise<ConfigPreviewResult>;
|
|
49
|
+
write(baseRevision: string, input: unknown): Promise<ConfigWriteResult>;
|
|
47
50
|
}
|