@open-agent-toolkit/cli 0.3.7 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/README.md +3 -3
  2. package/assets/agents/oat-codebase-mapper.md +3 -2
  3. package/assets/agents/oat-reviewer.md +5 -13
  4. package/assets/agents/skeptical-evaluator.md +6 -2
  5. package/assets/bundle-metadata.json +1 -1
  6. package/assets/docs/cli-utilities/backlog-lifecycle.md +3 -2
  7. package/assets/docs/cli-utilities/bootstrap.md +5 -2
  8. package/assets/docs/cli-utilities/config-and-local-state.md +13 -6
  9. package/assets/docs/cli-utilities/configuration.md +25 -10
  10. package/assets/docs/cli-utilities/tool-packs.md +60 -10
  11. package/assets/docs/cli-utilities/workflow-gates.md +37 -0
  12. package/assets/docs/contributing/code.md +9 -5
  13. package/assets/docs/provider-sync/commands.md +17 -8
  14. package/assets/docs/provider-sync/instruction-sync.md +241 -39
  15. package/assets/docs/provider-sync/providers.md +20 -0
  16. package/assets/docs/provider-sync/scope-and-surface.md +3 -1
  17. package/assets/docs/reference/cli-reference.md +4 -1
  18. package/assets/docs/reference/oat-directory-structure.md +12 -11
  19. package/assets/docs/reference/troubleshooting.md +19 -4
  20. package/assets/docs/workflows/projects/evidence-layers.md +5 -1
  21. package/assets/docs/workflows/projects/implementation-execution.md +22 -8
  22. package/assets/docs/workflows/projects/lifecycle.md +4 -6
  23. package/assets/docs/workflows/projects/retro.md +7 -0
  24. package/assets/public-package-versions.json +4 -4
  25. package/assets/skills/oat-agent-instructions-analyze/SKILL.md +4 -4
  26. package/assets/skills/oat-agent-instructions-analyze/references/analysis-artifact-template.md +5 -5
  27. package/assets/skills/oat-agent-instructions-analyze/references/docs/rules-files.md +14 -11
  28. package/assets/skills/oat-agent-instructions-analyze/references/quality-checklist.md +2 -2
  29. package/assets/skills/oat-agent-instructions-analyze/scripts/resolve-instruction-files.sh +4 -3
  30. package/assets/skills/oat-agent-instructions-analyze/scripts/resolve-providers.sh +17 -6
  31. package/assets/skills/oat-agent-instructions-apply/SKILL.md +3 -3
  32. package/assets/skills/oat-agent-instructions-apply/references/docs/rules-files.md +14 -11
  33. package/assets/skills/oat-dispatch-subagents/SKILL.md +1 -1
  34. package/assets/skills/oat-dispatch-subagents/references/managed-claude-example.json +387 -0
  35. package/assets/skills/oat-dispatch-subagents/references/record-schema.md +75 -0
  36. package/assets/skills/oat-doctor/SKILL.md +17 -13
  37. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
  38. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
  39. package/assets/skills/oat-project-implement/SKILL.md +2 -2
  40. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +33 -11
  41. package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +24 -22
  42. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
  43. package/assets/skills/oat-project-implement/references/phase-execution.md +109 -8
  44. package/assets/skills/oat-project-lite/SKILL.md +23 -1
  45. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +1 -1
  46. package/assets/skills/oat-project-next/SKILL.md +3 -3
  47. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
  48. package/assets/skills/oat-project-progress/SKILL.md +2 -2
  49. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
  50. package/assets/skills/oat-project-retro/SKILL.md +70 -6
  51. package/assets/skills/oat-project-review-provide/SKILL.md +3 -1
  52. package/assets/skills/oat-project-review-provide-remote/SKILL.md +3 -1
  53. package/assets/templates/docs-app-mkdocs/docs/contributing.md +1 -3
  54. package/assets/templates/pjm-agents.md +7 -3
  55. package/assets/templates/state.md +2 -2
  56. package/dist/agents/canonical/resolve.d.ts +6 -4
  57. package/dist/agents/canonical/resolve.d.ts.map +1 -1
  58. package/dist/agents/canonical/resolve.js +6 -4
  59. package/dist/commands/backlog/archive.d.ts +10 -2
  60. package/dist/commands/backlog/archive.d.ts.map +1 -1
  61. package/dist/commands/backlog/archive.js +22 -6
  62. package/dist/commands/backlog/index.d.ts.map +1 -1
  63. package/dist/commands/backlog/index.js +5 -1
  64. package/dist/commands/backlog/rewrite-references.d.ts +41 -0
  65. package/dist/commands/backlog/rewrite-references.d.ts.map +1 -0
  66. package/dist/commands/backlog/rewrite-references.js +516 -0
  67. package/dist/commands/config/index.d.ts +1 -0
  68. package/dist/commands/config/index.d.ts.map +1 -1
  69. package/dist/commands/config/index.js +69 -34
  70. package/dist/commands/gate/index.d.ts.map +1 -1
  71. package/dist/commands/gate/index.js +51 -2
  72. package/dist/commands/gate/review-verdict.d.ts +22 -0
  73. package/dist/commands/gate/review-verdict.d.ts.map +1 -1
  74. package/dist/commands/gate/review-verdict.js +111 -0
  75. package/dist/commands/init/index.d.ts +6 -0
  76. package/dist/commands/init/index.d.ts.map +1 -1
  77. package/dist/commands/init/index.js +27 -4
  78. package/dist/commands/init/tools/index.d.ts +18 -1
  79. package/dist/commands/init/tools/index.d.ts.map +1 -1
  80. package/dist/commands/init/tools/index.js +84 -17
  81. package/dist/commands/init/tools/project-guidance.d.ts +19 -4
  82. package/dist/commands/init/tools/project-guidance.d.ts.map +1 -1
  83. package/dist/commands/init/tools/project-guidance.js +58 -15
  84. package/dist/commands/init/tools/workflows/index.d.ts.map +1 -1
  85. package/dist/commands/init/tools/workflows/index.js +5 -1
  86. package/dist/commands/instructions/instructions.types.d.ts +105 -4
  87. package/dist/commands/instructions/instructions.types.d.ts.map +1 -1
  88. package/dist/commands/instructions/instructions.types.js +4 -5
  89. package/dist/commands/instructions/instructions.utils.d.ts +161 -6
  90. package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
  91. package/dist/commands/instructions/instructions.utils.js +650 -12
  92. package/dist/commands/instructions/sync/sync.d.ts.map +1 -1
  93. package/dist/commands/instructions/sync/sync.js +256 -18
  94. package/dist/commands/instructions/validate/validate.d.ts.map +1 -1
  95. package/dist/commands/instructions/validate/validate.js +36 -8
  96. package/dist/commands/pjm/index.d.ts.map +1 -1
  97. package/dist/commands/pjm/index.js +19 -4
  98. package/dist/commands/pjm/init.d.ts +3 -0
  99. package/dist/commands/pjm/init.d.ts.map +1 -1
  100. package/dist/commands/pjm/init.js +23 -5
  101. package/dist/commands/project/dispatch/canonical-role.d.ts +33 -0
  102. package/dist/commands/project/dispatch/canonical-role.d.ts.map +1 -0
  103. package/dist/commands/project/dispatch/canonical-role.js +114 -0
  104. package/dist/commands/project/dispatch/index.d.ts.map +1 -1
  105. package/dist/commands/project/dispatch/index.js +3 -1
  106. package/dist/commands/project/dispatch/record.d.ts.map +1 -1
  107. package/dist/commands/project/dispatch/record.js +146 -4
  108. package/dist/commands/shared/agents-md.d.ts +26 -5
  109. package/dist/commands/shared/agents-md.d.ts.map +1 -1
  110. package/dist/commands/shared/agents-md.js +182 -3
  111. package/dist/commands/sync/apply.d.ts.map +1 -1
  112. package/dist/commands/sync/apply.js +28 -21
  113. package/dist/commands/tools/guidance/index.d.ts +15 -0
  114. package/dist/commands/tools/guidance/index.d.ts.map +1 -0
  115. package/dist/commands/tools/guidance/index.js +81 -0
  116. package/dist/commands/tools/index.d.ts.map +1 -1
  117. package/dist/commands/tools/index.js +2 -0
  118. package/dist/commands/tools/shared/sync-evidence.d.ts.map +1 -1
  119. package/dist/commands/tools/shared/sync-evidence.js +32 -5
  120. package/dist/config/oat-config.d.ts +57 -3
  121. package/dist/config/oat-config.d.ts.map +1 -1
  122. package/dist/config/oat-config.js +223 -15
  123. package/dist/config/resolve.d.ts.map +1 -1
  124. package/dist/config/resolve.js +12 -2
  125. package/dist/engine/compute-plan.d.ts.map +1 -1
  126. package/dist/engine/compute-plan.js +31 -3
  127. package/dist/providers/claude/dispatch-envelope.d.ts +53 -0
  128. package/dist/providers/claude/dispatch-envelope.d.ts.map +1 -1
  129. package/dist/providers/claude/dispatch-envelope.js +324 -48
  130. package/dist/providers/claude/rule-transform.js +1 -1
  131. package/dist/providers/copilot/rule-transform.js +1 -1
  132. package/dist/providers/cursor/rule-transform.js +1 -1
  133. package/dist/providers/identity/absolute-paths.d.ts +13 -0
  134. package/dist/providers/identity/absolute-paths.d.ts.map +1 -1
  135. package/dist/providers/identity/absolute-paths.js +27 -14
  136. package/dist/providers/identity/generic-dispatch-record.d.ts +212 -0
  137. package/dist/providers/identity/generic-dispatch-record.d.ts.map +1 -1
  138. package/dist/providers/identity/generic-dispatch-record.js +78 -19
  139. package/dist/providers/identity/oat-dispatch-record.d.ts +5 -0
  140. package/dist/providers/identity/oat-dispatch-record.d.ts.map +1 -1
  141. package/dist/providers/identity/oat-dispatch-record.js +11 -2
  142. package/dist/providers/shared/registry.d.ts +6 -0
  143. package/dist/providers/shared/registry.d.ts.map +1 -1
  144. package/dist/providers/shared/registry.js +30 -0
  145. package/dist/rules/canonical/parse.d.ts.map +1 -1
  146. package/dist/rules/canonical/parse.js +38 -3
  147. package/package.json +2 -2
