@deftai/directive-content 0.59.0 → 0.61.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 (190) hide show
  1. package/.githooks/pre-commit +10 -128
  2. package/.githooks/pre-push +8 -108
  3. package/Taskfile.yml +48 -58
  4. package/UPGRADING.md +19 -3
  5. package/docs/assets/directive-lifecycle-diagram.png +0 -0
  6. package/docs/directive-lifecycle.md +73 -0
  7. package/docs/getting-started.md +5 -1
  8. package/package.json +3 -3
  9. package/packs/skills/skills-pack-0.1.json +1 -1
  10. package/packs/strategies/strategies-pack-0.1.json +19 -19
  11. package/scm/github.md +37 -6
  12. package/skills/deft-directive-setup/SKILL.md +24 -15
  13. package/strategies/speckit.md +14 -14
  14. package/strategies/v0-20-contract.md +12 -1
  15. package/tasks/change.yml +16 -31
  16. package/tasks/ci.yml +8 -0
  17. package/tasks/commit.yml +12 -19
  18. package/tasks/core.yml +10 -0
  19. package/tasks/engine.yml +42 -0
  20. package/tasks/framework.yml +3 -0
  21. package/tasks/install.yml +20 -19
  22. package/tasks/migrate.yml +26 -15
  23. package/tasks/project.yml +26 -0
  24. package/tasks/toolchain.yml +15 -5
  25. package/tasks/vbrief.yml +4 -3
  26. package/tasks/verify.yml +12 -14
  27. package/templates/agents-entry.md +1 -1
  28. package/scripts/_agents_md.py +0 -494
  29. package/scripts/_cache_fetch.py +0 -635
  30. package/scripts/_cache_quota.py +0 -529
  31. package/scripts/_cache_refresh.py +0 -163
  32. package/scripts/_cache_validate.py +0 -209
  33. package/scripts/_content_root.py +0 -42
  34. package/scripts/_doctor_state.py +0 -277
  35. package/scripts/_event_detect.py +0 -305
  36. package/scripts/_events.py +0 -514
  37. package/scripts/_lifecycle_hygiene.py +0 -568
  38. package/scripts/_pathspec.py +0 -91
  39. package/scripts/_policy_show_cli.py +0 -266
  40. package/scripts/_precutover.py +0 -92
  41. package/scripts/_project_context.py +0 -224
  42. package/scripts/_project_definition_io.py +0 -164
  43. package/scripts/_relocate_snapshot.py +0 -209
  44. package/scripts/_relocate_states.py +0 -343
  45. package/scripts/_resolve_preflight_path.py +0 -152
  46. package/scripts/_safe_subprocess.py +0 -167
  47. package/scripts/_session_start_hook.py +0 -205
  48. package/scripts/_sor_gate_diff.py +0 -365
  49. package/scripts/_stdio_utf8.py +0 -59
  50. package/scripts/_triage_bootstrap_gitignore.py +0 -904
  51. package/scripts/_triage_classify_cli.py +0 -122
  52. package/scripts/_triage_queue_cli.py +0 -625
  53. package/scripts/_triage_scope_cli.py +0 -343
  54. package/scripts/_triage_scope_drift_cli.py +0 -121
  55. package/scripts/_triage_scope_ignores.py +0 -286
  56. package/scripts/_triage_scope_milestone.py +0 -432
  57. package/scripts/_triage_scope_mutations.py +0 -337
  58. package/scripts/_triage_scope_renderers.py +0 -207
  59. package/scripts/_triage_smoketest_stages.py +0 -674
  60. package/scripts/_triage_subscribe_cli.py +0 -140
  61. package/scripts/_triage_welcome_cli.py +0 -421
  62. package/scripts/_vbrief_build.py +0 -239
  63. package/scripts/_vbrief_fidelity.py +0 -479
  64. package/scripts/_vbrief_legacy.py +0 -589
  65. package/scripts/_vbrief_reconciliation.py +0 -883
  66. package/scripts/_vbrief_routing.py +0 -277
  67. package/scripts/_vbrief_safety.py +0 -778
  68. package/scripts/_vbrief_sources.py +0 -312
  69. package/scripts/_vbrief_speckit.py +0 -262
  70. package/scripts/_vbrief_story_quality.py +0 -353
  71. package/scripts/_vbrief_validation.py +0 -299
  72. package/scripts/build_dist.py +0 -412
  73. package/scripts/cache.py +0 -1078
  74. package/scripts/cache_scanner.py +0 -745
  75. package/scripts/candidates_log.py +0 -432
  76. package/scripts/capacity_backfill.py +0 -680
  77. package/scripts/capacity_show.py +0 -653
  78. package/scripts/ci_local.py +0 -689
  79. package/scripts/code_structure_validate.py +0 -765
  80. package/scripts/codebase_default_extractor.py +0 -495
  81. package/scripts/codebase_map.py +0 -304
  82. package/scripts/codebase_map_fresh.py +0 -104
  83. package/scripts/codebase_projection_registry.py +0 -94
  84. package/scripts/codebase_provider.py +0 -582
  85. package/scripts/doctor.py +0 -2552
  86. package/scripts/framework_commands.py +0 -505
  87. package/scripts/gh_rest.py +0 -882
  88. package/scripts/github_auth_modes.py +0 -437
  89. package/scripts/github_body.py +0 -292
  90. package/scripts/ip_risk.py +0 -531
  91. package/scripts/issue_emit.py +0 -670
  92. package/scripts/issue_ingest.py +0 -1064
  93. package/scripts/migrate_preflight.py +0 -418
  94. package/scripts/migrate_vbrief.py +0 -2677
  95. package/scripts/monitor_pr.py +0 -401
  96. package/scripts/pack_migrate_lessons.py +0 -336
  97. package/scripts/pack_migrate_patterns.py +0 -254
  98. package/scripts/pack_migrate_rules.py +0 -350
  99. package/scripts/pack_migrate_skills.py +0 -423
  100. package/scripts/pack_migrate_strategies.py +0 -311
  101. package/scripts/pack_migrate_swarm_spec.py +0 -250
  102. package/scripts/pack_render.py +0 -434
  103. package/scripts/packs_slice.py +0 -712
  104. package/scripts/platform_capabilities.py +0 -336
  105. package/scripts/policy.py +0 -2826
  106. package/scripts/policy_set.py +0 -324
  107. package/scripts/pr_check_closing_keywords.py +0 -524
  108. package/scripts/pr_check_protected_issues.py +0 -267
  109. package/scripts/pr_merge_readiness.py +0 -1004
  110. package/scripts/pr_wait_mergeable.py +0 -669
  111. package/scripts/prd_render.py +0 -159
  112. package/scripts/preflight_architecture_sor.py +0 -974
  113. package/scripts/preflight_branch.py +0 -289
  114. package/scripts/preflight_cache.py +0 -974
  115. package/scripts/preflight_gh.py +0 -721
  116. package/scripts/preflight_implementation.py +0 -272
  117. package/scripts/preflight_story_start.py +0 -838
  118. package/scripts/preflight_wip_cap.py +0 -149
  119. package/scripts/probe_session.py +0 -545
  120. package/scripts/project_render.py +0 -293
  121. package/scripts/quarantine_ext.py +0 -237
  122. package/scripts/reconcile_issues.py +0 -1442
  123. package/scripts/refresh-path.ps1 +0 -107
  124. package/scripts/release.py +0 -2030
  125. package/scripts/release_e2e.py +0 -1011
  126. package/scripts/release_publish.py +0 -486
  127. package/scripts/release_rollback.py +0 -980
  128. package/scripts/relocate.py +0 -1034
  129. package/scripts/resolve_changelog_unreleased.py +0 -667
  130. package/scripts/resolve_version.py +0 -490
  131. package/scripts/resume_conditions.py +0 -706
  132. package/scripts/ritual_sentinel.py +0 -609
  133. package/scripts/roadmap_render.py +0 -635
  134. package/scripts/rule_ownership_lint.py +0 -325
  135. package/scripts/scm.py +0 -591
  136. package/scripts/scope_audit_log.py +0 -387
  137. package/scripts/scope_decompose.py +0 -654
  138. package/scripts/scope_demote.py +0 -509
  139. package/scripts/scope_lifecycle.py +0 -1126
  140. package/scripts/scope_undo.py +0 -772
  141. package/scripts/session_start.py +0 -406
  142. package/scripts/setup_ghx.py +0 -339
  143. package/scripts/setup_windows.ps1 +0 -220
  144. package/scripts/slice_audit.py +0 -585
  145. package/scripts/slice_record.py +0 -530
  146. package/scripts/slice_record_existing.py +0 -692
  147. package/scripts/slug_normalize.py +0 -178
  148. package/scripts/spec_render.py +0 -477
  149. package/scripts/spec_validate.py +0 -238
  150. package/scripts/subagent_monitor.py +0 -658
  151. package/scripts/swarm_complete_cohort.py +0 -644
  152. package/scripts/swarm_launch.py +0 -1206
  153. package/scripts/swarm_readiness.py +0 -554
  154. package/scripts/swarm_verify_review_clean.py +0 -438
  155. package/scripts/swarm_worktrees.py +0 -497
  156. package/scripts/toolchain-check.py +0 -52
  157. package/scripts/triage_actions.py +0 -871
  158. package/scripts/triage_bootstrap.py +0 -1153
  159. package/scripts/triage_bulk.py +0 -630
  160. package/scripts/triage_classify.py +0 -932
  161. package/scripts/triage_help.py +0 -1685
  162. package/scripts/triage_queue.py +0 -1944
  163. package/scripts/triage_reconcile.py +0 -581
  164. package/scripts/triage_refresh.py +0 -643
  165. package/scripts/triage_scope.py +0 -999
  166. package/scripts/triage_scope_drift.py +0 -575
  167. package/scripts/triage_smoketest.py +0 -396
  168. package/scripts/triage_subscribe.py +0 -399
  169. package/scripts/triage_summary.py +0 -1011
  170. package/scripts/triage_welcome.py +0 -1178
  171. package/scripts/ts_check_lane.py +0 -86
  172. package/scripts/validate-links.py +0 -64
  173. package/scripts/validate_strategy_output.py +0 -212
  174. package/scripts/vbrief_activate.py +0 -228
  175. package/scripts/vbrief_migrate_conformance.py +0 -368
  176. package/scripts/vbrief_reconcile_graph.py +0 -306
  177. package/scripts/vbrief_reconcile_labels.py +0 -460
  178. package/scripts/vbrief_reconcile_umbrellas.py +0 -741
  179. package/scripts/vbrief_validate.py +0 -1144
  180. package/scripts/verify-stubs.py +0 -61
  181. package/scripts/verify_capacity.py +0 -160
  182. package/scripts/verify_encoding.py +0 -699
  183. package/scripts/verify_hooks_installed.py +0 -206
  184. package/scripts/verify_investigation.py +0 -360
  185. package/scripts/verify_judgment_gates.py +0 -827
  186. package/scripts/verify_no_task_runtime.py +0 -171
  187. package/scripts/verify_scm_boundary.py +0 -509
  188. package/scripts/verify_session_ritual.py +0 -389
  189. package/scripts/verify_tools.py +0 -426
  190. package/scripts/verify_vbrief_conformance.py +0 -478
