harnery 0.17.0 → 0.18.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.
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/runner.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAC5B,WAAW,GACX,oBAAoB,GACpB,SAAS,GACT,kBAAkB,GAClB,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,WAAW,EAAE,oBAAoB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,EAAE,oBAAoB,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IACtF,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAQD,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqL3F"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/runner.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAC5B,WAAW,GACX,oBAAoB,GACpB,SAAS,GACT,kBAAkB,GAClB,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,WAAW,EAAE,oBAAoB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,EAAE,oBAAoB,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IACtF,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAQD,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA4L3F"}
@@ -33,8 +33,10 @@ export async function runSupervisor(input) {
33
33
  }
34
34
  const before = graphFingerprint(record);
35
35
  let changed = false;
36
- if (record.projection.next_action === "replan") {
37
- log(`[${record.intent.title}] replan active graph generation ${record.projection.plan_generation}`);
36
+ if (record.projection.next_action === "replan" ||
37
+ record.projection.next_action === "plan_initial" ||
38
+ record.projection.next_action === "plan_milestone") {
39
+ log(`[${record.intent.title}] ${record.projection.next_action} at graph generation ${record.projection.plan_generation}`);
38
40
  const plan = await runSupervisorPlanner({
39
41
  coordRoot,
40
42
  record,
@@ -48,6 +50,9 @@ export async function runSupervisor(input) {
48
50
  if (mode === "tick") {
49
51
  return report("tick_complete", `planner produced ${plan.status} plan ${plan.plan_id}`, record);
50
52
  }
53
+ if (record.projection.state === "succeeded") {
54
+ return report("succeeded", record.projection.reason, record);
55
+ }
51
56
  if (record.projection.state !== "ready") {
52
57
  return report(stopForProjection(record.projection), record.projection.reason, record);
53
58
  }
@@ -434,9 +434,12 @@ function projectionFingerprint(projection) {
434
434
  projection.attempts_used,
435
435
  projection.attempts_remaining,
436
436
  projection.root_work_id,
437
+ projection.root_materialized,
437
438
  projection.plan_generation,
438
439
  projection.replans_used,
439
440
  projection.replans_remaining,
441
+ projection.milestones_completed,
442
+ projection.milestones_remaining,
440
443
  projection.pending_plan_id,
441
444
  projection.latest_plan_status,
442
445
  projection.ready_work,
@@ -15,6 +15,16 @@ export interface SupervisorAutomationPolicy {
15
15
  resume_approved: boolean;
16
16
  retry_blocked: boolean;
17
17
  }
18
+ export interface SupervisorMission {
19
+ objective: string;
20
+ acceptance: string[];
21
+ max_milestones: number;
22
+ }
23
+ export interface CreateSupervisorMissionInput {
24
+ objective: string;
25
+ acceptance: readonly string[];
26
+ maxMilestones?: number;
27
+ }
18
28
  export interface SupervisorIntent {
19
29
  schema_version: typeof SUPERVISOR_INTENT_SCHEMA_VERSION;
20
30
  id: string;
@@ -23,15 +33,17 @@ export interface SupervisorIntent {
23
33
  specialists: Record<string, WorkflowSpecialistProfile>;
24
34
  limits: SupervisorLimits;
25
35
  automation: SupervisorAutomationPolicy;
36
+ mission?: SupervisorMission;
26
37
  replanning?: SupervisorReplanningPolicy;
27
38
  created_at: string;
28
39
  }
29
40
  export type SupervisorState = "ready" | "running" | "awaiting_attention" | "blocked" | "budget_exhausted" | "succeeded";
30
- export type SupervisorNextAction = "run" | "wait_for_run" | "resolve_approval" | "review" | "retry" | "replan" | "review_plan" | "none";
41
+ export type SupervisorNextAction = "run" | "wait_for_run" | "resolve_approval" | "review" | "retry" | "replan" | "plan_initial" | "plan_milestone" | "review_plan" | "none";
31
42
  export interface SupervisorProjection {
32
43
  id: string;
33
44
  title: string;
34
45
  root_work_id: string;
46
+ root_materialized: boolean;
35
47
  state: SupervisorState;
36
48
  reason: string;
37
49
  next_action: SupervisorNextAction;
@@ -46,6 +58,8 @@ export interface SupervisorProjection {
46
58
  plan_generation: number;
47
59
  replans_used: number;
48
60
  replans_remaining: number;
61
+ milestones_completed: number;
62
+ milestones_remaining: number;
49
63
  pending_plan_id?: string;
50
64
  latest_plan_status?: SupervisorPlanRecord["status"];
51
65
  governed_work_ids: string[];
@@ -58,12 +72,13 @@ export interface SupervisorRecord {
58
72
  }
59
73
  export interface CreateSupervisorInput {
60
74
  coordRoot: string;
61
- rootWorkId: string;
75
+ rootWorkId?: string;
62
76
  specialists: Readonly<Record<string, WorkflowSpecialistProfile>>;
63
77
  title?: string;
64
78
  id?: string;
65
79
  limits?: Partial<SupervisorLimits>;
66
80
  automation?: Partial<SupervisorAutomationPolicy>;
81
+ mission?: CreateSupervisorMissionInput;
67
82
  replanning?: CreateSupervisorReplanningInput;
68
83
  }
69
84
  export declare function createSupervisor(input: CreateSupervisorInput): SupervisorRecord;
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/state.ts"],"names":[],"mappings":"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"}
@@ -10,27 +10,44 @@ import { supervisorGraphFingerprint, } from "./plan-types.js";
10
10
  export const SUPERVISOR_INTENT_SCHEMA_VERSION = 1;
11
11
  const GOAL_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
12
12
  const MAX_TITLE = 200;
13
+ const MAX_OBJECTIVE = 4_000;
14
+ const MAX_ACCEPTANCE = 50;
13
15
  const MAX_INTENT_BYTES = 256 * 1024;
14
16
  const MAX_TEMPLATES = 20;
15
17
  const TEMPLATE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
16
18
  const FOREIGN_LEASE_STALE_MS = 24 * 60 * 60 * 1_000;
17
19
  export function createSupervisor(input) {
18
20
  const coordRoot = resolve(input.coordRoot);
19
- assertWorkId(input.rootWorkId);
20
- const root = readWorkItem(coordRoot, input.rootWorkId);
21
21
  const id = input.id ?? newSupervisorId();
22
22
  assertSupervisorId(id);
23
+ const mission = input.mission ? normalizeMission(input.mission) : undefined;
24
+ if (mission && !input.replanning) {
25
+ throw new Error("supervisor mission requires a replanning policy");
26
+ }
27
+ if (!input.rootWorkId && !mission) {
28
+ throw new Error("supervisor creation without root work requires a mission and replanning policy");
29
+ }
30
+ if (input.rootWorkId)
31
+ assertWorkId(input.rootWorkId);
32
+ const root = input.rootWorkId ? readWorkItem(coordRoot, input.rootWorkId) : undefined;
23
33
  const replanning = input.replanning
24
34
  ? normalizeReplanning(input.replanning, input.specialists)
25
35
  : undefined;
36
+ if (mission &&
37
+ !input.rootWorkId &&
38
+ replanning &&
39
+ replanning.max_replans <= mission.max_milestones) {
40
+ throw new Error("objective-first mission max_replans must exceed max_milestones to reserve completion review");
41
+ }
26
42
  const intent = {
27
43
  schema_version: SUPERVISOR_INTENT_SCHEMA_VERSION,
28
44
  id,
29
- title: bounded(input.title ?? root.intent.title, "supervisor title", MAX_TITLE),
30
- root_work_id: input.rootWorkId,
45
+ title: bounded(input.title ?? root?.intent.title ?? missionTitle(mission), "supervisor title", MAX_TITLE),
46
+ root_work_id: input.rootWorkId ?? missionRootId(id),
31
47
  specialists: normalizeWorkflowSpecialists(input.specialists),
32
48
  limits: normalizeLimits(input.limits),
33
49
  automation: normalizeAutomation(input.automation),
50
+ ...(mission ? { mission } : {}),
34
51
  ...(replanning ? { replanning } : {}),
35
52
  created_at: new Date().toISOString(),
36
53
  };
@@ -136,7 +153,11 @@ function readSupervisorInternal(coordRootRaw, goalId, ignoreLease) {
136
153
  const coordRoot = resolve(coordRootRaw);
137
154
  const intent = readSupervisorIntent(coordRoot, goalId);
138
155
  const plans = readSupervisorPlans(coordRoot, intent.id, intent.root_work_id);
139
- const work = collectSupervisorWork(coordRoot, plans.active_root_work_id);
156
+ const activeRootExists = workIntentExists(coordRoot, plans.active_root_work_id);
157
+ if (!activeRootExists && (!intent.mission || plans.generation > 0)) {
158
+ throw new Error(`supervisor ${intent.id} root work is missing`);
159
+ }
160
+ const work = activeRootExists ? collectSupervisorWork(coordRoot, plans.active_root_work_id) : [];
140
161
  const governed = collectGovernedWork(coordRoot, intent.root_work_id, plans, work);
141
162
  return {
142
163
  intent,
@@ -147,8 +168,6 @@ function readSupervisorInternal(coordRootRaw, goalId, ignoreLease) {
147
168
  }
148
169
  function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease) {
149
170
  const root = work.find((record) => record.intent.id === plans.active_root_work_id);
150
- if (!root)
151
- throw new Error(`supervisor ${intent.id} root work is missing`);
152
171
  const attemptsUsed = governed.reduce((sum, record) => sum + record.projection.attempts_used, 0);
153
172
  const readyWork = work
154
173
  .filter((record) => record.projection.state === "ready")
@@ -181,10 +200,14 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
181
200
  ...cancelled,
182
201
  ...terminalBlocked,
183
202
  ]);
203
+ const initialRootAccepted = intent.mission !== undefined &&
204
+ governed.some((record) => record.intent.id === intent.root_work_id && record.projection.state === "succeeded");
205
+ const milestonesCompleted = plans.milestones_completed + (initialRootAccepted ? 1 : 0);
184
206
  const base = {
185
207
  id: intent.id,
186
208
  title: intent.title,
187
209
  root_work_id: plans.active_root_work_id,
210
+ root_materialized: root !== undefined,
188
211
  work_ids: work.map((record) => record.intent.id),
189
212
  ready_work: readyWork,
190
213
  resumable_work: resumableWork,
@@ -196,6 +219,8 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
196
219
  plan_generation: plans.generation,
197
220
  replans_used: plans.plans.length,
198
221
  replans_remaining: Math.max(0, (intent.replanning?.max_replans ?? 0) - plans.plans.length),
222
+ milestones_completed: milestonesCompleted,
223
+ milestones_remaining: Math.max(0, (intent.mission?.max_milestones ?? 0) - milestonesCompleted),
199
224
  pending_plan_id: plans.latest?.status === "proposed" ? plans.latest.request.id : undefined,
200
225
  latest_plan_status: plans.latest?.status,
201
226
  governed_work_ids: governed.map((record) => record.intent.id),
@@ -208,11 +233,11 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
208
233
  next_action: "wait_for_run",
209
234
  };
210
235
  }
211
- if (root.projection.state === "succeeded") {
236
+ if (intent.mission && plans.completed) {
212
237
  return {
213
238
  ...base,
214
239
  state: "succeeded",
215
- reason: "root work was explicitly accepted",
240
+ reason: "mission completion was explicitly accepted",
216
241
  next_action: "none",
217
242
  };
218
243
  }
@@ -240,6 +265,64 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
240
265
  next_action: "replan",
241
266
  };
242
267
  }
268
+ const triggerFingerprint = supervisorGraphFingerprint({
269
+ rootWorkId: plans.active_root_work_id,
270
+ generation: plans.generation,
271
+ work,
272
+ });
273
+ const latestHandledSameGraph = plans.latest?.request.trigger_fingerprint === triggerFingerprint &&
274
+ plans.latest.request.prior_root_work_id === plans.active_root_work_id &&
275
+ plans.latest.status === "attention";
276
+ if (latestHandledSameGraph && plans.latest) {
277
+ return {
278
+ ...base,
279
+ state: "awaiting_attention",
280
+ reason: plans.latest.reason ?? `plan ${plans.latest.request.id} requires attention`,
281
+ next_action: "none",
282
+ };
283
+ }
284
+ if (!root && intent.mission) {
285
+ if (!intent.replanning || plans.plans.length >= intent.replanning.max_replans) {
286
+ return {
287
+ ...base,
288
+ state: "budget_exhausted",
289
+ reason: "mission exhausted its planning budget before creating an initial milestone",
290
+ next_action: "none",
291
+ };
292
+ }
293
+ return {
294
+ ...base,
295
+ state: "ready",
296
+ reason: "mission is ready for its initial bounded milestone plan",
297
+ next_action: "plan_initial",
298
+ };
299
+ }
300
+ if (!root)
301
+ throw new Error(`supervisor ${intent.id} root work is missing`);
302
+ if (root.projection.state === "succeeded" && intent.mission) {
303
+ if (!intent.replanning || plans.plans.length >= intent.replanning.max_replans) {
304
+ return {
305
+ ...base,
306
+ state: "budget_exhausted",
307
+ reason: "mission exhausted its planning budget at a milestone boundary",
308
+ next_action: "none",
309
+ };
310
+ }
311
+ return {
312
+ ...base,
313
+ state: "ready",
314
+ reason: `milestone ${plans.milestones_completed} is accepted and requires mission reassessment`,
315
+ next_action: "plan_milestone",
316
+ };
317
+ }
318
+ if (root.projection.state === "succeeded") {
319
+ return {
320
+ ...base,
321
+ state: "succeeded",
322
+ reason: "root work was explicitly accepted",
323
+ next_action: "none",
324
+ };
325
+ }
243
326
  const resumableDispatchable = intent.automation.resume_approved ? resumableWork : [];
244
327
  const attemptDispatchable = [
245
328
  ...readyWork,
@@ -318,14 +401,6 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
318
401
  next_action: "none",
319
402
  };
320
403
  }
321
- const triggerFingerprint = supervisorGraphFingerprint({
322
- rootWorkId: plans.active_root_work_id,
323
- generation: plans.generation,
324
- work,
325
- });
326
- const latestHandledSameGraph = plans.latest?.request.trigger_fingerprint === triggerFingerprint &&
327
- plans.latest.request.prior_root_work_id === plans.active_root_work_id &&
328
- plans.latest.status === "attention";
329
404
  const canReplan = intent.replanning !== undefined &&
330
405
  plans.plans.length < intent.replanning.max_replans &&
331
406
  cancelled.length === 0 &&
@@ -350,14 +425,6 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
350
425
  next_action: "none",
351
426
  };
352
427
  }
353
- if (latestHandledSameGraph && plans.latest) {
354
- return {
355
- ...base,
356
- state: "awaiting_attention",
357
- reason: plans.latest.reason ?? `plan ${plans.latest.request.id} requires attention`,
358
- next_action: "none",
359
- };
360
- }
361
428
  return {
362
429
  ...base,
363
430
  state: "blocked",
@@ -394,6 +461,19 @@ function validateIntent(intent, goalId) {
394
461
  }
395
462
  bounded(intent.title, "supervisor title", MAX_TITLE);
396
463
  assertWorkId(intent.root_work_id);
464
+ if (intent.mission) {
465
+ const normalizedMission = normalizeMission({
466
+ objective: intent.mission.objective,
467
+ acceptance: intent.mission.acceptance,
468
+ maxMilestones: intent.mission.max_milestones,
469
+ });
470
+ if (JSON.stringify(normalizedMission) !== JSON.stringify(intent.mission)) {
471
+ throw new Error(`supervisor intent ${goalId} mission is not canonical`);
472
+ }
473
+ if (!intent.replanning) {
474
+ throw new Error(`supervisor intent ${goalId} mission requires replanning`);
475
+ }
476
+ }
397
477
  const specialists = normalizeWorkflowSpecialists(intent.specialists);
398
478
  if (JSON.stringify(specialists) !== JSON.stringify(intent.specialists)) {
399
479
  throw new Error(`supervisor intent ${goalId} specialists are not canonical`);
@@ -407,6 +487,28 @@ function validateIntent(intent, goalId) {
407
487
  if (intent.replanning)
408
488
  validateReplanning(intent.replanning, specialists, goalId);
409
489
  }
490
+ function normalizeMission(input) {
491
+ if (!Array.isArray(input.acceptance)) {
492
+ throw new Error("supervisor mission acceptance must be an array");
493
+ }
494
+ if (input.acceptance.length < 1 || input.acceptance.length > MAX_ACCEPTANCE) {
495
+ throw new Error(`supervisor mission acceptance must contain 1 to ${MAX_ACCEPTANCE} criteria`);
496
+ }
497
+ const acceptance = input.acceptance.map((criterion, index) => bounded(criterion, `supervisor mission acceptance[${index}]`, 500));
498
+ if (new Set(acceptance).size !== acceptance.length) {
499
+ throw new Error("supervisor mission acceptance criteria must be unique");
500
+ }
501
+ return {
502
+ objective: bounded(input.objective, "supervisor mission objective", MAX_OBJECTIVE),
503
+ acceptance,
504
+ max_milestones: positive(input.maxMilestones ?? 4, "supervisor mission max_milestones", 20),
505
+ };
506
+ }
507
+ function missionTitle(mission) {
508
+ return mission.objective.length <= MAX_TITLE
509
+ ? mission.objective
510
+ : `${mission.objective.slice(0, MAX_TITLE - 1).trimEnd()}…`;
511
+ }
410
512
  function normalizeLimits(input) {
411
513
  return {
412
514
  max_cycles: positive(input?.max_cycles ?? 50, "supervisor max_cycles", 1_000),
@@ -502,8 +604,10 @@ function validateReplanning(policy, specialists, goalId) {
502
604
  }
503
605
  function collectGovernedWork(coordRoot, originalRootWorkId, plans, active) {
504
606
  const governed = new Map();
505
- for (const record of collectSupervisorWork(coordRoot, originalRootWorkId)) {
506
- governed.set(record.intent.id, record);
607
+ if (workIntentExists(coordRoot, originalRootWorkId)) {
608
+ for (const record of collectSupervisorWork(coordRoot, originalRootWorkId)) {
609
+ governed.set(record.intent.id, record);
610
+ }
507
611
  }
508
612
  for (const workId of plans.applied_work_ids)
509
613
  governed.set(workId, readWorkItem(coordRoot, workId));
@@ -511,6 +615,12 @@ function collectGovernedWork(coordRoot, originalRootWorkId, plans, active) {
511
615
  governed.set(record.intent.id, record);
512
616
  return [...governed.values()];
513
617
  }
618
+ function workIntentExists(coordRoot, workId) {
619
+ return existsSync(join(resolve(coordRoot), ".harnery", "work", workId, "intent.json"));
620
+ }
621
+ function missionRootId(goalId) {
622
+ return `${goalId.slice(0, 87)}-mission-root`;
623
+ }
514
624
  function supervisorDir(coordRoot, goalId) {
515
625
  assertSupervisorId(goalId);
516
626
  return join(resolve(coordRoot), ".harnery", "supervisors", goalId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harnery",
3
- "version": "0.17.0",
3
+ "version": "0.18.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",
@@ -9,6 +9,7 @@ import type { PolicyIsolation } from "../core/policy/index.ts";
9
9
  import { loadPolicyFile } from "../core/policy/index.ts";
10
10
  import {
11
11
  approveSupervisorPlan,
12
+ type CreateSupervisorMissionInput,
12
13
  type CreateSupervisorReplanningInput,
13
14
  configureSupervisorService,
14
15
  createSupervisor,
@@ -46,6 +47,7 @@ interface CreateOpts {
46
47
  resumeApproved?: boolean;
47
48
  retryBlocked?: boolean;
48
49
  replanning?: string;
50
+ mission?: string;
49
51
  json?: boolean;
50
52
  }
51
53
 
@@ -75,8 +77,8 @@ export function registerSupervisorCommand(program: Command, emit: EmitContext):
75
77
  .description("Run a bounded specialist team over a durable-work dependency graph.");
76
78
 
77
79
  supervisor
78
- .command("create <root-work-id>")
79
- .description("Freeze a goal, specialist team, automation policy, and execution limits.")
80
+ .command("create [root-work-id]")
81
+ .description("Freeze an existing-root goal or an objective-first bounded mission.")
80
82
  .requiredOption("--team <file>", "JSON object mapping specialist ids to profiles")
81
83
  .option("--id <goal-id>", "Stable goal id (generated by default)")
82
84
  .option("--title <text>", "Goal title (defaults to root work title)")
@@ -90,8 +92,9 @@ export function registerSupervisorCommand(program: Command, emit: EmitContext):
90
92
  .option("--no-resume-approved", "Stop after an approval instead of resuming its parked run")
91
93
  .option("--retry-blocked", "Allow bounded retry of blocked work")
92
94
  .option("--replanning <file>", "Frozen planner policy and allowed workflow-template catalog")
95
+ .option("--mission <file>", "Frozen objective, acceptance criteria, and milestone bound")
93
96
  .option("--json", "Emit the complete supervisor record as JSON")
94
- .action((rootWorkId: string, opts: CreateOpts) => {
97
+ .action((rootWorkId: string | undefined, opts: CreateOpts) => {
95
98
  withSupervisorRoot(emit, (coordRoot) => {
96
99
  const specialists = readTeamFile(opts.team);
97
100
  for (const [id, profile] of Object.entries(specialists)) {
@@ -121,6 +124,7 @@ export function registerSupervisorCommand(program: Command, emit: EmitContext):
121
124
  resume_approved: opts.resumeApproved,
122
125
  retry_blocked: opts.retryBlocked,
123
126
  },
127
+ mission: opts.mission ? readMissionFile(opts.mission) : undefined,
124
128
  replanning: opts.replanning ? readReplanningFile(opts.replanning) : undefined,
125
129
  }),
126
130
  opts.json,
@@ -626,6 +630,34 @@ function readReplanningFile(path: string): CreateSupervisorReplanningInput {
626
630
  };
627
631
  }
628
632
 
633
+ function readMissionFile(path: string): CreateSupervisorMissionInput {
634
+ const absolute = resolve(path);
635
+ let value: unknown;
636
+ try {
637
+ value = JSON.parse(readFileSync(absolute, "utf8"));
638
+ } catch (error) {
639
+ throw new Error(`cannot read supervisor mission at ${absolute}: ${(error as Error).message}`);
640
+ }
641
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
642
+ throw new Error("supervisor mission must be a JSON object");
643
+ }
644
+ const config = value as Record<string, unknown>;
645
+ if (typeof config.objective !== "string") {
646
+ throw new Error("supervisor mission objective must be a string");
647
+ }
648
+ if (
649
+ !Array.isArray(config.acceptance) ||
650
+ config.acceptance.some((item) => typeof item !== "string")
651
+ ) {
652
+ throw new Error("supervisor mission acceptance must be an array of strings");
653
+ }
654
+ return {
655
+ objective: config.objective,
656
+ acceptance: config.acceptance as string[],
657
+ maxMilestones: jsonInteger(config.max_milestones, "mission max_milestones"),
658
+ };
659
+ }
660
+
629
661
  function emitSupervisor(
630
662
  record: SupervisorRecord,
631
663
  json: boolean | undefined,
@@ -645,7 +677,7 @@ function emitSupervisor(
645
677
  const lines = [
646
678
  `${record.intent.id}: ${record.intent.title}`,
647
679
  `state: ${projection.state}`,
648
- `root: ${projection.root_work_id}`,
680
+ `root: ${projection.root_materialized ? projection.root_work_id : "pending initial plan"}`,
649
681
  `reason: ${projection.reason}`,
650
682
  `next: ${projection.next_action}`,
651
683
  `work: ${projection.work_ids.length}`,
@@ -663,6 +695,13 @@ function emitSupervisor(
663
695
  }
664
696
  if (projection.pending_plan_id) lines.push(`pending plan: ${projection.pending_plan_id}`);
665
697
  }
698
+ if (record.intent.mission) {
699
+ lines.push(`mission: ${record.intent.mission.objective}`);
700
+ lines.push(
701
+ `milestones: ${projection.milestones_completed}/${record.intent.mission.max_milestones}`,
702
+ );
703
+ lines.push(`mission acceptance: ${record.intent.mission.acceptance.length}`);
704
+ }
666
705
  if (projection.attention_work.length) {
667
706
  lines.push(`attention: ${projection.attention_work.join(", ")}`);
668
707
  }
@@ -724,6 +763,7 @@ function emitPlan(plan: SupervisorPlanRecord, json: boolean | undefined, emit: E
724
763
  `${plan.request.id}: ${plan.status}`,
725
764
  `goal: ${plan.request.goal_id}`,
726
765
  `sequence: ${plan.request.sequence}`,
766
+ `trigger: ${plan.request.trigger ?? "recovery"}`,
727
767
  `prior root: ${plan.request.prior_root_work_id}`,
728
768
  `planner run: ${plan.request.workflow_run_id}`,
729
769
  ];
@@ -731,6 +771,9 @@ function emitPlan(plan: SupervisorPlanRecord, json: boolean | undefined, emit: E
731
771
  lines.push(`decision: ${plan.proposal.decision}`);
732
772
  lines.push(`rationale: ${plan.proposal.rationale}`);
733
773
  lines.push(`proposed work: ${plan.proposal.work.length}`);
774
+ if (plan.proposal.milestone) {
775
+ lines.push(`milestone: ${plan.proposal.milestone.sequence} ${plan.proposal.milestone.title}`);
776
+ }
734
777
  }
735
778
  if (plan.root_work_id) lines.push(`applied root: ${plan.root_work_id}`);
736
779
  if (plan.approval_id) lines.push(`approval: ${plan.approval_id}`);
@@ -7,6 +7,7 @@ export {
7
7
  type SupervisorPlanEvent,
8
8
  type SupervisorPlanEventType,
9
9
  type SupervisorPlanHistory,
10
+ type SupervisorPlanMilestone,
10
11
  type SupervisorPlanOutcome,
11
12
  type SupervisorPlanProposal,
12
13
  type SupervisorPlanRecord,
@@ -53,6 +54,7 @@ export {
53
54
  export {
54
55
  assertSupervisorId,
55
56
  type CreateSupervisorInput,
57
+ type CreateSupervisorMissionInput,
56
58
  collectSupervisorWork,
57
59
  createSupervisor,
58
60
  listSupervisors,
@@ -62,6 +64,7 @@ export {
62
64
  type SupervisorAutomationPolicy,
63
65
  type SupervisorIntent,
64
66
  type SupervisorLimits,
67
+ type SupervisorMission,
65
68
  type SupervisorNextAction,
66
69
  type SupervisorProjection,
67
70
  type SupervisorRecord,