@deftai/directive-content 0.73.0 → 0.74.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.
@@ -24,6 +24,22 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
24
24
  - User asks to create USER.md, PROJECT-DEFINITION.xbrief.json, or a specification
25
25
  - User clones a deft-enabled repo for the first time with no config
26
26
 
27
+ ## Consumer-first default (#1813)
28
+
29
+ ! Assume the operator is **using Deft in their project** (consumer path). Proceed directly to the Pre-Cutover Detection Guard and Phase 1 — do NOT open with a contributor-vs-consumer fork.
30
+
31
+ ~ The overwhelming majority of setup sessions are consumer installs; contributor onboarding is a separate, opt-in path (see below).
32
+
33
+ ## Contributor / framework-maintainer path (secondary)
34
+
35
+ ? Only enter this branch when the user **explicitly** says they are working on Deft itself (framework source checkout, `deftai/directive` clone, or maintainer tooling).
36
+
37
+ When that happens:
38
+
39
+ 1. ! Tell the user: "Contributor setup lives in [`CONTRIBUTING.md`](../../../CONTRIBUTING.md) and this repo's root [`AGENTS.md`](../../../AGENTS.md). Use the maintainer installer: `deft-install --yes --upgrade --maintainer --repo-root . --json`."
40
+ 2. ⊗ Continue the consumer USER.md / PROJECT-DEFINITION interview — the maintainer path does not use the first-session consumer flow.
41
+ 3. **Stop here** unless the user explicitly asks to continue with consumer setup anyway.
42
+
27
43
  ## Pre-Cutover Detection Guard
28
44
 
29
45
  ! Before proceeding with any setup phase, detect whether the project uses the pre-v0.20 document model and redirect to migration if so.
package/tasks/engine.yml CHANGED
@@ -10,6 +10,76 @@ vars:
10
10
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'
11
11
 
12
12
  tasks:
13
+ pm-run:
14
+ internal: true
15
+ desc: "Run a package.json script via pnpm (bare or Corepack pin) or explicit DEFT_PACKAGE_MANAGER=npm (#2410)."
16
+ dir: '{{.DEFT_ROOT}}'
17
+ cmds:
18
+ - |
19
+ set -eu
20
+ node -e "
21
+ const {execFileSync}=require('child_process');
22
+ const fs=require('fs');
23
+ const root=process.argv[1];
24
+ const script=process.argv[2];
25
+ const pkgPath=root+'/package.json';
26
+ if(!fs.existsSync(pkgPath)){
27
+ console.error('deft: package.json missing at '+root);
28
+ process.exit(2);
29
+ }
30
+ const pkg=JSON.parse(fs.readFileSync(pkgPath,'utf8'));
31
+ // Cross-platform probe (#2415): do NOT use Unix `sh -c 'command -v'` —
32
+ // Windows native Task often has no `sh` on PATH, so Corepack.cmd was
33
+ // invisible after #2411. Prefer a direct spawn (POSIX / real binaries);
34
+ // fall back to shell:true so PATHEXT resolves .cmd/.exe on win32.
35
+ const hasCmd=(name)=>{
36
+ try{
37
+ execFileSync(name,['--version'],{stdio:'ignore'});
38
+ return true;
39
+ }catch{
40
+ try{
41
+ execFileSync(name,['--version'],{stdio:'ignore',shell:true});
42
+ return true;
43
+ }catch{
44
+ return false;
45
+ }
46
+ }
47
+ };
48
+ const run=(cmd,args)=>{
49
+ execFileSync(cmd,args,{cwd:root,stdio:'inherit',shell:true});
50
+ };
51
+ const trySteps=(steps)=>{
52
+ for(const [cmd,args] of steps){
53
+ try{
54
+ run(cmd,args);
55
+ process.exit(0);
56
+ }catch{
57
+ // fall through to Corepack / next resolver
58
+ }
59
+ }
60
+ };
61
+ const envPm=String(process.env.DEFT_PACKAGE_MANAGER||'').trim().toLowerCase();
62
+ if(envPm==='npm'){
63
+ run('npm',['run',script]);
64
+ process.exit(0);
65
+ }
66
+ const pin=String(pkg.packageManager||'').trim();
67
+ const match=pin.match(/^pnpm@(.+)$/);
68
+ const steps=[];
69
+ if(hasCmd('pnpm')) steps.push(['pnpm',['run',script]]);
70
+ if(hasCmd('corepack')&&match) steps.push(['corepack',['pnpm@'+match[1],'run',script]]);
71
+ if(hasCmd('corepack')) steps.push(['corepack',['pnpm','run',script]]);
72
+ trySteps(steps);
73
+ console.error('deft: neither pnpm nor corepack is available to run \"'+script+'\".');
74
+ if(pin){
75
+ console.error(' Enable Corepack for the pinned manager: corepack enable && corepack prepare '+pin+' --activate');
76
+ }else{
77
+ console.error(' Install pnpm or enable Corepack (see package.json#packageManager).');
78
+ }
79
+ console.error(' Or set DEFT_PACKAGE_MANAGER=npm for an explicit npm build path.');
80
+ process.exit(127);
81
+ " "{{.DEFT_ROOT}}" "{{.PM_SCRIPT}}"
82
+
13
83
  _ts-build:
14
84
  internal: true
15
85
  desc: "Build CLI dist from the framework source checkout; no-op on npm consumer deposits that ship no packages/ source (#2022 Phase 3 / #2126)."
@@ -32,12 +102,69 @@ tasks:
32
102
  if [ -f "{{.DEFT_ROOT}}/packages/cli/package.json" ] \
33
103
  && [ -f "{{.DEFT_ROOT}}/package.json" ] \
34
104
  && 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
35
- pnpm --dir "{{.DEFT_ROOT}}" run build
105
+ node -e "
106
+ const {execFileSync}=require('child_process');
107
+ const fs=require('fs');
108
+ const root=process.argv[1];
109
+ const script='build';
110
+ const pkgPath=root+'/package.json';
111
+ const pkg=JSON.parse(fs.readFileSync(pkgPath,'utf8'));
112
+ // Cross-platform probe (#2415): do NOT use Unix `sh -c 'command -v'` —
113
+ // Windows native Task often has no `sh` on PATH, so Corepack.cmd was
114
+ // invisible after #2411. Prefer a direct spawn (POSIX / real binaries);
115
+ // fall back to shell:true so PATHEXT resolves .cmd/.exe on win32.
116
+ const hasCmd=(name)=>{
117
+ try{
118
+ execFileSync(name,['--version'],{stdio:'ignore'});
119
+ return true;
120
+ }catch{
121
+ try{
122
+ execFileSync(name,['--version'],{stdio:'ignore',shell:true});
123
+ return true;
124
+ }catch{
125
+ return false;
126
+ }
127
+ }
128
+ };
129
+ const run=(cmd,args)=>{
130
+ execFileSync(cmd,args,{cwd:root,stdio:'inherit',shell:true});
131
+ };
132
+ const trySteps=(steps)=>{
133
+ for(const [cmd,args] of steps){
134
+ try{
135
+ run(cmd,args);
136
+ process.exit(0);
137
+ }catch{
138
+ // fall through to Corepack / next resolver
139
+ }
140
+ }
141
+ };
142
+ const envPm=String(process.env.DEFT_PACKAGE_MANAGER||'').trim().toLowerCase();
143
+ if(envPm==='npm'){
144
+ run('npm',['run',script]);
145
+ process.exit(0);
146
+ }
147
+ const pin=String(pkg.packageManager||'').trim();
148
+ const match=pin.match(/^pnpm@(.+)$/);
149
+ const steps=[];
150
+ if(hasCmd('pnpm')) steps.push(['pnpm',['run',script]]);
151
+ if(hasCmd('corepack')&&match) steps.push(['corepack',['pnpm@'+match[1],'run',script]]);
152
+ if(hasCmd('corepack')) steps.push(['corepack',['pnpm','run',script]]);
153
+ trySteps(steps);
154
+ console.error('deft: neither pnpm nor corepack is available to run \"'+script+'\".');
155
+ if(pin){
156
+ console.error(' Enable Corepack for the pinned manager: corepack enable && corepack prepare '+pin+' --activate');
157
+ }else{
158
+ console.error(' Install pnpm or enable Corepack (see package.json#packageManager).');
159
+ }
160
+ console.error(' Or set DEFT_PACKAGE_MANAGER=npm for an explicit npm build path.');
161
+ process.exit(127);
162
+ " "{{.DEFT_ROOT}}"
36
163
  fi
