@ornexus/neocortex 4.60.68 → 4.60.70

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 (232) hide show
  1. package/dist/release-source.json +1 -1
  2. package/dist/sbom.cdx.json +1194 -1194
  3. package/install.ps1 +1 -1
  4. package/install.sh +1 -1
  5. package/package.json +3 -3
  6. package/packages/client/dist/adapters/adapter-registry.js +1 -108
  7. package/packages/client/dist/adapters/antigravity-adapter.js +2 -77
  8. package/packages/client/dist/adapters/claude-code-adapter.js +3 -79
  9. package/packages/client/dist/adapters/codex-adapter.js +2 -80
  10. package/packages/client/dist/adapters/cursor-adapter.js +4 -115
  11. package/packages/client/dist/adapters/gemini-adapter.js +2 -71
  12. package/packages/client/dist/adapters/grok-adapter.js +2 -42
  13. package/packages/client/dist/adapters/index.js +1 -22
  14. package/packages/client/dist/adapters/platform-detector.js +1 -212
  15. package/packages/client/dist/adapters/target-adapter.js +0 -12
  16. package/packages/client/dist/adapters/vscode-adapter.js +2 -72
  17. package/packages/client/dist/agent/refresh-stubs.js +2 -417
  18. package/packages/client/dist/agent/update-agent-yaml.js +1 -102
  19. package/packages/client/dist/agent/update-description.js +1 -251
  20. package/packages/client/dist/cache/crypto-utils.js +1 -78
  21. package/packages/client/dist/cache/encrypted-cache.js +1 -108
  22. package/packages/client/dist/cache/in-memory-asset-cache.js +1 -73
  23. package/packages/client/dist/cache/index.js +1 -13
  24. package/packages/client/dist/cache/protected-pi-boundary.js +1 -44
  25. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -127
  26. package/packages/client/dist/checkpoint/index.js +1 -11
  27. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -32
  28. package/packages/client/dist/cli.js +3 -290
  29. package/packages/client/dist/commands/activate.js +8 -394
  30. package/packages/client/dist/commands/architecture-answers.js +7 -274
  31. package/packages/client/dist/commands/architecture-memory-terminal.js +4 -253
  32. package/packages/client/dist/commands/architecture-non-ui-continuation.js +1 -100
  33. package/packages/client/dist/commands/architecture-root-binding.js +1 -51
  34. package/packages/client/dist/commands/cache-status.js +2 -112
  35. package/packages/client/dist/commands/config.js +1 -88
  36. package/packages/client/dist/commands/doctor.js +2 -635
  37. package/packages/client/dist/commands/invoke.d.ts +6 -0
  38. package/packages/client/dist/commands/invoke.js +142 -7140
  39. package/packages/client/dist/commands/legacy-epic-terminal.js +1 -71
  40. package/packages/client/dist/commands/legacy-story-branch.js +1 -96
  41. package/packages/client/dist/commands/legacy-story-pr.js +1 -276
  42. package/packages/client/dist/commands/mutation-qa-checkpoint.js +5 -285
  43. package/packages/client/dist/commands/mutation-qa-gate.js +1 -54
  44. package/packages/client/dist/commands/mutation-qa-git.js +1 -41
  45. package/packages/client/dist/commands/mutation-qa-policy.js +1 -102
  46. package/packages/client/dist/commands/mutation-qa-run.js +3 -219
  47. package/packages/client/dist/commands/mutation-qa-verdict.js +1 -149
  48. package/packages/client/dist/commands/mutation-qa.js +1 -220
  49. package/packages/client/dist/commands/native-agent.js +2 -136
  50. package/packages/client/dist/commands/planning-diagnosis.js +1 -43
  51. package/packages/client/dist/commands/planning-generation.js +1 -53
  52. package/packages/client/dist/commands/planning-memory.js +1 -40
  53. package/packages/client/dist/commands/planning-research.js +1 -42
  54. package/packages/client/dist/commands/private-session.js +1 -75
  55. package/packages/client/dist/commands/property-qa.js +1 -139
  56. package/packages/client/dist/commands/qa-control.js +1 -16
  57. package/packages/client/dist/commands/qa-scan-browser-launch.js +1 -55
  58. package/packages/client/dist/commands/qa-scan-browser-route.js +1 -28
  59. package/packages/client/dist/commands/qa-scan-capture.js +5 -663
  60. package/packages/client/dist/commands/qa-scan-discovery.js +3 -376
  61. package/packages/client/dist/commands/qa-scan-review.js +5 -826
  62. package/packages/client/dist/commands/qa-synthetic-backend-capture.js +1 -266
  63. package/packages/client/dist/commands/qa-synthetic-backend-review.js +1 -297
  64. package/packages/client/dist/commands/qa-synthetic-backend.js +2 -340
  65. package/packages/client/dist/commands/qa-synthetic-broker-port.js +1 -85
  66. package/packages/client/dist/commands/qa-synthetic-browser.js +1 -39
  67. package/packages/client/dist/commands/refactor-characterization.js +21 -671
  68. package/packages/client/dist/commands/refactor-commit.js +13 -399
  69. package/packages/client/dist/commands/refactor-control.js +3 -142
  70. package/packages/client/dist/commands/refactor-cpp-assertions.js +3 -93
  71. package/packages/client/dist/commands/refactor-review.js +5 -283
  72. package/packages/client/dist/commands/refactor-root.js +7 -588
  73. package/packages/client/dist/commands/refresh-memory.js +3 -156
  74. package/packages/client/dist/commands/shared-architecture-non-ui.js +1 -24
  75. package/packages/client/dist/commands/story-checkpoint.js +1 -171
  76. package/packages/client/dist/config/profile-directory.js +1 -13
  77. package/packages/client/dist/config/resolver-selection.js +1 -278
  78. package/packages/client/dist/config/secure-config.js +12 -281
  79. package/packages/client/dist/config.js +2 -223
  80. package/packages/client/dist/constants.js +1 -25
  81. package/packages/client/dist/context/context-collector.js +2 -222
  82. package/packages/client/dist/context/context-sanitizer.js +1 -145
  83. package/packages/client/dist/continuity/autonomous-governance.js +1 -285
  84. package/packages/client/dist/continuity/continuity-client-state-store.js +1 -1587
  85. package/packages/client/dist/continuity/invoke-hooks.js +1 -129
  86. package/packages/client/dist/continuity/migrations/001-initial-schema.js +2 -12
  87. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +2 -12
  88. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +2 -12
  89. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +2 -12
  90. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +2 -12
  91. package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +2 -10
  92. package/packages/client/dist/continuity/native-agent-store.js +1 -69
  93. package/packages/client/dist/continuity/native-agent-types.js +1 -90
  94. package/packages/client/dist/continuity/outbox.js +1 -117
  95. package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -172
  96. package/packages/client/dist/continuity/sqlite-store.js +81 -2536
  97. package/packages/client/dist/effects/invoke-effect-gateways.js +1 -62
  98. package/packages/client/dist/errors/error-messages.js +2 -228
  99. package/packages/client/dist/errors/frontmatter-diagnostics.js +1 -125
  100. package/packages/client/dist/evidence/collector.js +1 -347
  101. package/packages/client/dist/evidence/index.js +1 -1
  102. package/packages/client/dist/evidence/types.js +0 -2
  103. package/packages/client/dist/fs/atomic-state-replace.js +1 -152
  104. package/packages/client/dist/generated/command-registry.generated.js +1 -4076
  105. package/packages/client/dist/generated/public-projections.generated.js +1 -149
  106. package/packages/client/dist/git/direct-yolo-c01-retry.js +4 -138
  107. package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -1234
  108. package/packages/client/dist/git/git-lifecycle-step-ids.js +1 -14
  109. package/packages/client/dist/git/git-lifecycle-store.js +9 -1938
  110. package/packages/client/dist/git/legacy-story-branch-checkpoint.js +9 -259
  111. package/packages/client/dist/git/legacy-story-branch-setup.js +4 -348
  112. package/packages/client/dist/git/legacy-story-pr.js +70 -3538
  113. package/packages/client/dist/git/secure-filesystem-boundary.js +5 -182
  114. package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -284
  115. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -237
  116. package/packages/client/dist/i18n/first-run.js +2 -60
  117. package/packages/client/dist/index.js +1 -47
  118. package/packages/client/dist/invocation/invoke-input.js +1 -24
  119. package/packages/client/dist/license/index.js +1 -5
  120. package/packages/client/dist/license/license-client.js +1 -304
  121. package/packages/client/dist/machine/fingerprint.js +2 -163
  122. package/packages/client/dist/machine/index.js +1 -5
  123. package/packages/client/dist/memory/project-memory-path-scope.js +1 -62
  124. package/packages/client/dist/memory/project-memory-writer.js +40 -1007
  125. package/packages/client/dist/memory/shared-project-memory-types.js +2 -253
  126. package/packages/client/dist/migrations/project-identity-capability.js +1 -50
  127. package/packages/client/dist/migrations/project-identity.js +7 -493
  128. package/packages/client/dist/migrations/state-json.js +4 -344
  129. package/packages/client/dist/policy/architecture-policy.js +2 -184
  130. package/packages/client/dist/policy/index.js +1 -7
  131. package/packages/client/dist/policy/shared-policy-types.js +0 -38
  132. package/packages/client/dist/policy/subagent-approval-policy.js +1 -55
  133. package/packages/client/dist/private-execution/clean-baseline.js +2 -279
  134. package/packages/client/dist/private-execution/codex-executor.js +4 -574
  135. package/packages/client/dist/private-execution/codex-host-runtime.js +1 -137
  136. package/packages/client/dist/private-execution/codex-lifecycle-guard.js +1 -97
  137. package/packages/client/dist/private-execution/codex-scoped-permissions.js +1 -128
  138. package/packages/client/dist/private-execution/delivery.js +13 -410
  139. package/packages/client/dist/private-execution/diagnosis-root-review.js +2 -294
  140. package/packages/client/dist/private-execution/frozen-handoff.js +6 -19
  141. package/packages/client/dist/private-execution/implementation-validation.js +2 -106
  142. package/packages/client/dist/private-execution/isolated-admission.js +23 -1432
  143. package/packages/client/dist/private-execution/isolated-session.js +5 -725
  144. package/packages/client/dist/private-execution/isolated-workspace.js +1 -122
  145. package/packages/client/dist/private-execution/pact-consumer-runtime.js +3 -409
  146. package/packages/client/dist/private-execution/pact-test-source.js +1 -258
  147. package/packages/client/dist/private-execution/pact-toolchain.js +3 -290
  148. package/packages/client/dist/private-execution/pact-write-set.js +1 -172
  149. package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +5 -406
  150. package/packages/client/dist/private-execution/planning-generation-checkpoint.js +5 -462
  151. package/packages/client/dist/private-execution/planning-memory-checkpoint.js +3 -139
  152. package/packages/client/dist/private-execution/planning-research-checkpoint.js +4 -325
  153. package/packages/client/dist/private-execution/private-report-store.js +1 -42
  154. package/packages/client/dist/private-execution/property-test-candidate.js +1 -103
  155. package/packages/client/dist/private-execution/property-test-choices.js +3 -147
  156. package/packages/client/dist/private-execution/property-test-plan.js +7 -271
  157. package/packages/client/dist/private-execution/property-test-review.js +4 -258
  158. package/packages/client/dist/private-execution/property-test-runtime.js +9 -372
  159. package/packages/client/dist/private-execution/property-test-source.js +1 -139
  160. package/packages/client/dist/private-execution/root-checkpoint.js +1 -80
  161. package/packages/client/dist/private-execution/root-memory-git-evidence.js +3 -135
  162. package/packages/client/dist/private-execution/root-memory-recovery.js +1 -93
  163. package/packages/client/dist/private-execution/root-memory-request.js +1 -29
  164. package/packages/client/dist/private-execution/root-memory-scope.js +1 -178
  165. package/packages/client/dist/private-execution/root-memory-writer.js +1 -102
  166. package/packages/client/dist/private-execution/session-lease.js +1 -63
  167. package/packages/client/dist/private-execution/shared-private-admission-types.js +1 -50
  168. package/packages/client/dist/private-execution/shared-project-validation.js +1 -66
  169. package/packages/client/dist/private-execution/shared-root-memory-types.js +1 -61
  170. package/packages/client/dist/private-execution/ux-source-validation.js +1 -372
  171. package/packages/client/dist/private-execution/ux-write-set.js +2 -191
  172. package/packages/client/dist/resilience/circuit-breaker.js +1 -170
  173. package/packages/client/dist/resilience/degradation-manager.js +1 -164
  174. package/packages/client/dist/resilience/freshness-indicator.js +1 -100
  175. package/packages/client/dist/resilience/index.js +1 -8
  176. package/packages/client/dist/resilience/recovery-detector.js +1 -74
  177. package/packages/client/dist/resolvers/asset-resolver.js +0 -13
  178. package/packages/client/dist/resolvers/local-resolver.js +8 -255
  179. package/packages/client/dist/resolvers/remote-resolver.js +1 -233
  180. package/packages/client/dist/runner/binary.js +1 -404
  181. package/packages/client/dist/runner/cli.js +17 -1571
  182. package/packages/client/dist/runner/headless/adapters.js +1 -49
  183. package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -79
  184. package/packages/client/dist/runner/headless/continuous-story-workspace.js +11 -1628
  185. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -69
  186. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +2 -110
  187. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +8 -1236
  188. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -318
  189. package/packages/client/dist/runner/headless/fake-adapter.js +1 -62
  190. package/packages/client/dist/runner/headless/managed-profile.js +1 -132
  191. package/packages/client/dist/runner/headless/opencode-adapter.js +2 -145
  192. package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -43
  193. package/packages/client/dist/runner/headless/resolver.js +1 -231
  194. package/packages/client/dist/runner/headless/run-yolo.js +1 -885
  195. package/packages/client/dist/runner/headless/run-yoloop.js +2 -2574
  196. package/packages/client/dist/runner/headless/types.js +2 -574
  197. package/packages/client/dist/runner/local-console.js +13 -396
  198. package/packages/client/dist/runner/portal-sync-worker.js +1 -1487
  199. package/packages/client/dist/runner/project-identity.js +1 -106
  200. package/packages/client/dist/runner/scheduler.js +7 -995
  201. package/packages/client/dist/runner-cli.js +2 -18
  202. package/packages/client/dist/state/invocation-shape.js +1 -13
  203. package/packages/client/dist/state/project-state-snapshot.js +1 -1677
  204. package/packages/client/dist/state/state-json-repair.js +3 -785
  205. package/packages/client/dist/state/structural-dag-projection.js +1 -118
  206. package/packages/client/dist/telemetry/index.js +1 -5
  207. package/packages/client/dist/telemetry/offline-queue.js +1 -131
  208. package/packages/client/dist/tier/index.js +1 -5
  209. package/packages/client/dist/tier/tier-aware-client.js +1 -405
  210. package/packages/client/dist/types/index.js +1 -38
  211. package/packages/client/dist/version.js +1 -27
  212. package/packages/client/dist/yolo/change-evidence-collector.js +1 -126
  213. package/packages/client/dist/yolo/invoke-envelope-capability.js +1 -62
  214. package/packages/client/dist/yolo/spec-envelope-collector.js +5 -185
  215. package/packages/client/dist/yoloop/discovery-hook.js +2 -300
  216. package/packages/client/dist/yoloop/index.js +1 -8
  217. package/packages/client/dist/yoloop/invoke-hooks.js +12 -669
  218. package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1007
  219. package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -33
  220. package/packages/client/dist/yoloop/target-normalization.js +1 -180
  221. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1723
  222. package/targets-stubs/antigravity/gemini.md +1 -1
  223. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  224. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  225. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  226. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  227. package/targets-stubs/claude-code/neocortex.md +2 -2
  228. package/targets-stubs/codex/AGENTS.md +1 -1
  229. package/targets-stubs/cursor/agent.md +2 -2
  230. package/targets-stubs/gemini-cli/agent.md +2 -2
  231. package/targets-stubs/opencode/neocortex-root.md +1 -1
  232. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1,1677 +1 @@
