@unbrained/pm-cli 2026.5.10 → 2026.5.11

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 (124) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/.pi/README.md +10 -1
  3. package/.pi/agents/pm-triage-agent.md +19 -0
  4. package/.pi/agents/pm-verification-agent.md +21 -0
  5. package/.pi/chains/pm-native-delivery.chain.md +11 -0
  6. package/.pi/extensions/pm-cli/index.js +276 -36
  7. package/.pi/skills/pm-native/SKILL.md +6 -2
  8. package/CHANGELOG.md +7 -0
  9. package/README.md +9 -1
  10. package/dist/cli/argv-utils.d.ts +5 -0
  11. package/dist/cli/argv-utils.js +34 -0
  12. package/dist/cli/argv-utils.js.map +1 -0
  13. package/dist/cli/bootstrap-args.d.ts +15 -0
  14. package/dist/cli/bootstrap-args.js +211 -0
  15. package/dist/cli/bootstrap-args.js.map +1 -1
  16. package/dist/cli/commander-usage.js +109 -3
  17. package/dist/cli/commander-usage.js.map +1 -1
  18. package/dist/cli/commands/completion.js +7 -3
  19. package/dist/cli/commands/completion.js.map +1 -1
  20. package/dist/cli/commands/contracts.d.ts +19 -0
  21. package/dist/cli/commands/contracts.js +33 -1
  22. package/dist/cli/commands/contracts.js.map +1 -1
  23. package/dist/cli/commands/create.js +112 -51
  24. package/dist/cli/commands/create.js.map +1 -1
  25. package/dist/cli/commands/docs.js +9 -2
  26. package/dist/cli/commands/docs.js.map +1 -1
  27. package/dist/cli/commands/extension.d.ts +3 -1
  28. package/dist/cli/commands/extension.js +174 -2
  29. package/dist/cli/commands/extension.js.map +1 -1
  30. package/dist/cli/commands/files.js +9 -2
  31. package/dist/cli/commands/files.js.map +1 -1
  32. package/dist/cli/commands/init.d.ts +2 -0
  33. package/dist/cli/commands/init.js +21 -1
  34. package/dist/cli/commands/init.js.map +1 -1
  35. package/dist/cli/commands/metadata-normalizers.d.ts +4 -0
  36. package/dist/cli/commands/metadata-normalizers.js +37 -0
  37. package/dist/cli/commands/metadata-normalizers.js.map +1 -0
  38. package/dist/cli/commands/reindex.js +173 -135
  39. package/dist/cli/commands/reindex.js.map +1 -1
  40. package/dist/cli/commands/search.js +16 -6
  41. package/dist/cli/commands/search.js.map +1 -1
  42. package/dist/cli/commands/test.js +9 -2
  43. package/dist/cli/commands/test.js.map +1 -1
  44. package/dist/cli/commands/update.js +70 -39
  45. package/dist/cli/commands/update.js.map +1 -1
  46. package/dist/cli/error-guidance.d.ts +9 -1
  47. package/dist/cli/error-guidance.js +147 -6
  48. package/dist/cli/error-guidance.js.map +1 -1
  49. package/dist/cli/help-json-payload.js +11 -1
  50. package/dist/cli/help-json-payload.js.map +1 -1
  51. package/dist/cli/main.js +69 -6
  52. package/dist/cli/main.js.map +1 -1
  53. package/dist/cli/register-setup.js +14 -0
  54. package/dist/cli/register-setup.js.map +1 -1
  55. package/dist/cli/telemetry-flush.d.ts +2 -0
  56. package/dist/cli/telemetry-flush.js +4 -0
  57. package/dist/cli/telemetry-flush.js.map +1 -0
  58. package/dist/cli.js +1 -2
  59. package/dist/cli.js.map +1 -1
  60. package/dist/core/extensions/extension-types.d.ts +72 -0
  61. package/dist/core/extensions/extension-types.js +24 -0
  62. package/dist/core/extensions/extension-types.js.map +1 -1
  63. package/dist/core/extensions/loader.d.ts +1 -0
  64. package/dist/core/extensions/loader.js +766 -7
  65. package/dist/core/extensions/loader.js.map +1 -1
  66. package/dist/core/lock/lock.js +2 -0
  67. package/dist/core/lock/lock.js.map +1 -1
  68. package/dist/core/sentry/instrument.d.ts +15 -0
  69. package/dist/core/sentry/instrument.js +35 -3
  70. package/dist/core/sentry/instrument.js.map +1 -1
  71. package/dist/core/shared/constants.js +20 -0
  72. package/dist/core/shared/constants.js.map +1 -1
  73. package/dist/core/shared/errors.d.ts +8 -0
  74. package/dist/core/shared/errors.js.map +1 -1
  75. package/dist/core/shared/levenshtein.d.ts +1 -0
  76. package/dist/core/shared/levenshtein.js +37 -0
  77. package/dist/core/shared/levenshtein.js.map +1 -0
  78. package/dist/core/store/paths.js +34 -1
  79. package/dist/core/store/paths.js.map +1 -1
  80. package/dist/core/store/settings.js +210 -1
  81. package/dist/core/store/settings.js.map +1 -1
  82. package/dist/core/telemetry/runtime.d.ts +1 -0
  83. package/dist/core/telemetry/runtime.js +102 -3
  84. package/dist/core/telemetry/runtime.js.map +1 -1
  85. package/dist/mcp/server.js +3 -1
  86. package/dist/mcp/server.js.map +1 -1
  87. package/dist/pi/native.js +57 -4
  88. package/dist/pi/native.js.map +1 -1
  89. package/dist/sdk/cli-contracts.d.ts +21 -1
  90. package/dist/sdk/cli-contracts.js +250 -0
  91. package/dist/sdk/cli-contracts.js.map +1 -1
  92. package/dist/sdk/index.d.ts +12 -1
  93. package/dist/sdk/index.js +8 -1
  94. package/dist/sdk/index.js.map +1 -1
  95. package/dist/types.d.ts +41 -0
  96. package/dist/types.js.map +1 -1
  97. package/docs/CLAUDE_CODE_PLUGIN.md +39 -0
  98. package/docs/EXTENSIONS.md +687 -0
  99. package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
  100. package/docs/PI_PACKAGE.md +95 -10
  101. package/docs/SDK.md +441 -0
  102. package/docs/examples/ci/github-actions-pm-extension-gate.yml +53 -0
  103. package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +41 -0
  104. package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +45 -0
  105. package/docs/examples/policy-restricted-extension/README.md +74 -0
  106. package/docs/examples/policy-restricted-extension/index.js +21 -0
  107. package/docs/examples/policy-restricted-extension/manifest.json +21 -0
  108. package/docs/examples/policy-restricted-extension/package.json +8 -0
  109. package/docs/examples/sdk-app-embedding/README.md +39 -0
  110. package/docs/examples/sdk-app-embedding/package.json +9 -0
  111. package/docs/examples/sdk-app-embedding/run-embedded-pm.mjs +61 -0
  112. package/docs/examples/sdk-contract-consumer/README.md +57 -0
  113. package/docs/examples/sdk-contract-consumer/inspect-contracts.mjs +47 -0
  114. package/docs/examples/sdk-contract-consumer/package.json +10 -0
  115. package/docs/examples/starter-extension/README.md +57 -42
  116. package/docs/examples/starter-extension/manifest.json +15 -0
  117. package/marketplace.json +3 -3
  118. package/package.json +1 -1
  119. package/plugins/pm-cli-claude/.claude-plugin/plugin.json +2 -2
  120. package/plugins/pm-cli-claude/README.md +55 -14
  121. package/plugins/pm-cli-claude/agents/pm-delivery-chain.md +88 -0
  122. package/plugins/pm-cli-claude/agents/pm-triage-agent.md +83 -0
  123. package/plugins/pm-cli-claude/agents/pm-verification-agent.md +88 -0
  124. package/plugins/pm-cli-claude/hooks/session-start.mjs +87 -22
