@cjhyy/code-shell-server 0.9.21 → 0.9.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +45 -1
  2. package/dist/bin/code-shell-settings-recovery.d.ts +2 -0
  3. package/dist/bin/code-shell-settings-recovery.js +4 -0
  4. package/dist/desktop-web/http-api.js +14 -0
  5. package/dist/environment-identity.d.ts +4 -0
  6. package/dist/environment-identity.js +67 -0
  7. package/dist/hub/auth-store.d.ts +2 -0
  8. package/dist/hub/auth-store.js +7 -0
  9. package/dist/index.auth.d.ts +3 -0
  10. package/dist/index.auth.js +2 -0
  11. package/dist/index.links.d.ts +1 -0
  12. package/dist/index.links.js +1 -0
  13. package/dist/index.panels.d.ts +7 -0
  14. package/dist/index.panels.js +7 -0
  15. package/dist/index.remote-relay.d.ts +5 -0
  16. package/dist/index.remote-relay.js +6 -0
  17. package/dist/index.serve.d.ts +2 -0
  18. package/dist/index.serve.js +2 -0
  19. package/dist/links/http.d.ts +3 -0
  20. package/dist/links/http.js +11 -2
  21. package/dist/links/remote-configuration.d.ts +4 -0
  22. package/dist/links/remote-configuration.js +32 -0
  23. package/dist/links/service.d.ts +6 -1
  24. package/dist/links/service.js +241 -19
  25. package/dist/mobile-remote/mobile-upload-service.d.ts +4 -0
  26. package/dist/mobile-remote/mobile-upload-service.js +69 -11
  27. package/dist/mobile-remote/remote-host-manager.d.ts +10 -5
  28. package/dist/mobile-remote/remote-host-manager.js +53 -5
  29. package/dist/panels/agent-task-service.js +9 -2
  30. package/dist/panels/automations.d.ts +49 -0
  31. package/dist/panels/automations.js +134 -0
  32. package/dist/panels/bridge-contract.d.ts +5 -3
  33. package/dist/panels/bridge-contract.js +11 -1
  34. package/dist/panels/directory-bookmarks.d.ts +9 -1
  35. package/dist/panels/directory-bookmarks.js +64 -5
  36. package/dist/panels/execution-gate.d.ts +26 -0
  37. package/dist/panels/execution-gate.js +70 -0
  38. package/dist/panels/http.d.ts +26 -2
  39. package/dist/panels/http.js +7 -1
  40. package/dist/panels/hub-automations.d.ts +31 -0
  41. package/dist/panels/hub-automations.js +352 -0
  42. package/dist/panels/management-http.d.ts +20 -2
  43. package/dist/panels/management-http.js +15 -2
  44. package/dist/panels/management.d.ts +26 -4
  45. package/dist/panels/management.js +382 -39
  46. package/dist/panels/package-mutation.d.ts +8 -0
  47. package/dist/panels/package-mutation.js +23 -0
  48. package/dist/panels/process-service.d.ts +3 -0
  49. package/dist/panels/process-service.js +77 -4
  50. package/dist/panels/resources/http.d.ts +11 -0
  51. package/dist/panels/resources/http.js +74 -0
  52. package/dist/panels/resources/references.d.ts +5 -0
  53. package/dist/panels/resources/references.js +26 -0
  54. package/dist/panels/runtime-services.js +16 -3
  55. package/dist/panels/runtime.d.ts +16 -4
  56. package/dist/panels/runtime.js +522 -64
  57. package/dist/panels/shared-tool-jobs.d.ts +40 -0
  58. package/dist/panels/shared-tool-jobs.js +37 -0
  59. package/dist/panels/storage-store.d.ts +21 -0
  60. package/dist/panels/storage-store.js +43 -0
  61. package/dist/panels/task-cookie-host.d.ts +26 -0
  62. package/dist/panels/task-cookie-host.js +145 -0
  63. package/dist/panels/task-cookies.d.ts +51 -0
  64. package/dist/panels/task-cookies.js +183 -0
  65. package/dist/panels/tool-executor.d.ts +21 -5
  66. package/dist/panels/tool-executor.js +171 -30
  67. package/dist/panels/tool-jobs-storage.d.ts +2 -0
  68. package/dist/panels/tool-jobs-storage.js +34 -0
  69. package/dist/panels/tool-jobs.d.ts +49 -3
  70. package/dist/panels/tool-jobs.js +270 -15
  71. package/dist/panels/types.d.ts +43 -0
  72. package/dist/project-runtime/backup.d.ts +26 -0
  73. package/dist/project-runtime/backup.js +500 -0
  74. package/dist/project-runtime/control-server.d.ts +4 -0
  75. package/dist/project-runtime/control-server.js +19 -1
  76. package/dist/project-runtime/docker-provider.d.ts +4 -0
  77. package/dist/project-runtime/docker-provider.js +16 -1
  78. package/dist/project-runtime/managed-entry.js +4 -0
  79. package/dist/project-runtime/registry.d.ts +2 -0
  80. package/dist/project-runtime/registry.js +15 -0
  81. package/dist/project-runtime/seccomp.d.ts +8 -0
  82. package/dist/project-runtime/seccomp.js +72 -0
  83. package/dist/project-runtime/types.d.ts +2 -0
  84. package/dist/remote-relay/byte-stream.d.ts +9 -0
  85. package/dist/remote-relay/byte-stream.js +71 -0
  86. package/dist/remote-relay/connector.d.ts +27 -0
  87. package/dist/remote-relay/connector.js +197 -0
  88. package/dist/remote-relay/local-stream.d.ts +10 -0
  89. package/dist/remote-relay/local-stream.js +120 -0
  90. package/dist/remote-relay/protocol.d.ts +39 -0
  91. package/dist/remote-relay/protocol.js +64 -0
  92. package/dist/serve/automation-worker.d.ts +16 -0
  93. package/dist/serve/automation-worker.js +126 -0
  94. package/dist/serve/cli.d.ts +3 -0
  95. package/dist/serve/cli.js +17 -0
  96. package/dist/serve/headless-server.d.ts +3 -0
  97. package/dist/serve/headless-server.js +140 -10
  98. package/dist/serve/settings-recovery-cli.d.ts +29 -0
  99. package/dist/serve/settings-recovery-cli.js +128 -0
  100. package/dist/session-http-responses.d.ts +7 -0
  101. package/dist/session-http-responses.js +40 -0
  102. package/dist/worker-bridge-core.d.ts +9 -1
  103. package/dist/worker-bridge-core.js +45 -0
  104. package/package.json +15 -6
