shennian 0.3.85 → 0.3.86
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/bin/shennian.js +1 -1
- package/dist/publish-build-manifest.json +28 -28
- package/dist/src/agents/adapter.js +19 -1
- package/dist/src/agents/claude-managed-permissions.js +248 -1
- package/dist/src/agents/claude.js +393 -8
- package/dist/src/agents/codex-managed-permissions.js +294 -1
- package/dist/src/agents/codex-managed-room-tools.js +249 -1
- package/dist/src/agents/codex-utils.js +200 -7
- package/dist/src/agents/codex.js +1352 -17
- package/dist/src/agents/config-status.js +226 -1
- package/dist/src/agents/cursor-managed-permissions.js +299 -2
- package/dist/src/agents/cursor.js +314 -1
- package/dist/src/agents/custom.js +418 -4
- package/dist/src/agents/external-channel-instructions.js +94 -11
- package/dist/src/agents/gemini.js +180 -1
- package/dist/src/agents/manager.d.ts +2 -0
- package/dist/src/agents/manager.js +250 -18
- package/dist/src/agents/model-registry/cache.js +37 -1
- package/dist/src/agents/model-registry/discovery.js +188 -2
- package/dist/src/agents/model-registry/parsers.js +521 -4
- package/dist/src/agents/model-registry/runner.js +30 -1
- package/dist/src/agents/model-registry/service.js +115 -1
- package/dist/src/agents/model-registry/types.js +8 -1
- package/dist/src/agents/model-registry.js +19 -1
- package/dist/src/agents/native-capabilities.js +237 -1
- package/dist/src/agents/openclaw.js +293 -2
- package/dist/src/agents/opencode-managed-permissions.js +187 -2
- package/dist/src/agents/opencode.js +298 -1
- package/dist/src/agents/platform-instructions.js +46 -17
- package/dist/src/agents/runtime-compatibility.js +44 -1
- package/dist/src/agents/workbuddy-managed-permissions.js +329 -2
- package/dist/src/agents/workbuddy.js +444 -3
- package/dist/src/commands/room.js +2 -2
- package/dist/src/fs/boundary.js +185 -1
- package/dist/src/fs/handler.js +130 -1
- package/dist/src/fs/security.js +32 -1
- package/dist/src/fs/text-decoder.js +110 -1
- package/dist/src/index.js +587 -3
- package/dist/src/manager/prompt.js +34 -29
- package/dist/src/manager/registry.js +317 -1
- package/dist/src/manager/retired-external-channel-compat.js +40 -1
- package/dist/src/manager/runtime.d.ts +4 -0
- package/dist/src/manager/runtime.js +1514 -23
- package/dist/src/native-fusion/codex-parser.js +660 -4
- package/dist/src/native-fusion/codex-user-input.js +102 -5
- package/dist/src/native-fusion/config.js +5 -1
- package/dist/src/native-fusion/file-watcher.js +191 -1
- package/dist/src/native-fusion/local-repository.js +569 -2
- package/dist/src/native-fusion/opencode-parser.js +130 -3
- package/dist/src/native-fusion/parsers.js +140 -3
- package/dist/src/native-fusion/service.js +739 -2
- package/dist/src/native-fusion/session-header.js +101 -2
- package/dist/src/native-fusion/state.js +104 -2
- package/dist/src/native-fusion/types.js +1 -1
- package/dist/src/personal-sync/machine-authority.js +34 -1
- package/dist/src/room/activation-audit.js +45 -2
- package/dist/src/room/activation-policy.js +30 -1
- package/dist/src/room/activation-service.d.ts +1 -0
- package/dist/src/room/activation-service.js +408 -8
- package/dist/src/room/invite-bootstrap.js +156 -1
- package/dist/src/room/managed-context.d.ts +1 -1
- package/dist/src/room/managed-context.js +1 -1
- package/dist/src/room/managed-prompt-composer.d.ts +1 -1
- package/dist/src/room/managed-prompt-composer.js +6 -5
- package/dist/src/room/managed-room-binding.js +167 -1
- package/dist/src/room/managed-room-ipc.d.ts +2 -2
- package/dist/src/room/managed-room-ipc.js +2 -2
- package/dist/src/room/mirror-sync-service.js +183 -1
- package/dist/src/room/room-action-client.d.ts +11 -0
- package/dist/src/room/room-action-client.js +1 -1
- package/dist/src/room/room-binding-client.d.ts +1 -0
- package/dist/src/room/room-binding-client.js +151 -1
- package/dist/src/security/managed-agent-policy.d.ts +3 -2
- package/dist/src/security/managed-agent-policy.js +1 -1
- package/dist/src/session/archive-zip.js +220 -1
- package/dist/src/session/deletion-sync-state.js +136 -2
- package/dist/src/session/handlers/agent-capabilities.js +14 -1
- package/dist/src/session/handlers/agent-config.js +150 -1
- package/dist/src/session/handlers/agents.js +55 -1
- package/dist/src/session/handlers/chat.d.ts +1 -1
- package/dist/src/session/handlers/chat.js +1030 -2
- package/dist/src/session/handlers/control.js +61 -1
- package/dist/src/session/handlers/fs.js +594 -1
- package/dist/src/session/handlers/message-status.js +15 -1
- package/dist/src/session/handlers/remote-access.js +43 -1
- package/dist/src/session/handlers/room-managed.js +101 -1
- package/dist/src/session/handlers/session-refresh.js +35 -1
- package/dist/src/session/handlers/title.js +79 -1
- package/dist/src/session/handlers/tool-detail.js +149 -1
- package/dist/src/session/handlers/voice-window.js +62 -1
- package/dist/src/session/history-subscriptions.js +470 -1
- package/dist/src/session/manager.js +658 -1
- package/dist/src/session/native-cleanup-outbox.js +287 -2
- package/dist/src/session/native-session-lifecycle.js +327 -6
- package/dist/src/session/queue.d.ts +5 -0
- package/dist/src/session/queue.js +8 -8
- package/dist/src/upgrade/scheduler.js +126 -1
- package/node_modules/@shennian/wire/dist/agent-workspace.js +1 -1
- package/package.json +1 -1
package/dist/bin/shennian.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import '../src/index.js';
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
"file": "src/agents/codex-managed-room-tools.js",
|
|
39
|
-
"beforeBytes":
|
|
40
|
-
"afterBytes":
|
|
39
|
+
"beforeBytes": 9529,
|
|
40
|
+
"afterBytes": 5253
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"file": "src/agents/codex-utils.js",
|
|
@@ -96,8 +96,8 @@
|
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
"file": "src/agents/manager.js",
|
|
99
|
-
"beforeBytes":
|
|
100
|
-
"afterBytes":
|
|
99
|
+
"beforeBytes": 10725,
|
|
100
|
+
"afterBytes": 5801
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
"file": "src/agents/model-registry/cache.js",
|
|
@@ -226,8 +226,8 @@
|
|
|
226
226
|
},
|
|
227
227
|
{
|
|
228
228
|
"file": "src/commands/room.js",
|
|
229
|
-
"beforeBytes":
|
|
230
|
-
"afterBytes":
|
|
229
|
+
"beforeBytes": 17685,
|
|
230
|
+
"afterBytes": 10063
|
|
231
231
|
},
|
|
232
232
|
{
|
|
233
233
|
"file": "src/commands/runtime.js",
|
|
@@ -341,8 +341,8 @@
|
|
|
341
341
|
},
|
|
342
342
|
{
|
|
343
343
|
"file": "src/manager/runtime.js",
|
|
344
|
-
"beforeBytes":
|
|
345
|
-
"afterBytes":
|
|
344
|
+
"beforeBytes": 72951,
|
|
345
|
+
"afterBytes": 36995
|
|
346
346
|
},
|
|
347
347
|
{
|
|
348
348
|
"file": "src/native-fusion/codex-files.js",
|
|
@@ -461,8 +461,8 @@
|
|
|
461
461
|
},
|
|
462
462
|
{
|
|
463
463
|
"file": "src/room/activation-service.js",
|
|
464
|
-
"beforeBytes":
|
|
465
|
-
"afterBytes":
|
|
464
|
+
"beforeBytes": 21587,
|
|
465
|
+
"afterBytes": 10726
|
|
466
466
|
},
|
|
467
467
|
{
|
|
468
468
|
"file": "src/room/attachment-cache.js",
|
|
@@ -496,13 +496,13 @@
|
|
|
496
496
|
},
|
|
497
497
|
{
|
|
498
498
|
"file": "src/room/managed-context.js",
|
|
499
|
-
"beforeBytes":
|
|
500
|
-
"afterBytes":
|
|
499
|
+
"beforeBytes": 4521,
|
|
500
|
+
"afterBytes": 2538
|
|
501
501
|
},
|
|
502
502
|
{
|
|
503
503
|
"file": "src/room/managed-prompt-composer.js",
|
|
504
|
-
"beforeBytes":
|
|
505
|
-
"afterBytes":
|
|
504
|
+
"beforeBytes": 8751,
|
|
505
|
+
"afterBytes": 8603
|
|
506
506
|
},
|
|
507
507
|
{
|
|
508
508
|
"file": "src/room/managed-room-binding.js",
|
|
@@ -511,8 +511,8 @@
|
|
|
511
511
|
},
|
|
512
512
|
{
|
|
513
513
|
"file": "src/room/managed-room-ipc.js",
|
|
514
|
-
"beforeBytes":
|
|
515
|
-
"afterBytes":
|
|
514
|
+
"beforeBytes": 11997,
|
|
515
|
+
"afterBytes": 5784
|
|
516
516
|
},
|
|
517
517
|
{
|
|
518
518
|
"file": "src/room/mirror-sync-service.js",
|
|
@@ -531,13 +531,13 @@
|
|
|
531
531
|
},
|
|
532
532
|
{
|
|
533
533
|
"file": "src/room/room-action-client.js",
|
|
534
|
-
"beforeBytes":
|
|
535
|
-
"afterBytes":
|
|
534
|
+
"beforeBytes": 27845,
|
|
535
|
+
"afterBytes": 13911
|
|
536
536
|
},
|
|
537
537
|
{
|
|
538
538
|
"file": "src/room/room-binding-client.js",
|
|
539
|
-
"beforeBytes":
|
|
540
|
-
"afterBytes":
|
|
539
|
+
"beforeBytes": 7085,
|
|
540
|
+
"afterBytes": 4068
|
|
541
541
|
},
|
|
542
542
|
{
|
|
543
543
|
"file": "src/room/session-registry.js",
|
|
@@ -556,8 +556,8 @@
|
|
|
556
556
|
},
|
|
557
557
|
{
|
|
558
558
|
"file": "src/security/managed-agent-policy.js",
|
|
559
|
-
"beforeBytes":
|
|
560
|
-
"afterBytes":
|
|
559
|
+
"beforeBytes": 6728,
|
|
560
|
+
"afterBytes": 3141
|
|
561
561
|
},
|
|
562
562
|
{
|
|
563
563
|
"file": "src/security/managed-agent-runtime.js",
|
|
@@ -606,8 +606,8 @@
|
|
|
606
606
|
},
|
|
607
607
|
{
|
|
608
608
|
"file": "src/session/handlers/chat.js",
|
|
609
|
-
"beforeBytes":
|
|
610
|
-
"afterBytes":
|
|
609
|
+
"beforeBytes": 43645,
|
|
610
|
+
"afterBytes": 18275
|
|
611
611
|
},
|
|
612
612
|
{
|
|
613
613
|
"file": "src/session/handlers/control.js",
|
|
@@ -666,8 +666,8 @@
|
|
|
666
666
|
},
|
|
667
667
|
{
|
|
668
668
|
"file": "src/session/manager.js",
|
|
669
|
-
"beforeBytes":
|
|
670
|
-
"afterBytes":
|
|
669
|
+
"beforeBytes": 30970,
|
|
670
|
+
"afterBytes": 16083
|
|
671
671
|
},
|
|
672
672
|
{
|
|
673
673
|
"file": "src/session/native-cleanup-outbox.js",
|
|
@@ -686,8 +686,8 @@
|
|
|
686
686
|
},
|
|
687
687
|
{
|
|
688
688
|
"file": "src/session/queue.js",
|
|
689
|
-
"beforeBytes":
|
|
690
|
-
"afterBytes":
|
|
689
|
+
"beforeBytes": 30478,
|
|
690
|
+
"afterBytes": 13987
|
|
691
691
|
},
|
|
692
692
|
{
|
|
693
693
|
"file": "src/session/store.js",
|
|
@@ -1 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
// @arch docs/architecture/cli/agent-adapters.md
|
|
2
|
+
// @test src/__tests__/agents-e2e.ts
|
|
3
|
+
import { EventEmitter } from 'node:events';
|
|
4
|
+
export class AgentAdapter extends EventEmitter {
|
|
5
|
+
}
|
|
6
|
+
const registry = new Map();
|
|
7
|
+
export function registerAgent(type, factory) {
|
|
8
|
+
registry.set(type, factory);
|
|
9
|
+
}
|
|
10
|
+
export function unregisterAgent(type) {
|
|
11
|
+
registry.delete(type);
|
|
12
|
+
}
|
|
13
|
+
export function createAgent(type) {
|
|
14
|
+
const factory = registry.get(type);
|
|
15
|
+
return factory ? factory() : null;
|
|
16
|
+
}
|
|
17
|
+
export function getRegisteredAgents() {
|
|
18
|
+
return [...registry.keys()];
|
|
19
|
+
}
|
|
@@ -1 +1,248 @@
|
|
|
1
|
-
|
|
1
|
+
// @arch docs/features/managed-agent-restricted-runtime.md
|
|
2
|
+
// @test src/__tests__/claude-managed-permissions.test.ts
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { resolveProtectedShennianDirectories } from '../security/managed-agent-credential-paths.js';
|
|
6
|
+
const fullExternalCapabilitySupport = {
|
|
7
|
+
commandNetwork: { allow: true, deny: true },
|
|
8
|
+
webSearch: { allow: true, deny: true },
|
|
9
|
+
browser: { allow: true, deny: true },
|
|
10
|
+
// Claude Code's computer-use surface controls the real desktop and does not
|
|
11
|
+
// currently expose a Shennian-verifiable, non-interactive permission gate.
|
|
12
|
+
computerUse: { allow: false, deny: true },
|
|
13
|
+
mcp: { allow: true, deny: true },
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* v2.1.260 is the first evidence baseline used by Shennian: it includes
|
|
17
|
+
* restricted mode, source isolation, fail-closed sandbox startup, credential
|
|
18
|
+
* scrubbing, outside-workspace read blocking, and the macOS fix for that read
|
|
19
|
+
* boundary. Unknown and older builds therefore resolve as unverified.
|
|
20
|
+
*/
|
|
21
|
+
export const CLAUDE_MANAGED_RUNTIME_SECURITY = {
|
|
22
|
+
minimumRuntimeVersion: '2.1.260',
|
|
23
|
+
maximumRuntimeVersionExclusive: '2.2.0',
|
|
24
|
+
platforms: {
|
|
25
|
+
darwin: {
|
|
26
|
+
level: 'hard',
|
|
27
|
+
fileAccess: { 'workspace-read': true, 'workspace-write': true, 'host-full': true },
|
|
28
|
+
externalCapabilities: fullExternalCapabilitySupport,
|
|
29
|
+
},
|
|
30
|
+
linux: {
|
|
31
|
+
level: 'partial',
|
|
32
|
+
fileAccess: { 'workspace-read': true, 'workspace-write': true, 'host-full': true },
|
|
33
|
+
externalCapabilities: fullExternalCapabilitySupport,
|
|
34
|
+
knownGaps: ['internalTransport.unixSocketGranularity'],
|
|
35
|
+
},
|
|
36
|
+
wsl: {
|
|
37
|
+
level: 'partial',
|
|
38
|
+
fileAccess: { 'workspace-read': true, 'workspace-write': true, 'host-full': true },
|
|
39
|
+
externalCapabilities: fullExternalCapabilitySupport,
|
|
40
|
+
knownGaps: ['internalTransport.unixSocketGranularity'],
|
|
41
|
+
},
|
|
42
|
+
win32: {
|
|
43
|
+
level: 'partial',
|
|
44
|
+
fileAccess: { 'workspace-read': false, 'workspace-write': false, 'host-full': true },
|
|
45
|
+
externalCapabilities: {
|
|
46
|
+
commandNetwork: { allow: true, deny: false },
|
|
47
|
+
webSearch: { allow: true, deny: true },
|
|
48
|
+
browser: { allow: true, deny: true },
|
|
49
|
+
computerUse: { allow: false, deny: true },
|
|
50
|
+
mcp: { allow: true, deny: true },
|
|
51
|
+
},
|
|
52
|
+
knownGaps: ['sandbox.nativeWindowsUnavailable'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const SENSITIVE_PERMISSION_PATHS = [
|
|
57
|
+
'//**/.env',
|
|
58
|
+
'//**/.env.*',
|
|
59
|
+
'//**/*.key',
|
|
60
|
+
'//**/*.pem',
|
|
61
|
+
'~/.ssh/**',
|
|
62
|
+
'~/.aws/**',
|
|
63
|
+
'~/.azure/**',
|
|
64
|
+
'~/.config/gcloud/**',
|
|
65
|
+
'~/.netrc',
|
|
66
|
+
'~/.npmrc',
|
|
67
|
+
'~/.shennian/**',
|
|
68
|
+
];
|
|
69
|
+
const SENSITIVE_SANDBOX_PATHS = [
|
|
70
|
+
'/**/.env',
|
|
71
|
+
'/**/.env.*',
|
|
72
|
+
'/**/*.key',
|
|
73
|
+
'/**/*.pem',
|
|
74
|
+
'~/.ssh',
|
|
75
|
+
'~/.aws',
|
|
76
|
+
'~/.azure',
|
|
77
|
+
'~/.config/gcloud',
|
|
78
|
+
'~/.netrc',
|
|
79
|
+
'~/.npmrc',
|
|
80
|
+
];
|
|
81
|
+
const SHENNIAN_HOME_SANDBOX_PATH = '~/.shennian';
|
|
82
|
+
const READ_TOOLS = ['Read', 'Glob', 'Grep', 'LSP'];
|
|
83
|
+
const WRITE_TOOLS = ['Edit', 'Write', 'NotebookEdit'];
|
|
84
|
+
/**
|
|
85
|
+
* Converts the daemon-verified effective policy into Claude Code's native,
|
|
86
|
+
* invocation-scoped permission and sandbox configuration. It never writes to
|
|
87
|
+
* ~/.claude or the project's .claude directory.
|
|
88
|
+
*/
|
|
89
|
+
export function compileClaudeManagedPermissions(enforcement, resolvedWorkDir, options = {}) {
|
|
90
|
+
const workDir = validateResolvedWorkDir(resolvedWorkDir);
|
|
91
|
+
const policy = enforcement.effectivePolicy;
|
|
92
|
+
const hardSandbox = enforcement.platform !== 'win32';
|
|
93
|
+
const internalReadPaths = normalizeAbsolutePaths(options.internalReadPaths);
|
|
94
|
+
const internalUnixSockets = normalizeAbsolutePaths(options.internalUnixSockets);
|
|
95
|
+
const fileRoot = normalizeForClaude(path.parse(workDir).root);
|
|
96
|
+
const normalizedWorkDir = normalizeForClaude(workDir);
|
|
97
|
+
const hostFull = policy.fileAccess === 'host-full';
|
|
98
|
+
const workspaceWritable = policy.fileAccess === 'workspace-write';
|
|
99
|
+
const shennianDirectories = resolveProtectedShennianDirectories();
|
|
100
|
+
const allowRules = [];
|
|
101
|
+
if (workspaceWritable)
|
|
102
|
+
allowRules.push('Edit(/**)');
|
|
103
|
+
if (hostFull)
|
|
104
|
+
allowRules.push('Read', 'Edit');
|
|
105
|
+
if (policy.externalCapabilities.webSearch)
|
|
106
|
+
allowRules.push('WebSearch', 'WebFetch');
|
|
107
|
+
if (policy.externalCapabilities.mcp)
|
|
108
|
+
allowRules.push('mcp__*');
|
|
109
|
+
// Native Windows has no Bash sandbox. The compiler has already widened the
|
|
110
|
+
// effective policy and required limited-protection confirmation before this
|
|
111
|
+
// unsandboxed command surface can be reached.
|
|
112
|
+
if (!hardSandbox)
|
|
113
|
+
allowRules.push('Bash', 'PowerShell');
|
|
114
|
+
const denyRules = [
|
|
115
|
+
...SENSITIVE_PERMISSION_PATHS.flatMap((entry) => [`Read(${entry})`, `Edit(${entry})`]),
|
|
116
|
+
...shennianDirectories.flatMap((entry) => [
|
|
117
|
+
`Read(${toClaudeAbsolutePermissionPattern(entry)}/**)`,
|
|
118
|
+
`Edit(${toClaudeAbsolutePermissionPattern(entry)}/**)`,
|
|
119
|
+
]),
|
|
120
|
+
...(!policy.externalCapabilities.webSearch ? ['WebSearch', 'WebFetch'] : []),
|
|
121
|
+
...(!policy.externalCapabilities.mcp ? ['mcp__*'] : []),
|
|
122
|
+
];
|
|
123
|
+
const filesystem = hardSandbox
|
|
124
|
+
? {
|
|
125
|
+
disabled: false,
|
|
126
|
+
// Claude's sandbox allowRead entries take precedence over denyRead.
|
|
127
|
+
// This keeps the product-owned directory opaque while restoring only
|
|
128
|
+
// the exact daemon transport files needed by the scoped Room CLI.
|
|
129
|
+
allowRead: [...new Set([normalizedWorkDir, ...internalReadPaths])],
|
|
130
|
+
allowWrite: hostFull ? [fileRoot] : workspaceWritable ? [normalizedWorkDir] : [],
|
|
131
|
+
denyRead: [
|
|
132
|
+
...SENSITIVE_SANDBOX_PATHS,
|
|
133
|
+
SHENNIAN_HOME_SANDBOX_PATH,
|
|
134
|
+
...shennianDirectories,
|
|
135
|
+
],
|
|
136
|
+
denyWrite: [
|
|
137
|
+
...SENSITIVE_SANDBOX_PATHS,
|
|
138
|
+
SHENNIAN_HOME_SANDBOX_PATH,
|
|
139
|
+
...shennianDirectories,
|
|
140
|
+
...(!hostFull && !workspaceWritable ? [normalizedWorkDir] : []),
|
|
141
|
+
],
|
|
142
|
+
}
|
|
143
|
+
: undefined;
|
|
144
|
+
const network = hardSandbox
|
|
145
|
+
? {
|
|
146
|
+
allowedDomains: policy.externalCapabilities.commandNetwork ? ['*'] : [],
|
|
147
|
+
deniedDomains: policy.externalCapabilities.commandNetwork ? [] : ['*'],
|
|
148
|
+
strictAllowlist: true,
|
|
149
|
+
allowLocalBinding: policy.externalCapabilities.commandNetwork,
|
|
150
|
+
allowUnixSockets: enforcement.platform === 'darwin' ? internalUnixSockets : [],
|
|
151
|
+
// Linux/WSL only expose an all-or-nothing AF_UNIX switch. The
|
|
152
|
+
// filesystem layer still exposes only the exact daemon path, but the
|
|
153
|
+
// runtime declaration reports this platform as partial.
|
|
154
|
+
allowAllUnixSockets: (enforcement.platform === 'linux' || enforcement.platform === 'wsl') &&
|
|
155
|
+
internalUnixSockets.length > 0,
|
|
156
|
+
}
|
|
157
|
+
: undefined;
|
|
158
|
+
const settings = {
|
|
159
|
+
permissions: {
|
|
160
|
+
defaultMode: 'dontAsk',
|
|
161
|
+
disableBypassPermissionsMode: 'disable',
|
|
162
|
+
disableAutoMode: 'disable',
|
|
163
|
+
blockReadsOutsideWorkingDirectories: !hostFull,
|
|
164
|
+
allow: [...new Set(allowRules)].sort(),
|
|
165
|
+
deny: [...new Set(denyRules)].sort(),
|
|
166
|
+
},
|
|
167
|
+
disableArtifact: true,
|
|
168
|
+
disableRemoteControl: true,
|
|
169
|
+
disableWorkflows: true,
|
|
170
|
+
disableClaudeAiConnectors: !policy.externalCapabilities.mcp,
|
|
171
|
+
...(hardSandbox
|
|
172
|
+
? {
|
|
173
|
+
sandbox: {
|
|
174
|
+
enabled: true,
|
|
175
|
+
failIfUnavailable: true,
|
|
176
|
+
autoAllowBashIfSandboxed: true,
|
|
177
|
+
allowUnsandboxedCommands: false,
|
|
178
|
+
excludedCommands: [],
|
|
179
|
+
allowAppleEvents: false,
|
|
180
|
+
filesystem,
|
|
181
|
+
network,
|
|
182
|
+
credentials: {
|
|
183
|
+
files: SENSITIVE_SANDBOX_PATHS.map((entry) => ({ path: entry, mode: 'deny' })),
|
|
184
|
+
envVars: normalizeEnvKeys(options.shellSubprocessPolicy?.deniedEnvKeys).map((name) => ({ name, mode: 'deny' })),
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
: {}),
|
|
189
|
+
};
|
|
190
|
+
const tools = [
|
|
191
|
+
'Bash',
|
|
192
|
+
...READ_TOOLS,
|
|
193
|
+
...(workspaceWritable || hostFull ? WRITE_TOOLS : []),
|
|
194
|
+
...(policy.externalCapabilities.webSearch ? ['WebSearch', 'WebFetch'] : []),
|
|
195
|
+
];
|
|
196
|
+
const args = [
|
|
197
|
+
'--restricted',
|
|
198
|
+
'--setting-sources',
|
|
199
|
+
'',
|
|
200
|
+
'--settings',
|
|
201
|
+
JSON.stringify(settings),
|
|
202
|
+
'--permission-mode',
|
|
203
|
+
'dontAsk',
|
|
204
|
+
'--tools',
|
|
205
|
+
[...new Set(tools)].join(','),
|
|
206
|
+
policy.externalCapabilities.browser ? '--chrome' : '--no-chrome',
|
|
207
|
+
];
|
|
208
|
+
if (hostFull)
|
|
209
|
+
args.push('--add-dir', fileRoot);
|
|
210
|
+
if (!policy.externalCapabilities.mcp) {
|
|
211
|
+
args.push('--strict-mcp-config', '--mcp-config', JSON.stringify({ mcpServers: {} }));
|
|
212
|
+
}
|
|
213
|
+
return { settings, args };
|
|
214
|
+
}
|
|
215
|
+
function validateResolvedWorkDir(value) {
|
|
216
|
+
const normalized = path.normalize(value.trim());
|
|
217
|
+
if (!normalized || !path.isAbsolute(normalized)) {
|
|
218
|
+
throw new Error('claude_managed_workdir_invalid');
|
|
219
|
+
}
|
|
220
|
+
let realPath;
|
|
221
|
+
try {
|
|
222
|
+
realPath = fs.realpathSync(normalized);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
throw new Error('claude_managed_workdir_unavailable');
|
|
226
|
+
}
|
|
227
|
+
if (path.normalize(realPath) !== normalized) {
|
|
228
|
+
throw new Error('claude_managed_workdir_not_realpath');
|
|
229
|
+
}
|
|
230
|
+
return normalized;
|
|
231
|
+
}
|
|
232
|
+
function normalizeAbsolutePaths(values) {
|
|
233
|
+
return [...new Set(values ?? [])]
|
|
234
|
+
.map((entry) => path.normalize(entry.trim()))
|
|
235
|
+
.filter((entry) => entry && path.isAbsolute(entry))
|
|
236
|
+
.map(normalizeForClaude)
|
|
237
|
+
.sort();
|
|
238
|
+
}
|
|
239
|
+
function normalizeForClaude(value) {
|
|
240
|
+
return value.replaceAll('\\', '/');
|
|
241
|
+
}
|
|
242
|
+
function toClaudeAbsolutePermissionPattern(value) {
|
|
243
|
+
const normalized = normalizeForClaude(value);
|
|
244
|
+
return normalized.startsWith('/') ? `/${normalized}` : `//${normalized}`;
|
|
245
|
+
}
|
|
246
|
+
function normalizeEnvKeys(values) {
|
|
247
|
+
return [...new Set(values ?? [])].filter((value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value)).sort();
|
|
248
|
+
}
|