@unbrained/pm-cli 2026.10.7 → 2026.10.9
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 +32 -0
- package/dist/cli/register-list-query.js +2 -2
- package/dist/cli-bundle/bundle-manifest.json +154 -154
- package/dist/cli-bundle/chunks/{chunk-DWH555SN.js → chunk-55MK3QQM.js} +30 -30
- package/dist/cli-bundle/chunks/chunk-5MOFELIF.js +3 -0
- package/dist/cli-bundle/chunks/{chunk-TON7H63A.js → chunk-5NR6TDYB.js} +53 -52
- package/dist/cli-bundle/chunks/chunk-5TCQ5J3V.js +234 -0
- package/dist/cli-bundle/chunks/{chunk-TG3IOQUG.js → chunk-CPZOW6L2.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-E4XR5LKU.js +8 -0
- package/dist/cli-bundle/chunks/{chunk-MOXX7D3F.js → chunk-KOGF6O6W.js} +3 -3
- package/dist/cli-bundle/chunks/chunk-N7GKWO4G.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-VU77O6HC.js → chunk-NIF7JOPW.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-N2PFAWVV.js → chunk-P5NS7EFC.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-A4QWRU7D.js → chunk-QQHNXCO3.js} +5 -5
- package/dist/cli-bundle/chunks/chunk-XW3BLWFF.js +20 -0
- package/dist/cli-bundle/chunks/chunk-ZNXRGATT.js +2 -0
- package/dist/cli-bundle/chunks/register-list-query-2YOWMNWY.js +11 -0
- package/dist/cli-bundle/chunks/{register-mutation-JRH6EGSE.js → register-mutation-ILOWFMTV.js} +2 -2
- package/dist/cli-bundle/chunks/register-operations-BMK65YM3.js +2 -0
- package/dist/cli-bundle/chunks/register-setup-24TFFK6N.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-7X3QD5V4.js → chunk-2ATAD56F.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-PBNQZV33.js → chunk-2CJWTLQG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-XIGFEA3W.js → chunk-362645PL.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-4FKCHJGV.js → chunk-AU6VJGTY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-QY4Z23QC.js → chunk-B3YW6H2I.js} +17 -21
- package/dist/cli-bundle/focused-chunks/{chunk-3NSZ5C4A.js → chunk-DMSADMEU.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-DSLNUL2Q.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-EPOCI7ZX.js → chunk-EZ4367G4.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FWWFCLDM.js → chunk-IARAEFMA.js} +60 -59
- package/dist/cli-bundle/focused-chunks/{chunk-SIR5RFJX.js → chunk-MCVWZUGK.js} +27 -27
- package/dist/cli-bundle/focused-chunks/chunk-PBCYGO7X.js +3 -0
- package/dist/cli-bundle/focused-chunks/{chunk-NRSA5ZB2.js → chunk-PLTTMQAW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-HMG5F5EC.js → chunk-SAN3KPX4.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-3BKRCR57.js → chunk-W5AE7GKZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-QEYEDXRI.js → chunk-WAOXID5J.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2YICTWWA.js → chunk-WOEZJUA2.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 +1 -1
- package/dist/cli-bundle/sdk-core.js +22 -22
- 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 +51 -50
- 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 +7 -7
- package/dist/core/extensions/item-fields.d.ts +6 -1
- package/dist/core/extensions/item-fields.js +1 -1
- package/dist/core/fs/fs-utils.d.ts +19 -4
- package/dist/core/fs/fs-utils.js +2 -2
- package/dist/core/history/event-index.d.ts +1 -2
- package/dist/core/history/event-index.js +2 -2
- package/dist/core/lock/lock.d.ts +9 -2
- package/dist/core/lock/lock.js +2 -2
- package/dist/core/output/output.d.ts +16 -14
- package/dist/core/output/output.js +6 -10
- package/dist/core/store/item-metadata-query-index.d.ts +1 -2
- package/dist/core/store/item-metadata-query-index.js +1 -1
- package/dist/core/store/settings.js +2 -2
- package/dist/core/store/sqlite-runtime.d.ts +15 -0
- package/dist/core/store/sqlite-runtime.js +2 -0
- package/dist/core/telemetry/runtime.d.ts +1 -1
- package/dist/core/telemetry/runtime.js +4 -4
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
- package/dist/sdk/governance/health.js +2 -2
- package/dist/sdk/history-repair.js +1 -1
- package/dist/sdk/item-transaction.js +1 -1
- package/dist/sdk/merge/abandoned-receipts.js +1 -1
- package/dist/sdk/merge/driver.js +1 -1
- package/dist/sdk/merge/install.js +3 -2
- package/dist/sdk/merge/receipt-operation.d.ts +5 -5
- package/dist/sdk/merge/receipt-operation.js +1 -1
- package/dist/sdk/merge/receipts.d.ts +1 -1
- package/dist/sdk/merge/receipts.js +3 -3
- package/dist/sdk/merge/worktree-config.d.ts +2 -0
- package/dist/sdk/merge/worktree-config.js +1 -1
- package/dist/sdk/output/table-rows.d.ts +37 -0
- package/dist/sdk/output/table-rows.js +2 -0
- package/dist/sdk/output.d.ts +1 -0
- package/dist/sdk/output.js +2 -2
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/read-output-contracts.d.ts +3 -3
- package/dist/sdk/read-output-contracts.js +1 -1
- package/dist/sdk/test/workspace-snapshot.d.ts +1 -1
- package/dist/sdk/test/workspace-snapshot.js +1 -1
- package/docs/AGENT_OUTPUT_ENCODINGS.md +119 -0
- package/docs/BUILD_AND_RELEASE_ACCEPTANCE.md +36 -100
- package/docs/MERGE_SAFETY.md +61 -6
- package/docs/PACKAGE_GATE_ACCEPTANCE.md +56 -0
- package/docs/PACKED_FIRST_RUN.md +26 -42
- package/docs/README.md +3 -0
- package/docs/SDK_AUDITED_MUTATIONS.md +18 -0
- package/docs/SDK_STORAGE_LIFECYCLE.md +35 -0
- package/docs/TESTING.md +11 -3
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
- package/marketplace.json +2 -2
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-claude/package.json +2 -2
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/package.json +2 -2
- package/plugins/pm-codex/plugin.json +1 -1
- package/runtime-dependencies.json +2 -2
- package/dist/cli-bundle/chunks/chunk-754AV3DC.js +0 -8
- package/dist/cli-bundle/chunks/chunk-CEM35QB2.js +0 -2
- package/dist/cli-bundle/chunks/chunk-CMIU2NDK.js +0 -20
- package/dist/cli-bundle/chunks/chunk-GJ2OJKRM.js +0 -238
- package/dist/cli-bundle/chunks/chunk-GSQK3VUT.js +0 -2
- package/dist/cli-bundle/chunks/chunk-WUOFG4JY.js +0 -3
- package/dist/cli-bundle/chunks/register-list-query-CBJELTDX.js +0 -11
- package/dist/cli-bundle/chunks/register-operations-FYV7CUBF.js +0 -2
- package/dist/cli-bundle/chunks/register-setup-M5VO6JUH.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3RJ4VK7U.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-H5VREEUE.js +0 -20
|
@@ -8,7 +8,12 @@ import type { ExtensionRegistrationRegistry } from "./loader.js";
|
|
|
8
8
|
export declare const RESERVED_ITEM_FIELD_NAMES: ReadonlySet<string>;
|
|
9
9
|
/** Implements collect registered item field names for the public runtime surface of this module. */
|
|
10
10
|
export declare function collectRegisteredItemFieldNames(registrations: ExtensionRegistrationRegistry | null): string[];
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Parse typed assignments using active extension declarations into a new object.
|
|
13
|
+
* Reserved keys name their dedicated core flags; unknown keys identify the
|
|
14
|
+
* rejected input separately from legal registered keys. Parsing never writes
|
|
15
|
+
* tracker state, so a failed assignment cannot persist partial metadata.
|
|
16
|
+
*/
|
|
12
17
|
export declare function parseRegisteredItemFieldAssignments(rawFields: string[] | undefined, registrations: ExtensionRegistrationRegistry | null): Record<string, unknown>;
|
|
13
18
|
/** Implements apply registered item field defaults and validation for the public runtime surface of this module. */
|
|
14
19
|
export declare function applyRegisteredItemFieldDefaultsAndValidation(itemMetadata: Record<string, unknown>, registrations: ExtensionRegistrationRegistry | null, options?: {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3b307f5a-3d23-5463-b90c-efbc4febe5dd")}catch{}})();import{normalizeItemFieldType}from"./item-field-types.js";import{EXIT_CODE,ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";const reservedItemFieldNames=new Set(ITEM_METADATA_KEY_ORDER),RESERVED_ITEM_FIELD_NAMES=Object.freeze({get size(){return reservedItemFieldNames.size},has(value){return reservedItemFieldNames.has(value)},entries(){return reservedItemFieldNames.entries()},keys(){return reservedItemFieldNames.keys()},values(){return reservedItemFieldNames.values()},forEach(callback,thisArg){reservedItemFieldNames.forEach(value=>callback.call(thisArg,value,value,RESERVED_ITEM_FIELD_NAMES))},[Symbol.iterator](){return reservedItemFieldNames.values()}});function normalizeFieldName(value){if(typeof value!="string")return null;const normalized=value.trim();return normalized.length>0?normalized:null}function normalizeFieldType(value){return typeof value!="string"?null:normalizeItemFieldType(value)}function cloneFieldValue(value){try{return structuredClone(value)}catch{return value}}function parseFieldAssignment(raw){const trimmed=raw.trim(),separatorIndex=trimmed.indexOf("=");if(separatorIndex<=0)throw new PmCliError(`--field entries must use name=value syntax, received: ${raw}`,EXIT_CODE.USAGE);const key=trimmed.slice(0,separatorIndex).trim(),value=trimmed.slice(separatorIndex+1);return{key,value}}function parseJsonFieldValue(raw,fieldName,expectedType){try{const parsed=JSON.parse(raw);if(expectedType==="array"&&Array.isArray(parsed)||expectedType==="object"&&typeof parsed=="object"&&parsed!==null&&!Array.isArray(parsed))return parsed}catch{}throw new PmCliError(`--field ${fieldName}=... must be valid JSON ${expectedType}`,EXIT_CODE.USAGE)}function coerceRegisteredFieldValue(fieldName,fieldType,raw){if(fieldType==="string")return raw;if(fieldType==="number"){const trimmed=raw.trim();if(trimmed.length===0)throw new PmCliError(`--field ${fieldName}=... must be a number`,EXIT_CODE.USAGE);const parsed=Number(trimmed);if(!Number.isFinite(parsed))throw new PmCliError(`--field ${fieldName}=... must be a number`,EXIT_CODE.USAGE);return parsed}if(fieldType==="boolean"){const normalized=raw.trim().toLowerCase();if(normalized==="true"||normalized==="1"||normalized==="yes")return!0;if(normalized==="false"||normalized==="0"||normalized==="no")return!1;throw new PmCliError(`--field ${fieldName}=... must be one of true|false|1|0|yes|no`,EXIT_CODE.USAGE)}return fieldType==="string_array"?raw.split(/[\n,|]/u).map(value=>value.trim()).filter(value=>value.length>0):parseJsonFieldValue(raw,fieldName,fieldType)}function collectRegisteredFieldDefinitions(registrations){const definitions=new Map;if(!registrations)return definitions;for(const registration of registrations.item_fields)for(const definition of registration.fields){const fieldName=normalizeFieldName(definition.name),fieldType=normalizeFieldType(definition.type);if(!fieldName||!fieldType)continue;const existing=definitions.get(fieldName);if(existing&&existing.type!==fieldType)throw new PmCliError(`Extension item field "${fieldName}" is declared with conflicting types: ${existing.type}, ${fieldType}`,EXIT_CODE.USAGE,{code:"extension_item_field_type_conflict",nextSteps:["Make every active extension declaration for this field use the same type."]});definitions.set(fieldName,{name:fieldName,type:fieldType})}return definitions}function assertNotReservedItemFieldName(fieldName){if(RESERVED_ITEM_FIELD_NAMES.has(fieldName))throw new PmCliError(`Extension item field "${fieldName}" collides with built-in item metadata "${fieldName}"; rename the extension field with an extension-specific prefix. Reserved fields: ${[...RESERVED_ITEM_FIELD_NAMES].sort((left,right)=>left.localeCompare(right)).join(", ")}.`,EXIT_CODE.USAGE,{code:"extension_item_field_reserved",nextSteps:["Rename the extension item field, preferably with an extension-specific prefix."]})}function collectRegisteredItemFieldNames(registrations){return[...collectRegisteredFieldDefinitions(registrations).keys()].sort((left,right)=>left.localeCompare(right))}function parseRegisteredItemFieldAssignments(rawFields,registrations){if(!rawFields||rawFields.length===0)return{};const definitions=collectRegisteredFieldDefinitions(registrations),values={};for(const raw of rawFields){const{key,value}=parseFieldAssignment(raw),definition=definitions.get(key);if(!definition){if(RESERVED_ITEM_FIELD_NAMES.has(key)){const flag=`--${key.replaceAll("_","-")}`;throw new PmCliError(`--field ${key} is a core item field, not an extension field`,EXIT_CODE.USAGE,{code:"core_item_field_requires_dedicated_flag",field:key,recovery:{provided_fields:[key],suggested_flags:[flag]},nextSteps:[`Set the core field with its dedicated flag: pm update <id> ${flag} <value>`,`When closing an item, pm close <id> also accepts ${flag} <value>.`]})}const known=[...definitions.keys()].sort((left,right)=>left.localeCompare(right));throw new PmCliError(`--field ${key} is not declared by an active extension item-field registration`,EXIT_CODE.USAGE,{code:"extension_item_field_unknown",field:key,recovery:{provided_fields:[key]},nextSteps:known.length>0?[`Use one of the declared fields: ${known.join(", ")}`]:["Activate an extension that calls registerItemFields before setting extension fields."]})}assertNotReservedItemFieldName(definition.name),values[definition.name]=coerceRegisteredFieldValue(definition.name,definition.type,value)}return values}function isValidFieldType(value,expectedType){return expectedType==="string"?typeof value=="string":expectedType==="number"?typeof value=="number"&&Number.isFinite(value):expectedType==="boolean"?typeof value=="boolean":expectedType==="array"?Array.isArray(value):expectedType==="string_array"?Array.isArray(value)&&value.every(entry=>typeof entry=="string"):typeof value=="object"&&value!==null&&!Array.isArray(value)}function isAllowedFieldValue(value,allowed){return!allowed||allowed.length===0?!0:allowed.some(candidate=>Object.is(candidate,value))}function applyRegisteredItemFieldDefaultsAndValidation(itemMetadata,registrations,options={}){if(registrations){collectRegisteredFieldDefinitions(registrations);for(const registration of registrations.item_fields)for(const definition of registration.fields){const fieldName=normalizeFieldName(definition.name);if(!fieldName)continue;assertNotReservedItemFieldName(fieldName),!(fieldName in itemMetadata)&&!options.skipDefaultFields?.has(fieldName)&&Object.prototype.hasOwnProperty.call(definition,"default")&&(itemMetadata[fieldName]=cloneFieldValue(definition.default));const currentValue=itemMetadata[fieldName];if(currentValue===void 0)continue;const expectedType=normalizeFieldType(definition.type);if(expectedType&&!isValidFieldType(currentValue,expectedType))throw new TypeError(`Item field "${fieldName}" must be of type ${expectedType}`);const allowedValues=Array.isArray(definition.values)?definition.values:void 0;if(!isAllowedFieldValue(currentValue,allowedValues))throw new TypeError(`Item field "${fieldName}" must match one of the configured allowed values`)}}}export{RESERVED_ITEM_FIELD_NAMES,applyRegisteredItemFieldDefaultsAndValidation,collectRegisteredItemFieldNames,parseRegisteredItemFieldAssignments};
|
|
2
2
|
//# sourceMappingURL=item-fields.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PmCliError } from "../shared/errors.js";
|
|
1
2
|
/** Implements ensure dir for the public runtime surface of this module. */
|
|
2
3
|
export declare function ensureDir(dirPath: string): Promise<void>;
|
|
3
4
|
/** Implements path exists for the public runtime surface of this module. */
|
|
@@ -24,11 +25,25 @@ export declare function readFileIfExists(targetPath: string): Promise<string | n
|
|
|
24
25
|
* POSIX flags. Entries and ancestors must be trusted and stable: these checks
|
|
25
26
|
* do not pin paths or prevent hostile concurrent redirection before a read.
|
|
26
27
|
* @param targetPath Contained file whose ancestors the caller already validated.
|
|
27
|
-
* @param
|
|
28
|
+
* @param rejectionError Declared refusal when the opened entry is not a regular file.
|
|
28
29
|
*/
|
|
29
|
-
export declare function readRegularFile(targetPath: string,
|
|
30
|
-
/**
|
|
31
|
-
|
|
30
|
+
export declare function readRegularFile(targetPath: string, rejectionError: Error): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Refuse unsafe preview storage without exposing filesystem paths. Entry and
|
|
33
|
+
* opened-descriptor checks share this usage error so SDK callers can repair
|
|
34
|
+
* tracker configuration rather than treating a preserved safety boundary as
|
|
35
|
+
* an unexpected runtime fault. Native filesystem failures retain their codes.
|
|
36
|
+
*/
|
|
37
|
+
export declare function transactionPreviewNonRegularFileError(): PmCliError;
|
|
38
|
+
/**
|
|
39
|
+
* Replace a UTF-8 file through a sibling temporary file and atomic rename.
|
|
40
|
+
* Parent directories are created by default. Background consumers can disable
|
|
41
|
+
* that behavior to respect removal of their storage while work is in flight;
|
|
42
|
+
* missing parents then produce the native filesystem error without recreation.
|
|
43
|
+
*/
|
|
44
|
+
export declare function writeFileAtomic(targetPath: string, contents: string, options?: {
|
|
45
|
+
createParentDirectories?: boolean;
|
|
46
|
+
}): Promise<void>;
|
|
32
47
|
/**
|
|
33
48
|
* Append a single newline-terminated line to a file, opened with `O_APPEND`.
|
|
34
49
|
*
|
package/dist/core/fs/fs-utils.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
-
`,"utf8")}finally{await handle.close()}}async function removeFileIfExists(targetPath){try{await fs.unlink(targetPath)}catch(error){if(!isFileAbsentError(error))throw error}}function isErrno(error,code){return typeof error=="object"&&error!==null&&"code"in error&&error.code===code}export{appendLineAtomic,ensureDir,isFileAbsentError,isFileMissingError,pathExists,readFileIfExists,readRegularFile,removeFileIfExists,writeFileAtomic};
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="78969134-5a5b-50b5-9601-9b1b8dbcf8ac")}catch{}})();import*as fs from"node:fs/promises";import{constants}from"node:fs";import path from"node:path";import crypto from"node:crypto";import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";const WINDOWS_RENAME_RETRY_DELAYS_MS=[10,25,50,100];async function ensureDir(dirPath){await fs.mkdir(dirPath,{recursive:!0})}async function pathExists(targetPath){try{return await fs.access(targetPath),!0}catch{return!1}}function isFileAbsentError(error){return isFileMissingError(error)||isErrno(error,"ENOTDIR")}function isFileMissingError(error){return isErrno(error,"ENOENT")}async function readFileIfExists(targetPath){try{return await fs.readFile(targetPath,"utf8")}catch(error){if(isFileAbsentError(error))return null;throw error}}async function readRegularFile(targetPath,rejectionError){const handle=await fs.open(targetPath,constants.O_RDONLY|constants.O_NOFOLLOW|constants.O_NONBLOCK);try{if(!(await handle.stat()).isFile())throw rejectionError;return await handle.readFile("utf8")}finally{await handle.close()}}function transactionPreviewNonRegularFileError(){return new PmCliError("Transaction preview requires regular files and directories.",EXIT_CODE.USAGE,{code:"transaction_preview_non_regular_file",required:"regular files and directories within the configured tracker storage",why:"Preview does not follow linked entries or read special files.",nextSteps:["Inspect the configured tracker storage, settings, schema and session entries for links, directories used as files, or special files.","Restore the intended regular files and directories, then retry the original dry-run command."]})}async function writeFileAtomic(targetPath,contents,options={}){const dirPath=path.dirname(targetPath);options.createParentDirectories!==!1&&await ensureDir(dirPath);const tempPath=path.join(dirPath,`.${path.basename(targetPath)}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString("hex")}.tmp`);await fs.writeFile(tempPath,contents,"utf8");try{await fs.rename(tempPath,targetPath)}catch(error){if(process.platform==="win32"&&(isErrno(error,"EPERM")||isErrno(error,"EBUSY"))){let lastError=error;for(const delayMs of WINDOWS_RENAME_RETRY_DELAYS_MS){await new Promise(resolve=>setTimeout(resolve,delayMs));try{await fs.rename(tempPath,targetPath);return}catch(retryError){if(lastError=retryError,!isErrno(retryError,"EPERM")&&!isErrno(retryError,"EBUSY"))break}}try{await fs.unlink(tempPath)}catch{}throw lastError}if(isErrno(error,"EXDEV")){try{await fs.copyFile(tempPath,targetPath)}finally{try{await fs.unlink(tempPath)}catch{}}return}try{await fs.unlink(tempPath)}catch{}throw error}}async function appendLineAtomic(targetPath,line){const dirPath=path.dirname(targetPath);await ensureDir(dirPath);const handle=await fs.open(targetPath,"a");try{await handle.writeFile(`${line}
|
|
2
|
+
`,"utf8")}finally{await handle.close()}}async function removeFileIfExists(targetPath){try{await fs.unlink(targetPath)}catch(error){if(!isFileAbsentError(error))throw error}}function isErrno(error,code){return typeof error=="object"&&error!==null&&"code"in error&&error.code===code}export{appendLineAtomic,ensureDir,isFileAbsentError,isFileMissingError,pathExists,readFileIfExists,readRegularFile,removeFileIfExists,transactionPreviewNonRegularFileError,writeFileAtomic};
|
|
3
3
|
//# sourceMappingURL=fs-utils.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DatabaseSync } from "node:sqlite";
|
|
2
2
|
import type { HistoryEntry } from "../../types/index.js";
|
|
3
|
+
import { loadDatabaseSync, loadStableDatabaseSync } from "../store/sqlite-runtime.js";
|
|
3
4
|
type DatabaseSyncConstructor = typeof DatabaseSync;
|
|
4
5
|
/** Stable location of one history entry inside its authoritative stream. */
|
|
5
6
|
export interface IndexedHistoryEvent {
|
|
@@ -49,8 +50,6 @@ export interface HistoryEventIndexQueryResult {
|
|
|
49
50
|
}
|
|
50
51
|
/** Latest substantive immutable event for each requested history stream. */
|
|
51
52
|
export type LatestSubstantiveHistoryEvents = Readonly<Record<string, IndexedHistoryEvent>>;
|
|
52
|
-
declare function loadDatabaseSync(loadModule: (specifier: string) => unknown): DatabaseSyncConstructor | null;
|
|
53
|
-
declare function loadStableDatabaseSync(nodeVersion: string, loadModule: (specifier: string) => unknown): DatabaseSyncConstructor | null;
|
|
54
53
|
/** Rebuild the complete optional event projection from authoritative streams. */
|
|
55
54
|
export declare function rebuildHistoryEventIndex(pmRoot: string): Promise<boolean>;
|
|
56
55
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
-
`,{flag:"wx"}),{pendingPath,committedPath:path.join(directory,`${token}.committed`)}}function sameInvalidationNames(left,right){return left.length===right.length&&left.every((name,index)=>name===right[index])}async function invalidateHistoryEventIndex(pmRoot){try{await fs.rm(eventIndexPath(pmRoot),{force:!0})}catch{}}async function withHistoryEventIndexLock(pmRoot,operation){const release=await acquireLock(pmRoot,HISTORY_EVENT_INDEX_LOCK_ID,HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS,`history-event-index:${process.pid}`,!1,!1,HISTORY_EVENT_INDEX_LOCK_WAIT_MS);try{return await operation()}finally{await release()}}async function readAuthoritativeHistorySnapshot(pmRoot){const historyRoot=path.join(pmRoot,"history"),entries=await fs.readdir(historyRoot,{withFileTypes:!0}).catch(error=>{if(typeof error=="object"&&error!==null&&"code"in error&&error.code==="ENOENT")return[];throw error}),cached=authoritativeHistoryCaches.get(pmRoot)??{streams:new Map,ordered_events:[]},presentStreams=new Set;let changed=!authoritativeHistoryCaches.has(pmRoot);for(const historyFile of entries.filter(entry=>entry.isFile()&&entry.name.endsWith(".jsonl")).sort((left,right)=>left.name.localeCompare(right.name))){const streamId=historyFile.name.slice(0,-6);presentStreams.add(streamId);const historyPath=path.join(historyRoot,historyFile.name),stats=await fs.stat(historyPath,{bigint:!0}),signature=[stats.dev,stats.ino,stats.size,stats.mtimeNs,stats.ctimeNs].join(":");if(cached.streams.get(streamId)?.signature===signature)continue;const history=await readIndexableHistoryEntries(historyPath,streamId);cached.streams.set(streamId,{signature,byte_size:Number(stats.size),events:history.map((entry,streamOffset)=>({stream_id:streamId,stream_offset:streamOffset,entry}))}),changed=!0}for(const streamId of cached.streams.keys())presentStreams.has(streamId)||(cached.streams.delete(streamId),changed=!0);if(changed&&(cached.ordered_events=[...cached.streams.values()].flatMap(stream=>stream.events).sort(compareHistoryEventPosition)),authoritativeHistoryCaches.delete(pmRoot),authoritativeHistoryCaches.set(pmRoot,cached),authoritativeHistoryCaches.size>AUTHORITATIVE_HISTORY_CACHE_LIMIT){const oldestRoot=authoritativeHistoryCaches.keys().next().value;authoritativeHistoryCaches.delete(oldestRoot)}return{events:cached.ordered_events,stream_byte_sizes:new Map([...cached.streams].map(([streamId,stream])=>[streamId,stream.byte_size]))}}async function readIndexableHistoryEntries(historyPath,streamId){const entries=await readHistoryEntries(historyPath,streamId);for(const[index,entry]of entries.entries())if(typeof entry.ts!="string"||!isMillisecondPrecisionRfc3339DateTime(entry.ts.trim()))throw new PmCliError(`History for ${streamId} contains an invalid or sub-millisecond timestamp at line ${index+1}. Repair or restore the history stream and retry.`,EXIT_CODE.GENERIC_FAILURE,{code:"history_timestamp_invalid"});return entries.map(entry=>({...entry,ts:new Date(entry.ts.trim()).toISOString()}))}async function readAuthoritativeHistoryEvents(pmRoot){return(await readAuthoritativeHistorySnapshot(pmRoot)).events}
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="59e8ff0e-d2af-5f7a-a64b-1b86e075acdc")}catch{}})();import fs from"node:fs/promises";import path from"node:path";import{randomUUID}from"node:crypto";import{createRequire}from"node:module";import{isFileMissingError}from"../fs/fs-utils.js";import{acquireLock,captureProcessIdentity,isProcessIdentityAlive}from"../lock/lock.js";import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{isMillisecondPrecisionRfc3339DateTime}from"../shared/time.js";import{readHistoryEntries}from"./read.js";import{classifyHistoryEvent}from"./event-classification.js";import{loadDatabaseSync,loadStableDatabaseSync}from"../store/sqlite-runtime.js";const EVENT_INDEX_FILENAME="history-event-index.sqlite",EVENT_INDEX_VERSION="5",AUTHORITATIVE_HISTORY_CACHE_LIMIT=8,HISTORY_EVENT_INDEX_LOCK_ID="history-event-index",HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS=300,HISTORY_EVENT_INDEX_LOCK_WAIT_MS=3e4,HISTORY_EVENT_INDEX_INVALIDATION_LOCK_ID="history-event-index-invalidation",HISTORY_EVENT_INDEX_INVALIDATION_DIRECTORY="history-event-index-invalidations",HISTORY_EVENT_INDEX_INVALIDATION_MAX_UNVERIFIED_AGE_MS=HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS*2*1e3,HISTORY_INDEX_LOCK_CONTENDED=Symbol("history-index-lock-contended"),authoritativeHistoryCaches=new Map;function eventIndexPath(pmRoot){return path.join(pmRoot,"runtime",EVENT_INDEX_FILENAME)}function historyEventIndexInvalidationDirectory(pmRoot){return path.join(pmRoot,"runtime",HISTORY_EVENT_INDEX_INVALIDATION_DIRECTORY)}async function listHistoryEventIndexInvalidations(pmRoot){const entries=await fs.readdir(historyEventIndexInvalidationDirectory(pmRoot)).catch(error=>{if(isFileMissingError(error))return[];throw error});return{pending:entries.filter(name=>name.endsWith(".pending")).sort(),committed:entries.filter(name=>name.endsWith(".committed")).sort()}}async function recoverAbandonedHistoryEventIndexInvalidations(pmRoot){const invalidations=await listHistoryEventIndexInvalidations(pmRoot);return{pending:(await Promise.all(invalidations.pending.map(async name=>{const owner=/^(\d+)-(unknown|\d+)-(\d+)-.+\.pending$/u.exec(name);if(owner!==null){const processStartIdentity=owner[2];if(await isProcessIdentityAlive({pid:Number(owner[1]),...processStartIdentity==="unknown"?{}:{process_start_identity:processStartIdentity}},Math.max(0,Date.now()-Number(owner[3])),HISTORY_EVENT_INDEX_INVALIDATION_MAX_UNVERIFIED_AGE_MS))return name}return await fs.rm(path.join(historyEventIndexInvalidationDirectory(pmRoot),name),{force:!0}),null}))).filter(name=>name!==null),committed:invalidations.committed}}async function withHistoryEventIndexInvalidationLock(pmRoot,operation){const release=await acquireLock(pmRoot,HISTORY_EVENT_INDEX_INVALIDATION_LOCK_ID,HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS,`history-event-index-invalidation:${process.pid}`,!1,!1,HISTORY_EVENT_INDEX_LOCK_WAIT_MS);try{return await operation()}finally{await release()}}async function beginHistoryEventIndexInvalidation(pmRoot){const directory=historyEventIndexInvalidationDirectory(pmRoot);await fs.mkdir(directory,{recursive:!0});const token=randomUUID(),processIdentity=await captureProcessIdentity(),pendingPath=path.join(directory,`${processIdentity.pid}-${processIdentity.process_start_identity??"unknown"}-${Date.now()}-${token}.pending`);return await fs.writeFile(pendingPath,`pending
|
|
2
|
+
`,{flag:"wx"}),{pendingPath,committedPath:path.join(directory,`${token}.committed`)}}function sameInvalidationNames(left,right){return left.length===right.length&&left.every((name,index)=>name===right[index])}async function invalidateHistoryEventIndex(pmRoot){try{await fs.rm(eventIndexPath(pmRoot),{force:!0})}catch{}}async function withHistoryEventIndexLock(pmRoot,operation){const release=await acquireLock(pmRoot,HISTORY_EVENT_INDEX_LOCK_ID,HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS,`history-event-index:${process.pid}`,!1,!1,HISTORY_EVENT_INDEX_LOCK_WAIT_MS);try{return await operation()}finally{await release()}}async function readAuthoritativeHistorySnapshot(pmRoot){const historyRoot=path.join(pmRoot,"history"),entries=await fs.readdir(historyRoot,{withFileTypes:!0}).catch(error=>{if(typeof error=="object"&&error!==null&&"code"in error&&error.code==="ENOENT")return[];throw error}),cached=authoritativeHistoryCaches.get(pmRoot)??{streams:new Map,ordered_events:[]},presentStreams=new Set;let changed=!authoritativeHistoryCaches.has(pmRoot);for(const historyFile of entries.filter(entry=>entry.isFile()&&entry.name.endsWith(".jsonl")).sort((left,right)=>left.name.localeCompare(right.name))){const streamId=historyFile.name.slice(0,-6);presentStreams.add(streamId);const historyPath=path.join(historyRoot,historyFile.name),stats=await fs.stat(historyPath,{bigint:!0}),signature=[stats.dev,stats.ino,stats.size,stats.mtimeNs,stats.ctimeNs].join(":");if(cached.streams.get(streamId)?.signature===signature)continue;const history=await readIndexableHistoryEntries(historyPath,streamId);cached.streams.set(streamId,{signature,byte_size:Number(stats.size),events:history.map((entry,streamOffset)=>({stream_id:streamId,stream_offset:streamOffset,entry}))}),changed=!0}for(const streamId of cached.streams.keys())presentStreams.has(streamId)||(cached.streams.delete(streamId),changed=!0);if(changed&&(cached.ordered_events=[...cached.streams.values()].flatMap(stream=>stream.events).sort(compareHistoryEventPosition)),authoritativeHistoryCaches.delete(pmRoot),authoritativeHistoryCaches.set(pmRoot,cached),authoritativeHistoryCaches.size>AUTHORITATIVE_HISTORY_CACHE_LIMIT){const oldestRoot=authoritativeHistoryCaches.keys().next().value;authoritativeHistoryCaches.delete(oldestRoot)}return{events:cached.ordered_events,stream_byte_sizes:new Map([...cached.streams].map(([streamId,stream])=>[streamId,stream.byte_size]))}}async function readIndexableHistoryEntries(historyPath,streamId){const entries=await readHistoryEntries(historyPath,streamId);for(const[index,entry]of entries.entries())if(typeof entry.ts!="string"||!isMillisecondPrecisionRfc3339DateTime(entry.ts.trim()))throw new PmCliError(`History for ${streamId} contains an invalid or sub-millisecond timestamp at line ${index+1}. Repair or restore the history stream and retry.`,EXIT_CODE.GENERIC_FAILURE,{code:"history_timestamp_invalid"});return entries.map(entry=>({...entry,ts:new Date(entry.ts.trim()).toISOString()}))}async function readAuthoritativeHistoryEvents(pmRoot){return(await readAuthoritativeHistorySnapshot(pmRoot)).events}let RuntimeDatabaseSync;function resolveDatabaseSync(){return RuntimeDatabaseSync!==void 0||(RuntimeDatabaseSync=loadStableDatabaseSync(process.versions.node,createRequire(import.meta.url))),RuntimeDatabaseSync}function createSchema(database){database.exec(`
|
|
3
3
|
PRAGMA journal_mode = OFF;
|
|
4
4
|
PRAGMA synchronous = OFF;
|
|
5
5
|
CREATE TABLE metadata (
|
package/dist/core/lock/lock.d.ts
CHANGED
|
@@ -76,6 +76,13 @@ export declare const _testOnly: {
|
|
|
76
76
|
acquireStaleCleanupGate: typeof acquireStaleCleanupGate;
|
|
77
77
|
removeConfirmedStaleLock: typeof removeConfirmedStaleLock;
|
|
78
78
|
};
|
|
79
|
-
/**
|
|
80
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Acquire a token-owned tracker lock with bounded contention waiting and
|
|
81
|
+
* explicit stale-owner policy. Background consumers may disable creation of
|
|
82
|
+
* parent directories so acquiring or retrying a lock cannot revive removed
|
|
83
|
+
* storage. Extension overrides retain responsibility for their own lifecycle.
|
|
84
|
+
*/
|
|
85
|
+
export declare function acquireLock(pmRoot: string, id: string, ttlSeconds: number, owner: string, force?: boolean, forceRequiredForStaleLock?: boolean, waitMs?: number, options?: {
|
|
86
|
+
createParentDirectories?: boolean;
|
|
87
|
+
}): Promise<() => Promise<void>>;
|
|
81
88
|
export {};
|
package/dist/core/lock/lock.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="dcf54e42-cfa8-5672-863c-b12451a7fa57")}catch{}})();import{isFileMissingError}from"../fs/fs-utils.js";import{constants as fsConstants}from"node:fs";import fs from"node:fs/promises";import path from"node:path";import{randomUUID}from"node:crypto";import{runActiveOnReadHooks,runActiveOnWriteHooks,runActiveServiceOverride}from"../extensions/index.js";import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{toErrorMessage}from"../shared/primitives.js";import{getLockPath}from"../store/paths.js";import{nowIso}from"../shared/time.js";function parseLockInfo(raw){let parsed;try{parsed=JSON.parse(raw)}catch{return{info:null,warnings:["lock_info_invalid_json"]}}if(typeof parsed!="object"||parsed===null||Array.isArray(parsed))return{info:null,warnings:["lock_info_invalid_shape"]};const candidate=parsed,id=candidate.id,pid=candidate.pid,owner=candidate.owner,token=candidate.token,createdAt=candidate.created_at,ttlSeconds=candidate.ttl_seconds;return typeof id!="string"||typeof pid!="number"||!Number.isFinite(pid)||typeof owner!="string"||token!==void 0&&(typeof token!="string"||token.trim().length===0)||typeof createdAt!="string"||typeof ttlSeconds!="number"||!Number.isFinite(ttlSeconds)?{info:null,warnings:["lock_info_invalid_shape"]}:{info:{id,pid,owner,...typeof token=="string"?{token}:{},created_at:createdAt,ttl_seconds:ttlSeconds},warnings:[]}}async function readLockInfo(lockPath,emitReadHook=!0){try{const raw=await fs.readFile(lockPath,"utf8");return emitReadHook&&await runActiveOnReadHooks({path:lockPath,scope:"project"}),parseLockInfo(raw)}catch(error){return isFileMissingError(error)?{info:null,warnings:[]}:{info:null,warnings:["lock_info_read_failed"]}}}function isErrno(error,code){return typeof error=="object"&&error!==null&&"code"in error&&error.code===code}async function isLockCreateContention(error,lockPath,platform=process.platform){if(isErrno(error,"EEXIST"))return!0;if(!isErrno(error,"EPERM")&&!isErrno(error,"EACCES")&&!isErrno(error,"EBUSY"))return!1;try{return await fs.lstat(lockPath),!0}catch(probeError){if(platform!=="win32"||!isFileMissingError(probeError)&&!isErrno(probeError,"EPERM")&&!isErrno(probeError,"EACCES")&&!isErrno(probeError,"EBUSY"))return!1}try{return await fs.access(path.dirname(lockPath),fsConstants.W_OK),!0}catch{return!1}}async function emitLockWriteHook(lockPath,op){await runActiveOnWriteHooks({path:lockPath,scope:"project",op})}function buildLockPayload(id,owner,ttlSeconds,token=randomUUID()){return{id,pid:process.pid,owner,token,created_at:nowIso(),ttl_seconds:ttlSeconds}}async function createLockFile(lockPath,id,owner,ttlSeconds,token,createParentDirectories){createParentDirectories&&await fs.mkdir(path.dirname(lockPath),{recursive:!0});const releaseCleanupGate=await acquireStaleCleanupGate(lockPath,id);if(releaseCleanupGate===null)throw await fs.access(path.dirname(lockPath)),Object.assign(new Error("Lock initialization is contended"),{code:"EEXIST"});try{const handle=await fs.open(lockPath,"wx");try{try{await handle.writeFile(`${JSON.stringify(buildLockPayload(id,owner,ttlSeconds,token),null,2)}
|
|
2
2
|
`,"utf8")}finally{await handle.close()}}catch(error){throw await unlinkLockWithHook(lockPath,"lock:release"),error}}finally{await releaseCleanupGate()}await emitLockWriteHook(lockPath,"lock:create")}async function unlinkLockWithHook(lockPath,op){try{return await fs.unlink(lockPath),await emitLockWriteHook(lockPath,op),!0}catch{return!1}}async function releaseOwnedLock(lockPath,id,owner,token){const startedAtMs=Date.now();let backoffMs=LOCK_WAIT_INITIAL_DELAY_MS;for(;;){const releaseCleanupGate=await acquireStaleCleanupGate(lockPath,id);if(releaseCleanupGate!==null){try{const current2=await readLockInfo(lockPath,!1);isOwnedLock(current2.info,id,owner,token)&&await unlinkLockWithHook(lockPath,"lock:release")}finally{await releaseCleanupGate()}return}const current=await readLockInfo(lockPath,!1);if(!isOwnedLock(current.info,id,owner,token))return;const elapsedMs=Date.now()-startedAtMs;if(elapsedMs>=LOCK_RELEASE_GATE_WAIT_MS)return;await sleepWithJitter(Math.min(backoffMs,LOCK_RELEASE_GATE_WAIT_MS-elapsedMs)),backoffMs=Math.min(backoffMs*2,LOCK_WAIT_MAX_DELAY_MS)}}function isOwnedLock(info,id,owner,token){return info?.id===id&&info.pid===process.pid&&info.owner===owner&&info.token===token}function isStaleLock(info,ttlSeconds){const createdAtMs=info?.created_at?Date.parse(info.created_at):Number.NaN;return(Number.isFinite(createdAtMs)?Date.now()-createdAtMs:Number.POSITIVE_INFINITY)>ttlSeconds*1e3}function lockOwnerSuffix(info){return info?.owner?` (owner ${info.owner})`:""}const LOCK_WAIT_INITIAL_DELAY_MS=25,LOCK_WAIT_MAX_DELAY_MS=200,LOCK_CONFLICT_RETRY_HINT_MS=250,MAX_STALE_LOCK_REMOVALS=3,STALE_CLEANUP_GATE_SUFFIX=".stale-cleanup",STALE_CLEANUP_GATE_OWNER_FILE="owner.json",STALE_CLEANUP_GATE_STALE_MS=1e4,LOCK_RELEASE_GATE_WAIT_MS=STALE_CLEANUP_GATE_STALE_MS+LOCK_WAIT_MAX_DELAY_MS,STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS=60*6e4;function parseNonNegativeIntegerWaitMs(value){if(typeof value=="string"){const trimmed=value.trim();if(!/^\d+$/.test(trimmed))return;const parsed=Number(trimmed);return Number.isSafeInteger(parsed)?parsed:void 0}if(typeof value=="number"&&Number.isFinite(value)&&value>=0)return Math.trunc(value)}function resolveLockWaitMs(waitMs){const envRaw=process.env.PM_LOCK_WAIT_MS,envParsed=parseNonNegativeIntegerWaitMs(envRaw);if(envParsed!==void 0)return envParsed;const callerParsed=parseNonNegativeIntegerWaitMs(waitMs);return callerParsed!==void 0?callerParsed:0}function sleepWithJitter(baseDelayMs){const jitteredMs=Math.max(1,Math.round(baseDelayMs*(.5+Math.random())));return new Promise(resolve=>setTimeout(resolve,jitteredMs))}function buildLockConflictError(id,info,waitedMs){const waitedSuffix=waitedMs>0?` after waiting ${waitedMs}ms`:"";return new PmCliError(`Item ${id} is locked${lockOwnerSuffix(info)}${waitedSuffix}`,EXIT_CODE.CONFLICT,{code:"lock_conflict",recovery:{retry_after_ms:LOCK_CONFLICT_RETRY_HINT_MS}})}function resolveLockOverrideRelease(result){if(typeof result=="function")return result;if(typeof result=="object"&&result!==null&&"release"in result){const release=result.release;return typeof release=="function"?release:null}return null}function throwIfStaleLockNeedsForce(id,lockInfo,force,forceRequired){if(!force&&forceRequired){const warningSuffix=lockInfo.warnings.length>0?` (${lockInfo.warnings.join(",")})`:"";throw new PmCliError(`Item ${id} lock is stale${warningSuffix}; rerun with --force when supported for this command`,EXIT_CODE.CONFLICT)}}function parseStaleCleanupGateOwner(raw){let parsed;try{parsed=JSON.parse(raw)}catch{return null}if(typeof parsed!="object"||parsed===null||Array.isArray(parsed))return null;const candidate=parsed,pid=candidate.pid,token=candidate.token,processStartIdentity=candidate.process_start_identity;return typeof pid!="number"||!Number.isInteger(pid)||pid<=0||typeof token!="string"||token.length===0||processStartIdentity!==void 0&&(typeof processStartIdentity!="string"||!/^\d+$/u.test(processStartIdentity))?null:{pid,token,...typeof processStartIdentity=="string"?{process_start_identity:processStartIdentity}:{}}}async function readStaleCleanupGateOwner(gatePath){try{return parseStaleCleanupGateOwner(await fs.readFile(path.join(gatePath,STALE_CLEANUP_GATE_OWNER_FILE),"utf8"))}catch{return null}}function isProcessAlive(pid){if(!Number.isSafeInteger(pid)||pid<=0)return!1;try{return process.kill(pid,0),!0}catch(error){return!isErrno(error,"ESRCH")}}function parseLinuxProcessStartIdentity(raw){const closeParenIndex=raw.lastIndexOf(")");if(closeParenIndex<0)return null;const startTime=raw.slice(closeParenIndex+2).trim().split(/\s+/u)[19];return startTime!==void 0&&/^\d+$/u.test(startTime)?startTime:null}async function readProcessStartIdentity(pid){try{return parseLinuxProcessStartIdentity(await fs.readFile(`/proc/${pid}/stat`,"utf8"))}catch{return null}}async function captureProcessIdentity(pid=process.pid){const processStartIdentity=await readProcessStartIdentity(pid);return{pid,...processStartIdentity===null?{}:{process_start_identity:processStartIdentity}}}async function isProcessIdentityAlive(identity,unverifiedAgeMs,maxUnverifiedAgeMs){if(!isProcessAlive(identity.pid))return!1;const currentStartIdentity=await readProcessStartIdentity(identity.pid);return identity.process_start_identity!==void 0&¤tStartIdentity!==null?currentStartIdentity===identity.process_start_identity:unverifiedAgeMs<=maxUnverifiedAgeMs}async function removeStaleCleanupGateDirectory(gatePath){try{return await fs.rm(gatePath,{recursive:!0,force:!0}),!0}catch{return!1}}async function releaseStaleCleanupGate(gatePath,token){const owner=await readStaleCleanupGateOwner(gatePath);owner===null||owner.token!==token||await removeStaleCleanupGateDirectory(gatePath)}async function tryCreateStaleCleanupGate(gatePath){try{await fs.mkdir(gatePath)}catch(error){return isErrno(error,"EEXIST"),null}const owner={...await captureProcessIdentity(),token:randomUUID()};try{await fs.writeFile(path.join(gatePath,STALE_CLEANUP_GATE_OWNER_FILE),`${JSON.stringify(owner)}
|
|
3
|
-
`,"utf8")}catch{return await removeStaleCleanupGateDirectory(gatePath),null}return owner}async function removeExpiredStaleCleanupGate(gatePath){let gateAgeMs;try{const stats=await fs.stat(gatePath);if(gateAgeMs=Date.now()-stats.mtimeMs,gateAgeMs<=STALE_CLEANUP_GATE_STALE_MS)return!1}catch(error){return isFileMissingError(error)}const owner=await readStaleCleanupGateOwner(gatePath);return owner!==null&&await isProcessIdentityAlive(owner,gateAgeMs,STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS)?!1:removeStaleCleanupGateDirectory(gatePath)}async function acquireStaleCleanupGate(lockPath,_id){const gatePath=`${lockPath}${STALE_CLEANUP_GATE_SUFFIX}`,owner=await tryCreateStaleCleanupGate(gatePath);if(owner!==null)return async()=>releaseStaleCleanupGate(gatePath,owner.token);if(!await removeExpiredStaleCleanupGate(gatePath))return null;const recoveredOwner=await tryCreateStaleCleanupGate(gatePath);return recoveredOwner===null?null:async()=>releaseStaleCleanupGate(gatePath,recoveredOwner.token)}async function removeConfirmedStaleLock(params){const releaseCleanupGate=await acquireStaleCleanupGate(params.lockPath,params.id);if(releaseCleanupGate===null)return{lockInfo:params.fallbackLockInfo,shouldRetryCreate:!1,staleRemovalCounted:!1};try{const currentLockInfo=await readLockInfo(params.lockPath);if(currentLockInfo.info===null&¤tLockInfo.warnings.length===0)return{lockInfo:currentLockInfo,shouldRetryCreate:!0,staleRemovalCounted:!1};if(!isStaleLock(currentLockInfo.info,params.ttlSeconds))return{lockInfo:currentLockInfo,shouldRetryCreate:!1,staleRemovalCounted:!1};if(throwIfStaleLockNeedsForce(params.id,currentLockInfo,params.force,params.forceRequiredForStaleLock),params.staleRemovals>=MAX_STALE_LOCK_REMOVALS)throw buildLockConflictError(params.id,currentLockInfo.info,Date.now()-params.startedAtMs);return{lockInfo:currentLockInfo,shouldRetryCreate:await unlinkLockWithHook(params.lockPath,"lock:stale_remove"),staleRemovalCounted:!0}}finally{await releaseCleanupGate()}}const _testOnly={parseLockInfo,readLockInfo,isErrno,isLockCreateContention,buildLockPayload,isStaleLock,lockOwnerSuffix,resolveLockWaitMs,parseLinuxProcessStartIdentity,readProcessStartIdentity,acquireStaleCleanupGate,removeConfirmedStaleLock};async function acquireLock(pmRoot,id,ttlSeconds,owner,force=!1,forceRequiredForStaleLock=!0,waitMs){const lockOverride=await runActiveServiceOverride("lock_acquire",{pm_root:pmRoot,id,ttl_seconds:ttlSeconds,owner,force,force_required_for_stale_lock:forceRequiredForStaleLock});if(lockOverride.handled){const release=resolveLockOverrideRelease(lockOverride.result);if(release)return async()=>{await Promise.resolve(release()),await runActiveServiceOverride("lock_release",{pm_root:pmRoot,id,owner})}}const lockPath=getLockPath(pmRoot,id),waitBudgetMs=resolveLockWaitMs(waitMs),startedAtMs=Date.now();let staleRemovals=0,backoffMs=LOCK_WAIT_INITIAL_DELAY_MS;const token=randomUUID();for(;;)try{return await createLockFile(lockPath,id,owner,ttlSeconds,token),async()=>{await releaseOwnedLock(lockPath,id,owner,token),await runActiveServiceOverride("lock_release",{pm_root:pmRoot,id,owner})}}catch(error){if(!await isLockCreateContention(error,lockPath))throw new PmCliError(`Failed to acquire lock for ${id}: ${toErrorMessage(error)}`,EXIT_CODE.GENERIC_FAILURE);let lockInfo=await readLockInfo(lockPath);if(isStaleLock(lockInfo.info,ttlSeconds)){const staleRemoval=await removeConfirmedStaleLock({lockPath,id,ttlSeconds,force,forceRequiredForStaleLock,staleRemovals,waitBudgetMs,startedAtMs,fallbackLockInfo:lockInfo});if(lockInfo=staleRemoval.lockInfo,staleRemoval.staleRemovalCounted&&(staleRemovals+=1),staleRemoval.shouldRetryCreate)continue}const elapsedMs=Date.now()-startedAtMs;if(waitBudgetMs===0||elapsedMs>=waitBudgetMs)throw buildLockConflictError(id,lockInfo.info,waitBudgetMs===0?0:elapsedMs);await sleepWithJitter(Math.min(backoffMs,waitBudgetMs-elapsedMs)),backoffMs=Math.min(backoffMs*2,LOCK_WAIT_MAX_DELAY_MS)}}export{_testOnly,acquireLock,captureProcessIdentity,isProcessIdentityAlive,readProcessStartIdentity};
|
|
3
|
+
`,"utf8")}catch{return await removeStaleCleanupGateDirectory(gatePath),null}return owner}async function removeExpiredStaleCleanupGate(gatePath){let gateAgeMs;try{const stats=await fs.stat(gatePath);if(gateAgeMs=Date.now()-stats.mtimeMs,gateAgeMs<=STALE_CLEANUP_GATE_STALE_MS)return!1}catch(error){return isFileMissingError(error)}const owner=await readStaleCleanupGateOwner(gatePath);return owner!==null&&await isProcessIdentityAlive(owner,gateAgeMs,STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS)?!1:removeStaleCleanupGateDirectory(gatePath)}async function acquireStaleCleanupGate(lockPath,_id){const gatePath=`${lockPath}${STALE_CLEANUP_GATE_SUFFIX}`,owner=await tryCreateStaleCleanupGate(gatePath);if(owner!==null)return async()=>releaseStaleCleanupGate(gatePath,owner.token);if(!await removeExpiredStaleCleanupGate(gatePath))return null;const recoveredOwner=await tryCreateStaleCleanupGate(gatePath);return recoveredOwner===null?null:async()=>releaseStaleCleanupGate(gatePath,recoveredOwner.token)}async function removeConfirmedStaleLock(params){const releaseCleanupGate=await acquireStaleCleanupGate(params.lockPath,params.id);if(releaseCleanupGate===null)return{lockInfo:params.fallbackLockInfo,shouldRetryCreate:!1,staleRemovalCounted:!1};try{const currentLockInfo=await readLockInfo(params.lockPath);if(currentLockInfo.info===null&¤tLockInfo.warnings.length===0)return{lockInfo:currentLockInfo,shouldRetryCreate:!0,staleRemovalCounted:!1};if(!isStaleLock(currentLockInfo.info,params.ttlSeconds))return{lockInfo:currentLockInfo,shouldRetryCreate:!1,staleRemovalCounted:!1};if(throwIfStaleLockNeedsForce(params.id,currentLockInfo,params.force,params.forceRequiredForStaleLock),params.staleRemovals>=MAX_STALE_LOCK_REMOVALS)throw buildLockConflictError(params.id,currentLockInfo.info,Date.now()-params.startedAtMs);return{lockInfo:currentLockInfo,shouldRetryCreate:await unlinkLockWithHook(params.lockPath,"lock:stale_remove"),staleRemovalCounted:!0}}finally{await releaseCleanupGate()}}const _testOnly={parseLockInfo,readLockInfo,isErrno,isLockCreateContention,buildLockPayload,isStaleLock,lockOwnerSuffix,resolveLockWaitMs,parseLinuxProcessStartIdentity,readProcessStartIdentity,acquireStaleCleanupGate,removeConfirmedStaleLock};async function acquireLock(pmRoot,id,ttlSeconds,owner,force=!1,forceRequiredForStaleLock=!0,waitMs,options={}){const lockOverride=await runActiveServiceOverride("lock_acquire",{pm_root:pmRoot,id,ttl_seconds:ttlSeconds,owner,force,force_required_for_stale_lock:forceRequiredForStaleLock});if(lockOverride.handled){const release=resolveLockOverrideRelease(lockOverride.result);if(release)return async()=>{await Promise.resolve(release()),await runActiveServiceOverride("lock_release",{pm_root:pmRoot,id,owner})}}const lockPath=getLockPath(pmRoot,id),waitBudgetMs=resolveLockWaitMs(waitMs),startedAtMs=Date.now();let staleRemovals=0,backoffMs=LOCK_WAIT_INITIAL_DELAY_MS;const token=randomUUID();for(;;)try{return await createLockFile(lockPath,id,owner,ttlSeconds,token,options.createParentDirectories!==!1),async()=>{await releaseOwnedLock(lockPath,id,owner,token),await runActiveServiceOverride("lock_release",{pm_root:pmRoot,id,owner})}}catch(error){if(!await isLockCreateContention(error,lockPath))throw new PmCliError(`Failed to acquire lock for ${id}: ${toErrorMessage(error)}`,EXIT_CODE.GENERIC_FAILURE);let lockInfo=await readLockInfo(lockPath);if(isStaleLock(lockInfo.info,ttlSeconds)){const staleRemoval=await removeConfirmedStaleLock({lockPath,id,ttlSeconds,force,forceRequiredForStaleLock,staleRemovals,waitBudgetMs,startedAtMs,fallbackLockInfo:lockInfo});if(lockInfo=staleRemoval.lockInfo,staleRemoval.staleRemovalCounted&&(staleRemovals+=1),staleRemoval.shouldRetryCreate)continue}const elapsedMs=Date.now()-startedAtMs;if(waitBudgetMs===0||elapsedMs>=waitBudgetMs)throw buildLockConflictError(id,lockInfo.info,waitBudgetMs===0?0:elapsedMs);await sleepWithJitter(Math.min(backoffMs,waitBudgetMs-elapsedMs)),backoffMs=Math.min(backoffMs*2,LOCK_WAIT_MAX_DELAY_MS)}}export{_testOnly,acquireLock,captureProcessIdentity,isProcessIdentityAlive,readProcessStartIdentity};
|
|
4
4
|
//# sourceMappingURL=lock.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Host output controls shared by command execution and extension rendering. */
|
|
2
2
|
export interface OutputOptions {
|
|
3
|
-
/**
|
|
3
|
+
/** Select JSON explicitly; otherwise use the host default format. */
|
|
4
4
|
json?: boolean;
|
|
5
|
-
/**
|
|
5
|
+
/** Suppress process output while retaining the active command result. */
|
|
6
6
|
quiet?: boolean;
|
|
7
7
|
/** When true, mutation results drop the verbose changed_fields array (keeps changed_field_count). */
|
|
8
8
|
noChangedFields?: boolean;
|
|
@@ -30,20 +30,22 @@ export interface OutputOptions {
|
|
|
30
30
|
outputRowContract?: boolean;
|
|
31
31
|
/** Fallback output format used when callers do not provide an override. */
|
|
32
32
|
defaultOutputFormat?: "toon" | "json";
|
|
33
|
-
/**
|
|
33
|
+
/** Command identity used to resolve read contracts and extension overrides. */
|
|
34
34
|
command?: string;
|
|
35
|
-
/**
|
|
35
|
+
/** Positional arguments passed to the output service override. */
|
|
36
36
|
commandArgs?: string[];
|
|
37
|
-
/**
|
|
37
|
+
/** Command options merged with active invocation options for output contracts. */
|
|
38
38
|
commandOptions?: Record<string, unknown>;
|
|
39
|
-
/**
|
|
39
|
+
/** Tracker root supplied to the output service override. */
|
|
40
40
|
pmRoot?: string;
|
|
41
41
|
}
|
|
42
|
-
/**
|
|
42
|
+
/** Write stdout and return false when its consumer has closed the pipe. */
|
|
43
43
|
export declare function writeStdout(text: string): boolean;
|
|
44
|
-
/**
|
|
44
|
+
/** Write stderr and preserve diagnostic delivery failures in the process exit code. */
|
|
45
45
|
export declare function writeStderr(text: string): boolean;
|
|
46
|
-
|
|
46
|
+
/** Keep sparse presentation rules shared while allowing lean JSON to retain count aliases. */
|
|
47
|
+
declare function compactToonValue(value: unknown, omitDuplicateCountAliases?: boolean): unknown | undefined;
|
|
48
|
+
/** Render objects recursively and arrays through the standard TOON encoder. */
|
|
47
49
|
declare function renderToonValue(value: unknown, depth: number): string;
|
|
48
50
|
/**
|
|
49
51
|
* Render a result with pm's built-in JSON or TOON formatter without invoking
|
|
@@ -51,13 +53,13 @@ declare function renderToonValue(value: unknown, depth: number): string;
|
|
|
51
53
|
* so reported token cost describes the bytes the host emits by default.
|
|
52
54
|
*/
|
|
53
55
|
export declare function formatBuiltInOutput(result: unknown, format: "json" | "toon"): string;
|
|
54
|
-
/**
|
|
56
|
+
/** Resolve command ownership and suppression before projecting and rendering the result. */
|
|
55
57
|
export declare function formatOutput(result: unknown, options: OutputOptions): string;
|
|
56
|
-
/**
|
|
58
|
+
/** Apply declared exit codes and mutation projection before writing a nonquiet result. */
|
|
57
59
|
export declare function printResult(result: unknown, options: OutputOptions): void;
|
|
58
|
-
/**
|
|
60
|
+
/** Apply the error service override and emit one newline-terminated diagnostic. */
|
|
59
61
|
export declare function printError(message: string): void;
|
|
60
|
-
/**
|
|
62
|
+
/** Internal rendering seams retained for deterministic presentation regression tests. */
|
|
61
63
|
export declare const outputTestOnly: {
|
|
62
64
|
compactToonValue: typeof compactToonValue;
|
|
63
65
|
renderToonValue: typeof renderToonValue;
|
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="391a4170-d29a-5c61-a0db-05181ebb0239")}catch{}})();import{getActiveCommandContext,runActiveCommandOverride,runActiveRendererOverride,runActiveServiceOverrideSync,setActiveCommandResult}from"../extensions/index.js";import{EXIT_CODE}from"../shared/constants.js";import{isHostOutputSuppressed}from"./output-control.js";import{projectMutationResult}from"./mutation-projection.js";import{attachReadOutputContracts}from"../../sdk/context-intent-contracts.js";import{attachOutputTokenAccounting}from"../../sdk/output-token-accounting.js";import{propagateContextUsageServingReceipt}from"../../sdk/context-usage.js";import{isReadOutputBudgetExceeded,resolveReadOutputEncoding}from"../../sdk/read-output-contracts.js";import{encode as encodeToon}from"@toon-format/toon";import{encodePmTableRows}from"../../sdk/output/table-rows.js";const DECLARED_PROCESS_EXIT_CODES=new Set(Object.values(EXIT_CODE)),COLLECTION_COUNT_ALIASES=new Map([["notes_count","notes"],["tests_count","tests"]]),NATIVE_OUTPUT_MARKER="__pm_native_output";let streamErrorHandlersInstalled=!1;function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function setActiveCommandResultOmitted(source){const omitted={read_output:{result_omitted:!0}};propagateContextUsageServingReceipt(source,omitted),setActiveCommandResult(omitted)}function setActiveCommandDeliveryResult(result,receiptSource,structuredDeliveryPreserved){if(structuredDeliveryPreserved){setActiveCommandResult(result);return}setActiveCommandResultOmitted(receiptSource)}function stripNativeOutputMarker(result){if(!isPlainObject(result)||result[NATIVE_OUTPUT_MARKER]!==!0)return result;const{[NATIVE_OUTPUT_MARKER]:_marker,...rest}=result;return rest}function isBrokenPipeError(error){return typeof error=="object"&&error!==null&&error.code==="EPIPE"}function markStdoutBrokenPipeExitCode(){(process.exitCode===void 0||process.exitCode===EXIT_CODE.SUCCESS)&&(process.exitCode=EXIT_CODE.SUCCESS)}function markStderrBrokenPipeExitCode(){(process.exitCode===void 0||process.exitCode===EXIT_CODE.SUCCESS)&&(process.exitCode=EXIT_CODE.GENERIC_FAILURE)}function markBrokenPipeExitCode(target){if(target==="stdout"){markStdoutBrokenPipeExitCode();return}markStderrBrokenPipeExitCode()}function handleUnhandledStreamError(error){const unhandled=error instanceof Error?error:new Error(String(error));setImmediate(()=>{throw unhandled})}function installStreamErrorHandlers(){streamErrorHandlersInstalled||(streamErrorHandlersInstalled=!0,process.stdout.on("error",error=>{if(isBrokenPipeError(error)){markBrokenPipeExitCode("stdout");return}handleUnhandledStreamError(error)}),process.stderr.on("error",error=>{if(isBrokenPipeError(error)){markBrokenPipeExitCode("stderr");return}handleUnhandledStreamError(error)}))}function writeToStream(target,text){installStreamErrorHandlers();try{return target==="stdout"?process.stdout.write(text):process.stderr.write(text),!0}catch(error){if(isBrokenPipeError(error))return markBrokenPipeExitCode(target),!1;throw error}}function writeStdout(text){return writeToStream("stdout",text)}function writeStderr(text){return writeToStream("stderr",text)}function renderScalar(value){return typeof value=="string"?JSON.stringify(value):typeof value=="number"||typeof value=="boolean"?String(value):value===null?"null":JSON.stringify(value)}function tabularObjectArray(value){const keys=Object.keys(value[0]);return keys.length>0&&value.every(entry=>Object.keys(entry).length===keys.length&&keys.every(key=>{if(!Object.hasOwn(entry,key))return!1;const cell=entry[key];return cell===null||typeof cell=="string"||typeof cell=="number"||typeof cell=="boolean"}))}function indentToon(encoded,depth){const indent=" ".repeat(depth);return encoded.split(`
|
|
2
2
|
`).map(line=>`${indent}${line}`).join(`
|
|
3
|
-
`)}function renderToonObjectEntry(key,entry,depth){const indent=" ".repeat(depth);
|
|
4
|
-
${renderToonValue(entry,depth+1)}`}function compactToonValue(value){if(value!=null){if(Array.isArray(value)){const compactedEntries=value.map(entry=>compactToonValue(entry)).filter(entry=>entry!==void 0);return compactedEntries.length>0?compactedEntries:void 0}if(isPlainObject(value)){const compacted={};for(const[key,entry]of
|
|
5
|
-
`),[firstLine,...rest]=lines;return rest.length===0?`${indent}- ${firstLine.trimStart()}`:`${indent}- ${firstLine.trimStart()}
|
|
6
|
-
${rest.join(`
|
|
7
|
-
`)}`}).join(`
|
|
8
|
-
`);if(isPlainObject(value)){const entries=Object.entries(value);return entries.length===0?"{}":entries.map(([key,entry])=>renderToonObjectEntry(key,entry,depth)).join(`
|
|
3
|
+
`)}function isNestedTableCandidateBounded(rows){const columns=new Set;let presentCells=0;for(const row of rows){const keys=Object.keys(row);presentCells+=keys.length;for(const key of keys)columns.add(key)}return rows.length*columns.size<=presentCells*2}function renderToonObjectEntry(key,entry,depth,allowNestedTable){const indent=" ".repeat(depth);if(!isPlainObject(entry)&&!Array.isArray(entry))return`${indent}${key}: ${renderScalar(entry)}`;if(Array.isArray(entry)){if(entry.length===0)return`${indent}${key}: []`;const expanded=indentToon(encodeToon({[key]:entry}),depth);if(allowNestedTable&&entry.length>=2&&entry.every(isPlainObject)&&!tabularObjectArray(entry)&&isNestedTableCandidateBounded(entry)){const table=encodePmTableRows(entry),tabular=indentToon(encodeToon({[key]:table.rows,[`${key}_encoding`]:table.encoding}),depth);if(Buffer.byteLength(tabular)<Buffer.byteLength(expanded))return tabular}return expanded}return isPlainObject(entry)&&Object.keys(entry).length===0?`${indent}${key}: {}`:`${indent}${key}:
|
|
4
|
+
${renderToonValue(entry,depth+1)}`}function compactToonValue(value,omitDuplicateCountAliases=!0){if(value!=null){if(Array.isArray(value)){const compactedEntries=value.map(entry=>compactToonValue(entry,omitDuplicateCountAliases)).filter(entry=>entry!==void 0);return compactedEntries.length>0?compactedEntries:void 0}if(isPlainObject(value)){const compacted={},entries=Object.entries(value).filter(([key,entry])=>{const canonicalCount=COLLECTION_COUNT_ALIASES.get(key);return!omitDuplicateCountAliases||canonicalCount===void 0||!isPlainObject(value.collection_counts)||entry!==value.collection_counts[canonicalCount]});for(const[key,entry]of entries){if(key==="omitted_field_groups"&&Array.isArray(entry)&&entry.length===0){compacted[key]=[];continue}const compactedEntry=compactToonValue(entry,omitDuplicateCountAliases);compactedEntry!==void 0&&(compacted[key]=compactedEntry)}return Object.keys(compacted).length>0?compacted:void 0}return value}}function renderToonValue(value,depth){const indent=" ".repeat(depth);if(Array.isArray(value))return value.length===0?"[]":indentToon(encodeToon(value),depth);if(isPlainObject(value)){const entries=Object.entries(value);return entries.length===0?"{}":entries.map(([key,entry])=>renderToonObjectEntry(key,entry,depth,!Object.hasOwn(value,`${key}_encoding`))).join(`
|
|
9
5
|
`)}return`${indent}${renderScalar(value)}`}function renderDefaultMarkdownResult(value){if(!isPlainObject(value)||value.output_default!=="markdown"||typeof value.view!="string"||!Array.isArray(value.events)||!Array.isArray(value.days))return null;const lines=[`# pm calendar (${value.view})`,""],summary=isPlainObject(value.summary)?value.summary:{};if(lines.push(`- events: ${String(summary.events??0)}`),lines.push(""),value.events.length===0)return lines.push("No calendar events matched the selected filters."),`${lines.join(`
|
|
10
6
|
`)}
|
|
11
7
|
`;for(const event of value.events){if(!isPlainObject(event))continue;const kind=typeof event.kind=="string"?event.kind:"event",title=typeof event.item_title=="string"?event.item_title:"",itemId=typeof event.item_id=="string"?event.item_id:"",reminderText=typeof event.reminder_text=="string"&&event.reminder_text.length>0?` ${event.reminder_text}`:"";lines.push(`- [${kind}] ${itemId} ${title}${reminderText}`.trim())}return`${lines.join(`
|
|
12
8
|
`)}
|
|
13
|
-
`}
|
|
9
|
+
`}const LEAN_READ_ENVELOPE_ECHO_KEYS=new Set(["filters","now","projection","sorting"]);function projectLeanJsonValue(value){const compacted=compactToonValue(value,!1);if(!isPlainObject(compacted)||!Array.isArray(compacted.items))return compacted??null;const projected=Object.fromEntries(Object.entries(compacted).filter(([key])=>!LEAN_READ_ENVELOPE_ECHO_KEYS.has(key)));return projected.has_more!==!0&&delete projected.next_cursor,projected}function projectLinkedTestEvidence(value,lean){if(!isPlainObject(value)||!Array.isArray(value.run_results)||!value.run_results.every(isPlainObject))return value;const rows=value.run_results,contexts=rows.map(row=>row.execution_context).filter(context=>context!==void 0),sharedContext=contexts.length===rows.length&&contexts.length>0&&contexts.every(context=>JSON.stringify(context)===JSON.stringify(contexts[0]))?contexts[0]:void 0,runResults=rows.map(row=>{const{execution_context:_executionContext,stdout,stderr,...rest}=row;return sharedContext===void 0?row:!lean||row.status!=="passed"?{...rest,stdout,stderr}:rest});return{...value,...sharedContext===void 0?{}:{execution_context:sharedContext},run_results:runResults}}function projectCompleteBriefList(value){if(!isPlainObject(value)||!Array.isArray(value.items)||Object.hasOwn(value,"details")||!isPlainObject(value.projection)||value.projection.mode!=="brief"||!isPlainObject(value.completeness)||value.completeness.status!=="complete"||[value.completeness.unreadable_item_count,value.completeness.unreadable_directory_count].some(count=>count!==0)||[value.has_more,value.truncated].some(flag=>flag!==!1)||value.count!==value.items.length||value.total!==value.count||!isPlainObject(value.omission_receipt)||JSON.stringify(value.omission_receipt.omitted_field_groups)!==JSON.stringify([{name:"full_item_fields",restore_with:"--full"}]))return value;const{total:_total,has_more:_hasMore,truncated:_truncated,next_cursor:_nextCursor,completeness:_completeness,projection:_projection,now:_now,omission_receipt:_omissions,sorting,...rest}=value;return{...rest,...isPlainObject(sorting)&&sorting.sort==="default"?{}:{sorting},details:"--full"}}function formatBuiltInOutput(result,format){if(format==="json")return`${JSON.stringify(result,null,2)}
|
|
14
10
|
`;const compactedToon=compactToonValue(projectCompleteBriefList(result));return compactedToon===void 0?`{}
|
|
15
11
|
`:`${renderToonValue(compactedToon,0)}
|
|
16
12
|
`}function resolveOutputService(effectiveResult,nativeOutput,options,format){const serviceOverride=nativeOutput?{handled:!1,result:effectiveResult,warnings:[]}:runActiveServiceOverrideSync("output_format",{command:options.command,args:options.commandArgs,command_options:options.commandOptions,global:{...options},pm_root:options.pmRoot,format,options:{...options},result:effectiveResult}),legacyPayloadEchoWarning=serviceOverride.warnings.find(warning=>warning.startsWith("extension_output_format_payload_echo_deprecated:"));return legacyPayloadEchoWarning!==void 0&&writeStderr(`Warning: ${legacyPayloadEchoWarning}. Returning context.payload now declines safely for compatibility; migrate the override to declineServiceOverride() or { handled: false }.
|
|
17
13
|
`),serviceOverride.handled&&typeof serviceOverride.result=="string"?{result:serviceOverride.result,rendered:serviceOverride.result.endsWith(`
|
|
18
14
|
`)?serviceOverride.result:`${serviceOverride.result}
|
|
19
|
-
`,structuredDeliveryPreserved:!1}:{result:serviceOverride.handled?serviceOverride.result:effectiveResult,rendered:null,structuredDeliveryPreserved:!serviceOverride.handled||isPlainObject(serviceOverride.result)}}function formatEffectiveOutput(effectiveResult,nativeOutput,options){const activeCommandContext=getActiveCommandContext(),command=options.command??activeCommandContext?.command,commandOptions={...activeCommandContext?.options,...options.commandOptions,...Object.fromEntries([["outputInclude",options.outputInclude],["outputLimit",options.outputLimit],["outputBudget",options.outputBudget],["outputFormat",options.outputFormat],["outputSession",options.outputSession],["outputCursor",options.outputCursor],["outputRowContract",options.outputRowContract]].filter(entry=>entry[1]!==void 0))},format=resolveReadOutputEncoding(command??"",commandOptions)??
|
|
15
|
+
`,structuredDeliveryPreserved:!1}:{result:serviceOverride.handled?serviceOverride.result:effectiveResult,rendered:null,structuredDeliveryPreserved:!serviceOverride.handled||isPlainObject(serviceOverride.result)}}function formatEffectiveOutput(effectiveResult,nativeOutput,options,defaultFormat){const activeCommandContext=getActiveCommandContext(),command=options.command??activeCommandContext?.command,commandOptions={...activeCommandContext?.options,...options.commandOptions,...Object.fromEntries([["outputInclude",options.outputInclude],["outputLimit",options.outputLimit],["outputBudget",options.outputBudget],["outputFormat",options.outputFormat],["outputSession",options.outputSession],["outputCursor",options.outputCursor],["outputRowContract",options.outputRowContract]].filter(entry=>entry[1]!==void 0))},format=resolveReadOutputEncoding(command??"",commandOptions)??defaultFormat,resolvedCommandOptions={...commandOptions,resolvedOutputFormat:format},effectiveOptions={...options,command,commandOptions:resolvedCommandOptions},service=resolveOutputService(effectiveResult,nativeOutput,effectiveOptions,format);if(service.rendered!==null)return setActiveCommandResultOmitted(effectiveResult),service.rendered;const outputResult=service.result;propagateContextUsageServingReceipt(effectiveResult,outputResult);const projectedOutputResult=command==="test"?projectLinkedTestEvidence(outputResult,options.lean===!0):outputResult,intentOutputResult=attachReadOutputContracts(command,resolvedCommandOptions,projectedOutputResult);isReadOutputBudgetExceeded(intentOutputResult)&&(process.exitCode||=EXIT_CODE.USAGE);let{structuredDeliveryPreserved}=service;const renderResolvedOutput=value=>{if(format==="toon"){const markdownDefault=renderDefaultMarkdownResult(value);if(markdownDefault!==null)return markdownDefault}const rendererOverride=nativeOutput?{rendered:null}:runActiveRendererOverride(format,value);return rendererOverride.rendered!==null?(structuredDeliveryPreserved=!1,rendererOverride.rendered.endsWith(`
|
|
20
16
|
`)?rendererOverride.rendered:`${rendererOverride.rendered}
|
|
21
|
-
`):format==="json"?formatBuiltInOutput(options.lean===!0?projectLeanJsonValue(value):value,"json"):formatBuiltInOutput(value,"toon")},accountedOutputResult=options.tokenAccounting===!0?attachOutputTokenAccounting(intentOutputResult,renderResolvedOutput):intentOutputResult,rendered=renderResolvedOutput(accountedOutputResult);return setActiveCommandDeliveryResult(accountedOutputResult,effectiveResult,options.quiet!==!0&&structuredDeliveryPreserved),rendered}function formatOutput(result,options){const commandOverride=runActiveCommandOverride(result),suppressedOutput=isHostOutputSuppressed(commandOverride.result)?commandOverride.result:null,
|
|
17
|
+
`):format==="json"?formatBuiltInOutput(options.lean===!0?projectLeanJsonValue(value):value,"json"):formatBuiltInOutput(value,"toon")},accountedOutputResult=options.tokenAccounting===!0?attachOutputTokenAccounting(intentOutputResult,renderResolvedOutput):intentOutputResult,rendered=renderResolvedOutput(accountedOutputResult);return setActiveCommandDeliveryResult(accountedOutputResult,effectiveResult,options.quiet!==!0&&structuredDeliveryPreserved),rendered}function formatOutput(result,options){const commandOverride=runActiveCommandOverride(result),suppressedOutput=isHostOutputSuppressed(commandOverride.result)?commandOverride.result:null,nativeResult=commandOverride.result,nativeOutput=isPlainObject(nativeResult)&&nativeResult[NATIVE_OUTPUT_MARKER]===!0,effectiveResult=suppressedOutput?suppressedOutput.result:stripNativeOutputMarker(commandOverride.result);if(setActiveCommandResult(effectiveResult),suppressedOutput)return setActiveCommandResultOmitted(effectiveResult),"";const defaultFormat=options.json===!0||options.json===void 0&&options.defaultOutputFormat==="json"?"json":"toon";return formatEffectiveOutput(effectiveResult,nativeOutput,options,defaultFormat)}function printResult(result,options){isPlainObject(result)&&Number.isInteger(result.exit_code)&&DECLARED_PROCESS_EXIT_CODES.has(Number(result.exit_code))&&(process.exitCode===void 0||process.exitCode===EXIT_CODE.SUCCESS)&&(process.exitCode=Number(result.exit_code));const projected=options.idOnly?projectMutationResult(result,{idOnly:!0}):options.fullChangedFields?result:options.noChangedFields?projectMutationResult(result,{changedFields:"compact"}):projectMutationResult(result,{compactEnvelope:!0}),rendered=formatOutput(projected,options);options.quiet||writeStdout(rendered)}function printError(message){const override=runActiveServiceOverrideSync("error_format",{message}),rendered=override.handled&&typeof override.result=="string"?override.result:message;writeStderr(rendered.endsWith(`
|
|
22
18
|
`)?rendered:`${rendered}
|
|
23
19
|
`)}const outputTestOnly={compactToonValue,renderToonValue};export{formatBuiltInOutput,formatOutput,outputTestOnly,printError,printResult,writeStderr,writeStdout};
|
|
24
20
|
//# sourceMappingURL=output.js.map
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { DatabaseSync } from "node:sqlite";
|
|
2
2
|
import type { ItemMetadata, LinkedFile, LinkScope } from "../../types/index.js";
|
|
3
|
+
import { loadDatabaseSync, loadStableDatabaseSync } from "./sqlite-runtime.js";
|
|
3
4
|
type DatabaseSyncConstructor = typeof DatabaseSync;
|
|
4
|
-
declare function loadDatabaseSync(loadModule: (specifier: string) => unknown): DatabaseSyncConstructor | null;
|
|
5
|
-
declare function loadStableDatabaseSync(nodeVersion: string, loadModule: (specifier: string) => unknown): DatabaseSyncConstructor | null;
|
|
6
5
|
/** One light-metadata row projected into the persistent query index. */
|
|
7
6
|
export interface ItemMetadataQueryIndexRow {
|
|
8
7
|
/** Tracker-relative authoritative item path. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="84a3dae8-69b6-589d-a8ec-11f77c1d103a")}catch{}})();import fs from"node:fs/promises";import path from"node:path";import{randomUUID}from"node:crypto";import{createRequire}from"node:module";import{loadDatabaseSync,loadStableDatabaseSync}from"./sqlite-runtime.js";const QUERY_INDEX_FILENAME="metadata-query-index.sqlite",QUERY_INDEX_VERSION="5";let RuntimeDatabaseSync;function resolveDatabaseSync(){return RuntimeDatabaseSync!==void 0||(RuntimeDatabaseSync=loadStableDatabaseSync(process.versions.node,createRequire(import.meta.url))),RuntimeDatabaseSync}function normalizeIndexWindowValue(value,fallback){return Math.max(0,Math.floor(value===void 0?fallback:value))}function queryIndexPath(pmRoot){return path.join(pmRoot,"runtime",QUERY_INDEX_FILENAME)}function createSchema(database){database.exec(`
|
|
2
2
|
PRAGMA foreign_keys = ON;
|
|
3
3
|
PRAGMA journal_mode = OFF;
|
|
4
4
|
PRAGMA synchronous = OFF;
|