@@ -0,0 +1,128 @@
1
+ import { parseArgs } from "node:util";
2
+ const HELP = `Usage: code-shell-settings-recovery <inspect|repair|restore> [options]
3
+
4
+ Offline administrator recovery for a stopped project's settings.
5
+ Stop the project and all its workers before repair or restore.
6
+ This command does not start a server, authenticate remote users or stop workers.
7
+
8
+ Options:
9
+ --project <directory> Actual project directory (default: current directory)
10
+ --scope <project|local> Configuration layer (default: project)
11
+ --from <file> Complete reviewed JSON candidate (inspect or repair)
12
+ --expected-revision <sha256> Revision returned by inspect (repair or restore)
13
+ --candidate-sha256 <sha256> Candidate hash returned by inspect (repair)
14
+ --backup-id <id> Backup returned by repair/restore (restore)
15
+ -h, --help Show this help without reading configuration
16
+
17
+ Inspection reports metadata and hashes, never configuration values.
18
+ Repair preserves original bytes before replacement. Restore also backs up current
19
+ bytes; restoring a damaged original restores that fault too. Keep backups private.
20
+ `;
21
+ export function parseSettingsRecoveryArgs(argv, cwd) {
22
+ const invalid = () => new Error("Invalid recovery arguments; use --help for usage.");
23
+ let parsed;
24
+ try {
25
+ parsed = parseArgs({
26
+ args: argv,
27
+ strict: true,
28
+ allowPositionals: true,
29
+ tokens: true,
30
+ options: {
31
+ project: { type: "string" },
32
+ scope: { type: "string" },
33
+ from: { type: "string" },
34
+ "expected-revision": { type: "string" },
35
+ "candidate-sha256": { type: "string" },
36
+ "backup-id": { type: "string" },
37
+ help: { type: "boolean", short: "h" },
38
+ },
39
+ });
40
+ }
41
+ catch {
42
+ // Parser errors can reflect unrecognized argument values. Do not echo them.
43
+ throw invalid();
44
+ }
45
+ const { values, positionals, tokens } = parsed;
46
+ const names = new Set();
47
+ for (const token of tokens ?? []) {
48
+ if (token.kind !== "option")
49
+ continue;
50
+ if (names.has(token.name))
51
+ throw invalid();
52
+ names.add(token.name);
53
+ }
54
+ const action = positionals[0];
55
+ if (positionals.length > 1 || (action && !["inspect", "repair", "restore"].includes(action)))
56
+ throw invalid();
57
+ if (values.help)
58
+ return { action: "help" };
59
+ if (!action)
60
+ throw invalid();
61
+ const allowed = new Set(["project", "scope"]);
62
+ if (action === "inspect" || action === "repair")
63
+ allowed.add("from");
64
+ if (action !== "inspect")
65
+ allowed.add("expected-revision");
66
+ if (action === "repair")
67
+ allowed.add("candidate-sha256");
68
+ if (action === "restore")
69
+ allowed.add("backup-id");
70
+ for (const name of names)
71
+ if (!allowed.has(name))
72
+ throw invalid();
73
+ const value = (name, required = false) => {
74
+ const result = values[name];
75
+ if (result === undefined && !required)
76
+ return undefined;
77
+ if (typeof result !== "string" || !result.trim())
78
+ throw invalid();
79
+ return result;
80
+ };
81
+ const scope = value("scope") ?? "project";
82
+ if (scope !== "project" && scope !== "local")
83
+ throw invalid();
84
+ const target = { cwd: value("project") ?? cwd(), scope };
85
+ if (action === "inspect")
86
+ return { action, ...target, candidatePath: value("from") };
87
+ const expectedRevision = value("expected-revision", true);
88
+ if (!/^[a-f0-9]{64}$/.test(expectedRevision))
89
+ throw invalid();
90
+ if (action === "repair") {
91
+ const candidateSha256 = value("candidate-sha256", true);
92
+ if (!/^[a-f0-9]{64}$/.test(candidateSha256))
93
+ throw invalid();
94
+ return {
95
+ action,
96
+ ...target,
97
+ candidatePath: value("from", true),
98
+ expectedRevision,
99
+ candidateSha256,
100
+ };
101
+ }
102
+ return { action: "restore", ...target, backupId: value("backup-id", true), expectedRevision };
103
+ }
104
+ export async function runSettingsRecoveryCli(argv = process.argv.slice(2), io = {}) {
105
+ const write = io.write ?? ((text) => process.stdout.write(text));
106
+ const error = io.error ?? ((text) => process.stderr.write(text));
107
+ try {
108
+ const args = parseSettingsRecoveryArgs(argv, io.cwd ?? (() => process.cwd()));
109
+ if (args.action === "help") {
110
+ write(HELP);
111
+ return 0;
112
+ }
113
+ // Load only the reviewed Host recovery operations, after argument validation.
114
+ // In particular, do not start serve/bootstrap or require TUI/model setup.
115
+ const core = await import("@cjhyy/code-shell-core/internal");
116
+ const result = args.action === "inspect"
117
+ ? core.inspectProjectSettingsRecovery(args)
118
+ : args.action === "repair"
119
+ ? core.repairProjectSettings(args)
120
+ : core.restoreProjectSettings(args);
121
+ write(JSON.stringify(result, null, 2) + "\n");
122
+ return 0;
123
+ }
124
+ catch (cause) {
125
+ error(`[settings-recovery] ${cause instanceof Error ? cause.message : "Recovery failed"}\n`);
126
+ return 1;
127
+ }
128
+ }
@@ -0,0 +1,7 @@
1
+ import type { ServerResponse } from "node:http";
2
+ /** Response lifetimes are session-owned; accepted background work is not. */
3
+ export declare function createSessionHttpResponses(): {
4
+ track(sessionId: string, response: ServerResponse): void;
5
+ cancelOwner: (sessionId: string) => void;
6
+ clear(): void;
7
+ };
@@ -0,0 +1,40 @@
1
+ /** Response lifetimes are session-owned; accepted background work is not. */
2
+ export function createSessionHttpResponses() {
3
+ const owners = new Map();
4
+ function cancelOwner(sessionId) {
5
+ const responses = owners.get(sessionId);
6
+ if (!responses)
7
+ return;
8
+ for (const [response, release] of responses) {
9
+ release();
10
+ response.destroy();
11
+ }
12
+ }
13
+ return {
14
+ track(sessionId, response) {
15
+ if (response.destroyed || response.writableFinished)
16
+ return;
17
+ let responses = owners.get(sessionId);
18
+ if (!responses)
19
+ owners.set(sessionId, (responses = new Map()));
20
+ const owned = responses;
21
+ const release = () => {
22
+ response.off("finish", release);
23
+ response.off("close", release);
24
+ owned.delete(response);
25
+ if (owned.size === 0)
26
+ owners.delete(sessionId);
27
+ };
28
+ owned.set(response, release);
29
+ // A handler may return before its stream finishes. Follow the actual
30
+ // response, so revocation still aborts the upstream pipeline and its files.
31
+ response.once("finish", release);
32
+ response.once("close", release);
33
+ },
34
+ cancelOwner,
35
+ clear() {
36
+ for (const sessionId of owners.keys())
37
+ cancelOwner(sessionId);
38
+ },
39
+ };
40
+ }
@@ -38,8 +38,11 @@ export type WorkerRpcOutcome = {
38
38
  };
