@cjhyy/code-shell-server 0.9.44 → 0.9.46

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 (83) hide show
  1. package/dist/attachment-service.d.ts +2 -0
  2. package/dist/attachment-service.js +40 -27
  3. package/dist/bin/code-shell-link-cleanup.d.ts +2 -0
  4. package/dist/bin/code-shell-link-cleanup.js +3 -0
  5. package/dist/desktop-web/http-api.d.ts +3 -0
  6. package/dist/desktop-web/http-api.js +16 -1
  7. package/dist/hub/configuration.d.ts +6 -3
  8. package/dist/hub/configuration.js +19 -6
  9. package/dist/hub/mcp-probe.d.ts +4 -24
  10. package/dist/hub/mcp-probe.js +18 -389
  11. package/dist/hub/model-probe.d.ts +2 -20
  12. package/dist/hub/model-probe.js +2 -193
  13. package/dist/hub/run-replay.d.ts +7 -1
  14. package/dist/hub/run-replay.js +10 -2
  15. package/dist/hub/session-management.js +18 -53
  16. package/dist/hub/skills-management.js +6 -8
  17. package/dist/hub/uploads.d.ts +10 -0
  18. package/dist/hub/uploads.js +107 -15
  19. package/dist/index.desktop-web.d.ts +1 -0
  20. package/dist/index.desktop-web.js +1 -0
  21. package/dist/index.links.d.ts +3 -0
  22. package/dist/index.links.js +2 -0
  23. package/dist/index.panels.d.ts +1 -0
  24. package/dist/index.panels.js +1 -0
  25. package/dist/index.serve.d.ts +1 -0
  26. package/dist/index.serve.js +1 -0
  27. package/dist/index.storage.d.ts +1 -0
  28. package/dist/index.storage.js +1 -0
  29. package/dist/links/catalog.js +2 -0
  30. package/dist/links/diagnostics.d.ts +60 -0
  31. package/dist/links/diagnostics.js +184 -0
  32. package/dist/links/http.d.ts +10 -8
  33. package/dist/links/http.js +144 -125
  34. package/dist/links/legacy-cleanup-cli.d.ts +3 -0
  35. package/dist/links/legacy-cleanup-cli.js +64 -0
  36. package/dist/links/providers/defaults.d.ts +5 -0
  37. package/dist/links/providers/defaults.js +782 -0
  38. package/dist/links/providers/index.d.ts +7 -0
  39. package/dist/links/providers/index.js +22 -0
  40. package/dist/links/remote-catalog.d.ts +10 -3
  41. package/dist/links/remote-catalog.js +76 -29
  42. package/dist/links/runtime/operation.d.ts +9 -0
  43. package/dist/links/runtime/operation.js +16 -0
  44. package/dist/links/service.d.ts +18 -2
  45. package/dist/links/service.js +593 -62
  46. package/dist/links/types.d.ts +21 -1
  47. package/dist/mobile-remote/codex-parse.d.ts +3 -1
  48. package/dist/mobile-remote/codex-parse.js +45 -11
  49. package/dist/mobile-remote/mobile-chat-turn.d.ts +1 -0
  50. package/dist/mobile-remote/mobile-chat-turn.js +3 -0
  51. package/dist/mobile-remote/mobile-client-event-validator.js +13 -0
  52. package/dist/mobile-remote/mobile-history.d.ts +10 -1
  53. package/dist/mobile-remote/mobile-history.js +24 -16
  54. package/dist/mobile-remote/remote-host-manager.d.ts +8 -0
  55. package/dist/mobile-remote/remote-host-manager.js +23 -8
  56. package/dist/mobile-remote/resident-agent.js +17 -4
  57. package/dist/mobile-remote/room-manager.d.ts +23 -13
  58. package/dist/mobile-remote/room-manager.js +102 -20
  59. package/dist/mobile-remote/room-model-tracing.d.ts +18 -0
  60. package/dist/mobile-remote/room-model-tracing.js +196 -0
  61. package/dist/model-trace-history.d.ts +29 -0
  62. package/dist/model-trace-history.js +198 -0
  63. package/dist/model-trace-http.d.ts +14 -0
  64. package/dist/model-trace-http.js +105 -0
  65. package/dist/panels/agent-task-host.js +1 -0
  66. package/dist/panels/directory-bookmarks.js +62 -29
  67. package/dist/panels/http.d.ts +1 -0
  68. package/dist/panels/hub-binding.js +5 -5
  69. package/dist/panels/model-trace-channel.d.ts +21 -0
  70. package/dist/panels/model-trace-channel.js +110 -0
  71. package/dist/panels/model-traces.d.ts +39 -0
  72. package/dist/panels/model-traces.js +222 -0
  73. package/dist/panels/process-service.d.ts +12 -2
  74. package/dist/panels/process-service.js +49 -6
  75. package/dist/panels/runtime.d.ts +1 -0
  76. package/dist/panels/runtime.js +54 -6
  77. package/dist/panels/tool-jobs.d.ts +2 -0
  78. package/dist/panels/tool-jobs.js +21 -1
  79. package/dist/serve/cli.js +8 -1
  80. package/dist/serve/headless-server.js +68 -14
  81. package/dist/sessions-service.js +17 -27
  82. package/dist/worker-bridge-core.js +11 -0
  83. package/package.json +8 -7
