@askdkc/dsh-cli 0.12.3 → 0.13.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.
- package/cordis.patch.yml +12 -131
- package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
- package/lib/types/adapter/channel/session-projection.js +0 -7
- package/lib/types/adapter/ports/channel-view.d.ts +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/dsh-adapter/bundled-presets.d.ts +3 -8
- package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/bundled-presets.js +5 -20
- package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding-events.js +2 -9
- package/lib/types/dsh-adapter/channel/external-commands.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/external-commands.js +9 -33
- package/lib/types/dsh-adapter/channel/local-actions.d.ts +2 -1
- package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/local-actions.js +6 -2
- package/lib/types/dsh-adapter/channel/model-actions.js +3 -3
- package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-switch.js +0 -1
- package/lib/types/dsh-adapter/channel/permissions.d.ts +1 -6
- package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/permissions.js +2 -54
- package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection.js +15 -70
- package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.js +2 -5
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.js +1 -4
- package/lib/types/dsh-adapter/channel/session-resume.js +2 -2
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-rewind.js +0 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.js +1 -2
- package/lib/types/dsh-adapter/channel/session-tree.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree.js +9 -62
- package/lib/types/dsh-adapter/channel/skill-catalog.js +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +2 -8
- package/lib/types/dsh-adapter/channel/transcript.d.ts +0 -16
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +0 -43
- package/lib/types/dsh-adapter/channel.js +2 -2
- package/lib/types/dsh-adapter/compat/index.d.ts +5 -25
- package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/index.js +5 -25
- package/lib/types/dsh-adapter/compat/liveSession.d.ts +12 -23
- package/lib/types/dsh-adapter/compat/liveSession.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/liveSession.js +15 -68
- package/lib/types/dsh-adapter/compat/messages.d.ts +1 -3
- package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/messages.js +2 -10
- package/lib/types/dsh-adapter/compat/persistence.d.ts +2 -3
- package/lib/types/dsh-adapter/compat/persistence.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/persistence.js +9 -14
- package/lib/types/dsh-adapter/compat/sessionLog.d.ts +10 -144
- package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/sessionLog.js +45 -275
- package/lib/types/dsh-adapter/compat/settings.d.ts +4 -10
- package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/settings.js +6 -23
- package/lib/types/dsh-adapter/compat/shell.d.ts +2 -3
- package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/shell.js +2 -7
- package/lib/types/dsh-adapter/contract.d.ts +4 -34
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +8 -83
- package/lib/types/dsh-adapter/packaged-presets.d.ts +0 -19
- package/lib/types/dsh-adapter/packaged-presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/packaged-presets.js +1 -83
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +26 -183
- package/lib/types/dsh-adapter/preset-resolution.d.ts +1 -22
- package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
- package/lib/types/dsh-adapter/preset-resolution.js +0 -34
- package/lib/types/dsh-adapter/presets.d.ts +1 -4
- package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/presets.js +3 -6
- package/lib/types/dsh-adapter/questions-answerer.d.ts +5 -43
- package/lib/types/dsh-adapter/questions-answerer.d.ts.map +1 -1
- package/lib/types/dsh-adapter/questions-answerer.js +7 -63
- package/lib/types/dsh-adapter/sessionTree.d.ts +0 -19
- package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessionTree.js +2 -112
- package/lib/types/dsh-adapter/sessions/header.d.ts +2 -2
- package/lib/types/dsh-adapter/sessions/header.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/header.js +2 -8
- package/lib/types/dsh-adapter/sessions/list.d.ts +7 -28
- package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/list.js +48 -103
- package/lib/types/dsh-adapter/sessions/store.d.ts +1 -2
- package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/store.js +7 -10
- package/lib/types/dsh-adapter/sharp.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sharp.js +0 -1
- package/lib/types/dsh-adapter/subagents.d.ts +1 -2
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +1 -12
- package/lib/types/dsh-adapter/trajectory/aggregate.d.ts +1 -1
- package/lib/types/dsh-adapter/trajectory/aggregate.js +1 -1
- package/lib/types/dsh-adapter/trajectory/guards.d.ts +5 -22
- package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/guards.js +5 -23
- package/lib/types/dsh-adapter/trajectory/projection.d.ts +5 -21
- package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/projection.js +4 -38
- package/lib/types/dsh-adapter/trajectory/types.d.ts +1 -1
- package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -1
- package/lib/types/i18n.d.ts +2 -22
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +2 -10
- package/lib/types/presetPrefs.d.ts +1 -3
- package/lib/types/presetPrefs.d.ts.map +1 -1
- package/lib/types/presetPrefs.js +2 -4
- package/lib/types/sessionHistory.d.ts +2 -0
- package/lib/types/sessionHistory.d.ts.map +1 -1
- package/lib/types/sessionHistory.js +8 -0
- package/node_modules/@askdkc/dsh-auth/README.ja.md +28 -9
- package/node_modules/@askdkc/dsh-auth/README.md +19 -8
- package/node_modules/@askdkc/dsh-auth/dsh-plugin.json +3 -3
- package/node_modules/@askdkc/dsh-auth/lib/THIRD_PARTY_NOTICES.txt +168 -0
- package/node_modules/@askdkc/dsh-auth/lib/abortable.d.ts +2 -0
- package/node_modules/@askdkc/dsh-auth/lib/abortable.js +9 -0
- package/node_modules/@askdkc/dsh-auth/lib/auth-contract.d.ts +66 -0
- package/node_modules/@askdkc/dsh-auth/lib/auth-contract.js +1 -0
- package/node_modules/@askdkc/dsh-auth/lib/command.js +15 -1
- package/node_modules/@askdkc/dsh-auth/lib/credentials.d.ts +8 -14
- package/node_modules/@askdkc/dsh-auth/lib/credentials.js +1 -1
- package/node_modules/@askdkc/dsh-auth/lib/index.d.ts +8 -28
- package/node_modules/@askdkc/dsh-auth/lib/index.js +67 -65
- package/node_modules/@askdkc/dsh-auth/lib/interaction.d.ts +5 -5
- package/node_modules/@askdkc/dsh-auth/lib/opencode-adapter.d.ts +37 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-adapter.js +206 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-catalog.d.ts +72 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-catalog.js +252 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.d.ts +6 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.js +93 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-owned.generated.d.ts +113 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-owned.generated.js +2866 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.d.ts +15 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.js +141 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.d.ts +5 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.js +43465 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.js.map +7 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-transport.d.ts +5 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-transport.js +69 -0
- package/node_modules/@askdkc/dsh-auth/lib/pi-routes.d.ts +32 -0
- package/node_modules/@askdkc/dsh-auth/lib/pi-routes.js +45 -0
- package/node_modules/@askdkc/dsh-auth/lib/profiles.d.ts +2 -20
- package/node_modules/@askdkc/dsh-auth/lib/profiles.js +6 -41
- package/node_modules/@askdkc/dsh-auth/lib/routes.d.ts +20 -0
- package/node_modules/@askdkc/dsh-auth/lib/routes.js +13 -0
- package/node_modules/@askdkc/dsh-auth/lib/service.d.ts +11 -2
- package/node_modules/@askdkc/dsh-auth/lib/service.js +26 -16
- package/node_modules/@askdkc/dsh-auth/package.json +26 -15
- package/package.json +100 -96
- package/lib/types/dsh-adapter/providerGuard.d.ts +0 -75
- package/lib/types/dsh-adapter/providerGuard.d.ts.map +0 -1
- package/lib/types/dsh-adapter/providerGuard.js +0 -104
- package/lib/types/migrationPrefs.d.ts +0 -60
- package/lib/types/migrationPrefs.d.ts.map +0 -1
- package/lib/types/migrationPrefs.js +0 -97
- package/node_modules/@askdkc/dsh-auth/lib/fresh-models.d.ts +0 -59
- package/node_modules/@askdkc/dsh-auth/lib/fresh-models.js +0 -246
- package/node_modules/@askdkc/dsh-auth/lib/opencode-snapshot.generated.d.ts +0 -321
- package/node_modules/@askdkc/dsh-auth/lib/opencode-snapshot.generated.js +0 -528
- package/presets/liangshen/.dsh-tui-managed.json +0 -5
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Protocol SDKs serialize the wire; the owned descriptor controls model settings. */
|
|
2
|
+
import type { GenerateOptions } from '@deepseek-ai/dsh-llm';
|
|
3
|
+
import type { LanguageModelV4, LanguageModelV4Prompt } from '@ai-sdk/provider';
|
|
4
|
+
import { type OpenCodeModel } from './opencode-catalog.js';
|
|
5
|
+
export declare function createTransport(descriptor: OpenCodeModel, options: GenerateOptions, apiKey: string, headers: Record<string, string>, prompt: LanguageModelV4Prompt, fetcher?: typeof fetch): LanguageModelV4;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createAnthropic, createOpenAI, createGoogleGenerativeAI, createOpenAICompatible } from './opencode-sdk.js';
|
|
2
|
+
import { OPEN_CODE_URLS } from './opencode-catalog.js';
|
|
3
|
+
export function createTransport(descriptor, options, apiKey, headers, prompt, fetcher = fetch) {
|
|
4
|
+
const baseURL = OPEN_CODE_URLS[options.provider];
|
|
5
|
+
if (!baseURL)
|
|
6
|
+
throw new Error('Unknown OpenCode route');
|
|
7
|
+
const fixedFetch = async (input, init) => {
|
|
8
|
+
const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
|
|
9
|
+
if (!new URL(url).href.startsWith(`${baseURL}/`))
|
|
10
|
+
throw new Error('OpenCode SDK attempted to leave its fixed route');
|
|
11
|
+
// SDK serializers keep their protocol codecs; all model settings come
|
|
12
|
+
// from our descriptor, overriding any SDK id-based limits or enums.
|
|
13
|
+
if (typeof init?.body === 'string') {
|
|
14
|
+
const body = JSON.parse(init.body);
|
|
15
|
+
const effort = descriptor.reasoning ? options.reasoningEffort : undefined;
|
|
16
|
+
const maxTokens = options.maxTokens ?? descriptor.maxTokens;
|
|
17
|
+
const sampling = descriptor.protocol === 'google' ? (body.generationConfig ??= {}) : body;
|
|
18
|
+
if (descriptor.temperature && options.temperature !== undefined)
|
|
19
|
+
sampling.temperature = options.temperature;
|
|
20
|
+
else
|
|
21
|
+
delete sampling.temperature;
|
|
22
|
+
switch (descriptor.protocol) {
|
|
23
|
+
case 'messages':
|
|
24
|
+
body.max_tokens = maxTokens;
|
|
25
|
+
// Effort works independently of thinking. Do not invent an
|
|
26
|
+
// adaptive mode or budget for models advertising only effort.
|
|
27
|
+
// https://platform.claude.com/docs/en/build-with-claude/effort
|
|
28
|
+
if (effort)
|
|
29
|
+
body.output_config = { ...body.output_config, effort };
|
|
30
|
+
break;
|
|
31
|
+
case 'responses': {
|
|
32
|
+
body.store = false;
|
|
33
|
+
const ids = new Map(prompt.flatMap(message => message.role === 'assistant' ? message.content.flatMap(part => part.type === 'tool-call' && typeof part.providerOptions?.openai?.itemId === 'string' ? [[part.toolCallId, part.providerOptions.openai.itemId]] : []) : []));
|
|
34
|
+
for (const item of body.input ?? [])
|
|
35
|
+
if (item.type === 'function_call' && ids.has(item.call_id))
|
|
36
|
+
item.id = ids.get(item.call_id);
|
|
37
|
+
body.max_output_tokens = maxTokens;
|
|
38
|
+
if (descriptor.reasoning) {
|
|
39
|
+
body.include = [...new Set([...(body.include ?? []), 'reasoning.encrypted_content'])];
|
|
40
|
+
if (effort)
|
|
41
|
+
body.reasoning = { effort };
|
|
42
|
+
}
|
|
43
|
+
else
|
|
44
|
+
delete body.reasoning;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case 'chat':
|
|
48
|
+
body.max_tokens = maxTokens;
|
|
49
|
+
if (effort)
|
|
50
|
+
body.reasoning_effort = effort;
|
|
51
|
+
break;
|
|
52
|
+
case 'google':
|
|
53
|
+
sampling.maxOutputTokens = maxTokens;
|
|
54
|
+
if (effort)
|
|
55
|
+
sampling.thinkingConfig = { ...sampling.thinkingConfig, thinkingLevel: effort, includeThoughts: true };
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
init = { ...init, body: JSON.stringify(body) };
|
|
59
|
+
}
|
|
60
|
+
return fetcher(input, { ...init, redirect: 'error' });
|
|
61
|
+
};
|
|
62
|
+
const settings = { baseURL, apiKey, headers, fetch: fixedFetch };
|
|
63
|
+
switch (descriptor.protocol) {
|
|
64
|
+
case 'messages': return createAnthropic(settings)(descriptor.id);
|
|
65
|
+
case 'responses': return createOpenAI(settings).responses(descriptor.id);
|
|
66
|
+
case 'google': return createGoogleGenerativeAI(settings)(descriptor.id);
|
|
67
|
+
case 'chat': return createOpenAICompatible({ ...settings, name: 'opencode' })(descriptor.id);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PiAiAdapter, type PiAiAdapterOptions } from '@deepseek-ai/dsh-llm-pi-ai';
|
|
2
|
+
import type { LlmModelInfo } from '@deepseek-ai/dsh-llm';
|
|
3
|
+
import type { PiAiAuthContext } from './pi-ai.js';
|
|
4
|
+
export { buildOAuthProfile } from './profiles.js';
|
|
5
|
+
export { createCustomProfile, CUSTOM_PROVIDER_IDS, type CustomProviderId } from './custom-profiles.js';
|
|
6
|
+
/**
|
|
7
|
+
* The ambient auth context providers may consult while resolving their own
|
|
8
|
+
* auth. `env()` answers from the process environment; `fileExists()` answers
|
|
9
|
+
* about the host process's filesystem (the paths a provider asks about —
|
|
10
|
+
* `~/.aws/credentials` and friends — are facts about where this process
|
|
11
|
+
* runs, not about the project under edit).
|
|
12
|
+
*/
|
|
13
|
+
export declare function hostAuthContext(): PiAiAuthContext;
|
|
14
|
+
/**
|
|
15
|
+
* The adapter the plugin registers: a {@link PiAiAdapter} whose *advisory
|
|
16
|
+
* catalog* is credential-gated. A provider with no stored credential
|
|
17
|
+
* lists no models — its rows never reach any model picker, which is the
|
|
18
|
+
* whole point: picking a model that would only fail with "not signed in"
|
|
19
|
+
* is noise. The gate only shapes `listModels`; `resolveModel` and requests
|
|
20
|
+
* are untouched, so a model id already saved in a session (or named
|
|
21
|
+
* explicitly) keeps resolving exactly as the registry contract promises
|
|
22
|
+
* ("advisory and never changes routing").
|
|
23
|
+
*
|
|
24
|
+
* An expired-but-stored credential still lists: token refresh runs on the
|
|
25
|
+
* next request, and a picker that hid a refreshable provider would look
|
|
26
|
+
* signed-out when it is not.
|
|
27
|
+
*/
|
|
28
|
+
export declare class CredentialGatedAdapter extends PiAiAdapter {
|
|
29
|
+
private readonly hasCredential;
|
|
30
|
+
constructor(options: PiAiAdapterOptions, hasCredential: (provider: string) => Promise<boolean>);
|
|
31
|
+
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { PiAiAdapter } from '@deepseek-ai/dsh-llm-pi-ai';
|
|
5
|
+
export { buildOAuthProfile } from './profiles.js';
|
|
6
|
+
export { createCustomProfile, CUSTOM_PROVIDER_IDS } from './custom-profiles.js';
|
|
7
|
+
/**
|
|
8
|
+
* The ambient auth context providers may consult while resolving their own
|
|
9
|
+
* auth. `env()` answers from the process environment; `fileExists()` answers
|
|
10
|
+
* about the host process's filesystem (the paths a provider asks about —
|
|
11
|
+
* `~/.aws/credentials` and friends — are facts about where this process
|
|
12
|
+
* runs, not about the project under edit).
|
|
13
|
+
*/
|
|
14
|
+
export function hostAuthContext() {
|
|
15
|
+
return {
|
|
16
|
+
env: async (name) => process.env[name],
|
|
17
|
+
fileExists: path => Promise.resolve(path.startsWith('~/') ? existsSync(join(homedir(), path.slice(2))) : existsSync(path)),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The adapter the plugin registers: a {@link PiAiAdapter} whose *advisory
|
|
22
|
+
* catalog* is credential-gated. A provider with no stored credential
|
|
23
|
+
* lists no models — its rows never reach any model picker, which is the
|
|
24
|
+
* whole point: picking a model that would only fail with "not signed in"
|
|
25
|
+
* is noise. The gate only shapes `listModels`; `resolveModel` and requests
|
|
26
|
+
* are untouched, so a model id already saved in a session (or named
|
|
27
|
+
* explicitly) keeps resolving exactly as the registry contract promises
|
|
28
|
+
* ("advisory and never changes routing").
|
|
29
|
+
*
|
|
30
|
+
* An expired-but-stored credential still lists: token refresh runs on the
|
|
31
|
+
* next request, and a picker that hid a refreshable provider would look
|
|
32
|
+
* signed-out when it is not.
|
|
33
|
+
*/
|
|
34
|
+
export class CredentialGatedAdapter extends PiAiAdapter {
|
|
35
|
+
hasCredential;
|
|
36
|
+
constructor(options, hasCredential) {
|
|
37
|
+
super(options);
|
|
38
|
+
this.hasCredential = hasCredential;
|
|
39
|
+
}
|
|
40
|
+
async listModels(provider) {
|
|
41
|
+
if (!(await this.hasCredential(provider)))
|
|
42
|
+
return [];
|
|
43
|
+
return super.listModels(provider);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -11,26 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { ResolvedPiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai';
|
|
13
13
|
import { type PiAiProvider } from './pi-ai.js';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export declare const CATALOG_PROVIDER_IDS: readonly ["openai-codex", "anthropic", "xai", "opencode", "opencode-go", "openrouter"];
|
|
17
|
-
export declare const AUTH_PROVIDER_IDS: readonly ["openai-codex", "anthropic", "xai", "opencode", "opencode-go", "openrouter", "orcarouter", "nous", "infron"];
|
|
18
|
-
export declare const PROVIDER_ALIASES: Readonly<Record<string, string>>;
|
|
19
|
-
export declare function canonicalProvider(id: string): string;
|
|
20
|
-
/** One routable provider id. */
|
|
21
|
-
export type OAuthProviderId = (typeof OAUTH_PROVIDER_IDS)[number];
|
|
22
|
-
/**
|
|
23
|
-
* One per-model catalog override a deployment may name, keyed by model id.
|
|
24
|
-
* Every field is optional; an absent field keeps the installed catalog's
|
|
25
|
-
* value, so one model's capacity can be tuned without restating the rest.
|
|
26
|
-
*/
|
|
27
|
-
export interface ModelOverride {
|
|
28
|
-
/** Override the installed catalog's context window, in tokens. */
|
|
29
|
-
contextWindow?: number;
|
|
30
|
-
/** Override the installed catalog's max output tokens. */
|
|
31
|
-
maxTokens?: number;
|
|
32
|
-
}
|
|
33
|
-
/** The OAuth flow object for one mounted route (login/refresh/toAuth live here). */
|
|
14
|
+
export { OAUTH_PROVIDER_IDS, CATALOG_PROVIDER_IDS, AUTH_PROVIDER_IDS, canonicalProvider, type ModelOverride } from './routes.js';
|
|
15
|
+
import { type ModelOverride } from './routes.js';
|
|
34
16
|
export declare function oauthOf(route: PiAiProvider): NonNullable<PiAiProvider['auth']['oauth']>;
|
|
35
17
|
/**
|
|
36
18
|
* Build the resolved profile one route registers under. Mirrors the fields
|
|
@@ -9,22 +9,10 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module dsh-auth/profiles
|
|
11
11
|
*/
|
|
12
|
-
import { randomUUID } from 'node:crypto';
|
|
13
12
|
import { resolveRetryPolicy } from '@deepseek-ai/dsh-llm';
|
|
14
13
|
import { adapterBuiltinProviders } from './pi-ai.js';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export const OAUTH_PROVIDER_IDS = ['openai-codex', 'anthropic', 'xai'];
|
|
18
|
-
export const CATALOG_PROVIDER_IDS = [...OAUTH_PROVIDER_IDS, 'opencode', 'opencode-go', 'openrouter'];
|
|
19
|
-
export const AUTH_PROVIDER_IDS = [...CATALOG_PROVIDER_IDS, 'orcarouter', 'nous', 'infron'];
|
|
20
|
-
export const PROVIDER_ALIASES = {
|
|
21
|
-
hermes: 'nous',
|
|
22
|
-
'infron.ai': 'infron',
|
|
23
|
-
'opencode-zen': 'opencode',
|
|
24
|
-
};
|
|
25
|
-
export function canonicalProvider(id) {
|
|
26
|
-
return PROVIDER_ALIASES[id] ?? id;
|
|
27
|
-
}
|
|
14
|
+
export { OAUTH_PROVIDER_IDS, CATALOG_PROVIDER_IDS, AUTH_PROVIDER_IDS, canonicalProvider } from './routes.js';
|
|
15
|
+
import { CATALOG_PROVIDER_IDS } from './routes.js';
|
|
28
16
|
/** llm-pi-ai `DEFAULT_MAX_REQUEST_IMAGE_BYTES` (20 MiB, base64 payload bound). */
|
|
29
17
|
const MAX_REQUEST_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
30
18
|
/** llm-pi-ai `DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET` (2048×2048 pixels). */
|
|
@@ -42,24 +30,6 @@ function catalogProviderOf(id) {
|
|
|
42
30
|
}
|
|
43
31
|
return found;
|
|
44
32
|
}
|
|
45
|
-
/** Add the per-request routing header that the installed pi-ai catalog omits. */
|
|
46
|
-
function withOpenCodeSessionHeader(catalog) {
|
|
47
|
-
return {
|
|
48
|
-
...catalog,
|
|
49
|
-
streamSimple(model, context, options) {
|
|
50
|
-
return catalog.streamSimple(model, context, {
|
|
51
|
-
...options,
|
|
52
|
-
headers: {
|
|
53
|
-
...options?.headers,
|
|
54
|
-
// Agent turns keep their durable id; direct calls without one still
|
|
55
|
-
// need a distinct routing identity instead of a gateway 400.
|
|
56
|
-
'x-opencode-session': options?.sessionId || randomUUID(),
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
/** The OAuth flow object for one mounted route (login/refresh/toAuth live here). */
|
|
63
33
|
export function oauthOf(route) {
|
|
64
34
|
const oauth = route.auth.oauth;
|
|
65
35
|
if (oauth === undefined) {
|
|
@@ -111,12 +81,9 @@ export function buildOAuthProfile(id, modelOverrides) {
|
|
|
111
81
|
throw new Error(`dsh-auth: "${id}" is not a catalog provider this build mounts (${CATALOG_PROVIDER_IDS.join(', ')})`);
|
|
112
82
|
}
|
|
113
83
|
const provider = catalogProviderOf(id);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// installed models always win, so this only ever adds (see fresh-models).
|
|
118
|
-
const fresh = id === 'opencode' || id === 'opencode-go' ? withFreshModels(routed, id) : routed;
|
|
119
|
-
const catalog = withModelOverrides(fresh, modelOverrides);
|
|
84
|
+
if (id === 'opencode' || id === 'opencode-go')
|
|
85
|
+
throw new Error('OpenCode uses the native adapter');
|
|
86
|
+
const catalog = withModelOverrides(provider, modelOverrides);
|
|
120
87
|
return {
|
|
121
88
|
provider: id,
|
|
122
89
|
displayName: catalog.name,
|
|
@@ -124,9 +91,7 @@ export function buildOAuthProfile(id, modelOverrides) {
|
|
|
124
91
|
retryPolicy: resolveRetryPolicy(undefined, `dsh-auth: provider "${id}" retryPolicy`),
|
|
125
92
|
configuredMaxTokens: new Map(),
|
|
126
93
|
piProvider: catalog,
|
|
127
|
-
//
|
|
128
|
-
// reports none. Older adapters never read the field, so carrying it is
|
|
129
|
-
// harmless on a pre-0.1.5 host.
|
|
94
|
+
// Per-model pre-request diagnostics.
|
|
130
95
|
modelErrors: new Map(),
|
|
131
96
|
maxRequestImageBytes: MAX_REQUEST_IMAGE_BYTES,
|
|
132
97
|
requestImagePixelBudget: REQUEST_IMAGE_PIXEL_BUDGET,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Provider identities and user-owned capacity overrides; no transport imports. */
|
|
2
|
+
/** Provider routes this build mounts, in picker order. */
|
|
3
|
+
export declare const OAUTH_PROVIDER_IDS: readonly ["openai-codex", "anthropic", "xai"];
|
|
4
|
+
export declare const CATALOG_PROVIDER_IDS: readonly ["openai-codex", "anthropic", "xai", "opencode", "opencode-go", "openrouter"];
|
|
5
|
+
export declare const AUTH_PROVIDER_IDS: readonly ["openai-codex", "anthropic", "xai", "opencode", "opencode-go", "openrouter", "orcarouter", "nous", "infron"];
|
|
6
|
+
export declare const PROVIDER_ALIASES: Readonly<Record<string, string>>;
|
|
7
|
+
export declare function canonicalProvider(id: string): string;
|
|
8
|
+
/** One routable provider id. */
|
|
9
|
+
export type OAuthProviderId = (typeof OAUTH_PROVIDER_IDS)[number];
|
|
10
|
+
/**
|
|
11
|
+
* One per-model catalog override a deployment may name, keyed by model id.
|
|
12
|
+
* Every field is optional; an absent field keeps the installed catalog's
|
|
13
|
+
* value, so one model's capacity can be tuned without restating the rest.
|
|
14
|
+
*/
|
|
15
|
+
export interface ModelOverride {
|
|
16
|
+
/** Override the installed catalog's context window, in tokens. */
|
|
17
|
+
contextWindow?: number;
|
|
18
|
+
/** Override the installed catalog's max output tokens. */
|
|
19
|
+
maxTokens?: number;
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Provider identities and user-owned capacity overrides; no transport imports. */
|
|
2
|
+
/** Provider routes this build mounts, in picker order. */
|
|
3
|
+
export const OAUTH_PROVIDER_IDS = ['openai-codex', 'anthropic', 'xai'];
|
|
4
|
+
export const CATALOG_PROVIDER_IDS = [...OAUTH_PROVIDER_IDS, 'opencode', 'opencode-go', 'openrouter'];
|
|
5
|
+
export const AUTH_PROVIDER_IDS = [...CATALOG_PROVIDER_IDS, 'orcarouter', 'nous', 'infron'];
|
|
6
|
+
export const PROVIDER_ALIASES = {
|
|
7
|
+
hermes: 'nous',
|
|
8
|
+
'infron.ai': 'infron',
|
|
9
|
+
'opencode-zen': 'opencode',
|
|
10
|
+
};
|
|
11
|
+
export function canonicalProvider(id) {
|
|
12
|
+
return PROVIDER_ALIASES[id] ?? id;
|
|
13
|
+
}
|
|
@@ -9,9 +9,15 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { Service } from '@deepseek-ai/cordis';
|
|
11
11
|
import type { Context } from '@deepseek-ai/cordis';
|
|
12
|
-
import type { ResolvedPiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai';
|
|
13
12
|
import { asStoredCredential, CredentialFile } from './credentials.js';
|
|
13
|
+
import type { OpenCodeCatalog, OpenCodeRoute, OpenCodeCatalogStatus } from './opencode-catalog.js';
|
|
14
14
|
import { type AskFn } from './interaction.js';
|
|
15
|
+
import type { OAuthFlow } from './auth-contract.js';
|
|
16
|
+
export interface AuthRoute {
|
|
17
|
+
provider: string;
|
|
18
|
+
displayName: string;
|
|
19
|
+
oauth?: OAuthFlow;
|
|
20
|
+
}
|
|
15
21
|
/** One provider's sign-in state; never carries token material. */
|
|
16
22
|
export interface DshAuthSignInStatus {
|
|
17
23
|
provider: string;
|
|
@@ -41,6 +47,8 @@ export interface DshAuthLoginResult {
|
|
|
41
47
|
export interface DshAuthApi {
|
|
42
48
|
/** Every mounted provider with masked sign-in state. */
|
|
43
49
|
providers(): Promise<readonly DshAuthSignInStatus[]>;
|
|
50
|
+
catalogStatus?(provider?: string): readonly OpenCodeCatalogStatus[];
|
|
51
|
+
refreshModels?(provider?: string, signal?: AbortSignal): Promise<readonly OpenCodeCatalogStatus[]>;
|
|
44
52
|
/**
|
|
45
53
|
* Run one provider's login. `provider` omitted asks the interactive
|
|
46
54
|
* surface to choose among providers not currently signed in.
|
|
@@ -62,7 +70,8 @@ export declare class DshAuthService extends Service {
|
|
|
62
70
|
}
|
|
63
71
|
/** Everything the api factory needs; all cordis surface is injected, so tests run without a host. */
|
|
64
72
|
export interface DshAuthApiDeps {
|
|
65
|
-
profiles: ReadonlyMap<string,
|
|
73
|
+
profiles: ReadonlyMap<string, AuthRoute>;
|
|
74
|
+
catalogs?: ReadonlyMap<OpenCodeRoute, OpenCodeCatalog>;
|
|
66
75
|
store: CredentialFile;
|
|
67
76
|
/** The interactive ask surface, resolved per call so mounting order never matters. */
|
|
68
77
|
resolveAsk: () => AskFn | undefined;
|
|
@@ -9,21 +9,14 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { Service } from '@deepseek-ai/cordis';
|
|
11
11
|
import { asStoredCredential } from './credentials.js';
|
|
12
|
-
import { canonicalProvider
|
|
12
|
+
import { canonicalProvider } from './routes.js';
|
|
13
13
|
import { QuestionBridge } from './interaction.js';
|
|
14
14
|
import { loginNous } from './nous-oauth.js';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* surfaced loudly rather than as an `undefined` dereference mid-flow.
|
|
21
|
-
*/
|
|
22
|
-
function mountedProvider(profile) {
|
|
23
|
-
if (profile.piProvider === undefined) {
|
|
24
|
-
throw new Error(`dsh-auth: provider "${profile.provider}" mounted without a constructed catalog provider`);
|
|
25
|
-
}
|
|
26
|
-
return profile.piProvider;
|
|
15
|
+
function oauthOf(profile) {
|
|
16
|
+
const oauth = profile.oauth;
|
|
17
|
+
if (!oauth)
|
|
18
|
+
throw new Error(`dsh-auth: OAuth flow unavailable for ${profile.provider}`);
|
|
19
|
+
return oauth;
|
|
27
20
|
}
|
|
28
21
|
/** Cordis service holder; `api` is set by the plugin's apply. */
|
|
29
22
|
export class DshAuthService extends Service {
|
|
@@ -61,7 +54,7 @@ export function createDshAuthApi(deps) {
|
|
|
61
54
|
const described = new Map((await deps.store.describe()).map(row => [row.provider, row]));
|
|
62
55
|
return [...deps.profiles.entries()].map(([id, profile]) => {
|
|
63
56
|
const methods = authMethodsOf(id);
|
|
64
|
-
const oauth = methods.includes('oauth') ? oauthOf(
|
|
57
|
+
const oauth = methods.includes('oauth') ? oauthOf(profile) : undefined;
|
|
65
58
|
const row = described.get(id);
|
|
66
59
|
return {
|
|
67
60
|
provider: id,
|
|
@@ -120,7 +113,7 @@ export function createDshAuthApi(deps) {
|
|
|
120
113
|
throw new Error('dsh-auth: sign-in cancelled');
|
|
121
114
|
let credential;
|
|
122
115
|
if (method === 'oauth') {
|
|
123
|
-
const oauth = oauthOf(
|
|
116
|
+
const oauth = oauthOf(profile);
|
|
124
117
|
credential = asStoredCredential(await oauth.login(bridge));
|
|
125
118
|
if (credential?.type !== 'oauth')
|
|
126
119
|
throw new Error(`dsh-auth: the ${oauth.name} flow returned an unusable credential`);
|
|
@@ -157,7 +150,7 @@ export function createDshAuthApi(deps) {
|
|
|
157
150
|
}
|
|
158
151
|
changed(provider);
|
|
159
152
|
const expiresAt = credential.type === 'oauth' && provider !== 'openrouter' ? credential.expires : undefined;
|
|
160
|
-
return { provider, oauthLabel: method === 'oauth' ? oauthOf(
|
|
153
|
+
return { provider, oauthLabel: method === 'oauth' ? oauthOf(profile).name : profile.displayName, authMethods: methods,
|
|
161
154
|
credentialKind: credential.type === 'api_key' || provider === 'openrouter' ? 'api-key' : 'oauth-token',
|
|
162
155
|
...(expiresAt === undefined ? {} : { expiresAt }),
|
|
163
156
|
...(modelWarning === undefined ? {} : { modelWarning }) };
|
|
@@ -168,6 +161,23 @@ export function createDshAuthApi(deps) {
|
|
|
168
161
|
};
|
|
169
162
|
return {
|
|
170
163
|
providers: statusOf,
|
|
164
|
+
catalogStatus: provider => [...(deps.catalogs?.values() ?? [])].filter(catalog => provider === undefined || catalog.provider === canonicalProvider(provider)).map(catalog => catalog.status()),
|
|
165
|
+
refreshModels: async (provider, signal) => {
|
|
166
|
+
signal?.throwIfAborted();
|
|
167
|
+
const selected = [...(deps.catalogs?.values() ?? [])].filter(catalog => provider === undefined || catalog.provider === canonicalProvider(provider));
|
|
168
|
+
if (!selected.length)
|
|
169
|
+
throw new Error('No matching OpenCode catalog is mounted');
|
|
170
|
+
const refresh = Promise.all(selected.map(catalog => catalog.refresh()));
|
|
171
|
+
if (!signal)
|
|
172
|
+
return refresh;
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
174
|
+
const abort = () => reject(new Error('Catalog update wait cancelled; shared background refresh may continue'));
|
|
175
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
176
|
+
void refresh.then(resolve, reject).finally(() => signal.removeEventListener('abort', abort));
|
|
177
|
+
if (signal.aborted)
|
|
178
|
+
abort();
|
|
179
|
+
});
|
|
180
|
+
},
|
|
171
181
|
login: async (provider, signal) => {
|
|
172
182
|
const ask = deps.resolveAsk();
|
|
173
183
|
let target = provider === undefined ? undefined : canonicalProvider(provider);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askdkc/dsh-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Provider authentication and model routes for DeepSeek Harness — no dsh source patch, bundled with dsh-cli",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -42,35 +42,46 @@
|
|
|
42
42
|
"node": "^22.19 || >=24"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
-
"build": "tsc -p tsconfig.json",
|
|
45
|
+
"build": "npm run clean && tsc -p tsconfig.json && node scripts/bundle-opencode.mjs",
|
|
46
46
|
"clean": "node -e \"require('node:fs').rmSync('lib', { recursive: true, force: true })\"",
|
|
47
47
|
"smoke": "node scripts/smoke.mjs",
|
|
48
|
-
"sync:models": "node scripts/sync-opencode
|
|
49
|
-
"verify": "npm run build && npm run smoke"
|
|
48
|
+
"sync:models": "node --import tsx/esm scripts/sync-owned-opencode.mjs",
|
|
49
|
+
"verify": "npm run build && npm run smoke && node --test scripts/verify-opencode.mjs && node --loader ./scripts/reject-pi-loader.mjs scripts/verify-opencode-isolated.mjs"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
53
|
-
"@deepseek-ai/dsh-attachment": "
|
|
54
|
-
"@deepseek-ai/dsh-commands": "
|
|
55
|
-
"@deepseek-ai/dsh-llm": "
|
|
56
|
-
"@deepseek-ai/dsh-llm-pi-ai": "
|
|
57
|
-
"@deepseek-ai/dsh-user-questions": "
|
|
53
|
+
"@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
|
|
54
|
+
"@deepseek-ai/dsh-commands": "0.2.0-rc.2",
|
|
55
|
+
"@deepseek-ai/dsh-llm": "0.2.0-rc.2",
|
|
56
|
+
"@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2",
|
|
57
|
+
"@deepseek-ai/dsh-user-questions": "0.2.0-rc.2",
|
|
58
58
|
"@deepseek-ai/schemastery": "^3.18.1"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
|
61
61
|
"@deepseek-ai/dsh-attachment": {
|
|
62
62
|
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"@deepseek-ai/dsh-llm-pi-ai": {
|
|
65
|
+
"optional": true
|
|
63
66
|
}
|
|
64
67
|
},
|
|
65
68
|
"devDependencies": {
|
|
66
69
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
67
|
-
"@deepseek-ai/dsh-attachment": "
|
|
68
|
-
"@deepseek-ai/dsh-commands": "
|
|
69
|
-
"@deepseek-ai/dsh-llm": "
|
|
70
|
-
"@deepseek-ai/dsh-llm-pi-ai": "
|
|
71
|
-
"@deepseek-ai/dsh-user-questions": "
|
|
70
|
+
"@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
|
|
71
|
+
"@deepseek-ai/dsh-commands": "0.2.0-rc.2",
|
|
72
|
+
"@deepseek-ai/dsh-llm": "0.2.0-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-user-questions": "0.2.0-rc.2",
|
|
72
75
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
73
76
|
"@types/node": "^22.0.0",
|
|
74
|
-
"typescript": "^6.0.3"
|
|
77
|
+
"typescript": "^6.0.3",
|
|
78
|
+
"@ai-sdk/anthropic": "4.0.71",
|
|
79
|
+
"@ai-sdk/google": "4.0.87",
|
|
80
|
+
"@ai-sdk/openai": "4.0.83",
|
|
81
|
+
"@ai-sdk/openai-compatible": "3.0.62",
|
|
82
|
+
"@ai-sdk/provider": "4.0.21",
|
|
83
|
+
"esbuild": "0.28.2",
|
|
84
|
+
"zod": "4.1.8",
|
|
85
|
+
"tsx": "4.23.13"
|
|
75
86
|
}
|
|
76
87
|
}
|