surfcode 0.0.0-stage → 0.1.1

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 (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +325 -2
  3. package/assets/surfcode-logo.gif +0 -0
  4. package/dist/cli/auth.js +315 -0
  5. package/dist/cli/auth.js.map +1 -0
  6. package/dist/cli/config.js +228 -0
  7. package/dist/cli/config.js.map +1 -0
  8. package/dist/cli/headless.js +355 -0
  9. package/dist/cli/headless.js.map +1 -0
  10. package/dist/cli/inspect.js +462 -0
  11. package/dist/cli/inspect.js.map +1 -0
  12. package/dist/cli/interactive.js +130 -0
  13. package/dist/cli/interactive.js.map +1 -0
  14. package/dist/cli/sessions.js +170 -0
  15. package/dist/cli/sessions.js.map +1 -0
  16. package/dist/cli/sync.js +190 -0
  17. package/dist/cli/sync.js.map +1 -0
  18. package/dist/cli/util.js +345 -0
  19. package/dist/cli/util.js.map +1 -0
  20. package/dist/cli.js +485 -0
  21. package/dist/cli.js.map +1 -0
  22. package/dist/core/agent.js +298 -0
  23. package/dist/core/agent.js.map +1 -0
  24. package/dist/core/agents.js +55 -0
  25. package/dist/core/agents.js.map +1 -0
  26. package/dist/core/auth.js +107 -0
  27. package/dist/core/auth.js.map +1 -0
  28. package/dist/core/catalog.js +306 -0
  29. package/dist/core/catalog.js.map +1 -0
  30. package/dist/core/chat/anthropic.js +222 -0
  31. package/dist/core/chat/anthropic.js.map +1 -0
  32. package/dist/core/chat/common.js +367 -0
  33. package/dist/core/chat/common.js.map +1 -0
  34. package/dist/core/chat/google.js +180 -0
  35. package/dist/core/chat/google.js.map +1 -0
  36. package/dist/core/chat/index.js +80 -0
  37. package/dist/core/chat/index.js.map +1 -0
  38. package/dist/core/chat/openai.js +164 -0
  39. package/dist/core/chat/openai.js.map +1 -0
  40. package/dist/core/chat/types.js +2 -0
  41. package/dist/core/chat/types.js.map +1 -0
  42. package/dist/core/clipboard.js +34 -0
  43. package/dist/core/clipboard.js.map +1 -0
  44. package/dist/core/compact.js +39 -0
  45. package/dist/core/compact.js.map +1 -0
  46. package/dist/core/config.js +211 -0
  47. package/dist/core/config.js.map +1 -0
  48. package/dist/core/delegate.js +184 -0
  49. package/dist/core/delegate.js.map +1 -0
  50. package/dist/core/effort.js +80 -0
  51. package/dist/core/effort.js.map +1 -0
  52. package/dist/core/errors.js +32 -0
  53. package/dist/core/errors.js.map +1 -0
  54. package/dist/core/free.js +21 -0
  55. package/dist/core/free.js.map +1 -0
  56. package/dist/core/github.js +445 -0
  57. package/dist/core/github.js.map +1 -0
  58. package/dist/core/paths.js +51 -0
  59. package/dist/core/paths.js.map +1 -0
  60. package/dist/core/prompt.js +95 -0
  61. package/dist/core/prompt.js.map +1 -0
  62. package/dist/core/provider.js +298 -0
  63. package/dist/core/provider.js.map +1 -0
  64. package/dist/core/session.js +159 -0
  65. package/dist/core/session.js.map +1 -0
  66. package/dist/core/sync.js +126 -0
  67. package/dist/core/sync.js.map +1 -0
  68. package/dist/core/types.js +2 -0
  69. package/dist/core/types.js.map +1 -0
  70. package/dist/core/usage.js +127 -0
  71. package/dist/core/usage.js.map +1 -0
  72. package/dist/core/workspace.js +70 -0
  73. package/dist/core/workspace.js.map +1 -0
  74. package/dist/data/models.json +1 -0
  75. package/dist/sync/server.js +179 -0
  76. package/dist/sync/server.js.map +1 -0
  77. package/dist/tools/diff.js +21 -0
  78. package/dist/tools/diff.js.map +1 -0
  79. package/dist/tools/files.js +227 -0
  80. package/dist/tools/files.js.map +1 -0
  81. package/dist/tools/github.js +238 -0
  82. package/dist/tools/github.js.map +1 -0
  83. package/dist/tools/index.js +34 -0
  84. package/dist/tools/index.js.map +1 -0
  85. package/dist/tools/search.js +231 -0
  86. package/dist/tools/search.js.map +1 -0
  87. package/dist/tools/shell.js +118 -0
  88. package/dist/tools/shell.js.map +1 -0
  89. package/dist/tools/todos.js +50 -0
  90. package/dist/tools/todos.js.map +1 -0
  91. package/dist/tools/webfetch.js +108 -0
  92. package/dist/tools/webfetch.js.map +1 -0
  93. package/dist/tui/App.js +2984 -0
  94. package/dist/tui/App.js.map +1 -0
  95. package/dist/tui/ansi.js +151 -0
  96. package/dist/tui/ansi.js.map +1 -0
  97. package/dist/tui/commands.js +61 -0
  98. package/dist/tui/commands.js.map +1 -0
  99. package/dist/tui/explorer.js +152 -0
  100. package/dist/tui/explorer.js.map +1 -0
  101. package/dist/tui/icons.js +21 -0
  102. package/dist/tui/icons.js.map +1 -0
  103. package/dist/tui/layout.js +324 -0
  104. package/dist/tui/layout.js.map +1 -0
  105. package/dist/tui/markdown.js +355 -0
  106. package/dist/tui/markdown.js.map +1 -0
  107. package/dist/tui/overlays.js +316 -0
  108. package/dist/tui/overlays.js.map +1 -0
  109. package/dist/tui/render.js +234 -0
  110. package/dist/tui/render.js.map +1 -0
  111. package/dist/tui/theme.js +148 -0
  112. package/dist/tui/theme.js.map +1 -0
  113. package/dist/tui/types.js +73 -0
  114. package/dist/tui/types.js.map +1 -0
  115. package/dist/version.js +3 -0
  116. package/dist/version.js.map +1 -0
  117. package/package.json +75 -4
@@ -0,0 +1,298 @@
1
+ import { addUsage, costForUsage, emptyUsage } from './usage.js';
2
+ import { buildSystemPrompt } from './prompt.js';
3
+ import { streamChat } from './chat/index.js';
4
+ import { createDelegateTool } from './delegate.js';
5
+ import { isAbortError, SurfError } from './errors.js';
6
+ import { findTool, toolSchemas } from '../tools/index.js';
7
+ export async function runAgent(options) {
8
+ const { cwd, provider, model, mode, tools, callbacks, permissions, maxSteps, signal } = options;
9
+ let messages = [...options.history];
10
+ const userMessage = { role: 'user', content: options.input.trim() };
11
+ if (!userMessage.content)
12
+ throw new SurfError('The prompt is empty.');
13
+ messages.push(userMessage);
14
+ const toolsEnabled = model.meta?.tool_call !== false;
15
+ const usage = emptyUsage();
16
+ const activeTools = [...tools];
17
+ const delegateWorkers = options.delegates?.map((delegate) => `${delegate.provider.id}/${delegate.model.id}`) ?? [];
18
+ if (toolsEnabled && options.delegates?.length) {
19
+ activeTools.push(createDelegateTool({
20
+ delegates: options.delegates,
21
+ getHistory: () => messages,
22
+ signal,
23
+ cwd,
24
+ maxTokens: options.maxTokens,
25
+ temperature: options.temperature,
26
+ effort: options.effort,
27
+ onUsage(delta) {
28
+ addUsage(usage, delta);
29
+ callbacks.onUsage({ ...usage });
30
+ }
31
+ }));
32
+ }
33
+ const system = await buildSystemPrompt({
34
+ cwd,
35
+ mode,
36
+ modelName: model.name,
37
+ providerName: provider.name,
38
+ toolsEnabled,
39
+ effort: options.effort,
40
+ agentWorkers: delegateWorkers
41
+ });
42
+ const schemas = toolsEnabled ? toolSchemas(activeTools) : [];
43
+ let aborted = false;
44
+ let todos = [];
45
+ let emptyRetries = 0;
46
+ for (let step = 1; step <= maxSteps; step += 1) {
47
+ if (signal.aborted) {
48
+ aborted = true;
49
+ break;
50
+ }
51
+ callbacks.onStep?.(step, maxSteps);
52
+ let partialText = '';
53
+ let partialReasoning = '';
54
+ let result;
55
+ try {
56
+ result = await streamChat({
57
+ provider,
58
+ model,
59
+ messages,
60
+ system,
61
+ tools: schemas,
62
+ options: {
63
+ signal,
64
+ maxTokens: options.maxTokens,
65
+ temperature: options.temperature,
66
+ effort: options.effort,
67
+ showReasoning: options.showReasoning,
68
+ timeout: provider.settings.timeout
69
+ },
70
+ callbacks: {
71
+ onText: (delta) => {
72
+ partialText += delta;
73
+ callbacks.onText(delta);
74
+ },
75
+ onReasoning: (delta) => {
76
+ partialReasoning += delta;
77
+ callbacks.onReasoning(delta);
78
+ }
79
+ }
80
+ });
81
+ }
82
+ catch (error) {
83
+ if (signal.aborted || isAbortError(error)) {
84
+ aborted = true;
85
+ if (partialText || partialReasoning) {
86
+ messages.push({
87
+ role: 'assistant',
88
+ content: partialText,
89
+ ...(partialReasoning ? { reasoning: partialReasoning } : {})
90
+ });
91
+ }
92
+ break;
93
+ }
94
+ if (error instanceof Error && error.name === 'TimeoutError') {
95
+ throw new SurfError('The provider did not finish the request in time and it was aborted.', {
96
+ hint: 'Try again, switch models with /model, or raise providers.<id>.settings.timeout in the config.',
97
+ cause: error,
98
+ retryable: true
99
+ });
100
+ }
101
+ throw error;
102
+ }
103
+ const turnUsage = {
104
+ inputTokens: result.usage.inputTokens ?? 0,
105
+ outputTokens: result.usage.outputTokens ?? 0,
106
+ reasoningTokens: result.usage.reasoningTokens ?? 0,
107
+ cacheReadTokens: result.usage.cacheReadTokens ?? 0,
108
+ cacheWriteTokens: result.usage.cacheWriteTokens ?? 0,
109
+ cost: costForUsage(model.meta, result.usage, provider.dialect),
110
+ requests: 1
111
+ };
112
+ addUsage(usage, turnUsage);
113
+ callbacks.onUsage({ ...usage });
114
+ if (result.text || result.reasoning || result.toolCalls.length > 0) {
115
+ messages.push({
116
+ role: 'assistant',
117
+ content: result.text,
118
+ ...(result.reasoning ? { reasoning: result.reasoning } : {}),
119
+ ...(result.toolCalls.length > 0 ? { toolCalls: result.toolCalls } : {}),
120
+ ...(result.thinkingBlocks?.length ? { thinkingBlocks: result.thinkingBlocks } : {})
121
+ });
122
+ }
123
+ if (result.toolCalls.length === 0) {
124
+ if (result.finishReason === 'length' || result.finishReason === 'max_tokens') {
125
+ messages.push({
126
+ role: 'assistant',
127
+ content: '_Response reached the output limit. Ask me to continue if you need the rest._'
128
+ });
129
+ break;
130
+ }
131
+ // An empty response (provider hiccup, content filter, dropped stream)
132
+ // used to end the turn silently. Nudge the model once so the task
133
+ // continues instead of appearing to stop for no reason.
134
+ if (!result.text && !result.reasoning && !aborted && step < maxSteps && emptyRetries < 1) {
135
+ emptyRetries += 1;
136
+ messages.push({ role: 'user', content: '(Your previous reply was empty. Continue the task.)' });
137
+ continue;
138
+ }
139
+ break;
140
+ }
141
+ for (let index = 0; index < result.toolCalls.length; index += 1) {
142
+ const call = result.toolCalls[index];
143
+ if (signal.aborted) {
144
+ aborted = true;
145
+ for (const remaining of result.toolCalls.slice(index)) {
146
+ const cancelled = { output: 'Cancelled by user.', isError: true };
147
+ callbacks.onToolStart(remaining, findTool(activeTools, remaining.name));
148
+ callbacks.onToolResult(remaining, cancelled, 0);
149
+ messages.push({
150
+ role: 'tool',
151
+ toolCallId: remaining.id,
152
+ name: remaining.name,
153
+ content: cancelled.output,
154
+ isError: true
155
+ });
156
+ }
157
+ break;
158
+ }
159
+ const tool = findTool(activeTools, call.name);
160
+ callbacks.onToolStart(call, tool);
161
+ const started = Date.now();
162
+ let toolResult;
163
+ try {
164
+ if (call.rawArguments && Object.keys(call.arguments).length === 0) {
165
+ toolResult = {
166
+ output: `Invalid JSON arguments for ${call.name}: ${call.rawArguments.slice(0, 500)}`,
167
+ isError: true
168
+ };
169
+ }
170
+ else if (!tool) {
171
+ toolResult = {
172
+ output: `Unknown tool: ${call.name}. Available tools: ${activeTools.map((entry) => entry.name).join(', ')}.`,
173
+ isError: true
174
+ };
175
+ }
176
+ else {
177
+ toolResult = await executeWithPermission(call, tool, options, permissions, mode, callbacks, todos, (next) => {
178
+ todos = next;
179
+ callbacks.onTodos?.(next);
180
+ });
181
+ }
182
+ }
183
+ catch (error) {
184
+ if (signal.aborted || isAbortError(error)) {
185
+ toolResult = { output: 'Cancelled by user.', isError: true };
186
+ aborted = true;
187
+ }
188
+ else {
189
+ toolResult = {
190
+ output: error instanceof Error ? error.message : String(error),
191
+ isError: true
192
+ };
193
+ }
194
+ }
195
+ const duration = Date.now() - started;
196
+ callbacks.onToolResult(call, toolResult, duration);
197
+ messages.push({
198
+ role: 'tool',
199
+ toolCallId: call.id,
200
+ name: call.name,
201
+ content: toolResult.output,
202
+ ...(toolResult.isError ? { isError: true } : {})
203
+ });
204
+ if (aborted)
205
+ break;
206
+ }
207
+ if (aborted)
208
+ break;
209
+ if (step === maxSteps) {
210
+ messages.push({
211
+ role: 'assistant',
212
+ content: `_Stopped after ${maxSteps} tool steps. Ask me to continue, or raise maxSteps in the config._`
213
+ });
214
+ }
215
+ }
216
+ return { messages, usage, aborted };
217
+ }
218
+ async function executeWithPermission(call, tool, options, permissions, mode, callbacks, todos, setTodos) {
219
+ const permission = buildPermissionRequest(call, tool);
220
+ if (mode === 'plan' && !tool.readOnly) {
221
+ return {
222
+ output: `Plan mode blocked ${tool.name}. Switch to build mode to make changes.`,
223
+ isError: true,
224
+ display: { summary: 'blocked by plan mode' }
225
+ };
226
+ }
227
+ const policy = permissions[tool.action] ?? 'ask';
228
+ if (policy === 'deny') {
229
+ return {
230
+ output: `Permission denied by policy for ${tool.action}.`,
231
+ isError: true,
232
+ display: { summary: 'denied by policy' }
233
+ };
234
+ }
235
+ if (policy === 'ask') {
236
+ const decision = await callbacks.requestPermission(permission);
237
+ if (decision === 'deny') {
238
+ return {
239
+ output: 'Permission denied by user. Do not retry this exact action.',
240
+ isError: true,
241
+ display: { summary: 'denied' }
242
+ };
243
+ }
244
+ }
245
+ const context = {
246
+ cwd: options.cwd,
247
+ signal: options.signal,
248
+ allowOutsideWorkspace: options.allowOutsideWorkspace,
249
+ planMode: mode === 'plan',
250
+ requestPermission: async () => 'allow',
251
+ setTodos,
252
+ getTodos: () => todos
253
+ };
254
+ return await tool.execute(call.arguments, context);
255
+ }
256
+ function buildPermissionRequest(call, tool) {
257
+ const path = typeof call.arguments.path === 'string' ? call.arguments.path : undefined;
258
+ const command = typeof call.arguments.command === 'string' ? call.arguments.command : undefined;
259
+ const url = typeof call.arguments.url === 'string' ? call.arguments.url : undefined;
260
+ let request;
261
+ if (tool.action === 'shell') {
262
+ const risk = riskyCommand(command ?? '') ? 'high' : 'medium';
263
+ request = {
264
+ action: 'shell',
265
+ title: 'Run shell command',
266
+ detail: command,
267
+ risk,
268
+ rule: command
269
+ };
270
+ }
271
+ else if (tool.action === 'write') {
272
+ request = {
273
+ action: 'write',
274
+ title: tool.name === 'edit' ? 'Edit file' : 'Write file',
275
+ detail: path,
276
+ risk: 'medium',
277
+ rule: path
278
+ };
279
+ }
280
+ else if (tool.action === 'fetch') {
281
+ request = { action: 'fetch', title: 'Fetch URL', detail: url, risk: 'low', rule: url };
282
+ }
283
+ else {
284
+ request = {
285
+ action: 'read',
286
+ title: tool.name === 'read' ? 'Read file' : tool.name,
287
+ detail: path ?? url ?? (typeof call.arguments.pattern === 'string' ? call.arguments.pattern : undefined),
288
+ risk: 'low',
289
+ rule: path
290
+ };
291
+ }
292
+ const custom = tool.permission?.(call.arguments);
293
+ return custom ? { ...request, ...custom } : request;
294
+ }
295
+ function riskyCommand(command) {
296
+ return /(\brm\s+-[a-z]*r|\bsudo\b|\bmkfs\b|\bdd\s+if=|\bgit\s+(reset\s+--hard|clean\s+-[a-z]*f)|\bcurl\b[^|]*\|\s*(ba)?sh|\bchmod\s+-R\s+777|\bkillall\b|\bshutdown\b|\breboot\b)/i.test(command);
297
+ }
298
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/core/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { findModel, providerById } from './catalog.js';
2
+ import { resolveSelection } from './provider.js';
3
+ /**
4
+ * Worker references are always `provider/model`. Model ids may themselves
5
+ * contain slashes, so only the first slash separates the two halves.
6
+ */
7
+ export function parseWorkerRef(reference) {
8
+ const trimmed = reference.trim();
9
+ const slash = trimmed.indexOf('/');
10
+ if (slash <= 0 || slash === trimmed.length - 1)
11
+ return undefined;
12
+ return {
13
+ provider: trimmed.slice(0, slash),
14
+ model: trimmed.slice(slash + 1)
15
+ };
16
+ }
17
+ export function workerLabel(worker) {
18
+ return `${worker.provider}/${worker.model}`;
19
+ }
20
+ /**
21
+ * Resolve every configured worker against the catalog and the user's saved
22
+ * credentials. One broken worker never blocks the rest of /agent mode.
23
+ */
24
+ export async function resolveAgentWorkers(catalog, config) {
25
+ const delegates = [];
26
+ const failures = [];
27
+ const seen = new Set();
28
+ for (const worker of config.agents.workers) {
29
+ const label = workerLabel(worker);
30
+ if (seen.has(label))
31
+ continue;
32
+ seen.add(label);
33
+ if (!providerById(catalog, worker.provider)) {
34
+ failures.push(`${label} — unknown provider`);
35
+ continue;
36
+ }
37
+ if (!findModel(catalog, worker.provider, worker.model)) {
38
+ failures.push(`${label} — model not in catalog`);
39
+ continue;
40
+ }
41
+ try {
42
+ const selection = await resolveSelection(catalog, config, {
43
+ provider: worker.provider,
44
+ model: worker.model
45
+ });
46
+ delegates.push({ provider: selection.provider, model: selection.model });
47
+ }
48
+ catch (error) {
49
+ const reason = error instanceof Error ? error.message : String(error);
50
+ failures.push(`${label} — ${reason}`);
51
+ }
52
+ }
53
+ return { delegates, failures };
54
+ }
55
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/core/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAgB,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjD;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,KAAK,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACjE,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;QACjC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAmB;IAC7C,OAAO,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;AAC9C,CAAC;AAOD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAgB,EAChB,MAAkB;IAElB,MAAM,SAAS,GAAoB,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QAC9B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5C,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;YAC7C,SAAS;QACX,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACvD,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,yBAAyB,CAAC,CAAC;YACjD,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE;gBACxD,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC,CAAC;YACH,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACtE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,107 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { z } from 'zod';
3
+ import { ensurePaths, getPaths, writeFileAtomic } from './paths.js';
4
+ const authSchema = z.object({
5
+ version: z.literal(1).default(1),
6
+ keys: z.record(z.string(), z.string()).default({})
7
+ });
8
+ const LOCAL_PROVIDERS = new Set(['ollama', 'llamacpp', 'vllm', 'lmstudio']);
9
+ let cached;
10
+ export async function loadAuth(force = false) {
11
+ const paths = getPaths();
12
+ let raw;
13
+ try {
14
+ raw = await readFile(paths.authFile, 'utf8');
15
+ }
16
+ catch (error) {
17
+ if (error.code === 'ENOENT') {
18
+ cached = { version: 1, keys: {} };
19
+ return cached;
20
+ }
21
+ throw error;
22
+ }
23
+ if (cached && !force)
24
+ return cached;
25
+ try {
26
+ const parsed = authSchema.safeParse(JSON.parse(raw));
27
+ if (!parsed.success)
28
+ throw new Error('invalid shape');
29
+ cached = parsed.data;
30
+ return cached;
31
+ }
32
+ catch {
33
+ throw new Error(`Could not parse auth file at ${paths.authFile}.`);
34
+ }
35
+ }
36
+ export async function saveProviderKey(providerId, key) {
37
+ await ensurePaths();
38
+ const auth = await loadAuth(true);
39
+ auth.keys[providerId] = key.trim();
40
+ await writeFileAtomic(getPaths().authFile, `${JSON.stringify(auth, null, 2)}\n`);
41
+ cached = auth;
42
+ }
43
+ export async function removeProviderKey(providerId) {
44
+ const paths = getPaths();
45
+ const auth = await loadAuth(true);
46
+ if (!(providerId in auth.keys))
47
+ return false;
48
+ delete auth.keys[providerId];
49
+ await writeFileAtomic(paths.authFile, `${JSON.stringify(auth, null, 2)}\n`);
50
+ cached = auth;
51
+ return true;
52
+ }
53
+ export async function getStoredKey(providerId) {
54
+ const auth = await loadAuth();
55
+ return auth.keys[providerId]?.trim() || undefined;
56
+ }
57
+ export function envKeyFor(provider) {
58
+ for (const name of provider.env) {
59
+ const value = process.env[name]?.trim();
60
+ if (value)
61
+ return value;
62
+ }
63
+ return undefined;
64
+ }
65
+ export function envNameFor(provider) {
66
+ for (const name of provider.env) {
67
+ if (process.env[name]?.trim())
68
+ return name;
69
+ }
70
+ return provider.env[0];
71
+ }
72
+ export function isKeylessProvider(provider) {
73
+ if (LOCAL_PROVIDERS.has(provider.id))
74
+ return true;
75
+ if (provider.local)
76
+ return true;
77
+ // OpenAI-compatible localhost servers often do not require a key.
78
+ return typeof provider.api === 'string' && /localhost|127\.0\.0\.1|0\.0\.0\.0/.test(provider.api);
79
+ }
80
+ export async function credentialStatus(providers, config) {
81
+ const auth = await loadAuth();
82
+ return providers.map((provider) => {
83
+ const settings = config.providers[provider.id] ?? config.customProviders[provider.id] ?? {};
84
+ const envName = envNameFor(provider);
85
+ if (settings?.apiKey?.trim()) {
86
+ return { provider, configured: true, source: 'config', envName, masked: mask(settings.apiKey) };
87
+ }
88
+ if (auth.keys[provider.id]?.trim()) {
89
+ return { provider, configured: true, source: 'auth', envName, masked: mask(auth.keys[provider.id]) };
90
+ }
91
+ const envValue = envKeyFor(provider);
92
+ if (envValue) {
93
+ return { provider, configured: true, source: 'env', envName, masked: mask(envValue) };
94
+ }
95
+ if (isKeylessProvider(provider) || settings?.keyless) {
96
+ return { provider, configured: true, source: 'keyless', envName };
97
+ }
98
+ return { provider, configured: false, envName };
99
+ });
100
+ }
101
+ export function mask(key) {
102
+ const trimmed = key.trim();
103
+ if (trimmed.length <= 8)
104
+ return '••••';
105
+ return `${trimmed.slice(0, 4)}…${trimmed.slice(-4)}`;
106
+ }
107
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"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"}