@unbrained/pm-cli 2026.5.18 → 2026.5.24

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 (225) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +2 -1
  3. package/dist/cli/commander-usage.js +16 -2
  4. package/dist/cli/commander-usage.js.map +1 -1
  5. package/dist/cli/commands/annotation-command.d.ts +49 -0
  6. package/dist/cli/commands/annotation-command.js +135 -0
  7. package/dist/cli/commands/annotation-command.js.map +1 -0
  8. package/dist/cli/commands/append.js +3 -7
  9. package/dist/cli/commands/append.js.map +1 -1
  10. package/dist/cli/commands/calendar.js +3 -6
  11. package/dist/cli/commands/calendar.js.map +1 -1
  12. package/dist/cli/commands/claim.js +12 -22
  13. package/dist/cli/commands/claim.js.map +1 -1
  14. package/dist/cli/commands/close.js +61 -9
  15. package/dist/cli/commands/close.js.map +1 -1
  16. package/dist/cli/commands/comments.d.ts +5 -0
  17. package/dist/cli/commands/comments.js +27 -117
  18. package/dist/cli/commands/comments.js.map +1 -1
  19. package/dist/cli/commands/completion.js +102 -15
  20. package/dist/cli/commands/completion.js.map +1 -1
  21. package/dist/cli/commands/context.js +4 -10
  22. package/dist/cli/commands/context.js.map +1 -1
  23. package/dist/cli/commands/contracts.js +168 -36
  24. package/dist/cli/commands/contracts.js.map +1 -1
  25. package/dist/cli/commands/create.js +49 -44
  26. package/dist/cli/commands/create.js.map +1 -1
  27. package/dist/cli/commands/dedupe-audit.js +7 -4
  28. package/dist/cli/commands/dedupe-audit.js.map +1 -1
  29. package/dist/cli/commands/delete.d.ts +3 -0
  30. package/dist/cli/commands/delete.js +9 -8
  31. package/dist/cli/commands/delete.js.map +1 -1
  32. package/dist/cli/commands/docs.d.ts +1 -0
  33. package/dist/cli/commands/docs.js +4 -8
  34. package/dist/cli/commands/docs.js.map +1 -1
  35. package/dist/cli/commands/event-validation-messages.d.ts +3 -0
  36. package/dist/cli/commands/event-validation-messages.js +44 -0
  37. package/dist/cli/commands/event-validation-messages.js.map +1 -0
  38. package/dist/cli/commands/extension.d.ts +1 -0
  39. package/dist/cli/commands/extension.js +138 -21
  40. package/dist/cli/commands/extension.js.map +1 -1
  41. package/dist/cli/commands/files.js +6 -13
  42. package/dist/cli/commands/files.js.map +1 -1
  43. package/dist/cli/commands/gc.js +17 -4
  44. package/dist/cli/commands/gc.js.map +1 -1
  45. package/dist/cli/commands/get.d.ts +3 -2
  46. package/dist/cli/commands/get.js +50 -8
  47. package/dist/cli/commands/get.js.map +1 -1
  48. package/dist/cli/commands/health.d.ts +10 -0
  49. package/dist/cli/commands/health.js +254 -75
  50. package/dist/cli/commands/health.js.map +1 -1
  51. package/dist/cli/commands/history-redact.d.ts +8 -0
  52. package/dist/cli/commands/history-redact.js +14 -97
  53. package/dist/cli/commands/history-redact.js.map +1 -1
  54. package/dist/cli/commands/history-repair.d.ts +33 -0
  55. package/dist/cli/commands/history-repair.js +166 -0
  56. package/dist/cli/commands/history-repair.js.map +1 -0
  57. package/dist/cli/commands/history.d.ts +4 -4
  58. package/dist/cli/commands/history.js +10 -88
  59. package/dist/cli/commands/history.js.map +1 -1
  60. package/dist/cli/commands/index.d.ts +3 -1
  61. package/dist/cli/commands/index.js +5 -3
  62. package/dist/cli/commands/index.js.map +1 -1
  63. package/dist/cli/commands/init.d.ts +28 -0
  64. package/dist/cli/commands/init.js +23 -2
  65. package/dist/cli/commands/init.js.map +1 -1
  66. package/dist/cli/commands/learnings.js +20 -119
  67. package/dist/cli/commands/learnings.js.map +1 -1
  68. package/dist/cli/commands/linked-test-entry.d.ts +3 -0
  69. package/dist/cli/commands/linked-test-entry.js +62 -0
  70. package/dist/cli/commands/linked-test-entry.js.map +1 -0
  71. package/dist/cli/commands/list.js +32 -22
  72. package/dist/cli/commands/list.js.map +1 -1
  73. package/dist/cli/commands/notes.js +20 -119
  74. package/dist/cli/commands/notes.js.map +1 -1
  75. package/dist/cli/commands/plan.d.ts +3 -0
  76. package/dist/cli/commands/plan.js +184 -22
  77. package/dist/cli/commands/plan.js.map +1 -1
  78. package/dist/cli/commands/restore.js +7 -50
  79. package/dist/cli/commands/restore.js.map +1 -1
  80. package/dist/cli/commands/schema.d.ts +31 -0
  81. package/dist/cli/commands/schema.js +98 -0
  82. package/dist/cli/commands/schema.js.map +1 -0
  83. package/dist/cli/commands/search.js +151 -40
  84. package/dist/cli/commands/search.js.map +1 -1
  85. package/dist/cli/commands/templates.d.ts +4 -0
  86. package/dist/cli/commands/templates.js +89 -17
  87. package/dist/cli/commands/templates.js.map +1 -1
  88. package/dist/cli/commands/test-all.js +4 -8
  89. package/dist/cli/commands/test-all.js.map +1 -1
  90. package/dist/cli/commands/test.d.ts +1 -0
  91. package/dist/cli/commands/test.js +7 -10
  92. package/dist/cli/commands/test.js.map +1 -1
  93. package/dist/cli/commands/update-many.js +4 -8
  94. package/dist/cli/commands/update-many.js.map +1 -1
  95. package/dist/cli/commands/update.js +109 -51
  96. package/dist/cli/commands/update.js.map +1 -1
  97. package/dist/cli/commands/validate.d.ts +3 -1
  98. package/dist/cli/commands/validate.js +23 -71
  99. package/dist/cli/commands/validate.js.map +1 -1
  100. package/dist/cli/error-guidance.js +96 -6
  101. package/dist/cli/error-guidance.js.map +1 -1
  102. package/dist/cli/extension-command-help.d.ts +0 -1
  103. package/dist/cli/extension-command-help.js +2 -13
  104. package/dist/cli/extension-command-help.js.map +1 -1
  105. package/dist/cli/extension-command-options.d.ts +1 -0
  106. package/dist/cli/extension-command-options.js +106 -7
  107. package/dist/cli/extension-command-options.js.map +1 -1
  108. package/dist/cli/help-content.d.ts +0 -1
  109. package/dist/cli/help-content.js +13 -9
  110. package/dist/cli/help-content.js.map +1 -1
  111. package/dist/cli/help-json-payload.d.ts +1 -0
  112. package/dist/cli/help-json-payload.js +33 -3
  113. package/dist/cli/help-json-payload.js.map +1 -1
  114. package/dist/cli/main.js +35 -29
  115. package/dist/cli/main.js.map +1 -1
  116. package/dist/cli/register-list-query.d.ts +1 -1
  117. package/dist/cli/register-list-query.js +40 -17
  118. package/dist/cli/register-list-query.js.map +1 -1
  119. package/dist/cli/register-mutation.d.ts +1 -1
  120. package/dist/cli/register-mutation.js +232 -64
  121. package/dist/cli/register-mutation.js.map +1 -1
  122. package/dist/cli/register-operations.js +16 -11
  123. package/dist/cli/register-operations.js.map +1 -1
  124. package/dist/cli/register-setup.js +26 -14
  125. package/dist/cli/register-setup.js.map +1 -1
  126. package/dist/cli/registration-helpers.d.ts +0 -2
  127. package/dist/cli/registration-helpers.js +13 -40
  128. package/dist/cli/registration-helpers.js.map +1 -1
  129. package/dist/cli.js +23 -3
  130. package/dist/cli.js.map +1 -1
  131. package/dist/core/extensions/index.d.ts +0 -1
  132. package/dist/core/extensions/index.js +2 -14
  133. package/dist/core/extensions/index.js.map +1 -1
  134. package/dist/core/extensions/loader.js +3 -9
  135. package/dist/core/extensions/loader.js.map +1 -1
  136. package/dist/core/fs/path-utils.d.ts +1 -0
  137. package/dist/core/fs/path-utils.js +12 -0
  138. package/dist/core/fs/path-utils.js.map +1 -0
  139. package/dist/core/history/drift-scan.d.ts +11 -0
  140. package/dist/core/history/drift-scan.js +67 -0
  141. package/dist/core/history/drift-scan.js.map +1 -0
  142. package/dist/core/history/replay.d.ts +82 -0
  143. package/dist/core/history/replay.js +249 -0
  144. package/dist/core/history/replay.js.map +1 -0
  145. package/dist/core/item/item-format.js +11 -8
  146. package/dist/core/item/item-format.js.map +1 -1
  147. package/dist/core/item/item-type-definition.d.ts +52 -0
  148. package/dist/core/item/item-type-definition.js +123 -0
  149. package/dist/core/item/item-type-definition.js.map +1 -0
  150. package/dist/core/item/parse.js +3 -2
  151. package/dist/core/item/parse.js.map +1 -1
  152. package/dist/core/item/priority.d.ts +23 -0
  153. package/dist/core/item/priority.js +55 -0
  154. package/dist/core/item/priority.js.map +1 -0
  155. package/dist/core/item/status.d.ts +14 -1
  156. package/dist/core/item/status.js +22 -2
  157. package/dist/core/item/status.js.map +1 -1
  158. package/dist/core/item/toon-decode.d.ts +19 -0
  159. package/dist/core/item/toon-decode.js +69 -0
  160. package/dist/core/item/toon-decode.js.map +1 -0
  161. package/dist/core/item/type-registry.js +13 -84
  162. package/dist/core/item/type-registry.js.map +1 -1
  163. package/dist/core/packages/manifest.js +3 -9
  164. package/dist/core/packages/manifest.js.map +1 -1
  165. package/dist/core/schema/item-types-file.d.ts +85 -0
  166. package/dist/core/schema/item-types-file.js +243 -0
  167. package/dist/core/schema/item-types-file.js.map +1 -0
  168. package/dist/core/schema/runtime-schema.d.ts +2 -1
  169. package/dist/core/schema/runtime-schema.js +11 -9
  170. package/dist/core/schema/runtime-schema.js.map +1 -1
  171. package/dist/core/search/semantic-defaults.js +3 -3
  172. package/dist/core/search/semantic-defaults.js.map +1 -1
  173. package/dist/core/shared/author.d.ts +1 -0
  174. package/dist/core/shared/author.js +9 -0
  175. package/dist/core/shared/author.js.map +1 -0
  176. package/dist/core/shared/lazy-module.d.ts +1 -0
  177. package/dist/core/shared/lazy-module.js +11 -0
  178. package/dist/core/shared/lazy-module.js.map +1 -0
  179. package/dist/core/shared/option-alias-visibility.d.ts +44 -0
  180. package/dist/core/shared/option-alias-visibility.js +76 -0
  181. package/dist/core/shared/option-alias-visibility.js.map +1 -0
  182. package/dist/core/shared/text-normalization.d.ts +0 -1
  183. package/dist/core/shared/text-normalization.js +2 -5
  184. package/dist/core/shared/text-normalization.js.map +1 -1
  185. package/dist/core/store/item-store.d.ts +2 -0
  186. package/dist/core/store/item-store.js +70 -39
  187. package/dist/core/store/item-store.js.map +1 -1
  188. package/dist/core/store/settings-validator.d.ts +106 -0
  189. package/dist/core/store/settings-validator.js +279 -0
  190. package/dist/core/store/settings-validator.js.map +1 -0
  191. package/dist/core/store/settings.js +6 -343
  192. package/dist/core/store/settings.js.map +1 -1
  193. package/dist/core/telemetry/runtime.js +5 -3
  194. package/dist/core/telemetry/runtime.js.map +1 -1
  195. package/dist/mcp/server.js +64 -13
  196. package/dist/mcp/server.js.map +1 -1
  197. package/dist/sdk/cli-contracts.d.ts +9 -2
  198. package/dist/sdk/cli-contracts.js +204 -13
  199. package/dist/sdk/cli-contracts.js.map +1 -1
  200. package/dist/sdk/runtime.d.ts +25 -1
  201. package/dist/sdk/runtime.js +46 -3
  202. package/dist/sdk/runtime.js.map +1 -1
  203. package/dist/types.d.ts +6 -0
  204. package/dist/types.js +10 -2
  205. package/dist/types.js.map +1 -1
  206. package/docs/AGENT_GUIDE.md +7 -1
  207. package/docs/ARCHITECTURE.md +1 -1
  208. package/docs/COMMANDS.md +39 -6
  209. package/docs/CONFIGURATION.md +1 -1
  210. package/docs/RELEASING.md +11 -7
  211. package/docs/SDK.md +11 -2
  212. package/package.json +12 -11
  213. package/packages/pm-calendar/README.md +3 -1
  214. package/packages/pm-calendar/extensions/calendar/index.js +21 -2
  215. package/packages/pm-calendar/extensions/calendar/index.ts +21 -2
  216. package/packages/pm-search-advanced/README.md +8 -0
  217. package/packages/pm-search-advanced/extensions/search-advanced/index.js +74 -0
  218. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +74 -0
  219. package/packages/pm-search-advanced/extensions/search-advanced/runtime.js +67 -9
  220. package/packages/pm-search-advanced/extensions/search-advanced/runtime.ts +67 -9
  221. package/packages/pm-templates/extensions/templates/runtime.js +11 -202
  222. package/packages/pm-templates/extensions/templates/runtime.ts +38 -230
  223. package/dist/core/output/command-aware.d.ts +0 -1
  224. package/dist/core/output/command-aware.js +0 -397
  225. package/dist/core/output/command-aware.js.map +0 -1
