@unbrained/pm-cli 2026.9.18 → 2026.9.19
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 +20 -0
- package/dist/cli/invocation-profile.d.ts +26 -0
- package/dist/cli/invocation-profile.js +3 -0
- package/dist/cli-bundle/bundle-manifest.json +148 -148
- package/dist/cli-bundle/chunks/{chunk-GRFRKHFC.js → chunk-7CN53F4S.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-X2EVS624.js → chunk-AACGU5IA.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-AOD5WE6U.js → chunk-CCLWCESZ.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-WD7BQXA7.js → chunk-J7NP7QLW.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-T4J2X3RK.js → chunk-K4VAU4HU.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-KHN4NMKT.js +238 -0
- package/dist/cli-bundle/chunks/{chunk-CA5DRNGA.js → chunk-KYG2QKNY.js} +28 -28
- package/dist/cli-bundle/chunks/{chunk-WUDF7HWM.js → chunk-OQS2Y6VN.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-XFGWFVR3.js → chunk-QA4GUEKJ.js} +20 -20
- package/dist/cli-bundle/chunks/chunk-QTHR3LXF.js +20 -0
- package/dist/cli-bundle/chunks/{chunk-FZZVWWQP.js → chunk-RVMDPIGD.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-Y2OK7IAD.js → chunk-WASMH647.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-43EQISX7.js → register-list-query-RMZNHSII.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-TSZNAKEU.js → register-mutation-HJGSGX3H.js} +2 -2
- package/dist/cli-bundle/chunks/{register-operations-KFZIKATY.js → register-operations-LBEMFUMM.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-KTJ4ZE65.js → register-setup-MU557JAA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-QVVOXVYI.js → chunk-5SZ4JSPZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-PNCUNPSA.js → chunk-7Y7PAC56.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-YJYSFWSW.js → chunk-ARK4FIO4.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-C6SH62BX.js → chunk-CJ4QA4RW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-ZDX2BCOT.js → chunk-I32L3FWW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-GEFWBVPQ.js → chunk-I4WDON3K.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-246P5AK7.js → chunk-IKPR4VVN.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-J3GN4SQT.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-LG3SYXBX.js → chunk-OOZHQFBF.js} +9 -9
- package/dist/cli-bundle/focused-chunks/{chunk-BVOQRMHF.js → chunk-P4BA7OX7.js} +27 -26
- package/dist/cli-bundle/focused-chunks/{chunk-7D6M45AN.js → chunk-QL4MO5M2.js} +9 -9
- package/dist/cli-bundle/focused-chunks/chunk-TDHVROGL.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-V3YMNAO7.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-YDFEWXXZ.js +59 -0
- package/dist/cli-bundle/focused-chunks/{chunk-MMX7BQLH.js → chunk-ZDBKYZFE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-7UZHYT5B.js → chunk-ZI2YBJFH.js} +2 -2
- package/dist/cli-bundle/main.js +2 -2
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +2 -2
- 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 +41 -41
- 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 +8 -8
- package/dist/cli.js +1 -1
- package/dist/core/checkpoint/mutation-checkpoint.d.ts +1 -1
- package/dist/core/checkpoint/mutation-checkpoint.js +2 -2
- package/dist/core/fs/atomic-create.d.ts +7 -0
- package/dist/core/fs/atomic-create.js +2 -0
- package/dist/core/history/history.js +1 -1
- package/dist/core/schema/runtime-schema.d.ts +1 -1
- package/dist/core/schema/runtime-schema.js +2 -2
- package/dist/core/session/session-state.js +1 -1
- package/dist/core/store/settings-concurrency.d.ts +7 -0
- package/dist/core/store/settings-concurrency.js +2 -0
- package/dist/core/store/settings.d.ts +8 -1
- package/dist/core/store/settings.js +3 -2
- package/dist/sdk/cli-contracts/flag-contracts.js +1 -1
- package/dist/sdk/contracts.d.ts +1 -0
- package/dist/sdk/contracts.js +1 -1
- package/dist/sdk/extension/install-runtime.d.ts +1 -1
- package/dist/sdk/extension/install-runtime.js +2 -2
- package/dist/sdk/governance/health.js +1 -1
- package/dist/sdk/governance/provenance-health.d.ts +27 -0
- package/dist/sdk/governance/provenance-health.js +1 -1
- package/dist/sdk/graph/index.d.ts +1 -0
- package/dist/sdk/graph/index.js +1 -1
- package/dist/sdk/graph/query-contracts.d.ts +18 -0
- package/dist/sdk/graph/query-contracts.js +2 -0
- package/dist/sdk/graph/run.d.ts +2 -0
- package/dist/sdk/graph/run.js +1 -1
- package/dist/sdk/graph/traversal.js +1 -1
- package/dist/sdk/lifecycle-policy.js +1 -1
- package/dist/sdk/public-surface.json +1 -1
- package/docs/MCP_OPTION_CONFORMANCE.md +41 -0
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +18 -2
- package/docs/PERFORMANCE.md +37 -0
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +28 -4
- package/docs/SDK_LIFECYCLE.md +16 -2
- package/docs/WORKSPACE_CONCURRENCY.md +67 -0
- package/marketplace.json +2 -2
- package/package.json +2 -2
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/dist/cli-bundle/chunks/chunk-CI2JCBN2.js +0 -237
- package/dist/cli-bundle/chunks/chunk-IPR2ICDO.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-HRANNGHM.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-LI6IGGB3.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QKG7JD34.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-QYQFBJXD.js +0 -59
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="51825a77-c7de-51ca-aa9e-4362278019ec")}catch(e2){}})();import fs from"node:fs";import*as nodeModule from"node:module";import os from"node:os";import path from"node:path";import{fileURLToPath}from"node:url";import{runCliWithBundleIntegrity}from"./cli/bundle-integrity.js";import{runRuntimeCompatibleCli}from"./cli/runtime-compatibility-boundary.js";import{registerInvocationProfile}from"./cli/invocation-profile.js";import{pruneCompileCacheGenerations,resolveCompileCacheGeneration}from"./sdk/compile-cache.js";function enableNodeCompileCache(){const{enableCompileCache}=nodeModule;if(typeof enableCompileCache!=="function"||process.env.PM_CLI_DISABLE_COMPILE_CACHE==="1"){return}const userCacheKey=typeof process.getuid==="function"?String(process.getuid()):os.userInfo().username.replace(/[^a-zA-Z0-9._-]/g,"_");const configuredCacheDir=process.env.PM_CLI_COMPILE_CACHE_DIR;const defaultCacheRoot=path.join(os.tmpdir(),`pm-cli-node-compile-cache-${userCacheKey}`);const generation=resolveCompileCacheGeneration(readPackageVersionForPath(fileURLToPath(import.meta.url)));const cacheDir=configuredCacheDir??path.join(defaultCacheRoot,generation);try{if(configuredCacheDir===void 0){pruneCompileCacheGenerations(defaultCacheRoot,generation)}enableCompileCache(cacheDir)}catch{}}function findPackageJson(startPath){let current=path.dirname(path.resolve(startPath));while(true){const candidate=path.join(current,"package.json");if(fs.existsSync(candidate)){return candidate}const parent=path.dirname(current);if(parent===current){return void 0}current=parent}}function printFastVersionIfRequested(){const args=process.argv.slice(2);const versionArgs=args.filter(arg=>arg!=="--no-extensions"&&arg!=="--profile");if(versionArgs.length!==1||versionArgs[0]!=="--version"&&versionArgs[0]!=="-V"){return false}const version=readPackageVersionForPath(fileURLToPath(import.meta.url));if(version===void 0){return false}console.log(version);return true}function readPackageVersionForPath(startPath){const packageJsonPath=findPackageJson(startPath);if(!packageJsonPath){return void 0}try{const parsed=JSON.parse(fs.readFileSync(packageJsonPath,"utf8"));if(typeof parsed.version!=="string"){return void 0}return parsed.version}catch{return void 0}}const _testOnly={enableNodeCompileCache,findPackageJson,printFastVersionIfRequested,readPackageVersionForPath};registerInvocationProfile(process.argv.slice(2));if(!printFastVersionIfRequested()){enableNodeCompileCache();const cliEntrypointPath=fileURLToPath(import.meta.url);const executingVersion=readPackageVersionForPath(cliEntrypointPath);const invocationArgv=process.argv.slice(2);await runRuntimeCompatibleCli({executingVersion,projectRoot:process.cwd(),argv:invocationArgv,allowStale:process.env.PM_ALLOW_STALE_CLI==="1",run:()=>runCliWithBundleIntegrity(invocationArgv,cliEntrypointPath,()=>import("./cli-bundle/main.js"),process.stderr.write.bind(process.stderr)),writeError:process.stderr.write.bind(process.stderr)})}export{_testOnly};
|
|
3
3
|
//# sourceMappingURL=cli.js.map
|
|
@@ -55,7 +55,7 @@ export declare function createCheckpointId(prefix: string, nowValue: string): st
|
|
|
55
55
|
export declare function checkpointDirectoryPath(pmRoot: string, subdir: string): string;
|
|
56
56
|
/** Implements checkpoint file path for the public runtime surface of this module. */
|
|
57
57
|
export declare function checkpointFilePath(pmRoot: string, subdir: string, checkpointId: string): string;
|
|
58
|
-
/**
|
|
58
|
+
/** Publish immutable checkpoint bytes once, including through path aliases; identical retries succeed and conflicting IDs preserve the original evidence. */
|
|
59
59
|
export declare function writeMutationCheckpoint(pmRoot: string, subdir: string, checkpointId: string, payload: unknown): Promise<string>;
|
|
60
60
|
/** Implements load mutation checkpoint for the public runtime surface of this module. */
|
|
61
61
|
export declare function loadMutationCheckpoint(pmRoot: string, subdir: string, rawCheckpointId: string, schemaVersion: number): Promise<LoadedMutationCheckpoint>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
!(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]="
|
|
2
|
-
`)
|
|
1
|
+
!(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]="93b04081-a71a-5987-8fb6-09a8d045c1da")}catch(e2){}})();import{readFile}from"node:fs/promises";import path from"node:path";import{pathExists,readFileIfExists}from"../fs/fs-utils.js";import{createFileAtomic}from"../fs/atomic-create.js";import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{toErrorMessage}from"../shared/primitives.js";import{nowIso}from"../shared/time.js";function normalizeCheckpointId(raw){const trimmed=raw.trim();if(!trimmed){throw new PmCliError("--rollback requires a non-empty checkpoint ID",EXIT_CODE.USAGE)}if(!/^[a-zA-Z0-9._-]+$/.test(trimmed)){throw new PmCliError("--rollback checkpoint ID must match [a-zA-Z0-9._-]+",EXIT_CODE.USAGE)}return trimmed}function createCheckpointId(prefix,nowValue){const compactTimestamp=nowValue.replace(/[-:.TZ]/g,"").slice(0,14);const randomSuffix=Math.random().toString(36).slice(2,8);return`${prefix}-${compactTimestamp}-${randomSuffix}`}function checkpointDirectoryPath(pmRoot,subdir){return path.join(pmRoot,"checkpoints",subdir)}function checkpointFilePath(pmRoot,subdir,checkpointId){return path.join(checkpointDirectoryPath(pmRoot,subdir),`${checkpointId}.json`)}async function writeMutationCheckpoint(pmRoot,subdir,checkpointId,payload){const filePath=checkpointFilePath(pmRoot,subdir,checkpointId);const raw=`${JSON.stringify(payload,null,2)}
|
|
2
|
+
`;if(!await createFileAtomic(filePath,raw)&&await readFileIfExists(filePath)!==raw){throw new PmCliError(`Checkpoint ${checkpointId} already exists with different contents; use a new checkpoint ID.`,EXIT_CODE.CONFLICT)}return filePath}function parseCheckpointItems(record,checkpointId){if(!Array.isArray(record.items)){throw new PmCliError(`Checkpoint ${checkpointId} is missing items`,EXIT_CODE.GENERIC_FAILURE)}return record.items.map(entry=>{if(!entry||typeof entry!=="object"){throw new PmCliError(`Checkpoint ${checkpointId} contains an invalid item entry`,EXIT_CODE.GENERIC_FAILURE)}const row=entry;if(typeof row.id!=="string"||row.id.trim().length===0){throw new PmCliError(`Checkpoint ${checkpointId} contains an item entry without ID`,EXIT_CODE.GENERIC_FAILURE)}if(typeof row.target_updated_at!=="string"||row.target_updated_at.trim().length===0){throw new PmCliError(`Checkpoint ${checkpointId} contains an item entry without target_updated_at`,EXIT_CODE.GENERIC_FAILURE)}return{id:row.id.trim(),target_updated_at:row.target_updated_at.trim()}})}async function loadMutationCheckpoint(pmRoot,subdir,rawCheckpointId,schemaVersion){const normalizedId=normalizeCheckpointId(rawCheckpointId);const filePath=checkpointFilePath(pmRoot,subdir,normalizedId);if(!await pathExists(filePath)){throw new PmCliError(`Checkpoint ${normalizedId} not found`,EXIT_CODE.NOT_FOUND)}const raw=await readFile(filePath,"utf8");let parsed;try{parsed=JSON.parse(raw)}catch(error){throw new PmCliError(`Checkpoint ${normalizedId} contains invalid JSON: ${toErrorMessage(error)}`,EXIT_CODE.GENERIC_FAILURE)}if(!parsed||typeof parsed!=="object"){throw new PmCliError(`Checkpoint ${normalizedId} is invalid`,EXIT_CODE.GENERIC_FAILURE)}const record=parsed;if(record.schema_version!==schemaVersion){throw new PmCliError(`Checkpoint ${normalizedId} has unsupported schema version`,EXIT_CODE.GENERIC_FAILURE)}const items=parseCheckpointItems(record,normalizedId);return{record,items,path:filePath,id:typeof record.id==="string"?record.id:normalizedId,created_at:typeof record.created_at==="string"?record.created_at:nowIso(),author:typeof record.author==="string"?record.author:"unknown"}}async function restoreCheckpointItems(items,restore){const rows=[];const restoredIds=[];for(const entry of items){try{const restored=await restore(entry.id,entry.target_updated_at);rows.push({id:entry.id,status:"restored",changed_fields:restored.changed_fields,warnings:restored.warnings});restoredIds.push(entry.id)}catch(error){rows.push({id:entry.id,status:"failed",error:toErrorMessage(error)})}}return{rows,restored_ids:restoredIds,failed_count:rows.filter(row=>row.status==="failed").length}}export{checkpointDirectoryPath,checkpointFilePath,createCheckpointId,loadMutationCheckpoint,normalizeCheckpointId,restoreCheckpointItems,writeMutationCheckpoint};
|
|
3
3
|
//# sourceMappingURL=mutation-checkpoint.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage bytes beside the destination, then atomically link them into an absent
|
|
3
|
+
* pathname. A competing creator wins without being overwritten. Hard-link
|
|
4
|
+
* failures other than EEXIST propagate; no unsafe overwrite fallback is used.
|
|
5
|
+
* Publication provides atomic visibility, not fsync-backed power-loss durability.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createFileAtomic(targetPath: string, contents: string): Promise<boolean>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!(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]="fcbdb4d9-ea0e-5944-98c3-4d1944d2641d")}catch(e2){}})();import{link,mkdir,mkdtemp,rm,writeFile}from"node:fs/promises";import path from"node:path";async function createFileAtomic(targetPath,contents){const parent=path.dirname(targetPath);await mkdir(parent,{recursive:true});const staging=await mkdtemp(path.join(parent,".pm-seed-"));const stagedFile=path.join(staging,"value");try{await writeFile(stagedFile,contents,"utf8");try{await link(stagedFile,targetPath);return true}catch(error){if(error.code==="EEXIST"){return false}throw error}}finally{await rm(staging,{recursive:true,force:true})}}export{createFileAtomic};
|
|
2
|
+
//# sourceMappingURL=atomic-create.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
!(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]="6583b1e2-5eae-5e97-af83-a78adac1d571")}catch(e2){}})();import jsonPatch from"fast-json-patch";import{normalizeHistoryOperationForWrite}from"./operation-contract.js";import{CURRENT_HISTORY_HASH_ALGORITHM,historyDigest,resolveHistoryHashAlgorithm}from"./digest.js";import fs from"node:fs/promises";import path from"node:path";import{EXIT_CODE,ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{runActiveServiceOverride}from"../extensions/index.js";import{appendLineAtomic}from"../fs/fs-utils.js";import{canonicalDocument}from"../item/item-format.js";import{toItemRecord}from"../item/item-record.js";import{orderObject,sha256Hex,stableStringify}from"../shared/serialization.js";import{isMillisecondPrecisionRfc3339DateTime,nowIso}from"../shared/time.js";import{diagnoseAgentIdentity,resolveHistoryAgentIdentity,resolveHistoryAuthorSource}from"../shared/author.js";import{appendHistoryEntryWithEventIndex,removeHistoryEventIndexForHistoryPath}from"./event-index.js";import{classifyHistoryEvent}from"./event-classification.js";import{invalidateHistoryDriftCacheForPath}from"./drift-cache.js";import{PmCliError}from"../shared/errors.js";const EMPTY_LEGACY_HASH_DOCUMENT={front_matter:{},body:""};const CURRENT_HISTORY_ITEM_HASH_VERSION=3;const SUPPORTED_HISTORY_ITEM_HASH_VERSIONS=[1,2,3];const CURRENT_HISTORY_RECORD_HASH_VERSION=1;const SUPPORTED_HISTORY_RECORD_HASH_VERSIONS=[1];function hashHistoryRecord(entry){return historyDigest(stableStringify(entry),entry.hash_algorithm)}function hashHistoryPatch(patch){return sha256Hex(stableStringify(patch))}function hashHistoryStream(entries){return sha256Hex(stableStringify(entries))}function sealHistoryRecord(entry){const sealed={...entry,record_hash_version:CURRENT_HISTORY_RECORD_HASH_VERSION};const{record_hash:_recordHash,...canonical}=sealed;return{...sealed,record_hash:hashHistoryRecord(canonical)}}function verifyHistoryRecordHash(entry){try{resolveHistoryHashAlgorithm(entry.hash_algorithm)}catch{return{ok:false,error:"unsupported_history_hash_algorithm"}}if(entry.record_hash_version===void 0&&entry.record_hash===void 0){return{ok:true,coverage:"item_state_only"}}if(entry.record_hash_version===void 0||entry.record_hash===void 0){return{ok:false,error:"incomplete_record_hash_envelope"}}if(!SUPPORTED_HISTORY_RECORD_HASH_VERSIONS.includes(entry.record_hash_version)){return{ok:false,error:"unsupported_record_hash_version"}}const{record_hash:_recordHash,...canonical}=entry;return hashHistoryRecord(canonical)===entry.record_hash?{ok:true,coverage:"record_and_item_state"}:{ok:false,error:"record_hash_mismatch"}}function createHistoryRewriteEvidence(original,options){const evidence={before_hash:original.before_hash,after_hash:original.after_hash,patch_hash:hashHistoryPatch(original.patch)};if(original.hash_algorithm!==void 0)evidence.hash_algorithm=original.hash_algorithm;if(original.item_hash_version!==void 0){evidence.item_hash_version=original.item_hash_version}if(options.retainOriginalPatch){evidence.patch=structuredClone(original.patch)}if(options.retainPriorRecordHash!==false&&original.record_hash_version!==void 0&&original.record_hash!==void 0){evidence.record_hash_version=original.record_hash_version;evidence.record_hash=original.record_hash;evidence.record=structuredClone(original)}return evidence}function resealHistoryRewrite(original,rewritten,options={}){const originalRecordVerification=verifyHistoryRecordHash(original);if(!originalRecordVerification.ok){throw new TypeError(originalRecordVerification.error)}const originalPatchHash=hashHistoryPatch(original.patch);const retainsRewriteEvidence=options.retainPriorRecord===true||original.before_hash!==rewritten.before_hash||original.after_hash!==rewritten.after_hash||original.item_hash_version!==rewritten.item_hash_version||original.hash_algorithm!==rewritten.hash_algorithm||originalPatchHash!==hashHistoryPatch(rewritten.patch);const sealed=sealHistoryRecord({...rewritten,...retainsRewriteEvidence?{reanchor_evidence:[...rewritten.reanchor_evidence??[],createHistoryRewriteEvidence(original,options)]}:{}});const evidenceVerification=verifyHistoryRewriteEvidence(sealed);if(!evidenceVerification.ok){throw new TypeError(evidenceVerification.error)}return sealed}function isHistoryPatch(value){if(!Array.isArray(value)||Object.keys(value).length!==value.length){return false}return value.every(operation=>{if(!isRecord(operation)||typeof operation.path!=="string"){return false}if(operation.op==="move"||operation.op==="copy"){return typeof operation.from==="string"}if(["add","replace","test"].includes(operation.op)){return Object.hasOwn(operation,"value")}return operation.op==="remove"})}function isRetainedHistoryRecordShape(value){return isRecord(value)&&typeof value.ts==="string"&&typeof value.author==="string"&&typeof value.op==="string"&&typeof value.before_hash==="string"&&typeof value.after_hash==="string"&&isHistoryPatch(value.patch)}function hasCompleteRetainedRecordHashEnvelope(evidence){const hasVersion=evidence.record_hash_version!==void 0;const hasHash=evidence.record_hash!==void 0;return hasVersion===hasHash}function isHistoryReanchorEvidence(evidence){if(!isRecord(evidence)||!hasCompleteRetainedRecordHashEnvelope(evidence)||typeof evidence.before_hash!=="string"||typeof evidence.after_hash!=="string"||typeof evidence.patch_hash!=="string"||!/^[a-f0-9]{64}$/u.test(evidence.patch_hash)||evidence.patch!==void 0&&!isHistoryPatch(evidence.patch)||evidence.record_hash_version!==void 0&&typeof evidence.record_hash_version!=="number"||evidence.record_hash!==void 0&&(typeof evidence.record_hash!=="string"||!/^(?:[a-f0-9]{64}|[a-f0-9]{128})$/u.test(evidence.record_hash))){return false}return evidence.record===void 0||isRetainedHistoryRecordShape(evidence.record)}function isHistoryRewriteEvidenceList(evidenceEntries){try{for(const evidence of evidenceEntries){if(!isHistoryReanchorEvidence(evidence))return false;resolveHistoryHashAlgorithm(evidence.hash_algorithm)}return true}catch{return false}}function matchesRetainedHistoryRecord(evidence){const record=evidence.record;return record!==void 0&&record.before_hash===evidence.before_hash&&record.after_hash===evidence.after_hash&&record.item_hash_version===evidence.item_hash_version&&record.hash_algorithm===evidence.hash_algorithm&&record.record_hash_version===evidence.record_hash_version&&record.record_hash===evidence.record_hash&&hashHistoryPatch(record.patch)===evidence.patch_hash}function reconstructPriorHistoryRecord(current,evidence,priorEvidence){if(evidence.patch&&hashHistoryPatch(evidence.patch)!==evidence.patch_hash){return{kind:"patch_hash_mismatch"}}if(evidence.record){if(!matchesRetainedHistoryRecord(evidence)){return{kind:"record_hash_mismatch"}}return{kind:"record",entry:evidence.record}}const priorPatch=evidence.patch??current.patch;if(hashHistoryPatch(priorPatch)!==evidence.patch_hash){return{kind:"digest_only"}}const priorRecord={...current,before_hash:evidence.before_hash,after_hash:evidence.after_hash,patch:priorPatch,hash_algorithm:evidence.hash_algorithm,...evidence.item_hash_version===void 0?{}:{item_hash_version:evidence.item_hash_version},...evidence.record_hash_version===void 0?{}:{record_hash_version:evidence.record_hash_version},...evidence.record_hash===void 0?{}:{record_hash:evidence.record_hash},...priorEvidence.length===0?{}:{reanchor_evidence:priorEvidence}};if(evidence.hash_algorithm===void 0)delete priorRecord.hash_algorithm;if(priorEvidence.length===0)delete priorRecord.reanchor_evidence;if(evidence.item_hash_version===void 0){delete priorRecord.item_hash_version}return evidence.record_hash_version===void 0||evidence.record_hash===void 0?{kind:"legacy",entry:priorRecord}:{kind:"record",entry:priorRecord}}function verifyHistoryRewriteEvidence(entry){const evidenceEntries=entry.reanchor_evidence;if(evidenceEntries===void 0)return{ok:true,coverage:"none"};if(!Array.isArray(evidenceEntries)||!isHistoryRewriteEvidenceList(evidenceEntries)){return{ok:false,error:"rewrite_evidence_invalid"}}if(evidenceEntries.length===0)return{ok:true,coverage:"none"};let reconstructed=entry;for(let index=evidenceEntries.length-1;index>=0;index-=1){const evidence=evidenceEntries[index];const prior=reconstructPriorHistoryRecord(reconstructed,evidence,evidenceEntries.slice(0,index));if(prior.kind==="patch_hash_mismatch"){return{ok:false,error:"rewrite_evidence_patch_hash_mismatch"}}if(prior.kind==="record_hash_mismatch"){return{ok:false,error:"rewrite_evidence_record_hash_mismatch"}}if(prior.kind==="digest_only"){return{ok:true,coverage:"digest_only"}}if(prior.kind==="legacy"){return{ok:true,coverage:"legacy_anchor_only"}}if(!verifyHistoryRecordHash(prior.entry).ok){return{ok:false,error:"rewrite_evidence_record_hash_mismatch"}}reconstructed=prior.entry}return{ok:true,coverage:"complete"}}function compareOptionalStrings(left,right){return(left??"").localeCompare(right??"")}function compareOptionalNumbers(left,right){return(left??0)-(right??0)}function compareJsonValues(left,right,fallback){return JSON.stringify(left??fallback).localeCompare(JSON.stringify(right??fallback))}function compareLegacyLinkedTests(left,right){const comparisons=[left.scope.localeCompare(right.scope),compareOptionalStrings(left.path,right.path),compareOptionalStrings(left.command,right.command),compareOptionalNumbers(left.timeout_seconds,right.timeout_seconds),compareOptionalStrings(left.pm_context_mode,right.pm_context_mode),Number(Boolean(left.shared_host_safe))-Number(Boolean(right.shared_host_safe)),compareJsonValues(left.env_clear,right.env_clear,[]),compareJsonValues(left.env_set,right.env_set,{}),compareJsonValues(left.assert_stdout_contains,right.assert_stdout_contains,[]),compareJsonValues(left.assert_stdout_regex,right.assert_stdout_regex,[]),compareJsonValues(left.assert_stderr_contains,right.assert_stderr_contains,[]),compareJsonValues(left.assert_stderr_regex,right.assert_stderr_regex,[]),compareOptionalNumbers(left.assert_stdout_min_lines,right.assert_stdout_min_lines),compareJsonValues(left.assert_json_field_equals,right.assert_json_field_equals,{}),compareJsonValues(left.assert_json_field_gte,right.assert_json_field_gte,{}),compareOptionalStrings(left.note,right.note)];return comparisons.find(comparison=>comparison!==0)??0}function decodeJsonPointer(path2){if(!path2||path2==="/"){return[]}if(!path2.startsWith("/")){return[]}return path2.slice(1).split("/").map(segment=>segment.replaceAll("~1","/").replaceAll("~0","~"))}function isDefinedPointerPath(document,path2){const segments=decodeJsonPointer(path2);if(segments.length===0){return true}let cursor=document;for(const segment of segments){const arrayIndex=/^(0|[1-9]\d*)$/.test(segment)?Number(segment):-1;const next=Array.isArray(cursor)?arrayIndex>=0&&arrayIndex<cursor.length?cursor[arrayIndex]:void 0:isRecord(cursor)&&Object.prototype.hasOwnProperty.call(cursor,segment)?cursor[segment]:void 0;if(next===void 0)return false;cursor=next}return true}function normalizeHistoryPatchOps(beforeDocument,patch){const normalized=[];let replayCursor=structuredClone(beforeDocument);for(const operation of patch){const normalizedOperation=operation.op==="replace"&&!isDefinedPointerPath(replayCursor,operation.path)?{...operation,op:"add"}:operation;normalized.push(normalizedOperation);replayCursor=jsonPatch.applyPatch(replayCursor,[normalizedOperation],true,true).newDocument}return normalized}function canonicalHashDocument(document,version,legacyV2Fields=false){const hasMetadata=document.metadata&&Object.keys(document.metadata).length>0;if(!hasMetadata){return{front_matter:{},body:document.body??""}}const canonical=canonicalDocument(document);const usesLegacyFields=version===1||version===2&&legacyV2Fields;const epochMetadata=usesLegacyFields?{...canonical.metadata,...canonical.metadata.dependencies===void 0?{}:{dependencies:canonical.metadata.dependencies.map(dependency=>({...dependency,id:dependency.id.toLowerCase()}))},...canonical.metadata.tests===void 0?{}:{tests:canonical.metadata.tests.map(({workspace_context_mode:_workspaceContextMode,provenance:_provenance,provenance_invalid:_provenanceInvalid,...test})=>test)},...canonical.metadata.test_runs===void 0?{}:{test_runs:canonical.metadata.test_runs.map(({executions:_executions,...testRun})=>testRun)}}:canonical.metadata;const metadata=version===1&&epochMetadata.tests?{...epochMetadata,tests:[...epochMetadata.tests].sort(compareLegacyLinkedTests)}:epochMetadata;const orderedMetadata=orderObject(toItemRecord(metadata),ITEM_METADATA_KEY_ORDER);return{front_matter:orderedMetadata,body:canonical.body}}function canonicalPatchDocument(document){const hasMetadata=document.metadata&&Object.keys(document.metadata).length>0;if(!hasMetadata){return{metadata:{},body:document.body??""}}const canonical=canonicalDocument(document);const orderedMetadata=orderObject(toItemRecord(canonical.metadata),ITEM_METADATA_KEY_ORDER);return{metadata:orderedMetadata,body:canonical.body}}function hashDocument(document){return hashDocumentForVersion(document,CURRENT_HISTORY_ITEM_HASH_VERSION)}function hashDocumentForVersion(document,version,algorithm){if(!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.some(supportedVersion=>supportedVersion===version)){throw new TypeError(`unsupported_item_hash_version:${String(version)}`)}return historyDigest(stableStringify(canonicalHashDocument(document,version)),algorithm)}function hashDocumentVerificationCandidates(document,version,algorithm){const canonicalHash=hashDocumentForVersion(document,version,algorithm);return version===2?[canonicalHash,historyDigest(stableStringify(canonicalHashDocument(document,version,true)),algorithm)]:[canonicalHash]}function hashEmptyDocument(){return sha256Hex(stableStringify(EMPTY_LEGACY_HASH_DOCUMENT))}function createHistoryEntry(params){const operation=normalizeHistoryOperationForWrite(params.op);const beforeHashCanonical=canonicalHashDocument(params.before,CURRENT_HISTORY_ITEM_HASH_VERSION);const afterHashCanonical=canonicalHashDocument(params.after,CURRENT_HISTORY_ITEM_HASH_VERSION);const beforePatchCanonical=canonicalPatchDocument(params.before);const afterPatchCanonical=canonicalPatchDocument(params.after);const rawPatch=jsonPatch.compare(beforePatchCanonical,afterPatchCanonical);const patch=normalizeHistoryPatchOps(beforePatchCanonical,rawPatch);const agentIdentity=resolveHistoryAgentIdentity(params.author);const provenanceOutcomes=agentIdentity.harness?Object.fromEntries(Object.entries(diagnoseAgentIdentity().provenance_outcomes).filter(([,outcome])=>outcome.resolver!==void 0&&outcome.status!=="resolved")):void 0;const context=provenanceOutcomes===void 0||Object.keys(provenanceOutcomes).length===0?params.context:{...params.context,agent_provenance_outcomes:provenanceOutcomes};const algorithm=params.hashAlgorithm??CURRENT_HISTORY_HASH_ALGORITHM;const entry={hash_algorithm:algorithm,ts:params.nowIso,author:params.author,author_source:params.authorSource??resolveHistoryAuthorSource(params.author),...agentIdentity.harness?{agent_harness:agentIdentity.harness}:{},...agentIdentity.model?{agent_model:agentIdentity.model}:{},...agentIdentity.model_source?{agent_model_source:agentIdentity.model_source}:{},...agentIdentity.instance?{agent_instance:agentIdentity.instance}:{},...agentIdentity.provenance?{agent_provenance:agentIdentity.provenance}:{},...agentIdentity.episode?{agent_episode:agentIdentity.episode}:{},op:operation,patch,before_hash:historyDigest(stableStringify(beforeHashCanonical),algorithm),after_hash:historyDigest(stableStringify(afterHashCanonical),algorithm),item_hash_version:CURRENT_HISTORY_ITEM_HASH_VERSION,message:params.message===void 0?void 0:params.message,...context===void 0?{}:{context}};return sealHistoryRecord({...entry,event_class:classifyHistoryEvent(entry)})}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function invalidHistoryTimestamp(message){return new PmCliError(message,EXIT_CODE.GENERIC_FAILURE,{code:"history_timestamp_invalid"})}function fallbackHistoryTimestamp(entry){const ts=entry.ts.trim();if(ts.length===0)return nowIso();if(!isMillisecondPrecisionRfc3339DateTime(ts)){throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision")}if(ts!==entry.ts){throw invalidHistoryTimestamp("History timestamp must not contain surrounding whitespace")}return entry.ts}function withHistoryTimestamp(value,fallbackTs){const ts=value.ts;if(typeof ts==="string"&&ts.trim().length>0){if(!isMillisecondPrecisionRfc3339DateTime(ts)){throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision")}return value}return{...value,ts:fallbackTs}}function serializeHistoryLine(value,fallbackEntry){const fallbackTs=fallbackHistoryTimestamp(fallbackEntry);if(typeof value==="string"){let parsed;try{parsed=JSON.parse(value)}catch{return value}if(isRecord(parsed)){return JSON.stringify(withHistoryTimestamp(parsed,fallbackTs))}return value}if(isRecord(value)){return JSON.stringify(withHistoryTimestamp(value,fallbackTs))}return JSON.stringify(value)}async function applyHistoryAppendOverride(historyPath,entry,result){if(result===false)return true;if(typeof result==="string"){const line2=serializeHistoryLine(result,entry);await appendHistoryLineWithIdentityReservation(historyPath,line2);await invalidateHistoryDriftCacheForPath(historyPath);await removeHistoryEventIndexForHistoryPath(historyPath);return true}if(typeof result!=="object"||result===null)return false;const record=result;if(record.skip===true)return true;const nextHistoryPath=typeof record.history_path==="string"?record.history_path:historyPath;const line=serializeHistoryLine(typeof record.line==="string"?record.line:record.entry??entry,entry);await appendHistoryLineWithIdentityReservation(nextHistoryPath,line);await invalidateHistoryDriftCacheForPath(nextHistoryPath);await removeHistoryEventIndexForHistoryPath(nextHistoryPath);return true}async function appendHistoryLineWithIdentityReservation(historyPath,line){let record;try{record=JSON.parse(line)}catch{record=null}if(!isRecord(record)||record.op!=="create"){await appendLineAtomic(historyPath,line);return}await fs.mkdir(path.dirname(historyPath),{recursive:true});try{await fs.writeFile(historyPath,`${line}
|
|
1
|
+
!(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]="8c02324c-231c-54ae-8edb-256ac7e04b50")}catch(e2){}})();import jsonPatch from"fast-json-patch";import{normalizeHistoryOperationForWrite}from"./operation-contract.js";import{CURRENT_HISTORY_HASH_ALGORITHM,historyDigest,resolveHistoryHashAlgorithm}from"./digest.js";import fs from"node:fs/promises";import path from"node:path";import{EXIT_CODE,ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{runActiveServiceOverride}from"../extensions/index.js";import{appendLineAtomic}from"../fs/fs-utils.js";import{canonicalDocument}from"../item/item-format.js";import{toItemRecord}from"../item/item-record.js";import{orderObject,sha256Hex,stableStringify}from"../shared/serialization.js";import{isMillisecondPrecisionRfc3339DateTime,nowIso}from"../shared/time.js";import{diagnoseAgentIdentity,resolveHistoryAgentIdentity,resolveHistoryAuthorSource}from"../shared/author.js";import{appendHistoryEntryWithEventIndex,removeHistoryEventIndexForHistoryPath}from"./event-index.js";import{classifyHistoryEvent}from"./event-classification.js";import{invalidateHistoryDriftCacheForPath}from"./drift-cache.js";import{PmCliError}from"../shared/errors.js";const EMPTY_LEGACY_HASH_DOCUMENT={front_matter:{},body:""};const CURRENT_HISTORY_ITEM_HASH_VERSION=3;const SUPPORTED_HISTORY_ITEM_HASH_VERSIONS=[1,2,3];const CURRENT_HISTORY_RECORD_HASH_VERSION=1;const SUPPORTED_HISTORY_RECORD_HASH_VERSIONS=[1];function hashHistoryRecord(entry){return historyDigest(stableStringify(entry),entry.hash_algorithm)}function hashHistoryPatch(patch){return sha256Hex(stableStringify(patch))}function hashHistoryStream(entries){return sha256Hex(stableStringify(entries))}function sealHistoryRecord(entry){const sealed={...entry,record_hash_version:CURRENT_HISTORY_RECORD_HASH_VERSION};const{record_hash:_recordHash,...canonical}=sealed;return{...sealed,record_hash:hashHistoryRecord(canonical)}}function verifyHistoryRecordHash(entry){try{resolveHistoryHashAlgorithm(entry.hash_algorithm)}catch{return{ok:false,error:"unsupported_history_hash_algorithm"}}if(entry.record_hash_version===void 0&&entry.record_hash===void 0){return{ok:true,coverage:"item_state_only"}}if(entry.record_hash_version===void 0||entry.record_hash===void 0){return{ok:false,error:"incomplete_record_hash_envelope"}}if(!SUPPORTED_HISTORY_RECORD_HASH_VERSIONS.includes(entry.record_hash_version)){return{ok:false,error:"unsupported_record_hash_version"}}const{record_hash:_recordHash,...canonical}=entry;return hashHistoryRecord(canonical)===entry.record_hash?{ok:true,coverage:"record_and_item_state"}:{ok:false,error:"record_hash_mismatch"}}function createHistoryRewriteEvidence(original,options){const evidence={before_hash:original.before_hash,after_hash:original.after_hash,patch_hash:hashHistoryPatch(original.patch)};if(original.hash_algorithm!==void 0)evidence.hash_algorithm=original.hash_algorithm;if(original.item_hash_version!==void 0){evidence.item_hash_version=original.item_hash_version}if(options.retainOriginalPatch){evidence.patch=structuredClone(original.patch)}if(options.retainPriorRecordHash!==false&&original.record_hash_version!==void 0&&original.record_hash!==void 0){evidence.record_hash_version=original.record_hash_version;evidence.record_hash=original.record_hash;evidence.record=structuredClone(original)}return evidence}function resealHistoryRewrite(original,rewritten,options={}){const originalRecordVerification=verifyHistoryRecordHash(original);if(!originalRecordVerification.ok){throw new TypeError(originalRecordVerification.error)}const originalPatchHash=hashHistoryPatch(original.patch);const retainsRewriteEvidence=options.retainPriorRecord===true||original.before_hash!==rewritten.before_hash||original.after_hash!==rewritten.after_hash||original.item_hash_version!==rewritten.item_hash_version||original.hash_algorithm!==rewritten.hash_algorithm||originalPatchHash!==hashHistoryPatch(rewritten.patch);const sealed=sealHistoryRecord({...rewritten,...retainsRewriteEvidence?{reanchor_evidence:[...rewritten.reanchor_evidence??[],createHistoryRewriteEvidence(original,options)]}:{}});const evidenceVerification=verifyHistoryRewriteEvidence(sealed);if(!evidenceVerification.ok){throw new TypeError(evidenceVerification.error)}return sealed}function isHistoryPatch(value){if(!Array.isArray(value)||Object.keys(value).length!==value.length){return false}return value.every(operation=>{if(!isRecord(operation)||typeof operation.path!=="string"){return false}if(operation.op==="move"||operation.op==="copy"){return typeof operation.from==="string"}if(["add","replace","test"].includes(operation.op)){return Object.hasOwn(operation,"value")}return operation.op==="remove"})}function isRetainedHistoryRecordShape(value){return isRecord(value)&&typeof value.ts==="string"&&typeof value.author==="string"&&typeof value.op==="string"&&typeof value.before_hash==="string"&&typeof value.after_hash==="string"&&isHistoryPatch(value.patch)}function hasCompleteRetainedRecordHashEnvelope(evidence){const hasVersion=evidence.record_hash_version!==void 0;const hasHash=evidence.record_hash!==void 0;return hasVersion===hasHash}function isHistoryReanchorEvidence(evidence){if(!isRecord(evidence)||!hasCompleteRetainedRecordHashEnvelope(evidence)||typeof evidence.before_hash!=="string"||typeof evidence.after_hash!=="string"||typeof evidence.patch_hash!=="string"||!/^[a-f0-9]{64}$/u.test(evidence.patch_hash)||evidence.patch!==void 0&&!isHistoryPatch(evidence.patch)||evidence.record_hash_version!==void 0&&typeof evidence.record_hash_version!=="number"||evidence.record_hash!==void 0&&(typeof evidence.record_hash!=="string"||!/^(?:[a-f0-9]{64}|[a-f0-9]{128})$/u.test(evidence.record_hash))){return false}return evidence.record===void 0||isRetainedHistoryRecordShape(evidence.record)}function isHistoryRewriteEvidenceList(evidenceEntries){try{for(const evidence of evidenceEntries){if(!isHistoryReanchorEvidence(evidence))return false;resolveHistoryHashAlgorithm(evidence.hash_algorithm)}return true}catch{return false}}function matchesRetainedHistoryRecord(evidence){const record=evidence.record;return record!==void 0&&record.before_hash===evidence.before_hash&&record.after_hash===evidence.after_hash&&record.item_hash_version===evidence.item_hash_version&&record.hash_algorithm===evidence.hash_algorithm&&record.record_hash_version===evidence.record_hash_version&&record.record_hash===evidence.record_hash&&hashHistoryPatch(record.patch)===evidence.patch_hash}function reconstructPriorHistoryRecord(current,evidence,priorEvidence){if(evidence.patch&&hashHistoryPatch(evidence.patch)!==evidence.patch_hash){return{kind:"patch_hash_mismatch"}}if(evidence.record){if(!matchesRetainedHistoryRecord(evidence)){return{kind:"record_hash_mismatch"}}return{kind:"record",entry:evidence.record}}const priorPatch=evidence.patch??current.patch;if(hashHistoryPatch(priorPatch)!==evidence.patch_hash){return{kind:"digest_only"}}const priorRecord={...current,before_hash:evidence.before_hash,after_hash:evidence.after_hash,patch:priorPatch,hash_algorithm:evidence.hash_algorithm,...evidence.item_hash_version===void 0?{}:{item_hash_version:evidence.item_hash_version},...evidence.record_hash_version===void 0?{}:{record_hash_version:evidence.record_hash_version},...evidence.record_hash===void 0?{}:{record_hash:evidence.record_hash},...priorEvidence.length===0?{}:{reanchor_evidence:priorEvidence}};if(evidence.hash_algorithm===void 0)delete priorRecord.hash_algorithm;if(priorEvidence.length===0)delete priorRecord.reanchor_evidence;if(evidence.item_hash_version===void 0){delete priorRecord.item_hash_version}return evidence.record_hash_version===void 0||evidence.record_hash===void 0?{kind:"legacy",entry:priorRecord}:{kind:"record",entry:priorRecord}}function verifyHistoryRewriteEvidence(entry){const evidenceEntries=entry.reanchor_evidence;if(evidenceEntries===void 0)return{ok:true,coverage:"none"};if(!Array.isArray(evidenceEntries)||!isHistoryRewriteEvidenceList(evidenceEntries)){return{ok:false,error:"rewrite_evidence_invalid"}}if(evidenceEntries.length===0)return{ok:true,coverage:"none"};let reconstructed=entry;for(let index=evidenceEntries.length-1;index>=0;index-=1){const evidence=evidenceEntries[index];const prior=reconstructPriorHistoryRecord(reconstructed,evidence,evidenceEntries.slice(0,index));if(prior.kind==="patch_hash_mismatch"){return{ok:false,error:"rewrite_evidence_patch_hash_mismatch"}}if(prior.kind==="record_hash_mismatch"){return{ok:false,error:"rewrite_evidence_record_hash_mismatch"}}if(prior.kind==="digest_only"){return{ok:true,coverage:"digest_only"}}if(prior.kind==="legacy"){return{ok:true,coverage:"legacy_anchor_only"}}if(!verifyHistoryRecordHash(prior.entry).ok){return{ok:false,error:"rewrite_evidence_record_hash_mismatch"}}reconstructed=prior.entry}return{ok:true,coverage:"complete"}}function compareOptionalStrings(left,right){return(left??"").localeCompare(right??"")}function compareOptionalNumbers(left,right){return(left??0)-(right??0)}function compareJsonValues(left,right,fallback){return JSON.stringify(left??fallback).localeCompare(JSON.stringify(right??fallback))}function compareLegacyLinkedTests(left,right){const comparisons=[left.scope.localeCompare(right.scope),compareOptionalStrings(left.path,right.path),compareOptionalStrings(left.command,right.command),compareOptionalNumbers(left.timeout_seconds,right.timeout_seconds),compareOptionalStrings(left.pm_context_mode,right.pm_context_mode),Number(Boolean(left.shared_host_safe))-Number(Boolean(right.shared_host_safe)),compareJsonValues(left.env_clear,right.env_clear,[]),compareJsonValues(left.env_set,right.env_set,{}),compareJsonValues(left.assert_stdout_contains,right.assert_stdout_contains,[]),compareJsonValues(left.assert_stdout_regex,right.assert_stdout_regex,[]),compareJsonValues(left.assert_stderr_contains,right.assert_stderr_contains,[]),compareJsonValues(left.assert_stderr_regex,right.assert_stderr_regex,[]),compareOptionalNumbers(left.assert_stdout_min_lines,right.assert_stdout_min_lines),compareJsonValues(left.assert_json_field_equals,right.assert_json_field_equals,{}),compareJsonValues(left.assert_json_field_gte,right.assert_json_field_gte,{}),compareOptionalStrings(left.note,right.note)];return comparisons.find(comparison=>comparison!==0)??0}function decodeJsonPointer(path2){if(!path2||path2==="/"){return[]}if(!path2.startsWith("/")){return[]}return path2.slice(1).split("/").map(segment=>segment.replaceAll("~1","/").replaceAll("~0","~"))}function isDefinedPointerPath(document,path2){const segments=decodeJsonPointer(path2);if(segments.length===0){return true}let cursor=document;for(const segment of segments){const arrayIndex=/^(0|[1-9]\d*)$/.test(segment)?Number(segment):-1;const next=Array.isArray(cursor)?arrayIndex>=0&&arrayIndex<cursor.length?cursor[arrayIndex]:void 0:isRecord(cursor)&&Object.prototype.hasOwnProperty.call(cursor,segment)?cursor[segment]:void 0;if(next===void 0)return false;cursor=next}return true}function normalizeHistoryPatchOps(beforeDocument,patch){const normalized=[];let replayCursor=structuredClone(beforeDocument);for(const operation of patch){const normalizedOperation=operation.op==="replace"&&!isDefinedPointerPath(replayCursor,operation.path)?{...operation,op:"add"}:operation;normalized.push(normalizedOperation);replayCursor=jsonPatch.applyPatch(replayCursor,[normalizedOperation],true,true).newDocument}return normalized}function canonicalHashDocument(document,version,legacyV2Fields=false){const hasMetadata=document.metadata&&Object.keys(document.metadata).length>0;if(!hasMetadata){return{front_matter:{},body:document.body??""}}const canonical=canonicalDocument(document);const usesLegacyFields=version===1||version===2&&legacyV2Fields;const epochMetadata=usesLegacyFields?{...canonical.metadata,...canonical.metadata.dependencies===void 0?{}:{dependencies:canonical.metadata.dependencies.map(dependency=>({...dependency,id:dependency.id.toLowerCase()}))},...canonical.metadata.tests===void 0?{}:{tests:canonical.metadata.tests.map(({workspace_context_mode:_workspaceContextMode,provenance:_provenance,provenance_invalid:_provenanceInvalid,...test})=>test)},...canonical.metadata.test_runs===void 0?{}:{test_runs:canonical.metadata.test_runs.map(({executions:_executions,...testRun})=>testRun)}}:canonical.metadata;const metadata=version===1&&epochMetadata.tests?{...epochMetadata,tests:[...epochMetadata.tests].sort(compareLegacyLinkedTests)}:epochMetadata;const orderedMetadata=orderObject(toItemRecord(metadata),ITEM_METADATA_KEY_ORDER);return{front_matter:orderedMetadata,body:canonical.body}}function canonicalPatchDocument(document){const hasMetadata=document.metadata&&Object.keys(document.metadata).length>0;if(!hasMetadata){return{metadata:{},body:document.body??""}}const canonical=canonicalDocument(document);const orderedMetadata=orderObject(toItemRecord(canonical.metadata),ITEM_METADATA_KEY_ORDER);return{metadata:orderedMetadata,body:canonical.body}}function hashDocument(document){return hashDocumentForVersion(document,CURRENT_HISTORY_ITEM_HASH_VERSION)}function hashDocumentForVersion(document,version,algorithm){if(!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.some(supportedVersion=>supportedVersion===version)){throw new TypeError(`unsupported_item_hash_version:${String(version)}`)}return historyDigest(stableStringify(canonicalHashDocument(document,version)),algorithm)}function hashDocumentVerificationCandidates(document,version,algorithm){const canonicalHash=hashDocumentForVersion(document,version,algorithm);return version===2?[canonicalHash,historyDigest(stableStringify(canonicalHashDocument(document,version,true)),algorithm)]:[canonicalHash]}function hashEmptyDocument(){return sha256Hex(stableStringify(EMPTY_LEGACY_HASH_DOCUMENT))}function createHistoryEntry(params){const operation=normalizeHistoryOperationForWrite(params.op);const beforeHashCanonical=canonicalHashDocument(params.before,CURRENT_HISTORY_ITEM_HASH_VERSION);const afterHashCanonical=canonicalHashDocument(params.after,CURRENT_HISTORY_ITEM_HASH_VERSION);const beforePatchCanonical=canonicalPatchDocument(params.before);const afterPatchCanonical=canonicalPatchDocument(params.after);const rawPatch=jsonPatch.compare(beforePatchCanonical,afterPatchCanonical);const patch=normalizeHistoryPatchOps(beforePatchCanonical,rawPatch);const agentIdentity=resolveHistoryAgentIdentity(params.author);const provenanceOutcomes=agentIdentity.harness?Object.fromEntries(Object.entries(diagnoseAgentIdentity().provenance_outcomes).filter(([dimension,outcome])=>outcome.resolver!==void 0&&(outcome.status!=="resolved"||agentIdentity.provenance?.[dimension]?.source==="probe"))):void 0;const context=provenanceOutcomes===void 0||Object.keys(provenanceOutcomes).length===0?params.context:{...params.context,agent_provenance_outcomes:provenanceOutcomes};const algorithm=params.hashAlgorithm??CURRENT_HISTORY_HASH_ALGORITHM;const entry={hash_algorithm:algorithm,ts:params.nowIso,author:params.author,author_source:params.authorSource??resolveHistoryAuthorSource(params.author),...agentIdentity.harness?{agent_harness:agentIdentity.harness}:{},...agentIdentity.model?{agent_model:agentIdentity.model}:{},...agentIdentity.model_source?{agent_model_source:agentIdentity.model_source}:{},...agentIdentity.instance?{agent_instance:agentIdentity.instance}:{},...agentIdentity.provenance?{agent_provenance:agentIdentity.provenance}:{},...agentIdentity.episode?{agent_episode:agentIdentity.episode}:{},op:operation,patch,before_hash:historyDigest(stableStringify(beforeHashCanonical),algorithm),after_hash:historyDigest(stableStringify(afterHashCanonical),algorithm),item_hash_version:CURRENT_HISTORY_ITEM_HASH_VERSION,message:params.message===void 0?void 0:params.message,...context===void 0?{}:{context}};return sealHistoryRecord({...entry,event_class:classifyHistoryEvent(entry)})}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function invalidHistoryTimestamp(message){return new PmCliError(message,EXIT_CODE.GENERIC_FAILURE,{code:"history_timestamp_invalid"})}function fallbackHistoryTimestamp(entry){const ts=entry.ts.trim();if(ts.length===0)return nowIso();if(!isMillisecondPrecisionRfc3339DateTime(ts)){throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision")}if(ts!==entry.ts){throw invalidHistoryTimestamp("History timestamp must not contain surrounding whitespace")}return entry.ts}function withHistoryTimestamp(value,fallbackTs){const ts=value.ts;if(typeof ts==="string"&&ts.trim().length>0){if(!isMillisecondPrecisionRfc3339DateTime(ts)){throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision")}return value}return{...value,ts:fallbackTs}}function serializeHistoryLine(value,fallbackEntry){const fallbackTs=fallbackHistoryTimestamp(fallbackEntry);if(typeof value==="string"){let parsed;try{parsed=JSON.parse(value)}catch{return value}if(isRecord(parsed)){return JSON.stringify(withHistoryTimestamp(parsed,fallbackTs))}return value}if(isRecord(value)){return JSON.stringify(withHistoryTimestamp(value,fallbackTs))}return JSON.stringify(value)}async function applyHistoryAppendOverride(historyPath,entry,result){if(result===false)return true;if(typeof result==="string"){const line2=serializeHistoryLine(result,entry);await appendHistoryLineWithIdentityReservation(historyPath,line2);await invalidateHistoryDriftCacheForPath(historyPath);await removeHistoryEventIndexForHistoryPath(historyPath);return true}if(typeof result!=="object"||result===null)return false;const record=result;if(record.skip===true)return true;const nextHistoryPath=typeof record.history_path==="string"?record.history_path:historyPath;const line=serializeHistoryLine(typeof record.line==="string"?record.line:record.entry??entry,entry);await appendHistoryLineWithIdentityReservation(nextHistoryPath,line);await invalidateHistoryDriftCacheForPath(nextHistoryPath);await removeHistoryEventIndexForHistoryPath(nextHistoryPath);return true}async function appendHistoryLineWithIdentityReservation(historyPath,line){let record;try{record=JSON.parse(line)}catch{record=null}if(!isRecord(record)||record.op!=="create"){await appendLineAtomic(historyPath,line);return}await fs.mkdir(path.dirname(historyPath),{recursive:true});try{await fs.writeFile(historyPath,`${line}
|
|
2
2
|
`,{encoding:"utf8",flag:"wx"})}catch(error){if(error.code!=="EEXIST")throw error;throw new PmCliError("This item identity is reserved by an existing history stream.",EXIT_CODE.CONFLICT,{code:"item_identity_reserved",required:"Choose a new item ID or restore the original item from its history.",nextSteps:["Run pm history <id> --full, then pm restore <id> <version> to recover the original item."]})}}async function appendHistoryEntry(historyPath,entry){const override=await runActiveServiceOverride("history_append",{history_path:historyPath,entry});if(override.handled&&await applyHistoryAppendOverride(historyPath,entry,override.result)){return}const timestampedEntry=entry.ts.trim().length>0?entry:{...entry,ts:fallbackHistoryTimestamp(entry)};const normalizedEntry=sealHistoryRecord({...timestampedEntry,hash_algorithm:resolveHistoryHashAlgorithm(timestampedEntry.hash_algorithm),event_class:classifyHistoryEvent(timestampedEntry)});await appendHistoryEntryWithEventIndex(historyPath,normalizedEntry,async()=>{await appendHistoryLineWithIdentityReservation(historyPath,serializeHistoryLine(normalizedEntry,normalizedEntry))});await invalidateHistoryDriftCacheForPath(historyPath)}const _testOnly={decodeJsonPointer,isDefinedPointerPath};export{CURRENT_HISTORY_ITEM_HASH_VERSION,CURRENT_HISTORY_RECORD_HASH_VERSION,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS,SUPPORTED_HISTORY_RECORD_HASH_VERSIONS,_testOnly,appendHistoryEntry,createHistoryEntry,hashDocument,hashDocumentForVersion,hashDocumentVerificationCandidates,hashEmptyDocument,hashHistoryPatch,hashHistoryRecord,hashHistoryStream,resealHistoryRewrite,sealHistoryRecord,verifyHistoryRecordHash,verifyHistoryRewriteEvidence};
|
|
3
3
|
//# sourceMappingURL=history.js.map
|
|
@@ -117,7 +117,7 @@ export declare function normalizeRuntimeSchemaSettings(schema: Partial<RuntimeSc
|
|
|
117
117
|
export declare function filePathForSchemaSection(pmRoot: string, configuredPath: string | undefined, fallbackPath: string): string;
|
|
118
118
|
/** Resolves the active tracker's `schema/types.json` path so user-facing hints (e.g. the invalid-type error) point at the real `--pm-path` location instead of the hardcoded `.agents/pm` default. Mirrors how `pm schema add/remove-type` report their target path. */
|
|
119
119
|
export declare function resolveItemTypesFilePath(pmRoot: string, schema: RuntimeSchemaSettings): string;
|
|
120
|
-
/**
|
|
120
|
+
/** Publish missing schema seeds without overwriting definitions created by a concurrent reader or schema mutation. */
|
|
121
121
|
export declare function ensureRuntimeSchemaFileScaffold(pmRoot: string, schema: RuntimeSchemaSettings): Promise<RuntimeSchemaFileBootstrapResult>;
|
|
122
122
|
/** Implements load runtime schema from optional files for the public runtime surface of this module. */
|
|
123
123
|
export declare function loadRuntimeSchemaFromOptionalFiles(pmRoot: string, schema: RuntimeSchemaSettings): Promise<LoadedRuntimeSchemaSections>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
!(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]="87798e93-c34c-5355-aa60-695fb9e3eef1")}catch(e2){}})();import path from"node:path";import{pathExists,readFileIfExists,writeFileAtomic}from"../fs/fs-utils.js";import{DEFAULT_STATUS_DEFINITIONS,DEFAULT_WORKFLOW_DEFINITION}from"../shared/constants.js";import{RUNTIME_FIELD_COMMAND_VALUES,RUNTIME_FIELD_TYPE_VALUES,RUNTIME_STATUS_ROLE_VALUES,RUNTIME_UNKNOWN_FIELD_POLICY_VALUES,STATUS_VALUES}from"../../types/index.js";import{normalizeStatusToken}from"./status-token.js";const DEFAULT_RUNTIME_SCHEMA_FILE_PATHS=Object.freeze({types:"schema/types.json",statuses:"schema/statuses.json",fields:"schema/fields.json",workflows:"schema/workflows.json"});const DEFAULT_RUNTIME_WORKFLOW=DEFAULT_WORKFLOW_DEFINITION;const DEFAULT_RUNTIME_STATUS_DEFINITIONS=DEFAULT_STATUS_DEFINITIONS;const DEFAULT_RUNTIME_FIELD_COMMANDS=["create","update"];const RUNTIME_STATUS_ROLE_SET=new Set(RUNTIME_STATUS_ROLE_VALUES);const RUNTIME_FIELD_TYPE_SET=new Set(RUNTIME_FIELD_TYPE_VALUES);const RUNTIME_FIELD_COMMAND_SET=new Set(RUNTIME_FIELD_COMMAND_VALUES);const RUNTIME_UNKNOWN_FIELD_POLICY_SET=new Set(RUNTIME_UNKNOWN_FIELD_POLICY_VALUES);const RUNTIME_FIELD_VALUE_TYPE_SET=new Set(["string","number","boolean","array","object"]);const MAX_RUNTIME_FIELD_VALUE_SCHEMA_DEPTH=16;function isPlainObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}const RUNTIME_FIELD_VALUE_SCHEMA_SHAPE_VALIDATORS=[schema=>schema.type===void 0||typeof schema.type==="string"&&RUNTIME_FIELD_VALUE_TYPE_SET.has(schema.type),schema=>!Object.hasOwn(schema,"const")||isStructuredJsonValue(schema.const),schema=>schema.enum===void 0||Array.isArray(schema.enum)&&schema.enum.every(entry=>isStructuredJsonValue(entry)),schema=>schema.min_length===void 0||Number.isInteger(schema.min_length)&&schema.min_length>=0,schema=>schema.min_items===void 0||Number.isInteger(schema.min_items)&&schema.min_items>=0,schema=>schema.format===void 0||schema.format==="date-time",schema=>schema.required===void 0||Array.isArray(schema.required)&&schema.required.every(entry=>typeof entry==="string"&&entry.length>0),schema=>schema.additional_properties===void 0||typeof schema.additional_properties==="boolean",schema=>schema.properties===void 0||isPlainObject(schema.properties),schema=>schema.one_of===void 0||Array.isArray(schema.one_of)&&schema.one_of.length>0];function isStructuredJsonValue(value,ancestors=new Set){if(value===null||typeof value==="string"||typeof value==="boolean"){return true}if(typeof value==="number")return Number.isFinite(value);if(typeof value!=="object"||ancestors.has(value))return false;ancestors.add(value);const valid=Array.isArray(value)?value.every(entry=>isStructuredJsonValue(entry,ancestors)):Object.values(value).every(entry=>isStructuredJsonValue(entry,ancestors));ancestors.delete(value);return valid}function normalizeRuntimeFieldValueSchema(value,depth=0,ancestors=new Set){if(!isPlainObject(value)||depth>MAX_RUNTIME_FIELD_VALUE_SCHEMA_DEPTH||ancestors.has(value)){return void 0}ancestors.add(value);const schema=value;const type=schema.type;const enumValues=schema.enum;const oneOf=schema.one_of;const properties=schema.properties;const items=schema.items;const required=schema.required;const minLength=schema.min_length;const minItems=schema.min_items;const format=schema.format;const additionalProperties=schema.additional_properties;if(!RUNTIME_FIELD_VALUE_SCHEMA_SHAPE_VALIDATORS.every(check=>check(schema))){ancestors.delete(value);return void 0}const normalizedProperties=properties===void 0?void 0:Object.fromEntries(Object.entries(properties).map(([key,entry])=>[key,normalizeRuntimeFieldValueSchema(entry,depth+1,ancestors)]));const normalizedItems=items===void 0?void 0:normalizeRuntimeFieldValueSchema(items,depth+1,ancestors);const normalizedOneOf=oneOf===void 0?void 0:oneOf.map(entry=>normalizeRuntimeFieldValueSchema(entry,depth+1,ancestors));const normalizedNestedSchemas=[...Object.values(normalizedProperties??{}),...items===void 0?[]:[normalizedItems],...normalizedOneOf??[]];if(normalizedNestedSchemas.some(entry=>entry===void 0)){ancestors.delete(value);return void 0}ancestors.delete(value);return Object.fromEntries(Object.entries({type,const:Object.hasOwn(schema,"const")?schema.const:void 0,enum:enumValues,min_length:minLength,min_items:minItems,format,properties:normalizedProperties,required:required===void 0?void 0:[...new Set(required)],additional_properties:additionalProperties,items:normalizedItems,one_of:normalizedOneOf}).filter(([,entry])=>entry!==void 0))}function normalizeStringList(values){const candidates=Array.isArray(values)?values:[];return[...new Set(candidates.map(value=>typeof value==="string"?value.trim():"").filter(value=>value.length>0))].sort((left,right)=>left.localeCompare(right))}function normalizeStatusId(value){if(typeof value!=="string"||value.length===0){return void 0}const normalized=normalizeStatusToken(value);return normalized.length>0?normalized:void 0}function stripFlagPrefix(value){return value.startsWith("--")?value.slice(2):value}function normalizeCliToken(value){return typeof value==="string"?stripFlagPrefix(value.trim().toLowerCase().replaceAll(/[\s_]+/g,"-")):""}function keyToDefaultCliFlag(value){return value.replaceAll("_","-")}function toCamelCase(input){const segments=input.replaceAll(/[^A-Za-z0-9]+/g," ").trim().split(/\s+/).filter(segment=>segment.length>0).map(segment=>segment.toLowerCase());if(segments.length===0){return input}const[first,...rest]=segments;return`${first}${rest.map(segment=>`${segment.slice(0,1).toUpperCase()}${segment.slice(1)}`).join("")}`}function normalizeRuntimeStatusDefinition(definition,fallbackOrder){const id=normalizeStatusId(definition.id);if(!id){return null}const aliases=[...new Set(normalizeStringList(definition.aliases).map(normalizeStatusToken).filter(value=>value.length>0))].sort((left,right)=>left.localeCompare(right));const roles=normalizeStringList(definition.roles).filter(value=>RUNTIME_STATUS_ROLE_SET.has(value));const description=definition.description?.trim();const order=typeof definition.order==="number"&&Number.isFinite(definition.order)?definition.order:fallbackOrder;return{id,aliases,roles,description:description&&description.length>0?description:void 0,order}}function normalizeRuntimeWorkflow(workflow){return{draft_status:normalizeStatusId(workflow?.draft_status),open_status:normalizeStatusId(workflow?.open_status),in_progress_status:normalizeStatusId(workflow?.in_progress_status),blocked_status:normalizeStatusId(workflow?.blocked_status),close_status:normalizeStatusId(workflow?.close_status),canceled_status:normalizeStatusId(workflow?.canceled_status)}}function appendTypeWorkflowPair(record,pair){if(!Array.isArray(pair)||pair.length!==2){return}const from=normalizeStatusToken(pair[0]);const to=normalizeStatusToken(pair[1]);if(from.length===0||to.length===0){return}if(record.pairs.some(candidate=>candidate[0]===from&&candidate[1]===to)){return}record.pairs.push([from,to])}function normalizedTypeWorkflowEntry(entry){const rawType=typeof entry?.type==="string"?entry.type.trim():"";if(rawType.length===0||!Array.isArray(entry?.allowed_transitions)){return null}const record={type:rawType,pairs:[],denyAll:entry.allowed_transitions.length===0};for(const pair of entry.allowed_transitions){appendTypeWorkflowPair(record,pair)}return{typeKey:rawType.toLowerCase(),record}}function normalizeTypeWorkflowDefinitions(workflows){if(!Array.isArray(workflows)||workflows.length===0){return void 0}const byTypeKey=new Map;for(const entry of workflows){const normalized2=normalizedTypeWorkflowEntry(entry);if(normalized2===null){continue}const record=byTypeKey.get(normalized2.typeKey)??normalized2.record;record.denyAll||=normalized2.record.denyAll;for(const pair of normalized2.record.pairs){appendTypeWorkflowPair(record,pair)}byTypeKey.set(normalized2.typeKey,record)}const normalized=[];for(const record of byTypeKey.values()){if(record.pairs.length>0||record.denyAll){normalized.push({type:record.type,allowed_transitions:record.pairs})}}normalized.sort((left,right)=>left.type.localeCompare(right.type));return normalized.length>0?normalized:void 0}function normalizeRuntimeFieldDefinition(definition){const key=normalizeStatusToken(definition.key??"");if(!key){return null}const metadataKey=normalizeStatusToken(definition.metadata_key??definition.front_matter_key??key);const cliFlag=normalizeCliToken(definition.cli_flag??keyToDefaultCliFlag(key));if(!cliFlag){return null}const cliAliases=normalizeStringList(definition.cli_aliases).map(value=>normalizeCliToken(value)).filter(value=>value.length>0&&value!==cliFlag);const typeCandidate=typeof definition.type==="string"?definition.type.trim().toLowerCase():"string";const type=RUNTIME_FIELD_TYPE_SET.has(typeCandidate)?typeCandidate:"string";const commands=(()=>{const normalized=normalizeStringList(definition.commands).filter(value=>RUNTIME_FIELD_COMMAND_SET.has(value));if(normalized.length>0){return normalized}return[...DEFAULT_RUNTIME_FIELD_COMMANDS]})();const description=definition.description?.trim();const requiredTypes=normalizeStringList(definition.required_types);const valueSchema=definition.value_schema===void 0?void 0:normalizeRuntimeFieldValueSchema(definition.value_schema);if(definition.value_schema!==void 0&&valueSchema===void 0){return null}return{key,metadata_key:metadataKey,cli_flag:cliFlag,cli_aliases:cliAliases,description:description&&description.length>0?description:void 0,type,commands,repeatable:[definition.repeatable===true,type==="string_array"].includes(true),required:definition.required===true,required_on_create:definition.required_on_create===true,required_types:requiredTypes,allow_unset:definition.allow_unset!==false,value_schema:valueSchema}}function normalizeRuntimeStatusDefinitions(statusesSource){const dedupedById=new Map;for(const[index,definition]of statusesSource.entries()){const normalized=normalizeRuntimeStatusDefinition(definition,index);if(normalized){dedupedById.set(normalized.id,normalized)}}const values=sortRuntimeStatusDefinitions([...dedupedById.values()]);if(values.length>0){return values}return sortRuntimeStatusDefinitions(DEFAULT_RUNTIME_STATUS_DEFINITIONS.map((definition,index)=>normalizeRuntimeStatusDefinition(definition,index)).filter(definition=>definition!==null))}function sortRuntimeStatusDefinitions(definitions){return definitions.sort((left,right)=>left.order===right.order?left.id.localeCompare(right.id):left.order-right.order)}function normalizeRuntimeFieldDefinitions(fieldsSource){const dedupedByKey=new Map;for(const definition of fieldsSource??[]){const normalized=normalizeRuntimeFieldDefinition(definition);if(normalized){dedupedByKey.set(normalized.key,normalized)}}return[...dedupedByKey.values()].sort((left,right)=>left.key.localeCompare(right.key))}function serializeRuntimeStatusDefinition(definition){return{id:definition.id,aliases:definition.aliases.length>0?[...definition.aliases]:void 0,roles:definition.roles.length>0?[...definition.roles]:void 0,description:definition.description,order:definition.order}}function serializeRuntimeFieldDefinition(definition){return{key:definition.key,metadata_key:definition.metadata_key!==definition.key?definition.metadata_key:void 0,cli_flag:definition.cli_flag!==keyToDefaultCliFlag(definition.key)?definition.cli_flag:void 0,cli_aliases:definition.cli_aliases.length>0?[...definition.cli_aliases]:void 0,description:definition.description,type:definition.type,commands:[...definition.commands],repeatable:definition.repeatable===true?true:void 0,required:definition.required===true?true:void 0,required_on_create:definition.required_on_create===true?true:void 0,required_types:definition.required_types.length>0?[...definition.required_types]:void 0,allow_unset:definition.allow_unset===false?false:void 0,value_schema:definition.value_schema}}function normalizeUnknownFieldPolicy(policy){const candidate=typeof policy==="string"?policy.trim().toLowerCase():"allow";return RUNTIME_UNKNOWN_FIELD_POLICY_SET.has(candidate)?candidate:"allow"}function normalizeRuntimeSchemaSettings(schema){const files={...DEFAULT_RUNTIME_SCHEMA_FILE_PATHS,...schema?.files};const statusesSource=schema?.statuses&&schema.statuses.length>0?schema.statuses:DEFAULT_RUNTIME_STATUS_DEFINITIONS;const normalizedStatuses=normalizeRuntimeStatusDefinitions(statusesSource);const normalizedFields=normalizeRuntimeFieldDefinitions(schema?.fields);return{version:typeof schema?.version==="number"&&Number.isFinite(schema.version)?Math.floor(schema.version):1,files,statuses:normalizedStatuses.map(serializeRuntimeStatusDefinition),fields:normalizedFields.map(serializeRuntimeFieldDefinition),workflow:{...DEFAULT_RUNTIME_WORKFLOW,...normalizeRuntimeWorkflow(schema?.workflow)},type_workflows:normalizeTypeWorkflowDefinitions(schema?.type_workflows),unknown_field_policy:normalizeUnknownFieldPolicy(schema?.unknown_field_policy)}}function serializeJson(value){return`${JSON.stringify(value,null,2)}
|
|
2
|
-
`}function buildTypesFileSeed(){return{definitions:[]}}function buildStatusesFileSeed(){return{statuses:DEFAULT_RUNTIME_STATUS_DEFINITIONS}}function buildFieldsFileSeed(){return{fields:[]}}function buildWorkflowsFileSeed(){return{workflow:DEFAULT_RUNTIME_WORKFLOW}}function parseOptionalJson(raw,warningKey,warnings){try{return JSON.parse(raw)}catch{warnings.push(warningKey);return void 0}}function readTypeDefinitionsFromSchemaFile(parsed){if(Array.isArray(parsed)){return parsed}if(typeof parsed!=="object"||parsed===null){return void 0}const record=parsed;if(Array.isArray(record.definitions)){return record.definitions}if(typeof record.item_types==="object"&&record.item_types!==null){const itemTypesRecord=record.item_types;if(Array.isArray(itemTypesRecord.definitions)){return itemTypesRecord.definitions}}return void 0}function readStatusesFromSchemaFile(parsed){if(Array.isArray(parsed)){return parsed}if(typeof parsed!=="object"||parsed===null){return void 0}const record=parsed;if(Array.isArray(record.statuses)){return record.statuses}if(Array.isArray(record.definitions)){return record.definitions}return void 0}function readFieldsFromSchemaFile(parsed){if(Array.isArray(parsed)){return parsed}if(typeof parsed!=="object"||parsed===null){return void 0}const record=parsed;if(Array.isArray(record.fields)){return record.fields}if(Array.isArray(record.definitions)){return record.definitions}return void 0}function readWorkflowFromSchemaFile(parsed){if(typeof parsed!=="object"||parsed===null||Array.isArray(parsed)){return void 0}const record=parsed;if(typeof record.workflow==="object"&&record.workflow!==null&&!Array.isArray(record.workflow)){return record.workflow}if(typeof record.workflows==="object"&&record.workflows!==null&&!Array.isArray(record.workflows)){return record.workflows}return record}function readTypeWorkflowsFromSchemaFile(parsed){if(typeof parsed!=="object"||parsed===null||Array.isArray(parsed)){return void 0}const record=parsed;if(Array.isArray(record.type_workflows)){return record.type_workflows}return void 0}function filePathForSchemaSection(pmRoot,configuredPath,fallbackPath){const normalized=configuredPath?.trim()||fallbackPath;if(path.isAbsolute(normalized)){return normalized}return path.join(pmRoot,normalized)}function resolveItemTypesFilePath(pmRoot,schema){return filePathForSchemaSection(pmRoot,schema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types)}async function ensureRuntimeSchemaFileScaffold(pmRoot,schema){const normalizedSchema=normalizeRuntimeSchemaSettings(schema);const specs=[{path:filePathForSchemaSection(pmRoot,normalizedSchema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types),seed:buildTypesFileSeed()},{path:filePathForSchemaSection(pmRoot,normalizedSchema.files.statuses,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.statuses),seed:buildStatusesFileSeed()},{path:filePathForSchemaSection(pmRoot,normalizedSchema.files.fields,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.fields),seed:buildFieldsFileSeed()},{path:filePathForSchemaSection(pmRoot,normalizedSchema.files.workflows,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.workflows),seed:buildWorkflowsFileSeed()}];const createdPaths=[];for(const spec of specs){if(await pathExists(spec.path)){continue}await writeFileAtomic(spec.path,serializeJson(spec.seed));createdPaths.push(spec.path)}return{created_paths:createdPaths}}async function loadRuntimeSchemaFromOptionalFiles(pmRoot,schema){const normalizedSchema=normalizeRuntimeSchemaSettings(schema);const warnings=[];const typeFilePath=filePathForSchemaSection(pmRoot,normalizedSchema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);const statusFilePath=filePathForSchemaSection(pmRoot,normalizedSchema.files.statuses,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.statuses);const fieldsFilePath=filePathForSchemaSection(pmRoot,normalizedSchema.files.fields,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.fields);const workflowsFilePath=filePathForSchemaSection(pmRoot,normalizedSchema.files.workflows,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.workflows);let loadedTypeDefinitions;let loadedStatuses;let loadedFields;let loadedWorkflow;let loadedTypeWorkflows;const readAndParse=async(targetPath,warningKey)=>{const raw=await readFileIfExists(targetPath);if(raw===null){return void 0}return parseOptionalJson(raw,warningKey,warnings)};const parsedTypes=await readAndParse(typeFilePath,"runtime_schema_types_invalid_json");if(parsedTypes!==void 0){loadedTypeDefinitions=readTypeDefinitionsFromSchemaFile(parsedTypes);if(loadedTypeDefinitions===void 0){warnings.push("runtime_schema_types_invalid_shape")}}const parsedStatuses=await readAndParse(statusFilePath,"runtime_schema_statuses_invalid_json");if(parsedStatuses!==void 0){loadedStatuses=readStatusesFromSchemaFile(parsedStatuses);if(loadedStatuses===void 0){warnings.push("runtime_schema_statuses_invalid_shape")}}const parsedFields=await readAndParse(fieldsFilePath,"runtime_schema_fields_invalid_json");if(parsedFields!==void 0){loadedFields=readFieldsFromSchemaFile(parsedFields);if(loadedFields===void 0){warnings.push("runtime_schema_fields_invalid_shape")}}const parsedWorkflow=await readAndParse(workflowsFilePath,"runtime_schema_workflows_invalid_json");if(parsedWorkflow!==void 0){loadedWorkflow=readWorkflowFromSchemaFile(parsedWorkflow);if(loadedWorkflow===void 0){warnings.push("runtime_schema_workflows_invalid_shape")}loadedTypeWorkflows=readTypeWorkflowsFromSchemaFile(parsedWorkflow)}const mergedSchema=normalizeRuntimeSchemaSettings({...normalizedSchema,statuses:[...normalizedSchema.statuses,...loadedStatuses??[]],fields:[...normalizedSchema.fields,...loadedFields??[]],workflow:{...normalizedSchema.workflow,...loadedWorkflow},type_workflows:[...normalizedSchema.type_workflows??[],...loadedTypeWorkflows??[]]});return{schema:mergedSchema,type_definitions_from_file:loadedTypeDefinitions,warnings,created_paths:[]}}function preferredStatusForRole(definitions,role,fallbackValues,fallbackFirst=false){const normalizedFallbacks=fallbackValues.map(value=>normalizeStatusId(value)).filter(value=>typeof value==="string");const fallbackMatch=normalizedFallbacks.find(normalized=>definitions.some(definition=>definition.id===normalized));if(fallbackFirst&&fallbackMatch!==void 0){return fallbackMatch}const withRole=definitions.find(definition=>definition.roles.includes(role));if(withRole!==void 0){return withRole.id}return fallbackMatch??definitions[0]?.id}function buildRuntimeStatusIndexes(definitions){const aliasToId=new Map;const byId=new Map;for(const definition of definitions){byId.set(definition.id,definition);aliasToId.set(definition.id,definition.id);aliasToId.set(definition.id.replaceAll("_","-"),definition.id);aliasToId.set(definition.id.replaceAll("_"," "),definition.id);for(const alias of definition.aliases){aliasToId.set(alias,definition.id);aliasToId.set(alias.replaceAll("_","-"),definition.id);aliasToId.set(alias.replaceAll("_"," "),definition.id)}}return{aliasToId,byId}}function buildRuntimeStatusRoleSets(definitions){const result={activeStatuses:new Set,blockedStatuses:new Set,draftStatuses:new Set,terminalCanceledStatuses:new Set,terminalDoneStatuses:new Set,terminalStatuses:new Set};for(const definition of definitions){const roles=new Set(definition.roles);if(roles.has("terminal")||roles.has("terminal_done")||roles.has("terminal_canceled")){result.terminalStatuses.add(definition.id)}if(roles.has("terminal_done"))result.terminalDoneStatuses.add(definition.id);if(roles.has("terminal_canceled")){result.terminalCanceledStatuses.add(definition.id)}if(roles.has("active"))result.activeStatuses.add(definition.id);if(roles.has("blocked"))result.blockedStatuses.add(definition.id);if(roles.has("draft"))result.draftStatuses.add(definition.id)}return result}function resolveRuntimeStatusRegistry(schema){const normalizedSchema=normalizeRuntimeSchemaSettings(schema);const definitions=normalizedSchema.statuses.map((definition,index)=>normalizeRuntimeStatusDefinition(definition,index)).filter(definition=>definition!==null);const{aliasToId,byId}=buildRuntimeStatusIndexes(definitions);const{activeStatuses,blockedStatuses,draftStatuses,terminalCanceledStatuses,terminalDoneStatuses,terminalStatuses}=buildRuntimeStatusRoleSets(definitions);const workflow=normalizedSchema.workflow;const openStatus=normalizeStatusId(workflow.open_status)??preferredStatusForRole(definitions,"default_open",["open","in_progress",STATUS_VALUES[0]]);const inProgressStatus=normalizeStatusId(workflow.in_progress_status)??preferredStatusForRole(definitions,"active",["in_progress","in-progress",openStatus],true);const blockedStatus=normalizeStatusId(workflow.blocked_status)??preferredStatusForRole(definitions,"blocked",["blocked"]);const closeStatus=normalizeStatusId(workflow.close_status)??preferredStatusForRole(definitions,"default_close",["closed","done","complete"]);const canceledStatus=normalizeStatusId(workflow.canceled_status)??preferredStatusForRole(definitions,"default_cancel",["canceled","cancelled"]);return{definitions,by_id:byId,alias_to_id:aliasToId,terminal_statuses:terminalStatuses,terminal_done_statuses:terminalDoneStatuses,terminal_canceled_statuses:terminalCanceledStatuses,active_statuses:activeStatuses,blocked_statuses:blockedStatuses,draft_statuses:draftStatuses,open_status:openStatus,in_progress_status:inProgressStatus,blocked_status:blockedStatus,close_status:closeStatus,canceled_status:canceledStatus}}function normalizeStatusInputWithRegistry(value,registry){const normalized=normalizeStatusToken(value);if(!normalized){return void 0}return registry.alias_to_id.get(normalized)}function resolveRuntimeFieldRegistry(schema){const normalizedSchema=normalizeRuntimeSchemaSettings(schema);const dedupedByKey=new Map;const normalizedFields=normalizedSchema.fields.map(definition=>normalizeRuntimeFieldDefinition(definition)).filter(definition=>definition!==null);for(const normalized of normalizedFields){dedupedByKey.set(normalized.key,normalized)}const definitions=[...dedupedByKey.values()].sort((left,right)=>left.key.localeCompare(right.key));const byKey=new Map;const byCliToken=new Map;const commandToFields=new Map;for(const definition of definitions){byKey.set(definition.key,definition);byCliToken.set(definition.cli_flag,definition);for(const alias of definition.cli_aliases){byCliToken.set(alias,definition)}for(const command of definition.commands){const existing=commandToFields.get(command)??[];existing.push(definition);commandToFields.set(command,existing)}}for(const[command,fieldDefinitions]of commandToFields.entries()){fieldDefinitions.sort((left,right)=>left.key.localeCompare(right.key));commandToFields.set(command,fieldDefinitions)}return{definitions,by_key:byKey,by_cli_token:byCliToken,command_to_fields:commandToFields}}function runtimeFieldOptionTarget(field){return toCamelCase(field.key)}function statusIsTerminal(status,registry){const normalized=normalizeStatusInputWithRegistry(status,registry);if(!normalized){return false}return registry.terminal_statuses.has(normalized)}export{DEFAULT_RUNTIME_SCHEMA_FILE_PATHS,DEFAULT_RUNTIME_STATUS_DEFINITIONS,DEFAULT_RUNTIME_WORKFLOW,ensureRuntimeSchemaFileScaffold,filePathForSchemaSection,loadRuntimeSchemaFromOptionalFiles,normalizeRuntimeSchemaSettings,normalizeStatusInputWithRegistry,resolveItemTypesFilePath,resolveRuntimeFieldRegistry,resolveRuntimeStatusRegistry,runtimeFieldOptionTarget,statusIsTerminal};
|
|
1
|
+
!(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]="5e083565-3e07-5fb3-81ce-c392feaa8630")}catch(e2){}})();import path from"node:path";import{pathExists,readFileIfExists}from"../fs/fs-utils.js";import{createFileAtomic}from"../fs/atomic-create.js";import{DEFAULT_STATUS_DEFINITIONS,DEFAULT_WORKFLOW_DEFINITION}from"../shared/constants.js";import{RUNTIME_FIELD_COMMAND_VALUES,RUNTIME_FIELD_TYPE_VALUES,RUNTIME_STATUS_ROLE_VALUES,RUNTIME_UNKNOWN_FIELD_POLICY_VALUES,STATUS_VALUES}from"../../types/index.js";import{normalizeStatusToken}from"./status-token.js";const DEFAULT_RUNTIME_SCHEMA_FILE_PATHS=Object.freeze({types:"schema/types.json",statuses:"schema/statuses.json",fields:"schema/fields.json",workflows:"schema/workflows.json"});const DEFAULT_RUNTIME_WORKFLOW=DEFAULT_WORKFLOW_DEFINITION;const DEFAULT_RUNTIME_STATUS_DEFINITIONS=DEFAULT_STATUS_DEFINITIONS;const DEFAULT_RUNTIME_FIELD_COMMANDS=["create","update"];const RUNTIME_STATUS_ROLE_SET=new Set(RUNTIME_STATUS_ROLE_VALUES);const RUNTIME_FIELD_TYPE_SET=new Set(RUNTIME_FIELD_TYPE_VALUES);const RUNTIME_FIELD_COMMAND_SET=new Set(RUNTIME_FIELD_COMMAND_VALUES);const RUNTIME_UNKNOWN_FIELD_POLICY_SET=new Set(RUNTIME_UNKNOWN_FIELD_POLICY_VALUES);const RUNTIME_FIELD_VALUE_TYPE_SET=new Set(["string","number","boolean","array","object"]);const MAX_RUNTIME_FIELD_VALUE_SCHEMA_DEPTH=16;function isPlainObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}const RUNTIME_FIELD_VALUE_SCHEMA_SHAPE_VALIDATORS=[schema=>schema.type===void 0||typeof schema.type==="string"&&RUNTIME_FIELD_VALUE_TYPE_SET.has(schema.type),schema=>!Object.hasOwn(schema,"const")||isStructuredJsonValue(schema.const),schema=>schema.enum===void 0||Array.isArray(schema.enum)&&schema.enum.every(entry=>isStructuredJsonValue(entry)),schema=>schema.min_length===void 0||Number.isInteger(schema.min_length)&&schema.min_length>=0,schema=>schema.min_items===void 0||Number.isInteger(schema.min_items)&&schema.min_items>=0,schema=>schema.format===void 0||schema.format==="date-time",schema=>schema.required===void 0||Array.isArray(schema.required)&&schema.required.every(entry=>typeof entry==="string"&&entry.length>0),schema=>schema.additional_properties===void 0||typeof schema.additional_properties==="boolean",schema=>schema.properties===void 0||isPlainObject(schema.properties),schema=>schema.one_of===void 0||Array.isArray(schema.one_of)&&schema.one_of.length>0];function isStructuredJsonValue(value,ancestors=new Set){if(value===null||typeof value==="string"||typeof value==="boolean"){return true}if(typeof value==="number")return Number.isFinite(value);if(typeof value!=="object"||ancestors.has(value))return false;ancestors.add(value);const valid=Array.isArray(value)?value.every(entry=>isStructuredJsonValue(entry,ancestors)):Object.values(value).every(entry=>isStructuredJsonValue(entry,ancestors));ancestors.delete(value);return valid}function normalizeRuntimeFieldValueSchema(value,depth=0,ancestors=new Set){if(!isPlainObject(value)||depth>MAX_RUNTIME_FIELD_VALUE_SCHEMA_DEPTH||ancestors.has(value)){return void 0}ancestors.add(value);const schema=value;const type=schema.type;const enumValues=schema.enum;const oneOf=schema.one_of;const properties=schema.properties;const items=schema.items;const required=schema.required;const minLength=schema.min_length;const minItems=schema.min_items;const format=schema.format;const additionalProperties=schema.additional_properties;if(!RUNTIME_FIELD_VALUE_SCHEMA_SHAPE_VALIDATORS.every(check=>check(schema))){ancestors.delete(value);return void 0}const normalizedProperties=properties===void 0?void 0:Object.fromEntries(Object.entries(properties).map(([key,entry])=>[key,normalizeRuntimeFieldValueSchema(entry,depth+1,ancestors)]));const normalizedItems=items===void 0?void 0:normalizeRuntimeFieldValueSchema(items,depth+1,ancestors);const normalizedOneOf=oneOf===void 0?void 0:oneOf.map(entry=>normalizeRuntimeFieldValueSchema(entry,depth+1,ancestors));const normalizedNestedSchemas=[...Object.values(normalizedProperties??{}),...items===void 0?[]:[normalizedItems],...normalizedOneOf??[]];if(normalizedNestedSchemas.some(entry=>entry===void 0)){ancestors.delete(value);return void 0}ancestors.delete(value);return Object.fromEntries(Object.entries({type,const:Object.hasOwn(schema,"const")?schema.const:void 0,enum:enumValues,min_length:minLength,min_items:minItems,format,properties:normalizedProperties,required:required===void 0?void 0:[...new Set(required)],additional_properties:additionalProperties,items:normalizedItems,one_of:normalizedOneOf}).filter(([,entry])=>entry!==void 0))}function normalizeStringList(values){const candidates=Array.isArray(values)?values:[];return[...new Set(candidates.map(value=>typeof value==="string"?value.trim():"").filter(value=>value.length>0))].sort((left,right)=>left.localeCompare(right))}function normalizeStatusId(value){if(typeof value!=="string"||value.length===0){return void 0}const normalized=normalizeStatusToken(value);return normalized.length>0?normalized:void 0}function stripFlagPrefix(value){return value.startsWith("--")?value.slice(2):value}function normalizeCliToken(value){return typeof value==="string"?stripFlagPrefix(value.trim().toLowerCase().replaceAll(/[\s_]+/g,"-")):""}function keyToDefaultCliFlag(value){return value.replaceAll("_","-")}function toCamelCase(input){const segments=input.replaceAll(/[^A-Za-z0-9]+/g," ").trim().split(/\s+/).filter(segment=>segment.length>0).map(segment=>segment.toLowerCase());if(segments.length===0){return input}const[first,...rest]=segments;return`${first}${rest.map(segment=>`${segment.slice(0,1).toUpperCase()}${segment.slice(1)}`).join("")}`}function normalizeRuntimeStatusDefinition(definition,fallbackOrder){const id=normalizeStatusId(definition.id);if(!id){return null}const aliases=[...new Set(normalizeStringList(definition.aliases).map(normalizeStatusToken).filter(value=>value.length>0))].sort((left,right)=>left.localeCompare(right));const roles=normalizeStringList(definition.roles).filter(value=>RUNTIME_STATUS_ROLE_SET.has(value));const description=definition.description?.trim();const order=typeof definition.order==="number"&&Number.isFinite(definition.order)?definition.order:fallbackOrder;return{id,aliases,roles,description:description&&description.length>0?description:void 0,order}}function normalizeRuntimeWorkflow(workflow){return{draft_status:normalizeStatusId(workflow?.draft_status),open_status:normalizeStatusId(workflow?.open_status),in_progress_status:normalizeStatusId(workflow?.in_progress_status),blocked_status:normalizeStatusId(workflow?.blocked_status),close_status:normalizeStatusId(workflow?.close_status),canceled_status:normalizeStatusId(workflow?.canceled_status)}}function appendTypeWorkflowPair(record,pair){if(!Array.isArray(pair)||pair.length!==2){return}const from=normalizeStatusToken(pair[0]);const to=normalizeStatusToken(pair[1]);if(from.length===0||to.length===0){return}if(record.pairs.some(candidate=>candidate[0]===from&&candidate[1]===to)){return}record.pairs.push([from,to])}function normalizedTypeWorkflowEntry(entry){const rawType=typeof entry?.type==="string"?entry.type.trim():"";if(rawType.length===0||!Array.isArray(entry?.allowed_transitions)){return null}const record={type:rawType,pairs:[],denyAll:entry.allowed_transitions.length===0};for(const pair of entry.allowed_transitions){appendTypeWorkflowPair(record,pair)}return{typeKey:rawType.toLowerCase(),record}}function normalizeTypeWorkflowDefinitions(workflows){if(!Array.isArray(workflows)||workflows.length===0){return void 0}const byTypeKey=new Map;for(const entry of workflows){const normalized2=normalizedTypeWorkflowEntry(entry);if(normalized2===null){continue}const record=byTypeKey.get(normalized2.typeKey)??normalized2.record;record.denyAll||=normalized2.record.denyAll;for(const pair of normalized2.record.pairs){appendTypeWorkflowPair(record,pair)}byTypeKey.set(normalized2.typeKey,record)}const normalized=[];for(const record of byTypeKey.values()){if(record.pairs.length>0||record.denyAll){normalized.push({type:record.type,allowed_transitions:record.pairs})}}normalized.sort((left,right)=>left.type.localeCompare(right.type));return normalized.length>0?normalized:void 0}function normalizeRuntimeFieldDefinition(definition){const key=normalizeStatusToken(definition.key??"");if(!key){return null}const metadataKey=normalizeStatusToken(definition.metadata_key??definition.front_matter_key??key);const cliFlag=normalizeCliToken(definition.cli_flag??keyToDefaultCliFlag(key));if(!cliFlag){return null}const cliAliases=normalizeStringList(definition.cli_aliases).map(value=>normalizeCliToken(value)).filter(value=>value.length>0&&value!==cliFlag);const typeCandidate=typeof definition.type==="string"?definition.type.trim().toLowerCase():"string";const type=RUNTIME_FIELD_TYPE_SET.has(typeCandidate)?typeCandidate:"string";const commands=(()=>{const normalized=normalizeStringList(definition.commands).filter(value=>RUNTIME_FIELD_COMMAND_SET.has(value));if(normalized.length>0){return normalized}return[...DEFAULT_RUNTIME_FIELD_COMMANDS]})();const description=definition.description?.trim();const requiredTypes=normalizeStringList(definition.required_types);const valueSchema=definition.value_schema===void 0?void 0:normalizeRuntimeFieldValueSchema(definition.value_schema);if(definition.value_schema!==void 0&&valueSchema===void 0){return null}return{key,metadata_key:metadataKey,cli_flag:cliFlag,cli_aliases:cliAliases,description:description&&description.length>0?description:void 0,type,commands,repeatable:[definition.repeatable===true,type==="string_array"].includes(true),required:definition.required===true,required_on_create:definition.required_on_create===true,required_types:requiredTypes,allow_unset:definition.allow_unset!==false,value_schema:valueSchema}}function normalizeRuntimeStatusDefinitions(statusesSource){const dedupedById=new Map;for(const[index,definition]of statusesSource.entries()){const normalized=normalizeRuntimeStatusDefinition(definition,index);if(normalized){dedupedById.set(normalized.id,normalized)}}const values=sortRuntimeStatusDefinitions([...dedupedById.values()]);if(values.length>0){return values}return sortRuntimeStatusDefinitions(DEFAULT_RUNTIME_STATUS_DEFINITIONS.map((definition,index)=>normalizeRuntimeStatusDefinition(definition,index)).filter(definition=>definition!==null))}function sortRuntimeStatusDefinitions(definitions){return definitions.sort((left,right)=>left.order===right.order?left.id.localeCompare(right.id):left.order-right.order)}function normalizeRuntimeFieldDefinitions(fieldsSource){const dedupedByKey=new Map;for(const definition of fieldsSource??[]){const normalized=normalizeRuntimeFieldDefinition(definition);if(normalized){dedupedByKey.set(normalized.key,normalized)}}return[...dedupedByKey.values()].sort((left,right)=>left.key.localeCompare(right.key))}function serializeRuntimeStatusDefinition(definition){return{id:definition.id,aliases:definition.aliases.length>0?[...definition.aliases]:void 0,roles:definition.roles.length>0?[...definition.roles]:void 0,description:definition.description,order:definition.order}}function serializeRuntimeFieldDefinition(definition){return{key:definition.key,metadata_key:definition.metadata_key!==definition.key?definition.metadata_key:void 0,cli_flag:definition.cli_flag!==keyToDefaultCliFlag(definition.key)?definition.cli_flag:void 0,cli_aliases:definition.cli_aliases.length>0?[...definition.cli_aliases]:void 0,description:definition.description,type:definition.type,commands:[...definition.commands],repeatable:definition.repeatable===true?true:void 0,required:definition.required===true?true:void 0,required_on_create:definition.required_on_create===true?true:void 0,required_types:definition.required_types.length>0?[...definition.required_types]:void 0,allow_unset:definition.allow_unset===false?false:void 0,value_schema:definition.value_schema}}function normalizeUnknownFieldPolicy(policy){const candidate=typeof policy==="string"?policy.trim().toLowerCase():"allow";return RUNTIME_UNKNOWN_FIELD_POLICY_SET.has(candidate)?candidate:"allow"}function normalizeRuntimeSchemaSettings(schema){const files={...DEFAULT_RUNTIME_SCHEMA_FILE_PATHS,...schema?.files};const statusesSource=schema?.statuses&&schema.statuses.length>0?schema.statuses:DEFAULT_RUNTIME_STATUS_DEFINITIONS;const normalizedStatuses=normalizeRuntimeStatusDefinitions(statusesSource);const normalizedFields=normalizeRuntimeFieldDefinitions(schema?.fields);return{version:typeof schema?.version==="number"&&Number.isFinite(schema.version)?Math.floor(schema.version):1,files,statuses:normalizedStatuses.map(serializeRuntimeStatusDefinition),fields:normalizedFields.map(serializeRuntimeFieldDefinition),workflow:{...DEFAULT_RUNTIME_WORKFLOW,...normalizeRuntimeWorkflow(schema?.workflow)},type_workflows:normalizeTypeWorkflowDefinitions(schema?.type_workflows),unknown_field_policy:normalizeUnknownFieldPolicy(schema?.unknown_field_policy)}}function parseOptionalJson(raw,warningKey,warnings){try{return JSON.parse(raw)}catch{warnings.push(warningKey);return void 0}}function readTypeDefinitionsFromSchemaFile(parsed){if(Array.isArray(parsed)){return parsed}if(typeof parsed!=="object"||parsed===null){return void 0}const record=parsed;if(Array.isArray(record.definitions)){return record.definitions}if(typeof record.item_types==="object"&&record.item_types!==null){const itemTypesRecord=record.item_types;if(Array.isArray(itemTypesRecord.definitions)){return itemTypesRecord.definitions}}return void 0}function readStatusesFromSchemaFile(parsed){if(Array.isArray(parsed)){return parsed}if(typeof parsed!=="object"||parsed===null){return void 0}const record=parsed;if(Array.isArray(record.statuses)){return record.statuses}if(Array.isArray(record.definitions)){return record.definitions}return void 0}function readFieldsFromSchemaFile(parsed){if(Array.isArray(parsed)){return parsed}if(typeof parsed!=="object"||parsed===null){return void 0}const record=parsed;if(Array.isArray(record.fields)){return record.fields}if(Array.isArray(record.definitions)){return record.definitions}return void 0}function readWorkflowFromSchemaFile(parsed){if(typeof parsed!=="object"||parsed===null||Array.isArray(parsed)){return void 0}const record=parsed;if(typeof record.workflow==="object"&&record.workflow!==null&&!Array.isArray(record.workflow)){return record.workflow}if(typeof record.workflows==="object"&&record.workflows!==null&&!Array.isArray(record.workflows)){return record.workflows}return record}function readTypeWorkflowsFromSchemaFile(parsed){if(typeof parsed!=="object"||parsed===null||Array.isArray(parsed)){return void 0}const record=parsed;if(Array.isArray(record.type_workflows)){return record.type_workflows}return void 0}function filePathForSchemaSection(pmRoot,configuredPath,fallbackPath){const normalized=configuredPath?.trim()||fallbackPath;if(path.isAbsolute(normalized)){return normalized}return path.join(pmRoot,normalized)}function resolveItemTypesFilePath(pmRoot,schema){return filePathForSchemaSection(pmRoot,schema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types)}async function ensureRuntimeSchemaFileScaffold(pmRoot,schema){const normalizedSchema=normalizeRuntimeSchemaSettings(schema);const specs=[{path:filePathForSchemaSection(pmRoot,normalizedSchema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types),seed:{definitions:[]}},{path:filePathForSchemaSection(pmRoot,normalizedSchema.files.statuses,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.statuses),seed:{statuses:DEFAULT_RUNTIME_STATUS_DEFINITIONS}},{path:filePathForSchemaSection(pmRoot,normalizedSchema.files.fields,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.fields),seed:{fields:[]}},{path:filePathForSchemaSection(pmRoot,normalizedSchema.files.workflows,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.workflows),seed:{workflow:DEFAULT_RUNTIME_WORKFLOW}}];const createdPaths=[];for(const spec of specs){if(await pathExists(spec.path)){continue}if(await createFileAtomic(spec.path,`${JSON.stringify(spec.seed,null,2)}
|
|
2
|
+
`)){createdPaths.push(spec.path)}}return{created_paths:createdPaths}}async function loadRuntimeSchemaFromOptionalFiles(pmRoot,schema){const normalizedSchema=normalizeRuntimeSchemaSettings(schema);const warnings=[];const typeFilePath=filePathForSchemaSection(pmRoot,normalizedSchema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);const statusFilePath=filePathForSchemaSection(pmRoot,normalizedSchema.files.statuses,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.statuses);const fieldsFilePath=filePathForSchemaSection(pmRoot,normalizedSchema.files.fields,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.fields);const workflowsFilePath=filePathForSchemaSection(pmRoot,normalizedSchema.files.workflows,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.workflows);let loadedTypeDefinitions;let loadedStatuses;let loadedFields;let loadedWorkflow;let loadedTypeWorkflows;const readAndParse=async(targetPath,warningKey)=>{const raw=await readFileIfExists(targetPath);if(raw===null){return void 0}return parseOptionalJson(raw,warningKey,warnings)};const parsedTypes=await readAndParse(typeFilePath,"runtime_schema_types_invalid_json");if(parsedTypes!==void 0){loadedTypeDefinitions=readTypeDefinitionsFromSchemaFile(parsedTypes);if(loadedTypeDefinitions===void 0){warnings.push("runtime_schema_types_invalid_shape")}}const parsedStatuses=await readAndParse(statusFilePath,"runtime_schema_statuses_invalid_json");if(parsedStatuses!==void 0){loadedStatuses=readStatusesFromSchemaFile(parsedStatuses);if(loadedStatuses===void 0){warnings.push("runtime_schema_statuses_invalid_shape")}}const parsedFields=await readAndParse(fieldsFilePath,"runtime_schema_fields_invalid_json");if(parsedFields!==void 0){loadedFields=readFieldsFromSchemaFile(parsedFields);if(loadedFields===void 0){warnings.push("runtime_schema_fields_invalid_shape")}}const parsedWorkflow=await readAndParse(workflowsFilePath,"runtime_schema_workflows_invalid_json");if(parsedWorkflow!==void 0){loadedWorkflow=readWorkflowFromSchemaFile(parsedWorkflow);if(loadedWorkflow===void 0){warnings.push("runtime_schema_workflows_invalid_shape")}loadedTypeWorkflows=readTypeWorkflowsFromSchemaFile(parsedWorkflow)}const mergedSchema=normalizeRuntimeSchemaSettings({...normalizedSchema,statuses:[...normalizedSchema.statuses,...loadedStatuses??[]],fields:[...normalizedSchema.fields,...loadedFields??[]],workflow:{...normalizedSchema.workflow,...loadedWorkflow},type_workflows:[...normalizedSchema.type_workflows??[],...loadedTypeWorkflows??[]]});return{schema:mergedSchema,type_definitions_from_file:loadedTypeDefinitions,warnings,created_paths:[]}}function preferredStatusForRole(definitions,role,fallbackValues,fallbackFirst=false){const normalizedFallbacks=fallbackValues.map(value=>normalizeStatusId(value)).filter(value=>typeof value==="string");const fallbackMatch=normalizedFallbacks.find(normalized=>definitions.some(definition=>definition.id===normalized));if(fallbackFirst&&fallbackMatch!==void 0){return fallbackMatch}const withRole=definitions.find(definition=>definition.roles.includes(role));if(withRole!==void 0){return withRole.id}return fallbackMatch??definitions[0]?.id}function buildRuntimeStatusIndexes(definitions){const aliasToId=new Map;const byId=new Map;for(const definition of definitions){byId.set(definition.id,definition);aliasToId.set(definition.id,definition.id);aliasToId.set(definition.id.replaceAll("_","-"),definition.id);aliasToId.set(definition.id.replaceAll("_"," "),definition.id);for(const alias of definition.aliases){aliasToId.set(alias,definition.id);aliasToId.set(alias.replaceAll("_","-"),definition.id);aliasToId.set(alias.replaceAll("_"," "),definition.id)}}return{aliasToId,byId}}function buildRuntimeStatusRoleSets(definitions){const result={activeStatuses:new Set,blockedStatuses:new Set,draftStatuses:new Set,terminalCanceledStatuses:new Set,terminalDoneStatuses:new Set,terminalStatuses:new Set};for(const definition of definitions){const roles=new Set(definition.roles);if(roles.has("terminal")||roles.has("terminal_done")||roles.has("terminal_canceled")){result.terminalStatuses.add(definition.id)}if(roles.has("terminal_done"))result.terminalDoneStatuses.add(definition.id);if(roles.has("terminal_canceled")){result.terminalCanceledStatuses.add(definition.id)}if(roles.has("active"))result.activeStatuses.add(definition.id);if(roles.has("blocked"))result.blockedStatuses.add(definition.id);if(roles.has("draft"))result.draftStatuses.add(definition.id)}return result}function resolveRuntimeStatusRegistry(schema){const normalizedSchema=normalizeRuntimeSchemaSettings(schema);const definitions=normalizedSchema.statuses.map((definition,index)=>normalizeRuntimeStatusDefinition(definition,index)).filter(definition=>definition!==null);const{aliasToId,byId}=buildRuntimeStatusIndexes(definitions);const{activeStatuses,blockedStatuses,draftStatuses,terminalCanceledStatuses,terminalDoneStatuses,terminalStatuses}=buildRuntimeStatusRoleSets(definitions);const workflow=normalizedSchema.workflow;const openStatus=normalizeStatusId(workflow.open_status)??preferredStatusForRole(definitions,"default_open",["open","in_progress",STATUS_VALUES[0]]);const inProgressStatus=normalizeStatusId(workflow.in_progress_status)??preferredStatusForRole(definitions,"active",["in_progress","in-progress",openStatus],true);const blockedStatus=normalizeStatusId(workflow.blocked_status)??preferredStatusForRole(definitions,"blocked",["blocked"]);const closeStatus=normalizeStatusId(workflow.close_status)??preferredStatusForRole(definitions,"default_close",["closed","done","complete"]);const canceledStatus=normalizeStatusId(workflow.canceled_status)??preferredStatusForRole(definitions,"default_cancel",["canceled","cancelled"]);return{definitions,by_id:byId,alias_to_id:aliasToId,terminal_statuses:terminalStatuses,terminal_done_statuses:terminalDoneStatuses,terminal_canceled_statuses:terminalCanceledStatuses,active_statuses:activeStatuses,blocked_statuses:blockedStatuses,draft_statuses:draftStatuses,open_status:openStatus,in_progress_status:inProgressStatus,blocked_status:blockedStatus,close_status:closeStatus,canceled_status:canceledStatus}}function normalizeStatusInputWithRegistry(value,registry){const normalized=normalizeStatusToken(value);if(!normalized){return void 0}return registry.alias_to_id.get(normalized)}function resolveRuntimeFieldRegistry(schema){const normalizedSchema=normalizeRuntimeSchemaSettings(schema);const dedupedByKey=new Map;const normalizedFields=normalizedSchema.fields.map(definition=>normalizeRuntimeFieldDefinition(definition)).filter(definition=>definition!==null);for(const normalized of normalizedFields){dedupedByKey.set(normalized.key,normalized)}const definitions=[...dedupedByKey.values()].sort((left,right)=>left.key.localeCompare(right.key));const byKey=new Map;const byCliToken=new Map;const commandToFields=new Map;for(const definition of definitions){byKey.set(definition.key,definition);byCliToken.set(definition.cli_flag,definition);for(const alias of definition.cli_aliases){byCliToken.set(alias,definition)}for(const command of definition.commands){const existing=commandToFields.get(command)??[];existing.push(definition);commandToFields.set(command,existing)}}for(const[command,fieldDefinitions]of commandToFields.entries()){fieldDefinitions.sort((left,right)=>left.key.localeCompare(right.key));commandToFields.set(command,fieldDefinitions)}return{definitions,by_key:byKey,by_cli_token:byCliToken,command_to_fields:commandToFields}}function runtimeFieldOptionTarget(field){return toCamelCase(field.key)}function statusIsTerminal(status,registry){const normalized=normalizeStatusInputWithRegistry(status,registry);if(!normalized){return false}return registry.terminal_statuses.has(normalized)}export{DEFAULT_RUNTIME_SCHEMA_FILE_PATHS,DEFAULT_RUNTIME_STATUS_DEFINITIONS,DEFAULT_RUNTIME_WORKFLOW,ensureRuntimeSchemaFileScaffold,filePathForSchemaSection,loadRuntimeSchemaFromOptionalFiles,normalizeRuntimeSchemaSettings,normalizeStatusInputWithRegistry,resolveItemTypesFilePath,resolveRuntimeFieldRegistry,resolveRuntimeStatusRegistry,runtimeFieldOptionTarget,statusIsTerminal};
|
|
3
3
|
//# sourceMappingURL=runtime-schema.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!(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]="
|
|
1
|
+
!(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]="8192f2f3-b5a0-510e-a7d4-963041cce389")}catch(e2){}})();import{createHash}from"node:crypto";import{existsSync,promises as fs,readFileSync}from"node:fs";import path from"node:path";import{writeFileAtomic}from"../fs/fs-utils.js";import{acquireLock}from"../lock/lock.js";import{SETTINGS_DEFAULTS}from"../shared/constants.js";import{getRuntimePath}from"../store/paths.js";const SESSION_FILENAME="session.json";function isBoundedNonEmptyString(value,maximum){return typeof value==="string"&&value.length>0&&value.length<=maximum}function parseSemanticAttribution(value){if(value===null||typeof value!=="object"||Array.isArray(value)){return void 0}const record=value;const validRole=["implementer","planner","release-operator"].includes(String(record.role));const validConfidence=["high","medium"].includes(String(record.confidence));const validTopic=isBoundedNonEmptyString(record.topic,256);const validEvidence=Array.isArray(record.evidence)&&record.evidence.length<=32&&record.evidence.every(entry=>typeof entry==="string"&&entry.length<=128);const validActiveItems=Array.isArray(record.active_item_ids)&&record.active_item_ids.length<=64&&record.active_item_ids.every(entry=>isBoundedNonEmptyString(entry,128));const validFocus=record.focused_item_id===void 0||isBoundedNonEmptyString(record.focused_item_id,128);if(![validRole,validConfidence,validTopic,validEvidence,validActiveItems,validFocus,record.rule_version==="v2"].every(Boolean)){return void 0}return record}function parseSemanticAttributionMap(value){if(value===null||typeof value!=="object"||Array.isArray(value)){return void 0}const entries=Object.entries(value).slice(0,128).flatMap(([key,attribution])=>{const parsed=parseSemanticAttribution(attribution);return parsed&&key.length<=128?[[key,parsed]]:[]});return entries.length>0?Object.fromEntries(entries):void 0}function getSessionStatePath(pmRoot){return path.join(getRuntimePath(pmRoot),SESSION_FILENAME)}async function readSessionState(pmRoot){try{const raw=await fs.readFile(getSessionStatePath(pmRoot),"utf8");const parsed=JSON.parse(raw);if(parsed===null||typeof parsed!=="object"||Array.isArray(parsed)){return{}}const record=parsed;const focused=record.focused_item;const semanticAttribution=parseSemanticAttributionMap(record.semantic_attribution);if(typeof focused==="string"&&focused.trim().length>0){return{focused_item:focused,...semanticAttribution?{semantic_attribution:semanticAttribution}:{}}}return semanticAttribution?{semantic_attribution:semanticAttribution}:{}}catch{return{}}}async function mutateSessionState(pmRoot,mutate){const release=await acquireLock(pmRoot,"session-state",SETTINGS_DEFAULTS.locks.ttl_seconds,"session-state",false,true,SETTINGS_DEFAULTS.locks.wait_ms);try{const state=await readSessionState(pmRoot);mutate(state);const target=getSessionStatePath(pmRoot);await fs.mkdir(path.dirname(target),{recursive:true});await writeFileAtomic(target,JSON.stringify(state))}finally{await release()}}function semanticAttributionKey(principal){const instance=/#([a-f0-9]{24})$/u.exec(principal.trim())?.[1];return instance??`author-${createHash("sha256").update(principal).digest("hex").slice(0,24)}`}function normalizedEvidence(values){return[...new Set(values.map(value=>value.trim()).filter(Boolean))].slice(0,32).map(value=>value.slice(0,128))}function worksetTopic(activeItemIds){const ids=[...new Set(activeItemIds)].sort((left,right)=>left.localeCompare(right));if(ids.length===1)return ids[0];const complete=`workset:${ids.join("+")}`;if(complete.length<=256)return complete;const visible=ids.join("+").slice(0,230);return`workset:${visible}+${createHash("sha256").update(ids.join("\0")).digest("hex").slice(0,12)}`}async function updateSemanticAttribution(pmRoot,key,mutate){await mutateSessionState(pmRoot,state=>{const attributions={...state.semantic_attribution};const next=mutate(attributions[key]);if(next===void 0)delete attributions[key];else attributions[key]=next;if(Object.keys(attributions).length===0){delete state.semantic_attribution}else{state.semantic_attribution=attributions}})}async function recordClaimedWorkAttribution(params){const key=semanticAttributionKey(params.principal);await updateSemanticAttribution(params.pmRoot,key,current=>{const activeItemIds=[...new Set([...current?.active_item_ids??[],params.itemId])].slice(-64).sort((left,right)=>left.localeCompare(right));const focusedItemId=current?.focused_item_id;return{role:"implementer",topic:focusedItemId??worksetTopic(activeItemIds),confidence:focusedItemId?"high":"medium",rule_version:"v2",evidence:normalizedEvidence([...activeItemIds.map(id=>`claim:${id}`),...focusedItemId?[`focus:${focusedItemId}`]:[],...(params.lineageIds??[]).map(id=>`lineage:${id}`)]),active_item_ids:activeItemIds,...focusedItemId?{focused_item_id:focusedItemId}:{}}})}async function releaseClaimedWorkAttribution(params){const key=semanticAttributionKey(params.principal);await updateSemanticAttribution(params.pmRoot,key,current=>{if(!current)return void 0;const activeItemIds=current.active_item_ids.filter(id=>id!==params.itemId);if(activeItemIds.length===0&&!current.focused_item_id)return void 0;const focusedItemId=current.focused_item_id;return{...current,role:"release-operator",topic:focusedItemId??worksetTopic(activeItemIds),confidence:focusedItemId?"high":"medium",evidence:normalizedEvidence([...activeItemIds.map(id=>`claim:${id}`),...focusedItemId?[`focus:${focusedItemId}`]:[],`release:${params.itemId}`]),active_item_ids:activeItemIds}})}async function recordFocusedWorkAttribution(params){const key=semanticAttributionKey(params.principal);await updateSemanticAttribution(params.pmRoot,key,current=>{const activeItemIds=current?.active_item_ids??[];if(!params.itemId&&activeItemIds.length===0)return void 0;const focusedItemId=params.itemId;return{role:focusedItemId?"planner":current.role,topic:focusedItemId??worksetTopic(activeItemIds),confidence:focusedItemId?"high":"medium",rule_version:"v2",evidence:normalizedEvidence([...activeItemIds.map(id=>`claim:${id}`),...focusedItemId?[`focus:${focusedItemId}`]:[],...(params.lineageIds??[]).map(id=>`lineage:${id}`)]),active_item_ids:activeItemIds,...focusedItemId?{focused_item_id:focusedItemId}:{}}})}function resolveAttributionRoot(cwd,env){const configured=env.PM_PATH?.trim();if(configured){const resolved=path.resolve(cwd,configured);if(existsSync(path.join(resolved,"settings.json")))return resolved;const nested=path.join(resolved,".agents","pm");if(existsSync(path.join(nested,"settings.json")))return nested}let cursor=path.resolve(cwd);for(let depth=0;depth<32;depth+=1){const candidate=path.join(cursor,".agents","pm");if(existsSync(path.join(candidate,"settings.json")))return candidate;const parent=path.dirname(cursor);if(parent===cursor)break;cursor=parent}return void 0}function readAgentSemanticAttributionSync(params){if(!params.key)return void 0;const pmRoot=resolveAttributionRoot(params.cwd,params.env);if(!pmRoot)return void 0;try{const parsed=JSON.parse(readFileSync(getSessionStatePath(pmRoot),"utf8"));return parseSemanticAttribution(parsed.semantic_attribution?.[params.key])}catch{return void 0}}async function getFocusedItem(pmRoot){const state=await readSessionState(pmRoot);return state.focused_item}async function setFocusedItem(pmRoot,id){await mutateSessionState(pmRoot,state=>{state.focused_item=id})}async function clearFocusedItem(pmRoot){await mutateSessionState(pmRoot,state=>{delete state.focused_item})}export{clearFocusedItem,getFocusedItem,getSessionStatePath,readAgentSemanticAttributionSync,readSessionState,recordClaimedWorkAttribution,recordFocusedWorkAttribution,releaseClaimedWorkAttribution,semanticAttributionKey,setFocusedItem};
|
|
2
2
|
//# sourceMappingURL=session-state.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preserve concurrent edits to untouched leaves. Arrays and scalar values are
|
|
3
|
+
* indivisible: incompatible edits to the same leaf refuse the entire write.
|
|
4
|
+
* The root must remain an object even for an unchanged snapshot. Error receipts
|
|
5
|
+
* contain a key path, never the potentially secret values.
|
|
6
|
+
*/
|
|
7
|
+
export declare function reconcileSettingsSnapshot(baseline: unknown, proposed: unknown, current: unknown, segments?: readonly string[]): unknown;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!(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]="e2270ad2-349e-5e8c-b23c-3cf0645907dc")}catch(e2){}})();import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{stableValueEquals}from"../shared/serialization.js";function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function reconcileSettingsSnapshot(baseline,proposed,current,segments=[]){if(stableValueEquals(baseline,proposed)&&(segments.length>0||isRecord(current)))return current;if(stableValueEquals(baseline,current)||stableValueEquals(proposed,current)){return proposed}if((baseline===void 0||isRecord(baseline))&&isRecord(proposed)&&isRecord(current)){const before=baseline??{};const keys=new Set([...Object.keys(before),...Object.keys(proposed),...Object.keys(current)]);return Object.fromEntries([...keys].flatMap(key=>{const merged=reconcileSettingsSnapshot(Object.hasOwn(before,key)?before[key]:void 0,Object.hasOwn(proposed,key)?proposed[key]:void 0,Object.hasOwn(current,key)?current[key]:void 0,[...segments,key]);return merged===void 0?[]:[[key,merged]]}))}throw new PmCliError(`Settings changed concurrently at ${segments.join(".")||"<root>"}; read the latest settings and reapply the intended change.`,EXIT_CODE.CONFLICT,{reason:"stale_settings_snapshot",required:"Read a fresh settings snapshot and reapply the intended change.",why:"Another writer changed the same setting after this snapshot was read.",examples:["pm config project export --json"],nextSteps:["Read the current settings, then retry the original config operation."]})}export{reconcileSettingsSnapshot};
|
|
2
|
+
//# sourceMappingURL=settings-concurrency.js.map
|
|
@@ -8,6 +8,8 @@ import { collectSettingsReadCacheSignatures } from "./settings-read-cache.js";
|
|
|
8
8
|
import type { ExtensionGovernancePolicy, PmMaxVersionExceededModeSetting } from "../extensions/extension-types.js";
|
|
9
9
|
import type { ExtensionSandboxProfile, ExtensionPolicyMode, ExtensionPolicyOverrideSettings, ExtensionTrustMode, GovernanceSettings, ItemTypeDefinition, PmSettings, ValidateMetadataRequiredField } from "../../types/index.js";
|
|
10
10
|
interface SettingsPersistSourceSnapshot {
|
|
11
|
+
/** Last sparse state proposed by this instance, independent of peer edits. */
|
|
12
|
+
persisted_settings: unknown;
|
|
11
13
|
source_settings: ParsedSettings;
|
|
12
14
|
has_source_item_type_definitions: boolean;
|
|
13
15
|
source_item_type_definitions: ItemTypeDefinition[];
|
|
@@ -85,7 +87,12 @@ export declare function serializeSettings(settings: PmSettings, options?: Serial
|
|
|
85
87
|
export declare function readSettingsWithMetadata(pmRoot: string): Promise<SettingsReadResult>;
|
|
86
88
|
/** Implements read settings for the public runtime surface of this module. */
|
|
87
89
|
export declare function readSettings(pmRoot: string): Promise<PmSettings>;
|
|
88
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Persist edits to a readSettings snapshot under the workspace-history lock.
|
|
92
|
+
* Disjoint concurrent edits survive; overlapping stale edits fail before any
|
|
93
|
+
* write. Caller-constructed settings without a read snapshot replace the whole
|
|
94
|
+
* document. History append failures compensate the document before unlocking.
|
|
95
|
+
*/
|
|
89
96
|
export declare function writeSettings(pmRoot: string, settings: PmSettings, op?: string): Promise<void>;
|
|
90
97
|
/** Public contract for settings store test only, shared by SDK and presentation-layer consumers. */
|
|
91
98
|
export declare const settingsStoreTestOnly: {
|