windows-development-sandbox 1.11.7 → 1.13.0
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/README.md +13 -6
- package/config.example.json +15 -4
- package/dist/app/features/access/access.def.d.ts +190 -0
- package/dist/app/features/access/access.def.js +273 -0
- package/dist/app/features/access/access.run.d.ts +79 -0
- package/dist/app/features/access/access.run.js +129 -0
- package/dist/app/features/access/index.d.ts +2 -0
- package/dist/app/features/access/index.js +3 -0
- package/dist/app/features/agents/agent-entry.js +5 -0
- package/dist/app/features/agents/agents.def.js +1 -0
- package/dist/app/features/apps/apps-rows.d.ts +4 -1
- package/dist/app/features/apps/apps-rows.js +7 -2
- package/dist/app/features/apps/apps.def.d.ts +19 -0
- package/dist/app/features/apps/apps.def.js +50 -12
- package/dist/app/features/apps/apps.run.d.ts +2 -0
- package/dist/app/features/apps/apps.run.js +1 -1
- package/dist/app/features/audit/audit.def.d.ts +350 -0
- package/dist/app/features/audit/audit.def.js +457 -0
- package/dist/app/features/audit/audit.run.d.ts +110 -0
- package/dist/app/features/audit/audit.run.js +133 -0
- package/dist/app/features/audit/index.d.ts +2 -0
- package/dist/app/features/audit/index.js +3 -0
- package/dist/app/features/defs.d.ts +349 -4
- package/dist/app/features/defs.js +16 -1
- package/dist/app/features/files/files.def.js +1 -0
- package/dist/app/features/health/health.def.js +1 -0
- package/dist/app/features/sandbox/sandbox.def.js +3 -0
- package/dist/app/features/sessions/sessions.def.d.ts +36 -0
- package/dist/app/features/sessions/sessions.def.js +77 -9
- package/dist/app/features/sessions/sessions.run.d.ts +25 -2
- package/dist/app/features/sessions/sessions.run.js +71 -3
- package/dist/app/features/settings/settings.def.d.ts +8 -0
- package/dist/app/features/settings/settings.def.js +17 -0
- package/dist/app/features/settings/settings.run.d.ts +3 -0
- package/dist/app/features/settings/settings.run.js +16 -2
- package/dist/app/features/web/web.def.d.ts +9 -0
- package/dist/app/features/web/web.def.js +26 -1
- package/dist/app/features/web/web.run.d.ts +3 -0
- package/dist/app/features/web/web.run.js +11 -3
- package/dist/app/kernel/access.d.ts +33 -0
- package/dist/app/kernel/access.js +44 -0
- package/dist/app/kernel/define.d.ts +26 -2
- package/dist/app/kernel/index.d.ts +1 -0
- package/dist/app/kernel/index.js +1 -0
- package/dist/app/kernel/rpc.d.ts +5 -2
- package/dist/app/registry.d.ts +4 -1
- package/dist/app/registry.js +26 -4
- package/dist/cli/args.d.ts +0 -3
- package/dist/cli/args.js +3 -4
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/launch/prepare.js +1 -1
- package/dist/cli/commands/maintenance/index.d.ts +0 -1
- package/dist/cli/commands/maintenance/index.js +0 -1
- package/dist/cli/commands/registry.js +3 -2
- package/dist/cli/commands/remote.d.ts +2 -0
- package/dist/cli/commands/remote.js +49 -0
- package/dist/cli/commands/sessions/reopen.js +3 -0
- package/dist/cli/commands/web.js +66 -0
- package/dist/cli/manifest.d.ts +63 -45
- package/dist/cli/manifest.js +33 -18
- package/dist/cli/menu/io-menu.d.ts +5 -3
- package/dist/cli/menu/io-menu.js +12 -5
- package/dist/cli/menu/pages/apps-page.js +2 -15
- package/dist/cli/menu/pages/maintenance-page.d.ts +4 -0
- package/dist/cli/menu/pages/maintenance-page.js +51 -8
- package/dist/cli/menu/remote-menu.d.ts +19 -0
- package/dist/cli/menu/remote-menu.js +108 -0
- package/dist/cli/menu/views.js +4 -0
- package/dist/cli/operations/handler.js +15 -1
- package/dist/cli/services/remote-client.d.ts +16 -0
- package/dist/cli/services/remote-client.js +141 -0
- package/dist/cli/services/sessions-service.d.ts +5 -0
- package/dist/cli/services/sessions-service.js +17 -1
- package/dist/core/config/defaults.js +12 -2
- package/dist/core/local-config/file.js +16 -2
- package/dist/core/local-config/overrides.js +7 -0
- package/dist/core/run/versions.js +9 -8
- package/dist/core/schema/apps.d.ts +9 -0
- package/dist/core/schema/apps.js +9 -0
- package/dist/core/schema/config.d.ts +23 -3
- package/dist/core/schema/config.js +42 -5
- package/dist/core/schema/sandbox.d.ts +1 -0
- package/dist/core/schema/sandbox.js +11 -3
- package/dist/core/schema/web.d.ts +51 -0
- package/dist/core/schema/web.js +46 -1
- package/dist/core/util/fs.d.ts +5 -0
- package/dist/core/util/fs.js +23 -0
- package/dist/core/util/index.d.ts +1 -1
- package/dist/core/util/index.js +1 -1
- package/dist/guest/apps/app-installer.js +50 -4
- package/dist/guest/apps/index.d.ts +1 -1
- package/dist/guest/apps/index.js +1 -1
- package/dist/guest/apps/sources.js +1 -1
- package/dist/guest/audit/parse.d.ts +32 -2
- package/dist/guest/audit/parse.js +43 -5
- package/dist/guest/audit/process-audit.d.ts +3 -1
- package/dist/guest/audit/process-audit.js +9 -6
- package/dist/guest/boot/boot.js +12 -3
- package/dist/guest/boot/guide.d.ts +1 -1
- package/dist/guest/boot/guide.js +27 -3
- package/dist/guest/daemon/daemon.js +2 -0
- package/dist/guest/daemon/idle-shutdown.js +2 -1
- package/dist/guest/daemon/sessions.d.ts +23 -2
- package/dist/guest/daemon/sessions.js +151 -20
- package/dist/guest/entries/daemon.js +2 -1
- package/dist/guest/git/decision.js +7 -0
- package/dist/guest/sessions/cmdline.d.ts +14 -0
- package/dist/guest/sessions/cmdline.js +10 -0
- package/dist/guest/setup/addon-mcp.d.ts +2 -0
- package/dist/guest/setup/addon-mcp.js +49 -0
- package/dist/guest/setup/agent-addons.d.ts +9 -0
- package/dist/guest/setup/agent-addons.js +22 -0
- package/dist/guest/setup/headroom.d.ts +7 -0
- package/dist/guest/setup/headroom.js +60 -0
- package/dist/guest/setup/managed-policy.d.ts +2 -1
- package/dist/guest/setup/managed-policy.js +15 -6
- package/dist/guest/toolchains/plan.js +8 -3
- package/dist/guest/toolchains/setup.js +3 -0
- package/dist/host/audit/attribute.d.ts +46 -0
- package/dist/host/audit/attribute.js +76 -0
- package/dist/host/audit/collect.d.ts +29 -3
- package/dist/host/audit/collect.js +256 -61
- package/dist/host/audit/git-commits.d.ts +29 -0
- package/dist/host/audit/git-commits.js +157 -0
- package/dist/host/audit/index.d.ts +5 -0
- package/dist/host/audit/index.js +6 -0
- package/dist/host/audit/log.d.ts +45 -7
- package/dist/host/audit/log.js +148 -45
- package/dist/host/audit/redact.d.ts +2 -0
- package/dist/host/audit/redact.js +67 -0
- package/dist/host/channel/channel.d.ts +5 -1
- package/dist/host/channel/channel.js +12 -0
- package/dist/host/guard/agent-files.js +7 -1
- package/dist/host/guard/commands.js +13 -1
- package/dist/host/guard/git-config.js +27 -7
- package/dist/host/guard/git-dirs.js +78 -3
- package/dist/host/guard/mark-of-the-web.js +3 -1
- package/dist/host/guard/nested-repos.js +7 -2
- package/dist/host/guard/store.js +1 -0
- package/dist/host/guard/types.d.ts +2 -0
- package/dist/host/launch/mappings.js +11 -1
- package/dist/host/launch/project-scan.js +2 -21
- package/dist/host/launch/stage.js +4 -0
- package/dist/host/life/session-ledger.js +2 -1
- package/dist/host/remote/access-store.d.ts +156 -0
- package/dist/host/remote/access-store.js +308 -0
- package/dist/host/remote/cert.d.ts +20 -0
- package/dist/host/remote/cert.js +103 -0
- package/dist/host/remote/door-client.d.ts +13 -0
- package/dist/host/remote/door-client.js +54 -0
- package/dist/host/remote/firewall.d.ts +44 -0
- package/dist/host/remote/firewall.js +118 -0
- package/dist/host/remote/gate.d.ts +125 -0
- package/dist/host/remote/gate.js +391 -0
- package/dist/host/remote/index.d.ts +8 -0
- package/dist/host/remote/index.js +10 -0
- package/dist/host/remote/lan.d.ts +24 -0
- package/dist/host/remote/lan.js +88 -0
- package/dist/host/remote/tls-store.d.ts +22 -0
- package/dist/host/remote/tls-store.js +63 -0
- package/dist/host/remote/windows-helper.d.ts +67 -0
- package/dist/host/remote/windows-helper.js +129 -0
- package/dist/host/web/bridge.d.ts +5 -1
- package/dist/host/web/bridge.js +6 -2
- package/dist/host/web/browser.js +1 -1
- package/dist/host/web/control.d.ts +4 -1
- package/dist/host/web/control.js +28 -4
- package/dist/host/web/rpc.d.ts +16 -2
- package/dist/host/web/rpc.js +37 -4
- package/dist/host/web/runner.d.ts +4 -0
- package/dist/host/web/runner.js +12 -0
- package/dist/host/web/server.d.ts +18 -2
- package/dist/host/web/server.js +97 -24
- package/dist/host/web/state.d.ts +5 -0
- package/dist/host/web/state.js +8 -0
- package/dist/runtime/agent.js +184 -18
- package/dist/runtime/daemon.js +772 -338
- package/dist/runtime/db.js +184 -18
- package/dist/runtime/gitguard.js +6 -0
- package/dist/runtime/main.js +966 -553
- package/dist/runtime/netproxy.js +184 -18
- package/dist/runtime/view.js +186 -18
- package/dist/selftest/app.test.js +66 -7
- package/dist/selftest/audit.test.js +354 -47
- package/dist/selftest/channel.test.js +16 -0
- package/dist/selftest/cmdline.test.js +16 -0
- package/dist/selftest/git-access.test.js +8 -0
- package/dist/selftest/hcs.test.js +35 -0
- package/dist/selftest/hostile-input.test.js +12 -1
- package/dist/selftest/index.js +2 -0
- package/dist/selftest/live-daemon.test.js +25 -0
- package/dist/selftest/local-config.test.js +30 -0
- package/dist/selftest/menu-screens.js +1 -1
- package/dist/selftest/menu.test.js +3 -3
- package/dist/selftest/remote.test.d.ts +2 -0
- package/dist/selftest/remote.test.js +536 -0
- package/dist/selftest/repo-guard.test.js +56 -2
- package/dist/selftest/resume.test.js +2 -1
- package/dist/selftest/sharing.test.js +9 -2
- package/dist/selftest/support/engine-golden.js +9 -0
- package/dist/selftest/support/fixtures.d.ts +14 -0
- package/dist/selftest/support/web-preview.js +157 -0
- package/dist/selftest/toolchains.test.js +147 -2
- package/dist/selftest/web.test.js +2 -0
- package/dist/shared/apps/agent-addons.d.ts +64 -0
- package/dist/shared/apps/agent-addons.js +95 -0
- package/dist/shared/apps/catalogue.d.ts +33 -2
- package/dist/shared/apps/catalogue.js +102 -11
- package/dist/shared/apps/index.d.ts +3 -2
- package/dist/shared/apps/index.js +3 -2
- package/dist/shared/apps/selection.d.ts +2 -0
- package/dist/shared/apps/selection.js +7 -0
- package/dist/shared/channel/schema.d.ts +23 -0
- package/dist/shared/channel/schema.js +8 -0
- package/dist/shared/pty/protocol.d.ts +2 -0
- package/dist/shared/pty/protocol.js +2 -0
- package/dist/sync/watcher.js +9 -1
- package/dist/web/index.html +2 -2
- package/dist/web/{main-RQFN4WBY.css → main-UAQPI5XD.css} +1 -1
- package/dist/web/main-Z2WYAE2Z.js +221 -0
- package/native/csharp/HcsHost/AssemblyInfo.cs +5 -3
- package/native/csharp/HcsHost/Hcs.cs +9 -0
- package/native/csharp/HcsHost/Program.cs +26 -1
- package/native/csharp/HcsHost/Share.cs +173 -0
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/Program.cs +17 -1
- package/native/csharp/HostTools/WebHelper.cs +499 -0
- package/native/scripts/get-network-profile.ps1 +19 -0
- package/native/scripts/set-folder-access.ps1 +11 -0
- package/native/scripts/set-web-firewall.ps1 +103 -0
- package/package.json +1 -1
- package/sandbox/addons/ccusage/package-lock.json +111 -0
- package/sandbox/addons/ccusage/package.json +7 -0
- package/sandbox/addons/context7/package-lock.json +1313 -0
- package/sandbox/addons/context7/package.json +7 -0
- package/sandbox/addons/headroom/requirements.in +1 -0
- package/sandbox/addons/headroom/requirements.txt +2922 -0
- package/sandbox/addons/playwright-mcp/package-lock.json +56 -0
- package/sandbox/addons/playwright-mcp/package.json +7 -0
- package/sandbox/csharp/PtyHost.cs +20 -0
- package/schemas/config.schema.json +78 -4
- package/schemas/sandbox-config.schema.json +2 -20
- package/dist/cli/commands/maintenance/audit.d.ts +0 -3
- package/dist/cli/commands/maintenance/audit.js +0 -58
- package/dist/web/main-K2JMCAZI.js +0 -219
|
@@ -9,18 +9,22 @@ import { changeDataFolder, containedOff, containedOn, containedStatus, moveStora
|
|
|
9
9
|
import { hideWindow, sandboxStatus, sandboxView, showWindow, stopSandbox } from './sandbox/sandbox.def.js';
|
|
10
10
|
import { addProject, allProjects, chooseProjects, excludeProject, includeProject, listProjects, projectRoots, projectsView, removeProject, } from './projects/projects.def.js';
|
|
11
11
|
import { listLogs, logsView, tailLog } from './logs/logs.def.js';
|
|
12
|
-
import {
|
|
12
|
+
import { auditView, listAudit } from './audit/audit.def.js';
|
|
13
|
+
import { closeSession, listSessions, restartSessions, sessionsView, startShell } from './sessions/sessions.def.js';
|
|
13
14
|
import { vpnLogin, vpnLogout, vpnStatus, vpnView } from './vpn/vpn.def.js';
|
|
14
15
|
import { githubLogin, githubLogout, githubStatus, githubView } from './github/github.def.js';
|
|
15
16
|
import { exportConfig, getSetting, importConfig, listSettings, resetSetting, setSetting, settingsView, } from './settings/settings.def.js';
|
|
16
17
|
import { migrateSettings, runUpdate, updatesStatus, updatesView } from './updates/updates.def.js';
|
|
17
18
|
import { openWeb, startWeb, stopWeb, webStatus, webView } from './web/web.def.js';
|
|
19
|
+
import { accessStatus, accessView, allowDevice, lanOff, lanOn, revokeAccess, revokeAllAccess, } from './access/access.def.js';
|
|
18
20
|
export const OPERATIONS = [
|
|
19
21
|
cleanEngine,
|
|
20
22
|
showWindow,
|
|
21
23
|
hideWindow,
|
|
22
24
|
stopSandbox,
|
|
23
25
|
restartSessions,
|
|
26
|
+
startShell,
|
|
27
|
+
closeSession,
|
|
24
28
|
startAgent,
|
|
25
29
|
addAgent,
|
|
26
30
|
makeDefaultAgent,
|
|
@@ -63,6 +67,11 @@ export const OPERATIONS = [
|
|
|
63
67
|
vpnLogout,
|
|
64
68
|
githubLogin,
|
|
65
69
|
githubLogout,
|
|
70
|
+
allowDevice,
|
|
71
|
+
revokeAccess,
|
|
72
|
+
revokeAllAccess,
|
|
73
|
+
lanOn,
|
|
74
|
+
lanOff,
|
|
66
75
|
];
|
|
67
76
|
export const QUERIES = [
|
|
68
77
|
sandboxStatus,
|
|
@@ -80,6 +89,7 @@ export const QUERIES = [
|
|
|
80
89
|
containedStatus,
|
|
81
90
|
listLogs,
|
|
82
91
|
tailLog,
|
|
92
|
+
listAudit,
|
|
83
93
|
updatesStatus,
|
|
84
94
|
engineStatus,
|
|
85
95
|
checkEngine,
|
|
@@ -87,6 +97,7 @@ export const QUERIES = [
|
|
|
87
97
|
webStatus,
|
|
88
98
|
vpnStatus,
|
|
89
99
|
githubStatus,
|
|
100
|
+
accessStatus,
|
|
90
101
|
];
|
|
91
102
|
export const VIEWS = [
|
|
92
103
|
sandboxView,
|
|
@@ -100,11 +111,13 @@ export const VIEWS = [
|
|
|
100
111
|
dataView,
|
|
101
112
|
storageView,
|
|
102
113
|
logsView,
|
|
114
|
+
auditView,
|
|
103
115
|
updatesView,
|
|
104
116
|
engineView,
|
|
105
117
|
webView,
|
|
106
118
|
vpnView,
|
|
107
119
|
githubView,
|
|
120
|
+
accessView,
|
|
108
121
|
];
|
|
109
122
|
export const DEFINITIONS = [...OPERATIONS, ...QUERIES];
|
|
110
123
|
export function definitionById(id) {
|
|
@@ -134,6 +147,7 @@ export function embeddingOf(nav, view) {
|
|
|
134
147
|
export const NAV = [
|
|
135
148
|
{ label: 'Agents', view: 'agents' },
|
|
136
149
|
{ label: 'Sessions', view: 'sessions' },
|
|
150
|
+
{ label: 'Activity', view: 'audit' },
|
|
137
151
|
{
|
|
138
152
|
label: 'Sandbox',
|
|
139
153
|
children: [
|
|
@@ -151,6 +165,7 @@ export const NAV = [
|
|
|
151
165
|
],
|
|
152
166
|
},
|
|
153
167
|
{ label: 'Accounts', view: 'accounts' },
|
|
168
|
+
{ label: 'Remote access', view: 'access' },
|
|
154
169
|
{
|
|
155
170
|
label: 'Maintenance',
|
|
156
171
|
children: [
|
|
@@ -22,6 +22,7 @@ export const FolderListingSchema = z.object({
|
|
|
22
22
|
});
|
|
23
23
|
export const browseFolder = defineQuery({
|
|
24
24
|
id: 'files.browse',
|
|
25
|
+
access: 'owner',
|
|
25
26
|
title: 'Browse folders',
|
|
26
27
|
summary: 'list what is in a folder of this PC, to pick a folder or a file',
|
|
27
28
|
input: z.object({
|
|
@@ -131,6 +131,7 @@ export const lastHealth = defineQuery({
|
|
|
131
131
|
});
|
|
132
132
|
export const checkHealth = defineOperation({
|
|
133
133
|
id: 'health.check',
|
|
134
|
+
access: 'control',
|
|
134
135
|
title: 'Check this PC',
|
|
135
136
|
summary: 'check this PC, the install, your settings and the sandbox (changes nothing)',
|
|
136
137
|
input: z.object({ harness: z.string().optional().describe('agent to check') }),
|
|
@@ -91,6 +91,7 @@ export const sandboxStatus = defineQuery({
|
|
|
91
91
|
});
|
|
92
92
|
export const showWindow = defineOperation({
|
|
93
93
|
id: 'sandbox.showWindow',
|
|
94
|
+
access: 'control',
|
|
94
95
|
title: 'Show the window',
|
|
95
96
|
summary: 'show the sandbox window',
|
|
96
97
|
input: z.object({}),
|
|
@@ -100,6 +101,7 @@ export const showWindow = defineOperation({
|
|
|
100
101
|
});
|
|
101
102
|
export const hideWindow = defineOperation({
|
|
102
103
|
id: 'sandbox.hideWindow',
|
|
104
|
+
access: 'control',
|
|
103
105
|
title: 'Hide the window',
|
|
104
106
|
summary: 'hide the sandbox window (it keeps running)',
|
|
105
107
|
input: z.object({}),
|
|
@@ -109,6 +111,7 @@ export const hideWindow = defineOperation({
|
|
|
109
111
|
});
|
|
110
112
|
export const stopSandbox = defineOperation({
|
|
111
113
|
id: 'sandbox.stop',
|
|
114
|
+
access: 'control',
|
|
112
115
|
title: 'Stop the sandbox…',
|
|
113
116
|
summary: "shut the sandbox down (every project's sessions end)",
|
|
114
117
|
input: z.object({}),
|
|
@@ -5,6 +5,10 @@ export declare const SessionRowSchema: z.ZodObject<{
|
|
|
5
5
|
id: z.ZodString;
|
|
6
6
|
launchId: z.ZodString;
|
|
7
7
|
harness: z.ZodString;
|
|
8
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
shell: "shell";
|
|
10
|
+
agent: "agent";
|
|
11
|
+
}>>;
|
|
8
12
|
cwd: z.ZodString;
|
|
9
13
|
project: z.ZodOptional<z.ZodString>;
|
|
10
14
|
phase: z.ZodEnum<{
|
|
@@ -36,6 +40,10 @@ export declare const SessionsListSchema: z.ZodObject<{
|
|
|
36
40
|
id: z.ZodString;
|
|
37
41
|
launchId: z.ZodString;
|
|
38
42
|
harness: z.ZodString;
|
|
43
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
44
|
+
shell: "shell";
|
|
45
|
+
agent: "agent";
|
|
46
|
+
}>>;
|
|
39
47
|
cwd: z.ZodString;
|
|
40
48
|
project: z.ZodOptional<z.ZodString>;
|
|
41
49
|
phase: z.ZodEnum<{
|
|
@@ -74,6 +82,10 @@ export declare const listSessions: import("../../kernel/define.js").QueryDef<z.Z
|
|
|
74
82
|
id: z.ZodString;
|
|
75
83
|
launchId: z.ZodString;
|
|
76
84
|
harness: z.ZodString;
|
|
85
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
86
|
+
shell: "shell";
|
|
87
|
+
agent: "agent";
|
|
88
|
+
}>>;
|
|
77
89
|
cwd: z.ZodString;
|
|
78
90
|
project: z.ZodOptional<z.ZodString>;
|
|
79
91
|
phase: z.ZodEnum<{
|
|
@@ -102,6 +114,26 @@ export declare const restartSessions: import("../../kernel/define.js").Operation
|
|
|
102
114
|
}, z.core.$strip>, z.ZodObject<{
|
|
103
115
|
message: z.ZodString;
|
|
104
116
|
}, z.core.$strip>, "sessions.restart">;
|
|
117
|
+
/** The shells a shell session can run; auto: PowerShell 7 when the sandbox has it, else Windows PowerShell. */
|
|
118
|
+
export declare const SHELL_CHOICES: readonly ["auto", "pwsh", "powershell", "cmd"];
|
|
119
|
+
export declare const startShell: import("../../kernel/define.js").OperationDef<z.ZodObject<{
|
|
120
|
+
project: z.ZodOptional<z.ZodString>;
|
|
121
|
+
shell: z.ZodDefault<z.ZodEnum<{
|
|
122
|
+
pwsh: "pwsh";
|
|
123
|
+
auto: "auto";
|
|
124
|
+
powershell: "powershell";
|
|
125
|
+
cmd: "cmd";
|
|
126
|
+
}>>;
|
|
127
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
128
|
+
session: z.ZodString;
|
|
129
|
+
shell: z.ZodString;
|
|
130
|
+
message: z.ZodString;
|
|
131
|
+
}, z.core.$strip>, "sessions.shell">;
|
|
132
|
+
export declare const closeSession: import("../../kernel/define.js").OperationDef<z.ZodObject<{
|
|
133
|
+
session: z.ZodString;
|
|
134
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
135
|
+
message: z.ZodString;
|
|
136
|
+
}, z.core.$strip>, "sessions.close">;
|
|
105
137
|
/** The sessions page: one list (a table on the command line), this folder's project first. */
|
|
106
138
|
export declare function sessionsPage(o: SessionsList): Page;
|
|
107
139
|
export declare const sessionsView: import("../../kernel/define.js").ViewDef<{
|
|
@@ -116,6 +148,10 @@ export declare const sessionsView: import("../../kernel/define.js").ViewDef<{
|
|
|
116
148
|
id: z.ZodString;
|
|
117
149
|
launchId: z.ZodString;
|
|
118
150
|
harness: z.ZodString;
|
|
151
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
152
|
+
shell: "shell";
|
|
153
|
+
agent: "agent";
|
|
154
|
+
}>>;
|
|
119
155
|
cwd: z.ZodString;
|
|
120
156
|
project: z.ZodOptional<z.ZodString>;
|
|
121
157
|
phase: z.ZodEnum<{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// The
|
|
2
|
-
// view; sessions.run.ts does the work. A running session links to
|
|
3
|
-
// in the web UI).
|
|
1
|
+
// The sessions of the running sandbox, agents and plain shells: the list (live), restarting the agents, opening a shell
|
|
2
|
+
// and closing a session. Pure: schemas, labels and the view; sessions.run.ts does the work. A running session links to
|
|
3
|
+
// its terminal (attach in the menu and on the command line, the terminal page in the web UI).
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { action, ago, defineOperation, defineQuery, defineView, link, } from '../../kernel/index.js';
|
|
6
6
|
const ViewersSchema = z.object({ viewers: z.number(), remote: z.number() });
|
|
@@ -8,7 +8,9 @@ const ViewersSchema = z.object({ viewers: z.number(), remote: z.number() });
|
|
|
8
8
|
export const SessionRowSchema = z.object({
|
|
9
9
|
id: z.string().describe('The session'),
|
|
10
10
|
launchId: z.string(),
|
|
11
|
-
harness: z.string().describe('The agent'),
|
|
11
|
+
harness: z.string().describe('The agent, or the shell (pwsh, powershell, cmd)'),
|
|
12
|
+
/** A plain shell rather than an agent (absent: an agent). */
|
|
13
|
+
kind: z.enum(['agent', 'shell']).optional(),
|
|
12
14
|
cwd: z.string().describe('Its folder in the sandbox'),
|
|
13
15
|
project: z.string().optional(),
|
|
14
16
|
phase: z.enum(['starting', 'running', 'exited', 'failed']).describe('What it is doing'),
|
|
@@ -50,7 +52,7 @@ export function orderedSessions(list) {
|
|
|
50
52
|
export const listSessions = defineQuery({
|
|
51
53
|
id: 'sessions.list',
|
|
52
54
|
title: 'Sessions',
|
|
53
|
-
summary: 'list
|
|
55
|
+
summary: 'list sessions (agents and shells) and who is attached',
|
|
54
56
|
input: z.object({ wide: z.boolean().default(false).describe("also show each session's folder") }),
|
|
55
57
|
output: SessionsListSchema,
|
|
56
58
|
live: { everyMs: 2500 },
|
|
@@ -65,6 +67,7 @@ export const listSessions = defineQuery({
|
|
|
65
67
|
});
|
|
66
68
|
export const restartSessions = defineOperation({
|
|
67
69
|
id: 'sessions.restart',
|
|
70
|
+
access: 'control',
|
|
68
71
|
title: 'Restart agents',
|
|
69
72
|
summary: "restart this project's running agents in place; they resume their conversation",
|
|
70
73
|
input: z.object({
|
|
@@ -82,19 +85,71 @@ export const restartSessions = defineOperation({
|
|
|
82
85
|
},
|
|
83
86
|
},
|
|
84
87
|
});
|
|
88
|
+
/** Agent and project names as the web UI has always accepted them. */
|
|
89
|
+
const NameText = z.string().regex(/^[A-Za-z0-9_.-]{1,64}$/);
|
|
90
|
+
const SessionId = z.string().regex(/^[A-Za-z0-9_-]{1,64}$/);
|
|
91
|
+
/** The shells a shell session can run; auto: PowerShell 7 when the sandbox has it, else Windows PowerShell. */
|
|
92
|
+
export const SHELL_CHOICES = ['auto', 'pwsh', 'powershell', 'cmd'];
|
|
93
|
+
/** The session the operation opened, as a link to its terminal. */
|
|
94
|
+
function openedSession(o) {
|
|
95
|
+
return { kind: 'terminal', session: o.session };
|
|
96
|
+
}
|
|
97
|
+
export const startShell = defineOperation({
|
|
98
|
+
id: 'sessions.shell',
|
|
99
|
+
title: 'New shell',
|
|
100
|
+
summary: 'open PowerShell or cmd in a project of the running sandbox, as a session you can attach to',
|
|
101
|
+
input: z.object({
|
|
102
|
+
project: NameText.optional().describe("The project of the running sandbox (default: this folder's, else asked)"),
|
|
103
|
+
shell: z
|
|
104
|
+
.enum(SHELL_CHOICES)
|
|
105
|
+
.default('auto')
|
|
106
|
+
.describe('The shell: pwsh, powershell or cmd (default: pwsh if present)'),
|
|
107
|
+
}),
|
|
108
|
+
output: z.object({
|
|
109
|
+
session: z.string().describe('The new session'),
|
|
110
|
+
shell: z.string().describe('The shell it runs'),
|
|
111
|
+
message: z.string().describe('What happened'),
|
|
112
|
+
}),
|
|
113
|
+
// A shell runs anything as you: someone you let in remotely may type into one you opened, never open one.
|
|
114
|
+
access: 'owner',
|
|
115
|
+
text: (o) => o.message,
|
|
116
|
+
opens: openedSession,
|
|
117
|
+
cli: {
|
|
118
|
+
name: 'shell',
|
|
119
|
+
group: 'Sessions',
|
|
120
|
+
positional: ['project'],
|
|
121
|
+
flags: { shell: { flag: '--shell', value: 'name', choices: ['pwsh', 'powershell', 'cmd'] } },
|
|
122
|
+
json: true,
|
|
123
|
+
examples: [
|
|
124
|
+
"sandbox shell PowerShell in this folder's project, in this terminal (Ctrl+] detaches)",
|
|
125
|
+
'sandbox shell api --shell cmd cmd in the project api',
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
export const closeSession = defineOperation({
|
|
130
|
+
id: 'sessions.close',
|
|
131
|
+
title: 'Close',
|
|
132
|
+
summary: 'end a running session (an agent or a shell) and every program it started',
|
|
133
|
+
input: z.object({ session: SessionId.describe('The session to close') }),
|
|
134
|
+
output: z.object({ message: z.string().describe("The sandbox's answer") }),
|
|
135
|
+
access: 'control',
|
|
136
|
+
danger: true,
|
|
137
|
+
text: (o) => o.message,
|
|
138
|
+
cli: { name: 'close', group: 'Sessions', positional: ['session'], examples: ['sandbox close 4f2c9a'] },
|
|
139
|
+
});
|
|
85
140
|
function sessionItem(s, wide) {
|
|
86
141
|
const state = s.phase + (s.exitCode !== undefined ? ' (' + s.exitCode + ')' : '');
|
|
87
142
|
const running = s.phase === 'running';
|
|
88
143
|
return {
|
|
89
144
|
id: s.id,
|
|
90
|
-
label: s.harness + ' ' + (s.projectName ?? '-'),
|
|
145
|
+
label: (s.kind === 'shell' ? s.harness + ' (shell)' : s.harness) + ' ' + (s.projectName ?? '-'),
|
|
91
146
|
hint: state + ' ' + ago(s.startedAt),
|
|
92
147
|
badges: [{ text: s.phase, tone: running ? 'ok' : s.phase === 'failed' ? 'danger' : 'muted' }],
|
|
93
148
|
group: s.here ? "This folder's project" : 'Other sessions',
|
|
94
149
|
marked: s.here,
|
|
95
150
|
icon: s.harness,
|
|
96
151
|
description: running
|
|
97
|
-
? "Opens this session's terminal (in a terminal, Ctrl+] detaches; the session keeps running)."
|
|
152
|
+
? "Opens this session's terminal (in a terminal, Ctrl+] detaches; the session keeps running). x closes it."
|
|
98
153
|
: undefined,
|
|
99
154
|
details: ['Session ' + s.id, 'Folder ' + s.cwd, 'Attached ' + viewerText(s.viewers)],
|
|
100
155
|
cells: {
|
|
@@ -108,6 +163,9 @@ function sessionItem(s, wide) {
|
|
|
108
163
|
started: ago(s.startedAt),
|
|
109
164
|
},
|
|
110
165
|
...(running && s.canOpen ? { primary: link({ kind: 'terminal', session: s.id }, 'Open', { verb: 'attach' }) } : {}),
|
|
166
|
+
...(running
|
|
167
|
+
? { actions: [action(closeSession, { session: s.id }, { key: 'x', verb: 'close', importance: 1 })] }
|
|
168
|
+
: {}),
|
|
111
169
|
...(running ? {} : { disabled: 'This session has ended.' }),
|
|
112
170
|
...(running && !s.canOpen ? { disabled: 'Not reachable from this PC.' } : {}),
|
|
113
171
|
};
|
|
@@ -150,6 +208,16 @@ export function sessionsPage(o) {
|
|
|
150
208
|
],
|
|
151
209
|
actions: [
|
|
152
210
|
...(o.sandboxRunning ? [{ ...start, label: 'New session', key: 'n', verb: 'new session', importance: 1 }] : []),
|
|
211
|
+
...(o.sandboxRunning
|
|
212
|
+
? [
|
|
213
|
+
action(startShell, { shell: 'auto' }, {
|
|
214
|
+
key: 's',
|
|
215
|
+
verb: 'new shell',
|
|
216
|
+
importance: 1,
|
|
217
|
+
description: 'Opens PowerShell in a project of the sandbox, as a session like the agents.',
|
|
218
|
+
}),
|
|
219
|
+
]
|
|
220
|
+
: []),
|
|
153
221
|
...(sessions.length
|
|
154
222
|
? [action(restartSessions, { all: false }, { key: 'r', verb: 'restart agents', importance: 1 })]
|
|
155
223
|
: []),
|
|
@@ -172,8 +240,8 @@ export function sessionsPage(o) {
|
|
|
172
240
|
export const sessionsView = defineView({
|
|
173
241
|
id: 'sessions',
|
|
174
242
|
title: 'Sessions',
|
|
175
|
-
summary: 'The
|
|
243
|
+
summary: 'The sessions of the running sandbox: open one, restart the agents, open a shell, close one.',
|
|
176
244
|
queries: { sessions: listSessions },
|
|
177
|
-
operations: [restartSessions],
|
|
245
|
+
operations: [restartSessions, startShell, closeSession],
|
|
178
246
|
build: ({ sessions }) => sessionsPage(sessions),
|
|
179
247
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Context } from '../../../cli/commands/context.js';
|
|
1
2
|
export declare const listSessionsRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").QueryDef<import("zod").ZodObject<{
|
|
2
3
|
wide: import("zod").ZodDefault<import("zod").ZodBoolean>;
|
|
3
4
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
@@ -9,6 +10,10 @@ export declare const listSessionsRun: import("../../kernel/define.js").Implement
|
|
|
9
10
|
id: import("zod").ZodString;
|
|
10
11
|
launchId: import("zod").ZodString;
|
|
11
12
|
harness: import("zod").ZodString;
|
|
13
|
+
kind: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
14
|
+
shell: "shell";
|
|
15
|
+
agent: "agent";
|
|
16
|
+
}>>;
|
|
12
17
|
cwd: import("zod").ZodString;
|
|
13
18
|
project: import("zod").ZodOptional<import("zod").ZodString>;
|
|
14
19
|
phase: import("zod").ZodEnum<{
|
|
@@ -30,10 +35,28 @@ export declare const listSessionsRun: import("../../kernel/define.js").Implement
|
|
|
30
35
|
}, import("zod/v4/core").$strip>>>;
|
|
31
36
|
canOpen: import("zod").ZodBoolean;
|
|
32
37
|
}, import("zod/v4/core").$strip>>;
|
|
33
|
-
}, import("zod/v4/core").$strip>, "sessions.list">,
|
|
38
|
+
}, import("zod/v4/core").$strip>, "sessions.list">, Context>;
|
|
34
39
|
export declare const restartSessionsRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{
|
|
35
40
|
harness: import("zod").ZodOptional<import("zod").ZodString>;
|
|
36
41
|
all: import("zod").ZodDefault<import("zod").ZodBoolean>;
|
|
37
42
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
38
43
|
message: import("zod").ZodString;
|
|
39
|
-
}, import("zod/v4/core").$strip>, "sessions.restart">,
|
|
44
|
+
}, import("zod/v4/core").$strip>, "sessions.restart">, Context>;
|
|
45
|
+
export declare const startShellRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{
|
|
46
|
+
project: import("zod").ZodOptional<import("zod").ZodString>;
|
|
47
|
+
shell: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
48
|
+
pwsh: "pwsh";
|
|
49
|
+
auto: "auto";
|
|
50
|
+
powershell: "powershell";
|
|
51
|
+
cmd: "cmd";
|
|
52
|
+
}>>;
|
|
53
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
54
|
+
session: import("zod").ZodString;
|
|
55
|
+
shell: import("zod").ZodString;
|
|
56
|
+
message: import("zod").ZodString;
|
|
57
|
+
}, import("zod/v4/core").$strip>, "sessions.shell">, Context>;
|
|
58
|
+
export declare const closeSessionRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{
|
|
59
|
+
session: import("zod").ZodString;
|
|
60
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
61
|
+
message: import("zod").ZodString;
|
|
62
|
+
}, import("zod/v4/core").$strip>, "sessions.close">, Context>;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
// The sessions feature's work: the list (as this user may see it under the sharing rules)
|
|
2
|
-
|
|
1
|
+
// The sessions feature's work: the list (as this user may see it under the sharing rules), restarting the agents,
|
|
2
|
+
// opening a shell in a project of the running sandbox and closing a session.
|
|
3
|
+
import { fail, safeText } from '../../../core/util/index.js';
|
|
4
|
+
import { RunDir } from '../../../shared/channel/index.js';
|
|
3
5
|
import { hostEndpoint } from '../../../host/channel/index.js';
|
|
4
6
|
import { isSandboxRunning } from '../../../host/sandbox/index.js';
|
|
5
7
|
import { requireOnPc, requireRunning } from '../../../cli/commands/context.js';
|
|
8
|
+
import { locateHere } from '../../../cli/commands/projects/here.js';
|
|
6
9
|
import { lookAtSandbox, useSharedSandbox } from '../../../cli/commands/shared-use.js';
|
|
7
10
|
import { SessionsService } from '../../../cli/services/index.js';
|
|
11
|
+
import { runningProjects } from '../../../cli/services/web-service.js';
|
|
8
12
|
import { implement, typedConfirm } from '../../context.js';
|
|
9
13
|
import { cancelled } from '../../kernel/index.js';
|
|
10
|
-
import { listSessions, restartSessions } from './sessions.def.js';
|
|
14
|
+
import { closeSession, listSessions, restartSessions, startShell } from './sessions.def.js';
|
|
11
15
|
/** A listed session as the surfaces see it: no attach address or token, text from the sandbox made safe. */
|
|
12
16
|
function sessionRow(s) {
|
|
13
17
|
const { attach: _attach, ...rest } = s;
|
|
@@ -56,3 +60,67 @@ export const restartSessionsRun = implement(restartSessions, async (ctx, input,
|
|
|
56
60
|
io.progress('Restarting the agents' + (scope.guest ? ' of ' + scope.projectName : ''));
|
|
57
61
|
return { message: safeText(await service.restart(input.harness ?? null, scope.guest)) };
|
|
58
62
|
});
|
|
63
|
+
/** Where a new shell opens: the project named, else the one of the current folder, else the only one, else asked. */
|
|
64
|
+
async function shellPlace(ctx, project, io) {
|
|
65
|
+
const projects = runningProjects({ ctx, line: null, limited: false, owner: null });
|
|
66
|
+
if (project !== undefined) {
|
|
67
|
+
const named = projects.find((p) => p.name.toLowerCase() === project.toLowerCase());
|
|
68
|
+
if (!named)
|
|
69
|
+
fail('The running sandbox has no project "' + project + '".', 'sandbox status lists its projects.');
|
|
70
|
+
return { name: named.name, guest: named.guest };
|
|
71
|
+
}
|
|
72
|
+
const here = locateHere(ctx, new RunDir(ctx.dataPath).readSandboxStatus());
|
|
73
|
+
if (here.guestDir)
|
|
74
|
+
return { name: here.project?.name, guest: here.guestDir };
|
|
75
|
+
if (!projects.length)
|
|
76
|
+
fail('The running sandbox has no projects.');
|
|
77
|
+
if (projects.length === 1)
|
|
78
|
+
return projects[0];
|
|
79
|
+
const chosen = await io.choose({
|
|
80
|
+
title: 'Which project?',
|
|
81
|
+
choices: projects.map((p) => ({ value: p.name, label: p.name, description: p.guest })),
|
|
82
|
+
});
|
|
83
|
+
const picked = projects.find((p) => p.name === chosen);
|
|
84
|
+
if (!picked)
|
|
85
|
+
cancelled();
|
|
86
|
+
return picked;
|
|
87
|
+
}
|
|
88
|
+
export const startShellRun = implement(startShell, async (asked, input, io) => {
|
|
89
|
+
requireOnPc('shell');
|
|
90
|
+
requireRunning();
|
|
91
|
+
const ctx = await useSharedSandbox(asked, { kind: 'use' }, typedConfirm(io));
|
|
92
|
+
const place = await shellPlace(ctx, input.project, io);
|
|
93
|
+
io.progress('Opening ' + (input.shell === 'auto' ? 'a shell' : input.shell) + ' in ' + (place.name ?? place.guest));
|
|
94
|
+
const session = await new SessionsService(ctx).openShell(input.shell, place.guest);
|
|
95
|
+
const shell = safeText(session.harness);
|
|
96
|
+
return {
|
|
97
|
+
session: safeText(session.id),
|
|
98
|
+
shell,
|
|
99
|
+
message: 'Opened ' + shell + ' in ' + safeText(place.name ?? place.guest) + ' (session ' + safeText(session.id) + ').',
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
export const closeSessionRun = implement(closeSession, async (asked, input, io) => {
|
|
103
|
+
requireOnPc('close');
|
|
104
|
+
requireRunning();
|
|
105
|
+
const find = (ctx) => new SessionsService(ctx).running(null).find((s) => s.id === input.session);
|
|
106
|
+
// Anyone the sandbox is shared with may close a shell; an agent session is its owner's to end.
|
|
107
|
+
const ctx = await useSharedSandbox(asked, (shared) => find(shared)?.kind === 'shell' ? { kind: 'use' } : { kind: 'owner-only', what: 'close an agent session' }, typedConfirm(io));
|
|
108
|
+
const session = find(ctx);
|
|
109
|
+
if (!session)
|
|
110
|
+
fail('No running session ' + input.session + '.', 'sandbox sessions lists the running ones.');
|
|
111
|
+
const what = safeText(session.harness) + (session.kind === 'shell' ? ' (shell)' : '');
|
|
112
|
+
const yes = await io.confirm({
|
|
113
|
+
title: 'Close ' + what + ' session ' + input.session + '?',
|
|
114
|
+
lines: [
|
|
115
|
+
'It ends, with every program it started.' +
|
|
116
|
+
(session.kind === 'shell' ? '' : ' The agent can pick its conversation up again in a new session.'),
|
|
117
|
+
],
|
|
118
|
+
yes: 'Close',
|
|
119
|
+
danger: true,
|
|
120
|
+
implied: true,
|
|
121
|
+
});
|
|
122
|
+
if (!yes)
|
|
123
|
+
cancelled();
|
|
124
|
+
io.progress('Closing session ' + input.session);
|
|
125
|
+
return { message: safeText(await new SessionsService(ctx).close(input.session)) };
|
|
126
|
+
});
|
|
@@ -94,6 +94,14 @@ export declare const getSetting: import("../../kernel/define.js").QueryDef<z.Zod
|
|
|
94
94
|
key: z.ZodString;
|
|
95
95
|
value: z.ZodUnknown;
|
|
96
96
|
}, z.core.$strip>, "settings.get">;
|
|
97
|
+
/**
|
|
98
|
+
* The settings someone with control (not the owner) may change: how attaching and reopening sessions behave, in your
|
|
99
|
+
* own settings file. Everything else (folders, agents, secrets, network, storage, sharing, the audit log, remote
|
|
100
|
+
* access) changes what the sandbox can reach or who can come in, so it is the owner's (docs/design/remote-access.md).
|
|
101
|
+
*/
|
|
102
|
+
export declare const CONTROL_SETTINGS: readonly string[];
|
|
103
|
+
/** settings.set / settings.reset: control for CONTROL_SETTINGS in the user file, owner for everything else. */
|
|
104
|
+
export declare function controlSettingAccess(input: unknown): 'control' | 'owner';
|
|
97
105
|
export declare const setSetting: import("../../kernel/define.js").OperationDef<z.ZodObject<{
|
|
98
106
|
scope: z.ZodDefault<z.ZodEnum<{
|
|
99
107
|
project: "project";
|
|
@@ -65,8 +65,24 @@ export const getSetting = defineQuery({
|
|
|
65
65
|
surfaces: { except: { menu: 'Settings shows every value', web: 'the Settings page shows every value' } },
|
|
66
66
|
cli: { name: 'config', action: 'get', positional: ['key'] },
|
|
67
67
|
});
|
|
68
|
+
/**
|
|
69
|
+
* The settings someone with control (not the owner) may change: how attaching and reopening sessions behave, in your
|
|
70
|
+
* own settings file. Everything else (folders, agents, secrets, network, storage, sharing, the audit log, remote
|
|
71
|
+
* access) changes what the sandbox can reach or who can come in, so it is the owner's (docs/design/remote-access.md).
|
|
72
|
+
*/
|
|
73
|
+
export const CONTROL_SETTINGS = ['attach.', 'resume.'];
|
|
74
|
+
/** settings.set / settings.reset: control for CONTROL_SETTINGS in the user file, owner for everything else. */
|
|
75
|
+
export function controlSettingAccess(input) {
|
|
76
|
+
const o = (input ?? {});
|
|
77
|
+
const key = typeof o.key === 'string' ? o.key : '';
|
|
78
|
+
const userFile = o.scope === undefined || o.scope === 'user';
|
|
79
|
+
return userFile && CONTROL_SETTINGS.some((prefix) => key.startsWith(prefix) && key.length > prefix.length)
|
|
80
|
+
? 'control'
|
|
81
|
+
: 'owner';
|
|
82
|
+
}
|
|
68
83
|
export const setSetting = defineOperation({
|
|
69
84
|
id: 'settings.set',
|
|
85
|
+
access: controlSettingAccess,
|
|
70
86
|
title: 'Change a setting',
|
|
71
87
|
summary: 'change one setting (text is read like the command line: true/on, numbers, JSON)',
|
|
72
88
|
input: z.object({
|
|
@@ -80,6 +96,7 @@ export const setSetting = defineOperation({
|
|
|
80
96
|
});
|
|
81
97
|
export const resetSetting = defineOperation({
|
|
82
98
|
id: 'settings.reset',
|
|
99
|
+
access: controlSettingAccess,
|
|
83
100
|
title: 'Reset a setting',
|
|
84
101
|
summary: 'put one setting back to its default (in a project file: remove it)',
|
|
85
102
|
input: z.object({ scope: ScopeSchema.default('user'), key: KeySchema }),
|
|
@@ -45,6 +45,9 @@ export declare const getSettingRun: import("../../kernel/define.js").Implementat
|
|
|
45
45
|
key: import("zod").ZodString;
|
|
46
46
|
value: import("zod").ZodUnknown;
|
|
47
47
|
}, import("zod/v4/core").$strip>, "settings.get">, import("../../../cli/commands/context.js").Context>;
|
|
48
|
+
/** The file of a scope, and the setting a key names in it. */
|
|
49
|
+
/** incoming with every *** that stands where saved has a text replaced by that saved text. Pure. */
|
|
50
|
+
export declare function keepShownSecrets(saved: unknown, incoming: unknown): unknown;
|
|
48
51
|
export declare const setSettingRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{
|
|
49
52
|
scope: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
50
53
|
project: "project";
|
|
@@ -4,7 +4,7 @@ import fs from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import _ from 'lodash';
|
|
6
6
|
import { loadConfig } from '../../../core/config/index.js';
|
|
7
|
-
import { redactSecrets } from '../../../core/schema/index.js';
|
|
7
|
+
import { REDACTED, redactSecrets } from '../../../core/schema/index.js';
|
|
8
8
|
import { fail, safeText, writeJson } from '../../../core/util/index.js';
|
|
9
9
|
import { hereDir } from '../../../cli/commands/projects/here.js';
|
|
10
10
|
import { implement } from '../../context.js';
|
|
@@ -50,6 +50,18 @@ export const getSettingRun = implement(getSetting, (ctx, input) => {
|
|
|
50
50
|
return { key: input.key, value: _.get(redactSecrets(file.userConfig()), key) };
|
|
51
51
|
});
|
|
52
52
|
/** The file of a scope, and the setting a key names in it. */
|
|
53
|
+
/** incoming with every *** that stands where saved has a text replaced by that saved text. Pure. */
|
|
54
|
+
export function keepShownSecrets(saved, incoming) {
|
|
55
|
+
if (incoming === REDACTED)
|
|
56
|
+
return typeof saved === 'string' ? saved : incoming;
|
|
57
|
+
if (Array.isArray(incoming))
|
|
58
|
+
return incoming.map((v, i) => keepShownSecrets(Array.isArray(saved) ? saved[i] : undefined, v));
|
|
59
|
+
if (incoming && typeof incoming === 'object') {
|
|
60
|
+
const from = saved && typeof saved === 'object' && !Array.isArray(saved) ? saved : {};
|
|
61
|
+
return Object.fromEntries(Object.entries(incoming).map(([k, v]) => [k, keepShownSecrets(from[k], v)]));
|
|
62
|
+
}
|
|
63
|
+
return incoming;
|
|
64
|
+
}
|
|
53
65
|
function target(ctx, scope, name) {
|
|
54
66
|
const file = settingsFiles(ctx)[scope];
|
|
55
67
|
return { ...findSetting(file, name), file };
|
|
@@ -58,7 +70,9 @@ export const setSettingRun = implement(setSetting, (ctx, input) => {
|
|
|
58
70
|
const { key, node, file } = target(ctx, input.scope, input.key);
|
|
59
71
|
if (node.isSection)
|
|
60
72
|
fail('"' + input.key + '" is a group of settings.', 'Set one of them, e.g. ' + node.leaves(key)[0]?.key.join('.'));
|
|
61
|
-
|
|
73
|
+
// A value that comes back with *** where a secret was shown (the web edits a whole map of secrets) keeps what is
|
|
74
|
+
// saved there: *** is how secrets are shown, never a value to save.
|
|
75
|
+
const value = keepShownSecrets(file.valueInFile(key), valueFor(node, input.value));
|
|
62
76
|
const problem = node.check(value);
|
|
63
77
|
if (problem !== true) {
|
|
64
78
|
const typed = typeof input.value === 'string' ? input.value : JSON.stringify(masked(key, input.value));
|
|
@@ -4,12 +4,18 @@ export declare const WebStatusSchema: z.ZodObject<{
|
|
|
4
4
|
running: z.ZodBoolean;
|
|
5
5
|
port: z.ZodNullable<z.ZodNumber>;
|
|
6
6
|
address: z.ZodNullable<z.ZodString>;
|
|
7
|
+
lanAddress: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
8
|
+
lanFingerprint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
9
|
+
lanProblem: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
7
10
|
}, z.core.$strip>;
|
|
8
11
|
export type WebStatus = z.output<typeof WebStatusSchema>;
|
|
9
12
|
export declare const webStatus: import("../../kernel/define.js").QueryDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
10
13
|
running: z.ZodBoolean;
|
|
11
14
|
port: z.ZodNullable<z.ZodNumber>;
|
|
12
15
|
address: z.ZodNullable<z.ZodString>;
|
|
16
|
+
lanAddress: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
17
|
+
lanFingerprint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
18
|
+
lanProblem: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
13
19
|
}, z.core.$strip>, "web.status">;
|
|
14
20
|
export declare const startWeb: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
15
21
|
port: z.ZodNumber;
|
|
@@ -29,5 +35,8 @@ export declare const webView: import("../../kernel/define.js").ViewDef<{
|
|
|
29
35
|
running: z.ZodBoolean;
|
|
30
36
|
port: z.ZodNullable<z.ZodNumber>;
|
|
31
37
|
address: z.ZodNullable<z.ZodString>;
|
|
38
|
+
lanAddress: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
39
|
+
lanFingerprint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
40
|
+
lanProblem: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
32
41
|
}, z.core.$strip>, "web.status">;
|
|
33
42
|
}, Record<string, never>, "web">;
|
|
@@ -8,6 +8,13 @@ export const WebStatusSchema = z.object({
|
|
|
8
8
|
running: z.boolean().describe('The web UI server answers'),
|
|
9
9
|
port: z.number().nullable().describe('Its port on 127.0.0.1, when it runs'),
|
|
10
10
|
address: z.string().nullable().describe('Its address (without the login token), when it runs'),
|
|
11
|
+
lanAddress: z
|
|
12
|
+
.string()
|
|
13
|
+
.nullable()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Its address on your network for paired devices (LAN mode), when it listens there'),
|
|
16
|
+
lanFingerprint: z.string().nullable().optional().describe("The LAN certificate's SHA-256 fingerprint"),
|
|
17
|
+
lanProblem: z.string().nullable().optional().describe('Why LAN mode is on but not listening'),
|
|
11
18
|
});
|
|
12
19
|
const MessageSchema = z.object({ message: z.string().describe('What happened') });
|
|
13
20
|
export const webStatus = defineQuery({
|
|
@@ -18,7 +25,11 @@ export const webStatus = defineQuery({
|
|
|
18
25
|
output: WebStatusSchema,
|
|
19
26
|
surfaces: NOT_ON_WEB,
|
|
20
27
|
text: (o) => o.running && o.port
|
|
21
|
-
? 'The web UI is running at http://127.0.0.1:' +
|
|
28
|
+
? 'The web UI is running at http://127.0.0.1:' +
|
|
29
|
+
o.port +
|
|
30
|
+
'/ (sandbox web open signs you in).' +
|
|
31
|
+
(o.lanAddress ? '\nOn your network: ' + o.lanAddress + ' (certificate ' + o.lanFingerprint + ')' : '') +
|
|
32
|
+
(o.lanProblem ? '\nLAN mode is on but not listening: ' + o.lanProblem : '')
|
|
22
33
|
: 'The web UI is not running (sandbox web start).',
|
|
23
34
|
cli: { name: 'web', action: 'status', json: true },
|
|
24
35
|
});
|
|
@@ -73,6 +84,20 @@ export function webPage(o) {
|
|
|
73
84
|
tone: o.running ? 'ok' : 'muted',
|
|
74
85
|
},
|
|
75
86
|
...(o.address ? [{ id: 'address', label: 'Address', value: o.address + ' (this PC only)' }] : []),
|
|
87
|
+
...(o.lanAddress
|
|
88
|
+
? [
|
|
89
|
+
{
|
|
90
|
+
id: 'lan',
|
|
91
|
+
label: 'On your network',
|
|
92
|
+
value: o.lanAddress,
|
|
93
|
+
description: 'Type this into the phone, then enter the code from Remote access > Allow a new device.',
|
|
94
|
+
details: o.lanFingerprint ? ['Certificate ' + o.lanFingerprint] : undefined,
|
|
95
|
+
},
|
|
96
|
+
]
|
|
97
|
+
: []),
|
|
98
|
+
...(o.lanProblem
|
|
99
|
+
? [{ id: 'lan-problem', label: 'LAN mode', value: o.lanProblem, tone: 'warn' }]
|
|
100
|
+
: []),
|
|
76
101
|
],
|
|
77
102
|
actions: o.running ? [open, stop] : [start, open],
|
|
78
103
|
notes: [{ text: 'Loopback only, behind a token. Open signs you in.', tone: 'muted' }],
|