@unbrained/pm-cli 2026.8.15 → 2026.8.17
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 +56 -12
- package/README.md +13 -13
- package/dist/cli/error-guidance.d.ts +5 -0
- package/dist/cli/error-guidance.js +15 -2
- package/dist/cli/public.d.ts +2 -0
- package/dist/cli/public.js +21 -0
- package/dist/cli/register-history-author.js +16 -11
- package/dist/cli/register-mutation.js +4 -4
- package/dist/cli-bundle/bundle-manifest.json +143 -143
- package/dist/cli-bundle/chunks/{chunk-J42EGKDK.js → chunk-2QLOXC3V.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-LJHOAVGI.js → chunk-3UEGXBMR.js} +49 -43
- package/dist/cli-bundle/chunks/chunk-4JPYF536.js +35 -0
- package/dist/cli-bundle/chunks/chunk-6VDLG2FC.js +13 -0
- package/dist/cli-bundle/chunks/chunk-7IBRGCHX.js +2 -0
- package/dist/cli-bundle/chunks/chunk-HBJAS566.js +8 -0
- package/dist/cli-bundle/chunks/chunk-ION3E43Q.js +197 -0
- package/dist/cli-bundle/chunks/{chunk-WLPDLNEZ.js → chunk-JOKATURE.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-MEM2ZS3O.js → chunk-TPXZIBIV.js} +5 -5
- package/dist/cli-bundle/chunks/chunk-YM2YAMF7.js +2 -0
- package/dist/cli-bundle/chunks/{register-list-query-CT3LFDDN.js → register-list-query-Q7KII4G5.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-NWEVA5YS.js → register-mutation-4WBRPXLV.js} +3 -3
- package/dist/cli-bundle/chunks/{register-operations-AHIAG5KM.js → register-operations-SSENDH5B.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-ZJZFVAKE.js → register-setup-DOSFBGKE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-WTSER4WJ.js → chunk-267MUUS6.js} +11 -11
- package/dist/cli-bundle/focused-chunks/chunk-2NNFLLNG.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-2QSAKMIH.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-ZMFXQ7VF.js → chunk-ATEY76SX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-BUCG4ZI2.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-M67F5AIN.js → chunk-CYFK5UPB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-EHXIKD6K.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-EXZA4257.js → chunk-KGEXTMPG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-KP2VQQVQ.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-MHPIL773.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-POEEAD2V.js +4 -0
- package/dist/cli-bundle/focused-chunks/{chunk-ITAUHSO6.js → chunk-SALH6B6K.js} +47 -47
- package/dist/cli-bundle/focused-chunks/{chunk-KLVUMNXJ.js → chunk-SYZENPIT.js} +3 -3
- package/dist/cli-bundle/focused-chunks/{chunk-KTKH4IMG.js → chunk-XKAMP5OU.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-NSPYTG6G.js → chunk-XPIC53VA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-6XKF3PGV.js → chunk-ZQPGZZWQ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZT2DJS27.js +155 -0
- package/dist/cli-bundle/main.js +10 -10
- 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 +31 -31
- 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 +4 -2
- package/dist/core/extensions/loader.js +10 -6
- package/dist/core/extensions/manifest-schema.d.ts +20 -0
- package/dist/core/extensions/manifest-schema.js +52 -0
- package/dist/core/history/replay.js +32 -14
- package/dist/core/history/workspace-history.js +32 -10
- package/dist/core/output/output.js +6 -3
- package/dist/core/schema/fields-file.d.ts +1 -1
- package/dist/core/schema/fields-file.js +2 -2
- package/dist/core/schema/runtime-field-values.js +115 -9
- package/dist/core/schema/runtime-schema.d.ts +3 -1
- package/dist/core/schema/runtime-schema.js +124 -3
- package/dist/core/shared/errors.d.ts +12 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/shared/time.d.ts +2 -0
- package/dist/core/shared/time.js +27 -2
- package/dist/core/store/item-store.js +28 -2
- package/dist/sdk/agent/refusal-reachability.d.ts +56 -8
- package/dist/sdk/agent/refusal-reachability.js +414 -4
- package/dist/sdk/author-attribution.d.ts +56 -11
- package/dist/sdk/author-attribution.js +174 -50
- package/dist/sdk/cli-contracts/flag-contracts.js +5 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +12 -4
- package/dist/sdk/cli-contracts/tool-schema.js +12 -4
- package/dist/sdk/completion.js +11 -4
- package/dist/sdk/compose.d.ts +6 -2
- package/dist/sdk/compose.js +33 -3
- package/dist/sdk/context-intent-contracts.d.ts +8 -4
- package/dist/sdk/context-intent-contracts.js +76 -31
- package/dist/sdk/dependency-flag-validation.d.ts +9 -2
- package/dist/sdk/dependency-flag-validation.js +101 -35
- package/dist/sdk/environment/host-environment-errors.js +25 -7
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +62 -14
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -2
- package/dist/sdk/governance/assurance-action.d.ts +3 -7
- package/dist/sdk/governance/assurance-action.js +97 -2
- package/dist/sdk/governance/boundary-fixtures.d.ts +86 -0
- package/dist/sdk/governance/boundary-fixtures.js +201 -0
- package/dist/sdk/governance/coverage-assurance.d.ts +24 -0
- package/dist/sdk/governance/coverage-assurance.js +61 -0
- package/dist/sdk/governance/defect-recurrence-signals.d.ts +10 -0
- package/dist/sdk/governance/defect-recurrence-signals.js +25 -0
- package/dist/sdk/governance/defect-recurrence.d.ts +242 -0
- package/dist/sdk/governance/defect-recurrence.js +523 -0
- package/dist/sdk/governance/extension-host-version.js +20 -9
- package/dist/sdk/governance.d.ts +2 -0
- package/dist/sdk/governance.js +4 -2
- package/dist/sdk/graph/governance.js +3 -2
- package/dist/sdk/guide-topics.js +191 -2
- package/dist/sdk/index.d.ts +5 -1
- package/dist/sdk/index.js +6 -3
- package/dist/sdk/lifecycle/create.js +4 -2
- package/dist/sdk/lifecycle/update-many.js +15 -2
- package/dist/sdk/lifecycle/update.js +5 -2
- package/dist/sdk/linked-artifacts.js +63 -14
- package/dist/sdk/query/get.d.ts +2 -0
- package/dist/sdk/query/get.js +32 -7
- package/dist/sdk/read-output-contracts.js +5 -3
- package/dist/sdk/relationship-analytics.js +90 -14
- package/dist/sdk/relationship-kinds/contract.d.ts +4 -0
- package/dist/sdk/relationship-kinds/contract.js +3 -2
- package/dist/sdk/relationships.d.ts +1 -1
- package/dist/sdk/relationships.js +11 -2
- package/dist/sdk/runtime.d.ts +2 -5
- package/dist/sdk/runtime.js +3 -2
- package/dist/sdk/schema.d.ts +1 -0
- package/dist/sdk/schema.js +2 -2
- package/dist/sdk/test/execution.d.ts +6 -2
- package/dist/sdk/test/execution.js +39 -13
- package/dist/types.d.ts +29 -2
- package/dist/types.js +4 -2
- package/docs/CONFIGURATION.md +58 -1
- package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +58 -0
- package/docs/DEFECT_RECURRENCE.md +134 -0
- package/docs/DEPENDENCY_KIND_CONTRACT.md +12 -2
- package/docs/README.md +2 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +7 -1
- package/docs/RELATIONSHIP_GRAPH.md +16 -2
- package/docs/RELEASING.md +13 -7
- package/docs/SDK.md +38 -5
- package/docs/SDK_CONTEXT_INTEGRITY.md +33 -5
- package/docs/SDK_CONTEXT_TRUTH_CONTRACTS.md +13 -5
- package/docs/SDK_RUNTIME_BOUNDARIES.md +9 -1
- package/docs/TESTING.md +18 -1
- package/docs/TRUSTWORTHY_CONTEXT_EVIDENCE.md +1 -1
- package/marketplace.json +2 -2
- package/package.json +6 -4
- 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-claude/skills/pm-audit/SKILL.md +26 -0
- package/plugins/pm-claude/skills/pm-developer/SKILL.md +26 -0
- package/plugins/pm-claude/skills/pm-planner/SKILL.md +26 -0
- package/plugins/pm-claude/skills/pm-release/SKILL.md +26 -0
- package/plugins/pm-claude/skills/pm-workflow/SKILL.md +26 -0
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/skills/pm-auditor/SKILL.md +26 -0
- package/plugins/pm-codex/skills/pm-native/SKILL.md +26 -0
- package/plugins/pm-codex/skills/pm-release/SKILL.md +26 -0
- package/sdk/public-surface.json +716 -33
- package/dist/cli-bundle/chunks/chunk-24GAV7XL.js +0 -8
- package/dist/cli-bundle/chunks/chunk-AIM6VT2N.js +0 -13
- package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +0 -197
- package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +0 -2
- package/dist/cli-bundle/chunks/chunk-KLKYLSDX.js +0 -2
- package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +0 -35
- package/dist/cli-bundle/focused-chunks/chunk-4X57RE4U.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-KT5XMYSX.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-OKA6ELTL.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PUISBOPP.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QLNMCESQ.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-SLKC6QLJ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +0 -2
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements extension runtime contracts and governance for Loader.
|
|
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]="c88047fc-2bbd-5781-96a8-01685c06fb33")}catch(e){}}();
|
|
8
8
|
import fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { pathToFileURL } from "node:url";
|
|
@@ -28,6 +28,7 @@ import { normalizeExtensionPolicy, serializeExtensionPolicy, hydrateExtensionPol
|
|
|
28
28
|
import { createEmptyExtensionHookRegistry, createEmptyExtensionCommandRegistry, createEmptyExtensionParserRegistry, createEmptyExtensionPreflightRegistry, createEmptyExtensionServiceRegistry, createEmptyExtensionRendererRegistry, createEmptyExtensionRegistrationRegistry, } from "./extension-registries.js";
|
|
29
29
|
import { normalizeCommandName, cloneContextSnapshot, } from "./extension-runtime-helpers.js";
|
|
30
30
|
import { normalizeExtensionContributionInventory } from "./contribution-inventory.js";
|
|
31
|
+
import { formatExtensionManifestSchemaWarnings } from "./manifest-schema.js";
|
|
31
32
|
import { attachRuntimeDefinition, assertHookHandler, assertNonEmptyRegistrationString, assertRegistrationFunction, cloneRuntimeRegistrationValue, createRegistrationValidationError, extractRegistrationValidationTrace, isExtensionServiceName, isOutputRendererFormat, normalizeRegistrationRecord, normalizeRegistrationRecordList, normalizeRuntimeRegistrationRecord, normalizeRegistrationName, sanitizeRegistrationValue, toRegistrationCommandPath, validateAssuranceMeasurementProviderDefinition, } from "./registration-values.js";
|
|
32
33
|
import { buildReadyExtensionCandidate, } from "./extension-candidate.js";
|
|
33
34
|
export { parseUnknownExtensionCapabilityWarning, parseLegacyExtensionCapabilityAliasWarning, } from "./extension-capability-aliases.js";
|
|
@@ -513,8 +514,8 @@ function buildUnavailableExtensionScan(layer, directory, manifestPath, warning)
|
|
|
513
514
|
};
|
|
514
515
|
}
|
|
515
516
|
/** Collect the non-fatal load warnings for a parsed extension manifest, in detection order: legacy capability aliases, unknown capabilities, an entry outside or absent from the extension directory, then the pm version floor/ceiling incompatibility warnings. */
|
|
516
|
-
function collectScannedExtensionWarnings(layer, manifest, entryWithinDirectory, entryExists, pmVersionCompatibility, pmMaxVersionCompatibility) {
|
|
517
|
-
const extensionWarnings =
|
|
517
|
+
function collectScannedExtensionWarnings(layer, manifest, rawManifest, entryWithinDirectory, entryExists, pmVersionCompatibility, pmMaxVersionCompatibility) {
|
|
518
|
+
const extensionWarnings = formatExtensionManifestSchemaWarnings(layer, manifest, rawManifest);
|
|
518
519
|
if (Array.isArray(manifest.legacy_capability_aliases) &&
|
|
519
520
|
manifest.legacy_capability_aliases.length > 0) {
|
|
520
521
|
extensionWarnings.push(formatLegacyExtensionCapabilityAliasWarning(layer, manifest.name, manifest.legacy_capability_aliases));
|
|
@@ -543,14 +544,17 @@ async function scanExtensionDirectory(layer, extensionsRoot, directory, enabled,
|
|
|
543
544
|
return buildUnavailableExtensionScan(layer, directory, manifestPath, `extension_manifest_missing:${layer}:${directory}`);
|
|
544
545
|
}
|
|
545
546
|
let manifest;
|
|
547
|
+
let rawManifest;
|
|
546
548
|
try {
|
|
547
549
|
const parsed = JSON.parse(await fs.readFile(manifestPath, "utf8"));
|
|
550
|
+
rawManifest = asRecordLoose(parsed);
|
|
548
551
|
manifest = parseExtensionManifestDocument(parsed);
|
|
549
552
|
}
|
|
550
553
|
catch {
|
|
554
|
+
rawManifest = null;
|
|
551
555
|
manifest = null;
|
|
552
556
|
}
|
|
553
|
-
if (!manifest) {
|
|
557
|
+
if (!manifest || !rawManifest) {
|
|
554
558
|
return buildUnavailableExtensionScan(layer, directory, manifestPath, `extension_manifest_invalid:${layer}:${directory}`);
|
|
555
559
|
}
|
|
556
560
|
const entryPath = path.resolve(extensionDir, manifest.entry);
|
|
@@ -564,7 +568,7 @@ async function scanExtensionDirectory(layer, extensionsRoot, directory, enabled,
|
|
|
564
568
|
const enabledForLoad = shouldEnable(manifest.name, enabled, disabled);
|
|
565
569
|
const pmVersionCompatibility = await evaluatePmMinVersionCompatibility(layer, manifest);
|
|
566
570
|
const pmMaxVersionCompatibility = await evaluatePmMaxVersionCompatibility(layer, manifest, pmMaxVersionExceededMode);
|
|
567
|
-
const extensionWarnings = collectScannedExtensionWarnings(layer, manifest, entryWithinDirectory, entryExists, pmVersionCompatibility, pmMaxVersionCompatibility);
|
|
571
|
+
const extensionWarnings = collectScannedExtensionWarnings(layer, manifest, rawManifest, entryWithinDirectory, entryExists, pmVersionCompatibility, pmMaxVersionCompatibility);
|
|
568
572
|
const extensionReady = entryWithinDirectory &&
|
|
569
573
|
entryExists &&
|
|
570
574
|
pmVersionCompatibility.allowed &&
|
|
@@ -2221,4 +2225,4 @@ export const _testOnlyLoader = {
|
|
|
2221
2225
|
},
|
|
2222
2226
|
};
|
|
2223
2227
|
//# sourceMappingURL=loader.js.map
|
|
2224
|
-
//# debugId=
|
|
2228
|
+
//# debugId=c88047fc-2bbd-5781-96a8-01685c06fb33
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/extensions/manifest-schema
|
|
3
|
+
*
|
|
4
|
+
* Defines the closed extension-manifest key vocabulary and returns pure schema
|
|
5
|
+
* diagnostics shared by SDK authoring checks and runtime discovery.
|
|
6
|
+
*/
|
|
7
|
+
import type { ExtensionLayer, ExtensionManifest } from "./extension-types.js";
|
|
8
|
+
/** Canonical top-level keys accepted by an extension `manifest.json`. */
|
|
9
|
+
export declare const KNOWN_EXTENSION_MANIFEST_KEYS: Set<string>;
|
|
10
|
+
/** Pure closed-schema inspection result for one raw extension manifest. */
|
|
11
|
+
export interface ExtensionManifestSchemaInspection {
|
|
12
|
+
/** Unknown top-level keys in deterministic lexical order. */
|
|
13
|
+
unknownKeys: string[];
|
|
14
|
+
/** Whether neither canonical pm compatibility bound is present. */
|
|
15
|
+
missingVersionBounds: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Inspect raw manifest keys without parsing, loading, or mutating an extension. */
|
|
18
|
+
export declare function inspectExtensionManifestSchema(manifest: Readonly<Record<string, unknown>>): ExtensionManifestSchemaInspection;
|
|
19
|
+
/** Format runtime discovery warnings for unknown keys and absent canonical compatibility bounds. */
|
|
20
|
+
export declare function formatExtensionManifestSchemaWarnings(layer: ExtensionLayer, manifest: ExtensionManifest, rawManifest: Readonly<Record<string, unknown>>): string[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/extensions/manifest-schema
|
|
3
|
+
*
|
|
4
|
+
* Defines the closed extension-manifest key vocabulary and returns pure schema
|
|
5
|
+
* diagnostics shared by SDK authoring checks and runtime discovery.
|
|
6
|
+
*/
|
|
7
|
+
/** Canonical top-level keys accepted by an extension `manifest.json`. */
|
|
8
|
+
|
|
9
|
+
!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]="7d9d8924-3186-5aab-ac36-164fb08624a8")}catch(e){}}();
|
|
10
|
+
export const KNOWN_EXTENSION_MANIFEST_KEYS = new Set([
|
|
11
|
+
"name",
|
|
12
|
+
"version",
|
|
13
|
+
"entry",
|
|
14
|
+
"priority",
|
|
15
|
+
"description",
|
|
16
|
+
"author",
|
|
17
|
+
"capabilities",
|
|
18
|
+
"manifest_version",
|
|
19
|
+
"pm_min_version",
|
|
20
|
+
"pm_max_version",
|
|
21
|
+
"engines",
|
|
22
|
+
"trusted",
|
|
23
|
+
"provenance",
|
|
24
|
+
"sandbox_profile",
|
|
25
|
+
"permissions",
|
|
26
|
+
"activation",
|
|
27
|
+
"contributions",
|
|
28
|
+
"legacy_capability_aliases",
|
|
29
|
+
]);
|
|
30
|
+
/** Inspect raw manifest keys without parsing, loading, or mutating an extension. */
|
|
31
|
+
export function inspectExtensionManifestSchema(manifest) {
|
|
32
|
+
return {
|
|
33
|
+
unknownKeys: Object.keys(manifest)
|
|
34
|
+
.filter((key) => !KNOWN_EXTENSION_MANIFEST_KEYS.has(key))
|
|
35
|
+
.sort((left, right) => (left > right ? 1 : -1)),
|
|
36
|
+
missingVersionBounds: manifest.pm_min_version === undefined &&
|
|
37
|
+
manifest.pm_max_version === undefined,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Format runtime discovery warnings for unknown keys and absent canonical compatibility bounds. */
|
|
41
|
+
export function formatExtensionManifestSchemaWarnings(layer, manifest, rawManifest) {
|
|
42
|
+
const inspection = inspectExtensionManifestSchema(rawManifest);
|
|
43
|
+
const warnings = inspection.unknownKeys.map((key) => key === "compatibility"
|
|
44
|
+
? `extension_manifest_unknown_key:${layer}:${manifest.name}:key=compatibility:suggested=pm_min_version`
|
|
45
|
+
: `extension_manifest_unknown_key:${layer}:${manifest.name}:key=${key}`);
|
|
46
|
+
if (inspection.missingVersionBounds) {
|
|
47
|
+
warnings.push(`extension_manifest_no_version_bounds:${layer}:${manifest.name}:suggested=pm_min_version`);
|
|
48
|
+
}
|
|
49
|
+
return warnings;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=manifest-schema.js.map
|
|
52
|
+
//# debugId=7d9d8924-3186-5aab-ac36-164fb08624a8
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements append-only history and replay behavior for Replay.
|
|
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]="bf8797ec-53d3-5d23-8a6e-8296a027ddf2")}catch(e){}}();
|
|
8
8
|
import jsonPatch from "fast-json-patch";
|
|
9
9
|
import { ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
|
|
10
10
|
import { canonicalDocument } from "../item/item-format.js";
|
|
@@ -123,11 +123,30 @@ export function tryApplyReplayPatch(current, patch) {
|
|
|
123
123
|
return { ok: false, error };
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
+
/** Return the distinct supported hash epochs explicitly declared by a stream. */
|
|
127
|
+
function supportedExplicitHistoryItemHashVersions(entries) {
|
|
128
|
+
return [
|
|
129
|
+
...new Set(entries
|
|
130
|
+
.map((entry) => entry.item_hash_version)
|
|
131
|
+
.filter((version) => version !== undefined &&
|
|
132
|
+
SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(version))),
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
/** Select the hash epochs allowed for one entry under an authoritative stream marker. */
|
|
136
|
+
function historyEntryHashCandidates(explicitVersion, authoritativeVersion) {
|
|
137
|
+
if (explicitVersion !== undefined) {
|
|
138
|
+
return [explicitVersion];
|
|
139
|
+
}
|
|
140
|
+
return authoritativeVersion === undefined
|
|
141
|
+
? [1, CURRENT_HISTORY_ITEM_HASH_VERSION]
|
|
142
|
+
: [authoritativeVersion];
|
|
143
|
+
}
|
|
126
144
|
/** Deterministically verify a history chain: each entry's before_hash must equal the prior replayed after_hash, the patch must strictly apply, and the recorded after_hash must equal the replayed result. */
|
|
127
145
|
/** Verify a chain and report the explicit or auto-detected item hash epoch. */
|
|
128
146
|
export function verifyHistoryChainWithVersion(entries) {
|
|
129
147
|
let replay = cloneEmptyReplayDocument();
|
|
130
148
|
let detectedVersion;
|
|
149
|
+
let authoritativeExplicitVersion;
|
|
131
150
|
for (let index = 0; index < entries.length; index += 1) {
|
|
132
151
|
const entry = entries[index];
|
|
133
152
|
const explicitVersion = entry.item_hash_version;
|
|
@@ -147,9 +166,10 @@ export function verifyHistoryChainWithVersion(entries) {
|
|
|
147
166
|
errors: [`verify_failed:patch_apply_failed:entry_${index + 1}`],
|
|
148
167
|
};
|
|
149
168
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
169
|
+
// Prefer legacy epoch 1 when an unversioned entry is valid under both
|
|
170
|
+
// algorithms, but retain compatibility with transitional epoch-2 writers
|
|
171
|
+
// that shipped before item_hash_version became explicit.
|
|
172
|
+
const candidates = historyEntryHashCandidates(explicitVersion, authoritativeExplicitVersion);
|
|
153
173
|
const beforeMatches = candidates.filter((version) => replayHash(replay, version) === entry.before_hash);
|
|
154
174
|
if (beforeMatches.length === 0) {
|
|
155
175
|
return {
|
|
@@ -166,6 +186,9 @@ export function verifyHistoryChainWithVersion(entries) {
|
|
|
166
186
|
}
|
|
167
187
|
replay = applied.document;
|
|
168
188
|
detectedVersion = version;
|
|
189
|
+
if (explicitVersion !== undefined) {
|
|
190
|
+
authoritativeExplicitVersion = version;
|
|
191
|
+
}
|
|
169
192
|
}
|
|
170
193
|
return {
|
|
171
194
|
ok: true,
|
|
@@ -228,19 +251,14 @@ export function lenientApplyReplayPatch(current, patch) {
|
|
|
228
251
|
* irreconcilably mixed stream falls forward to the current epoch.
|
|
229
252
|
*/
|
|
230
253
|
export function resolveHistoryRepairItemHashVersion(entries) {
|
|
254
|
+
const explicitVersions = supportedExplicitHistoryItemHashVersions(entries);
|
|
255
|
+
if (explicitVersions.length === 1) {
|
|
256
|
+
return explicitVersions[0];
|
|
257
|
+
}
|
|
231
258
|
const verified = verifyHistoryChainWithVersion(entries);
|
|
232
259
|
if (verified.ok && verified.item_hash_version !== undefined) {
|
|
233
260
|
return verified.item_hash_version;
|
|
234
261
|
}
|
|
235
|
-
const explicitVersions = [
|
|
236
|
-
...new Set(entries
|
|
237
|
-
.map((entry) => entry.item_hash_version)
|
|
238
|
-
.filter((version) => version !== undefined &&
|
|
239
|
-
SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(version))),
|
|
240
|
-
];
|
|
241
|
-
if (explicitVersions.length === 1) {
|
|
242
|
-
return explicitVersions[0];
|
|
243
|
-
}
|
|
244
262
|
if (explicitVersions.length === 0) {
|
|
245
263
|
return 1;
|
|
246
264
|
}
|
|
@@ -333,4 +351,4 @@ export function historyEntriesToRaw(entries) {
|
|
|
333
351
|
return `${entries.map((entry) => JSON.stringify(entry)).join("\n")}\n`;
|
|
334
352
|
}
|
|
335
353
|
//# sourceMappingURL=replay.js.map
|
|
336
|
-
//# debugId=
|
|
354
|
+
//# debugId=bf8797ec-53d3-5d23-8a6e-8296a027ddf2
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* HistoryEntry format used by item mutations.
|
|
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]="9027d972-ce29-5511-ba81-27e17d97446e")}catch(e){}}();
|
|
9
9
|
import fs from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { readFileIfExists, writeFileAtomic } from "../fs/fs-utils.js";
|
|
@@ -54,6 +54,28 @@ function workspaceDocuments(document) {
|
|
|
54
54
|
? document.metadata.documents
|
|
55
55
|
: {};
|
|
56
56
|
}
|
|
57
|
+
/** Refuse a workspace mutation or replay whose append-only chain is invalid. */
|
|
58
|
+
function throwWorkspaceHistoryVerificationFailure(errors) {
|
|
59
|
+
throw new PmCliError(`Workspace history verification failed: ${errors.join(", ")}`, EXIT_CODE.CONFLICT, {
|
|
60
|
+
code: "workspace_history_chain_invalid",
|
|
61
|
+
reason: "workspace_history_chain_verification_failed",
|
|
62
|
+
verification_errors: [...errors],
|
|
63
|
+
required: "Repair the _workspace history chain before reading, reconciling, restoring, or appending audited singleton state.",
|
|
64
|
+
why: "Continuing against an unverifiable append-only stream could hide or compound workspace state corruption.",
|
|
65
|
+
examples: [
|
|
66
|
+
"pm history _workspace --verify --json",
|
|
67
|
+
"pm validate --check-history-drift --fix-hints --json",
|
|
68
|
+
],
|
|
69
|
+
nextSteps: [
|
|
70
|
+
"Inspect the exact verification_errors and preserve the corrupt stream as evidence.",
|
|
71
|
+
"Use the history-drift remediation returned by validate before retrying the refused operation.",
|
|
72
|
+
],
|
|
73
|
+
recovery: {
|
|
74
|
+
recovery_mode: "compact",
|
|
75
|
+
next_best_command: "pm history _workspace --verify --json",
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
57
79
|
/** Resolve a governed singleton path and reject paths outside the tracker root. */
|
|
58
80
|
function resolveGovernedDocumentPath(pmRoot, filePath) {
|
|
59
81
|
const absolutePath = path.resolve(filePath);
|
|
@@ -76,7 +98,7 @@ export async function inspectWorkspaceHistoryState(pmRoot) {
|
|
|
76
98
|
const entries = await readHistoryEntries(getWorkspaceHistoryPath(pmRoot), WORKSPACE_HISTORY_ID);
|
|
77
99
|
const verification = verifyHistoryChain(entries);
|
|
78
100
|
if (!verification.ok) {
|
|
79
|
-
|
|
101
|
+
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
80
102
|
}
|
|
81
103
|
const documents = workspaceDocuments(entries.length === 0
|
|
82
104
|
? EMPTY_CANONICAL_DOCUMENT
|
|
@@ -123,7 +145,7 @@ async function appendWorkspaceHistoryChangeLocked(change) {
|
|
|
123
145
|
const entries = await readHistoryEntries(historyPath, WORKSPACE_HISTORY_ID);
|
|
124
146
|
const verification = verifyHistoryChain(entries);
|
|
125
147
|
if (!verification.ok) {
|
|
126
|
-
|
|
148
|
+
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
127
149
|
}
|
|
128
150
|
const idempotentEntry = change.idempotencyKey === undefined
|
|
129
151
|
? undefined
|
|
@@ -194,7 +216,7 @@ export async function appendWorkspaceAuditEvent(options) {
|
|
|
194
216
|
const entries = await readHistoryEntries(historyPath, WORKSPACE_HISTORY_ID);
|
|
195
217
|
const verification = verifyHistoryChain(entries);
|
|
196
218
|
if (!verification.ok) {
|
|
197
|
-
|
|
219
|
+
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
198
220
|
}
|
|
199
221
|
const beforeDocument = entries.length === 0
|
|
200
222
|
? EMPTY_CANONICAL_DOCUMENT
|
|
@@ -303,7 +325,7 @@ export async function reconcileWorkspaceJsonHistory(options) {
|
|
|
303
325
|
const entries = await readHistoryEntries(historyPath, WORKSPACE_HISTORY_ID);
|
|
304
326
|
const verification = verifyHistoryChain(entries);
|
|
305
327
|
if (!verification.ok) {
|
|
306
|
-
|
|
328
|
+
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
307
329
|
}
|
|
308
330
|
const beforeDocument = replayWorkspaceEntries(entries);
|
|
309
331
|
const priorDocuments = workspaceDocuments(beforeDocument);
|
|
@@ -349,15 +371,15 @@ export async function restoreWorkspaceJsonFromHistory(options) {
|
|
|
349
371
|
try {
|
|
350
372
|
const { documentPath, absolutePath } = resolveGovernedDocumentPath(options.pmRoot, options.filePath);
|
|
351
373
|
const entries = await readHistoryEntries(getWorkspaceHistoryPath(options.pmRoot), WORKSPACE_HISTORY_ID);
|
|
374
|
+
const verification = verifyHistoryChain(entries);
|
|
375
|
+
if (!verification.ok) {
|
|
376
|
+
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
377
|
+
}
|
|
352
378
|
if (!Number.isInteger(options.targetVersion) ||
|
|
353
379
|
options.targetVersion < 1 ||
|
|
354
380
|
options.targetVersion > entries.length) {
|
|
355
381
|
throw new TypeError(`Invalid workspace history target version: ${String(options.targetVersion)}`);
|
|
356
382
|
}
|
|
357
|
-
const verification = verifyHistoryChain(entries);
|
|
358
|
-
if (!verification.ok) {
|
|
359
|
-
throw new TypeError(`Workspace history verification failed: ${verification.errors.join(", ")}`);
|
|
360
|
-
}
|
|
361
383
|
const target = workspaceDocuments(replayWorkspaceEntries(entries, options.targetVersion))[documentPath];
|
|
362
384
|
if (target === undefined) {
|
|
363
385
|
throw new TypeError(`Workspace history version ${options.targetVersion} does not contain ${documentPath}`);
|
|
@@ -408,4 +430,4 @@ export async function restoreWorkspaceJsonFromHistory(options) {
|
|
|
408
430
|
}
|
|
409
431
|
}
|
|
410
432
|
//# sourceMappingURL=workspace-history.js.map
|
|
411
|
-
//# debugId=
|
|
433
|
+
//# debugId=9027d972-ce29-5511-ba81-27e17d97446e
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
* Formats compact human and machine output for Output.
|
|
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]="202cbb3e-71fe-5701-a1f5-eb515bf56561")}catch(e){}}();
|
|
8
8
|
import { getActiveCommandContext, runActiveCommandOverride, runActiveRendererOverride, runActiveServiceOverrideSync, setActiveCommandResult, } from "../extensions/index.js";
|
|
9
9
|
import { EXIT_CODE } from "../shared/constants.js";
|
|
10
10
|
import { isHostOutputSuppressed } from "./output-control.js";
|
|
11
11
|
import { projectMutationResult } from "./mutation-projection.js";
|
|
12
12
|
import { attachReadOutputContracts } from "../../sdk/context-intent-contracts.js";
|
|
13
13
|
import { attachOutputTokenAccounting } from "../../sdk/output-token-accounting.js";
|
|
14
|
-
import { resolveReadOutputEncoding } from "../../sdk/read-output-contracts.js";
|
|
14
|
+
import { isReadOutputBudgetExceeded, resolveReadOutputEncoding, } from "../../sdk/read-output-contracts.js";
|
|
15
15
|
import { encode as encodeToon } from "@toon-format/toon";
|
|
16
16
|
const DECLARED_PROCESS_EXIT_CODES = new Set(Object.values(EXIT_CODE));
|
|
17
17
|
const NATIVE_OUTPUT_MARKER = "__pm_native_output";
|
|
@@ -389,6 +389,9 @@ function formatEffectiveOutput(effectiveResult, nativeOutput, options) {
|
|
|
389
389
|
? projectLinkedTestEvidence(outputResult, options.lean === true)
|
|
390
390
|
: outputResult;
|
|
391
391
|
const intentOutputResult = attachReadOutputContracts(command, resolvedCommandOptions, projectedOutputResult);
|
|
392
|
+
if (isReadOutputBudgetExceeded(intentOutputResult)) {
|
|
393
|
+
process.exitCode ||= EXIT_CODE.USAGE;
|
|
394
|
+
}
|
|
392
395
|
const renderResolvedOutput = (value) => {
|
|
393
396
|
if (format === "toon") {
|
|
394
397
|
const markdownDefault = renderDefaultMarkdownResult(value);
|
|
@@ -465,4 +468,4 @@ export const outputTestOnly = {
|
|
|
465
468
|
renderToonValue,
|
|
466
469
|
};
|
|
467
470
|
//# sourceMappingURL=output.js.map
|
|
468
|
-
//# debugId=
|
|
471
|
+
//# debugId=202cbb3e-71fe-5701-a1f5-eb515bf56561
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RuntimeFieldCommand, RuntimeFieldDefinition, RuntimeFieldType } from "../../types/index.js";
|
|
2
2
|
export { normalizeStatusToken as normalizeFieldKey } from "./status-token.js";
|
|
3
|
-
export type { RuntimeFieldCommand, RuntimeFieldDefinition, RuntimeFieldType, } from "../../types/index.js";
|
|
3
|
+
export type { RuntimeFieldCommand, RuntimeFieldDefinition, RuntimeFieldValueSchema, RuntimeFieldType, } from "../../types/index.js";
|
|
4
4
|
/** Built-in item-metadata field names a custom field key must never shadow. A custom key that collides with one of these would let `pm create --<key>` write over reserved metadata, so add-field rejects them up front (symmetric with the built-in-type guard in item-types-file.ts). */
|
|
5
5
|
export declare const BUILTIN_FIELD_KEYS: ReadonlySet<string>;
|
|
6
6
|
/** The shape persisted at `.agents/pm/schema/fields.json`. */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Resolves configurable schema, fields, statuses, and workflows for Fields File.
|
|
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]="2b5a573e-1e36-58b9-b93b-4a4088f71e9a")}catch(e){}}();
|
|
8
8
|
import { RUNTIME_FIELD_COMMAND_VALUES, RUNTIME_FIELD_TYPE_VALUES, } from "../../types/index.js";
|
|
9
9
|
import { ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
|
|
10
10
|
import { normalizeStatusToken as normalizeFieldKey } from "./status-token.js";
|
|
@@ -286,4 +286,4 @@ function applyBooleanFlag(definition, key, value) {
|
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
//# sourceMappingURL=fields-file.js.map
|
|
289
|
-
//# debugId=
|
|
289
|
+
//# debugId=2b5a573e-1e36-58b9-b93b-4a4088f71e9a
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
* Resolves configurable schema, fields, statuses, and workflows for Runtime Field Values.
|
|
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]="91a3969e-59b3-506e-9349-ca08e73a1228")}catch(e){}}();
|
|
8
8
|
import { EXIT_CODE } from "../shared/constants.js";
|
|
9
9
|
import { PmCliError } from "../shared/errors.js";
|
|
10
|
+
import { stableStringify } from "../shared/serialization.js";
|
|
11
|
+
import { isRfc3339DateTime } from "../shared/time.js";
|
|
10
12
|
import { runtimeFieldOptionTarget, } from "./runtime-schema.js";
|
|
13
|
+
const MAX_VALUE_SCHEMA_DEPTH = 16;
|
|
11
14
|
function toCamelToken(value) {
|
|
12
15
|
const segments = value
|
|
13
16
|
.trim()
|
|
@@ -116,6 +119,109 @@ function parseJsonContainerValue(raw, label, expectedType) {
|
|
|
116
119
|
}
|
|
117
120
|
throw new PmCliError(`${label} must be valid JSON ${expectedType}`, EXIT_CODE.USAGE);
|
|
118
121
|
}
|
|
122
|
+
function valueMatchesSchemaType(value, type) {
|
|
123
|
+
if (type === undefined)
|
|
124
|
+
return true;
|
|
125
|
+
if (type === "array")
|
|
126
|
+
return Array.isArray(value);
|
|
127
|
+
if (type === "object") {
|
|
128
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
129
|
+
}
|
|
130
|
+
return typeof value === type;
|
|
131
|
+
}
|
|
132
|
+
function runtimeFieldPrimitiveSchemaError(value, schema, path) {
|
|
133
|
+
if (schema.const !== undefined &&
|
|
134
|
+
stableStringify(value) !== stableStringify(schema.const)) {
|
|
135
|
+
return `${path} must equal ${stableStringify(schema.const)}`;
|
|
136
|
+
}
|
|
137
|
+
if (schema.enum !== undefined &&
|
|
138
|
+
!schema.enum.some((candidate) => stableStringify(candidate) === stableStringify(value))) {
|
|
139
|
+
return `${path} must be one of ${schema.enum.map((entry) => stableStringify(entry)).join("|")}`;
|
|
140
|
+
}
|
|
141
|
+
if (!valueMatchesSchemaType(value, schema.type)) {
|
|
142
|
+
return `${path} must match configured type ${String(schema.type)}`;
|
|
143
|
+
}
|
|
144
|
+
if (typeof value === "string") {
|
|
145
|
+
if (schema.min_length !== undefined && value.length < schema.min_length) {
|
|
146
|
+
return `${path} must contain at least ${schema.min_length} characters`;
|
|
147
|
+
}
|
|
148
|
+
if (schema.format === "date-time" && !isRfc3339DateTime(value)) {
|
|
149
|
+
return `${path} must be an RFC 3339 date-time`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
function runtimeFieldArraySchemaError(value, schema, path, depth) {
|
|
155
|
+
if (!Array.isArray(value))
|
|
156
|
+
return undefined;
|
|
157
|
+
if (schema.min_items !== undefined && value.length < schema.min_items) {
|
|
158
|
+
return `${path} must contain at least ${schema.min_items} items`;
|
|
159
|
+
}
|
|
160
|
+
if (!schema.items)
|
|
161
|
+
return undefined;
|
|
162
|
+
for (const [index, entry] of value.entries()) {
|
|
163
|
+
const error = runtimeFieldSchemaError(entry, schema.items, `${path}[${index}]`, depth + 1);
|
|
164
|
+
if (error)
|
|
165
|
+
return error;
|
|
166
|
+
}
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
function runtimeFieldObjectSchemaError(value, schema, path, depth) {
|
|
170
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
171
|
+
return undefined;
|
|
172
|
+
const record = value;
|
|
173
|
+
for (const key of schema.required ?? []) {
|
|
174
|
+
if (!Object.hasOwn(record, key))
|
|
175
|
+
return `${path}.${key} is required`;
|
|
176
|
+
}
|
|
177
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
178
|
+
const propertySchema = schema.properties?.[key];
|
|
179
|
+
if (!propertySchema) {
|
|
180
|
+
if (schema.additional_properties === false)
|
|
181
|
+
return `${path}.${key} is not allowed`;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const error = runtimeFieldSchemaError(entry, propertySchema, `${path}.${key}`, depth + 1);
|
|
185
|
+
if (error)
|
|
186
|
+
return error;
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
/** Return the first semantic schema mismatch without mutating the input value. */
|
|
191
|
+
function runtimeFieldSchemaError(value, schema, path, depth = 0) {
|
|
192
|
+
if (depth > MAX_VALUE_SCHEMA_DEPTH)
|
|
193
|
+
return `${path} value schema exceeds maximum depth`;
|
|
194
|
+
const directError = runtimeFieldPrimitiveSchemaError(value, schema, path);
|
|
195
|
+
if (directError)
|
|
196
|
+
return directError;
|
|
197
|
+
const arrayError = runtimeFieldArraySchemaError(value, schema, path, depth);
|
|
198
|
+
if (arrayError)
|
|
199
|
+
return arrayError;
|
|
200
|
+
const objectError = runtimeFieldObjectSchemaError(value, schema, path, depth);
|
|
201
|
+
if (objectError)
|
|
202
|
+
return objectError;
|
|
203
|
+
if (!schema.one_of)
|
|
204
|
+
return undefined;
|
|
205
|
+
let matches = 0;
|
|
206
|
+
for (const candidate of schema.one_of) {
|
|
207
|
+
if (runtimeFieldSchemaError(value, candidate, path, depth + 1) === undefined) {
|
|
208
|
+
matches += 1;
|
|
209
|
+
if (matches > 1)
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return matches === 1
|
|
214
|
+
? undefined
|
|
215
|
+
: `${path} must match exactly one configured schema variant`;
|
|
216
|
+
}
|
|
217
|
+
function validateRuntimeFieldValue(definition, value, label) {
|
|
218
|
+
if (!definition.value_schema || value === undefined)
|
|
219
|
+
return value;
|
|
220
|
+
const error = runtimeFieldSchemaError(value, definition.value_schema, label);
|
|
221
|
+
if (error)
|
|
222
|
+
throw new PmCliError(error, EXIT_CODE.USAGE);
|
|
223
|
+
return value;
|
|
224
|
+
}
|
|
119
225
|
/** Implements coerce runtime field value for the public runtime surface of this module. */
|
|
120
226
|
export function coerceRuntimeFieldValue(definition, rawValue, labelOverride) {
|
|
121
227
|
const label = labelOverride ?? `--${definition.cli_flag}`;
|
|
@@ -126,17 +232,17 @@ export function coerceRuntimeFieldValue(definition, rawValue, labelOverride) {
|
|
|
126
232
|
if (containerRaw === undefined) {
|
|
127
233
|
return undefined;
|
|
128
234
|
}
|
|
129
|
-
return parseJsonContainerValue(containerRaw, label, definition.type);
|
|
235
|
+
return validateRuntimeFieldValue(definition, parseJsonContainerValue(containerRaw, label, definition.type), label);
|
|
130
236
|
}
|
|
131
237
|
if (definition.repeatable || definition.type === "string_array") {
|
|
132
238
|
const values = normalizeStringArrayValue(rawValue);
|
|
133
239
|
if (definition.type === "number") {
|
|
134
|
-
return values.map((value) => parseNumberValue(value, label));
|
|
240
|
+
return validateRuntimeFieldValue(definition, values.map((value) => parseNumberValue(value, label)), label);
|
|
135
241
|
}
|
|
136
242
|
if (definition.type === "boolean") {
|
|
137
|
-
return values.map((value) => parseBooleanValue(value, label));
|
|
243
|
+
return validateRuntimeFieldValue(definition, values.map((value) => parseBooleanValue(value, label)), label);
|
|
138
244
|
}
|
|
139
|
-
return values;
|
|
245
|
+
return validateRuntimeFieldValue(definition, values, label);
|
|
140
246
|
}
|
|
141
247
|
const scalarRaw = Array.isArray(rawValue)
|
|
142
248
|
? rawValue[rawValue.length - 1]
|
|
@@ -145,12 +251,12 @@ export function coerceRuntimeFieldValue(definition, rawValue, labelOverride) {
|
|
|
145
251
|
return undefined;
|
|
146
252
|
}
|
|
147
253
|
if (definition.type === "number") {
|
|
148
|
-
return parseNumberValue(scalarRaw, label);
|
|
254
|
+
return validateRuntimeFieldValue(definition, parseNumberValue(scalarRaw, label), label);
|
|
149
255
|
}
|
|
150
256
|
if (definition.type === "boolean") {
|
|
151
|
-
return parseBooleanValue(scalarRaw, label);
|
|
257
|
+
return validateRuntimeFieldValue(definition, parseBooleanValue(scalarRaw, label), label);
|
|
152
258
|
}
|
|
153
|
-
return typeof scalarRaw === "string" ? scalarRaw : String(scalarRaw);
|
|
259
|
+
return validateRuntimeFieldValue(definition, typeof scalarRaw === "string" ? scalarRaw : String(scalarRaw), label);
|
|
154
260
|
}
|
|
155
261
|
function shouldRequireFieldOnCreate(definition, itemTypeName) {
|
|
156
262
|
if (!definition.required && !definition.required_on_create) {
|
|
@@ -205,4 +311,4 @@ export function collectRuntimeUpdateFieldValues(options, fieldRegistry, commands
|
|
|
205
311
|
return values;
|
|
206
312
|
}
|
|
207
313
|
//# sourceMappingURL=runtime-field-values.js.map
|
|
208
|
-
//# debugId=
|
|
314
|
+
//# debugId=91a3969e-59b3-506e-9349-ca08e73a1228
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ItemTypeDefinition, RuntimeFieldCommand, RuntimeFieldType, RuntimeSchemaSettings, RuntimeStatusDefinition, RuntimeStatusRole, RuntimeWorkflowDefinition } from "../../types/index.js";
|
|
1
|
+
import type { ItemTypeDefinition, RuntimeFieldCommand, RuntimeFieldValueSchema, RuntimeFieldType, RuntimeSchemaSettings, RuntimeStatusDefinition, RuntimeStatusRole, RuntimeWorkflowDefinition } from "../../types/index.js";
|
|
2
2
|
export type { RuntimeFieldCommand } from "../../types/index.js";
|
|
3
3
|
/** Fallback runtime schema file paths used when callers do not provide an override. */
|
|
4
4
|
export declare const DEFAULT_RUNTIME_SCHEMA_FILE_PATHS: Readonly<{
|
|
@@ -50,6 +50,8 @@ export interface RuntimeFieldDefinitionResolved {
|
|
|
50
50
|
required_types: string[];
|
|
51
51
|
/** Value that configures or reports allow unset for this contract. */
|
|
52
52
|
allow_unset: boolean;
|
|
53
|
+
/** Optional semantic JSON-value constraints enforced on create and update. */
|
|
54
|
+
value_schema?: RuntimeFieldValueSchema;
|
|
53
55
|
}
|
|
54
56
|
/** Documents the runtime status registry payload exchanged by command, SDK, and package integrations. */
|
|
55
57
|
export interface RuntimeStatusRegistry {
|