@unbrained/pm-cli 2026.3.12 → 2026.5.1
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/.agents/pm/extensions/.managed-extensions.json +42 -0
- package/.agents/pm/extensions/beads/index.js +109 -0
- package/.agents/pm/extensions/beads/manifest.json +7 -0
- package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +31 -21
- package/.agents/pm/extensions/beads/runtime.ts +702 -0
- package/.agents/pm/extensions/todos/index.js +126 -0
- package/.agents/pm/extensions/todos/manifest.json +7 -0
- package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
- package/.agents/pm/extensions/todos/runtime.ts +568 -0
- package/AGENTS.md +196 -92
- package/CHANGELOG.md +399 -0
- package/CODE_OF_CONDUCT.md +42 -0
- package/CONTRIBUTING.md +144 -0
- package/PRD.md +512 -164
- package/README.md +1053 -2
- package/SECURITY.md +51 -0
- package/dist/cli/commands/activity.d.ts +5 -0
- package/dist/cli/commands/activity.js +66 -3
- package/dist/cli/commands/activity.js.map +1 -1
- package/dist/cli/commands/aggregate.d.ts +54 -0
- package/dist/cli/commands/aggregate.js +181 -0
- package/dist/cli/commands/aggregate.js.map +1 -0
- package/dist/cli/commands/append.js +4 -1
- package/dist/cli/commands/append.js.map +1 -1
- package/dist/cli/commands/calendar.d.ts +109 -0
- package/dist/cli/commands/calendar.js +797 -0
- package/dist/cli/commands/calendar.js.map +1 -0
- package/dist/cli/commands/claim.d.ts +5 -1
- package/dist/cli/commands/claim.js +42 -21
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.d.ts +1 -0
- package/dist/cli/commands/close.js +54 -5
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/comments-audit.d.ts +91 -0
- package/dist/cli/commands/comments-audit.js +195 -0
- package/dist/cli/commands/comments-audit.js.map +1 -0
- package/dist/cli/commands/comments.d.ts +1 -0
- package/dist/cli/commands/comments.js +70 -21
- package/dist/cli/commands/comments.js.map +1 -1
- package/dist/cli/commands/completion.d.ts +10 -4
- package/dist/cli/commands/completion.js +1184 -137
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/config.d.ts +35 -3
- package/dist/cli/commands/config.js +968 -13
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/context.d.ts +86 -0
- package/dist/cli/commands/context.js +299 -0
- package/dist/cli/commands/context.js.map +1 -0
- package/dist/cli/commands/contracts.d.ts +78 -0
- package/dist/cli/commands/contracts.js +920 -0
- package/dist/cli/commands/contracts.js.map +1 -0
- package/dist/cli/commands/create.d.ts +48 -14
- package/dist/cli/commands/create.js +1331 -160
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/dedupe-audit.d.ts +81 -0
- package/dist/cli/commands/dedupe-audit.js +330 -0
- package/dist/cli/commands/dedupe-audit.js.map +1 -0
- package/dist/cli/commands/deps.d.ts +52 -0
- package/dist/cli/commands/deps.js +204 -0
- package/dist/cli/commands/deps.js.map +1 -0
- package/dist/cli/commands/docs.d.ts +19 -0
- package/dist/cli/commands/docs.js +212 -13
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.d.ts +122 -0
- package/dist/cli/commands/extension.js +1850 -0
- package/dist/cli/commands/extension.js.map +1 -0
- package/dist/cli/commands/files.d.ts +52 -1
- package/dist/cli/commands/files.js +443 -13
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/gc.d.ts +11 -1
- package/dist/cli/commands/gc.js +89 -11
- package/dist/cli/commands/gc.js.map +1 -1
- package/dist/cli/commands/get.d.ts +13 -0
- package/dist/cli/commands/get.js +35 -3
- package/dist/cli/commands/get.js.map +1 -1
- package/dist/cli/commands/health.d.ts +10 -2
- package/dist/cli/commands/health.js +774 -23
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/history.d.ts +20 -0
- package/dist/cli/commands/history.js +152 -6
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/index.d.ts +16 -3
- package/dist/cli/commands/index.js +16 -3
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -2
- package/dist/cli/commands/init.js +137 -5
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/learnings.d.ts +17 -0
- package/dist/cli/commands/learnings.js +129 -0
- package/dist/cli/commands/learnings.js.map +1 -0
- package/dist/cli/commands/list.d.ts +29 -1
- package/dist/cli/commands/list.js +289 -53
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/normalize.d.ts +51 -0
- package/dist/cli/commands/normalize.js +298 -0
- package/dist/cli/commands/normalize.js.map +1 -0
- package/dist/cli/commands/notes.d.ts +17 -0
- package/dist/cli/commands/notes.js +129 -0
- package/dist/cli/commands/notes.js.map +1 -0
- package/dist/cli/commands/reindex.d.ts +1 -0
- package/dist/cli/commands/reindex.js +208 -32
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/restore.js +164 -30
- package/dist/cli/commands/restore.js.map +1 -1
- package/dist/cli/commands/search.d.ts +14 -1
- package/dist/cli/commands/search.js +475 -81
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/stats.js +26 -10
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/commands/templates.d.ts +26 -0
- package/dist/cli/commands/templates.js +179 -0
- package/dist/cli/commands/templates.js.map +1 -0
- package/dist/cli/commands/test-all.d.ts +19 -1
- package/dist/cli/commands/test-all.js +161 -13
- package/dist/cli/commands/test-all.js.map +1 -1
- package/dist/cli/commands/test-runs.d.ts +63 -0
- package/dist/cli/commands/test-runs.js +179 -0
- package/dist/cli/commands/test-runs.js.map +1 -0
- package/dist/cli/commands/test.d.ts +75 -1
- package/dist/cli/commands/test.js +1360 -41
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update-many.d.ts +57 -0
- package/dist/cli/commands/update-many.js +631 -0
- package/dist/cli/commands/update-many.js.map +1 -0
- package/dist/cli/commands/update.d.ts +30 -0
- package/dist/cli/commands/update.js +1393 -84
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +30 -0
- package/dist/cli/commands/validate.js +1140 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/error-guidance.d.ts +33 -0
- package/dist/cli/error-guidance.js +337 -0
- package/dist/cli/error-guidance.js.map +1 -0
- package/dist/cli/extension-command-options.d.ts +1 -0
- package/dist/cli/extension-command-options.js +92 -0
- package/dist/cli/extension-command-options.js.map +1 -1
- package/dist/cli/help-content.d.ts +20 -0
- package/dist/cli/help-content.js +543 -0
- package/dist/cli/help-content.js.map +1 -0
- package/dist/cli/main.js +3625 -445
- package/dist/cli/main.js.map +1 -1
- package/dist/core/extensions/index.d.ts +13 -1
- package/dist/core/extensions/index.js +108 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/item-fields.d.ts +2 -0
- package/dist/core/extensions/item-fields.js +79 -0
- package/dist/core/extensions/item-fields.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +322 -9
- package/dist/core/extensions/loader.js +911 -20
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runtime-registrations.d.ts +5 -0
- package/dist/core/extensions/runtime-registrations.js +51 -0
- package/dist/core/extensions/runtime-registrations.js.map +1 -0
- package/dist/core/history/history-stream-policy.d.ts +20 -0
- package/dist/core/history/history-stream-policy.js +53 -0
- package/dist/core/history/history-stream-policy.js.map +1 -0
- package/dist/core/history/history.js +90 -1
- package/dist/core/history/history.js.map +1 -1
- package/dist/core/item/id.js +4 -1
- package/dist/core/item/id.js.map +1 -1
- package/dist/core/item/index.d.ts +1 -0
- package/dist/core/item/index.js +1 -0
- package/dist/core/item/index.js.map +1 -1
- package/dist/core/item/item-format.d.ts +11 -5
- package/dist/core/item/item-format.js +507 -24
- package/dist/core/item/item-format.js.map +1 -1
- package/dist/core/item/parent-reference-policy.d.ts +6 -0
- package/dist/core/item/parent-reference-policy.js +32 -0
- package/dist/core/item/parent-reference-policy.js.map +1 -0
- package/dist/core/item/parse.d.ts +5 -0
- package/dist/core/item/parse.js +216 -19
- package/dist/core/item/parse.js.map +1 -1
- package/dist/core/item/sprint-release-format.d.ts +6 -0
- package/dist/core/item/sprint-release-format.js +33 -0
- package/dist/core/item/sprint-release-format.js.map +1 -0
- package/dist/core/item/status.d.ts +3 -0
- package/dist/core/item/status.js +24 -0
- package/dist/core/item/status.js.map +1 -0
- package/dist/core/item/type-registry.d.ts +37 -0
- package/dist/core/item/type-registry.js +706 -0
- package/dist/core/item/type-registry.js.map +1 -0
- package/dist/core/lock/lock.d.ts +1 -1
- package/dist/core/lock/lock.js +101 -12
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/output/command-aware.d.ts +1 -0
- package/dist/core/output/command-aware.js +394 -0
- package/dist/core/output/command-aware.js.map +1 -0
- package/dist/core/output/output.d.ts +3 -0
- package/dist/core/output/output.js +124 -6
- package/dist/core/output/output.js.map +1 -1
- package/dist/core/schema/runtime-field-filters.d.ts +3 -0
- package/dist/core/schema/runtime-field-filters.js +39 -0
- package/dist/core/schema/runtime-field-filters.js.map +1 -0
- package/dist/core/schema/runtime-field-values.d.ts +8 -0
- package/dist/core/schema/runtime-field-values.js +154 -0
- package/dist/core/schema/runtime-field-values.js.map +1 -0
- package/dist/core/schema/runtime-schema.d.ts +68 -0
- package/dist/core/schema/runtime-schema.js +554 -0
- package/dist/core/schema/runtime-schema.js.map +1 -0
- package/dist/core/search/cache.d.ts +13 -1
- package/dist/core/search/cache.js +123 -14
- package/dist/core/search/cache.js.map +1 -1
- package/dist/core/search/semantic-defaults.d.ts +6 -0
- package/dist/core/search/semantic-defaults.js +120 -0
- package/dist/core/search/semantic-defaults.js.map +1 -0
- package/dist/core/search/vector-stores.js +3 -1
- package/dist/core/search/vector-stores.js.map +1 -1
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/conflict-markers.d.ts +7 -0
- package/dist/core/shared/conflict-markers.js +27 -0
- package/dist/core/shared/conflict-markers.js.map +1 -0
- package/dist/core/shared/constants.d.ts +15 -4
- package/dist/core/shared/constants.js +141 -1
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.d.ts +10 -1
- package/dist/core/shared/errors.js +3 -1
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/text-normalization.d.ts +4 -0
- package/dist/core/shared/text-normalization.js +33 -0
- package/dist/core/shared/text-normalization.js.map +1 -0
- package/dist/core/shared/time.d.ts +1 -2
- package/dist/core/shared/time.js +98 -11
- package/dist/core/shared/time.js.map +1 -1
- package/dist/core/store/index.d.ts +1 -0
- package/dist/core/store/index.js +1 -0
- package/dist/core/store/index.js.map +1 -1
- package/dist/core/store/item-format-migration.d.ts +9 -0
- package/dist/core/store/item-format-migration.js +87 -0
- package/dist/core/store/item-format-migration.js.map +1 -0
- package/dist/core/store/item-store.d.ts +13 -4
- package/dist/core/store/item-store.js +238 -51
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/core/store/paths.d.ts +21 -3
- package/dist/core/store/paths.js +59 -4
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.d.ts +14 -1
- package/dist/core/store/settings.js +463 -7
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/consent.d.ts +2 -0
- package/dist/core/telemetry/consent.js +79 -0
- package/dist/core/telemetry/consent.js.map +1 -0
- package/dist/core/telemetry/runtime.d.ts +38 -0
- package/dist/core/telemetry/runtime.js +733 -0
- package/dist/core/telemetry/runtime.js.map +1 -0
- package/dist/core/test/background-runs.d.ts +117 -0
- package/dist/core/test/background-runs.js +760 -0
- package/dist/core/test/background-runs.js.map +1 -0
- package/dist/core/test/item-test-run-tracking.d.ts +9 -0
- package/dist/core/test/item-test-run-tracking.js +50 -0
- package/dist/core/test/item-test-run-tracking.js.map +1 -0
- package/dist/sdk/cli-contracts.d.ts +92 -0
- package/dist/sdk/cli-contracts.js +2357 -0
- package/dist/sdk/cli-contracts.js.map +1 -0
- package/dist/sdk/index.d.ts +34 -0
- package/dist/sdk/index.js +23 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/types.d.ts +197 -3
- package/dist/types.js +48 -1
- package/dist/types.js.map +1 -1
- package/docs/ARCHITECTURE.md +368 -39
- package/docs/EXTENSIONS.md +454 -49
- package/docs/RELEASING.md +68 -19
- package/docs/SDK.md +123 -0
- package/docs/examples/starter-extension/README.md +48 -0
- package/docs/examples/starter-extension/index.js +191 -0
- package/docs/examples/starter-extension/manifest.json +17 -0
- package/docs/examples/starter-extension/package.json +10 -0
- package/package.json +33 -6
- package/.pi/extensions/pm-cli/index.ts +0 -778
- package/dist/cli/commands/beads.d.ts +0 -16
- package/dist/cli/commands/beads.js.map +0 -1
- package/dist/cli/commands/install.d.ts +0 -18
- package/dist/cli/commands/install.js +0 -87
- package/dist/cli/commands/install.js.map +0 -1
- package/dist/core/extensions/builtins.d.ts +0 -3
- package/dist/core/extensions/builtins.js +0 -47
- package/dist/core/extensions/builtins.js.map +0 -1
- package/dist/extensions/builtins/beads/index.d.ts +0 -8
- package/dist/extensions/builtins/beads/index.js +0 -33
- package/dist/extensions/builtins/beads/index.js.map +0 -1
- package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
- package/dist/extensions/builtins/todos/import-export.js.map +0 -1
- package/dist/extensions/builtins/todos/index.d.ts +0 -8
- package/dist/extensions/builtins/todos/index.js +0 -38
- package/dist/extensions/builtins/todos/index.js.map +0 -1
package/docs/EXTENSIONS.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# pm-cli Extension Development Guide
|
|
2
2
|
|
|
3
|
-
Extensions let you add commands, renderers, importers, exporters, schema fields, search providers, and lifecycle hooks to `pm-cli` without modifying core.
|
|
3
|
+
Extensions let you add commands, parser/preflight lifecycle control, core service overrides, renderers, importers, exporters, schema fields, item-type definitions, search providers, and lifecycle hooks to `pm-cli` without modifying core.
|
|
4
|
+
|
|
5
|
+
For a quick SDK-first authoring path, start with `docs/SDK.md`.
|
|
4
6
|
|
|
5
7
|
## Extension Locations
|
|
6
8
|
|
|
@@ -9,7 +11,146 @@ Extensions let you add commands, renderers, importers, exporters, schema fields,
|
|
|
9
11
|
| Global | `~/.pm-cli/extensions/<name>/` (override: `PM_GLOBAL_PATH/extensions/<name>/`) |
|
|
10
12
|
| Project | `.agents/pm/extensions/<name>/` (override: `PM_PATH/extensions/<name>/`) |
|
|
11
13
|
|
|
12
|
-
**Load order:**
|
|
14
|
+
**Load order:** global → project. Project-local extensions take precedence over global when they declare the same command name or renderer key.
|
|
15
|
+
|
|
16
|
+
## Linked-Test Sandbox Parity
|
|
17
|
+
|
|
18
|
+
`pm test --run` and `pm test-all` execute linked commands in temporary sandbox roots (`PM_PATH`, `PM_GLOBAL_PATH`) to avoid mutating live tracker data. Before command execution, the runtime seeds sandbox project/global `settings.json` and `extensions/` directories from the source roots.
|
|
19
|
+
|
|
20
|
+
This preserves extension-defined schema behavior (including custom item type validation/filtering) while retaining sandbox isolation for linked-test execution.
|
|
21
|
+
|
|
22
|
+
Linked-test runtime controls are additive: run-level `--env-set`/`--env-clear`/`--shared-host-safe` flags and per-linked-test metadata directives (`env_set`, `env_clear`, `shared_host_safe`) apply before sandbox-protected `PM_PATH`/`PM_GLOBAL_PATH` overrides.
|
|
23
|
+
|
|
24
|
+
PM-command linked tests can opt into tracker-data parity via `--pm-context tracker` (default `schema` keeps isolated tracker data while still seeding settings/extensions). `--pm-context auto` automatically routes PM tracker-read commands through tracker-seeded context while keeping other commands in schema context. Per-linked-test metadata can override run-level mode with `pm_context_mode=schema|tracker|auto`. In default `schema` mode, PM tracker-read linked commands fail on context mismatch by default; strict guards remain available for other PM command shapes via `--fail-on-context-mismatch` plus `--fail-on-skipped` and `--require-assertions-for-pm`.
|
|
25
|
+
|
|
26
|
+
Context ergonomics flags are additive:
|
|
27
|
+
|
|
28
|
+
- `--check-context` emits deterministic preflight diagnostics/warnings (`context_preflight`) for PM command context mismatches
|
|
29
|
+
- `--auto-pm-context` auto-remediates tracker-read mismatches by routing those commands to tracker context
|
|
30
|
+
|
|
31
|
+
Per-run `execution_context` metadata includes resolved roots, item counts, mismatch signal, PM tracker-read classification, `requested_pm_context_mode`, and `auto_pm_context_applied`.
|
|
32
|
+
|
|
33
|
+
Linked-test assertion metadata is optional and additive (`assert_stdout_contains`, `assert_stdout_regex`, `assert_stderr_contains`, `assert_stderr_regex`, `assert_stdout_min_lines`, `assert_json_field_equals`, `assert_json_field_gte`).
|
|
34
|
+
|
|
35
|
+
## Lifecycle Manager CLI
|
|
36
|
+
|
|
37
|
+
`pm extension` is the canonical lifecycle manager for custom extensions.
|
|
38
|
+
|
|
39
|
+
Top-level action and subcommand forms are flag-equivalent for lifecycle operations (for example `pm extension --doctor --detail deep --trace` and `pm extension doctor --detail deep --trace` resolve the same behavior).
|
|
40
|
+
|
|
41
|
+
### Actions
|
|
42
|
+
|
|
43
|
+
Pass exactly one action flag:
|
|
44
|
+
|
|
45
|
+
- `--init` (alias: `--scaffold`)
|
|
46
|
+
- `--install`
|
|
47
|
+
- `--uninstall`
|
|
48
|
+
- `--explore`
|
|
49
|
+
- `--manage`
|
|
50
|
+
- `--doctor`
|
|
51
|
+
- `--adopt`
|
|
52
|
+
- `--adopt-all`
|
|
53
|
+
- `--activate`
|
|
54
|
+
- `--deactivate`
|
|
55
|
+
|
|
56
|
+
### Scope selection
|
|
57
|
+
|
|
58
|
+
- `--project` (default)
|
|
59
|
+
- `--local` (alias for `--project`)
|
|
60
|
+
- `--global`
|
|
61
|
+
|
|
62
|
+
Project scope resolves against `.agents/pm/extensions`. Global scope resolves against `~/.pm-cli/extensions` (or `PM_GLOBAL_PATH/extensions`).
|
|
63
|
+
|
|
64
|
+
### Install source normalization
|
|
65
|
+
|
|
66
|
+
`pm extension --install` accepts:
|
|
67
|
+
|
|
68
|
+
- local directory paths
|
|
69
|
+
- GitHub HTTPS URLs
|
|
70
|
+
- `github.com/<owner>/<repo>[/path]` shorthand
|
|
71
|
+
- `--gh <owner>/<repo>[/path]` (alias: `--github`)
|
|
72
|
+
- optional `--ref <branch|tag|sha>` for GitHub sources
|
|
73
|
+
|
|
74
|
+
When the source path is shorthand (for example `owner/repo/my-ext`), install resolution probes in this order:
|
|
75
|
+
|
|
76
|
+
1. `<clone>/<subpath>`
|
|
77
|
+
2. `<clone>/.agents/pm/extensions/<subpath>`
|
|
78
|
+
3. `<clone>/.custom/pm-extensions/<subpath>`
|
|
79
|
+
4. `<clone>/.custom/pm-extension/<subpath>`
|
|
80
|
+
|
|
81
|
+
If no subpath is supplied, the resolver accepts either:
|
|
82
|
+
|
|
83
|
+
- repo root containing one extension (`manifest.json` at root), or
|
|
84
|
+
- exactly one extension under default roots (`.agents/pm/extensions`, `.custom/pm-extensions`, `.custom/pm-extension`)
|
|
85
|
+
|
|
86
|
+
If multiple extension manifests are discovered, install fails with deterministic guidance to provide an explicit path.
|
|
87
|
+
|
|
88
|
+
### Requested equivalence examples
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Scaffold a starter extension project in your workspace
|
|
92
|
+
pm extension --init ./my-extension
|
|
93
|
+
pm extension scaffold ./my-extension
|
|
94
|
+
|
|
95
|
+
# Bundled aliases shipped with pm-cli (not auto-installed)
|
|
96
|
+
pm extension --install --project beads
|
|
97
|
+
pm extension --install --project todos
|
|
98
|
+
|
|
99
|
+
# Equivalent bundled local paths
|
|
100
|
+
pm extension --install --project .agents/pm/extensions/beads
|
|
101
|
+
pm extension --install --project .agents/pm/extensions/todos
|
|
102
|
+
|
|
103
|
+
# Custom roots
|
|
104
|
+
pm extension --install --project https://github.com/unbraind/pm-cli/tree/main/.custom/pm-extensions/my-ext
|
|
105
|
+
pm extension --install --project github.com/unbraind/pm-cli/.custom/pm-extensions/my-ext
|
|
106
|
+
pm extension --install --project --gh unbraind/pm-cli/.custom/pm-extensions/my-ext
|
|
107
|
+
|
|
108
|
+
# Single-extension repo or extension rooted at repository top-level
|
|
109
|
+
pm extension --install --project https://github.com/unbraind/pm-cli
|
|
110
|
+
pm extension --install --project github.com/unbraind/pm-cli
|
|
111
|
+
pm extension --install --project --gh unbraind/pm-cli
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Canonical public shorthand examples in this repository use `unbraind/pm-cli`. For private repositories, make sure git authentication is configured before using `--gh` or `github.com/...` selectors.
|
|
115
|
+
|
|
116
|
+
### Managed extension state
|
|
117
|
+
|
|
118
|
+
Each scope maintains a lifecycle state file:
|
|
119
|
+
|
|
120
|
+
- `<scope-extension-root>/.managed-extensions.json`
|
|
121
|
+
|
|
122
|
+
State records include deterministic source metadata (`local` or `github`), install timestamps, manifest summary, and update-check metadata.
|
|
123
|
+
|
|
124
|
+
Lifecycle semantics:
|
|
125
|
+
|
|
126
|
+
- Init/scaffold creates an idempotent starter extension project (`manifest.json`, `index.js`, `README.md`) and fails fast on conflicting pre-existing file contents.
|
|
127
|
+
- Install copies/clones into the selected extension root, validates `manifest.json` and `entry`, updates managed state, and activates the extension in settings.
|
|
128
|
+
- Uninstall removes extension files, removes managed-state entry, and clears settings references.
|
|
129
|
+
- Activate/deactivate updates `settings.extensions.enabled[]` / `settings.extensions.disabled[]`.
|
|
130
|
+
- Explore returns discovered extensions + compatibility/runtime status fields (`active`, `enabled`, `runtime_active`, `activation_status`) and managed state.
|
|
131
|
+
- Manage performs GitHub update checks (`git ls-remote`) for managed GitHub entries and persists update metadata (`last_update_check_at`, `last_update_remote_commit`, `update_available`, `update_error`).
|
|
132
|
+
- Manage supports `--runtime-probe` to opt into doctor-equivalent runtime activation semantics for `runtime_active`/`activation_status`.
|
|
133
|
+
- Manage and doctor support `--fix-managed-state` to adopt unmanaged extensions before diagnostics/update checks.
|
|
134
|
+
- Adopt records an already-installed unmanaged extension into managed state metadata without reinstalling files (supports local source metadata or explicit GitHub provenance via `--gh`/`--github` and optional `--ref`).
|
|
135
|
+
- Adopt-all bulk-records all unmanaged installed extensions in selected scope into managed state metadata without reinstalling files.
|
|
136
|
+
- Explore/manage extension rows include explicit update-check fields:
|
|
137
|
+
- `update_check_status`: `checked`, `failed`, `skipped_unmanaged`, `skipped_non_github`, or `not_checked`
|
|
138
|
+
- `update_check_reason`: deterministic reason/code for that status (for example `up_to_date`, `update_available`, `extension_not_managed`, or the update failure text)
|
|
139
|
+
- Manage triage includes `update_check_status_totals`, `update_check_failed_total`, and update-health coverage signals (`update_health_coverage`, `update_health_partial`) for operator-friendly rollups.
|
|
140
|
+
- Manage/doctor warning-code rollups include `extension_update_health_partial_coverage` only when unmanaged extensions are action-required for update-check coverage. Expected bundled/local unmanaged installs are surfaced as informational triage metadata.
|
|
141
|
+
- Doctor consolidates diagnostics into summary/deep modes (`--detail summary|deep`) with normalized warning codes, canonical extension load roots, consistency diagnostics for active-vs-loaded project extensions, update-health coverage telemetry, remediation hints, strict warning exits (`--strict-exit`, alias `--fail-on-warn`), blocking-failure indicators (`blocking_failure_count`, `has_blocking_failures`), capability guidance metadata (`pm extension --doctor` or `pm extension doctor`), and capability contract metadata (`details.capability_contract`).
|
|
142
|
+
- Doctor `--trace` (with `--detail deep`) includes actionable activation trace payloads for registration validation failures (method, command, registration index, expected schema, and sanitized received payload).
|
|
143
|
+
|
|
144
|
+
### Health integration
|
|
145
|
+
|
|
146
|
+
`pm health` includes managed extension diagnostics for project and global scope:
|
|
147
|
+
|
|
148
|
+
- managed-state file path
|
|
149
|
+
- managed entry count
|
|
150
|
+
- managed entry summaries
|
|
151
|
+
- managed-state read/schema warnings
|
|
152
|
+
- update-coverage parity warnings (`extension_update_health_partial_coverage`) when loaded unmanaged extensions are action-required and update checks are partial
|
|
153
|
+
- For focused extension triage, use `pm extension --doctor` for consolidated diagnostics without traversing full health payloads.
|
|
13
154
|
|
|
14
155
|
## Manifest
|
|
15
156
|
|
|
@@ -23,6 +164,9 @@ Every extension directory must contain a `manifest.json`:
|
|
|
23
164
|
"priority": 100,
|
|
24
165
|
"capabilities": [
|
|
25
166
|
"commands",
|
|
167
|
+
"parser",
|
|
168
|
+
"preflight",
|
|
169
|
+
"services",
|
|
26
170
|
"renderers",
|
|
27
171
|
"hooks",
|
|
28
172
|
"schema",
|
|
@@ -34,18 +178,43 @@ Every extension directory must contain a `manifest.json`:
|
|
|
34
178
|
|
|
35
179
|
- `entry` must resolve inside the extension directory (no path traversal).
|
|
36
180
|
- `capabilities` declares what the extension will register. API calls that exceed declared capabilities fail activation deterministically.
|
|
37
|
-
- Unknown capability names are
|
|
181
|
+
- Unknown capability names are ignored for gating but emit discovery diagnostics that include allowed-capability lists and nearest-match suggestions when confidence is high.
|
|
182
|
+
- Legacy manifest capability aliases `migration` and `validation` are remapped to `schema` and emit consolidated warning `extension_capability_legacy_alias` so compatibility remains additive while migration intent stays visible.
|
|
183
|
+
|
|
184
|
+
## SDK Dependency Setup
|
|
185
|
+
|
|
186
|
+
External extensions should declare an explicit dependency on the pm package so `@unbrained/pm-cli/sdk` resolves at runtime.
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"name": "my-pm-extension",
|
|
191
|
+
"type": "module",
|
|
192
|
+
"dependencies": {
|
|
193
|
+
"@unbrained/pm-cli": "^2026.3.12"
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
This keeps extension imports stable and avoids relying on internal `src/core/...` paths.
|
|
199
|
+
|
|
200
|
+
## Starter Extension Reference
|
|
201
|
+
|
|
202
|
+
For a complete example that demonstrates all 9 capabilities via the public SDK, see:
|
|
203
|
+
|
|
204
|
+
- `docs/examples/starter-extension/`
|
|
38
205
|
|
|
39
206
|
## Extension Module
|
|
40
207
|
|
|
41
208
|
The entry module must export an `activate` function:
|
|
42
209
|
|
|
43
210
|
```ts
|
|
44
|
-
import type
|
|
211
|
+
import { defineExtension, type ExtensionApi } from "@unbrained/pm-cli/sdk";
|
|
45
212
|
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
213
|
+
export default defineExtension({
|
|
214
|
+
activate(api: ExtensionApi): void {
|
|
215
|
+
// register commands, hooks, renderers, etc.
|
|
216
|
+
},
|
|
217
|
+
});
|
|
49
218
|
```
|
|
50
219
|
|
|
51
220
|
`activate` may be synchronous or return `Promise<void>`.
|
|
@@ -54,65 +223,204 @@ export function activate(api: ExtensionApi): void {
|
|
|
54
223
|
|
|
55
224
|
### `api.registerCommand(def)`
|
|
56
225
|
|
|
57
|
-
Register a new command or
|
|
226
|
+
Register a new command handler path or replace an existing core command at dispatch time.
|
|
58
227
|
|
|
59
228
|
**New command path:**
|
|
60
229
|
|
|
61
230
|
```ts
|
|
62
231
|
api.registerCommand({
|
|
63
232
|
name: "acme sync",
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
233
|
+
action: "acme-sync",
|
|
234
|
+
description: "Synchronize ACME assets into PM items.",
|
|
235
|
+
intent: "Run a deterministic import/sync pass before release prep.",
|
|
236
|
+
examples: ["pm acme sync --source ./assets.json --dry-run"],
|
|
237
|
+
failure_hints: ["Ensure --source points to a readable JSON file."],
|
|
238
|
+
arguments: [
|
|
239
|
+
{ name: "sourceId", required: false, description: "Optional source identifier override." },
|
|
240
|
+
],
|
|
241
|
+
flags: [
|
|
242
|
+
{ long: "--source", value_name: "path", description: "Input file path", required: true },
|
|
243
|
+
{ long: "--dry-run", description: "Preview without writing items" },
|
|
244
|
+
],
|
|
245
|
+
run: async (context) => {
|
|
246
|
+
// context.command: normalized command path
|
|
247
|
+
// context.args: string[] positional args
|
|
248
|
+
// context.options: Record<string, unknown> command-scoped flags
|
|
249
|
+
// context.global: GlobalOptions (--json/--quiet/--path/--no-extensions/--profile)
|
|
250
|
+
// context.pm_root: resolved PM root
|
|
68
251
|
return { ok: true, synced: 42 };
|
|
69
252
|
},
|
|
70
253
|
});
|
|
71
254
|
```
|
|
72
255
|
|
|
73
|
-
|
|
256
|
+
If the command path matches a core command (for example `list-open`), the extension handler runs first and the core action is skipped. Command names are canonicalized (trimmed, lowercased, repeated whitespace collapsed). Handlers receive cloned snapshots so mutation cannot leak into caller state.
|
|
257
|
+
|
|
258
|
+
Capability requirements:
|
|
259
|
+
|
|
260
|
+
- `registerCommand(...)` requires `commands` capability.
|
|
261
|
+
- Defining inline command metadata `flags` inside `registerCommand({ ... })` also requires `schema` capability (same gate as `registerFlags(...)`).
|
|
262
|
+
|
|
263
|
+
Optional command metadata (`action`, `description`, `intent`, `examples`, `failure_hints`, `arguments`, and inline `flags`) is consumed by runtime help surfaces and contracts:
|
|
264
|
+
|
|
265
|
+
- `pm <extension-command> --help` / `--help --json`
|
|
266
|
+
- `pm contracts --command <extension-command>`
|
|
267
|
+
- `pm contracts --action <extension-action>`
|
|
268
|
+
|
|
269
|
+
For backward compatibility, command definitions that still use `handler` are accepted and mapped to `run`, with warning `extension_command_definition_legacy_handler_alias` to guide migration.
|
|
74
270
|
|
|
75
271
|
**Override existing core command result:**
|
|
76
272
|
|
|
77
273
|
```ts
|
|
78
|
-
api.registerCommand("list", (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
274
|
+
api.registerCommand("list", (context) => {
|
|
275
|
+
return {
|
|
276
|
+
...(context.result as Record<string, unknown>),
|
|
277
|
+
_ext: "annotated",
|
|
278
|
+
command: context.command,
|
|
279
|
+
pm_root: context.pm_root,
|
|
280
|
+
};
|
|
82
281
|
});
|
|
83
282
|
```
|
|
84
283
|
|
|
284
|
+
Result override callbacks are synchronous. Returning a Promise is ignored and emits `extension_command_override_async_unsupported:<layer>:<name>:<command>`.
|
|
285
|
+
|
|
286
|
+
### `api.registerParser(command, override)`
|
|
287
|
+
|
|
288
|
+
Register command-scoped parser overrides for core or dynamic command paths. Parser overrides run before command handler dispatch and can rewrite `args`, `options`, and `global` values.
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
api.registerParser("acme sync", (context) => {
|
|
292
|
+
return {
|
|
293
|
+
options: {
|
|
294
|
+
...context.options,
|
|
295
|
+
limit: Number(context.options.limit),
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
});
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Notes:
|
|
302
|
+
|
|
303
|
+
- Requires `parser` capability.
|
|
304
|
+
- Resolution is deterministic (last registered override for the command path wins).
|
|
305
|
+
- Parser handlers can be async.
|
|
306
|
+
- Failed parser overrides fall back to the original command context and emit deterministic warnings.
|
|
307
|
+
|
|
308
|
+
### `api.registerPreflight(override)`
|
|
309
|
+
|
|
310
|
+
Register a preflight override to control command mutation gates and migration execution.
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
api.registerPreflight((context) => ({
|
|
314
|
+
enforce_item_format_gate: false,
|
|
315
|
+
run_preflight_item_format_sync: false,
|
|
316
|
+
run_extension_migrations: false,
|
|
317
|
+
enforce_mandatory_migration_gate: false,
|
|
318
|
+
}));
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
`context.decision` contains the default gate/migration plan:
|
|
322
|
+
|
|
323
|
+
- `enforce_item_format_gate`
|
|
324
|
+
- `run_preflight_item_format_sync`
|
|
325
|
+
- `run_extension_migrations`
|
|
326
|
+
- `enforce_mandatory_migration_gate`
|
|
327
|
+
|
|
328
|
+
Notes:
|
|
329
|
+
|
|
330
|
+
- Requires `preflight` capability.
|
|
331
|
+
- Only the latest registered preflight override is active (deterministic last-wins behavior).
|
|
332
|
+
- Use this API carefully: disabling gates/migrations can bypass core safety rails.
|
|
333
|
+
|
|
334
|
+
### `api.registerService(service, override)`
|
|
335
|
+
|
|
336
|
+
Register service-level overrides for deep runtime behavior.
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
api.registerService("output_format", (context) => {
|
|
340
|
+
return JSON.stringify({
|
|
341
|
+
rendered_by: "acme-service",
|
|
342
|
+
payload: context.payload.result,
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Supported service keys:
|
|
348
|
+
|
|
349
|
+
- `output_format`
|
|
350
|
+
- `error_format`
|
|
351
|
+
- `help_format`
|
|
352
|
+
- `lock_acquire`
|
|
353
|
+
- `lock_release`
|
|
354
|
+
- `history_append`
|
|
355
|
+
- `item_store_write`
|
|
356
|
+
- `item_store_delete`
|
|
357
|
+
|
|
358
|
+
Notes:
|
|
359
|
+
|
|
360
|
+
- Requires `services` capability.
|
|
361
|
+
- Service resolution is deterministic (last registration for each service key wins).
|
|
362
|
+
- `output_format` and `error_format` are synchronous call sites; async returns are ignored with deterministic warnings.
|
|
363
|
+
- `error_format` receives the final rendered error string. When callers use `--json`, that string is a JSON error envelope.
|
|
364
|
+
- `help_format` applies to text help/usage rendering paths; machine-readable `--json` errors and `--help --json` payloads bypass `help_format` and emit canonical JSON diagnostics/help data directly.
|
|
365
|
+
|
|
85
366
|
### `api.registerFlags(targetCommand, flags)`
|
|
86
367
|
|
|
87
368
|
Declare flags for a command (displayed in `--help` for dynamic extension commands):
|
|
88
369
|
|
|
89
370
|
```ts
|
|
90
371
|
api.registerFlags("acme sync", [
|
|
91
|
-
{
|
|
92
|
-
{
|
|
372
|
+
{ long: "--dry-run", short: "-d", description: "Simulate without writing" },
|
|
373
|
+
{ long: "--org", value_name: "name", description: "Organization name", required: true },
|
|
374
|
+
{ long: "--legacy-mode", enabled: false },
|
|
375
|
+
{ long: "--internal-debug", visible: false },
|
|
93
376
|
]);
|
|
94
377
|
```
|
|
95
378
|
|
|
379
|
+
Supported metadata for dynamic extension help/contract rendering:
|
|
380
|
+
|
|
381
|
+
- `required: true` appends a `[required]` marker in help.
|
|
382
|
+
- `enabled: false` appends a `[disabled]` marker in help.
|
|
383
|
+
- `visible: false` hides the flag from dynamic help output.
|
|
384
|
+
- `type` / `value_type` (`string` | `number` | `boolean`) enables runtime loose-option coercion for matching command flags.
|
|
385
|
+
- Validation contract: each entry must provide at least one of `long` or `short`; optional metadata fields must match expected scalar types.
|
|
386
|
+
|
|
387
|
+
Core help output appends command-level guidance with compact defaults (`Intent` + one example) and supports deep help via `--explain`. Dynamic extension commands receive flag-level rendering from both `registerFlags(...)` and `registerCommand({ flags: [...] })`; provide explicit `description` text on each flag to keep help/contracts high-signal.
|
|
388
|
+
|
|
96
389
|
### `api.registerRenderer(format, renderer)`
|
|
97
390
|
|
|
98
391
|
Override TOON or JSON output for a command:
|
|
99
392
|
|
|
100
393
|
```ts
|
|
101
|
-
api.registerRenderer("toon", (
|
|
102
|
-
if (command !== "stats")
|
|
103
|
-
|
|
394
|
+
api.registerRenderer("toon", (context) => {
|
|
395
|
+
if (context.command !== "stats") {
|
|
396
|
+
return `noop: ${JSON.stringify(context.result)}`;
|
|
397
|
+
}
|
|
398
|
+
return customToonFormat(context.result);
|
|
104
399
|
});
|
|
105
400
|
```
|
|
106
401
|
|
|
107
|
-
|
|
402
|
+
Renderer overrides must return a string. Non-string return values are ignored and produce a deterministic `extension_renderer_invalid_result:<layer>:<name>:<format>` warning.
|
|
403
|
+
|
|
404
|
+
Without a renderer override, core TOON fallback output renders the command payload directly and applies sparse compaction:
|
|
405
|
+
|
|
406
|
+
- omits `null` and `undefined`
|
|
407
|
+
- omits empty arrays and empty objects
|
|
408
|
+
- preserves meaningful scalar values
|
|
409
|
+
|
|
410
|
+
If your extension needs a different shape (or must include fields omitted by sparse fallback), register a TOON renderer override.
|
|
108
411
|
|
|
109
412
|
### `api.registerImporter(name, importer)`
|
|
110
413
|
|
|
111
414
|
Register an importer (also wires `<name> import` command path):
|
|
112
415
|
|
|
113
416
|
```ts
|
|
114
|
-
api.registerImporter("jira", async (
|
|
115
|
-
//
|
|
417
|
+
api.registerImporter("jira", async (context) => {
|
|
418
|
+
// context.registration: normalized importer name
|
|
419
|
+
// context.action: "import"
|
|
420
|
+
// context.command: command path
|
|
421
|
+
// context.options: parsed command flags
|
|
422
|
+
// context.global: GlobalOptions
|
|
423
|
+
// context.pm_root: resolved PM root
|
|
116
424
|
return { ok: true, imported: 5, skipped: 0, ids: ["pm-xxxx"], warnings: [] };
|
|
117
425
|
});
|
|
118
426
|
```
|
|
@@ -122,11 +430,16 @@ api.registerImporter("jira", async (options, global) => {
|
|
|
122
430
|
Register an exporter (also wires `<name> export` command path):
|
|
123
431
|
|
|
124
432
|
```ts
|
|
125
|
-
api.registerExporter("jira", async (
|
|
433
|
+
api.registerExporter("jira", async (context) => {
|
|
434
|
+
// context.action: "export"
|
|
126
435
|
return { ok: true, exported: 5, ids: ["pm-xxxx"], warnings: [] };
|
|
127
436
|
});
|
|
128
437
|
```
|
|
129
438
|
|
|
439
|
+
Notes:
|
|
440
|
+
|
|
441
|
+
- `registerExporter(...)` uses the same capability gate as importers. Declare `importers` in `manifest.json` to use both `registerImporter(...)` and `registerExporter(...)`.
|
|
442
|
+
|
|
130
443
|
### `api.registerItemFields(fields)`
|
|
131
444
|
|
|
132
445
|
Declare additional front-matter fields for schema-awareness:
|
|
@@ -137,6 +450,57 @@ api.registerItemFields([
|
|
|
137
450
|
]);
|
|
138
451
|
```
|
|
139
452
|
|
|
453
|
+
Validation contract: each field entry must include non-empty `name` and `type`; `optional` must be boolean when provided.
|
|
454
|
+
|
|
455
|
+
### `api.registerItemTypes(types)`
|
|
456
|
+
|
|
457
|
+
Register custom item types and per-type create/type-option rules:
|
|
458
|
+
|
|
459
|
+
```ts
|
|
460
|
+
api.registerItemTypes([
|
|
461
|
+
{
|
|
462
|
+
name: "Asset",
|
|
463
|
+
folder: "assets",
|
|
464
|
+
aliases: ["assets", "3d-asset"],
|
|
465
|
+
required_create_fields: ["title", "description", "status", "priority", "message"],
|
|
466
|
+
required_create_repeatables: [],
|
|
467
|
+
command_option_policies: [
|
|
468
|
+
{ command: "create", option: "severity", enabled: false },
|
|
469
|
+
{ command: "create", option: "reporter", enabled: false },
|
|
470
|
+
{ command: "create", option: "goal", visible: false },
|
|
471
|
+
{ command: "update", option: "message", required: true },
|
|
472
|
+
],
|
|
473
|
+
options: [
|
|
474
|
+
{
|
|
475
|
+
key: "category",
|
|
476
|
+
values: ["Map", "Character", "Prop", "VFX"],
|
|
477
|
+
required: true,
|
|
478
|
+
aliases: ["asset_category"],
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
key: "pipeline",
|
|
482
|
+
values: ["Blockout", "Modeling", "Rigging", "Texturing", "Done"],
|
|
483
|
+
},
|
|
484
|
+
],
|
|
485
|
+
},
|
|
486
|
+
]);
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Validation contract highlights:
|
|
490
|
+
|
|
491
|
+
- each type entry must include non-empty `name`
|
|
492
|
+
- `aliases`, `required_create_fields`, and `required_create_repeatables` must be arrays of non-empty strings when provided
|
|
493
|
+
- `options[]` entries require non-empty `key`
|
|
494
|
+
- `command_option_policies[]` entries require non-empty `command` and `option`
|
|
495
|
+
- optional boolean toggles (`enabled`, `required`, `visible`) must be booleans when provided
|
|
496
|
+
|
|
497
|
+
Notes:
|
|
498
|
+
|
|
499
|
+
- Requires `schema` capability in the extension manifest.
|
|
500
|
+
- Type names and aliases are resolved by the runtime type registry and become available to `--type` filters and completion.
|
|
501
|
+
- Option definitions are validated by `pm create` / `pm update` through `--type-option` flags.
|
|
502
|
+
- `command_option_policies` are enforced by core create/update runtime and surfaced in policy-aware help sections.
|
|
503
|
+
|
|
140
504
|
### `api.registerMigration(def)`
|
|
141
505
|
|
|
142
506
|
Declare a schema migration (tracked in `pm health`):
|
|
@@ -153,6 +517,8 @@ api.registerMigration({
|
|
|
153
517
|
});
|
|
154
518
|
```
|
|
155
519
|
|
|
520
|
+
Validation contract: migration definitions must be objects; when provided, `id`/`description`/`status` must be strings, `mandatory` must be boolean, and `run` must be a function.
|
|
521
|
+
|
|
156
522
|
Migrations with `mandatory: true` and `status` not `"applied"` block write commands until resolved (bypass with `--force`).
|
|
157
523
|
|
|
158
524
|
### `api.registerSearchProvider(provider)`
|
|
@@ -162,12 +528,16 @@ Register a custom search provider:
|
|
|
162
528
|
```ts
|
|
163
529
|
api.registerSearchProvider({
|
|
164
530
|
name: "elastic",
|
|
165
|
-
query: async (
|
|
166
|
-
|
|
531
|
+
query: async (context) => {
|
|
532
|
+
// context.query, context.mode, context.tokens
|
|
533
|
+
// context.options, context.settings, context.documents
|
|
534
|
+
return [{ id: "pm-xxxx", score: 0.95, matched_fields: ["provider:elastic"] }];
|
|
167
535
|
},
|
|
168
536
|
});
|
|
169
537
|
```
|
|
170
538
|
|
|
539
|
+
Use `settings.search.provider` to select the active extension provider for live `pm search` execution.
|
|
540
|
+
|
|
171
541
|
### `api.registerVectorStoreAdapter(adapter)`
|
|
172
542
|
|
|
173
543
|
Register a custom vector store:
|
|
@@ -175,12 +545,18 @@ Register a custom vector store:
|
|
|
175
545
|
```ts
|
|
176
546
|
api.registerVectorStoreAdapter({
|
|
177
547
|
name: "pinecone",
|
|
178
|
-
upsert: async (
|
|
179
|
-
|
|
180
|
-
|
|
548
|
+
upsert: async (context) => {
|
|
549
|
+
// context.points, context.settings
|
|
550
|
+
},
|
|
551
|
+
query: async (context) => {
|
|
552
|
+
// context.vector, context.limit, context.settings
|
|
553
|
+
return [{ id: "pm-xxxx", score: 0.87 }];
|
|
554
|
+
},
|
|
181
555
|
});
|
|
182
556
|
```
|
|
183
557
|
|
|
558
|
+
Use `settings.vector_store.adapter` to select the active extension adapter for `pm search` query and `pm reindex` upsert.
|
|
559
|
+
|
|
184
560
|
## Lifecycle Hooks
|
|
185
561
|
|
|
186
562
|
Hooks run for every applicable core operation. Hook handlers receive cloned context snapshots — mutations do not leak back into caller state.
|
|
@@ -208,7 +584,7 @@ Runs after a command completes (even on failure):
|
|
|
208
584
|
api.hooks.afterCommand((ctx) => {
|
|
209
585
|
// ctx.ok: boolean
|
|
210
586
|
// ctx.result?: unknown
|
|
211
|
-
// ctx.error?:
|
|
587
|
+
// ctx.error?: string
|
|
212
588
|
// same fields as beforeCommand
|
|
213
589
|
});
|
|
214
590
|
```
|
|
@@ -220,8 +596,8 @@ Runs before each item file write:
|
|
|
220
596
|
```ts
|
|
221
597
|
api.hooks.onWrite((ctx) => {
|
|
222
598
|
// ctx.path: string
|
|
599
|
+
// ctx.scope: "project" | "global"
|
|
223
600
|
// ctx.op: string (create, update, restore, etc.)
|
|
224
|
-
// ctx.item_id: string
|
|
225
601
|
});
|
|
226
602
|
```
|
|
227
603
|
|
|
@@ -232,7 +608,7 @@ Runs after each item file read:
|
|
|
232
608
|
```ts
|
|
233
609
|
api.hooks.onRead((ctx) => {
|
|
234
610
|
// ctx.path: string
|
|
235
|
-
// ctx.
|
|
611
|
+
// ctx.scope: "project" | "global"
|
|
236
612
|
});
|
|
237
613
|
```
|
|
238
614
|
|
|
@@ -243,7 +619,7 @@ Runs during reindex/gc operations:
|
|
|
243
619
|
```ts
|
|
244
620
|
api.hooks.onIndex((ctx) => {
|
|
245
621
|
// ctx.mode: "keyword" | "semantic" | "hybrid" | "gc"
|
|
246
|
-
// ctx.
|
|
622
|
+
// ctx.total_items?: number
|
|
247
623
|
});
|
|
248
624
|
```
|
|
249
625
|
|
|
@@ -252,9 +628,21 @@ api.hooks.onIndex((ctx) => {
|
|
|
252
628
|
`pm health` probes all loaded extensions and surfaces:
|
|
253
629
|
|
|
254
630
|
- `extension_load_failed:<layer>:<name>` — manifest parse or module import error
|
|
631
|
+
- `extension_load_failed_sdk_dependency_missing:<name>` — doctor detected missing `@unbrained/pm-cli` dependency resolution in extension runtime imports
|
|
632
|
+
- `extension_load_failed_module_mode_mismatch:<name>` — doctor detected ESM/CJS mode mismatch (for example missing `"type": "module"` for ESM-style entrypoints)
|
|
255
633
|
- `extension_activate_failed:<layer>:<name>` — exception in `activate()`
|
|
256
634
|
- `extension_entry_outside_extension:<layer>:<name>` — entry path escapes directory
|
|
257
|
-
- `extension_capability_unknown:<layer>:<name>:<capability>` — unknown capability in manifest
|
|
635
|
+
- `extension_capability_unknown:<layer>:<name>:<capability>:allowed=<csv>:suggested=<capability|none>` — unknown capability in manifest with inline guidance (including legacy alias replacements where applicable)
|
|
636
|
+
- `extension_capability_legacy_alias:<layer>:<name>:aliases=<csv>` — legacy manifest capability aliases were remapped (for example `migration`/`validation` -> `schema`)
|
|
637
|
+
- `extension_command_definition_legacy_handler_alias:<layer>:<name>:<command>` — command definition used legacy `handler` key; runtime mapped it to `run`
|
|
638
|
+
- collision warnings when multiple extensions target the same command/parser/preflight/service/renderer key (last registration wins)
|
|
639
|
+
|
|
640
|
+
`pm health` and `pm extension --doctor` also surface machine-readable capability contract metadata in diagnostics payloads:
|
|
641
|
+
|
|
642
|
+
- `details.capability_contract.version`
|
|
643
|
+
- `details.capability_contract.capabilities`
|
|
644
|
+
- `details.capability_contract.legacy_aliases`
|
|
645
|
+
- parsed guidance entries in `details.capability_guidance` include `capability_contract_version`, `suggestion_source`, and `legacy_alias_target` when available
|
|
258
646
|
|
|
259
647
|
Use `pm health --json` to parse diagnostics programmatically.
|
|
260
648
|
|
|
@@ -294,7 +682,7 @@ Or configure per-project in `.agents/pm/settings.json`:
|
|
|
294
682
|
export function activate(api) {
|
|
295
683
|
api.registerCommand({
|
|
296
684
|
name: "hello",
|
|
297
|
-
run: async (
|
|
685
|
+
run: async (_context) => {
|
|
298
686
|
return { message: "Hello from extension!" };
|
|
299
687
|
},
|
|
300
688
|
});
|
|
@@ -306,24 +694,41 @@ pm hello
|
|
|
306
694
|
# => message: Hello from extension!
|
|
307
695
|
```
|
|
308
696
|
|
|
309
|
-
##
|
|
697
|
+
## Bundled Managed Extensions
|
|
310
698
|
|
|
311
|
-
`pm-cli` ships two
|
|
699
|
+
`pm-cli` ships two bundled extension sources in `.agents/pm/extensions`, but they are not auto-installed in project or global scope.
|
|
312
700
|
|
|
313
|
-
| Extension | Commands | Purpose |
|
|
314
|
-
|
|
315
|
-
| `builtin-beads-import` | `pm beads import` | Import Beads JSONL records into pm items |
|
|
316
|
-
| `builtin-todos-import-export` | `pm todos import`, `pm todos export` | Round-trip todos markdown format |
|
|
701
|
+
| Extension | Alias | Commands (after install) | Purpose |
|
|
702
|
+
|-----------|-------|---------------------------|---------|
|
|
703
|
+
| `builtin-beads-import` | `beads` | `pm beads import` | Import Beads JSONL records into pm items |
|
|
704
|
+
| `builtin-todos-import-export` | `todos` | `pm todos import`, `pm todos export` | Round-trip todos markdown format |
|
|
317
705
|
|
|
318
|
-
|
|
706
|
+
Install either via alias or explicit bundled path:
|
|
707
|
+
|
|
708
|
+
```bash
|
|
709
|
+
# Alias installs
|
|
710
|
+
pm extension --install --project beads
|
|
711
|
+
pm extension --install --project todos
|
|
712
|
+
|
|
713
|
+
# Equivalent local bundled paths
|
|
714
|
+
pm extension --install --project .agents/pm/extensions/beads
|
|
715
|
+
pm extension --install --project .agents/pm/extensions/todos
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
The command paths `pm beads ...` and `pm todos ...` are available only after the extension is installed and active for the selected scope.
|
|
319
719
|
|
|
320
720
|
## Pi Agent Extension
|
|
321
721
|
|
|
322
|
-
The
|
|
722
|
+
The Pi wrapper implementation source remains at `.pi/extensions/pm-cli/index.ts` and is a Pi agent extension (not a pm-cli runtime extension managed by `pm extension`).
|
|
323
723
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
pm
|
|
327
|
-
|
|
724
|
+
Current wrapper parity includes:
|
|
725
|
+
|
|
726
|
+
- `action: "calendar"` for `pm calendar` / `pm cal` (`view`, `date`, `from`, `to`, `past`, `type`, `tag`, `priority`, `status`, `assignee`, `sprint`, `release`, `limit`, `format`)
|
|
727
|
+
- `create`/`update` reminder forwarding via repeatable `reminder` values (`at=<iso|relative>,text=<text>`)
|
|
728
|
+
- `create`/`update` custom type-option forwarding via repeatable `typeOption` values
|
|
729
|
+
- `create`/`update` audit controls including `allowAuditUpdate` and dependency-only `allowAuditDepUpdate`
|
|
730
|
+
- linked-test context preflight/remediation forwarding via `checkContext` and `autoPmContext` (`test` / `test-all`)
|
|
731
|
+
- cache cleanup forwarding via `dryRun` and repeatable `gcScope` (`gc`)
|
|
732
|
+
- extension lifecycle forwarding via `extension-install`, `extension-uninstall`, `extension-explore`, `extension-manage`, `extension-doctor`, `extension-adopt`, `extension-adopt-all`, `extension-activate`, and `extension-deactivate` actions (`target`, `scope`, `github`, `ref`, `detail`, `trace`, `runtimeProbe`, `fixManagedState`, `strictExit`, `failOnWarn`)
|
|
328
733
|
|
|
329
734
|
See [AGENTS.md](../AGENTS.md) section 9 for full usage details.
|