@unbrained/pm-cli 2026.9.26 → 2026.9.28

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.
Files changed (181) hide show
  1. package/.claude-plugin/marketplace.json +4 -6
  2. package/CHANGELOG.md +42 -0
  3. package/dist/cli/commander-usage.js +2 -2
  4. package/dist/cli/error-guidance.js +1 -1
  5. package/dist/cli/help-json-payload.js +1 -1
  6. package/dist/cli/main.js +2 -2
  7. package/dist/cli/register-operations.js +1 -1
  8. package/dist/cli/register-setup.js +1 -1
  9. package/dist/cli/runtime/selection.d.ts +3 -1
  10. package/dist/cli/runtime/selection.js +1 -1
  11. package/dist/cli-bundle/bundle-manifest.json +156 -148
  12. package/dist/cli-bundle/chunks/{chunk-TC74K7SS.js → chunk-35DME35A.js} +2 -2
  13. package/dist/cli-bundle/chunks/{chunk-QQD3VRMZ.js → chunk-A2G5OG6W.js} +2 -2
  14. package/dist/cli-bundle/chunks/chunk-CPOWTIIS.js +2 -0
  15. package/dist/cli-bundle/chunks/{chunk-TYJXMT3Q.js → chunk-GLH2LNRH.js} +2 -2
  16. package/dist/cli-bundle/chunks/{chunk-IYN4MJ2C.js → chunk-NBDB3SRC.js} +57 -57
  17. package/dist/cli-bundle/chunks/{chunk-HTHTX6E6.js → chunk-NEUIVBFO.js} +2 -2
  18. package/dist/cli-bundle/chunks/{chunk-U55RYT3I.js → chunk-OYCCWPBM.js} +2 -2
  19. package/dist/cli-bundle/chunks/{chunk-VMO4P5MX.js → chunk-PLNNUAFZ.js} +2 -2
  20. package/dist/cli-bundle/chunks/{chunk-FOTXRNY6.js → chunk-PR4UAMI5.js} +44 -44
  21. package/dist/cli-bundle/chunks/{chunk-SZQCHJI4.js → chunk-UT7GRGHY.js} +2 -2
  22. package/dist/cli-bundle/chunks/{chunk-MJWKR7YA.js → chunk-VMJLM7P2.js} +62 -62
  23. package/dist/cli-bundle/chunks/{chunk-4ODHIX7N.js → chunk-YERBAGQD.js} +2 -2
  24. package/dist/cli-bundle/chunks/chunk-ZFHJP7YD.js +29 -0
  25. package/dist/cli-bundle/chunks/{register-list-query-426QTRET.js → register-list-query-N6RP6PSP.js} +2 -2
  26. package/dist/cli-bundle/chunks/{register-mutation-FLI3HHMP.js → register-mutation-CY7JGQE6.js} +2 -2
  27. package/dist/cli-bundle/chunks/{register-operations-TP7ZG4MK.js → register-operations-53HAD3QP.js} +2 -2
  28. package/dist/cli-bundle/chunks/register-setup-NVX6374E.js +2 -0
  29. package/dist/cli-bundle/focused-chunks/chunk-5KJXX2TZ.js +2 -0
  30. package/dist/cli-bundle/focused-chunks/{chunk-UIFVIE5F.js → chunk-6IVQPNYN.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/{chunk-MK5AKKHK.js → chunk-A5O3VYWV.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/chunk-AZA4AEOR.js +75 -0
  33. package/dist/cli-bundle/focused-chunks/chunk-BGWF6CMP.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/{chunk-NVVB2HJC.js → chunk-BRLXKRI2.js} +17 -17
  35. package/dist/cli-bundle/focused-chunks/{chunk-ABA3KRPY.js → chunk-DTLRXY77.js} +2 -2
  36. package/dist/cli-bundle/focused-chunks/{chunk-XKH2FC5D.js → chunk-IJXZQE3D.js} +2 -2
  37. package/dist/cli-bundle/focused-chunks/{chunk-Q355NPLH.js → chunk-IWLMQLBO.js} +6 -6
  38. package/dist/cli-bundle/focused-chunks/chunk-K7GSZ7YZ.js +2 -0
  39. package/dist/cli-bundle/focused-chunks/{chunk-OY3VHCTX.js → chunk-ONDNR3VU.js} +2 -2
  40. package/dist/cli-bundle/focused-chunks/{chunk-XVBWZTU2.js → chunk-OVVCXTIE.js} +12 -12
  41. package/dist/cli-bundle/focused-chunks/{chunk-25BBHWMH.js → chunk-V7OPZRL6.js} +2 -2
  42. package/dist/cli-bundle/focused-chunks/{chunk-TLF6N56J.js → chunk-Y5Z3XNGY.js} +2 -2
  43. package/dist/cli-bundle/focused-chunks/{chunk-O7MIBEMK.js → chunk-YZB7IPR6.js} +2 -2
  44. package/dist/cli-bundle/focused-chunks/{chunk-NRHTXBTI.js → chunk-ZMQTIS3L.js} +2 -2
  45. package/dist/cli-bundle/main.js +22 -22
  46. package/dist/cli-bundle/sdk-authoring.js +1 -1
  47. package/dist/cli-bundle/sdk-contracts.js +1 -1
  48. package/dist/cli-bundle/sdk-core.js +18 -18
  49. package/dist/cli-bundle/sdk-governance.js +1 -1
  50. package/dist/cli-bundle/sdk-graph.js +1 -1
  51. package/dist/cli-bundle/sdk-merge.js +51 -51
  52. package/dist/cli-bundle/sdk-query.js +1 -1
  53. package/dist/cli-bundle/sdk-runtime.js +1 -1
  54. package/dist/cli-bundle/sdk-testing.js +1 -1
  55. package/dist/cli-bundle/sdk.js +8 -8
  56. package/dist/core/diagnostics/remediation.js +1 -1
  57. package/dist/core/item/item-format.js +1 -1
  58. package/dist/core/store/settings.js +3 -3
  59. package/dist/sdk/agent-capability-contracts.js +1 -1
  60. package/dist/sdk/cli-contracts/command-aliases.js +1 -1
  61. package/dist/sdk/cli-contracts/commander-mutation-options.js +1 -1
  62. package/dist/sdk/cli-contracts/grammar-contracts.js +1 -1
  63. package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -1
  64. package/dist/sdk/completion/fish.js +3 -3
  65. package/dist/sdk/completion/shared.d.ts +1 -1
  66. package/dist/sdk/completion/shared.js +1 -1
  67. package/dist/sdk/completion/zsh.js +3 -3
  68. package/dist/sdk/extension/copy-scope.d.ts +2 -2
  69. package/dist/sdk/extension/copy-scope.js +1 -1
  70. package/dist/sdk/extension/install-plan.js +1 -1
  71. package/dist/sdk/extension/install-runtime.js +2 -2
  72. package/dist/sdk/extension/static-inventory.d.ts +54 -0
  73. package/dist/sdk/extension/static-inventory.js +2 -0
  74. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
  75. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
  76. package/dist/sdk/governance/health-merge-evidence.d.ts +18 -0
  77. package/dist/sdk/governance/health-merge-evidence.js +2 -0
  78. package/dist/sdk/governance/health.js +1 -1
  79. package/dist/sdk/guide-topics.js +1 -1
  80. package/dist/sdk/index.d.ts +1 -0
  81. package/dist/sdk/index.js +1 -1
  82. package/dist/sdk/merge/install.js +2 -2
  83. package/dist/sdk/output-projection.d.ts +1 -1
  84. package/dist/sdk/output-projection.js +1 -1
  85. package/dist/sdk/public-surface.json +1 -1
  86. package/dist/sdk/query/complete-list.js +1 -1
  87. package/dist/sdk/read-output/provenance.d.ts +20 -0
  88. package/dist/sdk/read-output/provenance.js +2 -0
  89. package/dist/sdk/read-output-budget.d.ts +1 -1
  90. package/dist/sdk/read-output-budget.js +1 -1
  91. package/dist/sdk/read-output-contracts.js +1 -1
  92. package/dist/sdk/runtime-input.js +1 -1
  93. package/dist/sdk/test/execution.d.ts +11 -0
  94. package/dist/sdk/test/execution.js +2 -2
  95. package/dist/sdk/test/parsers.d.ts +1 -1
  96. package/dist/sdk/test/parsers.js +1 -1
  97. package/dist/types.d.ts +3 -3
  98. package/dist/types.js +1 -1
  99. package/docs/AGENT_READ_AND_TEST_RECEIPTS.md +21 -0
  100. package/docs/CLAUDE_CODE_PLUGIN.md +12 -7
  101. package/docs/CLI_GRAMMAR.md +31 -0
  102. package/docs/CODEX_PLUGIN.md +8 -0
  103. package/docs/CONFIGURATION.md +2 -0
  104. package/docs/EXTENSION_LIFECYCLE.md +18 -0
  105. package/docs/PACKAGE_EVIDENCE.md +18 -7
  106. package/docs/README.md +1 -0
  107. package/docs/RELEASING.md +46 -1
  108. package/docs/TESTING.md +14 -3
  109. package/docs/agent-task-token-baseline.json +4 -4
  110. package/docs/generated/AGENT_CAPABILITY_ROUTING.md +1 -1
  111. package/docs/generated/AGENT_COMMAND_SURFACE.md +5 -1
  112. package/docs/generated/FLAG_LEXICON_BUDGETS.md +4 -0
  113. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +18 -7
  114. package/marketplace.json +4 -6
  115. package/package.json +6 -6
  116. package/packages/pm-beads/package.json +1 -1
  117. package/packages/pm-calendar/package.json +1 -1
  118. package/packages/pm-command-kit/package.json +1 -1
  119. package/packages/pm-digital-twin/package.json +1 -1
  120. package/packages/pm-governance-audit/package.json +1 -1
  121. package/packages/pm-guide-shell/package.json +1 -1
  122. package/packages/pm-kanban/package.json +1 -1
  123. package/packages/pm-lifecycle-hooks/package.json +1 -1
  124. package/packages/pm-linked-test-adapters/package.json +1 -1
  125. package/packages/pm-search-advanced/package.json +1 -1
  126. package/packages/pm-templates/package.json +1 -1
  127. package/packages/pm-todos/package.json +1 -1
  128. package/packages/pm-vcs/package.json +1 -1
  129. package/plugins/pm-claude/.claude-plugin/plugin.json +4 -2
  130. package/plugins/pm-claude/.mcp.json +1 -2
  131. package/plugins/pm-claude/README.md +11 -7
  132. package/plugins/pm-claude/package.json +2 -2
  133. package/plugins/pm-claude/skills/pm-audit/SKILL.md +14 -103
  134. package/plugins/pm-claude/skills/pm-audit/agents/openai.yaml +4 -0
  135. package/plugins/pm-claude/{commands/pm-calendar.md → skills/pm-calendar/SKILL.md} +1 -0
  136. package/plugins/pm-claude/{commands/pm-close-task.md → skills/pm-close-task/SKILL.md} +1 -0
  137. package/plugins/pm-claude/skills/pm-developer/SKILL.md +20 -143
  138. package/plugins/pm-claude/skills/pm-developer/agents/openai.yaml +4 -0
  139. package/plugins/pm-claude/{commands/pm-init.md → skills/pm-init/SKILL.md} +2 -1
  140. package/plugins/pm-claude/{commands/pm-list.md → skills/pm-list/SKILL.md} +2 -1
  141. package/plugins/pm-claude/{commands/pm-new.md → skills/pm-new/SKILL.md} +1 -0
  142. package/plugins/pm-claude/skills/pm-planner/SKILL.md +16 -167
  143. package/plugins/pm-claude/skills/pm-planner/agents/openai.yaml +4 -0
  144. package/plugins/pm-claude/skills/pm-release/SKILL.md +18 -102
  145. package/plugins/pm-claude/skills/pm-release/agents/openai.yaml +4 -0
  146. package/plugins/pm-claude/{commands/pm-search.md → skills/pm-search/SKILL.md} +1 -0
  147. package/plugins/pm-claude/{commands/pm-start-task.md → skills/pm-start-task/SKILL.md} +1 -0
  148. package/plugins/pm-claude/{commands/pm-status.md → skills/pm-status/SKILL.md} +1 -0
  149. package/plugins/pm-claude/{commands/pm-triage.md → skills/pm-triage/SKILL.md} +1 -0
  150. package/plugins/pm-claude/skills/pm-workflow/SKILL.md +25 -156
  151. package/plugins/pm-claude/skills/pm-workflow/agents/openai.yaml +4 -0
  152. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  153. package/plugins/pm-codex/README.md +10 -2
  154. package/plugins/pm-codex/mcp.json +11 -0
  155. package/plugins/pm-codex/package.json +2 -2
  156. package/plugins/pm-codex/plugin.json +45 -0
  157. package/plugins/pm-codex/skills/pm-audit/SKILL.md +21 -0
  158. package/plugins/pm-codex/skills/pm-audit/agents/openai.yaml +4 -0
  159. package/plugins/pm-codex/skills/pm-auditor/SKILL.md +5 -40
  160. package/plugins/pm-codex/skills/pm-auditor/agents/openai.yaml +3 -5
  161. package/plugins/pm-codex/skills/pm-developer/SKILL.md +26 -0
  162. package/plugins/pm-codex/skills/pm-developer/agents/openai.yaml +4 -0
  163. package/plugins/pm-codex/skills/pm-native/SKILL.md +7 -87
  164. package/plugins/pm-codex/skills/pm-native/agents/openai.yaml +3 -5
  165. package/plugins/pm-codex/skills/pm-planner/SKILL.md +22 -0
  166. package/plugins/pm-codex/skills/pm-planner/agents/openai.yaml +4 -0
  167. package/plugins/pm-codex/skills/pm-release/SKILL.md +17 -38
  168. package/plugins/pm-codex/skills/pm-release/agents/openai.yaml +2 -4
  169. package/plugins/pm-codex/skills/pm-workflow/SKILL.md +39 -0
  170. package/plugins/pm-codex/skills/pm-workflow/agents/openai.yaml +4 -0
  171. package/dist/cli-bundle/chunks/chunk-GRWPZR7F.js +0 -29
  172. package/dist/cli-bundle/chunks/register-setup-574SIVQZ.js +0 -2
  173. package/dist/cli-bundle/focused-chunks/chunk-H3BI4EDO.js +0 -75
  174. package/dist/cli-bundle/focused-chunks/chunk-HNHMK5JI.js +0 -2
  175. package/dist/cli-bundle/focused-chunks/chunk-HQPTDJLF.js +0 -2
  176. package/dist/cli-bundle/focused-chunks/chunk-PMPFLA6X.js +0 -2
  177. package/plugins/pm-claude/commands/pm-audit.md +0 -38
  178. package/plugins/pm-claude/commands/pm-developer.md +0 -38
  179. package/plugins/pm-claude/commands/pm-planner.md +0 -54
  180. package/plugins/pm-claude/commands/pm-release.md +0 -41
  181. package/plugins/pm-claude/commands/pm-workflow.md +0 -49
@@ -1,4 +1,4 @@
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]="8e48bd9b-07b3-5772-984e-10f27864c736")}catch(e2){}})();import{PM_NAMESPACED_COMMAND_ALIASES}from"../cli-contracts.js";import{SCAFFOLD_CAPABILITIES}from"../extension/scaffold.js";import{ATTEST_INVOCATIONS,COMMAND_COMPLETION_DESCRIPTIONS,EXTENSION_LIFECYCLE_ACTIONS,GLOBAL_COMPLETION_INLINE_PATTERNS,GLOBAL_COMPLETION_SWITCH_PATTERNS,GLOBAL_COMPLETION_VALUE_PATTERNS,GUIDE_TOPIC_CHOICES,HIDDEN_COMMAND_ALIASES,NAMESPACE_NOUNS,PACKAGE_LIFECYCLE_ACTIONS,RESTORE_INVOCATIONS,SCHEMA_SUBCOMMAND_CHOICES,completionNamespaceLeaves,completionStatusValues,completionTypeValues,joinCompletionValues,normalizeRuntimeCompletionFlags,shellDoubleQuote}from"./shared.js";function escapeZshStaticChoices(value){return value.replace(/([^a-zA-Z0-9_./\s-])/gu,"\\$1").replaceAll("'","'\\''")}function renderZshRuntimeFieldFlagSpecs(runtimeFlags){const normalized=normalizeRuntimeCompletionFlags(runtimeFlags);if(normalized.length===0){return""}return`${normalized.map(flag=>` '${escapeZshStaticChoices(flag)}[Runtime schema field flag]:value' \\`).join("\n")}
1
+ !(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="818bb54f-06ad-587f-86d6-4eaee9e4966c")}catch(e2){}})();import{PM_NAMESPACED_COMMAND_ALIASES}from"../cli-contracts.js";import{SCAFFOLD_CAPABILITIES}from"../extension/scaffold.js";import{ATTEST_INVOCATIONS,COMMAND_COMPLETION_DESCRIPTIONS,EXTENSION_LIFECYCLE_ACTIONS,GLOBAL_COMPLETION_INLINE_PATTERNS,GLOBAL_COMPLETION_SWITCH_PATTERNS,GLOBAL_COMPLETION_VALUE_PATTERNS,GUIDE_TOPIC_CHOICES,HIDDEN_COMMAND_ALIASES,NAMESPACE_NOUNS,PACKAGE_LIFECYCLE_ACTIONS,RESTORE_INVOCATIONS,SCHEMA_SUBCOMMAND_CHOICES,completionNamespaceLeaves,completionStatusValues,completionTypeValues,joinCompletionValues,normalizeRuntimeCompletionFlags,shellDoubleQuote}from"./shared.js";function escapeZshStaticChoices(value){return value.replace(/([^a-zA-Z0-9_./\s-])/gu,"\\$1").replaceAll("'","'\\''")}function renderZshRuntimeFieldFlagSpecs(runtimeFlags){const normalized=normalizeRuntimeCompletionFlags(runtimeFlags);if(normalized.length===0){return""}return`${normalized.map(flag=>` '${escapeZshStaticChoices(flag)}[Runtime schema field flag]:value' \\`).join("\n")}
2
2
  `}function renderZshArgumentSpecs(specs,options={}){const trailingContinuation=options.trailingContinuation??true;const lastSpecIndex=specs.length-1;return specs.map((spec,index)=>` ${spec}${trailingContinuation||index!==lastSpecIndex?" \\":""}`).join("\n")}function renderZshCommandDescriptions(){return[...COMMAND_COMPLETION_DESCRIPTIONS,["ops","Workspace maintenance and diagnostics"]].filter(([command])=>!HIDDEN_COMMAND_ALIASES.has(command)).map(([command,description])=>` '${command}:${description}'`).join("\n")}function renderZshPresenceFilterSpecs(options){const missingSpecs=["reviewer-missing[Select only items missing reviewer]","risk-missing[Select only items missing risk]","confidence-missing[Select only items missing confidence]","sprint-missing[Select only items missing sprint]","release-missing[Select only items missing release]"];const contentMissingAliasSpecs=options.includeContentMissingAliases===true?["files-missing[Alias for --no-files]","docs-missing[Alias for --no-docs]"]:[];const pairedSpecs=[["has-notes[Select only items that have notes]","no-notes[Select only items with no notes]"],["has-learnings[Select only items that have learnings]","no-learnings[Select only items with no learnings]"],["has-files[Select only items that have linked files]","no-files[Select only items with no linked files]"],["has-docs[Select only items that have linked docs]","no-docs[Select only items with no linked docs]"],["has-tests[Select only items that have linked tests]","no-tests[Select only items with no linked tests]"],["has-comments[Select only items that have comments]","no-comments[Select only items with no comments]"],["has-deps[Select only items that have dependencies]","no-deps[Select only items with no dependencies]"],["has-body[Select only items with non-empty body]","empty-body[Select only items with empty body]"],["has-linked-command[Select only items that have a linked command]","no-linked-command[Select only items with no linked command]"]];return renderZshArgumentSpecs([...[...missingSpecs,...contentMissingAliasSpecs].map(spec=>`'--${options.missingPrefix}${spec}'`),...pairedSpecs.flatMap(([positive,negative])=>[`'--${options.pairedPrefix}${positive}'`,`'--${options.pairedPrefix}${negative}'`])])}const ZSH_MUTATION_COLLECTION_ARGUMENT_SPECS=["'--comment[Comment seed author=<value>,created_at=<iso|now>,text=<value>]:comment'","'--note[Note seed author=<value>,created_at=<iso|now>,text=<value>]:note'","'--learning[Learning seed author=<value>,created_at=<iso|now>,text=<value>]:learning'","'--file[Linked file path=<value>,scope=<project|global>,note=<text>]:file'","'--test[Linked test command=<value>,path=<value>,scope=<project|global>]:test'","'--doc[Linked doc path=<value>,scope=<project|global>,note=<text>]:doc'","'--reminder[Reminder entry at=<iso|relative>|date=<iso|relative>,text=<text>|title=<text>]:reminder'","'--event[Event entry start=<iso|relative>,end=<iso|relative>,recur_*]:event'","'--type-option[Type option key=value or key=<name>,value=<value>]:type_option'","'--unset[Clear scalar metadata field by name]:field'","'--replace-files[Atomically replace linked files with provided --file values]'","'--replace-docs[Atomically replace linked docs with provided --doc values]'","'--clear-deps[Clear dependency entries]'","'--clear-comments[Clear comments]'","'--clear-notes[Clear notes]'","'--clear-learnings[Clear learnings]'","'--clear-files[Clear linked files]'","'--clear-tests[Clear linked tests]'","'--clear-docs[Clear linked docs]'","'--clear-reminders[Clear reminders]'","'--clear-events[Clear events]'","'--clear-type-options[Clear type options]'"];function renderZshScheduleItemSpecs(kind){const leadingSpecs=kind==="reminder"?["'--at[Reminder time (default +1d)]:at'","'--text[Reminder text (defaults to title)]:text'"]:["'--start[Start time (ISO, now, or relative)]:start'","'--duration[Duration from start (default 1h)]:duration'","'--end[End time (overrides --duration)]:end'","'--location[Location]:location'","'--timezone[IANA timezone]:timezone'","'--all-day[Mark as an all-day event]'"];return renderZshArgumentSpecs([...leadingSpecs,"'--parent[Parent item id]:parent'","'--allow-missing-parent[Permit a parent id that does not exist yet]'","'--tags[Comma-separated tags]:tags'","'(-p --priority)'{-p,--priority}'[Priority (0-4)]:(0 1 2 3 4)'","'(-b --body)'{-b,--body}'[Item body]:body'","'(-d --description)'{-d,--description}'[Short description]:description'","'--author[Mutation author]:author'","'--message[History message]:message'","'--json[Output JSON]'","'--quiet[Suppress stdout]'"],{trailingContinuation:false})}function renderZshBulkSelectionFilterSpecs(action,statusChoices,typeChoices,tagChoices){return renderZshArgumentSpecs([`'--filter-status[Filter by status before ${action}]:(${statusChoices})'`,`'--filter-type[Filter by type before ${action}]:(${typeChoices})'`,`'--filter-tag[Filter by tag before ${action}]:(${tagChoices})'`,`'--filter-priority[Filter by priority before ${action}]:(0 1 2 3 4)'`,"'--filter-deadline-before[Filter by deadline upper bound]:deadline'","'--filter-deadline-after[Filter by deadline lower bound]:deadline'","'--filter-updated-after[Filter by updated_at lower bound (ISO/relative)]:timestamp'","'--filter-updated-before[Filter by updated_at upper bound (ISO/relative)]:timestamp'","'--filter-created-after[Filter by created_at lower bound (ISO/relative)]:timestamp'","'--filter-created-before[Filter by created_at upper bound (ISO/relative)]:timestamp'",`'--filter-assignee[Filter by assignee before ${action}]:assignee'`,"'--filter-assignee-filter[Filter assignee presence]:(assigned unassigned)'","'--filter-parent[Filter by parent item ID]:parent'","'--filter-sprint[Filter by sprint]:sprint'","'--filter-release[Filter by release]:release'"])}function renderZshDynamicChoiceResolver(kind,command,fallback){const envKind=kind.toUpperCase();const cacheVar=`PM_COMPLETION_${envKind}_CACHE`;const cacheTsVar=`PM_COMPLETION_${envKind}_CACHE_TS`;const ttlVar=`PM_COMPLETION_${envKind}_TTL`;const escapedFallback=shellDoubleQuote(fallback);return`
3
3
  _pm_${kind}_choices() {
4
4
  local now ttl cache_ts resolved
@@ -810,7 +810,7 @@ ${renderZshArgumentSpecs(ATTEST_INVOCATIONS.map(flag=>`'${flag.flag}[${flag.desc
810
810
  '--env-set[Set linked-test runtime environment values]:entry' \\
811
811
  '--env-clear[Clear linked-test runtime environment values]:name' \\
812
812
  '--shared-host-safe[Apply shared-host-safe runtime defaults]' \\
813
- '--pm-context[PM linked-test context mode]:(schema tracker auto)' \\
813
+ '--pm-context[PM linked-test context mode]:(schema tracker auto none)' \\
814
814
  '--override-linked-pm-context[Force run-level --pm-context over per-linked-test pm_context_mode metadata]' \\
815
815
  '--fail-on-context-mismatch[Fail when context item counts mismatch]' \\
816
816
  '--fail-on-skipped[Treat skipped linked tests as dependency failures]' \\
@@ -835,7 +835,7 @@ ${renderZshArgumentSpecs(ATTEST_INVOCATIONS.map(flag=>`'${flag.flag}[${flag.desc
835
835
  '--env-set[Set linked-test runtime environment values]:entry' \\
836
836
  '--env-clear[Clear linked-test runtime environment values]:name' \\
837
837
  '--shared-host-safe[Apply shared-host-safe runtime defaults]' \\
838
- '--pm-context[PM linked-test context mode]:(schema tracker auto)' \\
838
+ '--pm-context[PM linked-test context mode]:(schema tracker auto none)' \\
839
839
  '--override-linked-pm-context[Force run-level --pm-context over per-linked-test pm_context_mode metadata]' \\
840
840
  '--fail-on-context-mismatch[Fail when context item counts mismatch]' \\
841
841
  '--fail-on-skipped[Treat skipped linked tests as dependency failures]' \\
@@ -1,2 +1,2 @@
1
- /** Decide whether a lexical source path belongs in a nested-destination snapshot. Symlinks remain links. */
2
- export declare function includesExtensionCopyPath(source: string, destination: string, candidate: string): boolean;
1
+ /** Decide whether a lexical source path belongs in an extension snapshot. Git metadata is always excluded; symlinks remain links. */
2
+ export declare function includesExtensionCopyPath(source: string, destination: string, candidate: string, nestedDestination: boolean): boolean;
@@ -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]="a77d8d8d-f429-5154-ab3a-2caddc44472e")}catch(e2){}})();import path from"node:path";import{isPathWithinDirectory}from"../../core/fs/path-utils.js";function includesExtensionCopyPath(source,destination,candidate){const relative=path.relative(source,candidate);if(relative!==""&&!isPathWithinDirectory(source,candidate))return false;if(candidate===destination||isPathWithinDirectory(destination,candidate))return false;const segments=relative.split(path.sep);return!segments.some(segment=>segment===".agents"||segment==="node_modules"||segment.startsWith(".pm-extension-install-backup-"))}export{includesExtensionCopyPath};
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]="3df6b126-ff8b-55be-8f33-53ec9a2336a8")}catch(e2){}})();import path from"node:path";import{isPathWithinDirectory}from"../../core/fs/path-utils.js";function includesExtensionCopyPath(source,destination,candidate,nestedDestination){const relative=path.relative(source,candidate);if(relative!==""&&!isPathWithinDirectory(source,candidate))return false;if(candidate===destination||isPathWithinDirectory(destination,candidate))return false;const segments=relative.split(path.sep);if(segments.includes(".git"))return false;if(!nestedDestination)return true;return!segments.some(segment=>segment===".agents"||segment==="node_modules"||segment.startsWith(".pm-extension-install-backup-"))}export{includesExtensionCopyPath};
2
2
  //# sourceMappingURL=copy-scope.js.map
