@unbrained/pm-cli 2026.5.10 → 2026.5.12

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 (172) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/AGENTS.md +3 -116
  3. package/CHANGELOG.md +14 -0
  4. package/PRD.md +11 -11
  5. package/README.md +20 -2
  6. package/dist/cli/argv-utils.d.ts +5 -0
  7. package/dist/cli/argv-utils.js +34 -0
  8. package/dist/cli/argv-utils.js.map +1 -0
  9. package/dist/cli/bootstrap-args.d.ts +15 -0
  10. package/dist/cli/bootstrap-args.js +211 -0
  11. package/dist/cli/bootstrap-args.js.map +1 -1
  12. package/dist/cli/commander-usage.js +109 -3
  13. package/dist/cli/commander-usage.js.map +1 -1
  14. package/dist/cli/commands/completion.js +7 -3
  15. package/dist/cli/commands/completion.js.map +1 -1
  16. package/dist/cli/commands/contracts.d.ts +19 -0
  17. package/dist/cli/commands/contracts.js +40 -2
  18. package/dist/cli/commands/contracts.js.map +1 -1
  19. package/dist/cli/commands/create.js +112 -51
  20. package/dist/cli/commands/create.js.map +1 -1
  21. package/dist/cli/commands/docs.js +9 -2
  22. package/dist/cli/commands/docs.js.map +1 -1
  23. package/dist/cli/commands/extension.d.ts +12 -3
  24. package/dist/cli/commands/extension.js +421 -69
  25. package/dist/cli/commands/extension.js.map +1 -1
  26. package/dist/cli/commands/files.js +9 -2
  27. package/dist/cli/commands/files.js.map +1 -1
  28. package/dist/cli/commands/index.d.ts +1 -0
  29. package/dist/cli/commands/index.js +1 -0
  30. package/dist/cli/commands/index.js.map +1 -1
  31. package/dist/cli/commands/init.d.ts +2 -0
  32. package/dist/cli/commands/init.js +21 -1
  33. package/dist/cli/commands/init.js.map +1 -1
  34. package/dist/cli/commands/metadata-normalizers.d.ts +4 -0
  35. package/dist/cli/commands/metadata-normalizers.js +37 -0
  36. package/dist/cli/commands/metadata-normalizers.js.map +1 -0
  37. package/dist/cli/commands/reindex.js +173 -135
  38. package/dist/cli/commands/reindex.js.map +1 -1
  39. package/dist/cli/commands/search.js +16 -6
  40. package/dist/cli/commands/search.js.map +1 -1
  41. package/dist/cli/commands/test.js +23 -8
  42. package/dist/cli/commands/test.js.map +1 -1
  43. package/dist/cli/commands/update.js +70 -39
  44. package/dist/cli/commands/update.js.map +1 -1
  45. package/dist/cli/commands/upgrade.d.ts +63 -0
  46. package/dist/cli/commands/upgrade.js +260 -0
  47. package/dist/cli/commands/upgrade.js.map +1 -0
  48. package/dist/cli/error-guidance.d.ts +9 -1
  49. package/dist/cli/error-guidance.js +147 -6
  50. package/dist/cli/error-guidance.js.map +1 -1
  51. package/dist/cli/guide-topics.js +18 -16
  52. package/dist/cli/guide-topics.js.map +1 -1
  53. package/dist/cli/help-content.js +42 -2
  54. package/dist/cli/help-content.js.map +1 -1
  55. package/dist/cli/help-json-payload.js +11 -1
  56. package/dist/cli/help-json-payload.js.map +1 -1
  57. package/dist/cli/main.js +69 -6
  58. package/dist/cli/main.js.map +1 -1
  59. package/dist/cli/register-setup.js +174 -82
  60. package/dist/cli/register-setup.js.map +1 -1
  61. package/dist/cli/telemetry-flush.d.ts +2 -0
  62. package/dist/cli/telemetry-flush.js +4 -0
  63. package/dist/cli/telemetry-flush.js.map +1 -0
  64. package/dist/cli.js +1 -2
  65. package/dist/cli.js.map +1 -1
  66. package/dist/core/extensions/extension-types.d.ts +72 -0
  67. package/dist/core/extensions/extension-types.js +24 -0
  68. package/dist/core/extensions/extension-types.js.map +1 -1
  69. package/dist/core/extensions/loader.d.ts +1 -0
  70. package/dist/core/extensions/loader.js +766 -7
  71. package/dist/core/extensions/loader.js.map +1 -1
  72. package/dist/core/lock/lock.js +2 -0
  73. package/dist/core/lock/lock.js.map +1 -1
  74. package/dist/core/packages/manifest.d.ts +13 -0
  75. package/dist/core/packages/manifest.js +139 -0
  76. package/dist/core/packages/manifest.js.map +1 -0
  77. package/dist/core/sentry/instrument.d.ts +15 -0
  78. package/dist/core/sentry/instrument.js +35 -3
  79. package/dist/core/sentry/instrument.js.map +1 -1
  80. package/dist/core/shared/constants.js +20 -0
  81. package/dist/core/shared/constants.js.map +1 -1
  82. package/dist/core/shared/errors.d.ts +8 -0
  83. package/dist/core/shared/errors.js.map +1 -1
  84. package/dist/core/shared/levenshtein.d.ts +1 -0
  85. package/dist/core/shared/levenshtein.js +37 -0
  86. package/dist/core/shared/levenshtein.js.map +1 -0
  87. package/dist/core/store/paths.js +34 -1
  88. package/dist/core/store/paths.js.map +1 -1
  89. package/dist/core/store/settings.js +210 -1
  90. package/dist/core/store/settings.js.map +1 -1
  91. package/dist/core/telemetry/runtime.d.ts +1 -0
  92. package/dist/core/telemetry/runtime.js +102 -3
  93. package/dist/core/telemetry/runtime.js.map +1 -1
  94. package/dist/mcp/server.js +11 -2
  95. package/dist/mcp/server.js.map +1 -1
  96. package/dist/sdk/cli-contracts.d.ts +38 -17
  97. package/dist/sdk/cli-contracts.js +387 -35
  98. package/dist/sdk/cli-contracts.js.map +1 -1
  99. package/dist/sdk/index.d.ts +13 -1
  100. package/dist/sdk/index.js +9 -1
  101. package/dist/sdk/index.js.map +1 -1
  102. package/dist/types.d.ts +41 -0
  103. package/dist/types.js.map +1 -1
  104. package/docs/ARCHITECTURE.md +1 -1
  105. package/docs/CLAUDE_CODE_PLUGIN.md +39 -0
  106. package/docs/COMMANDS.md +14 -1
  107. package/docs/EXTENSIONS.md +782 -12
  108. package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
  109. package/docs/QUICKSTART.md +10 -2
  110. package/docs/README.md +4 -6
  111. package/docs/SDK.md +445 -0
  112. package/docs/examples/ci/github-actions-pm-extension-gate.yml +53 -0
  113. package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +41 -0
  114. package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +45 -0
  115. package/docs/examples/policy-restricted-extension/README.md +74 -0
  116. package/docs/examples/policy-restricted-extension/index.js +21 -0
  117. package/docs/examples/policy-restricted-extension/manifest.json +21 -0
  118. package/docs/examples/policy-restricted-extension/package.json +8 -0
  119. package/docs/examples/sdk-app-embedding/README.md +39 -0
  120. package/docs/examples/sdk-app-embedding/package.json +9 -0
  121. package/docs/examples/sdk-app-embedding/run-embedded-pm.mjs +61 -0
  122. package/docs/examples/sdk-contract-consumer/README.md +57 -0
  123. package/docs/examples/sdk-contract-consumer/inspect-contracts.mjs +47 -0
  124. package/docs/examples/sdk-contract-consumer/package.json +10 -0
  125. package/docs/examples/starter-extension/README.md +57 -42
  126. package/docs/examples/starter-extension/manifest.json +15 -0
  127. package/marketplace.json +3 -3
  128. package/package.json +5 -23
  129. package/packages/pm-beads/README.md +10 -0
  130. package/{.agents/pm → packages/pm-beads}/extensions/beads/index.js +24 -9
  131. package/packages/pm-beads/extensions/beads/index.ts +131 -0
  132. package/packages/pm-beads/package.json +17 -0
  133. package/packages/pm-todos/README.md +11 -0
  134. package/{.agents/pm → packages/pm-todos}/extensions/todos/index.js +24 -9
  135. package/packages/pm-todos/extensions/todos/index.ts +149 -0
  136. package/{.agents/pm → packages/pm-todos}/extensions/todos/runtime.js +1 -1
  137. package/{.agents/pm → packages/pm-todos}/extensions/todos/runtime.ts +1 -1
  138. package/packages/pm-todos/package.json +17 -0
  139. package/plugins/pm-cli-claude/.claude-plugin/plugin.json +2 -2
  140. package/plugins/pm-cli-claude/README.md +54 -14
  141. package/plugins/pm-cli-claude/agents/pm-delivery-chain.md +88 -0
  142. package/plugins/pm-cli-claude/agents/pm-triage-agent.md +83 -0
  143. package/plugins/pm-cli-claude/agents/pm-verification-agent.md +88 -0
  144. package/plugins/pm-cli-claude/hooks/session-start.mjs +35 -21
  145. package/.agents/pm/extensions/.managed-extensions.json +0 -42
  146. package/.agents/skills/HARNESS_COMPATIBILITY.md +0 -45
  147. package/.agents/skills/README.md +0 -21
  148. package/.agents/skills/pm-developer/SKILL.md +0 -73
  149. package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +0 -48
  150. package/.agents/skills/pm-developer/references/PROMPTS.md +0 -17
  151. package/.agents/skills/pm-extensions/SKILL.md +0 -57
  152. package/.agents/skills/pm-extensions/references/LIFECYCLE.md +0 -40
  153. package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +0 -25
  154. package/.agents/skills/pm-sdk/SKILL.md +0 -50
  155. package/.agents/skills/pm-sdk/references/INTEGRATION_CHECKLIST.md +0 -31
  156. package/.agents/skills/pm-sdk/references/PROMPTS.md +0 -13
  157. package/.agents/skills/pm-user/SKILL.md +0 -59
  158. package/.agents/skills/pm-user/references/PROMPTS.md +0 -17
  159. package/.agents/skills/pm-user/references/WORKFLOWS.md +0 -35
  160. package/.pi/README.md +0 -26
  161. package/.pi/extensions/pm-cli/index.js +0 -147
  162. package/.pi/prompts/pm-workflow.md +0 -5
  163. package/.pi/skills/pm-native/SKILL.md +0 -40
  164. package/.pi/skills/pm-release/SKILL.md +0 -35
  165. package/dist/pi/native.d.ts +0 -5
  166. package/dist/pi/native.js +0 -183
  167. package/dist/pi/native.js.map +0 -1
  168. package/docs/PI_PACKAGE.md +0 -56
  169. /package/{.agents/pm → packages/pm-beads}/extensions/beads/manifest.json +0 -0
  170. /package/{.agents/pm → packages/pm-beads}/extensions/beads/runtime.js +0 -0
  171. /package/{.agents/pm → packages/pm-beads}/extensions/beads/runtime.ts +0 -0
  172. /package/{.agents/pm → packages/pm-todos}/extensions/todos/manifest.json +0 -0