@@ -0,0 +1,7 @@
1
+ import { type AgentModule, type LocalLinkProviderSpec } from "@cjhyy/code-shell-core/extension";
2
+ export { createDefaultLinkProviders } from "./defaults.js";
3
+ type Registrar = (providers: readonly LocalLinkProviderSpec[]) => void;
4
+ /** Explicit product composition; custom SDK callers may supply their own registrar. */
5
+ export declare function installDefaultLinkProviders(register?: Registrar): void;
6
+ /** Loaded by the existing trusted worker module factory mechanism. */
7
+ export declare function createLinkProviderModule(): AgentModule;
@@ -0,0 +1,22 @@
1
+ import { registerLocalLinkProviders, getLocalLinkProvider, } from "@cjhyy/code-shell-core/extension";
2
+ import { createDefaultLinkProviders } from "./defaults.js";
3
+ export { createDefaultLinkProviders } from "./defaults.js";
4
+ const installed = new WeakSet();
5
+ /** Explicit product composition; custom SDK callers may supply their own registrar. */
6
+ export function installDefaultLinkProviders(register = registerLocalLinkProviders) {
7
+ if (installed.has(register))
8
+ return;
9
+ const providers = createDefaultLinkProviders();
10
+ // Two product module copies may share one Core registry (e.g. a host/plugin
11
+ // composition). Preserve explicitly installed implementations instead of
12
+ // overwriting them or treating the second default composition as an error.
13
+ register(register === registerLocalLinkProviders
14
+ ? providers.filter((provider) => !getLocalLinkProvider(provider.id))
15
+ : providers);
16
+ installed.add(register);
17
+ }
18
+ /** Loaded by the existing trusted worker module factory mechanism. */
19
+ export function createLinkProviderModule() {
20
+ installDefaultLinkProviders();
21
+ return { id: "codeshell-link-providers" };
22
+ }
@@ -1,5 +1,13 @@
1
1
  import { type RemoteLinkConfiguration } from "@cjhyy/code-shell-core";
2
2
  import { type RemoteLinkProviderId } from "@cjhyy/code-shell-core";
3
+ export type RemoteLinkCatalogFailureReason = "network" | "timeout" | "http_status" | "invalid_json" | "invalid_schema" | "unreviewed_capability" | "unsupported_auth" | "response_limit";
4
+ /** Fixed diagnostics distinguish unavailable discovery from a valid empty catalog. */
5
+ export declare class RemoteLinkCatalogError extends Error {
6
+ readonly reason: RemoteLinkCatalogFailureReason;
7
+ readonly httpStatus?: number | undefined;
8
+ readonly code: "network_error" | "http_error" | "invalid_response" | "response_too_large";
9
+ constructor(reason: RemoteLinkCatalogFailureReason, httpStatus?: number | undefined);
10
+ }
3
11
  /** The Host's compiled executors own authority, never remotely supplied presentation metadata. */
