sisyphi 1.1.39 → 1.1.40
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/README.md +10 -0
- package/dist/cli.js +283 -213
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +15 -1
- package/dist/daemon.js.map +1 -1
- package/dist/tui.js +72 -58
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -292,7 +292,7 @@ __export(tmux_exports, {
|
|
|
292
292
|
});
|
|
293
293
|
import { execSync as execSync18 } from "child_process";
|
|
294
294
|
import { join as join27 } from "path";
|
|
295
|
-
import { readFileSync as readFileSync30, writeFileSync as writeFileSync16, mkdtempSync, rmSync as rmSync6, cpSync as cpSync3, existsSync as
|
|
295
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync16, mkdtempSync, rmSync as rmSync6, cpSync as cpSync3, existsSync as existsSync28, mkdirSync as mkdirSync13 } from "fs";
|
|
296
296
|
import { tmpdir as tmpdir3 } from "os";
|
|
297
297
|
function getWindowId() {
|
|
298
298
|
const pane = process.env["TMUX_PANE"];
|
|
@@ -346,7 +346,7 @@ function registerDashboardWindow(cwd) {
|
|
|
346
346
|
function setupCompanionPlugin() {
|
|
347
347
|
const srcDir = join27(import.meta.dirname, "templates", "companion-plugin");
|
|
348
348
|
const destDir = join27(globalDir(), "companion-plugin");
|
|
349
|
-
if (!
|
|
349
|
+
if (!existsSync28(destDir)) mkdirSync13(destDir, { recursive: true });
|
|
350
350
|
cpSync3(srcDir, destDir, { recursive: true });
|
|
351
351
|
return destDir;
|
|
352
352
|
}
|
|
@@ -420,7 +420,7 @@ function promptInPopup(prompt, opts) {
|
|
|
420
420
|
`tmux display-popup -E -w ${w} -h ${h} ${shellQuote(`bash -c ${shellQuote(script)}`)}`,
|
|
421
421
|
{ stdio: "inherit", env: EXEC_ENV }
|
|
422
422
|
);
|
|
423
|
-
if (!
|
|
423
|
+
if (!existsSync28(outFile)) return null;
|
|
424
424
|
const result = readFileSync30(outFile, "utf-8").trim();
|
|
425
425
|
return result || null;
|
|
426
426
|
} finally {
|
|
@@ -539,14 +539,14 @@ __export(creds_exports, {
|
|
|
539
539
|
readTailscaleEnv: () => readTailscaleEnv,
|
|
540
540
|
writeTailscaleEnv: () => writeTailscaleEnv
|
|
541
541
|
});
|
|
542
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
542
|
+
import { chmodSync as chmodSync3, existsSync as existsSync29, mkdirSync as mkdirSync15, readFileSync as readFileSync32 } from "fs";
|
|
543
543
|
import { createInterface as createInterface4 } from "readline";
|
|
544
544
|
function isValidProvider(value) {
|
|
545
545
|
return PROVIDERS.includes(value);
|
|
546
546
|
}
|
|
547
547
|
function ensureDeployDir() {
|
|
548
548
|
const dir = deployDir();
|
|
549
|
-
if (!
|
|
549
|
+
if (!existsSync29(dir)) mkdirSync15(dir, { recursive: true, mode: 448 });
|
|
550
550
|
}
|
|
551
551
|
function parseEnvFile(text) {
|
|
552
552
|
const out = {};
|
|
@@ -572,7 +572,7 @@ function serializeEnvFile(values) {
|
|
|
572
572
|
return lines.join("\n") + "\n";
|
|
573
573
|
}
|
|
574
574
|
function readEnvFile(path) {
|
|
575
|
-
if (!
|
|
575
|
+
if (!existsSync29(path)) return null;
|
|
576
576
|
return parseEnvFile(readFileSync32(path, "utf-8"));
|
|
577
577
|
}
|
|
578
578
|
function writeEnvFile(path, values) {
|
|
@@ -668,7 +668,7 @@ var init_creds = __esm({
|
|
|
668
668
|
|
|
669
669
|
// src/cli/index.ts
|
|
670
670
|
import { Command } from "commander";
|
|
671
|
-
import { existsSync as
|
|
671
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync17, readFileSync as readFileSync37 } from "fs";
|
|
672
672
|
import { dirname as dirname13, join as join32 } from "path";
|
|
673
673
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
674
674
|
|
|
@@ -2420,7 +2420,7 @@ var DEFAULT_CONFIG = {
|
|
|
2420
2420
|
},
|
|
2421
2421
|
companionPopup: true,
|
|
2422
2422
|
requiredPlugins: [
|
|
2423
|
-
{ name: "devcore", marketplace: "crouton-kit" }
|
|
2423
|
+
{ name: "devcore", marketplace: "crouton-kit", owner: "crouton-labs" }
|
|
2424
2424
|
]
|
|
2425
2425
|
};
|
|
2426
2426
|
function readJsonFile(filePath) {
|
|
@@ -2494,7 +2494,7 @@ function isMarketplaceInstalled(marketplace) {
|
|
|
2494
2494
|
const output = exec("claude plugins marketplace list");
|
|
2495
2495
|
return output.includes(marketplace);
|
|
2496
2496
|
}
|
|
2497
|
-
function installMarketplace(marketplace, owner
|
|
2497
|
+
function installMarketplace(marketplace, owner) {
|
|
2498
2498
|
console.log(`Adding marketplace: ${owner}/${marketplace}`);
|
|
2499
2499
|
execSync2(`claude plugins marketplace add ${owner}/${marketplace}`, { stdio: "inherit" });
|
|
2500
2500
|
}
|
|
@@ -2532,7 +2532,7 @@ async function ensureRequiredPlugins(cwd) {
|
|
|
2532
2532
|
if (existing) continue;
|
|
2533
2533
|
console.log(`Required plugin ${key} not found \u2014 installing...`);
|
|
2534
2534
|
if (!isMarketplaceInstalled(plugin.marketplace)) {
|
|
2535
|
-
installMarketplace(plugin.marketplace);
|
|
2535
|
+
installMarketplace(plugin.marketplace, plugin.owner);
|
|
2536
2536
|
}
|
|
2537
2537
|
installPlugin(key);
|
|
2538
2538
|
const verified = resolveInstalledPlugin(key);
|
|
@@ -2587,6 +2587,7 @@ function isInstalled() {
|
|
|
2587
2587
|
async function ensureDaemonInstalled() {
|
|
2588
2588
|
if (process.platform !== "darwin") return;
|
|
2589
2589
|
const sisyphusPlugin = ensureSisyphusPluginInstalled();
|
|
2590
|
+
await ensureRequiredPlugins(process.cwd());
|
|
2590
2591
|
if (!isInstalled()) {
|
|
2591
2592
|
const nodePath = process.execPath;
|
|
2592
2593
|
const daemonPath = daemonBinPath();
|
|
@@ -2597,7 +2598,6 @@ async function ensureDaemonInstalled() {
|
|
|
2597
2598
|
writeFileSync2(plistPath(), plist, "utf8");
|
|
2598
2599
|
execSync3(`launchctl load -w ${plistPath()}`);
|
|
2599
2600
|
const keybindResult = await setupTmuxKeybind();
|
|
2600
|
-
await ensureRequiredPlugins(process.cwd());
|
|
2601
2601
|
printGettingStarted(keybindResult, sisyphusPlugin);
|
|
2602
2602
|
}
|
|
2603
2603
|
await waitForDaemon();
|
|
@@ -2935,14 +2935,14 @@ function registerStart(program2) {
|
|
|
2935
2935
|
process.exit(1);
|
|
2936
2936
|
}
|
|
2937
2937
|
const sessionId = response.data?.sessionId;
|
|
2938
|
-
console.
|
|
2938
|
+
console.error(`Task handed off to sisyphus orchestrator (session ${sessionId})`);
|
|
2939
2939
|
if (opts.tmuxCheck === false) {
|
|
2940
2940
|
const tmuxSessionName2 = response.data?.tmuxSessionName;
|
|
2941
2941
|
if (tmuxSessionName2) {
|
|
2942
|
-
console.
|
|
2943
|
-
console.
|
|
2942
|
+
console.error(`Tmux session: ${tmuxSessionName2}`);
|
|
2943
|
+
console.error(` tmux attach -t ${tmuxSessionName2}`);
|
|
2944
2944
|
}
|
|
2945
|
-
console.
|
|
2945
|
+
console.error(`Monitor: sis status ${sessionId}`);
|
|
2946
2946
|
return;
|
|
2947
2947
|
}
|
|
2948
2948
|
let tmuxSession;
|
|
@@ -2986,7 +2986,7 @@ function registerStart(program2) {
|
|
|
2986
2986
|
if (!process.env["TMUX"]) {
|
|
2987
2987
|
attachToTmuxSession(tmuxSession);
|
|
2988
2988
|
}
|
|
2989
|
-
console.
|
|
2989
|
+
console.error(`Monitor: sis status ${sessionId}`);
|
|
2990
2990
|
});
|
|
2991
2991
|
}
|
|
2992
2992
|
|
|
@@ -3039,24 +3039,38 @@ function statusColor(status) {
|
|
|
3039
3039
|
return "white";
|
|
3040
3040
|
}
|
|
3041
3041
|
}
|
|
3042
|
+
var COLOR_ENABLED = process.env["FORCE_COLOR"] === "1" || process.stdout.isTTY === true && process.env["NO_COLOR"] === void 0 && process.env["TERM"] !== "dumb";
|
|
3043
|
+
function wrap(open, close = "\x1B[0m") {
|
|
3044
|
+
return (s) => COLOR_ENABLED ? `${open}${s}${close}` : s;
|
|
3045
|
+
}
|
|
3046
|
+
var bold = wrap("\x1B[1m");
|
|
3047
|
+
var dim = wrap("\x1B[2m");
|
|
3048
|
+
var red = wrap("\x1B[31m");
|
|
3049
|
+
var green = wrap("\x1B[32m");
|
|
3050
|
+
var yellow = wrap("\x1B[33m");
|
|
3051
|
+
var cyan = wrap("\x1B[36m");
|
|
3052
|
+
var gray = wrap("\x1B[90m");
|
|
3053
|
+
var magenta = wrap("\x1B[35m");
|
|
3054
|
+
var white = wrap("\x1B[37m");
|
|
3055
|
+
var COLOR_FNS = {
|
|
3056
|
+
red,
|
|
3057
|
+
green,
|
|
3058
|
+
yellow,
|
|
3059
|
+
cyan,
|
|
3060
|
+
gray,
|
|
3061
|
+
magenta,
|
|
3062
|
+
white,
|
|
3063
|
+
bold,
|
|
3064
|
+
dim
|
|
3065
|
+
};
|
|
3066
|
+
function colorize(text, colorName) {
|
|
3067
|
+
const fn = COLOR_FNS[colorName];
|
|
3068
|
+
return fn ? fn(text) : text;
|
|
3069
|
+
}
|
|
3042
3070
|
|
|
3043
3071
|
// src/cli/commands/status.ts
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
yellow: "\x1B[33m",
|
|
3047
|
-
cyan: "\x1B[36m",
|
|
3048
|
-
red: "\x1B[31m",
|
|
3049
|
-
gray: "\x1B[90m",
|
|
3050
|
-
white: "\x1B[37m"
|
|
3051
|
-
};
|
|
3052
|
-
var RESET = "\x1B[0m";
|
|
3053
|
-
var BOLD = "\x1B[1m";
|
|
3054
|
-
var DIM = "\x1B[2m";
|
|
3055
|
-
function colorize(text, status) {
|
|
3056
|
-
const colorName = statusColor(status);
|
|
3057
|
-
const code = COLOR_CODES[colorName];
|
|
3058
|
-
if (!code) return `${text}\x1B[0m`;
|
|
3059
|
-
return `${code}${text}\x1B[0m`;
|
|
3072
|
+
function colorize2(text, status) {
|
|
3073
|
+
return colorize(text, statusColor(status));
|
|
3060
3074
|
}
|
|
3061
3075
|
function inferOrchestratorPhase(session2) {
|
|
3062
3076
|
const cycles = session2.orchestratorCycles;
|
|
@@ -3077,15 +3091,15 @@ function inferOrchestratorPhase(session2) {
|
|
|
3077
3091
|
}
|
|
3078
3092
|
}
|
|
3079
3093
|
function formatAgent(agent2, verbose) {
|
|
3080
|
-
const status =
|
|
3081
|
-
const name =
|
|
3082
|
-
const type =
|
|
3094
|
+
const status = colorize2(agent2.status, agent2.status);
|
|
3095
|
+
const name = bold(agent2.name);
|
|
3096
|
+
const type = dim(`(${agent2.agentType})`);
|
|
3083
3097
|
const duration = formatDuration(agent2.activeMs);
|
|
3084
|
-
let line = ` ${agent2.id} ${name} ${type} \u2014 ${status} ${
|
|
3098
|
+
let line = ` ${agent2.id} ${name} ${type} \u2014 ${status} ${dim(`(${duration})`)}`;
|
|
3085
3099
|
if (verbose && agent2.instruction) {
|
|
3086
3100
|
const truncated = agent2.instruction.length > 200 ? agent2.instruction.slice(0, 200) + "..." : agent2.instruction;
|
|
3087
3101
|
line += `
|
|
3088
|
-
${
|
|
3102
|
+
${dim(`Instruction: ${truncated}`)}`;
|
|
3089
3103
|
}
|
|
3090
3104
|
if (agent2.reports.length > 0) {
|
|
3091
3105
|
for (const r of agent2.reports) {
|
|
@@ -3103,10 +3117,10 @@ function formatAgent(agent2, verbose) {
|
|
|
3103
3117
|
function formatCycle(cycle, phase) {
|
|
3104
3118
|
let duration;
|
|
3105
3119
|
if (cycle.completedAt) {
|
|
3106
|
-
duration = ` ${
|
|
3120
|
+
duration = ` ${dim(`(${formatDuration(cycle.activeMs)})`)}`;
|
|
3107
3121
|
} else {
|
|
3108
3122
|
const elapsed = formatDuration(cycle.activeMs);
|
|
3109
|
-
duration = ` ${
|
|
3123
|
+
duration = ` ${dim(`(running, ${elapsed})`)}`;
|
|
3110
3124
|
}
|
|
3111
3125
|
const agents = cycle.agentsSpawned.length > 0 ? ` \u2014 agents: ${cycle.agentsSpawned.join(", ")}` : "";
|
|
3112
3126
|
const phaseStr = phase ? ` \u2014 orchestrator: ${phase}` : "";
|
|
@@ -3155,10 +3169,10 @@ function capturePaneOutput(paneId, lines = 50) {
|
|
|
3155
3169
|
}
|
|
3156
3170
|
}
|
|
3157
3171
|
function printSession(session2, verbose) {
|
|
3158
|
-
const status =
|
|
3172
|
+
const status = colorize2(session2.status, session2.status);
|
|
3159
3173
|
const sessionDuration = formatDuration(session2.createdAt, session2.completedAt);
|
|
3160
3174
|
console.log(`
|
|
3161
|
-
${
|
|
3175
|
+
${bold(`Session: ${session2.id}`)}`);
|
|
3162
3176
|
console.log(` Status: ${status}`);
|
|
3163
3177
|
const effortLabel = session2.effort != null ? session2.effort : "high (default)";
|
|
3164
3178
|
console.log(` Effort: ${effortLabel}`);
|
|
@@ -3179,7 +3193,7 @@ ${BOLD}Session: ${session2.id}${RESET}`);
|
|
|
3179
3193
|
if (session2.handoff) {
|
|
3180
3194
|
const h = session2.handoff;
|
|
3181
3195
|
if (h.lastError) {
|
|
3182
|
-
console.log(` Handoff: ${
|
|
3196
|
+
console.log(` Handoff: ${red("error")} \u2014 ${h.lastError}`);
|
|
3183
3197
|
} else if (h.reclaimedAt) {
|
|
3184
3198
|
const where = h.target ? `${h.target.provider}:${h.target.repo}` : "cloud";
|
|
3185
3199
|
console.log(` Handoff: reclaimed from ${where} at ${h.reclaimedAt}`);
|
|
@@ -3194,27 +3208,27 @@ ${BOLD}Session: ${session2.id}${RESET}`);
|
|
|
3194
3208
|
const runningAgents = session2.agents.filter((a) => a.status === "running");
|
|
3195
3209
|
if (runningAgents.length > 0) {
|
|
3196
3210
|
console.log(`
|
|
3197
|
-
${
|
|
3211
|
+
${bold(`Active agents (${runningAgents.length}):`)}`);
|
|
3198
3212
|
for (const agent2 of runningAgents) {
|
|
3199
|
-
const name =
|
|
3200
|
-
const type =
|
|
3213
|
+
const name = bold(agent2.name);
|
|
3214
|
+
const type = dim(`(${agent2.agentType})`);
|
|
3201
3215
|
const duration = formatDuration(agent2.activeMs);
|
|
3202
3216
|
console.log(` ${agent2.id} ${name} ${type} running ${duration}`);
|
|
3203
3217
|
if (verbose && agent2.instruction) {
|
|
3204
3218
|
const truncated = agent2.instruction.length > 200 ? agent2.instruction.slice(0, 200) + "..." : agent2.instruction;
|
|
3205
|
-
console.log(` ${
|
|
3219
|
+
console.log(` ${dim(`Instruction: ${truncated}`)}`);
|
|
3206
3220
|
}
|
|
3207
3221
|
}
|
|
3208
3222
|
}
|
|
3209
3223
|
const roadmap = readRoadmap(session2.cwd, session2.id);
|
|
3210
3224
|
if (roadmap) {
|
|
3211
3225
|
console.log(`
|
|
3212
|
-
${
|
|
3226
|
+
${bold("Roadmap:")}`);
|
|
3213
3227
|
console.log(roadmap);
|
|
3214
3228
|
}
|
|
3215
3229
|
if (session2.orchestratorCycles.length > 0) {
|
|
3216
3230
|
console.log(`
|
|
3217
|
-
${
|
|
3231
|
+
${bold("Cycles:")}`);
|
|
3218
3232
|
const cycles = session2.orchestratorCycles;
|
|
3219
3233
|
for (let i = 0; i < cycles.length; i++) {
|
|
3220
3234
|
const isLast = i === cycles.length - 1;
|
|
@@ -3225,12 +3239,12 @@ ${BOLD}Roadmap:${RESET}`);
|
|
|
3225
3239
|
if (log) {
|
|
3226
3240
|
const lines = log.split("\n");
|
|
3227
3241
|
const preview = lines.slice(0, 20).join("\n");
|
|
3228
|
-
console.log(` ${
|
|
3242
|
+
console.log(` ${dim("--- cycle log ---")}`);
|
|
3229
3243
|
for (const line of preview.split("\n")) {
|
|
3230
|
-
console.log(` ${
|
|
3244
|
+
console.log(` ${dim(line)}`);
|
|
3231
3245
|
}
|
|
3232
3246
|
if (lines.length > 20) {
|
|
3233
|
-
console.log(` ${
|
|
3247
|
+
console.log(` ${dim(`... (${lines.length - 20} more lines)`)}`);
|
|
3234
3248
|
}
|
|
3235
3249
|
}
|
|
3236
3250
|
}
|
|
@@ -3238,7 +3252,7 @@ ${BOLD}Roadmap:${RESET}`);
|
|
|
3238
3252
|
}
|
|
3239
3253
|
if (session2.agents.length > 0) {
|
|
3240
3254
|
console.log(`
|
|
3241
|
-
${
|
|
3255
|
+
${bold("Agents:")}`);
|
|
3242
3256
|
for (const agent2 of session2.agents) {
|
|
3243
3257
|
console.log(formatAgent(agent2, verbose));
|
|
3244
3258
|
}
|
|
@@ -3268,7 +3282,7 @@ ${BOLD}Roadmap:${RESET}`);
|
|
|
3268
3282
|
}
|
|
3269
3283
|
if (verbose && session2.completionReport) {
|
|
3270
3284
|
console.log(`
|
|
3271
|
-
${
|
|
3285
|
+
${bold("Completion Report:")}`);
|
|
3272
3286
|
console.log(session2.completionReport);
|
|
3273
3287
|
}
|
|
3274
3288
|
}
|
|
@@ -3300,38 +3314,45 @@ function registerStatus(program2) {
|
|
|
3300
3314
|
|
|
3301
3315
|
// src/cli/commands/list.ts
|
|
3302
3316
|
import { basename as basename3 } from "path";
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3317
|
+
function statusColor2(s) {
|
|
3318
|
+
switch (s) {
|
|
3319
|
+
case "active":
|
|
3320
|
+
return "green";
|
|
3321
|
+
case "paused":
|
|
3322
|
+
return "yellow";
|
|
3323
|
+
case "completed":
|
|
3324
|
+
return "cyan";
|
|
3325
|
+
default:
|
|
3326
|
+
return "";
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
function colorStatus(s) {
|
|
3330
|
+
const name = statusColor2(s);
|
|
3331
|
+
if (!name) return s;
|
|
3332
|
+
return colorize(s, name);
|
|
3333
|
+
}
|
|
3313
3334
|
function handoffAnnotation(h) {
|
|
3314
3335
|
if (!h) return "";
|
|
3315
3336
|
if (h.lastError) {
|
|
3316
|
-
return ` ${
|
|
3337
|
+
return ` ${red(`handoff error: ${h.lastError}`)}`;
|
|
3317
3338
|
}
|
|
3318
3339
|
if (h.reclaimedAt) {
|
|
3319
|
-
return ` ${
|
|
3340
|
+
return ` ${dim("(reclaimed)")}`;
|
|
3320
3341
|
}
|
|
3321
3342
|
if (h.sentAt && h.target) {
|
|
3322
|
-
return ` ${
|
|
3343
|
+
return ` ${magenta(`\u2192 ${h.target.provider}:${h.target.repo}`)}`;
|
|
3323
3344
|
}
|
|
3324
3345
|
if (h.target) {
|
|
3325
|
-
return ` ${
|
|
3346
|
+
return ` ${magenta(`handoff queued \u2192 ${h.target.provider}:${h.target.repo}`)}`;
|
|
3326
3347
|
}
|
|
3327
|
-
return ` ${
|
|
3348
|
+
return ` ${magenta("quiesce queued")}`;
|
|
3328
3349
|
}
|
|
3329
3350
|
function truncateTask(task, max) {
|
|
3330
3351
|
if (task.length <= max) return task;
|
|
3331
3352
|
return task.slice(0, max - 1) + "\u2026";
|
|
3332
3353
|
}
|
|
3333
3354
|
function registerList(program2) {
|
|
3334
|
-
program2.command("list").description("List sessions (defaults to current project)").option("-a, --all", "Show sessions from all projects").option("--cwd <path>", "Project directory to list sessions for (overrides SISYPHUS_CWD)").action(async (opts) => {
|
|
3355
|
+
program2.command("list").description("List sessions (defaults to current project)").option("-a, --all", "Show sessions from all projects").option("--cwd <path>", "Project directory to list sessions for (overrides SISYPHUS_CWD)").option("-j, --json", "Output raw JSON").action(async (opts) => {
|
|
3335
3356
|
const cwd = opts.cwd ?? process.env["SISYPHUS_CWD"] ?? process.cwd();
|
|
3336
3357
|
const request = { type: "list", cwd, all: opts.all };
|
|
3337
3358
|
const response = await sendRequest(request);
|
|
@@ -3339,29 +3360,32 @@ function registerList(program2) {
|
|
|
3339
3360
|
const sessions = response.data?.sessions ?? [];
|
|
3340
3361
|
const totalCount = response.data?.totalCount;
|
|
3341
3362
|
const filtered = response.data?.filtered;
|
|
3363
|
+
if (opts.json) {
|
|
3364
|
+
console.log(JSON.stringify(sessions));
|
|
3365
|
+
return;
|
|
3366
|
+
}
|
|
3342
3367
|
if (sessions.length === 0) {
|
|
3343
3368
|
if (filtered && totalCount && totalCount > 0) {
|
|
3344
3369
|
console.log(`No sessions in this project. ${totalCount} session(s) in other projects.`);
|
|
3345
|
-
console.log(`${
|
|
3370
|
+
console.log(`${dim("Run ")}sis list --all${dim(" to show all.")}`);
|
|
3346
3371
|
} else {
|
|
3347
3372
|
console.log("No sessions");
|
|
3348
3373
|
}
|
|
3349
3374
|
return;
|
|
3350
3375
|
}
|
|
3351
3376
|
for (const s of sessions) {
|
|
3352
|
-
const
|
|
3353
|
-
const
|
|
3354
|
-
const agents = `${DIM2}${s.agentCount} agent(s)${RESET2}`;
|
|
3377
|
+
const status = colorStatus(s.status);
|
|
3378
|
+
const agents = dim(`${s.agentCount} agent(s)`);
|
|
3355
3379
|
const task = truncateTask(s.task, 60);
|
|
3356
|
-
const label = s.name ? `${s.name} ${
|
|
3357
|
-
const cwdLabel = opts.all && s.cwd ? ` ${
|
|
3380
|
+
const label = s.name ? `${s.name} ${dim(`(${s.id.slice(0, 8)})`)}` : s.id;
|
|
3381
|
+
const cwdLabel = opts.all && s.cwd ? ` ${dim(basename3(s.cwd))}` : "";
|
|
3358
3382
|
const handoffLabel = handoffAnnotation(s.handoff);
|
|
3359
|
-
console.log(` ${
|
|
3383
|
+
console.log(` ${bold(label)} ${status} ${agents} ${task}${cwdLabel}${handoffLabel}`);
|
|
3360
3384
|
}
|
|
3361
3385
|
if (filtered && totalCount && totalCount > sessions.length) {
|
|
3362
3386
|
const otherCount = totalCount - sessions.length;
|
|
3363
3387
|
console.log(`
|
|
3364
|
-
${
|
|
3388
|
+
${dim(`${otherCount} more session(s) in other projects. Run `)}sis list --all${dim(" to show all.")}`);
|
|
3365
3389
|
}
|
|
3366
3390
|
} else {
|
|
3367
3391
|
console.error(`Error: ${response.error}`);
|
|
@@ -3423,7 +3447,7 @@ function registerTell(program2) {
|
|
|
3423
3447
|
};
|
|
3424
3448
|
const response = await sendRequest(request);
|
|
3425
3449
|
if (response.ok) {
|
|
3426
|
-
console.
|
|
3450
|
+
console.error(`Sent to ${targetRaw}${submit2 ? "" : " (not submitted)"}`);
|
|
3427
3451
|
} else {
|
|
3428
3452
|
console.error(`Error: ${response.error}`);
|
|
3429
3453
|
process.exit(1);
|
|
@@ -3500,7 +3524,7 @@ function summaryLine(entry) {
|
|
|
3500
3524
|
return `${role} ${ts} ${preview}`;
|
|
3501
3525
|
}
|
|
3502
3526
|
function registerRead(program2) {
|
|
3503
|
-
program2.command("read <target>").description("Print the Claude conversation transcript for a target ('orchestrator' or 'agent-NNN').").option("--session <sessionId>", "Session ID (defaults to SISYPHUS_SESSION_ID)").option("--cycle <n>", "Orchestrator cycle number (default: most recent live, else last completed)").option("--tail <n>", "Show last N turns", void 0).option("--head <n>", "Show first N turns", void 0).option("--raw", "Print raw JSONL (no formatting, no filtering)").option("--summary", "One-line-per-turn summary instead of full content").option("--tool-detail", "Include full tool inputs/outputs (default: truncated to 400/600 chars)").action(async (targetRaw, opts) => {
|
|
3527
|
+
program2.command("read <target>").description("Print the Claude conversation transcript for a target ('orchestrator' or 'agent-NNN').").option("--session <sessionId>", "Session ID (defaults to SISYPHUS_SESSION_ID)").option("--cycle <n>", "Orchestrator cycle number (default: most recent live, else last completed)").option("--tail <n>", "Show last N turns", void 0).option("--head <n>", "Show first N turns", void 0).option("--raw", "Print raw JSONL (no formatting, no filtering)").option("--summary", "One-line-per-turn summary instead of full content").option("--tool-detail", "Include full tool inputs/outputs (default: truncated to 400/600 chars)").option("-j, --json", "Output JSONL \u2014 one JSON object per turn (mutually exclusive with --raw and --summary)").action(async (targetRaw, opts) => {
|
|
3504
3528
|
const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;
|
|
3505
3529
|
if (!sessionId) {
|
|
3506
3530
|
console.error("Error: provide --session or set SISYPHUS_SESSION_ID");
|
|
@@ -3562,6 +3586,14 @@ function registerRead(program2) {
|
|
|
3562
3586
|
process.exit(1);
|
|
3563
3587
|
}
|
|
3564
3588
|
const raw = readFileSync7(path, "utf-8");
|
|
3589
|
+
if (opts.json && opts.raw) {
|
|
3590
|
+
console.error("Error: --json and --raw are mutually exclusive");
|
|
3591
|
+
process.exit(1);
|
|
3592
|
+
}
|
|
3593
|
+
if (opts.json && opts.summary) {
|
|
3594
|
+
console.error("Error: --json and --summary are mutually exclusive");
|
|
3595
|
+
process.exit(1);
|
|
3596
|
+
}
|
|
3565
3597
|
if (opts.raw) {
|
|
3566
3598
|
process.stdout.write(raw);
|
|
3567
3599
|
return;
|
|
@@ -3586,6 +3618,16 @@ function registerRead(program2) {
|
|
|
3586
3618
|
entries = entries.slice(-tail);
|
|
3587
3619
|
sliceNote = sliceNote ? `${sliceNote}, then last ${tail}` : `last ${tail} of ${totalTurns}`;
|
|
3588
3620
|
}
|
|
3621
|
+
if (opts.json) {
|
|
3622
|
+
for (const e of entries) {
|
|
3623
|
+
console.log(JSON.stringify({
|
|
3624
|
+
role: e.type,
|
|
3625
|
+
timestamp: e.timestamp,
|
|
3626
|
+
content: e.message?.content
|
|
3627
|
+
}));
|
|
3628
|
+
}
|
|
3629
|
+
return;
|
|
3630
|
+
}
|
|
3589
3631
|
console.log(`=== ${label} \u2014 ${entries.length} turn(s)${sliceNote ? ` (${sliceNote})` : ""} ===`);
|
|
3590
3632
|
console.log(`transcript: ${path}
|
|
3591
3633
|
`);
|
|
@@ -3636,7 +3678,7 @@ function registerMessage(program2) {
|
|
|
3636
3678
|
const request = { type: "message", sessionId, content, source, ...opts.agent ? { agentId: opts.agent } : {} };
|
|
3637
3679
|
const response = await sendRequest(request);
|
|
3638
3680
|
if (response.ok) {
|
|
3639
|
-
console.
|
|
3681
|
+
console.error("Message queued");
|
|
3640
3682
|
} else {
|
|
3641
3683
|
console.error(`Error: ${response.error}`);
|
|
3642
3684
|
process.exit(1);
|
|
@@ -5166,7 +5208,7 @@ function registerReport(program2) {
|
|
|
5166
5208
|
import { existsSync as existsSync15, readFileSync as readFileSync18 } from "fs";
|
|
5167
5209
|
var AWAIT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
5168
5210
|
function registerAwait(program2) {
|
|
5169
|
-
program2.command("await").description("Block until an agent reaches a terminal status, then print its final report inline. Marks the agent as consumed-inline so its report is suppressed from the next cycle.").argument("<agentId>", "Agent ID to await").option("--session <sessionId>", "Session ID (defaults to SISYPHUS_SESSION_ID env var)").action(async (agentId, opts) => {
|
|
5211
|
+
program2.command("await").description("Block until an agent reaches a terminal status, then print its final report inline. Marks the agent as consumed-inline so its report is suppressed from the next cycle.").argument("<agentId>", "Agent ID to await").option("--session <sessionId>", "Session ID (defaults to SISYPHUS_SESSION_ID env var)").option("-j, --json", "Output result as a single JSON object (report as string field)").action(async (agentId, opts) => {
|
|
5170
5212
|
assertTmux();
|
|
5171
5213
|
const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;
|
|
5172
5214
|
if (!sessionId) {
|
|
@@ -5184,19 +5226,24 @@ function registerAwait(program2) {
|
|
|
5184
5226
|
const reportPath = data.reportPath;
|
|
5185
5227
|
const agentName = data.agentName;
|
|
5186
5228
|
const agentType = data.agentType;
|
|
5187
|
-
|
|
5188
|
-
const label = shortType ? `${shortType}-${agentName}` : agentName;
|
|
5189
|
-
console.log(`[${status}] ${agentId} (${label})`);
|
|
5229
|
+
let report = "";
|
|
5190
5230
|
if (reportPath && existsSync15(reportPath)) {
|
|
5191
5231
|
try {
|
|
5192
|
-
|
|
5193
|
-
if (body.length > 0) {
|
|
5194
|
-
process.stdout.write(body.endsWith("\n") ? body : body + "\n");
|
|
5195
|
-
}
|
|
5232
|
+
report = readFileSync18(reportPath, "utf-8");
|
|
5196
5233
|
} catch (err) {
|
|
5197
5234
|
console.error(`Warning: could not read report at ${reportPath}: ${err instanceof Error ? err.message : err}`);
|
|
5198
5235
|
}
|
|
5199
5236
|
}
|
|
5237
|
+
if (opts.json) {
|
|
5238
|
+
console.log(JSON.stringify({ agentId, status, agentName, agentType, reportPath, report }));
|
|
5239
|
+
return;
|
|
5240
|
+
}
|
|
5241
|
+
const shortType = agentType && agentType !== "worker" ? agentType.replace(/^sisyphus:/, "") : "";
|
|
5242
|
+
const label = shortType ? `${shortType}-${agentName}` : agentName;
|
|
5243
|
+
console.log(`[${status}] ${agentId} (${label})`);
|
|
5244
|
+
if (report.length > 0) {
|
|
5245
|
+
process.stdout.write(report.endsWith("\n") ? report : report + "\n");
|
|
5246
|
+
}
|
|
5200
5247
|
});
|
|
5201
5248
|
}
|
|
5202
5249
|
|
|
@@ -5733,10 +5780,10 @@ function runOnboarding() {
|
|
|
5733
5780
|
if (!tmuxAlreadyInstalled && process.platform === "darwin") {
|
|
5734
5781
|
tmuxAutoInstalled = tryAutoInstallTmux();
|
|
5735
5782
|
tmuxInstalled = tmuxAutoInstalled;
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5783
|
+
}
|
|
5784
|
+
if (tmuxInstalled && !hasExistingTmuxConf()) {
|
|
5785
|
+
writeTmuxDefaults();
|
|
5786
|
+
tmuxDefaultsWritten = true;
|
|
5740
5787
|
}
|
|
5741
5788
|
let itermOptionKey = { checked: false, allCorrect: true, incorrectProfiles: [] };
|
|
5742
5789
|
if (terminal.isIterm) {
|
|
@@ -7010,6 +7057,7 @@ function registerConfigureUpload(program2) {
|
|
|
7010
7057
|
|
|
7011
7058
|
// src/cli/commands/getting-started.ts
|
|
7012
7059
|
import { execSync as execSync16 } from "child_process";
|
|
7060
|
+
import { existsSync as existsSync21 } from "fs";
|
|
7013
7061
|
import { dirname as dirname7, join as join20 } from "path";
|
|
7014
7062
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7015
7063
|
function templatePath(name) {
|
|
@@ -7380,6 +7428,7 @@ sis admin getting-started --tutorial 4
|
|
|
7380
7428
|
`);
|
|
7381
7429
|
}
|
|
7382
7430
|
function printStep4() {
|
|
7431
|
+
const demoPath = join20(process.cwd(), "tmp", "sisyphus-tutorial-demo");
|
|
7383
7432
|
console.log(`
|
|
7384
7433
|
<claude-instructions>
|
|
7385
7434
|
# Sisyphus Getting Started \u2014 Step 4: Demo Session
|
|
@@ -7421,26 +7470,29 @@ Have the user confirm they understand these keybinds before proceeding.
|
|
|
7421
7470
|
|
|
7422
7471
|
### 3. Set expectations, copy demo app, and launch
|
|
7423
7472
|
|
|
7424
|
-
First, copy the demo todo app
|
|
7473
|
+
First, copy the demo todo app into ./tmp/ under the user's current directory and init a git repo (sisyphus needs git). Run from the user's current shell \u2014 don't \`cd\` away first:
|
|
7425
7474
|
\`\`\`
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
git -C
|
|
7430
|
-
git -C
|
|
7475
|
+
mkdir -p ${join20(process.cwd(), "tmp")}
|
|
7476
|
+
rm -rf ${demoPath}
|
|
7477
|
+
cp -r ${templatePath("tutorial-demo")} ${demoPath}
|
|
7478
|
+
git -C ${demoPath} init
|
|
7479
|
+
git -C ${demoPath} add -A
|
|
7480
|
+
git -C ${demoPath} commit -m "Initial todo app"
|
|
7431
7481
|
\`\`\`
|
|
7432
7482
|
|
|
7433
7483
|
Tell the user:
|
|
7434
7484
|
|
|
7435
|
-
> I've set up a small todo app in
|
|
7436
|
-
> with a few files.
|
|
7485
|
+
> I've set up a small todo app in ${demoPath} \u2014 a Node.js API
|
|
7486
|
+
> with a few files. It lives under \`tmp/\` in your current directory so sisyphus
|
|
7487
|
+
> runs somewhere you can see, not in system /tmp. I'm going to launch sisyphus
|
|
7488
|
+
> on it. Here's what will happen:
|
|
7437
7489
|
> 1. The dashboard opens automatically (you'll be switched to it)
|
|
7438
7490
|
> 2. Press **Ctrl+p** to come back here to Claude \u2014 I'll guide you through what to watch
|
|
7439
7491
|
> 3. The session takes a few minutes. You can watch agents work live!
|
|
7440
7492
|
|
|
7441
|
-
Then launch from the demo directory:
|
|
7493
|
+
Then launch from the demo directory (sisyphus operates in whichever directory you launch it from, so we \`cd\` in so the \`.sisyphus/\` state lands inside the demo):
|
|
7442
7494
|
\`\`\`
|
|
7443
|
-
cd
|
|
7495
|
+
cd ${demoPath} && sis start "Add three improvements to this todo app: (1) add a priority field (high/medium/low) to todos, (2) add a GET /todos/stats endpoint that returns counts of total/done/pending todos, (3) add tests for the new features. Explain your thinking at each step." -c "TUTORIAL DEMO: A user is watching this session to learn how sisyphus works. Be EXTRA VERBOSE \u2014 explain your reasoning, narrate what you're doing, and make your planning visible. When spawning agents, give each agent context that this is a tutorial demo and they should explain their work clearly. Keep scope small: 2-3 agents, 1-2 cycles."
|
|
7444
7496
|
\`\`\`
|
|
7445
7497
|
|
|
7446
7498
|
After launching, tell them:
|
|
@@ -7483,8 +7535,8 @@ Between polls, encourage the user to explore:
|
|
|
7483
7535
|
|
|
7484
7536
|
Once the session shows "completed":
|
|
7485
7537
|
|
|
7486
|
-
- Show them what the agents built: \`cd
|
|
7487
|
-
- Run the tests to prove the work: \`cd
|
|
7538
|
+
- Show them what the agents built: \`cd ${demoPath} && git log --oneline\`
|
|
7539
|
+
- Run the tests to prove the work: \`cd ${demoPath} && node --test test.js\`
|
|
7488
7540
|
- Show the session artifacts: find the session dir in \`.sisyphus/sessions/\` and show \`roadmap.md\`
|
|
7489
7541
|
- Explain: "Every session creates a roadmap, agent reports, and logs \u2014 all stored in .sisyphus/sessions/"
|
|
7490
7542
|
|
|
@@ -7498,6 +7550,8 @@ sis admin getting-started --tutorial 5
|
|
|
7498
7550
|
`);
|
|
7499
7551
|
}
|
|
7500
7552
|
function printStep5() {
|
|
7553
|
+
const demoPath = join20(process.cwd(), "tmp", "sisyphus-tutorial-demo");
|
|
7554
|
+
const demoExists = existsSync21(demoPath);
|
|
7501
7555
|
let recentCommits = "";
|
|
7502
7556
|
let topLevelFiles = "";
|
|
7503
7557
|
try {
|
|
@@ -7512,6 +7566,10 @@ function printStep5() {
|
|
|
7512
7566
|
<claude-instructions>
|
|
7513
7567
|
# Sisyphus Getting Started \u2014 Step 5: What's Next
|
|
7514
7568
|
|
|
7569
|
+
## Environment Data
|
|
7570
|
+
- demoPath: ${demoPath}
|
|
7571
|
+
- demoExists: ${demoExists}
|
|
7572
|
+
|
|
7515
7573
|
## Codebase Context
|
|
7516
7574
|
<recent-commits>
|
|
7517
7575
|
${recentCommits || "(no git repo detected)"}
|
|
@@ -7574,14 +7632,38 @@ Or directly: \`sis start "your task" -c "any background context"\`
|
|
|
7574
7632
|
|
|
7575
7633
|
Look at the recent commits and top-level files above. Based on what you can see of their project, suggest 2-3 concrete sisyphus-scale tasks they could try. Be specific to their codebase \u2014 reference actual directories, patterns, or areas you can see.
|
|
7576
7634
|
|
|
7577
|
-
If there are no commits or files (e.g., they ran this from /
|
|
7635
|
+
If there are no commits or files (e.g., they ran this from an empty scratch dir, or from the tutorial demo dir itself at tmp/sisyphus-tutorial-demo), skip this section.
|
|
7578
7636
|
|
|
7579
7637
|
Format as:
|
|
7580
7638
|
> Based on your codebase, here are some tasks sisyphus would be great for:
|
|
7581
7639
|
> - "..."
|
|
7582
7640
|
> - "..."
|
|
7583
7641
|
|
|
7584
|
-
### 5.
|
|
7642
|
+
### 5. Clean up the demo dir
|
|
7643
|
+
|
|
7644
|
+
**Only if demoExists is true** (see Environment Data above). The tutorial dropped a
|
|
7645
|
+
demo todo app at \`${demoPath}\` with its own \`.sisyphus/\` session state. Ask the user
|
|
7646
|
+
before deleting \u2014 they may want to poke around the session files first.
|
|
7647
|
+
|
|
7648
|
+
Ask exactly:
|
|
7649
|
+
|
|
7650
|
+
> Want me to remove the tutorial demo at \`${demoPath}\`? It's safe to delete \u2014 it
|
|
7651
|
+
> only contains the demo todo app and the session sisyphus just ran on it.
|
|
7652
|
+
|
|
7653
|
+
If they say yes, run:
|
|
7654
|
+
\`\`\`
|
|
7655
|
+
rm -rf ${demoPath}
|
|
7656
|
+
\`\`\`
|
|
7657
|
+
|
|
7658
|
+
Then check whether \`${join20(process.cwd(), "tmp")}\` is now empty, and if so remove it too:
|
|
7659
|
+
\`\`\`
|
|
7660
|
+
rmdir ${join20(process.cwd(), "tmp")} 2>/dev/null || true
|
|
7661
|
+
\`\`\`
|
|
7662
|
+
|
|
7663
|
+
If they say no or want to explore first, leave it. They can clean up later with the same
|
|
7664
|
+
\`rm -rf\` command.
|
|
7665
|
+
|
|
7666
|
+
### 6. There's more to learn
|
|
7585
7667
|
|
|
7586
7668
|
Tell them:
|
|
7587
7669
|
|
|
@@ -7983,22 +8065,10 @@ function registerGettingStarted(program2) {
|
|
|
7983
8065
|
|
|
7984
8066
|
// src/cli/commands/history.ts
|
|
7985
8067
|
init_paths();
|
|
7986
|
-
import { readdirSync as readdirSync6, readFileSync as readFileSync23, existsSync as
|
|
8068
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync23, existsSync as existsSync22 } from "fs";
|
|
7987
8069
|
import { resolve as resolve6 } from "path";
|
|
7988
|
-
var RESET3 = "\x1B[0m";
|
|
7989
|
-
var BOLD3 = "\x1B[1m";
|
|
7990
|
-
var DIM3 = "\x1B[2m";
|
|
7991
|
-
var COLOR = {
|
|
7992
|
-
green: "\x1B[32m",
|
|
7993
|
-
yellow: "\x1B[33m",
|
|
7994
|
-
cyan: "\x1B[36m",
|
|
7995
|
-
red: "\x1B[31m",
|
|
7996
|
-
gray: "\x1B[90m",
|
|
7997
|
-
white: "\x1B[37m",
|
|
7998
|
-
magenta: "\x1B[35m"
|
|
7999
|
-
};
|
|
8000
8070
|
function c(color, text) {
|
|
8001
|
-
return
|
|
8071
|
+
return colorize(text, color);
|
|
8002
8072
|
}
|
|
8003
8073
|
var INTERACTIVE_AGENT_TYPES = /* @__PURE__ */ new Set([
|
|
8004
8074
|
"sisyphus:requirements",
|
|
@@ -8023,11 +8093,11 @@ function splitAgentTime(agents) {
|
|
|
8023
8093
|
}
|
|
8024
8094
|
function loadAllSummaries() {
|
|
8025
8095
|
const base = historyBaseDir();
|
|
8026
|
-
if (!
|
|
8096
|
+
if (!existsSync22(base)) return [];
|
|
8027
8097
|
const results = [];
|
|
8028
8098
|
for (const name of readdirSync6(base)) {
|
|
8029
8099
|
const summaryPath = historySessionSummaryPath(name);
|
|
8030
|
-
if (
|
|
8100
|
+
if (existsSync22(summaryPath)) {
|
|
8031
8101
|
try {
|
|
8032
8102
|
const raw = readFileSync23(summaryPath, "utf-8");
|
|
8033
8103
|
results.push({ id: name, summary: JSON.parse(raw) });
|
|
@@ -8043,7 +8113,7 @@ function loadAllSummaries() {
|
|
|
8043
8113
|
}
|
|
8044
8114
|
function buildLiveSummary(sessionId) {
|
|
8045
8115
|
const eventsPath = historyEventsPath(sessionId);
|
|
8046
|
-
if (!
|
|
8116
|
+
if (!existsSync22(eventsPath)) return null;
|
|
8047
8117
|
let cwd = null;
|
|
8048
8118
|
try {
|
|
8049
8119
|
const lines = readFileSync23(eventsPath, "utf-8").split("\n");
|
|
@@ -8064,7 +8134,7 @@ function buildLiveSummary(sessionId) {
|
|
|
8064
8134
|
}
|
|
8065
8135
|
if (!cwd) return null;
|
|
8066
8136
|
const sPath = statePath(cwd, sessionId);
|
|
8067
|
-
if (!
|
|
8137
|
+
if (!existsSync22(sPath)) return null;
|
|
8068
8138
|
let session2;
|
|
8069
8139
|
try {
|
|
8070
8140
|
session2 = JSON.parse(readFileSync23(sPath, "utf-8"));
|
|
@@ -8128,7 +8198,7 @@ function buildLiveSummary(sessionId) {
|
|
|
8128
8198
|
}
|
|
8129
8199
|
function loadEvents(sessionId) {
|
|
8130
8200
|
const eventsPath = historyEventsPath(sessionId);
|
|
8131
|
-
if (!
|
|
8201
|
+
if (!existsSync22(eventsPath)) return [];
|
|
8132
8202
|
const lines = readFileSync23(eventsPath, "utf-8").split("\n").filter((l) => l.trim());
|
|
8133
8203
|
const events = [];
|
|
8134
8204
|
for (const line of lines) {
|
|
@@ -8142,13 +8212,13 @@ function loadEvents(sessionId) {
|
|
|
8142
8212
|
}
|
|
8143
8213
|
function findSession(idOrName) {
|
|
8144
8214
|
const summaryPath = historySessionSummaryPath(idOrName);
|
|
8145
|
-
if (
|
|
8215
|
+
if (existsSync22(summaryPath)) {
|
|
8146
8216
|
try {
|
|
8147
8217
|
return { id: idOrName, summary: JSON.parse(readFileSync23(summaryPath, "utf-8")) };
|
|
8148
8218
|
} catch {
|
|
8149
8219
|
}
|
|
8150
8220
|
}
|
|
8151
|
-
if (
|
|
8221
|
+
if (existsSync22(historySessionDir(idOrName))) {
|
|
8152
8222
|
const live = buildLiveSummary(idOrName);
|
|
8153
8223
|
if (live) return { id: idOrName, summary: live };
|
|
8154
8224
|
}
|
|
@@ -8216,9 +8286,9 @@ function listSessions(opts) {
|
|
|
8216
8286
|
const agents = s.agentCount > 0 ? `${s.agentCount} agents` : "";
|
|
8217
8287
|
const cycles = s.cycleCount > 0 ? `${s.cycleCount} cycles` : "";
|
|
8218
8288
|
const meta = [agents, cycles, dur].filter(Boolean).join(", ");
|
|
8219
|
-
console.log(`${date} ${status} ${name} ${
|
|
8289
|
+
console.log(`${date} ${status} ${name} ${dim(meta)} ${proj}`);
|
|
8220
8290
|
const taskPreview = s.task.length > 100 ? s.task.slice(0, 100) + "..." : s.task;
|
|
8221
|
-
console.log(` ${
|
|
8291
|
+
console.log(` ${dim(taskPreview)}`);
|
|
8222
8292
|
console.log("");
|
|
8223
8293
|
}
|
|
8224
8294
|
const total = loadAllSummaries().length;
|
|
@@ -8257,54 +8327,54 @@ function showSession(idOrName, opts) {
|
|
|
8257
8327
|
}
|
|
8258
8328
|
const inProgress = s.completedAt == null;
|
|
8259
8329
|
const inProgressTag = inProgress ? ` ${c("yellow", "(in progress)")}` : "";
|
|
8260
|
-
console.log(`${
|
|
8261
|
-
console.log(`${
|
|
8262
|
-
console.log(`${
|
|
8263
|
-
console.log(`${
|
|
8264
|
-
console.log(`${
|
|
8265
|
-
console.log(`${
|
|
8330
|
+
console.log(`${bold(s.name ?? s.sessionId.slice(0, 8))} ${fmtStatus(s.status)}${inProgressTag}`);
|
|
8331
|
+
console.log(`${dim("ID:")} ${s.sessionId}`);
|
|
8332
|
+
console.log(`${dim("Project:")} ${s.cwd}`);
|
|
8333
|
+
console.log(`${dim("Model:")} ${s.model ?? "default"}`);
|
|
8334
|
+
console.log(`${dim("Started:")} ${fmtDate(s.startedAt)}`);
|
|
8335
|
+
console.log(`${dim("Ended:")} ${s.completedAt ? fmtDate(s.completedAt) : c("gray", "\u2014 still running")}`);
|
|
8266
8336
|
const { computeMs, interactiveMs } = splitAgentTime(s.agents);
|
|
8267
8337
|
const wallStr = s.wallClockMs ? formatDuration(s.wallClockMs) : "\u2014";
|
|
8268
|
-
console.log(`${
|
|
8338
|
+
console.log(`${dim("Active:")} ${formatDuration(s.activeMs)} ${dim("Wall:")} ${wallStr}`);
|
|
8269
8339
|
if (interactiveMs > 0) {
|
|
8270
|
-
console.log(`${
|
|
8340
|
+
console.log(`${dim("Compute:")} ${formatDuration(computeMs)} ${dim("Interactive:")} ${formatDuration(interactiveMs)} ${dim("(TUI wait time, not compute)")}`);
|
|
8271
8341
|
}
|
|
8272
8342
|
if (s.userBlockedMs > 0) {
|
|
8273
|
-
console.log(`${
|
|
8343
|
+
console.log(`${dim("Waiting on user:")} ${formatDuration(s.userBlockedMs)} ${dim("(blocked on sis ask, not compute)")}`);
|
|
8274
8344
|
}
|
|
8275
8345
|
console.log("");
|
|
8276
|
-
console.log(
|
|
8346
|
+
console.log(bold("Task"));
|
|
8277
8347
|
console.log(s.task);
|
|
8278
8348
|
console.log("");
|
|
8279
8349
|
if (s.context) {
|
|
8280
|
-
console.log(
|
|
8350
|
+
console.log(bold("Context"));
|
|
8281
8351
|
console.log(s.context.length > 500 ? s.context.slice(0, 500) + "..." : s.context);
|
|
8282
8352
|
console.log("");
|
|
8283
8353
|
}
|
|
8284
8354
|
if (s.agents.length > 0) {
|
|
8285
|
-
console.log(`${
|
|
8355
|
+
console.log(`${bold("Agents")} (${s.agents.length})`);
|
|
8286
8356
|
for (const a of s.agents) {
|
|
8287
8357
|
const name = a.nickname ? `${a.name} "${a.nickname}"` : a.name;
|
|
8288
8358
|
const type = a.agentType ? c("gray", ` [${a.agentType}]`) : "";
|
|
8289
8359
|
const interactive = isInteractiveAgent(a.agentType) ? c("yellow", " (interactive)") : "";
|
|
8290
8360
|
const blocked = a.userBlockedMs ?? 0;
|
|
8291
|
-
const waiting = blocked > 0 ? ` ${
|
|
8292
|
-
console.log(` ${fmtStatus(a.status)} ${name}${type}${interactive} ${
|
|
8361
|
+
const waiting = blocked > 0 ? ` ${dim(`\xB7 ${formatDuration(blocked)} waiting`)}` : "";
|
|
8362
|
+
console.log(` ${fmtStatus(a.status)} ${name}${type}${interactive} ${dim(formatDuration(a.activeMs))}${waiting}`);
|
|
8293
8363
|
}
|
|
8294
8364
|
console.log("");
|
|
8295
8365
|
}
|
|
8296
8366
|
if (s.cycles.length > 0) {
|
|
8297
|
-
console.log(`${
|
|
8367
|
+
console.log(`${bold("Cycles")} (${s.cycles.length})`);
|
|
8298
8368
|
for (const cy of s.cycles) {
|
|
8299
8369
|
const mode = cy.mode ? c("magenta", cy.mode) : "";
|
|
8300
8370
|
const blocked = cy.userBlockedMs ?? 0;
|
|
8301
|
-
const waiting = blocked > 0 ? ` ${
|
|
8302
|
-
console.log(` ${
|
|
8371
|
+
const waiting = blocked > 0 ? ` ${dim(`\xB7 ${formatDuration(blocked)} waiting`)}` : "";
|
|
8372
|
+
console.log(` ${dim(`#${cy.cycle}`)} ${mode} ${cy.agentsSpawned} agents ${dim(formatDuration(cy.activeMs))}${waiting}`);
|
|
8303
8373
|
}
|
|
8304
8374
|
console.log("");
|
|
8305
8375
|
}
|
|
8306
8376
|
if (s.messages.length > 0) {
|
|
8307
|
-
console.log(`${
|
|
8377
|
+
console.log(`${bold("Messages")} (${s.messages.length})`);
|
|
8308
8378
|
for (const m of s.messages) {
|
|
8309
8379
|
const src = c("gray", m.source);
|
|
8310
8380
|
const preview = m.content.length > 120 ? m.content.slice(0, 120) + "..." : m.content;
|
|
@@ -8313,12 +8383,12 @@ function showSession(idOrName, opts) {
|
|
|
8313
8383
|
console.log("");
|
|
8314
8384
|
}
|
|
8315
8385
|
if (s.completionReport) {
|
|
8316
|
-
console.log(
|
|
8386
|
+
console.log(bold("Completion Report"));
|
|
8317
8387
|
console.log(s.completionReport);
|
|
8318
8388
|
console.log("");
|
|
8319
8389
|
}
|
|
8320
8390
|
if (s.achievements.length > 0) {
|
|
8321
|
-
console.log(
|
|
8391
|
+
console.log(bold("Achievements Unlocked"));
|
|
8322
8392
|
console.log(` ${s.achievements.join(", ")}`);
|
|
8323
8393
|
console.log("");
|
|
8324
8394
|
}
|
|
@@ -8331,7 +8401,7 @@ function showSession(idOrName, opts) {
|
|
|
8331
8401
|
`hour ${sig.hourOfDay}`,
|
|
8332
8402
|
sig.idleDurationMs > 6e4 ? `idle ${formatDuration(sig.idleDurationMs)}` : null
|
|
8333
8403
|
].filter(Boolean);
|
|
8334
|
-
console.log(
|
|
8404
|
+
console.log(dim(`Final signals: ${parts.join(" \xB7 ")}`));
|
|
8335
8405
|
}
|
|
8336
8406
|
}
|
|
8337
8407
|
function formatEventData(e) {
|
|
@@ -8342,11 +8412,11 @@ function formatEventData(e) {
|
|
|
8342
8412
|
case "session-named":
|
|
8343
8413
|
return c("white", d.name);
|
|
8344
8414
|
case "agent-spawned":
|
|
8345
|
-
return `${c("white", d.agentId)} ${d.agentType ?? ""} ${
|
|
8415
|
+
return `${c("white", d.agentId)} ${d.agentType ?? ""} ${dim(`${d.instruction?.slice(0, 60) ?? ""}...`)}`;
|
|
8346
8416
|
case "agent-nicknamed":
|
|
8347
8417
|
return `${d.agentId} "${c("white", d.nickname)}"`;
|
|
8348
8418
|
case "agent-completed":
|
|
8349
|
-
return `${d.agentId} ${
|
|
8419
|
+
return `${d.agentId} ${dim(formatDuration(d.activeMs))} ${dim(d.reportSummary?.slice(0, 60) ?? "")}`;
|
|
8350
8420
|
case "agent-exited":
|
|
8351
8421
|
return `${d.agentId} ${fmtStatus(d.status)} ${d.reason ?? ""}`;
|
|
8352
8422
|
case "cycle-boundary":
|
|
@@ -8362,15 +8432,15 @@ function formatEventData(e) {
|
|
|
8362
8432
|
return `${c("cyan", d.type)} ${c("gray", fileParts)}`;
|
|
8363
8433
|
}
|
|
8364
8434
|
case "agent-killed":
|
|
8365
|
-
return `${d.agentId} ${fmtStatus(d.status)} ${
|
|
8435
|
+
return `${d.agentId} ${fmtStatus(d.status)} ${dim(formatDuration(d.activeMs))} ${d.reason ?? ""}`;
|
|
8366
8436
|
case "agent-restarted":
|
|
8367
|
-
return `${d.agentId} restart #${d.restartCount} ${
|
|
8437
|
+
return `${d.agentId} restart #${d.restartCount} ${dim(`was ${d.previousStatus}`)}`;
|
|
8368
8438
|
case "rollback":
|
|
8369
8439
|
return `cycle ${d.fromCycle} \u2192 ${d.toCycle} ${d.killedAgentCount} agents killed`;
|
|
8370
8440
|
case "session-resumed":
|
|
8371
8441
|
return `was ${fmtStatus(d.previousStatus)} ${d.lostAgentCount} agents lost`;
|
|
8372
8442
|
case "session-continued":
|
|
8373
|
-
return `${d.cycleCount} cycles ${
|
|
8443
|
+
return `${d.cycleCount} cycles ${dim(formatDuration(d.activeMs))}`;
|
|
8374
8444
|
case "session-end":
|
|
8375
8445
|
return `${fmtStatus(d.status)} ${formatDuration(d.activeMs)} ${d.agentCount} agents ${d.cycleCount} cycles`;
|
|
8376
8446
|
default:
|
|
@@ -8468,29 +8538,29 @@ function showStats(opts) {
|
|
|
8468
8538
|
}, null, 2));
|
|
8469
8539
|
return;
|
|
8470
8540
|
}
|
|
8471
|
-
console.log(
|
|
8541
|
+
console.log(bold("Session History Stats"));
|
|
8472
8542
|
console.log("");
|
|
8473
|
-
console.log(` ${
|
|
8474
|
-
const timeLine = ` ${
|
|
8543
|
+
console.log(` ${bold("Sessions:")} ${sessions.length} total ${c("cyan", `${completed.length} completed`)} ${c("red", `${killed.length} killed`)}`);
|
|
8544
|
+
const timeLine = ` ${bold("Time:")} ${formatDuration(totalActiveMs)} total ${formatDuration(avgMs)} avg` + (p50Ms != null && p90Ms != null ? ` ${dim(`p50=${formatDuration(p50Ms)} p90=${formatDuration(p90Ms)}`)}` : "");
|
|
8475
8545
|
console.log(timeLine);
|
|
8476
8546
|
if (avgEfficiency != null) {
|
|
8477
8547
|
const effColor = avgEfficiency >= 0.7 ? "green" : avgEfficiency >= 0.4 ? "yellow" : "red";
|
|
8478
|
-
console.log(` ${
|
|
8548
|
+
console.log(` ${bold("Efficiency:")} ${c(effColor, (avgEfficiency * 100).toFixed(1) + "%")} ${dim(`(${efficiencyValues.length} sessions with data)`)}`);
|
|
8479
8549
|
}
|
|
8480
|
-
console.log(` ${
|
|
8481
|
-
console.log(` ${
|
|
8482
|
-
console.log(` ${
|
|
8550
|
+
console.log(` ${bold("Agents:")} ${totalAgents} spawned (${(totalAgents / sessions.length).toFixed(1)} avg/session)`);
|
|
8551
|
+
console.log(` ${bold("Cycles:")} ${totalCycles} total (${(totalCycles / sessions.length).toFixed(1)} avg/session)`);
|
|
8552
|
+
console.log(` ${bold("Messages:")} ${totalMessages} total`);
|
|
8483
8553
|
console.log("");
|
|
8484
|
-
console.log(
|
|
8554
|
+
console.log(bold("By Project"));
|
|
8485
8555
|
const sorted = [...byProject.entries()].sort((a, b) => b[1].count - a[1].count);
|
|
8486
8556
|
for (const [proj, data] of sorted) {
|
|
8487
8557
|
console.log(` ${c("gray", fmtProject(proj))} ${data.count} sessions ${formatDuration(data.activeMs)} ${data.agents} agents`);
|
|
8488
8558
|
}
|
|
8489
8559
|
if (agentTypeMap.size > 0) {
|
|
8490
8560
|
console.log("");
|
|
8491
|
-
console.log(
|
|
8561
|
+
console.log(bold("By Agent Type"));
|
|
8492
8562
|
const typeHeader = ` ${"Type".padEnd(20)} ${"Count".padStart(6)} ${"Avg Time".padStart(10)} ${"Crash %".padStart(8)} ${"Done %".padStart(8)}`;
|
|
8493
|
-
console.log(
|
|
8563
|
+
console.log(dim(typeHeader));
|
|
8494
8564
|
const sortedTypes = [...agentTypeMap.entries()].sort((a, b) => b[1].count - a[1].count);
|
|
8495
8565
|
for (const [type, data] of sortedTypes) {
|
|
8496
8566
|
const avgTime = formatDuration(data.totalMs / data.count);
|
|
@@ -8502,12 +8572,12 @@ function showStats(opts) {
|
|
|
8502
8572
|
}
|
|
8503
8573
|
if (sessions.length >= 5) {
|
|
8504
8574
|
console.log("");
|
|
8505
|
-
console.log(
|
|
8575
|
+
console.log(bold("Temporal Patterns"));
|
|
8506
8576
|
const topBlocks = [...hourBlocks.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
8507
|
-
console.log(` ${
|
|
8577
|
+
console.log(` ${dim("Busiest times:")} ${topBlocks.map(([label, count]) => `${label} (${count})`).join(" ")}`);
|
|
8508
8578
|
const dayOrder = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
8509
8579
|
const dayParts = dayOrder.map((d) => `${d} ${dayCounts.get(d) ?? 0}`);
|
|
8510
|
-
console.log(` ${
|
|
8580
|
+
console.log(` ${dim("By day:")} ${dayParts.join(" ")}`);
|
|
8511
8581
|
}
|
|
8512
8582
|
}
|
|
8513
8583
|
function registerHistory(program2) {
|
|
@@ -8537,7 +8607,7 @@ function registerHistory(program2) {
|
|
|
8537
8607
|
init_paths();
|
|
8538
8608
|
import { execFile as execFile2 } from "child_process";
|
|
8539
8609
|
import { promisify } from "util";
|
|
8540
|
-
import { existsSync as
|
|
8610
|
+
import { existsSync as existsSync23, readFileSync as readFileSync24, mkdirSync as mkdirSync10, symlinkSync, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
|
|
8541
8611
|
import { homedir as homedir12 } from "os";
|
|
8542
8612
|
import { join as join22 } from "path";
|
|
8543
8613
|
function sanitizeName(name) {
|
|
@@ -8549,7 +8619,7 @@ function buildOutputPath(label, dir) {
|
|
|
8549
8619
|
const base = `sisyphus-${label}-${date}`;
|
|
8550
8620
|
let candidate = join22(dir, `${base}.zip`);
|
|
8551
8621
|
let counter = 1;
|
|
8552
|
-
while (
|
|
8622
|
+
while (existsSync23(candidate)) {
|
|
8553
8623
|
counter++;
|
|
8554
8624
|
candidate = join22(dir, `${base}-${counter}.zip`);
|
|
8555
8625
|
}
|
|
@@ -8613,14 +8683,14 @@ async function exportSessionToZip(sessionId, cwd, options) {
|
|
|
8613
8683
|
const reveal = options?.reveal ?? true;
|
|
8614
8684
|
const sessDir = sessionDir(cwd, sessionId);
|
|
8615
8685
|
const histDir = historySessionDir(sessionId);
|
|
8616
|
-
const sessExists =
|
|
8617
|
-
const histExists =
|
|
8686
|
+
const sessExists = existsSync23(sessDir);
|
|
8687
|
+
const histExists = existsSync23(histDir);
|
|
8618
8688
|
if (!sessExists && !histExists) {
|
|
8619
8689
|
throw new Error(`No data found for session ${sessionId}`);
|
|
8620
8690
|
}
|
|
8621
8691
|
let label = sessionId.slice(0, 8);
|
|
8622
8692
|
const stPath = statePath(cwd, sessionId);
|
|
8623
|
-
if (
|
|
8693
|
+
if (existsSync23(stPath)) {
|
|
8624
8694
|
try {
|
|
8625
8695
|
const state = JSON.parse(readFileSync24(stPath, "utf-8"));
|
|
8626
8696
|
if (state.name) {
|
|
@@ -8924,7 +8994,7 @@ function openScratchWindow(tmuxSession, cwd, prompt) {
|
|
|
8924
8994
|
// src/cli/commands/review.ts
|
|
8925
8995
|
init_paths();
|
|
8926
8996
|
import { join as join23, resolve as resolve8, dirname as dirname8 } from "path";
|
|
8927
|
-
import { existsSync as
|
|
8997
|
+
import { existsSync as existsSync24, readFileSync as readFileSync26, writeFileSync as writeFileSync12, renameSync as renameSync3, readdirSync as readdirSync7 } from "fs";
|
|
8928
8998
|
var _statusCheck = ["draft", "question", "approved", "rejected", "deferred"];
|
|
8929
8999
|
function resolveContextArtifact(file, opts, filename, notFoundMessage) {
|
|
8930
9000
|
const cwd = opts.cwd || process.env.SISYPHUS_CWD || process.cwd();
|
|
@@ -8932,18 +9002,18 @@ function resolveContextArtifact(file, opts, filename, notFoundMessage) {
|
|
|
8932
9002
|
const sessionId = opts.sessionId || process.env.SISYPHUS_SESSION_ID;
|
|
8933
9003
|
if (sessionId) {
|
|
8934
9004
|
const target = join23(contextDir(cwd, sessionId), filename);
|
|
8935
|
-
if (!
|
|
9005
|
+
if (!existsSync24(target)) {
|
|
8936
9006
|
console.error(`Error: File not found: ${target}`);
|
|
8937
9007
|
process.exit(1);
|
|
8938
9008
|
}
|
|
8939
9009
|
return target;
|
|
8940
9010
|
}
|
|
8941
9011
|
const dir = sessionsDir(cwd);
|
|
8942
|
-
if (
|
|
9012
|
+
if (existsSync24(dir)) {
|
|
8943
9013
|
const sessions = readdirSync7(dir);
|
|
8944
9014
|
for (const session2 of sessions.reverse()) {
|
|
8945
9015
|
const candidate = join23(dir, session2, "context", filename);
|
|
8946
|
-
if (
|
|
9016
|
+
if (existsSync24(candidate)) return candidate;
|
|
8947
9017
|
}
|
|
8948
9018
|
}
|
|
8949
9019
|
console.error(`Error: ${notFoundMessage}`);
|
|
@@ -8985,7 +9055,7 @@ Examples:
|
|
|
8985
9055
|
"requirements.json",
|
|
8986
9056
|
"No requirements.json found. Provide a path or use --session-id."
|
|
8987
9057
|
);
|
|
8988
|
-
if (!
|
|
9058
|
+
if (!existsSync24(targetPath)) {
|
|
8989
9059
|
console.error(`Error: File not found: ${targetPath}`);
|
|
8990
9060
|
process.exit(1);
|
|
8991
9061
|
}
|
|
@@ -8993,7 +9063,7 @@ Examples:
|
|
|
8993
9063
|
const rendered = renderRequirementsMarkdown(parsed);
|
|
8994
9064
|
const outPath = join23(dirname8(targetPath), "requirements.md");
|
|
8995
9065
|
const tmpPath = outPath + ".tmp";
|
|
8996
|
-
if (
|
|
9066
|
+
if (existsSync24(outPath)) {
|
|
8997
9067
|
const existing = readFileSync26(outPath, "utf-8");
|
|
8998
9068
|
if (existing !== rendered) {
|
|
8999
9069
|
if (!opts.force) {
|
|
@@ -9566,7 +9636,7 @@ var MOOD_COLORS = {
|
|
|
9566
9636
|
function getMoodTmuxColor(mood) {
|
|
9567
9637
|
return MOOD_COLORS[mood].tmux;
|
|
9568
9638
|
}
|
|
9569
|
-
function
|
|
9639
|
+
function colorize3(text, mood, tmux) {
|
|
9570
9640
|
const { ansi, tmux: tmuxColor } = MOOD_COLORS[mood];
|
|
9571
9641
|
if (tmux) {
|
|
9572
9642
|
return `#[fg=${tmuxColor}]${text}#[fg=default]`;
|
|
@@ -9664,7 +9734,7 @@ function applyColor(result, fields, facePart, mood, opts) {
|
|
|
9664
9734
|
const useColor = opts?.color === true || opts?.tmuxFormat === true;
|
|
9665
9735
|
if (!useColor || facePart === null || !fields.includes("face")) return result;
|
|
9666
9736
|
const tmux = opts?.tmuxFormat === true;
|
|
9667
|
-
const coloredFace =
|
|
9737
|
+
const coloredFace = colorize3(facePart, mood, tmux);
|
|
9668
9738
|
return result.replace(facePart, coloredFace);
|
|
9669
9739
|
}
|
|
9670
9740
|
|
|
@@ -10477,7 +10547,7 @@ function stripAnsiForWidth(s) {
|
|
|
10477
10547
|
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
10478
10548
|
}
|
|
10479
10549
|
function renderBadgeCard(def, unlock, opts) {
|
|
10480
|
-
const
|
|
10550
|
+
const dim2 = opts?.dim === true || unlock === null;
|
|
10481
10551
|
const art = BADGE_ART[def.id] ?? [];
|
|
10482
10552
|
const lines = [];
|
|
10483
10553
|
const category = def.category.toUpperCase();
|
|
@@ -10491,7 +10561,7 @@ function renderBadgeCard(def, unlock, opts) {
|
|
|
10491
10561
|
const artSlice = art.slice(0, artMaxLines);
|
|
10492
10562
|
for (const artLine of artSlice) {
|
|
10493
10563
|
const centered = centerLine(artLine, CARD_INNER);
|
|
10494
|
-
lines.push(`\u2502${
|
|
10564
|
+
lines.push(`\u2502${dim2 ? dimText(centered) : centered}\u2502`);
|
|
10495
10565
|
}
|
|
10496
10566
|
for (let i = artSlice.length; i < artMaxLines; i++) {
|
|
10497
10567
|
lines.push(`\u2502${" ".repeat(CARD_INNER)}\u2502`);
|
|
@@ -10502,7 +10572,7 @@ function renderBadgeCard(def, unlock, opts) {
|
|
|
10502
10572
|
const descLines = wrapText(def.description, CARD_INNER - 4);
|
|
10503
10573
|
for (const dl of descLines.slice(0, 2)) {
|
|
10504
10574
|
const centered = centerLine(dl, CARD_INNER);
|
|
10505
|
-
lines.push(`\u2502${
|
|
10575
|
+
lines.push(`\u2502${dim2 ? dimText(centered) : centered}\u2502`);
|
|
10506
10576
|
}
|
|
10507
10577
|
const usedContent = 1 + 1 + artMaxLines + 1 + 1 + Math.min(descLines.length, 2);
|
|
10508
10578
|
const remaining = CARD_HEIGHT - 2 - usedContent;
|
|
@@ -10562,7 +10632,7 @@ function createBadgeGallery(unlockedAchievements, startIndex) {
|
|
|
10562
10632
|
|
|
10563
10633
|
// src/daemon/companion-memory.ts
|
|
10564
10634
|
init_paths();
|
|
10565
|
-
import { existsSync as
|
|
10635
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync12, readFileSync as readFileSync28, renameSync as renameSync5, writeFileSync as writeFileSync14 } from "fs";
|
|
10566
10636
|
import { dirname as dirname10, join as join25 } from "path";
|
|
10567
10637
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
10568
10638
|
import { z as z2 } from "zod";
|
|
@@ -10574,7 +10644,7 @@ var COOLDOWN_MS = 5 * 60 * 1e3;
|
|
|
10574
10644
|
|
|
10575
10645
|
// src/daemon/companion.ts
|
|
10576
10646
|
init_paths();
|
|
10577
|
-
import { existsSync as
|
|
10647
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync11, readFileSync as readFileSync27, renameSync as renameSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
10578
10648
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
10579
10649
|
import { dirname as dirname9, join as join24 } from "path";
|
|
10580
10650
|
|
|
@@ -10625,7 +10695,7 @@ function normalizeCompanion(state) {
|
|
|
10625
10695
|
// src/daemon/companion.ts
|
|
10626
10696
|
function loadCompanion() {
|
|
10627
10697
|
const path = companionPath();
|
|
10628
|
-
if (!
|
|
10698
|
+
if (!existsSync25(path)) {
|
|
10629
10699
|
const state2 = createDefaultCompanion();
|
|
10630
10700
|
saveCompanion(state2);
|
|
10631
10701
|
return state2;
|
|
@@ -10711,7 +10781,7 @@ function fillDefaults(state) {
|
|
|
10711
10781
|
}
|
|
10712
10782
|
function loadMemoryStrict() {
|
|
10713
10783
|
const path = resolvedMemoryPath();
|
|
10714
|
-
if (!
|
|
10784
|
+
if (!existsSync26(path)) return defaultMemoryState();
|
|
10715
10785
|
let raw;
|
|
10716
10786
|
try {
|
|
10717
10787
|
raw = readFileSync28(path, "utf-8");
|
|
@@ -10757,7 +10827,7 @@ var ObservationZodSchema = z2.object({
|
|
|
10757
10827
|
});
|
|
10758
10828
|
|
|
10759
10829
|
// src/daemon/companion-popup.ts
|
|
10760
|
-
import { writeFileSync as writeFileSync15, readFileSync as readFileSync29, unlinkSync as unlinkSync3, existsSync as
|
|
10830
|
+
import { writeFileSync as writeFileSync15, readFileSync as readFileSync29, unlinkSync as unlinkSync3, existsSync as existsSync27 } from "fs";
|
|
10761
10831
|
import { tmpdir as tmpdir2 } from "os";
|
|
10762
10832
|
import { join as join26, resolve as resolve9 } from "path";
|
|
10763
10833
|
init_exec();
|
|
@@ -10811,7 +10881,7 @@ function showCommentaryPopupQueue(pages) {
|
|
|
10811
10881
|
if (contentHeight > maxContentHeight) maxContentHeight = contentHeight;
|
|
10812
10882
|
writeFileSync15(`${POPUP_TMP_PREFIX}-${i}.txt`, content);
|
|
10813
10883
|
}
|
|
10814
|
-
const whipAvailable =
|
|
10884
|
+
const whipAvailable = existsSync27(WHIP_ANIMATION_PATH);
|
|
10815
10885
|
if (whipAvailable && maxContentHeight < WHIP_ANIMATION_ROWS + 2) {
|
|
10816
10886
|
maxContentHeight = WHIP_ANIMATION_ROWS + 2;
|
|
10817
10887
|
}
|
|
@@ -11106,7 +11176,7 @@ init_paths();
|
|
|
11106
11176
|
init_exec();
|
|
11107
11177
|
init_creds();
|
|
11108
11178
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
|
|
11109
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
11179
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as readFileSync34 } from "fs";
|
|
11110
11180
|
|
|
11111
11181
|
// src/cli/deploy/pricing.ts
|
|
11112
11182
|
var LAST_VERIFIED = "2026-05-06";
|
|
@@ -11141,10 +11211,10 @@ function formatCostLine(provider, instanceType) {
|
|
|
11141
11211
|
// src/cli/deploy/runtime.ts
|
|
11142
11212
|
init_atomic();
|
|
11143
11213
|
init_paths();
|
|
11144
|
-
import { existsSync as
|
|
11214
|
+
import { existsSync as existsSync30, readFileSync as readFileSync33, unlinkSync as unlinkSync4 } from "fs";
|
|
11145
11215
|
function readRuntimeState(provider) {
|
|
11146
11216
|
const path = deployRuntimePath(provider);
|
|
11147
|
-
if (!
|
|
11217
|
+
if (!existsSync30(path)) return null;
|
|
11148
11218
|
try {
|
|
11149
11219
|
return JSON.parse(readFileSync33(path, "utf-8"));
|
|
11150
11220
|
} catch {
|
|
@@ -11156,7 +11226,7 @@ function writeRuntimeState(provider, state) {
|
|
|
11156
11226
|
}
|
|
11157
11227
|
function clearRuntimeState(provider) {
|
|
11158
11228
|
const path = deployRuntimePath(provider);
|
|
11159
|
-
if (
|
|
11229
|
+
if (existsSync30(path)) unlinkSync4(path);
|
|
11160
11230
|
}
|
|
11161
11231
|
|
|
11162
11232
|
// src/cli/deploy/tailnet.ts
|
|
@@ -11206,15 +11276,15 @@ function isTailscaleAvailable() {
|
|
|
11206
11276
|
}
|
|
11207
11277
|
|
|
11208
11278
|
// src/cli/deploy/templates.ts
|
|
11209
|
-
import { existsSync as
|
|
11279
|
+
import { existsSync as existsSync31 } from "fs";
|
|
11210
11280
|
import { dirname as dirname12, resolve as resolve10 } from "path";
|
|
11211
11281
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
11212
11282
|
function deployRoot() {
|
|
11213
11283
|
const here = dirname12(fileURLToPath4(import.meta.url));
|
|
11214
11284
|
const bundled = resolve10(here, "..", "deploy");
|
|
11215
|
-
if (
|
|
11285
|
+
if (existsSync31(bundled)) return bundled;
|
|
11216
11286
|
const sourceRoot = resolve10(here, "..", "..", "..", "deploy");
|
|
11217
|
-
if (
|
|
11287
|
+
if (existsSync31(sourceRoot)) return sourceRoot;
|
|
11218
11288
|
throw new Error(
|
|
11219
11289
|
`Could not locate deploy/ templates. Looked at:
|
|
11220
11290
|
${bundled}
|
|
@@ -11398,14 +11468,14 @@ function ensureTerraformInstalled() {
|
|
|
11398
11468
|
function ensureProviderStateDir(provider) {
|
|
11399
11469
|
ensureDeployDir();
|
|
11400
11470
|
const dir = deployProviderDir(provider);
|
|
11401
|
-
if (!
|
|
11471
|
+
if (!existsSync32(dir)) mkdirSync16(dir, { recursive: true, mode: 448 });
|
|
11402
11472
|
}
|
|
11403
11473
|
function backupState(provider) {
|
|
11404
11474
|
const src = deployStatePath(provider);
|
|
11405
|
-
if (
|
|
11475
|
+
if (existsSync32(src)) copyFileSync2(src, deployStateBackupPath(provider));
|
|
11406
11476
|
}
|
|
11407
11477
|
function readSshPubkey(path) {
|
|
11408
|
-
if (!
|
|
11478
|
+
if (!existsSync32(path)) {
|
|
11409
11479
|
const privateKeyPath = path.replace(/\.pub$/, "");
|
|
11410
11480
|
throw new Error(
|
|
11411
11481
|
`SSH pubkey not found at ${path}. Generate one with:
|
|
@@ -11440,7 +11510,7 @@ function readOutputs(provider) {
|
|
|
11440
11510
|
}
|
|
11441
11511
|
}
|
|
11442
11512
|
function isProvisioned(provider) {
|
|
11443
|
-
if (!
|
|
11513
|
+
if (!existsSync32(deployStatePath(provider))) return false;
|
|
11444
11514
|
return readOutputs(provider) !== null;
|
|
11445
11515
|
}
|
|
11446
11516
|
async function deployUp(provider, opts) {
|
|
@@ -11526,7 +11596,7 @@ Applied \u2014 but could not parse outputs. Run \`sis deploy ${provider} status\
|
|
|
11526
11596
|
console.log("");
|
|
11527
11597
|
}
|
|
11528
11598
|
async function deployDown(provider, opts) {
|
|
11529
|
-
if (!
|
|
11599
|
+
if (!existsSync32(deployStatePath(provider))) {
|
|
11530
11600
|
console.log(`No ${provider} state found at ${deployStatePath(provider)}. Nothing to destroy.`);
|
|
11531
11601
|
return;
|
|
11532
11602
|
}
|
|
@@ -11775,7 +11845,7 @@ function ensureGroveRegistered(provider, repo, instancePath) {
|
|
|
11775
11845
|
// src/cli/cloud/repo.ts
|
|
11776
11846
|
init_exec();
|
|
11777
11847
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
11778
|
-
import { existsSync as
|
|
11848
|
+
import { existsSync as existsSync33 } from "fs";
|
|
11779
11849
|
import { basename as basename6, join as join30 } from "path";
|
|
11780
11850
|
function captureGit(args2, cwd) {
|
|
11781
11851
|
const result = spawnSync6("git", args2, {
|
|
@@ -11828,10 +11898,10 @@ function buildRsyncArgs(localDir, remoteTarget) {
|
|
|
11828
11898
|
];
|
|
11829
11899
|
}
|
|
11830
11900
|
function detectPackageManager(toplevel) {
|
|
11831
|
-
if (
|
|
11832
|
-
if (
|
|
11833
|
-
if (
|
|
11834
|
-
if (
|
|
11901
|
+
if (existsSync33(join30(toplevel, "pnpm-lock.yaml"))) return "pnpm";
|
|
11902
|
+
if (existsSync33(join30(toplevel, "bun.lockb"))) return "bun";
|
|
11903
|
+
if (existsSync33(join30(toplevel, "yarn.lock"))) return "yarn";
|
|
11904
|
+
if (existsSync33(join30(toplevel, "package-lock.json"))) return "npm";
|
|
11835
11905
|
return null;
|
|
11836
11906
|
}
|
|
11837
11907
|
function packageManagerInstallCmd(pm) {
|
|
@@ -12040,7 +12110,7 @@ function cloudStatus(provider, repo) {
|
|
|
12040
12110
|
|
|
12041
12111
|
// src/cli/cloud/handoff.ts
|
|
12042
12112
|
import { spawn as spawn5 } from "child_process";
|
|
12043
|
-
import { existsSync as
|
|
12113
|
+
import { existsSync as existsSync34, readFileSync as readFileSync35, writeFileSync as writeFileSync18 } from "fs";
|
|
12044
12114
|
init_exec();
|
|
12045
12115
|
init_paths();
|
|
12046
12116
|
init_shell();
|
|
@@ -12115,7 +12185,7 @@ async function waitForSentOrError(cwd, sessionId) {
|
|
|
12115
12185
|
const path = statePath(cwd, sessionId);
|
|
12116
12186
|
while (Date.now() - start < MAX_WAIT_MS) {
|
|
12117
12187
|
await sleep2(POLL_INTERVAL_MS);
|
|
12118
|
-
if (!
|
|
12188
|
+
if (!existsSync34(path)) continue;
|
|
12119
12189
|
let session2;
|
|
12120
12190
|
try {
|
|
12121
12191
|
session2 = JSON.parse(readFileSync35(path, "utf-8"));
|
|
@@ -12212,7 +12282,7 @@ async function cloudReclaim(sessionId, opts) {
|
|
|
12212
12282
|
}
|
|
12213
12283
|
function readLocalSession(cwd, sessionId) {
|
|
12214
12284
|
const path = statePath(cwd, sessionId);
|
|
12215
|
-
if (!
|
|
12285
|
+
if (!existsSync34(path)) {
|
|
12216
12286
|
console.error(`No local state.json for ${sessionId} at ${path}.`);
|
|
12217
12287
|
process.exit(1);
|
|
12218
12288
|
}
|
|
@@ -12327,7 +12397,7 @@ function attachNotify(diagnostic2) {
|
|
|
12327
12397
|
// src/cli/commands/tmux-sessions.ts
|
|
12328
12398
|
init_paths();
|
|
12329
12399
|
import { execSync as execSync19 } from "child_process";
|
|
12330
|
-
import { readFileSync as readFileSync36, existsSync as
|
|
12400
|
+
import { readFileSync as readFileSync36, existsSync as existsSync35 } from "fs";
|
|
12331
12401
|
var DOT_MAP = {
|
|
12332
12402
|
"orchestrator:processing": { icon: "\u25CF", color: "#d4ad6a" },
|
|
12333
12403
|
"orchestrator:idle": { icon: "\u25CF", color: "#d47766" },
|
|
@@ -12338,7 +12408,7 @@ var DOT_MAP = {
|
|
|
12338
12408
|
};
|
|
12339
12409
|
function readManifest() {
|
|
12340
12410
|
const p = sessionsManifestPath();
|
|
12341
|
-
if (!
|
|
12411
|
+
if (!existsSync35(p)) return null;
|
|
12342
12412
|
try {
|
|
12343
12413
|
return JSON.parse(readFileSync36(p, "utf-8"));
|
|
12344
12414
|
} catch {
|
|
@@ -12474,7 +12544,7 @@ Run 'sis admin getting-started' for a complete usage guide.
|
|
|
12474
12544
|
var args = process.argv.slice(2);
|
|
12475
12545
|
var firstArg = args[0];
|
|
12476
12546
|
var skipWelcome = ["admin", "help", "--help", "-h", "--version", "-V"];
|
|
12477
|
-
if (!
|
|
12547
|
+
if (!existsSync36(globalDir()) && firstArg && !skipWelcome.includes(firstArg)) {
|
|
12478
12548
|
mkdirSync17(globalDir(), { recursive: true });
|
|
12479
12549
|
console.log("");
|
|
12480
12550
|
console.log(" Welcome to Sisyphus. Run 'sis admin setup' to get started.");
|