@ktpartners/dgs-platform 3.0.4 → 3.3.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 (115) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +8 -1
  3. package/agents/dgs-executor.md +124 -3
  4. package/agents/dgs-idea-researcher.md +447 -0
  5. package/agents/dgs-plan-checker.md +32 -0
  6. package/agents/dgs-planner.md +41 -8
  7. package/bin/install.js +44 -0
  8. package/commands/dgs/audit-milestone.md +2 -1
  9. package/commands/dgs/diff-report.md +124 -0
  10. package/commands/dgs/new-project.md +8 -21
  11. package/commands/dgs/package-scan.md +43 -0
  12. package/commands/dgs/research-idea.md +1 -0
  13. package/commands/dgs/switch-project.md +13 -0
  14. package/deliver-great-systems/bin/dgs-tools.cjs +120 -5
  15. package/deliver-great-systems/bin/lib/audit-tolerance.cjs +77 -0
  16. package/deliver-great-systems/bin/lib/audit-tolerance.test.cjs +101 -0
  17. package/deliver-great-systems/bin/lib/commands.cjs +311 -16
  18. package/deliver-great-systems/bin/lib/commands.test.cjs +115 -0
  19. package/deliver-great-systems/bin/lib/commit-verify.test.cjs +236 -0
  20. package/deliver-great-systems/bin/lib/config.cjs +41 -0
  21. package/deliver-great-systems/bin/lib/config.test.cjs +309 -0
  22. package/deliver-great-systems/bin/lib/core.cjs +7 -3
  23. package/deliver-great-systems/bin/lib/core.test.cjs +79 -1
  24. package/deliver-great-systems/bin/lib/fast-routing.cjs +199 -0
  25. package/deliver-great-systems/bin/lib/fast-routing.test.cjs +108 -0
  26. package/deliver-great-systems/bin/lib/final-commit-precondition.test.cjs +87 -0
  27. package/deliver-great-systems/bin/lib/fixtures/package-scan/bundler-audit-gemfile.json +21 -0
  28. package/deliver-great-systems/bin/lib/fixtures/package-scan/gate-parity-expected.md +186 -0
  29. package/deliver-great-systems/bin/lib/fixtures/package-scan/gate-parity-runresult.json +235 -0
  30. package/deliver-great-systems/bin/lib/fixtures/package-scan/govulncheck-import.json +3 -0
  31. package/deliver-great-systems/bin/lib/fixtures/package-scan/npm-audit-v10.json +37 -0
  32. package/deliver-great-systems/bin/lib/fixtures/package-scan/osv-clean.json +3 -0
  33. package/deliver-great-systems/bin/lib/fixtures/package-scan/osv-vulns.json +77 -0
  34. package/deliver-great-systems/bin/lib/fixtures/package-scan/pip-audit-requirements.json +28 -0
  35. package/deliver-great-systems/bin/lib/fixtures/package-scan/snyk-lodash.json +30 -0
  36. package/deliver-great-systems/bin/lib/fixtures/package-scan/snyk-workspaces.json +55 -0
  37. package/deliver-great-systems/bin/lib/frontmatter.cjs +1 -1
  38. package/deliver-great-systems/bin/lib/governance.cjs +211 -0
  39. package/deliver-great-systems/bin/lib/governance.test.cjs +339 -0
  40. package/deliver-great-systems/bin/lib/health-untracked-phase.test.cjs +269 -0
  41. package/deliver-great-systems/bin/lib/init.cjs +56 -27
  42. package/deliver-great-systems/bin/lib/init.test.cjs +212 -5
  43. package/deliver-great-systems/bin/lib/jobs.cjs +7 -4
  44. package/deliver-great-systems/bin/lib/milestone.cjs +101 -3
  45. package/deliver-great-systems/bin/lib/milestone.test.cjs +203 -0
  46. package/deliver-great-systems/bin/lib/package-adapters.cjs +530 -0
  47. package/deliver-great-systems/bin/lib/package-adapters.test.cjs +618 -0
  48. package/deliver-great-systems/bin/lib/package-ecosystems.cjs +350 -0
  49. package/deliver-great-systems/bin/lib/package-ecosystems.test.cjs +348 -0
  50. package/deliver-great-systems/bin/lib/package-runner.cjs +199 -0
  51. package/deliver-great-systems/bin/lib/package-runner.test.cjs +198 -0
  52. package/deliver-great-systems/bin/lib/package-scan-provenance.cjs +56 -0
  53. package/deliver-great-systems/bin/lib/package-scan-provenance.test.cjs +103 -0
  54. package/deliver-great-systems/bin/lib/package-scan-report.cjs +1140 -0
  55. package/deliver-great-systems/bin/lib/package-scan-report.test.cjs +1963 -0
  56. package/deliver-great-systems/bin/lib/package-scan-skill.cjs +96 -0
  57. package/deliver-great-systems/bin/lib/package-scan-skill.test.cjs +136 -0
  58. package/deliver-great-systems/bin/lib/package-scan.cjs +919 -0
  59. package/deliver-great-systems/bin/lib/package-scan.test.cjs +2147 -0
  60. package/deliver-great-systems/bin/lib/phase.cjs +18 -1
  61. package/deliver-great-systems/bin/lib/plan-number-validity.test.cjs +48 -0
  62. package/deliver-great-systems/bin/lib/projects.cjs +38 -3
  63. package/deliver-great-systems/bin/lib/projects.test.cjs +112 -2
  64. package/deliver-great-systems/bin/lib/quick.cjs +178 -23
  65. package/deliver-great-systems/bin/lib/quick.test.cjs +138 -4
  66. package/deliver-great-systems/bin/lib/repos.cjs +12 -12
  67. package/deliver-great-systems/bin/lib/review.cjs +1821 -0
  68. package/deliver-great-systems/bin/lib/state.cjs +7 -3
  69. package/deliver-great-systems/bin/lib/summary-frontmatter.cjs +54 -0
  70. package/deliver-great-systems/bin/lib/summary-frontmatter.test.cjs +78 -0
  71. package/deliver-great-systems/bin/lib/sweep-scope.test.cjs +263 -0
  72. package/deliver-great-systems/bin/lib/verify.cjs +118 -6
  73. package/deliver-great-systems/bin/lib/verify.test.cjs +82 -0
  74. package/deliver-great-systems/bin/lib/wave-0-template-rename.test.cjs +40 -0
  75. package/deliver-great-systems/bin/lib/worktrees.cjs +27 -1
  76. package/deliver-great-systems/bin/lib/worktrees.test.cjs +76 -0
  77. package/deliver-great-systems/references/agent-step-reliability.md +60 -0
  78. package/deliver-great-systems/references/conflict-resolution.md +4 -0
  79. package/deliver-great-systems/references/context-tiers.md +4 -0
  80. package/deliver-great-systems/references/package-scan-config.md +151 -0
  81. package/deliver-great-systems/references/questioning.md +0 -30
  82. package/deliver-great-systems/references/spec-review-loop.md +1 -2
  83. package/deliver-great-systems/references/workflow-conventions.md +29 -0
  84. package/deliver-great-systems/skills/dgs-tests/package-scan.md +44 -0
  85. package/deliver-great-systems/templates/REVIEW.md +35 -0
  86. package/deliver-great-systems/templates/VALIDATION.md +1 -1
  87. package/deliver-great-systems/templates/claude-md.md +11 -0
  88. package/deliver-great-systems/templates/package-scan-report.md +108 -0
  89. package/deliver-great-systems/templates/project.md +6 -170
  90. package/deliver-great-systems/templates/summary.md +3 -1
  91. package/deliver-great-systems/workflows/add-phase.md +5 -0
  92. package/deliver-great-systems/workflows/audit-milestone.md +66 -10
  93. package/deliver-great-systems/workflows/cancel-job.md +1 -1
  94. package/deliver-great-systems/workflows/codereview.md +103 -9
  95. package/deliver-great-systems/workflows/complete-milestone.md +26 -7
  96. package/deliver-great-systems/workflows/complete-quick.md +40 -2
  97. package/deliver-great-systems/workflows/discuss-phase.md +3 -2
  98. package/deliver-great-systems/workflows/execute-phase.md +89 -2
  99. package/deliver-great-systems/workflows/execute-plan.md +10 -1
  100. package/deliver-great-systems/workflows/help.md +51 -18
  101. package/deliver-great-systems/workflows/import-spec.md +65 -7
  102. package/deliver-great-systems/workflows/init-product.md +46 -152
  103. package/deliver-great-systems/workflows/new-milestone.md +115 -14
  104. package/deliver-great-systems/workflows/new-project.md +60 -331
  105. package/deliver-great-systems/workflows/package-scan.md +59 -0
  106. package/deliver-great-systems/workflows/plan-phase.md +79 -1
  107. package/deliver-great-systems/workflows/quick-complete.md +40 -2
  108. package/deliver-great-systems/workflows/quick.md +183 -10
  109. package/deliver-great-systems/workflows/research-idea.md +80 -142
  110. package/deliver-great-systems/workflows/run-job.md +21 -35
  111. package/deliver-great-systems/workflows/settings.md +13 -77
  112. package/deliver-great-systems/workflows/write-spec.md +9 -11
  113. package/hooks/dist/dgs-enforce-discipline.js +196 -0
  114. package/package.json +1 -1
  115. package/scripts/build-hooks.js +1 -0