39
39
  export interface WorkerRequestOptions {
40
40
  /** Wire id for the frame. Caller mints it (must be unique while pending). */
41
- id: string;
41
+ id: string | number;
42
42
  timeoutMs: number;
43
+ /** For agent/run, timeout covers admission only. A matching runAccepted
44
+ * transfers ownership to completion/exit; requires failFast + settleOnExit. */
45
+ waitForRunCompletion?: boolean;
43
46
  /**
44
47
  * true: the matching response line is consumed here and NOT dispatched to
45
48
  * line listeners (host-internal RPC, e.g. pet snapshots). false: the line
@@ -156,6 +159,11 @@ export declare class WorkerBridgeCore {
156
159
  * to map onto its own semantics.
157
160
  */
158
161
  request(method: string, params: unknown, options: WorkerRequestOptions): Promise<WorkerRpcOutcome>;
162
+ /** Request shutdown and retain ownership until this exact child exits.
163
+ * Does not resolve merely because SIGTERM was sent; an uncooperative child
164
+ * remains owned so a caller cannot start competing work prematurely.
165
+ */
166
+ stopAndWait(): Promise<void>;
159
167
  /** Graceful shutdown: SIGTERM the worker (no-op when none is alive). */
160
168
  kill(): void;
161
169
  }
