@deftai/directive-content 0.77.0 → 0.79.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/scm/github.md CHANGED
@@ -309,7 +309,7 @@ Phrasing from `deft policy:show --field=allowDirectCommitsToMaster`. When OFF (d
309
309
 
310
310
  ## Local git hooks (#747 / #2049)
311
311
 
312
- 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`).
312
+ Project-root `.githooks/` enforce branch policy and encoding gates through the **`deft` CLI only** — no Python `scripts/*.py` dispatch (#2049). `deft init` and `deft update` deposit hook files; `deft setup` / `task setup` wires `core.hooksPath=.githooks` and refuses when the directory is missing (#2530).
313
313
 
314
314
  | Hook | Dispatches | Purpose |
315
315
  |------|------------|---------|
@@ -318,7 +318,7 @@ Project-root `.githooks/` enforce branch policy and encoding gates through the *
318
318
 
319
319
  - ! Verify wiring after install or framework upgrade: `deft verify:hooks-installed` (also wired into `deft check`).
320
320
  - ! 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`.
321
- - ~ Recovery when hooks are stale or broken: `deft setup` (re-installs hooks path) or `deft update` (refreshes hook files from the deposited payload).
321
+ - ~ Recovery when hooks are stale or broken: `deft update` (deposits/refreshes hook files from the framework payload, including on an already-current deposit) then `deft setup` / `task setup` (wires `core.hooksPath` when files are present).
322
322
 
323
323
  ## Destructive gh verbs (#1019)
324
324
 
@@ -217,7 +217,8 @@ For each phase:
217
217
  2. ! **Test first** — write tests before implementation (TDD)
218
218
  3. ! **Implement** — make tests pass, following deft coding standards
219
219
  4. ! **Verify** — run `task check`, fix any issues
220
- 5. ! **Checkpoint** — tell user what's done, what's next
220
+ 5. ! **Origin sync** — when this phase materially changed an origin-linked scope xBRIEF (`plan.references` includes `x-xbrief/github-issue`), run `task issue:sync-from-xbrief -- <path>` (or `--dry-run` to preview) so the linked GitHub issue receives a sync comment; if skipped, document why in the PR or session notes (#2540)
221
+ 6. ! **Checkpoint** — tell user what's done, what's next
221
222
 
222
223
  - ⊗ Move to next phase until current phase passes all checks
223
224
 
@@ -254,6 +254,14 @@ The task scans every xBRIEF with a GitHub-backed reference (whether the referenc
254
254
  ⊗ Auto-update xBRIEFs based on origin changes without user approval
255
255
  ⊗ Overwrite intentional divergence -- if a xBRIEF has been refined beyond the original issue, preserve the refinement
256
256
 
257
+ ### Origin sync after material xBRIEF edits (#2540)
258
+
259
+ ! When this refinement pass **materially updates** an origin-linked scope xBRIEF (AC, `plan.status`, or `plan.items` statuses/titles), run `task issue:sync-from-xbrief -- <path>` to post a sync comment on the linked GitHub issue so the human-facing tracker stays current. Use `--dry-run` to preview the comment without posting.
260
+
261
+ ! If sync is intentionally skipped (offline, issue frozen, divergence is deliberate), document the skip reason in the session notes or PR body — do not silently leave the origin stale.
262
+
263
+ ⊗ Materially edit an origin-linked xBRIEF without running `issue:sync-from-xbrief` or documenting why it was skipped
264
+
257
265
  ## Phase 4 -- Promote/Demote
258
266
 
259
267
  ! Move xBRIEFs between lifecycle folders using deterministic task commands. The status values below align with the canonical v0.6 Status enum (`draft | proposed | approved | pending | running | completed | blocked | failed | cancelled`) — note that `failed` is also a valid terminal transition for active work that could not complete.
@@ -113,13 +113,15 @@ The dry-run prints `[N/13] <step>... DRYRUN (would <action>)` for every pipeline
113
113
 
114
114
  ## Phase 3 — E2E sanity
115
115
 
116
- ! Invoke `task release:e2e` against an auto-created+destroyed temp repo to verify the full pipeline shape works end-to-end before touching the real repo.
116
+ ! Invoke `task release:e2e` against an auto-created temp repo to verify the full pipeline shape works end-to-end before touching the real repo.
117
117
 
118
118
  ```
119
119
  task release:e2e
120
120
  ```
121
121
 
122
- The harness provisions `deftai/deftai-release-test-<ts>-<uuid6>`, runs the smoke-test rehearsal, and destroys the temp repo in a `try/finally` clause. Cleanup runs even if the rehearsal fails. If `gh repo delete` fails, surface the manual-cleanup hint to the user and continue.
122
+ The harness provisions `deftai/deftai-release-test-<ts>-<uuid6>`, runs the smoke-test rehearsal, and **by default keeps** the temp repo (#2572). Stderr always includes the full `owner/slug` and a copy-pasteable manual-cleanup command (`gh repo delete <owner>/<slug> --yes`). Privileged environments (CI or an operator with `delete_repo`) MAY pass `task release:e2e -- --destroy-repo` to attempt auto-delete; destroy failure emits a WARN and does **not** block Phase 4 when the rehearsal succeeded.
123
+
124
+ ! After Phase 3, the agent MUST NOT retry or escalate temp-repo deletion. Include any leftover temp repo(s) in the phase summary for the operator to clean up manually.
123
125
 
124
126
  ! Treat a non-zero exit from `task release:e2e` as a hard refusal to proceed to Phase 4. Surface the diagnostic and ask whether to debug (return to Phase 1) or abort (`quit`).
125
127
 
@@ -1,9 +1,11 @@
1
1
  ---
2
2
  name: deft-directive-review-cycle
3
3
  description: >-
4
- Greptile bot reviewer response workflow. Use when running a review cycle on
5
- a PR -- to audit process prerequisites, fetch bot findings, fix all issues
6
- in a single batch commit, and exit cleanly when no P0 or P1 issues remain.
4
+ Greptile / bot reviewer response and PR-shepherding workflow. Use when
5
+ running a review cycle or babysitting a PR to merge-ready -- audit process
6
+ prerequisites, fetch bot findings, fix all issues in a single batch commit,
7
+ and exit cleanly when no P0 or P1 issues remain. Supersedes Cursor global
8
+ babysit on Deft-managed repos (#2261).
7
9
  ---
8
10
  <!-- AUTO-GENERATED by task packs:render -- DO NOT EDIT MANUALLY -->
9
11
  <!-- Purpose: rendered skill -->
@@ -36,8 +38,17 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
36
38
  ## When to Use
37
39
 
38
40
  - User says "review cycle", "check reviews", or "run review cycle" on a PR
41
+ - Operator asks to **babysit**, **shepherd**, or **watch** a PR -- including the Cursor product action **babysit-pull-request-in-cloud** (#2261 / #1862 intent-routing class)
39
42
  - A bot reviewer (Greptile) has posted findings on an open PR
40
- - Dispatching a cloud agent to monitor and resolve PR review findings
43
+ - Dispatching a cloud or background agent to monitor and resolve PR review findings until merge-ready
44
+
45
+ ## Cursor global babysit supersession (#2261)
46
+
47
+ On repos with `.deft/core/` installed, **PR shepherding intent** routes here -- not the Cursor-global `babysit` skill (`~/.cursor/skills-cursor/babysit/SKILL.md`). The product action **babysit-pull-request-in-cloud** shares the babysit name but MUST chain into this review-cycle surface on Deft-managed projects.
48
+
49
+ - ! Orchestrators dispatching cloud/background workers for PR shepherding MUST include `templates/agent-prompt-preamble.md` (or reference it) and mandate reading this skill as the first workflow step.
50
+ - ! Cloud babysit workers use `worker_role: review-monitor` (or `drive-to: merge-ready` implementation workers that own the review cycle) -- not a generic babysit loop without Phase 1 audit or Step 6 exit predicate (#1259).
51
+ - ⊗ Route **babysit-pull-request-in-cloud** to Cursor global babysit when `.deft/core/` is present -- that bypasses xBRIEF preflight, `task check`, Greptile fail-closed exit, and CHANGELOG discipline (#2261 recurrence).
41
52
 
42
53
  ## Branch-Protection Policy Guard
43
54
 
@@ -389,6 +400,8 @@ task lifecycle:event -- emit plan:approved \
389
400
 
390
401
  ## Anti-Patterns
391
402
 
403
+ - ⊗ Route PR shepherding to Cursor global `babysit` on Deft-managed repos when `.deft/core/` is installed -- use this review-cycle skill instead (#2261)
404
+ - ⊗ Treat a passing SLizard/Greptile check run, a non-blocking review comment, or an ad hoc fix commit as the review-cycle exit predicate -- Step 6 fail-closed all-of (#1259) and multi-reviewer registry triage (#769) still apply
392
405
  - ⊗ Push individual fix commits per finding
393
406
  - ⊗ Start fixing before analyzing ALL findings
394
407
  - ⊗ Rely on the bot to catch syntax errors in structured data files
@@ -482,7 +482,11 @@ omit = [
482
482
 
483
483
  - ~ After Phase 2 writes `PROJECT-DEFINITION.xbrief.json`, recommend `task triage:welcome` to the user as the single chained command for picking up the v0.27 triage surface. The N3 ritual (#1143) is the consolidating onboarding step for the #1119 governance swarm verbs (`task triage:bootstrap` / `task triage:scope` / `plan.policy.wipCap` writes / `task scope:demote --batch` relief / `task triage:summary`); without it consumers must learn each verb individually from the v0.27 release notes.
484
484
  - ~ `task triage:welcome` is idempotent and detection-bound -- each phase emits an informational stderr line and skips when its precondition is already satisfied, so a re-run after a partial completion resumes cleanly. The destructive phases (subscription / `wipCap` writes, optional WIP-relief invocation) are gated by numbered-menu prompts per [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md). See [`../../UPGRADING.md`](../../UPGRADING.md) `## From v0.26.x -> v0.27` for the full walkthrough.
485
- - ? The recommendation is informational, not a hard gate -- consumers who plan to wire triage manually MAY skip the ritual and call the individual verbs in any order; the framework defaults stay fail-open per the umbrella `#1119 §12 framework-vs-consumer-config boundary`.
485
+ ### Consumer AGENTS always-pin recommendations (#2508)
486
+
487
+ ! After Phase 2 completes (or when closing a greenfield bootstrap), tell the consumer that process-critical directive skills should be named in their project's AGENTS.md **unmanaged header** when false-negative risk matters — full tier definitions: [`../../docs/skill-pin-policy.md`](../../docs/skill-pin-policy.md).
488
+ ~ Recommend the default consumer pin set for lifecycle work: `deft-directive-build` (implementation), `deft-directive-pre-pr` (before PR), `deft-directive-review-cycle` (bot review loop), and `deft-directive-swarm` when they plan parallel agents. Each is referenced by skill id + `.deft/core/.agents/skills/<id>/SKILL.md` path — not by pasting skill bodies.
489
+ ⊗ Recommend pinning entire `languages/`, `deployments/`, or other framework doc packs into AGENTS.md (#2508 anti-pattern).
486
490
 
487
491
  ---
488
492
 
@@ -57,6 +57,8 @@ This path became first-class in #1342 (platform adapter slices 1-3) and is fully
57
57
 
58
58
  ~ **Windows + Grok Build (#1353):** When issuing shell commands via `run_terminal_command` on this platform, avoid `|`, `>`, or `2>&1` in the command string — use Python `pathlib`/`subprocess` or plain `task` targets instead to avoid wrapper leakage. See `templates/agent-prompt-preamble.md` §3.5 for the full escape hatch list.
59
59
 
60
+ ! **Windows + Cursor Task-tool console windows (#2563):** Local Cursor Task swarms on Windows are first-class. Shipped mitigations (do not regress): `windowsHide: true` (CREATE_NO_WINDOW) on engine/spawn paths, and warm-dist skip via `tasks/ts-build-fresh.cjs` so `engine:_ts-build` does not cold-rebuild when `packages/cli/dist` is current. See `templates/agent-prompt-preamble.md` §3.8. ! Default to **local** Task workers on Windows (not cloud-for-Windows). Parallel cohorts are allowed — do not force concurrency=1 for #2563. ⊗ Drop or weaken those mitigations without a replacement that keeps Windows local swarm workable.
61
+
60
62
  ## Prerequisites
61
63
 
62
64
  - ! `xbrief/active/` contains one or more story-level xBRIEFs with status `running`
@@ -1,12 +1,13 @@
1
1
  ---
2
2
  name: deft-directive-triage
3
3
  description: >-
4
- Triage-cache hygiene and "what's next?" queue selection -- the agent-facing
5
- playbook for syncing the triage cache, classifying candidates, presenting a
6
- ranked queue, walking per-item decisions (accept / reject / defer / needs-ac
7
- / mark-duplicate), and auditing the session. Use when the operator asks what
8
- to work on next, wants to build a cohort, work the cache, or run a triage
9
- hygiene pass.
4
+ Triage-cache hygiene and "what's next?" work selection (ordered plan or
5
+ ranked queue) -- the agent-facing playbook for syncing the triage cache,
6
+ classifying candidates, presenting a ranked queue or binding to an active
7
+ plan-sequence, walking per-item decisions (accept / reject / defer /
8
+ needs-ac / mark-duplicate), and auditing the session. Use when the operator
9
+ asks what to work on next, wants to build a cohort, work the cache, or run a
10
+ triage hygiene pass.
10
11
  triggers:
11
12
  - triage
12
13
  - triage hygiene
@@ -26,7 +27,7 @@ triggers:
26
27
 
27
28
  # Deft Directive Triage
28
29
 
29
- Triage-cache hygiene + "what's next?" queue selection. Operates against the unified `.deft-cache/github-issue/` mirror (#883 Story 2) and the append-only `xbrief/.eval/candidates.jsonl` audit log (#845 Story 2); writes only via the canonical `task triage:*` verbs.
30
+ Triage-cache hygiene + "what's next?" work selection (ordered plan or ranked queue). Operates against the unified `.deft-cache/github-issue/` mirror (#883 Story 2) and the append-only `xbrief/.eval/candidates.jsonl` audit log (#845 Story 2); writes only via the canonical `task triage:*` verbs.
30
31
 
31
32
  Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
32
33
 
@@ -38,11 +39,17 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
38
39
 
39
40
  ! Every numbered-menu prompt rendered in this skill (Phase 2 candidate selection, Phase 3 per-item decision walk) ! MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md): render the canonical numbered menu in chat unless the host UI visibly preserves numeric option labels and returns numeric selections or exact displayed option text. The final two numbered options are `Discuss` and `Back`, in that order, and the Discuss-pause semantic from the contract applies verbatim -- on `Discuss` the agent halts the in-progress sequence and resumes only on an explicit user signal.
40
41
 
42
+ ## Work selection fork (#2542 / #2402)
43
+
44
+ Directive does not guess your mix: **ordered plan** (`task plan-sequence:*`) when you know the next units in order, or **ranked queue** (`task triage:queue`) when picking from the backlog. Labels bias the queue; they do not override an active plan.
45
+
46
+ ! Before Phase 2 on bare "what's next?", run `task plan-sequence:current`. Active sequence → that entry only; exhausted → fail closed. Explicit "what's the queue?" / "build a cohort" → Phase 2. See `commands.md` § Backlog Triage → Two paths.
47
+
41
48
  ## Phase 0 -- Sync
42
49
 
43
50
  ! Probe cache freshness before doing any classification or selection. Stale cache reads produce stale decisions; the gate is the contract.
44
51
 
45
- 1. ! Run `task verify:cache-fresh` (D5 / #1127). Exit 0 -> proceed to Phase 1. Exit 1 (stale or blocked) -> refresh per the printed remediation. Exit 2 (no bootstrap) -> run `task triage:bootstrap` first.
52
+ 1. ! Run `task verify:cache-fresh` (D5 / #1127). Exit 0 -> proceed to Phase 1. Exit 1 (stale or blocked) -> refresh per the printed remediation. Exit 2 (no bootstrap) -> run `task triage:bootstrap` first. When the cache has zero entries, read paths auto-fetch from GitHub first (#2575).
46
53
  2. ~ Refresh path: `task cache:fetch-all -- --source=github-issue --repo OWNER/NAME` for an already-bootstrapped project (idempotent, TTL-aware, re-applies the #883 scanner v2 quarantine rules); `task triage:bootstrap` for a first-time seed.
47
54
  3. ~ If `xbrief/active/*.xbrief.json` references are in play, run `task triage:refresh-active` to compare cached `meta.json.fetched_at` against live upstream `updatedAt` and surface drift before the queue is rendered.
48
55
  4. ~ When the one-liner emitted by the session-start ritual carries a `[scope-drift] N` segment (D14 / #1133), run `task triage:scope-drift` to see the per-label / per-milestone breakdown of upstream signals on cached open issues that fall outside the active `plan.policy.triageScope[]` subscription. The output documents both opt-in (`task triage:subscribe -- --label=<L>`) and opt-out (`task triage:scope-drift -- --ignore-label=<L>`) paths -- pick one before walking the queue so the cohort reflects the operator's current intent rather than a stale subscription.
@@ -59,14 +66,9 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
59
66
  5. ⊗ Re-classify items already terminally decided (accept / reject / mark-duplicate) without explicit operator approval -- the audit log is append-only and supersession runs through Layer 5 (`task triage:reset <N>`), not through silent re-walks.
60
67
  6. ⊗ Block issue creation solely because no label was selected, or invent ad hoc labels outside the repository's existing label set.
61
68
 
62
-
63
- ## Ordered-plan precedence (#2402)
64
-
65
- ! Before queue selection on bare "what's next?", run `task plan-sequence:current`. Active sequence → that entry only; exhausted → fail closed and ask. Explicit "what's the queue?" / "build a cohort" still use Phase 2. Chaining is non-authorizing. ⊗ Reuse triage `continuationNumbers`/`continuationOrder` for ordered-plan state.
66
-
67
69
  ## Phase 2 -- Present
68
70
 
69
- ! When no ordered-plan is active, render `task triage:queue` before suggesting work (#1149). Active sequence yields to the ordered-plan entry (#2402).
71
+ ! Apply the Work selection fork gate (#2542): when no ordered-plan is active, render `task triage:queue` before suggesting work (#1149). Active sequence yields to the ordered-plan entry (#2402).
70
72
 
71
73
  1. ! Run `task triage:queue --limit=N` (D11 / #1128) -- default `N=10` per the umbrella Current Shape v3 WIP cap. Output is grouped `[RESUME]` -> `[URGENT]` -> untriaged -> other; within-group ordering follows the consumer-supplied `plan.policy.triageRankingLabels[]` (framework default empty per §12 boundary), tiebroken by `updated_at` descending.
72
74
  2. ! For per-item detail, run `task triage:show <N>` -- prints the cached upstream payload, the latest triage decision, the audit timeline, and the active-xBRIEF reference flag. Exit 0 on hit, 1 on cache miss (re-sync per Phase 0).
@@ -118,6 +120,7 @@ What would you like to do with this candidate?
118
120
  ## Anti-Patterns
119
121
 
120
122
  - ⊗ Recommend a specific issue without first consulting `task triage:queue` (binding under AGENTS.md `## Cache-as-authoritative work selection (#1149)`).
123
+ - ⊗ Conclude "nothing to do" from `xbrief/{pending,active}` scans or live GitHub reads alone — `task triage:queue` is the ranked superset (#2576).
121
124
  - ⊗ Walk the queue against a stale cache (Phase 0 gate skipped).
122
125
  - ⊗ Reimplement audit-log append / `proposed/` write inline -- the `task triage:*` verbs own those surfaces (#845, #883).
123
126
  - ⊗ Treat `defer` / `needs-ac` as terminal -- they intentionally resurface on the next pass.
@@ -88,20 +88,23 @@ function main() {
88
88
  process.exit(2);
89
89
  }
90
90
 
91
+ // Command transport is one-hop: a spawned CLI may invoke Task again with a
92
+ // different ENGINE_CMD, which must not be shadowed by this inherited value.
93
+ const childEnv = { ...process.env };
94
+ delete childEnv.DEFT_ENGINE_CMD_JSON;
95
+ delete childEnv.DEFT_ENGINE_CMD;
96
+
97
+ // stdio inherit (not pipe): piped stdout/stderr deadlocks when the child emits
98
+ // more than the OS pipe buffer before exit — observed as greenfield smoke
99
+ // hanging then CI SIGTERM exit 143 with no output (#2554 / #2547).
91
100
  const result = spawnSync(execPath, execArgv, {
92
- encoding: "utf8",
93
- stdio: ["ignore", "pipe", "pipe"],
94
- env: process.env,
101
+ stdio: "inherit",
102
+ env: childEnv,
95
103
  // Global deft/directive on Windows are .cmd shims; shell:false cannot spawn them (#2415).
96
104
  shell: mode === "global" && process.platform === "win32",
97
- maxBuffer: 16 * 1024 * 1024,
105
+ // CREATE_NO_WINDOW: hide console windows from Cursor Task / nested shells (#2563).
106
+ windowsHide: true,
98
107
  });
99
- if (result.stdout) {
100
- process.stdout.write(result.stdout);
101
- }
102
- if (result.stderr) {
103
- process.stderr.write(result.stderr);
104
- }
105
108
  const code = result.status;
106
109
  process.exit(code === null ? 1 : code);
107
110
  }
package/tasks/engine.yml CHANGED
@@ -35,13 +35,16 @@ tasks:
35
35
  // Windows native Task often has no `sh` on PATH, so Corepack.cmd was
36
36
  // invisible after #2411. Prefer a direct spawn (POSIX / real binaries);
37
37
  // fall back to shell:true so PATHEXT resolves .cmd/.exe on win32.
38
+ // windowsHide (#2563): CREATE_NO_WINDOW so Cursor Task shells do not
39
+ // flood visible cmd.exe/conhost windows on every probe/build.
40
+ const spawnOpts=(extra)=>({stdio:'ignore',windowsHide:true,...extra});
38
41
  const hasCmd=(name)=>{
39
42
  try{
40
- execFileSync(name,['--version'],{stdio:'ignore'});
43
+ execFileSync(name,['--version'],spawnOpts());
41
44
  return true;
42
45
  }catch{
43
46
  try{
44
- execFileSync(name,['--version'],{stdio:'ignore',shell:true});
47
+ execFileSync(name,['--version'],spawnOpts({shell:true}));
45
48
  return true;
46
49
  }catch{
47
50
  return false;
@@ -49,7 +52,7 @@ tasks:
49
52
  }
50
53
  };
51
54
  const run=(cmd,args)=>{
52
- execFileSync(cmd,args,{cwd:root,stdio:'inherit',shell:true});
55
+ execFileSync(cmd,args,{cwd:root,stdio:'inherit',shell:true,windowsHide:true});
53
56
  };
54
57
  const trySteps=(steps)=>{
55
58
  for(const [cmd,args] of steps){
@@ -98,6 +101,10 @@ tasks:
98
101
  # ships no packages/ tree (guard false -> no-op, #2126). Git-vendored-payload
99
102
  # repos may carry a stray packages/ under .deft/core without a root `build`
100
103
  # script — source-only presence must NOT run `pnpm run build` there.
104
+ #
105
+ # Warm-dist skip (#2563): when packages/cli/dist/bin.js is newer than
106
+ # packages/{cli,core,types} sources, skip rebuild. Override with
107
+ # DEFT_FORCE_TS_BUILD=1; force-skip with DEFT_SKIP_TS_BUILD=1.
101
108
  dir: '{{.USER_WORKING_DIR}}'
102
109
  cmds:
103
110
  - |
@@ -105,6 +112,9 @@ tasks:
105
112
  if [ -f "{{.DEFT_ROOT}}/packages/cli/package.json" ] \
106
113
  && [ -f "{{.DEFT_ROOT}}/package.json" ] \
107
114
  && node -e "const fs=require('fs');const j=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));process.exit(j.scripts&&j.scripts.build?0:1)" "{{.DEFT_ROOT}}/package.json"; then
115
+ if node "{{.TASKFILE_DIR}}/ts-build-fresh.cjs" "{{.DEFT_ROOT}}"; then
116
+ exit 0
117
+ fi
108
118
  node -e "
109
119
  const {execFileSync}=require('child_process');
110
120
  const fs=require('fs');
@@ -116,13 +126,16 @@ tasks:
116
126
  // Windows native Task often has no `sh` on PATH, so Corepack.cmd was
117
127
  // invisible after #2411. Prefer a direct spawn (POSIX / real binaries);
118
128
  // fall back to shell:true so PATHEXT resolves .cmd/.exe on win32.
129
+ // windowsHide (#2563): CREATE_NO_WINDOW so Cursor Task shells do not
130
+ // flood visible cmd.exe/conhost windows on every probe/build.
131
+ const spawnOpts=(extra)=>({stdio:'ignore',windowsHide:true,...extra});
119
132
  const hasCmd=(name)=>{
120
133
  try{
121
- execFileSync(name,['--version'],{stdio:'ignore'});
134
+ execFileSync(name,['--version'],spawnOpts());
122
135
  return true;
123
136
  }catch{
124
137
  try{
125
- execFileSync(name,['--version'],{stdio:'ignore',shell:true});
138
+ execFileSync(name,['--version'],spawnOpts({shell:true}));
126
139
  return true;
127
140
  }catch{
128
141
  return false;
@@ -130,12 +143,20 @@ tasks:
130
143
  }
131
144
  };
132
145
  const run=(cmd,args)=>{
133
- execFileSync(cmd,args,{cwd:root,stdio:'inherit',shell:true});
146
+ execFileSync(cmd,args,{cwd:root,stdio:'inherit',shell:true,windowsHide:true});
147
+ };
148
+ const markWarm=()=>{
149
+ try{
150
+ const dist=root+'/packages/cli/dist';
151
+ fs.mkdirSync(dist,{recursive:true});
152
+ fs.writeFileSync(dist+'/.deft-ts-build-stamp',new Date().toISOString());
153
+ }catch{}
134
154
  };
135
155
  const trySteps=(steps)=>{
136
156
  for(const [cmd,args] of steps){
137
157
  try{
138
158
  run(cmd,args);
159
+ markWarm();
139
160
  process.exit(0);
140
161
  }catch{
141
162
  // fall through to Corepack / next resolver
@@ -145,6 +166,7 @@ tasks:
145
166
  const envPm=String(process.env.DEFT_PACKAGE_MANAGER||'').trim().toLowerCase();
146
167
  if(envPm==='npm'){
147
168
  run('npm',['run',script]);
169
+ markWarm();
148
170
  process.exit(0);
149
171
  }
150
172
  const pin=String(pkg.packageManager||'').trim();
package/tasks/eval.yml CHANGED
@@ -30,3 +30,12 @@ tasks:
30
30
  - task: :engine:invoke
31
31
  vars:
32
32
  ENGINE_CMD: 'eval:report --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
33
+
34
+ triggers:
35
+ desc: "Trigger routing coverage for AGENTS.md / Skills Index (#1586). Offline skill-pi-trigger-eval compatible eval over evals/trigger-cases.jsonl vs REFERENCES.md. -- task eval:triggers [-- --json] [--project-root PATH]"
36
+ deps:
37
+ - task: :engine:_ts-build
38
+ cmds:
39
+ - task: :engine:invoke
40
+ vars:
41
+ ENGINE_CMD: 'eval:triggers --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ /**
5
+ * Decide whether engine:_ts-build can skip `pnpm run build` (#2563).
6
+ *
7
+ * Exit codes:
8
+ * 0 — dist is fresh enough (or DEFT_SKIP_TS_BUILD=1); skip rebuild
9
+ * 1 — rebuild required (missing dist, newer sources, or DEFT_FORCE_TS_BUILD=1)
10
+ * 2 — usage / config error
11
+ *
12
+ * Warm-dist skip avoids a full `tsc -b` (and its nested shell:true spawns) on
13
+ * every `task <verb>` when packages/cli/dist/bin.js is already up to date.
14
+ */
15
+
16
+ const fs = require("node:fs");
17
+ const path = require("node:path");
18
+
19
+ const SKIP_DIRS = new Set(["node_modules", "dist", "coverage", ".git"]);
20
+
21
+ function walkSourceFiles(dir, out) {
22
+ if (!fs.existsSync(dir)) return;
23
+ let entries;
24
+ try {
25
+ entries = fs.readdirSync(dir, { withFileTypes: true });
26
+ } catch {
27
+ return;
28
+ }
29
+ for (const ent of entries) {
30
+ const full = path.join(dir, ent.name);
31
+ if (ent.isDirectory()) {
32
+ if (SKIP_DIRS.has(ent.name)) continue;
33
+ walkSourceFiles(full, out);
34
+ continue;
35
+ }
36
+ if (ent.isFile() && /\.(?:ts|tsx|json)$/.test(ent.name) && !ent.name.endsWith(".d.ts")) {
37
+ out.push(full);
38
+ }
39
+ }
40
+ }
41
+
42
+ function main() {
43
+ const root = process.argv[2];
44
+ if (!root) {
45
+ console.error("deft: ts-build-fresh usage: ts-build-fresh.cjs <DEFT_ROOT>");
46
+ process.exit(2);
47
+ }
48
+ if (process.env.DEFT_FORCE_TS_BUILD === "1") {
49
+ process.exit(1);
50
+ }
51
+ if (process.env.DEFT_SKIP_TS_BUILD === "1") {
52
+ process.exit(0);
53
+ }
54
+
55
+ const distDir = path.join(root, "packages", "cli", "dist");
56
+ const bin = path.join(distDir, "bin.js");
57
+ const stamp = path.join(distDir, ".deft-ts-build-stamp");
58
+ if (!fs.existsSync(bin)) {
59
+ process.exit(1);
60
+ }
61
+ // Prefer the post-build stamp (#2563): `tsc -b` incremental often leaves
62
+ // bin.js mtime unchanged even after a successful build when sources are
63
+ // newer than a previous emit. The stamp is written only after a completed
64
+ // engine:_ts-build, so it is the authoritative "warm dist" marker.
65
+ const marker = fs.existsSync(stamp) ? stamp : bin;
66
+ const markerMtime = fs.statSync(marker).mtimeMs;
67
+ const candidates = [];
68
+
69
+ for (const pkg of ["cli", "core", "types"]) {
70
+ const pkgRoot = path.join(root, "packages", pkg);
71
+ if (!fs.existsSync(pkgRoot)) continue;
72
+ walkSourceFiles(path.join(pkgRoot, "src"), candidates);
73
+ for (const name of ["package.json", "tsconfig.json", "tsconfig.build.json"]) {
74
+ const fp = path.join(pkgRoot, name);
75
+ if (fs.existsSync(fp)) candidates.push(fp);
76
+ }
77
+ }
78
+ for (const name of ["package.json", "tsconfig.json", "tsconfig.base.json", "pnpm-workspace.yaml"]) {
79
+ const fp = path.join(root, name);
80
+ if (fs.existsSync(fp)) candidates.push(fp);
81
+ }
82
+
83
+ for (const file of candidates) {
84
+ try {
85
+ if (fs.statSync(file).mtimeMs > markerMtime) {
86
+ process.exit(1);
87
+ }
88
+ } catch {
89
+ process.exit(1);
90
+ }
91
+ }
92
+ process.exit(0);
93
+ }
94
+
95
+ if (require.main === module) {
96
+ main();
97
+ }
98
+
99
+ module.exports = { walkSourceFiles };
package/tasks/verify.yml CHANGED
@@ -415,6 +415,16 @@ tasks:
415
415
  vars:
416
416
  ENGINE_CMD: 'verify:eval-health-relocation --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
417
417
 
418
+ eval-triggers-relocation:
419
+ desc: "Fail-closed eval:triggers gate when AGENTS.md / REFERENCES.md / trigger cases change (#1586). Skips (exit 0) when the diff does not touch trigger-routing homes. -- task verify:eval-triggers-relocation [-- --base-ref <ref> | --staged] [--quiet]"
420
+ dir: '{{.USER_WORKING_DIR}}'
421
+ deps:
422
+ - task: :engine:_ts-build
423
+ cmds:
424
+ - task: :engine:invoke
425
+ vars:
426
+ ENGINE_CMD: 'verify:eval-triggers-relocation --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
427
+
418
428
  agents-md-advisory:
419
429
  desc: "ADVISORY (never fail-closing) consumer AGENTS.md legibility signal (#2155). Counts the UNMANAGED (project-authored) region only -- the framework-owned managed section is excluded -- and compares it against the SOFT, operator-adjustable budget plan.policy.agentsMdAdvisory.unmanagedSoftMaxLines (generous default when unset). Consumer companion to the maintainer-only #645 ratchet; deliberately NOT a check:consumer dependency (advise->observe->enforce per #1419). Default posture ALWAYS exits 0; the opt-in --enforce flag promotes an over-budget region to a hard cap (exit 1). Raising the field is the documented, no-friction way to accept growth and silence the nudge."
420
430
  dir: '{{.USER_WORKING_DIR}}'
@@ -211,6 +211,24 @@ PYTEST_ADDOPTS="--basetemp=$(mktemp -d)/pt" task check
211
211
 
212
212
  A clean result under an isolated basetemp is attributable to your change, not to the ambient shared-`/tmp` race. Do NOT point `--basetemp` at a static path shared across workers -- that re-introduces the collision. Solo / single-run invocations on a private worktree do not require this, but it is harmless to apply unconditionally.
213
213
 
214
+ ## 3.8 Windows Cursor Task-tool console windows (#2563)
215
+
216
+ On Windows, Cursor Task-tool local subagents historically opened a visible `cmd.exe` / `conhost` window per shell turn. Framework source checkouts amplified this when every `task <verb>` cold-ran `engine:_ts-build` → `pnpm`/`tsc` via `shell: true`.
217
+
218
+ **Shipped mitigations (keep; do not regress):**
219
+
220
+ - `windowsHide: true` (CREATE_NO_WINDOW) on engine invoke / package-manager probe / `spawnCommandText` paths
221
+ - Warm-dist skip via `tasks/ts-build-fresh.cjs` so `_ts-build` does not rebuild when `packages/cli/dist` is current (override with `DEFT_FORCE_TS_BUILD=1` / `DEFT_SKIP_TS_BUILD=1`)
222
+
223
+ **Directive rule for orchestrators on Windows:**
224
+
225
+ - ! Use **local** Cursor Task swarm workers as the default dispatch path — same as other platforms. Do not route to cloud solely because the host is Windows.
226
+ - ! Parallel local cohorts are allowed; do not force concurrency=1 because of #2563.
227
+ - ~ Prefer the normal warm `task` / `dist/bin.js` path; avoid unnecessary `DEFT_FORCE_TS_BUILD=1` across a parallel cohort.
228
+ - ⊗ Drop or weaken the #2563 `windowsHide` / warm-dist mitigations without a replacement that keeps Windows local swarm workable.
229
+
230
+ Reference: issue #2563; swarm skill Platform Requirements; env scrub + stdio inherit for nested Task recursion (#2554 / #2438).
231
+
214
232
  ## 4. pre-pr and review-cycle skills
215
233
 
216
234
  Before pushing any branch:
@@ -225,8 +243,55 @@ Anti-pattern: pushing without pre-pr and relying on Greptile to find issues. Tha
225
243
  The active host harness may expose its own review-labeled surfaces. On Cursor these are the `bugbot` and `security-review` Task **subagent types** and the `review-bugbot` / `review-security` **skills**; other harnesses may ship equivalents. A generic operator request to "review" / "get this reviewed" / "use sub-agents for reviews" must NOT be routed to those host-native tools as the review of record.
226
244
 
227
245
  - ! Route ALL review work through the canonical `skills/deft-directive-review-cycle/SKILL.md` surface. Map a generic review request to the review cycle **by intent**, not by literal keyword -- "review this", "get this reviewed", and "use sub-agents for reviews" all mean run `deft-directive-review-cycle` (extends the #1862 / #2261 intent-routing fix).
228
- - ~ Host review tools (Cursor `bugbot` / `security-review` subagent types, `review-bugbot` / `review-security` skills, or any future host equivalent) MAY be folded in as *advisory* finding sources INSIDE the review cycle -- the #2019 harness-aware-reviewer path -- with their findings batched alongside the Greptile / bot findings the cycle already processes.
229
- - Substitute a host-native review subagent type or `review-*` skill for `deft-directive-review-cycle` as the review surface. The host tools are advisory inputs folded into the cycle, never a replacement for it. Reaching for them on a bare "review" request is the 3rd recurrence of the #1862 / #2261 wrong-review-surface class (see also #2019, #2018).
246
+ - ! Map **PR shepherding intent** the same way: `babysit`, `babysit this PR`, `shepherd`, `watch the PR`, and the Cursor product action **babysit-pull-request-in-cloud** all mean run `deft-directive-review-cycle` on Deft-managed repos (`.deft/core/` installed) -- NOT the Cursor-global `babysit` skill (`~/.cursor/skills-cursor/babysit/SKILL.md`) (#2261).
247
+ - ~ Host review tools (Cursor `babysit` / `bugbot` / `security-review` subagent types, `review-bugbot` / `review-security` skills, or any future host equivalent) MAY be folded in as *advisory* finding sources INSIDE the review cycle -- the #2019 harness-aware-reviewer path -- with their findings batched alongside the Greptile / bot findings the cycle already processes.
248
+ - ⊗ Substitute a host-native review subagent type, Cursor global `babysit`, or `review-*` skill for `deft-directive-review-cycle` as the review surface. The host tools are advisory inputs folded into the cycle, never a replacement for it. Reaching for them on a bare "review" or "babysit" request is the #1862 / #2261 wrong-review-surface class (see also #2019, #2018).
249
+
250
+ ## 4.6 Cloud PR-shepherd dispatch -- review-monitor worked example (#2261)
251
+
252
+ When an operator triggers **babysit-pull-request-in-cloud** (or equivalent PR-shepherding intent) on a Deft-managed repo, the orchestrator MUST dispatch a **review-monitor** worker with this preamble (or a reference to `templates/agent-prompt-preamble.md`) and an explicit mandate to read `skills/deft-directive-review-cycle/SKILL.md` before any PR mutation.
253
+
254
+ Worked example (cloud background review-monitor on PR #1037):
255
+
256
+ ```markdown
257
+ ## Allocation context
258
+
259
+ - dispatch_kind: solo
260
+ - allocation_plan_id: null
261
+ - batching_rationale: null
262
+ - cohort_vbriefs: []
263
+ - operator_approval_evidence: operator selected babysit-pull-request-in-cloud 2026-07-03
264
+
265
+ ## Worker metadata
266
+
267
+ - dispatch_provider: cursor-cloud-agent
268
+ - worker_role: review-monitor
269
+ - selected_backend: cursor-cloud
270
+ - routing_policy: null
271
+ - resolved_model: null
272
+ - model_source: harness-default explicit
273
+
274
+ ## Runtime and GitHub auth mode
275
+
276
+ - runtime_mode: cloud-headless
277
+ - github_auth_mode: injected-token
278
+
279
+ ## Unit of work
280
+
281
+ drive-to: merge-ready on PR #1037 (repo: deftai/deftvisage, branch: fix/visage-repo-org-scoping)
282
+
283
+ ## Mandates
284
+
285
+ 1. First tool call: read AGENTS.md; confirm Deft alignment.
286
+ 2. Read `templates/agent-prompt-preamble.md` (binding) and `skills/deft-directive-review-cycle/SKILL.md` end-to-end -- NOT `~/.cursor/skills-cursor/babysit/SKILL.md`.
287
+ 3. Run review-cycle Phase 1 process audit before the fix loop; batch Phase 1 + Phase 2 fixes per review-cycle discipline.
288
+ 4. Poll terminal verdict via `task pr:watch -- <N>` when waiting on Greptile/SLizard (#1056).
289
+ 5. Exit only on review-cycle Step 6 fail-closed all-of (#1259) -- ad hoc SLizard P2 fixes without the exit predicate are insufficient.
290
+
291
+ DONE: include PR URL, role review-monitor, and whether Step 6 CLEAN was reached.
292
+ ```
293
+
294
+ Anti-pattern: dispatching `Task(environment=cloud)` with only the Cursor global babysit skill attached and no preamble / `deft-directive-review-cycle` path -- that is the #2261 recurrence class.
230
295
 
231
296
  ## 5. REST-by-default for read-only gh calls
232
297
 
@@ -10,6 +10,7 @@ Scoped work, ranked queue, and tracked bugs live in authoritative sources — no
10
10
 
11
11
  - Project identity → `xbrief/PROJECT-DEFINITION.xbrief.json`
12
12
  - Scoped work → `xbrief/` lifecycle folders
13
+ - Work selection → default ranked queue (`deft triage:queue`); lock a short ordered plan (`deft plan-sequence:set`) when you want bounded delivery — see `deft/commands.md` § Backlog Triage → Two paths
13
14
  - Ranked queue → `deft triage:queue` / `deft triage:welcome`
14
15
  - Tracked bugs → GitHub issues
15
16
 
@@ -27,9 +27,9 @@ Legacy `vbrief/` read-accepted; `deft migrate:xbrief` for `xbrief/` (v0.6→v0.8
27
27
 
28
28
  ## Cache-as-authoritative work selection (#1149)
29
29
 
30
- ! "what next?" → ordered-plan first (#2402 / `deft plan-sequence:*`); else `deft triage:queue --limit=10` (D11) `commands.md` § Backlog Triage.
30
+ ! "what next?" → two work-selection modes (#2402): **ordered plan** (`deft plan-sequence:*`) or **ranked queue** (`deft triage:queue`) — `commands.md` § Backlog Triage → Two paths. ordered-plan first; else `deft-directive-triage` + `deft triage:queue --limit=10` (D11). Empty cache auto-populates from GitHub (#2575).
31
31
 
32
- ⊗ Recommend work without queue/plan consult; ⊗ widen past an exhausted plan.
32
+ ⊗ Recommend work without queue/plan consult; ⊗ widen past an exhausted plan; ⊗ conclude "nothing to do" from `xbrief/{pending,active}` folder scans or GitHub-only reads without `deft triage:queue` (#2576).
33
33
 
34
34
  ## Umbrella status reading (#1152 / #2066)
35
35
 
@@ -57,9 +57,15 @@ Legacy `vbrief/` read-accepted; `deft migrate:xbrief` for `xbrief/` (v0.6→v0.8
57
57
 
58
58
  ! **Skills Index** (Level-0) in `.deft/core/REFERENCES.md` — scan before improvising; read `SKILL.md` only on index match. `welcome` / `onboard triage` → `deft triage:welcome --onboard` (N3 / #1143); lessons → packs:slice.
59
59
 
60
+ ## Skill pin policy (#2508)
61
+
62
+ ! Process-critical skills with false-negative risk MUST be named in AGENTS.md (always-pin tier) — tier definitions: `.deft/core/docs/skill-pin-policy.md` (#2508).
63
+ ! **Default always-pins:** `deft-directive-build`, `deft-directive-pre-pr`, `deft-directive-review-cycle`, `deft-directive-swarm` — read each `SKILL.md` when that work type starts.
64
+ ⊗ Pin entire language packs, deployment docs, or framework bulk into AGENTS.md — pins are for false-negative-sensitive process gates only (#2508).
65
+
60
66
  ## Review-surface precedence (#2308)
61
67
 
62
- ! Route review through `deft-directive-review-cycle` — `.deft/core/.agents/skills/deft-directive-review-cycle/SKILL.md`; host `bugbot` / `security-review` / `review-*` advisory-only (#2308).
68
+ ! Route PR shepherding / review work through `deft-directive-review-cycle` — `.deft/core/.agents/skills/deft-directive-review-cycle/SKILL.md`; host `babysit` / `bugbot` / `security-review` advisory-only (#2308 / #2261).
63
69
 
64
70
  ## Value feedback and attribution (#1709)
65
71
 
@@ -67,7 +73,7 @@ Legacy `vbrief/` read-accepted; `deft migrate:xbrief` for `xbrief/` (v0.6→v0.8
67
73
 
68
74
  ## Eval and framework health (#1703)
69
75
 
70
- ! `deft eval:health` when orienting or after gate/policy changes (Tier 0; 4-hour debounce). Release: `deft eval:run` / `deft eval:report` (#1703).
76
+ ! `deft eval:health` when orienting or after gate/policy changes (Tier 0; 4-hour debounce). Release: `deft eval:run` / `deft eval:report`; skill routing: `deft eval:triggers` (#1586 / #1703).
71
77
 
72
78
  ## Branch policy & branch verification
73
79
 
@@ -79,7 +85,7 @@ Legacy `vbrief/` read-accepted; `deft migrate:xbrief` for `xbrief/` (v0.6→v0.8
79
85
 
80
86
  ## Contextual guardrails (runtime-detect lazy-load)
81
87
 
82
- ! Lazy-load `.deft/core/scm/github.md` before risky ops (#2157 / #2369): PowerShell → `deft verify:encoding` (#798); TS capture (#1366); cascade → `deft pr:wait-mergeable-and-merge` (#1369); SCM → `deft verify:scm-boundary` (#884).
88
+ ! Detect OS/shell; use portable syntax or explicit shell (#2568). `.deft/core/scm/github.md` (#2157/#2369): PS→`deft verify:encoding`; TS capture; cascade→`deft pr:wait-mergeable-and-merge`; SCM→`deft verify:scm-boundary`.
83
89
 
84
90
  ## Development Process
85
91