intentdna 1.7.5 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/LICENSE +201 -0
  4. package/README.md +143 -194
  5. package/dist/assets/candidates.d.ts +124 -0
  6. package/dist/assets/candidates.js +1249 -0
  7. package/dist/assets/catalog.d.ts +101 -0
  8. package/dist/assets/catalog.js +311 -0
  9. package/dist/assets/evidence.d.ts +93 -0
  10. package/dist/assets/evidence.js +391 -0
  11. package/dist/assets/index.d.ts +4 -0
  12. package/dist/assets/index.js +4 -0
  13. package/dist/assets/metadata.d.ts +19 -0
  14. package/dist/assets/metadata.js +227 -0
  15. package/dist/cli/commands/assets.d.ts +65 -0
  16. package/dist/cli/commands/assets.js +2871 -0
  17. package/dist/cli/commands/auth.d.ts +322 -0
  18. package/dist/cli/commands/auth.js +1592 -0
  19. package/dist/cli/commands/cloud-auth-guidance.d.ts +2 -0
  20. package/dist/cli/commands/cloud-auth-guidance.js +4 -0
  21. package/dist/cli/commands/cloud.d.ts +1359 -0
  22. package/dist/cli/commands/cloud.js +8364 -0
  23. package/dist/cli/commands/evolve.js +18 -2
  24. package/dist/cli/commands/generate.js +25 -2
  25. package/dist/cli/commands/guard.d.ts +1 -1
  26. package/dist/cli/commands/guard.js +1 -1
  27. package/dist/cli/commands/guide.d.ts +15 -0
  28. package/dist/cli/commands/guide.js +1747 -0
  29. package/dist/cli/commands/init.d.ts +12 -0
  30. package/dist/cli/commands/init.js +95 -60
  31. package/dist/cli/commands/org.d.ts +16 -0
  32. package/dist/cli/commands/org.js +2393 -0
  33. package/dist/cli/commands/release.d.ts +59 -0
  34. package/dist/cli/commands/release.js +716 -0
  35. package/dist/cli/commands/report.d.ts +82 -0
  36. package/dist/cli/commands/report.js +1516 -0
  37. package/dist/cli/commands/run.d.ts +6 -1
  38. package/dist/cli/commands/run.js +95 -26
  39. package/dist/cli/commands/sync.d.ts +8 -1
  40. package/dist/cli/commands/sync.js +436 -141
  41. package/dist/cli/commands/templates.d.ts +64 -0
  42. package/dist/cli/commands/templates.js +2151 -1
  43. package/dist/cli/commands/workflow.d.ts +26 -0
  44. package/dist/cli/commands/workflow.js +3053 -0
  45. package/dist/cli/index.js +703 -36
  46. package/dist/compiler/cascade.js +4 -9
  47. package/dist/compiler/compile.js +1 -0
  48. package/dist/governance/evidence-capture-attribution.d.ts +12 -0
  49. package/dist/governance/evidence-capture-attribution.js +46 -0
  50. package/dist/governance/index.d.ts +2 -0
  51. package/dist/governance/index.js +1 -0
  52. package/dist/hooks/cli.d.ts +5 -0
  53. package/dist/hooks/cli.js +149 -5
  54. package/dist/hooks/enforce.d.ts +1 -0
  55. package/dist/hooks/protocol.d.ts +1 -1
  56. package/dist/hooks/protocol.js +1 -1
  57. package/dist/hooks/state.d.ts +41 -0
  58. package/dist/hooks/state.js +126 -2
  59. package/dist/index.d.ts +3 -0
  60. package/dist/index.js +3 -0
  61. package/dist/mcp/tools-state.js +2 -0
  62. package/dist/organization/index.d.ts +121 -0
  63. package/dist/organization/index.js +413 -0
  64. package/dist/runtime/claude-sync-target.d.ts +49 -0
  65. package/dist/runtime/claude-sync-target.js +280 -0
  66. package/dist/runtime/codex-adapter.d.ts +254 -0
  67. package/dist/runtime/codex-adapter.js +1204 -0
  68. package/dist/runtime/codex-sync-target.d.ts +33 -0
  69. package/dist/runtime/codex-sync-target.js +241 -0
  70. package/dist/runtime/index.d.ts +8 -0
  71. package/dist/runtime/index.js +4 -0
  72. package/dist/runtime/output-artifact-registry.d.ts +1 -1
  73. package/dist/runtime/output-artifact-registry.js +2 -0
  74. package/dist/runtime/settings-adapter.d.ts +1 -1
  75. package/dist/runtime/settings-adapter.js +1 -1
  76. package/dist/runtime/skill-adapter.d.ts +5 -1
  77. package/dist/runtime/skill-adapter.js +120 -34
  78. package/dist/runtime/sync-artifact-registry.d.ts +99 -0
  79. package/dist/runtime/sync-artifact-registry.js +194 -0
  80. package/dist/runtime/sync-target-plan.d.ts +45 -0
  81. package/dist/runtime/sync-target-plan.js +19 -0
  82. package/dist/schema/controller-registry.d.ts +8 -1
  83. package/dist/schema/controller-registry.js +8 -0
  84. package/dist/schema/types.d.ts +35 -23
  85. package/dist/schema/types.js +10 -1
  86. package/dist/schema/validate.js +22 -22
  87. package/dist/schema/validators/controllers.js +38 -20
  88. package/dist/schema/workflow-authoring-contract.d.ts +29 -0
  89. package/dist/schema/workflow-authoring-contract.js +109 -0
  90. package/dist/schema/yaml-parser.js +18 -0
  91. package/dist/templates/api-backend.dna.yaml +19 -0
  92. package/dist/templates/brainstorming-first.dna.yaml +19 -0
  93. package/dist/templates/code-cleanup.dna.yaml +19 -0
  94. package/dist/templates/code-review-pipeline.dna.yaml +18 -0
  95. package/dist/templates/documentation-writer.dna.yaml +19 -0
  96. package/dist/templates/flutter-behavior-lock.dna.yaml +19 -0
  97. package/dist/templates/flutter-refactoring-rescue.dna.yaml +19 -0
  98. package/dist/templates/flutter-rewrite-diagnosis-review.dna.yaml +210 -0
  99. package/dist/templates/flutter-rewrite-fix-review-loop.dna.yaml +260 -0
  100. package/dist/templates/flutter-rewrite-new.dna.yaml +506 -0
  101. package/dist/templates/flutter-rewrite.dna.yaml +20 -0
  102. package/dist/templates/frontend-quality.dna.yaml +19 -0
  103. package/dist/templates/full-pipeline.dna.yaml +20 -0
  104. package/dist/templates/marketplace.d.ts +92 -0
  105. package/dist/templates/marketplace.js +502 -0
  106. package/dist/templates/metadata.d.ts +25 -0
  107. package/dist/templates/metadata.js +136 -3
  108. package/dist/templates/mobile-dev.dna.yaml +19 -0
  109. package/dist/templates/multi-agent-handoff-coordination.dna.yaml +156 -0
  110. package/dist/templates/multi-perspective-review.dna.yaml +19 -0
  111. package/dist/templates/persistent-executor.dna.yaml +19 -0
  112. package/dist/templates/qa-loop.dna.yaml +18 -0
  113. package/dist/templates/release-evidence-gate.dna.yaml +131 -0
  114. package/dist/templates/requirements-gate.dna.yaml +19 -0
  115. package/dist/templates/research-orchestration.dna.yaml +19 -0
  116. package/dist/templates/root-cause-analysis.dna.yaml +19 -0
  117. package/dist/templates/safe-refactoring.dna.yaml +321 -0
  118. package/dist/templates/secure-dev.dna.yaml +19 -0
  119. package/dist/templates/subagent-parallel.dna.yaml +19 -0
  120. package/dist/templates/systematic-debugging.dna.yaml +19 -0
  121. package/dist/templates/tdd-strict.dna.yaml +19 -0
  122. package/dist/templates/ui-visual-regression-qa.dna.yaml +133 -0
  123. package/dist/templates/workflow-author.dna.yaml +302 -0
  124. package/dist/templates/workflow-blocked-scope-triage.dna.yaml +242 -0
  125. package/dist/templates/workflow-completion-audit.dna.yaml +254 -0
  126. package/dist/templates/workflow-cross-boundary-resource-approval.dna.yaml +249 -0
  127. package/dist/templates/workflow-evidence-review.dna.yaml +198 -0
  128. package/dist/templates/workflow-module-inventory.dna.yaml +257 -0
  129. package/dist/templates/workflow-runtime-smoke-review.dna.yaml +252 -0
  130. package/dist/templates/workflow-verification-command-routing.dna.yaml +278 -0
  131. package/dist/workflow/authoring-packet.d.ts +67 -0
  132. package/dist/workflow/authoring-packet.js +218 -0
  133. package/dist/workflow/draft.d.ts +159 -0
  134. package/dist/workflow/draft.js +800 -0
  135. package/dist/workflow/index.d.ts +3 -0
  136. package/dist/workflow/index.js +3 -0
  137. package/dist/workflow/suggestion-review.d.ts +65 -0
  138. package/dist/workflow/suggestion-review.js +245 -0
  139. package/package.json +1 -1
  140. package/spec/README.md +15 -48
  141. package/spec/codex-adapter-contract.md +176 -0
  142. package/spec/sync-target-plan.md +158 -0
  143. package/spec/workflow-capability-ir.md +153 -0
  144. package/spec/agent-dispatch-fix.md +0 -116
  145. package/spec/control-plane-convergence-handoff-2026-04-24.md +0 -432
  146. package/spec/flutter-rewrite-template-optimization.md +0 -301
  147. package/spec/foundation-hardening.md +0 -178
  148. package/spec/hooks-infra-harness-hardening.md +0 -741
  149. package/spec/multi-config.md +0 -172
  150. package/spec/parallel-isolation.md +0 -268
  151. package/spec/template-version-namespace-fix.md +0 -653
  152. package/spec/workflow-pipeline.md +0 -101
