@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.
- package/.claude-plugin/marketplace.json +4 -4
- package/.pi/README.md +10 -1
- package/.pi/agents/pm-triage-agent.md +19 -0
- package/.pi/agents/pm-verification-agent.md +21 -0
- package/.pi/chains/pm-native-delivery.chain.md +11 -0
- package/.pi/extensions/pm-cli/index.js +276 -36
- package/.pi/skills/pm-native/SKILL.md +6 -2
- package/CHANGELOG.md +7 -0
- package/README.md +9 -1
- package/dist/cli/argv-utils.d.ts +5 -0
- package/dist/cli/argv-utils.js +34 -0
- package/dist/cli/argv-utils.js.map +1 -0
- package/dist/cli/bootstrap-args.d.ts +15 -0
- package/dist/cli/bootstrap-args.js +211 -0
- package/dist/cli/bootstrap-args.js.map +1 -1
- package/dist/cli/commander-usage.js +109 -3
- package/dist/cli/commander-usage.js.map +1 -1
- package/dist/cli/commands/completion.js +7 -3
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/contracts.d.ts +19 -0
- package/dist/cli/commands/contracts.js +33 -1
- package/dist/cli/commands/contracts.js.map +1 -1
- package/dist/cli/commands/create.js +112 -51
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/docs.js +9 -2
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.d.ts +3 -1
- package/dist/cli/commands/extension.js +174 -2
- package/dist/cli/commands/extension.js.map +1 -1
- package/dist/cli/commands/files.js +9 -2
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.js +21 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/metadata-normalizers.d.ts +4 -0
- package/dist/cli/commands/metadata-normalizers.js +37 -0
- package/dist/cli/commands/metadata-normalizers.js.map +1 -0
- package/dist/cli/commands/reindex.js +173 -135
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/search.js +16 -6
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/test.js +9 -2
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update.js +70 -39
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/error-guidance.d.ts +9 -1
- package/dist/cli/error-guidance.js +147 -6
- package/dist/cli/error-guidance.js.map +1 -1
- package/dist/cli/help-json-payload.js +11 -1
- package/dist/cli/help-json-payload.js.map +1 -1
- package/dist/cli/main.js +69 -6
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/register-setup.js +14 -0
- package/dist/cli/register-setup.js.map +1 -1
- package/dist/cli/telemetry-flush.d.ts +2 -0
- package/dist/cli/telemetry-flush.js +4 -0
- package/dist/cli/telemetry-flush.js.map +1 -0
- package/dist/cli.js +1 -2
- package/dist/cli.js.map +1 -1
- package/dist/core/extensions/extension-types.d.ts +72 -0
- package/dist/core/extensions/extension-types.js +24 -0
- package/dist/core/extensions/extension-types.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -0
- package/dist/core/extensions/loader.js +766 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/lock/lock.js +2 -0
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/sentry/instrument.d.ts +15 -0
- package/dist/core/sentry/instrument.js +35 -3
- package/dist/core/sentry/instrument.js.map +1 -1
- package/dist/core/shared/constants.js +20 -0
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.d.ts +8 -0
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/levenshtein.d.ts +1 -0
- package/dist/core/shared/levenshtein.js +37 -0
- package/dist/core/shared/levenshtein.js.map +1 -0
- package/dist/core/store/paths.js +34 -1
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.js +210 -1
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/runtime.d.ts +1 -0
- package/dist/core/telemetry/runtime.js +102 -3
- package/dist/core/telemetry/runtime.js.map +1 -1
- package/dist/mcp/server.js +3 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/pi/native.js +57 -4
- package/dist/pi/native.js.map +1 -1
- package/dist/sdk/cli-contracts.d.ts +21 -1
- package/dist/sdk/cli-contracts.js +250 -0
- package/dist/sdk/cli-contracts.js.map +1 -1
- package/dist/sdk/index.d.ts +12 -1
- package/dist/sdk/index.js +8 -1
- package/dist/sdk/index.js.map +1 -1
- package/dist/types.d.ts +41 -0
- package/dist/types.js.map +1 -1
- package/docs/CLAUDE_CODE_PLUGIN.md +39 -0
- package/docs/EXTENSIONS.md +687 -0
- package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
- package/docs/PI_PACKAGE.md +95 -10
- package/docs/SDK.md +441 -0
- package/docs/examples/ci/github-actions-pm-extension-gate.yml +53 -0
- package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +41 -0
- package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +45 -0
- package/docs/examples/policy-restricted-extension/README.md +74 -0
- package/docs/examples/policy-restricted-extension/index.js +21 -0
- package/docs/examples/policy-restricted-extension/manifest.json +21 -0
- package/docs/examples/policy-restricted-extension/package.json +8 -0
- package/docs/examples/sdk-app-embedding/README.md +39 -0
- package/docs/examples/sdk-app-embedding/package.json +9 -0
- package/docs/examples/sdk-app-embedding/run-embedded-pm.mjs +61 -0
- package/docs/examples/sdk-contract-consumer/README.md +57 -0
- package/docs/examples/sdk-contract-consumer/inspect-contracts.mjs +47 -0
- package/docs/examples/sdk-contract-consumer/package.json +10 -0
- package/docs/examples/starter-extension/README.md +57 -42
- package/docs/examples/starter-extension/manifest.json +15 -0
- package/marketplace.json +3 -3
- package/package.json +1 -1
- package/plugins/pm-cli-claude/.claude-plugin/plugin.json +2 -2
- package/plugins/pm-cli-claude/README.md +55 -14
- package/plugins/pm-cli-claude/agents/pm-delivery-chain.md +88 -0
- package/plugins/pm-cli-claude/agents/pm-triage-agent.md +83 -0
- package/plugins/pm-cli-claude/agents/pm-verification-agent.md +88 -0
- package/plugins/pm-cli-claude/hooks/session-start.mjs +87 -22
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "pm
|
|
2
|
+
"name": "pm",
|
|
3
3
|
"owner": {
|
|
4
4
|
"name": "unbrained",
|
|
5
5
|
"url": "https://github.com/unbraind/pm-cli"
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.3.0"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "pm-cli",
|
|
14
14
|
"source": "./plugins/pm-cli-claude",
|
|
15
|
-
"description": "Native pm CLI integration for Claude Code — 18 MCP tools, workflow skills, slash commands, session context injection, and
|
|
16
|
-
"version": "1.
|
|
15
|
+
"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.",
|
|
16
|
+
"version": "1.3.0",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "unbrained",
|
|
19
19
|
"url": "https://github.com/unbraind/pm-cli"
|
package/.pi/README.md
CHANGED
|
@@ -19,8 +19,17 @@ pi -e .
|
|
|
19
19
|
|
|
20
20
|
Resources exposed by `package.json`:
|
|
21
21
|
|
|
22
|
-
- `.pi/extensions/pm-cli/index.js` — native Pi extension registering the `pm` tool and slash commands.
|
|
22
|
+
- `.pi/extensions/pm-cli/index.js` — native Pi extension registering the `pm` tool, custom TUI renderers, autocomplete, status/widget UI, and slash commands.
|
|
23
23
|
- `.pi/skills/*` — Pi skills for native pm workflows and release validation.
|
|
24
24
|
- `.pi/prompts/*` — prompt templates for pm-tracked work.
|
|
25
|
+
- `.pi/agents/*` and `.pi/chains/*` — optional pi-subagents setup for pm triage and verification workflows in repositories that use subagents.
|
|
25
26
|
|
|
26
27
|
The extension imports the built package from `dist/`, so run `pnpm build` before local install or before publishing.
|
|
28
|
+
|
|
29
|
+
Interactive commands:
|
|
30
|
+
|
|
31
|
+
- `/pm-board [limit]` — dashboard panel for active pm context.
|
|
32
|
+
- `/pm-item <id>` and `/pm-history <id>` — item details/history panels.
|
|
33
|
+
- `/pm-actions` and `/pm-workflows` — native action list and workflow reminders.
|
|
34
|
+
|
|
35
|
+
The `pm` tool should be preferred over shelling out to `pm`; it calls pm command modules directly in-process.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pm-triage-agent
|
|
3
|
+
description: Native pm triage agent for Pi. Use to inspect context, search for duplicates, select or create tracker lineage, and hand off an implementation-ready pm item without shelling out to the pm CLI.
|
|
4
|
+
tools: pm,read,grep,find,ls
|
|
5
|
+
skills: pm-native,pm-user
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# pm Triage Agent
|
|
9
|
+
|
|
10
|
+
Use the native `pm` tool only for pm operations.
|
|
11
|
+
|
|
12
|
+
Workflow:
|
|
13
|
+
1. Run `pm` action `context` with `limit: 10`.
|
|
14
|
+
2. Run `pm` action `search` with the user's key terms.
|
|
15
|
+
3. Run `pm` actions `list-open` and `list-in-progress`.
|
|
16
|
+
4. If an item exists, recommend reusing it and claim/start only when asked.
|
|
17
|
+
5. If no item exists, identify parent lineage and propose a create payload with duplicate-check evidence.
|
|
18
|
+
|
|
19
|
+
Output a concise handoff with item id, rationale, recommended next action, and exact native `pm` tool calls.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pm-verification-agent
|
|
3
|
+
description: Native pm verification agent for Pi. Use to inspect linked files/tests/docs, run sandbox-safe linked tests through pm, validate close readiness, and produce closure evidence.
|
|
4
|
+
tools: pm,bash,read,grep,find,ls
|
|
5
|
+
skills: pm-native,pm-release
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# pm Verification Agent
|
|
9
|
+
|
|
10
|
+
Use the native `pm` tool for pm mutations and linked-test orchestration.
|
|
11
|
+
Use bash only for non-pm project commands such as `pnpm build` or `gh run list`.
|
|
12
|
+
|
|
13
|
+
Workflow:
|
|
14
|
+
1. Read the target item with `pm` action `get`.
|
|
15
|
+
2. Check linked files/docs/tests and acceptance criteria.
|
|
16
|
+
3. Run `pm` action `test` with `run: true` or equivalent linked-test options when available.
|
|
17
|
+
4. Run targeted project validation requested by the parent.
|
|
18
|
+
5. Add a `pm` comment summarizing evidence.
|
|
19
|
+
6. Recommend close/release only if verification is clean.
|
|
20
|
+
|
|
21
|
+
Output failures with exact commands, item id, and next remediation step.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pm-native-delivery
|
|
3
|
+
description: Triage, implement, and verify a pm-tracked change using native pm operations in Pi.
|
|
4
|
+
steps:
|
|
5
|
+
- agent: pm-triage-agent
|
|
6
|
+
task: "Triage the requested work and identify the canonical pm item for: {task}"
|
|
7
|
+
- agent: worker
|
|
8
|
+
task: "Implement the approved scope from the triage handoff. Use native pm for tracker operations, link changed files/tests/docs, and keep edits scoped. Original request: {task}\n\nTriage handoff:\n{previous}"
|
|
9
|
+
- agent: pm-verification-agent
|
|
10
|
+
task: "Verify the implementation and produce pm closure evidence. Original request: {task}\n\nImplementation handoff:\n{previous}"
|
|
11
|
+
---
|
|
@@ -1,32 +1,9 @@
|
|
|
1
|
-
import { PM_TOOL_ACTIONS } from "../../../dist/sdk/cli-contracts.js";
|
|
1
|
+
import { PM_PI_TOOL_PARAMETERS_SCHEMA, PM_TOOL_ACTIONS } from "../../../dist/sdk/cli-contracts.js";
|
|
2
2
|
import { runNativePmAction } from "../../../dist/pi/native.js";
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const PM_PI_TOOL_PARAMETERS_SCHEMA_COMPAT = {
|
|
5
|
+
...PM_PI_TOOL_PARAMETERS_SCHEMA,
|
|
6
6
|
additionalProperties: true,
|
|
7
|
-
required: ["action"],
|
|
8
|
-
description: "Parameters for the native pm Pi tool. Extra properties are forwarded to the selected pm action.",
|
|
9
|
-
properties: {
|
|
10
|
-
action: {
|
|
11
|
-
type: "string",
|
|
12
|
-
description: "pm action to execute, for example context, search, get, create, update, files, docs, test, validate, or close-task.",
|
|
13
|
-
},
|
|
14
|
-
id: { type: "string", description: "pm item id for item-scoped actions." },
|
|
15
|
-
text: { type: "string", description: "Text payload for comment-like actions or close reasons." },
|
|
16
|
-
title: { type: "string", description: "Title for create actions." },
|
|
17
|
-
description: { type: "string", description: "Description for create/update actions." },
|
|
18
|
-
query: { type: "string", description: "Search query text." },
|
|
19
|
-
limit: { type: "string", description: "Result limit. Numeric strings are accepted." },
|
|
20
|
-
author: { type: "string", description: "Explicit pm author for mutations." },
|
|
21
|
-
path: { type: "string", description: "pm data path override or linked file path, depending on action." },
|
|
22
|
-
scope: { type: "string", description: "Link scope such as project." },
|
|
23
|
-
command: { type: "string", description: "Linked test command or shell completion target, depending on action." },
|
|
24
|
-
options: {
|
|
25
|
-
type: "object",
|
|
26
|
-
additionalProperties: true,
|
|
27
|
-
description: "Advanced command options object forwarded to the selected pm action.",
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
7
|
};
|
|
31
8
|
|
|
32
9
|
function contentText(result) {
|
|
@@ -34,6 +11,155 @@ function contentText(result) {
|
|
|
34
11
|
return JSON.stringify(result, null, 2);
|
|
35
12
|
}
|
|
36
13
|
|
|
14
|
+
function firstText(result) {
|
|
15
|
+
const entry = Array.isArray(result?.content) ? result.content.find((part) => part?.type === "text") : undefined;
|
|
16
|
+
return typeof entry?.text === "string" ? entry.text : "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function truncatePlain(value, width) {
|
|
20
|
+
const text = String(value ?? "");
|
|
21
|
+
let visible = 0;
|
|
22
|
+
let output = "";
|
|
23
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
24
|
+
const char = text[index];
|
|
25
|
+
if (char === "\u001b") {
|
|
26
|
+
const match = text.slice(index).match(/^\u001b\[[0-9;?]*[ -/]*[@-~]/);
|
|
27
|
+
if (match) {
|
|
28
|
+
output += match[0];
|
|
29
|
+
index += match[0].length - 1;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (visible >= Math.max(0, width - 1)) return `${output}…`;
|
|
34
|
+
output += char;
|
|
35
|
+
visible += 1;
|
|
36
|
+
}
|
|
37
|
+
return output;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function statusIcon(status, theme) {
|
|
41
|
+
const normalized = String(status ?? "").toLowerCase();
|
|
42
|
+
if (normalized === "closed") return theme.fg("success", "✓");
|
|
43
|
+
if (normalized === "blocked") return theme.fg("warning", "!");
|
|
44
|
+
if (normalized === "in_progress") return theme.fg("accent", "▶");
|
|
45
|
+
if (normalized === "canceled") return theme.fg("dim", "×");
|
|
46
|
+
return theme.fg("dim", "○");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class PmPanelComponent {
|
|
50
|
+
constructor(title, lines, theme, onClose) {
|
|
51
|
+
this.title = title;
|
|
52
|
+
this.lines = lines;
|
|
53
|
+
this.theme = theme;
|
|
54
|
+
this.onClose = onClose;
|
|
55
|
+
this.cachedWidth = undefined;
|
|
56
|
+
this.cachedLines = undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
handleInput(data) {
|
|
60
|
+
if (data === "\u001b" || data === "\u0003" || data === "q" || data === "Q") {
|
|
61
|
+
this.onClose?.();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
render(width) {
|
|
66
|
+
if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
|
|
67
|
+
const theme = this.theme;
|
|
68
|
+
const usable = Math.max(20, width);
|
|
69
|
+
const border = theme.fg("borderMuted", "─".repeat(Math.max(0, usable)));
|
|
70
|
+
const rendered = [
|
|
71
|
+
border,
|
|
72
|
+
truncatePlain(`${theme.fg("accent", theme.bold(` pm ${this.title} `))}${theme.fg("dim", "q/esc closes")}`, usable),
|
|
73
|
+
border,
|
|
74
|
+
...this.lines.map((line) => truncatePlain(line, usable)),
|
|
75
|
+
border,
|
|
76
|
+
];
|
|
77
|
+
this.cachedWidth = width;
|
|
78
|
+
this.cachedLines = rendered;
|
|
79
|
+
return rendered;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
invalidate() {
|
|
83
|
+
this.cachedWidth = undefined;
|
|
84
|
+
this.cachedLines = undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function makeItemLine(item, theme) {
|
|
89
|
+
const id = theme.fg("accent", item.id ?? "unknown");
|
|
90
|
+
const type = theme.fg("muted", item.type ?? "Item");
|
|
91
|
+
const status = statusIcon(item.status, theme);
|
|
92
|
+
const priority = item.priority === undefined ? "" : theme.fg("dim", ` p${item.priority}`);
|
|
93
|
+
const owner = item.assignee ? theme.fg("dim", ` @${item.assignee}`) : "";
|
|
94
|
+
return `${status} ${id} ${type}${priority}${owner} ${item.title ?? "(untitled)"}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function contextLines(result, theme) {
|
|
98
|
+
const lines = [];
|
|
99
|
+
const summary = result?.summary;
|
|
100
|
+
if (summary) {
|
|
101
|
+
lines.push(
|
|
102
|
+
`${theme.fg("muted", "summary")} active=${summary.active_items ?? 0} open=${summary.open ?? 0} in_progress=${summary.in_progress ?? 0} blocked=${summary.blocked ?? 0}`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const high = Array.isArray(result?.high_level) ? result.high_level : [];
|
|
106
|
+
const low = Array.isArray(result?.low_level) ? result.low_level : [];
|
|
107
|
+
if (high.length > 0) {
|
|
108
|
+
lines.push("", theme.fg("accent", "High level"));
|
|
109
|
+
lines.push(...high.map((item) => makeItemLine(item, theme)));
|
|
110
|
+
}
|
|
111
|
+
if (low.length > 0) {
|
|
112
|
+
lines.push("", theme.fg("accent", "Tasks"));
|
|
113
|
+
lines.push(...low.map((item) => makeItemLine(item, theme)));
|
|
114
|
+
}
|
|
115
|
+
if (lines.length === 0) lines.push(theme.fg("dim", "No pm context items found."));
|
|
116
|
+
return lines;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function listLines(result, theme) {
|
|
120
|
+
const items = Array.isArray(result?.items) ? result.items : Array.isArray(result) ? result : [];
|
|
121
|
+
if (items.length === 0) return [theme.fg("dim", "No items.")];
|
|
122
|
+
return items.map((entry) => makeItemLine(entry.item ?? entry, theme));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function historyLines(result, theme) {
|
|
126
|
+
const entries = Array.isArray(result?.history) ? result.history : Array.isArray(result?.entries) ? result.entries : [];
|
|
127
|
+
if (entries.length === 0) return [theme.fg("dim", "No history entries.")];
|
|
128
|
+
return entries.slice(0, 30).map((entry) => {
|
|
129
|
+
const at = entry.timestamp ?? entry.created_at ?? "";
|
|
130
|
+
const op = entry.op ?? entry.operation ?? entry.type ?? "history";
|
|
131
|
+
const author = entry.author ? ` ${theme.fg("dim", `@${entry.author}`)}` : "";
|
|
132
|
+
const message = entry.message ?? entry.text ?? entry.reason ?? "";
|
|
133
|
+
return `${theme.fg("muted", at)} ${theme.fg("accent", op)}${author} ${message}`;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function getItemLines(result, theme) {
|
|
138
|
+
const item = result?.item ?? result;
|
|
139
|
+
if (!item || typeof item !== "object") return [theme.fg("dim", "No item details.")];
|
|
140
|
+
const lines = [makeItemLine(item, theme)];
|
|
141
|
+
if (item.description) lines.push("", item.description);
|
|
142
|
+
if (item.acceptance_criteria) lines.push("", `${theme.fg("accent", "Acceptance")}: ${item.acceptance_criteria}`);
|
|
143
|
+
if (Array.isArray(item.comments) && item.comments.length > 0) {
|
|
144
|
+
lines.push("", theme.fg("accent", "Recent comments"));
|
|
145
|
+
for (const comment of item.comments.slice(-5)) {
|
|
146
|
+
lines.push(`${theme.fg("muted", comment.created_at ?? "")} ${comment.author ?? "unknown"}: ${comment.text ?? ""}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return lines;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function resultLines(details, theme) {
|
|
153
|
+
const action = details?.action;
|
|
154
|
+
const result = details?.result;
|
|
155
|
+
if (action === "context") return contextLines(result, theme);
|
|
156
|
+
if (String(action ?? "").startsWith("list") || action === "search") return listLines(result, theme);
|
|
157
|
+
if (action === "history" || action === "activity") return historyLines(result, theme);
|
|
158
|
+
if (action === "get") return getItemLines(result, theme);
|
|
159
|
+
const raw = contentText(result);
|
|
160
|
+
return raw.split("\n").slice(0, 40);
|
|
161
|
+
}
|
|
162
|
+
|
|
37
163
|
function errorDetails(error) {
|
|
38
164
|
return {
|
|
39
165
|
message: error instanceof Error ? error.message : String(error),
|
|
@@ -41,19 +167,42 @@ function errorDetails(error) {
|
|
|
41
167
|
};
|
|
42
168
|
}
|
|
43
169
|
|
|
170
|
+
function uiTheme(ctx) {
|
|
171
|
+
return ctx.ui?.theme ?? {
|
|
172
|
+
fg: (_name, text) => String(text),
|
|
173
|
+
bold: (text) => String(text),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function showPanel(ctx, title, lines, overlay = true) {
|
|
178
|
+
if (!ctx.hasUI || typeof ctx.ui?.custom !== "function") {
|
|
179
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
await ctx.ui.custom((_tui, theme, _keybindings, done) => new PmPanelComponent(title, lines, theme, () => done(undefined)), {
|
|
183
|
+
overlay,
|
|
184
|
+
overlayOptions: { anchor: "right-center", width: "70%", minWidth: 60, maxHeight: "85%", margin: 1 },
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function runForCommand(ctx, params) {
|
|
189
|
+
return runNativePmAction({ cwd: ctx.cwd, ...params });
|
|
190
|
+
}
|
|
191
|
+
|
|
44
192
|
export function createPmToolDefinition() {
|
|
45
193
|
return {
|
|
46
194
|
name: "pm",
|
|
47
195
|
label: "pm",
|
|
48
196
|
description:
|
|
49
|
-
"Use pm natively from Pi without shelling out to the pm CLI. Supports pm project context, search, lifecycle mutations, links, tests, validation, extension management, templates, calendar,
|
|
197
|
+
"Use pm natively from Pi without shelling out to the pm CLI. Supports pm project context, search, lifecycle mutations, links, tests, validation, extension management, templates, calendar, guide, audit, beads, todos, and managed test-run workflows.",
|
|
50
198
|
promptSnippet: "Run native pm project-management operations without bash or the pm CLI.",
|
|
51
199
|
promptGuidelines: [
|
|
52
200
|
"Use the pm tool instead of bash pm commands for project-management operations when this tool is available.",
|
|
53
201
|
"Use pm action=context/list-open/list-in-progress/search before creating new work items.",
|
|
54
202
|
"For mutations, set author explicitly and link changed files/tests/docs through pm actions before closing work.",
|
|
203
|
+
"Use pm action=contracts or guide when you need exact action/flag support instead of guessing parameters.",
|
|
55
204
|
],
|
|
56
|
-
parameters:
|
|
205
|
+
parameters: PM_PI_TOOL_PARAMETERS_SCHEMA_COMPAT,
|
|
57
206
|
async execute(_toolCallId, params, _signal, onUpdate, ctx) {
|
|
58
207
|
onUpdate?.({ content: [{ type: "text", text: `Running native pm action: ${params.action}` }] });
|
|
59
208
|
try {
|
|
@@ -67,6 +216,20 @@ export function createPmToolDefinition() {
|
|
|
67
216
|
throw new Error(`pm ${params.action ?? "action"} failed: ${details.message}`);
|
|
68
217
|
}
|
|
69
218
|
},
|
|
219
|
+
renderCall(args, theme) {
|
|
220
|
+
const action = args?.action ?? "action";
|
|
221
|
+
const target = args?.id ?? args?.query ?? args?.target ?? args?.title ?? "";
|
|
222
|
+
return new PmPanelComponent("tool", [`${theme.fg("toolTitle", theme.bold("pm"))} ${theme.fg("accent", action)} ${theme.fg("dim", target)}`], theme);
|
|
223
|
+
},
|
|
224
|
+
renderResult(result, { expanded, isPartial }, theme) {
|
|
225
|
+
if (isPartial) return new PmPanelComponent("running", [theme.fg("warning", "Running…")], theme);
|
|
226
|
+
const details = result?.details;
|
|
227
|
+
if (!details?.ok) return new PmPanelComponent("result", [firstText(result) || contentText(result)], theme);
|
|
228
|
+
const lines = resultLines(details, theme);
|
|
229
|
+
const visible = expanded ? lines : lines.slice(0, 12);
|
|
230
|
+
if (!expanded && lines.length > visible.length) visible.push(theme.fg("dim", `… ${lines.length - visible.length} more; expand tool output for details`));
|
|
231
|
+
return new PmPanelComponent(String(details.action ?? "result"), visible, theme);
|
|
232
|
+
},
|
|
70
233
|
};
|
|
71
234
|
}
|
|
72
235
|
|
|
@@ -75,8 +238,38 @@ export function registerPmCommands(pi) {
|
|
|
75
238
|
description: "Show pm context snapshot using the native pm integration",
|
|
76
239
|
handler: async (args, ctx) => {
|
|
77
240
|
const limit = args?.trim() || "10";
|
|
78
|
-
const result = await
|
|
79
|
-
ctx
|
|
241
|
+
const result = await runForCommand(ctx, { action: "context", limit, json: true });
|
|
242
|
+
await showPanel(ctx, "context", contextLines(result, uiTheme(ctx)));
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
pi.registerCommand("pm-board", {
|
|
247
|
+
description: "Open an interactive pm dashboard panel: /pm-board [limit]",
|
|
248
|
+
handler: async (args, ctx) => {
|
|
249
|
+
const limit = args?.trim() || "12";
|
|
250
|
+
const result = await runForCommand(ctx, { action: "context", limit, depth: "standard", json: true });
|
|
251
|
+
await showPanel(ctx, "board", contextLines(result, uiTheme(ctx)));
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
pi.registerCommand("pm-item", {
|
|
256
|
+
description: "Open pm item details: /pm-item <id>",
|
|
257
|
+
getArgumentCompletions: () => null,
|
|
258
|
+
handler: async (args, ctx) => {
|
|
259
|
+
const id = args?.trim();
|
|
260
|
+
if (!id) return ctx.ui.notify("Usage: /pm-item <id>", "error");
|
|
261
|
+
const result = await runForCommand(ctx, { action: "get", id, json: true });
|
|
262
|
+
await showPanel(ctx, id, getItemLines(result, uiTheme(ctx)));
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
pi.registerCommand("pm-history", {
|
|
267
|
+
description: "Open pm item history/activity panel: /pm-history <id>",
|
|
268
|
+
handler: async (args, ctx) => {
|
|
269
|
+
const id = args?.trim();
|
|
270
|
+
if (!id) return ctx.ui.notify("Usage: /pm-history <id>", "error");
|
|
271
|
+
const result = await runForCommand(ctx, { action: "history", id, limit: 30, json: true });
|
|
272
|
+
await showPanel(ctx, `${id} history`, historyLines(result, uiTheme(ctx)));
|
|
80
273
|
},
|
|
81
274
|
});
|
|
82
275
|
|
|
@@ -85,7 +278,7 @@ export function registerPmCommands(pi) {
|
|
|
85
278
|
handler: async (args, ctx) => {
|
|
86
279
|
const id = args?.trim();
|
|
87
280
|
if (!id) return ctx.ui.notify("Usage: /pm-start <id>", "error");
|
|
88
|
-
const result = await
|
|
281
|
+
const result = await runForCommand(ctx, { action: "start-task", id, author: "pi-agent" });
|
|
89
282
|
ctx.ui.notify(contentText(result), "success");
|
|
90
283
|
},
|
|
91
284
|
});
|
|
@@ -96,7 +289,7 @@ export function registerPmCommands(pi) {
|
|
|
96
289
|
const [id, ...reasonParts] = (args ?? "").trim().split(/\s+/);
|
|
97
290
|
const reason = reasonParts.join(" ");
|
|
98
291
|
if (!id || !reason) return ctx.ui.notify("Usage: /pm-close <id> <reason>", "error");
|
|
99
|
-
const result = await
|
|
292
|
+
const result = await runForCommand(ctx, { action: "close-task", id, text: reason, author: "pi-agent", validateClose: "warn" });
|
|
100
293
|
ctx.ui.notify(contentText(result), "success");
|
|
101
294
|
},
|
|
102
295
|
});
|
|
@@ -104,7 +297,21 @@ export function registerPmCommands(pi) {
|
|
|
104
297
|
pi.registerCommand("pm-actions", {
|
|
105
298
|
description: "List native pm tool actions",
|
|
106
299
|
handler: async (_args, ctx) => {
|
|
107
|
-
ctx
|
|
300
|
+
await showPanel(ctx, "actions", PM_TOOL_ACTIONS.map((action) => `• ${action}`));
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
pi.registerCommand("pm-workflows", {
|
|
305
|
+
description: "Show native pm workflow shortcuts and bundled Pi resources",
|
|
306
|
+
handler: async (_args, ctx) => {
|
|
307
|
+
await showPanel(ctx, "workflows", [
|
|
308
|
+
"1. /pm-board to inspect focus/context items.",
|
|
309
|
+
"2. Use the pm tool action=search/list-open/list-in-progress before creating work.",
|
|
310
|
+
"3. /pm-start <id> or pm action=start-task to claim and move in_progress.",
|
|
311
|
+
"4. Use pm action=files/docs/test to link implementation evidence.",
|
|
312
|
+
"5. Run pm action=test/validate and close with pm action=close-task.",
|
|
313
|
+
"Bundled resources: pm-native and pm-release skills, pm-workflow prompt, pm subagent templates in .pi/agents.",
|
|
314
|
+
]);
|
|
108
315
|
},
|
|
109
316
|
});
|
|
110
317
|
}
|
|
@@ -122,14 +329,14 @@ function patchPmToolParametersInProviderPayload(payload) {
|
|
|
122
329
|
const parameters = tool.parameters;
|
|
123
330
|
if (!parameters || parameters.type !== "object") {
|
|
124
331
|
changed = true;
|
|
125
|
-
return { ...tool, parameters:
|
|
332
|
+
return { ...tool, parameters: PM_PI_TOOL_PARAMETERS_SCHEMA_COMPAT };
|
|
126
333
|
}
|
|
127
334
|
}
|
|
128
335
|
if (tool.function?.name === "pm") {
|
|
129
336
|
const parameters = tool.function.parameters;
|
|
130
337
|
if (!parameters || parameters.type !== "object") {
|
|
131
338
|
changed = true;
|
|
132
|
-
return { ...tool, function: { ...tool.function, parameters:
|
|
339
|
+
return { ...tool, function: { ...tool.function, parameters: PM_PI_TOOL_PARAMETERS_SCHEMA_COMPAT } };
|
|
133
340
|
}
|
|
134
341
|
}
|
|
135
342
|
return tool;
|
|
@@ -137,11 +344,44 @@ function patchPmToolParametersInProviderPayload(payload) {
|
|
|
137
344
|
return changed ? { ...payload, tools } : undefined;
|
|
138
345
|
}
|
|
139
346
|
|
|
347
|
+
function installPmAutocomplete(ctx) {
|
|
348
|
+
if (typeof ctx.ui?.addAutocompleteProvider !== "function") return;
|
|
349
|
+
ctx.ui.addAutocompleteProvider((current) => ({
|
|
350
|
+
async getSuggestions(lines, line, col, options) {
|
|
351
|
+
const beforeCursor = (lines[line] ?? "").slice(0, col);
|
|
352
|
+
const match = beforeCursor.match(/(?:^|[\s(])@(pm-[a-z0-9-]*)$/i);
|
|
353
|
+
if (!match) return current.getSuggestions(lines, line, col, options);
|
|
354
|
+
try {
|
|
355
|
+
const result = await runNativePmAction({ cwd: ctx.cwd, action: "list-open", limit: 20, json: true });
|
|
356
|
+
const items = Array.isArray(result?.items) ? result.items : [];
|
|
357
|
+
return {
|
|
358
|
+
prefix: `@${match[1] ?? ""}`,
|
|
359
|
+
items: items.map((item) => ({ value: `@${item.id}`, label: item.id, description: item.title ?? item.status ?? "pm item" })),
|
|
360
|
+
};
|
|
361
|
+
} catch {
|
|
362
|
+
return current.getSuggestions(lines, line, col, options);
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
applyCompletion(lines, line, col, item, prefix) {
|
|
366
|
+
return current.applyCompletion(lines, line, col, item, prefix);
|
|
367
|
+
},
|
|
368
|
+
shouldTriggerFileCompletion(lines, line, col) {
|
|
369
|
+
return current.shouldTriggerFileCompletion?.(lines, line, col) ?? true;
|
|
370
|
+
},
|
|
371
|
+
}));
|
|
372
|
+
}
|
|
373
|
+
|
|
140
374
|
export default function pmCliPiExtension(pi) {
|
|
141
375
|
pi.registerTool(createPmToolDefinition());
|
|
142
376
|
pi.on("before_provider_request", (event) => patchPmToolParametersInProviderPayload(event.payload));
|
|
143
377
|
registerPmCommands(pi);
|
|
144
378
|
pi.on("session_start", async (_event, ctx) => {
|
|
145
|
-
ctx.ui.setStatus?.("pm", "pm native");
|
|
379
|
+
ctx.ui.setStatus?.("pm", ctx.ui.theme?.fg ? ctx.ui.theme.fg("accent", "pm native") : "pm native");
|
|
380
|
+
ctx.ui.setWidget?.("pm-native", ["pm native ready • /pm-board • /pm-actions • @pm-id autocomplete"], { placement: "belowEditor" });
|
|
381
|
+
installPmAutocomplete(ctx);
|
|
382
|
+
});
|
|
383
|
+
pi.on("session_shutdown", async (_event, ctx) => {
|
|
384
|
+
ctx.ui.setStatus?.("pm", undefined);
|
|
385
|
+
ctx.ui.setWidget?.("pm-native", undefined);
|
|
146
386
|
});
|
|
147
387
|
}
|
|
@@ -11,7 +11,7 @@ metadata:
|
|
|
11
11
|
|
|
12
12
|
# pm Native for Pi
|
|
13
13
|
|
|
14
|
-
Use the `pm` tool for project-management operations. Do not run `pm ...` through bash when the native tool is available.
|
|
14
|
+
Use the `pm` tool for project-management operations. Do not run `pm ...` through bash when the native tool is available. In interactive Pi, use `/pm-board`, `/pm-item <id>`, `/pm-history <id>`, `/pm-actions`, and `/pm-workflows` when the user would benefit from seeing tracker state in the TUI.
|
|
15
15
|
|
|
16
16
|
## Required Loop
|
|
17
17
|
|
|
@@ -27,6 +27,7 @@ Use the `pm` tool for project-management operations. Do not run `pm ...` through
|
|
|
27
27
|
- action `test` with sandbox-safe commands
|
|
28
28
|
5. Verify with action `test`, `validate`, and project test commands when appropriate.
|
|
29
29
|
6. Close with action `close-task` or `close`, then release if needed.
|
|
30
|
+
7. For exact feature support, call `pm` action `contracts` or `guide` instead of guessing flags.
|
|
30
31
|
|
|
31
32
|
## Common Tool Calls
|
|
32
33
|
|
|
@@ -36,5 +37,8 @@ Use the `pm` tool for project-management operations. Do not run `pm ...` through
|
|
|
36
37
|
- Link file: `{ "action": "files", "id": "pm-1234", "add": ["path=src/file.ts,scope=project,note=implementation"], "author": "pi-agent" }`
|
|
37
38
|
- Add comment: `{ "action": "comments", "id": "pm-1234", "add": ["Evidence: build and tests passed"], "author": "pi-agent" }`
|
|
38
39
|
- Close: `{ "action": "close-task", "id": "pm-1234", "text": "All acceptance criteria met", "author": "pi-agent", "validateClose": "warn" }`
|
|
40
|
+
- Extension lifecycle: `{ "action": "extension", "install": true, "target": "todos", "scope": "project" }`
|
|
41
|
+
- Templates: `{ "action": "templates-list" }`
|
|
42
|
+
- Managed tests: `{ "action": "test-runs-list" }`
|
|
39
43
|
|
|
40
|
-
Use `pm guide` topics through action `guide` for deeper command docs.
|
|
44
|
+
Use `pm guide` topics through action `guide` for deeper command docs. The bundled Pi package also provides project subagent definitions (`pm-triage-agent`, `pm-verification-agent`) and a `pm-native-delivery` chain for installations that use pi-subagents.
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2026.5.11] - 2026-05-11
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Claude Code plugin v1.3.0: added `pm-triage-agent`, `pm-verification-agent`, and `pm-delivery-chain` subagents for full end-to-end pm workflow orchestration without leaving Claude Code.
|
|
14
|
+
- Claude Code plugin: registered `pm` as the canonical marketplace ID so the plugin installs via `/plugin install pm-cli@pm` (both `pm` and `pm-cli` marketplace IDs resolve to the same plugin).
|
|
15
|
+
- Claude Code plugin: rewrote session-start hook to use native `dist/pi/native.js` modules when available (repo checkout), falling back to `npx @unbrained/pm-cli` — no global `pm` CLI required.
|
|
16
|
+
|
|
10
17
|
## [2026.5.10] - 2026-05-10
|
|
11
18
|
|
|
12
19
|
### Changed
|
package/README.md
CHANGED
|
@@ -51,13 +51,21 @@ Project-local invocation also works:
|
|
|
51
51
|
npx @unbrained/pm-cli --help
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
For Claude Code, install the native plugin (no `pm` CLI required):
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
/plugin install pm-cli@pm
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This registers 18 MCP tools, 5 workflow skills, 14 slash commands, 3 subagents, hybrid TUI tracking, and a session-start context hook — all without shelling out to the `pm` CLI.
|
|
61
|
+
|
|
54
62
|
For Pi, install the native package integration after publish:
|
|
55
63
|
|
|
56
64
|
```bash
|
|
57
65
|
pi install npm:@unbrained/pm-cli
|
|
58
66
|
```
|
|
59
67
|
|
|
60
|
-
This registers a native `pm` tool, Pi skills,
|
|
68
|
+
This registers a native `pm` tool, custom TUI panels/renderers (`/pm-board`, `/pm-item`, `/pm-history`), Pi skills, prompt templates, and optional pi-subagents setup without requiring Pi to run the `pm` shell command.
|
|
61
69
|
|
|
62
70
|
## 60 Second Example
|
|
63
71
|
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function normalizeLongFlag(flag: string): string;
|
|
2
|
+
export declare function normalizeLongOptionFlag(token: string): string | undefined;
|
|
3
|
+
export declare function extractProvidedOptionFlags(argv: string[]): string[];
|
|
4
|
+
export declare function quoteCommandArg(arg: string): string;
|
|
5
|
+
export declare function renderPmCommand(argv: string[]): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function normalizeLongFlag(flag) {
|
|
2
|
+
return `--${flag
|
|
3
|
+
.replace(/^--?/, "")
|
|
4
|
+
.replace(/_/g, "-")
|
|
5
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
6
|
+
.toLowerCase()}`;
|
|
7
|
+
}
|
|
8
|
+
export function normalizeLongOptionFlag(token) {
|
|
9
|
+
if (!token.startsWith("--")) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const key = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
|
|
13
|
+
return normalizeLongFlag(key);
|
|
14
|
+
}
|
|
15
|
+
export function extractProvidedOptionFlags(argv) {
|
|
16
|
+
const provided = new Set();
|
|
17
|
+
for (const token of argv) {
|
|
18
|
+
const normalized = normalizeLongOptionFlag(token);
|
|
19
|
+
if (normalized) {
|
|
20
|
+
provided.add(normalized);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return [...provided].sort((left, right) => left.localeCompare(right));
|
|
24
|
+
}
|
|
25
|
+
export function quoteCommandArg(arg) {
|
|
26
|
+
if (/^[A-Za-z0-9._:/@=-]+$/.test(arg)) {
|
|
27
|
+
return arg;
|
|
28
|
+
}
|
|
29
|
+
return `"${arg.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
30
|
+
}
|
|
31
|
+
export function renderPmCommand(argv) {
|
|
32
|
+
return `pm ${argv.map((token) => quoteCommandArg(token)).join(" ")}`;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=argv-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"argv-utils.js","sourceRoot":"/","sources":["cli/argv-utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,KAAK,IAAI;SACb,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;SACnB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;SAClB,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,WAAW,EAAE,EAAE,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7E,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,IAAc;IACvD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,UAAU,EAAE,CAAC;YACf,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACvE,CAAC","sourcesContent":["export function normalizeLongFlag(flag: string): string {\n return `--${flag\n .replace(/^--?/, \"\")\n .replace(/_/g, \"-\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .toLowerCase()}`;\n}\n\nexport function normalizeLongOptionFlag(token: string): string | undefined {\n if (!token.startsWith(\"--\")) {\n return undefined;\n }\n const key = token.includes(\"=\") ? token.slice(0, token.indexOf(\"=\")) : token;\n return normalizeLongFlag(key);\n}\n\nexport function extractProvidedOptionFlags(argv: string[]): string[] {\n const provided = new Set<string>();\n for (const token of argv) {\n const normalized = normalizeLongOptionFlag(token);\n if (normalized) {\n provided.add(normalized);\n }\n }\n return [...provided].sort((left, right) => left.localeCompare(right));\n}\n\nexport function quoteCommandArg(arg: string): string {\n if (/^[A-Za-z0-9._:/@=-]+$/.test(arg)) {\n return arg;\n }\n return `\"${arg.replace(/([\"\\\\$`])/g, \"\\\\$1\")}\"`;\n}\n\nexport function renderPmCommand(argv: string[]): string {\n return `pm ${argv.map((token) => quoteCommandArg(token)).join(\" \")}`;\n}\n"]}
|
|
@@ -15,4 +15,19 @@ export declare function parseBootstrapHelpRequest(argv: string[]): BootstrapHelp
|
|
|
15
15
|
export declare function parseBootstrapCommandName(argv: string[]): string | undefined;
|
|
16
16
|
export declare function applyBootstrapPagerPolicy(argv: string[]): void;
|
|
17
17
|
export declare function normalizeLegacyExtensionActionSyntax(argv: string[]): string[];
|
|
18
|
+
type BootstrapNormalizationReason = "legacy_extension_action" | "flag_alias" | "flag_typo" | "bare_key_value";
|
|
19
|
+
type BootstrapNormalizationConfidence = "high" | "medium";
|
|
20
|
+
export interface BootstrapNormalizationEvent {
|
|
21
|
+
from: string;
|
|
22
|
+
to: string[];
|
|
23
|
+
reason: BootstrapNormalizationReason;
|
|
24
|
+
confidence: BootstrapNormalizationConfidence;
|
|
25
|
+
}
|
|
26
|
+
export interface BootstrapInvocationNormalizationResult {
|
|
27
|
+
argv: string[];
|
|
28
|
+
commandName: string | undefined;
|
|
29
|
+
trace: BootstrapNormalizationEvent[];
|
|
30
|
+
}
|
|
31
|
+
export declare function normalizeBootstrapInvocation(argv: string[]): BootstrapInvocationNormalizationResult;
|
|
18
32
|
export declare function parseBootstrapTypeValue(argv: string[]): string | undefined;
|
|
33
|
+
export {};
|