@sma1lboy/kobe 0.6.6 → 0.6.7
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 +1277 -498
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -64,7 +64,71 @@ var init_vendor = __esm(() => {
|
|
|
64
64
|
ALL_VENDORS = ["claude", "codex", "copilot"];
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
+
// package.json
|
|
68
|
+
var package_default;
|
|
69
|
+
var init_package = __esm(() => {
|
|
70
|
+
package_default = {
|
|
71
|
+
$schema: "https://json.schemastore.org/package.json",
|
|
72
|
+
name: "@sma1lboy/kobe",
|
|
73
|
+
version: "0.6.7",
|
|
74
|
+
description: "TUI orchestrator for Claude Code (codename)",
|
|
75
|
+
type: "module",
|
|
76
|
+
packageManager: "bun@1.3.13",
|
|
77
|
+
bin: {
|
|
78
|
+
kobe: "dist/cli/index.js"
|
|
79
|
+
},
|
|
80
|
+
files: ["dist", "README.md", "LICENSE"],
|
|
81
|
+
publishConfig: {
|
|
82
|
+
access: "public"
|
|
83
|
+
},
|
|
84
|
+
repository: {
|
|
85
|
+
type: "git",
|
|
86
|
+
url: "git+https://github.com/Sma1lboy/kobe.git"
|
|
87
|
+
},
|
|
88
|
+
homepage: "https://github.com/Sma1lboy/kobe#readme",
|
|
89
|
+
bugs: {
|
|
90
|
+
url: "https://github.com/Sma1lboy/kobe/issues"
|
|
91
|
+
},
|
|
92
|
+
engines: {
|
|
93
|
+
bun: ">=1.3.11"
|
|
94
|
+
},
|
|
95
|
+
scripts: {
|
|
96
|
+
dev: "env KOBE_DEV=1 bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
|
|
97
|
+
"dev:sandbox": "mkdir -p .dev-sandbox/home && env KOBE_DEV=1 KOBE_HOME_DIR=$PWD/.dev-sandbox/home KOBE_TMUX_SOCKET=kobe-sandbox bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
|
|
98
|
+
"dev:sandbox:reset": "env KOBE_TMUX_SOCKET=kobe-sandbox bun ./src/cli/index.ts kill-sessions",
|
|
99
|
+
build: "bun run scripts/build.ts",
|
|
100
|
+
compile: "bun run scripts/compile.ts",
|
|
101
|
+
typecheck: "tsc --noEmit",
|
|
102
|
+
test: "bun run test:fast && bun run test:socket",
|
|
103
|
+
"test:fast": "vitest run --passWithNoTests",
|
|
104
|
+
"test:socket": "KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=1 --passWithNoTests",
|
|
105
|
+
lint: "biome check .",
|
|
106
|
+
knip: "knip-bun",
|
|
107
|
+
postinstall: "bun run scripts/check-preview-deps.ts || true",
|
|
108
|
+
prepublishOnly: "bun run typecheck && bun run build"
|
|
109
|
+
},
|
|
110
|
+
"//": "biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",
|
|
111
|
+
dependencies: {
|
|
112
|
+
"@ansi-tools/parser": "^1.0.15",
|
|
113
|
+
"@opentui/core": "0.2.4",
|
|
114
|
+
"@opentui/solid": "0.2.4",
|
|
115
|
+
"solid-js": "1.9.12"
|
|
116
|
+
},
|
|
117
|
+
devDependencies: {
|
|
118
|
+
"@biomejs/biome": "1.9.4",
|
|
119
|
+
"@tsconfig/bun": "1.0.9",
|
|
120
|
+
"@types/bun": "1.3.12",
|
|
121
|
+
knip: "^6.14.2",
|
|
122
|
+
"node-pty": "^1.1.0",
|
|
123
|
+
typescript: "5.8.2",
|
|
124
|
+
vitest: "2.1.9"
|
|
125
|
+
},
|
|
126
|
+
trustedDependencies: []
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
|
|
67
130
|
// src/env.ts
|
|
131
|
+
import { createHash } from "crypto";
|
|
68
132
|
import { homedir } from "os";
|
|
69
133
|
import { join } from "path";
|
|
70
134
|
function isDev() {
|
|
@@ -79,17 +143,178 @@ function kobeStateDir() {
|
|
|
79
143
|
function kvStatePath() {
|
|
80
144
|
return join(homeDir(), ".config", "kobe", "state.json");
|
|
81
145
|
}
|
|
146
|
+
function worktreeInitMarkerPath(worktreePath) {
|
|
147
|
+
const hash = createHash("sha1").update(worktreePath).digest("hex").slice(0, 16);
|
|
148
|
+
return join(kobeStateDir(), "worktree-init", hash);
|
|
149
|
+
}
|
|
82
150
|
var init_env = () => {};
|
|
83
151
|
|
|
152
|
+
// src/version.ts
|
|
153
|
+
var exports_version = {};
|
|
154
|
+
__export(exports_version, {
|
|
155
|
+
repoSlug: () => repoSlug,
|
|
156
|
+
releasePageUrl: () => releasePageUrl,
|
|
157
|
+
recommendedGlobalInstallCommand: () => recommendedGlobalInstallCommand,
|
|
158
|
+
isNewerSemver: () => isNewerSemver,
|
|
159
|
+
fetchReleaseSummaries: () => fetchReleaseSummaries,
|
|
160
|
+
fetchReleaseNotes: () => fetchReleaseNotes,
|
|
161
|
+
checkLatestVersion: () => checkLatestVersion,
|
|
162
|
+
UPDATE_SCRIPT_URL: () => UPDATE_SCRIPT_URL,
|
|
163
|
+
UPDATE_COMMAND: () => UPDATE_COMMAND,
|
|
164
|
+
PACKAGE_NAME: () => PACKAGE_NAME,
|
|
165
|
+
CURRENT_VERSION: () => CURRENT_VERSION
|
|
166
|
+
});
|
|
167
|
+
function repoSlug() {
|
|
168
|
+
const url = package_default.repository?.url;
|
|
169
|
+
if (!url)
|
|
170
|
+
return null;
|
|
171
|
+
const m = url.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
|
|
172
|
+
if (!m || !m[1] || !m[2])
|
|
173
|
+
return null;
|
|
174
|
+
return `${m[1]}/${m[2]}`;
|
|
175
|
+
}
|
|
176
|
+
function recommendedGlobalInstallCommand() {
|
|
177
|
+
return `npm install -g ${PACKAGE_NAME}@latest`;
|
|
178
|
+
}
|
|
179
|
+
async function fetchLatestFromRegistry(packageName) {
|
|
180
|
+
const ctrl = new AbortController;
|
|
181
|
+
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
182
|
+
try {
|
|
183
|
+
const encoded = packageName.replace("/", "%2F");
|
|
184
|
+
const res = await fetch(`https://registry.npmjs.org/${encoded}/latest`, {
|
|
185
|
+
signal: ctrl.signal,
|
|
186
|
+
headers: { accept: "application/json" }
|
|
187
|
+
});
|
|
188
|
+
if (!res.ok)
|
|
189
|
+
return null;
|
|
190
|
+
const body = await res.json();
|
|
191
|
+
if (typeof body.version !== "string")
|
|
192
|
+
return null;
|
|
193
|
+
return body.version;
|
|
194
|
+
} catch {
|
|
195
|
+
return null;
|
|
196
|
+
} finally {
|
|
197
|
+
clearTimeout(timer);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function isNewerSemver(latest, current) {
|
|
201
|
+
const norm = (v) => v.split("-")[0] ?? v;
|
|
202
|
+
const a = norm(latest).split(".").map((s) => Number.parseInt(s, 10));
|
|
203
|
+
const b = norm(current).split(".").map((s) => Number.parseInt(s, 10));
|
|
204
|
+
for (let i = 0;i < 3; i++) {
|
|
205
|
+
const av = a[i] ?? 0;
|
|
206
|
+
const bv = b[i] ?? 0;
|
|
207
|
+
if (Number.isNaN(av) || Number.isNaN(bv))
|
|
208
|
+
return false;
|
|
209
|
+
if (av > bv)
|
|
210
|
+
return true;
|
|
211
|
+
if (av < bv)
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
async function checkLatestVersion(opts = {}) {
|
|
217
|
+
if (isDev() && !opts.force)
|
|
218
|
+
return null;
|
|
219
|
+
const latest = await fetchLatestFromRegistry(PACKAGE_NAME);
|
|
220
|
+
if (!latest)
|
|
221
|
+
return null;
|
|
222
|
+
return {
|
|
223
|
+
current: CURRENT_VERSION,
|
|
224
|
+
latest,
|
|
225
|
+
hasUpdate: isNewerSemver(latest, CURRENT_VERSION)
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function versionFromTagName(tagName) {
|
|
229
|
+
if (typeof tagName !== "string")
|
|
230
|
+
return null;
|
|
231
|
+
const match = tagName.match(/^v(\d+\.\d+\.\d+)$/);
|
|
232
|
+
return match?.[1] ?? null;
|
|
233
|
+
}
|
|
234
|
+
async function fetchReleaseNotes(version) {
|
|
235
|
+
const slug = repoSlug();
|
|
236
|
+
if (!slug)
|
|
237
|
+
return null;
|
|
238
|
+
const tag = `v${version}`;
|
|
239
|
+
const ctrl = new AbortController;
|
|
240
|
+
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
241
|
+
try {
|
|
242
|
+
const res = await fetch(`https://api.github.com/repos/${slug}/releases/tags/${tag}`, {
|
|
243
|
+
signal: ctrl.signal,
|
|
244
|
+
headers: {
|
|
245
|
+
accept: "application/vnd.github+json",
|
|
246
|
+
"x-github-api-version": "2022-11-28"
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
if (!res.ok)
|
|
250
|
+
return null;
|
|
251
|
+
const body = await res.json();
|
|
252
|
+
if (typeof body.body !== "string" || typeof body.html_url !== "string")
|
|
253
|
+
return null;
|
|
254
|
+
return { body: body.body, url: body.html_url, version };
|
|
255
|
+
} catch {
|
|
256
|
+
return null;
|
|
257
|
+
} finally {
|
|
258
|
+
clearTimeout(timer);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async function fetchReleaseSummaries(limit = 12) {
|
|
262
|
+
const slug = repoSlug();
|
|
263
|
+
if (!slug)
|
|
264
|
+
return [];
|
|
265
|
+
const ctrl = new AbortController;
|
|
266
|
+
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
267
|
+
try {
|
|
268
|
+
const res = await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`, {
|
|
269
|
+
signal: ctrl.signal,
|
|
270
|
+
headers: {
|
|
271
|
+
accept: "application/vnd.github+json",
|
|
272
|
+
"x-github-api-version": "2022-11-28"
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
if (!res.ok)
|
|
276
|
+
return [];
|
|
277
|
+
const body = await res.json();
|
|
278
|
+
if (!Array.isArray(body))
|
|
279
|
+
return [];
|
|
280
|
+
return body.map((release) => {
|
|
281
|
+
const version = versionFromTagName(release.tag_name);
|
|
282
|
+
if (!version || typeof release.html_url !== "string")
|
|
283
|
+
return null;
|
|
284
|
+
return { version, url: release.html_url };
|
|
285
|
+
}).filter((release) => release !== null);
|
|
286
|
+
} catch {
|
|
287
|
+
return [];
|
|
288
|
+
} finally {
|
|
289
|
+
clearTimeout(timer);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function releasePageUrl(version) {
|
|
293
|
+
const slug = repoSlug();
|
|
294
|
+
if (!slug)
|
|
295
|
+
return null;
|
|
296
|
+
return `https://github.com/${slug}/releases/tag/v${version}`;
|
|
297
|
+
}
|
|
298
|
+
var CURRENT_VERSION, PACKAGE_NAME, UPDATE_SCRIPT_URL = "https://raw.githubusercontent.com/Sma1lboy/kobe/main/scripts/update.sh", UPDATE_COMMAND, FETCH_TIMEOUT_MS = 3000;
|
|
299
|
+
var init_version = __esm(() => {
|
|
300
|
+
init_package();
|
|
301
|
+
init_env();
|
|
302
|
+
CURRENT_VERSION = package_default.version;
|
|
303
|
+
PACKAGE_NAME = package_default.name;
|
|
304
|
+
UPDATE_COMMAND = `curl -fsSL ${UPDATE_SCRIPT_URL} | sh`;
|
|
305
|
+
});
|
|
306
|
+
|
|
84
307
|
// src/state/repos.ts
|
|
85
308
|
var exports_repos = {};
|
|
86
309
|
__export(exports_repos, {
|
|
87
310
|
statePath: () => statePath,
|
|
311
|
+
setRepoInitOverride: () => setRepoInitOverride,
|
|
88
312
|
setPersistedString: () => setPersistedString,
|
|
89
313
|
resolveRepoRoot: () => resolveRepoRoot,
|
|
90
314
|
removeSavedRepo: () => removeSavedRepo,
|
|
91
315
|
normalizeSavedRepos: () => normalizeSavedRepos,
|
|
92
316
|
getSavedRepos: () => getSavedRepos,
|
|
317
|
+
getRepoInitOverride: () => getRepoInitOverride,
|
|
93
318
|
getPersistedString: () => getPersistedString,
|
|
94
319
|
addSavedRepo: () => addSavedRepo
|
|
95
320
|
});
|
|
@@ -182,6 +407,45 @@ function normalizeSavedRepos() {
|
|
|
182
407
|
state.savedRepos = next;
|
|
183
408
|
save(state);
|
|
184
409
|
}
|
|
410
|
+
function readRepoConfigs(state) {
|
|
411
|
+
const raw = state.repoConfigs;
|
|
412
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
413
|
+
return {};
|
|
414
|
+
return raw;
|
|
415
|
+
}
|
|
416
|
+
function coerceOverride(entry) {
|
|
417
|
+
if (!entry || typeof entry !== "object")
|
|
418
|
+
return {};
|
|
419
|
+
const e = entry;
|
|
420
|
+
return {
|
|
421
|
+
initScript: typeof e.initScript === "string" && e.initScript.length > 0 ? e.initScript : undefined,
|
|
422
|
+
initPrompt: typeof e.initPrompt === "string" && e.initPrompt.length > 0 ? e.initPrompt : undefined
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function getRepoInitOverride(repoRoot) {
|
|
426
|
+
return coerceOverride(readRepoConfigs(load())[resolveRepoRoot(repoRoot)]);
|
|
427
|
+
}
|
|
428
|
+
function setRepoInitOverride(repoRoot, patch) {
|
|
429
|
+
const normalized = resolveRepoRoot(repoRoot);
|
|
430
|
+
const state = load();
|
|
431
|
+
const configs = { ...readRepoConfigs(state) };
|
|
432
|
+
const cur = coerceOverride(configs[normalized]);
|
|
433
|
+
const nextScript = patch.initScript === undefined ? cur.initScript : patch.initScript || undefined;
|
|
434
|
+
const nextPrompt = patch.initPrompt === undefined ? cur.initPrompt : patch.initPrompt || undefined;
|
|
435
|
+
const next = {
|
|
436
|
+
...nextScript ? { initScript: nextScript } : {},
|
|
437
|
+
...nextPrompt ? { initPrompt: nextPrompt } : {}
|
|
438
|
+
};
|
|
439
|
+
if (!next.initScript && !next.initPrompt) {
|
|
440
|
+
const { [normalized]: _dropped, ...rest } = configs;
|
|
441
|
+
state.repoConfigs = rest;
|
|
442
|
+
} else {
|
|
443
|
+
configs[normalized] = next;
|
|
444
|
+
state.repoConfigs = configs;
|
|
445
|
+
}
|
|
446
|
+
save(state);
|
|
447
|
+
return next;
|
|
448
|
+
}
|
|
185
449
|
function removeSavedRepo(absPath) {
|
|
186
450
|
const state = load();
|
|
187
451
|
const cur = getSavedRepos();
|
|
@@ -272,7 +536,7 @@ class TaskIndexStore {
|
|
|
272
536
|
kobeDir;
|
|
273
537
|
path;
|
|
274
538
|
tmpPath;
|
|
275
|
-
cache = { version:
|
|
539
|
+
cache = { version: CURRENT_VERSION2, tasks: [] };
|
|
276
540
|
loaded = false;
|
|
277
541
|
listeners = new Set;
|
|
278
542
|
saveChain = Promise.resolve();
|
|
@@ -308,7 +572,7 @@ class TaskIndexStore {
|
|
|
308
572
|
} catch (err) {
|
|
309
573
|
const code = err.code;
|
|
310
574
|
if (code === "ENOENT") {
|
|
311
|
-
this.cache = { version:
|
|
575
|
+
this.cache = { version: CURRENT_VERSION2, tasks: [] };
|
|
312
576
|
this.loaded = true;
|
|
313
577
|
this.notifyListeners();
|
|
314
578
|
return this.snapshot();
|
|
@@ -320,7 +584,7 @@ class TaskIndexStore {
|
|
|
320
584
|
parsed = JSON.parse(raw);
|
|
321
585
|
} catch (err) {
|
|
322
586
|
console.warn(`[kobe] tasks.json at ${this.path} is corrupted (${err.message}); recovering with empty index. The stale file is left in place.`);
|
|
323
|
-
this.cache = { version:
|
|
587
|
+
this.cache = { version: CURRENT_VERSION2, tasks: [] };
|
|
324
588
|
this.loaded = true;
|
|
325
589
|
this.notifyListeners();
|
|
326
590
|
return this.snapshot();
|
|
@@ -420,7 +684,7 @@ class TaskIndexStore {
|
|
|
420
684
|
if (err.code !== "ENOENT")
|
|
421
685
|
throw err;
|
|
422
686
|
}
|
|
423
|
-
this.cache = { version:
|
|
687
|
+
this.cache = { version: CURRENT_VERSION2, tasks: [] };
|
|
424
688
|
this.loaded = false;
|
|
425
689
|
}
|
|
426
690
|
assertLoaded() {
|
|
@@ -430,7 +694,7 @@ class TaskIndexStore {
|
|
|
430
694
|
}
|
|
431
695
|
snapshot() {
|
|
432
696
|
return {
|
|
433
|
-
version:
|
|
697
|
+
version: CURRENT_VERSION2,
|
|
434
698
|
tasks: this.cache.tasks.slice()
|
|
435
699
|
};
|
|
436
700
|
}
|
|
@@ -450,13 +714,13 @@ class TaskIndexStore {
|
|
|
450
714
|
function normalizeIndex(parsed, source) {
|
|
451
715
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
452
716
|
console.warn(`[kobe] tasks.json at ${source} is not an object; recovering with empty index.`);
|
|
453
|
-
return { version:
|
|
717
|
+
return { version: CURRENT_VERSION2, tasks: [] };
|
|
454
718
|
}
|
|
455
719
|
const obj = parsed;
|
|
456
720
|
const version = obj.version;
|
|
457
721
|
if (version !== undefined && version !== 1 && version !== 2 && version !== 3) {
|
|
458
722
|
console.warn(`[kobe] tasks.json at ${source} has unsupported version=${String(version)}; recovering with empty index.`);
|
|
459
|
-
return { version:
|
|
723
|
+
return { version: CURRENT_VERSION2, tasks: [] };
|
|
460
724
|
}
|
|
461
725
|
const rawTasks = Array.isArray(obj.tasks) ? obj.tasks : [];
|
|
462
726
|
const tasks = [];
|
|
@@ -468,7 +732,7 @@ function normalizeIndex(parsed, source) {
|
|
|
468
732
|
console.warn(`[kobe] dropping malformed task entry from ${source}: ${JSON.stringify(entry)}`);
|
|
469
733
|
}
|
|
470
734
|
}
|
|
471
|
-
return { version:
|
|
735
|
+
return { version: CURRENT_VERSION2, tasks };
|
|
472
736
|
}
|
|
473
737
|
function coerceTask(value) {
|
|
474
738
|
if (!value || typeof value !== "object")
|
|
@@ -534,7 +798,7 @@ function isVendorId(v) {
|
|
|
534
798
|
function isTaskStatus(s) {
|
|
535
799
|
return s === "backlog" || s === "in_progress" || s === "in_review" || s === "done" || s === "canceled" || s === "error";
|
|
536
800
|
}
|
|
537
|
-
var
|
|
801
|
+
var CURRENT_VERSION2 = 3;
|
|
538
802
|
var init_store = __esm(() => {
|
|
539
803
|
init_ulid();
|
|
540
804
|
});
|
|
@@ -3047,286 +3311,68 @@ class KobeDaemonClient {
|
|
|
3047
3311
|
reject(err);
|
|
3048
3312
|
};
|
|
3049
3313
|
socket.once("connect", onConnect);
|
|
3050
|
-
socket.once("error", onError);
|
|
3051
|
-
socket.on("data", (chunk) => this.onData(chunk.toString("utf8")));
|
|
3052
|
-
socket.on("close", () => this.onSocketClose(socket));
|
|
3053
|
-
});
|
|
3054
|
-
}
|
|
3055
|
-
onSocketClose(which) {
|
|
3056
|
-
if (this.socket !== which)
|
|
3057
|
-
return;
|
|
3058
|
-
this.socket = null;
|
|
3059
|
-
for (const pending of this.pending.values())
|
|
3060
|
-
pending.reject(new Error("daemon connection closed"));
|
|
3061
|
-
this.pending.clear();
|
|
3062
|
-
this.emitLifecycle("close");
|
|
3063
|
-
}
|
|
3064
|
-
emitLifecycle(name) {
|
|
3065
|
-
for (const handler of this.lifecycleHandlers.get(name) ?? []) {
|
|
3066
|
-
try {
|
|
3067
|
-
handler();
|
|
3068
|
-
} catch (err) {
|
|
3069
|
-
console.error(`[kobe] lifecycle handler for "${name}" threw:`, err);
|
|
3070
|
-
}
|
|
3071
|
-
}
|
|
3072
|
-
}
|
|
3073
|
-
onData(chunk) {
|
|
3074
|
-
this.buffer += chunk;
|
|
3075
|
-
let nl = this.buffer.indexOf(`
|
|
3076
|
-
`);
|
|
3077
|
-
while (nl !== -1) {
|
|
3078
|
-
const line = this.buffer.slice(0, nl);
|
|
3079
|
-
this.buffer = this.buffer.slice(nl + 1);
|
|
3080
|
-
if (line.trim().length > 0)
|
|
3081
|
-
this.onLine(line);
|
|
3082
|
-
nl = this.buffer.indexOf(`
|
|
3083
|
-
`);
|
|
3084
|
-
}
|
|
3085
|
-
}
|
|
3086
|
-
onLine(line) {
|
|
3087
|
-
const frame = JSON.parse(line);
|
|
3088
|
-
if (frame.type === "event") {
|
|
3089
|
-
this.emit(frame);
|
|
3090
|
-
return;
|
|
3091
|
-
}
|
|
3092
|
-
if (frame.type !== "response")
|
|
3093
|
-
return;
|
|
3094
|
-
const pending = this.pending.get(frame.id);
|
|
3095
|
-
if (!pending)
|
|
3096
|
-
return;
|
|
3097
|
-
this.pending.delete(frame.id);
|
|
3098
|
-
if (frame.error)
|
|
3099
|
-
pending.reject(new Error(frame.error.message));
|
|
3100
|
-
else
|
|
3101
|
-
pending.resolve(frame.payload);
|
|
3102
|
-
}
|
|
3103
|
-
emit(frame) {
|
|
3104
|
-
for (const handler of this.handlers.get(frame.name) ?? [])
|
|
3105
|
-
handler(frame);
|
|
3106
|
-
for (const handler of this.handlers.get("*") ?? [])
|
|
3107
|
-
handler(frame);
|
|
3108
|
-
}
|
|
3109
|
-
}
|
|
3110
|
-
var init_client = __esm(() => {
|
|
3111
|
-
init_protocol();
|
|
3112
|
-
});
|
|
3113
|
-
|
|
3114
|
-
// package.json
|
|
3115
|
-
var package_default;
|
|
3116
|
-
var init_package = __esm(() => {
|
|
3117
|
-
package_default = {
|
|
3118
|
-
$schema: "https://json.schemastore.org/package.json",
|
|
3119
|
-
name: "@sma1lboy/kobe",
|
|
3120
|
-
version: "0.6.6",
|
|
3121
|
-
description: "TUI orchestrator for Claude Code (codename)",
|
|
3122
|
-
type: "module",
|
|
3123
|
-
packageManager: "bun@1.3.13",
|
|
3124
|
-
bin: {
|
|
3125
|
-
kobe: "dist/cli/index.js"
|
|
3126
|
-
},
|
|
3127
|
-
files: ["dist", "README.md", "LICENSE"],
|
|
3128
|
-
publishConfig: {
|
|
3129
|
-
access: "public"
|
|
3130
|
-
},
|
|
3131
|
-
repository: {
|
|
3132
|
-
type: "git",
|
|
3133
|
-
url: "git+https://github.com/Sma1lboy/kobe.git"
|
|
3134
|
-
},
|
|
3135
|
-
homepage: "https://github.com/Sma1lboy/kobe#readme",
|
|
3136
|
-
bugs: {
|
|
3137
|
-
url: "https://github.com/Sma1lboy/kobe/issues"
|
|
3138
|
-
},
|
|
3139
|
-
engines: {
|
|
3140
|
-
bun: ">=1.3.11"
|
|
3141
|
-
},
|
|
3142
|
-
scripts: {
|
|
3143
|
-
dev: "env KOBE_DEV=1 bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
|
|
3144
|
-
"dev:sandbox": "mkdir -p .dev-sandbox/home && env KOBE_DEV=1 KOBE_HOME_DIR=$PWD/.dev-sandbox/home KOBE_TMUX_SOCKET=kobe-sandbox bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
|
|
3145
|
-
"dev:sandbox:reset": "env KOBE_TMUX_SOCKET=kobe-sandbox bun ./src/cli/index.ts kill-sessions",
|
|
3146
|
-
build: "bun run scripts/build.ts",
|
|
3147
|
-
compile: "bun run scripts/compile.ts",
|
|
3148
|
-
typecheck: "tsc --noEmit",
|
|
3149
|
-
test: "bun run test:fast && bun run test:socket",
|
|
3150
|
-
"test:fast": "vitest run --passWithNoTests",
|
|
3151
|
-
"test:socket": "KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=1 --passWithNoTests",
|
|
3152
|
-
lint: "biome check .",
|
|
3153
|
-
knip: "knip-bun",
|
|
3154
|
-
postinstall: "bun run scripts/check-preview-deps.ts || true",
|
|
3155
|
-
prepublishOnly: "bun run typecheck && bun run build"
|
|
3156
|
-
},
|
|
3157
|
-
"//": "biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",
|
|
3158
|
-
dependencies: {
|
|
3159
|
-
"@ansi-tools/parser": "^1.0.15",
|
|
3160
|
-
"@opentui/core": "0.2.4",
|
|
3161
|
-
"@opentui/solid": "0.2.4",
|
|
3162
|
-
"solid-js": "1.9.12"
|
|
3163
|
-
},
|
|
3164
|
-
devDependencies: {
|
|
3165
|
-
"@biomejs/biome": "1.9.4",
|
|
3166
|
-
"@tsconfig/bun": "1.0.9",
|
|
3167
|
-
"@types/bun": "1.3.12",
|
|
3168
|
-
knip: "^6.14.2",
|
|
3169
|
-
"node-pty": "^1.1.0",
|
|
3170
|
-
typescript: "5.8.2",
|
|
3171
|
-
vitest: "2.1.9"
|
|
3172
|
-
},
|
|
3173
|
-
trustedDependencies: []
|
|
3174
|
-
};
|
|
3175
|
-
});
|
|
3176
|
-
|
|
3177
|
-
// src/version.ts
|
|
3178
|
-
var exports_version = {};
|
|
3179
|
-
__export(exports_version, {
|
|
3180
|
-
repoSlug: () => repoSlug,
|
|
3181
|
-
releasePageUrl: () => releasePageUrl,
|
|
3182
|
-
recommendedGlobalInstallCommand: () => recommendedGlobalInstallCommand,
|
|
3183
|
-
isNewerSemver: () => isNewerSemver,
|
|
3184
|
-
fetchReleaseSummaries: () => fetchReleaseSummaries,
|
|
3185
|
-
fetchReleaseNotes: () => fetchReleaseNotes,
|
|
3186
|
-
checkLatestVersion: () => checkLatestVersion,
|
|
3187
|
-
UPDATE_SCRIPT_URL: () => UPDATE_SCRIPT_URL,
|
|
3188
|
-
UPDATE_COMMAND: () => UPDATE_COMMAND,
|
|
3189
|
-
PACKAGE_NAME: () => PACKAGE_NAME,
|
|
3190
|
-
CURRENT_VERSION: () => CURRENT_VERSION2
|
|
3191
|
-
});
|
|
3192
|
-
function repoSlug() {
|
|
3193
|
-
const url = package_default.repository?.url;
|
|
3194
|
-
if (!url)
|
|
3195
|
-
return null;
|
|
3196
|
-
const m = url.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
|
|
3197
|
-
if (!m || !m[1] || !m[2])
|
|
3198
|
-
return null;
|
|
3199
|
-
return `${m[1]}/${m[2]}`;
|
|
3200
|
-
}
|
|
3201
|
-
function recommendedGlobalInstallCommand() {
|
|
3202
|
-
return `npm install -g ${PACKAGE_NAME}@latest`;
|
|
3203
|
-
}
|
|
3204
|
-
async function fetchLatestFromRegistry(packageName) {
|
|
3205
|
-
const ctrl = new AbortController;
|
|
3206
|
-
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
3207
|
-
try {
|
|
3208
|
-
const encoded = packageName.replace("/", "%2F");
|
|
3209
|
-
const res = await fetch(`https://registry.npmjs.org/${encoded}/latest`, {
|
|
3210
|
-
signal: ctrl.signal,
|
|
3211
|
-
headers: { accept: "application/json" }
|
|
3212
|
-
});
|
|
3213
|
-
if (!res.ok)
|
|
3214
|
-
return null;
|
|
3215
|
-
const body = await res.json();
|
|
3216
|
-
if (typeof body.version !== "string")
|
|
3217
|
-
return null;
|
|
3218
|
-
return body.version;
|
|
3219
|
-
} catch {
|
|
3220
|
-
return null;
|
|
3221
|
-
} finally {
|
|
3222
|
-
clearTimeout(timer);
|
|
3223
|
-
}
|
|
3224
|
-
}
|
|
3225
|
-
function isNewerSemver(latest, current) {
|
|
3226
|
-
const norm = (v) => v.split("-")[0] ?? v;
|
|
3227
|
-
const a = norm(latest).split(".").map((s) => Number.parseInt(s, 10));
|
|
3228
|
-
const b = norm(current).split(".").map((s) => Number.parseInt(s, 10));
|
|
3229
|
-
for (let i = 0;i < 3; i++) {
|
|
3230
|
-
const av = a[i] ?? 0;
|
|
3231
|
-
const bv = b[i] ?? 0;
|
|
3232
|
-
if (Number.isNaN(av) || Number.isNaN(bv))
|
|
3233
|
-
return false;
|
|
3234
|
-
if (av > bv)
|
|
3235
|
-
return true;
|
|
3236
|
-
if (av < bv)
|
|
3237
|
-
return false;
|
|
3238
|
-
}
|
|
3239
|
-
return false;
|
|
3240
|
-
}
|
|
3241
|
-
async function checkLatestVersion(opts = {}) {
|
|
3242
|
-
if (isDev() && !opts.force)
|
|
3243
|
-
return null;
|
|
3244
|
-
const latest = await fetchLatestFromRegistry(PACKAGE_NAME);
|
|
3245
|
-
if (!latest)
|
|
3246
|
-
return null;
|
|
3247
|
-
return {
|
|
3248
|
-
current: CURRENT_VERSION2,
|
|
3249
|
-
latest,
|
|
3250
|
-
hasUpdate: isNewerSemver(latest, CURRENT_VERSION2)
|
|
3251
|
-
};
|
|
3252
|
-
}
|
|
3253
|
-
function versionFromTagName(tagName) {
|
|
3254
|
-
if (typeof tagName !== "string")
|
|
3255
|
-
return null;
|
|
3256
|
-
const match = tagName.match(/^v(\d+\.\d+\.\d+)$/);
|
|
3257
|
-
return match?.[1] ?? null;
|
|
3258
|
-
}
|
|
3259
|
-
async function fetchReleaseNotes(version) {
|
|
3260
|
-
const slug = repoSlug();
|
|
3261
|
-
if (!slug)
|
|
3262
|
-
return null;
|
|
3263
|
-
const tag = `v${version}`;
|
|
3264
|
-
const ctrl = new AbortController;
|
|
3265
|
-
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
3266
|
-
try {
|
|
3267
|
-
const res = await fetch(`https://api.github.com/repos/${slug}/releases/tags/${tag}`, {
|
|
3268
|
-
signal: ctrl.signal,
|
|
3269
|
-
headers: {
|
|
3270
|
-
accept: "application/vnd.github+json",
|
|
3271
|
-
"x-github-api-version": "2022-11-28"
|
|
3272
|
-
}
|
|
3314
|
+
socket.once("error", onError);
|
|
3315
|
+
socket.on("data", (chunk) => this.onData(chunk.toString("utf8")));
|
|
3316
|
+
socket.on("close", () => this.onSocketClose(socket));
|
|
3273
3317
|
});
|
|
3274
|
-
if (!res.ok)
|
|
3275
|
-
return null;
|
|
3276
|
-
const body = await res.json();
|
|
3277
|
-
if (typeof body.body !== "string" || typeof body.html_url !== "string")
|
|
3278
|
-
return null;
|
|
3279
|
-
return { body: body.body, url: body.html_url, version };
|
|
3280
|
-
} catch {
|
|
3281
|
-
return null;
|
|
3282
|
-
} finally {
|
|
3283
|
-
clearTimeout(timer);
|
|
3284
3318
|
}
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3319
|
+
onSocketClose(which) {
|
|
3320
|
+
if (this.socket !== which)
|
|
3321
|
+
return;
|
|
3322
|
+
this.socket = null;
|
|
3323
|
+
for (const pending of this.pending.values())
|
|
3324
|
+
pending.reject(new Error("daemon connection closed"));
|
|
3325
|
+
this.pending.clear();
|
|
3326
|
+
this.emitLifecycle("close");
|
|
3327
|
+
}
|
|
3328
|
+
emitLifecycle(name) {
|
|
3329
|
+
for (const handler of this.lifecycleHandlers.get(name) ?? []) {
|
|
3330
|
+
try {
|
|
3331
|
+
handler();
|
|
3332
|
+
} catch (err) {
|
|
3333
|
+
console.error(`[kobe] lifecycle handler for "${name}" threw:`, err);
|
|
3298
3334
|
}
|
|
3299
|
-
}
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
const
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
}
|
|
3314
|
-
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
onData(chunk) {
|
|
3338
|
+
this.buffer += chunk;
|
|
3339
|
+
let nl = this.buffer.indexOf(`
|
|
3340
|
+
`);
|
|
3341
|
+
while (nl !== -1) {
|
|
3342
|
+
const line = this.buffer.slice(0, nl);
|
|
3343
|
+
this.buffer = this.buffer.slice(nl + 1);
|
|
3344
|
+
if (line.trim().length > 0)
|
|
3345
|
+
this.onLine(line);
|
|
3346
|
+
nl = this.buffer.indexOf(`
|
|
3347
|
+
`);
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
onLine(line) {
|
|
3351
|
+
const frame = JSON.parse(line);
|
|
3352
|
+
if (frame.type === "event") {
|
|
3353
|
+
this.emit(frame);
|
|
3354
|
+
return;
|
|
3355
|
+
}
|
|
3356
|
+
if (frame.type !== "response")
|
|
3357
|
+
return;
|
|
3358
|
+
const pending = this.pending.get(frame.id);
|
|
3359
|
+
if (!pending)
|
|
3360
|
+
return;
|
|
3361
|
+
this.pending.delete(frame.id);
|
|
3362
|
+
if (frame.error)
|
|
3363
|
+
pending.reject(new Error(frame.error.message));
|
|
3364
|
+
else
|
|
3365
|
+
pending.resolve(frame.payload);
|
|
3366
|
+
}
|
|
3367
|
+
emit(frame) {
|
|
3368
|
+
for (const handler of this.handlers.get(frame.name) ?? [])
|
|
3369
|
+
handler(frame);
|
|
3370
|
+
for (const handler of this.handlers.get("*") ?? [])
|
|
3371
|
+
handler(frame);
|
|
3315
3372
|
}
|
|
3316
3373
|
}
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
if (!slug)
|
|
3320
|
-
return null;
|
|
3321
|
-
return `https://github.com/${slug}/releases/tag/v${version}`;
|
|
3322
|
-
}
|
|
3323
|
-
var CURRENT_VERSION2, PACKAGE_NAME, UPDATE_SCRIPT_URL = "https://raw.githubusercontent.com/Sma1lboy/kobe/main/scripts/update.sh", UPDATE_COMMAND, FETCH_TIMEOUT_MS = 3000;
|
|
3324
|
-
var init_version = __esm(() => {
|
|
3325
|
-
init_package();
|
|
3326
|
-
init_env();
|
|
3327
|
-
CURRENT_VERSION2 = package_default.version;
|
|
3328
|
-
PACKAGE_NAME = package_default.name;
|
|
3329
|
-
UPDATE_COMMAND = `curl -fsSL ${UPDATE_SCRIPT_URL} | sh`;
|
|
3374
|
+
var init_client = __esm(() => {
|
|
3375
|
+
init_protocol();
|
|
3330
3376
|
});
|
|
3331
3377
|
|
|
3332
3378
|
// src/daemon/crash-log.ts
|
|
@@ -3386,11 +3432,11 @@ class DaemonEventBus {
|
|
|
3386
3432
|
}
|
|
3387
3433
|
|
|
3388
3434
|
// src/daemon/paths.ts
|
|
3389
|
-
import { createHash } from "crypto";
|
|
3435
|
+
import { createHash as createHash2 } from "crypto";
|
|
3390
3436
|
import { homedir as homedir3, tmpdir } from "os";
|
|
3391
3437
|
import { join as join3 } from "path";
|
|
3392
3438
|
function shortHomeTag(homeDir2) {
|
|
3393
|
-
return
|
|
3439
|
+
return createHash2("sha1").update(homeDir2).digest("hex").slice(0, 8);
|
|
3394
3440
|
}
|
|
3395
3441
|
function fitSocketPath(naturalPath, homeDir2, role, pidTag) {
|
|
3396
3442
|
if (Buffer.byteLength(naturalPath, "utf8") <= SOCKET_PATH_SAFETY_LIMIT)
|
|
@@ -3952,6 +3998,157 @@ var init_daemon_process = __esm(() => {
|
|
|
3952
3998
|
DAEMON_START_ARGS = ["daemon", "start"];
|
|
3953
3999
|
});
|
|
3954
4000
|
|
|
4001
|
+
// src/cli/repo-cmd.ts
|
|
4002
|
+
var exports_repo_cmd = {};
|
|
4003
|
+
__export(exports_repo_cmd, {
|
|
4004
|
+
runRepoSubcommand: () => runRepoSubcommand
|
|
4005
|
+
});
|
|
4006
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
4007
|
+
import { resolve as resolve3 } from "path";
|
|
4008
|
+
function usageError(message) {
|
|
4009
|
+
process.stderr.write(`kobe repo: ${message}
|
|
4010
|
+
|
|
4011
|
+
${REPO_USAGE}
|
|
4012
|
+
`);
|
|
4013
|
+
process.exit(2);
|
|
4014
|
+
}
|
|
4015
|
+
function readArgFile(path3) {
|
|
4016
|
+
try {
|
|
4017
|
+
return readFileSync2(resolve3(process.cwd(), path3), "utf8");
|
|
4018
|
+
} catch (err) {
|
|
4019
|
+
usageError(`cannot read ${path3}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
function parseRepoArgs(args) {
|
|
4023
|
+
const out = {};
|
|
4024
|
+
for (let i = 0;i < args.length; i++) {
|
|
4025
|
+
const a = args[i];
|
|
4026
|
+
const need = () => {
|
|
4027
|
+
const v = args[++i];
|
|
4028
|
+
if (v === undefined)
|
|
4029
|
+
usageError(`${a} requires a value`);
|
|
4030
|
+
return v;
|
|
4031
|
+
};
|
|
4032
|
+
if (a === "--init-script")
|
|
4033
|
+
out.initScript = need();
|
|
4034
|
+
else if (a === "--init-script-file")
|
|
4035
|
+
out.initScript = readArgFile(need());
|
|
4036
|
+
else if (a === "--init-prompt")
|
|
4037
|
+
out.initPrompt = need();
|
|
4038
|
+
else if (a === "--init-prompt-file")
|
|
4039
|
+
out.initPrompt = readArgFile(need());
|
|
4040
|
+
else if (a.startsWith("-"))
|
|
4041
|
+
usageError(`unknown flag "${a}"`);
|
|
4042
|
+
else if (out.path === undefined)
|
|
4043
|
+
out.path = a;
|
|
4044
|
+
else
|
|
4045
|
+
usageError(`unexpected argument "${a}"`);
|
|
4046
|
+
}
|
|
4047
|
+
return out;
|
|
4048
|
+
}
|
|
4049
|
+
function parseUnsetArgs(args) {
|
|
4050
|
+
let path3;
|
|
4051
|
+
let clearScript = false;
|
|
4052
|
+
let clearPrompt = false;
|
|
4053
|
+
for (const a of args) {
|
|
4054
|
+
if (a === "--init-script")
|
|
4055
|
+
clearScript = true;
|
|
4056
|
+
else if (a === "--init-prompt")
|
|
4057
|
+
clearPrompt = true;
|
|
4058
|
+
else if (a.startsWith("-"))
|
|
4059
|
+
usageError(`unknown flag "${a}"`);
|
|
4060
|
+
else if (path3 === undefined)
|
|
4061
|
+
path3 = a;
|
|
4062
|
+
else
|
|
4063
|
+
usageError(`unexpected argument "${a}"`);
|
|
4064
|
+
}
|
|
4065
|
+
if (!clearScript && !clearPrompt) {
|
|
4066
|
+
clearScript = true;
|
|
4067
|
+
clearPrompt = true;
|
|
4068
|
+
}
|
|
4069
|
+
return { path: path3, clearScript, clearPrompt };
|
|
4070
|
+
}
|
|
4071
|
+
async function runRepoSubcommand(args) {
|
|
4072
|
+
const [verb, ...rest] = args;
|
|
4073
|
+
if (verb === undefined || verb === "--help" || verb === "-h" || verb === "help") {
|
|
4074
|
+
process.stdout.write(`${REPO_USAGE}
|
|
4075
|
+
`);
|
|
4076
|
+
return;
|
|
4077
|
+
}
|
|
4078
|
+
const { getRepoInitOverride: getRepoInitOverride2, setRepoInitOverride: setRepoInitOverride2, resolveRepoRoot: resolveRepoRoot2 } = await Promise.resolve().then(() => (init_repos(), exports_repos));
|
|
4079
|
+
const { existsSync: existsSync2 } = await import("fs");
|
|
4080
|
+
const { join: join4 } = await import("path");
|
|
4081
|
+
if (verb === "show") {
|
|
4082
|
+
const [pathArg] = rest.filter((a) => !a.startsWith("-"));
|
|
4083
|
+
const repo = resolveRepoRoot2(resolve3(process.cwd(), pathArg ?? "."));
|
|
4084
|
+
const override = getRepoInitOverride2(repo);
|
|
4085
|
+
const hasFileScript = existsSync2(join4(repo, ".kobe", "init.sh"));
|
|
4086
|
+
const hasFilePrompt = existsSync2(join4(repo, ".kobe", "init-prompt.md"));
|
|
4087
|
+
console.log(`repo: ${repo}`);
|
|
4088
|
+
console.log(` .kobe/init.sh: ${hasFileScript ? "present (wins)" : "absent"}`);
|
|
4089
|
+
console.log(` .kobe/init-prompt.md: ${hasFilePrompt ? "present (wins)" : "absent"}`);
|
|
4090
|
+
console.log(` override initScript: ${override.initScript ? quotePreview(override.initScript) : "(unset)"}`);
|
|
4091
|
+
console.log(` override initPrompt: ${override.initPrompt ? quotePreview(override.initPrompt) : "(unset)"}`);
|
|
4092
|
+
return;
|
|
4093
|
+
}
|
|
4094
|
+
if (verb === "set") {
|
|
4095
|
+
const flags = parseRepoArgs(rest);
|
|
4096
|
+
if (flags.initScript === undefined && flags.initPrompt === undefined) {
|
|
4097
|
+
usageError("set needs at least one of --init-script(-file) / --init-prompt(-file)");
|
|
4098
|
+
}
|
|
4099
|
+
const repo = resolveRepoRoot2(resolve3(process.cwd(), flags.path ?? "."));
|
|
4100
|
+
const next = setRepoInitOverride2(repo, {
|
|
4101
|
+
...flags.initScript !== undefined ? { initScript: flags.initScript } : {},
|
|
4102
|
+
...flags.initPrompt !== undefined ? { initPrompt: flags.initPrompt } : {}
|
|
4103
|
+
});
|
|
4104
|
+
console.log(`updated override for ${repo}`);
|
|
4105
|
+
console.log(` initScript: ${next.initScript ? quotePreview(next.initScript) : "(unset)"}`);
|
|
4106
|
+
console.log(` initPrompt: ${next.initPrompt ? quotePreview(next.initPrompt) : "(unset)"}`);
|
|
4107
|
+
return;
|
|
4108
|
+
}
|
|
4109
|
+
if (verb === "unset") {
|
|
4110
|
+
const { path: path3, clearScript, clearPrompt } = parseUnsetArgs(rest);
|
|
4111
|
+
const repo = resolveRepoRoot2(resolve3(process.cwd(), path3 ?? "."));
|
|
4112
|
+
const next = setRepoInitOverride2(repo, {
|
|
4113
|
+
...clearScript ? { initScript: "" } : {},
|
|
4114
|
+
...clearPrompt ? { initPrompt: "" } : {}
|
|
4115
|
+
});
|
|
4116
|
+
console.log(`cleared override for ${repo}`);
|
|
4117
|
+
console.log(` initScript: ${next.initScript ? quotePreview(next.initScript) : "(unset)"}`);
|
|
4118
|
+
console.log(` initPrompt: ${next.initPrompt ? quotePreview(next.initPrompt) : "(unset)"}`);
|
|
4119
|
+
return;
|
|
4120
|
+
}
|
|
4121
|
+
usageError(`unknown verb "${verb}"`);
|
|
4122
|
+
}
|
|
4123
|
+
function quotePreview(value) {
|
|
4124
|
+
const oneLine = value.replace(/\s+/g, " ").trim();
|
|
4125
|
+
return oneLine.length > 60 ? `"${oneLine.slice(0, 57)}\u2026"` : `"${oneLine}"`;
|
|
4126
|
+
}
|
|
4127
|
+
var REPO_USAGE;
|
|
4128
|
+
var init_repo_cmd = __esm(() => {
|
|
4129
|
+
REPO_USAGE = [
|
|
4130
|
+
"Usage: kobe repo <show|set|unset> [path] [options]",
|
|
4131
|
+
"",
|
|
4132
|
+
"Manage a repo's per-user init override (state.json fallback for repos",
|
|
4133
|
+
"that don't ship .kobe/init.sh / .kobe/init-prompt.md).",
|
|
4134
|
+
"",
|
|
4135
|
+
"Commands:",
|
|
4136
|
+
" show [path] Print the override + whether the repo ships .kobe/ files",
|
|
4137
|
+
" set [path] <options> Set the init script and/or first prompt",
|
|
4138
|
+
" unset [path] [--init-script] [--init-prompt] Clear one or both (default: both)",
|
|
4139
|
+
"",
|
|
4140
|
+
"Set options (later wins; *-file reads from disk):",
|
|
4141
|
+
" --init-script <text> Inline shell to run before the engine",
|
|
4142
|
+
" --init-script-file <path> Read the init script from a file",
|
|
4143
|
+
" --init-prompt <text> Inline first prompt for the engine",
|
|
4144
|
+
" --init-prompt-file <path> Read the first prompt from a file",
|
|
4145
|
+
"",
|
|
4146
|
+
" path defaults to the current directory (resolved to its git toplevel).",
|
|
4147
|
+
""
|
|
4148
|
+
].join(`
|
|
4149
|
+
`);
|
|
4150
|
+
});
|
|
4151
|
+
|
|
3955
4152
|
// src/engine/interactive-command.ts
|
|
3956
4153
|
function engineCommandKey(vendor) {
|
|
3957
4154
|
return `engineCommand.${vendor}`;
|
|
@@ -4203,6 +4400,41 @@ var init_client2 = __esm(() => {
|
|
|
4203
4400
|
CLAUDE_ROLE_OPTION = PANE_ROLE_OPTION;
|
|
4204
4401
|
});
|
|
4205
4402
|
|
|
4403
|
+
// src/tmux/prompt-delivery.ts
|
|
4404
|
+
async function waitForEnginePane(session, fresh) {
|
|
4405
|
+
let prev = null;
|
|
4406
|
+
for (let attempt = 0;attempt < 24; attempt++) {
|
|
4407
|
+
const pane2 = await claudePaneIdStrict(session);
|
|
4408
|
+
if (pane2) {
|
|
4409
|
+
if (!fresh)
|
|
4410
|
+
return { pane: pane2, ready: true };
|
|
4411
|
+
const cur = (await capturePaneById(pane2)).trim();
|
|
4412
|
+
if (cur.length > 0 && cur === prev)
|
|
4413
|
+
return { pane: pane2, ready: true };
|
|
4414
|
+
prev = cur;
|
|
4415
|
+
}
|
|
4416
|
+
await sleep(250);
|
|
4417
|
+
}
|
|
4418
|
+
const pane = await claudePaneIdStrict(session) || await claudePaneId(session);
|
|
4419
|
+
return { pane, ready: false };
|
|
4420
|
+
}
|
|
4421
|
+
async function pasteAndSubmit(pane, text) {
|
|
4422
|
+
const buffer = `kobe-api-${pane.replace(/[^A-Za-z0-9]/g, "")}`;
|
|
4423
|
+
await runTmux(["set-buffer", "-b", buffer, "--", text]);
|
|
4424
|
+
await runTmux(["paste-buffer", "-p", "-d", "-b", buffer, "-t", pane]);
|
|
4425
|
+
await sendKeyName(pane, "Enter");
|
|
4426
|
+
}
|
|
4427
|
+
async function deliverFirstPrompt(session, prompt) {
|
|
4428
|
+
const { pane } = await waitForEnginePane(session, true);
|
|
4429
|
+
if (!pane)
|
|
4430
|
+
return;
|
|
4431
|
+
await pasteAndSubmit(pane, prompt);
|
|
4432
|
+
}
|
|
4433
|
+
var sleep = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
4434
|
+
var init_prompt_delivery = __esm(() => {
|
|
4435
|
+
init_client2();
|
|
4436
|
+
});
|
|
4437
|
+
|
|
4206
4438
|
// src/cli/invocation.ts
|
|
4207
4439
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4208
4440
|
function kobeCliInvocation() {
|
|
@@ -4225,6 +4457,35 @@ function shellQuoteArgv(argv) {
|
|
|
4225
4457
|
function keepAlive(cmd) {
|
|
4226
4458
|
return `${cmd}; exec "\${SHELL:-/bin/sh}"`;
|
|
4227
4459
|
}
|
|
4460
|
+
function shQuote(s) {
|
|
4461
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
4462
|
+
}
|
|
4463
|
+
function engineLaunchLine(engineCmd, init) {
|
|
4464
|
+
const tail = keepAlive(engineCmd);
|
|
4465
|
+
const script = init?.initScript?.trim();
|
|
4466
|
+
if (!script)
|
|
4467
|
+
return tail;
|
|
4468
|
+
const group = ["{", script, "}"].join(`
|
|
4469
|
+
`);
|
|
4470
|
+
if (init?.markerPath) {
|
|
4471
|
+
const marker = shQuote(init.markerPath);
|
|
4472
|
+
const markerDir = shQuote(markerDirOf(init.markerPath));
|
|
4473
|
+
return [
|
|
4474
|
+
`if [ ! -f ${marker} ]; then`,
|
|
4475
|
+
group,
|
|
4476
|
+
`if [ $? -eq 0 ]; then mkdir -p ${markerDir} && : > ${marker}; fi`,
|
|
4477
|
+
"fi",
|
|
4478
|
+
tail
|
|
4479
|
+
].join(`
|
|
4480
|
+
`);
|
|
4481
|
+
}
|
|
4482
|
+
return [group, tail].join(`
|
|
4483
|
+
`);
|
|
4484
|
+
}
|
|
4485
|
+
function markerDirOf(p) {
|
|
4486
|
+
const i = p.lastIndexOf("/");
|
|
4487
|
+
return i <= 0 ? "." : p.slice(0, i);
|
|
4488
|
+
}
|
|
4228
4489
|
function fallbackOpsScript(cwd) {
|
|
4229
4490
|
return `cd ${shellQuote(cwd)} && while :; do clear; printf "\\033[1m# %s\\033[0m\\n\\n" ${shellQuote(cwd)}; git status --short --branch 2>/dev/null | sed 's/^/ /' || true; printf "\\n"; if command -v lsd >/dev/null 2>&1; then lsd --tree --git -I node_modules -I .git --depth 2 .; elif command -v eza >/dev/null 2>&1; then eza --tree --git -L 2 -I 'node_modules|.git' .; elif command -v tree >/dev/null 2>&1; then tree -L 2 -I 'node_modules|.git'; else ls -la; fi; sleep 2; done`;
|
|
4230
4491
|
}
|
|
@@ -4235,6 +4496,9 @@ function previewWindowCommand(args) {
|
|
|
4235
4496
|
const fallback = `cd ${wt} && if ! git diff --quiet HEAD -- ${file} 2>/dev/null; then ` + `git diff HEAD -- ${file} | { delta --paging=always 2>/dev/null || less -R; }; ` + `else bat --style=plain --paging=always ${file} 2>/dev/null || \${PAGER:-less} ${file} 2>/dev/null || cat ${file}; fi`;
|
|
4236
4497
|
return `${inv} ops --worktree ${wt} --preview ${file} || { ${fallback}; }`;
|
|
4237
4498
|
}
|
|
4499
|
+
function updatePageCommand(args) {
|
|
4500
|
+
return `${shellQuoteArgv([...args.cliInvocation, "update-page"])}`;
|
|
4501
|
+
}
|
|
4238
4502
|
function tasksPaneCommand(cliInvocation) {
|
|
4239
4503
|
return shellQuoteArgv([...cliInvocation, "tasks"]);
|
|
4240
4504
|
}
|
|
@@ -4256,6 +4520,7 @@ __export(exports_tmux, {
|
|
|
4256
4520
|
tmuxAvailable: () => tmuxAvailable,
|
|
4257
4521
|
sessionExists: () => sessionExists,
|
|
4258
4522
|
quickCreate: () => quickCreate,
|
|
4523
|
+
openUpdateTab: () => openUpdateTab,
|
|
4259
4524
|
openSettingsTab: () => openSettingsTab,
|
|
4260
4525
|
openNewTaskTab: () => openNewTaskTab,
|
|
4261
4526
|
newChatTab: () => newChatTab,
|
|
@@ -4334,7 +4599,10 @@ async function ensureSessionImpl(opts) {
|
|
|
4334
4599
|
"-P",
|
|
4335
4600
|
"-F",
|
|
4336
4601
|
"#{pane_id}",
|
|
4337
|
-
|
|
4602
|
+
engineLaunchLine(shellQuoteArgv(opts.command), {
|
|
4603
|
+
initScript: opts.initScript,
|
|
4604
|
+
markerPath: opts.initScript ? worktreeInitMarkerPath(opts.cwd) : undefined
|
|
4605
|
+
})
|
|
4338
4606
|
]);
|
|
4339
4607
|
const pane0 = r0.stdout.trim();
|
|
4340
4608
|
if (!pane0) {
|
|
@@ -4378,6 +4646,10 @@ async function ensureSessionImpl(opts) {
|
|
|
4378
4646
|
["bind-key", "f", "run-shell", `${envStr}${invStr} quick-create --session '#{session_name}'`]
|
|
4379
4647
|
]);
|
|
4380
4648
|
await runTmux(["select-pane", "-t", pane0]);
|
|
4649
|
+
const initPrompt = opts.initPrompt?.trim();
|
|
4650
|
+
if (initPrompt) {
|
|
4651
|
+
deliverFirstPrompt(opts.name, initPrompt).catch((err) => console.error("[kobe tmux] init prompt delivery failed:", err));
|
|
4652
|
+
}
|
|
4381
4653
|
return true;
|
|
4382
4654
|
}
|
|
4383
4655
|
async function relaunchEngineInAllWindows(session, cwd, command) {
|
|
@@ -4454,10 +4726,10 @@ async function healKobePaneVersions(session, cwd, taskId, vendor) {
|
|
|
4454
4726
|
const claudePane = panes.find((pane) => pane.role === "claude")?.paneId;
|
|
4455
4727
|
const tasksPane = panes.find((pane) => pane.role === "tasks");
|
|
4456
4728
|
const opsPane = panes.find((pane) => pane.role === "ops");
|
|
4457
|
-
if (tasksPane && tasksPane.version !==
|
|
4458
|
-
commands.push(["respawn-pane", "-k", "-t", tasksPane.paneId, "-c", cwd, keepAlive(envPrefix + tasksPaneCommand(inv))], ["set-option", "-p", "-t", tasksPane.paneId, "@kobe_role", "tasks"], ["set-option", "-p", "-t", tasksPane.paneId, PANE_VERSION_OPTION,
|
|
4729
|
+
if (tasksPane && tasksPane.version !== CURRENT_VERSION) {
|
|
4730
|
+
commands.push(["respawn-pane", "-k", "-t", tasksPane.paneId, "-c", cwd, keepAlive(envPrefix + tasksPaneCommand(inv))], ["set-option", "-p", "-t", tasksPane.paneId, "@kobe_role", "tasks"], ["set-option", "-p", "-t", tasksPane.paneId, PANE_VERSION_OPTION, CURRENT_VERSION]);
|
|
4459
4731
|
}
|
|
4460
|
-
if (opsPane && claudePane && opsPane.version !==
|
|
4732
|
+
if (opsPane && claudePane && opsPane.version !== CURRENT_VERSION) {
|
|
4461
4733
|
commands.push([
|
|
4462
4734
|
"respawn-pane",
|
|
4463
4735
|
"-k",
|
|
@@ -4472,7 +4744,7 @@ async function healKobePaneVersions(session, cwd, taskId, vendor) {
|
|
|
4472
4744
|
cliInvocation: inv,
|
|
4473
4745
|
vendor
|
|
4474
4746
|
}))
|
|
4475
|
-
], ["set-option", "-p", "-t", opsPane.paneId, "@kobe_role", "ops"], ["set-option", "-p", "-t", opsPane.paneId, PANE_VERSION_OPTION,
|
|
4747
|
+
], ["set-option", "-p", "-t", opsPane.paneId, "@kobe_role", "ops"], ["set-option", "-p", "-t", opsPane.paneId, PANE_VERSION_OPTION, CURRENT_VERSION]);
|
|
4476
4748
|
}
|
|
4477
4749
|
}
|
|
4478
4750
|
if (commands.length > 0)
|
|
@@ -4535,9 +4807,9 @@ async function buildPanesAround(claudePane, args) {
|
|
|
4535
4807
|
`).map((line) => line.trim()).filter(Boolean).map((line) => line.split("=", 2)));
|
|
4536
4808
|
await runTmuxSequence([
|
|
4537
4809
|
...ids.tasks ? [["set-option", "-p", "-t", ids.tasks, "@kobe_role", "tasks"]] : [],
|
|
4538
|
-
...ids.tasks ? [["set-option", "-p", "-t", ids.tasks, PANE_VERSION_OPTION,
|
|
4810
|
+
...ids.tasks ? [["set-option", "-p", "-t", ids.tasks, PANE_VERSION_OPTION, CURRENT_VERSION]] : [],
|
|
4539
4811
|
...ids.ops ? [["set-option", "-p", "-t", ids.ops, "@kobe_role", "ops"]] : [],
|
|
4540
|
-
...ids.ops ? [["set-option", "-p", "-t", ids.ops, PANE_VERSION_OPTION,
|
|
4812
|
+
...ids.ops ? [["set-option", "-p", "-t", ids.ops, PANE_VERSION_OPTION, CURRENT_VERSION]] : []
|
|
4541
4813
|
]);
|
|
4542
4814
|
}
|
|
4543
4815
|
async function newChatTab(session, vendorOverride) {
|
|
@@ -4588,6 +4860,16 @@ async function openNewTaskTab(session, defaultRepo) {
|
|
|
4588
4860
|
const command = `${envPrefix}${inv.map(shellQuote).join(" ")} new-task${repoArg}`;
|
|
4589
4861
|
await newWindow(session, { cwd, command, name: "new task" });
|
|
4590
4862
|
}
|
|
4863
|
+
async function openUpdateTab(session) {
|
|
4864
|
+
if (!await sessionExists(session))
|
|
4865
|
+
return;
|
|
4866
|
+
const sessionOptions = await getSessionOptions(session, ["@kobe_worktree"]);
|
|
4867
|
+
const cwd = sessionOptions["@kobe_worktree"] || process.cwd();
|
|
4868
|
+
const inv = kobeCliInvocation();
|
|
4869
|
+
const envPrefix = inheritedEnvPrefix();
|
|
4870
|
+
const command = `${envPrefix}${updatePageCommand({ cliInvocation: inv })}`;
|
|
4871
|
+
await newWindow(session, { cwd, command, name: "update" });
|
|
4872
|
+
}
|
|
4591
4873
|
async function rememberSessionVendor(session, taskId, vendor) {
|
|
4592
4874
|
await setSessionOption(session, "@kobe_vendor", vendor);
|
|
4593
4875
|
if (!taskId)
|
|
@@ -4617,7 +4899,9 @@ var CHAT_TAB_SWITCH_BINDINGS, CHAT_TAB_CLOSE_BINDING, CHAT_TAB_RENAME_BINDING, C
|
|
|
4617
4899
|
var init_tmux = __esm(() => {
|
|
4618
4900
|
init_invocation();
|
|
4619
4901
|
init_interactive_command();
|
|
4902
|
+
init_env();
|
|
4620
4903
|
init_client2();
|
|
4904
|
+
init_prompt_delivery();
|
|
4621
4905
|
init_vendor();
|
|
4622
4906
|
init_version();
|
|
4623
4907
|
init_client2();
|
|
@@ -4653,6 +4937,43 @@ var init_tmux = __esm(() => {
|
|
|
4653
4937
|
ensureSessionLocks = new Map;
|
|
4654
4938
|
});
|
|
4655
4939
|
|
|
4940
|
+
// src/state/repo-init.ts
|
|
4941
|
+
var exports_repo_init = {};
|
|
4942
|
+
__export(exports_repo_init, {
|
|
4943
|
+
resolveRepoInit: () => resolveRepoInit
|
|
4944
|
+
});
|
|
4945
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
4946
|
+
import { join as join4 } from "path";
|
|
4947
|
+
function repoFileScript(worktreePath) {
|
|
4948
|
+
return existsSync2(join4(worktreePath, INIT_SCRIPT_REL)) ? `sh ${INIT_SCRIPT_REL}` : undefined;
|
|
4949
|
+
}
|
|
4950
|
+
function repoFilePrompt(worktreePath) {
|
|
4951
|
+
const p = join4(worktreePath, INIT_PROMPT_REL);
|
|
4952
|
+
if (!existsSync2(p))
|
|
4953
|
+
return;
|
|
4954
|
+
try {
|
|
4955
|
+
const text = readFileSync3(p, "utf8");
|
|
4956
|
+
return text.trim().length > 0 ? text : undefined;
|
|
4957
|
+
} catch {
|
|
4958
|
+
return;
|
|
4959
|
+
}
|
|
4960
|
+
}
|
|
4961
|
+
function resolveRepoInit(repoRoot, worktreePath) {
|
|
4962
|
+
const override = repoRoot ? getRepoInitOverride(repoRoot) : {};
|
|
4963
|
+
const initScript = repoFileScript(worktreePath) ?? override.initScript;
|
|
4964
|
+
const initPrompt = repoFilePrompt(worktreePath) ?? override.initPrompt;
|
|
4965
|
+
return {
|
|
4966
|
+
initScript: initScript && initScript.trim().length > 0 ? initScript : undefined,
|
|
4967
|
+
initPrompt: initPrompt && initPrompt.trim().length > 0 ? initPrompt : undefined
|
|
4968
|
+
};
|
|
4969
|
+
}
|
|
4970
|
+
var INIT_SCRIPT_REL, INIT_PROMPT_REL;
|
|
4971
|
+
var init_repo_init = __esm(() => {
|
|
4972
|
+
init_repos();
|
|
4973
|
+
INIT_SCRIPT_REL = join4(".kobe", "init.sh");
|
|
4974
|
+
INIT_PROMPT_REL = join4(".kobe", "init-prompt.md");
|
|
4975
|
+
});
|
|
4976
|
+
|
|
4656
4977
|
// src/tui/panes/sidebar/worktree-changes.ts
|
|
4657
4978
|
var exports_worktree_changes = {};
|
|
4658
4979
|
__export(exports_worktree_changes, {
|
|
@@ -4708,7 +5029,7 @@ __export(exports_api_cmd, {
|
|
|
4708
5029
|
ApiError: () => ApiError,
|
|
4709
5030
|
API_VERBS: () => API_VERBS
|
|
4710
5031
|
});
|
|
4711
|
-
import { resolve as
|
|
5032
|
+
import { resolve as resolve4 } from "path";
|
|
4712
5033
|
function parseFlags(argv) {
|
|
4713
5034
|
const flags = new Map;
|
|
4714
5035
|
let pretty = false;
|
|
@@ -4822,29 +5143,6 @@ function fail(message, code, exitCode = 1) {
|
|
|
4822
5143
|
`);
|
|
4823
5144
|
process.exit(exitCode);
|
|
4824
5145
|
}
|
|
4825
|
-
async function waitForEnginePane(session, fresh) {
|
|
4826
|
-
let prev = null;
|
|
4827
|
-
for (let attempt = 0;attempt < 24; attempt++) {
|
|
4828
|
-
const pane2 = await claudePaneIdStrict(session);
|
|
4829
|
-
if (pane2) {
|
|
4830
|
-
if (!fresh)
|
|
4831
|
-
return { pane: pane2, ready: true };
|
|
4832
|
-
const cur = (await capturePaneById(pane2)).trim();
|
|
4833
|
-
if (cur.length > 0 && cur === prev)
|
|
4834
|
-
return { pane: pane2, ready: true };
|
|
4835
|
-
prev = cur;
|
|
4836
|
-
}
|
|
4837
|
-
await sleep(250);
|
|
4838
|
-
}
|
|
4839
|
-
const pane = await claudePaneIdStrict(session) || await claudePaneId(session);
|
|
4840
|
-
return { pane, ready: false };
|
|
4841
|
-
}
|
|
4842
|
-
async function pasteAndSubmit(pane, text) {
|
|
4843
|
-
const buffer = `kobe-api-${pane.replace(/[^A-Za-z0-9]/g, "")}`;
|
|
4844
|
-
await runTmux(["set-buffer", "-b", buffer, "--", text]);
|
|
4845
|
-
await runTmux(["paste-buffer", "-p", "-d", "-b", buffer, "-t", pane]);
|
|
4846
|
-
await sendKeyName(pane, "Enter");
|
|
4847
|
-
}
|
|
4848
5146
|
async function deliverPrompt(client, target, prompt) {
|
|
4849
5147
|
let worktree = target.worktreePath;
|
|
4850
5148
|
if (!worktree) {
|
|
@@ -4857,12 +5155,15 @@ async function deliverPrompt(client, target, prompt) {
|
|
|
4857
5155
|
const existed = await sessionExists(session);
|
|
4858
5156
|
if (!existed) {
|
|
4859
5157
|
const { ensureSession: ensureSession2 } = await Promise.resolve().then(() => (init_tmux(), exports_tmux));
|
|
5158
|
+
const { resolveRepoInit: resolveRepoInit2 } = await Promise.resolve().then(() => (init_repo_init(), exports_repo_init));
|
|
5159
|
+
const init = resolveRepoInit2(target.repo ?? "", worktree);
|
|
4860
5160
|
const ok = await ensureSession2({
|
|
4861
5161
|
name: session,
|
|
4862
5162
|
cwd: worktree,
|
|
4863
5163
|
command: interactiveEngineCommand(target.vendor),
|
|
4864
5164
|
taskId: target.id,
|
|
4865
|
-
vendor: target.vendor
|
|
5165
|
+
vendor: target.vendor,
|
|
5166
|
+
initScript: init.initScript
|
|
4866
5167
|
});
|
|
4867
5168
|
if (!ok)
|
|
4868
5169
|
throw new ApiError(`failed to start tmux session for ${target.id}`, "SESSION_FAILED");
|
|
@@ -4902,7 +5203,12 @@ async function spawnTask(client, parsed) {
|
|
|
4902
5203
|
if (!prompt) {
|
|
4903
5204
|
return { taskId: res.taskId, task: res.task, started: false };
|
|
4904
5205
|
}
|
|
4905
|
-
const delivered = await deliverPrompt(client, {
|
|
5206
|
+
const delivered = await deliverPrompt(client, {
|
|
5207
|
+
id: res.taskId,
|
|
5208
|
+
worktreePath: res.task.worktreePath,
|
|
5209
|
+
vendor: res.task.vendor,
|
|
5210
|
+
repo: res.task.repo
|
|
5211
|
+
}, prompt);
|
|
4906
5212
|
return {
|
|
4907
5213
|
taskId: res.taskId,
|
|
4908
5214
|
task: res.task,
|
|
@@ -4923,7 +5229,12 @@ async function send(client, parsed) {
|
|
|
4923
5229
|
taskId = active;
|
|
4924
5230
|
}
|
|
4925
5231
|
const res = await client.request("task.get", { taskId });
|
|
4926
|
-
const delivered = await deliverPrompt(client, {
|
|
5232
|
+
const delivered = await deliverPrompt(client, {
|
|
5233
|
+
id: taskId,
|
|
5234
|
+
worktreePath: res.task.worktreePath,
|
|
5235
|
+
vendor: res.task.vendor,
|
|
5236
|
+
repo: res.task.repo
|
|
5237
|
+
}, prompt);
|
|
4927
5238
|
return {
|
|
4928
5239
|
ok: true,
|
|
4929
5240
|
taskId,
|
|
@@ -4960,7 +5271,7 @@ async function fanOut(client, parsed) {
|
|
|
4960
5271
|
if (baseRef)
|
|
4961
5272
|
payload.baseRef = baseRef;
|
|
4962
5273
|
const res = await client.request("task.create", payload);
|
|
4963
|
-
const delivered = await deliverPrompt(client, { id: res.taskId, worktreePath: res.task.worktreePath, vendor }, prompt);
|
|
5274
|
+
const delivered = await deliverPrompt(client, { id: res.taskId, worktreePath: res.task.worktreePath, vendor, repo: res.task.repo }, prompt);
|
|
4964
5275
|
tasks.push({
|
|
4965
5276
|
taskId: res.taskId,
|
|
4966
5277
|
vendor,
|
|
@@ -4980,7 +5291,7 @@ async function collect(client, parsed) {
|
|
|
4980
5291
|
taskIds = idsFlag.split(",").map((s) => s.trim()).filter(Boolean);
|
|
4981
5292
|
} else if (repoFlag) {
|
|
4982
5293
|
const { resolveRepoRoot: resolveRepoRoot2 } = await Promise.resolve().then(() => (init_repos(), exports_repos));
|
|
4983
|
-
const target = resolveRepoRoot2(
|
|
5294
|
+
const target = resolveRepoRoot2(resolve4(process.cwd(), repoFlag));
|
|
4984
5295
|
const { tasks } = await client.request("task.list");
|
|
4985
5296
|
taskIds = tasks.filter((t) => !t.archived && resolveRepoRoot2(t.repo) === target).map((t) => t.id);
|
|
4986
5297
|
} else {
|
|
@@ -5064,11 +5375,12 @@ ${apiUsage()}`, "BAD_VERB", 2);
|
|
|
5064
5375
|
client.close();
|
|
5065
5376
|
}
|
|
5066
5377
|
}
|
|
5067
|
-
var API_VERBS, FANOUT_CAP = 10, ApiError
|
|
5378
|
+
var API_VERBS, FANOUT_CAP = 10, ApiError;
|
|
5068
5379
|
var init_api_cmd = __esm(() => {
|
|
5069
5380
|
init_daemon_process();
|
|
5070
5381
|
init_interactive_command();
|
|
5071
5382
|
init_client2();
|
|
5383
|
+
init_prompt_delivery();
|
|
5072
5384
|
init_vendor();
|
|
5073
5385
|
API_VERBS = ["spawn-task", "fan-out", "send", "get-task", "collect", "list"];
|
|
5074
5386
|
ApiError = class ApiError extends Error {
|
|
@@ -5148,7 +5460,7 @@ async function runUpdateSubcommand(args, deps) {
|
|
|
5148
5460
|
return;
|
|
5149
5461
|
}
|
|
5150
5462
|
const plan = updatePlan();
|
|
5151
|
-
io.stdout.write(`kobe ${
|
|
5463
|
+
io.stdout.write(`kobe ${CURRENT_VERSION} -> latest
|
|
5152
5464
|
`);
|
|
5153
5465
|
io.stdout.write(`running: ${plan.display}
|
|
5154
5466
|
`);
|
|
@@ -5217,10 +5529,10 @@ function validateTheme(value) {
|
|
|
5217
5529
|
var init_schema = () => {};
|
|
5218
5530
|
|
|
5219
5531
|
// src/tui/context/theme/loader.ts
|
|
5220
|
-
import { readFileSync as
|
|
5221
|
-
import { join as
|
|
5532
|
+
import { readFileSync as readFileSync4, readdirSync } from "fs";
|
|
5533
|
+
import { join as join5 } from "path";
|
|
5222
5534
|
function userThemesDir() {
|
|
5223
|
-
return
|
|
5535
|
+
return join5(kobeStateDir(), "themes");
|
|
5224
5536
|
}
|
|
5225
5537
|
function loadUserThemes() {
|
|
5226
5538
|
const dir = userThemesDir();
|
|
@@ -5234,10 +5546,10 @@ function loadUserThemes() {
|
|
|
5234
5546
|
for (const file of entries) {
|
|
5235
5547
|
if (!file.endsWith(".json"))
|
|
5236
5548
|
continue;
|
|
5237
|
-
const path3 =
|
|
5549
|
+
const path3 = join5(dir, file);
|
|
5238
5550
|
let parsed;
|
|
5239
5551
|
try {
|
|
5240
|
-
const text =
|
|
5552
|
+
const text = readFileSync4(path3, "utf8");
|
|
5241
5553
|
parsed = JSON.parse(text);
|
|
5242
5554
|
} catch (err) {
|
|
5243
5555
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -5264,8 +5576,8 @@ var exports_theme = {};
|
|
|
5264
5576
|
__export(exports_theme, {
|
|
5265
5577
|
runThemeSubcommand: () => runThemeSubcommand
|
|
5266
5578
|
});
|
|
5267
|
-
import { existsSync as
|
|
5268
|
-
import { basename as basename3, join as
|
|
5579
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
5580
|
+
import { basename as basename3, join as join6, resolve as resolve5 } from "path";
|
|
5269
5581
|
function fail2(message) {
|
|
5270
5582
|
process.stderr.write(`kobe theme: ${message}
|
|
5271
5583
|
`);
|
|
@@ -5296,7 +5608,7 @@ function listThemes() {
|
|
|
5296
5608
|
} else {
|
|
5297
5609
|
for (const f of userFiles) {
|
|
5298
5610
|
const name = f.slice(0, -".json".length);
|
|
5299
|
-
const path3 =
|
|
5611
|
+
const path3 = join6(dir, f);
|
|
5300
5612
|
const overridesBundled = BUNDLED_NAMES.includes(name) ? " (overrides built-in)" : "";
|
|
5301
5613
|
lines.push(` ${name}${overridesBundled} ${path3}`);
|
|
5302
5614
|
}
|
|
@@ -5322,10 +5634,10 @@ async function readSource(source) {
|
|
|
5322
5634
|
const defaultName2 = file2.endsWith(".json") ? file2.slice(0, -".json".length) : file2;
|
|
5323
5635
|
return { text: text2, defaultName: defaultName2 };
|
|
5324
5636
|
}
|
|
5325
|
-
const abs =
|
|
5637
|
+
const abs = resolve5(process.cwd(), source);
|
|
5326
5638
|
let text;
|
|
5327
5639
|
try {
|
|
5328
|
-
text =
|
|
5640
|
+
text = readFileSync5(abs, "utf8");
|
|
5329
5641
|
} catch (err) {
|
|
5330
5642
|
fail2(`failed to read ${abs}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5331
5643
|
}
|
|
@@ -5386,8 +5698,8 @@ async function addTheme(args) {
|
|
|
5386
5698
|
}
|
|
5387
5699
|
const dir = userThemesDir();
|
|
5388
5700
|
mkdirSync3(dir, { recursive: true });
|
|
5389
|
-
const dest =
|
|
5390
|
-
if (
|
|
5701
|
+
const dest = join6(dir, `${name}.json`);
|
|
5702
|
+
if (existsSync3(dest) && !opts.force) {
|
|
5391
5703
|
fail2(`${dest} already exists (pass --force to overwrite)`);
|
|
5392
5704
|
}
|
|
5393
5705
|
writeFileSync2(dest, `${JSON.stringify(result.theme, null, 2)}
|
|
@@ -5404,8 +5716,8 @@ function removeTheme(args) {
|
|
|
5404
5716
|
if (BUNDLED_NAMES.includes(name)) {
|
|
5405
5717
|
fail2(`"${name}" is a built-in theme and cannot be removed`);
|
|
5406
5718
|
}
|
|
5407
|
-
const dest =
|
|
5408
|
-
if (!
|
|
5719
|
+
const dest = join6(userThemesDir(), `${name}.json`);
|
|
5720
|
+
if (!existsSync3(dest)) {
|
|
5409
5721
|
fail2(`no user theme named "${name}" (looked for ${dest})`);
|
|
5410
5722
|
}
|
|
5411
5723
|
unlinkSync(dest);
|
|
@@ -5588,16 +5900,16 @@ var init_daemon_cmd = __esm(() => {
|
|
|
5588
5900
|
});
|
|
5589
5901
|
|
|
5590
5902
|
// src/lib/skill-install.ts
|
|
5591
|
-
import { existsSync as
|
|
5903
|
+
import { existsSync as existsSync4 } from "fs";
|
|
5592
5904
|
import { homedir as homedir5 } from "os";
|
|
5593
|
-
import { join as
|
|
5905
|
+
import { join as join7 } from "path";
|
|
5594
5906
|
function kobeSkillPaths(opts = {}) {
|
|
5595
5907
|
const home = opts.home ?? homedir5();
|
|
5596
5908
|
const cwd = opts.cwd ?? process.cwd();
|
|
5597
|
-
return [
|
|
5909
|
+
return [join7(home, SKILL_REL_PATH), join7(cwd, SKILL_REL_PATH)];
|
|
5598
5910
|
}
|
|
5599
5911
|
function isKobeSkillInstalled(opts) {
|
|
5600
|
-
return kobeSkillPaths(opts).some((p) =>
|
|
5912
|
+
return kobeSkillPaths(opts).some((p) => existsSync4(p));
|
|
5601
5913
|
}
|
|
5602
5914
|
function maybeHintSkillInstall() {
|
|
5603
5915
|
if (isKobeSkillInstalled())
|
|
@@ -5623,9 +5935,9 @@ __export(exports_maintenance, {
|
|
|
5623
5935
|
runResetSubcommand: () => runResetSubcommand,
|
|
5624
5936
|
runDoctorSubcommand: () => runDoctorSubcommand
|
|
5625
5937
|
});
|
|
5626
|
-
import { existsSync as
|
|
5938
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6, statSync } from "fs";
|
|
5627
5939
|
import { unlink as unlink4 } from "fs/promises";
|
|
5628
|
-
import { join as
|
|
5940
|
+
import { join as join8 } from "path";
|
|
5629
5941
|
import { createInterface } from "readline";
|
|
5630
5942
|
function isProcessAlive2(pid) {
|
|
5631
5943
|
try {
|
|
@@ -5672,7 +5984,7 @@ function describeFile(path3) {
|
|
|
5672
5984
|
}
|
|
5673
5985
|
function taskCount(tasksPath) {
|
|
5674
5986
|
try {
|
|
5675
|
-
const parsed = JSON.parse(
|
|
5987
|
+
const parsed = JSON.parse(readFileSync6(tasksPath, "utf8"));
|
|
5676
5988
|
return Array.isArray(parsed.tasks) ? parsed.tasks.length : null;
|
|
5677
5989
|
} catch {
|
|
5678
5990
|
return null;
|
|
@@ -5680,7 +5992,7 @@ function taskCount(tasksPath) {
|
|
|
5680
5992
|
}
|
|
5681
5993
|
function tailFile(path3, n) {
|
|
5682
5994
|
try {
|
|
5683
|
-
const lines =
|
|
5995
|
+
const lines = readFileSync6(path3, "utf8").split(`
|
|
5684
5996
|
`).filter((l) => l.trim().length > 0);
|
|
5685
5997
|
return lines.slice(-n).join(`
|
|
5686
5998
|
`);
|
|
@@ -5722,7 +6034,7 @@ async function runDoctorSubcommand(argv = []) {
|
|
|
5722
6034
|
const socketPath = defaultDaemonSocketPath();
|
|
5723
6035
|
const pidPath = defaultDaemonPidPath();
|
|
5724
6036
|
const logPath = defaultDaemonLogPath();
|
|
5725
|
-
const tasksPath =
|
|
6037
|
+
const tasksPath = join8(kobeStateDir(), "tasks.json");
|
|
5726
6038
|
const statePath2 = kvStatePath();
|
|
5727
6039
|
const out = ["kobe doctor", ` home: ${homeDir()}`, ` socket: ${socketPath}`, ""];
|
|
5728
6040
|
const status = await probeDaemonStatus(socketPath);
|
|
@@ -5743,7 +6055,7 @@ async function runDoctorSubcommand(argv = []) {
|
|
|
5743
6055
|
} else {
|
|
5744
6056
|
out.push("daemon: \u2717 not running (no pidfile)");
|
|
5745
6057
|
}
|
|
5746
|
-
if (
|
|
6058
|
+
if (existsSync5(socketPath))
|
|
5747
6059
|
out.push(` orphan socket file present: ${socketPath}`);
|
|
5748
6060
|
const tail = tailFile(logPath, 8);
|
|
5749
6061
|
if (tail) {
|
|
@@ -5777,7 +6089,7 @@ async function runDoctorSubcommand(argv = []) {
|
|
|
5777
6089
|
async function confirmTty(prompt) {
|
|
5778
6090
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
5779
6091
|
try {
|
|
5780
|
-
const answer = await new Promise((
|
|
6092
|
+
const answer = await new Promise((resolve6) => rl.question(prompt, resolve6));
|
|
5781
6093
|
return /^y(es)?$/i.test(answer.trim());
|
|
5782
6094
|
} finally {
|
|
5783
6095
|
rl.close();
|
|
@@ -5829,7 +6141,7 @@ async function runResetSubcommand(argv) {
|
|
|
5829
6141
|
const yes = argv.includes("--yes") || argv.includes("-y");
|
|
5830
6142
|
const socketPath = defaultDaemonSocketPath();
|
|
5831
6143
|
const pidPath = defaultDaemonPidPath();
|
|
5832
|
-
const tasksPath =
|
|
6144
|
+
const tasksPath = join8(kobeStateDir(), "tasks.json");
|
|
5833
6145
|
const statePath2 = kvStatePath();
|
|
5834
6146
|
console.log("kobe reset will:");
|
|
5835
6147
|
console.log(" \u2022 stop the kobe daemon (graceful \u2192 SIGTERM \u2192 SIGKILL)");
|
|
@@ -9004,7 +9316,7 @@ function addTheme2(name, theme) {
|
|
|
9004
9316
|
}
|
|
9005
9317
|
function resolveTheme(theme, mode = "dark") {
|
|
9006
9318
|
const defs = theme.defs ?? {};
|
|
9007
|
-
function
|
|
9319
|
+
function resolve6(c, chain = []) {
|
|
9008
9320
|
if (typeof c === "string") {
|
|
9009
9321
|
if (c === "transparent" || c === "none")
|
|
9010
9322
|
return RGBA.fromInts(0, 0, 0, 0);
|
|
@@ -9016,13 +9328,13 @@ function resolveTheme(theme, mode = "dark") {
|
|
|
9016
9328
|
const next = defs[c] ?? theme.theme[c];
|
|
9017
9329
|
if (next === undefined)
|
|
9018
9330
|
return RGBA.fromInts(0, 0, 0);
|
|
9019
|
-
return
|
|
9331
|
+
return resolve6(next, [...chain, c]);
|
|
9020
9332
|
}
|
|
9021
|
-
return
|
|
9333
|
+
return resolve6(c[mode], chain);
|
|
9022
9334
|
}
|
|
9023
9335
|
const out = {};
|
|
9024
9336
|
for (const [k, v] of Object.entries(theme.theme)) {
|
|
9025
|
-
out[k] =
|
|
9337
|
+
out[k] = resolve6(v);
|
|
9026
9338
|
}
|
|
9027
9339
|
const text = out.text ?? RGBA.fromHex("#ffffff");
|
|
9028
9340
|
const background = out.background ?? RGBA.fromHex("#000000");
|
|
@@ -9793,7 +10105,7 @@ function findAvailableFolderName(parentDir, base) {
|
|
|
9793
10105
|
return trimmed;
|
|
9794
10106
|
}
|
|
9795
10107
|
function cloneRepo(url, target, onProgress) {
|
|
9796
|
-
return new Promise((
|
|
10108
|
+
return new Promise((resolve6) => {
|
|
9797
10109
|
let stderrBuf = "";
|
|
9798
10110
|
try {
|
|
9799
10111
|
const child = spawn2("git", ["clone", "--progress", url, target], {
|
|
@@ -9810,18 +10122,18 @@ function cloneRepo(url, target, onProgress) {
|
|
|
9810
10122
|
}
|
|
9811
10123
|
});
|
|
9812
10124
|
child.on("error", (err) => {
|
|
9813
|
-
|
|
10125
|
+
resolve6({ ok: false, error: err.message });
|
|
9814
10126
|
});
|
|
9815
10127
|
child.on("close", (code) => {
|
|
9816
10128
|
if (code === 0) {
|
|
9817
|
-
|
|
10129
|
+
resolve6({ ok: true, path: target });
|
|
9818
10130
|
return;
|
|
9819
10131
|
}
|
|
9820
10132
|
const tail = stderrBuf.split(/[\r\n]+/).filter((s) => s.trim().length > 0).pop() ?? `git clone exited with ${code}`;
|
|
9821
|
-
|
|
10133
|
+
resolve6({ ok: false, error: tail });
|
|
9822
10134
|
});
|
|
9823
10135
|
} catch (err) {
|
|
9824
|
-
|
|
10136
|
+
resolve6({ ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
9825
10137
|
}
|
|
9826
10138
|
});
|
|
9827
10139
|
}
|
|
@@ -10884,7 +11196,7 @@ var init_dialog2 = __esm(() => {
|
|
|
10884
11196
|
|
|
10885
11197
|
// src/tui/component/new-task-dialog/index.tsx
|
|
10886
11198
|
function show(dialog, defaultRepo, savedRepos, options) {
|
|
10887
|
-
return new Promise((
|
|
11199
|
+
return new Promise((resolve6) => {
|
|
10888
11200
|
dialog.replace(() => createComponent2(NewTaskDialogView, {
|
|
10889
11201
|
defaultRepo,
|
|
10890
11202
|
savedRepos,
|
|
@@ -10897,9 +11209,9 @@ function show(dialog, defaultRepo, savedRepos, options) {
|
|
|
10897
11209
|
get discoverAdoptable() {
|
|
10898
11210
|
return options?.discoverAdoptable;
|
|
10899
11211
|
},
|
|
10900
|
-
onSubmit: (v) =>
|
|
10901
|
-
onCancel: () =>
|
|
10902
|
-
}), () =>
|
|
11212
|
+
onSubmit: (v) => resolve6(v),
|
|
11213
|
+
onCancel: () => resolve6(undefined)
|
|
11214
|
+
}), () => resolve6(undefined));
|
|
10903
11215
|
dialog.setSize("medium");
|
|
10904
11216
|
});
|
|
10905
11217
|
}
|
|
@@ -10991,15 +11303,15 @@ var init_dialog3 = __esm(() => {
|
|
|
10991
11303
|
|
|
10992
11304
|
// src/tui/component/rename-task-dialog/index.tsx
|
|
10993
11305
|
function show2(dialog, currentTitle, opts = {}) {
|
|
10994
|
-
return new Promise((
|
|
11306
|
+
return new Promise((resolve6) => {
|
|
10995
11307
|
dialog.replace(() => createComponent2(RenameTaskDialogView, {
|
|
10996
11308
|
currentTitle,
|
|
10997
11309
|
get dialogTitle() {
|
|
10998
11310
|
return opts.dialogTitle;
|
|
10999
11311
|
},
|
|
11000
|
-
onSubmit: (v) =>
|
|
11001
|
-
onCancel: () =>
|
|
11002
|
-
}), () =>
|
|
11312
|
+
onSubmit: (v) => resolve6(v),
|
|
11313
|
+
onCancel: () => resolve6(undefined)
|
|
11314
|
+
}), () => resolve6(undefined));
|
|
11003
11315
|
});
|
|
11004
11316
|
}
|
|
11005
11317
|
var RenameTaskDialog;
|
|
@@ -11013,7 +11325,7 @@ var init_rename_task_dialog = __esm(() => {
|
|
|
11013
11325
|
|
|
11014
11326
|
// src/engine/claude-code-local/binary.ts
|
|
11015
11327
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
11016
|
-
import { existsSync as
|
|
11328
|
+
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
11017
11329
|
import { homedir as homedir7 } from "os";
|
|
11018
11330
|
import path4 from "path";
|
|
11019
11331
|
async function findClaudeBinary(deps = defaultDeps) {
|
|
@@ -11100,7 +11412,7 @@ var init_binary = __esm(() => {
|
|
|
11100
11412
|
return;
|
|
11101
11413
|
if (first.startsWith("claude:") && first.includes("aliased to")) {
|
|
11102
11414
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
11103
|
-
return aliasTarget &&
|
|
11415
|
+
return aliasTarget && existsSync7(aliasTarget) ? aliasTarget : undefined;
|
|
11104
11416
|
}
|
|
11105
11417
|
return first;
|
|
11106
11418
|
},
|
|
@@ -11117,7 +11429,7 @@ var init_binary = __esm(() => {
|
|
|
11117
11429
|
|
|
11118
11430
|
// src/engine/codex-local/binary.ts
|
|
11119
11431
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
11120
|
-
import { existsSync as
|
|
11432
|
+
import { existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
11121
11433
|
import { homedir as homedir8 } from "os";
|
|
11122
11434
|
import path5 from "path";
|
|
11123
11435
|
async function findCodexBinary(deps = defaultDeps2) {
|
|
@@ -11188,7 +11500,7 @@ var init_binary2 = __esm(() => {
|
|
|
11188
11500
|
return;
|
|
11189
11501
|
if (first.startsWith("codex:") && first.includes("aliased to")) {
|
|
11190
11502
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
11191
|
-
return aliasTarget &&
|
|
11503
|
+
return aliasTarget && existsSync8(aliasTarget) ? aliasTarget : undefined;
|
|
11192
11504
|
}
|
|
11193
11505
|
return first;
|
|
11194
11506
|
},
|
|
@@ -11205,7 +11517,7 @@ var init_binary2 = __esm(() => {
|
|
|
11205
11517
|
|
|
11206
11518
|
// src/engine/copilot-local/binary.ts
|
|
11207
11519
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
11208
|
-
import { existsSync as
|
|
11520
|
+
import { existsSync as existsSync9, statSync as statSync5 } from "fs";
|
|
11209
11521
|
import { homedir as homedir9 } from "os";
|
|
11210
11522
|
import path6 from "path";
|
|
11211
11523
|
async function findCopilotBinary(deps = defaultDeps3) {
|
|
@@ -11300,7 +11612,7 @@ var init_binary3 = __esm(() => {
|
|
|
11300
11612
|
return;
|
|
11301
11613
|
if (first.startsWith("copilot:") && first.includes("aliased to")) {
|
|
11302
11614
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
11303
|
-
return aliasTarget &&
|
|
11615
|
+
return aliasTarget && existsSync9(aliasTarget) ? aliasTarget : undefined;
|
|
11304
11616
|
}
|
|
11305
11617
|
return first;
|
|
11306
11618
|
},
|
|
@@ -11311,7 +11623,7 @@ var init_binary3 = __esm(() => {
|
|
|
11311
11623
|
});
|
|
11312
11624
|
|
|
11313
11625
|
// src/engine/account-detect.ts
|
|
11314
|
-
import { readFileSync as
|
|
11626
|
+
import { readFileSync as readFileSync7, statSync as statSync6 } from "fs";
|
|
11315
11627
|
import { homedir as homedir10 } from "os";
|
|
11316
11628
|
import path7 from "path";
|
|
11317
11629
|
function claudeGlobalConfigPath(env, home) {
|
|
@@ -11524,7 +11836,7 @@ var init_account_detect = __esm(() => {
|
|
|
11524
11836
|
return null;
|
|
11525
11837
|
throw err;
|
|
11526
11838
|
}
|
|
11527
|
-
return
|
|
11839
|
+
return readFileSync7(p, "utf8");
|
|
11528
11840
|
},
|
|
11529
11841
|
env(name) {
|
|
11530
11842
|
return process.env[name];
|
|
@@ -11660,18 +11972,18 @@ var init_dialog_confirm = __esm(() => {
|
|
|
11660
11972
|
init_keymap();
|
|
11661
11973
|
init_dialog();
|
|
11662
11974
|
DialogConfirm.show = (dialog, title, message, label, confirmLabel, options) => {
|
|
11663
|
-
return new Promise((
|
|
11975
|
+
return new Promise((resolve6) => {
|
|
11664
11976
|
dialog.replace(() => createComponent2(DialogConfirm, {
|
|
11665
11977
|
title,
|
|
11666
11978
|
message,
|
|
11667
|
-
onConfirm: () =>
|
|
11668
|
-
onCancel: () =>
|
|
11979
|
+
onConfirm: () => resolve6(true),
|
|
11980
|
+
onCancel: () => resolve6(false),
|
|
11669
11981
|
label,
|
|
11670
11982
|
confirmLabel,
|
|
11671
11983
|
get initialActive() {
|
|
11672
11984
|
return options?.initialActive;
|
|
11673
11985
|
}
|
|
11674
|
-
}), () =>
|
|
11986
|
+
}), () => resolve6(undefined));
|
|
11675
11987
|
dialog.setSize("small");
|
|
11676
11988
|
});
|
|
11677
11989
|
};
|
|
@@ -11679,7 +11991,7 @@ var init_dialog_confirm = __esm(() => {
|
|
|
11679
11991
|
|
|
11680
11992
|
// src/tui/component/settings-dialog/actions.ts
|
|
11681
11993
|
import { unlinkSync as unlinkSync2 } from "fs";
|
|
11682
|
-
import { join as
|
|
11994
|
+
import { join as join10 } from "path";
|
|
11683
11995
|
function hasRestartableDaemon(orchestrator) {
|
|
11684
11996
|
return orchestrator instanceof RemoteOrchestrator;
|
|
11685
11997
|
}
|
|
@@ -11696,7 +12008,7 @@ async function confirmResetState(dialog, kv, renderer) {
|
|
|
11696
12008
|
return;
|
|
11697
12009
|
kv.clear();
|
|
11698
12010
|
try {
|
|
11699
|
-
unlinkSync2(
|
|
12011
|
+
unlinkSync2(join10(homeDir(), ".kobe", "tasks.json"));
|
|
11700
12012
|
} catch (err) {
|
|
11701
12013
|
if (err.code !== "ENOENT") {
|
|
11702
12014
|
console.error("kobe: failed to delete tasks.json during reset:", err);
|
|
@@ -12853,12 +13165,12 @@ var init_settings_dialog = __esm(() => {
|
|
|
12853
13165
|
init_model();
|
|
12854
13166
|
init_sections();
|
|
12855
13167
|
SettingsDialog.show = (dialog, kv, orchestrator) => {
|
|
12856
|
-
return new Promise((
|
|
13168
|
+
return new Promise((resolve6) => {
|
|
12857
13169
|
dialog.replace(() => createComponent2(SettingsDialog, {
|
|
12858
13170
|
kv,
|
|
12859
13171
|
orchestrator,
|
|
12860
|
-
onClose: () =>
|
|
12861
|
-
}), () =>
|
|
13172
|
+
onClose: () => resolve6()
|
|
13173
|
+
}), () => resolve6());
|
|
12862
13174
|
});
|
|
12863
13175
|
};
|
|
12864
13176
|
});
|
|
@@ -12925,12 +13237,12 @@ var init_focus = __esm(() => {
|
|
|
12925
13237
|
});
|
|
12926
13238
|
|
|
12927
13239
|
// src/tui/context/kv.tsx
|
|
12928
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
13240
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
12929
13241
|
import { dirname as dirname5 } from "path";
|
|
12930
13242
|
function loadInitial() {
|
|
12931
13243
|
const statePath2 = kvStatePath();
|
|
12932
13244
|
try {
|
|
12933
|
-
const text =
|
|
13245
|
+
const text = readFileSync8(statePath2, "utf8");
|
|
12934
13246
|
const parsed = JSON.parse(text);
|
|
12935
13247
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
12936
13248
|
return parsed;
|
|
@@ -13014,10 +13326,10 @@ var init_kv = __esm(() => {
|
|
|
13014
13326
|
});
|
|
13015
13327
|
|
|
13016
13328
|
// src/tui/lib/persisted-ui-prefs.ts
|
|
13017
|
-
import { readFileSync as
|
|
13329
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
13018
13330
|
function readPersistedUiPrefs(fallbackTheme) {
|
|
13019
13331
|
try {
|
|
13020
|
-
const parsed = JSON.parse(
|
|
13332
|
+
const parsed = JSON.parse(readFileSync9(kvStatePath(), "utf8"));
|
|
13021
13333
|
const theme = typeof parsed.activeTheme === "string" && hasTheme(parsed.activeTheme) ? parsed.activeTheme : fallbackTheme;
|
|
13022
13334
|
const transparent = parsed.transparentBackground === true;
|
|
13023
13335
|
const focusAccent = typeof parsed.focusAccent === "string" && FOCUS_ACCENT_SLOTS.includes(parsed.focusAccent) ? parsed.focusAccent : null;
|
|
@@ -13033,8 +13345,8 @@ var init_persisted_ui_prefs = __esm(() => {
|
|
|
13033
13345
|
|
|
13034
13346
|
// src/tui/lib/worktree-opener.ts
|
|
13035
13347
|
import { spawn as spawn3 } from "child_process";
|
|
13036
|
-
import { existsSync as
|
|
13037
|
-
import { basename as basename4, delimiter, isAbsolute, join as
|
|
13348
|
+
import { existsSync as existsSync10 } from "fs";
|
|
13349
|
+
import { basename as basename4, delimiter, isAbsolute, join as join11 } from "path";
|
|
13038
13350
|
function executableOnPath(command, env, exists) {
|
|
13039
13351
|
if (isAbsolute(command))
|
|
13040
13352
|
return exists(command);
|
|
@@ -13042,7 +13354,7 @@ function executableOnPath(command, env, exists) {
|
|
|
13042
13354
|
for (const dir of pathEnv.split(delimiter)) {
|
|
13043
13355
|
if (!dir)
|
|
13044
13356
|
continue;
|
|
13045
|
-
if (exists(
|
|
13357
|
+
if (exists(join11(dir, command)))
|
|
13046
13358
|
return true;
|
|
13047
13359
|
}
|
|
13048
13360
|
return false;
|
|
@@ -13062,7 +13374,7 @@ function labelForOverride(command) {
|
|
|
13062
13374
|
function detectWorktreeOpener(deps = {}) {
|
|
13063
13375
|
const env = deps.env ?? process.env;
|
|
13064
13376
|
const platform = deps.platform ?? process.platform;
|
|
13065
|
-
const exists = deps.exists ??
|
|
13377
|
+
const exists = deps.exists ?? existsSync10;
|
|
13066
13378
|
const override = env.KOBE_OPEN_EDITOR?.trim();
|
|
13067
13379
|
if (override) {
|
|
13068
13380
|
return { id: "env", label: labelForOverride(override), command: override, args: [] };
|
|
@@ -14563,7 +14875,7 @@ var exports_host = {};
|
|
|
14563
14875
|
__export(exports_host, {
|
|
14564
14876
|
startTasksPane: () => startTasksPane
|
|
14565
14877
|
});
|
|
14566
|
-
import { existsSync as
|
|
14878
|
+
import { existsSync as existsSync11 } from "fs";
|
|
14567
14879
|
import { TextAttributes as TextAttributes9 } from "@opentui/core";
|
|
14568
14880
|
function TasksShell(props) {
|
|
14569
14881
|
const themeCtx = useTheme();
|
|
@@ -14654,6 +14966,15 @@ function TasksShell(props) {
|
|
|
14654
14966
|
}
|
|
14655
14967
|
SettingsDialog.show(dialog, kv, props.orch ?? undefined);
|
|
14656
14968
|
}
|
|
14969
|
+
async function openUpdate() {
|
|
14970
|
+
const info = updateInfo();
|
|
14971
|
+
if (!info?.hasUpdate)
|
|
14972
|
+
return;
|
|
14973
|
+
const session = await currentSessionName();
|
|
14974
|
+
if (!session)
|
|
14975
|
+
return;
|
|
14976
|
+
await openUpdateTab(session);
|
|
14977
|
+
}
|
|
14657
14978
|
async function archiveTask(id) {
|
|
14658
14979
|
const task = props.tasks().find((t) => t.id === id);
|
|
14659
14980
|
if (!task || !props.orch)
|
|
@@ -14760,7 +15081,7 @@ function TasksShell(props) {
|
|
|
14760
15081
|
async function openSelectedWorktree(id) {
|
|
14761
15082
|
const task = props.tasks().find((t) => t.id === id);
|
|
14762
15083
|
let worktree = task?.worktreePath;
|
|
14763
|
-
if (!worktree || !
|
|
15084
|
+
if (!worktree || !existsSync11(worktree)) {
|
|
14764
15085
|
if (!props.orch) {
|
|
14765
15086
|
console.error("[kobe tasks] no daemon; cannot materialise worktree");
|
|
14766
15087
|
return;
|
|
@@ -14773,7 +15094,7 @@ function TasksShell(props) {
|
|
|
14773
15094
|
}
|
|
14774
15095
|
await props.reload();
|
|
14775
15096
|
}
|
|
14776
|
-
if (!worktree || !
|
|
15097
|
+
if (!worktree || !existsSync11(worktree))
|
|
14777
15098
|
return;
|
|
14778
15099
|
const opener = detectWorktreeOpener();
|
|
14779
15100
|
if (!opener) {
|
|
@@ -14792,6 +15113,9 @@ function TasksShell(props) {
|
|
|
14792
15113
|
}, {
|
|
14793
15114
|
key: "s",
|
|
14794
15115
|
cmd: () => void openSettings()
|
|
15116
|
+
}, {
|
|
15117
|
+
key: "u",
|
|
15118
|
+
cmd: () => void openUpdate()
|
|
14795
15119
|
}, {
|
|
14796
15120
|
key: "o",
|
|
14797
15121
|
cmd: () => {
|
|
@@ -14821,7 +15145,7 @@ function TasksShell(props) {
|
|
|
14821
15145
|
const exists = await sessionExists(name);
|
|
14822
15146
|
if (exists) {
|
|
14823
15147
|
const cwd2 = await getSessionOption(name, "@kobe_worktree") || task?.worktreePath || "";
|
|
14824
|
-
if (cwd2 &&
|
|
15148
|
+
if (cwd2 && existsSync11(cwd2)) {
|
|
14825
15149
|
await ensureSession({
|
|
14826
15150
|
name,
|
|
14827
15151
|
cwd: cwd2,
|
|
@@ -14835,7 +15159,7 @@ function TasksShell(props) {
|
|
|
14835
15159
|
return;
|
|
14836
15160
|
}
|
|
14837
15161
|
let cwd = task?.worktreePath;
|
|
14838
|
-
if (!cwd || !
|
|
15162
|
+
if (!cwd || !existsSync11(cwd)) {
|
|
14839
15163
|
if (!props.orch) {
|
|
14840
15164
|
console.error("[kobe tasks] no daemon; cannot materialise worktree");
|
|
14841
15165
|
return;
|
|
@@ -14848,14 +15172,17 @@ function TasksShell(props) {
|
|
|
14848
15172
|
}
|
|
14849
15173
|
await props.reload();
|
|
14850
15174
|
}
|
|
14851
|
-
if (!cwd || !
|
|
15175
|
+
if (!cwd || !existsSync11(cwd))
|
|
14852
15176
|
return;
|
|
15177
|
+
const init2 = task?.repo ? resolveRepoInit(task.repo, cwd) : {};
|
|
14853
15178
|
const ready = await ensureSession({
|
|
14854
15179
|
name,
|
|
14855
15180
|
cwd,
|
|
14856
15181
|
command: interactiveEngineCommand(task?.vendor),
|
|
14857
15182
|
taskId: id,
|
|
14858
|
-
vendor: task?.vendor
|
|
15183
|
+
vendor: task?.vendor,
|
|
15184
|
+
initScript: init2.initScript,
|
|
15185
|
+
initPrompt: init2.initPrompt
|
|
14859
15186
|
});
|
|
14860
15187
|
if (!ready) {
|
|
14861
15188
|
console.error(`[kobe tasks] failed to start session ${name}`);
|
|
@@ -14886,7 +15213,8 @@ function TasksShell(props) {
|
|
|
14886
15213
|
focused: () => dialog.stack.length === 0
|
|
14887
15214
|
}));
|
|
14888
15215
|
insert(_el$, createComponent2(ShortcutHints, {
|
|
14889
|
-
updateInfo
|
|
15216
|
+
updateInfo,
|
|
15217
|
+
onOpenUpdate: () => void openUpdate()
|
|
14890
15218
|
}), null);
|
|
14891
15219
|
effect((_$p) => setProp(_el$, "backgroundColor", theme.background, _$p));
|
|
14892
15220
|
return _el$;
|
|
@@ -14899,8 +15227,8 @@ function ShortcutHints(props) {
|
|
|
14899
15227
|
const updateLabel = createMemo(() => {
|
|
14900
15228
|
const info = props.updateInfo();
|
|
14901
15229
|
if (!info)
|
|
14902
|
-
return `v${
|
|
14903
|
-
return info.hasUpdate ? `v${info.latest} available` : `v${
|
|
15230
|
+
return `v${CURRENT_VERSION}`;
|
|
15231
|
+
return info.hasUpdate ? `v${info.latest} available` : `v${CURRENT_VERSION} latest`;
|
|
14904
15232
|
});
|
|
14905
15233
|
const HINTS = [{
|
|
14906
15234
|
k: "\u23CE",
|
|
@@ -14952,10 +15280,10 @@ function ShortcutHints(props) {
|
|
|
14952
15280
|
label: "detach"
|
|
14953
15281
|
}];
|
|
14954
15282
|
return (() => {
|
|
14955
|
-
var _el$3 = createElement("box"), _el$4 = createElement("text"), _el$6 = createElement("box"), _el$7 = createElement("text"), _el$
|
|
15283
|
+
var _el$3 = createElement("box"), _el$4 = createElement("text"), _el$6 = createElement("box"), _el$7 = createElement("text"), _el$12 = createElement("text");
|
|
14956
15284
|
insertNode(_el$3, _el$4);
|
|
14957
15285
|
insertNode(_el$3, _el$6);
|
|
14958
|
-
insertNode(_el$3, _el$
|
|
15286
|
+
insertNode(_el$3, _el$12);
|
|
14959
15287
|
setProp(_el$3, "flexShrink", 0);
|
|
14960
15288
|
setProp(_el$3, "flexDirection", "column");
|
|
14961
15289
|
setProp(_el$3, "paddingLeft", 1);
|
|
@@ -14968,68 +15296,86 @@ function ShortcutHints(props) {
|
|
|
14968
15296
|
setProp(_el$6, "flexDirection", "row");
|
|
14969
15297
|
setProp(_el$6, "gap", 1);
|
|
14970
15298
|
setProp(_el$7, "wrapMode", "none");
|
|
15299
|
+
setProp(_el$7, "onMouseUp", () => {
|
|
15300
|
+
if (props.updateInfo()?.hasUpdate)
|
|
15301
|
+
props.onOpenUpdate();
|
|
15302
|
+
});
|
|
14971
15303
|
insert(_el$7, updateLabel);
|
|
14972
15304
|
insert(_el$3, createComponent2(Show, {
|
|
14973
15305
|
get when() {
|
|
14974
15306
|
return props.updateInfo()?.hasUpdate;
|
|
14975
15307
|
},
|
|
14976
15308
|
get children() {
|
|
14977
|
-
var _el$8 = createElement("text");
|
|
14978
|
-
insertNode(_el$8,
|
|
14979
|
-
|
|
15309
|
+
var _el$8 = createElement("box"), _el$9 = createElement("box"), _el$0 = createElement("text"), _el$10 = createElement("text");
|
|
15310
|
+
insertNode(_el$8, _el$9);
|
|
15311
|
+
insertNode(_el$8, _el$10);
|
|
15312
|
+
setProp(_el$8, "flexDirection", "row");
|
|
15313
|
+
setProp(_el$8, "gap", 1);
|
|
15314
|
+
setProp(_el$8, "onMouseUp", () => props.onOpenUpdate());
|
|
15315
|
+
insertNode(_el$9, _el$0);
|
|
15316
|
+
setProp(_el$9, "width", 10);
|
|
15317
|
+
setProp(_el$9, "flexShrink", 0);
|
|
15318
|
+
insertNode(_el$0, createTextNode(`[U]`));
|
|
15319
|
+
setProp(_el$0, "wrapMode", "none");
|
|
15320
|
+
insertNode(_el$10, createTextNode(`update page`));
|
|
15321
|
+
setProp(_el$10, "wrapMode", "none");
|
|
14980
15322
|
effect((_p$) => {
|
|
14981
|
-
var _v$ = theme.accent, _v$2 = TextAttributes9.DIM;
|
|
14982
|
-
_v$ !== _p$.e && (_p$.e = setProp(_el$
|
|
14983
|
-
_v$2 !== _p$.t && (_p$.t = setProp(_el$
|
|
15323
|
+
var _v$ = theme.accent, _v$2 = TextAttributes9.BOLD, _v$3 = theme.accent, _v$4 = TextAttributes9.DIM;
|
|
15324
|
+
_v$ !== _p$.e && (_p$.e = setProp(_el$0, "fg", _v$, _p$.e));
|
|
15325
|
+
_v$2 !== _p$.t && (_p$.t = setProp(_el$0, "attributes", _v$2, _p$.t));
|
|
15326
|
+
_v$3 !== _p$.a && (_p$.a = setProp(_el$10, "fg", _v$3, _p$.a));
|
|
15327
|
+
_v$4 !== _p$.o && (_p$.o = setProp(_el$10, "attributes", _v$4, _p$.o));
|
|
14984
15328
|
return _p$;
|
|
14985
15329
|
}, {
|
|
14986
15330
|
e: undefined,
|
|
14987
|
-
t: undefined
|
|
15331
|
+
t: undefined,
|
|
15332
|
+
a: undefined,
|
|
15333
|
+
o: undefined
|
|
14988
15334
|
});
|
|
14989
15335
|
return _el$8;
|
|
14990
15336
|
}
|
|
14991
|
-
}), _el$
|
|
14992
|
-
insertNode(_el$
|
|
14993
|
-
setProp(_el$
|
|
15337
|
+
}), _el$12);
|
|
15338
|
+
insertNode(_el$12, createTextNode(`\u2500\u2500 keys \u2500\u2500`));
|
|
15339
|
+
setProp(_el$12, "wrapMode", "none");
|
|
14994
15340
|
insert(_el$3, createComponent2(For, {
|
|
14995
15341
|
each: HINTS,
|
|
14996
15342
|
children: (h) => (() => {
|
|
14997
|
-
var _el$
|
|
14998
|
-
insertNode(_el$
|
|
14999
|
-
insertNode(_el$
|
|
15000
|
-
setProp(_el$
|
|
15001
|
-
setProp(_el$
|
|
15002
|
-
insertNode(_el$
|
|
15003
|
-
setProp(_el$
|
|
15004
|
-
setProp(_el$
|
|
15005
|
-
insertNode(_el$
|
|
15006
|
-
insertNode(_el$
|
|
15007
|
-
setProp(_el$
|
|
15008
|
-
insert(_el$
|
|
15009
|
-
setProp(_el$
|
|
15010
|
-
insert(_el$
|
|
15343
|
+
var _el$14 = createElement("box"), _el$15 = createElement("box"), _el$16 = createElement("text"), _el$17 = createTextNode(`[`), _el$18 = createTextNode(`]`), _el$19 = createElement("text");
|
|
15344
|
+
insertNode(_el$14, _el$15);
|
|
15345
|
+
insertNode(_el$14, _el$19);
|
|
15346
|
+
setProp(_el$14, "flexDirection", "row");
|
|
15347
|
+
setProp(_el$14, "gap", 1);
|
|
15348
|
+
insertNode(_el$15, _el$16);
|
|
15349
|
+
setProp(_el$15, "width", 10);
|
|
15350
|
+
setProp(_el$15, "flexShrink", 0);
|
|
15351
|
+
insertNode(_el$16, _el$17);
|
|
15352
|
+
insertNode(_el$16, _el$18);
|
|
15353
|
+
setProp(_el$16, "wrapMode", "none");
|
|
15354
|
+
insert(_el$16, () => h.k, _el$18);
|
|
15355
|
+
setProp(_el$19, "wrapMode", "none");
|
|
15356
|
+
insert(_el$19, () => h.label);
|
|
15011
15357
|
effect((_p$) => {
|
|
15012
|
-
var _v$
|
|
15013
|
-
_v$
|
|
15014
|
-
_v$
|
|
15015
|
-
_v$
|
|
15358
|
+
var _v$1 = theme.accent, _v$10 = TextAttributes9.BOLD, _v$11 = theme.textMuted;
|
|
15359
|
+
_v$1 !== _p$.e && (_p$.e = setProp(_el$16, "fg", _v$1, _p$.e));
|
|
15360
|
+
_v$10 !== _p$.t && (_p$.t = setProp(_el$16, "attributes", _v$10, _p$.t));
|
|
15361
|
+
_v$11 !== _p$.a && (_p$.a = setProp(_el$19, "fg", _v$11, _p$.a));
|
|
15016
15362
|
return _p$;
|
|
15017
15363
|
}, {
|
|
15018
15364
|
e: undefined,
|
|
15019
15365
|
t: undefined,
|
|
15020
15366
|
a: undefined
|
|
15021
15367
|
});
|
|
15022
|
-
return _el$
|
|
15368
|
+
return _el$14;
|
|
15023
15369
|
})()
|
|
15024
15370
|
}), null);
|
|
15025
15371
|
effect((_p$) => {
|
|
15026
|
-
var _v$
|
|
15027
|
-
_v$
|
|
15028
|
-
_v$
|
|
15029
|
-
_v$
|
|
15030
|
-
_v$
|
|
15031
|
-
_v$
|
|
15032
|
-
_v$
|
|
15372
|
+
var _v$5 = theme.textMuted, _v$6 = TextAttributes9.DIM, _v$7 = props.updateInfo()?.hasUpdate ? theme.warning : theme.textMuted, _v$8 = props.updateInfo()?.hasUpdate ? TextAttributes9.BOLD : TextAttributes9.DIM, _v$9 = theme.textMuted, _v$0 = TextAttributes9.DIM;
|
|
15373
|
+
_v$5 !== _p$.e && (_p$.e = setProp(_el$4, "fg", _v$5, _p$.e));
|
|
15374
|
+
_v$6 !== _p$.t && (_p$.t = setProp(_el$4, "attributes", _v$6, _p$.t));
|
|
15375
|
+
_v$7 !== _p$.a && (_p$.a = setProp(_el$7, "fg", _v$7, _p$.a));
|
|
15376
|
+
_v$8 !== _p$.o && (_p$.o = setProp(_el$7, "attributes", _v$8, _p$.o));
|
|
15377
|
+
_v$9 !== _p$.i && (_p$.i = setProp(_el$12, "fg", _v$9, _p$.i));
|
|
15378
|
+
_v$0 !== _p$.n && (_p$.n = setProp(_el$12, "attributes", _v$0, _p$.n));
|
|
15033
15379
|
return _p$;
|
|
15034
15380
|
}, {
|
|
15035
15381
|
e: undefined,
|
|
@@ -15134,6 +15480,7 @@ var init_host = __esm(() => {
|
|
|
15134
15480
|
init_env();
|
|
15135
15481
|
init_errors();
|
|
15136
15482
|
init_store();
|
|
15483
|
+
init_repo_init();
|
|
15137
15484
|
init_repos();
|
|
15138
15485
|
init_vendor();
|
|
15139
15486
|
init_version();
|
|
@@ -15417,6 +15764,415 @@ var init_host3 = __esm(() => {
|
|
|
15417
15764
|
init_dialog();
|
|
15418
15765
|
});
|
|
15419
15766
|
|
|
15767
|
+
// src/tui/update/host.tsx
|
|
15768
|
+
var exports_host4 = {};
|
|
15769
|
+
__export(exports_host4, {
|
|
15770
|
+
startUpdateHost: () => startUpdateHost
|
|
15771
|
+
});
|
|
15772
|
+
import { spawn as spawn4, spawnSync as spawnSync9 } from "child_process";
|
|
15773
|
+
import { TextAttributes as TextAttributes10 } from "@opentui/core";
|
|
15774
|
+
function openExternalUrl(url) {
|
|
15775
|
+
if (!url)
|
|
15776
|
+
return false;
|
|
15777
|
+
const platform = process.platform;
|
|
15778
|
+
const [command, args] = platform === "darwin" ? ["open", [url]] : platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
15779
|
+
try {
|
|
15780
|
+
const child = spawn4(command, args, {
|
|
15781
|
+
stdio: "ignore",
|
|
15782
|
+
detached: true
|
|
15783
|
+
});
|
|
15784
|
+
child.unref();
|
|
15785
|
+
return true;
|
|
15786
|
+
} catch {
|
|
15787
|
+
return false;
|
|
15788
|
+
}
|
|
15789
|
+
}
|
|
15790
|
+
function releaseBodyLines(body) {
|
|
15791
|
+
return body.replace(/\r\n/g, `
|
|
15792
|
+
`).split(`
|
|
15793
|
+
`).map((line) => line.trim()).filter(Boolean).slice(0, 40);
|
|
15794
|
+
}
|
|
15795
|
+
function waitForKeypress() {
|
|
15796
|
+
if (!process.stdin.isTTY)
|
|
15797
|
+
return Promise.resolve();
|
|
15798
|
+
return new Promise((resolve6) => {
|
|
15799
|
+
const stdin = process.stdin;
|
|
15800
|
+
const done = () => {
|
|
15801
|
+
stdin.off("data", done);
|
|
15802
|
+
stdin.setRawMode?.(false);
|
|
15803
|
+
stdin.pause();
|
|
15804
|
+
resolve6();
|
|
15805
|
+
};
|
|
15806
|
+
stdin.setRawMode?.(true);
|
|
15807
|
+
stdin.resume();
|
|
15808
|
+
stdin.once("data", done);
|
|
15809
|
+
});
|
|
15810
|
+
}
|
|
15811
|
+
function UpdatePage() {
|
|
15812
|
+
const {
|
|
15813
|
+
theme
|
|
15814
|
+
} = useTheme();
|
|
15815
|
+
const renderer = useRenderer();
|
|
15816
|
+
const [info, setInfo] = createSignal(null);
|
|
15817
|
+
const [notes, setNotes] = createSignal(null);
|
|
15818
|
+
const [loadingNotes, setLoadingNotes] = createSignal(true);
|
|
15819
|
+
const [selected, setSelected] = createSignal("update");
|
|
15820
|
+
const [status, setStatus] = createSignal(null);
|
|
15821
|
+
const latest = createMemo(() => info()?.latest ?? CURRENT_VERSION);
|
|
15822
|
+
const releaseUrl = createMemo(() => notes()?.url ?? releasePageUrl(latest()));
|
|
15823
|
+
const lines = createMemo(() => releaseBodyLines(notes()?.body ?? ""));
|
|
15824
|
+
const actions = createMemo(() => [{
|
|
15825
|
+
id: "update",
|
|
15826
|
+
key: "U",
|
|
15827
|
+
label: "Update now",
|
|
15828
|
+
detail: UPDATE_COMMAND
|
|
15829
|
+
}, {
|
|
15830
|
+
id: "release",
|
|
15831
|
+
key: "R",
|
|
15832
|
+
label: "Open release",
|
|
15833
|
+
detail: releaseUrl() ?? "release URL unavailable"
|
|
15834
|
+
}, {
|
|
15835
|
+
id: "close",
|
|
15836
|
+
key: "Q",
|
|
15837
|
+
label: "Close",
|
|
15838
|
+
detail: "return to the previous tmux window"
|
|
15839
|
+
}]);
|
|
15840
|
+
onMount(() => {
|
|
15841
|
+
load2();
|
|
15842
|
+
});
|
|
15843
|
+
async function load2() {
|
|
15844
|
+
const next = await checkLatestVersion({
|
|
15845
|
+
force: true
|
|
15846
|
+
});
|
|
15847
|
+
setInfo(next);
|
|
15848
|
+
const version = next?.latest ?? CURRENT_VERSION;
|
|
15849
|
+
const fetched = await fetchReleaseNotes(version);
|
|
15850
|
+
setNotes(fetched);
|
|
15851
|
+
setLoadingNotes(false);
|
|
15852
|
+
}
|
|
15853
|
+
function move(delta) {
|
|
15854
|
+
const ids = actions().map((a) => a.id);
|
|
15855
|
+
const index = ids.indexOf(selected());
|
|
15856
|
+
const next = (index + delta + ids.length) % ids.length;
|
|
15857
|
+
setSelected(ids[next] ?? "update");
|
|
15858
|
+
}
|
|
15859
|
+
function activate(id = selected()) {
|
|
15860
|
+
if (id === "close")
|
|
15861
|
+
process.exit(0);
|
|
15862
|
+
if (id === "release") {
|
|
15863
|
+
setStatus(openExternalUrl(releaseUrl()) ? "Opened release page in your browser." : "Could not open release URL.");
|
|
15864
|
+
return;
|
|
15865
|
+
}
|
|
15866
|
+
runUpdater();
|
|
15867
|
+
}
|
|
15868
|
+
async function runUpdater() {
|
|
15869
|
+
setStatus("Leaving the TUI page and running the updater in this tmux window...");
|
|
15870
|
+
await new Promise((resolve6) => setTimeout(resolve6, 30));
|
|
15871
|
+
renderer?.destroy();
|
|
15872
|
+
process.stdout.write(`
|
|
15873
|
+
kobe ${CURRENT_VERSION} -> latest
|
|
15874
|
+
`);
|
|
15875
|
+
process.stdout.write(`running: ${UPDATE_COMMAND}
|
|
15876
|
+
|
|
15877
|
+
`);
|
|
15878
|
+
const result = spawnSync9("sh", ["-c", UPDATE_COMMAND], {
|
|
15879
|
+
stdio: "inherit"
|
|
15880
|
+
});
|
|
15881
|
+
const code = result.status ?? (result.error ? 1 : 0);
|
|
15882
|
+
if (result.error)
|
|
15883
|
+
process.stderr.write(`
|
|
15884
|
+
kobe update: failed to start updater: ${result.error.message}
|
|
15885
|
+
`);
|
|
15886
|
+
process.stdout.write(code === 0 ? `
|
|
15887
|
+
kobe update complete. Relaunch kobe to use the new version.
|
|
15888
|
+
` : `
|
|
15889
|
+
kobe update failed with exit code ${code}.
|
|
15890
|
+
`);
|
|
15891
|
+
process.stdout.write("Press any key to close this update window.");
|
|
15892
|
+
await waitForKeypress();
|
|
15893
|
+
process.exit(code);
|
|
15894
|
+
}
|
|
15895
|
+
useBindings(() => ({
|
|
15896
|
+
bindings: [{
|
|
15897
|
+
key: "up",
|
|
15898
|
+
cmd: () => move(-1)
|
|
15899
|
+
}, {
|
|
15900
|
+
key: "down",
|
|
15901
|
+
cmd: () => move(1)
|
|
15902
|
+
}, {
|
|
15903
|
+
key: "k",
|
|
15904
|
+
cmd: () => move(-1)
|
|
15905
|
+
}, {
|
|
15906
|
+
key: "j",
|
|
15907
|
+
cmd: () => move(1)
|
|
15908
|
+
}, {
|
|
15909
|
+
key: "return",
|
|
15910
|
+
cmd: () => activate()
|
|
15911
|
+
}, {
|
|
15912
|
+
key: "u",
|
|
15913
|
+
cmd: () => activate("update")
|
|
15914
|
+
}, {
|
|
15915
|
+
key: "r",
|
|
15916
|
+
cmd: () => activate("release")
|
|
15917
|
+
}, {
|
|
15918
|
+
key: "q",
|
|
15919
|
+
cmd: () => activate("close")
|
|
15920
|
+
}, {
|
|
15921
|
+
key: "escape",
|
|
15922
|
+
cmd: () => activate("close")
|
|
15923
|
+
}, {
|
|
15924
|
+
key: "ctrl+c",
|
|
15925
|
+
cmd: () => activate("close")
|
|
15926
|
+
}]
|
|
15927
|
+
}));
|
|
15928
|
+
return (() => {
|
|
15929
|
+
var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$7 = createElement("box"), _el$8 = createElement("text"), _el$0 = createElement("text"), _el$1 = createTextNode(`v`), _el$10 = createElement("text"), _el$12 = createElement("text"), _el$13 = createTextNode(`v`), _el$14 = createElement("box"), _el$16 = createElement("box"), _el$17 = createElement("text"), _el$19 = createElement("scrollbox"), _el$20 = createElement("box");
|
|
15930
|
+
insertNode(_el$, _el$2);
|
|
15931
|
+
insertNode(_el$, _el$7);
|
|
15932
|
+
insertNode(_el$, _el$14);
|
|
15933
|
+
insertNode(_el$, _el$16);
|
|
15934
|
+
insertNode(_el$, _el$19);
|
|
15935
|
+
setProp(_el$, "flexDirection", "column");
|
|
15936
|
+
setProp(_el$, "flexGrow", 1);
|
|
15937
|
+
setProp(_el$, "paddingTop", 1);
|
|
15938
|
+
setProp(_el$, "paddingLeft", 2);
|
|
15939
|
+
setProp(_el$, "paddingRight", 2);
|
|
15940
|
+
insertNode(_el$2, _el$3);
|
|
15941
|
+
insertNode(_el$2, _el$5);
|
|
15942
|
+
setProp(_el$2, "flexDirection", "row");
|
|
15943
|
+
setProp(_el$2, "justifyContent", "space-between");
|
|
15944
|
+
setProp(_el$2, "flexShrink", 0);
|
|
15945
|
+
insertNode(_el$3, createTextNode(`KOBE UPDATE`));
|
|
15946
|
+
setProp(_el$3, "wrapMode", "none");
|
|
15947
|
+
insertNode(_el$5, createTextNode(`q / esc`));
|
|
15948
|
+
setProp(_el$5, "wrapMode", "none");
|
|
15949
|
+
setProp(_el$5, "onMouseUp", () => activate("close"));
|
|
15950
|
+
insertNode(_el$7, _el$8);
|
|
15951
|
+
insertNode(_el$7, _el$0);
|
|
15952
|
+
insertNode(_el$7, _el$10);
|
|
15953
|
+
insertNode(_el$7, _el$12);
|
|
15954
|
+
setProp(_el$7, "flexDirection", "row");
|
|
15955
|
+
setProp(_el$7, "gap", 2);
|
|
15956
|
+
setProp(_el$7, "flexShrink", 0);
|
|
15957
|
+
setProp(_el$7, "paddingTop", 1);
|
|
15958
|
+
insertNode(_el$8, createTextNode(`current`));
|
|
15959
|
+
setProp(_el$8, "wrapMode", "none");
|
|
15960
|
+
insertNode(_el$0, _el$1);
|
|
15961
|
+
setProp(_el$0, "wrapMode", "none");
|
|
15962
|
+
insert(_el$0, CURRENT_VERSION, null);
|
|
15963
|
+
insertNode(_el$10, createTextNode(`latest`));
|
|
15964
|
+
setProp(_el$10, "wrapMode", "none");
|
|
15965
|
+
insertNode(_el$12, _el$13);
|
|
15966
|
+
setProp(_el$12, "wrapMode", "none");
|
|
15967
|
+
insert(_el$12, latest, null);
|
|
15968
|
+
setProp(_el$14, "flexDirection", "column");
|
|
15969
|
+
setProp(_el$14, "flexShrink", 0);
|
|
15970
|
+
setProp(_el$14, "paddingTop", 1);
|
|
15971
|
+
setProp(_el$14, "gap", 0);
|
|
15972
|
+
insert(_el$14, createComponent2(For, {
|
|
15973
|
+
get each() {
|
|
15974
|
+
return actions();
|
|
15975
|
+
},
|
|
15976
|
+
children: (action) => (() => {
|
|
15977
|
+
var _el$25 = createElement("box"), _el$26 = createElement("box"), _el$27 = createElement("text"), _el$28 = createTextNode(`[`), _el$29 = createTextNode(`]`), _el$30 = createElement("box"), _el$31 = createElement("text"), _el$32 = createElement("text");
|
|
15978
|
+
insertNode(_el$25, _el$26);
|
|
15979
|
+
insertNode(_el$25, _el$30);
|
|
15980
|
+
insertNode(_el$25, _el$32);
|
|
15981
|
+
setProp(_el$25, "flexDirection", "row");
|
|
15982
|
+
setProp(_el$25, "gap", 1);
|
|
15983
|
+
setProp(_el$25, "paddingLeft", 1);
|
|
15984
|
+
setProp(_el$25, "paddingRight", 1);
|
|
15985
|
+
setProp(_el$25, "onMouseUp", () => activate(action.id));
|
|
15986
|
+
insertNode(_el$26, _el$27);
|
|
15987
|
+
setProp(_el$26, "width", 4);
|
|
15988
|
+
setProp(_el$26, "flexShrink", 0);
|
|
15989
|
+
insertNode(_el$27, _el$28);
|
|
15990
|
+
insertNode(_el$27, _el$29);
|
|
15991
|
+
setProp(_el$27, "wrapMode", "none");
|
|
15992
|
+
insert(_el$27, () => action.key, _el$29);
|
|
15993
|
+
insertNode(_el$30, _el$31);
|
|
15994
|
+
setProp(_el$30, "width", 14);
|
|
15995
|
+
setProp(_el$30, "flexShrink", 0);
|
|
15996
|
+
setProp(_el$31, "wrapMode", "none");
|
|
15997
|
+
insert(_el$31, () => action.label);
|
|
15998
|
+
setProp(_el$32, "wrapMode", "word");
|
|
15999
|
+
insert(_el$32, () => action.detail);
|
|
16000
|
+
effect((_p$) => {
|
|
16001
|
+
var _v$12 = selected() === action.id ? theme.primary : undefined, _v$13 = selected() === action.id ? theme.selectedListItemText : theme.accent, _v$14 = TextAttributes10.BOLD, _v$15 = selected() === action.id ? theme.selectedListItemText : theme.text, _v$16 = selected() === action.id ? theme.selectedListItemText : theme.textMuted;
|
|
16002
|
+
_v$12 !== _p$.e && (_p$.e = setProp(_el$25, "backgroundColor", _v$12, _p$.e));
|
|
16003
|
+
_v$13 !== _p$.t && (_p$.t = setProp(_el$27, "fg", _v$13, _p$.t));
|
|
16004
|
+
_v$14 !== _p$.a && (_p$.a = setProp(_el$27, "attributes", _v$14, _p$.a));
|
|
16005
|
+
_v$15 !== _p$.o && (_p$.o = setProp(_el$31, "fg", _v$15, _p$.o));
|
|
16006
|
+
_v$16 !== _p$.i && (_p$.i = setProp(_el$32, "fg", _v$16, _p$.i));
|
|
16007
|
+
return _p$;
|
|
16008
|
+
}, {
|
|
16009
|
+
e: undefined,
|
|
16010
|
+
t: undefined,
|
|
16011
|
+
a: undefined,
|
|
16012
|
+
o: undefined,
|
|
16013
|
+
i: undefined
|
|
16014
|
+
});
|
|
16015
|
+
return _el$25;
|
|
16016
|
+
})()
|
|
16017
|
+
}));
|
|
16018
|
+
insert(_el$, createComponent2(Show, {
|
|
16019
|
+
get when() {
|
|
16020
|
+
return status();
|
|
16021
|
+
},
|
|
16022
|
+
get children() {
|
|
16023
|
+
var _el$15 = createElement("text");
|
|
16024
|
+
setProp(_el$15, "wrapMode", "word");
|
|
16025
|
+
insert(_el$15, status);
|
|
16026
|
+
effect((_$p) => setProp(_el$15, "fg", theme.info, _$p));
|
|
16027
|
+
return _el$15;
|
|
16028
|
+
}
|
|
16029
|
+
}), _el$16);
|
|
16030
|
+
insertNode(_el$16, _el$17);
|
|
16031
|
+
setProp(_el$16, "flexShrink", 0);
|
|
16032
|
+
setProp(_el$16, "paddingTop", 1);
|
|
16033
|
+
insertNode(_el$17, createTextNode(`\u2500\u2500 release notes \u2500\u2500`));
|
|
16034
|
+
setProp(_el$17, "wrapMode", "none");
|
|
16035
|
+
insertNode(_el$19, _el$20);
|
|
16036
|
+
setProp(_el$19, "flexGrow", 1);
|
|
16037
|
+
setProp(_el$19, "flexShrink", 1);
|
|
16038
|
+
setProp(_el$19, "stickyScroll", false);
|
|
16039
|
+
setProp(_el$20, "flexDirection", "column");
|
|
16040
|
+
setProp(_el$20, "paddingRight", 1);
|
|
16041
|
+
setProp(_el$20, "paddingBottom", 1);
|
|
16042
|
+
setProp(_el$20, "gap", 0);
|
|
16043
|
+
insert(_el$20, createComponent2(Show, {
|
|
16044
|
+
get when() {
|
|
16045
|
+
return loadingNotes();
|
|
16046
|
+
},
|
|
16047
|
+
get children() {
|
|
16048
|
+
var _el$21 = createElement("text");
|
|
16049
|
+
insertNode(_el$21, createTextNode(`Loading release notes...`));
|
|
16050
|
+
effect((_$p) => setProp(_el$21, "fg", theme.textMuted, _$p));
|
|
16051
|
+
return _el$21;
|
|
16052
|
+
}
|
|
16053
|
+
}), null);
|
|
16054
|
+
insert(_el$20, createComponent2(Show, {
|
|
16055
|
+
get when() {
|
|
16056
|
+
return memo2(() => !!!loadingNotes())() && lines().length === 0;
|
|
16057
|
+
},
|
|
16058
|
+
get children() {
|
|
16059
|
+
var _el$23 = createElement("text");
|
|
16060
|
+
insertNode(_el$23, createTextNode(`Release notes are unavailable. Use Open release to view the GitHub release page.`));
|
|
16061
|
+
setProp(_el$23, "wrapMode", "word");
|
|
16062
|
+
effect((_$p) => setProp(_el$23, "fg", theme.textMuted, _$p));
|
|
16063
|
+
return _el$23;
|
|
16064
|
+
}
|
|
16065
|
+
}), null);
|
|
16066
|
+
insert(_el$20, createComponent2(For, {
|
|
16067
|
+
get each() {
|
|
16068
|
+
return lines();
|
|
16069
|
+
},
|
|
16070
|
+
children: (line) => (() => {
|
|
16071
|
+
var _el$33 = createElement("text");
|
|
16072
|
+
setProp(_el$33, "wrapMode", "word");
|
|
16073
|
+
insert(_el$33, line);
|
|
16074
|
+
effect((_$p) => setProp(_el$33, "fg", theme.textMuted, _$p));
|
|
16075
|
+
return _el$33;
|
|
16076
|
+
})()
|
|
16077
|
+
}), null);
|
|
16078
|
+
effect((_p$) => {
|
|
16079
|
+
var { background: _v$, text: _v$2 } = theme, _v$3 = TextAttributes10.BOLD, _v$4 = theme.textMuted, _v$5 = theme.textMuted, _v$6 = theme.text, _v$7 = TextAttributes10.BOLD, _v$8 = theme.textMuted, _v$9 = info()?.hasUpdate ? theme.warning : theme.success, _v$0 = TextAttributes10.BOLD, _v$1 = theme.textMuted, _v$10 = TextAttributes10.DIM, _v$11 = {
|
|
16080
|
+
trackOptions: {
|
|
16081
|
+
backgroundColor: theme.background,
|
|
16082
|
+
foregroundColor: theme.borderActive
|
|
16083
|
+
}
|
|
16084
|
+
};
|
|
16085
|
+
_v$ !== _p$.e && (_p$.e = setProp(_el$, "backgroundColor", _v$, _p$.e));
|
|
16086
|
+
_v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
|
|
16087
|
+
_v$3 !== _p$.a && (_p$.a = setProp(_el$3, "attributes", _v$3, _p$.a));
|
|
16088
|
+
_v$4 !== _p$.o && (_p$.o = setProp(_el$5, "fg", _v$4, _p$.o));
|
|
16089
|
+
_v$5 !== _p$.i && (_p$.i = setProp(_el$8, "fg", _v$5, _p$.i));
|
|
16090
|
+
_v$6 !== _p$.n && (_p$.n = setProp(_el$0, "fg", _v$6, _p$.n));
|
|
16091
|
+
_v$7 !== _p$.s && (_p$.s = setProp(_el$0, "attributes", _v$7, _p$.s));
|
|
16092
|
+
_v$8 !== _p$.h && (_p$.h = setProp(_el$10, "fg", _v$8, _p$.h));
|
|
16093
|
+
_v$9 !== _p$.r && (_p$.r = setProp(_el$12, "fg", _v$9, _p$.r));
|
|
16094
|
+
_v$0 !== _p$.d && (_p$.d = setProp(_el$12, "attributes", _v$0, _p$.d));
|
|
16095
|
+
_v$1 !== _p$.l && (_p$.l = setProp(_el$17, "fg", _v$1, _p$.l));
|
|
16096
|
+
_v$10 !== _p$.u && (_p$.u = setProp(_el$17, "attributes", _v$10, _p$.u));
|
|
16097
|
+
_v$11 !== _p$.c && (_p$.c = setProp(_el$19, "verticalScrollbarOptions", _v$11, _p$.c));
|
|
16098
|
+
return _p$;
|
|
16099
|
+
}, {
|
|
16100
|
+
e: undefined,
|
|
16101
|
+
t: undefined,
|
|
16102
|
+
a: undefined,
|
|
16103
|
+
o: undefined,
|
|
16104
|
+
i: undefined,
|
|
16105
|
+
n: undefined,
|
|
16106
|
+
s: undefined,
|
|
16107
|
+
h: undefined,
|
|
16108
|
+
r: undefined,
|
|
16109
|
+
d: undefined,
|
|
16110
|
+
l: undefined,
|
|
16111
|
+
u: undefined,
|
|
16112
|
+
c: undefined
|
|
16113
|
+
});
|
|
16114
|
+
return _el$;
|
|
16115
|
+
})();
|
|
16116
|
+
}
|
|
16117
|
+
async function startUpdateHost() {
|
|
16118
|
+
for (const {
|
|
16119
|
+
name,
|
|
16120
|
+
theme
|
|
16121
|
+
} of loadUserThemes()) {
|
|
16122
|
+
addTheme2(name, theme);
|
|
16123
|
+
}
|
|
16124
|
+
const prefs = readPersistedUiPrefs(FALLBACK_THEME4);
|
|
16125
|
+
await render(() => createComponent2(ThemeProvider, {
|
|
16126
|
+
mode: "dark",
|
|
16127
|
+
get theme() {
|
|
16128
|
+
return prefs.theme;
|
|
16129
|
+
},
|
|
16130
|
+
get children() {
|
|
16131
|
+
return createComponent2(KVProvider, {
|
|
16132
|
+
get children() {
|
|
16133
|
+
return createComponent2(FocusProvider, {
|
|
16134
|
+
initial: "sidebar",
|
|
16135
|
+
get children() {
|
|
16136
|
+
return createComponent2(DialogProvider, {
|
|
16137
|
+
get children() {
|
|
16138
|
+
return createComponent2(UpdatePage, {});
|
|
16139
|
+
}
|
|
16140
|
+
});
|
|
16141
|
+
}
|
|
16142
|
+
});
|
|
16143
|
+
}
|
|
16144
|
+
});
|
|
16145
|
+
}
|
|
16146
|
+
}), {
|
|
16147
|
+
backgroundColor: "transparent",
|
|
16148
|
+
externalOutputMode: "passthrough",
|
|
16149
|
+
exitOnCtrlC: false,
|
|
16150
|
+
screenMode: "alternate-screen",
|
|
16151
|
+
useKittyKeyboard: {}
|
|
16152
|
+
});
|
|
16153
|
+
}
|
|
16154
|
+
var FALLBACK_THEME4 = "claude";
|
|
16155
|
+
var init_host4 = __esm(() => {
|
|
16156
|
+
init_solid();
|
|
16157
|
+
init_solid();
|
|
16158
|
+
init_solid();
|
|
16159
|
+
init_solid();
|
|
16160
|
+
init_solid();
|
|
16161
|
+
init_solid();
|
|
16162
|
+
init_solid();
|
|
16163
|
+
init_solid();
|
|
16164
|
+
init_solid();
|
|
16165
|
+
init_dev();
|
|
16166
|
+
init_version();
|
|
16167
|
+
init_focus();
|
|
16168
|
+
init_kv();
|
|
16169
|
+
init_theme2();
|
|
16170
|
+
init_loader();
|
|
16171
|
+
init_keymap();
|
|
16172
|
+
init_persisted_ui_prefs();
|
|
16173
|
+
init_dialog();
|
|
16174
|
+
});
|
|
16175
|
+
|
|
15420
16176
|
// src/engine/claude-code-local/normalize.ts
|
|
15421
16177
|
function normalizeClaudeContent(content) {
|
|
15422
16178
|
if (typeof content === "string") {
|
|
@@ -16552,7 +17308,7 @@ var gitWrapper;
|
|
|
16552
17308
|
var init_git2 = __esm(() => {
|
|
16553
17309
|
gitWrapper = {
|
|
16554
17310
|
spawn(args, cwd) {
|
|
16555
|
-
return new Promise((
|
|
17311
|
+
return new Promise((resolve6, reject) => {
|
|
16556
17312
|
const child = nodeSpawn("git", [...args], {
|
|
16557
17313
|
cwd,
|
|
16558
17314
|
shell: false,
|
|
@@ -16570,7 +17326,7 @@ var init_git2 = __esm(() => {
|
|
|
16570
17326
|
});
|
|
16571
17327
|
child.on("error", reject);
|
|
16572
17328
|
child.on("close", (status, signal) => {
|
|
16573
|
-
|
|
17329
|
+
resolve6({ stdout, stderr, status, signal });
|
|
16574
17330
|
});
|
|
16575
17331
|
});
|
|
16576
17332
|
}
|
|
@@ -16622,17 +17378,17 @@ var init_keys2 = __esm(() => {
|
|
|
16622
17378
|
});
|
|
16623
17379
|
|
|
16624
17380
|
// src/tui/panes/filetree/open-external.ts
|
|
16625
|
-
import { spawn as
|
|
16626
|
-
import { existsSync as
|
|
17381
|
+
import { spawn as spawn5 } from "child_process";
|
|
17382
|
+
import { existsSync as existsSync12 } from "fs";
|
|
16627
17383
|
import { platform } from "os";
|
|
16628
17384
|
function openExternally(absPath) {
|
|
16629
17385
|
if (!absPath)
|
|
16630
17386
|
return;
|
|
16631
17387
|
const plat = platform();
|
|
16632
17388
|
if (plat === "linux") {
|
|
16633
|
-
if (
|
|
17389
|
+
if (existsSync12("/proc/sys/fs/binfmt_misc/WSLInterop") || process.env.WSL_DISTRO_NAME) {
|
|
16634
17390
|
spawnDetached("wslview", [absPath], () => {
|
|
16635
|
-
const child =
|
|
17391
|
+
const child = spawn5("wslpath", ["-w", absPath], { stdio: ["ignore", "pipe", "ignore"] });
|
|
16636
17392
|
let out = "";
|
|
16637
17393
|
child.stdout.on("data", (b) => {
|
|
16638
17394
|
out += b.toString();
|
|
@@ -16658,7 +17414,7 @@ function openExternally(absPath) {
|
|
|
16658
17414
|
}
|
|
16659
17415
|
function spawnDetached(cmd, args, onError) {
|
|
16660
17416
|
try {
|
|
16661
|
-
const child =
|
|
17417
|
+
const child = spawn5(cmd, args, { stdio: "ignore", detached: true });
|
|
16662
17418
|
child.on("error", () => onError?.());
|
|
16663
17419
|
child.unref();
|
|
16664
17420
|
} catch {
|
|
@@ -16669,7 +17425,7 @@ var init_open_external = () => {};
|
|
|
16669
17425
|
|
|
16670
17426
|
// src/tui/panes/filetree/FileTree.tsx
|
|
16671
17427
|
import { watch } from "fs";
|
|
16672
|
-
import { TextAttributes as
|
|
17428
|
+
import { TextAttributes as TextAttributes11 } from "@opentui/core";
|
|
16673
17429
|
function statusToken(s) {
|
|
16674
17430
|
switch (s) {
|
|
16675
17431
|
case "M":
|
|
@@ -17046,7 +17802,7 @@ function FileTree(props) {
|
|
|
17046
17802
|
insertNode(_el$6, createTextNode(`create PR`));
|
|
17047
17803
|
setProp(_el$6, "wrapMode", "none");
|
|
17048
17804
|
effect((_p$) => {
|
|
17049
|
-
var _v$ = theme.accent, _v$2 =
|
|
17805
|
+
var _v$ = theme.accent, _v$2 = TextAttributes11.BOLD, _v$3 = theme.text;
|
|
17050
17806
|
_v$ !== _p$.e && (_p$.e = setProp(_el$4, "fg", _v$, _p$.e));
|
|
17051
17807
|
_v$2 !== _p$.t && (_p$.t = setProp(_el$4, "attributes", _v$2, _p$.t));
|
|
17052
17808
|
_v$3 !== _p$.a && (_p$.a = setProp(_el$6, "fg", _v$3, _p$.a));
|
|
@@ -17076,7 +17832,7 @@ function FileTree(props) {
|
|
|
17076
17832
|
setProp(_el$23, "onMouseUp", () => setTab(t));
|
|
17077
17833
|
insert(_el$23, () => TAB_LABEL[t]);
|
|
17078
17834
|
effect((_p$) => {
|
|
17079
|
-
var _v$6 = isActive() ? theme.primary : theme.textMuted, _v$7 = isActive() ?
|
|
17835
|
+
var _v$6 = isActive() ? theme.primary : theme.textMuted, _v$7 = isActive() ? TextAttributes11.BOLD : undefined;
|
|
17080
17836
|
_v$6 !== _p$.e && (_p$.e = setProp(_el$23, "fg", _v$6, _p$.e));
|
|
17081
17837
|
_v$7 !== _p$.t && (_p$.t = setProp(_el$23, "attributes", _v$7, _p$.t));
|
|
17082
17838
|
return _p$;
|
|
@@ -17097,7 +17853,7 @@ function FileTree(props) {
|
|
|
17097
17853
|
setProp(_el$24, "wrapMode", "none");
|
|
17098
17854
|
insert(_el$24, () => badge().text);
|
|
17099
17855
|
effect((_p$) => {
|
|
17100
|
-
var _v$8 = badge().active ? theme.accent : theme.textMuted, _v$9 = badge().active ?
|
|
17856
|
+
var _v$8 = badge().active ? theme.accent : theme.textMuted, _v$9 = badge().active ? TextAttributes11.BOLD : undefined;
|
|
17101
17857
|
_v$8 !== _p$.e && (_p$.e = setProp(_el$24, "fg", _v$8, _p$.e));
|
|
17102
17858
|
_v$9 !== _p$.t && (_p$.t = setProp(_el$24, "attributes", _v$9, _p$.t));
|
|
17103
17859
|
return _p$;
|
|
@@ -17239,7 +17995,7 @@ function FileTree(props) {
|
|
|
17239
17995
|
setProp(_el$26, "wrapMode", "none");
|
|
17240
17996
|
insert(_el$26, () => `${indent}${marker} ${row.name}/`);
|
|
17241
17997
|
effect((_p$) => {
|
|
17242
|
-
var _v$0 = isCursor() ? theme.primary : undefined, _v$1 = isCursor() ? theme.selectedListItemText : theme.textMuted, _v$10 =
|
|
17998
|
+
var _v$0 = isCursor() ? theme.primary : undefined, _v$1 = isCursor() ? theme.selectedListItemText : theme.textMuted, _v$10 = TextAttributes11.BOLD;
|
|
17243
17999
|
_v$0 !== _p$.e && (_p$.e = setProp(_el$25, "backgroundColor", _v$0, _p$.e));
|
|
17244
18000
|
_v$1 !== _p$.t && (_p$.t = setProp(_el$26, "fg", _v$1, _p$.t));
|
|
17245
18001
|
_v$10 !== _p$.a && (_p$.a = setProp(_el$26, "attributes", _v$10, _p$.a));
|
|
@@ -17388,12 +18144,12 @@ var init_filetree = __esm(() => {
|
|
|
17388
18144
|
});
|
|
17389
18145
|
|
|
17390
18146
|
// src/tui/ops/pr-prompt.ts
|
|
17391
|
-
import { spawnSync as
|
|
18147
|
+
import { spawnSync as spawnSync10 } from "child_process";
|
|
17392
18148
|
import { promises as fs4 } from "fs";
|
|
17393
18149
|
import path11 from "path";
|
|
17394
18150
|
function git2(cwd, args) {
|
|
17395
18151
|
try {
|
|
17396
|
-
const out =
|
|
18152
|
+
const out = spawnSync10("git", args.slice(), {
|
|
17397
18153
|
cwd,
|
|
17398
18154
|
encoding: "utf8",
|
|
17399
18155
|
timeout: GIT_TIMEOUT_MS
|
|
@@ -17487,12 +18243,12 @@ If any of these steps fail, ask the user for help.`;
|
|
|
17487
18243
|
var init_pr_prompt = () => {};
|
|
17488
18244
|
|
|
17489
18245
|
// src/tui/ops/host.tsx
|
|
17490
|
-
var
|
|
17491
|
-
__export(
|
|
18246
|
+
var exports_host5 = {};
|
|
18247
|
+
__export(exports_host5, {
|
|
17492
18248
|
startOpsPreview: () => startOpsPreview,
|
|
17493
18249
|
startOpsHost: () => startOpsHost
|
|
17494
18250
|
});
|
|
17495
|
-
import { createHash as
|
|
18251
|
+
import { createHash as createHash3 } from "crypto";
|
|
17496
18252
|
import { SyntaxStyle } from "@opentui/core";
|
|
17497
18253
|
function OpsShell(props) {
|
|
17498
18254
|
const themeCtx = useTheme();
|
|
@@ -17631,7 +18387,7 @@ function basename5(p) {
|
|
|
17631
18387
|
return i >= 0 ? p.slice(i + 1) : p;
|
|
17632
18388
|
}
|
|
17633
18389
|
function fingerprint(text) {
|
|
17634
|
-
return
|
|
18390
|
+
return createHash3("sha1").update(text).digest("hex");
|
|
17635
18391
|
}
|
|
17636
18392
|
function OpsApp(props) {
|
|
17637
18393
|
return createComponent2(ThemeProvider, {
|
|
@@ -17655,7 +18411,7 @@ async function startOpsHost(args) {
|
|
|
17655
18411
|
} of loadUserThemes()) {
|
|
17656
18412
|
addTheme2(name, theme);
|
|
17657
18413
|
}
|
|
17658
|
-
const prefs = readPersistedUiPrefs(
|
|
18414
|
+
const prefs = readPersistedUiPrefs(FALLBACK_THEME5);
|
|
17659
18415
|
await render(() => createComponent2(OpsApp, mergeProps3(args, {
|
|
17660
18416
|
prefs
|
|
17661
18417
|
})), {
|
|
@@ -17883,7 +18639,7 @@ async function startOpsPreview(args) {
|
|
|
17883
18639
|
} of loadUserThemes()) {
|
|
17884
18640
|
addTheme2(name, theme);
|
|
17885
18641
|
}
|
|
17886
|
-
const prefs = readPersistedUiPrefs(
|
|
18642
|
+
const prefs = readPersistedUiPrefs(FALLBACK_THEME5);
|
|
17887
18643
|
await render(() => createComponent2(ThemeProvider, {
|
|
17888
18644
|
mode: "dark",
|
|
17889
18645
|
get theme() {
|
|
@@ -17904,8 +18660,8 @@ async function startOpsPreview(args) {
|
|
|
17904
18660
|
useKittyKeyboard: {}
|
|
17905
18661
|
});
|
|
17906
18662
|
}
|
|
17907
|
-
var
|
|
17908
|
-
var
|
|
18663
|
+
var FALLBACK_THEME5 = "claude", ACTIVITY_POLL_MS = 2500, TURN_STATUS_POLL_MS = 1500, STABLE_POLLS_FOR_DONE = 2, CHAT_TAB_STATE_OPTION2 = "@kobe_tab_state";
|
|
18664
|
+
var init_host5 = __esm(() => {
|
|
17909
18665
|
init_solid();
|
|
17910
18666
|
init_solid();
|
|
17911
18667
|
init_solid();
|
|
@@ -17971,7 +18727,7 @@ __export(exports_direct, {
|
|
|
17971
18727
|
startDirectTmux: () => startDirectTmux,
|
|
17972
18728
|
chooseInitialTask: () => chooseInitialTask
|
|
17973
18729
|
});
|
|
17974
|
-
import { resolve as
|
|
18730
|
+
import { resolve as resolve6 } from "path";
|
|
17975
18731
|
function chooseInitialTask(tasks, choice = {}) {
|
|
17976
18732
|
const byId = (id) => id ? tasks.find((t) => t.id === id) : undefined;
|
|
17977
18733
|
const active = byId(choice.activeTaskId);
|
|
@@ -18007,7 +18763,7 @@ async function ensureRepos(orchestrator) {
|
|
|
18007
18763
|
normalizeSavedRepos();
|
|
18008
18764
|
let repos = [...getSavedRepos()];
|
|
18009
18765
|
if (repos.length === 0) {
|
|
18010
|
-
const added = addSavedRepo(
|
|
18766
|
+
const added = addSavedRepo(resolve6(process.cwd()));
|
|
18011
18767
|
repos = [added.path];
|
|
18012
18768
|
}
|
|
18013
18769
|
for (const repo of repos) {
|
|
@@ -18017,7 +18773,7 @@ async function ensureRepos(orchestrator) {
|
|
|
18017
18773
|
console.error(`[kobe] ensureMainTask failed for ${repo}:`, err);
|
|
18018
18774
|
}
|
|
18019
18775
|
}
|
|
18020
|
-
return repos[0] ??
|
|
18776
|
+
return repos[0] ?? resolve6(process.cwd());
|
|
18021
18777
|
}
|
|
18022
18778
|
async function startDirectTmux() {
|
|
18023
18779
|
if (!await tmuxAvailable()) {
|
|
@@ -18045,12 +18801,15 @@ async function startDirectTmux() {
|
|
|
18045
18801
|
const name = tmuxSessionName(task.id);
|
|
18046
18802
|
await orchestrator.setActiveTask(task.id).catch(() => {});
|
|
18047
18803
|
setPersistedString("lastSelectedTaskId", task.id);
|
|
18804
|
+
const init2 = resolveRepoInit(task.repo, cwd);
|
|
18048
18805
|
const ready = await ensureSession({
|
|
18049
18806
|
name,
|
|
18050
18807
|
cwd,
|
|
18051
18808
|
command: interactiveEngineCommand(task.vendor),
|
|
18052
18809
|
taskId: task.id,
|
|
18053
|
-
vendor: task.vendor
|
|
18810
|
+
vendor: task.vendor,
|
|
18811
|
+
initScript: init2.initScript,
|
|
18812
|
+
initPrompt: init2.initPrompt
|
|
18054
18813
|
});
|
|
18055
18814
|
if (!ready) {
|
|
18056
18815
|
console.error(`kobe: tmux session ${name} failed to start (check the daemon log)`);
|
|
@@ -18088,12 +18847,13 @@ var init_direct = __esm(() => {
|
|
|
18088
18847
|
init_interactive_command();
|
|
18089
18848
|
init_auto_title();
|
|
18090
18849
|
init_core();
|
|
18850
|
+
init_repo_init();
|
|
18091
18851
|
init_repos();
|
|
18092
18852
|
init_tmux();
|
|
18093
18853
|
});
|
|
18094
18854
|
|
|
18095
18855
|
// src/tui/component/help-dialog.tsx
|
|
18096
|
-
import { TextAttributes as
|
|
18856
|
+
import { TextAttributes as TextAttributes12 } from "@opentui/core";
|
|
18097
18857
|
function groupBindings(keymap) {
|
|
18098
18858
|
const groups = new Map;
|
|
18099
18859
|
const order = [];
|
|
@@ -18197,7 +18957,7 @@ function HelpDialog() {
|
|
|
18197
18957
|
}
|
|
18198
18958
|
}), null);
|
|
18199
18959
|
effect((_p$) => {
|
|
18200
|
-
var _v$5 = theme.accent, _v$6 =
|
|
18960
|
+
var _v$5 = theme.accent, _v$6 = TextAttributes12.BOLD;
|
|
18201
18961
|
_v$5 !== _p$.e && (_p$.e = setProp(_el$0, "fg", _v$5, _p$.e));
|
|
18202
18962
|
_v$6 !== _p$.t && (_p$.t = setProp(_el$0, "attributes", _v$6, _p$.t));
|
|
18203
18963
|
return _p$;
|
|
@@ -18209,7 +18969,7 @@ function HelpDialog() {
|
|
|
18209
18969
|
})()
|
|
18210
18970
|
}));
|
|
18211
18971
|
effect((_p$) => {
|
|
18212
|
-
var _v$ =
|
|
18972
|
+
var _v$ = TextAttributes12.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = {
|
|
18213
18973
|
trackOptions: {
|
|
18214
18974
|
backgroundColor: theme.backgroundDialog,
|
|
18215
18975
|
foregroundColor: theme.borderActive
|
|
@@ -18249,7 +19009,7 @@ var init_help_dialog = __esm(() => {
|
|
|
18249
19009
|
});
|
|
18250
19010
|
|
|
18251
19011
|
// src/tui/component/pane-header.tsx
|
|
18252
|
-
import { TextAttributes as
|
|
19012
|
+
import { TextAttributes as TextAttributes13 } from "@opentui/core";
|
|
18253
19013
|
function PaneHeader(props) {
|
|
18254
19014
|
const {
|
|
18255
19015
|
theme
|
|
@@ -18279,7 +19039,7 @@ function PaneHeader(props) {
|
|
|
18279
19039
|
setProp(_el$3, "wrapMode", "none");
|
|
18280
19040
|
insert(_el$3, () => props.ordinal);
|
|
18281
19041
|
effect((_p$) => {
|
|
18282
|
-
var _v$ = titleColor(), _v$2 =
|
|
19042
|
+
var _v$ = titleColor(), _v$2 = TextAttributes13.BOLD;
|
|
18283
19043
|
_v$ !== _p$.e && (_p$.e = setProp(_el$3, "fg", _v$, _p$.e));
|
|
18284
19044
|
_v$2 !== _p$.t && (_p$.t = setProp(_el$3, "attributes", _v$2, _p$.t));
|
|
18285
19045
|
return _p$;
|
|
@@ -18330,7 +19090,7 @@ function PaneHeader(props) {
|
|
|
18330
19090
|
}
|
|
18331
19091
|
}), null);
|
|
18332
19092
|
effect((_p$) => {
|
|
18333
|
-
var _v$3 = titleColor(), _v$4 =
|
|
19093
|
+
var _v$3 = titleColor(), _v$4 = TextAttributes13.BOLD;
|
|
18334
19094
|
_v$3 !== _p$.e && (_p$.e = setProp(_el$4, "fg", _v$3, _p$.e));
|
|
18335
19095
|
_v$4 !== _p$.t && (_p$.t = setProp(_el$4, "attributes", _v$4, _p$.t));
|
|
18336
19096
|
return _p$;
|
|
@@ -18455,7 +19215,7 @@ var init_resizable_edge = __esm(() => {
|
|
|
18455
19215
|
});
|
|
18456
19216
|
|
|
18457
19217
|
// src/tui/component/status-bar.tsx
|
|
18458
|
-
import { TextAttributes as
|
|
19218
|
+
import { TextAttributes as TextAttributes14 } from "@opentui/core";
|
|
18459
19219
|
function Hotkey(props) {
|
|
18460
19220
|
const {
|
|
18461
19221
|
theme
|
|
@@ -18474,7 +19234,7 @@ function Hotkey(props) {
|
|
|
18474
19234
|
setProp(_el$5, "wrapMode", "none");
|
|
18475
19235
|
insert(_el$5, () => props.label);
|
|
18476
19236
|
effect((_p$) => {
|
|
18477
|
-
var _v$ = theme.accent, _v$2 =
|
|
19237
|
+
var _v$ = theme.accent, _v$2 = TextAttributes14.BOLD, _v$3 = theme.textMuted;
|
|
18478
19238
|
_v$ !== _p$.e && (_p$.e = setProp(_el$2, "fg", _v$, _p$.e));
|
|
18479
19239
|
_v$2 !== _p$.t && (_p$.t = setProp(_el$2, "attributes", _v$2, _p$.t));
|
|
18480
19240
|
_v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
|
|
@@ -18562,7 +19322,7 @@ function StatusBar() {
|
|
|
18562
19322
|
insertNode(_el$0, createTextNode(`Press Ctrl+C again to exit`));
|
|
18563
19323
|
setProp(_el$0, "wrapMode", "none");
|
|
18564
19324
|
effect((_p$) => {
|
|
18565
|
-
var _v$4 = theme.warning, _v$5 =
|
|
19325
|
+
var _v$4 = theme.warning, _v$5 = TextAttributes14.BOLD;
|
|
18566
19326
|
_v$4 !== _p$.e && (_p$.e = setProp(_el$0, "fg", _v$4, _p$.e));
|
|
18567
19327
|
_v$5 !== _p$.t && (_p$.t = setProp(_el$0, "attributes", _v$5, _p$.t));
|
|
18568
19328
|
return _p$;
|
|
@@ -18574,7 +19334,7 @@ function StatusBar() {
|
|
|
18574
19334
|
}
|
|
18575
19335
|
}), null);
|
|
18576
19336
|
effect((_p$) => {
|
|
18577
|
-
var _v$6 = theme.primary, _v$7 =
|
|
19337
|
+
var _v$6 = theme.primary, _v$7 = TextAttributes14.BOLD;
|
|
18578
19338
|
_v$6 !== _p$.e && (_p$.e = setProp(_el$8, "fg", _v$6, _p$.e));
|
|
18579
19339
|
_v$7 !== _p$.t && (_p$.t = setProp(_el$8, "attributes", _v$7, _p$.t));
|
|
18580
19340
|
return _p$;
|
|
@@ -18604,9 +19364,9 @@ var pulse_default = "../pulse-n3cq1btw.wav";
|
|
|
18604
19364
|
var init_pulse = () => {};
|
|
18605
19365
|
|
|
18606
19366
|
// src/tui/lib/sound.ts
|
|
18607
|
-
import { existsSync as
|
|
19367
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync5 } from "fs";
|
|
18608
19368
|
import { tmpdir as tmpdir2 } from "os";
|
|
18609
|
-
import { basename as basename6, isAbsolute as isAbsolute2, join as
|
|
19369
|
+
import { basename as basename6, isAbsolute as isAbsolute2, join as join12, resolve as resolve7 } from "path";
|
|
18610
19370
|
function args(player, file, volume) {
|
|
18611
19371
|
if (player === "ffplay")
|
|
18612
19372
|
return [player, "-autoexit", "-nodisp", "-af", `volume=${volume}`, file];
|
|
@@ -18629,13 +19389,13 @@ function pickPlayer() {
|
|
|
18629
19389
|
return cachedPlayer;
|
|
18630
19390
|
const path12 = process.env.PATH ?? "";
|
|
18631
19391
|
const segments = path12.split(":").filter(Boolean);
|
|
18632
|
-
cachedPlayer = PLAYERS.find((p) => segments.some((dir) =>
|
|
19392
|
+
cachedPlayer = PLAYERS.find((p) => segments.some((dir) => existsSync13(join12(dir, p)))) ?? null;
|
|
18633
19393
|
return cachedPlayer;
|
|
18634
19394
|
}
|
|
18635
19395
|
async function ensureAsset() {
|
|
18636
19396
|
cachedPath ??= (async () => {
|
|
18637
19397
|
mkdirSync5(DIR, { recursive: true });
|
|
18638
|
-
const dest =
|
|
19398
|
+
const dest = join12(DIR, basename6(pulseAsset));
|
|
18639
19399
|
const out = Bun.file(dest);
|
|
18640
19400
|
if (await out.exists())
|
|
18641
19401
|
return dest;
|
|
@@ -18664,8 +19424,8 @@ function pulse(volume = 0.4) {
|
|
|
18664
19424
|
var pulseAsset, DIR, PLAYERS, cachedPlayer, cachedPath;
|
|
18665
19425
|
var init_sound = __esm(() => {
|
|
18666
19426
|
init_pulse();
|
|
18667
|
-
pulseAsset = isAbsolute2(pulse_default) ? pulse_default :
|
|
18668
|
-
DIR =
|
|
19427
|
+
pulseAsset = isAbsolute2(pulse_default) ? pulse_default : resolve7(import.meta.dir, pulse_default);
|
|
19428
|
+
DIR = join12(tmpdir2(), "kobe-sfx");
|
|
18669
19429
|
PLAYERS = [
|
|
18670
19430
|
"ffplay",
|
|
18671
19431
|
"mpv",
|
|
@@ -18763,7 +19523,7 @@ var init_notifications = __esm(() => {
|
|
|
18763
19523
|
});
|
|
18764
19524
|
|
|
18765
19525
|
// src/tui/component/toast-overlay.tsx
|
|
18766
|
-
import { TextAttributes as
|
|
19526
|
+
import { TextAttributes as TextAttributes15 } from "@opentui/core";
|
|
18767
19527
|
function ToastOverlay() {
|
|
18768
19528
|
const {
|
|
18769
19529
|
theme
|
|
@@ -18806,7 +19566,7 @@ function ToastOverlay() {
|
|
|
18806
19566
|
setProp(_el$4, "wrapMode", "none");
|
|
18807
19567
|
insert(_el$4, () => toast.title);
|
|
18808
19568
|
effect((_p$) => {
|
|
18809
|
-
var _v$3 = bg(), _v$4 = fg(), _v$5 =
|
|
19569
|
+
var _v$3 = bg(), _v$4 = fg(), _v$5 = TextAttributes15.BOLD, _v$6 = fg();
|
|
18810
19570
|
_v$3 !== _p$.e && (_p$.e = setProp(_el$2, "backgroundColor", _v$3, _p$.e));
|
|
18811
19571
|
_v$4 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$4, _p$.t));
|
|
18812
19572
|
_v$5 !== _p$.a && (_p$.a = setProp(_el$3, "attributes", _v$5, _p$.a));
|
|
@@ -18865,8 +19625,8 @@ function repoBasename2(repo) {
|
|
|
18865
19625
|
}
|
|
18866
19626
|
|
|
18867
19627
|
// src/tui/component/top-bar.tsx
|
|
18868
|
-
import { spawnSync as
|
|
18869
|
-
import { TextAttributes as
|
|
19628
|
+
import { spawnSync as spawnSync11 } from "child_process";
|
|
19629
|
+
import { TextAttributes as TextAttributes16 } from "@opentui/core";
|
|
18870
19630
|
function TopBar(props) {
|
|
18871
19631
|
const {
|
|
18872
19632
|
theme
|
|
@@ -18894,7 +19654,7 @@ function TopBar(props) {
|
|
|
18894
19654
|
`);
|
|
18895
19655
|
process.stderr.write(`running: ${UPDATE_COMMAND}
|
|
18896
19656
|
`);
|
|
18897
|
-
const result =
|
|
19657
|
+
const result = spawnSync11("sh", ["-c", UPDATE_COMMAND], {
|
|
18898
19658
|
stdio: "inherit"
|
|
18899
19659
|
});
|
|
18900
19660
|
if (result.error) {
|
|
@@ -18941,7 +19701,7 @@ function TopBar(props) {
|
|
|
18941
19701
|
insertNode(_el$7, createTextNode(`[Update]`));
|
|
18942
19702
|
setProp(_el$7, "onMouseUp", () => void confirmUpdate());
|
|
18943
19703
|
effect((_p$) => {
|
|
18944
|
-
var _v$ = theme.warning, _v$2 =
|
|
19704
|
+
var _v$ = theme.warning, _v$2 = TextAttributes16.BOLD;
|
|
18945
19705
|
_v$ !== _p$.e && (_p$.e = setProp(_el$7, "fg", _v$, _p$.e));
|
|
18946
19706
|
_v$2 !== _p$.t && (_p$.t = setProp(_el$7, "attributes", _v$2, _p$.t));
|
|
18947
19707
|
return _p$;
|
|
@@ -18977,7 +19737,7 @@ function TopBar(props) {
|
|
|
18977
19737
|
insertNode(_el$12, createTextNode(`daemon disconnected`));
|
|
18978
19738
|
setProp(_el$12, "wrapMode", "none");
|
|
18979
19739
|
effect((_p$) => {
|
|
18980
|
-
var _v$6 = theme.error, _v$7 =
|
|
19740
|
+
var _v$6 = theme.error, _v$7 = TextAttributes16.BOLD;
|
|
18981
19741
|
_v$6 !== _p$.e && (_p$.e = setProp(_el$12, "fg", _v$6, _p$.e));
|
|
18982
19742
|
_v$7 !== _p$.t && (_p$.t = setProp(_el$12, "attributes", _v$7, _p$.t));
|
|
18983
19743
|
return _p$;
|
|
@@ -19007,7 +19767,7 @@ function TopBar(props) {
|
|
|
19007
19767
|
setProp(_el$15, "wrapMode", "none");
|
|
19008
19768
|
insert(_el$15, () => label().repoName);
|
|
19009
19769
|
effect((_p$) => {
|
|
19010
|
-
var _v$8 = label().branch ? theme.textMuted : theme.text, _v$9 = label().branch ? undefined :
|
|
19770
|
+
var _v$8 = label().branch ? theme.textMuted : theme.text, _v$9 = label().branch ? undefined : TextAttributes16.BOLD;
|
|
19011
19771
|
_v$8 !== _p$.e && (_p$.e = setProp(_el$15, "fg", _v$8, _p$.e));
|
|
19012
19772
|
_v$9 !== _p$.t && (_p$.t = setProp(_el$15, "attributes", _v$9, _p$.t));
|
|
19013
19773
|
return _p$;
|
|
@@ -19039,7 +19799,7 @@ function TopBar(props) {
|
|
|
19039
19799
|
setProp(_el$18, "wrapMode", "none");
|
|
19040
19800
|
insert(_el$18, () => label().branch);
|
|
19041
19801
|
effect((_p$) => {
|
|
19042
|
-
var _v$0 = theme.text, _v$1 =
|
|
19802
|
+
var _v$0 = theme.text, _v$1 = TextAttributes16.BOLD;
|
|
19043
19803
|
_v$0 !== _p$.e && (_p$.e = setProp(_el$18, "fg", _v$0, _p$.e));
|
|
19044
19804
|
_v$1 !== _p$.t && (_p$.t = setProp(_el$18, "attributes", _v$1, _p$.t));
|
|
19045
19805
|
return _p$;
|
|
@@ -19062,7 +19822,7 @@ function TopBar(props) {
|
|
|
19062
19822
|
setProp(_el$11, "gap", 2);
|
|
19063
19823
|
setProp(_el$11, "justifyContent", "flex-end");
|
|
19064
19824
|
effect((_p$) => {
|
|
19065
|
-
var _v$3 = theme.primary, _v$4 =
|
|
19825
|
+
var _v$3 = theme.primary, _v$4 = TextAttributes16.BOLD, _v$5 = theme.textMuted;
|
|
19066
19826
|
_v$3 !== _p$.e && (_p$.e = setProp(_el$3, "fg", _v$3, _p$.e));
|
|
19067
19827
|
_v$4 !== _p$.t && (_p$.t = setProp(_el$3, "attributes", _v$4, _p$.t));
|
|
19068
19828
|
_v$5 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$5, _p$.a));
|
|
@@ -19606,12 +20366,15 @@ async function launchTaskTmux(opts) {
|
|
|
19606
20366
|
}
|
|
19607
20367
|
}
|
|
19608
20368
|
const name = tmuxSessionName(opts.taskId);
|
|
20369
|
+
const init2 = opts.repo ? resolveRepoInit(opts.repo, cwd) : {};
|
|
19609
20370
|
const ready = await ensureSession({
|
|
19610
20371
|
name,
|
|
19611
20372
|
cwd,
|
|
19612
20373
|
command: opts.command,
|
|
19613
20374
|
taskId: opts.taskId,
|
|
19614
|
-
vendor: opts.vendor
|
|
20375
|
+
vendor: opts.vendor,
|
|
20376
|
+
initScript: init2.initScript,
|
|
20377
|
+
initPrompt: init2.initPrompt
|
|
19615
20378
|
});
|
|
19616
20379
|
if (!ready) {
|
|
19617
20380
|
return {
|
|
@@ -19709,6 +20472,7 @@ var init_fullscreen = __esm(() => {
|
|
|
19709
20472
|
init_solid();
|
|
19710
20473
|
init_solid();
|
|
19711
20474
|
init_dev();
|
|
20475
|
+
init_repo_init();
|
|
19712
20476
|
init_theme2();
|
|
19713
20477
|
init_keymap();
|
|
19714
20478
|
init_dialog();
|
|
@@ -19792,6 +20556,7 @@ function Shell(props) {
|
|
|
19792
20556
|
cwd: task.worktreePath || null,
|
|
19793
20557
|
command: interactiveEngineCommand(task.vendor),
|
|
19794
20558
|
vendor: task.vendor,
|
|
20559
|
+
repo: task.repo,
|
|
19795
20560
|
onEnsureWorktree: (taskId) => props.orchestrator.ensureWorktree(taskId)
|
|
19796
20561
|
});
|
|
19797
20562
|
if (res.kind === "error") {
|
|
@@ -20327,11 +21092,14 @@ var init_tui = __esm(() => {
|
|
|
20327
21092
|
// src/cli/index.ts
|
|
20328
21093
|
init_path_glob();
|
|
20329
21094
|
init_vendor();
|
|
20330
|
-
import { resolve as
|
|
21095
|
+
import { resolve as resolve8 } from "path";
|
|
20331
21096
|
|
|
20332
21097
|
// src/cli/usage.ts
|
|
21098
|
+
init_version();
|
|
20333
21099
|
function topLevelUsage() {
|
|
20334
21100
|
return [
|
|
21101
|
+
`kobe ${CURRENT_VERSION}`,
|
|
21102
|
+
"",
|
|
20335
21103
|
"Usage: kobe [command] [options]",
|
|
20336
21104
|
"",
|
|
20337
21105
|
"Run with no command to launch the TUI.",
|
|
@@ -20339,6 +21107,7 @@ function topLevelUsage() {
|
|
|
20339
21107
|
"Commands:",
|
|
20340
21108
|
" add [path] Save a repo path for the new-task picker",
|
|
20341
21109
|
" adopt [glob] Import existing git worktrees as tasks",
|
|
21110
|
+
" repo <verb> Per-repo init script + first prompt (show|set|unset)",
|
|
20342
21111
|
" api <verb> Scriptable RPC surface for agents (see `kobe api --help`)",
|
|
20343
21112
|
" daemon <verb> Manage the daemon (start|stop|status|restart)",
|
|
20344
21113
|
" theme <verb> Manage user themes (list|add|remove)",
|
|
@@ -20370,7 +21139,7 @@ Usage: kobe add [path]
|
|
|
20370
21139
|
`);
|
|
20371
21140
|
process.exit(2);
|
|
20372
21141
|
}
|
|
20373
|
-
const target =
|
|
21142
|
+
const target = resolve8(process.cwd(), arg && arg.length > 0 ? arg : ".");
|
|
20374
21143
|
const { addSavedRepo: addSavedRepo2 } = await Promise.resolve().then(() => (init_repos(), exports_repos));
|
|
20375
21144
|
const result = addSavedRepo2(target);
|
|
20376
21145
|
if (result.added) {
|
|
@@ -20469,7 +21238,7 @@ async function runAdoptSubcommand(args2) {
|
|
|
20469
21238
|
}
|
|
20470
21239
|
}
|
|
20471
21240
|
const { resolveRepoRoot: resolveRepoRoot2 } = await Promise.resolve().then(() => (init_repos(), exports_repos));
|
|
20472
|
-
const repo = resolveRepoRoot2(
|
|
21241
|
+
const repo = resolveRepoRoot2(resolve8(process.cwd(), repoArg && repoArg.length > 0 ? repoArg : "."));
|
|
20473
21242
|
const vendor = coerceVendorId(vendorArg);
|
|
20474
21243
|
const orch = await openLocalOrchestrator();
|
|
20475
21244
|
const worktrees = await orch.discoverAdoptableWorktrees(repo);
|
|
@@ -20559,6 +21328,11 @@ async function main() {
|
|
|
20559
21328
|
await runAdoptSubcommand(rest);
|
|
20560
21329
|
return;
|
|
20561
21330
|
}
|
|
21331
|
+
if (subcommand === "repo") {
|
|
21332
|
+
const { runRepoSubcommand: runRepoSubcommand2 } = await Promise.resolve().then(() => (init_repo_cmd(), exports_repo_cmd));
|
|
21333
|
+
await runRepoSubcommand2(rest);
|
|
21334
|
+
return;
|
|
21335
|
+
}
|
|
20562
21336
|
if (subcommand === "api") {
|
|
20563
21337
|
const { runApiSubcommand: runApiSubcommand2 } = await Promise.resolve().then(() => (init_api_cmd(), exports_api_cmd));
|
|
20564
21338
|
await runApiSubcommand2(rest);
|
|
@@ -20641,6 +21415,11 @@ async function main() {
|
|
|
20641
21415
|
await startNewTaskHost2({ defaultRepo: flags.repo });
|
|
20642
21416
|
return;
|
|
20643
21417
|
}
|
|
21418
|
+
if (subcommand === "update-page") {
|
|
21419
|
+
const { startUpdateHost: startUpdateHost2 } = await Promise.resolve().then(() => (init_host4(), exports_host4));
|
|
21420
|
+
await startUpdateHost2();
|
|
21421
|
+
return;
|
|
21422
|
+
}
|
|
20644
21423
|
if (subcommand === "ops") {
|
|
20645
21424
|
const flags = parseOpsFlags(rest);
|
|
20646
21425
|
if (!flags.worktree) {
|
|
@@ -20648,11 +21427,11 @@ async function main() {
|
|
|
20648
21427
|
process.exit(2);
|
|
20649
21428
|
}
|
|
20650
21429
|
if (flags.preview) {
|
|
20651
|
-
const { startOpsPreview: startOpsPreview2 } = await Promise.resolve().then(() => (
|
|
21430
|
+
const { startOpsPreview: startOpsPreview2 } = await Promise.resolve().then(() => (init_host5(), exports_host5));
|
|
20652
21431
|
await startOpsPreview2({ worktree: flags.worktree, relPath: flags.preview });
|
|
20653
21432
|
return;
|
|
20654
21433
|
}
|
|
20655
|
-
const { startOpsHost: startOpsHost2 } = await Promise.resolve().then(() => (
|
|
21434
|
+
const { startOpsHost: startOpsHost2 } = await Promise.resolve().then(() => (init_host5(), exports_host5));
|
|
20656
21435
|
await startOpsHost2({
|
|
20657
21436
|
taskId: flags.taskId ?? "",
|
|
20658
21437
|
worktree: flags.worktree,
|