@unbrained/pm-cli 2026.9.4 → 2026.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/HARNESS_COMPATIBILITY.md +1 -1
- package/.agents/skills/README.md +2 -2
- package/.agents/skills/pm-developer/SKILL.md +4 -1
- package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +10 -0
- package/.agents/skills/pm-developer/references/GRAPH_AND_RELATIONSHIPS.md +3 -1
- package/.agents/skills/pm-extensions/SKILL.md +2 -2
- package/.agents/skills/pm-extensions/references/LIFECYCLE.md +3 -3
- package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +3 -3
- package/.agents/skills/pm-user/SKILL.md +2 -0
- package/.agents/skills/pm-user/references/BACKLOG_SHAPING.md +5 -0
- package/.agents/skills/pm-user/references/WORKFLOWS.md +20 -5
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +58 -3
- package/dist/cli/commander-usage.d.ts +2 -0
- package/dist/cli/commander-usage.js +15 -12
- package/dist/cli/help-json-payload.js +12 -7
- package/dist/cli/main.js +22 -11
- package/dist/cli/register-list-query.js +4 -2
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +17 -8
- package/dist/cli-bundle/bundle-manifest.json +153 -161
- package/dist/cli-bundle/chunks/chunk-AZDFJGH6.js +9 -0
- package/dist/cli-bundle/chunks/{chunk-V72UV7QS.js → chunk-BAX2BYUW.js} +73 -73
- package/dist/cli-bundle/chunks/{chunk-HI6BHPCU.js → chunk-CKOL5U7J.js} +51 -51
- package/dist/cli-bundle/chunks/{chunk-A24WAVE6.js → chunk-JT6XF6GE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-I2AS367G.js → chunk-JX4DH4WC.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-YW4QK2G7.js → chunk-NPN5I67J.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-OF76PSDQ.js +5 -0
- package/dist/cli-bundle/chunks/chunk-QUWFABDM.js +232 -0
- package/dist/cli-bundle/chunks/{chunk-RI4XNOYS.js → chunk-RWWBOWJ5.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-WGAOYSYH.js +40 -0
- package/dist/cli-bundle/chunks/{chunk-X6CMGV6L.js → chunk-WI2AYPA7.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-Z5YYSJJG.js → register-list-query-5JL52D33.js} +3 -3
- package/dist/cli-bundle/chunks/{register-mutation-ELSP6I4I.js → register-mutation-ZPG7KMVP.js} +4 -4
- package/dist/cli-bundle/chunks/register-operations-I5W3KMGB.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-E2AE72QG.js → register-setup-H4SVAVX7.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-3646BZ4W.js → chunk-3BZEOXLT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-AL5ON6K6.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-CHC2IDXA.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-CK6QFAPZ.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-NBMJD6MK.js → chunk-EZR3GHFE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-H2WJWK7L.js +56 -0
- package/dist/cli-bundle/focused-chunks/{chunk-53IHPICX.js → chunk-LIJIA4TY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-25UJBH4M.js → chunk-M6PBRFSH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-AJR3OP2E.js → chunk-NTPY5GSO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-P5O7MP5Y.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-PDMW2E36.js +177 -0
- package/dist/cli-bundle/focused-chunks/{chunk-MHKUIPJW.js → chunk-PEFABF7E.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-6PWPQKDN.js → chunk-QTVCLMSZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-7N2TV7WZ.js → chunk-QTZRBUYA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-SGQST3PQ.js +12 -0
- package/dist/cli-bundle/focused-chunks/chunk-UKHASMMP.js +10 -0
- package/dist/cli-bundle/focused-chunks/chunk-ZPEKQHOC.js +2 -0
- package/dist/cli-bundle/main.js +22 -15
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +37 -37
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +42 -39
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +9 -9
- package/dist/core/extensions/extension-types.d.ts +2 -0
- package/dist/core/extensions/extension-types.js +2 -2
- package/dist/core/extensions/module-graph-snapshot.js +5 -4
- package/dist/core/fs/host-environment-errors.d.ts +27 -0
- package/dist/core/fs/host-environment-errors.js +142 -0
- package/dist/core/history/drift-scan.d.ts +5 -0
- package/dist/core/history/drift-scan.js +16 -6
- package/dist/core/history/event-classification.d.ts +1 -1
- package/dist/core/history/event-classification.js +3 -2
- package/dist/core/history/history.js +37 -5
- package/dist/core/history/identity.d.ts +15 -0
- package/dist/core/history/identity.js +31 -0
- package/dist/core/history/projection.js +50 -17
- package/dist/core/history/read.js +6 -3
- package/dist/core/history/replay.d.ts +1 -2
- package/dist/core/history/replay.js +4 -4
- package/dist/core/history/version-address.d.ts +13 -0
- package/dist/core/history/version-address.js +33 -0
- package/dist/core/item/actionability.d.ts +21 -1
- package/dist/core/item/actionability.js +45 -10
- package/dist/core/item/id.js +8 -4
- package/dist/core/item/item-type-definition.d.ts +2 -0
- package/dist/core/item/item-type-definition.js +9 -2
- package/dist/core/item/type-registry.d.ts +5 -1
- package/dist/core/item/type-registry.js +9 -4
- package/dist/core/output/mutation-projection.js +12 -5
- package/dist/core/shared/errors.d.ts +8 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/store/item-metadata-query-index.js +13 -10
- package/dist/core/store/item-metadata-read-work.d.ts +19 -0
- package/dist/core/store/item-metadata-read-work.js +44 -0
- package/dist/core/store/item-store.d.ts +14 -0
- package/dist/core/store/item-store.js +52 -10
- package/dist/core/store/settings-validator.js +3 -2
- package/dist/core/validate/fix-planning.d.ts +1 -1
- package/dist/core/validate/fix-planning.js +2 -2
- package/dist/core/validate/missing-link-owners.d.ts +1 -1
- package/dist/core/validate/missing-link-owners.js +5 -3
- package/dist/core/validate/stale-file-classification.d.ts +6 -4
- package/dist/core/validate/stale-file-classification.js +20 -5
- package/dist/mcp/server.js +12 -5
- package/dist/sdk/actionability.d.ts +1 -1
- package/dist/sdk/actionability.js +3 -3
- package/dist/sdk/cli-contracts/command-aliases.js +11 -2
- package/dist/sdk/cli-contracts/completeness.js +4 -3
- package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
- package/dist/sdk/cli-contracts/flag-contracts.js +31 -5
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +21 -13
- package/dist/sdk/cli-contracts/grammar-contracts.js +11 -2
- package/dist/sdk/cli-contracts/runtime-contracts.js +5 -2
- package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +254 -5
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +52 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +30 -6
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +32 -7
- package/dist/sdk/context/usage-ledger.d.ts +41 -0
- package/dist/sdk/context/usage-ledger.js +186 -0
- package/dist/sdk/context-intent-contracts.js +3 -3
- package/dist/sdk/context-usage.d.ts +18 -9
- package/dist/sdk/context-usage.js +44 -121
- package/dist/sdk/define.d.ts +1 -1
- package/dist/sdk/define.js +2 -2
- package/dist/sdk/dependency-provenance.d.ts +7 -0
- package/dist/sdk/dependency-provenance.js +14 -4
- package/dist/sdk/duplicates.d.ts +2 -0
- package/dist/sdk/duplicates.js +3 -2
- package/dist/sdk/environment/host-environment-errors.d.ts +5 -27
- package/dist/sdk/environment/host-environment-errors.js +4 -137
- package/dist/sdk/extension/install-runtime.js +9 -6
- package/dist/sdk/extension/install-snapshot.js +7 -6
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +104 -56
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -2
- package/dist/sdk/governance/assurance-action.d.ts +3 -2
- package/dist/sdk/governance/assurance-action.js +23 -11
- package/dist/sdk/governance/assurance-runtime.d.ts +2 -0
- package/dist/sdk/governance/assurance-runtime.js +6 -3
- package/dist/sdk/governance/defect-recurrence-coverage.d.ts +93 -0
- package/dist/sdk/governance/defect-recurrence-coverage.js +189 -0
- package/dist/sdk/governance/defect-recurrence-graph.d.ts +33 -0
- package/dist/sdk/governance/defect-recurrence-graph.js +121 -0
- package/dist/sdk/governance/defect-recurrence.d.ts +8 -0
- package/dist/sdk/governance/defect-recurrence.js +118 -17
- package/dist/sdk/governance/health.d.ts +17 -2
- package/dist/sdk/governance/health.js +31 -10
- package/dist/sdk/governance/linked-file-report.d.ts +41 -0
- package/dist/sdk/governance/linked-file-report.js +72 -0
- package/dist/sdk/governance/validate-history-drift.js +16 -5
- package/dist/sdk/governance/validate.d.ts +5 -2
- package/dist/sdk/governance/validate.js +21 -37
- package/dist/sdk/governance.d.ts +2 -0
- package/dist/sdk/governance.js +4 -2
- package/dist/sdk/guide-topics.js +116 -2
- package/dist/sdk/history/salvage.d.ts +35 -0
- package/dist/sdk/history/salvage.js +248 -0
- package/dist/sdk/history-compact.js +32 -37
- package/dist/sdk/history-read.d.ts +3 -2
- package/dist/sdk/history-read.js +6 -3
- package/dist/sdk/history-repair.d.ts +12 -0
- package/dist/sdk/history-repair.js +60 -13
- package/dist/sdk/lifecycle/claim.d.ts +4 -0
- package/dist/sdk/lifecycle/claim.js +9 -3
- package/dist/sdk/lifecycle/close.d.ts +8 -0
- package/dist/sdk/lifecycle/close.js +16 -8
- package/dist/sdk/lifecycle/create.js +9 -12
- package/dist/sdk/lifecycle/restore.d.ts +1 -0
- package/dist/sdk/lifecycle/restore.js +19 -7
- package/dist/sdk/lifecycle/update.js +12 -12
- package/dist/sdk/lifecycle-policy.d.ts +3 -0
- package/dist/sdk/lifecycle-policy.js +2 -2
- package/dist/sdk/merge/abandoned-receipts.d.ts +15 -0
- package/dist/sdk/merge/abandoned-receipts.js +47 -0
- package/dist/sdk/merge/driver.js +4 -2
- package/dist/sdk/merge/index.d.ts +1 -0
- package/dist/sdk/merge/index.js +2 -2
- package/dist/sdk/merge/receipt-operation.d.ts +15 -0
- package/dist/sdk/merge/receipt-operation.js +97 -0
- package/dist/sdk/merge/receipt-schema.d.ts +20 -0
- package/dist/sdk/merge/receipt-schema.js +398 -0
- package/dist/sdk/merge/receipts.d.ts +16 -7
- package/dist/sdk/merge/receipts.js +54 -340
- package/dist/sdk/merge/reconcile.d.ts +2 -0
- package/dist/sdk/merge/reconcile.js +11 -4
- package/dist/sdk/output-projection.d.ts +3 -1
- package/dist/sdk/output-projection.js +11 -3
- package/dist/sdk/public-surface.json +1 -0
- package/dist/sdk/query/context.d.ts +9 -0
- package/dist/sdk/query/context.js +33 -21
- package/dist/sdk/query/duplicate-candidates.d.ts +7 -0
- package/dist/sdk/query/duplicate-candidates.js +71 -0
- package/dist/sdk/query/get.d.ts +2 -2
- package/dist/sdk/query/get.js +9 -8
- package/dist/sdk/query/history.d.ts +11 -0
- package/dist/sdk/query/history.js +34 -10
- package/dist/sdk/query/next.d.ts +15 -1
- package/dist/sdk/query/next.js +43 -20
- package/dist/sdk/query.d.ts +3 -0
- package/dist/sdk/query.js +5 -2
- package/dist/sdk/read-output-session.js +5 -3
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.js +4 -2
- package/dist/sdk/similarity.d.ts +24 -3
- package/dist/sdk/similarity.js +50 -55
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -2
- package/docs/AGENT_GUIDE.md +58 -1
- package/docs/BOUNDED_CONTEXT_READS.md +185 -0
- package/docs/CLOSE_EVIDENCE_RECOVERY.md +35 -0
- package/docs/COMMANDS.md +30 -8
- package/docs/CONTEXT_RELEVANCE.md +16 -4
- package/docs/DEFECT_RECURRENCE.md +80 -6
- package/docs/EXTENSIONS.md +18 -19
- package/docs/HISTORY_RECOVERY.md +146 -0
- package/docs/MERGE_SAFETY.md +50 -0
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +66 -0
- package/docs/PR_REVIEW_LOOP.md +18 -3
- package/docs/README.md +19 -1
- package/docs/RELEASING.md +31 -13
- package/docs/SDK_CONTEXT_TRUTH_CONTRACTS.md +24 -1
- package/docs/SDK_EXECUTION_CONTRACTS.md +105 -0
- package/docs/SDK_LIFECYCLE.md +27 -0
- package/docs/SDK_RUNTIME_BOUNDARIES.md +11 -0
- package/docs/TESTING.md +5 -0
- package/docs/agent-task-token-baseline.json +17 -17
- package/docs/agent-task-transcripts.json +2 -1
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +11 -11
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +11 -3
- package/marketplace.json +2 -2
- package/package.json +8 -6
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/README.md +10 -1
- package/packages/pm-governance-audit/extensions/governance-audit/dedupe-audit.ts +50 -65
- package/packages/pm-governance-audit/extensions/governance-audit/index.ts +2 -2
- package/packages/pm-governance-audit/extensions/governance-audit/sdk.ts +1 -0
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-claude/skills/pm-audit/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-developer/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-planner/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-release/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-workflow/SKILL.md +3 -3
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/skills/pm-auditor/SKILL.md +2 -2
- package/plugins/pm-codex/skills/pm-native/SKILL.md +3 -4
- package/plugins/pm-codex/skills/pm-release/SKILL.md +2 -2
- package/scripts/finalize-build.mjs +13 -1
- package/dist/cli-bundle/chunks/chunk-6XSKPNCF.js +0 -230
- package/dist/cli-bundle/chunks/chunk-OGBVU67G.js +0 -5
- package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +0 -38
- package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +0 -9
- package/dist/cli-bundle/chunks/register-operations-OH7R3ZT4.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4YRAVI43.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +0 -176
- package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +0 -54
- package/dist/cli-bundle/focused-chunks/chunk-B3A6MJYE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-BFDDJ2T2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-BHUIRZWQ.js +0 -9
- package/dist/cli-bundle/focused-chunks/chunk-JADHHPY6.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-P2GOAOQN.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-YARWJM2B.js +0 -2
- package/sdk/public-surface.json +0 -33034
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
EXIT_CODE,
|
|
8
8
|
PmCliError,
|
|
9
9
|
isTerminalStatus,
|
|
10
|
-
|
|
10
|
+
SETTINGS_DEFAULTS,
|
|
11
|
+
parseStatusFilterCsv,
|
|
11
12
|
normalizeSimilarityText,
|
|
12
13
|
nowIso,
|
|
13
14
|
readSettings,
|
|
@@ -46,6 +47,8 @@ interface DedupeAuditPreparedCandidate {
|
|
|
46
47
|
created_at: string;
|
|
47
48
|
updated_at: string;
|
|
48
49
|
normalized_title: string;
|
|
50
|
+
/** Lifecycle evidence captured from this call's workspace registry. */
|
|
51
|
+
terminal?: boolean;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
/** Documents the dedupe audit candidate payload exchanged by command, SDK, and package integrations. */
|
|
@@ -176,8 +179,8 @@ export interface DedupeAuditResult {
|
|
|
176
179
|
warnings?: string[];
|
|
177
180
|
}
|
|
178
181
|
|
|
182
|
+
/** Normalize the optional strategy name against the supported audit modes. */
|
|
179
183
|
const parseMode = (raw: string | undefined): DedupeAuditMode => {
|
|
180
|
-
/** Normalize the optional strategy name against the supported audit modes. */
|
|
181
184
|
const normalized = (raw ?? "title_exact").trim().toLowerCase();
|
|
182
185
|
if (!DEDUPE_AUDIT_MODES.includes(normalized as DedupeAuditMode)) {
|
|
183
186
|
throw new PmCliError(
|
|
@@ -188,39 +191,23 @@ const parseMode = (raw: string | undefined): DedupeAuditMode => {
|
|
|
188
191
|
return normalized as DedupeAuditMode;
|
|
189
192
|
};
|
|
190
193
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
"in_progress",
|
|
195
|
-
"blocked",
|
|
196
|
-
"closed",
|
|
197
|
-
"canceled",
|
|
198
|
-
]);
|
|
199
|
-
let dedupeTerminalStatuses = new Set<string>(["closed", "canceled"]);
|
|
200
|
-
let dedupeStatusRegistry: RuntimeStatusRegistry | null = null;
|
|
194
|
+
const defaultStatusRegistry = resolveRuntimeStatusRegistry(
|
|
195
|
+
SETTINGS_DEFAULTS.schema,
|
|
196
|
+
);
|
|
201
197
|
|
|
198
|
+
/** Parse package filters with the host SDK's workflow aliases and all sentinel. */
|
|
202
199
|
const parseStatus = (
|
|
203
200
|
raw: string | undefined,
|
|
201
|
+
registry: RuntimeStatusRegistry = defaultStatusRegistry,
|
|
204
202
|
): ItemStatus | "all" | undefined => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const normalized = raw.trim().toLowerCase().replaceAll("-", "_");
|
|
210
|
-
if (normalized === "all") {
|
|
211
|
-
return "all";
|
|
212
|
-
}
|
|
213
|
-
if (!dedupeAllowedStatuses.has(normalized)) {
|
|
214
|
-
throw new PmCliError(
|
|
215
|
-
`Status filter must be one of all|${[...dedupeAllowedStatuses].join("|")}`,
|
|
216
|
-
EXIT_CODE.USAGE,
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
return normalized as ItemStatus;
|
|
203
|
+
if (raw === undefined) return undefined;
|
|
204
|
+
return (
|
|
205
|
+
parseStatusFilterCsv(raw, registry, { strict: true })?.join(",") ?? "all"
|
|
206
|
+
);
|
|
220
207
|
};
|
|
221
208
|
|
|
209
|
+
/** Parse an optional fuzzy-match threshold on the inclusive zero-to-one scale. */
|
|
222
210
|
const parseThreshold = (raw: string | undefined): number | undefined => {
|
|
223
|
-
/** Parse an optional fuzzy-match threshold on the inclusive zero-to-one scale. */
|
|
224
211
|
if (raw === undefined) {
|
|
225
212
|
return undefined;
|
|
226
213
|
}
|
|
@@ -234,22 +221,15 @@ const parseThreshold = (raw: string | undefined): number | undefined => {
|
|
|
234
221
|
return parsed;
|
|
235
222
|
};
|
|
236
223
|
|
|
237
|
-
|
|
238
|
-
/** Resolve terminality through the active schema with a built-in fallback. */
|
|
239
|
-
if (dedupeStatusRegistry) {
|
|
240
|
-
return isTerminalStatus(status, dedupeStatusRegistry);
|
|
241
|
-
}
|
|
242
|
-
const normalized = normalizeStatusInput(status) ?? status;
|
|
243
|
-
return dedupeTerminalStatuses.has(normalized);
|
|
244
|
-
};
|
|
245
|
-
|
|
224
|
+
/** Rank canonical candidates by lifecycle, priority, recency, and identity. */
|
|
246
225
|
const compareCandidates = (
|
|
247
226
|
left: DedupeAuditPreparedCandidate,
|
|
248
227
|
right: DedupeAuditPreparedCandidate,
|
|
249
228
|
): number => {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const rightTerminal =
|
|
229
|
+
const leftTerminal =
|
|
230
|
+
left.terminal ?? isTerminalStatus(left.status, defaultStatusRegistry);
|
|
231
|
+
const rightTerminal =
|
|
232
|
+
right.terminal ?? isTerminalStatus(right.status, defaultStatusRegistry);
|
|
253
233
|
if (leftTerminal !== rightTerminal) {
|
|
254
234
|
return leftTerminal ? 1 : -1;
|
|
255
235
|
}
|
|
@@ -264,10 +244,10 @@ const compareCandidates = (
|
|
|
264
244
|
return left.id.localeCompare(right.id);
|
|
265
245
|
};
|
|
266
246
|
|
|
247
|
+
/** Project one prepared comparison record into the public candidate shape. */
|
|
267
248
|
const toCandidate = (
|
|
268
249
|
candidate: DedupeAuditPreparedCandidate,
|
|
269
250
|
): DedupeAuditCandidate => {
|
|
270
|
-
/** Project one prepared comparison record into the public candidate shape. */
|
|
271
251
|
return {
|
|
272
252
|
id: candidate.id,
|
|
273
253
|
title: candidate.title,
|
|
@@ -280,12 +260,12 @@ const toCandidate = (
|
|
|
280
260
|
};
|
|
281
261
|
};
|
|
282
262
|
|
|
263
|
+
/** Build an executable close recommendation for one duplicate candidate. */
|
|
283
264
|
const toMergeSuggestion = (
|
|
284
265
|
duplicate: DedupeAuditPreparedCandidate,
|
|
285
266
|
canonical: DedupeAuditPreparedCandidate,
|
|
286
267
|
mode: DedupeAuditMode,
|
|
287
268
|
): DedupeMergeSuggestion => {
|
|
288
|
-
/** Build an executable close recommendation for one duplicate candidate. */
|
|
289
269
|
const closeReason = `Duplicate of ${canonical.id}`;
|
|
290
270
|
const message = `Close ${duplicate.id} as duplicate of ${canonical.id} from pm dedupe-audit (${mode}).`;
|
|
291
271
|
const escapedReason = closeReason.replaceAll('"', '\\"');
|
|
@@ -299,14 +279,15 @@ const toMergeSuggestion = (
|
|
|
299
279
|
};
|
|
300
280
|
};
|
|
301
281
|
|
|
282
|
+
/** Score exact normalized titles first, then fall back to token overlap. */
|
|
302
283
|
const similarityScore = (
|
|
303
284
|
left: DedupeAuditPreparedCandidate,
|
|
304
285
|
right: DedupeAuditPreparedCandidate,
|
|
305
286
|
): number => {
|
|
306
|
-
/** Score exact normalized titles first, then fall back to token overlap. */
|
|
307
287
|
return scoreItemSimilarity(left.title, right.title).score;
|
|
308
288
|
};
|
|
309
289
|
|
|
290
|
+
/** Visit each unordered candidate pair exactly once. */
|
|
310
291
|
const forEachCandidatePair = (
|
|
311
292
|
items: DedupeAuditPreparedCandidate[],
|
|
312
293
|
visit: (
|
|
@@ -316,7 +297,6 @@ const forEachCandidatePair = (
|
|
|
316
297
|
rightIndex: number,
|
|
317
298
|
) => void,
|
|
318
299
|
): void => {
|
|
319
|
-
/** Visit each unordered candidate pair exactly once. */
|
|
320
300
|
for (let leftIndex = 0; leftIndex < items.length; leftIndex += 1) {
|
|
321
301
|
for (
|
|
322
302
|
let rightIndex = leftIndex + 1;
|
|
@@ -328,15 +308,16 @@ const forEachCandidatePair = (
|
|
|
328
308
|
}
|
|
329
309
|
};
|
|
330
310
|
|
|
311
|
+
/** Select one numeric extreme while preserving a deterministic empty fallback. */
|
|
331
312
|
const extremeOrDefault = (
|
|
332
313
|
values: number[],
|
|
333
314
|
select: (...candidates: number[]) => number,
|
|
334
315
|
fallback: number,
|
|
335
316
|
): number => {
|
|
336
|
-
/** Select one numeric extreme while preserving a deterministic empty fallback. */
|
|
337
317
|
return values.length === 0 ? fallback : select(...values);
|
|
338
318
|
};
|
|
339
319
|
|
|
320
|
+
/** Assemble one deterministic cluster and its optional similarity envelope. */
|
|
340
321
|
const clusterFromMembers = (
|
|
341
322
|
mode: DedupeAuditMode,
|
|
342
323
|
key: string,
|
|
@@ -344,7 +325,6 @@ const clusterFromMembers = (
|
|
|
344
325
|
matchReason: string,
|
|
345
326
|
threshold?: number,
|
|
346
327
|
): DedupeAuditCluster => {
|
|
347
|
-
/** Assemble one deterministic cluster and its optional similarity envelope. */
|
|
348
328
|
const sortedMembers = [...members].sort(compareCandidates);
|
|
349
329
|
const canonical = sortedMembers[0];
|
|
350
330
|
const duplicates = sortedMembers.slice(1);
|
|
@@ -375,11 +355,11 @@ const clusterFromMembers = (
|
|
|
375
355
|
return cluster;
|
|
376
356
|
};
|
|
377
357
|
|
|
358
|
+
/** Group candidates by a caller-defined non-empty comparison key. */
|
|
378
359
|
const collectGroupedCandidates = (
|
|
379
360
|
items: DedupeAuditPreparedCandidate[],
|
|
380
361
|
keyFor: (item: DedupeAuditPreparedCandidate) => string | undefined,
|
|
381
362
|
): Map<string, DedupeAuditPreparedCandidate[]> => {
|
|
382
|
-
/** Group candidates by a caller-defined non-empty comparison key. */
|
|
383
363
|
const groups = new Map<string, DedupeAuditPreparedCandidate[]>();
|
|
384
364
|
for (const item of items) {
|
|
385
365
|
const key = keyFor(item);
|
|
@@ -391,12 +371,12 @@ const collectGroupedCandidates = (
|
|
|
391
371
|
return groups;
|
|
392
372
|
};
|
|
393
373
|
|
|
374
|
+
/** Convert non-singleton candidate groups into deterministic clusters. */
|
|
394
375
|
const clustersFromGroups = (
|
|
395
376
|
groups: Map<string, DedupeAuditPreparedCandidate[]>,
|
|
396
377
|
mode: DedupeAuditMode,
|
|
397
378
|
matchReason: string,
|
|
398
379
|
): DedupeAuditCluster[] => {
|
|
399
|
-
/** Convert non-singleton candidate groups into deterministic clusters. */
|
|
400
380
|
return [...groups.entries()]
|
|
401
381
|
.filter(([, members]) => members.length > 1)
|
|
402
382
|
.map(([key, members]) =>
|
|
@@ -404,10 +384,10 @@ const clustersFromGroups = (
|
|
|
404
384
|
);
|
|
405
385
|
};
|
|
406
386
|
|
|
387
|
+
/** Group candidates that share the same normalized title. */
|
|
407
388
|
const collectExactTitleClusters = (
|
|
408
389
|
items: DedupeAuditPreparedCandidate[],
|
|
409
390
|
): DedupeAuditCluster[] => {
|
|
410
|
-
/** Group candidates that share the same normalized title. */
|
|
411
391
|
const groups = collectGroupedCandidates(items, (item) =>
|
|
412
392
|
item.normalized_title.length === 0 ? undefined : item.normalized_title,
|
|
413
393
|
);
|
|
@@ -418,10 +398,10 @@ const collectExactTitleClusters = (
|
|
|
418
398
|
);
|
|
419
399
|
};
|
|
420
400
|
|
|
401
|
+
/** Group normalized-title duplicates only when they share a parent. */
|
|
421
402
|
const collectParentScopedClusters = (
|
|
422
403
|
items: DedupeAuditPreparedCandidate[],
|
|
423
404
|
): DedupeAuditCluster[] => {
|
|
424
|
-
/** Group normalized-title duplicates only when they share a parent. */
|
|
425
405
|
const groups = collectGroupedCandidates(items, (item) =>
|
|
426
406
|
item.parent && item.normalized_title.length > 0
|
|
427
407
|
? `${item.parent}|${item.normalized_title}`
|
|
@@ -434,8 +414,8 @@ const collectParentScopedClusters = (
|
|
|
434
414
|
);
|
|
435
415
|
};
|
|
436
416
|
|
|
417
|
+
/** Find and compress one disjoint-set root for fuzzy clustering. */
|
|
437
418
|
const findRoot = (parents: number[], index: number): number => {
|
|
438
|
-
/** Find and compress one disjoint-set root for fuzzy clustering. */
|
|
439
419
|
let current = index;
|
|
440
420
|
while (parents[current] !== current) {
|
|
441
421
|
parents[current] = parents[parents[current]];
|
|
@@ -444,8 +424,8 @@ const findRoot = (parents: number[], index: number): number => {
|
|
|
444
424
|
return current;
|
|
445
425
|
};
|
|
446
426
|
|
|
427
|
+
/** Join two fuzzy-cluster roots under the lower deterministic index. */
|
|
447
428
|
const unionRoots = (parents: number[], left: number, right: number): void => {
|
|
448
|
-
/** Join two fuzzy-cluster roots under the lower deterministic index. */
|
|
449
429
|
const leftRoot = findRoot(parents, left);
|
|
450
430
|
const rightRoot = findRoot(parents, right);
|
|
451
431
|
if (leftRoot === rightRoot) {
|
|
@@ -454,11 +434,11 @@ const unionRoots = (parents: number[], left: number, right: number): void => {
|
|
|
454
434
|
parents[Math.max(leftRoot, rightRoot)] = Math.min(leftRoot, rightRoot);
|
|
455
435
|
};
|
|
456
436
|
|
|
437
|
+
/** Build transitive fuzzy-title clusters at the requested similarity floor. */
|
|
457
438
|
const collectFuzzyTitleClusters = (
|
|
458
439
|
items: DedupeAuditPreparedCandidate[],
|
|
459
440
|
threshold: number,
|
|
460
441
|
): DedupeAuditCluster[] => {
|
|
461
|
-
/** Build transitive fuzzy-title clusters at the requested similarity floor. */
|
|
462
442
|
const parents = items.map((_item, index) => index);
|
|
463
443
|
forEachCandidatePair(items, (left, right, leftIndex, rightIndex) => {
|
|
464
444
|
if (similarityScore(left, right) >= threshold) {
|
|
@@ -490,11 +470,11 @@ const collectFuzzyTitleClusters = (
|
|
|
490
470
|
});
|
|
491
471
|
};
|
|
492
472
|
|
|
473
|
+
/** Order larger clusters first and break ties by canonical identity. */
|
|
493
474
|
const compareClusters = (
|
|
494
475
|
left: DedupeAuditCluster,
|
|
495
476
|
right: DedupeAuditCluster,
|
|
496
477
|
): number => {
|
|
497
|
-
/** Order larger clusters first and break ties by canonical identity. */
|
|
498
478
|
const bySize = right.cluster_size - left.cluster_size;
|
|
499
479
|
if (bySize !== 0) {
|
|
500
480
|
return bySize;
|
|
@@ -502,12 +482,12 @@ const compareClusters = (
|
|
|
502
482
|
return left.canonical.id.localeCompare(right.canonical.id);
|
|
503
483
|
};
|
|
504
484
|
|
|
485
|
+
/** Dispatch candidate collection to the selected comparison strategy. */
|
|
505
486
|
const collectDedupeClusters = (
|
|
506
487
|
mode: DedupeAuditMode,
|
|
507
488
|
prepared: DedupeAuditPreparedCandidate[],
|
|
508
489
|
fuzzyThreshold: number,
|
|
509
490
|
): DedupeAuditCluster[] => {
|
|
510
|
-
/** Dispatch candidate collection to the selected comparison strategy. */
|
|
511
491
|
if (mode === "title_exact") {
|
|
512
492
|
return collectExactTitleClusters(prepared);
|
|
513
493
|
}
|
|
@@ -517,10 +497,11 @@ const collectDedupeClusters = (
|
|
|
517
497
|
return collectFuzzyTitleClusters(prepared, fuzzyThreshold);
|
|
518
498
|
};
|
|
519
499
|
|
|
500
|
+
/** Precompute normalized fields used by every dedupe comparison strategy. */
|
|
520
501
|
const toPreparedDedupeCandidate = (
|
|
521
502
|
item: ListedItem,
|
|
503
|
+
registry: RuntimeStatusRegistry,
|
|
522
504
|
): DedupeAuditPreparedCandidate => {
|
|
523
|
-
/** Precompute normalized fields used by every dedupe comparison strategy. */
|
|
524
505
|
return {
|
|
525
506
|
id: item.id,
|
|
526
507
|
title: item.title,
|
|
@@ -531,6 +512,7 @@ const toPreparedDedupeCandidate = (
|
|
|
531
512
|
created_at: item.created_at,
|
|
532
513
|
updated_at: item.updated_at,
|
|
533
514
|
normalized_title: normalizeSimilarityText(item.title),
|
|
515
|
+
terminal: isTerminalStatus(item.status, registry),
|
|
534
516
|
};
|
|
535
517
|
};
|
|
536
518
|
|
|
@@ -538,6 +520,7 @@ const toPreparedDedupeCandidate = (
|
|
|
538
520
|
const toNullable = <Value>(value: Value | undefined): Value | null =>
|
|
539
521
|
value ?? null;
|
|
540
522
|
|
|
523
|
+
/** Echo normalized audit filters in the stable public result shape. */
|
|
541
524
|
const buildDedupeAuditFilters = (params: {
|
|
542
525
|
mode: DedupeAuditMode;
|
|
543
526
|
status: ItemStatus | "all" | undefined;
|
|
@@ -545,7 +528,6 @@ const buildDedupeAuditFilters = (params: {
|
|
|
545
528
|
limit: number | undefined;
|
|
546
529
|
fuzzyThreshold: number;
|
|
547
530
|
}): DedupeAuditResult["filters"] => {
|
|
548
|
-
/** Echo normalized audit filters in the stable public result shape. */
|
|
549
531
|
return {
|
|
550
532
|
mode: params.mode,
|
|
551
533
|
status: toNullable(params.status),
|
|
@@ -572,24 +554,27 @@ export const runDedupeAudit = async (
|
|
|
572
554
|
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
573
555
|
const settings = await readSettings(pmRoot);
|
|
574
556
|
const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
|
|
575
|
-
dedupeStatusRegistry = statusRegistry;
|
|
576
|
-
dedupeAllowedStatuses = new Set(
|
|
577
|
-
statusRegistry.definitions.map((definition) => definition.id),
|
|
578
|
-
);
|
|
579
|
-
dedupeTerminalStatuses = new Set(statusRegistry.terminal_statuses);
|
|
580
557
|
const mode = parseMode(options.mode);
|
|
581
|
-
const status = parseStatus(options.status);
|
|
558
|
+
const status = parseStatus(options.status, statusRegistry);
|
|
582
559
|
const limit = parseIntegerLimit(options.limit);
|
|
583
560
|
const threshold = parseThreshold(options.threshold);
|
|
584
561
|
const fuzzyThreshold = threshold ?? 0.8;
|
|
585
562
|
|
|
586
563
|
const listed = await runList(
|
|
587
564
|
status === "all" ? undefined : status,
|
|
588
|
-
{
|
|
565
|
+
{
|
|
566
|
+
...buildListQueryFilters(options),
|
|
567
|
+
full: true as const,
|
|
568
|
+
all: true,
|
|
569
|
+
noTruncate: true,
|
|
570
|
+
strictRead: true,
|
|
571
|
+
},
|
|
589
572
|
global,
|
|
590
573
|
);
|
|
591
574
|
|
|
592
|
-
const prepared = listed.items.map((item) =>
|
|
575
|
+
const prepared = listed.items.map((item) =>
|
|
576
|
+
toPreparedDedupeCandidate(item, statusRegistry),
|
|
577
|
+
);
|
|
593
578
|
|
|
594
579
|
const clusters = collectDedupeClusters(mode, prepared, fuzzyThreshold);
|
|
595
580
|
|
|
@@ -60,14 +60,14 @@ const dedupeAuditFlags = [
|
|
|
60
60
|
long: "--status",
|
|
61
61
|
value_name: "value",
|
|
62
62
|
value_type: "string",
|
|
63
|
-
description: "Filter by status.",
|
|
63
|
+
description: "Filter by configured status IDs or aliases (comma-separated); all includes every lifecycle state.",
|
|
64
64
|
},
|
|
65
65
|
...auditNormalizeFilterFlags,
|
|
66
66
|
{
|
|
67
67
|
long: "--limit",
|
|
68
68
|
value_name: "n",
|
|
69
69
|
value_type: "string",
|
|
70
|
-
description: "Limit analyzed
|
|
70
|
+
description: "Limit returned duplicate clusters; every matching item is analyzed.",
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
long: "--threshold",
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Resolves the host pm SDK runtime and exposes the typed subset consumed by
|
|
5
5
|
* the governance-audit package without copying core command implementations.
|
|
6
6
|
*/
|
|
7
|
+
export { SETTINGS_DEFAULTS, parseStatusFilterCsv } from "@unbrained/pm-cli/sdk";
|
|
7
8
|
import * as runtime from "@unbrained/pm-cli/sdk/runtime";
|
|
8
9
|
|
|
9
10
|
/** Host SDK values used by package-owned audit commands and runtime decorators. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pm-claude",
|
|
3
3
|
"description": "Native pm CLI integration for Claude Code — 28 MCP tools, 5 workflow skills, 14 slash commands, 4 subagents (coordinator, delivery-chain, 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": "2026.9.
|
|
4
|
+
"version": "2026.9.6",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "unbrained",
|
|
7
7
|
"url": "https://github.com/unbraind/pm-cli"
|
|
@@ -94,8 +94,8 @@ Load the smallest thing that answers the question. Costs are measured.
|
|
|
94
94
|
| The whole command surface with per-command ceilings | `pm_contracts` with `summary: true` | ~2.6k tok |
|
|
95
95
|
| An unfamiliar capability family | `pm_run` with `action: "guide", topic: "<topic>", depth: "brief"` | ~0.6-1k tok |
|
|
96
96
|
|
|
97
|
-
Guide topics: `
|
|
98
|
-
`
|
|
97
|
+
Guide topics are declared at runtime: `pm guide` prints the current index and
|
|
98
|
+
`pm guide <topic> --depth brief` expands one topic. Do not copy the list.
|
|
99
99
|
|
|
100
100
|
Never load `docs/COMMANDS.md` (~29k tok) or `docs/SDK.md` (~45k tok) whole.
|
|
101
101
|
|
|
@@ -133,8 +133,8 @@ Load the smallest thing that answers the question. Costs are measured.
|
|
|
133
133
|
| The whole command surface with per-command ceilings | `pm_contracts` with `summary: true` | ~2.6k tok |
|
|
134
134
|
| An unfamiliar capability family | `pm_run` with `action: "guide", topic: "<topic>", depth: "brief"` | ~0.6-1k tok |
|
|
135
135
|
|
|
136
|
-
Guide topics: `
|
|
137
|
-
`
|
|
136
|
+
Guide topics are declared at runtime: `pm guide` prints the current index and
|
|
137
|
+
`pm guide <topic> --depth brief` expands one topic. Do not copy the list.
|
|
138
138
|
|
|
139
139
|
Never load `docs/COMMANDS.md` (~29k tok) or `docs/SDK.md` (~45k tok) whole.
|
|
140
140
|
|
|
@@ -157,8 +157,8 @@ Load the smallest thing that answers the question. Costs are measured.
|
|
|
157
157
|
| The whole command surface with per-command ceilings | `pm_contracts` with `summary: true` | ~2.6k tok |
|
|
158
158
|
| An unfamiliar capability family | `pm_run` with `action: "guide", topic: "<topic>", depth: "brief"` | ~0.6-1k tok |
|
|
159
159
|
|
|
160
|
-
Guide topics: `
|
|
161
|
-
`
|
|
160
|
+
Guide topics are declared at runtime: `pm guide` prints the current index and
|
|
161
|
+
`pm guide <topic> --depth brief` expands one topic. Do not copy the list.
|
|
162
162
|
|
|
163
163
|
Never load `docs/COMMANDS.md` (~29k tok) or `docs/SDK.md` (~45k tok) whole.
|
|
164
164
|
|
|
@@ -92,8 +92,8 @@ Load the smallest thing that answers the question. Costs are measured.
|
|
|
92
92
|
| The whole command surface with per-command ceilings | `pm_contracts` with `summary: true` | ~2.6k tok |
|
|
93
93
|
| An unfamiliar capability family | `pm_run` with `action: "guide", topic: "<topic>", depth: "brief"` | ~0.6-1k tok |
|
|
94
94
|
|
|
95
|
-
Guide topics: `
|
|
96
|
-
`
|
|
95
|
+
Guide topics are declared at runtime: `pm guide` prints the current index and
|
|
96
|
+
`pm guide <topic> --depth brief` expands one topic. Do not copy the list.
|
|
97
97
|
|
|
98
98
|
Never load `docs/COMMANDS.md` (~29k tok) or `docs/SDK.md` (~45k tok) whole.
|
|
99
99
|
|
|
@@ -15,7 +15,7 @@ Use this skill for all pm-tracked work. Prefer native MCP tools over shell `pm`
|
|
|
15
15
|
|---------|------|
|
|
16
16
|
| Orient / read state | `pm_context`, `pm_search`, `pm_list`, `pm_get` |
|
|
17
17
|
| Create / update | `pm_create`, `pm_update`, `pm_claim`, `pm_release`, `pm_close` |
|
|
18
|
-
| Evidence | `pm_comments`, `pm_files`, `pm_docs`, `pm_test` |
|
|
18
|
+
| Evidence | `pm_comments`, `pm_notes`, `pm_learnings`, `pm_files`, `pm_docs`, `pm_test` |
|
|
19
19
|
| Verify | `pm_validate`, `pm_health`, `pm_contracts` |
|
|
20
20
|
| Everything else | `pm_run` with an explicit `action` |
|
|
21
21
|
|
|
@@ -154,8 +154,8 @@ Load the smallest thing that answers the question. Costs are measured.
|
|
|
154
154
|
| The whole command surface with per-command ceilings | `pm_contracts` with `summary: true` | ~2.6k tok |
|
|
155
155
|
| An unfamiliar capability family | `pm_run` with `action: "guide", topic: "<topic>", depth: "brief"` | ~0.6-1k tok |
|
|
156
156
|
|
|
157
|
-
Guide topics: `
|
|
158
|
-
`
|
|
157
|
+
Guide topics are declared at runtime: `pm guide` prints the current index and
|
|
158
|
+
`pm guide <topic> --depth brief` expands one topic. Do not copy the list.
|
|
159
159
|
|
|
160
160
|
Never load `docs/COMMANDS.md` (~29k tok) or `docs/SDK.md` (~45k tok) whole.
|
|
161
161
|
|
|
@@ -30,8 +30,8 @@ Load the smallest thing that answers the question. Costs are measured.
|
|
|
30
30
|
| The whole command surface with per-command ceilings | `pm_contracts` with `summary: true` | ~2.6k tok |
|
|
31
31
|
| An unfamiliar capability family | `pm_run` with `action: "guide", topic: "<topic>", depth: "brief"` | ~0.6-1k tok |
|
|
32
32
|
|
|
33
|
-
Guide topics: `
|
|
34
|
-
`
|
|
33
|
+
Guide topics are declared at runtime: `pm guide` prints the current index and
|
|
34
|
+
`pm guide <topic> --depth brief` expands one topic. Do not copy the list.
|
|
35
35
|
|
|
36
36
|
Never load `docs/COMMANDS.md` (~29k tok) or `docs/SDK.md` (~45k tok) whole.
|
|
37
37
|
|
|
@@ -14,7 +14,7 @@ Use MCP tools before shell commands:
|
|
|
14
14
|
|
|
15
15
|
- Orient: `pm_context`, `pm_search`, `pm_list`, `pm_get`
|
|
16
16
|
- Mutate: `pm_create`, `pm_update`, `pm_claim`, `pm_release`, `pm_close`
|
|
17
|
-
- Evidence: `pm_comments`, `pm_files`, `pm_docs`, `pm_test`
|
|
17
|
+
- Evidence: `pm_comments`, `pm_notes`, `pm_learnings`, `pm_files`, `pm_docs`, `pm_test`
|
|
18
18
|
- Verify: `pm_validate`, `pm_health`, `pm_contracts`
|
|
19
19
|
- Everything else: `pm_run` with an explicit `action`
|
|
20
20
|
|
|
@@ -37,7 +37,6 @@ Most tools accept:
|
|
|
37
37
|
```json
|
|
38
38
|
{
|
|
39
39
|
"cwd": "/repo/root",
|
|
40
|
-
"author": "codex-agent",
|
|
41
40
|
"options": {
|
|
42
41
|
"limit": "10"
|
|
43
42
|
}
|
|
@@ -79,8 +78,8 @@ Load the smallest thing that answers the question. Costs are measured.
|
|
|
79
78
|
| The whole command surface with per-command ceilings | `pm_contracts` with `summary: true` | ~2.6k tok |
|
|
80
79
|
| An unfamiliar capability family | `pm_run` with `action: "guide", topic: "<topic>", depth: "brief"` | ~0.6-1k tok |
|
|
81
80
|
|
|
82
|
-
Guide topics: `
|
|
83
|
-
`
|
|
81
|
+
Guide topics are declared at runtime: `pm guide` prints the current index and
|
|
82
|
+
`pm guide <topic> --depth brief` expands one topic. Do not copy the list.
|
|
84
83
|
|
|
85
84
|
Never load `docs/COMMANDS.md` (~29k tok) or `docs/SDK.md` (~45k tok) whole.
|
|
86
85
|
|
|
@@ -29,8 +29,8 @@ Load the smallest thing that answers the question. Costs are measured.
|
|
|
29
29
|
| The whole command surface with per-command ceilings | `pm_contracts` with `summary: true` | ~2.6k tok |
|
|
30
30
|
| An unfamiliar capability family | `pm_run` with `action: "guide", topic: "<topic>", depth: "brief"` | ~0.6-1k tok |
|
|
31
31
|
|
|
32
|
-
Guide topics: `
|
|
33
|
-
`
|
|
32
|
+
Guide topics are declared at runtime: `pm guide` prints the current index and
|
|
33
|
+
`pm guide <topic> --depth brief` expands one topic. Do not copy the list.
|
|
34
34
|
|
|
35
35
|
Never load `docs/COMMANDS.md` (~29k tok) or `docs/SDK.md` (~45k tok) whole.
|
|
36
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { chmod, stat } from "node:fs/promises";
|
|
3
|
+
import { chmod, readFile, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
|
|
@@ -16,6 +16,7 @@ async function outputExists(filePath) {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/** Finalize executable modes and the semantically identical compact public SDK manifest. */
|
|
19
20
|
export async function main(repoRoot = process.cwd()) {
|
|
20
21
|
const executableOutputs = [
|
|
21
22
|
path.join(repoRoot, "dist", "cli.js"),
|
|
@@ -28,6 +29,17 @@ export async function main(repoRoot = process.cwd()) {
|
|
|
28
29
|
await chmod(outputPath, 0o755);
|
|
29
30
|
}
|
|
30
31
|
}
|
|
32
|
+
|
|
33
|
+
// Keep the checked-in compatibility manifest readable, while distributing
|
|
34
|
+
// identical JSON data without indentation through its stable public export.
|
|
35
|
+
const manifest = JSON.parse(
|
|
36
|
+
await readFile(path.join(repoRoot, "sdk", "public-surface.json"), "utf8"),
|
|
37
|
+
);
|
|
38
|
+
await writeFile(
|
|
39
|
+
path.join(repoRoot, "dist", "sdk", "public-surface.json"),
|
|
40
|
+
`${JSON.stringify(manifest)}\n`,
|
|
41
|
+
"utf8",
|
|
42
|
+
);
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
/* c8 ignore start -- CLI auto-run guard; logic covered via exported main() */
|