harnery 0.12.2 → 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 +2 -1
- 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/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +193 -0
- package/dist/core/policy/types.d.ts +1 -1
- package/dist/core/policy/types.d.ts.map +1 -1
- 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/approvals.d.ts +71 -0
- package/dist/core/workflow/approvals.d.ts.map +1 -0
- package/dist/core/workflow/approvals.js +288 -0
- package/dist/core/workflow/engine.d.ts +6 -0
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +243 -43
- package/dist/core/workflow/index.d.ts +6 -2
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +3 -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 +44 -0
- package/dist/core/workflow/run-state.d.ts.map +1 -0
- package/dist/core/workflow/run-state.js +233 -0
- package/dist/core/workflow/types.d.ts +16 -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/commands/workflow.ts +226 -0
- package/src/core/policy/types.ts +1 -1
- 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/approvals.ts +393 -0
- package/src/core/workflow/engine.ts +288 -44
- package/src/core/workflow/index.ts +31 -1
- package/src/core/workflow/proof.ts +2 -0
- package/src/core/workflow/run-state.ts +290 -0
- package/src/core/workflow/types.ts +16 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
3
|
+
import { hostname } from "node:os";
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { normalizePolicy, policyDigest, } from "../policy/index.js";
|
|
6
|
+
import { assertWorkflowRunId, readWorkflowApproval } from "./approvals.js";
|
|
7
|
+
export const WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION = 1;
|
|
8
|
+
const MANIFEST_LIMIT_BYTES = 256 * 1024;
|
|
9
|
+
const FOREIGN_LEASE_STALE_MS = 24 * 60 * 60 * 1_000;
|
|
10
|
+
export function workflowScriptDigest(scriptPath) {
|
|
11
|
+
return createHash("sha256").update(readFileSync(scriptPath)).digest("hex");
|
|
12
|
+
}
|
|
13
|
+
export function writeWorkflowRunManifest(input) {
|
|
14
|
+
assertWorkflowRunId(input.manifest.run_id);
|
|
15
|
+
const path = workflowRunManifestPath(input.coordRoot, input.manifest.run_id);
|
|
16
|
+
if (existsSync(path))
|
|
17
|
+
throw new Error(`workflow run ${input.manifest.run_id} already has a manifest`);
|
|
18
|
+
const body = `${JSON.stringify(input.manifest, null, 2)}\n`;
|
|
19
|
+
if (Buffer.byteLength(body) > MANIFEST_LIMIT_BYTES) {
|
|
20
|
+
throw new Error(`workflow run manifest exceeds ${MANIFEST_LIMIT_BYTES} bytes`);
|
|
21
|
+
}
|
|
22
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
23
|
+
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
24
|
+
try {
|
|
25
|
+
writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
26
|
+
renameSync(temporary, path);
|
|
27
|
+
chmodSync(path, 0o600);
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
if (existsSync(temporary))
|
|
31
|
+
unlinkSync(temporary);
|
|
32
|
+
}
|
|
33
|
+
return path;
|
|
34
|
+
}
|
|
35
|
+
export function readWorkflowRunManifest(coordRoot, runId) {
|
|
36
|
+
assertWorkflowRunId(runId);
|
|
37
|
+
const path = workflowRunManifestPath(coordRoot, runId);
|
|
38
|
+
if (!existsSync(path))
|
|
39
|
+
throw new Error(`workflow run ${runId} has no resume manifest at ${path}`);
|
|
40
|
+
const bytes = statSync(path).size;
|
|
41
|
+
if (bytes <= 0 || bytes > MANIFEST_LIMIT_BYTES) {
|
|
42
|
+
throw new Error(`workflow run manifest at ${path} has invalid size ${bytes}`);
|
|
43
|
+
}
|
|
44
|
+
let manifest;
|
|
45
|
+
try {
|
|
46
|
+
manifest = JSON.parse(readFileSync(path, "utf8"));
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw new Error(`cannot parse workflow run manifest at ${path}: ${error.message}`);
|
|
50
|
+
}
|
|
51
|
+
if (manifest.schema_version !== WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION ||
|
|
52
|
+
manifest.run_id !== runId ||
|
|
53
|
+
(manifest.work_item_id !== undefined &&
|
|
54
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/.test(manifest.work_item_id)) ||
|
|
55
|
+
typeof manifest.name !== "string" ||
|
|
56
|
+
manifest.name.length === 0 ||
|
|
57
|
+
manifest.name.length > 200 ||
|
|
58
|
+
!validTimestamp(manifest.started_at) ||
|
|
59
|
+
!manifest.script?.path ||
|
|
60
|
+
!isAbsolute(manifest.script.path) ||
|
|
61
|
+
!/^[a-f0-9]{64}$/.test(manifest.script.sha256) ||
|
|
62
|
+
!validRepoSnapshot(manifest.repository_before) ||
|
|
63
|
+
!validExecution(manifest.execution)) {
|
|
64
|
+
throw new Error(`workflow run manifest at ${path} has an unsupported or mismatched schema`);
|
|
65
|
+
}
|
|
66
|
+
return manifest;
|
|
67
|
+
}
|
|
68
|
+
export function assertWorkflowRunResumable(coordRoot, runId) {
|
|
69
|
+
const manifest = readWorkflowRunManifest(coordRoot, runId);
|
|
70
|
+
const journalPath = join(coordRoot, ".harnery", "workflows", runId, "journal.jsonl");
|
|
71
|
+
if (!existsSync(journalPath))
|
|
72
|
+
throw new Error(`workflow run ${runId} has no journal`);
|
|
73
|
+
let approvalId;
|
|
74
|
+
let terminal = false;
|
|
75
|
+
for (const line of readFileSync(journalPath, "utf8").split("\n")) {
|
|
76
|
+
if (!line.trim())
|
|
77
|
+
continue;
|
|
78
|
+
try {
|
|
79
|
+
const event = JSON.parse(line);
|
|
80
|
+
if (event.event === "run.parked" && typeof event.approval_id === "string") {
|
|
81
|
+
approvalId = event.approval_id;
|
|
82
|
+
}
|
|
83
|
+
if (event.event === "run.end")
|
|
84
|
+
terminal = true;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
throw new Error(`workflow run ${runId} has a malformed journal line`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (terminal)
|
|
91
|
+
throw new Error(`workflow run ${runId} is already terminal`);
|
|
92
|
+
if (!approvalId)
|
|
93
|
+
throw new Error(`workflow run ${runId} is not parked on an approval`);
|
|
94
|
+
const approval = readWorkflowApproval(coordRoot, approvalId);
|
|
95
|
+
if (approval.request.run_id !== runId) {
|
|
96
|
+
throw new Error(`workflow run ${runId} has a mismatched parked approval`);
|
|
97
|
+
}
|
|
98
|
+
if (approval.status === "pending") {
|
|
99
|
+
throw new Error(`workflow run ${runId} is still waiting on approval ${approvalId}`);
|
|
100
|
+
}
|
|
101
|
+
return { manifest, approvalId };
|
|
102
|
+
}
|
|
103
|
+
export function assertWorkflowScriptUnchanged(manifest) {
|
|
104
|
+
const path = resolve(manifest.script.path);
|
|
105
|
+
if (!existsSync(path))
|
|
106
|
+
throw new Error(`workflow script no longer exists at ${path}`);
|
|
107
|
+
const actual = workflowScriptDigest(path);
|
|
108
|
+
if (actual !== manifest.script.sha256) {
|
|
109
|
+
throw new Error(`workflow script changed since run ${manifest.run_id} parked; start a new run instead of reusing its approval`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export function workflowRunManifestPath(coordRoot, runId) {
|
|
113
|
+
assertWorkflowRunId(runId);
|
|
114
|
+
return join(coordRoot, ".harnery", "workflows", runId, "run.json");
|
|
115
|
+
}
|
|
116
|
+
/** Acquire an exclusive, crash-recoverable lease for one resume segment. */
|
|
117
|
+
export function acquireWorkflowResumeLease(coordRoot, runId) {
|
|
118
|
+
assertWorkflowRunId(runId);
|
|
119
|
+
const path = join(coordRoot, ".harnery", "workflows", runId, "resume.lock");
|
|
120
|
+
const owner = { pid: process.pid, host: hostname(), created_at: new Date().toISOString() };
|
|
121
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
122
|
+
const acquire = () => {
|
|
123
|
+
try {
|
|
124
|
+
const fd = openSync(path, "wx", 0o600);
|
|
125
|
+
try {
|
|
126
|
+
writeFileSync(fd, `${JSON.stringify(owner)}\n`, "utf8");
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
closeSync(fd);
|
|
130
|
+
}
|
|
131
|
+
chmodSync(path, 0o600);
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (error.code !== "EEXIST")
|
|
136
|
+
throw error;
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
if (!acquire()) {
|
|
141
|
+
const existing = readResumeLease(path);
|
|
142
|
+
if (existing && resumeLeaseIsLive(existing)) {
|
|
143
|
+
throw new Error(`workflow run ${runId} is already being resumed by pid ${existing.pid} on ${existing.host}`);
|
|
144
|
+
}
|
|
145
|
+
unlinkSync(path);
|
|
146
|
+
if (!acquire())
|
|
147
|
+
throw new Error(`workflow run ${runId} resume lease raced with another process`);
|
|
148
|
+
}
|
|
149
|
+
return () => {
|
|
150
|
+
try {
|
|
151
|
+
const existing = readResumeLease(path);
|
|
152
|
+
if (existing?.pid === owner.pid && existing.host === owner.host)
|
|
153
|
+
unlinkSync(path);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Best effort. A stale lease is recoverable on the next resume attempt.
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function readResumeLease(path) {
|
|
161
|
+
try {
|
|
162
|
+
const value = JSON.parse(readFileSync(path, "utf8"));
|
|
163
|
+
return typeof value.pid === "number" &&
|
|
164
|
+
Number.isSafeInteger(value.pid) &&
|
|
165
|
+
value.pid > 0 &&
|
|
166
|
+
typeof value.host === "string" &&
|
|
167
|
+
typeof value.created_at === "string"
|
|
168
|
+
? { pid: value.pid, host: value.host, created_at: value.created_at }
|
|
169
|
+
: null;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function resumeLeaseIsLive(lease) {
|
|
176
|
+
if (lease.host !== hostname()) {
|
|
177
|
+
const age = Date.now() - Date.parse(lease.created_at);
|
|
178
|
+
return Number.isFinite(age) && age < FOREIGN_LEASE_STALE_MS;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
process.kill(lease.pid, 0);
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
return error.code === "EPERM";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function validExecution(value) {
|
|
189
|
+
if (!value || typeof value !== "object")
|
|
190
|
+
return false;
|
|
191
|
+
return (isAbsolute(value.cwd) &&
|
|
192
|
+
typeof value.default_harness === "string" &&
|
|
193
|
+
value.default_harness.length > 0 &&
|
|
194
|
+
positiveSafeInteger(value.max_agents) &&
|
|
195
|
+
positiveSafeInteger(value.concurrency) &&
|
|
196
|
+
typeof value.subscription_only === "boolean" &&
|
|
197
|
+
typeof value.allow_api_billing === "boolean" &&
|
|
198
|
+
(value.approval_mode === "deny" || value.approval_mode === "park") &&
|
|
199
|
+
typeof value.approval_addressee === "string" &&
|
|
200
|
+
value.approval_addressee.length > 0 &&
|
|
201
|
+
value.approval_addressee.length <= 200 &&
|
|
202
|
+
["shared", "worktree", "sandbox", "remote"].includes(value.isolation) &&
|
|
203
|
+
["enabled", "disabled", "unknown"].includes(value.network_access) &&
|
|
204
|
+
validFrozenPolicy(value.policy, value.cwd));
|
|
205
|
+
}
|
|
206
|
+
function validFrozenPolicy(policy, cwd) {
|
|
207
|
+
if (policy === undefined)
|
|
208
|
+
return true;
|
|
209
|
+
try {
|
|
210
|
+
const normalized = normalizePolicy(policy, { baseDir: cwd });
|
|
211
|
+
return policyDigest(normalized) === policyDigest(policy);
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function validRepoSnapshot(value) {
|
|
218
|
+
return (Boolean(value) &&
|
|
219
|
+
typeof value === "object" &&
|
|
220
|
+
isAbsolute(value.cwd) &&
|
|
221
|
+
(value.root === undefined || isAbsolute(value.root)) &&
|
|
222
|
+
(value.branch === undefined || typeof value.branch === "string") &&
|
|
223
|
+
(value.head === undefined || typeof value.head === "string") &&
|
|
224
|
+
Array.isArray(value.dirty_paths) &&
|
|
225
|
+
value.dirty_paths.every((path) => typeof path === "string") &&
|
|
226
|
+
(value.dirty_paths_truncated === undefined || typeof value.dirty_paths_truncated === "boolean"));
|
|
227
|
+
}
|
|
228
|
+
function positiveSafeInteger(value) {
|
|
229
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
230
|
+
}
|
|
231
|
+
function validTimestamp(value) {
|
|
232
|
+
return typeof value === "string" && value.length <= 40 && Number.isFinite(Date.parse(value));
|
|
233
|
+
}
|
|
@@ -14,6 +14,7 @@ export type EvidenceStatus = "passed" | "failed" | "observed" | "unknown";
|
|
|
14
14
|
export type EvidenceSource = "workflow" | "engine";
|
|
15
15
|
export type AcceptanceStatus = "satisfied" | "unsatisfied" | "unknown";
|
|
16
16
|
export type WorkflowRunStatus = "succeeded" | "failed";
|
|
17
|
+
export type WorkflowApprovalMode = "deny" | "park";
|
|
17
18
|
export interface AcceptanceCriterion {
|
|
18
19
|
/** Stable identifier referenced by evidence, for example `tests-pass`. */
|
|
19
20
|
id: string;
|
|
@@ -117,6 +118,8 @@ export interface WorkflowProof {
|
|
|
117
118
|
schema_version: typeof WORKFLOW_PROOF_SCHEMA_VERSION;
|
|
118
119
|
run: {
|
|
119
120
|
id: string;
|
|
121
|
+
/** Durable objective this execution attempt belongs to, when linked. */
|
|
122
|
+
work_item_id?: string;
|
|
120
123
|
name: string;
|
|
121
124
|
status: WorkflowRunStatus;
|
|
122
125
|
started_at: string;
|
|
@@ -269,6 +272,14 @@ export interface EngineOpts {
|
|
|
269
272
|
* agent() calls whose (stage, prompt, model, maxTurns, schema) key matches a
|
|
270
273
|
* completed prior agent return the journaled result without spawning. */
|
|
271
274
|
resumeFrom?: string;
|
|
275
|
+
/** Continue a parked run in its original directory after its durable
|
|
276
|
+
* approval has been resolved. The frozen run manifest supplies execution
|
|
277
|
+
* options and the original repository-before snapshot. */
|
|
278
|
+
resumeRunId?: string;
|
|
279
|
+
/** Stable id for a new run allocated by a durable-work host. */
|
|
280
|
+
runId?: string;
|
|
281
|
+
/** Durable objective this execution attempt belongs to. */
|
|
282
|
+
workItemId?: string;
|
|
272
283
|
/** Total-agent ceiling for the run (default 50): the runaway backstop. */
|
|
273
284
|
maxAgents?: number;
|
|
274
285
|
/** Concurrent-subagent cap for parallel() (default 4). */
|
|
@@ -299,6 +310,10 @@ export interface EngineOpts {
|
|
|
299
310
|
estimateDispatchCost?: DispatchCostEstimator;
|
|
300
311
|
/** Maximum wait for an ASK resolver (default 60 seconds). */
|
|
301
312
|
policyAskTimeoutMs?: number;
|
|
313
|
+
/** Missing or unavailable ASK resolver behavior (library default: deny). */
|
|
314
|
+
approvalMode?: WorkflowApprovalMode;
|
|
315
|
+
/** Bounded address recorded on newly parked approval requests. */
|
|
316
|
+
approvalAddressee?: string;
|
|
302
317
|
/** Execution boundary created by the host (default shared). */
|
|
303
318
|
isolation?: PolicyIsolation;
|
|
304
319
|
/** Network state of spawned harness subprocesses (default unknown). */
|
|
@@ -306,6 +321,7 @@ export interface EngineOpts {
|
|
|
306
321
|
}
|
|
307
322
|
export interface RunReport {
|
|
308
323
|
runId: string;
|
|
324
|
+
workItemId?: string;
|
|
309
325
|
name: string;
|
|
310
326
|
/** What the script's default export returned. */
|
|
311
327
|
result: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,UAAU,EACX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE/D,eAAO,MAAM,6BAA6B,EAAG,CAAU,CAAC;AAExD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;AACjG,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAC1E,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,CAAC;AACnD,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AACvE,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harnery",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Multi-agent coordination for AI coding agents - Claude Code, Cursor, and Codex.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ryan Kelly",
|
|
@@ -67,6 +67,16 @@
|
|
|
67
67
|
"types": "./dist/core/workflow/index.d.ts",
|
|
68
68
|
"import": "./dist/core/workflow/index.js"
|
|
69
69
|
},
|
|
70
|
+
"./core/work": {
|
|
71
|
+
"bun": "./src/core/work/index.ts",
|
|
72
|
+
"types": "./dist/core/work/index.d.ts",
|
|
73
|
+
"import": "./dist/core/work/index.js"
|
|
74
|
+
},
|
|
75
|
+
"./core/work/state": {
|
|
76
|
+
"bun": "./src/core/work/read.ts",
|
|
77
|
+
"types": "./dist/core/work/read.d.ts",
|
|
78
|
+
"import": "./dist/core/work/read.js"
|
|
79
|
+
},
|
|
70
80
|
"./core/policy": {
|
|
71
81
|
"bun": "./src/core/policy/index.ts",
|
|
72
82
|
"types": "./dist/core/policy/index.d.ts",
|
package/src/commander.ts
CHANGED
|
@@ -53,6 +53,7 @@ import { registerSectionCommand, registerTocCommand } from "./commands/toc.ts";
|
|
|
53
53
|
import { registerTokensCommand } from "./commands/tokens.ts";
|
|
54
54
|
import { registerTunnelCommand } from "./commands/tunnel.ts";
|
|
55
55
|
import { registerWebCommand } from "./commands/web.ts";
|
|
56
|
+
import { registerWorkCommand } from "./commands/work.ts";
|
|
56
57
|
import { registerWorkflowCommand } from "./commands/workflow.ts";
|
|
57
58
|
|
|
58
59
|
export interface HarneryContextOpts {
|
|
@@ -287,6 +288,7 @@ export function createHarneryProgram(opts: HarneryContextOpts = {}): Command {
|
|
|
287
288
|
registerClaudeDesktopCommand(program, emit);
|
|
288
289
|
registerSyncCommand(program, emit);
|
|
289
290
|
registerWorkflowCommand(program, emit);
|
|
291
|
+
registerWorkCommand(program, emit);
|
|
290
292
|
if (include("web")) registerWebCommand(program, emit);
|
|
291
293
|
|
|
292
294
|
return program;
|