@@ -109,15 +109,10 @@ function prefixRecordKeys(record, ns) {
109
109
  function prefixController(controller, ns) {
110
110
  return {
111
111
  ...controller,
112
- diagnosis_workflow: `${ns}_${controller.diagnosis_workflow}`,
113
- fix_workflow: `${ns}_${controller.fix_workflow}`,
114
- roles: {
115
- analyzer: `${ns}_${controller.roles.analyzer}`,
116
- analysis_reviewer: `${ns}_${controller.roles.analysis_reviewer}`,
117
- surgeon: `${ns}_${controller.roles.surgeon}`,
118
- fix_reviewer: `${ns}_${controller.roles.fix_reviewer}`,
119
- test_runner: `${ns}_${controller.roles.test_runner}`,
120
- },
112
+ workflow: controller.workflow ? `${ns}_${controller.workflow}` : undefined,
113
+ diagnosis_workflow: controller.diagnosis_workflow ? `${ns}_${controller.diagnosis_workflow}` : undefined,
114
+ fix_workflow: controller.fix_workflow ? `${ns}_${controller.fix_workflow}` : undefined,
115
+ roles: Object.fromEntries(Object.entries(controller.roles).map(([roleKey, roleName]) => [roleKey, `${ns}_${roleName}`])),
121
116
  };
122
117
  }
123
118
  function prefixLegibilityAssets(map, ns) {
@@ -384,6 +384,7 @@ export function compileDNA(activated, cascaded) {
384
384
  workflowsIR.push({
385
385
  workflow_name: wfKey,
386
386
  namespace,
387
+ step_ids: (wf.steps ?? []).map((step) => step.id),
387
388
  step_checkpoints: wfStepCheckpoints,
388
389
  active_roles: activeRoles,
389
390
  handoff_chain: handoffChain,
@@ -0,0 +1,12 @@
1
+ import type { ConstraintIR } from "../schema/types.js";
2
+ export interface EvidenceCaptureAttributionHint {
3
+ workflowAsset?: string;
4
+ workflowId?: string;
5
+ stepId?: string;
6
+ }
7
+ export interface TrustedEvidenceCaptureAttribution {
8
+ workflowAsset: string;
9
+ workflowId: string;
10
+ stepId: string;
11
+ }
12
+ export declare function trustedEvidenceCaptureAttribution(ir: ConstraintIR, hint: EvidenceCaptureAttributionHint): TrustedEvidenceCaptureAttribution;
@@ -0,0 +1,46 @@
1
+ const UNKNOWN_ATTRIBUTION = "unknown";
2
+ function canonicalWorkflowAsset(ir) {
3
+ const sourceIds = [...new Set(ir.source_dna_ids)]
4
+ .filter((sourceId) => sourceId.length > 0)
5
+ .filter((sourceId) => !sourceId.startsWith("species:"))
6
+ .filter((sourceId) => !sourceId.startsWith("enterprise:"));
7
+ return sourceIds.length === 1 ? sourceIds[0] : undefined;
8
+ }
9
+ function attributedWorkflow(ir, workflowId) {
10
+ if (workflowId) {
11
+ return ir.workflows_ir?.find((workflow) => workflow.workflow_name === workflowId);
12
+ }
13
+ return ir.workflows_ir?.length === 1 ? ir.workflows_ir[0] : undefined;
14
+ }
15
+ function workflowStepIds(ir, workflow) {
16
+ return new Set([
17
+ ...(workflow.step_ids ?? []),
18
+ ...workflow.step_checkpoints.map((checkpoint) => checkpoint.step_id),
19
+ ...workflow.handoff_chain.map((handoff) => handoff.step_id),
20
+ ...(workflow.step_enforce_rules ?? []).map((rule) => rule.step_id),
21
+ ...(ir.verifier_specs ?? [])
22
+ .filter((spec) => spec.workflow_name === workflow.workflow_name)
23
+ .map((spec) => spec.step_id)
24
+ .filter((stepId) => typeof stepId === "string"),
25
+ ]);
26
+ }
27
+ export function trustedEvidenceCaptureAttribution(ir, hint) {
28
+ const workflow = attributedWorkflow(ir, hint.workflowId);
29
+ const invalidExplicitWorkflow = Boolean(hint.workflowId && !workflow);
30
+ if (invalidExplicitWorkflow) {
31
+ return {
32
+ workflowAsset: UNKNOWN_ATTRIBUTION,
33
+ workflowId: UNKNOWN_ATTRIBUTION,
34
+ stepId: UNKNOWN_ATTRIBUTION,
35
+ };
36
+ }
37
+ const canonicalAsset = canonicalWorkflowAsset(ir);
38
+ const workflowAsset = canonicalAsset
39
+ ? hint.workflowAsset === canonicalAsset ? hint.workflowAsset : canonicalAsset
40
+ : UNKNOWN_ATTRIBUTION;
41
+ const workflowId = workflow?.workflow_name ?? UNKNOWN_ATTRIBUTION;
42
+ const stepId = workflow && hint.stepId && workflowStepIds(ir, workflow).has(hint.stepId)
43
+ ? hint.stepId
44
+ : UNKNOWN_ATTRIBUTION;
45
+ return { workflowAsset, workflowId, stepId };
46
+ }
@@ -5,4 +5,6 @@
5
5
  */
6
6
  export type { AuditReport, RemoteDNAPolicy, PolicyContent, PolicyScope, PolicyUpdate, GovernanceConfig, GovernanceClient, GovernanceResponse, GovernanceSubscription, } from "./types.js";
7
7
  export { CASCADE_LAYER_NAMES, RUNTIME_DECISION_EVENT_SCHEMA_VERSION, validateRuntimeDecisionEvent, } from "./runtime-decision-event.js";
8
+ export { trustedEvidenceCaptureAttribution } from "./evidence-capture-attribution.js";
9
+ export type { EvidenceCaptureAttributionHint, TrustedEvidenceCaptureAttribution, } from "./evidence-capture-attribution.js";
8
10
  export type { CascadeDecisionTrace, CascadeLayerFingerprint, CascadeLayerName, CascadeLayers, EnforcementPoint, ExplicitPlaceholder, HarnessRuntimeContext, PolicyBundle, RuntimeDecision, RuntimeDecisionEvent, RuntimeDecisionEventValidationResult, RuntimeEvidenceRef, WinningConstraint, } from "./runtime-decision-event.js";
@@ -4,3 +4,4 @@
4
4
  * Exports the v1.7.1 enterprise evidence contract plus reserved remote governance interfaces.
5
5
  */
6
6
  export { CASCADE_LAYER_NAMES, RUNTIME_DECISION_EVENT_SCHEMA_VERSION, validateRuntimeDecisionEvent, } from "./runtime-decision-event.js";
7
+ export { trustedEvidenceCaptureAttribution } from "./evidence-capture-attribution.js";
@@ -49,6 +49,9 @@ export interface RunHookEventOptions {
49
49
  }
50
50
  export declare function normalizeHookOutputForEvent(output: HookOutput, event: HookEvent): HookOutput;
51
51
  export declare function runHookEvent(options: RunHookEventOptions): Promise<HookOutput>;
52
+ export declare function codexHookEventForInput(rawInput: Record<string, unknown>, args: string[]): unknown;
53
+ declare function inferWorkflowAssetFromIr(ir: ConstraintIR, workflowId?: string): string | undefined;
54
+ declare function runCodexHookWithLoadedIr(rawInput: Record<string, unknown>, projectDir: string, args: string[], ir: ConstraintIR): Promise<import("../runtime/codex-adapter.js").CodexHookRunnerResult>;
52
55
  declare function recordProducedArtifacts(projectDir: string, ir: ConstraintIR, wfState: {
53
56
  workflow: string;
54
57
  current_step: string;
@@ -87,6 +90,8 @@ declare function finalizeAndResolveArtifactsForHook(projectDir: string, ir: Cons
87
90
  export declare const recordProducedArtifactsForTest: typeof recordProducedArtifacts;
88
91
  export declare const resolveWorkflowArtifactFactsForTest: typeof resolveWorkflowArtifactFacts;
89
92
  export declare const readWorkflowStateForHookTest: typeof readWorkflowStateForHook;
93
+ export declare const runCodexHookWithLoadedIrForTest: typeof runCodexHookWithLoadedIr;
94
+ export declare const inferWorkflowAssetFromIrForTest: typeof inferWorkflowAssetFromIr;
90
95
  export declare const resolveWorkflowArtifactFactsForHookTest: typeof resolveWorkflowArtifactFactsForHook;
91
96
  export declare const finalizeAndResolveArtifactsForHookTest: typeof finalizeAndResolveArtifactsForHook;
92
97
  export declare function appendStopVerifierWarnings(output: HookOutput, verifierResults: VerifierResultEntry[], currentStep?: string): HookOutput;
package/dist/hooks/cli.js CHANGED
@@ -23,10 +23,11 @@ import { fileURLToPath } from "node:url";
23
23
  import { readStdin, writeOutput, silentOutput, allowOutput, blockOutput, stopOutput } from "./protocol.js";
24
24
  import { validateHookInput } from "./schema.js";
25
25
  import { enforcePreToolUse, enforcePostToolUse, enforceUserPromptSubmit, enforceSubagentStop, enforcePreCompact, enforceNotification, enforceSessionStart, enforceStop, extractBashWritePaths, checkReflectionLimit, checkContextReadiness, checkWorkflowBoundary, } from "./enforce.js";
26
- import { appendAudit, readWorkflowState, appendTrace, appendRuntimeDecisionEvent, rotateTraces, readTraces, cleanStaleState, readSurgeonAttempts, writeSurgeonAttempts, appendSessionRead, readSessionReads, appendVerifierResult, appendCompletedArtifact, artifactIdentity, buildArtifactKey, readArtifactManifest, resolveArtifactTemplate, safePathComponent, writeArtifactManifest } from "./state.js";
26
+ import { appendAudit, readWorkflowState, appendTrace, appendRuntimeDecisionEvent, appendEvidenceCaptureEvent, rotateTraces, readTraces, cleanStaleState, readSurgeonAttempts, writeSurgeonAttempts, appendSessionRead, readSessionReads, appendVerifierResult, appendCompletedArtifact, artifactIdentity, buildArtifactKey, readArtifactManifest, resolveArtifactTemplate, safePathComponent, writeArtifactManifest, EVIDENCE_CAPTURE_SCHEMA_VERSION } from "./state.js";
27
27
  import { hookEventsForSurface } from "./event-registry.js";
28
28
  import { writeAuditEvent } from "../audit/index.js";
29
- import { RUNTIME_DECISION_EVENT_SCHEMA_VERSION } from "../governance/index.js";
29
+ import { RUNTIME_DECISION_EVENT_SCHEMA_VERSION, trustedEvidenceCaptureAttribution } from "../governance/index.js";
30
+ import { runCodexHook } from "../runtime/codex-adapter.js";
30
31
  // ── Constants ──────────────────────────────────────────────
31
32
  const DEFAULT_IR_PATH = ".dna/compiled/ir.json";
32
33
  const VALID_EVENTS = new Set(hookEventsForSurface("cli"));
@@ -150,6 +151,74 @@ function buildRuntimeDecisionEvent(params) {
150
151
  evidence_refs: [{ type: "trace", ref: params.traceId }],
151
152
  };
152
153
  }
154
+ function captureResultForHook(rawInput, decision) {
155
+ if (decision === "block")
156
+ return "blocked";
157
+ if (typeof rawInput.result === "string" && ["success", "failure", "blocked", "skipped", "unknown", "unsupported"].includes(rawInput.result)) {
158
+ return rawInput.result;
159
+ }
160
+ if (typeof rawInput.exit_code === "number")
161
+ return rawInput.exit_code === 0 ? "success" : "failure";
162
+ return "unknown";
163
+ }
164
+ function captureFactForHook(rawInput, decision, event) {
165
+ if (decision === "block")
166
+ return "blocker";
167
+ if (event === "PostToolUse" || event === "Stop" || rawInput.result || rawInput.exit_code !== undefined)
168
+ return "result";
169
+ const toolInput = typeof rawInput.tool_input === "object" && rawInput.tool_input !== null
170
+ ? rawInput.tool_input
171
+ : {};
172
+ if (typeof rawInput.command === "string" || typeof toolInput.command === "string")
173
+ return "command";
174
+ return "result";
175
+ }
176
+ function commandForHook(rawInput) {
177
+ const toolInput = typeof rawInput.tool_input === "object" && rawInput.tool_input !== null
178
+ ? rawInput.tool_input
179
+ : {};
180
+ const command = rawInput.command ?? toolInput.command;
181
+ return typeof command === "string" && command.trim().length > 0 ? command : undefined;
182
+ }
183
+ function buildClaudeEvidenceCaptureEvent(params) {
184
+ const fact = captureFactForHook(params.rawInput, params.decision, params.event);
185
+ const result = captureResultForHook(params.rawInput, params.decision);
186
+ const command = commandForHook(params.rawInput);
187
+ const toolName = typeof params.rawInput.tool_name === "string" ? params.rawInput.tool_name : "unknown tool";
188
+ const subject = command ?? `${toolName} ${params.event}`;
189
+ const attribution = trustedEvidenceCaptureAttribution(params.ir, {
190
+ workflowAsset: params.wfState?.workflow_asset,
191
+ workflowId: params.wfState?.workflow,
192
+ stepId: params.wfState?.current_step ?? params.runtimeEvent.step_id,
193
+ });
194
+ return {
195
+ schema_version: EVIDENCE_CAPTURE_SCHEMA_VERSION,
196
+ event_id: `c5:${params.runtimeEvent.event_id}`,
197
+ captured_at: params.runtimeEvent.timestamp,
198
+ project_root: params.projectDir,
199
+ source: "claude_code",
200
+ workflow_asset: attribution.workflowAsset,
201
+ workflow_id: attribution.workflowId,
202
+ run_id: params.runtimeEvent.run_id || params.runtimeEvent.session_id || "unknown",
203
+ step_id: attribution.stepId === "unknown" && !params.wfState
204
+ ? `${params.event}:direct`
205
+ : attribution.stepId,
206
+ fact,
207
+ summary: `Claude hook observed ${fact} for ${subject}: ${result}`,
208
+ command,
209
+ result,
210
+ exit_code: typeof params.rawInput.exit_code === "number" ? params.rawInput.exit_code : undefined,
211
+ duration_ms: typeof params.rawInput.duration_ms === "number" ? params.rawInput.duration_ms : undefined,
212
+ manual_intervention: fact === "manual_intervention"
213
+ ? { required: true, reason: params.reason, actor: "human" }
214
+ : undefined,
215
+ evidence_refs: [
216
+ { type: "runtime_decision_event", ref: params.runtimeEvent.event_id },
217
+ ...params.runtimeEvent.evidence_refs.map((ref) => ({ type: ref.type, ref: ref.ref })),
218
+ ],
219
+ redaction: "intentdna.c5.claude_hook_secret_redaction.v1",
220
+ };
221
+ }
153
222
  export function computeSummary(traces) {
154
223
  let blocks = 0, warns = 0;
155
224
  const toolCounts = new Map();
@@ -193,7 +262,12 @@ export function formatSummary(s) {
193
262
  async function main() {
194
263
  // Parse args
195
264
  const args = process.argv.slice(2);
196
- const event = args[0];
265
+ const eventArg = args[0];
266
+ if (eventArg === "CodexHook") {
267
+ await runCodexHookCli(args);
268
+ return;
269
+ }
270
+ const event = eventArg;
197
271
  if (!event || !VALID_EVENTS.has(event)) {
198
272
  writeOutput(silentOutput());
199
273
  return;
@@ -245,7 +319,7 @@ export async function runHookEvent(options) {
245
319
  const writeRuntimeDecision = async (output, result, wfState, traceId = randomUUID()) => {
246
320
  const decision = normalizeDecision(output);
247
321
  const reason = decision !== "allow" ? (output.reason ?? output.hookSpecificOutput?.additionalContext ?? "unknown") : "allowed by active policy";
248
- await appendRuntimeDecisionEvent(projectDir, buildRuntimeDecisionEvent({
322
+ const runtimeEvent = buildRuntimeDecisionEvent({
249
323
  ir,
250
324
  rawInput,
251
325
  output,
@@ -257,7 +331,18 @@ export async function runHookEvent(options) {
257
331
  decision,
258
332
  reason,
259
333
  wfState,
260
- }), sessionId);
334
+ });
335
+ await appendRuntimeDecisionEvent(projectDir, runtimeEvent, sessionId);
336
+ await appendEvidenceCaptureEvent(projectDir, buildClaudeEvidenceCaptureEvent({
337
+ ir,
338
+ rawInput,
339
+ event,
340
+ projectDir,
341
+ decision,
342
+ reason,
343
+ runtimeEvent,
344
+ wfState,
345
+ }));
261
346
  };
262
347
  let wfStateRaw = null;
263
348
  // Load workflow state for events that need it (handoff context + PreCompact preservation)
@@ -272,6 +357,7 @@ export async function runHookEvent(options) {
272
357
  state.workflowState = {
273
358
  current_step: wfStateRaw.current_step,
274
359
  workflow: wfStateRaw.workflow,
360
+ workflow_asset: wfStateRaw.workflow_asset,
275
361
  current_role: wfStateRaw.current_role,
276
362
  completed_artifacts: wfStateRaw.completed_artifacts,
277
363
  iteration: wfStateRaw.iteration, // G4: pass iteration for state-driven rules
@@ -554,6 +640,62 @@ function dispatch(event, ir, input, state, roles) {
554
640
  return null;
555
641
  }
556
642
  }
643
+ // ── Codex Hook Entry ───────────────────────────────────────
644
+ function argValue(args, flag) {
645
+ const index = args.indexOf(flag);
646
+ return index >= 0 ? args[index + 1] : undefined;
647
+ }
648
+ function codexInstallMode(value) {
649
+ return value === "plugin_scoped" || value === "managed" || value === "none" ? value : "project_fallback";
650
+ }
651
+ export function codexHookEventForInput(rawInput, args) {
652
+ return argValue(args, "--codex-event") ?? rawInput.event;
653
+ }
654
+ function inferWorkflowAssetFromIr(ir, workflowId) {
655
+ const attribution = trustedEvidenceCaptureAttribution(ir, { workflowId });
656
+ return attribution.workflowAsset === "unknown" ? undefined : attribution.workflowAsset;
657
+ }
658
+ async function runCodexHookWithLoadedIr(rawInput, projectDir, args, ir) {
659
+ const sessionId = typeof rawInput.session_id === "string"
660
+ ? rawInput.session_id
661
+ : typeof rawInput.sessionId === "string"
662
+ ? rawInput.sessionId
663
+ : undefined;
664
+ const sessionWorkflowState = sessionId
665
+ ? await readWorkflowState(projectDir, sessionId)
666
+ : null;
667
+ const workflowState = sessionWorkflowState ?? await readWorkflowState(projectDir);
668
+ const workflowAsset = inferWorkflowAssetFromIr(ir, workflowState?.workflow);
669
+ return runCodexHook({ ...rawInput, event: codexHookEventForInput(rawInput, args) }, {
670
+ ir,
671
+ projectDir,
672
+ hookInstallMode: codexInstallMode(argValue(args, "--codex-install-mode")),
673
+ hookTrusted: true,
674
+ codexVersion: process.env.CODEX_VERSION,
675
+ workflowAsset,
676
+ workflowId: workflowState?.workflow,
677
+ stepId: workflowState?.current_step,
678
+ appendEvent: true,
679
+ });
680
+ }
681
+ async function runCodexHookCli(args) {
682
+ try {
683
+ const rawInput = await readStdin(5000);
684
+ const projectDir = typeof rawInput.cwd === "string" ? rawInput.cwd : process.cwd();
685
+ const irPath = argValue(args, "--ir") ?? DEFAULT_IR_PATH;
686
+ const ir = await loadIR(resolve(projectDir, irPath));
687
+ if (!ir) {
688
+ writeOutput(silentOutput());
689
+ return;
690
+ }
691
+ const result = await runCodexHookWithLoadedIr(rawInput, projectDir, args, ir);
692
+ writeOutput(result.output);
693
+ }
694
+ catch (err) {
695
+ process.stderr.write(`\n Intent DNA: CodexHook failed open — ${err instanceof Error ? err.message : String(err)}\n`);
696
+ writeOutput(silentOutput());
697
+ }
698
+ }
557
699
  // ── IR Loading ─────────────────────────────────────────────
558
700
  /** Expected IR schema version — must match plugin-adapter.ts */
559
701
  const EXPECTED_IR_VERSION = 1;
@@ -777,6 +919,8 @@ function appendArtifactResolverTrace(projectDir, event, wfState, output, session
777
919
  export const recordProducedArtifactsForTest = recordProducedArtifacts;
778
920
  export const resolveWorkflowArtifactFactsForTest = resolveWorkflowArtifactFacts;
779
921
  export const readWorkflowStateForHookTest = readWorkflowStateForHook;
922
+ export const runCodexHookWithLoadedIrForTest = runCodexHookWithLoadedIr;
923
+ export const inferWorkflowAssetFromIrForTest = inferWorkflowAssetFromIr;
780
924
  export const resolveWorkflowArtifactFactsForHookTest = resolveWorkflowArtifactFactsForHook;
781
925
  export const finalizeAndResolveArtifactsForHookTest = finalizeAndResolveArtifactsForHook;
782
926
  function clearBlockingVerifierCheckpoints(ir, workflowState) {
@@ -26,6 +26,7 @@ export interface EnforceState {
26
26
  workflowState?: {
27
27
  current_step: string;
28
28
  workflow: string;
29
+ workflow_asset?: string;
29
30
  current_role?: string;
30
31
  completed_artifacts?: CompletedArtifactEntry[];
31
32
  /** G4: current workflow iteration (for relax_after_iteration rules) */
@@ -4,7 +4,7 @@
4
4
  * TypeScript types for Claude Code hook I/O and stdin/stdout utilities.
5
5
  * All hooks read JSON from stdin and write JSON to stdout.
6
6
  *
7
- * Protocol reference: docs/references/cc-source-analysis.md §2
7
+ * Protocol reference: docs/archive/2026H1/references/cc-source-analysis.md §2
8
8
  */
9
9
  export type { HookEvent } from "./event-registry.js";
10
10
  /** Base fields present in all hook inputs */
@@ -4,7 +4,7 @@
4
4
  * TypeScript types for Claude Code hook I/O and stdin/stdout utilities.
5
5
  * All hooks read JSON from stdin and write JSON to stdout.
6
6
  *
7
- * Protocol reference: docs/references/cc-source-analysis.md §2
7
+ * Protocol reference: docs/archive/2026H1/references/cc-source-analysis.md §2
8
8
  */
9
9
  // ── Output Helpers ─────────────────────────────────────────
10
10
  /** Create an allow output, optionally injecting text into the conversation. */
@@ -11,9 +11,11 @@
11
11
  */
12
12
  import type { ArtifactFact, ArtifactKey, ArtifactManifest, CompletedArtifactEntry, HandoffArtifact, HandoffType, VerifierKind, VerifierSeverity, VerifierWhen } from "../schema/types.js";
13
13
  import { type RuntimeDecisionEvent } from "../governance/index.js";
14
+ export declare const EVIDENCE_CAPTURE_SCHEMA_VERSION = "intentdna.evidence_capture.v1";
14
15
  /** Workflow state written by runtime and read by hooks */
15
16
  export interface DNAWorkflowState {
16
17
  active: boolean;
18
+ workflow_asset?: string;
17
19
  workflow: string;
18
20
  current_step: string;
19
21
  current_role: string;
@@ -51,6 +53,44 @@ export interface SurgeonAttemptState {
51
53
  lesson: string;
52
54
  }>;
53
55
  }
56
+ export type EvidenceCaptureSource = "dna_hook" | "codex_cli" | "claude_code" | "dna_cli" | "manual";
57
+ export type EvidenceCaptureFact = "command" | "result" | "retry" | "manual_intervention" | "blocker" | "handoff";
58
+ export type EvidenceCaptureResult = "success" | "failure" | "blocked" | "skipped" | "unknown" | "unsupported";
59
+ export interface EvidenceCaptureRetry {
60
+ attempt: number;
61
+ max_attempts: number;
62
+ reason: string;
63
+ }
64
+ export interface EvidenceCaptureManualIntervention {
65
+ required: boolean;
66
+ reason: string;
67
+ actor: string;
68
+ }
69
+ export interface EvidenceCaptureRef {
70
+ type: string;
71
+ ref: string;
72
+ }
73
+ export interface EvidenceCaptureEvent {
74
+ schema_version: typeof EVIDENCE_CAPTURE_SCHEMA_VERSION;
75
+ event_id: string;
76
+ captured_at: string;
77
+ project_root: string;
78
+ source: EvidenceCaptureSource;
79
+ workflow_asset: string;
80
+ workflow_id: string;
81
+ run_id: string;
82
+ step_id: string;
83
+ fact: EvidenceCaptureFact;
84
+ summary: string;
85
+ command?: string;
86
+ result?: EvidenceCaptureResult;
87
+ exit_code?: number;
88
+ duration_ms?: number;
89
+ retry?: EvidenceCaptureRetry;
90
+ manual_intervention?: EvidenceCaptureManualIntervention;
91
+ evidence_refs?: EvidenceCaptureRef[];
92
+ redaction?: string;
93
+ }
54
94
  export declare function safePathComponent(value: string, label: string): string;
55
95
  /**
56
96
  * Resolve state directory path.
@@ -181,6 +221,7 @@ export interface TraceEntry {
181
221
  * Fail-open: never throws.
182
222
  */
183
223
  export declare function appendTrace(projectDir: string, entry: TraceEntry, sessionId?: string): Promise<void>;
224
+ export declare function appendEvidenceCaptureEvent(projectDir: string, event: EvidenceCaptureEvent): Promise<void>;
184
225
  export declare function appendRuntimeDecisionEvent(projectDir: string, event: RuntimeDecisionEvent, sessionId?: string): Promise<void>;
185
226
  export declare function readRuntimeDecisionEvents(projectDir: string, days?: number, sessionId?: string): Promise<RuntimeDecisionEvent[]>;
186
227
  export declare function readTraces(projectDir: string, days?: number, sessionId?: string): Promise<TraceEntry[]>;
@@ -13,6 +13,8 @@ import { readFile, writeFile, rename, mkdir, appendFile, unlink, readdir, stat }
13
13
  import { createHash } from "node:crypto";
14
14
  import { join, dirname } from "node:path";
15
15
  import { CASCADE_LAYER_NAMES, RUNTIME_DECISION_EVENT_SCHEMA_VERSION } from "../governance/index.js";
16
+ // ── Types ──────────────────────────────────────────────────
17
+ export const EVIDENCE_CAPTURE_SCHEMA_VERSION = "intentdna.evidence_capture.v1";
16
18
  // ── Constants ──────────────────────────────────────────────
17
19
  const WORKFLOW_FILE = "workflow.json";
18
20
  const DEFAULT_STALENESS_MS = 2 * 60 * 60 * 1000; // 2 hours
@@ -408,6 +410,7 @@ export async function appendVerifierResult(projectDir, result, sessionId) {
408
410
  }
409
411
  const TRACE_DIR = "trace";
410
412
  const RUNTIME_DECISION_DIR = "runtime-decisions";
413
+ const EVIDENCE_CAPTURE_DIR = join("evidence", "capture");
411
414
  const MAX_TRACE_SIZE = 10 * 1024 * 1024; // 10MB
412
415
  const TRACE_RETENTION_DAYS = 7;
413
416
  /**
@@ -475,15 +478,135 @@ function datedJsonlFileName(prefix, date) {
475
478
  function decisionFileName(date) {
476
479
  return datedJsonlFileName("runtime-decision", date);
477
480
  }
481
+ function evidenceCaptureFileName(date) {
482
+ return `${date}.jsonl`;
483
+ }
484
+ function privacyDigest(domain, value) {
485
+ const material = value && value.trim().length > 0 ? value : "unknown";
486
+ return createHash("sha256")
487
+ .update(`intentdna.privacy.${domain}\0${material}`)
488
+ .digest("hex");
489
+ }
490
+ const OPAQUE_REFERENCE = /^(?:(?:[a-z][a-z0-9:-]*:)?sha256:[a-f0-9]{64}|[a-f0-9]{8}-[a-f0-9]{4}-[1-8][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12})$/i;
491
+ const PROJECTED_REFERENCE = /^intentdna-[a-z0-9-]+:sha256:[a-f0-9]{64}$/i;
492
+ const RUNTIME_EVIDENCE_REF_TYPES = new Set(["trace", "audit", "artifact", "verifier", "handoff", "legacy", "unknown", "unsupported"]);
493
+ const CAPTURE_EVIDENCE_REF_TYPES = new Set([...RUNTIME_EVIDENCE_REF_TYPES, "runtime_decision_event", "completion_check", "git_commit"]);
494
+ function projectedValue(domain, value) {
495
+ const material = value && value.trim().length > 0 ? value : "unknown";
496
+ if (material === "unknown" || material === "unsupported")
497
+ return material;
498
+ if (material.startsWith(`intentdna-${domain}:sha256:`) && PROJECTED_REFERENCE.test(material))
499
+ return material;
500
+ return `intentdna-${domain}:sha256:${privacyDigest(domain, material)}`;
501
+ }
502
+ function projectedSessionDirName(sessionId) {
503
+ return `session-sha256-${privacyDigest("session-dir", sessionId)}`;
504
+ }
505
+ function projectedRuntimeEvidenceRef(ref) {
506
+ const type = RUNTIME_EVIDENCE_REF_TYPES.has(ref.type) ? ref.type : "unknown";
507
+ return {
508
+ type,
509
+ ref: OPAQUE_REFERENCE.test(ref.ref) ? ref.ref : projectedValue(`c4-evidence-ref-${type}`, ref.ref),
510
+ };
511
+ }
512
+ function projectedCaptureEvidenceRef(ref) {
513
+ const type = CAPTURE_EVIDENCE_REF_TYPES.has(ref.type) ? ref.type : "unknown";
514
+ if (type === "runtime_decision_event" || OPAQUE_REFERENCE.test(ref.ref))
515
+ return { type, ref: ref.ref };
516
+ return {
517
+ type,
518
+ ref: projectedValue(`c5-evidence-ref-${type}`, ref.ref),
519
+ };
520
+ }
521
+ function dateFromIso(value) {
522
+ return typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)
523
+ ? value.slice(0, 10)
524
+ : new Date().toISOString().slice(0, 10);
525
+ }
526
+ function redactEvidenceCaptureText(value) {
527
+ return value
528
+ .replace(/(authorization:\s*Bearer\s+)[^\s'"]+/gi, "$1<redacted>")
529
+ .replace(/((?:INTENTDNA_API_TOKEN|INTENTDNA_SUPABASE_USER_JWT|SUPABASE_ACCESS_TOKEN|SUPABASE_SERVICE_ROLE_KEY|INTENTDNA_TOKEN_PEPPER|SUPABASE_SECRET_KEYS)=)(?:"[^"]*"|'[^']*'|[^\s'"]+)/gi, "$1<redacted>")
530
+ .replace(/idna_[A-Za-z0-9_-]+/g, "idna_<redacted>")
531
+ .replace(/sbp_[A-Za-z0-9_-]+/g, "sbp_<redacted>")
532
+ .replace(/eyJ[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+){2}/g, "<jwt-redacted>");
533
+ }
534
+ function redactEvidenceCaptureEvent(event) {
535
+ return {
536
+ ...event,
537
+ project_root: projectedValue("c5-project-root", event.project_root),
538
+ run_id: projectedValue("c5-run-id", event.run_id),
539
+ summary: projectedValue("c5-summary", redactEvidenceCaptureText(event.summary)),
540
+ command: event.command ? projectedValue("c5-command", redactEvidenceCaptureText(event.command)) : undefined,
541
+ retry: event.retry ? { ...event.retry, reason: projectedValue("c5-retry-reason", redactEvidenceCaptureText(event.retry.reason)) } : undefined,
542
+ manual_intervention: event.manual_intervention
543
+ ? { ...event.manual_intervention, reason: projectedValue("c5-manual-reason", redactEvidenceCaptureText(event.manual_intervention.reason)) }
544
+ : undefined,
545
+ evidence_refs: event.evidence_refs?.map(projectedCaptureEvidenceRef),
546
+ redaction: "intentdna.c5.persistent_projection.v1",
547
+ };
548
+ }
549
+ function projectRuntimeDecisionEventForDisk(event) {
550
+ return {
551
+ ...event,
552
+ org_id: projectedValue("c4-org-id", event.org_id),
553
+ team_id: projectedValue("c4-team-id", event.team_id),
554
+ user_id: projectedValue("c4-user-id", event.user_id),
555
+ project_id: projectedValue("c4-project-id", event.project_id),
556
+ agent_id: projectedValue("c4-agent-id", event.agent_id),
557
+ agent_role: projectedValue("c4-agent-role", event.agent_role),
558
+ agent_type: projectedValue("c4-agent-type", event.agent_type),
559
+ session_agent: projectedValue("c4-session-agent", event.session_agent),
560
+ cascade_layers: Object.fromEntries(CASCADE_LAYER_NAMES.map((layer) => {
561
+ const entry = event.cascade_layers[layer];
562
+ return [layer, {
563
+ ...entry,
564
+ source_ref: projectedValue(`c4-cascade-${layer}-source-ref`, entry.source_ref),
565
+ }];
566
+ })),
567
+ winning_constraint: {
568
+ ...event.winning_constraint,
569
+ provenance_reason: projectedValue("c4-winning-provenance-reason", event.winning_constraint.provenance_reason),
570
+ },
571
+ decision_reason: projectedValue("c4-decision-reason", event.decision_reason),
572
+ harness_runtime_context: {
573
+ ...event.harness_runtime_context,
574
+ agent_id: projectedValue("c4-agent-id", event.harness_runtime_context.agent_id),
575
+ agent_role: projectedValue("c4-agent-role", event.harness_runtime_context.agent_role),
576
+ agent_type: projectedValue("c4-agent-type", event.harness_runtime_context.agent_type),
577
+ session_agent: projectedValue("c4-session-agent", event.harness_runtime_context.session_agent),
578
+ },
579
+ session_id: projectedValue("c4-session-id", event.session_id),
580
+ run_id: projectedValue("c4-run-id", event.run_id),
581
+ step_id: projectedValue("c4-step-id", event.step_id),
582
+ tool_name: projectedValue("c4-tool-name", event.tool_name),
583
+ resource_ref: projectedValue("c4-resource-ref", event.resource_ref),
584
+ evidence_refs: event.evidence_refs.map(projectedRuntimeEvidenceRef),
585
+ };
586
+ }
587
+ export async function appendEvidenceCaptureEvent(projectDir, event) {
588
+ try {
589
+ const sanitized = redactEvidenceCaptureEvent(event);
590
+ const line = JSON.stringify(sanitized) + "\n";
591
+ const date = dateFromIso(sanitized.captured_at);
592
+ const captureDir = join(projectDir, ".dna", EVIDENCE_CAPTURE_DIR);
593
+ await mkdir(captureDir, { recursive: true });
594
+ await appendFile(join(captureDir, evidenceCaptureFileName(date)), line, "utf-8");
595
+ }
596
+ catch {
597
+ // Fail-open: evidence capture write failure never affects hook execution
598
+ }
599
+ }
478
600
  export async function appendRuntimeDecisionEvent(projectDir, event, sessionId) {
479
601
  try {
480
- const line = JSON.stringify(event) + "\n";
602
+ const projected = projectRuntimeDecisionEventForDisk(event);
603
+ const line = JSON.stringify(projected) + "\n";
481
604
  const date = new Date().toISOString().slice(0, 10);
482
605
  const globalDir = join(projectDir, ".dna", "state", RUNTIME_DECISION_DIR);
483
606
  await mkdir(globalDir, { recursive: true });
484
607
  await appendFile(join(globalDir, decisionFileName(date)), line, "utf-8");
485
608
  if (sessionId) {
486
- const sessionDir = resolveStateDir(projectDir, sessionId);
609
+ const sessionDir = resolveStateDir(projectDir, projectedSessionDirName(sessionId));
487
610
  await mkdir(sessionDir, { recursive: true });
488
611
  await appendFile(join(sessionDir, "runtime-decisions.jsonl"), line, "utf-8");
489
612
  }
@@ -572,6 +695,7 @@ function normalizeRuntimeDecisionEvent(value) {
572
695
  export async function readRuntimeDecisionEvents(projectDir, days = 1, sessionId) {
573
696
  const entries = [];
574
697
  if (sessionId) {
698
+ entries.push(...await readRuntimeDecisionFile(join(resolveStateDir(projectDir, projectedSessionDirName(sessionId)), "runtime-decisions.jsonl")));
575
699
  entries.push(...await readRuntimeDecisionFile(join(resolveStateDir(projectDir, sessionId), "runtime-decisions.jsonl")));
576
700
  }
577
701
  else {
package/dist/index.d.ts CHANGED
@@ -2,3 +2,6 @@ export * from "./schema/index.js";
2
2
  export * from "./compiler/index.js";
3
3
  export * from "./runtime/index.js";
4
4
  export * from "./governance/index.js";
5
+ export * from "./assets/index.js";
6
+ export * from "./workflow/index.js";
7
+ export * from "./organization/index.js";
package/dist/index.js CHANGED
@@ -2,3 +2,6 @@ export * from "./schema/index.js";
2
2
  export * from "./compiler/index.js";
3
3
  export * from "./runtime/index.js";
4
4
  export * from "./governance/index.js";
5
+ export * from "./assets/index.js";
6
+ export * from "./workflow/index.js";
7
+ export * from "./organization/index.js";
@@ -104,6 +104,7 @@ export function createStateTools(projectDir) {
104
104
  type: "object",
105
105
  properties: {
106
106
  workflow: { type: "string", description: "Workflow name" },
107
+ workflow_asset: { type: "string", description: "Workflow asset id/name for local evidence attribution" },
107
108
  current_step: { type: "string", description: "Current step ID" },
108
109
  current_role: { type: "string", description: "Current role name" },
109
110
  iteration: { type: "number", description: "Current iteration number" },
@@ -119,6 +120,7 @@ export function createStateTools(projectDir) {
119
120
  const existing = await readWorkflowState(projectDir, sessionId, 0);
120
121
  const state = {
121
122
  active: typeof args.active === "boolean" ? args.active : true,
123
+ workflow_asset: typeof args.workflow_asset === "string" ? args.workflow_asset : existing?.workflow_asset,
122
124
  workflow: String(args.workflow),
123
125
  current_step: String(args.current_step),
124
126
  current_role: String(args.current_role),