@indigoai-us/hq-cli 5.293.0 → 5.295.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.
Files changed (97) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +5 -1
  3. package/dist/command-catalog.generated.d.ts +54 -33
  4. package/dist/command-catalog.generated.js +68 -42
  5. package/dist/commands/auth.d.ts +1 -0
  6. package/dist/commands/auth.js +76 -1
  7. package/dist/commands/core-command-catalog.js +3 -2
  8. package/dist/commands/core-delegate-w1b.d.ts +2 -0
  9. package/dist/commands/core-delegate-w1b.js +28 -2
  10. package/dist/commands/core-delegate.d.ts +3 -1
  11. package/dist/commands/core-delegate.js +35 -5
  12. package/dist/commands/core-handoff-fast.d.ts +18 -0
  13. package/dist/commands/core-handoff-fast.js +103 -0
  14. package/dist/commands/core-handoff-open-steps.d.ts +21 -0
  15. package/dist/commands/core-handoff-open-steps.js +264 -0
  16. package/dist/commands/core-handoff.d.ts +4 -2
  17. package/dist/commands/core-handoff.js +22 -249
  18. package/dist/commands/core-jobs-native.d.ts +2 -0
  19. package/dist/commands/core-jobs-native.js +22 -11
  20. package/dist/commands/core-knowledge-prefs.d.ts +2 -0
  21. package/dist/commands/core-knowledge-prefs.js +13 -1
  22. package/dist/commands/core-ontology-native.d.ts +2 -0
  23. package/dist/commands/core-ontology-native.js +22 -2
  24. package/dist/commands/core-policy.d.ts +2 -0
  25. package/dist/commands/core-policy.js +18 -1
  26. package/dist/commands/core.js +2 -1
  27. package/dist/commands/daemon.d.ts +2 -1
  28. package/dist/commands/daemon.js +22 -7
  29. package/dist/commands/doctor.js +0 -74
  30. package/dist/commands/lanes-autopilot.d.ts +11 -0
  31. package/dist/commands/lanes-autopilot.js +336 -0
  32. package/dist/commands/lanes-message.js +23 -5
  33. package/dist/commands/lanes-questions.js +8 -5
  34. package/dist/commands/lanes-resume.js +0 -3
  35. package/dist/commands/lanes-shared.d.ts +18 -2
  36. package/dist/commands/lanes-stories.d.ts +14 -0
  37. package/dist/commands/lanes-stories.js +308 -0
  38. package/dist/commands/lanes.d.ts +1 -9
  39. package/dist/commands/lanes.js +216 -481
  40. package/dist/fast-core.js +53 -25
  41. package/dist/fast-scaffold.d.ts +15 -7
  42. package/dist/fast-scaffold.js +167 -17
  43. package/dist/index.js +1 -10
  44. package/dist/lib/core-utils/sentry-report.d.ts +0 -19
  45. package/dist/lib/core-utils/sentry-report.js +8 -61
  46. package/dist/lib/core-utils/worktree-resume.d.ts +2 -0
  47. package/dist/lib/core-utils/worktree-resume.js +16 -0
  48. package/dist/lib/daemon/migrate.d.ts +8 -1
  49. package/dist/lib/daemon/migrate.js +19 -7
  50. package/dist/lib/doctor/checks/claude-wiring.js +9 -0
  51. package/dist/lib/lanes/autopilot-metrics.d.ts +99 -0
  52. package/dist/lib/lanes/autopilot-metrics.js +301 -0
  53. package/dist/lib/lanes/flag-keys.d.ts +2 -0
  54. package/dist/lib/lanes/flag-keys.js +2 -0
  55. package/dist/lib/lanes/manager-status-gate.d.ts +0 -17
  56. package/dist/lib/lanes/manager-status-gate.js +2 -43
  57. package/dist/lib/lanes/outpost-dispatch.d.ts +2 -0
  58. package/dist/lib/lanes/outpost-dispatch.js +7 -1
  59. package/dist/lib/lanes/outpost-hire-cache.d.ts +0 -1
  60. package/dist/lib/lanes/outpost-hire-cache.js +0 -1
  61. package/dist/lib/lanes/outpost-snapshot-memo.d.ts +6 -0
  62. package/dist/lib/lanes/outpost-snapshot-memo.js +14 -0
  63. package/dist/lib/lanes/reconcile.d.ts +2 -3
  64. package/dist/lib/lanes/reconcile.js +44 -38
  65. package/dist/lib/lanes/spawn.d.ts +0 -2
  66. package/dist/lib/lanes/spawn.js +18 -5
  67. package/dist/lib/lanes/store.d.ts +2 -0
  68. package/dist/lib/lanes/store.js +54 -3
  69. package/dist/lib/lanes/types.d.ts +18 -1
  70. package/dist/lib/lanes/types.js +1 -1
  71. package/dist/lib/lanes/watcher.d.ts +4 -3
  72. package/dist/lib/lanes/watcher.js +102 -34
  73. package/dist/lib/mesh/live/daemon/run.js +18 -1
  74. package/dist/native-fast-route.d.ts +3 -1
  75. package/dist/native-fast-route.js +10 -8
  76. package/dist/utils/cognito-session.d.ts +6 -0
  77. package/dist/utils/cognito-session.js +9 -0
  78. package/dist/utils/contribution-table.d.ts +1 -1
  79. package/dist/utils/fast-stream-errors.d.ts +12 -0
  80. package/dist/utils/fast-stream-errors.js +18 -0
  81. package/dist/utils/scaffold-fast-import-guard.d.ts +2 -2
  82. package/dist/utils/scaffold-fast-import-guard.js +6 -3
  83. package/dist/utils/self-update.js +31 -0
  84. package/dist/utils/version-gate.js +22 -3
  85. package/package.json +1 -1
  86. package/dist/fast-lanes-list-route.d.ts +0 -8
  87. package/dist/fast-lanes-list-route.js +0 -32
  88. package/dist/fast-lanes-list.d.ts +0 -3
  89. package/dist/fast-lanes-list.js +0 -224
  90. package/dist/lib/doctor/client-health-sentry-flag.d.ts +0 -23
  91. package/dist/lib/doctor/client-health-sentry-flag.js +0 -99
  92. package/dist/lib/doctor/client-health-sentry.d.ts +0 -71
  93. package/dist/lib/doctor/client-health-sentry.js +0 -286
  94. package/dist/lib/lanes/outpost-snapshot-cache.d.ts +0 -26
  95. package/dist/lib/lanes/outpost-snapshot-cache.js +0 -215
  96. package/dist/lib/lanes/outpost-snapshot-refresh.d.ts +0 -21
  97. package/dist/lib/lanes/outpost-snapshot-refresh.js +0 -329
