slopwaresystems 0.4.16 → 0.4.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +207 -379
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19054,12 +19054,12 @@ function processSchema(schema, ctx, _params = { path: [], schemaPath: [] }) {
|
|
|
19054
19054
|
}
|
|
19055
19055
|
processor(schema, ctx, _json, params);
|
|
19056
19056
|
}
|
|
19057
|
-
const
|
|
19058
|
-
if (
|
|
19057
|
+
const parent = schema._zod.parent;
|
|
19058
|
+
if (parent) {
|
|
19059
19059
|
if (!result.ref)
|
|
19060
|
-
result.ref =
|
|
19061
|
-
processSchema(
|
|
19062
|
-
ctx.seen.get(
|
|
19060
|
+
result.ref = parent;
|
|
19061
|
+
processSchema(parent, ctx, params);
|
|
19062
|
+
ctx.seen.get(parent).isParent = true;
|
|
19063
19063
|
}
|
|
19064
19064
|
}
|
|
19065
19065
|
const meta3 = ctx.metadataRegistry.get(schema);
|
|
@@ -19322,10 +19322,10 @@ function finalize(ctx, schema) {
|
|
|
19322
19322
|
}
|
|
19323
19323
|
}
|
|
19324
19324
|
}
|
|
19325
|
-
const
|
|
19326
|
-
if (
|
|
19327
|
-
flattenRef(
|
|
19328
|
-
const parentSeen = ctx.seen.get(
|
|
19325
|
+
const parent = zodSchema._zod.parent;
|
|
19326
|
+
if (parent && parent !== ref) {
|
|
19327
|
+
flattenRef(parent);
|
|
19328
|
+
const parentSeen = ctx.seen.get(parent);
|
|
19329
19329
|
if (parentSeen?.schema.$ref) {
|
|
19330
19330
|
schema2.$ref = parentSeen.schema.$ref;
|
|
19331
19331
|
if (parentSeen.def) {
|
|
@@ -26852,16 +26852,16 @@ function generateAgentName(key) {
|
|
|
26852
26852
|
return AGENT_NAMES[hashKey(key) % AGENT_NAMES.length] ?? AGENT_NAMES[0];
|
|
26853
26853
|
}
|
|
26854
26854
|
var WORKER_TITLES = [
|
|
26855
|
-
(
|
|
26856
|
-
(
|
|
26857
|
-
(
|
|
26858
|
-
(
|
|
26859
|
-
(
|
|
26860
|
-
(
|
|
26861
|
-
(
|
|
26862
|
-
(
|
|
26863
|
-
(
|
|
26864
|
-
(
|
|
26855
|
+
(parent) => `${parent} Jr.`,
|
|
26856
|
+
(parent) => `${parent} II`,
|
|
26857
|
+
(parent) => `${parent} III`,
|
|
26858
|
+
(parent) => `${parent} the Second`,
|
|
26859
|
+
(parent) => `${parent} the Younger`,
|
|
26860
|
+
(parent) => `${parent} the Lesser`,
|
|
26861
|
+
(parent) => `${parent}, Deputised`,
|
|
26862
|
+
(parent) => `Young ${parent}`,
|
|
26863
|
+
(parent) => `Little ${parent}`,
|
|
26864
|
+
(parent) => `Second-Best ${parent}`
|
|
26865
26865
|
];
|
|
26866
26866
|
var CARRIED_ON = /(,? (?:Jr\.|Sr\.|II|III|IV|Prime|Junior|Minor|Deputised|the (?:Second|Third|Younger|Lesser)))+$/;
|
|
26867
26867
|
function generateWorkerName(parentName, ref) {
|
|
@@ -27079,8 +27079,56 @@ function resolveSession() {
|
|
|
27079
27079
|
|
|
27080
27080
|
// src/platform/session-file.ts
|
|
27081
27081
|
import { createHash as createHash2 } from "crypto";
|
|
27082
|
-
import { readFileSync as
|
|
27082
|
+
import { readFileSync as readFileSync4, realpathSync as realpathSync2, rmSync as rmSync3, statSync, readdirSync } from "fs";
|
|
27083
27083
|
import { dirname as dirname3, join as join3 } from "path";
|
|
27084
|
+
|
|
27085
|
+
// src/platform/process-tree.ts
|
|
27086
|
+
import { execFileSync } from "child_process";
|
|
27087
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
27088
|
+
var runPs = (args) => execFileSync("ps", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 2e3 });
|
|
27089
|
+
var isPid = (pid) => Number.isSafeInteger(pid) && pid > 0;
|
|
27090
|
+
function fetchProcessCommand(pid) {
|
|
27091
|
+
if (process.platform === "win32" || !isPid(pid)) return "";
|
|
27092
|
+
try {
|
|
27093
|
+
if (process.platform === "linux") return readFileSync3(`/proc/${pid}/cmdline`, "latin1").replace(/\0/g, " ").trim();
|
|
27094
|
+
return runPs(["-o", "command=", "-p", String(pid)]).trim();
|
|
27095
|
+
} catch {
|
|
27096
|
+
return "";
|
|
27097
|
+
}
|
|
27098
|
+
}
|
|
27099
|
+
function fetchParentPid(pid) {
|
|
27100
|
+
if (process.platform === "win32" || !isPid(pid) || pid === 1) return null;
|
|
27101
|
+
try {
|
|
27102
|
+
let text;
|
|
27103
|
+
if (process.platform === "linux") {
|
|
27104
|
+
const stat = readFileSync3(`/proc/${pid}/stat`, "utf8");
|
|
27105
|
+
text = stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1] ?? "";
|
|
27106
|
+
} else text = runPs(["-o", "ppid=", "-p", String(pid)]);
|
|
27107
|
+
const parent = Number(text.trim());
|
|
27108
|
+
return isPid(parent) ? parent : null;
|
|
27109
|
+
} catch {
|
|
27110
|
+
return null;
|
|
27111
|
+
}
|
|
27112
|
+
}
|
|
27113
|
+
function fetchProcessStart(pid) {
|
|
27114
|
+
if (process.platform === "win32" || !isPid(pid)) return null;
|
|
27115
|
+
try {
|
|
27116
|
+
return execFileSync("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8", env: { ...process.env, LC_ALL: "C", TZ: "UTC" }, stdio: ["ignore", "pipe", "ignore"], timeout: 1e3 }).trim() || null;
|
|
27117
|
+
} catch {
|
|
27118
|
+
return null;
|
|
27119
|
+
}
|
|
27120
|
+
}
|
|
27121
|
+
function isProcessAlive(pid) {
|
|
27122
|
+
if (!isPid(pid)) return false;
|
|
27123
|
+
try {
|
|
27124
|
+
process.kill(pid, 0);
|
|
27125
|
+
return true;
|
|
27126
|
+
} catch (error62) {
|
|
27127
|
+
return error62.code === "EPERM";
|
|
27128
|
+
}
|
|
27129
|
+
}
|
|
27130
|
+
|
|
27131
|
+
// src/platform/session-file.ts
|
|
27084
27132
|
var buildSessionsDir = () => join3(dirname3(buildConfigPath()), "sessions");
|
|
27085
27133
|
var resolveRealCwd = (cwd) => {
|
|
27086
27134
|
try {
|
|
@@ -27096,21 +27144,13 @@ function persistRememberedSession(cwd, sessionId, conversation) {
|
|
|
27096
27144
|
}
|
|
27097
27145
|
function fetchRememberedSession(cwd, conversation) {
|
|
27098
27146
|
try {
|
|
27099
|
-
return
|
|
27147
|
+
return readFileSync4(buildSessionPath(cwd, conversation), "utf8").trim() || null;
|
|
27100
27148
|
} catch (error62) {
|
|
27101
27149
|
if (error62.code === "ENOENT") return null;
|
|
27102
27150
|
throw error62;
|
|
27103
27151
|
}
|
|
27104
27152
|
}
|
|
27105
27153
|
var buildHolderPath = (cwd, conversation) => join3(buildSessionsDir(), `${generateLocalStateKey(cwd, conversation)}.holder.json`);
|
|
27106
|
-
var isProcessAlive = (pid) => {
|
|
27107
|
-
try {
|
|
27108
|
-
process.kill(pid, 0);
|
|
27109
|
-
return true;
|
|
27110
|
-
} catch (error62) {
|
|
27111
|
-
return error62.code === "EPERM";
|
|
27112
|
-
}
|
|
27113
|
-
};
|
|
27114
27154
|
function claimSessionHolder(cwd, conversation, pid = process.pid) {
|
|
27115
27155
|
const path2 = buildHolderPath(cwd, conversation);
|
|
27116
27156
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
@@ -27121,7 +27161,7 @@ function claimSessionHolder(cwd, conversation, pid = process.pid) {
|
|
|
27121
27161
|
}
|
|
27122
27162
|
let holder = null;
|
|
27123
27163
|
try {
|
|
27124
|
-
holder = JSON.parse(
|
|
27164
|
+
holder = JSON.parse(readFileSync4(path2, "utf8"));
|
|
27125
27165
|
} catch {
|
|
27126
27166
|
return false;
|
|
27127
27167
|
}
|
|
@@ -27134,7 +27174,7 @@ function claimSessionHolder(cwd, conversation, pid = process.pid) {
|
|
|
27134
27174
|
function releaseSessionHolder(cwd, conversation, pid = process.pid) {
|
|
27135
27175
|
const path2 = buildHolderPath(cwd, conversation);
|
|
27136
27176
|
try {
|
|
27137
|
-
const holder = JSON.parse(
|
|
27177
|
+
const holder = JSON.parse(readFileSync4(path2, "utf8"));
|
|
27138
27178
|
if (holder?.pid === pid) rmSync3(path2, { force: true });
|
|
27139
27179
|
} catch {
|
|
27140
27180
|
}
|
|
@@ -27157,7 +27197,7 @@ function fetchRememberedConversation(cwd, notBefore, harness) {
|
|
|
27157
27197
|
if (candidate.endsWith(".writing")) continue;
|
|
27158
27198
|
try {
|
|
27159
27199
|
if (statSync(candidate).mtimeMs < notBefore) continue;
|
|
27160
|
-
const parsed = JSON.parse(
|
|
27200
|
+
const parsed = JSON.parse(readFileSync4(candidate, "utf8"));
|
|
27161
27201
|
const wrote = AgentHarness.safeParse(parsed.harness ?? "other");
|
|
27162
27202
|
if (typeof parsed.id === "string" && parsed.id && wrote.success) candidates.push({ id: parsed.id, harness: wrote.data });
|
|
27163
27203
|
} catch {
|
|
@@ -27173,9 +27213,9 @@ import { randomUUID as randomUUID4 } from "crypto";
|
|
|
27173
27213
|
import { basename as basename3, join as join8, resolve as resolve4 } from "path";
|
|
27174
27214
|
|
|
27175
27215
|
// src/platform/git.ts
|
|
27176
|
-
import { execFileSync } from "child_process";
|
|
27216
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
27177
27217
|
import { createHash as createHash3, randomUUID as randomUUID2 } from "crypto";
|
|
27178
|
-
import { existsSync as existsSync3, readFileSync as
|
|
27218
|
+
import { existsSync as existsSync3, readFileSync as readFileSync5, rmSync as rmSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
27179
27219
|
import { basename, join as join4, resolve as resolve2 } from "path";
|
|
27180
27220
|
|
|
27181
27221
|
// src/platform/errors.ts
|
|
@@ -27194,7 +27234,7 @@ var CliError = class extends Error {
|
|
|
27194
27234
|
// src/platform/git.ts
|
|
27195
27235
|
function runGit(args, cwd = process.cwd()) {
|
|
27196
27236
|
try {
|
|
27197
|
-
return
|
|
27237
|
+
return execFileSync2("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
27198
27238
|
} catch {
|
|
27199
27239
|
return null;
|
|
27200
27240
|
}
|
|
@@ -27217,7 +27257,7 @@ function requireRepo() {
|
|
|
27217
27257
|
}
|
|
27218
27258
|
function fetchRepoLink(repo) {
|
|
27219
27259
|
try {
|
|
27220
|
-
return JSON.parse(
|
|
27260
|
+
return JSON.parse(readFileSync5(repo.linkPath, "utf8"));
|
|
27221
27261
|
} catch {
|
|
27222
27262
|
return null;
|
|
27223
27263
|
}
|
|
@@ -27253,20 +27293,20 @@ function buildRepoDescription(repo, existing) {
|
|
|
27253
27293
|
}
|
|
27254
27294
|
|
|
27255
27295
|
// src/platform/harness.ts
|
|
27256
|
-
import { execFileSync as
|
|
27296
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
27257
27297
|
import { closeSync, openSync, readdirSync as readdirSync3, readSync, readlinkSync, realpathSync as realpathSync3, statSync as statSync3 } from "fs";
|
|
27258
27298
|
import { basename as basename2, join as join7 } from "path";
|
|
27259
27299
|
|
|
27260
27300
|
// src/platform/harness-wake.ts
|
|
27261
|
-
import { existsSync as existsSync5, readFileSync as
|
|
27301
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
|
|
27262
27302
|
import { join as join6 } from "path";
|
|
27263
27303
|
import { connect } from "net";
|
|
27264
27304
|
import { spawn } from "child_process";
|
|
27265
27305
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
27266
27306
|
|
|
27267
27307
|
// src/platform/homes.ts
|
|
27268
|
-
import { execFileSync as
|
|
27269
|
-
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as
|
|
27308
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
27309
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
|
|
27270
27310
|
import { homedir as homedir3 } from "os";
|
|
27271
27311
|
import { join as join5, resolve as resolve3 } from "path";
|
|
27272
27312
|
var deduplicateStrings = (paths) => [...new Set(paths.map((path2) => resolve3(path2)))];
|
|
@@ -27277,26 +27317,26 @@ function fetchAncestorEnvironments() {
|
|
|
27277
27317
|
if (process.platform === "linux") {
|
|
27278
27318
|
let pid2 = process.ppid;
|
|
27279
27319
|
for (let hop = 0; hop < 6 && pid2 > 1; hop += 1) {
|
|
27280
|
-
seen.push(
|
|
27281
|
-
const stat =
|
|
27320
|
+
seen.push(readFileSync6(`/proc/${pid2}/environ`, "latin1").replace(/\0/g, " "));
|
|
27321
|
+
const stat = readFileSync6(`/proc/${pid2}/stat`, "utf8");
|
|
27282
27322
|
pid2 = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1]);
|
|
27283
27323
|
}
|
|
27284
27324
|
for (const entry of readdirSync2("/proc")) {
|
|
27285
27325
|
if (!/^\d+$/.test(entry)) continue;
|
|
27286
27326
|
try {
|
|
27287
|
-
seen.push(
|
|
27327
|
+
seen.push(readFileSync6(`/proc/${entry}/environ`, "latin1").replace(/\0/g, " "));
|
|
27288
27328
|
} catch {
|
|
27289
27329
|
}
|
|
27290
27330
|
}
|
|
27291
27331
|
return seen;
|
|
27292
27332
|
}
|
|
27293
|
-
const
|
|
27333
|
+
const runPs2 = (args) => execFileSync3("ps", args, { encoding: "utf8", maxBuffer: 64 << 20, stdio: ["ignore", "pipe", "ignore"] });
|
|
27294
27334
|
let pid = process.ppid;
|
|
27295
27335
|
for (let hop = 0; hop < 6 && pid > 1; hop += 1) {
|
|
27296
|
-
seen.push(
|
|
27297
|
-
pid = Number(
|
|
27336
|
+
seen.push(runPs2(["eww", "-o", "command=", "-p", String(pid)]));
|
|
27337
|
+
pid = Number(runPs2(["-o", "ppid=", "-p", String(pid)]).trim());
|
|
27298
27338
|
}
|
|
27299
|
-
seen.push(
|
|
27339
|
+
seen.push(runPs2(["axeww", "-o", "command="]));
|
|
27300
27340
|
} catch {
|
|
27301
27341
|
}
|
|
27302
27342
|
return seen;
|
|
@@ -27333,22 +27373,18 @@ function fetchCodexHomes(root = homedir3(), inUse = findHomesInUse) {
|
|
|
27333
27373
|
const named = process.env.CODEX_HOME ? [process.env.CODEX_HOME] : [];
|
|
27334
27374
|
return deduplicateStrings([join5(root, ".codex"), ...named, ...inUse("CODEX_HOME"), ...findDirectoriesNamed(root, ".codex").filter((dir) => hasAnyEntry(dir, ["config.toml", "auth.json", "sessions"]))]);
|
|
27335
27375
|
}
|
|
27336
|
-
function fetchCursorHomes(root = homedir3(), _inUse = findHomesInUse) {
|
|
27337
|
-
if (process.env.SLOP_CURSOR_HOME) return [process.env.SLOP_CURSOR_HOME];
|
|
27338
|
-
return deduplicateStrings([join5(root, ".cursor"), ...findDirectoriesNamed(root, ".cursor").filter((dir) => hasAnyEntry(dir, ["cli-config.json", "hooks.json", "mcp.json", "projects"]))]);
|
|
27339
|
-
}
|
|
27340
27376
|
function resolveOwnHarnessHome(variable) {
|
|
27341
27377
|
if (process.platform === "win32") return null;
|
|
27342
27378
|
try {
|
|
27343
27379
|
let pid = process.ppid;
|
|
27344
27380
|
for (let hop = 0; hop < 6 && pid > 1; hop += 1) {
|
|
27345
|
-
const text = process.platform === "linux" ?
|
|
27381
|
+
const text = process.platform === "linux" ? readFileSync6(`/proc/${pid}/environ`, "latin1").replace(/\0/g, " ") : execFileSync3("ps", ["eww", "-o", "command=", "-p", String(pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
27346
27382
|
const match = new RegExp(`(?:^|\\s)${variable}=(\\S+)`).exec(text);
|
|
27347
27383
|
if (match?.[1]) return resolve3(match[1]);
|
|
27348
27384
|
if (process.platform === "linux") {
|
|
27349
|
-
const stat =
|
|
27385
|
+
const stat = readFileSync6(`/proc/${pid}/stat`, "utf8");
|
|
27350
27386
|
pid = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1]);
|
|
27351
|
-
} else pid = Number(
|
|
27387
|
+
} else pid = Number(execFileSync3("ps", ["-o", "ppid=", "-p", String(pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim());
|
|
27352
27388
|
}
|
|
27353
27389
|
} catch {
|
|
27354
27390
|
}
|
|
@@ -27361,7 +27397,7 @@ function fetchHarnessRegistration(pid = process.ppid) {
|
|
|
27361
27397
|
const path2 = join6(home, "sessions", `${pid}.json`);
|
|
27362
27398
|
if (!existsSync5(path2)) continue;
|
|
27363
27399
|
try {
|
|
27364
|
-
return JSON.parse(
|
|
27400
|
+
return JSON.parse(readFileSync7(path2, "utf8"));
|
|
27365
27401
|
} catch {
|
|
27366
27402
|
return null;
|
|
27367
27403
|
}
|
|
@@ -27498,137 +27534,45 @@ function wakeCodexOverWs(text, threadId, endpoint) {
|
|
|
27498
27534
|
});
|
|
27499
27535
|
});
|
|
27500
27536
|
}
|
|
27501
|
-
var CURSOR_TURN_CAP_MS = 6e5;
|
|
27502
|
-
var CURSOR_LOAD_WITHIN_MS = 3e4;
|
|
27503
|
-
function wakeCursor(text, chatId, cwd, options = {}) {
|
|
27504
|
-
const binary = options.binary ?? "cursor-agent";
|
|
27505
|
-
return wakeCursorOverAcp(text, chatId, cwd, binary).then((woken) => woken || resumeCursorChat(text, chatId, cwd, binary));
|
|
27506
|
-
}
|
|
27507
|
-
function wakeCursorOverAcp(text, chatId, cwd, binary) {
|
|
27508
|
-
return new Promise((resolve6) => {
|
|
27509
|
-
let child;
|
|
27510
|
-
try {
|
|
27511
|
-
child = spawn(binary, ["acp"], { cwd, stdio: ["pipe", "pipe", "ignore"] });
|
|
27512
|
-
} catch {
|
|
27513
|
-
resolve6(false);
|
|
27514
|
-
return;
|
|
27515
|
-
}
|
|
27516
|
-
let settled = false;
|
|
27517
|
-
let nextId = 1;
|
|
27518
|
-
let buffer = "";
|
|
27519
|
-
const finishWake = (woken, keepRunning = false) => {
|
|
27520
|
-
if (settled) return;
|
|
27521
|
-
settled = true;
|
|
27522
|
-
clearTimeout(loadTimer);
|
|
27523
|
-
if (!keepRunning) child.kill();
|
|
27524
|
-
else setTimeout(() => child.kill(), CURSOR_TURN_CAP_MS).unref?.();
|
|
27525
|
-
resolve6(woken);
|
|
27526
|
-
};
|
|
27527
|
-
const loadTimer = setTimeout(() => finishWake(false), CURSOR_LOAD_WITHIN_MS);
|
|
27528
|
-
const send = (message) => {
|
|
27529
|
-
try {
|
|
27530
|
-
child.stdin?.write(`${JSON.stringify(message)}
|
|
27531
|
-
`);
|
|
27532
|
-
} catch {
|
|
27533
|
-
finishWake(false);
|
|
27534
|
-
}
|
|
27535
|
-
};
|
|
27536
|
-
const call = (method, params) => {
|
|
27537
|
-
const id = nextId++;
|
|
27538
|
-
send({ jsonrpc: "2.0", id, method, params });
|
|
27539
|
-
return id;
|
|
27540
|
-
};
|
|
27541
|
-
const initializeId = call("initialize", { protocolVersion: 1, clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false }, clientInfo: { name: "slop", version: "0.4.16" } });
|
|
27542
|
-
let loadId = 0;
|
|
27543
|
-
let promptId = 0;
|
|
27544
|
-
child.on("error", () => finishWake(false));
|
|
27545
|
-
child.on("exit", () => finishWake(false));
|
|
27546
|
-
child.stdout?.on("data", (chunk) => {
|
|
27547
|
-
buffer += chunk.toString("utf8");
|
|
27548
|
-
let index;
|
|
27549
|
-
while ((index = buffer.indexOf("\n")) >= 0) {
|
|
27550
|
-
const line = buffer.slice(0, index);
|
|
27551
|
-
buffer = buffer.slice(index + 1);
|
|
27552
|
-
if (!line.trim()) continue;
|
|
27553
|
-
let message;
|
|
27554
|
-
try {
|
|
27555
|
-
message = JSON.parse(line);
|
|
27556
|
-
} catch {
|
|
27557
|
-
continue;
|
|
27558
|
-
}
|
|
27559
|
-
if (message.id !== void 0 && message.method === "session/request_permission") {
|
|
27560
|
-
const options = message.params?.options ?? [];
|
|
27561
|
-
const allow = options.find((option) => option.kind === "allow_once") ?? options.find((option) => /allow|accept/i.test(option.optionId ?? "")) ?? options[0];
|
|
27562
|
-
send({ jsonrpc: "2.0", id: message.id, result: { outcome: { outcome: "selected", optionId: allow?.optionId ?? "allow" } } });
|
|
27563
|
-
continue;
|
|
27564
|
-
}
|
|
27565
|
-
if (message.id !== void 0 && message.method) {
|
|
27566
|
-
send({ jsonrpc: "2.0", id: message.id, result: {} });
|
|
27567
|
-
continue;
|
|
27568
|
-
}
|
|
27569
|
-
if (message.id === initializeId) {
|
|
27570
|
-
if (message.error) finishWake(false);
|
|
27571
|
-
else loadId = call("session/load", { sessionId: chatId, cwd, mcpServers: [] });
|
|
27572
|
-
continue;
|
|
27573
|
-
}
|
|
27574
|
-
if (message.id === loadId && loadId !== 0) {
|
|
27575
|
-
if (message.error) finishWake(false);
|
|
27576
|
-
else promptId = call("session/prompt", { sessionId: chatId, prompt: [{ type: "text", text }] });
|
|
27577
|
-
continue;
|
|
27578
|
-
}
|
|
27579
|
-
if (promptId !== 0 && (message.id === promptId || message.method === "session/update")) finishWake(true, true);
|
|
27580
|
-
}
|
|
27581
|
-
});
|
|
27582
|
-
});
|
|
27583
|
-
}
|
|
27584
|
-
function resumeCursorChat(text, chatId, cwd, binary) {
|
|
27585
|
-
return new Promise((resolve6) => {
|
|
27586
|
-
let child;
|
|
27587
|
-
try {
|
|
27588
|
-
child = spawn(binary, ["--resume", chatId, "-p", text, "--output-format", "text"], { cwd, stdio: ["ignore", "ignore", "ignore"] });
|
|
27589
|
-
} catch {
|
|
27590
|
-
resolve6(false);
|
|
27591
|
-
return;
|
|
27592
|
-
}
|
|
27593
|
-
const timer = setTimeout(() => resolve6(true), 5e3);
|
|
27594
|
-
child.on("error", () => {
|
|
27595
|
-
clearTimeout(timer);
|
|
27596
|
-
resolve6(false);
|
|
27597
|
-
});
|
|
27598
|
-
child.on("exit", (code) => {
|
|
27599
|
-
clearTimeout(timer);
|
|
27600
|
-
resolve6(code === 0);
|
|
27601
|
-
});
|
|
27602
|
-
});
|
|
27603
|
-
}
|
|
27604
27537
|
|
|
27605
27538
|
// src/platform/harness.ts
|
|
27606
27539
|
var AgentHarnessValues = AgentHarness.options;
|
|
27607
27540
|
var HEAD_BYTES = 64 * 1024;
|
|
27608
|
-
var parent = null;
|
|
27609
|
-
function fetchParentCommand() {
|
|
27610
|
-
if (parent !== null) return parent;
|
|
27611
|
-
try {
|
|
27612
|
-
parent = process.platform === "win32" ? "" : execFileSync3("ps", ["-o", "command=", "-p", String(process.ppid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
27613
|
-
} catch {
|
|
27614
|
-
parent = "";
|
|
27615
|
-
}
|
|
27616
|
-
return parent;
|
|
27617
|
-
}
|
|
27618
27541
|
function parseHarnessFromCommand(command) {
|
|
27619
27542
|
const first = basename2(command.trim().split(/\s+/)[0] ?? "");
|
|
27620
|
-
if (/^cursor-agent(\b|$)/.test(first)) return "cursor";
|
|
27621
27543
|
if (/^claude(\b|$)/.test(first)) return "claude";
|
|
27622
27544
|
if (/^codex(\b|$)/.test(first)) return "codex";
|
|
27623
27545
|
if (/(^|\/)codex(\S*)?\s/.test(command)) return "codex";
|
|
27624
|
-
if (/(^|\/)cursor-agent(\s|$)/.test(command)) return "cursor";
|
|
27625
27546
|
return null;
|
|
27626
27547
|
}
|
|
27548
|
+
var ANCESTOR_HOPS = 8;
|
|
27549
|
+
function findHarnessAncestor(pid, fetchCommand = fetchProcessCommand, fetchParent = fetchParentPid, hops = ANCESTOR_HOPS) {
|
|
27550
|
+
let current = pid;
|
|
27551
|
+
for (let hop = 0; hop < hops && current !== null && current > 1; hop += 1) {
|
|
27552
|
+
const command = fetchCommand(current);
|
|
27553
|
+
const harness = parseHarnessFromCommand(command);
|
|
27554
|
+
if (harness) return { pid: current, harness, command };
|
|
27555
|
+
current = fetchParent(current);
|
|
27556
|
+
}
|
|
27557
|
+
return null;
|
|
27558
|
+
}
|
|
27559
|
+
var ancestor;
|
|
27560
|
+
function fetchHarnessAncestor() {
|
|
27561
|
+
if (ancestor !== void 0) return ancestor;
|
|
27562
|
+
const named = process.env.SLOP_HARNESS_PID?.trim();
|
|
27563
|
+
const harness = process.env.SLOP_HARNESS;
|
|
27564
|
+
if (named === "0") ancestor = null;
|
|
27565
|
+
else if (named && Number(named) > 0) {
|
|
27566
|
+
const pid = Number(named);
|
|
27567
|
+
ancestor = AgentHarnessValues.includes(harness ?? "") ? { pid, harness, command: fetchProcessCommand(pid) } : findHarnessAncestor(pid);
|
|
27568
|
+
} else ancestor = findHarnessAncestor(process.ppid);
|
|
27569
|
+
return ancestor;
|
|
27570
|
+
}
|
|
27627
27571
|
function isNonInteractiveCommand(command) {
|
|
27628
27572
|
return /(^|[\s/])codex(\S*)?\s+exec(\s|$)/.test(command);
|
|
27629
27573
|
}
|
|
27630
27574
|
function isNonInteractiveHarness() {
|
|
27631
|
-
return isNonInteractiveCommand(
|
|
27575
|
+
return isNonInteractiveCommand(fetchProcessCommand(process.ppid)) || isNonInteractiveCommand(fetchHarnessAncestor()?.command ?? "");
|
|
27632
27576
|
}
|
|
27633
27577
|
var isSamePath = (a, b) => {
|
|
27634
27578
|
const resolveRealPath = (path2) => {
|
|
@@ -27739,13 +27683,14 @@ function fetchCodexRolloutPath(roots, threadId) {
|
|
|
27739
27683
|
}
|
|
27740
27684
|
function resolveCodexBinary() {
|
|
27741
27685
|
try {
|
|
27742
|
-
|
|
27686
|
+
execFileSync4(process.platform === "win32" ? "where" : "which", ["codex"], { stdio: "ignore" });
|
|
27743
27687
|
return "codex";
|
|
27744
27688
|
} catch {
|
|
27745
27689
|
}
|
|
27746
|
-
|
|
27690
|
+
const above = fetchHarnessAncestor();
|
|
27691
|
+
if (above?.harness === "codex" && process.platform !== "win32") {
|
|
27747
27692
|
try {
|
|
27748
|
-
const exe = process.platform === "linux" ? readlinkSync(`/proc/${
|
|
27693
|
+
const exe = process.platform === "linux" ? readlinkSync(`/proc/${above.pid}/exe`) : execFileSync4("ps", ["-o", "comm=", "-p", String(above.pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
27749
27694
|
if (exe && basename2(exe).startsWith("codex")) return exe;
|
|
27750
27695
|
} catch {
|
|
27751
27696
|
}
|
|
@@ -27753,43 +27698,21 @@ function resolveCodexBinary() {
|
|
|
27753
27698
|
return "codex";
|
|
27754
27699
|
}
|
|
27755
27700
|
function resolveParentHarness() {
|
|
27756
|
-
return
|
|
27757
|
-
}
|
|
27758
|
-
var RETRY_ACP_AFTER_MS = 5e3;
|
|
27759
|
-
var acpSession = null;
|
|
27760
|
-
function fetchCursorAcpSessionByCwd(cwd, binary = "cursor-agent") {
|
|
27761
|
-
if (acpSession && (acpSession.id !== null || Date.now() - acpSession.at < RETRY_ACP_AFTER_MS)) return acpSession.id;
|
|
27762
|
-
acpSession = { id: null, at: Date.now() };
|
|
27763
|
-
const said = [
|
|
27764
|
-
{ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1, clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false }, clientInfo: { name: "slop", version: "0.4.16" } } },
|
|
27765
|
-
{ jsonrpc: "2.0", id: 2, method: "session/list", params: {} }
|
|
27766
|
-
];
|
|
27767
|
-
try {
|
|
27768
|
-
const answered = execFileSync3(binary, ["acp"], { input: `${said.map((message) => JSON.stringify(message)).join("\n")}
|
|
27769
|
-
`, encoding: "utf8", timeout: 15e3, stdio: ["pipe", "pipe", "ignore"], cwd });
|
|
27770
|
-
for (const line of answered.split("\n")) {
|
|
27771
|
-
if (!line.includes('"sessions"')) continue;
|
|
27772
|
-
const listed = JSON.parse(line).result?.sessions ?? [];
|
|
27773
|
-
const here = listed.filter((session) => typeof session.sessionId === "string" && typeof session.cwd === "string" && isSamePath(session.cwd, cwd));
|
|
27774
|
-
if (here.length === 1) acpSession = { id: here[0].sessionId, at: Date.now() };
|
|
27775
|
-
}
|
|
27776
|
-
} catch {
|
|
27777
|
-
}
|
|
27778
|
-
return acpSession.id;
|
|
27701
|
+
return fetchHarnessAncestor()?.harness ?? null;
|
|
27779
27702
|
}
|
|
27780
27703
|
function fetchHarnessConversation(cwd) {
|
|
27781
27704
|
const explicit = process.env.SLOP_CONVERSATION_ID?.trim();
|
|
27782
27705
|
if (explicit) return { id: explicit, harness: AgentHarnessValues.includes(process.env.SLOP_HARNESS) ? process.env.SLOP_HARNESS : "other" };
|
|
27783
27706
|
if (process.env.CODEX_THREAD_ID?.trim()) return { id: process.env.CODEX_THREAD_ID.trim(), harness: "codex" };
|
|
27784
27707
|
if (process.env.CLAUDE_CODE_SESSION_ID?.trim()) return { id: process.env.CLAUDE_CODE_SESSION_ID.trim(), harness: "claude" };
|
|
27785
|
-
const
|
|
27786
|
-
if (harness === "claude") {
|
|
27708
|
+
const above = fetchHarnessAncestor();
|
|
27709
|
+
if (above?.harness === "claude") {
|
|
27787
27710
|
const id = resolveClaudeSession()?.sessionId;
|
|
27788
|
-
return id ? { id, harness } : null;
|
|
27711
|
+
return id ? { id, harness: "claude" } : null;
|
|
27789
27712
|
}
|
|
27790
|
-
if (harness === "codex" && !isNonInteractiveHarness()) {
|
|
27713
|
+
if (above?.harness === "codex" && !isNonInteractiveHarness()) {
|
|
27791
27714
|
const id = fetchCodexConversationByCwd(fetchCodexHomes().map((home) => join7(home, "sessions")), cwd);
|
|
27792
|
-
return id ? { id, harness } : null;
|
|
27715
|
+
return id ? { id, harness: "codex" } : null;
|
|
27793
27716
|
}
|
|
27794
27717
|
return null;
|
|
27795
27718
|
}
|
|
@@ -27802,11 +27725,7 @@ function fetchKnownConversation(cwd) {
|
|
|
27802
27725
|
if (own2) return own2;
|
|
27803
27726
|
const remembered = fetchRememberedConversation(cwd, startedAt - 12e4, resolveParentHarness());
|
|
27804
27727
|
if (remembered?.harness === "codex" && isMainChatThread(fetchCodexHomes().map((home) => join8(home, "sessions")), remembered.id)) return remembered;
|
|
27805
|
-
|
|
27806
|
-
if (known) return known;
|
|
27807
|
-
if (resolveParentHarness() !== "cursor") return null;
|
|
27808
|
-
const acp = fetchCursorAcpSessionByCwd(cwd);
|
|
27809
|
-
return acp ? { id: acp, harness: "cursor" } : null;
|
|
27728
|
+
return remembered?.harness === "codex" ? null : remembered;
|
|
27810
27729
|
}
|
|
27811
27730
|
function resolveAgentIdentity(cwd, fallback = "process") {
|
|
27812
27731
|
const conversation = fetchKnownConversation(cwd);
|
|
@@ -27907,14 +27826,14 @@ function buildAuthedApiClient() {
|
|
|
27907
27826
|
}
|
|
27908
27827
|
|
|
27909
27828
|
// src/platform/machine.ts
|
|
27910
|
-
import { execFileSync as
|
|
27829
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
27911
27830
|
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
27912
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as
|
|
27831
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
|
|
27913
27832
|
import { hostname as hostname3, platform, userInfo } from "os";
|
|
27914
27833
|
import { dirname as dirname4, join as join9 } from "path";
|
|
27915
27834
|
function runCommand(command, args) {
|
|
27916
27835
|
try {
|
|
27917
|
-
return
|
|
27836
|
+
return execFileSync5(command, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 });
|
|
27918
27837
|
} catch {
|
|
27919
27838
|
return null;
|
|
27920
27839
|
}
|
|
@@ -27925,7 +27844,7 @@ function fetchOsMachineId() {
|
|
|
27925
27844
|
return /"IOPlatformUUID" = "([^"]+)"/.exec(runCommand("ioreg", ["-rd1", "-c", "IOPlatformExpertDevice"]) ?? "")?.[1] ?? null;
|
|
27926
27845
|
case "linux":
|
|
27927
27846
|
for (const path2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
27928
|
-
if (existsSync6(path2)) return
|
|
27847
|
+
if (existsSync6(path2)) return readFileSync8(path2, "utf8").trim() || null;
|
|
27929
27848
|
}
|
|
27930
27849
|
return null;
|
|
27931
27850
|
case "win32":
|
|
@@ -27938,7 +27857,7 @@ function fetchOsMachineId() {
|
|
|
27938
27857
|
}
|
|
27939
27858
|
function resolvePersistedMachineId() {
|
|
27940
27859
|
const path2 = join9(dirname4(buildConfigPath()), "machine-id");
|
|
27941
|
-
if (existsSync6(path2)) return
|
|
27860
|
+
if (existsSync6(path2)) return readFileSync8(path2, "utf8").trim();
|
|
27942
27861
|
const id = randomUUID5();
|
|
27943
27862
|
mkdirSync4(dirname4(path2), { recursive: true, mode: 448 });
|
|
27944
27863
|
writeFileSync4(path2, `${id}
|
|
@@ -28223,32 +28142,24 @@ linked to ${link.projectKey} ${link.projectName} (${link.baseUrl})`
|
|
|
28223
28142
|
|
|
28224
28143
|
// src/commands/mcp.ts
|
|
28225
28144
|
import { execFileSync as execFileSync6, spawn as spawn3 } from "child_process";
|
|
28226
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as
|
|
28145
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync18, writeFileSync as writeFileSync8 } from "fs";
|
|
28227
28146
|
import { homedir as homedir4 } from "os";
|
|
28228
28147
|
import { join as join16 } from "path";
|
|
28229
28148
|
|
|
28230
28149
|
// src/platform/session-recovery.ts
|
|
28231
|
-
import { readFileSync as
|
|
28150
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
28232
28151
|
import { dirname as dirname6, join as join13 } from "path";
|
|
28233
28152
|
|
|
28234
28153
|
// src/platform/inbox.ts
|
|
28235
28154
|
import { createHash as createHash6, randomUUID as randomUUID7 } from "crypto";
|
|
28236
|
-
import { existsSync as existsSync9, linkSync as linkSync3, mkdirSync as mkdirSync7, readFileSync as
|
|
28155
|
+
import { existsSync as existsSync9, linkSync as linkSync3, mkdirSync as mkdirSync7, readFileSync as readFileSync11, readdirSync as readdirSync6, realpathSync as realpathSync4, renameSync as renameSync2, rmSync as rmSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
28237
28156
|
import { dirname as dirname5, join as join12 } from "path";
|
|
28238
28157
|
|
|
28239
28158
|
// src/platform/inbox-claims.ts
|
|
28240
|
-
import { execFileSync as execFileSync5 } from "child_process";
|
|
28241
28159
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
28242
|
-
import { existsSync as existsSync7, linkSync as linkSync2, mkdirSync as mkdirSync5, readFileSync as
|
|
28160
|
+
import { existsSync as existsSync7, linkSync as linkSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync9, readdirSync as readdirSync4, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
28243
28161
|
import { join as join10 } from "path";
|
|
28244
28162
|
var processOwner = null;
|
|
28245
|
-
function fetchProcessStart(pid) {
|
|
28246
|
-
try {
|
|
28247
|
-
return execFileSync5("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8", env: { ...process.env, LC_ALL: "C", TZ: "UTC" }, stdio: ["ignore", "pipe", "ignore"], timeout: 1e3 }).trim() || null;
|
|
28248
|
-
} catch {
|
|
28249
|
-
return null;
|
|
28250
|
-
}
|
|
28251
|
-
}
|
|
28252
28163
|
function isClaimOwnerRunning(owner) {
|
|
28253
28164
|
if (!Number.isSafeInteger(owner.pid) || owner.pid <= 0) throw new Error("Invalid inbox claim owner");
|
|
28254
28165
|
try {
|
|
@@ -28276,7 +28187,7 @@ function claimInboxMessage(directory) {
|
|
|
28276
28187
|
if (last && !existsSync7(join10(directory, `${last}.released`))) {
|
|
28277
28188
|
let owner;
|
|
28278
28189
|
try {
|
|
28279
|
-
owner = JSON.parse(
|
|
28190
|
+
owner = JSON.parse(readFileSync9(join10(directory, last), "utf8"));
|
|
28280
28191
|
} catch (error62) {
|
|
28281
28192
|
if (error62.code === "ENOENT") return null;
|
|
28282
28193
|
throw error62;
|
|
@@ -28306,7 +28217,7 @@ function claimInboxMessage(directory) {
|
|
|
28306
28217
|
|
|
28307
28218
|
// src/platform/inbox-receipts.ts
|
|
28308
28219
|
import { createHash as createHash5 } from "crypto";
|
|
28309
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as
|
|
28220
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync10, readdirSync as readdirSync5, rmSync as rmSync6 } from "fs";
|
|
28310
28221
|
import { join as join11 } from "path";
|
|
28311
28222
|
var COMPACTION_SIZE = 128;
|
|
28312
28223
|
var archives = /* @__PURE__ */ new Map();
|
|
@@ -28325,7 +28236,7 @@ function fetchArchivedReceipts(directory) {
|
|
|
28325
28236
|
}
|
|
28326
28237
|
for (const name of names) {
|
|
28327
28238
|
if (!name.endsWith(".json") || cached2.files.has(name)) continue;
|
|
28328
|
-
const keys = JSON.parse(
|
|
28239
|
+
const keys = JSON.parse(readFileSync10(join11(directory, "compacted", name), "utf8"));
|
|
28329
28240
|
if (!Array.isArray(keys) || !keys.every((key) => typeof key === "string" && /^[a-f0-9]{64}$/.test(key))) throw new Error("Invalid inbox receipt archive");
|
|
28330
28241
|
for (const key of keys) cached2.keys.add(key);
|
|
28331
28242
|
cached2.files.add(name);
|
|
@@ -28448,7 +28359,7 @@ function claimInbox(cwd, owner, accept = () => true) {
|
|
|
28448
28359
|
const available = [];
|
|
28449
28360
|
for (const name of names) {
|
|
28450
28361
|
try {
|
|
28451
|
-
available.push({ key: name.slice(0, -5), push: JSON.parse(
|
|
28362
|
+
available.push({ key: name.slice(0, -5), push: JSON.parse(readFileSync11(join12(directory, name), "utf8")) });
|
|
28452
28363
|
} catch (error62) {
|
|
28453
28364
|
if (error62.code !== "ENOENT") throw error62;
|
|
28454
28365
|
}
|
|
@@ -28505,7 +28416,7 @@ function drainInbox(cwd) {
|
|
|
28505
28416
|
throw error62;
|
|
28506
28417
|
}
|
|
28507
28418
|
try {
|
|
28508
|
-
pushes.push(JSON.parse(
|
|
28419
|
+
pushes.push(JSON.parse(readFileSync11(taken, "utf8")));
|
|
28509
28420
|
} finally {
|
|
28510
28421
|
rmSync7(taken, { force: true });
|
|
28511
28422
|
}
|
|
@@ -28521,7 +28432,7 @@ function drainLegacyInbox(cwd) {
|
|
|
28521
28432
|
} catch {
|
|
28522
28433
|
return [];
|
|
28523
28434
|
}
|
|
28524
|
-
const lines =
|
|
28435
|
+
const lines = readFileSync11(taken, "utf8").split("\n").filter(Boolean);
|
|
28525
28436
|
rmSync7(taken, { force: true });
|
|
28526
28437
|
return lines.flatMap((line) => {
|
|
28527
28438
|
try {
|
|
@@ -28558,7 +28469,7 @@ var SessionRecovery = class {
|
|
|
28558
28469
|
}
|
|
28559
28470
|
async fetchCursor() {
|
|
28560
28471
|
try {
|
|
28561
|
-
const value = JSON.parse(
|
|
28472
|
+
const value = JSON.parse(readFileSync12(this.path, "utf8"));
|
|
28562
28473
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error("Invalid saved message cursor");
|
|
28563
28474
|
this.cursor = value;
|
|
28564
28475
|
} catch (error62) {
|
|
@@ -28937,7 +28848,7 @@ var HeldSession = class {
|
|
|
28937
28848
|
};
|
|
28938
28849
|
|
|
28939
28850
|
// src/platform/harness-activity.ts
|
|
28940
|
-
import { closeSync as closeSync2, existsSync as existsSync10, openSync as openSync2, readdirSync as readdirSync7, readFileSync as
|
|
28851
|
+
import { closeSync as closeSync2, existsSync as existsSync10, openSync as openSync2, readdirSync as readdirSync7, readFileSync as readFileSync13, readSync as readSync2, statSync as statSync4 } from "fs";
|
|
28941
28852
|
import { basename as basename4, dirname as dirname7, join as join14 } from "path";
|
|
28942
28853
|
var WORKER_FRESH_MS = 12e4;
|
|
28943
28854
|
var WORKER_GONE_MS = 3e5;
|
|
@@ -29010,67 +28921,6 @@ function parseToolCallFromCodexLine(line) {
|
|
|
29010
28921
|
if (payload.type === "local_shell_call") return formatToolCallLine("shell", payload.action);
|
|
29011
28922
|
return null;
|
|
29012
28923
|
}
|
|
29013
|
-
function parseCursorTaskFromLine(line) {
|
|
29014
|
-
if (!line.includes("CallDynamicTool") || !line.includes('"Task"')) return null;
|
|
29015
|
-
let entry;
|
|
29016
|
-
try {
|
|
29017
|
-
entry = JSON.parse(line);
|
|
29018
|
-
} catch {
|
|
29019
|
-
return null;
|
|
29020
|
-
}
|
|
29021
|
-
const content = entry.message?.content;
|
|
29022
|
-
if (!Array.isArray(content)) return null;
|
|
29023
|
-
for (const block of content) {
|
|
29024
|
-
if (!block || typeof block !== "object") continue;
|
|
29025
|
-
const { type, name, input: input2 } = block;
|
|
29026
|
-
if (type !== "tool_use" || name !== "CallDynamicTool" || input2?.toolName !== "Task") continue;
|
|
29027
|
-
const asked = input2.arguments ?? {};
|
|
29028
|
-
const prompt = typeof asked.prompt === "string" ? asked.prompt : null;
|
|
29029
|
-
if (!prompt) continue;
|
|
29030
|
-
const label = [asked.subagent_type, asked.description].filter((part) => typeof part === "string" && part.trim() !== "").join(" \u2014 ");
|
|
29031
|
-
return { label: truncate(label || "subagent", WORKER_LABEL_MAX), prompt };
|
|
29032
|
-
}
|
|
29033
|
-
return null;
|
|
29034
|
-
}
|
|
29035
|
-
function parseCursorUserQuery(line) {
|
|
29036
|
-
let entry;
|
|
29037
|
-
try {
|
|
29038
|
-
entry = JSON.parse(line);
|
|
29039
|
-
} catch {
|
|
29040
|
-
return null;
|
|
29041
|
-
}
|
|
29042
|
-
const content = entry.message?.content;
|
|
29043
|
-
if (entry.role !== "user" || !Array.isArray(content)) return null;
|
|
29044
|
-
for (const block of content) {
|
|
29045
|
-
const text = block?.text;
|
|
29046
|
-
if (typeof text !== "string") continue;
|
|
29047
|
-
const asked = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/.exec(text);
|
|
29048
|
-
if (asked?.[1]) return asked[1];
|
|
29049
|
-
}
|
|
29050
|
-
return null;
|
|
29051
|
-
}
|
|
29052
|
-
function findCursorWorkerFiles(transcriptPath, conversation, changedAfter, asked) {
|
|
29053
|
-
if (asked.length === 0) return [];
|
|
29054
|
-
const directory = dirname7(dirname7(transcriptPath));
|
|
29055
|
-
let chats;
|
|
29056
|
-
try {
|
|
29057
|
-
chats = readdirSync7(directory);
|
|
29058
|
-
} catch {
|
|
29059
|
-
return [];
|
|
29060
|
-
}
|
|
29061
|
-
const found = [];
|
|
29062
|
-
for (const chat of chats) {
|
|
29063
|
-
if (chat === conversation) continue;
|
|
29064
|
-
const path2 = join14(directory, chat, `${chat}.jsonl`);
|
|
29065
|
-
const changedAt = fetchChangedAt(path2);
|
|
29066
|
-
if (changedAt < changedAfter) continue;
|
|
29067
|
-
const query = parseCursorUserQuery(fetchFileHead(path2, 16 * 1024).split("\n")[0] ?? "");
|
|
29068
|
-
const task = query === null ? void 0 : asked.find((candidate) => candidate.prompt === query);
|
|
29069
|
-
if (!task) continue;
|
|
29070
|
-
found.push({ ref: chat, label: task.label, path: path2, directory: null, branch: null, changedAt });
|
|
29071
|
-
}
|
|
29072
|
-
return found.sort((a, b) => b.changedAt - a.changedAt);
|
|
29073
|
-
}
|
|
29074
28924
|
var fetchFileSize = (path2) => {
|
|
29075
28925
|
try {
|
|
29076
28926
|
return statSync4(path2).size;
|
|
@@ -29139,21 +28989,6 @@ function findClaudeTranscriptPath(homes, conversation) {
|
|
|
29139
28989
|
}
|
|
29140
28990
|
return null;
|
|
29141
28991
|
}
|
|
29142
|
-
function findCursorTranscriptPath(homes, conversation) {
|
|
29143
|
-
for (const home of homes) {
|
|
29144
|
-
let projects;
|
|
29145
|
-
try {
|
|
29146
|
-
projects = readdirSync7(join14(home, "projects"));
|
|
29147
|
-
} catch {
|
|
29148
|
-
continue;
|
|
29149
|
-
}
|
|
29150
|
-
for (const project of projects) {
|
|
29151
|
-
const path2 = join14(home, "projects", project, "agent-transcripts", conversation, `${conversation}.jsonl`);
|
|
29152
|
-
if (existsSync10(path2)) return path2;
|
|
29153
|
-
}
|
|
29154
|
-
}
|
|
29155
|
-
return null;
|
|
29156
|
-
}
|
|
29157
28992
|
function parseClaudeWorkerLabel(text) {
|
|
29158
28993
|
let meta3;
|
|
29159
28994
|
try {
|
|
@@ -29181,7 +29016,7 @@ function findClaudeWorkerFiles(transcriptPath, conversation, changedAfter) {
|
|
|
29181
29016
|
if (changedAt < changedAfter) continue;
|
|
29182
29017
|
let label = null;
|
|
29183
29018
|
try {
|
|
29184
|
-
label = parseClaudeWorkerLabel(
|
|
29019
|
+
label = parseClaudeWorkerLabel(readFileSync13(join14(directory, `agent-${ref}.meta.json`), "utf8"));
|
|
29185
29020
|
} catch {
|
|
29186
29021
|
}
|
|
29187
29022
|
const first = fetchFileHead(path2, 8 * 1024).split("\n")[0] ?? "";
|
|
@@ -29239,7 +29074,6 @@ function findCodexChildRollouts(roots, parentThreadId, changedAfter) {
|
|
|
29239
29074
|
}
|
|
29240
29075
|
return found;
|
|
29241
29076
|
}
|
|
29242
|
-
var ASKED_CAP = 16;
|
|
29243
29077
|
var HarnessActivity = class {
|
|
29244
29078
|
constructor(conversation, onReport) {
|
|
29245
29079
|
this.conversation = conversation;
|
|
@@ -29248,8 +29082,6 @@ var HarnessActivity = class {
|
|
|
29248
29082
|
conversation;
|
|
29249
29083
|
onReport;
|
|
29250
29084
|
workers = /* @__PURE__ */ new Map();
|
|
29251
|
-
/** What this chat has asked a subagent to do, which is how a Cursor chat's children are claimed. */
|
|
29252
|
-
asked = [];
|
|
29253
29085
|
own = null;
|
|
29254
29086
|
doing = null;
|
|
29255
29087
|
watched = false;
|
|
@@ -29317,11 +29149,6 @@ var HarnessActivity = class {
|
|
|
29317
29149
|
this.own ??= transcript ? new FileTail(transcript, "end") : null;
|
|
29318
29150
|
return transcript ? findClaudeWorkerFiles(transcript, this.conversation.id, changedAfter) : [];
|
|
29319
29151
|
}
|
|
29320
|
-
if (this.conversation.harness === "cursor") {
|
|
29321
|
-
const transcript = findCursorTranscriptPath(fetchCursorHomes(), this.conversation.id);
|
|
29322
|
-
this.own ??= transcript ? new FileTail(transcript, "end") : null;
|
|
29323
|
-
return transcript ? findCursorWorkerFiles(transcript, this.conversation.id, changedAfter, this.asked) : [];
|
|
29324
|
-
}
|
|
29325
29152
|
if (this.conversation.harness === "codex") {
|
|
29326
29153
|
const roots = fetchCodexHomes().map((home) => join14(home, "sessions"));
|
|
29327
29154
|
const rollout = fetchCodexRolloutPath(roots, this.conversation.id);
|
|
@@ -29340,14 +29167,7 @@ var HarnessActivity = class {
|
|
|
29340
29167
|
};
|
|
29341
29168
|
if (this.own) {
|
|
29342
29169
|
let newest = null;
|
|
29343
|
-
for (const line of this.own.fetchNewLines())
|
|
29344
|
-
newest = parse3(line) ?? newest;
|
|
29345
|
-
const task = this.conversation.harness === "cursor" ? parseCursorTaskFromLine(line) : null;
|
|
29346
|
-
if (task) {
|
|
29347
|
-
this.asked.push(task);
|
|
29348
|
-
while (this.asked.length > ASKED_CAP) this.asked.shift();
|
|
29349
|
-
}
|
|
29350
|
-
}
|
|
29170
|
+
for (const line of this.own.fetchNewLines()) newest = parse3(line) ?? newest;
|
|
29351
29171
|
this.doing = newest ?? this.doing;
|
|
29352
29172
|
}
|
|
29353
29173
|
for (const worker of this.workers.values()) worker.doing = findNewestCall(worker.tail) ?? worker.doing;
|
|
@@ -29478,11 +29298,11 @@ function serveMcp(tools, info) {
|
|
|
29478
29298
|
}
|
|
29479
29299
|
|
|
29480
29300
|
// src/commands/tasks.ts
|
|
29481
|
-
import { readFileSync as
|
|
29301
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
29482
29302
|
|
|
29483
29303
|
// src/commands/items.ts
|
|
29484
|
-
import { readFileSync as
|
|
29485
|
-
var fetchTextArgument = (value) => value === "-" ?
|
|
29304
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
29305
|
+
var fetchTextArgument = (value) => value === "-" ? readFileSync14(0, "utf8").trim() : value;
|
|
29486
29306
|
var buildItemsPath = (projectId, key) => `/projects/${projectId}/tasks/${encodeURIComponent(key)}/items`;
|
|
29487
29307
|
function formatPlanItems(items) {
|
|
29488
29308
|
if (items.length === 0) return "No plan yet. Write one: slop task plan <KEY> -";
|
|
@@ -29509,7 +29329,7 @@ function registerItemCommands(task, registerProjectOption) {
|
|
|
29509
29329
|
registerProjectOption(task.command("plan <key> [lines...]")).description('Append items to the plan, one per argument; "-" reads one per line from stdin (list markers are fine).').action(async (key, lines, options) => {
|
|
29510
29330
|
const api = buildAuthedApiClient();
|
|
29511
29331
|
const project = await resolveProject(api, options.project);
|
|
29512
|
-
const source = lines.length === 1 && lines[0] === "-" ?
|
|
29332
|
+
const source = lines.length === 1 && lines[0] === "-" ? readFileSync14(0, "utf8") : lines.join("\n");
|
|
29513
29333
|
const titles = source.split("\n").map((line) => line.replace(/^\s*(?:[-*+]|\d+[.)])\s*(?:\[[ xX]\]\s*)?/, "").trim()).filter(Boolean);
|
|
29514
29334
|
if (titles.length === 0) throw new CliError("Nothing to add", 'give items as arguments, or "-" and one per line on stdin');
|
|
29515
29335
|
const items = await api.post(buildItemsPath(project.id, key), ApiResponses.TaskItems, { items: titles.map((title3) => ({ title: title3 })) });
|
|
@@ -29566,7 +29386,7 @@ function parseOneOf(value, allowed, what) {
|
|
|
29566
29386
|
if (allowed.includes(normalized)) return normalized;
|
|
29567
29387
|
throw new CliError(`Unknown ${what} "${value}"`, `use one of: ${allowed.join(", ")}`);
|
|
29568
29388
|
}
|
|
29569
|
-
var fetchTextArgument2 = (value) => value === "-" ?
|
|
29389
|
+
var fetchTextArgument2 = (value) => value === "-" ? readFileSync15(0, "utf8").trim() : value;
|
|
29570
29390
|
var buildTaskUrl = (baseUrl, projectId, task) => `${baseUrl}/projects/${projectId}?task=${task.key}`;
|
|
29571
29391
|
var fetchProject = (api, id) => api.get(`/projects/${id}`, ApiResponses.Project);
|
|
29572
29392
|
function resolveStatus(project, ref) {
|
|
@@ -29717,14 +29537,14 @@ ${buildTaskUrl(api.baseUrl, project.id, created)}`);
|
|
|
29717
29537
|
}
|
|
29718
29538
|
|
|
29719
29539
|
// src/platform/update-check.ts
|
|
29720
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as
|
|
29540
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync7 } from "fs";
|
|
29721
29541
|
import { dirname as dirname8, join as join15 } from "path";
|
|
29722
29542
|
var CHECK_EVERY_MS = 60 * 60 * 1e3;
|
|
29723
29543
|
var REGISTRY = "https://registry.npmjs.org/slopwaresystems/latest";
|
|
29724
29544
|
var buildUpdateCachePath = () => join15(dirname8(buildConfigPath()), "update-check.json");
|
|
29725
29545
|
function fetchUpdateCache() {
|
|
29726
29546
|
try {
|
|
29727
|
-
return JSON.parse(
|
|
29547
|
+
return JSON.parse(readFileSync16(buildUpdateCachePath(), "utf8"));
|
|
29728
29548
|
} catch {
|
|
29729
29549
|
return { checkedAt: 0, latest: null };
|
|
29730
29550
|
}
|
|
@@ -29763,8 +29583,8 @@ function buildUpdateNotice(current) {
|
|
|
29763
29583
|
var isUpdateCheckEnabled = () => !existsSync11(join15(dirname8(buildConfigPath()), "no-update-check")) && process.env.SLOP_NO_UPDATE_CHECK !== "1";
|
|
29764
29584
|
|
|
29765
29585
|
// src/commands/threads.ts
|
|
29766
|
-
import { readFileSync as
|
|
29767
|
-
var fetchTextArgument3 = (value) => value === "-" ?
|
|
29586
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
29587
|
+
var fetchTextArgument3 = (value) => value === "-" ? readFileSync17(0, "utf8").trim() : value;
|
|
29768
29588
|
var formatMessageTime = (iso) => iso.slice(0, 16).replace("T", " ");
|
|
29769
29589
|
var formatAuthor = (message) => message.via !== "agent" ? message.author.name : `${message.agent ?? message.author.name} (${message.agent ? `${message.author.name}'s agent` : "agent"}${message.machine ? ` \xB7 ${message.machine}` : ""})`;
|
|
29770
29590
|
function formatThreadLine(thread) {
|
|
@@ -29911,7 +29731,7 @@ function createProjectTools(api, project, identity) {
|
|
|
29911
29731
|
if (waking || stopped) return;
|
|
29912
29732
|
waking = true;
|
|
29913
29733
|
const text = `Messages are waiting for you on Slopware Tasks in project ${project.key}. Use session check with project ${project.id} to read them, then act or reply only if it changes something. Do not acknowledge.`;
|
|
29914
|
-
const wake = identity.harness === "codex" && identity.conversation ? wakeCodex(text, identity.conversation, { binary: resolveCodexBinary(), codexHome: resolveOwnHarnessHome("CODEX_HOME") }) : identity.harness === "claude" ? wakeHarness(text, void 0, identity.conversation) :
|
|
29734
|
+
const wake = identity.harness === "codex" && identity.conversation ? wakeCodex(text, identity.conversation, { binary: resolveCodexBinary(), codexHome: resolveOwnHarnessHome("CODEX_HOME") }) : identity.harness === "claude" ? wakeHarness(text, void 0, identity.conversation) : Promise.resolve(false);
|
|
29915
29735
|
void wake.catch(() => false).finally(() => {
|
|
29916
29736
|
waking = false;
|
|
29917
29737
|
});
|
|
@@ -30329,7 +30149,7 @@ ${task.notes}` : ""].filter(Boolean).join("\n");
|
|
|
30329
30149
|
}
|
|
30330
30150
|
function fetchJsonFile(path2) {
|
|
30331
30151
|
try {
|
|
30332
|
-
return JSON.parse(
|
|
30152
|
+
return JSON.parse(readFileSync18(path2, "utf8"));
|
|
30333
30153
|
} catch {
|
|
30334
30154
|
return {};
|
|
30335
30155
|
}
|
|
@@ -30379,7 +30199,7 @@ function installIntoCodexHome(dir) {
|
|
|
30379
30199
|
const done = [];
|
|
30380
30200
|
mkdirSync9(dir, { recursive: true });
|
|
30381
30201
|
const configTomlPath = join16(dir, "config.toml");
|
|
30382
|
-
const current = existsSync12(configTomlPath) ?
|
|
30202
|
+
const current = existsSync12(configTomlPath) ? readFileSync18(configTomlPath, "utf8") : "";
|
|
30383
30203
|
if (/^\[mcp_servers\.slop\]/m.test(current)) {
|
|
30384
30204
|
if (/tool_timeout_sec = 1800\b/.test(current)) writeFileSync8(configTomlPath, current.replace(/tool_timeout_sec = 1800\b/, "tool_timeout_sec = 21600"));
|
|
30385
30205
|
done.push(`Codex: MCP server already in ${configTomlPath}`);
|
|
@@ -30399,41 +30219,43 @@ tool_timeout_sec = 21600
|
|
|
30399
30219
|
done.push(`Codex: SessionStart hook written to ${hooksPath}; other slop hooks removed (Codex is woken with codex queue; no hook holds a turn open)`);
|
|
30400
30220
|
return done;
|
|
30401
30221
|
}
|
|
30402
|
-
function
|
|
30222
|
+
function removeFromCursorHome(dir) {
|
|
30403
30223
|
const done = [];
|
|
30404
|
-
mkdirSync9(dir, { recursive: true });
|
|
30405
|
-
const mcpPath = join16(dir, "mcp.json");
|
|
30406
|
-
const mcp = fetchJsonFile(mcpPath);
|
|
30407
|
-
const servers = mcp.mcpServers ?? {};
|
|
30408
|
-
const had = "slop" in servers;
|
|
30409
|
-
servers.slop = { command: "slop", args: ["mcp"] };
|
|
30410
|
-
mcp.mcpServers = servers;
|
|
30411
|
-
writeFileSync8(mcpPath, `${JSON.stringify(mcp, null, 2)}
|
|
30412
|
-
`);
|
|
30413
|
-
done.push(`Cursor: MCP server "slop" ${had ? "already in" : "added to"} ${mcpPath}`);
|
|
30414
30224
|
const hooksPath = join16(dir, "hooks.json");
|
|
30415
|
-
|
|
30416
|
-
|
|
30417
|
-
|
|
30418
|
-
|
|
30225
|
+
if (existsSync12(hooksPath)) {
|
|
30226
|
+
const file2 = fetchJsonFile(hooksPath);
|
|
30227
|
+
const hooks = file2.hooks ?? {};
|
|
30228
|
+
if (deleteSlopHooksFromCursorHooks(hooks)) {
|
|
30229
|
+
file2.hooks = hooks;
|
|
30230
|
+
writeFileSync8(hooksPath, `${JSON.stringify(file2, null, 2)}
|
|
30419
30231
|
`);
|
|
30420
|
-
|
|
30421
|
-
|
|
30422
|
-
|
|
30423
|
-
|
|
30424
|
-
|
|
30425
|
-
|
|
30232
|
+
done.push(`Cursor: slop hooks removed from ${hooksPath} (Cursor CLI is not supported)`);
|
|
30233
|
+
}
|
|
30234
|
+
}
|
|
30235
|
+
const mcpPath = join16(dir, "mcp.json");
|
|
30236
|
+
if (existsSync12(mcpPath)) {
|
|
30237
|
+
const mcp = fetchJsonFile(mcpPath);
|
|
30238
|
+
const servers = mcp.mcpServers ?? {};
|
|
30239
|
+
if ("slop" in servers) {
|
|
30240
|
+
delete servers.slop;
|
|
30241
|
+
mcp.mcpServers = servers;
|
|
30242
|
+
writeFileSync8(mcpPath, `${JSON.stringify(mcp, null, 2)}
|
|
30243
|
+
`);
|
|
30244
|
+
done.push(`Cursor: MCP server "slop" removed from ${mcpPath}`);
|
|
30245
|
+
}
|
|
30426
30246
|
}
|
|
30427
30247
|
return done;
|
|
30428
30248
|
}
|
|
30429
|
-
function
|
|
30249
|
+
function deleteSlopHooksFromCursorHooks(hooks) {
|
|
30430
30250
|
const isOwnHook = (hook) => typeof hook.command === "string" && /(^|\s)slop hook /.test(hook.command);
|
|
30251
|
+
let removed = false;
|
|
30431
30252
|
for (const event of Object.keys(hooks)) {
|
|
30432
|
-
|
|
30433
|
-
if (hooks[event].length
|
|
30253
|
+
const kept = (hooks[event] ?? []).filter((hook) => !isOwnHook(hook));
|
|
30254
|
+
if (kept.length !== (hooks[event] ?? []).length) removed = true;
|
|
30255
|
+
if (kept.length === 0) delete hooks[event];
|
|
30256
|
+
else hooks[event] = kept;
|
|
30434
30257
|
}
|
|
30435
|
-
|
|
30436
|
-
return hooks;
|
|
30258
|
+
return removed;
|
|
30437
30259
|
}
|
|
30438
30260
|
async function trustCodexHooks(codexHome) {
|
|
30439
30261
|
const server = spawn3("codex", ["app-server", "-c", "mcp_servers={}"], { stdio: ["pipe", "pipe", "ignore"], env: { ...process.env, CODEX_HOME: codexHome } });
|
|
@@ -30472,7 +30294,7 @@ async function trustCodexHooks(codexHome) {
|
|
|
30472
30294
|
const sendNotification = (method, params) => server.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, params })}
|
|
30473
30295
|
`);
|
|
30474
30296
|
try {
|
|
30475
|
-
await callCodexMethod("initialize", { clientInfo: { name: "slop", version: "0.4.
|
|
30297
|
+
await callCodexMethod("initialize", { clientInfo: { name: "slop", version: "0.4.18" }, capabilities: { experimentalApi: true } });
|
|
30476
30298
|
sendNotification("initialized", {});
|
|
30477
30299
|
const listed = await callCodexMethod("hooks/list", { cwds: [process.cwd()] });
|
|
30478
30300
|
const ours = listed.data.flatMap((entry) => entry.hooks).filter((hook) => hook.command?.startsWith("slop hook "));
|
|
@@ -30488,19 +30310,23 @@ async function trustCodexHooks(codexHome) {
|
|
|
30488
30310
|
server.kill();
|
|
30489
30311
|
}
|
|
30490
30312
|
}
|
|
30491
|
-
|
|
30492
|
-
|
|
30493
|
-
|
|
30313
|
+
var isCursorHook = () => Boolean(process.env.CURSOR_VERSION);
|
|
30314
|
+
function fetchHookPayloadFromStdin() {
|
|
30315
|
+
return new Promise((resolve6) => {
|
|
30494
30316
|
let data = "";
|
|
30495
30317
|
process.stdin.on("data", (chunk) => data += chunk);
|
|
30496
30318
|
process.stdin.on("end", () => resolve6(data));
|
|
30497
30319
|
setTimeout(() => resolve6(data), 2e3).unref();
|
|
30498
30320
|
});
|
|
30321
|
+
}
|
|
30322
|
+
async function parseHookInput(installedAs, remember = true) {
|
|
30323
|
+
const harness = fetchHarnessAncestor()?.harness ?? installedAs;
|
|
30324
|
+
const input2 = await fetchHookPayloadFromStdin();
|
|
30499
30325
|
let cwd = process.cwd();
|
|
30500
30326
|
let conversation = null;
|
|
30501
30327
|
try {
|
|
30502
30328
|
const parsed = JSON.parse(input2);
|
|
30503
|
-
cwd = parsed.cwd ??
|
|
30329
|
+
cwd = parsed.cwd ?? cwd;
|
|
30504
30330
|
conversation = parsed.session_id ?? null;
|
|
30505
30331
|
} catch {
|
|
30506
30332
|
}
|
|
@@ -30509,22 +30335,24 @@ async function parseHookInput(installedAs, remember = true) {
|
|
|
30509
30335
|
return { cwd, conversation, harness };
|
|
30510
30336
|
}
|
|
30511
30337
|
async function runPromptHook(harness) {
|
|
30338
|
+
if (isCursorHook()) return;
|
|
30512
30339
|
await parseHookInput(harness);
|
|
30513
30340
|
}
|
|
30514
30341
|
async function runToolHook(harness) {
|
|
30342
|
+
if (isCursorHook()) return;
|
|
30515
30343
|
await parseHookInput(harness, false);
|
|
30516
30344
|
}
|
|
30517
30345
|
async function runStartHook(installedAs) {
|
|
30518
|
-
if (isNonInteractiveHarness()) return;
|
|
30346
|
+
if (isCursorHook() || isNonInteractiveHarness()) return;
|
|
30519
30347
|
const { conversation, harness } = await parseHookInput(installedAs);
|
|
30520
30348
|
if (!conversation) return;
|
|
30521
|
-
const carried = harness === "codex" ? " (no wait tool on Codex; a reply becomes your next turn)" :
|
|
30349
|
+
const carried = harness === "codex" ? " (no wait tool on Codex; a reply becomes your next turn)" : "";
|
|
30522
30350
|
const text = `On Slopware Tasks you are ${generateAgentName(conversation)}: that is how people and other agents address you (session who lists everyone). Messages between agents are letters, read when the other side gets to them: write once, reply only when it changes something, never wait for a reply${carried}.`;
|
|
30523
30351
|
process.stdout.write(`${JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: text }, additional_context: text })}
|
|
30524
30352
|
`);
|
|
30525
30353
|
}
|
|
30526
30354
|
async function runStopHook(harness) {
|
|
30527
|
-
if (isNonInteractiveHarness()) return;
|
|
30355
|
+
if (isCursorHook() || isNonInteractiveHarness()) return;
|
|
30528
30356
|
const { cwd } = await parseHookInput(harness);
|
|
30529
30357
|
process.chdir(cwd);
|
|
30530
30358
|
const parts = drainInbox(cwd).map(formatPushBlock);
|
|
@@ -30651,9 +30479,9 @@ function attachUpdateNoticeToTools(list, version2) {
|
|
|
30651
30479
|
function registerMcpCommands(program3, version2) {
|
|
30652
30480
|
const mcp = program3.command("mcp").description("The MCP server: the board and its threads as tools for Claude Code, Codex and any MCP client. Holds your live session while it runs.");
|
|
30653
30481
|
mcp.command("serve", { isDefault: true }).description("Serve MCP over stdio (what the harness runs).").action(() => serveMcp(attachUpdateNoticeToTools(buildTools(), version2), { name: "slop", version: version2 }));
|
|
30654
|
-
mcp.command("install").description("Register the server and the
|
|
30482
|
+
mcp.command("install").description("Register the server and the hooks with Claude Code and Codex on this machine.").action(async () => {
|
|
30655
30483
|
const homes = fetchCodexHomes();
|
|
30656
|
-
const lines = [...fetchClaudeHomes().flatMap((home) => installIntoClaudeHome(home)), ...homes.flatMap((home) => installIntoCodexHome(home)), ...
|
|
30484
|
+
const lines = [...fetchClaudeHomes().flatMap((home) => installIntoClaudeHome(home)), ...homes.flatMap((home) => installIntoCodexHome(home)), ...removeFromCursorHome(join16(homedir4(), ".cursor"))];
|
|
30657
30485
|
let codexPresent = true;
|
|
30658
30486
|
try {
|
|
30659
30487
|
execFileSync6("codex", ["--version"], { stdio: "ignore" });
|
|
@@ -30669,10 +30497,10 @@ function registerMcpCommands(program3, version2) {
|
|
|
30669
30497
|
const known = AgentHarness.safeParse(options.harness);
|
|
30670
30498
|
return known.success ? known.data : "other";
|
|
30671
30499
|
};
|
|
30672
|
-
hook.command("start").description("SessionStart hook (Claude Code, Codex
|
|
30673
|
-
hook.command("tool").description("No longer installed; kept so an older install's hook exits cleanly.").option("--harness <name>", "claude
|
|
30674
|
-
hook.command("prompt").description("No longer installed; kept so an older install's hook exits cleanly.").option("--harness <name>", "claude
|
|
30675
|
-
hook.command("stop").description("No longer installed (Claude Code is woken over its socket, Codex through codex queue); kept so an older install's hook still hands over unread messages.").option("--harness <name>", "claude
|
|
30500
|
+
hook.command("start").description("SessionStart hook (Claude Code, Codex): writes the conversation down so the MCP server is its session, and tells the agent its name and how messages work.").option("--harness <name>", "claude or codex").action((options) => runStartHook(parseHarnessFromOption(options)));
|
|
30501
|
+
hook.command("tool").description("No longer installed; kept so an older install's hook exits cleanly.").option("--harness <name>", "claude or codex").action((options) => runToolHook(parseHarnessFromOption(options)));
|
|
30502
|
+
hook.command("prompt").description("No longer installed; kept so an older install's hook exits cleanly.").option("--harness <name>", "claude or codex").action((options) => runPromptHook(parseHarnessFromOption(options)));
|
|
30503
|
+
hook.command("stop").description("No longer installed (Claude Code is woken over its socket, Codex through codex queue); kept so an older install's hook still hands over unread messages.").option("--harness <name>", "claude or codex").action((options) => runStopHook(parseHarnessFromOption(options)));
|
|
30676
30504
|
}
|
|
30677
30505
|
|
|
30678
30506
|
// src/commands/sessions.ts
|
|
@@ -30760,13 +30588,13 @@ ${written.map((path2) => ` ${path2}`).join("\n")}`);
|
|
|
30760
30588
|
}
|
|
30761
30589
|
|
|
30762
30590
|
// src/index.ts
|
|
30763
|
-
var program2 = new Command().name("slop").description("Slopware Tasks from the terminal. Everything a person can do on the board, an agent can do here.").version("0.4.
|
|
30591
|
+
var program2 = new Command().name("slop").description("Slopware Tasks from the terminal. Everything a person can do on the board, an agent can do here.").version("0.4.18").option("--json", "machine-readable output: JSON on stdout, errors as JSON on stderr").hook("preAction", (_, action) => updateJsonMode(Boolean(action.optsWithGlobals().json))).showHelpAfterError("(run with --help for usage)");
|
|
30764
30592
|
registerAuthCommands(program2);
|
|
30765
30593
|
registerProjectCommands(program2);
|
|
30766
30594
|
var taskCommand = registerTaskCommands(program2);
|
|
30767
30595
|
registerSessionCommands(program2);
|
|
30768
30596
|
registerThreadCommands(program2, taskCommand);
|
|
30769
|
-
registerMcpCommands(program2, "0.4.
|
|
30597
|
+
registerMcpCommands(program2, "0.4.18");
|
|
30770
30598
|
registerGuideCommand(program2);
|
|
30771
30599
|
registerSkillCommands(program2);
|
|
30772
30600
|
program2.parseAsync().catch(exitWithError);
|