@deftai/directive-content 0.55.1 → 0.56.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 (220) hide show
  1. package/.githooks/pre-commit +143 -0
  2. package/.githooks/pre-push +121 -0
  3. package/QUICK-START.md +13 -3
  4. package/Taskfile.yml +934 -0
  5. package/UPGRADING.md +82 -11
  6. package/events/README.md +3 -3
  7. package/package.json +5 -4
  8. package/packs/skills/skills-pack-0.1.json +22 -22
  9. package/scripts/_agents_md.py +494 -0
  10. package/scripts/_cache_fetch.py +635 -0
  11. package/scripts/_cache_quota.py +529 -0
  12. package/scripts/_cache_refresh.py +163 -0
  13. package/scripts/_cache_validate.py +209 -0
  14. package/scripts/_content_root.py +42 -0
  15. package/scripts/_doctor_state.py +277 -0
  16. package/scripts/_event_detect.py +305 -0
  17. package/scripts/_events.py +514 -0
  18. package/scripts/_lifecycle_hygiene.py +568 -0
  19. package/scripts/_pathspec.py +91 -0
  20. package/scripts/_policy_show_cli.py +266 -0
  21. package/scripts/_precutover.py +92 -0
  22. package/scripts/_project_context.py +224 -0
  23. package/scripts/_project_definition_io.py +164 -0
  24. package/scripts/_relocate_snapshot.py +209 -0
  25. package/scripts/_relocate_states.py +343 -0
  26. package/scripts/_resolve_preflight_path.py +152 -0
  27. package/scripts/_safe_subprocess.py +167 -0
  28. package/scripts/_session_start_hook.py +205 -0
  29. package/scripts/_sor_gate_diff.py +365 -0
  30. package/scripts/_stdio_utf8.py +59 -0
  31. package/scripts/_triage_bootstrap_gitignore.py +904 -0
  32. package/scripts/_triage_classify_cli.py +122 -0
  33. package/scripts/_triage_queue_cli.py +625 -0
  34. package/scripts/_triage_scope_cli.py +343 -0
  35. package/scripts/_triage_scope_drift_cli.py +121 -0
  36. package/scripts/_triage_scope_ignores.py +286 -0
  37. package/scripts/_triage_scope_milestone.py +432 -0
  38. package/scripts/_triage_scope_mutations.py +337 -0
  39. package/scripts/_triage_scope_renderers.py +207 -0
  40. package/scripts/_triage_smoketest_stages.py +674 -0
  41. package/scripts/_triage_subscribe_cli.py +140 -0
  42. package/scripts/_triage_welcome_cli.py +421 -0
  43. package/scripts/_vbrief_build.py +239 -0
  44. package/scripts/_vbrief_fidelity.py +479 -0
  45. package/scripts/_vbrief_legacy.py +589 -0
  46. package/scripts/_vbrief_reconciliation.py +883 -0
  47. package/scripts/_vbrief_routing.py +277 -0
  48. package/scripts/_vbrief_safety.py +778 -0
  49. package/scripts/_vbrief_sources.py +312 -0
  50. package/scripts/_vbrief_speckit.py +262 -0
  51. package/scripts/_vbrief_story_quality.py +353 -0
  52. package/scripts/_vbrief_validation.py +299 -0
  53. package/scripts/build_dist.py +412 -0
  54. package/scripts/cache.py +1078 -0
  55. package/scripts/cache_scanner.py +745 -0
  56. package/scripts/candidates_log.py +432 -0
  57. package/scripts/capacity_backfill.py +680 -0
  58. package/scripts/capacity_show.py +653 -0
  59. package/scripts/ci_local.py +689 -0
  60. package/scripts/code_structure_validate.py +765 -0
  61. package/scripts/codebase_default_extractor.py +495 -0
  62. package/scripts/codebase_map.py +304 -0
  63. package/scripts/codebase_map_fresh.py +104 -0
  64. package/scripts/codebase_projection_registry.py +94 -0
  65. package/scripts/codebase_provider.py +582 -0
  66. package/scripts/doctor.py +2257 -0
  67. package/scripts/framework_commands.py +505 -0
  68. package/scripts/gh_rest.py +882 -0
  69. package/scripts/github_auth_modes.py +437 -0
  70. package/scripts/github_body.py +292 -0
  71. package/scripts/ip_risk.py +531 -0
  72. package/scripts/issue_emit.py +670 -0
  73. package/scripts/issue_ingest.py +1064 -0
  74. package/scripts/migrate_preflight.py +418 -0
  75. package/scripts/migrate_vbrief.py +2677 -0
  76. package/scripts/monitor_pr.py +401 -0
  77. package/scripts/pack_migrate_lessons.py +336 -0
  78. package/scripts/pack_migrate_patterns.py +254 -0
  79. package/scripts/pack_migrate_rules.py +350 -0
  80. package/scripts/pack_migrate_skills.py +423 -0
  81. package/scripts/pack_migrate_strategies.py +311 -0
  82. package/scripts/pack_migrate_swarm_spec.py +250 -0
  83. package/scripts/pack_render.py +434 -0
  84. package/scripts/packs_slice.py +712 -0
  85. package/scripts/platform_capabilities.py +336 -0
  86. package/scripts/policy.py +2826 -0
  87. package/scripts/policy_set.py +324 -0
  88. package/scripts/pr_check_closing_keywords.py +524 -0
  89. package/scripts/pr_check_protected_issues.py +267 -0
  90. package/scripts/pr_merge_readiness.py +1004 -0
  91. package/scripts/pr_wait_mergeable.py +669 -0
  92. package/scripts/prd_render.py +159 -0
  93. package/scripts/preflight_architecture_sor.py +974 -0
  94. package/scripts/preflight_branch.py +289 -0
  95. package/scripts/preflight_cache.py +974 -0
  96. package/scripts/preflight_gh.py +721 -0
  97. package/scripts/preflight_implementation.py +272 -0
  98. package/scripts/preflight_story_start.py +838 -0
  99. package/scripts/preflight_wip_cap.py +149 -0
  100. package/scripts/probe_session.py +545 -0
  101. package/scripts/project_render.py +293 -0
  102. package/scripts/quarantine_ext.py +237 -0
  103. package/scripts/reconcile_issues.py +1442 -0
  104. package/scripts/refresh-path.ps1 +107 -0
  105. package/scripts/release.py +2030 -0
  106. package/scripts/release_e2e.py +1011 -0
  107. package/scripts/release_publish.py +486 -0
  108. package/scripts/release_rollback.py +980 -0
  109. package/scripts/relocate.py +1034 -0
  110. package/scripts/resolve_changelog_unreleased.py +667 -0
  111. package/scripts/resolve_version.py +490 -0
  112. package/scripts/resume_conditions.py +706 -0
  113. package/scripts/ritual_sentinel.py +609 -0
  114. package/scripts/roadmap_render.py +635 -0
  115. package/scripts/rule_ownership_lint.py +325 -0
  116. package/scripts/scm.py +591 -0
  117. package/scripts/scope_audit_log.py +387 -0
  118. package/scripts/scope_decompose.py +654 -0
  119. package/scripts/scope_demote.py +509 -0
  120. package/scripts/scope_lifecycle.py +1126 -0
  121. package/scripts/scope_undo.py +772 -0
  122. package/scripts/session_start.py +406 -0
  123. package/scripts/setup_ghx.py +339 -0
  124. package/scripts/setup_windows.ps1 +220 -0
  125. package/scripts/slice_audit.py +585 -0
  126. package/scripts/slice_record.py +530 -0
  127. package/scripts/slice_record_existing.py +692 -0
  128. package/scripts/slug_normalize.py +178 -0
  129. package/scripts/spec_render.py +477 -0
  130. package/scripts/spec_validate.py +238 -0
  131. package/scripts/subagent_monitor.py +658 -0
  132. package/scripts/swarm_complete_cohort.py +644 -0
  133. package/scripts/swarm_launch.py +1206 -0
  134. package/scripts/swarm_readiness.py +554 -0
  135. package/scripts/swarm_verify_review_clean.py +438 -0
  136. package/scripts/swarm_worktrees.py +497 -0
  137. package/scripts/toolchain-check.py +52 -0
  138. package/scripts/triage_actions.py +871 -0
  139. package/scripts/triage_bootstrap.py +1153 -0
  140. package/scripts/triage_bulk.py +630 -0
  141. package/scripts/triage_classify.py +932 -0
  142. package/scripts/triage_help.py +1685 -0
  143. package/scripts/triage_queue.py +1944 -0
  144. package/scripts/triage_reconcile.py +581 -0
  145. package/scripts/triage_refresh.py +643 -0
  146. package/scripts/triage_scope.py +999 -0
  147. package/scripts/triage_scope_drift.py +575 -0
  148. package/scripts/triage_smoketest.py +396 -0
  149. package/scripts/triage_subscribe.py +399 -0
  150. package/scripts/triage_summary.py +1011 -0
  151. package/scripts/triage_welcome.py +1178 -0
  152. package/scripts/ts_check_lane.py +86 -0
  153. package/scripts/validate-links.py +64 -0
  154. package/scripts/validate_strategy_output.py +212 -0
  155. package/scripts/vbrief_activate.py +228 -0
  156. package/scripts/vbrief_migrate_conformance.py +368 -0
  157. package/scripts/vbrief_reconcile_graph.py +306 -0
  158. package/scripts/vbrief_reconcile_labels.py +460 -0
  159. package/scripts/vbrief_reconcile_umbrellas.py +741 -0
  160. package/scripts/vbrief_validate.py +1195 -0
  161. package/scripts/verify-stubs.py +61 -0
  162. package/scripts/verify_capacity.py +160 -0
  163. package/scripts/verify_encoding.py +699 -0
  164. package/scripts/verify_hooks_installed.py +206 -0
  165. package/scripts/verify_investigation.py +360 -0
  166. package/scripts/verify_judgment_gates.py +827 -0
  167. package/scripts/verify_no_task_runtime.py +171 -0
  168. package/scripts/verify_scm_boundary.py +509 -0
  169. package/scripts/verify_session_ritual.py +389 -0
  170. package/scripts/verify_tools.py +426 -0
  171. package/scripts/verify_vbrief_conformance.py +478 -0
  172. package/skills/deft-directive-swarm/SKILL.md +7 -26
  173. package/skills/deft-directive-sync/SKILL.md +1 -1
  174. package/tasks/architecture.yml +13 -0
  175. package/tasks/cache.yml +69 -0
  176. package/tasks/capacity.yml +38 -0
  177. package/tasks/change.yml +46 -0
  178. package/tasks/changelog.yml +24 -0
  179. package/tasks/ci.yml +49 -0
  180. package/tasks/codebase.yml +47 -0
  181. package/tasks/commit.yml +30 -0
  182. package/tasks/core.yml +126 -0
  183. package/tasks/deployments.yml +54 -0
  184. package/tasks/framework.yml +74 -0
  185. package/tasks/install.yml +60 -0
  186. package/tasks/issue.yml +50 -0
  187. package/tasks/migrate.yml +73 -0
  188. package/tasks/packs.yml +92 -0
  189. package/tasks/policy.yml +75 -0
  190. package/tasks/pr.yml +89 -0
  191. package/tasks/prd.yml +39 -0
  192. package/tasks/project.yml +27 -0
  193. package/tasks/reconcile.yml +32 -0
  194. package/tasks/relocate.yml +56 -0
  195. package/tasks/roadmap.yml +28 -0
  196. package/tasks/scm.yml +126 -0
  197. package/tasks/scope-undo.yml +36 -0
  198. package/tasks/scope.yml +141 -0
  199. package/tasks/session.yml +19 -0
  200. package/tasks/setup.yml +37 -0
  201. package/tasks/slice.yml +69 -0
  202. package/tasks/spec.yml +41 -0
  203. package/tasks/swarm.yml +85 -0
  204. package/tasks/toolchain.yml +13 -0
  205. package/tasks/triage-actions.yml +94 -0
  206. package/tasks/triage-bootstrap.yml +43 -0
  207. package/tasks/triage-bulk.yml +75 -0
  208. package/tasks/triage-classify.yml +30 -0
  209. package/tasks/triage-queue.yml +50 -0
  210. package/tasks/triage-reconcile.yml +29 -0
  211. package/tasks/triage-scope-drift.yml +29 -0
  212. package/tasks/triage-scope.yml +31 -0
  213. package/tasks/triage-smoketest.yml +33 -0
  214. package/tasks/triage-subscribe.yml +36 -0
  215. package/tasks/triage-summary.yml +29 -0
  216. package/tasks/triage-welcome.yml +32 -0
  217. package/tasks/ts.yml +328 -0
  218. package/tasks/vbrief.yml +206 -0
  219. package/tasks/verify.yml +292 -0
  220. package/templates/agents-entry.md +2 -2
