@xmoon76/dsh-pi-tui 0.3.6 → 0.4.0-alpha.2

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.
@@ -26,11 +26,15 @@ interface HarnessCompatEntry {
26
26
  max?: string;
27
27
  /** The bundle release line that first required this constraint. */
28
28
  since: string;
29
- /** Human-readable requirement, e.g. `DeepSeek Harness 0.1.1-rc.1 or later`. */
29
+ /** Human-readable requirement, e.g. `DeepSeek Harness 0.1.2-alpha.4 or later`. */
30
30
  requires: string;
31
- /** What the user must do; placeholders are NOT needed — the message
32
- * builder fills in the requirement and the installed version. */
33
- guidance: string;
31
+ /** The target DSH version to install when the current runtime is too old. */
32
+ upgradeDsh?: string;
33
+ /** The compatible TUI line to install when keeping an old DSH runtime. */
34
+ fallbackTui?: string;
35
+ /** Special guidance for a range that is not covered by the normal recovery
36
+ * commands, such as an unvalidated future DSH line. */
37
+ guidance?: string;
34
38
  }
35
39
  /** The compatibility table. */
36
40
  declare const HARNESS_COMPAT: readonly HarnessCompatEntry[];
@@ -41,9 +45,11 @@ declare function harnessCompatEntryFor(installed: string): HarnessCompatEntry |
41
45
  * package.json at runtime (never hardcoded). Falls back to the release
42
46
  * line that first imposed the requirement when unreadable. */
43
47
  declare function bundleVersionLabel(since: string): string;
44
- /** The actionable message printed before the loader's raw failure when the
45
- * installed harness falls in an incompatible range. `entry` MUST be the
46
- * entry {@link harnessCompatEntryFor} matched for `installed`. */
48
+ /** The actionable compatibility notice printed when the installed harness
49
+ * falls in an incompatible range. `entry` MUST be the entry
50
+ * {@link harnessCompatEntryFor} matched for `installed`. The notice is
51
+ * advisory: DSH Loader mounts profile entries concurrently, so this row cannot
52
+ * guarantee that its output precedes another row's import failure. */
47
53
  declare function incompatibleHarnessMessage(installed: string, entry: HarnessCompatEntry): string;
48
54
  /** Service provided by this plugin and injected by the TUI runner row. */
49
55
  declare const TUI_STARTUP_SERVICE = "tuiStartup";
@@ -53,13 +59,6 @@ interface TuiStartupValues {
53
59
  sessionId?: string;
54
60
  /** `--preset`, the agent preset a fresh session starts on. */
55
61
  presetId?: string;
56
- /**
57
- * The shipped agent-preset root bundled with this package. Absolute path of
58
- * `config/agent-presets/` beside the built `lib/`; rows configured from the
59
- * service (the `agent-presets` roster row) resolve it only after this
60
- * service exists, mirroring the web bundle's `webStartup` pattern.
61
- */
62
- shippedPresetRoot: string;
63
62
  }
64
63
  /**
65
64
  * Parse and provide the TUI invocation as an ordinary Cordis service. The
package/dist/startup.mjs CHANGED
@@ -68,10 +68,18 @@ const name = "tui-startup";
68
68
  const inject = ["cmdlineArgs"];
69
69
  /** The compatibility table. */
70
70
  const HARNESS_COMPAT = [{
71
- max: "0.1.1-rc.1",
72
- since: "0.3.0",
73
- requires: "DeepSeek Harness 0.1.1-rc.1 or later",
74
- guidance: "Upgrade dsh first, e.g.: npm install -g @deepseek-ai/dsh@0.1.1-rc.1"
71
+ min: "0.1.2-alpha.2",
72
+ max: "0.1.2-alpha.4",
73
+ since: "0.4.0-alpha.2",
74
+ requires: "DeepSeek Harness 0.1.2-alpha.4 or later",
75
+ upgradeDsh: "0.1.2-alpha.5",
76
+ fallbackTui: "0.4.0-alpha.1"
77
+ }, {
78
+ max: "0.1.2-alpha.2",
79
+ since: "0.4.0-alpha.1",
80
+ requires: "DeepSeek Harness 0.1.2-alpha.2 or later",
81
+ upgradeDsh: "0.1.2-alpha.5",
82
+ fallbackTui: "0.3"
75
83
  }];
