hatchee 0.1.5 → 0.1.6
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.mjs +112 -43
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -3942,16 +3942,24 @@ class SpawnedSession {
|
|
|
3942
3942
|
daemon;
|
|
3943
3943
|
sessionId;
|
|
3944
3944
|
cwd;
|
|
3945
|
+
model;
|
|
3945
3946
|
claudeBin;
|
|
3946
3947
|
proc = null;
|
|
3947
|
-
|
|
3948
|
-
|
|
3948
|
+
mode = "edits";
|
|
3949
|
+
claudeSessionId = null;
|
|
3950
|
+
stopped = false;
|
|
3951
|
+
constructor(daemon, sessionId, cwd, model = null, claudeBin = process.env.DROVER_CLAUDE_BIN || "claude") {
|
|
3949
3952
|
this.daemon = daemon;
|
|
3950
3953
|
this.sessionId = sessionId;
|
|
3951
3954
|
this.cwd = cwd;
|
|
3955
|
+
this.model = model;
|
|
3952
3956
|
this.claudeBin = claudeBin;
|
|
3953
3957
|
}
|
|
3954
3958
|
start(firstTask, mode = "edits") {
|
|
3959
|
+
this.mode = mode;
|
|
3960
|
+
this.spawnProc(firstTask);
|
|
3961
|
+
}
|
|
3962
|
+
spawnProc(firstMessage) {
|
|
3955
3963
|
const args = [
|
|
3956
3964
|
"--print",
|
|
3957
3965
|
"--output-format",
|
|
@@ -3960,7 +3968,9 @@ class SpawnedSession {
|
|
|
3960
3968
|
"stream-json",
|
|
3961
3969
|
"--verbose",
|
|
3962
3970
|
"--permission-mode",
|
|
3963
|
-
PERMISSION_MODE[mode] ?? "acceptEdits"
|
|
3971
|
+
PERMISSION_MODE[this.mode] ?? "acceptEdits",
|
|
3972
|
+
...this.model ? ["--model", this.model] : [],
|
|
3973
|
+
...this.claudeSessionId ? ["--resume", this.claudeSessionId] : []
|
|
3964
3974
|
];
|
|
3965
3975
|
let proc;
|
|
3966
3976
|
try {
|
|
@@ -3976,22 +3986,28 @@ class SpawnedSession {
|
|
|
3976
3986
|
if (s)
|
|
3977
3987
|
this.daemon.spawnLine(this.sessionId, s, "muted");
|
|
3978
3988
|
});
|
|
3979
|
-
proc.on("exit", (code) =>
|
|
3980
|
-
this.daemon.spawnExit(this.sessionId, code ?? 0);
|
|
3981
|
-
this.proc = null;
|
|
3982
|
-
});
|
|
3989
|
+
proc.on("exit", (code) => this.onProcExit(code ?? 0));
|
|
3983
3990
|
proc.on("error", (e) => this.daemon.spawnFailed(this.sessionId, String(e)));
|
|
3984
|
-
if (
|
|
3985
|
-
this.send(
|
|
3991
|
+
if (firstMessage.trim())
|
|
3992
|
+
this.send(firstMessage);
|
|
3986
3993
|
}
|
|
3987
3994
|
send(text) {
|
|
3988
|
-
if (
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
this.proc.stdin.write(JSON.stringify(msg) + `
|
|
3995
|
+
if (this.proc?.stdin.writable) {
|
|
3996
|
+
const msg = { type: "user", message: { role: "user", content: text } };
|
|
3997
|
+
this.proc.stdin.write(JSON.stringify(msg) + `
|
|
3992
3998
|
`);
|
|
3999
|
+
} else {
|
|
4000
|
+
this.spawnProc(text);
|
|
4001
|
+
}
|
|
4002
|
+
}
|
|
4003
|
+
onProcExit(_code) {
|
|
4004
|
+
this.proc = null;
|
|
4005
|
+
if (this.stopped)
|
|
4006
|
+
return;
|
|
4007
|
+
this.daemon.spawnState(this.sessionId, "waiting", "ready — send your next message");
|
|
3993
4008
|
}
|
|
3994
4009
|
stop() {
|
|
4010
|
+
this.stopped = true;
|
|
3995
4011
|
try {
|
|
3996
4012
|
this.proc?.stdin.end();
|
|
3997
4013
|
} catch {}
|
|
@@ -4009,8 +4025,11 @@ class SpawnedSession {
|
|
|
4009
4025
|
}
|
|
4010
4026
|
switch (m.type) {
|
|
4011
4027
|
case "system":
|
|
4012
|
-
if (m.subtype === "init")
|
|
4028
|
+
if (m.subtype === "init") {
|
|
4029
|
+
if (typeof m.session_id === "string")
|
|
4030
|
+
this.claudeSessionId = m.session_id;
|
|
4013
4031
|
this.daemon.spawnState(this.sessionId, "working", "session ready");
|
|
4032
|
+
}
|
|
4014
4033
|
break;
|
|
4015
4034
|
case "assistant": {
|
|
4016
4035
|
for (const block of m.message?.content ?? []) {
|
|
@@ -7263,6 +7282,9 @@ function lanIPv4() {
|
|
|
7263
7282
|
|
|
7264
7283
|
// src/server.ts
|
|
7265
7284
|
import { createServer } from "node:http";
|
|
7285
|
+
import { readdirSync, statSync, existsSync as existsSync2 } from "node:fs";
|
|
7286
|
+
import { homedir as homedir2 } from "node:os";
|
|
7287
|
+
import { join as join2, basename } from "node:path";
|
|
7266
7288
|
|
|
7267
7289
|
// ../../node_modules/ws/wrapper.mjs
|
|
7268
7290
|
var import_stream = __toESM(require_stream(), 1);
|
|
@@ -11343,6 +11365,11 @@ var RulesUpdate = exports_external.object({
|
|
|
11343
11365
|
t: exports_external.literal("rules"),
|
|
11344
11366
|
rules: exports_external.array(Rule)
|
|
11345
11367
|
});
|
|
11368
|
+
var DirEntry = exports_external.object({ path: exports_external.string(), name: exports_external.string(), git: exports_external.boolean().default(false) });
|
|
11369
|
+
var DirsUpdate = exports_external.object({
|
|
11370
|
+
t: exports_external.literal("dirs"),
|
|
11371
|
+
dirs: exports_external.array(DirEntry)
|
|
11372
|
+
});
|
|
11346
11373
|
var DaemonToPhone = exports_external.discriminatedUnion("t", [
|
|
11347
11374
|
ServerHello,
|
|
11348
11375
|
SessionUpsert,
|
|
@@ -11353,6 +11380,7 @@ var DaemonToPhone = exports_external.discriminatedUnion("t", [
|
|
|
11353
11380
|
ErrorMsg,
|
|
11354
11381
|
Pong,
|
|
11355
11382
|
RulesUpdate,
|
|
11383
|
+
DirsUpdate,
|
|
11356
11384
|
Encrypted
|
|
11357
11385
|
]);
|
|
11358
11386
|
var DaemonInner = exports_external.discriminatedUnion("t", [
|
|
@@ -11363,7 +11391,8 @@ var DaemonInner = exports_external.discriminatedUnion("t", [
|
|
|
11363
11391
|
PermissionResolved,
|
|
11364
11392
|
ErrorMsg,
|
|
11365
11393
|
Pong,
|
|
11366
|
-
RulesUpdate
|
|
11394
|
+
RulesUpdate,
|
|
11395
|
+
DirsUpdate
|
|
11367
11396
|
]);
|
|
11368
11397
|
var ClientHello = exports_external.object({
|
|
11369
11398
|
t: exports_external.literal("hello"),
|
|
@@ -11392,12 +11421,14 @@ var Spawn = exports_external.object({
|
|
|
11392
11421
|
t: exports_external.literal("spawn"),
|
|
11393
11422
|
task: exports_external.string().default(""),
|
|
11394
11423
|
cwd: exports_external.string().nullable().default(null),
|
|
11395
|
-
mode: SpawnMode.default("edits")
|
|
11424
|
+
mode: SpawnMode.default("edits"),
|
|
11425
|
+
model: exports_external.string().nullable().default(null)
|
|
11396
11426
|
});
|
|
11397
11427
|
var Stop = exports_external.object({
|
|
11398
11428
|
t: exports_external.literal("stop"),
|
|
11399
11429
|
sessionId: exports_external.string()
|
|
11400
11430
|
});
|
|
11431
|
+
var ListDirs = exports_external.object({ t: exports_external.literal("list_dirs") });
|
|
11401
11432
|
var Ping = exports_external.object({ t: exports_external.literal("ping") });
|
|
11402
11433
|
var PushRegister = exports_external.object({
|
|
11403
11434
|
t: exports_external.literal("push_register"),
|
|
@@ -11412,6 +11443,7 @@ var PhoneToDaemon = exports_external.discriminatedUnion("t", [
|
|
|
11412
11443
|
UserMessage,
|
|
11413
11444
|
Spawn,
|
|
11414
11445
|
Stop,
|
|
11446
|
+
ListDirs,
|
|
11415
11447
|
Ping,
|
|
11416
11448
|
PushRegister,
|
|
11417
11449
|
Encrypted
|
|
@@ -11422,6 +11454,7 @@ var PhoneInner = exports_external.discriminatedUnion("t", [
|
|
|
11422
11454
|
UserMessage,
|
|
11423
11455
|
Spawn,
|
|
11424
11456
|
Stop,
|
|
11457
|
+
ListDirs,
|
|
11425
11458
|
Ping,
|
|
11426
11459
|
PushRegister
|
|
11427
11460
|
]);
|
|
@@ -11579,7 +11612,7 @@ class Daemon {
|
|
|
11579
11612
|
relayLeave(conn) {
|
|
11580
11613
|
this.phones.delete(conn);
|
|
11581
11614
|
}
|
|
11582
|
-
async spawnSession(task, cwd, mode = "edits") {
|
|
11615
|
+
async spawnSession(task, cwd, mode = "edits", model = null) {
|
|
11583
11616
|
const { SpawnedSession: SpawnedSession2 } = await Promise.resolve().then(() => (init_spawn(), exports_spawn));
|
|
11584
11617
|
const id = `spawn-${crypto.randomUUID()}`;
|
|
11585
11618
|
const dir = cwd || this.defaultCwd;
|
|
@@ -11597,10 +11630,43 @@ class Daemon {
|
|
|
11597
11630
|
this.registry.appendLine(id, { text: `❯ ${task}`, color: "me" });
|
|
11598
11631
|
this.broadcast({ t: "line", sessionId: id, line: { text: `❯ ${task}`, color: "me" } });
|
|
11599
11632
|
}
|
|
11600
|
-
const session = new SpawnedSession2(this, id, dir);
|
|
11633
|
+
const session = new SpawnedSession2(this, id, dir, model);
|
|
11601
11634
|
this.spawned.set(id, session);
|
|
11602
11635
|
session.start(task, mode);
|
|
11603
11636
|
}
|
|
11637
|
+
listProjectDirs() {
|
|
11638
|
+
const home = homedir2();
|
|
11639
|
+
const roots = [home, ...["Projects", "code", "dev", "src", "repos", "Developer", "work"].map((d) => join2(home, d))];
|
|
11640
|
+
const out = new Map;
|
|
11641
|
+
const add2 = (p) => {
|
|
11642
|
+
if (out.has(p))
|
|
11643
|
+
return;
|
|
11644
|
+
out.set(p, { path: p, name: basename(p) || p, git: existsSync2(join2(p, ".git")) });
|
|
11645
|
+
};
|
|
11646
|
+
add2(this.defaultCwd);
|
|
11647
|
+
for (const root of roots) {
|
|
11648
|
+
let entries = [];
|
|
11649
|
+
try {
|
|
11650
|
+
entries = readdirSync(root);
|
|
11651
|
+
} catch {
|
|
11652
|
+
continue;
|
|
11653
|
+
}
|
|
11654
|
+
for (const e of entries) {
|
|
11655
|
+
if (e.startsWith(".") || out.size > 80)
|
|
11656
|
+
continue;
|
|
11657
|
+
const p = join2(root, e);
|
|
11658
|
+
try {
|
|
11659
|
+
if (!statSync(p).isDirectory())
|
|
11660
|
+
continue;
|
|
11661
|
+
} catch {
|
|
11662
|
+
continue;
|
|
11663
|
+
}
|
|
11664
|
+
if (root !== home || existsSync2(join2(p, ".git")))
|
|
11665
|
+
add2(p);
|
|
11666
|
+
}
|
|
11667
|
+
}
|
|
11668
|
+
return [...out.values()].sort((a, b) => Number(b.git) - Number(a.git) || a.name.localeCompare(b.name)).slice(0, 50);
|
|
11669
|
+
}
|
|
11604
11670
|
spawnLine(sessionId, text, color) {
|
|
11605
11671
|
this.registry.appendLine(sessionId, { text, color });
|
|
11606
11672
|
this.broadcast({ t: "line", sessionId, line: { text, color } });
|
|
@@ -11777,9 +11843,12 @@ class Daemon {
|
|
|
11777
11843
|
break;
|
|
11778
11844
|
}
|
|
11779
11845
|
case "spawn": {
|
|
11780
|
-
this.spawnSession(msg.task ?? "", msg.cwd ?? null, msg.mode ?? "edits");
|
|
11846
|
+
this.spawnSession(msg.task ?? "", msg.cwd ?? null, msg.mode ?? "edits", msg.model ?? null);
|
|
11781
11847
|
break;
|
|
11782
11848
|
}
|
|
11849
|
+
case "list_dirs":
|
|
11850
|
+
this.sendTo(p, { t: "dirs", dirs: this.listProjectDirs() });
|
|
11851
|
+
break;
|
|
11783
11852
|
case "stop": {
|
|
11784
11853
|
const owned = this.spawned.get(msg.sessionId);
|
|
11785
11854
|
if (owned) {
|
|
@@ -12108,16 +12177,16 @@ function b64url2(bytes) {
|
|
|
12108
12177
|
}
|
|
12109
12178
|
|
|
12110
12179
|
// src/hooks.ts
|
|
12111
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as
|
|
12112
|
-
import { homedir as
|
|
12113
|
-
import { join as
|
|
12114
|
-
var claudeDir = () => process.env.CLAUDE_CONFIG_DIR ||
|
|
12115
|
-
var settingsPath = () =>
|
|
12180
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "node:fs";
|
|
12181
|
+
import { homedir as homedir3 } from "node:os";
|
|
12182
|
+
import { join as join3 } from "node:path";
|
|
12183
|
+
var claudeDir = () => process.env.CLAUDE_CONFIG_DIR || join3(homedir3(), ".claude");
|
|
12184
|
+
var settingsPath = () => join3(claudeDir(), "settings.json");
|
|
12116
12185
|
var EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "Notification", "Stop"];
|
|
12117
12186
|
function installHooks(droverBin) {
|
|
12118
12187
|
mkdirSync2(claudeDir(), { recursive: true });
|
|
12119
12188
|
let settings = {};
|
|
12120
|
-
if (
|
|
12189
|
+
if (existsSync3(settingsPath())) {
|
|
12121
12190
|
try {
|
|
12122
12191
|
settings = JSON.parse(readFileSync2(settingsPath(), "utf8"));
|
|
12123
12192
|
} catch {
|
|
@@ -12154,7 +12223,7 @@ function isOurs(x) {
|
|
|
12154
12223
|
return cmd.includes("hatchee") || cmd.includes("drover") || cmd.includes("daemon/src/cli.ts");
|
|
12155
12224
|
}
|
|
12156
12225
|
function uninstallHooks() {
|
|
12157
|
-
if (!
|
|
12226
|
+
if (!existsSync3(settingsPath()))
|
|
12158
12227
|
return;
|
|
12159
12228
|
try {
|
|
12160
12229
|
const settings = JSON.parse(readFileSync2(settingsPath(), "utf8"));
|
|
@@ -12219,27 +12288,27 @@ async function runHook(hookPort) {
|
|
|
12219
12288
|
}
|
|
12220
12289
|
|
|
12221
12290
|
// src/service.ts
|
|
12222
|
-
import { homedir as
|
|
12223
|
-
import { join as
|
|
12224
|
-
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, copyFileSync, chmodSync, existsSync as
|
|
12291
|
+
import { homedir as homedir4 } from "node:os";
|
|
12292
|
+
import { join as join4, dirname } from "node:path";
|
|
12293
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, copyFileSync, chmodSync, existsSync as existsSync4, rmSync } from "node:fs";
|
|
12225
12294
|
import { execFileSync } from "node:child_process";
|
|
12226
|
-
var HOME =
|
|
12227
|
-
var HATCHEE_DIR =
|
|
12228
|
-
var BIN_DIR =
|
|
12229
|
-
var STABLE_BIN =
|
|
12230
|
-
var LOG =
|
|
12295
|
+
var HOME = homedir4();
|
|
12296
|
+
var HATCHEE_DIR = join4(HOME, ".hatchee");
|
|
12297
|
+
var BIN_DIR = join4(HATCHEE_DIR, "bin");
|
|
12298
|
+
var STABLE_BIN = join4(BIN_DIR, "hatchee.mjs");
|
|
12299
|
+
var LOG = join4(HATCHEE_DIR, "daemon.log");
|
|
12231
12300
|
var LABEL = "cloud.hatchee.daemon";
|
|
12232
|
-
var PLIST =
|
|
12233
|
-
var UNIT =
|
|
12301
|
+
var PLIST = join4(HOME, "Library", "LaunchAgents", `${LABEL}.plist`);
|
|
12302
|
+
var UNIT = join4(HOME, ".config", "systemd", "user", "hatchee.service");
|
|
12234
12303
|
function servicePath(node) {
|
|
12235
12304
|
const system = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
|
|
12236
12305
|
const userTool = [
|
|
12237
12306
|
dirname(node),
|
|
12238
12307
|
"/opt/homebrew/bin",
|
|
12239
12308
|
"/usr/local/bin",
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12309
|
+
join4(HOME, ".bun/bin"),
|
|
12310
|
+
join4(HOME, ".npm-global/bin"),
|
|
12311
|
+
join4(HOME, ".local/bin")
|
|
12243
12312
|
];
|
|
12244
12313
|
const seen = new Set;
|
|
12245
12314
|
return [...system, ...userTool].filter((p) => p && !seen.has(p) && seen.add(p)).join(":");
|
|
@@ -12390,12 +12459,12 @@ function uninstallService() {
|
|
|
12390
12459
|
if (process.platform === "darwin") {
|
|
12391
12460
|
const uid = String(process.getuid?.() ?? "");
|
|
12392
12461
|
run("launchctl", ["bootout", `gui/${uid}/${LABEL}`]);
|
|
12393
|
-
if (
|
|
12462
|
+
if (existsSync4(PLIST))
|
|
12394
12463
|
rmSync(PLIST);
|
|
12395
12464
|
console.log(` ✓ background service removed (launchd: ${LABEL})`);
|
|
12396
12465
|
} else if (process.platform === "linux") {
|
|
12397
12466
|
run("systemctl", ["--user", "disable", "--now", "hatchee.service"]);
|
|
12398
|
-
if (
|
|
12467
|
+
if (existsSync4(UNIT)) {
|
|
12399
12468
|
rmSync(UNIT);
|
|
12400
12469
|
run("systemctl", ["--user", "daemon-reload"]);
|
|
12401
12470
|
}
|
|
@@ -12403,12 +12472,12 @@ function uninstallService() {
|
|
|
12403
12472
|
} else {
|
|
12404
12473
|
console.log(` no background service on ${process.platform}.`);
|
|
12405
12474
|
}
|
|
12406
|
-
if (
|
|
12475
|
+
if (existsSync4(STABLE_BIN))
|
|
12407
12476
|
rmSync(STABLE_BIN);
|
|
12408
12477
|
}
|
|
12409
12478
|
|
|
12410
12479
|
// src/cli.ts
|
|
12411
|
-
var VERSION2 = "0.1.
|
|
12480
|
+
var VERSION2 = "0.1.6";
|
|
12412
12481
|
var cmd = process.argv[2] ?? "help";
|
|
12413
12482
|
switch (cmd) {
|
|
12414
12483
|
case "up": {
|
package/package.json
CHANGED