@@ -0,0 +1,61 @@
1
+ """Scan source files for stub patterns (TODO, FIXME, HACK, return null, bare pass)."""
2
+
3
+ import re
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ PATTERNS = [
8
+ (re.compile(r"\bTODO\b"), "TODO"),
9
+ (re.compile(r"\bFIXME\b"), "FIXME"),
10
+ (re.compile(r"\bHACK\b"), "HACK"),
11
+ (re.compile(r"\breturn\s+null\b"), "return null"),
12
+ ]
13
+
14
+ EXCLUDE_DIRS = {
15
+ "tests", "vendor", ".git", "backup", "history",
16
+ "node_modules", ".venv", "__pycache__", "dist",
17
+ "scripts", # exclude tooling scripts (contain pattern strings)
18
+ }
19
+
20
+ EXTENSIONS = {".py", ".go", ".sh"}
21
+
22
+
23
+ def main() -> int:
24
+ findings = []
25
+
26
+ for f in sorted(Path(".").rglob("*")):
27
+ if not f.is_file() or f.suffix not in EXTENSIONS:
28
+ continue
29
+ if any(p in f.parts for p in EXCLUDE_DIRS):
30
+ continue
31
+ try:
32
+ text = f.read_text("utf-8", errors="replace")
33
+ lines = text.splitlines()
34
+ for i, line in enumerate(lines, 1):
35
+ stripped = line.strip()
36
+ # Detect bare 'pass' after a colon-ending line (stub function/method)
37
+ if stripped == "pass" and f.suffix == ".py" and i >= 2:
38
+ prev = lines[i - 2].strip()
39
+ if prev.endswith(":") and not prev.startswith("#"):
40
+ findings.append((str(f), i, "bare pass", line.rstrip()))
41
+ # Detect keyword patterns
42
+ for pat, label in PATTERNS:
43
+ if pat.search(line):
44
+ findings.append((str(f), i, label, line.rstrip()))
45
+ except Exception:
46
+ pass
47
+
48
+ if findings:
49
+ print(f"Found {len(findings)} stub(s):")
50
+ for fp, ln, label, text in findings[:50]:
51
+ print(f" {fp}:{ln} [{label}] {text[:120]}")
52
+ if len(findings) > 50:
53
+ print(f" ... and {len(findings) - 50} more")
54
+ return 1
55
+
56
+ print("No stub patterns found in source files")
57
+ return 0
58
+
59
+
60
+ if __name__ == "__main__":
61
+ sys.exit(main())
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env python3
2
+ """verify_capacity.py -- three-state ADVISORY capacity gate (#1419 Slice 4).
3
+
4
+ Surfaced via ``task verify:capacity``. Reuses the offline accounting engine in
5
+ :mod:`scripts.capacity_show` to evaluate whether the trailing-window backward
6
+ mix has drifted away from the configured ``capacityAllocation`` targets.
7
+
8
+ Advisory by construction
9
+ ------------------------
10
+ ``plan.policy.capacityAllocation.enforcement`` defaults to ``"advise"``, and in
11
+ that posture this gate ALWAYS exits 0 -- it reports the mix and defers to the
12
+ selection ordering. It is therefore safe to run anywhere and is deliberately
13
+ NOT wired into the ``task check`` aggregate: a capacity deficit on the
14
+ framework's own tree MUST NOT fail-closed and wedge master.
15
+
16
+ A non-zero "deficit" exit (1) only fires when ALL of the following hold:
17
+
18
+ * ``enforcement == "enforce"`` (explicit per-project opt-in), AND
19
+ * the classified-completion sample is at or above ``minSampleSize`` (so the
20
+ signal is load-bearing, not noise), AND
21
+ * at least one protected bucket is starved past
22
+ :data:`DEFICIT_TOLERANCE` of the trailing window's completed weight.
23
+
24
+ Exit codes (three-state, mirrors the other deft verify gates):
25
+
26
+ * ``0`` -- within targets, OR advisory posture, OR insufficient sample, OR no
27
+ capacity policy configured. (This is the only state reachable on the
28
+ framework's own ``advise``-default tree.)
29
+ * ``1`` -- ``enforce`` posture with a real, sampled deficit.
30
+ * ``2`` -- config error (``--project-root`` is not a directory).
31
+ """
32
+
33
+ from __future__ import annotations
34
+
35
+ import argparse
36
+ import sys
37
+ from datetime import datetime
38
+ from pathlib import Path
39
+
40
+ # Make sibling helpers importable both as __main__ and when imported by tests.
41
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
42
+
43
+ from _stdio_utf8 import reconfigure_stdio # noqa: E402
44
+ from capacity_show import CapacityReport, compute_report, render_report # noqa: E402
45
+ from policy import resolve_capacity_allocation # noqa: E402
46
+
47
+ reconfigure_stdio()
48
+
49
+ #: Minimum absolute backward-weight deficit (in the report's unit) that an
50
+ #: ``enforce``-posture bucket may carry before the gate flags it. A small
51
+ #: tolerance absorbs rounding and single-item lumpiness so the gate fires only
52
+ #: on a genuine, sustained shortfall.
53
+ DEFICIT_TOLERANCE: float = 1.0
54
+
55
+
56
+ def _worst_deficit(report: CapacityReport) -> tuple[str, float]:
57
+ """Return the ``(bucket_id, deficit)`` with the largest positive deficit."""
58
+ worst_id = ""
59
+ worst = 0.0
60
+ for tally in report.buckets:
61
+ deficit = report.bucket_deficit(tally)
62
+ if deficit > worst:
63
+ worst = deficit
64
+ worst_id = tally.bucket_id
65
+ return worst_id, worst
66
+
67
+
68
+ def evaluate(
69
+ project_root: Path, *, now: datetime | None = None
70
+ ) -> tuple[int, str]:
71
+ """Pure entry point: returns ``(exit_code, message)``.
72
+
73
+ See the module docstring for the three-state contract. The ``advise``
74
+ default guarantees exit 0 on the framework's own tree.
75
+ """
76
+ if not project_root.is_dir():
77
+ return 2, (
78
+ f"verify_capacity: --project-root is not a directory: {project_root}\n"
79
+ " Recovery: pass an existing project root."
80
+ )
81
+
82
+ allocation = resolve_capacity_allocation(project_root)
83
+ report = compute_report(project_root, now=now, allocation=allocation)
84
+ rendered = render_report(report)
85
+
86
+ if allocation.enforcement != "enforce":
87
+ return 0, (
88
+ f"{rendered}\n"
89
+ "verify_capacity: OK -- advisory posture "
90
+ f"(enforcement={allocation.enforcement!r}); deferring to ordering."
91
+ )
92
+
93
+ if not report.configured:
94
+ return 0, (
95
+ f"{rendered}\n"
96
+ "verify_capacity: OK -- no capacityAllocation buckets configured."
97
+ )
98
+
99
+ if report.advisory_mode:
100
+ return 0, (
101
+ f"{rendered}\n"
102
+ "verify_capacity: OK -- sample below minSampleSize "
103
+ f"({report.classified_completions}/{report.min_sample_size}); "
104
+ "capacity stays advisory until enough classified completions accrue."
105
+ )
106
+
107
+ worst_id, worst = _worst_deficit(report)
108
+ if worst > DEFICIT_TOLERANCE:
109
+ return 1, (
110
+ f"{rendered}\n"
111
+ f"verify_capacity: DEFICIT -- bucket {worst_id!r} is starved by "
112
+ f"{worst:.2f} (enforce posture; tolerance {DEFICIT_TOLERANCE}). "
113
+ "Prioritize that bucket or relax its target."
114
+ )
115
+
116
+ return 0, (
117
+ f"{rendered}\n"
118
+ "verify_capacity: OK -- all buckets within target tolerance."
119
+ )
120
+
121
+
122
+ def _build_parser() -> argparse.ArgumentParser:
123
+ parser = argparse.ArgumentParser(
124
+ prog="verify_capacity.py",
125
+ description=(
126
+ "Three-state ADVISORY capacity gate (#1419 Slice 4). Exits 0 in the "
127
+ "default advise posture (and on insufficient sample / unconfigured "
128
+ "policy); exits 1 only under an explicit enforce posture with a "
129
+ "sampled deficit; exits 2 on config error. Not wired into "
130
+ "`task check` -- capacity must never fail-closed on the framework tree."
131
+ ),
132
+ )
133
+ parser.add_argument(
134
+ "--project-root",
135
+ default=".",
136
+ help="Project root path (default: current working directory).",
137
+ )
138
+ parser.add_argument(
139
+ "--quiet",
140
+ action="store_true",
141
+ help="Suppress the OK message (errors / deficits still print).",
142
+ )
143
+ return parser
144
+
145
+
146
+ def main(argv: list[str] | None = None) -> int:
147
+ parser = _build_parser()
148
+ args = parser.parse_args(argv)
149
+ project_root = Path(args.project_root).resolve()
150
+ code, message = evaluate(project_root)
151
+ if code == 0:
152
+ if not args.quiet:
153
+ print(message)
154
+ else:
155
+ print(message, file=sys.stderr)
156
+ return code
157
+
158
+
159
+ if __name__ == "__main__":
160
+ sys.exit(main())