76
84
  /** The compat entry covering the installed dsh version, or undefined when
77
85
  * the harness is supported. */
@@ -89,15 +97,25 @@ function bundleVersionLabel(since) {
89
97
  return `>= ${since}`;
90
98
  }
91
99
  }
92
- /** The actionable message printed before the loader's raw failure when the
93
- * installed harness falls in an incompatible range. `entry` MUST be the
94
- * entry {@link harnessCompatEntryFor} matched for `installed`. */
100
+ /** The actionable compatibility notice printed when the installed harness
101
+ * falls in an incompatible range. `entry` MUST be the entry
102
+ * {@link harnessCompatEntryFor} matched for `installed`. The notice is
103
+ * advisory: DSH Loader mounts profile entries concurrently, so this row cannot
104
+ * guarantee that its output precedes another row's import failure. */
95
105
  function incompatibleHarnessMessage(installed, entry) {
106
+ const recovery = [];
107
+ if (entry.upgradeDsh !== void 0) recovery.push("Upgrade DeepSeek Harness:", ` npm install -g @deepseek-ai/dsh@${entry.upgradeDsh}`);
108
+ if (entry.fallbackTui !== void 0) recovery.push("Or keep your current Harness and use the compatible TUI line:", ` npm install -g @xmoon76/dsh-pi-tui@${entry.fallbackTui}`);
109
+ if (entry.guidance !== void 0) recovery.push(entry.guidance);
96
110
  return [
97
111
  `dsh-pi-tui ${bundleVersionLabel(entry.since)} requires ${entry.requires},`,
98
112
  `but this installation is running dsh ${installed}.`,
99
113
  "",
100
- `${entry.guidance}`,
114
+ ...recovery.length === 0 ? [] : [
115
+ "Choose one:",
116
+ "",
117
+ ...recovery
118
+ ],
101
119
  "Then re-run: dsh --profile pi-tui"
102
120
  ].join("\n");
103
121
  }
@@ -127,14 +145,12 @@ function apply(ctx) {
127
145
  if (entry !== void 0) {
128
146
  const message = incompatibleHarnessMessage(installed, entry);
129
147
  process.stderr.write(`\n${message}\n\n`);
130
- throw new Error(message);
131
148
  }
132
149
  }
133
150
  const options = program.opts();
134
151
  ctx.provide(TUI_STARTUP_SERVICE, {
135
152
  ...options.session !== void 0 ? { sessionId: options.session } : {},
136
- ...options.preset !== void 0 ? { presetId: options.preset } : {},
137
- shippedPresetRoot: join(import.meta.dirname, "..", "config", "agent-presets")
153
+ ...options.preset !== void 0 ? { presetId: options.preset } : {}
138
154
  });
139
155
  });
140
156
  parseCmdline(ctx, program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmoon76/dsh-pi-tui",
3
- "version": "0.3.6",
3
+ "version": "0.4.0-alpha.2",
4
4
  "description": "The dsh-pi-tui bundle: a TUI surface for DeepSeek Harness profiles (dsh --profile pi-tui)",
5
5
  "license": "MIT",
6
6
  "author": "XMoon <xmoonox@gmail.com>",
@@ -53,7 +53,6 @@
53
53
  },
54
54
  "files": [
55
55
  "dist",
56
- "config",
57
56
  "scripts/repair-session.mjs",
58
57
  "scripts/repair-core.mjs",
59
58
  "cordis.patch.yml",
@@ -76,77 +75,108 @@
76
75
  "marked": "18.0.5"
77
76
  },
