@unbrained/pm-cli 2026.3.9 → 2026.5.1

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 (288) hide show
  1. package/.agents/pm/extensions/.managed-extensions.json +42 -0
  2. package/.agents/pm/extensions/beads/index.js +109 -0
  3. package/.agents/pm/extensions/beads/manifest.json +7 -0
  4. package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +167 -56
  5. package/.agents/pm/extensions/beads/runtime.ts +702 -0
  6. package/.agents/pm/extensions/todos/index.js +126 -0
  7. package/.agents/pm/extensions/todos/manifest.json +7 -0
  8. package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
  9. package/.agents/pm/extensions/todos/runtime.ts +568 -0
  10. package/AGENTS.md +212 -94
  11. package/CHANGELOG.md +399 -0
  12. package/CODE_OF_CONDUCT.md +42 -0
  13. package/CONTRIBUTING.md +144 -0
  14. package/PRD.md +522 -173
  15. package/README.md +996 -495
  16. package/SECURITY.md +51 -0
  17. package/dist/cli/commands/activity.d.ts +5 -0
  18. package/dist/cli/commands/activity.js +66 -3
  19. package/dist/cli/commands/activity.js.map +1 -1
  20. package/dist/cli/commands/aggregate.d.ts +54 -0
  21. package/dist/cli/commands/aggregate.js +181 -0
  22. package/dist/cli/commands/aggregate.js.map +1 -0
  23. package/dist/cli/commands/append.js +4 -1
  24. package/dist/cli/commands/append.js.map +1 -1
  25. package/dist/cli/commands/calendar.d.ts +109 -0
  26. package/dist/cli/commands/calendar.js +797 -0
  27. package/dist/cli/commands/calendar.js.map +1 -0
  28. package/dist/cli/commands/claim.d.ts +5 -1
  29. package/dist/cli/commands/claim.js +42 -21
  30. package/dist/cli/commands/claim.js.map +1 -1
  31. package/dist/cli/commands/close.d.ts +1 -0
  32. package/dist/cli/commands/close.js +54 -5
  33. package/dist/cli/commands/close.js.map +1 -1
  34. package/dist/cli/commands/comments-audit.d.ts +91 -0
  35. package/dist/cli/commands/comments-audit.js +195 -0
  36. package/dist/cli/commands/comments-audit.js.map +1 -0
  37. package/dist/cli/commands/comments.d.ts +1 -0
  38. package/dist/cli/commands/comments.js +70 -21
  39. package/dist/cli/commands/comments.js.map +1 -1
  40. package/dist/cli/commands/completion.d.ts +10 -4
  41. package/dist/cli/commands/completion.js +1240 -193
  42. package/dist/cli/commands/completion.js.map +1 -1
  43. package/dist/cli/commands/config.d.ts +35 -3
  44. package/dist/cli/commands/config.js +968 -13
  45. package/dist/cli/commands/config.js.map +1 -1
  46. package/dist/cli/commands/context.d.ts +86 -0
  47. package/dist/cli/commands/context.js +299 -0
  48. package/dist/cli/commands/context.js.map +1 -0
  49. package/dist/cli/commands/contracts.d.ts +78 -0
  50. package/dist/cli/commands/contracts.js +920 -0
  51. package/dist/cli/commands/contracts.js.map +1 -0
  52. package/dist/cli/commands/create.d.ts +48 -14
  53. package/dist/cli/commands/create.js +1331 -160
  54. package/dist/cli/commands/create.js.map +1 -1
  55. package/dist/cli/commands/dedupe-audit.d.ts +81 -0
  56. package/dist/cli/commands/dedupe-audit.js +330 -0
  57. package/dist/cli/commands/dedupe-audit.js.map +1 -0
  58. package/dist/cli/commands/deps.d.ts +52 -0
  59. package/dist/cli/commands/deps.js +204 -0
  60. package/dist/cli/commands/deps.js.map +1 -0
  61. package/dist/cli/commands/docs.d.ts +19 -0
  62. package/dist/cli/commands/docs.js +212 -13
  63. package/dist/cli/commands/docs.js.map +1 -1
  64. package/dist/cli/commands/extension.d.ts +122 -0
  65. package/dist/cli/commands/extension.js +1850 -0
  66. package/dist/cli/commands/extension.js.map +1 -0
  67. package/dist/cli/commands/files.d.ts +52 -1
  68. package/dist/cli/commands/files.js +443 -13
  69. package/dist/cli/commands/files.js.map +1 -1
  70. package/dist/cli/commands/gc.d.ts +11 -1
  71. package/dist/cli/commands/gc.js +89 -11
  72. package/dist/cli/commands/gc.js.map +1 -1
  73. package/dist/cli/commands/get.d.ts +13 -0
  74. package/dist/cli/commands/get.js +35 -3
  75. package/dist/cli/commands/get.js.map +1 -1
  76. package/dist/cli/commands/health.d.ts +10 -2
  77. package/dist/cli/commands/health.js +774 -23
  78. package/dist/cli/commands/health.js.map +1 -1
  79. package/dist/cli/commands/history.d.ts +20 -0
  80. package/dist/cli/commands/history.js +152 -6
  81. package/dist/cli/commands/history.js.map +1 -1
  82. package/dist/cli/commands/index.d.ts +16 -3
  83. package/dist/cli/commands/index.js +16 -3
  84. package/dist/cli/commands/index.js.map +1 -1
  85. package/dist/cli/commands/init.d.ts +7 -2
  86. package/dist/cli/commands/init.js +137 -5
  87. package/dist/cli/commands/init.js.map +1 -1
  88. package/dist/cli/commands/learnings.d.ts +17 -0
  89. package/dist/cli/commands/learnings.js +129 -0
  90. package/dist/cli/commands/learnings.js.map +1 -0
  91. package/dist/cli/commands/list.d.ts +29 -1
  92. package/dist/cli/commands/list.js +292 -56
  93. package/dist/cli/commands/list.js.map +1 -1
  94. package/dist/cli/commands/normalize.d.ts +51 -0
  95. package/dist/cli/commands/normalize.js +298 -0
  96. package/dist/cli/commands/normalize.js.map +1 -0
  97. package/dist/cli/commands/notes.d.ts +17 -0
  98. package/dist/cli/commands/notes.js +129 -0
  99. package/dist/cli/commands/notes.js.map +1 -0
  100. package/dist/cli/commands/reindex.d.ts +1 -0
  101. package/dist/cli/commands/reindex.js +208 -32
  102. package/dist/cli/commands/reindex.js.map +1 -1
  103. package/dist/cli/commands/restore.js +164 -30
  104. package/dist/cli/commands/restore.js.map +1 -1
  105. package/dist/cli/commands/search.d.ts +14 -1
  106. package/dist/cli/commands/search.js +479 -85
  107. package/dist/cli/commands/search.js.map +1 -1
  108. package/dist/cli/commands/stats.js +26 -10
  109. package/dist/cli/commands/stats.js.map +1 -1
  110. package/dist/cli/commands/templates.d.ts +26 -0
  111. package/dist/cli/commands/templates.js +179 -0
  112. package/dist/cli/commands/templates.js.map +1 -0
  113. package/dist/cli/commands/test-all.d.ts +19 -1
  114. package/dist/cli/commands/test-all.js +161 -13
  115. package/dist/cli/commands/test-all.js.map +1 -1
  116. package/dist/cli/commands/test-runs.d.ts +63 -0
  117. package/dist/cli/commands/test-runs.js +179 -0
  118. package/dist/cli/commands/test-runs.js.map +1 -0
  119. package/dist/cli/commands/test.d.ts +75 -1
  120. package/dist/cli/commands/test.js +1360 -41
  121. package/dist/cli/commands/test.js.map +1 -1
  122. package/dist/cli/commands/update-many.d.ts +57 -0
  123. package/dist/cli/commands/update-many.js +631 -0
  124. package/dist/cli/commands/update-many.js.map +1 -0
  125. package/dist/cli/commands/update.d.ts +30 -0
  126. package/dist/cli/commands/update.js +1393 -84
  127. package/dist/cli/commands/update.js.map +1 -1
  128. package/dist/cli/commands/validate.d.ts +30 -0
  129. package/dist/cli/commands/validate.js +1140 -0
  130. package/dist/cli/commands/validate.js.map +1 -0
  131. package/dist/cli/error-guidance.d.ts +33 -0
  132. package/dist/cli/error-guidance.js +337 -0
  133. package/dist/cli/error-guidance.js.map +1 -0
  134. package/dist/cli/extension-command-options.d.ts +1 -0
  135. package/dist/cli/extension-command-options.js +92 -0
  136. package/dist/cli/extension-command-options.js.map +1 -1
  137. package/dist/cli/help-content.d.ts +20 -0
  138. package/dist/cli/help-content.js +543 -0
  139. package/dist/cli/help-content.js.map +1 -0
  140. package/dist/cli/main.js +3648 -467
  141. package/dist/cli/main.js.map +1 -1
  142. package/dist/core/extensions/index.d.ts +13 -1
  143. package/dist/core/extensions/index.js +108 -1
  144. package/dist/core/extensions/index.js.map +1 -1
  145. package/dist/core/extensions/item-fields.d.ts +2 -0
  146. package/dist/core/extensions/item-fields.js +79 -0
  147. package/dist/core/extensions/item-fields.js.map +1 -0
  148. package/dist/core/extensions/loader.d.ts +322 -9
  149. package/dist/core/extensions/loader.js +911 -20
  150. package/dist/core/extensions/loader.js.map +1 -1
  151. package/dist/core/extensions/runtime-registrations.d.ts +5 -0
  152. package/dist/core/extensions/runtime-registrations.js +51 -0
  153. package/dist/core/extensions/runtime-registrations.js.map +1 -0
  154. package/dist/core/history/history-stream-policy.d.ts +20 -0
  155. package/dist/core/history/history-stream-policy.js +53 -0
  156. package/dist/core/history/history-stream-policy.js.map +1 -0
  157. package/dist/core/history/history.js +90 -1
  158. package/dist/core/history/history.js.map +1 -1
  159. package/dist/core/item/id.d.ts +1 -0
  160. package/dist/core/item/id.js +10 -3
  161. package/dist/core/item/id.js.map +1 -1
  162. package/dist/core/item/index.d.ts +1 -0
  163. package/dist/core/item/index.js +1 -0
  164. package/dist/core/item/index.js.map +1 -1
  165. package/dist/core/item/item-format.d.ts +11 -5
  166. package/dist/core/item/item-format.js +532 -28
  167. package/dist/core/item/item-format.js.map +1 -1
  168. package/dist/core/item/parent-reference-policy.d.ts +6 -0
  169. package/dist/core/item/parent-reference-policy.js +32 -0
  170. package/dist/core/item/parent-reference-policy.js.map +1 -0
  171. package/dist/core/item/parse.d.ts +5 -0
  172. package/dist/core/item/parse.js +216 -19
  173. package/dist/core/item/parse.js.map +1 -1
  174. package/dist/core/item/sprint-release-format.d.ts +6 -0
  175. package/dist/core/item/sprint-release-format.js +33 -0
  176. package/dist/core/item/sprint-release-format.js.map +1 -0
  177. package/dist/core/item/status.d.ts +3 -0
  178. package/dist/core/item/status.js +24 -0
  179. package/dist/core/item/status.js.map +1 -0
  180. package/dist/core/item/type-registry.d.ts +37 -0
  181. package/dist/core/item/type-registry.js +706 -0
  182. package/dist/core/item/type-registry.js.map +1 -0
  183. package/dist/core/lock/lock.d.ts +1 -1
  184. package/dist/core/lock/lock.js +101 -12
  185. package/dist/core/lock/lock.js.map +1 -1
  186. package/dist/core/output/command-aware.d.ts +1 -0
  187. package/dist/core/output/command-aware.js +394 -0
  188. package/dist/core/output/command-aware.js.map +1 -0
  189. package/dist/core/output/output.d.ts +3 -0
  190. package/dist/core/output/output.js +124 -6
  191. package/dist/core/output/output.js.map +1 -1
  192. package/dist/core/schema/runtime-field-filters.d.ts +3 -0
  193. package/dist/core/schema/runtime-field-filters.js +39 -0
  194. package/dist/core/schema/runtime-field-filters.js.map +1 -0
  195. package/dist/core/schema/runtime-field-values.d.ts +8 -0
  196. package/dist/core/schema/runtime-field-values.js +154 -0
  197. package/dist/core/schema/runtime-field-values.js.map +1 -0
  198. package/dist/core/schema/runtime-schema.d.ts +68 -0
  199. package/dist/core/schema/runtime-schema.js +554 -0
  200. package/dist/core/schema/runtime-schema.js.map +1 -0
  201. package/dist/core/search/cache.d.ts +13 -1
  202. package/dist/core/search/cache.js +123 -14
  203. package/dist/core/search/cache.js.map +1 -1
  204. package/dist/core/search/semantic-defaults.d.ts +6 -0
  205. package/dist/core/search/semantic-defaults.js +120 -0
  206. package/dist/core/search/semantic-defaults.js.map +1 -0
  207. package/dist/core/search/vector-stores.js +3 -1
  208. package/dist/core/search/vector-stores.js.map +1 -1
  209. package/dist/core/shared/command-types.d.ts +2 -0
  210. package/dist/core/shared/conflict-markers.d.ts +7 -0
  211. package/dist/core/shared/conflict-markers.js +27 -0
  212. package/dist/core/shared/conflict-markers.js.map +1 -0
  213. package/dist/core/shared/constants.d.ts +15 -4
  214. package/dist/core/shared/constants.js +146 -1
  215. package/dist/core/shared/constants.js.map +1 -1
  216. package/dist/core/shared/errors.d.ts +10 -1
  217. package/dist/core/shared/errors.js +3 -1
  218. package/dist/core/shared/errors.js.map +1 -1
  219. package/dist/core/shared/text-normalization.d.ts +4 -0
  220. package/dist/core/shared/text-normalization.js +33 -0
  221. package/dist/core/shared/text-normalization.js.map +1 -0
  222. package/dist/core/shared/time.d.ts +3 -2
  223. package/dist/core/shared/time.js +109 -11
  224. package/dist/core/shared/time.js.map +1 -1
  225. package/dist/core/store/index.d.ts +1 -0
  226. package/dist/core/store/index.js +1 -0
  227. package/dist/core/store/index.js.map +1 -1
  228. package/dist/core/store/item-format-migration.d.ts +9 -0
  229. package/dist/core/store/item-format-migration.js +87 -0
  230. package/dist/core/store/item-format-migration.js.map +1 -0
  231. package/dist/core/store/item-store.d.ts +13 -4
  232. package/dist/core/store/item-store.js +243 -52
  233. package/dist/core/store/item-store.js.map +1 -1
  234. package/dist/core/store/paths.d.ts +21 -3
  235. package/dist/core/store/paths.js +59 -4
  236. package/dist/core/store/paths.js.map +1 -1
  237. package/dist/core/store/settings.d.ts +14 -1
  238. package/dist/core/store/settings.js +463 -7
  239. package/dist/core/store/settings.js.map +1 -1
  240. package/dist/core/telemetry/consent.d.ts +2 -0
  241. package/dist/core/telemetry/consent.js +79 -0
  242. package/dist/core/telemetry/consent.js.map +1 -0
  243. package/dist/core/telemetry/runtime.d.ts +38 -0
  244. package/dist/core/telemetry/runtime.js +733 -0
  245. package/dist/core/telemetry/runtime.js.map +1 -0
  246. package/dist/core/test/background-runs.d.ts +117 -0
  247. package/dist/core/test/background-runs.js +760 -0
  248. package/dist/core/test/background-runs.js.map +1 -0
  249. package/dist/core/test/item-test-run-tracking.d.ts +9 -0
  250. package/dist/core/test/item-test-run-tracking.js +50 -0
  251. package/dist/core/test/item-test-run-tracking.js.map +1 -0
  252. package/dist/sdk/cli-contracts.d.ts +92 -0
  253. package/dist/sdk/cli-contracts.js +2357 -0
  254. package/dist/sdk/cli-contracts.js.map +1 -0
  255. package/dist/sdk/index.d.ts +34 -0
  256. package/dist/sdk/index.js +23 -0
  257. package/dist/sdk/index.js.map +1 -0
  258. package/dist/types.d.ts +204 -4
  259. package/dist/types.js +56 -1
  260. package/dist/types.js.map +1 -1
  261. package/docs/ARCHITECTURE.md +369 -40
  262. package/docs/EXTENSIONS.md +454 -49
  263. package/docs/RELEASING.md +68 -19
  264. package/docs/SDK.md +123 -0
  265. package/docs/examples/starter-extension/README.md +48 -0
  266. package/docs/examples/starter-extension/index.js +191 -0
  267. package/docs/examples/starter-extension/manifest.json +17 -0
  268. package/docs/examples/starter-extension/package.json +10 -0
  269. package/package.json +33 -6
  270. package/scripts/install.ps1 +2 -1
  271. package/scripts/install.sh +2 -1
  272. package/.pi/extensions/pm-cli/index.ts +0 -778
  273. package/dist/cli/commands/beads.d.ts +0 -15
  274. package/dist/cli/commands/beads.js.map +0 -1
  275. package/dist/cli/commands/install.d.ts +0 -18
  276. package/dist/cli/commands/install.js +0 -87
  277. package/dist/cli/commands/install.js.map +0 -1
  278. package/dist/core/extensions/builtins.d.ts +0 -3
  279. package/dist/core/extensions/builtins.js +0 -47
  280. package/dist/core/extensions/builtins.js.map +0 -1
  281. package/dist/extensions/builtins/beads/index.d.ts +0 -8
  282. package/dist/extensions/builtins/beads/index.js +0 -29
  283. package/dist/extensions/builtins/beads/index.js.map +0 -1
  284. package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
  285. package/dist/extensions/builtins/todos/import-export.js.map +0 -1
  286. package/dist/extensions/builtins/todos/index.d.ts +0 -8
  287. package/dist/extensions/builtins/todos/index.js +0 -38
  288. package/dist/extensions/builtins/todos/index.js.map +0 -1
