@yagni-app/code 1.0.5 → 1.0.7

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.
Files changed (111) hide show
  1. package/README.md +89 -27
  2. package/dist/claudeCompat.d.ts +59 -0
  3. package/dist/claudeCompat.js +109 -2
  4. package/dist/claudePlugins.d.ts +45 -3
  5. package/dist/claudePlugins.js +129 -19
  6. package/dist/cli.js +28 -4
  7. package/dist/doctor.d.ts +42 -4
  8. package/dist/doctor.js +150 -15
  9. package/dist/extension/condensedTools.d.ts +12 -1
  10. package/dist/extension/condensedTools.js +17 -9
  11. package/dist/extension/index.d.ts +18 -5
  12. package/dist/extension/index.js +319 -72
  13. package/dist/extension/mcp/approval.d.ts +45 -0
  14. package/dist/extension/mcp/approval.js +164 -0
  15. package/dist/extension/mcp/auth.d.ts +124 -0
  16. package/dist/extension/mcp/auth.js +560 -0
  17. package/dist/extension/mcp/authStore.d.ts +61 -0
  18. package/dist/extension/mcp/authStore.js +105 -0
  19. package/dist/extension/mcp/callbackPage.d.ts +31 -0
  20. package/dist/extension/mcp/callbackPage.js +222 -0
  21. package/dist/extension/mcp/cliConfig.d.ts +12 -0
  22. package/dist/extension/mcp/cliConfig.js +12 -0
  23. package/dist/extension/mcp/config.d.ts +153 -0
  24. package/dist/extension/mcp/config.js +381 -0
  25. package/dist/extension/mcp/log.d.ts +28 -0
  26. package/dist/extension/mcp/log.js +82 -0
  27. package/dist/extension/mcp/manager.d.ts +100 -0
  28. package/dist/extension/mcp/manager.js +273 -0
  29. package/dist/extension/mcp/names.d.ts +25 -0
  30. package/dist/extension/mcp/names.js +40 -0
  31. package/dist/extension/mcp/panel.d.ts +33 -0
  32. package/dist/extension/mcp/panel.js +268 -0
  33. package/dist/extension/mcp/prompts.d.ts +23 -0
  34. package/dist/extension/mcp/prompts.js +93 -0
  35. package/dist/extension/mcp/startup.d.ts +55 -0
  36. package/dist/extension/mcp/startup.js +152 -0
  37. package/dist/extension/mcp/tools.d.ts +31 -0
  38. package/dist/extension/mcp/tools.js +117 -0
  39. package/dist/extension/mcp/transports.d.ts +17 -0
  40. package/dist/extension/mcp/transports.js +44 -0
  41. package/dist/extension/permission/gate.d.ts +104 -2
  42. package/dist/extension/permission/gate.js +387 -31
  43. package/dist/extension/permission/guardian.d.ts +24 -5
  44. package/dist/extension/permission/guardian.js +162 -24
  45. package/dist/extension/permissionRules/bashFileArgs.d.ts +39 -0
  46. package/dist/extension/permissionRules/bashFileArgs.js +236 -0
  47. package/dist/extension/permissionRules/engine.d.ts +50 -0
  48. package/dist/extension/permissionRules/engine.js +238 -0
  49. package/dist/extension/permissionRules/loadConfig.d.ts +53 -0
  50. package/dist/extension/permissionRules/loadConfig.js +90 -0
  51. package/dist/extension/permissionRules/parser.d.ts +38 -0
  52. package/dist/extension/permissionRules/parser.js +136 -0
  53. package/dist/extension/permissionRules/pathRules.d.ts +58 -0
  54. package/dist/extension/permissionRules/pathRules.js +120 -0
  55. package/dist/extension/permissionRules/shellRules.d.ts +52 -0
  56. package/dist/extension/permissionRules/shellRules.js +221 -0
  57. package/dist/extension/pipeline/invocation.d.ts +3 -6
  58. package/dist/extension/pipeline/invocation.js +3 -6
  59. package/dist/extension/pipeline/personas.js +5 -0
  60. package/dist/extension/pipeline/runner.d.ts +0 -1
  61. package/dist/extension/pipeline/runner.js +6 -14
  62. package/dist/extension/plugins/inventory.d.ts +88 -0
  63. package/dist/extension/plugins/inventory.js +144 -0
  64. package/dist/extension/plugins/panel.d.ts +45 -0
  65. package/dist/extension/plugins/panel.js +293 -0
  66. package/dist/extension/sandbox/bash.d.ts +99 -0
  67. package/dist/extension/sandbox/bash.js +190 -0
  68. package/dist/extension/sandbox/config.d.ts +114 -0
  69. package/dist/extension/sandbox/config.js +366 -0
  70. package/dist/extension/sandbox/manager.d.ts +98 -0
  71. package/dist/extension/sandbox/manager.js +216 -0
  72. package/dist/extension/sandbox/panel.d.ts +111 -0
  73. package/dist/extension/sandbox/panel.js +342 -0
  74. package/dist/extension/sandbox/session.d.ts +85 -0
  75. package/dist/extension/sandbox/session.js +775 -0
  76. package/dist/extension/telemetry/attrs.d.ts +96 -0
  77. package/dist/extension/telemetry/attrs.js +149 -0
  78. package/dist/extension/telemetry/config.d.ts +99 -0
  79. package/dist/extension/telemetry/config.js +193 -0
  80. package/dist/extension/telemetry/index.d.ts +7 -0
  81. package/dist/extension/telemetry/index.js +7 -0
  82. package/dist/extension/telemetry/probe.d.ts +29 -0
  83. package/dist/extension/telemetry/probe.js +122 -0
  84. package/dist/extension/telemetry/register.d.ts +40 -0
  85. package/dist/extension/telemetry/register.js +192 -0
  86. package/dist/extension/telemetry/sdk.d.ts +63 -0
  87. package/dist/extension/telemetry/sdk.js +207 -0
  88. package/dist/extension/telemetry/tracker.d.ts +131 -0
  89. package/dist/extension/telemetry/tracker.js +551 -0
  90. package/dist/extension/vendor/IGNORE-LICENSE-MIT +21 -0
  91. package/dist/extension/vendor/ignore.d.ts +86 -0
  92. package/dist/extension/vendor/ignore.js +788 -0
  93. package/dist/goHeadless.d.ts +1 -1
  94. package/dist/goHeadless.js +2 -2
  95. package/dist/launch.d.ts +4 -3
  96. package/dist/launch.js +7 -4
  97. package/dist/mcpCommand.d.ts +122 -0
  98. package/dist/mcpCommand.js +787 -0
  99. package/dist/otel.d.ts +69 -63
  100. package/dist/otel.js +154 -119
  101. package/dist/paths.d.ts +13 -0
  102. package/dist/paths.js +18 -0
  103. package/dist/pluginCommand.d.ts +43 -0
  104. package/dist/pluginCommand.js +499 -0
  105. package/dist/pluginStore.d.ts +170 -0
  106. package/dist/pluginStore.js +554 -0
  107. package/dist/upgrade.d.ts +11 -2
  108. package/dist/upgrade.js +48 -8
  109. package/package.json +20 -3
  110. package/dist/extension/mcpTools.d.ts +0 -57
  111. package/dist/extension/mcpTools.js +0 -132
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Sandbox manager adapter — wraps @anthropic-ai/sandbox-runtime's
3
+ * SandboxManager with YAGNI Code wiring: dependency check against the
4
+ * vendored ripgrep, settings-derived runtime config (config.ts merge), and
5
+ * an injectable network ask-callback so the UI layer owns prompting (M5)
6
+ * while headless fails closed (deny).
7
+ *
8
+ * All state is session-scoped behind a single holder; nothing module-global
9
+ * is mutated except the underlying srt manager, which initialize/reset
10
+ * bracket. Pure functions (config building) live in config.ts.
11
+ */
12
+ import { type SandboxSettings, type SandboxRuntimeMerge } from "./config.js";
13
+ import type { PermissionRule } from "../permissionRules/loadConfig.js";
14
+ /** Where the network ask-callback surfaces a decision. */
15
+ export type NetworkAskHandler = (host: string) => Promise<boolean>;
16
+ export interface SandboxDependencyStatus {
17
+ /** Fatal: sandbox cannot run. */
18
+ errors: string[];
19
+ warnings: string[];
20
+ }
21
+ export interface SandboxManagerEvents {
22
+ onStateChange?: (enabled: boolean) => void;
23
+ }
24
+ export interface SandboxSessionOptions {
25
+ cwd: string;
26
+ env?: NodeJS.ProcessEnv;
27
+ userHome?: string;
28
+ stateHomeOverride?: string | null;
29
+ projectRoot?: string | null;
30
+ /** Ripgrep binary for srt's dependency check (default: vendored rg). */
31
+ rgPath?: string;
32
+ askHandler?: NetworkAskHandler | null;
33
+ events?: SandboxManagerEvents;
34
+ }
35
+ export interface SandboxSessionState {
36
+ /** srt initialized and commands will be wrapped. */
37
+ initialized: boolean;
38
+ /** Last dependency status (memoized per init attempt). */
39
+ dependencies: SandboxDependencyStatus | null;
40
+ /** The settings snapshot this session initialized with. */
41
+ settings: SandboxSettings | null;
42
+ }
43
+ /** Default vendored rg shipped with the CLI install. */
44
+ export declare function defaultRgPath(env?: NodeJS.ProcessEnv): string | undefined;
45
+ export declare class YagniSandboxManager {
46
+ private state;
47
+ private askHandler;
48
+ private readonly opts;
49
+ constructor(opts: SandboxSessionOptions);
50
+ get initialized(): boolean;
51
+ get settings(): SandboxSettings | null;
52
+ get dependencies(): SandboxDependencyStatus | null;
53
+ setAskHandler(handler: NetworkAskHandler | null): void;
54
+ /** The failure-trail wrapper handed to srt — exported for tests so the
55
+ * catch-and-log contract (fail closed + sink line) is observable without
56
+ * driving a real wrapped network connection. */
57
+ networkAsk(host: string): Promise<boolean>;
58
+ checkDependencies(): SandboxDependencyStatus;
59
+ /**
60
+ * Build the runtime filesystem/network config from current settings +
61
+ * permission rules. Exposed for diagnostics (/sandbox config display) and
62
+ * tests; initialize() consumes it internally.
63
+ */
64
+ buildRuntimeMerge(rules: readonly PermissionRule[]): SandboxRuntimeMerge;
65
+ private runtimeConfig;
66
+ /**
67
+ * Initialize srt for this session. Returns an error string when the sandbox
68
+ * cannot start (deps/platform) — the caller decides fail-soft (notify) vs
69
+ * fail-hard (refuse to run, `failIfUnavailable`). Idempotent: a second call
70
+ * while initialized is a no-op.
71
+ *
72
+ * `force` bypasses the disk `enabled` check: the session-level toggle
73
+ * (/sandbox enable, Alt+S) must be able to START the sandbox in a
74
+ * default-off config — that is its entire purpose. Config-driven starts
75
+ * (session_start) never pass force.
76
+ */
77
+ initialize(rules: readonly PermissionRule[], opts?: {
78
+ force?: boolean;
79
+ }): Promise<string | undefined>;
80
+ /**
81
+ * Rebuild + push the srt config without reset (settings changed or a grant
82
+ * landed). No-op when not initialized.
83
+ */
84
+ refreshConfig(rules: readonly PermissionRule[]): void;
85
+ /**
86
+ * Re-init from scratch (config grant changed semantics srt can't hot-swap,
87
+ * or a toggle). Tears down proxies + violation store first.
88
+ */
89
+ reinitialize(rules: readonly PermissionRule[]): Promise<string | undefined>;
90
+ /** Tear down srt (proxies, violation store, seatbelt state). */
91
+ reset(): Promise<void>;
92
+ wrapWithSandbox(command: string, binShell?: string): Promise<string>;
93
+ cleanupAfterCommand(): void;
94
+ annotateStderrWithSandboxFailures(command: string, stderr: string): string;
95
+ getProxyPort(): number | undefined;
96
+ getSocksProxyPort(): number | undefined;
97
+ }
98
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Sandbox manager adapter — wraps @anthropic-ai/sandbox-runtime's
3
+ * SandboxManager with YAGNI Code wiring: dependency check against the
4
+ * vendored ripgrep, settings-derived runtime config (config.ts merge), and
5
+ * an injectable network ask-callback so the UI layer owns prompting (M5)
6
+ * while headless fails closed (deny).
7
+ *
8
+ * All state is session-scoped behind a single holder; nothing module-global
9
+ * is mutated except the underlying srt manager, which initialize/reset
10
+ * bracket. Pure functions (config building) live in config.ts.
11
+ */
12
+ import { SandboxManager as SrtSandboxManager } from "@anthropic-ai/sandbox-runtime";
13
+ import { logEvent } from "../errorSink.js";
14
+ import { codeStateHome } from "../stateHome.js";
15
+ import { loadSandboxSettings, mergeRulesIntoSandbox, } from "./config.js";
16
+ /** Default vendored rg shipped with the CLI install. */
17
+ export function defaultRgPath(env = process.env) {
18
+ const agentDir = env.PI_CODING_AGENT_DIR;
19
+ if (!agentDir)
20
+ return undefined;
21
+ return `${agentDir.replace(/\/$/, "")}/bin/rg`;
22
+ }
23
+ export class YagniSandboxManager {
24
+ state = { initialized: false, dependencies: null, settings: null };
25
+ askHandler = null;
26
+ opts;
27
+ constructor(opts) {
28
+ this.opts = opts;
29
+ this.askHandler = opts.askHandler ?? null;
30
+ }
31
+ get initialized() { return this.state.initialized; }
32
+ get settings() { return this.state.settings; }
33
+ get dependencies() { return this.state.dependencies; }
34
+ setAskHandler(handler) {
35
+ this.askHandler = handler;
36
+ }
37
+ /** The failure-trail wrapper handed to srt — exported for tests so the
38
+ * catch-and-log contract (fail closed + sink line) is observable without
39
+ * driving a real wrapped network connection. */
40
+ async networkAsk(host) {
41
+ if (!this.askHandler)
42
+ return false; // fail closed (headless)
43
+ try {
44
+ return await this.askHandler(host);
45
+ }
46
+ catch (err) {
47
+ // Fail closed, but never silently — a denied host with no trail is
48
+ // undebuggable. Metadata only (host + error class): no command content.
49
+ logEvent({
50
+ source: "sandbox",
51
+ level: "warn",
52
+ event: "network_ask_failed",
53
+ fields: {
54
+ host,
55
+ errorClass: err instanceof Error ? err.constructor.name : String(err),
56
+ },
57
+ });
58
+ return false;
59
+ }
60
+ }
61
+ checkDependencies() {
62
+ // No explicit rgPath/PI_CODING_AGENT_DIR: fall through to srt's own check,
63
+ // which uses { command: 'rg' } and consults PATH — rg on PATH is a
64
+ // legitimate resolution (CI runners, bare-metal Linux installs). The
65
+ // vendored-rg case is the explicit path above.
66
+ const rg = this.opts.rgPath ?? defaultRgPath(this.opts.env ?? process.env);
67
+ const check = rg
68
+ ? SrtSandboxManager.checkDependencies({ command: rg, args: ["--version"] })
69
+ : SrtSandboxManager.checkDependencies();
70
+ return { errors: [...check.errors], warnings: [...check.warnings] };
71
+ }
72
+ /**
73
+ * Build the runtime filesystem/network config from current settings +
74
+ * permission rules. Exposed for diagnostics (/sandbox config display) and
75
+ * tests; initialize() consumes it internally.
76
+ */
77
+ buildRuntimeMerge(rules) {
78
+ const { settings } = loadSandboxSettings({
79
+ cwd: this.opts.cwd,
80
+ env: this.opts.env,
81
+ userHome: this.opts.userHome,
82
+ stateHomeOverride: this.opts.stateHomeOverride,
83
+ });
84
+ return mergeRulesIntoSandbox(settings, rules, {
85
+ cwd: this.opts.cwd,
86
+ userStateHome: this.opts.stateHomeOverride ?? codeStateHome(null, this.opts.env, this.opts.userHome),
87
+ projectRoot: this.opts.projectRoot ?? null,
88
+ homeDir: this.opts.userHome,
89
+ });
90
+ }
91
+ runtimeConfig(merge, settings) {
92
+ return {
93
+ network: {
94
+ allowedDomains: merge.network.allowedDomains,
95
+ deniedDomains: merge.network.deniedDomains,
96
+ allowUnixSockets: merge.network.allowUnixSockets,
97
+ allowAllUnixSockets: merge.network.allowAllUnixSockets,
98
+ allowLocalBinding: merge.network.allowLocalBinding,
99
+ httpProxyPort: merge.network.httpProxyPort,
100
+ socksProxyPort: merge.network.socksProxyPort,
101
+ },
102
+ filesystem: {
103
+ allowRead: merge.filesystem.allowRead,
104
+ denyRead: merge.filesystem.denyRead,
105
+ allowWrite: merge.filesystem.allowWrite,
106
+ denyWrite: merge.filesystem.denyWrite,
107
+ },
108
+ ignoreViolations: settings.ignoreViolations,
109
+ enableWeakerNestedSandbox: settings.enableWeakerNestedSandbox,
110
+ enableWeakerNetworkIsolation: settings.enableWeakerNetworkIsolation,
111
+ };
112
+ }
113
+ /**
114
+ * Initialize srt for this session. Returns an error string when the sandbox
115
+ * cannot start (deps/platform) — the caller decides fail-soft (notify) vs
116
+ * fail-hard (refuse to run, `failIfUnavailable`). Idempotent: a second call
117
+ * while initialized is a no-op.
118
+ *
119
+ * `force` bypasses the disk `enabled` check: the session-level toggle
120
+ * (/sandbox enable, Alt+S) must be able to START the sandbox in a
121
+ * default-off config — that is its entire purpose. Config-driven starts
122
+ * (session_start) never pass force.
123
+ */
124
+ async initialize(rules, opts = {}) {
125
+ if (this.state.initialized)
126
+ return undefined;
127
+ // Config-first (Claude's order): a sandbox the user did not enable must
128
+ // never report a dependency problem — disabled is disabled regardless of
129
+ // the machine's health. `force` (session toggle) reads config the same
130
+ // way; the dep check below still guards the actual start.
131
+ const load = loadSandboxSettings({
132
+ cwd: this.opts.cwd,
133
+ env: this.opts.env,
134
+ userHome: this.opts.userHome,
135
+ stateHomeOverride: this.opts.stateHomeOverride,
136
+ });
137
+ if (!load.settings.enabled && !opts.force)
138
+ return "sandbox disabled by config";
139
+ const deps = this.checkDependencies();
140
+ this.state.dependencies = deps;
141
+ if (deps.errors.length > 0)
142
+ return `sandbox dependencies unavailable: ${deps.errors.join(", ")}`;
143
+ const merge = this.buildRuntimeMerge(rules);
144
+ const ask = async (hostPattern) => this.networkAsk(hostPattern.host);
145
+ try {
146
+ await SrtSandboxManager.initialize(this.runtimeConfig(merge, load.settings), ask);
147
+ }
148
+ catch (err) {
149
+ this.state.dependencies = null;
150
+ return `sandbox initialization failed: ${err instanceof Error ? err.message : String(err)}`;
151
+ }
152
+ this.state.initialized = true;
153
+ this.state.settings = load.settings;
154
+ this.opts.events?.onStateChange?.(true);
155
+ return undefined;
156
+ }
157
+ /**
158
+ * Rebuild + push the srt config without reset (settings changed or a grant
159
+ * landed). No-op when not initialized.
160
+ */
161
+ refreshConfig(rules) {
162
+ if (!this.state.initialized)
163
+ return;
164
+ const merge = this.buildRuntimeMerge(rules);
165
+ SrtSandboxManager.updateConfig(this.runtimeConfig(merge, loadSandboxSettings({
166
+ cwd: this.opts.cwd,
167
+ env: this.opts.env,
168
+ userHome: this.opts.userHome,
169
+ stateHomeOverride: this.opts.stateHomeOverride,
170
+ }).settings));
171
+ }
172
+ /**
173
+ * Re-init from scratch (config grant changed semantics srt can't hot-swap,
174
+ * or a toggle). Tears down proxies + violation store first.
175
+ */
176
+ async reinitialize(rules) {
177
+ if (this.state.initialized) {
178
+ await this.reset();
179
+ }
180
+ return this.initialize(rules);
181
+ }
182
+ /** Tear down srt (proxies, violation store, seatbelt state). */
183
+ async reset() {
184
+ this.state = { initialized: false, dependencies: null, settings: null };
185
+ try {
186
+ await SrtSandboxManager.reset();
187
+ }
188
+ catch {
189
+ // teardown errors are non-fatal; state is already cleared
190
+ }
191
+ this.opts.events?.onStateChange?.(false);
192
+ }
193
+ // --- command wrapping (thin, typed passthroughs) ---
194
+ async wrapWithSandbox(command, binShell) {
195
+ if (!this.state.initialized)
196
+ return command;
197
+ return SrtSandboxManager.wrapWithSandbox(command, binShell);
198
+ }
199
+ cleanupAfterCommand() {
200
+ if (!this.state.initialized)
201
+ return;
202
+ SrtSandboxManager.cleanupAfterCommand();
203
+ }
204
+ annotateStderrWithSandboxFailures(command, stderr) {
205
+ if (!this.state.initialized)
206
+ return stderr;
207
+ return SrtSandboxManager.annotateStderrWithSandboxFailures(command, stderr);
208
+ }
209
+ getProxyPort() {
210
+ return this.state.initialized ? SrtSandboxManager.getProxyPort() : undefined;
211
+ }
212
+ getSocksProxyPort() {
213
+ return this.state.initialized ? SrtSandboxManager.getSocksProxyPort() : undefined;
214
+ }
215
+ }
216
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1,111 @@
1
+ /**
2
+ * /sandbox interactive TUI panel — mirrors Claude Code's SandboxSettings
3
+ * tabs (Mode / Overrides / Config, plus Dependencies when checkDependencies
4
+ * reports errors). Rendered via ctx.ui.custom() in TUI mode; RPC/headless
5
+ * keeps the text summary (custom() is unavailable there).
6
+ *
7
+ * Structure follows Claude's components (SandboxSettings/SandboxModeTab/
8
+ * SandboxOverridesTab/SandboxConfigTab): tabs switched with left/right,
9
+ * SelectList-driven option tabs, read-only config tab, off-state
10
+ * placeholders on Overrides/Config. Copy mirrors Claude's where the
11
+ * mechanism is identical; persistence deviates deliberately (see
12
+ * persistSandboxMode in session.ts) until the project-local settings tier
13
+ * lands.
14
+ *
15
+ * Input contract (verified against pi's interactive mode): pi focuses the
16
+ * ROOT component and calls only root.handleInput(data). Children without
17
+ * their own handleInput (Box, Text) are never consulted — so the panel
18
+ * keeps a direct reference to the active SelectList and forwards keys to
19
+ * it. A Box wrapper does NOT forward input.
20
+ */
21
+ import { Container, type SelectItem } from "@earendil-works/pi-tui";
22
+ import { type SandboxRuntimeMerge, type SandboxRuntimePaths, type SandboxSettings } from "./config.js";
23
+ import type { RenderTheme } from "../subagentRender.js";
24
+ import type { PermissionRule } from "../permissionRules/loadConfig.js";
25
+ export type SandboxPanelTab = "mode" | "overrides" | "config" | "dependencies";
26
+ export type SandboxModeChoice = "auto-allow" | "regular" | "disabled";
27
+ export type SandboxOverrideChoice = "open" | "closed";
28
+ /** Everything the panel needs, resolved by the caller (session.ts). */
29
+ export interface SandboxPanelState {
30
+ settings: SandboxSettings;
31
+ /** Session-only toggle state (false = forced off this session). */
32
+ sessionToggledOff: boolean;
33
+ /** Dependencies status for the Dependencies tab + warnings on Config. */
34
+ dependencyErrors: string[];
35
+ dependencyWarnings: string[];
36
+ /** Runtime merge output (rules + settings) for the Config tab. */
37
+ merge: SandboxRuntimeMerge;
38
+ /** Domains granted this session (memory-only). */
39
+ sessionGrants: string[];
40
+ }
41
+ export interface SandboxPanelActions {
42
+ /** Persist a mode choice. Resolves with the confirmation to surface
43
+ * after the panel closes (Claude's onComplete(message) contract). */
44
+ onModeSelect: (choice: SandboxModeChoice) => Promise<SandboxPanelOutcome>;
45
+ /** Persist an override choice. Same contract. */
46
+ onOverrideSelect: (choice: SandboxOverrideChoice) => Promise<SandboxPanelOutcome>;
47
+ }
48
+ /** What the panel hands back when it closes: the confirmation (or error)
49
+ * the session surfaces via notify once custom() resolves. */
50
+ export interface SandboxPanelOutcome {
51
+ text: string;
52
+ level: "info" | "error";
53
+ }
54
+ /** Current mode derived from resolved settings (Claude's currentMode). */
55
+ export declare function deriveCurrentMode(settings: SandboxSettings, sessionToggledOff: boolean): SandboxModeChoice;
56
+ export declare function deriveCurrentOverride(settings: SandboxSettings): SandboxOverrideChoice;
57
+ export declare function modeOptions(current: SandboxModeChoice): SelectItem[];
58
+ export declare function overrideOptions(current: SandboxOverrideChoice): SelectItem[];
59
+ /** Per-mode explanation (Claude's copy, adapted to our surfaces). */
60
+ export declare function modeExplanation(mode: SandboxModeChoice): string;
61
+ export declare function overrideExplanation(choice: SandboxOverrideChoice): string;
62
+ /**
63
+ * Config tab sections, conditional like Claude's SandboxConfigTab: empty
64
+ * sections are omitted entirely (Excluded Commands — Claude's one always-on
65
+ * section — shows None). Structured as title + detail lines so the tab can
66
+ * space sections apart instead of rendering one dense text block.
67
+ */
68
+ export interface ConfigSection {
69
+ title: string;
70
+ detail: string[];
71
+ }
72
+ export declare function configSections(state: SandboxPanelState): ConfigSection[];
73
+ /** Tabs offered, mirroring Claude: Dependencies appears only on errors. */
74
+ export declare function panelTabs(dependencyErrors: string[]): SandboxPanelTab[];
75
+ /**
76
+ * The /sandbox panel. Structure: top border · tab strip · blank · tab
77
+ * content · blank · footer · bottom border. pi focuses this root and calls
78
+ * its handleInput; the panel forwards keys to the active tab's SelectList
79
+ * (when one exists) and switches tabs on left/right.
80
+ */
81
+ export declare class SandboxPanel extends Container {
82
+ private readonly state;
83
+ private readonly actions;
84
+ private readonly theme;
85
+ private readonly done;
86
+ private activeTab;
87
+ private readonly tabs;
88
+ /** The active tab's SelectList (mode/overrides) or null (config/deps) —
89
+ * input forwards here. */
90
+ private activeList;
91
+ /** Padded content frame; children[0] = tab strip, children[1] = body. */
92
+ private readonly content;
93
+ constructor(state: SandboxPanelState, actions: SandboxPanelActions, theme: RenderTheme, done: (outcome?: SandboxPanelOutcome) => void);
94
+ private setTab;
95
+ private buildBody;
96
+ private buildTabContent;
97
+ private buildModeTab;
98
+ private buildOverridesTab;
99
+ private buildConfigTab;
100
+ private buildDependenciesTab;
101
+ handleInput(data: string): void;
102
+ }
103
+ /**
104
+ * Build the panel state from the pieces session.ts already holds. Exported
105
+ * for unit tests; the TUI component consumes it.
106
+ */
107
+ export declare function buildPanelState(settings: SandboxSettings, sessionToggledOff: boolean, rules: readonly PermissionRule[], paths: SandboxRuntimePaths, sessionGrants: readonly string[], dependencyStatus: {
108
+ errors: string[];
109
+ warnings: string[];
110
+ }): SandboxPanelState;
111
+ //# sourceMappingURL=panel.d.ts.map