78
77
  "peerDependencies": {
79
- "@deepseek-ai/cordis": "^4.0.1",
78
+ "@deepseek-ai/cordis": "^4.0.2",
80
79
  "@deepseek-ai/cordis-plugin-loader": "^1.0.2",
81
- "@deepseek-ai/dsh-agent": "^0.1.1-rc.1",
82
- "@deepseek-ai/dsh-agent-default-model": "^0.1.1-rc.1",
83
- "@deepseek-ai/dsh-agent-presets": "^0.1.1-rc.1",
84
- "@deepseek-ai/dsh-authorization": "^0.1.1-rc.1",
85
- "@deepseek-ai/dsh-cmdline": "^0.1.1-rc.1",
86
- "@deepseek-ai/dsh-commands": "^0.1.1-rc.1",
87
- "@deepseek-ai/dsh-credentials": "^0.1.1-rc.1",
88
- "@deepseek-ai/dsh-goal": "^0.1.1-rc.1",
89
- "@deepseek-ai/dsh-jobs": "^0.1.1-rc.1",
90
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.1",
91
- "@deepseek-ai/dsh-llm-retry": "^0.1.1-rc.1",
92
- "@deepseek-ai/dsh-permission-presets": "^0.1.1-rc.1",
93
- "@deepseek-ai/dsh-plan-mode": "^0.1.1-rc.1",
94
- "@deepseek-ai/dsh-sandbox-policy": "^0.1.1-rc.1",
95
- "@deepseek-ai/dsh-session": "^0.1.1-rc.1",
96
- "@deepseek-ai/dsh-session-persistence": "^0.1.1-rc.1",
97
- "@deepseek-ai/dsh-session-title": "^0.1.1-rc.1",
98
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.1",
99
- "@deepseek-ai/dsh-shell": "^0.1.1-rc.1",
100
- "@deepseek-ai/dsh-skill": "^0.1.1-rc.1",
101
- "@deepseek-ai/dsh-subagent": "^0.1.1-rc.1",
102
- "@deepseek-ai/dsh-token-meter": "^0.1.1-rc.1",
103
- "@deepseek-ai/dsh-tool-workflow": "^0.1.1-rc.1",
104
- "@deepseek-ai/dsh-tools": "^0.1.1-rc.1",
105
- "@deepseek-ai/dsh-user-approval": "^0.1.1-rc.1",
106
- "@deepseek-ai/dsh-user-questions": "^0.1.1-rc.1",
80
+ "@deepseek-ai/dsh-agent": ">=0.1.2-alpha.4",
81
+ "@deepseek-ai/dsh-agent-default-model": ">=0.1.2-alpha.4",
82
+ "@deepseek-ai/dsh-agent-presets": ">=0.1.2-alpha.4",
83
+ "@deepseek-ai/dsh-authorization": ">=0.1.2-alpha.4",
84
+ "@deepseek-ai/dsh-cmdline": ">=0.1.2-alpha.4",
85
+ "@deepseek-ai/dsh-commands": ">=0.1.2-alpha.4",
86
+ "@deepseek-ai/dsh-credentials": ">=0.1.2-alpha.4",
87
+ "@deepseek-ai/dsh-goal": ">=0.1.2-alpha.4",
88
+ "@deepseek-ai/dsh-jobs": ">=0.1.2-alpha.4",
89
+ "@deepseek-ai/dsh-llm": ">=0.1.2-alpha.4",
90
+ "@deepseek-ai/dsh-llm-retry": ">=0.1.2-alpha.4",
91
+ "@deepseek-ai/dsh-permission-presets": ">=0.1.2-alpha.4",
92
+ "@deepseek-ai/dsh-plan-mode": ">=0.1.2-alpha.4",
93
+ "@deepseek-ai/dsh-sandbox-policy": ">=0.1.2-alpha.4",
94
+ "@deepseek-ai/dsh-session": ">=0.1.2-alpha.4",
95
+ "@deepseek-ai/dsh-session-persistence": ">=0.1.2-alpha.4",
96
+ "@deepseek-ai/dsh-session-title": ">=0.1.2-alpha.4",
97
+ "@deepseek-ai/dsh-settings": ">=0.1.2-alpha.4",
98
+ "@deepseek-ai/dsh-shell": ">=0.1.2-alpha.4",
99
+ "@deepseek-ai/dsh-skill": ">=0.1.2-alpha.4",
100
+ "@deepseek-ai/dsh-subagent": ">=0.1.2-alpha.4",
101
+ "@deepseek-ai/dsh-token-meter": ">=0.1.2-alpha.4",
102
+ "@deepseek-ai/dsh-tool-todo": ">=0.1.2-alpha.4",
103
+ "@deepseek-ai/dsh-tool-workflow": ">=0.1.2-alpha.4",
104
+ "@deepseek-ai/dsh-tools": ">=0.1.2-alpha.4",
105
+ "@deepseek-ai/dsh-user-approval": ">=0.1.2-alpha.4",
106
+ "@deepseek-ai/dsh-user-questions": ">=0.1.2-alpha.4",
107
107
  "@deepseek-ai/schemastery": "^3.18.1"
108
108
  },
