mancode 0.6.1 → 0.6.3

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/dist/cli.js CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  assertExecutableImplementationScope,
11
11
  assertHandoffTransition,
12
12
  assertKnownKeys,
13
+ assertManDeliveryVerificationSurfaces,
13
14
  assertOperationJournalTransition,
14
15
  assertOperationReservationTopology,
15
16
  assertParentWorkflowRelation,
@@ -71,6 +72,8 @@ import {
71
72
  parseClaim,
72
73
  parseFreshness,
73
74
  parseHandoff,
75
+ parseManReviewEvidence,
76
+ parseManVerificationSurface,
74
77
  parseOperationJournal,
75
78
  parseOperationReservation,
76
79
  parseProjectConfig,
@@ -114,8 +117,9 @@ import {
114
117
  workflowMetadataDigest,
115
118
  writeOperationReservation,
116
119
  writeProjectFacts
117
- } from "./chunk-44UHUCE6.js";
120
+ } from "./chunk-NG72XZ3R.js";
118
121
  import {
122
+ ACCEPTED_STATE_NARRATIVE_GUIDANCE,
119
123
  DEFAULT_MANCODE_END_MARKER,
120
124
  DEFAULT_MANCODE_START_MARKER,
121
125
  INTERFACE_EMOJI_ICON_GUIDANCE,
@@ -128,6 +132,7 @@ import {
128
132
  assertV3AdapterInstallable,
129
133
  assertV3AdapterTargetSafe,
130
134
  hasManagedBlock,
135
+ inspectUnsafeV3AdapterPaths,
131
136
  inspectV3Adapter,
132
137
  inspectV3AdapterVersions,
133
138
  planV3AdapterFiles,
@@ -135,11 +140,13 @@ import {
135
140
  removeManagedBlock,
136
141
  removeV3Adapter,
137
142
  replaceManagedBlock,
143
+ replaceUnsafeV3AdapterSymlinks,
138
144
  stageV3Adapter,
139
145
  stageV3AdapterUpgradeFiles,
140
146
  v3AdapterTargetPath,
141
- v3AdapterVersionsFromStatuses
142
- } from "./chunk-PBXSV352.js";
147
+ v3AdapterVersionsFromStatuses,
148
+ writeThroughResolvedPath
149
+ } from "./chunk-RDPFQODS.js";
143
150
 
144
151
  // src/cli.ts
145
152
  import { realpathSync } from "fs";
@@ -383,6 +390,14 @@ var V3_AUTHORITY_PATHS = [
383
390
  "local",
384
391
  "runtime"
385
392
  ];
393
+ var LOCAL_CONTINUITY_PATHS = [
394
+ "sessions",
395
+ "workflows",
396
+ "cache",
397
+ "quarantine",
398
+ "publish",
399
+ "runtime"
400
+ ];
386
401
  async function scanLegacyAuthority(projectRoot) {
387
402
  const root = path.resolve(projectRoot, ".mancode");
388
403
  const entries = await Promise.all(
@@ -402,9 +417,10 @@ async function scanLegacyAuthority(projectRoot) {
402
417
  async function inspectMancodeLayout(projectRoot) {
403
418
  const root = path.resolve(projectRoot);
404
419
  const mancodeRoot = path.join(root, ".mancode");
405
- const [legacy, target] = await Promise.all([
420
+ const [legacy, target, entries] = await Promise.all([
406
421
  scanLegacyAuthority(root),
407
- lstatOrNull(mancodeRoot)
422
+ lstatOrNull(mancodeRoot),
423
+ targetEntries(mancodeRoot)
408
424
  ]);
409
425
  const v3AuthorityPathsPresent = (await Promise.all(
410
426
  V3_AUTHORITY_PATHS.map(
@@ -413,10 +429,16 @@ async function inspectMancodeLayout(projectRoot) {
413
429
  )).filter(
414
430
  (value) => value !== null
415
431
  );
432
+ const blockingV3AuthorityPresent = v3AuthorityPathsPresent.some(
433
+ (relativePath2) => relativePath2 !== "local"
434
+ );
435
+ const v3ScratchOnly = target?.isDirectory() === true && !blockingV3AuthorityPresent && !await localHasContinuityContent(mancodeRoot);
416
436
  return {
417
437
  legacy,
418
438
  v3TargetExists: target !== null,
419
- v3AuthorityPathsPresent
439
+ v3AuthorityPathsPresent,
440
+ v3ScratchOnly,
441
+ v3TargetEntries: entries
420
442
  };
421
443
  }
422
444
  async function assertGreenfieldInitializationPreflight(projectRoot) {
@@ -525,6 +547,23 @@ async function lstatOrNull(target) {
525
547
  throw error;
526
548
  }
527
549
  }
550
+ async function targetEntries(root) {
551
+ const stat5 = await lstatOrNull(root);
552
+ if (stat5 === null || !stat5.isDirectory()) return [];
553
+ const names = await readdir(root);
554
+ names.sort(compareUtf8);
555
+ return names;
556
+ }
557
+ async function localHasContinuityContent(root) {
558
+ const localPath = path.join(root, "local");
559
+ const stat5 = await lstatOrNull(localPath);
560
+ if (stat5 === null) return false;
561
+ if (!stat5.isDirectory()) return true;
562
+ const names = await readdir(localPath);
563
+ return names.some(
564
+ (name) => LOCAL_CONTINUITY_PATHS.includes(name)
565
+ );
566
+ }
528
567
  function sha256(value) {
529
568
  return `sha256:${createHash("sha256").update(value).digest("hex")}`;
530
569
  }
@@ -2697,6 +2736,13 @@ function operationRecoveryPayloadPath(store, operationId) {
2697
2736
  assertUlid(operationId, "operation recovery payload operationId");
2698
2737
  return path3.join(operationRecoveryDirectory(store), `${operationId}.json`);
2699
2738
  }
2739
+ function operationRecoveryPayloadVersionPath(store, operationId, payloadDigest) {
2740
+ assertUlid(operationId, "operation recovery payload operationId");
2741
+ return path3.join(
2742
+ operationRecoveryDirectory(store),
2743
+ `${operationId}.${payloadDigestToken(payloadDigest)}.json`
2744
+ );
2745
+ }
2700
2746
  async function writeOperationRecoveryPayload(store, value) {
2701
2747
  const payload = parseOperationRecoveryPayload(value);
2702
2748
  if (payload.primaryStoreId !== store.storeId) {
@@ -2725,12 +2771,51 @@ async function writeOperationRecoveryPayload(store, value) {
2725
2771
  throw new Error("MANCODE_OPERATION_RECOVERY_PAYLOAD_CONFLICT");
2726
2772
  }
2727
2773
  }
2774
+ async function writeOperationRecoveryPayloadVersion(store, value) {
2775
+ const payload = parseOperationRecoveryPayload(value);
2776
+ if (payload.primaryStoreId !== store.storeId) {
2777
+ throw new Error(
2778
+ "operation recovery payload primaryStoreId does not match its home store"
2779
+ );
2780
+ }
2781
+ const digest = operationRecoveryPayloadDigest(payload);
2782
+ const directory = operationRecoveryDirectory(store);
2783
+ const target = operationRecoveryPayloadVersionPath(
2784
+ store,
2785
+ payload.operationId,
2786
+ digest
2787
+ );
2788
+ await mkdir2(directory, { recursive: true });
2789
+ try {
2790
+ await writeFile2(target, serialize(payload), {
2791
+ encoding: "utf8",
2792
+ flag: "wx"
2793
+ });
2794
+ return payload;
2795
+ } catch (error) {
2796
+ if (!isAlreadyExists2(error)) throw error;
2797
+ const existing = await readOperationRecoveryPayloadAtPath(target);
2798
+ if (existing !== null && operationRecoveryPayloadDigest(existing) === digest) {
2799
+ return existing;
2800
+ }
2801
+ throw new Error("MANCODE_OPERATION_RECOVERY_PAYLOAD_CONFLICT");
2802
+ }
2803
+ }
2728
2804
  async function readOperationRecoveryPayload(store, operationId) {
2805
+ return readOperationRecoveryPayloadAtPath(
2806
+ operationRecoveryPayloadPath(store, operationId)
2807
+ );
2808
+ }
2809
+ async function readOperationRecoveryPayloadForDigest(store, operationId, payloadDigest) {
2810
+ const versioned = await readOperationRecoveryPayloadAtPath(
2811
+ operationRecoveryPayloadVersionPath(store, operationId, payloadDigest)
2812
+ );
2813
+ if (versioned !== null) return versioned;
2814
+ return readOperationRecoveryPayload(store, operationId);
2815
+ }
2816
+ async function readOperationRecoveryPayloadAtPath(target) {
2729
2817
  try {
2730
- const raw = await readFile3(
2731
- operationRecoveryPayloadPath(store, operationId),
2732
- "utf8"
2733
- );
2818
+ const raw = await readFile3(target, "utf8");
2734
2819
  return parseOperationRecoveryPayload(JSON.parse(raw));
2735
2820
  } catch (error) {
2736
2821
  if (isNotFound3(error)) return null;
@@ -2740,6 +2825,13 @@ async function readOperationRecoveryPayload(store, operationId) {
2740
2825
  throw error;
2741
2826
  }
2742
2827
  }
2828
+ function payloadDigestToken(payloadDigest) {
2829
+ const match = /^sha256:([a-f0-9]{64})$/.exec(payloadDigest);
2830
+ if (match?.[1] === void 0) {
2831
+ throw new Error("operation recovery payload digest is invalid");
2832
+ }
2833
+ return match[1];
2834
+ }
2743
2835
  function serialize(payload) {
2744
2836
  return `${JSON.stringify(payload, null, 2)}
2745
2837
  `;
@@ -5420,6 +5512,30 @@ async function writeTaskCheckpointAtRoot(taskRoot2, value) {
5420
5512
  throw new Error("MANCODE_CHECKPOINT_ID_CONFLICT");
5421
5513
  }
5422
5514
  }
5515
+ async function assertTaskCheckpointIdAvailableAtRoot(taskRoot2, checkpointId) {
5516
+ assertUlid(checkpointId, "checkpointId");
5517
+ await assertSafeTaskDirectory(taskRoot2);
5518
+ const directory = path11.join(taskRoot2, "checkpoints");
5519
+ try {
5520
+ const entry = await lstat4(directory);
5521
+ if (!entry.isDirectory() || entry.isSymbolicLink()) {
5522
+ throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
5523
+ }
5524
+ } catch (error) {
5525
+ if (isNotFound11(error)) return;
5526
+ throw error;
5527
+ }
5528
+ try {
5529
+ const entry = await lstat4(path11.join(directory, `${checkpointId}.json`));
5530
+ if (!entry.isFile() || entry.isSymbolicLink()) {
5531
+ throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
5532
+ }
5533
+ } catch (error) {
5534
+ if (isNotFound11(error)) return;
5535
+ throw error;
5536
+ }
5537
+ throw new Error("MANCODE_CHECKPOINT_ID_CONFLICT");
5538
+ }
5423
5539
  async function readTaskCheckpointAtRoot(taskRoot2, checkpointId) {
5424
5540
  assertUlid(checkpointId, "checkpointId");
5425
5541
  await assertSafeTaskDirectory(taskRoot2);
@@ -5434,9 +5550,13 @@ async function readTaskCheckpointAtRoot(taskRoot2, checkpointId) {
5434
5550
  throw error;
5435
5551
  }
5436
5552
  try {
5437
- return await readImmutableCheckpoint(
5553
+ const checkpoint = await readImmutableCheckpoint(
5438
5554
  path11.join(directory, `${checkpointId}.json`)
5439
5555
  );
5556
+ if (checkpoint.checkpointId !== checkpointId) {
5557
+ throw new Error("MANCODE_CHECKPOINT_CORRUPT");
5558
+ }
5559
+ return checkpoint;
5440
5560
  } catch (error) {
5441
5561
  if (error instanceof Error && error.message === "MANCODE_CHECKPOINT_ID_CONFLICT") {
5442
5562
  return null;
@@ -5607,6 +5727,16 @@ import path12 from "path";
5607
5727
  var REQUIREMENTS_FILE = "requirements.json";
5608
5728
  var REQUIREMENTS_MARKDOWN_FILE = "requirements.md";
5609
5729
  var ACCEPTANCE_ID_PATTERN = /^AC-[A-Z0-9][A-Z0-9-]{0,27}$/;
5730
+ var VERIFICATION_SURFACES = /* @__PURE__ */ new Set([
5731
+ "unit",
5732
+ "component",
5733
+ "handler",
5734
+ "real_http",
5735
+ "browser",
5736
+ "device",
5737
+ "external_service",
5738
+ "manual_observation"
5739
+ ]);
5610
5740
  var REQUIREMENT_DIMENSIONS = [
5611
5741
  "platform",
5612
5742
  "core_scope",
@@ -5692,11 +5822,16 @@ function parseRequirementsLedger2(raw, options = {}) {
5692
5822
  throw new Error(`duplicate acceptance criterion: ${item.id}`);
5693
5823
  }
5694
5824
  ids.add(item.id);
5825
+ const verificationSurfaces = parseVerificationSurfaces(
5826
+ item.verificationSurfaces,
5827
+ item.method
5828
+ );
5695
5829
  return {
5696
5830
  id: item.id,
5697
5831
  description: item.description.trim(),
5698
5832
  required: item.required,
5699
- method: item.method
5833
+ method: item.method,
5834
+ ...verificationSurfaces === void 0 ? {} : { verificationSurfaces }
5700
5835
  };
5701
5836
  });
5702
5837
  if (!options.allowIncomplete && !acceptanceCriteria.some((item) => item.required)) {
@@ -5757,9 +5892,10 @@ function renderRequirementsMarkdown(ledger) {
5757
5892
 
5758
5893
  ${items.length > 0 ? items.map((item) => `- ${item}`).join("\n") : "- \u65E0"}
5759
5894
  `;
5760
- const criteria = ledger.acceptanceCriteria.map(
5761
- (item) => `- **${item.id}** [${item.required ? "\u5FC5\u9700" : "\u53EF\u9009"} / ${item.method}] ${item.description}`
5762
- ).join("\n");
5895
+ const criteria = ledger.acceptanceCriteria.map((item) => {
5896
+ const surfaces = item.verificationSurfaces ? ` / ${Object.entries(item.verificationSurfaces).map(([slot, surface]) => `${slot}=${surface}`).join(", ")}` : "";
5897
+ return `- **${item.id}** [${item.required ? "\u5FC5\u9700" : "\u53EF\u9009"} / ${item.method}${surfaces}] ${item.description}`;
5898
+ }).join("\n");
5763
5899
  const coverage = ledger.coverage.map((item) => `- **${item.dimension}** [${item.status}] ${item.rationale}`).join("\n");
5764
5900
  return `# Requirements
5765
5901
 
@@ -5800,6 +5936,32 @@ function isNonEmptyStringArray(value) {
5800
5936
  function isVerificationMethod(value) {
5801
5937
  return value === "automated" || value === "manual" || value === "hybrid";
5802
5938
  }
5939
+ function parseVerificationSurfaces(value, method) {
5940
+ if (value === void 0) return void 0;
5941
+ if (!isRecord(value))
5942
+ throw new Error("invalid acceptance verificationSurfaces");
5943
+ const unknown = Object.keys(value).filter(
5944
+ (key) => key !== "automated" && key !== "manual"
5945
+ );
5946
+ if (unknown.length)
5947
+ throw new Error("invalid acceptance verificationSurfaces");
5948
+ const automated = parseVerificationSurface(value.automated);
5949
+ const manual = parseVerificationSurface(value.manual);
5950
+ if (method === "automated" && (automated === void 0 || manual !== void 0) || method === "manual" && (automated !== void 0 || manual === void 0) || method === "hybrid" && (automated === void 0 || manual === void 0)) {
5951
+ throw new Error("invalid acceptance verificationSurfaces");
5952
+ }
5953
+ return {
5954
+ ...automated === void 0 ? {} : { automated },
5955
+ ...manual === void 0 ? {} : { manual }
5956
+ };
5957
+ }
5958
+ function parseVerificationSurface(value) {
5959
+ if (value === void 0) return void 0;
5960
+ if (typeof value !== "string" || !VERIFICATION_SURFACES.has(value)) {
5961
+ throw new Error("invalid acceptance verification surface");
5962
+ }
5963
+ return value;
5964
+ }
5803
5965
  function isRequirementDimension(value) {
5804
5966
  return REQUIREMENT_DIMENSIONS.some((dimension) => dimension === value);
5805
5967
  }
@@ -9677,7 +9839,7 @@ async function activateLegacyMigration(input) {
9677
9839
  if (session === null || session.status !== "active") {
9678
9840
  throw new Error("MANCODE_SESSION_NOT_FOUND");
9679
9841
  }
9680
- const store = new (await import("./store-TQFQCAAF.js")).V3ContextStore(root);
9842
+ const store = new (await import("./store-C3G3HN3N.js")).V3ContextStore(root);
9681
9843
  const project = await store.readProjectSnapshot();
9682
9844
  const stage = await readMigrationStage(root, input.stageId);
9683
9845
  if (stage.state !== "staged" || stage.revision !== input.expectedStageRevision) {
@@ -9940,7 +10102,7 @@ async function activateLegacyMigration(input) {
9940
10102
  for (const action of payload.actions.filter(
9941
10103
  (action2) => action2.kind === "v3_adapter_file"
9942
10104
  )) {
9943
- const { applyV3AdapterFilePlan: applyV3AdapterFilePlan2 } = await import("./v3-adapter-TPXL336I.js");
10105
+ const { applyV3AdapterFilePlan: applyV3AdapterFilePlan2 } = await import("./v3-adapter-7KIOYYWS.js");
9944
10106
  await applyV3AdapterFilePlan2(root, action);
9945
10107
  }
9946
10108
  journal = await completeActivationStep(
@@ -12906,8 +13068,17 @@ async function executeOperationRecovery(input) {
12906
13068
  assertUlid(input.operationId, "operation recovery operationId");
12907
13069
  assertUlid(input.actorId, "operation recovery actorId");
12908
13070
  assertUlid(input.sessionId, "operation recovery sessionId");
13071
+ if (input.replacementCheckpointId !== void 0) {
13072
+ assertUlid(
13073
+ input.replacementCheckpointId,
13074
+ "operation recovery replacementCheckpointId"
13075
+ );
13076
+ }
12909
13077
  const now = input.now ?? /* @__PURE__ */ new Date();
12910
13078
  const mode = input.mode ?? "repair";
13079
+ if (mode === "abort" && input.replacementCheckpointId !== void 0) {
13080
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_INVALID");
13081
+ }
12911
13082
  const stores = await knownOperationStores(input.projectRoot);
12912
13083
  const located = await locateJournal(stores, input.operationId);
12913
13084
  if (located === null) throw new Error("MANCODE_OPERATION_JOURNAL_NOT_FOUND");
@@ -12921,23 +13092,30 @@ async function executeOperationRecovery(input) {
12921
13092
  });
12922
13093
  assertRecoveryActor(initialPlan, input.actorId, input.sessionId);
12923
13094
  if (located.journal.state === "committed" || located.journal.state === "aborted") {
13095
+ await assertTerminalCheckpointReplacementRetry(
13096
+ located.store,
13097
+ located.journal,
13098
+ input.replacementCheckpointId
13099
+ );
12924
13100
  return {
12925
13101
  state: "already_terminal",
12926
13102
  journal: located.journal,
12927
13103
  reason: "terminal"
12928
13104
  };
12929
13105
  }
13106
+ assertCheckpointReplacementSupported(
13107
+ located.journal,
13108
+ input.replacementCheckpointId
13109
+ );
12930
13110
  const locks = await acquireRecoveryOperationLocks(
12931
13111
  located.store,
12932
13112
  located.journal,
12933
13113
  stores,
12934
- now
13114
+ now,
13115
+ input.replacementCheckpointId === void 0 ? [] : [`checkpoint:${input.replacementCheckpointId}`]
12935
13116
  );
12936
13117
  try {
12937
- const journal = await readOperationJournal(
12938
- located.store,
12939
- input.operationId
12940
- );
13118
+ let journal = await readOperationJournal(located.store, input.operationId);
12941
13119
  if (journal === null)
12942
13120
  throw new Error("MANCODE_OPERATION_JOURNAL_NOT_FOUND");
12943
13121
  const plan = planOperationRecovery({
@@ -12946,9 +13124,18 @@ async function executeOperationRecovery(input) {
12946
13124
  });
12947
13125
  assertRecoveryActor(plan, input.actorId, input.sessionId);
12948
13126
  if (journal.state === "committed" || journal.state === "aborted") {
13127
+ await assertTerminalCheckpointReplacementRetry(
13128
+ located.store,
13129
+ journal,
13130
+ input.replacementCheckpointId
13131
+ );
12949
13132
  return { state: "already_terminal", journal, reason: "terminal" };
12950
13133
  }
12951
- const payload = await loadBoundPayload(located.store, journal);
13134
+ assertCheckpointReplacementSupported(
13135
+ journal,
13136
+ input.replacementCheckpointId
13137
+ );
13138
+ let payload = await loadBoundPayload(located.store, journal);
12952
13139
  if (payload === null) {
12953
13140
  if (plan.action === "safe_abort") {
12954
13141
  const aborted = await abortOperation(
@@ -12971,6 +13158,28 @@ async function executeOperationRecovery(input) {
12971
13158
  reason: "MANCODE_OPERATION_RECOVERY_PAYLOAD_REQUIRED"
12972
13159
  };
12973
13160
  }
13161
+ if (input.replacementCheckpointId === void 0 && payload.type === "reframe" && await reframeCheckpointReplacementProvenance(
13162
+ located.store,
13163
+ journal,
13164
+ payload
13165
+ ) !== null) {
13166
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_REQUIRED");
13167
+ }
13168
+ let checkpointReplacement;
13169
+ if (input.replacementCheckpointId !== void 0) {
13170
+ const amended = await replaceReframeRecoveryCheckpoint({
13171
+ projectRoot: input.projectRoot,
13172
+ primaryStore: located.store,
13173
+ stores,
13174
+ journal,
13175
+ payload,
13176
+ replacementCheckpointId: input.replacementCheckpointId,
13177
+ now
13178
+ });
13179
+ journal = amended.journal;
13180
+ payload = amended.payload;
13181
+ checkpointReplacement = amended.checkpointReplacement;
13182
+ }
12974
13183
  assertOperationRecoveryPayloadCoversJournal(journal, payload);
12975
13184
  try {
12976
13185
  await removePrivateWorkflowStaging(input.projectRoot, journal, payload);
@@ -12992,6 +13201,7 @@ async function executeOperationRecovery(input) {
12992
13201
  }
12993
13202
  if (mode === "abort") throw new Error("MANCODE_OPERATION_ABORT_UNSAFE");
12994
13203
  try {
13204
+ await assertReframeRecoveryPlanCurrent(input.projectRoot, payload);
12995
13205
  const repaired = await applyPayload(
12996
13206
  input.projectRoot,
12997
13207
  located.store,
@@ -13010,14 +13220,16 @@ async function executeOperationRecovery(input) {
13010
13220
  return {
13011
13221
  state: "repaired",
13012
13222
  journal: repaired,
13013
- reason: "forward_repair"
13223
+ reason: "forward_repair",
13224
+ ...checkpointReplacement === void 0 ? {} : { checkpointReplacement }
13014
13225
  };
13015
13226
  } catch (error) {
13016
13227
  const blocked = await markRepairRequired(located.store, journal, now);
13017
13228
  return {
13018
13229
  state: "repair_required",
13019
13230
  journal: blocked,
13020
- reason: error instanceof Error && error.message === "MANCODE_OPERATION_RECOVERY_CONFLICT" ? "MANCODE_OPERATION_RECOVERY_CONFLICT" : "MANCODE_OPERATION_RECOVERY_FAILED"
13231
+ reason: error instanceof Error && error.message === "MANCODE_OPERATION_RECOVERY_CONFLICT" ? "MANCODE_OPERATION_RECOVERY_CONFLICT" : "MANCODE_OPERATION_RECOVERY_FAILED",
13232
+ ...checkpointReplacement === void 0 ? {} : { checkpointReplacement }
13021
13233
  };
13022
13234
  }
13023
13235
  } finally {
@@ -13055,7 +13267,7 @@ async function readReservations(journal, stores) {
13055
13267
  })
13056
13268
  ).then((values) => values.filter((value) => value !== null));
13057
13269
  }
13058
- async function acquireRecoveryOperationLocks(primaryStore, journal, stores, now) {
13270
+ async function acquireRecoveryOperationLocks(primaryStore, journal, stores, now, extraPrimaryEntityLocks = []) {
13059
13271
  const byId = new Map(stores.map((store) => [store.storeId, store]));
13060
13272
  const secondaryTargets = journal.secondaryReservations.map((reservation) => {
13061
13273
  const store = byId.get(reservation.storeId);
@@ -13067,7 +13279,12 @@ async function acquireRecoveryOperationLocks(primaryStore, journal, stores, now)
13067
13279
  return acquireOperationEntityLocks(
13068
13280
  journal.operationId,
13069
13281
  [
13070
- { store: primaryStore, entityLockKeys: journal.entityLocks },
13282
+ {
13283
+ store: primaryStore,
13284
+ entityLockKeys: [
13285
+ .../* @__PURE__ */ new Set([...journal.entityLocks, ...extraPrimaryEntityLocks])
13286
+ ]
13287
+ },
13071
13288
  ...secondaryTargets
13072
13289
  ],
13073
13290
  { now }
@@ -13075,9 +13292,10 @@ async function acquireRecoveryOperationLocks(primaryStore, journal, stores, now)
13075
13292
  }
13076
13293
  async function loadBoundPayload(store, journal) {
13077
13294
  if (journal.recoveryPayloadDigest === void 0) return null;
13078
- const payload = await readOperationRecoveryPayload(
13295
+ const payload = await readOperationRecoveryPayloadForDigest(
13079
13296
  store,
13080
- journal.operationId
13297
+ journal.operationId,
13298
+ journal.recoveryPayloadDigest
13081
13299
  );
13082
13300
  if (payload === null) {
13083
13301
  throw new Error("MANCODE_OPERATION_RECOVERY_PAYLOAD_MISSING");
@@ -13088,6 +13306,301 @@ async function loadBoundPayload(store, journal) {
13088
13306
  }
13089
13307
  return parsed;
13090
13308
  }
13309
+ function assertCheckpointReplacementSupported(journal, replacementCheckpointId) {
13310
+ if (replacementCheckpointId === void 0) return;
13311
+ if (journal.type !== "reframe" || journal.state !== "repair_required" || journal.recoveryPayloadDigest === void 0 || journal.secondaryReservations.length !== 0) {
13312
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_UNSUPPORTED");
13313
+ }
13314
+ }
13315
+ async function assertTerminalCheckpointReplacementRetry(store, journal, replacementCheckpointId) {
13316
+ if (replacementCheckpointId === void 0) return;
13317
+ if (journal.type !== "reframe" || journal.state !== "committed" || journal.recoveryPayloadDigest === void 0 || journal.secondaryReservations.length !== 0) {
13318
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_UNSUPPORTED");
13319
+ }
13320
+ const payload = await loadBoundPayload(store, journal);
13321
+ if (payload === null) {
13322
+ throw new Error("MANCODE_OPERATION_RECOVERY_PAYLOAD_REQUIRED");
13323
+ }
13324
+ assertOperationRecoveryPayloadCoversJournal(journal, payload);
13325
+ const replacement = await reframeCheckpointReplacementProvenance(
13326
+ store,
13327
+ journal,
13328
+ payload
13329
+ );
13330
+ if (replacement?.replacementCheckpointId !== replacementCheckpointId) {
13331
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_NOT_APPLICABLE");
13332
+ }
13333
+ }
13334
+ async function replaceReframeRecoveryCheckpoint(input) {
13335
+ const checkpointAction = singleReframeCheckpointAction(input.payload);
13336
+ const previousCheckpointId = checkpointAction.checkpoint.checkpointId;
13337
+ const priorReplacement = await reframeCheckpointReplacementProvenance(
13338
+ input.primaryStore,
13339
+ input.journal,
13340
+ input.payload
13341
+ );
13342
+ if (priorReplacement !== null) {
13343
+ if (priorReplacement.replacementCheckpointId !== input.replacementCheckpointId) {
13344
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_NOT_APPLICABLE");
13345
+ }
13346
+ await assertRecoveryPayloadState(
13347
+ input.projectRoot,
13348
+ input.stores,
13349
+ input.payload
13350
+ );
13351
+ return {
13352
+ journal: input.journal,
13353
+ payload: input.payload,
13354
+ checkpointReplacement: priorReplacement
13355
+ };
13356
+ }
13357
+ if (previousCheckpointId === input.replacementCheckpointId) {
13358
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_NOT_APPLICABLE");
13359
+ }
13360
+ const taskRootPath2 = await taskRoot(
13361
+ input.projectRoot,
13362
+ checkpointAction.checkpoint.taskRef
13363
+ );
13364
+ const currentCheckpoint = await readTaskCheckpointAtRoot(
13365
+ taskRootPath2,
13366
+ previousCheckpointId
13367
+ );
13368
+ if (!reframeCheckpointStepReached(input.journal) || currentCheckpoint === null || currentCheckpoint.operationId === input.journal.operationId || !sameTaskRef(
13369
+ currentCheckpoint.taskRef,
13370
+ checkpointAction.checkpoint.taskRef
13371
+ ) || digestCanonicalJson(currentCheckpoint) === digestCanonicalJson(checkpointAction.checkpoint)) {
13372
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_NOT_APPLICABLE");
13373
+ }
13374
+ await assertRecoveryPayloadState(
13375
+ input.projectRoot,
13376
+ input.stores,
13377
+ input.payload,
13378
+ checkpointAction
13379
+ );
13380
+ await assertReframeRecoveryPlanCurrent(input.projectRoot, input.payload);
13381
+ const payload = buildReframeCheckpointReplacementPayload(
13382
+ input.payload,
13383
+ checkpointAction,
13384
+ input.replacementCheckpointId
13385
+ );
13386
+ const replacementAction = singleReframeCheckpointAction(payload);
13387
+ const existingReplacement = await readTaskCheckpointAtRoot(
13388
+ taskRootPath2,
13389
+ input.replacementCheckpointId
13390
+ );
13391
+ if (existingReplacement !== null && digestCanonicalJson(existingReplacement) !== digestCanonicalJson(replacementAction.checkpoint)) {
13392
+ throw new Error("MANCODE_REPLACEMENT_CHECKPOINT_ID_CONFLICT");
13393
+ }
13394
+ await assertRecoveryPayloadState(input.projectRoot, input.stores, payload);
13395
+ const fromKey = `checkpoint:${previousCheckpointId}`;
13396
+ const toKey = `checkpoint:${input.replacementCheckpointId}`;
13397
+ const payloadDigest = operationRecoveryPayloadDigest(payload);
13398
+ const journal = parseOperationJournal({
13399
+ ...input.journal,
13400
+ recoveryPayloadDigest: payloadDigest,
13401
+ entityLocks: input.journal.entityLocks.map(
13402
+ (key) => key === fromKey ? toKey : key
13403
+ ),
13404
+ expectedRevisions: Object.fromEntries(
13405
+ Object.entries(input.journal.expectedRevisions).map(([key, revision]) => [
13406
+ key === fromKey ? toKey : key,
13407
+ revision
13408
+ ])
13409
+ ),
13410
+ updatedAt: input.now.toISOString()
13411
+ });
13412
+ assertOperationJournalMatchesDefinition(journal);
13413
+ assertOperationRecoveryPayloadCoversJournal(journal, payload);
13414
+ await writeOperationRecoveryPayloadVersion(input.primaryStore, payload);
13415
+ const updatedJournal = await updateOperationJournal(
13416
+ input.primaryStore,
13417
+ journal,
13418
+ {
13419
+ canAbort: false,
13420
+ reframeCheckpointReplacement: {
13421
+ fromCheckpointId: previousCheckpointId,
13422
+ toCheckpointId: input.replacementCheckpointId
13423
+ }
13424
+ }
13425
+ );
13426
+ throwIfOperationCrashInjected("reframe", "rebind-reframe-checkpoint");
13427
+ return {
13428
+ journal: updatedJournal,
13429
+ payload,
13430
+ checkpointReplacement: {
13431
+ previousCheckpointId,
13432
+ replacementCheckpointId: input.replacementCheckpointId
13433
+ }
13434
+ };
13435
+ }
13436
+ function reframeCheckpointStepReached(journal) {
13437
+ const checkpointIndex = journal.steps.findIndex(
13438
+ (step) => step.id === "write-reframe-checkpoint"
13439
+ );
13440
+ return checkpointIndex >= 0 && journal.steps.slice(0, checkpointIndex).every((step) => step.state === "completed");
13441
+ }
13442
+ async function reframeCheckpointReplacementProvenance(store, journal, payload) {
13443
+ if (journal.type !== "reframe") return null;
13444
+ const canonicalValue = await readOperationRecoveryPayload(
13445
+ store,
13446
+ journal.operationId
13447
+ );
13448
+ if (canonicalValue === null) {
13449
+ throw new Error("MANCODE_OPERATION_RECOVERY_PAYLOAD_MISSING");
13450
+ }
13451
+ const canonical = parseOperationRecoveryPayload(canonicalValue);
13452
+ if (canonical.operationId !== journal.operationId || canonical.type !== journal.type || canonical.primaryStoreId !== journal.primaryStoreId) {
13453
+ throw new Error("MANCODE_OPERATION_RECOVERY_PAYLOAD_MISMATCH");
13454
+ }
13455
+ if (operationRecoveryPayloadDigest(canonical) === operationRecoveryPayloadDigest(payload)) {
13456
+ return null;
13457
+ }
13458
+ const previousCheckpointId = singleReframeCheckpointAction(canonical).checkpoint.checkpointId;
13459
+ const replacementCheckpointId = singleReframeCheckpointAction(payload).checkpoint.checkpointId;
13460
+ if (previousCheckpointId === replacementCheckpointId) return null;
13461
+ const expected = buildReframeCheckpointReplacementPayload(
13462
+ canonical,
13463
+ singleReframeCheckpointAction(canonical),
13464
+ replacementCheckpointId
13465
+ );
13466
+ if (operationRecoveryPayloadDigest(expected) !== operationRecoveryPayloadDigest(payload)) {
13467
+ throw new Error("MANCODE_OPERATION_RECOVERY_PAYLOAD_MISMATCH");
13468
+ }
13469
+ return { previousCheckpointId, replacementCheckpointId };
13470
+ }
13471
+ async function assertReframeRecoveryPlanCurrent(projectRoot, payload) {
13472
+ if (payload.type !== "reframe") return;
13473
+ const checkpointAction = singleReframeCheckpointAction(payload);
13474
+ const archiveAction = singleTaskArchiveAction(payload);
13475
+ const task = await new V3ContextStore(projectRoot).readTaskSnapshot(
13476
+ checkpointAction.checkpoint.taskRef
13477
+ );
13478
+ if ((task.plan?.digest ?? null) !== archiveAction.sourcePlanDigest) {
13479
+ throw new Error("MANCODE_OPERATION_RECOVERY_CONFLICT");
13480
+ }
13481
+ }
13482
+ function buildReframeCheckpointReplacementPayload(payload, checkpointAction, replacementCheckpointId) {
13483
+ const finalMetadataAction = singleTaskAuthorityAction(
13484
+ payload,
13485
+ "commit-reframed-metadata",
13486
+ "metadata.json"
13487
+ );
13488
+ const requirementsAction = singleTaskAuthorityAction(
13489
+ payload,
13490
+ "write-requirements-draft",
13491
+ "requirements.json"
13492
+ );
13493
+ const reviewAction = singleTaskAuthorityAction(
13494
+ payload,
13495
+ "mark-review-verification-stale",
13496
+ "review-ledger.json"
13497
+ );
13498
+ const verificationAction = singleTaskAuthorityAction(
13499
+ payload,
13500
+ "mark-review-verification-stale",
13501
+ "verification-ledger.json"
13502
+ );
13503
+ const archiveAction = singleTaskArchiveAction(payload);
13504
+ const metadata = parseWorkflowMetadata(
13505
+ JSON.parse(finalMetadataAction.targetContent)
13506
+ );
13507
+ if (metadata.lastOperationId !== payload.operationId || metadata.latestCheckpointRef?.kind !== "checkpoint" || metadata.latestCheckpointRef.artifactId !== checkpointAction.checkpoint.checkpointId) {
13508
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_INVALID");
13509
+ }
13510
+ const checkpoint = parseCheckpoint({
13511
+ ...checkpointAction.checkpoint,
13512
+ checkpointId: replacementCheckpointId
13513
+ });
13514
+ const replacementMetadata = parseWorkflowMetadata({
13515
+ ...metadata,
13516
+ latestCheckpointRef: {
13517
+ ...metadata.latestCheckpointRef,
13518
+ artifactId: replacementCheckpointId
13519
+ }
13520
+ });
13521
+ const aggregate = buildTaskAggregateManifest({
13522
+ metadata: replacementMetadata,
13523
+ requirements: parseRequirementsLedger(
13524
+ JSON.parse(requirementsAction.targetContent)
13525
+ ),
13526
+ review: parseReviewLedger(JSON.parse(reviewAction.targetContent)),
13527
+ verification: parseVerificationLedger(
13528
+ JSON.parse(verificationAction.targetContent)
13529
+ ),
13530
+ planDigest: archiveAction.sourcePlanDigest,
13531
+ latestCheckpoint: checkpoint
13532
+ });
13533
+ const fenceActions = payload.actions.filter(
13534
+ (action) => action.kind === "task_head_fence"
13535
+ );
13536
+ if (fenceActions.length > 1) {
13537
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_INVALID");
13538
+ }
13539
+ return parseOperationRecoveryPayload({
13540
+ ...payload,
13541
+ actions: payload.actions.map((action) => {
13542
+ if (action === checkpointAction) {
13543
+ return { ...action, checkpoint };
13544
+ }
13545
+ if (action === finalMetadataAction) {
13546
+ return {
13547
+ ...action,
13548
+ targetContent: serializeTaskAuthority(replacementMetadata)
13549
+ };
13550
+ }
13551
+ if (action.kind === "task_head_fence") {
13552
+ return {
13553
+ ...action,
13554
+ fence: parseTaskHeadFence({
13555
+ ...action.fence,
13556
+ aggregateDigest: taskAggregateDigest(aggregate)
13557
+ })
13558
+ };
13559
+ }
13560
+ return action;
13561
+ })
13562
+ });
13563
+ }
13564
+ function singleReframeCheckpointAction(payload) {
13565
+ const matches = payload.actions.filter(
13566
+ (action) => action.kind === "checkpoint" && action.stepId === "write-reframe-checkpoint" && action.beforeDigest === null
13567
+ );
13568
+ if (matches.length !== 1 || matches[0] === void 0) {
13569
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_UNSUPPORTED");
13570
+ }
13571
+ return matches[0];
13572
+ }
13573
+ function singleTaskAuthorityAction(payload, stepId, fileName) {
13574
+ const matches = payload.actions.filter(
13575
+ (action) => action.kind === "task_authority_file" && action.stepId === stepId && action.fileName === fileName
13576
+ );
13577
+ if (matches.length !== 1 || matches[0] === void 0) {
13578
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_UNSUPPORTED");
13579
+ }
13580
+ return matches[0];
13581
+ }
13582
+ function singleTaskArchiveAction(payload) {
13583
+ const matches = payload.actions.filter(
13584
+ (action) => action.kind === "task_archive" && action.stepId === "archive-requirements-plan"
13585
+ );
13586
+ if (matches.length !== 1 || matches[0] === void 0) {
13587
+ throw new Error("MANCODE_REFRAME_CHECKPOINT_REPLACEMENT_UNSUPPORTED");
13588
+ }
13589
+ return matches[0];
13590
+ }
13591
+ async function assertRecoveryPayloadState(projectRoot, stores, payload, ignoredAction) {
13592
+ for (const [index, action] of payload.actions.entries()) {
13593
+ if (action === ignoredAction) continue;
13594
+ const current = await currentActionDigest(projectRoot, stores, action);
13595
+ const target = recoveryActionTargetDigest(action);
13596
+ const laterTarget = payload.actions.slice(index + 1).some(
13597
+ (candidate) => recoveryActionResourceKey(candidate) === recoveryActionResourceKey(action) && recoveryActionTargetDigest(candidate) === current
13598
+ );
13599
+ if (current !== target && current !== action.beforeDigest && !laterTarget) {
13600
+ throw new Error("MANCODE_OPERATION_RECOVERY_CONFLICT");
13601
+ }
13602
+ }
13603
+ }
13091
13604
  async function allActionsAtInitialState(projectRoot, stores, payload) {
13092
13605
  const initialByResource = /* @__PURE__ */ new Map();
13093
13606
  for (const action of payload.actions) {
@@ -13796,7 +14309,7 @@ async function upgradeV3Adapters(input) {
13796
14309
  if (unfinished.length > 0) {
13797
14310
  throw new Error("MANCODE_ADAPTER_UPGRADE_OPERATION_PENDING");
13798
14311
  }
13799
- const actualVersions = await import("./v3-adapter-TPXL336I.js").then(
14312
+ const actualVersions = await import("./v3-adapter-7KIOYYWS.js").then(
13800
14313
  ({ inspectV3AdapterVersions: inspectV3AdapterVersions2 }) => inspectV3AdapterVersions2(
13801
14314
  root,
13802
14315
  managedAdapterNames(project.manifest.managedAdapters)
@@ -14808,6 +15321,7 @@ trigger: <\u5177\u4F53\u4E8B\u5B9E>
14808
15321
 
14809
15322
  **\u6536\u5C3E\u9636\u6BB5**\uFF1A
14810
15323
  - \u4E00\u8F6E\u4FEE\u590D\u540E\u91CD\u8DD1\u53D7\u5F71\u54CD\u7684 build/lint/typecheck/test \u548C\u5FC5\u8981 smoke test\uFF0C\u4E0D\u91CD\u590D\u8FD0\u884C\u5DF2\u5B8C\u6210 reviewer\u3002
15324
+ - ${ACCEPTED_STATE_NARRATIVE_GUIDANCE}
14811
15325
  - \u751F\u6210 summary\uFF1A\u6539\u52A8/\u65B0\u5EFA\u6587\u4EF6\u3001\u590D\u7528\u8D44\u6E90\u3001\u9A8C\u8BC1\u7ED3\u679C\u3001\u5BA1\u67E5\u6DF1\u5EA6\u3001\u95EE\u9898\u5904\u7F6E\u3001\u8DF3\u8FC7\u6B65\u9AA4\u548C\u6B8B\u4F59\u98CE\u9669\u3002
14812
15326
  - \u53EA\u6709\u9A8C\u8BC1\u901A\u8FC7\u3001\u6240\u9700\u5BA1\u67E5\u9886\u57DF\u5B8C\u6210\u4E14 blocker \u6E05\u96F6\u624D\u5EFA\u8BAE \`completed\`\uFF1B\u5426\u5219\u5199 \`blocked\` \u4E0E\u660E\u786E blockingReason\u3002
14813
15327
  - \u5C06\u5173\u952E\u51B3\u7B56\u4EA4\u7ED9\u8C03\u7528\u65B9 appendTeamDecision\uFF0C\u5E76\u66F4\u65B0 Active Plans\u3002
@@ -15388,6 +15902,9 @@ trigger: <\u5177\u4F53\u4E8B\u5B9E>
15388
15902
  - \u547D\u540D\u3001\u53EF\u8BFB\u6027\u3001DRY\u3001loading/error \u5F62\u5F0F\u7B49\u5EFA\u8BAE\u4E0D\u81EA\u52A8\u6269\u5927\u6539\u52A8\uFF1B\u4E0E\u9700\u6C42\u65E0\u5173\u65F6\u4E0D\u8F93\u51FA\u3002
15389
15903
  - \u9274\u6743\u3001\u652F\u4ED8\u3001\u654F\u611F\u6570\u636E\u3001\u5220\u9664\u3001\u516C\u5F00 API\u3001\u672A\u53EF\u4FE1\u8F93\u5165\u3001\u5E76\u53D1\u6216\u57FA\u7840\u8BBE\u65BD\u7B49\u786C\u98CE\u9669\u540C\u6837\u5C5E\u4E8E\u5347\u7EA7\u4FE1\u53F7\uFF1B\u82E5\u6CA1\u6709\u89E6\u53D1 realignment\uFF0C\u7528\u6237\u660E\u786E\u9009\u62E9\u7EE7\u7EED solo \u540E\u53EF\u4EE5\u7EE7\u7EED\u3002
15390
15904
 
15905
+ ### \u6700\u7EC8\u4EA4\u4ED8\u53D9\u4E8B
15906
+ ${ACCEPTED_STATE_NARRATIVE_GUIDANCE}
15907
+
15391
15908
  ## \u4F60\u7684\u98CE\u683C
15392
15909
 
15393
15910
  - \u76F4\u63A5\u3001\u7B80\u6D01\u3001\u4E0D\u5E9F\u8BDD
@@ -15403,7 +15920,11 @@ var CORE_CODING_PRINCIPLES = `## \u94C1\u5F8B\uFF08\u6C38\u4E0D\u8FDD\u53CD\uFF0
15403
15920
  2. **\u5148\u9A8C\u8BC1\u518D\u58F0\u79F0\u5B8C\u6210** \u2014 \u5F00\u5DE5\u524D\u5199\u660E\u5B9E\u8D28\u5047\u8BBE\u548C\u53EF\u9A8C\u8BC1\u6210\u529F\u6807\u51C6\uFF1Bbuild/lint/test \u5FC5\u987B\u5B9E\u9645\u8DD1
15404
15921
  3. **\u5931\u8D25\u4E24\u6B21\u5FC5\u987B\u505C\u4E0B** \u2014 \u4E0D\u76F2\u8BD5
15405
15922
  4. **\u4E0D\u53EF\u9006\u64CD\u4F5C\u5148\u95EE** \u2014 \u5220\u9664\u3001force push\u3001worktree \u5408\u5E76
15406
- 5. **\u53EA\u89E3\u51B3\u88AB\u95EE\u5230\u7684\u95EE\u9898** \u2014 \u4F18\u5148\u590D\u7528\u73B0\u6709\u5B9E\u73B0\uFF0C\u9009\u62E9\u6EE1\u8DB3\u9A8C\u6536\u7684\u6700\u5C0F\u76F4\u63A5\u6539\u52A8\uFF1B\u4E0D\u52A0\u63A8\u6D4B\u6027\u529F\u80FD\u3001\u4E00\u6B21\u6027\u62BD\u8C61\u3001\u65E0\u5173\u6E05\u7406\u6216\u591A\u4F59\u914D\u7F6E`;
15923
+ 5. **\u53EA\u89E3\u51B3\u88AB\u95EE\u5230\u7684\u95EE\u9898** \u2014 \u4F18\u5148\u590D\u7528\u73B0\u6709\u5B9E\u73B0\uFF0C\u9009\u62E9\u6EE1\u8DB3\u9A8C\u6536\u7684\u6700\u5C0F\u76F4\u63A5\u6539\u52A8\uFF1B\u4E0D\u52A0\u63A8\u6D4B\u6027\u529F\u80FD\u3001\u4E00\u6B21\u6027\u62BD\u8C61\u3001\u65E0\u5173\u6E05\u7406\u6216\u591A\u4F59\u914D\u7F6E
15924
+
15925
+ ## \u6700\u7EC8\u4EA4\u4ED8\u53D9\u4E8B
15926
+
15927
+ ${ACCEPTED_STATE_NARRATIVE_GUIDANCE}`;
15407
15928
 
15408
15929
  // src/templates/skills/man.ts
15409
15930
  var MAN_SKILL = {
@@ -15415,6 +15936,10 @@ var MAN_SKILL = {
15415
15936
 
15416
15937
  \u7528 \`mancode workflow create man "<task>" --json\` \u521B\u5EFA workflow \u5E76\u8BFB\u53D6\u8FD4\u56DE\u7684 taskId\uFF1B\u4E0D\u5F97\u76F4\u63A5\u521B\u5EFA\u6216\u6539\u5199 metadata.json\u3002\u968F\u540E\u53EA\u7528 workflow CLI \u66F4\u65B0\u9700\u6C42\u3001\u9A8C\u8BC1\u3001step/status/planVersion/skippedSteps\u3002\u901A\u7528 \`--skipped\` \u53EA\u7528\u4E8E Step 1\u20132 \u7684 \`clarification\`\uFF1B\u7528\u6237\u660E\u786E\u8DF3\u8FC7\u6574\u4E2A review \u65F6\u5FC5\u987B\u5728 Step 6 \u4F7F\u7528\u4E13\u7528 \`workflow review ... skip --reason\`\uFF0C\u4E0D\u80FD\u5199\u6570\u5B57\u3001\`film-1\` \u6216 \`film-2\`\u3002state \u7684 \`currentMode\`\u3001\`currentTask\` \u548C \`currentWorkflowMode\` \u6307\u5411\u672C task\u3002
15417
15938
 
15939
+ \u5F53\u4EFB\u52A1\u663E\u5F0F\u4F7F\u7528 document-bound delivery\uFF08\`mancode workflow create man "<task>" --delivery\`\uFF0Cplanning policy 3\uFF09\u65F6\uFF0C\u4EE5\u4E0B\u4EA4\u4ED8\u89C4\u5219\u53EA\u5BF9\u8BE5\u65B0 \`/man\` \u4EFB\u52A1\u751F\u6548\uFF1B\u666E\u901A \`/man\`\u3001\u65E7\u4EFB\u52A1\u3001\`/manba\`\u3001\`/manteam\`\u3001\`/manps\`\u3001\`/mansolo\` \u548C Solo handoff \u4FDD\u6301\u539F\u534F\u8BAE\u3002\u8BA1\u5212\u5FC5\u987B\u7ED1\u5B9A\u9879\u76EE\u6307\u5B9A\u7684\u8BA1\u5212\u6587\u4EF6\uFF08\u9ED8\u8BA4 \`doc/\`\uFF0C\u5DF2\u6709 \`docs/\` \u7EA6\u5B9A\u4F18\u5148\uFF09\uFF0C\u6A21\u5757\u5B8C\u6210\u540E\u628A\u5B9E\u9645\u4EA4\u4ED8\u56DE\u5199\u5230\u540C\u4E00\u6587\u4EF6\u7684 delivery record\uFF0C\u518D\u505A\u4E00\u6B21\u6A21\u5757\u603B\u5BA1\u3002\u603B\u5BA1\u8BFB\u53D6\u5DF2\u6279\u51C6\u8BA1\u5212\u3001\u76F8\u5173\u67B6\u6784\u3001\u5B8C\u6574\u6A21\u5757 diff\u3001\u5165\u53E3/\u8C03\u7528\u94FE\u548C\u9A8C\u8BC1\u8BC1\u636E\uFF0C\u68C0\u67E5\u76EE\u6807\u8986\u76D6\u3001\u771F\u5B9E\u6B63\u786E\u6027/\u6F0F\u6D1E\uFF0C\u4EE5\u53CA\u65E0\u4F9D\u636E\u7684\u9632\u5FA1\u548C\u62BD\u8C61\uFF1B\u5B83\u4E0D\u80FD\u53EA\u542C\u5B9E\u73B0\u8005\u603B\u7ED3\u3002reviewer \u8FDB\u7A0B\u9000\u51FA\u7801\u4E3A 0 \u6216\u81EA\u7136\u8BED\u8A00\u8BF4\u201C\u901A\u8FC7\u201D\u90FD\u4E0D\u4EE3\u8868 review \u5DF2\u5199\u5165\uFF1A\u5FC5\u987B\u91CD\u65B0\u8FD0\u884C \`mancode workflow delivery <TaskRef> inspect --json\`\uFF0C\u770B\u5230 ledger \u4ECD\u4E3A \`pending\`\u3001\`in_review\`\u3001\`stale\` \u6216 \`blocked\` \u65F6\uFF0C\u62A5\u544A \`review_incomplete\` \u5E76\u7EE7\u7EED\u5BA1\u6838\u6216\u4FEE\u590D\u3002\`reviewer: independent\` \u53EA\u662F\u8C03\u7528\u8005\u81EA\u8FF0\u7684\u5BA1\u6838\u5143\u6570\u636E\uFF0C\u4E0D\u662F actor/session \u8EAB\u4EFD\u8BA4\u8BC1\uFF0C\u4E0D\u80FD\u636E\u6B64\u5BA3\u79F0\u7CFB\u7EDF\u5DF2\u8BC1\u660E\u72EC\u7ACB\u5BA1\u6838\u3002
15940
+
15941
+ delivery requirements \u7684\u6BCF\u4E2A\u5FC5\u9700\u9A8C\u6536\u9879\u90FD\u5FC5\u987B\u7528 \`verificationSurfaces\` \u6309 automated/manual slot \u58F0\u660E\u671F\u671B observation surface\uFF1Bdelivery \u9A8C\u8BC1\u8F93\u5165\u518D\u58F0\u660E\u5B9E\u9645 surface\uFF1A\`unit\`\u3001\`component\`\u3001\`handler\`\u3001\`real_http\`\u3001\`browser\`\u3001\`device\`\u3001\`external_service\` \u6216 \`manual_observation\`\u3002\u4F8B\u5982\u771F\u5B9E HTTP \u7684\u671F\u671B\u548C\u5B9E\u9645\u90FD\u5FC5\u987B\u662F \`real_http\`\uFF1B\u4E0D\u80FD\u4ECE\u547D\u4EE4\u540D\u731C\u6D4B\uFF0C\u4E5F\u4E0D\u80FD\u628A handler/mock/\u622A\u56FE\u5F53\u6210\u771F\u5B9E HTTP\u3002\u7F3A\u5C11\u6216\u4E0D\u5339\u914D\u7684\u8BC1\u636E\u4FDD\u6301\u672A\u9A8C\u8BC1\u3002\u5B8C\u6210\u524D\u4EE5 \`delivery check --json\` \u7684\u7ED3\u6784\u5316 finalization blockers \u4E3A\u51C6\uFF0C\u5148\u89E3\u51B3 review\u3001verification\u3001delivery record\u3001scope \u548C\u672A\u63D0\u4EA4\u53D8\u66F4\uFF0C\u518D\u8FD0\u884C \`workflow complete\`\uFF1B\u8303\u56F4\u5916\u672A\u63D0\u4EA4\u6587\u4EF6\u5FC5\u987B\u5148\u79FB\u51FA\u3001stash \u6216\u5355\u72EC\u63D0\u4EA4\uFF0C\u4E0D\u80FD\u6DF7\u5165\u672C\u4EFB\u52A1\u63D0\u4EA4\u3002\u6CA1\u6709 upstream \u6216 push \u5931\u8D25\u8868\u793A\u672A\u53D1\u5E03\uFF0C\u4E0D\u662F\u4E1A\u52A1\u963B\u585E\u3002include/exclude \u53EA\u63A5\u6536 repo-relative path \u6216 glob\uFF0C\u8BED\u4E49\u8303\u56F4\u5199\u5728 requirements\uFF1B\u8BA1\u5212\u8DEF\u5F84\u8D8A\u754C\u65F6\u6309 CLI \u7ED9\u51FA\u7684\u5177\u4F53\u8DEF\u5F84\u4FEE\u6B63\uFF0C\u4E0D\u8981\u9760\u731C\u6D4B\u8BCD\u8868\u6269\u5927\u9632\u5FA1\u3002
15942
+
15418
15943
  ## \u8BA1\u5212\u804C\u8D23\u4E0E\u6280\u672F\u9009\u62E9\u5173\u5361
15419
15944
 
15420
15945
  \u628A \`/man\` \u4F5C\u4E3A\u6B63\u5F0F\u8BA1\u5212\u5165\u53E3\uFF1A\u5148\u5BF9\u9F50\u9700\u6C42\u5E76\u4EA7\u51FA\u53EF\u786E\u8BA4\u7684\u8BA1\u5212\uFF0C\u4E0D\u56E0\u8BA1\u5212\u5B8C\u6210\u800C\u81EA\u52A8\u8FDB\u5165\u5B8C\u6574\u5B9E\u65BD\u3002\u8BA1\u5212\u5173\u5361\u5FC5\u987B\u8BA9\u7528\u6237\u9009\u62E9\u53EA\u4FDD\u7559\u8BA1\u5212\u3001\u4EA4\u7ED9\u9ED8\u8BA4 \`solo\` \u8F7B\u91CF\u5B9E\u65BD\u3001\u7EE7\u7EED\u5B8C\u6574 \`/man\` \u6216\u4FEE\u6539\u8BA1\u5212\u3002
@@ -15438,7 +15963,7 @@ var MAN_SKILL = {
15438
15963
 
15439
15964
  \u6309\u4EFB\u52A1\u5B9E\u9645\u9002\u7528\u8303\u56F4\u68C0\u67E5\uFF1A\u7528\u6237\u76EE\u6807\u4E0E\u5E73\u53F0\u3001\u6838\u5FC3\u6D41\u7A0B\u3001\u9996\u671F\u8303\u56F4\u3001\u6392\u9664\u9879\u3001\u6280\u672F\u4E0E\u8FD0\u884C\u7EA6\u675F\u3001\u6570\u636E/\u72B6\u6001/\u96C6\u6210\u3001\u6027\u80FD/\u517C\u5BB9\u6027/\u5B89\u5168\u3001\u53EF\u9A8C\u8BC1\u5B8C\u6210\u6807\u51C6\u3002\u8FDE\u7EED\u6F84\u6E05\u6CA1\u6709\u51CF\u5C11 blocking \u9879\u65F6\uFF0C\u4E0D\u6563\u95EE\uFF1B\u8BA9\u7528\u6237\u9009\u62E9\u7F29\u5C0F\u9996\u671F\u8303\u56F4\u3001\u63A5\u53D7\u5217\u660E\u7684\u63A8\u8350\u9ED8\u8BA4\u503C\u6216\u6682\u505C\u3002
15440
15965
 
15441
- \u628A\u7ED3\u8BBA\u5199\u5165\u7ED3\u6784\u5316\u9700\u6C42\u8F93\u5165\uFF0C\u81F3\u5C11\u5305\u542B \`goal\`\u3001\u975E\u7A7A \`confirmedScope\`\u3001\`excludedScope\`\u3001\`technicalDecisions\`\u3001\`defaults\`\u3001\`blockingUnknowns\`\u3001\`coverage\` \u548C \`acceptanceCriteria\`\u3002coverage \u5FC5\u987B\u9010\u9879\u8BF4\u660E platform\u3001core_scope\u3001technical_stack\u3001data_and_persistence\u3001performance\u3001compatibility\u3001security \u662F \`confirmed\`\u3001\`defaulted\` \u6216\u5E26\u7406\u7531\u7684 \`not_applicable\`\uFF0C\u4E0D\u80FD\u7528\u7A7A\u6570\u7EC4\u5047\u88C5\u5DF2\u7ECF\u8003\u8651\u3002\u6BCF\u4E2A\u6838\u5FC3\u7528\u6237\u884C\u4E3A\u5FC5\u987B\u6709\u7A33\u5B9A\u9A8C\u6536 ID\uFF08\`AC-1\` \u7B49\uFF09\u3001\u63CF\u8FF0\u3001\`required\` \u548C\u9A8C\u8BC1\u65B9\u5F0F \`automated\` / \`manual\` / \`hybrid\`\uFF1B\u81F3\u5C11\u4E00\u4E2A\u9A8C\u6536\u9879\u5FC5\u9700\u3002\u8FD0\u884C \`mancode workflow requirements <taskId> finalize --file <requirements-input.json>\`\uFF0C\u7531 CLI \u6821\u9A8C\u5E76\u751F\u6210\u6743\u5A01 \`requirements.json\` \u4E0E \`requirements.md\`\uFF0C\u4E0D\u8981\u624B\u5DE5\u5236\u9020\u4E24\u4EFD\u53EF\u80FD\u51B2\u7A81\u7684\u7ED3\u8BBA\u3002\u65E0\u987B\u63D0\u95EE\u65F6\u53EF\u628A \`clarification\` \u8BB0\u5165\u7D2F\u8BA1 skippedSteps\uFF0C\u4F46\u4E0D\u80FD\u8DF3\u8FC7\u9700\u6C42\u6458\u8981\u4E0E\u5C31\u7EEA\u5224\u65AD\u3002\u4ECD\u6709 blocking \u9879\u65F6\u505C\u5728 Step 2\uFF1B\u53EA\u6709 CLI \u8FD4\u56DE ready \u624D\u8FD0\u884C \`mancode workflow update <taskId> --step 3\`\u3002
15966
+ \u628A\u7ED3\u8BBA\u5199\u5165\u7ED3\u6784\u5316\u9700\u6C42\u8F93\u5165\uFF0C\u81F3\u5C11\u5305\u542B \`goal\`\u3001\u975E\u7A7A \`confirmedScope\`\u3001\`excludedScope\`\u3001\`technicalDecisions\`\u3001\`defaults\`\u3001\`blockingUnknowns\`\u3001\`coverage\` \u548C \`acceptanceCriteria\`\u3002coverage \u5FC5\u987B\u9010\u9879\u8BF4\u660E platform\u3001core_scope\u3001technical_stack\u3001data_and_persistence\u3001performance\u3001compatibility\u3001security \u662F \`confirmed\`\u3001\`defaulted\` \u6216\u5E26\u7406\u7531\u7684 \`not_applicable\`\uFF0C\u4E0D\u80FD\u7528\u7A7A\u6570\u7EC4\u5047\u88C5\u5DF2\u7ECF\u8003\u8651\u3002\u6BCF\u4E2A\u6838\u5FC3\u7528\u6237\u884C\u4E3A\u5FC5\u987B\u6709\u7A33\u5B9A\u9A8C\u6536 ID\uFF08\`AC-1\` \u7B49\uFF09\u3001\u63CF\u8FF0\u3001\`required\` \u548C\u9A8C\u8BC1\u65B9\u5F0F \`automated\` / \`manual\` / \`hybrid\`\uFF1Bdocument-bound delivery \u7684\u5FC5\u9700\u9879\u8FD8\u8981\u63D0\u4F9B\u4E0E method \u69FD\u4F4D\u4E00\u81F4\u7684 \`verificationSurfaces\`\uFF0C\u4F8B\u5982 \`{ "automated": "real_http" }\`\uFF0Chybrid \u540C\u65F6\u63D0\u4F9B automated \u548C manual\u3002\u81F3\u5C11\u4E00\u4E2A\u9A8C\u6536\u9879\u5FC5\u9700\u3002\u8FD0\u884C \`mancode workflow requirements <taskId> finalize --file <requirements-input.json>\`\uFF0C\u7531 CLI \u6821\u9A8C\u5E76\u751F\u6210\u6743\u5A01 \`requirements.json\` \u4E0E \`requirements.md\`\uFF0C\u4E0D\u8981\u624B\u5DE5\u5236\u9020\u4E24\u4EFD\u53EF\u80FD\u51B2\u7A81\u7684\u7ED3\u8BBA\u3002\u65E0\u987B\u63D0\u95EE\u65F6\u53EF\u628A \`clarification\` \u8BB0\u5165\u7D2F\u8BA1 skippedSteps\uFF0C\u4F46\u4E0D\u80FD\u8DF3\u8FC7\u9700\u6C42\u6458\u8981\u4E0E\u5C31\u7EEA\u5224\u65AD\u3002\u4ECD\u6709 blocking \u9879\u65F6\u505C\u5728 Step 2\uFF1B\u53EA\u6709 CLI \u8FD4\u56DE ready \u624D\u8FD0\u884C \`mancode workflow update <taskId> --step 3\`\u3002
15442
15967
 
15443
15968
  ### Step 3: Plan Coach \u51FA\u8BA1\u5212
15444
15969
 
@@ -15492,7 +16017,7 @@ Plan Coach \u5FC5\u987B\u8BC1\u660E\u6240\u6709\u9009\u9879\u89E3\u51B3\u540C\u4
15492
16017
 
15493
16018
  1. \u5B58\u5728 open blocker \u65F6\uFF0CHead Coach \u4E00\u6B21\u6027\u4FEE\u590D\u5168\u90E8 blocker\uFF0C\u5E76\u7528 \`mancode workflow review <taskId> remediate --resolved Q1,D1\` \u8BB0\u5F55\u552F\u4E00\u4E00\u8F6E\u4FEE\u590D\uFF1B\u6CA1\u6709 blocker \u65F6\u4E0D\u8FD0\u884C remediate\u3002\u4E0D\u8981\u4E3A \u{1F7E1}/\u{1F7E2} \u6269\u5927\u6539\u52A8\u3002
15494
16019
  2. remediation \u4F1A\u4F7F\u65E7\u9A8C\u8BC1\u6574\u6279\u5931\u6548\u3002\u5728 Step 9 \u91CD\u8DD1\u5168\u90E8 required \u9A8C\u6536\uFF0C\u5E76\u901A\u8FC7 verify record/require-manual/confirm-manual \u91CD\u65B0\u767B\u8BB0\u8BC1\u636E\uFF1B\u672A\u91CD\u65B0\u5168\u90E8\u901A\u8FC7\u4E0D\u80FD completed\u3002\u4E0D\u91CD\u65B0\u8FD0\u884C\u5DF2\u5B8C\u6210\u7684 reviewer\u3002\u4FEE\u590D\u82E5\u5F15\u5165\u65B0\u7684\u9AD8\u98CE\u9669\u9762\u5219\u6807\u8BB0 blocked\uFF0C\u4E0D\u80FD\u5F00\u542F\u65E0\u754C review \u5FAA\u73AF\u3002
15495
- 3. \u5199 \`summary.md\`\uFF1A\u6539\u52A8\u3001\u65B0\u5EFA\u3001\u590D\u7528\u3001\u9A8C\u8BC1\u3001\u5BA1\u67E5\u6DF1\u5EA6\u3001findings \u5904\u7F6E\u3001\u8DF3\u8FC7\u6B65\u9AA4\u548C\u6B8B\u4F59\u98CE\u9669\u3002
16020
+ 3. \u57FA\u4E8E accepted target\u3001\u4EFB\u52A1\u8D77\u59CB baseline\u3001\u5B9E\u9645\u8BFB\u56DE\u72B6\u6001\u548C task-owned diff \u5199 \`summary.md\` \u53CA\u4EFB\u4F55 commit/PR \u6587\u6848\uFF1A\u8BB0\u5F55\u6539\u52A8\u3001\u65B0\u5EFA\u3001\u590D\u7528\u3001\u9A8C\u8BC1\u3001\u5BA1\u67E5\u6DF1\u5EA6\u3001findings \u5904\u7F6E\u3001\u8DF3\u8FC7\u6B65\u9AA4\u548C\u6B8B\u4F59\u98CE\u9669\uFF1B\u4FDD\u7559 \`excludedScope\`\u3001\u5931\u8D25\u9A8C\u8BC1\u3001blocker\u3001\u8FC1\u79FB/\u56DE\u6EDA\u548C\u5BA1\u8BA1\u4E8B\u5B9E\u3002
15496
16021
  4. CLI \u786E\u8BA4\u6240\u9700\u5BA1\u67E5\u9886\u57DF\u5B8C\u6210\u4E14 blocker \u6E05\u96F6\u540E\u624D\u5199 \`completed\`\uFF1B\u5426\u5219\u7528 \`--status blocked --blocking-reason "<\u539F\u56E0>"\`\u3002
15497
16022
  5. \u5173\u952E\u51B3\u7B56 appendTeamDecision \u5230 \`decisions.md\`\uFF0C\u66F4\u65B0 Active Plans\u3002\u53D1\u73B0\u65B0\u7684\u9AD8\u9891\u9886\u57DF\u8BCD\u65F6\u5411\u7528\u6237\u63D0\u8BAE\uFF0C\u7ECF\u7528\u6237\u786E\u8BA4\u540E\u7528 \`mancode context glossary add\` \u767B\u8BB0\uFF0C\u4E0D\u5F97\u672A\u7ECF\u786E\u8BA4\u5199\u5165\u672F\u8BED\u8868\u3002
15498
16023
  6. worktree \u5408\u5E76\u524D\u53D6\u5F97\u7528\u6237\u786E\u8BA4\uFF1B\u7EC8\u6001\u5199\u5165\u6210\u529F\u540E state \u56DE solo \u5E76\u6E05\u7A7A workflow \u6307\u9488\u3002
@@ -15540,7 +16065,7 @@ var MAMBA_SKILL = {
15540
16065
 
15541
16066
  ## 5. \u771F\u5B9E\u56DE\u5F52\u4E0E\u7ED3\u8BBA
15542
16067
 
15543
- \u91CD\u8DD1\u539F\u8DEF\u5F84\uFF0C\u8986\u76D6\u53D7\u5F71\u54CD\u7684\u5173\u952E\u6B63\u5411\u3001\u8D1F\u5411\u548C\u6743\u9650\u8FB9\u754C\u8DEF\u5F84\uFF0C\u5E76\u8FD0\u884C\u5FC5\u8981 build/lint/typecheck/test\u3002\u5199 \`mamba-report.md\`\uFF1A\u73AF\u5883\u3001\u6B65\u9AA4\u3001\u7ED3\u679C\u3001\u4EA7\u7269\u8DEF\u5F84\u3001\u56DE\u5F52\u8303\u56F4\u3001\u98CE\u9669\u4E0E\u5EFA\u8BAE\u3002
16068
+ \u91CD\u8DD1\u539F\u8DEF\u5F84\uFF0C\u8986\u76D6\u53D7\u5F71\u54CD\u7684\u5173\u952E\u6B63\u5411\u3001\u8D1F\u5411\u548C\u6743\u9650\u8FB9\u754C\u8DEF\u5F84\uFF0C\u5E76\u8FD0\u884C\u5FC5\u8981 build/lint/typecheck/test\u3002\u57FA\u4E8E\u5B9E\u9645\u89C2\u5BDF\u5230\u7684\u6700\u7EC8\u72B6\u6001\u5199 \`mamba-report.md\`\uFF1A\u73AF\u5883\u3001\u6B65\u9AA4\u3001\u7ED3\u679C\u3001\u4EA7\u7269\u8DEF\u5F84\u3001\u56DE\u5F52\u8303\u56F4\u3001\u98CE\u9669\u4E0E\u5EFA\u8BAE\uFF1B\u62A5\u544A\u5FC5\u987B\u5982\u5B9E\u4FDD\u7559 no_repro\u3001blocked/manual_test_required\u3001\u5931\u8D25\u9A8C\u8BC1\u3001\u8D1F\u5411\u6216\u6743\u9650\u7ED3\u679C\u548C\u6B8B\u4F59\u98CE\u9669\u3002
15544
16069
 
15545
16070
  - \u5DF2\u4FEE\u590D\uFF1A\`status: "completed", outcome: "fixed"\`
15546
16071
  - \u5DF2\u9A8C\u8BC1\u4F46\u672A\u6539\u4EE3\u7801\uFF1A\`status: "completed", outcome: "verified"\`
@@ -15844,6 +16369,8 @@ var MANTEAM_SKILL = {
15844
16369
  - Follow-up TODOs, only if unavoidable
15845
16370
  - Suggested commit message
15846
16371
 
16372
+ handoff\u3001commit \u548C PR \u6587\u6848\u5FC5\u987B\u6765\u81EA accepted target\u3001\u4EFB\u52A1\u8D77\u59CB baseline\u3001\u5B9E\u9645\u8BFB\u56DE\u72B6\u6001\u4E0E task-owned diff\u3002\u4E0D\u5F97\u8BA9\u4F1A\u8BDD\u4E2D\u88AB\u5426\u51B3\u7684\u65B9\u6848\u5B9A\u4E49\u4EA4\u4ED8\u8EAB\u4EFD\uFF0C\u4F46\u5FC5\u987B\u4FDD\u7559\u51B2\u7A81\u3001\u672A\u5B8C\u6210\u5DE5\u4F5C\u3001\u5931\u8D25\u9A8C\u8BC1\u3001blocker\u3001\u8FC1\u79FB/\u56DE\u6EDA\u3001\u5BA1\u8BA1\u4E8B\u5B9E\uFF0C\u4EE5\u53CA\u6B63\u5F0F handoff \u7684 rejected/cancelled \u72B6\u6001\u548C reason\u3002
16373
+
15847
16374
  \u53EA\u6709\u5728\u7528\u6237\u786E\u8BA4\u5B9E\u65BD\u5E76\u5B8C\u6210 workflow \u540E\uFF0C\u624D\u628A\u6700\u7EC8 ADR \u8FFD\u52A0\u5230 \`.mancode/memory/decisions.md\`\u3002abandoned / plan-only workflow \u53EA\u80FD\u4FDD\u7559\u5728 \`.mancode/workflows/<taskId>/team-context.md\`\u3001\`plan.md\` \u548C \`handoff.md\`\uFF0C\u4E0D\u80FD\u6C61\u67D3\u957F\u671F\u56E2\u961F memory\u3002
15848
16375
 
15849
16376
  ## Commit Discipline
@@ -16814,7 +17341,7 @@ var MODE_META = {
16814
17341
  " If environment, permission, or data is missing, set blocked with `--blocking-reason` and keep state resumable instead of advancing.",
16815
17342
  "3. Reproduce the shortest path and write `diagnosis.md` with evidence, root cause or candidates, impact, and confidence; then update to Step 4.",
16816
17343
  "4. Apply only the requested minimum fix, or make no code change when the user requested validation only. New architecture or cross-module scope returns to /man. Then update to Step 5.",
16817
- "5. Re-run the path and affected positive, negative, and permission boundaries; write `mamba-report.md` with environment, evidence, artifacts, regression scope, and risks.",
17344
+ "5. Re-run the path and affected positive, negative, and permission boundaries; write `mamba-report.md` from the observed final state with environment, evidence, artifacts, regression scope, and risks. Preserve authoritative no_repro, blocked/manual_test_required, failed validation, negative or permission results, and residual risks.",
16818
17345
  "",
16819
17346
  "Finish through the CLI with exactly one result: completed+fixed, completed+verified, completed+no_repro, completed+manual_test_required, or blocked+blockingReason. Never claim real testing in restricted mode. Child blocked/manual_test_required propagation is handled by the CLI. After a child finishes with fixed/verified/no_repro, inspect its parent; if that parent is still blocked because of this child, run `mancode workflow update <parentTaskId> --status in_progress` before restoring parent state at Step 6. Never auto-resume manual_test_required."
16820
17347
  ].join("\n")
@@ -16840,7 +17367,7 @@ var MODE_META = {
16840
17367
  "Step 6 \u2014 Run `workflow verify <taskId> init`, execute detected build/lint/typecheck/test and smoke checks, and record every required acceptance ID with reproducible evidence; automated passed/failed records include the command and exit code. Use require-manual when a foreground browser, device, or human judgment is necessary; stop for explicit user confirmation before confirm-manual. The CLI blocks Step 7 and review until all checks pass. Then write `review-scope.md` and initialize targeted or full review. An explicit user review skip uses `workflow review <taskId> skip --reason <reason>` at Step 6, never generic skipped metadata.",
16841
17368
  "Step 7 \u2014 Run one quality review limited to the changed diff and direct impact. Compare every changed path and behavior with confirmed requirements, acceptance IDs, and implementation scope; any unauthorized behavior, path outside include, or path matching exclude is a blocker. Findings require changed-line evidence and user impact, with at most three new findings. Record stable blocker IDs through `workflow review ... complete`; do not fix yet.",
16842
17369
  "Step 8 \u2014 Only full review runs the security/boundary reviewer. It must read Film #1, mark the same root cause duplicate, and stay within security, permissions, recovery, resources, and boundaries. A targeted review treats the second domain as not applicable; it is never recorded as a skipped step.",
16843
- "Step 9 \u2014 If open blockers exist, fix them in one remediation round and record resolved IDs through `workflow review ... remediate`; remediation invalidates all earlier acceptance evidence, so re-run and re-record every required check at Step 9 without re-running completed reviewers. Write `summary.md` and set completed only when verification and required review domains are complete and blockers are zero.",
17370
+ "Step 9 \u2014 If open blockers exist, fix them in one remediation round and record resolved IDs through `workflow review ... remediate`; remediation invalidates all earlier acceptance evidence, so re-run and re-record every required check at Step 9 without re-running completed reviewers. Build `summary.md`, commit, and PR copy from the accepted target, authoritative baseline, observed final state, and task-owned diff; preserve excluded scope, failed verification, blockers, migration or rollback, and audit facts. Set completed only when verification and required review domains are complete and blockers are zero.",
16844
17371
  "",
16845
17372
  "Stop and return the read-only diagnostic `NEEDS_REALIGNMENT` with reason `MANCODE_REFRAME_REQUIRED` when new evidence invalidates the confirmed goal, semantic owner, source of truth, or acceptance; platform entries would produce different semantics; status/contract/policy/transition meaning must change; an adapter is stale, the writer is incompatible, an operation is unfinished, an active child/open handoff/active solo assignment exists; or the change exceeds the current requirements/plan scope. Preserve metadata, requirements, plan, ledgers, claims, and handoffs. Do not call generic workflow update, write blocked/currentStep/planning, archive files, release claims, or claim to be back at Step 2.",
16846
17373
  "",
@@ -16870,7 +17397,7 @@ var MODE_META = {
16870
17397
  "`workflow update --status in_progress`; never auto-resume manual_test_required.",
16871
17398
  "",
16872
17399
  "Read `.mancode/memory/prd.md`, `spec.md`, and `decisions.md`; append durable",
16873
- "decisions only after confirmed implementation. Write `handoff.md`. Never",
17400
+ "decisions only after confirmed implementation. Build `handoff.md`, commit, and PR copy from the accepted target, authoritative baseline, observed final state, and task-owned diff; preserve conflicts, incomplete work, failed verification, migration or rollback, audit facts, and formal rejected or cancelled handoff states and reasons. Never",
16874
17401
  "overwrite teammate changes or commit/merge/push without explicit approval."
16875
17402
  ].join("\n")
16876
17403
  },
@@ -16977,6 +17504,8 @@ function renderPracticeRules() {
16977
17504
  "",
16978
17505
  "For every task, consider: why this change, what already exists, and what is the smallest useful diff?",
16979
17506
  "",
17507
+ `- ${ACCEPTED_STATE_NARRATIVE_GUIDANCE}`,
17508
+ "",
16980
17509
  "In solo mode, use the narrowest meaningful validation and one bounded self-check limited to the current diff. Do not start another reviewer or repeat the review.",
16981
17510
  "Recommend man and explain the trigger when platform entry/flow differs, the semantic owner or source of truth is unclear, status/contract/policy semantics change, scope/architecture/cost/acceptance crosses files or modules, or historical compatibility, migration, cross-platform, or team evidence is required. Auth, payment, sensitive data, deletion, public APIs, untrusted input, concurrency, and infrastructure remain hard-risk signals. Advice alone never changes mode, step, policy, or authority.",
16982
17511
  "While executing confirmed requirements/plan, new evidence that invalidates its goal, owner, source of truth, acceptance, or scope, or a stale adapter/incompatible writer/unfinished operation/active child/open handoff/active solo assignment, requires the read-only diagnostic `NEEDS_REALIGNMENT` with reason `MANCODE_REFRAME_REQUIRED`. Preserve metadata, requirements, plan, ledgers, claims, and handoffs; do not call generic workflow update, write blocked/currentStep/planning, archive files, release claims, or claim to be back at Step 2."
@@ -23357,14 +23886,14 @@ async function planLocalCacheRetention(root, localCacheDays, now) {
23357
23886
  async function applyContextCompaction(plan) {
23358
23887
  const deleted = [];
23359
23888
  for (const candidate of plan.candidates) {
23360
- await removeRegularFile(candidate.target);
23361
- deleted.push(candidate.target);
23362
23889
  for (const target of candidate.relatedTargets) {
23363
23890
  if (await regularFileExists(target)) {
23364
23891
  await removeRegularFile(target);
23365
23892
  deleted.push(target);
23366
23893
  }
23367
23894
  }
23895
+ await removeRegularFile(candidate.target);
23896
+ deleted.push(candidate.target);
23368
23897
  }
23369
23898
  return { ...plan, deleted };
23370
23899
  }
@@ -23446,6 +23975,7 @@ async function planOperationRetention(stores, now) {
23446
23975
  for (const store of stores) {
23447
23976
  const directory = operationDirectory(store);
23448
23977
  const entries = await readDirectoryOrEmpty(directory);
23978
+ let recoveryEntries = null;
23449
23979
  for (const entry of entries) {
23450
23980
  if (!entry.endsWith(".json")) continue;
23451
23981
  const target = path42.join(directory, entry);
@@ -23462,7 +23992,12 @@ async function planOperationRetention(stores, now) {
23462
23992
  }
23463
23993
  }
23464
23994
  } else if (Date.parse(journal.updatedAt) < threshold) {
23465
- candidates.push(operationRetentionCandidate(store, journal, target));
23995
+ recoveryEntries ??= await readDirectoryOrEmpty(
23996
+ operationRecoveryDirectory(store)
23997
+ );
23998
+ candidates.push(
23999
+ operationRetentionCandidate(store, journal, target, recoveryEntries)
24000
+ );
23466
24001
  }
23467
24002
  }
23468
24003
  }
@@ -23495,15 +24030,38 @@ async function planGitRefWorkflowRepairRetention(projectRoot, now) {
23495
24030
  }
23496
24031
  return { candidates, protectedSessionIds, protectedTaskRefs };
23497
24032
  }
23498
- function operationRetentionCandidate(store, journal, target) {
24033
+ function operationRetentionCandidate(store, journal, target, recoveryEntries) {
24034
+ const relatedTargets = journal.recoveryPayloadDigest === void 0 ? [] : operationRecoveryTargetsForRetention(store, journal, recoveryEntries);
23499
24035
  return {
23500
24036
  kind: "terminal_operation",
23501
24037
  target,
23502
24038
  reason: `${journal.state} operation exceeds ${TERMINAL_JOURNAL_RETENTION_DAYS} day retention`,
23503
24039
  taskRef: null,
23504
- relatedTargets: journal.recoveryPayloadDigest === void 0 ? [] : [operationRecoveryPayloadPath(store, journal.operationId)]
24040
+ relatedTargets
23505
24041
  };
23506
24042
  }
24043
+ function operationRecoveryTargetsForRetention(store, journal, recoveryEntries) {
24044
+ if (journal.recoveryPayloadDigest === void 0) return [];
24045
+ const directory = operationRecoveryDirectory(store);
24046
+ const versionPrefix = `${journal.operationId}.`;
24047
+ const discoveredVersions = recoveryEntries.filter((entry) => {
24048
+ if (!entry.startsWith(versionPrefix)) return false;
24049
+ return /^[a-f0-9]{64}\.json$/.test(entry.slice(versionPrefix.length));
24050
+ }).map((entry) => path42.join(directory, entry));
24051
+ return [
24052
+ .../* @__PURE__ */ new Set([
24053
+ operationRecoveryPayloadPath(store, journal.operationId),
24054
+ operationRecoveryPayloadVersionPath(
24055
+ store,
24056
+ journal.operationId,
24057
+ journal.recoveryPayloadDigest
24058
+ ),
24059
+ ...discoveredVersions
24060
+ ])
24061
+ ].sort(
24062
+ (left, right) => Buffer.from(left, "utf8").compare(Buffer.from(right, "utf8"))
24063
+ );
24064
+ }
23507
24065
  function operationEntityKeys(journal) {
23508
24066
  return [
23509
24067
  ...journal.entityLocks,
@@ -26812,6 +27370,7 @@ function errorCode3(error, fallback) {
26812
27370
  }
26813
27371
 
26814
27372
  // src/commands/init.ts
27373
+ import { randomUUID } from "crypto";
26815
27374
  import { promises as fs4 } from "fs";
26816
27375
  import os from "os";
26817
27376
  import path55 from "path";
@@ -27532,6 +28091,54 @@ function createTerminalPrompter() {
27532
28091
  } finally {
27533
28092
  rl.close();
27534
28093
  }
28094
+ },
28095
+ async resolveUnsafeAdapterPaths({ locale, paths, writeThroughAvailable }) {
28096
+ const rl = createInterface({ input: stdin, output: stdout });
28097
+ try {
28098
+ console.log(
28099
+ locale === "zh-CN" ? "\n\u68C0\u6D4B\u5230\u9002\u914D\u5668\u76EE\u6807\u8DEF\u5F84\u662F\u7B26\u53F7\u94FE\u63A5\uFF1A" : "\nAdapter target paths are symbolic links:"
28100
+ );
28101
+ for (const item of paths) {
28102
+ const detail = item.resolvedTo ? ` -> ${item.resolvedTo}` : "";
28103
+ console.log(` ${item.relative}${detail}`);
28104
+ }
28105
+ console.log(locale === "zh-CN" ? "1. \u9000\u51FA" : "1. Exit");
28106
+ console.log(
28107
+ locale === "zh-CN" ? "2. \u5C06\u7B26\u53F7\u94FE\u63A5\u66FF\u6362\u4E3A\u666E\u901A\u6587\u4EF6\uFF08\u4FDD\u7559\u539F\u5185\u5BB9\uFF09\u5E76\u7EE7\u7EED\u521D\u59CB\u5316" : "2. Replace the symbolic link(s) with regular file(s) (content preserved) and continue"
28108
+ );
28109
+ if (writeThroughAvailable) {
28110
+ console.log(
28111
+ locale === "zh-CN" ? "3. \u4FDD\u7559\u94FE\u63A5\uFF0Cmancode \u76F4\u63A5\u8BFB\u5199\u5176\u89E3\u6790\u76EE\u6807\uFF08CLAUDE.md -> AGENTS.md \u7EA6\u5B9A\uFF09" : "3. Keep the link(s); mancode reads and writes the resolved file (CLAUDE.md -> AGENTS.md convention)"
28112
+ );
28113
+ }
28114
+ const answer = (await rl.question(
28115
+ locale === "zh-CN" ? `\u9009\u62E9 [1/${writeThroughAvailable ? "2/3" : "2"}]: ` : `Choose [1/${writeThroughAvailable ? "2/3" : "2"}]: `
28116
+ )).trim().toLowerCase();
28117
+ if (answer === "2") return "replace";
28118
+ if (answer === "3" && writeThroughAvailable) return "write-through";
28119
+ return "exit";
28120
+ } finally {
28121
+ rl.close();
28122
+ }
28123
+ },
28124
+ async resolveScratchMancodeTarget({ locale, entries }) {
28125
+ const rl = createInterface({ input: stdin, output: stdout });
28126
+ try {
28127
+ console.log(
28128
+ locale === "zh-CN" ? "\n`.mancode` \u5DF2\u5B58\u5728\uFF0C\u4F46\u53EA\u5305\u542B\u975E Continuity \u7684\u672C\u5730\u8349\u7A3F\uFF08\u53D1\u5E03\u5DE5\u4EF6\u3001\u5176\u4ED6\u5DE5\u5177\u5907\u4EFD\uFF09\uFF1A" : "\n`.mancode` exists but contains only non-Continuity local scratch (release artifacts, other-tool backups):"
28129
+ );
28130
+ for (const entry of entries) console.log(` .mancode/${entry}`);
28131
+ console.log(locale === "zh-CN" ? "1. \u9000\u51FA" : "1. Exit");
28132
+ console.log(
28133
+ locale === "zh-CN" ? "2. \u628A `.mancode` \u79FB\u5230\u4E00\u8FB9\uFF08\u5185\u5BB9\u4FDD\u7559\uFF09\u5E76\u7EE7\u7EED\u521D\u59CB\u5316\uFF1B\u6210\u529F\u540E\u539F\u6837\u5F52\u4F4D\u5230 `.mancode/local/`" : "2. Move `.mancode` aside (content preserved) and continue; it is restored under `.mancode/local/` after success"
28134
+ );
28135
+ const answer = (await rl.question(
28136
+ locale === "zh-CN" ? "\u9009\u62E9 [1/2]: " : "Choose [1/2]: "
28137
+ )).trim().toLowerCase();
28138
+ return answer === "2" ? "relocate" : "exit";
28139
+ } finally {
28140
+ rl.close();
28141
+ }
27535
28142
  }
27536
28143
  };
27537
28144
  }
@@ -28449,12 +29056,12 @@ function parseAdapterPlans(value) {
28449
29056
  assertRecord(candidate, "greenfield initialization adapter plan");
28450
29057
  assertKnownKeys(
28451
29058
  candidate,
28452
- ["target", "beforeContent", "targetContent"],
29059
+ ["target", "beforeContent", "targetContent", "resolvedTarget"],
28453
29060
  "greenfield initialization adapter plan"
28454
29061
  );
28455
29062
  if (typeof candidate.target !== "string" || !V3_ADAPTER_FILE_TARGETS.includes(
28456
29063
  candidate.target
28457
- ) || seen.has(candidate.target) || candidate.beforeContent !== null && typeof candidate.beforeContent !== "string" || typeof candidate.targetContent !== "string" || !candidate.targetContent.trim()) {
29064
+ ) || seen.has(candidate.target) || candidate.beforeContent !== null && typeof candidate.beforeContent !== "string" || typeof candidate.targetContent !== "string" || !candidate.targetContent.trim() || candidate.resolvedTarget !== void 0 && (typeof candidate.resolvedTarget !== "string" || !candidate.resolvedTarget.trim() || path54.isAbsolute(candidate.resolvedTarget) || candidate.resolvedTarget.split(/[\\/]/).includes(".."))) {
28458
29065
  throw new Error(
28459
29066
  "greenfield initialization journal adapterPlans is invalid"
28460
29067
  );
@@ -28464,7 +29071,8 @@ function parseAdapterPlans(value) {
28464
29071
  return {
28465
29072
  target,
28466
29073
  beforeContent: candidate.beforeContent,
28467
- targetContent: candidate.targetContent
29074
+ targetContent: candidate.targetContent,
29075
+ resolvedTarget: candidate.resolvedTarget
28468
29076
  };
28469
29077
  });
28470
29078
  }
@@ -29138,7 +29746,16 @@ async function initializeV3(rootDir, options) {
29138
29746
  console.error(" Use one or more supported platform names, or all.");
29139
29747
  return EXIT_INIT_FAILED;
29140
29748
  }
29749
+ let scratchBackup = null;
29141
29750
  try {
29751
+ if (!existingV3) {
29752
+ const unsafeExit = await resolveUnsafeInitAdapterPaths(
29753
+ rootDir,
29754
+ options,
29755
+ selectedPlatforms
29756
+ );
29757
+ if (unsafeExit !== null) return unsafeExit;
29758
+ }
29142
29759
  if (existingV3 && selectedPlatforms.some((platform) => !registeredAdapters.has(platform))) {
29143
29760
  throw new Error(
29144
29761
  "MANCODE_ADAPTER_REGISTRATION_REQUIRED: run `mancode adapter upgrade --platform <platform> --dry-run`, then confirm that operation with an active session."
@@ -29161,6 +29778,9 @@ async function initializeV3(rootDir, options) {
29161
29778
  console.log("\u2139\uFE0F mancode is already initialized.");
29162
29779
  return EXIT_ALREADY_INITIALIZED;
29163
29780
  }
29781
+ const scratch = await resolveScratchMancodeTarget(rootDir, options);
29782
+ if (scratch.exit !== null) return scratch.exit;
29783
+ scratchBackup = scratch.backupPath;
29164
29784
  const result2 = await initializeV3Project({
29165
29785
  projectRoot: rootDir,
29166
29786
  managedAdapters: Object.fromEntries(
@@ -29171,6 +29791,9 @@ async function initializeV3(rootDir, options) {
29171
29791
  console.log("\u2713 Initialized mancode project.");
29172
29792
  console.log(` workspace: ${result2.runtime.workspaceId}`);
29173
29793
  console.log(` operation: ${result2.journal.operationId}`);
29794
+ if (scratchBackup !== null) {
29795
+ await restoreScratchBackup(rootDir, scratchBackup);
29796
+ }
29174
29797
  if (options.team !== void 0) {
29175
29798
  console.log(
29176
29799
  ` team policy: ${options.team ? "on (--team)" : "off (--no-team)"}`
@@ -29185,16 +29808,157 @@ async function initializeV3(rootDir, options) {
29185
29808
  }
29186
29809
  return EXIT_OK2;
29187
29810
  } catch (error) {
29811
+ if (scratchBackup !== null) {
29812
+ console.error(
29813
+ ` Previous .mancode scratch was preserved at ${path55.relative(rootDir, scratchBackup)}.`
29814
+ );
29815
+ }
29188
29816
  printV3InitError(error);
29189
29817
  return EXIT_INIT_FAILED;
29190
29818
  }
29191
29819
  }
29820
+ async function resolveUnsafeInitAdapterPaths(rootDir, options, selectedPlatforms) {
29821
+ const prompter = options.prompter ?? (options.interactive ? createTerminalPrompter() : null);
29822
+ if (!prompter) return null;
29823
+ const locale = detectInitLocale(options.lang) ?? "en";
29824
+ const found = [];
29825
+ const seen = /* @__PURE__ */ new Set();
29826
+ for (const platform of selectedPlatforms) {
29827
+ for (const entry of await inspectUnsafeV3AdapterPaths(rootDir, platform)) {
29828
+ if (seen.has(entry.target)) continue;
29829
+ seen.add(entry.target);
29830
+ found.push(entry);
29831
+ }
29832
+ }
29833
+ const fixable = found.filter(
29834
+ (entry) => entry.kind === "symlink" && entry.finalTarget
29835
+ );
29836
+ if (fixable.length === 0) return null;
29837
+ const writeThroughAvailable = found.length > 0 && (await Promise.all(
29838
+ found.map(
29839
+ (entry) => writeThroughResolvedPath(path55.resolve(rootDir), entry.target)
29840
+ )
29841
+ )).every((resolved) => resolved !== null);
29842
+ const choice = await prompter.resolveUnsafeAdapterPaths({
29843
+ locale,
29844
+ paths: found.map(({ relative, resolvedTo }) => ({ relative, resolvedTo })),
29845
+ writeThroughAvailable
29846
+ });
29847
+ if (choice === "exit") {
29848
+ console.log(
29849
+ locale === "zh-CN" ? "\u5DF2\u53D6\u6D88\u521D\u59CB\u5316\u3002" : "Initialization cancelled."
29850
+ );
29851
+ return EXIT_USER_CANCEL;
29852
+ }
29853
+ if (choice === "write-through") {
29854
+ console.log(
29855
+ locale === "zh-CN" ? "\u2139\uFE0F \u4FDD\u7559\u7B26\u53F7\u94FE\u63A5\uFF0Cmancode \u5C06\u8BFB\u5199\u5176\u89E3\u6790\u76EE\u6807\u3002" : "\u2139\uFE0F Keeping the symbolic link(s); mancode reads and writes the resolved target."
29856
+ );
29857
+ return null;
29858
+ }
29859
+ await replaceUnsafeV3AdapterSymlinks(fixable);
29860
+ return null;
29861
+ }
29862
+ var SCRATCH_BACKUP_PREFIX = ".mancode.preinit-scratch-";
29863
+ async function resolveScratchMancodeTarget(rootDir, options) {
29864
+ const inspection = await inspectMancodeLayout(rootDir);
29865
+ if (!inspection.v3ScratchOnly) {
29866
+ return { exit: null, backupPath: null };
29867
+ }
29868
+ const mancodeRoot = path55.join(rootDir, ".mancode");
29869
+ if (inspection.v3TargetEntries.length === 0) {
29870
+ await fs4.rmdir(mancodeRoot);
29871
+ console.log(
29872
+ "\u2139\uFE0F Removed an empty .mancode directory before initialization."
29873
+ );
29874
+ return { exit: null, backupPath: null };
29875
+ }
29876
+ const prompter = options.prompter ?? (options.interactive ? createTerminalPrompter() : null);
29877
+ if (!prompter) {
29878
+ throw new Error("MANCODE_V3_SCRATCH_TARGET_REQUIRES_CHOICE");
29879
+ }
29880
+ const locale = detectInitLocale(options.lang) ?? "en";
29881
+ const choice = prompter.resolveScratchMancodeTarget ? await prompter.resolveScratchMancodeTarget({
29882
+ locale,
29883
+ entries: inspection.v3TargetEntries
29884
+ }) : "exit";
29885
+ if (choice !== "relocate") {
29886
+ console.log(
29887
+ locale === "zh-CN" ? "\u5DF2\u53D6\u6D88\u521D\u59CB\u5316\u3002" : "Initialization cancelled."
29888
+ );
29889
+ return { exit: EXIT_USER_CANCEL, backupPath: null };
29890
+ }
29891
+ const backupPath = path55.join(
29892
+ rootDir,
29893
+ `${SCRATCH_BACKUP_PREFIX}${randomUUID()}`
29894
+ );
29895
+ await fs4.rename(mancodeRoot, backupPath);
29896
+ console.log(
29897
+ `\u2139\uFE0F Moved non-Continuity .mancode scratch aside: ${path55.relative(rootDir, backupPath)}`
29898
+ );
29899
+ return { exit: null, backupPath };
29900
+ }
29901
+ async function restoreScratchBackup(rootDir, backupPath) {
29902
+ const localTarget = path55.join(rootDir, ".mancode", "local");
29903
+ const leftover = path55.relative(rootDir, backupPath);
29904
+ try {
29905
+ await fs4.mkdir(localTarget, { recursive: true });
29906
+ const entries = await fs4.readdir(backupPath, { withFileTypes: true });
29907
+ for (const entry of entries) {
29908
+ const source = path55.join(backupPath, entry.name);
29909
+ if (entry.isDirectory() && entry.name === "local") {
29910
+ for (const child of await fs4.readdir(source)) {
29911
+ const destination = path55.join(localTarget, child);
29912
+ if (await pathExists6(destination)) continue;
29913
+ await fs4.rename(path55.join(source, child), destination);
29914
+ }
29915
+ } else {
29916
+ const preinitScratch = path55.join(localTarget, "preinit-scratch");
29917
+ await fs4.mkdir(preinitScratch, { recursive: true });
29918
+ const destination = path55.join(preinitScratch, entry.name);
29919
+ if (await pathExists6(destination)) continue;
29920
+ await fs4.rename(source, destination);
29921
+ }
29922
+ }
29923
+ await fs4.rmdir(path55.join(backupPath, "local")).catch(() => void 0);
29924
+ await fs4.rmdir(backupPath).catch(() => void 0);
29925
+ if (await pathExists6(backupPath)) {
29926
+ console.warn(
29927
+ `\u26A0\uFE0F Could not fully restore previous scratch; it remains at ${leftover}.`
29928
+ );
29929
+ } else {
29930
+ console.log(
29931
+ "\u2139\uFE0F Restored previous .mancode scratch into .mancode/local/."
29932
+ );
29933
+ }
29934
+ } catch {
29935
+ console.warn(
29936
+ `\u26A0\uFE0F Failed to restore previous .mancode scratch; it remains at ${leftover}.`
29937
+ );
29938
+ }
29939
+ }
29192
29940
  function printV3InitError(error) {
29193
29941
  const message = error instanceof Error ? error.message : "mancode initialization failed";
29194
29942
  console.error(`\u2717 ${message}`);
29195
29943
  if (message === "MANCODE_LEGACY_AUTHORITY_PRESENT") {
29196
29944
  console.error(" Run `mancode migrate context --dry-run` instead.");
29197
29945
  }
29946
+ if (message === "MANCODE_V3_TARGET_EXISTS") {
29947
+ console.error(
29948
+ " `.mancode` already exists with Continuity authority content; refusing to overwrite it."
29949
+ );
29950
+ console.error(
29951
+ " For an initialized project, use `mancode adapter status` / `mancode adapter upgrade`; otherwise inspect `.mancode` first."
29952
+ );
29953
+ }
29954
+ if (message === "MANCODE_V3_SCRATCH_TARGET_REQUIRES_CHOICE") {
29955
+ console.error(
29956
+ " `.mancode` holds only non-Continuity scratch (release artifacts, other-tool backups)."
29957
+ );
29958
+ console.error(
29959
+ " Run init interactively to move it aside, or remove/rename the directory yourself."
29960
+ );
29961
+ }
29198
29962
  }
29199
29963
  async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms) {
29200
29964
  const configPath = path55.join(mancodeDir, "config.json");
@@ -29318,15 +30082,17 @@ async function validateV3CliProjectBoundary(rootDir, options, locale, legacyInit
29318
30082
  const isGitRepo = await pathExists6(path55.join(rootDir, ".git"));
29319
30083
  const hasEvidence = await hasProjectEvidence(rootDir);
29320
30084
  if (isGitRepo || hasEvidence) return null;
29321
- const v3Initialized = await pathExists6(
29322
- path55.join(rootDir, ".mancode", "schema.json")
29323
- );
29324
- const legacyAuthorityPresent = legacyInitialized || (await scanLegacyAuthority(rootDir)).authorityPresent;
29325
- if (!genericSafety.ok && !((legacyAuthorityPresent || v3Initialized) && genericSafety.reason === "nonempty")) {
30085
+ const inspection = await inspectMancodeLayout(rootDir);
30086
+ const v3Initialized = inspection.v3AuthorityPathsPresent.includes("schema.json");
30087
+ const legacyAuthorityPresent = legacyInitialized || inspection.legacy.authorityPresent;
30088
+ const scratchOnlyMancode = inspection.v3ScratchOnly;
30089
+ if (!genericSafety.ok && !((legacyAuthorityPresent || v3Initialized || scratchOnlyMancode) && genericSafety.reason === "nonempty")) {
29326
30090
  printNotProjectDirectory(rootDir, locale, genericSafety.reason);
29327
30091
  return EXIT_NOT_A_PROJECT_DIR;
29328
30092
  }
29329
- if (legacyAuthorityPresent || v3Initialized) return null;
30093
+ if (legacyAuthorityPresent || v3Initialized || scratchOnlyMancode) {
30094
+ return null;
30095
+ }
29330
30096
  const prompter = options.prompter ?? (options.interactive ? createTerminalPrompter() : null);
29331
30097
  const confirmed = options.empty || options.yes ? true : prompter ? await prompter.confirmGenericProject({ rootDir, locale }) : false;
29332
30098
  if (!confirmed) {
@@ -31243,8 +32009,19 @@ async function runOperationMutation(rootDir, operationId, options, mode) {
31243
32009
  EXIT_V3_INVALID_ARGUMENT
31244
32010
  );
31245
32011
  }
32012
+ if (options.replacementCheckpointId !== void 0 && !isUlid(options.replacementCheckpointId)) {
32013
+ return printV3Error(
32014
+ options.json,
32015
+ "MANCODE_REPLACEMENT_CHECKPOINT_ID_INVALID",
32016
+ "replacement checkpoint ID must be a canonical ULID.",
32017
+ EXIT_V3_INVALID_ARGUMENT
32018
+ );
32019
+ }
31246
32020
  try {
31247
32021
  assertUlid(operationId, "operationId");
32022
+ if (options.replacementCheckpointId !== void 0) {
32023
+ assertUlid(options.replacementCheckpointId, "replacementCheckpointId");
32024
+ }
31248
32025
  const project = await readV3CommandProject(rootDir);
31249
32026
  const session = await resolveV3CommandSession(project, options);
31250
32027
  const result2 = await executeOperationRecovery({
@@ -31252,7 +32029,8 @@ async function runOperationMutation(rootDir, operationId, options, mode) {
31252
32029
  operationId,
31253
32030
  actorId: session.actorId,
31254
32031
  sessionId: session.sessionId,
31255
- mode
32032
+ mode,
32033
+ replacementCheckpointId: options.replacementCheckpointId
31256
32034
  });
31257
32035
  return printV3Result(options.json, { schemaVersion: 1, ...result2 });
31258
32036
  } catch (error) {
@@ -31804,7 +32582,7 @@ async function projectUpgrade(rootDir, options) {
31804
32582
  }
31805
32583
 
31806
32584
  // src/commands/refresh-project.ts
31807
- import { randomUUID } from "crypto";
32585
+ import { randomUUID as randomUUID2 } from "crypto";
31808
32586
  import { promises as fs7 } from "fs";
31809
32587
  import path62 from "path";
31810
32588
  import process9 from "process";
@@ -31980,7 +32758,7 @@ async function readOptionalText(filePath) {
31980
32758
  function temporaryPath(filePath) {
31981
32759
  return path62.join(
31982
32760
  path62.dirname(filePath),
31983
- `.${path62.basename(filePath)}.${process9.pid}.${randomUUID()}.tmp`
32761
+ `.${path62.basename(filePath)}.${process9.pid}.${randomUUID2()}.tmp`
31984
32762
  );
31985
32763
  }
31986
32764
  async function refreshStaticPlatforms(rootDir, config, fallbackPlatform, stack, uiLibrary, profile) {
@@ -41784,7 +42562,8 @@ var WORKFLOW_SUBCOMMANDS = [
41784
42562
  "checkpoint",
41785
42563
  "child",
41786
42564
  "promote",
41787
- "handoff"
42565
+ "handoff",
42566
+ "delivery"
41788
42567
  ];
41789
42568
  var WORKFLOW_SUBCOMMAND_SET = new Set(
41790
42569
  WORKFLOW_SUBCOMMANDS
@@ -41792,8 +42571,8 @@ var WORKFLOW_SUBCOMMAND_SET = new Set(
41792
42571
  var CONTINUITY_COMPATIBILITY_SUBCOMMANDS = /* @__PURE__ */ new Set(["clean"]);
41793
42572
 
41794
42573
  // src/commands/workflow.ts
41795
- import { access as access6, readFile as readFile48, rm as rm24, writeFile as writeFile51 } from "fs/promises";
41796
- import path70 from "path";
42574
+ import { access as access6, readFile as readFile51, rm as rm26, writeFile as writeFile53 } from "fs/promises";
42575
+ import path74 from "path";
41797
42576
 
41798
42577
  // src/context/child-result-merge.ts
41799
42578
  async function mergeV3ChildResult(input) {
@@ -42121,8 +42900,746 @@ function assertPositiveRevision6(value, label) {
42121
42900
  }
42122
42901
  }
42123
42902
 
42903
+ // src/context/man-delivery-runtime.ts
42904
+ import { execFile as execFileCallback7 } from "child_process";
42905
+ import { createHash as createHash11, randomUUID as randomUUID4 } from "crypto";
42906
+ import {
42907
+ lstat as lstat28,
42908
+ readFile as readFile48,
42909
+ readlink as readlink2,
42910
+ realpath as realpath4,
42911
+ rm as rm24,
42912
+ writeFile as writeFile51
42913
+ } from "fs/promises";
42914
+ import path71 from "path";
42915
+ import { promisify as promisify9 } from "util";
42916
+
42917
+ // src/context/man-delivery-plan.ts
42918
+ import path69 from "path";
42919
+ var SOURCE_PREFIX = "<!-- mancode:delivery-plan ";
42920
+ var MARKERS = [
42921
+ "<!-- mancode:plan-baseline:start -->",
42922
+ "<!-- mancode:plan-baseline:end -->",
42923
+ "<!-- mancode:delivery-record:start -->",
42924
+ "<!-- mancode:delivery-record:end -->"
42925
+ ];
42926
+ function parseManPlanDocument(document) {
42927
+ const markers = unfencedLines(document).filter(
42928
+ (line) => MARKERS.includes(line.marker)
42929
+ );
42930
+ if (markers.length !== 4 || markers.some((value, index) => value.marker !== MARKERS[index])) {
42931
+ throw new Error("MANCODE_MAN_PLAN_MARKERS_INVALID");
42932
+ }
42933
+ const [baselineStart, baselineEnd, recordStart, recordEnd] = markers;
42934
+ if (!baselineStart || !baselineEnd || !recordStart || !recordEnd) {
42935
+ throw new Error("MANCODE_MAN_PLAN_MARKERS_INVALID");
42936
+ }
42937
+ const baseline = document.slice(baselineStart.end, baselineEnd.start).trim();
42938
+ if (!baseline) throw new Error("MANCODE_MAN_PLAN_BASELINE_REQUIRED");
42939
+ return {
42940
+ baseline,
42941
+ record: document.slice(recordStart.end, recordEnd.start).trim(),
42942
+ recordStart: recordStart.end,
42943
+ recordEnd: recordEnd.start
42944
+ };
42945
+ }
42946
+ function manProgressTaskId(baseline) {
42947
+ const bindings = unfencedLines(baseline).map(
42948
+ (line) => /^<!-- mancode:progress-task ([a-zA-Z0-9:_-]+) -->$/.exec(
42949
+ line.marker
42950
+ )?.[1]
42951
+ ).filter((id) => id !== void 0);
42952
+ if (bindings.length > 1)
42953
+ throw new Error("ambiguous plan progress task binding");
42954
+ return bindings[0] ?? null;
42955
+ }
42956
+ function unfencedLines(document) {
42957
+ let offset = 0;
42958
+ let fence = null;
42959
+ const markers = [];
42960
+ for (const line of document.match(/[^\n]*(?:\n|$)/g) ?? []) {
42961
+ const text = line.replace(/\r?\n$/, "");
42962
+ const delimiter = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(text);
42963
+ if (fence !== null) {
42964
+ if (delimiter && delimiter[1]?.[0] === fence.character && delimiter[1].length >= fence.length && delimiter[2]?.trim() === "")
42965
+ fence = null;
42966
+ } else if (delimiter?.[1]) {
42967
+ fence = {
42968
+ character: delimiter[1][0],
42969
+ length: delimiter[1].length
42970
+ };
42971
+ } else {
42972
+ markers.push({ marker: text, start: offset, end: offset + line.length });
42973
+ }
42974
+ offset += line.length;
42975
+ }
42976
+ return markers;
42977
+ }
42978
+ function replaceManDeliveryRecord(document, record) {
42979
+ const parsed = parseManPlanDocument(document);
42980
+ const next = `${document.slice(0, parsed.recordStart)}${record.trim()}
42981
+ ${document.slice(parsed.recordEnd)}`;
42982
+ const checked = parseManPlanDocument(next);
42983
+ if (checked.baseline !== parsed.baseline)
42984
+ throw new Error("MANCODE_MAN_PLAN_BASELINE_CHANGED");
42985
+ return next;
42986
+ }
42987
+ function assertManPlanPath(file) {
42988
+ if (!file || path69.posix.isAbsolute(file) || /[\\\r\n\0<>:]/.test(file) || file.split("/").some((part) => !part || part === "." || part === "..") || /^(?:\.git|\.mancode|架构|项目接口)(?:\/|$)/.test(file) || !file.endsWith(".md") || !file.includes("/"))
42989
+ throw new Error("MANCODE_MAN_PLAN_PATH_INVALID");
42990
+ }
42991
+ function parseSource(value) {
42992
+ assertRecord(value, "man plan source");
42993
+ assertKnownKeys(value, ["version", "path", "baseHead"], "man plan source");
42994
+ if (value.version !== 1 || typeof value.path !== "string") {
42995
+ throw new Error("MANCODE_MAN_PLAN_SOURCE_INVALID");
42996
+ }
42997
+ assertManPlanPath(value.path);
42998
+ if (value.baseHead !== null && (typeof value.baseHead !== "string" || !/^[a-f0-9]{40,64}$/.test(value.baseHead))) {
42999
+ throw new Error("MANCODE_MAN_PLAN_BASE_INVALID");
43000
+ }
43001
+ return { version: 1, path: value.path, baseHead: value.baseHead };
43002
+ }
43003
+ function compileManDeliveryPlan(source, document) {
43004
+ return `${SOURCE_PREFIX}${JSON.stringify(parseSource(source))} -->
43005
+ ${parseManPlanDocument(document).baseline}`;
43006
+ }
43007
+ function parseManDeliveryPlan(plan) {
43008
+ if (!plan.startsWith(SOURCE_PREFIX)) return null;
43009
+ const end = plan.indexOf(" -->\n");
43010
+ if (end < 0) throw new Error("MANCODE_MAN_PLAN_SOURCE_INVALID");
43011
+ const source = parseSource(JSON.parse(plan.slice(SOURCE_PREFIX.length, end)));
43012
+ const baseline = plan.slice(end + " -->\n".length);
43013
+ if (!baseline.trim()) throw new Error("MANCODE_MAN_PLAN_BASELINE_REQUIRED");
43014
+ return { source, baseline };
43015
+ }
43016
+
43017
+ // src/context/man-progress.ts
43018
+ import { randomUUID as randomUUID3 } from "crypto";
43019
+ import { lstat as lstat27, readFile as readFile47, realpath as realpath3, rm as rm23, writeFile as writeFile50 } from "fs/promises";
43020
+ import path70 from "path";
43021
+ var START = '<script type="application/json" id="mancode-progress-data">';
43022
+ var END = "</script>";
43023
+ function updateManProgressHtml(html, taskId, status2, reason) {
43024
+ if (html.split(START).length !== 2 || [...html.matchAll(/\bid\s*=\s*["']mancode-progress-data["']/gi)].length !== 1)
43025
+ throw new Error("progress data block is missing or ambiguous");
43026
+ const tokens = [
43027
+ ...html.matchAll(
43028
+ /<!--[\s\S]*?-->|<(script|style|textarea|title|xmp|iframe|noembed|noframes|noscript)\b(?:[^"'<>]|"[^"]*"|'[^']*')*>[\s\S]*?<\/\1\s*>|<(?:[^"'<>]|"[^"]*"|'[^']*')*>/gi
43029
+ )
43030
+ ];
43031
+ if (!tokens.some(
43032
+ (token) => token.index === html.indexOf(START) && token[0].startsWith(START)
43033
+ ))
43034
+ throw new Error("progress data must be an active standalone script block");
43035
+ const start = html.indexOf(START) + START.length;
43036
+ const end = html.indexOf(END, start);
43037
+ if (end < start) throw new Error("progress data block is unterminated");
43038
+ const data = JSON.parse(html.slice(start, end));
43039
+ if (!data || typeof data !== "object" || !("schemaVersion" in data) || data.schemaVersion !== 1 || !("tasks" in data) || !Array.isArray(data.tasks))
43040
+ throw new Error("unsupported progress data");
43041
+ const matches = data.tasks.filter(
43042
+ (item) => item && typeof item === "object" && item.taskId === taskId
43043
+ );
43044
+ if (matches.length !== 1)
43045
+ throw new Error("progress taskId is missing or ambiguous");
43046
+ Object.assign(matches[0], { status: status2, reason });
43047
+ return `${html.slice(0, start)}
43048
+ ${JSON.stringify(data).replaceAll("<", "\\u003c")}
43049
+ ${html.slice(end)}`;
43050
+ }
43051
+ async function syncManProgressPage(root, taskId, status2, reason, allowed) {
43052
+ const target = path70.join(root, "\u9879\u76EE\u8FDB\u5EA6.html");
43053
+ let temporary;
43054
+ try {
43055
+ const stat5 = await lstat27(target);
43056
+ if (!allowed)
43057
+ return {
43058
+ status: "manual_sync",
43059
+ reason: "progress page is outside the approved write scope"
43060
+ };
43061
+ if (!stat5.isFile() || await realpath3(target) !== path70.join(await realpath3(root), "\u9879\u76EE\u8FDB\u5EA6.html"))
43062
+ return {
43063
+ status: "manual_sync",
43064
+ reason: "progress page must be a regular project file"
43065
+ };
43066
+ const previous = await readFile47(target, "utf8");
43067
+ const next = updateManProgressHtml(previous, taskId, status2, reason);
43068
+ if (next !== previous) {
43069
+ temporary = `${target}.${randomUUID3()}.tmp`;
43070
+ await writeFile50(temporary, next, { flag: "wx", mode: stat5.mode });
43071
+ if (await readFile47(target, "utf8") !== previous)
43072
+ throw new Error("progress page changed during sync");
43073
+ await replaceFileAtomically(temporary, target);
43074
+ }
43075
+ return { status: "synced" };
43076
+ } catch (error) {
43077
+ if (error.code === "ENOENT" && !temporary)
43078
+ return { status: "absent" };
43079
+ return {
43080
+ status: "manual_sync",
43081
+ reason: error instanceof Error ? error.message : String(error)
43082
+ };
43083
+ } finally {
43084
+ if (temporary) await rm23(temporary, { force: true });
43085
+ }
43086
+ }
43087
+
43088
+ // src/context/man-delivery-runtime.ts
43089
+ var execFile10 = promisify9(execFileCallback7);
43090
+ var MAN_DELIVERY_POLICY = 3;
43091
+ function isManDelivery(metadata) {
43092
+ return metadata.workflowMode === "man" && metadata.governance.policyVersions.planning === MAN_DELIVERY_POLICY && metadata.governance.planDecision !== "solo_handoff";
43093
+ }
43094
+ async function manGit(root, args) {
43095
+ return (await execFile10("git", args, {
43096
+ cwd: root,
43097
+ encoding: "utf8",
43098
+ maxBuffer: 16 * 1024 * 1024
43099
+ })).stdout;
43100
+ }
43101
+ async function hasGitWorktree(root) {
43102
+ try {
43103
+ return (await manGit(root, ["rev-parse", "--is-inside-work-tree"])).trim() === "true";
43104
+ } catch (error) {
43105
+ if (error.code === 128 && String(error.stderr).includes(
43106
+ "not a git repository"
43107
+ ))
43108
+ return false;
43109
+ throw error;
43110
+ }
43111
+ }
43112
+ async function readManPlanFile(root, file) {
43113
+ assertManPlanPath(file);
43114
+ const resolvedRoot = await realpath4(root);
43115
+ const resolved = await realpath4(path71.join(root, file));
43116
+ const relative = path71.relative(resolvedRoot, resolved).split(path71.sep).join("/");
43117
+ assertManPlanPath(relative);
43118
+ if (relative !== file) throw new Error("MANCODE_MAN_PLAN_USE_REAL_PATH");
43119
+ if (!(await lstat28(resolved)).isFile())
43120
+ throw new Error("MANCODE_MAN_PLAN_FILE_REQUIRED");
43121
+ if (!await hasGitWorktree(root)) return readFile48(resolved, "utf8");
43122
+ try {
43123
+ await manGit(root, ["check-ignore", "--no-index", "-q", "--", relative]);
43124
+ } catch (error) {
43125
+ if (error.code === 1)
43126
+ return readFile48(resolved, "utf8");
43127
+ throw error;
43128
+ }
43129
+ throw new Error("MANCODE_MAN_PLAN_IGNORED");
43130
+ }
43131
+ async function bindManPlan(root, file, document, previous) {
43132
+ if (await readManPlanFile(root, file) !== document)
43133
+ throw new Error("MANCODE_MAN_PLAN_FILE_CHANGED");
43134
+ const existing = previous === null ? null : parseManDeliveryPlan(previous);
43135
+ return compileManDeliveryPlan(
43136
+ {
43137
+ version: 1,
43138
+ path: file,
43139
+ baseHead: existing ? existing.source.baseHead : await readCheckoutCodeHead(root)
43140
+ },
43141
+ document
43142
+ );
43143
+ }
43144
+ async function readBoundManPlan(root, task) {
43145
+ const plan = task.plan && parseManDeliveryPlan(task.plan.content);
43146
+ if (!plan) throw new Error("MANCODE_MAN_PLAN_SOURCE_REQUIRED");
43147
+ const document = await readManPlanFile(root, plan.source.path);
43148
+ if (parseManPlanDocument(document).baseline !== plan.baseline)
43149
+ throw new Error("MANCODE_MAN_PLAN_BASELINE_CHANGED");
43150
+ return { ...plan, document };
43151
+ }
43152
+ async function captureManSubject(root, task) {
43153
+ const bound = await readBoundManPlan(root, task);
43154
+ if (!await hasGitWorktree(root))
43155
+ throw new Error(
43156
+ "MANCODE_MAN_DELIVERY_GIT_REQUIRED: planning is available; versioned delivery is not"
43157
+ );
43158
+ const files = [
43159
+ ...new Set(
43160
+ (await manGit(root, [
43161
+ "ls-files",
43162
+ "-z",
43163
+ "--cached",
43164
+ "--others",
43165
+ "--exclude-standard"
43166
+ ])).split("\0").filter(Boolean)
43167
+ )
43168
+ ].sort();
43169
+ const hashes = [];
43170
+ for (const file of files) {
43171
+ if (file.startsWith(".mancode/") || file === "\u9879\u76EE\u8FDB\u5EA6.html") continue;
43172
+ const absolute = path71.join(root, file);
43173
+ let contents;
43174
+ let kind = "deleted";
43175
+ try {
43176
+ const stat5 = await lstat28(absolute);
43177
+ kind = `file:${stat5.mode & 73}`;
43178
+ if (stat5.isSymbolicLink()) {
43179
+ kind = "symlink";
43180
+ const target = path71.relative(
43181
+ await realpath4(root),
43182
+ await realpath4(absolute)
43183
+ );
43184
+ if (target.startsWith(`..${path71.sep}`) || path71.isAbsolute(target))
43185
+ throw new Error("MANCODE_MAN_EXTERNAL_DEPENDENCY_UNVERIFIED");
43186
+ contents = `${await readlink2(absolute)}\0${await readFile48(absolute, "base64")}`;
43187
+ } else if (stat5.isFile()) {
43188
+ contents = file === bound.source.path ? bound.baseline : await readFile48(absolute);
43189
+ } else throw new Error("MANCODE_MAN_CONTENT_NODE_UNSUPPORTED");
43190
+ } catch (error) {
43191
+ if (error.code !== "ENOENT") throw error;
43192
+ kind = "deleted";
43193
+ contents = "<deleted>";
43194
+ }
43195
+ hashes.push([
43196
+ file,
43197
+ createHash11("sha256").update(`${kind}\0`).update(contents).digest("hex")
43198
+ ]);
43199
+ }
43200
+ return {
43201
+ contentDigest: digestCanonicalJson(hashes),
43202
+ environment: `${process.platform}/${process.arch};node=${process.version}`
43203
+ };
43204
+ }
43205
+ function assertManReviewCoverage(task, review, subject) {
43206
+ if (!isManDelivery(task.metadata)) {
43207
+ if (review.delivery) throw new Error("MANCODE_MAN_DELIVERY_MODE_REQUIRED");
43208
+ return;
43209
+ }
43210
+ for (const blocker of task.review.blockers.filter(
43211
+ (item) => item.status === "open"
43212
+ )) {
43213
+ if (!review.blockers.some((item) => item.blockerId === blocker.blockerId))
43214
+ throw new Error(
43215
+ `MANCODE_MAN_REVIEW_FINDING_DROPPED: ${blocker.displayId}`
43216
+ );
43217
+ }
43218
+ if (review.status === "skipped") return;
43219
+ if (!review.delivery && review.status !== "passed") return;
43220
+ if (!review.delivery || review.delivery.subject.contentDigest !== subject.contentDigest || review.delivery.subject.environment !== subject.environment) {
43221
+ throw new Error("MANCODE_MAN_REVIEW_SUBJECT_STALE");
43222
+ }
43223
+ const criteria = task.requirements.acceptanceCriteria;
43224
+ if (review.delivery.coverage.some(
43225
+ (row) => !criteria.some((criterion) => criterion.displayId === row.acceptanceId)
43226
+ ))
43227
+ throw new Error("MANCODE_MAN_REVIEW_UNKNOWN_ACCEPTANCE");
43228
+ if (review.status !== "passed") return;
43229
+ for (const criterion of criteria.filter((item) => item.required)) {
43230
+ if (!review.delivery.coverage.some(
43231
+ (row) => row.acceptanceId === criterion.displayId && row.status === "met"
43232
+ )) {
43233
+ throw new Error(
43234
+ `MANCODE_MAN_REVIEW_ACCEPTANCE_MISSING: ${criterion.displayId}`
43235
+ );
43236
+ }
43237
+ }
43238
+ }
43239
+ function assertManVerificationSubjects(task, verification, subject) {
43240
+ for (const check of verification.checks) {
43241
+ for (const evidence of [check.automated, check.manual]) {
43242
+ if (!isManDelivery(task.metadata)) {
43243
+ if (evidence?.subject)
43244
+ throw new Error("MANCODE_MAN_DELIVERY_MODE_REQUIRED");
43245
+ } else if (evidence?.status === "passed" && (evidence.subject?.contentDigest !== subject.contentDigest || evidence.subject.environment !== subject.environment)) {
43246
+ throw new Error(
43247
+ `MANCODE_MAN_VERIFICATION_SUBJECT_STALE: ${check.displayId}`
43248
+ );
43249
+ }
43250
+ }
43251
+ }
43252
+ }
43253
+ function manScopeContains(metadata, file) {
43254
+ return metadata.implementationScope.include.some(
43255
+ (include) => path71.matchesGlob(file, include)
43256
+ ) && !metadata.implementationScope.exclude.some(
43257
+ (exclude) => path71.matchesGlob(file, exclude)
43258
+ );
43259
+ }
43260
+ function assertManPlanInScope(metadata, file) {
43261
+ if (!manScopeContains(metadata, file))
43262
+ throw new Error(
43263
+ `MANCODE_MAN_PLAN_OUTSIDE_SCOPE: ${file} is not covered by implementationScope.include; add that exact repo-relative path or a covering glob`
43264
+ );
43265
+ }
43266
+ function manDeliveryFinalization(task, subject, recordCurrent, outsideScope, outsideScopeDirty, pendingCommit) {
43267
+ const blockers = [];
43268
+ if (task.metadata.governance.planDecision !== "governed_execution")
43269
+ blockers.push({
43270
+ code: "plan_execution_required",
43271
+ status: task.metadata.governance.planDecision ?? "unconfirmed",
43272
+ nextAction: "Confirm the bound plan for governed execution."
43273
+ });
43274
+ const reviewSubjectCurrent = task.review.status === "skipped" || task.review.status === "passed" && task.review.delivery?.subject.contentDigest === subject.contentDigest && task.review.delivery?.subject.environment === subject.environment;
43275
+ if (!reviewSubjectCurrent)
43276
+ blockers.push({
43277
+ code: "review_incomplete",
43278
+ status: task.review.status === "passed" ? "stale" : task.review.status,
43279
+ nextAction: task.review.status === "blocked" ? "Fix the recorded findings, verify the changed module, and submit the targeted review result." : "Complete one module review for the current subject and apply its review ledger."
43280
+ });
43281
+ const verification = assessManVerification(task, subject);
43282
+ if (verification.status !== "passed")
43283
+ blockers.push({
43284
+ code: "verification_incomplete",
43285
+ status: verification.status,
43286
+ nextAction: verification.nextAction
43287
+ });
43288
+ if (!recordCurrent)
43289
+ blockers.push({
43290
+ code: "delivery_record_stale",
43291
+ status: "stale",
43292
+ nextAction: "Sync the delivery record after the latest evidence change."
43293
+ });
43294
+ if (outsideScope.length)
43295
+ blockers.push({
43296
+ code: "committed_outside_scope",
43297
+ status: "blocked",
43298
+ nextAction: "Remove the unrelated committed changes or obtain an approved scope realignment.",
43299
+ files: outsideScope
43300
+ });
43301
+ if (outsideScopeDirty.length)
43302
+ blockers.push({
43303
+ code: "uncommitted_outside_scope",
43304
+ status: "blocked",
43305
+ nextAction: "Move, stash, or separately commit unrelated working-tree changes before recording final delivery evidence; do not add them to this task commit.",
43306
+ files: outsideScopeDirty
43307
+ });
43308
+ if (pendingCommit.length)
43309
+ blockers.push({
43310
+ code: "uncommitted_changes",
43311
+ status: "pending",
43312
+ nextAction: "Commit only the task-owned versionable changes.",
43313
+ files: pendingCommit
43314
+ });
43315
+ return {
43316
+ status: blockers.length ? "incomplete" : "ready",
43317
+ blockers
43318
+ };
43319
+ }
43320
+ function manInspectionFailureFinalization(error) {
43321
+ const diagnostic = error instanceof Error ? error.message : String(error);
43322
+ let nextAction = "Resolve the reported inspection diagnostic, then run delivery inspect again.";
43323
+ if (diagnostic.includes("MANCODE_MAN_PLAN_BASELINE_CHANGED")) {
43324
+ nextAction = "Restore the approved plan baseline or explicitly reframe the task before inspecting delivery again.";
43325
+ } else if (diagnostic.includes("MANCODE_MAN_PLAN_IGNORED")) {
43326
+ nextAction = "Remove the ignore rule for the approved plan file, then inspect delivery again.";
43327
+ } else if (diagnostic.includes("MANCODE_MAN_DELIVERY_GIT_REQUIRED")) {
43328
+ nextAction = "Use a Git worktree for versioned delivery, then inspect the task again.";
43329
+ } else if (diagnostic.includes("MANCODE_MAN_CONTENT_NODE_UNSUPPORTED")) {
43330
+ nextAction = "Remove the unsupported repository content node from the delivery subject or use a supported versioned file, then inspect again.";
43331
+ }
43332
+ return {
43333
+ status: "incomplete",
43334
+ blockers: [
43335
+ {
43336
+ code: "inspection_failed",
43337
+ status: "failed",
43338
+ nextAction,
43339
+ diagnostic
43340
+ }
43341
+ ]
43342
+ };
43343
+ }
43344
+ function assessManVerification(task, subject) {
43345
+ const missingConfiguredCriteria = task.requirements.acceptanceCriteria.filter(
43346
+ (criterion) => criterion.required && criterion.verificationSurfaces === void 0
43347
+ ).map((criterion) => criterion.displayId);
43348
+ if (missingConfiguredCriteria.length) {
43349
+ return {
43350
+ status: "surface_requirement_missing",
43351
+ nextAction: `Reframe or re-finalize requirements with verificationSurfaces for ${missingConfiguredCriteria.join(", ")}.`
43352
+ };
43353
+ }
43354
+ if (task.verification.status !== "passed") {
43355
+ return {
43356
+ status: task.verification.status,
43357
+ nextAction: "Run or confirm the missing acceptance evidence against the current subject."
43358
+ };
43359
+ }
43360
+ const criteria = new Map(
43361
+ task.requirements.acceptanceCriteria.map((criterion) => [
43362
+ criterion.criterionId,
43363
+ criterion
43364
+ ])
43365
+ );
43366
+ const missingRequirements = [];
43367
+ const missingActual = [];
43368
+ const stale = [];
43369
+ const mismatches = [];
43370
+ for (const check of task.verification.checks) {
43371
+ if (!check.required) continue;
43372
+ const criterion = criteria.get(check.criterionId);
43373
+ for (const slot of ["automated", "manual"]) {
43374
+ const evidence = check[slot];
43375
+ if (evidence?.status !== "passed") continue;
43376
+ const expected = criterion?.verificationSurfaces?.[slot];
43377
+ const label = `${check.displayId}:${slot}`;
43378
+ if (!expected) {
43379
+ missingRequirements.push(label);
43380
+ continue;
43381
+ }
43382
+ if (!evidence.surface) {
43383
+ missingActual.push(label);
43384
+ continue;
43385
+ }
43386
+ if (subject !== void 0 && (evidence.subject?.contentDigest !== subject.contentDigest || evidence.subject.environment !== subject.environment)) {
43387
+ stale.push(label);
43388
+ continue;
43389
+ }
43390
+ if (evidence.surface !== expected) {
43391
+ mismatches.push(
43392
+ `${label} requires ${expected}, recorded ${evidence.surface}`
43393
+ );
43394
+ }
43395
+ }
43396
+ }
43397
+ if (missingRequirements.length) {
43398
+ return {
43399
+ status: "surface_requirement_missing",
43400
+ nextAction: `Reframe or re-finalize requirements with verificationSurfaces for ${missingRequirements.join(", ")}.`
43401
+ };
43402
+ }
43403
+ if (missingActual.length) {
43404
+ return {
43405
+ status: "surface_required",
43406
+ nextAction: `Record the actual observation surface for ${missingActual.join(", ")}.`
43407
+ };
43408
+ }
43409
+ if (stale.length) {
43410
+ return {
43411
+ status: "stale",
43412
+ nextAction: `Re-run or confirm evidence against the current subject for ${stale.join(", ")}.`
43413
+ };
43414
+ }
43415
+ if (mismatches.length) {
43416
+ return {
43417
+ status: "surface_mismatch",
43418
+ nextAction: `Record evidence at the required observation surface: ${mismatches.join("; ")}.`
43419
+ };
43420
+ }
43421
+ return { status: "passed", nextAction: "No verification action required." };
43422
+ }
43423
+ async function inspectManDelivery(root, task) {
43424
+ if (!isManDelivery(task.metadata))
43425
+ throw new Error("MANCODE_MAN_DELIVERY_MODE_REQUIRED");
43426
+ const bound = await readBoundManPlan(root, task);
43427
+ const subject = await captureManSubject(root, task);
43428
+ const head = await readCheckoutCodeHead(root);
43429
+ const trackedDirty = (await manGit(
43430
+ root,
43431
+ head === null ? ["ls-files", "-z", "--cached"] : ["diff", "--name-only", "--relative", "-z", "HEAD", "--", "."]
43432
+ )).split("\0").filter(Boolean);
43433
+ const untracked = (await manGit(root, ["ls-files", "--others", "--exclude-standard", "-z"])).split("\0").filter(Boolean);
43434
+ const inTask = (file) => file === bound.source.path || manScopeContains(task.metadata, file);
43435
+ const dirtyFiles = [.../* @__PURE__ */ new Set([...trackedDirty, ...untracked])].filter(
43436
+ (file) => !file.startsWith(".mancode/")
43437
+ );
43438
+ const pendingCommit = dirtyFiles.filter(inTask);
43439
+ const outsideScopeDirty = dirtyFiles.filter((file) => !inTask(file));
43440
+ const committedChanges = head === null ? [] : bound.source.baseHead === null ? (await manGit(root, ["ls-tree", "-r", "--name-only", "-z", "HEAD"])).split("\0").filter(Boolean) : (await manGit(root, [
43441
+ "diff",
43442
+ "--name-only",
43443
+ "--relative",
43444
+ "-z",
43445
+ bound.source.baseHead,
43446
+ "HEAD",
43447
+ "--",
43448
+ "."
43449
+ ])).split("\0").filter(Boolean);
43450
+ const outsideScope = committedChanges.filter(
43451
+ (file) => !file.startsWith(".mancode/") && !inTask(file)
43452
+ );
43453
+ const upstream = (await manGit(root, [
43454
+ "for-each-ref",
43455
+ "--format=%(upstream:short)",
43456
+ `refs/heads/${(await manGit(root, ["branch", "--show-current"])).trim()}`
43457
+ ])).trim() || null;
43458
+ const recordCurrent = parseManPlanDocument(bound.document).record === renderManDeliveryRecord(task, subject).trim();
43459
+ return {
43460
+ subject,
43461
+ source: bound.source,
43462
+ pendingCommit,
43463
+ outsideScopeDirty,
43464
+ outsideScope,
43465
+ upstream,
43466
+ publication: upstream === null ? "unpublished" : "unknown",
43467
+ finalization: manDeliveryFinalization(
43468
+ task,
43469
+ subject,
43470
+ recordCurrent,
43471
+ outsideScope,
43472
+ outsideScopeDirty,
43473
+ pendingCommit
43474
+ )
43475
+ };
43476
+ }
43477
+ async function inspectManPublication(root) {
43478
+ const head = await readCheckoutCodeHead(root);
43479
+ const branch = (await manGit(root, ["branch", "--show-current"])).trim();
43480
+ if (!head || !branch)
43481
+ return { status: "unpublished", reason: "no committed task branch" };
43482
+ const [remote, ref] = (await manGit(root, [
43483
+ "for-each-ref",
43484
+ "--format=%(upstream:remotename)%00%(upstream:remoteref)",
43485
+ `refs/heads/${branch}`
43486
+ ])).trim().split("\0");
43487
+ if (!remote || !ref)
43488
+ return { status: "unpublished", reason: "no upstream configured" };
43489
+ try {
43490
+ const remoteHead = (await manGit(root, ["ls-remote", "--exit-code", "--", remote, ref])).trim().split(/\s+/)[0];
43491
+ if (!remoteHead)
43492
+ return { status: "unpublished", reason: "upstream ref absent" };
43493
+ if (remoteHead === head) return { status: "published", head, remoteHead };
43494
+ try {
43495
+ await manGit(root, ["merge-base", "--is-ancestor", head, remoteHead]);
43496
+ return { status: "published", head, remoteHead };
43497
+ } catch (error) {
43498
+ if (error.code === 1)
43499
+ return {
43500
+ status: "unpublished",
43501
+ head,
43502
+ remoteHead,
43503
+ reason: "upstream does not contain this commit"
43504
+ };
43505
+ throw error;
43506
+ }
43507
+ } catch (error) {
43508
+ return {
43509
+ status: "unverified",
43510
+ reason: "upstream publication could not be verified; no fetch, push or business-state change was performed",
43511
+ diagnostic: error instanceof Error ? error.message : String(error)
43512
+ };
43513
+ }
43514
+ }
43515
+ function renderManDeliveryRecord(task, subject) {
43516
+ const reviewStale = subject && task.review.delivery && (task.review.delivery.subject.contentDigest !== subject.contentDigest || task.review.delivery.subject.environment !== subject.environment);
43517
+ const verificationStatus = assessManVerification(task, subject).status;
43518
+ return [
43519
+ `Task: ${task.metadata.taskRef.namespace}:${task.metadata.taskRef.taskId}`,
43520
+ `Plan version: ${task.metadata.governance.planVersion}`,
43521
+ `Review: ${reviewStale ? "stale" : task.review.status}`,
43522
+ `Verification: ${verificationStatus}`,
43523
+ "",
43524
+ ...task.review.delivery ? [
43525
+ `Reviewer declaration: ${task.review.delivery.reviewer}`,
43526
+ `Direction: ${task.review.delivery.direction}`,
43527
+ `Correctness: ${task.review.delivery.correctness}`,
43528
+ `Proportionality: ${task.review.delivery.proportionality}`,
43529
+ `Next: ${task.review.delivery.nextAction}`
43530
+ ] : [
43531
+ "Next: finish relevant verification, then review the complete module."
43532
+ ],
43533
+ ...task.review.blockers.map(
43534
+ (item) => `- ${item.displayId}: ${item.status} \u2014 ${item.summary}`
43535
+ ),
43536
+ ...task.review.delivery?.coverage.map(
43537
+ (row) => `- ${row.acceptanceId}: ${row.status} \u2014 ${row.evidence}`
43538
+ ) ?? [],
43539
+ ...task.verification.checks.map((check) => {
43540
+ const component = (item) => item === null ? "n/a" : `${item.status}(surface=${item.surface ?? "unspecified"})`;
43541
+ return `- ${check.displayId}: automated=${component(check.automated)}; manual=${component(check.manual)}; ${check.automated?.summary ?? check.manual?.summary ?? "No evidence yet."}`;
43542
+ })
43543
+ ].join("\n");
43544
+ }
43545
+ async function syncManDeliveryRecord(root, task) {
43546
+ const bound = await readBoundManPlan(root, task);
43547
+ if (task.metadata.governance.planDecision === "governed_execution" && !manScopeContains(task.metadata, bound.source.path))
43548
+ assertManPlanInScope(task.metadata, bound.source.path);
43549
+ const subject = await hasGitWorktree(root) ? await captureManSubject(root, task) : void 0;
43550
+ const next = replaceManDeliveryRecord(
43551
+ bound.document,
43552
+ renderManDeliveryRecord(task, subject)
43553
+ );
43554
+ if (scanSharedText(next).some(
43555
+ (finding) => ["authorization", "cookie", "private_key", "secret"].includes(
43556
+ finding.kind
43557
+ )
43558
+ ))
43559
+ throw new Error(
43560
+ "MANCODE_MAN_DOCUMENT_SENSITIVE: redact credential-like text before versioning"
43561
+ );
43562
+ const target = await realpath4(path71.join(root, bound.source.path));
43563
+ if (next !== bound.document) {
43564
+ const temporary = `${target}.${randomUUID4()}.tmp`;
43565
+ try {
43566
+ await writeFile51(temporary, next, {
43567
+ flag: "wx",
43568
+ mode: (await lstat28(target)).mode
43569
+ });
43570
+ if (await readFile48(target, "utf8") !== bound.document)
43571
+ throw new Error("MANCODE_MAN_PLAN_FILE_CHANGED");
43572
+ await replaceFileAtomically(temporary, target);
43573
+ } finally {
43574
+ await rm24(temporary, { force: true });
43575
+ }
43576
+ }
43577
+ let taskId;
43578
+ try {
43579
+ taskId = manProgressTaskId(bound.baseline) ?? `${task.metadata.taskRef.namespace}:${task.metadata.taskRef.taskId}`;
43580
+ } catch (error) {
43581
+ return {
43582
+ status: "manual_sync",
43583
+ reason: error instanceof Error ? error.message : String(error)
43584
+ };
43585
+ }
43586
+ const unresolved = task.requirements.blockingUnknowns.filter(
43587
+ (item) => item.status === "open"
43588
+ );
43589
+ const reason = task.metadata.status === "blocked" && unresolved.length ? unresolved.map((item) => item.statement).join("; ") : null;
43590
+ const verified = subject !== void 0 && assessManVerification(task, subject).status === "passed";
43591
+ const reviewed = task.review.status === "skipped" || task.review.status === "passed" && task.review.delivery?.subject.contentDigest === subject?.contentDigest && task.review.delivery?.subject.environment === subject?.environment;
43592
+ const status2 = reason ? "\u963B\u585E" : verified && reviewed ? "\u5DF2\u5B8C\u6210" : verified && task.review.status !== "blocked" ? "\u5F85\u5BA1\u6838" : task.metadata.currentStep >= 5 ? "\u8FDB\u884C\u4E2D" : "\u672A\u5B8C\u6210";
43593
+ return syncManProgressPage(
43594
+ root,
43595
+ taskId,
43596
+ status2,
43597
+ reason,
43598
+ manScopeContains(task.metadata, "\u9879\u76EE\u8FDB\u5EA6.html")
43599
+ );
43600
+ }
43601
+ async function assertManDeliveryReady(root, task) {
43602
+ if (!isManDelivery(task.metadata)) return;
43603
+ const result2 = await inspectManDelivery(root, task);
43604
+ const blocker = (code) => result2.finalization.blockers.find((item) => item.code === code);
43605
+ const plan = blocker("plan_execution_required");
43606
+ if (plan)
43607
+ throw new Error(
43608
+ `MANCODE_MAN_DELIVERY_EXECUTION_REQUIRED: ${plan.nextAction}`
43609
+ );
43610
+ const verification = blocker("verification_incomplete");
43611
+ if (verification)
43612
+ throw new Error(
43613
+ `MANCODE_MAN_VERIFICATION_INCOMPLETE: ${verification.status}; ${verification.nextAction}`
43614
+ );
43615
+ const review = blocker("review_incomplete");
43616
+ if (review)
43617
+ throw new Error(
43618
+ `MANCODE_MAN_REVIEW_INCOMPLETE: ${review.status}; ${review.nextAction}`
43619
+ );
43620
+ assertManReviewCoverage(task, task.review, result2.subject);
43621
+ assertManVerificationSubjects(task, task.verification, result2.subject);
43622
+ if (blocker("delivery_record_stale"))
43623
+ throw new Error("MANCODE_MAN_DELIVERY_RECORD_STALE");
43624
+ const outside = blocker("committed_outside_scope");
43625
+ if (outside)
43626
+ throw new Error(
43627
+ `MANCODE_MAN_COMMIT_OUTSIDE_SCOPE: ${outside.files?.join(", ")}`
43628
+ );
43629
+ const outsideDirty = blocker("uncommitted_outside_scope");
43630
+ if (outsideDirty)
43631
+ throw new Error(
43632
+ `MANCODE_MAN_UNCOMMITTED_OUTSIDE_SCOPE: ${outsideDirty.files?.join(", ")}`
43633
+ );
43634
+ const pending = blocker("uncommitted_changes");
43635
+ if (pending)
43636
+ throw new Error(
43637
+ `MANCODE_MAN_DELIVERY_UNCOMMITTED: ${pending.files?.join(", ")}`
43638
+ );
43639
+ }
43640
+
42124
43641
  // src/context/scope-change.ts
42125
- import { createHash as createHash11 } from "crypto";
43642
+ import { createHash as createHash12 } from "crypto";
42126
43643
  async function changeV3WorkflowScope(input) {
42127
43644
  const taskRef = parseTaskRefValue(input.taskRef);
42128
43645
  if (taskRef.namespace !== "shared") {
@@ -42741,7 +44258,7 @@ function scopeSuccessorClaimId(operationId, predecessorClaimId, timestamp4) {
42741
44258
  if (Number.isNaN(milliseconds)) {
42742
44259
  throw new Error("MANCODE_SCOPE_TIMESTAMP_INVALID");
42743
44260
  }
42744
- const entropy = createHash11("sha256").update(`scope-change:${operationId}:${predecessorClaimId}`, "utf8").digest().subarray(0, 10);
44261
+ const entropy = createHash12("sha256").update(`scope-change:${operationId}:${predecessorClaimId}`, "utf8").digest().subarray(0, 10);
42745
44262
  return createUlid(milliseconds, entropy);
42746
44263
  }
42747
44264
  function requireCodeHead3(context) {
@@ -42760,7 +44277,7 @@ function compareUtf815(left, right) {
42760
44277
  // src/context/plan-revision.ts
42761
44278
  async function reviseV3Plan(input) {
42762
44279
  const taskRef = parseTaskRefValue(input.taskRef);
42763
- const plan = requirePlan(input.plan);
44280
+ let plan = requirePlan(input.plan);
42764
44281
  const planDecision = parsePlanDecision(input.planDecision);
42765
44282
  const submittedScope = input.implementationScope === void 0 ? null : normalizeImplementationScope(input.implementationScope);
42766
44283
  if (taskRef.namespace === "shared") {
@@ -42777,6 +44294,21 @@ async function reviseV3Plan(input) {
42777
44294
  });
42778
44295
  let journal = null;
42779
44296
  try {
44297
+ if (isManDelivery(context.task.metadata)) {
44298
+ if (input.planSource) {
44299
+ plan = await bindManPlan(
44300
+ input.projectRoot,
44301
+ input.planSource,
44302
+ plan,
44303
+ context.task.plan?.content ?? null
44304
+ );
44305
+ } else {
44306
+ await readBoundManPlan(input.projectRoot, context.task);
44307
+ if (plan !== context.task.plan?.content)
44308
+ throw new Error("MANCODE_MAN_PLAN_SOURCE_REQUIRED");
44309
+ }
44310
+ } else if (input.planSource)
44311
+ throw new Error("MANCODE_MAN_DELIVERY_MODE_REQUIRED");
42780
44312
  const planChanged = context.task.plan?.content !== plan;
42781
44313
  const executionScopeBinding = assertExecutionScopeBindingAttempt({
42782
44314
  metadata: context.task.metadata,
@@ -42795,6 +44327,17 @@ async function reviseV3Plan(input) {
42795
44327
  const scopeChanged = submittedScope !== null && submittedScope.digest !== context.task.metadata.implementationScope.digest;
42796
44328
  if (planDecision === "governed_execution") {
42797
44329
  assertExecutableImplementationScope(implementationScope);
44330
+ if (isManDelivery(context.task.metadata)) {
44331
+ const source = parseManDeliveryPlan(plan)?.source;
44332
+ if (!source)
44333
+ throw new Error(
44334
+ "MANCODE_MAN_PLAN_OUTSIDE_SCOPE: bound plan source path is missing; provide a repo-relative plan path"
44335
+ );
44336
+ assertManPlanInScope(
44337
+ { ...context.task.metadata, implementationScope },
44338
+ source.path
44339
+ );
44340
+ }
42798
44341
  }
42799
44342
  if (executionScopeBinding) {
42800
44343
  assertExecutableImplementationScope(implementationScope);
@@ -43110,6 +44653,10 @@ async function reframeV3Workflow(input) {
43110
44653
  try {
43111
44654
  assertReframeEligible(context, activeClaims2, openHandoffs, activeChildren);
43112
44655
  assertReframeClaimsFresh(context, activeClaims2);
44656
+ await assertTaskCheckpointIdAvailableAtRoot(
44657
+ context.task.location.taskRoot,
44658
+ input.checkpointId
44659
+ );
43113
44660
  const timestamp4 = context.now.toISOString();
43114
44661
  const archivedRequirementsContent = await readTaskAuthorityFileAtRoot(
43115
44662
  context.task.location.taskRoot,
@@ -43681,6 +45228,9 @@ async function writeV3Requirements(input, action) {
43681
45228
  let journal = null;
43682
45229
  try {
43683
45230
  assertRequirementsFinalizeEligible(context.task.metadata);
45231
+ if (action === "finalize" && context.task.metadata.workflowMode === "man" && context.task.metadata.governance.policyVersions.planning === 3 && context.task.metadata.governance.planDecision !== "solo_handoff") {
45232
+ assertManDeliveryVerificationSurfaces(submitted);
45233
+ }
43684
45234
  const timestamp4 = context.now.toISOString();
43685
45235
  const requirements = createReplacementRequirements(
43686
45236
  context.task.requirements,
@@ -43901,6 +45451,12 @@ async function applyV3ReviewLedger(input) {
43901
45451
  });
43902
45452
  let journal = null;
43903
45453
  try {
45454
+ const subject = isManDelivery(context.task.metadata) ? await captureManSubject(input.projectRoot, context.task) : null;
45455
+ assertManReviewCoverage(
45456
+ context.task,
45457
+ submitted,
45458
+ subject ?? { contentDigest: "", environment: "" }
45459
+ );
43904
45460
  assertReviewEligible(context.task.metadata, context.task.plan !== null);
43905
45461
  const timestamp4 = context.now.toISOString();
43906
45462
  const review = createCurrentReview(
@@ -43910,11 +45466,34 @@ async function applyV3ReviewLedger(input) {
43910
45466
  context.operationId,
43911
45467
  timestamp4
43912
45468
  );
43913
- const verification = markTaskVerificationStale(
45469
+ let verification = markTaskVerificationStale(
43914
45470
  context.task.verification,
43915
45471
  context.operationId,
43916
45472
  timestamp4
43917
45473
  );
45474
+ const previous = context.task.verification;
45475
+ if (subject && previous.requirementsDigest === context.task.metadata.governance.requirementsDigest && previous.planVersion === context.task.metadata.governance.planVersion && previous.checks.every(
45476
+ (check) => [check.automated, check.manual].every(
45477
+ (item) => item?.status !== "passed" || item.subject?.contentDigest === subject.contentDigest && item.subject.environment === subject.environment
45478
+ )
45479
+ )) {
45480
+ const current = {
45481
+ ...previous,
45482
+ revision: previous.revision + 1,
45483
+ remediationRound: review.remediationRound,
45484
+ lastOperationId: context.operationId,
45485
+ updatedAt: timestamp4
45486
+ };
45487
+ const draft = {
45488
+ ...current,
45489
+ status: deriveVerificationLedgerStatus(current)
45490
+ };
45491
+ verification = parseVerificationLedger({
45492
+ ...draft,
45493
+ contentDigest: verificationLedgerDigest(draft)
45494
+ });
45495
+ assertVerificationLedgerTransition(previous, verification);
45496
+ }
43918
45497
  const metadata = updateMetadata3(
43919
45498
  context.task.metadata,
43920
45499
  review,
@@ -44495,6 +46074,7 @@ async function completeV3Task(input) {
44495
46074
  throw new Error("MANCODE_GIT_REF_TRANSPORT_NOT_IMPLEMENTED");
44496
46075
  }
44497
46076
  const activeChildren = await context.store.listActiveChildTaskRefs(taskRef);
46077
+ await assertManDeliveryReady(input.projectRoot, context.task);
44498
46078
  assertTaskCompletionGate(
44499
46079
  {
44500
46080
  metadata: context.task.metadata,
@@ -44816,6 +46396,12 @@ async function recordV3Verification(input) {
44816
46396
  });
44817
46397
  let journal = null;
44818
46398
  try {
46399
+ const subject = isManDelivery(context.task.metadata) ? await captureManSubject(input.projectRoot, context.task) : null;
46400
+ assertManVerificationSubjects(
46401
+ context.task,
46402
+ submitted,
46403
+ subject ?? { contentDigest: "", environment: "" }
46404
+ );
44819
46405
  assertVerificationEligible(
44820
46406
  context.task.metadata,
44821
46407
  context.task.plan !== null
@@ -44828,7 +46414,12 @@ async function recordV3Verification(input) {
44828
46414
  context.task.review.remediationRound,
44829
46415
  context.task.requirements,
44830
46416
  context.operationId,
44831
- timestamp4
46417
+ timestamp4,
46418
+ subject !== null && context.task.verification.checks.some(
46419
+ (check) => [check.automated, check.manual].some(
46420
+ (item) => item?.status === "passed" && (item.subject?.contentDigest !== subject.contentDigest || item.subject.environment !== subject.environment)
46421
+ )
46422
+ )
44832
46423
  );
44833
46424
  const metadata = updateMetadata4(
44834
46425
  context.task.metadata,
@@ -44938,7 +46529,7 @@ function assertVerificationEligible(metadata, hasPlan) {
44938
46529
  throw new Error("MANCODE_VERIFICATION_PLAN_GATE_REQUIRED");
44939
46530
  }
44940
46531
  }
44941
- function createCurrentVerification(previous, submitted, metadata, remediationRound, requirements, operationId, updatedAt) {
46532
+ function createCurrentVerification(previous, submitted, metadata, remediationRound, requirements, operationId, updatedAt, contentInvalidated) {
44942
46533
  if (submitted.requirementsDigest !== metadata.governance.requirementsDigest || submitted.planVersion !== metadata.governance.planVersion || submitted.remediationRound !== remediationRound) {
44943
46534
  throw new Error("MANCODE_VERIFICATION_CONTEXT_STALE");
44944
46535
  }
@@ -44957,7 +46548,7 @@ function createCurrentVerification(previous, submitted, metadata, remediationRou
44957
46548
  },
44958
46549
  requirements
44959
46550
  );
44960
- assertVerificationLedgerTransition(previous, next);
46551
+ assertVerificationLedgerTransition(previous, next, contentInvalidated);
44961
46552
  assertVerificationLedgerRequirements(next, requirements);
44962
46553
  assertVerificationLedgerAgainstContext(next, {
44963
46554
  requirementsDigest: metadata.governance.requirementsDigest,
@@ -44985,14 +46576,14 @@ function updateMetadata4(previous, verification, operationId, updatedAt) {
44985
46576
 
44986
46577
  // src/context/workflow-create.ts
44987
46578
  import {
44988
- lstat as lstat27,
46579
+ lstat as lstat29,
44989
46580
  mkdir as mkdir41,
44990
- readFile as readFile47,
46581
+ readFile as readFile49,
44991
46582
  rename as rename15,
44992
- rm as rm23,
44993
- writeFile as writeFile50
46583
+ rm as rm25,
46584
+ writeFile as writeFile52
44994
46585
  } from "fs/promises";
44995
- import path69 from "path";
46586
+ import path72 from "path";
44996
46587
 
44997
46588
  // src/context/creation-resolution.ts
44998
46589
  function resolveWorkflowCreation(request) {
@@ -45102,13 +46693,16 @@ function rejectConflict(provided, expected, label) {
45102
46693
 
45103
46694
  // src/context/workflow-create.ts
45104
46695
  async function createV3Workflow(input) {
45105
- const projectRoot = path69.resolve(requireProjectRoot2(input.projectRoot));
46696
+ const projectRoot = path72.resolve(requireProjectRoot2(input.projectRoot));
45106
46697
  const task = requireText2(input.task, "workflow task");
45107
46698
  const client = requireText2(input.client, "workflow client");
45108
46699
  const now = input.now ?? /* @__PURE__ */ new Date();
45109
46700
  const timestamp4 = now.toISOString();
45110
46701
  assertUlid(input.sessionId, "workflow sessionId");
45111
46702
  const workflowMode = parseWorkflowMode(input.workflowMode);
46703
+ if (input.delivery && (workflowMode !== "man" || input.parentTaskRef)) {
46704
+ throw new Error("MANCODE_MAN_DELIVERY_MODE_REQUIRED");
46705
+ }
45112
46706
  const session = await readSession(projectRoot, input.sessionId);
45113
46707
  if (session === null || session.status !== "active") {
45114
46708
  throw new Error("MANCODE_SESSION_NOT_FOUND");
@@ -45189,7 +46783,7 @@ async function createV3Workflow(input) {
45189
46783
  explicitScope: input.implementationScope,
45190
46784
  ownershipEpoch: taskRef.namespace === "shared" && project.config.transport.mode === "git-ref" ? 0 : 1,
45191
46785
  timestamp: timestamp4,
45192
- planningPolicyVersion: parent === null ? project.manifest.manifestVersion === 2 && workflowMode === "man" ? project.manifest.workflowPolicyDefaults.planning : 1 : parent.metadata.governance.policyVersions.planning
46786
+ planningPolicyVersion: input.delivery ? 3 : parent === null ? project.manifest.manifestVersion === 2 && workflowMode === "man" ? project.manifest.workflowPolicyDefaults.planning : 1 : parent.metadata.governance.policyVersions.planning === 3 ? 2 : parent.metadata.governance.policyVersions.planning
45193
46787
  });
45194
46788
  const homeStore = resolveTaskEntityHomeStore(
45195
46789
  runtime.entityHomeStoreContext,
@@ -45287,8 +46881,8 @@ async function createV3Workflow(input) {
45287
46881
  throw new Error("MANCODE_REVISION_CONFLICT");
45288
46882
  }
45289
46883
  const taskParent = await ensureSafeTaskParent3(projectRoot, taskRef);
45290
- const targetDirectory = path69.join(taskParent, taskRef.taskId);
45291
- stagingDirectory = path69.join(
46884
+ const targetDirectory = path72.join(taskParent, taskRef.taskId);
46885
+ stagingDirectory = path72.join(
45292
46886
  taskParent,
45293
46887
  `.${taskRef.taskId}.${operationId}.staging`
45294
46888
  );
@@ -45746,7 +47340,7 @@ async function ensureSafeTaskParent3(projectRoot, taskRef) {
45746
47340
  const segments = [".mancode", taskRef.namespace, "workflows"];
45747
47341
  let current = projectRoot;
45748
47342
  for (const segment of segments) {
45749
- current = path69.join(current, segment);
47343
+ current = path72.join(current, segment);
45750
47344
  const existing = await lstatOrNull5(current);
45751
47345
  if (existing === null) {
45752
47346
  await mkdir41(current);
@@ -45782,13 +47376,13 @@ async function writeStagedEntities(stagingDirectory, entities) {
45782
47376
  }
45783
47377
  async function writeStagedJson(stagingDirectory, fileName, value) {
45784
47378
  await assertDirectory(stagingDirectory);
45785
- const target = path69.join(stagingDirectory, fileName);
45786
- await writeFile50(target, `${JSON.stringify(value, null, 2)}
47379
+ const target = path72.join(stagingDirectory, fileName);
47380
+ await writeFile52(target, `${JSON.stringify(value, null, 2)}
45787
47381
  `, {
45788
47382
  encoding: "utf8",
45789
47383
  flag: "wx"
45790
47384
  });
45791
- const entry = await lstat27(target);
47385
+ const entry = await lstat29(target);
45792
47386
  if (!entry.isFile() || entry.isSymbolicLink()) {
45793
47387
  throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
45794
47388
  }
@@ -45820,13 +47414,13 @@ async function validateStagedEntities(stagingDirectory) {
45820
47414
  });
45821
47415
  }
45822
47416
  async function readStagedJson(stagingDirectory, fileName, parser) {
45823
- const target = path69.join(stagingDirectory, fileName);
45824
- const before = await lstat27(target);
47417
+ const target = path72.join(stagingDirectory, fileName);
47418
+ const before = await lstat29(target);
45825
47419
  if (!before.isFile() || before.isSymbolicLink()) {
45826
47420
  throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
45827
47421
  }
45828
- const parsed = parser(JSON.parse(await readFile47(target, "utf8")));
45829
- const after = await lstat27(target);
47422
+ const parsed = parser(JSON.parse(await readFile49(target, "utf8")));
47423
+ const after = await lstat29(target);
45830
47424
  if (!after.isFile() || after.isSymbolicLink() || before.dev !== after.dev || before.ino !== after.ino) {
45831
47425
  throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
45832
47426
  }
@@ -45917,18 +47511,18 @@ async function abortPreparedCreate(store, journal, stagingDirectory, now) {
45917
47511
  { canAbort: true }
45918
47512
  );
45919
47513
  } finally {
45920
- await rm23(stagingDirectory, { recursive: true, force: true });
47514
+ await rm25(stagingDirectory, { recursive: true, force: true });
45921
47515
  }
45922
47516
  }
45923
47517
  async function assertDirectory(target) {
45924
- const entry = await lstat27(target);
47518
+ const entry = await lstat29(target);
45925
47519
  if (!entry.isDirectory() || entry.isSymbolicLink()) {
45926
47520
  throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
45927
47521
  }
45928
47522
  }
45929
47523
  async function lstatOrNull5(target) {
45930
47524
  try {
45931
- return await lstat27(target);
47525
+ return await lstat29(target);
45932
47526
  } catch (error) {
45933
47527
  if (isNotFound34(error)) return null;
45934
47528
  throw error;
@@ -46261,6 +47855,7 @@ async function completeGitRefTask(input) {
46261
47855
  try {
46262
47856
  assertNoPendingHandoff(opened.manifest, taskRef);
46263
47857
  assertCompletionOutcome2(opened.context.task.metadata, input.outcome);
47858
+ await assertManDeliveryReady(input.projectRoot, opened.context.task);
46264
47859
  const activeClaims2 = activeRemoteClaims(opened.manifest, taskRef);
46265
47860
  const activeChildren = await opened.context.store.listActiveChildTaskRefs(taskRef);
46266
47861
  assertTaskCompletionGate(
@@ -46870,6 +48465,360 @@ function compareUtf817(left, right) {
46870
48465
  return Buffer.from(left, "utf8").compare(Buffer.from(right, "utf8"));
46871
48466
  }
46872
48467
 
48468
+ // src/commands/man-delivery.ts
48469
+ import { execFile as execFileCallback8 } from "child_process";
48470
+ import { readFile as readFile50 } from "fs/promises";
48471
+ import path73 from "path";
48472
+ import { promisify as promisify10 } from "util";
48473
+ var execFile11 = promisify10(execFileCallback8);
48474
+ async function manDeliveryCommand(root, args, options) {
48475
+ try {
48476
+ const [ref, action] = args;
48477
+ if (!ref || args.length !== 2 || ![
48478
+ "inspect",
48479
+ "check",
48480
+ "publication",
48481
+ "sync",
48482
+ "verify",
48483
+ "confirm",
48484
+ "review"
48485
+ ].includes(action ?? "")) {
48486
+ throw new Error(
48487
+ "MANCODE_MAN_DELIVERY_ARGUMENT_INVALID: delivery <TaskRef> <inspect|check|publication|sync|verify|confirm|review>"
48488
+ );
48489
+ }
48490
+ const project = await readV3CommandProject(root);
48491
+ const taskRef = parseTaskRef(ref);
48492
+ let task = await project.store.readTaskSnapshot(taskRef);
48493
+ if (!isManDelivery(task.metadata))
48494
+ throw new Error("MANCODE_MAN_DELIVERY_MODE_REQUIRED");
48495
+ if (action === "publication")
48496
+ return printV3Result(
48497
+ options.json,
48498
+ await inspectManPublication(project.projectRoot)
48499
+ );
48500
+ if (action === "inspect")
48501
+ return printV3Result(options.json, {
48502
+ ...await inspectManDelivery(project.projectRoot, task),
48503
+ acceptanceCriteria: task.requirements.acceptanceCriteria,
48504
+ review: task.review,
48505
+ verification: task.verification
48506
+ });
48507
+ if (action === "check") {
48508
+ await assertManDeliveryReady(project.projectRoot, task);
48509
+ assertTaskCompletionGate(
48510
+ { ...task, planDigest: task.plan?.digest ?? null },
48511
+ {
48512
+ activeChildTaskRefs: await project.store.listActiveChildTaskRefs(taskRef),
48513
+ hasPendingRepairOperation: false,
48514
+ activeClaimCount: 0
48515
+ }
48516
+ );
48517
+ return printV3Result(options.json, {
48518
+ delivery: "ready_for_complete",
48519
+ publication: "not_checked",
48520
+ note: "complete rechecks operation authority; upstream publication requires an actual push result"
48521
+ });
48522
+ }
48523
+ const expectedTaskRevision = Number(options.expectedRevision);
48524
+ if (!Number.isSafeInteger(expectedTaskRevision) || expectedTaskRevision < 1)
48525
+ throw new Error("MANCODE_EXPECTED_REVISION_REQUIRED");
48526
+ if (options.sync) throw new Error("MANCODE_GIT_REF_DEFERRED_SYNC_REQUIRED");
48527
+ const session = await resolveV3CommandSession(project, options);
48528
+ const context = await openV3TaskOperation({
48529
+ projectRoot: project.projectRoot,
48530
+ taskRef,
48531
+ sessionId: session.sessionId,
48532
+ expectedTaskRevision
48533
+ });
48534
+ const actorId = context.session.actorId;
48535
+ try {
48536
+ task = context.task;
48537
+ if (action === "sync") {
48538
+ const progress = await syncManDeliveryRecord(project.projectRoot, task);
48539
+ const synced = await project.store.readTaskSnapshot(taskRef);
48540
+ const finalization2 = await inspectFinalization(
48541
+ project.projectRoot,
48542
+ synced
48543
+ );
48544
+ return printV3Result(options.json, {
48545
+ deliveryRecord: "synced",
48546
+ progress,
48547
+ revision: synced.metadata.revision,
48548
+ finalization: finalization2
48549
+ });
48550
+ }
48551
+ if (task.metadata.governance.planDecision !== "governed_execution" || task.metadata.currentStep < 5 || task.metadata.status !== "in_progress") {
48552
+ throw new Error("MANCODE_MAN_DELIVERY_EXECUTION_REQUIRED");
48553
+ }
48554
+ } finally {
48555
+ await context.release();
48556
+ }
48557
+ if (!options.file) throw new Error("MANCODE_MAN_DELIVERY_INPUT_REQUIRED");
48558
+ const input = JSON.parse(
48559
+ await readFile50(path73.resolve(project.projectRoot, options.file), "utf8")
48560
+ );
48561
+ let output;
48562
+ if (action === "verify" || action === "confirm") {
48563
+ assertRecord(input, "verification command");
48564
+ assertKnownKeys(
48565
+ input,
48566
+ action === "verify" ? ["argv", "surface"] : ["confirmed", "summary", "surface"],
48567
+ "verification command"
48568
+ );
48569
+ if (action === "verify" && (!Array.isArray(input.argv) || !input.argv.length || input.argv.some(
48570
+ (arg) => typeof arg !== "string" || arg.includes("\0")
48571
+ ) || !input.argv[0]))
48572
+ throw new Error("MANCODE_MAN_VERIFY_ARGV_INVALID");
48573
+ if (action === "confirm" && (input.confirmed !== true || typeof input.summary !== "string" || !input.summary.trim()))
48574
+ throw new Error("MANCODE_MAN_EXPLICIT_CONFIRMATION_REQUIRED");
48575
+ const surface = parseManVerificationSurface(input.surface);
48576
+ const checks = verificationChecks(task);
48577
+ const acceptanceIds = options.acceptance?.split(",").map((id) => id.trim()) ?? [];
48578
+ const component = action === "verify" ? "automated" : "manual";
48579
+ if (!acceptanceIds.length || new Set(acceptanceIds).size !== acceptanceIds.length || acceptanceIds.some(
48580
+ (id) => !checks.some(
48581
+ (check) => check.displayId === id && check[component] !== null
48582
+ )
48583
+ ))
48584
+ throw new Error("MANCODE_MAN_ACCEPTANCE_SLOT_REQUIRED");
48585
+ const subject = await captureManSubject(project.projectRoot, task);
48586
+ let result2 = {
48587
+ stdout: "",
48588
+ stderr: "",
48589
+ exitCode: 0
48590
+ };
48591
+ if (action === "verify") {
48592
+ const argv = input.argv;
48593
+ try {
48594
+ const run = await execFile11(argv[0], argv.slice(1), {
48595
+ cwd: project.projectRoot,
48596
+ encoding: "utf8",
48597
+ maxBuffer: 8 * 1024 * 1024
48598
+ });
48599
+ result2 = { ...run, exitCode: 0 };
48600
+ } catch (error) {
48601
+ const failed = error;
48602
+ if (typeof failed.code !== "number") throw error;
48603
+ result2 = {
48604
+ exitCode: failed.code,
48605
+ stdout: failed.stdout ?? "",
48606
+ stderr: failed.stderr ?? ""
48607
+ };
48608
+ }
48609
+ }
48610
+ if ((await captureManSubject(project.projectRoot, task)).contentDigest !== subject.contentDigest)
48611
+ throw new Error("MANCODE_MAN_VERIFICATION_CHANGED_DURING_RUN");
48612
+ const timestamp4 = (/* @__PURE__ */ new Date()).toISOString();
48613
+ const invalidate = (evidence) => {
48614
+ if (!evidence || evidence.subject?.contentDigest === subject.contentDigest && evidence.subject.environment === subject.environment)
48615
+ return evidence;
48616
+ const {
48617
+ subject: _oldSubject,
48618
+ surface: _oldSurface,
48619
+ ...rest
48620
+ } = evidence;
48621
+ return {
48622
+ ...rest,
48623
+ status: "pending",
48624
+ summary: null,
48625
+ command: null,
48626
+ exitCode: null,
48627
+ artifactRef: null,
48628
+ confirmedByActorId: null,
48629
+ confirmationSource: null,
48630
+ updatedAt: timestamp4
48631
+ };
48632
+ };
48633
+ const draft = {
48634
+ ...task.verification,
48635
+ requirementsDigest: task.requirements.contentDigest,
48636
+ planVersion: task.metadata.governance.planVersion,
48637
+ remediationRound: task.review.remediationRound,
48638
+ checks: checks.map((item) => {
48639
+ const next = {
48640
+ ...item,
48641
+ automated: invalidate(item.automated),
48642
+ manual: invalidate(item.manual)
48643
+ };
48644
+ const slot = item[component];
48645
+ if (acceptanceIds.includes(item.displayId) && slot)
48646
+ next[component] = {
48647
+ ...slot,
48648
+ subject,
48649
+ surface,
48650
+ status: result2.exitCode === 0 ? "passed" : "failed",
48651
+ command: action === "verify" ? JSON.stringify(input.argv) : null,
48652
+ exitCode: action === "verify" ? result2.exitCode : null,
48653
+ summary: action === "verify" ? `Executed argv in project root; captured exit code ${result2.exitCode}.` : input.summary,
48654
+ confirmedByActorId: action === "confirm" ? actorId : null,
48655
+ confirmationSource: action === "confirm" ? "actor" : null,
48656
+ updatedAt: timestamp4
48657
+ };
48658
+ return next;
48659
+ })
48660
+ };
48661
+ const current = {
48662
+ ...draft,
48663
+ status: deriveVerificationLedgerStatus(draft)
48664
+ };
48665
+ output = {
48666
+ ...await recordV3Verification({
48667
+ projectRoot: project.projectRoot,
48668
+ taskRef,
48669
+ sessionId: session.sessionId,
48670
+ expectedTaskRevision,
48671
+ verification: {
48672
+ ...current,
48673
+ contentDigest: verificationLedgerDigest(current)
48674
+ }
48675
+ }),
48676
+ ...action === "verify" ? { commandResult: result2 } : { manualConfirmation: { actorId, summary: input.summary } }
48677
+ };
48678
+ } else {
48679
+ output = await applyV3ReviewLedger({
48680
+ projectRoot: project.projectRoot,
48681
+ taskRef,
48682
+ sessionId: session.sessionId,
48683
+ expectedTaskRevision,
48684
+ review: reviewInput(task, input, options.reviewDepth)
48685
+ });
48686
+ }
48687
+ const updated = await project.store.readTaskSnapshot(taskRef);
48688
+ let deliveryRecord = { status: "synced" };
48689
+ try {
48690
+ deliveryRecord.progress = await syncManDeliveryRecord(
48691
+ project.projectRoot,
48692
+ updated
48693
+ );
48694
+ } catch (error) {
48695
+ deliveryRecord = {
48696
+ status: "pending",
48697
+ error: error instanceof Error ? error.message : String(error)
48698
+ };
48699
+ }
48700
+ const finalization = await inspectFinalization(
48701
+ project.projectRoot,
48702
+ updated
48703
+ );
48704
+ return printV3Result(options.json, {
48705
+ result: output,
48706
+ deliveryRecord,
48707
+ revision: updated.metadata.revision,
48708
+ finalization
48709
+ });
48710
+ } catch (error) {
48711
+ return printV3Error(
48712
+ options.json,
48713
+ v3ErrorCode(error, "MANCODE_MAN_DELIVERY_FAILED"),
48714
+ error instanceof Error ? error.message : String(error)
48715
+ );
48716
+ }
48717
+ }
48718
+ async function inspectFinalization(root, task) {
48719
+ try {
48720
+ return (await inspectManDelivery(root, task)).finalization;
48721
+ } catch (error) {
48722
+ return manInspectionFailureFinalization(error);
48723
+ }
48724
+ }
48725
+ function verificationChecks(task) {
48726
+ const emptySlot = () => ({
48727
+ evidenceId: createUlid(),
48728
+ status: "pending",
48729
+ summary: null,
48730
+ command: null,
48731
+ exitCode: null,
48732
+ artifactRef: null,
48733
+ confirmedByActorId: null,
48734
+ confirmationSource: null,
48735
+ updatedAt: null
48736
+ });
48737
+ return task.requirements.acceptanceCriteria.map((criterion) => {
48738
+ const previous = task.verification.checks.find(
48739
+ (check) => check.criterionId === criterion.criterionId && check.verificationRequirement === criterion.verificationRequirement
48740
+ );
48741
+ return previous ?? {
48742
+ displayId: criterion.displayId,
48743
+ legacyId: criterion.legacyId,
48744
+ checkId: createUlid(),
48745
+ criterionId: criterion.criterionId,
48746
+ required: criterion.required,
48747
+ verificationRequirement: criterion.verificationRequirement,
48748
+ automated: criterion.verificationRequirement === "manual" ? null : emptySlot(),
48749
+ manual: criterion.verificationRequirement === "automated" ? null : emptySlot()
48750
+ };
48751
+ });
48752
+ }
48753
+ function reviewInput(task, input, depth) {
48754
+ assertRecord(input, "module review");
48755
+ const { findings = [], resolved = [], ...report } = input;
48756
+ const delivery = parseManReviewEvidence(report);
48757
+ if (!Array.isArray(findings) || !Array.isArray(resolved) || resolved.some((id) => typeof id !== "string"))
48758
+ throw new Error("MANCODE_MAN_REVIEW_FINDINGS_INVALID");
48759
+ if (resolved.some(
48760
+ (id) => !task.review.blockers.some((blocker) => blocker.displayId === id)
48761
+ ))
48762
+ throw new Error("MANCODE_MAN_REVIEW_UNKNOWN_FINDING");
48763
+ const blockers = task.review.blockers.map(
48764
+ (blocker) => resolved.includes(blocker.displayId) ? { ...blocker, status: "resolved" } : blocker
48765
+ );
48766
+ const ids = /* @__PURE__ */ new Set();
48767
+ for (const finding of findings) {
48768
+ assertRecord(finding, "module review finding");
48769
+ assertKnownKeys(
48770
+ finding,
48771
+ ["id", "domain", "severity", "summary"],
48772
+ "module review finding"
48773
+ );
48774
+ if (typeof finding.id !== "string" || !finding.id.trim() || ids.has(finding.id) || typeof finding.summary !== "string" || !finding.summary.trim() || finding.domain !== "quality" && finding.domain !== "security" || !["p0", "p1", "p2"].includes(String(finding.severity)))
48775
+ throw new Error("MANCODE_MAN_REVIEW_FINDINGS_INVALID");
48776
+ ids.add(finding.id);
48777
+ const previous = blockers.find((item) => item.displayId === finding.id);
48778
+ const entry = {
48779
+ displayId: finding.id,
48780
+ legacyId: null,
48781
+ blockerId: previous?.blockerId ?? createUlid(),
48782
+ domain: finding.domain,
48783
+ severity: finding.severity,
48784
+ status: "open",
48785
+ summary: finding.summary,
48786
+ waiver: null
48787
+ };
48788
+ if (previous) blockers[blockers.indexOf(previous)] = entry;
48789
+ else blockers.push(entry);
48790
+ }
48791
+ if (depth !== void 0 && depth !== "targeted" && depth !== "full")
48792
+ throw new Error("MANCODE_MAN_REVIEW_DEPTH_INVALID");
48793
+ const full = depth === "full" || task.review.depth === "full" || blockers.some((item) => item.domain === "security");
48794
+ const requiredDomains = full ? ["quality", "security"] : ["quality"];
48795
+ const covered = task.requirements.acceptanceCriteria.filter((item) => item.required).every(
48796
+ (criterion) => delivery.coverage.some(
48797
+ (row) => row.acceptanceId === criterion.displayId && row.status === "met"
48798
+ )
48799
+ );
48800
+ const draft = {
48801
+ ...task.review,
48802
+ delivery,
48803
+ depth: full ? "full" : "targeted",
48804
+ requiredDomains: [...requiredDomains],
48805
+ requirementsDigest: task.requirements.contentDigest,
48806
+ planVersion: task.metadata.governance.planVersion,
48807
+ domains: requiredDomains.map((domain) => ({
48808
+ domain,
48809
+ status: blockers.some(
48810
+ (item) => item.domain === domain && item.status === "open"
48811
+ ) || !covered ? "blocked" : "passed",
48812
+ reportRef: null
48813
+ })),
48814
+ blockers,
48815
+ skip: null,
48816
+ remediationRound: task.review.remediationRound + (resolved.length ? 1 : 0)
48817
+ };
48818
+ const current = { ...draft, status: deriveReviewLedgerStatus(draft) };
48819
+ return { ...current, contentDigest: reviewLedgerDigest(current) };
48820
+ }
48821
+
46873
48822
  // src/commands/requirements-input.ts
46874
48823
  function normalizeRequirementsInput(value, requestedTaskRef, now = /* @__PURE__ */ new Date(), options = {}) {
46875
48824
  if (isRecord14(value) && "schemaVersion" in value) {
@@ -46921,7 +48870,8 @@ function buildCanonicalRequirements(semantic, requestedTaskRef, now) {
46921
48870
  requirementIds: [],
46922
48871
  statement: item.description,
46923
48872
  required: item.required,
46924
- verificationRequirement: item.method
48873
+ verificationRequirement: item.method,
48874
+ ...item.verificationSurfaces === void 0 ? {} : { verificationSurfaces: item.verificationSurfaces }
46925
48875
  })),
46926
48876
  blockingUnknowns: semantic.blockingUnknowns.map((statement, index) => ({
46927
48877
  displayId: `U-${index + 1}`,
@@ -46953,7 +48903,14 @@ async function workflow(rootDir, subcommand, args = [], options = {}) {
46953
48903
  if (v3Activation === "v3_active") {
46954
48904
  return workflowV3(rootDir, subcommand, args, options);
46955
48905
  }
46956
- if (!await pathExists16(path70.join(rootDir, ".mancode", "state.json"))) {
48906
+ if (options.delivery || subcommand === "delivery") {
48907
+ return printV3Error(
48908
+ options.json,
48909
+ "MANCODE_MAN_DELIVERY_REQUIRES_CONTINUITY",
48910
+ "Man delivery requires Continuity; legacy workflows are unchanged."
48911
+ );
48912
+ }
48913
+ if (!await pathExists16(path74.join(rootDir, ".mancode", "state.json"))) {
46957
48914
  if (v3Activation !== null) {
46958
48915
  return printV3Error(
46959
48916
  options.json,
@@ -47009,6 +48966,7 @@ async function workflow(rootDir, subcommand, args = [], options = {}) {
47009
48966
  }
47010
48967
  }
47011
48968
  var WORKFLOW_V3_HANDLERS = {
48969
+ delivery: manDeliveryCommand,
47012
48970
  create: workflowCreateV3,
47013
48971
  list: workflowListV3,
47014
48972
  show: workflowShowV3,
@@ -47913,6 +49871,7 @@ async function workflowPlanV3(rootDir, args, options) {
47913
49871
  sessionId: session.sessionId,
47914
49872
  expectedTaskRevision,
47915
49873
  plan,
49874
+ planSource: action === "revise" && isManDelivery((await project.store.readTaskSnapshot(taskRef)).metadata) ? options.file : void 0,
47916
49875
  implementationScope,
47917
49876
  planDecision: parseV3PlanDecision(options.planDecision)
47918
49877
  });
@@ -48036,8 +49995,8 @@ function parseV3ParticipantActorIds(values) {
48036
49995
  return values;
48037
49996
  }
48038
49997
  async function readWorkflowInputFile(projectRoot, value) {
48039
- const inputPath = path70.isAbsolute(value) ? value : path70.resolve(projectRoot, value);
48040
- return readFile48(inputPath, "utf8");
49998
+ const inputPath = path74.isAbsolute(value) ? value : path74.resolve(projectRoot, value);
49999
+ return readFile51(inputPath, "utf8");
48041
50000
  }
48042
50001
  async function readWorkflowJsonInputFile(projectRoot, value) {
48043
50002
  return JSON.parse(await readWorkflowInputFile(projectRoot, value));
@@ -48077,6 +50036,7 @@ async function workflowCreateV3(rootDir, args, options) {
48077
50036
  evaluatedAt: (/* @__PURE__ */ new Date()).toISOString()
48078
50037
  });
48079
50038
  const result2 = await createV3Workflow({
50039
+ delivery: options.delivery,
48080
50040
  projectRoot: project.projectRoot,
48081
50041
  task,
48082
50042
  workflowMode: parsedWorkflowMode,
@@ -48110,7 +50070,7 @@ async function readV3ActivationState2(rootDir) {
48110
50070
  try {
48111
50071
  const manifest = parseSchemaManifest(
48112
50072
  JSON.parse(
48113
- await readFile48(path70.join(rootDir, ".mancode", "schema.json"), "utf8")
50073
+ await readFile51(path74.join(rootDir, ".mancode", "schema.json"), "utf8")
48114
50074
  )
48115
50075
  );
48116
50076
  return manifest.activationState === "v3_active" ? "v3_active" : "other";
@@ -48155,22 +50115,22 @@ async function workflowRequirements(rootDir, args, options) {
48155
50115
  "requirements can only be finalized for an in-progress man or manteam workflow at step 1 or 2"
48156
50116
  );
48157
50117
  }
48158
- const workflowPath = path70.join(rootDir, ".mancode", "workflows", taskId);
48159
- const jsonPath = path70.join(workflowPath, "requirements.json");
48160
- const markdownPath = path70.join(workflowPath, "requirements.md");
48161
- const metadataPath3 = path70.join(workflowPath, "metadata.json");
50118
+ const workflowPath = path74.join(rootDir, ".mancode", "workflows", taskId);
50119
+ const jsonPath = path74.join(workflowPath, "requirements.json");
50120
+ const markdownPath = path74.join(workflowPath, "requirements.md");
50121
+ const metadataPath3 = path74.join(workflowPath, "metadata.json");
48162
50122
  let originalJson;
48163
50123
  let originalMarkdown;
48164
50124
  let originalMetadata;
48165
50125
  try {
48166
- const inputPath = path70.isAbsolute(options.file) ? options.file : path70.resolve(rootDir, options.file);
48167
- const input = await readFile48(inputPath, "utf-8");
50126
+ const inputPath = path74.isAbsolute(options.file) ? options.file : path74.resolve(rootDir, options.file);
50127
+ const input = await readFile51(inputPath, "utf-8");
48168
50128
  const requirements = parseRequirementsLedger2(input);
48169
50129
  assertRequirementsScopeConsistent2(requirements);
48170
50130
  [originalJson, originalMarkdown, originalMetadata] = await Promise.all([
48171
50131
  readOptionalText2(jsonPath),
48172
50132
  readOptionalText2(markdownPath),
48173
- readFile48(metadataPath3, "utf-8")
50133
+ readFile51(metadataPath3, "utf-8")
48174
50134
  ]);
48175
50135
  await writeRequirementsArtifacts(rootDir, taskId, requirements);
48176
50136
  await updateWorkflow(rootDir, taskId, {
@@ -48200,7 +50160,7 @@ async function workflowRequirements(rootDir, args, options) {
48200
50160
  const rollback = await Promise.allSettled([
48201
50161
  restoreOptionalText(jsonPath, originalJson),
48202
50162
  restoreOptionalText(markdownPath, originalMarkdown),
48203
- writeFile51(metadataPath3, originalMetadata, "utf-8")
50163
+ writeFile53(metadataPath3, originalMetadata, "utf-8")
48204
50164
  ]);
48205
50165
  rollbackIncomplete = rollback.some(
48206
50166
  (result2) => result2.status === "rejected"
@@ -48288,7 +50248,7 @@ async function workflowVerify(rootDir, args, options) {
48288
50248
  );
48289
50249
  }
48290
50250
  if (options.evidenceFile) {
48291
- const evidencePath = path70.isAbsolute(options.evidenceFile) ? options.evidenceFile : path70.resolve(rootDir, options.evidenceFile);
50251
+ const evidencePath = path74.isAbsolute(options.evidenceFile) ? options.evidenceFile : path74.resolve(rootDir, options.evidenceFile);
48292
50252
  if (!await pathExists16(evidencePath)) {
48293
50253
  return invalidArg(
48294
50254
  options,
@@ -48348,17 +50308,17 @@ async function workflowVerify(rootDir, args, options) {
48348
50308
  }
48349
50309
  async function commitVerificationTransition(rootDir, meta, ledger) {
48350
50310
  const ledgerPath = verificationLedgerPath(rootDir, meta.taskId);
48351
- const metadataPath3 = path70.join(
50311
+ const metadataPath3 = path74.join(
48352
50312
  rootDir,
48353
50313
  ".mancode",
48354
50314
  "workflows",
48355
50315
  meta.taskId,
48356
50316
  "metadata.json"
48357
50317
  );
48358
- const specPath = path70.join(rootDir, ".mancode", "memory", "spec.md");
50318
+ const specPath = path74.join(rootDir, ".mancode", "memory", "spec.md");
48359
50319
  const [originalLedger, originalMetadata, originalSpec] = await Promise.all([
48360
50320
  readOptionalText2(ledgerPath),
48361
- readFile48(metadataPath3, "utf-8"),
50321
+ readFile51(metadataPath3, "utf-8"),
48362
50322
  readOptionalText2(specPath)
48363
50323
  ]);
48364
50324
  const wasVerificationBlocked = meta.status === "blocked" && meta.blockingReason?.startsWith("[verification]");
@@ -48387,7 +50347,7 @@ async function commitVerificationTransition(rootDir, meta, ledger) {
48387
50347
  } catch (error) {
48388
50348
  const rollback = await Promise.allSettled([
48389
50349
  restoreOptionalText(ledgerPath, originalLedger),
48390
- writeFile51(metadataPath3, originalMetadata, "utf-8"),
50350
+ writeFile53(metadataPath3, originalMetadata, "utf-8"),
48391
50351
  restoreOptionalText(specPath, originalSpec)
48392
50352
  ]);
48393
50353
  const message = error instanceof Error ? error.message : "verification transition failed";
@@ -48519,7 +50479,7 @@ async function workflowReview(rootDir, args, options) {
48519
50479
  }
48520
50480
  async function commitReviewSkip(rootDir, meta, reason) {
48521
50481
  const ledgerPath = reviewLedgerPath(rootDir, meta.taskId);
48522
- const metadataPath3 = path70.join(
50482
+ const metadataPath3 = path74.join(
48523
50483
  rootDir,
48524
50484
  ".mancode",
48525
50485
  "workflows",
@@ -48528,7 +50488,7 @@ async function commitReviewSkip(rootDir, meta, reason) {
48528
50488
  );
48529
50489
  const [originalLedger, originalMetadata] = await Promise.all([
48530
50490
  readOptionalText2(ledgerPath),
48531
- readFile48(metadataPath3, "utf-8")
50491
+ readFile51(metadataPath3, "utf-8")
48532
50492
  ]);
48533
50493
  try {
48534
50494
  await initializeSkippedReview(rootDir, meta.taskId, reason);
@@ -48539,7 +50499,7 @@ async function commitReviewSkip(rootDir, meta, reason) {
48539
50499
  } catch (error) {
48540
50500
  const rollback = await Promise.allSettled([
48541
50501
  restoreOptionalText(ledgerPath, originalLedger),
48542
- writeFile51(metadataPath3, originalMetadata, "utf-8")
50502
+ writeFile53(metadataPath3, originalMetadata, "utf-8")
48543
50503
  ]);
48544
50504
  const message = error instanceof Error ? error.message : "review skip failed";
48545
50505
  return rollback.some((result2) => result2.status === "rejected") ? `${message}; rollback was incomplete` : message;
@@ -48759,18 +50719,18 @@ async function workflowHandoff(rootDir, taskId, options) {
48759
50719
  "solo handoff requires an undecided in-progress workflow at step 4 with ready requirements"
48760
50720
  );
48761
50721
  }
48762
- const workflowPath = path70.join(rootDir, ".mancode", "workflows", taskId);
48763
- if (!await pathExists16(path70.join(workflowPath, "requirements.md")) || !await pathExists16(path70.join(workflowPath, "plan.md"))) {
50722
+ const workflowPath = path74.join(rootDir, ".mancode", "workflows", taskId);
50723
+ if (!await pathExists16(path74.join(workflowPath, "requirements.md")) || !await pathExists16(path74.join(workflowPath, "plan.md"))) {
48764
50724
  return invalidArg(
48765
50725
  options,
48766
50726
  "solo handoff requires requirements.md and plan.md"
48767
50727
  );
48768
50728
  }
48769
- const statePath = path70.join(rootDir, ".mancode", "state.json");
50729
+ const statePath = path74.join(rootDir, ".mancode", "state.json");
48770
50730
  let originalState;
48771
50731
  let state;
48772
50732
  try {
48773
- originalState = await readFile48(statePath, "utf-8");
50733
+ originalState = await readFile51(statePath, "utf-8");
48774
50734
  state = JSON.parse(originalState);
48775
50735
  } catch {
48776
50736
  return invalidArg(
@@ -48841,11 +50801,11 @@ async function workflowCompleteHandoff(rootDir, taskId, options) {
48841
50801
  `workflow is not an active solo handoff: ${taskId}`
48842
50802
  );
48843
50803
  }
48844
- const statePath = path70.join(rootDir, ".mancode", "state.json");
50804
+ const statePath = path74.join(rootDir, ".mancode", "state.json");
48845
50805
  let originalState;
48846
50806
  let state;
48847
50807
  try {
48848
- originalState = await readFile48(statePath, "utf-8");
50808
+ originalState = await readFile51(statePath, "utf-8");
48849
50809
  state = JSON.parse(originalState);
48850
50810
  } catch {
48851
50811
  return invalidArg(
@@ -48908,18 +50868,18 @@ async function workflowDecide(rootDir, taskId, options) {
48908
50868
  `workflow is not ready for a plan-only decision: ${taskId}`
48909
50869
  );
48910
50870
  }
48911
- const workflowPath = path70.join(rootDir, ".mancode", "workflows", taskId);
48912
- if (!await pathExists16(path70.join(workflowPath, "requirements.md")) || !await pathExists16(path70.join(workflowPath, "plan.md"))) {
50871
+ const workflowPath = path74.join(rootDir, ".mancode", "workflows", taskId);
50872
+ if (!await pathExists16(path74.join(workflowPath, "requirements.md")) || !await pathExists16(path74.join(workflowPath, "plan.md"))) {
48913
50873
  return invalidArg(
48914
50874
  options,
48915
50875
  "plan-only requires requirements.md and plan.md"
48916
50876
  );
48917
50877
  }
48918
- const statePath = path70.join(rootDir, ".mancode", "state.json");
50878
+ const statePath = path74.join(rootDir, ".mancode", "state.json");
48919
50879
  let originalState;
48920
50880
  let state;
48921
50881
  try {
48922
- originalState = await readFile48(statePath, "utf-8");
50882
+ originalState = await readFile51(statePath, "utf-8");
48923
50883
  state = JSON.parse(originalState);
48924
50884
  } catch {
48925
50885
  return invalidArg(
@@ -48971,25 +50931,25 @@ async function workflowDecide(rootDir, taskId, options) {
48971
50931
  return EXIT_OK11;
48972
50932
  }
48973
50933
  async function commitPlanningTransition(args) {
48974
- const metadataPath3 = path70.join(
50934
+ const metadataPath3 = path74.join(
48975
50935
  args.rootDir,
48976
50936
  ".mancode",
48977
50937
  "workflows",
48978
50938
  args.taskId,
48979
50939
  "metadata.json"
48980
50940
  );
48981
- const specPath = path70.join(args.rootDir, ".mancode", "memory", "spec.md");
50941
+ const specPath = path74.join(args.rootDir, ".mancode", "memory", "spec.md");
48982
50942
  let originalMetadata;
48983
50943
  let originalSpec;
48984
50944
  try {
48985
- originalMetadata = await readFile48(metadataPath3, "utf-8");
50945
+ originalMetadata = await readFile51(metadataPath3, "utf-8");
48986
50946
  originalSpec = await readOptionalText2(specPath);
48987
50947
  } catch (error) {
48988
50948
  return error instanceof Error ? `unable to prepare planning transition: ${error.message}` : "unable to prepare planning transition";
48989
50949
  }
48990
50950
  try {
48991
50951
  await updateWorkflow(args.rootDir, args.taskId, args.workflowPatch);
48992
- await writeFile51(
50952
+ await writeFile53(
48993
50953
  args.statePath,
48994
50954
  `${JSON.stringify(args.nextState, null, 2)}
48995
50955
  `,
@@ -49003,9 +50963,9 @@ async function commitPlanningTransition(args) {
49003
50963
  return null;
49004
50964
  } catch (error) {
49005
50965
  const rollback = await Promise.allSettled([
49006
- writeFile51(metadataPath3, originalMetadata, "utf-8"),
49007
- writeFile51(args.statePath, args.originalState, "utf-8"),
49008
- originalSpec === null ? rm24(specPath, { force: true }) : writeFile51(specPath, originalSpec, "utf-8")
50966
+ writeFile53(metadataPath3, originalMetadata, "utf-8"),
50967
+ writeFile53(args.statePath, args.originalState, "utf-8"),
50968
+ originalSpec === null ? rm26(specPath, { force: true }) : writeFile53(specPath, originalSpec, "utf-8")
49009
50969
  ]);
49010
50970
  const message = error instanceof Error ? error.message : "planning transition failed";
49011
50971
  return rollback.some((result2) => result2.status === "rejected") ? `${message}; rollback was incomplete` : message;
@@ -49013,7 +50973,7 @@ async function commitPlanningTransition(args) {
49013
50973
  }
49014
50974
  async function readOptionalText2(filePath) {
49015
50975
  try {
49016
- return await readFile48(filePath, "utf-8");
50976
+ return await readFile51(filePath, "utf-8");
49017
50977
  } catch (error) {
49018
50978
  if (isNodeError11(error) && error.code === "ENOENT") return null;
49019
50979
  throw error;
@@ -49021,10 +50981,10 @@ async function readOptionalText2(filePath) {
49021
50981
  }
49022
50982
  async function restoreOptionalText(filePath, content) {
49023
50983
  if (content === null) {
49024
- await rm24(filePath, { force: true });
50984
+ await rm26(filePath, { force: true });
49025
50985
  return;
49026
50986
  }
49027
- await writeFile51(filePath, content, "utf-8");
50987
+ await writeFile53(filePath, content, "utf-8");
49028
50988
  }
49029
50989
  function readActiveSoloPlan(value) {
49030
50990
  if (!value || typeof value !== "object") return null;
@@ -49371,7 +51331,10 @@ Public Continuity subcommands:
49371
51331
  ).option("--to <mode>", "Workflow handoff target (solo)").option("--complete", "Complete an active solo handoff").option(
49372
51332
  "--skipped <steps>",
49373
51333
  "Policy v2: clarification only; use workflow review skip for review"
49374
- ).option("--review-depth <depth>", "Review depth: targeted or full").option("--review-domain <domain>", "Review domain: quality or security").option(
51334
+ ).option("--review-depth <depth>", "Review depth: targeted or full").option(
51335
+ "--delivery",
51336
+ "Opt in a new man task to document-bound module delivery"
51337
+ ).option("--review-domain <domain>", "Review domain: quality or security").option(
49375
51338
  "--report <path>",
49376
51339
  "Relative Markdown report path for a review domain"
49377
51340
  ).option("--blockers <ids>", "Comma-separated blocker ids found by a review").option(
@@ -49520,7 +51483,10 @@ Public Continuity subcommands:
49520
51483
  options
49521
51484
  );
49522
51485
  });
49523
- operationProgram.command("repair <operationId>").description("Repair an operation using its original actor and session").option("--session <id>", "Session ID (otherwise MANCODE_SESSION_ID)").option("--client <name>", "Client identity (default: mancode-cli)").option("--json", "Output as JSON (for scripts)").action(async (operationId, options) => {
51486
+ operationProgram.command("repair <operationId>").description("Repair an operation using its original actor and session").option(
51487
+ "--replacement-checkpoint-id <id>",
51488
+ "Replace only a conflicted reframe checkpoint target"
51489
+ ).option("--session <id>", "Session ID (otherwise MANCODE_SESSION_ID)").option("--client <name>", "Client identity (default: mancode-cli)").option("--json", "Output as JSON (for scripts)").action(async (operationId, options) => {
49524
51490
  process.exitCode = await operationRepair(
49525
51491
  process.cwd(),
49526
51492
  operationId,