@@ -8,6 +8,36 @@ import { normalizeDispatchMatrix, } from './dispatch-matrix.js';
8
8
  import { parseJsonConfig } from './json.js';
9
9
  import { resolveUserSyncConfig } from './user-sync-config.js';
10
10
  export { VALID_DISPATCH_MATRIX_TIERS, isCodexMaterializedRouteTarget, isWorkflowDispatchCandidateLadder, isWorkflowDispatchFallbackRoute, toWorkflowDispatchCandidateLadder, validateDispatchRouteTarget, } from './dispatch-matrix.js';
11
+ /**
12
+ * The CLAUDE.md strategies `oat instructions sync` and
13
+ * `oat instructions validate` understand, and the values
14
+ * `instructions.claude.shims` accepts. `none` keeps no CLAUDE.md
15
+ * shims at all; the other three are the shim strategies.
16
+ *
17
+ * Declared here rather than in the instructions command so the config
18
+ * normalizer, the `oat config set` validator, and the commands share one list:
19
+ * a value the normalizer accepted but the commands did not understand would
20
+ * silently fall through to the built-in default.
21
+ */
22
+ export const INSTRUCTION_SYNC_STRATEGIES = [
23
+ 'none',
24
+ 'pointer',
25
+ 'symlink',
26
+ 'copy',
27
+ ];
28
+ /**
29
+ * The strategy used when neither `--strategy` nor
30
+ * `instructions.claude.shims` names one.
31
+ *
32
+ * `none` (DR-260927-claude-md-shims-are-opt): Claude Code reads AGENTS.md
33
+ * itself through its `agents-md` plugin, which stands down for the whole
34
+ * project while any CLAUDE.md exists, so shims are opt-in.
35
+ */
36
+ export const DEFAULT_INSTRUCTION_SYNC_STRATEGY = 'none';
37
+ export function isInstructionSyncStrategy(value) {
38
+ return (typeof value === 'string' &&
39
+ INSTRUCTION_SYNC_STRATEGIES.includes(value));
40
+ }
11
41
  export const MIN_GATE_TIMEOUT_MS = 1_000;
