@unbrained/pm-cli 2026.10.1 → 2026.10.3
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 +23 -0
- package/dist/cli/error-guidance.d.ts +5 -0
- package/dist/cli/error-guidance.js +1 -1
- package/dist/cli/main.js +2 -2
- package/dist/cli/register-structured-mutation.d.ts +2 -0
- package/dist/cli/register-structured-mutation.js +1 -1
- package/dist/cli/runtime/projection-retry.d.ts +9 -0
- package/dist/cli/runtime/projection-retry.js +2 -0
- package/dist/cli/runtime/selection.d.ts +5 -1
- package/dist/cli/runtime/selection.js +1 -1
- package/dist/cli-bundle/bundle-manifest.json +156 -156
- package/dist/cli-bundle/chunks/chunk-3AF2R3Y6.js +6 -0
- package/dist/cli-bundle/chunks/chunk-44UGMMQ6.js +3 -0
- package/dist/cli-bundle/chunks/{chunk-VWVFKPLX.js → chunk-5XKF5SQV.js} +38 -38
- package/dist/cli-bundle/chunks/{chunk-AYHLUJKD.js → chunk-6ST3SCQ6.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-6Z4IV2MC.js +8 -0
- package/dist/cli-bundle/chunks/{chunk-A2UPOCSW.js → chunk-FW5LJXQY.js} +31 -31
- package/dist/cli-bundle/chunks/{chunk-SCZMJ5DC.js → chunk-H2DZW6I6.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-H7CXQBGQ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-DGOIXJZJ.js → chunk-KP7NBQK3.js} +47 -47
- package/dist/cli-bundle/chunks/chunk-MKXBCBAN.js +20 -0
- package/dist/cli-bundle/chunks/chunk-QPKQKSQU.js +238 -0
- package/dist/cli-bundle/chunks/chunk-YCBGZF3T.js +2 -0
- package/dist/cli-bundle/chunks/chunk-YDWKGUQU.js +3 -0
- package/dist/cli-bundle/chunks/{register-list-query-L6HAHW7V.js → register-list-query-DYCGUQEW.js} +2 -2
- package/dist/cli-bundle/chunks/register-mutation-5PT3NW3A.js +20 -0
- package/dist/cli-bundle/chunks/{register-operations-3E5U4TOE.js → register-operations-QDDQOAAV.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-VUD37N4A.js → register-setup-BBX67YMA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-MOUCTR72.js → chunk-3BIYG72P.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-T4PZJQG4.js → chunk-4FFPGNCJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-YBQ27KG7.js → chunk-73DA7ISY.js} +47 -47
- package/dist/cli-bundle/focused-chunks/{chunk-XUCXRZZZ.js → chunk-DBD4W4QP.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-6275G2AN.js → chunk-E754JDLY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-4AORVUT4.js → chunk-EJN7DY3B.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-OMBDUJWZ.js → chunk-FKK2HI3S.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-ZJ3CLTV4.js → chunk-GMYUNHST.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-HIA2ZF64.js +12 -0
- package/dist/cli-bundle/focused-chunks/{chunk-RIJQQOEZ.js → chunk-UTRSM3ZK.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-EVMH4SKN.js → chunk-VVWYI2X7.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-WAJNX4RN.js +20 -0
- package/dist/cli-bundle/focused-chunks/chunk-WCY6HRZO.js +30 -0
- package/dist/cli-bundle/focused-chunks/{chunk-XB5Q2P7Z.js → chunk-XRSCIYHR.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-YC32ZSLS.js +165 -0
- package/dist/cli-bundle/focused-chunks/{chunk-IQBFYQF2.js → chunk-ZIXFMIUL.js} +2 -2
- package/dist/cli-bundle/main.js +22 -22
- 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 +31 -31
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +48 -48
- 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/fs/fs-utils.d.ts +11 -0
- package/dist/core/fs/fs-utils.js +2 -2
- package/dist/core/shared/errors.d.ts +9 -0
- package/dist/core/shared/errors.js +1 -1
- package/dist/core/shared/secret-rules.js +1 -1
- package/dist/core/store/settings.d.ts +15 -5
- package/dist/core/store/settings.js +3 -3
- package/dist/core/telemetry/runtime.js +3 -3
- package/dist/mcp/server.js +1 -1
- package/dist/sdk/agent/closed-domain-contracts.js +1 -1
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
- package/dist/sdk/item-transaction.d.ts +11 -0
- package/dist/sdk/item-transaction.js +1 -1
- package/dist/sdk/linked-artifacts.d.ts +1 -1
- package/dist/sdk/linked-artifacts.js +1 -1
- package/dist/sdk/pagination.js +1 -1
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query/context.d.ts +2 -0
- package/dist/sdk/query/context.js +1 -1
- package/dist/sdk/query/get.js +1 -1
- package/dist/sdk/query/list.js +1 -1
- package/dist/sdk/query/search-contracts.js +1 -1
- package/dist/sdk/query/search-pagination.d.ts +4 -0
- package/dist/sdk/query/search-pagination.js +1 -1
- package/dist/sdk/query/search.js +1 -1
- package/dist/sdk/read-output/options.d.ts +14 -0
- package/dist/sdk/read-output/options.js +2 -0
- package/dist/sdk/read-output-budget.js +1 -1
- package/dist/sdk/read-output-contracts.js +1 -1
- package/dist/sdk/read-output-rows.d.ts +4 -0
- package/dist/sdk/read-output-rows.js +1 -1
- package/dist/sdk/runtime-primitives.d.ts +2 -2
- package/dist/sdk/runtime-primitives.js +1 -1
- package/dist/sdk/runtime.js +1 -1
- package/dist/sdk/test/execution.js +2 -2
- package/dist/sdk/test/workspace-snapshot.d.ts +11 -0
- package/dist/sdk/test/workspace-snapshot.js +2 -0
- package/dist/sdk/workspace-transaction.d.ts +2 -0
- package/dist/sdk/workspace-transaction.js +2 -2
- package/docs/DEVELOPMENT_DEPENDENCY_SECURITY.md +109 -0
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +27 -0
- package/docs/SDK.md +98 -0
- package/docs/TESTING.md +32 -5
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +5 -3
- package/marketplace.json +2 -2
- package/package.json +5 -4
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-claude/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/dist/cli-bundle/chunks/chunk-7E2EBJLY.js +0 -3
- package/dist/cli-bundle/chunks/chunk-BNAT4EYR.js +0 -20
- package/dist/cli-bundle/chunks/chunk-HGJLVN56.js +0 -8
- package/dist/cli-bundle/chunks/chunk-JAVO3Z42.js +0 -6
- package/dist/cli-bundle/chunks/chunk-TV3YDE36.js +0 -2
- package/dist/cli-bundle/chunks/chunk-UIAH7UFK.js +0 -238
- package/dist/cli-bundle/chunks/chunk-USTAFHIM.js +0 -2
- package/dist/cli-bundle/chunks/chunk-YM342ELM.js +0 -3
- package/dist/cli-bundle/chunks/register-mutation-6OCZVTW5.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-3CAZ7Z4R.js +0 -30
- package/dist/cli-bundle/focused-chunks/chunk-DJPP2HAK.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-IDB6E3ZV.js +0 -165
- package/dist/cli-bundle/focused-chunks/chunk-UPOMLSW7.js +0 -20
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
-
`)}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);if(cloned===void 0)delete target[stepId];else 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 false;const startedStepIds=journal.startedStepIds;const started=new Set(startedStepIds);const completedStepIds=journal.completedStepIds;const completed=new Set(completedStepIds);if(Object.keys(journal.compensationData).some(stepId=>!started.has(stepId))||Object.keys(journal.results).some(stepId=>!completed.has(stepId)))return false;if(journal.status==="committed")return stepIds.every(stepId=>completed.has(stepId));return journal.status!=="compensated"||completed.size===0&&started.size===0}function parseJournal(raw,transactionId,stepIds){let parsed;try{parsed=JSON.parse(raw)}catch{throw new TypeError(`Workspace transaction ${transactionId} journal is invalid JSON`)}if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))throw new TypeError(`Workspace transaction ${transactionId} journal is invalid`);const journal=parsed;const identityMatches=journal.schemaVersion===1&&journal.transactionId===transactionId;const stepsMatch=Array.isArray(journal.stepIds)&&journal.stepIds.length===stepIds.length&&journal.stepIds.every((stepId,index)=>stepId===stepIds[index]);const lifecycleMatches=hasValidJournalLifecycle(journal,stepIds);const metadataMatches=hasValidJournalMetadata(journal);const statusMatches=["applying","compensating","compensated","committed"].includes(String(journal.status));if(!identityMatches||!stepsMatch||!lifecycleMatches||!metadataMatches||!statusMatches)throw new TypeError(`Workspace transaction ${transactionId} journal does not match the supplied plan`);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);if(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);const 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)}await emitTransition(options,journal,"committing");journal.status="committed";await writeJournal(options.pmRoot,journal);await emitTransition(options,journal,"committed");return{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 void 0;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;const results=createResultMap();for(const step of steps){const inspection=await step.inspect();if(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);const 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)}if(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
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d9ef3878-afce-5983-8fe9-8a896f82d0a7")}catch(e2){}})();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";class WorkspaceTransactionInterruptedError extends Error{constructor(message="Workspace transaction interrupted"){super(message);this.name="WorkspaceTransactionInterruptedError"}}const WORKSPACE_TRANSACTION_LOCK_ID="sdk-workspace-transaction";const TRANSACTION_ID_PATTERN=/^[a-zA-Z0-9._-]+$/;const DEFAULT_LOCK_TTL_SECONDS=30;const 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:true});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);if(cloned===void 0)delete target[stepId];else 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 false;const startedStepIds=journal.startedStepIds;const started=new Set(startedStepIds);const completedStepIds=journal.completedStepIds;const completed=new Set(completedStepIds);if(Object.keys(journal.compensationData).some(stepId=>!started.has(stepId))||Object.keys(journal.results).some(stepId=>!completed.has(stepId)))return false;if(journal.status==="committed")return stepIds.every(stepId=>completed.has(stepId));return journal.status!=="compensated"||completed.size===0&&started.size===0}function parseJournal(raw,transactionId,stepIds){let parsed;try{parsed=JSON.parse(raw)}catch{throw new TypeError(`Workspace transaction ${transactionId} journal is invalid JSON`)}if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))throw new TypeError(`Workspace transaction ${transactionId} journal is invalid`);const journal=parsed;const identityMatches=journal.schemaVersion===1&&journal.transactionId===transactionId;const stepsMatch=Array.isArray(journal.stepIds)&&journal.stepIds.length===stepIds.length&&journal.stepIds.every((stepId,index)=>stepId===stepIds[index]);const lifecycleMatches=hasValidJournalLifecycle(journal,stepIds);const metadataMatches=hasValidJournalMetadata(journal);const statusMatches=["applying","compensating","compensated","committed"].includes(String(journal.status));if(!identityMatches||!stepsMatch||!lifecycleMatches||!metadataMatches||!statusMatches)throw new TypeError(`Workspace transaction ${transactionId} journal does not match the supplied plan`);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);if(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);const 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)}await emitTransition(options,journal,"committing");journal.status="committed";await writeJournal(options.pmRoot,journal);await emitTransition(options,journal,"committed");return{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 void 0;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;const results=createResultMap();for(const step of steps){const inspection=await step.inspect();if(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);const 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)}if(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);const lockTtlSeconds=positiveInteger(options.lockTtlSeconds,DEFAULT_LOCK_TTL_SECONDS,"Transaction lock TTL");const lockWaitMs=positiveInteger(options.lockWaitMs,DEFAULT_LOCK_WAIT_MS,"Transaction lock wait");const 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};const release=await acquireLock(pmRoot,WORKSPACE_TRANSACTION_LOCK_ID,lockTtlSeconds,author,false,false,lockWaitMs);try{const existing=await loadJournal(pmRoot,transactionId,stepIds);const recovered=existing!==void 0;if(existing?.status==="committed")return{transactionId,status:"committed",recovered:true,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
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Development dependency security
|
|
2
|
+
|
|
3
|
+
Tracked by [pm-r61juc](../.agents/pm/issues/pm-r61juc.toon) and
|
|
4
|
+
[pm-fnx3np](../.agents/pm/issues/pm-fnx3np.toon).
|
|
5
|
+
|
|
6
|
+
Development tools execute during tests, benchmarks and release preparation.
|
|
7
|
+
Their dependencies have the same admission requirement as production packages:
|
|
8
|
+
no known advisory may pass the required static gate. Run:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pnpm install --frozen-lockfile
|
|
12
|
+
pnpm quality:dependencies
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This runs the full `pnpm audit`, with no production-only or severity filter,
|
|
16
|
+
then verifies the installed CodSpeed bundle policy. Network/audit errors,
|
|
17
|
+
missing packages, incomplete policy entries, changed package files, and unreviewed
|
|
18
|
+
upgrades all fail. `quality:static` includes this command, so the existing CI,
|
|
19
|
+
nightly quality and release paths enforce it. The registry-owned local
|
|
20
|
+
preflight also requires the static gate and permits no skip. Trivy separately
|
|
21
|
+
includes development dependencies in its required repository scan.
|
|
22
|
+
|
|
23
|
+
## File matching dependency removal
|
|
24
|
+
|
|
25
|
+
[GHSA-vfj7-8cjw-p6xm](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm)
|
|
26
|
+
affects `braces` 3.0.3, previously reachable through the production `fast-glob`
|
|
27
|
+
dependency. A pattern under 10,000 characters can exhaust the recursive brace
|
|
28
|
+
expansion stack. No fixed version was published when this change was verified.
|
|
29
|
+
The SDK and repository censuses now use `tinyglobby` 0.2.17, removing `fast-glob`,
|
|
30
|
+
`micromatch` and `braces` from the installed graph. Explicit
|
|
31
|
+
`expandDirectories: false` retains file-only semantics: a directory argument
|
|
32
|
+
does not silently become a recursive match. Dot files, brace and extglob
|
|
33
|
+
patterns, absolute paths and invocation-relative anchoring remain supported.
|
|
34
|
+
The regression uses a real temporary directory and the same deeply nested input
|
|
35
|
+
that failed before the replacement. Audit errors remain mandatory failures.
|
|
36
|
+
|
|
37
|
+
## CodSpeed 5.7.1 patch
|
|
38
|
+
|
|
39
|
+
CodSpeed's declared dependency previously resolved Axios 1.19.0, and both
|
|
40
|
+
`@codspeed/core` bundles embedded Axios 1.4.0. Updating the declared dependency
|
|
41
|
+
alone leaves those embedded implementations and their source-map contents
|
|
42
|
+
intact. The pnpm override selects Axios 1.20.0 or a newer compatible 1.x
|
|
43
|
+
release that satisfies the normal dependency cooldown. The exact-version
|
|
44
|
+
patch in [the patch file](../patches/@codspeed__core@5.7.1.patch) replaces the
|
|
45
|
+
embedded dependency section in both CJS and ESM entries with imports of the
|
|
46
|
+
declared `axios` and `form-data` packages. Each entry creates its own Axios
|
|
47
|
+
client and retains the cancellation constructor, preserving isolation from
|
|
48
|
+
application request and response interceptors.
|
|
49
|
+
|
|
50
|
+
The replacement boundary starts at `function bind$2(fn, thisArg)` and ends
|
|
51
|
+
immediately before `var __defProp$3 = Object.defineProperty`. Only `axios` and
|
|
52
|
+
`FormData$2` from that section are referenced by the retained code. The patch
|
|
53
|
+
preserves the preceding and following benchmark code, declarations, export
|
|
54
|
+
surface and native binaries. Each entry removes 19,201 embedded lines. Its map
|
|
55
|
+
retains 5,375 mappings, removes 39,536 obsolete mappings, and reduces its source
|
|
56
|
+
inventory from 131 to 21. Remaining generated positions are shifted by the
|
|
57
|
+
replacement's line delta; their original source, line, column and names are
|
|
58
|
+
preserved. Removed Axios, redirects, proxy and form-data sources are absent.
|
|
59
|
+
Both maps end with a newline; the integrity policy records the installed bytes.
|
|
60
|
+
|
|
61
|
+
[The integrity policy](../config/dependency-bundle-integrity.json) pins all twelve
|
|
62
|
+
package-owned files by SHA-256: both entries, both maps, all three native binaries,
|
|
63
|
+
the manifest, declarations and declaration map, license and README. Owned
|
|
64
|
+
artifacts must be regular files; symlinks cannot redirect their module resolution
|
|
65
|
+
to an unreviewed dependency tree even when their target bytes have the same hash. Admission
|
|
66
|
+
also checks the exact installed file inventory, so an added executable, map or
|
|
67
|
+
native payload fails even when the previously approved files are unchanged.
|
|
68
|
+
Package-local dependency overrides also fail inventory admission: an added
|
|
69
|
+
`node_modules/axios` could shadow the audited dependency resolved by the bundle.
|
|
70
|
+
Only the three `node-gyp-build` commands and their CMD/PowerShell variants may
|
|
71
|
+
appear directly in `node_modules/.bin`. Each must be a regular file whose complete
|
|
72
|
+
program matches the reviewed [shim templates](../config/codspeed-shims/), with
|
|
73
|
+
targets and module paths derived from the audited installed dependency. Arbitrary
|
|
74
|
+
names, nested payloads, links, altered programs and forged target markers fail;
|
|
75
|
+
these shims are outside the twelve package-owned hashes but are independently
|
|
76
|
+
validated. The shell template records pnpm 11.10.0's installed output; the CMD
|
|
77
|
+
and PowerShell templates come from `@zkochan/cmd-shim` 9.0.7. Template changes
|
|
78
|
+
require renewed real installation evidence on both POSIX and native Windows.
|
|
79
|
+
The CMD suffix follows the installed `PATHEXT` spelling, including `.CMD`;
|
|
80
|
+
format lookup folds its case while validating the complete program. All three
|
|
81
|
+
shell launchers are required, together with the CMD and PowerShell sets on
|
|
82
|
+
Windows. Any additional format must also contain all three commands. Missing
|
|
83
|
+
or duplicate launchers fail admission. Installation roots and rendered paths
|
|
84
|
+
containing shell interpolation syntax fail before template comparison;
|
|
85
|
+
ordinary paths containing spaces remain supported. Templates are comparison
|
|
86
|
+
data: the checker never rewrites pnpm-generated launchers.
|
|
87
|
+
The locked dependency graph is checked by the full audit. An
|
|
88
|
+
upstream upgrade requires a reviewed patch removal or refresh, renewed runtime
|
|
89
|
+
compatibility evidence, and a matching policy update. Never update hashes
|
|
90
|
+
merely to admit an unexplained difference.
|
|
91
|
+
|
|
92
|
+
## Verification and scope
|
|
93
|
+
|
|
94
|
+
The admission suite edits real temporary package copies and proves that each
|
|
95
|
+
changed package file and additional unreviewed payload is refused. The runtime
|
|
96
|
+
integration suite
|
|
97
|
+
uses both public entries in fresh processes, calls a real loopback HTTP server,
|
|
98
|
+
and verifies setup, benchmark start/stop, HTTP failure conversion, exports,
|
|
99
|
+
measurement conversions, root-frame wrappers and isolation from real application
|
|
100
|
+
interceptors. The server observes the
|
|
101
|
+
audited Axios transport rather than a mocked client. The existing CodSpeed
|
|
102
|
+
workflow continues to execute the native benchmark integration.
|
|
103
|
+
|
|
104
|
+
These findings establish vulnerable dependency inventory, not a demonstrated
|
|
105
|
+
production exploit. CodSpeed is a development dependency. Its Mongo
|
|
106
|
+
instrumentation transport requires an explicitly configured instrumentation
|
|
107
|
+
server; ordinary benchmarks do not configure one. Native Scorecard analysis
|
|
108
|
+
of the merged commit must confirm alert retirement independently of local
|
|
109
|
+
audits and PR checks.
|
|
@@ -244,6 +244,24 @@ Explicit overrides below 256 tokens are rejected because the minimum
|
|
|
244
244
|
machine-readable receipt cannot fit; malformed or absent overrides retain the
|
|
245
245
|
declared intent budget.
|
|
246
246
|
|
|
247
|
+
Projection refusals repair the original CLI invocation: tracker selection,
|
|
248
|
+
operands, output encoding, filters and unrelated controls survive the retry.
|
|
249
|
+
Unknown field selectors are removed while valid requested selectors remain.
|
|
250
|
+
Full/projection conflicts retain the selected full or brief mode and remove the
|
|
251
|
+
conflicting projection and intent controls. If that correction cannot be
|
|
252
|
+
constructed safely, the error does not advertise an automatic retry.
|
|
253
|
+
Tracked by [pm-gh1364](../.agents/pm/issues/pm-gh1364.toon).
|
|
254
|
+
|
|
255
|
+
For a budget-compacted producer page, follow
|
|
256
|
+
`output_budget_truncation.recovery.cursor` with `--output-cursor`, keeping the
|
|
257
|
+
original arguments and any `--after` value. Once that cursor is absent, use the
|
|
258
|
+
producer `next_cursor` with `--after` and remove `--output-cursor`. Universal
|
|
259
|
+
output shaping and continuation controls do not change producer query identity;
|
|
260
|
+
actual filter and scope changes still invalidate its cursor. Emitted `count`
|
|
261
|
+
and `summary.returned_focus` describe delivered rows; matching-population totals
|
|
262
|
+
remain separate, including explicit count-only aggregates. Context hierarchy companions may repeat while continuing a
|
|
263
|
+
focus collection. Tracked by [pm-gh1371](../.agents/pm/issues/pm-gh1371.toon).
|
|
264
|
+
|
|
247
265
|
The first cursor page carries the complete projection, filtering, sorting,
|
|
248
266
|
completeness, row, and omission contracts. Continuation pages replace those
|
|
249
267
|
chain-invariant blocks with `continuation_contract`, which carries the cursor's
|
|
@@ -380,3 +398,12 @@ key continue to receive the same rows.
|
|
|
380
398
|
Dependency token accounting includes the projection declaration and derived
|
|
381
399
|
receipt. Reported `usedTokens` and truncation estimates therefore describe the
|
|
382
400
|
final serialized result, not a pre-receipt intermediate.
|
|
401
|
+
|
|
402
|
+
When context field selection hides focus roles or blocker flags, optional
|
|
403
|
+
`summary.focus_row_states` strings retain those classifications across JSON
|
|
404
|
+
transport. Each character corresponds to a delivered record in its named focus
|
|
405
|
+
section: `i`/`I` means in progress, `o`/`O` means open; uppercase means blocked.
|
|
406
|
+
Continuation and compaction slice these receipts with the rows. Self-describing
|
|
407
|
+
focus rows need no extra receipt. Semantic receipts are preserved during
|
|
408
|
+
explanatory-string compaction, and corrupt alphabet or row-count mismatches are
|
|
409
|
+
rejected.
|
package/docs/SDK.md
CHANGED
|
@@ -1449,6 +1449,104 @@ the same durable coordinator, restoring annotations, linked artifacts,
|
|
|
1449
1449
|
lifecycle fields, and claim ownership on failure. It is the SDK primitive
|
|
1450
1450
|
behind `pm item complete`.
|
|
1451
1451
|
|
|
1452
|
+
`previewItemMutations` validates an ordered plan with the same transaction
|
|
1453
|
+
coordinator and lifecycle primitives as apply, using a disposable copy of the
|
|
1454
|
+
tracker. Earlier staged creates, evidence updates and closures participate in
|
|
1455
|
+
later validation. Existing journals retain the coordinator's replay and
|
|
1456
|
+
plan-identity behavior. The preview coordinator writes no source item, history,
|
|
1457
|
+
claim, lock or journal data. Active declarative extension registrations are preserved;
|
|
1458
|
+
executable extension guards, hooks, service overrides, and package command
|
|
1459
|
+
handlers remain disabled. Package-backed `--template` create input cannot be
|
|
1460
|
+
semantically previewed through its package handler; expand it into explicit core
|
|
1461
|
+
mutation options before preview.
|
|
1462
|
+
|
|
1463
|
+
Staging excludes derived `search` and `locks` content and unrelated runtime state,
|
|
1464
|
+
retaining registered item folders, explicitly configured schema files, and
|
|
1465
|
+
`runtime/session.json` for core focus and inherited-parent semantics. Root-layout
|
|
1466
|
+
trackers copy only tracker-owned files and directories, including standard and
|
|
1467
|
+
custom item folders and configured schema files; unrelated project content is
|
|
1468
|
+
excluded. Preview accepts regular files and directories. Entry checks reject
|
|
1469
|
+
existing interior symbolic links and special files; an explicitly selected root
|
|
1470
|
+
link is resolved once to establish the tracker boundary. Absolute configured
|
|
1471
|
+
schema paths inside that resolved boundary are
|
|
1472
|
+
remapped only in the staged settings. Schema files configured outside the
|
|
1473
|
+
tracker fail with `transaction_preview_external_schema`; relocate them inside
|
|
1474
|
+
the selected tracker root before retrying.
|
|
1475
|
+
|
|
1476
|
+
Preview requires trusted, stable directory entries and ancestors. Where Node
|
|
1477
|
+
exposes `O_NOFOLLOW` and `O_NONBLOCK`, descriptor opens request those POSIX guards.
|
|
1478
|
+
Windows retains entry checks, regular-file descriptor checks and snapshot
|
|
1479
|
+
comparisons without these flags. Portable Node APIs do not pin directory entries
|
|
1480
|
+
or ancestors, and later fingerprints cannot prevent hostile path redirection
|
|
1481
|
+
before a read. Use a caller-owned isolated copy when an untrusted actor can
|
|
1482
|
+
concurrently replace workspace paths.
|
|
1483
|
+
|
|
1484
|
+
Durable source bytes are fingerprinted before and after copying and compared
|
|
1485
|
+
with the staged copy. An inconsistent copy or a file disappearing during the
|
|
1486
|
+
scan fails with `transaction_preview_snapshot_changed` and can be retried.
|
|
1487
|
+
File contents are hashed in bounded streams so large history files do not
|
|
1488
|
+
require whole-file buffers. `PmCliError` failures from staged step inspection,
|
|
1489
|
+
compensation preparation and apply preserve their lifecycle classification and
|
|
1490
|
+
include a structured `transaction_operation` with the zero-based index,
|
|
1491
|
+
operation and requested target ID from the mutation plan, after any batch-local
|
|
1492
|
+
reference resolution. That ID need not be prefix-normalized. Native errors and
|
|
1493
|
+
compensation or recovery failures retain the coordinator's error semantics; if
|
|
1494
|
+
compensation also fails, its `AggregateError` preserves the decorated primary
|
|
1495
|
+
error.
|
|
1496
|
+
|
|
1497
|
+
CLI `item mutate --dry-run`, `item complete --dry-run`, and MCP `pm_mutate`
|
|
1498
|
+
with `dryRun: true` share this validation. CLI structured previews use
|
|
1499
|
+
`runWithConfigurationOnlySettings(pmRoot, run, isEnabled?)` across bootstrap,
|
|
1500
|
+
command execution and error cleanup. The optional predicate defaults to enabled.
|
|
1501
|
+
Scoped settings reads validate `settings.json` and
|
|
1502
|
+
merge inline configuration with defaults, without loading or scaffolding optional
|
|
1503
|
+
schema files, running settings-read hooks, or consulting or populating hydrated
|
|
1504
|
+
settings caches. Only selected bootstrap/action tracker roots, the actual global
|
|
1505
|
+
tracker root, and their resolved aliases are scoped.
|
|
1506
|
+
|
|
1507
|
+
Nested async-local scopes compose through new policy layers without modifying
|
|
1508
|
+
their ancestors. Matching-root reads evaluate live predicates, so returning
|
|
1509
|
+
`false` disables that layer while an enabled caller-owned ancestor can still
|
|
1510
|
+
protect the same root. Concurrent invocations keep separate policies, and scopes
|
|
1511
|
+
restore when the callback returns or throws. Staged and unrelated roots retain
|
|
1512
|
+
normal settings behavior, including schema-file hydration.
|
|
1513
|
+
|
|
1514
|
+
CLI bootstrap conservatively protects normalized invocations in the `item`
|
|
1515
|
+
namespace that contain a literal `--dry-run`, before extension option contracts
|
|
1516
|
+
are available. These settings policies cover command registration, invocation
|
|
1517
|
+
base-settings reads and parser-error cleanup. The earliest root `preAction` hook
|
|
1518
|
+
then settles invocation-owned policies from the actual selected command path and
|
|
1519
|
+
effective `optsWithGlobals()` values, before host-owned consent, migration and
|
|
1520
|
+
telemetry preparation. The real parser owns required-option values, `--`
|
|
1521
|
+
boundaries, positional child selection and inherited option precedence. For
|
|
1522
|
+
example, an extension's required `--package-note --dry-run` consumes `--dry-run`
|
|
1523
|
+
as its value. Without a separate preview flag, ordinary apply disables its own
|
|
1524
|
+
policy layers and resumes normal source/global settings hydration, consent,
|
|
1525
|
+
identity initialization and migration preparation. Explicit caller-owned layers
|
|
1526
|
+
remain effective. Genuine previews remain scoped when extension options are
|
|
1527
|
+
present.
|
|
1528
|
+
Structured CLI previews skip host-owned extension
|
|
1529
|
+
migration execution, first-use telemetry consent persistence and installation-ID
|
|
1530
|
+
initialization. Pending migration effects on a later commit remain unvalidated.
|
|
1531
|
+
Existing consented telemetry with a persisted identity still
|
|
1532
|
+
enters derived local queues; preview schedules no flush worker, and later normal
|
|
1533
|
+
commands retain delivery. Normal CLI extension discovery and activation happen
|
|
1534
|
+
before staged execution and retain their existing policy. CLI parser/preflight
|
|
1535
|
+
overrides and before/after-command hooks are also outside staged
|
|
1536
|
+
suppression; `--no-extensions` disables those executable paths.
|
|
1537
|
+
|
|
1538
|
+
`ItemMutationPreviewValidation`
|
|
1539
|
+
reports `validated: true, state: "staged_snapshot"` when the coordinator
|
|
1540
|
+
executes the staged plan. An already committed journal instead returns
|
|
1541
|
+
`validated: false, state: "replayed_committed_plan"`, matching idempotent apply
|
|
1542
|
+
without freshly executing or validating the supplied lifecycle steps. Both
|
|
1543
|
+
results disclose
|
|
1544
|
+
`unresolved_commit_constraints: ["concurrent_tracker_changes",
|
|
1545
|
+
"extension_mutation_guards_and_hooks"]`. Newly staged validation proves core
|
|
1546
|
+
semantic validity at that snapshot; commit still checks current state and runs
|
|
1547
|
+
extension guards and hooks. Preview cost is proportional to the tracker data
|
|
1548
|
+
staged, rather than unrelated root-layout project content.
|
|
1549
|
+
|
|
1452
1550
|
`itemDocumentToMutationOptions` is the companion full-document adapter. It
|
|
1453
1551
|
accepts either a direct `ItemDocument` or the envelope returned by
|
|
1454
1552
|
`pm get <id> --json`, strips read-only metadata, maps canonical snake-case item
|
package/docs/TESTING.md
CHANGED
|
@@ -288,6 +288,8 @@ control and fails if `pm eval --fail-under` stops returning a non-zero exit.
|
|
|
288
288
|
Refresh the baseline only with `pnpm quality:retrieval-eval:update` after
|
|
289
289
|
reviewing query-level ranking changes.
|
|
290
290
|
|
|
291
|
+
Development tools must also pass the [development dependency security gate](DEVELOPMENT_DEPENDENCY_SECURITY.md), including the full audit and installed bundle integrity policy.
|
|
292
|
+
|
|
291
293
|
## Context Quality Evaluation
|
|
292
294
|
|
|
293
295
|
The required context relevance gate proves that `pm context` and `pm next`
|
|
@@ -545,11 +547,36 @@ pm test <item-id> --run --workspace-context snapshot --override-linked-workspace
|
|
|
545
547
|
declaration. Use it only for commands that do not require checkout files.
|
|
546
548
|
- `snapshot` copies the workspace into the linked-test sandbox, runs from that
|
|
547
549
|
copy, and binds its `.agents/pm` path to the selected temporary tracker.
|
|
548
|
-
`.git`, `.agents`,
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
550
|
+
`.git`, `.agents`, coverage output, and common cache directories are excluded
|
|
551
|
+
at every directory depth, with reserved names matched case-insensitively for
|
|
552
|
+
portable admission. Each existing root or nested `node_modules`
|
|
553
|
+
directory is linked at its original relative path, including installations
|
|
554
|
+
already represented by directory symlinks. This preserves independent
|
|
555
|
+
monorepo dependency versions without copying dependency trees. Dependency
|
|
556
|
+
aliases into excluded trees or included workspace source are refused. Internal
|
|
557
|
+
shared targets must remain within admitted `node_modules` subtrees; external
|
|
558
|
+
installations must be disjoint from the source workspace, rather than
|
|
559
|
+
containing it. They remain available even when an external ancestor shares an
|
|
560
|
+
excluded directory name.
|
|
561
|
+
Links are read-only **by convention**; they do not prevent a trusted command
|
|
562
|
+
from modifying the original installation. Use an independent installation
|
|
563
|
+
when testing package-manager operations or dependency writes. Built output
|
|
564
|
+
remains available so linked commands such as `node dist/cli.js` keep working.
|
|
565
|
+
The source workspace root is resolved before copying. Ordinary file and
|
|
566
|
+
directory symlinks into included workspace source are rebased into the copy,
|
|
567
|
+
including dangling file aliases; writes through those aliases stay in the
|
|
568
|
+
disposable snapshot. Targets are canonicalized through their nearest existing
|
|
569
|
+
ancestor, so absolute aliases through another workspace path spelling and
|
|
570
|
+
missing target suffixes retain the same isolation on supported platforms.
|
|
571
|
+
Source aliases into unadmitted external directories or excluded tracker/build
|
|
572
|
+
trees fail before the linked command runs. An alias into an admitted shared
|
|
573
|
+
dependency namespace retains the dependency-write convention above, including
|
|
574
|
+
packages linked within that installation. Source and snapshot destinations
|
|
575
|
+
must be physically disjoint; overlapping roots fail before copying with a
|
|
576
|
+
diagnostic directing the caller to a temporary root outside the checkout.
|
|
577
|
+
|
|
578
|
+
The real-filesystem regression for this contract is tracked by
|
|
579
|
+
[pm-5iwfkj](../.agents/pm/issues/pm-5iwfkj.toon).
|
|
553
580
|
|
|
554
581
|
Every result reports the requested/effective workspace mode, working
|
|
555
582
|
directory, exposed source root, and trust decision. Recorded `test_runs` retain
|
|
@@ -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: 393
|
|
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: 374
|
|
12
|
+
- Coverage fraction: 0.048346
|
|
13
13
|
- Closed-domain probes: 19
|
|
14
14
|
- Grammar probes: 117
|
|
15
15
|
|
|
@@ -321,6 +321,8 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati
|
|
|
321
321
|
| `tracker_root_missing` | `tracker_root_missing` | executable | owned_state | 1 |
|
|
322
322
|
| `tracker_root_not_directory` | `tracker_root_not_directory` | executable | owned_state | 1 |
|
|
323
323
|
| `tracker_root_unreadable` | `tracker_root_unreadable` | executable | owned_state | 1 |
|
|
324
|
+
| `transaction_preview_external_schema` | `transaction_preview_external_schema` | uncovered | none | 0 |
|
|
325
|
+
| `transaction_preview_snapshot_changed` | `transaction_preview_snapshot_changed` | uncovered | none | 0 |
|
|
324
326
|
| `type_duplicate` | `type_duplicate` | uncovered | none | 0 |
|
|
325
327
|
| `type_invalid` | `type_invalid` | uncovered | none | 0 |
|
|
326
328
|
| `undeclared_observation` | `undeclared_observation` | uncovered | none | 0 |
|
package/marketplace.json
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
"url": "https://github.com/unbraind/pm-cli"
|
|
6
6
|
},
|
|
7
7
|
"description": "Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.",
|
|
8
|
-
"version": "2026.10.
|
|
8
|
+
"version": "2026.10.3",
|
|
9
9
|
"plugins": [
|
|
10
10
|
{
|
|
11
11
|
"name": "pm-claude",
|
|
12
12
|
"source": "./plugins/pm-claude",
|
|
13
13
|
"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.",
|
|
14
|
-
"version": "2026.10.
|
|
14
|
+
"version": "2026.10.3",
|
|
15
15
|
"author": {
|
|
16
16
|
"name": "unbrained",
|
|
17
17
|
"url": "https://github.com/unbraind/pm-cli"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unbrained/pm-cli",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.3",
|
|
4
4
|
"description": "Git-native project management CLI for humans and agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.10.0",
|
|
@@ -123,8 +123,9 @@
|
|
|
123
123
|
"lint:complexity:baseline": "eslint . --suppress-rule complexity --suppress-rule sonarjs/cognitive-complexity",
|
|
124
124
|
"lint:duplicates": "jscpd --config .jscpd.json && jscpd --config .jscpd.source.json && jscpd --config .jscpd.tables.json",
|
|
125
125
|
"lint:codefactor": "pnpm quality:static",
|
|
126
|
-
"quality:static": "pnpm quality:docstrings && pnpm quality:exports && pnpm lint:eslint && pnpm lint:duplicates && node scripts/check-workflow-permissions.mjs && node scripts/check-dependency-cooldown.mjs && node scripts/gen-plugin-mcp-wrappers.mjs --check && node scripts/gen-agent-plugin-skills.mjs --check && pnpm build && node scripts/contracts-snapshot.mjs --check && node scripts/generate-agent-capability-surfaces.mjs --check && node scripts/generate-error-code-catalog.mjs --check && node scripts/release/repository-assurance.mjs repository-static-quality --trigger ci --json && node scripts/release/audit-package-boundary.mjs && node scripts/release/package-sdk-contract-parity.mjs && node scripts/release/surface-replication-gate.mjs && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs && node scripts/release/refusal-closure-gate.mjs && node scripts/release/agent-task-token-gate.mjs && pnpm quality:mcp-deprecations && node dist/cli.js assurance run tracker-context-quality --trigger ci --dry-run --json --output-budget unbounded && node scripts/release/gate-registry.mjs && node scripts/sdk-surface-snapshot.mjs --check && node scripts/bench/sdk-entrypoint-costs.mjs --check && node scripts/bench/cli-transport-floor.mjs --check && node dist/cli.js assurance run graph-composition --trigger ci --dry-run --json --output-budget unbounded && node dist/cli.js assurance run record-integrity --trigger ci --dry-run --json --output-budget unbounded && pnpm quality:mutation -- --prebuilt",
|
|
126
|
+
"quality:static": "pnpm quality:dependencies && pnpm quality:docstrings && pnpm quality:exports && pnpm lint:eslint && pnpm lint:duplicates && node scripts/check-workflow-permissions.mjs && node scripts/check-dependency-cooldown.mjs && node scripts/gen-plugin-mcp-wrappers.mjs --check && node scripts/gen-agent-plugin-skills.mjs --check && pnpm build && node scripts/contracts-snapshot.mjs --check && node scripts/generate-agent-capability-surfaces.mjs --check && node scripts/generate-error-code-catalog.mjs --check && node scripts/release/repository-assurance.mjs repository-static-quality --trigger ci --json && node scripts/release/audit-package-boundary.mjs && node scripts/release/package-sdk-contract-parity.mjs && node scripts/release/surface-replication-gate.mjs && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs && node scripts/release/refusal-closure-gate.mjs && node scripts/release/agent-task-token-gate.mjs && pnpm quality:mcp-deprecations && node dist/cli.js assurance run tracker-context-quality --trigger ci --dry-run --json --output-budget unbounded && node scripts/release/gate-registry.mjs && node scripts/sdk-surface-snapshot.mjs --check && node scripts/bench/sdk-entrypoint-costs.mjs --check && node scripts/bench/cli-transport-floor.mjs --check && node dist/cli.js assurance run graph-composition --trigger ci --dry-run --json --output-budget unbounded && node dist/cli.js assurance run record-integrity --trigger ci --dry-run --json --output-budget unbounded && pnpm quality:mutation -- --prebuilt",
|
|
127
127
|
"quality:exports": "knip --no-config-hints && node scripts/run-tests.mjs test -- tests/unit/scripts/release/dead-exports.spec.ts",
|
|
128
|
+
"quality:dependencies": "pnpm audit && node scripts/check-development-dependencies.mjs",
|
|
128
129
|
"quality:command-grammar": "pnpm build && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs",
|
|
129
130
|
"quality:recovery-closure": "pnpm build && node scripts/release/refusal-closure-gate.mjs",
|
|
130
131
|
"quality:token-budget": "node scripts/release/token-budget-gate.mjs",
|
|
@@ -216,16 +217,16 @@
|
|
|
216
217
|
"@toon-format/toon": "^4.1.1",
|
|
217
218
|
"@types/node": ">=22",
|
|
218
219
|
"commander": "^15.0.0",
|
|
219
|
-
"fast-glob": "^3.3.3",
|
|
220
220
|
"fast-json-patch": "^3.1.1",
|
|
221
221
|
"npm-package-arg": "^13.0.2",
|
|
222
222
|
"tar": "7.5.22",
|
|
223
|
+
"tinyglobby": "^0.2.17",
|
|
223
224
|
"yaml": "^2.9.1"
|
|
224
225
|
},
|
|
225
226
|
"devDependencies": {
|
|
226
227
|
"@codspeed/vitest-plugin": "^5.7.1",
|
|
227
228
|
"@eslint/js": "^10.0.1",
|
|
228
|
-
"@modelcontextprotocol/ext-apps": "2.0.
|
|
229
|
+
"@modelcontextprotocol/ext-apps": "2.0.3",
|
|
229
230
|
"@sentry/cli": "^3.8.0",
|
|
230
231
|
"@stryker-mutator/core": "10.0.0",
|
|
231
232
|
"@stryker-mutator/vitest-runner": "10.0.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unbrained/pm-digital-twin",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.3",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Beyond-PM exemplar: a temporal production-facility digital twin built entirely on public pm SDK and extension primitives.",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "pm-claude",
|
|
4
4
|
"displayName": "pm CLI",
|
|
5
5
|
"description": "Native pm CLI integration for Claude Code — 32 MCP tools, 14 skills with slash invocations, 4 subagents (coordinator, delivery-chain, triage, verification), hybrid TUI task tracking (pm as persistent store + Claude Code task panel as live view), session context injection, and full git-based project management without leaving Claude Code.",
|
|
6
|
-
"version": "2026.10.
|
|
6
|
+
"version": "2026.10.3",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "unbrained",
|
|
9
9
|
"url": "https://github.com/unbraind/pm-cli"
|