claudish 7.28.0 → 7.29.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/dist/index.js +1032 -523
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -651,7 +651,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
651
651
|
});
|
|
652
652
|
|
|
653
653
|
// src/version.ts
|
|
654
|
-
var VERSION = "7.
|
|
654
|
+
var VERSION = "7.29.1";
|
|
655
655
|
|
|
656
656
|
// src/logger.ts
|
|
657
657
|
var exports_logger = {};
|
|
@@ -37099,13 +37099,15 @@ var init_config = __esm(() => {
|
|
|
37099
37099
|
SeveritySchema = exports_external.enum(["off", "warn", "fix"]);
|
|
37100
37100
|
BehaviorConfigSchema = exports_external.object({
|
|
37101
37101
|
preset: exports_external.string().optional(),
|
|
37102
|
+
telemetry: exports_external.object({ enabled: exports_external.boolean().optional() }).optional(),
|
|
37102
37103
|
rules: exports_external.record(exports_external.string(), SeveritySchema).optional(),
|
|
37103
37104
|
hooks: exports_external.array(exports_external.string()).optional(),
|
|
37104
37105
|
observer: exports_external.object({
|
|
37105
37106
|
enabled: exports_external.boolean().optional(),
|
|
37106
|
-
mode: exports_external.enum(["off", "suggest"
|
|
37107
|
+
mode: exports_external.enum(["off", "suggest"]).optional(),
|
|
37107
37108
|
model: exports_external.string().optional(),
|
|
37108
|
-
timeoutMs: exports_external.number().int().positive().optional()
|
|
37109
|
+
timeoutMs: exports_external.number().int().positive().optional(),
|
|
37110
|
+
watchTools: exports_external.array(exports_external.string()).optional()
|
|
37109
37111
|
}).optional()
|
|
37110
37112
|
});
|
|
37111
37113
|
});
|
|
@@ -37172,17 +37174,274 @@ var init_harness = __esm(() => {
|
|
|
37172
37174
|
PLAN_MODE_HINT = /plan file|create your plan at|Plan mode is active|Plan mode still active/i;
|
|
37173
37175
|
});
|
|
37174
37176
|
|
|
37177
|
+
// src/behavior/journal.ts
|
|
37178
|
+
import { appendFile as appendFile2, mkdir, stat } from "fs/promises";
|
|
37179
|
+
import { homedir as homedir17 } from "os";
|
|
37180
|
+
import { dirname as dirname6, join as join17 } from "path";
|
|
37181
|
+
function classifyPath(observed, expected) {
|
|
37182
|
+
if (!observed)
|
|
37183
|
+
return "not_applicable";
|
|
37184
|
+
if (!expected)
|
|
37185
|
+
return "no_expectation";
|
|
37186
|
+
if (observed === expected)
|
|
37187
|
+
return "as_expected";
|
|
37188
|
+
const dirOf = (p) => p.slice(0, Math.max(0, p.lastIndexOf("/")));
|
|
37189
|
+
return dirOf(observed) === dirOf(expected) ? "same_dir_wrong_name" : "outside_expected_dir";
|
|
37190
|
+
}
|
|
37191
|
+
function journalPath() {
|
|
37192
|
+
return join17(homedir17(), ".claudish", "behavior-journal.jsonl");
|
|
37193
|
+
}
|
|
37194
|
+
async function recordDecision(entry, path = journalPath()) {
|
|
37195
|
+
try {
|
|
37196
|
+
const size = await stat(path).then((s) => s.size, () => 0);
|
|
37197
|
+
if (size > MAX_JOURNAL_BYTES) {
|
|
37198
|
+
if (!capWarned) {
|
|
37199
|
+
capWarned = true;
|
|
37200
|
+
log(`[behavior:journal] ${path} exceeded ${Math.round(MAX_JOURNAL_BYTES / 1e6)}MB \u2014 ` + "no longer recording. Archive or delete it to resume.");
|
|
37201
|
+
}
|
|
37202
|
+
return;
|
|
37203
|
+
}
|
|
37204
|
+
if (size === 0)
|
|
37205
|
+
await mkdir(dirname6(path), { recursive: true }).catch(() => {});
|
|
37206
|
+
await appendFile2(path, `${JSON.stringify(entry)}
|
|
37207
|
+
`);
|
|
37208
|
+
} catch (err) {
|
|
37209
|
+
log(`[behavior:journal] could not record: ${err}`);
|
|
37210
|
+
}
|
|
37211
|
+
}
|
|
37212
|
+
var MAX_JOURNAL_BYTES, capWarned = false;
|
|
37213
|
+
var init_journal = __esm(() => {
|
|
37214
|
+
init_logger();
|
|
37215
|
+
MAX_JOURNAL_BYTES = 32 * 1024 * 1024;
|
|
37216
|
+
});
|
|
37217
|
+
|
|
37218
|
+
// src/behavior/observer/digest.ts
|
|
37219
|
+
var exports_digest = {};
|
|
37220
|
+
__export(exports_digest, {
|
|
37221
|
+
buildDigest: () => buildDigest
|
|
37222
|
+
});
|
|
37223
|
+
function buildDigest(params) {
|
|
37224
|
+
const digest = {
|
|
37225
|
+
model: params.model,
|
|
37226
|
+
toolNames: params.toolNames.slice(0, MAX_TOOL_NAMES),
|
|
37227
|
+
harness: params.harness,
|
|
37228
|
+
ruleVocabulary: params.ruleVocabulary
|
|
37229
|
+
};
|
|
37230
|
+
if (params.call) {
|
|
37231
|
+
const paths = [];
|
|
37232
|
+
for (const [key, value] of Object.entries(params.call.args)) {
|
|
37233
|
+
if (PATH_KEYS.has(key) && typeof value === "string")
|
|
37234
|
+
paths.push(value);
|
|
37235
|
+
}
|
|
37236
|
+
digest.proposedCall = {
|
|
37237
|
+
name: params.call.name,
|
|
37238
|
+
argKeys: Object.keys(params.call.args),
|
|
37239
|
+
paths: paths.length > 0 ? paths : undefined
|
|
37240
|
+
};
|
|
37241
|
+
}
|
|
37242
|
+
return digest;
|
|
37243
|
+
}
|
|
37244
|
+
var MAX_TOOL_NAMES = 40, PATH_KEYS;
|
|
37245
|
+
var init_digest = __esm(() => {
|
|
37246
|
+
PATH_KEYS = new Set(["file_path", "path", "notebook_path", "filePath"]);
|
|
37247
|
+
});
|
|
37248
|
+
|
|
37249
|
+
// src/providers/ollama-discovery.ts
|
|
37250
|
+
function ollamaBaseUrl() {
|
|
37251
|
+
return process.env.OLLAMA_HOST || process.env.OLLAMA_BASE_URL || "http://localhost:11434";
|
|
37252
|
+
}
|
|
37253
|
+
async function fetchOllamaModels(options = {}) {
|
|
37254
|
+
const { enrichCapabilities = true } = options;
|
|
37255
|
+
const host = ollamaBaseUrl();
|
|
37256
|
+
try {
|
|
37257
|
+
const response = await fetch(`${host}/api/tags`, {
|
|
37258
|
+
signal: AbortSignal.timeout(3000)
|
|
37259
|
+
});
|
|
37260
|
+
if (!response.ok)
|
|
37261
|
+
return [];
|
|
37262
|
+
const data = await response.json();
|
|
37263
|
+
const models = data.models || [];
|
|
37264
|
+
const enriched = await Promise.all(models.map(async (m) => {
|
|
37265
|
+
let capabilities = [];
|
|
37266
|
+
if (enrichCapabilities) {
|
|
37267
|
+
try {
|
|
37268
|
+
const showResponse = await fetch(`${host}/api/show`, {
|
|
37269
|
+
method: "POST",
|
|
37270
|
+
headers: { "Content-Type": "application/json" },
|
|
37271
|
+
body: JSON.stringify({ name: m.name }),
|
|
37272
|
+
signal: AbortSignal.timeout(2000)
|
|
37273
|
+
});
|
|
37274
|
+
if (showResponse.ok) {
|
|
37275
|
+
const showData = await showResponse.json();
|
|
37276
|
+
capabilities = showData.capabilities || [];
|
|
37277
|
+
}
|
|
37278
|
+
} catch {}
|
|
37279
|
+
}
|
|
37280
|
+
const nameLower = String(m.name).toLowerCase();
|
|
37281
|
+
const supportsTools = capabilities.includes("tools");
|
|
37282
|
+
const isEmbeddingModel = capabilities.includes("embedding") || nameLower.includes("embed");
|
|
37283
|
+
const sizeInfo = m.details?.parameter_size || "unknown size";
|
|
37284
|
+
const toolsIndicator = supportsTools ? "\u2713 tools" : "\u2717 no tools";
|
|
37285
|
+
return {
|
|
37286
|
+
id: `ollama/${m.name}`,
|
|
37287
|
+
name: m.name,
|
|
37288
|
+
description: `Local Ollama model (${sizeInfo}, ${toolsIndicator})`,
|
|
37289
|
+
provider: "ollama",
|
|
37290
|
+
pricing: { prompt: "0", completion: "0" },
|
|
37291
|
+
isLocal: true,
|
|
37292
|
+
supportsTools,
|
|
37293
|
+
isEmbeddingModel,
|
|
37294
|
+
capabilities,
|
|
37295
|
+
details: m.details,
|
|
37296
|
+
size: m.size
|
|
37297
|
+
};
|
|
37298
|
+
}));
|
|
37299
|
+
return enriched.filter((m) => !m.isEmbeddingModel);
|
|
37300
|
+
} catch {
|
|
37301
|
+
return [];
|
|
37302
|
+
}
|
|
37303
|
+
}
|
|
37304
|
+
|
|
37305
|
+
// src/behavior/observer/client.ts
|
|
37306
|
+
var exports_client = {};
|
|
37307
|
+
__export(exports_client, {
|
|
37308
|
+
resetObserverModelCache: () => resetObserverModelCache,
|
|
37309
|
+
observe: () => observe
|
|
37310
|
+
});
|
|
37311
|
+
function isGenuinelyLocal(model) {
|
|
37312
|
+
if (/[-:]cloud$/i.test(model.name))
|
|
37313
|
+
return false;
|
|
37314
|
+
return (model.size ?? 0) >= MIN_LOCAL_MODEL_BYTES;
|
|
37315
|
+
}
|
|
37316
|
+
async function resolveObserverModel(config2) {
|
|
37317
|
+
if (config2.observer?.model)
|
|
37318
|
+
return config2.observer.model;
|
|
37319
|
+
if (cachedModel !== undefined)
|
|
37320
|
+
return cachedModel;
|
|
37321
|
+
try {
|
|
37322
|
+
const models = await fetchOllamaModels({ enrichCapabilities: false });
|
|
37323
|
+
const usable = models.filter((m) => !m.isEmbeddingModel && isGenuinelyLocal(m));
|
|
37324
|
+
if (usable.length === 0) {
|
|
37325
|
+
log("[behavior:observer] No local Ollama models found \u2014 observer disabled for this run");
|
|
37326
|
+
cachedModel = null;
|
|
37327
|
+
return null;
|
|
37328
|
+
}
|
|
37329
|
+
usable.sort((a, b) => (a.size ?? Number.MAX_SAFE_INTEGER) - (b.size ?? Number.MAX_SAFE_INTEGER));
|
|
37330
|
+
cachedModel = usable[0].name;
|
|
37331
|
+
log(`[behavior:observer] Using discovered local model: ${cachedModel}`);
|
|
37332
|
+
return cachedModel;
|
|
37333
|
+
} catch (err) {
|
|
37334
|
+
log(`[behavior:observer] Model discovery failed, observer disabled: ${err}`);
|
|
37335
|
+
cachedModel = null;
|
|
37336
|
+
return null;
|
|
37337
|
+
}
|
|
37338
|
+
}
|
|
37339
|
+
function resetObserverModelCache() {
|
|
37340
|
+
cachedModel = undefined;
|
|
37341
|
+
}
|
|
37342
|
+
async function observe(digest, config2) {
|
|
37343
|
+
const mode = config2.observer?.mode ?? "suggest";
|
|
37344
|
+
if (config2.observer?.enabled !== true || mode === "off")
|
|
37345
|
+
return null;
|
|
37346
|
+
const model = await resolveObserverModel(config2);
|
|
37347
|
+
if (!model)
|
|
37348
|
+
return null;
|
|
37349
|
+
const timeoutMs = config2.observer?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
37350
|
+
try {
|
|
37351
|
+
const response = await fetch(`${ollamaBaseUrl()}/api/chat`, {
|
|
37352
|
+
method: "POST",
|
|
37353
|
+
headers: { "Content-Type": "application/json" },
|
|
37354
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
37355
|
+
body: JSON.stringify({
|
|
37356
|
+
model,
|
|
37357
|
+
stream: false,
|
|
37358
|
+
format: "json",
|
|
37359
|
+
options: { temperature: 0 },
|
|
37360
|
+
messages: [
|
|
37361
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
37362
|
+
{ role: "user", content: JSON.stringify(digest) }
|
|
37363
|
+
]
|
|
37364
|
+
})
|
|
37365
|
+
});
|
|
37366
|
+
if (!response.ok) {
|
|
37367
|
+
log(`[behavior:observer] HTTP ${response.status} \u2014 skipping`);
|
|
37368
|
+
return null;
|
|
37369
|
+
}
|
|
37370
|
+
const body = await response.json();
|
|
37371
|
+
const content = body?.message?.content;
|
|
37372
|
+
if (typeof content !== "string")
|
|
37373
|
+
return null;
|
|
37374
|
+
const parsed = JSON.parse(content);
|
|
37375
|
+
const ruleId = typeof parsed?.ruleId === "string" ? parsed.ruleId : null;
|
|
37376
|
+
if (ruleId && !digest.ruleVocabulary.includes(ruleId)) {
|
|
37377
|
+
log(`[behavior:observer] Discarding unknown ruleId "${ruleId}"`);
|
|
37378
|
+
return null;
|
|
37379
|
+
}
|
|
37380
|
+
return {
|
|
37381
|
+
ruleId,
|
|
37382
|
+
confidence: typeof parsed?.confidence === "number" ? parsed.confidence : 0,
|
|
37383
|
+
note: typeof parsed?.note === "string" ? parsed.note : undefined
|
|
37384
|
+
};
|
|
37385
|
+
} catch (err) {
|
|
37386
|
+
log(`[behavior:observer] Skipped: ${err instanceof Error ? err.message : err}`);
|
|
37387
|
+
return null;
|
|
37388
|
+
}
|
|
37389
|
+
}
|
|
37390
|
+
var DEFAULT_TIMEOUT_MS2 = 1500, SYSTEM_PROMPT = `You audit an AI coding agent for violations of Claude Code's conventions.
|
|
37391
|
+
You receive a JSON digest: the tools available, detected harness state, and the tool call the agent proposes.
|
|
37392
|
+
Decide whether the proposed call violates one of the rules listed in ruleVocabulary.
|
|
37393
|
+
|
|
37394
|
+
Reply with ONLY a JSON object, no prose:
|
|
37395
|
+
{"ruleId": "<id from ruleVocabulary, or null>", "confidence": <0-1>, "note": "<short reason>"}
|
|
37396
|
+
|
|
37397
|
+
Return ruleId null unless you are confident. A false positive is worse than a miss.`, MIN_LOCAL_MODEL_BYTES, cachedModel;
|
|
37398
|
+
var init_client = __esm(() => {
|
|
37399
|
+
init_logger();
|
|
37400
|
+
MIN_LOCAL_MODEL_BYTES = 50 * 1024 * 1024;
|
|
37401
|
+
});
|
|
37402
|
+
|
|
37403
|
+
// src/behavior/observer/live-log.ts
|
|
37404
|
+
var exports_live_log = {};
|
|
37405
|
+
__export(exports_live_log, {
|
|
37406
|
+
recordLiveDivergence: () => recordLiveDivergence
|
|
37407
|
+
});
|
|
37408
|
+
import { appendFile as appendFile3 } from "fs/promises";
|
|
37409
|
+
import { homedir as homedir18 } from "os";
|
|
37410
|
+
import { join as join18 } from "path";
|
|
37411
|
+
function defaultPath() {
|
|
37412
|
+
return join18(homedir18(), ".claudish", "behavior-divergences.jsonl");
|
|
37413
|
+
}
|
|
37414
|
+
async function recordLiveDivergence(entry, path = defaultPath()) {
|
|
37415
|
+
try {
|
|
37416
|
+
await appendFile3(path, `${JSON.stringify(entry)}
|
|
37417
|
+
`);
|
|
37418
|
+
} catch (err) {
|
|
37419
|
+
log(`[behavior:observer] could not append divergence: ${err}`);
|
|
37420
|
+
}
|
|
37421
|
+
}
|
|
37422
|
+
var init_live_log = __esm(() => {
|
|
37423
|
+
init_logger();
|
|
37424
|
+
});
|
|
37425
|
+
|
|
37175
37426
|
// src/behavior/engine.ts
|
|
37176
37427
|
class BehaviorSession {
|
|
37177
37428
|
active;
|
|
37178
37429
|
modelId;
|
|
37179
37430
|
providerName;
|
|
37431
|
+
config;
|
|
37180
37432
|
facts = { planModeActive: false };
|
|
37181
37433
|
bufferedTools = new Set;
|
|
37182
|
-
constructor(active, modelId, providerName) {
|
|
37434
|
+
constructor(active, modelId, providerName, config2 = {}) {
|
|
37183
37435
|
this.active = active;
|
|
37184
37436
|
this.modelId = modelId;
|
|
37185
37437
|
this.providerName = providerName;
|
|
37438
|
+
this.config = config2;
|
|
37439
|
+
}
|
|
37440
|
+
get observerOn() {
|
|
37441
|
+
return this.config.observer?.enabled === true && (this.config.observer.mode ?? "suggest") !== "off";
|
|
37442
|
+
}
|
|
37443
|
+
observerWatchList() {
|
|
37444
|
+
return this.config.observer?.watchTools ?? ["Write", "Edit", "NotebookEdit", "ExitPlanMode"];
|
|
37186
37445
|
}
|
|
37187
37446
|
armBuffering() {
|
|
37188
37447
|
const armed = new Set;
|
|
@@ -37194,6 +37453,10 @@ class BehaviorSession {
|
|
|
37194
37453
|
for (const t of rule.interceptsTools ?? [])
|
|
37195
37454
|
armed.add(t);
|
|
37196
37455
|
}
|
|
37456
|
+
if (this.observerOn) {
|
|
37457
|
+
for (const t of this.observerWatchList())
|
|
37458
|
+
armed.add(t);
|
|
37459
|
+
}
|
|
37197
37460
|
this.bufferedTools = armed;
|
|
37198
37461
|
}
|
|
37199
37462
|
get harness() {
|
|
@@ -37275,13 +37538,80 @@ class BehaviorSession {
|
|
|
37275
37538
|
log(`[behavior] ${rule.id} (warn-only, not applied): ${action.reason}`);
|
|
37276
37539
|
continue;
|
|
37277
37540
|
}
|
|
37541
|
+
this.journal("tool_call", "repaired", {
|
|
37542
|
+
ruleId: rule.id,
|
|
37543
|
+
toolName,
|
|
37544
|
+
argKeys: Object.keys(args),
|
|
37545
|
+
observedPath: typeof args.file_path === "string" ? args.file_path : undefined,
|
|
37546
|
+
expectedPath: this.facts.planFilePath,
|
|
37547
|
+
note: action.reason
|
|
37548
|
+
});
|
|
37278
37549
|
args = action.args;
|
|
37279
37550
|
changed = true;
|
|
37280
37551
|
log(`[behavior] ${rule.id} repaired ${toolName}: ${action.reason}`);
|
|
37281
37552
|
}
|
|
37282
37553
|
}
|
|
37554
|
+
if (!changed) {
|
|
37555
|
+
this.journal("tool_call", "ignored", {
|
|
37556
|
+
toolName,
|
|
37557
|
+
argKeys: Object.keys(args),
|
|
37558
|
+
observedPath: typeof args.file_path === "string" ? args.file_path : undefined,
|
|
37559
|
+
expectedPath: this.facts.planFilePath
|
|
37560
|
+
});
|
|
37561
|
+
}
|
|
37562
|
+
if (this.observerOn && !changed) {
|
|
37563
|
+
this.consultObserver(toolName, args);
|
|
37564
|
+
}
|
|
37283
37565
|
return changed ? JSON.stringify(args) : null;
|
|
37284
37566
|
}
|
|
37567
|
+
journal(surface, decision, detail) {
|
|
37568
|
+
recordDecision({
|
|
37569
|
+
ts: new Date().toISOString(),
|
|
37570
|
+
model: this.modelId,
|
|
37571
|
+
provider: this.providerName,
|
|
37572
|
+
surface,
|
|
37573
|
+
decision,
|
|
37574
|
+
ruleId: detail.ruleId,
|
|
37575
|
+
toolName: detail.toolName,
|
|
37576
|
+
argKeys: detail.argKeys,
|
|
37577
|
+
pathRelation: classifyPath(detail.observedPath, detail.expectedPath),
|
|
37578
|
+
local: {
|
|
37579
|
+
observedPath: detail.observedPath,
|
|
37580
|
+
expectedPath: detail.expectedPath,
|
|
37581
|
+
note: detail.note
|
|
37582
|
+
}
|
|
37583
|
+
});
|
|
37584
|
+
}
|
|
37585
|
+
async consultObserver(toolName, args) {
|
|
37586
|
+
try {
|
|
37587
|
+
const { buildDigest: buildDigest2 } = await Promise.resolve().then(() => (init_digest(), exports_digest));
|
|
37588
|
+
const { observe: observe2 } = await Promise.resolve().then(() => (init_client(), exports_client));
|
|
37589
|
+
const { recordLiveDivergence: recordLiveDivergence2 } = await Promise.resolve().then(() => (init_live_log(), exports_live_log));
|
|
37590
|
+
const digest = buildDigest2({
|
|
37591
|
+
model: this.modelId,
|
|
37592
|
+
toolNames: [...this.bufferedTools],
|
|
37593
|
+
harness: this.facts,
|
|
37594
|
+
ruleVocabulary: this.active.map((a) => a.rule.id),
|
|
37595
|
+
call: { name: toolName, args }
|
|
37596
|
+
});
|
|
37597
|
+
const verdict = await observe2(digest, this.config);
|
|
37598
|
+
if (!verdict?.ruleId)
|
|
37599
|
+
return;
|
|
37600
|
+
log(`[behavior:observer] flagged ${toolName} as ${verdict.ruleId} (confidence ${verdict.confidence})${verdict.note ? `: ${verdict.note}` : ""}`);
|
|
37601
|
+
await recordLiveDivergence2({
|
|
37602
|
+
source: "observer",
|
|
37603
|
+
ts: new Date().toISOString(),
|
|
37604
|
+
model: this.modelId,
|
|
37605
|
+
toolName,
|
|
37606
|
+
ruleId: verdict.ruleId,
|
|
37607
|
+
confidence: verdict.confidence,
|
|
37608
|
+
note: verdict.note,
|
|
37609
|
+
paths: digest.proposedCall?.paths
|
|
37610
|
+
});
|
|
37611
|
+
} catch (err) {
|
|
37612
|
+
log(`[behavior:observer] consult failed: ${err}`);
|
|
37613
|
+
}
|
|
37614
|
+
}
|
|
37285
37615
|
applyAction(ruleId, severity, action, ctx) {
|
|
37286
37616
|
if (action.type === "warn") {
|
|
37287
37617
|
log(`[behavior] ${ruleId} (warn): ${action.message}`);
|
|
@@ -37359,13 +37689,14 @@ class BehaviorEngine {
|
|
|
37359
37689
|
if (active.length > 0) {
|
|
37360
37690
|
log(`[behavior] ${active.length} rule(s) active for ${params.modelId}: ` + active.map((a) => `${a.rule.id}=${a.severity}`).join(", "));
|
|
37361
37691
|
}
|
|
37362
|
-
return new BehaviorSession(active, params.modelId, params.providerName);
|
|
37692
|
+
return new BehaviorSession(active, params.modelId, params.providerName, this.config);
|
|
37363
37693
|
}
|
|
37364
37694
|
}
|
|
37365
37695
|
var init_engine = __esm(() => {
|
|
37366
37696
|
init_logger();
|
|
37367
37697
|
init_config();
|
|
37368
37698
|
init_harness();
|
|
37699
|
+
init_journal();
|
|
37369
37700
|
});
|
|
37370
37701
|
|
|
37371
37702
|
// src/behavior/rules/plan-mode.ts
|
|
@@ -37497,75 +37828,118 @@ var init_hooks = __esm(() => {
|
|
|
37497
37828
|
init_logger();
|
|
37498
37829
|
});
|
|
37499
37830
|
|
|
37500
|
-
// src/behavior/observer/
|
|
37501
|
-
|
|
37502
|
-
|
|
37503
|
-
|
|
37504
|
-
|
|
37505
|
-
|
|
37506
|
-
|
|
37507
|
-
function ollamaBaseUrl() {
|
|
37508
|
-
return process.env.OLLAMA_HOST || process.env.OLLAMA_BASE_URL || "http://localhost:11434";
|
|
37831
|
+
// src/behavior/observer/corpus.ts
|
|
37832
|
+
import { appendFileSync as appendFileSync3, readFileSync as readFileSync12, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
37833
|
+
import { homedir as homedir19 } from "os";
|
|
37834
|
+
import { join as join19 } from "path";
|
|
37835
|
+
function directoryOf2(filePath) {
|
|
37836
|
+
const slash = filePath.lastIndexOf("/");
|
|
37837
|
+
return slash > 0 ? filePath.slice(0, slash) : undefined;
|
|
37509
37838
|
}
|
|
37510
|
-
|
|
37511
|
-
const
|
|
37512
|
-
|
|
37839
|
+
function writeTargetsOf(row) {
|
|
37840
|
+
const content = row?.message?.content;
|
|
37841
|
+
if (!Array.isArray(content))
|
|
37842
|
+
return [];
|
|
37843
|
+
const paths = [];
|
|
37844
|
+
for (const block of content) {
|
|
37845
|
+
if (block?.type !== "tool_use" || !WRITE_TOOLS2.has(block.name))
|
|
37846
|
+
continue;
|
|
37847
|
+
const p = block.input?.file_path;
|
|
37848
|
+
if (typeof p === "string")
|
|
37849
|
+
paths.push(p);
|
|
37850
|
+
}
|
|
37851
|
+
return paths;
|
|
37852
|
+
}
|
|
37853
|
+
function replayTranscript(file2) {
|
|
37854
|
+
let text;
|
|
37513
37855
|
try {
|
|
37514
|
-
|
|
37515
|
-
signal: AbortSignal.timeout(3000)
|
|
37516
|
-
});
|
|
37517
|
-
if (!response.ok)
|
|
37518
|
-
return [];
|
|
37519
|
-
const data = await response.json();
|
|
37520
|
-
const models = data.models || [];
|
|
37521
|
-
const enriched = await Promise.all(models.map(async (m) => {
|
|
37522
|
-
let capabilities = [];
|
|
37523
|
-
if (enrichCapabilities) {
|
|
37524
|
-
try {
|
|
37525
|
-
const showResponse = await fetch(`${host}/api/show`, {
|
|
37526
|
-
method: "POST",
|
|
37527
|
-
headers: { "Content-Type": "application/json" },
|
|
37528
|
-
body: JSON.stringify({ name: m.name }),
|
|
37529
|
-
signal: AbortSignal.timeout(2000)
|
|
37530
|
-
});
|
|
37531
|
-
if (showResponse.ok) {
|
|
37532
|
-
const showData = await showResponse.json();
|
|
37533
|
-
capabilities = showData.capabilities || [];
|
|
37534
|
-
}
|
|
37535
|
-
} catch {}
|
|
37536
|
-
}
|
|
37537
|
-
const nameLower = String(m.name).toLowerCase();
|
|
37538
|
-
const supportsTools = capabilities.includes("tools");
|
|
37539
|
-
const isEmbeddingModel = capabilities.includes("embedding") || nameLower.includes("embed");
|
|
37540
|
-
const sizeInfo = m.details?.parameter_size || "unknown size";
|
|
37541
|
-
const toolsIndicator = supportsTools ? "\u2713 tools" : "\u2717 no tools";
|
|
37542
|
-
return {
|
|
37543
|
-
id: `ollama/${m.name}`,
|
|
37544
|
-
name: m.name,
|
|
37545
|
-
description: `Local Ollama model (${sizeInfo}, ${toolsIndicator})`,
|
|
37546
|
-
provider: "ollama",
|
|
37547
|
-
pricing: { prompt: "0", completion: "0" },
|
|
37548
|
-
isLocal: true,
|
|
37549
|
-
supportsTools,
|
|
37550
|
-
isEmbeddingModel,
|
|
37551
|
-
capabilities,
|
|
37552
|
-
details: m.details,
|
|
37553
|
-
size: m.size
|
|
37554
|
-
};
|
|
37555
|
-
}));
|
|
37556
|
-
return enriched.filter((m) => !m.isEmbeddingModel);
|
|
37856
|
+
text = readFileSync12(file2, "utf8");
|
|
37557
37857
|
} catch {
|
|
37558
37858
|
return [];
|
|
37559
37859
|
}
|
|
37860
|
+
if (!text.includes("ExitPlanMode"))
|
|
37861
|
+
return [];
|
|
37862
|
+
const out = [];
|
|
37863
|
+
const planWrites = [];
|
|
37864
|
+
let lastModel;
|
|
37865
|
+
for (const line of text.split(`
|
|
37866
|
+
`)) {
|
|
37867
|
+
if (!line)
|
|
37868
|
+
continue;
|
|
37869
|
+
let row;
|
|
37870
|
+
try {
|
|
37871
|
+
row = JSON.parse(line);
|
|
37872
|
+
} catch {
|
|
37873
|
+
continue;
|
|
37874
|
+
}
|
|
37875
|
+
if (row?.message?.role === "assistant" && typeof row?.message?.model === "string") {
|
|
37876
|
+
lastModel = row.message.model;
|
|
37877
|
+
}
|
|
37878
|
+
planWrites.push(...writeTargetsOf(row));
|
|
37879
|
+
const record4 = divergenceOf(row, file2, planWrites, lastModel);
|
|
37880
|
+
if (record4)
|
|
37881
|
+
out.push(record4);
|
|
37882
|
+
}
|
|
37883
|
+
return out;
|
|
37560
37884
|
}
|
|
37561
|
-
|
|
37562
|
-
|
|
37563
|
-
|
|
37564
|
-
|
|
37565
|
-
|
|
37566
|
-
|
|
37567
|
-
|
|
37568
|
-
|
|
37885
|
+
function divergenceOf(row, file2, planWrites, lastModel) {
|
|
37886
|
+
const result = row?.toolUseResult;
|
|
37887
|
+
if (!result || typeof result !== "object")
|
|
37888
|
+
return null;
|
|
37889
|
+
if (!("plan" in result) || typeof result.filePath !== "string")
|
|
37890
|
+
return null;
|
|
37891
|
+
const assignedPath = result.filePath;
|
|
37892
|
+
const planDir = directoryOf2(assignedPath);
|
|
37893
|
+
const observedPaths = planDir ? [...new Set(planWrites.filter((p) => directoryOf2(p) === planDir && p !== assignedPath))] : [];
|
|
37894
|
+
return {
|
|
37895
|
+
transcript: file2,
|
|
37896
|
+
timestamp: row?.timestamp,
|
|
37897
|
+
model: row?.message?.model ?? lastModel,
|
|
37898
|
+
ruleId: RULE_ID,
|
|
37899
|
+
assignedPath,
|
|
37900
|
+
observedPaths,
|
|
37901
|
+
outcome: result.plan === null ? "degraded" : "ok"
|
|
37902
|
+
};
|
|
37903
|
+
}
|
|
37904
|
+
function listTranscripts(root) {
|
|
37905
|
+
const files = [];
|
|
37906
|
+
let projects;
|
|
37907
|
+
try {
|
|
37908
|
+
projects = readdirSync2(root);
|
|
37909
|
+
} catch {
|
|
37910
|
+
return files;
|
|
37911
|
+
}
|
|
37912
|
+
for (const project of projects) {
|
|
37913
|
+
const dir = join19(root, project);
|
|
37914
|
+
try {
|
|
37915
|
+
if (!statSync2(dir).isDirectory())
|
|
37916
|
+
continue;
|
|
37917
|
+
for (const f of readdirSync2(dir)) {
|
|
37918
|
+
if (f.endsWith(".jsonl"))
|
|
37919
|
+
files.push(join19(dir, f));
|
|
37920
|
+
}
|
|
37921
|
+
} catch {}
|
|
37922
|
+
}
|
|
37923
|
+
return files;
|
|
37924
|
+
}
|
|
37925
|
+
function buildCorpus(options = {}) {
|
|
37926
|
+
const root = options.projectsRoot ?? join19(homedir19(), ".claude", "projects");
|
|
37927
|
+
const files = listTranscripts(root);
|
|
37928
|
+
const records = [];
|
|
37929
|
+
for (const f of files)
|
|
37930
|
+
records.push(...replayTranscript(f));
|
|
37931
|
+
if (options.write && records.length > 0) {
|
|
37932
|
+
const outputPath = options.outputPath ?? join19(homedir19(), ".claudish", "behavior-divergences.jsonl");
|
|
37933
|
+
try {
|
|
37934
|
+
appendFileSync3(outputPath, `${records.map((r) => JSON.stringify(r)).join(`
|
|
37935
|
+
`)}
|
|
37936
|
+
`);
|
|
37937
|
+
return { scanned: files.length, records, outputPath };
|
|
37938
|
+
} catch {}
|
|
37939
|
+
}
|
|
37940
|
+
return { scanned: files.length, records };
|
|
37941
|
+
}
|
|
37942
|
+
var RULE_ID = "plan-mode/plan-file-path", WRITE_TOOLS2;
|
|
37569
37943
|
var init_corpus = __esm(() => {
|
|
37570
37944
|
WRITE_TOOLS2 = new Set(["Write", "Edit", "NotebookEdit"]);
|
|
37571
37945
|
});
|
|
@@ -37979,7 +38353,7 @@ var init_openai = __esm(() => {
|
|
|
37979
38353
|
});
|
|
37980
38354
|
|
|
37981
38355
|
// src/providers/catalog-query.ts
|
|
37982
|
-
import { statSync as
|
|
38356
|
+
import { statSync as statSync3 } from "fs";
|
|
37983
38357
|
function project(entry) {
|
|
37984
38358
|
return {
|
|
37985
38359
|
modelId: entry.modelId,
|
|
@@ -37992,7 +38366,7 @@ function project(entry) {
|
|
|
37992
38366
|
function getCachedEntries() {
|
|
37993
38367
|
let mtimeMs;
|
|
37994
38368
|
try {
|
|
37995
|
-
mtimeMs =
|
|
38369
|
+
mtimeMs = statSync3(ALL_MODELS_CACHE_PATH).mtimeMs;
|
|
37996
38370
|
} catch {
|
|
37997
38371
|
return null;
|
|
37998
38372
|
}
|
|
@@ -38168,13 +38542,13 @@ var init_vision_proxy = __esm(() => {
|
|
|
38168
38542
|
import {
|
|
38169
38543
|
existsSync as existsSync14,
|
|
38170
38544
|
mkdirSync as mkdirSync9,
|
|
38171
|
-
readFileSync as
|
|
38545
|
+
readFileSync as readFileSync13,
|
|
38172
38546
|
renameSync,
|
|
38173
38547
|
unlinkSync as unlinkSync5,
|
|
38174
38548
|
writeFileSync as writeFileSync9
|
|
38175
38549
|
} from "fs";
|
|
38176
|
-
import { homedir as
|
|
38177
|
-
import { join as
|
|
38550
|
+
import { homedir as homedir20 } from "os";
|
|
38551
|
+
import { join as join20 } from "path";
|
|
38178
38552
|
function ensureDir() {
|
|
38179
38553
|
if (!existsSync14(CLAUDISH_DIR)) {
|
|
38180
38554
|
mkdirSync9(CLAUDISH_DIR, { recursive: true });
|
|
@@ -38184,7 +38558,7 @@ function readFromDisk() {
|
|
|
38184
38558
|
try {
|
|
38185
38559
|
if (!existsSync14(BUFFER_FILE))
|
|
38186
38560
|
return [];
|
|
38187
|
-
const raw2 =
|
|
38561
|
+
const raw2 = readFileSync13(BUFFER_FILE, "utf-8");
|
|
38188
38562
|
const parsed = JSON.parse(raw2);
|
|
38189
38563
|
if (!Array.isArray(parsed.events))
|
|
38190
38564
|
return [];
|
|
@@ -38209,7 +38583,7 @@ function writeToDisk(events) {
|
|
|
38209
38583
|
ensureDir();
|
|
38210
38584
|
const trimmed = enforceSizeCap([...events]);
|
|
38211
38585
|
const payload = { version: 1, events: trimmed };
|
|
38212
|
-
const tmpFile =
|
|
38586
|
+
const tmpFile = join20(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
|
|
38213
38587
|
writeFileSync9(tmpFile, JSON.stringify(payload, null, 2), "utf-8");
|
|
38214
38588
|
renameSync(tmpFile, BUFFER_FILE);
|
|
38215
38589
|
memoryCache = trimmed;
|
|
@@ -38282,8 +38656,8 @@ function syncFlushOnExit() {
|
|
|
38282
38656
|
var BUFFER_MAX_BYTES, CLAUDISH_DIR, BUFFER_FILE, memoryCache = null, eventsSinceLastFlush = 0, flushScheduled = false;
|
|
38283
38657
|
var init_stats_buffer = __esm(() => {
|
|
38284
38658
|
BUFFER_MAX_BYTES = 64 * 1024;
|
|
38285
|
-
CLAUDISH_DIR =
|
|
38286
|
-
BUFFER_FILE =
|
|
38659
|
+
CLAUDISH_DIR = join20(homedir20(), ".claudish");
|
|
38660
|
+
BUFFER_FILE = join20(CLAUDISH_DIR, "stats-buffer.json");
|
|
38287
38661
|
process.on("exit", syncFlushOnExit);
|
|
38288
38662
|
process.on("SIGTERM", () => {
|
|
38289
38663
|
try {
|
|
@@ -40564,8 +40938,8 @@ var init_openai_responses_sse = __esm(() => {
|
|
|
40564
40938
|
|
|
40565
40939
|
// src/handlers/shared/token-tracker.ts
|
|
40566
40940
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
40567
|
-
import { homedir as
|
|
40568
|
-
import { dirname as
|
|
40941
|
+
import { homedir as homedir21 } from "os";
|
|
40942
|
+
import { dirname as dirname7, join as join21 } from "path";
|
|
40569
40943
|
|
|
40570
40944
|
class TokenTracker {
|
|
40571
40945
|
port;
|
|
@@ -40709,8 +41083,8 @@ class TokenTracker {
|
|
|
40709
41083
|
data.quota_remaining = this.quotaRemaining;
|
|
40710
41084
|
}
|
|
40711
41085
|
const override = process.env.CLAUDISH_TOKEN_FILE;
|
|
40712
|
-
const outPath = override ||
|
|
40713
|
-
mkdirSync10(
|
|
41086
|
+
const outPath = override || join21(homedir21(), ".claudish", `tokens-${this.port}.json`);
|
|
41087
|
+
mkdirSync10(dirname7(outPath), { recursive: true });
|
|
40714
41088
|
writeFileSync10(outPath, JSON.stringify(data), "utf-8");
|
|
40715
41089
|
} catch (e) {
|
|
40716
41090
|
log(`[TokenTracker] Error writing token file: ${e}`);
|
|
@@ -41556,7 +41930,7 @@ var init_fallback_handler = __esm(() => {
|
|
|
41556
41930
|
});
|
|
41557
41931
|
|
|
41558
41932
|
// src/handlers/native-handler-advisor.ts
|
|
41559
|
-
import { appendFileSync as
|
|
41933
|
+
import { appendFileSync as appendFileSync4 } from "fs";
|
|
41560
41934
|
function loadAdvisorSwapConfig(cliModels, cliCollector) {
|
|
41561
41935
|
return {
|
|
41562
41936
|
enabled: process.env.CLAUDISH_SWAP_ADVISOR === "1" || (cliModels?.length ?? 0) > 0,
|
|
@@ -41611,7 +41985,7 @@ function logAdvisorEvent(cfg, event) {
|
|
|
41611
41985
|
const line = `${JSON.stringify({ ts: new Date().toISOString(), ...event })}
|
|
41612
41986
|
`;
|
|
41613
41987
|
try {
|
|
41614
|
-
|
|
41988
|
+
appendFileSync4(cfg.logPath, line);
|
|
41615
41989
|
} catch {}
|
|
41616
41990
|
}
|
|
41617
41991
|
function recordAdvisorEventsFromChunk(cfg, chunkText) {
|
|
@@ -42659,38 +43033,32 @@ function extractModelIds(body) {
|
|
|
42659
43033
|
}
|
|
42660
43034
|
return [];
|
|
42661
43035
|
}
|
|
43036
|
+
function orderByCost(models) {
|
|
43037
|
+
const sized = models.filter((m) => typeof m.size === "number");
|
|
43038
|
+
const unsized = models.filter((m) => typeof m.size !== "number");
|
|
43039
|
+
const bySize = [...sized].sort((a, b) => (a.size ?? Number.POSITIVE_INFINITY) - (b.size ?? Number.POSITIVE_INFINITY)).map((m) => m.name);
|
|
43040
|
+
return [...bySize, ...rankProbeCandidates(unsized.map((m) => m.name))];
|
|
43041
|
+
}
|
|
42662
43042
|
async function discoverViaOllama(baseUrl, cacheKey) {
|
|
42663
43043
|
const cached2 = cacheGet(cacheKey.key, cacheKey.exclude);
|
|
42664
43044
|
if (cached2 !== undefined)
|
|
42665
43045
|
return cached2;
|
|
42666
|
-
|
|
42667
|
-
|
|
42668
|
-
|
|
42669
|
-
|
|
42670
|
-
|
|
42671
|
-
|
|
42672
|
-
}
|
|
42673
|
-
|
|
42674
|
-
|
|
42675
|
-
|
|
42676
|
-
|
|
42677
|
-
}
|
|
42678
|
-
connectionError ??= classifyFetchError(e, `${baseUrl}/api/tags`);
|
|
42679
|
-
}
|
|
42680
|
-
}
|
|
42681
|
-
const candidates = allRaw.filter((m) => isChatCapable(m.name));
|
|
42682
|
-
if (candidates.length === 0) {
|
|
42683
|
-
const reason = connectionError ?? (allRaw.length === 0 ? `no models on ${baseUrl} (pull one: ollama pull llama3.2)` : `only embedding/non-chat models on ${baseUrl}`);
|
|
43046
|
+
const [psResult, tagsResult] = await Promise.allSettled([
|
|
43047
|
+
fetchOllamaModels2(`${baseUrl}/api/ps`),
|
|
43048
|
+
fetchOllamaModels2(`${baseUrl}/api/tags`)
|
|
43049
|
+
]);
|
|
43050
|
+
const loadedRaw = psResult.status === "fulfilled" ? psResult.value : [];
|
|
43051
|
+
const tagsRaw = tagsResult.status === "fulfilled" ? tagsResult.value : [];
|
|
43052
|
+
const connectionError = psResult.status === "rejected" ? classifyFetchError(psResult.reason, `${baseUrl}/api/ps`) : tagsResult.status === "rejected" ? classifyFetchError(tagsResult.reason, `${baseUrl}/api/tags`) : undefined;
|
|
43053
|
+
const loaded = loadedRaw.filter((m) => isChatCapable(m.name));
|
|
43054
|
+
const loadedNames = new Set(loaded.map((m) => m.name));
|
|
43055
|
+
const rest = tagsRaw.filter((m) => isChatCapable(m.name) && !loadedNames.has(m.name));
|
|
43056
|
+
if (loaded.length === 0 && rest.length === 0) {
|
|
43057
|
+
const reason = connectionError ?? (loadedRaw.length === 0 && tagsRaw.length === 0 ? `no models on ${baseUrl} (pull one: ollama pull llama3.2)` : `only embedding/non-chat models on ${baseUrl}`);
|
|
42684
43058
|
cacheSetFailure(cacheKey.key, reason);
|
|
42685
43059
|
return { model: null, reason };
|
|
42686
43060
|
}
|
|
42687
|
-
const
|
|
42688
|
-
let ranked;
|
|
42689
|
-
if (sized.length > 0) {
|
|
42690
|
-
ranked = [...sized].sort((a, b) => (a.size ?? Number.POSITIVE_INFINITY) - (b.size ?? Number.POSITIVE_INFINITY)).map((m) => m.name);
|
|
42691
|
-
} else {
|
|
42692
|
-
ranked = rankProbeCandidates(candidates.map((m) => m.name));
|
|
42693
|
-
}
|
|
43061
|
+
const ranked = [...orderByCost(loaded), ...orderByCost(rest)];
|
|
42694
43062
|
if (ranked.length === 0) {
|
|
42695
43063
|
const reason = "no chat-capable model on Ollama endpoint";
|
|
42696
43064
|
cacheSetFailure(cacheKey.key, reason);
|
|
@@ -43214,11 +43582,11 @@ var init_ollama_api_format = __esm(() => {
|
|
|
43214
43582
|
});
|
|
43215
43583
|
|
|
43216
43584
|
// src/providers/api-key-provenance.ts
|
|
43217
|
-
import { existsSync as existsSync15, readFileSync as
|
|
43218
|
-
import { homedir as
|
|
43219
|
-
import { join as
|
|
43585
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
43586
|
+
import { homedir as homedir22 } from "os";
|
|
43587
|
+
import { join as join22, resolve as resolve2 } from "path";
|
|
43220
43588
|
function activeConfigPath() {
|
|
43221
|
-
return activeGlobalConfigFile(
|
|
43589
|
+
return activeGlobalConfigFile(join22(homedir22(), ".claudish", "config.json"));
|
|
43222
43590
|
}
|
|
43223
43591
|
function configLayerLabel() {
|
|
43224
43592
|
return getConfigFileOverride() ? activeConfigPath() : "~/.claudish/config.json";
|
|
@@ -43297,7 +43665,7 @@ function readDotenvKey(envVars) {
|
|
|
43297
43665
|
const dotenvPath = resolve2(".env");
|
|
43298
43666
|
if (!existsSync15(dotenvPath))
|
|
43299
43667
|
return null;
|
|
43300
|
-
const parsed = import_dotenv.parse(
|
|
43668
|
+
const parsed = import_dotenv.parse(readFileSync14(dotenvPath, "utf-8"));
|
|
43301
43669
|
for (const v of envVars) {
|
|
43302
43670
|
if (parsed[v])
|
|
43303
43671
|
return parsed[v];
|
|
@@ -43312,7 +43680,7 @@ function readConfigKey(envVar) {
|
|
|
43312
43680
|
const configPath = activeConfigPath();
|
|
43313
43681
|
if (!existsSync15(configPath))
|
|
43314
43682
|
return null;
|
|
43315
|
-
const cfg = JSON.parse(
|
|
43683
|
+
const cfg = JSON.parse(readFileSync14(configPath, "utf-8"));
|
|
43316
43684
|
return cfg.apiKeys?.[envVar] || null;
|
|
43317
43685
|
} catch {
|
|
43318
43686
|
return null;
|
|
@@ -44870,9 +45238,9 @@ var init_poe = __esm(() => {
|
|
|
44870
45238
|
});
|
|
44871
45239
|
|
|
44872
45240
|
// src/services/pricing-cache.ts
|
|
44873
|
-
import { existsSync as existsSync16, readFileSync as
|
|
44874
|
-
import { homedir as
|
|
44875
|
-
import { join as
|
|
45241
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15, statSync as statSync4 } from "fs";
|
|
45242
|
+
import { homedir as homedir23 } from "os";
|
|
45243
|
+
import { join as join23 } from "path";
|
|
44876
45244
|
function prefixMatch(modelName) {
|
|
44877
45245
|
for (const [key, pricing] of pricingMap) {
|
|
44878
45246
|
if (modelName.startsWith(key))
|
|
@@ -44912,10 +45280,10 @@ function loadDiskCache() {
|
|
|
44912
45280
|
try {
|
|
44913
45281
|
if (!existsSync16(CACHE_FILE))
|
|
44914
45282
|
return false;
|
|
44915
|
-
const
|
|
44916
|
-
const age = Date.now() -
|
|
45283
|
+
const stat2 = statSync4(CACHE_FILE);
|
|
45284
|
+
const age = Date.now() - stat2.mtimeMs;
|
|
44917
45285
|
const isFresh = age < CACHE_TTL_MS2;
|
|
44918
|
-
const raw2 =
|
|
45286
|
+
const raw2 = readFileSync15(CACHE_FILE, "utf-8");
|
|
44919
45287
|
const data = JSON.parse(raw2);
|
|
44920
45288
|
for (const [key, pricing] of Object.entries(data)) {
|
|
44921
45289
|
pricingMap.set(key, pricing);
|
|
@@ -44931,8 +45299,8 @@ var init_pricing_cache = __esm(() => {
|
|
|
44931
45299
|
init_logger();
|
|
44932
45300
|
init_catalog_query();
|
|
44933
45301
|
pricingMap = new Map;
|
|
44934
|
-
CACHE_DIR =
|
|
44935
|
-
CACHE_FILE =
|
|
45302
|
+
CACHE_DIR = join23(homedir23(), ".claudish");
|
|
45303
|
+
CACHE_FILE = join23(CACHE_DIR, "pricing-cache.json");
|
|
44936
45304
|
CACHE_TTL_MS2 = 24 * 60 * 60 * 1000;
|
|
44937
45305
|
});
|
|
44938
45306
|
|
|
@@ -45389,20 +45757,20 @@ var init_proxy_server = __esm(() => {
|
|
|
45389
45757
|
});
|
|
45390
45758
|
|
|
45391
45759
|
// src/team-stats.ts
|
|
45392
|
-
import { existsSync as existsSync17, readFileSync as
|
|
45393
|
-
import { join as
|
|
45760
|
+
import { existsSync as existsSync17, readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
|
|
45761
|
+
import { join as join24 } from "path";
|
|
45394
45762
|
function statsDir(sessionPath) {
|
|
45395
|
-
return
|
|
45763
|
+
return join24(sessionPath, "stats");
|
|
45396
45764
|
}
|
|
45397
45765
|
function tokenFileFor(sessionPath, anonId) {
|
|
45398
|
-
return
|
|
45766
|
+
return join24(statsDir(sessionPath), `${anonId}.json`);
|
|
45399
45767
|
}
|
|
45400
45768
|
function readTokenStats(sessionPath, anonId) {
|
|
45401
45769
|
const path = tokenFileFor(sessionPath, anonId);
|
|
45402
45770
|
if (!existsSync17(path))
|
|
45403
45771
|
return null;
|
|
45404
45772
|
try {
|
|
45405
|
-
return JSON.parse(
|
|
45773
|
+
return JSON.parse(readFileSync16(path, "utf-8"));
|
|
45406
45774
|
} catch {
|
|
45407
45775
|
return null;
|
|
45408
45776
|
}
|
|
@@ -45550,7 +45918,7 @@ ${segs.join(" \xB7 ")}`;
|
|
|
45550
45918
|
}
|
|
45551
45919
|
function writeStatusFile(sessionPath, manifest, status, opts) {
|
|
45552
45920
|
try {
|
|
45553
|
-
writeFileSync11(
|
|
45921
|
+
writeFileSync11(join24(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
|
|
45554
45922
|
`, "utf-8");
|
|
45555
45923
|
} catch {}
|
|
45556
45924
|
}
|
|
@@ -45578,11 +45946,11 @@ import {
|
|
|
45578
45946
|
createWriteStream as createWriteStream2,
|
|
45579
45947
|
existsSync as existsSync18,
|
|
45580
45948
|
mkdirSync as mkdirSync11,
|
|
45581
|
-
readFileSync as
|
|
45582
|
-
readdirSync as
|
|
45949
|
+
readFileSync as readFileSync17,
|
|
45950
|
+
readdirSync as readdirSync3,
|
|
45583
45951
|
writeFileSync as writeFileSync12
|
|
45584
45952
|
} from "fs";
|
|
45585
|
-
import { join as
|
|
45953
|
+
import { join as join25, resolve as resolve3 } from "path";
|
|
45586
45954
|
function classifyRunOutput(opts) {
|
|
45587
45955
|
const { outputSize, stdoutTail, stderr, minOutputBytes } = opts;
|
|
45588
45956
|
const apiError = API_ERROR_RE.exec(stdoutTail);
|
|
@@ -45643,18 +46011,18 @@ function setupSession(sessionPath, models, input) {
|
|
|
45643
46011
|
if (models.length === 0) {
|
|
45644
46012
|
throw new Error("At least one model is required");
|
|
45645
46013
|
}
|
|
45646
|
-
if (existsSync18(
|
|
46014
|
+
if (existsSync18(join25(sessionPath, "manifest.json"))) {
|
|
45647
46015
|
throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
|
|
45648
46016
|
}
|
|
45649
46017
|
const sentinels = models.filter(isSentinelModel);
|
|
45650
46018
|
if (sentinels.length > 0) {
|
|
45651
46019
|
throw new Error(`Invalid model(s) for team run: ${sentinels.join(", ")}. These are Claude Code agent selectors, not external model IDs. Use real external models (e.g., "gemini-2.0-flash", "gpt-4o", "or@deepseek/deepseek-r1"). For Claude models, use a Task agent instead of the team tool.`);
|
|
45652
46020
|
}
|
|
45653
|
-
mkdirSync11(
|
|
45654
|
-
mkdirSync11(
|
|
46021
|
+
mkdirSync11(join25(sessionPath, "work"), { recursive: true });
|
|
46022
|
+
mkdirSync11(join25(sessionPath, "errors"), { recursive: true });
|
|
45655
46023
|
if (input !== undefined) {
|
|
45656
|
-
writeFileSync12(
|
|
45657
|
-
} else if (!existsSync18(
|
|
46024
|
+
writeFileSync12(join25(sessionPath, "input.md"), input, "utf-8");
|
|
46025
|
+
} else if (!existsSync18(join25(sessionPath, "input.md"))) {
|
|
45658
46026
|
throw new Error(`No input.md found at ${sessionPath} and no input provided`);
|
|
45659
46027
|
}
|
|
45660
46028
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
@@ -45671,9 +46039,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
45671
46039
|
model: models[i],
|
|
45672
46040
|
assignedAt: now
|
|
45673
46041
|
};
|
|
45674
|
-
mkdirSync11(
|
|
46042
|
+
mkdirSync11(join25(sessionPath, "work", anonId), { recursive: true });
|
|
45675
46043
|
}
|
|
45676
|
-
writeFileSync12(
|
|
46044
|
+
writeFileSync12(join25(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
45677
46045
|
const status = {
|
|
45678
46046
|
startedAt: now,
|
|
45679
46047
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
@@ -45687,17 +46055,17 @@ function setupSession(sessionPath, models, input) {
|
|
|
45687
46055
|
}
|
|
45688
46056
|
]))
|
|
45689
46057
|
};
|
|
45690
|
-
writeFileSync12(
|
|
46058
|
+
writeFileSync12(join25(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
|
|
45691
46059
|
return manifest;
|
|
45692
46060
|
}
|
|
45693
46061
|
async function runModels(sessionPath, opts = {}) {
|
|
45694
46062
|
const timeoutMs = (opts.timeout ?? 300) * 1000;
|
|
45695
|
-
const manifest = JSON.parse(
|
|
45696
|
-
const statusPath =
|
|
45697
|
-
const inputPath =
|
|
45698
|
-
const inputContent =
|
|
46063
|
+
const manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
|
|
46064
|
+
const statusPath = join25(sessionPath, "status.json");
|
|
46065
|
+
const inputPath = join25(sessionPath, "input.md");
|
|
46066
|
+
const inputContent = readFileSync17(inputPath, "utf-8");
|
|
45699
46067
|
await prehydrateCredentialsForSpawn(Object.values(manifest.models).map((m) => m.model));
|
|
45700
|
-
const statusCache = JSON.parse(
|
|
46068
|
+
const statusCache = JSON.parse(readFileSync17(statusPath, "utf-8"));
|
|
45701
46069
|
function updateModelStatus(id, update) {
|
|
45702
46070
|
statusCache.models[id] = { ...statusCache.models[id], ...update };
|
|
45703
46071
|
writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
|
|
@@ -45716,8 +46084,8 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
45716
46084
|
process.on("SIGINT", sigintHandler);
|
|
45717
46085
|
const completionPromises = [];
|
|
45718
46086
|
for (const [anonId, entry] of Object.entries(manifest.models)) {
|
|
45719
|
-
const outputPath =
|
|
45720
|
-
const errorLogPath =
|
|
46087
|
+
const outputPath = join25(sessionPath, `response-${anonId}.md`);
|
|
46088
|
+
const errorLogPath = join25(sessionPath, "errors", `${anonId}.log`);
|
|
45721
46089
|
const args = ["--model", entry.model, "-y", "--stdin", "--quiet", ...opts.claudeFlags ?? []];
|
|
45722
46090
|
updateModelStatus(anonId, {
|
|
45723
46091
|
state: "RUNNING",
|
|
@@ -45899,30 +46267,30 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
45899
46267
|
return statusCache;
|
|
45900
46268
|
}
|
|
45901
46269
|
async function judgeResponses(sessionPath, opts = {}) {
|
|
45902
|
-
const responseFiles =
|
|
46270
|
+
const responseFiles = readdirSync3(sessionPath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
|
|
45903
46271
|
if (responseFiles.length < 2) {
|
|
45904
46272
|
throw new Error(`Need at least 2 responses to judge, found ${responseFiles.length}`);
|
|
45905
46273
|
}
|
|
45906
46274
|
const responses = {};
|
|
45907
46275
|
for (const file2 of responseFiles) {
|
|
45908
46276
|
const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
|
|
45909
|
-
responses[id] =
|
|
46277
|
+
responses[id] = readFileSync17(join25(sessionPath, file2), "utf-8");
|
|
45910
46278
|
}
|
|
45911
|
-
const input =
|
|
46279
|
+
const input = readFileSync17(join25(sessionPath, "input.md"), "utf-8");
|
|
45912
46280
|
const judgePrompt = buildJudgePrompt(input, responses);
|
|
45913
|
-
writeFileSync12(
|
|
46281
|
+
writeFileSync12(join25(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
|
|
45914
46282
|
const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
|
|
45915
|
-
const judgePath =
|
|
46283
|
+
const judgePath = join25(sessionPath, "judging");
|
|
45916
46284
|
mkdirSync11(judgePath, { recursive: true });
|
|
45917
46285
|
setupSession(judgePath, judgeModels, judgePrompt);
|
|
45918
46286
|
await runModels(judgePath, { claudeFlags: opts.claudeFlags });
|
|
45919
46287
|
const votes = parseJudgeVotes(judgePath, Object.keys(responses));
|
|
45920
46288
|
const verdict = aggregateVerdict(votes, Object.keys(responses));
|
|
45921
|
-
writeFileSync12(
|
|
46289
|
+
writeFileSync12(join25(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
|
|
45922
46290
|
return verdict;
|
|
45923
46291
|
}
|
|
45924
46292
|
function getStatus(sessionPath) {
|
|
45925
|
-
return JSON.parse(
|
|
46293
|
+
return JSON.parse(readFileSync17(join25(sessionPath, "status.json"), "utf-8"));
|
|
45926
46294
|
}
|
|
45927
46295
|
function fisherYatesShuffle(arr) {
|
|
45928
46296
|
for (let i = arr.length - 1;i > 0; i--) {
|
|
@@ -45932,7 +46300,7 @@ function fisherYatesShuffle(arr) {
|
|
|
45932
46300
|
return arr;
|
|
45933
46301
|
}
|
|
45934
46302
|
function getDefaultJudgeModels(sessionPath) {
|
|
45935
|
-
const manifest = JSON.parse(
|
|
46303
|
+
const manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
|
|
45936
46304
|
return Object.values(manifest.models).map((e) => e.model);
|
|
45937
46305
|
}
|
|
45938
46306
|
function buildJudgePrompt(input, responses) {
|
|
@@ -45990,12 +46358,12 @@ function buildJudgePrompt(input, responses) {
|
|
|
45990
46358
|
}
|
|
45991
46359
|
function parseJudgeVotes(judgePath, responseIds) {
|
|
45992
46360
|
const votes = [];
|
|
45993
|
-
const responseFiles =
|
|
46361
|
+
const responseFiles = readdirSync3(judgePath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
|
|
45994
46362
|
for (const file2 of responseFiles) {
|
|
45995
46363
|
const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
|
|
45996
46364
|
let content;
|
|
45997
46365
|
try {
|
|
45998
|
-
content =
|
|
46366
|
+
content = readFileSync17(join25(judgePath, file2), "utf-8");
|
|
45999
46367
|
} catch {
|
|
46000
46368
|
continue;
|
|
46001
46369
|
}
|
|
@@ -46047,7 +46415,7 @@ function aggregateVerdict(votes, responseIds) {
|
|
|
46047
46415
|
function formatVerdict(verdict, sessionPath) {
|
|
46048
46416
|
let manifest = null;
|
|
46049
46417
|
try {
|
|
46050
|
-
manifest = JSON.parse(
|
|
46418
|
+
manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
|
|
46051
46419
|
} catch {}
|
|
46052
46420
|
let output = `# Team Verdict
|
|
46053
46421
|
|
|
@@ -46102,14 +46470,14 @@ __export(exports_mcp_server, {
|
|
|
46102
46470
|
parseAnthropicSse: () => parseAnthropicSse,
|
|
46103
46471
|
formatTeamResult: () => formatTeamResult
|
|
46104
46472
|
});
|
|
46105
|
-
import { existsSync as existsSync19, mkdirSync as mkdirSync12, readFileSync as
|
|
46106
|
-
import { homedir as
|
|
46107
|
-
import { dirname as
|
|
46473
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync12, readFileSync as readFileSync18, readdirSync as readdirSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
46474
|
+
import { homedir as homedir24 } from "os";
|
|
46475
|
+
import { dirname as dirname8, join as join26 } from "path";
|
|
46108
46476
|
import { fileURLToPath } from "url";
|
|
46109
46477
|
async function loadAllModels(forceRefresh = false) {
|
|
46110
46478
|
if (!forceRefresh && existsSync19(ALL_MODELS_CACHE_PATH2)) {
|
|
46111
46479
|
try {
|
|
46112
|
-
const cacheData = JSON.parse(
|
|
46480
|
+
const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH2, "utf-8"));
|
|
46113
46481
|
const lastUpdated = new Date(cacheData.lastUpdated);
|
|
46114
46482
|
const ageInDays = (Date.now() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
|
|
46115
46483
|
if (ageInDays <= CACHE_MAX_AGE_DAYS) {
|
|
@@ -46128,7 +46496,7 @@ async function loadAllModels(forceRefresh = false) {
|
|
|
46128
46496
|
return models;
|
|
46129
46497
|
} catch {
|
|
46130
46498
|
if (existsSync19(ALL_MODELS_CACHE_PATH2)) {
|
|
46131
|
-
const cacheData = JSON.parse(
|
|
46499
|
+
const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH2, "utf-8"));
|
|
46132
46500
|
return cacheData.models || [];
|
|
46133
46501
|
}
|
|
46134
46502
|
return [];
|
|
@@ -46695,7 +47063,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
46695
47063
|
let stderrFull = stderr_snippet || "";
|
|
46696
47064
|
if (error_log_path) {
|
|
46697
47065
|
try {
|
|
46698
|
-
stderrFull =
|
|
47066
|
+
stderrFull = readFileSync18(error_log_path, "utf-8");
|
|
46699
47067
|
} catch {}
|
|
46700
47068
|
}
|
|
46701
47069
|
const sessionData = {};
|
|
@@ -46703,26 +47071,26 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
46703
47071
|
const sp = session_path;
|
|
46704
47072
|
for (const file2 of ["status.json", "manifest.json", "input.md"]) {
|
|
46705
47073
|
try {
|
|
46706
|
-
sessionData[file2] =
|
|
47074
|
+
sessionData[file2] = readFileSync18(join26(sp, file2), "utf-8");
|
|
46707
47075
|
} catch {}
|
|
46708
47076
|
}
|
|
46709
47077
|
try {
|
|
46710
|
-
const errorDir =
|
|
47078
|
+
const errorDir = join26(sp, "errors");
|
|
46711
47079
|
if (existsSync19(errorDir)) {
|
|
46712
|
-
for (const f of
|
|
47080
|
+
for (const f of readdirSync4(errorDir)) {
|
|
46713
47081
|
if (f.endsWith(".log")) {
|
|
46714
47082
|
try {
|
|
46715
|
-
sessionData[`errors/${f}`] =
|
|
47083
|
+
sessionData[`errors/${f}`] = readFileSync18(join26(errorDir, f), "utf-8");
|
|
46716
47084
|
} catch {}
|
|
46717
47085
|
}
|
|
46718
47086
|
}
|
|
46719
47087
|
}
|
|
46720
47088
|
} catch {}
|
|
46721
47089
|
try {
|
|
46722
|
-
for (const f of
|
|
47090
|
+
for (const f of readdirSync4(sp)) {
|
|
46723
47091
|
if (f.startsWith("response-") && f.endsWith(".md")) {
|
|
46724
47092
|
try {
|
|
46725
|
-
const content =
|
|
47093
|
+
const content = readFileSync18(join26(sp, f), "utf-8");
|
|
46726
47094
|
sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
|
|
46727
47095
|
} catch {}
|
|
46728
47096
|
}
|
|
@@ -46731,9 +47099,9 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
46731
47099
|
}
|
|
46732
47100
|
let version2 = "unknown";
|
|
46733
47101
|
try {
|
|
46734
|
-
const pkgPath =
|
|
47102
|
+
const pkgPath = join26(__dirname2, "../package.json");
|
|
46735
47103
|
if (existsSync19(pkgPath)) {
|
|
46736
|
-
version2 = JSON.parse(
|
|
47104
|
+
version2 = JSON.parse(readFileSync18(pkgPath, "utf-8")).version;
|
|
46737
47105
|
}
|
|
46738
47106
|
} catch {}
|
|
46739
47107
|
const report = {
|
|
@@ -47130,9 +47498,9 @@ var init_mcp_server = __esm(() => {
|
|
|
47130
47498
|
import_dotenv2 = __toESM(require_main(), 1);
|
|
47131
47499
|
import_dotenv2.config({ quiet: true });
|
|
47132
47500
|
__filename2 = fileURLToPath(import.meta.url);
|
|
47133
|
-
__dirname2 =
|
|
47134
|
-
CLAUDISH_CACHE_DIR =
|
|
47135
|
-
ALL_MODELS_CACHE_PATH2 =
|
|
47501
|
+
__dirname2 = dirname8(__filename2);
|
|
47502
|
+
CLAUDISH_CACHE_DIR = join26(homedir24(), ".claudish");
|
|
47503
|
+
ALL_MODELS_CACHE_PATH2 = join26(CLAUDISH_CACHE_DIR, "all-models.json");
|
|
47136
47504
|
NEXT_STEP = {
|
|
47137
47505
|
nonzero_exit: "read the evidence log, then retry or drop the model",
|
|
47138
47506
|
timeout: "raise `timeout`, or pick a faster model",
|
|
@@ -47157,7 +47525,7 @@ var exports_serve_command = {};
|
|
|
47157
47525
|
__export(exports_serve_command, {
|
|
47158
47526
|
serveCommand: () => serveCommand
|
|
47159
47527
|
});
|
|
47160
|
-
import { existsSync as existsSync20, readFileSync as
|
|
47528
|
+
import { existsSync as existsSync20, readFileSync as readFileSync19 } from "fs";
|
|
47161
47529
|
function parseServeArgs(args) {
|
|
47162
47530
|
const out = {};
|
|
47163
47531
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -47181,7 +47549,7 @@ function loadModelMap(path) {
|
|
|
47181
47549
|
}
|
|
47182
47550
|
let raw2;
|
|
47183
47551
|
try {
|
|
47184
|
-
raw2 =
|
|
47552
|
+
raw2 = readFileSync19(path, "utf-8");
|
|
47185
47553
|
} catch (e) {
|
|
47186
47554
|
throw new Error(`failed to read --models file ${path}: ${e instanceof Error ? e.message : String(e)}`);
|
|
47187
47555
|
}
|
|
@@ -47253,6 +47621,127 @@ var init_serve_command = __esm(() => {
|
|
|
47253
47621
|
init_proxy_server();
|
|
47254
47622
|
});
|
|
47255
47623
|
|
|
47624
|
+
// src/behavior-command.ts
|
|
47625
|
+
var exports_behavior_command = {};
|
|
47626
|
+
__export(exports_behavior_command, {
|
|
47627
|
+
behaviorCommand: () => behaviorCommand
|
|
47628
|
+
});
|
|
47629
|
+
function severityColor(sev) {
|
|
47630
|
+
if (sev === "fix")
|
|
47631
|
+
return green(sev);
|
|
47632
|
+
if (sev === "warn")
|
|
47633
|
+
return yellow(sev);
|
|
47634
|
+
return dim2(sev);
|
|
47635
|
+
}
|
|
47636
|
+
function showRules(json2) {
|
|
47637
|
+
const config3 = parseBehaviorConfig(loadConfig().behavior);
|
|
47638
|
+
const rows = BUILTIN_RULES.map((rule) => ({
|
|
47639
|
+
id: rule.id,
|
|
47640
|
+
severity: resolveSeverity(rule.id, rule.defaultSeverity, config3),
|
|
47641
|
+
defaultSeverity: rule.defaultSeverity,
|
|
47642
|
+
intercepts: rule.interceptsTools ?? [],
|
|
47643
|
+
description: rule.description
|
|
47644
|
+
}));
|
|
47645
|
+
if (json2) {
|
|
47646
|
+
console.log(JSON.stringify({ rules: rows, observer: config3.observer ?? null }, null, 2));
|
|
47647
|
+
return;
|
|
47648
|
+
}
|
|
47649
|
+
console.log(bold2(`
|
|
47650
|
+
Behavior rules
|
|
47651
|
+
`));
|
|
47652
|
+
for (const r of rows) {
|
|
47653
|
+
const overridden = r.severity !== r.defaultSeverity ? dim2(` (default ${r.defaultSeverity})`) : "";
|
|
47654
|
+
console.log(` ${severityColor(r.severity).padEnd(18)} ${r.id}${overridden}`);
|
|
47655
|
+
console.log(` ${dim2(r.description)}`);
|
|
47656
|
+
if (r.intercepts.length > 0) {
|
|
47657
|
+
console.log(` ${dim2(`repairs: ${r.intercepts.join(", ")}`)}`);
|
|
47658
|
+
}
|
|
47659
|
+
console.log();
|
|
47660
|
+
}
|
|
47661
|
+
console.log(dim2(` Rules are inactive for native Claude models by design.
|
|
47662
|
+
`));
|
|
47663
|
+
const obs = config3.observer;
|
|
47664
|
+
const obsState = obs?.enabled ? obs.mode ?? "suggest" : "off";
|
|
47665
|
+
console.log(` observer: ${obsState === "off" ? dim2("off") : green(obsState)}`);
|
|
47666
|
+
if (obs?.model)
|
|
47667
|
+
console.log(` ${dim2(`observer model: ${obs.model}`)}`);
|
|
47668
|
+
console.log();
|
|
47669
|
+
}
|
|
47670
|
+
function showCorpus(write, json2) {
|
|
47671
|
+
const result = buildCorpus({ write });
|
|
47672
|
+
if (json2) {
|
|
47673
|
+
console.log(JSON.stringify(result, null, 2));
|
|
47674
|
+
return;
|
|
47675
|
+
}
|
|
47676
|
+
const degraded = result.records.filter((r) => r.outcome === "degraded");
|
|
47677
|
+
const ok = result.records.filter((r) => r.outcome === "ok");
|
|
47678
|
+
const catchable = degraded.filter((r) => r.observedPaths.length > 0);
|
|
47679
|
+
console.log(bold2(`
|
|
47680
|
+
Behavior divergence corpus
|
|
47681
|
+
`));
|
|
47682
|
+
console.log(` transcripts scanned : ${result.scanned}`);
|
|
47683
|
+
console.log(` plan-exit records : ${result.records.length}`);
|
|
47684
|
+
console.log(` ${green("plan found")} : ${ok.length}`);
|
|
47685
|
+
console.log(` ${yellow("degraded (no plan)")} : ${degraded.length}`);
|
|
47686
|
+
console.log(` of those, a rule would have fired on ${catchable.length}
|
|
47687
|
+
`);
|
|
47688
|
+
const byModel = new Map;
|
|
47689
|
+
for (const r of result.records) {
|
|
47690
|
+
const m = r.model ?? "unknown";
|
|
47691
|
+
const e = byModel.get(m) ?? { ok: 0, degraded: 0 };
|
|
47692
|
+
if (r.outcome === "degraded")
|
|
47693
|
+
e.degraded++;
|
|
47694
|
+
else
|
|
47695
|
+
e.ok++;
|
|
47696
|
+
byModel.set(m, e);
|
|
47697
|
+
}
|
|
47698
|
+
if (byModel.size > 0) {
|
|
47699
|
+
console.log(bold2(` by model (degraded / ok)
|
|
47700
|
+
`));
|
|
47701
|
+
for (const [model, v] of [...byModel.entries()].sort((a, b) => b[1].degraded - a[1].degraded || b[1].ok - a[1].ok)) {
|
|
47702
|
+
const flag = v.degraded > 0 ? yellow(String(v.degraded)) : dim2("0");
|
|
47703
|
+
console.log(` ${model.padEnd(26)} ${flag} / ${v.ok}`);
|
|
47704
|
+
}
|
|
47705
|
+
console.log();
|
|
47706
|
+
}
|
|
47707
|
+
if (result.outputPath) {
|
|
47708
|
+
console.log(dim2(` appended to ${result.outputPath}
|
|
47709
|
+
`));
|
|
47710
|
+
} else if (write) {
|
|
47711
|
+
console.log(dim2(` nothing to write (no records found)
|
|
47712
|
+
`));
|
|
47713
|
+
} else {
|
|
47714
|
+
console.log(dim2(` pass --write to append these records to the divergence log
|
|
47715
|
+
`));
|
|
47716
|
+
}
|
|
47717
|
+
}
|
|
47718
|
+
async function behaviorCommand(argv) {
|
|
47719
|
+
const json2 = argv.includes("--json");
|
|
47720
|
+
const write = argv.includes("--write");
|
|
47721
|
+
const action = argv.find((a) => !a.startsWith("-")) ?? "rules";
|
|
47722
|
+
switch (action) {
|
|
47723
|
+
case "rules":
|
|
47724
|
+
showRules(json2);
|
|
47725
|
+
return;
|
|
47726
|
+
case "corpus":
|
|
47727
|
+
showCorpus(write, json2);
|
|
47728
|
+
return;
|
|
47729
|
+
default:
|
|
47730
|
+
console.error(`Unknown action "${action}".
|
|
47731
|
+
|
|
47732
|
+
` + `Usage:
|
|
47733
|
+
` + ` claudish behavior rules [--json]
|
|
47734
|
+
` + ` claudish behavior corpus [--write] [--json]
|
|
47735
|
+
`);
|
|
47736
|
+
process.exit(1);
|
|
47737
|
+
}
|
|
47738
|
+
}
|
|
47739
|
+
var green = (s) => `\x1B[32m${s}\x1B[0m`, yellow = (s) => `\x1B[33m${s}\x1B[0m`, dim2 = (s) => `\x1B[2m${s}\x1B[0m`, bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
47740
|
+
var init_behavior_command = __esm(() => {
|
|
47741
|
+
init_behavior();
|
|
47742
|
+
init_profile_config();
|
|
47743
|
+
});
|
|
47744
|
+
|
|
47256
47745
|
// src/auth/credentials/source.ts
|
|
47257
47746
|
function describeSourceSync(p, config3) {
|
|
47258
47747
|
if (p.isLocal)
|
|
@@ -48169,8 +48658,8 @@ function assembleStyles() {
|
|
|
48169
48658
|
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
48170
48659
|
Object.defineProperties(styles, {
|
|
48171
48660
|
rgbToAnsi256: {
|
|
48172
|
-
value(red,
|
|
48173
|
-
if (red ===
|
|
48661
|
+
value(red, green2, blue) {
|
|
48662
|
+
if (red === green2 && green2 === blue) {
|
|
48174
48663
|
if (red < 8) {
|
|
48175
48664
|
return 16;
|
|
48176
48665
|
}
|
|
@@ -48179,7 +48668,7 @@ function assembleStyles() {
|
|
|
48179
48668
|
}
|
|
48180
48669
|
return Math.round((red - 8) / 247 * 24) + 232;
|
|
48181
48670
|
}
|
|
48182
|
-
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(
|
|
48671
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue / 255 * 5);
|
|
48183
48672
|
},
|
|
48184
48673
|
enumerable: false
|
|
48185
48674
|
},
|
|
@@ -48215,24 +48704,24 @@ function assembleStyles() {
|
|
|
48215
48704
|
return 90 + (code - 8);
|
|
48216
48705
|
}
|
|
48217
48706
|
let red;
|
|
48218
|
-
let
|
|
48707
|
+
let green2;
|
|
48219
48708
|
let blue;
|
|
48220
48709
|
if (code >= 232) {
|
|
48221
48710
|
red = ((code - 232) * 10 + 8) / 255;
|
|
48222
|
-
|
|
48711
|
+
green2 = red;
|
|
48223
48712
|
blue = red;
|
|
48224
48713
|
} else {
|
|
48225
48714
|
code -= 16;
|
|
48226
48715
|
const remainder = code % 36;
|
|
48227
48716
|
red = Math.floor(code / 36) / 5;
|
|
48228
|
-
|
|
48717
|
+
green2 = Math.floor(remainder / 6) / 5;
|
|
48229
48718
|
blue = remainder % 6 / 5;
|
|
48230
48719
|
}
|
|
48231
|
-
const value = Math.max(red,
|
|
48720
|
+
const value = Math.max(red, green2, blue) * 2;
|
|
48232
48721
|
if (value === 0) {
|
|
48233
48722
|
return 30;
|
|
48234
48723
|
}
|
|
48235
|
-
let result = 30 + (Math.round(blue) << 2 | Math.round(
|
|
48724
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green2) << 1 | Math.round(red));
|
|
48236
48725
|
if (value === 2) {
|
|
48237
48726
|
result += 60;
|
|
48238
48727
|
}
|
|
@@ -48241,7 +48730,7 @@ function assembleStyles() {
|
|
|
48241
48730
|
enumerable: false
|
|
48242
48731
|
},
|
|
48243
48732
|
rgbToAnsi: {
|
|
48244
|
-
value: (red,
|
|
48733
|
+
value: (red, green2, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green2, blue)),
|
|
48245
48734
|
enumerable: false
|
|
48246
48735
|
},
|
|
48247
48736
|
hexToAnsi: {
|
|
@@ -48251,7 +48740,7 @@ function assembleStyles() {
|
|
|
48251
48740
|
});
|
|
48252
48741
|
return styles;
|
|
48253
48742
|
}
|
|
48254
|
-
var ANSI_BACKGROUND_OFFSET = 10, wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`, wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, wrapAnsi16m = (offset = 0) => (red,
|
|
48743
|
+
var ANSI_BACKGROUND_OFFSET = 10, wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`, wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, wrapAnsi16m = (offset = 0) => (red, green2, blue) => `\x1B[${38 + offset};2;${red};${green2};${blue}m`, styles, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default;
|
|
48255
48744
|
var init_ansi_styles = __esm(() => {
|
|
48256
48745
|
styles = {
|
|
48257
48746
|
modifier: {
|
|
@@ -58653,7 +59142,7 @@ var init_RemoveFileError = __esm(() => {
|
|
|
58653
59142
|
|
|
58654
59143
|
// ../../node_modules/.bun/@inquirer+external-editor@2.0.1+04f2146be16c61ef/node_modules/@inquirer/external-editor/dist/index.js
|
|
58655
59144
|
import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
|
|
58656
|
-
import { readFileSync as
|
|
59145
|
+
import { readFileSync as readFileSync20, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
58657
59146
|
import path from "path";
|
|
58658
59147
|
import os from "os";
|
|
58659
59148
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
@@ -58769,7 +59258,7 @@ class ExternalEditor {
|
|
|
58769
59258
|
}
|
|
58770
59259
|
readTemporaryFile() {
|
|
58771
59260
|
try {
|
|
58772
|
-
const tempFileBuffer =
|
|
59261
|
+
const tempFileBuffer = readFileSync20(this.tempFile);
|
|
58773
59262
|
if (tempFileBuffer.length === 0) {
|
|
58774
59263
|
this.text = "";
|
|
58775
59264
|
} else {
|
|
@@ -59964,15 +60453,15 @@ async function geminiQuotaHandler() {
|
|
|
59964
60453
|
}
|
|
59965
60454
|
}
|
|
59966
60455
|
async function codexQuotaHandler() {
|
|
59967
|
-
const { readFileSync:
|
|
59968
|
-
const { join:
|
|
59969
|
-
const { homedir:
|
|
59970
|
-
const credPath =
|
|
60456
|
+
const { readFileSync: readFileSync21, existsSync: existsSync21 } = await import("fs");
|
|
60457
|
+
const { join: join27 } = await import("path");
|
|
60458
|
+
const { homedir: homedir25 } = await import("os");
|
|
60459
|
+
const credPath = join27(homedir25(), ".claudish", "codex-oauth.json");
|
|
59971
60460
|
if (!existsSync21(credPath)) {
|
|
59972
60461
|
console.error(`${RED}No Codex credentials found.${R} Run: ${B}claudish login codex${R}`);
|
|
59973
60462
|
process.exit(1);
|
|
59974
60463
|
}
|
|
59975
|
-
const creds = JSON.parse(
|
|
60464
|
+
const creds = JSON.parse(readFileSync21(credPath, "utf-8"));
|
|
59976
60465
|
let email3 = "";
|
|
59977
60466
|
try {
|
|
59978
60467
|
const parts = creds.access_token.split(".");
|
|
@@ -60024,9 +60513,9 @@ async function codexQuotaHandler() {
|
|
|
60024
60513
|
}
|
|
60025
60514
|
let modelSlugs = [];
|
|
60026
60515
|
try {
|
|
60027
|
-
const modelsPath =
|
|
60516
|
+
const modelsPath = join27(homedir25(), ".codex", "models_cache.json");
|
|
60028
60517
|
if (existsSync21(modelsPath)) {
|
|
60029
|
-
const cache2 = JSON.parse(
|
|
60518
|
+
const cache2 = JSON.parse(readFileSync21(modelsPath, "utf-8"));
|
|
60030
60519
|
modelSlugs = (cache2.models || []).map((m) => m.slug || m.id).filter(Boolean);
|
|
60031
60520
|
}
|
|
60032
60521
|
} catch {}
|
|
@@ -61397,6 +61886,8 @@ function annotateOAuthHint(result, provider, isOAuth) {
|
|
|
61397
61886
|
const loginCommand2 = provider === "gemini-codeassist" ? "claudish login gemini" : provider === "vertex" ? "gcloud auth application-default login" : undefined;
|
|
61398
61887
|
if (!loginCommand2)
|
|
61399
61888
|
return result;
|
|
61889
|
+
if (result.httpStatus === 403)
|
|
61890
|
+
return result;
|
|
61400
61891
|
const looksLikeAuthFailure = result.state === "auth-failed" || /auth|token|login|credential|unauthor/i.test(result.errorMessage || "");
|
|
61401
61892
|
if (!looksLikeAuthFailure)
|
|
61402
61893
|
return result;
|
|
@@ -61679,29 +62170,34 @@ function isContentEvent(parsed, eventType) {
|
|
|
61679
62170
|
return true;
|
|
61680
62171
|
return false;
|
|
61681
62172
|
}
|
|
62173
|
+
function withDetail(base, message) {
|
|
62174
|
+
return message ? `${base} \u2014 ${message}` : base;
|
|
62175
|
+
}
|
|
61682
62176
|
function describeProbeState(result) {
|
|
62177
|
+
const status = result.httpStatus ?? "";
|
|
62178
|
+
const latency = result.latencyMs ? ` \xB7 ${result.latencyMs}ms` : "";
|
|
61683
62179
|
switch (result.state) {
|
|
61684
62180
|
case "live":
|
|
61685
62181
|
return `live \xB7 ${result.latencyMs}ms`;
|
|
61686
62182
|
case "key-missing":
|
|
61687
62183
|
return result.errorMessage ? `missing (${result.errorMessage})` : "missing";
|
|
61688
62184
|
case "auth-failed":
|
|
61689
|
-
return `auth failed \xB7 ${
|
|
62185
|
+
return withDetail(`auth failed \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
61690
62186
|
case "model-not-found":
|
|
61691
|
-
return `model not found \xB7 ${
|
|
62187
|
+
return withDetail(`model not found \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
61692
62188
|
case "rate-limited":
|
|
61693
|
-
return `rate limited \xB7 ${result.latencyMs}ms
|
|
62189
|
+
return withDetail(`rate limited \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
61694
62190
|
case "out-of-credit":
|
|
61695
|
-
return `out of credit \xB7 ${
|
|
62191
|
+
return withDetail(`out of credit \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
61696
62192
|
case "server-error":
|
|
61697
|
-
return `server error \xB7 ${
|
|
62193
|
+
return withDetail(`server error \xB7 ${status} \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
61698
62194
|
case "timeout":
|
|
61699
|
-
return `timeout \xB7 ${result.latencyMs}ms
|
|
62195
|
+
return withDetail(`timeout \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
61700
62196
|
case "network-error":
|
|
61701
|
-
return `network error \xB7 ${result.latencyMs}ms
|
|
62197
|
+
return withDetail(`network error \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
61702
62198
|
case "error": {
|
|
61703
|
-
const base = `error${result.httpStatus ? ` \xB7 ${result.httpStatus}` : ""}${
|
|
61704
|
-
return
|
|
62199
|
+
const base = `error${result.httpStatus ? ` \xB7 ${result.httpStatus}` : ""}${latency}`;
|
|
62200
|
+
return withDetail(base, result.errorMessage);
|
|
61705
62201
|
}
|
|
61706
62202
|
}
|
|
61707
62203
|
}
|
|
@@ -61819,7 +62315,7 @@ function tokBarCells(tokensPerSec, maxTokPerSec, tokWidth) {
|
|
|
61819
62315
|
const raw2 = Math.round(tokWidth * Math.max(0, tokensPerSec) / denom);
|
|
61820
62316
|
return Math.min(tokWidth, Math.max(0, raw2));
|
|
61821
62317
|
}
|
|
61822
|
-
var C,
|
|
62318
|
+
var C, bold3, A, LATENCY_BUCKETS, latencyFg = "#ffffff", LATENCY_FG_ANSI = "\x1B[38;2;255;255;255m", ANSI_RESET = "\x1B[0m", STAGE_BG, STAGE_FG, STAGE_BG_ANSI;
|
|
61823
62319
|
var init_theme2 = __esm(() => {
|
|
61824
62320
|
C = {
|
|
61825
62321
|
bg: "#000000",
|
|
@@ -61850,10 +62346,10 @@ var init_theme2 = __esm(() => {
|
|
|
61850
62346
|
chipKeyBg: "#3a3a3a",
|
|
61851
62347
|
chipLabelBg: "#222222"
|
|
61852
62348
|
};
|
|
61853
|
-
|
|
62349
|
+
bold3 = createTextAttributes({ bold: true });
|
|
61854
62350
|
A = {
|
|
61855
|
-
bold:
|
|
61856
|
-
boldIf: (enabled) => enabled ?
|
|
62351
|
+
bold: bold3,
|
|
62352
|
+
boldIf: (enabled) => enabled ? bold3 : undefined
|
|
61857
62353
|
};
|
|
61858
62354
|
LATENCY_BUCKETS = [
|
|
61859
62355
|
{ maxMs: 500, hex: "#1f8f3b" },
|
|
@@ -63991,28 +64487,28 @@ import {
|
|
|
63991
64487
|
copyFileSync as copyFileSync2,
|
|
63992
64488
|
existsSync as existsSync21,
|
|
63993
64489
|
mkdirSync as mkdirSync13,
|
|
63994
|
-
readFileSync as
|
|
63995
|
-
readdirSync as
|
|
64490
|
+
readFileSync as readFileSync21,
|
|
64491
|
+
readdirSync as readdirSync5,
|
|
63996
64492
|
unlinkSync as unlinkSync7,
|
|
63997
64493
|
writeFileSync as writeFileSync15
|
|
63998
64494
|
} from "fs";
|
|
63999
|
-
import { homedir as
|
|
64000
|
-
import { dirname as
|
|
64495
|
+
import { homedir as homedir25 } from "os";
|
|
64496
|
+
import { dirname as dirname9, join as join27 } from "path";
|
|
64001
64497
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
64002
64498
|
function getVersion3() {
|
|
64003
64499
|
return VERSION;
|
|
64004
64500
|
}
|
|
64005
64501
|
function clearAllModelCaches() {
|
|
64006
|
-
const cacheDir =
|
|
64502
|
+
const cacheDir = join27(homedir25(), ".claudish");
|
|
64007
64503
|
if (!existsSync21(cacheDir))
|
|
64008
64504
|
return;
|
|
64009
64505
|
const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
|
|
64010
64506
|
let cleared = 0;
|
|
64011
64507
|
try {
|
|
64012
|
-
const files =
|
|
64508
|
+
const files = readdirSync5(cacheDir);
|
|
64013
64509
|
for (const file2 of files) {
|
|
64014
64510
|
if (cachePatterns.includes(file2)) {
|
|
64015
|
-
unlinkSync7(
|
|
64511
|
+
unlinkSync7(join27(cacheDir, file2));
|
|
64016
64512
|
cleared++;
|
|
64017
64513
|
}
|
|
64018
64514
|
}
|
|
@@ -64422,14 +64918,14 @@ Usage: claudish --models --provider <slug>`);
|
|
|
64422
64918
|
});
|
|
64423
64919
|
config3.resolvedDefaultProvider = resolved;
|
|
64424
64920
|
if (resolved.legacyAutoPromoted && !config3.quiet) {
|
|
64425
|
-
const markerFile =
|
|
64921
|
+
const markerFile = join27(homedir25(), ".claudish", ".legacy-litellm-hint-shown");
|
|
64426
64922
|
if (!existsSync21(markerFile)) {
|
|
64427
64923
|
const hint = buildLegacyHint(resolved);
|
|
64428
64924
|
if (hint) {
|
|
64429
64925
|
console.error(hint);
|
|
64430
64926
|
}
|
|
64431
64927
|
try {
|
|
64432
|
-
mkdirSync13(
|
|
64928
|
+
mkdirSync13(dirname9(markerFile), { recursive: true });
|
|
64433
64929
|
writeFileSync15(markerFile, new Date().toISOString(), "utf-8");
|
|
64434
64930
|
} catch {}
|
|
64435
64931
|
}
|
|
@@ -65189,261 +65685,261 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
|
|
|
65189
65685
|
function printHelp() {
|
|
65190
65686
|
const useColor = !!process.stdout.isTTY && !process.env.NO_COLOR;
|
|
65191
65687
|
const c = (code) => (s) => useColor ? `\x1B[${code}m${s}\x1B[0m` : s;
|
|
65192
|
-
const
|
|
65193
|
-
const
|
|
65688
|
+
const bold4 = c("1");
|
|
65689
|
+
const dim3 = c("2");
|
|
65194
65690
|
const cyan = c("36");
|
|
65195
|
-
const
|
|
65196
|
-
const
|
|
65691
|
+
const green2 = c("32");
|
|
65692
|
+
const yellow2 = c("33");
|
|
65197
65693
|
const magenta = c("35");
|
|
65198
65694
|
const blue = c("34");
|
|
65199
|
-
const h = (title) =>
|
|
65695
|
+
const h = (title) => bold4(cyan(`\u258C ${title}`));
|
|
65200
65696
|
console.log(`
|
|
65201
|
-
${
|
|
65202
|
-
${
|
|
65697
|
+
${bold4("claudish")} ${dim3("\xB7")} Run Claude Code with any AI model
|
|
65698
|
+
${dim3("OpenRouter \xB7 Gemini \xB7 OpenAI \xB7 xAI \xB7 MiniMax \xB7 Kimi \xB7 GLM \xB7 Z.AI \xB7 Sakana \xB7 Poe \xB7 LiteLLM \xB7 Local")}
|
|
65203
65699
|
|
|
65204
65700
|
${h("USAGE")}
|
|
65205
|
-
${
|
|
65206
|
-
${
|
|
65207
|
-
${
|
|
65208
|
-
${
|
|
65701
|
+
${green2("claudish")} ${dim3("# Interactive mode (default, model selector)")}
|
|
65702
|
+
${green2("claudish")} ${yellow2("[OPTIONS] <claude-args...>")} ${dim3("# Single-shot mode (requires --model)")}
|
|
65703
|
+
${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${yellow2('"prompt"')} ${dim3("# Run models in parallel (magmux grid)")}
|
|
65704
|
+
${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${green2("-f")} ${yellow2("input.md")} ${dim3("# Team mode with file input")}
|
|
65209
65705
|
|
|
65210
65706
|
${h("MODEL ROUTING")}
|
|
65211
|
-
${
|
|
65212
|
-
${magenta("google@gemini-3-pro")} ${
|
|
65213
|
-
${magenta("openrouter@google/gemini-3-pro")} ${
|
|
65214
|
-
${magenta("oai@gpt-5.3")} ${
|
|
65215
|
-
${magenta("ollama@llama3.2:3")} ${
|
|
65216
|
-
${magenta("ollama@llama3.2:0")} ${
|
|
65217
|
-
|
|
65218
|
-
${
|
|
65219
|
-
${magenta("g, gemini")} ${
|
|
65220
|
-
${magenta("oai")} ${
|
|
65221
|
-
${magenta("cx, codex")} ${
|
|
65222
|
-
${magenta("or")} ${
|
|
65223
|
-
${magenta("x-ai, xai, grok")} ${
|
|
65224
|
-
${magenta("mm, mmax")} ${
|
|
65225
|
-
${magenta("mmc")} ${
|
|
65226
|
-
${magenta("kimi, moon")} ${
|
|
65227
|
-
${magenta("kc")} ${
|
|
65228
|
-
${magenta("glm, zhipu")} ${
|
|
65229
|
-
${magenta("gc")} ${
|
|
65230
|
-
${magenta("z-ai, zai")} ${
|
|
65231
|
-
${magenta("oc, llama, lc, meta")} ${
|
|
65232
|
-
${magenta("zen")} ${
|
|
65233
|
-
${magenta("zengo, zgo")} ${
|
|
65234
|
-
${magenta("v, vertex")} ${
|
|
65235
|
-
${magenta("go")} ${
|
|
65236
|
-
${magenta("poe")} ${
|
|
65237
|
-
${magenta("litellm, ll")} ${
|
|
65238
|
-
${magenta("ds")} ${
|
|
65239
|
-
${magenta("sakana, fugu")} ${
|
|
65240
|
-
${magenta("sc")} ${
|
|
65241
|
-
${magenta("ollama")} ${
|
|
65242
|
-
${magenta("lms, lmstudio")} ${
|
|
65243
|
-
${magenta("vllm")} ${
|
|
65244
|
-
${magenta("mlx")} ${
|
|
65245
|
-
|
|
65246
|
-
${
|
|
65247
|
-
${
|
|
65248
|
-
${
|
|
65249
|
-
${
|
|
65250
|
-
${
|
|
65251
|
-
${
|
|
65252
|
-
${
|
|
65253
|
-
${
|
|
65254
|
-
${
|
|
65255
|
-
${
|
|
65256
|
-
${
|
|
65257
|
-
${
|
|
65258
|
-
|
|
65259
|
-
${
|
|
65707
|
+
${bold4("New syntax:")} ${yellow2("provider@model[:concurrency]")}
|
|
65708
|
+
${magenta("google@gemini-3-pro")} ${dim3("Direct Google API (explicit)")}
|
|
65709
|
+
${magenta("openrouter@google/gemini-3-pro")} ${dim3("OpenRouter (explicit)")}
|
|
65710
|
+
${magenta("oai@gpt-5.3")} ${dim3("Direct OpenAI API (shortcut)")}
|
|
65711
|
+
${magenta("ollama@llama3.2:3")} ${dim3("Local Ollama, 3 concurrent requests")}
|
|
65712
|
+
${magenta("ollama@llama3.2:0")} ${dim3("Local Ollama, no limits")}
|
|
65713
|
+
|
|
65714
|
+
${bold4("Provider shortcuts:")}
|
|
65715
|
+
${magenta("g, gemini")} ${dim3("->")} Google Gemini ${dim3("google@gemini-3-pro")}
|
|
65716
|
+
${magenta("oai")} ${dim3("->")} OpenAI Direct ${dim3("oai@gpt-5.3")}
|
|
65717
|
+
${magenta("cx, codex")} ${dim3("->")} OpenAI Codex ${dim3("cx@gpt-5.3 (Responses API)")}
|
|
65718
|
+
${magenta("or")} ${dim3("->")} OpenRouter ${dim3("or@openai/gpt-5.3")}
|
|
65719
|
+
${magenta("x-ai, xai, grok")} ${dim3("->")} xAI / Grok ${dim3("x-ai@grok-3")}
|
|
65720
|
+
${magenta("mm, mmax")} ${dim3("->")} MiniMax Direct ${dim3("mm@MiniMax-M2.1")}
|
|
65721
|
+
${magenta("mmc")} ${dim3("->")} MiniMax Coding ${dim3("mmc@MiniMax-M2.1")}
|
|
65722
|
+
${magenta("kimi, moon")} ${dim3("->")} Kimi Direct ${dim3("kimi@kimi-k2-thinking-turbo")}
|
|
65723
|
+
${magenta("kc")} ${dim3("->")} Kimi Coding ${dim3("kc@kimi-k2-thinking-turbo")}
|
|
65724
|
+
${magenta("glm, zhipu")} ${dim3("->")} GLM Direct ${dim3("glm@glm-4.7")}
|
|
65725
|
+
${magenta("gc")} ${dim3("->")} GLM Coding ${dim3("gc@glm-4.7")}
|
|
65726
|
+
${magenta("z-ai, zai")} ${dim3("->")} Z.AI Direct ${dim3("z-ai@glm-4.7")}
|
|
65727
|
+
${magenta("oc, llama, lc, meta")} ${dim3("->")} OllamaCloud ${dim3("oc@llama-3.1")}
|
|
65728
|
+
${magenta("zen")} ${dim3("->")} OpenCode Zen ${dim3("zen@grok-code")}
|
|
65729
|
+
${magenta("zengo, zgo")} ${dim3("->")} OpenCode Zen Go ${dim3("zengo@grok-code")}
|
|
65730
|
+
${magenta("v, vertex")} ${dim3("->")} Vertex AI ${dim3("v@gemini-2.5-flash")}
|
|
65731
|
+
${magenta("go")} ${dim3("->")} Gemini Code Assist ${dim3("go@gemini-2.5-flash")}
|
|
65732
|
+
${magenta("poe")} ${dim3("->")} Poe ${dim3("poe@GPT-4o")}
|
|
65733
|
+
${magenta("litellm, ll")} ${dim3("->")} LiteLLM ${dim3("ll@gpt-4o (needs LITELLM_BASE_URL)")}
|
|
65734
|
+
${magenta("ds")} ${dim3("->")} DeepSeek ${dim3("ds@deepseek-chat")}
|
|
65735
|
+
${magenta("sakana, fugu")} ${dim3("->")} Sakana Fugu ${dim3("fugu@fugu-ultra")}
|
|
65736
|
+
${magenta("sc")} ${dim3("->")} Sakana Subscription ${dim3("sc@fugu-ultra")}
|
|
65737
|
+
${magenta("ollama")} ${dim3("->")} Ollama (local) ${dim3("ollama@llama3.2")}
|
|
65738
|
+
${magenta("lms, lmstudio")} ${dim3("->")} LM Studio (local) ${dim3("lms@qwen")}
|
|
65739
|
+
${magenta("vllm")} ${dim3("->")} vLLM (local) ${dim3("vllm@model")}
|
|
65740
|
+
${magenta("mlx")} ${dim3("->")} MLX (local) ${dim3("mlx@model")}
|
|
65741
|
+
|
|
65742
|
+
${bold4("Native auto-detection")} ${dim3("(when no provider specified):")}
|
|
65743
|
+
${yellow2("google/*, gemini-*")} ${dim3("->")} Google API
|
|
65744
|
+
${yellow2("openai/*, gpt-*, o1-*")} ${dim3("->")} OpenAI API
|
|
65745
|
+
${yellow2("x-ai/*, grok-*")} ${dim3("->")} xAI
|
|
65746
|
+
${yellow2("meta-llama/*, llama-*")} ${dim3("->")} OllamaCloud
|
|
65747
|
+
${yellow2("minimax/*, abab-*")} ${dim3("->")} MiniMax API
|
|
65748
|
+
${yellow2("moonshot/*, kimi-*")} ${dim3("->")} Kimi API
|
|
65749
|
+
${yellow2("zhipu/*, glm-*")} ${dim3("->")} GLM API
|
|
65750
|
+
${yellow2("sakana/*, fugu-*")} ${dim3("->")} Sakana Fugu
|
|
65751
|
+
${yellow2("poe:*")} ${dim3("->")} Poe
|
|
65752
|
+
${yellow2("anthropic/*, claude-*")} ${dim3("->")} Native Anthropic
|
|
65753
|
+
${yellow2("(unknown vendor/)")} ${dim3("->")} Error (use openrouter@vendor/model)
|
|
65754
|
+
|
|
65755
|
+
${dim3("A defaultProvider (config / --default-provider) catches bare names that match no rule.")}
|
|
65260
65756
|
|
|
65261
65757
|
${h("OPTIONS")}
|
|
65262
|
-
${
|
|
65263
|
-
${
|
|
65264
|
-
${
|
|
65265
|
-
${
|
|
65266
|
-
${
|
|
65267
|
-
${
|
|
65268
|
-
${
|
|
65269
|
-
${
|
|
65270
|
-
${
|
|
65271
|
-
${
|
|
65272
|
-
${
|
|
65273
|
-
${
|
|
65274
|
-
${
|
|
65275
|
-
${
|
|
65276
|
-
${
|
|
65277
|
-
${
|
|
65278
|
-
${
|
|
65279
|
-
${
|
|
65280
|
-
${
|
|
65281
|
-
${
|
|
65282
|
-
${
|
|
65283
|
-
${
|
|
65284
|
-
${
|
|
65285
|
-
${
|
|
65286
|
-
${
|
|
65287
|
-
${
|
|
65288
|
-
${
|
|
65289
|
-
${
|
|
65290
|
-
${
|
|
65291
|
-
${
|
|
65292
|
-
${
|
|
65293
|
-
${
|
|
65294
|
-
${
|
|
65295
|
-
${
|
|
65296
|
-
${
|
|
65297
|
-
${
|
|
65298
|
-
${
|
|
65299
|
-
${
|
|
65300
|
-
${
|
|
65301
|
-
${
|
|
65302
|
-
${
|
|
65303
|
-
${
|
|
65758
|
+
${green2("-i, --interactive")} Run in interactive mode (default when no prompt given)
|
|
65759
|
+
${green2("-m, --model")} ${yellow2("<model>")} Model to use (required for single-shot mode)
|
|
65760
|
+
${green2("--profile")} ${yellow2("<name>")} Use named profile for model mapping (default profile if omitted)
|
|
65761
|
+
${green2("--default-provider")} ${yellow2("<name>")} Fallback provider for bare model names (builtin or customEndpoints key)
|
|
65762
|
+
${dim3("Precedence: this flag > CLAUDISH_DEFAULT_PROVIDER env > config.json")}
|
|
65763
|
+
${green2("--anthropic-api-billing")} Use your real ANTHROPIC_API_KEY for native Claude models
|
|
65764
|
+
${dim3("(metered API billing). Default: the key is hidden so Claude Code")}
|
|
65765
|
+
${dim3("uses your claude.ai subscription. Env: CLAUDISH_ANTHROPIC_API_BILLING")}
|
|
65766
|
+
${dim3("Config: anthropicApiBilling: true")}
|
|
65767
|
+
${green2("--config")} ${yellow2("<file>")} Use THIS config file for the run, fully replacing the machine
|
|
65768
|
+
${dim3("global (~/.claudish/config.json) AND project (.claudish.json).")}
|
|
65769
|
+
${dim3("A file naming no op:// source never touches 1Password (no prompt).")}
|
|
65770
|
+
${dim3("Env vars still resolve first. Env: CLAUDISH_CONFIG")}
|
|
65771
|
+
${green2("--op")} ${yellow2("<op://glob>")} Load API keys from a 1Password item glob (SDK-based, no op CLI)
|
|
65772
|
+
${green2("--op")} ${yellow2("<glob>")} ${green2("--list")} Preview which fields the glob would import (names only, no values)
|
|
65773
|
+
${green2("--op-env")} ${yellow2("<id>")} Load env vars from a 1Password Environment (highest priority)
|
|
65774
|
+
${green2("--port")} ${yellow2("<port>")} Proxy server port (default: random)
|
|
65775
|
+
${green2("-d, --debug-claudish")} Enable claudish debug logging to file (logs/claudish_*.log)
|
|
65776
|
+
${dim3('Always-on: CLAUDISH_DEBUG=1 env var or "debug": true in config.json')}
|
|
65777
|
+
${green2("--no-debug-claudish")} Force debug logging off for this run (when globally enabled)
|
|
65778
|
+
${green2("--log-off")} Disable always-on structural logging (~/.claudish/logs/)
|
|
65779
|
+
${green2("--log-diag")} ${yellow2("<mode>")} Diagnostic output: auto (default), logfile, off
|
|
65780
|
+
${dim3('Also: CLAUDISH_DIAG_MODE env var or "diagMode" in config.json')}
|
|
65781
|
+
${green2("--log-level")} ${yellow2("<level>")} Log verbosity: debug (full), info (truncated), minimal (labels)
|
|
65782
|
+
${green2("-q, --quiet")} Suppress [claudish] log messages (default in single-shot mode)
|
|
65783
|
+
${green2("-v, --verbose")} Show [claudish] log messages (default in interactive mode)
|
|
65784
|
+
${green2("--json")} Output JSON for tool integration (implies --quiet)
|
|
65785
|
+
${green2("--stdin")} Read prompt from stdin (large prompts / piping)
|
|
65786
|
+
${green2("--free")} Show only FREE models in the interactive selector
|
|
65787
|
+
${green2("--monitor")} Monitor mode - proxy to REAL Anthropic API and log traffic
|
|
65788
|
+
${green2("--advisor")} ${yellow2('"m1,m2[:collector]"')} Multi-model advisor replacement (implies --monitor)
|
|
65789
|
+
${green2("-y, --auto-approve")} Skip permission prompts (--dangerously-skip-permissions)
|
|
65790
|
+
${green2("--no-auto-approve")} Explicitly enable permission prompts (default)
|
|
65791
|
+
${green2("--dangerous")} Pass --dangerouslyDisableSandbox to Claude Code
|
|
65792
|
+
${green2("--cost-track")} Enable cost tracking for API usage
|
|
65793
|
+
${green2("--cost-audit")} Show cost analysis report
|
|
65794
|
+
${green2("--cost-reset")} Reset accumulated cost statistics
|
|
65795
|
+
${green2("--version")} Show version information
|
|
65796
|
+
${green2("-h, --help")} Show this help message
|
|
65797
|
+
${green2("--help-ai")} Show AI agent usage guide (file-based patterns, sub-agents)
|
|
65798
|
+
${green2("--init")} Install Claudish skill in current project (.claude/skills/)
|
|
65799
|
+
${green2("--")} Separator: everything after passes directly to Claude Code
|
|
65304
65800
|
|
|
65305
65801
|
${h("MODEL DISCOVERY")}
|
|
65306
|
-
${
|
|
65307
|
-
${
|
|
65308
|
-
${
|
|
65309
|
-
${
|
|
65310
|
-
${
|
|
65311
|
-
${
|
|
65312
|
-
${
|
|
65313
|
-
${
|
|
65314
|
-
${
|
|
65315
|
-
${
|
|
65316
|
-
${
|
|
65317
|
-
${
|
|
65318
|
-
${
|
|
65319
|
-
${
|
|
65802
|
+
${green2("--models")} Top 100 ranked (Firebase + local providers)
|
|
65803
|
+
${green2("--models --provider")} ${yellow2("<slug>")} Filter the catalog to one provider
|
|
65804
|
+
${dim3("e.g. --provider opencode-zen, anthropic, openai")}
|
|
65805
|
+
${green2("--providers")} Every provider + active-model count
|
|
65806
|
+
${green2("-s, --models-search")} ${yellow2("<query>")} Fuzzy search: id, brand synonyms (chatgpt,
|
|
65807
|
+
${dim3("claude, grok), gateways (zen, oc, codex), caps")}
|
|
65808
|
+
${green2("--models-top")} Curated recommended models (flagship + fast)
|
|
65809
|
+
${green2("--probe")} ${yellow2("<models...>")} Probe each provider in the fallback chain with
|
|
65810
|
+
${dim3("a real 1-token request (may incur tiny cost)")}
|
|
65811
|
+
${green2("--no-probe")} Skip live requests, show static chain only
|
|
65812
|
+
${green2("--probe-timeout")} ${yellow2("<secs>")} Per-link timeout for live probes (default: 40)
|
|
65813
|
+
${green2("--models-refresh")} Force refresh the slim model catalog from Firebase
|
|
65814
|
+
${green2("--models-skip-update")} Skip the launcher catalog warm step (offline)
|
|
65815
|
+
${green2("--json")} JSON output (with --models / --models-top / --probe)
|
|
65320
65816
|
|
|
65321
65817
|
${h("TEAM MODE")}
|
|
65322
|
-
${
|
|
65323
|
-
${
|
|
65324
|
-
${
|
|
65325
|
-
${
|
|
65818
|
+
${green2("--team")} ${yellow2("<models>")} Run multiple models in parallel (comma-separated)
|
|
65819
|
+
${dim3('Example: --team minimax-m2.5,kimi-k2.5 "prompt"')}
|
|
65820
|
+
${green2("--mode")} ${yellow2("<mode>")} Team mode: default (grid), interactive, json
|
|
65821
|
+
${green2("-f, --file")} ${yellow2("<path>")} Read prompt from file (use with --team or single-shot)
|
|
65326
65822
|
|
|
65327
|
-
${h("MODEL MAPPING")} ${
|
|
65328
|
-
${
|
|
65329
|
-
${
|
|
65330
|
-
${
|
|
65331
|
-
${
|
|
65823
|
+
${h("MODEL MAPPING")} ${dim3("(per-role override)")}
|
|
65824
|
+
${green2("--model-opus")} ${yellow2("<model>")} Model for Opus role (planning, complex tasks)
|
|
65825
|
+
${green2("--model-sonnet")} ${yellow2("<model>")} Model for Sonnet role (default coding)
|
|
65826
|
+
${green2("--model-haiku")} ${yellow2("<model>")} Model for Haiku role (fast tasks, background)
|
|
65827
|
+
${green2("--model-subagent")} ${yellow2("<model>")} Model for sub-agents (Task tool)
|
|
65332
65828
|
|
|
65333
65829
|
${h("SUBCOMMANDS")}
|
|
65334
|
-
${
|
|
65335
|
-
${
|
|
65336
|
-
${
|
|
65337
|
-
${
|
|
65338
|
-
${
|
|
65339
|
-
${
|
|
65340
|
-
|
|
65341
|
-
${
|
|
65342
|
-
${
|
|
65343
|
-
${
|
|
65344
|
-
${
|
|
65345
|
-
${
|
|
65346
|
-
${
|
|
65347
|
-
${
|
|
65348
|
-
${
|
|
65349
|
-
${
|
|
65350
|
-
|
|
65351
|
-
${
|
|
65352
|
-
${
|
|
65353
|
-
${
|
|
65354
|
-
${
|
|
65355
|
-
|
|
65356
|
-
${h("1PASSWORD")} ${
|
|
65357
|
-
${
|
|
65358
|
-
${
|
|
65359
|
-
${
|
|
65360
|
-
${
|
|
65361
|
-
${
|
|
65362
|
-
${
|
|
65363
|
-
${
|
|
65830
|
+
${green2("claudish config")} Open the interactive config TUI (profiles,
|
|
65831
|
+
${dim3("providers, routing, 1Password)")}
|
|
65832
|
+
${green2("claudish providers")} ${yellow2("[--json]")} Show provider credential status (no key material)
|
|
65833
|
+
${green2("claudish quota")} ${yellow2("[provider]")} Show remaining quota/usage (alias: usage)
|
|
65834
|
+
${green2("claudish serve")} ${yellow2("--port <n> --models <p>")} Run the Claude Desktop redirect gateway
|
|
65835
|
+
${green2("claudish update")} Check for updates and install the latest version
|
|
65836
|
+
|
|
65837
|
+
${bold4("Profiles:")}
|
|
65838
|
+
${green2("claudish init")} ${yellow2("[--local|--global]")} Setup wizard - create config + first profile
|
|
65839
|
+
${green2("claudish profile list")} ${yellow2("[scope]")} List all profiles (both scopes by default)
|
|
65840
|
+
${green2("claudish profile add")} ${yellow2("[scope]")} Add a new profile
|
|
65841
|
+
${green2("claudish profile remove")} ${yellow2("[name] [scope]")} Remove a profile
|
|
65842
|
+
${green2("claudish profile use")} ${yellow2("[name] [scope]")} Set default profile
|
|
65843
|
+
${green2("claudish profile show")} ${yellow2("[name] [scope]")} Show profile details
|
|
65844
|
+
${green2("claudish profile edit")} ${yellow2("[name] [scope]")} Edit a profile
|
|
65845
|
+
${dim3("scope = --local (.claudish.json) | --global (~/.claudish/config.json) | (prompted)")}
|
|
65846
|
+
|
|
65847
|
+
${bold4("Authentication:")}
|
|
65848
|
+
${green2("claudish login")} ${yellow2("[provider]")} Login to an OAuth provider (interactive if omitted)
|
|
65849
|
+
${green2("claudish logout")} ${yellow2("[provider]")} Clear OAuth credentials
|
|
65850
|
+
${dim3("Providers: gemini, kimi")}
|
|
65851
|
+
|
|
65852
|
+
${h("1PASSWORD")} ${dim3("(SDK-based \u2014 no op CLI needed for secrets)")}
|
|
65853
|
+
${dim3("Auth via OP_SERVICE_ACCOUNT_TOKEN, or OP_ACCOUNT / onepasswordAccount config (DesktopAuth).")}
|
|
65854
|
+
${green2("--op")} ${yellow2("<glob> --list")} Preview which fields a glob would import (names only)
|
|
65855
|
+
${green2("--op")} ${yellow2("<glob>")} ${yellow2("[...args]")} Resolve a glob into env vars, then run a session
|
|
65856
|
+
${dim3("Inline op import requires a GLOB (self-names via field labels)")}
|
|
65857
|
+
${dim3('Example: claudish --op "op://Jack/Keys/**" --model gpt-4o "task"')}
|
|
65858
|
+
${green2("--op-env")} ${yellow2("<id>")} Load a 1Password Environment (highest-priority source)
|
|
65859
|
+
${dim3("Persistent setup (single refs, sets, environments, account): claudish config -> 1Password tab")}
|
|
65364
65860
|
|
|
65365
65861
|
${h("CLAUDE CODE FLAG PASSTHROUGH")}
|
|
65366
|
-
${
|
|
65367
|
-
${
|
|
65368
|
-
${
|
|
65369
|
-
${
|
|
65370
|
-
${
|
|
65371
|
-
${
|
|
65862
|
+
${dim3("Any unrecognized flag is forwarded to Claude Code. Claudish flags can appear in any order.")}
|
|
65863
|
+
${green2("claudish")} --model grok ${yellow2("--agent test")} ${yellow2('"task"')} ${dim3("# --agent passes through")}
|
|
65864
|
+
${green2("claudish")} --model grok ${yellow2("--effort high")} --stdin ${yellow2('"task"')} ${dim3("# --effort passes, --stdin stays")}
|
|
65865
|
+
${green2("claudish")} --model grok ${yellow2("--permission-mode plan")} -i ${dim3("# works in interactive too")}
|
|
65866
|
+
${dim3("Use -- when a Claude Code flag value starts with '-':")}
|
|
65867
|
+
${green2("claudish")} --model grok ${green2("--")} ${yellow2('--system-prompt "-verbose mode" "task"')}
|
|
65372
65868
|
|
|
65373
65869
|
${h("CUSTOM MODELS & ENDPOINTS")}
|
|
65374
|
-
${
|
|
65375
|
-
${
|
|
65376
|
-
${
|
|
65377
|
-
${
|
|
65870
|
+
${dim3("Claudish accepts ANY valid model ID from the Firebase catalog, even if not in --models:")}
|
|
65871
|
+
${green2("claudish")} --model ${yellow2("openrouter@your_provider/custom-model-123")} ${yellow2('"task"')}
|
|
65872
|
+
${dim3("Named custom endpoints live in ~/.claudish/config.json under 'customEndpoints' and route via @:")}
|
|
65873
|
+
${green2("claudish")} --model ${yellow2("my-vllm@llama3.1-70b")} ${yellow2('"task"')}
|
|
65378
65874
|
|
|
65379
65875
|
${h("MODES")}
|
|
65380
|
-
${
|
|
65381
|
-
${
|
|
65876
|
+
${green2("\u2022")} ${bold4("Interactive")} ${dim3("(default):")} shows model selector, starts a persistent session
|
|
65877
|
+
${green2("\u2022")} ${bold4("Single-shot")} ${dim3("(--model):")} runs one task headless and exits
|
|
65382
65878
|
|
|
65383
65879
|
${h("NOTES")}
|
|
65384
|
-
${
|
|
65385
|
-
${
|
|
65386
|
-
${
|
|
65387
|
-
${
|
|
65880
|
+
${yellow2("\u2022")} Permission prompts are ${bold4("ENABLED")} by default (normal Claude Code behavior)
|
|
65881
|
+
${yellow2("\u2022")} Use ${green2("-y")} / ${green2("--auto-approve")} to skip permission prompts
|
|
65882
|
+
${yellow2("\u2022")} Model selector appears ONLY in interactive mode when ${green2("--model")} not specified
|
|
65883
|
+
${yellow2("\u2022")} ${green2("--dangerous")} disables the sandbox \u2014 use with extreme caution
|
|
65388
65884
|
|
|
65389
65885
|
${h("ENVIRONMENT VARIABLES")}
|
|
65390
|
-
${
|
|
65886
|
+
${dim3("Claudish auto-loads a .env file from the current directory.")}
|
|
65391
65887
|
|
|
65392
|
-
${
|
|
65888
|
+
${bold4("Claude Code installation:")}
|
|
65393
65889
|
${blue("CLAUDE_PATH")} Custom path to Claude Code binary
|
|
65394
|
-
${
|
|
65890
|
+
${dim3("Search: CLAUDE_PATH -> ~/.claude/local/claude -> PATH")}
|
|
65395
65891
|
|
|
65396
|
-
${
|
|
65892
|
+
${bold4("API keys")} ${dim3("(at least one required for cloud models):")}
|
|
65397
65893
|
${blue("OPENROUTER_API_KEY")} OpenRouter (default backend)
|
|
65398
|
-
${blue("GEMINI_API_KEY")} Google Gemini ${
|
|
65399
|
-
${blue("OPENAI_API_KEY")} OpenAI ${
|
|
65400
|
-
${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${
|
|
65401
|
-
${blue("XAI_API_KEY")} xAI / Grok ${
|
|
65402
|
-
${blue("MINIMAX_API_KEY")} MiniMax ${
|
|
65403
|
-
${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${
|
|
65404
|
-
${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${
|
|
65405
|
-
${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${
|
|
65406
|
-
${blue("ZHIPU_API_KEY")} GLM / Zhipu ${
|
|
65407
|
-
${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${
|
|
65408
|
-
${blue("ZAI_API_KEY")} Z.AI ${
|
|
65409
|
-
${blue("DEEPSEEK_API_KEY")} DeepSeek ${
|
|
65410
|
-
${blue("SAKANA_API_KEY")} Sakana Fugu ${
|
|
65411
|
-
${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${
|
|
65412
|
-
${blue("OLLAMA_API_KEY")} OllamaCloud ${
|
|
65413
|
-
${blue("OPENCODE_API_KEY")} OpenCode Zen ${
|
|
65414
|
-
${blue("POE_API_KEY")} Poe ${
|
|
65415
|
-
${blue("LITELLM_API_KEY")} LiteLLM ${
|
|
65416
|
-
${blue("VERTEX_API_KEY")} Vertex AI Express ${
|
|
65417
|
-
${blue("VERTEX_PROJECT")} Vertex AI project ID ${
|
|
65418
|
-
${blue("VERTEX_LOCATION")} Vertex AI region ${
|
|
65894
|
+
${blue("GEMINI_API_KEY")} Google Gemini ${dim3("(g@, gemini@; alias GOOGLE_API_KEY)")}
|
|
65895
|
+
${blue("OPENAI_API_KEY")} OpenAI ${dim3("(oai@)")}
|
|
65896
|
+
${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${dim3("(cx@, codex@)")}
|
|
65897
|
+
${blue("XAI_API_KEY")} xAI / Grok ${dim3("(x-ai@, grok@)")}
|
|
65898
|
+
${blue("MINIMAX_API_KEY")} MiniMax ${dim3("(mm@, mmax@)")}
|
|
65899
|
+
${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${dim3("(mmc@)")}
|
|
65900
|
+
${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${dim3("(kimi@, moon@; alias KIMI_API_KEY)")}
|
|
65901
|
+
${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${dim3("(kc@)")}
|
|
65902
|
+
${blue("ZHIPU_API_KEY")} GLM / Zhipu ${dim3("(glm@, zhipu@; alias GLM_API_KEY)")}
|
|
65903
|
+
${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${dim3("(gc@; alias ZAI_CODING_API_KEY)")}
|
|
65904
|
+
${blue("ZAI_API_KEY")} Z.AI ${dim3("(z-ai@, zai@)")}
|
|
65905
|
+
${blue("DEEPSEEK_API_KEY")} DeepSeek ${dim3("(ds@)")}
|
|
65906
|
+
${blue("SAKANA_API_KEY")} Sakana Fugu ${dim3("(sakana@, fugu@)")}
|
|
65907
|
+
${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${dim3("(sc@; separate subscription key)")}
|
|
65908
|
+
${blue("OLLAMA_API_KEY")} OllamaCloud ${dim3("(oc@, llama@)")}
|
|
65909
|
+
${blue("OPENCODE_API_KEY")} OpenCode Zen ${dim3("(zen@; optional - free models work without it)")}
|
|
65910
|
+
${blue("POE_API_KEY")} Poe ${dim3("(poe@)")}
|
|
65911
|
+
${blue("LITELLM_API_KEY")} LiteLLM ${dim3("(litellm@, ll@; needs LITELLM_BASE_URL)")}
|
|
65912
|
+
${blue("VERTEX_API_KEY")} Vertex AI Express ${dim3("(v@)")}
|
|
65913
|
+
${blue("VERTEX_PROJECT")} Vertex AI project ID ${dim3("(OAuth mode, v@)")}
|
|
65914
|
+
${blue("VERTEX_LOCATION")} Vertex AI region ${dim3("(default: us-central1)")}
|
|
65419
65915
|
${blue("ANTHROPIC_API_KEY")} Placeholder (prevents Claude Code dialog)
|
|
65420
65916
|
${blue("ANTHROPIC_AUTH_TOKEN")} Placeholder (prevents Claude Code login screen)
|
|
65421
65917
|
|
|
65422
|
-
${
|
|
65918
|
+
${bold4("Custom / base-URL overrides:")}
|
|
65423
65919
|
${blue("GEMINI_BASE_URL")} Custom Gemini endpoint
|
|
65424
65920
|
${blue("OPENAI_BASE_URL")} Custom OpenAI / Azure endpoint
|
|
65425
65921
|
${blue("MINIMAX_BASE_URL")} Custom MiniMax endpoint
|
|
65426
|
-
${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${
|
|
65427
|
-
${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${
|
|
65428
|
-
${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${
|
|
65429
|
-
${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${
|
|
65430
|
-
${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${
|
|
65431
|
-
${blue("OPENCODE_BASE_URL")} OpenCode Zen ${
|
|
65432
|
-
|
|
65433
|
-
${
|
|
65434
|
-
${blue("OLLAMA_BASE_URL")} Ollama server ${
|
|
65435
|
-
${blue("LMSTUDIO_BASE_URL")} LM Studio server ${
|
|
65436
|
-
${blue("VLLM_BASE_URL")} vLLM server ${
|
|
65437
|
-
${blue("MLX_BASE_URL")} MLX server ${
|
|
65438
|
-
|
|
65439
|
-
${
|
|
65440
|
-
${blue("CLAUDISH_MODEL")} Default model ${
|
|
65441
|
-
${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${
|
|
65922
|
+
${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${dim3("(alias KIMI_BASE_URL)")}
|
|
65923
|
+
${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${dim3("(alias GLM_BASE_URL)")}
|
|
65924
|
+
${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${dim3("(default: https://api.sakana.ai)")}
|
|
65925
|
+
${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${dim3("(required for ll@)")}
|
|
65926
|
+
${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${dim3("(default: https://ollama.com)")}
|
|
65927
|
+
${blue("OPENCODE_BASE_URL")} OpenCode Zen ${dim3("(default: https://opencode.ai/zen)")}
|
|
65928
|
+
|
|
65929
|
+
${bold4("Local providers:")}
|
|
65930
|
+
${blue("OLLAMA_BASE_URL")} Ollama server ${dim3("(default: http://localhost:11434; alias OLLAMA_HOST)")}
|
|
65931
|
+
${blue("LMSTUDIO_BASE_URL")} LM Studio server ${dim3("(default: http://localhost:1234)")}
|
|
65932
|
+
${blue("VLLM_BASE_URL")} vLLM server ${dim3("(default: http://localhost:8000)")}
|
|
65933
|
+
${blue("MLX_BASE_URL")} MLX server ${dim3("(default: http://127.0.0.1:8080)")}
|
|
65934
|
+
|
|
65935
|
+
${bold4("Claudish settings:")}
|
|
65936
|
+
${blue("CLAUDISH_MODEL")} Default model ${dim3("(default: openai/gpt-5.3)")}
|
|
65937
|
+
${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${dim3("(see --default-provider)")}
|
|
65442
65938
|
${blue("CLAUDISH_PORT")} Default proxy port
|
|
65443
65939
|
${blue("CLAUDISH_CONTEXT_WINDOW")} Override context window size
|
|
65444
65940
|
${blue("CLAUDISH_DIAG_MODE")} Diagnostic output: auto / logfile / off
|
|
65445
|
-
${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${
|
|
65446
|
-
${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${
|
|
65941
|
+
${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${dim3("(same as -d)")}
|
|
65942
|
+
${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${dim3("(see --anthropic-api-billing)")}
|
|
65447
65943
|
${blue("CLAUDISH_MCP_TOOLS")} MCP tool gating: all / low-level / agentic / channel
|
|
65448
65944
|
${blue("CLAUDISH_MODEL_OPUS")} Override model for Opus role
|
|
65449
65945
|
${blue("CLAUDISH_MODEL_SONNET")} Override model for Sonnet role
|
|
@@ -65451,47 +65947,47 @@ ${h("ENVIRONMENT VARIABLES")}
|
|
|
65451
65947
|
${blue("CLAUDISH_MODEL_SUBAGENT")} Override model for sub-agents
|
|
65452
65948
|
${blue("NO_COLOR")} Set to disable colored output
|
|
65453
65949
|
|
|
65454
|
-
${
|
|
65950
|
+
${bold4("1Password auth:")}
|
|
65455
65951
|
${blue("OP_SERVICE_ACCOUNT_TOKEN")} Service-account token (preferred for headless)
|
|
65456
|
-
${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${
|
|
65952
|
+
${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${dim3("(e.g. my-team.1password.com)")}
|
|
65457
65953
|
|
|
65458
65954
|
${h("EXAMPLES")}
|
|
65459
|
-
${
|
|
65460
|
-
${
|
|
65461
|
-
${
|
|
65955
|
+
${dim3("# Interactive (default) - model selector")}
|
|
65956
|
+
${green2("claudish")}
|
|
65957
|
+
${green2("claudish")} --free ${dim3("# only FREE models")}
|
|
65462
65958
|
|
|
65463
|
-
${
|
|
65464
|
-
${
|
|
65465
|
-
${
|
|
65466
|
-
${
|
|
65959
|
+
${dim3("# Explicit provider routing")}
|
|
65960
|
+
${green2("claudish")} --model ${magenta("google@gemini-3-pro")} ${yellow2('"implement auth"')}
|
|
65961
|
+
${green2("claudish")} --model ${magenta("oai@gpt-5.3")} ${yellow2('"add tests for login"')}
|
|
65962
|
+
${green2("claudish")} --model ${magenta("openrouter@deepseek/deepseek-r1")} ${yellow2('"unknown vendor"')}
|
|
65467
65963
|
|
|
65468
|
-
${
|
|
65469
|
-
${
|
|
65470
|
-
${
|
|
65964
|
+
${dim3("# Native auto-detection (provider inferred from model name)")}
|
|
65965
|
+
${green2("claudish")} --model ${yellow2("gpt-4o")} ${yellow2('"routes to OpenAI"')}
|
|
65966
|
+
${green2("claudish")} --model ${yellow2("gemini-2.5-pro")} ${yellow2('"routes to Google"')}
|
|
65471
65967
|
|
|
65472
|
-
${
|
|
65473
|
-
${
|
|
65968
|
+
${dim3("# Per-role model mapping")}
|
|
65969
|
+
${green2("claudish")} --model-opus ${magenta("oai@gpt-5.3")} --model-sonnet ${magenta("google@gemini-3-pro")}
|
|
65474
65970
|
|
|
65475
|
-
${
|
|
65476
|
-
${
|
|
65971
|
+
${dim3("# stdin for large prompts (diffs, code review)")}
|
|
65972
|
+
${dim3("git diff |")} ${green2("claudish")} --stdin --model ${magenta("oai@gpt-5.3")} ${yellow2('"Review these changes"')}
|
|
65477
65973
|
|
|
65478
|
-
${
|
|
65479
|
-
${
|
|
65480
|
-
${
|
|
65481
|
-
${
|
|
65974
|
+
${dim3("# Local models with concurrency control")}
|
|
65975
|
+
${green2("claudish")} --model ${magenta("ollama@llama3.2:3")} ${yellow2('"3 concurrent requests"')}
|
|
65976
|
+
${green2("claudish")} --model ${magenta("lms@qwen2.5-coder")} ${yellow2('"LM Studio shortcut"')}
|
|
65977
|
+
${green2("claudish")} --model ${yellow2('"http://localhost:8000/mistral"')} ${yellow2('"any OpenAI-compatible URL"')}
|
|
65482
65978
|
|
|
65483
|
-
${
|
|
65484
|
-
${
|
|
65979
|
+
${dim3("# Autonomous (no prompts, no sandbox) \u2014 use with caution")}
|
|
65980
|
+
${green2("claudish")} -y --dangerous ${yellow2('"refactor entire codebase"')}
|
|
65485
65981
|
|
|
65486
65982
|
${h("MORE INFO")}
|
|
65487
|
-
${
|
|
65488
|
-
${
|
|
65983
|
+
${dim3("GitHub:")} ${blue("https://github.com/MadAppGang/claude-code")}
|
|
65984
|
+
${dim3("OpenRouter:")} ${blue("https://openrouter.ai")}
|
|
65489
65985
|
`);
|
|
65490
65986
|
}
|
|
65491
65987
|
function printAIAgentGuide() {
|
|
65492
65988
|
try {
|
|
65493
|
-
const guidePath =
|
|
65494
|
-
const guideContent =
|
|
65989
|
+
const guidePath = join27(__dirname3, "../AI_AGENT_GUIDE.md");
|
|
65990
|
+
const guideContent = readFileSync21(guidePath, "utf-8");
|
|
65495
65991
|
console.log(guideContent);
|
|
65496
65992
|
} catch (error46) {
|
|
65497
65993
|
console.error("Error reading AI Agent Guide:");
|
|
@@ -65507,10 +66003,10 @@ async function initializeClaudishSkill() {
|
|
|
65507
66003
|
console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
|
|
65508
66004
|
`);
|
|
65509
66005
|
const cwd = process.cwd();
|
|
65510
|
-
const claudeDir =
|
|
65511
|
-
const skillsDir =
|
|
65512
|
-
const claudishSkillDir =
|
|
65513
|
-
const skillFile =
|
|
66006
|
+
const claudeDir = join27(cwd, ".claude");
|
|
66007
|
+
const skillsDir = join27(claudeDir, "skills");
|
|
66008
|
+
const claudishSkillDir = join27(skillsDir, "claudish-usage");
|
|
66009
|
+
const skillFile = join27(claudishSkillDir, "SKILL.md");
|
|
65514
66010
|
if (existsSync21(skillFile)) {
|
|
65515
66011
|
console.log("\u2705 Claudish skill already installed at:");
|
|
65516
66012
|
console.log(` ${skillFile}
|
|
@@ -65518,7 +66014,7 @@ async function initializeClaudishSkill() {
|
|
|
65518
66014
|
console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
|
|
65519
66015
|
return;
|
|
65520
66016
|
}
|
|
65521
|
-
const sourceSkillPath =
|
|
66017
|
+
const sourceSkillPath = join27(__dirname3, "../skills/claudish-usage/SKILL.md");
|
|
65522
66018
|
if (!existsSync21(sourceSkillPath)) {
|
|
65523
66019
|
console.error("\u274C Error: Claudish skill file not found in installation.");
|
|
65524
66020
|
console.error(` Expected at: ${sourceSkillPath}`);
|
|
@@ -65609,7 +66105,7 @@ var init_cli = __esm(() => {
|
|
|
65609
66105
|
init_routing_rules();
|
|
65610
66106
|
init_provider_resolver();
|
|
65611
66107
|
__filename3 = fileURLToPath2(import.meta.url);
|
|
65612
|
-
__dirname3 =
|
|
66108
|
+
__dirname3 = dirname9(__filename3);
|
|
65613
66109
|
});
|
|
65614
66110
|
|
|
65615
66111
|
// src/update-checker.ts
|
|
@@ -65621,24 +66117,24 @@ __export(exports_update_checker, {
|
|
|
65621
66117
|
clearCache: () => clearCache,
|
|
65622
66118
|
checkForUpdates: () => checkForUpdates
|
|
65623
66119
|
});
|
|
65624
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as
|
|
65625
|
-
import { homedir as
|
|
65626
|
-
import { join as
|
|
66120
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync22, unlinkSync as unlinkSync8, writeFileSync as writeFileSync16 } from "fs";
|
|
66121
|
+
import { homedir as homedir26, platform as platform2, tmpdir } from "os";
|
|
66122
|
+
import { join as join28 } from "path";
|
|
65627
66123
|
function getCacheFilePath() {
|
|
65628
66124
|
let cacheDir;
|
|
65629
66125
|
if (isWindows) {
|
|
65630
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
65631
|
-
cacheDir =
|
|
66126
|
+
const localAppData = process.env.LOCALAPPDATA || join28(homedir26(), "AppData", "Local");
|
|
66127
|
+
cacheDir = join28(localAppData, "claudish");
|
|
65632
66128
|
} else {
|
|
65633
|
-
cacheDir =
|
|
66129
|
+
cacheDir = join28(homedir26(), ".cache", "claudish");
|
|
65634
66130
|
}
|
|
65635
66131
|
try {
|
|
65636
66132
|
if (!existsSync22(cacheDir)) {
|
|
65637
66133
|
mkdirSync14(cacheDir, { recursive: true });
|
|
65638
66134
|
}
|
|
65639
|
-
return
|
|
66135
|
+
return join28(cacheDir, "update-check.json");
|
|
65640
66136
|
} catch {
|
|
65641
|
-
return
|
|
66137
|
+
return join28(tmpdir(), "claudish-update-check.json");
|
|
65642
66138
|
}
|
|
65643
66139
|
}
|
|
65644
66140
|
function readCache() {
|
|
@@ -65647,7 +66143,7 @@ function readCache() {
|
|
|
65647
66143
|
if (!existsSync22(cachePath)) {
|
|
65648
66144
|
return null;
|
|
65649
66145
|
}
|
|
65650
|
-
const data = JSON.parse(
|
|
66146
|
+
const data = JSON.parse(readFileSync22(cachePath, "utf-8"));
|
|
65651
66147
|
return data;
|
|
65652
66148
|
} catch {
|
|
65653
66149
|
return null;
|
|
@@ -66518,16 +67014,22 @@ function localBaseUrl(catalogName) {
|
|
|
66518
67014
|
}
|
|
66519
67015
|
return (def.baseUrl || "").replace(/\/+$/, "") || null;
|
|
66520
67016
|
}
|
|
67017
|
+
function isHtmlResponse(res) {
|
|
67018
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
67019
|
+
return /\btext\/html\b|\bapplication\/xhtml\+xml\b/i.test(contentType);
|
|
67020
|
+
}
|
|
66521
67021
|
async function pingLocalProvider(catalogName, timeoutMs = PING_TIMEOUT_MS) {
|
|
66522
67022
|
const base = localBaseUrl(catalogName);
|
|
66523
67023
|
const path2 = HEALTH_PATH[catalogName];
|
|
66524
67024
|
if (!base || !path2)
|
|
66525
67025
|
return "unknown";
|
|
66526
67026
|
try {
|
|
66527
|
-
await fetch(`${base}${path2}`, {
|
|
67027
|
+
const res = await fetch(`${base}${path2}`, {
|
|
66528
67028
|
method: "GET",
|
|
66529
67029
|
signal: AbortSignal.timeout(timeoutMs)
|
|
66530
67030
|
});
|
|
67031
|
+
if (res.ok && isHtmlResponse(res))
|
|
67032
|
+
return "down";
|
|
66531
67033
|
return "running";
|
|
66532
67034
|
} catch {
|
|
66533
67035
|
return "down";
|
|
@@ -66549,15 +67051,15 @@ var init_local_liveness = __esm(() => {
|
|
|
66549
67051
|
});
|
|
66550
67052
|
|
|
66551
67053
|
// src/providers/probe-catalog.ts
|
|
66552
|
-
import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as
|
|
66553
|
-
import { homedir as
|
|
66554
|
-
import { dirname as
|
|
67054
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync23, writeFileSync as writeFileSync17 } from "fs";
|
|
67055
|
+
import { homedir as homedir27 } from "os";
|
|
67056
|
+
import { dirname as dirname10, join as join29 } from "path";
|
|
66555
67057
|
function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
|
|
66556
67058
|
if (!existsSync23(path2))
|
|
66557
67059
|
return null;
|
|
66558
67060
|
let raw2;
|
|
66559
67061
|
try {
|
|
66560
|
-
raw2 = JSON.parse(
|
|
67062
|
+
raw2 = JSON.parse(readFileSync23(path2, "utf-8"));
|
|
66561
67063
|
} catch {
|
|
66562
67064
|
return null;
|
|
66563
67065
|
}
|
|
@@ -66566,7 +67068,7 @@ function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
|
|
|
66566
67068
|
return raw2;
|
|
66567
67069
|
}
|
|
66568
67070
|
function writeProbeModelsCache(data, path2 = PROBE_MODELS_CACHE_PATH) {
|
|
66569
|
-
mkdirSync15(
|
|
67071
|
+
mkdirSync15(dirname10(path2), { recursive: true });
|
|
66570
67072
|
writeFileSync17(path2, JSON.stringify(data), "utf-8");
|
|
66571
67073
|
}
|
|
66572
67074
|
function isCacheFresh(data, ttlMs = CACHE_TTL_MS4) {
|
|
@@ -66686,7 +67188,7 @@ function isValidResponse(raw2) {
|
|
|
66686
67188
|
var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS4, FETCH_TIMEOUT_MS3 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null;
|
|
66687
67189
|
var init_probe_catalog = __esm(() => {
|
|
66688
67190
|
CACHE_TTL_MS4 = 60 * 60 * 1000;
|
|
66689
|
-
PROBE_MODELS_CACHE_PATH =
|
|
67191
|
+
PROBE_MODELS_CACHE_PATH = join29(homedir27(), ".claudish", "probe-models.json");
|
|
66690
67192
|
});
|
|
66691
67193
|
|
|
66692
67194
|
// src/tui/constants.ts
|
|
@@ -73026,12 +73528,12 @@ import {
|
|
|
73026
73528
|
existsSync as existsSync24,
|
|
73027
73529
|
mkdirSync as mkdirSync16,
|
|
73028
73530
|
openSync as openSync5,
|
|
73029
|
-
readFileSync as
|
|
73531
|
+
readFileSync as readFileSync24,
|
|
73030
73532
|
unlinkSync as unlinkSync9,
|
|
73031
73533
|
writeFileSync as writeFileSync18
|
|
73032
73534
|
} from "fs";
|
|
73033
|
-
import { homedir as
|
|
73034
|
-
import { join as
|
|
73535
|
+
import { homedir as homedir28, tmpdir as tmpdir2 } from "os";
|
|
73536
|
+
import { join as join30 } from "path";
|
|
73035
73537
|
import { isatty } from "tty";
|
|
73036
73538
|
function releaseTerminalIsolation() {
|
|
73037
73539
|
if (!restoreTerminal)
|
|
@@ -73066,14 +73568,14 @@ function isProxyAuthMode(config3) {
|
|
|
73066
73568
|
}
|
|
73067
73569
|
function managedSettingsPath() {
|
|
73068
73570
|
if (isWindows2()) {
|
|
73069
|
-
return
|
|
73571
|
+
return join30(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
|
|
73070
73572
|
}
|
|
73071
73573
|
if (process.platform === "darwin") {
|
|
73072
73574
|
return "/Library/Application Support/ClaudeCode/managed-settings.json";
|
|
73073
73575
|
}
|
|
73074
73576
|
return "/etc/claude-code/managed-settings.json";
|
|
73075
73577
|
}
|
|
73076
|
-
function managedSettingsForcesClaudeAi(readFile =
|
|
73578
|
+
function managedSettingsForcesClaudeAi(readFile = readFileSync24) {
|
|
73077
73579
|
try {
|
|
73078
73580
|
const raw2 = readFile(managedSettingsPath(), "utf-8");
|
|
73079
73581
|
const parsed = JSON.parse(raw2);
|
|
@@ -73087,9 +73589,9 @@ function isWindows2() {
|
|
|
73087
73589
|
}
|
|
73088
73590
|
function createStatusLineScript(tokenFilePath) {
|
|
73089
73591
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
|
|
73090
|
-
const claudishDir =
|
|
73592
|
+
const claudishDir = join30(homeDir, ".claudish");
|
|
73091
73593
|
const timestamp = Date.now();
|
|
73092
|
-
const scriptPath =
|
|
73594
|
+
const scriptPath = join30(claudishDir, `status-${timestamp}.js`);
|
|
73093
73595
|
const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
|
|
73094
73596
|
const script = `
|
|
73095
73597
|
const fs = require('fs');
|
|
@@ -73212,13 +73714,13 @@ process.stdin.on('end', () => {
|
|
|
73212
73714
|
}
|
|
73213
73715
|
function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
|
|
73214
73716
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
|
|
73215
|
-
const claudishDir =
|
|
73717
|
+
const claudishDir = join30(homeDir, ".claudish");
|
|
73216
73718
|
try {
|
|
73217
73719
|
mkdirSync16(claudishDir, { recursive: true });
|
|
73218
73720
|
} catch {}
|
|
73219
73721
|
const timestamp = Date.now();
|
|
73220
|
-
const tempPath =
|
|
73221
|
-
const tokenFilePath =
|
|
73722
|
+
const tempPath = join30(claudishDir, `settings-${timestamp}.json`);
|
|
73723
|
+
const tokenFilePath = join30(claudishDir, `tokens-${port}.json`);
|
|
73222
73724
|
let statusCommand;
|
|
73223
73725
|
if (isWindows2()) {
|
|
73224
73726
|
const scriptPath = createStatusLineScript(tokenFilePath);
|
|
@@ -73262,7 +73764,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
|
|
|
73262
73764
|
if (userSettingsValue.trimStart().startsWith("{")) {
|
|
73263
73765
|
userSettings = JSON.parse(userSettingsValue);
|
|
73264
73766
|
} else {
|
|
73265
|
-
const rawUserSettings =
|
|
73767
|
+
const rawUserSettings = readFileSync24(userSettingsValue, "utf-8");
|
|
73266
73768
|
userSettings = JSON.parse(rawUserSettings);
|
|
73267
73769
|
}
|
|
73268
73770
|
userSettings.statusLine = statusLine;
|
|
@@ -73433,8 +73935,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
|
|
|
73433
73935
|
console.error("Install it from: https://claude.com/claude-code");
|
|
73434
73936
|
console.error(`
|
|
73435
73937
|
Or set CLAUDE_PATH to your custom installation:`);
|
|
73436
|
-
const home =
|
|
73437
|
-
const localPath = isWindows2() ?
|
|
73938
|
+
const home = homedir28();
|
|
73939
|
+
const localPath = isWindows2() ? join30(home, ".claude", "local", "claude.exe") : join30(home, ".claude", "local", "claude");
|
|
73438
73940
|
console.error(` export CLAUDE_PATH=${localPath}`);
|
|
73439
73941
|
process.exit(1);
|
|
73440
73942
|
}
|
|
@@ -73518,16 +74020,16 @@ async function findClaudeBinary() {
|
|
|
73518
74020
|
return process.env.CLAUDE_PATH;
|
|
73519
74021
|
}
|
|
73520
74022
|
}
|
|
73521
|
-
const home =
|
|
73522
|
-
const localPath = isWindows3 ?
|
|
74023
|
+
const home = homedir28();
|
|
74024
|
+
const localPath = isWindows3 ? join30(home, ".claude", "local", "claude.exe") : join30(home, ".claude", "local", "claude");
|
|
73523
74025
|
if (existsSync24(localPath)) {
|
|
73524
74026
|
return localPath;
|
|
73525
74027
|
}
|
|
73526
74028
|
if (isWindows3) {
|
|
73527
74029
|
const windowsPaths = [
|
|
73528
|
-
|
|
73529
|
-
|
|
73530
|
-
|
|
74030
|
+
join30(home, "AppData", "Roaming", "npm", "claude.cmd"),
|
|
74031
|
+
join30(home, ".npm-global", "claude.cmd"),
|
|
74032
|
+
join30(home, "node_modules", ".bin", "claude.cmd")
|
|
73531
74033
|
];
|
|
73532
74034
|
for (const path2 of windowsPaths) {
|
|
73533
74035
|
if (existsSync24(path2)) {
|
|
@@ -73538,11 +74040,11 @@ async function findClaudeBinary() {
|
|
|
73538
74040
|
const commonPaths = [
|
|
73539
74041
|
"/usr/local/bin/claude",
|
|
73540
74042
|
"/opt/homebrew/bin/claude",
|
|
73541
|
-
|
|
73542
|
-
|
|
73543
|
-
|
|
74043
|
+
join30(home, ".npm-global/bin/claude"),
|
|
74044
|
+
join30(home, ".local/bin/claude"),
|
|
74045
|
+
join30(home, "node_modules/.bin/claude"),
|
|
73544
74046
|
"/data/data/com.termux/files/usr/bin/claude",
|
|
73545
|
-
|
|
74047
|
+
join30(home, "../usr/bin/claude")
|
|
73546
74048
|
];
|
|
73547
74049
|
for (const path2 of commonPaths) {
|
|
73548
74050
|
if (existsSync24(path2)) {
|
|
@@ -73603,17 +74105,17 @@ __export(exports_diag_output, {
|
|
|
73603
74105
|
LogFileDiagOutput: () => LogFileDiagOutput
|
|
73604
74106
|
});
|
|
73605
74107
|
import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync17, unlinkSync as unlinkSync10, writeFileSync as writeFileSync19 } from "fs";
|
|
73606
|
-
import { homedir as
|
|
73607
|
-
import { join as
|
|
74108
|
+
import { homedir as homedir29 } from "os";
|
|
74109
|
+
import { join as join31 } from "path";
|
|
73608
74110
|
function getClaudishDir() {
|
|
73609
|
-
const dir =
|
|
74111
|
+
const dir = join31(homedir29(), ".claudish");
|
|
73610
74112
|
try {
|
|
73611
74113
|
mkdirSync17(dir, { recursive: true });
|
|
73612
74114
|
} catch {}
|
|
73613
74115
|
return dir;
|
|
73614
74116
|
}
|
|
73615
74117
|
function getDiagLogPath() {
|
|
73616
|
-
return
|
|
74118
|
+
return join31(getClaudishDir(), `diag-${process.pid}.log`);
|
|
73617
74119
|
}
|
|
73618
74120
|
|
|
73619
74121
|
class LogFileDiagOutput {
|
|
@@ -73824,9 +74326,9 @@ __export(exports_team_grid, {
|
|
|
73824
74326
|
});
|
|
73825
74327
|
import { spawn as spawn5 } from "child_process";
|
|
73826
74328
|
import { execSync as execSync2 } from "child_process";
|
|
73827
|
-
import { existsSync as existsSync25, readFileSync as
|
|
74329
|
+
import { existsSync as existsSync25, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
|
|
73828
74330
|
import { connect as netConnect } from "net";
|
|
73829
|
-
import { dirname as
|
|
74331
|
+
import { dirname as dirname11, join as join32 } from "path";
|
|
73830
74332
|
import { setTimeout as wait } from "timers/promises";
|
|
73831
74333
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
73832
74334
|
function resolveRouteInfo(modelId) {
|
|
@@ -73919,21 +74421,21 @@ function buildPaneHeader(model, prompt, bg) {
|
|
|
73919
74421
|
}
|
|
73920
74422
|
function findMagmuxBinary() {
|
|
73921
74423
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
73922
|
-
const thisDir =
|
|
73923
|
-
const pkgRoot =
|
|
74424
|
+
const thisDir = dirname11(thisFile);
|
|
74425
|
+
const pkgRoot = join32(thisDir, "..");
|
|
73924
74426
|
const platform3 = process.platform;
|
|
73925
74427
|
const arch = process.arch;
|
|
73926
|
-
const bundledMagmux =
|
|
74428
|
+
const bundledMagmux = join32(pkgRoot, "native", `magmux-${platform3}-${arch}`);
|
|
73927
74429
|
if (existsSync25(bundledMagmux))
|
|
73928
74430
|
return bundledMagmux;
|
|
73929
74431
|
try {
|
|
73930
74432
|
const pkgName = `@claudish/magmux-${platform3}-${arch}`;
|
|
73931
74433
|
let searchDir = pkgRoot;
|
|
73932
74434
|
for (let i = 0;i < 5; i++) {
|
|
73933
|
-
const candidate =
|
|
74435
|
+
const candidate = join32(searchDir, "node_modules", pkgName, "bin", "magmux");
|
|
73934
74436
|
if (existsSync25(candidate))
|
|
73935
74437
|
return candidate;
|
|
73936
|
-
const parent =
|
|
74438
|
+
const parent = dirname11(searchDir);
|
|
73937
74439
|
if (parent === searchDir)
|
|
73938
74440
|
break;
|
|
73939
74441
|
searchDir = parent;
|
|
@@ -74037,9 +74539,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
74037
74539
|
const keep = opts?.keep ?? false;
|
|
74038
74540
|
const manifest = setupSession(sessionPath, models, input);
|
|
74039
74541
|
const startedAt = new Date().toISOString();
|
|
74040
|
-
const gridfilePath =
|
|
74041
|
-
const prompt =
|
|
74042
|
-
const rawPrompt =
|
|
74542
|
+
const gridfilePath = join32(sessionPath, "gridfile.txt");
|
|
74543
|
+
const prompt = readFileSync25(join32(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
|
|
74544
|
+
const rawPrompt = readFileSync25(join32(sessionPath, "input.md"), "utf-8");
|
|
74043
74545
|
const usedBannerColors = new Set;
|
|
74044
74546
|
const gridLines = Object.entries(manifest.models).map(([anonId]) => {
|
|
74045
74547
|
const model = manifest.models[anonId].model;
|
|
@@ -74070,7 +74572,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
74070
74572
|
});
|
|
74071
74573
|
const [{ results }] = await Promise.all([subscription, procExit]);
|
|
74072
74574
|
const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
|
|
74073
|
-
const statusPath =
|
|
74575
|
+
const statusPath = join32(sessionPath, "status.json");
|
|
74074
74576
|
writeFileSync20(statusPath, JSON.stringify(status, null, 2), "utf-8");
|
|
74075
74577
|
return status;
|
|
74076
74578
|
}
|
|
@@ -74094,8 +74596,8 @@ var init_team_grid = __esm(() => {
|
|
|
74094
74596
|
init_op_source();
|
|
74095
74597
|
init_startup_trace();
|
|
74096
74598
|
var import_dotenv3 = __toESM(require_main(), 1);
|
|
74097
|
-
import { existsSync as existsSync26, readFileSync as
|
|
74098
|
-
import { join as
|
|
74599
|
+
import { existsSync as existsSync26, readFileSync as readFileSync26 } from "fs";
|
|
74600
|
+
import { join as join33, resolve as resolve4 } from "path";
|
|
74099
74601
|
import_dotenv3.config({ quiet: true });
|
|
74100
74602
|
function classifyStartupKind() {
|
|
74101
74603
|
const argv = process.argv.slice(2);
|
|
@@ -74228,6 +74730,7 @@ var isStatsCommand = firstPositional === "stats";
|
|
|
74228
74730
|
var isConfigCommand = firstPositional === "config";
|
|
74229
74731
|
var isServeCommand = firstPositional === "serve";
|
|
74230
74732
|
var isProvidersCommand = firstPositional === "providers";
|
|
74733
|
+
var isBehaviorCommand = firstPositional === "behavior";
|
|
74231
74734
|
var isLoginCommand = firstPositional === "login";
|
|
74232
74735
|
var isLogoutCommand = firstPositional === "logout";
|
|
74233
74736
|
var isQuotaCommand = firstPositional === "quota" || firstPositional === "usage";
|
|
@@ -74243,6 +74746,12 @@ if (isMcpMode) {
|
|
|
74243
74746
|
console.error(`[claudish serve] ${e instanceof Error ? e.message : String(e)}`);
|
|
74244
74747
|
process.exit(1);
|
|
74245
74748
|
}));
|
|
74749
|
+
} else if (isBehaviorCommand) {
|
|
74750
|
+
const behaviorArgIndex = args.indexOf("behavior");
|
|
74751
|
+
Promise.resolve().then(() => (init_behavior_command(), exports_behavior_command)).then((m) => m.behaviorCommand(args.slice(behaviorArgIndex + 1)).catch((e) => {
|
|
74752
|
+
console.error(`[claudish behavior] ${e instanceof Error ? e.message : String(e)}`);
|
|
74753
|
+
process.exit(1);
|
|
74754
|
+
}));
|
|
74246
74755
|
} else if (isProvidersCommand) {
|
|
74247
74756
|
const json2 = args.includes("--json");
|
|
74248
74757
|
Promise.resolve().then(() => (init_providers_command(), exports_providers_command)).then((m) => m.providersCommand({ json: json2 }).catch((e) => {
|
|
@@ -74329,14 +74838,14 @@ async function runCli() {
|
|
|
74329
74838
|
if (cliConfig.team && cliConfig.team.length > 0) {
|
|
74330
74839
|
let prompt = cliConfig.claudeArgs.join(" ");
|
|
74331
74840
|
if (cliConfig.inputFile) {
|
|
74332
|
-
prompt =
|
|
74841
|
+
prompt = readFileSync26(cliConfig.inputFile, "utf-8");
|
|
74333
74842
|
}
|
|
74334
74843
|
if (!prompt.trim()) {
|
|
74335
74844
|
console.error("Error: --team requires a prompt (positional args or -f <file>)");
|
|
74336
74845
|
process.exit(1);
|
|
74337
74846
|
}
|
|
74338
74847
|
const mode = cliConfig.teamMode ?? "default";
|
|
74339
|
-
const sessionPath =
|
|
74848
|
+
const sessionPath = join33(process.cwd(), `.claudish-team-${Date.now()}`);
|
|
74340
74849
|
if (mode === "json") {
|
|
74341
74850
|
const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
|
|
74342
74851
|
setupSession2(sessionPath, cliConfig.team, prompt);
|
|
@@ -74346,9 +74855,9 @@ async function runCli() {
|
|
|
74346
74855
|
});
|
|
74347
74856
|
const result = { ...status2, responses: {} };
|
|
74348
74857
|
for (const anonId of Object.keys(status2.models)) {
|
|
74349
|
-
const responsePath =
|
|
74858
|
+
const responsePath = join33(sessionPath, `response-${anonId}.md`);
|
|
74350
74859
|
try {
|
|
74351
|
-
const raw2 =
|
|
74860
|
+
const raw2 = readFileSync26(responsePath, "utf-8").trim();
|
|
74352
74861
|
try {
|
|
74353
74862
|
result.responses[anonId] = JSON.parse(raw2);
|
|
74354
74863
|
} catch {
|