@deftai/directive-content 0.59.0 → 0.60.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 (184) hide show
  1. package/.githooks/pre-push +10 -9
  2. package/Taskfile.yml +48 -58
  3. package/UPGRADING.md +1 -1
  4. package/docs/assets/directive-lifecycle-diagram.png +0 -0
  5. package/docs/directive-lifecycle.md +73 -0
  6. package/docs/getting-started.md +5 -1
  7. package/package.json +3 -3
  8. package/packs/skills/skills-pack-0.1.json +22 -22
  9. package/scm/github.md +20 -2
  10. package/tasks/change.yml +16 -31
  11. package/tasks/ci.yml +8 -0
  12. package/tasks/commit.yml +12 -19
  13. package/tasks/core.yml +10 -0
  14. package/tasks/engine.yml +42 -0
  15. package/tasks/framework.yml +3 -0
  16. package/tasks/install.yml +20 -19
  17. package/tasks/migrate.yml +26 -15
  18. package/tasks/project.yml +16 -0
  19. package/tasks/toolchain.yml +15 -5
  20. package/tasks/vbrief.yml +4 -3
  21. package/tasks/verify.yml +12 -14
  22. package/scripts/_agents_md.py +0 -494
  23. package/scripts/_cache_fetch.py +0 -635
  24. package/scripts/_cache_quota.py +0 -529
  25. package/scripts/_cache_refresh.py +0 -163
  26. package/scripts/_cache_validate.py +0 -209
  27. package/scripts/_content_root.py +0 -42
  28. package/scripts/_doctor_state.py +0 -277
  29. package/scripts/_event_detect.py +0 -305
  30. package/scripts/_events.py +0 -514
  31. package/scripts/_lifecycle_hygiene.py +0 -568
  32. package/scripts/_pathspec.py +0 -91
  33. package/scripts/_policy_show_cli.py +0 -266
  34. package/scripts/_precutover.py +0 -92
  35. package/scripts/_project_context.py +0 -224
  36. package/scripts/_project_definition_io.py +0 -164
  37. package/scripts/_relocate_snapshot.py +0 -209
  38. package/scripts/_relocate_states.py +0 -343
  39. package/scripts/_resolve_preflight_path.py +0 -152
  40. package/scripts/_safe_subprocess.py +0 -167
  41. package/scripts/_session_start_hook.py +0 -205
  42. package/scripts/_sor_gate_diff.py +0 -365
  43. package/scripts/_stdio_utf8.py +0 -59
  44. package/scripts/_triage_bootstrap_gitignore.py +0 -904
  45. package/scripts/_triage_classify_cli.py +0 -122
  46. package/scripts/_triage_queue_cli.py +0 -625
  47. package/scripts/_triage_scope_cli.py +0 -343
  48. package/scripts/_triage_scope_drift_cli.py +0 -121
  49. package/scripts/_triage_scope_ignores.py +0 -286
  50. package/scripts/_triage_scope_milestone.py +0 -432
  51. package/scripts/_triage_scope_mutations.py +0 -337
  52. package/scripts/_triage_scope_renderers.py +0 -207
  53. package/scripts/_triage_smoketest_stages.py +0 -674
  54. package/scripts/_triage_subscribe_cli.py +0 -140
  55. package/scripts/_triage_welcome_cli.py +0 -421
  56. package/scripts/_vbrief_build.py +0 -239
  57. package/scripts/_vbrief_fidelity.py +0 -479
  58. package/scripts/_vbrief_legacy.py +0 -589
  59. package/scripts/_vbrief_reconciliation.py +0 -883
  60. package/scripts/_vbrief_routing.py +0 -277
  61. package/scripts/_vbrief_safety.py +0 -778
  62. package/scripts/_vbrief_sources.py +0 -312
  63. package/scripts/_vbrief_speckit.py +0 -262
  64. package/scripts/_vbrief_story_quality.py +0 -353
  65. package/scripts/_vbrief_validation.py +0 -299
  66. package/scripts/build_dist.py +0 -412
  67. package/scripts/cache.py +0 -1078
  68. package/scripts/cache_scanner.py +0 -745
  69. package/scripts/candidates_log.py +0 -432
  70. package/scripts/capacity_backfill.py +0 -680
  71. package/scripts/capacity_show.py +0 -653
  72. package/scripts/ci_local.py +0 -689
  73. package/scripts/code_structure_validate.py +0 -765
  74. package/scripts/codebase_default_extractor.py +0 -495
  75. package/scripts/codebase_map.py +0 -304
  76. package/scripts/codebase_map_fresh.py +0 -104
  77. package/scripts/codebase_projection_registry.py +0 -94
  78. package/scripts/codebase_provider.py +0 -582
  79. package/scripts/doctor.py +0 -2552
  80. package/scripts/framework_commands.py +0 -505
  81. package/scripts/gh_rest.py +0 -882
  82. package/scripts/github_auth_modes.py +0 -437
  83. package/scripts/github_body.py +0 -292
  84. package/scripts/ip_risk.py +0 -531
  85. package/scripts/issue_emit.py +0 -670
  86. package/scripts/issue_ingest.py +0 -1064
  87. package/scripts/migrate_preflight.py +0 -418
  88. package/scripts/migrate_vbrief.py +0 -2677
  89. package/scripts/monitor_pr.py +0 -401
  90. package/scripts/pack_migrate_lessons.py +0 -336
  91. package/scripts/pack_migrate_patterns.py +0 -254
  92. package/scripts/pack_migrate_rules.py +0 -350
  93. package/scripts/pack_migrate_skills.py +0 -423
  94. package/scripts/pack_migrate_strategies.py +0 -311
  95. package/scripts/pack_migrate_swarm_spec.py +0 -250
  96. package/scripts/pack_render.py +0 -434
  97. package/scripts/packs_slice.py +0 -712
  98. package/scripts/platform_capabilities.py +0 -336
  99. package/scripts/policy.py +0 -2826
  100. package/scripts/policy_set.py +0 -324
  101. package/scripts/pr_check_closing_keywords.py +0 -524
  102. package/scripts/pr_check_protected_issues.py +0 -267
  103. package/scripts/pr_merge_readiness.py +0 -1004
  104. package/scripts/pr_wait_mergeable.py +0 -669
  105. package/scripts/prd_render.py +0 -159
  106. package/scripts/preflight_architecture_sor.py +0 -974
  107. package/scripts/preflight_branch.py +0 -289
  108. package/scripts/preflight_cache.py +0 -974
  109. package/scripts/preflight_gh.py +0 -721
  110. package/scripts/preflight_implementation.py +0 -272
  111. package/scripts/preflight_story_start.py +0 -838
  112. package/scripts/preflight_wip_cap.py +0 -149
  113. package/scripts/probe_session.py +0 -545
  114. package/scripts/project_render.py +0 -293
  115. package/scripts/quarantine_ext.py +0 -237
  116. package/scripts/reconcile_issues.py +0 -1442
  117. package/scripts/refresh-path.ps1 +0 -107
  118. package/scripts/release.py +0 -2030
  119. package/scripts/release_e2e.py +0 -1011
  120. package/scripts/release_publish.py +0 -486
  121. package/scripts/release_rollback.py +0 -980
  122. package/scripts/relocate.py +0 -1034
  123. package/scripts/resolve_changelog_unreleased.py +0 -667
  124. package/scripts/resolve_version.py +0 -490
  125. package/scripts/resume_conditions.py +0 -706
  126. package/scripts/ritual_sentinel.py +0 -609
  127. package/scripts/roadmap_render.py +0 -635
  128. package/scripts/rule_ownership_lint.py +0 -325
  129. package/scripts/scm.py +0 -591
  130. package/scripts/scope_audit_log.py +0 -387
  131. package/scripts/scope_decompose.py +0 -654
  132. package/scripts/scope_demote.py +0 -509
  133. package/scripts/scope_lifecycle.py +0 -1126
  134. package/scripts/scope_undo.py +0 -772
  135. package/scripts/session_start.py +0 -406
  136. package/scripts/setup_ghx.py +0 -339
  137. package/scripts/setup_windows.ps1 +0 -220
  138. package/scripts/slice_audit.py +0 -585
  139. package/scripts/slice_record.py +0 -530
  140. package/scripts/slice_record_existing.py +0 -692
  141. package/scripts/slug_normalize.py +0 -178
  142. package/scripts/spec_render.py +0 -477
  143. package/scripts/spec_validate.py +0 -238
  144. package/scripts/subagent_monitor.py +0 -658
  145. package/scripts/swarm_complete_cohort.py +0 -644
  146. package/scripts/swarm_launch.py +0 -1206
  147. package/scripts/swarm_readiness.py +0 -554
  148. package/scripts/swarm_verify_review_clean.py +0 -438
  149. package/scripts/swarm_worktrees.py +0 -497
  150. package/scripts/toolchain-check.py +0 -52
  151. package/scripts/triage_actions.py +0 -871
  152. package/scripts/triage_bootstrap.py +0 -1153
  153. package/scripts/triage_bulk.py +0 -630
  154. package/scripts/triage_classify.py +0 -932
  155. package/scripts/triage_help.py +0 -1685
  156. package/scripts/triage_queue.py +0 -1944
  157. package/scripts/triage_reconcile.py +0 -581
  158. package/scripts/triage_refresh.py +0 -643
  159. package/scripts/triage_scope.py +0 -999
  160. package/scripts/triage_scope_drift.py +0 -575
  161. package/scripts/triage_smoketest.py +0 -396
  162. package/scripts/triage_subscribe.py +0 -399
  163. package/scripts/triage_summary.py +0 -1011
  164. package/scripts/triage_welcome.py +0 -1178
  165. package/scripts/ts_check_lane.py +0 -86
  166. package/scripts/validate-links.py +0 -64
  167. package/scripts/validate_strategy_output.py +0 -212
  168. package/scripts/vbrief_activate.py +0 -228
  169. package/scripts/vbrief_migrate_conformance.py +0 -368
  170. package/scripts/vbrief_reconcile_graph.py +0 -306
  171. package/scripts/vbrief_reconcile_labels.py +0 -460
  172. package/scripts/vbrief_reconcile_umbrellas.py +0 -741
  173. package/scripts/vbrief_validate.py +0 -1144
  174. package/scripts/verify-stubs.py +0 -61
  175. package/scripts/verify_capacity.py +0 -160
  176. package/scripts/verify_encoding.py +0 -699
  177. package/scripts/verify_hooks_installed.py +0 -206
  178. package/scripts/verify_investigation.py +0 -360
  179. package/scripts/verify_judgment_gates.py +0 -827
  180. package/scripts/verify_no_task_runtime.py +0 -171
  181. package/scripts/verify_scm_boundary.py +0 -509
  182. package/scripts/verify_session_ritual.py +0 -389
  183. package/scripts/verify_tools.py +0 -426
  184. package/scripts/verify_vbrief_conformance.py +0 -478