37
164
 
38
165
  invoke:
39
166
  internal: true
40
- desc: "Run a deft-ts verb from vendored bin.js (source checkout) or global deft (npm consumer deposit). Source checkouts without a built dist fail fast (#2181) -- runtime/session tasks must not trigger engine:_ts-build / pnpm."
167
+ desc: "Run a deft-ts verb from vendored bin.js (source checkout) or global deft (npm consumer deposit / runtime fallback #2409). Runtime/session verbs must not trigger engine:_ts-build / pnpm (#2181)."
41
168
  # Run from the operator project root so deft verbs resolve USER_WORKING_DIR
42
169
  # correctly; without this, included engine.yml defaults cwd to tasks/ (#2022).
43
170
  dir: '{{.USER_WORKING_DIR}}'
@@ -69,11 +196,67 @@ tasks:
69
196
  fi
70
197
  node "$bin" {{.ENGINE_CMD}}
71
198
  elif [ "$is_buildable_source" = 1 ]; then
72
- echo "deft: CLI artifact missing at {{.DEFT_ROOT}}/packages/cli/dist/bin.js" >&2
73
- echo " Run \`task build\` first (framework source checkout)." >&2
74
- exit 2
199
+ engine_cmd='{{.ENGINE_CMD}}'
200
+ first_token="${engine_cmd%% *}"
201
+ is_runtime_verb=0
202
+ case " ${first_token} " in
203
+ " session:start "|" session-start "|\
204
+ " verify:session-ritual "|" verify-session-ritual "|\
205
+ " verify:tools "|" verify-tools "|\
206
+ " triage:summary "|" triage-summary "|\
207
+ " triage:welcome "|" triage-welcome "|\
208
+ " verify:cache-fresh "|" verify-cache-fresh "|\
209
+ " preflight-cache ")
210
+ is_runtime_verb=1
211
+ ;;
212
+ esac
213
+ if [ "${DEFT_USE_GLOBAL_CLI:-}" = "1" ]; then
214
+ is_runtime_verb=1
215
+ fi
216
+ global_cli=""
217
+ if command -v deft >/dev/null 2>&1; then
218
+ global_cli=deft
219
+ elif command -v directive >/dev/null 2>&1; then
220
+ global_cli=directive
221
+ fi
222
+ if [ "$is_runtime_verb" = 1 ] && [ -n "$global_cli" ]; then
223
+ node -e "
224
+ const {execFileSync}=require('child_process');
225
+ const root=process.argv[1];
226
+ const cli=process.argv[2];
227
+ let srcVer='0.0.0-dev';
228
+ try{
229
+ if(process.env.DEFT_RELEASE_VERSION){
230
+ srcVer=process.env.DEFT_RELEASE_VERSION;
231
+ }else{
232
+ srcVer=execFileSync('git',['describe','--tags','--abbrev=0'],{cwd:root,encoding:'utf8'}).trim().replace(/^v/,'');
233
+ }
234
+ }catch{}
235
+ let globalVer='unknown';
236
+ try{
237
+ globalVer=execFileSync(cli,['--version'],{encoding:'utf8'}).trim();
238
+ }catch{}
239
+ const m=globalVer.match(/@([0-9]+\\.[0-9]+\\.[0-9]+)/)||globalVer.match(/([0-9]+\\.[0-9]+\\.[0-9]+)/);
240
+ const gv=m?m[1]:globalVer;
241
+ if(srcVer!=='0.0.0-dev'&&gv!=='unknown'&&gv!==srcVer){
242
+ console.error('deft: using global '+cli+' ('+gv+'); source checkout is v'+srcVer+' — run task build for a local engine match.');
243
+ }
244
+ " "{{.DEFT_ROOT}}" "$global_cli" >&2 || true
245
+ "$global_cli" {{.ENGINE_CMD}}
246
+ else
247
+ echo "deft: CLI artifact missing at {{.DEFT_ROOT}}/packages/cli/dist/bin.js" >&2
248
+ if [ "$is_runtime_verb" = 1 ]; then
249
+ echo " Install global deft: npm i -g @deftai/directive" >&2
250
+ echo " Or run \`task build\` first (framework source checkout)." >&2
251
+ else
252
+ echo " Run \`task build\` first (framework source checkout)." >&2
253
+ fi
254
+ exit 2
255
+ fi
75
256
  elif command -v deft >/dev/null 2>&1; then