@@ -1,2 +1,2 @@
1
- !(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f4b9502f-f742-5f11-b341-56763bbed7c2")}catch(e2){}})();import fs from"node:fs/promises";import path from"node:path";import{isPathWithinDirectory}from"../../core/fs/path-utils.js";import{PmCliError}from"../../core/shared/errors.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{includesExtensionCopyPath}from"./copy-scope.js";import{resolveCanonicalExtensionInstallDestination}from"./install-runtime.js";import{pathExists}from"../../core/fs/fs-utils.js";import{areDirectoriesEquivalent}from"./install-sources.js";const DEVELOPMENT_DIRECTORIES=new Set(["node_modules",".git","dist","build","coverage"]);async function buildExtensionInstallPlan(resolved,destination,scope,options){const localStat=resolved.source.kind==="local"?await fs.stat(resolved.source.absolute_path):void 0;const sourceMode=resolved.source.kind==="local"?localStat.isDirectory()?"directory":"archive":resolved.source.kind;const copy=await planExtensionDirectoryCopy(resolved.directory,destination,options);const plan={source_mode:sourceMode,...sourceMode==="archive"?{archive_bytes:localStat.size}:{},copy};const packageRoot=resolved.source_root??resolved.directory;if(sourceMode==="directory"&&(!copy.complete||copy.development_entries>0||copy.bytes>=16*1024*1024)&&await pathExists(path.join(packageRoot,"package.json"))){plan.packed_alternative={cwd:packageRoot,pack:{command:"npm",args:["pack","--ignore-scripts","--json"]},install:{command:"pm",args:["package","install","<archive-filename>",`--${scope}`]},archive_argument:"pack_result[0].filename"}}return plan}async function planExtensionDirectoryCopy(sourceDirectory,destinationDirectory,options={}){const{maxEntries=1e4,maxDepth=64,signal}=options;if(![maxEntries,maxDepth].every(value=>Number.isSafeInteger(value)&&value>0)){throw new PmCliError("maxEntries and maxDepth must be positive safe integers.",EXIT_CODE.USAGE)}signal?.throwIfAborted();const source=await fs.realpath(sourceDirectory);const destination=await resolveCanonicalExtensionInstallDestination(destinationDirectory);const installInPlace=await areDirectoriesEquivalent(source,destination);signal?.throwIfAborted();const scope=installInPlace?"in_place":isPathWithinDirectory(source,destination)?"nested_filtered_snapshot":"directory_snapshot";const plan={copy_scope:scope,source_directory:source,destination_directory:destination,files:0,bytes:0,directories:0,symlinks:0,other_entries:0,scanned_entries:0,excluded_entries:0,development_entries:0,complete:true,stop_reason:"complete",max_entries:maxEntries,max_depth:maxDepth};if(scope==="in_place")return plan;await scanExtensionCopyDirectory(source,0,plan,signal);return plan}async function scanExtensionCopyDirectory(directory,depth,plan,signal){signal?.throwIfAborted();const handle=await fs.opendir(directory);for await(const entry of handle){signal?.throwIfAborted();if(plan.scanned_entries>=plan.max_entries){plan.complete=false;plan.stop_reason="entry_limit";return}plan.scanned_entries+=1;const candidate=path.join(directory,entry.name);if(plan.copy_scope==="nested_filtered_snapshot"&&!includesExtensionCopyPath(plan.source_directory,plan.destination_directory,candidate)){plan.excluded_entries+=1;continue}if(path.relative(plan.source_directory,candidate).split(path.sep).some(segment=>DEVELOPMENT_DIRECTORIES.has(segment)))plan.development_entries+=1;await countExtensionCopyEntry(candidate,depth,plan,signal);if(!plan.complete)return}}async function countExtensionCopyEntry(candidate,depth,plan,signal){const stat=await fs.lstat(candidate);signal?.throwIfAborted();if(stat.isDirectory()){plan.directories+=1;if(depth+1>=plan.max_depth){plan.complete=false;plan.stop_reason="depth_limit";return}await scanExtensionCopyDirectory(candidate,depth+1,plan,signal)}else if(stat.isFile()){plan.files+=1;plan.bytes+=stat.size}else if(stat.isSymbolicLink()){plan.symlinks+=1}else{plan.other_entries+=1}}export{buildExtensionInstallPlan,planExtensionDirectoryCopy};
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]="7819cf2a-73dd-5002-9b79-4e099848d0d3")}catch(e2){}})();import fs from"node:fs/promises";import path from"node:path";import{isPathWithinDirectory}from"../../core/fs/path-utils.js";import{PmCliError}from"../../core/shared/errors.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{includesExtensionCopyPath}from"./copy-scope.js";import{resolveCanonicalExtensionInstallDestination}from"./install-runtime.js";import{pathExists}from"../../core/fs/fs-utils.js";import{areDirectoriesEquivalent}from"./install-sources.js";const DEVELOPMENT_DIRECTORIES=new Set(["node_modules",".git","dist","build","coverage"]);async function buildExtensionInstallPlan(resolved,destination,scope,options){const localStat=resolved.source.kind==="local"?await fs.stat(resolved.source.absolute_path):void 0;const sourceMode=resolved.source.kind==="local"?localStat.isDirectory()?"directory":"archive":resolved.source.kind;const copy=await planExtensionDirectoryCopy(resolved.directory,destination,options);const plan={source_mode:sourceMode,...sourceMode==="archive"?{archive_bytes:localStat.size}:{},copy};const packageRoot=resolved.source_root??resolved.directory;if(sourceMode==="directory"&&(!copy.complete||copy.development_entries>0||copy.bytes>=16*1024*1024)&&await pathExists(path.join(packageRoot,"package.json"))){plan.packed_alternative={cwd:packageRoot,pack:{command:"npm",args:["pack","--ignore-scripts","--json"]},install:{command:"pm",args:["package","install","<archive-filename>",`--${scope}`]},archive_argument:"pack_result[0].filename"}}if(sourceMode==="directory"&&!copy.complete){const limit=copy.stop_reason==="entry_limit"?`${copy.max_entries} entries`:`${copy.max_depth} directory levels`;throw new PmCliError(`Local extension source scan stopped at ${limit}; the directory snapshot is incomplete and installation was refused. ${plan.packed_alternative?"Pack the package with npm pack --ignore-scripts --json, then install its archive.":"Install a smaller source directory or a packed archive."}`,EXIT_CODE.USAGE,{code:"extension_install_incomplete_source_scan",reason:copy.stop_reason,nextSteps:plan.packed_alternative?[`Run npm pack --ignore-scripts --json from the package root, then pm package install <archive-filename> --${scope}.`]:["Choose a smaller source directory or install a packed archive."]})}return plan}async function planExtensionDirectoryCopy(sourceDirectory,destinationDirectory,options={}){const{maxEntries=1e4,maxDepth=64,signal}=options;if(![maxEntries,maxDepth].every(value=>Number.isSafeInteger(value)&&value>0)){throw new PmCliError("maxEntries and maxDepth must be positive safe integers.",EXIT_CODE.USAGE)}signal?.throwIfAborted();const source=await fs.realpath(sourceDirectory);const destination=await resolveCanonicalExtensionInstallDestination(destinationDirectory);const installInPlace=await areDirectoriesEquivalent(source,destination);signal?.throwIfAborted();const scope=installInPlace?"in_place":isPathWithinDirectory(source,destination)?"nested_filtered_snapshot":"directory_snapshot";const plan={copy_scope:scope,source_directory:source,destination_directory:destination,files:0,bytes:0,directories:0,symlinks:0,other_entries:0,scanned_entries:0,excluded_entries:0,development_entries:0,complete:true,stop_reason:"complete",max_entries:maxEntries,max_depth:maxDepth};if(scope==="in_place")return plan;await scanExtensionCopyDirectory(source,0,plan,signal);return plan}async function scanExtensionCopyDirectory(directory,depth,plan,signal){signal?.throwIfAborted();const handle=await fs.opendir(directory);for await(const entry of handle){signal?.throwIfAborted();if(plan.scanned_entries>=plan.max_entries){plan.complete=false;plan.stop_reason="entry_limit";return}plan.scanned_entries+=1;const candidate=path.join(directory,entry.name);if(!includesExtensionCopyPath(plan.source_directory,plan.destination_directory,candidate,plan.copy_scope==="nested_filtered_snapshot")){plan.excluded_entries+=1;continue}if(path.relative(plan.source_directory,candidate).split(path.sep).some(segment=>DEVELOPMENT_DIRECTORIES.has(segment)))plan.development_entries+=1;await countExtensionCopyEntry(candidate,depth,plan,signal);if(!plan.complete)return}}async function countExtensionCopyEntry(candidate,depth,plan,signal){const stat=await fs.lstat(candidate);signal?.throwIfAborted();if(stat.isDirectory()){plan.directories+=1;if(depth+1>=plan.max_depth){plan.complete=false;plan.stop_reason="depth_limit";return}await scanExtensionCopyDirectory(candidate,depth+1,plan,signal)}else if(stat.isFile()){plan.files+=1;plan.bytes+=stat.size}else if(stat.isSymbolicLink()){plan.symlinks+=1}else{plan.other_entries+=1}}export{buildExtensionInstallPlan,planExtensionDirectoryCopy};
2
2
  //# sourceMappingURL=install-plan.js.map
