@unbrained/pm-cli 2026.3.9

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 (245) hide show
  1. package/.pi/extensions/pm-cli/index.ts +778 -0
  2. package/AGENTS.md +475 -0
  3. package/LICENSE +21 -0
  4. package/PRD.md +1390 -0
  5. package/README.md +655 -0
  6. package/dist/cli/commands/activity.d.ts +14 -0
  7. package/dist/cli/commands/activity.js +80 -0
  8. package/dist/cli/commands/activity.js.map +1 -0
  9. package/dist/cli/commands/append.d.ts +13 -0
  10. package/dist/cli/commands/append.js +46 -0
  11. package/dist/cli/commands/append.js.map +1 -0
  12. package/dist/cli/commands/beads.d.ts +15 -0
  13. package/dist/cli/commands/beads.js +475 -0
  14. package/dist/cli/commands/beads.js.map +1 -0
  15. package/dist/cli/commands/claim.d.ts +19 -0
  16. package/dist/cli/commands/claim.js +79 -0
  17. package/dist/cli/commands/claim.js.map +1 -0
  18. package/dist/cli/commands/close.d.ts +12 -0
  19. package/dist/cli/commands/close.js +58 -0
  20. package/dist/cli/commands/close.js.map +1 -0
  21. package/dist/cli/commands/comments.d.ts +15 -0
  22. package/dist/cli/commands/comments.js +80 -0
  23. package/dist/cli/commands/comments.js.map +1 -0
  24. package/dist/cli/commands/completion.d.ts +10 -0
  25. package/dist/cli/commands/completion.js +469 -0
  26. package/dist/cli/commands/completion.js.map +1 -0
  27. package/dist/cli/commands/config.d.ts +15 -0
  28. package/dist/cli/commands/config.js +72 -0
  29. package/dist/cli/commands/config.js.map +1 -0
  30. package/dist/cli/commands/create.d.ts +60 -0
  31. package/dist/cli/commands/create.js +456 -0
  32. package/dist/cli/commands/create.js.map +1 -0
  33. package/dist/cli/commands/delete.d.ts +12 -0
  34. package/dist/cli/commands/delete.js +33 -0
  35. package/dist/cli/commands/delete.js.map +1 -0
  36. package/dist/cli/commands/docs.d.ts +16 -0
  37. package/dist/cli/commands/docs.js +113 -0
  38. package/dist/cli/commands/docs.js.map +1 -0
  39. package/dist/cli/commands/files.d.ts +17 -0
  40. package/dist/cli/commands/files.js +113 -0
  41. package/dist/cli/commands/files.js.map +1 -0
  42. package/dist/cli/commands/gc.d.ts +9 -0
  43. package/dist/cli/commands/gc.js +80 -0
  44. package/dist/cli/commands/gc.js.map +1 -0
  45. package/dist/cli/commands/get.d.ts +12 -0
  46. package/dist/cli/commands/get.js +28 -0
  47. package/dist/cli/commands/get.js.map +1 -0
  48. package/dist/cli/commands/health.d.ts +15 -0
  49. package/dist/cli/commands/health.js +288 -0
  50. package/dist/cli/commands/health.js.map +1 -0
  51. package/dist/cli/commands/history.d.ts +13 -0
  52. package/dist/cli/commands/history.js +72 -0
  53. package/dist/cli/commands/history.js.map +1 -0
  54. package/dist/cli/commands/index.d.ts +26 -0
  55. package/dist/cli/commands/index.js +27 -0
  56. package/dist/cli/commands/index.js.map +1 -0
  57. package/dist/cli/commands/init.d.ts +10 -0
  58. package/dist/cli/commands/init.js +59 -0
  59. package/dist/cli/commands/init.js.map +1 -0
  60. package/dist/cli/commands/install.d.ts +18 -0
  61. package/dist/cli/commands/install.js +87 -0
  62. package/dist/cli/commands/install.js.map +1 -0
  63. package/dist/cli/commands/list.d.ts +21 -0
  64. package/dist/cli/commands/list.js +137 -0
  65. package/dist/cli/commands/list.js.map +1 -0
  66. package/dist/cli/commands/reindex.d.ts +16 -0
  67. package/dist/cli/commands/reindex.js +154 -0
  68. package/dist/cli/commands/reindex.js.map +1 -0
  69. package/dist/cli/commands/restore.d.ts +20 -0
  70. package/dist/cli/commands/restore.js +208 -0
  71. package/dist/cli/commands/restore.js.map +1 -0
  72. package/dist/cli/commands/search.d.ts +45 -0
  73. package/dist/cli/commands/search.js +531 -0
  74. package/dist/cli/commands/search.js.map +1 -0
  75. package/dist/cli/commands/stats.d.ts +13 -0
  76. package/dist/cli/commands/stats.js +88 -0
  77. package/dist/cli/commands/stats.js.map +1 -0
  78. package/dist/cli/commands/test-all.d.ts +30 -0
  79. package/dist/cli/commands/test-all.js +157 -0
  80. package/dist/cli/commands/test-all.js.map +1 -0
  81. package/dist/cli/commands/test.d.ts +29 -0
  82. package/dist/cli/commands/test.js +492 -0
  83. package/dist/cli/commands/test.js.map +1 -0
  84. package/dist/cli/commands/update.d.ts +52 -0
  85. package/dist/cli/commands/update.js +467 -0
  86. package/dist/cli/commands/update.js.map +1 -0
  87. package/dist/cli/extension-command-options.d.ts +1 -0
  88. package/dist/cli/extension-command-options.js +76 -0
  89. package/dist/cli/extension-command-options.js.map +1 -0
  90. package/dist/cli/main.d.ts +2 -0
  91. package/dist/cli/main.js +1494 -0
  92. package/dist/cli/main.js.map +1 -0
  93. package/dist/cli.d.ts +2 -0
  94. package/dist/cli.js +3 -0
  95. package/dist/cli.js.map +1 -0
  96. package/dist/command-types.d.ts +1 -0
  97. package/dist/command-types.js +2 -0
  98. package/dist/command-types.js.map +1 -0
  99. package/dist/constants.d.ts +1 -0
  100. package/dist/constants.js +2 -0
  101. package/dist/constants.js.map +1 -0
  102. package/dist/core/extensions/builtins.d.ts +3 -0
  103. package/dist/core/extensions/builtins.js +47 -0
  104. package/dist/core/extensions/builtins.js.map +1 -0
  105. package/dist/core/extensions/index.d.ts +13 -0
  106. package/dist/core/extensions/index.js +88 -0
  107. package/dist/core/extensions/index.js.map +1 -0
  108. package/dist/core/extensions/loader.d.ts +301 -0
  109. package/dist/core/extensions/loader.js +917 -0
  110. package/dist/core/extensions/loader.js.map +1 -0
  111. package/dist/core/fs/fs-utils.d.ts +6 -0
  112. package/dist/core/fs/fs-utils.js +58 -0
  113. package/dist/core/fs/fs-utils.js.map +1 -0
  114. package/dist/core/fs/index.d.ts +1 -0
  115. package/dist/core/fs/index.js +2 -0
  116. package/dist/core/fs/index.js.map +1 -0
  117. package/dist/core/history/history.d.ts +12 -0
  118. package/dist/core/history/history.js +44 -0
  119. package/dist/core/history/history.js.map +1 -0
  120. package/dist/core/history/index.d.ts +1 -0
  121. package/dist/core/history/index.js +2 -0
  122. package/dist/core/history/index.js.map +1 -0
  123. package/dist/core/item/id.d.ts +3 -0
  124. package/dist/core/item/id.js +54 -0
  125. package/dist/core/item/id.js.map +1 -0
  126. package/dist/core/item/index.d.ts +3 -0
  127. package/dist/core/item/index.js +4 -0
  128. package/dist/core/item/index.js.map +1 -0
  129. package/dist/core/item/item-format.d.ts +9 -0
  130. package/dist/core/item/item-format.js +363 -0
  131. package/dist/core/item/item-format.js.map +1 -0
  132. package/dist/core/item/parse.d.ts +3 -0
  133. package/dist/core/item/parse.js +72 -0
  134. package/dist/core/item/parse.js.map +1 -0
  135. package/dist/core/lock/index.d.ts +1 -0
  136. package/dist/core/lock/index.js +2 -0
  137. package/dist/core/lock/index.js.map +1 -0
  138. package/dist/core/lock/lock.d.ts +1 -0
  139. package/dist/core/lock/lock.js +100 -0
  140. package/dist/core/lock/lock.js.map +1 -0
  141. package/dist/core/output/output.d.ts +7 -0
  142. package/dist/core/output/output.js +79 -0
  143. package/dist/core/output/output.js.map +1 -0
  144. package/dist/core/search/cache.d.ts +17 -0
  145. package/dist/core/search/cache.js +212 -0
  146. package/dist/core/search/cache.js.map +1 -0
  147. package/dist/core/search/embedding-batches.d.ts +7 -0
  148. package/dist/core/search/embedding-batches.js +54 -0
  149. package/dist/core/search/embedding-batches.js.map +1 -0
  150. package/dist/core/search/providers.d.ts +59 -0
  151. package/dist/core/search/providers.js +265 -0
  152. package/dist/core/search/providers.js.map +1 -0
  153. package/dist/core/search/vector-stores.d.ts +89 -0
  154. package/dist/core/search/vector-stores.js +546 -0
  155. package/dist/core/search/vector-stores.js.map +1 -0
  156. package/dist/core/shared/command-types.d.ts +7 -0
  157. package/dist/core/shared/command-types.js +2 -0
  158. package/dist/core/shared/command-types.js.map +1 -0
  159. package/dist/core/shared/constants.d.ts +19 -0
  160. package/dist/core/shared/constants.js +134 -0
  161. package/dist/core/shared/constants.js.map +1 -0
  162. package/dist/core/shared/errors.d.ts +4 -0
  163. package/dist/core/shared/errors.js +9 -0
  164. package/dist/core/shared/errors.js.map +1 -0
  165. package/dist/core/shared/index.d.ts +3 -0
  166. package/dist/core/shared/index.js +4 -0
  167. package/dist/core/shared/index.js.map +1 -0
  168. package/dist/core/shared/serialization.d.ts +3 -0
  169. package/dist/core/shared/serialization.js +70 -0
  170. package/dist/core/shared/serialization.js.map +1 -0
  171. package/dist/core/shared/time.d.ts +3 -0
  172. package/dist/core/shared/time.js +28 -0
  173. package/dist/core/shared/time.js.map +1 -0
  174. package/dist/core/store/index.d.ts +3 -0
  175. package/dist/core/store/index.js +4 -0
  176. package/dist/core/store/index.js.map +1 -0
  177. package/dist/core/store/item-store.d.ts +42 -0
  178. package/dist/core/store/item-store.js +186 -0
  179. package/dist/core/store/item-store.js.map +1 -0
  180. package/dist/core/store/paths.d.ts +8 -0
  181. package/dist/core/store/paths.js +29 -0
  182. package/dist/core/store/paths.js.map +1 -0
  183. package/dist/core/store/settings.d.ts +4 -0
  184. package/dist/core/store/settings.js +148 -0
  185. package/dist/core/store/settings.js.map +1 -0
  186. package/dist/errors.d.ts +1 -0
  187. package/dist/errors.js +2 -0
  188. package/dist/errors.js.map +1 -0
  189. package/dist/extensions/builtins/beads/index.d.ts +8 -0
  190. package/dist/extensions/builtins/beads/index.js +29 -0
  191. package/dist/extensions/builtins/beads/index.js.map +1 -0
  192. package/dist/extensions/builtins/todos/import-export.d.ts +26 -0
  193. package/dist/extensions/builtins/todos/import-export.js +460 -0
  194. package/dist/extensions/builtins/todos/import-export.js.map +1 -0
  195. package/dist/extensions/builtins/todos/index.d.ts +8 -0
  196. package/dist/extensions/builtins/todos/index.js +38 -0
  197. package/dist/extensions/builtins/todos/index.js.map +1 -0
  198. package/dist/fs-utils.d.ts +1 -0
  199. package/dist/fs-utils.js +2 -0
  200. package/dist/fs-utils.js.map +1 -0
  201. package/dist/history.d.ts +1 -0
  202. package/dist/history.js +2 -0
  203. package/dist/history.js.map +1 -0
  204. package/dist/id.d.ts +1 -0
  205. package/dist/id.js +2 -0
  206. package/dist/id.js.map +1 -0
  207. package/dist/item-format.d.ts +1 -0
  208. package/dist/item-format.js +2 -0
  209. package/dist/item-format.js.map +1 -0
  210. package/dist/item-store.d.ts +1 -0
  211. package/dist/item-store.js +2 -0
  212. package/dist/item-store.js.map +1 -0
  213. package/dist/lock.d.ts +1 -0
  214. package/dist/lock.js +2 -0
  215. package/dist/lock.js.map +1 -0
  216. package/dist/output.d.ts +1 -0
  217. package/dist/output.js +2 -0
  218. package/dist/output.js.map +1 -0
  219. package/dist/parse.d.ts +1 -0
  220. package/dist/parse.js +2 -0
  221. package/dist/parse.js.map +1 -0
  222. package/dist/paths.d.ts +1 -0
  223. package/dist/paths.js +2 -0
  224. package/dist/paths.js.map +1 -0
  225. package/dist/serialization.d.ts +1 -0
  226. package/dist/serialization.js +2 -0
  227. package/dist/serialization.js.map +1 -0
  228. package/dist/settings.d.ts +1 -0
  229. package/dist/settings.js +2 -0
  230. package/dist/settings.js.map +1 -0
  231. package/dist/time.d.ts +1 -0
  232. package/dist/time.js +2 -0
  233. package/dist/time.js.map +1 -0
  234. package/dist/types/index.d.ts +1 -0
  235. package/dist/types/index.js +2 -0
  236. package/dist/types/index.js.map +1 -0
  237. package/dist/types.d.ts +179 -0
  238. package/dist/types.js +21 -0
  239. package/dist/types.js.map +1 -0
  240. package/docs/ARCHITECTURE.md +246 -0
  241. package/docs/EXTENSIONS.md +329 -0
  242. package/docs/RELEASING.md +65 -0
  243. package/package.json +79 -0
  244. package/scripts/install.ps1 +112 -0
  245. package/scripts/install.sh +113 -0