@@ -1,124 +1,25 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e775672d-e669-5b8d-bd54-5340390b2120")}catch(e){}}();
3
- import { pathExists } from "../../core/fs/fs-utils.js";
4
- import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
5
- import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
6
- import { EXIT_CODE } from "../../core/shared/constants.js";
7
- import { PmCliError } from "../../core/shared/errors.js";
8
- import { nowIso } from "../../core/shared/time.js";
9
- import { createStdinTokenResolver, parseCsvKv } from "../../core/item/parse.js";
10
- import { locateItem, mutateItem, readLocatedItem } from "../../core/store/item-store.js";
11
- import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
12
- import { readSettings } from "../../core/store/settings.js";
13
- import { parseLimit } from "../shared-parsers.js";
14
- function resolveAuthor(candidate, fallback) {
15
- const resolved = candidate ?? process.env.PM_AUTHOR ?? fallback;
16
- const trimmed = resolved.trim();
17
- return trimmed || "unknown";
18
- }
19
- function limitNotes(values, limit) {
20
- if (limit === undefined)
21
- return values;
22
- if (limit === 0)
23
- return [];
24
- return values.slice(Math.max(0, values.length - limit));
25
- }
26
- function parseNoteTextInput(raw) {
27
- const trimmed = raw.trim();
28
- if (!trimmed) {
29
- return "";
30
- }
31
- const looksStructured = /^(?:[-*+]\s*)?text\s*[:=]/im.test(trimmed) || trimmed.startsWith("```");
32
- if (!looksStructured) {
33
- return trimmed;
34
- }
35
- try {
36
- const kv = parseCsvKv(trimmed, "--add");
37
- const keys = Object.keys(kv).map((key) => key.trim().toLowerCase());
38
- if (keys.some((key) => key !== "text")) {
39
- return trimmed;
40
- }
41
- const text = kv.text?.trim();
42
- return text || trimmed;
43
- }
44
- catch {
45
- return trimmed;
46
- }
47
- }
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="60f1e397-2d8b-5ef9-a3e2-d4e20160ed6a")}catch(e){}}();
3
+ import { createStdinTokenResolver } from "../../core/item/parse.js";
4
+ import { parseAnnotationTextInput, runAnnotationCommand } from "./annotation-command.js";
48
5
  export async function runNotes(id, options, global) {
49
6
  const stdinResolver = createStdinTokenResolver();
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 settings = await readSettings(pmRoot);
55
- const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
56
- const limit = parseLimit(options.limit);
57
- if (options.add === undefined) {
58
- const located = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
59
- if (!located) {
60
- throw new PmCliError(`Item ${id} not found`, EXIT_CODE.NOT_FOUND);
61
- }
62
- const loaded = await readLocatedItem(located, { schema: settings.schema });
63
- const notes = limitNotes(loaded.document.metadata.notes ?? [], limit);
64
- return {
65
- id: located.id,
66
- notes,
67
- count: notes.length,
68
- };
69
- }
70
- const author = resolveAuthor(options.author, settings.author_default);
71
- const addInput = await stdinResolver.resolveValue(options.add, "--add");
72
- const text = parseNoteTextInput(addInput ?? "");
73
- if (!text) {
74
- throw new PmCliError("--add text cannot be empty", EXIT_CODE.USAGE);
75
- }
76
- let result;
77
- try {
78
- result = await mutateItem({
79
- pmRoot,
80
- settings,
81
- id,
82
- op: "note_add",
83
- author,
84
- message: options.message,
85
- force: options.force,
86
- bypassAssigneeConflict: Boolean(options.allowAuditNote || options.allowAuditComment),
87
- mutate(document) {
88
- const notes = document.metadata.notes ?? [];
89
- notes.push({
90
- created_at: nowIso(),
91
- author,
92
- text,
93
- });
94
- document.metadata.notes = notes;
95
- return { changedFields: ["notes"] };
96
- },
97
- });
98
- }
99
- catch (error) {
100
- if (error instanceof PmCliError &&
101
- error.exitCode === EXIT_CODE.CONFLICT &&
102
- error.message.includes("is assigned to") &&
103
- error.message.includes("Use --force to override")) {
104
- throw new PmCliError(error.message, error.exitCode, {
105
- code: "ownership_conflict",
106
- required: "For append-only note audits on another owner's item, prefer --allow-audit-note (legacy alias: --allow-audit-comment) before considering --force.",
107
- examples: ['pm notes pm-a1b2 --add "audit note" --author "reviewer" --allow-audit-note'],
108
- nextSteps: [
109
- "Retry with --allow-audit-note (or legacy --allow-audit-comment) for append-only note audits that do not mutate item metadata beyond notes.",
110
- "Use --force only when an ownership override is explicitly approved.",
111
- ],
112
- });
113
- }
114
- throw error;
115
- }
116
- const notes = limitNotes(result.item.notes, limit);
117
- return {
118
- id: result.item.id,
119
- notes,
120
- count: notes.length,
121
- };
7
+ const addInput = options.add === undefined ? undefined : await stdinResolver.resolveValue(options.add, "--add");
8
+ return runAnnotationCommand(id, options, global, {
9
+ input: options.add === undefined ? { mode: "list" } : { mode: "add", value: addInput ?? "", emptyFlag: "--add" },
10
+ collectionKey: "notes",
11
+ op: "note_add",
12
+ parseText: (raw) => parseAnnotationTextInput(raw),
13
+ allowAuditBypass: Boolean(options.allowAuditNote || options.allowAuditComment),
14
+ conflictGuidance: {
15
+ required: "For append-only note audits on another owner's item, prefer --allow-audit-note (legacy alias: --allow-audit-comment) before considering --force.",
16
+ examples: ['pm notes pm-a1b2 --add "audit note" --author "reviewer" --allow-audit-note'],
17
+ nextSteps: [
18
+ "Retry with --allow-audit-note (or legacy --allow-audit-comment) for append-only note audits that do not mutate item metadata beyond notes.",
19
+ "Use --force only when an ownership override is explicitly approved.",
20
+ ],
21
+ },
22
+ });
122
23
  }