109
109
  "devDependencies": {
110
110
  "@deepseek-ai/cordis-plugin-loader": "^1.0.2",
111
- "@deepseek-ai/dsh-agent": "^0.1.1-rc.1",
112
- "@deepseek-ai/dsh-agent-default-model": "^0.1.1-rc.1",
113
- "@deepseek-ai/dsh-agent-loop": "^0.1.1-rc.1",
114
- "@deepseek-ai/dsh-agent-presets": "^0.1.1-rc.1",
115
- "@deepseek-ai/dsh-attachment": "^0.1.1-rc.1",
116
- "@deepseek-ai/dsh-authorization": "^0.1.1-rc.1",
117
- "@deepseek-ai/dsh-brand": "^0.1.1-rc.1",
118
- "@deepseek-ai/dsh-commands": "^0.1.1-rc.1",
119
- "@deepseek-ai/dsh-credentials": "^0.1.1-rc.1",
120
- "@deepseek-ai/dsh-goal": "^0.1.1-rc.1",
121
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.1",
122
- "@deepseek-ai/dsh-jobs": "^0.1.1-rc.1",
123
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.1",
124
- "@deepseek-ai/dsh-llm-retry": "^0.1.1-rc.1",
125
- "@deepseek-ai/dsh-permission-presets": "^0.1.1-rc.1",
126
- "@deepseek-ai/dsh-plan-mode": "^0.1.1-rc.1",
127
- "@deepseek-ai/dsh-scope": "^0.1.1-rc.1",
128
- "@deepseek-ai/dsh-session": "^0.1.1-rc.1",
129
- "@deepseek-ai/dsh-session-persistence": "^0.1.1-rc.1",
130
- "@deepseek-ai/dsh-session-title": "^0.1.1-rc.1",
131
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.1",
132
- "@deepseek-ai/dsh-shell": "^0.1.1-rc.1",
133
- "@deepseek-ai/dsh-skill": "^0.1.1-rc.1",
134
- "@deepseek-ai/dsh-subagent": "^0.1.1-rc.1",
135
- "@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.1",
136
- "@deepseek-ai/dsh-timeout": "^0.1.1-rc.1",
137
- "@deepseek-ai/dsh-token-meter": "^0.1.1-rc.1",
138
- "@deepseek-ai/dsh-tool-workflow": "^0.1.1-rc.1",
139
- "@deepseek-ai/dsh-tools": "^0.1.1-rc.1",
140
- "@deepseek-ai/dsh-user-approval": "^0.1.1-rc.1",
141
- "@deepseek-ai/dsh-user-questions": "^0.1.1-rc.1",
111
+ "@deepseek-ai/dsh-agent": "0.1.2-alpha.5",
112
+ "@deepseek-ai/dsh-agent-default-model": "0.1.2-alpha.5",
113
+ "@deepseek-ai/dsh-agent-loop": "0.1.2-alpha.5",
114
+ "@deepseek-ai/dsh-agent-presets": "0.1.2-alpha.5",
115
+ "@deepseek-ai/dsh-attachment": "0.1.2-alpha.5",
116
+ "@deepseek-ai/dsh-authorization": "0.1.2-alpha.5",
117
+ "@deepseek-ai/dsh-brand": "0.1.2-alpha.5",
118
+ "@deepseek-ai/dsh-cmdline": "0.1.2-alpha.5",
119
+ "@deepseek-ai/dsh-commands": "0.1.2-alpha.5",
120
+ "@deepseek-ai/dsh-credentials": "0.1.2-alpha.5",
121
+ "@deepseek-ai/dsh-goal": "0.1.2-alpha.5",
122
+ "@deepseek-ai/dsh-invariants": "0.1.2-alpha.5",
123
+ "@deepseek-ai/dsh-jobs": "0.1.2-alpha.5",
124
+ "@deepseek-ai/dsh-llm": "0.1.2-alpha.5",
125
+ "@deepseek-ai/dsh-llm-retry": "0.1.2-alpha.5",
126
+ "@deepseek-ai/dsh-permission-presets": "0.1.2-alpha.5",
127
+ "@deepseek-ai/dsh-plan-mode": "0.1.2-alpha.5",
128
+ "@deepseek-ai/dsh-sandbox-policy": "0.1.2-alpha.5",
129
+ "@deepseek-ai/dsh-scope": "0.1.2-alpha.5",
130
+ "@deepseek-ai/dsh-session": "0.1.2-alpha.5",
131
+ "@deepseek-ai/dsh-session-persistence": "0.1.2-alpha.5",
132
+ "@deepseek-ai/dsh-session-title": "0.1.2-alpha.5",
133
+ "@deepseek-ai/dsh-settings": "0.1.2-alpha.5",
134
+ "@deepseek-ai/dsh-shell": "0.1.2-alpha.5",
135
+ "@deepseek-ai/dsh-skill": "0.1.2-alpha.5",
136
+ "@deepseek-ai/dsh-subagent": "0.1.2-alpha.5",
137
+ "@deepseek-ai/dsh-system-prompt": "0.1.2-alpha.5",
138
+ "@deepseek-ai/dsh-timeout": "0.1.2-alpha.5",
139
+ "@deepseek-ai/dsh-token-meter": "0.1.2-alpha.5",
140
+ "@deepseek-ai/dsh-tool-todo": "0.1.2-alpha.5",
141
+ "@deepseek-ai/dsh-tool-workflow": "0.1.2-alpha.5",
142
+ "@deepseek-ai/dsh-tools": "0.1.2-alpha.5",
143
+ "@deepseek-ai/dsh-user-approval": "0.1.2-alpha.5",
144
+ "@deepseek-ai/dsh-user-questions": "0.1.2-alpha.5",
142
145
  "@deepseek-ai/schemastery": "^3.18.1",
143
146
  "@types/node": "^22.0.0",
144
- "@xmoon76/pi-tui": "^0.84.3",
147
+ "@xmoon76/pi-tui": "^0.84.4",
145
148
  "@xterm/headless": "5.5.0",
146
149
  "husky": "^9.1.7",
150
+ "semver": "7.8.5",
147
151
  "tsdown": "0.22.0",
148
152
  "tsx": "^4.23.12",
149
- "typescript": "^5.9.0"
153
+ "typescript": "^5.9.0",
154
+ "@deepseek-ai/dsh-session-projection": "0.1.2-alpha.5",
155
+ "@deepseek-ai/dsh-persona": "0.1.2-alpha.5",
156
+ "@deepseek-ai/dsh-agent-instructions": "0.1.2-alpha.5",
157
+ "@deepseek-ai/dsh-tool-fs": "0.1.2-alpha.5",
158
+ "@deepseek-ai/dsh-tool-fs-search": "0.1.2-alpha.5",
159
+ "@deepseek-ai/dsh-tool-jobs": "0.1.2-alpha.5",
160
+ "@deepseek-ai/dsh-skill-filesystem": "0.1.2-alpha.5",
161
+ "@deepseek-ai/dsh-tool-skill": "0.1.2-alpha.5",
162
+ "@deepseek-ai/dsh-command-goal": "0.1.2-alpha.5",
163
+ "@deepseek-ai/dsh-tool-goal": "0.1.2-alpha.5",
164
+ "@deepseek-ai/dsh-compaction-basic": "0.1.2-alpha.5",
165
+ "@deepseek-ai/dsh-command-compact": "0.1.2-alpha.5",
166
+ "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.1.2-alpha.5",
167
+ "@deepseek-ai/dsh-tool-subagent-control": "0.1.2-alpha.5",
168
+ "@deepseek-ai/dsh-tool-subagent": "0.1.2-alpha.5",
169
+ "@deepseek-ai/dsh-workflow-worker-thread": "0.1.2-alpha.5",
170
+ "@deepseek-ai/dsh-tool-ralph": "0.1.2-alpha.5",
171
+ "@deepseek-ai/dsh-tool-ask-user": "0.1.2-alpha.5",
172
+ "@deepseek-ai/dsh-tool-web": "0.1.2-alpha.5",
173
+ "@deepseek-ai/dsh-agent-tool-presentation": "0.1.2-alpha.5",
174
+ "@deepseek-ai/dsh-terminal": "0.1.2-alpha.5",
175
+ "@deepseek-ai/dsh-fs-local": "0.1.2-alpha.5",
176
+ "@deepseek-ai/dsh-tool-str-replace-editor": "0.1.2-alpha.5",
177
+ "@deepseek-ai/dsh-tool-cordis": "0.1.2-alpha.5",
178
+ "@deepseek-ai/dsh-agent-loop-testkit": "0.1.2-alpha.5",
179
+ "@deepseek-ai/dsh-subagent-spawn-in-process": "0.1.2-alpha.5"
150
180
  },