@@ -1,5 +1,5 @@
1
1
  <purpose>
2
- Execute a milestone build job end-to-end. Reads the job file, loops through pending steps, spawns an isolated subagent per step, updates the job file in real-time, handles failures with immediate halt, manages dynamic gap-fix cycles at both milestone level (GapFixCycle, max 3) and phase level (PhaseFixCycle, max 2), and moves completed jobs to the completed/ directory. Supports --dry-run mode for step preview without execution. Auto-generates job summaries on completion and failure.
2
+ Execute a milestone build job end-to-end. Reads the job file, loops through pending steps, spawns an isolated subagent per step, updates the job file in real-time, handles failures with immediate halt, manages dynamic gap-fix cycles at both milestone level (GapFixCycle, max 3) and phase level (PhaseFixCycle, max 2), and marks completed jobs with status: completed. Supports --dry-run mode for step preview without execution. Auto-generates job summaries on completion and failure.
3
3
 
4
4
  The orchestrator stays lean: it reads only the job file and MILESTONE-AUDIT.md (plus phase UAT status via CLI for phase-level audits). All actual work is delegated to subagents via Task tool. Each subagent gets a fresh context window with no shared state beyond what is on disk.
5
5
  </purpose>
@@ -106,7 +106,7 @@ Parse the JSON result.
106
106
  Error: No job found for version {VERSION}. Create one with /dgs:create-milestone-job {VERSION}
