@unbrained/pm-cli 2026.8.9 → 2026.8.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +142 -80
- package/dist/cli/commander-usage.js +94 -17
- package/dist/cli/error-guidance.d.ts +10 -0
- package/dist/cli/error-guidance.js +76 -25
- package/dist/cli/help-json-payload.js +51 -16
- package/dist/cli/main.js +11 -6
- package/dist/cli/register-assurance.d.ts +8 -0
- package/dist/cli/register-assurance.js +52 -0
- package/dist/cli/register-files-lookup.js +14 -3
- package/dist/cli/register-mutation.js +30 -9
- package/dist/cli/register-operations.js +16 -11
- package/dist/cli-bundle/bundle-manifest.json +163 -163
- package/dist/cli-bundle/chunks/{chunk-RJC7TPF4.js → chunk-2OOU2AFH.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-2RA2YTHJ.js +33 -0
- package/dist/cli-bundle/chunks/chunk-A2SJGHSI.js +3 -0
- package/dist/cli-bundle/chunks/chunk-DSKYD4LG.js +13 -0
- package/dist/cli-bundle/chunks/chunk-HC3GM6YY.js +194 -0
- package/dist/cli-bundle/chunks/chunk-IUNRVDAI.js +2 -0
- package/dist/cli-bundle/chunks/chunk-W7CPZGSB.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-YC3UF2IO.js → chunk-WMEZHCFI.js} +66 -60
- package/dist/cli-bundle/chunks/{chunk-GMX5YOI3.js → chunk-ZU34C3LH.js} +48 -48
- package/dist/cli-bundle/chunks/chunk-ZXOC6HG5.js +5 -0
- package/dist/cli-bundle/chunks/{register-list-query-BUE7PTCU.js → register-list-query-HAUXVUPY.js} +8 -8
- package/dist/cli-bundle/chunks/register-mutation-7Y5U7ABT.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-EQX3DLAZ.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-UQDTNTLJ.js → register-setup-NOCOOWQY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-KNEHLPBF.js → chunk-23FTGO3W.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-6DO4YQWZ.js → chunk-2DL3MRTD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-3AYKXMYX.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-4AHEC74N.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-MRWVJ3ZG.js → chunk-4H5IA6AV.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4SV3ZKG3.js +16 -0
- package/dist/cli-bundle/focused-chunks/chunk-55BIB6DV.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-6JW6Z2P5.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-BKPIY34S.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-D4PIWE6D.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-DPO7TEFX.js +31 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3WVHTUAW.js → chunk-E3KCL7AY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ERAAFLPS.js +153 -0
- package/dist/cli-bundle/focused-chunks/chunk-F6E4JZKG.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-FPSYO5ZG.js +18 -0
- package/dist/cli-bundle/focused-chunks/{chunk-73FIJONU.js → chunk-J5EKAIVD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-KDH5OX3D.js +4 -0
- package/dist/cli-bundle/focused-chunks/chunk-OJ3LVVIS.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-TL5M2PAY.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-UDAZWT25.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-VABB4L5Y.js +17 -0
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +41 -39
- 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 +1 -1
- 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 +2 -2
- package/dist/core/diagnostics/remediation.js +9 -9
- package/dist/core/fs/fs-utils.d.ts +10 -0
- package/dist/core/fs/fs-utils.js +16 -4
- package/dist/core/item/item-format.js +3 -32
- package/dist/core/schema/fields-file.d.ts +1 -2
- package/dist/core/schema/fields-file.js +4 -11
- package/dist/core/schema/runtime-schema.js +3 -10
- package/dist/core/schema/status-defs-file.d.ts +1 -2
- package/dist/core/schema/status-defs-file.js +4 -32
- package/dist/core/schema/status-token.d.ts +2 -0
- package/dist/core/schema/status-token.js +32 -0
- package/dist/core/schema/type-workflows.d.ts +1 -2
- package/dist/core/schema/type-workflows.js +4 -11
- package/dist/core/session/session-state.d.ts +47 -0
- package/dist/core/session/session-state.js +207 -6
- package/dist/core/shared/author.d.ts +8 -2
- package/dist/core/shared/author.js +85 -52
- package/dist/core/shared/errors.d.ts +12 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/shared/text-normalization.d.ts +1 -1
- package/dist/core/shared/text-normalization.js +2 -2
- package/dist/sdk/agent/command-recovery.d.ts +4 -0
- package/dist/sdk/agent/command-recovery.js +52 -0
- package/dist/sdk/agent/command-suggestions.d.ts +4 -0
- package/dist/sdk/agent/command-suggestions.js +67 -0
- package/dist/sdk/agent/create-option-policy.d.ts +12 -0
- package/dist/sdk/agent/create-option-policy.js +32 -0
- package/dist/sdk/agent/item-addressing.d.ts +19 -0
- package/dist/sdk/agent/item-addressing.js +208 -0
- package/dist/sdk/agent/refusal-reachability.d.ts +40 -0
- package/dist/sdk/agent/refusal-reachability.js +72 -0
- package/dist/sdk/agent/subcommand-recovery.d.ts +40 -0
- package/dist/sdk/agent/subcommand-recovery.js +84 -0
- package/dist/sdk/cli-bootstrap.d.ts +9 -1
- package/dist/sdk/cli-bootstrap.js +25 -10
- package/dist/sdk/cli-contracts/commander-mutation-options.js +16 -4
- package/dist/sdk/cli-contracts/completeness.js +13 -3
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts/enum-contracts.js +3 -2
- package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
- package/dist/sdk/cli-contracts/flag-contracts.js +77 -21
- package/dist/sdk/cli-contracts/registration-helpers.js +10 -2
- package/dist/sdk/cli-contracts/runtime-contracts.js +6 -3
- package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +513 -0
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +251 -0
- package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +6 -0
- package/dist/sdk/cli-contracts/tool-option-contracts.js +4 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +96 -4
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +49 -6
- package/dist/sdk/cli-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts.js +3 -3
- package/dist/sdk/completion.js +9 -3
- package/dist/sdk/config.js +9 -3
- package/dist/sdk/context/semantic-session-attribution.d.ts +32 -0
- package/dist/sdk/context/semantic-session-attribution.js +83 -0
- package/dist/sdk/context-intent-runtime.js +8 -5
- package/dist/sdk/context-signal-store.d.ts +34 -0
- package/dist/sdk/context-signal-store.js +24 -2
- package/dist/sdk/core-governance.d.ts +3 -1
- package/dist/sdk/core-governance.js +5 -3
- package/dist/sdk/core.d.ts +1 -1
- package/dist/sdk/core.js +2 -2
- package/dist/sdk/dependency-flag-validation.d.ts +15 -1
- package/dist/sdk/dependency-flag-validation.js +54 -2
- package/dist/sdk/error-code-catalog.d.ts +13 -0
- package/dist/sdk/error-code-catalog.js +35 -2
- package/dist/sdk/extension.js +18 -17
- package/dist/sdk/files.d.ts +11 -0
- package/dist/sdk/files.js +82 -24
- package/dist/sdk/generated-error-code-catalog.js +104 -13
- package/dist/sdk/governance/assurance-action-contracts.d.ts +7 -0
- package/dist/sdk/governance/assurance-action-contracts.js +5 -0
- package/dist/sdk/governance/assurance-action.d.ts +70 -0
- package/dist/sdk/governance/assurance-action.js +198 -0
- package/dist/sdk/governance/assurance-limits.d.ts +7 -0
- package/dist/sdk/governance/assurance-limits.js +11 -0
- package/dist/sdk/governance/assurance-runtime.d.ts +20 -0
- package/dist/sdk/governance/assurance-runtime.js +131 -0
- package/dist/sdk/governance/assurance.d.ts +432 -0
- package/dist/sdk/governance/assurance.js +689 -0
- package/dist/sdk/governance/health.js +14 -7
- package/dist/sdk/governance/provenance-health.d.ts +13 -0
- package/dist/sdk/governance/provenance-health.js +63 -17
- package/dist/sdk/governance/validate-item-reader.d.ts +13 -0
- package/dist/sdk/governance/validate-item-reader.js +18 -0
- package/dist/sdk/governance/validate.d.ts +2 -2
- package/dist/sdk/governance/validate.js +15 -6
- package/dist/sdk/graph/run.js +8 -3
- package/dist/sdk/index.d.ts +10 -1
- package/dist/sdk/index.js +12 -3
- package/dist/sdk/lifecycle/claim.js +18 -3
- package/dist/sdk/lifecycle/close.js +17 -14
- package/dist/sdk/lifecycle/create.d.ts +2 -0
- package/dist/sdk/lifecycle/create.js +62 -9
- package/dist/sdk/lifecycle/focus.js +13 -3
- package/dist/sdk/lifecycle/plan.js +8 -3
- package/dist/sdk/lifecycle/update-many.js +39 -27
- package/dist/sdk/lifecycle/update.d.ts +6 -1
- package/dist/sdk/lifecycle/update.js +47 -10
- package/dist/sdk/merge/index.d.ts +1 -1
- package/dist/sdk/merge/index.js +3 -3
- package/dist/sdk/merge/install.d.ts +4 -0
- package/dist/sdk/merge/install.js +28 -16
- package/dist/sdk/merge/receipts.d.ts +3 -0
- package/dist/sdk/merge/receipts.js +81 -17
- package/dist/sdk/output-projection.js +24 -4
- package/dist/sdk/provenance.d.ts +38 -0
- package/dist/sdk/provenance.js +64 -2
- package/dist/sdk/query/context.d.ts +2 -0
- package/dist/sdk/query/context.js +24 -10
- package/dist/sdk/query/light-metadata.d.ts +3 -0
- package/dist/sdk/query/light-metadata.js +19 -0
- package/dist/sdk/runtime-extended-actions.js +22 -5
- package/dist/sdk/runtime-primitives.d.ts +2 -0
- package/dist/sdk/runtime-primitives.js +4 -2
- package/dist/sdk/runtime.d.ts +8 -1
- package/dist/sdk/runtime.js +37 -28
- package/dist/sdk/schema-migration.js +7 -9
- package/dist/sdk/similarity-scoring.d.ts +1 -2
- package/dist/sdk/similarity-scoring.js +4 -16
- package/dist/sdk/telemetry.js +7 -4
- package/dist/sdk/traceability/runtime-files-lookup.d.ts +8 -0
- package/dist/sdk/traceability/runtime-files-lookup.js +33 -0
- package/dist/sdk/traceability/source-traceability.d.ts +102 -0
- package/dist/sdk/traceability/source-traceability.js +293 -0
- package/dist/sdk/workspace-snapshot.d.ts +4 -0
- package/dist/sdk/workspace-snapshot.js +24 -11
- package/dist/types.d.ts +8 -2
- package/dist/types.js +2 -2
- package/docs/AGENT_GUIDE.md +3 -1
- package/docs/ASSURANCE.md +132 -0
- package/docs/COMMANDS.md +8 -5
- package/docs/MERGE_SAFETY.md +7 -5
- package/docs/README.md +3 -5
- package/docs/READ_OUTPUT_CONTRACTS.md +2 -2
- package/docs/RELEASING.md +9 -5
- package/docs/SDK.md +44 -8
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +43 -6
- package/docs/SDK_CONTEXT.md +97 -0
- package/docs/SDK_CONTEXT_INTEGRITY.md +18 -3
- package/docs/SDK_EVIDENCE_TRACEABILITY.md +39 -1
- package/docs/SDK_RUNTIME_BOUNDARIES.md +36 -1
- package/docs/TESTING.md +12 -9
- package/docs/agent-task-token-baseline.json +2 -2
- package/docs/generated/AGENT_COMMAND_SURFACE.md +1 -0
- package/marketplace.json +2 -2
- package/package.json +7 -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/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/extensions/templates/index.ts +9 -3
- 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-codex/.codex-plugin/plugin.json +1 -1
- package/sdk/public-surface.json +1028 -48
- package/dist/cli-bundle/chunks/chunk-2DTCZXSD.js +0 -13
- package/dist/cli-bundle/chunks/chunk-5JO6R4BS.js +0 -3
- package/dist/cli-bundle/chunks/chunk-5KN4DZYV.js +0 -194
- package/dist/cli-bundle/chunks/chunk-EF43KODO.js +0 -2
- package/dist/cli-bundle/chunks/chunk-HUV2Z7IS.js +0 -28
- package/dist/cli-bundle/chunks/chunk-MHBVCUF2.js +0 -2
- package/dist/cli-bundle/chunks/chunk-PYO5GZU6.js +0 -5
- package/dist/cli-bundle/chunks/register-mutation-FC3XLVIK.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-YH2WAOXU.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-2VVP5RAA.js +0 -153
- package/dist/cli-bundle/focused-chunks/chunk-3GSFUDAI.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4H6MVCK3.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-54TZJ4BM.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-5NK5TJ5D.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-C3GCHDSQ.js +0 -31
- package/dist/cli-bundle/focused-chunks/chunk-JGRSQZJT.js +0 -18
- package/dist/cli-bundle/focused-chunks/chunk-NL57J7BZ.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-P6BBIQRG.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-PZAGVQNN.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-QDAO3XEK.js +0 -14
- package/dist/cli-bundle/focused-chunks/chunk-T4IGQCSY.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-U46GQJNY.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-VRXJSGIT.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-XC2ZW3CJ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZG54B4XG.js +0 -2
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* extension packages without loading tracker query infrastructure.
|
|
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]="dff9b113-2b29-5154-afbf-f191f2f556a6")}catch(e){}}();
|
|
9
|
+
import { jaccardSimilarity } from "../core/shared/text-normalization.js";
|
|
10
|
+
export { jaccardSimilarity } from "../core/shared/text-normalization.js";
|
|
9
11
|
const ISSUE_CODE_PATTERN = /\b[a-z][a-z0-9]*-\d+(?:-[a-z0-9]+)*\b/giu;
|
|
10
12
|
/** Normalize title text for exact comparisons and tokenization. */
|
|
11
13
|
export function normalizeSimilarityText(value) {
|
|
@@ -30,20 +32,6 @@ export function prepareSimilarityText(value) {
|
|
|
30
32
|
],
|
|
31
33
|
};
|
|
32
34
|
}
|
|
33
|
-
/** Measure set overlap between two token collections. */
|
|
34
|
-
export function jaccardSimilarity(leftTokens, rightTokens) {
|
|
35
|
-
const left = new Set(leftTokens);
|
|
36
|
-
const right = new Set(rightTokens);
|
|
37
|
-
const union = new Set([...left, ...right]);
|
|
38
|
-
if (union.size === 0)
|
|
39
|
-
return 1;
|
|
40
|
-
let intersection = 0;
|
|
41
|
-
for (const token of left) {
|
|
42
|
-
if (right.has(token))
|
|
43
|
-
intersection += 1;
|
|
44
|
-
}
|
|
45
|
-
return intersection / union.size;
|
|
46
|
-
}
|
|
47
35
|
/** Score two titles through the canonical exact, issue-code, and token signals. */
|
|
48
36
|
export function scoreItemSimilarity(leftTitle, rightTitle) {
|
|
49
37
|
return scorePreparedItemSimilarity(prepareSimilarityText(leftTitle), prepareSimilarityText(rightTitle));
|
|
@@ -63,4 +51,4 @@ export function scorePreparedItemSimilarity(left, right) {
|
|
|
63
51
|
};
|
|
64
52
|
}
|
|
65
53
|
//# sourceMappingURL=similarity-scoring.js.map
|
|
66
|
-
//# debugId=
|
|
54
|
+
//# debugId=dff9b113-2b29-5154-afbf-f191f2f556a6
|
package/dist/sdk/telemetry.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm telemetry command surface and its agent-facing runtime behavior.
|
|
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]="ad3110ca-e85b-5a7e-b0a1-591796c298eb")}catch(e){}}();
|
|
8
8
|
import fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { pathExists, readFileIfExists } from "../core/fs/fs-utils.js";
|
|
@@ -14,6 +14,7 @@ import { nowIso } from "../core/shared/time.js";
|
|
|
14
14
|
import { resolveGlobalPmRoot } from "../core/store/paths.js";
|
|
15
15
|
import { readSettings, writeSettings } from "../core/store/settings.js";
|
|
16
16
|
import { flushTelemetryQueueNow } from "../core/telemetry/runtime.js";
|
|
17
|
+
import { createUnknownSubcommandError } from "./agent/subcommand-recovery.js";
|
|
17
18
|
const TELEMETRY_QUEUE_RELATIVE_PATH = path.join("runtime", "telemetry", "events.jsonl");
|
|
18
19
|
const TELEMETRY_STATE_RELATIVE_PATH = path.join("runtime", "telemetry", "state.json");
|
|
19
20
|
const TELEMETRY_RUNTIME_RELATIVE_PATH = path.join("runtime", "telemetry");
|
|
@@ -161,8 +162,10 @@ const normalizeTelemetrySubcommand = (value) => {
|
|
|
161
162
|
}
|
|
162
163
|
// `value` is always a defined string here: an undefined subcommand normalizes
|
|
163
164
|
// to "status" above (a valid value) and never reaches this throw.
|
|
164
|
-
throw
|
|
165
|
-
|
|
165
|
+
throw createUnknownSubcommandError({
|
|
166
|
+
command_path: "telemetry",
|
|
167
|
+
token: value?.trim() || "<empty>",
|
|
168
|
+
allowed: TELEMETRY_SUBCOMMANDS,
|
|
166
169
|
examples: [
|
|
167
170
|
"pm telemetry status",
|
|
168
171
|
"pm telemetry flush",
|
|
@@ -400,4 +403,4 @@ export async function runTelemetry(options, _global) {
|
|
|
400
403
|
});
|
|
401
404
|
}
|
|
402
405
|
//# sourceMappingURL=telemetry.js.map
|
|
403
|
-
//# debugId=
|
|
406
|
+
//# debugId=ad3110ca-e85b-5a7e-b0a1-591796c298eb
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/traceability/runtime-files-lookup
|
|
3
|
+
*
|
|
4
|
+
* Projects transport-neutral action values into reverse source lookup options.
|
|
5
|
+
*/
|
|
6
|
+
import type { FilesLookupOptions } from "../files.js";
|
|
7
|
+
/** Convert bounded MCP/action values into the public files lookup contract. */
|
|
8
|
+
export declare function runtimeFilesLookupOptions(options: Readonly<Record<string, unknown>>, paths: string[], parseInteger: (value: unknown, label: string) => number | undefined): FilesLookupOptions;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
!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]="c2ef0de1-bc44-5550-862c-f3929334fbef")}catch(e){}}();
|
|
3
|
+
import { parseSourceLineRange } from "./source-traceability.js";
|
|
4
|
+
/** Convert bounded MCP/action values into the public files lookup contract. */
|
|
5
|
+
export function runtimeFilesLookupOptions(options, paths, parseInteger) {
|
|
6
|
+
let lineRange;
|
|
7
|
+
if (typeof options.lines === "string") {
|
|
8
|
+
lineRange = parseSourceLineRange(options.lines);
|
|
9
|
+
}
|
|
10
|
+
else if (options.lineRange !== undefined) {
|
|
11
|
+
if (options.lineRange === null ||
|
|
12
|
+
typeof options.lineRange !== "object" ||
|
|
13
|
+
Array.isArray(options.lineRange)) {
|
|
14
|
+
throw new RangeError("Source line range must be an object with numeric start and end values.");
|
|
15
|
+
}
|
|
16
|
+
lineRange = parseSourceLineRange(`${String(Reflect.get(options.lineRange, "start"))}:${String(Reflect.get(options.lineRange, "end"))}`);
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
paths,
|
|
20
|
+
scope: options.scope === "project" || options.scope === "global"
|
|
21
|
+
? options.scope
|
|
22
|
+
: undefined,
|
|
23
|
+
limit: parseInteger(options.limit, "files lookup limit"),
|
|
24
|
+
offset: parseInteger(options.offset, "files lookup offset"),
|
|
25
|
+
noTruncate: options.noTruncate === true,
|
|
26
|
+
strictRead: options.strictRead === true,
|
|
27
|
+
explain: options.explain === true,
|
|
28
|
+
lineRange,
|
|
29
|
+
decisionDepth: parseInteger(options.decisionDepth, "files lookup decision depth"),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=runtime-files-lookup.js.map
|
|
33
|
+
//# debugId=c2ef0de1-bc44-5550-862c-f3929334fbef
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { ItemMetadata, LinkedFile } from "../../types/index.js";
|
|
2
|
+
/** Inclusive one-based source range accepted by traceability lookup. */
|
|
3
|
+
export interface SourceLineRange {
|
|
4
|
+
/** First included source line. */
|
|
5
|
+
start: number;
|
|
6
|
+
/** Last included source line. */
|
|
7
|
+
end: number;
|
|
8
|
+
}
|
|
9
|
+
/** One evidence class supporting a source-to-item association. */
|
|
10
|
+
export interface SourceTraceabilityEvidence {
|
|
11
|
+
/** Evidence producer. */
|
|
12
|
+
kind: "linked_file" | "git_commit";
|
|
13
|
+
/** Linked path or abbreviated commit identifier. */
|
|
14
|
+
reference: string;
|
|
15
|
+
/** Number of selected lines attributed to this evidence. */
|
|
16
|
+
contribution_lines?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Rationale fields projected without arbitrary body or comment content. */
|
|
19
|
+
export interface SourceTraceabilityRationale {
|
|
20
|
+
/** User or project value statement. */
|
|
21
|
+
value: string | null;
|
|
22
|
+
/** Recorded timing rationale. */
|
|
23
|
+
why_now: string | null;
|
|
24
|
+
/** Recorded intended or achieved outcome. */
|
|
25
|
+
outcome: string | null;
|
|
26
|
+
/** Recorded implementation objective. */
|
|
27
|
+
objective: string | null;
|
|
28
|
+
}
|
|
29
|
+
/** Shortest typed path from source-owning work to a governing decision. */
|
|
30
|
+
export interface SourceDecisionPath {
|
|
31
|
+
/** Whether a unique decision path was found under the bound. */
|
|
32
|
+
status: "found" | "ambiguous" | "not_found";
|
|
33
|
+
/** Ordered item identifiers, including source work and decision. */
|
|
34
|
+
nodes: string[];
|
|
35
|
+
/** Relationship kinds connecting consecutive nodes. */
|
|
36
|
+
kinds: string[];
|
|
37
|
+
/** Equally short governing decision candidates. */
|
|
38
|
+
alternative_decision_ids: string[];
|
|
39
|
+
}
|
|
40
|
+
/** Explainable fields added to one reverse linked-file match. */
|
|
41
|
+
export interface SourceTraceabilityExplanation {
|
|
42
|
+
/** Higher values sort first within the original scheduling priority. */
|
|
43
|
+
score: number;
|
|
44
|
+
/** Selected source lines attributable to commits naming this item. */
|
|
45
|
+
contribution_lines: number;
|
|
46
|
+
/** Structured evidence supporting the association. */
|
|
47
|
+
evidence: SourceTraceabilityEvidence[];
|
|
48
|
+
/** Project rationale carried by the item. */
|
|
49
|
+
rationale: SourceTraceabilityRationale;
|
|
50
|
+
/** Governing decision path under the declared graph bound. */
|
|
51
|
+
decision_path: SourceDecisionPath;
|
|
52
|
+
/** Honest ambiguity codes; an empty list means no ambiguity was observed. */
|
|
53
|
+
ambiguities: string[];
|
|
54
|
+
}
|
|
55
|
+
/** Aggregate line-attribution receipt returned beside explained matches. */
|
|
56
|
+
export interface SourceTraceabilityReceipt {
|
|
57
|
+
/** Inclusive selected range, or null for path-only explanation. */
|
|
58
|
+
line_range: SourceLineRange | null;
|
|
59
|
+
/** Number of distinct blamed commits. */
|
|
60
|
+
blamed_commit_count: number;
|
|
61
|
+
/** Number of blamed commits whose message named at least one pm item. */
|
|
62
|
+
mapped_commit_count: number;
|
|
63
|
+
/** Number of blamed commits without an item reference. */
|
|
64
|
+
unmapped_commit_count: number;
|
|
65
|
+
/** Maximum relationship depth searched for a governing decision. */
|
|
66
|
+
decision_depth: number;
|
|
67
|
+
}
|
|
68
|
+
interface TraceabilityCandidate {
|
|
69
|
+
item: ItemMetadata;
|
|
70
|
+
files: LinkedFile[];
|
|
71
|
+
}
|
|
72
|
+
interface GitAttribution {
|
|
73
|
+
commitLines: Map<string, number>;
|
|
74
|
+
commitItems: Map<string, string[]>;
|
|
75
|
+
available: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** Parse an inclusive `start:end` source-line selector. */
|
|
78
|
+
export declare function parseSourceLineRange(value: string): SourceLineRange;
|
|
79
|
+
declare function parseBlameCommits(output: string): Map<string, number>;
|
|
80
|
+
declare function parseCommitItemReferences(output: string): Map<string, string[]>;
|
|
81
|
+
declare function shortestDecisionPath(itemId: string, corpus: readonly ItemMetadata[], maxDepth: number): SourceDecisionPath;
|
|
82
|
+
declare function mappedBlamedCommits(attribution: GitAttribution): string[];
|
|
83
|
+
/** Enrich reverse linked-file candidates with bounded source rationale. */
|
|
84
|
+
export declare function explainSourceTraceability(params: {
|
|
85
|
+
workspaceRoot: string;
|
|
86
|
+
paths: readonly string[];
|
|
87
|
+
candidates: readonly TraceabilityCandidate[];
|
|
88
|
+
corpus: readonly ItemMetadata[];
|
|
89
|
+
lineRange?: SourceLineRange;
|
|
90
|
+
decisionDepth?: number;
|
|
91
|
+
}): Promise<{
|
|
92
|
+
explanations: Map<string, SourceTraceabilityExplanation>;
|
|
93
|
+
receipt: SourceTraceabilityReceipt;
|
|
94
|
+
}>;
|
|
95
|
+
/** Internal parser and traversal seams for deterministic boundary tests. */
|
|
96
|
+
export declare const _testOnlySourceTraceability: {
|
|
97
|
+
mappedBlamedCommits: typeof mappedBlamedCommits;
|
|
98
|
+
parseBlameCommits: typeof parseBlameCommits;
|
|
99
|
+
parseCommitItemReferences: typeof parseCommitItemReferences;
|
|
100
|
+
shortestDecisionPath: typeof shortestDecisionPath;
|
|
101
|
+
};
|
|
102
|
+
export {};
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/source-traceability
|
|
3
|
+
*
|
|
4
|
+
* Composes linked-file evidence, bounded Git line attribution, item rationale,
|
|
5
|
+
* and typed relationship paths into an explainable source-to-work projection.
|
|
6
|
+
*/
|
|
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]="b8b3f729-be32-5a77-b08f-f616ee068e0f")}catch(e){}}();
|
|
9
|
+
import { execFile } from "node:child_process";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { assembleWorkspaceRelationshipGraph } from "../graph/assembly.js";
|
|
12
|
+
function runGit(workspaceRoot, args) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
execFile("git", [...args], {
|
|
15
|
+
cwd: workspaceRoot,
|
|
16
|
+
encoding: "utf8",
|
|
17
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
18
|
+
}, (error, stdout) => {
|
|
19
|
+
if (error)
|
|
20
|
+
reject(error);
|
|
21
|
+
else
|
|
22
|
+
resolve(stdout);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function validateLineRange(range) {
|
|
27
|
+
if (range &&
|
|
28
|
+
(!Number.isSafeInteger(range.start) ||
|
|
29
|
+
!Number.isSafeInteger(range.end) ||
|
|
30
|
+
range.start < 1 ||
|
|
31
|
+
range.end < range.start)) {
|
|
32
|
+
throw new RangeError("Source line range must be inclusive positive integers with end >= start.");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Parse an inclusive `start:end` source-line selector. */
|
|
36
|
+
export function parseSourceLineRange(value) {
|
|
37
|
+
const match = /^(\d+):(\d+)$/u.exec(value.trim());
|
|
38
|
+
const range = match
|
|
39
|
+
? { start: Number(match[1]), end: Number(match[2]) }
|
|
40
|
+
: undefined;
|
|
41
|
+
validateLineRange(range);
|
|
42
|
+
if (!range) {
|
|
43
|
+
throw new RangeError("Source line range must use start:end.");
|
|
44
|
+
}
|
|
45
|
+
return range;
|
|
46
|
+
}
|
|
47
|
+
function parseBlameCommits(output) {
|
|
48
|
+
const lines = new Map();
|
|
49
|
+
for (const row of output.split("\n")) {
|
|
50
|
+
const commit = /^([0-9a-f^]{40,64}) \d+ \d+(?: \d+)?$/u.exec(row)?.[1];
|
|
51
|
+
if (commit)
|
|
52
|
+
lines.set(commit, (lines.get(commit) ?? 0) + 1);
|
|
53
|
+
}
|
|
54
|
+
return lines;
|
|
55
|
+
}
|
|
56
|
+
function parseCommitItemReferences(output) {
|
|
57
|
+
const fields = output.split("\0");
|
|
58
|
+
const references = new Map();
|
|
59
|
+
for (let index = 0; index + 1 < fields.length; index += 2) {
|
|
60
|
+
const commit = fields[index]?.trim();
|
|
61
|
+
if (!commit)
|
|
62
|
+
continue;
|
|
63
|
+
const ids = [
|
|
64
|
+
...new Set(fields[index + 1]?.match(/\bpm-[a-z0-9][a-z0-9-]{2,63}\b/gu) ?? []),
|
|
65
|
+
].sort((left, right) => left.localeCompare(right));
|
|
66
|
+
references.set(commit, ids);
|
|
67
|
+
}
|
|
68
|
+
return references;
|
|
69
|
+
}
|
|
70
|
+
async function readGitAttribution(params) {
|
|
71
|
+
const relativePath = path.relative(params.workspaceRoot, path.resolve(params.workspaceRoot, params.sourcePath));
|
|
72
|
+
const blame = await runGit(params.workspaceRoot, [
|
|
73
|
+
"blame",
|
|
74
|
+
"--line-porcelain",
|
|
75
|
+
"-L",
|
|
76
|
+
`${params.lineRange.start},${params.lineRange.end}`,
|
|
77
|
+
"--",
|
|
78
|
+
relativePath,
|
|
79
|
+
]);
|
|
80
|
+
const log = await runGit(params.workspaceRoot, [
|
|
81
|
+
"log",
|
|
82
|
+
"-n",
|
|
83
|
+
"256",
|
|
84
|
+
"--format=%H%x00%B%x00",
|
|
85
|
+
"--",
|
|
86
|
+
relativePath,
|
|
87
|
+
]);
|
|
88
|
+
return {
|
|
89
|
+
commitLines: parseBlameCommits(blame),
|
|
90
|
+
commitItems: parseCommitItemReferences(log),
|
|
91
|
+
available: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function expandDecisionPath(params) {
|
|
95
|
+
const tail = params.current.nodes.at(-1);
|
|
96
|
+
const nextDepth = params.current.kinds.length + 1;
|
|
97
|
+
let foundDepth;
|
|
98
|
+
for (const edge of params.graph.incidentEdges(tail)) {
|
|
99
|
+
const outgoing = edge.source === tail;
|
|
100
|
+
const next = outgoing ? edge.target : edge.source;
|
|
101
|
+
if ((params.visitedDepth.get(next) ?? Number.POSITIVE_INFINITY) < nextDepth)
|
|
102
|
+
continue;
|
|
103
|
+
params.visitedDepth.set(next, nextDepth);
|
|
104
|
+
const definition = params.graph.registry().require(edge.kind);
|
|
105
|
+
const nextPath = {
|
|
106
|
+
nodes: [...params.current.nodes, next],
|
|
107
|
+
kinds: [
|
|
108
|
+
...params.current.kinds,
|
|
109
|
+
outgoing ? edge.kind : (definition.inverse ?? edge.kind),
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
if (params.details.get(next)?.type?.toLowerCase() === "decision") {
|
|
113
|
+
foundDepth = nextDepth;
|
|
114
|
+
params.found.push(nextPath);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
params.queue.push(nextPath);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return foundDepth;
|
|
121
|
+
}
|
|
122
|
+
function collectDecisionPaths(params) {
|
|
123
|
+
const queue = [
|
|
124
|
+
{ nodes: [params.itemId], kinds: [] },
|
|
125
|
+
];
|
|
126
|
+
const visitedDepth = new Map([[params.itemId, 0]]);
|
|
127
|
+
const found = [];
|
|
128
|
+
let foundDepth;
|
|
129
|
+
while (queue.length > 0) {
|
|
130
|
+
const current = queue.shift();
|
|
131
|
+
const depth = current.kinds.length;
|
|
132
|
+
if (foundDepth !== undefined && depth >= foundDepth)
|
|
133
|
+
continue;
|
|
134
|
+
if (depth >= params.maxDepth)
|
|
135
|
+
continue;
|
|
136
|
+
foundDepth =
|
|
137
|
+
expandDecisionPath({
|
|
138
|
+
current,
|
|
139
|
+
graph: params.graph,
|
|
140
|
+
details: params.details,
|
|
141
|
+
visitedDepth,
|
|
142
|
+
queue,
|
|
143
|
+
found,
|
|
144
|
+
}) ?? foundDepth;
|
|
145
|
+
}
|
|
146
|
+
found.sort((left, right) => left.nodes.join("\0").localeCompare(right.nodes.join("\0")));
|
|
147
|
+
return found;
|
|
148
|
+
}
|
|
149
|
+
function shortestDecisionPath(itemId, corpus, maxDepth) {
|
|
150
|
+
const assembly = assembleWorkspaceRelationshipGraph(corpus);
|
|
151
|
+
if (!assembly.graph.hasNode(itemId)) {
|
|
152
|
+
return {
|
|
153
|
+
status: "not_found",
|
|
154
|
+
nodes: [],
|
|
155
|
+
kinds: [],
|
|
156
|
+
alternative_decision_ids: [],
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const found = collectDecisionPaths({
|
|
160
|
+
itemId,
|
|
161
|
+
maxDepth,
|
|
162
|
+
graph: assembly.graph,
|
|
163
|
+
details: new Map(assembly.details.map((detail) => [detail.id, detail])),
|
|
164
|
+
});
|
|
165
|
+
const selected = found[0];
|
|
166
|
+
if (!selected) {
|
|
167
|
+
return {
|
|
168
|
+
status: "not_found",
|
|
169
|
+
nodes: [],
|
|
170
|
+
kinds: [],
|
|
171
|
+
alternative_decision_ids: [],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const decisionIds = [...new Set(found.map((entry) => entry.nodes.at(-1)))];
|
|
175
|
+
return {
|
|
176
|
+
status: decisionIds.length === 1 ? "found" : "ambiguous",
|
|
177
|
+
nodes: selected.nodes,
|
|
178
|
+
kinds: selected.kinds,
|
|
179
|
+
alternative_decision_ids: decisionIds.slice(1),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async function resolveGitAttribution(params) {
|
|
183
|
+
if (!params.lineRange) {
|
|
184
|
+
return {
|
|
185
|
+
commitLines: new Map(),
|
|
186
|
+
commitItems: new Map(),
|
|
187
|
+
available: true,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
return await readGitAttribution({
|
|
192
|
+
workspaceRoot: params.workspaceRoot,
|
|
193
|
+
sourcePath: params.paths[0],
|
|
194
|
+
lineRange: params.lineRange,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return {
|
|
199
|
+
commitLines: new Map(),
|
|
200
|
+
commitItems: new Map(),
|
|
201
|
+
available: false,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function sourceAmbiguities(params) {
|
|
206
|
+
const ambiguities = [];
|
|
207
|
+
if (params.hasLineRange && !params.attributionAvailable) {
|
|
208
|
+
ambiguities.push("git_attribution_unavailable");
|
|
209
|
+
}
|
|
210
|
+
if (params.hasLineRange && params.contributionLines === 0) {
|
|
211
|
+
ambiguities.push("line_attribution_unmapped");
|
|
212
|
+
}
|
|
213
|
+
if (params.decisionStatus === "ambiguous") {
|
|
214
|
+
ambiguities.push("multiple_governing_decisions");
|
|
215
|
+
}
|
|
216
|
+
if (params.decisionStatus === "not_found") {
|
|
217
|
+
ambiguities.push("governing_decision_not_found");
|
|
218
|
+
}
|
|
219
|
+
return ambiguities;
|
|
220
|
+
}
|
|
221
|
+
function mappedBlamedCommits(attribution) {
|
|
222
|
+
return [...attribution.commitLines.keys()].filter((commit) => (attribution.commitItems.get(commit)?.length ?? 0) > 0);
|
|
223
|
+
}
|
|
224
|
+
/** Enrich reverse linked-file candidates with bounded source rationale. */
|
|
225
|
+
export async function explainSourceTraceability(params) {
|
|
226
|
+
validateLineRange(params.lineRange);
|
|
227
|
+
const decisionDepth = params.decisionDepth ?? 8;
|
|
228
|
+
if (!Number.isSafeInteger(decisionDepth) ||
|
|
229
|
+
decisionDepth < 1 ||
|
|
230
|
+
decisionDepth > 32) {
|
|
231
|
+
throw new RangeError("Decision path depth must be an integer from 1 to 32.");
|
|
232
|
+
}
|
|
233
|
+
const attribution = await resolveGitAttribution(params);
|
|
234
|
+
const mappedCommits = mappedBlamedCommits(attribution);
|
|
235
|
+
const explanations = new Map();
|
|
236
|
+
for (const candidate of params.candidates) {
|
|
237
|
+
const attributedCommits = [...attribution.commitLines.entries()].filter(([commit]) => attribution.commitItems.get(commit)?.includes(candidate.item.id));
|
|
238
|
+
const contributionLines = attributedCommits.reduce((total, [, lines]) => total + lines, 0);
|
|
239
|
+
const decisionPath = shortestDecisionPath(candidate.item.id, params.corpus, decisionDepth);
|
|
240
|
+
const ambiguities = sourceAmbiguities({
|
|
241
|
+
hasLineRange: params.lineRange !== undefined,
|
|
242
|
+
attributionAvailable: attribution.available,
|
|
243
|
+
contributionLines,
|
|
244
|
+
decisionStatus: decisionPath.status,
|
|
245
|
+
});
|
|
246
|
+
explanations.set(candidate.item.id, {
|
|
247
|
+
score: contributionLines * 100 +
|
|
248
|
+
candidate.files.length * 10 +
|
|
249
|
+
Math.max(0, 9 -
|
|
250
|
+
Math.floor((Date.now() - Date.parse(candidate.item.updated_at)) /
|
|
251
|
+
(30 * 24 * 60 * 60 * 1000))),
|
|
252
|
+
contribution_lines: contributionLines,
|
|
253
|
+
evidence: [
|
|
254
|
+
...candidate.files.map((file) => ({
|
|
255
|
+
kind: "linked_file",
|
|
256
|
+
reference: file.path,
|
|
257
|
+
})),
|
|
258
|
+
...attributedCommits.map(([commit, lines]) => ({
|
|
259
|
+
kind: "git_commit",
|
|
260
|
+
reference: commit.slice(0, 12),
|
|
261
|
+
contribution_lines: lines,
|
|
262
|
+
})),
|
|
263
|
+
],
|
|
264
|
+
rationale: {
|
|
265
|
+
value: candidate.item.value?.trim() || null,
|
|
266
|
+
why_now: candidate.item.why_now?.trim() || null,
|
|
267
|
+
outcome: candidate.item.outcome?.trim() || null,
|
|
268
|
+
objective: candidate.item.objective?.trim() || null,
|
|
269
|
+
},
|
|
270
|
+
decision_path: decisionPath,
|
|
271
|
+
ambiguities,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
explanations,
|
|
276
|
+
receipt: {
|
|
277
|
+
line_range: params.lineRange ?? null,
|
|
278
|
+
blamed_commit_count: attribution.commitLines.size,
|
|
279
|
+
mapped_commit_count: mappedCommits.length,
|
|
280
|
+
unmapped_commit_count: attribution.commitLines.size - mappedCommits.length,
|
|
281
|
+
decision_depth: decisionDepth,
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/** Internal parser and traversal seams for deterministic boundary tests. */
|
|
286
|
+
export const _testOnlySourceTraceability = {
|
|
287
|
+
mappedBlamedCommits,
|
|
288
|
+
parseBlameCommits,
|
|
289
|
+
parseCommitItemReferences,
|
|
290
|
+
shortestDecisionPath,
|
|
291
|
+
};
|
|
292
|
+
//# sourceMappingURL=source-traceability.js.map
|
|
293
|
+
//# debugId=b8b3f729-be32-5a77-b08f-f616ee068e0f
|
|
@@ -19,10 +19,14 @@ declare class WorkspaceLockHeartbeat {
|
|
|
19
19
|
constructor(lockPath: string, owner: string, ttlSeconds: number);
|
|
20
20
|
/** Begin renewing the lock without keeping the process alive on its own. */
|
|
21
21
|
start(): void;
|
|
22
|
+
/** Force and await one owned renewal so callers can establish a fresh lease boundary. */
|
|
23
|
+
refreshNow(): Promise<void>;
|
|
22
24
|
/** Fail the restore before activation when lease ownership was lost. */
|
|
23
25
|
assertHealthy(): void;
|
|
24
26
|
/** Stop future renewals and await the last in-flight atomic write. */
|
|
25
27
|
stop(): Promise<void>;
|
|
28
|
+
/** Serialize renewal attempts and retain the first ownership failure. */
|
|
29
|
+
private scheduleRenewal;
|
|
26
30
|
/** Atomically refresh only the lock still owned by this process and actor. */
|
|
27
31
|
private renew;
|
|
28
32
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* state while excluding clone-local caches, locks, and recovery journals.
|
|
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]="470bb466-4619-5c54-a154-186b7ef4a049")}catch(e){}}();
|
|
9
9
|
import crypto from "node:crypto";
|
|
10
10
|
import { cp, lstat, mkdir, readFile, readdir, rename, rm, writeFile, } from "node:fs/promises";
|
|
11
11
|
import path from "node:path";
|
|
@@ -55,19 +55,18 @@ class WorkspaceLockHeartbeat {
|
|
|
55
55
|
}
|
|
56
56
|
/** Begin renewing the lock without keeping the process alive on its own. */
|
|
57
57
|
start() {
|
|
58
|
+
this.scheduleRenewal();
|
|
58
59
|
this.timer = setInterval(() => {
|
|
59
|
-
|
|
60
|
-
return;
|
|
61
|
-
this.refresh = this.renew()
|
|
62
|
-
.catch((error) => {
|
|
63
|
-
this.failure = error;
|
|
64
|
-
})
|
|
65
|
-
.finally(() => {
|
|
66
|
-
this.refresh = undefined;
|
|
67
|
-
});
|
|
60
|
+
this.scheduleRenewal();
|
|
68
61
|
}, this.intervalMs);
|
|
69
62
|
this.timer.unref();
|
|
70
63
|
}
|
|
64
|
+
/** Force and await one owned renewal so callers can establish a fresh lease boundary. */
|
|
65
|
+
async refreshNow() {
|
|
66
|
+
this.scheduleRenewal();
|
|
67
|
+
await this.refresh;
|
|
68
|
+
this.assertHealthy();
|
|
69
|
+
}
|
|
71
70
|
/** Fail the restore before activation when lease ownership was lost. */
|
|
72
71
|
assertHealthy() {
|
|
73
72
|
if (this.failure !== undefined) {
|
|
@@ -83,6 +82,18 @@ class WorkspaceLockHeartbeat {
|
|
|
83
82
|
await this.refresh;
|
|
84
83
|
this.assertHealthy();
|
|
85
84
|
}
|
|
85
|
+
/** Serialize renewal attempts and retain the first ownership failure. */
|
|
86
|
+
scheduleRenewal() {
|
|
87
|
+
if (this.refresh !== undefined || this.failure !== undefined)
|
|
88
|
+
return;
|
|
89
|
+
this.refresh = this.renew()
|
|
90
|
+
.catch((error) => {
|
|
91
|
+
this.failure = error;
|
|
92
|
+
})
|
|
93
|
+
.finally(() => {
|
|
94
|
+
this.refresh = undefined;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
86
97
|
/** Atomically refresh only the lock still owned by this process and actor. */
|
|
87
98
|
async renew() {
|
|
88
99
|
const parsed = JSON.parse(await readFile(this.lockPath, "utf8"));
|
|
@@ -483,6 +494,7 @@ export async function restoreWorkspaceSnapshotWithRecovery(pmRoot, target, optio
|
|
|
483
494
|
const releaseWorkspaceLock = await acquireLock(pmRoot, WORKSPACE_WRITER_LOCK_ID, lockTtlSeconds, author, false, false, lockWaitMs);
|
|
484
495
|
const heartbeat = new WorkspaceLockHeartbeat(getLockPath(pmRoot, WORKSPACE_WRITER_LOCK_ID), author, lockTtlSeconds);
|
|
485
496
|
heartbeat.start();
|
|
497
|
+
await heartbeat.refreshNow();
|
|
486
498
|
let staging;
|
|
487
499
|
let swapStarted = false;
|
|
488
500
|
let heartbeatStopped = false;
|
|
@@ -536,6 +548,7 @@ export async function restoreWorkspaceSnapshotWithRecovery(pmRoot, target, optio
|
|
|
536
548
|
await swapWorkspaceSnapshotRootWithActivation(staging, pmRoot, backup, DEFAULT_ATOMIC_OPERATIONS, async () => {
|
|
537
549
|
heartbeat.start();
|
|
538
550
|
heartbeatStopped = false;
|
|
551
|
+
await heartbeat.refreshNow();
|
|
539
552
|
});
|
|
540
553
|
await heartbeat.stop();
|
|
541
554
|
heartbeatStopped = true;
|
|
@@ -596,4 +609,4 @@ export async function deleteWorkspaceSnapshot(pmRoot, target) {
|
|
|
596
609
|
return { deleted: "object", target };
|
|
597
610
|
}
|
|
598
611
|
//# sourceMappingURL=workspace-snapshot.js.map
|
|
599
|
-
//# debugId=
|
|
612
|
+
//# debugId=470bb466-4619-5c54-a154-186b7ef4a049
|
package/dist/types.d.ts
CHANGED
|
@@ -743,7 +743,7 @@ export interface HistoryEntry {
|
|
|
743
743
|
/** Observed agent model identifier, retained in local history. */
|
|
744
744
|
agent_model?: string;
|
|
745
745
|
/** Bounded signal class that supplied `agent_model`. */
|
|
746
|
-
agent_model_source?: "override" | "environment" | "mcp_client" | "argv" | "host" | "session" | "probe";
|
|
746
|
+
agent_model_source?: "override" | "environment" | "mcp_client" | "argv" | "host" | "session" | "probe" | "inferred";
|
|
747
747
|
/** Privacy-safe fingerprint distinguishing concurrent harness invocations. */
|
|
748
748
|
agent_instance?: string;
|
|
749
749
|
/** Extensible local-only descriptive agent provenance; null means declared but unavailable. */
|
|
@@ -751,7 +751,13 @@ export interface HistoryEntry {
|
|
|
751
751
|
/** Bounded descriptive value observed for this dimension. */
|
|
752
752
|
value: string;
|
|
753
753
|
/** Bounded signal class that supplied the value. */
|
|
754
|
-
source: "override" | "environment" | "mcp_client" | "argv" | "host" | "session" | "probe";
|
|
754
|
+
source: "override" | "environment" | "mcp_client" | "argv" | "host" | "session" | "probe" | "inferred";
|
|
755
|
+
/** Confidence attached to a semantic inference. */
|
|
756
|
+
confidence?: "high" | "medium" | "low";
|
|
757
|
+
/** Versioned semantic inference rule. */
|
|
758
|
+
rule_version?: "v2";
|
|
759
|
+
/** Bounded item and lineage references supporting the inference. */
|
|
760
|
+
evidence?: readonly string[];
|
|
755
761
|
} | null>>;
|
|
756
762
|
/** Stable declared episode identity; absent on legacy or undeclared events. */
|
|
757
763
|
agent_episode?: {
|
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]="605cf12e-6106-563a-abc0-38d648d4aa43")}catch(e){}}();
|
|
9
9
|
export const BUILTIN_ITEM_TYPE_VALUES = [
|
|
10
10
|
"Epic",
|
|
11
11
|
"Feature",
|
|
@@ -241,4 +241,4 @@ export const CONTEXT_SECTION_VALUES = [
|
|
|
241
241
|
"tests",
|
|
242
242
|
];
|
|
243
243
|
//# sourceMappingURL=types.js.map
|
|
244
|
-
//# debugId=
|
|
244
|
+
//# debugId=605cf12e-6106-563a-abc0-38d648d4aa43
|
package/docs/AGENT_GUIDE.md
CHANGED
|
@@ -50,7 +50,9 @@ Repeated singular/plural list flags accumulate, so `--tag a --tag b` is equivale
|
|
|
50
50
|
|
|
51
51
|
`--tags` REPLACES the whole tag list. To edit tags without restating the full set, prefer `--add-tags <value>` (adds without replacing) and `--remove-tags <value>` (prunes) on `create`/`update`/`update-many` (both repeatable; CSV or JSON-array). `--remove-tags` is `update`/`update-many` only. Also note `--expected`/`--actual` are short aliases for `--expected-result`/`--actual-result` on these commands, matching `pm close`.
|
|
52
52
|
|
|
53
|
-
`--acceptance-criteria`/`--ac` likewise REPLACES the whole criteria value
|
|
53
|
+
`--acceptance-criteria`/`--ac` likewise explicitly REPLACES the whole criteria value and cannot be combined with `--add-ac` or `--remove-ac`. Prefer `--add-ac <text>` (appends one criterion; deduped on exact text) and `--remove-ac <text>` (removes one criterion by exact text) on `update`/`update-many` so concurrent branch edits with disjoint additions merge instead of clobbering. Every removal must match or the complete mutation fails atomically with structured unmatched-selector recovery. Acceptance criteria use semicolons as storage boundaries, so one criterion cannot itself contain a semicolon.
|
|
54
|
+
|
|
55
|
+
Local dependency targets supplied to `create`, `update`, or `update-many` must already exist. Mark cross-workspace targets with `source_kind=external`; reserve `--allow-unresolved-deps` for deliberate staged imports and retain its structured warning as evidence.
|
|
54
56
|
|
|
55
57
|
```bash
|
|
56
58
|
pm update <item-id> --add-tags urgent,backend # keep existing tags, add two
|