@unbrained/pm-cli 2026.8.18 → 2026.8.20
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 +35 -2
- package/dist/cli/error-guidance.js +3 -2
- package/dist/cli/help-content.js +32 -13
- package/dist/cli/help-json-payload.d.ts +15 -0
- package/dist/cli/help-json-payload.js +101 -23
- package/dist/cli/main.js +6 -2
- package/dist/cli/register-list-query.js +18 -13
- package/dist/cli/register-mutation.js +8 -8
- package/dist/cli/register-operations.js +6 -6
- package/dist/cli/register-structured-mutation.d.ts +2 -0
- package/dist/cli/register-structured-mutation.js +29 -6
- package/dist/cli-bundle/bundle-manifest.json +151 -143
- package/dist/cli-bundle/chunks/{chunk-UYCLQVL2.js → chunk-2RDVGYWE.js} +12 -12
- package/dist/cli-bundle/chunks/{chunk-BSK2IN3C.js → chunk-4GB2LTOQ.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-RZQTVMRQ.js → chunk-7BRF2BX2.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-BLVQHFSY.js +35 -0
- package/dist/cli-bundle/chunks/chunk-CU25EQVV.js +5 -0
- package/dist/cli-bundle/chunks/chunk-K3EN3LK2.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-YRGOLZA7.js → chunk-L4LGPBJU.js} +49 -49
- package/dist/cli-bundle/chunks/chunk-RS3IV2R6.js +197 -0
- package/dist/cli-bundle/chunks/chunk-TSMWLCHS.js +3 -0
- package/dist/cli-bundle/chunks/chunk-US2ZQW2M.js +77 -0
- package/dist/cli-bundle/chunks/{chunk-5UZZAJKR.js → chunk-XYDDWBZN.js} +2 -2
- package/dist/cli-bundle/chunks/register-list-query-JSAQCVOC.js +11 -0
- package/dist/cli-bundle/chunks/register-mutation-XJPAW63D.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-DSOSB2XQ.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-PPPEF3SN.js → register-setup-QUR6QL2C.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-325UXIO7.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-5L7M4AI7.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-ODOVCP45.js → chunk-6AHG2YW7.js} +44 -44
- package/dist/cli-bundle/focused-chunks/chunk-AZBACT5T.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-TN4AE665.js → chunk-BLJCGGID.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-FUREQLQN.js +18 -0
- package/dist/cli-bundle/focused-chunks/{chunk-M62NO7EI.js → chunk-G3C5ERXG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-K43KKAFS.js → chunk-GXWQBE3T.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-UI6AJ5TD.js → chunk-JWKEDZJI.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-KYZ6JGPL.js +155 -0
- package/dist/cli-bundle/focused-chunks/{chunk-EX6MKP2X.js → chunk-M32HFIQB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-EUEGXZ2A.js → chunk-OM65KHGF.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-Q47EX4DI.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-V5XTGLK7.js → chunk-RIHDMCUM.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-T4ZFY7ZJ.js +16 -0
- package/dist/cli-bundle/focused-chunks/chunk-TDR5OGG3.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-UGSS4F5X.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-Z3PLWSGM.js +2 -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 -1
- package/dist/cli-bundle/sdk-core.js +41 -41
- 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 -4
- package/dist/core/output/mutation-projection.js +26 -2
- package/dist/core/shared/constants.d.ts +1 -5
- package/dist/core/shared/constants.js +3 -81
- package/dist/core/shared/errors.d.ts +2 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/shared/item-metadata-contract.d.ts +14 -0
- package/dist/core/shared/item-metadata-contract.js +90 -0
- package/dist/core/store/item-store.d.ts +60 -0
- package/dist/core/store/item-store.js +22 -5
- package/dist/sdk/agent/closed-domain-contracts.d.ts +25 -0
- package/dist/sdk/agent/closed-domain-contracts.js +140 -0
- package/dist/sdk/agent/refusal-closure.d.ts +53 -0
- package/dist/sdk/agent/refusal-closure.js +134 -0
- package/dist/sdk/agent/refusal-reachability.d.ts +27 -1
- package/dist/sdk/agent/refusal-reachability.js +26 -2
- package/dist/sdk/agent-capability-contracts.d.ts +13 -0
- package/dist/sdk/agent-capability-contracts.js +101 -9
- package/dist/sdk/cli-contracts/command-aliases.js +18 -2
- package/dist/sdk/cli-contracts/commander-mutation-options.js +30 -6
- package/dist/sdk/cli-contracts/commander-types.js +5 -4
- package/dist/sdk/cli-contracts/completeness.js +8 -2
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -2
- package/dist/sdk/cli-contracts/enum-contracts.js +16 -6
- package/dist/sdk/cli-contracts/flag-contracts.d.ts +7 -0
- package/dist/sdk/cli-contracts/flag-contracts.js +84 -8
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.d.ts +72 -0
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +340 -0
- package/dist/sdk/cli-contracts/grammar-contracts.d.ts +83 -2
- package/dist/sdk/cli-contracts/grammar-contracts.js +618 -2
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +15 -4
- package/dist/sdk/cli-contracts/runtime-contracts.js +47 -13
- package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +28 -1
- package/dist/sdk/cli-contracts/tool-option-contracts.js +38 -3
- package/dist/sdk/cli-contracts/tool-schema.js +7 -2
- package/dist/sdk/cli-contracts.d.ts +4 -3
- package/dist/sdk/cli-contracts.js +6 -5
- package/dist/sdk/context-intent-contracts.d.ts +2 -2
- package/dist/sdk/context-intent-contracts.js +22 -7
- package/dist/sdk/contracts.d.ts +3 -0
- package/dist/sdk/contracts.js +5 -2
- package/dist/sdk/core.d.ts +1 -1
- package/dist/sdk/core.js +3 -3
- package/dist/sdk/flag-invocation-contracts.d.ts +37 -0
- package/dist/sdk/flag-invocation-contracts.js +218 -9
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +206 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +244 -40
- package/dist/sdk/index.d.ts +11 -7
- package/dist/sdk/index.js +10 -6
- package/dist/sdk/init-agent-guidance.d.ts +5 -3
- package/dist/sdk/init-agent-guidance.js +69 -9
- package/dist/sdk/lifecycle/mcp-actions.d.ts +18 -0
- package/dist/sdk/lifecycle/mcp-actions.js +52 -0
- package/dist/sdk/lifecycle/reopen.d.ts +44 -0
- package/dist/sdk/lifecycle/reopen.js +69 -0
- package/dist/sdk/lifecycle/update.d.ts +31 -0
- package/dist/sdk/lifecycle/update.js +95 -13
- package/dist/sdk/output-projection.d.ts +2 -0
- package/dist/sdk/output-projection.js +11 -5
- package/dist/sdk/query/get.d.ts +1 -1
- package/dist/sdk/query/get.js +34 -49
- package/dist/sdk/query/list.d.ts +7 -21
- package/dist/sdk/query/list.js +44 -44
- package/dist/sdk/query/projection-contracts.d.ts +33 -0
- package/dist/sdk/query/projection-contracts.js +185 -0
- package/dist/sdk/query/search-contracts.d.ts +3 -2
- package/dist/sdk/query/search-contracts.js +30 -85
- package/dist/sdk/query/search.d.ts +15 -0
- package/dist/sdk/query/search.js +32 -6
- package/dist/sdk/read-output/continuation.d.ts +1 -1
- package/dist/sdk/read-output/continuation.js +7 -24
- package/dist/sdk/read-output-contracts.js +55 -6
- package/dist/sdk/read-output-rows.d.ts +4 -0
- package/dist/sdk/read-output-rows.js +47 -18
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.d.ts +6 -0
- package/dist/sdk/runtime.js +25 -17
- package/dist/sdk/similarity.d.ts +13 -0
- package/dist/sdk/similarity.js +32 -6
- package/dist/sdk/workspace-snapshot.d.ts +2 -0
- package/dist/sdk/workspace-snapshot.js +10 -2
- package/docs/COMMANDS.md +29 -5
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +11 -2
- package/docs/README.md +1 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +10 -6
- package/docs/RECURRENCE_RECOVERY_CONTRACTS.md +114 -0
- package/docs/SDK.md +16 -2
- package/docs/SDK_CONTEXT_INTEGRITY.md +45 -0
- package/docs/TESTING.md +14 -1
- package/docs/generated/AGENT_COMMAND_SURFACE.md +78 -78
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +76 -0
- package/docs/performance/sdk-entrypoint-import-costs.md +14 -21
- package/marketplace.json +2 -2
- package/package.json +9 -7
- 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/scripts/generate-agent-capability-surfaces.mjs +20 -14
- package/sdk/public-surface.json +950 -24
- package/dist/cli-bundle/chunks/chunk-ALDJGKAK.js +0 -2
- package/dist/cli-bundle/chunks/chunk-DY4DMUMC.js +0 -197
- package/dist/cli-bundle/chunks/chunk-GNFAFIJI.js +0 -77
- package/dist/cli-bundle/chunks/chunk-L5Q2CLPE.js +0 -35
- package/dist/cli-bundle/chunks/chunk-PVRUN5ZS.js +0 -5
- package/dist/cli-bundle/chunks/chunk-SARFF5H5.js +0 -3
- package/dist/cli-bundle/chunks/register-list-query-I23LALEE.js +0 -11
- package/dist/cli-bundle/chunks/register-mutation-6YGU3GPH.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-4HTFC6J7.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-2PN4TJXH.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3TKWMNKF.js +0 -18
- package/dist/cli-bundle/focused-chunks/chunk-5AF3ZBNB.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-C5IW2NDA.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-RNDNMARJ.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-TVV2DONO.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-WGHQVU6P.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-XYNBXTDQ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-Z56ECT7I.js +0 -2
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm init agent guidance 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]="e404796d-439b-5f4c-9330-5b12ff41d7b2")}catch(e){}}();
|
|
8
8
|
import fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import readline from "node:readline/promises";
|
|
@@ -91,14 +91,14 @@ function findGuidanceBlockRange(content) {
|
|
|
91
91
|
function hasGuidanceMarker(content) {
|
|
92
92
|
return findGuidanceBlockRange(content) !== null;
|
|
93
93
|
}
|
|
94
|
-
function buildAgentGuidanceBlock(lineEnding) {
|
|
94
|
+
function buildAgentGuidanceBlock(lineEnding, projectTestCommand = "<your project test command>") {
|
|
95
95
|
const lines = [
|
|
96
96
|
AGENT_GUIDANCE_START_MARKER,
|
|
97
97
|
"## pm Workflow (Agent Quickstart)",
|
|
98
98
|
"",
|
|
99
99
|
'- Orient before mutate: `pm context --limit 10`, `pm search "<keywords>" --limit 10`, `pm list --status open --limit 20`.',
|
|
100
100
|
"- Claim and execute: `pm claim <id>` then `pm update <id> --status in_progress`.",
|
|
101
|
-
|
|
101
|
+
`- Link evidence while coding: \`pm files <id> --add ...\`, \`pm docs <id> --add ...\`, \`pm test <id> --add command="${projectTestCommand}"\`.`,
|
|
102
102
|
'- Verify and close: `pm test <id> --run --progress`, `pm close <id> "<evidence>" --validate-close warn`, `pm release <id>`.',
|
|
103
103
|
"- Author identity is automatic for supported agent harnesses; use `--author` only for an explicit override.",
|
|
104
104
|
"",
|
|
@@ -107,9 +107,9 @@ function buildAgentGuidanceBlock(lineEnding) {
|
|
|
107
107
|
];
|
|
108
108
|
return lines.join(lineEnding);
|
|
109
109
|
}
|
|
110
|
-
function upsertAgentGuidanceBlock(existingContent) {
|
|
110
|
+
function upsertAgentGuidanceBlock(existingContent, projectTestCommand = "<your project test command>") {
|
|
111
111
|
const lineEnding = detectLineEnding(existingContent);
|
|
112
|
-
const nextBlock = buildAgentGuidanceBlock(lineEnding);
|
|
112
|
+
const nextBlock = buildAgentGuidanceBlock(lineEnding, projectTestCommand);
|
|
113
113
|
const existingRange = findGuidanceBlockRange(existingContent);
|
|
114
114
|
if (existingRange) {
|
|
115
115
|
const trailingContent = existingContent.slice(existingRange.end_index);
|
|
@@ -135,6 +135,65 @@ function upsertAgentGuidanceBlock(existingContent) {
|
|
|
135
135
|
changed: nextContent !== existingContent,
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
|
+
/** Resolve an executable linked-test command from a target repository's own files. */
|
|
139
|
+
export async function resolveProjectTestCommand(projectRoot) {
|
|
140
|
+
if (await pathExists(path.join(projectRoot, "scripts", "run-tests.mjs"))) {
|
|
141
|
+
return "node scripts/run-tests.mjs test";
|
|
142
|
+
}
|
|
143
|
+
let packageDocument;
|
|
144
|
+
try {
|
|
145
|
+
packageDocument = JSON.parse(await fs.readFile(path.join(projectRoot, "package.json"), "utf8"));
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return "<your project test command>";
|
|
149
|
+
}
|
|
150
|
+
const manifest = normalizeProjectPackageManifest(packageDocument);
|
|
151
|
+
if (manifest === undefined) {
|
|
152
|
+
return "<your project test command>";
|
|
153
|
+
}
|
|
154
|
+
const packageManager = manifest.packageManager?.split("@")[0];
|
|
155
|
+
if (packageManager === "pnpm") {
|
|
156
|
+
return "pnpm test";
|
|
157
|
+
}
|
|
158
|
+
if (packageManager === "bun") {
|
|
159
|
+
return "bun run test";
|
|
160
|
+
}
|
|
161
|
+
if (packageManager === "yarn") {
|
|
162
|
+
return "yarn test";
|
|
163
|
+
}
|
|
164
|
+
if (packageManager === "npm")
|
|
165
|
+
return "npm test";
|
|
166
|
+
if (await pathExists(path.join(projectRoot, "pnpm-lock.yaml"))) {
|
|
167
|
+
return "pnpm test";
|
|
168
|
+
}
|
|
169
|
+
if ((await pathExists(path.join(projectRoot, "bun.lock"))) ||
|
|
170
|
+
(await pathExists(path.join(projectRoot, "bun.lockb")))) {
|
|
171
|
+
return "bun run test";
|
|
172
|
+
}
|
|
173
|
+
if (await pathExists(path.join(projectRoot, "yarn.lock")))
|
|
174
|
+
return "yarn test";
|
|
175
|
+
return "npm test";
|
|
176
|
+
}
|
|
177
|
+
/** Validate the minimal package manifest shape needed for executable test guidance. */
|
|
178
|
+
function normalizeProjectPackageManifest(value) {
|
|
179
|
+
if (typeof value !== "object" || value === null || !("scripts" in value)) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
const scripts = value.scripts;
|
|
183
|
+
if (typeof scripts !== "object" ||
|
|
184
|
+
scripts === null ||
|
|
185
|
+
!("test" in scripts) ||
|
|
186
|
+
typeof scripts.test !== "string" ||
|
|
187
|
+
scripts.test.trim().length === 0) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
scripts: { test: scripts.test },
|
|
192
|
+
...("packageManager" in value && typeof value.packageManager === "string"
|
|
193
|
+
? { packageManager: value.packageManager }
|
|
194
|
+
: {}),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
138
197
|
function resolveProjectRoot(pmRoot, cwd) {
|
|
139
198
|
const parent = path.dirname(pmRoot);
|
|
140
199
|
if (path.basename(pmRoot) === "pm" && path.basename(parent) === ".agents") {
|
|
@@ -240,10 +299,10 @@ function applyAgentGuidanceState(settings, currentState) {
|
|
|
240
299
|
}
|
|
241
300
|
return { changed, state: currentState };
|
|
242
301
|
}
|
|
243
|
-
async function writeGuidanceFile(filePath) {
|
|
302
|
+
async function writeGuidanceFile(filePath, projectRoot = path.dirname(filePath)) {
|
|
244
303
|
const exists = await pathExists(filePath);
|
|
245
304
|
const currentContent = exists ? await fs.readFile(filePath, "utf8") : "";
|
|
246
|
-
const nextContent = upsertAgentGuidanceBlock(currentContent);
|
|
305
|
+
const nextContent = upsertAgentGuidanceBlock(currentContent, await resolveProjectTestCommand(projectRoot));
|
|
247
306
|
if (!nextContent.changed) {
|
|
248
307
|
return { changed: false, warnings: [] };
|
|
249
308
|
}
|
|
@@ -292,7 +351,7 @@ async function addAgentGuidanceBlockIfMissing(flow, context) {
|
|
|
292
351
|
if (context.presentBefore) {
|
|
293
352
|
return;
|
|
294
353
|
}
|
|
295
|
-
const writeResult = await writeGuidanceFile(context.targetPath);
|
|
354
|
+
const writeResult = await writeGuidanceFile(context.targetPath, context.projectRoot);
|
|
296
355
|
flow.warnings.push(...writeResult.warnings);
|
|
297
356
|
if (writeResult.changed) {
|
|
298
357
|
flow.applied = true;
|
|
@@ -413,6 +472,7 @@ export async function runInitAgentGuidance(options) {
|
|
|
413
472
|
targetRelativePath,
|
|
414
473
|
checkedFiles,
|
|
415
474
|
presentBefore,
|
|
475
|
+
projectRoot,
|
|
416
476
|
});
|
|
417
477
|
const stateUpdate = applyAgentGuidanceState(options.settings, flow.state);
|
|
418
478
|
scans = await refreshGuidanceScansAfterApply(flow.applied, scans, projectRoot);
|
|
@@ -434,4 +494,4 @@ export async function runInitAgentGuidance(options) {
|
|
|
434
494
|
};
|
|
435
495
|
}
|
|
436
496
|
//# sourceMappingURL=init-agent-guidance.js.map
|
|
437
|
-
//# debugId=
|
|
497
|
+
//# debugId=e404796d-439b-5f4c-9330-5b12ff41d7b2
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { GlobalOptions } from "../../core/shared/command-types.js";
|
|
2
|
+
/** Minimal generic dispatch context consumed by lifecycle mutation adapters. */
|
|
3
|
+
export interface LifecycleMutationActionContext {
|
|
4
|
+
/** Flat MCP/action arguments. */
|
|
5
|
+
args: Record<string, unknown>;
|
|
6
|
+
/** Normalized command option bag. */
|
|
7
|
+
options: Record<string, unknown>;
|
|
8
|
+
/** Item id resolved from flat arguments, when present. */
|
|
9
|
+
id: string | undefined;
|
|
10
|
+
/** Normalized transport-level force override. */
|
|
11
|
+
force?: boolean;
|
|
12
|
+
/** Presentation-neutral global command options. */
|
|
13
|
+
global: GlobalOptions;
|
|
14
|
+
}
|
|
15
|
+
/** Dispatch close through the shared MCP mutation compaction contract. */
|
|
16
|
+
export declare function runMcpCloseAction(context: LifecycleMutationActionContext): Promise<unknown>;
|
|
17
|
+
/** Dispatch recurrence through the shared MCP mutation compaction contract. */
|
|
18
|
+
export declare function runMcpReopenAction(context: LifecycleMutationActionContext): Promise<unknown>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/runtime-mutation-actions
|
|
3
|
+
*
|
|
4
|
+
* Keeps lifecycle-specific MCP mutation adapters outside the generic runtime
|
|
5
|
+
* dispatcher while preserving the shared token-efficient result projection.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
!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]="55869854-565d-52d2-8dca-b66aade074bb")}catch(e){}}();
|
|
9
|
+
import { projectMutationResult } from "../../core/output/mutation-projection.js";
|
|
10
|
+
import { PmCliError } from "../../core/shared/errors.js";
|
|
11
|
+
import { runClose } from "./close.js";
|
|
12
|
+
import { runReopen } from "./reopen.js";
|
|
13
|
+
import { readRuntimeString, withMutationCompaction } from "../runtime-input.js";
|
|
14
|
+
function requireLifecycleItemId(context, options) {
|
|
15
|
+
const id = context.id ?? readRuntimeString(options, "id");
|
|
16
|
+
if (!id) {
|
|
17
|
+
throw new PmCliError("Missing required argument: id", 64);
|
|
18
|
+
}
|
|
19
|
+
return id;
|
|
20
|
+
}
|
|
21
|
+
function readLifecycleReason(context, options) {
|
|
22
|
+
return (readRuntimeString(context.args, "reason") ??
|
|
23
|
+
readRuntimeString(context.args, "text") ??
|
|
24
|
+
readRuntimeString(options, "reason") ??
|
|
25
|
+
readRuntimeString(options, "text"));
|
|
26
|
+
}
|
|
27
|
+
/** Dispatch close through the shared MCP mutation compaction contract. */
|
|
28
|
+
export async function runMcpCloseAction(context) {
|
|
29
|
+
const { changedFields, idOnly, runnerOptions } = withMutationCompaction(context.args, context.options);
|
|
30
|
+
return projectMutationResult(await runClose(requireLifecycleItemId(context, runnerOptions), readLifecycleReason(context, runnerOptions), {
|
|
31
|
+
...runnerOptions,
|
|
32
|
+
force: context.force === true || runnerOptions.force === true,
|
|
33
|
+
}, context.global), {
|
|
34
|
+
changedFields,
|
|
35
|
+
compactEnvelope: changedFields === "compact" && !idOnly,
|
|
36
|
+
idOnly,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/** Dispatch recurrence through the shared MCP mutation compaction contract. */
|
|
40
|
+
export async function runMcpReopenAction(context) {
|
|
41
|
+
const { changedFields, idOnly, runnerOptions } = withMutationCompaction(context.args, context.options);
|
|
42
|
+
return projectMutationResult(await runReopen(requireLifecycleItemId(context, runnerOptions), readLifecycleReason(context, runnerOptions) ?? "", {
|
|
43
|
+
...runnerOptions,
|
|
44
|
+
force: context.force === true || runnerOptions.force === true,
|
|
45
|
+
}, context.global), {
|
|
46
|
+
changedFields,
|
|
47
|
+
compactEnvelope: changedFields === "compact" && !idOnly,
|
|
48
|
+
idOnly,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=mcp-actions.js.map
|
|
52
|
+
//# debugId=55869854-565d-52d2-8dca-b66aade074bb
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/lifecycle/reopen
|
|
3
|
+
*
|
|
4
|
+
* Reopens terminal work as a recurrence while preserving immutable closure
|
|
5
|
+
* evidence and delegating every state change to the canonical update pipeline.
|
|
6
|
+
*/
|
|
7
|
+
import type { GlobalOptions } from "../../core/shared/command-types.js";
|
|
8
|
+
import { type PreviousTerminalEvidence } from "./update.js";
|
|
9
|
+
export type { PreviousTerminalEvidence } from "./update.js";
|
|
10
|
+
/** Options accepted by the SDK and `pm item reopen` recurrence primitive. */
|
|
11
|
+
export interface ReopenCommandOptions {
|
|
12
|
+
/** Active target status; only the workspace open or in-progress status is allowed. */
|
|
13
|
+
status?: string;
|
|
14
|
+
/** Explicit mutation author override. */
|
|
15
|
+
author?: string;
|
|
16
|
+
/** Optional human-readable history message in addition to structured recurrence context. */
|
|
17
|
+
message?: string;
|
|
18
|
+
/** Override an ownership or stale-lock conflict. */
|
|
19
|
+
force?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Structured recurrence receipt returned by every presentation surface. */
|
|
22
|
+
export interface RecurrenceReceipt {
|
|
23
|
+
/** Required reason that the terminal work became active again. */
|
|
24
|
+
reason: string;
|
|
25
|
+
/** Terminal status observed while holding the item lock. */
|
|
26
|
+
from_status: string;
|
|
27
|
+
/** Active status written through the update pipeline. */
|
|
28
|
+
to_status: string;
|
|
29
|
+
/** Prior terminal evidence retained in immutable history. */
|
|
30
|
+
previous_terminal: PreviousTerminalEvidence;
|
|
31
|
+
}
|
|
32
|
+
/** Result returned after a terminal item is reopened. */
|
|
33
|
+
export interface ReopenResult {
|
|
34
|
+
/** Reopened item metadata. */
|
|
35
|
+
item: Record<string, unknown>;
|
|
36
|
+
/** Fields changed by the canonical update pipeline. */
|
|
37
|
+
changed_fields: string[];
|
|
38
|
+
/** Non-fatal mutation and extension warnings. */
|
|
39
|
+
warnings: string[];
|
|
40
|
+
/** Immutable recurrence transition receipt. */
|
|
41
|
+
recurrence: RecurrenceReceipt;
|
|
42
|
+
}
|
|
43
|
+
/** Reopen terminal work through the canonical update mutation and history path. */
|
|
44
|
+
export declare function runReopen(id: string, reason: string, options: ReopenCommandOptions, global: GlobalOptions): Promise<ReopenResult>;
|
|
@@ -0,0 +1,69 @@
|
|
|
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]="08dcee99-5572-5133-b76a-6a50e4e292e7")}catch(e){}}();
|
|
3
|
+
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
4
|
+
import { PmCliError } from "../../core/shared/errors.js";
|
|
5
|
+
import { normalizeStatusInput } from "../../core/item/status.js";
|
|
6
|
+
import { resolveRuntimeStatusRegistry } from "../../core/schema/runtime-schema.js";
|
|
7
|
+
import { resolvePmRoot } from "../../core/store/paths.js";
|
|
8
|
+
import { readSettings } from "../../core/store/settings.js";
|
|
9
|
+
import { resolveStartTaskInProgressStatus } from "../start-task-status.js";
|
|
10
|
+
import { runReopenUpdate, } from "./update.js";
|
|
11
|
+
/** Reopen terminal work through the canonical update mutation and history path. */
|
|
12
|
+
export async function runReopen(id, reason, options, global) {
|
|
13
|
+
const normalizedReason = reason.trim();
|
|
14
|
+
if (normalizedReason.length === 0) {
|
|
15
|
+
throw new PmCliError("pm item reopen requires a non-empty recurrence reason.", EXIT_CODE.USAGE, {
|
|
16
|
+
code: "reopen_reason_required",
|
|
17
|
+
required: "Describe why the terminal work became active again.",
|
|
18
|
+
recovery: {
|
|
19
|
+
suggested_retry: `pm item reopen ${id} "<recurrence reason>"`,
|
|
20
|
+
suggested_retry_args: ["item", "reopen", id, "<recurrence reason>"],
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
25
|
+
const statusRegistry = resolveRuntimeStatusRegistry((await readSettings(pmRoot)).schema);
|
|
26
|
+
const openStatus = statusRegistry.open_status;
|
|
27
|
+
const inProgressStatus = resolveStartTaskInProgressStatus(statusRegistry);
|
|
28
|
+
const requestedStatus = options.status ?? openStatus;
|
|
29
|
+
const targetStatus = normalizeStatusInput(requestedStatus, statusRegistry) ?? requestedStatus;
|
|
30
|
+
if (targetStatus !== openStatus && targetStatus !== inProgressStatus) {
|
|
31
|
+
throw new PmCliError(`Reopen target status must be ${openStatus} or ${inProgressStatus}; received ${requestedStatus}.`, EXIT_CODE.USAGE, {
|
|
32
|
+
code: "reopen_target_status_invalid",
|
|
33
|
+
required: "Choose the workspace open or in-progress lifecycle status.",
|
|
34
|
+
recovery: {
|
|
35
|
+
allowed_values: [...new Set([openStatus, inProgressStatus])],
|
|
36
|
+
suggested_retry: `pm item reopen ${id} "${normalizedReason}" --status ${openStatus}`,
|
|
37
|
+
suggested_retry_args: [
|
|
38
|
+
"item",
|
|
39
|
+
"reopen",
|
|
40
|
+
id,
|
|
41
|
+
normalizedReason,
|
|
42
|
+
"--status",
|
|
43
|
+
openStatus,
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const update = await runReopenUpdate(id, {
|
|
49
|
+
status: targetStatus,
|
|
50
|
+
unset: [
|
|
51
|
+
"close-reason",
|
|
52
|
+
"resolution",
|
|
53
|
+
"expected-result",
|
|
54
|
+
"actual-result",
|
|
55
|
+
"fixed-version",
|
|
56
|
+
],
|
|
57
|
+
author: options.author,
|
|
58
|
+
message: options.message,
|
|
59
|
+
force: options.force,
|
|
60
|
+
}, global, normalizedReason);
|
|
61
|
+
return {
|
|
62
|
+
item: update.item,
|
|
63
|
+
changed_fields: update.changed_fields,
|
|
64
|
+
warnings: update.warnings,
|
|
65
|
+
recurrence: update.lifecycle_transition,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=reopen.js.map
|
|
69
|
+
//# debugId=08dcee99-5572-5133-b76a-6a50e4e292e7
|
|
@@ -67,6 +67,35 @@ export interface UpdateResult {
|
|
|
67
67
|
/** Value that configures or reports warnings for this contract. */
|
|
68
68
|
warnings: string[];
|
|
69
69
|
}
|
|
70
|
+
/** Terminal evidence captured atomically before a recurrence transition. */
|
|
71
|
+
export interface PreviousTerminalEvidence {
|
|
72
|
+
/** Prior close reason, when recorded. */
|
|
73
|
+
close_reason?: string;
|
|
74
|
+
/** Prior structured resolution, when recorded. */
|
|
75
|
+
resolution?: string;
|
|
76
|
+
/** Prior expected result, when recorded. */
|
|
77
|
+
expected_result?: string;
|
|
78
|
+
/** Prior actual result, when recorded. */
|
|
79
|
+
actual_result?: string;
|
|
80
|
+
/** Prior fixed version, when recorded. */
|
|
81
|
+
fixed_version?: string;
|
|
82
|
+
}
|
|
83
|
+
/** Internal update-path receipt consumed by the public recurrence primitive. */
|
|
84
|
+
export interface ReopenUpdateReceipt {
|
|
85
|
+
/** Recurrence reason stored in immutable history context. */
|
|
86
|
+
reason: string;
|
|
87
|
+
/** Terminal status observed while holding the item lock. */
|
|
88
|
+
from_status: string;
|
|
89
|
+
/** Active status written by the update path. */
|
|
90
|
+
to_status: string;
|
|
91
|
+
/** Terminal evidence removed from active metadata but retained in history. */
|
|
92
|
+
previous_terminal: PreviousTerminalEvidence;
|
|
93
|
+
}
|
|
94
|
+
/** Update result carrying the recurrence receipt produced by the locked transition. */
|
|
95
|
+
export interface ReopenUpdateResult extends UpdateResult {
|
|
96
|
+
/** Lifecycle-specific receipt populated by the recurrence primitive. */
|
|
97
|
+
lifecycle_transition: ReopenUpdateReceipt;
|
|
98
|
+
}
|
|
70
99
|
declare function normalizeLegacyNoneUpdateOptions(options: UpdateCommandOptions): UpdateCommandOptions;
|
|
71
100
|
declare function parseUpdateUnsetTargets(raw: string[] | undefined, runtimeFieldRegistry?: RuntimeFieldRegistry, extensionFieldNames?: readonly string[]): {
|
|
72
101
|
metadataKeys: Set<string>;
|
|
@@ -139,6 +168,8 @@ type UpdateStatusMutationContext = Pick<UpdateMutationContext, "options" | "stat
|
|
|
139
168
|
declare function applyStatusAndCloseReasonMutations(document: ItemDocument, context: UpdateStatusMutationContext, previousStatusNormalized: string, changedFields: string[]): void;
|
|
140
169
|
/** Implements run update for the public runtime surface of this module. */
|
|
141
170
|
export declare function runUpdate(id: string, options: UpdateCommandOptions, global: GlobalOptions): Promise<UpdateResult>;
|
|
171
|
+
/** Execute a recurrence transition through the exact atomic update pipeline. */
|
|
172
|
+
export declare function runReopenUpdate(id: string, options: UpdateCommandOptions, global: GlobalOptions, recurrenceReason: string): Promise<ReopenUpdateResult>;
|
|
142
173
|
/** Public contract for test only update command, shared by SDK and presentation-layer consumers. */
|
|
143
174
|
export declare const _testOnlyUpdateCommand: {
|
|
144
175
|
applyStatusAndCloseReasonMutations: typeof applyStatusAndCloseReasonMutations;
|
|
@@ -4,8 +4,9 @@
|
|
|
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]="
|
|
8
|
-
import { pathExists, 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,
|
|
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]="3ab4f16d-ce37-546e-a2f6-0495fd1967c7")}catch(e){}}();
|
|
8
|
+
import { pathExists, 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, getSettingsPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
|
|
9
|
+
import { mutateItemWithHistoryContextResolver } from "../../core/store/item-store.js";
|
|
9
10
|
import { runClose } from "./close.js";
|
|
10
11
|
import { normalizeRiskInput, normalizeSeverityInput, parseConfidenceInput, parseRegressionInput, } from "./metadata-normalizers.js";
|
|
11
12
|
import { applyLegacyNoneCollectionNormalizers, createLegacyNoneCollectionNormalizers, assertNoLegacyNoneToken, assertNoLegacyNoneTokens, isLegacyNoneToken, } from "./legacy-none-tokens.js";
|
|
@@ -1214,8 +1215,8 @@ function applyStatusMutation(document, context, statusInput, previousStatusNorma
|
|
|
1214
1215
|
changedFields.push("closed_at", "completed_at");
|
|
1215
1216
|
return;
|
|
1216
1217
|
}
|
|
1217
|
-
if (status
|
|
1218
|
-
previousStatusNormalized
|
|
1218
|
+
if (!isTerminalStatus(status, context.statusRegistry) &&
|
|
1219
|
+
isTerminalStatus(previousStatusNormalized, context.statusRegistry) &&
|
|
1219
1220
|
document.metadata.closed_at !== undefined) {
|
|
1220
1221
|
delete document.metadata.closed_at;
|
|
1221
1222
|
changedFields.push("closed_at");
|
|
@@ -1254,8 +1255,8 @@ function applyCloseReasonMutations(document, context, previousStatusNormalized,
|
|
|
1254
1255
|
return;
|
|
1255
1256
|
}
|
|
1256
1257
|
if (context.options.status !== undefined &&
|
|
1257
|
-
previousStatusNormalized
|
|
1258
|
-
document.metadata.status
|
|
1258
|
+
isTerminalStatus(previousStatusNormalized, context.statusRegistry) &&
|
|
1259
|
+
!isTerminalStatus(document.metadata.status, context.statusRegistry) &&
|
|
1259
1260
|
document.metadata.close_reason !== undefined) {
|
|
1260
1261
|
delete document.metadata.close_reason;
|
|
1261
1262
|
changedFields.push("close_reason");
|
|
@@ -1700,7 +1701,7 @@ function mutateUpdateDocument(document, context) {
|
|
|
1700
1701
|
return { changedFields: actualChangedFields, warnings };
|
|
1701
1702
|
}
|
|
1702
1703
|
/** Implements run update for the public runtime surface of this module. */
|
|
1703
|
-
|
|
1704
|
+
async function runUpdateWithContext(id, options, global, execution = {}) {
|
|
1704
1705
|
options = await resolveStdinUpdateOptions(options);
|
|
1705
1706
|
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
1706
1707
|
await assertUpdateTrackerInitialized(pmRoot);
|
|
@@ -1820,23 +1821,32 @@ export async function runUpdate(id, options, global) {
|
|
|
1820
1821
|
let graphBeforeUpdate = fieldFlags.dep || fieldFlags.depRemove || fieldFlags.blockedBy
|
|
1821
1822
|
? await listAllItemMetadataLight(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema)
|
|
1822
1823
|
: undefined;
|
|
1823
|
-
|
|
1824
|
+
let lifecycleTransition;
|
|
1825
|
+
let recurrenceHistoryContext;
|
|
1826
|
+
const result = await mutateItemWithHistoryContextResolver({
|
|
1824
1827
|
pmRoot,
|
|
1825
1828
|
settings,
|
|
1826
1829
|
typeToFolder: typeRegistry.type_to_folder,
|
|
1827
1830
|
id,
|
|
1828
|
-
op: options
|
|
1829
|
-
options.ownershipDependencyBypass === true
|
|
1830
|
-
? "update_ownership_bypass"
|
|
1831
|
-
: "update",
|
|
1831
|
+
op: resolveUpdateHistoryOperation(options, execution),
|
|
1832
1832
|
author,
|
|
1833
1833
|
message: options.message,
|
|
1834
|
+
resolveHistoryContext: () => recurrenceHistoryContext,
|
|
1834
1835
|
force: options.force,
|
|
1835
1836
|
bypassAssigneeConflict: options.ownershipMetadataBypass === true ||
|
|
1836
1837
|
options.ownershipDependencyBypass === true,
|
|
1837
1838
|
extensionFieldNames,
|
|
1838
1839
|
skipNoop: true,
|
|
1839
1840
|
mutate(document) {
|
|
1841
|
+
lifecycleTransition = prepareRecurrenceTransition({
|
|
1842
|
+
document,
|
|
1843
|
+
recurrenceReason: execution.recurrenceReason,
|
|
1844
|
+
requestedStatus: options.status,
|
|
1845
|
+
statusRegistry,
|
|
1846
|
+
});
|
|
1847
|
+
recurrenceHistoryContext = lifecycleTransition
|
|
1848
|
+
? { recurrence: lifecycleTransition }
|
|
1849
|
+
: undefined;
|
|
1840
1850
|
graphBeforeUpdate = graphBeforeUpdate?.map((item) => item.id === document.metadata.id
|
|
1841
1851
|
? structuredClone(document.metadata)
|
|
1842
1852
|
: item);
|
|
@@ -1880,8 +1890,80 @@ export async function runUpdate(id, options, global) {
|
|
|
1880
1890
|
...orderingCycleWarnings,
|
|
1881
1891
|
...result.warnings,
|
|
1882
1892
|
],
|
|
1893
|
+
...(lifecycleTransition === undefined
|
|
1894
|
+
? {}
|
|
1895
|
+
: { lifecycle_transition: lifecycleTransition }),
|
|
1883
1896
|
};
|
|
1884
1897
|
}
|
|
1898
|
+
/** Resolve the immutable operation name for ordinary, bypass, and recurrence updates. */
|
|
1899
|
+
function resolveUpdateHistoryOperation(options, execution) {
|
|
1900
|
+
if (options.ownershipMetadataBypass === true ||
|
|
1901
|
+
options.ownershipDependencyBypass === true) {
|
|
1902
|
+
return "update_ownership_bypass";
|
|
1903
|
+
}
|
|
1904
|
+
return execution.recurrenceReason === undefined ? "update" : "reopen";
|
|
1905
|
+
}
|
|
1906
|
+
/** Validate and capture a terminal-to-active recurrence while the item lock is held. */
|
|
1907
|
+
function prepareRecurrenceTransition(params) {
|
|
1908
|
+
if (params.recurrenceReason === undefined) {
|
|
1909
|
+
return undefined;
|
|
1910
|
+
}
|
|
1911
|
+
const fromStatus = normalizeStatusInput(params.document.metadata.status, params.statusRegistry) ?? params.document.metadata.status;
|
|
1912
|
+
if (!isTerminalStatus(fromStatus, params.statusRegistry)) {
|
|
1913
|
+
throw new PmCliError(`Item ${params.document.metadata.id} is already active with status ${fromStatus}; recurrence transitions require a terminal item.`, EXIT_CODE.CONFLICT, {
|
|
1914
|
+
code: "item_already_active",
|
|
1915
|
+
reason: "recurrence_requires_terminal_item",
|
|
1916
|
+
required: "Use item reopen only for a terminal item whose work has recurred.",
|
|
1917
|
+
why: "Appending a recurrence event to active work would corrupt lifecycle history.",
|
|
1918
|
+
recovery: {
|
|
1919
|
+
suggested_retry: `pm get ${params.document.metadata.id} --full`,
|
|
1920
|
+
suggested_retry_args: ["get", params.document.metadata.id, "--full"],
|
|
1921
|
+
},
|
|
1922
|
+
nextSteps: [
|
|
1923
|
+
`Inspect the active item with: pm get ${params.document.metadata.id} --full`,
|
|
1924
|
+
`Continue the existing work with: pm update ${params.document.metadata.id} ...`,
|
|
1925
|
+
],
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
const requestedStatus = params.requestedStatus ?? params.statusRegistry.open_status;
|
|
1929
|
+
const toStatus = normalizeStatusInput(requestedStatus, params.statusRegistry) ??
|
|
1930
|
+
requestedStatus;
|
|
1931
|
+
const metadata = toItemRecord(params.document.metadata);
|
|
1932
|
+
const previousTerminal = Object.fromEntries([
|
|
1933
|
+
"close_reason",
|
|
1934
|
+
"resolution",
|
|
1935
|
+
"expected_result",
|
|
1936
|
+
"actual_result",
|
|
1937
|
+
"fixed_version",
|
|
1938
|
+
].flatMap((key) => {
|
|
1939
|
+
const value = metadata[key];
|
|
1940
|
+
return typeof value === "string" ? [[key, value]] : [];
|
|
1941
|
+
}));
|
|
1942
|
+
return {
|
|
1943
|
+
reason: params.recurrenceReason,
|
|
1944
|
+
from_status: fromStatus,
|
|
1945
|
+
to_status: toStatus,
|
|
1946
|
+
previous_terminal: previousTerminal,
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
/** Implements run update for the public runtime surface of this module. */
|
|
1950
|
+
export async function runUpdate(id, options, global) {
|
|
1951
|
+
return runUpdateWithContext(id, options, global);
|
|
1952
|
+
}
|
|
1953
|
+
/** Execute a recurrence transition through the exact atomic update pipeline. */
|
|
1954
|
+
export async function runReopenUpdate(id, options, global, recurrenceReason) {
|
|
1955
|
+
const result = await runUpdateWithContext(id, options, global, {
|
|
1956
|
+
recurrenceReason,
|
|
1957
|
+
});
|
|
1958
|
+
if (result.lifecycle_transition === undefined) {
|
|
1959
|
+
throw new PmCliError(`Item ${id} did not produce the required recurrence receipt.`, EXIT_CODE.GENERIC_FAILURE, {
|
|
1960
|
+
code: "reopen_receipt_missing",
|
|
1961
|
+
reason: "recurrence_transition_not_recorded",
|
|
1962
|
+
required: "A successful reopen must return the terminal-to-active lifecycle transition recorded in immutable history.",
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
return { ...result, lifecycle_transition: result.lifecycle_transition };
|
|
1966
|
+
}
|
|
1885
1967
|
/* c8 ignore stop */
|
|
1886
1968
|
/** Public contract for test only update command, shared by SDK and presentation-layer consumers. */
|
|
1887
1969
|
export const _testOnlyUpdateCommand = {
|
|
@@ -1900,4 +1982,4 @@ export const _testOnlyUpdateCommand = {
|
|
|
1900
1982
|
resolveRuntimeUnsetDefinition: (token, registry) => resolveRuntimeUnsetFieldDefinition(token, "update", registry),
|
|
1901
1983
|
};
|
|
1902
1984
|
//# sourceMappingURL=update.js.map
|
|
1903
|
-
//# debugId=
|
|
1985
|
+
//# debugId=3ab4f16d-ce37-546e-a2f6-0495fd1967c7
|
|
@@ -33,6 +33,8 @@ export interface ReadRowContract {
|
|
|
33
33
|
row_kind: "collection" | "none";
|
|
34
34
|
/** Dot-delimited paths to array or object-map collections containing iterable result rows. */
|
|
35
35
|
row_keys: string[];
|
|
36
|
+
/** Optional nested collections that are independently resumable without redefining primary result rows. */
|
|
37
|
+
continuation_row_keys?: string[];
|
|
36
38
|
/** Whether the command accepts an explicit row-field projection. */
|
|
37
39
|
fields: "supported" | "unsupported";
|
|
38
40
|
/** Universal jq expression that iterates every declared collection path. */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Declares machine-readable field-group omissions for bounded command results.
|
|
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]="8ffd2cd5-8b7e-5ae1-a0c6-aab488edb73c")}catch(e){}}();
|
|
8
8
|
import { EXIT_CODE } from "../core/shared/constants.js";
|
|
9
9
|
import { PmCliError } from "../core/shared/errors.js";
|
|
10
10
|
const MATERIAL_FIELD_GROUPS_BY_RESULT = new WeakMap();
|
|
@@ -161,15 +161,21 @@ const READ_ROW_TOON_ENCODINGS = new Set([
|
|
|
161
161
|
]);
|
|
162
162
|
const READ_ROW_KINDS = new Set(["collection", "none"]);
|
|
163
163
|
const READ_ROW_FIELD_MODES = new Set(["supported", "unsupported"]);
|
|
164
|
+
function isUniqueNonEmptyStringArray(value, allowEmpty) {
|
|
165
|
+
return (Array.isArray(value) &&
|
|
166
|
+
(allowEmpty || value.length > 0) &&
|
|
167
|
+
value.every((entry) => typeof entry === "string" && entry.length > 0) &&
|
|
168
|
+
new Set(value).size === value.length);
|
|
169
|
+
}
|
|
164
170
|
/** Return whether an unknown value is a structurally valid row declaration. */
|
|
165
171
|
export function isReadRowContract(value) {
|
|
166
172
|
return (isRecord(value) &&
|
|
167
173
|
typeof value.command === "string" &&
|
|
168
174
|
value.command.trim().length > 0 &&
|
|
169
175
|
READ_ROW_KINDS.has(value.row_kind) &&
|
|
170
|
-
|
|
171
|
-
value.
|
|
172
|
-
|
|
176
|
+
isUniqueNonEmptyStringArray(value.row_keys, true) &&
|
|
177
|
+
(value.continuation_row_keys === undefined ||
|
|
178
|
+
isUniqueNonEmptyStringArray(value.continuation_row_keys, false)) &&
|
|
173
179
|
READ_ROW_FIELD_MODES.has(value.fields) &&
|
|
174
180
|
READ_ROW_TOON_ENCODINGS.has(value.toon_encoding) &&
|
|
175
181
|
(value.row_kind === "collection"
|
|
@@ -414,4 +420,4 @@ export function attachOutputOmissionReceipt(command, result) {
|
|
|
414
420
|
: { ...disclosedResult, omission_receipt: receipt };
|
|
415
421
|
}
|
|
416
422
|
//# sourceMappingURL=output-projection.js.map
|
|
417
|
-
//# debugId=
|
|
423
|
+
//# debugId=8ffd2cd5-8b7e-5ae1-a0c6-aab488edb73c
|
package/dist/sdk/query/get.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { type GlobalOptions } from "../runtime-primitives.js";
|
|
|
7
7
|
import { type ChildRollupContext } from "../item-children.js";
|
|
8
8
|
import { type ItemScheduleContext } from "../item-schedule.js";
|
|
9
9
|
import type { ItemMetadata, LinkedDoc, LinkedFile, LinkedTest } from "../../types/index.js";
|
|
10
|
+
export { GET_DEPTH_VALUES, listGetProjectionFields, } from "./projection-contracts.js";
|
|
10
11
|
interface ClaimHistoryContext {
|
|
11
12
|
ts: string;
|
|
12
13
|
author: string;
|
|
@@ -92,4 +93,3 @@ export declare function runGet(id: string, global: GlobalOptions, options?: GetO
|
|
|
92
93
|
export declare const _testOnlyGetCommand: {
|
|
93
94
|
shouldAutoIncludeGetChildren: typeof shouldAutoIncludeGetChildren;
|
|
94
95
|
};
|
|
95
|
-
export {};
|