@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.
- package/.claude-plugin/marketplace.json +4 -4
- package/AGENTS.md +3 -116
- package/CHANGELOG.md +14 -0
- package/PRD.md +11 -11
- package/README.md +20 -2
- 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 +40 -2
- 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 +12 -3
- package/dist/cli/commands/extension.js +421 -69
- 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/index.d.ts +1 -0
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/index.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 +23 -8
- 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/commands/upgrade.d.ts +63 -0
- package/dist/cli/commands/upgrade.js +260 -0
- package/dist/cli/commands/upgrade.js.map +1 -0
- 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/guide-topics.js +18 -16
- package/dist/cli/guide-topics.js.map +1 -1
- package/dist/cli/help-content.js +42 -2
- package/dist/cli/help-content.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 +174 -82
- 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/packages/manifest.d.ts +13 -0
- package/dist/core/packages/manifest.js +139 -0
- package/dist/core/packages/manifest.js.map +1 -0
- 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 +11 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/sdk/cli-contracts.d.ts +38 -17
- package/dist/sdk/cli-contracts.js +387 -35
- package/dist/sdk/cli-contracts.js.map +1 -1
- package/dist/sdk/index.d.ts +13 -1
- package/dist/sdk/index.js +9 -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/ARCHITECTURE.md +1 -1
- package/docs/CLAUDE_CODE_PLUGIN.md +39 -0
- package/docs/COMMANDS.md +14 -1
- package/docs/EXTENSIONS.md +782 -12
- package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
- package/docs/QUICKSTART.md +10 -2
- package/docs/README.md +4 -6
- package/docs/SDK.md +445 -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 +5 -23
- package/packages/pm-beads/README.md +10 -0
- package/{.agents/pm → packages/pm-beads}/extensions/beads/index.js +24 -9
- package/packages/pm-beads/extensions/beads/index.ts +131 -0
- package/packages/pm-beads/package.json +17 -0
- package/packages/pm-todos/README.md +11 -0
- package/{.agents/pm → packages/pm-todos}/extensions/todos/index.js +24 -9
- package/packages/pm-todos/extensions/todos/index.ts +149 -0
- package/{.agents/pm → packages/pm-todos}/extensions/todos/runtime.js +1 -1
- package/{.agents/pm → packages/pm-todos}/extensions/todos/runtime.ts +1 -1
- package/packages/pm-todos/package.json +17 -0
- package/plugins/pm-cli-claude/.claude-plugin/plugin.json +2 -2
- package/plugins/pm-cli-claude/README.md +54 -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 +35 -21
- package/.agents/pm/extensions/.managed-extensions.json +0 -42
- package/.agents/skills/HARNESS_COMPATIBILITY.md +0 -45
- package/.agents/skills/README.md +0 -21
- package/.agents/skills/pm-developer/SKILL.md +0 -73
- package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +0 -48
- package/.agents/skills/pm-developer/references/PROMPTS.md +0 -17
- package/.agents/skills/pm-extensions/SKILL.md +0 -57
- package/.agents/skills/pm-extensions/references/LIFECYCLE.md +0 -40
- package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +0 -25
- package/.agents/skills/pm-sdk/SKILL.md +0 -50
- package/.agents/skills/pm-sdk/references/INTEGRATION_CHECKLIST.md +0 -31
- package/.agents/skills/pm-sdk/references/PROMPTS.md +0 -13
- package/.agents/skills/pm-user/SKILL.md +0 -59
- package/.agents/skills/pm-user/references/PROMPTS.md +0 -17
- package/.agents/skills/pm-user/references/WORKFLOWS.md +0 -35
- package/.pi/README.md +0 -26
- package/.pi/extensions/pm-cli/index.js +0 -147
- package/.pi/prompts/pm-workflow.md +0 -5
- package/.pi/skills/pm-native/SKILL.md +0 -40
- package/.pi/skills/pm-release/SKILL.md +0 -35
- package/dist/pi/native.d.ts +0 -5
- package/dist/pi/native.js +0 -183
- package/dist/pi/native.js.map +0 -1
- package/docs/PI_PACKAGE.md +0 -56
- /package/{.agents/pm → packages/pm-beads}/extensions/beads/manifest.json +0 -0
- /package/{.agents/pm → packages/pm-beads}/extensions/beads/runtime.js +0 -0
- /package/{.agents/pm → packages/pm-beads}/extensions/beads/runtime.ts +0 -0
- /package/{.agents/pm → packages/pm-todos}/extensions/todos/manifest.json +0 -0
|
@@ -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/AGENTS.md
CHANGED
|
@@ -321,120 +321,7 @@ Recover previous state:
|
|
|
321
321
|
pm restore pm-a1b2 2026-02-17T11:15:03.120Z
|
|
322
322
|
```
|
|
323
323
|
|
|
324
|
-
## 9)
|
|
325
|
-
|
|
326
|
-
The built-in Pi wrapper exposes one tool: `pm`.
|
|
327
|
-
Reference implementation source lives at `.pi/extensions/pm-cli/index.ts` as a Pi agent extension module.
|
|
328
|
-
`pm install` has been removed; install bundled managed runtime extensions via `pm extension --install beads|todos` (or explicit `.agents/pm/extensions/<name>` paths) when needed.
|
|
329
|
-
Load the Pi wrapper in Pi with `pi -e ./.pi/extensions/pm-cli/index.ts` (or copy it into your Pi extensions directory).
|
|
330
|
-
Use `action: "completion"` with `shell: "bash"|"zsh"|"fish"` to forward to `pm completion <shell>`.
|
|
331
|
-
Use `action: "calendar"` for date-centric event views (`view`, `date`, `from`, `to`, `past`, `fullPeriod`, `type`, `tag`, `priority`, `status`, `assignee`, `sprint`, `release`, `limit`, `format`).
|
|
332
|
-
Use `action: "aggregate"` for grouped decomposition checks (`groupBy`, `count`, `includeUnparented`, list-style filters).
|
|
333
|
-
Use `action: "dedupe-audit"` for duplicate corpus checks (`mode`, `threshold`, `limit`, list-style filters).
|
|
334
|
-
Use `action: "normalize"` for lifecycle metadata hygiene scans (`dryRun`) and explicit apply mode (`apply`) with list-style filter targeting.
|
|
335
|
-
Use `action: "validate"` with optional check toggles (`checkMetadata`, `checkResolution`, `checkFiles`, `checkHistoryDrift`) and optional `scanMode` (`default|tracked-all`) for standalone audit workflows.
|
|
336
|
-
Use `action: "extension-doctor"` for consolidated extension diagnostics with optional `scope` and `detail` (`summary|deep`).
|
|
337
|
-
For `list*` wrapper actions, use projection/sort controls (`compact`, `fields`, `sort`, `order`) plus `includeBody` when body projection is needed.
|
|
338
|
-
For `comments-audit`, use governance filters (`parent`, `tag`, `sprint`, `release`, `priority`) in addition to status/type/assignee filters.
|
|
339
|
-
For `health`, use vector refresh controls (`checkOnly`, `noRefresh`, `refreshVectors`) while keeping strict flags available (`strictDirectories`, `strictExit`, `failOnWarn`).
|
|
340
|
-
For `create` and `update`, use camelCase wrapper parameters for the canonical CLI scalar fields such as `parent`, `reviewer`, `risk`, `confidence`, `sprint`, `release`, `blockedBy`, `blockedReason`, `unblockNote`, `definitionOfReady`, `order`, `goal`, `objective`, `value`, `impact`, `outcome`, `whyNow`, `reporter`, `severity`, `environment`, `reproSteps`, `resolution`, `expectedResult`, `actualResult`, `affectedVersion`, `fixedVersion`, `component`, `regression`, and `customerImpact`; use `createMode` (`strict|progressive`) when staged creation is needed, `appendStable` for minimal-diff file-link appends, `allowAuditUpdate` for ownership-safe metadata-only non-owner updates, `allowAuditDepUpdate` for ownership-safe dependency-only non-owner updates, `allowAuditComment` for additive non-owner comment writes, repeatable `reminder` values for persistent reminders (`at=<iso|relative>,text=<text>`), and repeatable `typeOption` values for custom type metadata.
|
|
341
|
-
For `contracts`, use projection controls (`flagsOnly`, `availabilityOnly`) when you need narrow machine-readable payloads; with `command` selected, contract output is command-scoped by default.
|
|
342
|
-
For `completion`, use `eagerTags` only when embedding static tags in generated scripts is required; default generated scripts resolve tags lazily at runtime.
|
|
343
|
-
For `activity`, use `id`, `op`, `author`, `from`, `to`, `limit`, and `stream` (`rows|ndjson|jsonl` or boolean true) for deterministic timeline filtering/export.
|
|
344
|
-
For `test` and `test-all`, prefer explicit runtime parity/strictness parameters when needed: `pmContext` (`schema|tracker|auto`), `checkContext`, `autoPmContext`, `failOnContextMismatch`, `failOnSkipped`, and `requireAssertionsForPm`.
|
|
345
|
-
For `gc`, use `dryRun` and repeatable `gcScope` (`index`, `embeddings`, `runtime`) for no-side-effect previews and targeted cleanup.
|
|
346
|
-
|
|
347
|
-
### Example: list open tasks
|
|
348
|
-
|
|
349
|
-
```json
|
|
350
|
-
{
|
|
351
|
-
"action": "list-open",
|
|
352
|
-
"limit": 10
|
|
353
|
-
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
### Example: create item
|
|
357
|
-
|
|
358
|
-
```json
|
|
359
|
-
{
|
|
360
|
-
"action": "create",
|
|
361
|
-
"title": "Implement extension loader",
|
|
362
|
-
"description": "Load global and project extensions with precedence.",
|
|
363
|
-
"type": "Feature",
|
|
364
|
-
"status": "open",
|
|
365
|
-
"priority": 1,
|
|
366
|
-
"tags": "extensions,core",
|
|
367
|
-
"body": "",
|
|
368
|
-
"deadline": "+14d",
|
|
369
|
-
"estimate": 120,
|
|
370
|
-
"acceptanceCriteria": "Loader applies deterministic precedence for core global and project extensions.",
|
|
371
|
-
"author": "maintainer-agent",
|
|
372
|
-
"message": "Create extension loader task",
|
|
373
|
-
"assignee": "maintainer-agent",
|
|
374
|
-
"parent": "pm-epic01",
|
|
375
|
-
"reviewer": "maintainer-reviewer",
|
|
376
|
-
"risk": "medium",
|
|
377
|
-
"confidence": "high",
|
|
378
|
-
"sprint": "maintainer-loop",
|
|
379
|
-
"release": "v0.1",
|
|
380
|
-
"blockedBy": "pm-arch-review",
|
|
381
|
-
"blockedReason": "Awaiting architecture sign-off",
|
|
382
|
-
"unblockNote": "Resume implementation once review notes are resolved",
|
|
383
|
-
"reporter": "maintainer-agent",
|
|
384
|
-
"severity": "medium",
|
|
385
|
-
"environment": "cli",
|
|
386
|
-
"reproSteps": "Create conflicting extension registrations across project/global scopes",
|
|
387
|
-
"resolution": "Apply deterministic precedence in extension loader bootstrap",
|
|
388
|
-
"expectedResult": "Loader applies project-over-global precedence deterministically",
|
|
389
|
-
"actualResult": "Registration order currently varies by load path",
|
|
390
|
-
"affectedVersion": "v0.1",
|
|
391
|
-
"fixedVersion": "v0.2",
|
|
392
|
-
"component": "extension-host",
|
|
393
|
-
"regression": "false",
|
|
394
|
-
"customerImpact": "Unpredictable extension behavior increases operator overhead",
|
|
395
|
-
"definitionOfReady": "Extension loading behavior is clarified in docs.",
|
|
396
|
-
"order": 1,
|
|
397
|
-
"goal": "Release-hardening",
|
|
398
|
-
"objective": "Ship deterministic extension loading",
|
|
399
|
-
"value": "Makes extension behavior predictable for agents and humans",
|
|
400
|
-
"impact": "Reduces configuration and precedence drift",
|
|
401
|
-
"outcome": "Extension loader applies deterministic precedence",
|
|
402
|
-
"whyNow": "Extension loading is foundational for the remaining roadmap",
|
|
403
|
-
"dep": ["id=pm-epic01,kind=parent,author=maintainer-agent,created_at=now"],
|
|
404
|
-
"comment": ["author=maintainer-agent,created_at=now,text=Why this task exists align extension load precedence behavior."],
|
|
405
|
-
"note": ["author=maintainer-agent,created_at=now,text=Initial implementation plan wire loader in runtime bootstrap."],
|
|
406
|
-
"learning": [],
|
|
407
|
-
"linkedFile": ["path=src/core/extensions/loader.ts,scope=project,note=planned implementation file"],
|
|
408
|
-
"linkedTest": ["command=node scripts/run-tests.mjs test,scope=project,timeout_seconds=240,note=sandbox-safe regression"],
|
|
409
|
-
"doc": ["path=docs/ARCHITECTURE.md,scope=project,note=implementation reference"]
|
|
410
|
-
}
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
### Example: append body update
|
|
414
|
-
|
|
415
|
-
```json
|
|
416
|
-
{
|
|
417
|
-
"action": "append",
|
|
418
|
-
"id": "pm-a1b2",
|
|
419
|
-
"body": "Implemented lock TTL and stale lock override."
|
|
420
|
-
}
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
Expected wrapper return shape:
|
|
424
|
-
|
|
425
|
-
```json
|
|
426
|
-
{
|
|
427
|
-
"content": [
|
|
428
|
-
{ "type": "text", "text": "..." }
|
|
429
|
-
],
|
|
430
|
-
"details": {
|
|
431
|
-
"action": "create",
|
|
432
|
-
"item": {}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
## 10) Multi-Agent Etiquette
|
|
324
|
+
## 9) Multi-Agent Etiquette
|
|
438
325
|
|
|
439
326
|
- Claim before heavy edits.
|
|
440
327
|
- Release when blocked or context-switching.
|
|
@@ -442,7 +329,7 @@ Expected wrapper return shape:
|
|
|
442
329
|
- Avoid silent force-claim unless policy allows and conflict is stale.
|
|
443
330
|
- Keep item descriptions stable; append details in body/notes/comments.
|
|
444
331
|
|
|
445
|
-
##
|
|
332
|
+
## 10) Troubleshooting for Agents
|
|
446
333
|
|
|
447
334
|
Lock conflict:
|
|
448
335
|
|
|
@@ -467,7 +354,7 @@ Extension issues:
|
|
|
467
354
|
- when debugging runtime behavior changes, inspect parser/preflight/service override collisions in health/profile diagnostics (last registration wins)
|
|
468
355
|
- use SDK contracts from `@unbrained/pm-cli/sdk` (not internal `src/core/...` imports) for extension authoring and examples
|
|
469
356
|
|
|
470
|
-
##
|
|
357
|
+
## 11) Dogfood Logging Protocol (Required)
|
|
471
358
|
|
|
472
359
|
From now on in this repository, all implementation work must be tracked through `pm` items and `pm` mutations.
|
|
473
360
|
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2026.5.12] - 2026-05-12
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Added `pm install '*'` / `pm install all` to install all bundled first-party pm packages, including shell-expanded `pm install *`, and added typechecking for TypeScript-authored package sources.
|
|
14
|
+
- Added `pm upgrade` for package-first maintenance, including dry-run planning, CLI/SDK npm self-upgrade, managed package refresh from recorded sources, SDK/MCP action contracts, and docs/help coverage.
|
|
15
|
+
- Moved the Beads and Todo import/export bridges out of active project extension state so they are sourced from the first-party `packages/pm-beads` and `packages/pm-todos` package roots and installed on demand.
|
|
16
|
+
|
|
17
|
+
## [2026.5.11] - 2026-05-11
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- 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.
|
|
21
|
+
- 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).
|
|
22
|
+
- 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.
|
|
23
|
+
|
|
10
24
|
## [2026.5.10] - 2026-05-10
|
|
11
25
|
|
|
12
26
|
### Changed
|
package/PRD.md
CHANGED
|
@@ -43,9 +43,9 @@ Existing trackers either rely on hosted backends, store state in non-diff-friend
|
|
|
43
43
|
- Provide safe mutation under concurrent access (claim/release + lock + atomic writes).
|
|
44
44
|
- Default stdout to TOON; support `--json` parity for every command.
|
|
45
45
|
- Provide extension architecture for commands, schema, rendering, import/export, search adapters, and hooks.
|
|
46
|
-
- Ship
|
|
47
|
-
- Beads import (`beads
|
|
48
|
-
- todos.ts import/export (`todos
|
|
46
|
+
- Ship first-party installable package sources:
|
|
47
|
+
- Beads import (`packages/pm-beads`, installed via `pm install`)
|
|
48
|
+
- todos.ts import/export (`packages/pm-todos`, installed via `pm install`)
|
|
49
49
|
- Pi agent extension wrapper source module
|
|
50
50
|
- Provide optional semantic search with provider + vector-store adapters.
|
|
51
51
|
|
|
@@ -1327,7 +1327,7 @@ export interface ExtensionApi {
|
|
|
1327
1327
|
- Mandatory migration resolution is deterministic: `status` equal to `"applied"` (case-insensitive) is treated as resolved; any other/missing status is unresolved.
|
|
1328
1328
|
- Force-capable write commands may bypass the guard with explicit `--force`; write commands without `--force` remain blocked until blockers resolve.
|
|
1329
1329
|
|
|
1330
|
-
## 15)
|
|
1330
|
+
## 15) First-Party Installable Packages Required in v1
|
|
1331
1331
|
|
|
1332
1332
|
### A) Beads import
|
|
1333
1333
|
|
|
@@ -1337,8 +1337,8 @@ Command:
|
|
|
1337
1337
|
|
|
1338
1338
|
Current baseline status (release-hardening):
|
|
1339
1339
|
|
|
1340
|
-
- Command is packaged in
|
|
1341
|
-
- Command path is available only after
|
|
1340
|
+
- Command is packaged in the first-party package root (`packages/pm-beads`) using `activate(api)` and `api.registerCommand({ name, run })` for `beads import`.
|
|
1341
|
+
- Command path is available only after package install/activation in selected scope (`pm install packages/pm-beads`, package aliases, or explicit package source install).
|
|
1342
1342
|
|
|
1343
1343
|
Behavior:
|
|
1344
1344
|
|
|
@@ -1359,8 +1359,8 @@ Commands:
|
|
|
1359
1359
|
|
|
1360
1360
|
Current baseline status (release-hardening):
|
|
1361
1361
|
|
|
1362
|
-
- Commands are packaged in
|
|
1363
|
-
- Command paths are available only after
|
|
1362
|
+
- Commands are packaged in the first-party package root (`packages/pm-todos`) using `activate(api)` and `api.registerCommand({ name, run })` for `todos import` and `todos export`.
|
|
1363
|
+
- Command paths are available only after package install/activation in selected scope (`pm install packages/pm-todos`, package aliases, or explicit package source install).
|
|
1364
1364
|
|
|
1365
1365
|
Behavior:
|
|
1366
1366
|
|
|
@@ -1711,10 +1711,10 @@ Definition of Done:
|
|
|
1711
1711
|
Checklist:
|
|
1712
1712
|
|
|
1713
1713
|
- [x] extension manifest loader + sandboxed execution boundary (deterministic manifest discovery, precedence, failure-isolated runtime loading, realpath/symlink-resolved entry containment enforcement, command-handler context snapshot isolation for `args`/`options`/`global`, per-hook context snapshot isolation, and dynamic extension command loose-option parsing hardening (null-prototype option maps + prototype-pollution key rejection) are implemented; broader command sandbox API surface is post-v0.1 roadmap)
|
|
1714
|
-
- [x] hook lifecycle (extension `activate(api)` baseline with deterministic hook registration is implemented; registration now validates hook handlers as functions at activation time, per-hook context snapshot isolation prevents mutation leakage across hook callbacks and caller state, and `beforeCommand`/`afterCommand` command-lifecycle execution plus baseline read/write/index call-site wiring for core item-store reads/writes, create/restore item and history writes, settings read/write operations, history/activity history-directory scans and history-stream reads, health history-directory scans plus history-stream path dispatch, search item/linked reads, reindex flows, stats/health/gc command file-system paths (including `pm gc` onIndex dispatch with mode `gc` and deterministic cache-target totals), lock file read/write/unlink operations, init directory bootstrap ensure-write dispatch, and
|
|
1714
|
+
- [x] hook lifecycle (extension `activate(api)` baseline with deterministic hook registration is implemented; registration now validates hook handlers as functions at activation time, per-hook context snapshot isolation prevents mutation leakage across hook callbacks and caller state, and `beforeCommand`/`afterCommand` command-lifecycle execution plus baseline read/write/index call-site wiring for core item-store reads/writes, create/restore item and history writes, settings read/write operations, history/activity history-directory scans and history-stream reads, health history-directory scans plus history-stream path dispatch, search item/linked reads, reindex flows, stats/health/gc command file-system paths (including `pm gc` onIndex dispatch with mode `gc` and deterministic cache-target totals), lock file read/write/unlink operations, init directory bootstrap ensure-write dispatch, and first-party Beads/Todos package source/item/history file operations are implemented)
|
|
1715
1715
|
- [x] renderer and command extension points (deterministic core-command override + renderer override registration/dispatch is implemented with failure containment, extension command handlers for declared command paths including dynamically surfaced non-core paths are implemented, dynamic command help now surfaces `registerFlags` metadata deterministically, deep snapshot isolation for override/renderer result contexts is implemented, and override/renderer execution now includes cloned command `args`/`options`/`global` snapshots plus `pm_root` metadata for contextual deterministic extension output behavior)
|
|
1716
|
-
- [x]
|
|
1717
|
-
- [x]
|
|
1716
|
+
- [x] first-party Beads import package (`packages/pm-beads`) with install-only command surfacing through `pm install`, Beads JSONL field mapping, deterministic defaults, `op: "import"` history entries, and parity polish implemented)
|
|
1717
|
+
- [x] first-party Todos import/export package (`packages/pm-todos`) with install-only command surfacing through `pm install`, todos markdown round-trip, canonical optional metadata preservation including planning/workflow and issue fields, hierarchical ID preservation, and `med` alias normalization implemented)
|
|
1718
1718
|
- [x] Pi tool wrapper extension source module (Pi agent extension module at `.pi/extensions/pm-cli/index.ts` with full v0.1 action dispatch parity, including `completion` + `shell` mapping, camelCase parameter surface for all canonical scalar metadata, explicit empty-string passthrough, numeric-flag stringification, claim/release parity, packaged CLI fallback, and distribution packaging polish implemented)
|
|
1719
1719
|
|
|
1720
1720
|
Definition of Done:
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
| Command families and examples | [Command Reference](docs/COMMANDS.md) |
|
|
17
17
|
| Settings, storage, search, and output | [Configuration](docs/CONFIGURATION.md) |
|
|
18
18
|
| Safe test execution and linked tests | [Testing](docs/TESTING.md) |
|
|
19
|
-
|
|
|
19
|
+
| Package and extension authoring | [Packages and Extensions](docs/EXTENSIONS.md) and [SDK](docs/SDK.md) |
|
|
20
20
|
| Pi native package | [Pi Package](docs/PI_PACKAGE.md) |
|
|
21
21
|
| Codex native integration | [Codex Plugin](docs/CODEX_PLUGIN.md) |
|
|
22
22
|
| Maintainer release process (daily auto-release + local parity) | [Releasing](docs/RELEASING.md) |
|
|
@@ -51,13 +51,31 @@ 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.
|
|
69
|
+
|
|
70
|
+
`pm` packages use the same package-first vocabulary:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pm install ./my-package
|
|
74
|
+
pm package manage --project
|
|
75
|
+
pm package doctor --detail summary
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The legacy `pm extension ...` command remains available for existing automation.
|
|
61
79
|
|
|
62
80
|
## 60 Second Example
|
|
63
81
|
|
|
@@ -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 {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { resolveSubcommandFlagContractsForCommand } from "../sdk/cli-contracts.js";
|
|
2
|
+
import { levenshteinDistanceWithinLimit } from "../core/shared/levenshtein.js";
|
|
1
3
|
function parseBootstrapPathToken(token, next) {
|
|
2
4
|
if (token === "--path") {
|
|
3
5
|
if (typeof next === "string" && next.length > 0) {
|
|
@@ -220,6 +222,215 @@ export function normalizeLegacyExtensionActionSyntax(argv) {
|
|
|
220
222
|
}
|
|
221
223
|
return [...argv.slice(0, extensionIndex + 1), forcedActionFlag, ...argv.slice(extensionIndex + 2)];
|
|
222
224
|
}
|
|
225
|
+
function normalizeFlagKeyToken(raw) {
|
|
226
|
+
const withoutPrefix = raw.replace(/^--?/, "");
|
|
227
|
+
return withoutPrefix
|
|
228
|
+
.replace(/_/g, "-")
|
|
229
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
230
|
+
.toLowerCase();
|
|
231
|
+
}
|
|
232
|
+
function toComparableFlagKey(raw) {
|
|
233
|
+
return normalizeFlagKeyToken(raw).replace(/-/g, "");
|
|
234
|
+
}
|
|
235
|
+
function markUnambiguousFlag(map, key, canonicalFlag) {
|
|
236
|
+
const existing = map.get(key);
|
|
237
|
+
if (existing === undefined) {
|
|
238
|
+
map.set(key, canonicalFlag);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (existing !== canonicalFlag) {
|
|
242
|
+
map.set(key, null);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function collectLongFlagCandidates(contract) {
|
|
246
|
+
const candidates = [];
|
|
247
|
+
const pushLongFlag = (value) => {
|
|
248
|
+
if (typeof value !== "string") {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (!value.startsWith("--")) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
candidates.push(value);
|
|
255
|
+
};
|
|
256
|
+
pushLongFlag(contract.flag);
|
|
257
|
+
for (const alias of contract.aliases ?? []) {
|
|
258
|
+
pushLongFlag(alias);
|
|
259
|
+
}
|
|
260
|
+
return candidates;
|
|
261
|
+
}
|
|
262
|
+
function buildFlagLookup(commandName) {
|
|
263
|
+
const contracts = resolveSubcommandFlagContractsForCommand(commandName);
|
|
264
|
+
const canonicalByNormalized = new Map();
|
|
265
|
+
const canonicalByCompact = new Map();
|
|
266
|
+
const canonicalComparablesMap = new Map();
|
|
267
|
+
for (const contract of contracts) {
|
|
268
|
+
const longCandidates = collectLongFlagCandidates(contract);
|
|
269
|
+
if (longCandidates.length === 0) {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const canonicalFlag = `--${normalizeFlagKeyToken(longCandidates[0])}`;
|
|
273
|
+
for (const candidate of longCandidates) {
|
|
274
|
+
markUnambiguousFlag(canonicalByNormalized, normalizeFlagKeyToken(candidate), canonicalFlag);
|
|
275
|
+
markUnambiguousFlag(canonicalByCompact, toComparableFlagKey(candidate), canonicalFlag);
|
|
276
|
+
}
|
|
277
|
+
const comparable = toComparableFlagKey(canonicalFlag);
|
|
278
|
+
if (!canonicalComparablesMap.has(canonicalFlag)) {
|
|
279
|
+
canonicalComparablesMap.set(canonicalFlag, comparable);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
canonicalByNormalized,
|
|
284
|
+
canonicalByCompact,
|
|
285
|
+
canonicalComparables: [...canonicalComparablesMap.entries()].map(([canonicalFlag, comparable]) => ({
|
|
286
|
+
canonicalFlag,
|
|
287
|
+
comparable,
|
|
288
|
+
})),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function resolveCanonicalFlag(rawKey, lookup) {
|
|
292
|
+
const normalizedKey = normalizeFlagKeyToken(rawKey);
|
|
293
|
+
const direct = lookup.canonicalByNormalized.get(normalizedKey);
|
|
294
|
+
if (typeof direct === "string") {
|
|
295
|
+
return {
|
|
296
|
+
flag: direct,
|
|
297
|
+
reason: "flag_alias",
|
|
298
|
+
confidence: "high",
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
const comparableKey = normalizedKey.replace(/-/g, "");
|
|
302
|
+
const compactMatch = lookup.canonicalByCompact.get(comparableKey);
|
|
303
|
+
if (typeof compactMatch === "string") {
|
|
304
|
+
return {
|
|
305
|
+
flag: compactMatch,
|
|
306
|
+
reason: "flag_alias",
|
|
307
|
+
confidence: "high",
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
const maxDistance = comparableKey.length >= 8 ? 2 : 1;
|
|
311
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
312
|
+
let bestFlag;
|
|
313
|
+
let tied = false;
|
|
314
|
+
for (const candidate of lookup.canonicalComparables) {
|
|
315
|
+
const distance = levenshteinDistanceWithinLimit(comparableKey, candidate.comparable, maxDistance);
|
|
316
|
+
if (distance === null) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (distance < bestDistance) {
|
|
320
|
+
bestDistance = distance;
|
|
321
|
+
bestFlag = candidate.canonicalFlag;
|
|
322
|
+
tied = false;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (distance === bestDistance && bestFlag !== candidate.canonicalFlag) {
|
|
326
|
+
tied = true;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (!bestFlag || tied || !Number.isFinite(bestDistance) || bestDistance <= 0) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
flag: bestFlag,
|
|
334
|
+
reason: "flag_typo",
|
|
335
|
+
confidence: bestDistance >= 2 ? "medium" : "high",
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
function parseBareKeyValueToken(token) {
|
|
339
|
+
if (token.includes("://")) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
const match = token.match(/^([A-Za-z][A-Za-z0-9_-]{1,63})([:=])(.*)$/);
|
|
343
|
+
if (!match) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const key = match[1];
|
|
347
|
+
const value = match[3];
|
|
348
|
+
if (value.length === 0) {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
key,
|
|
353
|
+
value,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function normalizeLongOptionToken(token, lookup) {
|
|
357
|
+
if (!token.startsWith("--")) {
|
|
358
|
+
return { tokens: [token] };
|
|
359
|
+
}
|
|
360
|
+
const equalsIndex = token.indexOf("=");
|
|
361
|
+
const key = equalsIndex >= 0 ? token.slice(0, equalsIndex) : token;
|
|
362
|
+
const inlineValue = equalsIndex >= 0 ? token.slice(equalsIndex + 1) : undefined;
|
|
363
|
+
const resolution = resolveCanonicalFlag(key, lookup);
|
|
364
|
+
if (!resolution) {
|
|
365
|
+
return { tokens: [token] };
|
|
366
|
+
}
|
|
367
|
+
const normalizedToken = inlineValue === undefined ? resolution.flag : `${resolution.flag}=${inlineValue}`;
|
|
368
|
+
if (normalizedToken === token) {
|
|
369
|
+
return { tokens: [token] };
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
tokens: [normalizedToken],
|
|
373
|
+
event: {
|
|
374
|
+
from: token,
|
|
375
|
+
to: [normalizedToken],
|
|
376
|
+
reason: resolution.reason,
|
|
377
|
+
confidence: resolution.confidence,
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
export function normalizeBootstrapInvocation(argv) {
|
|
382
|
+
const trace = [];
|
|
383
|
+
const legacyNormalized = normalizeLegacyExtensionActionSyntax(argv);
|
|
384
|
+
if (legacyNormalized.length !== argv.length || legacyNormalized.some((token, index) => token !== argv[index])) {
|
|
385
|
+
trace.push({
|
|
386
|
+
from: argv.join(" "),
|
|
387
|
+
to: [...legacyNormalized],
|
|
388
|
+
reason: "legacy_extension_action",
|
|
389
|
+
confidence: "high",
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
const commandName = parseBootstrapCommandName(legacyNormalized);
|
|
393
|
+
const lookup = buildFlagLookup(commandName);
|
|
394
|
+
const normalizedArgv = [];
|
|
395
|
+
for (let index = 0; index < legacyNormalized.length; index += 1) {
|
|
396
|
+
const token = legacyNormalized[index];
|
|
397
|
+
if (token === "--") {
|
|
398
|
+
normalizedArgv.push(...legacyNormalized.slice(index));
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
const previous = normalizedArgv[normalizedArgv.length - 1];
|
|
402
|
+
if (token.startsWith("--")) {
|
|
403
|
+
const normalizedToken = normalizeLongOptionToken(token, lookup);
|
|
404
|
+
normalizedArgv.push(...normalizedToken.tokens);
|
|
405
|
+
if (normalizedToken.event) {
|
|
406
|
+
trace.push(normalizedToken.event);
|
|
407
|
+
}
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
const bareKeyValue = parseBareKeyValueToken(token);
|
|
411
|
+
if (bareKeyValue &&
|
|
412
|
+
!(typeof previous === "string" && previous.startsWith("-"))) {
|
|
413
|
+
const resolution = resolveCanonicalFlag(bareKeyValue.key, lookup);
|
|
414
|
+
if (resolution) {
|
|
415
|
+
const replacement = [resolution.flag, bareKeyValue.value];
|
|
416
|
+
normalizedArgv.push(...replacement);
|
|
417
|
+
trace.push({
|
|
418
|
+
from: token,
|
|
419
|
+
to: replacement,
|
|
420
|
+
reason: "bare_key_value",
|
|
421
|
+
confidence: resolution.confidence,
|
|
422
|
+
});
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
normalizedArgv.push(token);
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
argv: normalizedArgv,
|
|
430
|
+
commandName,
|
|
431
|
+
trace,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
223
434
|
export function parseBootstrapTypeValue(argv) {
|
|
224
435
|
for (let index = 0; index < argv.length; index += 1) {
|
|
225
436
|
const token = argv[index];
|