@vybestack/llxprt-code 0.10.0 → 0.11.0-nightly.260728.ffaa8d5d7
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/package.json +13 -13
- package/src/commands/mcp/add.ts +8 -4
- package/src/config/cliArgParser.ts +2 -0
- package/src/config/config.ts +2 -0
- package/src/config/configBuilder.ts +3 -0
- package/src/config/configError.ts +23 -0
- package/src/config/extensions/extensionEnablement.ts +62 -1
- package/src/config/interactiveContext.ts +2 -1
- package/src/config/intermediateConfig.ts +4 -0
- package/src/config/keyBindings.ts +29 -3
- package/src/config/policy.ts +7 -1
- package/src/config/postConfigRuntime.ts +20 -14
- package/src/config/settings-schema/schema-ui.ts +9 -0
- package/src/config/settingsLoader.ts +21 -17
- package/src/config/settingsSchema.ts +2 -2
- package/src/config/trustedFolders.ts +275 -58
- package/src/config/yargsOptions.ts +7 -0
- package/src/generated/git-commit.json +1 -1
- package/src/nonInteractiveCli.ts +1 -0
- package/src/nonInteractiveCliSupport.ts +171 -51
- package/src/runtime/interactiveToolScheduler.ts +6 -6
- package/src/services/BuiltinCommandLoader.ts +33 -25
- package/src/services/FileCommandLoader.ts +34 -7
- package/src/test-utils/async.ts +20 -0
- package/src/test-utils/render.tsx +10 -1
- package/src/ui/App.tsx +17 -10
- package/src/ui/AppContainerRuntime.tsx +7 -9
- package/src/ui/cliUiRuntime.ts +28 -0
- package/src/ui/commands/authCommand.ts +240 -3
- package/src/ui/commands/compressCommand.ts +9 -1
- package/src/ui/commands/directoryCommand.tsx +1 -1
- package/src/ui/commands/logoutCommand.ts +2 -2
- package/src/ui/commands/permissionsCommand.ts +77 -20
- package/src/ui/commands/policiesCommand.ts +6 -1
- package/src/ui/commands/quotaCommand.ts +501 -0
- package/src/ui/commands/statsCommand.ts +2 -2
- package/src/ui/commands/statsQuota.ts +1 -1
- package/src/ui/commands/subagentCommand.ts +59 -27
- package/src/ui/components/AuthDialog.tsx +3 -3
- package/src/ui/components/Composer.tsx +1 -0
- package/src/ui/components/DialogManager.tsx +9 -2
- package/src/ui/components/FolderTrustDialog.tsx +71 -60
- package/src/ui/components/PermissionsModifyTrustDialog.tsx +211 -146
- package/src/ui/components/ProfileCreateWizard/constants.ts +13 -1
- package/src/ui/components/QueuedMessagesPanel.tsx +388 -0
- package/src/ui/components/inputPromptHooks.ts +2 -0
- package/src/ui/components/inputPromptKeyHandlers.ts +14 -0
- package/src/ui/components/inputPromptTypes.ts +6 -0
- package/src/ui/components/messages/AiMessage.tsx +24 -12
- package/src/ui/components/messages/ToolMessage.tsx +26 -40
- package/src/ui/containers/AppContainer/builders/buildUIActions.ts +3 -1
- package/src/ui/containers/AppContainer/builders/buildUIState.ts +5 -4
- package/src/ui/containers/AppContainer/hooks/useAppBootstrap.ts +3 -33
- package/src/ui/containers/AppContainer/hooks/useAppDialogs.ts +2 -14
- package/src/ui/containers/AppContainer/hooks/useAppInput.ts +31 -25
- package/src/ui/containers/AppContainer/hooks/useAppLayout.ts +90 -60
- package/src/ui/containers/AppContainer/hooks/useDisplayPreferences.ts +10 -0
- package/src/ui/containers/AppContainer/hooks/useInputHandling.ts +3 -17
- package/src/ui/containers/AppContainer/hooks/useKeybindings.ts +51 -38
- package/src/ui/containers/AppContainer/hooks/useSteer.ts +51 -0
- package/src/ui/contexts/KeypressContext.tsx +13 -2
- package/src/ui/contexts/ShellCommandDisplayContext.tsx +103 -0
- package/src/ui/contexts/TodoContext.tsx +0 -13
- package/src/ui/contexts/TodoProvider.tsx +1 -34
- package/src/ui/contexts/UIActionsContext.tsx +2 -1
- package/src/ui/contexts/UIStateContext.tsx +3 -2
- package/src/ui/hooks/agentStream/streamUtils.ts +0 -24
- package/src/ui/hooks/agentStream/thoughtState.ts +110 -30
- package/src/ui/hooks/agentStream/types.ts +1 -0
- package/src/ui/hooks/agentStream/useAgentEventStream.ts +8 -17
- package/src/ui/hooks/agentStream/useAgentStream.ts +2 -2
- package/src/ui/hooks/agentStream/useAgentStreamLifecycle.ts +4 -5
- package/src/ui/hooks/agentStream/useAgentStreamOrchestration.ts +12 -5
- package/src/ui/hooks/agentStream/useQueuedSubmissions.ts +99 -0
- package/src/ui/hooks/agentStream/useStreamEventHandlers.ts +4 -13
- package/src/ui/hooks/agentStream/useStreamState.ts +60 -41
- package/src/ui/hooks/agentStream/useSubmitQuery.ts +284 -59
- package/src/ui/hooks/slashCommandProcessorSupport.ts +4 -0
- package/src/ui/hooks/useAgentStream-test-helpers.ts +1 -0
- package/src/ui/hooks/useAutoAcceptIndicator.ts +13 -0
- package/src/ui/hooks/useFolderTrust.ts +118 -81
- package/src/ui/hooks/useGitBranchName.ts +79 -33
- package/src/ui/hooks/useIdeTrustListener.ts +5 -19
- package/src/ui/hooks/usePermissionsModifyTrust.ts +223 -85
- package/src/ui/hooks/useReactToolScheduler.ts +13 -17
- package/src/ui/hooks/useTodoPausePreserver.ts +0 -55
- package/src/ui/layouts/DefaultAppLayout.tsx +2 -0
- package/src/ui/layouts/DefaultAppLayoutHelpers.tsx +37 -162
- package/src/ui/layouts/InlineContent.tsx +198 -0
- package/src/ui/trustDialogHelpers.ts +190 -0
- package/src/utils/cleanup-state.ts +115 -0
- package/src/utils/cleanup.ts +32 -34
- package/src/utils/sandbox-containers.ts +183 -53
- package/src/utils/sandbox-exec.ts +9 -3
- package/src/zed-integration/acp-terminal-shell-host.ts +112 -0
- package/src/zed-integration/acp-types.ts +35 -0
- package/src/zed-integration/fileSystemService.ts +1 -1
- package/src/zed-integration/runZedIntegration.ts +142 -0
- package/src/zed-integration/zed-agent-event-handler.ts +179 -0
- package/src/zed-integration/zed-agent-setup.ts +43 -0
- package/src/zed-integration/zed-command-registry.ts +167 -0
- package/src/zed-integration/zed-config-options.ts +280 -0
- package/src/zed-integration/zed-content-utils.ts +2 -2
- package/src/zed-integration/zed-helpers.ts +132 -0
- package/src/zed-integration/zed-initialize.ts +64 -0
- package/src/zed-integration/zed-plan-update.ts +20 -0
- package/src/zed-integration/zed-prompt-command.ts +77 -0
- package/src/zed-integration/zed-session-config.ts +119 -0
- package/src/zed-integration/zed-session-errors.ts +337 -0
- package/src/zed-integration/zed-session-events.ts +216 -0
- package/src/zed-integration/zed-session-info.ts +255 -0
- package/src/zed-integration/zed-session-lifecycle.ts +186 -0
- package/src/zed-integration/zed-session-listing.ts +153 -0
- package/src/zed-integration/zed-session-loader.ts +193 -0
- package/src/zed-integration/zed-session-pagination.ts +240 -0
- package/src/zed-integration/zed-session-replay.ts +564 -0
- package/src/zed-integration/zed-stream-batcher.ts +236 -0
- package/src/zed-integration/zed-terminal-manager.ts +416 -0
- package/src/zed-integration/zed-terminal-setup.ts +72 -0
- package/src/zed-integration/zed-test-helpers.ts +349 -4
- package/src/zed-integration/zed-tool-handler.ts +47 -5
- package/src/zed-integration/zedIntegration.ts +538 -587
- package/src/services/todo-continuation/todoContinuationService.ts +0 -610
- package/src/ui/containers/AppContainer/hooks/useIdeRestartHotkey.ts +0 -33
- package/src/ui/containers/AppContainer/hooks/useTodoContinuationFlow.ts +0 -160
- package/src/ui/hooks/useTodoContinuation.ts +0 -299
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
7
8
|
import * as fs from 'node:fs';
|
|
8
9
|
import * as path from 'node:path';
|
|
9
10
|
import {
|
|
@@ -13,7 +14,9 @@ import {
|
|
|
13
14
|
getIdeTrust,
|
|
14
15
|
} from '@vybestack/llxprt-code-core';
|
|
15
16
|
import stripJsonComments from 'strip-json-comments';
|
|
17
|
+
import { debugLogger } from '@vybestack/llxprt-code-telemetry';
|
|
16
18
|
import type { Settings } from './settings.js';
|
|
19
|
+
import { formatConfigFileErrors } from './configError.js';
|
|
17
20
|
import { USER_SETTINGS_DIR } from './paths.js';
|
|
18
21
|
|
|
19
22
|
export const TRUSTED_FOLDERS_FILENAME = 'trustedFolders.json';
|
|
@@ -43,6 +46,13 @@ export interface TrustRule {
|
|
|
43
46
|
trustLevel: TrustLevel;
|
|
44
47
|
}
|
|
45
48
|
|
|
49
|
+
export interface ResolvedTrustRule {
|
|
50
|
+
readonly rule: TrustRule;
|
|
51
|
+
readonly effectivePath: string;
|
|
52
|
+
readonly trusted: boolean;
|
|
53
|
+
readonly provenance: 'direct' | 'inherited';
|
|
54
|
+
}
|
|
55
|
+
|
|
46
56
|
export interface TrustedFoldersError {
|
|
47
57
|
message: string;
|
|
48
58
|
path: string;
|
|
@@ -53,6 +63,37 @@ export interface TrustedFoldersFile {
|
|
|
53
63
|
path: string;
|
|
54
64
|
}
|
|
55
65
|
|
|
66
|
+
export interface TrustedFolderSnapshot {
|
|
67
|
+
readonly canonicalPath: string;
|
|
68
|
+
readonly entries: ReadonlyArray<readonly [string, TrustLevel]>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function resolveCanonicalPath(location: string): string | undefined {
|
|
72
|
+
try {
|
|
73
|
+
return fs.realpathSync(path.resolve(location));
|
|
74
|
+
} catch {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function requireCanonicalPath(location: string): string {
|
|
80
|
+
const canonicalPath = resolveCanonicalPath(location);
|
|
81
|
+
if (canonicalPath === undefined) {
|
|
82
|
+
throw new Error(`Unable to resolve canonical path for "${location}".`);
|
|
83
|
+
}
|
|
84
|
+
return canonicalPath;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function restoreConfigInPlace(
|
|
88
|
+
target: Record<string, TrustLevel>,
|
|
89
|
+
snapshot: Readonly<Record<string, TrustLevel>>,
|
|
90
|
+
): void {
|
|
91
|
+
for (const key of Object.keys(target)) {
|
|
92
|
+
delete target[key];
|
|
93
|
+
}
|
|
94
|
+
Object.assign(target, snapshot);
|
|
95
|
+
}
|
|
96
|
+
|
|
56
97
|
export class LoadedTrustedFolders {
|
|
57
98
|
constructor(
|
|
58
99
|
readonly user: TrustedFoldersFile,
|
|
@@ -74,54 +115,142 @@ export class LoadedTrustedFolders {
|
|
|
74
115
|
* @returns
|
|
75
116
|
*/
|
|
76
117
|
isPathTrusted(location: string): boolean | undefined {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
for (const rule of this.rules) {
|
|
81
|
-
switch (rule.trustLevel) {
|
|
82
|
-
case TrustLevel.TRUST_FOLDER:
|
|
83
|
-
trustedPaths.push(rule.path);
|
|
84
|
-
break;
|
|
85
|
-
case TrustLevel.TRUST_PARENT:
|
|
86
|
-
trustedPaths.push(path.dirname(rule.path));
|
|
87
|
-
break;
|
|
88
|
-
case TrustLevel.DO_NOT_TRUST:
|
|
89
|
-
untrustedPaths.push(rule.path);
|
|
90
|
-
break;
|
|
91
|
-
default:
|
|
92
|
-
// Do nothing for unknown trust levels.
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
118
|
+
return this.resolvePathTrust(location)?.trusted;
|
|
119
|
+
}
|
|
96
120
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
121
|
+
resolvePathTrust(location: string): ResolvedTrustRule | undefined {
|
|
122
|
+
const resolvedLocation = resolveCanonicalPath(location);
|
|
123
|
+
if (resolvedLocation === undefined) {
|
|
124
|
+
return undefined;
|
|
101
125
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
|
|
126
|
+
const matches = this.rules.flatMap((rule) => {
|
|
127
|
+
const canonicalRulePath = resolveCanonicalPath(rule.path);
|
|
128
|
+
if (canonicalRulePath === undefined) {
|
|
129
|
+
if (rule.trustLevel !== TrustLevel.DO_NOT_TRUST) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
const effectivePath = path.resolve(rule.path);
|
|
133
|
+
const lexicalLocation = path.resolve(location);
|
|
134
|
+
if (
|
|
135
|
+
!isWithinRoot(lexicalLocation, effectivePath) &&
|
|
136
|
+
!isWithinRoot(resolvedLocation, effectivePath)
|
|
137
|
+
) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
return [
|
|
141
|
+
{
|
|
142
|
+
rule,
|
|
143
|
+
effectivePath,
|
|
144
|
+
trusted: false,
|
|
145
|
+
provenance:
|
|
146
|
+
lexicalLocation === effectivePath
|
|
147
|
+
? ('direct' as const)
|
|
148
|
+
: ('inherited' as const),
|
|
149
|
+
},
|
|
150
|
+
];
|
|
106
151
|
}
|
|
152
|
+
const effectivePath =
|
|
153
|
+
rule.trustLevel === TrustLevel.TRUST_PARENT
|
|
154
|
+
? path.dirname(canonicalRulePath)
|
|
155
|
+
: canonicalRulePath;
|
|
156
|
+
if (!isWithinRoot(resolvedLocation, effectivePath)) {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
return [
|
|
160
|
+
{
|
|
161
|
+
rule,
|
|
162
|
+
effectivePath,
|
|
163
|
+
trusted: rule.trustLevel !== TrustLevel.DO_NOT_TRUST,
|
|
164
|
+
provenance:
|
|
165
|
+
resolvedLocation === effectivePath
|
|
166
|
+
? ('direct' as const)
|
|
167
|
+
: ('inherited' as const),
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// The most specific rule wins; at equal specificity, denial wins so an
|
|
173
|
+
// ambiguous configuration cannot accidentally grant trust.
|
|
174
|
+
matches.sort((left, right) => {
|
|
175
|
+
const specificity =
|
|
176
|
+
right.effectivePath.length - left.effectivePath.length;
|
|
177
|
+
return specificity !== 0
|
|
178
|
+
? specificity
|
|
179
|
+
: Number(left.trusted) - Number(right.trusted);
|
|
180
|
+
});
|
|
181
|
+
return matches[0];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
getValue(location: string): TrustLevel | undefined {
|
|
185
|
+
const canonicalPath = resolveCanonicalPath(location);
|
|
186
|
+
return canonicalPath === undefined
|
|
187
|
+
? undefined
|
|
188
|
+
: this.user.config[canonicalPath];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private aliasesFor(canonicalPath: string): string[] {
|
|
192
|
+
return Object.keys(this.user.config).filter(
|
|
193
|
+
(rulePath) => resolveCanonicalPath(rulePath) === canonicalPath,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
snapshotValue(location: string): TrustedFolderSnapshot {
|
|
198
|
+
const canonicalPath = requireCanonicalPath(location);
|
|
199
|
+
const aliases = new Set(this.aliasesFor(canonicalPath));
|
|
200
|
+
return {
|
|
201
|
+
canonicalPath,
|
|
202
|
+
entries: Object.entries(this.user.config).filter(([rulePath]) =>
|
|
203
|
+
aliases.has(rulePath),
|
|
204
|
+
),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
restoreSnapshot(snapshot: TrustedFolderSnapshot): void {
|
|
209
|
+
const originalConfig = { ...this.user.config };
|
|
210
|
+
for (const rulePath of this.aliasesFor(snapshot.canonicalPath)) {
|
|
211
|
+
delete this.user.config[rulePath];
|
|
212
|
+
}
|
|
213
|
+
for (const [rulePath, trustLevel] of snapshot.entries) {
|
|
214
|
+
this.user.config[rulePath] = trustLevel;
|
|
107
215
|
}
|
|
216
|
+
try {
|
|
217
|
+
saveTrustedFolders(this.user);
|
|
218
|
+
} catch (e) {
|
|
219
|
+
restoreConfigInPlace(this.user.config, originalConfig);
|
|
220
|
+
throw e;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
108
223
|
|
|
109
|
-
|
|
224
|
+
setValue(location: string, trustLevel: TrustLevel): void {
|
|
225
|
+
const canonicalPath = requireCanonicalPath(location);
|
|
226
|
+
const originalConfig = { ...this.user.config };
|
|
227
|
+
const aliases = this.aliasesFor(canonicalPath);
|
|
228
|
+
for (const alias of aliases) {
|
|
229
|
+
delete this.user.config[alias];
|
|
230
|
+
}
|
|
231
|
+
this.user.config[canonicalPath] = trustLevel;
|
|
232
|
+
try {
|
|
233
|
+
saveTrustedFolders(this.user);
|
|
234
|
+
} catch (e) {
|
|
235
|
+
restoreConfigInPlace(this.user.config, originalConfig);
|
|
236
|
+
throw e;
|
|
237
|
+
}
|
|
110
238
|
}
|
|
111
239
|
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
|
|
240
|
+
deleteValue(location: string): void {
|
|
241
|
+
const canonicalPath = requireCanonicalPath(location);
|
|
242
|
+
const originalConfig = { ...this.user.config };
|
|
243
|
+
const aliases = this.aliasesFor(canonicalPath);
|
|
244
|
+
if (aliases.length === 0) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
for (const alias of aliases) {
|
|
248
|
+
delete this.user.config[alias];
|
|
249
|
+
}
|
|
116
250
|
try {
|
|
117
251
|
saveTrustedFolders(this.user);
|
|
118
252
|
} catch (e) {
|
|
119
|
-
|
|
120
|
-
if (!hadOriginalTrustLevel) {
|
|
121
|
-
delete this.user.config[path];
|
|
122
|
-
} else {
|
|
123
|
-
this.user.config[path] = originalTrustLevel;
|
|
124
|
-
}
|
|
253
|
+
restoreConfigInPlace(this.user.config, originalConfig);
|
|
125
254
|
throw e;
|
|
126
255
|
}
|
|
127
256
|
}
|
|
@@ -185,6 +314,50 @@ export function loadTrustedFolders(): LoadedTrustedFolders {
|
|
|
185
314
|
return loadedTrustedFolders;
|
|
186
315
|
}
|
|
187
316
|
|
|
317
|
+
function removeTemporaryFile(temporaryPath: string): void {
|
|
318
|
+
try {
|
|
319
|
+
fs.unlinkSync(temporaryPath);
|
|
320
|
+
} catch (error) {
|
|
321
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
|
322
|
+
debugLogger.warn(
|
|
323
|
+
`Failed to remove trusted folders temporary file ${temporaryPath}:`,
|
|
324
|
+
error,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function isUnsupportedFileModeError(error: unknown): boolean {
|
|
331
|
+
if (!(error instanceof Error) || !('code' in error)) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
return (
|
|
335
|
+
error.code === 'ENOSYS' ||
|
|
336
|
+
error.code === 'ENOTSUP' ||
|
|
337
|
+
error.code === 'EOPNOTSUPP'
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function secureTemporaryFileMode(temporaryPath: string): void {
|
|
342
|
+
try {
|
|
343
|
+
fs.chmodSync(temporaryPath, 0o600);
|
|
344
|
+
const temporaryMode = fs.statSync(temporaryPath).mode & 0o777;
|
|
345
|
+
if (temporaryMode !== 0o600) {
|
|
346
|
+
throw new Error(
|
|
347
|
+
`Trusted folders temporary file has mode ${temporaryMode.toString(8)} instead of 600.`,
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
} catch (error) {
|
|
351
|
+
if (!isUnsupportedFileModeError(error)) {
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
debugLogger.warn(
|
|
355
|
+
`Filesystem for trusted folders does not support POSIX file modes; continuing with the mode requested at file creation for ${temporaryPath}:`,
|
|
356
|
+
error,
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
188
361
|
export function saveTrustedFolders(
|
|
189
362
|
trustedFoldersFile: TrustedFoldersFile,
|
|
190
363
|
): void {
|
|
@@ -194,11 +367,32 @@ export function saveTrustedFolders(
|
|
|
194
367
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
195
368
|
}
|
|
196
369
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
{ encoding: 'utf-8', mode: 0o600 },
|
|
370
|
+
const temporaryPath = path.join(
|
|
371
|
+
dirPath,
|
|
372
|
+
`.${path.basename(trustedFoldersFile.path)}.${process.pid}.${randomUUID()}.tmp`,
|
|
201
373
|
);
|
|
374
|
+
try {
|
|
375
|
+
fs.writeFileSync(
|
|
376
|
+
temporaryPath,
|
|
377
|
+
JSON.stringify(trustedFoldersFile.config, null, 2),
|
|
378
|
+
{ encoding: 'utf-8', mode: 0o600, flag: 'wx' },
|
|
379
|
+
);
|
|
380
|
+
if (process.platform !== 'win32') {
|
|
381
|
+
secureTemporaryFileMode(temporaryPath);
|
|
382
|
+
}
|
|
383
|
+
} catch (error) {
|
|
384
|
+
removeTemporaryFile(temporaryPath);
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Atomic replacement is the commit point; nothing fallible may follow it on
|
|
389
|
+
// success. A failed commit still owns the temporary file and must remove it.
|
|
390
|
+
try {
|
|
391
|
+
fs.renameSync(temporaryPath, trustedFoldersFile.path);
|
|
392
|
+
} catch (error) {
|
|
393
|
+
removeTemporaryFile(temporaryPath);
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
202
396
|
}
|
|
203
397
|
|
|
204
398
|
/** Is folder trust feature enabled per the current applied settings */
|
|
@@ -208,33 +402,56 @@ export function isFolderTrustEnabled(settings: Settings): boolean {
|
|
|
208
402
|
return folderTrustSetting;
|
|
209
403
|
}
|
|
210
404
|
|
|
211
|
-
function
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
`${errorMessages.join('\n')}\nPlease fix the configuration file and try again.`,
|
|
220
|
-
);
|
|
405
|
+
export function resolveWorkspaceTrust(
|
|
406
|
+
settings: Settings,
|
|
407
|
+
trustedFolders: LoadedTrustedFolders,
|
|
408
|
+
workingDirectory: string,
|
|
409
|
+
ideTrust: boolean | undefined = getIdeTrust(),
|
|
410
|
+
): boolean | undefined {
|
|
411
|
+
if (!isFolderTrustEnabled(settings)) {
|
|
412
|
+
return true;
|
|
221
413
|
}
|
|
222
|
-
|
|
223
|
-
|
|
414
|
+
if (ideTrust !== undefined) {
|
|
415
|
+
return ideTrust;
|
|
416
|
+
}
|
|
417
|
+
return trustedFolders.isPathTrusted(workingDirectory);
|
|
224
418
|
}
|
|
225
419
|
|
|
226
|
-
export function
|
|
420
|
+
export function resolveLocalWorkspaceTrust(
|
|
421
|
+
settings: Settings,
|
|
422
|
+
trustedFolders: LoadedTrustedFolders,
|
|
423
|
+
workingDirectory: string,
|
|
424
|
+
): boolean | undefined {
|
|
227
425
|
if (!isFolderTrustEnabled(settings)) {
|
|
228
426
|
return true;
|
|
229
427
|
}
|
|
428
|
+
return trustedFolders.isPathTrusted(workingDirectory);
|
|
429
|
+
}
|
|
230
430
|
|
|
231
|
-
|
|
431
|
+
export function isWorkspaceTrusted(
|
|
432
|
+
settings: Settings,
|
|
433
|
+
workingDirectory: string = process.cwd(),
|
|
434
|
+
ideTrust: boolean | undefined = getIdeTrust(),
|
|
435
|
+
): boolean | undefined {
|
|
436
|
+
if (!isFolderTrustEnabled(settings)) {
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
232
439
|
if (ideTrust !== undefined) {
|
|
233
440
|
return ideTrust;
|
|
234
441
|
}
|
|
235
442
|
|
|
236
|
-
|
|
237
|
-
|
|
443
|
+
const trustedFolders = loadTrustedFolders();
|
|
444
|
+
if (trustedFolders.errors.length > 0) {
|
|
445
|
+
throw new FatalConfigError(
|
|
446
|
+
formatConfigFileErrors(trustedFolders.errors, 'configuration file'),
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
return resolveWorkspaceTrust(
|
|
450
|
+
settings,
|
|
451
|
+
trustedFolders,
|
|
452
|
+
workingDirectory,
|
|
453
|
+
ideTrust,
|
|
454
|
+
);
|
|
238
455
|
}
|
|
239
456
|
|
|
240
457
|
/**
|
|
@@ -207,6 +207,13 @@ export const innerCommandOptions: Record<string, Options> = {
|
|
|
207
207
|
description:
|
|
208
208
|
'Output format for non-interactive mode (text, json, or stream-json).',
|
|
209
209
|
},
|
|
210
|
+
quiet: {
|
|
211
|
+
alias: 'q',
|
|
212
|
+
type: 'boolean',
|
|
213
|
+
description:
|
|
214
|
+
'Suppress tool calls, tool results, and intermediate text. Only the final response is written to stdout (non-interactive mode).',
|
|
215
|
+
default: false,
|
|
216
|
+
},
|
|
210
217
|
sandbox: {
|
|
211
218
|
alias: 's',
|
|
212
219
|
type: 'boolean',
|
package/src/nonInteractiveCli.ts
CHANGED
|
@@ -368,6 +368,7 @@ async function processQuery(
|
|
|
368
368
|
config: params.config,
|
|
369
369
|
jsonOutput: options.jsonOutput,
|
|
370
370
|
streamJsonOutput: options.streamJsonOutput,
|
|
371
|
+
quiet: params.config.getQuiet(),
|
|
371
372
|
streamFormatter: options.streamFormatter,
|
|
372
373
|
emojiFilter: options.emojiFilter,
|
|
373
374
|
createProfileNameWriter: () =>
|