@unbrained/pm-cli 2026.5.24 → 2026.5.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/CHANGELOG.md +953 -522
  2. package/README.md +2 -10
  3. package/dist/cli/bootstrap-args.d.ts +18 -1
  4. package/dist/cli/bootstrap-args.js +143 -3
  5. package/dist/cli/bootstrap-args.js.map +1 -1
  6. package/dist/cli/commander-usage.js +134 -11
  7. package/dist/cli/commander-usage.js.map +1 -1
  8. package/dist/cli/commands/append.js +4 -3
  9. package/dist/cli/commands/append.js.map +1 -1
  10. package/dist/cli/commands/claim.js +5 -4
  11. package/dist/cli/commands/claim.js.map +1 -1
  12. package/dist/cli/commands/close.d.ts +3 -0
  13. package/dist/cli/commands/close.js +26 -3
  14. package/dist/cli/commands/close.js.map +1 -1
  15. package/dist/cli/commands/completion.d.ts +2 -2
  16. package/dist/cli/commands/completion.js +109 -56
  17. package/dist/cli/commands/completion.js.map +1 -1
  18. package/dist/cli/commands/config.d.ts +1 -1
  19. package/dist/cli/commands/config.js +82 -4
  20. package/dist/cli/commands/config.js.map +1 -1
  21. package/dist/cli/commands/create.js +7 -272
  22. package/dist/cli/commands/create.js.map +1 -1
  23. package/dist/cli/commands/delete.js +4 -3
  24. package/dist/cli/commands/delete.js.map +1 -1
  25. package/dist/cli/commands/docs.d.ts +1 -12
  26. package/dist/cli/commands/docs.js +8 -312
  27. package/dist/cli/commands/docs.js.map +1 -1
  28. package/dist/cli/commands/extension/bundled-catalog.d.ts +14 -0
  29. package/dist/cli/commands/extension/bundled-catalog.js +268 -0
  30. package/dist/cli/commands/extension/bundled-catalog.js.map +1 -0
  31. package/dist/cli/commands/extension/doctor.d.ts +31 -0
  32. package/dist/cli/commands/extension/doctor.js +345 -0
  33. package/dist/cli/commands/extension/doctor.js.map +1 -0
  34. package/dist/cli/commands/extension/install-sources.d.ts +37 -0
  35. package/dist/cli/commands/extension/install-sources.js +384 -0
  36. package/dist/cli/commands/extension/install-sources.js.map +1 -0
  37. package/dist/cli/commands/extension/managed-state.d.ts +48 -0
  38. package/dist/cli/commands/extension/managed-state.js +172 -0
  39. package/dist/cli/commands/extension/managed-state.js.map +1 -0
  40. package/dist/cli/commands/extension/scaffold.d.ts +14 -0
  41. package/dist/cli/commands/extension/scaffold.js +202 -0
  42. package/dist/cli/commands/extension/scaffold.js.map +1 -0
  43. package/dist/cli/commands/extension/shared.d.ts +14 -0
  44. package/dist/cli/commands/extension/shared.js +106 -0
  45. package/dist/cli/commands/extension/shared.js.map +1 -0
  46. package/dist/cli/commands/extension.d.ts +36 -68
  47. package/dist/cli/commands/extension.js +143 -1422
  48. package/dist/cli/commands/extension.js.map +1 -1
  49. package/dist/cli/commands/files.d.ts +1 -12
  50. package/dist/cli/commands/files.js +11 -308
  51. package/dist/cli/commands/files.js.map +1 -1
  52. package/dist/cli/commands/get.js +4 -3
  53. package/dist/cli/commands/get.js.map +1 -1
  54. package/dist/cli/commands/health.js +17 -3
  55. package/dist/cli/commands/health.js.map +1 -1
  56. package/dist/cli/commands/history-redact.js +23 -18
  57. package/dist/cli/commands/history-redact.js.map +1 -1
  58. package/dist/cli/commands/history-repair.js +24 -18
  59. package/dist/cli/commands/history-repair.js.map +1 -1
  60. package/dist/cli/commands/legacy-none-tokens.d.ts +3 -0
  61. package/dist/cli/commands/legacy-none-tokens.js +39 -0
  62. package/dist/cli/commands/legacy-none-tokens.js.map +1 -0
  63. package/dist/cli/commands/linked-artifacts.d.ts +96 -0
  64. package/dist/cli/commands/linked-artifacts.js +335 -0
  65. package/dist/cli/commands/linked-artifacts.js.map +1 -0
  66. package/dist/cli/commands/linked-test-parsers.d.ts +28 -0
  67. package/dist/cli/commands/linked-test-parsers.js +192 -0
  68. package/dist/cli/commands/linked-test-parsers.js.map +1 -0
  69. package/dist/cli/commands/list.js +19 -5
  70. package/dist/cli/commands/list.js.map +1 -1
  71. package/dist/cli/commands/normalize.js +4 -3
  72. package/dist/cli/commands/normalize.js.map +1 -1
  73. package/dist/cli/commands/plan.d.ts +5 -0
  74. package/dist/cli/commands/plan.js +56 -8
  75. package/dist/cli/commands/plan.js.map +1 -1
  76. package/dist/cli/commands/recurrence-parsers.d.ts +26 -0
  77. package/dist/cli/commands/recurrence-parsers.js +98 -0
  78. package/dist/cli/commands/recurrence-parsers.js.map +1 -0
  79. package/dist/cli/commands/restore.js +19 -8
  80. package/dist/cli/commands/restore.js.map +1 -1
  81. package/dist/cli/commands/search.js +5 -8
  82. package/dist/cli/commands/search.js.map +1 -1
  83. package/dist/cli/commands/test/linked-command-detection.d.ts +37 -0
  84. package/dist/cli/commands/test/linked-command-detection.js +200 -0
  85. package/dist/cli/commands/test/linked-command-detection.js.map +1 -0
  86. package/dist/cli/commands/test.d.ts +1 -2
  87. package/dist/cli/commands/test.js +8 -350
  88. package/dist/cli/commands/test.js.map +1 -1
  89. package/dist/cli/commands/update-many.js +4 -3
  90. package/dist/cli/commands/update-many.js.map +1 -1
  91. package/dist/cli/commands/update.js +83 -356
  92. package/dist/cli/commands/update.js.map +1 -1
  93. package/dist/cli/commands/validate.js +32 -12
  94. package/dist/cli/commands/validate.js.map +1 -1
  95. package/dist/cli/error-guidance.d.ts +1 -0
  96. package/dist/cli/error-guidance.js +6 -2
  97. package/dist/cli/error-guidance.js.map +1 -1
  98. package/dist/cli/main.d.ts +11 -0
  99. package/dist/cli/main.js +76 -28
  100. package/dist/cli/main.js.map +1 -1
  101. package/dist/cli/register-list-query.d.ts +4 -1
  102. package/dist/cli/register-list-query.js +242 -203
  103. package/dist/cli/register-list-query.js.map +1 -1
  104. package/dist/cli/register-mutation.js +73 -11
  105. package/dist/cli/register-mutation.js.map +1 -1
  106. package/dist/cli/register-operations.js +3 -3
  107. package/dist/cli/register-operations.js.map +1 -1
  108. package/dist/cli/register-setup.js +12 -7
  109. package/dist/cli/register-setup.js.map +1 -1
  110. package/dist/cli/registration-helpers.js +3 -2
  111. package/dist/cli/registration-helpers.js.map +1 -1
  112. package/dist/cli.js +4 -3
  113. package/dist/cli.js.map +1 -1
  114. package/dist/core/config/positional-value.d.ts +44 -0
  115. package/dist/core/config/positional-value.js +109 -0
  116. package/dist/core/config/positional-value.js.map +1 -0
  117. package/dist/core/extensions/extension-capability-aliases.d.ts +14 -0
  118. package/dist/core/extensions/extension-capability-aliases.js +159 -0
  119. package/dist/core/extensions/extension-capability-aliases.js.map +1 -0
  120. package/dist/core/extensions/extension-hook-runtime.d.ts +13 -0
  121. package/dist/core/extensions/extension-hook-runtime.js +414 -0
  122. package/dist/core/extensions/extension-hook-runtime.js.map +1 -0
  123. package/dist/core/extensions/extension-policy.d.ts +69 -0
  124. package/dist/core/extensions/extension-policy.js +481 -0
  125. package/dist/core/extensions/extension-policy.js.map +1 -0
  126. package/dist/core/extensions/extension-registries.d.ts +8 -0
  127. package/dist/core/extensions/extension-registries.js +52 -0
  128. package/dist/core/extensions/extension-registries.js.map +1 -0
  129. package/dist/core/extensions/extension-runtime-helpers.d.ts +6 -0
  130. package/dist/core/extensions/extension-runtime-helpers.js +29 -0
  131. package/dist/core/extensions/extension-runtime-helpers.js.map +1 -0
  132. package/dist/core/extensions/extension-types.d.ts +13 -39
  133. package/dist/core/extensions/extension-types.js +34 -2
  134. package/dist/core/extensions/extension-types.js.map +1 -1
  135. package/dist/core/extensions/index.d.ts +7 -0
  136. package/dist/core/extensions/index.js +11 -2
  137. package/dist/core/extensions/index.js.map +1 -1
  138. package/dist/core/extensions/loader.d.ts +4 -22
  139. package/dist/core/extensions/loader.js +22 -1139
  140. package/dist/core/extensions/loader.js.map +1 -1
  141. package/dist/core/history/drift-scan.d.ts +11 -0
  142. package/dist/core/history/drift-scan.js +114 -32
  143. package/dist/core/history/drift-scan.js.map +1 -1
  144. package/dist/core/history/history-rewrite.d.ts +43 -0
  145. package/dist/core/history/history-rewrite.js +48 -0
  146. package/dist/core/history/history-rewrite.js.map +1 -0
  147. package/dist/core/history/history.js +5 -4
  148. package/dist/core/history/history.js.map +1 -1
  149. package/dist/core/history/replay.js +4 -3
  150. package/dist/core/history/replay.js.map +1 -1
  151. package/dist/core/item/item-record.d.ts +19 -0
  152. package/dist/core/item/item-record.js +24 -0
  153. package/dist/core/item/item-record.js.map +1 -0
  154. package/dist/core/output/mutation-projection.d.ts +31 -0
  155. package/dist/core/output/mutation-projection.js +103 -0
  156. package/dist/core/output/mutation-projection.js.map +1 -0
  157. package/dist/core/output/output.d.ts +2 -0
  158. package/dist/core/output/output.js +5 -3
  159. package/dist/core/output/output.js.map +1 -1
  160. package/dist/core/schema/runtime-schema.js +8 -38
  161. package/dist/core/schema/runtime-schema.js.map +1 -1
  162. package/dist/core/search/vector-stores.js +46 -9
  163. package/dist/core/search/vector-stores.js.map +1 -1
  164. package/dist/core/sentry/helpers.d.ts +1 -1
  165. package/dist/core/sentry/helpers.js +20 -3
  166. package/dist/core/sentry/helpers.js.map +1 -1
  167. package/dist/core/shared/command-types.d.ts +1 -0
  168. package/dist/core/shared/command-types.js +2 -2
  169. package/dist/core/shared/command-types.js.map +1 -1
  170. package/dist/core/shared/constants.d.ts +10 -1
  171. package/dist/core/shared/constants.js +56 -58
  172. package/dist/core/shared/constants.js.map +1 -1
  173. package/dist/core/shared/levenshtein.js +23 -7
  174. package/dist/core/shared/levenshtein.js.map +1 -1
  175. package/dist/core/shared/primitives.d.ts +23 -0
  176. package/dist/core/shared/primitives.js +39 -2
  177. package/dist/core/shared/primitives.js.map +1 -1
  178. package/dist/core/store/front-matter-cache.d.ts +16 -2
  179. package/dist/core/store/front-matter-cache.js +99 -33
  180. package/dist/core/store/front-matter-cache.js.map +1 -1
  181. package/dist/core/store/item-store.js +8 -73
  182. package/dist/core/store/item-store.js.map +1 -1
  183. package/dist/mcp/server.js +76 -28
  184. package/dist/mcp/server.js.map +1 -1
  185. package/dist/sdk/cli-contracts/enum-contracts.d.ts +20 -0
  186. package/dist/sdk/cli-contracts/enum-contracts.js +156 -0
  187. package/dist/sdk/cli-contracts/enum-contracts.js.map +1 -0
  188. package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +14 -0
  189. package/dist/sdk/cli-contracts/tool-option-contracts.js +243 -0
  190. package/dist/sdk/cli-contracts/tool-option-contracts.js.map +1 -0
  191. package/dist/sdk/cli-contracts/tool-parameter-tables.d.ts +11 -0
  192. package/dist/sdk/cli-contracts/tool-parameter-tables.js +901 -0
  193. package/dist/sdk/cli-contracts/tool-parameter-tables.js.map +1 -0
  194. package/dist/sdk/cli-contracts.d.ts +11 -33
  195. package/dist/sdk/cli-contracts.js +30 -1356
  196. package/dist/sdk/cli-contracts.js.map +1 -1
  197. package/dist/sdk/package-import-adapters.d.ts +74 -0
  198. package/dist/sdk/package-import-adapters.js +186 -0
  199. package/dist/sdk/package-import-adapters.js.map +1 -0
  200. package/dist/sdk/package-runtime-options.d.ts +26 -0
  201. package/dist/sdk/package-runtime-options.js +71 -0
  202. package/dist/sdk/package-runtime-options.js.map +1 -0
  203. package/dist/sdk/runtime.d.ts +2 -0
  204. package/dist/sdk/runtime.js +4 -2
  205. package/dist/sdk/runtime.js.map +1 -1
  206. package/docs/AGENT_GUIDE.md +6 -10
  207. package/docs/CLAUDE_CODE_PLUGIN.md +5 -28
  208. package/docs/CODEX_PLUGIN.md +5 -5
  209. package/docs/COMMANDS.md +19 -3
  210. package/docs/CONFIGURATION.md +15 -0
  211. package/docs/EXTENSIONS.md +4 -63
  212. package/docs/RELEASING.md +4 -4
  213. package/marketplace.json +7 -3
  214. package/package.json +9 -6
  215. package/packages/pm-beads/extensions/beads/index.js +2 -49
  216. package/packages/pm-beads/extensions/beads/index.ts +2 -54
  217. package/packages/pm-beads/extensions/beads/runtime-loader.js +86 -0
  218. package/packages/pm-beads/extensions/beads/runtime-loader.ts +88 -0
  219. package/packages/pm-beads/extensions/beads/runtime.js +26 -115
  220. package/packages/pm-beads/extensions/beads/runtime.ts +33 -132
  221. package/packages/pm-calendar/extensions/calendar/index.js +47 -2
  222. package/packages/pm-calendar/extensions/calendar/index.ts +52 -2
  223. package/packages/pm-calendar/extensions/calendar/runtime.js +1 -0
  224. package/packages/pm-calendar/extensions/calendar/runtime.ts +1 -0
  225. package/packages/pm-governance-audit/extensions/governance-audit/runtime.js +14 -41
  226. package/packages/pm-governance-audit/extensions/governance-audit/runtime.ts +25 -41
  227. package/packages/pm-guide-shell/extensions/guide-shell/runtime.js +10 -50
  228. package/packages/pm-guide-shell/extensions/guide-shell/runtime.ts +17 -50
  229. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/runtime.js +8 -40
  230. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/runtime.ts +10 -40
  231. package/packages/pm-search-advanced/extensions/search-advanced/index.js +1 -1
  232. package/packages/pm-search-advanced/extensions/search-advanced/runtime.js +4 -37
  233. package/packages/pm-search-advanced/extensions/search-advanced/runtime.ts +6 -37
  234. package/packages/pm-todos/extensions/todos/index.js +3 -50
  235. package/packages/pm-todos/extensions/todos/index.ts +3 -55
  236. package/packages/pm-todos/extensions/todos/runtime-loader.js +86 -0
  237. package/packages/pm-todos/extensions/todos/runtime-loader.ts +88 -0
  238. package/packages/pm-todos/extensions/todos/runtime.js +24 -117
  239. package/packages/pm-todos/extensions/todos/runtime.ts +32 -129
  240. package/plugins/pm-claude/README.md +2 -2
  241. package/plugins/pm-claude/commands/pm-planner.md +1 -15
  242. package/plugins/pm-claude/scripts/pm-mcp-server.mjs +5 -2
  243. package/plugins/pm-claude/skills/pm-planner/SKILL.md +3 -21
  244. package/plugins/pm-codex/scripts/pm-mcp-server.mjs +15 -6
  245. package/plugins/pm-codex/skills/pm-native/SKILL.md +1 -13
  246. package/PRD.md +0 -1734