@@ -1,7 +1,8 @@
1
1
  import path from "node:path";
2
- import { pathToFileURL } from "node:url";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
3
 
4
4
  const PM_PACKAGE_ROOT_ENV = "PM_CLI_PACKAGE_ROOT";
5
+ const CURRENT_EXTENSION_ROOT = path.dirname(fileURLToPath(import.meta.url));
5
6
 
6
7
  export const manifest = {
7
8
  name: "builtin-beads-import",
@@ -48,17 +49,31 @@ function resolvePackageRootCandidates() {
48
49
  async function loadRuntimeModule() {
49
50
  const attempted = [];
50
51
  for (const packageRoot of resolvePackageRootCandidates()) {
51
- const modulePath = path.join(packageRoot, ".agents", "pm", "extensions", "beads", "runtime.js");
52
- attempted.push(modulePath);
53
- try {
54
- return await import(pathToFileURL(modulePath).href);
55
- } catch {
56
- // Try the next package-root candidate.
52
+ const modulePaths = [
53
+ path.join(packageRoot, ".agents", "pm", "extensions", "beads", "runtime.js"),
54
+ path.join(packageRoot, "packages", "pm-beads", "extensions", "beads", "runtime.js"),
55
+ ];
56
+ for (const modulePath of modulePaths) {
57
+ attempted.push(modulePath);
58
+ try {
59
+ return await import(pathToFileURL(modulePath).href);
60
+ } catch {
61
+ // Try the next package-root candidate.
62
+ }
57
63
  }
58
64
  }
65
+
66
+ const localRuntimePath = path.join(CURRENT_EXTENSION_ROOT, "runtime.js");
67
+ attempted.push(localRuntimePath);
68
+ try {
69
+ return await import(pathToFileURL(localRuntimePath).href);
70
+ } catch {
71
+ // Fall through to the diagnostic below.
72
+ }
73
+
59
74
  throw new Error(
60
- "Unable to resolve bundled beads extension runtime module. " +
61
- `Tried: ${attempted.join(", ")}. Ensure PM_CLI_PACKAGE_ROOT points to an installed pm package root.`,
75
+ "Unable to resolve packaged beads extension runtime module. " +
76
+ `Tried: ${attempted.join(", ")}. Ensure the installed extension includes runtime.js or PM_CLI_PACKAGE_ROOT points to an installed pm package root.`,
62
77
  );
63
78
  }
64
79
 
@@ -0,0 +1,131 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
+ import type { CommandDefinition, ExtensionApi } from "../../../../src/core/extensions/loader.js";
4
+ import type { GlobalOptions } from "../../../../src/core/shared/command-types.js";
5
+ import type { BeadsImportOptions, BeadsImportResult } from "./runtime.js";
6
+
7
+ const PM_PACKAGE_ROOT_ENV = "PM_CLI_PACKAGE_ROOT";
8
+ const CURRENT_EXTENSION_ROOT = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ export const manifest = {
11
+ name: "builtin-beads-import",
12
+ version: "0.1.0",
13
+ entry: "./index.js",
14
+ priority: 0,
15
+ capabilities: ["commands", "schema"],
16
+ };
17
+
18
+ type RuntimeModule = {
19
+ runBeadsImport?: (options: BeadsImportOptions, global: GlobalOptions) => Promise<BeadsImportResult>;
20
+ };
21
+
22
+ function asOptionalString(value: unknown): string | undefined {
23
+ return typeof value === "string" ? value : undefined;
24
+ }
25
+
26
+ function asBoolean(value: unknown): boolean | undefined {
27
+ return typeof value === "boolean" ? value : undefined;
28
+ }
29
+
30
+ function toBeadsImportOptions(options: Record<string, unknown>): BeadsImportOptions {
31
+ return {
32
+ file: asOptionalString(options.file),
33
+ author: asOptionalString(options.author),
34
+ message: asOptionalString(options.message),
35
+ preserveSourceIds: asBoolean(options.preserveSourceIds),
36
+ };
37
+ }
38
+
39
+ function resolvePackageRootCandidates(): string[] {
40
+ const candidates: string[] = [];
41
+ const envRoot = process.env[PM_PACKAGE_ROOT_ENV];
42
+ if (typeof envRoot === "string" && envRoot.trim().length > 0) {
43
+ candidates.push(path.resolve(envRoot.trim()));
44
+ }
45
+ const argvEntry = typeof process.argv[1] === "string" ? process.argv[1].trim() : "";
46
+ if (argvEntry.length > 0) {
47
+ const resolvedEntry = path.resolve(argvEntry);
48
+ const entryDir = path.dirname(resolvedEntry);
49
+ candidates.push(path.resolve(entryDir, ".."));
50
+ candidates.push(path.resolve(entryDir, "../.."));
51
+ candidates.push(path.resolve(entryDir, "../../.."));
52
+ }
53
+ return [...new Set(candidates)];
54
+ }
55
+
56
+ async function loadRuntimeModule(): Promise<RuntimeModule> {
57
+ const attempted: string[] = [];
58
+ for (const packageRoot of resolvePackageRootCandidates()) {
59
+ const modulePaths = [
60
+ path.join(packageRoot, ".agents", "pm", "extensions", "beads", "runtime.js"),
61
+ path.join(packageRoot, "packages", "pm-beads", "extensions", "beads", "runtime.js"),
62
+ ];
63
+ for (const modulePath of modulePaths) {
64
+ attempted.push(modulePath);
65
+ try {
66
+ return await import(pathToFileURL(modulePath).href) as RuntimeModule;
67
+ } catch {
68
+ // Try the next package-root candidate.
69
+ }
70
+ }
71
+ }
72
+
73
+ const localRuntimePath = path.join(CURRENT_EXTENSION_ROOT, "runtime.js");
74
+ attempted.push(localRuntimePath);
75
+ try {
76
+ return await import(pathToFileURL(localRuntimePath).href) as RuntimeModule;
77
+ } catch {
78
+ // Fall through to the diagnostic below.
79
+ }
80
+
81
+ throw new Error(
82
+ "Unable to resolve packaged beads extension runtime module. " +
83
+ `Tried: ${attempted.join(", ")}. Ensure the installed extension includes runtime.js or PM_CLI_PACKAGE_ROOT points to an installed pm package root.`,
84
+ );
85
+ }
86
+
87
+ async function runBeadsImportFromRuntime(options: BeadsImportOptions, global: GlobalOptions): Promise<BeadsImportResult> {
88
+ const runtime = await loadRuntimeModule();
89
+ if (typeof runtime.runBeadsImport !== "function") {
90
+ throw new Error("Bundled beads runtime module is missing runBeadsImport().");
91
+ }
92
+ return runtime.runBeadsImport(options, global);
93
+ }
94
+
95
+ export function activate(api: ExtensionApi): void {
96
+ api.registerCommand({
97
+ name: "beads import",
98
+ description: "Import Beads JSONL records into pm items.",
99
+ flags: [
100
+ {
101
+ long: "--file",
102
+ value_name: "path",
103
+ value_type: "string",
104
+ description: "Path to the Beads JSONL source file.",
105
+ },
106
+ {
107
+ long: "--author",
108
+ value_name: "author",
109
+ value_type: "string",
110
+ description: "Override import mutation author.",
111
+ },
112
+ {
113
+ long: "--message",
114
+ value_name: "text",
115
+ value_type: "string",
116
+ description: "Override import history message.",
117
+ },
118
+ {
119
+ long: "--preserve-source-ids",
120
+ value_type: "boolean",
121
+ description: "Preserve source IDs from Beads payload records when possible.",
122
+ },
123
+ ],
124
+ run: async (context) => runBeadsImportFromRuntime(toBeadsImportOptions(context.options), context.global),
125
+ } satisfies CommandDefinition);
126
+ }
127
+
128
+ export default {
129
+ manifest,
130
+ activate,
131
+ };
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@unbrained/pm-package-beads",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "First-party pm package for importing Beads JSONL records.",
7
+ "keywords": [
8
+ "pm-package",
9
+ "project-management",
10
+ "beads"
11
+ ],
12
+ "pm": {
13
+ "extensions": [
14
+ "extensions/beads"
15
+ ]
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ # pm Todos Package
2
+
3
+ First-party pm package for Todo markdown import and export.
4
+
5
+ ```bash
6
+ pm install ./packages/pm-todos --project
7
+ pm todos import --folder .pm/todos
8
+ pm todos export --folder .pm/todos
9
+ ```
10
+
11
+ The package exposes the `todos import` and `todos export` extension commands through the `pm.extensions` package manifest. Runtime sources are authored in TypeScript and shipped with JavaScript entry artifacts for Node extension loading.
@@ -1,7 +1,8 @@
1
1
  import path from "node:path";
2
- import { pathToFileURL } from "node:url";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
3
 
4
4
  const PM_PACKAGE_ROOT_ENV = "PM_CLI_PACKAGE_ROOT";
5
+ const CURRENT_EXTENSION_ROOT = path.dirname(fileURLToPath(import.meta.url));
5
6
 
6
7
  export const manifest = {
7
8
  name: "builtin-todos-import-export",
@@ -49,17 +50,31 @@ function resolvePackageRootCandidates() {
49
50
  async function loadRuntimeModule() {
50
51
  const attempted = [];
51
52
  for (const packageRoot of resolvePackageRootCandidates()) {
52
- const modulePath = path.join(packageRoot, ".agents", "pm", "extensions", "todos", "runtime.js");
53
- attempted.push(modulePath);
54
- try {
55
- return await import(pathToFileURL(modulePath).href);
56
- } catch {
57
- // Try the next package-root candidate.
53
+ const modulePaths = [
54
+ path.join(packageRoot, ".agents", "pm", "extensions", "todos", "runtime.js"),
55
+ path.join(packageRoot, "packages", "pm-todos", "extensions", "todos", "runtime.js"),
56
+ ];
57
+ for (const modulePath of modulePaths) {
58
+ attempted.push(modulePath);
59
+ try {
60
+ return await import(pathToFileURL(modulePath).href);
61
+ } catch {
62
+ // Try the next package-root candidate.
63
+ }
58
64
  }
59
65
  }
66
+
67
+ const localRuntimePath = path.join(CURRENT_EXTENSION_ROOT, "runtime.js");
68
+ attempted.push(localRuntimePath);
69
+ try {
70
+ return await import(pathToFileURL(localRuntimePath).href);
71
+ } catch {
72
+ // Fall through to the diagnostic below.
73
+ }
74
+
60
75
  throw new Error(
61
- "Unable to resolve bundled todos extension runtime module. " +
62
- `Tried: ${attempted.join(", ")}. Ensure PM_CLI_PACKAGE_ROOT points to an installed pm package root.`,
76
+ "Unable to resolve packaged todos extension runtime module. " +
77
+ `Tried: ${attempted.join(", ")}. Ensure the installed extension includes runtime.js or PM_CLI_PACKAGE_ROOT points to an installed pm package root.`,
63
78
  );
64
79
  }
65
80
 
@@ -0,0 +1,149 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
+ import type { CommandDefinition, ExtensionApi } from "../../../../src/core/extensions/loader.js";
4
+ import type { GlobalOptions } from "../../../../src/core/shared/command-types.js";
5
+ import type { TodosExportOptions, TodosExportResult, TodosImportOptions, TodosImportResult } from "./runtime.js";
6
+
7
+ const PM_PACKAGE_ROOT_ENV = "PM_CLI_PACKAGE_ROOT";
8
+ const CURRENT_EXTENSION_ROOT = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ export const manifest = {
11
+ name: "builtin-todos-import-export",
12
+ version: "0.1.0",
13
+ entry: "./index.js",
14
+ priority: 0,
15
+ capabilities: ["commands", "schema"],
16
+ };
17
+
18
+ type RuntimeModule = {
19
+ runTodosImport?: (options: TodosImportOptions, global: GlobalOptions) => Promise<TodosImportResult>;
20
+ runTodosExport?: (options: TodosExportOptions, global: GlobalOptions) => Promise<TodosExportResult>;
21
+ };
22
+
23
+ function asOptionalString(value: unknown): string | undefined {
24
+ return typeof value === "string" ? value : undefined;
25
+ }
26
+
27
+ function toImportOptions(options: Record<string, unknown>): TodosImportOptions {
28
+ return {
29
+ folder: asOptionalString(options.folder),
30
+ author: asOptionalString(options.author),
31
+ message: asOptionalString(options.message),
32
+ };
33
+ }
34
+
35
+ function toExportOptions(options: Record<string, unknown>): TodosExportOptions {
36
+ return {
37
+ folder: asOptionalString(options.folder),
38
+ };
39
+ }
40
+
41
+ function resolvePackageRootCandidates(): string[] {
42
+ const candidates: string[] = [];
43
+ const envRoot = process.env[PM_PACKAGE_ROOT_ENV];
44
+ if (typeof envRoot === "string" && envRoot.trim().length > 0) {
45
+ candidates.push(path.resolve(envRoot.trim()));
46
+ }
47
+ const argvEntry = typeof process.argv[1] === "string" ? process.argv[1].trim() : "";
48
+ if (argvEntry.length > 0) {
49
+ const resolvedEntry = path.resolve(argvEntry);
50
+ const entryDir = path.dirname(resolvedEntry);
51
+ candidates.push(path.resolve(entryDir, ".."));
52
+ candidates.push(path.resolve(entryDir, "../.."));
53
+ candidates.push(path.resolve(entryDir, "../../.."));
54
+ }
55
+ return [...new Set(candidates)];
56
+ }
57
+
58
+ async function loadRuntimeModule(): Promise<RuntimeModule> {
59
+ const attempted: string[] = [];
60
+ for (const packageRoot of resolvePackageRootCandidates()) {
61
+ const modulePaths = [
62
+ path.join(packageRoot, ".agents", "pm", "extensions", "todos", "runtime.js"),
63
+ path.join(packageRoot, "packages", "pm-todos", "extensions", "todos", "runtime.js"),
64
+ ];
65
+ for (const modulePath of modulePaths) {
66
+ attempted.push(modulePath);
67
+ try {
68
+ return await import(pathToFileURL(modulePath).href) as RuntimeModule;
69
+ } catch {
70
+ // Try the next package-root candidate.
71
+ }
72
+ }
73
+ }
74
+
75
+ const localRuntimePath = path.join(CURRENT_EXTENSION_ROOT, "runtime.js");
76
+ attempted.push(localRuntimePath);
77
+ try {
78
+ return await import(pathToFileURL(localRuntimePath).href) as RuntimeModule;
79
+ } catch {
80
+ // Fall through to the diagnostic below.
81
+ }
82
+
83
+ throw new Error(
84
+ "Unable to resolve packaged todos extension runtime module. " +
85
+ `Tried: ${attempted.join(", ")}. Ensure the installed extension includes runtime.js or PM_CLI_PACKAGE_ROOT points to an installed pm package root.`,
86
+ );
87
+ }
88
+
89
+ async function runTodosImportFromRuntime(options: TodosImportOptions, global: GlobalOptions): Promise<TodosImportResult> {
90
+ const runtime = await loadRuntimeModule();
91
+ if (typeof runtime.runTodosImport !== "function") {
92
+ throw new Error("Bundled todos runtime module is missing runTodosImport().");
93
+ }
94
+ return runtime.runTodosImport(options, global);
95
+ }
96
+
97
+ async function runTodosExportFromRuntime(options: TodosExportOptions, global: GlobalOptions): Promise<TodosExportResult> {
98
+ const runtime = await loadRuntimeModule();
99
+ if (typeof runtime.runTodosExport !== "function") {
100
+ throw new Error("Bundled todos runtime module is missing runTodosExport().");
101
+ }
102
+ return runtime.runTodosExport(options, global);
103
+ }
104
+
105
+ export function activate(api: ExtensionApi): void {
106
+ api.registerCommand({
107
+ name: "todos import",
108
+ description: "Import Todo markdown files into pm items.",
109
+ flags: [
110
+ {
111
+ long: "--folder",
112
+ value_name: "path",
113
+ value_type: "string",
114
+ description: "Source folder containing Todo markdown files.",
115
+ },
116
+ {
117
+ long: "--author",
118
+ value_name: "author",
119
+ value_type: "string",
120
+ description: "Override import mutation author.",
121
+ },
122
+ {
123
+ long: "--message",
124
+ value_name: "text",
125
+ value_type: "string",
126
+ description: "Override import history message.",
127
+ },
128
+ ],
129
+ run: async (context) => runTodosImportFromRuntime(toImportOptions(context.options), context.global),
130
+ } satisfies CommandDefinition);
131
+ api.registerCommand({
132
+ name: "todos export",
133
+ description: "Export pm items into Todo markdown files.",
134
+ flags: [
135
+ {
136
+ long: "--folder",
137
+ value_name: "path",
138
+ value_type: "string",
139
+ description: "Destination folder for exported Todo markdown files.",
140
+ },
141
+ ],
142
+ run: async (context) => runTodosExportFromRuntime(toExportOptions(context.options), context.global),
143
+ } satisfies CommandDefinition);
144
+ }
145
+
146
+ export default {
147
+ manifest,
148
+ activate,
149
+ };
@@ -16,7 +16,7 @@ import { listAllFrontMatter, locateItem, readLocatedItem } from "../../../../dis
16
16
  import { getHistoryPath, getItemPath, getSettingsPath, resolvePmRoot } from "../../../../dist/core/store/paths.js";
17
17
  import { readSettings } from "../../../../dist/core/store/settings.js";
18
18
  import { CONFIDENCE_TEXT_VALUES, ISSUE_SEVERITY_VALUES, RISK_VALUES } from "../../../../dist/types/index.js";
19
- const DEFAULT_TODOS_FOLDER = ".pi/todos";
19
+ const DEFAULT_TODOS_FOLDER = ".pm/todos";
20
20
  function isRecord(value) {
21
21
  return typeof value === "object" && value !== null && !Array.isArray(value);
22
22
  }
@@ -20,7 +20,7 @@ import { readSettings } from "../../../../src/core/store/settings.js";
20
20
  import { CONFIDENCE_TEXT_VALUES, ISSUE_SEVERITY_VALUES, RISK_VALUES } from "../../../../src/types/index.js";
21
21
  import type { ItemDocument, ItemMetadata, ItemStatus, ItemType, PmSettings } from "../../../../src/types/index.js";
22
22
 
23
- const DEFAULT_TODOS_FOLDER = ".pi/todos";
23
+ const DEFAULT_TODOS_FOLDER = ".pm/todos";
24
24
 
25
25
  export interface TodosImportOptions {
26
26
  folder?: string;
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@unbrained/pm-package-todos",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "First-party pm package for Todo markdown import and export.",
7
+ "keywords": [
8
+ "pm-package",
9
+ "project-management",
10
+ "todos"
11
+ ],
12
+ "pm": {
13
+ "extensions": [
14
+ "extensions/todos"
15
+ ]
16
+ }
17
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pm-cli",
3
- "description": "Native pm CLI integration for Claude Code — 18 MCP tools, 5 workflow skills, 14 slash commands, hybrid TUI task tracking (pm as persistent store + Claude Code task panel as live view), session context injection, and a coordination subagent for git-based project management without leaving Claude Code.",
4
- "version": "1.2.0",
3
+ "description": "Native pm CLI integration for Claude Code — 18 MCP tools, 5 workflow skills, 14 slash commands, 3 subagents (coordinator, triage, verification), hybrid TUI task tracking (pm as persistent store + Claude Code task panel as live view), session context injection, and full git-based project management without leaving Claude Code.",
4
+ "version": "1.3.0",
5
5
  "author": {
6
6
  "name": "unbrained",
7
7
  "url": "https://github.com/unbraind/pm-cli"
@@ -1,6 +1,6 @@
1
1
  # pm CLI — Claude Code Plugin
2
2
 
3
- Native pm CLI integration for Claude Code. Use pm project management tools directly through Claude Code's MCP protocol — no shell invocations, no context switching.
3
+ Native pm CLI integration for Claude Code. Use pm project management tools directly through Claude Code's MCP protocol — no shell invocations, no context switching, no `pm` CLI required.
4
4
 
5
5
  ## What's Included
6
6
 
@@ -9,29 +9,37 @@ Native pm CLI integration for Claude Code. Use pm project management tools direc
9
9
  | **18 MCP tools** | Full pm surface: context, search, list, get, create, update, claim, release, close, comments, files, docs, test, validate, health, contracts, guide + `pm_run` for everything else |
10
10
  | **5 skills** | `pm-workflow`, `pm-developer`, `pm-release`, `pm-audit`, `pm-planner` — auto-loaded as Claude Code skills |
11
11
  | **14 slash commands** | Full lifecycle coverage — status, start, close, triage, audit, search, new, list, calendar, developer, planner, release, workflow, init |
12
+ | **3 subagents** | `pm-coordinator` (batch/multi-item), `pm-triage-agent` (duplicate-safe item creation), `pm-verification-agent` (evidence + close readiness), and a `pm-delivery-chain` orchestrator |
12
13
  | **Hybrid TUI tracking** | pm items sync to Claude Code's task panel — pm is the persistent store, the task panel is the live session view |
13
- | **Session hook** | Injects active pm item summary at session start when pm is initialized |
14
- | **pm-coordinator agent** | Subagent for coordinating multi-item and batch operations |
14
+ | **Session hook** | Injects active pm item summary at session start when pm is initialized (uses native modules, no CLI required) |
15
15
 
16
16
  ## Installation
17
17
 
18
- ### Option A: Plugin marketplace (recommended)
18
+ ### Option A: Plugin marketplace — canonical install (recommended)
19
19
 
20
20
  ```
21
- /plugin install pm-cli@pm-cli
21
+ /plugin install pm-cli@pm
22
22
  ```
23
23
 
24
- This installs the plugin including all MCP tools, skills, slash commands, hybrid TUI tracking, and the session hook in one step.
25
-
26
- To add the marketplace first (if not already configured):
24
+ First time: add the marketplace if it's not configured yet:
27
25
 
28
26
  ```bash
29
27
  claude plugin marketplace add /path/to/pm-cli
30
- # or from GitHub:
28
+ # or after npm publish:
31
29
  # claude plugin marketplace add unbraind/pm-cli
32
30
  ```
33
31
 
34
- ### Option B: Global MCP server via Claude Code CLI (MCP tools only)
32
+ This installs all 18 MCP tools, 5 skills, 14 slash commands, 3 subagents, hybrid TUI tracking, and the session hook in one step.
33
+
34
+ ### Option B: Legacy marketplace alias (also works)
35
+
36
+ ```
37
+ /plugin install pm-cli@pm-cli
38
+ ```
39
+
40
+ Both `pm` and `pm-cli` marketplace IDs resolve to the same plugin.
41
+
42
+ ### Option C: Global MCP server via Claude Code CLI (MCP tools only)
35
43
 
36
44
  ```bash
37
45
  claude mcp add --transport stdio pm-cli-native -- npx -y @unbrained/pm-cli pm-mcp
@@ -39,9 +47,9 @@ claude mcp add --transport stdio pm-cli-native -- npx -y @unbrained/pm-cli pm-mc
39
47
 
40
48
  This gives you the 18 MCP tools but not the skills, slash commands, or session hook.
41
49
 
42
- ### Option C: Direct `.mcp.json` (project-scoped MCP only)
50
+ ### Option D: Direct `.mcp.json` (project-scoped MCP only)
43
51
 
44
- Add to your project's `.mcp.json` for MCP tools in a single project:
52
+ Add to your project's `.mcp.json`:
45
53
 
46
54
  ```json
47
55
  {
@@ -70,6 +78,9 @@ Start working on the authentication bug.
70
78
 
71
79
  Close pm-xxxx — the fix is complete.
72
80
  → Claude runs /pm-close-task pm-xxxx with evidence linking, closes pm item, marks task panel entry completed
81
+
82
+ Triage this request: add dark mode toggle to settings screen
83
+ → Claude spawns pm-triage-agent, checks duplicates, creates pm item with AC, hands off to /pm-developer
73
84
  ```
74
85
 
75
86
  ## Hybrid TUI Task Tracking
@@ -116,6 +127,20 @@ This means you get full history in pm (survives restarts, visible in `pm list`)
116
127
  | `pm-audit` | Repository health audits — validate, dedupe, aggregate |
117
128
  | `pm-planner` | Planning — decompose epics, prioritize backlog, triage |
118
129
 
130
+ ## Subagents
131
+
132
+ | Agent | Role |
133
+ |-------|------|
134
+ | `pm-coordinator` | Multi-item and batch coordination — batch updates, audit workflows, release gate sequences |
135
+ | `pm-triage-agent` | Duplicate-safe item creation — orient, search, establish lineage, produce implementation-ready item |
136
+ | `pm-verification-agent` | Closure evidence — read item, check AC, run tests, validate, produce structured close recommendation |
137
+ | `pm-delivery-chain` | End-to-end orchestrator — runs triage → implement → verify as a single tracked loop |
138
+
139
+ Use subagents via Claude Code's built-in `Agent` tool:
140
+ ```
141
+ Spawn pm-triage-agent to set up the pm item for: add OAuth2 login support
142
+ ```
143
+
119
144
  ## MCP Tools Reference
120
145
 
121
146
  ### Narrow tools (prefer these)
@@ -163,6 +188,21 @@ All skills and commands implement this pattern for every claimed item:
163
188
  → [✔ appears in Claude Code task panel]
164
189
  ```
165
190
 
191
+ ## Session Context Injection
192
+
193
+ At session start, the hook runs natively (no `pm` CLI required):
194
+ - Uses `npx @unbrained/pm-cli` without requiring a global install
195
+ - Injects a compact summary of in-progress/open/blocked items
196
+
197
+ Example output:
198
+ ```
199
+ pm tracker: 2 in_progress, 1 open
200
+ • [pm-abc1] Add OAuth2 login (in_progress)
201
+ • [pm-abc2] Fix test flakiness (in_progress)
202
+ • [pm-abc3] Update docs (open)
203
+ Use pm_context tool or /pm-status for full details.
204
+ ```
205
+
166
206
  ## Safety
167
207
 
168
208
  - Never pass `path` during real repository tracking — only use it for sandbox/test runs.
@@ -173,12 +213,12 @@ All skills and commands implement this pattern for every claimed item:
173
213
  ## Requirements
174
214
 
175
215
  - Node.js ≥ 20
176
- - pm CLI available via npx (auto-resolved) or installed globally: `npm install -g @unbrained/pm-cli`
216
+ - pm CLI resolved automatically via local dist (in repo) or `npx @unbrained/pm-cli` (no global install needed)
177
217
  - Project initialized with `pm init` (or use `/pm-init`)
178
218
 
179
219
  ## Links
180
220
 
181
221
  - [pm CLI docs](https://github.com/unbraind/pm-cli/tree/main/docs)
182
- - [Command reference](https://github.com/unbraind/pm-cli/blob/main/docs/COMMANDS.md)
183
222
  - [Architecture guide](https://github.com/unbraind/pm-cli/blob/main/docs/ARCHITECTURE.md)
223
+ - [Extension guide](https://github.com/unbraind/pm-cli/blob/main/docs/EXTENSIONS.md)
184
224
  - [CHANGELOG](https://github.com/unbraind/pm-cli/blob/main/CHANGELOG.md)