package/scm/github.md CHANGED
@@ -214,6 +214,26 @@ Following a v1.0.0 release, commits:
214
214
  - ⊗ Allow force pushes
215
215
  - ⊗ Allow deletions
216
216
 
217
+ ## ghx cache proxy (#884)
218
+
219
+ [ghx](https://github.com/brunoborges/ghx) is a **supported, recommended** read-only cache proxy for the GitHub CLI. Deft's SCM layer (`resolveBinary` in `@deftai/directive-core/scm`) prefers `ghx` over `gh` when both are on PATH, so consumers benefit automatically once ghx is installed. ghx is optional for consumer projects — only `gh` is required — but strongly recommended for maintainers and multi-agent swarms that issue many read-only `gh api` / `gh issue view` calls.
220
+
221
+ **Install (consent-gated, default deny):**
222
+
223
+ ```bash
224
+ directive setup:ghx # interactive y/N prompt (default: no)
225
+ task setup:ghx # same via Taskfile
226
+ task setup:ghx -- --yes # non-interactive CI / scripted approval
227
+ ```
228
+
229
+ `task setup` runs a detection-only `--check` pass and nudges when `gh` is present but `ghx` is missing. Set `DEFT_SETUP_GHX_SKIP=1` to suppress the interactive install path in non-interactive shells.
230
+
231
+ **Surface rules:**
232
+
233
+ - ! Prefer `ghx` over `gh` for read-only GET operations when ghx is on PATH
234
+ - ! Use live `gh` for mutations (POST/PATCH/PUT/DELETE) and for immediate read-back after a mutation — ghx is a cached GET proxy only
235
+ - ⊗ Use `ghx api` for multi-arg write invocations — ghx accepts a single positional path arg; writes fall through to `gh`
236
+
217
237
  ## Destructive gh verbs (#1019)
218
238
 
219
239
  A detection-bound gate (`scripts/preflight_gh.py`) refuses three classes of destructive surface before they execute, complementing the #747 branch-protection gate which already refuses commits to the default branch:
@@ -234,8 +254,6 @@ Three enforcement surfaces back the gate:
234
254
  - For repo deletion specifically: prefer the GitHub web UI's archive-or-delete prompt -- archiving is reversible, the gate is not opining on it.
235
255
  - For an admin merge: the canonical recovery is to request review through the normal flow. The `--admin` flag is gated because the most-common legitimate use case (release hot-fix) is rare enough that documenting an explicit bypass is cheaper than letting the verb pass by default.
236
256
 
237
- **Out of scope (v1):** a PATH-shim that intercepts `gh` at the command layer is deferred -- the consent-gated install path mirrors `setup_ghx.py` (#884) and lands additively when a follow-up issue is opened. The current gate is detection-bound (pre-push hook + agent-side `--command` classifier + self-test contract) rather than execution-bound, which is sufficient to refuse the recurring failure mode that motivated #1019 (an agent with an unrestricted `gh` token executing a destructive verb).
238
-
239
257
  ## Release Workflow (UCCPR)
240
258
 
241
259
  **UCCPR** = Update Changelog, Commit, Push, Release
package/tasks/change.yml CHANGED
@@ -3,44 +3,29 @@ version: '3'
3
3
  vars:
4
4
  # Per ../Taskfile.yml header: joinPath is evaluated eagerly by go-task
5
5
  # templating and yields a native-separator absolute path so {{.DEFT_ROOT}}
6
- # resolves correctly under uv on Windows (#566). Used here to pin
7
- # `uv --project` against ancestor pyproject.toml leakage (#1011).
6
+ # resolves correctly under node on Windows (#566).
8
7
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
9
8
 
10
9
  tasks:
10
+ _ts-build:
11
+ internal: true
12
+ desc: "Build @deftai/cli dist/ before TS-backed gates run (#1828 s2)."
13
+ dir: '{{.USER_WORKING_DIR}}'
14
+ cmds:
15
+ - pnpm --dir "{{.DEFT_ROOT}}" run build
16
+
11
17
  changelog:check:
12
18
  desc: Verify CHANGELOG.md has an [Unreleased] section with at least one entry
13
- env:
14
- PYTHONUTF8: "1"
19
+ dir: '{{.USER_WORKING_DIR}}'
20
+ deps:
21
+ - _ts-build
15
22
  cmds:
16
- - cmd: >-
17
- uv --project "{{.DEFT_ROOT}}" run python -c
18
- "import sys, pathlib, re;
19
- p = pathlib.Path('CHANGELOG.md');
20
- (not p.exists()) and (print('FAIL: CHANGELOG.md not found'), sys.exit(1));
21
- text = p.read_text('utf-8');
22
- m = re.search(r'## \[Unreleased\][ \t]*\n(.*?)(?=\n## \[|$)', text, re.DOTALL);
23
- (m is None) and (print('FAIL: No [Unreleased] section found in CHANGELOG.md'), sys.exit(1));
24
- body = m.group(1);
25
- entries = [l for l in body.splitlines() if l.strip().startswith('- ')];
26
- (len(entries) == 0) and (print('FAIL: [Unreleased] section has no entries (no lines starting with \"- \")'), sys.exit(1));
27
- print(f'OK: CHANGELOG.md [Unreleased] section has {len(entries)} entries')"
23
+ - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" changelog-check --project-root "{{.USER_WORKING_DIR}}"
28
24
 
29
25
  change:init:
30
26
  desc: Create a new change proposal directory structure in history/changes/<name>/
27
+ dir: '{{.USER_WORKING_DIR}}'
28
+ deps:
29
+ - _ts-build
31
30
  cmds:
32
- - cmd: >-
33
- uv --project "{{.DEFT_ROOT}}" run python -c
34
- "import sys, pathlib, json, re;
35
- name = '{{.CLI_ARGS}}'.strip();
36
- (not name) and (print('FAIL: Usage: task change:init -- <name>'), sys.exit(1));
37
- (not re.match(r'^[\w][\w-]*$', name)) and (print('FAIL: Name must contain only alphanumeric characters, underscores, and hyphens'), sys.exit(1));
38
- base = pathlib.Path('history/changes') / name;
39
- base.exists() and (print(f'FAIL: {base} already exists'), sys.exit(1));
40
- (base / 'specs').mkdir(parents=True, exist_ok=True);
41
- proposal = {'vBRIEFInfo': {'version': '0.5'}, 'plan': {'title': name, 'status': 'draft', 'narratives': {'Problem': 'What is wrong or missing.', 'Change': 'What this proposal does about it.', 'Scope': 'In scope: ... Out of scope: ...', 'Impact': 'What existing code/specs are affected.', 'Risks': 'What could go wrong.', 'Approach': 'How to implement the change.', 'Alternatives': 'What else was considered and why not.', 'Dependencies': 'What must exist before this works.'}}};
42
- (base / 'proposal.vbrief.json').write_text(json.dumps(proposal, indent=2) + chr(10), encoding='utf-8');
43
- tasks = {'vBRIEFInfo': {'version': '0.5'}, 'plan': {'title': name, 'status': 'draft', 'items': [], 'edges': []}};
44
- (base / 'tasks.vbrief.json').write_text(json.dumps(tasks, indent=2) + chr(10), encoding='utf-8');
45
- print(f'OK: Created change proposal at {base}/');
46
- [print(f' - {f}') for f in ['proposal.vbrief.json', 'tasks.vbrief.json', 'specs/']]"
31
+ - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" change-init --project-root "{{.USER_WORKING_DIR}}" --name {{.CLI_ARGS}}
package/tasks/ci.yml CHANGED
@@ -1,5 +1,13 @@
1
1
  version: '3'
2
2
 
3
+ # Maintainer-only local CI mirror (#1813 contributor path / #2022 Phase 2).
4
+ #
5
+ # `ci:local` shells into scripts/ci_local.py via `uv run python`. Release
6
+ # Step-5 pre-flight now uses the TS `task check` path (py-purge-ci-local-ts);
7
+ # this fragment remains for explicit maintainer local CI only. Included from
8
+ # the root Taskfile with `internal: true` — not wired into `check:consumer`
9
+ # or the default `task check` aggregate.
10
+
3
11
  vars:
4
12
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
5
13
 
package/tasks/commit.yml CHANGED
@@ -3,28 +3,21 @@ version: '3'
3
3
  vars:
4
4
  # Per ../Taskfile.yml header: joinPath is evaluated eagerly by go-task
5
5
  # templating and yields a native-separator absolute path so {{.DEFT_ROOT}}
6
- # resolves correctly under uv on Windows (#566). Used here to pin
7
- # `uv --project` against ancestor pyproject.toml leakage (#1011).
6
+ # resolves correctly under node on Windows (#566).
8
7
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
9
8
 
10
9
  tasks:
10
+ _ts-build:
11
+ internal: true
12
+ desc: "Build @deftai/cli dist/ before TS-backed gates run (#1828 s2)."
13
+ dir: '{{.USER_WORKING_DIR}}'
14
+ cmds:
15
+ - pnpm --dir "{{.DEFT_ROOT}}" run build
16
+
11
17
  commit:lint:
12
18
  desc: Validate HEAD commit message against conventional commit format
19
+ dir: '{{.USER_WORKING_DIR}}'
20
+ deps:
21
+ - _ts-build
13
22
  cmds:
14
- - cmd: >-
15
- uv --project "{{.DEFT_ROOT}}" run python -c
16
- "import sys, re, subprocess;
17
- result = subprocess.run(['git', 'log', '--format=%B', '-1'], capture_output=True, text=True);
18
- (result.returncode != 0) and (print('FAIL: Could not read HEAD commit message'), sys.exit(1));
19
- msg = result.stdout.strip();
20
- subject = msg.splitlines()[0] if msg else '';
21
- types = 'feat|fix|docs|chore|refactor|test|style|perf|ci|build|revert';
22
- pattern = r'^(' + types + r')(\(.+\))?!?: .+';
23
- ok = re.match(pattern, subject);
24
- (not ok) and (print('FAIL: Commit message does not match conventional commit format'),
25
- print(f' Got: {subject}'),
26
- print(f' Expected: type(scope): description'),
27
- print(f' Types: feat, fix, docs, chore, refactor, test, style, perf, ci, build, revert'),
28
- sys.exit(1));
29
- print(f'OK: Commit message is valid conventional commit');
30
- print(f' Subject: {subject}')"
23
+ - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" commit-lint --project-root "{{.USER_WORKING_DIR}}"
package/tasks/core.yml CHANGED
@@ -1,5 +1,15 @@
1
1
  version: '3'
2
2
 
3
+ # Maintainer-only Python self-test lane (#1813 contributor path / #2022 Phase 2).
4
+ #
5
+ # pytest, ruff, black, and mypy run here via `uv run` for framework-source-repo
6
+ # pre-commit checks. This fragment is included from the root Taskfile with
7
+ # `internal: true` so `core:*` tasks are NOT listed or callable from the CLI on
8
+ # consumer installs — only `task check:framework-source` wires them as deps.
9
+ #
10
+ # Consumer `task check` dispatches to `check:consumer` (TS / deft verbs only).
11
+ # Do NOT add these tasks to the consumer check aggregate.
12
+
3
13
  vars:
4
14
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
5
15
 
@@ -0,0 +1,42 @@
1
+ version: '3'
2
+
3
+ # Consumer engine resolution (#2022 Phase 3).
4
+ #
5
+ # Framework-source checkouts invoke the vendored `packages/cli/dist/bin.js`.
6
+ # npm consumer deposits copy @deftai/directive-content only — no bundled CLI —
7
+ # so tasks fall back to the globally installed `deft` / `directive` command.
8
+
9
+ vars:
10
+ DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
11
+
12
+ tasks:
13
+ _ts-build:
14
+ internal: true
15
+ desc: "Build CLI dist when running from the framework source checkout; no-op on npm consumer deposits (#2022 Phase 3)."
16
+ dir: '{{.DEFT_ROOT}}'
17
+ cmds:
18
+ - |
19
+ set -eu
20
+ if [ -f packages/cli/dist/bin.js ]; then
21
+ pnpm run build
22
+ fi
23
+
24
+ invoke:
25
+ internal: true
26
+ desc: "Run a deft-ts verb from vendored bin.js (source checkout) or global deft (npm consumer deposit)."
27
+ # Run from the operator project root so deft verbs resolve USER_WORKING_DIR
28
+ # correctly; without this, included engine.yml defaults cwd to tasks/ (#2022).
29
+ dir: '{{.USER_WORKING_DIR}}'
30
+ cmds:
31
+ - |
32
+ set -eu
33
+ bin="{{.DEFT_ROOT}}/packages/cli/dist/bin.js"
34
+ if [ -f "$bin" ]; then
35
+ node "$bin" {{.ENGINE_CMD}}
36
+ elif command -v deft >/dev/null 2>&1; then
37
+ deft {{.ENGINE_CMD}}
38
+ else
39
+ echo "deft: neither {{.DEFT_ROOT}}/packages/cli/dist/bin.js nor a global deft command is available." >&2
40
+ echo " Install with: npm i -g @deftai/directive" >&2
41
+ exit 2
42
+ fi
@@ -13,6 +13,9 @@ version: '3'
13
13
  # `cmds:` skip would silently discard the recovery flag.
14
14
 
15
15
  vars:
16
+ # Per ../Taskfile.yml header: joinPath is evaluated eagerly by go-task
17
+ # templating and yields a native-separator absolute path so {{.DEFT_ROOT}}
18
+ # resolves correctly under node on Windows (#566).
16
19
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
17
20
 
18
21
  tasks:
package/tasks/install.yml CHANGED
@@ -3,11 +3,17 @@ version: '3'
3
3
  vars:
4
4
  # Per ../Taskfile.yml header: joinPath is evaluated eagerly by go-task
5
5
  # templating and yields a native-separator absolute path so {{.DEFT_ROOT}}
6
- # resolves correctly under uv on Windows (#566). Used here to pin
7
- # `uv --project` against ancestor pyproject.toml leakage (#1011).
6
+ # resolves correctly under node on Windows (#566).
8
7
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
9
8
 
10
9
  tasks:
10
+ _ts-build:
11
+ internal: true
12
+ desc: "Build @deftai/cli dist/ before TS-backed gates run (#1828 s2)."
13
+ dir: '{{.USER_WORKING_DIR}}'
14
+ cmds:
15
+ - pnpm --dir "{{.DEFT_ROOT}}" run build
16
+
11
17
  install:
12
18
  desc: Install deft (dev convenience -- end users should use the compiled binary from GitHub Releases)
13
19
  cmds:
@@ -15,23 +21,18 @@ tasks:
15
21
 
16
22
  uninstall:
17
23
  desc: Remove deft entry from AGENTS.md
24
+ dir: '{{.USER_WORKING_DIR}}'
25
+ deps:
26
+ - _ts-build
18
27
  cmds:
19
- - cmd: >-
20
- uv --project "{{.DEFT_ROOT}}" run python -c "from pathlib import Path;
21
- f=Path('AGENTS.md');
22
- t=f.read_text('utf-8') if f.exists() else '';
23
- lines=t.splitlines(keepends=True);
24
- out=''.join(l for l in lines if not l.startswith('See deft/main.md') and not l.startswith('Skills: deft/skills/'));
25
- f.write_text(out,'utf-8') if f.exists() else None;
26
- print('Removed deft entry from AGENTS.md' if out!=t else 'No deft entry found in AGENTS.md')"
28
+ - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" install-uninstall --project-root "{{.USER_WORKING_DIR}}"
27
29
 
28
- # User-facing upgrade entrypoint (#1061). Wraps the canonical
29
- # ``run upgrade`` command (`cmd_upgrade` in ./run) which:
30
+ # User-facing upgrade entrypoint (#1061). Native deft-ts handler (#2022 Phase 2):
30
31
  # 1. Writes / refreshes the bare ``.deft-version`` marker.
31
32
  # 2. Writes the canonical YAML provenance manifest at
32
33
  # ``<install>/VERSION`` (#1046 PR-B AC-4) -- including the
33
34
  # ``install_root`` field added in #1062.
34
- # 3. Delegates to ``cmd_agents_refresh`` so the AGENTS.md managed
35
+ # 3. Delegates to ``agents:refresh`` so the AGENTS.md managed
35
36
  # section is brought to the current rendered template (v3 marker
36
37
  # with sha/refreshed/session attributes, #1046 PR-B AC-5).
37
38
  # This wrapper exists so the ``framework:doctor`` failure prose and
@@ -43,18 +44,18 @@ tasks:
43
44
  # ``generates:`` because the task is mutating + must run on every
44
45
  # invocation. CLI_ARGS is explicitly cleared (``vars: { CLI_ARGS: "" }``)
45
46
  # so any operator-supplied ``-- <flags>`` are deterministically dropped
46
- # before reaching ``run upgrade``: go-task only forwards ``{{.CLI_ARGS}}``
47
+ # before reaching the upgrade handler: go-task only forwards ``{{.CLI_ARGS}}``
47
48
  # when a ``cmds`` line references it, but pinning the var to empty makes
48
49
  # the contract explicit AND defends against a future edit that
49
50
  # accidentally appends ``{{.CLI_ARGS}}`` to the dispatch line (SLizard P1
50
- # on PR #1067 -- ``cmd_upgrade`` does not currently accept flags; future
51
+ # on PR #1067 -- the upgrade handler does not currently accept flags; future
51
52
  # flag additions land deliberately, not implicitly via Taskfile drift).
52
53
  upgrade:
53
- desc: "Upgrade deft framework: refresh AGENTS.md to current marker, write canonical install manifest, regenerate .deft-version derivative (#1061). Wraps `run upgrade`."
54
+ desc: "Upgrade deft framework: refresh AGENTS.md to current marker, write canonical install manifest, regenerate .deft-version derivative (#1061). Dispatches via deft-ts install-upgrade."
54
55
  dir: '{{.USER_WORKING_DIR}}'
55
- env:
56
- PYTHONUTF8: "1"
57
56
  vars:
58
57
  CLI_ARGS: ""
58
+ deps:
59
+ - _ts-build
59
60
  cmds:
60
- - uv --project "{{.DEFT_ROOT}}" run python "{{.DEFT_ROOT}}/run" upgrade
61
+ - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" install-upgrade --project-root "{{.USER_WORKING_DIR}}" --framework-root "{{.DEFT_ROOT}}"
package/tasks/migrate.yml CHANGED
@@ -1,13 +1,22 @@
1
1
  version: '3'
2
2
 
3
3
  vars:
4
- # See deft/Taskfile.yml for the rationale behind per-subfile DEFT_ROOT
5
- # (go-task re-evaluates var templates at use site; joinPath is eager and
6
- # produces a clean, native-separator path so `uv --project "{{.DEFT_ROOT}}" run python` resolves it
7
- # correctly on Windows -- #566).
4
+ # Per ../Taskfile.yml header: joinPath is evaluated eagerly by go-task
5
+ # templating and yields a native-separator absolute path so {{.DEFT_ROOT}}
6
+ # resolves correctly under node on Windows (#566).
8
7
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
9
8
 
10
9
  tasks:
10
+ _ts-build:
11
+ internal: true
12
+ desc: "Build @deftai/cli dist/ before TS-backed gates run (#1828 s2)."
13
+ # Match scope.yml _ensure-ts: run from USER_WORKING_DIR with pnpm --dir so
14
+ # Windows consumer invocations via `-t <abs Taskfile>` do not double-prefix
15
+ # DEFT_ROOT under go-task's dir: handling (#566 / Windows CI regression).
16
+ dir: '{{.USER_WORKING_DIR}}'
17
+ cmds:
18
+ - pnpm --dir "{{.DEFT_ROOT}}" run build
19
+
11
20
  preflight:
12
21
  # Agent-side environment preflight for `task migrate:vbrief` (#793).
13
22
  # Reifies the prose contract documented in
@@ -18,16 +27,19 @@ tasks:
18
27
  # any destructive mutation runs. Three-state exit (0 ready / 1 not-ready / 2 config
19
28
  # error) mirrors `scripts/preflight_branch.py` (#747).
20
29
  #
30
+ # Consumer path dispatches through the native deft-ts handler (#2022 Phase 2);
31
+ # the legacy Python script remains for maintainer parity only.
32
+ #
21
33
  # NO `sources:` / `generates:` per `conventions/task-caching.md`: the
22
34
  # script forwards user-facing CLI flags (`--project-root`, `--deft-root`,
23
35
  # `--quiet`) via `{{.CLI_ARGS}}` and a cached cmds skip would silently
24
36
  # swallow them.
25
37
  desc: "Verify environment readiness for `task migrate:vbrief` (uv on PATH, v0.20+ layout, document model, git tree). Three-state exit (#793)."
26
38
  dir: '{{.USER_WORKING_DIR}}'
27
- env:
28
- PYTHONUTF8: "1"
39
+ deps:
40
+ - _ts-build
29
41
  cmds:
30
- - uv --project "{{.DEFT_ROOT}}" run --frozen python "{{.DEFT_ROOT}}/scripts/migrate_preflight.py" --project-root "{{.USER_WORKING_DIR}}" --deft-root "{{.DEFT_ROOT}}" {{.CLI_ARGS}}
42
+ - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" migrate-preflight --project-root "{{.USER_WORKING_DIR}}" --deft-root "{{.DEFT_ROOT}}" {{.CLI_ARGS}}
31
43
 
32
44
  vbrief:
33
45
  desc: >
@@ -44,12 +56,15 @@ tasks:
44
56
  run::_check_upgrade_gate is consulted by the CLI flow). See
45
57
  events/registry.json for the payload contracts and `DEFT_EVENT_LOG` for
46
58
  opt-in JSON-line capture (#635).
59
+ #2013 HOLDOUT: `migrate:vbrief` remains the sole consumer-path Python
60
+ entrypoint until the spec-authority umbrella resolves the
61
+ `migrate_vbrief.py` port-vs-cutoff decision (#2022 Phase 2).
47
62
  deps:
48
63
  # #793: gate destructive migration on the environment preflight. A
49
64
  # non-zero exit from the preflight task aborts this task before any
50
65
  # `cmds:` line runs. Operator-supplied `{{.CLI_ARGS}}` (e.g.
51
66
  # `--dry-run`, `--force`, `--rollback`, `--strict`) belong to the
52
- # migrator and are NOT valid migrate_preflight.py flags. go-task
67
+ # migrator and are NOT valid migrate:preflight flags. go-task
53
68
  # forwards parent CLI_ARGS into dependency tasks by default, so we
54
69
  # explicitly clear CLI_ARGS here; otherwise `task migrate:vbrief --
55
70
  # --dry-run` reaches the preflight argparse surface as
@@ -63,11 +78,7 @@ tasks:
63
78
  env:
64
79
  PYTHONUTF8: "1"
65
80
  cmds:
66
- # Pass Taskfile CLI args through so operators can opt into safety flags
67
- # (#497) or --strict reconciliation (#496) without editing this file.
68
- # Script path uses {{.DEFT_ROOT}} (defined locally in this file's
69
- # `vars:` block above via `joinPath .TASKFILE_DIR ".."` -- see
70
- # ../Taskfile.yml for why root-level definition is avoided) rather
71
- # than {{.TASKFILE_DIR}}/.. to keep the path traversal-free; the
72
- # mixed-separator form breaks `uv --project "{{.DEFT_ROOT}}" run python` on Windows (#566).
81
+ # #2013 holdout: migrate_vbrief.py stays on the consumer path until the
82
+ # spec-authority umbrella closes the port-vs-cutoff decision (#2022).
83
+ # Preflight is TS-native; the migrator body remains Python for now.
73
84
  - uv --project "{{.DEFT_ROOT}}" run python "{{.DEFT_ROOT}}/scripts/migrate_vbrief.py" "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}
package/tasks/project.yml CHANGED
@@ -9,6 +9,12 @@ vars:
9
9
  # own repo root when invoked via ``includes:`` -- consumers got their data
10
10
  # scanned from ``deft/vbrief/``. Switched to ``{{.USER_WORKING_DIR}}`` to
11
11
  # match the convention used by roadmap:render / spec:render / migrate:vbrief.
12
+ #
13
+ # Staleness acknowledgement (#640): ``task project:ack-staleness`` records a
14
+ # completed-scope watermark on PROJECT-DEFINITION ``plan.metadata.staleness_review``
15
+ # so ``task project:render`` stops re-emitting the same narrative staleness flags
16
+ # after review. This is distinct from ``task reconcile:issues``, which reconciles
17
+ # origin freshness on scope vBRIEFs — not PROJECT-DEFINITION narrative heuristics.
12
18
 
13
19
  tasks:
14
20
  _ts-build:
@@ -25,3 +31,13 @@ tasks:
25
31
  - _ts-build
26
32
  cmds:
27
33
  - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" project-render "{{.USER_WORKING_DIR}}/vbrief"
34
+
35
+ ack-staleness:
36
+ desc: >-
37
+ Acknowledge reviewed PROJECT-DEFINITION narrative staleness (#640).
38
+ Distinct from task reconcile:issues (scope origin freshness).
39
+ dir: '{{.USER_WORKING_DIR}}'
40
+ deps:
41
+ - _ts-build
42
+ cmds:
43
+ - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" project-render --acknowledge-staleness "{{.USER_WORKING_DIR}}/vbrief"
@@ -5,9 +5,19 @@ vars:
5
5
 
6
6
  tasks:
7
7
  check:
8
- desc: Verify required toolchain is installed (go, uv, git, gh, node, pnpm)
9
- deps: [":ts:build"]
10
- env:
11
- PYTHONUTF8: "1"
8
+ desc: Verify required maintainer toolchain is installed (go, uv, git, gh, node, pnpm)
9
+ deps:
10
+ - task: :engine:_ts-build
12
11
  cmds:
13
- - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" toolchain:check
12
+ - task: :engine:invoke
13
+ vars:
14
+ ENGINE_CMD: 'toolchain-check'
15
+
16
+ check-consumer:
17
+ desc: Verify required consumer toolchain is installed (git, gh, node, pnpm, task) without Python/go/uv (#2022 Phase 3).
18
+ deps:
19
+ - task: :engine:_ts-build
20
+ cmds:
21
+ - task: :engine:invoke
22
+ vars:
23
+ ENGINE_CMD: 'toolchain-check --consumer'
package/tasks/vbrief.yml CHANGED
@@ -15,10 +15,11 @@ tasks:
15
15
  desc: Validate vBRIEF lifecycle folder structure and cross-file consistency
16
16
  dir: '{{.USER_WORKING_DIR}}'
17
17
  deps:
18
- - _ts-build
18
+ - task: :engine:_ts-build
19
19
  cmds:
20
- # Oracle/fallback (parity): scripts/vbrief_validate.py (#1828 Wave 8).
21
- - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" vbrief:validate --vbrief-dir "{{.USER_WORKING_DIR}}/vbrief"
20
+ - task: :engine:invoke
21
+ vars:
22
+ ENGINE_CMD: 'vbrief:validate --vbrief-dir "{{.USER_WORKING_DIR}}/vbrief"'
22
23
 
23
24
  preflight:
24
25
  # Implementation-intent preflight wrapper (#810 / PR #812 fixup;
package/tasks/verify.yml CHANGED
@@ -70,15 +70,11 @@ tasks:
70
70
  desc: "Detection-bound branch-protection gate (#747). Reads plan.policy.allowDirectCommitsToMaster from PROJECT-DEFINITION."
71
71
  dir: '{{.USER_WORKING_DIR}}'
72
72
  deps:
73
- - _ts-build
73
+ - task: :engine:_ts-build
74
74
  cmds:
75
- # Oracle/fallback (parity): scripts/preflight_branch.py (#1828 Wave 8).
76
- # `--allow-missing-project-definition` keeps the framework's own check
77
- # green for fresh checkouts that have not yet run `task setup` (the
78
- # bootstrap fallback path documented in #746 acceptance criterion E).
79
- # Production projects with PROJECT-DEFINITION present will still get
80
- # the full enforcement -- the flag is a no-op when the file exists.
81
- - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" verify:branch --project-root "{{.USER_WORKING_DIR}}" --allow-missing-project-definition
75
+ - task: :engine:invoke
76
+ vars:
77
+ ENGINE_CMD: 'verify:branch --project-root "{{.USER_WORKING_DIR}}" --allow-missing-project-definition'
82
78
 
83
79
  routing:
84
80
  desc: "Operator coding sub-agent model routing gate (#1739). Pre-dispatch (default): fails when a dispatched worker role has no decision in .deft/routing.local.json. Pass --advise for the non-blocking session-start disclosure; --roles a,b to widen the gated set; --provider to override the runtime."
@@ -145,7 +141,7 @@ tasks:
145
141
  desc: "Pre-`start_agent` cache-freshness gate (#1127). Refuses implementation dispatch when the triage cache is stale, missing, or the target issue's latest decision is not `accept`. Subscription-aware via plan.policy.triageScope[] (D12 / #1131). Flags: --for-issue N / --max-age-hours N / --allow-stale / --repo OWNER/NAME / --allow-missing-bootstrap (consumed by the framework's own `task check` so a fresh checkout passes -- consumers leave it OFF)."
146
142
  dir: '{{.USER_WORKING_DIR}}'
147
143
  deps:
148
- - _ts-build
144
+ - task: :engine:_ts-build
149
145
  # Per `conventions/task-caching.md` (#574): NO `sources:` / `generates:`
150
146
  # because the gate forwards user-facing flags via {{.CLI_ARGS}}
151
147
  # (--for-issue / --max-age-hours / --allow-stale / --repo) that
@@ -155,8 +151,9 @@ tasks:
155
151
  # `task triage:bootstrap`; consumer projects leave it off so a
156
152
  # missing cache fails their `task check` loudly.
157
153
  cmds:
158
- # Oracle/fallback (parity): scripts/preflight_cache.py --allow-missing-bootstrap (#1854 s5).
159
- - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" preflight-cache --project-root "{{.USER_WORKING_DIR}}" --allow-missing-bootstrap {{.CLI_ARGS}}
154
+ - task: :engine:invoke
155
+ vars:
156
+ ENGINE_CMD: 'preflight-cache --project-root "{{.USER_WORKING_DIR}}" --allow-missing-bootstrap {{.CLI_ARGS}}'
160
157
 
161
158
  codebase-map-fresh:
162
159
  desc: "Drift gate for the generated .planning/codebase/MAP.md projection (#1595 PR4)."
@@ -276,7 +273,7 @@ tasks:
276
273
  desc: "Pre-merge re-validation that pending/+active/ count is within plan.policy.wipCap (#1124 / D4 of #1119). Catches stale-branch merges + --force overrides. Default cap is 10 per umbrella #1119 Current Shape v3. The framework's own task check passes --allow-over-cap during landing-day overage; consumer projects MUST NOT pass that flag."
277
274
  dir: '{{.USER_WORKING_DIR}}'
278
275
  deps:
279
- - _ts-build
276
+ - task: :engine:_ts-build
280
277
  # Per `conventions/task-caching.md` (#574): NO `sources:` /
281
278
  # `generates:` because the gate forwards user-facing flags via
282
279
  # {{.CLI_ARGS}} (--allow-over-cap / --quiet) that go-task's
@@ -288,5 +285,6 @@ tasks:
288
285
  # OFF so a stale-branch / --force-merge over-cap state fails their
289
286
  # `task check` loudly.
290
287
  cmds:
291
- # Oracle/fallback (parity): scripts/preflight_wip_cap.py (#1828 Wave 8).
292
- - node "{{.DEFT_ROOT}}/packages/cli/dist/bin.js" verify:wip-cap --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}
288
+ - task: :engine:invoke
289
+ vars:
290
+ ENGINE_CMD: 'verify:wip-cap --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'