@@ -0,0 +1,200 @@
1
+ // Pure, leaf-level helpers for detecting how linked-test shell commands invoke
2
+ // the pm CLI (directly, via npx/pnpm/npm exec, or a launcher subcommand) and for
3
+ // pulling structured context (subcommand, referenced item ids, runner) out of a
4
+ // normalized command string. Extracted from test.ts to keep that command file
5
+ // under the per-file LOC budget; consumers re-export these from test.ts so no
6
+ // caller outside test.ts changes.
7
+
8
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1e2744b0-89b5-5779-ae5b-f905a5780eb3")}catch(e){}}();
9
+ export const PM_GLOBAL_FLAGS_WITH_VALUE = new Set(["--path"]);
10
+ export const NPX_FLAGS_WITH_VALUE = new Set(["-p", "--package", "-c", "--call"]);
11
+ export const PNPM_GLOBAL_FLAGS_WITH_VALUE = new Set([
12
+ "-c",
13
+ "-C",
14
+ "--config",
15
+ "--dir",
16
+ "--filter",
17
+ "--workspace-dir",
18
+ ]);
19
+ export const NPM_GLOBAL_FLAGS_WITH_VALUE = new Set(["-C", "--prefix", "--userconfig", "--cache"]);
20
+ export const YARN_GLOBAL_FLAGS_WITH_VALUE = new Set(["--cwd"]);
21
+ export const BUN_GLOBAL_FLAGS_WITH_VALUE = new Set(["--cwd"]);
22
+ export const NPM_EXEC_SUBCOMMANDS = new Set(["exec", "x"]);
23
+ export const SCRIPT_RUN_SUBCOMMANDS = new Set(["run", "run-script"]);
24
+ export const SCRIPT_RUN_FLAGS_WITH_VALUE = new Set(["-C", "--dir", "--cwd", "-w", "--workspace", "--filter"]);
25
+ export function splitNormalizedCommandSegments(normalizedCommand) {
26
+ return normalizedCommand
27
+ .split(/&&|\|\||\||;/)
28
+ .map((segment) => segment.trim())
29
+ .filter((segment) => segment.length > 0);
30
+ }
31
+ export function stripLeadingEnvAssignments(tokens) {
32
+ let start = 0;
33
+ if (tokens[start] === "env") {
34
+ start += 1;
35
+ }
36
+ while (start < tokens.length) {
37
+ const token = tokens[start];
38
+ if (/^(?:[a-z_][a-z0-9_]*|\$env:[a-z_][a-z0-9_]*)=.*/.test(token)) {
39
+ start += 1;
40
+ continue;
41
+ }
42
+ break;
43
+ }
44
+ return tokens.slice(start);
45
+ }
46
+ export function firstPmSubcommand(args) {
47
+ let index = 0;
48
+ while (index < args.length) {
49
+ const token = args[index];
50
+ if (token === "--") {
51
+ index += 1;
52
+ continue;
53
+ }
54
+ if (token.startsWith("-")) {
55
+ if (PM_GLOBAL_FLAGS_WITH_VALUE.has(token)) {
56
+ index += 2;
57
+ continue;
58
+ }
59
+ index += 1;
60
+ continue;
61
+ }
62
+ return token;
63
+ }
64
+ return undefined;
65
+ }
66
+ export function isPmExecutableToken(token) {
67
+ return (token === "pm" ||
68
+ token === "pm.cmd" ||
69
+ token === "pm.exe" ||
70
+ token.endsWith("/pm") ||
71
+ token.endsWith("/pm.cmd") ||
72
+ token.endsWith("/pm.exe"));
73
+ }
74
+ export function normalizePackageSpecifier(token) {
75
+ const trimmed = token.trim();
76
+ if (!trimmed.startsWith("@")) {
77
+ const versionSeparator = trimmed.indexOf("@");
78
+ return versionSeparator === -1 ? trimmed : trimmed.slice(0, versionSeparator);
79
+ }
80
+ const scopeSeparator = trimmed.indexOf("/");
81
+ if (scopeSeparator === -1) {
82
+ return trimmed;
83
+ }
84
+ const versionSeparator = trimmed.indexOf("@", scopeSeparator + 1);
85
+ return versionSeparator === -1 ? trimmed : trimmed.slice(0, versionSeparator);
86
+ }
87
+ export function isPmCliPackageToken(token) {
88
+ const normalizedSpecifier = normalizePackageSpecifier(token);
89
+ return (normalizedSpecifier === "pm-cli" ||
90
+ normalizedSpecifier.endsWith("/pm-cli") ||
91
+ token === "pm-cli" ||
92
+ token.endsWith("/pm-cli"));
93
+ }
94
+ export function isPmCliScriptToken(token) {
95
+ return token === "dist/cli.js" || token === "./dist/cli.js" || token.endsWith("/dist/cli.js");
96
+ }
97
+ export function parseNpxCommand(tokens) {
98
+ let index = 0;
99
+ while (index < tokens.length) {
100
+ const token = tokens[index];
101
+ if (token === "--") {
102
+ index += 1;
103
+ break;
104
+ }
105
+ if (!token.startsWith("-")) {
106
+ break;
107
+ }
108
+ if (token.includes("=")) {
109
+ index += 1;
110
+ continue;
111
+ }
112
+ if (NPX_FLAGS_WITH_VALUE.has(token)) {
113
+ index += 2;
114
+ continue;
115
+ }
116
+ index += 1;
117
+ }
118
+ const command = tokens[index];
119
+ if (!command) {
120
+ return null;
121
+ }
122
+ return {
123
+ command,
124
+ args: tokens.slice(index + 1),
125
+ };
126
+ }
127
+ export function parseLauncherSubcommand(tokens, flagsWithValue) {
128
+ let index = 0;
129
+ while (index < tokens.length) {
130
+ const token = tokens[index];
131
+ if (token === "--") {
132
+ index += 1;
133
+ continue;
134
+ }
135
+ if (token.startsWith("-")) {
136
+ if (token.includes("=")) {
137
+ index += 1;
138
+ continue;
139
+ }
140
+ if (flagsWithValue.has(token)) {
141
+ index += 2;
142
+ continue;
143
+ }
144
+ index += 1;
145
+ continue;
146
+ }
147
+ return {
148
+ subcommand: token,
149
+ args: tokens.slice(index + 1),
150
+ };
151
+ }
152
+ return null;
153
+ }
154
+ export function parsePnpmDlxCommand(tokens) {
155
+ const parsed = parseLauncherSubcommand(tokens, PNPM_GLOBAL_FLAGS_WITH_VALUE);
156
+ if (parsed?.subcommand !== "dlx") {
157
+ return null;
158
+ }
159
+ return parseNpxCommand(parsed.args);
160
+ }
161
+ export function parseNpmExecCommand(tokens) {
162
+ const parsed = parseLauncherSubcommand(tokens, NPM_GLOBAL_FLAGS_WITH_VALUE);
163
+ if (!parsed || !NPM_EXEC_SUBCOMMANDS.has(parsed.subcommand)) {
164
+ return null;
165
+ }
166
+ return parseNpxCommand(parsed.args);
167
+ }
168
+ export function resolvePmSubcommandContext(args) {
169
+ let index = 0;
170
+ while (index < args.length) {
171
+ const token = args[index];
172
+ if (token === "--") {
173
+ index += 1;
174
+ continue;
175
+ }
176
+ if (token.startsWith("-")) {
177
+ if (PM_GLOBAL_FLAGS_WITH_VALUE.has(token)) {
178
+ index += 2;
179
+ continue;
180
+ }
181
+ index += 1;
182
+ continue;
183
+ }
184
+ return {
185
+ subcommand: token,
186
+ remaining: args.slice(index + 1),
187
+ };
188
+ }
189
+ return null;
190
+ }
191
+ export function firstPositionalToken(tokens) {
192
+ for (const token of tokens) {
193
+ if (!token.startsWith("-")) {
194
+ return token;
195
+ }
196
+ }
197
+ return undefined;
198
+ }
199
+ //# sourceMappingURL=linked-command-detection.js.map
200
+ //# debugId=1e2744b0-89b5-5779-ae5b-f905a5780eb3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linked-command-detection.js","sources":["cli/commands/test/linked-command-detection.ts"],"sourceRoot":"/","sourcesContent":["// Pure, leaf-level helpers for detecting how linked-test shell commands invoke\n// the pm CLI (directly, via npx/pnpm/npm exec, or a launcher subcommand) and for\n// pulling structured context (subcommand, referenced item ids, runner) out of a\n// normalized command string. Extracted from test.ts to keep that command file\n// under the per-file LOC budget; consumers re-export these from test.ts so no\n// caller outside test.ts changes.\n\nexport const PM_GLOBAL_FLAGS_WITH_VALUE = new Set([\"--path\"]);\nexport const NPX_FLAGS_WITH_VALUE = new Set([\"-p\", \"--package\", \"-c\", \"--call\"]);\nexport const PNPM_GLOBAL_FLAGS_WITH_VALUE = new Set([\n \"-c\",\n \"-C\",\n \"--config\",\n \"--dir\",\n \"--filter\",\n \"--workspace-dir\",\n]);\nexport const NPM_GLOBAL_FLAGS_WITH_VALUE = new Set([\"-C\", \"--prefix\", \"--userconfig\", \"--cache\"]);\nexport const YARN_GLOBAL_FLAGS_WITH_VALUE = new Set([\"--cwd\"]);\nexport const BUN_GLOBAL_FLAGS_WITH_VALUE = new Set([\"--cwd\"]);\nexport const NPM_EXEC_SUBCOMMANDS = new Set([\"exec\", \"x\"]);\nexport const SCRIPT_RUN_SUBCOMMANDS = new Set([\"run\", \"run-script\"]);\nexport const SCRIPT_RUN_FLAGS_WITH_VALUE = new Set([\"-C\", \"--dir\", \"--cwd\", \"-w\", \"--workspace\", \"--filter\"]);\n\nexport function splitNormalizedCommandSegments(normalizedCommand: string): string[] {\n return normalizedCommand\n .split(/&&|\\|\\||\\||;/)\n .map((segment) => segment.trim())\n .filter((segment) => segment.length > 0);\n}\n\nexport function stripLeadingEnvAssignments(tokens: string[]): string[] {\n let start = 0;\n if (tokens[start] === \"env\") {\n start += 1;\n }\n while (start < tokens.length) {\n const token = tokens[start];\n if (/^(?:[a-z_][a-z0-9_]*|\\$env:[a-z_][a-z0-9_]*)=.*/.test(token)) {\n start += 1;\n continue;\n }\n break;\n }\n return tokens.slice(start);\n}\n\nexport function firstPmSubcommand(args: string[]): string | undefined {\n let index = 0;\n while (index < args.length) {\n const token = args[index];\n if (token === \"--\") {\n index += 1;\n continue;\n }\n if (token.startsWith(\"-\")) {\n if (PM_GLOBAL_FLAGS_WITH_VALUE.has(token)) {\n index += 2;\n continue;\n }\n index += 1;\n continue;\n }\n return token;\n }\n return undefined;\n}\n\nexport function isPmExecutableToken(token: string): boolean {\n return (\n token === \"pm\" ||\n token === \"pm.cmd\" ||\n token === \"pm.exe\" ||\n token.endsWith(\"/pm\") ||\n token.endsWith(\"/pm.cmd\") ||\n token.endsWith(\"/pm.exe\")\n );\n}\n\nexport function normalizePackageSpecifier(token: string): string {\n const trimmed = token.trim();\n if (!trimmed.startsWith(\"@\")) {\n const versionSeparator = trimmed.indexOf(\"@\");\n return versionSeparator === -1 ? trimmed : trimmed.slice(0, versionSeparator);\n }\n const scopeSeparator = trimmed.indexOf(\"/\");\n if (scopeSeparator === -1) {\n return trimmed;\n }\n const versionSeparator = trimmed.indexOf(\"@\", scopeSeparator + 1);\n return versionSeparator === -1 ? trimmed : trimmed.slice(0, versionSeparator);\n}\n\nexport function isPmCliPackageToken(token: string): boolean {\n const normalizedSpecifier = normalizePackageSpecifier(token);\n return (\n normalizedSpecifier === \"pm-cli\" ||\n normalizedSpecifier.endsWith(\"/pm-cli\") ||\n token === \"pm-cli\" ||\n token.endsWith(\"/pm-cli\")\n );\n}\n\nexport function isPmCliScriptToken(token: string): boolean {\n return token === \"dist/cli.js\" || token === \"./dist/cli.js\" || token.endsWith(\"/dist/cli.js\");\n}\n\nexport function parseNpxCommand(tokens: string[]): { command: string; args: string[] } | null {\n let index = 0;\n while (index < tokens.length) {\n const token = tokens[index];\n if (token === \"--\") {\n index += 1;\n break;\n }\n if (!token.startsWith(\"-\")) {\n break;\n }\n if (token.includes(\"=\")) {\n index += 1;\n continue;\n }\n if (NPX_FLAGS_WITH_VALUE.has(token)) {\n index += 2;\n continue;\n }\n index += 1;\n }\n const command = tokens[index];\n if (!command) {\n return null;\n }\n return {\n command,\n args: tokens.slice(index + 1),\n };\n}\n\nexport function parseLauncherSubcommand(\n tokens: string[],\n flagsWithValue: Set<string>,\n): { subcommand: string; args: string[] } | null {\n let index = 0;\n while (index < tokens.length) {\n const token = tokens[index];\n if (token === \"--\") {\n index += 1;\n continue;\n }\n if (token.startsWith(\"-\")) {\n if (token.includes(\"=\")) {\n index += 1;\n continue;\n }\n if (flagsWithValue.has(token)) {\n index += 2;\n continue;\n }\n index += 1;\n continue;\n }\n return {\n subcommand: token,\n args: tokens.slice(index + 1),\n };\n }\n return null;\n}\n\nexport function parsePnpmDlxCommand(tokens: string[]): { command: string; args: string[] } | null {\n const parsed = parseLauncherSubcommand(tokens, PNPM_GLOBAL_FLAGS_WITH_VALUE);\n if (parsed?.subcommand !== \"dlx\") {\n return null;\n }\n return parseNpxCommand(parsed.args);\n}\n\nexport function parseNpmExecCommand(tokens: string[]): { command: string; args: string[] } | null {\n const parsed = parseLauncherSubcommand(tokens, NPM_GLOBAL_FLAGS_WITH_VALUE);\n if (!parsed || !NPM_EXEC_SUBCOMMANDS.has(parsed.subcommand)) {\n return null;\n }\n return parseNpxCommand(parsed.args);\n}\n\nexport function resolvePmSubcommandContext(args: string[]): { subcommand: string; remaining: string[] } | null {\n let index = 0;\n while (index < args.length) {\n const token = args[index];\n if (token === \"--\") {\n index += 1;\n continue;\n }\n if (token.startsWith(\"-\")) {\n if (PM_GLOBAL_FLAGS_WITH_VALUE.has(token)) {\n index += 2;\n continue;\n }\n index += 1;\n continue;\n }\n return {\n subcommand: token,\n remaining: args.slice(index + 1),\n };\n }\n return null;\n}\n\nexport function firstPositionalToken(tokens: string[]): string | undefined {\n for (const token of tokens) {\n if (!token.startsWith(\"-\")) {\n return token;\n }\n }\n return undefined;\n}\n"],"names":[],"mappings":"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","debugId":"1e2744b0-89b5-5779-ae5b-f905a5780eb3"}
@@ -1,7 +1,6 @@
1
1
  import type { GlobalOptions } from "../../core/shared/command-types.js";
