@unbrained/pm-cli 2026.5.10 → 2026.5.11

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 (124) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/.pi/README.md +10 -1
  3. package/.pi/agents/pm-triage-agent.md +19 -0
  4. package/.pi/agents/pm-verification-agent.md +21 -0
  5. package/.pi/chains/pm-native-delivery.chain.md +11 -0
  6. package/.pi/extensions/pm-cli/index.js +276 -36
  7. package/.pi/skills/pm-native/SKILL.md +6 -2
  8. package/CHANGELOG.md +7 -0
  9. package/README.md +9 -1
  10. package/dist/cli/argv-utils.d.ts +5 -0
  11. package/dist/cli/argv-utils.js +34 -0
  12. package/dist/cli/argv-utils.js.map +1 -0
  13. package/dist/cli/bootstrap-args.d.ts +15 -0
  14. package/dist/cli/bootstrap-args.js +211 -0
  15. package/dist/cli/bootstrap-args.js.map +1 -1
  16. package/dist/cli/commander-usage.js +109 -3
  17. package/dist/cli/commander-usage.js.map +1 -1
  18. package/dist/cli/commands/completion.js +7 -3
  19. package/dist/cli/commands/completion.js.map +1 -1
  20. package/dist/cli/commands/contracts.d.ts +19 -0
  21. package/dist/cli/commands/contracts.js +33 -1
  22. package/dist/cli/commands/contracts.js.map +1 -1
  23. package/dist/cli/commands/create.js +112 -51
  24. package/dist/cli/commands/create.js.map +1 -1
  25. package/dist/cli/commands/docs.js +9 -2
  26. package/dist/cli/commands/docs.js.map +1 -1
  27. package/dist/cli/commands/extension.d.ts +3 -1
  28. package/dist/cli/commands/extension.js +174 -2
  29. package/dist/cli/commands/extension.js.map +1 -1
  30. package/dist/cli/commands/files.js +9 -2
  31. package/dist/cli/commands/files.js.map +1 -1
  32. package/dist/cli/commands/init.d.ts +2 -0
  33. package/dist/cli/commands/init.js +21 -1
  34. package/dist/cli/commands/init.js.map +1 -1
  35. package/dist/cli/commands/metadata-normalizers.d.ts +4 -0
  36. package/dist/cli/commands/metadata-normalizers.js +37 -0
  37. package/dist/cli/commands/metadata-normalizers.js.map +1 -0
  38. package/dist/cli/commands/reindex.js +173 -135
  39. package/dist/cli/commands/reindex.js.map +1 -1
  40. package/dist/cli/commands/search.js +16 -6
  41. package/dist/cli/commands/search.js.map +1 -1
  42. package/dist/cli/commands/test.js +9 -2
  43. package/dist/cli/commands/test.js.map +1 -1
  44. package/dist/cli/commands/update.js +70 -39
  45. package/dist/cli/commands/update.js.map +1 -1
  46. package/dist/cli/error-guidance.d.ts +9 -1
  47. package/dist/cli/error-guidance.js +147 -6
  48. package/dist/cli/error-guidance.js.map +1 -1
  49. package/dist/cli/help-json-payload.js +11 -1
  50. package/dist/cli/help-json-payload.js.map +1 -1
  51. package/dist/cli/main.js +69 -6
  52. package/dist/cli/main.js.map +1 -1
  53. package/dist/cli/register-setup.js +14 -0
  54. package/dist/cli/register-setup.js.map +1 -1
  55. package/dist/cli/telemetry-flush.d.ts +2 -0
  56. package/dist/cli/telemetry-flush.js +4 -0
  57. package/dist/cli/telemetry-flush.js.map +1 -0
  58. package/dist/cli.js +1 -2
  59. package/dist/cli.js.map +1 -1
  60. package/dist/core/extensions/extension-types.d.ts +72 -0
  61. package/dist/core/extensions/extension-types.js +24 -0
  62. package/dist/core/extensions/extension-types.js.map +1 -1
  63. package/dist/core/extensions/loader.d.ts +1 -0
  64. package/dist/core/extensions/loader.js +766 -7
  65. package/dist/core/extensions/loader.js.map +1 -1
  66. package/dist/core/lock/lock.js +2 -0
  67. package/dist/core/lock/lock.js.map +1 -1
  68. package/dist/core/sentry/instrument.d.ts +15 -0
  69. package/dist/core/sentry/instrument.js +35 -3
  70. package/dist/core/sentry/instrument.js.map +1 -1
  71. package/dist/core/shared/constants.js +20 -0
  72. package/dist/core/shared/constants.js.map +1 -1
  73. package/dist/core/shared/errors.d.ts +8 -0
  74. package/dist/core/shared/errors.js.map +1 -1
  75. package/dist/core/shared/levenshtein.d.ts +1 -0
  76. package/dist/core/shared/levenshtein.js +37 -0
  77. package/dist/core/shared/levenshtein.js.map +1 -0
  78. package/dist/core/store/paths.js +34 -1
  79. package/dist/core/store/paths.js.map +1 -1
  80. package/dist/core/store/settings.js +210 -1
  81. package/dist/core/store/settings.js.map +1 -1
  82. package/dist/core/telemetry/runtime.d.ts +1 -0
  83. package/dist/core/telemetry/runtime.js +102 -3
  84. package/dist/core/telemetry/runtime.js.map +1 -1
  85. package/dist/mcp/server.js +3 -1
  86. package/dist/mcp/server.js.map +1 -1
  87. package/dist/pi/native.js +57 -4
  88. package/dist/pi/native.js.map +1 -1
  89. package/dist/sdk/cli-contracts.d.ts +21 -1
  90. package/dist/sdk/cli-contracts.js +250 -0
  91. package/dist/sdk/cli-contracts.js.map +1 -1
  92. package/dist/sdk/index.d.ts +12 -1
  93. package/dist/sdk/index.js +8 -1
  94. package/dist/sdk/index.js.map +1 -1
  95. package/dist/types.d.ts +41 -0
  96. package/dist/types.js.map +1 -1
  97. package/docs/CLAUDE_CODE_PLUGIN.md +39 -0
  98. package/docs/EXTENSIONS.md +687 -0
  99. package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
  100. package/docs/PI_PACKAGE.md +95 -10
  101. package/docs/SDK.md +441 -0
  102. package/docs/examples/ci/github-actions-pm-extension-gate.yml +53 -0
  103. package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +41 -0
  104. package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +45 -0
  105. package/docs/examples/policy-restricted-extension/README.md +74 -0
  106. package/docs/examples/policy-restricted-extension/index.js +21 -0
  107. package/docs/examples/policy-restricted-extension/manifest.json +21 -0
  108. package/docs/examples/policy-restricted-extension/package.json +8 -0
  109. package/docs/examples/sdk-app-embedding/README.md +39 -0
  110. package/docs/examples/sdk-app-embedding/package.json +9 -0
  111. package/docs/examples/sdk-app-embedding/run-embedded-pm.mjs +61 -0
  112. package/docs/examples/sdk-contract-consumer/README.md +57 -0
  113. package/docs/examples/sdk-contract-consumer/inspect-contracts.mjs +47 -0
  114. package/docs/examples/sdk-contract-consumer/package.json +10 -0
  115. package/docs/examples/starter-extension/README.md +57 -42
  116. package/docs/examples/starter-extension/manifest.json +15 -0
  117. package/marketplace.json +3 -3
  118. package/package.json +1 -1
  119. package/plugins/pm-cli-claude/.claude-plugin/plugin.json +2 -2
  120. package/plugins/pm-cli-claude/README.md +55 -14
  121. package/plugins/pm-cli-claude/agents/pm-delivery-chain.md +88 -0
  122. package/plugins/pm-cli-claude/agents/pm-triage-agent.md +83 -0
  123. package/plugins/pm-cli-claude/agents/pm-verification-agent.md +88 -0
  124. package/plugins/pm-cli-claude/hooks/session-start.mjs +87 -22