12
42
  export const MAX_GATE_TIMEOUT_MS = 14_400_000;
13
43
  export function isValidGateTimeoutMs(value) {
@@ -635,13 +665,18 @@ function normalizePjmRemoteSharedConfig(value, configPath) {
635
665
  function assertClosedPjmRemoteSharedConfig(value, configPath) {
636
666
  const findings = [];
637
667
  collectUnknownPjmRemoteKeys(value, ['schemaVersion', 'storage', 'policy'], 'pjm.remote', findings);
668
+ if ('schemaVersion' in value && typeof value.schemaVersion !== 'number') {
669
+ findings.push(`pjm.remote.schemaVersion (expected number, received ${describePjmRemoteStructure(value.schemaVersion)})`);
670
+ }
638
671
  if ('storage' in value &&
639
672
  collectPjmRemoteExpectedObject(value.storage, 'pjm.remote.storage', findings)) {
640
673
  collectUnknownPjmRemoteKeys(value.storage, ['state'], 'pjm.remote.storage', findings);
674
+ collectPjmRemoteStringLeaf(value.storage, 'state', 'pjm.remote.storage', findings);
641
675
  }
642
676
  if ('policy' in value &&
643
677
  collectPjmRemoteExpectedObject(value.policy, 'pjm.remote.policy', findings)) {
644
678
  collectUnknownPjmRemoteKeys(value.policy, ['description', 'authority', 'providers'], 'pjm.remote.policy', findings);
679
+ collectPjmRemoteStringLeaf(value.policy, 'description', 'pjm.remote.policy', findings);
645
680
  if ('authority' in value.policy) {
646
681
  collectPjmRemoteAuthorityFindings(value.policy.authority, 'pjm.remote.policy.authority', findings);
647
682
  }
@@ -656,6 +691,7 @@ function assertClosedPjmRemoteSharedConfig(value, configPath) {
656
691
  continue;
657
692
  }
658
693
  collectUnknownPjmRemoteKeys(providerPolicy, ['description', 'authority'], `pjm.remote.policy.providers.${provider}`, findings);
694
+ collectPjmRemoteStringLeaf(providerPolicy, 'description', `pjm.remote.policy.providers.${provider}`, findings);
659
695
  if ('authority' in providerPolicy) {
660
696
  collectPjmRemoteAuthorityFindings(providerPolicy.authority, `pjm.remote.policy.providers.${provider}.authority`, findings);
661
697
  }
@@ -670,11 +706,27 @@ function collectPjmRemoteAuthorityFindings(value, path, findings) {
670
706
  if (!collectPjmRemoteExpectedObject(value, path, findings))
671
707
  return;
672
708
  collectUnknownPjmRemoteKeys(value, ['default', 'operations'], path, findings);
709
+ collectPjmRemoteStringLeaf(value, 'default', path, findings);
673
710
  if ('operations' in value &&
674
711
  collectPjmRemoteExpectedObject(value.operations, `${path}.operations`, findings)) {
675
712
  collectUnknownPjmRemoteKeys(value.operations, PJM_REMOTE_OPERATION_CLASSES, `${path}.operations`, findings);
713
+ for (const operation of PJM_REMOTE_OPERATION_CLASSES) {
714
+ collectPjmRemoteStringLeaf(value.operations, operation, `${path}.operations`, findings);
715
+ }
676
716
  }
677
717
  }
718
+ /**
719
+ * Records a present leaf whose value is not a string.
720
+ *
721
+ * Only the *type* is checked: an unrecognized string keeps its documented
722
+ * coercion in the normalizer. The finding names the structure type, never the
723
+ * value, so a secret pasted into the wrong field cannot leak into the error.
724
+ */
725
+ function collectPjmRemoteStringLeaf(value, key, path, findings) {
726
+ if (!(key in value) || typeof value[key] === 'string')
727
+ return;
728
+ findings.push(`${path}.${key} (expected string, received ${describePjmRemoteStructure(value[key])})`);
729
+ }
678
730
  function collectPjmRemoteExpectedObject(value, path, findings) {
679
731
  if (isRecord(value) && !Array.isArray(value))
680
732
  return true;
@@ -812,7 +864,7 @@ function normalizeDocumentationExcludes(value, configPath) {
812
864
  return normalized;
813
865
  }
814
866
  /**
815
- * Parse `documentation.instructionPointerExcludes` into a trimmed,
867
+ * Parse `instructions.claude.excludes` into a trimmed,
816
868
  * de-duplicated, order-preserving list.
817
869
  *
818
870
  * Fails closed, exactly like its `documentation.excludes` sibling above and for
@@ -822,7 +874,7 @@ function normalizeDocumentationExcludes(value, configPath) {
822
874
  * an error.
823
875
  *
824
876
  * The repair instruction names `oat config set` first and the file second: the
825
- * command is catalogued (`oat config set documentation.instructionPointerExcludes`),
877
+ * command is catalogued (`oat config set instructions.claude.excludes`),
826
878
  * and an operator repairing a malformed value should reach for the validated
827
879
  * write path before hand-editing JSON.
828
880
  */
@@ -831,8 +883,8 @@ function normalizeInstructionPointerExcludes(value, configPath) {
831
883
  return [];
832
884
  }
833
885
  const invalid = () => {
834
- throw new CliError(`Invalid documentation.instructionPointerExcludes in ${configPath}: expected an array of non-empty strings. ` +
835
- 'Repair it with `oat config set documentation.instructionPointerExcludes <path[,path...]>` (an empty value clears the key), or by editing that file.', 2);
886
+ throw new CliError(`Invalid instructions.claude.excludes in ${configPath}: expected an array of non-empty strings. ` +
887
+ 'Repair it with `oat config set instructions.claude.excludes <path[,path...]>` (an empty value clears the key), or by editing that file.', 2);
836
888
  };
837
889
  if (!Array.isArray(value)) {
838
890
  invalid();
@@ -849,6 +901,27 @@ function normalizeInstructionPointerExcludes(value, configPath) {
849
901
  }
850
902
  return normalized;
851
903
  }
904
+ /**
905
+ * Parse `instructions.claude.shims`.
906
+ *
907
+ * Fails closed like `projects.defaultScope`: a misspelled strategy must never
908
+ * read as unset, because unset means the built-in default, and the default
909
+ * decides whether `oat instructions sync` writes CLAUDE.md files. An absent key
910
+ * is "not configured"; any present value outside the accepted list is an error
911
+ * that names the `oat config set` repair.
912
+ */
913
+ function normalizeInstructionSyncStrategy(value, configPath) {
914
+ if (value === undefined) {
915
+ return undefined;
916
+ }
917
+ if (!isInstructionSyncStrategy(value)) {
918
+ const accepted = INSTRUCTION_SYNC_STRATEGIES.join('|');
919
+ throw new CliError(`Invalid instructions.claude.shims in ${configPath}: ${JSON.stringify(value)}. ` +
920
+ `Expected one of: ${INSTRUCTION_SYNC_STRATEGIES.join(', ')}. ` +
921
+ `Repair it with oat config set instructions.claude.shims <${accepted}>.`, 2);
922
+ }
923
+ return value;
924
+ }
852
925
  /**
853
926
  * Report a stored value whose type the normalizer cannot use.
854
927
  *
@@ -999,14 +1072,24 @@ function normalizeOatConfig(parsed, configPath = '.oat/config.json', onWarning)
999
1072
  if (excludes.length > 0) {
1000
1073
  doc.excludes = excludes;
1001
1074
  }
1002
- const instructionPointerExcludes = normalizeInstructionPointerExcludes(parsed.documentation.instructionPointerExcludes, configPath);
1003
- if (instructionPointerExcludes.length > 0) {
1004
- doc.instructionPointerExcludes = instructionPointerExcludes;
1005
- }
1006
1075
  if (Object.keys(doc).length > 0) {
1007
1076
  next.documentation = doc;
1008
1077
  }
1009
1078
  }
1079
+ if (isRecord(parsed.instructions) && isRecord(parsed.instructions.claude)) {
1080
+ const claude = {};
1081
+ const shims = normalizeInstructionSyncStrategy(parsed.instructions.claude.shims, configPath);
1082
+ if (shims !== undefined) {
1083
+ claude.shims = shims;
1084
+ }
1085
+ const excludes = normalizeInstructionPointerExcludes(parsed.instructions.claude.excludes, configPath);
1086
+ if (excludes.length > 0) {
1087
+ claude.excludes = excludes;
1088
+ }
1089
+ if (Object.keys(claude).length > 0) {
1090
+ next.instructions = { claude };
1091
+ }
1092
+ }
1010
1093
  if (Array.isArray(parsed.localPaths)) {
1011
1094
  const filtered = parsed.localPaths.filter((v) => typeof v === 'string' && v.trim() !== '');
1012
1095
  if (filtered.length > 0) {
@@ -1176,8 +1259,24 @@ export async function readOatConfigForDocumentationExcludesRepair(repoRoot) {
1176
1259
  }
1177
1260
  }
1178
1261
  /**
1179
- * Read the shared config with a malformed
1180
- * `documentation.instructionPointerExcludes` dropped.
1262
+ * Return `parsed` with `instructions.claude.<key>` removed, leaving every other
1263
+ * value untouched, so a repair read can load the file whose value it replaces.
1264
+ */
1265
+ function withoutInstructionsClaudeKey(parsed, key) {
1266
+ if (!isRecord(parsed) ||
1267
+ !isRecord(parsed.instructions) ||
1268
+ !isRecord(parsed.instructions.claude)) {
1269
+ return parsed;
1270
+ }
1271
+ const claude = Object.fromEntries(Object.entries(parsed.instructions.claude).filter(([name]) => name !== key));
1272
+ return {
1273
+ ...parsed,
1274
+ instructions: { ...parsed.instructions, claude },
1275
+ };
1276
+ }
1277
+ /**
1278
+ * Read the shared config with a malformed `instructions.claude.excludes`
1279
+ * dropped.
1181
1280
  *
1182
1281
  * The sibling of `readOatConfigForDocumentationExcludesRepair`, and it exists
1183
1282
  * for the same reason: this key's own validation error now names
@@ -1189,11 +1288,27 @@ export async function readOatConfigForInstructionPointerExcludesRepair(repoRoot)
1189
1288
  try {
1190
1289
  const raw = await readFile(configPath, 'utf8');
1191
1290
  const parsed = parseJsonConfig(raw, configPath);
1192
- if (isRecord(parsed) && isRecord(parsed.documentation)) {
1193
- const { instructionPointerExcludes: _invalidInstructionPointerExcludes, ...documentation } = parsed.documentation;
1194
- return normalizeOatConfig({ ...parsed, documentation }, configPath);
1291
+ return normalizeOatConfig(withoutInstructionsClaudeKey(parsed, 'excludes'), configPath);
1292
+ }
1293
+ catch (error) {
1294
+ if (isMissingFileError(error)) {
1295
+ return { ...DEFAULT_OAT_CONFIG };
1195
1296
  }
1196
- return normalizeOatConfig(parsed, configPath);
1297
+ throw error;
1298
+ }
1299
+ }
1300
+ /**
1301
+ * Read the shared config with a malformed `instructions.claude.shims`
1302
+ * dropped, so the
1303
+ * `oat config set`/`unset` repair its validation error names can load the file
1304
+ * it is repairing.
1305
+ */
1306
+ export async function readOatConfigForInstructionSyncStrategyRepair(repoRoot) {
1307
+ const configPath = getConfigPath(repoRoot);
1308
+ try {
1309
+ const raw = await readFile(configPath, 'utf8');
1310
+ const parsed = parseJsonConfig(raw, configPath);
1311
+ return normalizeOatConfig(withoutInstructionsClaudeKey(parsed, 'shims'), configPath);
1197
1312
  }
1198
1313
  catch (error) {
1199
1314
  if (isMissingFileError(error)) {
@@ -1219,10 +1334,103 @@ export async function readOatLocalConfig(repoRoot) {
1219
1334
  throw error;
1220
1335
  }
1221
1336
  }
1337
+ /**
1338
+ * Reads the existing config file as raw JSON for ordering and no-op checks.
1339
+ *
1340
+ * Parses through `parseJsonConfig`, the same tolerant parser every config
1341
+ * reader uses (trailing commas accepted, `__proto__` kept as data), so a file
1342
+ * the readers accept is never treated as unparsable here. Deliberately
1343
+ * bypasses the normalizer, which throws on the malformed values repair flows
1344
+ * exist to remove. A missing or unparsable file yields `undefined`, so the
1345
+ * caller always writes it.
1346
+ */
1347
+ async function readRawJsonForWrite(filePath) {
1348
+ let raw;
1349
+ try {
1350
+ raw = await readFile(filePath, 'utf8');
1351
+ }
1352
+ catch {
1353
+ return undefined;
1354
+ }
1355
+ try {
1356
+ return parseJsonConfig(raw, filePath);
1357
+ }
1358
+ catch {
1359
+ return undefined;
1360
+ }
1361
+ }
1362
+ function isPlainJsonObject(value) {
1363
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
1364
+ }
1365
+ /**
1366
+ * Orders `value` like `template`, recursively: keys already present in the
1367
+ * template keep their existing position, and new keys follow in the
1368
+ * normalizer's order. Arrays keep their own element order.
1369
+ */
1370
+ function orderLike(value, template) {
1371
+ if (Array.isArray(value)) {
1372
+ return value.map((element, index) => orderLike(element, Array.isArray(template) ? template[index] : undefined));
1373
+ }
1374
+ if (!isPlainJsonObject(value))
1375
+ return value;
1376
+ const templateObject = isPlainJsonObject(template) ? template : {};
1377
+ const ordered = {};
1378
+ // Define rather than assign: a config key named `__proto__` is data and must
1379
+ // never replace the output object's prototype.
1380
+ const place = (key, next) => {
1381
+ Object.defineProperty(ordered, key, {
1382
+ value: next,
1383
+ enumerable: true,
1384
+ writable: true,
1385
+ configurable: true,
1386
+ });
1387
+ };
1388
+ for (const key of Object.keys(templateObject)) {
1389
+ if (Object.hasOwn(value, key) && value[key] !== undefined) {
1390
+ place(key, orderLike(value[key], templateObject[key]));
1391
+ }
1392
+ }
1393
+ for (const key of Object.keys(value)) {
1394
+ if (!Object.hasOwn(ordered, key) && value[key] !== undefined) {
1395
+ place(key, orderLike(value[key], undefined));
1396
+ }
1397
+ }
1398
+ return ordered;
1399
+ }
1400
+ function jsonDeepEqual(left, right) {
1401
+ if (Array.isArray(left) || Array.isArray(right)) {
1402
+ return (Array.isArray(left) &&
1403
+ Array.isArray(right) &&
1404
+ left.length === right.length &&
1405
+ left.every((element, index) => jsonDeepEqual(element, right[index])));
1406
+ }
1407
+ if (isPlainJsonObject(left) || isPlainJsonObject(right)) {
1408
+ if (!isPlainJsonObject(left) || !isPlainJsonObject(right))
1409
+ return false;
1410
+ const leftKeys = Object.keys(left);
1411
+ return (leftKeys.length === Object.keys(right).length &&
1412
+ leftKeys.every((key) => Object.hasOwn(right, key) && jsonDeepEqual(left[key], right[key])));
1413
+ }
1414
+ return Object.is(left, right);
1415
+ }
1416
+ /**
1417
+ * Writes the shared config, preserving the existing file's key order and
1418
+ * skipping writes that would not change its JSON value (GitHub #329, #311).
1419
+ *
1420
+ * Formatting-only differences (indentation, trailing newline) therefore leave
1421
+ * the file byte-identical, while repairs, raw-disk removals, and rewrites of a
1422
+ * malformed or unparsable file always land.
1423
+ */
1222
1424
  export async function writeOatConfig(repoRoot, config) {
1223
1425
  const configPath = getConfigPath(repoRoot);
1224
1426
  const normalized = normalizeOatConfig(config, configPath);
1225
- await atomicWriteJson(configPath, normalized);
1427
+ const existing = await readRawJsonForWrite(configPath);
1428
+ // Round-trip through JSON so the comparison sees exactly what would be
1429
+ // serialized (undefined-valued keys dropped).
1430
+ const output = JSON.parse(JSON.stringify(existing === undefined ? normalized : orderLike(normalized, existing)));
1431
+ if (existing !== undefined && jsonDeepEqual(existing, output))
1432
+ return;
1433
+ await atomicWriteJson(configPath, output);
1226
1434
  }
1227
1435
  export async function writeOatLocalConfig(repoRoot, config) {
1228
1436
  const configPath = getLocalConfigPath(repoRoot);
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAGtB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAkC;IACjD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAChE;AAgHD,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CAAC,cAAc,CAAC,CAgFzB;AAED,wDAAwD;AACxD,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB;;;;OAIG;IACH,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACjC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,MAAM,GAChB,sBAAsB,CAkBxB;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,MAAM,GAChB,UAAU,GAAG,IAAI,CAEnB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAY5B;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvE,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;IACzB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CA0DxC;AAiMD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,MAAM,GAAG,SAAS,CAQpB"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAGtB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAkC;IACjD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAChE;AA0HD,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CAAC,cAAc,CAAC,CAgFzB;AAED,wDAAwD;AACxD,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB;;;;OAIG;IACH,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACjC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,MAAM,GAChB,sBAAsB,CAkBxB;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,MAAM,GAChB,UAAU,GAAG,IAAI,CAEnB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAY5B;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvE,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;IACzB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CA0DxC;AAiMD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,MAAM,GAAG,SAAS,CAQpB"}
@@ -1,5 +1,5 @@
1
1
  import { isWorkflowDispatchCandidateLadder } from './dispatch-matrix.js';
2
- import { BUILTIN_EXEC_TARGETS, isWorkflowPostImplementStructuredSequence, readOatConfig, readOatLocalConfig, readUserConfig, } from './oat-config.js';
2
+ import { BUILTIN_EXEC_TARGETS, DEFAULT_INSTRUCTION_SYNC_STRATEGY, isWorkflowPostImplementStructuredSequence, readOatConfig, readOatLocalConfig, readUserConfig, } from './oat-config.js';
3
3
  import { getOwnKey, setOwnKey } from './own-keys.js';
4
4
  const DEFAULT_DEPENDENCIES = {
5
5
  readOatConfig,
@@ -35,9 +35,19 @@ const DEFAULT_SHARED_CONFIG = {
35
35
  // is absent here has no row at all while it is unset. `null` keeps meaning
36
36
  // "not set at this layer", so a configured array still wins.
37
37
  excludes: null,
38
- instructionPointerExcludes: null,
39
38
  requireForProjectCompletion: false,
40
39
  },
40
+ instructions: {
41
+ claude: {
42
+ // The strategy `oat instructions sync` applies when neither
43
+ // `--strategy` nor this key names one, so `oat config get` reports what
44
+ // will happen.
45
+ shims: DEFAULT_INSTRUCTION_SYNC_STRATEGY,
46
+ // Listed for the same reason as `documentation.excludes`: `oat config
47
+ // dump` enumerates the resolved map, and `null` means "not set here".
48
+ excludes: null,
49
+ },
50
+ },
41
51
  tools: {
42
52
  brainstorm: false,
43
53
  core: false,
@@ -1 +1 @@
1
- {"version":3,"file":"compute-plan.d.ts","sourceRoot":"","sources":["../../src/engine/compute-plan.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,KAAK,EACV,QAAQ,EACR,aAAa,EAGd,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,KAAK,EAEV,WAAW,EACX,oBAAoB,EACpB,QAAQ,EAET,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,UAAU,mBAAmB;IAC3B,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,sCAAsC,CAAC,EAAE,QAAQ,CAC/C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAClC,CAAC;IACF,+BAA+B,CAAC,EAAE,SAAS;QACzC,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,WAAW,CAAC;KAC1B,EAAE,CAAC;IACJ,gCAAgC,CAAC,EAAE,OAAO,CAAC;CAC5C;AAiOD,wBAAsB,iCAAiC,CACrD,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC,CAqG/B;AAyJD,wBAAsB,eAAe,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,SAAS,EAAE,iBAAiB,EAC5B,qBAAqB,EACrB,sCAAsC,EACtC,+BAAoC,EACpC,gCAAwC,GACzC,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4bzC"}
1
+ {"version":3,"file":"compute-plan.d.ts","sourceRoot":"","sources":["../../src/engine/compute-plan.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAItD,OAAO,KAAK,EACV,QAAQ,EACR,aAAa,EAGd,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,KAAK,EAEV,WAAW,EACX,oBAAoB,EACpB,QAAQ,EAET,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,UAAU,mBAAmB;IAC3B,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,sCAAsC,CAAC,EAAE,QAAQ,CAC/C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAClC,CAAC;IACF,+BAA+B,CAAC,EAAE,SAAS;QACzC,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,WAAW,CAAC;KAC1B,EAAE,CAAC;IACJ,gCAAgC,CAAC,EAAE,OAAO,CAAC;CAC5C;AAiOD,wBAAsB,iCAAiC,CACrD,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC,CAqG/B;AAyJD,wBAAsB,eAAe,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,SAAS,EAAE,iBAAiB,EAC5B,qBAAqB,EACrB,sCAAsC,EACtC,+BAAoC,EACpC,gCAAwC,GACzC,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6dzC"}
@@ -1,5 +1,6 @@
1
1
  import { access, lstat, readFile, readlink, stat } from 'node:fs/promises';
2
2
  import { basename, dirname, join, normalize, relative, resolve, } from 'node:path';
3
+ import { CliError } from '../errors/index.js';
3
4
  import { computeContentHash, computeStringHash } from '../manifest/hash.js';
4
5
  import { findEntry } from '../manifest/manager.js';
5
6
  import { getSyncMappings } from '../providers/shared/adapter.utils.js';
@@ -315,6 +316,7 @@ export async function computeSyncPlan({ canonical, adapters, manifest, scope, co
315
316
  const collections = [];
316
317
  const scopeRoot = resolveScopeRoot(canonical, explicitScopeRoot);
317
318
  const seenCanonicalKeys = new Set();
319
+ const transformFailures = new Map();
318
320
  const activeProviderNames = new Set();
319
321
  const activeMappingsByProvider = new Map();
320
322
  const manifestV2 = manifest;
@@ -538,9 +540,27 @@ export async function computeSyncPlan({ canonical, adapters, manifest, scope, co
538
540
  if (!entryInsideMapping(canonicalEntry, mapping.canonicalDir)) {
539
541
  continue;
540
542
  }
541
- const renderedContent = mapping.transformCanonical && canonicalEntry.isFile
542
- ? mapping.transformCanonical(await readFile(canonicalEntry.canonicalPath, 'utf8'), relativeCanonicalPath.replaceAll('\\', '/'))
543
- : undefined;
543
+ let renderedContent;
544
+ if (mapping.transformCanonical && canonicalEntry.isFile) {
545
+ const displayPath = relativeCanonicalPath.replaceAll('\\', '/');
546
+ try {
547
+ renderedContent = mapping.transformCanonical(await readFile(canonicalEntry.canonicalPath, 'utf8'), displayPath);
548
+ }
549
+ catch (error) {
550
+ if (!(error instanceof CliError)) {
551
+ throw error;
552
+ }
553
+ // Every provider transform parses the same canonical file, so key
554
+ // the failure by path and report each invalid file exactly once.
555
+ const failureKey = normalize(relativeCanonicalPath);
556
+ if (!transformFailures.has(failureKey)) {
557
+ transformFailures.set(failureKey, error.message.includes(displayPath)
558
+ ? error.message
559
+ : `${displayPath}: ${error.message}`);
560
+ }
561
+ continue;
562
+ }
563
+ }
544
564
  const entryScopeRoot = scopeRoot
545
565
  ? scopeRoot
546
566
  : resolveScopeRootFromCanonical(canonicalEntry, relativeCanonicalPath);
@@ -579,6 +599,14 @@ export async function computeSyncPlan({ canonical, adapters, manifest, scope, co
579
599
  }
580
600
  }
581
601
  }
602
+ if (transformFailures.size > 0) {
603
+ const count = transformFailures.size;
604
+ throw new CliError(`Sync stopped: ${count} invalid canonical ${count === 1 ? 'rule' : 'rules'}. Fix ${count === 1 ? 'it' : 'them'} and re-run oat sync:\n${[
605
+ ...transformFailures.values(),
606
+ ]
607
+ .map((message) => ` - ${message}`)
608
+ .join('\n')}`);
609
+ }
582
610
  if (!scopeRoot) {
583
611
  return { scope, entries, removals, collections };
584
612
  }
@@ -1,4 +1,5 @@
1
1
  import { type GenericDispatchRecord } from '../identity/generic-dispatch-record.js';
2
+ import { z } from 'zod';
2
3
  import { type ClaudeCapabilityEvidence } from './targets.js';
3
4
  export interface AcceptedClaudeLaunchEnvelope {
4
5
  schemaVersion: 1;
@@ -16,19 +17,71 @@ export interface AcceptedClaudeLaunchEnvelope {
16
17
  model?: string;
17
18
  };
18
19
  }
20
+ type ResolverRole = AcceptedClaudeLaunchEnvelope['resolverRole'];
21
+ /**
22
+ * One violation found while validating a managed Claude dispatch input.
23
+ * `stage` is the top-level input key it belongs to (`claudeLaunch`,
24
+ * `recordBase`, or `event`); `path` locates it inside that stage.
25
+ * Messages name fields and expected forms; they are still routed through the
26
+ * command's redaction boundary because a few echo caller-supplied selectors.
27
+ */
28
+ export interface ManagedClaudeViolation {
29
+ stage: string;
30
+ path: string;
31
+ message: string;
32
+ }
33
+ /** Render a Zod issue path as `a.b[0].c`, or `<root>` when empty. */
34
+ export declare function formatIssuePath(prefix: string | null, path: readonly (string | number)[]): string;
35
+ export declare function zodIssueViolations(stage: string, prefix: string | null, error: z.ZodError): ManagedClaudeViolation[];
19
36
  /**
20
37
  * Validate the managed resolver result against the generated provider role and
21
38
  * the exact payload that will be launched. This is the production boundary
22
39
  * used by the project dispatch-record producer for managed Claude dispatches.
40
+ * It stops at the first failure; {@link collectClaudeLaunchViolations} reports
41
+ * every failure for a caller building its input.
23
42
  */
24
43
  export declare function acceptClaudeLaunchEnvelope(input: {
25
44
  resolution: unknown;
26
45
  definition: string;
27
46
  launch: unknown;
28
47
  }): AcceptedClaudeLaunchEnvelope;
48
+ /**
49
+ * Report every `claudeLaunch` violation in one pass: each schema issue in the
50
+ * resolution and the payload, then every consistency check the parsed inputs
51
+ * allow. Consistency checks depend on a parsed resolution, and the two payload
52
+ * checks on a parsed payload; those are skipped and named in `skipped` rather
53
+ * than reported against a value that failed to parse.
54
+ */
55
+ export declare function collectClaudeLaunchViolations(claudeLaunch: unknown): {
56
+ resolverRole: ResolverRole | null;
57
+ violations: ManagedClaudeViolation[];
58
+ skipped: string[];
59
+ };
60
+ /**
61
+ * Report every `recordBase` violation in one pass: each derived field that is
62
+ * present, the action/role check, every missing, mistyped, or unknown field,
63
+ * every absolute path in an identity or control field, and every sensitive key
64
+ * or value. The action/role check needs a parsed resolution and is skipped
65
+ * without one.
66
+ */
67
+ export declare function collectClaudeRecordBaseViolations(candidate: unknown, resolverRole: ResolverRole | null): {
68
+ violations: ManagedClaudeViolation[];
69
+ skipped: string[];
70
+ };
71
+ /**
72
+ * One error for a whole validation run: a header, then one
73
+ * `stage path: message` line per violation, then the checks that were skipped
74
+ * because they depend on a stage that failed to parse.
75
+ */
76
+ export declare class ManagedClaudeDispatchValidationError extends Error {
77
+ readonly violations: readonly ManagedClaudeViolation[];
78
+ readonly skipped: readonly string[];
79
+ constructor(violations: readonly ManagedClaudeViolation[], skipped?: readonly string[]);
80
+ }
29
81
  /** Build configured invocation evidence only from an accepted launch envelope. */
30
82
  export declare function buildClaudeDispatchRecord(input: {
31
83
  envelope: AcceptedClaudeLaunchEnvelope;
32
84
  recordBase: unknown;
33
85
  }): GenericDispatchRecord;
86
+ export {};
34
87
  //# sourceMappingURL=dispatch-envelope.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-envelope.d.ts","sourceRoot":"","sources":["../../../src/providers/claude/dispatch-envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AAKrD,OAAO,EAEL,KAAK,wBAAwB,EAE9B,MAAM,WAAW,CAAC;AA4FnB,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,CAAC,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,aAAa,GAAG,UAAU,CAAC;IACzC,QAAQ,EAAE,uBAAuB,GAAG,cAAc,CAAC;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,wBAAwB,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAsCD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,4BAA4B,CA6F/B;AAmBD,kFAAkF;AAClF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,QAAQ,EAAE,4BAA4B,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;CACrB,GAAG,qBAAqB,CAoDxB"}
1
+ {"version":3,"file":"dispatch-envelope.d.ts","sourceRoot":"","sources":["../../../src/providers/claude/dispatch-envelope.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAEL,KAAK,wBAAwB,EAE9B,MAAM,WAAW,CAAC;AA4FnB,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,CAAC,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,aAAa,GAAG,UAAU,CAAC;IACzC,QAAQ,EAAE,uBAAuB,GAAG,cAAc,CAAC;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,wBAAwB,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAgBD,KAAK,YAAY,GAAG,4BAA4B,CAAC,cAAc,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD,qEAAqE;AACrE,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GACjC,MAAM,CAWR;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,EAAE,CAAC,CAAC,QAAQ,GAChB,sBAAsB,EAAE,CAM1B;AAsID;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,4BAA4B,CAgC/B;AASD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,OAAO,GAAG;IACpE,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,sBAAsB,EAAE,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAqDA;AAuDD;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,SAAS,EAAE,OAAO,EAClB,YAAY,EAAE,YAAY,GAAG,IAAI,GAChC;IAAE,UAAU,EAAE,sBAAsB,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAkE7D;AAMD;;;;GAIG;AACH,qBAAa,oCAAqC,SAAQ,KAAK;IAC7D,QAAQ,CAAC,UAAU,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAEpC,YACE,UAAU,EAAE,SAAS,sBAAsB,EAAE,EAC7C,OAAO,GAAE,SAAS,MAAM,EAAO,EAyBhC;CACF;AAmBD,kFAAkF;AAClF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,QAAQ,EAAE,4BAA4B,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;CACrB,GAAG,qBAAqB,CA2CxB"}