2
+ import { type LinkedTestPmContextMode } from "./linked-test-parsers.js";
2
3
  import type { LinkedTest } from "../../types/index.js";
3
- declare const PM_CONTEXT_MODE_VALUES: readonly ["schema", "tracker", "auto"];
4
- type LinkedTestPmContextMode = (typeof PM_CONTEXT_MODE_VALUES)[number];
5
4
  interface LinkedTestExecutionResult {
6
5
  stdout: string;
7
6
  stderr: string;
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e91148e1-f113-54d8-a61c-7c8b6ac06935")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f4d1b3b4-fb85-5127-a4b7-7877a66286e8")}catch(e){}}();
3
3
  import { spawn } from "node:child_process";
4
4
  import { cp, mkdir, mkdtemp, readdir, rm } from "node:fs/promises";
5
5
  import { tmpdir } from "node:os";
@@ -17,14 +17,12 @@ import { readSettings } from "../../core/store/settings.js";
17
17
  import { appendTrackedTestRunSummary } from "../../core/test/item-test-run-tracking.js";
18
18
  import { runInit } from "./init.js";
19
19
  import { looksLikeStructuredLinkedTestEntry, normalizeStructuredLinkedTestEntry } from "./linked-test-entry.js";
20
+ import { LINKED_TEST_PM_CONTEXT_MODE_VALUES as PM_CONTEXT_MODE_VALUES, LINKED_TEST_PROTECTED_ENV_KEYS, parseLinkedTestAssertionEqualsMap, parseLinkedTestAssertionGteMap, parseLinkedTestBoolean as parseLinkedTestBooleanValue, parseLinkedTestContextMode as parseLinkedTestContextModeValue, parseLinkedTestEnvClear as parseLinkedTestEnvClearValue, parseLinkedTestEnvSet as parseLinkedTestEnvSetValue, parseLinkedTestMinLines, parseLinkedTestRegexList, parseLinkedTestStringList, } from "./linked-test-parsers.js";
20
21
  import { SCOPE_VALUES } from "../../types/index.js";
