@lannguyensi/harness 0.56.0 → 0.58.0
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/CHANGELOG.md +186 -0
- package/README.md +1 -1
- package/dist/cli/apply/apply.js +4 -3
- package/dist/cli/apply/apply.js.map +1 -1
- package/dist/cli/apply/generate-codex-config.js +3 -3
- package/dist/cli/apply/generate-codex-config.js.map +1 -1
- package/dist/cli/apply/generate-memory-index.js +20 -10
- package/dist/cli/apply/generate-memory-index.js.map +1 -1
- package/dist/cli/apply/generate-settings.d.ts +7 -0
- package/dist/cli/apply/generate-settings.js +10 -1
- package/dist/cli/apply/generate-settings.js.map +1 -1
- package/dist/cli/approve/understanding.d.ts +4 -4
- package/dist/cli/doctor/format.js +68 -2
- package/dist/cli/doctor/format.js.map +1 -1
- package/dist/cli/doctor/index.d.ts +6 -0
- package/dist/cli/doctor/index.js +214 -28
- package/dist/cli/doctor/index.js.map +1 -1
- package/dist/cli/doctor/session-start-preflight-setup-version.d.ts +83 -0
- package/dist/cli/doctor/session-start-preflight-setup-version.js +114 -0
- package/dist/cli/doctor/session-start-preflight-setup-version.js.map +1 -0
- package/dist/cli/doctor/types.d.ts +35 -4
- package/dist/cli/doctor/types.js +2 -1
- package/dist/cli/doctor/types.js.map +1 -1
- package/dist/cli/doctor/ug-delegations.js +9 -0
- package/dist/cli/doctor/ug-delegations.js.map +1 -1
- package/dist/cli/explain-policy.d.ts +67 -0
- package/dist/cli/explain-policy.js +140 -3
- package/dist/cli/explain-policy.js.map +1 -1
- package/dist/cli/gc/index.js +28 -14
- package/dist/cli/gc/index.js.map +1 -1
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +10 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/composer.js +4 -3
- package/dist/cli/init/composer.js.map +1 -1
- package/dist/cli/init/dependencies.js +15 -9
- package/dist/cli/init/dependencies.js.map +1 -1
- package/dist/cli/init/templates.d.ts +1 -0
- package/dist/cli/init/templates.js +30 -4
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/list.js +19 -0
- package/dist/cli/list.js.map +1 -1
- package/dist/cli/loader.js +16 -1
- package/dist/cli/loader.js.map +1 -1
- package/dist/cli/pack/hook-bootstrap.js +2 -1
- package/dist/cli/pack/hook-bootstrap.js.map +1 -1
- package/dist/cli/pack/hook-codex-user-prompt-submit.d.ts +0 -32
- package/dist/cli/pack/hook-codex-user-prompt-submit.js +11 -118
- package/dist/cli/pack/hook-codex-user-prompt-submit.js.map +1 -1
- package/dist/cli/pack/hook-pre-tool-use.js +34 -7
- package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-solution-acceptance.d.ts +55 -0
- package/dist/cli/pack/hook-solution-acceptance.js +222 -16
- package/dist/cli/pack/hook-solution-acceptance.js.map +1 -1
- package/dist/cli/pack/hook-stay-in-scope.d.ts +5 -26
- package/dist/cli/pack/hook-stay-in-scope.js +62 -274
- package/dist/cli/pack/hook-stay-in-scope.js.map +1 -1
- package/dist/cli/pack/hook-track-active-claim.d.ts +1 -0
- package/dist/cli/pack/hook-track-active-claim.js +107 -43
- package/dist/cli/pack/hook-track-active-claim.js.map +1 -1
- package/dist/cli/session-start/index.d.ts +32 -1
- package/dist/cli/session-start/index.js +142 -12
- package/dist/cli/session-start/index.js.map +1 -1
- package/dist/cli/validate/checks.d.ts +0 -2
- package/dist/cli/validate/checks.js +30 -30
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/io/harness-lock.js +11 -1
- package/dist/io/harness-lock.js.map +1 -1
- package/dist/io/lock.d.ts +26 -0
- package/dist/io/lock.js +25 -0
- package/dist/io/lock.js.map +1 -1
- package/dist/io/project-name.d.ts +115 -0
- package/dist/io/project-name.js +158 -0
- package/dist/io/project-name.js.map +1 -0
- package/dist/io/read-json-dir-entries.js +10 -0
- package/dist/io/read-json-dir-entries.js.map +1 -1
- package/dist/io/version-compare.d.ts +59 -0
- package/dist/io/version-compare.js +67 -0
- package/dist/io/version-compare.js.map +1 -1
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.d.ts +50 -0
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.js +151 -0
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.js.map +1 -0
- package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +43 -4
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js +43 -39
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/solution-acceptance.js +4 -2
- package/dist/policy-packs/builtin/solution-acceptance.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +15 -0
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js +5 -7
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js +23 -0
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js +8 -17
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.d.ts +129 -0
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js +166 -0
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js.map +1 -0
- package/dist/policy-packs/builtin/understanding-before-execution.d.ts +129 -0
- package/dist/policy-packs/builtin/understanding-before-execution.js +44 -57
- package/dist/policy-packs/builtin/understanding-before-execution.js.map +1 -1
- package/dist/policy-packs/version-check.d.ts +8 -1
- package/dist/policy-packs/version-check.js +10 -6
- package/dist/policy-packs/version-check.js.map +1 -1
- package/dist/probes/memory.d.ts +34 -0
- package/dist/probes/memory.js +87 -14
- package/dist/probes/memory.js.map +1 -1
- package/dist/runtime/git-context.d.ts +125 -0
- package/dist/runtime/git-context.js +164 -1
- package/dist/runtime/git-context.js.map +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/task-providers/agent-tasks.d.ts +90 -0
- package/dist/runtime/task-providers/agent-tasks.js +231 -0
- package/dist/runtime/task-providers/agent-tasks.js.map +1 -0
- package/dist/runtime/workflow-policies.d.ts +1 -0
- package/dist/runtime/workflow-policies.js +8 -8
- package/dist/runtime/workflow-policies.js.map +1 -1
- package/dist/schema/index.d.ts +19 -0
- package/dist/schema/index.js +5 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/session-start-preflight.d.ts +10 -0
- package/dist/schema/session-start-preflight.js +106 -0
- package/dist/schema/session-start-preflight.js.map +1 -0
- package/package.json +7 -2
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Doctor finding for task 6993d9b5 (tracker id, harness repo): warns
|
|
2
|
+
// when `session_start_preflight.setup: true` is set but the resolved
|
|
3
|
+
// `preflight` binary is below the release that made `--setup` build
|
|
4
|
+
// code, not just install dependencies (agent-preflight 0.6.0, tag
|
|
5
|
+
// v0.6.0). On 0.5.0 `--setup` is dependency-install only, so an
|
|
6
|
+
// operator who enabled the knob against that version pays install time
|
|
7
|
+
// plus the `--setup` trust exposure (see session-start-preflight.ts's
|
|
8
|
+
// SECURITY note) for zero build benefit, with nothing today telling
|
|
9
|
+
// them so.
|
|
10
|
+
//
|
|
11
|
+
// Deliberately independent of the `git-preflight` manifest hook's own
|
|
12
|
+
// `min_version`/`version_command` (checked generically by
|
|
13
|
+
// `checkHookVersion` in ./index.ts): that floor is whatever the
|
|
14
|
+
// operator's own manifest declares, and existing manifests generated
|
|
15
|
+
// before task 6993d9b5 still carry the pre-existing 0.2.0 floor (bumped
|
|
16
|
+
// to `GIT_PREFLIGHT_HOOK_MIN_VERSION`, src/cli/init/templates.ts, in the
|
|
17
|
+
// `init` template only going forward, task 6993d9b5's second commit).
|
|
18
|
+
// This check hardcodes the build-capable floor so an operator on an
|
|
19
|
+
// unregenerated manifest still gets the warning the moment they flip
|
|
20
|
+
// `setup: true`, rather than only after re-running `harness init`.
|
|
21
|
+
//
|
|
22
|
+
// BY DESIGN: on a freshly generated manifest with `setup: true` probed
|
|
23
|
+
// against a stale preflight, this check and the generic `hooks[]`
|
|
24
|
+
// `min_version` walk both fire and both count toward `warningCount` (see
|
|
25
|
+
// `docs/CLI.md`'s VERSION CAVEAT). The two are not a duplicate of the
|
|
26
|
+
// same finding: the hook floor guards the `git-preflight` hook itself,
|
|
27
|
+
// this check guards the `--setup` build-step feature specifically, and
|
|
28
|
+
// a stale preflight breaks both independently.
|
|
29
|
+
//
|
|
30
|
+
// SPLIT FROM THE HOOK FLOOR (task 65952a0c, docs/decisions/2026-09-08-
|
|
31
|
+
// preflight-floors.md): this check's floor,
|
|
32
|
+
// `SESSION_START_PREFLIGHT_SETUP_BUILD_MIN_VERSION`, and the hook
|
|
33
|
+
// floor above, `GIT_PREFLIGHT_HOOK_MIN_VERSION`, were ONE shared
|
|
34
|
+
// constant through task 6993d9b5. Both are `"0.6.0"` today and can
|
|
35
|
+
// diverge on a future bump that applies to only one rationale; see the
|
|
36
|
+
// ADR for the bump rule each carries.
|
|
37
|
+
//
|
|
38
|
+
// Silent (returns `undefined`) whenever `session_start_preflight.setup`
|
|
39
|
+
// is `false`/absent: the trust exposure and the install/build cost only
|
|
40
|
+
// exist once the knob is actually on, mirroring every other advisory
|
|
41
|
+
// doctor check's "no opinion when the feature isn't in use" gate.
|
|
42
|
+
import { parseProbedVersion, compareVersionFloor } from "../../io/version-compare.js";
|
|
43
|
+
import { PREFLIGHT_BIN } from "../session-start/index.js";
|
|
44
|
+
import { SESSION_START_PREFLIGHT_SETUP_BUILD_MIN_VERSION } from "../../schema/session-start-preflight.js";
|
|
45
|
+
/**
|
|
46
|
+
* The probe command run against the `preflight` binary on PATH. Matches
|
|
47
|
+
* the `version_command` the shipped `git-preflight` hook template
|
|
48
|
+
* declares (src/cli/init/templates.ts), same binary and `--version`
|
|
49
|
+
* flag, but is not read FROM the manifest's hook entry: an operator
|
|
50
|
+
* could rename/remove that hook while `session_start_preflight.setup`
|
|
51
|
+
* stays on, and the check should still probe the binary the producer
|
|
52
|
+
* (`harness session-start preflight`) actually spawns.
|
|
53
|
+
*/
|
|
54
|
+
export const PREFLIGHT_SETUP_VERSION_COMMAND = [PREFLIGHT_BIN, "--version"];
|
|
55
|
+
/**
|
|
56
|
+
* Pure: manifest + versionProbe in, a finding out (or `undefined` when
|
|
57
|
+
* there is nothing to flag). Mirrors `checkHookVersion`'s probe/parse
|
|
58
|
+
* idiom (src/cli/doctor/index.ts) so the warning vocabulary
|
|
59
|
+
* (`below_floor` / `probe_failed` / `parse_failed`) and version-regex
|
|
60
|
+
* parsing stay consistent across both checks, without importing from
|
|
61
|
+
* index.ts (which would create a cycle back into this module's own
|
|
62
|
+
* caller).
|
|
63
|
+
*
|
|
64
|
+
* `projectName` (task c88461c1, review round 3 residual; task
|
|
65
|
+
* `1c4eb3ea`): OPTIONAL third argument, carried onto every returned finding
|
|
66
|
+
* unchanged (see {@link SessionStartPreflightSetupVersionFinding.projectName}'s
|
|
67
|
+
* doc comment). `doctor()` always passes it (the SAME name it derived
|
|
68
|
+
* for its own scoped load, or `null`); every pre-existing direct call
|
|
69
|
+
* to this pure function in its own unit tests omits it, so those
|
|
70
|
+
* findings' shape is unchanged.
|
|
71
|
+
*/
|
|
72
|
+
export function checkSessionStartPreflightSetupVersion(manifest, versionProbe, projectName) {
|
|
73
|
+
if (!manifest.session_start_preflight.setup)
|
|
74
|
+
return undefined;
|
|
75
|
+
const withProjectName = (finding) => projectName !== undefined ? { ...finding, projectName } : finding;
|
|
76
|
+
const required = SESSION_START_PREFLIGHT_SETUP_BUILD_MIN_VERSION;
|
|
77
|
+
const stdout = versionProbe(PREFLIGHT_SETUP_VERSION_COMMAND);
|
|
78
|
+
if (stdout === null) {
|
|
79
|
+
return withProjectName({
|
|
80
|
+
kind: "probe_failed",
|
|
81
|
+
actualVersion: null,
|
|
82
|
+
requiredVersion: required,
|
|
83
|
+
message: `session_start_preflight.setup is enabled but the installed preflight version could not ` +
|
|
84
|
+
`be determined (probe for "${PREFLIGHT_SETUP_VERSION_COMMAND.join(" ")}" failed); the ` +
|
|
85
|
+
`build step needs preflight >= ${required}`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// parseProbedVersion/compareVersionFloor (not plain compareNumericVersions):
|
|
89
|
+
// a preflight release candidate of the floor (e.g. "0.6.0-rc.1") must not
|
|
90
|
+
// count as build-capable. See docs/decisions/2026-09-08-preflight-floors.md.
|
|
91
|
+
const parsed = parseProbedVersion(stdout);
|
|
92
|
+
if (!parsed) {
|
|
93
|
+
return withProjectName({
|
|
94
|
+
kind: "parse_failed",
|
|
95
|
+
actualVersion: null,
|
|
96
|
+
requiredVersion: required,
|
|
97
|
+
message: `session_start_preflight.setup is enabled but the installed preflight version could not ` +
|
|
98
|
+
`be parsed from "${stdout.trim()}"; the build step needs preflight >= ${required}`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const { version: actual, isPrerelease, token } = parsed;
|
|
102
|
+
if (compareVersionFloor(actual, isPrerelease, required) < 0) {
|
|
103
|
+
return withProjectName({
|
|
104
|
+
kind: "below_floor",
|
|
105
|
+
actualVersion: actual,
|
|
106
|
+
requiredVersion: required,
|
|
107
|
+
message: `session_start_preflight.setup is enabled but installed preflight v${token} < ${required}: ` +
|
|
108
|
+
`--setup on v${token} is dependency-install only (no build step); upgrade preflight ` +
|
|
109
|
+
`(npm i -g @lannguyensi/agent-preflight) or set session_start_preflight.setup: false`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=session-start-preflight-setup-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-start-preflight-setup-version.js","sourceRoot":"","sources":["../../../src/cli/doctor/session-start-preflight-setup-version.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,qEAAqE;AACrE,oEAAoE;AACpE,kEAAkE;AAClE,gEAAgE;AAChE,uEAAuE;AACvE,sEAAsE;AACtE,oEAAoE;AACpE,WAAW;AACX,EAAE;AACF,sEAAsE;AACtE,0DAA0D;AAC1D,gEAAgE;AAChE,qEAAqE;AACrE,wEAAwE;AACxE,yEAAyE;AACzE,sEAAsE;AACtE,oEAAoE;AACpE,qEAAqE;AACrE,mEAAmE;AACnE,EAAE;AACF,uEAAuE;AACvE,kEAAkE;AAClE,yEAAyE;AACzE,sEAAsE;AACtE,uEAAuE;AACvE,uEAAuE;AACvE,+CAA+C;AAC/C,EAAE;AACF,uEAAuE;AACvE,4CAA4C;AAC5C,kEAAkE;AAClE,iEAAiE;AACjE,mEAAmE;AACnE,uEAAuE;AACvE,sCAAsC;AACtC,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,qEAAqE;AACrE,kEAAkE;AAElE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,+CAA+C,EAAE,MAAM,yCAAyC,CAAC;AAG1G;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,aAAa,EAAE,WAAW,CAAU,CAAC;AAyDrF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sCAAsC,CACpD,QAAkB,EAClB,YAAuD,EACvD,WAA2B;IAE3B,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAE9D,MAAM,eAAe,GAAG,CACtB,OAAsE,EAC5B,EAAE,CAC5C,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;IAEpE,MAAM,QAAQ,GAAG,+CAA+C,CAAC;IACjE,MAAM,MAAM,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC;IAC7D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC;YACrB,IAAI,EAAE,cAAc;YACpB,aAAa,EAAE,IAAI;YACnB,eAAe,EAAE,QAAQ;YACzB,OAAO,EACL,yFAAyF;gBACzF,6BAA6B,+BAA+B,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB;gBACvF,iCAAiC,QAAQ,EAAE;SAC9C,CAAC,CAAC;IACL,CAAC;IACD,6EAA6E;IAC7E,0EAA0E;IAC1E,6EAA6E;IAC7E,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,eAAe,CAAC;YACrB,IAAI,EAAE,cAAc;YACpB,aAAa,EAAE,IAAI;YACnB,eAAe,EAAE,QAAQ;YACzB,OAAO,EACL,yFAAyF;gBACzF,mBAAmB,MAAM,CAAC,IAAI,EAAE,wCAAwC,QAAQ,EAAE;SACrF,CAAC,CAAC;IACL,CAAC;IACD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IACxD,IAAI,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5D,OAAO,eAAe,CAAC;YACrB,IAAI,EAAE,aAAa;YACnB,aAAa,EAAE,MAAM;YACrB,eAAe,EAAE,QAAQ;YACzB,OAAO,EACL,qEAAqE,KAAK,MAAM,QAAQ,IAAI;gBAC5F,eAAe,KAAK,iEAAiE;gBACrF,qFAAqF;SACxF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -15,6 +15,7 @@ import type { UgInflightSection } from "./ug-inflight.js";
|
|
|
15
15
|
import type { SettingsDriftSection } from "./settings-drift.js";
|
|
16
16
|
import type { AutoApproveModeWarning } from "./auto-approve-mode.js";
|
|
17
17
|
import type { BypassWithoutAutoApproveFinding } from "./bypass-without-auto-approve.js";
|
|
18
|
+
import type { SessionStartPreflightSetupVersionFinding } from "./session-start-preflight-setup-version.js";
|
|
18
19
|
import type { CodexConfigDriftSection } from "./codex-config-drift.js";
|
|
19
20
|
/**
|
|
20
21
|
* Phase 6 #6 follow-up — doctor target identifier. Distinct from
|
|
@@ -84,7 +85,21 @@ export type HookVersionReport = {
|
|
|
84
85
|
* classifies its outcome, so there is no warn case without one.
|
|
85
86
|
*/
|
|
86
87
|
kind: "below_floor" | "probe_failed" | "parse_failed";
|
|
87
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Parsed installed version, when the probe succeeded. Null when
|
|
90
|
+
* the probe failed or its stdout didn't parse. Always the
|
|
91
|
+
* NUMERIC run (`parseProbedVersion`'s `version` field, e.g.
|
|
92
|
+
* "0.6.0"), never the probed prerelease/build suffix: for a
|
|
93
|
+
* `below_floor` finding caused by a prerelease of the floor
|
|
94
|
+
* (e.g. probed "0.6.0-rc.1" against a "0.6.0" `min_version`),
|
|
95
|
+
* `actualVersion` therefore equals `hook.min_version` even
|
|
96
|
+
* though `kind` is `"below_floor"`: the numeric components tie,
|
|
97
|
+
* and `compareVersionFloor`'s prerelease tie-break is what
|
|
98
|
+
* actually failed the floor. `message` carries the full probed
|
|
99
|
+
* token (including the suffix) for the human-facing distinction;
|
|
100
|
+
* this field's JSON shape does not gain a new field for it. See
|
|
101
|
+
* docs/decisions/2026-09-08-preflight-floors.md.
|
|
102
|
+
*/
|
|
88
103
|
actualVersion: string | null;
|
|
89
104
|
message: string;
|
|
90
105
|
};
|
|
@@ -171,6 +186,12 @@ export interface PolicyPackConfigIssue {
|
|
|
171
186
|
export interface PolicyPackVersionGapReport {
|
|
172
187
|
name: string;
|
|
173
188
|
declaredMinVersion: string;
|
|
189
|
+
/**
|
|
190
|
+
* Numeric run only (never the prerelease or build suffix), so a
|
|
191
|
+
* `below_floor` gap from a prerelease of the floor shows an
|
|
192
|
+
* `actualVersion` equal to `declaredMinVersion`; `message` carries the
|
|
193
|
+
* full probed token. Same trap as `HookVersionReport.actualVersion`.
|
|
194
|
+
*/
|
|
174
195
|
actualVersion: string | null;
|
|
175
196
|
message: string;
|
|
176
197
|
}
|
|
@@ -435,6 +456,15 @@ export interface DoctorReport {
|
|
|
435
456
|
* bypass-without-auto-approve.ts.
|
|
436
457
|
*/
|
|
437
458
|
ugBypassWithoutAutoApprove?: BypassWithoutAutoApproveFinding;
|
|
459
|
+
/**
|
|
460
|
+
* `session_start_preflight.setup: true` against a `preflight` binary
|
|
461
|
+
* below the build-capable release (task 6993d9b5). Present only when
|
|
462
|
+
* `setup` is enabled AND the probed/parsed version is below
|
|
463
|
+
* `SESSION_START_PREFLIGHT_SETUP_BUILD_MIN_VERSION` (or the probe
|
|
464
|
+
* failed/could not be parsed); always a warning (`⚠`) when present,
|
|
465
|
+
* see session-start-preflight-setup-version.ts.
|
|
466
|
+
*/
|
|
467
|
+
sessionStartPreflightSetupVersion?: SessionStartPreflightSetupVersionFinding;
|
|
438
468
|
/**
|
|
439
469
|
* `auto_approve` configured without `mode: grill_me` (agent-tasks
|
|
440
470
|
* abfad738, follow-up of ADR
|
|
@@ -565,14 +595,15 @@ export interface DoctorReport {
|
|
|
565
595
|
warningCount: number;
|
|
566
596
|
}
|
|
567
597
|
export type { NpmBinReport } from "./npm-bin-path.js";
|
|
568
|
-
export type {
|
|
598
|
+
export type { SessionStartPreflightSetupVersionFinding } from "./session-start-preflight-setup-version.js";
|
|
599
|
+
export type { ClaudeMcpRegistrationSection, ClaudeMcpEntryReport, } from "./claude-mcp.js";
|
|
569
600
|
export type { UnderstandingModeEnvDivergence } from "./understanding-mode-env.js";
|
|
570
|
-
export type { UgAutoApprovalsSection, AutoApprovalListingEntry } from "./ug-auto-approvals.js";
|
|
601
|
+
export type { UgAutoApprovalsSection, AutoApprovalListingEntry, } from "./ug-auto-approvals.js";
|
|
571
602
|
export type { UgDelegationsSection } from "./ug-delegations.js";
|
|
572
603
|
export type { UgInflightSection } from "./ug-inflight.js";
|
|
573
604
|
export type { AutoApproveModeWarning } from "./auto-approve-mode.js";
|
|
574
605
|
export type { BypassWithoutAutoApproveFinding } from "./bypass-without-auto-approve.js";
|
|
575
606
|
export type { SettingsDriftSection } from "./settings-drift.js";
|
|
576
607
|
export type { CodexConfigDriftSection } from "./codex-config-drift.js";
|
|
577
|
-
export type { ToolchainParitySection, ToolchainParityPeerReport } from "./toolchain-parity.js";
|
|
608
|
+
export type { ToolchainParitySection, ToolchainParityPeerReport, } from "./toolchain-parity.js";
|
|
578
609
|
export type { Manifest, McpProbeResult, MemoryReport, StaleMemory, CodexTargetReport, RogueLedgerDb, };
|
package/dist/cli/doctor/types.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export const KNOWN_DOCTOR_TARGETS = ["codex", "opencode"];
|
|
10
10
|
export function isDoctorTarget(value) {
|
|
11
|
-
return typeof value === "string" &&
|
|
11
|
+
return (typeof value === "string" &&
|
|
12
|
+
KNOWN_DOCTOR_TARGETS.includes(value));
|
|
12
13
|
}
|
|
13
14
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/cli/doctor/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/cli/doctor/types.ts"],"names":[],"mappings":"AAoBA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,UAAU,CAAU,CAAC;AAGnE,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACxB,oBAA0C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC5D,CAAC;AACJ,CAAC"}
|
|
@@ -58,6 +58,15 @@ const SESSION_ID_BASENAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
|
58
58
|
export function buildUgDelegations(generatedDir, opts = {}) {
|
|
59
59
|
const now = opts.now ?? new Date();
|
|
60
60
|
const dir = path.join(generatedDir, DELEGATION_MARKER_DIRNAME);
|
|
61
|
+
let dirStat;
|
|
62
|
+
try {
|
|
63
|
+
dirStat = fs.lstatSync(dir);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return emptySection();
|
|
67
|
+
}
|
|
68
|
+
if (!dirStat.isDirectory())
|
|
69
|
+
return emptySection();
|
|
61
70
|
let dirents;
|
|
62
71
|
try {
|
|
63
72
|
dirents = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ug-delegations.js","sourceRoot":"","sources":["../../../src/cli/doctor/ug-delegations.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ug-delegations.js","sourceRoot":"","sources":["../../../src/cli/doctor/ug-delegations.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,7 +15,44 @@ export interface ExplainPolicyOptions extends EventInputSeams, LoaderOptions {
|
|
|
15
15
|
kubeContext?: string;
|
|
16
16
|
/** Inject the kube namespace (tests); bypasses `~/.kube/config`. */
|
|
17
17
|
kubeNamespace?: string;
|
|
18
|
+
/**
|
|
19
|
+
* cwd `session_start_preflight.setup`'s per-repo project layer is
|
|
20
|
+
* derived from when `opts.project` is absent (task c88461c1, review
|
|
21
|
+
* round 2, decision D-021b): the same `deriveProjectName` helper
|
|
22
|
+
* `harness session-start preflight` and `harness doctor` also feed
|
|
23
|
+
* their own `loadManifest` call from, so all three consumers agree on
|
|
24
|
+
* which project layer applies to a given cwd instead of `explain-
|
|
25
|
+
* policy` silently reporting the base/machine value for a repo whose
|
|
26
|
+
* producer is actually reading a project layer. Defaults to
|
|
27
|
+
* `process.cwd()`; tests inject a fixture repo dir to stay hermetic
|
|
28
|
+
* against the real cwd.
|
|
29
|
+
*/
|
|
30
|
+
cwd?: string;
|
|
18
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Which resolved layer decided `session_start_preflight.setup` (task
|
|
34
|
+
* c88461c1): "project" when the resolved project-override layer
|
|
35
|
+
* itself declares the key, "machine" when a resolved machine-override
|
|
36
|
+
* layer declares it (and no project layer does), "base" otherwise
|
|
37
|
+
* (the base manifest, or the schema default when nothing declares the
|
|
38
|
+
* key at all). Mirrors the loader's own last-wins precedence
|
|
39
|
+
* (`applyLayers(baseRaw, ...machineLayers, projectLayer)`,
|
|
40
|
+
* `src/overrides/merge.ts`): the project layer is checked first since
|
|
41
|
+
* it is the highest-precedence layer, then machine layers from the
|
|
42
|
+
* last-applied (highest-precedence) one back to the first.
|
|
43
|
+
*
|
|
44
|
+
* "unresolvable" (task c88461c1, review round 3 residual; task
|
|
45
|
+
* `1c4eb3ea` of the batch-44 follow-up run): the cwd-derived project-scoped SECOND
|
|
46
|
+
* load itself threw (a malformed project layer, an unreadable file).
|
|
47
|
+
* Deliberately NOT "base": the base/machine values were never actually
|
|
48
|
+
* re-read on this path (the plain load above them; see the round-3
|
|
49
|
+
* comment this residual corrected), so attributing the result to
|
|
50
|
+
* "base" would claim a value the base layer may not carry. `setup`
|
|
51
|
+
* degrades to `false` alongside it, matching the producer's own
|
|
52
|
+
* `setupEnabled` catch (`src/cli/session-start/index.ts`), so the two
|
|
53
|
+
* agree on a scoped-load failure instead of only on a healthy load.
|
|
54
|
+
*/
|
|
55
|
+
export type SessionStartPreflightLayerSource = "base" | "machine" | "project" | "unresolvable";
|
|
19
56
|
interface ExplainPolicyProjection {
|
|
20
57
|
policy: string;
|
|
21
58
|
description: string;
|
|
@@ -31,6 +68,36 @@ interface ExplainPolicyProjection {
|
|
|
31
68
|
/** Static deletion-target verdict (task d03af8f6); null when the
|
|
32
69
|
* event's command is not a recognized deletion verb. */
|
|
33
70
|
deletion_target: DeletionTargetVerdict | null;
|
|
71
|
+
/**
|
|
72
|
+
* Resolved `session_start_preflight` config (task 30183330), shown
|
|
73
|
+
* only when the explained policy is one of the init-generated
|
|
74
|
+
* `preflight-before-*` gates (name starts with `preflight-before-`):
|
|
75
|
+
* this is the knob that decides whether the `harness session-start
|
|
76
|
+
* preflight` / `harness preflight` producer passes `--setup` to the
|
|
77
|
+
* `preflight run` invocation whose `ready:true` result these policies
|
|
78
|
+
* gate on. Omitted for every other policy; it has no bearing on
|
|
79
|
+
* their evaluation (review round 3 residual; task `1c4eb3ea`: the
|
|
80
|
+
* scoped SECOND load below this field's assignment site runs ONLY
|
|
81
|
+
* when this condition is already true, so a policy this block is
|
|
82
|
+
* never rendered for never pays for that extra load either).
|
|
83
|
+
* `source` (task c88461c1) names which resolved layer decided the
|
|
84
|
+
* value: `"base"` (also covers an injected `opts.manifest`, which
|
|
85
|
+
* carries no per-layer provenance to attribute), `"machine"`,
|
|
86
|
+
* `"project"` (the cwd-derived per-repo layer), or `"unresolvable"`
|
|
87
|
+
* (review round 3 residual; task `1c4eb3ea`: the scoped load itself
|
|
88
|
+
* threw, `setup` degrades to `false` alongside it). This function
|
|
89
|
+
* derives that project name itself, from `opts.cwd`, via the SAME
|
|
90
|
+
* `deriveProjectName` helper `harness session-start preflight` feeds
|
|
91
|
+
* through `LoaderOptions.project` (review round 2, decision D-021b:
|
|
92
|
+
* without this, an operator running `explain-policy` with no
|
|
93
|
+
* `--project` in a repo that DOES have a project layer would see the
|
|
94
|
+
* base/machine value while the producer itself reads the project
|
|
95
|
+
* layer, see src/cli/session-start/index.ts).
|
|
96
|
+
*/
|
|
97
|
+
session_start_preflight?: {
|
|
98
|
+
setup: boolean;
|
|
99
|
+
source: SessionStartPreflightLayerSource;
|
|
100
|
+
};
|
|
34
101
|
when: {
|
|
35
102
|
declared: false;
|
|
36
103
|
} | {
|
|
@@ -12,13 +12,63 @@
|
|
|
12
12
|
// Distinct from `harness explain <policy> --trace`: that replays the
|
|
13
13
|
// LAST recorded decision from the evidence ledger; `explain-policy`
|
|
14
14
|
// evaluates a hypothetical event live and reads nothing from the ledger.
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
15
|
+
import * as fs from "node:fs";
|
|
16
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
17
|
+
import { classifyRisk, deriveProjectName, evaluateWhen, policyMatchesEvent, resolveDeletionTarget, resolveEnvironment, resolveKubeContext, } from "../runtime/index.js";
|
|
17
18
|
import { extractShellCommand } from "../runtime/tool-name-aliases.js";
|
|
18
19
|
import { DEFAULT_SAFE_DELETION_ROOTS } from "../schema/risk.js";
|
|
19
20
|
import { loadEventEnvelope } from "./event-input.js";
|
|
20
21
|
import { EX_USAGE, HarnessExitError } from "./exit-codes.js";
|
|
21
22
|
import { loadManifest } from "./loader.js";
|
|
23
|
+
/**
|
|
24
|
+
* Does `filePath`'s raw YAML explicitly declare `session_start_preflight.setup`?
|
|
25
|
+
*
|
|
26
|
+
* "Declare" means KEY PRESENCE, not "holds a boolean" (review round 2,
|
|
27
|
+
* finding: a tombstone, `session_start_preflight: null` or `{setup:
|
|
28
|
+
* null}`, both honoured by `mergeValue` in src/overrides/merge.ts as
|
|
29
|
+
* "delete whatever a lower layer set, falling back to the schema
|
|
30
|
+
* default", is exactly as much a deliberate declaration by THIS layer
|
|
31
|
+
* as `setup: true`/`false` is; it just resolves to a different final
|
|
32
|
+
* value. Attributing a tombstoned layer's decision to whichever lower
|
|
33
|
+
* layer happens to also declare the key (or to "base" when none does)
|
|
34
|
+
* would name the WRONG layer as the one that decided the merged
|
|
35
|
+
* result.
|
|
36
|
+
*/
|
|
37
|
+
function layerDeclaresSetup(filePath) {
|
|
38
|
+
try {
|
|
39
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
40
|
+
const parsed = parseYaml(raw);
|
|
41
|
+
if (parsed === null || typeof parsed !== "object")
|
|
42
|
+
return false;
|
|
43
|
+
if (!("session_start_preflight" in parsed))
|
|
44
|
+
return false;
|
|
45
|
+
const block = parsed.session_start_preflight;
|
|
46
|
+
if (block === null)
|
|
47
|
+
return true; // whole-block tombstone
|
|
48
|
+
if (typeof block !== "object" || Array.isArray(block))
|
|
49
|
+
return false;
|
|
50
|
+
return "setup" in block;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Re-reads the resolved layer files (independent of the already-merged
|
|
58
|
+
* `manifest` object, which no longer carries per-layer provenance once
|
|
59
|
+
* `applyLayers` has folded them together) to attribute the decided
|
|
60
|
+
* `session_start_preflight.setup` value to the layer that set it.
|
|
61
|
+
*/
|
|
62
|
+
function resolveSessionStartPreflightSource(resolved) {
|
|
63
|
+
if (resolved.projectLayer !== null && layerDeclaresSetup(resolved.projectLayer)) {
|
|
64
|
+
return "project";
|
|
65
|
+
}
|
|
66
|
+
for (let i = resolved.machineLayers.length - 1; i >= 0; i--) {
|
|
67
|
+
if (layerDeclaresSetup(resolved.machineLayers[i]))
|
|
68
|
+
return "machine";
|
|
69
|
+
}
|
|
70
|
+
return "base";
|
|
71
|
+
}
|
|
22
72
|
/**
|
|
23
73
|
* Explain whether `policyName` applies to the event at `opts.eventPath`.
|
|
24
74
|
*
|
|
@@ -27,12 +77,93 @@ import { loadManifest } from "./loader.js";
|
|
|
27
77
|
* `loadEventEnvelope`) when the event file is missing or malformed.
|
|
28
78
|
*/
|
|
29
79
|
export function explainPolicy(policyName, opts) {
|
|
30
|
-
|
|
80
|
+
// `resolved` is only available on the real `loadManifest(opts)` path:
|
|
81
|
+
// an injected `opts.manifest` already IS the merged result and
|
|
82
|
+
// carries no per-layer provenance, so `session_start_preflight.source`
|
|
83
|
+
// falls back to "base" in that case (see the field's doc comment).
|
|
84
|
+
//
|
|
85
|
+
// PLAIN load (task c88461c1, review round 3, decision D-028): every
|
|
86
|
+
// check this verb performs against `manifest` below -- finding the
|
|
87
|
+
// named policy, trigger matching, the Risk Classifier, environment
|
|
88
|
+
// resolution, deletion-target resolution, and the `when:` evaluation
|
|
89
|
+
// -- reads the base/machine/explicit-`--project` manifest only, an
|
|
90
|
+
// explicit `opts.project` still wins outright but NOTHING is derived
|
|
91
|
+
// from cwd here. This mirrors `harness policy intercept`
|
|
92
|
+
// (src/cli/policy/intercept.ts) and `harness dry-run`
|
|
93
|
+
// (src/cli/dry-run.ts), the two enforcement-facing verbs that decide
|
|
94
|
+
// a policy's real trigger verdict: neither ever consults a derived
|
|
95
|
+
// project layer, so this manifest must not either, or an operator's
|
|
96
|
+
// "would this apply" answer could disagree with what actually
|
|
97
|
+
// enforces. Only `session_start_preflight.setup` (and its `source`
|
|
98
|
+
// attribution) below get a project-scoped SECOND load: routing a
|
|
99
|
+
// derived layer through THIS one, unrelated load would let it
|
|
100
|
+
// silently reach the policy engine this verb evaluates, for zero
|
|
101
|
+
// benefit to the one key that needs it.
|
|
102
|
+
let manifest;
|
|
103
|
+
let resolvedPaths;
|
|
104
|
+
if (opts.manifest) {
|
|
105
|
+
manifest = opts.manifest;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const loaded = loadManifest(opts);
|
|
109
|
+
manifest = loaded.manifest;
|
|
110
|
+
resolvedPaths = loaded.resolved;
|
|
111
|
+
}
|
|
31
112
|
const policy = manifest.policies.find((p) => p.name === policyName);
|
|
32
113
|
if (!policy) {
|
|
33
114
|
const available = manifest.policies.map((p) => p.name).join(", ") || "(none)";
|
|
34
115
|
throw new HarnessExitError(`no policy named "${policyName}" declared; available: ${available}`, EX_USAGE);
|
|
35
116
|
}
|
|
117
|
+
// `session_start_preflight.setup` / `source` (task c88461c1, review
|
|
118
|
+
// round 2 decision D-021b; scope narrowed to this one key, review
|
|
119
|
+
// round 3 decision D-028; gated on the name-prefix check below,
|
|
120
|
+
// review round 3 residual, task `1c4eb3ea`): an explicit
|
|
121
|
+
// `opts.project` still wins outright; otherwise derive the project
|
|
122
|
+
// name from `opts.cwd` (defaulting to `process.cwd()`) via the SAME
|
|
123
|
+
// `deriveProjectName` the two other producers reach through
|
|
124
|
+
// `resolveScopedProjectName` (src/runtime/git-context.ts; this verb keeps
|
|
125
|
+
// its own copy with an `undefined` fallback, task f1eb1c5c), so this
|
|
126
|
+
// verb's `setup`/`source` reflect the layer the producer would read for
|
|
127
|
+
// this cwd, WITHOUT letting that derived layer reach the policy evaluation above. An injected
|
|
128
|
+
// `opts.manifest` carries no per-layer provenance to re-derive from
|
|
129
|
+
// and always reports "base" (unchanged from before this task).
|
|
130
|
+
//
|
|
131
|
+
// ONLY COMPUTED FOR `preflight-before-*` POLICIES (moved behind this
|
|
132
|
+
// check, review round 3 residual, task `1c4eb3ea`): the block below
|
|
133
|
+
// is rendered into the projection ONLY for those policies (see
|
|
134
|
+
// `ExplainPolicyProjection.session_start_preflight`'s doc comment),
|
|
135
|
+
// so a caller explaining any OTHER policy no longer pays for a
|
|
136
|
+
// second manifest load whose result it can never see.
|
|
137
|
+
let sessionStartPreflightSetup = false;
|
|
138
|
+
let sessionStartPreflightSource = "base";
|
|
139
|
+
if (policy.name.startsWith("preflight-before-")) {
|
|
140
|
+
sessionStartPreflightSetup = manifest.session_start_preflight.setup;
|
|
141
|
+
sessionStartPreflightSource = resolvedPaths
|
|
142
|
+
? resolveSessionStartPreflightSource(resolvedPaths)
|
|
143
|
+
: "base";
|
|
144
|
+
if (!opts.manifest) {
|
|
145
|
+
try {
|
|
146
|
+
const scoped = loadManifest({
|
|
147
|
+
...opts,
|
|
148
|
+
project: opts.project ?? deriveProjectName(opts.cwd ?? process.cwd()) ?? undefined,
|
|
149
|
+
});
|
|
150
|
+
sessionStartPreflightSetup = scoped.manifest.session_start_preflight.setup;
|
|
151
|
+
sessionStartPreflightSource = resolveSessionStartPreflightSource(scoped.resolved);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Review round 3 residual, task `1c4eb3ea`: degrade to
|
|
155
|
+
// setup:false / source:"unresolvable" rather than keeping the
|
|
156
|
+
// plain load's values, matching the producer's own
|
|
157
|
+
// `setupEnabled` catch (`src/cli/session-start/index.ts`),
|
|
158
|
+
// which degrades to `setup: false` on the identical failure
|
|
159
|
+
// instead of falling back to a base/machine value it never
|
|
160
|
+
// actually re-read on this path. "base" would misattribute
|
|
161
|
+
// the result to a layer this function never consulted here.
|
|
162
|
+
sessionStartPreflightSetup = false;
|
|
163
|
+
sessionStartPreflightSource = "unresolvable";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
36
167
|
const { event, envelope } = loadEventEnvelope(opts.eventPath, opts, "explain-policy");
|
|
37
168
|
// Kube seams resolve together: if either is injected, skip the
|
|
38
169
|
// `~/.kube/config` read entirely — same contract as `resolve-env`.
|
|
@@ -73,6 +204,12 @@ export function explainPolicy(policyName, opts) {
|
|
|
73
204
|
classifier,
|
|
74
205
|
environment,
|
|
75
206
|
deletion_target: deletionTarget,
|
|
207
|
+
...(policy.name.startsWith("preflight-before-") && {
|
|
208
|
+
session_start_preflight: {
|
|
209
|
+
setup: sessionStartPreflightSetup,
|
|
210
|
+
source: sessionStartPreflightSource,
|
|
211
|
+
},
|
|
212
|
+
}),
|
|
76
213
|
when: whenEval
|
|
77
214
|
? {
|
|
78
215
|
declared: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain-policy.js","sourceRoot":"","sources":["../../src/cli/explain-policy.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,EAAE;AACF,wEAAwE;AACxE,mEAAmE;AACnE,wEAAwE;AACxE,wEAAwE;AACxE,qEAAqE;AACrE,yEAAyE;AACzE,uEAAuE;AACvE,6CAA6C;AAC7C,EAAE;AACF,qEAAqE;AACrE,oEAAoE;AACpE,yEAAyE;AAEzE,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"explain-policy.js","sourceRoot":"","sources":["../../src/cli/explain-policy.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/gc/index.js
CHANGED
|
@@ -86,6 +86,15 @@ function ageDays(nowMs, thenMs) {
|
|
|
86
86
|
}
|
|
87
87
|
/** Plain files in `dir` whose mtime is older than `cutoffMs`. */
|
|
88
88
|
function staleFilesByMtime(dir, cutoffMs, nowMs, category) {
|
|
89
|
+
let dirStat;
|
|
90
|
+
try {
|
|
91
|
+
dirStat = fs.lstatSync(dir);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return { candidates: [], kept: 0 };
|
|
95
|
+
}
|
|
96
|
+
if (!dirStat.isDirectory())
|
|
97
|
+
return { candidates: [], kept: 0 };
|
|
89
98
|
let names;
|
|
90
99
|
try {
|
|
91
100
|
names = fs.readdirSync(dir);
|
|
@@ -205,13 +214,24 @@ function sweepDelegations(generatedDir, cutoffMs, nowMs) {
|
|
|
205
214
|
// and session-id-shaped, so the ledger pass below can tell "expired"
|
|
206
215
|
// from "absent" from "still valid" without re-reading the file.
|
|
207
216
|
const statusBySessionId = new Map();
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
const readRootNames = (dir) => {
|
|
218
|
+
let dirStat;
|
|
219
|
+
try {
|
|
220
|
+
dirStat = fs.lstatSync(dir);
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return [];
|
|
224
|
+
}
|
|
225
|
+
if (!dirStat.isDirectory())
|
|
226
|
+
return [];
|
|
227
|
+
try {
|
|
228
|
+
return fs.readdirSync(dir);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const delegationNames = readRootNames(delegationsDir);
|
|
215
235
|
for (const name of delegationNames) {
|
|
216
236
|
if (!SESSION_ID_BASENAME_RE.test(name))
|
|
217
237
|
continue;
|
|
@@ -229,13 +249,7 @@ function sweepDelegations(generatedDir, cutoffMs, nowMs) {
|
|
|
229
249
|
kept += 1;
|
|
230
250
|
}
|
|
231
251
|
}
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
ledgerNames = fs.readdirSync(ledgerDir);
|
|
235
|
-
}
|
|
236
|
-
catch {
|
|
237
|
-
ledgerNames = [];
|
|
238
|
-
}
|
|
252
|
+
const ledgerNames = readRootNames(ledgerDir);
|
|
239
253
|
for (const name of ledgerNames) {
|
|
240
254
|
if (!SESSION_ID_BASENAME_RE.test(name))
|
|
241
255
|
continue;
|