@unbrained/pm-cli 2026.8.10 → 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 +102 -80
- package/dist/cli/commander-usage.js +79 -7
- package/dist/cli/error-guidance.d.ts +10 -0
- package/dist/cli/error-guidance.js +76 -25
- package/dist/cli/main.js +6 -2
- 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 +159 -159
- package/dist/cli-bundle/chunks/{chunk-TRWXF476.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-EBO7OUUE.js → chunk-WMEZHCFI.js} +59 -53
- package/dist/cli-bundle/chunks/{chunk-ETML5C6H.js → chunk-ZU34C3LH.js} +47 -47
- package/dist/cli-bundle/chunks/chunk-ZXOC6HG5.js +5 -0
- package/dist/cli-bundle/chunks/{register-list-query-OJ6ZXKV4.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-S3KT2LTH.js → register-setup-NOCOOWQY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-34SX654S.js → chunk-23FTGO3W.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2COZ67XT.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-7UN6BHHO.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-IW43E4XL.js → chunk-BKPIY34S.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-D4PIWE6D.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KR5RVXLQ.js → chunk-DPO7TEFX.js} +29 -29
- package/dist/cli-bundle/focused-chunks/{chunk-JMVA4HKR.js → chunk-E3KCL7AY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ERAAFLPS.js +153 -0
- package/dist/cli-bundle/focused-chunks/{chunk-RIIN5V4N.js → chunk-F6E4JZKG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-FPSYO5ZG.js +18 -0
- package/dist/cli-bundle/focused-chunks/{chunk-M6RPIXKC.js → chunk-J5EKAIVD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2EXI2DKR.js → chunk-KDH5OX3D.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-OJ3LVVIS.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-DZGAHZZV.js → chunk-TL5M2PAY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-75774JWP.js → chunk-UDAZWT25.js} +2 -2
- 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/session/session-state.d.ts +47 -0
- package/dist/core/session/session-state.js +207 -6
- package/dist/core/shared/author.d.ts +7 -1
- package/dist/core/shared/author.js +66 -46
- package/dist/core/shared/errors.d.ts +8 -0
- package/dist/core/shared/errors.js +2 -2
- 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 +8 -0
- package/dist/sdk/cli-bootstrap.js +7 -7
- 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 +17 -2
- package/dist/sdk/cli-contracts/runtime-contracts.js +4 -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-parameter-tables.js +79 -2
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +34 -4
- 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/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/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 +32 -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/graph/run.js +8 -3
- package/dist/sdk/index.d.ts +6 -1
- package/dist/sdk/index.js +8 -3
- package/dist/sdk/lifecycle/claim.js +18 -3
- package/dist/sdk/lifecycle/focus.js +13 -3
- package/dist/sdk/lifecycle/plan.js +8 -3
- package/dist/sdk/provenance.d.ts +38 -0
- package/dist/sdk/provenance.js +64 -2
- package/dist/sdk/query/context.js +19 -8
- 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 +4 -0
- package/dist/sdk/runtime.js +31 -27
- 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/types.d.ts +8 -2
- package/dist/types.js +2 -2
- package/docs/ASSURANCE.md +132 -0
- package/docs/README.md +1 -0
- package/docs/RELEASING.md +9 -5
- package/docs/SDK.md +12 -1
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +40 -4
- package/docs/SDK_EVIDENCE_TRACEABILITY.md +39 -1
- package/docs/SDK_RUNTIME_BOUNDARIES.md +36 -1
- package/docs/TESTING.md +12 -9
- package/docs/generated/AGENT_COMMAND_SURFACE.md +1 -0
- package/marketplace.json +2 -2
- package/package.json +3 -3
- 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 +840 -28
- package/dist/cli-bundle/chunks/chunk-2QYH4QMI.js +0 -30
- package/dist/cli-bundle/chunks/chunk-JUDU4RO4.js +0 -194
- package/dist/cli-bundle/chunks/chunk-JZSNADRR.js +0 -5
- package/dist/cli-bundle/chunks/chunk-MENWVGJW.js +0 -2
- package/dist/cli-bundle/chunks/chunk-S4EITGLA.js +0 -3
- package/dist/cli-bundle/chunks/chunk-TIGKWVLA.js +0 -13
- package/dist/cli-bundle/chunks/chunk-TSLDTJLQ.js +0 -2
- package/dist/cli-bundle/chunks/register-mutation-DKI7QC7O.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-P5OGMT6I.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-36FTZ2NT.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3CQECMKR.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-CHIBMEZR.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-FF4MNAYB.js +0 -153
- package/dist/cli-bundle/focused-chunks/chunk-GHTN2ILR.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-I4YM2I7S.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-IMDTEN7K.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-KSNJG4KI.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-MXYSIQ56.js +0 -18
- package/dist/cli-bundle/focused-chunks/chunk-RKWSCYYN.js +0 -2
package/dist/sdk/runtime.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export type { PmReadOutputSessionReceipt, PmReadOutputSessionState, } from "./re
|
|
|
15
15
|
export type { PmContextIntentContract } from "./context-intent-contracts.js";
|
|
16
16
|
export type { PmErrorCodeContract } from "./error-code-catalog.js";
|
|
17
17
|
export { clearWorkspaceContractsCache } from "./workspace-contracts-cache.js";
|
|
18
|
+
import { type AssuranceActionInput, type AssuranceActionResult } from "./governance/assurance-action.js";
|
|
19
|
+
export type * from "./governance/assurance-action-contracts.js";
|
|
18
20
|
import { type AggregateOptions, type AggregateResult } from "./query/aggregate.js";
|
|
19
21
|
import { type UpgradeCommandOptions, type UpgradeResult } from "./governance/upgrade.js";
|
|
20
22
|
import { type CreateResult } from "./lifecycle/create.js";
|
|
@@ -235,6 +237,8 @@ export declare class PmClient {
|
|
|
235
237
|
health<Options extends ReadOptions<RunHealthOptions> = RunHealthOptions>(options?: Options): ReadPromise<HealthResult, Options>;
|
|
236
238
|
/** Run tracker cache/runtime garbage collection. */
|
|
237
239
|
gc(options?: GcCommandOptions): Promise<GcResult>;
|
|
240
|
+
/** Declare, inspect, or evaluate a project assurance contract. */
|
|
241
|
+
assurance(input: AssuranceActionInput): Promise<AssuranceActionResult>;
|
|
238
242
|
/** Redact sensitive values while preserving an audited, verified history chain. */
|
|
239
243
|
historyRedact(id: string, options: HistoryRedactCommandOptions): Promise<HistoryRedactResult>;
|
|
240
244
|
/** Repair and re-anchor one drifted history stream. */
|
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]="a294f940-5bb9-55a4-bf2c-64842a3a177b")}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
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -28,11 +28,13 @@ import { PM_TOOL_ACTIONS } from "./cli-contracts/enum-contracts.js";
|
|
|
28
28
|
import { clearWorkspaceContractsCache, memoizeWorkspaceExtensionRegistrations, } from "./workspace-contracts-cache.js";
|
|
29
29
|
import { SDK_ACTION_ALIASES } from "./runtime-action-aliases.js";
|
|
30
30
|
import { createExtensionCommandSdk } from "./extension-command-context.js";
|
|
31
|
+
import { createUnknownSubcommandError } from "./agent/subcommand-recovery.js";
|
|
31
32
|
import { applyContextIntentProjection, attachReadOutputContracts, } from "./context-intent-contracts.js";
|
|
32
33
|
import { runWithDiscoveredContextIntentContracts, } from "./context-intent-runtime.js";
|
|
33
34
|
import { validateReadOutputOptions, } from "./read-output-contracts.js";
|
|
34
35
|
export { clearWorkspaceContractsCache } from "./workspace-contracts-cache.js";
|
|
35
36
|
import { runActivity } from "./query/activity.js";
|
|
37
|
+
import { runAssuranceDispatch } from "./governance/assurance-action.js";
|
|
36
38
|
import { runAggregate, } from "./query/aggregate.js";
|
|
37
39
|
import { runAppend } from "./lifecycle/append.js";
|
|
38
40
|
import { runClaim, runClaimNext, runRelease } from "./lifecycle/claim.js";
|
|
@@ -63,7 +65,7 @@ import { runConfig } from "./config.js";
|
|
|
63
65
|
import { runInit } from "./init.js";
|
|
64
66
|
import { runRuntimeEvalAction, runRuntimeEventsAction, runRuntimeMergeAction, runRuntimeSchedulingAction, runRuntimeWorkspaceAction, } from "./runtime-extended-actions.js";
|
|
65
67
|
import { acknowledgeUnknownAuthorHistoryEventsFromTransport, } from "./author-attribution.js";
|
|
66
|
-
import { runProfileApply, runProfileLint, runProfileList, runProfileShow, } from "./profile.js";
|
|
68
|
+
import { PROFILE_SUBCOMMANDS, runProfileApply, runProfileLint, runProfileList, runProfileShow, } from "./profile.js";
|
|
67
69
|
import { runHistoryRedact, } from "./history-redact.js";
|
|
68
70
|
import { runMcpHistoryCompactAction, runMcpHistoryRepairAction, } from "./history-mcp.js";
|
|
69
71
|
import { actionGlobalOptions as globalOptions, closeManyOptionsFromFlat, extensionOptionsFromArgs, graphOptionsFromFlat, mutationListOptions, normalizeActionName, normalizeCommandPath, normalizeMcpOptionsArrays, normalizeMcpUpdateOptions, optionsWithAuthor, parseRuntimeInteger as parseMcpInteger, readRuntimeScalarString as readScalarString, readRuntimeScalarStringAllowBlank as readScalarStringAllowBlank, readRuntimeString as readString, readRuntimeStringArray as readStringArray, resolveRuntimeLimit, updateManyOptionsFromFlat, withAddNoteOption, withFilesDiscoveryOptions, withMutationCompaction, } from "./runtime-input.js";
|
|
@@ -71,6 +73,7 @@ import { runDeps } from "./dependencies.js";
|
|
|
71
73
|
import { runDocs } from "./docs.js";
|
|
72
74
|
import { runGraph, } from "./graph/run.js";
|
|
73
75
|
import { runFiles, runFilesDiscover, runFilesLookup } from "./files.js";
|
|
76
|
+
import { runtimeFilesLookupOptions } from "./traceability/runtime-files-lookup.js";
|
|
74
77
|
import { runContracts, } from "./cli-contracts/runtime-contracts.js";
|
|
75
78
|
import { runList } from "./query/list.js";
|
|
76
79
|
import { runSearch, } from "./query/search.js";
|
|
@@ -81,7 +84,7 @@ import { runTelemetry } from "./telemetry.js";
|
|
|
81
84
|
import { runTest } from "./test/execution.js";
|
|
82
85
|
import { runTestAll } from "./test/batch.js";
|
|
83
86
|
import { resolveStartTaskInProgressStatus } from "./start-task-status.js";
|
|
84
|
-
import { runSchemaAddField, runSchemaAddStatus, runSchemaAddType, runSchemaApplyPreset, runSchemaInferTypes, runSchemaList, runSchemaListFields, runSchemaEvolutionMigration, runSchemaRemoveField, runSchemaRemoveStatus, runSchemaRemoveType, runSchemaShow, runSchemaShowField, runSchemaShowStatus, } from "./schema.js";
|
|
87
|
+
import { SCHEMA_SUBCOMMANDS, runSchemaAddField, runSchemaAddStatus, runSchemaAddType, runSchemaApplyPreset, runSchemaInferTypes, runSchemaList, runSchemaListFields, runSchemaEvolutionMigration, runSchemaRemoveField, runSchemaRemoveStatus, runSchemaRemoveType, runSchemaShow, runSchemaShowField, runSchemaShowStatus, } from "./schema.js";
|
|
85
88
|
export { getActiveExtensionRegistrations, runActiveOnReadHooks, runActiveOnWriteHooks, } from "../core/extensions/index.js";
|
|
86
89
|
export { pathExists, readFileIfExists, removeFileIfExists, writeFileAtomic, } from "../core/fs/fs-utils.js";
|
|
87
90
|
export { appendHistoryEntry, createHistoryEntry, } from "../core/history/history.js";
|
|
@@ -408,6 +411,10 @@ export class PmClient {
|
|
|
408
411
|
gc(options = {}) {
|
|
409
412
|
return this.runTyped("gc", { options });
|
|
410
413
|
}
|
|
414
|
+
/** Declare, inspect, or evaluate a project assurance contract. */
|
|
415
|
+
assurance(input) {
|
|
416
|
+
return this.runTyped("assurance", { options: { ...input, subcommand: input.action } });
|
|
417
|
+
}
|
|
411
418
|
/** Redact sensitive values while preserving an audited, verified history chain. */
|
|
412
419
|
historyRedact(id, options) {
|
|
413
420
|
return this.runTyped("history-redact", { id, options });
|
|
@@ -1401,25 +1408,20 @@ function runMcpCommentsAction(ctx) {
|
|
|
1401
1408
|
commentOptions.delete === undefined;
|
|
1402
1409
|
if (isListing) {
|
|
1403
1410
|
commentOptions.includeMeta = true;
|
|
1404
|
-
if (commentOptions.limit === undefined &&
|
|
1411
|
+
if (commentOptions.limit === undefined &&
|
|
1412
|
+
commentOptions.fullHistory !== true) {
|
|
1405
1413
|
commentOptions.limit = "20";
|
|
1406
1414
|
}
|
|
1407
1415
|
}
|
|
1408
1416
|
return runComments(requireMcpItemId(ctx), commentOptions, ctx.global);
|
|
1409
1417
|
}
|
|
1418
|
+
function runMcpFilesLookupAction(ctx, paths) {
|
|
1419
|
+
return runFilesLookup(runtimeFilesLookupOptions(ctx.options, paths, parseMcpInteger), ctx.global);
|
|
1420
|
+
}
|
|
1410
1421
|
function runMcpFilesAction(ctx) {
|
|
1411
1422
|
const lookupPaths = readStringArray(ctx.options.lookupPath);
|
|
1412
1423
|
if (lookupPaths && lookupPaths.length > 0) {
|
|
1413
|
-
return
|
|
1414
|
-
paths: lookupPaths,
|
|
1415
|
-
scope: ctx.options.scope === "project" || ctx.options.scope === "global"
|
|
1416
|
-
? ctx.options.scope
|
|
1417
|
-
: undefined,
|
|
1418
|
-
limit: parseMcpInteger(ctx.options.limit, "files lookup limit"),
|
|
1419
|
-
offset: parseMcpInteger(ctx.options.offset, "files lookup offset"),
|
|
1420
|
-
noTruncate: ctx.options.noTruncate === true,
|
|
1421
|
-
strictRead: ctx.options.strictRead === true,
|
|
1422
|
-
}, ctx.global);
|
|
1424
|
+
return runMcpFilesLookupAction(ctx, lookupPaths);
|
|
1423
1425
|
}
|
|
1424
1426
|
const fileId = requireMcpItemId(ctx);
|
|
1425
1427
|
return ctx.options.discover === true
|
|
@@ -1644,7 +1646,12 @@ function runMcpSchemaAction(ctx) {
|
|
|
1644
1646
|
}
|
|
1645
1647
|
return runMcpSchemaAddTypeAction(schema);
|
|
1646
1648
|
}
|
|
1647
|
-
throw
|
|
1649
|
+
throw createUnknownSubcommandError({
|
|
1650
|
+
command_path: "schema",
|
|
1651
|
+
token: schema.subcommand,
|
|
1652
|
+
allowed: SCHEMA_SUBCOMMANDS,
|
|
1653
|
+
exit_code: 64,
|
|
1654
|
+
});
|
|
1648
1655
|
}
|
|
1649
1656
|
function runMcpProfileAction(ctx) {
|
|
1650
1657
|
const subcommand = readString(ctx.args, "subcommand") ??
|
|
@@ -1663,7 +1670,12 @@ function runMcpProfileAction(ctx) {
|
|
|
1663
1670
|
};
|
|
1664
1671
|
const handler = getOwnHandler(handlers, normalizedSubcommand);
|
|
1665
1672
|
if (!handler) {
|
|
1666
|
-
throw
|
|
1673
|
+
throw createUnknownSubcommandError({
|
|
1674
|
+
command_path: "profile",
|
|
1675
|
+
token: subcommand,
|
|
1676
|
+
allowed: PROFILE_SUBCOMMANDS,
|
|
1677
|
+
exit_code: 64,
|
|
1678
|
+
});
|
|
1667
1679
|
}
|
|
1668
1680
|
return handler();
|
|
1669
1681
|
}
|
|
@@ -1813,6 +1825,7 @@ const SDK_ACTION_HANDLERS = {
|
|
|
1813
1825
|
runUpdate: (id, options, global) => runUpdate(id, options, global),
|
|
1814
1826
|
}),
|
|
1815
1827
|
health: runMcpHealthAction,
|
|
1828
|
+
assurance: (ctx) => runAssuranceDispatch(ctx.args, ctx.options, ctx.global),
|
|
1816
1829
|
contracts: (ctx) => runContracts(ctx.options, ctx.global),
|
|
1817
1830
|
config: runMcpConfigAction,
|
|
1818
1831
|
activity: runMcpActivityAction,
|
|
@@ -1825,16 +1838,7 @@ const SDK_ACTION_HANDLERS = {
|
|
|
1825
1838
|
deps: (ctx) => runDeps(requireMcpItemId(ctx), ctx.options, ctx.global),
|
|
1826
1839
|
graph: runMcpGraphAction,
|
|
1827
1840
|
"files-discover": (ctx) => runFilesDiscover(requireMcpItemId(ctx), ctx.options, ctx.global),
|
|
1828
|
-
"files-lookup": (ctx) =>
|
|
1829
|
-
paths: readStringArray(ctx.options.paths),
|
|
1830
|
-
scope: ctx.options.scope === "project" || ctx.options.scope === "global"
|
|
1831
|
-
? ctx.options.scope
|
|
1832
|
-
: undefined,
|
|
1833
|
-
limit: parseMcpInteger(ctx.options.limit, "files lookup limit"),
|
|
1834
|
-
offset: parseMcpInteger(ctx.options.offset, "files lookup offset"),
|
|
1835
|
-
noTruncate: ctx.options.noTruncate === true,
|
|
1836
|
-
strictRead: ctx.options.strictRead === true,
|
|
1837
|
-
}, ctx.global),
|
|
1841
|
+
"files-lookup": (ctx) => runMcpFilesLookupAction(ctx, readStringArray(ctx.options.paths)),
|
|
1838
1842
|
history: (ctx) => runHistory(requireMcpItemId(ctx), ctx.options, ctx.global),
|
|
1839
1843
|
"history-redact": (ctx) => runHistoryRedact(requireMcpItemId(ctx), ctx.options, ctx.global),
|
|
1840
1844
|
"history-repair": runMcpHistoryRepairAction,
|
|
@@ -1930,4 +1934,4 @@ async function loadWorkspaceExtensionRegistrations(pmRoot, settings, cwd) {
|
|
|
1930
1934
|
}
|
|
1931
1935
|
}
|
|
1932
1936
|
//# sourceMappingURL=runtime.js.map
|
|
1933
|
-
//# debugId=
|
|
1937
|
+
//# debugId=a294f940-5bb9-55a4-bf2c-64842a3a177b
|
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
|
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?: {
|