@unbrained/pm-cli 2026.3.12 → 2026.5.1-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) 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} +31 -21
  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 +196 -92
  11. package/CHANGELOG.md +404 -0
  12. package/CODE_OF_CONDUCT.md +42 -0
  13. package/CONTRIBUTING.md +144 -0
  14. package/PRD.md +512 -164
  15. package/README.md +1053 -2
  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 +1184 -137
  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 +455 -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 +289 -53
  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 +475 -81
  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 +1151 -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 +3625 -445
  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.js +4 -1
  160. package/dist/core/item/id.js.map +1 -1
  161. package/dist/core/item/index.d.ts +1 -0
  162. package/dist/core/item/index.js +1 -0
  163. package/dist/core/item/index.js.map +1 -1
  164. package/dist/core/item/item-format.d.ts +11 -5
  165. package/dist/core/item/item-format.js +507 -24
  166. package/dist/core/item/item-format.js.map +1 -1
  167. package/dist/core/item/parent-reference-policy.d.ts +6 -0
  168. package/dist/core/item/parent-reference-policy.js +32 -0
  169. package/dist/core/item/parent-reference-policy.js.map +1 -0
  170. package/dist/core/item/parse.d.ts +5 -0
  171. package/dist/core/item/parse.js +216 -19
  172. package/dist/core/item/parse.js.map +1 -1
  173. package/dist/core/item/sprint-release-format.d.ts +6 -0
  174. package/dist/core/item/sprint-release-format.js +33 -0
  175. package/dist/core/item/sprint-release-format.js.map +1 -0
  176. package/dist/core/item/status.d.ts +3 -0
  177. package/dist/core/item/status.js +24 -0
  178. package/dist/core/item/status.js.map +1 -0
  179. package/dist/core/item/type-registry.d.ts +37 -0
  180. package/dist/core/item/type-registry.js +706 -0
  181. package/dist/core/item/type-registry.js.map +1 -0
  182. package/dist/core/lock/lock.d.ts +1 -1
  183. package/dist/core/lock/lock.js +101 -12
  184. package/dist/core/lock/lock.js.map +1 -1
  185. package/dist/core/output/command-aware.d.ts +1 -0
  186. package/dist/core/output/command-aware.js +394 -0
  187. package/dist/core/output/command-aware.js.map +1 -0
  188. package/dist/core/output/output.d.ts +3 -0
  189. package/dist/core/output/output.js +124 -6
  190. package/dist/core/output/output.js.map +1 -1
  191. package/dist/core/schema/runtime-field-filters.d.ts +3 -0
  192. package/dist/core/schema/runtime-field-filters.js +39 -0
  193. package/dist/core/schema/runtime-field-filters.js.map +1 -0
  194. package/dist/core/schema/runtime-field-values.d.ts +8 -0
  195. package/dist/core/schema/runtime-field-values.js +154 -0
  196. package/dist/core/schema/runtime-field-values.js.map +1 -0
  197. package/dist/core/schema/runtime-schema.d.ts +68 -0
  198. package/dist/core/schema/runtime-schema.js +554 -0
  199. package/dist/core/schema/runtime-schema.js.map +1 -0
  200. package/dist/core/search/cache.d.ts +13 -1
  201. package/dist/core/search/cache.js +123 -14
  202. package/dist/core/search/cache.js.map +1 -1
  203. package/dist/core/search/semantic-defaults.d.ts +6 -0
  204. package/dist/core/search/semantic-defaults.js +120 -0
  205. package/dist/core/search/semantic-defaults.js.map +1 -0
  206. package/dist/core/search/vector-stores.js +3 -1
  207. package/dist/core/search/vector-stores.js.map +1 -1
  208. package/dist/core/shared/command-types.d.ts +2 -0
  209. package/dist/core/shared/conflict-markers.d.ts +7 -0
  210. package/dist/core/shared/conflict-markers.js +27 -0
  211. package/dist/core/shared/conflict-markers.js.map +1 -0
  212. package/dist/core/shared/constants.d.ts +15 -4
  213. package/dist/core/shared/constants.js +141 -1
  214. package/dist/core/shared/constants.js.map +1 -1
  215. package/dist/core/shared/errors.d.ts +10 -1
  216. package/dist/core/shared/errors.js +3 -1
  217. package/dist/core/shared/errors.js.map +1 -1
  218. package/dist/core/shared/text-normalization.d.ts +4 -0
  219. package/dist/core/shared/text-normalization.js +33 -0
  220. package/dist/core/shared/text-normalization.js.map +1 -0
  221. package/dist/core/shared/time.d.ts +1 -2
  222. package/dist/core/shared/time.js +98 -11
  223. package/dist/core/shared/time.js.map +1 -1
  224. package/dist/core/store/index.d.ts +1 -0
  225. package/dist/core/store/index.js +1 -0
  226. package/dist/core/store/index.js.map +1 -1
  227. package/dist/core/store/item-format-migration.d.ts +9 -0
  228. package/dist/core/store/item-format-migration.js +87 -0
  229. package/dist/core/store/item-format-migration.js.map +1 -0
  230. package/dist/core/store/item-store.d.ts +13 -4
  231. package/dist/core/store/item-store.js +238 -51
  232. package/dist/core/store/item-store.js.map +1 -1
  233. package/dist/core/store/paths.d.ts +21 -3
  234. package/dist/core/store/paths.js +59 -4
  235. package/dist/core/store/paths.js.map +1 -1
  236. package/dist/core/store/settings.d.ts +14 -1
  237. package/dist/core/store/settings.js +463 -7
  238. package/dist/core/store/settings.js.map +1 -1
  239. package/dist/core/telemetry/consent.d.ts +2 -0
  240. package/dist/core/telemetry/consent.js +79 -0
  241. package/dist/core/telemetry/consent.js.map +1 -0
  242. package/dist/core/telemetry/runtime.d.ts +38 -0
  243. package/dist/core/telemetry/runtime.js +733 -0
  244. package/dist/core/telemetry/runtime.js.map +1 -0
  245. package/dist/core/test/background-runs.d.ts +117 -0
  246. package/dist/core/test/background-runs.js +760 -0
  247. package/dist/core/test/background-runs.js.map +1 -0
  248. package/dist/core/test/item-test-run-tracking.d.ts +9 -0
  249. package/dist/core/test/item-test-run-tracking.js +50 -0
  250. package/dist/core/test/item-test-run-tracking.js.map +1 -0
  251. package/dist/sdk/cli-contracts.d.ts +92 -0
  252. package/dist/sdk/cli-contracts.js +2357 -0
  253. package/dist/sdk/cli-contracts.js.map +1 -0
  254. package/dist/sdk/index.d.ts +34 -0
  255. package/dist/sdk/index.js +23 -0
  256. package/dist/sdk/index.js.map +1 -0
  257. package/dist/types.d.ts +197 -3
  258. package/dist/types.js +48 -1
  259. package/dist/types.js.map +1 -1
  260. package/docs/ARCHITECTURE.md +368 -39
  261. package/docs/EXTENSIONS.md +454 -49
  262. package/docs/RELEASING.md +70 -19
  263. package/docs/SDK.md +123 -0
  264. package/docs/examples/starter-extension/README.md +48 -0
  265. package/docs/examples/starter-extension/index.js +191 -0
  266. package/docs/examples/starter-extension/manifest.json +17 -0
  267. package/docs/examples/starter-extension/package.json +10 -0
  268. package/package.json +41 -14
  269. package/.pi/extensions/pm-cli/index.ts +0 -778
  270. package/dist/cli/commands/beads.d.ts +0 -16
  271. package/dist/cli/commands/beads.js.map +0 -1
  272. package/dist/cli/commands/install.d.ts +0 -18
  273. package/dist/cli/commands/install.js +0 -87
  274. package/dist/cli/commands/install.js.map +0 -1
  275. package/dist/core/extensions/builtins.d.ts +0 -3
  276. package/dist/core/extensions/builtins.js +0 -47
  277. package/dist/core/extensions/builtins.js.map +0 -1
  278. package/dist/extensions/builtins/beads/index.d.ts +0 -8
  279. package/dist/extensions/builtins/beads/index.js +0 -33
  280. package/dist/extensions/builtins/beads/index.js.map +0 -1
  281. package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
  282. package/dist/extensions/builtins/todos/import-export.js.map +0 -1
  283. package/dist/extensions/builtins/todos/index.d.ts +0 -8
  284. package/dist/extensions/builtins/todos/index.js +0 -38
  285. package/dist/extensions/builtins/todos/index.js.map +0 -1
