@unbrained/pm-cli 2026.9.13 → 2026.9.15
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 +34 -0
- package/dist/cli/commander-usage.js +2 -2
- package/dist/cli/error-guidance.js +1 -1
- package/dist/cli/extension-command-help.d.ts +2 -2
- package/dist/cli/extension-command-help.js +2 -2
- package/dist/cli-bundle/bundle-manifest.json +144 -144
- package/dist/cli-bundle/chunks/{chunk-KM4XVZR7.js → chunk-3AHONKLL.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-ZZI7IHMM.js → chunk-3RB6Z7XE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-GQQR6JAL.js → chunk-5P5PYCZX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-XM7RWQLM.js → chunk-BOZ4HVYL.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-J4DRE3WN.js +237 -0
- package/dist/cli-bundle/chunks/{chunk-LA44JECQ.js → chunk-RKPUO75B.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-XEZOGC3P.js → chunk-RM2OGG65.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-YQTJACN5.js → chunk-UKLOSZV6.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-GBK5MV6N.js → chunk-WDF7PP4P.js} +26 -26
- package/dist/cli-bundle/chunks/chunk-WLJJ4MAU.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-YDSV4QIQ.js → chunk-Y2P3DSSO.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-3DWX3CKN.js → chunk-YMMLKKEP.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-WMJTBWNW.js → register-list-query-IWSPNFFD.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-EXGOXP3D.js → register-mutation-3DVF4R64.js} +2 -2
- package/dist/cli-bundle/chunks/{register-operations-2H4CDRGU.js → register-operations-LXP3MECQ.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-NYBWGPOS.js → register-setup-KFQSNBDX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4YTDKIPF.js +30 -0
- package/dist/cli-bundle/focused-chunks/{chunk-LQ67C7ZO.js → chunk-533DCWPY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-B6JAANOH.js → chunk-5SBU4QDC.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-SDQCJF4H.js → chunk-63YRRGKX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-KP3N6PVZ.js → chunk-6C3CUU2G.js} +3 -3
- package/dist/cli-bundle/focused-chunks/{chunk-TUHRUFID.js → chunk-AXDAIBT3.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FBCLVOBE.js → chunk-BMATJLPT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-DSJYL4VP.js → chunk-JKJYXCT6.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-V7PSTKHD.js → chunk-MD7ADLME.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-OENAWWP4.js → chunk-OGGF2RBL.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FPNI4U2B.js → chunk-PBJC2ZNA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-SHF57M2H.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-F66QJWI4.js → chunk-UACMCSCC.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-XCCM7P7V.js → chunk-YBQTVE5S.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-ZAMG7HBB.js → chunk-ZHX3433X.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZOE2NSJB.js +20 -0
- package/dist/cli-bundle/main.js +19 -19
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +24 -24
- 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 +40 -40
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +8 -8
- package/dist/core/extensions/index.d.ts +7 -0
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/lock/lock.js +2 -2
- package/dist/core/output/output.js +3 -3
- package/dist/core/telemetry/policy.d.ts +2 -0
- package/dist/core/telemetry/policy.js +1 -1
- package/dist/core/telemetry/read-sampling.d.ts +8 -0
- package/dist/core/telemetry/read-sampling.js +3 -0
- package/dist/core/telemetry/runtime.d.ts +35 -8
- package/dist/core/telemetry/runtime.js +5 -4
- package/dist/sdk/agent/command-suggestions.d.ts +6 -0
- package/dist/sdk/agent/command-suggestions.js +1 -1
- package/dist/sdk/cli-contracts/command-aliases.js +1 -1
- package/dist/sdk/cli-contracts/grammar-contracts.d.ts +2 -2
- package/dist/sdk/cli-contracts/grammar-contracts.js +1 -1
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +7 -3
- package/dist/sdk/cli-contracts/runtime-contracts.js +1 -1
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/telemetry.js +1 -1
- package/docs/AGENT_UX_CONTRACTS.md +10 -2
- package/docs/CLI_GRAMMAR.md +28 -0
- package/docs/CONFIGURATION.md +41 -3
- package/docs/generated/AGENT_CAPABILITY_ROUTING.md +1 -1
- package/docs/generated/AGENT_COMMAND_SURFACE.md +1 -0
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +1 -0
- package/marketplace.json +2 -2
- package/package.json +5 -5
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/dist/cli-bundle/chunks/chunk-6KHYW3FH.js +0 -235
- package/dist/cli-bundle/chunks/chunk-AKTBOX6U.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-7JR6M2JR.js +0 -30
- package/dist/cli-bundle/focused-chunks/chunk-YUXBHIUV.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-ZF5PXK6A.js +0 -2
package/dist/sdk/telemetry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1f7fc9b3-ef8b-56df-b1e4-2b5a3560716e")}catch(e2){}})();import fs from"node:fs/promises";import path from"node:path";import{pathExists,readFileIfExists}from"../core/fs/fs-utils.js";import{EXIT_CODE}from"../core/shared/constants.js";import{PmCliError}from"../core/shared/errors.js";import{nowIso}from"../core/shared/time.js";import{resolveGlobalPmRoot}from"../core/store/paths.js";import{readSettings,writeSettings}from"../core/store/settings.js";import{resolveTelemetryEnvironmentPolicy}from"../core/telemetry/policy.js";import{flushTelemetryQueueNow}from"../core/telemetry/runtime.js";import{createUnknownSubcommandError}from"./agent/subcommand-recovery.js";const TELEMETRY_QUEUE_RELATIVE_PATH=path.join("runtime","telemetry","events.jsonl");const TELEMETRY_STATE_RELATIVE_PATH=path.join("runtime","telemetry","state.json");const TELEMETRY_RUNTIME_RELATIVE_PATH=path.join("runtime","telemetry");const DEFAULT_STATS_LIMIT=20;const TELEMETRY_SUBCOMMANDS=["status","flush","stats","clear"];const nearestRankPercentile=(sortedAscending,fraction)=>{const rank=Math.ceil(fraction*sortedAscending.length);const index=Math.min(sortedAscending.length-1,Math.max(0,rank-1));return sortedAscending[index]};const normalizeTelemetryText=(value,fallback)=>{if(typeof value!=="string"){return fallback}return value.trim().length>0?value:fallback};const normalizeFiniteInteger=value=>{if(typeof value!=="number"||!Number.isFinite(value)){return void 0}return Math.trunc(value)};const normalizeTelemetryQueueEntry=entry=>{return{command:normalizeTelemetryText(entry.event.command,"<unknown>"),eventType:normalizeTelemetryText(entry.event.event_type,"unknown"),eventSchemaVersion:normalizeFiniteInteger(entry.event.schema_version),clientSchemaVersion:normalizeFiniteInteger(entry.client_schema_version)}};const createTelemetryStatsAccumulator=()=>{return{count:0,max_attempts:0,event_type_counts:{},event_schema_versions:new Set,client_schema_versions:new Set,finish_durations_ms:[],ok_count:0,error_count:0,resolution_counts:{}}};const readTelemetryDuration=payload=>{const value=payload?.duration_ms;return typeof value==="number"&&Number.isFinite(value)?value:void 0};const readTelemetryResolution=payload=>{const value=payload?.command_resolution;return normalizeTelemetryText(value,"")||void 0};const incrementTelemetryCount=(counts,key)=>{counts[key]=(counts[key]??0)+1};const recordTelemetryFinishPayload=(current,payload)=>{const durationMs=readTelemetryDuration(payload);if(durationMs!==void 0){current.finish_durations_ms.push(durationMs)}if(payload?.ok===true){current.ok_count+=1}else{current.error_count+=1}const resolution=readTelemetryResolution(payload);if(resolution!==void 0){incrementTelemetryCount(current.resolution_counts,resolution)}};const normalizeTelemetryAttempts=attempts=>Number.isFinite(attempts)?Math.max(0,Math.trunc(attempts)):0;const addTelemetryDimension=(values,value)=>{if(value!==void 0){values.add(value)}};const recordTelemetryQueueEntry=(grouped,entry)=>{const normalized=normalizeTelemetryQueueEntry(entry);const current=grouped.get(normalized.command)??createTelemetryStatsAccumulator();current.count+=1;current.max_attempts=Math.max(current.max_attempts,normalizeTelemetryAttempts(entry.attempts));incrementTelemetryCount(current.event_type_counts,normalized.eventType);addTelemetryDimension(current.event_schema_versions,normalized.eventSchemaVersion);addTelemetryDimension(current.client_schema_versions,normalized.clientSchemaVersion);if(normalized.eventType==="command_finish"){recordTelemetryFinishPayload(current,entry.event.payload)}grouped.set(normalized.command,current)};const buildTelemetryStatsBucket=(command,value)=>{const finishCount=value.ok_count+value.error_count;const sortedDurations=[...value.finish_durations_ms].sort((left,right)=>left-right);const resolutionEntries=Object.entries(value.resolution_counts).sort((left,right)=>left[0].localeCompare(right[0]));return{command,count:value.count,event_type_counts:Object.fromEntries(Object.entries(value.event_type_counts).sort((left,right)=>left[0].localeCompare(right[0]))),max_attempts:value.max_attempts,event_schema_versions:[...value.event_schema_versions].sort((left,right)=>left-right),client_schema_versions:[...value.client_schema_versions].sort((left,right)=>left-right),...sortedDurations.length>0?{duration_p50_ms:nearestRankPercentile(sortedDurations,.5),duration_p95_ms:nearestRankPercentile(sortedDurations,.95),duration_max_ms:sortedDurations[sortedDurations.length-1]}:{},...finishCount>0?{ok_count:value.ok_count,error_count:value.error_count,error_rate:value.error_count/finishCount}:{},...resolutionEntries.length>0?{command_resolution_counts:Object.fromEntries(resolutionEntries)}:{}}};const normalizeTelemetrySubcommand=value=>{const normalized=(value??"status").trim().toLowerCase();if(TELEMETRY_SUBCOMMANDS.includes(normalized)){return normalized}throw createUnknownSubcommandError({command_path:"telemetry",token:value?.trim()||"<empty>",allowed:TELEMETRY_SUBCOMMANDS,examples:["pm telemetry status","pm telemetry flush","pm telemetry stats --limit 10","pm telemetry clear"]})};const throwInvalidTelemetryLimit=()=>{throw new PmCliError("--limit must be a positive integer",EXIT_CODE.USAGE)};const requirePositiveTelemetryLimit=value=>{if([!Number.isFinite(value),!Number.isInteger(value),value<=0].includes(true)){return throwInvalidTelemetryLimit()}return value};const parseTelemetryStringLimit=raw=>{const trimmed=raw.trim();if([trimmed.length===0,!/^\d+$/.test(trimmed)].includes(true)){return throwInvalidTelemetryLimit()}return requirePositiveTelemetryLimit(Number.parseInt(trimmed,10))};const parseTelemetryStatsLimit=raw=>{if(raw===void 0){return DEFAULT_STATS_LIMIT}if(typeof raw==="number"){return requirePositiveTelemetryLimit(raw)}if(typeof raw==="string"){return parseTelemetryStringLimit(raw)}return throwInvalidTelemetryLimit()};const isTelemetryQueueEntry=value=>{if(typeof value!=="object"||value===null){return false}const candidate=value;return typeof candidate.attempts==="number"&&typeof candidate.event==="object"&&candidate.event!==null};const parseTelemetryQueueRow=row=>{try{const parsed=JSON.parse(row);return isTelemetryQueueEntry(parsed)?parsed:void 0}catch{return void 0}};const splitTelemetryQueueRows=raw=>{if(raw===null){return[]}return raw.split("\n").map(line=>line.trim()).filter(line=>line.length>0)};const parseTelemetryQueue=raw=>{const rows=splitTelemetryQueueRows(raw);const entries=[];let invalidRows=0;for(const row of rows){const parsed=parseTelemetryQueueRow(row);if(parsed===void 0){invalidRows+=1}else{entries.push(parsed)}}return{rows_total:rows.length,valid_entries:entries.length,invalid_rows:invalidRows,entries}};const isTelemetryRuntimeState=value=>typeof value==="object"&&value!==null&&!Array.isArray(value);const parseTelemetryRuntimeState=raw=>{try{const parsed=JSON.parse(raw);return isTelemetryRuntimeState(parsed)?parsed:{}}catch{return{}}};const readTelemetryRuntimeState=async statePath=>{const stateRaw=await readFileIfExists(statePath);if(stateRaw===null||stateRaw.trim().length===0){return{}}return parseTelemetryRuntimeState(stateRaw)};const nullableTelemetryStateValue=value=>value??null;const buildTelemetryStatusSummary=async globalPmRoot=>{const settings=await readSettings(globalPmRoot);const queuePath=path.join(globalPmRoot,TELEMETRY_QUEUE_RELATIVE_PATH);const statePath=path.join(globalPmRoot,TELEMETRY_STATE_RELATIVE_PATH);const queueRaw=await readFileIfExists(queuePath);const queue=parseTelemetryQueue(queueRaw);const runtimeState=await readTelemetryRuntimeState(statePath);const environmentPolicy=resolveTelemetryEnvironmentPolicy();return{enabled:settings.telemetry.enabled&&!environmentPolicy.telemetry_disabled,configured_enabled:settings.telemetry.enabled,env_overrides:environmentPolicy,endpoint:settings.telemetry.endpoint,queue_path:queuePath,state_path:statePath,queue_rows_total:queue.rows_total,queue_entries:queue.valid_entries,queue_invalid_rows:queue.invalid_rows,queue_size_bytes:Buffer.byteLength(queueRaw??"","utf8"),last_attempted_flush_at:nullableTelemetryStateValue(runtimeState.last_attempted_flush_at),last_successful_flush_at:nullableTelemetryStateValue(runtimeState.last_successful_flush_at),last_failed_flush_at:nullableTelemetryStateValue(runtimeState.last_failed_flush_at),last_failed_flush_error:nullableTelemetryStateValue(runtimeState.last_failed_flush_error)}};const buildTelemetryStatsBuckets=entries=>{const grouped=new Map;for(const entry of entries){recordTelemetryQueueEntry(grouped,entry)}return[...grouped.entries()].map(([command,value])=>buildTelemetryStatsBucket(command,value)).sort((left,right)=>right.count-left.count||left.command.localeCompare(right.command))};const runTelemetryStatus=async(_options,context)=>({action:"telemetry",subcommand:"status",status:await buildTelemetryStatusSummary(context.globalPmRoot),generated_at:nowIso()});const runTelemetryFlush=async(_options,context)=>{const before=await buildTelemetryStatusSummary(context.globalPmRoot);await flushTelemetryQueueNow(context.globalPmRoot);const after=await buildTelemetryStatusSummary(context.globalPmRoot);const queueEntriesDrained=Math.max(0,before.queue_entries-after.queue_entries);const queueEmpty=after.queue_entries===0;return{action:"telemetry",subcommand:"flush",queue_entries_before:before.queue_entries,queue_entries_after:after.queue_entries,queue_entries_drained:queueEntriesDrained,queue_progressed:queueEntriesDrained>0,queue_empty:queueEmpty,queue_drained:queueEmpty,status:after,generated_at:nowIso()}};const runTelemetryStats=async(options,context)=>{const limit=parseTelemetryStatsLimit(options.limit);const queueRaw=await readFileIfExists(context.queuePath);const queue=parseTelemetryQueue(queueRaw);const buckets=buildTelemetryStatsBuckets(queue.entries);const selected=buckets.slice(0,limit);return{action:"telemetry",subcommand:"stats",limit,total_commands:buckets.length,queue_entries:queue.valid_entries,queue_invalid_rows:queue.invalid_rows,queue_rows_total:queue.rows_total,truncated:buckets.length>selected.length,stats:selected,generated_at:nowIso()}};const runTelemetryClear=async(_options,context)=>{const settings=await readSettings(context.globalPmRoot);const settingsChanged=[settings.telemetry.enabled!==false,settings.telemetry.installation_id!=="",settings.telemetry.first_run_prompt_completed!==true].includes(true);settings.telemetry.enabled=false;settings.telemetry.first_run_prompt_completed=true;settings.telemetry.installation_id="";if(settingsChanged){await writeSettings(context.globalPmRoot,settings,"telemetry:clear")}const telemetryRuntimePath=path.join(context.globalPmRoot,TELEMETRY_RUNTIME_RELATIVE_PATH);const existed=await pathExists(telemetryRuntimePath);await fs.rm(telemetryRuntimePath,{recursive:true,force:true});return{action:"telemetry",subcommand:"clear",settings_changed:settingsChanged,runtime_dir_removed:existed&&!await pathExists(telemetryRuntimePath),queue_exists_after:await pathExists(context.queuePath),state_exists_after:await pathExists(context.statePath),status:await buildTelemetryStatusSummary(context.globalPmRoot),generated_at:nowIso()}};const TELEMETRY_COMMAND_HANDLERS={status:runTelemetryStatus,flush:runTelemetryFlush,stats:runTelemetryStats,clear:runTelemetryClear};async function runTelemetry(options,_global){void _global;const subcommand=normalizeTelemetrySubcommand(options.subcommand);const globalPmRoot=resolveGlobalPmRoot(process.cwd());return TELEMETRY_COMMAND_HANDLERS[subcommand](options,{globalPmRoot,queuePath:path.join(globalPmRoot,TELEMETRY_QUEUE_RELATIVE_PATH),statePath:path.join(globalPmRoot,TELEMETRY_STATE_RELATIVE_PATH)})}export{TELEMETRY_SUBCOMMANDS,runTelemetry};
|
|
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]="0c2960a8-84b8-57d1-bf5f-cea9cde0f544")}catch(e2){}})();import fs from"node:fs/promises";import path from"node:path";import{pathExists,readFileIfExists}from"../core/fs/fs-utils.js";import{EXIT_CODE}from"../core/shared/constants.js";import{PmCliError}from"../core/shared/errors.js";import{nowIso}from"../core/shared/time.js";import{resolveGlobalPmRoot}from"../core/store/paths.js";import{readSettings,writeSettings}from"../core/store/settings.js";import{resolveTelemetryEnvironmentPolicy}from"../core/telemetry/policy.js";import{flushTelemetryQueueNow,withTelemetryQueueMutation}from"../core/telemetry/runtime.js";import{createUnknownSubcommandError}from"./agent/subcommand-recovery.js";const TELEMETRY_QUEUE_RELATIVE_PATH=path.join("runtime","telemetry","events.jsonl");const TELEMETRY_STATE_RELATIVE_PATH=path.join("runtime","telemetry","state.json");const TELEMETRY_RUNTIME_RELATIVE_PATH=path.join("runtime","telemetry");const DEFAULT_STATS_LIMIT=20;const TELEMETRY_SUBCOMMANDS=["status","flush","stats","clear"];const nearestRankPercentile=(sortedAscending,fraction)=>{const rank=Math.ceil(fraction*sortedAscending.length);const index=Math.min(sortedAscending.length-1,Math.max(0,rank-1));return sortedAscending[index]};const normalizeTelemetryText=(value,fallback)=>{if(typeof value!=="string"){return fallback}return value.trim().length>0?value:fallback};const normalizeFiniteInteger=value=>{if(typeof value!=="number"||!Number.isFinite(value)){return void 0}return Math.trunc(value)};const normalizeTelemetryQueueEntry=entry=>{return{command:normalizeTelemetryText(entry.event.command,"<unknown>"),eventType:normalizeTelemetryText(entry.event.event_type,"unknown"),eventSchemaVersion:normalizeFiniteInteger(entry.event.schema_version),clientSchemaVersion:normalizeFiniteInteger(entry.client_schema_version)}};const createTelemetryStatsAccumulator=()=>{return{count:0,max_attempts:0,event_type_counts:{},event_schema_versions:new Set,client_schema_versions:new Set,finish_durations_ms:[],ok_count:0,error_count:0,resolution_counts:{}}};const readTelemetryDuration=payload=>{const value=payload?.duration_ms;return typeof value==="number"&&Number.isFinite(value)?value:void 0};const readTelemetryResolution=payload=>{const value=payload?.command_resolution;return normalizeTelemetryText(value,"")||void 0};const incrementTelemetryCount=(counts,key)=>{counts[key]=(counts[key]??0)+1};const recordTelemetryFinishPayload=(current,payload)=>{const durationMs=readTelemetryDuration(payload);if(durationMs!==void 0){current.finish_durations_ms.push(durationMs)}if(payload?.ok===true){current.ok_count+=1}else{current.error_count+=1}const resolution=readTelemetryResolution(payload);if(resolution!==void 0){incrementTelemetryCount(current.resolution_counts,resolution)}};const normalizeTelemetryAttempts=attempts=>Number.isFinite(attempts)?Math.max(0,Math.trunc(attempts)):0;const addTelemetryDimension=(values,value)=>{if(value!==void 0){values.add(value)}};const recordTelemetryQueueEntry=(grouped,entry)=>{const normalized=normalizeTelemetryQueueEntry(entry);const current=grouped.get(normalized.command)??createTelemetryStatsAccumulator();current.count+=1;current.max_attempts=Math.max(current.max_attempts,normalizeTelemetryAttempts(entry.attempts));incrementTelemetryCount(current.event_type_counts,normalized.eventType);addTelemetryDimension(current.event_schema_versions,normalized.eventSchemaVersion);addTelemetryDimension(current.client_schema_versions,normalized.clientSchemaVersion);if(normalized.eventType==="command_finish"){recordTelemetryFinishPayload(current,entry.event.payload)}grouped.set(normalized.command,current)};const buildTelemetryStatsBucket=(command,value)=>{const finishCount=value.ok_count+value.error_count;const sortedDurations=[...value.finish_durations_ms].sort((left,right)=>left-right);const resolutionEntries=Object.entries(value.resolution_counts).sort((left,right)=>left[0].localeCompare(right[0]));return{command,count:value.count,event_type_counts:Object.fromEntries(Object.entries(value.event_type_counts).sort((left,right)=>left[0].localeCompare(right[0]))),max_attempts:value.max_attempts,event_schema_versions:[...value.event_schema_versions].sort((left,right)=>left-right),client_schema_versions:[...value.client_schema_versions].sort((left,right)=>left-right),...sortedDurations.length>0?{duration_p50_ms:nearestRankPercentile(sortedDurations,.5),duration_p95_ms:nearestRankPercentile(sortedDurations,.95),duration_max_ms:sortedDurations[sortedDurations.length-1]}:{},...finishCount>0?{ok_count:value.ok_count,error_count:value.error_count,error_rate:value.error_count/finishCount}:{},...resolutionEntries.length>0?{command_resolution_counts:Object.fromEntries(resolutionEntries)}:{}}};const normalizeTelemetrySubcommand=value=>{const normalized=(value??"status").trim().toLowerCase();if(TELEMETRY_SUBCOMMANDS.includes(normalized)){return normalized}throw createUnknownSubcommandError({command_path:"telemetry",token:value?.trim()||"<empty>",allowed:TELEMETRY_SUBCOMMANDS,examples:["pm telemetry status","pm telemetry flush","pm telemetry stats --limit 10","pm telemetry clear"]})};const throwInvalidTelemetryLimit=()=>{throw new PmCliError("--limit must be a positive integer",EXIT_CODE.USAGE)};const requirePositiveTelemetryLimit=value=>{if([!Number.isFinite(value),!Number.isInteger(value),value<=0].includes(true)){return throwInvalidTelemetryLimit()}return value};const parseTelemetryStringLimit=raw=>{const trimmed=raw.trim();if([trimmed.length===0,!/^\d+$/.test(trimmed)].includes(true)){return throwInvalidTelemetryLimit()}return requirePositiveTelemetryLimit(Number.parseInt(trimmed,10))};const parseTelemetryStatsLimit=raw=>{if(raw===void 0){return DEFAULT_STATS_LIMIT}if(typeof raw==="number"){return requirePositiveTelemetryLimit(raw)}if(typeof raw==="string"){return parseTelemetryStringLimit(raw)}return throwInvalidTelemetryLimit()};const isTelemetryQueueEntry=value=>{if(typeof value!=="object"||value===null){return false}const candidate=value;return typeof candidate.attempts==="number"&&typeof candidate.event==="object"&&candidate.event!==null};const parseTelemetryQueueRow=row=>{try{const parsed=JSON.parse(row);return isTelemetryQueueEntry(parsed)?parsed:void 0}catch{return void 0}};const splitTelemetryQueueRows=raw=>{if(raw===null){return[]}return raw.split("\n").map(line=>line.trim()).filter(line=>line.length>0)};const parseTelemetryQueue=raw=>{const rows=splitTelemetryQueueRows(raw);const entries=[];let invalidRows=0;for(const row of rows){const parsed=parseTelemetryQueueRow(row);if(parsed===void 0){invalidRows+=1}else{entries.push(parsed)}}return{rows_total:rows.length,valid_entries:entries.length,invalid_rows:invalidRows,entries}};const isTelemetryRuntimeState=value=>typeof value==="object"&&value!==null&&!Array.isArray(value);const parseTelemetryRuntimeState=raw=>{try{const parsed=JSON.parse(raw);return isTelemetryRuntimeState(parsed)?parsed:{}}catch{return{}}};const readTelemetryRuntimeState=async statePath=>{const stateRaw=await readFileIfExists(statePath);if(stateRaw===null||stateRaw.trim().length===0){return{}}return parseTelemetryRuntimeState(stateRaw)};const nullableTelemetryStateValue=value=>value??null;const buildTelemetryStatusSummary=async globalPmRoot=>{const settings=await readSettings(globalPmRoot);const queuePath=path.join(globalPmRoot,TELEMETRY_QUEUE_RELATIVE_PATH);const statePath=path.join(globalPmRoot,TELEMETRY_STATE_RELATIVE_PATH);const queueRaw=await readFileIfExists(queuePath);const queue=parseTelemetryQueue(queueRaw);const runtimeState=await readTelemetryRuntimeState(statePath);const environmentPolicy=resolveTelemetryEnvironmentPolicy();return{enabled:settings.telemetry.enabled&&!environmentPolicy.telemetry_disabled,configured_enabled:settings.telemetry.enabled,env_overrides:environmentPolicy,endpoint:settings.telemetry.endpoint,queue_path:queuePath,state_path:statePath,queue_rows_total:queue.rows_total,queue_entries:queue.valid_entries,queue_invalid_rows:queue.invalid_rows,queue_size_bytes:Buffer.byteLength(queueRaw??"","utf8"),last_attempted_flush_at:nullableTelemetryStateValue(runtimeState.last_attempted_flush_at),last_successful_flush_at:nullableTelemetryStateValue(runtimeState.last_successful_flush_at),last_failed_flush_at:nullableTelemetryStateValue(runtimeState.last_failed_flush_at),last_failed_flush_error:nullableTelemetryStateValue(runtimeState.last_failed_flush_error)}};const buildTelemetryStatsBuckets=entries=>{const grouped=new Map;for(const entry of entries){recordTelemetryQueueEntry(grouped,entry)}return[...grouped.entries()].map(([command,value])=>buildTelemetryStatsBucket(command,value)).sort((left,right)=>right.count-left.count||left.command.localeCompare(right.command))};const runTelemetryStatus=async(_options,context)=>({action:"telemetry",subcommand:"status",status:await buildTelemetryStatusSummary(context.globalPmRoot),generated_at:nowIso()});const runTelemetryFlush=async(_options,context)=>{const before=await buildTelemetryStatusSummary(context.globalPmRoot);await flushTelemetryQueueNow(context.globalPmRoot);const after=await buildTelemetryStatusSummary(context.globalPmRoot);const queueEntriesDrained=Math.max(0,before.queue_entries-after.queue_entries);const queueEmpty=after.queue_entries===0;return{action:"telemetry",subcommand:"flush",queue_entries_before:before.queue_entries,queue_entries_after:after.queue_entries,queue_entries_drained:queueEntriesDrained,queue_progressed:queueEntriesDrained>0,queue_empty:queueEmpty,queue_drained:queueEmpty,status:after,generated_at:nowIso()}};const runTelemetryStats=async(options,context)=>{const limit=parseTelemetryStatsLimit(options.limit);const queueRaw=await readFileIfExists(context.queuePath);const queue=parseTelemetryQueue(queueRaw);const buckets=buildTelemetryStatsBuckets(queue.entries);const selected=buckets.slice(0,limit);return{action:"telemetry",subcommand:"stats",limit,total_commands:buckets.length,queue_entries:queue.valid_entries,queue_invalid_rows:queue.invalid_rows,queue_rows_total:queue.rows_total,truncated:buckets.length>selected.length,stats:selected,generated_at:nowIso()}};const runTelemetryClear=async(_options,context)=>{return withTelemetryQueueMutation(async()=>{const settings=await readSettings(context.globalPmRoot);const settingsChanged=[settings.telemetry.enabled!==false,settings.telemetry.installation_id!=="",settings.telemetry.first_run_prompt_completed!==true].includes(true);settings.telemetry.enabled=false;settings.telemetry.first_run_prompt_completed=true;settings.telemetry.installation_id="";if(settingsChanged){await writeSettings(context.globalPmRoot,settings,"telemetry:clear")}const telemetryRuntimePath=path.join(context.globalPmRoot,TELEMETRY_RUNTIME_RELATIVE_PATH);const existed=await pathExists(telemetryRuntimePath);await fs.rm(telemetryRuntimePath,{recursive:true,force:true});return{action:"telemetry",subcommand:"clear",settings_changed:settingsChanged,runtime_dir_removed:existed&&!await pathExists(telemetryRuntimePath),queue_exists_after:await pathExists(context.queuePath),state_exists_after:await pathExists(context.statePath),status:await buildTelemetryStatusSummary(context.globalPmRoot),generated_at:nowIso()}},context.globalPmRoot)};const TELEMETRY_COMMAND_HANDLERS={status:runTelemetryStatus,flush:runTelemetryFlush,stats:runTelemetryStats,clear:runTelemetryClear};async function runTelemetry(options,_global){void _global;const subcommand=normalizeTelemetrySubcommand(options.subcommand);const globalPmRoot=resolveGlobalPmRoot(process.cwd());return TELEMETRY_COMMAND_HANDLERS[subcommand](options,{globalPmRoot,queuePath:path.join(globalPmRoot,TELEMETRY_QUEUE_RELATIVE_PATH),statePath:path.join(globalPmRoot,TELEMETRY_STATE_RELATIVE_PATH)})}export{TELEMETRY_SUBCOMMANDS,runTelemetry};
|
|
2
2
|
//# sourceMappingURL=telemetry.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agent UX Contracts
|
|
2
2
|
|
|
3
|
-
Tracker references: [pm-v1yo](../.agents/pm/issues/pm-v1yo.toon), [pm-i6pi](../.agents/pm/issues/pm-i6pi.toon), [pm-um4g](../.agents/pm/issues/pm-um4g.toon), [pm-tmhs](../.agents/pm/issues/pm-tmhs.toon), [pm-6m1i](../.agents/pm/issues/pm-6m1i.toon), [pm-cj9v](../.agents/pm/issues/pm-cj9v.toon), [pm-yp56](../.agents/pm/issues/pm-yp56.toon), [pm-gos426](../.agents/pm/issues/pm-gos426.toon), [pm-flnefm](../.agents/pm/issues/pm-flnefm.toon), [pm-rggtvd](../.agents/pm/issues/pm-rggtvd.toon), and [pm-vk7zek](../.agents/pm/issues/pm-vk7zek.toon).
|
|
3
|
+
Tracker references: [pm-bwkmp4](../.agents/pm/issues/pm-bwkmp4.toon), [pm-zsic8h](../.agents/pm/issues/pm-zsic8h.toon), [pm-4f86c4](../.agents/pm/issues/pm-4f86c4.toon), [pm-v1yo](../.agents/pm/issues/pm-v1yo.toon), [pm-i6pi](../.agents/pm/issues/pm-i6pi.toon), [pm-um4g](../.agents/pm/issues/pm-um4g.toon), [pm-tmhs](../.agents/pm/issues/pm-tmhs.toon), [pm-6m1i](../.agents/pm/issues/pm-6m1i.toon), [pm-cj9v](../.agents/pm/issues/pm-cj9v.toon), [pm-yp56](../.agents/pm/issues/pm-yp56.toon), [pm-gos426](../.agents/pm/issues/pm-gos426.toon), [pm-flnefm](../.agents/pm/issues/pm-flnefm.toon), [pm-rggtvd](../.agents/pm/issues/pm-rggtvd.toon), and [pm-vk7zek](../.agents/pm/issues/pm-vk7zek.toon).
|
|
4
4
|
|
|
5
5
|
These contracts keep common agent loops deterministic, token-efficient, and recoverable. Runtime contracts and `--help --json` remain the exact source for available flags.
|
|
6
6
|
|
|
@@ -50,7 +50,15 @@ Compatibility note: before the 2026.7.19 release, `findings_by_code` incorrectly
|
|
|
50
50
|
|
|
51
51
|
## Extension command ownership
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Extensions may add unique leaves beneath core groups: `ops metrics` can coexist with core `ops health`. Core leaf paths, including declared leaves awaiting lazy registration, remain reserved. A same-path handler collision emits `extension_command_collision:` with both owners and preserves core execution. Metadata-only registrations can augment an already registered core command; matching a core action name does not grant ownership of its path. Declared package-backed relocated facets retain their existing registration contract. Packages should rename a conflicting leaf instead of abandoning the shared namespace.
|
|
54
|
+
|
|
55
|
+
Existing `pm-ops` installations keep their `ops` namespace and command paths. Upgrading to the leaf-composition implementation restores commands such as `ops metrics` without reinstalling or renaming the package. For a true collision such as `ops health`, the warning identifies both owners; rename that extension leaf while keeping its non-conflicting siblings.
|
|
56
|
+
|
|
57
|
+
## Command recovery and compact reads
|
|
58
|
+
|
|
59
|
+
Unknown-command suggestions resolve deprecated spellings to their available canonical replacement, including required flags. For example, `pm start` suggests `pm claim --start`, and a misspelled `list-open` points to `pm list --status open`. The SDK exports `canonicalizeCommandSuggestions` alongside its ranking primitives so package hosts can apply the same alias policy. Its optional query token prefers available semantic matches, so `start` does not also suggest unrelated statistics commands. Unavailable replacements are omitted.
|
|
60
|
+
|
|
61
|
+
Default TOON lists with complete brief rows show the rows, count, and `details: "--full"` recovery pointer. Active filters, warnings, and additional diagnostics remain visible. A producer-owned `details` field preserves the detailed envelope instead of being replaced. Partial or truncated reads retain their detailed completeness and continuation receipts. `--full` restores item metadata; JSON retains the complete structured list envelope. Human recovery bundles echo an attempted command once; JSON retains the separate normalized argument vector for programmatic recovery.
|
|
54
62
|
|
|
55
63
|
## Context and work selection
|
|
56
64
|
|
package/docs/CLI_GRAMMAR.md
CHANGED
|
@@ -164,3 +164,31 @@ public parents. Existing worker and completion-helper spellings remain valid.
|
|
|
164
164
|
Default contract discovery also omits internal paths; use `contracts --full` or
|
|
165
165
|
an exact `contracts --command "item test worker" --flags-only` selection to
|
|
166
166
|
inspect their contracts without expanding ordinary agent context.
|
|
167
|
+
|
|
168
|
+
## Declared visibility and completed destinations
|
|
169
|
+
|
|
170
|
+
Tracked by [pm-34xisz](../.agents/pm/issues/pm-34xisz.toon),
|
|
171
|
+
[pm-3ig9b6](../.agents/pm/issues/pm-3ig9b6.toon), and
|
|
172
|
+
[pm-djyvbk](../.agents/pm/tasks/pm-djyvbk.toon).
|
|
173
|
+
|
|
174
|
+
A package command's declared `tier` controls SDK runtime discovery. Internal
|
|
175
|
+
commands and actions are omitted from default contracts, summaries, and schemas;
|
|
176
|
+
full or explicitly scoped inspection retains them and their declared tier.
|
|
177
|
+
Packages need no entry in a core-only visibility list.
|
|
178
|
+
|
|
179
|
+
`history acknowledge` is the canonical author-disposition command. The permanent
|
|
180
|
+
`history-author-acknowledge` alias keeps the same preview/apply handshake, flags,
|
|
181
|
+
results, and SDK/MCP action identity. `assurance` retains its established surface
|
|
182
|
+
as a reasoned exception: measurements, assertions, gates, and verdicts are
|
|
183
|
+
persistent project data, with operations beyond diagnostics.
|
|
184
|
+
|
|
185
|
+
Consolidation rows are checked against a complete all-status tracker snapshot.
|
|
186
|
+
A missing, closed, or canceled owner fails the grammar gate unless a declared
|
|
187
|
+
alias already resolves the spelling to a live canonical command. Delivered
|
|
188
|
+
leaves are classified as target paths; deliberate concise item operations carry
|
|
189
|
+
explicit keep-as-is reasons. Closing an owner cannot silently certify unfinished
|
|
190
|
+
command migration.
|
|
191
|
+
|
|
192
|
+
Full discovery uses a uniform destination table. Its `reason` column contains
|
|
193
|
+
the rationale for exceptions and an empty string where no exception applies,
|
|
194
|
+
so adding a rationale does not expand every row into repeated field names.
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -157,17 +157,51 @@ Telemetry is enabled by default. Use `pm config set telemetry-tracking off` to o
|
|
|
157
157
|
| `PM_TELEMETRY_DISABLED` | boolean | Hard-disable all telemetry for this process, ignoring settings. |
|
|
158
158
|
| `DO_NOT_TRACK` | boolean | Hard-disable event capture, identity creation, flush workers, endpoint probes, and Sentry, regardless of persisted preferences. |
|
|
159
159
|
| `PM_TELEMETRY_SEND_TEST_EVENTS` | boolean | Explicitly allow inferred test events. Hard opt-outs still take precedence. |
|
|
160
|
-
| `PM_TELEMETRY_READ_SAMPLE_RATE` | number greater than `0` and at most `1` |
|
|
160
|
+
| `PM_TELEMETRY_READ_SAMPLE_RATE` | number greater than `0` and at most `1` | Override automatic successful-read sampling; `1`, empty, or invalid values retain every invocation. Omit for automatic frequency bounding. |
|
|
161
161
|
| `PM_NO_TELEMETRY` | boolean | Alias for `PM_TELEMETRY_DISABLED` (honoured by the same checks). |
|
|
162
162
|
| `PM_TELEMETRY_OTEL_DISABLED` | boolean | Disable only OTLP trace-span export; the event queue still flushes. |
|
|
163
163
|
| `PM_TELEMETRY_INLINE_FLUSH` | boolean | Flush the queue and OTLP spans inline instead of dispatching the detached worker. Mainly for tests; normal use relies on the background worker. |
|
|
164
|
-
| `PM_TELEMETRY_SOURCE_CONTEXT` | `user` \| `automation` \| `test` \| `dogfood` | Override the inferred source context recorded on each event.
|
|
164
|
+
| `PM_TELEMETRY_SOURCE_CONTEXT` | `user` \| `automation` \| `test` \| `dogfood` | Override the inferred source context recorded on each event. Unrecognized nonempty values use inferred context with `source_context_source=env_override_rejected`; the raw value is never emitted. |
|
|
165
165
|
| `PM_TELEMETRY_HTTP_TIMEOUT_MS` | integer milliseconds | Bound each background event or OTLP request (default `20000`, clamped to `1000`–`25000` to stay below the worker lock TTL). |
|
|
166
166
|
| `PM_TELEMETRY_INGEST_KEY` | string | Sent as the `x-pm-telemetry-key` header on queue flushes; never logged. |
|
|
167
167
|
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | URL | OTLP/HTTP traces endpoint for command spans. Takes precedence over the base endpoint. |
|
|
168
168
|
| `OTEL_EXPORTER_OTLP_ENDPOINT` | URL | Base OTLP endpoint; the traces endpoint is derived by appending `/v1/traces`. |
|
|
169
169
|
| `OTEL_SERVICE_NAME` | string | `service.name` attribute on exported spans (defaults to `pm-cli`). |
|
|
170
170
|
|
|
171
|
+
Unrecognized source-context overrides produce one bounded warning per process on
|
|
172
|
+
stderr, naming the accepted values without echoing the rejected input. JSON
|
|
173
|
+
invocations retain parseable stdout and receive the warning on stderr. Explicit
|
|
174
|
+
quiet mode suppresses the warning; events and spans still carry the fixed
|
|
175
|
+
rejection marker. Empty overrides mean no override. Existing consent
|
|
176
|
+
rules continue to suppress all capture when telemetry is disabled.
|
|
177
|
+
|
|
178
|
+
Event and OTLP queue appends and reconciliation share an installation-level
|
|
179
|
+
mutex. Successful delivery, retry updates, and retention pruning reread the
|
|
180
|
+
current queue while holding that mutex, so another updated CLI process cannot
|
|
181
|
+
append into a file about to be replaced. Network delivery runs outside the
|
|
182
|
+
mutex. Each foreground start, finish, or error capture uses a 250 ms
|
|
183
|
+
lock-acquisition budget by default; queue maintenance, clear, and flush initialization
|
|
184
|
+
retain a five-second default. `PM_LOCK_WAIT_MS` explicitly overrides these
|
|
185
|
+
budgets. These are per-acquisition contention budgets, not total operation
|
|
186
|
+
deadlines: queued in-process transactions and filesystem work can add latency.
|
|
187
|
+
The existing 60-second stale-lock recovery policy applies. Telemetry remains best
|
|
188
|
+
effort when storage is unavailable or contention exhausts the wait budget;
|
|
189
|
+
collector success and an empty queue are separate observations, not a guarantee
|
|
190
|
+
of exactly-once delivery. Upgrade concurrent CLI processes together: older
|
|
191
|
+
versions do not participate in the installation mutex.
|
|
192
|
+
|
|
193
|
+
Start and error capture recheck process opt-outs and saved consent under the
|
|
194
|
+
installation mutex before initializing identity, and retain that mutex through
|
|
195
|
+
immediate event writes. Completion rechecks both consent sources and its saved
|
|
196
|
+
installation identity under the same mutex through deferred start, finish,
|
|
197
|
+
and span writes. `telemetry clear` uses this transaction boundary, so it either
|
|
198
|
+
removes a completed capture or prevents that capture from appending afterward.
|
|
199
|
+
Flush identity initialization also revalidates consent under the mutex; network
|
|
200
|
+
delivery and flush scheduling remain outside it. Preference changes are
|
|
201
|
+
evaluated at the capture transaction's consent check. Re-enabling after a clear
|
|
202
|
+
does not revive an invocation's old identity. These checks cannot recall
|
|
203
|
+
requests already dispatched to a collector.
|
|
204
|
+
|
|
171
205
|
Interaction rules:
|
|
172
206
|
|
|
173
207
|
- `DO_NOT_TRACK` / `PM_TELEMETRY_DISABLED` / `PM_NO_TELEMETRY` short-circuit everything, including OTLP export, regardless of the other knobs.
|
|
@@ -182,7 +216,11 @@ SDK consumers that previously used `TelemetryStatusSummary.enabled` to display t
|
|
|
182
216
|
|
|
183
217
|
At `redacted` and `max` capture, events include a bounded `agent_harness` dimension (`claude-code`, `codex`, `pi`, `opencode`, `cursor`, `aider`, `gemini-cli`, `ci`, `other`, or `none`) and a boolean `ci`. Installation-keyed hashes remain available; raw author and model names remain private. Minimal capture omits both new dimensions.
|
|
184
218
|
|
|
185
|
-
|
|
219
|
+
Repeated core reads are sampled automatically after the first ten invocations of a command in each UTC minute. The nth invocation has successful-pair inclusion probability `min(1, (10 / n)^2)`, keeping expected successful pairs below twenty per command per minute. This is a statistical bound, not a hard cap; failures remain retained. Counters are shared across processes under the installation queue mutex, reset at the next minute, and store only the eight fixed command names and numbers in `runtime/telemetry/read-sampling.json`. Unavailable state retains the invocation.
|
|
220
|
+
|
|
221
|
+
Eligible commands are `stats`, `ops stats`, `list`, `get`, `next`, `context`, `activity`, and `aggregate`. The runtime must establish core ownership: `--no-extensions` provides an explicit boundary, while an active core command may coexist with unrelated extension commands. Matching handlers or parsers, and active hooks, services, preflights, renderers, migrations, search/vector adapters, or assurance providers prevent sampling. Unknown ownership and mutations retain every invocation. Set `PM_TELEMETRY_READ_SAMPLE_RATE=1` to disable automatic sampling, or a number greater than zero and below one for a fixed rate; explicitly empty or invalid values also retain every invocation.
|
|
222
|
+
|
|
223
|
+
Successful sampled reads defer their start until completion so both lifecycle events are retained or dropped together; abruptly terminated sampled reads have no event pair. Retained pairs carry numeric `sample_rate`, and OTLP spans carry `pm.sample_rate`; estimate population totals with weight `1 / sample_rate` (missing means `1`). Very small inclusion probabilities produce high-variance estimates. Failed sampled reads carry probability `1`. Local queue statistics describe retained observations, not weighted population estimates.
|
|
186
224
|
|
|
187
225
|
`pm telemetry stats` reads the local queue and reports, per command bucket, latency percentiles (`duration_p50_ms`/`duration_p95_ms`/`duration_max_ms`, nearest-rank over `command_finish` `duration_ms`), outcome rates (`ok_count`/`error_count`/`error_rate`; a finish event whose `ok` is missing or not strictly `true` is counted conservatively as an error), and `command_resolution_counts`. These are an always-available, zero-network performance and reliability signal for the most recent queued window.
|
|
188
226
|
|
|
@@ -10,7 +10,7 @@ This file is generated from `PM_COMMAND_CAPABILITY_CONTRACTS`. Do not edit it ma
|
|
|
10
10
|
| intake | `create`, `item`, `item copy`, `context focus`, `history restore` |
|
|
11
11
|
| context | `list`, `aggregate`, `context`, `get`, `search`, `item duplicates`, `ops eval`, `context next`, `history activity`, `ops stats`, `help` |
|
|
12
12
|
| lifecycle | `update`, `update many`, `close`, `close many`, `close delete`, `claim`, `release` |
|
|
13
|
-
| evidence | `history`, `history events`, `history redact`, `history repair`, `history compact`, `history attest`, `history
|
|
13
|
+
| evidence | `history`, `history events`, `history redact`, `history repair`, `history compact`, `history attest`, `history acknowledge`, `item append`, `item comments`, `item notes`, `item learnings`, `item files`, `item docs` |
|
|
14
14
|
| graph | `graph`, `item deps`, `plan` |
|
|
15
15
|
| quality | `item test`, `ops test-all`, `ops validate`, `assurance`, `contracts`, `ops` |
|
|
16
16
|
| automation | `meet`, `event`, `remind` |
|
|
@@ -50,6 +50,7 @@ This file is generated from `PM_COMMAND_CAPABILITY_CONTRACTS`. Do not edit it ma
|
|
|
50
50
|
| `history-attest` | full | evidence |
|
|
51
51
|
| `history attest` | full | evidence |
|
|
52
52
|
| `history-author-acknowledge` | full | evidence |
|
|
53
|
+
| `history acknowledge` | full | evidence |
|
|
53
54
|
| `merge` | full | workspace |
|
|
54
55
|
| `workspace merge` | full | workspace |
|
|
55
56
|
| `schema` | standard | workspace |
|
|
@@ -104,6 +104,7 @@ This file is generated by `listPmFlagLexicon()`. Compatibility aliases do not co
|
|
|
104
104
|
| `item append` | evidence | 25 | 25 |
|
|
105
105
|
| `item test` | quality | 53 | 53 |
|
|
106
106
|
| `item test worker` | internal | 20 | 20 |
|
|
107
|
+
| `history acknowledge` | evidence | 28 | 28 |
|
|
107
108
|
| `item copy` | intake | 24 | 24 |
|
|
108
109
|
| `workspace merge` | workspace | 27 | 27 |
|
|
109
110
|
| `item duplicates` | context | 25 | 25 |
|
package/marketplace.json
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.",
|
|
9
|
-
"version": "2026.9.
|
|
9
|
+
"version": "2026.9.15"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "pm-claude",
|
|
14
14
|
"source": "./plugins/pm-claude",
|
|
15
15
|
"description": "Native pm CLI integration for Claude Code — 28 MCP tools, 5 workflow skills, 14 slash commands, 4 subagents, hybrid TUI task tracking, session context injection, and coordination subagents for git-based project management without leaving Claude Code.",
|
|
16
|
-
"version": "2026.9.
|
|
16
|
+
"version": "2026.9.15",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "unbrained",
|
|
19
19
|
"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.9.
|
|
3
|
+
"version": "2026.9.15",
|
|
4
4
|
"description": "Git-native project management CLI for humans and agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.10.0",
|
|
@@ -213,25 +213,25 @@
|
|
|
213
213
|
"fast-json-patch": "^3.1.1",
|
|
214
214
|
"npm-package-arg": "^13.0.2",
|
|
215
215
|
"tar": "7.5.22",
|
|
216
|
-
"yaml": "^2.9.
|
|
216
|
+
"yaml": "^2.9.1"
|
|
217
217
|
},
|
|
218
218
|
"devDependencies": {
|
|
219
219
|
"@codspeed/vitest-plugin": "^5.7.1",
|
|
220
220
|
"@eslint/js": "^10.0.1",
|
|
221
221
|
"@modelcontextprotocol/ext-apps": "2.0.0",
|
|
222
222
|
"@sentry/cli": "^3.7.0",
|
|
223
|
-
"@types/node": "^26.5.
|
|
223
|
+
"@types/node": "^26.5.1",
|
|
224
224
|
"@types/npm-package-arg": "^6.1.4",
|
|
225
225
|
"@vitest/coverage-v8": "^4.1.11",
|
|
226
226
|
"esbuild": "0.28.2",
|
|
227
227
|
"eslint": "^10.10.0",
|
|
228
228
|
"eslint-plugin-sonarjs": "^4.2.0",
|
|
229
229
|
"eslint-plugin-unicorn": "74.0.0",
|
|
230
|
-
"fast-check": "^4.
|
|
230
|
+
"fast-check": "^4.10.0",
|
|
231
231
|
"github-slugger": "2.0.0",
|
|
232
232
|
"greptile": "^3.5.2",
|
|
233
233
|
"jscpd": "^5.2.0",
|
|
234
|
-
"marked": "18.0.
|
|
234
|
+
"marked": "18.0.13",
|
|
235
235
|
"parse5": "8.0.1",
|
|
236
236
|
"tsx": "^4.23.13",
|
|
237
237
|
"typescript": "^6.0.3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unbrained/pm-digital-twin",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.15",
|
|
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.",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pm-claude",
|
|
3
3
|
"description": "Native pm CLI integration for Claude Code — 28 MCP tools, 5 workflow skills, 14 slash commands, 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.",
|
|
4
|
-
"version": "2026.9.
|
|
4
|
+
"version": "2026.9.15",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "unbrained",
|
|
7
7
|
"url": "https://github.com/unbraind/pm-cli"
|