@@ -197,6 +197,11 @@ export class WorkerBridgeCore {
197
197
  }
198
198
  if (!msg || typeof msg !== "object" || Array.isArray(msg))
199
199
  return false;
200
+ if (msg.method === "agent/runAccepted" &&
201
+ (typeof msg.params?.requestId === "string" || typeof msg.params?.requestId === "number")) {
202
+ this.pendingRequests.get(msg.params.requestId)?.acceptRun?.(msg.params.sessionId);
203
+ return false;
204
+ }
200
205
  if (msg.id === undefined || msg.id === null)
201
206
  return false;
202
207
  const pending = this.pendingRequests.get(msg.id);
@@ -268,6 +273,13 @@ export class WorkerBridgeCore {
268
273
  */
269
274
  request(method, params, options) {
270
275
  const { id } = options;
276
+ if (options.waitForRunCompletion &&
277
+ (method !== "agent/run" || !options.failFast || !options.settleOnExit)) {
278
+ return Promise.resolve({
279
+ status: "sendFailed",
280
+ error: new Error("Completion tracking requires agent/run, failFast and settleOnExit"),
281
+ });
282
+ }
271
283
  return new Promise((resolve) => {
272
284
  let settled = false;
273
285
  const settle = (outcome) => {
@@ -289,6 +301,16 @@ export class WorkerBridgeCore {
289
301
  consume: options.consume === true,
290
302
  settleOnExit: options.settleOnExit === true,
291
303
  settle,
304
+ ...(options.waitForRunCompletion
305
+ ? {
306
+ acceptRun: (sessionId) => {
307
+ const expected = params?.sessionId;
308
+ if (typeof sessionId === "string" && (!expected || sessionId === expected)) {
309
+ clearTimeout(timer);
310
+ }
311
+ },
312
+ }
313
+ : {}),
292
314
  });
293
315
  let rawFrame;
294
316
  try {
@@ -343,6 +365,29 @@ export class WorkerBridgeCore {
343
365
  }
344
366
  });
345
367
  }
368
+ /** Request shutdown and retain ownership until this exact child exits.
369
+ * Does not resolve merely because SIGTERM was sent; an uncooperative child
370
+ * remains owned so a caller cannot start competing work prematurely.
371
+ */
372
+ async stopAndWait() {
373
+ const child = this.child;
374
+ if (!child || child.exitCode !== null || child.signalCode !== null)
375
+ return;
376
+ await new Promise((resolve) => {
377
+ const done = () => {
378
+ child.off("exit", done);
379
+ child.off("error", spawnFailed);
380
+ resolve();
381
+ };
382
+ const spawnFailed = () => {
383
+ if (!child.pid)
384
+ done();
385
+ };
386
+ child.once("exit", done);
387
+ child.on("error", spawnFailed);
388
+ child.kill("SIGTERM");
389
+ });
390
+ }
346
391
  /** Graceful shutdown: SIGTERM the worker (no-op when none is alive). */
347
392
  kill() {
348
393
  this.log("kill", { pid: this.child?.pid });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cjhyy/code-shell-server",
3
- "version": "0.9.21",
3
+ "version": "0.9.23",
4
4
  "description": "CodeShell server transport layer — mobile remote HTTP/WS host, pairing, passcode gate, tunnel, rooms, uploads, and session/attachment services. Electron-free; precursor of the auth gateway.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,6 +18,14 @@
18
18
  "types": "./dist/index.worker.d.ts",
19
19
  "import": "./dist/index.worker.js"
20
20
  },
21
+ "./remote-relay": {
22
+ "types": "./dist/index.remote-relay.d.ts",
23
+ "import": "./dist/index.remote-relay.js"
24
+ },
25
+ "./auth": {
26
+ "types": "./dist/index.auth.d.ts",
27
+ "import": "./dist/index.auth.js"
28
+ },
21
29
  "./mobile-remote": {
22
30
  "types": "./dist/index.mobile-remote.d.ts",
23
31
  "import": "./dist/index.mobile-remote.js"
@@ -40,7 +48,8 @@
40
48
  }
41
49
  },
42
50
  "bin": {
43
- "code-shell-serve": "./dist/bin/code-shell-serve.js"
51
+ "code-shell-serve": "./dist/bin/code-shell-serve.js",
52
+ "code-shell-settings-recovery": "./dist/bin/code-shell-settings-recovery.js"
44
53
  },
45
54
  "files": [
46
55
  "dist"
@@ -51,13 +60,13 @@
51
60
  "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
52
61
  },
53
62
  "dependencies": {
54
- "@cjhyy/code-shell-capability-coding": "0.9.21",
55
- "@cjhyy/code-shell-core": "0.9.21",
56
- "@cjhyy/code-shell-web": "0.9.21",
63
+ "@cjhyy/code-shell-capability-coding": "0.9.23",
64
+ "@cjhyy/code-shell-core": "0.9.23",
65
+ "@cjhyy/code-shell-web": "0.9.23",
57
66
  "@modelcontextprotocol/sdk": "^1.12.1",
58
67
  "@types/ws": "^8.18.1",
59
68
  "ws": "^8.21.0",
60
- "@cjhyy/code-shell-link": "0.9.21"
69
+ "@cjhyy/code-shell-link": "0.9.23"
61
70
  },
62
71
  "engines": {
63
72
  "node": ">=20.10"