@aragon-agent/cli 0.4.3
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 +292 -0
- package/README.md +558 -0
- package/dist/agent/coalesce.d.ts +14 -0
- package/dist/agent/coalesce.js +41 -0
- package/dist/agent/controller.d.ts +132 -0
- package/dist/agent/controller.js +332 -0
- package/dist/agent/headless.d.ts +22 -0
- package/dist/agent/headless.js +74 -0
- package/dist/agent/reducer.d.ts +181 -0
- package/dist/agent/reducer.js +420 -0
- package/dist/agent/system-prompt.d.ts +30 -0
- package/dist/agent/system-prompt.js +58 -0
- package/dist/agent/usage.d.ts +13 -0
- package/dist/agent/usage.js +41 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +482 -0
- package/dist/commands/builtins.d.ts +16 -0
- package/dist/commands/builtins.js +223 -0
- package/dist/commands/registry.d.ts +48 -0
- package/dist/commands/registry.js +45 -0
- package/dist/commands/skills.d.ts +22 -0
- package/dist/commands/skills.js +625 -0
- package/dist/config/app-paths.d.ts +11 -0
- package/dist/config/app-paths.js +16 -0
- package/dist/config/env.d.ts +28 -0
- package/dist/config/env.js +92 -0
- package/dist/config/load.d.ts +48 -0
- package/dist/config/load.js +158 -0
- package/dist/config/migrate-legacy-state.d.ts +78 -0
- package/dist/config/migrate-legacy-state.js +181 -0
- package/dist/config/schema.d.ts +249 -0
- package/dist/config/schema.js +247 -0
- package/dist/config/store.d.ts +44 -0
- package/dist/config/store.js +126 -0
- package/dist/input/keymap.d.ts +20 -0
- package/dist/input/keymap.js +85 -0
- package/dist/session/persist.d.ts +24 -0
- package/dist/session/persist.js +51 -0
- package/dist/skills/archive.d.ts +41 -0
- package/dist/skills/archive.js +152 -0
- package/dist/skills/cli-commands.d.ts +52 -0
- package/dist/skills/cli-commands.js +502 -0
- package/dist/skills/fetch-source.d.ts +104 -0
- package/dist/skills/fetch-source.js +448 -0
- package/dist/skills/installer.d.ts +117 -0
- package/dist/skills/installer.js +414 -0
- package/dist/skills/lock.d.ts +75 -0
- package/dist/skills/lock.js +223 -0
- package/dist/skills/manifest.d.ts +47 -0
- package/dist/skills/manifest.js +95 -0
- package/dist/skills/node-host.d.ts +23 -0
- package/dist/skills/node-host.js +59 -0
- package/dist/skills/paths.d.ts +61 -0
- package/dist/skills/paths.js +107 -0
- package/dist/skills/service.d.ts +256 -0
- package/dist/skills/service.js +730 -0
- package/dist/skills/tools.d.ts +35 -0
- package/dist/skills/tools.js +164 -0
- package/dist/skills/updater.d.ts +101 -0
- package/dist/skills/updater.js +330 -0
- package/dist/skills/usage.d.ts +72 -0
- package/dist/skills/usage.js +216 -0
- package/dist/tools/bash-tool.d.ts +12 -0
- package/dist/tools/bash-tool.js +131 -0
- package/dist/tools/diff.d.ts +15 -0
- package/dist/tools/diff.js +50 -0
- package/dist/tools/fs-tools.d.ts +16 -0
- package/dist/tools/fs-tools.js +215 -0
- package/dist/tools/index.d.ts +93 -0
- package/dist/tools/index.js +157 -0
- package/dist/tools/search-tools.d.ts +11 -0
- package/dist/tools/search-tools.js +225 -0
- package/dist/ui/App.d.ts +24 -0
- package/dist/ui/App.js +522 -0
- package/dist/ui/AutocompletePopup.d.ts +21 -0
- package/dist/ui/AutocompletePopup.js +19 -0
- package/dist/ui/Composer.d.ts +40 -0
- package/dist/ui/Composer.js +61 -0
- package/dist/ui/Header.d.ts +30 -0
- package/dist/ui/Header.js +25 -0
- package/dist/ui/Logo.d.ts +50 -0
- package/dist/ui/Logo.js +85 -0
- package/dist/ui/Markdown.d.ts +23 -0
- package/dist/ui/Markdown.js +122 -0
- package/dist/ui/PromptInput.d.ts +81 -0
- package/dist/ui/PromptInput.js +383 -0
- package/dist/ui/SessionOpener.d.ts +30 -0
- package/dist/ui/SessionOpener.js +12 -0
- package/dist/ui/StatusBar.d.ts +39 -0
- package/dist/ui/StatusBar.js +43 -0
- package/dist/ui/ToastStack.d.ts +24 -0
- package/dist/ui/ToastStack.js +38 -0
- package/dist/ui/Transcript.d.ts +62 -0
- package/dist/ui/Transcript.js +128 -0
- package/dist/ui/capabilities.d.ts +25 -0
- package/dist/ui/capabilities.js +59 -0
- package/dist/ui/console-bridge.d.ts +19 -0
- package/dist/ui/console-bridge.js +52 -0
- package/dist/ui/density.d.ts +26 -0
- package/dist/ui/density.js +34 -0
- package/dist/ui/entries/AssistantEntry.d.ts +23 -0
- package/dist/ui/entries/AssistantEntry.js +13 -0
- package/dist/ui/entries/EntryFrame.d.ts +23 -0
- package/dist/ui/entries/EntryFrame.js +6 -0
- package/dist/ui/entries/ToolCard.d.ts +38 -0
- package/dist/ui/entries/ToolCard.js +72 -0
- package/dist/ui/entries/ToolPreview.d.ts +57 -0
- package/dist/ui/entries/ToolPreview.js +144 -0
- package/dist/ui/entries/UserEntry.d.ts +14 -0
- package/dist/ui/entries/UserEntry.js +5 -0
- package/dist/ui/exit-snapshot.d.ts +27 -0
- package/dist/ui/exit-snapshot.js +26 -0
- package/dist/ui/gauge.d.ts +24 -0
- package/dist/ui/gauge.js +36 -0
- package/dist/ui/glyphs.d.ts +87 -0
- package/dist/ui/glyphs.js +127 -0
- package/dist/ui/gradient.d.ts +11 -0
- package/dist/ui/gradient.js +50 -0
- package/dist/ui/layout/AppShell.d.ts +24 -0
- package/dist/ui/layout/AppShell.js +9 -0
- package/dist/ui/layout/Gutter.d.ts +67 -0
- package/dist/ui/layout/Gutter.js +42 -0
- package/dist/ui/layout/OverlayFrame.d.ts +62 -0
- package/dist/ui/layout/OverlayFrame.js +92 -0
- package/dist/ui/layout/ScrollViewport.d.ts +33 -0
- package/dist/ui/layout/ScrollViewport.js +71 -0
- package/dist/ui/layout/budget.d.ts +42 -0
- package/dist/ui/layout/budget.js +47 -0
- package/dist/ui/layout/frame.d.ts +58 -0
- package/dist/ui/layout/frame.js +75 -0
- package/dist/ui/layout/overlay-window.d.ts +43 -0
- package/dist/ui/layout/overlay-window.js +51 -0
- package/dist/ui/layout/scroll.d.ts +28 -0
- package/dist/ui/layout/scroll.js +76 -0
- package/dist/ui/layout/useTerminalSize.d.ts +13 -0
- package/dist/ui/layout/useTerminalSize.js +50 -0
- package/dist/ui/markdown-blocks.d.ts +62 -0
- package/dist/ui/markdown-blocks.js +120 -0
- package/dist/ui/overlays/ConfirmDialog.d.ts +30 -0
- package/dist/ui/overlays/ConfirmDialog.js +25 -0
- package/dist/ui/overlays/HelpOverlay.d.ts +17 -0
- package/dist/ui/overlays/HelpOverlay.js +60 -0
- package/dist/ui/overlays/ModelPicker.d.ts +29 -0
- package/dist/ui/overlays/ModelPicker.js +29 -0
- package/dist/ui/overlays/SettingsScreen.d.ts +37 -0
- package/dist/ui/overlays/SettingsScreen.js +106 -0
- package/dist/ui/palettes.d.ts +79 -0
- package/dist/ui/palettes.js +115 -0
- package/dist/ui/screen.d.ts +27 -0
- package/dist/ui/screen.js +57 -0
- package/dist/ui/theme.d.ts +78 -0
- package/dist/ui/theme.js +127 -0
- package/dist/ui/transcript-text.d.ts +27 -0
- package/dist/ui/transcript-text.js +110 -0
- package/package.json +73 -0
- package/skills/skill-creator/SKILL.md +96 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillService — discovery, lazy loading, prompt-block assembly, and the
|
|
3
|
+
* lifecycle surface the UI and the agent tools call into (spec §12.2).
|
|
4
|
+
*
|
|
5
|
+
* Everything mutating (install / create / remove) delegates to `installer.ts`;
|
|
6
|
+
* this file owns the read side and the registry.
|
|
7
|
+
*/
|
|
8
|
+
import { SkillRegistry, type SkillFileRef, type SkillHost, type SkillPlatform, type SkillPolicyView, type SkillRecord, type SkillUsageMap, type ToolPolicyDecision, type ToolPolicyVerdict } from '@aragon-agent/core';
|
|
9
|
+
import type { NoticeLevel } from '../agent/reducer.js';
|
|
10
|
+
import type { SkillsConfig, SkillsRuntimeOptions, SkillsToolPolicyMode } from '../config/schema.js';
|
|
11
|
+
import { type ConfirmRequest } from '../tools/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Capability-probing approval gate (D17 / §8.3.1).
|
|
14
|
+
*
|
|
15
|
+
* NOT `confirm?: (req) => Promise<boolean>`. That shape cannot express "there is
|
|
16
|
+
* no human here", and the CLI's existing confirm callback resolves `true` when
|
|
17
|
+
* unattached (`cli.tsx`'s `confirmBridge.handler ? … : Promise.resolve(true)`).
|
|
18
|
+
* Inheriting that fallback would make `requireApproval: true` a no-op under
|
|
19
|
+
* `-p`, where the App never mounts and the handler is permanently null.
|
|
20
|
+
* Probing FIRST makes fail-closed the default path rather than a discipline.
|
|
21
|
+
*/
|
|
22
|
+
export interface ApprovalGate {
|
|
23
|
+
/** Is there a human channel RIGHT NOW? Must be read live, never cached (Q7). */
|
|
24
|
+
canPrompt(): boolean;
|
|
25
|
+
/** Only called when `canPrompt()` returned true. */
|
|
26
|
+
request(req: ConfirmRequest): Promise<boolean>;
|
|
27
|
+
}
|
|
28
|
+
export interface DiscoverResult {
|
|
29
|
+
records: SkillRecord[];
|
|
30
|
+
errors: string[];
|
|
31
|
+
/** Project roots skipped because the directory is not trusted yet (D13). */
|
|
32
|
+
pendingTrust: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface SkillServiceDeps {
|
|
35
|
+
host: SkillHost;
|
|
36
|
+
getCwd: () => string;
|
|
37
|
+
config: SkillsConfig;
|
|
38
|
+
runtime: SkillsRuntimeOptions;
|
|
39
|
+
approval: ApprovalGate;
|
|
40
|
+
/** → `controller.refreshSkills()`. */
|
|
41
|
+
onChange?: () => void;
|
|
42
|
+
notify?: (level: NoticeLevel, text: string) => void;
|
|
43
|
+
/** Persist a skills patch. MUST deep-merge (§10.3.2). */
|
|
44
|
+
persist?: (patch: Partial<SkillsConfig>) => void;
|
|
45
|
+
}
|
|
46
|
+
export declare class SkillService {
|
|
47
|
+
private readonly deps;
|
|
48
|
+
private readonly registry;
|
|
49
|
+
private config;
|
|
50
|
+
private lastErrors;
|
|
51
|
+
private pendingTrust;
|
|
52
|
+
/** Empty when `skills.usageTracking` is off — which is exactly invariant I-A1. */
|
|
53
|
+
private usage;
|
|
54
|
+
/** The integrity warning is worth saying once a session, not once a rescan. */
|
|
55
|
+
private integrityWarned;
|
|
56
|
+
/**
|
|
57
|
+
* `/skills policy <mode>` writes here. `null` = this session has no opinion.
|
|
58
|
+
* NEVER persisted — the config file is written separately by the same command.
|
|
59
|
+
*/
|
|
60
|
+
private sessionToolPolicy;
|
|
61
|
+
/**
|
|
62
|
+
* The previous decision, used to notice when the ceiling WIDENS (§5.6e).
|
|
63
|
+
*
|
|
64
|
+
* A skill can tell the model to load a second skill, and because the ceiling
|
|
65
|
+
* is a union with `skill` permanently in the floor, that works (D-G17). The
|
|
66
|
+
* path is not blocked — every way of blocking it costs more than it saves —
|
|
67
|
+
* so instead it leaves a trace. This pair of fields is that trace's memory.
|
|
68
|
+
*/
|
|
69
|
+
private lastDecisionAllowed;
|
|
70
|
+
private lastDecisionSources;
|
|
71
|
+
constructor(deps: SkillServiceDeps);
|
|
72
|
+
/**
|
|
73
|
+
* Scan all four roots in ascending precedence and rebuild the registry.
|
|
74
|
+
*
|
|
75
|
+
* One unreadable directory must never sink the whole pass: every root and
|
|
76
|
+
* every candidate is wrapped, and partial results are returned alongside the
|
|
77
|
+
* errors so `/skills` can show both what loaded and what did not.
|
|
78
|
+
*/
|
|
79
|
+
discover(): DiscoverResult;
|
|
80
|
+
/**
|
|
81
|
+
* Enforce the usage-file cap (§9.2) — and ONLY when it is actually exceeded.
|
|
82
|
+
*
|
|
83
|
+
* `pruneUsage()` drops every counter whose skill is absent from the registry,
|
|
84
|
+
* and the registry is CWD-DEPENDENT: it holds the `project` skills of
|
|
85
|
+
* whichever directory this process happens to be running in. Calling it on
|
|
86
|
+
* every scan would therefore make a session in repo B silently erase the
|
|
87
|
+
* usage history of repo A — and a root that was momentarily unreadable would
|
|
88
|
+
* erase all of it. Counters for uninstalled skills are worth a few hundred
|
|
89
|
+
* bytes; the ranking signal they would take with them is not.
|
|
90
|
+
*/
|
|
91
|
+
private pruneUsageIfOverCap;
|
|
92
|
+
/**
|
|
93
|
+
* Tell the user once per session which skills no longer match what they
|
|
94
|
+
* approved (`warn` mode only — `strict` already refuses them outright, and
|
|
95
|
+
* repeating the notice on every rescan is how a warning becomes wallpaper).
|
|
96
|
+
*/
|
|
97
|
+
private reportIntegrity;
|
|
98
|
+
/** Scan one root. Returns the records it yielded; appends to `errors` in place. */
|
|
99
|
+
private scanRoot;
|
|
100
|
+
/** Build a record from a candidate directory, or `null` when it is not a skill. */
|
|
101
|
+
private readSkillDir;
|
|
102
|
+
/**
|
|
103
|
+
* Compare SKILL.md against the hash recorded at install time (§8.1).
|
|
104
|
+
*
|
|
105
|
+
* Costs no extra read on the happy path: the text is already in memory from
|
|
106
|
+
* the scan, and the manifest was already parsed.
|
|
107
|
+
*
|
|
108
|
+
* D-A12 — THE SECOND HASH IS NOT REDUNDANT. `readTextFile()` returns a
|
|
109
|
+
* DECODED string. Re-encoding it round-trips byte-for-byte only for
|
|
110
|
+
* well-formed UTF-8; a file containing an invalid sequence comes back with
|
|
111
|
+
* U+FFFD substituted, so the re-encoded bytes differ from what is on disk and
|
|
112
|
+
* an untouched file would be reported as tampered. A false alarm here is
|
|
113
|
+
* worse than no alarm at all — it teaches the user that this warning is noise,
|
|
114
|
+
* and it is the same warning that has to be believed on the day it is real.
|
|
115
|
+
*/
|
|
116
|
+
private computeIntegrity;
|
|
117
|
+
/** Reload from disk and notify the controller so the prompt is rebuilt. */
|
|
118
|
+
reload(): DiscoverResult;
|
|
119
|
+
list(): SkillRecord[];
|
|
120
|
+
get(name: string): SkillRecord | undefined;
|
|
121
|
+
getRegistry(): SkillRegistry;
|
|
122
|
+
errors(): string[];
|
|
123
|
+
/** Project roots the trust gate is still holding back (§9.3). */
|
|
124
|
+
untrustedDirs(): string[];
|
|
125
|
+
/**
|
|
126
|
+
* Level 2 load: SKILL.md body + the bundled-file listing.
|
|
127
|
+
* MAY THROW — see the `SkillHost` error contract; `skill`'s `execute()` and
|
|
128
|
+
* every UI caller wrap this.
|
|
129
|
+
*
|
|
130
|
+
* THE SINGLE USAGE MEASUREMENT POINT (F8). All three consumption paths — the
|
|
131
|
+
* `skill` tool, a `/<skill-name>` command, and `alwaysBlock()` — funnel
|
|
132
|
+
* through here, so one call site covers everything.
|
|
133
|
+
*
|
|
134
|
+
* `countUse: false` is MANDATORY for `alwaysBlock()`. An always-on skill is
|
|
135
|
+
* injected automatically on every single turn; counting that would pin it to
|
|
136
|
+
* the top of the ranking forever and drown out the signal the ranking exists
|
|
137
|
+
* to capture, which is what a human or a model actually CHOSE to reach for.
|
|
138
|
+
*/
|
|
139
|
+
loadBody(name: string, opts?: {
|
|
140
|
+
countUse?: boolean;
|
|
141
|
+
}): {
|
|
142
|
+
body: string;
|
|
143
|
+
files: SkillFileRef[];
|
|
144
|
+
};
|
|
145
|
+
/** Walk a skill directory for bundled resources (depth ≤ 3, dotfiles skipped). */
|
|
146
|
+
private listSkillFiles;
|
|
147
|
+
/** Level 1 catalog for the system prompt, or `''` when there is nothing to say. */
|
|
148
|
+
catalogBlock(): string;
|
|
149
|
+
/**
|
|
150
|
+
* `activation: always` bodies plus anything forced with `--skill`.
|
|
151
|
+
* Returns `''` when empty so the caller can concatenate unconditionally
|
|
152
|
+
* without disturbing invariant I-S1.
|
|
153
|
+
*/
|
|
154
|
+
alwaysBlock(): string;
|
|
155
|
+
/** Host shell family, forwarded into every Level 2 / Level 3 render (D-G14). */
|
|
156
|
+
platform(): SkillPlatform;
|
|
157
|
+
/**
|
|
158
|
+
* The mode actually in force, and where it came from.
|
|
159
|
+
*
|
|
160
|
+
* THREE LAYERS, not two (D-G19). `SkillsRuntimeOptions` is read-only for the
|
|
161
|
+
* life of the session, so with only `flag > config` a user who started with
|
|
162
|
+
* `--skill-tool-policy enforce` could run the very command the refusal text
|
|
163
|
+
* recommends — `/skills policy off` — and have precisely nothing happen, with
|
|
164
|
+
* no message either. An iteration about silent failures cannot ship one in its
|
|
165
|
+
* own escape hatch.
|
|
166
|
+
*/
|
|
167
|
+
effectiveToolPolicy(): {
|
|
168
|
+
mode: SkillsToolPolicyMode;
|
|
169
|
+
from: 'session' | 'flag' | 'config';
|
|
170
|
+
};
|
|
171
|
+
setSessionToolPolicy(mode: SkillsToolPolicyMode): void;
|
|
172
|
+
/** `/skills policy <mode>` — session slot and config file, together. */
|
|
173
|
+
persistToolPolicy(mode: SkillsToolPolicyMode): void;
|
|
174
|
+
/**
|
|
175
|
+
* Compute the ceiling for right now. Constant-time when the frame is empty or
|
|
176
|
+
* the mode is `off`, which is the overwhelmingly common case on the hot path.
|
|
177
|
+
*/
|
|
178
|
+
toolPolicyDecision(getRegistered: () => readonly string[]): ToolPolicyDecision;
|
|
179
|
+
/** The renderer-facing slice of the current decision, or `undefined` for "say nothing". */
|
|
180
|
+
toolPolicyView(getRegistered: () => readonly string[]): SkillPolicyView | undefined;
|
|
181
|
+
/**
|
|
182
|
+
* The ceiling a QUEUED skill is about to impose — for the `/<skill-name>` path,
|
|
183
|
+
* whose message has not been submitted yet and whose frame is therefore still
|
|
184
|
+
* pending (§13.2).
|
|
185
|
+
*
|
|
186
|
+
* Computed from the pending set alone, which is exactly right for the common
|
|
187
|
+
* case (`controller.prompt()` replaces the frame with the pending one). When
|
|
188
|
+
* the agent happens to be running, `steer()` unions instead, so this can
|
|
189
|
+
* understate — it will never claim a tool is forbidden that is in fact allowed
|
|
190
|
+
* only because some other skill is also in the frame. Overstating would be the
|
|
191
|
+
* dangerous direction; a refusal, if one ever happens, prints the true set.
|
|
192
|
+
*
|
|
193
|
+
* Emits no announcements: nothing has been decided yet.
|
|
194
|
+
*/
|
|
195
|
+
pendingToolPolicyView(getRegistered: () => readonly string[]): SkillPolicyView | undefined;
|
|
196
|
+
/**
|
|
197
|
+
* One notice per skill per session when a frame member stops constraining
|
|
198
|
+
* because it was uninstalled, disabled, or turned invalid (D-G20 / AC-G21).
|
|
199
|
+
*
|
|
200
|
+
* Without this, `/skills disable`, a `/skills reload` after an uninstall, and a
|
|
201
|
+
* flip to `integrity: strict` each end with the ceiling gone and nothing said
|
|
202
|
+
* — a silent lift, which is the same failure class as the silent no-op this
|
|
203
|
+
* whole iteration set out to remove.
|
|
204
|
+
*/
|
|
205
|
+
private reportCeilingLifted;
|
|
206
|
+
/** One notice per skill per session when D-G4 waives it (§5.7 / RG3). */
|
|
207
|
+
private reportFailOpen;
|
|
208
|
+
/** Print the union-escalation trace (§5.6e / D-G17) and remember the new state. */
|
|
209
|
+
private reportCeilingWidened;
|
|
210
|
+
/**
|
|
211
|
+
* The single place the three announce-once rules live (§5.4c / P1-2).
|
|
212
|
+
*
|
|
213
|
+
* `verdict.message` is MUTATED in the escalate branch rather than being
|
|
214
|
+
* followed by a second message: the model is already reading this text, and a
|
|
215
|
+
* separate message is one more thing for it to skip.
|
|
216
|
+
*/
|
|
217
|
+
reportToolPolicyEvent(e: {
|
|
218
|
+
tool: string;
|
|
219
|
+
verdict: ToolPolicyVerdict;
|
|
220
|
+
sourceNames: string[];
|
|
221
|
+
}): void;
|
|
222
|
+
beginUserTurn(): void;
|
|
223
|
+
absorbPendingFrames(): void;
|
|
224
|
+
queueFrame(name: string): void;
|
|
225
|
+
clearFrames(): void;
|
|
226
|
+
frameNames(): string[];
|
|
227
|
+
/** Level 2 body budget — shared by the tool path and the slash path (GG3). */
|
|
228
|
+
bodyMaxBytes(): number;
|
|
229
|
+
/** Warn once about `--skill <name>` values that match nothing (§7.5). */
|
|
230
|
+
reportUnknownForcedSkills(): void;
|
|
231
|
+
setDisabled(name: string, disabled: boolean): void;
|
|
232
|
+
getConfig(): SkillsConfig;
|
|
233
|
+
/** Local use counters backing `--sort=recent`; empty when tracking is off. */
|
|
234
|
+
getUsage(): SkillUsageMap;
|
|
235
|
+
/** Working directory an install should resolve `--scope project` against. */
|
|
236
|
+
getCwdForInstall(): string;
|
|
237
|
+
getRuntime(): SkillsRuntimeOptions;
|
|
238
|
+
getApproval(): ApprovalGate;
|
|
239
|
+
notify(level: NoticeLevel, text: string): void;
|
|
240
|
+
/** Keep the in-memory copy and the config file in step (deep-merged, §10.3.2). */
|
|
241
|
+
private updateConfig;
|
|
242
|
+
isTrusted(dir: string): boolean;
|
|
243
|
+
trustDir(dir: string): boolean;
|
|
244
|
+
untrustDir(dir: string): boolean;
|
|
245
|
+
/**
|
|
246
|
+
* Load a project root for THIS SESSION ONLY, without persisting trust.
|
|
247
|
+
* Used when the user answers the confirm dialog with "just this once".
|
|
248
|
+
*/
|
|
249
|
+
trustForSession(dir: string): void;
|
|
250
|
+
/**
|
|
251
|
+
* Drop staging directories left behind by a crashed install (P2-10).
|
|
252
|
+
* Same discipline as the host repo's workspace cleanup: age-based, best
|
|
253
|
+
* effort, and never allowed to interrupt discovery.
|
|
254
|
+
*/
|
|
255
|
+
private reclaimStaleStaging;
|
|
256
|
+
}
|