1
- /**
2
- * @license FSL-1.1
3
- * Copyright (c) 2026 OrNexus AI
4
- *
5
- * Pure request-scoped projection helpers for invoke state snapshots.
6
- */
7
- import { createHash } from 'node:crypto';
8
- import { analyzeDependencyDag, StructuralDagError, } from './structural-dag-projection.js';
9
- import { classifyInvocationShapeV2 } from './invocation-shape.js';
10
- const RECENT_STORY_LIMIT = 12;
11
- const REASON_CODE_LIMIT = 16;
12
- const EPIC_LIFECYCLE_CLASSIFICATIONS = ['active', 'archived', 'rolled-back', 'synthetic', 'orphan'];
13
- // Publish-safe shadow of packages/shared/src/yoloop/status-policy.ts. The
14
- // standalone client tarball cannot take a runtime dependency on @neocortex/shared.
15
- const YOLOOP_ACTIVE_STORY_STATUS_SET = new Set([
16
- 'in-progress', 'branch-ready', 'diagnose', 'research', 'write-spec',
17
- 'create-tasks', 'implemented', 'refactor-suggest-done',
18
- 'property-tests-emitted', 'tests-validated', 'qa-gate-passed',
19
- 'memory-updated', 'committed', 'synced', 'pr-created', 'pr-reviewed',
20
- 'partial',
21
- ]);
22
- const policy = (commandId, stateProjectionPolicy, options = {}) => ({
23
- commandId,
24
- stateProjectionPolicy,
25
- ...options,
26
- });
27
- // P198.03: local publish-safe shadow of the P198.01 shared command-context
28
- // projection policies. The published CLI does not ship `packages/shared/dist`, so
29
- // this file must not add a runtime `@neocortex/shared` import until packaging is
30
- // changed. Keep ids/aliases/numbers aligned with the public command registry.
31
- const COMMAND_POLICY_BY_ID = Object.freeze({
32
- status: policy('status', 'full'),
33
- 'arch-plan': policy('arch-plan', 'full'),
34
- 'arch-prd': policy('arch-prd', 'full'),
35
- 'arch-architecture': policy('arch-architecture', 'epic-targeted', { structuralRequired: true }),
36
- 'arch-api-contracts': policy('arch-api-contracts', 'epic-targeted', { structuralRequired: true }),
37
- 'arch-api-integrations': policy('arch-api-integrations', 'epic-targeted', { structuralRequired: true }),
38
- 'arch-database': policy('arch-database', 'epic-targeted', { structuralRequired: true }),
39
- 'arch-security': policy('arch-security', 'epic-targeted', { structuralRequired: true }),
40
- 'arch-design-system': policy('arch-design-system', 'epic-targeted', { structuralRequired: true }),
41
- 'arch-ux-design': policy('arch-ux-design', 'epic-targeted', { structuralRequired: true }),
42
- 'arch-performance': policy('arch-performance', 'epic-targeted', { structuralRequired: true }),
43
- 'arch-testing': policy('arch-testing', 'epic-targeted', { structuralRequired: true }),
44
- 'arch-infrastructure': policy('arch-infrastructure', 'epic-targeted', { structuralRequired: true }),
45
- 'arch-review': policy('arch-review', 'epic-targeted', { structuralRequired: true }),
46
- 'arch-fitness-functions': policy('arch-fitness-functions', 'epic-targeted', { structuralRequired: true }),
47
- 'create-epic': policy('create-epic', 'epic-summary'),
48
- 'idea-diagnose': policy('idea-diagnose', 'full'),
49
- 'idea-research': policy('idea-research', 'epic-targeted', { structuralRequired: true }),
50
- 'generate-epic': policy('generate-epic', 'epic-targeted', { structuralRequired: true }),
51
- exec: policy('exec', 'story-targeted', { structuralRequired: true }),
52
- yolo: policy('yolo', 'story-targeted', { structuralRequired: true }),
53
- 'yolo-inline': policy('yolo-inline', 'story-targeted', { structuralRequired: true }),
54
- epic: policy('epic', 'epic-targeted', { structuralRequired: true }),
55
- 'setup-branch': policy('setup-branch', 'story-targeted', { structuralRequired: true }),
56
- diagnose: policy('diagnose', 'adaptive-targeted'),
57
- 'diagnose-inline': policy('diagnose-inline', 'full'),
58
- research: policy('research', 'adaptive-targeted'),
59
- 'research-inline': policy('research-inline', 'full'),
60
- 'write-spec': policy('write-spec', 'story-targeted', { structuralRequired: true }),
61
- 'create-tasks': policy('create-tasks', 'story-targeted', { structuralRequired: true }),
62
- implement: policy('implement', 'story-targeted', { structuralRequired: true }),
63
- commit: policy('commit', 'story-targeted', { structuralRequired: true }),
64
- 'commit-push': policy('commit', 'story-targeted', { structuralRequired: true }),
65
- sync: policy('sync', 'story-targeted', { structuralRequired: true }),
66
- 'sync-main': policy('sync', 'story-targeted', { structuralRequired: true }),
67
- 'create-pr': policy('create-pr', 'story-targeted', { structuralRequired: true }),
68
- review: policy('review', 'story-targeted'),
69
- 'review-pr': policy('review', 'story-targeted'),
70
- merge: policy('merge', 'story-targeted', { structuralRequired: true }),
71
- 'merge-pr': policy('merge', 'story-targeted', { structuralRequired: true }),
72
- 'fix-blocked': policy('fix-blocked', 'story-targeted'),
73
- 'finalize-epic': policy('finalize-epic', 'epic-targeted'),
74
- 'resolve-conflicts': policy('resolve-conflicts', 'story-targeted'),
75
- 'update-memory': policy('update-memory', 'full'),
76
- 'update-project-memory': policy('update-memory', 'story-targeted', { structuralRequired: true }),
77
- refactor: policy('refactor', 'adaptive-targeted'),
78
- 'refactor-suggest': policy('refactor', 'story-targeted', { structuralRequired: true }),
79
- cleanup: policy('cleanup', 'full'),
80
- audit: policy('audit', 'full'),
81
- 'tech-debt': policy('tech-debt', 'full'),
82
- menu: policy('menu', 'full'),
83
- plans: policy('plans', 'full'),
84
- billing: policy('billing', 'full'),
85
- subscribe: policy('subscribe', 'full'),
86
- 'qa-scan': policy('qa-scan', 'full'),
87
- yoloop: policy('yoloop', 'yoloop-targeted', { structuralRequired: true }),
88
- 'migrate-state': policy('migrate-state', 'full'),
89
- 'migrate-project-id': policy('migrate-project-id', 'full'),
90
- 'policy-audit': policy('policy-audit', 'full'),
91
- 'mutation-test': policy('mutation-test', 'full'),
92
- 'sync-openapi': policy('sync-openapi', 'full'),
93
- 'generate-pacts': policy('generate-pacts', 'full'),
94
- 'verify-pacts': policy('verify-pacts', 'full'),
95
- 'property-test': policy('property-test', 'full'),
96
- 'property-tests': policy('property-test', 'story-targeted', { structuralRequired: true }),
97
- 'chaos-plan': policy('chaos-plan', 'full'),
98
- 'ui-ux-review': policy('ui-ux-review', 'adaptive-targeted'),
99
- 'solyd-system': policy('solyd-system', 'adaptive-targeted'),
100
- goal: policy('goal', 'continuity-scoped'),
101
- loop: policy('loop', 'continuity-scoped'),
102
- jobs: policy('jobs', 'continuity-scoped'),
103
- runner: policy('runner', 'continuity-scoped'),
104
- 'goal-tick': policy('goal-tick', 'continuity-scoped'),
105
- 'loop-tick': policy('loop-tick', 'continuity-scoped'),
106
- 'validate-tests': policy('validate-tests', 'story-targeted', { structuralRequired: true }),
107
- 'qa-gate': policy('qa-gate', 'story-targeted', { structuralRequired: true }),
108
- });
109
- const COMMAND_ALIAS_TO_ID = Object.freeze({
110
- st: 'status',
111
- arquitetura: 'arch-plan',
112
- architecture: 'arch-plan',
113
- arch: 'arch-plan',
114
- prd: 'arch-prd',
115
- 'product-requirements': 'arch-prd',
116
- 'arch-doc': 'arch-architecture',
117
- 'tech-architecture': 'arch-architecture',
118
- 'api-contracts': 'arch-api-contracts',
119
- 'api-contract': 'arch-api-contracts',
120
- 'api-integrations': 'arch-api-integrations',
121
- 'api-int': 'arch-api-integrations',
122
- 'database-schema': 'arch-database',
123
- 'db-schema': 'arch-database',
124
- db: 'arch-database',
125
- 'cyber-security': 'arch-security',
126
- security: 'arch-security',
127
- sec: 'arch-security',
128
- 'design-system': 'arch-design-system',
129
- ds: 'arch-design-system',
130
- 'atomic-design': 'arch-design-system',
131
- 'ux-design': 'arch-ux-design',
132
- ux: 'arch-ux-design',
133
- wireframes: 'arch-ux-design',
134
- wireframe: 'arch-ux-design',
135
- 'user-flows': 'arch-ux-design',
136
- performance: 'arch-performance',
137
- perf: 'arch-performance',
138
- 'capacity-planning': 'arch-performance',
139
- capacity: 'arch-performance',
140
- 'arch-perf': 'arch-performance',
141
- 'performance-strategy': 'arch-performance',
142
- 'testing-strategy': 'arch-testing',
143
- 'test-plan': 'arch-testing',
144
- 'test-strategy': 'arch-testing',
145
- 'arch-test': 'arch-testing',
146
- infrastructure: 'arch-infrastructure',
147
- infra: 'arch-infrastructure',
148
- 'deploy-plan': 'arch-infrastructure',
149
- deployment: 'arch-infrastructure',
150
- 'arch-infra': 'arch-infrastructure',
151
- 'arch-deploy': 'arch-infrastructure',
152
- 'review-consolidation': 'arch-review',
153
- consolidation: 'arch-review',
154
- 'architecture-review': 'arch-review',
155
- 'arch-consolidation': 'arch-review',
156
- fitness: 'arch-fitness-functions',
157
- 'fitness-functions': 'arch-fitness-functions',
158
- archfit: 'arch-fitness-functions',
159
- 'arch-fit': 'arch-fitness-functions',
160
- 'fit-funcs': 'arch-fitness-functions',
161
- 'criar-epic': 'create-epic',
162
- planejamento: 'create-epic',
163
- 'idea-diag': 'idea-diagnose',
164
- 'idea-pesq': 'idea-research',
165
- 'gerar-epic': 'generate-epic',
166
- executar: 'exec',
167
- pipeline: 'exec',
168
- 'parallel-epic': 'epic',
169
- setup: 'setup-branch',
170
- branch: 'setup-branch',
171
- diag: 'diagnose',
172
- diagnostico: 'diagnose',
173
- c02: 'diagnose',
174
- pesquisar: 'research',
175
- pesq: 'research',
176
- 'research-fix': 'research',
177
- c03: 'research',
178
- spec: 'write-spec',
179
- especificacao: 'write-spec',
180
- c04: 'write-spec',
181
- tasks: 'create-tasks',
182
- tarefas: 'create-tasks',
183
- c05: 'create-tasks',
184
- impl: 'implement',
185
- implementar: 'implement',
186
- c06: 'implement',
187
- push: 'commit',
188
- 'commit_push': 'commit',
189
- cp: 'commit',
190
- c07: 'commit',
191
- sincronizar: 'sync',
192
- c08: 'sync',
193
- pr: 'create-pr',
194
- c09: 'create-pr',
195
- revisar: 'review',
196
- c11: 'review',
197
- mesclar: 'merge',
198
- c12: 'merge',
199
- fix: 'fix-blocked',
200
- corrigir: 'fix-blocked',
201
- finalizar: 'finalize-epic',
202
- conflitos: 'resolve-conflicts',
203
- memoria: 'update-memory',
204
- refactoring: 'refactor',
205
- refact: 'refactor',
206
- refac: 'refactor',
207
- rf: 'refactor',
208
- 'cleanup-code': 'refactor',
209
- 'code-cleanup': 'refactor',
210
- 'code-quality': 'refactor',
211
- 'improve-code': 'refactor',
212
- modernize: 'refactor',
213
- modernization: 'refactor',
214
- legacy: 'refactor',
215
- 'legacy-code': 'refactor',
216
- 'debt-pay': 'refactor',
217
- 'pay-debt': 'refactor',
218
- 'debt-reduction': 'refactor',
219
- 'smell-fix': 'refactor',
220
- 'fix-smells': 'refactor',
221
- 'code-smells': 'refactor',
222
- strangler: 'refactor',
223
- 'strangler-fig': 'refactor',
224
- limpar: 'cleanup',
225
- limpeza: 'cleanup',
226
- auditar: 'audit',
227
- auditoria: 'audit',
228
- debt: 'tech-debt',
229
- debts: 'tech-debt',
230
- 'debt-list': 'tech-debt',
231
- 'tech-debts': 'tech-debt',
232
- td: 'tech-debt',
233
- help: 'menu',
234
- ajuda: 'menu',
235
- '?': 'menu',
236
- commands: 'menu',
237
- cmds: 'menu',
238
- planos: 'plans',
239
- pricing: 'plans',
240
- bill: 'billing',
241
- subscription: 'billing',
242
- sub: 'billing',
243
- upgrade: 'subscribe',
244
- checkout: 'subscribe',
245
- qa: 'qa-scan',
246
- 'qa-test': 'qa-scan',
247
- 'visual-qa': 'qa-scan',
248
- 'e2e-scan': 'qa-scan',
249
- troubleshoot: 'qa-scan',
250
- 'debug-ui': 'qa-scan',
251
- scan: 'qa-scan',
252
- a11y: 'qa-scan',
253
- accessibility: 'qa-scan',
254
- wcag: 'qa-scan',
255
- 'auto-yolo': 'yoloop',
256
- 'epic-runner': 'yoloop',
257
- 'story-runner': 'yoloop',
258
- 'loop-yolo': 'yoloop',
259
- 'auto-epic': 'yoloop',
260
- migrate: 'migrate-state',
261
- 'state-migrate': 'migrate-state',
262
- 'schema-migrate': 'migrate-state',
263
- policy: 'policy-audit',
264
- 'audit-policy': 'policy-audit',
265
- 'policy-history': 'policy-audit',
266
- policies: 'policy-audit',
267
- mutation: 'mutation-test',
268
- stryker: 'mutation-test',
269
- 'kill-mutants': 'mutation-test',
270
- 'openapi-sync': 'sync-openapi',
271
- 'api-sync': 'sync-openapi',
272
- 'spec-sync': 'sync-openapi',
273
- 'regen-openapi': 'sync-openapi',
274
- pacts: 'generate-pacts',
275
- 'gen-pacts': 'generate-pacts',
276
- 'regen-pacts': 'generate-pacts',
277
- 'create-pacts': 'generate-pacts',
278
- 'verify-pact': 'verify-pacts',
279
- 'pact-verify': 'verify-pacts',
280
- 'check-pacts': 'verify-pacts',
281
- 'pact-check': 'verify-pacts',
282
- property: 'property-test',
283
- pbt: 'property-test',
284
- proptest: 'property-test',
285
- 'invariant-test': 'property-test',
286
- chaos: 'chaos-plan',
287
- gameday: 'chaos-plan',
288
- 'resilience-test': 'chaos-plan',
289
- 'ux-review': 'ui-ux-review',
290
- 'design-review': 'ui-ux-review',
291
- 'visual-review': 'ui-ux-review',
292
- 'product-polish': 'ui-ux-review',
293
- 'security-system': 'solyd-system',
294
- 'authorized-security': 'solyd-system',
295
- 'sec-system': 'solyd-system',
296
- goals: 'goal',
297
- 'durable-goal': 'goal',
298
- 'continuity-goal': 'goal',
299
- loops: 'loop',
300
- 'durable-loop': 'loop',
301
- 'continuity-loop': 'loop',
302
- job: 'jobs',
303
- 'continuity-jobs': 'jobs',
304
- 'neocortex-runner': 'runner',
305
- 'continuity-runner': 'runner',
306
- });
307
- const COMMAND_NUMBER_TO_ID = Object.freeze({
308
- '1': 'status',
309
- '3': 'arch-plan',
310
- '4': 'arch-prd',
311
- '5': 'arch-architecture',
312
- '6': 'arch-api-contracts',
313
- '7': 'arch-api-integrations',
314
- '8': 'arch-database',
315
- '9': 'arch-security',
316
- '10': 'arch-design-system',
317
- '11': 'arch-ux-design',
318
- '12': 'arch-performance',
319
- '13': 'arch-testing',
320
- '14': 'arch-infrastructure',
321
- '15': 'arch-review',
322
- '16': 'arch-fitness-functions',
323
- '17': 'create-epic',
324
- '18': 'idea-diagnose',
325
- '19': 'idea-research',
326
- '20': 'generate-epic',
327
- '21': 'exec',
328
- '22': 'yolo',
329
- '23': 'epic',
330
- '24': 'setup-branch',
331
- '25': 'diagnose',
332
- '26': 'research',
333
- '27': 'write-spec',
334
- '28': 'create-tasks',
335
- '29': 'implement',
336
- '30': 'commit',
337
- '31': 'sync',
338
- '32': 'create-pr',
339
- '33': 'review',
340
- '34': 'merge',
341
- '35': 'fix-blocked',
342
- '36': 'finalize-epic',
343
- '37': 'resolve-conflicts',
344
- '38': 'update-memory',
345
- '39': 'refactor',
346
- '40': 'cleanup',
347
- '41': 'audit',
348
- '42': 'tech-debt',
349
- '43': 'menu',
350
- '44': 'plans',
351
- '45': 'billing',
352
- '46': 'subscribe',
353
- '47': 'qa-scan',
354
- '48': 'yoloop',
355
- '49': 'migrate-state',
356
- '50': 'policy-audit',
357
- '51': 'mutation-test',
358
- '52': 'sync-openapi',
359
- '53': 'generate-pacts',
360
- '54': 'verify-pacts',
361
- '55': 'property-test',
362
- '56': 'chaos-plan',
363
- '57': 'ui-ux-review',
364
- '58': 'solyd-system',
365
- '59': 'goal',
366
- '60': 'loop',
367
- '61': 'jobs',
368
- '62': 'runner',
369
- });
370
- function safeToken(value, maxLength = 120) {
371
- if (typeof value !== 'string')
372
- return undefined;
373
- const trimmed = value.trim();
374
- if (!trimmed)
375
- return undefined;
376
- return trimmed.replace(/[^a-z0-9_.:-]+/gi, '_').slice(0, maxLength);
377
- }
378
- function safeCanonicalToken(value, maxLength = 120) {
379
- if (typeof value !== 'string')
380
- return undefined;
381
- const trimmed = value.trim();
382
- const safe = safeToken(value, maxLength);
383
- return safe === trimmed ? safe : undefined;
384
- }
385
- function safeGitRef(value) {
386
- if (typeof value !== 'string')
387
- return undefined;
388
- const trimmed = value.trim();
389
- if (!trimmed || trimmed.length > 240 || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(trimmed)
390
- || trimmed.includes('..') || trimmed.includes('//') || trimmed.includes('@{')
391
- || trimmed.endsWith('/') || trimmed.endsWith('.')
392
- || trimmed.split('/').some((part) => !part || part.startsWith('.') || part.endsWith('.lock')))
393
- return undefined;
394
- return trimmed;
395
- }
396
- function safeWriteRef(value) {
397
- if (typeof value !== 'string')
398
- return undefined;
399
- const normalized = value.replace(/\\/g, '/');
400
- if (!normalized || normalized.length > 240 || normalized.startsWith('/')
401
- || /^[A-Za-z]:/.test(normalized) || normalized.includes('..') || normalized.includes('//')
402
- || normalized.split('/').includes('.') || !/^[A-Za-z0-9._/:@#-]+$/.test(normalized))
403
- return undefined;
404
- return normalized;
405
- }
406
- function safeWriteRefs(value) {
407
- if (value === undefined)
408
- return undefined;
409
- if (!Array.isArray(value) || value.length > 128)
410
- return undefined;
411
- const refs = value.map(safeWriteRef);
412
- if (refs.some((ref) => ref === undefined))
413
- return undefined;
414
- return [...new Set(refs)].sort((left, right) => left.localeCompare(right, 'en'));
415
- }
416
- function isActiveYoloopStory(status) {
417
- return typeof status === 'string'
418
- && YOLOOP_ACTIVE_STORY_STATUS_SET.has(status.trim().toLowerCase().replace(/_/g, '-'));
419
- }
420
- function pickPublicScalarFields(value, allowlist) {
421
- const result = {};
422
- for (const key of allowlist) {
423
- const field = value[key];
424
- if (typeof field === 'string' || typeof field === 'boolean'
425
- || typeof field === 'number' && Number.isFinite(field))
426
- result[key] = field;
427
- else if (Array.isArray(field) && field.every((item) => typeof item === 'string'))
428
- result[key] = [...field];
429
- }
430
- return result;
431
- }
432
- function publicResumeCheckpoint(storyId, story) {
433
- const value = story.checkpoint;
434
- if (!isRecord(value) || value.schemaVersion !== 1 || value.storyId !== storyId
435
- || value.epicId !== story.epic_id || !safeGitRef(value.branch)
436
- || typeof value.baseSha !== 'string' || !/^[0-9a-f]{7,64}$/i.test(value.baseSha)
437
- || typeof value.headSha !== 'string' || !/^[0-9a-f]{7,64}$/i.test(value.headSha)
438
- || value.baseSha === value.headSha || !safeCanonicalToken(value.idempotencyKey)
439
- || typeof value.recordedAt !== 'string' || !Number.isFinite(Date.parse(value.recordedAt))
440
- || !Array.isArray(value.commits) || value.commits.length === 0 || value.commits.length > 256
441
- || value.commits.some((sha) => typeof sha !== 'string' || !/^[0-9a-f]{7,64}$/i.test(sha))
442
- || !Array.isArray(value.receiptRefs) || value.receiptRefs.length === 0 || value.receiptRefs.length > 256
443
- || value.receiptRefs.some((ref) => typeof ref !== 'string' || ref.length > 240 || ref.includes('..')
444
- || !/^[A-Za-z0-9._:/#\-[\]]+$/.test(ref))
445
- || !isRecord(value.qaReceipt) || value.qaReceipt.kind !== 'story_qa_evidence'
446
- || value.qaReceipt.producer !== 'local-yolo-tdd'
447
- || !['passed', 'blocked'].includes(String(value.qaVerdict))
448
- || !['approved', 'changes-requested', 'pending'].includes(String(value.reviewVerdict)))
449
- return undefined;
450
- if (value.reviewVerdict === 'pending' ? value.reviewReceipt !== undefined : !isRecord(value.reviewReceipt))
451
- return undefined;
452
- // collectStateSnapshot already validated field values. Re-project the exact
453
- // public allowlist so later hooks or synthetic callers cannot append content.
454
- const result = pickPublicScalarFields(value, [
455
- 'schemaVersion', 'storyId', 'epicId', 'branch', 'baseSha', 'headSha',
456
- 'idempotencyKey', 'dispatchId', 'bundleId', 'bundleDigest', 'graphRevision',
457
- 'claimRevision', 'qaVerdict', 'reviewVerdict', 'recordedAt', 'commits',
458
- 'receiptRefs',
459
- ]);
460
- result.qaReceipt = pickPublicScalarFields(value.qaReceipt, [
461
- 'schemaVersion', 'kind', 'producer', 'evidenceVersion', 'storyId', 'epicId',
462
- 'contract', 'command', 'manifestDigest', 'gateIds', 'resultDigest', 'baseSha',
463
- 'headSha', 'bundleDigest', 'graphRevision', 'sourceEvidenceDigest', 'verdict',
464
- 'checkedAt', 'receiptRef',
465
- ]);
466
- if (isRecord(value.reviewReceipt)) {
467
- result.reviewReceipt = pickPublicScalarFields(value.reviewReceipt, [
468
- 'schemaVersion', 'kind', 'producer', 'storyId', 'epicId', 'baseSha',
469
- 'headSha', 'bundleDigest', 'graphRevision', 'sourceEvidenceDigest',
470
- 'qaReceiptRef', 'verdict', 'reviewedAt', 'receiptRef',
471
- ]);
472
- }
473
- return result;
474
- }
475
- function publicCheckpointVerification(storyId, story) {
476
- const value = story.checkpoint_verification;
477
- if (!isRecord(value) || value.schemaVersion !== 1
478
- || value.kind !== 'story_checkpoint_physical_verification'
479
- || value.producer !== 'client-p205-transient-v1' || value.publicSafe !== true
480
- || value.storyId !== storyId || value.epicId !== story.epic_id
481
- || !['verified', 'rejected'].includes(String(value.verdict)))
482
- return undefined;
483
- return pickPublicScalarFields(value, [
484
- 'schemaVersion', 'kind', 'producer', 'storyId', 'epicId', 'branch',
485
- 'baseSha', 'headSha', 'aggregateHeadSha', 'commitBodyDigest',
486
- 'changedPathsDigest', 'claimVerification', 'effectiveClaimRevision',
487
- 'command', 'manifestDigest', 'gateIds', 'resultDigest', 'graphRevision',
488
- 'executionEvidenceDigest', 'sourceEvidenceDigest', 'verifiedAt', 'verdict',
489
- 'reasonCodes', 'publicSafe',
490
- ]);
491
- }
492
- function publicSchedulingCheckpointEvidence(storyId, story) {
493
- const value = story.scheduling_checkpoint_evidence;
494
- const allowed = new Set([
495
- 'schemaVersion', 'kind', 'producer', 'storyId', 'epicId', 'branch', 'baseSha', 'headSha',
496
- 'graphRevision', 'effectiveClaimRevision', 'sourceEvidenceDigest', 'verifiedAt', 'reasonCodes',
497
- 'integrationAuthorized', 'publicSafe',
498
- ]);
499
- if (!isRecord(value) || Object.keys(value).some((key) => !allowed.has(key))
500
- || value.schemaVersion !== 1 || value.kind !== 'story_scheduling_checkpoint_evidence'
501
- || value.producer !== 'client-git-physical-v1' || value.publicSafe !== true
502
- || value.integrationAuthorized !== false || value.storyId !== storyId || value.epicId !== story.epic_id
503
- || !safeGitRef(value.branch) || typeof value.baseSha !== 'string' || !/^[0-9a-f]{40,64}$/i.test(value.baseSha)
504
- || typeof value.headSha !== 'string' || !/^[0-9a-f]{40,64}$/i.test(value.headSha)
505
- || typeof value.graphRevision !== 'string' || !/^[0-9a-f]{64}$/i.test(value.graphRevision)
506
- || typeof value.effectiveClaimRevision !== 'string' || !/^[0-9a-f]{64}$/i.test(value.effectiveClaimRevision)
507
- || typeof value.sourceEvidenceDigest !== 'string' || !/^[0-9a-f]{64}$/i.test(value.sourceEvidenceDigest)
508
- || typeof value.verifiedAt !== 'string' || !Number.isFinite(Date.parse(value.verifiedAt))
509
- || !Array.isArray(value.reasonCodes) || value.reasonCodes.length !== 1
510
- || value.reasonCodes[0] !== 'checkpoint-git-scheduling-verified')
511
- return undefined;
512
- return pickPublicScalarFields(value, [...allowed]);
513
- }
514
- function projectSchedulingLane(storyId, story) {
515
- const projected = { ...story };
516
- const evidence = publicSchedulingCheckpointEvidence(storyId, story);
517
- if (evidence) {
518
- projected.scheduling_checkpoint_evidence = evidence;
519
- delete projected.checkpoint;
520
- delete projected.checkpoint_verification;
521
- }
522
- else {
523
- delete projected.scheduling_checkpoint_evidence;
524
- }
525
- return projected;
526
- }
527
- function isRecord(value) {
528
- return value !== null && typeof value === 'object' && !Array.isArray(value);
529
- }
530
- function safeReasonCodes(...groups) {
531
- const seen = new Set();
532
- const reasonCodes = [];
533
- for (const group of groups) {
534
- for (const reasonCode of group ?? []) {
535
- const safe = safeToken(reasonCode, 80);
536
- if (!safe || seen.has(safe))
537
- continue;
538
- seen.add(safe);
539
- reasonCodes.push(safe);
540
- if (reasonCodes.length >= REASON_CODE_LIMIT)
541
- return reasonCodes;
542
- }
543
- }
544
- return reasonCodes;
545
- }
546
- function normalizeCommandToken(input) {
547
- return input.trim().replace(/^@?\*/, '').replace(/^@/, '').toLowerCase();
548
- }
549
- function leadingCommandToken(input) {
550
- return input.trim().split(/\s+/, 1)[0] ?? '';
551
- }
552
- function resolveCommandProjectionPolicy(args) {
553
- // The exact published @epic-P{N} spelling is a one-token command and its
554
- // own target. It must receive the same structural projection as *epic.
555
- if (/^@epic-P[0-9]{1,12}$/.test(args.trim()))
556
- return COMMAND_POLICY_BY_ID.epic;
557
- const token = leadingCommandToken(args);
558
- if (!token)
559
- return COMMAND_POLICY_BY_ID.menu;
560
- const normalized = normalizeCommandToken(token);
561
- const commandId = COMMAND_NUMBER_TO_ID[normalized]
562
- ?? COMMAND_ALIAS_TO_ID[normalized]
563
- ?? normalized;
564
- return COMMAND_POLICY_BY_ID[commandId] ?? null;
565
- }
566
- function createFullScope(trigger, snapshot, commandPolicy, projectionMode = 'full-compatible', reasonCodes = ['full-state']) {
567
- return {
568
- kind: 'full',
569
- commandId: commandPolicy?.commandId ?? null,
570
- stateProjectionPolicy: commandPolicy?.stateProjectionPolicy ?? null,
571
- projectionMode,
572
- trigger,
573
- targetEpicId: null,
574
- targetStoryId: null,
575
- includedStoryCount: Object.keys(snapshot.stories).length,
576
- includedEpicCount: Object.keys(snapshot.epics).length,
577
- omittedStoryCount: 0,
578
- omittedEpicCount: 0,
579
- reason: 'full-state',
580
- reasonCodes: safeReasonCodes(reasonCodes),
581
- };
582
- }
583
- function fullSnapshot(trigger, snapshot, commandPolicy, projectionMode = 'full-compatible', reasonCodes = ['full-state']) {
584
- const scope = createFullScope(trigger, snapshot, commandPolicy, projectionMode, reasonCodes);
585
- return withStateSummary({
586
- ...snapshot,
587
- scope,
588
- }, snapshot, scope);
589
- }
590
- function firstTokenIsStoryReference(args) {
591
- const [firstToken] = args.trim().split(/\s+/, 1);
592
- if (!firstToken)
593
- return false;
594
- return (/^[A-Z]?\d+(?:\.\d+)+$/i.test(firstToken.replace(/^@/, '')) ||
595
- /(?:^|\/)[A-Z]?\d+(?:\.\d+)+\.story\.md$/i.test(firstToken.replace(/^@/, '')));
596
- }
597
- function extractStoryId(args) {
598
- const storyFileMatch = args.match(/(?:^|[/@\s])([A-Z]?\d+(?:\.\d+)+)\.story\.md\b/i);
599
- if (storyFileMatch?.[1])
600
- return storyFileMatch[1];
601
- const storyIdMatch = args.match(/(?:^|\s|@)([A-Z]?\d+(?:\.\d+)+)(?=$|\s)/i);
602
- return storyIdMatch?.[1] ?? null;
603
- }
604
- function triggerRemainder(args) {
605
- const trimmed = args.trim();
606
- const firstWhitespace = trimmed.search(/\s/);
607
- return firstWhitespace === -1 ? '' : trimmed.slice(firstWhitespace).trim();
608
- }
609
- function positionalTokens(args) {
610
- return triggerRemainder(args)
611
- .split(/\s+/)
612
- .map((token) => token.replace(/^@/, '').replace(/^['"]|['"]$/g, ''))
613
- .filter((token) => token.length > 0 && !token.startsWith('-'));
614
- }
615
- function firstPositionalArg(args) {
616
- return positionalTokens(args)[0] ?? null;
617
- }
618
- function resolveEpicId(candidate, snapshot) {
619
- const normalized = candidate.replace(/^@/, '').replace(/^epic-/i, '');
620
- const withoutExtension = normalized.replace(/\.md$/i, '');
621
- const candidates = [
622
- withoutExtension,
623
- withoutExtension.toUpperCase(),
624
- /^p\d+$/i.test(withoutExtension)
625
- ? `P${withoutExtension.replace(/^p/i, '')}`
626
- : null,
627
- /^\d+$/.test(withoutExtension) ? `P${withoutExtension}` : null,
628
- ].filter((entry) => typeof entry === 'string' && entry.length > 0);
629
- for (const entry of candidates) {
630
- if (snapshot.epics[entry])
631
- return entry;
632
- }
633
- return null;
634
- }
635
- function extractEpicIdFromCanonicalFile(args, snapshot) {
636
- const match = args.match(/(?:^|[/@\s])epic-(P?\d+)\.md\b/i);
637
- if (!match?.[1])
638
- return null;
639
- return resolveEpicId(match[1], snapshot);
640
- }
641
- function extractTargetEpicId(args, snapshot) {
642
- const directEpic = args.trim().match(/^@epic-(P[0-9]{1,12})$/);
643
- if (directEpic)
644
- return resolveEpicId(directEpic[1], snapshot);
645
- const fromFile = extractEpicIdFromCanonicalFile(args, snapshot);
646
- if (fromFile)
647
- return fromFile;
648
- for (const token of positionalTokens(args)) {
649
- if (/^[A-Z]?\d+(?:\.\d+)+$/i.test(token))
650
- continue;
651
- const fromToken = resolveEpicId(token, snapshot);
652
- if (fromToken)
653
- return fromToken;
654
- }
655
- return null;
656
- }
657
- function extractYoloopTargetEpicId(args, snapshot) {
658
- const fromTarget = extractTargetEpicId(args, snapshot);
659
- if (fromTarget)
660
- return fromTarget;
661
- const yoloop = snapshot.yoloop;
662
- const sessionEpicId = yoloop?.state?.currentSession?.currentEpicId;
663
- if (typeof sessionEpicId === 'string' && snapshot.epics[sessionEpicId]) {
664
- return sessionEpicId;
665
- }
666
- const lockEpicId = yoloop?.lock?.currentEpicId ?? yoloop?.lock?.epicId;
667
- if (typeof lockEpicId === 'string' && snapshot.epics[lockEpicId]) {
668
- return lockEpicId;
669
- }
670
- return null;
671
- }
672
- function explicitYoloopEpicCandidate(args) {
673
- const fromFile = args.match(/(?:^|[/@\s])epic-(P?\d+)\.md\b/i)?.[1];
674
- if (fromFile)
675
- return /^P/i.test(fromFile) ? fromFile.toUpperCase() : `P${fromFile}`;
676
- for (const token of positionalTokens(args)) {
677
- if (/^P\d+$/i.test(token))
678
- return token.toUpperCase();
679
- if (/^\d+$/.test(token))
680
- return `P${token}`;
681
- }
682
- return null;
683
- }
684
- function storyEpicId(story, storyId) {
685
- if (typeof story.epic_id === 'string' && story.epic_id.length > 0) {
686
- return story.epic_id;
687
- }
688
- const derived = storyId.split('.').slice(0, -1).join('.');
689
- return derived.length > 0 ? derived : null;
690
- }
691
- function isTerminalStoryStatus(status) {
692
- return typeof status === 'string' && ['done', 'completed', 'merged', 'cancelled', 'canceled', 'abandoned'].includes(status.toLowerCase());
693
- }
694
- function addStoryAndDependencies(storyId, snapshot, includedStoryIds) {
695
- if (includedStoryIds.has(storyId))
696
- return;
697
- const story = snapshot.stories[storyId];
698
- if (!story)
699
- return;
700
- includedStoryIds.add(storyId);
701
- const dependsOn = story.depends_on;
702
- if (!Array.isArray(dependsOn))
703
- return;
704
- for (const dependencyId of dependsOn) {
705
- if (typeof dependencyId === 'string') {
706
- addStoryAndDependencies(dependencyId, snapshot, includedStoryIds);
707
- }
708
- }
709
- }
710
- function buildProjectedStories(targetStoryId, snapshot) {
711
- const analysis = analyzeDependencyDag(snapshot.stories, [targetStoryId]);
712
- const projectedStories = {};
713
- for (const storyId of analysis.orderedIds) {
714
- const story = snapshot.stories[storyId];
715
- if (story) {
716
- projectedStories[storyId] = story;
717
- }
718
- }
719
- return projectedStories;
720
- }
721
- function buildProjectedEpics(projectedStories, snapshot, requiredEpicIds = []) {
722
- const projectedEpics = {};
723
- for (const epicId of requiredEpicIds) {
724
- if (snapshot.epics[epicId]) {
725
- projectedEpics[epicId] = snapshot.epics[epicId];
726
- }
727
- }
728
- for (const [storyId, story] of Object.entries(projectedStories)) {
729
- const epicId = storyEpicId(story, storyId);
730
- if (epicId && snapshot.epics[epicId]) {
731
- projectedEpics[epicId] = snapshot.epics[epicId];
732
- }
733
- }
734
- return projectedEpics;
735
- }
736
- function addEpicAndDependencies(epicId, snapshot, includedEpicIds) {
737
- if (includedEpicIds.has(epicId))
738
- return;
739
- const epic = snapshot.epics[epicId];
740
- if (!epic)
741
- return;
742
- includedEpicIds.add(epicId);
743
- const dependsOn = epic.depends_on;
744
- if (!Array.isArray(dependsOn))
745
- return;
746
- for (const dependencyId of dependsOn) {
747
- if (typeof dependencyId === 'string' && dependencyId.length > 0) {
748
- addEpicAndDependencies(dependencyId, snapshot, includedEpicIds);
749
- }
750
- }
751
- }
752
- function buildProjectedYoloopEpics(targetEpicId, projectedStories, snapshot) {
753
- const epicAnalysis = analyzeDependencyDag(snapshot.epics, [targetEpicId]);
754
- const requiredEpicIds = new Set(epicAnalysis.orderedIds);
755
- for (const [storyId, story] of Object.entries(projectedStories)) {
756
- const parentEpicId = storyEpicId(story, storyId);
757
- if (parentEpicId && snapshot.epics[parentEpicId])
758
- requiredEpicIds.add(parentEpicId);
759
- }
760
- const projectedEpics = {};
761
- for (const epicId of [...requiredEpicIds].sort((left, right) => left.localeCompare(right, 'en'))) {
762
- const epic = snapshot.epics[epicId];
763
- if (!epic)
764
- continue;
765
- projectedEpics[epicId] = epicId === targetEpicId ? epic : compactStructuralEpic(epicId, epic);
766
- }
767
- return projectedEpics;
768
- }
769
- function buildProjectedYoloopStories(targetEpicId, targetEpic, snapshot) {
770
- const storyIds = targetEpic.stories;
771
- if (!Array.isArray(storyIds)
772
- || storyIds.some((storyId) => typeof storyId !== 'string' || storyId.length === 0)) {
773
- throw new StructuralDagError('STRUCTURAL_DEPENDENCY_MISSING', {
774
- nodes: 0,
775
- edges: 0,
776
- malformedStoryMemberships: 1,
777
- });
778
- }
779
- const analysis = analyzeDependencyDag(snapshot.stories, storyIds);
780
- const projectedStories = {};
781
- for (const storyId of analysis.orderedIds) {
782
- const story = snapshot.stories[storyId];
783
- if (story) {
784
- projectedStories[storyId] = storyEpicId(story, storyId) === targetEpicId
785
- ? projectSchedulingLane(storyId, story)
786
- : compactStructuralStory(storyId, story);
787
- }
788
- }
789
- return projectedStories;
790
- }
791
- function buildTargetEpicCoverage(targetEpicId, targetEpic, projectedStories) {
792
- const declaredStoryIds = [...targetEpic.stories]
793
- .sort((left, right) => left.localeCompare(right, 'en'));
794
- const includedStoryIds = Object.entries(projectedStories)
795
- .filter(([storyId, story]) => storyEpicId(story, storyId) === targetEpicId)
796
- .map(([storyId]) => storyId)
797
- .sort((left, right) => left.localeCompare(right, 'en'));
798
- const membershipSha256 = createHash('sha256')
799
- .update(`target-epic-coverage-v1\0${JSON.stringify({ targetEpicId, declaredStoryIds, includedStoryIds })}`)
800
- .digest('hex');
801
- return {
802
- schemaVersion: 'TargetEpicCoverage/1.0',
803
- targetEpicId,
804
- declaredStoryIds,
805
- includedStoryIds,
806
- membershipSha256,
807
- publicSafe: true,
808
- };
809
- }
810
- function compactStructuralStory(storyId, story) {
811
- const dependsOn = Array.isArray(story.depends_on)
812
- ? [...new Set(story.depends_on.filter((value) => typeof value === 'string' && value.length > 0))]
813
- .sort((left, right) => left.localeCompare(right, 'en'))
814
- : [];
815
- const compact = {
816
- id: safeToken(story.id) ?? storyId,
817
- ...(safeToken(story.epic_id) ? { epic_id: safeToken(story.epic_id) } : {}),
818
- ...(safeToken(story.status, 40) ? { status: safeToken(story.status, 40) } : {}),
819
- depends_on: dependsOn,
820
- };
821
- const schedulingEvidence = publicSchedulingCheckpointEvidence(storyId, story);
822
- if (!isActiveYoloopStory(story.status)) {
823
- return { ...compact, ...(schedulingEvidence ? { scheduling_checkpoint_evidence: schedulingEvidence } : {}) };
824
- }
825
- const source = story.source === 'create-epic' || story.source === 'discovered'
826
- ? story.source : undefined;
827
- const branchName = safeGitRef(story.branch_name);
828
- const lastStep = safeCanonicalToken(story.last_step, 120);
829
- const steps = Array.isArray(story.steps_completed) && story.steps_completed.length <= 64
830
- ? story.steps_completed.map((step) => safeCanonicalToken(step, 120))
831
- : [];
832
- const validSteps = steps.length > 0 && steps.every((step) => step !== undefined)
833
- ? steps : undefined;
834
- const prNumber = typeof story.pr_number === 'number' && Number.isSafeInteger(story.pr_number)
835
- && story.pr_number > 0 ? story.pr_number : undefined;
836
- const checkpoint = publicResumeCheckpoint(storyId, story);
837
- const checkpointVerification = checkpoint ? publicCheckpointVerification(storyId, story) : undefined;
838
- return {
839
- ...compact,
840
- ...(source ? { source } : {}),
841
- ...(branchName ? { branch_name: branchName } : {}),
842
- ...(lastStep ? { last_step: lastStep } : {}),
843
- ...(validSteps ? { steps_completed: validSteps } : {}),
844
- ...(prNumber ? { pr_number: prNumber } : {}),
845
- ...(checkpoint ? { checkpoint } : {}),
846
- ...(checkpointVerification ? { checkpoint_verification: checkpointVerification } : {}),
847
- ...(schedulingEvidence ? { scheduling_checkpoint_evidence: schedulingEvidence } : {}),
848
- ...(safeWriteRefs(story.files_to_modify) !== undefined
849
- ? { files_to_modify: safeWriteRefs(story.files_to_modify) } : {}),
850
- ...(safeWriteRefs(story.contracts) !== undefined
851
- ? { contracts: safeWriteRefs(story.contracts) } : {}),
852
- ...(safeWriteRefs(story.contract_refs) !== undefined
853
- ? { contract_refs: safeWriteRefs(story.contract_refs) } : {}),
854
- ...(safeWriteRefs(story.shared_surfaces) !== undefined
855
- ? { shared_surfaces: safeWriteRefs(story.shared_surfaces) } : {}),
856
- };
857
- }
858
- function compactStructuralEpic(epicId, epic) {
859
- const stories = Array.isArray(epic.stories)
860
- ? [...new Set(epic.stories.filter((value) => typeof value === 'string' && value.length > 0))]
861
- .sort((left, right) => left.localeCompare(right, 'en'))
862
- : [];
863
- const dependsOn = Array.isArray(epic.depends_on)
864
- ? [...new Set(epic.depends_on.filter((value) => typeof value === 'string' && value.length > 0))]
865
- .sort((left, right) => left.localeCompare(right, 'en'))
866
- : [];
867
- return {
868
- id: safeToken(epic.id) ?? epicId,
869
- ...(safeToken(epic.status, 40) ? { status: safeToken(epic.status, 40) } : {}),
870
- ...(safeToken(epic.lifecycle_classification, 40)
871
- ? { lifecycle_classification: safeToken(epic.lifecycle_classification, 40) }
872
- : {}),
873
- stories,
874
- depends_on: dependsOn,
875
- };
876
- }
877
- function buildYoloopDiscoveryProjection(trigger, snapshot, commandPolicy) {
878
- const storyAnalysis = analyzeDependencyDag(snapshot.stories);
879
- const epicAnalysis = analyzeDependencyDag(snapshot.epics);
880
- const projectedStories = Object.fromEntries(storyAnalysis.orderedIds.map((storyId) => [
881
- storyId,
882
- compactStructuralStory(storyId, snapshot.stories[storyId]),
883
- ]));
884
- const projectedEpics = Object.fromEntries(epicAnalysis.orderedIds.map((epicId) => [
885
- epicId,
886
- compactStructuralEpic(epicId, snapshot.epics[epicId]),
887
- ]));
888
- const scope = {
889
- kind: 'projected',
890
- commandId: commandPolicy.commandId,
891
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
892
- projectionMode: 'yoloop-discovery',
893
- trigger,
894
- targetEpicId: null,
895
- targetStoryId: null,
896
- includedStoryCount: storyAnalysis.orderedIds.length,
897
- includedEpicCount: epicAnalysis.orderedIds.length,
898
- omittedStoryCount: 0,
899
- omittedEpicCount: 0,
900
- reason: 'targeted-invocation',
901
- reasonCodes: safeReasonCodes([
902
- 'structural-required',
903
- 'yoloop-discovery',
904
- `structural-edges-${storyAnalysis.edgeCount + epicAnalysis.edgeCount}`,
905
- 'content-fields-omitted',
906
- ]),
907
- };
908
- return withStateSummary({
909
- ...snapshot,
910
- stories: projectedStories,
911
- epics: projectedEpics,
912
- scope,
913
- }, snapshot, scope);
914
- }
915
- function buildProjectedTargetEpicStories(targetEpic, snapshot) {
916
- const includedStoryIds = new Set();
917
- const storyIds = targetEpic.stories;
918
- if (Array.isArray(storyIds)) {
919
- for (const storyId of storyIds) {
920
- if (typeof storyId === 'string') {
921
- addStoryAndDependencies(storyId, snapshot, includedStoryIds);
922
- }
923
- }
924
- }
925
- const projectedStories = {};
926
- for (const storyId of includedStoryIds) {
927
- const story = snapshot.stories[storyId];
928
- if (story) {
929
- projectedStories[storyId] = story;
930
- }
931
- }
932
- return projectedStories;
933
- }
934
- function buildEpicStubs(snapshot) {
935
- const projectedEpics = {};
936
- for (const [epicId, epic] of Object.entries(snapshot.epics)) {
937
- projectedEpics[epicId] = {
938
- id: safeToken(epic.id) ?? epicId,
939
- ...(safeToken(epic.status) ? { status: safeToken(epic.status) } : {}),
940
- ...(EPIC_LIFECYCLE_CLASSIFICATIONS.includes(epic.lifecycle_classification)
941
- ? { lifecycle_classification: epic.lifecycle_classification }
942
- : {}),
943
- ...(typeof epic.total_stories === 'number' && Number.isFinite(epic.total_stories)
944
- ? { total_stories: epic.total_stories }
945
- : {}),
946
- ...(typeof epic.completed_stories === 'number' && Number.isFinite(epic.completed_stories)
947
- ? { completed_stories: epic.completed_stories }
948
- : {}),
949
- };
950
- }
951
- return projectedEpics;
952
- }
953
- function countStatuses(records) {
954
- const counts = {};
955
- for (const record of Object.values(records)) {
956
- const status = safeToken(record.status, 40) ?? 'unknown';
957
- counts[status] = (counts[status] ?? 0) + 1;
958
- }
959
- return counts;
960
- }
961
- function countEpicLifecycles(records) {
962
- const counts = Object.fromEntries(EPIC_LIFECYCLE_CLASSIFICATIONS.map((classification) => [classification, 0]));
963
- for (const record of Object.values(records)) {
964
- const classification = EPIC_LIFECYCLE_CLASSIFICATIONS.includes(record.lifecycle_classification)
965
- ? record.lifecycle_classification
966
- : 'active';
967
- counts[classification] = (counts[classification] ?? 0) + 1;
968
- }
969
- return counts;
970
- }
971
- function isActiveEpicLifecycle(snapshot, epicId) {
972
- if (!epicId)
973
- return true;
974
- const epic = snapshot.epics[epicId];
975
- if (!epic)
976
- return true;
977
- return !EPIC_LIFECYCLE_CLASSIFICATIONS.includes(epic.lifecycle_classification) || epic.lifecycle_classification === 'active';
978
- }
979
- function sortableStoryTimestamp(story) {
980
- for (const key of ['last_updated', 'updated_at', 'completed_at', 'created_at', 'discovered_at']) {
981
- const value = story[key];
982
- if (typeof value !== 'string')
983
- continue;
984
- const parsed = Date.parse(value);
985
- if (Number.isFinite(parsed))
986
- return parsed;
987
- }
988
- return 0;
989
- }
990
- function recentStories(snapshot) {
991
- return Object.entries(snapshot.stories)
992
- .map(([id, story]) => ({ id, story, timestamp: sortableStoryTimestamp(story) }))
993
- .sort((left, right) => right.timestamp - left.timestamp || left.id.localeCompare(right.id))
994
- .slice(0, RECENT_STORY_LIMIT)
995
- .map(({ id, story }) => ({
996
- id,
997
- ...(safeToken(story.epic_id) ? { epicId: safeToken(story.epic_id) } : {}),
998
- ...(safeToken(story.status, 40) ? { status: safeToken(story.status, 40) } : {}),
999
- ...(safeToken(story.last_step ?? story.lastStep) ? { lastStep: safeToken(story.last_step ?? story.lastStep) } : {}),
1000
- ...(safeToken(story.last_updated ?? story.updated_at ?? story.completed_at ?? story.created_at)
1001
- ? { lastUpdated: safeToken(story.last_updated ?? story.updated_at ?? story.completed_at ?? story.created_at) }
1002
- : {}),
1003
- }));
1004
- }
1005
- function currentSessionRef(snapshot) {
1006
- const session = snapshot.current_session;
1007
- if (!session)
1008
- return undefined;
1009
- const ref = {
1010
- activeEpicId: safeToken(session.active_epic_id) ?? null,
1011
- activeStoryId: safeToken(session.active_story_id) ?? null,
1012
- activeStepId: safeToken(session.active_step_id) ?? null,
1013
- sessionId: safeToken(session.session_id) ?? null,
1014
- startedAt: safeToken(session.started_at) ?? null,
1015
- };
1016
- return Object.values(ref).some((value) => value !== null && value !== undefined) ? ref : undefined;
1017
- }
1018
- function yoloopSessionRef(snapshot) {
1019
- const yoloop = snapshot.yoloop;
1020
- if (!isRecord(yoloop))
1021
- return undefined;
1022
- const state = isRecord(yoloop.state) ? yoloop.state : undefined;
1023
- const currentSession = isRecord(state?.currentSession) ? state.currentSession : undefined;
1024
- const lock = isRecord(yoloop.lock) ? yoloop.lock : undefined;
1025
- const ref = {
1026
- ...(typeof yoloop.active === 'boolean' ? { active: yoloop.active } : {}),
1027
- currentEpicId: safeToken(currentSession?.currentEpicId ?? yoloop.currentEpicId) ?? null,
1028
- currentStoryId: safeToken(currentSession?.currentStoryId ?? yoloop.currentStoryId) ?? null,
1029
- sessionId: safeToken(currentSession?.sessionId ?? yoloop.sessionId) ?? null,
1030
- lockEpicId: safeToken(lock?.currentEpicId ?? lock?.epicId) ?? null,
1031
- };
1032
- return Object.keys(ref).length > 0 ? ref : undefined;
1033
- }
1034
- function continuitySessionRef(snapshot) {
1035
- const continuity = snapshot.continuity;
1036
- if (!isRecord(continuity))
1037
- return undefined;
1038
- const reasonCodes = Array.isArray(continuity.reasonCodes)
1039
- ? continuity.reasonCodes.filter((entry) => typeof entry === 'string')
1040
- : undefined;
1041
- return {
1042
- present: true,
1043
- activeJobId: safeToken(continuity.activeJobId ?? continuity.jobId) ?? null,
1044
- activeGoalId: safeToken(continuity.activeGoalId ?? continuity.goalId) ?? null,
1045
- activeLoopId: safeToken(continuity.activeLoopId ?? continuity.loopId) ?? null,
1046
- ...(reasonCodes && reasonCodes.length > 0 ? { reasonCodes: safeReasonCodes(reasonCodes) } : {}),
1047
- };
1048
- }
1049
- function deriveActiveRef(snapshot, session, yoloop) {
1050
- const sessionStoryId = safeToken(session?.activeStoryId);
1051
- const sessionEpicId = safeToken(session?.activeEpicId);
1052
- const sessionStepId = safeToken(session?.activeStepId);
1053
- const sessionStoryEpicId = sessionStoryId && snapshot.stories[sessionStoryId]
1054
- ? storyEpicId(snapshot.stories[sessionStoryId], sessionStoryId)
1055
- : null;
1056
- if ((sessionStoryId || sessionEpicId || sessionStepId) && isActiveEpicLifecycle(snapshot, sessionEpicId ?? sessionStoryEpicId)) {
1057
- return {
1058
- epicId: sessionEpicId ?? null,
1059
- storyId: sessionStoryId ?? null,
1060
- stepId: sessionStepId ?? null,
1061
- };
1062
- }
1063
- const yoloopStoryId = safeToken(yoloop?.currentStoryId);
1064
- const yoloopEpicId = safeToken(yoloop?.currentEpicId ?? yoloop?.lockEpicId);
1065
- if ((yoloopStoryId || yoloopEpicId) && isActiveEpicLifecycle(snapshot, yoloopEpicId)) {
1066
- return {
1067
- epicId: yoloopEpicId ?? null,
1068
- storyId: yoloopStoryId ?? null,
1069
- stepId: null,
1070
- };
1071
- }
1072
- const latestNonTerminal = Object.entries(snapshot.stories)
1073
- .map(([id, story]) => ({ id, story, timestamp: sortableStoryTimestamp(story) }))
1074
- .filter(({ id, story }) => !isTerminalStoryStatus(story.status) && isActiveEpicLifecycle(snapshot, storyEpicId(story, id)))
1075
- .sort((left, right) => right.timestamp - left.timestamp || left.id.localeCompare(right.id))[0];
1076
- if (latestNonTerminal) {
1077
- return {
1078
- epicId: storyEpicId(latestNonTerminal.story, latestNonTerminal.id),
1079
- storyId: latestNonTerminal.id,
1080
- stepId: safeToken(latestNonTerminal.story.last_step ?? latestNonTerminal.story.lastStep) ?? null,
1081
- };
1082
- }
1083
- return { epicId: null, storyId: null, stepId: null };
1084
- }
1085
- function buildStateSummary(sourceSnapshot, scope) {
1086
- const storyStatus = countStatuses(sourceSnapshot.stories);
1087
- const epicStatus = countStatuses(sourceSnapshot.epics);
1088
- const epicLifecycle = countEpicLifecycles(sourceSnapshot.epics);
1089
- const activeEpics = Object.values(sourceSnapshot.epics).filter((epic) => {
1090
- const lifecycle = EPIC_LIFECYCLE_CLASSIFICATIONS.includes(epic.lifecycle_classification)
1091
- ? epic.lifecycle_classification
1092
- : 'active';
1093
- return lifecycle === 'active' && !isTerminalStoryStatus(epic.status);
1094
- }).length;
1095
- const session = currentSessionRef(sourceSnapshot);
1096
- const yoloop = yoloopSessionRef(sourceSnapshot);
1097
- const continuity = continuitySessionRef(sourceSnapshot);
1098
- const active = deriveActiveRef(sourceSnapshot, session, yoloop);
1099
- const recent = recentStories(sourceSnapshot);
1100
- const reasonCodes = safeReasonCodes(scope.reasonCodes, [
1101
- 'state-summary-attached',
1102
- 'state-summary-bounded',
1103
- `projection-${scope.projectionMode ?? scope.kind}`,
1104
- scope.stateProjectionPolicy ? `policy-${scope.stateProjectionPolicy}` : 'policy-unknown',
1105
- recent.length >= RECENT_STORY_LIMIT ? 'recent-stories-capped' : 'recent-stories-bounded',
1106
- active.storyId || active.epicId ? 'active-ref-derived' : 'active-ref-empty',
1107
- yoloop ? 'yoloop-session-present' : 'yoloop-session-absent',
1108
- continuity ? 'continuity-session-present' : 'continuity-session-absent',
1109
- ]);
1110
- return {
1111
- schemaVersion: 1,
1112
- totals: {
1113
- stories: Object.keys(sourceSnapshot.stories).length,
1114
- epics: Object.keys(sourceSnapshot.epics).length,
1115
- storyStatus,
1116
- epicStatus,
1117
- epicLifecycle,
1118
- activeEpics,
1119
- blockedStories: storyStatus.blocked ?? 0,
1120
- },
1121
- active,
1122
- blockedCount: storyStatus.blocked ?? 0,
1123
- recentStories: recent,
1124
- ...(session ? { currentSession: session } : {}),
1125
- ...(yoloop ? { currentYoloopSession: yoloop } : {}),
1126
- ...(continuity ? { currentContinuitySession: continuity } : {}),
1127
- projection: {
1128
- commandId: scope.commandId ?? null,
1129
- stateProjectionPolicy: scope.stateProjectionPolicy ?? null,
1130
- projectionMode: scope.projectionMode,
1131
- scopeKind: scope.kind,
1132
- includedStoryCount: scope.includedStoryCount,
1133
- includedEpicCount: scope.includedEpicCount ?? Object.keys(sourceSnapshot.epics).length,
1134
- omittedStoryCount: scope.omittedStoryCount,
1135
- omittedEpicCount: scope.omittedEpicCount,
1136
- reason: scope.reason,
1137
- },
1138
- reasonCodes,
1139
- publicSafe: true,
1140
- };
1141
- }
1142
- function withStateSummary(projected, sourceSnapshot, scope) {
1143
- return {
1144
- ...projected,
1145
- stateSummary: buildStateSummary(sourceSnapshot, scope),
1146
- };
1147
- }
1148
- function buildCreateEpicProjection(trigger, snapshot, commandPolicy) {
1149
- const projectedEpics = {};
1150
- for (const epicId of Object.keys(snapshot.epics)) {
1151
- projectedEpics[epicId] = { id: epicId };
1152
- }
1153
- const scope = {
1154
- kind: 'projected',
1155
- commandId: commandPolicy.commandId,
1156
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1157
- projectionMode: 'summary-only',
1158
- trigger,
1159
- targetEpicId: null,
1160
- targetStoryId: null,
1161
- includedStoryCount: 0,
1162
- includedEpicCount: Object.keys(projectedEpics).length,
1163
- omittedStoryCount: Object.keys(snapshot.stories).length,
1164
- omittedEpicCount: 0,
1165
- reason: 'epic-summary',
1166
- reasonCodes: ['epic-summary', 'stories-omitted', 'epic-stubs-only'],
1167
- };
1168
- return withStateSummary({
1169
- ...snapshot,
1170
- stories: {},
1171
- epics: projectedEpics,
1172
- scope,
1173
- }, snapshot, scope);
1174
- }
1175
- function buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, reasonCodes = ['summary-only', 'stories-omitted'], projectionMode = 'summary-only') {
1176
- const projectedEpics = buildEpicStubs(snapshot);
1177
- const scope = {
1178
- kind: 'projected',
1179
- commandId: commandPolicy.commandId,
1180
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1181
- projectionMode,
1182
- trigger,
1183
- targetEpicId: null,
1184
- targetStoryId: null,
1185
- includedStoryCount: 0,
1186
- includedEpicCount: Object.keys(projectedEpics).length,
1187
- omittedStoryCount: Object.keys(snapshot.stories).length,
1188
- omittedEpicCount: Math.max(0, Object.keys(snapshot.epics).length - Object.keys(projectedEpics).length),
1189
- reason: 'summary-only',
1190
- reasonCodes: safeReasonCodes(reasonCodes),
1191
- };
1192
- return withStateSummary({
1193
- ...snapshot,
1194
- stories: {},
1195
- epics: projectedEpics,
1196
- scope,
1197
- }, snapshot, scope);
1198
- }
1199
- function buildStoryProjection(trigger, snapshot, commandPolicy, targetStoryId, projectionMode, reasonCodes) {
1200
- const targetStory = snapshot.stories[targetStoryId];
1201
- if (!targetStory) {
1202
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1203
- stories: Object.keys(snapshot.stories).length,
1204
- epics: Object.keys(snapshot.epics).length,
1205
- targetKind: 'story',
1206
- });
1207
- }
1208
- const targetEpicId = storyEpicId(targetStory, targetStoryId);
1209
- if (!targetEpicId) {
1210
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1211
- stories: Object.keys(snapshot.stories).length,
1212
- epics: Object.keys(snapshot.epics).length,
1213
- targetKind: 'epic',
1214
- });
1215
- }
1216
- const targetEpic = snapshot.epics[targetEpicId];
1217
- if (!targetEpic) {
1218
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1219
- stories: Object.keys(snapshot.stories).length,
1220
- epics: Object.keys(snapshot.epics).length,
1221
- targetKind: 'epic',
1222
- });
1223
- }
1224
- // Direct *yolo needs the same epic topology seen by *yoloop so a standalone
1225
- // invocation can bootstrap the canonical P207 graph epoch. Other story
1226
- // commands remain dependency-scoped. Stories outside the owning epic are
1227
- // retained only as compact structural dependencies by the yoloop projector.
1228
- const yoloEpicGraph = projectionMode === 'yolo-story';
1229
- const projectedStories = yoloEpicGraph
1230
- ? buildProjectedYoloopStories(targetEpicId, targetEpic, snapshot)
1231
- : buildProjectedStories(targetStoryId, snapshot);
1232
- const projectedEpics = yoloEpicGraph
1233
- ? buildProjectedYoloopEpics(targetEpicId, projectedStories, snapshot)
1234
- : buildProjectedEpics(projectedStories, snapshot);
1235
- if (!projectedStories[targetStoryId] || !projectedEpics[targetEpicId]) {
1236
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1237
- stories: Object.keys(projectedStories).length,
1238
- epics: Object.keys(projectedEpics).length,
1239
- targetKind: 'story',
1240
- });
1241
- }
1242
- const scope = {
1243
- kind: 'projected',
1244
- commandId: commandPolicy.commandId,
1245
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1246
- projectionMode,
1247
- trigger,
1248
- targetEpicId,
1249
- targetStoryId,
1250
- includedStoryCount: Object.keys(projectedStories).length,
1251
- includedEpicCount: Object.keys(projectedEpics).length,
1252
- omittedStoryCount: Math.max(0, Object.keys(snapshot.stories).length - Object.keys(projectedStories).length),
1253
- omittedEpicCount: Math.max(0, Object.keys(snapshot.epics).length - Object.keys(projectedEpics).length),
1254
- reason: 'targeted-invocation',
1255
- reasonCodes: safeReasonCodes(reasonCodes, yoloEpicGraph ? ['epic-graph-authority-complete'] : []),
1256
- };
1257
- return withStateSummary({
1258
- ...snapshot,
1259
- stories: projectedStories,
1260
- epics: projectedEpics,
1261
- scope,
1262
- }, snapshot, scope);
1263
- }
1264
- function buildTargetedEpicProjection(trigger, snapshot, commandPolicy, targetEpicId, projectionMode, reasonCodes) {
1265
- const targetEpic = snapshot.epics[targetEpicId];
1266
- if (!targetEpic) {
1267
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1268
- stories: Object.keys(snapshot.stories).length,
1269
- epics: Object.keys(snapshot.epics).length,
1270
- targetKind: 'epic',
1271
- });
1272
- }
1273
- const projectedStories = buildProjectedTargetEpicStories(targetEpic, snapshot);
1274
- const projectedEpics = buildProjectedEpics(projectedStories, snapshot, [targetEpicId]);
1275
- if (!projectedEpics[targetEpicId]) {
1276
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1277
- stories: Object.keys(projectedStories).length,
1278
- epics: Object.keys(projectedEpics).length,
1279
- targetKind: 'epic',
1280
- });
1281
- }
1282
- const scope = {
1283
- kind: 'projected',
1284
- commandId: commandPolicy.commandId,
1285
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1286
- projectionMode,
1287
- trigger,
1288
- targetEpicId,
1289
- targetStoryId: null,
1290
- includedStoryCount: Object.keys(projectedStories).length,
1291
- includedEpicCount: Object.keys(projectedEpics).length,
1292
- omittedStoryCount: Math.max(0, Object.keys(snapshot.stories).length - Object.keys(projectedStories).length),
1293
- omittedEpicCount: Math.max(0, Object.keys(snapshot.epics).length - Object.keys(projectedEpics).length),
1294
- reason: 'targeted-invocation',
1295
- reasonCodes: safeReasonCodes(reasonCodes),
1296
- };
1297
- return withStateSummary({
1298
- ...snapshot,
1299
- stories: projectedStories,
1300
- epics: projectedEpics,
1301
- scope,
1302
- }, snapshot, scope);
1303
- }
1304
- function buildYoloopProjection(trigger, snapshot, commandPolicy) {
1305
- const explicitCandidate = explicitYoloopEpicCandidate(trigger);
1306
- const explicitTargetEpicId = extractTargetEpicId(trigger, snapshot);
1307
- if (explicitCandidate && !explicitTargetEpicId) {
1308
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1309
- stories: Object.keys(snapshot.stories).length,
1310
- epics: Object.keys(snapshot.epics).length,
1311
- targetKind: 'epic',
1312
- });
1313
- }
1314
- const targetEpicId = extractYoloopTargetEpicId(trigger, snapshot);
1315
- const shape = classifyInvocationShapeV2({
1316
- commandId: commandPolicy.commandId,
1317
- explicitYoloopEpicId: explicitTargetEpicId,
1318
- sessionYoloopEpicId: explicitTargetEpicId ? null : targetEpicId,
1319
- });
1320
- if (shape === 'yoloop-discovery')
1321
- return buildYoloopDiscoveryProjection(trigger, snapshot, commandPolicy);
1322
- if (!targetEpicId || (shape !== 'yoloop-target' && shape !== 'yoloop-session')) {
1323
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1324
- stories: Object.keys(snapshot.stories).length,
1325
- epics: Object.keys(snapshot.epics).length,
1326
- targetKind: 'epic',
1327
- });
1328
- }
1329
- const targetEpic = snapshot.epics[targetEpicId];
1330
- if (!targetEpic) {
1331
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1332
- stories: Object.keys(snapshot.stories).length,
1333
- epics: Object.keys(snapshot.epics).length,
1334
- targetKind: 'epic',
1335
- });
1336
- }
1337
- const projectedStories = buildProjectedYoloopStories(targetEpicId, targetEpic, snapshot);
1338
- const projectedEpics = buildProjectedYoloopEpics(targetEpicId, projectedStories, snapshot);
1339
- if (!projectedEpics[targetEpicId]) {
1340
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1341
- stories: Object.keys(projectedStories).length,
1342
- epics: Object.keys(projectedEpics).length,
1343
- targetKind: 'epic',
1344
- });
1345
- }
1346
- const projectionMode = shape;
1347
- const scope = {
1348
- kind: 'projected',
1349
- commandId: commandPolicy.commandId,
1350
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1351
- projectionMode,
1352
- trigger,
1353
- targetEpicId,
1354
- targetStoryId: null,
1355
- targetEpicCoverage: buildTargetEpicCoverage(targetEpicId, targetEpic, projectedStories),
1356
- includedStoryCount: Object.keys(projectedStories).length,
1357
- includedEpicCount: Object.keys(projectedEpics).length,
1358
- omittedStoryCount: Math.max(0, Object.keys(snapshot.stories).length - Object.keys(projectedStories).length),
1359
- omittedEpicCount: Math.max(0, Object.keys(snapshot.epics).length - Object.keys(projectedEpics).length),
1360
- reason: 'targeted-invocation',
1361
- reasonCodes: ['structural-required', projectionMode, 'yoloop-targeted'],
1362
- };
1363
- return withStateSummary({
1364
- ...snapshot,
1365
- stories: projectedStories,
1366
- epics: projectedEpics,
1367
- scope,
1368
- }, snapshot, scope);
1369
- }
1370
- function buildPayloadGuardrailEpics(snapshot, retainedStoryIds) {
1371
- const projectedEpics = {};
1372
- for (const [epicId, epic] of Object.entries(snapshot.epics)) {
1373
- const retainedEpicStories = Array.isArray(epic.stories)
1374
- ? epic.stories.filter((storyId) => typeof storyId === 'string' && retainedStoryIds.has(storyId))
1375
- : [];
1376
- projectedEpics[epicId] = {
1377
- id: safeToken(epic.id) ?? epicId,
1378
- ...(safeToken(epic.status, 40) ? { status: safeToken(epic.status, 40) } : {}),
1379
- ...(typeof epic.total_stories === 'number' && Number.isFinite(epic.total_stories)
1380
- ? { total_stories: epic.total_stories }
1381
- : {}),
1382
- ...(typeof epic.completed_stories === 'number' && Number.isFinite(epic.completed_stories)
1383
- ? { completed_stories: epic.completed_stories }
1384
- : {}),
1385
- ...(retainedEpicStories.length > 0 ? { stories: retainedEpicStories } : {}),
1386
- ...(retainedEpicStories.length > 0 && Array.isArray(epic.depends_on)
1387
- ? { depends_on: epic.depends_on.filter((value) => typeof value === 'string' && value.length > 0) }
1388
- : {}),
1389
- ...(retainedEpicStories.length > 0 && (epic.branch_mode === 'epic' || epic.branch_mode === 'story')
1390
- ? { branch_mode: epic.branch_mode }
1391
- : {}),
1392
- ...(retainedEpicStories.length > 0 && typeof epic.execution_branch === 'string'
1393
- ? { execution_branch: epic.execution_branch }
1394
- : {}),
1395
- ...(retainedEpicStories.length > 0 && typeof epic.origin_branch === 'string'
1396
- ? { origin_branch: epic.origin_branch }
1397
- : {}),
1398
- ...(retainedEpicStories.length > 0 && (epic.branch_lease === null || typeof epic.branch_lease === 'object')
1399
- ? { branch_lease: epic.branch_lease }
1400
- : {}),
1401
- ...(retainedEpicStories.length > 0 && (epic.origin_binding === null || typeof epic.origin_binding === 'object')
1402
- ? { origin_binding: epic.origin_binding }
1403
- : {}),
1404
- ...(retainedEpicStories.length > 0 && (epic.aggregate_qa_receipt === null || typeof epic.aggregate_qa_receipt === 'object')
1405
- ? { aggregate_qa_receipt: epic.aggregate_qa_receipt }
1406
- : {}),
1407
- };
1408
- }
1409
- return projectedEpics;
1410
- }
1411
- function sourceStoryTotal(snapshot) {
1412
- return snapshot.stateSummary?.totals.stories
1413
- ?? ((snapshot.scope?.includedStoryCount ?? Object.keys(snapshot.stories).length) + (snapshot.scope?.omittedStoryCount ?? 0));
1414
- }
1415
- function sourceEpicTotal(snapshot) {
1416
- return snapshot.stateSummary?.totals.epics
1417
- ?? ((snapshot.scope?.includedEpicCount ?? Object.keys(snapshot.epics).length) + (snapshot.scope?.omittedEpicCount ?? 0));
1418
- }
1419
- function updateStateSummaryForPayloadGuardrail(snapshot, scope) {
1420
- if (!snapshot.stateSummary)
1421
- return undefined;
1422
- return {
1423
- ...snapshot.stateSummary,
1424
- projection: {
1425
- ...snapshot.stateSummary.projection,
1426
- scopeKind: 'projected',
1427
- projectionMode: scope.projectionMode,
1428
- includedStoryCount: scope.includedStoryCount,
1429
- includedEpicCount: scope.includedEpicCount ?? snapshot.stateSummary.projection.includedEpicCount,
1430
- omittedStoryCount: scope.omittedStoryCount,
1431
- omittedEpicCount: scope.omittedEpicCount,
1432
- reason: 'body-size',
1433
- },
1434
- reasonCodes: safeReasonCodes(snapshot.stateSummary.reasonCodes, ['payload-size-guardrail', 'state-summary-preserved', 'nonessential-state-degraded']),
1435
- };
1436
- }
1437
- /**
1438
- * P198.04 -- deterministic post-assembly state degradation.
1439
- *
1440
- * This helper is intentionally pure and request-only. It removes historical story
1441
- * bodies that are not structural for the already-projected request, converts the
1442
- * epic map to public stubs, keeps `stateSummary`, and preserves structural-required
1443
- * story/yolo/yoloop target state instead of silently corrupting it.
1444
- */
1445
- export function degradeStateSnapshotForPayloadLimit(snapshot) {
1446
- const scope = snapshot.scope;
1447
- const retainedStoryIds = new Set();
1448
- const preserveProjectedStructuralStories = scope?.projectionMode === 'structural-required'
1449
- || scope?.projectionMode === 'yolo-story'
1450
- || scope?.projectionMode === 'yoloop-target'
1451
- || scope?.projectionMode === 'yoloop-session'
1452
- || scope?.projectionMode === 'yoloop-discovery';
1453
- if (preserveProjectedStructuralStories) {
1454
- for (const storyId of Object.keys(snapshot.stories)) {
1455
- retainedStoryIds.add(storyId);
1456
- }
1457
- }
1458
- else if (scope?.targetStoryId) {
1459
- addStoryAndDependencies(scope.targetStoryId, snapshot, retainedStoryIds);
1460
- }
1461
- const projectedStories = {};
1462
- for (const storyId of retainedStoryIds) {
1463
- const story = snapshot.stories[storyId];
1464
- if (story)
1465
- projectedStories[storyId] = story;
1466
- }
1467
- const projectedEpics = buildPayloadGuardrailEpics(snapshot, retainedStoryIds);
1468
- const includedStoryCount = Object.keys(projectedStories).length;
1469
- const includedEpicCount = Object.keys(projectedEpics).length;
1470
- const omittedStoryCount = Math.max(0, sourceStoryTotal(snapshot) - includedStoryCount);
1471
- const omittedEpicCount = Math.max(0, sourceEpicTotal(snapshot) - includedEpicCount);
1472
- const projectionMode = preserveProjectedStructuralStories
1473
- ? scope?.projectionMode ?? 'structural-required'
1474
- : scope?.projectionMode === 'yolo-story'
1475
- ? 'yolo-story'
1476
- : 'summary-only';
1477
- const nextScope = {
1478
- kind: 'projected',
1479
- commandId: scope?.commandId ?? null,
1480
- stateProjectionPolicy: scope?.stateProjectionPolicy ?? null,
1481
- projectionMode,
1482
- targetEpicId: scope?.targetEpicId ?? null,
1483
- targetStoryId: scope?.targetStoryId ?? null,
1484
- ...(scope?.targetEpicCoverage ? { targetEpicCoverage: scope.targetEpicCoverage } : {}),
1485
- includedStoryCount,
1486
- includedEpicCount,
1487
- omittedStoryCount,
1488
- omittedEpicCount,
1489
- reason: 'body-size',
1490
- reasonCodes: safeReasonCodes(scope?.reasonCodes, [
1491
- 'payload-size-guardrail',
1492
- retainedStoryIds.size > 0 ? 'structural-targets-preserved' : 'stories-omitted',
1493
- 'epics-stubbed',
1494
- 'state-summary-preserved',
1495
- 'redundant-trigger-omitted',
1496
- ]),
1497
- };
1498
- const stateSummary = updateStateSummaryForPayloadGuardrail(snapshot, nextScope);
1499
- return {
1500
- ...snapshot,
1501
- stories: projectedStories,
1502
- epics: projectedEpics,
1503
- scope: nextScope,
1504
- ...(stateSummary ? { stateSummary } : {}),
1505
- };
1506
- }
1507
- /**
1508
- * Return a request-scoped state snapshot for invoke commands.
1509
- *
1510
- * The function is intentionally pure. Structural uncertainty fails closed;
1511
- * callers must surface the public code instead of sending a full-state fallback.
1512
- */
1513
- export function projectStateSnapshotForInvoke(args, snapshot) {
1514
- const trigger = args.trim();
1515
- const commandPolicy = resolveCommandProjectionPolicy(trigger);
1516
- try {
1517
- if (!commandPolicy) {
1518
- if (firstTokenIsStoryReference(trigger)) {
1519
- const storyReferencePolicy = policy('story-reference', 'story-targeted');
1520
- const targetStoryId = extractStoryId(trigger);
1521
- if (targetStoryId) {
1522
- return buildStoryProjection(trigger, snapshot, storyReferencePolicy, targetStoryId, 'targeted-story', ['story-reference-targeted']);
1523
- }
1524
- }
1525
- return buildSummaryOnlyProjection(trigger, snapshot, policy('unknown', 'adaptive-targeted'), ['unknown-command-summary-only']);
1526
- }
1527
- if (commandPolicy.stateProjectionPolicy === 'epic-summary') {
1528
- return buildCreateEpicProjection(trigger, snapshot, commandPolicy);
1529
- }
1530
- if (commandPolicy.stateProjectionPolicy === 'yoloop-targeted') {
1531
- return buildYoloopProjection(trigger, snapshot, commandPolicy);
1532
- }
1533
- const targetStoryId = extractStoryId(trigger);
1534
- if (commandPolicy.stateProjectionPolicy === 'story-targeted') {
1535
- if (targetStoryId) {
1536
- const invocationShape = classifyInvocationShapeV2({ commandId: commandPolicy.commandId, targetStoryId });
1537
- const yoloStory = invocationShape === 'yolo-story';
1538
- return buildStoryProjection(trigger, snapshot, commandPolicy, targetStoryId, yoloStory ? 'yolo-story' : commandPolicy.structuralRequired ? 'structural-required' : 'targeted-story', [yoloStory ? 'yolo-story' : commandPolicy.structuralRequired ? 'structural-required' : 'targeted-story']);
1539
- }
1540
- if (commandPolicy.commandId === 'yolo' || commandPolicy.commandId === 'yolo-inline') {
1541
- const invocationShape = classifyInvocationShapeV2({ commandId: commandPolicy.commandId });
1542
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['yolo-inline', 'stories-omitted', 'historical-content-omitted'], invocationShape ?? 'yolo-inline');
1543
- }
1544
- // Commit without a story is an exact root working-tree workflow. It
1545
- // needs no story graph, but a malformed or unknown target must not gain
1546
- // this summary-only escape from structural target validation.
1547
- if (commandPolicy.commandId === 'commit' && /^\*?(?:commit|commit-push)$/i.test(trigger)) {
1548
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['working-tree-commit', 'stories-omitted', 'historical-content-omitted']);
1549
- }
1550
- return commandPolicy.structuralRequired
1551
- ? (() => {
1552
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1553
- stories: Object.keys(snapshot.stories).length,
1554
- epics: Object.keys(snapshot.epics).length,
1555
- targetKind: 'story',
1556
- });
1557
- })()
1558
- : buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['story-target-missing-summary-only']);
1559
- }
1560
- if (commandPolicy.stateProjectionPolicy === 'adaptive-targeted') {
1561
- if (targetStoryId && snapshot.stories[targetStoryId]) {
1562
- return buildStoryProjection(trigger, snapshot, commandPolicy, targetStoryId, 'targeted-story', ['adaptive-story-targeted']);
1563
- }
1564
- const targetEpicId = extractTargetEpicId(trigger, snapshot);
1565
- if (targetEpicId) {
1566
- return buildTargetedEpicProjection(trigger, snapshot, commandPolicy, targetEpicId, 'targeted-epic', ['adaptive-epic-targeted']);
1567
- }
1568
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['adaptive-summary-only', 'target-unresolved-summary-only']);
1569
- }
1570
- if (commandPolicy.stateProjectionPolicy === 'epic-targeted') {
1571
- // The root *arch-plan pipeline delegates its current stage with the
1572
- // internal marker `epic-arch`. It has no user-selected epic yet; keep
1573
- // this exact marker only when the bounded root checkpoint names the
1574
- // same stage. The server still verifies the accounting receipt.
1575
- if (commandPolicy.commandId.startsWith('arch-')
1576
- && /(?:^|\s)epic-arch\s*$/i.test(trigger)
1577
- && snapshot.archPlan?.execution?.currentStageCommand === commandPolicy.commandId) {
1578
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['architecture-root-delegated']);
1579
- }
1580
- const targetEpicId = extractTargetEpicId(trigger, snapshot);
1581
- if (targetEpicId) {
1582
- return buildTargetedEpicProjection(trigger, snapshot, commandPolicy, targetEpicId, commandPolicy.structuralRequired ? 'structural-required' : 'targeted-epic', [commandPolicy.structuralRequired ? 'structural-required' : 'targeted-epic']);
1583
- }
1584
- return commandPolicy.structuralRequired
1585
- ? (() => {
1586
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1587
- stories: Object.keys(snapshot.stories).length,
1588
- epics: Object.keys(snapshot.epics).length,
1589
- targetKind: 'epic',
1590
- });
1591
- })()
1592
- : buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['epic-target-missing-summary-only']);
1593
- }
1594
- if (commandPolicy.stateProjectionPolicy === 'continuity-scoped') {
1595
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['continuity-scoped-summary-only']);
1596
- }
1597
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['policy-full-summary-only']);
1598
- }
1599
- catch (error) {
1600
- if (error instanceof StructuralDagError)
1601
- throw error;
1602
- if (commandPolicy?.structuralRequired) {
1603
- throw new StructuralDagError('STRUCTURAL_DEPENDENCY_MISSING', {
1604
- stories: Object.keys(snapshot.stories).length,
1605
- epics: Object.keys(snapshot.epics).length,
1606
- projectionErrors: 1,
1607
- });
1608
- }
1609
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy ?? policy('unknown', 'adaptive-targeted'), ['projection-error-summary-only']);
1610
- }
1611
- }
1612
- const V2_INVOCATION_SHAPES = new Set([
1613
- 'yolo-story',
1614
- 'yolo-inline',
1615
- 'yoloop-target',
1616
- 'yoloop-session',
1617
- 'yoloop-discovery',
1618
- ]);
1619
- function projectedEdgeCount(snapshot) {
1620
- let edges = 0;
1621
- for (const collection of [snapshot.stories, snapshot.epics]) {
1622
- for (const entry of Object.values(collection)) {
1623
- if (Array.isArray(entry.depends_on)) {
1624
- edges += entry.depends_on.filter((value) => typeof value === 'string').length;
1625
- }
1626
- }
1627
- }
1628
- return edges;
1629
- }
1630
- /**
1631
- * Versioned result contract for the five structural YOLO/yoloop shapes.
1632
- * Other command families retain their existing projection policy and return
1633
- * null because they are outside StateProjectionV2's closed shape union.
1634
- */
1635
- export function projectStateSnapshotResultV2ForInvoke(args, snapshot) {
1636
- const commandPolicy = resolveCommandProjectionPolicy(args.trim());
1637
- if (!commandPolicy
1638
- || !['yolo', 'yolo-inline', 'yoloop'].includes(commandPolicy.commandId)) {
1639
- return null;
1640
- }
1641
- try {
1642
- const projected = projectStateSnapshotForInvoke(args, snapshot);
1643
- const shape = projected.scope?.projectionMode;
1644
- if (!shape || !V2_INVOCATION_SHAPES.has(shape)) {
1645
- throw new StructuralDagError('STRUCTURAL_DEPENDENCY_MISSING', {
1646
- stories: Object.keys(projected.stories).length,
1647
- epics: Object.keys(projected.epics).length,
1648
- projectionShapeErrors: 1,
1649
- });
1650
- }
1651
- return Object.freeze({
1652
- ok: true,
1653
- version: 2,
1654
- shape,
1655
- snapshot: projected,
1656
- included: {
1657
- epics: projected.scope?.includedEpicCount ?? Object.keys(projected.epics).length,
1658
- stories: projected.scope?.includedStoryCount ?? Object.keys(projected.stories).length,
1659
- edges: projectedEdgeCount(projected),
1660
- },
1661
- omitted: {
1662
- epics: projected.scope?.omittedEpicCount ?? 0,
1663
- stories: projected.scope?.omittedStoryCount ?? 0,
1664
- },
1665
- cycleCount: 0,
1666
- });
1667
- }
1668
- catch (error) {
1669
- if (!(error instanceof StructuralDagError))
1670
- throw error;
1671
- return Object.freeze({
1672
- ok: false,
1673
- code: error.code,
1674
- publicDetails: error.publicDetails,
1675
- });
1676
- }
1677
- }
1
+ import{createHash as H}from"node:crypto";import{analyzeDependencyDag as I,StructuralDagError as y}from"./structural-dag-projection.js";import{classifyInvocationShapeV2 as O}from"./invocation-shape.js";const U=12,J=16,k=["active","archived","rolled-back","synthetic","orphan"],Q=new Set(["in-progress","branch-ready","diagnose","research","write-spec","create-tasks","implemented","refactor-suggest-done","property-tests-emitted","tests-validated","qa-gate-passed","memory-updated","committed","synced","pr-created","pr-reviewed","partial"]),n=(r,e,t={})=>({commandId:r,stateProjectionPolicy:e,...t}),A=Object.freeze({status:n("status","full"),"arch-plan":n("arch-plan","full"),"arch-prd":n("arch-prd","full"),"arch-architecture":n("arch-architecture","epic-targeted",{structuralRequired:!0}),"arch-api-contracts":n("arch-api-contracts","epic-targeted",{structuralRequired:!0}),"arch-api-integrations":n("arch-api-integrations","epic-targeted",{structuralRequired:!0}),"arch-database":n("arch-database","epic-targeted",{structuralRequired:!0}),"arch-security":n("arch-security","epic-targeted",{structuralRequired:!0}),"arch-design-system":n("arch-design-system","epic-targeted",{structuralRequired:!0}),"arch-ux-design":n("arch-ux-design","epic-targeted",{structuralRequired:!0}),"arch-performance":n("arch-performance","epic-targeted",{structuralRequired:!0}),"arch-testing":n("arch-testing","epic-targeted",{structuralRequired:!0}),"arch-infrastructure":n("arch-infrastructure","epic-targeted",{structuralRequired:!0}),"arch-review":n("arch-review","epic-targeted",{structuralRequired:!0}),"arch-fitness-functions":n("arch-fitness-functions","epic-targeted",{structuralRequired:!0}),"create-epic":n("create-epic","epic-summary"),"idea-diagnose":n("idea-diagnose","full"),"idea-research":n("idea-research","epic-targeted",{structuralRequired:!0}),"generate-epic":n("generate-epic","epic-targeted",{structuralRequired:!0}),exec:n("exec","story-targeted",{structuralRequired:!0}),yolo:n("yolo","story-targeted",{structuralRequired:!0}),"yolo-inline":n("yolo-inline","story-targeted",{structuralRequired:!0}),epic:n("epic","epic-targeted",{structuralRequired:!0}),"setup-branch":n("setup-branch","story-targeted",{structuralRequired:!0}),diagnose:n("diagnose","adaptive-targeted"),"diagnose-inline":n("diagnose-inline","full"),research:n("research","adaptive-targeted"),"research-inline":n("research-inline","full"),"write-spec":n("write-spec","story-targeted",{structuralRequired:!0}),"create-tasks":n("create-tasks","story-targeted",{structuralRequired:!0}),implement:n("implement","story-targeted",{structuralRequired:!0}),commit:n("commit","story-targeted",{structuralRequired:!0}),"commit-push":n("commit","story-targeted",{structuralRequired:!0}),sync:n("sync","story-targeted",{structuralRequired:!0}),"sync-main":n("sync","story-targeted",{structuralRequired:!0}),"create-pr":n("create-pr","story-targeted",{structuralRequired:!0}),review:n("review","story-targeted"),"review-pr":n("review","story-targeted"),merge:n("merge","story-targeted",{structuralRequired:!0}),"merge-pr":n("merge","story-targeted",{structuralRequired:!0}),"fix-blocked":n("fix-blocked","story-targeted"),"finalize-epic":n("finalize-epic","epic-targeted"),"resolve-conflicts":n("resolve-conflicts","story-targeted"),"update-memory":n("update-memory","full"),"update-project-memory":n("update-memory","story-targeted",{structuralRequired:!0}),refactor:n("refactor","adaptive-targeted"),"refactor-suggest":n("refactor","story-targeted",{structuralRequired:!0}),cleanup:n("cleanup","full"),audit:n("audit","full"),"tech-debt":n("tech-debt","full"),menu:n("menu","full"),plans:n("plans","full"),billing:n("billing","full"),subscribe:n("subscribe","full"),"qa-scan":n("qa-scan","full"),yoloop:n("yoloop","yoloop-targeted",{structuralRequired:!0}),"migrate-state":n("migrate-state","full"),"migrate-project-id":n("migrate-project-id","full"),"policy-audit":n("policy-audit","full"),"mutation-test":n("mutation-test","full"),"sync-openapi":n("sync-openapi","full"),"generate-pacts":n("generate-pacts","full"),"verify-pacts":n("verify-pacts","full"),"property-test":n("property-test","full"),"property-tests":n("property-test","story-targeted",{structuralRequired:!0}),"chaos-plan":n("chaos-plan","full"),"ui-ux-review":n("ui-ux-review","adaptive-targeted"),"solyd-system":n("solyd-system","adaptive-targeted"),goal:n("goal","continuity-scoped"),loop:n("loop","continuity-scoped"),jobs:n("jobs","continuity-scoped"),runner:n("runner","continuity-scoped"),"goal-tick":n("goal-tick","continuity-scoped"),"loop-tick":n("loop-tick","continuity-scoped"),"validate-tests":n("validate-tests","story-targeted",{structuralRequired:!0}),"qa-gate":n("qa-gate","story-targeted",{structuralRequired:!0})}),X=Object.freeze({st:"status",arquitetura:"arch-plan",architecture:"arch-plan",arch:"arch-plan",prd:"arch-prd","product-requirements":"arch-prd","arch-doc":"arch-architecture","tech-architecture":"arch-architecture","api-contracts":"arch-api-contracts","api-contract":"arch-api-contracts","api-integrations":"arch-api-integrations","api-int":"arch-api-integrations","database-schema":"arch-database","db-schema":"arch-database",db:"arch-database","cyber-security":"arch-security",security:"arch-security",sec:"arch-security","design-system":"arch-design-system",ds:"arch-design-system","atomic-design":"arch-design-system","ux-design":"arch-ux-design",ux:"arch-ux-design",wireframes:"arch-ux-design",wireframe:"arch-ux-design","user-flows":"arch-ux-design",performance:"arch-performance",perf:"arch-performance","capacity-planning":"arch-performance",capacity:"arch-performance","arch-perf":"arch-performance","performance-strategy":"arch-performance","testing-strategy":"arch-testing","test-plan":"arch-testing","test-strategy":"arch-testing","arch-test":"arch-testing",infrastructure:"arch-infrastructure",infra:"arch-infrastructure","deploy-plan":"arch-infrastructure",deployment:"arch-infrastructure","arch-infra":"arch-infrastructure","arch-deploy":"arch-infrastructure","review-consolidation":"arch-review",consolidation:"arch-review","architecture-review":"arch-review","arch-consolidation":"arch-review",fitness:"arch-fitness-functions","fitness-functions":"arch-fitness-functions",archfit:"arch-fitness-functions","arch-fit":"arch-fitness-functions","fit-funcs":"arch-fitness-functions","criar-epic":"create-epic",planejamento:"create-epic","idea-diag":"idea-diagnose","idea-pesq":"idea-research","gerar-epic":"generate-epic",executar:"exec",pipeline:"exec","parallel-epic":"epic",setup:"setup-branch",branch:"setup-branch",diag:"diagnose",diagnostico:"diagnose",c02:"diagnose",pesquisar:"research",pesq:"research","research-fix":"research",c03:"research",spec:"write-spec",especificacao:"write-spec",c04:"write-spec",tasks:"create-tasks",tarefas:"create-tasks",c05:"create-tasks",impl:"implement",implementar:"implement",c06:"implement",push:"commit",commit_push:"commit",cp:"commit",c07:"commit",sincronizar:"sync",c08:"sync",pr:"create-pr",c09:"create-pr",revisar:"review",c11:"review",mesclar:"merge",c12:"merge",fix:"fix-blocked",corrigir:"fix-blocked",finalizar:"finalize-epic",conflitos:"resolve-conflicts",memoria:"update-memory",refactoring:"refactor",refact:"refactor",refac:"refactor",rf:"refactor","cleanup-code":"refactor","code-cleanup":"refactor","code-quality":"refactor","improve-code":"refactor",modernize:"refactor",modernization:"refactor",legacy:"refactor","legacy-code":"refactor","debt-pay":"refactor","pay-debt":"refactor","debt-reduction":"refactor","smell-fix":"refactor","fix-smells":"refactor","code-smells":"refactor",strangler:"refactor","strangler-fig":"refactor",limpar:"cleanup",limpeza:"cleanup",auditar:"audit",auditoria:"audit",debt:"tech-debt",debts:"tech-debt","debt-list":"tech-debt","tech-debts":"tech-debt",td:"tech-debt",help:"menu",ajuda:"menu","?":"menu",commands:"menu",cmds:"menu",planos:"plans",pricing:"plans",bill:"billing",subscription:"billing",sub:"billing",upgrade:"subscribe",checkout:"subscribe",qa:"qa-scan","qa-test":"qa-scan","visual-qa":"qa-scan","e2e-scan":"qa-scan",troubleshoot:"qa-scan","debug-ui":"qa-scan",scan:"qa-scan",a11y:"qa-scan",accessibility:"qa-scan",wcag:"qa-scan","auto-yolo":"yoloop","epic-runner":"yoloop","story-runner":"yoloop","loop-yolo":"yoloop","auto-epic":"yoloop",migrate:"migrate-state","state-migrate":"migrate-state","schema-migrate":"migrate-state",policy:"policy-audit","audit-policy":"policy-audit","policy-history":"policy-audit",policies:"policy-audit",mutation:"mutation-test",stryker:"mutation-test","kill-mutants":"mutation-test","openapi-sync":"sync-openapi","api-sync":"sync-openapi","spec-sync":"sync-openapi","regen-openapi":"sync-openapi",pacts:"generate-pacts","gen-pacts":"generate-pacts","regen-pacts":"generate-pacts","create-pacts":"generate-pacts","verify-pact":"verify-pacts","pact-verify":"verify-pacts","check-pacts":"verify-pacts","pact-check":"verify-pacts",property:"property-test",pbt:"property-test",proptest:"property-test","invariant-test":"property-test",chaos:"chaos-plan",gameday:"chaos-plan","resilience-test":"chaos-plan","ux-review":"ui-ux-review","design-review":"ui-ux-review","visual-review":"ui-ux-review","product-polish":"ui-ux-review","security-system":"solyd-system","authorized-security":"solyd-system","sec-system":"solyd-system",goals:"goal","durable-goal":"goal","continuity-goal":"goal",loops:"loop","durable-loop":"loop","continuity-loop":"loop",job:"jobs","continuity-jobs":"jobs","neocortex-runner":"runner","continuity-runner":"runner"}),ee=Object.freeze({1:"status",3:"arch-plan",4:"arch-prd",5:"arch-architecture",6:"arch-api-contracts",7:"arch-api-integrations",8:"arch-database",9:"arch-security",10:"arch-design-system",11:"arch-ux-design",12:"arch-performance",13:"arch-testing",14:"arch-infrastructure",15:"arch-review",16:"arch-fitness-functions",17:"create-epic",18:"idea-diagnose",19:"idea-research",20:"generate-epic",21:"exec",22:"yolo",23:"epic",24:"setup-branch",25:"diagnose",26:"research",27:"write-spec",28:"create-tasks",29:"implement",30:"commit",31:"sync",32:"create-pr",33:"review",34:"merge",35:"fix-blocked",36:"finalize-epic",37:"resolve-conflicts",38:"update-memory",39:"refactor",40:"cleanup",41:"audit",42:"tech-debt",43:"menu",44:"plans",45:"billing",46:"subscribe",47:"qa-scan",48:"yoloop",49:"migrate-state",50:"policy-audit",51:"mutation-test",52:"sync-openapi",53:"generate-pacts",54:"verify-pacts",55:"property-test",56:"chaos-plan",57:"ui-ux-review",58:"solyd-system",59:"goal",60:"loop",61:"jobs",62:"runner"});function d(r,e=120){if(typeof r!="string")return;const t=r.trim();if(t)return t.replace(/[^a-z0-9_.:-]+/gi,"_").slice(0,e)}function w(r,e=120){if(typeof r!="string")return;const t=r.trim(),i=d(r,e);return i===t?i:void 0}function T(r){if(typeof r!="string")return;const e=r.trim();if(!(!e||e.length>240||!/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(e)||e.includes("..")||e.includes("//")||e.includes("@{")||e.endsWith("/")||e.endsWith(".")||e.split("/").some(t=>!t||t.startsWith(".")||t.endsWith(".lock"))))return e}function te(r){if(typeof r!="string")return;const e=r.replace(/\\/g,"/");if(!(!e||e.length>240||e.startsWith("/")||/^[A-Za-z]:/.test(e)||e.includes("..")||e.includes("//")||e.split("/").includes(".")||!/^[A-Za-z0-9._/:@#-]+$/.test(e)))return e}function S(r){if(r===void 0||!Array.isArray(r)||r.length>128)return;const e=r.map(te);if(!e.some(t=>t===void 0))return[...new Set(e)].sort((t,i)=>t.localeCompare(i,"en"))}function re(r){return typeof r=="string"&&Q.has(r.trim().toLowerCase().replace(/_/g,"-"))}function C(r,e){const t={};for(const i of e){const c=r[i];typeof c=="string"||typeof c=="boolean"||typeof c=="number"&&Number.isFinite(c)?t[i]=c:Array.isArray(c)&&c.every(o=>typeof o=="string")&&(t[i]=[...c])}return t}function ie(r,e){const t=e.checkpoint;if(!h(t)||t.schemaVersion!==1||t.storyId!==r||t.epicId!==e.epic_id||!T(t.branch)||typeof t.baseSha!="string"||!/^[0-9a-f]{7,64}$/i.test(t.baseSha)||typeof t.headSha!="string"||!/^[0-9a-f]{7,64}$/i.test(t.headSha)||t.baseSha===t.headSha||!w(t.idempotencyKey)||typeof t.recordedAt!="string"||!Number.isFinite(Date.parse(t.recordedAt))||!Array.isArray(t.commits)||t.commits.length===0||t.commits.length>256||t.commits.some(c=>typeof c!="string"||!/^[0-9a-f]{7,64}$/i.test(c))||!Array.isArray(t.receiptRefs)||t.receiptRefs.length===0||t.receiptRefs.length>256||t.receiptRefs.some(c=>typeof c!="string"||c.length>240||c.includes("..")||!/^[A-Za-z0-9._:/#\-[\]]+$/.test(c))||!h(t.qaReceipt)||t.qaReceipt.kind!=="story_qa_evidence"||t.qaReceipt.producer!=="local-yolo-tdd"||!["passed","blocked"].includes(String(t.qaVerdict))||!["approved","changes-requested","pending"].includes(String(t.reviewVerdict))||(t.reviewVerdict==="pending"?t.reviewReceipt!==void 0:!h(t.reviewReceipt)))return;const i=C(t,["schemaVersion","storyId","epicId","branch","baseSha","headSha","idempotencyKey","dispatchId","bundleId","bundleDigest","graphRevision","claimRevision","qaVerdict","reviewVerdict","recordedAt","commits","receiptRefs"]);return i.qaReceipt=C(t.qaReceipt,["schemaVersion","kind","producer","evidenceVersion","storyId","epicId","contract","command","manifestDigest","gateIds","resultDigest","baseSha","headSha","bundleDigest","graphRevision","sourceEvidenceDigest","verdict","checkedAt","receiptRef"]),h(t.reviewReceipt)&&(i.reviewReceipt=C(t.reviewReceipt,["schemaVersion","kind","producer","storyId","epicId","baseSha","headSha","bundleDigest","graphRevision","sourceEvidenceDigest","qaReceiptRef","verdict","reviewedAt","receiptRef"])),i}function ce(r,e){const t=e.checkpoint_verification;if(!(!h(t)||t.schemaVersion!==1||t.kind!=="story_checkpoint_physical_verification"||t.producer!=="client-p205-transient-v1"||t.publicSafe!==!0||t.storyId!==r||t.epicId!==e.epic_id||!["verified","rejected"].includes(String(t.verdict))))return C(t,["schemaVersion","kind","producer","storyId","epicId","branch","baseSha","headSha","aggregateHeadSha","commitBodyDigest","changedPathsDigest","claimVerification","effectiveClaimRevision","command","manifestDigest","gateIds","resultDigest","graphRevision","executionEvidenceDigest","sourceEvidenceDigest","verifiedAt","verdict","reasonCodes","publicSafe"])}function M(r,e){const t=e.scheduling_checkpoint_evidence,i=new Set(["schemaVersion","kind","producer","storyId","epicId","branch","baseSha","headSha","graphRevision","effectiveClaimRevision","sourceEvidenceDigest","verifiedAt","reasonCodes","integrationAuthorized","publicSafe"]);if(!(!h(t)||Object.keys(t).some(c=>!i.has(c))||t.schemaVersion!==1||t.kind!=="story_scheduling_checkpoint_evidence"||t.producer!=="client-git-physical-v1"||t.publicSafe!==!0||t.integrationAuthorized!==!1||t.storyId!==r||t.epicId!==e.epic_id||!T(t.branch)||typeof t.baseSha!="string"||!/^[0-9a-f]{40,64}$/i.test(t.baseSha)||typeof t.headSha!="string"||!/^[0-9a-f]{40,64}$/i.test(t.headSha)||typeof t.graphRevision!="string"||!/^[0-9a-f]{64}$/i.test(t.graphRevision)||typeof t.effectiveClaimRevision!="string"||!/^[0-9a-f]{64}$/i.test(t.effectiveClaimRevision)||typeof t.sourceEvidenceDigest!="string"||!/^[0-9a-f]{64}$/i.test(t.sourceEvidenceDigest)||typeof t.verifiedAt!="string"||!Number.isFinite(Date.parse(t.verifiedAt))||!Array.isArray(t.reasonCodes)||t.reasonCodes.length!==1||t.reasonCodes[0]!=="checkpoint-git-scheduling-verified"))return C(t,[...i])}function oe(r,e){const t={...e},i=M(r,e);return i?(t.scheduling_checkpoint_evidence=i,delete t.checkpoint,delete t.checkpoint_verification):delete t.scheduling_checkpoint_evidence,t}function h(r){return r!==null&&typeof r=="object"&&!Array.isArray(r)}function _(...r){const e=new Set,t=[];for(const i of r)for(const c of i??[]){const o=d(c,80);if(!(!o||e.has(o))&&(e.add(o),t.push(o),t.length>=J))return t}return t}function ne(r){return r.trim().replace(/^@?\*/,"").replace(/^@/,"").toLowerCase()}function se(r){return r.trim().split(/\s+/,1)[0]??""}function z(r){if(/^@epic-P[0-9]{1,12}$/.test(r.trim()))return A.epic;const e=se(r);if(!e)return A.menu;const t=ne(e),i=ee[t]??X[t]??t;return A[i]??null}function ae(r,e,t,i="full-compatible",c=["full-state"]){return{kind:"full",commandId:t?.commandId??null,stateProjectionPolicy:t?.stateProjectionPolicy??null,projectionMode:i,trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:Object.keys(e.stories).length,includedEpicCount:Object.keys(e.epics).length,omittedStoryCount:0,omittedEpicCount:0,reason:"full-state",reasonCodes:_(c)}}function ze(r,e,t,i="full-compatible",c=["full-state"]){const o=ae(r,e,t,i,c);return v({...e,scope:o},e,o)}function de(r){const[e]=r.trim().split(/\s+/,1);return e?/^[A-Z]?\d+(?:\.\d+)+$/i.test(e.replace(/^@/,""))||/(?:^|\/)[A-Z]?\d+(?:\.\d+)+\.story\.md$/i.test(e.replace(/^@/,"")):!1}function F(r){const e=r.match(/(?:^|[/@\s])([A-Z]?\d+(?:\.\d+)+)\.story\.md\b/i);return e?.[1]?e[1]:r.match(/(?:^|\s|@)([A-Z]?\d+(?:\.\d+)+)(?=$|\s)/i)?.[1]??null}function ue(r){const e=r.trim(),t=e.search(/\s/);return t===-1?"":e.slice(t).trim()}function q(r){return ue(r).split(/\s+/).map(e=>e.replace(/^@/,"").replace(/^['"]|['"]$/g,"")).filter(e=>e.length>0&&!e.startsWith("-"))}function Fe(r){return q(r)[0]??null}function P(r,e){const i=r.replace(/^@/,"").replace(/^epic-/i,"").replace(/\.md$/i,""),c=[i,i.toUpperCase(),/^p\d+$/i.test(i)?`P${i.replace(/^p/i,"")}`:null,/^\d+$/.test(i)?`P${i}`:null].filter(o=>typeof o=="string"&&o.length>0);for(const o of c)if(e.epics[o])return o;return null}function le(r,e){const t=r.match(/(?:^|[/@\s])epic-(P?\d+)\.md\b/i);return t?.[1]?P(t[1],e):null}function R(r,e){const t=r.trim().match(/^@epic-(P[0-9]{1,12})$/);if(t)return P(t[1],e);const i=le(r,e);if(i)return i;for(const c of q(r)){if(/^[A-Z]?\d+(?:\.\d+)+$/i.test(c))continue;const o=P(c,e);if(o)return o}return null}function pe(r,e){const t=R(r,e);if(t)return t;const i=e.yoloop,c=i?.state?.currentSession?.currentEpicId;if(typeof c=="string"&&e.epics[c])return c;const o=i?.lock?.currentEpicId??i?.lock?.epicId;return typeof o=="string"&&e.epics[o]?o:null}function fe(r){const e=r.match(/(?:^|[/@\s])epic-(P?\d+)\.md\b/i)?.[1];if(e)return/^P/i.test(e)?e.toUpperCase():`P${e}`;for(const t of q(r)){if(/^P\d+$/i.test(t))return t.toUpperCase();if(/^\d+$/.test(t))return`P${t}`}return null}function j(r,e){if(typeof r.epic_id=="string"&&r.epic_id.length>0)return r.epic_id;const t=e.split(".").slice(0,-1).join(".");return t.length>0?t:null}function L(r){return typeof r=="string"&&["done","completed","merged","cancelled","canceled","abandoned"].includes(r.toLowerCase())}function x(r,e,t){if(t.has(r))return;const i=e.stories[r];if(!i)return;t.add(r);const c=i.depends_on;if(Array.isArray(c))for(const o of c)typeof o=="string"&&x(o,e,t)}function ye(r,e){const t=I(e.stories,[r]),i={};for(const c of t.orderedIds){const o=e.stories[c];o&&(i[c]=o)}return i}function $(r,e,t=[]){const i={};for(const c of t)e.epics[c]&&(i[c]=e.epics[c]);for(const[c,o]of Object.entries(r)){const s=j(o,c);s&&e.epics[s]&&(i[s]=e.epics[s])}return i}function me(r,e,t){if(t.has(r))return;const i=e.epics[r];if(!i)return;t.add(r);const c=i.depends_on;if(Array.isArray(c))for(const o of c)typeof o=="string"&&o.length>0&&me(o,e,t)}function V(r,e,t){const i=I(t.epics,[r]),c=new Set(i.orderedIds);for(const[s,a]of Object.entries(e)){const u=j(a,s);u&&t.epics[u]&&c.add(u)}const o={};for(const s of[...c].sort((a,u)=>a.localeCompare(u,"en"))){const a=t.epics[s];a&&(o[s]=s===r?a:K(s,a))}return o}function G(r,e,t){const i=e.stories;if(!Array.isArray(i)||i.some(s=>typeof s!="string"||s.length===0))throw new y("STRUCTURAL_DEPENDENCY_MISSING",{nodes:0,edges:0,malformedStoryMemberships:1});const c=I(t.stories,i),o={};for(const s of c.orderedIds){const a=t.stories[s];a&&(o[s]=j(a,s)===r?oe(s,a):Y(s,a))}return o}function ge(r,e,t){const i=[...e.stories].sort((s,a)=>s.localeCompare(a,"en")),c=Object.entries(t).filter(([s,a])=>j(a,s)===r).map(([s])=>s).sort((s,a)=>s.localeCompare(a,"en")),o=H("sha256").update(`target-epic-coverage-v1\0${JSON.stringify({targetEpicId:r,declaredStoryIds:i,includedStoryIds:c})}`).digest("hex");return{schemaVersion:"TargetEpicCoverage/1.0",targetEpicId:r,declaredStoryIds:i,includedStoryIds:c,membershipSha256:o,publicSafe:!0}}function Y(r,e){const t=Array.isArray(e.depends_on)?[...new Set(e.depends_on.filter(m=>typeof m=="string"&&m.length>0))].sort((m,E)=>m.localeCompare(E,"en")):[],i={id:d(e.id)??r,...d(e.epic_id)?{epic_id:d(e.epic_id)}:{},...d(e.status,40)?{status:d(e.status,40)}:{},depends_on:t},c=M(r,e);if(!re(e.status))return{...i,...c?{scheduling_checkpoint_evidence:c}:{}};const o=e.source==="create-epic"||e.source==="discovered"?e.source:void 0,s=T(e.branch_name),a=w(e.last_step,120),u=Array.isArray(e.steps_completed)&&e.steps_completed.length<=64?e.steps_completed.map(m=>w(m,120)):[],l=u.length>0&&u.every(m=>m!==void 0)?u:void 0,f=typeof e.pr_number=="number"&&Number.isSafeInteger(e.pr_number)&&e.pr_number>0?e.pr_number:void 0,p=ie(r,e),g=p?ce(r,e):void 0;return{...i,...o?{source:o}:{},...s?{branch_name:s}:{},...a?{last_step:a}:{},...l?{steps_completed:l}:{},...f?{pr_number:f}:{},...p?{checkpoint:p}:{},...g?{checkpoint_verification:g}:{},...c?{scheduling_checkpoint_evidence:c}:{},...S(e.files_to_modify)!==void 0?{files_to_modify:S(e.files_to_modify)}:{},...S(e.contracts)!==void 0?{contracts:S(e.contracts)}:{},...S(e.contract_refs)!==void 0?{contract_refs:S(e.contract_refs)}:{},...S(e.shared_surfaces)!==void 0?{shared_surfaces:S(e.shared_surfaces)}:{}}}function K(r,e){const t=Array.isArray(e.stories)?[...new Set(e.stories.filter(c=>typeof c=="string"&&c.length>0))].sort((c,o)=>c.localeCompare(o,"en")):[],i=Array.isArray(e.depends_on)?[...new Set(e.depends_on.filter(c=>typeof c=="string"&&c.length>0))].sort((c,o)=>c.localeCompare(o,"en")):[];return{id:d(e.id)??r,...d(e.status,40)?{status:d(e.status,40)}:{},...d(e.lifecycle_classification,40)?{lifecycle_classification:d(e.lifecycle_classification,40)}:{},stories:t,depends_on:i}}function he(r,e,t){const i=I(e.stories),c=I(e.epics),o=Object.fromEntries(i.orderedIds.map(u=>[u,Y(u,e.stories[u])])),s=Object.fromEntries(c.orderedIds.map(u=>[u,K(u,e.epics[u])])),a={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:"yoloop-discovery",trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:i.orderedIds.length,includedEpicCount:c.orderedIds.length,omittedStoryCount:0,omittedEpicCount:0,reason:"targeted-invocation",reasonCodes:_(["structural-required","yoloop-discovery",`structural-edges-${i.edgeCount+c.edgeCount}`,"content-fields-omitted"])};return v({...e,stories:o,epics:s,scope:a},e,a)}function be(r,e){const t=new Set,i=r.stories;if(Array.isArray(i))for(const o of i)typeof o=="string"&&x(o,e,t);const c={};for(const o of t){const s=e.stories[o];s&&(c[o]=s)}return c}function _e(r){const e={};for(const[t,i]of Object.entries(r.epics))e[t]={id:d(i.id)??t,...d(i.status)?{status:d(i.status)}:{},...k.includes(i.lifecycle_classification)?{lifecycle_classification:i.lifecycle_classification}:{},...typeof i.total_stories=="number"&&Number.isFinite(i.total_stories)?{total_stories:i.total_stories}:{},...typeof i.completed_stories=="number"&&Number.isFinite(i.completed_stories)?{completed_stories:i.completed_stories}:{}};return e}function W(r){const e={};for(const t of Object.values(r)){const i=d(t.status,40)??"unknown";e[i]=(e[i]??0)+1}return e}function Se(r){const e=Object.fromEntries(k.map(t=>[t,0]));for(const t of Object.values(r)){const i=k.includes(t.lifecycle_classification)?t.lifecycle_classification:"active";e[i]=(e[i]??0)+1}return e}function N(r,e){if(!e)return!0;const t=r.epics[e];return t?!k.includes(t.lifecycle_classification)||t.lifecycle_classification==="active":!0}function Z(r){for(const e of["last_updated","updated_at","completed_at","created_at","discovered_at"]){const t=r[e];if(typeof t!="string")continue;const i=Date.parse(t);if(Number.isFinite(i))return i}return 0}function je(r){return Object.entries(r.stories).map(([e,t])=>({id:e,story:t,timestamp:Z(t)})).sort((e,t)=>t.timestamp-e.timestamp||e.id.localeCompare(t.id)).slice(0,U).map(({id:e,story:t})=>({id:e,...d(t.epic_id)?{epicId:d(t.epic_id)}:{},...d(t.status,40)?{status:d(t.status,40)}:{},...d(t.last_step??t.lastStep)?{lastStep:d(t.last_step??t.lastStep)}:{},...d(t.last_updated??t.updated_at??t.completed_at??t.created_at)?{lastUpdated:d(t.last_updated??t.updated_at??t.completed_at??t.created_at)}:{}}))}function ve(r){const e=r.current_session;if(!e)return;const t={activeEpicId:d(e.active_epic_id)??null,activeStoryId:d(e.active_story_id)??null,activeStepId:d(e.active_step_id)??null,sessionId:d(e.session_id)??null,startedAt:d(e.started_at)??null};return Object.values(t).some(i=>i!=null)?t:void 0}function Ie(r){const e=r.yoloop;if(!h(e))return;const t=h(e.state)?e.state:void 0,i=h(t?.currentSession)?t.currentSession:void 0,c=h(e.lock)?e.lock:void 0,o={...typeof e.active=="boolean"?{active:e.active}:{},currentEpicId:d(i?.currentEpicId??e.currentEpicId)??null,currentStoryId:d(i?.currentStoryId??e.currentStoryId)??null,sessionId:d(i?.sessionId??e.sessionId)??null,lockEpicId:d(c?.currentEpicId??c?.epicId)??null};return Object.keys(o).length>0?o:void 0}function ke(r){const e=r.continuity;if(!h(e))return;const t=Array.isArray(e.reasonCodes)?e.reasonCodes.filter(i=>typeof i=="string"):void 0;return{present:!0,activeJobId:d(e.activeJobId??e.jobId)??null,activeGoalId:d(e.activeGoalId??e.goalId)??null,activeLoopId:d(e.activeLoopId??e.loopId)??null,...t&&t.length>0?{reasonCodes:_(t)}:{}}}function Ce(r,e,t){const i=d(e?.activeStoryId),c=d(e?.activeEpicId),o=d(e?.activeStepId),s=i&&r.stories[i]?j(r.stories[i],i):null;if((i||c||o)&&N(r,c??s))return{epicId:c??null,storyId:i??null,stepId:o??null};const a=d(t?.currentStoryId),u=d(t?.currentEpicId??t?.lockEpicId);if((a||u)&&N(r,u))return{epicId:u??null,storyId:a??null,stepId:null};const l=Object.entries(r.stories).map(([f,p])=>({id:f,story:p,timestamp:Z(p)})).filter(({id:f,story:p})=>!L(p.status)&&N(r,j(p,f))).sort((f,p)=>p.timestamp-f.timestamp||f.id.localeCompare(p.id))[0];return l?{epicId:j(l.story,l.id),storyId:l.id,stepId:d(l.story.last_step??l.story.lastStep)??null}:{epicId:null,storyId:null,stepId:null}}function Ee(r,e){const t=W(r.stories),i=W(r.epics),c=Se(r.epics),o=Object.values(r.epics).filter(g=>(k.includes(g.lifecycle_classification)?g.lifecycle_classification:"active")==="active"&&!L(g.status)).length,s=ve(r),a=Ie(r),u=ke(r),l=Ce(r,s,a),f=je(r),p=_(e.reasonCodes,["state-summary-attached","state-summary-bounded",`projection-${e.projectionMode??e.kind}`,e.stateProjectionPolicy?`policy-${e.stateProjectionPolicy}`:"policy-unknown",f.length>=U?"recent-stories-capped":"recent-stories-bounded",l.storyId||l.epicId?"active-ref-derived":"active-ref-empty",a?"yoloop-session-present":"yoloop-session-absent",u?"continuity-session-present":"continuity-session-absent"]);return{schemaVersion:1,totals:{stories:Object.keys(r.stories).length,epics:Object.keys(r.epics).length,storyStatus:t,epicStatus:i,epicLifecycle:c,activeEpics:o,blockedStories:t.blocked??0},active:l,blockedCount:t.blocked??0,recentStories:f,...s?{currentSession:s}:{},...a?{currentYoloopSession:a}:{},...u?{currentContinuitySession:u}:{},projection:{commandId:e.commandId??null,stateProjectionPolicy:e.stateProjectionPolicy??null,projectionMode:e.projectionMode,scopeKind:e.kind,includedStoryCount:e.includedStoryCount,includedEpicCount:e.includedEpicCount??Object.keys(r.epics).length,omittedStoryCount:e.omittedStoryCount,omittedEpicCount:e.omittedEpicCount,reason:e.reason},reasonCodes:p,publicSafe:!0}}function v(r,e,t){return{...r,stateSummary:Ee(e,t)}}function Re(r,e,t){const i={};for(const o of Object.keys(e.epics))i[o]={id:o};const c={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:"summary-only",trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:0,includedEpicCount:Object.keys(i).length,omittedStoryCount:Object.keys(e.stories).length,omittedEpicCount:0,reason:"epic-summary",reasonCodes:["epic-summary","stories-omitted","epic-stubs-only"]};return v({...e,stories:{},epics:i,scope:c},e,c)}function b(r,e,t,i=["summary-only","stories-omitted"],c="summary-only"){const o=_e(e),s={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:c,trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:0,includedEpicCount:Object.keys(o).length,omittedStoryCount:Object.keys(e.stories).length,omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(o).length),reason:"summary-only",reasonCodes:_(i)};return v({...e,stories:{},epics:o,scope:s},e,s)}function D(r,e,t,i,c,o){const s=e.stories[i];if(!s)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"story"});const a=j(s,i);if(!a)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const u=e.epics[a];if(!u)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const l=c==="yolo-story",f=l?G(a,u,e):ye(i,e),p=l?V(a,f,e):$(f,e);if(!f[i]||!p[a])throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(f).length,epics:Object.keys(p).length,targetKind:"story"});const g={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:c,trigger:r,targetEpicId:a,targetStoryId:i,includedStoryCount:Object.keys(f).length,includedEpicCount:Object.keys(p).length,omittedStoryCount:Math.max(0,Object.keys(e.stories).length-Object.keys(f).length),omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(p).length),reason:"targeted-invocation",reasonCodes:_(o,l?["epic-graph-authority-complete"]:[])};return v({...e,stories:f,epics:p,scope:g},e,g)}function B(r,e,t,i,c,o){const s=e.epics[i];if(!s)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const a=be(s,e),u=$(a,e,[i]);if(!u[i])throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(a).length,epics:Object.keys(u).length,targetKind:"epic"});const l={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:c,trigger:r,targetEpicId:i,targetStoryId:null,includedStoryCount:Object.keys(a).length,includedEpicCount:Object.keys(u).length,omittedStoryCount:Math.max(0,Object.keys(e.stories).length-Object.keys(a).length),omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(u).length),reason:"targeted-invocation",reasonCodes:_(o)};return v({...e,stories:a,epics:u,scope:l},e,l)}function Oe(r,e,t){const i=fe(r),c=R(r,e);if(i&&!c)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const o=pe(r,e),s=O({commandId:t.commandId,explicitYoloopEpicId:c,sessionYoloopEpicId:c?null:o});if(s==="yoloop-discovery")return he(r,e,t);if(!o||s!=="yoloop-target"&&s!=="yoloop-session")throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const a=e.epics[o];if(!a)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const u=G(o,a,e),l=V(o,u,e);if(!l[o])throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(u).length,epics:Object.keys(l).length,targetKind:"epic"});const f=s,p={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:f,trigger:r,targetEpicId:o,targetStoryId:null,targetEpicCoverage:ge(o,a,u),includedStoryCount:Object.keys(u).length,includedEpicCount:Object.keys(l).length,omittedStoryCount:Math.max(0,Object.keys(e.stories).length-Object.keys(u).length),omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(l).length),reason:"targeted-invocation",reasonCodes:["structural-required",f,"yoloop-targeted"]};return v({...e,stories:u,epics:l,scope:p},e,p)}function Ae(r,e){const t={};for(const[i,c]of Object.entries(r.epics)){const o=Array.isArray(c.stories)?c.stories.filter(s=>typeof s=="string"&&e.has(s)):[];t[i]={id:d(c.id)??i,...d(c.status,40)?{status:d(c.status,40)}:{},...typeof c.total_stories=="number"&&Number.isFinite(c.total_stories)?{total_stories:c.total_stories}:{},...typeof c.completed_stories=="number"&&Number.isFinite(c.completed_stories)?{completed_stories:c.completed_stories}:{},...o.length>0?{stories:o}:{},...o.length>0&&Array.isArray(c.depends_on)?{depends_on:c.depends_on.filter(s=>typeof s=="string"&&s.length>0)}:{},...o.length>0&&(c.branch_mode==="epic"||c.branch_mode==="story")?{branch_mode:c.branch_mode}:{},...o.length>0&&typeof c.execution_branch=="string"?{execution_branch:c.execution_branch}:{},...o.length>0&&typeof c.origin_branch=="string"?{origin_branch:c.origin_branch}:{},...o.length>0&&(c.branch_lease===null||typeof c.branch_lease=="object")?{branch_lease:c.branch_lease}:{},...o.length>0&&(c.origin_binding===null||typeof c.origin_binding=="object")?{origin_binding:c.origin_binding}:{},...o.length>0&&(c.aggregate_qa_receipt===null||typeof c.aggregate_qa_receipt=="object")?{aggregate_qa_receipt:c.aggregate_qa_receipt}:{}}}return t}function we(r){return r.stateSummary?.totals.stories??(r.scope?.includedStoryCount??Object.keys(r.stories).length)+(r.scope?.omittedStoryCount??0)}function Te(r){return r.stateSummary?.totals.epics??(r.scope?.includedEpicCount??Object.keys(r.epics).length)+(r.scope?.omittedEpicCount??0)}function qe(r,e){if(r.stateSummary)return{...r.stateSummary,projection:{...r.stateSummary.projection,scopeKind:"projected",projectionMode:e.projectionMode,includedStoryCount:e.includedStoryCount,includedEpicCount:e.includedEpicCount??r.stateSummary.projection.includedEpicCount,omittedStoryCount:e.omittedStoryCount,omittedEpicCount:e.omittedEpicCount,reason:"body-size"},reasonCodes:_(r.stateSummary.reasonCodes,["payload-size-guardrail","state-summary-preserved","nonessential-state-degraded"])}}function Le(r){const e=r.scope,t=new Set,i=e?.projectionMode==="structural-required"||e?.projectionMode==="yolo-story"||e?.projectionMode==="yoloop-target"||e?.projectionMode==="yoloop-session"||e?.projectionMode==="yoloop-discovery";if(i)for(const m of Object.keys(r.stories))t.add(m);else e?.targetStoryId&&x(e.targetStoryId,r,t);const c={};for(const m of t){const E=r.stories[m];E&&(c[m]=E)}const o=Ae(r,t),s=Object.keys(c).length,a=Object.keys(o).length,u=Math.max(0,we(r)-s),l=Math.max(0,Te(r)-a),f=i?e?.projectionMode??"structural-required":e?.projectionMode==="yolo-story"?"yolo-story":"summary-only",p={kind:"projected",commandId:e?.commandId??null,stateProjectionPolicy:e?.stateProjectionPolicy??null,projectionMode:f,targetEpicId:e?.targetEpicId??null,targetStoryId:e?.targetStoryId??null,...e?.targetEpicCoverage?{targetEpicCoverage:e.targetEpicCoverage}:{},includedStoryCount:s,includedEpicCount:a,omittedStoryCount:u,omittedEpicCount:l,reason:"body-size",reasonCodes:_(e?.reasonCodes,["payload-size-guardrail",t.size>0?"structural-targets-preserved":"stories-omitted","epics-stubbed","state-summary-preserved","redundant-trigger-omitted"])},g=qe(r,p);return{...r,stories:c,epics:o,scope:p,...g?{stateSummary:g}:{}}}function Pe(r,e){const t=r.trim(),i=z(t);try{if(!i){if(de(t)){const o=n("story-reference","story-targeted"),s=F(t);if(s)return D(t,e,o,s,"targeted-story",["story-reference-targeted"])}return b(t,e,n("unknown","adaptive-targeted"),["unknown-command-summary-only"])}if(i.stateProjectionPolicy==="epic-summary")return Re(t,e,i);if(i.stateProjectionPolicy==="yoloop-targeted")return Oe(t,e,i);const c=F(t);if(i.stateProjectionPolicy==="story-targeted"){if(c){const s=O({commandId:i.commandId,targetStoryId:c})==="yolo-story";return D(t,e,i,c,s?"yolo-story":i.structuralRequired?"structural-required":"targeted-story",[s?"yolo-story":i.structuralRequired?"structural-required":"targeted-story"])}if(i.commandId==="yolo"||i.commandId==="yolo-inline"){const o=O({commandId:i.commandId});return b(t,e,i,["yolo-inline","stories-omitted","historical-content-omitted"],o??"yolo-inline")}return i.commandId==="commit"&&/^\*?(?:commit|commit-push)$/i.test(t)?b(t,e,i,["working-tree-commit","stories-omitted","historical-content-omitted"]):i.structuralRequired?(()=>{throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"story"})})():b(t,e,i,["story-target-missing-summary-only"])}if(i.stateProjectionPolicy==="adaptive-targeted"){if(c&&e.stories[c])return D(t,e,i,c,"targeted-story",["adaptive-story-targeted"]);const o=R(t,e);return o?B(t,e,i,o,"targeted-epic",["adaptive-epic-targeted"]):b(t,e,i,["adaptive-summary-only","target-unresolved-summary-only"])}if(i.stateProjectionPolicy==="epic-targeted"){if(i.commandId.startsWith("arch-")&&/(?:^|\s)epic-arch\s*$/i.test(t)&&e.archPlan?.execution?.currentStageCommand===i.commandId)return b(t,e,i,["architecture-root-delegated"]);const o=R(t,e);return o?B(t,e,i,o,i.structuralRequired?"structural-required":"targeted-epic",[i.structuralRequired?"structural-required":"targeted-epic"]):i.structuralRequired?(()=>{throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"})})():b(t,e,i,["epic-target-missing-summary-only"])}return i.stateProjectionPolicy==="continuity-scoped"?b(t,e,i,["continuity-scoped-summary-only"]):b(t,e,i,["policy-full-summary-only"])}catch(c){if(c instanceof y)throw c;if(i?.structuralRequired)throw new y("STRUCTURAL_DEPENDENCY_MISSING",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,projectionErrors:1});return b(t,e,i??n("unknown","adaptive-targeted"),["projection-error-summary-only"])}}const xe=new Set(["yolo-story","yolo-inline","yoloop-target","yoloop-session","yoloop-discovery"]);function Ne(r){let e=0;for(const t of[r.stories,r.epics])for(const i of Object.values(t))Array.isArray(i.depends_on)&&(e+=i.depends_on.filter(c=>typeof c=="string").length);return e}function $e(r,e){const t=z(r.trim());if(!t||!["yolo","yolo-inline","yoloop"].includes(t.commandId))return null;try{const i=Pe(r,e),c=i.scope?.projectionMode;if(!c||!xe.has(c))throw new y("STRUCTURAL_DEPENDENCY_MISSING",{stories:Object.keys(i.stories).length,epics:Object.keys(i.epics).length,projectionShapeErrors:1});return Object.freeze({ok:!0,version:2,shape:c,snapshot:i,included:{epics:i.scope?.includedEpicCount??Object.keys(i.epics).length,stories:i.scope?.includedStoryCount??Object.keys(i.stories).length,edges:Ne(i)},omitted:{epics:i.scope?.omittedEpicCount??0,stories:i.scope?.omittedStoryCount??0},cycleCount:0})}catch(i){if(!(i instanceof y))throw i;return Object.freeze({ok:!1,code:i.code,publicDetails:i.publicDetails})}}export{Le as degradeStateSnapshotForPayloadLimit,Pe as projectStateSnapshotForInvoke,$e as projectStateSnapshotResultV2ForInvoke};