@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
package/dist/sdk/query/next.js
CHANGED
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
* re-deriving readiness from a full `pm context` snapshot every turn.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
13
|
-
import { collectBlockedByIds, computeActionabilityReport, } from "../actionability.js";
|
|
14
|
-
import { resolveRuntimeStatusRegistry, EXIT_CODE, PmCliError, nowIso, normalizeStatusInput, normalizeStatusForRegistry, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
|
|
12
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6035e85b-81ed-512e-b291-b0d86af1848b")}catch(e){}}();
|
|
13
|
+
import { collectBlockedByIds, computeActionabilityReport, resolveItemExecutionRole, selectActionableEntries, } from "../actionability.js";
|
|
14
|
+
import { resolveRuntimeStatusRegistry, EXIT_CODE, PmCliError, nowIso, normalizeStatusInput, normalizeStatusForRegistry, resolvePmRoot, readSettings, resolveAuthor, resolveItemTypeRegistry, } from "../runtime-primitives.js";
|
|
15
|
+
import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
|
|
15
16
|
import { parseIntegerLimit } from "./parsers.js";
|
|
16
17
|
import { buildChildrenByParent, collectSubtreeIds, compareCriticalItems, mergeSortedWarnings, packRankedContextItems, resolveContextTokenBudget, toContextPackingSummary, toContextRankingSummary, toContextFocusItem, } from "./context.js";
|
|
17
18
|
import { runList } from "./list.js";
|
|
@@ -94,7 +95,7 @@ function buildRecommendationReasons(entry, statusRegistry, now, completedContain
|
|
|
94
95
|
reasons.push(`advances ${item.parent.trim()}`);
|
|
95
96
|
}
|
|
96
97
|
if (entry.unblocks.length > 0) {
|
|
97
|
-
reasons.push(`unblocks ${entry.unblocks.length} item(s)
|
|
98
|
+
reasons.push(`unblocks ${entry.unblocks.length} item(s)`);
|
|
98
99
|
}
|
|
99
100
|
return reasons;
|
|
100
101
|
}
|
|
@@ -118,12 +119,12 @@ export const _testOnlyNextCommand = {
|
|
|
118
119
|
resolveNextCallerAuthor: (options, settingsAuthor) => resolveNextCallerAuthor(options, settingsAuthor),
|
|
119
120
|
};
|
|
120
121
|
/** Separates human-gated decisions from autonomous agent work unless the caller explicitly opts into decision claims. */
|
|
121
|
-
export function partitionDecisionEntries(ready, includeDecisions) {
|
|
122
|
-
const decisions = ready.filter((entry) => entry.item.type
|
|
122
|
+
export function partitionDecisionEntries(ready, includeDecisions, typeRegistry) {
|
|
123
|
+
const decisions = ready.filter((entry) => resolveItemExecutionRole(entry.item.type, typeRegistry) === "human");
|
|
123
124
|
return {
|
|
124
125
|
agent: includeDecisions
|
|
125
126
|
? ready
|
|
126
|
-
: ready.filter((entry) => entry.item.type
|
|
127
|
+
: ready.filter((entry) => resolveItemExecutionRole(entry.item.type, typeRegistry) !== "human"),
|
|
127
128
|
decisions: includeDecisions ? [] : decisions,
|
|
128
129
|
};
|
|
129
130
|
}
|
|
@@ -195,13 +196,17 @@ function buildNextRecommendation(params) {
|
|
|
195
196
|
reasons: buildRecommendationReasons(params.projectedReady[0], params.statusRegistry, params.now, params.completedContainer),
|
|
196
197
|
};
|
|
197
198
|
}
|
|
198
|
-
function buildNextSuggestions(recommended, blockedRows) {
|
|
199
|
+
function buildNextSuggestions(recommended, blockedRows, gateCount) {
|
|
199
200
|
if (recommended !== null) {
|
|
200
201
|
return undefined;
|
|
201
202
|
}
|
|
203
|
+
const gateGuidance = gateCount > 0
|
|
204
|
+
? ["No executable recommendation: outcome gates require verification. Inspect gate_needed, or use pm next --include-gates to opt in."]
|
|
205
|
+
: [];
|
|
202
206
|
if (blockedRows.length > 0) {
|
|
203
207
|
const blockedWithReferences = blockedRows.find((item) => item.blockers.length > 0);
|
|
204
208
|
return [
|
|
209
|
+
...gateGuidance,
|
|
205
210
|
blockedWithReferences
|
|
206
211
|
? `${blockedRows.length} item(s) are blocked; unblock the top one by closing ${blockedWithReferences.blockers.map((blocker) => blocker.id).join(", ")}`
|
|
207
212
|
: `${blockedRows.length} item(s) are blocked; add blocker context or move the top item back to an active status`,
|
|
@@ -210,6 +215,7 @@ function buildNextSuggestions(recommended, blockedRows) {
|
|
|
210
215
|
];
|
|
211
216
|
}
|
|
212
217
|
return [
|
|
218
|
+
...gateGuidance,
|
|
213
219
|
'pm create --type Task --title "..." to add a new work item',
|
|
214
220
|
"pm list --status in_progress to review work already underway",
|
|
215
221
|
"pm context --depth deep for the full project snapshot",
|
|
@@ -271,7 +277,7 @@ async function finalizeNextResult(params) {
|
|
|
271
277
|
params.result.ranking = toContextRankingSummary(params.readyRanking, params.featureStore);
|
|
272
278
|
params.result.packing = toContextPackingSummary(params.packing);
|
|
273
279
|
}
|
|
274
|
-
params.result.suggestions = buildNextSuggestions(params.recommended, params.blockedRows);
|
|
280
|
+
params.result.suggestions = buildNextSuggestions(params.recommended, params.blockedRows, params.gateCount);
|
|
275
281
|
await attachNextUsageFeedback({
|
|
276
282
|
result: params.result,
|
|
277
283
|
pmRoot: params.pmRoot,
|
|
@@ -291,9 +297,9 @@ function filterCandidatesByParentScope(candidates, corpus, parentScope) {
|
|
|
291
297
|
}
|
|
292
298
|
return candidates.filter((item) => subtree.ids.has(item.id.trim().toLowerCase()));
|
|
293
299
|
}
|
|
294
|
-
async function rankReadyEntriesWithRelevance(rankedReady, childrenByParent, statusRegistry, now, callerAuthor, pmRoot, tokenBudget) {
|
|
300
|
+
async function rankReadyEntriesWithRelevance(rankedReady, childrenByParent, statusRegistry, now, callerAuthor, pmRoot, tokenBudget, includeContainers) {
|
|
295
301
|
const concreteReady = rankedReady.filter((entry) => !hasCompletedDescendants(entry.item, childrenByParent));
|
|
296
|
-
const structuralReady = concreteReady.length
|
|
302
|
+
const structuralReady = includeContainers || concreteReady.length === 0 ? rankedReady : concreteReady;
|
|
297
303
|
const usage = await readContextUsageAffinity({
|
|
298
304
|
pmRoot,
|
|
299
305
|
author: callerAuthor,
|
|
@@ -316,7 +322,7 @@ async function rankReadyEntriesWithRelevance(rankedReady, childrenByParent, stat
|
|
|
316
322
|
return {
|
|
317
323
|
projectedReady,
|
|
318
324
|
ranking,
|
|
319
|
-
completedContainer: concreteReady.length === 0,
|
|
325
|
+
completedContainer: concreteReady.length === 0 && !includeContainers,
|
|
320
326
|
packing,
|
|
321
327
|
featureStore,
|
|
322
328
|
};
|
|
@@ -335,6 +341,7 @@ export async function runNext(options, global) {
|
|
|
335
341
|
const settings = await readSettings(pmRoot);
|
|
336
342
|
const callerAuthor = resolveNextCallerAuthor(options, settings.author_default);
|
|
337
343
|
const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
|
|
344
|
+
const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
|
|
338
345
|
const now = nowIso();
|
|
339
346
|
const limit = parseNextLimit(options.limit, "--limit", DEFAULT_NEXT_LIMIT);
|
|
340
347
|
const tokenBudget = resolveContextTokenBudget(options.tokenBudget, Math.max(192, limit * 128));
|
|
@@ -350,16 +357,18 @@ export async function runNext(options, global) {
|
|
|
350
357
|
const corpusList = await runList(undefined, { excludeTerminal: false, noTruncate: true }, global);
|
|
351
358
|
const candidates = filterCandidatesByParentScope(candidatesList.items, corpusList.items, parentScope);
|
|
352
359
|
const corpus = corpusList.items;
|
|
353
|
-
const report = computeActionabilityReport(candidates, corpus, statusRegistry);
|
|
360
|
+
const report = computeActionabilityReport(candidates, corpus, statusRegistry, typeRegistry);
|
|
354
361
|
const childrenByParent = buildChildrenByParent(corpus);
|
|
355
|
-
const
|
|
356
|
-
const callerPartition = partitionCallerOwnedReady(
|
|
362
|
+
const selected = selectActionableEntries(report, statusRegistry, options, typeRegistry);
|
|
363
|
+
const callerPartition = partitionCallerOwnedReady(selected.ready, settings.author_default, callerAuthor);
|
|
357
364
|
const rankedReady = rankNextReadyEntries(callerPartition.available, childrenByParent, statusRegistry);
|
|
358
365
|
const rankedBlocked = [...report.blocked].sort((left, right) => compareCriticalItems(left.item, right.item, statusRegistry));
|
|
359
|
-
const { projectedReady, ranking: readyRanking, completedContainer, packing: readyPacking, featureStore, } = await rankReadyEntriesWithRelevance(rankedReady, childrenByParent, statusRegistry, now, callerAuthor, pmRoot, tokenBudget);
|
|
366
|
+
const { projectedReady, ranking: readyRanking, completedContainer, packing: readyPacking, featureStore, } = await rankReadyEntriesWithRelevance(rankedReady, childrenByParent, statusRegistry, now, callerAuthor, pmRoot, tokenBudget, options.includeContainers === true);
|
|
360
367
|
const readyRows = projectedReady.map((entry, index) => toNextActionableItem(entry, statusRegistry, childrenByParent, index + 1));
|
|
361
368
|
const blockedRows = rankedBlocked.map((entry, index) => toNextActionableItem(entry, statusRegistry, childrenByParent, index + 1));
|
|
362
|
-
const decisionRows = rankNextReadyEntries(
|
|
369
|
+
const decisionRows = rankNextReadyEntries(selected.decisions, childrenByParent, statusRegistry).map((entry, index) => toNextActionableItem(entry, statusRegistry, childrenByParent, index + 1));
|
|
370
|
+
const gateRows = rankNextReadyEntries(selected.gates, childrenByParent, statusRegistry).map((entry, index) => toNextActionableItem(entry, statusRegistry, childrenByParent, index + 1));
|
|
371
|
+
const containerRows = rankNextReadyEntries(report.containers, childrenByParent, statusRegistry).map((entry, index) => toNextActionableItem(entry, statusRegistry, childrenByParent, index + 1));
|
|
363
372
|
const recommended = buildNextRecommendation({
|
|
364
373
|
projectedReady,
|
|
365
374
|
readyRows,
|
|
@@ -367,13 +376,19 @@ export async function runNext(options, global) {
|
|
|
367
376
|
now,
|
|
368
377
|
completedContainer,
|
|
369
378
|
});
|
|
370
|
-
const truncation = buildNextTruncation(decisionRows.length, callerPartition.held.length, limit);
|
|
379
|
+
const truncation = buildNextTruncation(decisionRows.length, callerPartition.held.length, limit) ?? {};
|
|
380
|
+
if (gateRows.length > limit)
|
|
381
|
+
truncation.gate_needed_total = gateRows.length;
|
|
382
|
+
if (containerRows.length > limit)
|
|
383
|
+
truncation.containers_total = containerRows.length;
|
|
371
384
|
const result = {
|
|
372
385
|
output_default: "toon",
|
|
373
386
|
now,
|
|
374
387
|
recommended,
|
|
375
388
|
ready: readyRows.slice(1, limit + 1),
|
|
376
389
|
decision_needed: decisionRows.slice(0, limit),
|
|
390
|
+
gate_needed: gateRows.slice(0, limit),
|
|
391
|
+
containers: containerRows.slice(0, limit),
|
|
377
392
|
blocked: readyOnly ? [] : blockedRows.slice(0, blockedLimit),
|
|
378
393
|
held_by_others: callerPartition.held.slice(0, limit),
|
|
379
394
|
summary: {
|
|
@@ -384,6 +399,7 @@ export async function runNext(options, global) {
|
|
|
384
399
|
candidates: report.active_count,
|
|
385
400
|
containers: report.container_count,
|
|
386
401
|
decision_needed: decisionRows.length,
|
|
402
|
+
gate_needed: gateRows.length,
|
|
387
403
|
held_by_others: callerPartition.held.length,
|
|
388
404
|
},
|
|
389
405
|
filters: {
|
|
@@ -399,14 +415,17 @@ export async function runNext(options, global) {
|
|
|
399
415
|
blocked_limit: blockedLimit,
|
|
400
416
|
ready_only: readyOnly,
|
|
401
417
|
include_decisions: options.includeDecisions === true,
|
|
418
|
+
include_gates: options.includeGates === true,
|
|
419
|
+
include_containers: options.includeContainers === true,
|
|
402
420
|
token_budget: tokenBudget,
|
|
403
421
|
},
|
|
404
|
-
truncation,
|
|
422
|
+
truncation: Object.keys(truncation).length > 0 ? truncation : undefined,
|
|
405
423
|
};
|
|
406
424
|
return finalizeNextResult({
|
|
407
425
|
result,
|
|
408
426
|
recommended,
|
|
409
427
|
blockedRows,
|
|
428
|
+
gateCount: gateRows.length,
|
|
410
429
|
candidatesWarnings: candidatesList.warnings,
|
|
411
430
|
corpusWarnings: corpusList.warnings,
|
|
412
431
|
readyRanking,
|
|
@@ -424,6 +443,10 @@ export async function runNext(options, global) {
|
|
|
424
443
|
*/
|
|
425
444
|
export function renderNextMarkdown(result) {
|
|
426
445
|
const lines = ["# pm next", "", ...renderNextSummaryLines(result)];
|
|
446
|
+
for (const [title, rows] of [["Gate verification needed", result.gate_needed], ["Containers", result.containers]]) {
|
|
447
|
+
if (rows && rows.length > 0)
|
|
448
|
+
lines.push(...renderNextSection(title, rows.map((item) => `- ${formatNextLine(item)}`), ""));
|
|
449
|
+
}
|
|
427
450
|
lines.push(...renderNextSection("Recommended", renderNextRecommendedRows(result.recommended), "No ready work."));
|
|
428
451
|
lines.push(...renderNextSection("Decision needed",
|
|
429
452
|
// `?? []` tolerates JSON payloads from pre-decision-queue builds (the
|
|
@@ -488,4 +511,4 @@ function formatNextLine(item) {
|
|
|
488
511
|
return `${rankToken}${item.id} p${item.priority} ${item.status} ${item.type} deadline:${deadlineToken}${parentToken}${unblocksToken} ${item.title}`;
|
|
489
512
|
}
|
|
490
513
|
//# sourceMappingURL=next.js.map
|
|
491
|
-
//# debugId=
|
|
514
|
+
//# debugId=6035e85b-81ed-512e-b291-b0d86af1848b
|
package/dist/sdk/query.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { CONTEXT_OUTPUT_VALUES, applyContextTagProjection, buildChildrenByParent
|
|
|
13
13
|
export * from "./query/get.js";
|
|
14
14
|
export * from "./query/history.js";
|
|
15
15
|
export * from "./query/next.js";
|
|
16
|
+
export * from "./actionability.js";
|
|
16
17
|
export * from "./query/search-pagination.js";
|
|
17
18
|
export * from "./query/search-rendering.js";
|
|
18
19
|
export * from "./query/item-filter-options.js";
|
|
@@ -27,3 +28,5 @@ export * from "./context-signal-store.js";
|
|
|
27
28
|
export * from "./context-usage.js";
|
|
28
29
|
export * from "./workspace-memory.js";
|
|
29
30
|
export * from "./duplicates.js";
|
|
31
|
+
export { analyzeDuplicateItems, type DuplicateItemInput, type DuplicateItemsAnalysis } from "./similarity.js";
|
|
32
|
+
export { measureItemMetadataReadWork, type ItemMetadataReadWork } from "../core/store/item-metadata-read-work.js";
|
package/dist/sdk/query.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Provides focused read, search, pagination, and context-ranking primitives.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="affe6060-5129-5914-9d4e-46c300d49080")}catch(e){}}();
|
|
8
8
|
export * from "./query/list.js";
|
|
9
9
|
export * from "./query/complete-list.js";
|
|
10
10
|
export * from "./query/search.js";
|
|
@@ -15,6 +15,7 @@ export { CONTEXT_OUTPUT_VALUES, applyContextTagProjection, buildChildrenByParent
|
|
|
15
15
|
export * from "./query/get.js";
|
|
16
16
|
export * from "./query/history.js";
|
|
17
17
|
export * from "./query/next.js";
|
|
18
|
+
export * from "./actionability.js";
|
|
18
19
|
export * from "./query/search-pagination.js";
|
|
19
20
|
export * from "./query/search-rendering.js";
|
|
20
21
|
export * from "./query/item-filter-options.js";
|
|
@@ -29,5 +30,7 @@ export * from "./context-signal-store.js";
|
|
|
29
30
|
export * from "./context-usage.js";
|
|
30
31
|
export * from "./workspace-memory.js";
|
|
31
32
|
export * from "./duplicates.js";
|
|
33
|
+
export { analyzeDuplicateItems } from "./similarity.js";
|
|
34
|
+
export { measureItemMetadataReadWork } from "../core/store/item-metadata-read-work.js";
|
|
32
35
|
//# sourceMappingURL=query.js.map
|
|
33
|
-
//# debugId=
|
|
36
|
+
//# debugId=affe6060-5129-5914-9d4e-46c300d49080
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* budgets and resolvable references to item facts served by earlier reads.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
8
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bb73f77d-d372-5d68-8ef2-90b208129f21")}catch(e){}}();
|
|
9
9
|
import { EXIT_CODE } from "../core/shared/constants.js";
|
|
10
10
|
import { PmCliError } from "../core/shared/errors.js";
|
|
11
11
|
import { mapReadOutputRows, readOutputRowCollections, } from "./read-output-rows.js";
|
|
@@ -119,7 +119,9 @@ function summarizeReadOutputSessionRows(result) {
|
|
|
119
119
|
continue;
|
|
120
120
|
}
|
|
121
121
|
const itemId = itemIdFromRow(row);
|
|
122
|
-
|
|
122
|
+
// Activity can contain workspace pseudo-identities. Preserve those rows
|
|
123
|
+
// in the response, but only carry ids the next invocation can consume.
|
|
124
|
+
if (itemId !== undefined && ITEM_ID_PATTERN.test(itemId))
|
|
123
125
|
deliveredIds.add(itemId);
|
|
124
126
|
}
|
|
125
127
|
}
|
|
@@ -204,4 +206,4 @@ export function readOutputSessionRemainingTokens(state) {
|
|
|
204
206
|
return Math.max(0, state.token_budget - state.spent_tokens);
|
|
205
207
|
}
|
|
206
208
|
//# sourceMappingURL=read-output-session.js.map
|
|
207
|
-
//# debugId=
|
|
209
|
+
//# debugId=bb73f77d-d372-5d68-8ef2-90b208129f21
|
|
@@ -34,7 +34,7 @@ export { isTerminalStatus, normalizeStatusForRegistry, normalizeStatusInput, } f
|
|
|
34
34
|
export { COMMON_MUTATION_COMMAND_OPTION_KEYS, type ItemTypeRegistry, type ResolvedItemTypeDefinition, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveCommandOptionPolicyState, resolveItemTypeRegistry, resolveTypeDefinition, resolveTypeName, validateTypeOptions, } from "../core/item/type-registry.js";
|
|
35
35
|
export { resolveTypeSynonym } from "../core/item/type-synonyms.js";
|
|
36
36
|
export { acquireLock } from "../core/lock/lock.js";
|
|
37
|
-
export { printError, printResult, writeStdout } from "../core/output/output.js";
|
|
37
|
+
export { printError, printResult, writeStderr, writeStdout } from "../core/output/output.js";
|
|
38
38
|
export { renderRowsAsCsv, renderRowsAsTable } from "../core/output/tabular.js";
|
|
39
39
|
export { parseLimit } from "../core/shared/numeric-parsers.js";
|
|
40
40
|
export { resolveConfiguredPmPackageRoot, resolvePmCliVersion, resolvePmPackageRootFromModule, } from "../core/packages/root.js";
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* prefer the typed operations exported by the main SDK barrel.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
10
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="619b20e3-78d9-55bd-9d2d-857a3bc1bee8")}catch(e){}}();
|
|
11
11
|
export { createCheckpointId, loadMutationCheckpoint, restoreCheckpointItems, writeMutationCheckpoint, } from "../core/checkpoint/mutation-checkpoint.js";
|
|
12
12
|
export { flattenFlagListValue, resolveFlagValueKind, } from "../core/extensions/flag-value-types.js";
|
|
13
13
|
export { createUnknownSubcommandError, } from "./agent/subcommand-recovery.js";
|
|
@@ -36,7 +36,7 @@ export { isTerminalStatus, normalizeStatusForRegistry, normalizeStatusInput, } f
|
|
|
36
36
|
export { COMMON_MUTATION_COMMAND_OPTION_KEYS, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveCommandOptionPolicyState, resolveItemTypeRegistry, resolveTypeDefinition, resolveTypeName, validateTypeOptions, } from "../core/item/type-registry.js";
|
|
37
37
|
export { resolveTypeSynonym } from "../core/item/type-synonyms.js";
|
|
38
38
|
export { acquireLock } from "../core/lock/lock.js";
|
|
39
|
-
export { printError, printResult, writeStdout } from "../core/output/output.js";
|
|
39
|
+
export { printError, printResult, writeStderr, writeStdout } from "../core/output/output.js";
|
|
40
40
|
export { renderRowsAsCsv, renderRowsAsTable } from "../core/output/tabular.js";
|
|
41
41
|
export { parseLimit } from "../core/shared/numeric-parsers.js";
|
|
42
42
|
export { resolveConfiguredPmPackageRoot, resolvePmCliVersion, resolvePmPackageRootFromModule, } from "../core/packages/root.js";
|
|
@@ -82,4 +82,4 @@ export { maybeRunFirstUseTelemetryPrompt } from "../core/telemetry/consent.js";
|
|
|
82
82
|
export { deriveTelemetryCommandResolution, } from "../core/telemetry/observability.js";
|
|
83
83
|
export { emitTelemetryErrorEvent, finishTelemetryCommand, startTelemetryCommand, } from "../core/telemetry/runtime.js";
|
|
84
84
|
//# sourceMappingURL=runtime-primitives.js.map
|
|
85
|
-
//# debugId=
|
|
85
|
+
//# debugId=619b20e3-78d9-55bd-9d2d-857a3bc1bee8
|
package/dist/sdk/runtime.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Defines public SDK APIs and package-author helpers for Runtime.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="422ff60b-97b1-5477-a7b8-ed4f983155e0")}catch(e){}}();
|
|
8
8
|
export { PM_GITIGNORE_END, PM_GITIGNORE_START, ensurePmGitignore, getPmGitignoreBlock, } from "./workspace.js";
|
|
9
9
|
export { SEARCH_EXTENSION_FLAG_DEFINITIONS } from "./extension-contracts.js";
|
|
10
10
|
export * from "./cli-contracts/agent-output-contracts.js";
|
|
@@ -1770,11 +1770,13 @@ const SDK_ACTION_HANDLERS = {
|
|
|
1770
1770
|
return runGet(id, ctx.global, applyContextIntentProjection("get", ctx.options, [id]));
|
|
1771
1771
|
},
|
|
1772
1772
|
search: runMcpSearchAction,
|
|
1773
|
+
/** Normalize MCP duplicate controls before delegating to the shared SDK action. */
|
|
1773
1774
|
duplicates: (ctx) => {
|
|
1774
1775
|
const status = typeof ctx.options.status === "string"
|
|
1775
1776
|
? [ctx.options.status]
|
|
1776
1777
|
: readStringArray(ctx.options.status);
|
|
1777
1778
|
return runDuplicates(ctx.global, {
|
|
1779
|
+
exhaustive: ctx.options.exhaustive === true,
|
|
1778
1780
|
...(status.length === 0 ? {} : { status }),
|
|
1779
1781
|
since: readString(ctx.options, "since"),
|
|
1780
1782
|
threshold: typeof ctx.options.threshold === "number"
|
|
@@ -1924,4 +1926,4 @@ async function loadWorkspaceExtensionRegistrations(pmRoot, settings, cwd) {
|
|
|
1924
1926
|
}
|
|
1925
1927
|
}
|
|
1926
1928
|
//# sourceMappingURL=runtime.js.map
|
|
1927
|
-
//# debugId=
|
|
1929
|
+
//# debugId=422ff60b-97b1-5477-a7b8-ed4f983155e0
|
package/dist/sdk/similarity.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { collectDuplicateCandidatePairs } from "./query/duplicate-candidates.js";
|
|
1
2
|
import type { ItemMetadata } from "../types/index.js";
|
|
2
3
|
import { type PreparedSimilarityText } from "./similarity-scoring.js";
|
|
3
4
|
export { jaccardSimilarity, normalizeSimilarityText, prepareSimilarityText, scoreItemSimilarity, scorePreparedItemSimilarity, tokenizeSimilarityText, type ItemSimilarityScore, type PreparedSimilarityText, } from "./similarity-scoring.js";
|
|
@@ -51,6 +52,8 @@ export interface SimilarItemsResult {
|
|
|
51
52
|
}
|
|
52
53
|
/** Query controls for one all-status duplicate-cluster sweep. */
|
|
53
54
|
export interface FindDuplicateClustersOptions extends FindSimilarItemsOptions {
|
|
55
|
+
/** Compare every pair as an exact oracle; retains the declared safety bound. */
|
|
56
|
+
exhaustive?: boolean;
|
|
54
57
|
/** Lifecycle statuses to include; omit to inspect every status. */
|
|
55
58
|
statuses?: readonly string[];
|
|
56
59
|
/** Inclusive ISO timestamp lower bound on item creation. */
|
|
@@ -97,6 +100,14 @@ export interface DuplicateClustersResult {
|
|
|
97
100
|
cost: {
|
|
98
101
|
/** Items retained after filters. */
|
|
99
102
|
item_count: number;
|
|
103
|
+
/** Algorithm used to generate candidates before canonical scoring. */
|
|
104
|
+
algorithm: "prefix_exact" | "exhaustive";
|
|
105
|
+
/** Pairs in the exhaustive population, including pairs pruned without scoring. */
|
|
106
|
+
possible_pairs: number;
|
|
107
|
+
/** Safety ceiling, exceeded only by an explicit refusal. */
|
|
108
|
+
pair_limit: number;
|
|
109
|
+
/** Every qualifying pair is retained by candidate generation. */
|
|
110
|
+
recall_guarantee: "exact";
|
|
100
111
|
/** Candidate pairs sharing at least one deterministic signal. */
|
|
101
112
|
candidate_pairs: number;
|
|
102
113
|
/** Candidate pairs scored. */
|
|
@@ -104,7 +115,7 @@ export interface DuplicateClustersResult {
|
|
|
104
115
|
};
|
|
105
116
|
}
|
|
106
117
|
interface PreparedDuplicateItem {
|
|
107
|
-
item: ItemMetadata
|
|
118
|
+
item: Pick<ItemMetadata, "id" | "title" | "status" | "type">;
|
|
108
119
|
prepared: PreparedSimilarityText;
|
|
109
120
|
}
|
|
110
121
|
/** Create/copy governance envelope attached when likely duplicates exist. */
|
|
@@ -131,7 +142,6 @@ export interface SimilarityRecovery {
|
|
|
131
142
|
}
|
|
132
143
|
/** Render compact warning tokens shared by create and copy results. */
|
|
133
144
|
export declare function similarityAdvisoryWarnings(advisory: SimilarityAdvisory | undefined): string[];
|
|
134
|
-
declare function collectDuplicateCandidatePairs(items: PreparedDuplicateItem[], maxPairEvaluations?: number): Set<string>;
|
|
135
145
|
/** Internal deterministic seams used to prove bounded batch behavior without building a million-pair fixture. */
|
|
136
146
|
export declare const _testOnlySimilarity: {
|
|
137
147
|
buildDuplicateClusters: typeof buildDuplicateClusters;
|
|
@@ -142,10 +152,21 @@ declare function createDuplicateUnionFind(size: number): {
|
|
|
142
152
|
parent: number[];
|
|
143
153
|
findRoot: (index: number) => number;
|
|
144
154
|
};
|
|
155
|
+
/** Group unioned endpoints and their scored evidence once, then deterministically rank and limit complete components. */
|
|
145
156
|
declare function buildDuplicateClusters(items: PreparedDuplicateItem[], matches: DuplicateClusterMatch[], union: ReturnType<typeof createDuplicateUnionFind>, limit: number): DuplicateCluster[];
|
|
146
157
|
/** Find likely existing duplicates through an index-first bounded read. */
|
|
147
158
|
export declare function findSimilarItems(candidate: SimilarItemCandidate, options?: FindSimilarItemsOptions): Promise<SimilarItemsResult>;
|
|
148
|
-
/**
|
|
159
|
+
/** Minimal metadata accepted from package-owned or remote project stores. */
|
|
160
|
+
export type DuplicateItemInput = Pick<ItemMetadata, "id" | "title" | "status" | "type">;
|
|
161
|
+
/** Exact in-memory duplicate analysis, independent of a filesystem workspace. */
|
|
162
|
+
export type DuplicateItemsAnalysis = Omit<DuplicateClustersResult, "source" | "filters">;
|
|
163
|
+
/**
|
|
164
|
+
* Cluster caller-owned metadata using the same scorer and safety bounds as the CLI.
|
|
165
|
+
* Candidate filtering is lossless; exhaustive mode provides an independent pair
|
|
166
|
+
* population for recall checks. Inputs are copied, sorted and never mutated.
|
|
167
|
+
*/
|
|
168
|
+
export declare function analyzeDuplicateItems(input: readonly DuplicateItemInput[], options?: Pick<FindDuplicateClustersOptions, "threshold" | "limit" | "exhaustive">): DuplicateItemsAnalysis;
|
|
169
|
+
/** Find connected duplicate clusters with one metadata read and shared package analysis. */
|
|
149
170
|
export declare function findDuplicateClusters(options?: FindDuplicateClustersOptions): Promise<DuplicateClustersResult>;
|
|
150
171
|
/** Apply off/advisory/strict mutation governance through the shared query. */
|
|
151
172
|
export declare function evaluateSimilarityGovernance(candidate: SimilarItemCandidate, options: FindSimilarItemsOptions & {
|
package/dist/sdk/similarity.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* governance and package-owned duplicate analysis.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
8
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9baf5711-9796-57e8-99e5-8990fd481ef8")}catch(e){}}();
|
|
9
9
|
import { EXIT_CODE } from "../core/shared/constants.js";
|
|
10
10
|
import { PmCliError } from "../core/shared/errors.js";
|
|
11
11
|
import { resolveItemTypeRegistry } from "../core/item/type-registry.js";
|
|
@@ -16,6 +16,7 @@ import { resolvePmRoot } from "../core/store/paths.js";
|
|
|
16
16
|
import { readSettings } from "../core/store/settings.js";
|
|
17
17
|
import { readItemMetadataDerivedIndexState } from "../core/store/item-metadata-cache.js";
|
|
18
18
|
import { querySimilarItemMetadataIndex } from "../core/store/item-metadata-query-index.js";
|
|
19
|
+
import { collectDuplicateCandidatePairs, MAX_DUPLICATE_CANDIDATE_PAIRS } from "./query/duplicate-candidates.js";
|
|
19
20
|
import { prepareSimilarityText, scoreItemSimilarity, scorePreparedItemSimilarity, tokenizeSimilarityText, } from "./similarity-scoring.js";
|
|
20
21
|
export { jaccardSimilarity, normalizeSimilarityText, prepareSimilarityText, scoreItemSimilarity, scorePreparedItemSimilarity, tokenizeSimilarityText, } from "./similarity-scoring.js";
|
|
21
22
|
const DEFAULT_SIMILARITY_LIMIT = 3;
|
|
@@ -23,7 +24,6 @@ const MAX_SIMILARITY_LIMIT = 20;
|
|
|
23
24
|
const DEFAULT_SIMILARITY_THRESHOLD = 0.8;
|
|
24
25
|
const DEFAULT_DUPLICATE_CLUSTER_LIMIT = 100;
|
|
25
26
|
const MAX_DUPLICATE_CLUSTER_LIMIT = 1_000;
|
|
26
|
-
const MAX_BATCH_PAIR_EVALUATIONS = 1_000_000;
|
|
27
27
|
/** Render compact warning tokens shared by create and copy results. */
|
|
28
28
|
export function similarityAdvisoryWarnings(advisory) {
|
|
29
29
|
return advisory === undefined
|
|
@@ -80,7 +80,8 @@ function validateDuplicateClusterOptions(options) {
|
|
|
80
80
|
}
|
|
81
81
|
return { limit, since };
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
/** Resolve registered statuses and load the metadata population before applying status and creation-time filters. */
|
|
84
|
+
async function loadDuplicateItems(options, since) {
|
|
84
85
|
const pmRoot = resolvePmRoot(options.cwd ?? process.cwd(), options.pmRoot);
|
|
85
86
|
const settings = await readSettings(pmRoot);
|
|
86
87
|
const typeRegistry = resolveItemTypeRegistry(settings);
|
|
@@ -111,43 +112,10 @@ async function loadPreparedDuplicateItems(options, since) {
|
|
|
111
112
|
return {
|
|
112
113
|
items: (await listAllItemMetadataLight(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema))
|
|
113
114
|
.filter((item) => (!allowedStatuses || allowedStatuses.has(item.status)) &&
|
|
114
|
-
(!since || new Date(item.created_at).getTime() >= since.getTime()))
|
|
115
|
-
.sort((left, right) => left.id.localeCompare(right.id))
|
|
116
|
-
.map((item) => ({ item, prepared: prepareSimilarityText(item.title) })),
|
|
115
|
+
(!since || new Date(item.created_at).getTime() >= since.getTime())),
|
|
117
116
|
statuses: effectiveStatuses,
|
|
118
117
|
};
|
|
119
118
|
}
|
|
120
|
-
function collectDuplicateCandidatePairs(items, maxPairEvaluations = MAX_BATCH_PAIR_EVALUATIONS) {
|
|
121
|
-
const candidates = new Set();
|
|
122
|
-
const indexes = [
|
|
123
|
-
new Map(),
|
|
124
|
-
new Map(),
|
|
125
|
-
new Map(),
|
|
126
|
-
];
|
|
127
|
-
for (const [index, entry] of items.entries()) {
|
|
128
|
-
const signals = [
|
|
129
|
-
[entry.prepared.normalized],
|
|
130
|
-
entry.prepared.issueCodes,
|
|
131
|
-
entry.prepared.tokens,
|
|
132
|
-
];
|
|
133
|
-
for (const [signalKind, values] of signals.entries()) {
|
|
134
|
-
for (const value of values) {
|
|
135
|
-
const matches = indexes[signalKind].get(value) ?? [];
|
|
136
|
-
for (const other of matches)
|
|
137
|
-
candidates.add(`${other}:${index}`);
|
|
138
|
-
if (candidates.size > maxPairEvaluations) {
|
|
139
|
-
throw new PmCliError(`Duplicate sweep exceeded ${MAX_BATCH_PAIR_EVALUATIONS} candidate pairs; narrow it with statuses or since.`, EXIT_CODE.CONFLICT, {
|
|
140
|
-
code: "duplicate_sweep_cost_limit",
|
|
141
|
-
required: "Narrow the batch duplicate query until its deterministic candidate set fits the disclosed safety bound.",
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
matches.push(index);
|
|
145
|
-
indexes[signalKind].set(value, matches);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return candidates;
|
|
150
|
-
}
|
|
151
119
|
/** Internal deterministic seams used to prove bounded batch behavior without building a million-pair fixture. */
|
|
152
120
|
export const _testOnlySimilarity = {
|
|
153
121
|
buildDuplicateClusters,
|
|
@@ -190,6 +158,7 @@ function scoreDuplicateCandidates(items, candidates, threshold, union) {
|
|
|
190
158
|
}
|
|
191
159
|
return matches;
|
|
192
160
|
}
|
|
161
|
+
/** Group unioned endpoints and their scored evidence once, then deterministically rank and limit complete components. */
|
|
193
162
|
function buildDuplicateClusters(items, matches, union, limit) {
|
|
194
163
|
const components = new Map();
|
|
195
164
|
for (const index of items.keys()) {
|
|
@@ -198,12 +167,19 @@ function buildDuplicateClusters(items, matches, union, limit) {
|
|
|
198
167
|
component.push(index);
|
|
199
168
|
components.set(root, component);
|
|
200
169
|
}
|
|
170
|
+
const rootsById = new Map(items.map(({ item }, index) => [item.id, union.findRoot(index)]));
|
|
171
|
+
const matchesByRoot = new Map();
|
|
172
|
+
for (const match of matches) {
|
|
173
|
+
// Scored matches have already joined both endpoints in the union above.
|
|
174
|
+
const root = rootsById.get(match.left_id);
|
|
175
|
+
const rows = matchesByRoot.get(root) ?? [];
|
|
176
|
+
rows.push(match);
|
|
177
|
+
matchesByRoot.set(root, rows);
|
|
178
|
+
}
|
|
201
179
|
return [...components.values()]
|
|
202
180
|
.filter((component) => component.length > 1)
|
|
203
181
|
.map((component) => {
|
|
204
|
-
const
|
|
205
|
-
const clusterMatches = matches
|
|
206
|
-
.filter((match) => ids.has(match.left_id) && ids.has(match.right_id))
|
|
182
|
+
const clusterMatches = (matchesByRoot.get(union.findRoot(component[0])) ?? [])
|
|
207
183
|
.sort((left, right) => right.score - left.score ||
|
|
208
184
|
left.left_id.localeCompare(right.left_id) ||
|
|
209
185
|
left.right_id.localeCompare(right.right_id));
|
|
@@ -272,15 +248,24 @@ export async function findSimilarItems(candidate, options = {}) {
|
|
|
272
248
|
source: indexed ? "persistent_index" : "metadata_fallback",
|
|
273
249
|
};
|
|
274
250
|
}
|
|
275
|
-
/**
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const {
|
|
282
|
-
const {
|
|
283
|
-
const
|
|
251
|
+
/**
|
|
252
|
+
* Cluster caller-owned metadata using the same scorer and safety bounds as the CLI.
|
|
253
|
+
* Candidate filtering is lossless; exhaustive mode provides an independent pair
|
|
254
|
+
* population for recall checks. Inputs are copied, sorted and never mutated.
|
|
255
|
+
*/
|
|
256
|
+
export function analyzeDuplicateItems(input, options = {}) {
|
|
257
|
+
const { threshold } = validateSimilarityOptions({ ...options, limit: undefined });
|
|
258
|
+
const { limit } = validateDuplicateClusterOptions(options);
|
|
259
|
+
const ids = new Set();
|
|
260
|
+
for (const item of input) {
|
|
261
|
+
if (!item.id.trim() || ids.has(item.id)) {
|
|
262
|
+
throw new PmCliError("Duplicate analysis requires unique non-empty item ids.", EXIT_CODE.USAGE);
|
|
263
|
+
}
|
|
264
|
+
ids.add(item.id);
|
|
265
|
+
}
|
|
266
|
+
const items = [...input].sort((left, right) => left.id.localeCompare(right.id))
|
|
267
|
+
.map((item) => ({ item, prepared: prepareSimilarityText(item.title) }));
|
|
268
|
+
const candidates = collectDuplicateCandidatePairs(items, MAX_DUPLICATE_CANDIDATE_PAIRS, threshold, options.exhaustive === true);
|
|
284
269
|
const union = createDuplicateUnionFind(items.length);
|
|
285
270
|
const matches = scoreDuplicateCandidates(items, candidates, threshold, union);
|
|
286
271
|
const clusters = buildDuplicateClusters(items, matches, union, limit);
|
|
@@ -288,18 +273,28 @@ export async function findDuplicateClusters(options = {}) {
|
|
|
288
273
|
clusters,
|
|
289
274
|
count: clusters.length,
|
|
290
275
|
threshold,
|
|
291
|
-
source: "metadata_scan",
|
|
292
|
-
filters: {
|
|
293
|
-
statuses: statuses ?? null,
|
|
294
|
-
since: options.since ?? null,
|
|
295
|
-
},
|
|
296
276
|
cost: {
|
|
297
277
|
item_count: items.length,
|
|
278
|
+
algorithm: options.exhaustive === true || threshold === 0 ? "exhaustive" : "prefix_exact",
|
|
279
|
+
possible_pairs: items.length * (items.length - 1) / 2,
|
|
280
|
+
pair_limit: MAX_DUPLICATE_CANDIDATE_PAIRS,
|
|
281
|
+
recall_guarantee: "exact",
|
|
298
282
|
candidate_pairs: candidates.size,
|
|
299
283
|
scored_pairs: candidates.size,
|
|
300
284
|
},
|
|
301
285
|
};
|
|
302
286
|
}
|
|
287
|
+
/** Find connected duplicate clusters with one metadata read and shared package analysis. */
|
|
288
|
+
export async function findDuplicateClusters(options = {}) {
|
|
289
|
+
validateSimilarityOptions({ ...options, limit: undefined });
|
|
290
|
+
const { since } = validateDuplicateClusterOptions(options);
|
|
291
|
+
const { items, statuses } = await loadDuplicateItems(options, since);
|
|
292
|
+
return {
|
|
293
|
+
...analyzeDuplicateItems(items, options),
|
|
294
|
+
source: "metadata_scan",
|
|
295
|
+
filters: { statuses: statuses ?? null, since: options.since ?? null },
|
|
296
|
+
};
|
|
297
|
+
}
|
|
303
298
|
/** Apply off/advisory/strict mutation governance through the shared query. */
|
|
304
299
|
export async function evaluateSimilarityGovernance(candidate, options) {
|
|
305
300
|
if (options.mode === "off")
|
|
@@ -329,4 +324,4 @@ export async function evaluateSimilarityGovernance(candidate, options) {
|
|
|
329
324
|
return { mode: options.mode, bypassed, result, recovery };
|
|
330
325
|
}
|
|
331
326
|
//# sourceMappingURL=similarity.js.map
|
|
332
|
-
//# debugId=
|
|
327
|
+
//# debugId=9baf5711-9796-57e8-99e5-8990fd481ef8
|
package/dist/types.d.ts
CHANGED
|
@@ -428,6 +428,8 @@ export interface ItemTypeDefinition {
|
|
|
428
428
|
description?: string;
|
|
429
429
|
/** Status assigned to newly created items of this type when `--status` is not provided. Falls back to the workflow's open status when unset or invalid. */
|
|
430
430
|
default_status?: string;
|
|
431
|
+
/** Agent work can be dispatched automatically; human work needs a decision, and gates track outcomes. Omission inherits the built-in role or defaults custom types to agent work. */
|
|
432
|
+
execution_role?: "agent" | "human" | "gate";
|
|
431
433
|
/** Value that configures or reports folder for this contract. */
|
|
432
434
|
folder?: string;
|
|
433
435
|
/** Value that configures or reports aliases for this contract. */
|
package/dist/types.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/** Supported values accepted by the builtin item type contract. */
|
|
7
7
|
|
|
8
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
8
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8173bdb0-39c8-56c0-85c2-5c39f5c213cc")}catch(e){}}();
|
|
9
9
|
export const BUILTIN_ITEM_TYPE_VALUES = [
|
|
10
10
|
"Epic",
|
|
11
11
|
"Feature",
|
|
@@ -243,4 +243,4 @@ export const CONTEXT_SECTION_VALUES = [
|
|
|
243
243
|
"tests",
|
|
244
244
|
];
|
|
245
245
|
//# sourceMappingURL=types.js.map
|
|
246
|
-
//# debugId=
|
|
246
|
+
//# debugId=8173bdb0-39c8-56c0-85c2-5c39f5c213cc
|