@@ -1,778 +0,0 @@
1
- import { fileURLToPath } from "node:url";
2
-
3
- export const PM_TOOL_ACTIONS = [
4
- "init",
5
- "config",
6
- "create",
7
- "list",
8
- "list-all",
9
- "list-draft",
10
- "list-open",
11
- "list-in-progress",
12
- "list-blocked",
13
- "list-closed",
14
- "list-canceled",
15
- "get",
16
- "search",
17
- "reindex",
18
- "history",
19
- "activity",
20
- "restore",
21
- "update",
22
- "close",
23
- "delete",
24
- "append",
25
- "comments",
26
- "files",
27
- "docs",
28
- "test",
29
- "test-all",
30
- "stats",
31
- "health",
32
- "gc",
33
- "completion",
34
- "claim",
35
- "release",
36
- "beads-import",
37
- "todos-import",
38
- "todos-export",
39
- "start-task",
40
- "pause-task",
41
- "close-task",
42
- ] as const;
43
-
44
- export type PmToolAction = (typeof PM_TOOL_ACTIONS)[number];
45
- type NumericFlagInput = string | number;
46
- type BooleanFlagInput = string | number | boolean;
47
-
48
- const NODE_FALLBACK_CLI_PATH = fileURLToPath(new URL("../../../dist/cli.js", import.meta.url));
49
-
50
- export interface PmToolParameters {
51
- action: string;
52
- json?: boolean;
53
- quiet?: boolean;
54
- profile?: boolean;
55
- noExtensions?: boolean;
56
- path?: string;
57
- pmExecutable?: string;
58
- timeoutMs?: number;
59
- id?: string;
60
- target?: string;
61
- query?: string;
62
- keywords?: string;
63
- prefix?: string;
64
- scope?: string;
65
- configAction?: string;
66
- key?: string;
67
- title?: string;
68
- description?: string;
69
- type?: string;
70
- status?: string;
71
- priority?: NumericFlagInput;
72
- tags?: string;
73
- body?: string;
74
- deadline?: string;
75
- estimate?: NumericFlagInput;
76
- acceptanceCriteria?: string;
77
- author?: string;
78
- message?: string;
79
- assignee?: string;
80
- parent?: string;
81
- reviewer?: string;
82
- risk?: string;
83
- confidence?: NumericFlagInput | string;
84
- sprint?: string;
85
- release?: string;
86
- blockedBy?: string;
87
- blockedReason?: string;
88
- unblockNote?: string;
89
- reporter?: string;
90
- severity?: string;
91
- environment?: string;
92
- reproSteps?: string;
93
- resolution?: string;
94
- expectedResult?: string;
95
- actualResult?: string;
96
- affectedVersion?: string;
97
- fixedVersion?: string;
98
- component?: string;
99
- regression?: BooleanFlagInput;
100
- customerImpact?: string;
101
- definitionOfReady?: string;
102
- order?: NumericFlagInput;
103
- goal?: string;
104
- objective?: string;
105
- value?: string;
106
- impact?: string;
107
- outcome?: string;
108
- whyNow?: string;
109
- mode?: string;
110
- includeLinked?: boolean;
111
- tag?: string;
112
- deadlineBefore?: string;
113
- deadlineAfter?: string;
114
- limit?: NumericFlagInput;
115
- timeout?: NumericFlagInput;
116
- force?: boolean;
117
- run?: boolean;
118
- shell?: string;
119
- file?: string;
120
- folder?: string;
121
- text?: string;
122
- add?: string[];
123
- remove?: string[];
124
- dep?: string[];
125
- comment?: string[];
126
- note?: string[];
127
- learning?: string[];
128
- linkedFile?: string[];
129
- linkedTest?: string[];
130
- doc?: string[];
131
- criterion?: string[];
132
- }
133
-
134
- export interface PiExecResult {
135
- stdout?: string;
136
- stderr?: string;
137
- code?: number | null;
138
- killed?: boolean;
139
- }
140
-
141
- export interface PiToolResultEnvelope {
142
- content: Array<{ type: "text"; text: string }>;
143
- details: Record<string, unknown>;
144
- isError?: boolean;
145
- }
146
-
147
- export interface PiToolDefinition {
148
- name: string;
149
- label: string;
150
- description: string;
151
- parameters: Record<string, unknown>;
152
- execute: (
153
- toolCallId: string,
154
- params: PmToolParameters,
155
- signal?: AbortSignal,
156
- onUpdate?: (update: { content?: Array<{ type: "text"; text: string }>; details?: unknown }) => void,
157
- ) => Promise<PiToolResultEnvelope>;
158
- }
159
-
160
- export interface PiExtensionApi {
161
- registerTool(definition: PiToolDefinition): void;
162
- exec(command: string, args: string[], options?: { signal?: AbortSignal; timeout?: number }): Promise<PiExecResult>;
163
- }
164
-
165
- export const PM_TOOL_PARAMETERS_SCHEMA: Record<string, unknown> = {
166
- type: "object",
167
- additionalProperties: false,
168
- required: ["action"],
169
- properties: {
170
- action: { type: "string", enum: [...PM_TOOL_ACTIONS] },
171
- json: { type: "boolean", default: true },
172
- quiet: { type: "boolean" },
173
- profile: { type: "boolean" },
174
- noExtensions: { type: "boolean" },
175
- path: { type: "string" },
176
- pmExecutable: { type: "string" },
177
- timeoutMs: { type: "number" },
178
- id: { type: "string" },
179
- target: { type: "string" },
180
- query: { type: "string" },
181
- keywords: { type: "string" },
182
- prefix: { type: "string" },
183
- scope: { type: "string" },
184
- configAction: { type: "string" },
185
- key: { type: "string" },
186
- title: { type: "string" },
187
- description: { type: "string" },
188
- type: { type: "string" },
189
- status: { type: "string" },
190
- priority: { anyOf: [{ type: "string" }, { type: "number" }] },
191
- tags: { type: "string" },
192
- body: { type: "string" },
193
- deadline: { type: "string" },
194
- estimate: { anyOf: [{ type: "string" }, { type: "number" }] },
195
- acceptanceCriteria: { type: "string" },
196
- author: { type: "string" },
197
- message: { type: "string" },
198
- assignee: { type: "string" },
199
- parent: { type: "string" },
200
- reviewer: { type: "string" },
201
- risk: { type: "string" },
202
- confidence: { anyOf: [{ type: "string" }, { type: "number" }] },
203
- sprint: { type: "string" },
204
- release: { type: "string" },
205
- blockedBy: { type: "string" },
206
- blockedReason: { type: "string" },
207
- unblockNote: { type: "string" },
208
- reporter: { type: "string" },
209
- severity: { type: "string" },
210
- environment: { type: "string" },
211
- reproSteps: { type: "string" },
212
- resolution: { type: "string" },
213
- expectedResult: { type: "string" },
214
- actualResult: { type: "string" },
215
- affectedVersion: { type: "string" },
216
- fixedVersion: { type: "string" },
217
- component: { type: "string" },
218
- regression: { anyOf: [{ type: "boolean" }, { type: "string" }, { type: "number" }] },
219
- customerImpact: { type: "string" },
220
- definitionOfReady: { type: "string" },
221
- order: { anyOf: [{ type: "string" }, { type: "number" }] },
222
- goal: { type: "string" },
223
- objective: { type: "string" },
224
- value: { type: "string" },
225
- impact: { type: "string" },
226
- outcome: { type: "string" },
227
- whyNow: { type: "string" },
228
- mode: { type: "string" },
229
- includeLinked: { type: "boolean" },
230
- tag: { type: "string" },
231
- deadlineBefore: { type: "string" },
232
- deadlineAfter: { type: "string" },
233
- limit: { anyOf: [{ type: "string" }, { type: "number" }] },
234
- timeout: { anyOf: [{ type: "string" }, { type: "number" }] },
235
- force: { type: "boolean" },
236
- run: { type: "boolean" },
237
- shell: { type: "string" },
238
- file: { type: "string" },
239
- folder: { type: "string" },
240
- text: { type: "string" },
241
- add: { type: "array", items: { type: "string" } },
242
- remove: { type: "array", items: { type: "string" } },
243
- dep: { type: "array", items: { type: "string" } },
244
- comment: { type: "array", items: { type: "string" } },
245
- note: { type: "array", items: { type: "string" } },
246
- learning: { type: "array", items: { type: "string" } },
247
- linkedFile: { type: "array", items: { type: "string" } },
248
- linkedTest: { type: "array", items: { type: "string" } },
249
- doc: { type: "array", items: { type: "string" } },
250
- criterion: { type: "array", items: { type: "string" } },
251
- },
252
- };
253
-
254
- function isPmToolAction(action: string): action is PmToolAction {
255
- return (PM_TOOL_ACTIONS as readonly string[]).includes(action);
256
- }
257
-
258
- function pushOption(args: string[], flag: string, value: string | number | undefined, allowEmpty = false): void {
259
- if (typeof value === "number") {
260
- if (!Number.isFinite(value)) {
261
- return;
262
- }
263
- args.push(flag, String(value));
264
- return;
265
- }
266
- if (typeof value !== "string") {
267
- return;
268
- }
269
- if (!allowEmpty && value.length === 0) {
270
- return;
271
- }
272
- args.push(flag, value);
273
- }
274
-
275
- function pushRepeatable(args: string[], flag: string, values: string[] | undefined): void {
276
- if (!Array.isArray(values)) {
277
- return;
278
- }
279
- for (const value of values) {
280
- if (typeof value === "string" && value.length > 0) {
281
- args.push(flag, value);
282
- }
283
- }
284
- }
285
-
286
- function pushBooleanishOption(args: string[], flag: string, value: BooleanFlagInput | undefined): void {
287
- if (typeof value === "boolean") {
288
- args.push(flag, value ? "true" : "false");
289
- return;
290
- }
291
- pushOption(args, flag, value);
292
- }
293
-
294
- function pushRepeatableOrNone(args: string[], flag: string, values: string[] | undefined): void {
295
- const validValues = Array.isArray(values) ? values.filter((value) => typeof value === "string" && value.length > 0) : [];
296
- if (validValues.length === 0) {
297
- args.push(flag, "none");
298
- return;
299
- }
300
- for (const value of validValues) {
301
- args.push(flag, value);
302
- }
303
- }
304
-
305
- function requireString(value: string | undefined, name: string, action: PmToolAction): string {
306
- if (typeof value !== "string" || value.length === 0) {
307
- throw new Error(`Action "${action}" requires "${name}".`);
308
- }
309
- return value;
310
- }
311
-
312
- function addListFilters(args: string[], params: PmToolParameters): void {
313
- pushOption(args, "--type", params.type);
314
- pushOption(args, "--tag", params.tag);
315
- pushOption(args, "--priority", params.priority);
316
- pushOption(args, "--deadline-before", params.deadlineBefore);
317
- pushOption(args, "--deadline-after", params.deadlineAfter);
318
- pushOption(args, "--limit", params.limit);
319
- }
320
-
321
- function addCreateFlags(args: string[], params: PmToolParameters): void {
322
- pushOption(args, "--title", params.title);
323
- pushOption(args, "--description", params.description, true);
324
- pushOption(args, "--type", params.type);
325
- pushOption(args, "--status", params.status);
326
- pushOption(args, "--priority", params.priority);
327
- pushOption(args, "--tags", params.tags, true);
328
- pushOption(args, "--body", params.body, true);
329
- pushOption(args, "--deadline", params.deadline);
330
- pushOption(args, "--estimate", params.estimate);
331
- pushOption(args, "--acceptance-criteria", params.acceptanceCriteria, true);
332
- pushOption(args, "--author", params.author);
333
- pushOption(args, "--message", params.message, true);
334
- const assignee = typeof params.assignee === "string" && params.assignee.length > 0 ? params.assignee : "none";
335
- pushOption(args, "--assignee", assignee);
336
- addSharedCreateUpdateFlags(args, params);
337
- pushRepeatableOrNone(args, "--dep", params.dep);
338
- pushRepeatableOrNone(args, "--comment", params.comment);
339
- pushRepeatableOrNone(args, "--note", params.note);
340
- pushRepeatableOrNone(args, "--learning", params.learning);
341
- pushRepeatableOrNone(args, "--file", params.linkedFile);
342
- pushRepeatableOrNone(args, "--test", params.linkedTest);
343
- pushRepeatableOrNone(args, "--doc", params.doc);
344
- }
345
-
346
- function addUpdateFlags(args: string[], params: PmToolParameters): void {
347
- pushOption(args, "--title", params.title);
348
- pushOption(args, "--description", params.description, true);
349
- pushOption(args, "--status", params.status);
350
- pushOption(args, "--priority", params.priority);
351
- pushOption(args, "--type", params.type);
352
- pushOption(args, "--tags", params.tags, true);
353
- pushOption(args, "--deadline", params.deadline);
354
- pushOption(args, "--estimate", params.estimate);
355
- pushOption(args, "--acceptance-criteria", params.acceptanceCriteria, true);
356
- pushOption(args, "--author", params.author);
357
- pushOption(args, "--message", params.message, true);
358
- pushOption(args, "--assignee", params.assignee);
359
- addSharedCreateUpdateFlags(args, params);
360
- if (params.force) {
361
- args.push("--force");
362
- }
363
- }
364
-
365
- function addSharedCreateUpdateFlags(args: string[], params: PmToolParameters): void {
366
- pushOption(args, "--parent", params.parent);
367
- pushOption(args, "--reviewer", params.reviewer);
368
- pushOption(args, "--risk", params.risk);
369
- pushOption(args, "--confidence", params.confidence);
370
- pushOption(args, "--sprint", params.sprint);
371
- pushOption(args, "--release", params.release);
372
- pushOption(args, "--blocked-by", params.blockedBy);
373
- pushOption(args, "--blocked-reason", params.blockedReason);
374
- pushOption(args, "--unblock-note", params.unblockNote);
375
- pushOption(args, "--reporter", params.reporter);
376
- pushOption(args, "--severity", params.severity);
377
- pushOption(args, "--environment", params.environment);
378
- pushOption(args, "--repro-steps", params.reproSteps);
379
- pushOption(args, "--resolution", params.resolution);
380
- pushOption(args, "--expected-result", params.expectedResult);
381
- pushOption(args, "--actual-result", params.actualResult);
382
- pushOption(args, "--affected-version", params.affectedVersion);
383
- pushOption(args, "--fixed-version", params.fixedVersion);
384
- pushOption(args, "--component", params.component);
385
- pushBooleanishOption(args, "--regression", params.regression);
386
- pushOption(args, "--customer-impact", params.customerImpact);
387
- pushOption(args, "--definition-of-ready", params.definitionOfReady, true);
388
- pushOption(args, "--order", params.order);
389
- pushOption(args, "--goal", params.goal);
390
- pushOption(args, "--objective", params.objective);
391
- pushOption(args, "--value", params.value);
392
- pushOption(args, "--impact", params.impact);
393
- pushOption(args, "--outcome", params.outcome);
394
- pushOption(args, "--why-now", params.whyNow);
395
- }
396
-
397
- function addAuthorMessageForceFlags(args: string[], params: PmToolParameters): void {
398
- pushOption(args, "--author", params.author);
399
- pushOption(args, "--message", params.message, true);
400
- if (params.force) {
401
- args.push("--force");
402
- }
403
- }
404
-
405
- function addGlobalFlags(args: string[], params: PmToolParameters): void {
406
- if (params.json !== false) {
407
- args.push("--json");
408
- }
409
- if (params.quiet) {
410
- args.push("--quiet");
411
- }
412
- if (params.profile) {
413
- args.push("--profile");
414
- }
415
- if (params.noExtensions) {
416
- args.push("--no-extensions");
417
- }
418
- pushOption(args, "--path", params.path);
419
- }
420
-
421
- export function buildPmCliSequences(params: PmToolParameters): string[][] {
422
- const action = params.action.trim().toLowerCase();
423
- if (action === "start-task") {
424
- const globalArgs: string[] = [];
425
- addGlobalFlags(globalArgs, params);
426
- const id = requireString(params.id, "id", action);
427
- const claimArgs = ["claim", id];
428
- addAuthorMessageForceFlags(claimArgs, params);
429
- const updateArgs = ["update", id, "--status", "in_progress"];
430
- addAuthorMessageForceFlags(updateArgs, params);
431
- return [[...globalArgs, ...claimArgs], [...globalArgs, ...updateArgs]];
432
- }
433
- if (action === "pause-task") {
434
- const globalArgs: string[] = [];
435
- addGlobalFlags(globalArgs, params);
436
- const id = requireString(params.id, "id", action);
437
- const updateArgs = ["update", id, "--status", "open"];
438
- addAuthorMessageForceFlags(updateArgs, params);
439
- const releaseArgs = ["release", id];
440
- addAuthorMessageForceFlags(releaseArgs, params);
441
- return [[...globalArgs, ...updateArgs], [...globalArgs, ...releaseArgs]];
442
- }
443
- if (action === "close-task") {
444
- const globalArgs: string[] = [];
445
- addGlobalFlags(globalArgs, params);
446
- const id = requireString(params.id, "id", action);
447
- const closeArgs = ["close", id, requireString(params.text, "text", action)];
448
- addAuthorMessageForceFlags(closeArgs, params);
449
- const releaseArgs = ["release", id];
450
- addAuthorMessageForceFlags(releaseArgs, params);
451
- return [[...globalArgs, ...closeArgs], [...globalArgs, ...releaseArgs]];
452
- }
453
- return [buildPmCliArgs(params)];
454
- }
455
-
456
- export function buildPmCliArgs(params: PmToolParameters): string[] {
457
- const action = params.action.trim().toLowerCase();
458
- if (!isPmToolAction(action)) {
459
- throw new Error(`Unsupported action "${params.action}".`);
460
- }
461
-
462
- const args: string[] = [];
463
- addGlobalFlags(args, params);
464
-
465
- switch (action) {
466
- case "init":
467
- args.push("init");
468
- if (params.prefix) {
469
- args.push(params.prefix);
470
- }
471
- return args;
472
- case "config":
473
- args.push(
474
- "config",
475
- requireString(params.scope, "scope", action),
476
- requireString(params.configAction, "configAction", action),
477
- requireString(params.key, "key", action),
478
- );
479
- pushRepeatable(args, "--criterion", params.criterion);
480
- return args;
481
- case "create":
482
- args.push("create");
483
- addCreateFlags(args, params);
484
- return args;
485
- case "list":
486
- case "list-all":
487
- case "list-draft":
488
- case "list-open":
489
- case "list-in-progress":
490
- case "list-blocked":
491
- case "list-closed":
492
- case "list-canceled":
493
- args.push(action);
494
- addListFilters(args, params);
495
- return args;
496
- case "get":
497
- args.push("get", requireString(params.id, "id", action));
498
- return args;
499
- case "search":
500
- args.push("search", requireString(params.query ?? params.keywords, "query", action));
501
- pushOption(args, "--mode", params.mode);
502
- if (params.includeLinked) {
503
- args.push("--include-linked");
504
- }
505
- addListFilters(args, params);
506
- return args;
507
- case "reindex":
508
- args.push("reindex");
509
- pushOption(args, "--mode", params.mode);
510
- return args;
511
- case "history":
512
- args.push("history", requireString(params.id, "id", action));
513
- pushOption(args, "--limit", params.limit);
514
- return args;
515
- case "activity":
516
- args.push("activity");
517
- pushOption(args, "--limit", params.limit);
518
- return args;
519
- case "restore":
520
- args.push("restore", requireString(params.id, "id", action), requireString(params.target, "target", action));
521
- addAuthorMessageForceFlags(args, params);
522
- return args;
523
- case "update":
524
- args.push("update", requireString(params.id, "id", action));
525
- addUpdateFlags(args, params);
526
- return args;
527
- case "close":
528
- args.push("close", requireString(params.id, "id", action), requireString(params.text, "text", action));
529
- addAuthorMessageForceFlags(args, params);
530
- return args;
531
- case "delete":
532
- args.push("delete", requireString(params.id, "id", action));
533
- addAuthorMessageForceFlags(args, params);
534
- return args;
535
- case "append":
536
- args.push("append", requireString(params.id, "id", action));
537
- pushOption(args, "--body", params.body, true);
538
- addAuthorMessageForceFlags(args, params);
539
- return args;
540
- case "comments":
541
- args.push("comments", requireString(params.id, "id", action));
542
- pushOption(args, "--add", params.text ?? params.add?.[0]);
543
- pushOption(args, "--limit", params.limit);
544
- addAuthorMessageForceFlags(args, params);
545
- return args;
546
- case "files":
547
- args.push("files", requireString(params.id, "id", action));
548
- pushRepeatable(args, "--add", params.add);
549
- pushRepeatable(args, "--remove", params.remove);
550
- addAuthorMessageForceFlags(args, params);
551
- return args;
552
- case "docs":
553
- args.push("docs", requireString(params.id, "id", action));
554
- pushRepeatable(args, "--add", params.add);
555
- pushRepeatable(args, "--remove", params.remove);
556
- addAuthorMessageForceFlags(args, params);
557
- return args;
558
- case "test":
559
- args.push("test", requireString(params.id, "id", action));
560
- pushRepeatable(args, "--add", params.add);
561
- pushRepeatable(args, "--remove", params.remove);
562
- if (params.run) {
563
- args.push("--run");
564
- }
565
- pushOption(args, "--timeout", params.timeout);
566
- addAuthorMessageForceFlags(args, params);
567
- return args;
568
- case "test-all":
569
- args.push("test-all");
570
- pushOption(args, "--status", params.status);
571
- pushOption(args, "--timeout", params.timeout);
572
- return args;
573
- case "stats":
574
- case "health":
575
- case "gc":
576
- args.push(action);
577
- return args;
578
- case "completion":
579
- args.push("completion", requireString(params.shell, "shell", action));
580
- return args;
581
- case "claim":
582
- case "release":
583
- args.push(action, requireString(params.id, "id", action));
584
- addAuthorMessageForceFlags(args, params);
585
- return args;
586
- case "start-task":
587
- case "pause-task":
588
- case "close-task":
589
- throw new Error(`Action "${action}" is a workflow preset and must be built via buildPmCliSequences().`);
590
- case "beads-import":
591
- args.push("beads", "import");
592
- pushOption(args, "--file", params.file);
593
- pushOption(args, "--author", params.author);
594
- pushOption(args, "--message", params.message);
595
- return args;
596
- case "todos-import":
597
- args.push("todos", "import");
598
- pushOption(args, "--folder", params.folder);
599
- pushOption(args, "--author", params.author);
600
- pushOption(args, "--message", params.message);
601
- return args;
602
- case "todos-export":
603
- args.push("todos", "export");
604
- pushOption(args, "--folder", params.folder);
605
- return args;
606
- }
607
- }
608
-
609
- function looksLikeCommandNotFound(stderr: string, command: string, code: number | null | undefined): boolean {
610
- if (code === 127) {
611
- return true;
612
- }
613
- const normalized = stderr.toLowerCase();
614
- return (
615
- normalized.includes("not found") ||
616
- normalized.includes("enoent") ||
617
- normalized.includes(`${command.toLowerCase()}: command not found`) ||
618
- normalized.includes(`'${command.toLowerCase()}' is not recognized`)
619
- );
620
- }
621
-
622
- function parseJsonOutput(text: string): unknown {
623
- try {
624
- return JSON.parse(text);
625
- } catch {
626
- return null;
627
- }
628
- }
629
-
630
- function renderContentText(stdout: string, stderr: string, code: number | null | undefined): string {
631
- if (stdout.length > 0) {
632
- return stdout;
633
- }
634
- if (stderr.length > 0) {
635
- return stderr;
636
- }
637
- return `pm command exited with code ${code ?? "unknown"}.`;
638
- }
639
-
640
- function commandToDisplay(command: string, args: string[]): string {
641
- return [command, ...args].join(" ").trim();
642
- }
643
-
644
- export async function runPmToolAction(
645
- pi: PiExtensionApi,
646
- params: PmToolParameters,
647
- signal?: AbortSignal,
648
- ): Promise<PiToolResultEnvelope> {
649
- const sequences = buildPmCliSequences(params);
650
- const timeout = typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs) ? params.timeoutMs : undefined;
651
-
652
- let lastResult: PiExecResult = {
653
- code: 1,
654
- stdout: "",
655
- stderr: "No pm invocation attempts were configured.",
656
- };
657
- let selectedAttempt: { command: string; args: string[]; display: string } | undefined;
658
- const tried: string[] = [];
659
- const allStdout: string[] = [];
660
- const allStderr: string[] = [];
661
- let parsed: unknown = null;
662
- let exitCode = 1;
663
-
664
- for (const cliArgs of sequences) {
665
- const attempts: Array<{ command: string; args: string[]; display: string }> = [];
666
- if (typeof params.pmExecutable === "string" && params.pmExecutable.length > 0) {
667
- attempts.push({
668
- command: params.pmExecutable,
669
- args: cliArgs,
670
- display: commandToDisplay(params.pmExecutable, cliArgs),
671
- });
672
- } else {
673
- attempts.push(
674
- {
675
- command: "pm",
676
- args: cliArgs,
677
- display: commandToDisplay("pm", cliArgs),
678
- },
679
- {
680
- command: "node",
681
- args: [NODE_FALLBACK_CLI_PATH, ...cliArgs],
682
- display: commandToDisplay("node", [NODE_FALLBACK_CLI_PATH, ...cliArgs]),
683
- },
684
- );
685
- }
686
-
687
- let sequenceResult: PiExecResult = {
688
- code: 1,
689
- stdout: "",
690
- stderr: "No pm invocation attempts were configured.",
691
- };
692
-
693
- for (let index = 0; index < attempts.length; index += 1) {
694
- const attempt = attempts[index];
695
- selectedAttempt = attempt;
696
- tried.push(attempt.display);
697
- try {
698
- sequenceResult = await pi.exec(attempt.command, attempt.args, { signal, timeout });
699
- } catch (error: unknown) {
700
- const message = error instanceof Error ? error.message : String(error);
701
- sequenceResult = {
702
- code: 1,
703
- stdout: "",
704
- stderr: message,
705
- };
706
- }
707
-
708
- const code = sequenceResult.code ?? 1;
709
- const stderr = (sequenceResult.stderr ?? "").trim();
710
- if (code === 0) {
711
- break;
712
- }
713
-
714
- if (!looksLikeCommandNotFound(stderr, attempt.command, code) || index === attempts.length - 1) {
715
- break;
716
- }
717
- }
718
-
719
- lastResult = sequenceResult;
720
- exitCode = lastResult.code ?? 1;
721
-
722
- const currentStdout = (lastResult.stdout ?? "").trim();
723
- const currentStderr = (lastResult.stderr ?? "").trim();
724
- if (currentStdout) allStdout.push(currentStdout);
725
- if (currentStderr) allStderr.push(currentStderr);
726
- parsed = parseJsonOutput(currentStdout);
727
-
728
- if (exitCode !== 0) {
729
- break;
730
- }
731
- }
732
-
733
- const stdout = allStdout.join("\n\n");
734
- const stderr = allStderr.join("\n\n");
735
- const contentText = renderContentText(stdout, stderr, exitCode);
736
-
737
- return {
738
- content: [{ type: "text", text: contentText }],
739
- details: {
740
- action: params.action,
741
- invocation: selectedAttempt ? {
742
- command: selectedAttempt.command,
743
- args: selectedAttempt.args,
744
- display: selectedAttempt.display,
745
- } : { command: "unknown", args: [], display: "unknown" },
746
- tried,
747
- exit_code: exitCode,
748
- ok: exitCode === 0,
749
- stdout,
750
- stderr,
751
- parsed,
752
- },
753
- isError: exitCode !== 0,
754
- };
755
- }
756
-
757
- export function createPmToolDefinition(pi: PiExtensionApi): PiToolDefinition {
758
- return {
759
- name: "pm",
760
- label: "pm",
761
- description: "Run pm-cli actions through a Pi tool wrapper.",
762
- parameters: PM_TOOL_PARAMETERS_SCHEMA,
763
- async execute(_toolCallId, params, signal, onUpdate) {
764
- onUpdate?.({
765
- content: [{ type: "text", text: `Running pm action: ${params.action}` }],
766
- });
767
- return runPmToolAction(pi, params, signal);
768
- },
769
- };
770
- }
771
-
772
- export function registerPmTool(pi: PiExtensionApi): void {
773
- pi.registerTool(createPmToolDefinition(pi));
774
- }
775
-
776
- export default function pmPiExtension(pi: PiExtensionApi): void {
777
- registerPmTool(pi);
778
- }