@@ -1,4 +1,4 @@
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]="9b04c14b-8049-52ef-b7e8-dc87a0fb7629")}catch(e2){}})();import{withHostEnvironmentBoundary}from"../../core/fs/host-environment-errors.js";import{includesExtensionCopyPath}from"./copy-scope.js";import{randomUUID}from"node:crypto";import fs from"node:fs/promises";import os from"node:os";import path from"node:path";import{isFileAbsentError,pathExists}from"../../core/fs/fs-utils.js";import{isPathWithinDirectory}from"../../core/fs/path-utils.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{resolvePmPackageRootFromModule}from"../../core/packages/root.js";import{nowIso}from"../../core/shared/time.js";const EXTENSION_INSTALL_COPY_ATTEMPTS=3;const EXTENSION_INSTALL_LOCK_ATTEMPTS=120;const EXTENSION_INSTALL_LOCK_DELAY_MS=250;const EXTENSION_INSTALL_LOCK_STALE_MS=12e4;const RETRIABLE_EXTENSION_INSTALL_COPY_CODES=new Set(["EEXIST","ENOTEMPTY","ENOENT"]);const errnoCode=error=>typeof error==="object"&&error!==null&&"code"in error?error.code:void 0;const isRetriableExtensionInstallCopyError=error=>RETRIABLE_EXTENSION_INSTALL_COPY_CODES.has(String(errnoCode(error)));const isErrnoCode=(error,code)=>errnoCode(error)===code;const sleep=ms=>new Promise(resolve=>{setTimeout(resolve,ms)});const ensureExtensionModuleTypeMarker=async destinationDirectory=>{const markerPath=path.join(destinationDirectory,"package.json");if(await pathExists(markerPath)){return}await fs.writeFile(markerPath,`${JSON.stringify({type:"module"},null,2)}
2
- `,"utf8")};const ensureInstalledExtensionSdkLink=async destinationDirectory=>{const hostPackageRoot=resolvePmPackageRootFromModule(import.meta.url,["../../.."]);const scopedDirectory=path.join(destinationDirectory,"node_modules","@unbrained");const linkPath=path.join(scopedDirectory,"pm-cli");await fs.mkdir(scopedDirectory,{recursive:true});await fs.rm(linkPath,{recursive:true,force:true});await fs.symlink(hostPackageRoot,linkPath,process.platform==="win32"?"junction":"dir")};const resolveCanonicalExtensionInstallDestination=async destinationDirectory=>{const resolvedDestination=path.resolve(destinationDirectory);const destinationParent=path.dirname(resolvedDestination);const destinationRoot=path.parse(destinationParent).root;let canonicalDestinationParent=await fs.realpath(destinationRoot).catch(()=>destinationRoot);const relativeDestinationParent=path.relative(destinationRoot,destinationParent);const destinationSegments=relativeDestinationParent===""?[]:relativeDestinationParent.split(path.sep);for(const[index,segment]of destinationSegments.entries()){const candidate=path.join(canonicalDestinationParent,segment);try{canonicalDestinationParent=await fs.realpath(candidate)}catch{canonicalDestinationParent=path.join(canonicalDestinationParent,...destinationSegments.slice(index));break}}return path.join(canonicalDestinationParent,path.basename(resolvedDestination))};const copyExtensionDirectoryWithoutSelfNesting=async(sourceDirectory,destinationDirectory,copyDirectory,temporaryDirectory=os.tmpdir())=>withHostEnvironmentBoundary("extension_install_copy",async()=>{const resolvedSource=path.resolve(sourceDirectory);const canonicalSource=await fs.realpath(resolvedSource).catch(()=>resolvedSource);const canonicalDestination=await resolveCanonicalExtensionInstallDestination(destinationDirectory);if(canonicalSource===canonicalDestination){return}if(!isPathWithinDirectory(canonicalSource,canonicalDestination)){await copyDirectory(canonicalSource,destinationDirectory,{recursive:true,force:true});return}const systemTempDirectory=await fs.realpath(path.resolve(temporaryDirectory)).catch(()=>resolveCanonicalExtensionInstallDestination(temporaryDirectory));const stagingBase=isPathWithinDirectory(canonicalSource,systemTempDirectory)?path.dirname(canonicalSource):systemTempDirectory;if(isPathWithinDirectory(canonicalSource,stagingBase)){throw new PmCliError(`Extension source "${sourceDirectory}" contains its install destination and no external staging directory is available. Install a narrower package directory instead.`,EXIT_CODE.USAGE,{code:"extension_install_source_contains_destination"})}const stagingRoot=await fs.mkdtemp(path.join(stagingBase,"pm-extension-copy-"));const stagedDirectory=path.join(stagingRoot,"extension");try{await copyDirectory(canonicalSource,stagedDirectory,{recursive:true,force:true,filter:sourcePath=>includesExtensionCopyPath(canonicalSource,canonicalDestination,path.resolve(sourcePath))});await copyDirectory(stagedDirectory,destinationDirectory,{recursive:true,force:true})}finally{await fs.rm(stagingRoot,{recursive:true,force:true})}});const copyExtensionDirectoryForInstall=async(sourceDirectory,destinationDirectory,copyDirectory=fs.cp)=>{for(let attempt=1;attempt<=EXTENSION_INSTALL_COPY_ATTEMPTS;attempt+=1){try{await withHostEnvironmentBoundary("extension_install_copy",async()=>{await fs.rm(destinationDirectory,{recursive:true,force:true});await copyExtensionDirectoryWithoutSelfNesting(sourceDirectory,destinationDirectory,copyDirectory)});return}catch(error){if(!isRetriableExtensionInstallCopyError(error)||attempt===EXTENSION_INSTALL_COPY_ATTEMPTS){throw error}await sleep(EXTENSION_INSTALL_LOCK_DELAY_MS)}}};const readExtensionInstallLockOwnerToken=async lockPath=>{let ownerContents;try{ownerContents=await fs.readFile(path.join(lockPath,"owner.json"),"utf8")}catch(error){if(!isFileAbsentError(error))throw error;return null}let parsed;try{parsed=JSON.parse(ownerContents)}catch{return null}if(typeof parsed!=="object"||parsed===null||!("token"in parsed)){return null}const token=parsed.token;return typeof token==="string"&&token.length>0?token:null};const removeExtensionInstallLockIfOwned=async(lockPath,ownerToken)=>{const currentOwnerToken=await readExtensionInstallLockOwnerToken(lockPath);if(currentOwnerToken!==ownerToken){return false}await fs.rm(lockPath,{recursive:true,force:true});return true};const reclaimStaleExtensionInstallLock=async(lockPath,staleMs)=>{let stat;try{stat=await fs.stat(lockPath)}catch{return false}if(Date.now()-stat.mtimeMs<=staleMs){return false}const staleOwnerToken=await readExtensionInstallLockOwnerToken(lockPath);if(staleOwnerToken===null){await fs.rm(lockPath,{recursive:true,force:true});return true}return removeExtensionInstallLockIfOwned(lockPath,staleOwnerToken)};const startExtensionInstallLockHeartbeat=(lockPath,ownerToken,intervalMs)=>{let heartbeat=Promise.resolve();const timer=setInterval(()=>{heartbeat=heartbeat.then(async()=>{if(await readExtensionInstallLockOwnerToken(lockPath)!==ownerToken){return}const heartbeatAt=new Date;await fs.utimes(lockPath,heartbeatAt,heartbeatAt)}).catch(()=>void 0)},intervalMs);timer.unref();return async()=>{clearInterval(timer);await heartbeat}};const createExtensionInstallLock=async(lockPath,owner)=>{await fs.mkdir(lockPath);try{await fs.writeFile(path.join(lockPath,"owner.json"),`${JSON.stringify(owner,null,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]="67bd3c08-81bf-5286-81ee-60126f7f979b")}catch(e2){}})();import{withHostEnvironmentBoundary}from"../../core/fs/host-environment-errors.js";import{includesExtensionCopyPath}from"./copy-scope.js";import{randomUUID}from"node:crypto";import fs from"node:fs/promises";import os from"node:os";import path from"node:path";import{isFileAbsentError,pathExists}from"../../core/fs/fs-utils.js";import{isPathWithinDirectory}from"../../core/fs/path-utils.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{resolvePmPackageRootFromModule}from"../../core/packages/root.js";import{nowIso}from"../../core/shared/time.js";const EXTENSION_INSTALL_COPY_ATTEMPTS=3;const EXTENSION_INSTALL_LOCK_ATTEMPTS=120;const EXTENSION_INSTALL_LOCK_DELAY_MS=250;const EXTENSION_INSTALL_LOCK_STALE_MS=12e4;const RETRIABLE_EXTENSION_INSTALL_COPY_CODES=new Set(["EEXIST","ENOTEMPTY","ENOENT"]);const errnoCode=error=>typeof error==="object"&&error!==null&&"code"in error?error.code:void 0;const isRetriableExtensionInstallCopyError=error=>RETRIABLE_EXTENSION_INSTALL_COPY_CODES.has(String(errnoCode(error)));const isErrnoCode=(error,code)=>errnoCode(error)===code;const sleep=ms=>new Promise(resolve=>{setTimeout(resolve,ms)});const ensureExtensionModuleTypeMarker=async destinationDirectory=>{const markerPath=path.join(destinationDirectory,"package.json");if(await pathExists(markerPath)){return}await fs.writeFile(markerPath,`${JSON.stringify({type:"module"},null,2)}
2
+ `,"utf8")};const ensureInstalledExtensionSdkLink=async destinationDirectory=>{const hostPackageRoot=resolvePmPackageRootFromModule(import.meta.url,["../../.."]);const scopedDirectory=path.join(destinationDirectory,"node_modules","@unbrained");const linkPath=path.join(scopedDirectory,"pm-cli");await fs.mkdir(scopedDirectory,{recursive:true});await fs.rm(linkPath,{recursive:true,force:true});await fs.symlink(hostPackageRoot,linkPath,process.platform==="win32"?"junction":"dir")};const resolveCanonicalExtensionInstallDestination=async destinationDirectory=>{const resolvedDestination=path.resolve(destinationDirectory);const destinationParent=path.dirname(resolvedDestination);const destinationRoot=path.parse(destinationParent).root;let canonicalDestinationParent=await fs.realpath(destinationRoot).catch(()=>destinationRoot);const relativeDestinationParent=path.relative(destinationRoot,destinationParent);const destinationSegments=relativeDestinationParent===""?[]:relativeDestinationParent.split(path.sep);for(const[index,segment]of destinationSegments.entries()){const candidate=path.join(canonicalDestinationParent,segment);try{canonicalDestinationParent=await fs.realpath(candidate)}catch{canonicalDestinationParent=path.join(canonicalDestinationParent,...destinationSegments.slice(index));break}}return path.join(canonicalDestinationParent,path.basename(resolvedDestination))};const copyExtensionDirectoryWithoutSelfNesting=async(sourceDirectory,destinationDirectory,copyDirectory,temporaryDirectory=os.tmpdir())=>withHostEnvironmentBoundary("extension_install_copy",async()=>{const resolvedSource=path.resolve(sourceDirectory);const canonicalSource=await fs.realpath(resolvedSource).catch(()=>resolvedSource);const canonicalDestination=await resolveCanonicalExtensionInstallDestination(destinationDirectory);if(canonicalSource===canonicalDestination){return}if(!isPathWithinDirectory(canonicalSource,canonicalDestination)){await copyDirectory(canonicalSource,destinationDirectory,{recursive:true,force:true,filter:sourcePath=>includesExtensionCopyPath(canonicalSource,canonicalDestination,path.resolve(sourcePath),false)});return}const systemTempDirectory=await fs.realpath(path.resolve(temporaryDirectory)).catch(()=>resolveCanonicalExtensionInstallDestination(temporaryDirectory));const stagingBase=isPathWithinDirectory(canonicalSource,systemTempDirectory)?path.dirname(canonicalSource):systemTempDirectory;if(isPathWithinDirectory(canonicalSource,stagingBase)){throw new PmCliError(`Extension source "${sourceDirectory}" contains its install destination and no external staging directory is available. Install a narrower package directory instead.`,EXIT_CODE.USAGE,{code:"extension_install_source_contains_destination"})}const stagingRoot=await fs.mkdtemp(path.join(stagingBase,"pm-extension-copy-"));const stagedDirectory=path.join(stagingRoot,"extension");try{await copyDirectory(canonicalSource,stagedDirectory,{recursive:true,force:true,filter:sourcePath=>includesExtensionCopyPath(canonicalSource,canonicalDestination,path.resolve(sourcePath),true)});await copyDirectory(stagedDirectory,destinationDirectory,{recursive:true,force:true})}finally{await fs.rm(stagingRoot,{recursive:true,force:true})}});const copyExtensionDirectoryForInstall=async(sourceDirectory,destinationDirectory,copyDirectory=fs.cp)=>{for(let attempt=1;attempt<=EXTENSION_INSTALL_COPY_ATTEMPTS;attempt+=1){try{await withHostEnvironmentBoundary("extension_install_copy",async()=>{await fs.rm(destinationDirectory,{recursive:true,force:true});await copyExtensionDirectoryWithoutSelfNesting(sourceDirectory,destinationDirectory,copyDirectory)});return}catch(error){if(!isRetriableExtensionInstallCopyError(error)||attempt===EXTENSION_INSTALL_COPY_ATTEMPTS){throw error}await sleep(EXTENSION_INSTALL_LOCK_DELAY_MS)}}};const readExtensionInstallLockOwnerToken=async lockPath=>{let ownerContents;try{ownerContents=await fs.readFile(path.join(lockPath,"owner.json"),"utf8")}catch(error){if(!isFileAbsentError(error))throw error;return null}let parsed;try{parsed=JSON.parse(ownerContents)}catch{return null}if(typeof parsed!=="object"||parsed===null||!("token"in parsed)){return null}const token=parsed.token;return typeof token==="string"&&token.length>0?token:null};const removeExtensionInstallLockIfOwned=async(lockPath,ownerToken)=>{const currentOwnerToken=await readExtensionInstallLockOwnerToken(lockPath);if(currentOwnerToken!==ownerToken){return false}await fs.rm(lockPath,{recursive:true,force:true});return true};const reclaimStaleExtensionInstallLock=async(lockPath,staleMs)=>{let stat;try{stat=await fs.stat(lockPath)}catch{return false}if(Date.now()-stat.mtimeMs<=staleMs){return false}const staleOwnerToken=await readExtensionInstallLockOwnerToken(lockPath);if(staleOwnerToken===null){await fs.rm(lockPath,{recursive:true,force:true});return true}return removeExtensionInstallLockIfOwned(lockPath,staleOwnerToken)};const startExtensionInstallLockHeartbeat=(lockPath,ownerToken,intervalMs)=>{let heartbeat=Promise.resolve();const timer=setInterval(()=>{heartbeat=heartbeat.then(async()=>{if(await readExtensionInstallLockOwnerToken(lockPath)!==ownerToken){return}const heartbeatAt=new Date;await fs.utimes(lockPath,heartbeatAt,heartbeatAt)}).catch(()=>void 0)},intervalMs);timer.unref();return async()=>{clearInterval(timer);await heartbeat}};const createExtensionInstallLock=async(lockPath,owner)=>{await fs.mkdir(lockPath);try{await fs.writeFile(path.join(lockPath,"owner.json"),`${JSON.stringify(owner,null,2)}
3
3
  `,"utf8")}catch(error){await fs.rm(lockPath,{recursive:true,force:true}).catch(()=>{});throw error}};const acquireExtensionInstallLock=async(lockPath,owner,attempts,delayMs,staleMs)=>{for(let attempt=1;attempt<=attempts;attempt+=1){try{await createExtensionInstallLock(lockPath,owner);return true}catch(error){if(!isErrnoCode(error,"EEXIST")){throw error}if(await reclaimStaleExtensionInstallLock(lockPath,staleMs)){attempt-=1}else{await sleep(delayMs)}}}return false};const withExtensionInstallLock=async(settingsRoot,destinationDirectoryName,run,options)=>withHostEnvironmentBoundary("extension_install",async()=>{const lockRoot=path.join(settingsRoot,"runtime","extension-install-locks");const lockPath=path.join(lockRoot,"scope.lock");await fs.mkdir(lockRoot,{recursive:true});const{attempts:rawAttempts=EXTENSION_INSTALL_LOCK_ATTEMPTS,delay_ms:rawDelayMs=EXTENSION_INSTALL_LOCK_DELAY_MS,stale_ms:rawStaleMs=EXTENSION_INSTALL_LOCK_STALE_MS,heartbeat_ms:rawHeartbeatMs}=options??{};if(![rawAttempts,rawDelayMs,rawStaleMs,rawHeartbeatMs].filter(value=>value!==void 0).every(Number.isFinite)){throw new PmCliError("Extension install lock timings must be finite numbers.",EXIT_CODE.USAGE)}const attempts=Math.max(1,Math.floor(rawAttempts));const delayMs=Math.max(0,Math.floor(rawDelayMs));const staleMs=Math.floor(rawStaleMs);const heartbeatMs=Math.floor(rawHeartbeatMs??staleMs/3);if(staleMs<=0||heartbeatMs<=0||heartbeatMs>=staleMs){throw new PmCliError("Extension install lock timings require stale_ms > 0 and 0 < heartbeat_ms < stale_ms.",EXIT_CODE.USAGE)}const owner={pid:process.pid,token:randomUUID(),created_at:nowIso(),destination:destinationDirectoryName};const acquired=await acquireExtensionInstallLock(lockPath,owner,attempts,delayMs,staleMs);if(!acquired){throw new PmCliError(`Timed out waiting for extension install lock for "${destinationDirectoryName}".`,EXIT_CODE.CONFLICT)}const stopHeartbeat=startExtensionInstallLockHeartbeat(lockPath,owner.token,heartbeatMs);let operationSucceeded=false;try{const result=await run();operationSucceeded=true;return result}finally{await stopHeartbeat();await removeExtensionInstallLockIfOwned(lockPath,owner.token).catch(error=>{if(operationSucceeded)throw error})}});export{copyExtensionDirectoryForInstall,copyExtensionDirectoryWithoutSelfNesting,ensureExtensionModuleTypeMarker,ensureInstalledExtensionSdkLink,isErrnoCode,isRetriableExtensionInstallCopyError,resolveCanonicalExtensionInstallDestination,withExtensionInstallLock};
4
4
  //# sourceMappingURL=install-runtime.js.map
@@ -0,0 +1,54 @@
1
+ /** One read failure or malformed document that prevents a complete inventory. */
2
+ export interface StaticExtensionInventoryError {
3
+ /** Stable machine-readable reason. */
4
+ code: "settings_invalid" | "settings_unreadable" | "managed_state_invalid" | "managed_state_unreadable" | "extensions_unreadable" | "manifest_invalid" | "manifest_unreadable";
5
+ /** File or directory whose read failed. */
6
+ path: string;
7
+ }
8
+ /** A configured package; runtime activation has deliberately not been tested. */
9
+ export interface StaticExtensionInventoryEntry {
10
+ /** Manifest name, or directory name when the manifest is malformed. */
11
+ name: string;
12
+ /** Extension directory basename. */
13
+ directory: string | null;
14
+ /** Selected storage scope. */
15
+ scope: "project" | "global";
16
+ /** Whether an installed directory was found. */
17
+ installed: boolean;
18
+ /** Installed, disabled, absent, or unreadable manifest outcome. */
19
+ status: "installed" | "inactive" | "absent" | "malformed_manifest";
20
+ /** Effective configured state; null when settings cannot be trusted. */
21
+ configured_enabled: boolean | null;
22
+ /** Whether managed metadata identifies this install; null when that metadata is invalid. */
23
+ managed: boolean | null;
24
+ /** Runtime state is never inferred from configuration. */
25
+ runtime_active: null;
26
+ /** Manifest version when available. */
27
+ version?: string;
28
+ }
29
+ /** A read-only inventory with explicit completeness and source receipts. */
30
+ export interface StaticExtensionInventoryResult {
31
+ /** Selected storage scope. */
32
+ scope: "project" | "global";
33
+ /** False if any source could not be read or parsed completely. */
34
+ complete: boolean;
35
+ /** Status of the two configuration sources. */
36
+ settings_status: "ok" | "absent" | "invalid" | "unreadable";
37
+ /** Status of the managed install metadata. */
38
+ managed_state_status: "ok" | "absent" | "invalid" | "unreadable";
39
+ /** Installed entries, or one absent entry for a missing requested name. */
40
+ extensions: StaticExtensionInventoryEntry[];
41
+ /** Every failure that affected completeness. */
42
+ errors: StaticExtensionInventoryError[];
43
+ }
44
+ /** Read configured extension state through filesystem reads only. */
45
+ export declare function inspectStaticExtensionInventory(options: {
46
+ /** Tracker root for the project scope. */
47
+ pmRoot: string;
48
+ /** Storage scope; project is the default. */
49
+ scope?: "project" | "global";
50
+ /** Optional name or directory to inspect, including absent installs. */
51
+ name?: string;
52
+ /** Base directory used to resolve the global PM root. */
53
+ cwd?: string;
54
+ }): Promise<StaticExtensionInventoryResult>;
@@ -0,0 +1,2 @@
1
+ !(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3425a1da-ef02-5235-a3b7-158d9efd12a2")}catch(e2){}})();import fs from"node:fs/promises";import path from"node:path";import{resolveGlobalPmRoot}from"../../core/store/paths.js";import{normalizeManagedState}from"./managed-state.js";import{normalizeExtensionNameForMatch,normalizeStringList,parseExtensionManifest}from"./shared.js";function isMissing(error){return typeof error==="object"&&error!==null&&"code"in error&&error.code==="ENOENT"}function isTrustedSourceStatus(status){return status!=="invalid"&&status!=="unreadable"}function parseEnablement(raw){const parsed=JSON.parse(raw);if(typeof parsed!=="object"||parsed===null||Array.isArray(parsed))throw new SyntaxError("Invalid settings object");const configured=parsed.extensions;if(configured===void 0)return{enabled:[],disabled:[]};if(typeof configured!=="object"||configured===null||Array.isArray(configured))throw new SyntaxError("Invalid extensions settings");const value=configured;if(value.enabled!==void 0&&(!Array.isArray(value.enabled)||!value.enabled.every(entry=>typeof entry==="string"))||value.disabled!==void 0&&(!Array.isArray(value.disabled)||!value.disabled.every(entry=>typeof entry==="string"))){throw new SyntaxError("Invalid extension enablement lists")}return{enabled:value.enabled??[],disabled:value.disabled??[]}}async function readEnablement(settingsPath){let raw;try{raw=await fs.readFile(settingsPath,"utf8")}catch(error){if(isMissing(error))return{status:"absent",enabled:[],disabled:[]};return{status:"unreadable",enabled:[],disabled:[],error:{code:"settings_unreadable",path:settingsPath}}}try{return{status:"ok",...parseEnablement(raw)}}catch{return{status:"invalid",enabled:[],disabled:[],error:{code:"settings_invalid",path:settingsPath}}}}async function readManagedRecords(managedPath){let raw;try{raw=await fs.readFile(managedPath,"utf8")}catch(error){if(isMissing(error)){try{if((await fs.stat(path.dirname(managedPath))).isDirectory()){return{status:"absent",entries:[]}}}catch(parentError){if(isMissing(parentError))return{status:"absent",entries:[]}}}return{status:"unreadable",entries:[],error:{code:"managed_state_unreadable",path:managedPath}}}try{const parsed=JSON.parse(raw);const normalized=normalizeManagedState(parsed);if(!normalized||typeof parsed!=="object"||parsed===null||!Array.isArray(parsed.entries)||normalized.entries.length!==parsed.entries.length){throw new SyntaxError("Invalid managed extension state")}return{status:"ok",entries:normalized.entries}}catch{return{status:"invalid",entries:[],error:{code:"managed_state_invalid",path:managedPath}}}}async function readExtensionDirectories(extensionsRoot){try{const directories=(await fs.readdir(extensionsRoot,{withFileTypes:true})).filter(entry=>entry.isDirectory()).map(entry=>entry.name).sort((left,right)=>left.localeCompare(right));return{directories}}catch(error){if(isMissing(error))return{directories:[]};return{directories:[],error:{code:"extensions_unreadable",path:extensionsRoot}}}}async function readManifest(manifestPath){let raw;try{raw=await fs.readFile(manifestPath,"utf8")}catch(error){if(isMissing(error)){return{manifest:null,error:{code:"manifest_invalid",path:manifestPath}}}return{manifest:null,error:{code:"manifest_unreadable",path:manifestPath}}}try{const manifest=parseExtensionManifest(JSON.parse(raw));return manifest?{manifest}:{manifest:null,error:{code:"manifest_invalid",path:manifestPath}}}catch{return{manifest:null,error:{code:"manifest_invalid",path:manifestPath}}}}function projectConfiguredEntry(input){const name=input.manifest?.name??input.directory;const enabled=new Set(normalizeStringList(input.settings.enabled));const disabled=new Set(normalizeStringList(input.settings.disabled));const configuredEnabled=!isTrustedSourceStatus(input.settings.status)||!input.manifest?null:!disabled.has(name)&&(enabled.size===0||enabled.has(name));const managed=!isTrustedSourceStatus(input.managed.status)?null:input.managed.entries.some(entry=>normalizeExtensionNameForMatch(entry.name)===normalizeExtensionNameForMatch(name)||normalizeExtensionNameForMatch(entry.directory)===normalizeExtensionNameForMatch(input.directory));return{name,directory:input.directory,scope:input.scope,installed:true,status:input.manifest?configuredEnabled===false?"inactive":"installed":"malformed_manifest",configured_enabled:configuredEnabled,managed,runtime_active:null,...input.manifest?{version:input.manifest.version}:{}}}async function inspectStaticExtensionInventory(options){const scope=options.scope??"project";const selectedRoot=scope==="global"?resolveGlobalPmRoot(options.cwd??process.cwd()):options.pmRoot;const extensionsRoot=path.join(selectedRoot,"extensions");const settings=await readEnablement(path.join(selectedRoot,"settings.json"));const managed=await readManagedRecords(path.join(extensionsRoot,".managed-extensions.json"));const listed=await readExtensionDirectories(extensionsRoot);const errors=[];for(const source of[settings,managed,listed]){if(source.error)errors.push(source.error)}const requested=options.name?.trim();const extensions=[];for(const directory of listed.directories){const manifestPath=path.join(extensionsRoot,directory,"manifest.json");const inspected=await readManifest(manifestPath);if(inspected.error)errors.push(inspected.error);const entry=projectConfiguredEntry({directory,scope,manifest:inspected.manifest,settings,managed});if(requested&&![entry.name,directory].some(value=>normalizeExtensionNameForMatch(value)===normalizeExtensionNameForMatch(requested))){continue}extensions.push(entry)}if(requested&&extensions.length===0&&errors.every(error=>error.code!=="extensions_unreadable")){extensions.push({name:requested,directory:null,scope,installed:false,status:"absent",configured_enabled:isTrustedSourceStatus(settings.status)?false:null,managed:isTrustedSourceStatus(managed.status)?false:null,runtime_active:null})}return{scope,complete:errors.length===0,settings_status:settings.status,managed_state_status:managed.status,extensions,errors}}export{inspectStaticExtensionInventory};
2
+ //# sourceMappingURL=static-inventory.js.map