intentdna 1.7.5 → 1.8.1

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 (154) 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 +8 -1
  38. package/dist/cli/commands/run.js +129 -57
  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 +9 -0
  53. package/dist/hooks/cli.js +170 -411
  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 +164 -39
  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/runtime/verifier.d.ts +51 -0
  83. package/dist/runtime/verifier.js +462 -0
  84. package/dist/schema/controller-registry.d.ts +8 -1
  85. package/dist/schema/controller-registry.js +8 -0
  86. package/dist/schema/types.d.ts +35 -23
  87. package/dist/schema/types.js +10 -1
  88. package/dist/schema/validate.js +22 -22
  89. package/dist/schema/validators/controllers.js +38 -20
  90. package/dist/schema/workflow-authoring-contract.d.ts +29 -0
  91. package/dist/schema/workflow-authoring-contract.js +109 -0
  92. package/dist/schema/yaml-parser.js +18 -0
  93. package/dist/templates/api-backend.dna.yaml +19 -0
  94. package/dist/templates/brainstorming-first.dna.yaml +19 -0
  95. package/dist/templates/code-cleanup.dna.yaml +19 -0
  96. package/dist/templates/code-review-pipeline.dna.yaml +18 -0
  97. package/dist/templates/documentation-writer.dna.yaml +19 -0
  98. package/dist/templates/flutter-behavior-lock.dna.yaml +19 -0
  99. package/dist/templates/flutter-refactoring-rescue.dna.yaml +19 -0
  100. package/dist/templates/flutter-rewrite-diagnosis-review.dna.yaml +210 -0
  101. package/dist/templates/flutter-rewrite-fix-review-loop.dna.yaml +260 -0
  102. package/dist/templates/flutter-rewrite-new.dna.yaml +506 -0
  103. package/dist/templates/flutter-rewrite.dna.yaml +100 -4
  104. package/dist/templates/frontend-quality.dna.yaml +19 -0
  105. package/dist/templates/full-pipeline.dna.yaml +20 -0
  106. package/dist/templates/marketplace.d.ts +92 -0
  107. package/dist/templates/marketplace.js +502 -0
  108. package/dist/templates/metadata.d.ts +25 -0
  109. package/dist/templates/metadata.js +136 -3
  110. package/dist/templates/mobile-dev.dna.yaml +19 -0
  111. package/dist/templates/multi-agent-handoff-coordination.dna.yaml +156 -0
  112. package/dist/templates/multi-perspective-review.dna.yaml +19 -0
  113. package/dist/templates/persistent-executor.dna.yaml +19 -0
  114. package/dist/templates/qa-loop.dna.yaml +18 -0
  115. package/dist/templates/release-evidence-gate.dna.yaml +131 -0
  116. package/dist/templates/requirements-gate.dna.yaml +19 -0
  117. package/dist/templates/research-orchestration.dna.yaml +19 -0
  118. package/dist/templates/root-cause-analysis.dna.yaml +19 -0
  119. package/dist/templates/safe-refactoring.dna.yaml +321 -0
  120. package/dist/templates/secure-dev.dna.yaml +19 -0
  121. package/dist/templates/subagent-parallel.dna.yaml +19 -0
  122. package/dist/templates/systematic-debugging.dna.yaml +19 -0
  123. package/dist/templates/tdd-strict.dna.yaml +19 -0
  124. package/dist/templates/ui-visual-regression-qa.dna.yaml +133 -0
  125. package/dist/templates/workflow-author.dna.yaml +302 -0
  126. package/dist/templates/workflow-blocked-scope-triage.dna.yaml +242 -0
  127. package/dist/templates/workflow-completion-audit.dna.yaml +254 -0
  128. package/dist/templates/workflow-cross-boundary-resource-approval.dna.yaml +249 -0
  129. package/dist/templates/workflow-evidence-review.dna.yaml +198 -0
  130. package/dist/templates/workflow-module-inventory.dna.yaml +257 -0
  131. package/dist/templates/workflow-runtime-smoke-review.dna.yaml +252 -0
  132. package/dist/templates/workflow-verification-command-routing.dna.yaml +278 -0
  133. package/dist/workflow/authoring-packet.d.ts +67 -0
  134. package/dist/workflow/authoring-packet.js +218 -0
  135. package/dist/workflow/draft.d.ts +159 -0
  136. package/dist/workflow/draft.js +800 -0
  137. package/dist/workflow/index.d.ts +3 -0
  138. package/dist/workflow/index.js +3 -0
  139. package/dist/workflow/suggestion-review.d.ts +65 -0
  140. package/dist/workflow/suggestion-review.js +245 -0
  141. package/package.json +1 -1
  142. package/spec/README.md +15 -48
  143. package/spec/codex-adapter-contract.md +176 -0
  144. package/spec/sync-target-plan.md +158 -0
  145. package/spec/workflow-capability-ir.md +153 -0
  146. package/spec/agent-dispatch-fix.md +0 -116
  147. package/spec/control-plane-convergence-handoff-2026-04-24.md +0 -432
  148. package/spec/flutter-rewrite-template-optimization.md +0 -301
  149. package/spec/foundation-hardening.md +0 -178
  150. package/spec/hooks-infra-harness-hardening.md +0 -741
  151. package/spec/multi-config.md +0 -172
  152. package/spec/parallel-isolation.md +0 -268
  153. package/spec/template-version-namespace-fix.md +0 -653
  154. package/spec/workflow-pipeline.md +0 -101
