linkshell-cli 0.5.6 → 0.5.8
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/dist/cli/src/runtime/acp/agent-session.js +7 -1
- package/dist/cli/src/runtime/acp/agent-session.js.map +1 -1
- package/dist/cli/src/runtime/acp/claude-sdk-client.d.ts +1 -0
- package/dist/cli/src/runtime/acp/claude-sdk-client.js +67 -8
- package/dist/cli/src/runtime/acp/claude-sdk-client.js.map +1 -1
- package/dist/cli/src/runtime/acp/claude-stream-json-client.js +24 -9
- package/dist/cli/src/runtime/acp/claude-stream-json-client.js.map +1 -1
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/runtime/acp/agent-session.ts +7 -1
- package/src/runtime/acp/claude-sdk-client.ts +62 -9
- package/src/runtime/acp/claude-stream-json-client.ts +23 -9
|
@@ -434,8 +434,19 @@ export function claudePermissionModeFor(input: {
|
|
|
434
434
|
return "default";
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
const FALLBACK_MODEL_LABELS: Record<string, string> = {
|
|
438
|
+
default: "默认模型",
|
|
439
|
+
sonnet: "Sonnet",
|
|
440
|
+
opus: "Opus",
|
|
441
|
+
opusplan: "Opus Plan",
|
|
442
|
+
haiku: "Haiku",
|
|
443
|
+
"sonnet[1m]": "Sonnet 1M",
|
|
444
|
+
"opus[1m]": "Opus 1M",
|
|
445
|
+
};
|
|
446
|
+
|
|
437
447
|
export class ClaudeSdkClient {
|
|
438
448
|
private query: ClaudeQuery | undefined;
|
|
449
|
+
private startup: ((params?: { options?: Record<string, unknown>; initializeTimeoutMs?: number }) => Promise<{ query(prompt: string): AsyncGenerator<unknown> & { supportedModels(): Promise<{ value: string; displayName: string }[]>; interrupt(): Promise<void> }; close(): void }>) | undefined;
|
|
439
450
|
private claudeSessionId: string | undefined;
|
|
440
451
|
private abortController: AbortController | undefined;
|
|
441
452
|
private permissionWaiters = new Map<string, (outcome: "allow" | "deny") => void>();
|
|
@@ -461,6 +472,12 @@ export class ClaudeSdkClient {
|
|
|
461
472
|
throw new Error("Claude Agent SDK does not export query()");
|
|
462
473
|
}
|
|
463
474
|
this.query = query as ClaudeQuery;
|
|
475
|
+
// startup() pre-warms the CLI subprocess so we can discover available models
|
|
476
|
+
// without starting a full conversation (via supportedModels() on the Query).
|
|
477
|
+
const startup = (mod as { startup?: unknown }).startup;
|
|
478
|
+
if (typeof startup === "function") {
|
|
479
|
+
this.startup = startup as typeof this.startup;
|
|
480
|
+
}
|
|
464
481
|
return { status: "ok", protocol: "claude-agent-sdk" };
|
|
465
482
|
} catch (error) {
|
|
466
483
|
throw new Error(
|
|
@@ -675,27 +692,63 @@ export class ClaudeSdkClient {
|
|
|
675
692
|
|
|
676
693
|
async listModels(): Promise<unknown> {
|
|
677
694
|
let defaultModel: string = "default";
|
|
695
|
+
// Read the user's configured default model from settings.json. This is always
|
|
696
|
+
// consulted (both for live discovery and for the fallback path).
|
|
697
|
+
let availableModels: string[] | undefined;
|
|
678
698
|
try {
|
|
679
699
|
const settingsPath = join(homedir(), ".claude", "settings.json");
|
|
680
700
|
if (existsSync(settingsPath)) {
|
|
681
|
-
const raw = JSON.parse(readFileSync(settingsPath, "utf8")) as { model?: unknown };
|
|
701
|
+
const raw = JSON.parse(readFileSync(settingsPath, "utf8")) as { model?: unknown; availableModels?: unknown };
|
|
682
702
|
if (typeof raw.model === "string" && raw.model.trim().length > 0) {
|
|
683
703
|
defaultModel = raw.model.trim();
|
|
684
704
|
}
|
|
705
|
+
if (Array.isArray(raw.availableModels)) {
|
|
706
|
+
availableModels = raw.availableModels.filter((m): m is string => typeof m === "string");
|
|
707
|
+
}
|
|
685
708
|
}
|
|
686
709
|
} catch {
|
|
687
710
|
// Fallback to "default" if settings file is unreadable.
|
|
688
711
|
}
|
|
712
|
+
|
|
713
|
+
// Dynamic model discovery: use the Claude Agent SDK's startup() to get the
|
|
714
|
+
// REAL model list for THIS API key (different keys/tiers see different models).
|
|
715
|
+
// Falls back to settings.json availableModels → hardcoded list on any failure.
|
|
716
|
+
if (this.startup) {
|
|
717
|
+
let warm: Awaited<ReturnType<NonNullable<typeof this.startup>>> | undefined;
|
|
718
|
+
try {
|
|
719
|
+
warm = await this.startup({ initializeTimeoutMs: 10_000 });
|
|
720
|
+
const q = warm.query("");
|
|
721
|
+
try {
|
|
722
|
+
const sdkModels: { value: string; displayName: string }[] = await (q as unknown as { supportedModels(): Promise<{ value: string; displayName: string }[]> }).supportedModels();
|
|
723
|
+
if (sdkModels.length > 0) {
|
|
724
|
+
// Filter to admin-configured allowlist if present, then map to our format.
|
|
725
|
+
const allow = availableModels;
|
|
726
|
+
const filtered = allow
|
|
727
|
+
? sdkModels.filter((m) => allow.includes(m.value) || m.value === "default")
|
|
728
|
+
: sdkModels;
|
|
729
|
+
return {
|
|
730
|
+
defaultModel,
|
|
731
|
+
models: filtered.map((m) => ({ id: m.value, label: m.displayName || m.value })),
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
} catch {
|
|
735
|
+
// supportedModels() failed — the subprocess may be in a bad state. Close it.
|
|
736
|
+
} finally {
|
|
737
|
+
try { warm.close(); } catch { /* ignore */ }
|
|
738
|
+
}
|
|
739
|
+
} catch {
|
|
740
|
+
// startup() failed — clean up if it partially succeeded.
|
|
741
|
+
try { warm?.close(); } catch { /* ignore */ }
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Fallback: admin-configured allowlist, or the full Claude Code alias set.
|
|
746
|
+
const fallbackModels = availableModels ?? [
|
|
747
|
+
"default", "sonnet", "opus", "opusplan", "haiku", "sonnet[1m]", "opus[1m]",
|
|
748
|
+
];
|
|
689
749
|
return {
|
|
690
750
|
defaultModel,
|
|
691
|
-
models: [
|
|
692
|
-
{ id: "default", label: "默认模型" },
|
|
693
|
-
{ id: "sonnet", label: "Sonnet" },
|
|
694
|
-
{ id: "opus", label: "Opus" },
|
|
695
|
-
{ id: "haiku", label: "Haiku" },
|
|
696
|
-
{ id: "sonnet[1m]", label: "Sonnet 1M" },
|
|
697
|
-
{ id: "opusplan", label: "Opus Plan" },
|
|
698
|
-
],
|
|
751
|
+
models: fallbackModels.map((id) => ({ id, label: FALLBACK_MODEL_LABELS[id] ?? id })),
|
|
699
752
|
};
|
|
700
753
|
}
|
|
701
754
|
|
|
@@ -574,16 +574,30 @@ export class ClaudeStreamJsonClient {
|
|
|
574
574
|
}
|
|
575
575
|
|
|
576
576
|
async listModels(): Promise<unknown> {
|
|
577
|
+
let defaultModel: string = "default";
|
|
578
|
+
let availableModels: string[] | undefined;
|
|
579
|
+
try {
|
|
580
|
+
const settingsPath = join(homedir(), ".claude", "settings.json");
|
|
581
|
+
if (existsSync(settingsPath)) {
|
|
582
|
+
const raw = JSON.parse(readFileSync(settingsPath, "utf8")) as { model?: unknown; availableModels?: unknown };
|
|
583
|
+
if (typeof raw.model === "string" && raw.model.trim().length > 0) {
|
|
584
|
+
defaultModel = raw.model.trim();
|
|
585
|
+
}
|
|
586
|
+
if (Array.isArray(raw.availableModels)) {
|
|
587
|
+
availableModels = raw.availableModels.filter((m): m is string => typeof m === "string");
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
} catch {
|
|
591
|
+
// Fallback to defaults if settings file is unreadable.
|
|
592
|
+
}
|
|
593
|
+
const ids = availableModels ?? ["default", "sonnet", "opus", "opusplan", "haiku", "sonnet[1m]", "opus[1m]"];
|
|
594
|
+
const LABELS: Record<string, string> = {
|
|
595
|
+
default: "默认模型", sonnet: "Sonnet", opus: "Opus", opusplan: "Opus Plan",
|
|
596
|
+
haiku: "Haiku", "sonnet[1m]": "Sonnet 1M", "opus[1m]": "Opus 1M",
|
|
597
|
+
};
|
|
577
598
|
return {
|
|
578
|
-
defaultModel
|
|
579
|
-
models: [
|
|
580
|
-
{ id: "default", label: "默认模型" },
|
|
581
|
-
{ id: "sonnet", label: "Sonnet" },
|
|
582
|
-
{ id: "opus", label: "Opus" },
|
|
583
|
-
{ id: "haiku", label: "Haiku" },
|
|
584
|
-
{ id: "sonnet[1m]", label: "Sonnet 1M" },
|
|
585
|
-
{ id: "opusplan", label: "Opus Plan" },
|
|
586
|
-
],
|
|
599
|
+
defaultModel,
|
|
600
|
+
models: ids.map((id) => ({ id, label: LABELS[id] ?? id })),
|
|
587
601
|
};
|
|
588
602
|
}
|
|
589
603
|
|