@unbrained/pm-cli 2026.8.21 → 2026.8.22
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 +2 -2
- package/CHANGELOG.md +16 -0
- package/dist/cli/error-guidance.d.ts +9 -4
- package/dist/cli/error-guidance.js +16 -15
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.js +40 -7
- package/dist/cli-bundle/bundle-manifest.json +153 -153
- package/dist/cli-bundle/chunks/{chunk-BKYB45NQ.js → chunk-BWX4SK46.js} +48 -48
- package/dist/cli-bundle/chunks/chunk-EMWDM5FI.js +13 -0
- package/dist/cli-bundle/chunks/chunk-HYG6LRL4.js +200 -0
- package/dist/cli-bundle/chunks/{chunk-LARJJ3RK.js → chunk-MYYI3ZOA.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-BUNIEJNE.js → chunk-MZTZQTMS.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-LOVTQ52Z.js → chunk-QI2CT3IX.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-SMWXHMVB.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-N3DSV4CH.js → chunk-U6GQ4VMV.js} +6 -6
- package/dist/cli-bundle/chunks/{chunk-3AFAUHUE.js → chunk-VMMIL3SI.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-WG4STC36.js +5 -0
- package/dist/cli-bundle/chunks/{chunk-JSLOFXGA.js → chunk-YBPJAOQQ.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-F57EWDEF.js → register-list-query-HZKBQNWW.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-7IY2D5KO.js → register-mutation-HTKEEGRD.js} +2 -2
- package/dist/cli-bundle/chunks/{register-operations-FALL3YTU.js → register-operations-6EMRWJJY.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-HXU7IZZD.js → register-setup-QK4OTOXN.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FJ22HNRP.js → chunk-2ARQGDDW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-CKKQSJNN.js → chunk-2AZT5WXZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-F4YEW5I2.js → chunk-2POVTNLY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-3LKU6PTJ.js +4 -0
- package/dist/cli-bundle/focused-chunks/chunk-5SHSBMX2.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-FH6DYED3.js → chunk-6S2MO3Q3.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-UZE7XUZK.js → chunk-A2BC5PQL.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-C4S4A4JJ.js +5 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KDNG7TKQ.js → chunk-D6RBZEJJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-E2EWYPY6.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4ERLO7QD.js → chunk-GMYPD4FX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-L5LDSRO2.js +155 -0
- package/dist/cli-bundle/focused-chunks/{chunk-ZOSEELYJ.js → chunk-MB37AYN6.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-MCOR37QK.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-2NIY5NKG.js → chunk-PH2OXXVZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-YKBKIEAJ.js → chunk-PMGJUFNQ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-R6SR45XU.js +50 -0
- package/dist/cli-bundle/focused-chunks/chunk-WZE4LIPW.js +8 -0
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +40 -40
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +32 -32
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +5 -5
- package/dist/core/extensions/extension-hook-runtime.js +22 -20
- package/dist/core/extensions/extension-types.d.ts +8 -1
- package/dist/core/extensions/extension-types.js +2 -2
- package/dist/core/extensions/loader.js +7 -3
- package/dist/core/extensions/service-ownership.d.ts +8 -0
- package/dist/core/extensions/service-ownership.js +20 -0
- package/dist/core/item/id.js +20 -5
- package/dist/core/item/item-format.js +27 -2
- package/dist/core/shared/errors.d.ts +4 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/sdk/agent/refusal-reachability.d.ts +1 -1
- package/dist/sdk/authoring.d.ts +1 -1
- package/dist/sdk/authoring.js +2 -2
- package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +77 -0
- package/dist/sdk/cli-contracts/agent-output-contracts.js +324 -2
- package/dist/sdk/cli-contracts/commander-mutation-options.js +3 -3
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +3 -1
- package/dist/sdk/cli-contracts/runtime-contracts.js +4 -3
- package/dist/sdk/cli-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts.js +3 -3
- package/dist/sdk/extension/install-sources.d.ts +1 -1
- package/dist/sdk/extension/install-sources.js +6 -3
- package/dist/sdk/extension/output-ownership.d.ts +1 -0
- package/dist/sdk/extension/output-ownership.js +3 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +38 -14
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -2
- package/dist/sdk/governance/health.d.ts +3 -0
- package/dist/sdk/governance/health.js +39 -7
- package/dist/sdk/governance/hierarchy-validation.d.ts +29 -0
- package/dist/sdk/governance/hierarchy-validation.js +109 -0
- package/dist/sdk/governance/validate.d.ts +1 -7
- package/dist/sdk/governance/validate.js +47 -99
- package/dist/sdk/graph/assembly.d.ts +6 -1
- package/dist/sdk/graph/assembly.js +16 -22
- package/dist/sdk/graph/governance-contracts.d.ts +1 -1
- package/dist/sdk/graph/governance-contracts.js +8 -2
- package/dist/sdk/graph/governance.js +46 -2
- package/dist/sdk/graph/hierarchy-integrity.d.ts +94 -0
- package/dist/sdk/graph/hierarchy-integrity.js +311 -0
- package/dist/sdk/graph/index.d.ts +2 -1
- package/dist/sdk/graph/index.js +3 -2
- package/dist/sdk/graph/remediation.js +32 -2
- package/dist/sdk/graph/run.d.ts +31 -2
- package/dist/sdk/graph/run.js +80 -31
- package/dist/sdk/graph/workspace-relationship-kind-registry.d.ts +8 -0
- package/dist/sdk/graph/workspace-relationship-kind-registry.js +28 -0
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/index.js +3 -3
- package/dist/sdk/item-children.js +21 -8
- package/dist/sdk/lifecycle/create.js +125 -96
- package/dist/sdk/lifecycle/hierarchy-mutation-lock.d.ts +15 -0
- package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +25 -0
- package/dist/sdk/lifecycle/update.d.ts +2 -0
- package/dist/sdk/lifecycle/update.js +171 -83
- package/dist/sdk/query/complete-list.d.ts +3 -3
- package/dist/sdk/query/complete-list.js +46 -3
- package/dist/sdk/query/list.d.ts +4 -3
- package/dist/sdk/query/list.js +89 -49
- package/dist/sdk/read-output-contracts.d.ts +5 -1
- package/dist/sdk/read-output-contracts.js +87 -22
- package/dist/sdk/relationship-context.js +3 -4
- package/dist/sdk/relationships.js +17 -10
- package/dist/sdk/runtime.d.ts +3 -2
- package/dist/sdk/runtime.js +3 -2
- package/dist/sdk/test/batch.js +13 -5
- package/dist/sdk/test/execution.js +10 -2
- package/dist/types.d.ts +11 -0
- package/dist/types.js +2 -2
- package/docs/AGENT_UX_CONTRACTS.md +20 -4
- package/docs/COMMANDS.md +29 -14
- package/docs/DEPENDENCY_KIND_CONTRACT.md +31 -3
- package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +98 -0
- package/docs/EXTENSIONS.md +2 -1
- package/docs/README.md +1 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +9 -2
- package/docs/RELATIONSHIP_GRAPH.md +6 -3
- package/docs/TESTING.md +15 -0
- package/marketplace.json +2 -2
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/sdk/public-surface.json +593 -35
- package/dist/cli-bundle/chunks/chunk-2MA6ZQVZ.js +0 -197
- package/dist/cli-bundle/chunks/chunk-7VHZS727.js +0 -5
- package/dist/cli-bundle/chunks/chunk-OCLPLFAY.js +0 -35
- package/dist/cli-bundle/chunks/chunk-S4IRYKBU.js +0 -13
- package/dist/cli-bundle/focused-chunks/chunk-7WZRLCYF.js +0 -50
- package/dist/cli-bundle/focused-chunks/chunk-EEFKYMDR.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-F2A56DHV.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-FV5ACOK7.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-JEAVFOWM.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-NJ63LOP6.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-NXRTQ7HI.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-TJ7EMJ46.js +0 -4
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm update command surface and its agent-facing runtime behavior.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!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]="
|
|
7
|
+
!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]="7c1729f8-4a67-5746-a1bf-351f862ceb66")}catch(e){}}();
|
|
8
8
|
import { assertInitializedTracker } from "../environment/tracker-preflight.js";
|
|
9
9
|
import { COMMON_MUTATION_COMMAND_OPTION_KEYS, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, normalizeItemId, toItemRecord, buildInvalidTypeError, assertParentReferenceIsNotSelf, normalizeParentReferenceValue, validateMissingParentReference, validateSprintOrReleaseValue, applyAcceptanceCriteriaMutations, applyTagRemovals, assertNoUnknownCsvKeys, createStdinTokenResolver, looksLikeGenericKeyValueEntry, mergeAdditiveTags, parseCsvKv, parseOptionalNonNegativeInteger, parseOptionalNumber, parseTags, splitAcceptanceCriteria, resolvePriority, normalizeStatusInput, isTerminalStatus, collectRuntimeUpdateFieldValues, resolveItemTypesFilePath, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, describeAllowedTransitions, evaluateTransition, resolveTypeWorkflows, EXIT_CODE, PmCliError, stableValueEquals, resolveIsoOrRelative, getActiveExtensionRegistrations, collectRegisteredItemFieldNames, applyRegisteredItemFieldDefaultsAndValidation, parseRegisteredItemFieldAssignments, buildItemNotFoundError, listAllItemMetadataLight, locateItem, readLocatedItem, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
|
|
10
10
|
import { mutateItemWithHistoryContextResolver } from "../../core/store/item-store.js";
|
|
@@ -17,6 +17,9 @@ import { assertDependencyEdgesAllowed, assertDependencyTargetsResolvable, assert
|
|
|
17
17
|
import { normalizeDependencySeedId, normalizeDependencySourceKind, } from "../dependency-provenance.js";
|
|
18
18
|
import { resolveCanonicalRelationshipKind } from "../relationships.js";
|
|
19
19
|
import { collectNewOrderingCycleWarnings } from "../graph/mutation-advisory.js";
|
|
20
|
+
import { assertHierarchyMutationAllowed } from "../graph/hierarchy-integrity.js";
|
|
21
|
+
import { resolveWorkspaceRelationshipKindRegistry } from "../graph/assembly.js";
|
|
22
|
+
import { acquireHierarchyMutationLock } from "./hierarchy-mutation-lock.js";
|
|
20
23
|
import { DEPENDENCY_KIND_VALUES, ISSUE_SEVERITY_VALUES, RISK_VALUES, } from "../../types/index.js";
|
|
21
24
|
import { parseDocs, parseFiles, parseLogSeed, parseTests, requireStringOption, } from "./create.js";
|
|
22
25
|
import { COMMON_UNSET_FIELD_DEFINITIONS_AFTER_CLOSE_REASON_BEFORE_AUTHOR, COMMON_UNSET_FIELD_DEFINITIONS_AFTER_AUTHOR, COMMON_UNSET_FIELD_DEFINITIONS_BEFORE_CLOSE_REASON, parseCommandUnsetTargets, resolveRuntimeUnsetFieldDefinition, } from "./shared-unset-fields.js";
|
|
@@ -355,6 +358,9 @@ function parseDependencyCreatedAt(value, currentIso) {
|
|
|
355
358
|
if (!value || value.trim() === "" || value.trim().toLowerCase() === "now") {
|
|
356
359
|
return currentIso;
|
|
357
360
|
}
|
|
361
|
+
return normalizeDependencyTimestamp(value);
|
|
362
|
+
}
|
|
363
|
+
function normalizeDependencyTimestamp(value) {
|
|
358
364
|
const parsed = Date.parse(value);
|
|
359
365
|
if (!Number.isFinite(parsed)) {
|
|
360
366
|
throw new PmCliError(`Invalid dependency created_at timestamp "${value}"`, EXIT_CODE.USAGE);
|
|
@@ -377,7 +383,14 @@ const DEP_ADDITION_KEYS = [
|
|
|
377
383
|
"source_kind",
|
|
378
384
|
];
|
|
379
385
|
/** Allowed CSV/markdown keys for the `--dep-remove` selector (GH-258). */
|
|
380
|
-
const DEP_REMOVE_KEYS = [
|
|
386
|
+
const DEP_REMOVE_KEYS = [
|
|
387
|
+
"id",
|
|
388
|
+
"kind",
|
|
389
|
+
"type",
|
|
390
|
+
"author",
|
|
391
|
+
"created_at",
|
|
392
|
+
"source_kind",
|
|
393
|
+
];
|
|
381
394
|
function looksLikeStructuredDependencyEntry(raw) {
|
|
382
395
|
if (raw.startsWith("```") || raw.includes("\n")) {
|
|
383
396
|
return true;
|
|
@@ -455,12 +468,18 @@ function parseDependencyRemovals(raw, prefix) {
|
|
|
455
468
|
}
|
|
456
469
|
const kindRaw = normalizeDependencyKindInput(parseOptionalDependencyString(kv.kind ?? kv.type));
|
|
457
470
|
const sourceKind = normalizeDependencySourceKind(parseOptionalDependencyString(kv.source_kind));
|
|
471
|
+
const author = parseOptionalDependencyString(kv.author);
|
|
472
|
+
const createdAt = parseOptionalDependencyString(kv.created_at);
|
|
458
473
|
return {
|
|
459
474
|
id: normalizeDependencySeedId(idRaw, prefix, sourceKind),
|
|
460
475
|
kind: kindRaw
|
|
461
476
|
? ensureEnum(kindRaw, DEPENDENCY_KIND_VALUES, "dependency kind")
|
|
462
477
|
: undefined,
|
|
463
478
|
source_kind: sourceKind,
|
|
479
|
+
author,
|
|
480
|
+
created_at: createdAt
|
|
481
|
+
? normalizeDependencyTimestamp(createdAt)
|
|
482
|
+
: undefined,
|
|
464
483
|
};
|
|
465
484
|
}
|
|
466
485
|
if (trimmed.toLowerCase() === "undefined") {
|
|
@@ -473,7 +492,24 @@ function parseDependencyRemovals(raw, prefix) {
|
|
|
473
492
|
}
|
|
474
493
|
function dependencyKey(value) {
|
|
475
494
|
const sourceKind = value.source_kind?.trim().toLowerCase() ?? "";
|
|
476
|
-
return
|
|
495
|
+
return [value.id.trim().toLowerCase(), value.kind, sourceKind].join("\u0000");
|
|
496
|
+
}
|
|
497
|
+
/** Return the complete normalized identity of one stored dependency row. */
|
|
498
|
+
function storedDependencyIdentityKey(value) {
|
|
499
|
+
const sourceKind = value.source_kind?.trim().toLowerCase() ?? "";
|
|
500
|
+
const author = value.author?.trim().toLowerCase() ?? "";
|
|
501
|
+
const rawCreatedAt = value.created_at?.trim() ?? "";
|
|
502
|
+
const parsedCreatedAt = Date.parse(rawCreatedAt);
|
|
503
|
+
const createdAt = Number.isFinite(parsedCreatedAt)
|
|
504
|
+
? new Date(parsedCreatedAt).toISOString()
|
|
505
|
+
: rawCreatedAt;
|
|
506
|
+
return [
|
|
507
|
+
value.id.trim().toLowerCase(),
|
|
508
|
+
value.kind,
|
|
509
|
+
sourceKind,
|
|
510
|
+
author,
|
|
511
|
+
createdAt,
|
|
512
|
+
].join("\u0000");
|
|
477
513
|
}
|
|
478
514
|
// pm-kyd6: `--blocked-by` writes the `blocked_by` scalar, but the dependency
|
|
479
515
|
// graph (`pm deps`) is built only from the `dependencies` array. Mirror the
|
|
@@ -568,6 +604,17 @@ function matchesDependencySelector(value, selector) {
|
|
|
568
604
|
selector.source_kind.trim().toLowerCase()) {
|
|
569
605
|
return false;
|
|
570
606
|
}
|
|
607
|
+
if (selector.author !== undefined &&
|
|
608
|
+
value.author?.trim().toLowerCase() !== selector.author.trim().toLowerCase()) {
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
if (selector.created_at !== undefined &&
|
|
612
|
+
(value.created_at === undefined ||
|
|
613
|
+
!Number.isFinite(Date.parse(value.created_at)) ||
|
|
614
|
+
new Date(Date.parse(value.created_at)).toISOString() !==
|
|
615
|
+
selector.created_at)) {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
571
618
|
return true;
|
|
572
619
|
}
|
|
573
620
|
function ensurePriority(raw) {
|
|
@@ -1082,6 +1129,19 @@ async function buildNoopUpdateResult(params) {
|
|
|
1082
1129
|
warnings: ["noop_no_update_fields"],
|
|
1083
1130
|
};
|
|
1084
1131
|
}
|
|
1132
|
+
async function loadUpdateRelationshipGraph(params) {
|
|
1133
|
+
if (!params.fieldFlags.dep &&
|
|
1134
|
+
!params.fieldFlags.blockedBy &&
|
|
1135
|
+
!params.fieldFlags.parent &&
|
|
1136
|
+
!params.clearedMetadataKeys.has("parent"))
|
|
1137
|
+
return undefined;
|
|
1138
|
+
return listAllItemMetadataLight(params.pmRoot, params.settings.item_format, params.typeToFolder, undefined, params.settings.schema);
|
|
1139
|
+
}
|
|
1140
|
+
function assertUpdateHierarchyIntegrity(params) {
|
|
1141
|
+
if (!params.before)
|
|
1142
|
+
return;
|
|
1143
|
+
assertHierarchyMutationAllowed(params.before, params.before.map((item) => item.id === params.document.metadata.id ? params.document.metadata : item), params.document.metadata.id, (status) => isTerminalStatus(status, params.statusRegistry), resolveWorkspaceRelationshipKindRegistry());
|
|
1144
|
+
}
|
|
1085
1145
|
async function assertUpdateTrackerInitialized(pmRoot) {
|
|
1086
1146
|
await assertInitializedTracker(pmRoot);
|
|
1087
1147
|
}
|
|
@@ -1315,16 +1375,16 @@ function applyTypeOptionMutation(document, context, activeTypeName, changedField
|
|
|
1315
1375
|
/** Collapse duplicate rows only for identities explicitly touched by this mutation. */
|
|
1316
1376
|
function normalizeTouchedDependencyIdentities(current, additions) {
|
|
1317
1377
|
const touchedKeys = new Set(additions.map((entry) => dependencyKey(entry)));
|
|
1318
|
-
const
|
|
1378
|
+
const retainedStoredIdentities = new Set();
|
|
1319
1379
|
return current.filter((entry) => {
|
|
1320
|
-
|
|
1321
|
-
if (!touchedKeys.has(key)) {
|
|
1380
|
+
if (!touchedKeys.has(dependencyKey(entry))) {
|
|
1322
1381
|
return true;
|
|
1323
1382
|
}
|
|
1324
|
-
|
|
1383
|
+
const storedIdentity = storedDependencyIdentityKey(entry);
|
|
1384
|
+
if (retainedStoredIdentities.has(storedIdentity)) {
|
|
1325
1385
|
return false;
|
|
1326
1386
|
}
|
|
1327
|
-
|
|
1387
|
+
retainedStoredIdentities.add(storedIdentity);
|
|
1328
1388
|
return true;
|
|
1329
1389
|
});
|
|
1330
1390
|
}
|
|
@@ -1342,11 +1402,13 @@ function assertDependencyRemovalSelectorsMatch(current, selectors, itemId) {
|
|
|
1342
1402
|
id: entry.id,
|
|
1343
1403
|
kind: entry.kind,
|
|
1344
1404
|
source_kind: entry.source_kind,
|
|
1405
|
+
author: entry.author,
|
|
1406
|
+
created_at: entry.created_at,
|
|
1345
1407
|
})),
|
|
1346
1408
|
why: "Failing on a zero-match selector prevents a mistyped dependency removal from being reported as successful.",
|
|
1347
1409
|
nextSteps: [
|
|
1348
1410
|
`Inspect the current item with: pm get ${itemId} --full`,
|
|
1349
|
-
"Retry --dep-remove with the exact id
|
|
1411
|
+
"Retry --dep-remove with the exact id plus any kind, source_kind, author, or created_at selectors needed to identify one stored row.",
|
|
1350
1412
|
],
|
|
1351
1413
|
});
|
|
1352
1414
|
}
|
|
@@ -1857,82 +1919,108 @@ async function runUpdateWithContext(id, options, global, execution = {}) {
|
|
|
1857
1919
|
return routedClose;
|
|
1858
1920
|
}
|
|
1859
1921
|
assertMatchingOrderRank(options);
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
let recurrenceHistoryContext;
|
|
1865
|
-
const result = await mutateItemWithHistoryContextResolver({
|
|
1922
|
+
const relationshipRegistry = resolveWorkspaceRelationshipKindRegistry();
|
|
1923
|
+
const hierarchyMutationRequired = (fieldFlags.parent && !clearItemMetadataKeys.has("parent")) ||
|
|
1924
|
+
dependencyUpdates.additions.some((dependency) => relationshipRegistry.resolve(dependency.kind)?.hierarchy);
|
|
1925
|
+
const releaseHierarchyMutationLock = await acquireHierarchyMutationLock({
|
|
1866
1926
|
pmRoot,
|
|
1867
|
-
settings,
|
|
1868
|
-
typeToFolder: typeRegistry.type_to_folder,
|
|
1869
|
-
id,
|
|
1870
|
-
op: resolveUpdateHistoryOperation(options, execution),
|
|
1871
1927
|
author,
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
bypassAssigneeConflict: options.ownershipMetadataBypass === true ||
|
|
1876
|
-
options.ownershipDependencyBypass === true,
|
|
1877
|
-
extensionFieldNames,
|
|
1878
|
-
skipNoop: true,
|
|
1879
|
-
mutate(document) {
|
|
1880
|
-
lifecycleTransition = prepareRecurrenceTransition({
|
|
1881
|
-
document,
|
|
1882
|
-
recurrenceReason: execution.recurrenceReason,
|
|
1883
|
-
requestedStatus: options.status,
|
|
1884
|
-
statusRegistry,
|
|
1885
|
-
});
|
|
1886
|
-
recurrenceHistoryContext = lifecycleTransition
|
|
1887
|
-
? { recurrence: lifecycleTransition }
|
|
1888
|
-
: undefined;
|
|
1889
|
-
graphBeforeUpdate = graphBeforeUpdate?.map((item) => item.id === document.metadata.id
|
|
1890
|
-
? structuredClone(document.metadata)
|
|
1891
|
-
: item);
|
|
1892
|
-
return mutateUpdateDocument(document, {
|
|
1893
|
-
options,
|
|
1894
|
-
settings,
|
|
1895
|
-
typeRegistry,
|
|
1896
|
-
statusRegistry,
|
|
1897
|
-
runtimeFieldRegistry,
|
|
1898
|
-
extensionRegistrations,
|
|
1899
|
-
extensionFieldNames,
|
|
1900
|
-
clearItemMetadataKeys,
|
|
1901
|
-
dependencyUpdates,
|
|
1902
|
-
dependencyRemovals,
|
|
1903
|
-
commentUpdates,
|
|
1904
|
-
noteUpdates,
|
|
1905
|
-
learningUpdates,
|
|
1906
|
-
fileUpdates,
|
|
1907
|
-
testUpdates,
|
|
1908
|
-
docUpdates,
|
|
1909
|
-
resolvedParentValue: parentReference.resolvedParentValue,
|
|
1910
|
-
resolvedBlockedByDependencyId,
|
|
1911
|
-
runtimeFieldUpdates,
|
|
1912
|
-
nowValue,
|
|
1913
|
-
nowIso,
|
|
1914
|
-
author,
|
|
1915
|
-
pmRoot,
|
|
1916
|
-
});
|
|
1917
|
-
},
|
|
1928
|
+
ttlSeconds: settings.locks.ttl_seconds,
|
|
1929
|
+
waitMs: settings.locks.wait_ms,
|
|
1930
|
+
required: hierarchyMutationRequired,
|
|
1918
1931
|
});
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
:
|
|
1935
|
-
|
|
1932
|
+
try {
|
|
1933
|
+
let graphBeforeUpdate = await loadUpdateRelationshipGraph({
|
|
1934
|
+
fieldFlags,
|
|
1935
|
+
clearedMetadataKeys: clearItemMetadataKeys,
|
|
1936
|
+
pmRoot,
|
|
1937
|
+
settings,
|
|
1938
|
+
typeToFolder: typeRegistry.type_to_folder,
|
|
1939
|
+
});
|
|
1940
|
+
let lifecycleTransition;
|
|
1941
|
+
let recurrenceHistoryContext;
|
|
1942
|
+
const result = await mutateItemWithHistoryContextResolver({
|
|
1943
|
+
pmRoot,
|
|
1944
|
+
settings,
|
|
1945
|
+
typeToFolder: typeRegistry.type_to_folder,
|
|
1946
|
+
id,
|
|
1947
|
+
op: resolveUpdateHistoryOperation(options, execution),
|
|
1948
|
+
author,
|
|
1949
|
+
message: options.message,
|
|
1950
|
+
resolveHistoryContext: () => recurrenceHistoryContext,
|
|
1951
|
+
force: options.force,
|
|
1952
|
+
bypassAssigneeConflict: options.ownershipMetadataBypass === true ||
|
|
1953
|
+
options.ownershipDependencyBypass === true,
|
|
1954
|
+
extensionFieldNames,
|
|
1955
|
+
skipNoop: true,
|
|
1956
|
+
mutate(document) {
|
|
1957
|
+
lifecycleTransition = prepareRecurrenceTransition({
|
|
1958
|
+
document,
|
|
1959
|
+
recurrenceReason: execution.recurrenceReason,
|
|
1960
|
+
requestedStatus: options.status,
|
|
1961
|
+
statusRegistry,
|
|
1962
|
+
});
|
|
1963
|
+
recurrenceHistoryContext = lifecycleTransition
|
|
1964
|
+
? { recurrence: lifecycleTransition }
|
|
1965
|
+
: undefined;
|
|
1966
|
+
graphBeforeUpdate = graphBeforeUpdate?.map((item) => item.id === document.metadata.id
|
|
1967
|
+
? structuredClone(document.metadata)
|
|
1968
|
+
: item);
|
|
1969
|
+
const mutation = mutateUpdateDocument(document, {
|
|
1970
|
+
options,
|
|
1971
|
+
settings,
|
|
1972
|
+
typeRegistry,
|
|
1973
|
+
statusRegistry,
|
|
1974
|
+
runtimeFieldRegistry,
|
|
1975
|
+
extensionRegistrations,
|
|
1976
|
+
extensionFieldNames,
|
|
1977
|
+
clearItemMetadataKeys,
|
|
1978
|
+
dependencyUpdates,
|
|
1979
|
+
dependencyRemovals,
|
|
1980
|
+
commentUpdates,
|
|
1981
|
+
noteUpdates,
|
|
1982
|
+
learningUpdates,
|
|
1983
|
+
fileUpdates,
|
|
1984
|
+
testUpdates,
|
|
1985
|
+
docUpdates,
|
|
1986
|
+
resolvedParentValue: parentReference.resolvedParentValue,
|
|
1987
|
+
resolvedBlockedByDependencyId,
|
|
1988
|
+
runtimeFieldUpdates,
|
|
1989
|
+
nowValue,
|
|
1990
|
+
nowIso,
|
|
1991
|
+
author,
|
|
1992
|
+
pmRoot,
|
|
1993
|
+
});
|
|
1994
|
+
assertUpdateHierarchyIntegrity({
|
|
1995
|
+
before: graphBeforeUpdate,
|
|
1996
|
+
document,
|
|
1997
|
+
statusRegistry,
|
|
1998
|
+
});
|
|
1999
|
+
return mutation;
|
|
2000
|
+
},
|
|
2001
|
+
});
|
|
2002
|
+
await releaseHierarchyMutationLock();
|
|
2003
|
+
const orderingCycleWarnings = graphBeforeUpdate
|
|
2004
|
+
? collectNewOrderingCycleWarnings(graphBeforeUpdate, graphBeforeUpdate.map((item) => item.id === result.item.id ? result.item : item), result.item.id)
|
|
2005
|
+
: [];
|
|
2006
|
+
return {
|
|
2007
|
+
item: toItemRecord(result.item),
|
|
2008
|
+
changed_fields: result.changedFields,
|
|
2009
|
+
warnings: [
|
|
2010
|
+
...workflowTransitionWarnings,
|
|
2011
|
+
...parentReferenceWarnings,
|
|
2012
|
+
...dependencyTargetWarnings,
|
|
2013
|
+
...orderingCycleWarnings,
|
|
2014
|
+
...result.warnings,
|
|
2015
|
+
],
|
|
2016
|
+
...(lifecycleTransition === undefined
|
|
2017
|
+
? {}
|
|
2018
|
+
: { lifecycle_transition: lifecycleTransition }),
|
|
2019
|
+
};
|
|
2020
|
+
}
|
|
2021
|
+
finally {
|
|
2022
|
+
await releaseHierarchyMutationLock();
|
|
2023
|
+
}
|
|
1936
2024
|
}
|
|
1937
2025
|
/** Resolve the immutable operation name for ordinary, bypass, and recurrence updates. */
|
|
1938
2026
|
function resolveUpdateHistoryOperation(options, execution) {
|
|
@@ -2021,4 +2109,4 @@ export const _testOnlyUpdateCommand = {
|
|
|
2021
2109
|
resolveRuntimeUnsetDefinition: (token, registry) => resolveRuntimeUnsetFieldDefinition(token, "update", registry),
|
|
2022
2110
|
};
|
|
2023
2111
|
//# sourceMappingURL=update.js.map
|
|
2024
|
-
//# debugId=
|
|
2112
|
+
//# debugId=7c1729f8-4a67-5746-a1bf-351f862ceb66
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { PmReadOutputReceipt } from "../read-output-contracts.js";
|
|
7
7
|
import type { ListFullResult, ListOptions } from "./list.js";
|
|
8
8
|
/** Stable reasons a purported whole-workspace list cannot be trusted. */
|
|
9
|
-
export declare const PM_COMPLETE_LIST_FINDING_CODES: readonly ["invalid_envelope", "source_incomplete", "source_unchecked", "filtered_corpus", "terminal_items_excluded", "strict_read_unproven", "page_incomplete", "count_mismatch", "projection_incomplete", "field_omission", "budget_compaction", "budget_omission", "session_projection", "invalid_item_id", "duplicate_item_id"];
|
|
9
|
+
export declare const PM_COMPLETE_LIST_FINDING_CODES: readonly ["invalid_envelope", "source_incomplete", "source_unchecked", "filtered_corpus", "terminal_items_excluded", "strict_read_unproven", "page_incomplete", "count_mismatch", "projection_incomplete", "field_omission", "omission_receipt_missing", "omission_receipt_invalid", "read_output_missing", "read_output_invalid", "read_output_dimensions_incomplete", "budget_compaction", "budget_omission", "session_projection", "invalid_item_id", "duplicate_item_id"];
|
|
10
10
|
/** Machine-readable reason a complete-list candidate failed certification. */
|
|
11
11
|
export type PmCompleteListFindingCode = (typeof PM_COMPLETE_LIST_FINDING_CODES)[number];
|
|
12
12
|
/** One independently actionable complete-list contract violation. */
|
|
@@ -39,8 +39,8 @@ export interface PmCompleteListCertificate {
|
|
|
39
39
|
export interface PmCompleteListResult extends ListFullResult {
|
|
40
40
|
/** Exact proof that the returned rows represent the full tracker corpus. */
|
|
41
41
|
complete_list: PmCompleteListCertificate;
|
|
42
|
-
/**
|
|
43
|
-
read_output
|
|
42
|
+
/** Mandatory universal read receipt proving unbounded, uncompacted delivery. */
|
|
43
|
+
read_output: PmReadOutputReceipt;
|
|
44
44
|
}
|
|
45
45
|
/** Inspection report returned without throwing for policy and UI consumers. */
|
|
46
46
|
export interface PmCompleteListInspection {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Stable reasons a purported whole-workspace list cannot be trusted. */
|
|
2
2
|
|
|
3
|
-
!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]="
|
|
3
|
+
!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]="c14a67b4-102d-5219-b2b3-15d39da36627")}catch(e){}}();
|
|
4
4
|
export const PM_COMPLETE_LIST_FINDING_CODES = [
|
|
5
5
|
"invalid_envelope",
|
|
6
6
|
"source_incomplete",
|
|
@@ -12,6 +12,11 @@ export const PM_COMPLETE_LIST_FINDING_CODES = [
|
|
|
12
12
|
"count_mismatch",
|
|
13
13
|
"projection_incomplete",
|
|
14
14
|
"field_omission",
|
|
15
|
+
"omission_receipt_missing",
|
|
16
|
+
"omission_receipt_invalid",
|
|
17
|
+
"read_output_missing",
|
|
18
|
+
"read_output_invalid",
|
|
19
|
+
"read_output_dimensions_incomplete",
|
|
15
20
|
"budget_compaction",
|
|
16
21
|
"budget_omission",
|
|
17
22
|
"session_projection",
|
|
@@ -31,7 +36,7 @@ export class PmCompleteListValidationError extends Error {
|
|
|
31
36
|
contract: "complete_list",
|
|
32
37
|
findings,
|
|
33
38
|
recovery: {
|
|
34
|
-
suggested_retry: "pm list
|
|
39
|
+
suggested_retry: "pm list --all --output-include full --strict-read --no-truncate --output-budget unbounded --output-limit unbounded --json",
|
|
35
40
|
sdk: "await client.listAllComplete()",
|
|
36
41
|
},
|
|
37
42
|
};
|
|
@@ -67,6 +72,17 @@ function inspectSourceScope(candidate, findings) {
|
|
|
67
72
|
: {};
|
|
68
73
|
addFinding(findings, completeness.status === "partial", "source_incomplete", "The source scan reported unreadable tracker artifacts.");
|
|
69
74
|
addFinding(findings, completeness.status !== "complete" && completeness.status !== "partial", "source_unchecked", "The source scan did not prove completeness.");
|
|
75
|
+
const unreadableItemCount = completeness.unreadable_item_count;
|
|
76
|
+
const unreadableDirectoryCount = completeness.unreadable_directory_count;
|
|
77
|
+
addFinding(findings, completeness.status === "complete" &&
|
|
78
|
+
(unreadableItemCount !== 0 || unreadableDirectoryCount !== 0) &&
|
|
79
|
+
Number.isSafeInteger(unreadableItemCount) &&
|
|
80
|
+
Number.isSafeInteger(unreadableDirectoryCount), "source_incomplete", "The source scan reports unreadable tracker artifacts despite a complete status.");
|
|
81
|
+
addFinding(findings, completeness.status === "complete" &&
|
|
82
|
+
(!Number.isSafeInteger(unreadableItemCount) ||
|
|
83
|
+
!Number.isSafeInteger(unreadableDirectoryCount) ||
|
|
84
|
+
Number(unreadableItemCount) < 0 ||
|
|
85
|
+
Number(unreadableDirectoryCount) < 0), "source_unchecked", "The source scan did not report safe non-negative unreadable counts.");
|
|
70
86
|
const filters = isRecord(candidate.filters) ? candidate.filters : {};
|
|
71
87
|
const runtimeFilters = isRecord(filters.runtime_filters)
|
|
72
88
|
? filters.runtime_filters
|
|
@@ -100,13 +116,40 @@ function inspectEnvelopeShape(candidate, filters, findings) {
|
|
|
100
116
|
const omissionReceipt = isRecord(candidate.omission_receipt)
|
|
101
117
|
? candidate.omission_receipt
|
|
102
118
|
: undefined;
|
|
119
|
+
addFinding(findings, omissionReceipt === undefined, "omission_receipt_missing", "The result carries no field-omission receipt.");
|
|
120
|
+
addFinding(findings, omissionReceipt !== undefined &&
|
|
121
|
+
(omissionReceipt.has_omissions !== false ||
|
|
122
|
+
omissionReceipt.omitted_field_group_count !== 0 ||
|
|
123
|
+
!Number.isSafeInteger(omissionReceipt.omitted_field_group_count) ||
|
|
124
|
+
!Array.isArray(omissionReceipt.omitted_field_groups) ||
|
|
125
|
+
omissionReceipt.omitted_field_groups.length !== 0), "omission_receipt_invalid", "The field-omission receipt is malformed or contradicts its no-omission claim.");
|
|
103
126
|
addFinding(findings, omissionReceipt?.has_omissions === true, "field_omission", "The omission receipt reports withheld field groups.");
|
|
104
127
|
}
|
|
128
|
+
/** Return whether a universal read receipt cannot prove an intact list result. */
|
|
129
|
+
function isInvalidCompleteListReadOutput(readOutput) {
|
|
130
|
+
return (readOutput.contract_version !== 1 ||
|
|
131
|
+
readOutput.command !== "list" ||
|
|
132
|
+
readOutput.within_budget !== true ||
|
|
133
|
+
readOutput.strings_compacted !== false ||
|
|
134
|
+
readOutput.rows_compacted !== false ||
|
|
135
|
+
readOutput.result_omitted !== false);
|
|
136
|
+
}
|
|
137
|
+
/** Return whether the receipt proves every dimension required for an unbounded full read. */
|
|
138
|
+
function hasCompleteListReadOutputDimensions(readOutput) {
|
|
139
|
+
if (!Array.isArray(readOutput.requested_dimensions))
|
|
140
|
+
return false;
|
|
141
|
+
const requestedDimensions = new Set(readOutput.requested_dimensions);
|
|
142
|
+
return ["include", "amount", "cost"].every((dimension) => requestedDimensions.has(dimension));
|
|
143
|
+
}
|
|
105
144
|
/** Append universal-output and cross-call-session findings. */
|
|
106
145
|
function inspectOutputScope(candidate, findings) {
|
|
107
146
|
const readOutput = isRecord(candidate.read_output)
|
|
108
147
|
? candidate.read_output
|
|
109
148
|
: undefined;
|
|
149
|
+
addFinding(findings, readOutput === undefined, "read_output_missing", "The result carries no universal read-output receipt.");
|
|
150
|
+
addFinding(findings, readOutput !== undefined && isInvalidCompleteListReadOutput(readOutput), "read_output_invalid", "The universal read-output receipt does not prove an intact list result.");
|
|
151
|
+
addFinding(findings, readOutput !== undefined &&
|
|
152
|
+
!hasCompleteListReadOutputDimensions(readOutput), "read_output_dimensions_incomplete", "The universal read-output receipt does not prove full, unbounded include, amount, and cost dimensions.");
|
|
110
153
|
addFinding(findings, readOutput?.strings_compacted === true ||
|
|
111
154
|
readOutput?.rows_compacted === true ||
|
|
112
155
|
candidate.output_budget_truncation !== undefined, "budget_compaction", "Universal output shaping compacted the result.");
|
|
@@ -170,4 +213,4 @@ export function assertCompleteListResult(candidate) {
|
|
|
170
213
|
certifyCompleteListResult(candidate);
|
|
171
214
|
}
|
|
172
215
|
//# sourceMappingURL=complete-list.js.map
|
|
173
|
-
//# debugId=
|
|
216
|
+
//# debugId=c14a67b4-102d-5219-b2b3-15d39da36627
|
package/dist/sdk/query/list.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { type RuntimeStatusRegistry } from "../../core/schema/runtime-schema.js"
|
|
|
5
5
|
import type { GlobalOptions } from "../../core/shared/command-types.js";
|
|
6
6
|
import type { ItemMetadata, ItemStatus } from "../../types/index.js";
|
|
7
7
|
import type { SharedItemFilterOptions } from "./item-filter-options.js";
|
|
8
|
+
import { type HierarchyRelationIndexes } from "../graph/hierarchy-integrity.js";
|
|
8
9
|
import { type ListCommandName, type ListProjectionMode } from "./projection-contracts.js";
|
|
9
10
|
export { BRIEF_LIST_FIELDS, DEFAULT_COMPACT_LIST_FIELDS, LIST_COMMAND_DEFAULT_PROJECTIONS, listListProjectionFields, type ListCommandName, type ListProjectionMode, } from "./projection-contracts.js";
|
|
10
11
|
/** Documents the list options payload exchanged by command, SDK, and package integrations. */
|
|
@@ -236,10 +237,10 @@ declare function normalizeProjectionField(field: string): string;
|
|
|
236
237
|
declare function parseSortField(raw: string | undefined): ListSortField | undefined;
|
|
237
238
|
declare function parseSortOrder(raw: string | undefined): ListSortOrder | undefined;
|
|
238
239
|
declare function parseAssigneeFilter(raw: string | undefined): "assigned" | "unassigned" | undefined;
|
|
239
|
-
declare function applyFilters(items: ListedItem[], status: ItemStatus[] | undefined, options: ListOptions, typeRegistry: ItemTypeRegistry, statusRegistry: RuntimeStatusRegistry, runtimeFieldFilters: Record<string, unknown
|
|
240
|
+
declare function applyFilters(items: ListedItem[], status: ItemStatus[] | undefined, options: ListOptions, typeRegistry: ItemTypeRegistry, statusRegistry: RuntimeStatusRegistry, runtimeFieldFilters: Record<string, unknown>, parentsByChild?: HierarchyRelationIndexes["parents_by_child"]): ListedItem[];
|
|
240
241
|
declare function trimNonEmpty(value: string | undefined): string | undefined;
|
|
241
|
-
declare function withTreeMetadata(item: ListedItem, depth: number, childCount: number): ListTreeItem;
|
|
242
|
-
declare function orderItemsAsTree(sortedItems: ListedItem[], parentRoot: string | undefined, maxDepth: number | undefined): ListedItem[];
|
|
242
|
+
declare function withTreeMetadata(item: ListedItem, depth: number, childCount: number, parentId?: string): ListTreeItem;
|
|
243
|
+
declare function orderItemsAsTree(sortedItems: ListedItem[], parentRoot: string | undefined, maxDepth: number | undefined, hierarchyIndexes?: HierarchyRelationIndexes, completeItems?: readonly ListedItem[]): ListedItem[];
|
|
243
244
|
declare function compareNullableString(left: string | null, right: string | null): number;
|
|
244
245
|
declare function compareNullableTimestamp(left: string | null, right: string | null): number;
|
|
245
246
|
declare function compareBySortField(left: ListedItem, right: ListedItem, field: ListSortField): number;
|