@@ -5,7 +5,6 @@ import { parseCliEffort } from "../lib/lanes/effort.js";
5
5
  import { parseOutpostHireGrantContext } from "../lib/lanes/hire-grant-dispatch.js";
6
6
  import { assertNoSecretText } from "../lib/lanes/text-scan.js";
7
7
  import { laneStories, laneStory, storyWarning } from "../lib/lanes/stories.js";
8
- import { managerStatusGateEnabledForLane } from "../lib/lanes/manager-status-gate.js";
9
8
  import { spawnLaneWorker } from "../lib/lanes/spawn.js";
10
9
  import { accountMoveSummary, accountRequestKeepsCurrentLane, assertCurrentResumeAccountAvailable, hasKeepAliveProgress, recordedResumeEffort, resetKeepAliveProgress, resolveResumeEffort } from "./lanes-shared.js";
11
10
  export function createLaneResumeHandlers(deps) {
@@ -328,7 +327,6 @@ export function createLaneResumeHandlers(deps) {
328
327
  resumed = lane;
329
328
  }
330
329
  else {
331
- const managerStatusGateEnabled = await managerStatusGateEnabledForLane(hqRoot, lane, { env: ctx.env });
332
330
  resumed = await withLaneAdmissionLock(hqRoot, lane.provider, async () => {
333
331
  const admission = await assessLaneAdmission(ctx, lane, { queueAt: at });
334
332
  if (admission.action === "refuse" && admission.error)
@@ -376,7 +374,6 @@ export function createLaneResumeHandlers(deps) {
376
374
  }
377
375
  return spawnLaneWorker(hqRoot, lane, {
378
376
  env: ctx.env,
379
- managerStatusGateEnabled,
380
377
  modelDeps: {
381
378
  readFileSync: ctx.readFileSync,
382
379
  probe: ctx.probeProvider,
@@ -157,6 +157,7 @@ export interface LaneMessageHandlerDeps {
157
157
  }): Promise<AdmissionResult>;
158
158
  casUpdateLane(hqRoot: string, laneId: string, updater: (current: LaneRecord) => LaneRecord): LaneRecord;
159
159
  dispatchOutpostLaneCommand(ctx: Ctx, lane: LaneRecord, action: "message" | "resume", options: LaneMessageOptions | LaneResumeOptions, behavior?: OutpostLaneDispatchBehavior): Promise<void>;
160
+ dispatchPrimaryLaneMessage(ctx: Ctx, laneId: string, options: LaneMessageOptions): Promise<void>;
160
161
  drainHookStatusFor(ctx: Ctx, lane: LaneRecord): {
161
162
  registered: boolean;
162
163
  kind: string;
@@ -248,8 +249,6 @@ export interface Ctx {
248
249
  backfillOutpostIdentity: (expectedId: string) => "created" | "unchanged";
249
250
  fetchText: (url: string) => Promise<string>;
250
251
  lanePlacementEnabled: (company: LaneCompanyRef | undefined) => Promise<boolean>;
251
- outpostSnapshotCacheEnabled: () => Promise<boolean>;
252
- startOutpostLaneSnapshotRefresh: (hqRoot: string) => void;
253
252
  storyLedgerEnabled: () => boolean;
254
253
  isSsmOwnerDispatch: () => boolean;
255
254
  withGrantHireLocks: typeof withLaneHireLocks;
@@ -376,6 +375,7 @@ export interface LaneQuestionsHandlerDeps {
376
375
  MAX_PLACEMENT_OUTPOSTS: number;
377
376
  OUTPOST_QUESTION_LOOKUP_CONCURRENCY: number;
378
377
  assertLaneRunsHereForOperatorMutation(ctx: Ctx, lane: LaneRecord, action: string): void;
378
+ assertQuestionAnswerAuthorized(ctx: Ctx, lane: LaneRecord): void;
379
379
  assertQuestionCompanyMatchesLane(question: QuestionRecord, lane: Pick<LaneRecord, "lane_id" | "company" | "mesh_company" | "project_id">, code: string, hqRoot?: string): void;
380
380
  casUpdateQuestion(hqRoot: string, questionId: string, updater: (current: QuestionRecord) => QuestionRecord): QuestionRecord;
381
381
  effectiveLaneQuestionCompany(lane: Pick<LaneRecord, "company" | "mesh_company" | "project_id" | "lane_id">, hqRoot?: string): LaneCompanyRef | null;
@@ -407,4 +407,20 @@ export interface LaneQuestionsHandlerDeps {
407
407
  seniorOfSession(hqRoot: string, sessionId: string, ctx: Ctx): SeniorRef;
408
408
  writeAnswerDeliveryFailed(hqRoot: string, laneId: string, questionId: string, err: unknown, at: string): void;
409
409
  }
410
+ export interface LaneStoryHandlerDeps {
411
+ assertLaneRunsHereForOperatorMutation(ctx: Ctx, lane: LaneRecord, action: string): void;
412
+ casUpdateLane(hqRoot: string, laneId: string, updater: (current: LaneRecord) => LaneRecord): LaneRecord;
413
+ combinedStoryWarning(lane: LaneRecord, additional?: readonly string[]): string | null;
414
+ emitLaneMeshEvent(ctx: Ctx, company: LaneCompanyRef | null | undefined, threadId: string | undefined, event: LaneMeshEvent, payload: Record<string, unknown>): Promise<void>;
415
+ ensureLaneThreadRecord(ctx: Ctx, lane: LaneRecord, projectId?: string, storyId?: string, laneStatus?: string): Promise<LaneRecord>;
416
+ printJson(value: unknown): void;
417
+ readLane(hqRoot: string, laneId: string): LaneRecord;
418
+ storyBoardCheck(ctx: Ctx, company: LaneCompanyRef, projectId: string, storyIds: readonly string[]): Promise<{
419
+ warning?: string;
420
+ absentStoryIds: ReadonlySet<string>;
421
+ }>;
422
+ storyNotOnBoardWarning(err: unknown): string | undefined;
423
+ updateLane(hqRoot: string, laneId: string, expectedVersion: number, source: "command", updater: (current: LaneRecord) => LaneRecord): LaneRecord;
424
+ validateProjectStories(hqRoot: string, projectId: string, storyIds: string[], companySlug?: string): void;
425
+ }
410
426
  //# sourceMappingURL=lanes-shared.d.ts.map
@@ -0,0 +1,14 @@
1
+ import type { Ctx, LaneStoryHandlerDeps } from "./lanes-shared.js";
2
+ export interface StoryCommandOptions {
3
+ project?: string;
4
+ reason?: string;
5
+ verified?: boolean;
6
+ }
7
+ export declare function createLaneStoryHandlers(deps: LaneStoryHandlerDeps): {
8
+ runStoryList: (ctx: Ctx, laneId: string) => Promise<void>;
9
+ runStoryAdd: (ctx: Ctx, laneId: string, storyId: string, opts: StoryCommandOptions) => Promise<void>;
10
+ runStoryStart: (ctx: Ctx, laneId: string, storyId: string, opts: StoryCommandOptions) => Promise<void>;
11
+ runStoryBlock: (ctx: Ctx, laneId: string, storyId: string, opts: StoryCommandOptions) => Promise<void>;
12
+ runStoryDone: (ctx: Ctx, laneId: string, storyId: string, opts: StoryCommandOptions) => Promise<void>;
13
+ };
14
+ //# sourceMappingURL=lanes-stories.d.ts.map
@@ -0,0 +1,308 @@
1
+ import { activeLaneStories, laneStories, laneStory, storyWarning } from "../lib/lanes/stories.js";
2
+ import { LanesError } from "../lib/lanes/errors.js";
3
+ import { sessionIdFromEnv } from "../lib/mesh/live/session-identity.js";
4
+ export function createLaneStoryHandlers(deps) {
5
+ const { assertLaneRunsHereForOperatorMutation, casUpdateLane, combinedStoryWarning, emitLaneMeshEvent, ensureLaneThreadRecord, printJson, readLane, storyBoardCheck, storyNotOnBoardWarning, updateLane, validateProjectStories, } = deps;
6
+ function storyCommandTarget(lane, storyId, project) {
7
+ const projectId = project?.trim() || lane.project_id;
8
+ const normalizedStoryId = storyId.trim();
9
+ if (!projectId) {
10
+ throw new LanesError("missing_project", "--project is required", {});
11
+ }
12
+ if (!normalizedStoryId) {
13
+ throw new LanesError("missing_story", "<story-id> is required", {});
14
+ }
15
+ const story = laneStory(lane, projectId, normalizedStoryId);
16
+ if (!story) {
17
+ throw new LanesError("story_not_on_lane", `Story ${projectId}/${normalizedStoryId} is not carried by lane ${lane.lane_id}`, { lane_id: lane.lane_id, project_id: projectId, story_id: normalizedStoryId });
18
+ }
19
+ return { projectId, storyId: normalizedStoryId, story };
20
+ }
21
+ function updateCarriedStory(lane, projectId, storyId, status, at, extras = {}) {
22
+ const stories = laneStories(lane).map((story) => story.project_id === projectId && story.story_id === storyId
23
+ ? {
24
+ ...story,
25
+ status,
26
+ updated_at: at,
27
+ blocked_reason: extras.blocked_reason,
28
+ verified_at: extras.verified_at,
29
+ verified_by: extras.verified_by,
30
+ }
31
+ : story);
32
+ return {
33
+ ...lane,
34
+ project_id: projectId,
35
+ story_id: storyId,
36
+ stories,
37
+ };
38
+ }
39
+ function addCarriedStory(lane, projectId, storyId, at) {
40
+ if (laneStory(lane, projectId, storyId)) {
41
+ throw new LanesError("story_already_on_lane", `Story ${projectId}/${storyId} is already carried by lane ${lane.lane_id}`, {
42
+ lane_id: lane.lane_id,
43
+ project_id: projectId,
44
+ story_id: storyId,
45
+ });
46
+ }
47
+ return {
48
+ ...lane,
49
+ ...(lane.story_id.trim() ? {} : { project_id: projectId, story_id: storyId }),
50
+ stories: [
51
+ ...laneStories(lane),
52
+ { project_id: projectId, story_id: storyId, status: "in_progress", added_at: at, updated_at: at },
53
+ ],
54
+ };
55
+ }
56
+ function callerMayVerifyStory(ctx, lane) {
57
+ const callerLaneId = ctx.env.HQ_LANE_ID?.trim();
58
+ if (callerLaneId) {
59
+ return lane.senior.kind === "lane" && lane.senior.id === callerLaneId;
60
+ }
61
+ if (lane.senior.kind === "user")
62
+ return true;
63
+ if (lane.senior.kind === "lane")
64
+ return false;
65
+ return sessionIdFromEnv(ctx.env) === lane.senior.id;
66
+ }
67
+ async function ensureStoryThread(ctx, lane, projectId, storyId = lane.story_id) {
68
+ const company = lane.mesh_company ?? lane.company;
69
+ if (!company)
70
+ return lane;
71
+ return ensureLaneThreadRecord(ctx, lane, projectId, storyId);
72
+ }
73
+ async function ensureStoryThreadForTransition(ctx, lane, projectId, storyId) {
74
+ try {
75
+ return { lane: await ensureStoryThread(ctx, lane, projectId, storyId) };
76
+ }
77
+ catch (err) {
78
+ const warning = storyNotOnBoardWarning(err);
79
+ if (warning === undefined)
80
+ throw err;
81
+ return { lane, warning };
82
+ }
83
+ }
84
+ async function emitStoryTransition(ctx, lane, projectId, storyId, event, status, payload = {}, skipStoryStatusPatch = false) {
85
+ const company = lane.mesh_company ?? lane.company;
86
+ if (!company)
87
+ return;
88
+ const ready = await ensureStoryThread(ctx, lane, projectId, storyId);
89
+ if (!ready.thread_id)
90
+ return;
91
+ await emitLaneMeshEvent(ctx, company, ready.thread_id, event, {
92
+ lane_id: ready.lane_id,
93
+ project_id: projectId,
94
+ story_id: storyId,
95
+ ...payload,
96
+ lane_status: lane.state,
97
+ });
98
+ if (!skipStoryStatusPatch && projectId?.trim() && storyId?.trim()) {
99
+ await ctx.mesh.patchStoryStatus(company, projectId, storyId, status === "blocked" ? "in_progress" : status);
100
+ }
101
+ }
102
+ function sameCommittedStory(current, expected, projectId, storyId) {
103
+ const currentStory = laneStory(current, projectId, storyId);
104
+ const expectedStory = laneStory(expected, projectId, storyId);
105
+ return (current.project_id === expected.project_id &&
106
+ current.story_id === expected.story_id &&
107
+ JSON.stringify(currentStory) === JSON.stringify(expectedStory));
108
+ }
109
+ async function commitStoryTransition(ctx, before, next, projectId, storyId, event, status, payload = {}, skipStoryStatusPatch = false) {
110
+ try {
111
+ await emitStoryTransition(ctx, next, projectId, storyId, event, status, payload, skipStoryStatusPatch);
112
+ return undefined;
113
+ }
114
+ catch (err) {
115
+ const warning = storyNotOnBoardWarning(err);
116
+ if (warning !== undefined)
117
+ return warning;
118
+ try {
119
+ const current = readLane(ctx.hqRoot(), next.lane_id);
120
+ if (!sameCommittedStory(current, next, projectId, storyId)) {
121
+ throw new LanesError("story_transition_rollback_conflict", `Story ${projectId}/${storyId} changed while mesh publication failed`, { lane_id: next.lane_id, project_id: projectId, story_id: storyId });
122
+ }
123
+ updateLane(ctx.hqRoot(), next.lane_id, current.version, "command", (latest) => {
124
+ if (!sameCommittedStory(latest, next, projectId, storyId)) {
125
+ throw new LanesError("story_transition_rollback_conflict", `Story ${projectId}/${storyId} changed before rollback`, { lane_id: next.lane_id, project_id: projectId, story_id: storyId });
126
+ }
127
+ return {
128
+ ...latest,
129
+ project_id: before.project_id,
130
+ story_id: before.story_id,
131
+ stories: before.stories,
132
+ };
133
+ });
134
+ }
135
+ catch (rollbackErr) {
136
+ process.stderr.write(`hq lanes: story transition rollback failed for ${next.lane_id}/${projectId}/${storyId}: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}\n`);
137
+ }
138
+ throw err;
139
+ }
140
+ }
141
+ async function runStoryList(ctx, laneId) {
142
+ const lane = readLane(ctx.hqRoot(), laneId);
143
+ printJson({
144
+ ok: true,
145
+ action: "story.list",
146
+ lane_id: laneId,
147
+ stories: laneStories(lane),
148
+ active_stories: activeLaneStories(lane),
149
+ story_warning: storyWarning(lane) ?? null,
150
+ });
151
+ }
152
+ async function runStoryAdd(ctx, laneId, storyId, opts) {
153
+ const hqRoot = ctx.hqRoot();
154
+ let lane = readLane(hqRoot, laneId);
155
+ assertLaneRunsHereForOperatorMutation(ctx, lane, "update story status for");
156
+ const projectId = opts.project?.trim() || lane.project_id;
157
+ if (!projectId)
158
+ throw new LanesError("missing_project", "--project is required", {});
159
+ const normalizedStoryId = storyId.trim();
160
+ if (!normalizedStoryId)
161
+ throw new LanesError("missing_story", "<story-id> is required", {});
162
+ if (ctx.storyLedgerEnabled()) {
163
+ validateProjectStories(hqRoot, projectId, [normalizedStoryId], lane.company?.slug);
164
+ }
165
+ const company = lane.mesh_company ?? lane.company;
166
+ const warnings = [];
167
+ let storyKnownAbsent = false;
168
+ if (company) {
169
+ const boardCheck = await storyBoardCheck(ctx, company, projectId, [normalizedStoryId]);
170
+ if (boardCheck.warning !== undefined)
171
+ warnings.push(boardCheck.warning);
172
+ storyKnownAbsent = boardCheck.absentStoryIds.has(normalizedStoryId);
173
+ }
174
+ const at = ctx.now().toISOString();
175
+ const thread = await ensureStoryThreadForTransition(ctx, lane, projectId, normalizedStoryId);
176
+ lane = thread.lane;
177
+ if (thread.warning !== undefined)
178
+ warnings.push(thread.warning);
179
+ const before = lane;
180
+ const next = casUpdateLane(hqRoot, laneId, (current) => {
181
+ assertLaneRunsHereForOperatorMutation(ctx, current, "update story status for");
182
+ const added = addCarriedStory(current, projectId, normalizedStoryId, at);
183
+ return {
184
+ ...added,
185
+ no_story_reason: undefined,
186
+ };
187
+ });
188
+ const transitionWarning = await commitStoryTransition(ctx, before, next, projectId, normalizedStoryId, "lane_started", "in_progress", {}, storyKnownAbsent);
189
+ if (transitionWarning !== undefined)
190
+ warnings.push(transitionWarning);
191
+ const finalLane = readLane(hqRoot, laneId);
192
+ printJson({
193
+ ok: true,
194
+ action: "story.add",
195
+ lane_id: laneId,
196
+ project_id: projectId,
197
+ story_id: normalizedStoryId,
198
+ status: "in_progress",
199
+ story_warning: combinedStoryWarning(finalLane, warnings),
200
+ lane: finalLane,
201
+ });
202
+ }
203
+ async function runStoryStart(ctx, laneId, storyId, opts) {
204
+ const hqRoot = ctx.hqRoot();
205
+ let lane = readLane(hqRoot, laneId);
206
+ assertLaneRunsHereForOperatorMutation(ctx, lane, "update story status for");
207
+ const target = storyCommandTarget(lane, storyId, opts.project);
208
+ if (target.story.status === "done") {
209
+ throw new LanesError("story_already_done", `Story ${target.projectId}/${target.storyId} is done and cannot be started again`, {
210
+ lane_id: laneId,
211
+ project_id: target.projectId,
212
+ story_id: target.storyId,
213
+ });
214
+ }
215
+ const at = ctx.now().toISOString();
216
+ const warnings = [];
217
+ const thread = await ensureStoryThreadForTransition(ctx, lane, target.projectId, target.storyId);
218
+ lane = thread.lane;
219
+ if (thread.warning !== undefined)
220
+ warnings.push(thread.warning);
221
+ const before = lane;
222
+ const next = casUpdateLane(hqRoot, laneId, (current) => {
223
+ assertLaneRunsHereForOperatorMutation(ctx, current, "update story status for");
224
+ return updateCarriedStory(current, target.projectId, target.storyId, "in_progress", at);
225
+ });
226
+ const transitionWarning = await commitStoryTransition(ctx, before, next, target.projectId, target.storyId, "lane_started", "in_progress");
227
+ if (transitionWarning !== undefined)
228
+ warnings.push(transitionWarning);
229
+ const finalLane = readLane(hqRoot, laneId);
230
+ printJson({ ok: true, action: "story.start", lane_id: laneId, project_id: target.projectId, story_id: target.storyId, status: "in_progress", story_warning: combinedStoryWarning(finalLane, warnings), lane: finalLane });
231
+ }
232
+ async function runStoryBlock(ctx, laneId, storyId, opts) {
233
+ const hqRoot = ctx.hqRoot();
234
+ let lane = readLane(hqRoot, laneId);
235
+ assertLaneRunsHereForOperatorMutation(ctx, lane, "update story status for");
236
+ const target = storyCommandTarget(lane, storyId, opts.project);
237
+ if (target.story.status === "done") {
238
+ throw new LanesError("story_already_done", `Story ${target.projectId}/${target.storyId} is done and cannot be blocked again`, {
239
+ lane_id: laneId,
240
+ project_id: target.projectId,
241
+ story_id: target.storyId,
242
+ });
243
+ }
244
+ const reason = opts.reason?.trim();
245
+ if (!reason)
246
+ throw new LanesError("missing_block_reason", "--reason is required", {});
247
+ const at = ctx.now().toISOString();
248
+ const warnings = [];
249
+ const thread = await ensureStoryThreadForTransition(ctx, lane, target.projectId, target.storyId);
250
+ lane = thread.lane;
251
+ if (thread.warning !== undefined)
252
+ warnings.push(thread.warning);
253
+ const before = lane;
254
+ const next = casUpdateLane(hqRoot, laneId, (current) => {
255
+ assertLaneRunsHereForOperatorMutation(ctx, current, "update story status for");
256
+ return updateCarriedStory(current, target.projectId, target.storyId, "blocked", at, { blocked_reason: reason });
257
+ });
258
+ const transitionWarning = await commitStoryTransition(ctx, before, next, target.projectId, target.storyId, "lane_blocked", "blocked", { blocked_reason: reason });
259
+ if (transitionWarning !== undefined)
260
+ warnings.push(transitionWarning);
261
+ const finalLane = readLane(hqRoot, laneId);
262
+ printJson({ ok: true, action: "story.block", lane_id: laneId, project_id: target.projectId, story_id: target.storyId, status: "blocked", blocked_reason: reason, story_warning: combinedStoryWarning(finalLane, warnings), lane: finalLane });
263
+ }
264
+ async function runStoryDone(ctx, laneId, storyId, opts) {
265
+ const hqRoot = ctx.hqRoot();
266
+ let lane = readLane(hqRoot, laneId);
267
+ assertLaneRunsHereForOperatorMutation(ctx, lane, "update story status for");
268
+ if (!opts.verified) {
269
+ throw new LanesError("senior_verification_required", "Only a senior may mark a story done; pass --verified after reviewing or merging it", { lane_id: laneId });
270
+ }
271
+ if (!callerMayVerifyStory(ctx, lane)) {
272
+ throw new LanesError("senior_verification_required", `Caller is not the senior for lane ${laneId}`, {
273
+ lane_id: laneId,
274
+ senior: lane.senior,
275
+ });
276
+ }
277
+ const target = storyCommandTarget(lane, storyId, opts.project);
278
+ if (target.story.status !== "review") {
279
+ throw new LanesError("story_not_ready_for_verification", `Story ${target.projectId}/${target.storyId} must be in review before senior verification`, {
280
+ lane_id: laneId,
281
+ project_id: target.projectId,
282
+ story_id: target.storyId,
283
+ status: target.story.status,
284
+ });
285
+ }
286
+ const at = ctx.now().toISOString();
287
+ const warnings = [];
288
+ const thread = await ensureStoryThreadForTransition(ctx, lane, target.projectId, target.storyId);
289
+ lane = thread.lane;
290
+ if (thread.warning !== undefined)
291
+ warnings.push(thread.warning);
292
+ const before = lane;
293
+ const next = casUpdateLane(hqRoot, laneId, (current) => {
294
+ assertLaneRunsHereForOperatorMutation(ctx, current, "update story status for");
295
+ return updateCarriedStory(current, target.projectId, target.storyId, "done", at, {
296
+ verified_at: at,
297
+ verified_by: current.senior,
298
+ });
299
+ });
300
+ const transitionWarning = await commitStoryTransition(ctx, before, next, target.projectId, target.storyId, "lane_done", "done", { summary: "Senior verification complete" });
301
+ if (transitionWarning !== undefined)
302
+ warnings.push(transitionWarning);
303
+ const finalLane = readLane(hqRoot, laneId);
304
+ printJson({ ok: true, action: "story.done", lane_id: laneId, project_id: target.projectId, story_id: target.storyId, status: "done", verified: true, story_warning: combinedStoryWarning(finalLane, warnings), lane: finalLane });
305
+ }
306
+ return { runStoryList, runStoryAdd, runStoryStart, runStoryBlock, runStoryDone };
307
+ }
308
+ //# sourceMappingURL=lanes-stories.js.map
@@ -14,7 +14,6 @@ import type { OutpostIdentity } from "../lib/lanes/admission-host.js";
14
14
  export { OUTPOST_DIR, OUTPOST_ID_PATH, readOutpostIdentity } from "../lib/lanes/admission-host.js";
15
15
  export type { OutpostIdentity } from "../lib/lanes/admission-host.js";
16
16
  import { type OutpostDispatchResult } from "../lib/lanes/outpost-dispatch.js";
17
- import { LANE_OUTPOST_SNAPSHOT_CACHE_FLAG } from "../lib/lanes/outpost-hire-cache.js";
18
17
  import { emitLaneDecisionEvents } from "../lib/lanes/mesh-events.js";
19
18
  import { MAX_LANE_DEPTH, withLaneHireLocks, type LaneCompanyRef, type QuestionBody, type LaneRecord, type QuestionRecord, type ResolvedLaneWorker, type SeniorRef, type LivenessDeps, type MachineIdentity, type MonitorEvidenceReader, type RunCommand, type ThrottleDeps } from "../lib/lanes/index.js";
20
19
  import { questionBodyAbsPath } from "../lib/lanes/questions.js";
@@ -62,7 +61,7 @@ export interface LanesCommandDeps {
62
61
  /** Test seam for worker PID identity checks. */
63
62
  readStarttime?: (pid: number) => number | null;
64
63
  /** Test seams for synchronous dead-worker classification and repair. */
65
- watcherLoopDeps?: Pick<WatcherLoopDeps, "sleep" | "spawnRepair" | "readManagerStatusGateFlag">;
64
+ watcherLoopDeps?: Pick<WatcherLoopDeps, "sleep" | "spawnRepair">;
66
65
  stopSleepMs?: (ms: number) => void;
67
66
  livenessDeps?: LivenessDeps;
68
67
  presenceConnected?: boolean;
@@ -88,10 +87,6 @@ export interface LanesCommandDeps {
88
87
  monitorEvidence?: MonitorEvidenceReader;
89
88
  /** Test seam for the default-off outpost placement rollout flag. */
90
89
  lanePlacementEnabled?: (company: LaneCompanyRef | undefined) => Promise<boolean>;
91
- /** Test seam for the default-off shared Outpost snapshot cache. */
92
- outpostSnapshotCacheEnabled?: () => Promise<boolean>;
93
- /** Test seam for the detached refresh started by the cache-first lane list. */
94
- startOutpostLaneSnapshotRefresh?: (hqRoot: string) => void;
95
90
  /** Test seam for the default-off story ledger flag. */
96
91
  storyLedgerEnabled?: () => boolean;
97
92
  /** Test seam for the SSM-only Outpost owner grant path. */
@@ -103,7 +98,6 @@ export interface LanesCommandDeps {
103
98
  /** Test seam for the repository-merge-hold registry flag. */
104
99
  mergeHoldEnabled?: (company: LaneCompanyRef) => boolean | Promise<boolean>;
105
100
  }
106
- export { LANE_OUTPOST_SNAPSHOT_CACHE_FLAG };
107
101
  export declare function parseSeniorRef(raw: string): SeniorRef;
108
102
  export declare function parseQuestionBody(raw: unknown): QuestionBody | null;
109
103
  /**
@@ -148,8 +142,6 @@ export declare function pickupFailureUpdater(reasonRaw: string, details: Record<
148
142
  */
149
143
  export declare function applyOutpostAccountPickup(hqRoot: string, laneId: string, modelDeps?: KnownModelsDeps): LaneRecord;
150
144
  export declare function cancelPendingQuestionsForLane(hqRoot: string, laneId: string, nowIso: string, operatorReason?: string): QuestionRecord[];
151
- /** Keeps the placement-enabled cache-first path on the full lane command graph. */
152
- export declare function runFastCachedLanesListFromEntrypoint(): Promise<void>;
153
145
  export declare function stopCommittedState(state: LaneRecord["state"]): "cancelled" | "killed";
154
146
  /** Stderr notice that `stop` ends a lane for good, naming the resumable path. */
155
147
  export declare function stopTerminalWarning(laneId: string): string;