21
22
  const TEST_OUTPUT_MAX_BUFFER_BYTES = 20 * 1024 * 1024;
22
23
  const DEFAULT_LINKED_TEST_TIMEOUT_FORCE_KILL_DELAY_MS = 3000;
23
24
  const DEFAULT_LINKED_TEST_HEARTBEAT_INTERVAL_MS = 10000;
24
25
  const MAX_LINKED_TEST_COMMAND_LABEL_LENGTH = 120;
25
- const LINKED_TEST_PROTECTED_ENV_KEYS = new Set(["PM_PATH", "PM_GLOBAL_PATH", "FORCE_COLOR"]);
26
- const LINKED_TEST_ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
27
- const PM_CONTEXT_MODE_VALUES = ["schema", "tracker", "auto"];
28
26
  const LINKED_TEST_TRACKER_DIRS_TO_SKIP = new Set(["locks", "extensions", "runtime"]);
29
27
  const LINKED_TEST_ITEM_COUNT_DIRS_TO_SKIP = new Set(["history", "index", "search", "extensions", "locks", "runtime"]);
30
28
  const LINKED_TEST_INFRA_COLLISION_PATTERNS = [
@@ -155,165 +153,6 @@ function ensureScope(raw) {
155
153
  }
156
154
  return value;
157
155
  }