4
12
  export declare const REMOTE_LINK_ADAPTERS: ({
5
13
  methodId: string;
@@ -80,7 +88,7 @@ export declare const REMOTE_LINK_ADAPTERS: ({
80
88
  id: "figma";
81
89
  name: "Figma";
82
90
  group: "files";
83
- actions: readonly ["get_file", "get_comments", "get_nodes", "get_images", "get_image_fills"];
91
+ actions: readonly ["get_file", "read_design_content", "get_comments", "get_nodes", "get_images", "get_image_fills"];
84
92
  })[];
85
93
  export type RemoteProviderId = RemoteLinkProviderId;
86
94
  export interface RemoteProviderCapabilities {
@@ -88,7 +96,6 @@ export interface RemoteProviderCapabilities {
88
96
  actions: string[];
89
97
  scopes: string[];
90
98
  }
91
- export declare const LEGACY_REMOTE_PROVIDERS: RemoteProviderCapabilities[];
92
99
  export declare function readRemoteProviderCatalog(configuration: RemoteLinkConfiguration): Promise<RemoteProviderId[]>;
93
- /** A legacy v1 service has no catalog. Its one already-reviewed adapter remains compatible. */
100
+ /** Discovery never grants authority or turns a failed response into an empty catalog. */
94
101
  export declare function readRemoteProviderCapabilities(configuration: RemoteLinkConfiguration): Promise<RemoteProviderCapabilities[]>;
@@ -1,5 +1,34 @@
1
1
  import { beginRemoteLinkAuthorization } from "@cjhyy/code-shell-core";
2
- import { REMOTE_LINK_PROVIDER_ADAPTERS, LEGACY_GITHUB_ACTIONS, } from "@cjhyy/code-shell-core";
2
+ import { REMOTE_LINK_PROVIDER_ADAPTERS } from "@cjhyy/code-shell-core";
3
+ /** Fixed diagnostics distinguish unavailable discovery from a valid empty catalog. */
4
+ export class RemoteLinkCatalogError extends Error {
5
+ reason;
6
+ httpStatus;
7
+ code;
8
+ constructor(reason, httpStatus) {
9
+ super({
10
+ network: "Could not reach the Link provider catalog. Retry the request.",
11
+ timeout: "The Link provider catalog request timed out. Retry the request.",
12
+ http_status: "The Link provider catalog returned an unsuccessful HTTP status.",
13
+ invalid_json: "The Link provider catalog response is not valid JSON.",
14
+ invalid_schema: "The Link provider catalog response does not match the supported protocol.",
15
+ unreviewed_capability: "The Link provider catalog advertised an unreviewed capability.",
16
+ unsupported_auth: "The Link provider catalog uses an unsupported authorization mechanism.",
17
+ response_limit: "The Link provider catalog exceeded the 32 KiB response limit.",
18
+ }[reason]);
19
+ this.reason = reason;
20
+ this.httpStatus = httpStatus;
21
+ this.name = "RemoteLinkCatalogError";
22
+ this.code =
23
+ reason === "network" || reason === "timeout"
24
+ ? "network_error"
25
+ : reason === "http_status"
26
+ ? "http_error"
27
+ : reason === "response_limit"
28
+ ? "response_too_large"
29
+ : "invalid_response";
30
+ }
31
+ }
3
32
  /** The Host's compiled executors own authority, never remotely supplied presentation metadata. */
4
33
  export const REMOTE_LINK_ADAPTERS = REMOTE_LINK_PROVIDER_ADAPTERS.map((adapter) => ({
5
34
  ...adapter,
@@ -7,36 +36,36 @@ export const REMOTE_LINK_ADAPTERS = REMOTE_LINK_PROVIDER_ADAPTERS.map((adapter)
7
36
  authModeId: "remote-link",
8
37
  scopes: adapter.actions.map((action) => `${adapter.id}:${action}`),
9
38
  }));
10
- export const LEGACY_REMOTE_PROVIDERS = [
11
- {
12
- id: "github",
13
- actions: [...LEGACY_GITHUB_ACTIONS],
14
- scopes: LEGACY_GITHUB_ACTIONS.map((action) => `github:${action}`),
15
- },
16
- ];
17
39
  export async function readRemoteProviderCatalog(configuration) {
18
40
  return (await readRemoteProviderCapabilities(configuration)).map((provider) => provider.id);
19
41
  }
20
- /** A legacy v1 service has no catalog. Its one already-reviewed adapter remains compatible. */
42
+ /** Discovery never grants authority or turns a failed response into an empty catalog. */
21
43
  export async function readRemoteProviderCapabilities(configuration) {
22
44
  const issuer = beginRemoteLinkAuthorization(configuration).configuration.issuer;
23
45
  const scopes = REMOTE_LINK_ADAPTERS.flatMap((adapter) => adapter.scopes);
24
46
  const capabilities = JSON.stringify({ version: 1, scopes });
25
47
  if (scopes.length > 128 || Buffer.byteLength(capabilities) > 4_096)
26
48
  throw new Error("Host Link capabilities exceed catalog negotiation limits");
27
- const response = await fetch(new URL("/api/v1/links/providers", issuer), {
28
- redirect: "error",
29
- signal: AbortSignal.timeout(5_000),
30
- headers: { Accept: "application/json", "X-CodeShell-Link-Capabilities": capabilities },
31
- });
32
- if ([404, 501].includes(response.status)) {
33
- await response.body?.cancel();
34
- return structuredClone(LEGACY_REMOTE_PROVIDERS);
49
+ const signal = AbortSignal.timeout(5_000);
50
+ let response;
51
+ try {
52
+ response = await fetch(new URL("/api/v1/links/providers", issuer), {
53
+ redirect: "error",
54
+ signal,
55
+ headers: { Accept: "application/json", "X-CodeShell-Link-Capabilities": capabilities },
56
+ });
35
57
  }
36
- if (!response.ok || !response.body) {
37
- await response.body?.cancel();
38
- throw new Error("Link catalog unavailable");
58
+ catch (error) {
59
+ throw new RemoteLinkCatalogError(signal.aborted || (error instanceof Error && error.name === "TimeoutError")
60
+ ? "timeout"
61
+ : "network");
39
62
  }
63
+ if (!response.ok) {
64
+ await response.body?.cancel().catch(() => { });
65
+ throw new RemoteLinkCatalogError("http_status", response.status);
66
+ }
67
+ if (!response.body)
68
+ throw new RemoteLinkCatalogError("invalid_schema");
40
69
  const reader = response.body.getReader();
41
70
  const chunks = [];
42
71
  let size = 0;
@@ -47,12 +76,17 @@ export async function readRemoteProviderCapabilities(configuration) {
47
76
  break;
48
77
  size += value.byteLength;
49
78
  if (size > 32_768) {
50
- await reader.cancel();
51
- return [];
79
+ throw new RemoteLinkCatalogError("response_limit");
52
80
  }
53
81
  chunks.push(value);
54
82
  }
55
83
  }
84
+ catch (error) {
85
+ await reader.cancel().catch(() => { });
86
+ if (error instanceof RemoteLinkCatalogError)
87
+ throw error;
88
+ throw new RemoteLinkCatalogError(signal.aborted ? "timeout" : "network");
89
+ }
56
90
  finally {
57
91
  reader.releaseLock();
58
92
  }
@@ -61,13 +95,22 @@ export async function readRemoteProviderCapabilities(configuration) {
61
95
  catalog = JSON.parse(Buffer.concat(chunks).toString("utf8"));
62
96
  }
63
97
  catch {
64
- return [];
98
+ throw new RemoteLinkCatalogError("invalid_json");
65
99
  }
66
100
  if (catalog?.version !== 1 || !Array.isArray(catalog.providers) || catalog.providers.length > 32)
67
- return [];
101
+ throw new RemoteLinkCatalogError("invalid_schema");
102
+ if (catalog.providers.some((item) => !item ||
103
+ typeof item !== "object" ||
104
+ Array.isArray(item) ||
105
+ typeof item.id !== "string" ||
106
+ !/^[a-z][a-z0-9_-]{0,63}$/.test(item.id)))
107
+ throw new RemoteLinkCatalogError("invalid_schema");
108
+ const ids = catalog.providers.map((item) => item.id);
109
+ if (new Set(ids).size !== ids.length)
110
+ throw new RemoteLinkCatalogError("invalid_schema");
68
111
  return REMOTE_LINK_ADAPTERS.flatMap((adapter) => {
69
112
  const matches = catalog.providers.filter((item) => item?.id === adapter.id);
70
- if (matches.length !== 1)
113
+ if (!matches.length)
71
114
  return [];
72
115
  const provider = matches[0];
73
116
  const actions = provider.actions;
@@ -81,14 +124,18 @@ export async function readRemoteProviderCapabilities(configuration) {
81
124
  scopes.length !== actions.length ||
82
125
  new Set(scopes).size !== scopes.length ||
83
126
  actions.some((action) => !scopes.includes(`${adapter.id}:${action}`)))
84
- return [];
85
- if (!Array.isArray(provider.methods) ||
86
- !provider.methods.some((method) => method?.id === adapter.methodId &&
127
+ throw new RemoteLinkCatalogError("unreviewed_capability");
128
+ const methods = Array.isArray(provider.methods)
129
+ ? provider.methods.filter((method) => method?.id === adapter.methodId)
130
+ : [];
131
+ if (methods.length !== 1 ||
132
+ !methods.some((method) => method?.id === adapter.methodId &&
87
133
  method.authKind === "oauth" &&
88
134
  method.defaultAuthModeId === "browser" &&
89
135
  Array.isArray(method.authModes) &&
136
+ method.authModes.filter((mode) => mode?.id === "browser").length === 1 &&
90
137
  method.authModes.some((mode) => mode?.id === "browser" && mode.kind === "redirect")))
91
- return [];
138
+ throw new RemoteLinkCatalogError("unsupported_auth");
92
139
  return [{ id: adapter.id, actions: [...actions], scopes: [...scopes] }];
93
140
  });
94
141
  }
@@ -0,0 +1,9 @@
1
+ /** One adapter invocation. Write approval, durable intent and verification belong to the owning controller. */
2
+ export declare function executeLinkOperation(options: {
3
+ providerId: string;
4
+ action: string;
5
+ params: Record<string, unknown>;
6
+ execute(params: Record<string, unknown>): Promise<unknown>;
7
+ assertAuthorized?(): void;
8
+ signal?: AbortSignal;
9
+ }): Promise<unknown>;
@@ -0,0 +1,16 @@
1
+ import { LinkOperationError, assertLinkOperationResult, getLinkOperationContract, snapshotLinkOperationInput, } from "@cjhyy/code-shell-link";
2
+ /** One adapter invocation. Write approval, durable intent and verification belong to the owning controller. */
3
+ export async function executeLinkOperation(options) {
4
+ const contract = getLinkOperationContract(options.providerId, options.action);
5
+ if (!contract)
6
+ throw new LinkOperationError("unsupported_contract", "This Host does not support the requested operation contract.");
7
+ // Detach input before asynchronous code can observe caller changes.
8
+ const params = snapshotLinkOperationInput(contract, options.params);
9
+ options.signal?.throwIfAborted();
10
+ options.assertAuthorized?.();
11
+ const result = await options.execute(params);
12
+ options.assertAuthorized?.();
13
+ options.signal?.throwIfAborted();
14
+ assertLinkOperationResult(contract, result);
15
+ return result;
16
+ }
@@ -1,12 +1,18 @@
1
1
  import { CredentialStore, type RemoteLinkConfiguration, connectCliLink, getCliLinkStatus, validateLocalLinkToken, type LocalLinkValidationResult } from "@cjhyy/code-shell-core";
2
+ import { type LinkAuthorizationDiagnosticSink } from "./diagnostics.js";
2
3
  import { readRemoteProviderCatalog } from "./remote-catalog.js";
3
4
  import { LinkDeviceOAuthBroker, type LocalBrowserAuthToken } from "./device-oauth.js";
4
- import type { LinkAuthorization, LinkAuthorizationResponse, LinkConnectionInput, LinkErrorCode, LinkOperationContext, LinkSnapshot, MaskedLinkConnection, TokenConnectionInput } from "./types.js";
5
+ import type { LinkAuthorization, LinkAuthorizationFailure, LinkAuthorizationResponse, LinkConnectionInput, LinkErrorCode, LinkOperationContext, LinkSnapshot, MaskedLinkConnection, TokenConnectionInput, HostLinkOAuthAdapter } from "./types.js";
5
6
  export declare class LinkServiceError extends Error {
6
7
  readonly status: number;
7
8
  readonly code: LinkErrorCode;
8
9
  constructor(status: number, code: LinkErrorCode);
9
10
  }
11
+ /** Trusted Host adapters use this to expose reviewed failure stages, never raw provider text. */
12
+ export declare class HostLinkOAuthError extends LinkServiceError {
13
+ readonly failure: LinkAuthorizationFailure;
14
+ constructor(failure: LinkAuthorizationFailure);
15
+ }
10
16
  export declare function publicLinkError(error: unknown): LinkServiceError;
11
17
  export interface LinkServiceOptions {
12
18
  cwd?: string;
@@ -16,6 +22,11 @@ export interface LinkServiceOptions {
16
22
  now?: () => number;
17
23
  /** Trusted Host configuration; never accepted from a browser request. */
18
24
  remoteLink?: () => RemoteLinkConfiguration | undefined;
25
+ /** Optional Host authority for a remote authorization's complete lifetime. */
26
+ captureRemoteAuthority?: () => {
27
+ current(): void;
28
+ signal: AbortSignal;
29
+ };
19
30
  /** Trusted Host opt-in: reuse a uniquely identified user connection after remote OAuth. */
20
31
  reuseRemoteConnection?: boolean;
21
32
  /** Test seams. Production delegates to Core's fixed provider and CLI executors. */
@@ -26,6 +37,9 @@ export interface LinkServiceOptions {
26
37
  readRemoteCatalog?: typeof readRemoteProviderCatalog;
27
38
  /** Native Host only; remote browser callers may bind existing Host sessions but cannot start login. */
28
39
  allowCliLogin?: boolean;
40
+ hostOAuthAdapters?: readonly HostLinkOAuthAdapter[];
41
+ /** Defaults to redacted single-line JSON on stderr for HTTP and native authorization starts. */
42
+ onAuthorizationDiagnostic?: LinkAuthorizationDiagnosticSink;
29
43
  }
30
44
  /** Trusted host adapter input; deliberately absent from the HTTP API. */
31
45
  export type ValidatedLinkAuthentication = {
@@ -45,6 +59,7 @@ export declare function createLinkService(options?: LinkServiceOptions): {
45
59
  connectToken: (context: LinkOperationContext, input: TokenConnectionInput) => Promise<MaskedLinkConnection>;
46
60
  connectCli: (context: LinkOperationContext, input: LinkConnectionInput) => Promise<MaskedLinkConnection>;
47
61
  cliStatus: (context: LinkOperationContext, rawProviderId: unknown) => Promise<{
62
+ accountId?: string | undefined;
48
63
  account?: string | undefined;
49
64
  providerId: import("@cjhyy/code-shell-core").CliLinkProviderId;
50
65
  command: string;
@@ -55,8 +70,9 @@ export declare function createLinkService(options?: LinkServiceOptions): {
55
70
  disconnect: (context: LinkOperationContext, id: string, expectedRevision: string) => Promise<void>;
56
71
  startDeviceAuth: (context: LinkOperationContext, input: LinkConnectionInput) => Promise<LinkAuthorization>;
57
72
  startAuthorization: (context: LinkOperationContext, input: LinkConnectionInput, rawAuthModeId: unknown) => Promise<LinkAuthorization>;
73
+ openHostAuthorization: (context: LinkOperationContext, id: string) => Promise<boolean>;
58
74
  respondAuthorization: (context: LinkOperationContext, id: string, response: LinkAuthorizationResponse) => Promise<LinkAuthorization>;
59
- refreshRemoteCatalog: (context: LinkOperationContext) => Promise<void>;
75
+ refreshRemoteCatalog: (context: LinkOperationContext, force?: boolean) => Promise<void>;
60
76
  startRemoteAuth: (context: LinkOperationContext, input: LinkConnectionInput) => Promise<LinkAuthorization>;
61
77
  completeRemoteAuth: (context: LinkOperationContext, id: string, callbackUrl: string) => Promise<LinkAuthorization>;
62
78
  retryRemoteCleanup: () => Promise<void>;