@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.
- package/.githooks/pre-commit +10 -128
- package/.githooks/pre-push +8 -108
- package/Taskfile.yml +48 -58
- package/UPGRADING.md +19 -3
- package/docs/assets/directive-lifecycle-diagram.png +0 -0
- package/docs/directive-lifecycle.md +73 -0
- package/docs/getting-started.md +5 -1
- package/package.json +3 -3
- package/packs/skills/skills-pack-0.1.json +1 -1
- package/packs/strategies/strategies-pack-0.1.json +19 -19
- package/scm/github.md +37 -6
- package/skills/deft-directive-setup/SKILL.md +24 -15
- package/strategies/speckit.md +14 -14
- package/strategies/v0-20-contract.md +12 -1
- package/tasks/change.yml +16 -31
- package/tasks/ci.yml +8 -0
- package/tasks/commit.yml +12 -19
- package/tasks/core.yml +10 -0
- package/tasks/engine.yml +42 -0
- package/tasks/framework.yml +3 -0
- package/tasks/install.yml +20 -19
- package/tasks/migrate.yml +26 -15
- package/tasks/project.yml +26 -0
- package/tasks/toolchain.yml +15 -5
- package/tasks/vbrief.yml +4 -3
- package/tasks/verify.yml +12 -14
- package/templates/agents-entry.md +1 -1
- package/scripts/_agents_md.py +0 -494
- package/scripts/_cache_fetch.py +0 -635
- package/scripts/_cache_quota.py +0 -529
- package/scripts/_cache_refresh.py +0 -163
- package/scripts/_cache_validate.py +0 -209
- package/scripts/_content_root.py +0 -42
- package/scripts/_doctor_state.py +0 -277
- package/scripts/_event_detect.py +0 -305
- package/scripts/_events.py +0 -514
- package/scripts/_lifecycle_hygiene.py +0 -568
- package/scripts/_pathspec.py +0 -91
- package/scripts/_policy_show_cli.py +0 -266
- package/scripts/_precutover.py +0 -92
- package/scripts/_project_context.py +0 -224
- package/scripts/_project_definition_io.py +0 -164
- package/scripts/_relocate_snapshot.py +0 -209
- package/scripts/_relocate_states.py +0 -343
- package/scripts/_resolve_preflight_path.py +0 -152
- package/scripts/_safe_subprocess.py +0 -167
- package/scripts/_session_start_hook.py +0 -205
- package/scripts/_sor_gate_diff.py +0 -365
- package/scripts/_stdio_utf8.py +0 -59
- package/scripts/_triage_bootstrap_gitignore.py +0 -904
- package/scripts/_triage_classify_cli.py +0 -122
- package/scripts/_triage_queue_cli.py +0 -625
- package/scripts/_triage_scope_cli.py +0 -343
- package/scripts/_triage_scope_drift_cli.py +0 -121
- package/scripts/_triage_scope_ignores.py +0 -286
- package/scripts/_triage_scope_milestone.py +0 -432
- package/scripts/_triage_scope_mutations.py +0 -337
- package/scripts/_triage_scope_renderers.py +0 -207
- package/scripts/_triage_smoketest_stages.py +0 -674
- package/scripts/_triage_subscribe_cli.py +0 -140
- package/scripts/_triage_welcome_cli.py +0 -421
- package/scripts/_vbrief_build.py +0 -239
- package/scripts/_vbrief_fidelity.py +0 -479
- package/scripts/_vbrief_legacy.py +0 -589
- package/scripts/_vbrief_reconciliation.py +0 -883
- package/scripts/_vbrief_routing.py +0 -277
- package/scripts/_vbrief_safety.py +0 -778
- package/scripts/_vbrief_sources.py +0 -312
- package/scripts/_vbrief_speckit.py +0 -262
- package/scripts/_vbrief_story_quality.py +0 -353
- package/scripts/_vbrief_validation.py +0 -299
- package/scripts/build_dist.py +0 -412
- package/scripts/cache.py +0 -1078
- package/scripts/cache_scanner.py +0 -745
- package/scripts/candidates_log.py +0 -432
- package/scripts/capacity_backfill.py +0 -680
- package/scripts/capacity_show.py +0 -653
- package/scripts/ci_local.py +0 -689
- package/scripts/code_structure_validate.py +0 -765
- package/scripts/codebase_default_extractor.py +0 -495
- package/scripts/codebase_map.py +0 -304
- package/scripts/codebase_map_fresh.py +0 -104
- package/scripts/codebase_projection_registry.py +0 -94
- package/scripts/codebase_provider.py +0 -582
- package/scripts/doctor.py +0 -2552
- package/scripts/framework_commands.py +0 -505
- package/scripts/gh_rest.py +0 -882
- package/scripts/github_auth_modes.py +0 -437
- package/scripts/github_body.py +0 -292
- package/scripts/ip_risk.py +0 -531
- package/scripts/issue_emit.py +0 -670
- package/scripts/issue_ingest.py +0 -1064
- package/scripts/migrate_preflight.py +0 -418
- package/scripts/migrate_vbrief.py +0 -2677
- package/scripts/monitor_pr.py +0 -401
- package/scripts/pack_migrate_lessons.py +0 -336
- package/scripts/pack_migrate_patterns.py +0 -254
- package/scripts/pack_migrate_rules.py +0 -350
- package/scripts/pack_migrate_skills.py +0 -423
- package/scripts/pack_migrate_strategies.py +0 -311
- package/scripts/pack_migrate_swarm_spec.py +0 -250
- package/scripts/pack_render.py +0 -434
- package/scripts/packs_slice.py +0 -712
- package/scripts/platform_capabilities.py +0 -336
- package/scripts/policy.py +0 -2826
- package/scripts/policy_set.py +0 -324
- package/scripts/pr_check_closing_keywords.py +0 -524
- package/scripts/pr_check_protected_issues.py +0 -267
- package/scripts/pr_merge_readiness.py +0 -1004
- package/scripts/pr_wait_mergeable.py +0 -669
- package/scripts/prd_render.py +0 -159
- package/scripts/preflight_architecture_sor.py +0 -974
- package/scripts/preflight_branch.py +0 -289
- package/scripts/preflight_cache.py +0 -974
- package/scripts/preflight_gh.py +0 -721
- package/scripts/preflight_implementation.py +0 -272
- package/scripts/preflight_story_start.py +0 -838
- package/scripts/preflight_wip_cap.py +0 -149
- package/scripts/probe_session.py +0 -545
- package/scripts/project_render.py +0 -293
- package/scripts/quarantine_ext.py +0 -237
- package/scripts/reconcile_issues.py +0 -1442
- package/scripts/refresh-path.ps1 +0 -107
- package/scripts/release.py +0 -2030
- package/scripts/release_e2e.py +0 -1011
- package/scripts/release_publish.py +0 -486
- package/scripts/release_rollback.py +0 -980
- package/scripts/relocate.py +0 -1034
- package/scripts/resolve_changelog_unreleased.py +0 -667
- package/scripts/resolve_version.py +0 -490
- package/scripts/resume_conditions.py +0 -706
- package/scripts/ritual_sentinel.py +0 -609
- package/scripts/roadmap_render.py +0 -635
- package/scripts/rule_ownership_lint.py +0 -325
- package/scripts/scm.py +0 -591
- package/scripts/scope_audit_log.py +0 -387
- package/scripts/scope_decompose.py +0 -654
- package/scripts/scope_demote.py +0 -509
- package/scripts/scope_lifecycle.py +0 -1126
- package/scripts/scope_undo.py +0 -772
- package/scripts/session_start.py +0 -406
- package/scripts/setup_ghx.py +0 -339
- package/scripts/setup_windows.ps1 +0 -220
- package/scripts/slice_audit.py +0 -585
- package/scripts/slice_record.py +0 -530
- package/scripts/slice_record_existing.py +0 -692
- package/scripts/slug_normalize.py +0 -178
- package/scripts/spec_render.py +0 -477
- package/scripts/spec_validate.py +0 -238
- package/scripts/subagent_monitor.py +0 -658
- package/scripts/swarm_complete_cohort.py +0 -644
- package/scripts/swarm_launch.py +0 -1206
- package/scripts/swarm_readiness.py +0 -554
- package/scripts/swarm_verify_review_clean.py +0 -438
- package/scripts/swarm_worktrees.py +0 -497
- package/scripts/toolchain-check.py +0 -52
- package/scripts/triage_actions.py +0 -871
- package/scripts/triage_bootstrap.py +0 -1153
- package/scripts/triage_bulk.py +0 -630
- package/scripts/triage_classify.py +0 -932
- package/scripts/triage_help.py +0 -1685
- package/scripts/triage_queue.py +0 -1944
- package/scripts/triage_reconcile.py +0 -581
- package/scripts/triage_refresh.py +0 -643
- package/scripts/triage_scope.py +0 -999
- package/scripts/triage_scope_drift.py +0 -575
- package/scripts/triage_smoketest.py +0 -396
- package/scripts/triage_subscribe.py +0 -399
- package/scripts/triage_summary.py +0 -1011
- package/scripts/triage_welcome.py +0 -1178
- package/scripts/ts_check_lane.py +0 -86
- package/scripts/validate-links.py +0 -64
- package/scripts/validate_strategy_output.py +0 -212
- package/scripts/vbrief_activate.py +0 -228
- package/scripts/vbrief_migrate_conformance.py +0 -368
- package/scripts/vbrief_reconcile_graph.py +0 -306
- package/scripts/vbrief_reconcile_labels.py +0 -460
- package/scripts/vbrief_reconcile_umbrellas.py +0 -741
- package/scripts/vbrief_validate.py +0 -1144
- package/scripts/verify-stubs.py +0 -61
- package/scripts/verify_capacity.py +0 -160
- package/scripts/verify_encoding.py +0 -699
- package/scripts/verify_hooks_installed.py +0 -206
- package/scripts/verify_investigation.py +0 -360
- package/scripts/verify_judgment_gates.py +0 -827
- package/scripts/verify_no_task_runtime.py +0 -171
- package/scripts/verify_scm_boundary.py +0 -509
- package/scripts/verify_session_ritual.py +0 -389
- package/scripts/verify_tools.py +0 -426
- package/scripts/verify_vbrief_conformance.py +0 -478
package/scm/github.md
CHANGED
|
@@ -214,9 +214,42 @@ 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
|
+
|
|
237
|
+
## Local git hooks (#747 / #2049)
|
|
238
|
+
|
|
239
|
+
Project-root `.githooks/` enforce branch policy and encoding gates through the **`deft` CLI only** — no Python `scripts/*.py` dispatch (#2049). Hooks are installed idempotently via `deft setup` (`git config core.hooksPath .githooks`).
|
|
240
|
+
|
|
241
|
+
| Hook | Dispatches | Purpose |
|
|
242
|
+
|------|------------|---------|
|
|
243
|
+
| `pre-commit` | `deft verify:branch`, `deft verify:encoding`, `deft verify:vbrief-conformance` (when `vbrief/` exists) | Default-branch commit refusal (#747), encoding gate (#798), staged vBRIEF conformance (#1620) |
|
|
244
|
+
| `pre-push` | `deft preflight-gh --pre-push-stdin` | Refspec-aware default-branch push refusal + destructive gh verb gate (#1019) |
|
|
245
|
+
|
|
246
|
+
- ! Verify wiring after install or framework upgrade: `deft verify:hooks-installed` (also wired into `deft check`).
|
|
247
|
+
- ! After upgrading the framework payload, run `deft update` from the project root to refresh `.githooks/` to the current TS-native templates (#2049). Stale hooks that still invoke `python scripts/preflight_branch.py` or other legacy paths fail `deft verify:hooks-installed`.
|
|
248
|
+
- ~ Recovery when hooks are stale or broken: `deft setup` (re-installs hooks path) or `deft update` (refreshes hook files from the deposited payload).
|
|
249
|
+
|
|
217
250
|
## Destructive gh verbs (#1019)
|
|
218
251
|
|
|
219
|
-
A detection-bound gate (`
|
|
252
|
+
A detection-bound gate (`deft preflight-gh`) refuses three classes of destructive surface before they execute, complementing the #747 branch-protection gate which already refuses commits to the default branch:
|
|
220
253
|
|
|
221
254
|
- `delete_repo` -- `gh repo delete <owner/repo>` and `gh api -X DELETE repos/<owner>/<repo>[/...]`. Irreversible.
|
|
222
255
|
- `force_push_default` -- `git push --force` / `--force-with-lease` / `+refspec` targeting `master` or `main`.
|
|
@@ -224,9 +257,9 @@ A detection-bound gate (`scripts/preflight_gh.py`) refuses three classes of dest
|
|
|
224
257
|
|
|
225
258
|
Three enforcement surfaces back the gate:
|
|
226
259
|
|
|
227
|
-
1. `.githooks/pre-push` invokes `
|
|
228
|
-
2. `task verify:destructive-gh-verbs` is wired into the `
|
|
229
|
-
3. Agent pre-execution callers can invoke `
|
|
260
|
+
1. `.githooks/pre-push` invokes `deft preflight-gh --pre-push-stdin` after the #747 branch gate (on pre-commit), refusing any push that touches the default branch (force-push or otherwise). Install via `deft setup` (idempotent `git config core.hooksPath .githooks`); verify via `deft verify:hooks-installed`.
|
|
261
|
+
2. `deft verify:destructive-gh-verbs` (or `task verify:destructive-gh-verbs` in framework source repos) is wired into the `deft check` aggregate. It runs `deft preflight-gh --self-test`, which drives a built-in fixture table through the classifier so a future edit that introduces a false negative / false positive fails CI immediately.
|
|
262
|
+
3. Agent pre-execution callers can invoke `deft preflight-gh --command "<full command>"` to classify a candidate verb before it executes. Three-state exit (0 allowed / 1 destructive refused / 2 config error) mirrors `deft verify:branch`.
|
|
230
263
|
|
|
231
264
|
**Override paths:**
|
|
232
265
|
|
|
@@ -234,8 +267,6 @@ Three enforcement surfaces back the gate:
|
|
|
234
267
|
- 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
268
|
- 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
269
|
|
|
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
270
|
## Release Workflow (UCCPR)
|
|
240
271
|
|
|
241
272
|
**UCCPR** = Update Changelog, Commit, Push, Release
|
|
@@ -12,6 +12,12 @@ description: >-
|
|
|
12
12
|
<!-- Regenerate with: task packs:render -->
|
|
13
13
|
<!-- Edit the source, not this file. Slice instead of loading every SKILL.md: task packs:slice skills by-trigger --trigger <kw> (or list) -->
|
|
14
14
|
|
|
15
|
+
<!-- AUTO-GENERATED by task packs:render -- DO NOT EDIT MANUALLY -->
|
|
16
|
+
<!-- Purpose: rendered skill -->
|
|
17
|
+
<!-- Source of truth: packs/skills/skills-pack-0.1.json -->
|
|
18
|
+
<!-- Regenerate with: task packs:render -->
|
|
19
|
+
<!-- Edit the source, not this file. Slice instead of loading every SKILL.md: task packs:slice skills by-trigger --trigger <kw> (or list) -->
|
|
20
|
+
|
|
15
21
|
# Deft Directive Setup
|
|
16
22
|
|
|
17
23
|
Agent-driven alternative to `.deft/core/run bootstrap && .deft/core/run project && .deft/core/run spec`.
|
|
@@ -497,7 +503,7 @@ omit = [
|
|
|
497
503
|
|
|
498
504
|
## Phase 3 — Specification
|
|
499
505
|
|
|
500
|
-
**Goal:** Generate an implementable spec using the strategy chosen in Phase 2, producing
|
|
506
|
+
**Goal:** Generate an implementable spec using the strategy chosen in Phase 2, producing scope vBRIEFs in `vbrief/proposed/` and PROJECT-DEFINITION narratives for human approval — greenfield v0.20 does not create `specification.vbrief.json`.
|
|
501
507
|
|
|
502
508
|
! **Path Resolution Anchor**: Same rule as Phase 2 -- resolve ALL paths relative to the user's pwd at skill entry, never relative to the skill file, AGENTS.md, or any framework directory.
|
|
503
509
|
|
|
@@ -656,24 +662,27 @@ Per [strategies/interview.md](../../strategies/interview.md#interview-rules-shar
|
|
|
656
662
|
|
|
657
663
|
⊗ Drop the user at the end of Phase 3 with scope vBRIEFs in `vbrief/proposed/` and no forward pointer to the bridge. Without this section the user discovers the gap at runtime when the swarm Phase 0 Step 1 preflight rejects every candidate (`Invalid transition: 'activate' requires file in pending/`), as in the originating 2026-05-10 first-session consumer tic-tac-toe swarm (issue #1025).
|
|
658
664
|
|
|
659
|
-
### End-of-Phase-3 Export Prompt
|
|
665
|
+
### End-of-Phase-3 Export Prompt (project:export-spec)
|
|
660
666
|
|
|
661
|
-
! After
|
|
667
|
+
! After scope vBRIEFs are written to `vbrief/proposed/` and PROJECT-DEFINITION is populated, but BEFORE handing off to `deft-directive-build` (or advancing speckit Phase 3 → Phase 4), ask the user whether to generate human-readable exports. Greenfield v0.20 projects export via `task project:export-spec` (not legacy `task spec:render`). This replaces the invisible skip-if-absent behavior of `task check` (#398), closes the greenfield gap (#433), and is the Phase 3 → Phase 4 transition gate required by [strategies/speckit.md Post-Phase 3 Transition Gate](../../strategies/speckit.md#post-phase-3-transition-gate-export-for-review) (#432 / #2013).
|
|
662
668
|
|
|
663
|
-
1. ! Prompt: "Your
|
|
664
|
-
1. Yes —
|
|
665
|
-
2. `SPECIFICATION.md`
|
|
669
|
+
1. ! Prompt: "Your scope vBRIEFs are ready. Generate a stakeholder-facing spec export and/or `PRD.md` now? (recommended for stakeholder review)"
|
|
670
|
+
1. Yes — export spec (+ PRD if selected)
|
|
671
|
+
2. Spec export only (`SPECIFICATION.md`)
|
|
666
672
|
3. `PRD.md` only
|
|
667
|
-
4. Skip — I
|
|
668
|
-
2. ! Run the selected
|
|
669
|
-
- `task spec
|
|
670
|
-
- `task
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
673
|
+
4. Skip — I'll export later with `task project:export-spec` / `task prd:render`
|
|
674
|
+
2. ! Run the selected export command(s):
|
|
675
|
+
- `task project:export-spec` → writes `SPECIFICATION.md` from PROJECT-DEFINITION + lifecycle scopes (greenfield default; stakeholder audience)
|
|
676
|
+
- `task project:export-spec -- --audience=internal` → same export but includes proposed scopes under `## Scope outlook` (use for setup/speckit internal handoff when proposed scopes need visibility)
|
|
677
|
+
- `task prd:render` → writes `PRD.md` (optional stakeholder review)
|
|
678
|
+
- Legacy `task spec:render` — migrated trees only (when `vbrief/specification.vbrief.json` exists); do NOT use on greenfield v0.20 projects
|
|
679
|
+
3. ! If the user picked a speckit-strategy project: export is **mandatory** at this boundary — invoke `task project:export-spec` (with `--audience=internal` when proposed scopes exist) even if the user declined the prompt, because speckit Phase 3 → Phase 4 is gated on **export succeeded** (exit 0), not on `specification.vbrief.json` approval.
|
|
680
|
+
4. ! Confirm to the user which files were written and remind them that direct edits to `SPECIFICATION.md` / `PRD.md` are overwritten on the next export — edit vBRIEF narratives in `vbrief/proposed/` and PROJECT-DEFINITION instead.
|
|
681
|
+
5. ~ If the user skipped export and is NOT on a speckit strategy, no-op and continue.
|
|
682
|
+
|
|
683
|
+
⊗ Advance a speckit project to Phase 4 without a successful `task project:export-spec` at this gate — export must succeed (exit 0) for the Phase 3 transition criterion.
|
|
676
684
|
⊗ Silently skip the prompt — greenfield users who never open a PR will miss the exports without it.
|
|
685
|
+
⊗ Invoke legacy `task spec:render` on a greenfield v0.20 project — use `task project:export-spec` instead (#2013).
|
|
677
686
|
|
|
678
687
|
### Handoff to deft-directive-build
|
|
679
688
|
|
package/strategies/speckit.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
A spec-driven development workflow inspired by [GitHub's spec-kit](https://github.com/github/spec-kit), with a Phase 4.5 readiness layer for decomposing broad implementation scopes into swarm-safe stories. Fully migrated to v0.20 (phases + stories emitted as date-prefixed vBRIEFs in proposed/; no legacy specification.vbrief.json).
|
|
10
10
|
|
|
11
|
-
**v0.20 note (s5-migrate-speckit-rapid-enterprise / #1166):** Speckit now emits only the canonical v0.20 shape (date-prefixed phase/epic + story vBRIEFs in proposed/, full PROJECT-DEFINITION.vbrief.json via task project:render
|
|
11
|
+
**v0.20 note (s5-migrate-speckit-rapid-enterprise / #1166):** Speckit now emits only the canonical v0.20 shape (date-prefixed phase/epic + story vBRIEFs in proposed/, full PROJECT-DEFINITION.vbrief.json via task project:render post, seeded lifecycle folders, no legacy specification.vbrief.json). Phase 4/4.5 scopes go to proposed/ (not pending/). Review exports use `task project:export-spec` (gate: export succeeded). See the dedicated ## v0.20 Output Shape section, the Artifacts Summary updated to the contract table, and the canonical contract `strategies/v0-20-contract.md` (s1-contract of #1166).
|
|
12
12
|
|
|
13
13
|
Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
|
|
14
14
|
|
|
@@ -49,7 +49,7 @@ flowchart LR
|
|
|
49
49
|
style I fill:#f0abfc,stroke:#a855f7,color:#000
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
(See ## v0.20 Output Shape for exact artifact rules, the mandatory `task project:render`
|
|
52
|
+
(See ## v0.20 Output Shape for exact artifact rules, the mandatory `task project:render` post call and `task project:export-spec` for review exports, and citation of strategies/v0-20-contract.md.)
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
@@ -137,13 +137,13 @@ Add the following narrative keys to the proposed/ vBRIEF `plan.narratives`:
|
|
|
137
137
|
- ⊗ Write implementation code
|
|
138
138
|
- ⊗ Create `specs/` directories or standalone `plan.md` files -- all content goes in the proposed/ date-prefixed vBRIEF(s)
|
|
139
139
|
|
|
140
|
-
### Post-Phase 3 Transition Gate:
|
|
140
|
+
### Post-Phase 3 Transition Gate: Export for Review
|
|
141
141
|
|
|
142
|
-
! Phase 3 -> Phase 4 is gated on
|
|
142
|
+
! Phase 3 -> Phase 4 is gated on a successful spec export for human review, mirroring the Phase 2 approval gate. Complete the steps below **in order** before advancing. [skills/deft-directive-setup/SKILL.md](../skills/deft-directive-setup/SKILL.md) is required to invoke `task project:export-spec` at this boundary when running speckit interactively; the gate fails silently otherwise (yolo-mode agents used to skip it -- that is what this gate exists to prevent).
|
|
143
143
|
|
|
144
|
-
1. ! Run `task spec
|
|
145
|
-
2. ! Confirm
|
|
146
|
-
3. ! The proposed/ vBRIEFs + PROJECT-DEFINITION are the source of truth.
|
|
144
|
+
1. ! Run `task project:export-spec` (use `--audience=internal` when proposed scopes must appear in the `## Scope outlook` section). Legacy migrated trees MAY use `task spec:render` when `vbrief/specification.vbrief.json` exists.
|
|
145
|
+
2. ! Confirm export **succeeded** (command exit 0) and `SPECIFICATION.md` exists at the project root with the greenfield banner (`<!-- Source of truth: vbrief/PROJECT-DEFINITION.vbrief.json -->`) or full-spec banner as appropriate.
|
|
146
|
+
3. ! The proposed/ vBRIEFs + PROJECT-DEFINITION are the source of truth. `SPECIFICATION.md` is a read-only export.
|
|
147
147
|
4. ! Human reviewer approves (or requests changes). On approval, proceed to Phase 4.
|
|
148
148
|
|
|
149
149
|
### Transition Criteria
|
|
@@ -151,7 +151,7 @@ Add the following narrative keys to the proposed/ vBRIEF `plan.narratives`:
|
|
|
151
151
|
- ! All gates pass (or exceptions documented)
|
|
152
152
|
- ! Every spec requirement maps to a plan element
|
|
153
153
|
- ! Architecture reviewed and approved
|
|
154
|
-
- ! **Phase 3 -> Phase 4 transition criterion:**
|
|
154
|
+
- ! **Phase 3 -> Phase 4 transition criterion:** `task project:export-spec` succeeded (exit 0) AND the proposed/ date-prefixed vBRIEF(s) + PROJECT-DEFINITION represent the approved spec (agents MUST NOT advance to Phase 4 without review of the v0.20 artifacts).
|
|
155
155
|
|
|
156
156
|
---
|
|
157
157
|
|
|
@@ -353,7 +353,7 @@ The readiness report lists ready stories, blocked stories, decomposition-needed
|
|
|
353
353
|
| 1. Principles | `vbrief/PROJECT-DEFINITION.vbrief.json` | Governing rules (Principles narrative) |
|
|
354
354
|
| 2. Specify | date-prefixed in `vbrief/proposed/` | WHAT/WHY narratives (v0.20) |
|
|
355
355
|
| 3. Plan | date-prefixed in `vbrief/proposed/` | HOW narratives (enriches Phase 2; v0.20) |
|
|
356
|
-
| 3b.
|
|
356
|
+
| 3b. Export (review) | `SPECIFICATION.md` (via `task project:export-spec`) | Read-only human review export (optional; gate requires export succeeded for Phase 3→4) |
|
|
357
357
|
| 3c. Render PRD (derivative) | `PRD.md` (via `task prd:render`, sentinel only) | Optional stakeholder-review export |
|
|
358
358
|
| 4. Tasks | `./vbrief/proposed/YYYY-MM-DD-ip<NNN>-<slug>.vbrief.json` (one per IP/epic) | Phase/epic scope vBRIEFs (v0.20: proposed/) drive roadmap/project render + decomposition |
|
|
359
359
|
| 4.5. Story decomposition | Child story vBRIEFs with `plan.metadata.swarm` in proposed/ | Swarm-ready executable units (v0.20) |
|
|
@@ -371,7 +371,7 @@ project/
|
|
|
371
371
|
│ │ └── YYYY-MM-DD-ip001-....vbrief.json
|
|
372
372
|
│ ├── plan.vbrief.json # Phase 4b: session todos (planRef to active scope)
|
|
373
373
|
│ └── pending/ active/ etc. # Lifecycle (seeded empty or with promoted)
|
|
374
|
-
├── SPECIFICATION.md # Optional
|
|
374
|
+
├── SPECIFICATION.md # Optional export (task project:export-spec)
|
|
375
375
|
├── PRD.md # Optional derivative (task prd:render; sentinel only)
|
|
376
376
|
└── src/ # Phase 5
|
|
377
377
|
```
|
|
@@ -386,12 +386,12 @@ This strategy has been migrated to the full v0.20 output shape so speckit-genera
|
|
|
386
386
|
|
|
387
387
|
- ! Seed the five lifecycle folders under `vbrief/` if any are missing: `proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`.
|
|
388
388
|
- ! Emit all scope items (principles context, spec phases/stories, implementation phases/epics) exclusively as date-prefixed scope vBRIEFs in `vbrief/proposed/YYYY-MM-DD-<kebab-slug>.vbrief.json` (or the ipNNN convention for phases per vbrief.md). For speckit, phases use `YYYY-MM-DD-ip<NNN>-<slug>.vbrief.json` in proposed/; stories from Phase 4.5 also in proposed/. Decompose plans into focused, buildable vBRIEFs (v0.6 schema) rather than a monolithic legacy spec.
|
|
389
|
-
- ! After the proposed/ vBRIEFs are written (or at Phase 3/4 boundaries), invoke `task project:render`
|
|
389
|
+
- ! After the proposed/ vBRIEFs are written (or at Phase 3/4 boundaries), invoke `task project:render` from the repo root to generate/refresh the complete `vbrief/PROJECT-DEFINITION.vbrief.json` (items registry derived from the lifecycle folders). For human review at Phase 3→4, invoke `task project:export-spec` (or `--audience=internal` when proposed scopes must appear in `## Scope outlook`).
|
|
390
390
|
- ⊗ Never emit `vbrief/specification.vbrief.json` (or any legacy dual-write).
|
|
391
|
-
- ~ `SPECIFICATION.md` / `PRD.md` at the project root, if produced at all,
|
|
391
|
+
- ~ `SPECIFICATION.md` / `PRD.md` at the project root, if produced at all, are read-only exports from `task project:export-spec` / `task prd:render`. The source of truth is the vbrief/ lifecycle (proposed/ phases + stories) + PROJECT-DEFINITION. Legacy `task spec:render` applies only to migrated trees with `vbrief/specification.vbrief.json`.
|
|
392
392
|
- ! Before writing any proposed/ vBRIEFs or PROJECT-DEFINITION, follow the guards in [artifact-guards.md](./artifact-guards.md) (Preparatory Guard for scope items in proposed/; Spec-Generating Guard for PROJECT-DEFINITION).
|
|
393
393
|
- ! Final output tree must pass the deterministic v0.20 strategy output validation gate (s2-deterministic-gate) and the build Pre-Cutover Detection Guard with zero warnings/errors. See full acceptance in the s5 vBRIEF (a1: date-prefixed stories in proposed/ + deterministic gate; a2: speckit story-level in proposed/ not only pending phases; a3: no legacy specification.vbrief.json) and the 1166 decomposition.
|
|
394
|
-
- ! Cite the canonical contract `strategies/v0-20-contract.md` (s1-contract) for the exact shape and the per-strategy table row (speckit: Yes lifecycle; Yes PROJECT-DEFINITION Phase 1+; proposed/ (phases + stories date-prefixed); Never specification.vbrief.json;
|
|
394
|
+
- ! Cite the canonical contract `strategies/v0-20-contract.md` (s1-contract) for the exact shape and the per-strategy table row (speckit: Yes lifecycle; Yes PROJECT-DEFINITION Phase 1+; proposed/ (phases + stories date-prefixed); Never specification.vbrief.json; `task project:export-spec` for SPEC export).
|
|
395
395
|
|
|
396
396
|
---
|
|
397
397
|
|
|
@@ -404,7 +404,7 @@ This strategy has been migrated to the full v0.20 output shape so speckit-genera
|
|
|
404
404
|
| `vbrief/PROJECT-DEFINITION.vbrief.json` | Principles + full items registry | Speckit Phase 1 + `task project:render` |
|
|
405
405
|
| `vbrief/proposed/YYYY-MM-DD-*.vbrief.json` + `YYYY-MM-DD-ipNNN-*.vbrief.json` | All spec (WHAT/WHY/HOW) + phases/epics/stories (date-prefixed; per v0.20 contract and vbrief.md speckit convention) | Speckit Phases 2-4.5 |
|
|
406
406
|
| `vbrief/{proposed,pending,active,completed,cancelled}/` | All five lifecycle folders seeded | Speckit |
|
|
407
|
-
| (optional
|
|
407
|
+
| (optional export) `SPECIFICATION.md` / `PRD.md` | Human-readable spec export | `task project:export-spec` / `task prd:render` |
|
|
408
408
|
| `vbrief/plan.vbrief.json` | Session-level tactical plan (planRef to active) | Speckit (internal) |
|
|
409
409
|
|
|
410
410
|
**Pre-v0.20 / legacy artifacts that MUST NOT be produced by this strategy:**
|
|
@@ -76,6 +76,17 @@ All five lifecycle folders MUST be present (even if empty). This is the cutover
|
|
|
76
76
|
- ⊗ No v0.20 strategy may create or dual-write `vbrief/specification.vbrief.json` alongside the new model artifacts.
|
|
77
77
|
- Existing legacy files are handled only by `task migrate:vbrief` (which ingests them into scope vBRIEFs + PROJECT-DEFINITION and leaves a redirect stub at root if needed).
|
|
78
78
|
|
|
79
|
+
### Greenfield spec export (#2013 / #1502)
|
|
80
|
+
|
|
81
|
+
Greenfield projects (no `vbrief/specification.vbrief.json`) export stakeholder-facing spec text via `task project:export-spec`:
|
|
82
|
+
|
|
83
|
+
- ! Source of truth: `vbrief/PROJECT-DEFINITION.vbrief.json` product narratives + lifecycle scope bodies (never the legacy singular spec file).
|
|
84
|
+
- ! Default audience is **stakeholder** — proposed scopes are omitted; only pending/active/completed scopes appear under `## Scope outlook`.
|
|
85
|
+
- ! Internal handoff (setup Phase 3, speckit Phase 3→4 when proposed scopes must be visible) uses `task project:export-spec -- --audience=internal`, which adds `### Not yet accepted (proposed)` under `## Scope outlook` with a fixed disclaimer that proposed scopes are ideas, not approved backlog.
|
|
86
|
+
- ! Phase 3→4 transition gate: **export succeeded** (exit 0), not spec-file `approved` status — PROJECT-DEFINITION has no spec-approval lifecycle on greenfield trees.
|
|
87
|
+
- ~ Legacy migrated trees with `vbrief/specification.vbrief.json` MAY continue using `task spec:render` until fully cut over.
|
|
88
|
+
- ⊗ Invoke `task spec:render` on a greenfield tree that lacks `specification.vbrief.json` — use `task project:export-spec` instead.
|
|
89
|
+
|
|
79
90
|
### plan.vbrief.json and continue.vbrief.json
|
|
80
91
|
- Session/tactical state files are permitted at vbrief/ root (they carry `planRef` links). They are not part of the "spec output" contract but strategies that maintain chaining state (e.g. interview) update them per their own rules.
|
|
81
92
|
|
|
@@ -85,7 +96,7 @@ All five lifecycle folders MUST be present (even if empty). This is the cutover
|
|
|
85
96
|
|--------------|------------------|-------------------------------|-------------------------------|-----------------------------------------|-----------------------------|----------------------------------------|
|
|
86
97
|
| interview | spec-generating | Yes | Yes (narratives + items) | proposed/YYYY-MM-DD-*.vbrief.json only | Never (post-migration) | Omit or deprecation redirect only |
|
|
87
98
|
| yolo | spec-generating | Yes | Yes | proposed/YYYY-MM-DD-*.vbrief.json only | Never | Omit or deprecation redirect only |
|
|
88
|
-
| speckit | spec-generating | Yes | Yes (Phase 1+) | proposed/YYYY-MM-DD-*.vbrief.json only (phases + stories) | Never | Omit (
|
|
99
|
+
| speckit | spec-generating | Yes | Yes (Phase 1+) | proposed/YYYY-MM-DD-*.vbrief.json only (phases + stories) | Never | Omit or `task project:export-spec` (legacy: `task spec:render` on migrated trees) |
|
|
89
100
|
| rapid | spec-generating | Yes | Yes | proposed/YYYY-MM-DD-*.vbrief.json only | Never | Omit or deprecation redirect only |
|
|
90
101
|
| enterprise | spec-generating | Yes | Yes | proposed/YYYY-MM-DD-*.vbrief.json only | Never | Omit or deprecation redirect only |
|
|
91
102
|
| preparatory (research, discuss, map, etc.) | preparatory | Yes (if first touch) | No (unless also spec path) | proposed/YYYY-MM-DD-*.vbrief.json (context/decision vBRIEFs) | N/A | N/A (preparatory only) |
|
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
|
|
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
|
-
|
|
14
|
-
|
|
19
|
+
dir: '{{.USER_WORKING_DIR}}'
|
|
20
|
+
deps:
|
|
21
|
+
- _ts-build
|
|
15
22
|
cmds:
|
|
16
|
-
-
|
|
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
|
-
-
|
|
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
|
|
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
|
-
-
|
|
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
|
|
package/tasks/engine.yml
ADDED
|
@@ -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
|
package/tasks/framework.yml
CHANGED
|
@@ -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
|
|
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
|
-
-
|
|
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).
|
|
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 ``
|
|
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
|
|
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 --
|
|
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).
|
|
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
|
-
-
|
|
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
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
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
|
-
|
|
28
|
-
|
|
39
|
+
deps:
|
|
40
|
+
- _ts-build
|
|
29
41
|
cmds:
|
|
30
|
-
-
|
|
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
|
|
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
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
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}}
|