@ours.network/fleet 0.12.0 → 0.13.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 +184 -0
- package/dist/briefing.js +10 -0
- package/dist/cli.js +404 -1
- package/dist/config.d.ts +18 -2
- package/dist/config.js +67 -3
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +111 -0
- package/dist/duration.js +7 -3
- package/dist/loops/config.d.ts +30 -0
- package/dist/loops/config.js +135 -0
- package/dist/loops/manager.d.ts +48 -0
- package/dist/loops/manager.js +237 -0
- package/dist/loops/state.d.ts +54 -0
- package/dist/loops/state.js +148 -0
- package/dist/monitor.js +26 -2
- package/dist/owner-channel/attachments.d.ts +74 -0
- package/dist/owner-channel/attachments.js +378 -0
- package/dist/owner-channel/channel.d.ts +114 -2
- package/dist/owner-channel/channel.js +622 -43
- package/dist/owner-channel/notices.d.ts +21 -0
- package/dist/owner-channel/notices.js +66 -0
- package/dist/owner-channel/state.d.ts +34 -0
- package/dist/owner-channel/state.js +148 -1
- package/dist/owner-channel/tasks.d.ts +62 -0
- package/dist/owner-channel/tasks.js +246 -0
- package/dist/resolved-plan.js +11 -0
- package/dist/runner.js +86 -7
- package/dist/session/acp.d.ts +3 -2
- package/dist/session/acp.js +67 -25
- package/dist/session/arbiter.d.ts +42 -0
- package/dist/session/arbiter.js +72 -0
- package/dist/session/control.d.ts +12 -1
- package/dist/session/control.js +56 -3
- package/dist/session/types.d.ts +26 -2
- package/dist/session/types.js +5 -2
- package/dist/supervisor/systemd.js +12 -2
- package/package.json +1 -1
package/dist/session/types.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import type { SessionBackendId } from '../config.js';
|
|
2
2
|
export type SessionReadiness = 'starting' | 'idle' | 'running' | 'awaiting_permission' | 'failed';
|
|
3
3
|
export type TurnOutcome = 'completed' | 'refused' | 'cancelled' | 'failed' | 'inconclusive';
|
|
4
|
+
export type TurnCancellationSource = 'owner' | 'local-console' | 'fleet-monitor' | 'scheduled-loop' | 'shutdown';
|
|
5
|
+
export type PromptOrigin = {
|
|
6
|
+
kind: 'startup';
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'local-console';
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'owner';
|
|
11
|
+
requestId: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'fleet-monitor';
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'scheduled-loop';
|
|
16
|
+
loop: string;
|
|
17
|
+
runId: string;
|
|
18
|
+
};
|
|
4
19
|
/**
|
|
5
20
|
* Two independent facts about one turn, deliberately kept apart:
|
|
6
21
|
*
|
|
@@ -19,6 +34,8 @@ export interface TurnResult {
|
|
|
19
34
|
outcome: TurnOutcome;
|
|
20
35
|
succeeded: boolean;
|
|
21
36
|
detail?: string;
|
|
37
|
+
/** Present only when fleet can prove what initiated a cancelled turn. */
|
|
38
|
+
cancellationSource?: TurnCancellationSource;
|
|
22
39
|
/** Final assistant text captured structurally by a backend, when available. */
|
|
23
40
|
output?: string;
|
|
24
41
|
}
|
|
@@ -41,6 +58,7 @@ export interface QueuedPrompt {
|
|
|
41
58
|
promptId: string;
|
|
42
59
|
/** Turns already queued ahead of this one. 0 means it starts immediately. */
|
|
43
60
|
queuedBehind: number;
|
|
61
|
+
origin?: PromptOrigin;
|
|
44
62
|
/** The turn's terminal result. Never rejects. */
|
|
45
63
|
completion: Promise<TurnResult>;
|
|
46
64
|
}
|
|
@@ -77,10 +95,14 @@ export declare function classifyChildExit(code: number | null, signal: string |
|
|
|
77
95
|
/** The single definition of terminal success. Nothing else may re-derive it. */
|
|
78
96
|
export declare const isTerminalSuccess: (outcome: TurnOutcome) => boolean;
|
|
79
97
|
/** Build a TurnResult with `succeeded` always consistent with `outcome`. */
|
|
80
|
-
export declare function turnResult(accepted: boolean, outcome: TurnOutcome, detail?: string, output?: string): TurnResult;
|
|
98
|
+
export declare function turnResult(accepted: boolean, outcome: TurnOutcome, detail?: string, output?: string, cancellationSource?: TurnCancellationSource): TurnResult;
|
|
81
99
|
export interface SubmitPromptOptions {
|
|
82
100
|
/** Cancel active work before delivering this prompt. */
|
|
83
101
|
interrupt?: boolean;
|
|
102
|
+
/** Internal provenance; ordinary callers must leave this unset. */
|
|
103
|
+
interruptSource?: TurnCancellationSource;
|
|
104
|
+
/** Typed in-process provenance. Text markers never grant this origin. */
|
|
105
|
+
origin?: PromptOrigin;
|
|
84
106
|
/** Use the ACP steering extension when available; ignored by other backends. */
|
|
85
107
|
steer?: boolean;
|
|
86
108
|
}
|
|
@@ -107,6 +129,8 @@ export interface SessionEvent {
|
|
|
107
129
|
title?: string;
|
|
108
130
|
status?: string;
|
|
109
131
|
stopReason?: string;
|
|
132
|
+
origin?: PromptOrigin;
|
|
133
|
+
cancellationSource?: TurnCancellationSource;
|
|
110
134
|
options?: Array<{
|
|
111
135
|
optionId: string;
|
|
112
136
|
name: string;
|
|
@@ -135,7 +159,7 @@ export interface SessionHandle {
|
|
|
135
159
|
queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
|
|
136
160
|
/** Queue a prompt and wait for its terminal result. */
|
|
137
161
|
submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
|
|
138
|
-
interrupt(): Promise<void>;
|
|
162
|
+
interrupt(source?: TurnCancellationSource): Promise<void>;
|
|
139
163
|
respondPermission(permissionId: string, optionId: string): boolean;
|
|
140
164
|
eventsSince(seq: number): SessionEvent[];
|
|
141
165
|
subscribe(listener: (event: SessionEvent) => void): () => void;
|
package/dist/session/types.js
CHANGED
|
@@ -37,6 +37,9 @@ export function classifyChildExit(code, signal) {
|
|
|
37
37
|
/** The single definition of terminal success. Nothing else may re-derive it. */
|
|
38
38
|
export const isTerminalSuccess = (outcome) => outcome === 'completed';
|
|
39
39
|
/** Build a TurnResult with `succeeded` always consistent with `outcome`. */
|
|
40
|
-
export function turnResult(accepted, outcome, detail, output) {
|
|
41
|
-
return {
|
|
40
|
+
export function turnResult(accepted, outcome, detail, output, cancellationSource) {
|
|
41
|
+
return {
|
|
42
|
+
accepted, outcome, succeeded: isTerminalSuccess(outcome), detail, output,
|
|
43
|
+
...(outcome === 'cancelled' && cancellationSource ? { cancellationSource } : {}),
|
|
44
|
+
};
|
|
42
45
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
2
|
+
import { delimiter, dirname, join } from 'node:path';
|
|
3
3
|
import { userInfo } from 'node:os';
|
|
4
4
|
import { home } from '../paths.js';
|
|
5
5
|
import { realExec } from '../exec.js';
|
|
@@ -15,6 +15,8 @@ export const busHint = (stderr) => /user scope bus|XDG_RUNTIME_DIR/.test(stderr)
|
|
|
15
15
|
`\n (if linger is already on: export XDG_RUNTIME_DIR=/run/user/$(id -u))`
|
|
16
16
|
: '';
|
|
17
17
|
export const unitFor = (name) => `ours-fleet-agent@${name}.service`;
|
|
18
|
+
/** Quote a systemd unit argument and escape its specifier marker. */
|
|
19
|
+
const unitArg = (value) => `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/%/g, '%%')}"`;
|
|
18
20
|
/**
|
|
19
21
|
* systemd's own ActiveState vocabulary, classified. `activating` covers
|
|
20
22
|
* `auto-restart` — the unit is mid-restart, not stopped, so its context stands.
|
|
@@ -60,6 +62,13 @@ export function makeSystemdBackend(exec = realExec) {
|
|
|
60
62
|
async init(binPath) {
|
|
61
63
|
const msgs = [];
|
|
62
64
|
const unitDir = join(home(), '.config', 'systemd', 'user');
|
|
65
|
+
// Lingering user units often start before a login shell imports its PATH.
|
|
66
|
+
// Pin the Node runtime and persist the install-time PATH so the runner and
|
|
67
|
+
// children such as `ours-mcp proxy` resolve the same tools after reboot.
|
|
68
|
+
const servicePath = [...new Set([
|
|
69
|
+
dirname(process.execPath),
|
|
70
|
+
...(process.env.PATH ?? '').split(delimiter),
|
|
71
|
+
].filter(Boolean))].join(delimiter);
|
|
63
72
|
mkdirSync(unitDir, { recursive: true });
|
|
64
73
|
writeFileSync(join(unitDir, UNIT_TEMPLATE), `[Unit]
|
|
65
74
|
Description=ours-fleet agent %i
|
|
@@ -67,7 +76,8 @@ After=default.target
|
|
|
67
76
|
|
|
68
77
|
[Service]
|
|
69
78
|
Type=simple
|
|
70
|
-
|
|
79
|
+
Environment="PATH=${servicePath.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/%/g, '%%')}"
|
|
80
|
+
ExecStart=${unitArg(process.execPath)} ${unitArg(binPath)} _run %i
|
|
71
81
|
# The RUNNER owns the child-session restart loop, with a counted, backed-off
|
|
72
82
|
# circuit breaker (3.2). systemd must only recover the runner PROCESS crashing —
|
|
73
83
|
# Restart=always here would resume the uncounted two-second relaunch loop, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
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",
|