@deftai/directive-core 0.108.0 → 0.109.1
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/dist/cache/operations.js +1 -1
- package/dist/check/gate-lists.d.ts +14 -0
- package/dist/check/gate-lists.js +26 -3
- package/dist/check/session-completed-ac.d.ts +1 -1
- package/dist/check/session-completed-ac.js +1 -1
- package/dist/consumer-check-contract/evaluate.d.ts +47 -0
- package/dist/consumer-check-contract/evaluate.js +181 -15
- package/dist/delivery-attempt/evaluate.d.ts +9 -1
- package/dist/delivery-attempt/evaluate.js +69 -0
- package/dist/delivery-attempt/index.d.ts +1 -1
- package/dist/delivery-attempt/index.js +1 -1
- package/dist/deposit/live-procedure-exclusions.d.ts +18 -0
- package/dist/deposit/live-procedure-exclusions.js +110 -0
- package/dist/deposit/live-procedure-targets.d.ts +45 -0
- package/dist/deposit/live-procedure-targets.js +274 -0
- package/dist/deposit/python-free.d.ts +6 -0
- package/dist/deposit/python-free.js +15 -0
- package/dist/deposit/rewrite-deposit-links.d.ts +42 -0
- package/dist/deposit/rewrite-deposit-links.js +148 -0
- package/dist/deposit/run-stage-content-pack.d.ts +2 -0
- package/dist/deposit/run-stage-content-pack.js +3 -0
- package/dist/deposit/stage-content-pack.d.ts +17 -0
- package/dist/deposit/stage-content-pack.js +91 -0
- package/dist/design-critique/citation-grammar.d.ts +7 -0
- package/dist/design-critique/citation-grammar.js +1 -1
- package/dist/design-critique/completed-arc-record.d.ts +8 -1
- package/dist/design-critique/completed-arc-record.js +98 -14
- package/dist/hooks/classify/host-session-identity.d.ts +25 -12
- package/dist/hooks/classify/host-session-identity.js +64 -49
- package/dist/hooks/classify/index.d.ts +2 -2
- package/dist/hooks/classify/index.js +2 -2
- package/dist/hooks/classify/paths.d.ts +2 -0
- package/dist/hooks/classify/paths.js +8 -4
- package/dist/hooks/classify/stdin.js +69 -3
- package/dist/hooks/dest-form.d.ts +20 -1
- package/dist/hooks/dest-form.js +158 -21
- package/dist/hooks/dispatcher.d.ts +22 -2
- package/dist/hooks/dispatcher.js +338 -66
- package/dist/hooks/fixtures/cases.d.ts +6 -0
- package/dist/hooks/fixtures/cases.js +53 -0
- package/dist/hooks/git-destructive-log.d.ts +32 -0
- package/dist/hooks/git-destructive-log.js +46 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/owner-liveness.d.ts +92 -0
- package/dist/hooks/owner-liveness.js +103 -0
- package/dist/hooks/shell-write-targets.d.ts +10 -0
- package/dist/hooks/shell-write-targets.js +274 -0
- package/dist/hooks/tools.d.ts +49 -2
- package/dist/hooks/tools.js +96 -1
- package/dist/init-deposit/agent-hooks.d.ts +10 -0
- package/dist/init-deposit/agent-hooks.js +39 -0
- package/dist/init-deposit/gitignore.d.ts +7 -0
- package/dist/init-deposit/gitignore.js +24 -0
- package/dist/init-deposit/host-tool-coverage.d.ts +53 -0
- package/dist/init-deposit/host-tool-coverage.js +150 -0
- package/dist/init-deposit/index.d.ts +1 -0
- package/dist/init-deposit/index.js +1 -0
- package/dist/init-deposit/init-deposit.js +3 -0
- package/dist/init-deposit/refresh.js +7 -0
- package/dist/init-deposit/runtime-writers.d.ts +14 -0
- package/dist/init-deposit/runtime-writers.js +33 -0
- package/dist/intake/issue-ingest.d.ts +6 -1
- package/dist/intake/issue-ingest.js +21 -2
- package/dist/intake/reconcile-issues.js +13 -13
- package/dist/lifecycle/brief-envelope.d.ts +25 -0
- package/dist/lifecycle/brief-envelope.js +42 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/literal-acceptance/evaluate.js +14 -5
- package/dist/literal-acceptance/index.d.ts +1 -1
- package/dist/literal-acceptance/index.js +1 -1
- package/dist/literal-acceptance/run.d.ts +2 -0
- package/dist/literal-acceptance/run.js +19 -1
- package/dist/orchestration/subagent-monitor.d.ts +6 -0
- package/dist/orchestration/subagent-monitor.js +23 -1
- package/dist/orphan-active/candidate-scope.d.ts +53 -0
- package/dist/orphan-active/candidate-scope.js +157 -0
- package/dist/orphan-active/evaluate.d.ts +27 -0
- package/dist/orphan-active/evaluate.js +63 -6
- package/dist/orphan-active/index.d.ts +1 -0
- package/dist/orphan-active/index.js +1 -0
- package/dist/policy/merge-approval-head.js +7 -6
- package/dist/pr-closing-keywords/gh.js +32 -9
- package/dist/pr-closing-keywords/main.d.ts +1 -0
- package/dist/pr-closing-keywords/main.js +68 -3
- package/dist/pr-closing-keywords/types.d.ts +2 -0
- package/dist/pr-merge-readiness/gh.js +32 -9
- package/dist/pr-protected-issues/gh.js +36 -9
- package/dist/pr-wait-mergeable/wrappers.js +3 -3
- package/dist/product-first-done-gate/evaluate.js +6 -2
- package/dist/product-first-done-gate/types.js +2 -0
- package/dist/release/consumer-hard-stops.d.ts +48 -0
- package/dist/release/consumer-hard-stops.js +140 -0
- package/dist/release/consumer-readiness-disclosure.d.ts +18 -0
- package/dist/release/consumer-readiness-disclosure.js +51 -0
- package/dist/release/index.d.ts +2 -0
- package/dist/release/index.js +2 -0
- package/dist/release/pipeline.js +55 -0
- package/dist/release/run-consumer-readiness.d.ts +15 -0
- package/dist/release/run-consumer-readiness.js +24 -0
- package/dist/release/types.d.ts +6 -0
- package/dist/review-monitor/github-lease.js +4 -3
- package/dist/run-summary/types.d.ts +2 -2
- package/dist/scm/build-command.d.ts +2 -2
- package/dist/scm/build-command.js +2 -2
- package/dist/scm/call-shape.d.ts +25 -0
- package/dist/scm/call-shape.js +59 -0
- package/dist/scm/call.d.ts +7 -4
- package/dist/scm/call.js +41 -11
- package/dist/scm/gh-rest.d.ts +25 -12
- package/dist/scm/gh-rest.js +65 -15
- package/dist/scm/index.d.ts +2 -0
- package/dist/scm/index.js +2 -0
- package/dist/scm/spawn-status.d.ts +33 -0
- package/dist/scm/spawn-status.js +53 -0
- package/dist/scope/acceptance-evidence.d.ts +1 -1
- package/dist/scope/transition.js +4 -14
- package/dist/session/ac-pass-banking.d.ts +2 -2
- package/dist/session/ac-pass-banking.js +2 -2
- package/dist/session/child-occupancy.d.ts +72 -0
- package/dist/session/child-occupancy.js +209 -0
- package/dist/session/host-session-owner.d.ts +93 -0
- package/dist/session/host-session-owner.js +148 -0
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +2 -0
- package/dist/session/occupancy.d.ts +107 -2
- package/dist/session/occupancy.js +272 -34
- package/dist/session/verify-ac-session-cache.d.ts +2 -2
- package/dist/session/verify-ac-session-cache.js +2 -2
- package/dist/swarm/complete-cohort.js +2 -0
- package/dist/swarm/pre-dispatch.js +2 -0
- package/dist/swarm/subagent-status-dir.d.ts +2 -1
- package/dist/swarm/subagent-status-dir.js +11 -2
- package/dist/swarm/worktrees.js +2 -0
- package/dist/triage/evaluate/worktrees.js +153 -6
- package/dist/umbrella-current-shape/index.d.ts +51 -3
- package/dist/umbrella-current-shape/index.js +106 -18
- package/dist/validate-content/deposit-required.d.ts +39 -0
- package/dist/validate-content/deposit-required.js +147 -0
- package/dist/validate-content/index.d.ts +1 -0
- package/dist/validate-content/index.js +1 -0
- package/dist/validate-content/validate-links.d.ts +2 -3
- package/dist/validate-content/validate-links.js +29 -2
- package/dist/vbrief-activate/activate.d.ts +7 -2
- package/dist/vbrief-activate/activate.js +26 -13
- package/dist/verify-ac/evaluate.d.ts +9 -0
- package/dist/verify-ac/evaluate.js +32 -9
- package/dist/verify-env/agent-hooks.d.ts +6 -1
- package/dist/verify-env/agent-hooks.js +28 -2
- package/dist/verify-source/deposit-closure.d.ts +23 -0
- package/dist/verify-source/deposit-closure.js +162 -0
- package/dist/verify-source/index.d.ts +2 -0
- package/dist/verify-source/index.js +2 -0
- package/dist/verify-source/semantic-single-source.d.ts +36 -0
- package/dist/verify-source/semantic-single-source.js +349 -0
- package/package.json +3 -3
package/dist/hooks/tools.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
import type { ClassifyHookHost } from "./classify/types.js";
|
|
1
2
|
/** Host spellings that install-time matchers and runtime classification share. */
|
|
2
|
-
export declare const DIRECT_WRITE_TOOL_NAMES: readonly ["Edit", "Write", "WriteFile", "CreateFile", "MultiEdit", "NotebookEdit", "StrReplace", "SearchReplace", "Delete", "DeleteFile", "ApplyPatch", "apply_patch"];
|
|
3
|
+
export declare const DIRECT_WRITE_TOOL_NAMES: readonly ["Edit", "Write", "WriteFile", "CreateFile", "MultiEdit", "NotebookEdit", "StrReplace", "SearchReplace", "Delete", "DeleteFile", "ApplyPatch", "apply_patch", "write", "search_replace"];
|
|
3
4
|
/** PreToolUse spawn / sub-agent dispatch tools (#1185 / #2437). */
|
|
4
5
|
export declare const SPAWN_TOOL_NAMES: readonly ["Task", "SubagentStart", "spawn_subagent", "start_agent", "CreateAgent"];
|
|
5
6
|
/**
|
|
6
7
|
* Host spellings for Shell/Bash execution tools (#2711).
|
|
7
8
|
* Used for runtimeAuthority scopes.push / scopes.merge classification.
|
|
9
|
+
*
|
|
10
|
+
* `monitor` is Grok Build's second shell surface (#3987 audit): it executes an
|
|
11
|
+
* arbitrary shell command in the background, so leaving it out reproduces the
|
|
12
|
+
* `run_terminal_command` gap one tool over.
|
|
8
13
|
*/
|
|
9
|
-
export declare const SHELL_TOOL_NAMES: readonly ["Shell", "Bash", "BashTool", "shell", "bash"];
|
|
14
|
+
export declare const SHELL_TOOL_NAMES: readonly ["Shell", "Bash", "BashTool", "shell", "bash", "run_terminal_command", "monitor"];
|
|
10
15
|
/** Env override forcing hook-level read-only write denial (#1185). */
|
|
11
16
|
export declare const READ_ONLY_HOOK_ENV = "DEFT_HOOK_READ_ONLY";
|
|
12
17
|
export declare function isDirectWriteTool(toolName: string): boolean;
|
|
@@ -32,6 +37,48 @@ export declare const MCP_PUSH_MERGE_BARE_NAMES: readonly ["merge_pull_request",
|
|
|
32
37
|
export declare const DIRECT_WRITE_HOOK_MATCHER: string;
|
|
33
38
|
export declare const SPAWN_HOOK_MATCHER: string;
|
|
34
39
|
export declare const SHELL_HOOK_MATCHER: string;
|
|
40
|
+
/** Mutation tool names a host emits, grouped by the matcher that must carry them. */
|
|
41
|
+
export interface HostMutationToolCatalog {
|
|
42
|
+
readonly directWrite: readonly string[];
|
|
43
|
+
readonly shell: readonly string[];
|
|
44
|
+
readonly spawn: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One host's audited tool surface (#3987 acceptance item 2).
|
|
48
|
+
*
|
|
49
|
+
* The audit answers one question per tool name the host emits: is it in
|
|
50
|
+
* `mutation` (and therefore required to be a literal token of the deposited
|
|
51
|
+
* matcher AND recognized by the runtime classifier), or is it in `nonMutation`
|
|
52
|
+
* with the written reason it stays outside the gate? A name in neither is the
|
|
53
|
+
* silent gap this record exists to make loud.
|
|
54
|
+
*
|
|
55
|
+
* `unobservedReason` is the honest third state. The deposit asserting a
|
|
56
|
+
* spelling is not evidence that the host emits it, so a host whose PreToolUse
|
|
57
|
+
* payloads have not been observed says so rather than publishing a guess as
|
|
58
|
+
* coverage.
|
|
59
|
+
*/
|
|
60
|
+
export interface HostToolSurfaceAudit {
|
|
61
|
+
readonly mutation: HostMutationToolCatalog;
|
|
62
|
+
readonly nonMutation: Readonly<Record<string, string>>;
|
|
63
|
+
/** Null when the audit covers every name the host emits. */
|
|
64
|
+
readonly unobservedReason: string | null;
|
|
65
|
+
/** Where the observation came from, so a reader can re-run it. */
|
|
66
|
+
readonly source: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Per-host tool-surface audit (#3987). Read by the deterministic deposit
|
|
70
|
+
* coverage check, which fails closed when a host is absent from this table —
|
|
71
|
+
* so a newly supported host cannot silently ship with no coverage claim.
|
|
72
|
+
*/
|
|
73
|
+
export declare const HOST_TOOL_SURFACE_AUDIT: Readonly<Record<ClassifyHookHost, HostToolSurfaceAudit>>;
|
|
74
|
+
/**
|
|
75
|
+
* Known Grok mutation tool names. Deposited matchers must cover each name (#3987).
|
|
76
|
+
* Projection of the per-host audit; kept as a named export for the #3990 tests.
|
|
77
|
+
*/
|
|
78
|
+
export declare const GROK_MUTATION_TOOL_CATALOG: HostMutationToolCatalog;
|
|
79
|
+
/** Grok tools that are intentionally not mutation-gated, each with its reason. */
|
|
80
|
+
export declare const GROK_NON_MUTATION_TOOLS: Readonly<Record<string, string>>;
|
|
81
|
+
export declare function matcherHasLiteralToken(matcher: string, toolName: string): boolean;
|
|
35
82
|
/**
|
|
36
83
|
* PreToolUse matcher for MCP-class push/merge tools (#2711).
|
|
37
84
|
* Regex-friendly for Claude/nested hosts. Prefer broad install match +
|
package/dist/hooks/tools.js
CHANGED
|
@@ -12,6 +12,8 @@ export const DIRECT_WRITE_TOOL_NAMES = [
|
|
|
12
12
|
"DeleteFile",
|
|
13
13
|
"ApplyPatch",
|
|
14
14
|
"apply_patch",
|
|
15
|
+
"write",
|
|
16
|
+
"search_replace",
|
|
15
17
|
];
|
|
16
18
|
/** PreToolUse spawn / sub-agent dispatch tools (#1185 / #2437). */
|
|
17
19
|
export const SPAWN_TOOL_NAMES = [
|
|
@@ -24,8 +26,20 @@ export const SPAWN_TOOL_NAMES = [
|
|
|
24
26
|
/**
|
|
25
27
|
* Host spellings for Shell/Bash execution tools (#2711).
|
|
26
28
|
* Used for runtimeAuthority scopes.push / scopes.merge classification.
|
|
29
|
+
*
|
|
30
|
+
* `monitor` is Grok Build's second shell surface (#3987 audit): it executes an
|
|
31
|
+
* arbitrary shell command in the background, so leaving it out reproduces the
|
|
32
|
+
* `run_terminal_command` gap one tool over.
|
|
27
33
|
*/
|
|
28
|
-
export const SHELL_TOOL_NAMES = [
|
|
34
|
+
export const SHELL_TOOL_NAMES = [
|
|
35
|
+
"Shell",
|
|
36
|
+
"Bash",
|
|
37
|
+
"BashTool",
|
|
38
|
+
"shell",
|
|
39
|
+
"bash",
|
|
40
|
+
"run_terminal_command",
|
|
41
|
+
"monitor",
|
|
42
|
+
];
|
|
29
43
|
/** Env override forcing hook-level read-only write denial (#1185). */
|
|
30
44
|
export const READ_ONLY_HOOK_ENV = "DEFT_HOOK_READ_ONLY";
|
|
31
45
|
function normalizedToolName(toolName) {
|
|
@@ -87,6 +101,87 @@ export const MCP_PUSH_MERGE_BARE_NAMES = [
|
|
|
87
101
|
export const DIRECT_WRITE_HOOK_MATCHER = DIRECT_WRITE_TOOL_NAMES.join("|");
|
|
88
102
|
export const SPAWN_HOOK_MATCHER = SPAWN_TOOL_NAMES.join("|");
|
|
89
103
|
export const SHELL_HOOK_MATCHER = SHELL_TOOL_NAMES.join("|");
|
|
104
|
+
/**
|
|
105
|
+
* Per-host tool-surface audit (#3987). Read by the deterministic deposit
|
|
106
|
+
* coverage check, which fails closed when a host is absent from this table —
|
|
107
|
+
* so a newly supported host cannot silently ship with no coverage claim.
|
|
108
|
+
*/
|
|
109
|
+
export const HOST_TOOL_SURFACE_AUDIT = {
|
|
110
|
+
grok: {
|
|
111
|
+
mutation: {
|
|
112
|
+
directWrite: ["write", "search_replace"],
|
|
113
|
+
shell: ["run_terminal_command", "monitor"],
|
|
114
|
+
spawn: ["spawn_subagent"],
|
|
115
|
+
},
|
|
116
|
+
nonMutation: {
|
|
117
|
+
read_file: "read",
|
|
118
|
+
grep: "read",
|
|
119
|
+
list_dir: "read",
|
|
120
|
+
search_tool: "read",
|
|
121
|
+
web_search: "read",
|
|
122
|
+
web_fetch: "read",
|
|
123
|
+
todo_write: "session-local non-product scratch",
|
|
124
|
+
get_command_or_subagent_output: "poll, not a mutation; elapsed bound is evaluateInFlight",
|
|
125
|
+
wait_commands_or_subagents: "poll over already-dispatched work",
|
|
126
|
+
kill_command_or_subagent: "process control",
|
|
127
|
+
scheduler_delete: "removes a scheduled task; mutates no product path",
|
|
128
|
+
scheduler_list: "read",
|
|
129
|
+
enter_plan_mode: "session posture",
|
|
130
|
+
exit_plan_mode: "session posture",
|
|
131
|
+
image_gen: "writes generated media to session scratch, never a tracked product path",
|
|
132
|
+
image_edit: "writes generated media to session scratch, never a tracked product path",
|
|
133
|
+
image_to_video: "writes generated media to session scratch, never a tracked product path",
|
|
134
|
+
reference_to_video: "writes generated media to session scratch, never a tracked product path",
|
|
135
|
+
scheduler_create: "spawn-class and NOT covered: gating it routes a scheduling primitive through the " +
|
|
136
|
+
"full spawn stack (ritual + active xBRIEF), a new deny class that needs a deliberate " +
|
|
137
|
+
"policy decision rather than a coverage edit (#3987 residual)",
|
|
138
|
+
use_tool: "mcp-class and NOT covered: the dispatcher classifies on the outer tool name, and the " +
|
|
139
|
+
"MCP tool actually invoked is nested in tool_input.tool_name, so a matcher entry alone " +
|
|
140
|
+
"buys a hook invocation and no enforcement; reading the inner name is a classifier " +
|
|
141
|
+
"change, not a matcher change (#3987 residual)",
|
|
142
|
+
},
|
|
143
|
+
unobservedReason: null,
|
|
144
|
+
source: "Observed directly on Grok Build: this host's published tool list, plus the 5,354-call " +
|
|
145
|
+
"session census recorded on issue #3987.",
|
|
146
|
+
},
|
|
147
|
+
claude: {
|
|
148
|
+
mutation: { directWrite: [], shell: ["Bash"], spawn: [] },
|
|
149
|
+
nonMutation: {},
|
|
150
|
+
unobservedReason: "Only the shell spelling is established (`Bash`, re-derived from the deposits by the " +
|
|
151
|
+
"#3987 panel's completing seat 5471374558 F8). No PreToolUse payload for this host has " +
|
|
152
|
+
"been observed in this tree, so the direct-write and spawn spellings stay unclaimed " +
|
|
153
|
+
"rather than asserted from the deposit that is supposed to be under test.",
|
|
154
|
+
source: "Issue #3987 comment 5471374558 finding F8.",
|
|
155
|
+
},
|
|
156
|
+
codex: {
|
|
157
|
+
mutation: { directWrite: ["apply_patch"], shell: ["shell"], spawn: [] },
|
|
158
|
+
nonMutation: {},
|
|
159
|
+
unobservedReason: "Shell (`shell`) and the apply_patch write form are established — F8 for the shell " +
|
|
160
|
+
"spelling, #3614 for the Codex apply_patch payload path. The rest of this host's surface " +
|
|
161
|
+
"has not been observed in this tree.",
|
|
162
|
+
source: "Issue #3987 comment 5471374558 finding F8; #3614 Codex apply_patch handling.",
|
|
163
|
+
},
|
|
164
|
+
cursor: {
|
|
165
|
+
mutation: { directWrite: [], shell: [], spawn: [] },
|
|
166
|
+
nonMutation: {},
|
|
167
|
+
unobservedReason: "Unverified. Nothing in this tree establishes which tool names Cursor emits on " +
|
|
168
|
+
"preToolUse: the deposit asserts a matcher string and the fixture corpus asserts the " +
|
|
169
|
+
"framework's own assumption, neither of which observes the host. Cursor could be a " +
|
|
170
|
+
"second zero-coverage host by the exact mechanism that produced #3987 (5471374558 F8), " +
|
|
171
|
+
"and claiming coverage here would hide that.",
|
|
172
|
+
source: "Issue #3987 comment 5471374558 finding F8.",
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Known Grok mutation tool names. Deposited matchers must cover each name (#3987).
|
|
177
|
+
* Projection of the per-host audit; kept as a named export for the #3990 tests.
|
|
178
|
+
*/
|
|
179
|
+
export const GROK_MUTATION_TOOL_CATALOG = HOST_TOOL_SURFACE_AUDIT.grok.mutation;
|
|
180
|
+
/** Grok tools that are intentionally not mutation-gated, each with its reason. */
|
|
181
|
+
export const GROK_NON_MUTATION_TOOLS = HOST_TOOL_SURFACE_AUDIT.grok.nonMutation;
|
|
182
|
+
export function matcherHasLiteralToken(matcher, toolName) {
|
|
183
|
+
return matcher.split("|").includes(toolName);
|
|
184
|
+
}
|
|
90
185
|
/**
|
|
91
186
|
* PreToolUse matcher for MCP-class push/merge tools (#2711).
|
|
92
187
|
* Regex-friendly for Claude/nested hosts. Prefer broad install match +
|
|
@@ -27,6 +27,8 @@ export declare const CURSOR_TOOL_BEFORE_TIMEOUT_SECONDS = 30;
|
|
|
27
27
|
/** Nested Claude/Grok/Codex command-hook default timeout (seconds). */
|
|
28
28
|
export declare const NESTED_HOOK_TIMEOUT_SECONDS = 5;
|
|
29
29
|
export type AgentHookPath = (typeof AGENT_HOOK_PATHS)[number];
|
|
30
|
+
/** Deposit file each supported host reads its PreToolUse registration from. */
|
|
31
|
+
export declare const AGENT_HOOK_PATH_BY_HOST: Readonly<Record<HookHost, AgentHookPath>>;
|
|
30
32
|
export type AgentHookRegistrationStatus = "healthy" | "disabled" | "missing" | "drifted";
|
|
31
33
|
/** Whether the host receives a compact/resume hook deposit (#2113). */
|
|
32
34
|
export type AgentHookCompactSupport = "deposited" | "unsupported";
|
|
@@ -43,6 +45,14 @@ export interface AgentHookDepositResult {
|
|
|
43
45
|
}
|
|
44
46
|
/** Merge Directive-owned project hook entries without replacing user configuration. */
|
|
45
47
|
export declare function writeAgentHookDeposit(projectRoot: string, io?: InitDepositIo, hostHooksPolicy?: HostHooksPolicy, travelSeams?: HookRuntimeTravelSeams): AgentHookDepositResult;
|
|
48
|
+
/**
|
|
49
|
+
* PreToolUse matchers a host would actually match against, read from the
|
|
50
|
+
* deposited file rather than regenerated from the constants (#3987).
|
|
51
|
+
*
|
|
52
|
+
* Null means the deposit is absent or unreadable — a different failure with a
|
|
53
|
+
* different remediation, already reported by `inspectAgentHookDeposit`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function depositedPreToolUseMatchers(projectRoot: string, host: HookHost): readonly string[] | null;
|
|
46
56
|
/** Read-only registration probe shared by verify and doctor. */
|
|
47
57
|
export declare function inspectAgentHookDeposit(projectRoot: string, hostHooksPolicy?: HostHooksPolicy): AgentHookInspection[];
|
|
48
58
|
//# sourceMappingURL=agent-hooks.d.ts.map
|
|
@@ -34,6 +34,13 @@ export const CURSOR_SESSION_HOOK_TIMEOUT_SECONDS = 5;
|
|
|
34
34
|
export const CURSOR_TOOL_BEFORE_TIMEOUT_SECONDS = 30;
|
|
35
35
|
/** Nested Claude/Grok/Codex command-hook default timeout (seconds). */
|
|
36
36
|
export const NESTED_HOOK_TIMEOUT_SECONDS = 5;
|
|
37
|
+
/** Deposit file each supported host reads its PreToolUse registration from. */
|
|
38
|
+
export const AGENT_HOOK_PATH_BY_HOST = {
|
|
39
|
+
claude: AGENT_HOOK_PATHS[0],
|
|
40
|
+
grok: AGENT_HOOK_PATHS[1],
|
|
41
|
+
cursor: AGENT_HOOK_PATHS[2],
|
|
42
|
+
codex: AGENT_HOOK_PATHS[3],
|
|
43
|
+
};
|
|
37
44
|
function object(value) {
|
|
38
45
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
39
46
|
? value
|
|
@@ -404,6 +411,38 @@ function hasCursorRegistration(config) {
|
|
|
404
411
|
preTool.some((entry) => isCursorToolBeforeEntry(entry, MCP_HOOK_MATCHER)) &&
|
|
405
412
|
preCompact.some((entry) => object(entry)?.command === command("cursor", "session.compact")));
|
|
406
413
|
}
|
|
414
|
+
/**
|
|
415
|
+
* PreToolUse matchers a host would actually match against, read from the
|
|
416
|
+
* deposited file rather than regenerated from the constants (#3987).
|
|
417
|
+
*
|
|
418
|
+
* Null means the deposit is absent or unreadable — a different failure with a
|
|
419
|
+
* different remediation, already reported by `inspectAgentHookDeposit`.
|
|
420
|
+
*/
|
|
421
|
+
export function depositedPreToolUseMatchers(projectRoot, host) {
|
|
422
|
+
const path = join(resolve(projectRoot), AGENT_HOOK_PATH_BY_HOST[host]);
|
|
423
|
+
if (!existsSync(path))
|
|
424
|
+
return null;
|
|
425
|
+
let config;
|
|
426
|
+
try {
|
|
427
|
+
config = readConfig(path);
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
const hooks = object(config.hooks);
|
|
433
|
+
if (hooks === null)
|
|
434
|
+
return [];
|
|
435
|
+
const matcherOf = (entry) => {
|
|
436
|
+
const matcher = object(entry)?.matcher;
|
|
437
|
+
return typeof matcher === "string" ? [matcher] : [];
|
|
438
|
+
};
|
|
439
|
+
if (host === "cursor") {
|
|
440
|
+
const entries = Array.isArray(hooks.preToolUse) ? hooks.preToolUse : [];
|
|
441
|
+
return entries.filter(isManagedCursorEntry).flatMap(matcherOf);
|
|
442
|
+
}
|
|
443
|
+
const entries = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
|
|
444
|
+
return entries.filter((entry) => isManagedNestedGroupForHost(entry, host)).flatMap(matcherOf);
|
|
445
|
+
}
|
|
407
446
|
/** Read-only registration probe shared by verify and doctor. */
|
|
408
447
|
export function inspectAgentHookDeposit(projectRoot, hostHooksPolicy = loadHostHooksPolicyFromProject(projectRoot)) {
|
|
409
448
|
const definitions = [
|
|
@@ -25,6 +25,13 @@ export interface ReconstituteDepositResult {
|
|
|
25
25
|
readonly reconstituted: boolean;
|
|
26
26
|
}
|
|
27
27
|
export type GitLsFiles = (projectDir: string, paths: readonly string[]) => string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Strip leading/trailing slashes so `.deft/cache/` and `.deft/cache` match.
|
|
30
|
+
* Globs are not expanded: a writer covered only by a glob fails closed (#3612).
|
|
31
|
+
*/
|
|
32
|
+
export declare function normalizeGitignorePath(p: string): string;
|
|
33
|
+
export declare function gitignoreRuleCoversPath(rule: string, relPath: string): boolean;
|
|
34
|
+
export declare function ignoreSetCoversPath(rules: readonly string[], relPath: string): boolean;
|
|
28
35
|
/**
|
|
29
36
|
* Reports whether `.deft/core` is tracked in git. Returns `null` when git is
|
|
30
37
|
* unavailable or the tree is not a repository (treated as greenfield).
|
|
@@ -31,6 +31,13 @@ export const CANONICAL_GITIGNORE_BASELINE = [
|
|
|
31
31
|
".deft/last-session.json",
|
|
32
32
|
".deft/occupancy.json",
|
|
33
33
|
".deft/routing.local.json",
|
|
34
|
+
// #3612: remaining runtime writer roots kept at historical names (on-disk
|
|
35
|
+
// contracts). Relocating them would break existing consumer state.
|
|
36
|
+
".deft/authz/",
|
|
37
|
+
".deft/delivery-attempts/",
|
|
38
|
+
".deft/metrics/",
|
|
39
|
+
".deft/escalations/",
|
|
40
|
+
".deft/approved-scope/",
|
|
34
41
|
// Agent-host working state (#3502). Selective, NEVER blanket `.claude/`:
|
|
35
42
|
// `.claude/settings.json`, `.claude/skills/` and `.claude/commands/` are
|
|
36
43
|
// MANAGED DEPOSITS (agent-hooks.ts / skill-discovery-hosts.ts) and must stay
|
|
@@ -105,6 +112,23 @@ function gitignoreCoversLine(present, line) {
|
|
|
105
112
|
}
|
|
106
113
|
return false;
|
|
107
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Strip leading/trailing slashes so `.deft/cache/` and `.deft/cache` match.
|
|
117
|
+
* Globs are not expanded: a writer covered only by a glob fails closed (#3612).
|
|
118
|
+
*/
|
|
119
|
+
export function normalizeGitignorePath(p) {
|
|
120
|
+
return p.replaceAll("\\", "/").replace(/^\/+/, "").replace(/\/+$/, "");
|
|
121
|
+
}
|
|
122
|
+
export function gitignoreRuleCoversPath(rule, relPath) {
|
|
123
|
+
const r = normalizeGitignorePath(stripGitignoreInlineComment(rule));
|
|
124
|
+
const p = normalizeGitignorePath(relPath);
|
|
125
|
+
if (!r || r.startsWith("#"))
|
|
126
|
+
return false;
|
|
127
|
+
return r === p || p.startsWith(`${r}/`);
|
|
128
|
+
}
|
|
129
|
+
export function ignoreSetCoversPath(rules, relPath) {
|
|
130
|
+
return rules.some((rule) => gitignoreRuleCoversPath(rule, relPath));
|
|
131
|
+
}
|
|
108
132
|
function collectPresentGitignoreLines(existing) {
|
|
109
133
|
const present = new Set();
|
|
110
134
|
for (const raw of existing.split("\n")) {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic host tool-surface coverage check (#3987 acceptance item 3).
|
|
3
|
+
*
|
|
4
|
+
* #3990 shipped a Grok-only catalog asserted by a unit test against the
|
|
5
|
+
* generated matcher constants. That cannot catch what the acceptance item
|
|
6
|
+
* names: a host whose deposit went stale, or a host added with no coverage
|
|
7
|
+
* claim at all (5471374558 F7). This check reads the deposited files, walks
|
|
8
|
+
* every supported host, and fails closed on four distinct silences:
|
|
9
|
+
*
|
|
10
|
+
* 1. A supported host with no audit entry — the "new host drops out of
|
|
11
|
+
* coverage" case. The typed `HOST_TOOL_SURFACE_AUDIT` record makes this a
|
|
12
|
+
* compile error inside this package; the runtime check covers hosts added
|
|
13
|
+
* to the deposit list alone.
|
|
14
|
+
* 2. A catalogued mutation tool name that is not a literal token of any
|
|
15
|
+
* deposited matcher — the "renamed tool drops out of coverage" case. Read
|
|
16
|
+
* from the deposit, so a stale file fails even when the constants are right.
|
|
17
|
+
* 3. A catalogued mutation tool name the runtime classifier does not place in
|
|
18
|
+
* the same group. The deposited matcher is a literal alternation while the
|
|
19
|
+
* classifier lowercases and strips punctuation, so the two layers can
|
|
20
|
+
* disagree on a name that is present in both.
|
|
21
|
+
* 4. An audit entry that claims something without saying why: an empty
|
|
22
|
+
* out-of-scope reason, a host claiming a fully observed surface while naming
|
|
23
|
+
* no mutation tool, or a non-mutation entry the classifier actually gates.
|
|
24
|
+
*/
|
|
25
|
+
import { type HookHost } from "../hooks/dispatcher.js";
|
|
26
|
+
import { type HostHooksPolicy } from "../policy/host-hooks.js";
|
|
27
|
+
import { type AgentHookPath } from "./agent-hooks.js";
|
|
28
|
+
export type HostToolCoverageFindingKind =
|
|
29
|
+
/** Supported host with no entry in the audit table. */
|
|
30
|
+
"missing-audit"
|
|
31
|
+
/** Catalogued mutation name absent from every deposited matcher. */
|
|
32
|
+
| "uncovered-tool"
|
|
33
|
+
/** Deposited name the runtime classifier does not place in the same group. */
|
|
34
|
+
| "unclassified-tool"
|
|
35
|
+
/** Audit entry that asserts without a written reason. */
|
|
36
|
+
| "unexplained-entry";
|
|
37
|
+
export interface HostToolCoverageFinding {
|
|
38
|
+
readonly host: HookHost;
|
|
39
|
+
readonly path: AgentHookPath;
|
|
40
|
+
readonly kind: HostToolCoverageFindingKind;
|
|
41
|
+
readonly toolName: string | null;
|
|
42
|
+
readonly detail: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Read-only per-host coverage probe over the deposited matchers.
|
|
46
|
+
* A host whose deposit is missing or unreadable is skipped: that is a
|
|
47
|
+
* registration failure with its own remediation, reported by
|
|
48
|
+
* `inspectAgentHookDeposit`, and reporting it twice hides which one to fix.
|
|
49
|
+
*/
|
|
50
|
+
export declare function inspectHostToolCoverage(projectRoot: string, hostHooksPolicy: HostHooksPolicy): readonly HostToolCoverageFinding[];
|
|
51
|
+
/** Remediation line for the coverage class, distinct from the deposit-refresh one. */
|
|
52
|
+
export declare const HOST_TOOL_COVERAGE_RECOVERY: string;
|
|
53
|
+
//# sourceMappingURL=host-tool-coverage.d.ts.map
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic host tool-surface coverage check (#3987 acceptance item 3).
|
|
3
|
+
*
|
|
4
|
+
* #3990 shipped a Grok-only catalog asserted by a unit test against the
|
|
5
|
+
* generated matcher constants. That cannot catch what the acceptance item
|
|
6
|
+
* names: a host whose deposit went stale, or a host added with no coverage
|
|
7
|
+
* claim at all (5471374558 F7). This check reads the deposited files, walks
|
|
8
|
+
* every supported host, and fails closed on four distinct silences:
|
|
9
|
+
*
|
|
10
|
+
* 1. A supported host with no audit entry — the "new host drops out of
|
|
11
|
+
* coverage" case. The typed `HOST_TOOL_SURFACE_AUDIT` record makes this a
|
|
12
|
+
* compile error inside this package; the runtime check covers hosts added
|
|
13
|
+
* to the deposit list alone.
|
|
14
|
+
* 2. A catalogued mutation tool name that is not a literal token of any
|
|
15
|
+
* deposited matcher — the "renamed tool drops out of coverage" case. Read
|
|
16
|
+
* from the deposit, so a stale file fails even when the constants are right.
|
|
17
|
+
* 3. A catalogued mutation tool name the runtime classifier does not place in
|
|
18
|
+
* the same group. The deposited matcher is a literal alternation while the
|
|
19
|
+
* classifier lowercases and strips punctuation, so the two layers can
|
|
20
|
+
* disagree on a name that is present in both.
|
|
21
|
+
* 4. An audit entry that claims something without saying why: an empty
|
|
22
|
+
* out-of-scope reason, a host claiming a fully observed surface while naming
|
|
23
|
+
* no mutation tool, or a non-mutation entry the classifier actually gates.
|
|
24
|
+
*/
|
|
25
|
+
import { HOOK_HOSTS } from "../hooks/dispatcher.js";
|
|
26
|
+
import { HOST_TOOL_SURFACE_AUDIT, isDirectWriteTool, isShellTool, isSpawnTool, matcherHasLiteralToken, } from "../hooks/tools.js";
|
|
27
|
+
import { isHostHookDepositEnabled } from "../policy/host-hooks.js";
|
|
28
|
+
import { AGENT_HOOK_PATH_BY_HOST, depositedPreToolUseMatchers, } from "./agent-hooks.js";
|
|
29
|
+
const CLASSIFIERS = {
|
|
30
|
+
directWrite: isDirectWriteTool,
|
|
31
|
+
shell: isShellTool,
|
|
32
|
+
spawn: isSpawnTool,
|
|
33
|
+
};
|
|
34
|
+
const MUTATION_GROUPS = ["directWrite", "shell", "spawn"];
|
|
35
|
+
function auditFor(host) {
|
|
36
|
+
return HOST_TOOL_SURFACE_AUDIT[host];
|
|
37
|
+
}
|
|
38
|
+
function checkAuditShape(host, path, audit) {
|
|
39
|
+
const findings = [];
|
|
40
|
+
const mutationNames = MUTATION_GROUPS.flatMap((group) => audit.mutation[group]);
|
|
41
|
+
if (audit.unobservedReason !== null && audit.unobservedReason.trim().length === 0) {
|
|
42
|
+
findings.push({
|
|
43
|
+
host,
|
|
44
|
+
path,
|
|
45
|
+
kind: "unexplained-entry",
|
|
46
|
+
toolName: null,
|
|
47
|
+
detail: "unobservedReason is present but empty — say what was not observed, or set it null.",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (audit.unobservedReason === null && mutationNames.length === 0) {
|
|
51
|
+
findings.push({
|
|
52
|
+
host,
|
|
53
|
+
path,
|
|
54
|
+
kind: "unexplained-entry",
|
|
55
|
+
toolName: null,
|
|
56
|
+
detail: "the audit claims a fully observed surface yet names no mutation tool. Either list the " +
|
|
57
|
+
"host's mutation spellings or record why the surface is unobserved.",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (audit.source.trim().length === 0) {
|
|
61
|
+
findings.push({
|
|
62
|
+
host,
|
|
63
|
+
path,
|
|
64
|
+
kind: "unexplained-entry",
|
|
65
|
+
toolName: null,
|
|
66
|
+
detail: "source is empty — a coverage claim must name where it was observed.",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
for (const [toolName, reason] of Object.entries(audit.nonMutation)) {
|
|
70
|
+
if (reason.trim().length === 0) {
|
|
71
|
+
findings.push({
|
|
72
|
+
host,
|
|
73
|
+
path,
|
|
74
|
+
kind: "unexplained-entry",
|
|
75
|
+
toolName,
|
|
76
|
+
detail: "listed out of scope with no written reason.",
|
|
77
|
+
});
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const gated = MUTATION_GROUPS.find((group) => CLASSIFIERS[group](toolName));
|
|
81
|
+
if (gated !== undefined) {
|
|
82
|
+
findings.push({
|
|
83
|
+
host,
|
|
84
|
+
path,
|
|
85
|
+
kind: "unexplained-entry",
|
|
86
|
+
toolName,
|
|
87
|
+
detail: `recorded as out of scope, but the runtime classifier gates it as ${gated}.`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return findings;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Read-only per-host coverage probe over the deposited matchers.
|
|
95
|
+
* A host whose deposit is missing or unreadable is skipped: that is a
|
|
96
|
+
* registration failure with its own remediation, reported by
|
|
97
|
+
* `inspectAgentHookDeposit`, and reporting it twice hides which one to fix.
|
|
98
|
+
*/
|
|
99
|
+
export function inspectHostToolCoverage(projectRoot, hostHooksPolicy) {
|
|
100
|
+
const findings = [];
|
|
101
|
+
for (const host of HOOK_HOSTS) {
|
|
102
|
+
const path = AGENT_HOOK_PATH_BY_HOST[host];
|
|
103
|
+
if (!isHostHookDepositEnabled(host, hostHooksPolicy))
|
|
104
|
+
continue;
|
|
105
|
+
const audit = auditFor(host);
|
|
106
|
+
if (audit === undefined) {
|
|
107
|
+
findings.push({
|
|
108
|
+
host,
|
|
109
|
+
path,
|
|
110
|
+
kind: "missing-audit",
|
|
111
|
+
toolName: null,
|
|
112
|
+
detail: "supported host has no entry in HOST_TOOL_SURFACE_AUDIT, so nothing states which of " +
|
|
113
|
+
"its tool names must be covered.",
|
|
114
|
+
});
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
findings.push(...checkAuditShape(host, path, audit));
|
|
118
|
+
const matchers = depositedPreToolUseMatchers(projectRoot, host);
|
|
119
|
+
if (matchers === null)
|
|
120
|
+
continue;
|
|
121
|
+
for (const group of MUTATION_GROUPS) {
|
|
122
|
+
for (const toolName of audit.mutation[group]) {
|
|
123
|
+
if (!matchers.some((matcher) => matcherHasLiteralToken(matcher, toolName))) {
|
|
124
|
+
findings.push({
|
|
125
|
+
host,
|
|
126
|
+
path,
|
|
127
|
+
kind: "uncovered-tool",
|
|
128
|
+
toolName,
|
|
129
|
+
detail: `${group} tool is absent from every deposited PreToolUse matcher.`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (!CLASSIFIERS[group](toolName)) {
|
|
133
|
+
findings.push({
|
|
134
|
+
host,
|
|
135
|
+
path,
|
|
136
|
+
kind: "unclassified-tool",
|
|
137
|
+
toolName,
|
|
138
|
+
detail: `${group} tool is not recognized by the runtime ${group} classifier.`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return findings;
|
|
145
|
+
}
|
|
146
|
+
/** Remediation line for the coverage class, distinct from the deposit-refresh one. */
|
|
147
|
+
export const HOST_TOOL_COVERAGE_RECOVERY = "Recovery: run `deft update` to re-deposit the current matchers. If a finding survives that, " +
|
|
148
|
+
"the tool name is missing from Directive's own catalog rather than from your deposit — report " +
|
|
149
|
+
"it upstream with the host and tool name. Audit record: .deft/core/docs/host-tool-surface-audit.md (#3987).";
|
|
150
|
+
//# sourceMappingURL=host-tool-coverage.js.map
|
|
@@ -10,6 +10,7 @@ import { homedir, platform } from "node:os";
|
|
|
10
10
|
import { basename, join, resolve } from "node:path";
|
|
11
11
|
import { assertDepositContained } from "../deposit/contain.js";
|
|
12
12
|
import { copyTree } from "../deposit/copy-tree.js";
|
|
13
|
+
import { assertLiveProcedureDepositClean } from "../deposit/live-procedure-targets.js";
|
|
13
14
|
import { prunePythonArtifactsFromDeposit } from "../deposit/python-free.js";
|
|
14
15
|
import { resolveInstalledContentRoot } from "../deposit/resolve-content.js";
|
|
15
16
|
import { readCorePackageVersion } from "../engine-version.js";
|
|
@@ -173,8 +174,10 @@ export async function runInitDeposit(args, io, seams = {}) {
|
|
|
173
174
|
const resolveContent = seams.resolveContentRoot ?? resolveInstalledContentRoot;
|
|
174
175
|
const copyContent = seams.copyContent ?? copyTree;
|
|
175
176
|
const contentRoot = await resolveContent();
|
|
177
|
+
assertLiveProcedureDepositClean(contentRoot);
|
|
176
178
|
await reconstituteDepositFromContent(contentRoot, deftDir, copyContent);
|
|
177
179
|
await prunePythonArtifactsFromDeposit(deftDir, projectDir, io);
|
|
180
|
+
assertLiveProcedureDepositClean(deftDir);
|
|
178
181
|
ensureInitGitignoreLines(projectDir, io);
|
|
179
182
|
ensurePrettierIgnoreLines(projectDir, io);
|
|
180
183
|
const nowIso = seams.nowIso ?? (() => new Date().toISOString().replace(/\.\d{3}Z$/, "Z"));
|
|
@@ -13,6 +13,7 @@ import { platform as osPlatform } from "node:os";
|
|
|
13
13
|
import { join, resolve } from "node:path";
|
|
14
14
|
import { assertDepositContained } from "../deposit/contain.js";
|
|
15
15
|
import { replaceTree } from "../deposit/copy-tree.js";
|
|
16
|
+
import { assertLiveProcedureDepositClean } from "../deposit/live-procedure-targets.js";
|
|
16
17
|
import { prunePythonArtifactsFromDeposit } from "../deposit/python-free.js";
|
|
17
18
|
import { resolveInstalledContentRoot } from "../deposit/resolve-content.js";
|
|
18
19
|
import { manifestTagToVersion, parseInstallManifest } from "../doctor/manifest.js";
|
|
@@ -476,9 +477,12 @@ export async function runRefreshDeposit(args, io, seams = {}) {
|
|
|
476
477
|
const strategy = alreadyCurrent ? "no-op" : "file-swap";
|
|
477
478
|
if (alreadyCurrent) {
|
|
478
479
|
io.printf("[deft update] Framework payload already current; skipping payload copy.\n");
|
|
480
|
+
// C3 even when VERSION matches: skip-copy is not skip-validation (#3602).
|
|
481
|
+
assertLiveProcedureDepositClean(contentRoot);
|
|
479
482
|
// #2913: still fail-closed reconcile so dst-only leftovers cannot linger when
|
|
480
483
|
// VERSION already matches (e.g. pre-#2804 additive deposits). Does not re-stamp.
|
|
481
484
|
await reconcileDepositToContentPackage(deftDir, contentRoot, io);
|
|
485
|
+
assertLiveProcedureDepositClean(deftDir);
|
|
482
486
|
migrateLegacyInstallManifest(projectDir, join(deftDir, "VERSION"));
|
|
483
487
|
// #3117: ensure a readable live generation token exists without advancing
|
|
484
488
|
// when the payload did not swap (already-current). stampLiveGeneration is a
|
|
@@ -504,8 +508,11 @@ export async function runRefreshDeposit(args, io, seams = {}) {
|
|
|
504
508
|
}
|
|
505
509
|
else {
|
|
506
510
|
// Full-tree replace (or injected seam). Additive copy is no longer the default.
|
|
511
|
+
// C3 the incoming package BEFORE replace so a reject cannot leave a broken deposit.
|
|
512
|
+
assertLiveProcedureDepositClean(contentRoot);
|
|
507
513
|
await copyContent(contentRoot, deftDir);
|
|
508
514
|
await prunePythonArtifactsFromDeposit(deftDir, projectDir, io);
|
|
515
|
+
assertLiveProcedureDepositClean(deftDir);
|
|
509
516
|
// #2913 / #2804 / #2347: fail-closed delete-not-in-source BEFORE VERSION stamp.
|
|
510
517
|
// replaceTree already drops dst-only paths; reconcile verifies and covers
|
|
511
518
|
// additive seams. Throws => no VERSION rewrite (refuse stamp until clean).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime writer paths that land in a consumer working tree (#3612).
|
|
3
|
+
*
|
|
4
|
+
* The ignore baselines and this list are coupled: every exported writer path
|
|
5
|
+
* constant MUST appear here, and a fail-closed test asserts the ignore set
|
|
6
|
+
* covers each entry on both shipped surfaces. New writers join this registry;
|
|
7
|
+
* they do not get a silent extra .deft/ name.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Imported writer path constants. Order is the lockstep contract with
|
|
11
|
+
* runtime-writer-paths.json (Go reads that file).
|
|
12
|
+
*/
|
|
13
|
+
export declare const RUNTIME_WRITER_PATHS: readonly string[];
|
|
14
|
+
//# sourceMappingURL=runtime-writers.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime writer paths that land in a consumer working tree (#3612).
|
|
3
|
+
*
|
|
4
|
+
* The ignore baselines and this list are coupled: every exported writer path
|
|
5
|
+
* constant MUST appear here, and a fail-closed test asserts the ignore set
|
|
6
|
+
* covers each entry on both shipped surfaces. New writers join this registry;
|
|
7
|
+
* they do not get a silent extra .deft/ name.
|
|
8
|
+
*/
|
|
9
|
+
import { AUTHZ_DIR } from "../authz/types.js";
|
|
10
|
+
import { DEFAULT_TASK_CACHE_ROOT } from "../cache/task-cache/constants.js";
|
|
11
|
+
import { SESSION_COMPLETED_MARKER_REL } from "../check/session-completed-ac.js";
|
|
12
|
+
import { DELIVERY_ATTEMPT_DIR } from "../delivery-attempt/types.js";
|
|
13
|
+
import { ESCALATION_DIR } from "../escalation/types.js";
|
|
14
|
+
import { PROJECT_LOCAL_METRICS_DIR } from "../metrics/resolve-metrics-home.js";
|
|
15
|
+
import { APPROVED_SCOPE_DIR } from "../scope-provenance/digest.js";
|
|
16
|
+
import { AC_PASS_BANK_DIR } from "../session/ac-pass-banking.js";
|
|
17
|
+
import { VERIFY_AC_SESSION_CACHE_DIR } from "../session/verify-ac-session-cache.js";
|
|
18
|
+
/**
|
|
19
|
+
* Imported writer path constants. Order is the lockstep contract with
|
|
20
|
+
* runtime-writer-paths.json (Go reads that file).
|
|
21
|
+
*/
|
|
22
|
+
export const RUNTIME_WRITER_PATHS = Object.freeze([
|
|
23
|
+
AC_PASS_BANK_DIR,
|
|
24
|
+
VERIFY_AC_SESSION_CACHE_DIR,
|
|
25
|
+
SESSION_COMPLETED_MARKER_REL.join("/"),
|
|
26
|
+
AUTHZ_DIR,
|
|
27
|
+
DELIVERY_ATTEMPT_DIR,
|
|
28
|
+
PROJECT_LOCAL_METRICS_DIR,
|
|
29
|
+
ESCALATION_DIR,
|
|
30
|
+
APPROVED_SCOPE_DIR,
|
|
31
|
+
DEFAULT_TASK_CACHE_ROOT,
|
|
32
|
+
]);
|
|
33
|
+
//# sourceMappingURL=runtime-writers.js.map
|