@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.
- package/.claude-plugin/marketplace.json +4 -4
- package/.pi/README.md +10 -1
- package/.pi/agents/pm-triage-agent.md +19 -0
- package/.pi/agents/pm-verification-agent.md +21 -0
- package/.pi/chains/pm-native-delivery.chain.md +11 -0
- package/.pi/extensions/pm-cli/index.js +276 -36
- package/.pi/skills/pm-native/SKILL.md +6 -2
- package/CHANGELOG.md +7 -0
- package/README.md +9 -1
- package/dist/cli/argv-utils.d.ts +5 -0
- package/dist/cli/argv-utils.js +34 -0
- package/dist/cli/argv-utils.js.map +1 -0
- package/dist/cli/bootstrap-args.d.ts +15 -0
- package/dist/cli/bootstrap-args.js +211 -0
- package/dist/cli/bootstrap-args.js.map +1 -1
- package/dist/cli/commander-usage.js +109 -3
- package/dist/cli/commander-usage.js.map +1 -1
- package/dist/cli/commands/completion.js +7 -3
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/contracts.d.ts +19 -0
- package/dist/cli/commands/contracts.js +33 -1
- package/dist/cli/commands/contracts.js.map +1 -1
- package/dist/cli/commands/create.js +112 -51
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/docs.js +9 -2
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.d.ts +3 -1
- package/dist/cli/commands/extension.js +174 -2
- package/dist/cli/commands/extension.js.map +1 -1
- package/dist/cli/commands/files.js +9 -2
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.js +21 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/metadata-normalizers.d.ts +4 -0
- package/dist/cli/commands/metadata-normalizers.js +37 -0
- package/dist/cli/commands/metadata-normalizers.js.map +1 -0
- package/dist/cli/commands/reindex.js +173 -135
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/search.js +16 -6
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/test.js +9 -2
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update.js +70 -39
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/error-guidance.d.ts +9 -1
- package/dist/cli/error-guidance.js +147 -6
- package/dist/cli/error-guidance.js.map +1 -1
- package/dist/cli/help-json-payload.js +11 -1
- package/dist/cli/help-json-payload.js.map +1 -1
- package/dist/cli/main.js +69 -6
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/register-setup.js +14 -0
- package/dist/cli/register-setup.js.map +1 -1
- package/dist/cli/telemetry-flush.d.ts +2 -0
- package/dist/cli/telemetry-flush.js +4 -0
- package/dist/cli/telemetry-flush.js.map +1 -0
- package/dist/cli.js +1 -2
- package/dist/cli.js.map +1 -1
- package/dist/core/extensions/extension-types.d.ts +72 -0
- package/dist/core/extensions/extension-types.js +24 -0
- package/dist/core/extensions/extension-types.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -0
- package/dist/core/extensions/loader.js +766 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/lock/lock.js +2 -0
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/sentry/instrument.d.ts +15 -0
- package/dist/core/sentry/instrument.js +35 -3
- package/dist/core/sentry/instrument.js.map +1 -1
- package/dist/core/shared/constants.js +20 -0
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.d.ts +8 -0
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/levenshtein.d.ts +1 -0
- package/dist/core/shared/levenshtein.js +37 -0
- package/dist/core/shared/levenshtein.js.map +1 -0
- package/dist/core/store/paths.js +34 -1
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.js +210 -1
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/runtime.d.ts +1 -0
- package/dist/core/telemetry/runtime.js +102 -3
- package/dist/core/telemetry/runtime.js.map +1 -1
- package/dist/mcp/server.js +3 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/pi/native.js +57 -4
- package/dist/pi/native.js.map +1 -1
- package/dist/sdk/cli-contracts.d.ts +21 -1
- package/dist/sdk/cli-contracts.js +250 -0
- package/dist/sdk/cli-contracts.js.map +1 -1
- package/dist/sdk/index.d.ts +12 -1
- package/dist/sdk/index.js +8 -1
- package/dist/sdk/index.js.map +1 -1
- package/dist/types.d.ts +41 -0
- package/dist/types.js.map +1 -1
- package/docs/CLAUDE_CODE_PLUGIN.md +39 -0
- package/docs/EXTENSIONS.md +687 -0
- package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
- package/docs/PI_PACKAGE.md +95 -10
- package/docs/SDK.md +441 -0
- package/docs/examples/ci/github-actions-pm-extension-gate.yml +53 -0
- package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +41 -0
- package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +45 -0
- package/docs/examples/policy-restricted-extension/README.md +74 -0
- package/docs/examples/policy-restricted-extension/index.js +21 -0
- package/docs/examples/policy-restricted-extension/manifest.json +21 -0
- package/docs/examples/policy-restricted-extension/package.json +8 -0
- package/docs/examples/sdk-app-embedding/README.md +39 -0
- package/docs/examples/sdk-app-embedding/package.json +9 -0
- package/docs/examples/sdk-app-embedding/run-embedded-pm.mjs +61 -0
- package/docs/examples/sdk-contract-consumer/README.md +57 -0
- package/docs/examples/sdk-contract-consumer/inspect-contracts.mjs +47 -0
- package/docs/examples/sdk-contract-consumer/package.json +10 -0
- package/docs/examples/starter-extension/README.md +57 -42
- package/docs/examples/starter-extension/manifest.json +15 -0
- package/marketplace.json +3 -3
- package/package.json +1 -1
- package/plugins/pm-cli-claude/.claude-plugin/plugin.json +2 -2
- package/plugins/pm-cli-claude/README.md +55 -14
- package/plugins/pm-cli-claude/agents/pm-delivery-chain.md +88 -0
- package/plugins/pm-cli-claude/agents/pm-triage-agent.md +83 -0
- package/plugins/pm-cli-claude/agents/pm-verification-agent.md +88 -0
- 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 {
|
|
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
|
|
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);
|