@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,335 @@
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]="352e67e3-0c41-5c04-8d2d-3395c6216303")}catch(e){}}();
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import fg from "fast-glob";
6
+ import { pathExists } from "../../core/fs/fs-utils.js";
7
+ import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
8
+ import { createStdinTokenResolver, parseCsvKv } from "../../core/item/parse.js";
9
+ import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
10
+ import { EXIT_CODE } from "../../core/shared/constants.js";
11
+ import { PmCliError } from "../../core/shared/errors.js";
12
+ import { listAllFrontMatter, locateItem, mutateItem, readLocatedItem } from "../../core/store/item-store.js";
13
+ import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
14
+ import { readSettings } from "../../core/store/settings.js";
15
+ import { SCOPE_VALUES } from "../../types/index.js";
16
+ import { resolveAuthor } from "../../core/shared/author.js";
17
+ export function ensureScope(raw) {
18
+ const value = (raw ?? "project");
19
+ if (!SCOPE_VALUES.includes(value)) {
20
+ throw new PmCliError(`Invalid scope "${raw}". Valid scopes: ${SCOPE_VALUES.join(", ")} (default: project).`, EXIT_CODE.USAGE);
21
+ }
22
+ return value;
23
+ }
24
+ export function looksLikeStructuredPathEntry(raw) {
25
+ if (raw.startsWith("```") || raw.includes("\n")) {
26
+ return true;
27
+ }
28
+ return /^(?:[-*+]\s+)?(?:path|scope|note)\s*[:=]/i.test(raw);
29
+ }
30
+ export function parseAddEntries(raw, bareNoun) {
31
+ if (!raw)
32
+ return [];
33
+ return raw.map((entry) => {
34
+ const trimmed = entry.trim();
35
+ const kv = looksLikeStructuredPathEntry(trimmed) ? parseCsvKv(entry, "--add") : { path: trimmed };
36
+ if (!kv.path) {
37
+ throw new PmCliError(`--add requires path=<value> or a bare ${bareNoun} path`, EXIT_CODE.USAGE);
38
+ }
39
+ return {
40
+ path: kv.path,
41
+ scope: ensureScope(kv.scope),
42
+ note: kv.note?.trim() || undefined,
43
+ };
44
+ });
45
+ }
46
+ export function parseAddGlobEntries(raw) {
47
+ if (!raw)
48
+ return [];
49
+ return raw.map((entry) => {
50
+ const trimmed = entry.trim();
51
+ if (!trimmed) {
52
+ throw new PmCliError("--add-glob requires a glob pattern value", EXIT_CODE.USAGE);
53
+ }
54
+ if (trimmed.includes("=") || /^(?:[-*+]\s+)?(?:pattern|glob|path)\s*[:=]/i.test(trimmed) || trimmed.startsWith("```")) {
55
+ const kv = parseCsvKv(trimmed, "--add-glob");
56
+ const pattern = kv.pattern?.trim() || kv.glob?.trim() || kv.path?.trim();
57
+ if (!pattern) {
58
+ throw new PmCliError("--add-glob key/value form requires pattern=<glob>", EXIT_CODE.USAGE);
59
+ }
60
+ return {
61
+ pattern,
62
+ scope: ensureScope(kv.scope),
63
+ note: kv.note?.trim() || undefined,
64
+ };
65
+ }
66
+ return {
67
+ pattern: trimmed,
68
+ scope: "project",
69
+ };
70
+ });
71
+ }
72
+ export function parseRemoveEntries(raw) {
73
+ if (!raw)
74
+ return [];
75
+ return raw.map((entry) => {
76
+ const trimmed = entry.trim();
77
+ if (!trimmed) {
78
+ throw new PmCliError("--remove requires a path value", EXIT_CODE.USAGE);
79
+ }
80
+ if (trimmed.includes("=") || /^(?:[-*+]\s+)?path\s*[:=]/i.test(trimmed) || trimmed.startsWith("```")) {
81
+ const kv = parseCsvKv(trimmed, "--remove");
82
+ if (!kv.path) {
83
+ throw new PmCliError("--remove key/value form requires path=<value>", EXIT_CODE.USAGE);
84
+ }
85
+ return kv.path;
86
+ }
87
+ return trimmed;
88
+ });
89
+ }
90
+ export function parseMigrateEntries(raw) {
91
+ if (!raw)
92
+ return [];
93
+ return raw.map((entry) => {
94
+ const kv = parseCsvKv(entry, "--migrate");
95
+ const from = kv.from?.trim();
96
+ const to = kv.to?.trim();
97
+ if (!from || !to) {
98
+ throw new PmCliError("--migrate requires from=<value> and to=<value>", EXIT_CODE.USAGE);
99
+ }
100
+ return { from, to };
101
+ });
102
+ }
103
+ export function applyPathMigrations(artifactPath, migrations) {
104
+ let next = artifactPath;
105
+ for (const migration of migrations) {
106
+ if (next.startsWith(migration.from)) {
107
+ next = `${migration.to}${next.slice(migration.from.length)}`;
108
+ }
109
+ }
110
+ return next;
111
+ }
112
+ export function normalizeLinkedPath(value) {
113
+ return value.split(path.sep).join("/");
114
+ }
115
+ export async function expandAddGlobEntries(entries) {
116
+ const expanded = [];
117
+ for (const entry of entries) {
118
+ const absolutePattern = path.isAbsolute(entry.pattern);
119
+ const matches = await fg(entry.pattern, {
120
+ cwd: process.cwd(),
121
+ absolute: absolutePattern,
122
+ onlyFiles: true,
123
+ dot: true,
124
+ unique: true,
125
+ followSymbolicLinks: true,
126
+ });
127
+ const sortedMatches = [...new Set(matches.map((match) => normalizeLinkedPath(path.normalize(match))))].sort((left, right) => left.localeCompare(right));
128
+ for (const matchedPath of sortedMatches) {
129
+ expanded.push({
130
+ path: matchedPath,
131
+ scope: entry.scope,
132
+ note: entry.note,
133
+ });
134
+ }
135
+ }
136
+ return expanded;
137
+ }
138
+ export function artifactKey(value) {
139
+ return `${value.path}::${value.scope}`;
140
+ }
141
+ export function sortLinkedArtifacts(artifacts) {
142
+ return [...artifacts].sort((left, right) => {
143
+ const byPath = left.path.localeCompare(right.path);
144
+ if (byPath !== 0)
145
+ return byPath;
146
+ return left.scope.localeCompare(right.scope);
147
+ });
148
+ }
149
+ export function dedupeLinkedArtifacts(artifacts) {
150
+ return [...new Map(artifacts.map((entry) => [artifactKey(entry), entry])).values()].map((entry) => ({
151
+ ...entry,
152
+ note: entry.note?.trim() || undefined,
153
+ }));
154
+ }
155
+ export async function validateLinkedPaths(paths) {
156
+ const uniquePaths = [...new Set(paths)].sort((left, right) => left.localeCompare(right));
157
+ const existingFiles = [];
158
+ const missingPaths = [];
159
+ const nonFilePaths = [];
160
+ for (const relativePath of uniquePaths) {
161
+ const resolvedPath = path.isAbsolute(relativePath) ? relativePath : path.resolve(process.cwd(), relativePath);
162
+ try {
163
+ const stats = await fs.stat(resolvedPath);
164
+ if (stats.isFile()) {
165
+ existingFiles.push(relativePath);
166
+ }
167
+ else {
168
+ nonFilePaths.push(relativePath);
169
+ }
170
+ }
171
+ catch (error) {
172
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
173
+ missingPaths.push(relativePath);
174
+ continue;
175
+ }
176
+ nonFilePaths.push(relativePath);
177
+ }
178
+ }
179
+ return {
180
+ checked: uniquePaths.length,
181
+ existing_files: existingFiles,
182
+ missing_paths: missingPaths,
183
+ non_file_paths: nonFilePaths,
184
+ };
185
+ }
186
+ export function buildLinkedPathAudit(paths, allItems) {
187
+ const index = new Map();
188
+ for (const item of allItems) {
189
+ for (const linkedArtifact of item.artifacts ?? []) {
190
+ const seen = index.get(linkedArtifact.path) ?? new Set();
191
+ seen.add(item.id);
192
+ index.set(linkedArtifact.path, seen);
193
+ }
194
+ }
195
+ return [...new Set(paths)]
196
+ .sort((left, right) => left.localeCompare(right))
197
+ .map((linkedPath) => {
198
+ const linkedIds = [...(index.get(linkedPath) ?? new Set())].sort((left, right) => left.localeCompare(right));
199
+ return {
200
+ path: linkedPath,
201
+ linked_by_count: linkedIds.length,
202
+ linked_item_ids: linkedIds,
203
+ };
204
+ });
205
+ }
206
+ /**
207
+ * Shared linked-artifact list/mutate command core used by runFiles and runDocs.
208
+ * The kind config selects metadata key, op, bare-path noun, and whether
209
+ * append-stable ordering is honored, preserving each twin's exact semantics.
210
+ */
211
+ export async function runLinkedArtifacts(id, options, global, config) {
212
+ const { metadataKey } = config;
213
+ const stdinResolver = createStdinTokenResolver();
214
+ const pmRoot = resolvePmRoot(process.cwd(), global.path);
215
+ if (!(await pathExists(getSettingsPath(pmRoot)))) {
216
+ throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
217
+ }
218
+ const settings = await readSettings(pmRoot);
219
+ const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
220
+ const resolvedAdds = await stdinResolver.resolveList(options.add, "--add");
221
+ const resolvedAddGlobs = await stdinResolver.resolveList(options.addGlob, "--add-glob");
222
+ const resolvedRemoves = await stdinResolver.resolveList(options.remove, "--remove");
223
+ const resolvedMigrations = await stdinResolver.resolveList(options.migrate, "--migrate");
224
+ const parsedAdds = parseAddEntries(resolvedAdds, config.bareNoun);
225
+ const addGlobs = parseAddGlobEntries(resolvedAddGlobs);
226
+ const expandedGlobAdds = await expandAddGlobEntries(addGlobs);
227
+ const adds = [...parsedAdds, ...expandedGlobAdds];
228
+ const removes = parseRemoveEntries(resolvedRemoves);
229
+ const migrations = parseMigrateEntries(resolvedMigrations);
230
+ const shouldMutate = adds.length > 0 || removes.length > 0 || migrations.length > 0;
231
+ const collectAuditItems = async () => (await listAllFrontMatter(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema)).map((entry) => ({
232
+ id: entry.id,
233
+ artifacts: entry[metadataKey],
234
+ }));
235
+ if (!shouldMutate) {
236
+ const located = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
237
+ if (!located) {
238
+ throw new PmCliError(`Item ${id} not found`, EXIT_CODE.NOT_FOUND);
239
+ }
240
+ const loaded = await readLocatedItem(located, { schema: settings.schema });
241
+ const artifacts = loaded.document.metadata[metadataKey] ?? [];
242
+ return {
243
+ id: located.id,
244
+ artifacts,
245
+ changed: false,
246
+ count: artifacts.length,
247
+ validation: options.validatePaths ? await validateLinkedPaths(artifacts.map((entry) => entry.path)) : undefined,
248
+ audit: options.audit ? buildLinkedPathAudit(artifacts.map((entry) => entry.path), await collectAuditItems()) : undefined,
249
+ };
250
+ }
251
+ const author = resolveAuthor(options.author, settings.author_default);
252
+ const result = await mutateItem({
253
+ pmRoot,
254
+ settings,
255
+ id,
256
+ op: config.op,
257
+ author,
258
+ message: options.message,
259
+ force: options.force,
260
+ mutate(document) {
261
+ const metadata = document.metadata;
262
+ const next = [...(metadata[metadataKey] ?? [])];
263
+ let migrationCount = 0;
264
+ if (migrations.length > 0) {
265
+ for (let index = 0; index < next.length; index += 1) {
266
+ const migratedPath = applyPathMigrations(next[index].path, migrations);
267
+ if (migratedPath !== next[index].path) {
268
+ next[index] = { ...next[index], path: migratedPath };
269
+ migrationCount += 1;
270
+ }
271
+ }
272
+ }
273
+ const migratedAdds = adds.map((entry) => {
274
+ const migratedPath = applyPathMigrations(entry.path, migrations);
275
+ if (migratedPath !== entry.path) {
276
+ migrationCount += 1;
277
+ }
278
+ return {
279
+ ...entry,
280
+ path: migratedPath,
281
+ };
282
+ });
283
+ const migratedRemoves = removes.map((entry) => applyPathMigrations(entry, migrations));
284
+ for (const add of migratedAdds) {
285
+ const exists = next.some((entry) => entry.path === add.path && entry.scope === add.scope);
286
+ if (!exists) {
287
+ next.push(add);
288
+ }
289
+ }
290
+ if (migratedRemoves.length > 0) {
291
+ for (let i = next.length - 1; i >= 0; i -= 1) {
292
+ if (migratedRemoves.includes(next[i].path)) {
293
+ next.splice(i, 1);
294
+ }
295
+ }
296
+ }
297
+ const deduped = dedupeLinkedArtifacts(next);
298
+ const normalized = config.supportsAppendStable && options.appendStable ? deduped : sortLinkedArtifacts(deduped);
299
+ if (normalized.length > 0) {
300
+ metadata[metadataKey] = normalized;
301
+ }
302
+ else {
303
+ delete metadata[metadataKey];
304
+ }
305
+ return { changedFields: [metadataKey], warnings: migrationCount > 0 ? [`path_migrations_applied:${migrationCount}`] : [] };
306
+ },
307
+ });
308
+ const artifacts = result.item[metadataKey] ?? [];
309
+ const migrationWarning = result.warnings.find((warning) => warning.startsWith("path_migrations_applied:"));
310
+ const migrationCount = migrationWarning ? Number(migrationWarning.slice("path_migrations_applied:".length)) : 0;
311
+ const allItems = options.audit ? await collectAuditItems() : [];
312
+ return {
313
+ id: result.item.id,
314
+ artifacts,
315
+ changed: true,
316
+ count: artifacts.length,
317
+ migrations_applied: migrationCount > 0 ? migrationCount : undefined,
318
+ validation: options.validatePaths ? await validateLinkedPaths(artifacts.map((entry) => entry.path)) : undefined,
319
+ audit: options.audit ? buildLinkedPathAudit(artifacts.map((entry) => entry.path), allItems) : undefined,
320
+ };
321
+ }
322
+ /**
323
+ * Re-key the generic `artifacts` field to the resource-specific name (files/docs)
324
+ * while preserving the original key order and presence so kind-specific result
325
+ * shapes (and their deterministic JSON key ordering) stay byte-identical.
326
+ */
327
+ export function renameArtifactsResultKey(result, key) {
328
+ const out = {};
329
+ for (const [field, value] of Object.entries(result)) {
330
+ out[field === "artifacts" ? key : field] = value;
331
+ }
332
+ return out;
333
+ }
334
+ //# sourceMappingURL=linked-artifacts.js.map
335
+ //# debugId=352e67e3-0c41-5c04-8d2d-3395c6216303
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linked-artifacts.js","sources":["cli/commands/linked-artifacts.ts"],"sourceRoot":"/","sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport fg from \"fast-glob\";\nimport { pathExists } from \"../../core/fs/fs-utils.js\";\nimport { getActiveExtensionRegistrations } from \"../../core/extensions/index.js\";\nimport { createStdinTokenResolver, parseCsvKv } from \"../../core/item/parse.js\";\nimport { resolveItemTypeRegistry } from \"../../core/item/type-registry.js\";\nimport { EXIT_CODE } from \"../../core/shared/constants.js\";\nimport type { GlobalOptions } from \"../../core/shared/command-types.js\";\nimport { PmCliError } from \"../../core/shared/errors.js\";\nimport { listAllFrontMatter, locateItem, mutateItem, readLocatedItem } from \"../../core/store/item-store.js\";\nimport { getSettingsPath, resolvePmRoot } from \"../../core/store/paths.js\";\nimport { readSettings } from \"../../core/store/settings.js\";\nimport { SCOPE_VALUES } from \"../../types/index.js\";\nimport { resolveAuthor } from \"../../core/shared/author.js\";\nimport type { LinkScope } from \"../../types/index.js\";\n\nexport type LinkedArtifact = {\n path: string;\n scope: LinkScope;\n note?: string;\n};\n\nexport interface LinkedArtifactCommandOptions {\n add?: string[];\n addGlob?: string[];\n remove?: string[];\n migrate?: string[];\n list?: boolean;\n appendStable?: boolean;\n validatePaths?: boolean;\n audit?: boolean;\n author?: string;\n message?: string;\n force?: boolean;\n}\n\nexport interface PathMigration {\n from: string;\n to: string;\n}\n\nexport interface AddGlobEntry {\n pattern: string;\n scope: LinkScope;\n note?: string;\n}\n\nexport interface LinkedPathValidation {\n checked: number;\n existing_files: string[];\n missing_paths: string[];\n non_file_paths: string[];\n}\n\nexport interface LinkedPathAuditEntry {\n path: string;\n linked_by_count: number;\n linked_item_ids: string[];\n}\n\nexport interface LinkedArtifactResult {\n id: string;\n changed: boolean;\n count: number;\n migrations_applied?: number;\n validation?: LinkedPathValidation;\n audit?: LinkedPathAuditEntry[];\n artifacts: LinkedArtifact[];\n}\n\n/**\n * Configuration that adapts the shared linked-artifact command core to a\n * specific resource kind (files or docs) while preserving every behavioral\n * detail of the original twin implementations.\n */\nexport interface LinkedArtifactKindConfig {\n /** Metadata key under which the artifacts are stored (e.g. \"files\" | \"docs\"). */\n metadataKey: \"files\" | \"docs\";\n /** Mutation op recorded in history (e.g. \"files_add\" | \"docs_add\"). */\n op: \"files_add\" | \"docs_add\";\n /** Noun used in the \"bare <noun> path\" --add usage error (e.g. \"file\" | \"doc\"). */\n bareNoun: \"file\" | \"doc\";\n /**\n * Whether this kind honors the append-stable option. files supports it;\n * docs always sorts and must never expose append-stable behavior.\n */\n supportsAppendStable: boolean;\n}\n\nexport function ensureScope(raw: string | undefined): LinkScope {\n const value = (raw ?? \"project\") as LinkScope;\n if (!SCOPE_VALUES.includes(value)) {\n throw new PmCliError(\n `Invalid scope \"${raw}\". Valid scopes: ${SCOPE_VALUES.join(\", \")} (default: project).`,\n EXIT_CODE.USAGE,\n );\n }\n return value;\n}\n\nexport function looksLikeStructuredPathEntry(raw: string): boolean {\n if (raw.startsWith(\"```\") || raw.includes(\"\\n\")) {\n return true;\n }\n return /^(?:[-*+]\\s+)?(?:path|scope|note)\\s*[:=]/i.test(raw);\n}\n\nexport function parseAddEntries(raw: string[] | undefined, bareNoun: \"file\" | \"doc\"): LinkedArtifact[] {\n if (!raw) return [];\n return raw.map((entry) => {\n const trimmed = entry.trim();\n const kv = looksLikeStructuredPathEntry(trimmed) ? parseCsvKv(entry, \"--add\") : { path: trimmed };\n if (!kv.path) {\n throw new PmCliError(`--add requires path=<value> or a bare ${bareNoun} path`, EXIT_CODE.USAGE);\n }\n return {\n path: kv.path,\n scope: ensureScope(kv.scope),\n note: kv.note?.trim() || undefined,\n };\n });\n}\n\nexport function parseAddGlobEntries(raw: string[] | undefined): AddGlobEntry[] {\n if (!raw) return [];\n return raw.map((entry) => {\n const trimmed = entry.trim();\n if (!trimmed) {\n throw new PmCliError(\"--add-glob requires a glob pattern value\", EXIT_CODE.USAGE);\n }\n if (trimmed.includes(\"=\") || /^(?:[-*+]\\s+)?(?:pattern|glob|path)\\s*[:=]/i.test(trimmed) || trimmed.startsWith(\"```\")) {\n const kv = parseCsvKv(trimmed, \"--add-glob\");\n const pattern = kv.pattern?.trim() || kv.glob?.trim() || kv.path?.trim();\n if (!pattern) {\n throw new PmCliError(\"--add-glob key/value form requires pattern=<glob>\", EXIT_CODE.USAGE);\n }\n return {\n pattern,\n scope: ensureScope(kv.scope),\n note: kv.note?.trim() || undefined,\n };\n }\n return {\n pattern: trimmed,\n scope: \"project\",\n };\n });\n}\n\nexport function parseRemoveEntries(raw: string[] | undefined): string[] {\n if (!raw) return [];\n return raw.map((entry) => {\n const trimmed = entry.trim();\n if (!trimmed) {\n throw new PmCliError(\"--remove requires a path value\", EXIT_CODE.USAGE);\n }\n if (trimmed.includes(\"=\") || /^(?:[-*+]\\s+)?path\\s*[:=]/i.test(trimmed) || trimmed.startsWith(\"```\")) {\n const kv = parseCsvKv(trimmed, \"--remove\");\n if (!kv.path) {\n throw new PmCliError(\"--remove key/value form requires path=<value>\", EXIT_CODE.USAGE);\n }\n return kv.path;\n }\n return trimmed;\n });\n}\n\nexport function parseMigrateEntries(raw: string[] | undefined): PathMigration[] {\n if (!raw) return [];\n return raw.map((entry) => {\n const kv = parseCsvKv(entry, \"--migrate\");\n const from = kv.from?.trim();\n const to = kv.to?.trim();\n if (!from || !to) {\n throw new PmCliError(\"--migrate requires from=<value> and to=<value>\", EXIT_CODE.USAGE);\n }\n return { from, to };\n });\n}\n\nexport function applyPathMigrations(artifactPath: string, migrations: PathMigration[]): string {\n let next = artifactPath;\n for (const migration of migrations) {\n if (next.startsWith(migration.from)) {\n next = `${migration.to}${next.slice(migration.from.length)}`;\n }\n }\n return next;\n}\n\nexport function normalizeLinkedPath(value: string): string {\n return value.split(path.sep).join(\"/\");\n}\n\nexport async function expandAddGlobEntries(entries: AddGlobEntry[]): Promise<LinkedArtifact[]> {\n const expanded: LinkedArtifact[] = [];\n for (const entry of entries) {\n const absolutePattern = path.isAbsolute(entry.pattern);\n const matches = await fg(entry.pattern, {\n cwd: process.cwd(),\n absolute: absolutePattern,\n onlyFiles: true,\n dot: true,\n unique: true,\n followSymbolicLinks: true,\n });\n const sortedMatches = [...new Set(matches.map((match) => normalizeLinkedPath(path.normalize(match))))].sort((left, right) =>\n left.localeCompare(right),\n );\n for (const matchedPath of sortedMatches) {\n expanded.push({\n path: matchedPath,\n scope: entry.scope,\n note: entry.note,\n });\n }\n }\n return expanded;\n}\n\nexport function artifactKey(value: Pick<LinkedArtifact, \"path\" | \"scope\">): string {\n return `${value.path}::${value.scope}`;\n}\n\nexport function sortLinkedArtifacts(artifacts: LinkedArtifact[]): LinkedArtifact[] {\n return [...artifacts].sort((left, right) => {\n const byPath = left.path.localeCompare(right.path);\n if (byPath !== 0) return byPath;\n return left.scope.localeCompare(right.scope);\n });\n}\n\nexport function dedupeLinkedArtifacts(artifacts: LinkedArtifact[]): LinkedArtifact[] {\n return [...new Map(artifacts.map((entry) => [artifactKey(entry), entry])).values()].map((entry) => ({\n ...entry,\n note: entry.note?.trim() || undefined,\n }));\n}\n\nexport async function validateLinkedPaths(paths: string[]): Promise<LinkedPathValidation> {\n const uniquePaths = [...new Set(paths)].sort((left, right) => left.localeCompare(right));\n const existingFiles: string[] = [];\n const missingPaths: string[] = [];\n const nonFilePaths: string[] = [];\n for (const relativePath of uniquePaths) {\n const resolvedPath = path.isAbsolute(relativePath) ? relativePath : path.resolve(process.cwd(), relativePath);\n try {\n const stats = await fs.stat(resolvedPath);\n if (stats.isFile()) {\n existingFiles.push(relativePath);\n } else {\n nonFilePaths.push(relativePath);\n }\n } catch (error: unknown) {\n if (typeof error === \"object\" && error !== null && \"code\" in error && (error as { code?: string }).code === \"ENOENT\") {\n missingPaths.push(relativePath);\n continue;\n }\n nonFilePaths.push(relativePath);\n }\n }\n return {\n checked: uniquePaths.length,\n existing_files: existingFiles,\n missing_paths: missingPaths,\n non_file_paths: nonFilePaths,\n };\n}\n\nexport function buildLinkedPathAudit(\n paths: string[],\n allItems: Array<{ id: string; artifacts?: LinkedArtifact[] }>,\n): LinkedPathAuditEntry[] {\n const index = new Map<string, Set<string>>();\n for (const item of allItems) {\n for (const linkedArtifact of item.artifacts ?? []) {\n const seen = index.get(linkedArtifact.path) ?? new Set<string>();\n seen.add(item.id);\n index.set(linkedArtifact.path, seen);\n }\n }\n return [...new Set(paths)]\n .sort((left, right) => left.localeCompare(right))\n .map((linkedPath) => {\n const linkedIds = [...(index.get(linkedPath) ?? new Set<string>())].sort((left, right) => left.localeCompare(right));\n return {\n path: linkedPath,\n linked_by_count: linkedIds.length,\n linked_item_ids: linkedIds,\n };\n });\n}\n\n/**\n * Shared linked-artifact list/mutate command core used by runFiles and runDocs.\n * The kind config selects metadata key, op, bare-path noun, and whether\n * append-stable ordering is honored, preserving each twin's exact semantics.\n */\nexport async function runLinkedArtifacts(\n id: string,\n options: LinkedArtifactCommandOptions,\n global: GlobalOptions,\n config: LinkedArtifactKindConfig,\n): Promise<LinkedArtifactResult> {\n const { metadataKey } = config;\n const stdinResolver = createStdinTokenResolver();\n const pmRoot = resolvePmRoot(process.cwd(), global.path);\n if (!(await pathExists(getSettingsPath(pmRoot)))) {\n throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);\n }\n const settings = await readSettings(pmRoot);\n const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());\n const resolvedAdds = await stdinResolver.resolveList(options.add, \"--add\");\n const resolvedAddGlobs = await stdinResolver.resolveList(options.addGlob, \"--add-glob\");\n const resolvedRemoves = await stdinResolver.resolveList(options.remove, \"--remove\");\n const resolvedMigrations = await stdinResolver.resolveList(options.migrate, \"--migrate\");\n const parsedAdds = parseAddEntries(resolvedAdds, config.bareNoun);\n const addGlobs = parseAddGlobEntries(resolvedAddGlobs);\n const expandedGlobAdds = await expandAddGlobEntries(addGlobs);\n const adds = [...parsedAdds, ...expandedGlobAdds];\n const removes = parseRemoveEntries(resolvedRemoves);\n const migrations = parseMigrateEntries(resolvedMigrations);\n const shouldMutate = adds.length > 0 || removes.length > 0 || migrations.length > 0;\n\n const collectAuditItems = async (): Promise<Array<{ id: string; artifacts?: LinkedArtifact[] }>> =>\n (await listAllFrontMatter(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema)).map((entry) => ({\n id: entry.id,\n artifacts: (entry as Record<string, unknown>)[metadataKey] as LinkedArtifact[] | undefined,\n }));\n\n if (!shouldMutate) {\n const located = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);\n if (!located) {\n throw new PmCliError(`Item ${id} not found`, EXIT_CODE.NOT_FOUND);\n }\n const loaded = await readLocatedItem(located, { schema: settings.schema });\n const artifacts = ((loaded.document.metadata as Record<string, unknown>)[metadataKey] as LinkedArtifact[] | undefined) ?? [];\n return {\n id: located.id,\n artifacts,\n changed: false,\n count: artifacts.length,\n validation: options.validatePaths ? await validateLinkedPaths(artifacts.map((entry) => entry.path)) : undefined,\n audit: options.audit ? buildLinkedPathAudit(artifacts.map((entry) => entry.path), await collectAuditItems()) : undefined,\n };\n }\n\n const author = resolveAuthor(options.author, settings.author_default);\n const result = await mutateItem({\n pmRoot,\n settings,\n id,\n op: config.op,\n author,\n message: options.message,\n force: options.force,\n mutate(document) {\n const metadata = document.metadata as Record<string, unknown>;\n const next = [...((metadata[metadataKey] as LinkedArtifact[] | undefined) ?? [])];\n let migrationCount = 0;\n if (migrations.length > 0) {\n for (let index = 0; index < next.length; index += 1) {\n const migratedPath = applyPathMigrations(next[index].path, migrations);\n if (migratedPath !== next[index].path) {\n next[index] = { ...next[index], path: migratedPath };\n migrationCount += 1;\n }\n }\n }\n const migratedAdds = adds.map((entry) => {\n const migratedPath = applyPathMigrations(entry.path, migrations);\n if (migratedPath !== entry.path) {\n migrationCount += 1;\n }\n return {\n ...entry,\n path: migratedPath,\n };\n });\n const migratedRemoves = removes.map((entry) => applyPathMigrations(entry, migrations));\n for (const add of migratedAdds) {\n const exists = next.some((entry) => entry.path === add.path && entry.scope === add.scope);\n if (!exists) {\n next.push(add);\n }\n }\n if (migratedRemoves.length > 0) {\n for (let i = next.length - 1; i >= 0; i -= 1) {\n if (migratedRemoves.includes(next[i].path)) {\n next.splice(i, 1);\n }\n }\n }\n const deduped = dedupeLinkedArtifacts(next);\n const normalized = config.supportsAppendStable && options.appendStable ? deduped : sortLinkedArtifacts(deduped);\n if (normalized.length > 0) {\n metadata[metadataKey] = normalized;\n } else {\n delete metadata[metadataKey];\n }\n return { changedFields: [metadataKey], warnings: migrationCount > 0 ? [`path_migrations_applied:${migrationCount}`] : [] };\n },\n });\n\n const artifacts = ((result.item as Record<string, unknown>)[metadataKey] as LinkedArtifact[] | undefined) ?? [];\n const migrationWarning = result.warnings.find((warning) => warning.startsWith(\"path_migrations_applied:\"));\n const migrationCount = migrationWarning ? Number(migrationWarning.slice(\"path_migrations_applied:\".length)) : 0;\n const allItems = options.audit ? await collectAuditItems() : [];\n return {\n id: result.item.id,\n artifacts,\n changed: true,\n count: artifacts.length,\n migrations_applied: migrationCount > 0 ? migrationCount : undefined,\n validation: options.validatePaths ? await validateLinkedPaths(artifacts.map((entry) => entry.path)) : undefined,\n audit: options.audit ? buildLinkedPathAudit(artifacts.map((entry) => entry.path), allItems) : undefined,\n };\n}\n\n/**\n * Re-key the generic `artifacts` field to the resource-specific name (files/docs)\n * while preserving the original key order and presence so kind-specific result\n * shapes (and their deterministic JSON key ordering) stay byte-identical.\n */\nexport function renameArtifactsResultKey(result: LinkedArtifactResult, key: \"files\" | \"docs\"): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(result)) {\n out[field === \"artifacts\" ? key : field] = value;\n }\n return out;\n}\n"],"names":[],"mappings":"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","debugId":"352e67e3-0c41-5c04-8d2d-3395c6216303"}
@@ -0,0 +1,28 @@
1
+ import type { LinkedTest } from "../../types/index.js";
2
+ /**
3
+ * Shared linked-test field parsers used by the `create` and `test` commands.
4
+ *
5
+ * Extracted verbatim from create.ts and test.ts (pm-why9). The two copies were
6
+ * byte-identical apart from their empty-input guard: create called these with
7
+ * raw (untrimmed) values and used `if (!normalized)`; test called them with
8
+ * pre-`.trim()`-ed values and used `if (!raw || raw.trim().length === 0)`.
9
+ *
10
+ * Both reduce to the same observable behaviour when the guard is the plain
11
+ * falsy check used here: create's call sites still pass untrimmed values
12
+ * (behaviour preserved exactly), and test's call sites pre-trim so a
13
+ * whitespace-only value collapses to "" and is rejected by `!raw` exactly as
14
+ * before. Error strings and parsing semantics are identical to both originals.
15
+ */
16
+ export declare const LINKED_TEST_PROTECTED_ENV_KEYS: Set<string>;
17
+ export declare const LINKED_TEST_ENV_NAME_PATTERN: RegExp;
18
+ export declare const LINKED_TEST_PM_CONTEXT_MODE_VALUES: readonly ["schema", "tracker", "auto"];
19
+ export type LinkedTestPmContextMode = (typeof LINKED_TEST_PM_CONTEXT_MODE_VALUES)[number];
20
+ export declare function parseLinkedTestEnvSet(raw: string | undefined, optionName: string): Record<string, string> | undefined;
21
+ export declare function parseLinkedTestEnvClear(raw: string | undefined, optionName: string): string[] | undefined;
22
+ export declare function parseLinkedTestBoolean(raw: string | undefined, optionName: string, fieldLabel: string): boolean | undefined;
23
+ export declare function parseLinkedTestContextMode(raw: string | undefined, optionName: string): LinkedTest["pm_context_mode"] | undefined;
24
+ export declare function parseLinkedTestStringList(raw: string | undefined): string[] | undefined;
25
+ export declare function parseLinkedTestRegexList(raw: string | undefined, optionName: string, fieldLabel: string): string[] | undefined;
26
+ export declare function parseLinkedTestMinLines(raw: string | undefined, optionName: string): number | undefined;
27
+ export declare function parseLinkedTestAssertionEqualsMap(raw: string | undefined, optionName: string): Record<string, string> | undefined;
28
+ export declare function parseLinkedTestAssertionGteMap(raw: string | undefined, optionName: string): Record<string, number> | undefined;
@@ -0,0 +1,192 @@
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]="8dda4564-25c9-55a3-a141-656338bf70bd")}catch(e){}}();
3
+ import { parseOptionalNumber } from "../../core/item/parse.js";
4
+ import { EXIT_CODE } from "../../core/shared/constants.js";
5
+ import { PmCliError } from "../../core/shared/errors.js";
6
+ /**
7
+ * Shared linked-test field parsers used by the `create` and `test` commands.
8
+ *
9
+ * Extracted verbatim from create.ts and test.ts (pm-why9). The two copies were
10
+ * byte-identical apart from their empty-input guard: create called these with
11
+ * raw (untrimmed) values and used `if (!normalized)`; test called them with
12
+ * pre-`.trim()`-ed values and used `if (!raw || raw.trim().length === 0)`.
13
+ *
14
+ * Both reduce to the same observable behaviour when the guard is the plain
15
+ * falsy check used here: create's call sites still pass untrimmed values
16
+ * (behaviour preserved exactly), and test's call sites pre-trim so a
17
+ * whitespace-only value collapses to "" and is rejected by `!raw` exactly as
18
+ * before. Error strings and parsing semantics are identical to both originals.
19
+ */
20
+ export const LINKED_TEST_PROTECTED_ENV_KEYS = new Set(["PM_PATH", "PM_GLOBAL_PATH", "FORCE_COLOR"]);
21
+ export const LINKED_TEST_ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
22
+ export const LINKED_TEST_PM_CONTEXT_MODE_VALUES = ["schema", "tracker", "auto"];
23
+ export function parseLinkedTestEnvSet(raw, optionName) {
24
+ if (!raw) {
25
+ return undefined;
26
+ }
27
+ const assignments = raw
28
+ .split(/[;\n]/)
29
+ .map((entry) => entry.trim())
30
+ .filter((entry) => entry.length > 0);
31
+ if (assignments.length === 0) {
32
+ throw new PmCliError(`${optionName} env_set must include at least one KEY=VALUE assignment`, EXIT_CODE.USAGE);
33
+ }
34
+ const envSet = {};
35
+ for (const assignment of assignments) {
36
+ const separatorIndex = assignment.indexOf("=");
37
+ if (separatorIndex <= 0) {
38
+ 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);
39
+ }
40
+ const key = assignment.slice(0, separatorIndex).trim();
41
+ const value = assignment.slice(separatorIndex + 1);
42
+ if (!LINKED_TEST_ENV_NAME_PATTERN.test(key)) {
43
+ throw new PmCliError(`${optionName} env_set key "${key}" is invalid`, EXIT_CODE.USAGE);
44
+ }
45
+ if (LINKED_TEST_PROTECTED_ENV_KEYS.has(key.toUpperCase())) {
46
+ throw new PmCliError(`${optionName} env_set key "${key}" is reserved for sandbox safety`, EXIT_CODE.USAGE);
47
+ }
48
+ envSet[key] = value;
49
+ }
50
+ /* c8 ignore start -- envSet always has >=1 key here (assignments is non-empty and each adds one); the undefined branch is defensive. */
51
+ return Object.keys(envSet).length > 0 ? envSet : undefined;
52
+ /* c8 ignore stop */
53
+ }
54
+ export function parseLinkedTestEnvClear(raw, optionName) {
55
+ if (!raw) {
56
+ return undefined;
57
+ }
58
+ const keys = [...new Set(raw.split(/[;,\n]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0))];
59
+ if (keys.length === 0) {
60
+ throw new PmCliError(`${optionName} env_clear must include at least one environment variable name`, EXIT_CODE.USAGE);
61
+ }
62
+ for (const key of keys) {
63
+ if (!LINKED_TEST_ENV_NAME_PATTERN.test(key)) {
64
+ throw new PmCliError(`${optionName} env_clear key "${key}" is invalid`, EXIT_CODE.USAGE);
65
+ }
66
+ if (LINKED_TEST_PROTECTED_ENV_KEYS.has(key.toUpperCase())) {
67
+ throw new PmCliError(`${optionName} env_clear key "${key}" is reserved for sandbox safety`, EXIT_CODE.USAGE);
68
+ }
69
+ }
70
+ return keys;
71
+ }
72
+ export function parseLinkedTestBoolean(raw, optionName, fieldLabel) {
73
+ if (!raw) {
74
+ return undefined;
75
+ }
76
+ const value = raw.trim().toLowerCase();
77
+ if (value === "true" || value === "1" || value === "yes") {
78
+ return true;
79
+ }
80
+ if (value === "false" || value === "0" || value === "no") {
81
+ return false;
82
+ }
83
+ throw new PmCliError(`${optionName} ${fieldLabel} must be one of true|false|1|0|yes|no`, EXIT_CODE.USAGE);
84
+ }
85
+ export function parseLinkedTestContextMode(raw, optionName) {
86
+ if (!raw) {
87
+ return undefined;
88
+ }
89
+ const value = raw.trim().toLowerCase();
90
+ if (LINKED_TEST_PM_CONTEXT_MODE_VALUES.includes(value)) {
91
+ return value;
92
+ }
93
+ throw new PmCliError(`${optionName} pm_context_mode must be one of: ${LINKED_TEST_PM_CONTEXT_MODE_VALUES.join(", ")}`, EXIT_CODE.USAGE);
94
+ }
95
+ export function parseLinkedTestStringList(raw) {
96
+ if (!raw) {
97
+ return undefined;
98
+ }
99
+ const values = [...new Set(raw.split(/[;\n]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0))];
100
+ return values.length > 0 ? values : undefined;
101
+ }
102
+ export function parseLinkedTestRegexList(raw, optionName, fieldLabel) {
103
+ const values = parseLinkedTestStringList(raw);
104
+ if (!values || values.length === 0) {
105
+ return undefined;
106
+ }
107
+ for (const pattern of values) {
108
+ try {
109
+ // Validate regex syntax early so malformed assertions fail at parse time.
110
+ // User-provided, per-item patterns only run during local CLI validation.
111
+ new RegExp(pattern, "m");
112
+ }
113
+ catch (error) {
114
+ throw new PmCliError(
115
+ /* c8 ignore next -- RegExp only throws SyntaxError (an Error); String(error) fallback is defensive. */
116
+ `${optionName} ${fieldLabel} includes invalid regex "${pattern}": ${error instanceof Error ? error.message : String(error)}`, EXIT_CODE.USAGE);
117
+ }
118
+ }
119
+ return values;
120
+ }
121
+ export function parseLinkedTestMinLines(raw, optionName) {
122
+ if (!raw) {
123
+ return undefined;
124
+ }
125
+ const parsed = parseOptionalNumber(raw, "assert_stdout_min_lines");
126
+ if (!Number.isInteger(parsed) || parsed < 0) {
127
+ throw new PmCliError(`${optionName} assert_stdout_min_lines must be an integer >= 0`, EXIT_CODE.USAGE);
128
+ }
129
+ return parsed;
130
+ }
131
+ export function parseLinkedTestAssertionEqualsMap(raw, optionName) {
132
+ if (!raw) {
133
+ return undefined;
134
+ }
135
+ const assignments = raw
136
+ .split(/[;\n]/)
137
+ .map((entry) => entry.trim())
138
+ .filter((entry) => entry.length > 0);
139
+ if (assignments.length === 0) {
140
+ throw new PmCliError(`${optionName} assert_json_field_equals must include at least one path=value assignment`, EXIT_CODE.USAGE);
141
+ }
142
+ const values = {};
143
+ for (const assignment of assignments) {
144
+ const separatorIndex = assignment.indexOf("=");
145
+ if (separatorIndex <= 0) {
146
+ throw new PmCliError(`${optionName} assert_json_field_equals entries must use path=value and be separated by semicolons`, EXIT_CODE.USAGE);
147
+ }
148
+ const key = assignment.slice(0, separatorIndex).trim();
149
+ const value = assignment.slice(separatorIndex + 1).trim();
150
+ if (key.length === 0 || value.length === 0) {
151
+ throw new PmCliError(`${optionName} assert_json_field_equals entries must include non-empty path and value`, EXIT_CODE.USAGE);
152
+ }
153
+ values[key] = value;
154
+ }
155
+ /* c8 ignore start -- values always has >=1 key here (assignments is non-empty and each adds one); the undefined branch is defensive. */
156
+ return Object.keys(values).length > 0 ? values : undefined;
157
+ /* c8 ignore stop */
158
+ }
159
+ export function parseLinkedTestAssertionGteMap(raw, optionName) {
160
+ if (!raw) {
161
+ return undefined;
162
+ }
163
+ const assignments = raw
164
+ .split(/[;\n]/)
165
+ .map((entry) => entry.trim())
166
+ .filter((entry) => entry.length > 0);
167
+ if (assignments.length === 0) {
168
+ throw new PmCliError(`${optionName} assert_json_field_gte must include at least one path=value assignment`, EXIT_CODE.USAGE);
169
+ }
170
+ const values = {};
171
+ for (const assignment of assignments) {
172
+ const separatorIndex = assignment.indexOf("=");
173
+ if (separatorIndex <= 0) {
174
+ throw new PmCliError(`${optionName} assert_json_field_gte entries must use path=value and be separated by semicolons`, EXIT_CODE.USAGE);
175
+ }
176
+ const key = assignment.slice(0, separatorIndex).trim();
177
+ const valueRaw = assignment.slice(separatorIndex + 1).trim();
178
+ if (key.length === 0 || valueRaw.length === 0) {
179
+ throw new PmCliError(`${optionName} assert_json_field_gte entries must include non-empty path and value`, EXIT_CODE.USAGE);
180
+ }
181
+ const value = Number.parseFloat(valueRaw);
182
+ if (!Number.isFinite(value)) {
183
+ throw new PmCliError(`${optionName} assert_json_field_gte value for "${key}" must be numeric`, EXIT_CODE.USAGE);
184
+ }
185
+ values[key] = value;
186
+ }
187
+ /* c8 ignore start -- values always has >=1 key here (assignments is non-empty and each adds one); the undefined branch is defensive. */
188
+ return Object.keys(values).length > 0 ? values : undefined;
189
+ /* c8 ignore stop */
190
+ }
191
+ //# sourceMappingURL=linked-test-parsers.js.map
192
+ //# debugId=8dda4564-25c9-55a3-a141-656338bf70bd