107
107
  ```
108
108
 
109
- **If found in `completed/` directory:**
109
+ **If found.status is 'completed':**
110
110
  ```
111
111
  Error: Job {VERSION} is already completed.
112
112
  ```
@@ -117,21 +117,14 @@ Store `JOB_PATH` from the result for all subsequent operations.
117
117
  <step name="move_to_in_progress">
118
118
  Transition the job to in-progress state if needed.
119
119
 
120
- **If job is in `pending/`:**
120
+ **If found.status is 'pending':**
121
121
 
122
- 1. Move the file to `in-progress/`:
122
+ 1. Set the job status to in-progress (updates both frontmatter and header):
123
123
  ```bash
124
- node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs jobs move "$JOB_PATH" "${jobs_root}/in-progress"
124
+ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs jobs set-status "$VERSION" --status in-progress
125
125
  ```
126
126
 
127
- 2. Update `JOB_PATH` to reflect the new location under `in-progress/`.
128
-
129
- 3. Update the header Status field (using the updated `$JOB_PATH`):
130
- ```bash
131
- node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs jobs update-header "$JOB_PATH" Status in-progress
132
- ```
133
-
134
- **If already in `in-progress/`:** Skip the move. The job is being resumed.
127
+ **If found.status is already 'in-progress':** Skip. The job is being resumed.
135
128
 
136
129
  **Record starting commit SHAs:**
137
130
 
@@ -332,13 +325,13 @@ Loop through steps starting from `nextStepIndex`.
332
325
  ```bash
333
326
  SUMMARY=$(node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs jobs generate-summary "$VERSION")
334
327
  ```
335
- Parse the result. If `found: true`, write the `content` field to `${jobs_root}/in-progress/job-{version}-SUMMARY.md` using the Write tool (job stays in in-progress/ on failure).
336
- Display: `Job summary written to ${jobs_root}/in-progress/job-{version}-SUMMARY.md`
328
+ Parse the result. If `found: true`, write the `content` field to `${jobs_root}/job-{version}-SUMMARY.md` using the Write tool (job stays in place on failure -- status is tracked in frontmatter).
329
+ Display: `Job summary written to ${jobs_root}/job-{version}-SUMMARY.md`
337
330
 
338
331
  **Commit and push failure summary:**
339
332
 
340
333
  ```bash
341
- node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(job): ${VERSION} failure summary" --files "${jobs_root}/in-progress/job-${VERSION}-SUMMARY.md" --push
334
+ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(job): ${VERSION} failure summary" --files "${jobs_root}/job-${VERSION}-SUMMARY.md" --push
342
335
  ```
343
336
 
344
337
  **HALT immediately.** Do not proceed to the next step.
@@ -536,39 +529,32 @@ After an `audit-phase` step completes successfully, check the phase audit outcom
536
529
  <step name="complete_job">
537
530
  When all steps are completed (`nextStepIndex` is null after the loop):
538
531
 
539
- 1. **Update header Status to `completed`:**
532
+ 1. **Set job status to `completed`** (updates both frontmatter and header):
540
533
  ```bash
541
- node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs jobs update-header "$JOB_PATH" Status completed
534
+ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs jobs set-status "$VERSION" --status completed
542
535
  ```
543
536
 
544
- 2. **Move job to `completed/`:**
545
- ```bash
546
- node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs jobs move "$JOB_PATH" "${jobs_root}/completed"
547
- ```
548
-
549
- Update `JOB_PATH` to reflect the new location under `completed/`.
550
-
551
537
  **Commit and push job status:**
552
538
 
553
539
  ```bash
