@unbrained/pm-cli 2026.10.25 → 2026.10.26
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 +1 -1
- package/CHANGELOG.md +28 -0
- package/dist/cli/error-guidance.d.ts +5 -0
- package/dist/cli/error-guidance.js +2 -2
- package/dist/cli/register-mutation.js +2 -2
- package/dist/cli-bundle/bundle-manifest.json +1 -1
- package/dist/cli-bundle/chunks/{chunk-O3ZTGRIH.js → chunk-25MTQAHX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-TLMXSYJA.js → chunk-57YPOOED.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-4GD6QOP6.js → chunk-7UDQAINZ.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-LNKPH2DD.js → chunk-ER7RLJW5.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-YCCGZHOR.js → chunk-MWCG25PO.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-444VPGQT.js → chunk-N6FTEILW.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-FNZT4BTE.js → chunk-NGKTROAO.js} +86 -86
- package/dist/cli-bundle/chunks/chunk-OCDRHIVQ.js +6 -0
- package/dist/cli-bundle/chunks/{chunk-3CYXE6BV.js → chunk-ONC4BBQP.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-RQKDANP7.js → chunk-OUDR2HWR.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-RD6UW3MW.js → chunk-T7T4WLUY.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-MVJGGCGQ.js → chunk-TGOG5BFM.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-UF6EXZSP.js +2 -0
- package/dist/cli-bundle/chunks/chunk-VS2IIV3F.js +128 -0
- package/dist/cli-bundle/chunks/chunk-XAIR53QZ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-VAEB6IUQ.js → chunk-Y42DYMZX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-EYCVAAIP.js → chunk-YJBIPNDL.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-UI3FD3DW.js → chunk-Z35XAHUN.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-7C3GCLOO.js → chunk-ZLVFUZI4.js} +27 -27
- package/dist/cli-bundle/chunks/{chunk-7T3H24HN.js → chunk-ZT64RDMF.js} +2 -2
- package/dist/cli-bundle/chunks/{indexed-receipt-blobs-47I6KKDO.js → indexed-receipt-blobs-NWQIDTH7.js} +2 -2
- package/dist/cli-bundle/chunks/{mutation-admission-747C6IUR.js → mutation-admission-VTNV6JV2.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-COST6KRV.js → register-list-query-LZDWUZS4.js} +2 -2
- package/dist/cli-bundle/chunks/register-mutation-M2A7PH42.js +20 -0
- package/dist/cli-bundle/chunks/{register-operations-S4LKLUBJ.js → register-operations-E7P2JTXM.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-3ITZXPOL.js → register-setup-DOV7KGSH.js} +2 -2
- package/dist/cli-bundle/chunks/{settlement-hook-5IVCF6ZY.js → settlement-hook-SVD6CO7U.js} +2 -2
- package/dist/cli-bundle/chunks/{stage-3UUIYROS.js → stage-LYLEOAQB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-HMYDUEQK.js → chunk-226XKW3W.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-ABMNYWV6.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3M5FZCMC.js → chunk-ADSBGYLW.js} +8 -8
- package/dist/cli-bundle/focused-chunks/{chunk-22727JYL.js → chunk-B266DDBJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-Y4JHHY24.js → chunk-BH7RE2ZY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-BL77VCRB.js +22 -0
- package/dist/cli-bundle/focused-chunks/{chunk-77NU7NPN.js → chunk-CSCZYSNZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-URWYYJ7K.js → chunk-D5YQ4KAE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-ZYCOMRFT.js → chunk-E5C24MCV.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-74KC7FUQ.js → chunk-I7H3XF25.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-IF6C43IP.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-KERJNFXY.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-46KDJH3K.js → chunk-KTXU5WU6.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-NE27VCU7.js +91 -0
- package/dist/cli-bundle/focused-chunks/{chunk-NI5SG2M2.js → chunk-NFN2P4TW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-NC5HUGHU.js → chunk-NLZUI234.js} +4 -4
- package/dist/cli-bundle/focused-chunks/chunk-PK5FJIVA.js +12 -0
- package/dist/cli-bundle/focused-chunks/{chunk-LWJ2X75I.js → chunk-UHWTPOM4.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-B5JOVH5F.js → chunk-UP765R2V.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-U6HXIF6G.js → chunk-WDWHUJQW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-7DEZT4JN.js → chunk-YQKLKRMW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-YTEC2EPM.js +3 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3FM75SBJ.js → chunk-YW5GHQN2.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{indexed-receipt-blobs-YCLN2ZZG.js → indexed-receipt-blobs-YFDNGHCM.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{mutation-admission-BQBQXILV.js → mutation-admission-L42E3U5U.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{settlement-hook-XVS6P2XI.js → settlement-hook-3CADO4XZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{stage-VSIL4MTZ.js → stage-TUQHWU7N.js} +2 -2
- package/dist/cli-bundle/main.js +4 -4
- 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 +23 -23
- 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 +57 -57
- 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 +9 -9
- package/dist/core/extensions/extension-types.d.ts +3 -0
- package/dist/core/extensions/extension-types.js +1 -1
- package/dist/core/output/mutation-projection.js +1 -1
- package/dist/core/policy/workflow-policy-store.js +1 -1
- package/dist/core/shared/errors.d.ts +9 -0
- package/dist/core/shared/errors.js +1 -1
- package/dist/core/shared/secret-rules.d.ts +17 -0
- package/dist/core/shared/secret-rules.js +2 -1
- package/dist/core/store/item-mutation-precondition.d.ts +8 -0
- package/dist/core/store/item-mutation-precondition.js +1 -1
- package/dist/core/store/item-store.js +1 -1
- package/dist/sdk/cli-contracts/commander-mutation-options.js +1 -1
- package/dist/sdk/cli-contracts/completeness.js +1 -1
- package/dist/sdk/cli-contracts/flag-contracts.js +1 -1
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -1
- package/dist/sdk/cli-contracts/registration-helpers.d.ts +1 -1
- package/dist/sdk/cli-contracts/registration-helpers.js +1 -1
- package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +4 -0
- package/dist/sdk/cli-contracts/tool-option-contracts.js +1 -1
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -1
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +1 -1
- package/dist/sdk/context-signal-store.js +2 -2
- package/dist/sdk/core.d.ts +1 -1
- package/dist/sdk/core.js +1 -1
- package/dist/sdk/extension-command-context.js +2 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
- package/dist/sdk/index.d.ts +2 -1
- package/dist/sdk/index.js +1 -1
- package/dist/sdk/item-transaction.js +1 -1
- package/dist/sdk/lifecycle/close-many.d.ts +3 -0
- package/dist/sdk/lifecycle/close-many.js +1 -1
- package/dist/sdk/lifecycle/close.d.ts +3 -1
- package/dist/sdk/lifecycle/close.js +1 -1
- package/dist/sdk/lifecycle/create.d.ts +2 -0
- package/dist/sdk/lifecycle/create.js +1 -1
- package/dist/sdk/lifecycle/plan.d.ts +2 -0
- package/dist/sdk/lifecycle/plan.js +1 -1
- package/dist/sdk/lifecycle/restore.js +1 -1
- package/dist/sdk/lifecycle-policy.d.ts +11 -0
- package/dist/sdk/lifecycle-policy.js +1 -1
- package/dist/sdk/mutation-guard.d.ts +6 -1
- package/dist/sdk/mutation-guard.js +1 -1
- package/dist/sdk/output/fit-envelope.d.ts +98 -0
- package/dist/sdk/output/fit-envelope.js +2 -0
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query.d.ts +1 -0
- package/dist/sdk/query.js +1 -1
- package/dist/sdk/read-output-session.d.ts +1 -1
- package/dist/sdk/read-output-session.js +1 -1
- package/dist/sdk/runtime-input.js +1 -1
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +1 -1
- package/dist/sdk/runtime.d.ts +2 -2
- package/dist/sdk/runtime.js +1 -1
- package/dist/sdk/scheduling-shortcuts.d.ts +2 -0
- package/dist/sdk/scheduling-shortcuts.js +1 -1
- package/dist/sdk/workspace-transaction.d.ts +3 -1
- package/dist/sdk/workspace-transaction.js +2 -2
- package/docs/COMMANDS.md +2 -1
- package/docs/MUTATION_INTEGRITY.md +33 -0
- package/docs/QUALITY_EVIDENCE.md +9 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +55 -1
- package/docs/SDK.md +88 -6
- package/docs/WORKFLOW_POLICIES.md +14 -1
- package/docs/agent-task-token-baseline.json +1 -1
- package/docs/agent-task-transcripts.json +1 -1
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +2 -2
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
- package/marketplace.json +1 -1
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/extensions/calendar/shortcuts.ts +2 -2
- 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 +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/package.json +1 -1
- package/plugins/pm-codex/plugin.json +1 -1
- package/runtime-dependencies.json +1 -1
- package/dist/cli-bundle/chunks/chunk-5ZPT67NJ.js +0 -127
- package/dist/cli-bundle/chunks/chunk-HMJSFWHK.js +0 -2
- package/dist/cli-bundle/chunks/chunk-RLXK2S7P.js +0 -2
- package/dist/cli-bundle/chunks/chunk-XYLBOXSH.js +0 -6
- package/dist/cli-bundle/chunks/register-mutation-JZVVJUHY.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-5LBZR6YW.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-IVLIUPVV.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-KIIGME23.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-MT5TYMEU.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-QH5KMIYZ.js +0 -91
- package/dist/cli-bundle/focused-chunks/chunk-W7MCCFYV.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-WMPDY5ZU.js +0 -21
|
@@ -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
|
-
`)}function hasValidJournalMetadata(journal){return Number.isInteger(journal.attempt)&&typeof journal.author=="string"&&typeof journal.createdAt=="string"&&typeof journal.updatedAt=="string"}function createResultMap(source){return Object.assign(Object.create(null),source)}function cloneJournalValue(value,label){try{const serialized=JSON.stringify(value,(_key,nestedValue)=>{if(typeof nestedValue=="number"&&!Number.isFinite(nestedValue))throw new TypeError(`${label} contains a non-finite number`);if(nestedValue===void 0||typeof nestedValue=="function"||typeof nestedValue=="symbol")throw new TypeError(`${label} contains a non-JSON value`);return nestedValue});return JSON.parse(serialized)}catch(error){throw new TypeError(`${label} must be JSON serializable`,{cause:error})}}function cloneOptionalJournalValue(value,label){return value===void 0?void 0:cloneJournalValue(value,label)}function setJournalEntry(target,stepId,value,label){const cloned=cloneOptionalJournalValue(value,label);cloned===void 0?delete target[stepId]:target[stepId]=cloned}function isJournalMap(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function hasUniqueKnownStepIds(value,stepIds){return Array.isArray(value)&&new Set(value).size===value.length&&value.every(stepId=>typeof stepId=="string"&&stepIds.includes(stepId))}function hasValidJournalLifecycle(journal,stepIds){if(!hasUniqueKnownStepIds(journal.startedStepIds,stepIds)||!hasUniqueKnownStepIds(journal.completedStepIds,stepIds)||!isJournalMap(journal.results)||!isJournalMap(journal.compensationData))return!1;const startedStepIds=journal.startedStepIds,started=new Set(startedStepIds),completedStepIds=journal.completedStepIds,completed=new Set(completedStepIds);return Object.keys(journal.compensationData).some(stepId=>!started.has(stepId))||Object.keys(journal.results).some(stepId=>!completed.has(stepId))?!1:journal.status==="committed"?stepIds.every(stepId=>completed.has(stepId)):journal.status!=="compensated"||completed.size===0&&started.size===0}function invalidJournal(transactionId,detail){return new PmCliError(`Workspace transaction ${transactionId} journal is invalid (${detail})`,EXIT_CODE.CONFLICT,{code:"transaction_journal_invalid",required:"A valid durable journal is required before transaction recovery can continue.",why:"Corrupt journal data cannot establish which steps applied or still require compensation.",nextSteps:["Preserve the journal and inspect its integrity or restore a verified backup before retrying.","Do not switch to a new transaction id to bypass an unreadable journal; previously applied work may remain."]})}function journalPlanMismatch(transactionId){return new PmCliError(`Workspace transaction ${transactionId} journal does not match the supplied plan`,EXIT_CODE.CONFLICT,{code:"transaction_plan_mismatch",required:"Replay the exact plan that started this transaction, or start a new transaction with a different id.",why:"A journal records the plan it is resuming; applying a different plan under the same id could skip or duplicate steps.",nextSteps:["Re-run with the original document to resume or replay it.","Pass --transaction-id <new-id> (or a new transactionId over MCP) to commit the changed plan as its own transaction.","Run pm ops gc --scope transactions --dry-run to inspect abandoned journals before pruning them."]})}function parseJournal(raw,transactionId,stepIds){let parsed;try{parsed=JSON.parse(raw)}catch{throw invalidJournal(transactionId,"invalid JSON")}if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw invalidJournal(transactionId,"expected an object");const journal=parsed;if(!(journal.schemaVersion===1&&journal.transactionId===transactionId))throw invalidJournal(transactionId,"schema version or transaction id does not match the journal file");const recordedStepIds=journal.stepIds;if(!Array.isArray(recordedStepIds)||!hasUniqueKnownStepIds(recordedStepIds,recordedStepIds)||!hasValidJournalLifecycle(journal,recordedStepIds)||!hasValidJournalMetadata(journal)||typeof journal.status!="string"||!["applying","compensating","compensated","committed"].includes(journal.status))throw invalidJournal(transactionId,"invalid lifecycle, metadata, status or step ids");if(!(journal.status==="compensated"||recordedStepIds.length===stepIds.length&&recordedStepIds.every((stepId,index)=>stepId===stepIds[index])))throw journalPlanMismatch(transactionId);return{...journal,results:createResultMap(journal.results),compensationData:createResultMap(journal.compensationData)}}async function prepareJournalForApply(options,transactionId,author,stepIds,existing){let journal=existing;const recovered=journal!==void 0;if(journal?.status==="compensating"&&await compensateAppliedSteps(options,journal),journal===void 0||journal.status==="compensated"){const timestamp=nowIso();journal={schemaVersion:1,transactionId,author,status:"applying",attempt:(journal?.attempt??0)+1,createdAt:journal?.createdAt??timestamp,updatedAt:timestamp,stepIds,startedStepIds:[],completedStepIds:[],results:createResultMap(),compensationData:createResultMap()},await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"prepared")}return{journal,recovered}}async function applyPreparedTransaction(options,journal,recovered){try{await discoverAppliedSteps(journal,options.steps),await writeJournal(options.pmRoot,journal);const completed=new Set(journal.completedStepIds),started=new Set(journal.startedStepIds);for(const step of options.steps){if(completed.has(step.id))continue;const inspection=await step.inspect();let result=cloneOptionalJournalValue(inspection.result,`Step ${step.id} result`);if(inspection.state!=="applied"){const compensationData=await step.prepareCompensation?.();setJournalEntry(journal.compensationData,step.id,compensationData,`Step ${step.id} compensation data`),started.add(step.id),journal.startedStepIds=options.steps.map(candidate=>candidate.id).filter(stepId=>started.has(stepId)),await writeJournal(options.pmRoot,journal);const appliedResult=await step.apply();result=cloneOptionalJournalValue(appliedResult,`Step ${step.id} result`)}await emitTransition(options,journal,"step_applied",step.id),completed.add(step.id),journal.completedStepIds=options.steps.map(candidate=>candidate.id).filter(stepId=>completed.has(stepId)),setJournalEntry(journal.results,step.id,result,`Step ${step.id} result`),await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"step_recorded",step.id)}return await emitTransition(options,journal,"committing"),journal.status="committed",await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"committed"),{transactionId:journal.transactionId,status:"committed",recovered,results:createResultMap(journal.results)}}catch(error){if(error instanceof WorkspaceTransactionInterruptedError||journal.status==="committed")throw error;try{await compensateAppliedSteps(options,journal)}catch(compensationError){throw new AggregateError([error,compensationError],`Workspace transaction failed and compensation failed: ${String(compensationError)}`,{cause:compensationError})}throw error}}async function loadJournal(pmRoot,transactionId,stepIds){try{return parseJournal(await readFile(journalPath(pmRoot,transactionId),"utf8"),transactionId,stepIds)}catch(error){if(error!==null&&typeof error=="object"&&"code"in error&&isFileMissingError(error))return;throw error}}async function emitTransition(options,journal,transition,stepId){await options.onTransition?.({transactionId:journal.transactionId,attempt:journal.attempt,transition,...stepId===void 0?{}:{stepId}})}async function discoverAppliedSteps(journal,steps){const completed=new Set,results=createResultMap();for(const step of steps){const inspection=await step.inspect();inspection.state==="applied"&&(completed.add(step.id),setJournalEntry(results,step.id,inspection.result,`Step ${step.id} result`))}journal.results=results,journal.completedStepIds=steps.map(step=>step.id).filter(stepId=>completed.has(stepId))}async function compensateAppliedSteps(options,journal){journal.status="compensating",await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"compensating");const completed=new Set(journal.completedStepIds),started=new Set(journal.startedStepIds);for(const step of[...options.steps].reverse()){if(!started.has(step.id)&&!completed.has(step.id))continue;let shouldCompensate;try{shouldCompensate=started.has(step.id)&&(await step.inspect()).state==="applied"}catch{shouldCompensate=started.has(step.id)}shouldCompensate&&(await emitTransition(options,journal,"step_compensating",step.id),await step.compensate(journal.compensationData[step.id])),completed.delete(step.id),started.delete(step.id),journal.completedStepIds=options.steps.map(candidate=>candidate.id).filter(stepId=>completed.has(stepId)),journal.startedStepIds=options.steps.map(candidate=>candidate.id).filter(stepId=>started.has(stepId)),delete journal.results[step.id],delete journal.compensationData[step.id],await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"step_compensated",step.id)}journal.status="compensated",await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"compensated")}async function commitWorkspaceTransaction(options){const{pmRoot,transactionId,author}=validateWorkspaceTransactionIdentity(options),lockTtlSeconds=positiveInteger(options.lockTtlSeconds,DEFAULT_LOCK_TTL_SECONDS,"Transaction lock TTL"),lockWaitMs=positiveInteger(options.lockWaitMs,DEFAULT_LOCK_WAIT_MS,"Transaction lock wait"),steps=[...options.steps];if(steps.length===0)throw new TypeError("Workspace transaction requires at least one step");const stepIds=steps.map(step=>{const stepId=requiredIdentifier(step.id,"Transaction step id");if(stepId!==step.id)throw new TypeError("Transaction step id must not contain surrounding whitespace");return stepId});if(new Set(stepIds).size!==stepIds.length)throw new TypeError("Workspace transaction step ids must be unique");const stableOptions={...options,pmRoot,transactionId,author,steps,lockTtlSeconds,lockWaitMs},release=await acquireLock(pmRoot,WORKSPACE_TRANSACTION_LOCK_ID,lockTtlSeconds,author,!1,!1,lockWaitMs);try{const existing=await loadJournal(pmRoot,transactionId,stepIds),recovered=existing!==void 0;if(existing?.status==="committed")return{transactionId,status:"committed",recovered:!0,results:createResultMap(existing.results)};const prepared=await prepareJournalForApply(stableOptions,transactionId,author,stepIds,existing);return await applyPreparedTransaction(stableOptions,prepared.journal,recovered||prepared.recovered)}finally{await release()}}export{WorkspaceTransactionInterruptedError,commitWorkspaceTransaction,validateWorkspaceTransactionIdentity};
|
|
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]="d913251a-fc99-5767-b19d-ae9473adc138")}catch{}})();import{mkdir,readFile}from"node:fs/promises";import path from"node:path";import{acquireLock}from"../core/lock/lock.js";import{isFileMissingError,writeFileAtomic}from"../core/fs/fs-utils.js";import{nowIso}from"../core/shared/time.js";import{EXIT_CODE}from"../core/shared/constants.js";import{PmCliError}from"../core/shared/errors.js";class WorkspaceTransactionInterruptedError extends Error{constructor(message="Workspace transaction interrupted"){super(message),this.name="WorkspaceTransactionInterruptedError"}}const WORKSPACE_TRANSACTION_LOCK_ID="sdk-workspace-transaction",TRANSACTION_ID_PATTERN=/^[a-zA-Z0-9._-]+$/,DEFAULT_LOCK_TTL_SECONDS=30,DEFAULT_LOCK_WAIT_MS=3e3;function requiredIdentifier(value,label){if(typeof value!="string")throw new TypeError(`${label} must be a string`);const normalized=value.trim();if(!normalized||!TRANSACTION_ID_PATTERN.test(normalized))throw new TypeError(`${label} must match [a-zA-Z0-9._-]+`);return normalized}function requiredText(value,label){if(typeof value!="string")throw new TypeError(`${label} must be a string`);const normalized=value.trim();if(!normalized)throw new TypeError(`${label} must be non-empty`);return normalized}function validateWorkspaceTransactionIdentity(options){return{pmRoot:requiredText(options.pmRoot,"Transaction pmRoot"),transactionId:requiredIdentifier(options.transactionId,"Transaction id"),author:requiredText(options.author,"Transaction author")}}function positiveInteger(value,fallback,label){const resolved=value??fallback;if(!Number.isInteger(resolved)||resolved<=0)throw new TypeError(`${label} must be a positive integer`);return resolved}function journalPath(pmRoot,transactionId){return path.join(pmRoot,"transactions","sdk",`${transactionId}.json`)}async function writeJournal(pmRoot,journal){journal.updatedAt=nowIso();const target=journalPath(pmRoot,journal.transactionId);await mkdir(path.dirname(target),{recursive:!0}),await writeFileAtomic(target,`${JSON.stringify(journal,null,2)}
|
|
2
|
+
`)}function hasValidJournalMetadata(journal){return Number.isInteger(journal.attempt)&&typeof journal.author=="string"&&typeof journal.createdAt=="string"&&typeof journal.updatedAt=="string"}function createResultMap(source){return Object.assign(Object.create(null),source)}function cloneJournalValue(value,label){try{const serialized=JSON.stringify(value,(_key,nestedValue)=>{if(typeof nestedValue=="number"&&!Number.isFinite(nestedValue))throw new TypeError(`${label} contains a non-finite number`);if(nestedValue===void 0||typeof nestedValue=="function"||typeof nestedValue=="symbol")throw new TypeError(`${label} contains a non-JSON value`);return nestedValue});return JSON.parse(serialized)}catch(error){throw new TypeError(`${label} must be JSON serializable`,{cause:error})}}function cloneOptionalJournalValue(value,label){return value===void 0?void 0:cloneJournalValue(value,label)}function setJournalEntry(target,stepId,value,label){const cloned=cloneOptionalJournalValue(value,label);cloned===void 0?delete target[stepId]:target[stepId]=cloned}function isJournalMap(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function hasUniqueKnownStepIds(value,stepIds){return Array.isArray(value)&&new Set(value).size===value.length&&value.every(stepId=>typeof stepId=="string"&&stepIds.includes(stepId))}function hasValidJournalLifecycle(journal,stepIds){if(!hasUniqueKnownStepIds(journal.startedStepIds,stepIds)||!hasUniqueKnownStepIds(journal.completedStepIds,stepIds)||!isJournalMap(journal.results)||!isJournalMap(journal.compensationData))return!1;const startedStepIds=journal.startedStepIds,started=new Set(startedStepIds),completedStepIds=journal.completedStepIds,completed=new Set(completedStepIds);return Object.keys(journal.compensationData).some(stepId=>!started.has(stepId))||Object.keys(journal.results).some(stepId=>!completed.has(stepId))?!1:journal.status==="committed"?stepIds.every(stepId=>completed.has(stepId)):journal.status!=="compensated"||completed.size===0&&started.size===0}function invalidJournal(transactionId,detail){return new PmCliError(`Workspace transaction ${transactionId} journal is invalid (${detail})`,EXIT_CODE.CONFLICT,{code:"transaction_journal_invalid",required:"A valid durable journal is required before transaction recovery can continue.",why:"Corrupt journal data cannot establish which steps applied or still require compensation.",nextSteps:["Preserve the journal and inspect its integrity or restore a verified backup before retrying.","Do not switch to a new transaction id to bypass an unreadable journal; previously applied work may remain."]})}function journalPlanMismatch(transactionId){return new PmCliError(`Workspace transaction ${transactionId} journal does not match the supplied plan`,EXIT_CODE.CONFLICT,{code:"transaction_plan_mismatch",required:"Replay the exact plan that started this transaction, or start a new transaction with a different id.",why:"A journal records the plan it is resuming; applying a different plan under the same id could skip or duplicate steps.",nextSteps:["Re-run with the original document to resume or replay it.","Pass --transaction-id <new-id> (or a new transactionId over MCP) to commit the changed plan as its own transaction.","Run pm ops gc --scope transactions --dry-run to inspect abandoned journals before pruning them."]})}function parseJournal(raw,transactionId,stepIds){let parsed;try{parsed=JSON.parse(raw)}catch{throw invalidJournal(transactionId,"invalid JSON")}if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw invalidJournal(transactionId,"expected an object");const journal=parsed;if(!(journal.schemaVersion===1&&journal.transactionId===transactionId))throw invalidJournal(transactionId,"schema version or transaction id does not match the journal file");const recordedStepIds=journal.stepIds;if(!Array.isArray(recordedStepIds)||!hasUniqueKnownStepIds(recordedStepIds,recordedStepIds)||!hasValidJournalLifecycle(journal,recordedStepIds)||!hasValidJournalMetadata(journal)||typeof journal.status!="string"||!["applying","compensating","compensated","committed"].includes(journal.status))throw invalidJournal(transactionId,"invalid lifecycle, metadata, status or step ids");if(!(journal.status==="compensated"||recordedStepIds.length===stepIds.length&&recordedStepIds.every((stepId,index)=>stepId===stepIds[index])))throw journalPlanMismatch(transactionId);return{...journal,results:createResultMap(journal.results),compensationData:createResultMap(journal.compensationData)}}async function prepareJournalForApply(options,transactionId,author,stepIds,existing){let journal=existing;const recovered=journal!==void 0;if(journal?.status==="compensating"&&await compensateAppliedSteps(options,journal),journal===void 0||journal.status==="compensated"){const timestamp=nowIso();journal={schemaVersion:1,transactionId,author,status:"applying",attempt:(journal?.attempt??0)+1,createdAt:journal?.createdAt??timestamp,updatedAt:timestamp,stepIds,startedStepIds:[],completedStepIds:[],results:createResultMap(),compensationData:createResultMap()},await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"prepared")}return{journal,recovered}}async function applyPreparedTransaction(options,journal,recovered){try{await discoverAppliedSteps(journal,options.steps),await writeJournal(options.pmRoot,journal);const completed=new Set(journal.completedStepIds),started=new Set(journal.startedStepIds);for(const step of options.steps){if(completed.has(step.id))continue;const inspection=await step.inspect();let result=cloneOptionalJournalValue(inspection.result,`Step ${step.id} result`);if(inspection.state!=="applied"){const compensationData=await step.prepareCompensation?.();setJournalEntry(journal.compensationData,step.id,compensationData,`Step ${step.id} compensation data`),started.add(step.id),journal.startedStepIds=options.steps.map(candidate=>candidate.id).filter(stepId=>started.has(stepId)),await writeJournal(options.pmRoot,journal);const appliedResult=await step.apply();result=cloneOptionalJournalValue(appliedResult,`Step ${step.id} result`)}await emitTransition(options,journal,"step_applied",step.id),completed.add(step.id),journal.completedStepIds=options.steps.map(candidate=>candidate.id).filter(stepId=>completed.has(stepId)),setJournalEntry(journal.results,step.id,result,`Step ${step.id} result`),await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"step_recorded",step.id)}return await emitTransition(options,journal,"committing"),journal.status="committed",await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"committed"),{transactionId:journal.transactionId,status:"committed",recovered,results:createResultMap(journal.results)}}catch(error){if(error instanceof WorkspaceTransactionInterruptedError||journal.status==="committed")throw error;try{await compensateAppliedSteps(options,journal)}catch(compensationError){throw new AggregateError([error,compensationError],`Workspace transaction failed and compensation failed: ${String(compensationError)}`,{cause:compensationError})}throw error}}async function loadJournal(pmRoot,transactionId,stepIds){try{return parseJournal(await readFile(journalPath(pmRoot,transactionId),"utf8"),transactionId,stepIds)}catch(error){if(error!==null&&typeof error=="object"&&"code"in error&&isFileMissingError(error))return;throw error}}async function emitTransition(options,journal,transition,stepId){await options.onTransition?.({transactionId:journal.transactionId,attempt:journal.attempt,transition,...stepId===void 0?{}:{stepId}})}async function discoverAppliedSteps(journal,steps){const completed=new Set,results=createResultMap();for(const step of steps){const inspection=await step.inspect();inspection.state==="applied"&&(completed.add(step.id),setJournalEntry(results,step.id,inspection.result,`Step ${step.id} result`))}journal.results=results,journal.completedStepIds=steps.map(step=>step.id).filter(stepId=>completed.has(stepId))}async function compensateAppliedSteps(options,journal){journal.status="compensating",await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"compensating");const completed=new Set(journal.completedStepIds),started=new Set(journal.startedStepIds);for(const step of[...options.steps].reverse()){if(!started.has(step.id)&&!completed.has(step.id))continue;let shouldCompensate;try{const state=(await step.inspect()).state;shouldCompensate=started.has(step.id)&&(state==="applied"||state==="pending"&&step.compensatePending===!0)}catch{shouldCompensate=started.has(step.id)}shouldCompensate&&(await emitTransition(options,journal,"step_compensating",step.id),await step.compensate(journal.compensationData[step.id])),completed.delete(step.id),started.delete(step.id),journal.completedStepIds=options.steps.map(candidate=>candidate.id).filter(stepId=>completed.has(stepId)),journal.startedStepIds=options.steps.map(candidate=>candidate.id).filter(stepId=>started.has(stepId)),delete journal.results[step.id],delete journal.compensationData[step.id],await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"step_compensated",step.id)}journal.status="compensated",await writeJournal(options.pmRoot,journal),await emitTransition(options,journal,"compensated")}async function commitWorkspaceTransaction(options){const{pmRoot,transactionId,author}=validateWorkspaceTransactionIdentity(options),lockTtlSeconds=positiveInteger(options.lockTtlSeconds,DEFAULT_LOCK_TTL_SECONDS,"Transaction lock TTL"),lockWaitMs=positiveInteger(options.lockWaitMs,DEFAULT_LOCK_WAIT_MS,"Transaction lock wait"),steps=[...options.steps];if(steps.length===0)throw new TypeError("Workspace transaction requires at least one step");const stepIds=steps.map(step=>{const stepId=requiredIdentifier(step.id,"Transaction step id");if(stepId!==step.id)throw new TypeError("Transaction step id must not contain surrounding whitespace");return stepId});if(new Set(stepIds).size!==stepIds.length)throw new TypeError("Workspace transaction step ids must be unique");const stableOptions={...options,pmRoot,transactionId,author,steps,lockTtlSeconds,lockWaitMs},release=await acquireLock(pmRoot,WORKSPACE_TRANSACTION_LOCK_ID,lockTtlSeconds,author,!1,!1,lockWaitMs);try{const existing=await loadJournal(pmRoot,transactionId,stepIds),recovered=existing!==void 0;if(existing?.status==="committed")return{transactionId,status:"committed",recovered:!0,results:createResultMap(existing.results)};const prepared=await prepareJournalForApply(stableOptions,transactionId,author,stepIds,existing);return await applyPreparedTransaction(stableOptions,prepared.journal,recovered||prepared.recovered)}finally{await release()}}export{WorkspaceTransactionInterruptedError,commitWorkspaceTransaction,validateWorkspaceTransactionIdentity};
|
|
3
3
|
//# sourceMappingURL=workspace-transaction.js.map
|
package/docs/COMMANDS.md
CHANGED
|
@@ -818,7 +818,8 @@ pm focus --clear # clear focus; new items stop inheriting a parent
|
|
|
818
818
|
Behavior and guarantees:
|
|
819
819
|
|
|
820
820
|
- Focus is **session-local**: it is stored in `.agents/pm/runtime/session.json`, which is gitignored, so it never affects teammates or the tracker's git history.
|
|
821
|
-
- When a focus is set and `pm create` is run **without** `--parent`, the new item inherits the focused item as its parent
|
|
821
|
+
- When a focus is set and `pm create` or `pm plan create` is run **without** `--parent`, the new item inherits the focused item as its parent. With `--full-changed-fields`, `pm create` reports `"parent_source": "focus"`; `pm plan create` exposes the effective parent as `plan.parent`.
|
|
822
|
+
- `--no-inherit-focus` or `--parent none` suppresses inheritance (`pm create` also accepts `--unset parent`). SDK and MCP creates, including plans, default to ignoring saved focus and opt in with `inheritFocus: true` ([pm-gh1577](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1577.toon); this tracker record is repository-only and excluded from npm).
|
|
822
823
|
- An explicit `--parent` always overrides focus, including `--parent none` (create with no parent). An explicit but unresolvable focused parent produces the same missing-parent error/warning as an explicit stale `--parent` (it flows through the same `validation.parent_reference` policy).
|
|
823
824
|
- `pm focus <id>` validates the item exists and fails fast with a not-found error otherwise. `pm focus --clear <id>` is a usage error (choose either set or clear).
|
|
824
825
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Tracker references: [pm-h90s](../.agents/pm/issues/pm-h90s.toon), [pm-pim7](../.agents/pm/features/pm-pim7.toon), [pm-w8q4](../.agents/pm/features/pm-w8q4.toon), [pm-9yfo](../.agents/pm/tasks/pm-9yfo.toon), [pm-wwooxx](../.agents/pm/issues/pm-wwooxx.toon), [pm-3kk6](../.agents/pm/issues/pm-3kk6.toon)
|
|
4
4
|
|
|
5
|
+
Concrete home-path normalization is tracked by [pm-gh1583](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1583.toon). Tracker records are repository-only and excluded from npm.
|
|
6
|
+
|
|
5
7
|
`pm` treats mutation provenance and content safety as shared SDK policy. CLI,
|
|
6
8
|
MCP, and package hosts can therefore enforce the same rules without duplicating
|
|
7
9
|
argument parsing or exposing detected values.
|
|
@@ -70,6 +72,10 @@ whether a blocking policy was explicitly overridden. `scanMutationSecrets` is
|
|
|
70
72
|
available separately for package-specific preflight UIs. Cyclic inputs are
|
|
71
73
|
safe; scanner failures fail open with `secret_guard_scan_failed_open`.
|
|
72
74
|
|
|
75
|
+
Direct SDK persistence does not automatically apply this host preflight.
|
|
76
|
+
Integrations that require the policy must evaluate it before dispatching their
|
|
77
|
+
SDK mutations. CLI and MCP adapters already do this.
|
|
78
|
+
|
|
73
79
|
The SDK guard and repository scanner consume one inventory in
|
|
74
80
|
`src/core/shared/secret-rules.ts`. It covers GitHub, npm, Slack, AWS access
|
|
75
81
|
keys (including temporary keys), Google, Anthropic, OpenAI, GitLab, Sentry,
|
|
@@ -91,6 +97,33 @@ remains advisory; a workspace selecting `block` must replace those literals
|
|
|
91
97
|
with references or explicitly review a force override. CLI routing paths and
|
|
92
98
|
payload content are distinct: pass only content to package-owned preflight.
|
|
93
99
|
|
|
100
|
+
Home-path detection recognizes concrete POSIX and macOS account roots, root
|
|
101
|
+
subdirectories, Windows user profiles, UNC profile shares, DOS device namespace
|
|
102
|
+
profiles, and explicit file URLs. Device prefixes follow the
|
|
103
|
+
[documented Windows path families](https://learn.microsoft.com/dotnet/standard/io/file-path-formats).
|
|
104
|
+
It accepts surrounding markup and punctuation. Detection-only views
|
|
105
|
+
decode percent-byte runs, serialized slash/character escapes, and documented
|
|
106
|
+
Unicode disguises. Unicode handling applies NFKC, removes zero-width/bidi
|
|
107
|
+
controls, and folds division/fraction slashes and Cyrillic look-alikes for the
|
|
108
|
+
path vocabulary's letters o and s. These are finite heuristics, not filesystem
|
|
109
|
+
canonicalization or a complete confidentiality guarantee.
|
|
110
|
+
|
|
111
|
+
Inspection is limited to four normalization passes per original line. Findings
|
|
112
|
+
can include typed `normalizations` identifiers; original and decoded values are
|
|
113
|
+
never returned, and payloads are never rewritten. If encoding remains after the
|
|
114
|
+
limit, `normalization_incomplete: true` conservatively requires review using
|
|
115
|
+
the same advisory/blocking policy. It applies to the entire string leaf, even
|
|
116
|
+
when an earlier line already contained a concrete path. A blocking workspace
|
|
117
|
+
may explicitly force a reviewed value. Repository diagnostics retain original source lines, including
|
|
118
|
+
when an encoded value contains a newline.
|
|
119
|
+
|
|
120
|
+
Portable references remain literal: current-user and named tilde references,
|
|
121
|
+
home environment variables, and Windows profile variables are not expanded
|
|
122
|
+
using the scanner's host. They do not establish a concrete absolute coordinate.
|
|
123
|
+
Ordinary web URLs and relative paths are also preserved. Package-specific
|
|
124
|
+
policies may classify additional context, but must not treat an empty finding
|
|
125
|
+
list as proof that arbitrary content is safe to publish.
|
|
126
|
+
|
|
94
127
|
Nested settings reads use own properties. Writes reject empty and prototype
|
|
95
128
|
path segments before changing any object, create local containers for inherited
|
|
96
129
|
values, and define own data properties without invoking inherited setters. Findings expose only the stable rule
|
package/docs/QUALITY_EVIDENCE.md
CHANGED
|
@@ -54,6 +54,15 @@ their real emitted-byte counts may differ. Output growth still fails the
|
|
|
54
54
|
unchanged ceilings; normalization does not waive accounting, payload parity,
|
|
55
55
|
required-field or executable-recovery checks.
|
|
56
56
|
|
|
57
|
+
The completion-provenance delivery
|
|
58
|
+
([pm-gh1579](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1579.toon),
|
|
59
|
+
a repository-only tracker record excluded from npm) makes the existing close and
|
|
60
|
+
partial-bulk transcripts consume completion timestamp, source and correction
|
|
61
|
+
guidance. Their reviewed ceilings increase by 76 and 80 estimated tokens
|
|
62
|
+
respectively to account for this new required context. Other task and step
|
|
63
|
+
ceilings, orientation selection, output accounting and the seeded growth
|
|
64
|
+
negative control retain their existing enforcement.
|
|
65
|
+
|
|
57
66
|
## SDK mutation testing
|
|
58
67
|
|
|
59
68
|
`pnpm quality:mutation` uses Stryker's Vitest runner to mutate the SDK cursor and
|
|
@@ -4,6 +4,10 @@ Tracker references: [pm-15yuly](../.agents/pm/issues/pm-15yuly.toon), [pm-g8oh0f
|
|
|
4
4
|
|
|
5
5
|
## Agent Quick Context
|
|
6
6
|
|
|
7
|
+
Complete package-envelope fitting and session-reference recovery are tracked by
|
|
8
|
+
[pm-gh1567](../.agents/pm/issues/pm-gh1567.toon) and
|
|
9
|
+
[pm-session-reference-recovery](../.agents/pm/issues/pm-session-reference-recovery.toon).
|
|
10
|
+
|
|
7
11
|
Every built-in read surface uses four output dimensions: what to include, how much to return, how much the result may cost, and how to encode it. The same canonical controls work through the CLI, SDK, MCP, generated schemas, runtime contracts, and shell completions.
|
|
8
12
|
|
|
9
13
|
| Dimension | CLI | SDK and MCP | Meaning |
|
|
@@ -27,6 +31,56 @@ repeated metadata from results by default. Request
|
|
|
27
31
|
`--output-row-contract` / `outputRowContract: true` when a consumer needs the
|
|
28
32
|
row paths, jq selector, and active TOON encoding contract.
|
|
29
33
|
|
|
34
|
+
### Package-defined complete envelopes
|
|
35
|
+
|
|
36
|
+
`fitOutputEnvelope` is available from `@unbrained/pm-cli/sdk/query`, the
|
|
37
|
+
aggregate SDK, and an extension command's `sdk.fitOutputEnvelope`. It fits
|
|
38
|
+
ordered whole rows into a caller-defined envelope without changing domain
|
|
39
|
+
ranking, metadata or transport policy:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { fitOutputEnvelope } from "@unbrained/pm-cli/sdk/query";
|
|
43
|
+
|
|
44
|
+
const fitted = fitOutputEnvelope([{ id: "one", title: "Context" }], {
|
|
45
|
+
tokenBudget: 800,
|
|
46
|
+
buildEnvelope: (items) => ({ source: "my-package", items }),
|
|
47
|
+
renderers: { json: (value) => JSON.stringify(value) + "\n" },
|
|
48
|
+
});
|
|
49
|
+
process.stdout.write(fitted.renderings[0]!.text);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The SDK reserves `output_fit`, attaches the omission/accounting receipt, and
|
|
53
|
+
stabilizes its `estimated_tokens` and `output_bytes` against complete output,
|
|
54
|
+
including the receipt itself and caller-supplied framing. Multiple required
|
|
55
|
+
renderers may be supplied, such as JSON and TOON; each must fit, and the receipt
|
|
56
|
+
records the greatest token estimate and byte count independently. Emit a cached
|
|
57
|
+
rendering directly: another serializer or extra newline changes its cost.
|
|
58
|
+
`buildEnvelope` can read the receipt for a package-owned self-accounting field.
|
|
59
|
+
|
|
60
|
+
The default estimator is `ceil(UTF-8 bytes / 4)`. Supply `estimateTokens` for
|
|
61
|
+
another contract, including a stronger one-token-per-byte bound. Estimates are
|
|
62
|
+
not a tokenizer guarantee. Callbacks must be pure, deterministic, promptly
|
|
63
|
+
returning, and include mandatory metadata in every rendering. The SDK does not
|
|
64
|
+
interpret package fields or provider authentication.
|
|
65
|
+
|
|
66
|
+
The default `prefix` policy stops at the first row that does not fit. `skip`
|
|
67
|
+
tries later rows without changing their order. The receipt retains original
|
|
68
|
+
`included_indices`, `total_candidates` and `omitted_count`; `complete` on the
|
|
69
|
+
result means all candidate rows fit. Neither policy splits rows or assumes
|
|
70
|
+
serialized size is monotone. A smaller budget does not promise nested selected
|
|
71
|
+
sets under `skip`; use `prefix` when prefix continuity matters.
|
|
72
|
+
|
|
73
|
+
The empty mandatory envelope must fit before any row is attempted.
|
|
74
|
+
`OutputEnvelopeFitError.code` distinguishes `output_envelope_infeasible`
|
|
75
|
+
(with `minimum_tokens`), `output_envelope_work_limit`, and
|
|
76
|
+
`output_envelope_unstable`. No unverified or oversized packet is returned.
|
|
77
|
+
`maxRenderCalls` defaults to 10,000 across every trial and renderer;
|
|
78
|
+
`maxStabilizationPasses` defaults to 16 per trial. Actual renderer calls and
|
|
79
|
+
evaluated candidates are reported in `work`, outside the measured packet.
|
|
80
|
+
These ceilings bound fitting work; they cannot interrupt arbitrary callback
|
|
81
|
+
execution. Existing candidate-projection packing and pre-receipt token
|
|
82
|
+
attribution retain their distinct contracts.
|
|
83
|
+
|
|
30
84
|
### Include Modes
|
|
31
85
|
|
|
32
86
|
`--output-include` accepts two kinds of token. A **field selector** names a row
|
|
@@ -195,7 +249,7 @@ The session ceiling and an explicit `--output-budget` both bind; the smaller
|
|
|
195
249
|
remaining allowance wins. Rows for item facts already present in the caller's
|
|
196
250
|
context become `{ "id": "pm-a1b2", "context_ref":
|
|
197
251
|
"session:orientation:pm-a1b2" }` instead of repeating prose. References retain
|
|
198
|
-
stable item identity and can be restored with `pm get <item-id> --brief` when
|
|
252
|
+
stable item identity and can be restored with `pm get <item-id> --depth brief` when
|
|
199
253
|
the prior context is unavailable. The receipt reports estimated and charged
|
|
200
254
|
tokens separately when the remaining group allowance is smaller than the
|
|
201
255
|
minimum control envelope, plus the accumulated spend, remaining capacity,
|
package/docs/SDK.md
CHANGED
|
@@ -599,6 +599,17 @@ sentinel rather than presenting it as a mistyped pm id.
|
|
|
599
599
|
|
|
600
600
|
### Agent output budgets and discovery
|
|
601
601
|
|
|
602
|
+
Package-defined packets can use `fitOutputEnvelope` from the query entrypoint
|
|
603
|
+
or `CommandHandlerContext.sdk.fitOutputEnvelope` to fit complete JSON/TOON
|
|
604
|
+
renderings, including self-accounting receipts and framing. See
|
|
605
|
+
[complete envelope fitting](READ_OUTPUT_CONTRACTS.md#package-defined-complete-envelopes)
|
|
606
|
+
for policies, work ceilings and refusal contracts, tracked by
|
|
607
|
+
[pm-gh1567](../.agents/pm/issues/pm-gh1567.toon).
|
|
608
|
+
Session receipts now advertise `pm get <item-id> --depth brief`; the
|
|
609
|
+
`restore_reference_with` literal type changes accordingly. Hosts constructing
|
|
610
|
+
`ExtensionCommandSdk` implementations must supply `fitOutputEnvelope` from the
|
|
611
|
+
public SDK; host-created command contexts already provide it.
|
|
612
|
+
|
|
602
613
|
Tracked by [pm-5t33or](../.agents/pm/features/pm-5t33or.toon),
|
|
603
614
|
[pm-gmdzaa](../.agents/pm/issues/pm-gmdzaa.toon), and
|
|
604
615
|
[pm-dpqa3h](../.agents/pm/chores/pm-dpqa3h.toon).
|
|
@@ -1123,6 +1134,28 @@ recurrence reason, accepts only the workspace open or in-progress target, and
|
|
|
1123
1134
|
returns the terminal evidence captured atomically before the update path clears
|
|
1124
1135
|
it from active metadata.
|
|
1125
1136
|
|
|
1137
|
+
Create focus policy is tracked by [pm-gh1577](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1577.toon)
|
|
1138
|
+
(this tracker record is repository-only and excluded from npm).
|
|
1139
|
+
Programmatic `create`, `PmClient.create`, `runCreate`, and MCP `pm_create`
|
|
1140
|
+
ignore saved session focus unless `inheritFocus: true` is supplied. An explicit
|
|
1141
|
+
parent, a parent from the selected template, or `unset: ["parent"]` takes
|
|
1142
|
+
precedence. Create receipts report `parent_source: "focus"`; the effective
|
|
1143
|
+
parent remains in the item and immutable create event. Plan results expose the
|
|
1144
|
+
effective parent as `plan.parent`. `pm create` and
|
|
1145
|
+
`pm plan create` enable this convenience by default; `--no-inherit-focus` or
|
|
1146
|
+
`--parent none` suppresses it (`pm create` also accepts `--unset parent`).
|
|
1147
|
+
SDK `planCreate` and MCP plan creation follow the same explicit opt-in policy.
|
|
1148
|
+
SDK scheduling shortcuts follow the same opt-in policy; package scheduling
|
|
1149
|
+
commands retain their focused creation convenience.
|
|
1150
|
+
|
|
1151
|
+
Other create defaults still apply: an explicitly selected template supplies
|
|
1152
|
+
options before explicit caller values, workspace governance selects the default
|
|
1153
|
+
type/create mode, the type workflow selects its initial status, priority defaults
|
|
1154
|
+
to 2, tags to an empty array, and author identity comes from invocation/workspace
|
|
1155
|
+
policy. There is no implicit saved assignee or tag default outside the selected
|
|
1156
|
+
template. Importers should supply explicit type, status, priority, tags, assignee,
|
|
1157
|
+
and parent/unset policy when those values are part of their source contract.
|
|
1158
|
+
|
|
1126
1159
|
Lifecycle handoff and receipt guidance are tracked by
|
|
1127
1160
|
[pm-gh1465](../.agents/pm/features/pm-gh1465.toon) and
|
|
1128
1161
|
[pm-gh1464](../.agents/pm/issues/pm-gh1464.toon). Register a project-specific
|
|
@@ -1174,10 +1207,31 @@ If a process stops between the domain write and the journal update, rerunning
|
|
|
1174
1207
|
the same plan discovers the already-applied step and continues. An ordinary
|
|
1175
1208
|
error switches the journal to compensation mode and runs applied steps in
|
|
1176
1209
|
reverse order, limited to steps whose forward attempt was durably recorded.
|
|
1210
|
+
Adapters can opt into `compensatePending: true` when `apply()` may fail after
|
|
1211
|
+
an internal write while inspection still reports `pending`. Such compensators
|
|
1212
|
+
must handle absent and partial effects idempotently. The default preserves
|
|
1213
|
+
applied-only compensation; an inspected `compensated` step is skipped.
|
|
1214
|
+
If compensation refuses, the journal retains its started steps
|
|
1215
|
+
and recovery data in `compensating` state instead of claiming a rollback.
|
|
1177
1216
|
Compensations are new item-history or relationship events: the
|
|
1178
1217
|
coordinator never deletes or rewrites immutable history. A crash during
|
|
1179
1218
|
compensation resumes compensation before a new attempt begins.
|
|
1180
1219
|
|
|
1220
|
+
Guarded terminal updates are tracked by
|
|
1221
|
+
[pm-pllp78](../.agents/pm/issues/pm-pllp78.toon). A bulk update's `match` guard
|
|
1222
|
+
is checked under each item lock and advances to the operation's own committed
|
|
1223
|
+
key value before its next internal lifecycle write. A stale starting value
|
|
1224
|
+
still refuses without item or history writes. Item updates opt into pending
|
|
1225
|
+
compensation and attribute every internal write in immutable history. New
|
|
1226
|
+
receipts bind the history fingerprint, integer prefix length and exact version, so writes sharing
|
|
1227
|
+
one timestamp remain distinguishable. Recovery restores exclusively owned
|
|
1228
|
+
effects and preserves peer-only changes. Mixed ownership, rewritten receipts,
|
|
1229
|
+
or a peer write before the restore lock refuse with
|
|
1230
|
+
`transaction_partial_mutation`; the surfaced `AggregateError` retains both
|
|
1231
|
+
failures and the journal keeps recovery data. Repeated compensation recognizes
|
|
1232
|
+
its durable marker even when a peer adds context afterward. Legacy timestamp
|
|
1233
|
+
receipts remain supported, with ambiguous partial effects refused.
|
|
1234
|
+
|
|
1181
1235
|
### Schema evolution and workspace history
|
|
1182
1236
|
|
|
1183
1237
|
Tracked by [pm-dijg](../.agents/pm/features/pm-dijg.toon) and
|
|
@@ -1527,8 +1581,9 @@ handlers remain disabled. Package-backed `--template` create input cannot be
|
|
|
1527
1581
|
semantically previewed through its package handler; expand it into explicit core
|
|
1528
1582
|
mutation options before preview.
|
|
1529
1583
|
|
|
1530
|
-
Actionable previews are tracked by [pm-ekf2gu](../.agents/pm/issues/pm-ekf2gu.toon)
|
|
1531
|
-
|
|
1584
|
+
Actionable previews are tracked by [pm-ekf2gu](../.agents/pm/issues/pm-ekf2gu.toon),
|
|
1585
|
+
[pm-fa9olc](../.agents/pm/tasks/pm-fa9olc.toon), and
|
|
1586
|
+
[pm-jhkzk0](../.agents/pm/features/pm-jhkzk0.toon).
|
|
1532
1587
|
`previewItemMutations` returns `warnings` grouped by zero-based operation
|
|
1533
1588
|
`index`, canonical `id`, and `op`. These are the original create lifecycle
|
|
1534
1589
|
warnings, including advisory `likely_duplicates` and duplicate-recovery tokens.
|
|
@@ -1544,7 +1599,14 @@ use this same projection. A `replayed_committed_plan` has no newly evaluated
|
|
|
1544
1599
|
warnings; an empty warning list in that state does not certify current policy.
|
|
1545
1600
|
|
|
1546
1601
|
Staging excludes derived `search` and `locks` content and unrelated runtime state,
|
|
1547
|
-
|
|
1602
|
+
plus `extensions/<directory>/node_modules` dependency trees. These trees are
|
|
1603
|
+
excluded before entry inspection or traversal, including dependency links;
|
|
1604
|
+
configured schema files and registered item folders take precedence and retain
|
|
1605
|
+
the regular-file safety checks even inside a dependency tree. Extension source,
|
|
1606
|
+
manifests and managed-package metadata remain in the snapshot. The receipt
|
|
1607
|
+
declares `derived_extension_dependencies_excluded` among its unresolved commit
|
|
1608
|
+
constraints because executable package dependencies are not validated.
|
|
1609
|
+
Staging retains registered item folders, explicitly configured schema files, and
|
|
1548
1610
|
`runtime/session.json` for core focus and inherited-parent semantics. Root-layout
|
|
1549
1611
|
trackers copy only tracker-owned files and directories, including standard and
|
|
1550
1612
|
custom item folders and configured schema files; unrelated project content is
|
|
@@ -2067,9 +2129,15 @@ signal-set metadata are supported, its item source matches, and its cursor,
|
|
|
2067
2129
|
complete item-id set, and substantive recency-evidence fingerprint match.
|
|
2068
2130
|
Missing, stale, version-incompatible, or corrupt state is rebuilt from the
|
|
2069
2131
|
authoritative items and atomically replaced. The result reports `cache_status`
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2132
|
+
without a warning for a successful missing/stale refresh
|
|
2133
|
+
([pm-gh1581](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1581.toon);
|
|
2134
|
+
this tracker record is repository-only and excluded from npm). Rebuilt signals are used in
|
|
2135
|
+
the current response; another read is unnecessary. With `explainRanking`,
|
|
2136
|
+
`ranking.feature_store.cache_status` exposes the refresh on context receipts.
|
|
2137
|
+
Corrupt/unreadable state and failed persistence retain actionable
|
|
2138
|
+
`context_signal_store_invalid` and `context_signal_store_write_failed` warnings.
|
|
2139
|
+
The exported stale-warning descriptor remains for compatibility with older
|
|
2140
|
+
receipts. A write failure still serves the in-memory rebuilt candidates because
|
|
2073
2141
|
the snapshot is derived, never authoritative. Optional maps for activity density,
|
|
2074
2142
|
graph proximity, claim/focus, knowledge density, author affinity, usage
|
|
2075
2143
|
affinity, and semantic similarity let an index or application-specific host
|
|
@@ -3510,6 +3578,20 @@ search degrades gracefully and emits warning codes instead of hard-failing.
|
|
|
3510
3578
|
|
|
3511
3579
|
## Completion-aware reporting and migration
|
|
3512
3580
|
|
|
3581
|
+
Close provenance is tracked by [pm-gh1579](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1579.toon)
|
|
3582
|
+
(a repository-only tracker record excluded from npm).
|
|
3583
|
+
`closeItem`, `PmClient.close`, CLI/MCP close receipts and successful `closeMany`
|
|
3584
|
+
rows return `completion` with the persisted `timestamp` and `source`:
|
|
3585
|
+
`asserted` means this close supplied `completedAt`, `existing` preserves an
|
|
3586
|
+
earlier metadata value, and `close_time` means completion was inferred from the
|
|
3587
|
+
tracker close time. Timestamp and source are sealed in the close event's
|
|
3588
|
+
`context.completion`; the local correction hint remains in the response.
|
|
3589
|
+
Existing records without it have unknown provenance;
|
|
3590
|
+
`existing` does not assert how an earlier value was obtained. No prior events are
|
|
3591
|
+
rewritten. Inferred receipts include a tracker-bound `update --completed-at`
|
|
3592
|
+
correction hint. Pass `completedAt` (CLI `--completed-at`) when closing delivered
|
|
3593
|
+
work retroactively; core never extracts a delivery date from reason prose.
|
|
3594
|
+
|
|
3513
3595
|
`resolveCompletionTimestamp(item)` gives reports one canonical timestamp plus a
|
|
3514
3596
|
`source` and `fallback` disclosure. It prefers `completed_at` (when the work
|
|
3515
3597
|
actually finished), then legacy `closed_at`, then `updated_at`.
|
|
@@ -80,7 +80,20 @@ reviewable history and skip approval requirements; use `transition` rules with
|
|
|
80
80
|
of the current record, using the same content and independent-actor checks.
|
|
81
81
|
|
|
82
82
|
Refused mutations preserve item state and item history, and append a workspace
|
|
83
|
-
refusal event.
|
|
83
|
+
refusal event. This append changes the tracked `history/_workspace.jsonl` file
|
|
84
|
+
under the selected tracker. Retain it with the workspace changes. The typed SDK
|
|
85
|
+
error's `context.side_effects` and CLI JSON `side_effects` disclose the
|
|
86
|
+
tracker-relative `path`, `op: "policy_refused"`, and sealed `record_hash`; MCP
|
|
87
|
+
error details retain the same context. Human-readable diagnostics also name the
|
|
88
|
+
write. Every refused attempt records a distinct event and returns its own record
|
|
89
|
+
identity, including repeated identical requests. This preserves attempt history
|
|
90
|
+
instead of silently coalescing it. Dry-run refusals have `side_effects: []` and
|
|
91
|
+
append nothing. An audit failure retains its separate error contract below and
|
|
92
|
+
does not claim a completed append. This disclosure is tracked by
|
|
93
|
+
[pm-gh1585](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1585.toon)
|
|
94
|
+
(a repository-only tracker record excluded from npm).
|
|
95
|
+
|
|
96
|
+
Accepted mutations attach bounded policy decisions to their normal
|
|
84
97
|
history event. Diagnostics contain policy ids and missing field paths, without
|
|
85
98
|
copying reviewed content into errors.
|
|
86
99
|
If the mandatory refusal audit cannot be appended, the mutation instead raises
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":5,"transcript_version":2,"transcript_digest":"sha256:
|
|
1
|
+
{"version":5,"transcript_version":2,"transcript_digest":"sha256:83d4523ca528ad5e8801cf5c7c02dcebbf2b87dc72422d4b8e648755dcdc36c2","estimator":"ceil(utf8_bytes / 4)","comparison_scope":"plan_recovery_tracker_root_canonicalized","measurement_scope":"output_before_token_accounting","published_with_release":true,"orientation":{"canonical_task_id":"orientation-context-intent","required_capabilities":["actionable_work","active_ownership","workspace_state"],"measured_winner_tokens":1087,"protocols":[{"task_id":"orientation-context-intent","command_count":1,"estimated_tokens":1087,"capabilities":["actionable_work","active_ownership","workspace_state"],"capability_evidence":{"actionable_work":[{"step_id":"context","field_path":"hierarchy"}],"active_ownership":[{"step_id":"context","field_path":"activity"}],"workspace_state":[{"step_id":"context","field_path":"summary.active_items"}]}},{"task_id":"orientation-operating-rules","command_count":4,"estimated_tokens":2139,"capabilities":["actionable_work","active_ownership","workspace_state"],"capability_evidence":{"actionable_work":[{"step_id":"open","field_path":"items"}],"active_ownership":[{"step_id":"in-progress","field_path":"items"}],"workspace_state":[{"step_id":"context","field_path":"summary.active_items"}]}},{"task_id":"orientation-contracts-next","command_count":2,"estimated_tokens":5203,"capabilities":["actionable_work","active_ownership","workspace_state"],"capability_evidence":{"actionable_work":[{"step_id":"next","field_path":"recommended.id"}],"active_ownership":[{"step_id":"next","field_path":"held_by_others"}],"workspace_state":[{"step_id":"next","field_path":"summary.in_progress"}]}}]},"tasks":[{"id":"orientation-context-intent","max_estimated_tokens":1087,"steps":[{"id":"context","max_estimated_tokens":1087,"accounting_mode":"self_reported"}]},{"id":"orientation-contracts-next","max_estimated_tokens":5203,"steps":[{"id":"contracts","max_estimated_tokens":4481,"accounting_mode":"self_reported"},{"id":"next","max_estimated_tokens":722,"accounting_mode":"self_reported"}]},{"id":"orientation-operating-rules","max_estimated_tokens":2139,"steps":[{"id":"context","max_estimated_tokens":1087,"accounting_mode":"self_reported"},{"id":"search","max_estimated_tokens":164,"accounting_mode":"self_reported"},{"id":"open","max_estimated_tokens":712,"accounting_mode":"self_reported"},{"id":"in-progress","max_estimated_tokens":176,"accounting_mode":"self_reported"}]},{"id":"context-bootstrap","max_estimated_tokens":2077,"steps":[{"id":"triage","max_estimated_tokens":619,"accounting_mode":"self_reported"},{"id":"orient","max_estimated_tokens":1087,"accounting_mode":"self_reported"},{"id":"inspect","max_estimated_tokens":371,"accounting_mode":"self_reported"}]},{"id":"closed-domain-recovery","max_estimated_tokens":630,"steps":[{"id":"refuse-intent","max_estimated_tokens":259,"accounting_mode":"self_reported"},{"id":"retry-intent","max_estimated_tokens":371,"accounting_mode":"self_reported"}]},{"id":"unknown-option-recovery","max_estimated_tokens":596,"steps":[{"id":"refuse-option","max_estimated_tokens":433,"accounting_mode":"self_reported"},{"id":"retry-option","max_estimated_tokens":163,"accounting_mode":"self_reported"}]},{"id":"lifecycle-mutation","max_estimated_tokens":888,"steps":[{"id":"create","max_estimated_tokens":20,"accounting_mode":"self_reported"},{"id":"inspect-open","max_estimated_tokens":363,"accounting_mode":"self_reported"},{"id":"close","max_estimated_tokens":107,"accounting_mode":"self_reported"},{"id":"inspect-closed","max_estimated_tokens":398,"accounting_mode":"self_reported"}]},{"id":"bulk-effect-outcomes","max_estimated_tokens":406,"steps":[{"id":"create-bulk-target","max_estimated_tokens":20,"accounting_mode":"self_reported"},{"id":"partial-effect","max_estimated_tokens":254,"accounting_mode":"self_reported"},{"id":"no-effect","max_estimated_tokens":132,"accounting_mode":"self_reported"}]},{"id":"plan-execution-mutations","max_estimated_tokens":806,"steps":[{"id":"create-plan","max_estimated_tokens":21,"accounting_mode":"self_reported"},{"id":"add-step","max_estimated_tokens":254,"accounting_mode":"self_reported"},{"id":"complete-step","max_estimated_tokens":253,"accounting_mode":"self_reported"},{"id":"inspect-plan","max_estimated_tokens":278,"accounting_mode":"self_reported"}]}],"composite_max_estimated_tokens":13832}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":2,"orientation":{"canonical_task_id":"orientation-context-intent","required_capabilities":["workspace_state","active_ownership","actionable_work"],"protocols":[{"task_id":"orientation-context-intent","capabilities":["workspace_state","active_ownership","actionable_work"],"capability_evidence":{"workspace_state":[{"step_id":"context","field_path":"summary.active_items"}],"active_ownership":[{"step_id":"context","field_path":"activity"}],"actionable_work":[{"step_id":"context","field_path":"hierarchy"}]}},{"task_id":"orientation-contracts-next","capabilities":["workspace_state","active_ownership","actionable_work"],"capability_evidence":{"workspace_state":[{"step_id":"next","field_path":"summary.in_progress"}],"active_ownership":[{"step_id":"next","field_path":"held_by_others"}],"actionable_work":[{"step_id":"next","field_path":"recommended.id"}]}},{"task_id":"orientation-operating-rules","capabilities":["workspace_state","active_ownership","actionable_work"],"capability_evidence":{"workspace_state":[{"step_id":"context","field_path":"summary.active_items"}],"active_ownership":[{"step_id":"in-progress","field_path":"items"}],"actionable_work":[{"step_id":"open","field_path":"items"}]}}]},"tasks":[{"id":"orientation-context-intent","description":"Build sufficient cold-start workspace, ownership, and actionable-work context with the bounded orientation intent.","steps":[{"id":"context","args":["context","--for","orient","--limit","10"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["summary.active_items","hierarchy","activity"]}]},{"id":"orientation-contracts-next","description":"Compare the proposed contracts-summary plus next cold-start protocol on the same fixed workspace.","steps":[{"id":"contracts","args":["contracts","--summary"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["commands"]},{"id":"next","args":["next","--for","execute","--ready-only","--limit","3"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["summary.in_progress","held_by_others","recommended.id"]}]},{"id":"orientation-operating-rules","description":"Compare the historical context, search, open-list, and in-progress-list orientation sequence.","steps":[{"id":"context","args":["context","--for","orient","--limit","10"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["summary.active_items","hierarchy","activity"]},{"id":"search","args":["search","agent task","--status","all","--limit","10"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"]},{"id":"open","args":["list","--status","open","--limit","20"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"]},{"id":"in-progress","args":["list","--status","in_progress","--limit","20"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"]}]},{"id":"context-bootstrap","description":"Orient in a scaled workspace and inspect the canonical focus item.","steps":[{"id":"triage","args":["list","--for","triage","--limit","2"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"]},{"id":"orient","args":["context","--for","orient","--limit","5"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["summary.active_items","hierarchy","activity"]},{"id":"inspect","args":["get","$ANCHOR_ID","--for","inspect"],"expected_exit_code":0,"expected_output_kind":"entity","expected_accounting_mode":"self_reported","required_fields":["item.id"]}]},{"id":"closed-domain-recovery","description":"Reject an invalid context intent and execute the advertised shell-free retry.","steps":[{"id":"refuse-intent","args":["get","$ANCHOR_ID","--for","invalid-agent-intent"],"expected_exit_code":2,"expected_output_kind":"refusal","expected_accounting_mode":"self_reported","required_fields":["code","refusal","recovery"],"expected_error_code":"unknown_context_intent","expected_field_values":{"recovery.recovery_mode":"compact"},"expected_refusal_surface":"--for"},{"id":"retry-intent","args":["get","$ANCHOR_ID","--for","inspect"],"expected_exit_code":0,"expected_output_kind":"entity","expected_accounting_mode":"self_reported","required_fields":["item.id"],"recovery_for":"refuse-intent"}]},{"id":"unknown-option-recovery","description":"Identify an unsupported option after valid flags and continue with the corrected command.","steps":[{"id":"refuse-option","args":["search","agent task","--status","open","--limit","5","--include-body"],"expected_exit_code":2,"expected_output_kind":"refusal","expected_accounting_mode":"self_reported","required_fields":["code","refusal","recovery"],"expected_error_code":"unknown_option","expected_refusal_surface":"--include-body"},{"id":"retry-option","args":["search","agent task","--status","open","--limit","5"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"],"recovery_for":"refuse-option"}]},{"id":"lifecycle-mutation","description":"Create, inspect, close, and confirm a project item through public CLI receipts.","steps":[{"id":"create","args":["create","--id","$LIFECYCLE_ID","--title","Transcript lifecycle item","--description","Golden multi-step lifecycle task","--type","Task","--status","open","--create-mode","progressive"],"expected_exit_code":0,"expected_output_kind":"mutation_receipt","expected_accounting_mode":"self_reported","required_fields":["id","changed_field_count"]},{"id":"inspect-open","args":["get","$LIFECYCLE_ID","--for","inspect"],"expected_exit_code":0,"expected_output_kind":"entity","expected_accounting_mode":"self_reported","required_fields":["item.id","item.status"],"expected_field_values":{"item.status":"open"}},{"id":"close","args":["close","$LIFECYCLE_ID","Golden task completed"],"expected_exit_code":0,"expected_output_kind":"mutation_receipt","expected_accounting_mode":"self_reported","required_fields":["id","status","close_reason"]},{"id":"inspect-closed","args":["get","$LIFECYCLE_ID","--for","inspect"],"expected_exit_code":0,"expected_output_kind":"entity","expected_accounting_mode":"self_reported","required_fields":["item.id","item.status"],"expected_field_values":{"item.status":"closed"}}]},{"id":"bulk-effect-outcomes","description":"Preserve successful partial-effect and no-effect outcomes across a bulk lifecycle task.","steps":[{"id":"create-bulk-target","args":["create","--id","$BULK_ID","--title","Transcript bulk effect target","--description","Golden bulk outcome transcript target","--type","Task","--status","open","--create-mode","progressive"],"expected_exit_code":0,"expected_output_kind":"mutation_receipt","expected_accounting_mode":"self_reported","required_fields":["id","status","changed_field_count"]},{"id":"partial-effect","args":["close-many","--ids","$BULK_ID,pm-transcript-missing","--reason","Golden partial-effect transcript","--validate-close","off","--no-checkpoint"],"expected_exit_code":7,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["rows","outcome","exit_code"],"expected_field_values":{"outcome":"partial_effect"}},{"id":"no-effect","args":["close-many","--ids","$BULK_ID","--reason","Golden no-effect transcript","--validate-close","off","--no-checkpoint"],"expected_exit_code":6,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["rows","outcome","exit_code"],"expected_field_values":{"outcome":"no_effect"}}]},{"id":"plan-execution-mutations","description":"Create a Plan, add and complete a step, then inspect its durable evidence without echoing the full Plan on each mutation.","steps":[{"id":"create-plan","args":["create","--id","pm-transcript-plan","--type","Plan","--title","Transcript execution Plan","--create-mode","progressive"],"expected_exit_code":0,"expected_output_kind":"mutation_receipt","expected_accounting_mode":"self_reported","required_fields":["id","status"]},{"id":"add-step","args":["plan","add-step","pm-transcript-plan","--step-title","Verify result","--step-body","Durable execution context retained for later inspection."],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["id","step.id","steps_summary.total","inspection_command"],"expected_field_values":{"kind":"plan_mutation","steps_summary.total":1}},{"id":"complete-step","args":["plan","complete-step","pm-transcript-plan","plan-step-001","--step-evidence","Verified result"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["id","step.status","steps_summary.completed","omission_receipt"],"expected_field_values":{"step.status":"completed","steps_summary.completed":1}},{"id":"inspect-plan","args":["plan","show","pm-transcript-plan","--depth","deep"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["plan.steps","plan.steps_summary.completed"],"expected_field_values":{"plan.steps_summary.completed":1}}]}]}
|
|
1
|
+
{"version":2,"orientation":{"canonical_task_id":"orientation-context-intent","required_capabilities":["workspace_state","active_ownership","actionable_work"],"protocols":[{"task_id":"orientation-context-intent","capabilities":["workspace_state","active_ownership","actionable_work"],"capability_evidence":{"workspace_state":[{"step_id":"context","field_path":"summary.active_items"}],"active_ownership":[{"step_id":"context","field_path":"activity"}],"actionable_work":[{"step_id":"context","field_path":"hierarchy"}]}},{"task_id":"orientation-contracts-next","capabilities":["workspace_state","active_ownership","actionable_work"],"capability_evidence":{"workspace_state":[{"step_id":"next","field_path":"summary.in_progress"}],"active_ownership":[{"step_id":"next","field_path":"held_by_others"}],"actionable_work":[{"step_id":"next","field_path":"recommended.id"}]}},{"task_id":"orientation-operating-rules","capabilities":["workspace_state","active_ownership","actionable_work"],"capability_evidence":{"workspace_state":[{"step_id":"context","field_path":"summary.active_items"}],"active_ownership":[{"step_id":"in-progress","field_path":"items"}],"actionable_work":[{"step_id":"open","field_path":"items"}]}}]},"tasks":[{"id":"orientation-context-intent","description":"Build sufficient cold-start workspace, ownership, and actionable-work context with the bounded orientation intent.","steps":[{"id":"context","args":["context","--for","orient","--limit","10"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["summary.active_items","hierarchy","activity"]}]},{"id":"orientation-contracts-next","description":"Compare the proposed contracts-summary plus next cold-start protocol on the same fixed workspace.","steps":[{"id":"contracts","args":["contracts","--summary"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["commands"]},{"id":"next","args":["next","--for","execute","--ready-only","--limit","3"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["summary.in_progress","held_by_others","recommended.id"]}]},{"id":"orientation-operating-rules","description":"Compare the historical context, search, open-list, and in-progress-list orientation sequence.","steps":[{"id":"context","args":["context","--for","orient","--limit","10"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["summary.active_items","hierarchy","activity"]},{"id":"search","args":["search","agent task","--status","all","--limit","10"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"]},{"id":"open","args":["list","--status","open","--limit","20"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"]},{"id":"in-progress","args":["list","--status","in_progress","--limit","20"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"]}]},{"id":"context-bootstrap","description":"Orient in a scaled workspace and inspect the canonical focus item.","steps":[{"id":"triage","args":["list","--for","triage","--limit","2"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"]},{"id":"orient","args":["context","--for","orient","--limit","5"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["summary.active_items","hierarchy","activity"]},{"id":"inspect","args":["get","$ANCHOR_ID","--for","inspect"],"expected_exit_code":0,"expected_output_kind":"entity","expected_accounting_mode":"self_reported","required_fields":["item.id"]}]},{"id":"closed-domain-recovery","description":"Reject an invalid context intent and execute the advertised shell-free retry.","steps":[{"id":"refuse-intent","args":["get","$ANCHOR_ID","--for","invalid-agent-intent"],"expected_exit_code":2,"expected_output_kind":"refusal","expected_accounting_mode":"self_reported","required_fields":["code","refusal","recovery"],"expected_error_code":"unknown_context_intent","expected_field_values":{"recovery.recovery_mode":"compact"},"expected_refusal_surface":"--for"},{"id":"retry-intent","args":["get","$ANCHOR_ID","--for","inspect"],"expected_exit_code":0,"expected_output_kind":"entity","expected_accounting_mode":"self_reported","required_fields":["item.id"],"recovery_for":"refuse-intent"}]},{"id":"unknown-option-recovery","description":"Identify an unsupported option after valid flags and continue with the corrected command.","steps":[{"id":"refuse-option","args":["search","agent task","--status","open","--limit","5","--include-body"],"expected_exit_code":2,"expected_output_kind":"refusal","expected_accounting_mode":"self_reported","required_fields":["code","refusal","recovery"],"expected_error_code":"unknown_option","expected_refusal_surface":"--include-body"},{"id":"retry-option","args":["search","agent task","--status","open","--limit","5"],"expected_exit_code":0,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["items"],"recovery_for":"refuse-option"}]},{"id":"lifecycle-mutation","description":"Create, inspect, close, and confirm a project item through public CLI receipts.","steps":[{"id":"create","args":["create","--id","$LIFECYCLE_ID","--title","Transcript lifecycle item","--description","Golden multi-step lifecycle task","--type","Task","--status","open","--create-mode","progressive"],"expected_exit_code":0,"expected_output_kind":"mutation_receipt","expected_accounting_mode":"self_reported","required_fields":["id","changed_field_count"]},{"id":"inspect-open","args":["get","$LIFECYCLE_ID","--for","inspect"],"expected_exit_code":0,"expected_output_kind":"entity","expected_accounting_mode":"self_reported","required_fields":["item.id","item.status"],"expected_field_values":{"item.status":"open"}},{"id":"close","args":["close","$LIFECYCLE_ID","Golden task completed"],"expected_exit_code":0,"expected_output_kind":"mutation_receipt","expected_accounting_mode":"self_reported","required_fields":["id","status","close_reason","completion.timestamp","completion.source","completion.hint"],"expected_field_values":{"completion.source":"close_time"}},{"id":"inspect-closed","args":["get","$LIFECYCLE_ID","--for","inspect"],"expected_exit_code":0,"expected_output_kind":"entity","expected_accounting_mode":"self_reported","required_fields":["item.id","item.status"],"expected_field_values":{"item.status":"closed"}}]},{"id":"bulk-effect-outcomes","description":"Preserve successful partial-effect and no-effect outcomes across a bulk lifecycle task.","steps":[{"id":"create-bulk-target","args":["create","--id","$BULK_ID","--title","Transcript bulk effect target","--description","Golden bulk outcome transcript target","--type","Task","--status","open","--create-mode","progressive"],"expected_exit_code":0,"expected_output_kind":"mutation_receipt","expected_accounting_mode":"self_reported","required_fields":["id","status","changed_field_count"]},{"id":"partial-effect","args":["close-many","--ids","$BULK_ID,pm-transcript-missing","--reason","Golden partial-effect transcript","--validate-close","off","--no-checkpoint"],"expected_exit_code":7,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["rows","outcome","exit_code","rows.0.completion.timestamp","rows.0.completion.source","rows.0.completion.hint"],"expected_field_values":{"outcome":"partial_effect","rows.0.completion.source":"close_time"}},{"id":"no-effect","args":["close-many","--ids","$BULK_ID","--reason","Golden no-effect transcript","--validate-close","off","--no-checkpoint"],"expected_exit_code":6,"expected_output_kind":"collection","expected_accounting_mode":"self_reported","required_fields":["rows","outcome","exit_code"],"expected_field_values":{"outcome":"no_effect"}}]},{"id":"plan-execution-mutations","description":"Create a Plan, add and complete a step, then inspect its durable evidence without echoing the full Plan on each mutation.","steps":[{"id":"create-plan","args":["create","--id","pm-transcript-plan","--type","Plan","--title","Transcript execution Plan","--create-mode","progressive"],"expected_exit_code":0,"expected_output_kind":"mutation_receipt","expected_accounting_mode":"self_reported","required_fields":["id","status"]},{"id":"add-step","args":["plan","add-step","pm-transcript-plan","--step-title","Verify result","--step-body","Durable execution context retained for later inspection."],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["id","step.id","steps_summary.total","inspection_command"],"expected_field_values":{"kind":"plan_mutation","steps_summary.total":1}},{"id":"complete-step","args":["plan","complete-step","pm-transcript-plan","plan-step-001","--step-evidence","Verified result"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["id","step.status","steps_summary.completed","omission_receipt"],"expected_field_values":{"step.status":"completed","steps_summary.completed":1}},{"id":"inspect-plan","args":["plan","show","pm-transcript-plan","--depth","deep"],"expected_exit_code":0,"expected_output_kind":"diagnostic","expected_accounting_mode":"self_reported","required_fields":["plan.steps","plan.steps_summary.completed"],"expected_field_values":{"plan.steps_summary.completed":1}}]}]}
|
|
@@ -12,7 +12,7 @@ This file is generated by `listPmFlagLexicon()`. Compatibility aliases do not co
|
|
|
12
12
|
| `packages` | extensions | 56 | 56 |
|
|
13
13
|
| `install` | extensions | 27 | 27 |
|
|
14
14
|
| `upgrade` | extensions | 29 | 29 |
|
|
15
|
-
| `create` | intake |
|
|
15
|
+
| `create` | intake | 102 | 102 |
|
|
16
16
|
| `copy` | intake | 24 | 24 |
|
|
17
17
|
| `focus` | intake | 22 | 22 |
|
|
18
18
|
| `list` | context | 86 | 86 |
|
|
@@ -56,7 +56,7 @@ This file is generated by `listPmFlagLexicon()`. Compatibility aliases do not co
|
|
|
56
56
|
| `files` | evidence | 39 | 39 |
|
|
57
57
|
| `docs` | evidence | 30 | 30 |
|
|
58
58
|
| `deps` | graph | 32 | 32 |
|
|
59
|
-
| `plan` | graph |
|
|
59
|
+
| `plan` | graph | 111 | 111 |
|
|
60
60
|
| `test` | quality | 56 | 56 |
|
|
61
61
|
| `test-all` | quality | 40 | 40 |
|
|
62
62
|
| `telemetry` | workspace | 21 | 21 |
|
|
@@ -4,12 +4,12 @@ Tracker: `pm-f05lsg`.
|
|
|
4
4
|
|
|
5
5
|
Every catalog code is listed. An `uncovered` row is an explicit closure obligation, never an omission or implied approval.
|
|
6
6
|
|
|
7
|
-
- Catalog error codes:
|
|
7
|
+
- Catalog error codes: 430
|
|
8
8
|
- Executable error codes: 19
|
|
9
9
|
- Executable-code ratchet floor: 18
|
|
10
10
|
- Required executable canonical codes: `bulk_ids_input_empty`, `bulk_ids_input_missing_path`, `bulk_ids_input_unreadable`, `invalid_argument_value`, `manifest_unknown_key`, `missing_lifecycle_target`, `missing_required_argument`, `no_version_bounds_declared`, `projection_options_mutually_exclusive`, `tracker_not_initialized`, `tracker_root_missing`, `tracker_root_not_directory`, `tracker_root_unreadable`, `unknown_context_intent`, `unknown_field_projection`, `unknown_option`, `unknown_subcommand`
|
|
11
|
-
- Uncovered error codes:
|
|
12
|
-
- Coverage fraction: 0.
|
|
11
|
+
- Uncovered error codes: 411
|
|
12
|
+
- Coverage fraction: 0.044186
|
|
13
13
|
- Closed-domain probes: 19
|
|
14
14
|
- Grammar probes: 117
|
|
15
15
|
|
|
@@ -350,6 +350,7 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati
|
|
|
350
350
|
| `tracker_root_unreadable` | `tracker_root_unreadable` | executable | owned_state | 1 |
|
|
351
351
|
| `transaction_create_compensated` | `transaction_create_compensated` | uncovered | none | 0 |
|
|
352
352
|
| `transaction_journal_invalid` | `transaction_journal_invalid` | uncovered | none | 0 |
|
|
353
|
+
| `transaction_partial_mutation` | `transaction_partial_mutation` | uncovered | none | 0 |
|
|
353
354
|
| `transaction_plan_mismatch` | `transaction_plan_mismatch` | uncovered | none | 0 |
|
|
354
355
|
| `transaction_preview_external_schema` | `transaction_preview_external_schema` | uncovered | none | 0 |
|
|
355
356
|
| `transaction_preview_non_regular_file` | `transaction_preview_non_regular_file` | uncovered | none | 0 |
|
package/marketplace.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"pm","owner":{"name":"unbrained","url":"https://github.com/unbraind/pm-cli"},"description":"Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.","version":"2026.10.
|
|
1
|
+
{"name":"pm","owner":{"name":"unbrained","url":"https://github.com/unbraind/pm-cli"},"description":"Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.","version":"2026.10.26","plugins":[{"name":"pm-claude","source":"./plugins/pm-claude","description":"Native pm CLI integration for Claude Code — 32 MCP tools, 14 workflow skills with slash invocations, 4 subagents, hybrid TUI task tracking, session context injection, and coordination subagents for git-based project management without leaving Claude Code.","version":"2026.10.26","author":{"name":"unbrained","url":"https://github.com/unbraind/pm-cli"},"homepage":"https://github.com/unbraind/pm-cli","repository":"https://github.com/unbraind/pm-cli","license":"MIT","keywords":["pm-cli","project-management","mcp","tasks","agents","workflows","git-native","task-tracker","ai"],"category":"productivity"}]}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@unbrained/pm-beads","version":"2026.10.
|
|
1
|
+
{"name":"@unbrained/pm-beads","version":"2026.10.26","private":true,"type":"module","description":"First-party pm package for importing Beads JSONL records.","homepage":"https://github.com/unbraind/pm-cli/tree/main/packages/pm-beads#readme","repository":{"type":"git","url":"git+https://github.com/unbraind/pm-cli.git","directory":"packages/pm-beads"},"bugs":{"url":"https://github.com/unbraind/pm-cli/issues"},"keywords":["pm-package","project-management","beads"],"pm":{"aliases":["beads"],"extensions":["extensions/beads"],"catalog":{"display_name":"Beads Import","category":"migration","summary":"Import Beads JSONL records into pm while preserving source IDs.","tags":["migration","beads","import"],"links":{"docs":"https://github.com/unbraind/pm-cli/tree/main/packages/pm-beads#readme","repository":"https://github.com/unbraind/pm-cli/tree/main/packages/pm-beads","report":"https://github.com/unbraind/pm-cli/issues"}},"docs":["README.md"],"examples":["README.md"]}}
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
import { runEvent, runMeet, runRemind, type CommandDefinition } from "@unbrained/pm-cli/sdk";
|
|
7
7
|
import { schedulingCommandDefinitions } from "./command-definitions.ts";
|
|
8
8
|
|
|
9
|
-
/**
|
|
9
|
+
/** Preserve CLI focus for absent policy, explicit opt-out, and native SDK validation/history/receipts. */
|
|
10
10
|
export const schedulingCommands: CommandDefinition[] = schedulingCommandDefinitions.map((definition) => ({
|
|
11
11
|
...definition,
|
|
12
12
|
run: (context) => (
|
|
13
13
|
definition.name === "meet" ? runMeet : definition.name === "event" ? runEvent : runRemind
|
|
14
|
-
)(context.args[0], context.options, context.global),
|
|
14
|
+
)(context.args[0], { ...context.options, inheritFocus: (context.options.inheritFocus ?? true) === true }, context.global),
|
|
15
15
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@unbrained/pm-calendar","version":"2026.10.
|
|
1
|
+
{"name":"@unbrained/pm-calendar","version":"2026.10.26","private":true,"type":"module","description":"First-party pm package for calendar and agenda views.","homepage":"https://github.com/unbraind/pm-cli/tree/main/packages/pm-calendar#readme","repository":{"type":"git","url":"git+https://github.com/unbraind/pm-cli.git","directory":"packages/pm-calendar"},"bugs":{"url":"https://github.com/unbraind/pm-cli/issues"},"keywords":["pm-package","project-management","calendar","agenda"],"pm":{"aliases":["calendar"],"extensions":["extensions/calendar"],"catalog":{"display_name":"Calendar Views","category":"workflow","summary":"Show agenda, day, week, and month views for deadlines, reminders, and scheduled events.","tags":["calendar","agenda","workflow"],"links":{"docs":"https://github.com/unbraind/pm-cli/tree/main/packages/pm-calendar#readme","repository":"https://github.com/unbraind/pm-cli/tree/main/packages/pm-calendar","report":"https://github.com/unbraind/pm-cli/issues"}},"docs":["README.md"],"examples":["README.md"]}}
|