@@ -0,0 +1,42 @@
1
+ {
2
+ "version": 1,
3
+ "updated_at": "2026-04-25T17:01:49.273Z",
4
+ "entries": [
5
+ {
6
+ "name": "builtin-beads-import",
7
+ "directory": "beads",
8
+ "scope": "project",
9
+ "manifest_version": "0.1.0",
10
+ "manifest_entry": "./index.js",
11
+ "capabilities": [
12
+ "commands",
13
+ "schema"
14
+ ],
15
+ "installed_at": "2026-04-25T17:01:49.268Z",
16
+ "updated_at": "2026-04-25T17:01:49.268Z",
17
+ "source": {
18
+ "kind": "local",
19
+ "input": "builtin-beads-import",
20
+ "location": "/home/steve/GITHUB_RELEASE/pm-cli/.agents/pm/extensions/beads"
21
+ }
22
+ },
23
+ {
24
+ "name": "builtin-todos-import-export",
25
+ "directory": "todos",
26
+ "scope": "project",
27
+ "manifest_version": "0.1.0",
28
+ "manifest_entry": "./index.js",
29
+ "capabilities": [
30
+ "commands",
31
+ "schema"
32
+ ],
33
+ "installed_at": "2026-04-25T17:01:49.268Z",
34
+ "updated_at": "2026-04-25T17:01:49.268Z",
35
+ "source": {
36
+ "kind": "local",
37
+ "input": "builtin-todos-import-export",
38
+ "location": "/home/steve/GITHUB_RELEASE/pm-cli/.agents/pm/extensions/todos"
39
+ }
40
+ }
41
+ ]
42
+ }
@@ -0,0 +1,109 @@
1
+ import path from "node:path";
2
+ import { pathToFileURL } from "node:url";
3
+
4
+ const PM_PACKAGE_ROOT_ENV = "PM_CLI_PACKAGE_ROOT";
5
+
6
+ export const manifest = {
7
+ name: "builtin-beads-import",
8
+ version: "0.1.0",
9
+ entry: "./index.js",
10
+ priority: 0,
11
+ capabilities: ["commands", "schema"],
12
+ };
13
+
14
+ function asOptionalString(value) {
15
+ return typeof value === "string" ? value : undefined;
16
+ }
17
+
18
+ function asBoolean(value) {
19
+ return typeof value === "boolean" ? value : undefined;
20
+ }
21
+
22
+ function toBeadsImportOptions(options) {
23
+ return {
24
+ file: asOptionalString(options.file),
25
+ author: asOptionalString(options.author),
26
+ message: asOptionalString(options.message),
27
+ preserveSourceIds: asBoolean(options.preserveSourceIds),
28
+ };
29
+ }
30
+
31
+ function resolvePackageRootCandidates() {
32
+ const candidates = [];
33
+ const envRoot = process.env[PM_PACKAGE_ROOT_ENV];
34
+ if (typeof envRoot === "string" && envRoot.trim().length > 0) {
35
+ candidates.push(path.resolve(envRoot.trim()));
36
+ }
37
+ const argvEntry = typeof process.argv[1] === "string" ? process.argv[1].trim() : "";
38
+ if (argvEntry.length > 0) {
39
+ const resolvedEntry = path.resolve(argvEntry);
40
+ const entryDir = path.dirname(resolvedEntry);
41
+ candidates.push(path.resolve(entryDir, ".."));
42
+ candidates.push(path.resolve(entryDir, "../.."));
43
+ candidates.push(path.resolve(entryDir, "../../.."));
44
+ }
45
+ return [...new Set(candidates)];
46
+ }
47
+
48
+ async function loadRuntimeModule() {
49
+ const attempted = [];
50
+ for (const packageRoot of resolvePackageRootCandidates()) {
51
+ const modulePath = path.join(packageRoot, ".agents", "pm", "extensions", "beads", "runtime.js");
52
+ attempted.push(modulePath);
53
+ try {
54
+ return await import(pathToFileURL(modulePath).href);
55
+ } catch {
56
+ // Try the next package-root candidate.
57
+ }
58
+ }
59
+ throw new Error(
60
+ "Unable to resolve bundled beads extension runtime module. " +
61
+ `Tried: ${attempted.join(", ")}. Ensure PM_CLI_PACKAGE_ROOT points to an installed pm package root.`,
62
+ );
63
+ }
64
+
65
+ async function runBeadsImportFromRuntime(options, global) {
66
+ const runtime = await loadRuntimeModule();
67
+ if (typeof runtime.runBeadsImport !== "function") {
68
+ throw new Error('Bundled beads runtime module is missing runBeadsImport().');
69
+ }
70
+ return runtime.runBeadsImport(options, global);
71
+ }
72
+
73
+ export function activate(api) {
74
+ api.registerCommand({
75
+ name: "beads import",
76
+ description: "Import Beads JSONL records into pm items.",
77
+ flags: [
78
+ {
79
+ long: "--file",
80
+ value_name: "path",
81
+ value_type: "string",
82
+ description: "Path to the Beads JSONL source file.",
83
+ },
84
+ {
85
+ long: "--author",
86
+ value_name: "author",
87
+ value_type: "string",
88
+ description: "Override import mutation author.",
89
+ },
90
+ {
91
+ long: "--message",
92
+ value_name: "text",
93
+ value_type: "string",
94
+ description: "Override import history message.",
95
+ },
96
+ {
97
+ long: "--preserve-source-ids",
98
+ value_type: "boolean",
99
+ description: "Preserve source IDs from Beads payload records when possible.",
100
+ },
101
+ ],
102
+ run: async (context) => runBeadsImportFromRuntime(toBeadsImportOptions(context.options), context.global),
103
+ });
104
+ }
105
+
106
+ export default {
107
+ manifest,
108
+ activate,
109
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "builtin-beads-import",
3
+ "version": "0.1.0",
4
+ "entry": "./index.js",
5
+ "priority": 0,
6
+ "capabilities": ["commands", "schema"]
7
+ }
@@ -1,19 +1,29 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { pathExists, removeFileIfExists, writeFileAtomic } from "../../core/fs/fs-utils.js";
4
- import { runActiveOnReadHooks, runActiveOnWriteHooks } from "../../core/extensions/index.js";
5
- import { appendHistoryEntry, createHistoryEntry } from "../../core/history/history.js";
6
- import { generateItemId, normalizeItemId } from "../../core/item/id.js";
7
- import { canonicalDocument, normalizeFrontMatter, serializeItemDocument } from "../../core/item/item-format.js";
8
- import { parseTags } from "../../core/item/parse.js";
9
- import { acquireLock } from "../../core/lock/lock.js";
10
- import { EXIT_CODE } from "../../core/shared/constants.js";
11
- import { PmCliError } from "../../core/shared/errors.js";
12
- import { nowIso } from "../../core/shared/time.js";
13
- import { getHistoryPath, getItemPath, getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
14
- import { readSettings } from "../../core/store/settings.js";
15
- import { DEPENDENCY_KIND_VALUES, STATUS_VALUES } from "../../types/index.js";
16
- const DEFAULT_BEADS_FILE = ".beads/issues.jsonl";
3
+ import { pathExists, removeFileIfExists, writeFileAtomic } from "../../../../dist/core/fs/fs-utils.js";
4
+ import { getActiveExtensionRegistrations, runActiveOnReadHooks, runActiveOnWriteHooks } from "../../../../dist/core/extensions/index.js";
5
+ import { appendHistoryEntry, createHistoryEntry } from "../../../../dist/core/history/history.js";
6
+ import { generateItemId, normalizeItemId, normalizeRawItemId } from "../../../../dist/core/item/id.js";
7
+ import { canonicalDocument, normalizeFrontMatter, serializeItemDocument } from "../../../../dist/core/item/item-format.js";
8
+ import { normalizeStatusInput } from "../../../../dist/core/item/status.js";
9
+ import { resolveItemTypeRegistry } from "../../../../dist/core/item/type-registry.js";
10
+ import { parseTags } from "../../../../dist/core/item/parse.js";
11
+ import { acquireLock } from "../../../../dist/core/lock/lock.js";
12
+ import { EXIT_CODE } from "../../../../dist/core/shared/constants.js";
13
+ import { PmCliError } from "../../../../dist/core/shared/errors.js";
14
+ import { isTimestampLiteral, nowIso } from "../../../../dist/core/shared/time.js";
15
+ import { locateItem } from "../../../../dist/core/store/item-store.js";
16
+ import { getHistoryPath, getItemPath, getSettingsPath, resolvePmRoot } from "../../../../dist/core/store/paths.js";
17
+ import { readSettings } from "../../../../dist/core/store/settings.js";
18
+ import { DEPENDENCY_KIND_VALUES } from "../../../../dist/types/index.js";
19
+ const PRIMARY_AUTO_DISCOVERY_FILES = [
20
+ ".beads/issues.jsonl",
21
+ "issues.jsonl",
22
+ ];
23
+ const UNSAFE_AUTO_DISCOVERY_FILES = [
24
+ ".beads/sync_base.jsonl",
25
+ "sync_base.jsonl",
26
+ ];
17
27
  function toNonEmptyString(value) {
18
28
  if (typeof value !== "string") {
19
29
  return undefined;
@@ -26,11 +36,10 @@ function toIsoString(value) {
26
36
  if (!raw) {
27
37
  return undefined;
28
38
  }
29
- const timestamp = Date.parse(raw);
30
- if (!Number.isFinite(timestamp)) {
39
+ if (!isTimestampLiteral(raw)) {
31
40
  return undefined;
32
41
  }
33
- return new Date(timestamp).toISOString();
42
+ return raw;
34
43
  }
35
44
  function toEstimatedMinutes(value) {
36
45
  if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
@@ -71,37 +80,75 @@ function toTags(value) {
71
80
  return [];
72
81
  }
73
82
  function toItemType(value) {
74
- const normalized = toNonEmptyString(value)?.toLowerCase();
83
+ const raw = toNonEmptyString(value);
84
+ const normalized = raw?.toLowerCase();
75
85
  switch (normalized) {
76
86
  case "epic":
77
- return "Epic";
87
+ return { type: "Epic" };
78
88
  case "feature":
79
- return "Feature";
89
+ return { type: "Feature" };
80
90
  case "task":
81
- return "Task";
91
+ return { type: "Task" };
82
92
  case "chore":
83
- return "Chore";
93
+ return { type: "Chore" };
84
94
  case "issue":
85
- return "Issue";
95
+ return { type: "Issue" };
96
+ case "bug":
97
+ return { type: "Issue", sourceType: raw };
98
+ case "event":
99
+ return { type: "Task", sourceType: raw };
86
100
  default:
87
- return "Task";
101
+ return { type: "Task", sourceType: raw };
88
102
  }
89
103
  }
90
104
  function toStatus(value) {
91
- const normalized = toNonEmptyString(value)?.toLowerCase();
92
- if (normalized && STATUS_VALUES.includes(normalized)) {
93
- return normalized;
105
+ const normalized = toNonEmptyString(value);
106
+ if (normalized) {
107
+ const canonical = normalizeStatusInput(normalized);
108
+ if (canonical) {
109
+ return canonical;
110
+ }
94
111
  }
95
112
  return "open";
96
113
  }
97
114
  function toDependencyKind(value) {
98
- const normalized = toNonEmptyString(value)?.toLowerCase();
99
- if (normalized && DEPENDENCY_KIND_VALUES.includes(normalized)) {
100
- return normalized;
115
+ const raw = toNonEmptyString(value);
116
+ const normalized = raw?.toLowerCase();
117
+ if (!normalized) {
118
+ return { kind: "related" };
119
+ }
120
+ const preserveIfChanged = (kind) => ({
121
+ kind,
122
+ sourceKind: normalized === kind ? undefined : raw,
123
+ });
124
+ if (DEPENDENCY_KIND_VALUES.includes(normalized)) {
125
+ return preserveIfChanged(normalized);
126
+ }
127
+ switch (normalized) {
128
+ case "parent-child":
129
+ return preserveIfChanged("parent_child");
130
+ case "child-of":
131
+ return preserveIfChanged("child_of");
132
+ case "related-to":
133
+ case "relates-to":
134
+ return preserveIfChanged("related_to");
135
+ case "discovered-from":
136
+ return preserveIfChanged("discovered_from");
137
+ case "blocked-by":
138
+ return preserveIfChanged("blocked_by");
139
+ case "incident-from":
140
+ return preserveIfChanged("incident_from");
141
+ default:
142
+ return {
143
+ kind: "related",
144
+ sourceKind: raw,
145
+ };
101
146
  }
102
- return "related";
103
147
  }
104
- function toDependencies(value, fallbackCreatedAt, prefix) {
148
+ function normalizeImportedId(id, prefix, preserveSourceIds) {
149
+ return preserveSourceIds ? normalizeRawItemId(id) : normalizeItemId(id, prefix);
150
+ }
151
+ function toDependencies(value, fallbackCreatedAt, prefix, preserveSourceIds) {
105
152
  if (!Array.isArray(value)) {
106
153
  return undefined;
107
154
  }
@@ -113,7 +160,7 @@ function toDependencies(value, fallbackCreatedAt, prefix) {
113
160
  continue;
114
161
  }
115
162
  dependencies.push({
116
- id: normalizeItemId(id, prefix),
163
+ id: normalizeImportedId(id, prefix, preserveSourceIds),
117
164
  kind: "related",
118
165
  created_at: fallbackCreatedAt,
119
166
  });
@@ -127,11 +174,13 @@ function toDependencies(value, fallbackCreatedAt, prefix) {
127
174
  if (!id) {
128
175
  continue;
129
176
  }
177
+ const dependencyKind = toDependencyKind(candidate.type ?? candidate.kind);
130
178
  dependencies.push({
131
- id: normalizeItemId(id, prefix),
132
- kind: toDependencyKind(candidate.kind),
179
+ id: normalizeImportedId(id, prefix, preserveSourceIds),
180
+ kind: dependencyKind.kind,
133
181
  created_at: toIsoString(candidate.created_at) ?? fallbackCreatedAt,
134
- author: toNonEmptyString(candidate.author),
182
+ author: toNonEmptyString(candidate.author) ?? toNonEmptyString(candidate.created_by),
183
+ source_kind: dependencyKind.sourceKind,
135
184
  });
136
185
  }
137
186
  return dependencies.length > 0 ? dependencies : undefined;
@@ -319,22 +368,76 @@ function emptyDocument() {
319
368
  function resolveInputPath(rawPath) {
320
369
  return path.isAbsolute(rawPath) ? rawPath : path.resolve(process.cwd(), rawPath);
321
370
  }
371
+ async function readStdin() {
372
+ if (process.stdin.isTTY === true) {
373
+ throw new PmCliError('--file value "-" requires piped stdin input. Pipe JSONL content into the command, or end manual stdin with Ctrl+D (Unix/macOS) or Ctrl+Z then Enter (Windows).', EXIT_CODE.USAGE);
374
+ }
375
+ return await new Promise((resolve, reject) => {
376
+ let raw = "";
377
+ process.stdin.setEncoding("utf8");
378
+ process.stdin.on("data", (chunk) => {
379
+ raw += chunk;
380
+ });
381
+ process.stdin.on("end", () => resolve(raw));
382
+ process.stdin.on("error", reject);
383
+ });
384
+ }
385
+ async function resolveBeadsSource(rawPath) {
386
+ const explicitSource = toNonEmptyString(rawPath);
387
+ if (explicitSource) {
388
+ if (explicitSource === "-") {
389
+ return {
390
+ source: "-",
391
+ raw: await readStdin(),
392
+ warnings: [],
393
+ };
394
+ }
395
+ const explicitPath = resolveInputPath(explicitSource);
396
+ if (!(await pathExists(explicitPath))) {
397
+ throw new PmCliError(`Beads source file not found at ${explicitPath}`, EXIT_CODE.NOT_FOUND);
398
+ }
399
+ return {
400
+ source: explicitSource,
401
+ sourcePath: explicitPath,
402
+ raw: await fs.readFile(explicitPath, "utf8"),
403
+ warnings: [],
404
+ };
405
+ }
406
+ for (const candidate of PRIMARY_AUTO_DISCOVERY_FILES) {
407
+ const candidatePath = resolveInputPath(candidate);
408
+ if (await pathExists(candidatePath)) {
409
+ return {
410
+ source: candidate,
411
+ sourcePath: candidatePath,
412
+ raw: await fs.readFile(candidatePath, "utf8"),
413
+ warnings: candidate === PRIMARY_AUTO_DISCOVERY_FILES[0] ? [] : [`beads_import_source_autodiscovered:${candidate}`],
414
+ };
415
+ }
416
+ }
417
+ for (const candidate of UNSAFE_AUTO_DISCOVERY_FILES) {
418
+ const candidatePath = resolveInputPath(candidate);
419
+ if (await pathExists(candidatePath)) {
420
+ throw new PmCliError(`Beads auto-discovery found ${candidatePath}, but sync_base snapshots may be partial. Export a full Beads JSONL file and pass --file <path> (or --file - for stdin).`, EXIT_CODE.NOT_FOUND);
421
+ }
422
+ }
423
+ throw new PmCliError(`Beads source file not found. Checked ${PRIMARY_AUTO_DISCOVERY_FILES.join(", ")}. Use --file <path> or --file - for stdin.`, EXIT_CODE.NOT_FOUND);
424
+ }
322
425
  export async function runBeadsImport(options, global) {
323
426
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
324
427
  await ensureInitHasRun(pmRoot);
325
428
  const settings = await readSettings(pmRoot);
326
- const source = toNonEmptyString(options.file) ?? DEFAULT_BEADS_FILE;
327
- const sourcePath = resolveInputPath(source);
328
- if (!(await pathExists(sourcePath))) {
329
- throw new PmCliError(`Beads source file not found at ${sourcePath}`, EXIT_CODE.NOT_FOUND);
330
- }
331
- const raw = await fs.readFile(sourcePath, "utf8");
429
+ const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
430
+ const preserveSourceIds = options.preserveSourceIds === true;
431
+ const { source, sourcePath, raw, warnings: sourceWarnings } = await resolveBeadsSource(options.file);
332
432
  const warnings = [
333
- ...(await runActiveOnReadHooks({
433
+ ...sourceWarnings,
434
+ ];
435
+ if (sourcePath) {
436
+ warnings.push(...(await runActiveOnReadHooks({
334
437
  path: sourcePath,
335
438
  scope: "project",
336
- })),
337
- ];
439
+ })));
440
+ }
338
441
  const lines = raw.split(/\r?\n/);
339
442
  const author = selectAuthor(toNonEmptyString(options.author), settings.author_default);
340
443
  const message = toNonEmptyString(options.message) ?? "Import from Beads JSONL";
@@ -371,26 +474,34 @@ export async function runBeadsImport(options, global) {
371
474
  const createdAt = toIsoString(record.created_at) ?? nowIso();
372
475
  const updatedAt = toIsoString(record.updated_at) ?? createdAt;
373
476
  const id = toNonEmptyString(record.id)
374
- ? normalizeItemId(toNonEmptyString(record.id), settings.id_prefix)
477
+ ? normalizeImportedId(toNonEmptyString(record.id), settings.id_prefix, preserveSourceIds)
375
478
  : await generateItemId(pmRoot, settings.id_prefix);
376
- const type = toItemType(record.issue_type ?? record.type);
479
+ const typeMapping = toItemType(record.issue_type ?? record.type);
480
+ const type = typeMapping.type;
481
+ const closedAt = toIsoString(record.closed_at);
482
+ const assignee = toNonEmptyString(record.assignee) ?? toNonEmptyString(record.owner);
377
483
  const frontMatter = normalizeFrontMatter({
378
484
  id,
379
485
  title,
380
486
  description: toNonEmptyString(record.description) ?? "",
381
487
  type,
488
+ source_type: typeMapping.sourceType,
382
489
  status: toStatus(record.status),
383
490
  priority: toPriority(record.priority),
384
491
  tags: toTags(record.tags ?? record.labels),
385
492
  created_at: createdAt,
386
493
  updated_at: updatedAt,
387
- deadline: toIsoString(record.deadline),
388
- assignee: toNonEmptyString(record.assignee),
494
+ deadline: toIsoString(record.due_at ?? record.deadline),
495
+ closed_at: closedAt,
496
+ assignee,
497
+ source_owner: toNonEmptyString(record.owner),
389
498
  author: toNonEmptyString(record.author) ?? toNonEmptyString(record.created_by) ?? author,
390
499
  estimated_minutes: toEstimatedMinutes(record.estimated_minutes),
391
500
  acceptance_criteria: toNonEmptyString(record.acceptance_criteria),
392
- close_reason: toNonEmptyString(record.close_reason) ?? (toIsoString(record.closed_at) ? `Closed at ${toIsoString(record.closed_at)}` : undefined),
393
- dependencies: toDependencies(record.dependencies, createdAt, settings.id_prefix),
501
+ design: toNonEmptyString(record.design),
502
+ external_ref: toNonEmptyString(record.external_ref),
503
+ close_reason: toNonEmptyString(record.close_reason),
504
+ dependencies: toDependencies(record.dependencies, createdAt, settings.id_prefix, preserveSourceIds),
394
505
  comments: toLogEntries(record.comments, createdAt, author),
395
506
  notes: toLogEntries(record.notes, createdAt, author),
396
507
  learnings: toLogEntries(record.learnings, createdAt, author),
@@ -412,17 +523,18 @@ export async function runBeadsImport(options, global) {
412
523
  front_matter: frontMatter,
413
524
  body: finalBody,
414
525
  });
415
- const itemPath = getItemPath(pmRoot, type, id);
416
- if (await pathExists(itemPath)) {
526
+ const existing = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
527
+ if (existing) {
417
528
  warnings.push(`beads_import_item_exists:${id}`);
418
529
  skipped += 1;
419
530
  continue;
420
531
  }
532
+ const itemPath = getItemPath(pmRoot, type, id, settings.item_format, typeRegistry.type_to_folder);
421
533
  const historyPath = getHistoryPath(pmRoot, id);
422
534
  try {
423
535
  const releaseLock = await acquireLock(pmRoot, id, settings.locks.ttl_seconds, author);
424
536
  try {
425
- await writeFileAtomic(itemPath, serializeItemDocument(afterDocument));
537
+ await writeFileAtomic(itemPath, serializeItemDocument(afterDocument, { format: settings.item_format }));
426
538
  try {
427
539
  const entry = createHistoryEntry({
428
540
  nowIso: nowIso(),
@@ -471,5 +583,4 @@ export async function runBeadsImport(options, global) {
471
583
  ids,
472
584
  warnings,
473
585
  };
474
- }
475
- //# sourceMappingURL=beads.js.map
586
+ }