76
257
  deft {{.ENGINE_CMD}}
258
+ elif command -v directive >/dev/null 2>&1; then
259
+ directive {{.ENGINE_CMD}}
77
260
  else
78
261
  echo "deft: neither {{.DEFT_ROOT}}/packages/cli/dist/bin.js nor a global deft command is available." >&2
79
262
  echo " Install with: npm i -g @deftai/directive" >&2
package/tasks/ts.yml CHANGED
@@ -8,21 +8,24 @@ vars:
8
8
  tasks:
9
9
  build:
10
10
  desc: "Build the TypeScript engine monorepo (tsc -b project references, #1717)"
11
- dir: '{{.DEFT_ROOT}}'
12
11
  cmds:
13
- - pnpm run build
12
+ - task: :engine:pm-run
13
+ vars:
14
+ PM_SCRIPT: build
14
15
 
15
16
  test:
16
17
  desc: "Run the TypeScript engine test suite with coverage (vitest, #1717)"
17
- dir: '{{.DEFT_ROOT}}'
18
18
  cmds:
19
- - pnpm run test
19
+ - task: :engine:pm-run
20
+ vars:
21
+ PM_SCRIPT: test
20
22
 
21
23
  lint:
22
24
  desc: "Lint + format-check the TypeScript engine (biome, #1717)"
23
- dir: '{{.DEFT_ROOT}}'
24
25
  cmds:
25
- - pnpm run lint
26
+ - task: :engine:pm-run
27
+ vars:
28
+ PM_SCRIPT: lint
26
29
 
27
30
  check-lane:
28
31
  desc: "Run the TS lane (lint+build+test) when a Node toolchain is present; skip with a notice otherwise (#1530, #1790)."
@@ -96,23 +96,21 @@ Projects on the legacy `vbrief/` tree are still read-accepted; run `deft migrate
96
96
 
97
97
  ## Umbrella status reading (#1152 / #2066)
98
98
 
99
- Rationale + cross-references: `.deft/core/docs/analysis/2026-07-02-agents-md-incident-rule-rationale.md` § Umbrella current-shape convention (#1152).
100
-
101
99
  - ! Fetch issue comments via REST (`gh api repos/<owner>/<repo>/issues/<N>/comments`), read the `## Current shape (as of pass-N)` comment, and any linked context or `LockedDecisions` xBRIEF referenced there — following the reading order body -> current-shape comment -> amendment comments (claim-cites-state-surface, #2066). Prefer the deterministic read path: `deft umbrella:current-shape <N>` (or `task umbrella:current-shape <N>`) — it locates the canonical comment, validates #1152 sections, and never falls back to the issue body.
102
100
  - ⊗ Conclude umbrella or epic status from the issue body alone. Any "X is done" / "X is the blocker" assertion about an umbrella MUST cite the current-shape comment or another state artifact, not the body.
103
101
 
104
102
  ## Deterministic questions runtime obligation (#1470)
105
103
 