554
- git add -A "$(dirname "$JOB_PATH")/../"
540
+ git add -A "$(dirname "$JOB_PATH")/"
555
541
  node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(job): ${VERSION} completed" --push
556
542
  ```
557
543
 
558
- 3. **Generate job summary:**
544
+ 2. **Generate job summary:**
559
545
  ```bash
560
546
  SUMMARY=$(node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs jobs generate-summary "$VERSION")
561
547
  ```
562
- Parse the result. If `found: true`, write the `content` field to `${jobs_root}/completed/job-{version}-SUMMARY.md` using the Write tool.
563
- Display: `Job summary written to ${jobs_root}/completed/job-{version}-SUMMARY.md`
548
+ Parse the result. If `found: true`, write the `content` field to `${jobs_root}/job-{version}-SUMMARY.md` using the Write tool.
549
+ Display: `Job summary written to ${jobs_root}/job-{version}-SUMMARY.md`
564
550
 
565
551
  **Commit and push completion summary:**
566
552
 
567
553
  ```bash
568
- node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(job): ${VERSION} completion summary" --files "${jobs_root}/completed/job-${VERSION}-SUMMARY.md" --push
554
+ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(job): ${VERSION} completion summary" --files "${jobs_root}/job-${VERSION}-SUMMARY.md" --push
569
555
  ```
570
556
 
571
- 4. **Post-workflow push (sync_after):**
557
+ 3. **Post-workflow push (sync_after):**
572
558
 
573
559
  Follow the sync-hooks post-workflow push pattern with `WORKFLOW_NAME = "run-job"`:
574
560
 
@@ -582,7 +568,7 @@ When all steps are completed (`nextStepIndex` is null after the loop):
582
568
 
583
569
  Display aggregated push summary including any accumulated `SYNC_WARNINGS` from mid-workflow pushes.
584
570
 
585
- 5. **Display completion banner:**
571
+ 4. **Display completion banner:**
586
572
 
587
573
  If `AUTO_RESOLVE_COUNT` is 0:
588
574
  ```
@@ -617,11 +603,11 @@ The orchestrator MUST stay lean per EXEC-07:
617
603
  - [ ] Milestone audit gap-fix cycle auto-approved with 3-cycle safety limit
618
604
  - [ ] Phase audit gap-fix cycle auto-approved with 2-cycle safety limit
619
605
  - [ ] PhaseFixCycle counter resets on plan-phase/map-codebase steps
620
- - [ ] Completed jobs moved to completed/ directory with banner
606
+ - [ ] Completed jobs marked with status: completed with banner
621
607
  - [ ] Orchestrator reads only job file and MILESTONE-AUDIT.md (phase UAT via CLI)
622
608
  - [ ] --dry-run flag displays step preview without executing
623
- - [ ] Job summary auto-generated on completion (written to completed/)
624
- - [ ] Job summary auto-generated on failure (written to in-progress/)
609
+ - [ ] Job summary auto-generated on completion (written to ${jobs_root}/)
610
+ - [ ] Job summary auto-generated on failure (written to ${jobs_root}/)
625
611
  - [ ] Pre-workflow pull executed before job steps start (sync_before)
626
612
  - [ ] Mid-workflow push after phase-completing steps (silent, no prompt)
627
613
  - [ ] Post-workflow push after job completion (sync_after)
@@ -45,8 +45,8 @@ Parse current values (default to `true` if not present):
45
45
  - `workflow.verifier` — spawn verifier during execute-phase
46
46
  - `workflow.nyquist_validation` — validation architecture research during plan-phase (default: true if absent)
47
47
  - `workflow.codereview` — spawn code reviewer after plan execution (default: false if absent)
48
+ - `workflow.four_eyes` — four-eyes completion governance mode (default: "off" if absent)
48
49
  - `model_profile` — which model each agent uses (default: `balanced`)
49
- - `git.branching_strategy` — branching approach (default: `"none"`)
50
50
  - `git.base_branch` — integration target branch for code repos (default: `"main"`)
51
51
  - `git.sync_push` — remote sync push mode (default: "off" if absent for existing installs)
52
52
  - `git.sync_pull` — remote sync pull mode (default: "off" if absent for existing installs)