158
- function parseLinkedTestBooleanValue(raw, optionName, fieldLabel) {
159
- if (!raw || raw.trim().length === 0) {
160
- return undefined;
161
- }
162
- const normalized = raw.trim().toLowerCase();
163
- if (normalized === "true" || normalized === "1" || normalized === "yes") {
164
- return true;
165
- }
166
- if (normalized === "false" || normalized === "0" || normalized === "no") {
167
- return false;
168
- }
169
- throw new PmCliError(`${optionName} ${fieldLabel} must be one of true|false|1|0|yes|no`, EXIT_CODE.USAGE);
170
- }
171
- function parseLinkedTestEnvSetValue(raw, optionName) {
172
- if (!raw || raw.trim().length === 0) {
173
- return undefined;
174
- }
175
- const assignments = raw
176
- .split(/[;\n]/)
177
- .map((entry) => entry.trim())
178
- .filter((entry) => entry.length > 0);
179
- if (assignments.length === 0) {
180
- throw new PmCliError(`${optionName} env_set must include at least one KEY=VALUE assignment`, EXIT_CODE.USAGE);
181
- }
182
- const envSet = {};
183
- for (const assignment of assignments) {
184
- const separatorIndex = assignment.indexOf("=");
185
- if (separatorIndex <= 0) {
186
- throw new PmCliError(`${optionName} env_set entries must use KEY=VALUE and be separated by semicolons. Example: env_set=PORT=0;PLAYWRIGHT_BASE_URL=http://127.0.0.1:4173`, EXIT_CODE.USAGE);
187
- }
188
- const key = assignment.slice(0, separatorIndex).trim();
189
- const value = assignment.slice(separatorIndex + 1);
190
- if (!LINKED_TEST_ENV_NAME_PATTERN.test(key)) {
191
- throw new PmCliError(`${optionName} env_set key "${key}" is invalid`, EXIT_CODE.USAGE);
192
- }
193
- if (LINKED_TEST_PROTECTED_ENV_KEYS.has(key.toUpperCase())) {
194
- throw new PmCliError(`${optionName} env_set key "${key}" is reserved for sandbox safety`, EXIT_CODE.USAGE);
195
- }
196
- envSet[key] = value;
197
- }
198
- return Object.keys(envSet).length > 0 ? envSet : undefined;
199
- }
200
- function parseLinkedTestEnvClearValue(raw, optionName) {
201
- if (!raw || raw.trim().length === 0) {
202
- return undefined;
203
- }
204
- const values = [...new Set(raw.split(/[;,\n]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0))];
205
- if (values.length === 0) {
206
- throw new PmCliError(`${optionName} env_clear must include at least one environment variable name`, EXIT_CODE.USAGE);
207
- }
208
- for (const key of values) {
209
- if (!LINKED_TEST_ENV_NAME_PATTERN.test(key)) {
210
- throw new PmCliError(`${optionName} env_clear key "${key}" is invalid`, EXIT_CODE.USAGE);
211
- }
212
- if (LINKED_TEST_PROTECTED_ENV_KEYS.has(key.toUpperCase())) {
213
- throw new PmCliError(`${optionName} env_clear key "${key}" is reserved for sandbox safety`, EXIT_CODE.USAGE);
214
- }
215
- }
216
- return values;
217
- }
218
- function parseLinkedTestStringList(raw) {
219
- if (!raw || raw.trim().length === 0) {
220
- return undefined;
221
- }
222
- const values = [...new Set(raw.split(/[;\n]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0))];
223
- return values.length > 0 ? values : undefined;
224
- }
225
- function parseLinkedTestRegexList(raw, optionName, fieldLabel) {
226
- const values = parseLinkedTestStringList(raw);
227
- if (!values || values.length === 0) {
228
- return undefined;
229
- }
230
- for (const pattern of values) {
231
- try {
232
- // Validate syntax when linked-test metadata is added.
233
- new RegExp(pattern, "m");
234
- }
235
- catch (error) {
236
- throw new PmCliError(`${optionName} ${fieldLabel} includes invalid regex "${pattern}": ${error instanceof Error ? error.message : String(error)}`, EXIT_CODE.USAGE);
237
- }
238
- }
239
- return values;
240
- }
241
- function parseLinkedTestMinLines(raw, optionName) {
242
- if (!raw || raw.trim().length === 0) {
243
- return undefined;
244
- }
245
- const parsed = parseOptionalNumber(raw, "assert_stdout_min_lines");
246
- if (!Number.isInteger(parsed) || parsed < 0) {
247
- throw new PmCliError(`${optionName} assert_stdout_min_lines must be an integer >= 0`, EXIT_CODE.USAGE);
248
- }
249
- return parsed;
250
- }
251
- function parseLinkedTestAssertionEqualsMap(raw, optionName) {
252
- if (!raw || raw.trim().length === 0) {
253
- return undefined;
254
- }
255
- const assignments = raw
256
- .split(/[;\n]/)
257
- .map((entry) => entry.trim())
258
- .filter((entry) => entry.length > 0);
259
- if (assignments.length === 0) {
260
- throw new PmCliError(`${optionName} assert_json_field_equals must include at least one path=value assignment`, EXIT_CODE.USAGE);
261
- }
262
- const values = {};
263
- for (const assignment of assignments) {
264
- const separatorIndex = assignment.indexOf("=");
265
- if (separatorIndex <= 0) {
266
- throw new PmCliError(`${optionName} assert_json_field_equals entries must use path=value and be separated by semicolons`, EXIT_CODE.USAGE);
267
- }
268
- const key = assignment.slice(0, separatorIndex).trim();
269
- const value = assignment.slice(separatorIndex + 1).trim();
270
- if (key.length === 0 || value.length === 0) {
271
- throw new PmCliError(`${optionName} assert_json_field_equals entries must include non-empty path and value`, EXIT_CODE.USAGE);
272
- }
273
- values[key] = value;
274
- }
275
- return Object.keys(values).length > 0 ? values : undefined;
276
- }
277
- function parseLinkedTestAssertionGteMap(raw, optionName) {
278
- if (!raw || raw.trim().length === 0) {
279
- return undefined;
280
- }
281
- const assignments = raw
282
- .split(/[;\n]/)
283
- .map((entry) => entry.trim())
284
- .filter((entry) => entry.length > 0);
285
- if (assignments.length === 0) {
286
- throw new PmCliError(`${optionName} assert_json_field_gte must include at least one path=value assignment`, EXIT_CODE.USAGE);
287
- }
288
- const values = {};
289
- for (const assignment of assignments) {
290
- const separatorIndex = assignment.indexOf("=");
291
- if (separatorIndex <= 0) {
292
- throw new PmCliError(`${optionName} assert_json_field_gte entries must use path=value and be separated by semicolons`, EXIT_CODE.USAGE);
293
- }
294
- const key = assignment.slice(0, separatorIndex).trim();
295
- const valueRaw = assignment.slice(separatorIndex + 1).trim();
296
- if (key.length === 0 || valueRaw.length === 0) {
297
- throw new PmCliError(`${optionName} assert_json_field_gte entries must include non-empty path and value`, EXIT_CODE.USAGE);
298
- }
299
- const value = Number.parseFloat(valueRaw);
300
- if (!Number.isFinite(value)) {
301
- throw new PmCliError(`${optionName} assert_json_field_gte value for "${key}" must be numeric`, EXIT_CODE.USAGE);
302
- }
303
- values[key] = value;
304
- }
305
- return Object.keys(values).length > 0 ? values : undefined;
306
- }
307
- function parseLinkedTestContextModeValue(raw, optionName) {
308
- if (!raw || raw.trim().length === 0) {
309
- return undefined;
310
- }
311
- const normalized = raw.trim().toLowerCase();
312
- if (PM_CONTEXT_MODE_VALUES.includes(normalized)) {
313
- return normalized;
314
- }
315
- throw new PmCliError(`${optionName} pm_context_mode must be one of: ${PM_CONTEXT_MODE_VALUES.join(", ")}`, EXIT_CODE.USAGE);
316
- }
317
156
  function parsePmContextMode(raw) {
318
157
  if (!raw) {
319
158
  return "schema";
@@ -391,191 +230,10 @@ function mergeEnvClearDirectives(entries, optionName) {
391
230
  }
392
231
  return [...new Set(values)];
393
232
  }
394
- const PM_GLOBAL_FLAGS_WITH_VALUE = new Set(["--path"]);
395
- const NPX_FLAGS_WITH_VALUE = new Set(["-p", "--package", "-c", "--call"]);
396
- const PNPM_GLOBAL_FLAGS_WITH_VALUE = new Set([
397
- "-c",
398
- "-C",
399
- "--config",
400
- "--dir",
401
- "--filter",
402
- "--workspace-dir",
403
- ]);
404
- const NPM_GLOBAL_FLAGS_WITH_VALUE = new Set(["-C", "--prefix", "--userconfig", "--cache"]);
405
- const YARN_GLOBAL_FLAGS_WITH_VALUE = new Set(["--cwd"]);
406
- const BUN_GLOBAL_FLAGS_WITH_VALUE = new Set(["--cwd"]);
407
- const NPM_EXEC_SUBCOMMANDS = new Set(["exec", "x"]);
408
- const SCRIPT_RUN_SUBCOMMANDS = new Set(["run", "run-script"]);
409
- const SCRIPT_RUN_FLAGS_WITH_VALUE = new Set(["-C", "--dir", "--cwd", "-w", "--workspace", "--filter"]);
410
- function splitNormalizedCommandSegments(normalizedCommand) {
411
- return normalizedCommand
412
- .split(/&&|\|\||\||;/)
413
- .map((segment) => segment.trim())
414
- .filter((segment) => segment.length > 0);
415
- }
416
- function stripLeadingEnvAssignments(tokens) {
417
- let start = 0;
418
- if (tokens[start] === "env") {
419
- start += 1;
420
- }
421
- while (start < tokens.length) {
422
- const token = tokens[start];
423
- if (/^(?:[a-z_][a-z0-9_]*|\$env:[a-z_][a-z0-9_]*)=.*/.test(token)) {
424
- start += 1;
425
- continue;
426
- }
427
- break;
428
- }
429
- return tokens.slice(start);
430
- }
431
- function firstPmSubcommand(args) {
432
- let index = 0;
433
- while (index < args.length) {
434
- const token = args[index];
435
- if (token === "--") {
436
- index += 1;
437
- continue;
438
- }
439
- if (token.startsWith("-")) {
440
- if (PM_GLOBAL_FLAGS_WITH_VALUE.has(token)) {
441
- index += 2;
442
- continue;
443
- }
444
- index += 1;
445
- continue;
446
- }
447
- return token;
448
- }
449
- return undefined;
450
- }
451
- function isPmExecutableToken(token) {
452
- return token === "pm" || token.endsWith("/pm") || token.endsWith("/pm.cmd") || token.endsWith("/pm.exe");
453
- }
454
- function normalizePackageSpecifier(token) {
455
- const trimmed = token.trim();
456
- if (!trimmed.startsWith("@")) {
457
- const versionSeparator = trimmed.indexOf("@");
458
- return versionSeparator === -1 ? trimmed : trimmed.slice(0, versionSeparator);
459
- }
460
- const scopeSeparator = trimmed.indexOf("/");
461
- if (scopeSeparator === -1) {
462
- return trimmed;
463
- }
464
- const versionSeparator = trimmed.indexOf("@", scopeSeparator + 1);
465
- return versionSeparator === -1 ? trimmed : trimmed.slice(0, versionSeparator);
466
- }
467
- function isPmCliPackageToken(token) {
468
- const normalizedSpecifier = normalizePackageSpecifier(token);
469
- return (normalizedSpecifier === "pm-cli" ||
470
- normalizedSpecifier.endsWith("/pm-cli") ||
471
- token === "pm-cli" ||
472
- token.endsWith("/pm-cli"));
473
- }
474
- function isPmCliScriptToken(token) {
475
- return token === "dist/cli.js" || token === "./dist/cli.js" || token.endsWith("/dist/cli.js");
476
- }
477
- function parseNpxCommand(tokens) {
478
- let index = 0;
479
- while (index < tokens.length) {
480
- const token = tokens[index];
481
- if (token === "--") {
482
- index += 1;
483
- break;
484
- }
485
- if (!token.startsWith("-")) {
486
- break;
487
- }
488
- if (token.includes("=")) {
489
- index += 1;
490
- continue;
491
- }
492
- if (NPX_FLAGS_WITH_VALUE.has(token)) {
493
- index += 2;
494
- continue;
495
- }
496
- index += 1;
497
- }
498
- const command = tokens[index];
499
- if (!command) {
500
- return null;
501
- }
502
- return {
503
- command,
504
- args: tokens.slice(index + 1),
505
- };
506
- }
507
- function parseLauncherSubcommand(tokens, flagsWithValue) {
508
- let index = 0;
509
- while (index < tokens.length) {
510
- const token = tokens[index];
511
- if (token === "--") {
512
- index += 1;
513
- continue;
514
- }
515
- if (token.startsWith("-")) {
516
- if (token.includes("=")) {
517
- index += 1;
518
- continue;
519
- }
520
- if (flagsWithValue.has(token)) {
521
- index += 2;
522
- continue;
523
- }
524
- index += 1;
525
- continue;
526
- }
527
- return {
528
- subcommand: token,
529
- args: tokens.slice(index + 1),
530
- };
531
- }
532
- return null;
533
- }
534
- function parsePnpmDlxCommand(tokens) {
535
- const parsed = parseLauncherSubcommand(tokens, PNPM_GLOBAL_FLAGS_WITH_VALUE);
536
- if (parsed?.subcommand !== "dlx") {
537
- return null;
538
- }
539
- return parseNpxCommand(parsed.args);
540
- }
541
- function parseNpmExecCommand(tokens) {
542
- const parsed = parseLauncherSubcommand(tokens, NPM_GLOBAL_FLAGS_WITH_VALUE);
543
- if (!parsed || !NPM_EXEC_SUBCOMMANDS.has(parsed.subcommand)) {
544
- return null;
545
- }
546
- return parseNpxCommand(parsed.args);
547
- }
548
- function resolvePmSubcommandContext(args) {
549
- let index = 0;
550
- while (index < args.length) {
551
- const token = args[index];
552
- if (token === "--") {
553
- index += 1;
554
- continue;
555
- }
556
- if (token.startsWith("-")) {
557
- if (PM_GLOBAL_FLAGS_WITH_VALUE.has(token)) {
558
- index += 2;
559
- continue;
560
- }
561
- index += 1;
562
- continue;
563
- }
564
- return {
565
- subcommand: token,
566
- remaining: args.slice(index + 1),
567
- };
568
- }
569
- return null;
570
- }
571
- function firstPositionalToken(tokens) {
572
- for (const token of tokens) {
573
- if (!token.startsWith("-")) {
574
- return token;
575
- }
576
- }
577
- return undefined;
578
- }
233
+ // Linked-test command detection helpers + constants live in a sibling leaf
234
+ // module to keep this command file under the per-file LOC budget. Re-exported
235
+ // here so no consumer outside this file changes.
236
+ import { BUN_GLOBAL_FLAGS_WITH_VALUE, NPM_GLOBAL_FLAGS_WITH_VALUE, PNPM_GLOBAL_FLAGS_WITH_VALUE, SCRIPT_RUN_FLAGS_WITH_VALUE, SCRIPT_RUN_SUBCOMMANDS, YARN_GLOBAL_FLAGS_WITH_VALUE, firstPmSubcommand, firstPositionalToken, isPmCliPackageToken, isPmCliScriptToken, isPmExecutableToken, parseLauncherSubcommand, parseNpmExecCommand, parseNpxCommand, parsePnpmDlxCommand, resolvePmSubcommandContext, splitNormalizedCommandSegments, stripLeadingEnvAssignments, } from "./test/linked-command-detection.js";
579
237
  function looksLikePrefixedItemId(token, idPrefix) {
580
238
  const normalizedPrefix = idPrefix.trim().toLowerCase().replace(/-+$/, "");
581
239
  if (normalizedPrefix.length === 0) {
@@ -783,7 +441,7 @@ function assertSandboxSafeTestRunnerCommand(command) {
783
441
  if (!hasUnsafeDirectRunnerSegment) {
784
442
  return;
785
443
  }
786
- throw new PmCliError('Linked test runner commands must be sandbox-safe: use "node scripts/run-tests.mjs <test|coverage>" or explicitly set both PM_PATH and PM_GLOBAL_PATH.', EXIT_CODE.USAGE);
444
+ throw new PmCliError('Linked test runner commands must be sandbox-safe: use "node scripts/run-tests.mjs <test|coverage>" or include PM_PATH=... PM_GLOBAL_PATH=... INLINE in the command string (exporting them in your shell environment is not checked). Example: "PM_PATH=/tmp/pm-x PM_GLOBAL_PATH=/tmp/pm-x-g vitest run".', EXIT_CODE.USAGE);
787
445
  }
788
446
  function getRuntimeSafetySkipReason(command) {
789
447
  if (!invokesRecursiveTestAllCommand(command))
@@ -1824,4 +1482,4 @@ export async function runTest(id, options, global) {
1824
1482
  };
1825
1483
  }
1826
1484
  //# sourceMappingURL=test.js.map
1827
- //# debugId=e91148e1-f113-54d8-a61c-7c8b6ac06935
1485
+ //# debugId=f4d1b3b4-fb85-5127-a4b7-7877a66286e8