123
24
  //# sourceMappingURL=notes.js.map
124
- //# debugId=e775672d-e669-5b8d-bd54-5340390b2120
25
+ //# debugId=60f1e397-2d8b-5ef9-a3e2-d4e20160ed6a
@@ -1 +1 @@
1
- {"version":3,"file":"notes.js","sources":["cli/commands/notes.ts"],"sourceRoot":"/","sourcesContent":["import { pathExists } from \"../../core/fs/fs-utils.js\";\nimport { getActiveExtensionRegistrations } from \"../../core/extensions/index.js\";\nimport { resolveItemTypeRegistry } from \"../../core/item/type-registry.js\";\nimport { EXIT_CODE } from \"../../core/shared/constants.js\";\nimport type { GlobalOptions } from \"../../core/shared/command-types.js\";\nimport { PmCliError } from \"../../core/shared/errors.js\";\nimport { nowIso } from \"../../core/shared/time.js\";\nimport { createStdinTokenResolver, parseCsvKv } from \"../../core/item/parse.js\";\nimport { locateItem, mutateItem, readLocatedItem } from \"../../core/store/item-store.js\";\nimport { getSettingsPath, resolvePmRoot } from \"../../core/store/paths.js\";\nimport { readSettings } from \"../../core/store/settings.js\";\nimport { parseLimit } from \"../shared-parsers.js\";\nimport type { LogNote } from \"../../types/index.js\";\n\nexport interface NotesCommandOptions {\n add?: string;\n limit?: string;\n author?: string;\n message?: string;\n allowAuditNote?: boolean;\n allowAuditComment?: boolean;\n force?: boolean;\n}\n\nexport interface NotesResult {\n id: string;\n notes: LogNote[];\n count: number;\n}\n\nfunction resolveAuthor(candidate: string | undefined, fallback: string): string {\n const resolved = candidate ?? process.env.PM_AUTHOR ?? fallback;\n const trimmed = resolved.trim();\n return trimmed || \"unknown\";\n}\n\nfunction limitNotes(values: LogNote[], limit: number | undefined): LogNote[] {\n if (limit === undefined) return values;\n if (limit === 0) return [];\n return values.slice(Math.max(0, values.length - limit));\n}\n\nfunction parseNoteTextInput(raw: string): string {\n const trimmed = raw.trim();\n if (!trimmed) {\n return \"\";\n }\n const looksStructured = /^(?:[-*+]\\s*)?text\\s*[:=]/im.test(trimmed) || trimmed.startsWith(\"```\");\n if (!looksStructured) {\n return trimmed;\n }\n try {\n const kv = parseCsvKv(trimmed, \"--add\");\n const keys = Object.keys(kv).map((key) => key.trim().toLowerCase());\n if (keys.some((key) => key !== \"text\")) {\n return trimmed;\n }\n const text = kv.text?.trim();\n return text || trimmed;\n } catch {\n return trimmed;\n }\n}\n\nexport async function runNotes(id: string, options: NotesCommandOptions, global: GlobalOptions): Promise<NotesResult> {\n const stdinResolver = createStdinTokenResolver();\n const pmRoot = resolvePmRoot(process.cwd(), global.path);\n if (!(await pathExists(getSettingsPath(pmRoot)))) {\n throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);\n }\n const settings = await readSettings(pmRoot);\n const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());\n const limit = parseLimit(options.limit);\n\n if (options.add === undefined) {\n const located = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);\n if (!located) {\n throw new PmCliError(`Item ${id} not found`, EXIT_CODE.NOT_FOUND);\n }\n const loaded = await readLocatedItem(located, { schema: settings.schema });\n const notes = limitNotes(loaded.document.metadata.notes ?? [], limit);\n return {\n id: located.id,\n notes,\n count: notes.length,\n };\n }\n\n const author = resolveAuthor(options.author, settings.author_default);\n const addInput = await stdinResolver.resolveValue(options.add, \"--add\");\n const text = parseNoteTextInput(addInput ?? \"\");\n if (!text) {\n throw new PmCliError(\"--add text cannot be empty\", EXIT_CODE.USAGE);\n }\n\n let result: Awaited<ReturnType<typeof mutateItem>>;\n try {\n result = await mutateItem({\n pmRoot,\n settings,\n id,\n op: \"note_add\",\n author,\n message: options.message,\n force: options.force,\n bypassAssigneeConflict: Boolean(options.allowAuditNote || options.allowAuditComment),\n mutate(document) {\n const notes = document.metadata.notes ?? [];\n notes.push({\n created_at: nowIso(),\n author,\n text,\n });\n document.metadata.notes = notes;\n return { changedFields: [\"notes\"] };\n },\n });\n } catch (error: unknown) {\n if (\n error instanceof PmCliError &&\n error.exitCode === EXIT_CODE.CONFLICT &&\n error.message.includes(\"is assigned to\") &&\n error.message.includes(\"Use --force to override\")\n ) {\n throw new PmCliError(error.message, error.exitCode, {\n code: \"ownership_conflict\",\n required:\n \"For append-only note audits on another owner's item, prefer --allow-audit-note (legacy alias: --allow-audit-comment) before considering --force.\",\n examples: ['pm notes pm-a1b2 --add \"audit note\" --author \"reviewer\" --allow-audit-note'],\n nextSteps: [\n \"Retry with --allow-audit-note (or legacy --allow-audit-comment) for append-only note audits that do not mutate item metadata beyond notes.\",\n \"Use --force only when an ownership override is explicitly approved.\",\n ],\n });\n }\n throw error;\n }\n\n const notes = limitNotes(result.item.notes as LogNote[], limit);\n return {\n id: result.item.id,\n notes,\n count: notes.length,\n };\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAmBlD,SAAS,aAAa,CAAC,SAA6B,EAAE,QAAgB;IACpE,MAAM,QAAQ,GAAG,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,QAAQ,CAAC;IAChE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChC,OAAO,OAAO,IAAI,SAAS,CAAC;AAC9B,CAAC;AAED,SAAS,UAAU,CAAC,MAAiB,EAAE,KAAyB;IAC9D,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3B,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACrC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,eAAe,GAAG,6BAA6B,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACjG,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QACpE,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,MAAM,CAAC,EAAE,CAAC;YACvC,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;QAC7B,OAAO,IAAI,IAAI,OAAO,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,EAAU,EAAE,OAA4B,EAAE,MAAqB;IAC5F,MAAM,aAAa,GAAG,wBAAwB,EAAE,CAAC;IACjD,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,YAAY,GAAG,uBAAuB,CAAC,QAAQ,EAAE,+BAA+B,EAAE,CAAC,CAAC;IAC1F,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAExC,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;QACpH,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,UAAU,CAAC,QAAQ,EAAE,YAAY,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QACpE,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3E,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;QACtE,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,MAAM;SACpB,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,kBAAkB,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,UAAU,CAAC,4BAA4B,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,MAA8C,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,UAAU,CAAC;YACxB,MAAM;YACN,QAAQ;YACR,EAAE;YACF,EAAE,EAAE,UAAU;YACd,MAAM;YACN,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,sBAAsB,EAAE,OAAO,CAAC,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC;YACpF,MAAM,CAAC,QAAQ;gBACb,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5C,KAAK,CAAC,IAAI,CAAC;oBACT,UAAU,EAAE,MAAM,EAAE;oBACpB,MAAM;oBACN,IAAI;iBACL,CAAC,CAAC;gBACH,QAAQ,CAAC,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;gBAChC,OAAO,EAAE,aAAa,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,IACE,KAAK,YAAY,UAAU;YAC3B,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,QAAQ;YACrC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACxC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EACjD,CAAC;YACD,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,EAAE;gBAClD,IAAI,EAAE,oBAAoB;gBAC1B,QAAQ,EACN,kJAAkJ;gBACpJ,QAAQ,EAAE,CAAC,4EAA4E,CAAC;gBACxF,SAAS,EAAE;oBACT,4IAA4I;oBAC5I,qEAAqE;iBACtE;aACF,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAkB,EAAE,KAAK,CAAC,CAAC;IAChE,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;QAClB,KAAK;QACL,KAAK,EAAE,KAAK,CAAC,MAAM;KACpB,CAAC;AACJ,CAAC","debugId":"e775672d-e669-5b8d-bd54-5340390b2120"}
1
+ {"version":3,"file":"notes.js","sources":["cli/commands/notes.ts"],"sourceRoot":"/","sourcesContent":["import type { GlobalOptions } from \"../../core/shared/command-types.js\";\nimport { createStdinTokenResolver } from \"../../core/item/parse.js\";\nimport type { LogNote } from \"../../types/index.js\";\nimport { parseAnnotationTextInput, runAnnotationCommand } from \"./annotation-command.js\";\n\nexport interface NotesCommandOptions {\n add?: string;\n limit?: string;\n author?: string;\n message?: string;\n allowAuditNote?: boolean;\n allowAuditComment?: boolean;\n force?: boolean;\n}\n\nexport interface NotesResult {\n id: string;\n notes: LogNote[];\n count: number;\n}\n\nexport async function runNotes(id: string, options: NotesCommandOptions, global: GlobalOptions): Promise<NotesResult> {\n const stdinResolver = createStdinTokenResolver();\n const addInput = options.add === undefined ? undefined : await stdinResolver.resolveValue(options.add, \"--add\");\n\n return runAnnotationCommand<\"notes\", LogNote>(id, options, global, {\n input: options.add === undefined ? { mode: \"list\" } : { mode: \"add\", value: addInput ?? \"\", emptyFlag: \"--add\" },\n collectionKey: \"notes\",\n op: \"note_add\",\n parseText: (raw) => parseAnnotationTextInput(raw),\n allowAuditBypass: Boolean(options.allowAuditNote || options.allowAuditComment),\n conflictGuidance: {\n required:\n \"For append-only note audits on another owner's item, prefer --allow-audit-note (legacy alias: --allow-audit-comment) before considering --force.\",\n examples: ['pm notes pm-a1b2 --add \"audit note\" --author \"reviewer\" --allow-audit-note'],\n nextSteps: [\n \"Retry with --allow-audit-note (or legacy --allow-audit-comment) for append-only note audits that do not mutate item metadata beyond notes.\",\n \"Use --force only when an ownership override is explicitly approved.\",\n ],\n },\n });\n}\n"],"names":[],"mappings":";;AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAkBzF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,EAAU,EAAE,OAA4B,EAAE,MAAqB;IAC5F,MAAM,aAAa,GAAG,wBAAwB,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAEhH,OAAO,oBAAoB,CAAmB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;QACjE,KAAK,EAAE,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;QAChH,aAAa,EAAE,OAAO;QACtB,EAAE,EAAE,UAAU;QACd,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,wBAAwB,CAAC,GAAG,CAAC;QACjD,gBAAgB,EAAE,OAAO,CAAC,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC;QAC9E,gBAAgB,EAAE;YAChB,QAAQ,EACN,kJAAkJ;YACpJ,QAAQ,EAAE,CAAC,4EAA4E,CAAC;YACxF,SAAS,EAAE;gBACT,4IAA4I;gBAC5I,qEAAqE;aACtE;SACF;KACF,CAAC,CAAC;AACL,CAAC","debugId":"60f1e397-2d8b-5ef9-a3e2-d4e20160ed6a"}
@@ -37,10 +37,13 @@ export interface PlanCommandOptions {
37
37
  test?: string | string[];
38
38
  doc?: string | string[];
39
39
  decisionText?: string;
40
+ decision?: string;
40
41
  decisionRationale?: string;
41
42
  decisionEvidence?: string;
42
43
  discoveryText?: string;
44
+ discovery?: string;
43
45
  validationText?: string;
46
+ validation?: string;
44
47
  validationCommand?: string;
45
48
  validationExpected?: string;
46
49
  depth?: string;
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="588c239a-66d0-5d60-b675-5a5a4e79d70b")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="55dd5c6d-22e8-50d4-a39c-f08a7db05b06")}catch(e){}}();
3
3
  import { pathExists } from "../../core/fs/fs-utils.js";