@@ -15,7 +15,8 @@ import { applyRegisteredItemFieldDefaultsAndValidation } from "../../core/extens
15
15
  import { locateItem, mutateItem } from "../../core/store/item-store.js";
16
16
  import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
17
17
  import { readSettings } from "../../core/store/settings.js";
18
- import { CONFIDENCE_TEXT_VALUES, DEPENDENCY_KIND_VALUES, ISSUE_SEVERITY_VALUES, RECURRENCE_FREQUENCY_VALUES, RECURRENCE_WEEKDAY_VALUES, RISK_VALUES, } from "../../types/index.js";
18
+ import { normalizeRiskInput, normalizeSeverityInput, parseConfidenceInput, parseRegressionInput, } from "./metadata-normalizers.js";
19
+ import { DEPENDENCY_KIND_VALUES, ISSUE_SEVERITY_VALUES, RECURRENCE_FREQUENCY_VALUES, RECURRENCE_WEEKDAY_VALUES, RISK_VALUES, } from "../../types/index.js";
19
20
  import { parseDocs, parseFiles, parseLogSeed, parseTests } from "./create.js";
20
21
  const LEGACY_NONE_TOKENS = new Set(["none", "null"]);
21
22
  const UPDATE_UNSET_FIELD_DEFINITIONS = [
@@ -187,6 +188,61 @@ function assertNoLegacyNoneTokens(values, flag, replacementHint) {
187
188
  const suffix = replacementHint ? ` ${replacementHint}` : "";
188
189
  throw new PmCliError(`${flag} no longer accepts "none" or "null".${suffix}`.trim(), EXIT_CODE.USAGE);
189
190
  }
191
+ const UPDATE_LEGACY_NONE_COLLECTION_NORMALIZERS = [
192
+ { optionKey: "dep", clearFlagKey: "clearDeps", valueFlag: "--dep", clearFlag: "--clear-deps", disableReplaceFlagKey: "replaceDeps" },
193
+ { optionKey: "comment", clearFlagKey: "clearComments", valueFlag: "--comment", clearFlag: "--clear-comments" },
194
+ { optionKey: "note", clearFlagKey: "clearNotes", valueFlag: "--note", clearFlag: "--clear-notes" },
195
+ { optionKey: "learning", clearFlagKey: "clearLearnings", valueFlag: "--learning", clearFlag: "--clear-learnings" },
196
+ { optionKey: "file", clearFlagKey: "clearFiles", valueFlag: "--file", clearFlag: "--clear-files" },
197
+ { optionKey: "test", clearFlagKey: "clearTests", valueFlag: "--test", clearFlag: "--clear-tests", disableReplaceFlagKey: "replaceTests" },
198
+ { optionKey: "doc", clearFlagKey: "clearDocs", valueFlag: "--doc", clearFlag: "--clear-docs" },
199
+ { optionKey: "reminder", clearFlagKey: "clearReminders", valueFlag: "--reminder", clearFlag: "--clear-reminders" },
200
+ { optionKey: "event", clearFlagKey: "clearEvents", valueFlag: "--event", clearFlag: "--clear-events" },
201
+ { optionKey: "typeOption", clearFlagKey: "clearTypeOptions", valueFlag: "--type-option", clearFlag: "--clear-type-options" },
202
+ ];
203
+ function normalizeLegacyNoneUpdateOptions(options) {
204
+ const normalized = {
205
+ ...options,
206
+ unset: options.unset ? [...options.unset] : undefined,
207
+ };
208
+ const appendUnsetTarget = (value) => {
209
+ const current = normalized.unset ? [...normalized.unset] : [];
210
+ if (!current.includes(value)) {
211
+ current.push(value);
212
+ }
213
+ normalized.unset = current;
214
+ };
215
+ const scalarOptionKeys = new Set([...UPDATE_OPTION_KEY_TO_UNSET_CANONICAL.keys(), "rank"]);
216
+ for (const optionKey of scalarOptionKeys) {
217
+ const candidate = normalized[optionKey];
218
+ if (typeof candidate !== "string" || !isLegacyNoneToken(candidate)) {
219
+ continue;
220
+ }
221
+ const canonicalUnset = optionKey === "rank" ? "order" : (UPDATE_OPTION_KEY_TO_UNSET_CANONICAL.get(optionKey) ?? optionKey);
222
+ appendUnsetTarget(canonicalUnset);
223
+ normalized[optionKey] = undefined;
224
+ }
225
+ for (const definition of UPDATE_LEGACY_NONE_COLLECTION_NORMALIZERS) {
226
+ const entries = normalized[definition.optionKey];
227
+ if (!Array.isArray(entries) || entries.length === 0) {
228
+ continue;
229
+ }
230
+ const hasLegacy = entries.some((entry) => isLegacyNoneToken(entry));
231
+ if (!hasLegacy) {
232
+ continue;
233
+ }
234
+ const concreteEntries = entries.filter((entry) => !isLegacyNoneToken(entry));
235
+ if (concreteEntries.length > 0) {
236
+ throw new PmCliError(`Cannot mix legacy clear token "none"/"null" with concrete ${definition.valueFlag} entries. Use ${definition.clearFlag} to clear or provide explicit entries.`, EXIT_CODE.USAGE);
237
+ }
238
+ normalized[definition.optionKey] = undefined;
239
+ normalized[definition.clearFlagKey] = true;
240
+ if (definition.disableReplaceFlagKey) {
241
+ normalized[definition.disableReplaceFlagKey] = false;
242
+ }
243
+ }
244
+ return normalized;
245
+ }
190
246
  function resolveRuntimeUnsetDefinition(token, runtimeFieldRegistry) {
191
247
  if (!runtimeFieldRegistry) {
192
248
  return undefined;
@@ -433,38 +489,6 @@ function parseStatus(value, statusRegistry) {
433
489
  }
434
490
  return normalized;
435
491
  }
436
- function normalizeRiskInput(value) {
437
- const trimmed = value.trim();
438
- return trimmed.toLowerCase() === "med" ? "medium" : trimmed;
439
- }
440
- function normalizeSeverityInput(value) {
441
- const trimmed = value.trim();
442
- return trimmed.toLowerCase() === "med" ? "medium" : trimmed;
443
- }
444
- function parseConfidenceInput(value) {
445
- const trimmed = value.trim().toLowerCase();
446
- if (trimmed === "med") {
447
- return "medium";
448
- }
449
- if (CONFIDENCE_TEXT_VALUES.includes(trimmed)) {
450
- return trimmed;
451
- }
452
- const parsed = parseOptionalNumber(value, "confidence");
453
- if (!Number.isInteger(parsed) || parsed < 0 || parsed > 100) {
454
- throw new PmCliError("Confidence must be an integer 0..100 or one of low|med|medium|high", EXIT_CODE.USAGE);
455
- }
456
- return parsed;
457
- }
458
- function parseRegressionInput(value) {
459
- const normalized = value.trim().toLowerCase();
460
- if (normalized === "true" || normalized === "1") {
461
- return true;
462
- }
463
- if (normalized === "false" || normalized === "0") {
464
- return false;
465
- }
466
- throw new PmCliError("Regression must be one of true|false|1|0", EXIT_CODE.USAGE);
467
- }
468
492
  function weekdayOrderIndex(value) {
469
493
  return RECURRENCE_WEEKDAY_VALUES.indexOf(value);
470
494
  }
@@ -554,9 +578,9 @@ function parseRecurrenceRule(kv, startAt, nowValue) {
554
578
  function parseEventEntries(raw, nowValue) {
555
579
  return raw.map((entry) => {
556
580
  const kv = parseCsvKv(entry, "--event");
557
- const startRaw = kv.start?.trim();
581
+ const startRaw = (kv.start ?? kv.date)?.trim();
558
582
  if (!startRaw) {
559
- throw new PmCliError("--event requires start=<iso|relative>", EXIT_CODE.USAGE);
583
+ throw new PmCliError("--event requires start=<iso|relative> or date=<iso|relative>", EXIT_CODE.USAGE);
560
584
  }
561
585
  const startAt = resolveIsoOrRelative(startRaw, nowValue, "event.start");
562
586
  const endRaw = kv.end?.trim();
@@ -652,17 +676,24 @@ function parseOptionalDependencyString(value) {
652
676
  const trimmed = value.trim();
653
677
  return trimmed.length > 0 ? trimmed : undefined;
654
678
  }
679
+ function looksLikeStructuredDependencyEntry(raw) {
680
+ if (raw.startsWith("```") || raw.includes("\n")) {
681
+ return true;
682
+ }
683
+ return /^(?:[-*+]\s+)?(?:id|kind|author|created_at|source_kind)\s*[:=]/i.test(raw);
684
+ }
655
685
  function parseDependencyAdditions(raw, prefix, nowIso) {
656
686
  if (!raw) {
657
687
  return { additions: [] };
658
688
  }
659
689
  assertNoLegacyNoneTokens(raw, "--dep", "Use --clear-deps to clear dependencies.");
660
690
  const additions = raw.map((entry) => {
661
- const kv = parseCsvKv(entry, "--dep");
691
+ const trimmedEntry = entry.trim();
692
+ const kv = looksLikeStructuredDependencyEntry(trimmedEntry) ? parseCsvKv(entry, "--dep") : { id: trimmedEntry, kind: "related" };
662
693
  const id = kv.id?.trim();
663
694
  const kind = kv.kind?.trim();
664
695
  if (!id || !kind) {
665
- throw new PmCliError("--dep requires id and kind", EXIT_CODE.USAGE);
696
+ throw new PmCliError("--dep requires id and kind, or a bare item id to add a related dependency", EXIT_CODE.USAGE);
666
697
  }
667
698
  if (id.toLowerCase() === "undefined") {
668
699
  throw new PmCliError(`--dep id must not use placeholder token "${id}". Use --clear-deps to clear dependencies.`, EXIT_CODE.USAGE);
@@ -857,7 +888,7 @@ function enforceUpdateOptionsByType(typeName, options, typeRegistry) {
857
888
  }
858
889
  export async function runUpdate(id, options, global) {
859
890
  const stdinResolver = createStdinTokenResolver();
860
- options = {
891
+ options = normalizeLegacyNoneUpdateOptions({
861
892
  ...options,
862
893
  body: await stdinResolver.resolveValue(options.body, "--body"),
863
894
  dep: await stdinResolver.resolveList(options.dep, "--dep"),
@@ -871,7 +902,7 @@ export async function runUpdate(id, options, global) {
871
902
  reminder: await stdinResolver.resolveList(options.reminder, "--reminder"),
872
903
  event: await stdinResolver.resolveList(options.event, "--event"),
873
904
  typeOption: await stdinResolver.resolveList(options.typeOption, "--type-option"),
874
- };
905
+ });
875
906
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
876
907
  if (!(await pathExists(getSettingsPath(pmRoot)))) {
877
908
  throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);