@sma1lboy/kobe 0.7.22 → 0.7.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +291 -48
- package/dist/web-ui/assets/AppShell-C0hhV6qB.js +16 -0
- package/dist/web-ui/assets/AppShell-NZ5KYJKh.css +1 -0
- package/dist/web-ui/assets/{routes-BY2-JOW5.js → ChatTerminal-j3zmSA6m.js} +3 -3
- package/dist/web-ui/assets/ChatTerminal-kHJ-D0s7.css +1 -0
- package/dist/web-ui/assets/index-BPEy1cTR.css +2 -0
- package/dist/web-ui/assets/index-CMnpXQhx.js +10 -0
- package/dist/web-ui/assets/jsx-runtime-bzQ4Vb5N.js +1 -0
- package/dist/web-ui/assets/overview-Gj7Z3GGU.js +1 -0
- package/dist/web-ui/assets/routes-BQZWyGJi.js +1 -0
- package/dist/web-ui/assets/task._taskId-CF3ph7W5.js +1 -0
- package/dist/web-ui/assets/triage-DT7sWoTl.js +1 -0
- package/dist/web-ui/index.html +3 -2
- package/dist/web-ui/pty-scrollback.mjs +51 -0
- package/dist/web-ui/pty-server.mjs +16 -3
- package/package.json +1 -1
- package/dist/web-ui/assets/index-B_AO4Tl6.js +0 -10
- package/dist/web-ui/assets/index-ClDlEZ7A.css +0 -2
- package/dist/web-ui/assets/routes-O3B6rKf2.css +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -90,7 +90,7 @@ var init_package = __esm(() => {
|
|
|
90
90
|
package_default = {
|
|
91
91
|
$schema: "https://json.schemastore.org/package.json",
|
|
92
92
|
name: "@sma1lboy/kobe",
|
|
93
|
-
version: "0.7.
|
|
93
|
+
version: "0.7.24",
|
|
94
94
|
description: "TUI orchestrator for Claude Code (codename)",
|
|
95
95
|
type: "module",
|
|
96
96
|
packageManager: "bun@1.3.13",
|
|
@@ -13256,6 +13256,62 @@ async function handleDiffRequest(req, url) {
|
|
|
13256
13256
|
}
|
|
13257
13257
|
var GIT_TIMEOUT_MS = 15000, UNTRACKED_DIFF_CONCURRENCY = 8;
|
|
13258
13258
|
|
|
13259
|
+
// src/web/history.ts
|
|
13260
|
+
import { isAbsolute } from "path";
|
|
13261
|
+
function isSafeVendor(value) {
|
|
13262
|
+
return typeof value === "string" && value.length > 0 && /^[A-Za-z0-9_-]+$/.test(value);
|
|
13263
|
+
}
|
|
13264
|
+
function isSafeSessionId(value) {
|
|
13265
|
+
return typeof value === "string" && value.length > 0 && /^[A-Za-z0-9._-]+$/.test(value) && !value.includes("..");
|
|
13266
|
+
}
|
|
13267
|
+
async function handleSessions(url) {
|
|
13268
|
+
const worktreePath = url.searchParams.get("worktreePath");
|
|
13269
|
+
const vendor = url.searchParams.get("vendor") ?? "claude";
|
|
13270
|
+
if (!worktreePath || !isAbsolute(worktreePath)) {
|
|
13271
|
+
return Response.json({ error: "worktreePath must be an absolute path" }, { status: 400 });
|
|
13272
|
+
}
|
|
13273
|
+
if (!isSafeVendor(vendor)) {
|
|
13274
|
+
return Response.json({ error: "invalid vendor" }, { status: 400 });
|
|
13275
|
+
}
|
|
13276
|
+
try {
|
|
13277
|
+
const reader = engineEntry(vendor).history;
|
|
13278
|
+
const [sessions, latestMtime] = await Promise.all([
|
|
13279
|
+
reader.listSessionIdsForWorktree(worktreePath),
|
|
13280
|
+
reader.latestTranscriptMtimeForWorktree(worktreePath)
|
|
13281
|
+
]);
|
|
13282
|
+
return Response.json({ sessions, latestMtime });
|
|
13283
|
+
} catch (err) {
|
|
13284
|
+
return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 500 });
|
|
13285
|
+
}
|
|
13286
|
+
}
|
|
13287
|
+
async function handleMessages(url) {
|
|
13288
|
+
const vendor = url.searchParams.get("vendor") ?? "claude";
|
|
13289
|
+
const sessionId = url.searchParams.get("sessionId");
|
|
13290
|
+
if (!isSafeVendor(vendor)) {
|
|
13291
|
+
return Response.json({ error: "invalid vendor" }, { status: 400 });
|
|
13292
|
+
}
|
|
13293
|
+
if (!isSafeSessionId(sessionId)) {
|
|
13294
|
+
return Response.json({ error: "invalid sessionId" }, { status: 400 });
|
|
13295
|
+
}
|
|
13296
|
+
try {
|
|
13297
|
+
const messages = await engineEntry(vendor).history.readHistory(sessionId);
|
|
13298
|
+
return Response.json({ messages });
|
|
13299
|
+
} catch (err) {
|
|
13300
|
+
return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 500 });
|
|
13301
|
+
}
|
|
13302
|
+
}
|
|
13303
|
+
async function handleHistoryRequest(req, url) {
|
|
13304
|
+
if (url.pathname !== SESSIONS_ROUTE && url.pathname !== MESSAGES_ROUTE)
|
|
13305
|
+
return null;
|
|
13306
|
+
if (req.method !== "GET")
|
|
13307
|
+
return Response.json({ error: "method not allowed" }, { status: 405 });
|
|
13308
|
+
return url.pathname === SESSIONS_ROUTE ? handleSessions(url) : handleMessages(url);
|
|
13309
|
+
}
|
|
13310
|
+
var SESSIONS_ROUTE = "/api/history/sessions", MESSAGES_ROUTE = "/api/history/messages";
|
|
13311
|
+
var init_history4 = __esm(() => {
|
|
13312
|
+
init_registry();
|
|
13313
|
+
});
|
|
13314
|
+
|
|
13259
13315
|
// src/web/notes.ts
|
|
13260
13316
|
import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
|
|
13261
13317
|
import { join as join11 } from "path";
|
|
@@ -13321,6 +13377,89 @@ var init_notes = __esm(() => {
|
|
|
13321
13377
|
init_env();
|
|
13322
13378
|
});
|
|
13323
13379
|
|
|
13380
|
+
// src/web/themes.ts
|
|
13381
|
+
function resolveHex(themeJson, value, chain = []) {
|
|
13382
|
+
if (value === undefined)
|
|
13383
|
+
return null;
|
|
13384
|
+
if (typeof value !== "string")
|
|
13385
|
+
return resolveHex(themeJson, value.dark, chain);
|
|
13386
|
+
if (value === "transparent" || value === "none")
|
|
13387
|
+
return null;
|
|
13388
|
+
if (value.startsWith("#"))
|
|
13389
|
+
return value;
|
|
13390
|
+
if (chain.includes(value))
|
|
13391
|
+
return null;
|
|
13392
|
+
const next = themeJson.defs?.[value] ?? themeJson.theme[value];
|
|
13393
|
+
return resolveHex(themeJson, next, [...chain, value]);
|
|
13394
|
+
}
|
|
13395
|
+
function clampByte(n) {
|
|
13396
|
+
return Math.max(0, Math.min(255, Math.round(n)));
|
|
13397
|
+
}
|
|
13398
|
+
function mix(a, b, t) {
|
|
13399
|
+
const pa = Number.parseInt(a.slice(1), 16);
|
|
13400
|
+
const pb = Number.parseInt(b.slice(1), 16);
|
|
13401
|
+
const ch = (p, shift) => p >> shift & 255;
|
|
13402
|
+
const out = clampByte(ch(pa, 16) + (ch(pb, 16) - ch(pa, 16)) * t) << 16 | clampByte(ch(pa, 8) + (ch(pb, 8) - ch(pa, 8)) * t) << 8 | clampByte(ch(pa, 0) + (ch(pb, 0) - ch(pa, 0)) * t);
|
|
13403
|
+
return `#${out.toString(16).padStart(6, "0")}`;
|
|
13404
|
+
}
|
|
13405
|
+
function toWebPalette(themeJson) {
|
|
13406
|
+
const slot = (name) => resolveHex(themeJson, themeJson.theme[name]);
|
|
13407
|
+
const bg = slot("background");
|
|
13408
|
+
const fg = slot("text");
|
|
13409
|
+
if (!bg || !fg)
|
|
13410
|
+
return null;
|
|
13411
|
+
const muted = slot("textMuted") ?? mix(fg, bg, 0.35);
|
|
13412
|
+
const primary = slot("primary") ?? fg;
|
|
13413
|
+
const line = slot("border") ?? mix(fg, bg, 0.8);
|
|
13414
|
+
return {
|
|
13415
|
+
bg,
|
|
13416
|
+
surface: slot("backgroundPanel") ?? bg,
|
|
13417
|
+
inset: slot("backgroundElement") ?? bg,
|
|
13418
|
+
menu: slot("backgroundMenu") ?? slot("backgroundElement") ?? bg,
|
|
13419
|
+
line,
|
|
13420
|
+
"line-subtle": slot("borderSubtle") ?? line,
|
|
13421
|
+
"line-active": slot("borderActive") ?? mix(line, fg, 0.3),
|
|
13422
|
+
fg,
|
|
13423
|
+
muted,
|
|
13424
|
+
subtle: mix(muted, bg, 0.35),
|
|
13425
|
+
primary,
|
|
13426
|
+
"primary-hover": mix(primary, fg, 0.35),
|
|
13427
|
+
"kobe-orange": primary,
|
|
13428
|
+
"kobe-green": slot("success") ?? fg,
|
|
13429
|
+
"kobe-blue": slot("info") ?? fg,
|
|
13430
|
+
"kobe-red": slot("error") ?? fg,
|
|
13431
|
+
"kobe-yellow": slot("warning") ?? fg,
|
|
13432
|
+
"kobe-violet": slot("secondary") ?? primary
|
|
13433
|
+
};
|
|
13434
|
+
}
|
|
13435
|
+
function handleThemesRequest(req, url) {
|
|
13436
|
+
if (url.pathname !== THEMES_ROUTE)
|
|
13437
|
+
return null;
|
|
13438
|
+
if (req.method !== "GET")
|
|
13439
|
+
return Response.json({ error: "method not allowed" }, { status: 405 });
|
|
13440
|
+
return Response.json({ themes: WEB_THEMES });
|
|
13441
|
+
}
|
|
13442
|
+
var THEME_JSONS, WEB_THEMES, THEMES_ROUTE = "/api/themes";
|
|
13443
|
+
var init_themes = __esm(() => {
|
|
13444
|
+
init_claude();
|
|
13445
|
+
init_conductor();
|
|
13446
|
+
init_dracula();
|
|
13447
|
+
init_nord();
|
|
13448
|
+
init_opencode();
|
|
13449
|
+
init_osaka_jade();
|
|
13450
|
+
init_tokyonight();
|
|
13451
|
+
THEME_JSONS = {
|
|
13452
|
+
claude: claude_default,
|
|
13453
|
+
conductor: conductor_default,
|
|
13454
|
+
dracula: dracula_default,
|
|
13455
|
+
nord: nord_default,
|
|
13456
|
+
opencode: opencode_default,
|
|
13457
|
+
"osaka-jade": osaka_jade_default,
|
|
13458
|
+
tokyonight: tokyonight_default
|
|
13459
|
+
};
|
|
13460
|
+
WEB_THEMES = Object.fromEntries(Object.entries(THEME_JSONS).map(([name, json]) => [name, toWebPalette(json)]).filter((entry) => entry[1] !== null));
|
|
13461
|
+
});
|
|
13462
|
+
|
|
13324
13463
|
// ../kobe-web/server/spa-channels.ts
|
|
13325
13464
|
var SPA_CHANNELS, SPA_CHANNEL_SET;
|
|
13326
13465
|
var init_spa_channels = __esm(() => {
|
|
@@ -13328,7 +13467,10 @@ var init_spa_channels = __esm(() => {
|
|
|
13328
13467
|
"task.snapshot",
|
|
13329
13468
|
"active-task",
|
|
13330
13469
|
"engine-state",
|
|
13331
|
-
"update"
|
|
13470
|
+
"update",
|
|
13471
|
+
"task.jobs",
|
|
13472
|
+
"worktree.changes",
|
|
13473
|
+
"ui-prefs"
|
|
13332
13474
|
];
|
|
13333
13475
|
SPA_CHANNEL_SET = new Set(SPA_CHANNELS);
|
|
13334
13476
|
});
|
|
@@ -13349,6 +13491,9 @@ class DaemonLink {
|
|
|
13349
13491
|
activeTaskId = null;
|
|
13350
13492
|
engineStates = {};
|
|
13351
13493
|
update = null;
|
|
13494
|
+
jobs = {};
|
|
13495
|
+
worktreeChanges = {};
|
|
13496
|
+
uiPrefs = null;
|
|
13352
13497
|
async start() {
|
|
13353
13498
|
await this.connectOnce(true);
|
|
13354
13499
|
}
|
|
@@ -13358,6 +13503,9 @@ class DaemonLink {
|
|
|
13358
13503
|
activeTaskId: this.activeTaskId,
|
|
13359
13504
|
engineStates: this.engineStates,
|
|
13360
13505
|
update: this.update,
|
|
13506
|
+
jobs: this.jobs,
|
|
13507
|
+
worktreeChanges: this.worktreeChanges,
|
|
13508
|
+
uiPrefs: this.uiPrefs,
|
|
13361
13509
|
connected: this.connected
|
|
13362
13510
|
};
|
|
13363
13511
|
}
|
|
@@ -13399,6 +13547,7 @@ class DaemonLink {
|
|
|
13399
13547
|
if (hello.tasks)
|
|
13400
13548
|
this.tasks = hello.tasks;
|
|
13401
13549
|
this.engineStates = {};
|
|
13550
|
+
this.jobs = {};
|
|
13402
13551
|
client.on("*", (frame) => this.onFrame(frame.name, frame.payload));
|
|
13403
13552
|
client.onLifecycle("close", () => this.onDrop(client));
|
|
13404
13553
|
await client.subscribe({ role: "gui", channels: SPA_CHANNELS });
|
|
@@ -13432,9 +13581,16 @@ class DaemonLink {
|
|
|
13432
13581
|
}
|
|
13433
13582
|
onFrame(name, payload) {
|
|
13434
13583
|
switch (name) {
|
|
13435
|
-
case "task.snapshot":
|
|
13436
|
-
|
|
13584
|
+
case "task.snapshot": {
|
|
13585
|
+
const tasks = payload.tasks;
|
|
13586
|
+
this.tasks = tasks;
|
|
13587
|
+
const live = new Set(tasks.map((t) => t.id));
|
|
13588
|
+
const kept = Object.entries(this.engineStates).filter(([id]) => live.has(id));
|
|
13589
|
+
if (kept.length !== Object.keys(this.engineStates).length) {
|
|
13590
|
+
this.engineStates = Object.fromEntries(kept);
|
|
13591
|
+
}
|
|
13437
13592
|
break;
|
|
13593
|
+
}
|
|
13438
13594
|
case "active-task":
|
|
13439
13595
|
this.activeTaskId = payload.taskId;
|
|
13440
13596
|
break;
|
|
@@ -13446,6 +13602,22 @@ class DaemonLink {
|
|
|
13446
13602
|
case "update":
|
|
13447
13603
|
this.update = payload.info;
|
|
13448
13604
|
break;
|
|
13605
|
+
case "task.jobs": {
|
|
13606
|
+
const job = payload;
|
|
13607
|
+
if (job.phase === "running") {
|
|
13608
|
+
this.jobs = { ...this.jobs, [job.taskId]: job };
|
|
13609
|
+
} else {
|
|
13610
|
+
const { [job.taskId]: _done, ...rest } = this.jobs;
|
|
13611
|
+
this.jobs = rest;
|
|
13612
|
+
}
|
|
13613
|
+
break;
|
|
13614
|
+
}
|
|
13615
|
+
case "worktree.changes":
|
|
13616
|
+
this.worktreeChanges = payload.changes;
|
|
13617
|
+
break;
|
|
13618
|
+
case "ui-prefs":
|
|
13619
|
+
this.uiPrefs = payload;
|
|
13620
|
+
break;
|
|
13449
13621
|
case "daemon.stopping":
|
|
13450
13622
|
return;
|
|
13451
13623
|
default:
|
|
@@ -13474,6 +13646,31 @@ var init_daemon_link = __esm(() => {
|
|
|
13474
13646
|
init_spa_channels();
|
|
13475
13647
|
});
|
|
13476
13648
|
|
|
13649
|
+
// ../kobe-web/server/rpc-allowlist.ts
|
|
13650
|
+
var WEB_RPC_ALLOWLIST, WEB_RPC_ALLOWSET;
|
|
13651
|
+
var init_rpc_allowlist = __esm(() => {
|
|
13652
|
+
WEB_RPC_ALLOWLIST = [
|
|
13653
|
+
"daemon.status",
|
|
13654
|
+
"task.list",
|
|
13655
|
+
"task.get",
|
|
13656
|
+
"task.create",
|
|
13657
|
+
"task.archive",
|
|
13658
|
+
"task.rename",
|
|
13659
|
+
"task.setBranch",
|
|
13660
|
+
"task.setVendor",
|
|
13661
|
+
"task.delete",
|
|
13662
|
+
"task.pin",
|
|
13663
|
+
"task.move",
|
|
13664
|
+
"task.status",
|
|
13665
|
+
"task.ensureMain",
|
|
13666
|
+
"task.ensureWorktree",
|
|
13667
|
+
"task.setActive",
|
|
13668
|
+
"worktree.discoverAdoptable",
|
|
13669
|
+
"worktree.adopt"
|
|
13670
|
+
];
|
|
13671
|
+
WEB_RPC_ALLOWSET = new Set(WEB_RPC_ALLOWLIST);
|
|
13672
|
+
});
|
|
13673
|
+
|
|
13477
13674
|
// ../kobe-web/server/session.ts
|
|
13478
13675
|
async function getTask2(link, taskId) {
|
|
13479
13676
|
const { task } = await link.request("task.get", { taskId });
|
|
@@ -13524,9 +13721,15 @@ async function terminalSpec(link, taskId) {
|
|
|
13524
13721
|
const shell = process.env.SHELL?.trim() || "/bin/zsh";
|
|
13525
13722
|
return { cwd: worktreePath, command: [shell, "-il"] };
|
|
13526
13723
|
}
|
|
13724
|
+
async function tearDownTaskSession(taskId) {
|
|
13725
|
+
const session = tmuxSessionName(taskId);
|
|
13726
|
+
await switchClientBeforeKill(session).catch(() => {});
|
|
13727
|
+
await killSession(session).catch(() => {});
|
|
13728
|
+
}
|
|
13527
13729
|
var init_session = __esm(() => {
|
|
13528
13730
|
init_interactive_command();
|
|
13529
13731
|
init_repo_init();
|
|
13732
|
+
init_client2();
|
|
13530
13733
|
init_tmux();
|
|
13531
13734
|
});
|
|
13532
13735
|
|
|
@@ -13570,20 +13773,35 @@ data: ${JSON.stringify(data)}
|
|
|
13570
13773
|
}
|
|
13571
13774
|
});
|
|
13572
13775
|
}
|
|
13573
|
-
async function rpcResponse(req, link) {
|
|
13776
|
+
async function rpcResponse(req, link, tearDown) {
|
|
13574
13777
|
try {
|
|
13575
13778
|
const { name, payload } = await req.json();
|
|
13576
13779
|
if (!name)
|
|
13577
13780
|
return Response.json({ error: "missing rpc name" }, { status: 400 });
|
|
13578
|
-
if (name
|
|
13579
|
-
|
|
13781
|
+
if (!WEB_RPC_ALLOWSET.has(name)) {
|
|
13782
|
+
return Response.json({ error: `rpc ${name} is not exposed to the web UI` }, { status: 403 });
|
|
13580
13783
|
}
|
|
13581
13784
|
const result = await link.request(name, payload);
|
|
13785
|
+
const taskId = payload?.taskId;
|
|
13786
|
+
if (typeof taskId === "string") {
|
|
13787
|
+
const archiving = name === "task.archive" && payload.archived !== false;
|
|
13788
|
+
if (name === "task.delete" || archiving)
|
|
13789
|
+
tearDown(taskId);
|
|
13790
|
+
}
|
|
13582
13791
|
return Response.json({ result });
|
|
13583
13792
|
} catch (err) {
|
|
13584
13793
|
return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 500 });
|
|
13585
13794
|
}
|
|
13586
13795
|
}
|
|
13796
|
+
async function enginesResponse() {
|
|
13797
|
+
try {
|
|
13798
|
+
const ids = await availableEngineIds();
|
|
13799
|
+
const engines = ids.map((id) => ({ id, label: engineDisplayName(id) }));
|
|
13800
|
+
return Response.json({ engines: engines.length > 0 ? engines : [{ id: "claude", label: "Claude" }] });
|
|
13801
|
+
} catch (err) {
|
|
13802
|
+
return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 500 });
|
|
13803
|
+
}
|
|
13804
|
+
}
|
|
13587
13805
|
async function sessionResponse(req, link) {
|
|
13588
13806
|
try {
|
|
13589
13807
|
const { taskId } = await req.json();
|
|
@@ -13604,6 +13822,49 @@ async function specResponse(url, link, spec) {
|
|
|
13604
13822
|
return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 500 });
|
|
13605
13823
|
}
|
|
13606
13824
|
}
|
|
13825
|
+
function createRequestHandler(deps) {
|
|
13826
|
+
const { link, sseSends, staticDir } = deps;
|
|
13827
|
+
const tearDown = deps.tearDownSession ?? ((taskId) => void tearDownTaskSession(taskId));
|
|
13828
|
+
return async function handle(req) {
|
|
13829
|
+
const url = new URL(req.url);
|
|
13830
|
+
if (url.pathname === WEB_HEALTH_PATH)
|
|
13831
|
+
return new Response(WEB_HEALTH_MARKER);
|
|
13832
|
+
if (url.pathname === "/events") {
|
|
13833
|
+
return sseResponse((send2) => {
|
|
13834
|
+
send2("snapshot", link.snapshot());
|
|
13835
|
+
sseSends.add(send2);
|
|
13836
|
+
return () => {
|
|
13837
|
+
sseSends.delete(send2);
|
|
13838
|
+
};
|
|
13839
|
+
});
|
|
13840
|
+
}
|
|
13841
|
+
if (url.pathname === "/api/rpc" && req.method === "POST")
|
|
13842
|
+
return rpcResponse(req, link, tearDown);
|
|
13843
|
+
if (url.pathname === "/api/session" && req.method === "POST")
|
|
13844
|
+
return sessionResponse(req, link);
|
|
13845
|
+
if (url.pathname === "/api/engine-spec" && req.method === "GET")
|
|
13846
|
+
return specResponse(url, link, engineSpec);
|
|
13847
|
+
if (url.pathname === "/api/terminal-spec" && req.method === "GET")
|
|
13848
|
+
return specResponse(url, link, terminalSpec);
|
|
13849
|
+
if (url.pathname === "/api/engines" && req.method === "GET")
|
|
13850
|
+
return enginesResponse();
|
|
13851
|
+
const notes = await handleNotesRequest(req, url);
|
|
13852
|
+
if (notes)
|
|
13853
|
+
return notes;
|
|
13854
|
+
const diff = await handleDiffRequest(req, url);
|
|
13855
|
+
if (diff)
|
|
13856
|
+
return diff;
|
|
13857
|
+
const history = await handleHistoryRequest(req, url);
|
|
13858
|
+
if (history)
|
|
13859
|
+
return history;
|
|
13860
|
+
const themes = handleThemesRequest(req, url);
|
|
13861
|
+
if (themes)
|
|
13862
|
+
return themes;
|
|
13863
|
+
if (staticDir)
|
|
13864
|
+
return staticResponse(url.pathname, staticDir);
|
|
13865
|
+
return new Response("not found", { status: 404 });
|
|
13866
|
+
};
|
|
13867
|
+
}
|
|
13607
13868
|
async function staticResponse(pathname, staticDir) {
|
|
13608
13869
|
const rel = pathname === "/" ? "/index.html" : pathname;
|
|
13609
13870
|
const resolved = normalize2(join12(staticDir, rel));
|
|
@@ -13670,41 +13931,9 @@ async function createBridgeServer(opts = {}) {
|
|
|
13670
13931
|
for (const send2 of sseSends)
|
|
13671
13932
|
send2("snapshot", link.snapshot());
|
|
13672
13933
|
});
|
|
13673
|
-
const
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
async fetch(req) {
|
|
13677
|
-
const url = new URL(req.url);
|
|
13678
|
-
if (url.pathname === WEB_HEALTH_PATH)
|
|
13679
|
-
return new Response(WEB_HEALTH_MARKER);
|
|
13680
|
-
if (url.pathname === "/events") {
|
|
13681
|
-
return sseResponse((send2) => {
|
|
13682
|
-
send2("snapshot", link.snapshot());
|
|
13683
|
-
sseSends.add(send2);
|
|
13684
|
-
return () => {
|
|
13685
|
-
sseSends.delete(send2);
|
|
13686
|
-
};
|
|
13687
|
-
});
|
|
13688
|
-
}
|
|
13689
|
-
if (url.pathname === "/api/rpc" && req.method === "POST")
|
|
13690
|
-
return rpcResponse(req, link);
|
|
13691
|
-
if (url.pathname === "/api/session" && req.method === "POST")
|
|
13692
|
-
return sessionResponse(req, link);
|
|
13693
|
-
if (url.pathname === "/api/engine-spec" && req.method === "GET")
|
|
13694
|
-
return specResponse(url, link, engineSpec);
|
|
13695
|
-
if (url.pathname === "/api/terminal-spec" && req.method === "GET")
|
|
13696
|
-
return specResponse(url, link, terminalSpec);
|
|
13697
|
-
const notes = await handleNotesRequest(req, url);
|
|
13698
|
-
if (notes)
|
|
13699
|
-
return notes;
|
|
13700
|
-
const diff = await handleDiffRequest(req, url);
|
|
13701
|
-
if (diff)
|
|
13702
|
-
return diff;
|
|
13703
|
-
if (staticDir)
|
|
13704
|
-
return staticResponse(url.pathname, staticDir);
|
|
13705
|
-
return new Response("not found", { status: 404 });
|
|
13706
|
-
}
|
|
13707
|
-
});
|
|
13934
|
+
const handle = createRequestHandler({ link, sseSends, staticDir });
|
|
13935
|
+
const hostname = process.env.KOBE_WEB_HOST?.trim() || "127.0.0.1";
|
|
13936
|
+
const server = Bun.serve({ port, hostname, idleTimeout: 0, fetch: handle });
|
|
13708
13937
|
return {
|
|
13709
13938
|
port: server.port ?? port,
|
|
13710
13939
|
close() {
|
|
@@ -13715,8 +13944,13 @@ async function createBridgeServer(opts = {}) {
|
|
|
13715
13944
|
}
|
|
13716
13945
|
var WEB_HEALTH_MARKER = "kobe-web", WEB_HEALTH_PATH = "/__kobe_web";
|
|
13717
13946
|
var init_bridge = __esm(() => {
|
|
13947
|
+
init_account_detect();
|
|
13948
|
+
init_interactive_command();
|
|
13949
|
+
init_history4();
|
|
13718
13950
|
init_notes();
|
|
13951
|
+
init_themes();
|
|
13719
13952
|
init_daemon_link();
|
|
13953
|
+
init_rpc_allowlist();
|
|
13720
13954
|
init_session();
|
|
13721
13955
|
});
|
|
13722
13956
|
|
|
@@ -13731,8 +13965,13 @@ __export(exports_web_cmd, {
|
|
|
13731
13965
|
runWebSubcommand: () => runWebSubcommand
|
|
13732
13966
|
});
|
|
13733
13967
|
import { existsSync as existsSync12 } from "fs";
|
|
13968
|
+
import { homedir as homedir17 } from "os";
|
|
13734
13969
|
import { resolve as resolve6 } from "path";
|
|
13735
13970
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
13971
|
+
function homeLabel() {
|
|
13972
|
+
const explicit = process.env.KOBE_HOME_DIR?.trim();
|
|
13973
|
+
return explicit ? `sandbox: ${explicit}` : `${homedir17()}/.kobe (production)`;
|
|
13974
|
+
}
|
|
13736
13975
|
function resolveStaticDir() {
|
|
13737
13976
|
const here = fileURLToPath3(import.meta.url);
|
|
13738
13977
|
const candidates = [
|
|
@@ -13850,10 +14089,14 @@ async function runWebSubcommand(args) {
|
|
|
13850
14089
|
};
|
|
13851
14090
|
if (bridgeOnly) {
|
|
13852
14091
|
process.stdout.write(`kobe web bridge listening on http://localhost:${bridge.port} (routes only)
|
|
14092
|
+
`);
|
|
14093
|
+
process.stdout.write(` home: ${homeLabel()}
|
|
13853
14094
|
`);
|
|
13854
14095
|
} else {
|
|
13855
14096
|
pty = await startPtyServer({ webPort: bridge.port, takeover });
|
|
13856
14097
|
process.stdout.write(`kobe web \u2192 http://localhost:${bridge.port}
|
|
14098
|
+
`);
|
|
14099
|
+
process.stdout.write(` home: ${homeLabel()}
|
|
13857
14100
|
`);
|
|
13858
14101
|
if (!pty) {
|
|
13859
14102
|
process.stderr.write(`kobe web: PTY server not found; terminal tabs will be unavailable
|
|
@@ -14007,7 +14250,7 @@ __export(exports_hook_cmd, {
|
|
|
14007
14250
|
parseWorktreeAddPath: () => parseWorktreeAddPath,
|
|
14008
14251
|
ensureGlobalKobeHooks: () => ensureGlobalKobeHooks
|
|
14009
14252
|
});
|
|
14010
|
-
import { homedir as
|
|
14253
|
+
import { homedir as homedir18 } from "os";
|
|
14011
14254
|
import { join as join13, resolve as resolve7 } from "path";
|
|
14012
14255
|
async function readTextWithTimeout(read, timeoutMs = STDIN_READ_TIMEOUT_MS) {
|
|
14013
14256
|
let raceTimer;
|
|
@@ -14139,7 +14382,7 @@ function activityHookAdapters() {
|
|
|
14139
14382
|
return ALL_VENDORS.map((v) => createEngineHookAdapter(v)).filter((a) => a.supportsHooks());
|
|
14140
14383
|
}
|
|
14141
14384
|
function globalSettingsPath() {
|
|
14142
|
-
return join13(
|
|
14385
|
+
return join13(homedir18(), ".claude", "settings.json");
|
|
14143
14386
|
}
|
|
14144
14387
|
function persistedSyncPath(stored) {
|
|
14145
14388
|
if (!stored || stored === "off")
|
|
@@ -19074,7 +19317,7 @@ var init_pulse = () => {};
|
|
|
19074
19317
|
// src/tui/lib/sound.ts
|
|
19075
19318
|
import { existsSync as existsSync14, mkdirSync as mkdirSync6 } from "fs";
|
|
19076
19319
|
import { tmpdir as tmpdir2 } from "os";
|
|
19077
|
-
import { basename as basename6, isAbsolute, join as join15, resolve as resolve8 } from "path";
|
|
19320
|
+
import { basename as basename6, isAbsolute as isAbsolute2, join as join15, resolve as resolve8 } from "path";
|
|
19078
19321
|
function args(player, file, volume) {
|
|
19079
19322
|
if (player === "ffplay")
|
|
19080
19323
|
return [player, "-autoexit", "-nodisp", "-af", `volume=${volume}`, file];
|
|
@@ -19132,7 +19375,7 @@ function pulse(volume = 0.4) {
|
|
|
19132
19375
|
var pulseAsset, DIR, PLAYERS, cachedPlayer, cachedPath;
|
|
19133
19376
|
var init_sound = __esm(() => {
|
|
19134
19377
|
init_pulse();
|
|
19135
|
-
pulseAsset =
|
|
19378
|
+
pulseAsset = isAbsolute2(pulse_default) ? pulse_default : resolve8(import.meta.dir, pulse_default);
|
|
19136
19379
|
DIR = join15(tmpdir2(), "kobe-sfx");
|
|
19137
19380
|
PLAYERS = [
|
|
19138
19381
|
"ffplay",
|
|
@@ -22586,9 +22829,9 @@ var init_task_actions = __esm(() => {
|
|
|
22586
22829
|
// src/tui/lib/worktree-opener.ts
|
|
22587
22830
|
import { spawn as spawn5 } from "child_process";
|
|
22588
22831
|
import { existsSync as existsSync15 } from "fs";
|
|
22589
|
-
import { basename as basename7, delimiter, isAbsolute as
|
|
22832
|
+
import { basename as basename7, delimiter, isAbsolute as isAbsolute3, join as join17 } from "path";
|
|
22590
22833
|
function executableOnPath(command, env, exists) {
|
|
22591
|
-
if (
|
|
22834
|
+
if (isAbsolute3(command))
|
|
22592
22835
|
return exists(command);
|
|
22593
22836
|
const pathEnv = env.PATH ?? "";
|
|
22594
22837
|
for (const dir of pathEnv.split(delimiter)) {
|