@@ -1,238 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- spec_validate.py — Validate a vbrief specification JSON file.
4
-
5
- Usage:
6
- uv run python scripts/spec_validate.py <spec_file>
7
-
8
- Exit codes:
9
- 0 — valid
10
- 1 — invalid (file missing, bad JSON, or schema violation)
11
- 2 — usage error (no argument provided)
12
-
13
- Implementation: IMPLEMENTATION.md Phase 5.1
14
- """
15
-
16
- import json
17
- import sys
18
- from pathlib import Path
19
-
20
- # Belt-and-suspenders UTF-8 stdout guard (#540) so non-ASCII status glyphs
21
- # do not crash on Windows cp1252 when the ``PYTHONUTF8`` env var is not set.
22
- sys.path.insert(0, str(Path(__file__).resolve().parent))
23
- from _stdio_utf8 import reconfigure_stdio # noqa: E402
24
-
25
- reconfigure_stdio()
26
-
27
- # v0.6 Status enum (includes the new ``failed`` terminal status per
28
- # the canonical schema at vbrief/schemas/vbrief-core.schema.json, #533).
29
- VALID_STATUSES = frozenset({
30
- "draft", "proposed", "approved", "pending",
31
- "running", "completed", "blocked", "failed", "cancelled",
32
- })
33
-
34
-
35
- def _validate_narratives(narratives: object, path: str, errors: list[str]) -> None:
36
- """Validate that all values in a narratives/narrative object are strings."""
37
- if not isinstance(narratives, dict):
38
- errors.append(f"{path} must be an object")
39
- return
40
- for key, value in narratives.items():
41
- if not isinstance(value, str):
42
- errors.append(
43
- f"{path}.{key} must be a string, got {type(value).__name__}"
44
- )
45
-
46
-
47
- def _validate_plan_item(
48
- item: dict, path: str, errors: list[str],
49
- ) -> None:
50
- """Recursively validate a PlanItem and its nested children.
51
-
52
- Per the canonical v0.6 schema, ``PlanItem.items`` is the PREFERRED
53
- nested field and ``PlanItem.subItems`` is the deprecated legacy alias
54
- kept for backward compatibility (#533 / Greptile P1). Both are accepted
55
- here and recursively validated; neither is treated as an error.
56
- """
57
- item_id = item.get("id", "<no-id>")
58
- item_path = f"{path}[{item_id}]"
59
-
60
- if "title" not in item:
61
- errors.append(f"{item_path} missing 'title'")
62
- if "status" not in item:
63
- errors.append(f"{item_path} missing 'status'")
64
- elif item["status"] not in VALID_STATUSES:
65
- errors.append(
66
- f"{item_path} invalid status: {item['status']!r}"
67
- )
68
-
69
- # Narrative values must be strings
70
- if "narrative" in item:
71
- _validate_narratives(item["narrative"], f"{item_path}.narrative", errors)
72
-
73
- # v0.6 preferred nested field.
74
- if "items" in item:
75
- if not isinstance(item["items"], list):
76
- errors.append(f"{item_path}.items must be an array")
77
- else:
78
- for j, sub in enumerate(item["items"]):
79
- if not isinstance(sub, dict):
80
- errors.append(f"{item_path}.items[{j}] must be an object")
81
- continue
82
- _validate_plan_item(sub, f"{item_path}.items", errors)
83
-
84
- # Deprecated legacy alias -- still accepted for backward compatibility.
85
- if "subItems" in item:
86
- if not isinstance(item["subItems"], list):
87
- errors.append(f"{item_path}.subItems must be an array")
88
- else:
89
- for j, sub in enumerate(item["subItems"]):
90
- if not isinstance(sub, dict):
91
- errors.append(f"{item_path}.subItems[{j}] must be an object")
92
- continue
93
- _validate_plan_item(sub, f"{item_path}.subItems", errors)
94
-
95
-
96
- # Strict v0.6-only acceptance (#533). The canonical schema at
97
- # vbrief/schemas/vbrief-core.schema.json pins vBRIEFInfo.version to
98
- # const "0.6"; this validator rejects every other version. Pre-existing
99
- # v0.5 vBRIEFs are automatically bumped to v0.6 during ``task
100
- # migrate:vbrief`` (#571); operators who see the error below should run
101
- # the migrator on the affected project. The check below consults this
102
- # frozenset rather than an inline literal so the validator shares the
103
- # version-check pattern with ``scripts/vbrief_validate.py`` (#565,
104
- # Option B): future v0.7 introduction adds one entry here instead of
105
- # touching multiple inline string comparisons.
106
- VALID_VBRIEF_VERSIONS: frozenset[str] = frozenset({"0.6"})
107
-
108
-
109
- def _validate_schema(data: dict, path: str) -> list[str]:
110
- """Validate vBRIEF structural requirements (v0.6). Returns a list of errors.
111
-
112
- Strictly requires ``vBRIEFInfo.version`` to be one of
113
- ``VALID_VBRIEF_VERSIONS`` (currently ``{"0.6"}``) to match the
114
- canonical v0.6 schema (#533). Any v0.5 vBRIEF must be migrated to
115
- v0.6 via ``task migrate:vbrief``.
116
- """
117
- errors: list[str] = []
118
-
119
- # Top-level envelope
120
- if "vBRIEFInfo" not in data:
121
- errors.append("missing required top-level key 'vBRIEFInfo'")
122
- else:
123
- info = data["vBRIEFInfo"]
124
- if not isinstance(info, dict):
125
- errors.append("'vBRIEFInfo' must be an object")
126
- elif info.get("version") not in VALID_VBRIEF_VERSIONS:
127
- # #571: the previous wording pointed at a "migrator sweep"
128
- # that did not exist as a standalone command, leaving
129
- # operators with an unactionable error. The migrator now
130
- # auto-bumps v0.5 -> v0.6 on ingest (see
131
- # ``scripts/migrate_vbrief.py`` ``_ingest_spec_narratives``
132
- # path), so the actionable recovery command is just
133
- # ``task migrate:vbrief``.
134
- #
135
- # #565: the version comparison consults
136
- # ``VALID_VBRIEF_VERSIONS`` rather than an inline ``"0.6"``
137
- # literal so this validator matches the
138
- # ``scripts/vbrief_validate.py`` pattern (Option B).
139
- errors.append(
140
- f"'vBRIEFInfo.version' must be '0.6' (canonical v0.6 "
141
- f"schema, #533), got {info.get('version')!r}. Run "
142
- f"`task migrate:vbrief` to upgrade pre-existing v0.5 "
143
- f"vBRIEFs in-place."
144
- )
145
-
146
- if "plan" not in data:
147
- errors.append("missing required top-level key 'plan'")
148
- else:
149
- plan = data["plan"]
150
- if not isinstance(plan, dict):
151
- errors.append("'plan' must be an object, not a string or other type")
152
- else:
153
- for field in ("title", "status", "items"):
154
- if field not in plan:
155
- errors.append(f"'plan' missing required field '{field}'")
156
-
157
- if "title" in plan and (not isinstance(plan["title"], str) or not plan["title"]):
158
- errors.append("'plan.title' must be a non-empty string")
159
-
160
- if "status" in plan and plan["status"] not in VALID_STATUSES:
161
- errors.append(
162
- f"'plan.status' invalid: {plan['status']!r} "
163
- f"(expected one of {sorted(VALID_STATUSES)})"
164
- )
165
-
166
- # Validate plan-level narratives
167
- if "narratives" in plan:
168
- _validate_narratives(
169
- plan["narratives"], "plan.narratives", errors
170
- )
171
-
172
- if "items" in plan:
173
- if not isinstance(plan["items"], list):
174
- errors.append("'plan.items' must be an array")
175
- else:
176
- for i, item in enumerate(plan["items"]):
177
- if not isinstance(item, dict):
178
- errors.append(f"plan.items[{i}] must be an object")
179
- continue
180
- _validate_plan_item(item, "plan.items", errors)
181
-
182
- # Detect legacy flat format. Per #565, the migration target message
183
- # advertises the canonical v0.6 envelope (the prior wording pointed
184
- # at the retired v0.5 envelope after the strict v0.6 tightening in
185
- # #533).
186
- legacy_keys = {"vbrief", "tasks", "overview", "architecture"}
187
- found_legacy = legacy_keys & set(data.keys())
188
- if found_legacy:
189
- errors.append(
190
- f"legacy flat-format keys found at top level: {sorted(found_legacy)}. "
191
- "Migrate to vBRIEF v0.6 envelope (vBRIEFInfo + plan)"
192
- )
193
-
194
- return errors
195
-
196
-
197
- def validate_spec(spec_path: str) -> tuple[bool, str]:
198
- """
199
- Validate the spec file at *spec_path*.
200
-
201
- Returns:
202
- (True, success_message) on success.
203
- (False, error_message) on failure.
204
- """
205
- path = Path(spec_path)
206
- if not path.exists():
207
- return (
208
- False,
209
- f"✗ {spec_path} not found\n"
210
- " Create it by running the interview process "
211
- "(see deft/templates/make-spec.md)",
212
- )
213
- try:
214
- with open(path, encoding="utf-8") as fh:
215
- data = json.load(fh)
216
- except json.JSONDecodeError as exc:
217
- return False, f"✗ {spec_path} is not valid JSON: {exc}"
218
-
219
- errors = _validate_schema(data, spec_path)
220
- if errors:
221
- detail = "\n".join(f" • {e}" for e in errors)
222
- return False, f"✗ {path.name} has schema violations:\n{detail}"
223
-
224
- return True, f"✓ {path.name} is valid vBRIEF"
225
-
226
-
227
- def main() -> int:
228
- if len(sys.argv) < 2:
229
- print("Usage: spec_validate.py <spec_file>", file=sys.stderr)
230
- return 2
231
-
232
- ok, message = validate_spec(sys.argv[1])
233
- print(message)
234
- return 0 if ok else 1
235
-
236
-
237
- if __name__ == "__main__":
238
- sys.exit(main())