@@ -0,0 +1,53 @@
1
+ name: pm-extension-gate
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ jobs:
10
+ extension-gate:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout
14
+ uses: actions/checkout@v4
15
+
16
+ - name: Setup Node
17
+ uses: actions/setup-node@v4
18
+ with:
19
+ node-version: 22
20
+ cache: pnpm
21
+
22
+ - name: Setup pnpm
23
+ uses: pnpm/action-setup@v4
24
+ with:
25
+ version: 10
26
+
27
+ - name: Install dependencies
28
+ run: pnpm install --frozen-lockfile
29
+
30
+ - name: Build
31
+ run: pnpm build
32
+
33
+ - name: Export contracts (schema + flags)
34
+ run: |
35
+ pm contracts --schema-only --json > contracts-schema.json
36
+ pm contracts --command extension --flags-only --json > contracts-extension-flags.json
37
+ pm contracts --json > contracts-runtime.json
38
+
39
+ - name: Verify extension contract compatibility metadata
40
+ run: |
41
+ node -e 'const fs=require("node:fs");const c=JSON.parse(fs.readFileSync("contracts-runtime.json","utf8"));if(!c.extension_contracts?.compatibility){throw new Error("missing extension compatibility metadata");}'
42
+
43
+ - name: Reload extensions
44
+ run: pm extension --reload --project --json
45
+
46
+ - name: Extension governance diagnostics gate
47
+ run: pm extension --doctor --project --detail summary --strict-exit
48
+
49
+ - name: Unit tests
50
+ run: node scripts/run-tests.mjs test -- tests/unit/contracts-command.spec.ts tests/unit/extension-loader.spec.ts tests/unit/extension-command.spec.ts
51
+
52
+ - name: Coverage
53
+ run: node scripts/run-tests.mjs coverage
@@ -0,0 +1,41 @@
1
+ image: node:22
2
+
3
+ stages:
4
+ - build
5
+ - contracts
6
+ - extension_gate
7
+ - test
8
+
9
+ before_script:
10
+ - corepack enable
11
+ - corepack prepare pnpm@10 --activate
12
+ - pnpm install --frozen-lockfile
13
+
14
+ build:
15
+ stage: build
16
+ script:
17
+ - pnpm build
18
+
19
+ contracts:
20
+ stage: contracts
21
+ script:
22
+ - node dist/cli.js contracts --schema-only --json > contracts-schema.json
23
+ - node dist/cli.js contracts --command extension --flags-only --json > contracts-extension-flags.json
24
+ - node dist/cli.js contracts --json > contracts-runtime.json
25
+ artifacts:
26
+ paths:
27
+ - contracts-schema.json
28
+ - contracts-extension-flags.json
29
+ - contracts-runtime.json
30
+
31
+ extension_gate:
32
+ stage: extension_gate
33
+ script:
34
+ - node dist/cli.js extension --reload --project --json
35
+ - node dist/cli.js extension --doctor --project --detail summary --strict-exit --json
36
+
37
+ test:
38
+ stage: test
39
+ script:
40
+ - node scripts/run-tests.mjs test -- tests/unit/contracts-command.spec.ts tests/unit/extension-loader.spec.ts tests/unit/extension-command.spec.ts
41
+ - node scripts/run-tests.mjs coverage
@@ -0,0 +1,45 @@
1
+ pipeline {
2
+ agent any
3
+
4
+ tools {
5
+ nodejs "node-22"
6
+ }
7
+
8
+ stages {
9
+ stage("Install") {
10
+ steps {
11
+ sh "corepack enable"
12
+ sh "corepack prepare pnpm@10 --activate"
13
+ sh "pnpm install --frozen-lockfile"
14
+ }
15
+ }
16
+
17
+ stage("Build") {
18
+ steps {
19
+ sh "pnpm build"
20
+ }
21
+ }
22
+
23
+ stage("Contracts") {
24
+ steps {
25
+ sh "node dist/cli.js contracts --schema-only --json > contracts-schema.json"
26
+ sh "node dist/cli.js contracts --command extension --flags-only --json > contracts-extension-flags.json"
27
+ sh "node dist/cli.js contracts --json > contracts-runtime.json"
28
+ }
29
+ }
30
+
31
+ stage("Extension Gate") {
32
+ steps {
33
+ sh "node dist/cli.js extension --reload --project --json"
34
+ sh "node dist/cli.js extension --doctor --project --detail summary --strict-exit --json"
35
+ }
36
+ }
37
+
38
+ stage("Tests") {
39
+ steps {
40
+ sh "node scripts/run-tests.mjs test -- tests/unit/contracts-command.spec.ts tests/unit/extension-loader.spec.ts tests/unit/extension-command.spec.ts"
41
+ sh "node scripts/run-tests.mjs coverage"
42
+ }
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,74 @@
1
+ # Policy-Restricted Extension Example
2
+
3
+ This example demonstrates governance policy behavior with real registrations.
4
+
5
+ The extension declares:
6
+
7
+ - `commands` (handler registration)
8
+ - `hooks` (beforeCommand)
9
+ - `services` (output_format override)
10
+
11
+ You can enforce policy so command/hooks remain allowed while service override is blocked.
12
+
13
+ ## Run It
14
+
15
+ From repository root:
16
+
17
+ ```bash
18
+ mkdir -p .agents/pm/extensions
19
+ cp -R docs/examples/policy-restricted-extension .agents/pm/extensions/policy-restricted-extension
20
+ cd .agents/pm/extensions/policy-restricted-extension
21
+ npm install
22
+ cd -
23
+ pm extension --install --project .agents/pm/extensions/policy-restricted-extension
24
+ ```
25
+
26
+ Add policy in `.agents/pm/settings.json`:
27
+
28
+ ```json
29
+ {
30
+ "extensions": {
31
+ "policy": {
32
+ "mode": "enforce",
33
+ "trust_mode": "enforce",
34
+ "require_provenance": true,
35
+ "trusted_extensions": ["policy-restricted-extension"],
36
+ "default_sandbox_profile": "restricted",
37
+ "allowed_extensions": ["policy-restricted-extension"],
38
+ "blocked_extensions": [],
39
+ "allowed_capabilities": [],
40
+ "blocked_capabilities": [],
41
+ "allowed_surfaces": [],
42
+ "blocked_surfaces": ["services.override"],
43
+ "allowed_commands": [],
44
+ "blocked_commands": [],
45
+ "allowed_actions": [],
46
+ "blocked_actions": [],
47
+ "allowed_services": [],
48
+ "blocked_services": ["output_format"],
49
+ "extension_overrides": [
50
+ {
51
+ "name": "policy-restricted-extension",
52
+ "require_trusted": true,
53
+ "require_provenance": true,
54
+ "sandbox_profile": "strict"
55
+ }
56
+ ]
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ Then validate:
63
+
64
+ ```bash
65
+ pm extension --doctor --project --detail summary
66
+ pm policy demo
67
+ ```
68
+
69
+ Expected behavior:
70
+
71
+ - `pm policy demo` still works (command handler allowed).
72
+ - `extension --doctor` includes `extension_policy_blocked_registration`.
73
+ - `details.triage.policy_blocked_count` is greater than `0`.
74
+ - trust/provenance contract fields are visible in `pm contracts --json` metadata.
@@ -0,0 +1,21 @@
1
+ import { defineExtension } from "@unbrained/pm-cli/sdk";
2
+
3
+ export default defineExtension({
4
+ activate(api) {
5
+ api.registerCommand({
6
+ name: "policy demo",
7
+ action: "policy-demo",
8
+ description: "Emit a deterministic payload to validate policy-gated activation.",
9
+ run: async (context) => ({
10
+ ok: true,
11
+ command: context.command,
12
+ source: "policy-restricted-extension",
13
+ }),
14
+ });
15
+
16
+ api.hooks.beforeCommand(() => {});
17
+
18
+ // This registration is intentionally useful for policy demos.
19
+ api.registerService("output_format", (payload) => payload);
20
+ },
21
+ });
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "policy-restricted-extension",
3
+ "version": "0.1.0",
4
+ "entry": "./index.js",
5
+ "manifest_version": 2,
6
+ "trusted": true,
7
+ "provenance": {
8
+ "source": "docs/examples/policy-restricted-extension",
9
+ "verified": true
10
+ },
11
+ "sandbox_profile": "restricted",
12
+ "permissions": {
13
+ "fs_read": true,
14
+ "fs_write": false,
15
+ "network": false,
16
+ "env_read": true,
17
+ "env_write": false,
18
+ "process_spawn": false
19
+ },
20
+ "capabilities": ["commands", "hooks", "services"]
21
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "policy-restricted-extension",
3
+ "private": true,
4
+ "type": "module",
5
+ "dependencies": {
6
+ "@unbrained/pm-cli": "latest"
7
+ }
8
+ }
@@ -0,0 +1,39 @@
1
+ # SDK App Embedding Example
2
+
3
+ This example demonstrates a simple app-style wrapper that:
4
+
5
+ 1. validates an action using SDK contracts
6
+ 2. checks runtime availability (`pm contracts --json`)
7
+ 3. executes a safe command mapping
8
+ 4. emits a structured JSON payload for CI/services
9
+
10
+ ## Files
11
+
12
+ - `package.json`
13
+ - `run-embedded-pm.mjs`
14
+
15
+ ## Run
16
+
17
+ ```bash
18
+ cp -R docs/examples/sdk-app-embedding /tmp/pm-sdk-app-embedding
19
+ cd /tmp/pm-sdk-app-embedding
20
+
21
+ # During local development against this repository:
22
+ PM_CLI_REPO_ROOT=/absolute/path/to/pm-cli
23
+ npm install "$PM_CLI_REPO_ROOT"
24
+
25
+ # Run extension reload flow
26
+ node run-embedded-pm.mjs extension-reload
27
+ ```
28
+
29
+ ## What It Returns
30
+
31
+ The script returns JSON with:
32
+
33
+ - `action`
34
+ - resolved command invocation
35
+ - required/optional parameter contracts
36
+ - `policy_state` from action availability
37
+ - command result payload
38
+
39
+ This pattern is useful for backend workers, CI jobs, or orchestrators that must remain contract-safe across SDK/CLI upgrades.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "pm-sdk-app-embedding-example",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "start": "node run-embedded-pm.mjs",
7
+ "reload": "node run-embedded-pm.mjs extension-reload"
8
+ }
9
+ }
@@ -0,0 +1,61 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { PM_TOOL_ACTION_PARAMETER_CONTRACTS, isPmToolAction } from "@unbrained/pm-cli/sdk";
3
+
4
+ function runPm(args) {
5
+ const completed = spawnSync("pm", args, {
6
+ encoding: "utf8",
7
+ env: {
8
+ ...process.env,
9
+ NO_COLOR: "1",
10
+ },
11
+ });
12
+ if (completed.status !== 0) {
13
+ const stderr = (completed.stderr ?? "").trim();
14
+ throw new Error(stderr.length > 0 ? stderr : `pm ${args.join(" ")} failed with exit code ${completed.status}`);
15
+ }
16
+ const stdout = (completed.stdout ?? "").trim();
17
+ return stdout.length > 0 ? JSON.parse(stdout) : {};
18
+ }
19
+
20
+ function resolveCommandForAction(action) {
21
+ const commandMap = {
22
+ "extension-reload": ["extension", "--reload", "--project", "--json"],
23
+ "extension-doctor": ["extension", "--doctor", "--project", "--detail", "summary", "--json"],
24
+ contracts: ["contracts", "--json"],
25
+ };
26
+ return commandMap[action] ?? [action, "--json"];
27
+ }
28
+
29
+ const requestedAction = (process.argv[2] ?? "extension-reload").trim().toLowerCase();
30
+ if (!isPmToolAction(requestedAction)) {
31
+ throw new Error(`Unsupported pm action "${requestedAction}".`);
32
+ }
33
+
34
+ const contracts = runPm(["contracts", "--json"]);
35
+ const actionAvailability = Array.isArray(contracts.action_availability)
36
+ ? contracts.action_availability.find((entry) => entry?.action === requestedAction) ?? null
37
+ : null;
38
+ if (actionAvailability?.available === false) {
39
+ throw new Error(
40
+ `Action "${requestedAction}" is not available in this runtime (${actionAvailability.disabled_reason ?? "unknown_reason"}).`,
41
+ );
42
+ }
43
+
44
+ const actionContract = PM_TOOL_ACTION_PARAMETER_CONTRACTS[requestedAction];
45
+ const command = resolveCommandForAction(requestedAction);
46
+ const commandResult = runPm(command);
47
+
48
+ process.stdout.write(
49
+ `${JSON.stringify(
50
+ {
51
+ action: requestedAction,
52
+ command: `pm ${command.join(" ")}`,
53
+ required_parameters: actionContract.required ?? [],
54
+ optional_parameters: actionContract.optional ?? [],
55
+ policy_state: actionAvailability?.policy_state ?? null,
56
+ result: commandResult,
57
+ },
58
+ null,
59
+ 2,
60
+ )}\n`,
61
+ );
@@ -0,0 +1,57 @@
1
+ # SDK Contracts Consumer Example
2
+
3
+ This example shows how to consume `pm` contracts programmatically in a script and validate action payload requirements before execution.
4
+
5
+ ## Files
6
+
7
+ - `package.json` -> installs `@unbrained/pm-cli` and script aliases
8
+ - `inspect-contracts.mjs` -> loads contracts + SDK helpers and prints required/optional parameter metadata
9
+
10
+ ## Run
11
+
12
+ ```bash
13
+ cp -R docs/examples/sdk-contract-consumer /tmp/pm-sdk-contract-consumer
14
+ cd /tmp/pm-sdk-contract-consumer
15
+ # Local checkout (recommended while iterating on unreleased SDK changes):
16
+ PM_CLI_REPO_ROOT=/absolute/path/to/pm-cli
17
+ npm install "$PM_CLI_REPO_ROOT"
18
+
19
+ # Or use a published release once available:
20
+ # npm install @unbrained/pm-cli@latest
21
+
22
+ node inspect-contracts.mjs create
23
+ ```
24
+
25
+ Expected output shape:
26
+
27
+ ```json
28
+ {
29
+ "action": "create",
30
+ "required_parameters": ["title", "description", "type", "status", "priority", "message"],
31
+ "optional_parameters": ["template", "createMode", "schedulePreset"],
32
+ "any_of_required_groups": [],
33
+ "runtime_available": true,
34
+ "policy_state": null,
35
+ "compatibility": {
36
+ "current": "v2",
37
+ "previous": ["v1"],
38
+ "breaking_strategy": "versioned_breaking"
39
+ },
40
+ "manifest_versions": [1, 2]
41
+ }
42
+ ```
43
+
44
+ You can inspect any action:
45
+
46
+ ```bash
47
+ node inspect-contracts.mjs update
48
+ node inspect-contracts.mjs extension
49
+ node inspect-contracts.mjs extension-reload
50
+ ```
51
+
52
+ ## Why This Pattern Works
53
+
54
+ - Uses `isPmToolAction()` for strict action validation.
55
+ - Uses `PM_TOOL_ACTION_PARAMETER_CONTRACTS` for deterministic required/optional metadata.
56
+ - Uses runtime `pm contracts --json` so extension-provided actions and command availability are reflected.
57
+ - Includes policy-state and compatibility metadata so CI/app callers can gate behavior during v1 -> v2 migrations.
@@ -0,0 +1,47 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { PM_TOOL_ACTION_PARAMETER_CONTRACTS, isPmToolAction } from "@unbrained/pm-cli/sdk";
3
+
4
+ function runPmContracts() {
5
+ const completed = spawnSync("pm", ["contracts", "--json"], {
6
+ encoding: "utf8",
7
+ env: {
8
+ ...process.env,
9
+ NO_COLOR: "1",
10
+ },
11
+ });
12
+ if (completed.status !== 0) {
13
+ const stderr = (completed.stderr ?? "").trim();
14
+ throw new Error(stderr.length > 0 ? stderr : `pm contracts failed with exit code ${completed.status}`);
15
+ }
16
+ return JSON.parse(completed.stdout ?? "{}");
17
+ }
18
+
19
+ const requestedAction = (process.argv[2] ?? "create").trim().toLowerCase();
20
+ if (!isPmToolAction(requestedAction)) {
21
+ throw new Error(`Unsupported pm action "${requestedAction}".`);
22
+ }
23
+
24
+ const contracts = runPmContracts();
25
+ const availableActions = Array.isArray(contracts.actions) ? contracts.actions : [];
26
+ if (!availableActions.includes(requestedAction)) {
27
+ throw new Error(`Action "${requestedAction}" is not currently invocable in this runtime.`);
28
+ }
29
+ const actionAvailability = Array.isArray(contracts.action_availability)
30
+ ? contracts.action_availability.find((entry) => entry?.action === requestedAction) ?? null
31
+ : null;
32
+ const extensionContracts =
33
+ contracts.extension_contracts && typeof contracts.extension_contracts === "object" ? contracts.extension_contracts : null;
34
+
35
+ const actionContract = PM_TOOL_ACTION_PARAMETER_CONTRACTS[requestedAction];
36
+ const payload = {
37
+ action: requestedAction,
38
+ required_parameters: actionContract.required ?? [],
39
+ optional_parameters: actionContract.optional ?? [],
40
+ any_of_required_groups: actionContract.anyOfRequired ?? [],
41
+ runtime_available: actionAvailability?.available === true,
42
+ policy_state: actionAvailability?.policy_state ?? null,
43
+ compatibility: extensionContracts?.compatibility ?? null,
44
+ manifest_versions: extensionContracts?.manifest_versions ?? [],
45
+ };
46
+
47
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "pm-sdk-contract-consumer-example",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "inspect:create": "node inspect-contracts.mjs create",
7
+ "inspect:update": "node inspect-contracts.mjs update",
8
+ "inspect:reload": "node inspect-contracts.mjs extension-reload"
9
+ }
10
+ }
@@ -1,62 +1,77 @@
1
- # Starter Extension
1
+ # Starter Extension (Runnable Example)
2
2
 
3
- This example demonstrates all extension capability categories through the public SDK import `@unbrained/pm-cli/sdk`.
3
+ This example is a full capability reference extension. It intentionally demonstrates every extension capability surface, including parser/preflight/services/search/schema hooks.
4
4
 
5
- ## Agent Quick Context
5
+ Use it to learn APIs, then narrow capabilities for production extensions.
6
6
 
7
- - Copy this folder when you need a complete capability reference.
8
- - Use `pm extension init ./my-extension` when you need a smaller scaffold.
9
- - Keep production extensions narrower than this example.
7
+ ## Contents
10
8
 
11
- Related docs:
9
+ - `manifest.json` -> extension metadata/capabilities
10
+ - `package.json` -> local dependency metadata
11
+ - `index.js` -> capability demonstrations
12
12
 
13
- - [Extensions](../../EXTENSIONS.md)
14
- - [SDK](../../SDK.md)
13
+ ## End-to-End Run
15
14
 
16
- ## Files
17
-
18
- | File | Purpose |
19
- |------|---------|
20
- | `manifest.json` | declares extension metadata and capabilities |
21
- | `package.json` | declares local package metadata and SDK dependency |
22
- | `index.js` | registers examples for each capability category |
23
-
24
- ## Capability Coverage
25
-
26
- | Capability | Example surface |
27
- |------------|-----------------|
28
- | `commands` | `api.registerCommand(...)` |
29
- | `parser` | `api.registerParser(...)` |
30
- | `preflight` | `api.registerPreflight(...)` |
31
- | `services` | `api.registerService(...)` |
32
- | `renderers` | `api.registerRenderer(...)` |
33
- | `hooks` | command, read, write, and index hooks |
34
- | `schema` | item fields, item types, migrations |
35
- | `importers` | importer and exporter registration |
36
- | `search` | search provider and vector adapter |
37
-
38
- ## Quick Start
39
-
40
- Copy into an extension root:
15
+ From repository root:
41
16
 
42
17
  ```bash
18
+ # 1) Copy into project extension root
43
19
  mkdir -p .agents/pm/extensions
44
20
  cp -R docs/examples/starter-extension .agents/pm/extensions/starter-extension
21
+
22
+ # 2) Install dependencies for the copied extension
45
23
  cd .agents/pm/extensions/starter-extension
46
24
  npm install
25
+ cd -
26
+
27
+ # 3) Install/activate in project scope
28
+ pm extension --install --project .agents/pm/extensions/starter-extension
29
+
30
+ # 4) Run a starter command
31
+ pm starter ping --name "agent"
32
+
33
+ # 5) Reload extension modules after edits
34
+ pm extension --reload --project
35
+
36
+ # 6) Optional watch-mode semantics
37
+ pm extension --reload --project --watch
38
+
39
+ # 7) Verify runtime health
40
+ pm extension --doctor --project --detail summary
47
41
  ```
48
42
 
49
- Activate and test from the repository root:
43
+ Expected outcomes:
44
+
45
+ - `pm starter ping` returns deterministic output (plain text when starter service overrides output formatting).
46
+ - `extension --doctor` shows `details.summary.status` as `ok` or `warn`.
47
+ - If `warn`, inspect `details.summary.warning_codes` and `details.triage.remediation`.
48
+ - `extension --reload` returns deterministic load/activation diagnostics for cache-busted imports.
49
+
50
+ ## Policy-Restricted Variant
51
+
52
+ To test governance controls with this extension:
53
+
54
+ 1. Set `settings.extensions.policy.mode` to `warn` or `enforce`.
55
+ 2. Block one surface (for example `commands.override`).
56
+ 3. Re-run `pm extension --doctor --detail summary`.
57
+
58
+ You should see `extension_policy_*` warnings and policy counters in `details.triage`.
59
+
60
+ ## CI-Friendly Verification Commands
50
61
 
51
62
  ```bash
52
- pm extension activate starter-extension --project
53
- pm starter ping --name "agent"
54
- pm extension doctor --detail summary
63
+ pm contracts --command extension --flags-only --json
64
+ pm extension --doctor --project --detail summary --strict-exit
65
+ node scripts/run-tests.mjs test -- tests/unit/extension-loader.spec.ts tests/unit/extension-command.spec.ts
55
66
  ```
56
67
 
57
68
  ## Notes
58
69
 
59
- - This starter is for learning and scaffold reference.
60
- - Real extensions should declare only the capabilities they need.
61
- - Keep service, parser, and preflight overrides narrow and well tested.
62
- - Return deterministic JSON-like objects from command handlers.
70
+ - Keep production manifests minimal: only declare capabilities you need.
71
+ - Prefer command metadata (`action`, `examples`, `failure_hints`) for machine+human diagnostics.
72
+ - Keep parser/preflight/service overrides narrow and deterministic.
73
+
74
+ ## Related Examples
75
+
76
+ - `docs/examples/policy-restricted-extension/README.md`
77
+ - `docs/examples/sdk-contract-consumer/README.md`
@@ -3,6 +3,21 @@
3
3
  "version": "0.1.0",
4
4
  "description": "SDK-first starter extension demonstrating all pm extension capabilities.",
5
5
  "entry": "./index.js",
6
+ "manifest_version": 2,
7
+ "trusted": true,
8
+ "provenance": {
9
+ "source": "docs/examples/starter-extension",
10
+ "verified": true
11
+ },
12
+ "sandbox_profile": "none",
13
+ "permissions": {
14
+ "fs_read": true,
15
+ "fs_write": true,
16
+ "network": false,
17
+ "env_read": true,
18
+ "env_write": false,
19
+ "process_spawn": false
20
+ },
6
21
  "capabilities": [
7
22
  "commands",
8
23
  "parser",
package/marketplace.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "pm-cli",
2
+ "name": "pm",
3
3
  "description": "Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.",
4
4
  "owner": {
5
5
  "name": "unbrained",
@@ -8,8 +8,8 @@
8
8
  "plugins": [
9
9
  {
10
10
  "name": "pm-cli",
11
- "description": "Native pm CLI integration for Claude Code — 18 MCP tools, 5 workflow skills, 14 slash commands, hybrid TUI task tracking, session context injection, and a coordination subagent for git-based project management without leaving Claude Code.",
12
- "version": "1.2.0",
11
+ "description": "Native pm CLI integration for Claude Code — 18 MCP tools, 5 workflow skills, 14 slash commands, 3 subagents, hybrid TUI task tracking, session context injection, and coordination subagents for git-based project management without leaving Claude Code.",
12
+ "version": "1.3.0",
13
13
  "source": "./plugins/pm-cli-claude",
14
14
  "author": {
15
15
  "name": "unbrained",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-cli",
3
- "version": "2026.5.10",
3
+ "version": "2026.5.11",
4
4
  "description": "Git-native project management CLI for humans and agents.",
5
5
  "type": "module",
6
6
  "author": "unbrained",