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