@sanqianx/claude-ai-workbench 0.11.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.
Files changed (90) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +129 -0
  3. package/apps/agent-terminal/app.css +567 -0
  4. package/apps/agent-terminal/app.js +2392 -0
  5. package/apps/agent-terminal/index.html +158 -0
  6. package/apps/ai-profile-settings-host/index.html +25 -0
  7. package/apps/ai-profile-settings-host/page.css +1 -0
  8. package/apps/ai-profile-settings-host/page.js +113 -0
  9. package/apps/minimal-test-host/README.md +15 -0
  10. package/apps/minimal-test-host/host.css +2 -0
  11. package/apps/minimal-test-host/host.js +35 -0
  12. package/apps/minimal-test-host/index.html +58 -0
  13. package/apps/minimal-test-host/optional-mock/fault-injection.js +15 -0
  14. package/docs/sdk/FILE_LAYOUT.md +31 -0
  15. package/docs/sdk/INTEGRATION.md +126 -0
  16. package/docs/sdk/README.md +21 -0
  17. package/docs/sdk/openapi.yaml +760 -0
  18. package/package.json +51 -0
  19. package/packages/client/README.md +11 -0
  20. package/packages/client/index.d.ts +81 -0
  21. package/packages/client/index.js +198 -0
  22. package/packages/client/package.json +29 -0
  23. package/packages/contracts/README.md +9 -0
  24. package/packages/contracts/index.d.ts +252 -0
  25. package/packages/contracts/index.js +295 -0
  26. package/packages/contracts/package.json +24 -0
  27. package/packages/core/README.md +8 -0
  28. package/packages/core/index.d.ts +76 -0
  29. package/packages/core/index.js +214 -0
  30. package/packages/core/package.json +29 -0
  31. package/packages/server/README.md +17 -0
  32. package/packages/server/bin/agent-terminal-server.js +36 -0
  33. package/packages/server/bin/claude-workbench-server.js +46 -0
  34. package/packages/server/bin/claude-workbench.js +225 -0
  35. package/packages/server/index.d.ts +145 -0
  36. package/packages/server/index.js +183 -0
  37. package/packages/server/lib/agent-discovery.js +112 -0
  38. package/packages/server/lib/agent-registry.js +98 -0
  39. package/packages/server/lib/attachment-store.js +78 -0
  40. package/packages/server/lib/bridges/app-server-bridge.js +372 -0
  41. package/packages/server/lib/bridges/opencode-server-bridge.js +490 -0
  42. package/packages/server/lib/capture-settings-store.js +34 -0
  43. package/packages/server/lib/context-resolver.js +40 -0
  44. package/packages/server/lib/drivers/cli-json-runner.js +960 -0
  45. package/packages/server/lib/drivers/codex-driver.js +1413 -0
  46. package/packages/server/lib/drivers/opencode-driver.js +1527 -0
  47. package/packages/server/lib/drivers/zcode-driver.js +1167 -0
  48. package/packages/server/lib/event-stream.js +35 -0
  49. package/packages/server/lib/folder-picker.js +623 -0
  50. package/packages/server/lib/http-handler.js +254 -0
  51. package/packages/server/lib/json-file.js +19 -0
  52. package/packages/server/lib/model-detection.js +295 -0
  53. package/packages/server/lib/profile-store.js +149 -0
  54. package/packages/server/lib/project-store.js +102 -0
  55. package/packages/server/lib/session-archive-store.js +53 -0
  56. package/packages/server/lib/system-doctor.js +119 -0
  57. package/packages/server/lib/ui-preferences-store.js +48 -0
  58. package/packages/server/lib/workbench-service.js +620 -0
  59. package/packages/server/package.json +34 -0
  60. package/packages/ui/README.md +30 -0
  61. package/packages/ui/ai-profile-settings.d.ts +45 -0
  62. package/packages/ui/ai-profile-settings.js +283 -0
  63. package/packages/ui/claude-terminal.d.ts +31 -0
  64. package/packages/ui/claude-terminal.js +343 -0
  65. package/packages/ui/index.d.ts +18 -0
  66. package/packages/ui/index.js +51 -0
  67. package/packages/ui/package.json +42 -0
  68. package/packages/ui/theme.css +13 -0
  69. package/src/assets/claude-prompts.json +21 -0
  70. package/src/backend/http/ai-profile-routes.js +61 -0
  71. package/src/backend/http/claude-routes.js +170 -0
  72. package/src/backend/http/node-helpers.js +45 -0
  73. package/src/backend/index.js +21 -0
  74. package/src/backend/lib/ai-adapter.js +144 -0
  75. package/src/backend/lib/ai-profile-store.js +259 -0
  76. package/src/backend/lib/ai-vendor-presets.js +83 -0
  77. package/src/backend/lib/ai-workspace.js +140 -0
  78. package/src/backend/lib/automation-config.js +253 -0
  79. package/src/backend/lib/claude-cli-runner.js +1749 -0
  80. package/src/backend/lib/data-dir.js +169 -0
  81. package/src/backend/lib/llm-client.js +176 -0
  82. package/src/backend/lib/model-context-windows.js +82 -0
  83. package/src/backend/lib/prompt-registry.js +166 -0
  84. package/src/backend/lib/runtime-config.js +121 -0
  85. package/src/index.js +7 -0
  86. package/src/sdk-wave-a.ts +1 -0
  87. package/src/sdk-wave-b.ts +1 -0
  88. package/src/sdk-wave-c.ts +1 -0
  89. package/src/sdk-wave-d.ts +1 -0
  90. package/src/sdk-wave-e.ts +1 -0
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@sanqianx/claude-ai-workbench",
3
+ "version": "0.11.0",
4
+ "description": "Shared Claude Code terminal and Anthropic-compatible AI profile modules for local developer tools.",
5
+ "type": "commonjs",
6
+ "main": "src/index.js",
7
+ "bin": {
8
+ "claude-workbench": "packages/server/bin/claude-workbench.js",
9
+ "claude-ai-workbench": "packages/server/bin/claude-workbench.js"
10
+ },
11
+ "files": [
12
+ "packages",
13
+ "apps",
14
+ "src",
15
+ "docs/sdk",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "check": "node scripts/check-package.js",
21
+ "test": "node --test tests/unit/*.test.js tests/integration/*.test.js tests/contract/*.test.js",
22
+ "test:real": "node --test tests/real/*.test.js",
23
+ "start": "node packages/server/bin/claude-workbench-server.js",
24
+ "start:agent-terminal": "node packages/server/bin/agent-terminal-server.js",
25
+ "start:test-host": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/start-test-host.ps1",
26
+ "sdk:check": "node scripts/validate-sdk.js && tsc -p tsconfig.sdk.json",
27
+ "sdk:pack": "node scripts/pack-sdk.js",
28
+ "release:sync": "node scripts/sync-release-version.js",
29
+ "release:verify": "npm run verify && node scripts/sync-release-version.js --check",
30
+ "prepublishOnly": "npm run release:verify",
31
+ "preversion": "npm run release:verify",
32
+ "version": "node scripts/sync-release-version.js --stage",
33
+ "postversion": "npm run release:verify",
34
+ "verify": "npm run check && npm test && npm run sdk:check"
35
+ },
36
+ "workspaces": [
37
+ "packages/*"
38
+ ],
39
+ "dependencies": {
40
+ "@anthropic-ai/claude-agent-sdk": "^0.2.141"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
44
+ },
45
+ "license": "Apache-2.0",
46
+ "devDependencies": {
47
+ "@types/node": "^26.1.1",
48
+ "typescript": "^7.0.2",
49
+ "yaml": "^2.9.0"
50
+ }
51
+ }
@@ -0,0 +1,11 @@
1
+ # @claude-ai-workbench/client
2
+
3
+ 浏览器和 Node.js 使用的 HTTP/SSE Client SDK。
4
+
5
+ ```js
6
+ const { createClaudeWorkbenchClient } = require("@claude-ai-workbench/client");
7
+ const client = createClaudeWorkbenchClient({ apiBase: "http://127.0.0.1:5760/api/claude-workbench/v1" });
8
+ const profiles = await client.listProfiles();
9
+ ```
10
+
11
+ 浏览器也可直接加载 `index.js`,然后使用全局函数 `createClaudeWorkbenchClient`。
@@ -0,0 +1,81 @@
1
+ import type {
2
+ AgentId,
3
+ AgentStatus,
4
+ AiProfile,
5
+ AiProfileInput,
6
+ CredentialInput,
7
+ EffortLevel,
8
+ HealthResult,
9
+ PermissionMode,
10
+ ProfileTestResult,
11
+ Project,
12
+ ProjectInput,
13
+ ProjectPatch,
14
+ RuntimeInfo,
15
+ AttachmentInput,
16
+ SlashCommand,
17
+ SessionSnapshot,
18
+ SessionSummary,
19
+ WorkbenchContext,
20
+ WorkbenchEvent,
21
+ } from "@claude-ai-workbench/contracts";
22
+
23
+ export interface RequestOptions { signal?: AbortSignal; [key: string]: unknown; }
24
+ export interface StartSessionOptions extends RequestOptions {
25
+ permissionMode?: PermissionMode;
26
+ agentId?: AgentId;
27
+ effort?: EffortLevel;
28
+ aiProfileId?: string | null;
29
+ model?: string | null;
30
+ }
31
+ export interface ListSessionsOptions extends RequestOptions { archived?: boolean; }
32
+ export interface SendOptions { permissionMode?: PermissionMode; [key: string]: unknown; }
33
+ export interface StreamHandlers {
34
+ onEvent?: (event: WorkbenchEvent) => void;
35
+ onError?: (error: Error) => void;
36
+ onOpen?: () => void;
37
+ afterSequence?: number;
38
+ }
39
+ export interface ClientResourceCounts { streams: number; requests: number; reconnects: number; }
40
+ export interface ClaudeWorkbenchClientOptions {
41
+ apiBase?: string;
42
+ fetch?: typeof fetch;
43
+ EventSource?: typeof EventSource;
44
+ }
45
+
46
+ export interface ClaudeWorkbenchClient {
47
+ health(): Promise<HealthResult>;
48
+ runtime(): Promise<RuntimeInfo>;
49
+ listAgents(): Promise<AgentStatus[]>;
50
+ listProjects(): Promise<Project[]>;
51
+ createProject(project: ProjectInput): Promise<Project>;
52
+ getProject(id: string): Promise<Project>;
53
+ renameProject(id: string, name: string): Promise<Project>;
54
+ updateProject(id: string, patch: ProjectPatch): Promise<Project>;
55
+ removeProject(id: string): Promise<void>;
56
+ listProfiles(): Promise<AiProfile[]>;
57
+ saveProfile(profile: AiProfileInput): Promise<AiProfile>;
58
+ deleteProfile(id: string): Promise<void>;
59
+ setCredential(id: string, credential: string | CredentialInput): Promise<void>;
60
+ testProfile(id: string): Promise<ProfileTestResult>;
61
+ testProfileDraft(profile: AiProfileInput, credential?: string): Promise<ProfileTestResult>;
62
+ listSessions(context: WorkbenchContext | string, options?: ListSessionsOptions): Promise<SessionSummary[]>;
63
+ startSession(context: WorkbenchContext, options?: StartSessionOptions): Promise<SessionSummary>;
64
+ loadSession(id: string, options?: RequestOptions): Promise<SessionSnapshot>;
65
+ listCommands(id: string, options?: RequestOptions): Promise<SlashCommand[]>;
66
+ subscribe(id: string, handlers: StreamHandlers | ((event: WorkbenchEvent) => void), onError?: (error: Error) => void, options?: {afterSequence?: number}): () => void;
67
+ send(sessionId: string, text: string, options?: SendOptions): Promise<unknown>;
68
+ send(args: {sessionId: string; text?: string; attachments?: AttachmentInput[]; options?: SendOptions}): Promise<unknown>;
69
+ resolvePermission(sessionId: string, requestId: string, allow: boolean, message?: string): Promise<unknown>;
70
+ resolvePermission(args: {sessionId: string; requestId: string; allow: boolean; message?: string}): Promise<unknown>;
71
+ abort(sessionId: string | {sessionId: string}): Promise<unknown>;
72
+ setPermissionMode(sessionId: string, mode: PermissionMode): Promise<unknown>;
73
+ setPermissionMode(args: {sessionId: string; mode: PermissionMode}): Promise<unknown>;
74
+ archiveSession(sessionId: string | {sessionId: string}): Promise<{sessionId: string; archivedAt: string}>;
75
+ restoreSession(sessionId: string | {sessionId: string}): Promise<void>;
76
+ resourceCounts(): ClientResourceCounts;
77
+ destroy(): void;
78
+ }
79
+
80
+ export declare const EVENT_TYPES: readonly string[];
81
+ export declare function createClaudeWorkbenchClient(options?: ClaudeWorkbenchClientOptions): ClaudeWorkbenchClient;
@@ -0,0 +1,198 @@
1
+ (function (global, factory) {
2
+ const exported = factory();
3
+ if (typeof module !== 'undefined' && module.exports) module.exports = exported;
4
+ global.createClaudeWorkbenchClient = exported.createClaudeWorkbenchClient;
5
+ })(typeof window !== 'undefined' ? window : globalThis, function () {
6
+ 'use strict';
7
+
8
+ const EVENT_TYPES = [
9
+ 'workbench/stream-open', 'workbench/stream-reconnecting', 'claude/init', 'claude/state',
10
+ 'claude/session-ready', 'claude/user-prompt', 'claude/system-prompt', 'claude/text-start',
11
+ 'claude/text-delta', 'claude/result', 'claude/thinking-start', 'claude/thinking-delta',
12
+ 'claude/tool-use', 'claude/tool-result', 'claude/permission-request', 'claude/permission-resolved',
13
+ 'claude/usage', 'claude/commands', 'claude/image', 'claude/retry', 'claude/error', 'claude/stderr', 'claude/aborted',
14
+ 'claude/selection-changed',
15
+ ];
16
+
17
+ function createClaudeWorkbenchClient(options = {}) {
18
+ const apiBase = String(options.apiBase || '/api/claude-workbench/v1').replace(/\/$/, '');
19
+ const fetchImpl = options.fetch || globalThis.fetch;
20
+ const EventSourceImpl = options.EventSource || globalThis.EventSource;
21
+ if (typeof fetchImpl !== 'function') throw new Error('fetch is required');
22
+ const streams = new Set();
23
+ const controllers = new Set();
24
+ let destroyed = false;
25
+ let reconnects = 0;
26
+
27
+ async function request(path, init = {}) {
28
+ if (destroyed) throw new Error('ClaudeWorkbenchClient is destroyed');
29
+ const controller = new AbortController();
30
+ const external = init.signal;
31
+ const abort = () => controller.abort();
32
+ if (external) {
33
+ if (external.aborted) controller.abort();
34
+ else external.addEventListener('abort', abort, { once: true });
35
+ }
36
+ controllers.add(controller);
37
+ try {
38
+ const response = await fetchImpl(`${apiBase}${path}`, {
39
+ ...init,
40
+ headers: { 'Content-Type': 'application/json', ...(init.headers || {}) },
41
+ signal: controller.signal,
42
+ });
43
+ const text = await response.text();
44
+ const data = text ? JSON.parse(text) : null;
45
+ if (!response.ok) {
46
+ const error = new Error(data && data.error || `HTTP ${response.status}`);
47
+ error.status = response.status; error.body = data; throw error;
48
+ }
49
+ return data;
50
+ } finally {
51
+ controllers.delete(controller);
52
+ if (external) external.removeEventListener('abort', abort);
53
+ }
54
+ }
55
+
56
+ function subscribe(sessionId, handlers, onError, subscribeOptions = {}) {
57
+ if (destroyed) throw new Error('ClaudeWorkbenchClient is destroyed');
58
+ if (typeof EventSourceImpl !== 'function') throw new Error('EventSource is required');
59
+ const callback = typeof handlers === 'function' ? handlers : handlers && handlers.onEvent;
60
+ const errorCallback = typeof onError === 'function' ? onError : handlers && handlers.onError;
61
+ const openCallback = handlers && typeof handlers === 'object' && handlers.onOpen;
62
+ const after = Number(subscribeOptions.afterSequence || handlers && handlers.afterSequence || 0);
63
+ const suffix = after > 0 ? `?after=${encodeURIComponent(after)}` : '';
64
+ const stream = new EventSourceImpl(`${apiBase}/sessions/${encodeURIComponent(sessionId)}/events${suffix}`);
65
+ streams.add(stream);
66
+ let closed = false;
67
+ const deliver = message => {
68
+ try { callback && callback(JSON.parse(message.data)); }
69
+ catch (error) { errorCallback && errorCallback(error); }
70
+ };
71
+ EVENT_TYPES.forEach(type => stream.addEventListener && stream.addEventListener(type, deliver));
72
+ stream.onmessage = deliver;
73
+ stream.onopen = () => { openCallback && openCallback(); };
74
+ stream.onerror = () => {
75
+ reconnects += 1;
76
+ errorCallback && errorCallback(new Error('SSE connection interrupted; EventSource will reconnect'));
77
+ };
78
+ const close = () => {
79
+ if (closed) return; closed = true; streams.delete(stream); stream.close();
80
+ };
81
+ return close;
82
+ }
83
+
84
+ const client = {
85
+ health: () => request('/health'),
86
+ runtime: () => request('/runtime'),
87
+ async listAgents() { const result = await request('/agents'); return result.agents || result || []; },
88
+ async listProjects() { const result = await request('/projects'); return result.projects || result || []; },
89
+ createProject(project) {
90
+ return request('/projects', { method: 'POST', body: JSON.stringify(project) });
91
+ },
92
+ getProject(id) { return request(`/projects/${encodeURIComponent(id)}`); },
93
+ renameProject(id, name) {
94
+ return request(`/projects/${encodeURIComponent(id)}`, { method: 'PATCH', body: JSON.stringify({ name }) });
95
+ },
96
+ updateProject(id, patch) {
97
+ return request(`/projects/${encodeURIComponent(id)}`, { method: 'PATCH', body: JSON.stringify(patch) });
98
+ },
99
+ removeProject(id, opts = {}) {
100
+ const qs = opts.keepSessions ? '?keepSessions=1' : '';
101
+ return request(`/projects/${encodeURIComponent(id)}${qs}`, { method: 'DELETE' });
102
+ },
103
+ async listProfiles() { const result = await request('/profiles'); return result.profiles || result || []; },
104
+ saveProfile(profile) {
105
+ const id = encodeURIComponent(profile.id);
106
+ return request(`/profiles/${id}`, { method: 'PUT', body: JSON.stringify(profile) });
107
+ },
108
+ deleteProfile(id) { return request(`/profiles/${encodeURIComponent(id)}`, { method: 'DELETE' }); },
109
+ setCredential(id, credential) {
110
+ const payload = typeof credential === 'string' ? { secret: credential } : credential;
111
+ return request(`/profiles/${encodeURIComponent(id)}/credential`, { method: 'PUT', body: JSON.stringify(payload) });
112
+ },
113
+ testProfile(id) { return request(`/profiles/${encodeURIComponent(id)}/test`, { method: 'POST', body: '{}' }); },
114
+ testProfileDraft(profile, credential = '') {
115
+ return request('/profiles/test', { method: 'POST', body: JSON.stringify({ profile, credential }) });
116
+ },
117
+ detectProfileModels(profile, credential = '') {
118
+ return request('/profiles/detect-models', { method: 'POST', body: JSON.stringify({ profile, credential }) });
119
+ },
120
+ async listSessions(context, opts = {}) {
121
+ const contextId = context && (context.contextId || context.projectId) || context;
122
+ const archived = opts.archived === true ? '&archived=1' : '';
123
+ const result = await request(`/sessions?contextId=${encodeURIComponent(contextId)}${archived}`, opts);
124
+ return result.sessions || result || [];
125
+ },
126
+ startSession(context, opts = {}) {
127
+ const payloadContext = { ...context, contextId: context.contextId || context.projectId };
128
+ const result = request('/sessions', {
129
+ method: 'POST',
130
+ body: JSON.stringify({
131
+ context: payloadContext,
132
+ aiProfileId: opts.aiProfileId !== undefined ? opts.aiProfileId : context.aiProfileId,
133
+ model: opts.model !== undefined ? opts.model : context.model,
134
+ permissionMode: opts.permissionMode || 'default',
135
+ agentId: opts.agentId || undefined,
136
+ effort: opts.effort || undefined,
137
+ }),
138
+ signal: opts.signal,
139
+ });
140
+ return result.then(r => r.session || r);
141
+ },
142
+ loadSession(id, opts = {}) { return request(`/sessions/${encodeURIComponent(id)}`, opts); },
143
+ async listCommands(id, opts = {}) {
144
+ const result = await request(`/sessions/${encodeURIComponent(id)}/commands`, opts);
145
+ return result.commands || result || [];
146
+ },
147
+ subscribe,
148
+ send(sessionOrArgs, text, opts = {}) {
149
+ const args = typeof sessionOrArgs === 'object' ? sessionOrArgs : { sessionId: sessionOrArgs, text, options: opts };
150
+ return request(`/sessions/${encodeURIComponent(args.sessionId)}/input`, {
151
+ method: 'POST', body: JSON.stringify({ text: args.text || '', attachments: args.attachments || [], options: args.options || {} }),
152
+ });
153
+ },
154
+ resolvePermission(sessionOrArgs, requestId, allow, message) {
155
+ const args = typeof sessionOrArgs === 'object' ? sessionOrArgs : { sessionId: sessionOrArgs, requestId, allow, message };
156
+ return request(`/sessions/${encodeURIComponent(args.sessionId)}/permissions/${encodeURIComponent(args.requestId)}/resolve`, {
157
+ method: 'POST', body: JSON.stringify({ allow: args.allow === true, message: args.message || '' }),
158
+ });
159
+ },
160
+ abort(sessionOrArgs) {
161
+ const id = typeof sessionOrArgs === 'object' ? sessionOrArgs.sessionId : sessionOrArgs;
162
+ return request(`/sessions/${encodeURIComponent(id)}/abort`, { method: 'POST', body: '{}' });
163
+ },
164
+ setPermissionMode(sessionOrArgs, mode) {
165
+ const args = typeof sessionOrArgs === 'object' ? sessionOrArgs : { sessionId: sessionOrArgs, mode };
166
+ return request(`/sessions/${encodeURIComponent(args.sessionId)}/permission-mode`, {
167
+ method: 'PUT', body: JSON.stringify({ mode: args.mode }),
168
+ });
169
+ },
170
+ updateSessionSelection(sessionOrArgs, selection = {}) {
171
+ const args = typeof sessionOrArgs === 'object' ? sessionOrArgs : { sessionId: sessionOrArgs, ...selection };
172
+ return request(`/sessions/${encodeURIComponent(args.sessionId)}/selection`, {
173
+ method: 'PUT',
174
+ body: JSON.stringify({ aiProfileId: args.aiProfileId !== undefined ? args.aiProfileId : selection.aiProfileId, model: args.model !== undefined ? args.model : selection.model }),
175
+ });
176
+ },
177
+ archiveSession(sessionOrArgs) {
178
+ const id = typeof sessionOrArgs === 'object' ? sessionOrArgs.sessionId : sessionOrArgs;
179
+ return request(`/sessions/${encodeURIComponent(id)}/archive`, { method: 'PUT', body: '{}' });
180
+ },
181
+ restoreSession(sessionOrArgs) {
182
+ const id = typeof sessionOrArgs === 'object' ? sessionOrArgs.sessionId : sessionOrArgs;
183
+ return request(`/sessions/${encodeURIComponent(id)}/archive`, { method: 'DELETE' });
184
+ },
185
+ resourceCounts() { return { streams: streams.size, requests: controllers.size, reconnects }; },
186
+ destroy() {
187
+ destroyed = true;
188
+ for (const stream of streams) try { stream.close(); } catch {}
189
+ streams.clear();
190
+ for (const controller of controllers) controller.abort();
191
+ controllers.clear();
192
+ },
193
+ };
194
+ return client;
195
+ }
196
+
197
+ return { createClaudeWorkbenchClient, EVENT_TYPES };
198
+ });
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@claude-ai-workbench/client",
3
+ "version": "0.11.0",
4
+ "type": "commonjs",
5
+ "main": "index.js",
6
+ "browser": "index.js",
7
+ "types": "index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./index.d.ts",
11
+ "browser": "./index.js",
12
+ "require": "./index.js",
13
+ "default": "./index.js"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "index.js",
19
+ "index.d.ts",
20
+ "README.md"
21
+ ],
22
+ "dependencies": {
23
+ "@claude-ai-workbench/contracts": "0.11.0"
24
+ },
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "license": "Apache-2.0"
29
+ }
@@ -0,0 +1,9 @@
1
+ # @claude-ai-workbench/contracts
2
+
3
+ Claude AI Workbench 的公共数据契约和 TypeScript 类型,等价于传统 SDK 的公共头文件。
4
+
5
+ ```ts
6
+ import type { AiProfile, AiProfileInput, ProfileTestResult } from "@claude-ai-workbench/contracts";
7
+ ```
8
+
9
+ 本包不包含运行时服务,也不接触 API Key。
@@ -0,0 +1,252 @@
1
+ export type PermissionMode = "default" | "acceptEdits" | "plan" | "bypassPermissions";
2
+ export type ProfileProtocol = "anthropic-compatible" | "openai-compatible" | string;
3
+ export type AgentId = "claude-code" | "codex" | "opencode" | "zcode";
4
+ export type EffortLevel = "low" | "medium" | "high" | "max";
5
+
6
+ export interface AgentCapabilities {
7
+ thinking: boolean;
8
+ permissions: boolean;
9
+ toolStream: boolean;
10
+ images: boolean;
11
+ resume: true;
12
+ modelOverride: boolean;
13
+ generationParams: readonly string[];
14
+ }
15
+
16
+ export interface AgentDefinition {
17
+ id: AgentId;
18
+ label: string;
19
+ transport: string;
20
+ authModes: readonly string[];
21
+ capabilities: AgentCapabilities;
22
+ }
23
+
24
+ export interface AgentStatus extends AgentDefinition {
25
+ capabilities: { generationParams: string[] } & Omit<AgentCapabilities, "generationParams">;
26
+ available: boolean;
27
+ version: string | null;
28
+ }
29
+
30
+ export interface Project {
31
+ id: string;
32
+ name: string;
33
+ rootPath: string;
34
+ createdAt: string;
35
+ updatedAt: string;
36
+ defaultAiProfileId?: string | null;
37
+ defaultModel?: string | null;
38
+ defaultAgentId?: AgentId;
39
+ }
40
+
41
+ export interface ProjectInput {
42
+ name: string;
43
+ rootPath: string;
44
+ defaultAiProfileId?: string | null;
45
+ defaultModel?: string | null;
46
+ defaultAgentId?: AgentId;
47
+ }
48
+
49
+ export type ProjectPatch = Partial<Omit<ProjectInput, "rootPath">>;
50
+
51
+ export interface ModelListEntry {
52
+ id: string;
53
+ openaiId?: string;
54
+ label: string;
55
+ tags: string[];
56
+ }
57
+
58
+ export interface WorkbenchContext {
59
+ contextId: string;
60
+ contextType?: string;
61
+ displayName?: string;
62
+ workspaceRef?: string;
63
+ aiProfileId?: string | null;
64
+ model?: string | null;
65
+ metadata?: Record<string, unknown>;
66
+ }
67
+
68
+ export interface AiProfileModels {
69
+ default: string;
70
+ fast?: string;
71
+ reasoning?: string;
72
+ coding?: string;
73
+ largeContext?: string;
74
+ list?: ModelListEntry[];
75
+ [role: string]: string | undefined | ModelListEntry[];
76
+ }
77
+
78
+ export interface AiProfileInput {
79
+ id: string;
80
+ name?: string;
81
+ provider: string;
82
+ protocol?: ProfileProtocol;
83
+ runtime?: "claude-code";
84
+ baseUrl: string;
85
+ openaiBaseUrl?: string;
86
+ credentialRef?: string;
87
+ models: AiProfileModels;
88
+ contextWindow?: number;
89
+ timeoutMs?: number;
90
+ permissionMode?: PermissionMode;
91
+ systemPrompt?: Record<string, unknown> | string;
92
+ enabled?: boolean;
93
+ }
94
+
95
+ export interface AiProfile extends AiProfileInput {
96
+ name: string;
97
+ protocol: ProfileProtocol;
98
+ runtime: "claude-code";
99
+ credentialRef: string;
100
+ contextWindow: number;
101
+ timeoutMs: number;
102
+ permissionMode: PermissionMode;
103
+ systemPrompt: Record<string, unknown>;
104
+ enabled: boolean;
105
+ credentialConfigured?: boolean;
106
+ credentialMasked?: string;
107
+ }
108
+
109
+ export interface CredentialInput { secret: string; }
110
+
111
+ export interface ProfileTestResult {
112
+ ok: true;
113
+ runtime: "claude-code";
114
+ runtimeVerified: true;
115
+ profileId: string;
116
+ model: string;
117
+ firstEventMs: number;
118
+ durationMs: number;
119
+ resultPreview: string;
120
+ }
121
+
122
+ export interface HealthResult {
123
+ status: "ok";
124
+ version: string;
125
+ apiVersion: string;
126
+ activeProcesses: number;
127
+ sessions: number;
128
+ time: string;
129
+ }
130
+
131
+ export interface RuntimeInfo {
132
+ runtime: "claude-code";
133
+ available: boolean;
134
+ executable: string | null;
135
+ transport: string;
136
+ }
137
+
138
+ export interface SessionSummary {
139
+ sessionId: string;
140
+ contextId: string;
141
+ projectId: string;
142
+ agentId: AgentId;
143
+ title: string;
144
+ active: boolean;
145
+ state: string;
146
+ model: string | null;
147
+ aiProfileId: string | null;
148
+ providerName?: string | null;
149
+ authSource?: "profile-injected" | "agent-owned";
150
+ selectedModel?: string | null;
151
+ permissionMode: PermissionMode;
152
+ archived: boolean;
153
+ turns: number;
154
+ startedAt: string;
155
+ updatedAt: string;
156
+ connectionState: string;
157
+ }
158
+
159
+ export interface WorkbenchEvent {
160
+ type: string;
161
+ sessionId: string;
162
+ contextId: string;
163
+ sequence: number;
164
+ at: string;
165
+ [key: string]: unknown;
166
+ }
167
+
168
+ export interface ImageAttachmentInput {
169
+ id?: string;
170
+ name: string;
171
+ mediaType: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
172
+ data: string;
173
+ size?: number;
174
+ width?: number;
175
+ height?: number;
176
+ }
177
+
178
+ export interface ImageAttachment {
179
+ id: string;
180
+ name: string;
181
+ mediaType: ImageAttachmentInput["mediaType"];
182
+ size: number;
183
+ width?: number;
184
+ height?: number;
185
+ url: string;
186
+ }
187
+
188
+ export interface TextAttachmentInput {
189
+ id?: string;
190
+ name: string;
191
+ mediaType: "text/plain" | "text/markdown" | "application/json" | "text/csv";
192
+ data: string;
193
+ size?: number;
194
+ }
195
+
196
+ export type AttachmentInput = ImageAttachmentInput | TextAttachmentInput;
197
+ export interface TextAttachment {
198
+ id: string;
199
+ name: string;
200
+ mediaType: TextAttachmentInput["mediaType"];
201
+ size: number;
202
+ url: string;
203
+ }
204
+ export type Attachment = ImageAttachment | TextAttachment;
205
+
206
+ export interface SlashCommand {
207
+ name: string;
208
+ description: string;
209
+ argumentHint?: string;
210
+ aliases?: string[];
211
+ source?: string;
212
+ }
213
+
214
+ export interface SessionSnapshot {
215
+ session: SessionSummary;
216
+ events: WorkbenchEvent[];
217
+ permission: Record<string, unknown> | null;
218
+ permissionMode: PermissionMode;
219
+ tokenUsage: Record<string, unknown>;
220
+ }
221
+
222
+ export declare const API_VERSION: "v1";
223
+ export declare const DEFAULT_API_PREFIX: "/api/claude-workbench/v1";
224
+ export declare const RUNTIME: "claude-code";
225
+ export declare const DEFAULT_AGENT: AgentId;
226
+ export declare const AGENT_IDS: readonly AgentId[];
227
+ export declare const EFFORT_LEVELS: readonly EffortLevel[];
228
+ export declare const AGENTS: Record<AgentId, AgentDefinition>;
229
+ export declare const PERMISSION_MODES: readonly PermissionMode[];
230
+ export declare const IMAGE_MEDIA_TYPES: readonly ImageAttachmentInput["mediaType"][];
231
+ export declare const TEXT_MEDIA_TYPES: readonly TextAttachmentInput["mediaType"][];
232
+ export declare const TEXT_FILE_TYPES: Readonly<Record<string, TextAttachmentInput["mediaType"]>>;
233
+ export declare const MAX_IMAGE_BYTES: number;
234
+ export declare const MAX_IMAGES_PER_MESSAGE: number;
235
+ export declare const MAX_IMAGE_MESSAGE_BYTES: number;
236
+ export declare const MAX_TEXT_BYTES: number;
237
+ export declare const MAX_ATTACHMENTS_PER_MESSAGE: number;
238
+ export declare const MAX_ATTACHMENT_MESSAGE_BYTES: number;
239
+ export declare const EVENT_TYPES: readonly string[];
240
+ export declare function cleanId(value: unknown, field?: string): string;
241
+ export declare function normalizeContext(input: unknown): WorkbenchContext;
242
+ export declare function normalizeProfile(input: unknown, idOverride?: string): AiProfile;
243
+ export declare function normalizeProject(input: unknown, idOverride?: string): Project;
244
+ export declare function normalizeAgentId(value: unknown): AgentId;
245
+ export declare function normalizeEffort(value: unknown): EffortLevel | undefined;
246
+ export declare function normalizeModelEntries(input: unknown): ModelListEntry[];
247
+ export declare function normalizeImageAttachments(input: unknown): Array<ImageAttachmentInput & { size: number }>;
248
+ export declare function normalizeAttachments(input: unknown): Array<AttachmentInput & { size: number }>;
249
+ export declare function appendTextAttachments(text: string, attachments?: AttachmentInput[]): string;
250
+ export declare function resolveOpenAIBaseUrl(profile?: Partial<AiProfileInput>): string;
251
+ export declare function resolveOpenAIModel(profile?: Partial<AiProfileInput> & { mainModel?: string }, model?: string): string;
252
+ export declare function positiveInt(value: unknown, fallback: number): number;