4
4
  import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
5
5
  import { resolveItemTypeRegistry, resolveTypeName } from "../../core/item/type-registry.js";
@@ -117,18 +117,53 @@ function parsePlanFields(raw) {
117
117
  }
118
118
  return fields;
119
119
  }
120
+ const PLAN_FIELD_KEYS = new Set([
121
+ "id",
122
+ "title",
123
+ "status",
124
+ "mode",
125
+ "scope",
126
+ "harness",
127
+ "parent",
128
+ "resume_context",
129
+ "steps_summary",
130
+ "current_step",
131
+ "blocked_steps",
132
+ "steps",
133
+ "decisions",
134
+ "discoveries",
135
+ "validation",
136
+ "linked_items",
137
+ ]);
120
138
  function projectPlanForFields(plan, fields) {
121
139
  const source = plan;
122
140
  const projected = {};
141
+ const unknownFields = [];
123
142
  for (const field of fields) {
124
143
  const normalized = field.startsWith("plan.") ? field.slice("plan.".length) : field;
125
144
  if (normalized.length === 0) {
126
145
  continue;
127
146
  }
147
+ if (!PLAN_FIELD_KEYS.has(normalized)) {
148
+ unknownFields.push(field);
149
+ continue;
150
+ }
128
151
  if (Object.prototype.hasOwnProperty.call(source, normalized)) {
129
152
  projected[normalized] = source[normalized];
130
153
  }
131
154
  }
155
+ if (unknownFields.length > 0) {
156
+ throw new PmCliError(`Unknown Plan --fields value(s): ${unknownFields.join(", ")}`, EXIT_CODE.USAGE, {
157
+ nextSteps: [
158
+ `Use --fields ${[...PLAN_FIELD_KEYS].join(",")}`,
159
+ "Run pm plan show <id> --depth brief for compact default fields.",
160
+ ],
161
+ recovery: {
162
+ provided_fields: unknownFields,
163
+ suggested_retry: `pm plan show <id> --fields ${[...PLAN_FIELD_KEYS].join(",")}`,
164
+ },
165
+ });
166
+ }
132
167
  return projected;
133
168
  }
