@unbrained/pm-cli 2026.8.12 → 2026.8.14
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 +162 -111
- package/dist/cli/error-guidance.js +4 -8
- package/dist/cli/main.js +40 -3
- package/dist/cli/register-assurance.js +28 -17
- package/dist/cli-bundle/bundle-manifest.json +141 -173
- package/dist/cli-bundle/chunks/chunk-BBOFSVAK.js +197 -0
- package/dist/cli-bundle/chunks/chunk-BFALV3YP.js +5 -0
- package/dist/cli-bundle/chunks/{chunk-WLAHPSOX.js → chunk-FIW4P64F.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-BM5YJ2UW.js → chunk-G5JUB66K.js} +52 -52
- package/dist/cli-bundle/chunks/chunk-SBRKH6OR.js +2 -0
- package/dist/cli-bundle/chunks/chunk-TMJ7URWS.js +13 -0
- package/dist/cli-bundle/chunks/chunk-TXMEUUUY.js +8 -0
- package/dist/cli-bundle/chunks/{chunk-KOQMGCTA.js → chunk-XAVMOK6B.js} +50 -50
- package/dist/cli-bundle/chunks/chunk-YAMTJL6Y.js +34 -0
- package/dist/cli-bundle/chunks/chunk-YSVSMJ2B.js +2 -0
- package/dist/cli-bundle/chunks/{register-list-query-XPCJRUUD.js → register-list-query-T3EHHNNV.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-4RJCBKRS.js → register-mutation-E27WCLSZ.js} +2 -2
- package/dist/cli-bundle/chunks/register-operations-4R6I7CPY.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-LLHAKP2V.js → register-setup-3YXZ444E.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-JAFRIWVF.js → chunk-4DQ2YERC.js} +4 -4
- package/dist/cli-bundle/focused-chunks/chunk-F43TT2QQ.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-K7RWWOAG.js +4 -0
- package/dist/cli-bundle/focused-chunks/chunk-KFSZ3BP6.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KHM2CS2C.js → chunk-KSEDUWVZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-KYUQGTSB.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-ZMGWAYH7.js → chunk-LZ4MV3RH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-PGXJQLCT.js +155 -0
- package/dist/cli-bundle/focused-chunks/{chunk-RWPAWUOT.js → chunk-PPFGQDSI.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-Q4YY3XNF.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-QK753U3U.js +46 -0
- package/dist/cli-bundle/focused-chunks/chunk-QUMB2J27.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-SM7MTG27.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-GQW4BPUT.js → chunk-WCVE2NIG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-XDNAW5OI.js +18 -0
- package/dist/cli-bundle/focused-chunks/{chunk-YIAXMC3T.js → chunk-YOOI3UZX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZM6TZVHC.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 +1 -1
- package/dist/cli-bundle/sdk-core.js +45 -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 +109 -1
- 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 +2 -2
- package/dist/core/checkpoint/checkpoint-gc.js +7 -12
- package/dist/core/extensions/activation-summary-markdown.js +5 -4
- package/dist/core/extensions/activation-summary.d.ts +2 -0
- package/dist/core/extensions/activation-summary.js +6 -2
- package/dist/core/extensions/capability-usage.d.ts +1 -1
- package/dist/core/extensions/capability-usage.js +4 -3
- package/dist/core/extensions/contribution-inventory.d.ts +1 -0
- package/dist/core/extensions/contribution-inventory.js +6 -2
- package/dist/core/extensions/extension-registries.js +3 -2
- package/dist/core/extensions/extension-types.d.ts +83 -1
- package/dist/core/extensions/extension-types.js +3 -2
- package/dist/core/extensions/loader.d.ts +2 -8
- package/dist/core/extensions/loader.js +53 -144
- package/dist/core/extensions/registration-values.d.ts +43 -0
- package/dist/core/extensions/registration-values.js +210 -0
- package/dist/core/extensions/runtime-registrations.d.ts +3 -1
- package/dist/core/extensions/runtime-registrations.js +12 -2
- package/dist/core/fs/fs-utils.d.ts +2 -0
- package/dist/core/fs/fs-utils.js +7 -3
- package/dist/core/history/drift-cache.js +4 -3
- package/dist/core/history/drift-scan.d.ts +6 -0
- package/dist/core/history/drift-scan.js +76 -58
- package/dist/core/history/workspace-history.d.ts +59 -0
- package/dist/core/history/workspace-history.js +197 -10
- package/dist/core/lock/lock-gc.js +8 -13
- package/dist/core/lock/lock.js +5 -4
- package/dist/core/output/output.js +12 -4
- package/dist/core/search/vector-stores.js +6 -11
- package/dist/core/store/item-metadata-cache.js +4 -4
- package/dist/core/telemetry/runtime.d.ts +6 -0
- package/dist/core/telemetry/runtime.js +101 -30
- package/dist/sdk/agent/command-recovery.d.ts +2 -0
- package/dist/sdk/agent/command-recovery.js +10 -2
- package/dist/sdk/annotations.js +4 -4
- package/dist/sdk/cli-contracts/completeness.js +9 -3
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts/flag-contracts.js +6 -3
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +6 -1
- package/dist/sdk/cli-contracts/runtime-contracts.js +155 -60
- package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +32 -0
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +25 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +35 -5
- package/dist/sdk/cli-contracts/tool-schema.js +17 -2
- package/dist/sdk/cli-program.js +3 -3
- package/dist/sdk/comments.js +4 -3
- package/dist/sdk/compile-cache.js +4 -3
- package/dist/sdk/compose.d.ts +3 -1
- package/dist/sdk/compose.js +16 -2
- package/dist/sdk/context-relevance.js +12 -4
- package/dist/sdk/context-signal-store.js +4 -3
- package/dist/sdk/extension/install-runtime.js +4 -4
- package/dist/sdk/extension/managed-state.js +4 -3
- package/dist/sdk/extension-contracts.d.ts +1 -1
- package/dist/sdk/flag-invocation-contracts.js +5 -6
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
- package/dist/sdk/governance/assurance-action.d.ts +27 -3
- package/dist/sdk/governance/assurance-action.js +112 -28
- package/dist/sdk/governance/assurance-mutation-error.d.ts +7 -0
- package/dist/sdk/governance/assurance-mutation-error.js +25 -2
- package/dist/sdk/governance/assurance-presets.d.ts +54 -0
- package/dist/sdk/governance/assurance-presets.js +136 -0
- package/dist/sdk/governance/assurance-runtime.d.ts +4 -0
- package/dist/sdk/governance/assurance-runtime.js +109 -8
- package/dist/sdk/governance/assurance.d.ts +39 -0
- package/dist/sdk/governance/assurance.js +145 -6
- package/dist/sdk/governance/gc.js +5 -11
- package/dist/sdk/governance/health.js +18 -6
- package/dist/sdk/governance/validate-history-drift.d.ts +7 -0
- package/dist/sdk/governance/validate-history-drift.js +68 -0
- package/dist/sdk/governance/validate.js +6 -48
- package/dist/sdk/graph/assembly.d.ts +23 -0
- package/dist/sdk/graph/assembly.js +54 -2
- package/dist/sdk/graph/durable-cache.js +91 -3
- package/dist/sdk/graph/governance-contracts.d.ts +12 -0
- package/dist/sdk/graph/governance-contracts.js +29 -0
- package/dist/sdk/graph/governance.d.ts +51 -3
- package/dist/sdk/graph/governance.js +216 -35
- package/dist/sdk/graph/index.d.ts +2 -2
- package/dist/sdk/graph/index.js +4 -4
- package/dist/sdk/graph/mutation-advisory.js +15 -7
- package/dist/sdk/graph/remediation.js +12 -2
- package/dist/sdk/guide.js +4 -4
- package/dist/sdk/history-read.d.ts +8 -0
- package/dist/sdk/history-read.js +2 -2
- package/dist/sdk/index.d.ts +3 -2
- package/dist/sdk/index.js +5 -4
- package/dist/sdk/linked-artifacts.d.ts +2 -0
- package/dist/sdk/linked-artifacts.js +29 -4
- package/dist/sdk/merge/install.js +5 -4
- package/dist/sdk/query/activity.js +4 -3
- package/dist/sdk/query/history.js +20 -3
- package/dist/sdk/read-output-budget.d.ts +2 -0
- package/dist/sdk/read-output-budget.js +12 -5
- package/dist/sdk/read-output-contracts.d.ts +61 -5
- package/dist/sdk/read-output-contracts.js +210 -28
- package/dist/sdk/read-output-rows.d.ts +11 -0
- package/dist/sdk/read-output-rows.js +47 -2
- package/dist/sdk/relationship-history.js +5 -5
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.js +5 -3
- package/dist/sdk/schema-migration.js +4 -4
- package/dist/sdk/test/execution.js +4 -4
- package/dist/sdk/workspace-memory.js +4 -4
- package/dist/sdk/workspace-snapshot.js +8 -14
- package/dist/sdk/workspace-transaction-gc.js +4 -9
- package/dist/sdk/workspace-transaction.js +4 -4
- package/dist/sdk/workspace.js +4 -3
- package/docs/ASSURANCE.md +163 -3
- package/docs/COMMANDS.md +31 -2
- package/docs/CONFIGURATION.md +2 -0
- package/docs/EXTENSIONS.md +11 -12
- package/docs/READ_OUTPUT_CONTRACTS.md +44 -8
- package/docs/RELATIONSHIP_GRAPH.md +34 -4
- package/docs/SDK.md +29 -8
- package/docs/SDK_CONTEXT_INTEGRITY.md +32 -1
- package/docs/TESTING.md +47 -16
- package/docs/performance/sdk-entrypoint-import-costs.md +20 -13
- package/marketplace.json +2 -2
- package/package.json +6 -6
- package/packages/pm-beads/extensions/beads/index.ts +1 -0
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/extensions/calendar/index.ts +1 -0
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/extensions/digital-twin/index.ts +7 -0
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/extensions/governance-audit/index.ts +4 -0
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/extensions/guide-shell/index.ts +5 -0
- 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/extensions/linked-test-adapters/index.ts +6 -0
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/extensions/search-advanced/index.ts +2 -0
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/extensions/templates/index.ts +4 -0
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/extensions/todos/index.ts +2 -0
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/extensions/vcs/index.ts +7 -0
- 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/bundle-cli.mjs +17 -4
- package/sdk/public-surface.json +390 -60
- package/dist/cli-bundle/chunks/chunk-3PS7X6GS.js +0 -8
- package/dist/cli-bundle/chunks/chunk-7KL6KMWF.js +0 -13
- package/dist/cli-bundle/chunks/chunk-D55A5AEN.js +0 -33
- package/dist/cli-bundle/chunks/chunk-KIKDWECH.js +0 -196
- package/dist/cli-bundle/chunks/chunk-R76342NV.js +0 -2
- package/dist/cli-bundle/chunks/chunk-RBTK5EZV.js +0 -5
- package/dist/cli-bundle/chunks/chunk-VLUQOIDT.js +0 -2
- package/dist/cli-bundle/chunks/register-operations-2OGISOVR.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-2DALMVF7.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-5OQIMELN.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-5TAGTDRE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-ECADZMVC.js +0 -18
- package/dist/cli-bundle/focused-chunks/chunk-EJGXRA6B.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-FFGSZCPK.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-ISKOBJCM.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-KPSXVBDV.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-KTLOKKCQ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-LGYK3NUF.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-NBLUKITQ.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-NYLOUPOB.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-Q4T463SD.js +0 -31
- package/dist/cli-bundle/focused-chunks/chunk-QVZVY53N.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-UTEWXDEQ.js +0 -17
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* Implements the pm test 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]="76053150-cc55-57e0-80d6-369196284cd0")}catch(e){}}();
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
9
|
import { cp, mkdir, mkdtemp, open, readdir, rm } from "node:fs/promises";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
|
|
13
|
-
import { pathExists } from "../../core/fs/fs-utils.js";
|
|
13
|
+
import { isFileMissingError, pathExists } from "../../core/fs/fs-utils.js";
|
|
14
14
|
import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
|
|
15
15
|
import { createStdinTokenResolver, parseCsvKv, parseOptionalNumber, } from "../../core/item/parse.js";
|
|
16
16
|
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
@@ -989,7 +989,7 @@ async function copyIntoSandboxIfPresent(sourcePath, targetPath, recursive = fals
|
|
|
989
989
|
if (typeof error === "object" &&
|
|
990
990
|
error !== null &&
|
|
991
991
|
"code" in error &&
|
|
992
|
-
error
|
|
992
|
+
isFileMissingError(error)) {
|
|
993
993
|
return;
|
|
994
994
|
}
|
|
995
995
|
throw error;
|
|
@@ -1939,4 +1939,4 @@ export const _testOnlyTestCommand = {
|
|
|
1939
1939
|
summarizeRunResultStatuses,
|
|
1940
1940
|
};
|
|
1941
1941
|
//# sourceMappingURL=execution.js.map
|
|
1942
|
-
//# debugId=
|
|
1942
|
+
//# debugId=76053150-cc55-57e0-80d6-369196284cd0
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Builds compact, cursor-bound historical rollups for large workspaces.
|
|
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]="ad77a79d-54da-55f1-8ac8-935366880d90")}catch(e){}}();
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
|
-
import { writeFileAtomic } from "../core/fs/fs-utils.js";
|
|
10
|
+
import { isFileAbsentError, writeFileAtomic } from "../core/fs/fs-utils.js";
|
|
11
11
|
import { normalizeStatusForRegistry } from "../core/item/status.js";
|
|
12
12
|
import { stableStringify } from "../core/shared/serialization.js";
|
|
13
13
|
import { readItemMetadataDerivedIndexState } from "../core/store/item-metadata-cache.js";
|
|
@@ -194,7 +194,7 @@ async function readPersistedWorkspaceMemory(filePath) {
|
|
|
194
194
|
const missing = typeof error === "object" &&
|
|
195
195
|
error !== null &&
|
|
196
196
|
"code" in error &&
|
|
197
|
-
error
|
|
197
|
+
isFileAbsentError(error);
|
|
198
198
|
return { snapshot: null, invalid: !missing };
|
|
199
199
|
}
|
|
200
200
|
}
|
|
@@ -316,4 +316,4 @@ export function searchWorkspaceMemoryReadResult(memory, query, limit = 5) {
|
|
|
316
316
|
};
|
|
317
317
|
}
|
|
318
318
|
//# sourceMappingURL=workspace-memory.js.map
|
|
319
|
-
//# debugId=
|
|
319
|
+
//# debugId=ad77a79d-54da-55f1-8ac8-935366880d90
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* state while excluding clone-local caches, locks, and recovery journals.
|
|
6
6
|
*/
|
|
7
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]="
|
|
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]="36aacc71-c5f5-56f1-85f4-28b2be5b02e2")}catch(e){}}();
|
|
9
9
|
import crypto from "node:crypto";
|
|
10
10
|
import { cp, lstat, mkdir, readFile, readdir, rename, rm, writeFile, } from "node:fs/promises";
|
|
11
11
|
import path from "node:path";
|
|
12
|
-
import { writeFileAtomic } from "../core/fs/fs-utils.js";
|
|
12
|
+
import { isFileMissingError, writeFileAtomic } from "../core/fs/fs-utils.js";
|
|
13
13
|
import { appendWorkspaceAuditEvent } from "../core/history/workspace-history.js";
|
|
14
14
|
import { acquireLock } from "../core/lock/lock.js";
|
|
15
15
|
import { getLockPath } from "../core/store/paths.js";
|
|
@@ -205,12 +205,6 @@ function validateSnapshotTarget(target) {
|
|
|
205
205
|
});
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
|
-
function isErrno(error, code) {
|
|
209
|
-
return (typeof error === "object" &&
|
|
210
|
-
error !== null &&
|
|
211
|
-
"code" in error &&
|
|
212
|
-
error.code === code);
|
|
213
|
-
}
|
|
214
208
|
/**
|
|
215
209
|
* Runs a bounded snapshot filesystem stage, converting host environment faults
|
|
216
210
|
* into declared refusals.
|
|
@@ -250,7 +244,7 @@ async function readSnapshotJson(file, target) {
|
|
|
250
244
|
return JSON.parse(await readFile(file, "utf8"));
|
|
251
245
|
}
|
|
252
246
|
catch (error) {
|
|
253
|
-
if (
|
|
247
|
+
if (isFileMissingError(error)) {
|
|
254
248
|
throw workspaceSnapshotNotFound(target);
|
|
255
249
|
}
|
|
256
250
|
throw error;
|
|
@@ -261,7 +255,7 @@ async function removeSnapshotEntry(entry, target, recursive) {
|
|
|
261
255
|
await rm(entry, { recursive });
|
|
262
256
|
}
|
|
263
257
|
catch (error) {
|
|
264
|
-
if (
|
|
258
|
+
if (isFileMissingError(error)) {
|
|
265
259
|
throw workspaceSnapshotNotFound(target);
|
|
266
260
|
}
|
|
267
261
|
throw error;
|
|
@@ -335,7 +329,7 @@ export async function createWorkspaceSnapshot(pmRoot, options = {}) {
|
|
|
335
329
|
deduplicated = objectStat.isDirectory();
|
|
336
330
|
}
|
|
337
331
|
catch (error) {
|
|
338
|
-
if (!(error instanceof Error && "code" in error && error
|
|
332
|
+
if (!(error instanceof Error && "code" in error && isFileMissingError(error))) {
|
|
339
333
|
throw error;
|
|
340
334
|
}
|
|
341
335
|
}
|
|
@@ -392,7 +386,7 @@ export async function listWorkspaceSnapshots(pmRoot) {
|
|
|
392
386
|
const objectNames = await readdir(path.join(store, "objects")).catch((error) => {
|
|
393
387
|
if (error instanceof Error &&
|
|
394
388
|
"code" in error &&
|
|
395
|
-
error
|
|
389
|
+
isFileMissingError(error)) {
|
|
396
390
|
return [];
|
|
397
391
|
}
|
|
398
392
|
throw error;
|
|
@@ -400,7 +394,7 @@ export async function listWorkspaceSnapshots(pmRoot) {
|
|
|
400
394
|
const referenceNames = await readdir(path.join(store, "refs")).catch((error) => {
|
|
401
395
|
if (error instanceof Error &&
|
|
402
396
|
"code" in error &&
|
|
403
|
-
error
|
|
397
|
+
isFileMissingError(error)) {
|
|
404
398
|
return [];
|
|
405
399
|
}
|
|
406
400
|
throw error;
|
|
@@ -609,4 +603,4 @@ export async function deleteWorkspaceSnapshot(pmRoot, target) {
|
|
|
609
603
|
return { deleted: "object", target };
|
|
610
604
|
}
|
|
611
605
|
//# sourceMappingURL=workspace-snapshot.js.map
|
|
612
|
-
//# debugId=
|
|
606
|
+
//# debugId=36aacc71-c5f5-56f1-85f4-28b2be5b02e2
|
|
@@ -13,17 +13,12 @@
|
|
|
13
13
|
* never breaks correctness.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
!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]="
|
|
16
|
+
!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]="7df80849-51e1-5efa-b40a-b44088f941a9")}catch(e){}}();
|
|
17
|
+
import { isFileMissingError } from "../core/fs/fs-utils.js";
|
|
17
18
|
import fs from "node:fs/promises";
|
|
18
19
|
import path from "node:path";
|
|
19
20
|
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
20
21
|
const TERMINAL_JOURNAL_STATUSES = new Set(["committed", "compensated"]);
|
|
21
|
-
function isErrno(error, code) {
|
|
22
|
-
return (typeof error === "object" &&
|
|
23
|
-
error !== null &&
|
|
24
|
-
"code" in error &&
|
|
25
|
-
error.code === code);
|
|
26
|
-
}
|
|
27
22
|
function readJournalStatusAndTimestamp(raw) {
|
|
28
23
|
let parsed;
|
|
29
24
|
try {
|
|
@@ -129,7 +124,7 @@ export async function runWorkspaceTransactionGc(pmRoot, options) {
|
|
|
129
124
|
.sort((left, right) => left.localeCompare(right));
|
|
130
125
|
}
|
|
131
126
|
catch (error) {
|
|
132
|
-
if (
|
|
127
|
+
if (isFileMissingError(error)) {
|
|
133
128
|
return result;
|
|
134
129
|
}
|
|
135
130
|
throw error;
|
|
@@ -152,4 +147,4 @@ export async function runWorkspaceTransactionGc(pmRoot, options) {
|
|
|
152
147
|
return result;
|
|
153
148
|
}
|
|
154
149
|
//# sourceMappingURL=workspace-transaction-gc.js.map
|
|
155
|
-
//# debugId=
|
|
150
|
+
//# debugId=7df80849-51e1-5efa-b40a-b44088f941a9
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* mutation primitives without rewriting immutable item or relationship history.
|
|
6
6
|
*/
|
|
7
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]="
|
|
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]="6ed4a26f-2ae2-556a-87db-56844108757f")}catch(e){}}();
|
|
9
9
|
import { mkdir, readFile } from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { acquireLock } from "../core/lock/lock.js";
|
|
12
|
-
import { writeFileAtomic } from "../core/fs/fs-utils.js";
|
|
12
|
+
import { isFileMissingError, writeFileAtomic } from "../core/fs/fs-utils.js";
|
|
13
13
|
import { nowIso } from "../core/shared/time.js";
|
|
14
14
|
/**
|
|
15
15
|
* Deliberate process-boundary interruption used by deterministic crash tests.
|
|
@@ -244,7 +244,7 @@ async function loadJournal(pmRoot, transactionId, stepIds) {
|
|
|
244
244
|
if (error !== null &&
|
|
245
245
|
typeof error === "object" &&
|
|
246
246
|
"code" in error &&
|
|
247
|
-
error
|
|
247
|
+
isFileMissingError(error))
|
|
248
248
|
return undefined;
|
|
249
249
|
throw error;
|
|
250
250
|
}
|
|
@@ -361,4 +361,4 @@ export async function commitWorkspaceTransaction(options) {
|
|
|
361
361
|
}
|
|
362
362
|
}
|
|
363
363
|
//# sourceMappingURL=workspace-transaction.js.map
|
|
364
|
-
//# debugId=
|
|
364
|
+
//# debugId=6ed4a26f-2ae2-556a-87db-56844108757f
|
package/dist/sdk/workspace.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Maintains repository-scaffold contracts shared by the public SDK and CLI.
|
|
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]="89261a49-97e5-5ffc-a81c-2409f0b529cf")}catch(e){}}();
|
|
8
|
+
import { isFileMissingError } from "../core/fs/fs-utils.js";
|
|
8
9
|
import { readFile, writeFile } from "node:fs/promises";
|
|
9
10
|
import path from "node:path";
|
|
10
11
|
import { EXIT_CODE } from "../core/shared/constants.js";
|
|
@@ -107,7 +108,7 @@ export async function ensurePmGitignore(workspaceRoot, options = {}) {
|
|
|
107
108
|
current = await withGitignorePermissionRecovery(() => readFile(gitignorePath, "utf8"));
|
|
108
109
|
}
|
|
109
110
|
catch (error) {
|
|
110
|
-
if (!(error instanceof Error && "code" in error && error
|
|
111
|
+
if (!(error instanceof Error && "code" in error && isFileMissingError(error))) {
|
|
111
112
|
throw error;
|
|
112
113
|
}
|
|
113
114
|
}
|
|
@@ -125,4 +126,4 @@ export async function ensurePmGitignore(workspaceRoot, options = {}) {
|
|
|
125
126
|
return { path: gitignorePath, changed: true };
|
|
126
127
|
}
|
|
127
128
|
//# sourceMappingURL=workspace.js.map
|
|
128
|
-
//# debugId=
|
|
129
|
+
//# debugId=89261a49-97e5-5ffc-a81c-2409f0b529cf
|
package/docs/ASSURANCE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Project Assurance Primitives
|
|
2
2
|
|
|
3
|
-
Tracker: [pm-2lex4r](../.agents/pm/features/pm-2lex4r.toon), [pm-lyfu7b](../.agents/pm/features/pm-lyfu7b.toon), [pm-wn6wot](../.agents/pm/features/pm-wn6wot.toon), [pm-91xeam](../.agents/pm/features/pm-91xeam.toon), [pm-py7qv2](../.agents/pm/issues/pm-py7qv2.toon), [pm-33mjrw](../.agents/pm/issues/pm-33mjrw.toon), [pm-q6n8sj](../.agents/pm/issues/pm-q6n8sj.toon)
|
|
3
|
+
Tracker: [pm-2lex4r](../.agents/pm/features/pm-2lex4r.toon), [pm-lyfu7b](../.agents/pm/features/pm-lyfu7b.toon), [pm-wn6wot](../.agents/pm/features/pm-wn6wot.toon), [pm-91xeam](../.agents/pm/features/pm-91xeam.toon), [pm-uhv1m5](../.agents/pm/features/pm-uhv1m5.toon), [pm-m7bb7r](../.agents/pm/features/pm-m7bb7r.toon), [pm-py7qv2](../.agents/pm/issues/pm-py7qv2.toon), [pm-33mjrw](../.agents/pm/issues/pm-33mjrw.toon), [pm-q6n8sj](../.agents/pm/issues/pm-q6n8sj.toon), [pm-h06944](../.agents/pm/issues/pm-h06944.toon), [pm-dwj33e](../.agents/pm/decisions/pm-dwj33e.toon)
|
|
4
4
|
|
|
5
5
|
## Agent Quick Context
|
|
6
6
|
|
|
@@ -12,6 +12,15 @@ Assurance turns project policy into three reusable SDK-owned declarations:
|
|
|
12
12
|
|
|
13
13
|
Declarations live in `.agents/pm/assurance.json`. Every registry mutation and non-dry gate verdict is appended through the verified workspace history stream; never edit either file directly.
|
|
14
14
|
|
|
15
|
+
`pm history _workspace --verify`, `pm validate`, and `pm health` verify both
|
|
16
|
+
the hash chain and replay-to-disk agreement for every governed singleton. A
|
|
17
|
+
valid chain paired with a different, missing, or unreadable singleton is still
|
|
18
|
+
drift. SDK hosts can inspect that state with `inspectWorkspaceHistoryState`,
|
|
19
|
+
adopt a reviewed out-of-band value only through
|
|
20
|
+
`reconcileWorkspaceJsonHistory` with a terminal authorizing Decision, or
|
|
21
|
+
replace it from a verified version with `restoreWorkspaceJsonFromHistory`.
|
|
22
|
+
Both recovery paths append forward; neither rewrites the existing stream.
|
|
23
|
+
|
|
15
24
|
## Why Assurance Exists
|
|
16
25
|
|
|
17
26
|
Project management is context management. A useful quality gate therefore needs more than a shell exit code: it must preserve what was measured, which population was judged, why a bound exists, who owns it, what changed the result, how expensive the evaluation was, and which immutable tree received the verdict.
|
|
@@ -36,6 +45,11 @@ Measurements support these built-in sources:
|
|
|
36
45
|
|
|
37
46
|
Each measurement may declare `max_cost`. Evaluation fails closed when the total abstract compute units exceed that ceiling. Every result reports units, scanned items, scanned history rows, provider calls, duration, population size, and contributors.
|
|
38
47
|
|
|
48
|
+
One workspace context memoizes identical graph operations and the shared
|
|
49
|
+
validate and health reports for its lifetime. A gate may therefore project many
|
|
50
|
+
fields from one authoritative audit snapshot without multiplying full-workspace
|
|
51
|
+
I/O or allowing concurrent assertions to observe different tracker states.
|
|
52
|
+
|
|
39
53
|
An `items` source with `field` must declare exactly one predicate: `equals` (including an explicit `null`) or `state`. `state: missing` treats an absent property, `null`, an empty string, or an empty array as missing; `state: present` selects the complement. Workspace evaluation loads full item metadata, so `files`, `tests`, and `docs` selectors measure stored evidence rather than a light projection that omitted those collections.
|
|
40
54
|
|
|
41
55
|
Assertions require exactly one polarity:
|
|
@@ -86,6 +100,152 @@ pm assurance remove gate release-readiness
|
|
|
86
100
|
|
|
87
101
|
Referenced measurements and assertions cannot be removed. Remove the consuming gate or assertion first.
|
|
88
102
|
|
|
103
|
+
### Presets, derivation, and promotion
|
|
104
|
+
|
|
105
|
+
List the four built-in project shapes, preview one as ordinary declarations, or apply it atomically:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pm assurance presets
|
|
109
|
+
pm assurance presets software-delivery --owner pm-example
|
|
110
|
+
pm assurance apply software-delivery --owner pm-example \
|
|
111
|
+
--message "Adopt the initial delivery evidence contract"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The preset creates measurements, assertions, and a gate in one audited transaction. Reapplying the same bundle is idempotent; an existing divergent id is refused rather than overwritten. The available shapes are `software-delivery`, `research`, `agent-evaluation`, and `operations`.
|
|
115
|
+
|
|
116
|
+
Self-derivation observes active items without writing anything. Each proposal reports its active scope, population size, and observed missing-evidence ceiling. Persistence requires the explicit `--apply` flag:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pm assurance derive --owner pm-example
|
|
120
|
+
pm assurance derive --owner pm-example --apply \
|
|
121
|
+
--message "Accept the observed evidence baseline"
|
|
122
|
+
pm assurance promote derived-active-missing-tests-ceiling --enforcement warn
|
|
123
|
+
pm assurance promote derived-active-missing-tests-ceiling --enforcement block
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Derived assertions start at `observe`. Promotion is exactly one step (`observe` to `warn`, then `warn` to `block`) and each transition is an ordinary audited declaration mutation. There is no automatic promotion and no privileged preset execution path.
|
|
127
|
+
|
|
128
|
+
## Extension Measurement Providers
|
|
129
|
+
|
|
130
|
+
An extension opens the measurement vocabulary through `api.registerAssuranceMeasurementProvider`. The registration declares stable keys, parameter types, a coarse `low`/`medium`/`high` cost class, network use, a host timeout, and a resolver. It requires the `services` capability; a network provider must also declare `permissions.network: true` in `manifest.json`.
|
|
131
|
+
|
|
132
|
+
This code-quality provider measures a local report without changing assertion or gate semantics:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { readFile } from "node:fs/promises";
|
|
136
|
+
import { defineExtension } from "@unbrained/pm-cli/sdk";
|
|
137
|
+
|
|
138
|
+
export default defineExtension({
|
|
139
|
+
activate(api) {
|
|
140
|
+
api.registerAssuranceMeasurementProvider({
|
|
141
|
+
id: "coverage",
|
|
142
|
+
keys: {
|
|
143
|
+
lines: {
|
|
144
|
+
value_type: "number",
|
|
145
|
+
parameters: { report: { type: "string", required: true } },
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
cost_class: "low",
|
|
149
|
+
network: false,
|
|
150
|
+
timeout_ms: 2_000,
|
|
151
|
+
async resolve({ parameters }) {
|
|
152
|
+
const report = JSON.parse(
|
|
153
|
+
await readFile(String(parameters.report), "utf8"),
|
|
154
|
+
) as {
|
|
155
|
+
total: { lines: { pct: number } };
|
|
156
|
+
};
|
|
157
|
+
return { value: report.total.lines.pct, population_size: 1, cost: 1 };
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
An evaluation package can expose episode reward on the same surface:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
api.registerAssuranceMeasurementProvider({
|
|
168
|
+
id: "agent-eval",
|
|
169
|
+
keys: {
|
|
170
|
+
"mean-reward": {
|
|
171
|
+
value_type: "number",
|
|
172
|
+
parameters: { suite: { type: "string", required: true } },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
cost_class: "high",
|
|
176
|
+
network: false,
|
|
177
|
+
timeout_ms: 120_000,
|
|
178
|
+
async resolve({ parameters }) {
|
|
179
|
+
const result = await runFrozenEvaluation(String(parameters.suite));
|
|
180
|
+
return {
|
|
181
|
+
value: result.meanReward,
|
|
182
|
+
population_size: result.episodes,
|
|
183
|
+
cost: result.steps,
|
|
184
|
+
contributors: result.regressedScenarioIds,
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
An external registry provider declares its network dependency explicitly:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
api.registerAssuranceMeasurementProvider({
|
|
194
|
+
id: "npm-registry",
|
|
195
|
+
keys: {
|
|
196
|
+
"dist-tag-count": {
|
|
197
|
+
value_type: "number",
|
|
198
|
+
parameters: { package: { type: "string", required: true } },
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
cost_class: "medium",
|
|
202
|
+
network: true,
|
|
203
|
+
timeout_ms: 5_000,
|
|
204
|
+
async resolve({ parameters }) {
|
|
205
|
+
const name = encodeURIComponent(String(parameters.package));
|
|
206
|
+
const response = await fetch(
|
|
207
|
+
`https://registry.npmjs.org/-/package/${name}/dist-tags`,
|
|
208
|
+
);
|
|
209
|
+
if (!response.ok) throw new Error(`registry returned ${response.status}`);
|
|
210
|
+
const tags = (await response.json()) as Record<string, string>;
|
|
211
|
+
return { value: Object.keys(tags).length, population_size: 1, cost: 10 };
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
The corresponding measurement is ordinary registry data:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"id": "published-tag-count",
|
|
221
|
+
"source": {
|
|
222
|
+
"kind": "provider",
|
|
223
|
+
"provider": "npm-registry",
|
|
224
|
+
"key": "dist-tag-count",
|
|
225
|
+
"parameters": { "package": "@example/tool" }
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
A provider-backed gate must opt into every provider and each trigger's execution envelope. Omission refuses provider execution:
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"id": "release-readiness",
|
|
235
|
+
"assertion_ids": ["published-tag-count-ceiling"],
|
|
236
|
+
"triggers": ["ci", "scheduled"],
|
|
237
|
+
"provider_policy": {
|
|
238
|
+
"allowed_providers": ["npm-registry"],
|
|
239
|
+
"triggers": {
|
|
240
|
+
"ci": { "max_cost_class": "low", "allow_network": false },
|
|
241
|
+
"scheduled": { "max_cost_class": "medium", "allow_network": true }
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Before invocation the host verifies the provider allow-list, declared cost class, and network capability for the active trigger. It then validates key parameters and result shape, enforces the registered timeout, and charges the returned cost through the existing measurement ceiling. Extension tests must bind `PM_PATH` and `PM_GLOBAL_PATH` to temporary roots; never point provider fixtures at the repository tracker or a live service.
|
|
248
|
+
|
|
89
249
|
## SDK and MCP
|
|
90
250
|
|
|
91
251
|
The reusable client exposes the same action grammar:
|
|
@@ -103,9 +263,9 @@ await pm.assurance({
|
|
|
103
263
|
});
|
|
104
264
|
```
|
|
105
265
|
|
|
106
|
-
For direct host composition, use `evaluateMeasurement`, `evaluateAssuranceGate`, `createAssuranceWorkspaceContext`, and the audited declaration/verdict helpers exported from `@unbrained/pm-cli/sdk`.
|
|
266
|
+
For direct host composition, use `evaluateMeasurement`, `evaluateAssuranceGate`, `createAssuranceWorkspaceContext`, the preset/derivation helpers, and the audited declaration/verdict helpers exported from `@unbrained/pm-cli/sdk`. Active extension registrations are discovered automatically. Embedding hosts may additionally pass stable resolver ids and matching `provider_capabilities` to `createAssuranceWorkspaceContext`; an absent resolver or capability fails loudly. The core evaluator bounds concurrent assertions and expression operands, and workspace history loading uses bounded concurrency; item-only callers can explicitly skip history and Git identity resolution.
|
|
107
267
|
|
|
108
|
-
Generic SDK and MCP dispatch use `action: "assurance"` with `subcommand` set to `list`, `show`, `put`, `remove`, `run`, or `
|
|
268
|
+
Generic SDK and MCP dispatch use `action: "assurance"` with `subcommand` set to `list`, `show`, `put`, `remove`, `run`, `verdicts`, `presets`, `apply`, `derive`, or `promote`. Discover the current machine contract instead of copying parameter lists:
|
|
109
269
|
|
|
110
270
|
```bash
|
|
111
271
|
pm contracts --action assurance --schema-only --json
|
package/docs/COMMANDS.md
CHANGED
|
@@ -21,7 +21,29 @@ pm contracts --command <command> --flags-only --json
|
|
|
21
21
|
|
|
22
22
|
Tracked documentation work: [pm-u9d0](../.agents/pm/epics/pm-u9d0.toon),
|
|
23
23
|
[pm-7nqo6b](../.agents/pm/issues/pm-7nqo6b.toon), and
|
|
24
|
-
[pm-j1r8gl](../.agents/pm/issues/pm-j1r8gl.toon).
|
|
24
|
+
[pm-j1r8gl](../.agents/pm/issues/pm-j1r8gl.toon). Universal command intent and
|
|
25
|
+
default output-budget enforcement are tracked by
|
|
26
|
+
[pm-5t33or](../.agents/pm/features/pm-5t33or.toon),
|
|
27
|
+
[pm-s2h0mq](../.agents/pm/issues/pm-s2h0mq.toon),
|
|
28
|
+
[pm-pmrae8](../.agents/pm/issues/pm-pmrae8.toon), and
|
|
29
|
+
[pm-7i97c3](../.agents/pm/issues/pm-7i97c3.toon).
|
|
30
|
+
|
|
31
|
+
### Universal read-output ceiling
|
|
32
|
+
|
|
33
|
+
Every SDK-backed read has a format-aware default token ceiling discovered from
|
|
34
|
+
`pm contracts`. Results already within that ceiling are returned unchanged, so
|
|
35
|
+
the default adds no receipt overhead to ordinary reads. An oversized result is
|
|
36
|
+
degraded deterministically through string compaction, row compaction, and a
|
|
37
|
+
truthful omission envelope; automatic degradation adds `read_output` with
|
|
38
|
+
`budget_source: default`, `budget_tokens`, the final estimate, and the applied
|
|
39
|
+
compaction flags.
|
|
40
|
+
|
|
41
|
+
Use `--output-budget <tokens>` to request a tighter per-call ceiling. Use
|
|
42
|
+
`--output-budget unbounded` only when the caller deliberately accepts the full
|
|
43
|
+
cost. This cost opt-out is distinct from command-local row controls such as
|
|
44
|
+
`activity --unbounded`, which disable a row limit but do not disable the shared
|
|
45
|
+
token ceiling. `--output-format json` and global `--json` select the declared
|
|
46
|
+
JSON ceiling; TOON uses the smaller default agent ceiling.
|
|
25
47
|
|
|
26
48
|
## Command Families
|
|
27
49
|
|
|
@@ -1161,7 +1183,14 @@ Extension policy tokens are explicitly scoped by
|
|
|
1161
1183
|
Project-governance setters use the separate `governance_contracts` value
|
|
1162
1184
|
domains; in particular, workflow enforcement is `off|warn|strict`, not the
|
|
1163
1185
|
extension policy token `enforce`.
|
|
1164
|
-
Use `pm contracts --summary --json` first when bootstrapping in a tight context
|
|
1186
|
+
Use `pm contracts --summary --json` first when bootstrapping in a tight context
|
|
1187
|
+
window. `command_summaries` contains exactly one row per advertised command
|
|
1188
|
+
path—including aliases and namespace children—with a meaningful intent plus
|
|
1189
|
+
`default_max_estimated_tokens` and the format-specific TOON/JSON ceilings.
|
|
1190
|
+
Package commands contribute their intent through command registration (falling
|
|
1191
|
+
back to the registered description), so agents never need a generic
|
|
1192
|
+
`Inspect flags.` placeholder. Request heavier command-specific flags or schemas
|
|
1193
|
+
only after selecting the exact path.
|
|
1165
1194
|
|
|
1166
1195
|
## Completion
|
|
1167
1196
|
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -156,6 +156,7 @@ Telemetry is opt-in via `pm config set telemetry-tracking on` (see [Common Setti
|
|
|
156
156
|
| `PM_TELEMETRY_OTEL_DISABLED` | boolean | Disable only OTLP trace-span export; the event queue still flushes. |
|
|
157
157
|
| `PM_TELEMETRY_INLINE_FLUSH` | boolean | Flush the queue and OTLP spans inline instead of dispatching the detached worker. Mainly for tests; normal use relies on the background worker. |
|
|
158
158
|
| `PM_TELEMETRY_SOURCE_CONTEXT` | `user` \| `automation` \| `test` \| `dogfood` | Override the inferred source context recorded on each event. Any other value is ignored and the context is inferred. |
|
|
159
|
+
| `PM_TELEMETRY_HTTP_TIMEOUT_MS` | integer milliseconds | Bound each background event or OTLP request (default `20000`, clamped to `1000`–`25000` to stay below the worker lock TTL). |
|
|
159
160
|
| `PM_TELEMETRY_INGEST_KEY` | string | Sent as the `x-pm-telemetry-key` header on queue flushes; never logged. |
|
|
160
161
|
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | URL | OTLP/HTTP traces endpoint for command spans. Takes precedence over the base endpoint. |
|
|
161
162
|
| `OTEL_EXPORTER_OTLP_ENDPOINT` | URL | Base OTLP endpoint; the traces endpoint is derived by appending `/v1/traces`. |
|
|
@@ -164,6 +165,7 @@ Telemetry is opt-in via `pm config set telemetry-tracking on` (see [Common Setti
|
|
|
164
165
|
Interaction rules:
|
|
165
166
|
|
|
166
167
|
- `PM_TELEMETRY_DISABLED` / `PM_NO_TELEMETRY` short-circuit everything, including OTLP export, regardless of the other knobs.
|
|
168
|
+
- `PM_TELEMETRY_HTTP_TIMEOUT_MS` applies only to the detached flush worker in normal use. It covers DNS, each IPv4/IPv6 connection attempt, TLS, and response completion. The upper bound preserves the 60-second worker-lock safety margin across the sequential event and OTLP phases; it does not make foreground commands wait for the network.
|
|
167
169
|
- OTLP span export only happens when telemetry is enabled, `PM_TELEMETRY_OTEL_DISABLED` is off, and a traces endpoint is configured. By default spans are persisted to a bounded queue and exported by the detached, unref'd flush worker so commands exit promptly even when the traces endpoint is unreachable. `PM_TELEMETRY_INLINE_FLUSH=1` is the explicit test-oriented exception that performs the flush inline.
|
|
168
170
|
- `pm health --check-telemetry --json` surfaces flush and OTLP export diagnostics (`pending_otel_spans`, `last_otel_attempt_at`, `last_otel_success_at`, `last_otel_failure_at`, `last_otel_failure_error`) and the active `env_overrides` (including `telemetry_inline_flush` and `telemetry_source_context`) so agents can self-diagnose a stalled endpoint.
|
|
169
171
|
- An explicit `PM_AUTHOR` override adds a privacy-preserving agent-identity dimension to `command_start`/`command_finish` events so overridden invocations can be segmented in dashboards without leaking the raw author string. At `redacted`/`max` capture the events carry `author_context_hash` — the same installation-id-keyed one-way SHA-256 used for `pm_root_hash`/`cwd_hash`, so the same author hashes consistently within an installation but differently across installations. At `minimal` capture only a boolean `has_author_context` is emitted. The raw `PM_AUTHOR` value is never exported.
|
package/docs/EXTENSIONS.md
CHANGED
|
@@ -29,6 +29,7 @@ pm install npm:package@1.2.3 --project
|
|
|
29
29
|
pm install https://github.com/org/repo --project
|
|
30
30
|
pm install --github org/repo/path --ref main --project
|
|
31
31
|
```
|
|
32
|
+
|
|
32
33
|
Bundled first-party packages live under `packages/pm-*`:
|
|
33
34
|
|
|
34
35
|
```bash
|
|
@@ -38,6 +39,7 @@ pm install calendar --project
|
|
|
38
39
|
pm install search-advanced --project
|
|
39
40
|
pm install kanban --project
|
|
40
41
|
```
|
|
42
|
+
|
|
41
43
|
`pm install '*'`, `pm install all`, and shell-expanded `pm install *` are normalized to the same bundled install-all request. First-party package aliases come from each package manifest, with a fallback derived from the `packages/pm-*` directory name. A bare bundled alias that also names an installed npm package reports both explicit choices in `source_resolution`; see [Extension Lifecycle Contracts](EXTENSION_LIFECYCLE.md).
|
|
42
44
|
|
|
43
45
|
External registry packages are installed by exact package name. If `npm:<name>` returns a registry 404, JSON error output includes `fallback_candidates` and `next_best_command`; unpublished first-party packages fall back to `pm install --project github.com/unbraind/<name>`. Install results include package-owned `command_paths`, `action_paths`, `contributions`, `command_discovery`, and a light `verification` block covering the target tracker, activation status, registered commands/actions/item types, and health verdict. Agents should consume those fields instead of guessing from the package name or immediately spending another invocation on doctor. A successful activation persists the versioned contribution inventory in `.managed-extensions.json`; subsequent discovery can enumerate command handlers, hooks, parser/renderer targets, schema names, and the other registered surfaces without importing the package module. A failed runtime activation returns `ok: false`, `activated: false`, a non-zero CLI exit, and actionable diagnostics; missing SDK resolution adds an explicit dependency recovery step. Local installs are containment-safe when the extension destination is nested inside the source checkout: pm stages the package outside the source and prunes the destination, `.agents`, `node_modules`, and install-backup directories before copying, so reinstalling cannot recursively copy tracker history, host dependencies, or prior backups.
|
|
@@ -52,6 +54,7 @@ pm install npm:pm-github --project
|
|
|
52
54
|
pm package doctor --project --detail deep --trace
|
|
53
55
|
pm github validate --repo owner/repo
|
|
54
56
|
```
|
|
57
|
+
|
|
55
58
|
For `pm-github`, run `pm github validate --repo owner/repo` before mutating commands; write paths require `GITHUB_TOKEN`/`GH_TOKEN` or `gh auth login`.
|
|
56
59
|
|
|
57
60
|
For ecosystem maintenance, use the reusable external package smoke harness after building `dist/`:
|
|
@@ -132,7 +135,11 @@ Extensions are authored **and loaded** as TypeScript (ADR [pm-2c28](../.agents/p
|
|
|
132
135
|
"process_spawn": false
|
|
133
136
|
},
|
|
134
137
|
"capabilities": ["commands"],
|
|
135
|
-
"contributions": {
|
|
138
|
+
"contributions": {
|
|
139
|
+
"schema_version": 1,
|
|
140
|
+
"commands": ["hello"],
|
|
141
|
+
"command_handlers": ["hello"]
|
|
142
|
+
},
|
|
136
143
|
"activation": { "commands": ["hello"] }
|
|
137
144
|
}
|
|
138
145
|
```
|
|
@@ -286,11 +293,9 @@ Doctor JSON also includes `triage.collision_plan` with grouped surfaces, ranked
|
|
|
286
293
|
## Runtime APIs
|
|
287
294
|
|
|
288
295
|
Use the public SDK barrel. Do not deep-import from `src/core` or `dist/core`.
|
|
289
|
-
|
|
290
296
|
```ts
|
|
291
297
|
import { defineExtension } from "@unbrained/pm-cli/sdk";
|
|
292
298
|
```
|
|
293
|
-
|
|
294
299
|
Common APIs:
|
|
295
300
|
|
|
296
301
|
- `api.extension` is a read-only identity (`name`, `layer`, `version`, `capabilities`, `pm_min_version?`, `pm_max_version?`, `source_package?`) for self-identifying logs and version gating without re-reading the manifest.
|
|
@@ -302,6 +307,7 @@ Common APIs:
|
|
|
302
307
|
- `api.registerRelationshipKinds(definitions)` adds validated graph semantics. Definitions declare direction, inverse spelling, ordering/precedence, hierarchy, cardinality, lifecycle, aliases, payload schema, compatibility version, and self-edge policy. Active definitions are merged into native CLI, MCP, and SDK workspace graph assembly. Requires the `schema` capability and is governed by the `schema.relationshipkinds` policy surface.
|
|
303
308
|
- `api.registerMigration(definition)` adds schema migrations.
|
|
304
309
|
- `api.registerProfile(profile)` contributes a project profile — a declarative archetype bundling item types, statuses, fields, per-type workflows, config, templates, and package recommendations. Once active it resolves by name through `pm profile list/show/apply` alongside the core `agile`/`ops`/`research` archetypes (built-in names are reserved; a colliding registration is ignored with a warning). Requires the `schema` capability.
|
|
310
|
+
- `api.registerAssuranceMeasurementProvider(provider)` contributes typed measurements to assurance. It requires `services`; network providers also require manifest `permissions.network: true`. Gates allow providers and cost/network limits per trigger. See [Project Assurance Primitives](ASSURANCE.md#extension-measurement-providers) for examples.
|
|
305
311
|
- `api.registerService("output_format", handler)` customizes output formatting through the service override API. Use `handleServiceOverride(result)` to claim a payload and return the scaffold-compatible literal `{ handled: false }` (or `declineServiceOverride()`) for commands the extension does not own. Legacy `null`/`undefined` declines remain supported; returning the original payload is now an unambiguous handled result.
|
|
306
312
|
- `api.registerRenderer("toon" | "json", renderer, ownership?)` adds format-specific renderers. Scope ownership with `commands` and/or a `resultDiscriminator`; the host checks both before invoking the renderer and falls back to native rendering for unrelated output. The legacy unscoped callback remains supported, but doctor warns because package ownership cannot be proven statically.
|
|
307
313
|
- `suppressHostOutput(result?)` from `@unbrained/pm-cli/sdk` marks commands that already wrote output, preventing a second CLI payload while retaining the optional result for hooks, telemetry, and embedded hosts.
|
|
@@ -312,15 +318,8 @@ Common APIs:
|
|
|
312
318
|
- Registered command, importer, and exporter handlers receive `context.sdk`, a host-bound service bundle containing a native-action `PmClient`, `getItemAt`, and `openRelationshipEventStore`, alongside portable workspace coordinates. The client reuses the already-active extension schema context without recursively loading extensions, so package commands and data adapters can compose core lifecycle operations safely in CLI and SDK hosts.
|
|
313
319
|
- An optional module-level `deactivate()` export (VS Code-style) is invoked by the host on shutdown/reload — including by the long-running MCP server between native-action requests — to close connections, clear timers, and release resources opened during `activate`. Teardown is best-effort and timeout-bounded by default so it does not block other extensions, except when a host explicitly disables waiting limits with `deactivate_timeout_ms: 0` or `Infinity`, which can wait indefinitely for a hanging `deactivate()` hook.
|
|
314
320
|
|
|
315
|
-
The bundled `pm-lifecycle-hooks` package is the hook exemplar: it declares only
|
|
316
|
-
`
|
|
317
|
-
safe lifecycle pattern without changing command output.
|
|
318
|
-
|
|
319
|
-
If a package calls a `register*` API without declaring the required manifest
|
|
320
|
-
capability, `pm package doctor --project --detail deep --trace` reports
|
|
321
|
-
`extension_capability_missing:<name>:<capability>` and shows the exact capability
|
|
322
|
-
to add before publishing.
|
|
323
|
-
|
|
321
|
+
The bundled `pm-lifecycle-hooks` package is the hook exemplar: it declares only `hooks` and registers a default-inert `afterCommand` hook so authors can copy a safe lifecycle pattern without changing command output.
|
|
322
|
+
If a package calls a `register*` API without declaring the required manifest capability, `pm package doctor --project --detail deep --trace` reports `extension_capability_missing:<name>:<capability>` and shows the exact capability to add before publishing.
|
|
324
323
|
Inline command flags require both `commands` and `schema` capabilities. Runtime schema changes should be verified with:
|
|
325
324
|
|
|
326
325
|
```bash
|