@@ -96,7 +96,8 @@ export interface VerifierCommandPolicy {
96
96
  allow_builtin_asserts?: string[];
97
97
  }
98
98
  /** Handoff artifact type — what kind of artifact is passed between steps */
99
- export type HandoffType = "file" | "directory" | "test_result" | "git_commit" | "summary" | "state";
99
+ export declare const HANDOFF_TYPE_VALUES: readonly ["file", "directory", "test_result", "git_commit", "summary", "state"];
100
+ export type HandoffType = typeof HANDOFF_TYPE_VALUES[number];
100
101
  /** A single artifact consumed or produced by a workflow step */
101
102
  export interface HandoffArtifact {
102
103
  type: HandoffType;
@@ -142,14 +143,18 @@ export interface StepHandoff {
142
143
  export interface TransitionDef {
143
144
  from: string;
144
145
  to: string;
145
- condition: "pass" | "fail" | "always" | "error";
146
+ condition: TransitionCondition;
146
147
  }
148
+ export declare const TRANSITION_CONDITION_VALUES: readonly ["pass", "fail", "always", "error"];
149
+ export type TransitionCondition = typeof TRANSITION_CONDITION_VALUES[number];
147
150
  /** Retry policy for the workflow */
148
151
  export interface RetryPolicy {
149
152
  max_retries: number;
150
153
  retry_from?: string;
151
- backoff?: "none" | "linear" | "exponential";
154
+ backoff?: RetryBackoff;
152
155
  }
156
+ export declare const RETRY_BACKOFF_VALUES: readonly ["none", "linear", "exponential"];
157
+ export type RetryBackoff = typeof RETRY_BACKOFF_VALUES[number];
153
158
  /** Predefined checkpoint assertion types — compiler knows how to translate each to shell */
154
159
  export type CheckpointAssertType = "clean_working_tree" | "no_test_regression" | "lint_passing" | "build_passing";
155
160
  /** Step checkpoint — condition that must be met before transitioning to next step */
@@ -157,8 +162,18 @@ export interface StepCheckpoint {
157
162
  assert: CheckpointAssertType | string;
158
163
  command?: string;
159
164
  message: string;
160
- action?: "block" | "warn";
161
- }
165
+ action?: CheckpointAction;
166
+ }
167
+ export declare const CHECKPOINT_ACTION_VALUES: readonly ["block", "warn"];
168
+ export type CheckpointAction = typeof CHECKPOINT_ACTION_VALUES[number];
169
+ export declare const WORKFLOW_ISOLATION_VALUES: readonly ["none", "worktree", "auto"];
170
+ export type WorkflowIsolation = typeof WORKFLOW_ISOLATION_VALUES[number];
171
+ export declare const WORKFLOW_STEP_FAILURE_VALUES: readonly ["retry_with_feedback", "handoff", "skip"];
172
+ export type WorkflowStepFailureAction = typeof WORKFLOW_STEP_FAILURE_VALUES[number];
173
+ export declare const WORKFLOW_HANDOFF_EXHAUSTED_VALUES: readonly ["skip", "stop"];
174
+ export type WorkflowHandoffExhaustedAction = typeof WORKFLOW_HANDOFF_EXHAUSTED_VALUES[number];
175
+ export declare const WORKFLOW_MERGE_STRATEGY_VALUES: readonly ["escalate"];
176
+ export type WorkflowMergeStrategy = typeof WORKFLOW_MERGE_STRATEGY_VALUES[number];
162
177
  /** Completion check for a workflow step */
163
178
  export interface CompletionCheck {
164
179
  file_exists?: string;
@@ -181,17 +196,17 @@ export interface WorkflowStepDef {
181
196
  completion?: CompletionCheck[];
182
197
  checkpoints?: StepCheckpoint[];
183
198
  handoff?: StepHandoff;
184
- isolation?: "none" | "worktree" | "auto";
199
+ isolation?: WorkflowIsolation;
185
200
  enforce?: {
186
201
  read_only?: boolean;
187
202
  relax_after_iteration?: number;
188
203
  additional_write_paths?: string[];
189
204
  };
190
205
  max_attempts?: number;
191
- on_fail?: "retry_with_feedback" | "handoff" | "skip";
206
+ on_fail?: WorkflowStepFailureAction;
192
207
  handoff_to?: string;
193
208
  max_handoffs?: number;
194
- on_handoff_exhausted?: "skip" | "stop";
209
+ on_handoff_exhausted?: WorkflowHandoffExhaustedAction;
195
210
  blocked_items_path?: string;
196
211
  }
197
212
  /** Top-level workflow definition */
@@ -204,10 +219,10 @@ export interface WorkflowDef {
204
219
  max_rounds?: number;
205
220
  produces?: HandoffArtifact[];
206
221
  consumes?: HandoffArtifact[];
207
- default_isolation?: "none" | "worktree" | "auto";
208
- merge_strategy?: "escalate";
222
+ default_isolation?: WorkflowIsolation;
223
+ merge_strategy?: WorkflowMergeStrategy;
209
224
  }
210
- export type ControllerKind = "fix_loop" | "flutter_rewrite_fix_loop";
225
+ export type ControllerKind = "fix_loop" | "flutter_rewrite_fix_loop" | "sequential";
211
226
  export interface ControllerPolicyDef {
212
227
  diagnosis_reuse_criteria?: string[];
213
228
  progress_provenance_checks?: string[];
@@ -223,18 +238,13 @@ export interface ControllerDef {
223
238
  kind: ControllerKind;
224
239
  max_rounds: number;
225
240
  progress_artifact_path: string;
226
- diagnosis_workflow: string;
227
- fix_workflow: string;
228
- diagnosis_artifact_path: string;
229
- diagnosis_review_artifact_path: string;
230
- review_artifact_path: string;
231
- roles: {
232
- analyzer: string;
233
- analysis_reviewer: string;
234
- surgeon: string;
235
- fix_reviewer: string;
236
- test_runner: string;
237
- };
241
+ workflow?: string;
242
+ diagnosis_workflow?: string;
243
+ fix_workflow?: string;
244
+ diagnosis_artifact_path?: string;
245
+ diagnosis_review_artifact_path?: string;
246
+ review_artifact_path?: string;
247
+ roles: Record<string, string>;
238
248
  stop_format: "configured_stop_report" | "zh_three_part";
239
249
  policy?: ControllerPolicyDef;
240
250
  }
@@ -479,6 +489,7 @@ export interface StepEnforceRule {
479
489
  export interface WorkflowIR {
480
490
  workflow_name: string;
481
491
  namespace: string;
492
+ step_ids?: string[];
482
493
  step_checkpoints: StepCheckpointIR[];
483
494
  active_roles: string[];
484
495
  handoff_chain: HandoffChainEntry[];
@@ -502,6 +513,7 @@ export interface CompletedArtifactEntry {
502
513
  /** Runtime workflow state written to .dna/state/workflow.json */
503
514
  export interface WorkflowState {
504
515
  active: boolean;
516
+ workflow_asset?: string;
505
517
  workflow: string;
506
518
  current_step: string;
507
519
  current_role: string;
@@ -7,4 +7,13 @@
7
7
  * Layer 3: Regulatory Regions (context-dependent expression)
8
8
  * Layer 4: Epigenetic Markers (experience-driven modulation)
9
9
  */
10
- export {};
10
+ // ── Workflow System ─────────────────────────────────────────
11
+ /** Handoff artifact type — what kind of artifact is passed between steps */
12
+ export const HANDOFF_TYPE_VALUES = ["file", "directory", "test_result", "git_commit", "summary", "state"];
13
+ export const TRANSITION_CONDITION_VALUES = ["pass", "fail", "always", "error"];
14
+ export const RETRY_BACKOFF_VALUES = ["none", "linear", "exponential"];
15
+ export const CHECKPOINT_ACTION_VALUES = ["block", "warn"];
16
+ export const WORKFLOW_ISOLATION_VALUES = ["none", "worktree", "auto"];
17
+ export const WORKFLOW_STEP_FAILURE_VALUES = ["retry_with_feedback", "handoff", "skip"];
18
+ export const WORKFLOW_HANDOFF_EXHAUSTED_VALUES = ["skip", "stop"];
19
+ export const WORKFLOW_MERGE_STRATEGY_VALUES = ["escalate"];
@@ -8,6 +8,7 @@
8
8
  * - No circular inheritance
9
9
  */
10
10
  import { isAbsolute } from "node:path";
11
+ import { CHECKPOINT_ACTION_VALUES, HANDOFF_TYPE_VALUES, RETRY_BACKOFF_VALUES, TRANSITION_CONDITION_VALUES, WORKFLOW_HANDOFF_EXHAUSTED_VALUES, WORKFLOW_ISOLATION_VALUES, WORKFLOW_MERGE_STRATEGY_VALUES, WORKFLOW_STEP_FAILURE_VALUES, } from "./types.js";
11
12
  import { validateController } from "./validators/controllers.js";
12
13
  const SAFE_GENERATED_IDENTIFIER = /^[A-Za-z0-9_-]+$/;
13
14
  const SAFE_GENERATED_DISPLAY_NAME = /^[A-Za-z0-9][A-Za-z0-9 _-]*$/;
@@ -503,25 +504,22 @@ function validateWorkflow(workflow, roleNames, pathPrefix) {
503
504
  }
504
505
  // on_fail: must be a valid enum value
505
506
  if (step.on_fail !== undefined) {
506
- const validOnFail = ["retry_with_feedback", "handoff", "skip"];
507
- if (!validOnFail.includes(step.on_fail)) {
508
- errors.push({ path: `${stepPath}.on_fail`, message: `must be one of: ${validOnFail.join(", ")}` });
507
+ if (!WORKFLOW_STEP_FAILURE_VALUES.includes(step.on_fail)) {
508
+ errors.push({ path: `${stepPath}.on_fail`, message: `must be one of: ${WORKFLOW_STEP_FAILURE_VALUES.join(", ")}` });
509
509
  }
510
510
  }
511
511
  // on_handoff_exhausted: must be a valid enum value
512
512
  if (step.on_handoff_exhausted !== undefined) {
513
- const validExhausted = ["skip", "stop"];
514
- if (!validExhausted.includes(step.on_handoff_exhausted)) {
515
- errors.push({ path: `${stepPath}.on_handoff_exhausted`, message: `must be one of: ${validExhausted.join(", ")}` });
513
+ if (!WORKFLOW_HANDOFF_EXHAUSTED_VALUES.includes(step.on_handoff_exhausted)) {
514
+ errors.push({ path: `${stepPath}.on_handoff_exhausted`, message: `must be one of: ${WORKFLOW_HANDOFF_EXHAUSTED_VALUES.join(", ")}` });
516
515
  }
517
516
  }
518
517
  // isolation: must be a valid enum value
519
518
  if (step.isolation !== undefined) {
520
- const validIsolation = ["none", "worktree", "auto"];
521
- if (!validIsolation.includes(step.isolation)) {
519
+ if (!WORKFLOW_ISOLATION_VALUES.includes(step.isolation)) {
522
520
  errors.push({
523
521
  path: `${stepPath}.isolation`,
524
- message: `must be one of: ${validIsolation.join(", ")}`,
522
+ message: `must be one of: ${WORKFLOW_ISOLATION_VALUES.join(", ")}`,
525
523
  });
526
524
  }
527
525
  }
@@ -540,6 +538,12 @@ function validateWorkflow(workflow, roleNames, pathPrefix) {
540
538
  for (let j = 0; j < artifacts.length; j++) {
541
539
  const artifact = artifacts[j];
542
540
  const artifactPath = `${stepPath}.handoff.${direction}[${j}]`;
541
+ if (!HANDOFF_TYPE_VALUES.includes(artifact.type)) {
542
+ errors.push({ path: `${artifactPath}.type`, message: `must be one of: ${HANDOFF_TYPE_VALUES.join(", ")}` });
543
+ }
544
+ if (!artifact.description) {
545
+ errors.push({ path: `${artifactPath}.description`, message: "handoff artifact requires 'description'" });
546
+ }
543
547
  if (artifact.required !== false && artifact.type !== "git_commit" && !artifact.path && !artifact.name && !artifact.artifact_id) {
544
548
  errors.push({ path: artifactPath, message: "required handoff artifacts must define path, name, or artifact_id" });
545
549
  }
@@ -567,7 +571,7 @@ function validateWorkflow(workflow, roleNames, pathPrefix) {
567
571
  if (!cp.message) {
568
572
  errors.push({ path: `${cpPath}.message`, message: "checkpoint requires 'message'" });
569
573
  }
570
- if (cp.action && cp.action !== "block" && cp.action !== "warn") {
574
+ if (cp.action && !CHECKPOINT_ACTION_VALUES.includes(cp.action)) {
571
575
  errors.push({ path: `${cpPath}.action`, message: "checkpoint action must be 'block' or 'warn'" });
572
576
  }
573
577
  }
@@ -607,26 +611,23 @@ function validateWorkflow(workflow, roleNames, pathPrefix) {
607
611
  }
608
612
  // Validate default_isolation
609
613
  if (workflow.default_isolation !== undefined) {
610
- const validIsolation = ["none", "worktree", "auto"];
611
- if (!validIsolation.includes(workflow.default_isolation)) {
614
+ if (!WORKFLOW_ISOLATION_VALUES.includes(workflow.default_isolation)) {
612
615
  errors.push({
613
616
  path: `${path}.default_isolation`,
614
- message: `must be one of: ${validIsolation.join(", ")}`,
617
+ message: `must be one of: ${WORKFLOW_ISOLATION_VALUES.join(", ")}`,
615
618
  });
616
619
  }
617
620
  }
618
621
  // Validate merge_strategy
619
622
  if (workflow.merge_strategy !== undefined) {
620
- const validStrategies = ["escalate"];
621
- if (!validStrategies.includes(workflow.merge_strategy)) {
623
+ if (!WORKFLOW_MERGE_STRATEGY_VALUES.includes(workflow.merge_strategy)) {
622
624
  errors.push({
623
625
  path: `${path}.merge_strategy`,
624
- message: `must be one of: ${validStrategies.join(", ")}`,
626
+ message: `must be one of: ${WORKFLOW_MERGE_STRATEGY_VALUES.join(", ")}`,
625
627
  });
626
628
  }
627
629
  }
628
630
  // Validate transitions
629
- const validConditions = ["pass", "fail", "always", "error"];
630
631
  for (let i = 0; i < (workflow.transitions?.length ?? 0); i++) {
631
632
  const t = workflow.transitions[i];
632
633
  const tPath = `${path}.transitions[${i}]`;
@@ -642,10 +643,10 @@ function validateWorkflow(workflow, roleNames, pathPrefix) {
642
643
  else if (!stepIds.has(t.to)) {
643
644
  errors.push({ path: `${tPath}.to`, message: `transition references unknown step '${t.to}'` });
644
645
  }
645
- if (!t.condition || !validConditions.includes(t.condition)) {
646
+ if (!t.condition || !TRANSITION_CONDITION_VALUES.includes(t.condition)) {
646
647
  errors.push({
647
648
  path: `${tPath}.condition`,
648
- message: `transition condition must be one of: ${validConditions.join(", ")}`,
649
+ message: `transition condition must be one of: ${TRANSITION_CONDITION_VALUES.join(", ")}`,
649
650
  });
650
651
  }
651
652
  }
@@ -665,11 +666,10 @@ function validateWorkflow(workflow, roleNames, pathPrefix) {
665
666
  message: `retry_from references unknown step '${rp.retry_from}'`,
666
667
  });
667
668
  }
668
- const validBackoff = ["none", "linear", "exponential"];
669
- if (rp.backoff && !validBackoff.includes(rp.backoff)) {
669
+ if (rp.backoff && !RETRY_BACKOFF_VALUES.includes(rp.backoff)) {
670
670
  errors.push({
671
671
  path: `${rpPath}.backoff`,
672
- message: `backoff must be one of: ${validBackoff.join(", ")}`,
672
+ message: `backoff must be one of: ${RETRY_BACKOFF_VALUES.join(", ")}`,
673
673
  });
674
674
  }
675
675
  }
@@ -54,12 +54,11 @@ function validateControllerPolicy(policy, path, errors) {
54
54
  errors.push({ path: `${path}.progress_provenance_failure`, message: "must be a non-empty string" });
55
55
  }
56
56
  }
57
- function validateControllerWorkflowRoles(workflow, requiredRoleKeys, roleMap, path, errors) {
57
+ function validateControllerWorkflowRoles(workflow, roleEntries, path, errors) {
58
58
  if (!workflow)
59
59
  return;
60
60
  const workflowRoles = new Set(workflow.steps.map((step) => step.role));
61
- for (const roleKey of requiredRoleKeys) {
62
- const roleName = roleMap[roleKey];
61
+ for (const [roleKey, roleName] of roleEntries) {
63
62
  if (typeof roleName !== "string" || !roleName)
64
63
  continue;
65
64
  if (!workflowRoles.has(roleName)) {
@@ -91,32 +90,40 @@ export function validateController(controller, roleNames, workflows, path) {
91
90
  if (!Number.isInteger(controller.max_rounds) || controller.max_rounds < 1 || controller.max_rounds > 20) {
92
91
  errors.push({ path: `${path}.max_rounds`, message: "max_rounds must be an integer in 1..20" });
93
92
  }
94
- const requiredStringFields = [
95
- "progress_artifact_path",
96
- "diagnosis_workflow",
97
- "fix_workflow",
98
- "diagnosis_artifact_path",
99
- "diagnosis_review_artifact_path",
100
- "review_artifact_path",
101
- ];
93
+ const requiredStringFields = kindMetadata?.kind === "sequential"
94
+ ? ["progress_artifact_path", "workflow"]
95
+ : [
96
+ "progress_artifact_path",
97
+ "diagnosis_workflow",
98
+ "fix_workflow",
99
+ "diagnosis_artifact_path",
100
+ "diagnosis_review_artifact_path",
101
+ "review_artifact_path",
102
+ ];
102
103
  for (const field of requiredStringFields) {
103
104
  if (typeof controller[field] !== "string" || !controller[field]) {
104
105
  errors.push({ path: `${path}.${field}`, message: "must be a non-empty string" });
105
106
  }
106
107
  }
107
- const artifactPathFields = [
108
- "progress_artifact_path",
109
- "diagnosis_artifact_path",
110
- "diagnosis_review_artifact_path",
111
- "review_artifact_path",
112
- ];
108
+ const artifactPathFields = kindMetadata?.kind === "sequential"
109
+ ? ["progress_artifact_path"]
110
+ : [
111
+ "progress_artifact_path",
112
+ "diagnosis_artifact_path",
113
+ "diagnosis_review_artifact_path",
114
+ "review_artifact_path",
115
+ ];
113
116
  for (const field of artifactPathFields) {
114
117
  if (typeof controller[field] === "string" && !isSafeControllerArtifactPath(controller[field])) {
115
118
  errors.push({ path: `${path}.${field}`, message: "must be a relative .dna/ artifact template containing $ARGUMENTS without glob, brace, absolute, or parent traversal syntax" });
116
119
  }
117
120
  }
121
+ const workflow = controller.workflow ? workflows[controller.workflow] : undefined;
118
122
  const diagnosisWorkflow = controller.diagnosis_workflow ? workflows[controller.diagnosis_workflow] : undefined;
119
123
  const fixWorkflow = controller.fix_workflow ? workflows[controller.fix_workflow] : undefined;
124
+ if (controller.workflow && !workflow) {
125
+ errors.push({ path: `${path}.workflow`, message: `references unknown workflow '${controller.workflow}'` });
126
+ }
120
127
  if (controller.diagnosis_workflow && !diagnosisWorkflow) {
121
128
  errors.push({ path: `${path}.diagnosis_workflow`, message: `references unknown workflow '${controller.diagnosis_workflow}'` });
122
129
  }
@@ -128,8 +135,14 @@ export function validateController(controller, roleNames, workflows, path) {
128
135
  if (!roleMap || typeof roleMap !== "object") {
129
136
  errors.push({ path: `${path}.roles`, message: "controller requires roles" });
130
137
  }
138
+ else if (kindMetadata?.kind === "sequential" && Object.keys(roleMap).length === 0) {
139
+ errors.push({ path: `${path}.roles`, message: "sequential controller requires at least one workflow role" });
140
+ }
131
141
  else {
132
- for (const roleKey of requiredRoles) {
142
+ const roleKeysToValidate = kindMetadata?.kind === "sequential"
143
+ ? Object.keys(roleMap)
144
+ : requiredRoles;
145
+ for (const roleKey of roleKeysToValidate) {
133
146
  const roleName = roleMap[roleKey];
134
147
  if (typeof roleName !== "string" || !roleName) {
135
148
  errors.push({ path: `${path}.roles.${roleKey}`, message: "must be a non-empty role name" });
@@ -143,8 +156,13 @@ export function validateController(controller, roleNames, workflows, path) {
143
156
  }
144
157
  }
145
158
  if (roleMap && typeof roleMap === "object") {
146
- validateControllerWorkflowRoles(diagnosisWorkflow, kindMetadata?.diagnosisRoleKeys ?? ["analyzer", "analysis_reviewer"], roleMap, `${path}.diagnosis_workflow`, errors);
147
- validateControllerWorkflowRoles(fixWorkflow, kindMetadata?.fixRoleKeys ?? ["surgeon", "fix_reviewer", "test_runner"], roleMap, `${path}.fix_workflow`, errors);
159
+ if (kindMetadata?.kind === "sequential") {
160
+ validateControllerWorkflowRoles(workflow, Object.entries(roleMap), `${path}.workflow`, errors);
161
+ }
162
+ else {
163
+ validateControllerWorkflowRoles(diagnosisWorkflow, (kindMetadata?.diagnosisRoleKeys ?? ["analyzer", "analysis_reviewer"]).map((roleKey) => [roleKey, roleMap[roleKey]]), `${path}.diagnosis_workflow`, errors);
164
+ validateControllerWorkflowRoles(fixWorkflow, (kindMetadata?.fixRoleKeys ?? ["surgeon", "fix_reviewer", "test_runner"]).map((roleKey) => [roleKey, roleMap[roleKey]]), `${path}.fix_workflow`, errors);
165
+ }
148
166
  }
149
167
  if (controller.stop_format !== "configured_stop_report" && controller.stop_format !== "zh_three_part") {
150
168
  errors.push({ path: `${path}.stop_format`, message: "stop_format must be 'configured_stop_report' or legacy 'zh_three_part'" });
@@ -0,0 +1,29 @@
1
+ export interface AuthoringFieldConstraint {
2
+ name: string;
3
+ required: boolean;
4
+ type: string;
5
+ allowed_values?: readonly string[];
6
+ notes?: string;
7
+ }
8
+ export declare const WORKFLOW_AUTHORING_SCHEMA: {
9
+ readonly source: "src/schema/workflow-authoring-contract.ts; field maps are exhaustive against src/schema/types.ts";
10
+ readonly workflow: readonly AuthoringFieldConstraint[];
11
+ readonly step: readonly AuthoringFieldConstraint[];
12
+ readonly role: readonly AuthoringFieldConstraint[];
13
+ readonly tool_permissions: readonly AuthoringFieldConstraint[];
14
+ readonly scope: readonly AuthoringFieldConstraint[];
15
+ readonly handoff_artifact: {
16
+ readonly fields: readonly AuthoringFieldConstraint[];
17
+ readonly type_values: readonly ["file", "directory", "test_result", "git_commit", "summary", "state"];
18
+ readonly required_fields: string[];
19
+ readonly optional_fields: string[];
20
+ };
21
+ readonly checkpoint: {
22
+ readonly fields: readonly AuthoringFieldConstraint[];
23
+ readonly required_fields: string[];
24
+ readonly optional_fields: string[];
25
+ readonly action_values: readonly ["block", "warn"];
26
+ };
27
+ readonly transition: readonly AuthoringFieldConstraint[];
28
+ readonly retry_policy: readonly AuthoringFieldConstraint[];
29
+ };
@@ -0,0 +1,109 @@
1
+ import { CHECKPOINT_ACTION_VALUES, HANDOFF_TYPE_VALUES, RETRY_BACKOFF_VALUES, TRANSITION_CONDITION_VALUES, WORKFLOW_HANDOFF_EXHAUSTED_VALUES, WORKFLOW_ISOLATION_VALUES, WORKFLOW_MERGE_STRATEGY_VALUES, WORKFLOW_STEP_FAILURE_VALUES, } from "./types.js";
2
+ function fieldsFrom(definitions) {
3
+ return Object.entries(definitions).map(([name, definition]) => ({
4
+ name,
5
+ ...definition,
6
+ }));
7
+ }
8
+ const WORKFLOW_FIELDS = {
9
+ name: { required: true, type: "string", notes: "Human-readable workflow name." },
10
+ description: { required: false, type: "string" },
11
+ steps: { required: true, type: "WorkflowStepDef[]", notes: "At least one step; ids must be unique within the workflow." },
12
+ transitions: { required: false, type: "TransitionDef[]" },
13
+ retry_policy: { required: false, type: "RetryPolicy" },
14
+ max_rounds: { required: false, type: "number", notes: "Alias for retry rounds when retry_policy is omitted." },
15
+ produces: { required: false, type: "HandoffArtifact[]" },
16
+ consumes: { required: false, type: "HandoffArtifact[]" },
17
+ default_isolation: { required: false, type: "WorkflowIsolation", allowed_values: WORKFLOW_ISOLATION_VALUES },
18
+ merge_strategy: { required: false, type: "WorkflowMergeStrategy", allowed_values: WORKFLOW_MERGE_STRATEGY_VALUES },
19
+ };
20
+ const STEP_FIELDS = {
21
+ id: { required: true, type: "string", notes: "Stable safe identifier, unique within the workflow." },
22
+ role: { required: true, type: "string", notes: "Must reference a declared role in the same asset." },
23
+ description: { required: false, type: "string" },
24
+ depends_on: { required: false, type: "string[]" },
25
+ optional: { required: false, type: "boolean" },
26
+ run_if: { required: false, type: "string" },
27
+ prompt: { required: false, type: "string" },
28
+ completion: { required: false, type: "CompletionCheck[]" },
29
+ checkpoints: { required: false, type: "StepCheckpoint[]" },
30
+ handoff: { required: false, type: "StepHandoff" },
31
+ isolation: { required: false, type: "WorkflowIsolation", allowed_values: WORKFLOW_ISOLATION_VALUES },
32
+ enforce: { required: false, type: "step-level enforcement object" },
33
+ max_attempts: { required: false, type: "number" },
34
+ on_fail: { required: false, type: "WorkflowStepFailureAction", allowed_values: WORKFLOW_STEP_FAILURE_VALUES },
35
+ handoff_to: { required: false, type: "string" },
36
+ max_handoffs: { required: false, type: "number" },
37
+ on_handoff_exhausted: { required: false, type: "WorkflowHandoffExhaustedAction", allowed_values: WORKFLOW_HANDOFF_EXHAUSTED_VALUES },
38
+ blocked_items_path: { required: false, type: "string" },
39
+ };
40
+ const ROLE_FIELDS = {
41
+ description: { required: true, type: "string" },
42
+ tool_permissions: { required: false, type: "ToolPermissions" },
43
+ scope: { required: false, type: "ScopeDef" },
44
+ output_schema: { required: false, type: "string|OutputSchema" },
45
+ model: { required: false, type: "string", notes: "Harness hint only; use human for an explicit user-owned gate or interactive for a main-session external-agent step." },
46
+ activates_genes: { required: false, type: "string[]" },
47
+ suppresses_genes: { required: false, type: "string[]" },
48
+ post_checks: { required: false, type: "string[]" },
49
+ instructions: { required: false, type: "string[]" },
50
+ success_criteria: { required: false, type: "string[]" },
51
+ failure_modes: { required: false, type: "string[]" },
52
+ };
53
+ const TOOL_PERMISSION_FIELDS = {
54
+ allow: { required: false, type: "string[]" },
55
+ deny: { required: false, type: "string[]" },
56
+ };
57
+ const SCOPE_FIELDS = {
58
+ read: { required: false, type: "string[]" },
59
+ write: { required: false, type: "string[]" },
60
+ };
61
+ const HANDOFF_FIELDS = {
62
+ type: { required: true, type: "HandoffType", allowed_values: HANDOFF_TYPE_VALUES },
63
+ path: { required: false, type: "string" },
64
+ name: { required: false, type: "string" },
65
+ artifact_id: { required: false, type: "string" },
66
+ from: { required: false, type: "string" },
67
+ required: { required: false, type: "boolean", notes: "Defaults to true." },
68
+ description: { required: true, type: "string" },
69
+ };
70
+ const CHECKPOINT_FIELDS = {
71
+ assert: { required: true, type: "string" },
72
+ command: { required: false, type: "string", notes: "Required for custom assertions that are not built-ins." },
73
+ message: { required: true, type: "string" },
74
+ action: { required: false, type: "CheckpointAction", allowed_values: CHECKPOINT_ACTION_VALUES, notes: "Defaults to block." },
75
+ };
76
+ const TRANSITION_FIELDS = {
77
+ from: { required: true, type: "string" },
78
+ to: { required: true, type: "string" },
79
+ condition: { required: true, type: "TransitionCondition", allowed_values: TRANSITION_CONDITION_VALUES },
80
+ };
81
+ const RETRY_POLICY_FIELDS = {
82
+ max_retries: { required: true, type: "number", notes: "Must be zero or greater." },
83
+ retry_from: { required: false, type: "string", notes: "Must reference an existing step when present." },
84
+ backoff: { required: false, type: "RetryBackoff", allowed_values: RETRY_BACKOFF_VALUES },
85
+ };
86
+ const handoffFields = fieldsFrom(HANDOFF_FIELDS);
87
+ const checkpointFields = fieldsFrom(CHECKPOINT_FIELDS);
88
+ export const WORKFLOW_AUTHORING_SCHEMA = {
89
+ source: "src/schema/workflow-authoring-contract.ts; field maps are exhaustive against src/schema/types.ts",
90
+ workflow: fieldsFrom(WORKFLOW_FIELDS),
91
+ step: fieldsFrom(STEP_FIELDS),
92
+ role: fieldsFrom(ROLE_FIELDS),
93
+ tool_permissions: fieldsFrom(TOOL_PERMISSION_FIELDS),
94
+ scope: fieldsFrom(SCOPE_FIELDS),
95
+ handoff_artifact: {
96
+ fields: handoffFields,
97
+ type_values: HANDOFF_TYPE_VALUES,
98
+ required_fields: handoffFields.filter((field) => field.required).map((field) => field.name),
99
+ optional_fields: handoffFields.filter((field) => !field.required).map((field) => field.name),
100
+ },
101
+ checkpoint: {
102
+ fields: checkpointFields,
103
+ required_fields: checkpointFields.filter((field) => field.required).map((field) => field.name),
104
+ optional_fields: checkpointFields.filter((field) => !field.required).map((field) => field.name),
105
+ action_values: CHECKPOINT_ACTION_VALUES,
106
+ },
107
+ transition: fieldsFrom(TRANSITION_FIELDS),
108
+ retry_policy: fieldsFrom(RETRY_POLICY_FIELDS),
109
+ };
@@ -224,6 +224,24 @@ function parseScalar(s) {
224
224
  // Inline empty object: {}
225
225
  if (s === "{}")
226
226
  return {};
227
+ // Inline object: { key: value, other: "quoted" }
228
+ if (s.startsWith("{") && s.endsWith("}")) {
229
+ const inner = s.slice(1, -1).trim();
230
+ if (inner === "")
231
+ return {};
232
+ const result = {};
233
+ for (const entry of splitInlineArray(inner)) {
234
+ const colonIdx = findKeyColon(entry);
235
+ if (colonIdx <= 0)
236
+ return s;
237
+ const key = entry.slice(0, colonIdx).trim().replace(/^["']|["']$/g, "");
238
+ const value = entry.slice(colonIdx + 1).trim();
239
+ if (!key)
240
+ return s;
241
+ result[key] = parseScalar(value);
242
+ }
243
+ return result;
244
+ }
227
245
  // Quoted string
228
246
  if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
229
247
  return s.slice(1, -1).replace(/\\"/g, '"').replace(/\\'/g, "'").replace(/\\\\/g, "\\");
@@ -5,6 +5,25 @@
5
5
  version: "0.1.0"
6
6
  id: template_api_backend
7
7
  name: API Backend Standards
8
+ purpose: Provide a backend API baseline for security, quality, database safety, and reviewable implementation.
9
+ maturity: draft
10
+ fit:
11
+ - Node.js, Python, or service API projects that need a local governance baseline.
12
+ - Teams starting from API standards before authoring a richer workflow asset.
13
+ not_for:
14
+ - Replacing endpoint-specific design, tests, or threat modeling.
15
+ - Online execution, cloud deployment, or database mutation by the template itself.
16
+ inputs:
17
+ - API task scope
18
+ - endpoint and data model context
19
+ - security and database constraints
20
+ outputs:
21
+ - backend development guardrails
22
+ - API quality review notes
23
+ - database safety reminders
24
+ lineage:
25
+ source: built-in backend standards template
26
+ reference: src/templates/api-backend.dna.yaml
8
27
  type: project
9
28
  namespace: be
10
29
 
@@ -6,6 +6,25 @@
6
6
  version: "0.1.0"
7
7
  id: template_brainstorming_first
8
8
  name: Brainstorming First
9
+ purpose: Force design, Socratic refinement, and task decomposition before implementation starts.
10
+ maturity: draft
11
+ fit:
12
+ - Early-stage tasks where requirements, tradeoffs, or implementation chunks are unclear.
13
+ - Planning work that should produce small verifiable steps before coding.
14
+ not_for:
15
+ - Already approved implementation slices with clear acceptance criteria.
16
+ - Letting brainstorming replace tests, review, or delivery evidence.
17
+ inputs:
18
+ - raw idea or task request
19
+ - known constraints and open questions
20
+ - desired outcome or decision point
21
+ outputs:
22
+ - refined requirements
23
+ - decomposed task plan
24
+ - implementation readiness notes
25
+ lineage:
26
+ source: brainstorming and writing-plans workflow shape
27
+ reference: src/templates/brainstorming-first.dna.yaml
9
28
  type: project
10
29
  namespace: bs
11
30
 
@@ -1,6 +1,25 @@
1
1
  version: "0.1.0"
2
2
  id: template_code_cleanup
3
3
  name: Code Cleanup (Regression-Safe)
4
+ purpose: Clean code in small behavior-preserving passes with tests between each smell-focused edit.
5
+ maturity: reviewed
6
+ fit:
7
+ - Refactors or cleanup where existing behavior must stay stable.
8
+ - Reducing dead code, duplication, naming issues, or local complexity under test coverage.
9
+ not_for:
10
+ - Mixing feature work into cleanup.
11
+ - Large unverified rewrites or cleanup without regression checks.
12
+ inputs:
13
+ - cleanup scope
14
+ - current tests or behavior evidence
15
+ - identified smell category
16
+ outputs:
17
+ - scoped cleanup diff
18
+ - regression verification evidence
19
+ - remaining cleanup risk notes
20
+ lineage:
21
+ source: built-in regression-safe cleanup workflow
22
+ reference: docs/archive/fix-notes/refactoring-workflow-principles.md
4
23
  type: project
5
24
  namespace: cc
6
25
 
@@ -5,6 +5,24 @@
5
5
  version: "0.1.0"
6
6
  id: template_code_review_pipeline
7
7
  name: Code Review Pipeline
8
+ purpose: Run structured implementation review with actionable findings, tests, and follow-up fixes before merge or adoption.
9
+ maturity: reviewed
10
+ fit:
11
+ - Pull request or patch review that needs explicit PASS/FAIL evidence.
12
+ - Separating reviewer feedback from implementation fixes.
13
+ not_for:
14
+ - Rubber-stamp approval.
15
+ - Replacing targeted tests or security checks with prose.
16
+ inputs:
17
+ - changed files
18
+ - task specification
19
+ - test results
20
+ outputs:
21
+ - review findings with code references
22
+ - required fixes
23
+ - re-review verdict
24
+ lineage:
25
+ source: requesting-code-review and receiving-code-review workflow shape
8
26
  type: project
9
27
  namespace: crp
10
28