134
169
  function parsePairList(raw, label) {
@@ -224,6 +259,38 @@ function resolveStepRef(steps, ref) {
224
259
  }
225
260
  throw new PmCliError(`Step "${ref}" not found in plan`, EXIT_CODE.NOT_FOUND);
226
261
  }
262
+ function resolveMaterializeTargets(steps, refs) {
263
+ const allRefs = refs.filter((ref) => ref.trim().toLowerCase() === "all");
264
+ if (allRefs.length > 0) {
265
+ if (refs.length > allRefs.length) {
266
+ throw new PmCliError("pm plan materialize --steps all cannot be combined with other step refs", EXIT_CODE.USAGE);
267
+ }
268
+ return steps.slice().sort((left, right) => left.order - right.order);
269
+ }
270
+ const targets = [];
271
+ const seen = new Set();
272
+ for (const ref of refs) {
273
+ const step = resolveStepRef(steps, ref);
274
+ if (seen.has(step.id))
275
+ continue;
276
+ targets.push(step);
277
+ seen.add(step.id);
278
+ }
279
+ return targets;
280
+ }
281
+ function resolvePlanLogText(kind, options) {
282
+ const canonical = kind === "decision"
283
+ ? options.decisionText
284
+ : kind === "discovery"
285
+ ? options.discoveryText
286
+ : options.validationText;
287
+ const shorthand = kind === "decision"
288
+ ? options.decision
289
+ : kind === "discovery"
290
+ ? options.discovery
291
+ : options.validation;
292
+ return canonical?.trim() || shorthand?.trim() || undefined;
293
+ }
227
294
  function findCurrentStep(steps) {
228
295
  return steps.find((step) => step.status === "in_progress")
229
296
  ?? steps.find((step) => step.status === "pending");
@@ -285,7 +352,15 @@ function nextActionsFor(planId, plan) {
285
352
  function ensurePlanItem(item) {
286
353
  const normalizedType = (item.type ?? "").trim().toLowerCase();
287
354
  if (normalizedType !== "plan") {
288
- throw new PmCliError(`Item ${item.id} is type ${item.type}; pm plan commands require type=Plan. Use pm plan create or pm create --type Plan first.`, EXIT_CODE.USAGE);
355
+ throw new PmCliError(`Item ${item.id} is type ${item.type}; pm plan commands require type=Plan. Use pm plan create or pm create --type Plan first.`, EXIT_CODE.USAGE, {
356
+ code: "wrong_item_type",
357
+ required: "Use pm plan commands only with items whose type is Plan.",
358
+ why: "Plan commands read and mutate Plan-specific step, decision, discovery, and validation fields.",
359
+ examples: [
360
+ `pm get ${item.id} --depth brief`,
361
+ 'pm plan create --title "Execution plan" --scope "<goal>"',
362
+ ],
363
+ });
289
364
  }
290
365
  }
291
366
  async function loadContext(global) {
@@ -373,6 +448,91 @@ async function planCreate(options, global, ctx) {
373
448
  },
374
449
  });
375
450
  let finalMetadata = seedResult.item;
451
+ let initialStep;
452
+ const initialValidationText = options.validationText?.trim();
453
+ const initialValidationCommand = options.validationCommand?.trim();
454
+ const initialValidationExpected = options.validationExpected?.trim();
455
+ const initialValidation = initialValidationText || initialValidationCommand || initialValidationExpected
456
+ ? {
457
+ text: initialValidationText || initialValidationCommand || "Validation check",
458
+ command: initialValidationCommand || undefined,
459
+ expected: initialValidationExpected || undefined,
460
+ }
461
+ : undefined;
462
+ if (options.stepTitle?.trim()) {
463
+ const status = asStepStatus(options.stepStatus, "pending");
464
+ const linkedItems = buildLinkInputs(options, "depends_on");
465
+ const files = toSpecArray(options.file).map(parseStepFile);
466
+ const tests = toSpecArray(options.test).map(parseStepTest);
467
+ const docs = toSpecArray(options.doc).map(parseStepDoc);
468
+ const now = nowIso();
469
+ initialStep = {
470
+ id: "plan-step-001",
471
+ order: 1,
472
+ title: options.stepTitle.trim(),
473
+ body: options.stepBody?.trim() || undefined,
474
+ status,
475
+ owner: options.stepOwner?.trim() || undefined,
476
+ evidence: options.stepEvidence?.trim() || undefined,
477
+ blocked_reason: status === "blocked" ? options.stepBlockedReason?.trim() || "" : undefined,
478
+ linked_items: linkedItems.length > 0 ? linkedItems : undefined,
479
+ files: files.length > 0 ? files : undefined,
480
+ tests: tests.length > 0 ? tests : undefined,
481
+ docs: docs.length > 0 ? docs : undefined,
482
+ created_at: now,
483
+ updated_at: now,
484
+ completed_at: status === "completed" ? now : undefined,
485
+ };
486
+ const stepped = await mutateItem({
487
+ pmRoot: ctx.pmRoot,
488
+ settings: ctx.settings,
489
+ id: createResult.item.id,
490
+ op: "plan_create_initial_step",
491
+ author: resolveAuthor(options.author, ctx.settings.author_default),
492
+ message: `plan create initial step "${initialStep.title}"`,
493
+ mutate(doc) {
494
+ ensurePlanItem(doc.metadata);
495
+ doc.metadata.plan_steps = [initialStep];
496
+ if (initialValidation) {
497
+ doc.metadata.plan_validation = [...(doc.metadata.plan_validation ?? []), initialValidation];
498
+ }
499
+ return { changedFields: initialValidation ? ["plan_steps", "plan_validation"] : ["plan_steps"] };
500
+ },
501
+ });
502
+ finalMetadata = stepped.item;
503
+ }
504
+ else if (initialValidation) {
505
+ const validated = await mutateItem({
506
+ pmRoot: ctx.pmRoot,
507
+ settings: ctx.settings,
508
+ id: createResult.item.id,
509
+ op: "plan_create_initial_validation",
510
+ author: resolveAuthor(options.author, ctx.settings.author_default),
511
+ message: "plan create initial validation",
512
+ mutate(doc) {
513
+ ensurePlanItem(doc.metadata);
514
+ doc.metadata.plan_validation = [...(doc.metadata.plan_validation ?? []), initialValidation];
515
+ return { changedFields: ["plan_validation"] };
516
+ },
517
+ });
518
+ finalMetadata = validated.item;
519
+ }
520
+ else if (options.stepBody?.trim() ||
521
+ options.stepOwner?.trim() ||
522
+ options.stepStatus?.trim() ||
523
+ options.stepEvidence?.trim() ||
524
+ options.stepBlockedReason?.trim() ||
525
+ options.stepReplacement?.trim() ||
526
+ toArray(options.dependsOn).length > 0 ||
527
+ toArray(options.link).length > 0 ||
528
+ toSpecArray(options.file).length > 0 ||
529
+ toSpecArray(options.test).length > 0 ||
530
+ toSpecArray(options.doc).length > 0) {
531
+ throw new PmCliError("pm plan create step options require --step-title", EXIT_CODE.USAGE, {
532
+ code: "missing_required_option",
533
+ examples: ['pm plan create --title "Execution plan" --step-title "Read the code"'],
534
+ });
535
+ }
376
536
  if (options.claim) {
377
537
  const claimed = await mutateItem({
378
538
  pmRoot: ctx.pmRoot,
@@ -392,6 +552,7 @@ async function planCreate(options, global, ctx) {
392
552
  return {
393
553
  action: "create",
394
554
  plan,
555
+ step: initialStep,
395
556
  next_actions: nextActionsFor(createResult.item.id, plan),
396
557
  warnings: [...createResult.warnings],
397
558
  generated_at: nowIso(),
@@ -401,7 +562,7 @@ async function planShow(id, options, ctx) {
401
562
  const depth = asDepth(options.depth);
402
563
  const fields = parsePlanFields(options.fields);
403
564
  const { document, itemId } = await readPlanItem(ctx, id);
404
- const fullPlan = projectPlan(document.metadata, depth);
565
+ const fullPlan = projectPlan(document.metadata, fields === null ? depth : "deep");
405
566
  const plan = fields === null ? fullPlan : projectPlanForFields(fullPlan, fields);
406
567
  return {
407
568
  action: "show",
@@ -720,14 +881,20 @@ async function planUnlink(id, options, ctx, stepRef) {
720
881
  };
721
882
  }
722
883
  async function planAppendLog(id, options, ctx, kind) {
723
- if (kind === "decision" && !options.decisionText?.trim()) {
724
- throw new PmCliError("pm plan decision requires --decision-text", EXIT_CODE.USAGE);
725
- }
726
- if (kind === "discovery" && !options.discoveryText?.trim()) {
727
- throw new PmCliError("pm plan discovery requires --discovery-text", EXIT_CODE.USAGE);
728
- }
729
- if (kind === "validation" && !options.validationText?.trim()) {
730
- throw new PmCliError("pm plan validation requires --validation-text", EXIT_CODE.USAGE);
884
+ const logText = resolvePlanLogText(kind, options);
885
+ if (!logText) {
886
+ const canonical = `--${kind}-text`;
887
+ const shorthand = `--${kind}`;
888
+ throw new PmCliError(`pm plan ${kind} requires ${canonical}`, EXIT_CODE.USAGE, {
889
+ code: "missing_required_option",
890
+ examples: [
891
+ `pm plan ${kind} <plan-id> ${canonical} "..."`,
892
+ `pm plan ${kind} <plan-id> ${shorthand} "..."`,
893
+ ],
894
+ recovery: {
895
+ suggested_retry: `pm plan ${kind} <plan-id> ${canonical} <value>`,
896
+ },
897
+ });
731
898
  }
732
899
  const author = resolveAuthor(options.author, ctx.settings.author_default);
733
900
  const { document, itemId } = await mutatePlanSteps({
@@ -743,7 +910,7 @@ async function planAppendLog(id, options, ctx, kind) {
743
910
  list.push({
744
911
  ts: now,
745
912
  author,
746
- decision: options.decisionText.trim(),
913
+ decision: logText,
747
914
  rationale: options.decisionRationale?.trim() || undefined,
748
915
  evidence: options.decisionEvidence?.trim() || undefined,
749
916
  });
@@ -752,13 +919,13 @@ async function planAppendLog(id, options, ctx, kind) {
752
919
  }
753
920
  if (kind === "discovery") {
754
921
  const list = doc.metadata.plan_discoveries ?? [];
755
- list.push({ ts: now, author, text: options.discoveryText.trim() });
922
+ list.push({ ts: now, author, text: logText });
756
923
  doc.metadata.plan_discoveries = list;
757
924
  return { changedSteps: [] };
758
925
  }
759
926
  const list = doc.metadata.plan_validation ?? [];
760
927
  list.push({
761
- text: options.validationText.trim(),
928
+ text: logText,
762
929
  command: options.validationCommand?.trim() || undefined,
763
930
  expected: options.validationExpected?.trim() || undefined,
764
931
  });
@@ -825,7 +992,7 @@ async function planApprove(id, options, ctx) {
825
992
  async function planMaterialize(id, options, ctx) {
826
993
  const stepRefs = toArray(options.steps);
827
994
  if (stepRefs.length === 0) {
828
- throw new PmCliError("pm plan materialize requires --steps <ids|orders>", EXIT_CODE.USAGE);
995
+ throw new PmCliError("pm plan materialize requires --steps <ids|orders|all>", EXIT_CODE.USAGE);
829
996
  }
830
997
  const targetType = options.materializeType?.trim() || "Task";
831
998
  const typeRegistry = resolveItemTypeRegistry(ctx.settings, getActiveExtensionRegistrations());
@@ -837,7 +1004,7 @@ async function planMaterialize(id, options, ctx) {
837
1004
  const tags = options.materializeTags;
838
1005
  const planRead = await readPlanItem(ctx, id);
839
1006
  const steps = (planRead.document.metadata.plan_steps ?? []).slice();
840
- const targets = stepRefs.map((ref) => resolveStepRef(steps, ref));
1007
+ const targets = resolveMaterializeTargets(steps, stepRefs);
841
1008
  if (targets.length === 0) {
842
1009
  throw new PmCliError("No matching plan steps found for --steps", EXIT_CODE.NOT_FOUND);
843
1010
  }
@@ -884,11 +1051,6 @@ async function planMaterialize(id, options, ctx) {
884
1051
  step.linked_items = links;
885
1052
  step.updated_at = nowIso();
886
1053
  }
887
- const deps = doc.metadata.dependencies ?? [];
888
- for (const m of materialized) {
889
- deps.push({ id: m.id, kind: "child", created_at: nowIso(), author: resolveAuthor(options.author, ctx.settings.author_default) });
890
- }
891
- doc.metadata.dependencies = deps;
892
1054
  return { changedSteps: targets.map((entry) => entry.id) };
893
1055
  },
894
1056
  });
@@ -972,4 +1134,4 @@ export async function runPlan(input) {
972
1134
  }
973
1135
  }
974
1136
  //# sourceMappingURL=plan.js.map
975
- //# debugId=588c239a-66d0-5d60-b675-5a5a4e79d70b
1137
+ //# debugId=55dd5c6d-22e8-50d4-a39c-f08a7db05b06