harnery 0.13.0 → 0.14.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 +1 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +2 -0
- package/dist/commands/work.d.ts +4 -0
- package/dist/commands/work.d.ts.map +1 -0
- package/dist/commands/work.js +281 -0
- package/dist/core/work/index.d.ts +3 -0
- package/dist/core/work/index.d.ts.map +1 -0
- package/dist/core/work/index.js +2 -0
- package/dist/core/work/read.d.ts +2 -0
- package/dist/core/work/read.d.ts.map +1 -0
- package/dist/core/work/read.js +1 -0
- package/dist/core/work/runner.d.ts +10 -0
- package/dist/core/work/runner.d.ts.map +1 -0
- package/dist/core/work/runner.js +63 -0
- package/dist/core/work/state.d.ts +109 -0
- package/dist/core/work/state.d.ts.map +1 -0
- package/dist/core/work/state.js +698 -0
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +20 -1
- package/dist/core/workflow/proof.d.ts +1 -0
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +1 -0
- package/dist/core/workflow/run-state.d.ts +1 -0
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +2 -0
- package/dist/core/workflow/types.d.ts +7 -0
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/package.json +11 -1
- package/src/commander.ts +2 -0
- package/src/commands/work.ts +367 -0
- package/src/core/work/index.ts +24 -0
- package/src/core/work/read.ts +15 -0
- package/src/core/work/runner.ts +81 -0
- package/src/core/work/state.ts +900 -0
- package/src/core/workflow/engine.ts +21 -1
- package/src/core/workflow/proof.ts +2 -0
- package/src/core/workflow/run-state.ts +3 -0
- package/src/core/workflow/types.ts +7 -0
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
- **Multi-agent coordination:** per-agent heartbeats in `.harnery/active/`, claim-time and commit-time guards, the canonical event stream, councils, a decision docket, per-agent scratchpads, and harness adapters for Claude Code / Cursor / Codex.
|
|
23
23
|
- **Cross-machine presence:** sessions on every machine that shares a repo see each other, labeled by machine. Zero-config over the repo's own git remote (presence refs), with an optional live-socket upgrade via an end-to-end-encrypted relay — the public `relay.harnery.com`, or self-host with `harn relay serve` / the bundled Cloudflare Worker (`relay/worker/`). The relay sees only ciphertext in opaquely-named rooms.
|
|
24
24
|
- **Coordination-aware workflows:** `harn workflow run <script>` executes bounded, schema-gated multi-subagent workflow scripts — plain JS stages fanning out to headless harness-CLI subagents that are born coordination-registered (heartbeats, events, claim guards), with deterministic code deciding the routing between stages. An optional host-owned policy gates dispatch and declared external mutations with `ALLOW`, `ASK`, and `DENY`; CLI `ASK` requests park durably for an explicit approve/deny and same-run resume, while library callers remain fail-closed by default.
|
|
25
|
+
- **Durable work above attempts:** `harn work` preserves an objective across bounded workflow attempts, dependencies, approval parks, failures, and review. Its one-shot reconciler derives state from append-only local evidence and reports the next explicit action without silently spawning, retrying, or accepting work.
|
|
25
26
|
- **Standalone web UI:** `harn web up` boots a local Next.js dashboard for the coord layer, councils, per-project state, and a local coding-agent status view (Claude Code / Codex / Cursor usage, backed by `harn devtools`). Ships with the git clone, not the npm package (see [Install](#install)).
|
|
26
27
|
- **Backup + sync:** `harn backup` snapshots `.harnery/` via [restic](https://restic.net/); `harn sync` keeps a curated subset live across machines via [rclone](https://rclone.org/) (Google Drive or any rclone remote).
|
|
27
28
|
|
package/dist/commander.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commander.d.ts","sourceRoot":"","sources":["../src/commander.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"commander.d.ts","sourceRoot":"","sources":["../src/commander.ts"],"names":[],"mappings":"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"}
|
package/dist/commander.js
CHANGED
|
@@ -52,6 +52,7 @@ import { registerSectionCommand, registerTocCommand } from "./commands/toc.js";
|
|
|
52
52
|
import { registerTokensCommand } from "./commands/tokens.js";
|
|
53
53
|
import { registerTunnelCommand } from "./commands/tunnel.js";
|
|
54
54
|
import { registerWebCommand } from "./commands/web.js";
|
|
55
|
+
import { registerWorkCommand } from "./commands/work.js";
|
|
55
56
|
import { registerWorkflowCommand } from "./commands/workflow.js";
|
|
56
57
|
export const defaultEmit = {
|
|
57
58
|
config() {
|
|
@@ -132,6 +133,7 @@ export function createHarneryProgram(opts = {}) {
|
|
|
132
133
|
registerClaudeDesktopCommand(program, emit);
|
|
133
134
|
registerSyncCommand(program, emit);
|
|
134
135
|
registerWorkflowCommand(program, emit);
|
|
136
|
+
registerWorkCommand(program, emit);
|
|
135
137
|
if (include("web"))
|
|
136
138
|
registerWebCommand(program, emit);
|
|
137
139
|
return program;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work.d.ts","sourceRoot":"","sources":["../../src/commands/work.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAmDnD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA8F7E"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { workflowSubscriptionOnly } from "../core/config.js";
|
|
2
|
+
import { createBuiltinHarnessRegistry } from "../core/harnesses/index.js";
|
|
3
|
+
import { findCoordRoot } from "../core/hooks/resolve/coord-root.js";
|
|
4
|
+
import { loadPolicyFile } from "../core/policy/index.js";
|
|
5
|
+
import { acceptWorkItem, cancelWorkItem, createWorkItem, listWorkItems, readWorkItem, reconcileAllWorkItems, reconcileWorkItem, reopenWorkItem, runWorkItem, } from "../core/work/index.js";
|
|
6
|
+
import { WorkflowParkedError } from "../core/workflow/index.js";
|
|
7
|
+
export function registerWorkCommand(program, emit) {
|
|
8
|
+
const registry = createBuiltinHarnessRegistry();
|
|
9
|
+
const harnesses = registry.ids();
|
|
10
|
+
const work = program
|
|
11
|
+
.command("work")
|
|
12
|
+
.description("Track durable objectives across bounded workflow attempts.");
|
|
13
|
+
work
|
|
14
|
+
.command("create <title> <workflow>")
|
|
15
|
+
.description("Create an immutable durable-work intent linked to a workflow script.")
|
|
16
|
+
.requiredOption("--objective <text>", "Objective that must survive execution attempts")
|
|
17
|
+
.option("--id <work-id>", "Stable work id (generated by default)")
|
|
18
|
+
.option("--accept <text>", "Acceptance statement; repeat for more than one", collect, [])
|
|
19
|
+
.option("--depends-on <ids>", "Comma-separated prerequisite work ids")
|
|
20
|
+
.option("--max-attempts <n>", "Attempt ceiling (default 3)")
|
|
21
|
+
.option("--source-kind <kind>", "human | workflow | external", "human")
|
|
22
|
+
.option("--source-ref <ref>", "Bounded source reference")
|
|
23
|
+
.option("--actor <name>", "Actor recorded in the creation receipt")
|
|
24
|
+
.option("--json", "Emit the complete work record as JSON")
|
|
25
|
+
.action((title, workflowPath, opts) => {
|
|
26
|
+
withWorkRoot(emit, (coordRoot) => {
|
|
27
|
+
const record = createWorkItem({
|
|
28
|
+
coordRoot,
|
|
29
|
+
id: opts.id,
|
|
30
|
+
title,
|
|
31
|
+
objective: opts.objective,
|
|
32
|
+
workflowPath,
|
|
33
|
+
acceptance: opts.accept,
|
|
34
|
+
dependencies: splitIds(opts.dependsOn),
|
|
35
|
+
maxAttempts: opts.maxAttempts ? Number.parseInt(opts.maxAttempts, 10) : undefined,
|
|
36
|
+
source: opts.sourceKind ? { kind: opts.sourceKind, ref: opts.sourceRef } : undefined,
|
|
37
|
+
actor: opts.actor,
|
|
38
|
+
});
|
|
39
|
+
emitWork(record, opts.json, emit);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
work
|
|
43
|
+
.command("list")
|
|
44
|
+
.description("List durable work with its currently derived state.")
|
|
45
|
+
.option("--state <state>", "Filter by derived state")
|
|
46
|
+
.option("--json", "Emit complete work records as JSON")
|
|
47
|
+
.action((opts) => {
|
|
48
|
+
withWorkRoot(emit, (coordRoot) => {
|
|
49
|
+
const records = listWorkItems(coordRoot).filter((record) => !opts.state || record.projection.state === opts.state);
|
|
50
|
+
if (opts.json) {
|
|
51
|
+
emit.config({ format: "json" });
|
|
52
|
+
emit.data(records);
|
|
53
|
+
}
|
|
54
|
+
else if (records.length === 0) {
|
|
55
|
+
emit.text("no durable work\n");
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
emit.text(`${records.map(renderWorkRow).join("\n")}\n`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
work
|
|
63
|
+
.command("show <work-id>")
|
|
64
|
+
.description("Show one work item, its attempts, and the next explicit action.")
|
|
65
|
+
.option("--json", "Emit the complete work record as JSON")
|
|
66
|
+
.action((workId, opts) => {
|
|
67
|
+
withWorkRoot(emit, (coordRoot) => {
|
|
68
|
+
emitWork(readWorkItem(coordRoot, workId), opts.json, emit, true);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
work
|
|
72
|
+
.command("reconcile [work-id]")
|
|
73
|
+
.description("Derive state from durable evidence without starting or retrying work.")
|
|
74
|
+
.option("--actor <name>", "Actor recorded on changed reconciliation receipts")
|
|
75
|
+
.option("--json", "Emit reconciled work records as JSON")
|
|
76
|
+
.action((workId, opts) => {
|
|
77
|
+
withWorkRoot(emit, (coordRoot) => {
|
|
78
|
+
const records = workId
|
|
79
|
+
? [reconcileWorkItem(coordRoot, workId, opts.actor)]
|
|
80
|
+
: reconcileAllWorkItems(coordRoot, opts.actor);
|
|
81
|
+
if (opts.json) {
|
|
82
|
+
emit.config({ format: "json" });
|
|
83
|
+
emit.data(workId ? records[0] : records);
|
|
84
|
+
}
|
|
85
|
+
else if (records.length === 0) {
|
|
86
|
+
emit.text("no durable work\n");
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
emit.text(`${records.map(renderWorkRow).join("\n")}\n`);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
registerRunCommand(work, "run", false, registry, harnesses, emit);
|
|
94
|
+
registerRunCommand(work, "retry", true, registry, harnesses, emit);
|
|
95
|
+
registerGovernanceCommand(work, "accept", emit);
|
|
96
|
+
registerGovernanceCommand(work, "cancel", emit);
|
|
97
|
+
registerGovernanceCommand(work, "reopen", emit);
|
|
98
|
+
}
|
|
99
|
+
function registerRunCommand(work, name, retry, registry, harnesses, emit) {
|
|
100
|
+
work
|
|
101
|
+
.command(`${name} <work-id>`)
|
|
102
|
+
.description(retry
|
|
103
|
+
? "Start a new bounded attempt after a blocked run."
|
|
104
|
+
: "Start ready work or resume its resolved parked attempt.")
|
|
105
|
+
.option("--max-agents <n>", "Total-agent ceiling for the workflow")
|
|
106
|
+
.option("--concurrency <n>", "Concurrent-subagent cap")
|
|
107
|
+
.option("--cwd <dir>", "Working directory children spawn in")
|
|
108
|
+
.option("--harness <name>", `Default harness: ${harnesses.join(" | ")}`)
|
|
109
|
+
.option("--subscription-only", "Require stored harness-login billing")
|
|
110
|
+
.option("--allow-api-billing", "Permit API-key override billing")
|
|
111
|
+
.option("--policy <file>", "Host policy JSON/JSONC")
|
|
112
|
+
.option("--isolation <mode>", "shared | worktree | sandbox | remote")
|
|
113
|
+
.option("--approval-to <address>", "Address durable ASK requests")
|
|
114
|
+
.option("--actor <name>", "Actor recorded in attempt receipts")
|
|
115
|
+
.option("--json", "Emit the workflow report or parked result as JSON")
|
|
116
|
+
.action(async (workId, opts) => {
|
|
117
|
+
await withWorkRootAsync(emit, async (coordRoot) => {
|
|
118
|
+
if (opts.harness && !registry.get(opts.harness)) {
|
|
119
|
+
throw new Error(`unknown harness ${JSON.stringify(opts.harness)}`);
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const report = await runWorkItem({
|
|
123
|
+
coordRoot,
|
|
124
|
+
workId,
|
|
125
|
+
retry,
|
|
126
|
+
actor: opts.actor,
|
|
127
|
+
engine: {
|
|
128
|
+
spawners: registry.spawners(),
|
|
129
|
+
defaultHarness: opts.harness,
|
|
130
|
+
maxAgents: opts.maxAgents ? Number.parseInt(opts.maxAgents, 10) : undefined,
|
|
131
|
+
concurrency: opts.concurrency ? Number.parseInt(opts.concurrency, 10) : undefined,
|
|
132
|
+
cwd: opts.cwd,
|
|
133
|
+
subscriptionOnly: opts.subscriptionOnly === true ? true : workflowSubscriptionOnly(coordRoot),
|
|
134
|
+
allowApiBilling: opts.allowApiBilling,
|
|
135
|
+
harnessEvidence: Object.fromEntries(registry
|
|
136
|
+
.list()
|
|
137
|
+
.map((adapter) => [
|
|
138
|
+
adapter.profile.id,
|
|
139
|
+
{ toolEvidence: adapter.profile.capabilities.toolEvidence },
|
|
140
|
+
])),
|
|
141
|
+
policy: opts.policy ? loadPolicyFile(opts.policy) : undefined,
|
|
142
|
+
approvalMode: "park",
|
|
143
|
+
approvalAddressee: opts.approvalTo,
|
|
144
|
+
isolation: opts.isolation,
|
|
145
|
+
networkAccess: "enabled",
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
if (opts.json) {
|
|
149
|
+
emit.config({ format: "json" });
|
|
150
|
+
emit.data(report);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
emit.text(`work ${workId}: run ${report.runId} finished\nproof: ${report.proofPath}\n` +
|
|
154
|
+
`next: harn work reconcile ${workId}\n`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (error instanceof WorkflowParkedError) {
|
|
159
|
+
if (opts.json) {
|
|
160
|
+
emit.config({ format: "json" });
|
|
161
|
+
emit.data({
|
|
162
|
+
status: "parked",
|
|
163
|
+
workId,
|
|
164
|
+
runId: error.runId,
|
|
165
|
+
approvalId: error.approvalId,
|
|
166
|
+
journalPath: error.journalPath,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
emit.text(`work ${workId}: run ${error.runId} parked\napproval: ${error.approvalId}\n` +
|
|
171
|
+
`next: resolve the approval, then harn work run ${workId}\n`);
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function registerGovernanceCommand(work, name, emit) {
|
|
181
|
+
work
|
|
182
|
+
.command(`${name} <work-id>`)
|
|
183
|
+
.description(name === "accept"
|
|
184
|
+
? "Explicitly accept reviewed proof and complete the objective."
|
|
185
|
+
: name === "cancel"
|
|
186
|
+
? "Explicitly cancel unfinished durable work."
|
|
187
|
+
: "Explicitly reopen terminal or blocked work for a future attempt.")
|
|
188
|
+
.option("--actor <name>", "Actor recorded in the governance receipt")
|
|
189
|
+
.option("--reason <text>", "Bounded decision reason")
|
|
190
|
+
.option("--json", "Emit the complete work record as JSON")
|
|
191
|
+
.action((workId, opts) => {
|
|
192
|
+
withWorkRoot(emit, (coordRoot) => {
|
|
193
|
+
const fn = name === "accept" ? acceptWorkItem : name === "cancel" ? cancelWorkItem : reopenWorkItem;
|
|
194
|
+
emitWork(fn(coordRoot, workId, opts), opts.json, emit, true);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function emitWork(record, json, emit, detail = false) {
|
|
199
|
+
if (json) {
|
|
200
|
+
emit.config({ format: "json" });
|
|
201
|
+
emit.data(record);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!detail) {
|
|
205
|
+
emit.text(`${renderWorkRow(record)}\n`);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const projection = record.projection;
|
|
209
|
+
const lines = [
|
|
210
|
+
`${record.intent.id}: ${record.intent.title}`,
|
|
211
|
+
`state: ${projection.state}`,
|
|
212
|
+
`objective: ${record.intent.objective}`,
|
|
213
|
+
`reason: ${projection.reason}`,
|
|
214
|
+
`next: ${projection.next_action}`,
|
|
215
|
+
`attempts: ${projection.attempts_used}/${record.intent.max_attempts}`,
|
|
216
|
+
];
|
|
217
|
+
if (record.intent.dependencies.length)
|
|
218
|
+
lines.push(`depends on: ${record.intent.dependencies.join(", ")}`);
|
|
219
|
+
if (record.intent.acceptance.length) {
|
|
220
|
+
lines.push("acceptance:", ...record.intent.acceptance.map((item) => ` - ${item}`));
|
|
221
|
+
}
|
|
222
|
+
if (projection.attempts.length) {
|
|
223
|
+
lines.push("attempts:", ...projection.attempts.map((attempt) => ` ${attempt.number}. ${attempt.run_id} ${attempt.status}`));
|
|
224
|
+
}
|
|
225
|
+
if (projection.approval_id)
|
|
226
|
+
lines.push(`approval: ${projection.approval_id}`);
|
|
227
|
+
if (projection.proof_path)
|
|
228
|
+
lines.push(`proof: ${projection.proof_path}`);
|
|
229
|
+
emit.text(`${lines.join("\n")}\n`);
|
|
230
|
+
}
|
|
231
|
+
function renderWorkRow(record) {
|
|
232
|
+
const projection = record.projection;
|
|
233
|
+
return `${record.intent.id} ${projection.state.padEnd(17)} ${projection.attempts_used}/${record.intent.max_attempts} ${projection.next_action.padEnd(21)} ${record.intent.title}`;
|
|
234
|
+
}
|
|
235
|
+
function withWorkRoot(emit, fn) {
|
|
236
|
+
const coordRoot = findCoordRoot();
|
|
237
|
+
if (!coordRoot) {
|
|
238
|
+
emit.error({
|
|
239
|
+
code: "no_coord_root",
|
|
240
|
+
message: "no .harnery/ coordination root found; run `init` first",
|
|
241
|
+
});
|
|
242
|
+
emit.setExitCode(1);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
fn(coordRoot);
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
emit.error({ code: "work_failed", message: error.message });
|
|
250
|
+
emit.setExitCode(1);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async function withWorkRootAsync(emit, fn) {
|
|
254
|
+
const coordRoot = findCoordRoot();
|
|
255
|
+
if (!coordRoot) {
|
|
256
|
+
emit.error({
|
|
257
|
+
code: "no_coord_root",
|
|
258
|
+
message: "no .harnery/ coordination root found; run `init` first",
|
|
259
|
+
});
|
|
260
|
+
emit.setExitCode(1);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
await fn(coordRoot);
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
emit.error({ code: "work_failed", message: error.message });
|
|
268
|
+
emit.setExitCode(1);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function splitIds(value) {
|
|
272
|
+
return value
|
|
273
|
+
? value
|
|
274
|
+
.split(",")
|
|
275
|
+
.map((item) => item.trim())
|
|
276
|
+
.filter(Boolean)
|
|
277
|
+
: [];
|
|
278
|
+
}
|
|
279
|
+
function collect(value, previous) {
|
|
280
|
+
return [...previous, value];
|
|
281
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { type RunWorkItemInput, runWorkItem } from "./runner.js";
|
|
2
|
+
export { acceptWorkItem, assertWorkId, type CreateWorkItemInput, cancelWorkItem, createWorkItem, listWorkItems, newWorkId, readWorkItem, reconcileAllWorkItems, reconcileWorkItem, reopenWorkItem, WORK_EVENT_SCHEMA_VERSION, WORK_INTENT_SCHEMA_VERSION, type WorkAttempt, type WorkEvent, type WorkEventType, type WorkIntent, type WorkNextAction, type WorkProjection, type WorkRecord, type WorkState, } from "./state.js";
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/work/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EACL,cAAc,EACd,YAAY,EACZ,KAAK,mBAAmB,EACxB,cAAc,EACd,cAAc,EACd,aAAa,EACb,SAAS,EACT,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,yBAAyB,EACzB,0BAA0B,EAC1B,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { runWorkItem } from "./runner.js";
|
|
2
|
+
export { acceptWorkItem, assertWorkId, cancelWorkItem, createWorkItem, listWorkItems, newWorkId, readWorkItem, reconcileAllWorkItems, reconcileWorkItem, reopenWorkItem, WORK_EVENT_SCHEMA_VERSION, WORK_INTENT_SCHEMA_VERSION, } from "./state.js";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { assertWorkId, listWorkItems, readWorkItem, WORK_EVENT_SCHEMA_VERSION, WORK_INTENT_SCHEMA_VERSION, type WorkAttempt, type WorkEvent, type WorkEventType, type WorkIntent, type WorkNextAction, type WorkProjection, type WorkRecord, type WorkState, } from "./state.js";
|
|
2
|
+
//# sourceMappingURL=read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/work/read.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,yBAAyB,EACzB,0BAA0B,EAC1B,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { assertWorkId, listWorkItems, readWorkItem, WORK_EVENT_SCHEMA_VERSION, WORK_INTENT_SCHEMA_VERSION, } from "./state.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EngineOpts, RunReport } from "../workflow/types.js";
|
|
2
|
+
export interface RunWorkItemInput {
|
|
3
|
+
coordRoot: string;
|
|
4
|
+
workId: string;
|
|
5
|
+
engine: Omit<EngineOpts, "coordRoot" | "runId" | "resumeRunId" | "workItemId">;
|
|
6
|
+
retry?: boolean;
|
|
7
|
+
actor?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function runWorkItem(input: RunWorkItemInput): Promise<RunReport>;
|
|
10
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/work/runner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAWlE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,OAAO,GAAG,aAAa,GAAG,YAAY,CAAC,CAAC;IAC/E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CA2D7E"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { runWorkflow } from "../workflow/engine.js";
|
|
3
|
+
import { acquireWorkLease, appendReconcileIfChanged, appendWorkEvent, assertWorkflowUnchanged, boundedActor, newWorkflowRunId, readWorkItemIgnoringLease, } from "./state.js";
|
|
4
|
+
export async function runWorkItem(input) {
|
|
5
|
+
const coordRoot = resolve(input.coordRoot);
|
|
6
|
+
const release = acquireWorkLease(coordRoot, input.workId);
|
|
7
|
+
try {
|
|
8
|
+
const record = readWorkItemIgnoringLease(coordRoot, input.workId);
|
|
9
|
+
assertWorkflowUnchanged(record.intent);
|
|
10
|
+
const latest = record.projection.attempts.at(-1);
|
|
11
|
+
if (record.projection.state === "awaiting_approval" && latest) {
|
|
12
|
+
if (record.projection.next_action !== "resume") {
|
|
13
|
+
throw new Error(`work item ${input.workId} is waiting for approval ${latest.approval_id}`);
|
|
14
|
+
}
|
|
15
|
+
appendWorkEvent(coordRoot, input.workId, {
|
|
16
|
+
event: "attempt.resumed",
|
|
17
|
+
actor: boundedActor(input.actor),
|
|
18
|
+
reason: "resuming the parked workflow attempt",
|
|
19
|
+
run_id: latest.run_id,
|
|
20
|
+
attempt: latest.number,
|
|
21
|
+
});
|
|
22
|
+
return await runWorkflow(record.intent.workflow.path, {
|
|
23
|
+
...input.engine,
|
|
24
|
+
coordRoot,
|
|
25
|
+
resumeRunId: latest.run_id,
|
|
26
|
+
workItemId: input.workId,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (record.projection.state === "blocked" && !input.retry) {
|
|
30
|
+
throw new Error(`work item ${input.workId} is blocked; use an explicit retry`);
|
|
31
|
+
}
|
|
32
|
+
if (!(record.projection.state === "ready" || record.projection.state === "blocked")) {
|
|
33
|
+
throw new Error(`work item ${input.workId} cannot run from state ${record.projection.state}`);
|
|
34
|
+
}
|
|
35
|
+
if (record.projection.attempts_used >= record.intent.max_attempts) {
|
|
36
|
+
throw new Error(`work item ${input.workId} exhausted its ${record.intent.max_attempts} attempts`);
|
|
37
|
+
}
|
|
38
|
+
const attempt = record.projection.attempts_used + 1;
|
|
39
|
+
const runId = newWorkflowRunId();
|
|
40
|
+
appendWorkEvent(coordRoot, input.workId, {
|
|
41
|
+
event: "attempt.started",
|
|
42
|
+
actor: boundedActor(input.actor),
|
|
43
|
+
reason: input.retry ? "explicit retry started" : "workflow attempt started",
|
|
44
|
+
run_id: runId,
|
|
45
|
+
attempt,
|
|
46
|
+
});
|
|
47
|
+
return await runWorkflow(record.intent.workflow.path, {
|
|
48
|
+
...input.engine,
|
|
49
|
+
coordRoot,
|
|
50
|
+
runId,
|
|
51
|
+
workItemId: input.workId,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
try {
|
|
56
|
+
const current = readWorkItemIgnoringLease(coordRoot, input.workId);
|
|
57
|
+
appendReconcileIfChanged(coordRoot, current, boundedActor(input.actor, "work-runner"));
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
release();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export declare const WORK_INTENT_SCHEMA_VERSION: 1;
|
|
2
|
+
export declare const WORK_EVENT_SCHEMA_VERSION: 1;
|
|
3
|
+
export type WorkState = "waiting" | "ready" | "running" | "awaiting_approval" | "in_review" | "blocked" | "succeeded" | "cancelled";
|
|
4
|
+
export type WorkNextAction = "wait_for_dependencies" | "run" | "wait_for_run" | "resolve_approval" | "resume" | "retry" | "review" | "none";
|
|
5
|
+
export interface WorkIntent {
|
|
6
|
+
schema_version: typeof WORK_INTENT_SCHEMA_VERSION;
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
objective: string;
|
|
10
|
+
acceptance: string[];
|
|
11
|
+
dependencies: string[];
|
|
12
|
+
workflow: {
|
|
13
|
+
path: string;
|
|
14
|
+
sha256: string;
|
|
15
|
+
};
|
|
16
|
+
max_attempts: number;
|
|
17
|
+
source?: {
|
|
18
|
+
kind: "human" | "workflow" | "external";
|
|
19
|
+
ref?: string;
|
|
20
|
+
};
|
|
21
|
+
created_at: string;
|
|
22
|
+
}
|
|
23
|
+
export type WorkEventType = "work.created" | "work.reconciled" | "attempt.started" | "attempt.resumed" | "work.accepted" | "work.cancelled" | "work.reopened";
|
|
24
|
+
export interface WorkEvent {
|
|
25
|
+
schema_version: typeof WORK_EVENT_SCHEMA_VERSION;
|
|
26
|
+
work_id: string;
|
|
27
|
+
seq: number;
|
|
28
|
+
ts: string;
|
|
29
|
+
event: WorkEventType;
|
|
30
|
+
actor: string;
|
|
31
|
+
reason?: string;
|
|
32
|
+
run_id?: string;
|
|
33
|
+
attempt?: number;
|
|
34
|
+
state?: WorkState;
|
|
35
|
+
next_action?: WorkNextAction;
|
|
36
|
+
}
|
|
37
|
+
export interface WorkAttempt {
|
|
38
|
+
number: number;
|
|
39
|
+
run_id: string;
|
|
40
|
+
started_at: string;
|
|
41
|
+
status: "running" | "parked" | "succeeded" | "failed" | "lost";
|
|
42
|
+
approval_id?: string;
|
|
43
|
+
proof_path?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface WorkProjection {
|
|
46
|
+
id: string;
|
|
47
|
+
title: string;
|
|
48
|
+
state: WorkState;
|
|
49
|
+
reason: string;
|
|
50
|
+
next_action: WorkNextAction;
|
|
51
|
+
unresolved_dependencies: string[];
|
|
52
|
+
attempts: WorkAttempt[];
|
|
53
|
+
attempts_used: number;
|
|
54
|
+
attempts_remaining: number;
|
|
55
|
+
latest_run_id?: string;
|
|
56
|
+
approval_id?: string;
|
|
57
|
+
proof_path?: string;
|
|
58
|
+
updated_at: string;
|
|
59
|
+
}
|
|
60
|
+
export interface WorkRecord {
|
|
61
|
+
intent: WorkIntent;
|
|
62
|
+
events: WorkEvent[];
|
|
63
|
+
projection: WorkProjection;
|
|
64
|
+
}
|
|
65
|
+
export interface CreateWorkItemInput {
|
|
66
|
+
coordRoot: string;
|
|
67
|
+
title: string;
|
|
68
|
+
objective: string;
|
|
69
|
+
workflowPath: string;
|
|
70
|
+
acceptance?: string[];
|
|
71
|
+
dependencies?: string[];
|
|
72
|
+
maxAttempts?: number;
|
|
73
|
+
source?: WorkIntent["source"];
|
|
74
|
+
id?: string;
|
|
75
|
+
actor?: string;
|
|
76
|
+
}
|
|
77
|
+
export declare function createWorkItem(input: CreateWorkItemInput): WorkRecord;
|
|
78
|
+
export declare function readWorkItem(coordRoot: string, workId: string): WorkRecord;
|
|
79
|
+
export declare function listWorkItems(coordRoot: string): WorkRecord[];
|
|
80
|
+
export declare function reconcileWorkItem(coordRoot: string, workId: string, actor?: string): WorkRecord;
|
|
81
|
+
export declare function reconcileAllWorkItems(coordRoot: string, actor?: string): WorkRecord[];
|
|
82
|
+
export declare function acceptWorkItem(coordRoot: string, workId: string, input?: {
|
|
83
|
+
actor?: string;
|
|
84
|
+
reason?: string;
|
|
85
|
+
}): WorkRecord;
|
|
86
|
+
export declare function cancelWorkItem(coordRoot: string, workId: string, input?: {
|
|
87
|
+
actor?: string;
|
|
88
|
+
reason?: string;
|
|
89
|
+
}): WorkRecord;
|
|
90
|
+
export declare function reopenWorkItem(coordRoot: string, workId: string, input?: {
|
|
91
|
+
actor?: string;
|
|
92
|
+
reason?: string;
|
|
93
|
+
}): WorkRecord;
|
|
94
|
+
export declare function assertWorkId(workId: string): void;
|
|
95
|
+
export declare function newWorkId(): string;
|
|
96
|
+
export declare function newWorkflowRunId(): string;
|
|
97
|
+
/** @internal Runner seam; not a separate persistence contract. */
|
|
98
|
+
export declare function appendReconcileIfChanged(coordRoot: string, record: WorkRecord, actor: string): void;
|
|
99
|
+
/** @internal Runner seam; not a separate persistence contract. */
|
|
100
|
+
export declare function appendWorkEvent(coordRoot: string, workId: string, input: Omit<WorkEvent, "schema_version" | "work_id" | "seq" | "ts">): WorkEvent;
|
|
101
|
+
/** @internal Runner seam; not a separate persistence contract. */
|
|
102
|
+
export declare function readWorkItemIgnoringLease(coordRoot: string, workId: string): WorkRecord;
|
|
103
|
+
/** @internal Runner seam; not a separate persistence contract. */
|
|
104
|
+
export declare function assertWorkflowUnchanged(intent: WorkIntent): void;
|
|
105
|
+
/** @internal Runner seam; not a separate persistence contract. */
|
|
106
|
+
export declare function acquireWorkLease(coordRoot: string, workId: string): () => void;
|
|
107
|
+
/** @internal Runner seam; not a separate persistence contract. */
|
|
108
|
+
export declare function boundedActor(value?: string, fallback?: string): string;
|
|
109
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/core/work/state.ts"],"names":[],"mappings":"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"}
|