@@ -59,62 +59,6 @@ CLAUDE_MD_HAS_DGS=$(grep -l 'DGS:BEGIN' ./CLAUDE.md 2>/dev/null && echo "true" |
59
59
  ```
60
60
  </step>
61
61
 
62
- <step name="detect_old_templates">
63
- After loading current config, check if the branch templates use old defaults without `{project}`:
64
-
65
- ```bash
66
- CURRENT_PHASE_TPL=$(node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" config-get git.phase_branch_template --raw 2>/dev/null)
67
- CURRENT_MILESTONE_TPL=$(node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" config-get git.milestone_branch_template --raw 2>/dev/null)
68
- ```
69
-
70
- If either template is set AND does not contain `{project}`, and `branching_strategy` is not `"none"`, show migration hint before the settings questions:
71
-
72
- ```
73
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
74
- DGS ► BRANCH TEMPLATE UPDATE AVAILABLE
75
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
76
-
77
- Your branch templates don't include the project name, which can cause
78
- collisions in multi-project setups.
79
-
80
- Current: {current_phase_tpl}
81
- Suggested: dgs/{project}/phase-{phase}-{slug}
82
-
83
- Current: {current_milestone_tpl}
84
- Suggested: dgs/{project}/{milestone}-{slug}
85
- ```
86
-
87
- Use AskUserQuestion:
88
- ```
89
- AskUserQuestion([{
90
- question: "Update branch templates to include project name?",
91
- header: "Templates",
92
- multiSelect: false,
93
- options: [
94
- { label: "Yes (Recommended)", description: "Updates templates to include {project} for multi-project safety" },
95
- { label: "No", description: "Keep current templates" }
96
- ]
97
- }])
98
- ```
99
-
100
- If "Yes": write updated templates to config.json using config-set:
101
- ```bash
102
- node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" config-set git.phase_branch_template "dgs/{project}/phase-{phase}-{slug}"
103
- node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" config-set git.milestone_branch_template "dgs/{project}/{milestone}-{slug}"
104
- ```
105
-
106
- Show confirmation:
107
- ```
108
- Updated branch templates to include {project}.
109
- Branch names will now look like: dgs/your-project/phase-03-auth
110
-
111
- Note: Existing branches using the old format will NOT be renamed.
112
- Only new branches will use the updated format.
113
- ```
114
-
115
- If templates already contain `{project}` or branching_strategy is "none": skip this step silently.
116
- </step>
117
-
118
62
  <step name="present_settings">
119
63
  Use AskUserQuestion with current values pre-selected:
120
64
 
@@ -185,21 +129,14 @@ AskUserQuestion([
185
129
  ]
186
130
  },
187
131
  {
188
- question: "Git branching strategy?",
189
- header: "Branching",
132
+ question: "Four-eyes completion governance? (requires a second contributor for milestone/quick completion)",
133
+ header: "Four-Eyes",
190
134
  multiSelect: false,
191
135
  options: [
192
- { label: "None (Recommended)", description: "Commit to current branch (fine for single projects)" },
193
- { label: "Per Phase", description: "Branch per phase, review before merging" },
194
- { label: "Per Milestone", description: "Branch per project, merge all at end (for parallel projects)" }
136
+ { label: "Off", description: "No contributor check at completion gates" },
137
+ { label: "Warn", description: "Warn if only one contributor, but allow completion" },
138
+ { label: "Enforce", description: "Block completion unless a second contributor is detected (bypass with --force)" }
195
139
  ]
196
- },
197
- {
198
- question: "Base branch for code repos? (integration target for branching operations)",
199
- header: "Git",
200
- multiSelect: false,
201
- freeform: true,
202
- placeholder: currentConfig.base_branch || "main"
203
140
  }
204
141
  ])
205
142
  ```
@@ -450,11 +387,11 @@ Merge new settings into existing config:
450
387
  "auto_advance": true/false,
451
388
  "nyquist_validation": true/false,
452
389
  "codereview": true/false,
453
- "discipline": true/false
390
+ "discipline": true/false,
391
+ "four_eyes": "off" | "warn" | "enforce"
454
392
  },
455
393
  "git": {
456
- "branching_strategy": "none" | "phase" | "milestone",
457
- "base_branch": "main" | user_answer,
394
+ "base_branch": "main",
458
395
  "sync_push": "off" | "prompt" | "auto",
459
396
  "sync_pull": "off" | "prompt" | "auto"
460
397
  }
@@ -495,7 +432,6 @@ Write `~/.dgs/defaults.json` with:
495
432
  "model_profile": <current>,
496
433
  "commit_docs": <current>,
497
434
  "parallelization": <current>,
498
- "branching_strategy": <current>,
499
435
  "workflow": {
500
436
  "research": <current>,
501
437
  "plan_check": <current>,
@@ -503,7 +439,8 @@ Write `~/.dgs/defaults.json` with:
503
439
  "auto_advance": <current>,
504
440
  "nyquist_validation": <current>,
505
441
  "codereview": <current>,
506
- "discipline": <current>
442
+ "discipline": <current>,
443
+ "four_eyes": <current>
507
444
  },
508
445
  "git": {
509
446
  "sync_push": <current>,
@@ -544,8 +481,7 @@ Display:
544
481
  | Auto-Advance | {On/Off} |
545
482
  | Nyquist Validation | {On/Off} |
546
483
  | Code Reviewer | {On/Off} |
547
- | Git Branching | {None/Per Phase/Per Milestone} |
548
- | Base Branch | {main/develop/etc.} |
484
+ | Four-Eyes Governance | {Off/Warn/Enforce} |
549
485
  | Workflow Discipline | {On/Off} |
550
486
  | Git Sync Push | {Off/Prompt/Auto} |
551
487
  | Git Sync Pull | {Off/Prompt/Auto} |
@@ -567,7 +503,7 @@ Quick commands:
567
503
 
568
504
  <success_criteria>
569
505
  - [ ] Current config read
570
- - [ ] User presented with 9 workflow settings (profile + 6 workflow toggles + git branching + base branch)
506
+ - [ ] User presented with 8 workflow settings (profile + 6 workflow toggles + four-eyes governance)
571
507
  - [ ] User shown review key status (read-only)
572
508
  - [ ] Config updated with model_profile, workflow, and git sections
573
509
  - [ ] User offered to save as global defaults (~/.dgs/defaults.json)
@@ -222,7 +222,7 @@ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs specs add-log-entry --id
222
222
 
223
223
  Commit the draft:
224
224
  ```bash
225
- node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: draft $id from ideas $idea_ids" --push --files ${project_root}/specs/$filename
225
+ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: draft $id from ideas $idea_ids" --push --files specs/$filename
226
226
  ```
227
227
 
228
228
  Store `SPEC_ID` and `FILENAME` for subsequent steps.
@@ -289,7 +289,7 @@ Use AskUserQuestion: "Review the draft spec above. Type **approve** to send to r
289
289
 
290
290
  After approval, commit any changes:
291
291
  ```bash
292
- node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: revise draft $SPEC_ID" --push --files ${project_root}/specs/$FILENAME
292
+ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: revise draft $SPEC_ID" --push --files specs/$FILENAME
293
293
  ```
294
294
  </step>
295
295
 
@@ -350,7 +350,7 @@ Estimated cost: ~$X.XX
350
350
  **6. Commit updated spec:**
351
351
 
352
352
  ```bash
353
- node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: review $SPEC_ID (N rounds)" --push --files ${project_root}/specs/$FILENAME
353
+ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: review $SPEC_ID (N rounds)" --push --files specs/$FILENAME
354
354
  ```
355
355
  </step>
356
356
 
@@ -394,18 +394,16 @@ Source ideas moved to done: $IDEAS_MOVED
394
394
  Research documents moved to done: $RESEARCH_DOCS_MOVED (if any)
395
395
 
396
396
  What would you like to do next?
397
- 1. Create a new project from this spec -> /dgs:new-project
398
- 2. Add a milestone to an existing project -> /dgs:new-milestone
399
- 3. Nothing for now -- the spec is saved and ready when you are
397
+ 1. Start a milestone from this spec -> /dgs:new-milestone --auto $SPEC_ID
398
+ 2. Nothing for now -- the spec is saved and ready when you are
400
399
  ```
401
400
 
402
- In interactive mode, use AskUserQuestion: "Choose 1, 2, or 3 (or just press enter to defer):"
401
+ In interactive mode, use AskUserQuestion: "Choose 1 or 2 (or just press enter to defer):"
403
402
 
404
- - If **1**: Tell user "Run `/dgs:new-project` and reference spec `$FILENAME` during project creation."
405
- - If **2**: Tell user "Run `/dgs:new-milestone` and reference spec `$FILENAME` during milestone creation."
406
- - If **3** or empty/enter: Output "Spec saved. You can find it at `${project_root}/specs/$FILENAME`."
403
+ - If **1**: Tell user "Run `/dgs:new-milestone --auto $SPEC_ID` to start a milestone from this spec. If no project exists yet, run `/dgs:new-project` first to create the project holder, then `/dgs:new-milestone --auto $SPEC_ID`."
404
+ - If **2** or empty/enter: Output "Spec saved. You can find it at `specs/$FILENAME` (planning root)."
407
405
 
408
- In `--auto` mode: skip the routing question, just output the summary with the three options listed for reference.
406
+ In `--auto` mode: skip the routing question, just output the summary with the two options listed for reference.
409
407
  </step>
410
408
 
411
409
  </process>
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ // DGS Workflow Discipline Enforcement - PreToolUse + PostToolUse hook
3
+ //
4
+ // Ensures Edit/Write tool calls only happen inside /dgs:* commands.
5
+ // Works via a marker file that tracks active DGS command state:
6
+ //
7
+ // 1. When tool_name is "Skill" and the skill name starts with "dgs:":
8
+ // - PreToolUse: Write a marker file to /tmp/dgs-active-{session_id}.json
9
+ // - PostToolUse: Delete the marker, then check for uncommitted DGS files
10
+ //
11
+ // 2. When tool_name is "Edit" or "Write":
12
+ // - Check for marker file — if present, allow
13
+ // - Check if target path is in the allowlist — if so, allow
14
+ // - Check if cwd is a DGS planning folder — if not, allow (non-DGS project)
15
+ // - Otherwise, deny with explanation
16
+ //
17
+ // Safety net: After every /dgs:* command completes, checks for uncommitted
18
+ // DGS-managed files and auto-commits them. Logs a warning so the upstream
19
+ // workflow bug can be identified and fixed.
20
+
21
+ const fs = require('fs');
22
+ const os = require('os');
23
+ const path = require('path');
24
+ const { execSync } = require('child_process');
25
+
26
+ // Paths where Edit/Write is allowed without a DGS command
27
+ const ALLOWED_PATH_PATTERNS = [
28
+ /\.claude\/projects\/.*\/memory\//, // Auto-memory system
29
+ /\.claude\/.*\/memory\//, // Memory in any .claude subfolder
30
+ /\/tmp\//, // Temp files
31
+ ];
32
+
33
+ // DGS-managed paths that should be committed (relative to planning root)
34
+ // Used by the safety net to detect orphaned writes after a command completes
35
+ const DGS_MANAGED_PATTERNS = [
36
+ /^STATE\.md$/,
37
+ /^PROJECTS\.md$/,
38
+ /^MILESTONES\.md$/,
39
+ /^RETROSPECTIVE\.md$/,
40
+ /^CLAUDE\.md$/,
41
+ /^config\.json$/,
42
+ /^projects\/[^/]+\/STATE\.md$/,
43
+ /^projects\/[^/]+\/ROADMAP\.md$/,
44
+ /^projects\/[^/]+\/REQUIREMENTS\.md$/,
45
+ /^projects\/[^/]+\/PROJECT\.md$/,
46
+ /^projects\/[^/]+\/phases\//,
47
+ /^projects\/[^/]+\/milestones\//,
48
+ /^specs\//,
49
+ /^ideas\//,
50
+ /^todos\//,
51
+ /^jobs\//,
52
+ /^quick\//,
53
+ /^milestones\//,
54
+ /^codebase\//,
55
+ ];
56
+
57
+ function getMarkerPath(sessionId) {
58
+ return path.join(os.tmpdir(), `dgs-active-${sessionId}.json`);
59
+ }
60
+
61
+ function isDgsProject(cwd) {
62
+ try {
63
+ const configPath = path.join(cwd, 'config.json');
64
+ if (!fs.existsSync(configPath)) return false;
65
+ const content = fs.readFileSync(configPath, 'utf-8');
66
+ return content.includes('"product_name"');
67
+ } catch {
68
+ return false;
69
+ }
70
+ }
71
+
72
+ function isAllowedPath(filePath) {
73
+ if (!filePath) return false;
74
+ return ALLOWED_PATH_PATTERNS.some(pattern => pattern.test(filePath));
75
+ }
76
+
77
+ function getTargetPath(toolName, toolInput) {
78
+ if (!toolInput) return null;
79
+ // Edit and Write both use file_path
80
+ return toolInput.file_path || null;
81
+ }
82
+
83
+ let input = '';
84
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
85
+ process.stdin.setEncoding('utf8');
86
+ process.stdin.on('data', chunk => input += chunk);
87
+ process.stdin.on('end', () => {
88
+ clearTimeout(stdinTimeout);
89
+ try {
90
+ const data = JSON.parse(input);
91
+ const sessionId = data.session_id;
92
+ const hookEvent = data.hook_event_name;
93
+ const toolName = data.tool_name;
94
+ const toolInput = data.tool_input || {};
95
+ const cwd = data.cwd || process.cwd();
96
+
97
+ // ── PostToolUse: Clean up marker + safety net when Skill completes ──
98
+ if (hookEvent === 'PostToolUse') {
99
+ if (toolName === 'Skill') {
100
+ const skillName = toolInput.skill || toolInput.name || '';
101
+ if (skillName.startsWith('dgs:')) {
102
+ // Delete the active marker
103
+ const markerPath = getMarkerPath(sessionId);
104
+ try { fs.unlinkSync(markerPath); } catch { /* already gone */ }
105
+
106
+ // Safety net: check for uncommitted DGS-managed files
107
+ if (isDgsProject(cwd)) {
108
+ try {
109
+ const status = execSync('git status --porcelain', { cwd, encoding: 'utf-8', timeout: 5000 });
110
+ if (status.trim()) {
111
+ const lines = status.trim().split('\n');
112
+ const dirty = lines
113
+ .map(l => l.slice(3).trim()) // strip status prefix (e.g., " M ", "?? ")
114
+ .filter(f => DGS_MANAGED_PATTERNS.some(p => p.test(f)));
115
+
116
+ if (dirty.length > 0) {
117
+ // Stage and commit orphaned DGS files
118
+ for (const f of dirty) {
119
+ execSync(`git add "${f}"`, { cwd, stdio: 'pipe', timeout: 5000 });
120
+ }
121
+ const msg = `chore: auto-commit ${dirty.length} uncommitted DGS file(s) after ${skillName}`;
122
+ execSync(`git commit -m "${msg}"`, { cwd, stdio: 'pipe', timeout: 10000 });
123
+
124
+ // Warn via additionalContext so Claude sees it
125
+ const result = {
126
+ continue: true,
127
+ suppressOutput: false,
128
+ hookSpecificOutput: {
129
+ hookEventName: 'PostToolUse',
130
+ additionalContext: `[DGS safety net] Auto-committed ${dirty.length} orphaned file(s) after ${skillName}: ${dirty.join(', ')}. This indicates a missing commit in the ${skillName} workflow — consider fixing upstream.`,
131
+ },
132
+ };
133
+ process.stdout.write(JSON.stringify(result));
134
+ process.exit(0);
135
+ }
136
+ }
137
+ } catch { /* git not available or commit failed — don't block */ }
138
+ }
139
+ }
140
+ }
141
+ process.exit(0);
142
+ }
143
+
144
+ // ── PreToolUse: Skill → write marker ──
145
+ if (hookEvent === 'PreToolUse' && toolName === 'Skill') {
146
+ const skillName = toolInput.skill || toolInput.name || '';
147
+ if (skillName.startsWith('dgs:')) {
148
+ const markerPath = getMarkerPath(sessionId);
149
+ const marker = {
150
+ command: skillName,
151
+ started: new Date().toISOString(),
152
+ session_id: sessionId,
153
+ };
154
+ fs.writeFileSync(markerPath, JSON.stringify(marker));
155
+ }
156
+ process.exit(0);
157
+ }
158
+
159
+ // ── PreToolUse: Edit/Write → check marker ──
160
+ if (hookEvent === 'PreToolUse' && (toolName === 'Edit' || toolName === 'Write')) {
161
+ // Not a DGS project? Allow everything.
162
+ if (!isDgsProject(cwd)) {
163
+ process.exit(0);
164
+ }
165
+
166
+ // Target path in allowlist? Allow.
167
+ const targetPath = getTargetPath(toolName, toolInput);
168
+ if (isAllowedPath(targetPath)) {
169
+ process.exit(0);
170
+ }
171
+
172
+ // DGS command active? Allow.
173
+ const markerPath = getMarkerPath(sessionId);
174
+ if (fs.existsSync(markerPath)) {
175
+ process.exit(0);
176
+ }
177
+
178
+ // No DGS command active in a DGS project — deny.
179
+ const result = {
180
+ hookSpecificOutput: {
181
+ hookEventName: 'PreToolUse',
182
+ permissionDecision: 'deny',
183
+ permissionDecisionReason: 'DGS workflow discipline: Edit/Write requires an active /dgs:* command. Use /dgs:fast (trivial), /dgs:quick (small), or /dgs:execute-phase (feature). Say "skip DGS" to bypass.',
184
+ },
185
+ };
186
+ process.stdout.write(JSON.stringify(result));
187
+ process.exit(0);
188
+ }
189
+
190
+ // Any other tool/event — allow
191
+ process.exit(0);
192
+ } catch {
193
+ // Parse error or unexpected input — don't block
194
+ process.exit(0);
195
+ }
196
+ });
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "bugs": {
9
9
  "url": "https://github.com/KT-Partners-Ltd/dgs-platform-docs/issues"
10
10
  },
11
- "version": "3.0.4",
11
+ "version": "3.3.0",
12
12
  "description": "Deliver Great Systems Platform — A meta-prompting, context engineering and spec-driven development system for Claude Code and Gemini by KT Partners.",
13
13
  "bin": {
14
14
  "dgs": "bin/install.js"
@@ -13,6 +13,7 @@ const DIST_DIR = path.join(HOOKS_DIR, 'dist');
13
13
  const HOOKS_TO_COPY = [
14
14
  'dgs-check-update.js',
15
15
  'dgs-context-monitor.js',
16
+ 'dgs-enforce-discipline.js',
16
17
  'dgs-statusline.js'
17
18
  ];
18
19