151
181
  "engines": {
152
182
  "node": "^22.19.0 || >=24"
@@ -160,28 +190,40 @@
160
190
  "typecheck:fork": "pnpm --dir packages/pi-tui typecheck",
161
191
  "typecheck:bundle": "tsc -p tsconfig.json --noEmit",
162
192
  "typecheck": "pnpm typecheck:fork && pnpm typecheck:bundle",
163
- "test:fork": "pnpm --dir packages/pi-tui test",
164
- "test:bundle": "node --test test/*.test.ts test/*.test.mjs",
165
- "test:docs": "node --test docs/tmux/*.test.mjs",
166
- "test": "pnpm test:fork && pnpm test:bundle && pnpm test:docs",
193
+ "test:fork": "node scripts/run-with-temp-root.mjs pnpm --dir packages/pi-tui test",
194
+ "test:bundle": "pnpm test:product && pnpm test:tooling",
195
+ "test:docs": "node scripts/run-with-temp-root.mjs node --test docs/tmux/*.test.mjs",
196
+ "test": "pnpm test:fork && pnpm test:product && pnpm test:tooling && pnpm test:docs",
167
197
  "smoke": "node scripts/tarball-smoke.mjs",
168
198
  "smoke:fixture": "node scripts/extension-fixture-smoke.mjs",
169
199
  "smoke:advanced": "node scripts/advanced-plugin-smoke.mjs",
170
200
  "smoke:phase4": "node scripts/phase4-plugin-smoke.mjs",
171
201
  "smoke:unstable": "node scripts/unstable-plugin-smoke.mjs",
172
202
  "smoke:pi2dsh": "node scripts/pi2dsh-compat-smoke.mjs",
203
+ "smoke:official-presets": "node scripts/official-presets-smoke.mjs",
204
+ "smoke:boundary": "node scripts/dsh-runtime-boundary-smoke.mjs",
205
+ "dsh:source:pack": "node scripts/dsh-source-pack.mjs",
206
+ "compat:dsh:source": "node scripts/dsh-source-verify.mjs",
207
+ "compat:dsh:npm": "node scripts/dsh-npm-verify.mjs",
208
+ "prepare:dsh:test": "node scripts/prepare-dsh-test-environment.mjs",
209
+ "gate:source-leak": "node scripts/dsh-source-leak-gate.mjs",
210
+ "gate:temp-hygiene": "node scripts/temp-hygiene-gate.mjs",
211
+ "gate:pi-vendor-diff": "node scripts/pi-vendor-diff-gate.mjs",
173
212
  "smoke:vim": "node scripts/vim-plugin-smoke.mjs",
174
213
  "gate:pi-surface-compat": "node --test test/pi-component-compat.test.ts",
175
214
  "smoke:examples": "node scripts/examples-plugin-smoke.mjs",
176
215
  "pack:release": "rm -f xmoon76-dsh-pi-tui-*.tgz && pnpm pack --pack-destination .",
216
+ "release:context": "node scripts/release-context.mjs",
177
217
  "release:notes": "node scripts/release-notes.mjs",
178
218
  "smoke:pack": "node scripts/tarball-smoke.mjs",
179
219
  "dev:doctor": "node scripts/dev-doctor.mjs",
180
220
  "dev:bootstrap": "node scripts/dev-bootstrap.mjs",
181
221
  "dev:shell": "node scripts/dev-shell.mjs",
182
- "verify:prepush": "pnpm typecheck:fork && pnpm test:fork && pnpm test:docs && node scripts/naming-gate.mjs && pnpm gate:boundary && pnpm gate:keybindings && pnpm audit --prod --audit-level high && pnpm pack:release",
183
- "verify:prepush:nofork": "pnpm test:docs && node scripts/naming-gate.mjs && pnpm gate:boundary && pnpm gate:keybindings && pnpm audit --prod --audit-level high && pnpm pack:release",
222
+ "verify:prepush": "pnpm typecheck:fork && pnpm test:fork && pnpm test:docs && pnpm test:tooling && node scripts/naming-gate.mjs && pnpm gate:temp-hygiene && node scripts/check-no-session-events.mjs && pnpm gate:boundary && pnpm gate:keybindings && pnpm audit --prod --audit-level high && pnpm pack:release",
223
+ "verify:prepush:nofork": "pnpm test:docs && pnpm test:tooling && node scripts/naming-gate.mjs && pnpm gate:temp-hygiene && node scripts/check-no-session-events.mjs && pnpm gate:boundary && pnpm gate:keybindings && pnpm audit --prod --audit-level high && pnpm pack:release",
184
224
  "gate:boundary": "node scripts/client-boundary-gate.mjs",
185
- "gate:keybindings": "node --import tsx/esm scripts/check-host-keybindings.mts"
225
+ "gate:keybindings": "node --import tsx/esm scripts/check-host-keybindings.mts",
226
+ "test:tooling": "node scripts/run-with-temp-root.mjs node --test test/dev-environment.test.mjs test/dev-bootstrap-ephemeral.test.mjs test/pre-push-hook.test.mjs test/pre-push-stages.test.mjs test/dsh-ci-context.test.mjs test/dsh-distribution.test.mjs test/dsh-npm-verify.test.mjs test/dsh-peer-window.test.mjs test/dsh-process.test.mjs test/dsh-runtime-boundary.test.mjs test/dsh-source-identity.test.mjs test/dsh-source-leak.test.mjs test/release-context.test.mjs test/release-notes.test.mjs test/source-mode-rules.test.mjs test/client-boundary-gate.test.mjs test/tarball-source-install.test.mjs test/pi2dsh-compat-smoke.test.mjs test/temp-hygiene-gate.test.mjs test/pi-vendor-diff-gate.test.mjs test/run-with-temp-root.test.mjs",
227
+ "test:product": "node scripts/run-with-temp-root.mjs node --test test/*.test.ts test/repair.test.mjs test/tarball-smoke.test.mjs"
186
228
  }