@@ -0,0 +1,80 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { pathExists } from "../../core/fs/fs-utils.js";
4
+ import { runActiveOnReadHooks } from "../../core/extensions/index.js";
5
+ import { EXIT_CODE } from "../../core/shared/constants.js";
6
+ import { PmCliError } from "../../core/shared/errors.js";
7
+ import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
8
+ import { readSettings } from "../../core/store/settings.js";
9
+ import { readHistoryEntries } from "./history.js";
10
+ function parseLimit(raw) {
11
+ if (raw === undefined)
12
+ return undefined;
13
+ const parsed = Number(raw);
14
+ if (!Number.isFinite(parsed) || parsed < 0) {
15
+ throw new PmCliError("Invalid --limit value", EXIT_CODE.USAGE);
16
+ }
17
+ return Math.floor(parsed);
18
+ }
19
+ function limitEntries(values, limit) {
20
+ if (limit === undefined)
21
+ return values;
22
+ return values.slice(0, limit);
23
+ }
24
+ function sortActivity(entries) {
25
+ return [...entries].sort((a, b) => {
26
+ const byTimestamp = b.ts.localeCompare(a.ts);
27
+ if (byTimestamp !== 0)
28
+ return byTimestamp;
29
+ const byId = a.id.localeCompare(b.id);
30
+ if (byId !== 0)
31
+ return byId;
32
+ return a.op.localeCompare(b.op);
33
+ });
34
+ }
35
+ async function listHistoryFiles(historyDir) {
36
+ try {
37
+ return (await fs.readdir(historyDir))
38
+ .filter((entry) => entry.endsWith(".jsonl"))
39
+ .sort((a, b) => a.localeCompare(b));
40
+ }
41
+ catch (error) {
42
+ // Activity should degrade gracefully when optional history storage is absent.
43
+ if (error.code === "ENOENT") {
44
+ return [];
45
+ }
46
+ throw error;
47
+ }
48
+ }
49
+ export async function runActivity(options, global) {
50
+ const pmRoot = resolvePmRoot(process.cwd(), global.path);
51
+ if (!(await pathExists(getSettingsPath(pmRoot)))) {
52
+ throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
53
+ }
54
+ const limit = parseLimit(options.limit);
55
+ await readSettings(pmRoot);
56
+ const historyDir = path.join(pmRoot, "history");
57
+ await runActiveOnReadHooks({
58
+ path: historyDir,
59
+ scope: "project",
60
+ });
61
+ const historyFiles = await listHistoryFiles(historyDir);
62
+ const combined = [];
63
+ for (const file of historyFiles) {
64
+ const id = file.slice(0, -".jsonl".length);
65
+ const entries = await readHistoryEntries(path.join(historyDir, file), id);
66
+ for (const entry of entries) {
67
+ combined.push({
68
+ id,
69
+ ...entry,
70
+ });
71
+ }
72
+ }
73
+ const activity = limitEntries(sortActivity(combined), limit);
74
+ return {
75
+ activity,
76
+ count: activity.length,
77
+ limit: limit ?? null,
78
+ };
79
+ }
80
+ //# sourceMappingURL=activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.js","sourceRoot":"","sources":["../../../src/cli/commands/activity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { GlobalOptions } from "../../core/shared/command-types.js";
2
+ export interface AppendCommandOptions {
3
+ body: string;
4
+ author?: string;
5
+ message?: string;
6
+ force?: boolean;
7
+ }
8
+ export interface AppendResult {
9
+ item: Record<string, unknown>;
10
+ appended: string;
11
+ changed_fields: string[];
12
+ }
13
+ export declare function runAppend(id: string, options: AppendCommandOptions, global: GlobalOptions): Promise<AppendResult>;
@@ -0,0 +1,46 @@
1
+ import { pathExists } from "../../core/fs/fs-utils.js";
2
+ import { EXIT_CODE } from "../../core/shared/constants.js";
3
+ import { PmCliError } from "../../core/shared/errors.js";
4
+ import { mutateItem } from "../../core/store/item-store.js";
5
+ import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
6
+ import { readSettings } from "../../core/store/settings.js";
7
+ function resolveAuthor(candidate, defaultAuthor) {
8
+ const resolved = candidate ?? process.env.PM_AUTHOR ?? defaultAuthor;
9
+ const trimmed = resolved.trim();
10
+ return trimmed || "unknown";
11
+ }
12
+ export async function runAppend(id, options, global) {
13
+ if (options.body === undefined) {
14
+ throw new PmCliError("Missing required --body text", EXIT_CODE.USAGE);
15
+ }
16
+ const pmRoot = resolvePmRoot(process.cwd(), global.path);
17
+ if (!(await pathExists(getSettingsPath(pmRoot)))) {
18
+ throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
19
+ }
20
+ const settings = await readSettings(pmRoot);
21
+ const author = resolveAuthor(options.author, settings.author_default);
22
+ const appended = options.body.trim();
23
+ const result = await mutateItem({
24
+ pmRoot,
25
+ settings,
26
+ id,
27
+ op: "append",
28
+ author,
29
+ message: options.message,
30
+ force: options.force,
31
+ mutate(document) {
32
+ if (appended.length === 0) {
33
+ return { changedFields: [] };
34
+ }
35
+ const spacer = document.body.trim().length > 0 ? "\n\n" : "";
36
+ document.body = `${document.body.replace(/\s+$/, "")}${spacer}${appended}\n`;
37
+ return { changedFields: ["body"] };
38
+ },
39
+ });
40
+ return {
41
+ item: result.item,
42
+ appended: appended.length > 0 ? appended : "",
43
+ changed_fields: result.changedFields,
44
+ };
45
+ }
46
+ //# sourceMappingURL=append.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"append.js","sourceRoot":"","sources":["../../../src/cli/commands/append.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAe5D,SAAS,aAAa,CAAC,SAA6B,EAAE,aAAqB;IACzE,MAAM,QAAQ,GAAG,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,aAAa,CAAC;IACrE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChC,OAAO,OAAO,IAAI,SAAS,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAU,EAAE,OAA6B,EAAE,MAAqB;IAC9F,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,UAAU,CAAC,8BAA8B,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,UAAU,CAAC,iCAAiC,MAAM,sBAAsB,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC3G,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAErC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC;QAC9B,MAAM;QACN,QAAQ;QACR,EAAE;QACF,EAAE,EAAE,QAAQ;QACZ,MAAM;QACN,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,CAAC,QAAQ;YACb,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;YAC/B,CAAC;YACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,QAAQ,CAAC,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,QAAQ,IAAI,CAAC;YAC7E,OAAO,EAAE,aAAa,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;QACrC,CAAC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAA0C;QACvD,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;QAC7C,cAAc,EAAE,MAAM,CAAC,aAAa;KACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { GlobalOptions } from "../../core/shared/command-types.js";
2
+ export interface BeadsImportOptions {
3
+ file?: string;
4
+ author?: string;
5
+ message?: string;
6
+ }
7
+ export interface BeadsImportResult {
8
+ ok: boolean;
9
+ source: string;
10
+ imported: number;
11
+ skipped: number;
12
+ ids: string[];
13
+ warnings: string[];
14
+ }
15
+ export declare function runBeadsImport(options: BeadsImportOptions, global: GlobalOptions): Promise<BeadsImportResult>;
@@ -0,0 +1,475 @@
1
+ import fs from "node:fs/promises";
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";
17
+ function toNonEmptyString(value) {
18
+ if (typeof value !== "string") {
19
+ return undefined;
20
+ }
21
+ const trimmed = value.trim();
22
+ return trimmed.length > 0 ? trimmed : undefined;
23
+ }
24
+ function toIsoString(value) {
25
+ const raw = toNonEmptyString(value);
26
+ if (!raw) {
27
+ return undefined;
28
+ }
29
+ const timestamp = Date.parse(raw);
30
+ if (!Number.isFinite(timestamp)) {
31
+ return undefined;
32
+ }
33
+ return new Date(timestamp).toISOString();
34
+ }
35
+ function toEstimatedMinutes(value) {
36
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
37
+ return value;
38
+ }
39
+ if (typeof value === "string" && value.trim().length > 0) {
40
+ const parsed = Number(value);
41
+ if (Number.isFinite(parsed) && parsed >= 0) {
42
+ return parsed;
43
+ }
44
+ }
45
+ return undefined;
46
+ }
47
+ function toPriority(value) {
48
+ const fallback = 2;
49
+ if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 4) {
50
+ return value;
51
+ }
52
+ if (typeof value === "string" && value.trim().length > 0) {
53
+ const parsed = Number(value);
54
+ if (Number.isInteger(parsed) && parsed >= 0 && parsed <= 4) {
55
+ return parsed;
56
+ }
57
+ }
58
+ return fallback;
59
+ }
60
+ function toTags(value) {
61
+ if (Array.isArray(value)) {
62
+ const tags = value
63
+ .filter((entry) => typeof entry === "string")
64
+ .map((entry) => entry.trim().toLowerCase())
65
+ .filter((entry) => entry.length > 0);
66
+ return Array.from(new Set(tags)).sort((left, right) => left.localeCompare(right));
67
+ }
68
+ if (typeof value === "string") {
69
+ return parseTags(value);
70
+ }
71
+ return [];
72
+ }
73
+ function toItemType(value) {
74
+ const normalized = toNonEmptyString(value)?.toLowerCase();
75
+ switch (normalized) {
76
+ case "epic":
77
+ return "Epic";
78
+ case "feature":
79
+ return "Feature";
80
+ case "task":
81
+ return "Task";
82
+ case "chore":
83
+ return "Chore";
84
+ case "issue":
85
+ return "Issue";
86
+ default:
87
+ return "Task";
88
+ }
89
+ }
90
+ function toStatus(value) {
91
+ const normalized = toNonEmptyString(value)?.toLowerCase();
92
+ if (normalized && STATUS_VALUES.includes(normalized)) {
93
+ return normalized;
94
+ }
95
+ return "open";
96
+ }
97
+ function toDependencyKind(value) {
98
+ const normalized = toNonEmptyString(value)?.toLowerCase();
99
+ if (normalized && DEPENDENCY_KIND_VALUES.includes(normalized)) {
100
+ return normalized;
101
+ }
102
+ return "related";
103
+ }
104
+ function toDependencies(value, fallbackCreatedAt, prefix) {
105
+ if (!Array.isArray(value)) {
106
+ return undefined;
107
+ }
108
+ const dependencies = [];
109
+ for (const entry of value) {
110
+ if (typeof entry === "string") {
111
+ const id = toNonEmptyString(entry);
112
+ if (!id) {
113
+ continue;
114
+ }
115
+ dependencies.push({
116
+ id: normalizeItemId(id, prefix),
117
+ kind: "related",
118
+ created_at: fallbackCreatedAt,
119
+ });
120
+ continue;
121
+ }
122
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
123
+ continue;
124
+ }
125
+ const candidate = entry;
126
+ const id = toNonEmptyString(candidate.id) ?? toNonEmptyString(candidate.item_id) ?? toNonEmptyString(candidate.depends_on_id);
127
+ if (!id) {
128
+ continue;
129
+ }
130
+ dependencies.push({
131
+ id: normalizeItemId(id, prefix),
132
+ kind: toDependencyKind(candidate.kind),
133
+ created_at: toIsoString(candidate.created_at) ?? fallbackCreatedAt,
134
+ author: toNonEmptyString(candidate.author),
135
+ });
136
+ }
137
+ return dependencies.length > 0 ? dependencies : undefined;
138
+ }
139
+ function toLogEntries(value, fallbackCreatedAt, fallbackAuthor) {
140
+ if (typeof value === "string") {
141
+ const text = toNonEmptyString(value);
142
+ if (!text) {
143
+ return undefined;
144
+ }
145
+ return [
146
+ {
147
+ created_at: fallbackCreatedAt,
148
+ author: fallbackAuthor,
149
+ text,
150
+ },
151
+ ];
152
+ }
153
+ if (!Array.isArray(value)) {
154
+ return undefined;
155
+ }
156
+ const entries = [];
157
+ for (const entry of value) {
158
+ if (typeof entry === "string") {
159
+ const text = toNonEmptyString(entry);
160
+ if (!text) {
161
+ continue;
162
+ }
163
+ entries.push({
164
+ created_at: fallbackCreatedAt,
165
+ author: fallbackAuthor,
166
+ text,
167
+ });
168
+ continue;
169
+ }
170
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
171
+ continue;
172
+ }
173
+ const candidate = entry;
174
+ const text = toNonEmptyString(candidate.text) ??
175
+ toNonEmptyString(candidate.comment) ??
176
+ toNonEmptyString(candidate.note) ??
177
+ toNonEmptyString(candidate.learning);
178
+ if (!text) {
179
+ continue;
180
+ }
181
+ entries.push({
182
+ created_at: toIsoString(candidate.created_at) ?? fallbackCreatedAt,
183
+ author: toNonEmptyString(candidate.author) ?? fallbackAuthor,
184
+ text,
185
+ });
186
+ }
187
+ return entries.length > 0 ? entries : undefined;
188
+ }
189
+ function toLinkedFiles(value) {
190
+ if (typeof value === "string") {
191
+ const p = toNonEmptyString(value);
192
+ if (!p)
193
+ return undefined;
194
+ return [{ path: p, scope: "project" }];
195
+ }
196
+ if (!Array.isArray(value)) {
197
+ return undefined;
198
+ }
199
+ const files = [];
200
+ for (const entry of value) {
201
+ if (typeof entry === "string") {
202
+ const p = toNonEmptyString(entry);
203
+ if (p)
204
+ files.push({ path: p, scope: "project" });
205
+ continue;
206
+ }
207
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
208
+ continue;
209
+ }
210
+ const candidate = entry;
211
+ const p = toNonEmptyString(candidate.path) ?? toNonEmptyString(candidate.file);
212
+ if (!p)
213
+ continue;
214
+ files.push({
215
+ path: p,
216
+ scope: toNonEmptyString(candidate.scope) === "global" ? "global" : "project",
217
+ note: toNonEmptyString(candidate.note),
218
+ });
219
+ }
220
+ return files.length > 0 ? files : undefined;
221
+ }
222
+ function toLinkedTests(value) {
223
+ if (typeof value === "string") {
224
+ const c = toNonEmptyString(value);
225
+ if (!c)
226
+ return undefined;
227
+ return [{ command: c, scope: "project" }];
228
+ }
229
+ if (!Array.isArray(value)) {
230
+ return undefined;
231
+ }
232
+ const tests = [];
233
+ for (const entry of value) {
234
+ if (typeof entry === "string") {
235
+ const c = toNonEmptyString(entry);
236
+ if (c)
237
+ tests.push({ command: c, scope: "project" });
238
+ continue;
239
+ }
240
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
241
+ continue;
242
+ }
243
+ const candidate = entry;
244
+ const command = toNonEmptyString(candidate.command) ?? toNonEmptyString(candidate.test);
245
+ const p = toNonEmptyString(candidate.path);
246
+ if (!command && !p)
247
+ continue;
248
+ let timeout;
249
+ if (typeof candidate.timeout_seconds === "number" && Number.isFinite(candidate.timeout_seconds)) {
250
+ timeout = candidate.timeout_seconds;
251
+ }
252
+ else if (typeof candidate.timeout_seconds === "string") {
253
+ const parsed = Number(candidate.timeout_seconds);
254
+ if (Number.isFinite(parsed) && parsed >= 0) {
255
+ timeout = parsed;
256
+ }
257
+ }
258
+ tests.push({
259
+ command,
260
+ path: p,
261
+ scope: toNonEmptyString(candidate.scope) === "global" ? "global" : "project",
262
+ timeout_seconds: timeout,
263
+ note: toNonEmptyString(candidate.note),
264
+ });
265
+ }
266
+ return tests.length > 0 ? tests : undefined;
267
+ }
268
+ function toLinkedDocs(value) {
269
+ if (typeof value === "string") {
270
+ const p = toNonEmptyString(value);
271
+ if (!p)
272
+ return undefined;
273
+ return [{ path: p, scope: "project" }];
274
+ }
275
+ if (!Array.isArray(value)) {
276
+ return undefined;
277
+ }
278
+ const docs = [];
279
+ for (const entry of value) {
280
+ if (typeof entry === "string") {
281
+ const p = toNonEmptyString(entry);
282
+ if (p)
283
+ docs.push({ path: p, scope: "project" });
284
+ continue;
285
+ }
286
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
287
+ continue;
288
+ }
289
+ const candidate = entry;
290
+ const p = toNonEmptyString(candidate.path) ?? toNonEmptyString(candidate.doc);
291
+ if (!p)
292
+ continue;
293
+ docs.push({
294
+ path: p,
295
+ scope: toNonEmptyString(candidate.scope) === "global" ? "global" : "project",
296
+ note: toNonEmptyString(candidate.note),
297
+ });
298
+ }
299
+ return docs.length > 0 ? docs : undefined;
300
+ }
301
+ function selectAuthor(explicitAuthor, settingsAuthor) {
302
+ const candidate = explicitAuthor ?? process.env.PM_AUTHOR ?? settingsAuthor;
303
+ const trimmed = candidate.trim();
304
+ return trimmed.length > 0 ? trimmed : "unknown";
305
+ }
306
+ function ensureInitHasRun(pmRoot) {
307
+ return pathExists(getSettingsPath(pmRoot)).then((exists) => {
308
+ if (!exists) {
309
+ throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
310
+ }
311
+ });
312
+ }
313
+ function emptyDocument() {
314
+ return {
315
+ front_matter: {},
316
+ body: "",
317
+ };
318
+ }
319
+ function resolveInputPath(rawPath) {
320
+ return path.isAbsolute(rawPath) ? rawPath : path.resolve(process.cwd(), rawPath);
321
+ }
322
+ export async function runBeadsImport(options, global) {
323
+ const pmRoot = resolvePmRoot(process.cwd(), global.path);
324
+ await ensureInitHasRun(pmRoot);
325
+ 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");
332
+ const warnings = [
333
+ ...(await runActiveOnReadHooks({
334
+ path: sourcePath,
335
+ scope: "project",
336
+ })),
337
+ ];
338
+ const lines = raw.split(/\r?\n/);
339
+ const author = selectAuthor(toNonEmptyString(options.author), settings.author_default);
340
+ const message = toNonEmptyString(options.message) ?? "Import from Beads JSONL";
341
+ const ids = [];
342
+ let imported = 0;
343
+ let skipped = 0;
344
+ for (let index = 0; index < lines.length; index += 1) {
345
+ const lineNumber = index + 1;
346
+ const line = lines[index].trim();
347
+ if (line.length === 0) {
348
+ continue;
349
+ }
350
+ let parsed;
351
+ try {
352
+ parsed = JSON.parse(line);
353
+ }
354
+ catch {
355
+ warnings.push(`beads_import_invalid_jsonl_line:${lineNumber}`);
356
+ skipped += 1;
357
+ continue;
358
+ }
359
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
360
+ warnings.push(`beads_import_invalid_record:${lineNumber}`);
361
+ skipped += 1;
362
+ continue;
363
+ }
364
+ const record = parsed;
365
+ const title = toNonEmptyString(record.title);
366
+ if (!title) {
367
+ warnings.push(`beads_import_missing_title:${lineNumber}`);
368
+ skipped += 1;
369
+ continue;
370
+ }
371
+ const createdAt = toIsoString(record.created_at) ?? nowIso();
372
+ const updatedAt = toIsoString(record.updated_at) ?? createdAt;
373
+ const id = toNonEmptyString(record.id)
374
+ ? normalizeItemId(toNonEmptyString(record.id), settings.id_prefix)
375
+ : await generateItemId(pmRoot, settings.id_prefix);
376
+ const type = toItemType(record.issue_type ?? record.type);
377
+ const frontMatter = normalizeFrontMatter({
378
+ id,
379
+ title,
380
+ description: toNonEmptyString(record.description) ?? "",
381
+ type,
382
+ status: toStatus(record.status),
383
+ priority: toPriority(record.priority),
384
+ tags: toTags(record.tags ?? record.labels),
385
+ created_at: createdAt,
386
+ updated_at: updatedAt,
387
+ deadline: toIsoString(record.deadline),
388
+ assignee: toNonEmptyString(record.assignee),
389
+ author: toNonEmptyString(record.author) ?? toNonEmptyString(record.created_by) ?? author,
390
+ estimated_minutes: toEstimatedMinutes(record.estimated_minutes),
391
+ 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),
394
+ comments: toLogEntries(record.comments, createdAt, author),
395
+ notes: toLogEntries(record.notes, createdAt, author),
396
+ learnings: toLogEntries(record.learnings, createdAt, author),
397
+ files: toLinkedFiles(record.files),
398
+ tests: toLinkedTests(record.tests),
399
+ docs: toLinkedDocs(record.docs),
400
+ });
401
+ const rawBody = toNonEmptyString(record.body) ?? "";
402
+ const design = toNonEmptyString(record.design);
403
+ const externalRef = toNonEmptyString(record.external_ref);
404
+ let finalBody = rawBody;
405
+ if (design) {
406
+ finalBody += (finalBody ? "\n\n" : "") + "## Design\n\n" + design;
407
+ }
408
+ if (externalRef) {
409
+ finalBody += (finalBody ? "\n\n" : "") + "## External Reference\n" + externalRef;
410
+ }
411
+ const afterDocument = canonicalDocument({
412
+ front_matter: frontMatter,
413
+ body: finalBody,
414
+ });
415
+ const itemPath = getItemPath(pmRoot, type, id);
416
+ if (await pathExists(itemPath)) {
417
+ warnings.push(`beads_import_item_exists:${id}`);
418
+ skipped += 1;
419
+ continue;
420
+ }
421
+ const historyPath = getHistoryPath(pmRoot, id);
422
+ try {
423
+ const releaseLock = await acquireLock(pmRoot, id, settings.locks.ttl_seconds, author);
424
+ try {
425
+ await writeFileAtomic(itemPath, serializeItemDocument(afterDocument));
426
+ try {
427
+ const entry = createHistoryEntry({
428
+ nowIso: nowIso(),
429
+ author,
430
+ op: "import",
431
+ before: emptyDocument(),
432
+ after: afterDocument,
433
+ message,
434
+ });
435
+ await appendHistoryEntry(historyPath, entry);
436
+ warnings.push(...(await runActiveOnWriteHooks({
437
+ path: itemPath,
438
+ scope: "project",
439
+ op: "import",
440
+ })), ...(await runActiveOnWriteHooks({
441
+ path: historyPath,
442
+ scope: "project",
443
+ op: "import:history",
444
+ })));
445
+ }
446
+ catch (error) {
447
+ await removeFileIfExists(itemPath);
448
+ throw error;
449
+ }
450
+ }
451
+ finally {
452
+ await releaseLock();
453
+ }
454
+ }
455
+ catch (error) {
456
+ if (error instanceof PmCliError && error.exitCode === EXIT_CODE.CONFLICT) {
457
+ warnings.push(`beads_import_lock_conflict:${id}`);
458
+ skipped += 1;
459
+ continue;
460
+ }
461
+ throw error;
462
+ }
463
+ ids.push(id);
464
+ imported += 1;
465
+ }
466
+ return {
467
+ ok: true,
468
+ source,
469
+ imported,
470
+ skipped,
471
+ ids,
472
+ warnings,
473
+ };
474
+ }
475
+ //# sourceMappingURL=beads.js.map