106
- Rationale + cross-references: `.deft/core/content/contracts/deterministic-questions.md` (#767); closes the agent-runtime enforcement gap on issue #1470.
104
+ Rationale + cross-references: `.deft/core/contracts/deterministic-questions.md` (#767); closes the agent-runtime enforcement gap on issue #1470.
107
105
 
108
- - ! ANY agent-initiated structured question — whether via host `ask_user_question` / `AskQuestion` tooling or a numbered menu rendered in chat — inside OR outside any skill flow MUST include `Discuss` and `Back` as the final two options, in that order, and MUST obey the Discuss-pause semantic documented verbatim in `.deft/core/content/contracts/deterministic-questions.md`.
106
+ - ! ANY agent-initiated structured question — whether via host `ask_user_question` / `AskQuestion` tooling or a numbered menu rendered in chat — inside OR outside any skill flow MUST include `Discuss` and `Back` as the final two options, in that order, and MUST obey the Discuss-pause semantic documented verbatim in `.deft/core/contracts/deterministic-questions.md`.
109
107
  - ! Before emitting any structured or numbered question, self-check: confirm `Discuss` and `Back` are present as the final two options; if not, add them before calling the tool or rendering the menu. Host-native `Other` / free-text affordances are NOT substitutes for `Discuss` (#767 / #431).
110
108
  - ⊗ Emit a structured or numbered question without `Discuss` and `Back` as the final two options — including ad-hoc orchestration approvals, dispatch confirmations, and decision walkthroughs outside interview/setup/refinement skills.
111
109
  - ⊗ Treat the host UI's automatic `Other` option as the stop-and-discuss escape hatch — `Other` widens the answer space; `Discuss` exits the deterministic flow entirely (see contract).
112
110
 
113
111
  ## Issue body→comments reading (#2143)
114
112
 
115
- Rationale + cross-references: `.deft/core/docs/analysis/2026-07-02-agents-md-incident-rule-rationale.md` § Issue body→comments reading (#2143); preamble § 5.6 in `.deft/core/content/templates/agent-prompt-preamble.md`.
113
+ Rationale + cross-references: preamble § 5.6 in `.deft/core/templates/agent-prompt-preamble.md` (#2143).
116
114
 
117
115
  - ! Fetch both the issue body and `repos/<owner>/<repo>/issues/<N>/comments` via REST before concluding what the issue asks for or building a worker dispatch envelope. Read body first, then the comment thread in chronological order.
118
116
  - ! `deft issue:ingest` / `task issue:ingest` fetches `/comments` by default and folds the thread into the ingested overview (#2143).
@@ -192,7 +190,7 @@ Override paths (`deft policy:show` / `deft policy:enforce-branches` / `deft poli
192
190
 
193
191
  ## Platform-conditional rules (PowerShell / Windows)
194
192
 
195
- Platform/tool/runtime-specific rules are lazy-loaded, not rendered here, so they don't crowd context for sessions that can't trigger them (#2157 / #1882). If your session matches a trigger below, load `.deft/core/content/scm/github.md` § "PowerShell platform-conditional rules for agents" **before** the risky operation:
193
+ Platform/tool/runtime-specific rules are lazy-loaded, not rendered here, so they don't crowd context for sessions that can't trigger them (#2157 / #1882). If your session matches a trigger below, load `.deft/core/scm/github.md` § "PowerShell platform-conditional rules for agents" **before** the risky operation:
196
194
 
197
195
  - ! Editing files with non-ASCII glyphs from PowerShell (especially PS 5.1) -- enforced at commit by `deft verify:encoding` (#798).
198
196
  - ! Running shell commands under the Grok Build Windows + pwsh 7+ runtime -- piped/redirected commands leak wrapper text (#1353); PTY-based Warp + Claude are exempt.
@@ -222,7 +220,7 @@ Platform/tool/runtime-specific rules are lazy-loaded, not rendered here, so they
222
220
 
223
221
  ## Commands
224
222
 
225
- Directive product commands use the `/deft:directive:*` namespace (#418 / #1670). Prior `/deft:*` product forms remain as deprecation-warning aliases — see `content/commands.md` for the full alias table. Cross-product session commands stay at the umbrella `/deft:*` level.
223
+ Directive product commands use the `/deft:directive:*` namespace (#418 / #1670). Prior `/deft:*` product forms remain as deprecation-warning aliases — see `.deft/core/commands.md` for the full alias table. Cross-product session commands stay at the umbrella `/deft:*` level.
226
224
 
227
225
  **Directive product (`/deft:directive:*`):**
228
226