187
229
  }
@@ -37,7 +37,7 @@ import { randomUUID } from 'node:crypto'
37
37
  import { copyFileSync, existsSync, openSync, fsyncSync, closeSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs'
38
38
  import { homedir } from 'node:os'
39
39
  import { basename, dirname, join, resolve } from 'node:path'
40
- import { pathToFileURL } from 'node:url'
40
+ import { fileURLToPath, pathToFileURL } from 'node:url'
41
41
  import { createRequire } from 'node:module'
42
42
  import { spawnSync } from 'node:child_process'
43
43
  import { zstdCompressSync, zstdDecompressSync } from 'node:zlib'
@@ -461,8 +461,20 @@ function main(args) {
461
461
  console.log(` verify: valid frame layout, contiguous, ${verifyEvents.events.length} event(s)`)
462
462
  }
463
463
 
464
- const isMain = process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href
465
- if (isMain) {
464
+ function invokedAsMainModule() {
465
+ const entry = process.argv[1]
466
+ if (entry === undefined) return false
467
+ try {
468
+ // pnpm exposes package files through symlinks. Node resolves
469
+ // import.meta.url to the real file while argv[1] retains the symlink, so
470
+ // compare canonical paths instead of treating a symlinked CLI as an import.
471
+ return realpathSync(entry) === fileURLToPath(import.meta.url)
472
+ } catch {
473
+ return import.meta.url === pathToFileURL(entry).href
474
+ }
475
+ }
476
+
477
+ if (invokedAsMainModule()) {
466
478
  try {
467
479
  main(process.argv.slice(2))
468
480
  } catch (error) {