sisyphi 1.1.19 → 1.1.23
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/deploy/aws/main.tf +121 -0
- package/deploy/aws/outputs.tf +18 -0
- package/deploy/aws/variables.tf +69 -0
- package/deploy/aws/versions.tf +16 -0
- package/deploy/hetzner/.terraform.lock.hcl +23 -0
- package/deploy/hetzner/main.tf +69 -0
- package/deploy/hetzner/outputs.tf +18 -0
- package/deploy/hetzner/variables.tf +57 -0
- package/deploy/hetzner/versions.tf +15 -0
- package/deploy/shared/bin/pbcopy-shim +5 -0
- package/deploy/shared/bin/pbpaste-shim +4 -0
- package/deploy/shared/cloud-init.yaml.tpl +119 -0
- package/deploy/shared/sisyphusd.service.tpl +17 -0
- package/deploy/shared/tmux-osc52.conf +10 -0
- package/dist/cli.js +3681 -310
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +3863 -474
- package/dist/daemon.js.map +1 -1
- package/dist/deploy/aws/main.tf +121 -0
- package/dist/deploy/aws/outputs.tf +18 -0
- package/dist/deploy/aws/variables.tf +69 -0
- package/dist/deploy/aws/versions.tf +16 -0
- package/dist/deploy/hetzner/.terraform.lock.hcl +23 -0
- package/dist/deploy/hetzner/main.tf +69 -0
- package/dist/deploy/hetzner/outputs.tf +18 -0
- package/dist/deploy/hetzner/variables.tf +57 -0
- package/dist/deploy/hetzner/versions.tf +15 -0
- package/dist/deploy/shared/bin/pbcopy-shim +5 -0
- package/dist/deploy/shared/bin/pbpaste-shim +4 -0
- package/dist/deploy/shared/cloud-init.yaml.tpl +119 -0
- package/dist/deploy/shared/sisyphusd.service.tpl +17 -0
- package/dist/deploy/shared/tmux-osc52.conf +10 -0
- package/dist/tui.js +2915 -185
- package/dist/tui.js.map +1 -1
- package/native/build-notify.sh +23 -0
- package/package.json +4 -3
- package/dist/chunk-36VJ7ZBD.js +0 -1898
- package/dist/chunk-36VJ7ZBD.js.map +0 -1
- package/dist/chunk-M6Z3KHOH.js +0 -1165
- package/dist/chunk-M6Z3KHOH.js.map +0 -1
- package/dist/chunk-O4ZHSQ5R.js +0 -544
- package/dist/chunk-O4ZHSQ5R.js.map +0 -1
- package/dist/chunk-P2HHTIPM.js +0 -478
- package/dist/chunk-P2HHTIPM.js.map +0 -1
- package/dist/chunk-PNDCVKBN.js +0 -201
- package/dist/chunk-PNDCVKBN.js.map +0 -1
- package/dist/chunk-SVGIQ2G4.js +0 -1076
- package/dist/chunk-SVGIQ2G4.js.map +0 -1
- package/dist/paths-JXFLR5BN.js +0 -102
- package/dist/paths-JXFLR5BN.js.map +0 -1
- package/dist/single-ask-6G4BIVY2.js +0 -132
- package/dist/single-ask-6G4BIVY2.js.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,70 +1,1014 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/tui/terminal.ts
|
|
13
|
+
function emptyKey() {
|
|
14
|
+
return {
|
|
15
|
+
upArrow: false,
|
|
16
|
+
downArrow: false,
|
|
17
|
+
leftArrow: false,
|
|
18
|
+
rightArrow: false,
|
|
19
|
+
pageUp: false,
|
|
20
|
+
pageDown: false,
|
|
21
|
+
return: false,
|
|
22
|
+
escape: false,
|
|
23
|
+
ctrl: false,
|
|
24
|
+
shift: false,
|
|
25
|
+
tab: false,
|
|
26
|
+
backspace: false,
|
|
27
|
+
delete: false,
|
|
28
|
+
meta: false
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function setupTerminal() {
|
|
32
|
+
let cleaned = false;
|
|
33
|
+
const cleanup2 = () => {
|
|
34
|
+
if (cleaned) return;
|
|
35
|
+
cleaned = true;
|
|
36
|
+
process.stdout.write("\x1B[?25h\x1B[?1049l");
|
|
37
|
+
process.stdin.setRawMode(false);
|
|
38
|
+
process.stdin.pause();
|
|
39
|
+
};
|
|
40
|
+
process.stdin.setRawMode(true);
|
|
41
|
+
process.stdin.resume();
|
|
42
|
+
process.stdin.setEncoding("utf-8");
|
|
43
|
+
process.stdout.write("\x1B[?1049h\x1B[?25l\x1B[2J");
|
|
44
|
+
process.on("SIGINT", () => {
|
|
45
|
+
cleanup2();
|
|
46
|
+
process.exit(0);
|
|
47
|
+
});
|
|
48
|
+
process.on("SIGTERM", () => {
|
|
49
|
+
cleanup2();
|
|
50
|
+
process.exit(0);
|
|
51
|
+
});
|
|
52
|
+
process.on("exit", cleanup2);
|
|
53
|
+
process.on("uncaughtException", (err) => {
|
|
54
|
+
cleanup2();
|
|
55
|
+
console.error(err);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
});
|
|
58
|
+
return cleanup2;
|
|
59
|
+
}
|
|
60
|
+
function writeToStdout(data) {
|
|
61
|
+
process.stdout.write(data);
|
|
62
|
+
}
|
|
63
|
+
function parseBuffer(buf) {
|
|
64
|
+
const events = [];
|
|
65
|
+
let i = 0;
|
|
66
|
+
while (i < buf.length) {
|
|
67
|
+
const ch = buf[i];
|
|
68
|
+
if (ch === "\x1B") {
|
|
69
|
+
const rest = buf.slice(i + 1);
|
|
70
|
+
if (rest.startsWith("[")) {
|
|
71
|
+
const after = rest.slice(1);
|
|
72
|
+
const shiftArrow = after.match(/^1;2([ABCD])/);
|
|
73
|
+
if (shiftArrow) {
|
|
74
|
+
const key2 = emptyKey();
|
|
75
|
+
key2.shift = true;
|
|
76
|
+
const dir = shiftArrow[1];
|
|
77
|
+
if (dir === "A") key2.upArrow = true;
|
|
78
|
+
else if (dir === "B") key2.downArrow = true;
|
|
79
|
+
else if (dir === "C") key2.rightArrow = true;
|
|
80
|
+
else if (dir === "D") key2.leftArrow = true;
|
|
81
|
+
const seq = `\x1B[1;2${dir}`;
|
|
82
|
+
events.push([seq, key2]);
|
|
83
|
+
i += seq.length;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (after.length >= 1 && after[0] === "Z") {
|
|
87
|
+
const key2 = emptyKey();
|
|
88
|
+
key2.tab = true;
|
|
89
|
+
key2.shift = true;
|
|
90
|
+
const seq = `\x1B[Z`;
|
|
91
|
+
events.push([seq, key2]);
|
|
92
|
+
i += seq.length;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (after.length >= 1 && "ABCD".includes(after[0])) {
|
|
96
|
+
const key2 = emptyKey();
|
|
97
|
+
const dir = after[0];
|
|
98
|
+
if (dir === "A") key2.upArrow = true;
|
|
99
|
+
else if (dir === "B") key2.downArrow = true;
|
|
100
|
+
else if (dir === "C") key2.rightArrow = true;
|
|
101
|
+
else if (dir === "D") key2.leftArrow = true;
|
|
102
|
+
const seq = `\x1B[${dir}`;
|
|
103
|
+
events.push([seq, key2]);
|
|
104
|
+
i += seq.length;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const tildeMatch = after.match(/^(\d+)~/);
|
|
108
|
+
if (tildeMatch) {
|
|
109
|
+
const num = tildeMatch[1];
|
|
110
|
+
const key2 = emptyKey();
|
|
111
|
+
if (num === "5") key2.pageUp = true;
|
|
112
|
+
else if (num === "6") key2.pageDown = true;
|
|
113
|
+
else if (num === "3") key2.delete = true;
|
|
114
|
+
const seq = `\x1B[${num}~`;
|
|
115
|
+
events.push([seq, key2]);
|
|
116
|
+
i += seq.length;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
return { events, remaining: buf.slice(i) };
|
|
120
|
+
}
|
|
121
|
+
if (rest.length === 0) {
|
|
122
|
+
return { events, remaining: buf.slice(i) };
|
|
123
|
+
}
|
|
124
|
+
const metaCh = rest[0];
|
|
125
|
+
const key = emptyKey();
|
|
126
|
+
key.meta = true;
|
|
127
|
+
events.push([metaCh, key]);
|
|
128
|
+
i += 2;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (ch === "\r") {
|
|
132
|
+
const key = emptyKey();
|
|
133
|
+
key.return = true;
|
|
134
|
+
events.push([ch, key]);
|
|
135
|
+
i++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (ch === " ") {
|
|
139
|
+
const key = emptyKey();
|
|
140
|
+
key.tab = true;
|
|
141
|
+
events.push([ch, key]);
|
|
142
|
+
i++;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (ch === "\x7F" || ch === "\b") {
|
|
146
|
+
const key = emptyKey();
|
|
147
|
+
key.backspace = true;
|
|
148
|
+
events.push([ch, key]);
|
|
149
|
+
i++;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const code = ch.charCodeAt(0);
|
|
153
|
+
if (code >= 1 && code <= 26) {
|
|
154
|
+
const key = emptyKey();
|
|
155
|
+
key.ctrl = true;
|
|
156
|
+
const letter = String.fromCharCode(code + 96);
|
|
157
|
+
events.push([letter, key]);
|
|
158
|
+
i++;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
events.push([ch, emptyKey()]);
|
|
162
|
+
i++;
|
|
163
|
+
}
|
|
164
|
+
return { events, remaining: "" };
|
|
165
|
+
}
|
|
166
|
+
function startKeypressListener(handler) {
|
|
167
|
+
let buffer = "";
|
|
168
|
+
let escTimer = null;
|
|
169
|
+
const onData = (data) => {
|
|
170
|
+
if (rawBypassHandler) {
|
|
171
|
+
const handled = rawBypassHandler(data);
|
|
172
|
+
if (handled) return;
|
|
173
|
+
}
|
|
174
|
+
if (escTimer !== null) {
|
|
175
|
+
clearTimeout(escTimer);
|
|
176
|
+
escTimer = null;
|
|
177
|
+
}
|
|
178
|
+
buffer += data;
|
|
179
|
+
const { events, remaining } = parseBuffer(buffer);
|
|
180
|
+
buffer = remaining;
|
|
181
|
+
for (const [input, key] of events) {
|
|
182
|
+
handler(input, key);
|
|
183
|
+
}
|
|
184
|
+
if (buffer === "\x1B") {
|
|
185
|
+
escTimer = setTimeout(() => {
|
|
186
|
+
escTimer = null;
|
|
187
|
+
buffer = "";
|
|
188
|
+
const key = emptyKey();
|
|
189
|
+
key.escape = true;
|
|
190
|
+
handler("\x1B", key);
|
|
191
|
+
}, 50);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
process.stdin.on("data", onData);
|
|
195
|
+
return () => {
|
|
196
|
+
process.stdin.off("data", onData);
|
|
197
|
+
if (escTimer !== null) {
|
|
198
|
+
clearTimeout(escTimer);
|
|
199
|
+
escTimer = null;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function onResize(callback) {
|
|
204
|
+
const onStdoutResize = () => callback();
|
|
205
|
+
const onSigwinch = () => callback();
|
|
206
|
+
process.stdout.on("resize", onStdoutResize);
|
|
207
|
+
process.on("SIGWINCH", onSigwinch);
|
|
208
|
+
return () => {
|
|
209
|
+
process.stdout.off("resize", onStdoutResize);
|
|
210
|
+
process.off("SIGWINCH", onSigwinch);
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
var rawBypassHandler;
|
|
214
|
+
var init_terminal = __esm({
|
|
215
|
+
"src/tui/terminal.ts"() {
|
|
216
|
+
"use strict";
|
|
217
|
+
rawBypassHandler = null;
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// src/shared/paths.ts
|
|
222
|
+
import { homedir } from "os";
|
|
223
|
+
import { basename, join } from "path";
|
|
224
|
+
function globalDir() {
|
|
225
|
+
return join(homedir(), ".sisyphus");
|
|
226
|
+
}
|
|
227
|
+
function socketPath() {
|
|
228
|
+
return join(globalDir(), "daemon.sock");
|
|
229
|
+
}
|
|
230
|
+
function globalConfigPath() {
|
|
231
|
+
return join(globalDir(), "config.json");
|
|
232
|
+
}
|
|
233
|
+
function projectDir(cwd2) {
|
|
234
|
+
return join(cwd2, ".sisyphus");
|
|
235
|
+
}
|
|
236
|
+
function projectConfigPath(cwd2) {
|
|
237
|
+
return join(projectDir(cwd2), "config.json");
|
|
238
|
+
}
|
|
239
|
+
function sessionsDir(cwd2) {
|
|
240
|
+
return join(projectDir(cwd2), "sessions");
|
|
241
|
+
}
|
|
242
|
+
function sessionDir(cwd2, sessionId2) {
|
|
243
|
+
return join(sessionsDir(cwd2), sessionId2);
|
|
244
|
+
}
|
|
245
|
+
function statePath(cwd2, sessionId2) {
|
|
246
|
+
return join(sessionDir(cwd2, sessionId2), "state.json");
|
|
247
|
+
}
|
|
248
|
+
function reportsDir(cwd2, sessionId2) {
|
|
249
|
+
return join(sessionDir(cwd2, sessionId2), "reports");
|
|
250
|
+
}
|
|
251
|
+
function contextDir(cwd2, sessionId2) {
|
|
252
|
+
return join(sessionDir(cwd2, sessionId2), "context");
|
|
253
|
+
}
|
|
254
|
+
function roadmapPath(cwd2, sessionId2) {
|
|
255
|
+
return join(sessionDir(cwd2, sessionId2), "roadmap.md");
|
|
256
|
+
}
|
|
257
|
+
function goalPath(cwd2, sessionId2) {
|
|
258
|
+
return join(sessionDir(cwd2, sessionId2), "goal.md");
|
|
259
|
+
}
|
|
260
|
+
function strategyPath(cwd2, sessionId2) {
|
|
261
|
+
return join(sessionDir(cwd2, sessionId2), "strategy.md");
|
|
262
|
+
}
|
|
263
|
+
function digestPath(cwd2, sessionId2) {
|
|
264
|
+
return join(sessionDir(cwd2, sessionId2), "digest.json");
|
|
265
|
+
}
|
|
266
|
+
function logsDir(cwd2, sessionId2) {
|
|
267
|
+
return join(sessionDir(cwd2, sessionId2), "logs");
|
|
268
|
+
}
|
|
269
|
+
function askDir(cwd2, sessionId2) {
|
|
270
|
+
return join(contextDir(cwd2, sessionId2), "ask");
|
|
271
|
+
}
|
|
272
|
+
function askEntryDir(cwd2, sessionId2, askId2) {
|
|
273
|
+
return join(askDir(cwd2, sessionId2), askId2);
|
|
274
|
+
}
|
|
275
|
+
function askMetaPath(cwd2, sessionId2, askId2) {
|
|
276
|
+
return join(askEntryDir(cwd2, sessionId2, askId2), "meta.json");
|
|
277
|
+
}
|
|
278
|
+
function askDecisionsPath(cwd2, sessionId2, askId2) {
|
|
279
|
+
return join(askEntryDir(cwd2, sessionId2, askId2), "decisions.json");
|
|
280
|
+
}
|
|
281
|
+
function askOutputPath(cwd2, sessionId2, askId2) {
|
|
282
|
+
return join(askEntryDir(cwd2, sessionId2, askId2), "output.json");
|
|
283
|
+
}
|
|
284
|
+
function askProgressPath(cwd2, sessionId2, askId2) {
|
|
285
|
+
return join(askEntryDir(cwd2, sessionId2, askId2), "progress.json");
|
|
286
|
+
}
|
|
287
|
+
function tmuxSessionName(cwd2, sessionLabel) {
|
|
288
|
+
return `ssyph_${basename(cwd2)}_${sessionLabel}`;
|
|
289
|
+
}
|
|
290
|
+
function companionPath() {
|
|
291
|
+
return join(globalDir(), "companion.json");
|
|
292
|
+
}
|
|
293
|
+
function historyBaseDir() {
|
|
294
|
+
return join(globalDir(), "history");
|
|
295
|
+
}
|
|
296
|
+
function historySessionDir(sessionId2) {
|
|
297
|
+
return join(historyBaseDir(), sessionId2);
|
|
298
|
+
}
|
|
299
|
+
var init_paths = __esm({
|
|
300
|
+
"src/shared/paths.ts"() {
|
|
301
|
+
"use strict";
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// src/tui/render.ts
|
|
306
|
+
import stringWidth2 from "string-width";
|
|
307
|
+
function colorToSGR(color) {
|
|
308
|
+
const code = COLOR_SGR[color];
|
|
309
|
+
if (code === void 0) throw new Error(`Unknown color: ${color}`);
|
|
310
|
+
return code;
|
|
311
|
+
}
|
|
312
|
+
function renderLine(segs) {
|
|
313
|
+
let out = "";
|
|
314
|
+
for (const s of segs) {
|
|
315
|
+
const codes = [];
|
|
316
|
+
if (s.bold) codes.push("1");
|
|
317
|
+
if (s.dim) codes.push("2");
|
|
318
|
+
if (s.italic) codes.push("3");
|
|
319
|
+
if (s.strikethrough) codes.push("9");
|
|
320
|
+
if (s.inverse) codes.push("7");
|
|
321
|
+
if (s.fg) codes.push(s.fg);
|
|
322
|
+
else if (s.color) codes.push(String(colorToSGR(s.color)));
|
|
323
|
+
if (s.bg) codes.push(s.bg);
|
|
324
|
+
if (codes.length > 0) {
|
|
325
|
+
out += `\x1B[${codes.join(";")}m${s.text}\x1B[0m`;
|
|
326
|
+
} else {
|
|
327
|
+
out += s.text;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return out;
|
|
331
|
+
}
|
|
332
|
+
function createFrameBuffer(width, height) {
|
|
333
|
+
if (width !== cachedBlankWidth) {
|
|
334
|
+
cachedBlank = " ".repeat(width);
|
|
335
|
+
cachedBlankWidth = width;
|
|
336
|
+
}
|
|
337
|
+
const lines = new Array(height);
|
|
338
|
+
for (let i = 0; i < height; i++) lines[i] = cachedBlank;
|
|
339
|
+
return { lines, width, height };
|
|
340
|
+
}
|
|
341
|
+
function copyRows(buf, src, startRow, count) {
|
|
342
|
+
for (let i = 0; i < count && startRow + i < buf.height; i++) {
|
|
343
|
+
buf.lines[startRow + i] = src[startRow + i];
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function flushFrame(frame, prevFrame2, suffix) {
|
|
347
|
+
let out = "\x1B[?2026h";
|
|
348
|
+
for (let i = 0; i < frame.length; i++) {
|
|
349
|
+
if (frame[i] !== prevFrame2[i]) {
|
|
350
|
+
out += `\x1B[${i + 1};1H`;
|
|
351
|
+
out += "\x1B[2K";
|
|
352
|
+
out += frame[i];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (suffix) out += suffix;
|
|
356
|
+
out += "\x1B[?2026l";
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
function clipAnsi(content, maxWidth) {
|
|
360
|
+
let out = "";
|
|
361
|
+
let displayWidth = 0;
|
|
362
|
+
let i = 0;
|
|
363
|
+
while (i < content.length) {
|
|
364
|
+
if (content[i] === "\x1B" && content[i + 1] === "[") {
|
|
365
|
+
const seqLen = ansiLen(content, i);
|
|
366
|
+
if (seqLen > 0) {
|
|
367
|
+
out += content.substring(i, i + seqLen);
|
|
368
|
+
i += seqLen;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const cp = content.codePointAt(i);
|
|
373
|
+
if (cp < 32 && cp !== 27) {
|
|
374
|
+
i++;
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const ch = String.fromCodePoint(cp);
|
|
378
|
+
const chWidth = cp < 128 ? 1 : stringWidth2(ch);
|
|
379
|
+
if (displayWidth + chWidth > maxWidth) break;
|
|
380
|
+
out += ch;
|
|
381
|
+
displayWidth += chWidth;
|
|
382
|
+
i += ch.length;
|
|
383
|
+
}
|
|
384
|
+
if (out.includes("\x1B[") && !out.endsWith("\x1B[0m")) {
|
|
385
|
+
out += "\x1B[0m";
|
|
386
|
+
}
|
|
387
|
+
const remaining = maxWidth - displayWidth;
|
|
388
|
+
if (remaining > 0) out += " ".repeat(remaining);
|
|
389
|
+
return out;
|
|
390
|
+
}
|
|
391
|
+
function displayWidthFast(s) {
|
|
392
|
+
let w = 0;
|
|
393
|
+
let i = 0;
|
|
394
|
+
while (i < s.length) {
|
|
395
|
+
if (s[i] === "\x1B" && s[i + 1] === "[") {
|
|
396
|
+
const len = ansiLen(s, i);
|
|
397
|
+
if (len > 0) {
|
|
398
|
+
i += len;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
const cp = s.codePointAt(i);
|
|
403
|
+
const ch = String.fromCodePoint(cp);
|
|
404
|
+
w += cp < 128 ? 1 : stringWidth2(ch);
|
|
405
|
+
i += ch.length;
|
|
406
|
+
}
|
|
407
|
+
return w;
|
|
408
|
+
}
|
|
409
|
+
function ansiLen(s, i) {
|
|
410
|
+
let j = i + 2;
|
|
411
|
+
const len = s.length;
|
|
412
|
+
while (j < len) {
|
|
413
|
+
const c = s.charCodeAt(j);
|
|
414
|
+
if (c >= 48 && c <= 57 || c === 59) {
|
|
415
|
+
j++;
|
|
416
|
+
} else {
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (j < len) {
|
|
421
|
+
const c = s.charCodeAt(j);
|
|
422
|
+
if (c >= 65 && c <= 90 || c >= 97 && c <= 122) {
|
|
423
|
+
return j + 1 - i;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return 0;
|
|
427
|
+
}
|
|
428
|
+
function writeAt(buf, x, y, content) {
|
|
429
|
+
if (y < 0 || y >= buf.height) return;
|
|
430
|
+
if (x < 0 || x >= buf.width) return;
|
|
431
|
+
const existing = buf.lines[y];
|
|
432
|
+
const contentDisplayWidth = stringWidth2(content.replace(ANSI_RE, ""));
|
|
433
|
+
const prefix = sliceDisplayCols(existing, 0, x);
|
|
434
|
+
const suffix = sliceDisplayCols(existing, x + contentDisplayWidth, buf.width, true);
|
|
435
|
+
const prefixWidth = stringWidth2(prefix.replace(ANSI_RE, ""));
|
|
436
|
+
const paddedPrefix = prefix + " ".repeat(Math.max(0, x - prefixWidth));
|
|
437
|
+
buf.lines[y] = paddedPrefix + content + suffix;
|
|
438
|
+
}
|
|
439
|
+
function writeClipped(buf, x, y, content, maxWidth) {
|
|
440
|
+
if (y < 0 || y >= buf.height) return;
|
|
441
|
+
if (x < 0 || x >= buf.width) return;
|
|
442
|
+
let out = "";
|
|
443
|
+
let displayWidth = 0;
|
|
444
|
+
let i = 0;
|
|
445
|
+
while (i < content.length) {
|
|
446
|
+
if (content[i] === "\x1B" && content[i + 1] === "[") {
|
|
447
|
+
const seqLen = ansiLen(content, i);
|
|
448
|
+
if (seqLen > 0) {
|
|
449
|
+
out += content.substring(i, i + seqLen);
|
|
450
|
+
i += seqLen;
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
const cp = content.codePointAt(i);
|
|
455
|
+
if (cp < 32 && cp !== 27) {
|
|
456
|
+
i++;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const ch = String.fromCodePoint(cp);
|
|
460
|
+
const chWidth = cp < 128 ? 1 : stringWidth2(ch);
|
|
461
|
+
if (displayWidth + chWidth > maxWidth) break;
|
|
462
|
+
out += ch;
|
|
463
|
+
displayWidth += chWidth;
|
|
464
|
+
i += ch.length;
|
|
465
|
+
}
|
|
466
|
+
if (out.includes("\x1B[") && !out.endsWith("\x1B[0m")) {
|
|
467
|
+
out += "\x1B[0m";
|
|
468
|
+
}
|
|
469
|
+
const remaining = maxWidth - displayWidth;
|
|
470
|
+
if (remaining > 0) {
|
|
471
|
+
out += " ".repeat(remaining);
|
|
472
|
+
}
|
|
473
|
+
const existing = buf.lines[y];
|
|
474
|
+
const prefix = sliceDisplayCols(existing, 0, x);
|
|
475
|
+
const suffix = sliceDisplayCols(existing, x + maxWidth, buf.width, true);
|
|
476
|
+
const prefixDisplayW = displayWidthFast(prefix);
|
|
477
|
+
const paddedPrefix = prefixDisplayW < x ? prefix + " ".repeat(x - prefixDisplayW) : prefix;
|
|
478
|
+
buf.lines[y] = paddedPrefix + out + suffix;
|
|
479
|
+
}
|
|
480
|
+
function writeCenter(buf, row, content) {
|
|
481
|
+
const textWidth = stringWidth2(content.replace(ANSI_RE, ""));
|
|
482
|
+
const x = Math.max(0, Math.floor((buf.width - textWidth) / 2));
|
|
483
|
+
writeAt(buf, x, row, content);
|
|
484
|
+
}
|
|
485
|
+
function drawBorder(buf, x, y, w, h, color) {
|
|
486
|
+
const sgr = `\x1B[${colorToSGR(color)}m`;
|
|
487
|
+
const reset = "\x1B[0m";
|
|
488
|
+
writeAt(buf, x, y, sgr + "\u256D" + "\u2500".repeat(w - 2) + "\u256E" + reset);
|
|
489
|
+
writeAt(buf, x, y + h - 1, sgr + "\u2570" + "\u2500".repeat(w - 2) + "\u256F" + reset);
|
|
490
|
+
for (let row = y + 1; row < y + h - 1; row++) {
|
|
491
|
+
writeAt(buf, x, row, sgr + "\u2502" + reset);
|
|
492
|
+
writeAt(buf, x + w - 1, row, sgr + "\u2502" + reset);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function buildPanelRows(rect, lines, scroll, focused, borderColor, renderedCache) {
|
|
496
|
+
const { w, h } = rect;
|
|
497
|
+
const rows = new Array(h);
|
|
498
|
+
const color = focused ? "cyan" : "gray";
|
|
499
|
+
const sgr = `\x1B[${colorToSGR(color)}m`;
|
|
500
|
+
const reset = "\x1B[0m";
|
|
501
|
+
const innerW = w - 4;
|
|
502
|
+
const innerH = h - 2;
|
|
503
|
+
const blankInner = " ".repeat(innerW);
|
|
504
|
+
rows[0] = sgr + "\u256D" + "\u2500".repeat(w - 2) + "\u256E" + reset;
|
|
505
|
+
rows[h - 1] = sgr + "\u2570" + "\u2500".repeat(w - 2) + "\u256F" + reset;
|
|
506
|
+
const borderL = sgr + "\u2502" + reset + " ";
|
|
507
|
+
const borderR = " " + sgr + "\u2502" + reset;
|
|
508
|
+
const emptyRow = borderL + blankInner + borderR;
|
|
509
|
+
for (let i = 1; i < h - 1; i++) rows[i] = emptyRow;
|
|
510
|
+
if (innerW <= 0 || innerH <= 0) return rows;
|
|
511
|
+
let ansiLines;
|
|
512
|
+
if (renderedCache && renderedCache.lines === lines) {
|
|
513
|
+
ansiLines = renderedCache.ansi;
|
|
514
|
+
} else {
|
|
515
|
+
ansiLines = new Array(lines.length);
|
|
516
|
+
for (let i = 0; i < lines.length; i++) {
|
|
517
|
+
ansiLines[i] = renderLine(lines[i]);
|
|
518
|
+
}
|
|
519
|
+
if (renderedCache) {
|
|
520
|
+
renderedCache.lines = lines;
|
|
521
|
+
renderedCache.ansi = ansiLines;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
const hasOverflow = lines.length > innerH;
|
|
525
|
+
const viewableH = hasOverflow ? innerH - 1 : innerH;
|
|
526
|
+
const maxScroll = Math.max(0, lines.length - viewableH);
|
|
527
|
+
scroll.setMax(maxScroll);
|
|
528
|
+
const effectiveOffset = scroll.offset;
|
|
529
|
+
for (let i = 0; i < viewableH && effectiveOffset + i < ansiLines.length; i++) {
|
|
530
|
+
const clipped = clipAnsi(ansiLines[effectiveOffset + i], innerW);
|
|
531
|
+
rows[1 + i] = borderL + clipped + borderR;
|
|
532
|
+
}
|
|
533
|
+
if (hasOverflow) {
|
|
534
|
+
const scrollPct = maxScroll > 0 ? Math.round(effectiveOffset / maxScroll * 100) : 100;
|
|
535
|
+
const indicator = ` \u2195 ${scrollPct}% \xB7 ${lines.length} lines`;
|
|
536
|
+
const clipped = clipAnsi(`\x1B[2m${indicator}\x1B[0m`, innerW);
|
|
537
|
+
rows[1 + viewableH] = borderL + clipped + borderR;
|
|
538
|
+
}
|
|
539
|
+
return rows;
|
|
540
|
+
}
|
|
541
|
+
function buildEmptyPanelRows(rect, focused, borderColor, centerText) {
|
|
542
|
+
const { w, h } = rect;
|
|
543
|
+
const rows = new Array(h);
|
|
544
|
+
const color = focused ? "cyan" : "gray";
|
|
545
|
+
const sgr = `\x1B[${colorToSGR(color)}m`;
|
|
546
|
+
const reset = "\x1B[0m";
|
|
547
|
+
const innerW = w - 4;
|
|
548
|
+
const borderL = sgr + "\u2502" + reset + " ";
|
|
549
|
+
const borderR = " " + sgr + "\u2502" + reset;
|
|
550
|
+
const emptyRow = borderL + " ".repeat(innerW) + borderR;
|
|
551
|
+
rows[0] = sgr + "\u256D" + "\u2500".repeat(w - 2) + "\u256E" + reset;
|
|
552
|
+
rows[h - 1] = sgr + "\u2570" + "\u2500".repeat(w - 2) + "\u256F" + reset;
|
|
553
|
+
for (let i = 1; i < h - 1; i++) rows[i] = emptyRow;
|
|
554
|
+
if (centerText) {
|
|
555
|
+
const midRow = Math.floor(h / 2);
|
|
556
|
+
if (midRow > 0 && midRow < h - 1) {
|
|
557
|
+
const clipped = clipAnsi(centerText, innerW);
|
|
558
|
+
const textW = displayWidthFast(centerText);
|
|
559
|
+
const pad = Math.max(0, Math.floor((innerW - textW) / 2));
|
|
560
|
+
const centered = " ".repeat(pad) + clipped;
|
|
561
|
+
rows[midRow] = borderL + clipAnsi(centered, innerW) + borderR;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return rows;
|
|
565
|
+
}
|
|
566
|
+
function sliceDisplayCols(s, start, end, restoreState = false) {
|
|
567
|
+
let out = "";
|
|
568
|
+
let col = 0;
|
|
569
|
+
let i = 0;
|
|
570
|
+
let inSlice = false;
|
|
571
|
+
let hasOpenSGR = false;
|
|
572
|
+
let pendingSGR = "";
|
|
573
|
+
while (i < s.length && col < end) {
|
|
574
|
+
if (s[i] === "\x1B" && s[i + 1] === "[") {
|
|
575
|
+
const seqLen = ansiLen(s, i);
|
|
576
|
+
if (seqLen > 0) {
|
|
577
|
+
const seq = s.substring(i, i + seqLen);
|
|
578
|
+
if (col >= start) {
|
|
579
|
+
out += seq;
|
|
580
|
+
hasOpenSGR = seq !== "\x1B[0m" && seq !== "\x1B[m";
|
|
581
|
+
} else if (restoreState) {
|
|
582
|
+
if (seq === "\x1B[0m" || seq === "\x1B[m") {
|
|
583
|
+
pendingSGR = "";
|
|
584
|
+
} else {
|
|
585
|
+
pendingSGR += seq;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
i += seqLen;
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
const cp = s.codePointAt(i);
|
|
593
|
+
const ch = String.fromCodePoint(cp);
|
|
594
|
+
const chWidth = cp < 128 ? 1 : stringWidth2(ch);
|
|
595
|
+
if (col >= start) {
|
|
596
|
+
inSlice = true;
|
|
597
|
+
if (col + chWidth > end) break;
|
|
598
|
+
out += ch;
|
|
599
|
+
}
|
|
600
|
+
col += chWidth;
|
|
601
|
+
i += ch.length;
|
|
602
|
+
}
|
|
603
|
+
if (inSlice && hasOpenSGR) {
|
|
604
|
+
out += "\x1B[0m";
|
|
605
|
+
}
|
|
606
|
+
if (restoreState && pendingSGR) {
|
|
607
|
+
out = pendingSGR + out;
|
|
608
|
+
}
|
|
609
|
+
return out;
|
|
610
|
+
}
|
|
611
|
+
var COLOR_SGR, cachedBlank, cachedBlankWidth, ANSI_RE;
|
|
612
|
+
var init_render = __esm({
|
|
613
|
+
"src/tui/render.ts"() {
|
|
614
|
+
"use strict";
|
|
615
|
+
COLOR_SGR = {
|
|
616
|
+
black: 30,
|
|
617
|
+
red: 31,
|
|
618
|
+
green: 32,
|
|
619
|
+
yellow: 33,
|
|
620
|
+
blue: 34,
|
|
621
|
+
magenta: 35,
|
|
622
|
+
cyan: 36,
|
|
623
|
+
white: 37,
|
|
624
|
+
gray: 90
|
|
625
|
+
};
|
|
626
|
+
cachedBlank = "";
|
|
627
|
+
cachedBlankWidth = 0;
|
|
628
|
+
ANSI_RE = /\x1b\[[0-9;]*[a-zA-Z]/g;
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
// src/shared/config.ts
|
|
633
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
634
|
+
function readJsonFile(filePath) {
|
|
635
|
+
try {
|
|
636
|
+
const content = readFileSync4(filePath, "utf-8");
|
|
637
|
+
return JSON.parse(content);
|
|
638
|
+
} catch {
|
|
639
|
+
return {};
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
function loadConfig(cwd2) {
|
|
643
|
+
const globalConfig = readJsonFile(globalConfigPath());
|
|
644
|
+
const projectConfig = readJsonFile(projectConfigPath(cwd2));
|
|
645
|
+
if (projectConfig.upload !== void 0) {
|
|
646
|
+
console.warn(
|
|
647
|
+
"ignoring `upload` block from project-local .sisyphus/config.json \u2014 only the global config can set upload credentials"
|
|
648
|
+
);
|
|
649
|
+
delete projectConfig.upload;
|
|
650
|
+
}
|
|
651
|
+
const merged = { ...DEFAULT_CONFIG, ...globalConfig, ...projectConfig };
|
|
652
|
+
if (globalConfig.statusBar || projectConfig.statusBar) {
|
|
653
|
+
merged.statusBar = {
|
|
654
|
+
...merged.statusBar,
|
|
655
|
+
...globalConfig.statusBar,
|
|
656
|
+
...projectConfig.statusBar,
|
|
657
|
+
colors: {
|
|
658
|
+
...merged.statusBar?.colors,
|
|
659
|
+
...globalConfig.statusBar?.colors,
|
|
660
|
+
...projectConfig.statusBar?.colors
|
|
661
|
+
},
|
|
662
|
+
segments: {
|
|
663
|
+
...merged.statusBar?.segments,
|
|
664
|
+
...globalConfig.statusBar?.segments,
|
|
665
|
+
...projectConfig.statusBar?.segments
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
return merged;
|
|
670
|
+
}
|
|
671
|
+
var DEFAULT_CONFIG;
|
|
672
|
+
var init_config = __esm({
|
|
673
|
+
"src/shared/config.ts"() {
|
|
674
|
+
"use strict";
|
|
675
|
+
init_paths();
|
|
676
|
+
DEFAULT_CONFIG = {
|
|
677
|
+
model: "claude-opus-4-7[1m]",
|
|
678
|
+
pollIntervalMs: 5e3,
|
|
679
|
+
orchestratorEffort: "xhigh",
|
|
680
|
+
agentEffort: "medium",
|
|
681
|
+
notifications: {
|
|
682
|
+
enabled: true,
|
|
683
|
+
sound: "/System/Library/Sounds/Hero.aiff"
|
|
684
|
+
},
|
|
685
|
+
companionPopup: true,
|
|
686
|
+
requiredPlugins: [
|
|
687
|
+
{ name: "devcore", marketplace: "crouton-kit" }
|
|
688
|
+
]
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
// src/daemon/history.ts
|
|
694
|
+
import { appendFileSync, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, renameSync as renameSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as rmSync2, statSync } from "fs";
|
|
695
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
696
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
697
|
+
var init_history = __esm({
|
|
698
|
+
"src/daemon/history.ts"() {
|
|
699
|
+
"use strict";
|
|
700
|
+
init_paths();
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
// src/daemon/lib/atomic.ts
|
|
705
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
706
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
707
|
+
import { renameSync as renameSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
708
|
+
function atomicWrite(filePath, data) {
|
|
709
|
+
const dir = dirname4(filePath);
|
|
710
|
+
const tmpPath = join7(dir, `.atomic.${randomUUID4()}.tmp`);
|
|
711
|
+
writeFileSync5(tmpPath, data, "utf-8");
|
|
712
|
+
renameSync4(tmpPath, filePath);
|
|
713
|
+
}
|
|
714
|
+
async function withLock(key, fn) {
|
|
715
|
+
const prev = locks.get(key) ?? Promise.resolve();
|
|
716
|
+
let resolve2;
|
|
717
|
+
const next = new Promise((r) => {
|
|
718
|
+
resolve2 = r;
|
|
719
|
+
});
|
|
720
|
+
locks.set(key, next);
|
|
721
|
+
await prev;
|
|
722
|
+
try {
|
|
723
|
+
return fn();
|
|
724
|
+
} finally {
|
|
725
|
+
resolve2();
|
|
726
|
+
if (locks.get(key) === next) {
|
|
727
|
+
locks.delete(key);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
var locks;
|
|
732
|
+
var init_atomic = __esm({
|
|
733
|
+
"src/daemon/lib/atomic.ts"() {
|
|
734
|
+
"use strict";
|
|
735
|
+
locks = /* @__PURE__ */ new Map();
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
// src/shared/shell.ts
|
|
740
|
+
function shellQuote(s) {
|
|
741
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
742
|
+
}
|
|
743
|
+
var init_shell = __esm({
|
|
744
|
+
"src/shared/shell.ts"() {
|
|
745
|
+
"use strict";
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
// src/daemon/notify.ts
|
|
750
|
+
import { spawn, execFile as execFile2 } from "child_process";
|
|
751
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync4 } from "fs";
|
|
752
|
+
import { join as join8 } from "path";
|
|
753
|
+
import { homedir as homedir3 } from "os";
|
|
754
|
+
var TMUX_SOCKET, SWITCH_SCRIPT;
|
|
755
|
+
var init_notify = __esm({
|
|
756
|
+
"src/daemon/notify.ts"() {
|
|
757
|
+
"use strict";
|
|
758
|
+
init_shell();
|
|
759
|
+
TMUX_SOCKET = `/tmp/tmux-${process.getuid?.() ?? 0}/default`;
|
|
760
|
+
SWITCH_SCRIPT = [
|
|
761
|
+
"#!/bin/bash",
|
|
762
|
+
'SESSION="$1"',
|
|
763
|
+
`TMUX_SOCKET="${TMUX_SOCKET}"`,
|
|
764
|
+
"TMUX=/opt/homebrew/bin/tmux",
|
|
765
|
+
"",
|
|
766
|
+
"# Find any attached client (user is likely on a different session)",
|
|
767
|
+
`CLIENT_TTY=$("$TMUX" -S "$TMUX_SOCKET" list-clients -F '#{client_tty}' 2>/dev/null | head -1)`,
|
|
768
|
+
'[ -z "$CLIENT_TTY" ] && exit 0',
|
|
769
|
+
"",
|
|
770
|
+
"# Switch that client to the target session",
|
|
771
|
+
'"$TMUX" -S "$TMUX_SOCKET" switch-client -c "$CLIENT_TTY" -t "$SESSION" 2>/dev/null',
|
|
772
|
+
'"$TMUX" -S "$TMUX_SOCKET" select-window -t "$SESSION" 2>/dev/null',
|
|
773
|
+
"",
|
|
774
|
+
"# Bring iTerm2 to front and select the tab with this client",
|
|
775
|
+
`TTY_SHORT=$(echo "$CLIENT_TTY" | sed 's|/dev/||')`,
|
|
776
|
+
'osascript -e "',
|
|
777
|
+
' tell application \\"iTerm2\\"',
|
|
778
|
+
" activate",
|
|
779
|
+
" repeat with w in windows",
|
|
780
|
+
" tell w",
|
|
781
|
+
" repeat with t in tabs",
|
|
782
|
+
" tell t",
|
|
783
|
+
" repeat with s in sessions",
|
|
784
|
+
" tell s",
|
|
785
|
+
' if tty contains \\"$TTY_SHORT\\" then',
|
|
786
|
+
" select t",
|
|
787
|
+
" return",
|
|
788
|
+
" end if",
|
|
789
|
+
" end tell",
|
|
790
|
+
" end repeat",
|
|
791
|
+
" end tell",
|
|
792
|
+
" end repeat",
|
|
793
|
+
" end tell",
|
|
794
|
+
" end repeat",
|
|
795
|
+
" end tell",
|
|
796
|
+
`" 2>/dev/null || osascript -e 'tell application "iTerm2" to activate' 2>/dev/null`,
|
|
797
|
+
""
|
|
798
|
+
].join("\n");
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
// src/shared/gitignore.ts
|
|
803
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
804
|
+
import { join as join9 } from "path";
|
|
805
|
+
var init_gitignore = __esm({
|
|
806
|
+
"src/shared/gitignore.ts"() {
|
|
807
|
+
"use strict";
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
// src/shared/types.ts
|
|
812
|
+
var init_types = __esm({
|
|
813
|
+
"src/shared/types.ts"() {
|
|
814
|
+
"use strict";
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
// src/daemon/state.ts
|
|
819
|
+
import { copyFileSync, cpSync, existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync7, readdirSync as readdirSync3, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
820
|
+
import { join as join10 } from "path";
|
|
821
|
+
var init_state = __esm({
|
|
822
|
+
"src/daemon/state.ts"() {
|
|
823
|
+
"use strict";
|
|
824
|
+
init_atomic();
|
|
825
|
+
init_paths();
|
|
826
|
+
init_gitignore();
|
|
827
|
+
init_types();
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
// src/daemon/ask-store.ts
|
|
832
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync8, readdirSync as readdirSync4 } from "fs";
|
|
833
|
+
function readDecisions(cwd2, sessionId2, askId2) {
|
|
834
|
+
const p = askDecisionsPath(cwd2, sessionId2, askId2);
|
|
835
|
+
try {
|
|
836
|
+
return JSON.parse(readFileSync8(p, { encoding: "utf-8" }));
|
|
837
|
+
} catch (_e) {
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function readProgress(cwd2, sessionId2, askId2) {
|
|
842
|
+
const p = askProgressPath(cwd2, sessionId2, askId2);
|
|
843
|
+
try {
|
|
844
|
+
const data = JSON.parse(readFileSync8(p, { encoding: "utf-8" }));
|
|
845
|
+
if (!Array.isArray(data["responses"])) return null;
|
|
846
|
+
return { responses: data["responses"], savedAt: data["savedAt"] };
|
|
847
|
+
} catch (_e) {
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
function writeOutput(cwd2, sessionId2, askId2, responses, completedAt) {
|
|
852
|
+
atomicWrite(askOutputPath(cwd2, sessionId2, askId2), JSON.stringify({
|
|
853
|
+
responses,
|
|
854
|
+
completedAt: completedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
855
|
+
}, null, 2));
|
|
856
|
+
}
|
|
857
|
+
function readMeta(cwd2, sessionId2, askId2) {
|
|
858
|
+
const p = askMetaPath(cwd2, sessionId2, askId2);
|
|
859
|
+
if (!existsSync7(p)) {
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
return JSON.parse(readFileSync8(p, "utf-8"));
|
|
863
|
+
}
|
|
864
|
+
async function updateMeta(cwd2, sessionId2, askId2, patch) {
|
|
865
|
+
return withLock(askId2, () => {
|
|
866
|
+
const cur = readMeta(cwd2, sessionId2, askId2);
|
|
867
|
+
if (!cur) {
|
|
868
|
+
throw new Error(`updateMeta: askId ${askId2} not found`);
|
|
869
|
+
}
|
|
870
|
+
const next = { ...cur, ...patch };
|
|
871
|
+
atomicWrite(askMetaPath(cwd2, sessionId2, askId2), JSON.stringify(next, null, 2));
|
|
872
|
+
return next;
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
var init_ask_store = __esm({
|
|
876
|
+
"src/daemon/ask-store.ts"() {
|
|
877
|
+
"use strict";
|
|
878
|
+
init_paths();
|
|
879
|
+
init_config();
|
|
880
|
+
init_history();
|
|
881
|
+
init_atomic();
|
|
882
|
+
init_notify();
|
|
883
|
+
init_state();
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
// src/tui/single-ask.ts
|
|
888
|
+
var single_ask_exports = {};
|
|
889
|
+
__export(single_ask_exports, {
|
|
890
|
+
runSingleAsk: () => runSingleAsk
|
|
891
|
+
});
|
|
892
|
+
import { existsSync as existsSync11, watchFile, unwatchFile } from "fs";
|
|
893
|
+
import { mountPanel as mountPanel2 } from "@crouton-kit/humanloop";
|
|
894
|
+
async function runSingleAsk(opts) {
|
|
895
|
+
const { cwd: cwd2, sessionId: sessionId2, askId: askId2 } = opts;
|
|
896
|
+
const meta = readMeta(cwd2, sessionId2, askId2);
|
|
897
|
+
if (!meta || meta.status === "answered") {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
const deck = readDecisions(cwd2, sessionId2, askId2);
|
|
901
|
+
if (!deck) return;
|
|
902
|
+
const cleanupTerminal = setupTerminal();
|
|
903
|
+
let exiting = false;
|
|
904
|
+
let panel = null;
|
|
905
|
+
let prevFrame2 = [];
|
|
906
|
+
let stopKeypress = null;
|
|
907
|
+
let stopResize = null;
|
|
908
|
+
const outputPath = askOutputPath(cwd2, sessionId2, askId2);
|
|
909
|
+
const exit = (code) => {
|
|
910
|
+
if (exiting) return;
|
|
911
|
+
exiting = true;
|
|
912
|
+
try {
|
|
913
|
+
stopKeypress?.();
|
|
914
|
+
} catch {
|
|
915
|
+
}
|
|
916
|
+
try {
|
|
917
|
+
stopResize?.();
|
|
918
|
+
} catch {
|
|
919
|
+
}
|
|
920
|
+
try {
|
|
921
|
+
panel?.unmount();
|
|
922
|
+
} catch {
|
|
923
|
+
}
|
|
924
|
+
try {
|
|
925
|
+
unwatchFile(outputPath, onExternalChange);
|
|
926
|
+
} catch {
|
|
927
|
+
}
|
|
928
|
+
cleanupTerminal();
|
|
929
|
+
process.exit(code);
|
|
930
|
+
};
|
|
931
|
+
const flushHost = (lines) => {
|
|
932
|
+
const out = flushFrame(lines, prevFrame2, "\x1B[?25l");
|
|
933
|
+
writeToStdout(out);
|
|
934
|
+
prevFrame2 = lines;
|
|
935
|
+
};
|
|
936
|
+
const onExternalChange = () => {
|
|
937
|
+
if (exiting) return;
|
|
938
|
+
if (!existsSync11(outputPath)) return;
|
|
939
|
+
exit(0);
|
|
940
|
+
};
|
|
941
|
+
let lastResponses = [];
|
|
942
|
+
const submit = (responses) => {
|
|
943
|
+
if (exiting) return;
|
|
944
|
+
void (async () => {
|
|
945
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
946
|
+
writeOutput(cwd2, sessionId2, askId2, responses, completedAt);
|
|
947
|
+
try {
|
|
948
|
+
await updateMeta(cwd2, sessionId2, askId2, { status: "answered", completedAt });
|
|
949
|
+
} catch {
|
|
950
|
+
}
|
|
951
|
+
exit(0);
|
|
952
|
+
})();
|
|
953
|
+
};
|
|
954
|
+
const cols = process.stdout.columns ?? 80;
|
|
955
|
+
const rows = process.stdout.rows ?? 24;
|
|
956
|
+
panel = mountPanel2({
|
|
957
|
+
deck,
|
|
958
|
+
cols,
|
|
959
|
+
rows,
|
|
960
|
+
progressPath: askProgressPath(cwd2, sessionId2, askId2),
|
|
961
|
+
onProgress: (responses) => {
|
|
962
|
+
lastResponses = responses;
|
|
963
|
+
const cur = readMeta(cwd2, sessionId2, askId2);
|
|
964
|
+
if (cur?.status === "pending") {
|
|
965
|
+
void updateMeta(cwd2, sessionId2, askId2, { status: "in-progress", startedAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => {
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
if (panel) flushHost(panel.render());
|
|
969
|
+
},
|
|
970
|
+
onComplete: (responses) => {
|
|
971
|
+
submit(responses);
|
|
972
|
+
},
|
|
973
|
+
// Final-phase Enter on an incomplete deck — submit what we have.
|
|
974
|
+
onExit: () => {
|
|
975
|
+
submit(lastResponses);
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
stopKeypress = startKeypressListener((input, key) => {
|
|
979
|
+
if (exiting || !panel) return;
|
|
980
|
+
panel.handleKey(input, key);
|
|
981
|
+
flushHost(panel.render());
|
|
982
|
+
});
|
|
983
|
+
stopResize = onResize(() => {
|
|
984
|
+
if (exiting || !panel) return;
|
|
985
|
+
const newCols = process.stdout.columns ?? 80;
|
|
986
|
+
const newRows = process.stdout.rows ?? 24;
|
|
987
|
+
panel.handleResize(newCols, newRows);
|
|
988
|
+
prevFrame2 = [];
|
|
989
|
+
flushHost(panel.render());
|
|
990
|
+
});
|
|
991
|
+
watchFile(outputPath, { interval: 250 }, onExternalChange);
|
|
992
|
+
if (existsSync11(outputPath)) {
|
|
993
|
+
exit(0);
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
flushHost(panel.render());
|
|
997
|
+
await new Promise(() => {
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
var init_single_ask = __esm({
|
|
1001
|
+
"src/tui/single-ask.ts"() {
|
|
1002
|
+
"use strict";
|
|
1003
|
+
init_ask_store();
|
|
1004
|
+
init_paths();
|
|
1005
|
+
init_terminal();
|
|
1006
|
+
init_render();
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
// src/tui/index.ts
|
|
1011
|
+
init_terminal();
|
|
68
1012
|
|
|
69
1013
|
// src/tui/state.ts
|
|
70
1014
|
var OPTIONAL_COMPOSE = /* @__PURE__ */ new Set(["resume", "continue"]);
|
|
@@ -271,19 +1215,184 @@ function autoExpandCycle(state2) {
|
|
|
271
1215
|
}
|
|
272
1216
|
|
|
273
1217
|
// src/tui/app.ts
|
|
274
|
-
import { readFileSync as
|
|
275
|
-
import { join as
|
|
1218
|
+
import { readFileSync as readFileSync15, existsSync as existsSync10, readdirSync as readdirSync7, statSync as statSync4 } from "fs";
|
|
1219
|
+
import { join as join14 } from "path";
|
|
276
1220
|
|
|
277
1221
|
// src/tui/input.ts
|
|
278
1222
|
import { execSync } from "child_process";
|
|
279
|
-
import { readFileSync as
|
|
1223
|
+
import { readFileSync as readFileSync10, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
1224
|
+
import { join as join11 } from "path";
|
|
1225
|
+
|
|
1226
|
+
// src/shared/session-export.ts
|
|
1227
|
+
init_paths();
|
|
1228
|
+
import { execFile } from "child_process";
|
|
1229
|
+
import { promisify } from "util";
|
|
1230
|
+
import { existsSync, readFileSync, mkdirSync, symlinkSync, rmSync, writeFileSync } from "fs";
|
|
1231
|
+
import { homedir as homedir2 } from "os";
|
|
280
1232
|
import { join as join2 } from "path";
|
|
1233
|
+
function sanitizeName(name) {
|
|
1234
|
+
return name.replace(/[^a-zA-Z0-9-_]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
1235
|
+
}
|
|
1236
|
+
function buildOutputPath(label, dir) {
|
|
1237
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1238
|
+
mkdirSync(dir, { recursive: true });
|
|
1239
|
+
const base = `sisyphus-${label}-${date}`;
|
|
1240
|
+
let candidate = join2(dir, `${base}.zip`);
|
|
1241
|
+
let counter = 1;
|
|
1242
|
+
while (existsSync(candidate)) {
|
|
1243
|
+
counter++;
|
|
1244
|
+
candidate = join2(dir, `${base}-${counter}.zip`);
|
|
1245
|
+
}
|
|
1246
|
+
return candidate;
|
|
1247
|
+
}
|
|
1248
|
+
function generateGuide() {
|
|
1249
|
+
return `# Sisyphus Session Export
|
|
1250
|
+
|
|
1251
|
+
## Quick Orientation
|
|
1252
|
+
|
|
1253
|
+
Start with \`session/state.json\` for the full session state, or \`history/session.json\` for a compact summary with metrics.
|
|
1254
|
+
|
|
1255
|
+
## session/
|
|
1256
|
+
|
|
1257
|
+
Project-local session data \u2014 the orchestrator's working directory.
|
|
1258
|
+
|
|
1259
|
+
### Top-level files
|
|
1260
|
+
- **state.json** \u2014 Complete session state: id, task, status, timing, and the full \`agents[]\` array (each agent has id, type, instruction, status, reports, Claude session ID, and resume args)
|
|
1261
|
+
- **goal.md** \u2014 The task description; updated if the goal evolves across phases
|
|
1262
|
+
- **initial-prompt.md** \u2014 Verbatim user input that started the session
|
|
1263
|
+
- **roadmap.md** \u2014 Orchestrator's working memory: current stage, exit criteria, active context files, next steps
|
|
1264
|
+
- **strategy.md** \u2014 Work breakdown: completed stages, current stage decomposition (concerns/phases), and what's ahead
|
|
1265
|
+
- **digest.json** \u2014 4-field snapshot: \`recentWork\`, \`unusualEvents\`, \`currentActivity\`, \`whatsNext\`
|
|
1266
|
+
|
|
1267
|
+
### Subdirectories
|
|
1268
|
+
|
|
1269
|
+
**context/** \u2014 Research artifacts produced by agents and consumed by downstream agents
|
|
1270
|
+
- \`explore-*.md\` \u2014 Codebase exploration findings (key files, architecture notes)
|
|
1271
|
+
- \`requirements*.md/json\` \u2014 Feature requirements (structured + human-readable)
|
|
1272
|
+
- \`design*.md/json\` \u2014 Architecture specs, decision records, diagrams
|
|
1273
|
+
- \`{agent-id}/plan*.md\` \u2014 Implementation plans (tasks, files to touch, dependencies) \u2014 per plan-lead subdirectory
|
|
1274
|
+
- \`e2e-recipe.md\` \u2014 End-to-end validation steps
|
|
1275
|
+
- \`review-*.md\` \u2014 Code review findings (severity-ranked)
|
|
1276
|
+
- \`completion-summary.md\` \u2014 Final handoff document
|
|
1277
|
+
|
|
1278
|
+
**logs/** \u2014 One \`cycle-NNN.md\` per orchestrator cycle. Each logs what happened, agents spawned, user decisions, and key findings.
|
|
1279
|
+
|
|
1280
|
+
**prompts/** \u2014 Full agent configs, one set per agent:
|
|
1281
|
+
- \`agent-NNN-system.md\` \u2014 System prompt (instructions, tools, output format)
|
|
1282
|
+
- \`agent-NNN-run.sh\` \u2014 Executable bash script to resume the agent (contains env, CLI args, instruction)
|
|
1283
|
+
- \`agent-NNN-plugin/\` \u2014 Plugin directory (hooks, sub-agent configs)
|
|
1284
|
+
|
|
1285
|
+
**reports/** \u2014 Agent deliverables:
|
|
1286
|
+
- \`agent-NNN-final.md\` \u2014 Final report (findings, implementation summary, or review results)
|
|
1287
|
+
- \`agent-NNN-00N.md\` \u2014 Interim progress reports (optional)
|
|
1288
|
+
|
|
1289
|
+
**snapshots/** \u2014 Point-in-time checkpoints (\`snapshots/cycle-N/\`). Each contains state.json, roadmap.md, strategy.md, and logs/ as they were at that cycle boundary. Used for rollback.
|
|
1290
|
+
|
|
1291
|
+
**.tui/** \u2014 Lightweight TUI render cache (cycle summaries for display). Regenerable; not primary data.
|
|
1292
|
+
|
|
1293
|
+
## history/
|
|
1294
|
+
|
|
1295
|
+
Global telemetry from the daemon \u2014 timing, events, and aggregate metrics.
|
|
1296
|
+
|
|
1297
|
+
- **events.jsonl** \u2014 Newline-delimited JSON event stream. Each line: \`{ ts, event, sessionId, data }\`. Events include session-start, agent-spawned, agent-completed, cycle-boundary, signals-snapshot, session-end, etc. Complete audit trail.
|
|
1298
|
+
- **session.json** \u2014 Summary: id, name, task, status, timing (activeMs, wallClockMs, efficiency), agent/cycle counts, crash/rollback counts, completion report, and a compact agents array.
|
|
1299
|
+
`;
|
|
1300
|
+
}
|
|
1301
|
+
var execFileAsync = promisify(execFile);
|
|
1302
|
+
async function exportSessionToZip(sessionId2, cwd2, options) {
|
|
1303
|
+
const reveal = options?.reveal ?? true;
|
|
1304
|
+
const sessDir = sessionDir(cwd2, sessionId2);
|
|
1305
|
+
const histDir = historySessionDir(sessionId2);
|
|
1306
|
+
const sessExists = existsSync(sessDir);
|
|
1307
|
+
const histExists = existsSync(histDir);
|
|
1308
|
+
if (!sessExists && !histExists) {
|
|
1309
|
+
throw new Error(`No data found for session ${sessionId2}`);
|
|
1310
|
+
}
|
|
1311
|
+
let label = sessionId2.slice(0, 8);
|
|
1312
|
+
const stPath = statePath(cwd2, sessionId2);
|
|
1313
|
+
if (existsSync(stPath)) {
|
|
1314
|
+
try {
|
|
1315
|
+
const state2 = JSON.parse(readFileSync(stPath, "utf-8"));
|
|
1316
|
+
if (state2.name) {
|
|
1317
|
+
label = sanitizeName(state2.name);
|
|
1318
|
+
}
|
|
1319
|
+
} catch {
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
const dir = options?.outputDir ?? join2(homedir2(), "Downloads");
|
|
1323
|
+
const outputPath = buildOutputPath(label, dir);
|
|
1324
|
+
const tmpDir = `/tmp/sisyphus-export-${sessionId2.slice(0, 8)}-${Date.now()}`;
|
|
1325
|
+
try {
|
|
1326
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
1327
|
+
writeFileSync(join2(tmpDir, "CLAUDE.md"), generateGuide(), "utf-8");
|
|
1328
|
+
if (sessExists) {
|
|
1329
|
+
symlinkSync(sessDir, join2(tmpDir, "session"));
|
|
1330
|
+
}
|
|
1331
|
+
if (histExists) {
|
|
1332
|
+
symlinkSync(histDir, join2(tmpDir, "history"));
|
|
1333
|
+
}
|
|
1334
|
+
const parts = ["CLAUDE.md", sessExists ? "session/" : "", histExists ? "history/" : ""].filter(Boolean);
|
|
1335
|
+
await execFileAsync("zip", ["-rq", outputPath, ...parts], { cwd: tmpDir });
|
|
1336
|
+
} finally {
|
|
1337
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
1338
|
+
}
|
|
1339
|
+
if (reveal) {
|
|
1340
|
+
try {
|
|
1341
|
+
await execFileAsync("open", ["-R", outputPath]);
|
|
1342
|
+
} catch {
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
return outputPath;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
// src/tui/input.ts
|
|
1349
|
+
init_paths();
|
|
281
1350
|
|
|
282
1351
|
// src/tui/lib/tree.ts
|
|
283
|
-
import { join } from "path";
|
|
1352
|
+
import { join as join3 } from "path";
|
|
284
1353
|
|
|
285
1354
|
// src/tui/lib/format.ts
|
|
286
1355
|
import stringWidth from "string-width";
|
|
1356
|
+
|
|
1357
|
+
// src/shared/format.ts
|
|
1358
|
+
function formatDuration(startOrMs, endIso) {
|
|
1359
|
+
let totalMs;
|
|
1360
|
+
if (typeof startOrMs === "number") {
|
|
1361
|
+
totalMs = startOrMs;
|
|
1362
|
+
} else {
|
|
1363
|
+
const start = new Date(startOrMs).getTime();
|
|
1364
|
+
const end = endIso ? new Date(endIso).getTime() : Date.now();
|
|
1365
|
+
totalMs = end - start;
|
|
1366
|
+
}
|
|
1367
|
+
const totalSeconds = Math.floor(totalMs / 1e3);
|
|
1368
|
+
if (totalSeconds < 0) return "0s";
|
|
1369
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
1370
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
1371
|
+
const seconds = totalSeconds % 60;
|
|
1372
|
+
if (hours > 0) return `${hours}h${minutes}m`;
|
|
1373
|
+
if (minutes > 0) return `${minutes}m${seconds}s`;
|
|
1374
|
+
return `${seconds}s`;
|
|
1375
|
+
}
|
|
1376
|
+
function statusColor(status) {
|
|
1377
|
+
switch (status) {
|
|
1378
|
+
case "active":
|
|
1379
|
+
case "running":
|
|
1380
|
+
return "green";
|
|
1381
|
+
case "completed":
|
|
1382
|
+
return "cyan";
|
|
1383
|
+
case "paused":
|
|
1384
|
+
return "yellow";
|
|
1385
|
+
case "killed":
|
|
1386
|
+
case "crashed":
|
|
1387
|
+
return "red";
|
|
1388
|
+
case "lost":
|
|
1389
|
+
return "gray";
|
|
1390
|
+
default:
|
|
1391
|
+
return "white";
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// src/tui/lib/format.ts
|
|
287
1396
|
function formatTimeAgo(iso) {
|
|
288
1397
|
const diff = Date.now() - new Date(iso).getTime();
|
|
289
1398
|
const minutes = Math.floor(diff / 6e4);
|
|
@@ -493,6 +1602,7 @@ function wrapText(text, width) {
|
|
|
493
1602
|
}
|
|
494
1603
|
|
|
495
1604
|
// src/tui/lib/tree.ts
|
|
1605
|
+
init_paths();
|
|
496
1606
|
function sessionSortKey(s) {
|
|
497
1607
|
if (s.status === "completed") return 4;
|
|
498
1608
|
const open = s.windowAlive ?? false;
|
|
@@ -669,7 +1779,7 @@ function buildTree(sessions, selectedSession, expanded, cwd2, polledContextFiles
|
|
|
669
1779
|
expanded: false,
|
|
670
1780
|
sessionId: s.id,
|
|
671
1781
|
label: filename,
|
|
672
|
-
filePath:
|
|
1782
|
+
filePath: join3(contextDir(cwd2, s.id), filename)
|
|
673
1783
|
});
|
|
674
1784
|
}
|
|
675
1785
|
}
|
|
@@ -741,6 +1851,1339 @@ function findParentIndex(nodes, index) {
|
|
|
741
1851
|
return 0;
|
|
742
1852
|
}
|
|
743
1853
|
|
|
1854
|
+
// src/tui/panels/overlays.ts
|
|
1855
|
+
init_render();
|
|
1856
|
+
|
|
1857
|
+
// src/shared/companion-render.ts
|
|
1858
|
+
import stringWidth3 from "string-width";
|
|
1859
|
+
function sliceToWidth(s, maxCols) {
|
|
1860
|
+
let w = 0;
|
|
1861
|
+
let i = 0;
|
|
1862
|
+
while (i < s.length) {
|
|
1863
|
+
const cp = s.codePointAt(i);
|
|
1864
|
+
const ch = String.fromCodePoint(cp);
|
|
1865
|
+
const cw = stringWidth3(ch);
|
|
1866
|
+
if (w + cw > maxCols) break;
|
|
1867
|
+
w += cw;
|
|
1868
|
+
i += ch.length;
|
|
1869
|
+
}
|
|
1870
|
+
return s.slice(0, i);
|
|
1871
|
+
}
|
|
1872
|
+
var IDLE_HOBBIES = [
|
|
1873
|
+
"reading Camus",
|
|
1874
|
+
"stacking pebbles",
|
|
1875
|
+
"watching clouds",
|
|
1876
|
+
"sketching boulders",
|
|
1877
|
+
"counting stars",
|
|
1878
|
+
"writing haiku",
|
|
1879
|
+
"practicing zen",
|
|
1880
|
+
"studying geology",
|
|
1881
|
+
"polishing rocks",
|
|
1882
|
+
"mapping the hill",
|
|
1883
|
+
"resting",
|
|
1884
|
+
"stargazing",
|
|
1885
|
+
"whittling",
|
|
1886
|
+
"collecting fossils",
|
|
1887
|
+
"napping on summit",
|
|
1888
|
+
"journaling",
|
|
1889
|
+
"stretching",
|
|
1890
|
+
"humming",
|
|
1891
|
+
"doodling",
|
|
1892
|
+
"tending moss",
|
|
1893
|
+
"making tea",
|
|
1894
|
+
"reading Myth of Sisyphus",
|
|
1895
|
+
"reorganizing rocks",
|
|
1896
|
+
"people watching",
|
|
1897
|
+
"whistling"
|
|
1898
|
+
];
|
|
1899
|
+
var SPINNER_VERBS = [
|
|
1900
|
+
// physical
|
|
1901
|
+
"pushing",
|
|
1902
|
+
"hauling",
|
|
1903
|
+
"heaving",
|
|
1904
|
+
"toiling",
|
|
1905
|
+
"straining",
|
|
1906
|
+
"trudging",
|
|
1907
|
+
"laboring",
|
|
1908
|
+
"rolling",
|
|
1909
|
+
"ascending",
|
|
1910
|
+
"dragging",
|
|
1911
|
+
"shouldering",
|
|
1912
|
+
"hoisting",
|
|
1913
|
+
"lugging",
|
|
1914
|
+
"schlepping",
|
|
1915
|
+
"grinding",
|
|
1916
|
+
"lifting",
|
|
1917
|
+
"bracing",
|
|
1918
|
+
"climbing",
|
|
1919
|
+
"leaning in",
|
|
1920
|
+
"digging in",
|
|
1921
|
+
// philosophical
|
|
1922
|
+
"philosophizing",
|
|
1923
|
+
"contemplating",
|
|
1924
|
+
"pondering",
|
|
1925
|
+
"musing",
|
|
1926
|
+
"ruminating",
|
|
1927
|
+
"reflecting",
|
|
1928
|
+
"meditating",
|
|
1929
|
+
"wondering",
|
|
1930
|
+
"questioning",
|
|
1931
|
+
"theorizing",
|
|
1932
|
+
"considering",
|
|
1933
|
+
"deliberating",
|
|
1934
|
+
"introspecting",
|
|
1935
|
+
"cogitating",
|
|
1936
|
+
"brooding",
|
|
1937
|
+
// endurance
|
|
1938
|
+
"persevering",
|
|
1939
|
+
"enduring",
|
|
1940
|
+
"persisting",
|
|
1941
|
+
"sustaining",
|
|
1942
|
+
"weathering",
|
|
1943
|
+
"carrying on",
|
|
1944
|
+
"pressing on",
|
|
1945
|
+
"holding steady",
|
|
1946
|
+
"keeping at it",
|
|
1947
|
+
"not stopping",
|
|
1948
|
+
// light/silly
|
|
1949
|
+
"napping",
|
|
1950
|
+
"procrastinating",
|
|
1951
|
+
"daydreaming",
|
|
1952
|
+
"vibing",
|
|
1953
|
+
"winging it",
|
|
1954
|
+
"hoping",
|
|
1955
|
+
"improvising",
|
|
1956
|
+
"making do",
|
|
1957
|
+
"whistling"
|
|
1958
|
+
];
|
|
1959
|
+
function getBaseForm(level) {
|
|
1960
|
+
if (level <= 2) return "(FACE) {BOULDER}";
|
|
1961
|
+
if (level <= 4) return "(FACE)/ {BOULDER}";
|
|
1962
|
+
if (level <= 7) return "/(FACE)/ {BOULDER}";
|
|
1963
|
+
if (level <= 11) return "\\(FACE)/ {BOULDER}";
|
|
1964
|
+
if (level <= 19) return "\u1566(FACE)\u1564 {BOULDER}";
|
|
1965
|
+
return "\u265B\u1566(FACE)\u1564 {BOULDER}";
|
|
1966
|
+
}
|
|
1967
|
+
var MOOD_FACES = {
|
|
1968
|
+
happy: ["^.^", "^\u203F^", "\u2727\u203F\u2727"],
|
|
1969
|
+
grinding: [">.<", ">_<", "\xF2.\xF3"],
|
|
1970
|
+
frustrated: [">.<#", "\u0CA0_\u0CA0", "\u0CA0\u76CA\u0CA0"],
|
|
1971
|
+
zen: ["\u203E.\u203E", "\u203E\u203F\u203E", "\u02D8\u203F\u02D8"],
|
|
1972
|
+
sleepy: ["-.-)zzZ", "-_-)zzZ", "\u02D8.\u02D8)zzZ"],
|
|
1973
|
+
excited: ["*o*", "*\u25E1*", "\u2726\u25E1\u2726"],
|
|
1974
|
+
existential: ["\u25C9_\u25C9", "\u2299_\u2299", "\u25C9\u2038\u25C9"]
|
|
1975
|
+
};
|
|
1976
|
+
function getMoodFace(mood, intensity = 0) {
|
|
1977
|
+
const faces = MOOD_FACES[mood];
|
|
1978
|
+
if (!faces) throw new Error(`Unknown mood: ${mood}`);
|
|
1979
|
+
const tier = intensity < 30 ? 0 : intensity <= 70 ? 1 : 2;
|
|
1980
|
+
return faces[tier];
|
|
1981
|
+
}
|
|
1982
|
+
function getStatCosmetics(stats) {
|
|
1983
|
+
const cosmetics = [];
|
|
1984
|
+
if (stats.wisdom > 5) cosmetics.push("wisps");
|
|
1985
|
+
if (stats.endurance > 36e6) cosmetics.push("trail");
|
|
1986
|
+
if (stats.patience > 50) cosmetics.push("zen-prefix");
|
|
1987
|
+
return cosmetics;
|
|
1988
|
+
}
|
|
1989
|
+
function getBoulderForm(agentCount, repoNickname) {
|
|
1990
|
+
let boulder;
|
|
1991
|
+
if (agentCount === void 0 || agentCount <= 0) {
|
|
1992
|
+
boulder = "";
|
|
1993
|
+
} else if (agentCount <= 2) {
|
|
1994
|
+
boulder = "o";
|
|
1995
|
+
} else if (agentCount <= 6) {
|
|
1996
|
+
boulder = "O";
|
|
1997
|
+
} else if (agentCount <= 15) {
|
|
1998
|
+
boulder = "\u25C9";
|
|
1999
|
+
} else if (agentCount <= 35) {
|
|
2000
|
+
boulder = "@";
|
|
2001
|
+
} else {
|
|
2002
|
+
boulder = "@@";
|
|
2003
|
+
}
|
|
2004
|
+
if (repoNickname !== void 0) {
|
|
2005
|
+
boulder = `${boulder} "${repoNickname}"`;
|
|
2006
|
+
}
|
|
2007
|
+
return boulder;
|
|
2008
|
+
}
|
|
2009
|
+
function composeLine(body, cosmetics, boulder) {
|
|
2010
|
+
let b = boulder;
|
|
2011
|
+
let hasZenPrefix = false;
|
|
2012
|
+
if (boulder !== "") {
|
|
2013
|
+
for (const c of cosmetics) {
|
|
2014
|
+
switch (c) {
|
|
2015
|
+
case "wisps":
|
|
2016
|
+
b = `~${b}~`;
|
|
2017
|
+
break;
|
|
2018
|
+
case "trail":
|
|
2019
|
+
b = `${b} ...`;
|
|
2020
|
+
break;
|
|
2021
|
+
case "zen-prefix":
|
|
2022
|
+
hasZenPrefix = true;
|
|
2023
|
+
break;
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
} else {
|
|
2027
|
+
if (cosmetics.includes("zen-prefix")) hasZenPrefix = true;
|
|
2028
|
+
}
|
|
2029
|
+
let line = b === "" ? body.replace(" {BOULDER}", "") : body.replace("{BOULDER}", b);
|
|
2030
|
+
if (hasZenPrefix) line = `\u262F ${line}`;
|
|
2031
|
+
return line;
|
|
2032
|
+
}
|
|
2033
|
+
var MOOD_COLORS = {
|
|
2034
|
+
happy: { ansi: 32, tmux: "green" },
|
|
2035
|
+
grinding: { ansi: 33, tmux: "yellow" },
|
|
2036
|
+
frustrated: { ansi: 31, tmux: "red" },
|
|
2037
|
+
zen: { ansi: 36, tmux: "cyan" },
|
|
2038
|
+
sleepy: { ansi: 90, tmux: "colour245" },
|
|
2039
|
+
excited: { ansi: 97, tmux: "white" },
|
|
2040
|
+
existential: { ansi: 35, tmux: "magenta" }
|
|
2041
|
+
};
|
|
2042
|
+
function getMoodAnsiCode(mood) {
|
|
2043
|
+
return MOOD_COLORS[mood].ansi;
|
|
2044
|
+
}
|
|
2045
|
+
function colorize(text, mood, tmux) {
|
|
2046
|
+
const { ansi, tmux: tmuxColor } = MOOD_COLORS[mood];
|
|
2047
|
+
if (tmux) {
|
|
2048
|
+
return `#[fg=${tmuxColor}]${text}#[fg=default]`;
|
|
2049
|
+
}
|
|
2050
|
+
return `\x1B[${ansi}m${text}\x1B[0m`;
|
|
2051
|
+
}
|
|
2052
|
+
function statSummary(stats) {
|
|
2053
|
+
const endH = Math.floor(stats.endurance / 36e5);
|
|
2054
|
+
return `STR:${stats.strength} END:${endH}h WIS:${stats.wisdom} PAT:${stats.patience}`;
|
|
2055
|
+
}
|
|
2056
|
+
function renderCompanion(companion, fields, opts) {
|
|
2057
|
+
const hasFace = fields.includes("face");
|
|
2058
|
+
const hasBoulder = fields.includes("boulder");
|
|
2059
|
+
const repoNickname = opts?.repoPath !== void 0 ? companion.repos[opts.repoPath]?.nickname ?? void 0 : void 0;
|
|
2060
|
+
const boulder = getBoulderForm(opts?.agentCount, repoNickname);
|
|
2061
|
+
const cosmetics = getStatCosmetics(companion.stats);
|
|
2062
|
+
let facePart = null;
|
|
2063
|
+
let boulderOnlyPart = null;
|
|
2064
|
+
if (hasFace) {
|
|
2065
|
+
const baseForm = getBaseForm(companion.level);
|
|
2066
|
+
const intensity = companion.debugMood?.scores[companion.mood] ?? 0;
|
|
2067
|
+
const face = getMoodFace(companion.mood, intensity);
|
|
2068
|
+
const bodyWithFace = baseForm.replace("FACE", face);
|
|
2069
|
+
facePart = composeLine(bodyWithFace, cosmetics, boulder);
|
|
2070
|
+
} else if (hasBoulder) {
|
|
2071
|
+
boulderOnlyPart = boulder;
|
|
2072
|
+
}
|
|
2073
|
+
let commentary = fields.includes("commentary") ? companion.lastCommentary?.text ?? "" : null;
|
|
2074
|
+
const parts = [];
|
|
2075
|
+
for (const field of fields) {
|
|
2076
|
+
switch (field) {
|
|
2077
|
+
case "face":
|
|
2078
|
+
if (facePart !== null) parts.push(facePart);
|
|
2079
|
+
break;
|
|
2080
|
+
case "boulder":
|
|
2081
|
+
if (!hasFace && boulderOnlyPart !== null) parts.push(boulderOnlyPart);
|
|
2082
|
+
break;
|
|
2083
|
+
case "title":
|
|
2084
|
+
parts.push(companion.title);
|
|
2085
|
+
break;
|
|
2086
|
+
case "commentary":
|
|
2087
|
+
if (commentary !== null) parts.push(commentary);
|
|
2088
|
+
break;
|
|
2089
|
+
case "mood":
|
|
2090
|
+
parts.push(`[${companion.mood}]`);
|
|
2091
|
+
break;
|
|
2092
|
+
case "level":
|
|
2093
|
+
parts.push(`Lv ${companion.level}`);
|
|
2094
|
+
break;
|
|
2095
|
+
case "stats":
|
|
2096
|
+
parts.push(statSummary(companion.stats));
|
|
2097
|
+
break;
|
|
2098
|
+
case "achievements":
|
|
2099
|
+
parts.push(`${companion.achievements.length} achievements`);
|
|
2100
|
+
break;
|
|
2101
|
+
case "verb": {
|
|
2102
|
+
const idx = (opts?.verbIndex ?? companion.spinnerVerbIndex) % SPINNER_VERBS.length;
|
|
2103
|
+
parts.push(SPINNER_VERBS[idx]);
|
|
2104
|
+
break;
|
|
2105
|
+
}
|
|
2106
|
+
case "hobby": {
|
|
2107
|
+
const hobbyIdx = ((/* @__PURE__ */ new Date()).getHours() + companion.level) % IDLE_HOBBIES.length;
|
|
2108
|
+
parts.push(IDLE_HOBBIES[hobbyIdx]);
|
|
2109
|
+
break;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
if (opts?.maxWidth !== void 0) {
|
|
2114
|
+
const maxWidth = opts.maxWidth;
|
|
2115
|
+
const joined = parts.join(" ");
|
|
2116
|
+
const joinedWidth = stringWidth3(joined);
|
|
2117
|
+
if (joinedWidth > maxWidth && commentary !== null && commentary.length > 0) {
|
|
2118
|
+
const commentaryIdx = parts.indexOf(commentary);
|
|
2119
|
+
if (commentaryIdx !== -1) {
|
|
2120
|
+
const commentaryWidth = stringWidth3(commentary);
|
|
2121
|
+
const overhead = joinedWidth - commentaryWidth;
|
|
2122
|
+
const available = maxWidth - overhead - 2;
|
|
2123
|
+
if (available < 0) {
|
|
2124
|
+
parts[commentaryIdx] = "";
|
|
2125
|
+
} else {
|
|
2126
|
+
parts[commentaryIdx] = sliceToWidth(commentary, available);
|
|
2127
|
+
}
|
|
2128
|
+
commentary = parts[commentaryIdx];
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
const result2 = parts.filter((p) => p.length > 0).join(" ");
|
|
2132
|
+
const resultWidth = stringWidth3(result2);
|
|
2133
|
+
const final = resultWidth > maxWidth ? sliceToWidth(result2, maxWidth - 1) + "\u2026" : result2;
|
|
2134
|
+
return applyColor(final, fields, facePart, companion.mood, opts);
|
|
2135
|
+
}
|
|
2136
|
+
const result = parts.filter((p) => p.length > 0).join(" ");
|
|
2137
|
+
return applyColor(result, fields, facePart, companion.mood, opts);
|
|
2138
|
+
}
|
|
2139
|
+
function applyColor(result, fields, facePart, mood, opts) {
|
|
2140
|
+
const useColor = opts?.color === true || opts?.tmuxFormat === true;
|
|
2141
|
+
if (!useColor || facePart === null || !fields.includes("face")) return result;
|
|
2142
|
+
const tmux = opts?.tmuxFormat === true;
|
|
2143
|
+
const coloredFace = colorize(facePart, mood, tmux);
|
|
2144
|
+
return result.replace(facePart, coloredFace);
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
// src/daemon/companion.ts
|
|
2148
|
+
init_paths();
|
|
2149
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2150
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2151
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
2152
|
+
|
|
2153
|
+
// src/shared/companion-normalize.ts
|
|
2154
|
+
function emptyStats() {
|
|
2155
|
+
return { count: 0, mean: 0, m2: 0 };
|
|
2156
|
+
}
|
|
2157
|
+
function defaultBaselines() {
|
|
2158
|
+
return {
|
|
2159
|
+
sessionMs: emptyStats(),
|
|
2160
|
+
cycleCount: emptyStats(),
|
|
2161
|
+
agentCount: emptyStats(),
|
|
2162
|
+
sessionsPerDay: emptyStats(),
|
|
2163
|
+
recentAgentThroughput: emptyStats(),
|
|
2164
|
+
lastCountedDay: null,
|
|
2165
|
+
pendingDayCount: 0
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
function normalizeCompanion(state2) {
|
|
2169
|
+
if (state2.stats == null) state2.stats = { strength: 0, endurance: 0, wisdom: 0, patience: 0 };
|
|
2170
|
+
if (state2.level == null) state2.level = 1;
|
|
2171
|
+
if (state2.xp == null) state2.xp = 0;
|
|
2172
|
+
if (state2.title == null) state2.title = "Boulder Intern";
|
|
2173
|
+
if (state2.mood == null) state2.mood = "sleepy";
|
|
2174
|
+
if (state2.achievements == null) state2.achievements = [];
|
|
2175
|
+
if (state2.repos == null) state2.repos = {};
|
|
2176
|
+
if (state2.lastCommentary === void 0) state2.lastCommentary = null;
|
|
2177
|
+
if (state2.sessionsCompleted == null) state2.sessionsCompleted = 0;
|
|
2178
|
+
if (state2.sessionsCrashed == null) state2.sessionsCrashed = 0;
|
|
2179
|
+
if (state2.totalActiveMs == null) state2.totalActiveMs = 0;
|
|
2180
|
+
if (state2.consecutiveCleanSessions == null) state2.consecutiveCleanSessions = 0;
|
|
2181
|
+
if (state2.consecutiveDaysActive == null) state2.consecutiveDaysActive = 0;
|
|
2182
|
+
if (state2.lastActiveDate === void 0) state2.lastActiveDate = null;
|
|
2183
|
+
if (state2.taskHistory == null) state2.taskHistory = {};
|
|
2184
|
+
if (state2.dailyRepos == null) state2.dailyRepos = {};
|
|
2185
|
+
if (state2.recentCompletions == null) state2.recentCompletions = [];
|
|
2186
|
+
if (state2.lifetimeAgentsSpawned == null) state2.lifetimeAgentsSpawned = 0;
|
|
2187
|
+
if (state2.consecutiveEfficientSessions == null) state2.consecutiveEfficientSessions = 0;
|
|
2188
|
+
if (state2.consecutiveHighCycleSessions == null) state2.consecutiveHighCycleSessions = 0;
|
|
2189
|
+
if (state2.spinnerVerbIndex == null) state2.spinnerVerbIndex = 0;
|
|
2190
|
+
if (state2.baselines == null) state2.baselines = defaultBaselines();
|
|
2191
|
+
if (state2.baselines.recentAgentThroughput == null) state2.baselines.recentAgentThroughput = emptyStats();
|
|
2192
|
+
if (state2.commentaryHistory == null) state2.commentaryHistory = [];
|
|
2193
|
+
if (state2.feedbackHistory == null) state2.feedbackHistory = [];
|
|
2194
|
+
return state2;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
// src/shared/companion-types.ts
|
|
2198
|
+
var OBSERVATION_CATEGORIES = ["session-sentiments", "repo-impressions", "user-patterns", "notable-moments"];
|
|
2199
|
+
var ACHIEVEMENTS = [
|
|
2200
|
+
// Milestone (25)
|
|
2201
|
+
{ id: "first-blood", name: "First Blood", category: "milestone", description: "Complete your first session.", badge: null },
|
|
2202
|
+
{ id: "regular", name: "Regular", category: "milestone", description: "Complete 10 sessions.", badge: null },
|
|
2203
|
+
{ id: "centurion", name: "Centurion", category: "milestone", description: "Complete 100 sessions.", badge: null },
|
|
2204
|
+
{ id: "veteran", name: "Veteran", category: "milestone", description: "Complete 500 sessions.", badge: null },
|
|
2205
|
+
{ id: "thousand-boulder", name: "Thousand Boulder", category: "milestone", description: "Complete 1,000 sessions.", badge: null },
|
|
2206
|
+
{ id: "cartographer", name: "Cartographer", category: "milestone", description: "Work in 5 different repos.", badge: "+" },
|
|
2207
|
+
{ id: "world-traveler", name: "World Traveler", category: "milestone", description: "Work in 15 different repos.", badge: null },
|
|
2208
|
+
{ id: "omnipresent", name: "Omnipresent", category: "milestone", description: "Work in 30 different repos.", badge: null },
|
|
2209
|
+
{ id: "swarm-starter", name: "Swarm Starter", category: "milestone", description: "Spawn 50 agents over a lifetime.", badge: null },
|
|
2210
|
+
{ id: "hive-mind", name: "Hive Mind", category: "milestone", description: "Spawn 500 agents over a lifetime.", badge: null },
|
|
2211
|
+
{ id: "legion", name: "Legion", category: "milestone", description: "Spawn 2,000 agents over a lifetime.", badge: null },
|
|
2212
|
+
{ id: "army-of-thousands", name: "Army of Thousands", category: "milestone", description: "Spawn 5,000 agents over a lifetime.", badge: null },
|
|
2213
|
+
{ id: "singularity", name: "Singularity", category: "milestone", description: "Spawn 10,000 agents over a lifetime.", badge: null },
|
|
2214
|
+
{ id: "first-shift", name: "First Shift", category: "milestone", description: "10 hours of total agent active time.", badge: null },
|
|
2215
|
+
{ id: "workaholic", name: "Workaholic", category: "milestone", description: "100 hours of total agent active time.", badge: null },
|
|
2216
|
+
{ id: "time-lord", name: "Time Lord", category: "milestone", description: "500 hours of total agent active time.", badge: null },
|
|
2217
|
+
{ id: "eternal-grind", name: "Eternal Grind", category: "milestone", description: "2,000 hours of total agent active time.", badge: null },
|
|
2218
|
+
{ id: "epoch", name: "Epoch", category: "milestone", description: "5,000 hours of total agent active time.", badge: null },
|
|
2219
|
+
{ id: "old-growth", name: "Old Growth", category: "milestone", description: "Companion is 14 days old.", badge: null },
|
|
2220
|
+
{ id: "seasoned", name: "Seasoned", category: "milestone", description: "Companion is 90 days old.", badge: null },
|
|
2221
|
+
{ id: "ancient", name: "Ancient", category: "milestone", description: "Companion is 365 days old.", badge: null },
|
|
2222
|
+
{ id: "apprentice", name: "Apprentice", category: "milestone", description: "Reach level 5.", badge: null },
|
|
2223
|
+
{ id: "journeyman", name: "Journeyman", category: "milestone", description: "Reach level 15.", badge: null },
|
|
2224
|
+
{ id: "master", name: "Master", category: "milestone", description: "Reach level 30.", badge: null },
|
|
2225
|
+
{ id: "grandmaster", name: "Grandmaster", category: "milestone", description: "Reach level 50.", badge: null },
|
|
2226
|
+
// Session (19)
|
|
2227
|
+
{ id: "marathon", name: "Marathon", category: "session", description: "Complete a session with 15+ agents.", badge: "~^~" },
|
|
2228
|
+
{ id: "squad", name: "Squad Up", category: "session", description: "Complete a session with 10+ agents.", badge: null },
|
|
2229
|
+
{ id: "battalion", name: "Battalion", category: "session", description: "Complete a session with 25+ agents.", badge: null },
|
|
2230
|
+
{ id: "swarm", name: "The Swarm", category: "session", description: "Complete a session with 50+ agents.", badge: null },
|
|
2231
|
+
{ id: "blitz", name: "Blitz", category: "session", description: "Complete a session in under 5 minutes.", badge: null },
|
|
2232
|
+
{ id: "speed-run", name: "Speed Run", category: "session", description: "Complete a session in under 15 minutes.", badge: null },
|
|
2233
|
+
{ id: "flash", name: "Flash", category: "session", description: "Complete a session in under 2 minutes.", badge: null },
|
|
2234
|
+
{ id: "flawless", name: "Flawless", category: "session", description: "Complete a session with 10+ agents and zero crashes.", badge: "*" },
|
|
2235
|
+
{ id: "speed-demon", name: "Speed Demon", category: "session", description: "10 consecutive sessions completing in 3 or fewer cycles.", badge: "\u26A1" },
|
|
2236
|
+
{ id: "iron-will", name: "Iron Will", category: "session", description: "5 consecutive sessions each with 8+ orchestrator cycles.", badge: "[]" },
|
|
2237
|
+
{ id: "glass-cannon", name: "Glass Cannon", category: "session", description: "5+ agents, all crashed, but session completed anyway.", badge: null },
|
|
2238
|
+
{ id: "solo", name: "Solo", category: "session", description: "Complete a session with exactly one agent.", badge: null },
|
|
2239
|
+
{ id: "one-more-cycle", name: "One More Cycle", category: "session", description: "A session with 10+ orchestrator cycles.", badge: null },
|
|
2240
|
+
{ id: "deep-dive", name: "Deep Dive", category: "session", description: "A session with 15+ orchestrator cycles.", badge: null },
|
|
2241
|
+
{ id: "abyss", name: "Into the Abyss", category: "session", description: "A session with 25+ orchestrator cycles.", badge: null },
|
|
2242
|
+
{ id: "eternal-recurrence", name: "Eternal Recurrence", category: "session", description: "A session with 40+ orchestrator cycles.", badge: null },
|
|
2243
|
+
{ id: "endurance", name: "Endurance", category: "session", description: "A single session running 4+ hours.", badge: null },
|
|
2244
|
+
{ id: "ultramarathon", name: "Ultramarathon", category: "session", description: "A single session running 6+ hours.", badge: null },
|
|
2245
|
+
{ id: "one-shot", name: "One Shot", category: "session", description: "Complete with 5+ agents in exactly 1 orchestrator cycle.", badge: null },
|
|
2246
|
+
{ id: "quick-draw", name: "Quick Draw", category: "session", description: "First agent spawned within 20s of session start.", badge: null },
|
|
2247
|
+
// Time (6)
|
|
2248
|
+
{ id: "night-owl", name: "Night Owl", category: "time", description: "Complete a session started between 1am and 5am.", badge: ")" },
|
|
2249
|
+
{ id: "dawn-patrol", name: "Dawn Patrol", category: "time", description: "Session running 3+ hours that spans midnight to 6am.", badge: null },
|
|
2250
|
+
{ id: "early-bird", name: "Early Bird", category: "time", description: "Start a session before 6am.", badge: null },
|
|
2251
|
+
{ id: "weekend-warrior", name: "Weekend Warrior", category: "time", description: "Complete a session on a Saturday or Sunday.", badge: null },
|
|
2252
|
+
{ id: "all-nighter", name: "All-Nighter", category: "time", description: "Single session running 5+ hours.", badge: null },
|
|
2253
|
+
{ id: "witching-hour", name: "Witching Hour", category: "time", description: "Start a session between 3am and 4am.", badge: null },
|
|
2254
|
+
// Behavioral (16)
|
|
2255
|
+
{ id: "sisyphean", name: "Sisyphean", category: "behavioral", description: "Restart the same task 3+ times.", badge: ";" },
|
|
2256
|
+
{ id: "stubborn", name: "Stubborn", category: "behavioral", description: "Restart the same task 5+ times and eventually complete it.", badge: null },
|
|
2257
|
+
{ id: "one-must-imagine", name: "One Must Imagine", category: "behavioral", description: "Restart the same task 10+ times.", badge: null },
|
|
2258
|
+
{ id: "creature-of-habit", name: "Creature of Habit", category: "behavioral", description: "Visit the same repo 10 times.", badge: null },
|
|
2259
|
+
{ id: "loyal", name: "Loyal", category: "behavioral", description: "Visit the same repo 30 times.", badge: null },
|
|
2260
|
+
{ id: "wanderer", name: "Wanderer", category: "behavioral", description: "3+ different repos in a single calendar day.", badge: null },
|
|
2261
|
+
{ id: "streak", name: "Streak", category: "behavioral", description: "7 consecutive days with at least one session.", badge: null },
|
|
2262
|
+
{ id: "iron-streak", name: "Iron Streak", category: "behavioral", description: "14 consecutive days with at least one session.", badge: null },
|
|
2263
|
+
{ id: "hot-streak", name: "Hot Streak", category: "behavioral", description: "15 consecutive clean sessions.", badge: null },
|
|
2264
|
+
{ id: "momentum", name: "Momentum", category: "behavioral", description: "5 sessions completed within 4 hours.", badge: null },
|
|
2265
|
+
{ id: "overdrive", name: "Overdrive", category: "behavioral", description: "Complete 6+ sessions in a single calendar day.", badge: null },
|
|
2266
|
+
{ id: "patient-one", name: "Patient One", category: "behavioral", description: "Idle 30+ minutes between cycles in a session.", badge: null },
|
|
2267
|
+
{ id: "message-in-a-bottle", name: "Message in a Bottle", category: "behavioral", description: "10+ messages sent to a single session.", badge: null },
|
|
2268
|
+
{ id: "deep-conversation", name: "Deep Conversation", category: "behavioral", description: "Send 20+ messages to a single session.", badge: null },
|
|
2269
|
+
{ id: "comeback-kid", name: "Comeback Kid", category: "behavioral", description: "Resume a paused/killed session and complete it.", badge: null },
|
|
2270
|
+
{ id: "pair-programming", name: "Pair Programming", category: "behavioral", description: "8+ user messages during a single active session.", badge: null }
|
|
2271
|
+
];
|
|
2272
|
+
|
|
2273
|
+
// src/daemon/companion-memory.ts
|
|
2274
|
+
init_paths();
|
|
2275
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "fs";
|
|
2276
|
+
import { dirname, join as join4 } from "path";
|
|
2277
|
+
import { randomUUID } from "crypto";
|
|
2278
|
+
import { z } from "zod";
|
|
2279
|
+
|
|
2280
|
+
// src/daemon/haiku.ts
|
|
2281
|
+
import { query, createSdkMcpServer } from "@r-cli/sdk";
|
|
2282
|
+
|
|
2283
|
+
// src/shared/env.ts
|
|
2284
|
+
import { resolve } from "path";
|
|
2285
|
+
function augmentedPath() {
|
|
2286
|
+
const rawPath = process.env["PATH"];
|
|
2287
|
+
const basePath = rawPath !== void 0 && rawPath.length > 0 ? rawPath : "/usr/bin:/bin";
|
|
2288
|
+
const home = process.env["HOME"];
|
|
2289
|
+
const candidates = [
|
|
2290
|
+
...home ? [`${home}/.local/bin`] : [],
|
|
2291
|
+
// Claude CLI, pipx, user-local installs
|
|
2292
|
+
resolve(process.execPath, ".."),
|
|
2293
|
+
// Node.js bin dir (ensures node/npm available)
|
|
2294
|
+
"/opt/homebrew/bin",
|
|
2295
|
+
// Homebrew (Apple Silicon macOS)
|
|
2296
|
+
"/opt/homebrew/sbin",
|
|
2297
|
+
// Homebrew sbin
|
|
2298
|
+
"/usr/local/bin",
|
|
2299
|
+
// Homebrew (Intel macOS), manual installs
|
|
2300
|
+
"/usr/local/sbin",
|
|
2301
|
+
// Manual installs
|
|
2302
|
+
"/opt/local/bin",
|
|
2303
|
+
// MacPorts
|
|
2304
|
+
"/opt/local/sbin",
|
|
2305
|
+
// MacPorts
|
|
2306
|
+
"/home/linuxbrew/.linuxbrew/bin"
|
|
2307
|
+
// Linuxbrew
|
|
2308
|
+
];
|
|
2309
|
+
const nixProfile = process.env["NIX_PROFILES"];
|
|
2310
|
+
if (nixProfile) {
|
|
2311
|
+
for (const p of nixProfile.split(" ").reverse()) {
|
|
2312
|
+
candidates.push(`${p}/bin`);
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
const existing = new Set(basePath.split(":"));
|
|
2316
|
+
const prepend = candidates.filter((dir) => !existing.has(dir));
|
|
2317
|
+
return prepend.length > 0 ? `${prepend.join(":")}:${basePath}` : basePath;
|
|
2318
|
+
}
|
|
2319
|
+
function execEnv() {
|
|
2320
|
+
return {
|
|
2321
|
+
...process.env,
|
|
2322
|
+
PATH: augmentedPath()
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
// src/daemon/haiku.ts
|
|
2327
|
+
var COOLDOWN_MS = 5 * 60 * 1e3;
|
|
2328
|
+
|
|
2329
|
+
// src/daemon/companion-memory.ts
|
|
2330
|
+
var OBSERVATION_TEXT_REJECT_RE = /[<>]/;
|
|
2331
|
+
var CONTROL_CHARS_DETECT_RE = /[\x00-\x1f\x7f]/;
|
|
2332
|
+
function isSafeObservationText(text) {
|
|
2333
|
+
if (OBSERVATION_TEXT_REJECT_RE.test(text)) return false;
|
|
2334
|
+
if (CONTROL_CHARS_DETECT_RE.test(text)) return false;
|
|
2335
|
+
return true;
|
|
2336
|
+
}
|
|
2337
|
+
var writeQueue = Promise.resolve();
|
|
2338
|
+
var OBSERVATION_JSON_SCHEMA = {
|
|
2339
|
+
type: "object",
|
|
2340
|
+
properties: {
|
|
2341
|
+
category: {
|
|
2342
|
+
type: "string",
|
|
2343
|
+
enum: [...OBSERVATION_CATEGORIES],
|
|
2344
|
+
description: "Which of the four observation categories best fits this observation"
|
|
2345
|
+
},
|
|
2346
|
+
text: {
|
|
2347
|
+
type: "string",
|
|
2348
|
+
minLength: 10,
|
|
2349
|
+
maxLength: 180,
|
|
2350
|
+
description: "One sentence, first-person, no angle brackets or control characters"
|
|
2351
|
+
}
|
|
2352
|
+
},
|
|
2353
|
+
required: ["category", "text"],
|
|
2354
|
+
additionalProperties: false
|
|
2355
|
+
};
|
|
2356
|
+
var ObservationZodSchema = z.object({
|
|
2357
|
+
category: z.enum(OBSERVATION_CATEGORIES),
|
|
2358
|
+
text: z.string().min(10).max(180).refine(isSafeObservationText, "contains unsafe characters")
|
|
2359
|
+
});
|
|
2360
|
+
|
|
2361
|
+
// src/daemon/companion.ts
|
|
2362
|
+
function computeLevelProgress(xp) {
|
|
2363
|
+
let threshold = 150;
|
|
2364
|
+
let cumulative = 0;
|
|
2365
|
+
while (cumulative + threshold <= xp) {
|
|
2366
|
+
cumulative += threshold;
|
|
2367
|
+
threshold = Math.floor(threshold * 1.35);
|
|
2368
|
+
}
|
|
2369
|
+
return { xpIntoLevel: xp - cumulative, xpForNextLevel: threshold };
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
// src/shared/companion-badges.ts
|
|
2373
|
+
var BADGE_ART = {
|
|
2374
|
+
// ── Milestone ─────────────────────────────────────────────────────────────
|
|
2375
|
+
"first-blood": [
|
|
2376
|
+
" \u2571\u2572 ",
|
|
2377
|
+
" \u2571 \u2572 ",
|
|
2378
|
+
" \u2571 \u25C6\u25C6 \u2572 ",
|
|
2379
|
+
" \u2571 \u25C6\u25C6 \u2572 ",
|
|
2380
|
+
" \u2571 \u25C6\u25C6 \u2572 ",
|
|
2381
|
+
" \u2571 \u25C6\u25C6 \u2572 ",
|
|
2382
|
+
" \u2571\u2500\u2500\u2500\u2500\u2500\u25C6\u25C6\u2500\u2500\u2500\u2500\u2500\u2572 ",
|
|
2383
|
+
" \u2572 \u25C6\u25C6 \u2571 ",
|
|
2384
|
+
" \u2572 \u25C6\u25C6 \u2571 ",
|
|
2385
|
+
" \u2572\u2500\u2500\u2500\u25C6\u25C6\u2500\u2500\u2500\u2571 ",
|
|
2386
|
+
" \u2502\u2502 ",
|
|
2387
|
+
" \u2550\u2550\u256A\u256A\u2550\u2550 "
|
|
2388
|
+
],
|
|
2389
|
+
"centurion": [
|
|
2390
|
+
" \u250C\u2500\u2500\u2550\u2550\u2550\u2550\u2550\u2500\u2500\u2510 ",
|
|
2391
|
+
" \u2502 \u2554\u2550\u2550\u2550\u2557 \u2502 ",
|
|
2392
|
+
" \u2571\u2502 \u2551100\u2551 \u2502\u2572 ",
|
|
2393
|
+
" \u2571 \u2502 \u255A\u2550\u2550\u2550\u255D \u2502 \u2572 ",
|
|
2394
|
+
" \u2571 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2572 ",
|
|
2395
|
+
" \u2572 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2571 ",
|
|
2396
|
+
" \u2572 \u2502 \u2605 \u2605 \u2605 \u2502 \u2571 ",
|
|
2397
|
+
" \u2572 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2571 ",
|
|
2398
|
+
" \u2572\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2571 "
|
|
2399
|
+
],
|
|
2400
|
+
"thousand-boulder": [
|
|
2401
|
+
" \u256D\u2501\u2501\u2501\u256E ",
|
|
2402
|
+
" \u256D\u2501\u252B1K \u2523\u2501\u256E ",
|
|
2403
|
+
" \u256D\u2501\u252B \u2570\u2501\u2501\u2501\u256F \u2523\u2501\u256E ",
|
|
2404
|
+
" \u2503 \u25C9\u25C9\u25C9\u25C9\u25C9\u25C9 \u2503 ",
|
|
2405
|
+
" \u2503 \u25C9\u25C9\u25C9\u25C9\u25C9\u25C9\u25C9\u25C9 \u2503 ",
|
|
2406
|
+
" \u2503 \u25C9\u25C9\u25C9\u25C9\u25C9\u25C9 \u2503 ",
|
|
2407
|
+
" \u2570\u2501\u252B \u2523\u2501\u256F ",
|
|
2408
|
+
" \u2570\u2501\u252B \u2523\u2501\u256F ",
|
|
2409
|
+
" \u2570\u2501\u2501\u2501\u256F "
|
|
2410
|
+
],
|
|
2411
|
+
"cartographer": [
|
|
2412
|
+
" N ",
|
|
2413
|
+
" \u25B3 ",
|
|
2414
|
+
" \u256D\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u256E ",
|
|
2415
|
+
" \u2502 \xB7 \u2502 \xB7 \u2502 ",
|
|
2416
|
+
" W\u253C\xB7\xB7\xB7\xB7+\xB7\xB7\xB7\xB7\u253CE ",
|
|
2417
|
+
" \u2502 \xB7 \u2502 \xB7 \u2502 ",
|
|
2418
|
+
" \u2570\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u256F ",
|
|
2419
|
+
" \u25BD ",
|
|
2420
|
+
" S "
|
|
2421
|
+
],
|
|
2422
|
+
"world-traveler": [
|
|
2423
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
2424
|
+
" \u256D\u2500\u2500\u2524 \u251C\u2500\u2500\u256E ",
|
|
2425
|
+
" \u2571 \xB7\u2502 \u25E0\u25E1\u25E0 \u2502\xB7 \u2572 ",
|
|
2426
|
+
" \u2502 \xB7 \u2502\u25E0 \u25E1\u2502 \xB7 \u2502 ",
|
|
2427
|
+
" \u2502 \xB7 \u2502 \u25E1\u25E0\u25E1 \u2502 \xB7 \u2502 ",
|
|
2428
|
+
" \u2572 \xB7\u2502 \u2502\xB7 \u2571 ",
|
|
2429
|
+
" \u2570\u2500\u2500\u2524 \u251C\u2500\u2500\u256F ",
|
|
2430
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u256F "
|
|
2431
|
+
],
|
|
2432
|
+
"hive-mind": [
|
|
2433
|
+
" \u2571\u2572 \u2571\u2572 \u2571\u2572 ",
|
|
2434
|
+
" \u2571\u25C6\u25C6\u2572\u2571\u25C6\u25C6\u2572\u2571\u25C6\u25C6\u2572 ",
|
|
2435
|
+
" \u2572\u25C6\u25C6\u2571\u2572\u25C6\u25C6\u2571\u2572\u25C6\u25C6\u2571 ",
|
|
2436
|
+
" \u2571\u2572\u2571\u2571\u25C6\u2572\u2571\u2571\u25C6\u2572\u2572\u2571\u2572 ",
|
|
2437
|
+
" \u2571\u25C6\u25C6\u2572\u2572\u25C6\u25C6\u2572\u2572\u25C6\u25C6\u2571\u25C6\u25C6\u2572 ",
|
|
2438
|
+
" \u2572\u25C6\u25C6\u2571\u2571\u25C6\u25C6\u2571\u2571\u25C6\u25C6\u2572\u25C6\u25C6\u2571 ",
|
|
2439
|
+
" \u2572\u2571\u2572\u2572\u25C6\u2571\u2572\u2572\u25C6\u2571\u2571\u2572\u2571 ",
|
|
2440
|
+
" \u2572\u25C6\u25C6\u2571\u2572\u25C6\u25C6\u2571\u2572\u25C6\u25C6\u2571 ",
|
|
2441
|
+
" \u2572\u2571 \u2572\u2571 \u2572\u2571 "
|
|
2442
|
+
],
|
|
2443
|
+
"old-growth": [
|
|
2444
|
+
" \u2571\u2572 ",
|
|
2445
|
+
" \u2571\u2571\u2572\u2572 ",
|
|
2446
|
+
" \u2571\u2571 \u2572\u2572 ",
|
|
2447
|
+
" \u2571\u2571\u2571\u2572\u2571\u2572\u2572\u2572 ",
|
|
2448
|
+
" \u2571\u2571\u2571 \u2572\u2572\u2572 ",
|
|
2449
|
+
" \u2571\u2571\u2571\u2571\u2572\u2571\u2572\u2571\u2572\u2572\u2572\u2572 ",
|
|
2450
|
+
" \u2551\u2551\u2551 ",
|
|
2451
|
+
" \u2551\u2551\u2551 ",
|
|
2452
|
+
" \u2550\u2550\u2550\u2569\u2569\u2569\u2550\u2550\u2550 "
|
|
2453
|
+
],
|
|
2454
|
+
"ancient": [
|
|
2455
|
+
" \u250C\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2510 ",
|
|
2456
|
+
" \u2502 \u2502 \u25C9 \u25C9 \u2502 \u2502 ",
|
|
2457
|
+
" \u2502 \u2502 \u25BD \u2502 \u2502 ",
|
|
2458
|
+
" \u2554\u2550\u2567\u2550\u2567\u2550\u2550\u2550\u2550\u2550\u2567\u2550\u2567\u2550\u2557 ",
|
|
2459
|
+
" \u2551 A N C I E N \u2551 ",
|
|
2460
|
+
" \u2551 T \u2551 ",
|
|
2461
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D ",
|
|
2462
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2463
|
+
" \u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594 "
|
|
2464
|
+
],
|
|
2465
|
+
"regular": [
|
|
2466
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
2467
|
+
" \u256D\u2500\u2524 10 \u251C\u2500\u256E ",
|
|
2468
|
+
" \u2571 \u2570\u2500\u2500\u2500\u2500\u2500\u256F \u2572 ",
|
|
2469
|
+
" \u2502 \u256D\u2500\u2500\u2500\u2500\u2500\u256E \u2502 ",
|
|
2470
|
+
" \u2502 \u2502 \u25C9 \u2502 \u2502 ",
|
|
2471
|
+
" \u2502 \u2570\u2500\u2500\u2500\u2500\u2500\u256F \u2502 ",
|
|
2472
|
+
" \u2572 \u2571 ",
|
|
2473
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F "
|
|
2474
|
+
],
|
|
2475
|
+
"veteran": [
|
|
2476
|
+
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 ",
|
|
2477
|
+
" \u2551 \u2554\u2550\u2550\u2550\u2550\u2550\u2557 \u2551 ",
|
|
2478
|
+
" \u2551 \u2551 V \u2551 \u2551 ",
|
|
2479
|
+
" \u2551 \u2551 500 \u2551 \u2551 ",
|
|
2480
|
+
" \u2551 \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u2551 ",
|
|
2481
|
+
" \u2551 \u2605 \u2605 \u2605 \u2605 \u2605 \u2551 ",
|
|
2482
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D ",
|
|
2483
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2484
|
+
" \u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594 "
|
|
2485
|
+
],
|
|
2486
|
+
"swarm-starter": [
|
|
2487
|
+
" ",
|
|
2488
|
+
" \u25C6 \u25C6 \u25C6 \u25C6 \u25C6 ",
|
|
2489
|
+
" \u25C6 \u25C6 \u25C6 \u25C6 \u25C6 ",
|
|
2490
|
+
" \u25C6 \u25C6 \u25C6 \u25C6 \u25C6 ",
|
|
2491
|
+
" \u25C6 \u25C6 \u25C6 \u25C6 \u25C6 ",
|
|
2492
|
+
" \u25C6 \u25C6 \u25C6 \u25C6 \u25C6 ",
|
|
2493
|
+
" ",
|
|
2494
|
+
" \xB7 50 out \xB7 "
|
|
2495
|
+
],
|
|
2496
|
+
"legion": [
|
|
2497
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2498
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2499
|
+
" \u25C6\u25C6\u25C6 2K \u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2500
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2501
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2502
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2503
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 "
|
|
2504
|
+
],
|
|
2505
|
+
"army-of-thousands": [
|
|
2506
|
+
" \xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7 ",
|
|
2507
|
+
" \xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6 ",
|
|
2508
|
+
" \xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7 ",
|
|
2509
|
+
" \xB7\u25C6\xB7\u25C6\xB75K\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7 ",
|
|
2510
|
+
" \xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7 ",
|
|
2511
|
+
" \xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6 ",
|
|
2512
|
+
" \xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7 ",
|
|
2513
|
+
" \xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6 ",
|
|
2514
|
+
" \xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7 "
|
|
2515
|
+
],
|
|
2516
|
+
"singularity": [
|
|
2517
|
+
" \u2572 \u2502 \u2571 \u2500 \xB7 ",
|
|
2518
|
+
" \u2572 \u2502 \u2571 ",
|
|
2519
|
+
" \u2572\u2502\u2571 ",
|
|
2520
|
+
" \u2500\u2500\u2500\u2500\u25C6\u2500\u2500\u2500\u2500 ",
|
|
2521
|
+
" \u2571\u2502\u2572 ",
|
|
2522
|
+
" \u2571 \u2502 \u2572 ",
|
|
2523
|
+
" \u2571 \u2502 \u2572 \u2500 \xB7 ",
|
|
2524
|
+
" 10000 agents "
|
|
2525
|
+
],
|
|
2526
|
+
"first-shift": [
|
|
2527
|
+
" \u250C\u2500\u2500\u2500\u2500\u2500\u2510 ",
|
|
2528
|
+
" \u2502 \u2572 \u2502 ",
|
|
2529
|
+
" \u2571\u2502 \u2572 \u2502\u2572 ",
|
|
2530
|
+
" \u2571 \u2502 \u2572 \u2502 \u2572 ",
|
|
2531
|
+
" \u2572 \u2502 \u2572\u2502 \u2571 ",
|
|
2532
|
+
" \u2572\u2502 \u2502\u2571 ",
|
|
2533
|
+
" \u2502 \u2571 \u2502 ",
|
|
2534
|
+
" \u2514\u2500\u2500\u2500\u2500\u2500\u2518 ",
|
|
2535
|
+
" 10 hrs "
|
|
2536
|
+
],
|
|
2537
|
+
"workaholic": [
|
|
2538
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
2539
|
+
" \u2571 12 \u2572 ",
|
|
2540
|
+
" \u2502 \xB7 \u2502 \u2502 ",
|
|
2541
|
+
" \u25029 \xB7 \u2502 3 \u2502 ",
|
|
2542
|
+
" \u2502 \u2572 \u2502 ",
|
|
2543
|
+
" \u2572 6 \xB7 \u2571 ",
|
|
2544
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F ",
|
|
2545
|
+
" 100 hrs "
|
|
2546
|
+
],
|
|
2547
|
+
"time-lord": [
|
|
2548
|
+
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 ",
|
|
2549
|
+
" \u2571 \u2572 ",
|
|
2550
|
+
" \u2502 \xB7 11 12 1 \xB7 \u2502 ",
|
|
2551
|
+
" \u2502 10 \u2572 2 \u2502 ",
|
|
2552
|
+
" \u2502 9 \xB7 3 \u2502 ",
|
|
2553
|
+
" \u2502 8 4 \u2502 ",
|
|
2554
|
+
" \u2572 7 5 \u2571 ",
|
|
2555
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D ",
|
|
2556
|
+
" 500 hrs "
|
|
2557
|
+
],
|
|
2558
|
+
"eternal-grind": [
|
|
2559
|
+
" \u256D\u2500\u2500\u2500\u256E \u256D\u2500\u2500\u2500\u256E ",
|
|
2560
|
+
" \u2571 \u2572 \u2571 \u2572 ",
|
|
2561
|
+
" \u2502 \u221E \u2573 \u221E \u2502 ",
|
|
2562
|
+
" \u2572 \u2571 \u2572 \u2571 ",
|
|
2563
|
+
" \u2570\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u256F ",
|
|
2564
|
+
" \u250C\u2500\u2500\u2500\u2500\u2500\u2510 ",
|
|
2565
|
+
" \u2502 \u2572 \u2571 \u2502 ",
|
|
2566
|
+
" \u2502 \xD7 \u2502 ",
|
|
2567
|
+
" \u2514\u2500\u2500\u2500\u2500\u2500\u2518 "
|
|
2568
|
+
],
|
|
2569
|
+
"epoch": [
|
|
2570
|
+
" \xB7 \u2605 \xB7 ",
|
|
2571
|
+
" \xB7 \u2571\u2502\u2572 \xB7 ",
|
|
2572
|
+
" \u2572 \u2571 \u2502 \u2572 \u2571 ",
|
|
2573
|
+
" \u2572\u2571 \u2502 \u2572\u2571 ",
|
|
2574
|
+
" \u2500\u2500\u2500\u2500\u25C6\u2500\u2500\u253C\u2500\u2500\u25C6\u2500\u2500\u2500\u2500 ",
|
|
2575
|
+
" \u2571\u2572 \u2502 \u2571\u2572 ",
|
|
2576
|
+
" \u2571 \u2572 \u2502 \u2571 \u2572 ",
|
|
2577
|
+
" \xB7 \u2572\u2502\u2571 \xB7 ",
|
|
2578
|
+
" 5000 hrs "
|
|
2579
|
+
],
|
|
2580
|
+
"seasoned": [
|
|
2581
|
+
" \u2571\u2572 ",
|
|
2582
|
+
" \u2571 \u2572 ",
|
|
2583
|
+
" \u2571\u2571\u2572\u2571\u2572\u2572 ",
|
|
2584
|
+
" \u2571\u2571 \u2572\u2572 ",
|
|
2585
|
+
" \u2571\u2571\u2571\u2571\u2572\u2571\u2572\u2572\u2572\u2572 ",
|
|
2586
|
+
" \u2551\u2551 ",
|
|
2587
|
+
" \u2500\u2500\u2500\u2500\u2500\u2568\u2568\u2500\u2500\u2500\u2500\u2500 ",
|
|
2588
|
+
" \u2572\u2572\u2572\u2572\u2572\u2572\u2572\u2572\u2572\u2572\u2572\u2572\u2572 ",
|
|
2589
|
+
" 90 day roots "
|
|
2590
|
+
],
|
|
2591
|
+
"omnipresent": [
|
|
2592
|
+
" N ",
|
|
2593
|
+
" \xB7 \u25B3 \xB7 ",
|
|
2594
|
+
" NW \u256D\u2500\u253C\u2500\u256E NE ",
|
|
2595
|
+
" \xB7 \u256D\u2500\u2524\xB7+\xB7\u251C\u2500\u256E \xB7 ",
|
|
2596
|
+
" W\u2500\u2500\u2524\xB7\u2502 \xB7 \u2502\xB7\u251C\u2500\u2500E ",
|
|
2597
|
+
" \xB7 \u2570\u2500\u2524\xB7+\xB7\u251C\u2500\u256F \xB7 ",
|
|
2598
|
+
" SW \u2570\u2500\u253C\u2500\u256F SE ",
|
|
2599
|
+
" \xB7 \u25BD \xB7 ",
|
|
2600
|
+
" S "
|
|
2601
|
+
],
|
|
2602
|
+
"apprentice": [
|
|
2603
|
+
" ",
|
|
2604
|
+
" \u2571\u2572 ",
|
|
2605
|
+
" \u2571 \u2572 ",
|
|
2606
|
+
" \u2571 \u2572 ",
|
|
2607
|
+
" \u2571 \u2572 ",
|
|
2608
|
+
" \u2571\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2572 ",
|
|
2609
|
+
" \u2571 level 5 \u2572 ",
|
|
2610
|
+
" \u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594 "
|
|
2611
|
+
],
|
|
2612
|
+
"journeyman": [
|
|
2613
|
+
" \u2571\u2572 ",
|
|
2614
|
+
" \u2571 \u2572 \u2571\u2572 ",
|
|
2615
|
+
" \u2571 \u2572 \u2571 \u2572 ",
|
|
2616
|
+
" \u2571 \u2573 \u2572 ",
|
|
2617
|
+
" \u2571 \u2571 \u2572 \u2572 ",
|
|
2618
|
+
" \u2571\u2500\u2500\u2500\u2500\u2500\u2500\u2571\u2500\u2500\u2500\u2572\u2500\u2500\u2500\u2500\u2572",
|
|
2619
|
+
" \u2571 level 15 ",
|
|
2620
|
+
" \u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594 "
|
|
2621
|
+
],
|
|
2622
|
+
"master": [
|
|
2623
|
+
" \u2605\u2572\u2571\u2605 ",
|
|
2624
|
+
" \u2571\u2572 ",
|
|
2625
|
+
" \u2571 \u2572 ",
|
|
2626
|
+
" \u2571\u2571\u2572\u2571\u2572\u2572 ",
|
|
2627
|
+
" \u2571\u2571 \u2572\u2572 ",
|
|
2628
|
+
" \u2571\u2571 \u2572\u2572 ",
|
|
2629
|
+
" \u2571\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2572\u2572 ",
|
|
2630
|
+
" \u2571 level 30 \u2572 ",
|
|
2631
|
+
" \u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594 "
|
|
2632
|
+
],
|
|
2633
|
+
"grandmaster": [
|
|
2634
|
+
" \u2605 \u2605 \u2605 ",
|
|
2635
|
+
" \u2572\u2502\u2571 ",
|
|
2636
|
+
" \u2571\u2572 ",
|
|
2637
|
+
" \u2571 \u2572 ",
|
|
2638
|
+
" \u2571\u2571\u2572\u2571\u2572\u2572 ",
|
|
2639
|
+
" \u2571\u2571 \u2572\u2572 ",
|
|
2640
|
+
" \u2571\u2571 \u2605 \u2572\u2572 ",
|
|
2641
|
+
" \u2571\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2572\u2572 ",
|
|
2642
|
+
" \u2571 level 50 \u2572 "
|
|
2643
|
+
],
|
|
2644
|
+
// ── Session ───────────────────────────────────────────────────────────────
|
|
2645
|
+
"marathon": [
|
|
2646
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
2647
|
+
" \u2502 \u2571\u2572 \u2571\u2572 \u2571\u2572 \u2571\u2572 \u2502 ",
|
|
2648
|
+
" \u2502\u2571 \u2573 \u2573 \u2573 \u2572 \u2502 ",
|
|
2649
|
+
" \u2502 \u2571\u2572 \u2571\u2572 \u2571\u2572 \u2502 ",
|
|
2650
|
+
" \u2502 \u2571 \u2573 \u2573 \u2572 \u2502 ",
|
|
2651
|
+
" \u2502 \u2571 \u2571 \u2572\u2571 \u2572 \u2572 \u2502 ",
|
|
2652
|
+
" \u2502\u2571 \u2571 \u2572 \u2572\u2502 ",
|
|
2653
|
+
" \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 ",
|
|
2654
|
+
" \u2502 ~ ^ ~ \u2502 ",
|
|
2655
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F "
|
|
2656
|
+
],
|
|
2657
|
+
"blitz": [
|
|
2658
|
+
" \u2571\u2571 ",
|
|
2659
|
+
" \u2571\u2571 ",
|
|
2660
|
+
" \u2571\u2571 ",
|
|
2661
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2662
|
+
" \u2571\u2571 ",
|
|
2663
|
+
" \u2571\u2571 ",
|
|
2664
|
+
" \u2571\u2571 ",
|
|
2665
|
+
" \u2571\u2571 "
|
|
2666
|
+
],
|
|
2667
|
+
"speed-run": [
|
|
2668
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
2669
|
+
" \u2571 \u2572 ",
|
|
2670
|
+
" \u2502 10 \u2571\u2571 \u2502 ",
|
|
2671
|
+
" \u2502 \xB7 \u2571\u2571 \u2502 ",
|
|
2672
|
+
" \u2502 \u2571 \u2571\u2571 \u2502 ",
|
|
2673
|
+
" \u2502 \u2571 \u2571\u2571 \u2502 ",
|
|
2674
|
+
" \u2572 \u2571\u2571 \u2571 ",
|
|
2675
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F "
|
|
2676
|
+
],
|
|
2677
|
+
"flawless": [
|
|
2678
|
+
" \u2726 \u2726 ",
|
|
2679
|
+
" \u2726 \u2571\u2572 \u2726 ",
|
|
2680
|
+
" \u2554\u2550\u2550\u2567\u2550\u2550\u2550\u2557 ",
|
|
2681
|
+
" \u2726 \u2551 \u2551 \u2726 ",
|
|
2682
|
+
" \u2551 \u25C6 \u2551 ",
|
|
2683
|
+
" \u2551 \u2551 ",
|
|
2684
|
+
" \u2726 \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u2726 ",
|
|
2685
|
+
" \u2726 \u2726 "
|
|
2686
|
+
],
|
|
2687
|
+
"speed-demon": [
|
|
2688
|
+
" ",
|
|
2689
|
+
" \u2571\u2571 ",
|
|
2690
|
+
" \u2571\u2571 ",
|
|
2691
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2692
|
+
" \u2571\u2571 ",
|
|
2693
|
+
" \u2571\u2571 ",
|
|
2694
|
+
" \u26A1 \u22643 \u26A1 ",
|
|
2695
|
+
" x10 streak "
|
|
2696
|
+
],
|
|
2697
|
+
"iron-will": [
|
|
2698
|
+
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 ",
|
|
2699
|
+
" \u2551 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2551 ",
|
|
2700
|
+
" \u2551 \u2502\u2554\u2550\u2550\u2550\u2550\u2550\u2557\u2502 \u2551 ",
|
|
2701
|
+
" \u2551 \u2502\u2551 8+ \u2551\u2502 \u2551 ",
|
|
2702
|
+
" \u2551 \u2502\u2551cycle\u2551\u2502 \u2551 ",
|
|
2703
|
+
" \u2551 \u2502\u255A\u2550\u2550\u2550\u2550\u2550\u255D\u2502 \u2551 ",
|
|
2704
|
+
" \u2551 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2551 ",
|
|
2705
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D "
|
|
2706
|
+
],
|
|
2707
|
+
"glass-cannon": [
|
|
2708
|
+
" \u2571\u2572 ",
|
|
2709
|
+
" \u2571\u2571\u2572\u2572 ",
|
|
2710
|
+
" \u2571\u2571 \u2572\u2572 ",
|
|
2711
|
+
" \u2571\u2571 \u2573\u2573 \u2572\u2572 ",
|
|
2712
|
+
" \u2571\u2571 \u2573\u2573 \u2572\u2572 ",
|
|
2713
|
+
" \u2572\u2572 \u2573\u2573 \u2571\u2571 ",
|
|
2714
|
+
" \u2572\u2572 \u2571\u2571 ",
|
|
2715
|
+
" \u2572\u2572 \u2571\u2571 ",
|
|
2716
|
+
" \u2572\u2572\u2571\u2571 ",
|
|
2717
|
+
" \u2550\u2550\u2550\u2567\u2567\u2550\u2550\u2550 "
|
|
2718
|
+
],
|
|
2719
|
+
"solo": [
|
|
2720
|
+
" ",
|
|
2721
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
2722
|
+
" \u2502 \u2502 ",
|
|
2723
|
+
" \u2502 \u25C6 \u2502 ",
|
|
2724
|
+
" \u2502 \u2502 ",
|
|
2725
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F ",
|
|
2726
|
+
" "
|
|
2727
|
+
],
|
|
2728
|
+
"one-more-cycle": [
|
|
2729
|
+
" \u256D\u2500\u2500\u2192\u2500\u2500\u256E ",
|
|
2730
|
+
" \u2502 \u2502 ",
|
|
2731
|
+
" \u2191 \u221E \u2193 ",
|
|
2732
|
+
" \u2502 \u2502 ",
|
|
2733
|
+
" \u2570\u2500\u2500\u2190\u2500\u2500\u256F ",
|
|
2734
|
+
" ",
|
|
2735
|
+
" \u256D\u2500\u2500\u2192\u2500\u2500\u256E ",
|
|
2736
|
+
" \u2502 \u2502 ",
|
|
2737
|
+
" \u2191 \u221E \u2193 ",
|
|
2738
|
+
" \u2502 \u2502 ",
|
|
2739
|
+
" \u2570\u2500\u2500\u2190\u2500\u2500\u256F "
|
|
2740
|
+
],
|
|
2741
|
+
"quick-draw": [
|
|
2742
|
+
" \u2571\u2502 ",
|
|
2743
|
+
" \u2571 \u2502 ",
|
|
2744
|
+
" \u2500\u2500\u2571\u2500\u2500\u2502\u2500\u2500 ",
|
|
2745
|
+
" \u2571 \u2502 ",
|
|
2746
|
+
" \u2571 \u256D\u2500\u256F ",
|
|
2747
|
+
" \u2571 \u2502 ",
|
|
2748
|
+
" \u2571 \u256D\u2500\u256F ",
|
|
2749
|
+
" \u2502 ",
|
|
2750
|
+
" \u2500\u2500\u2568\u2500\u2500 "
|
|
2751
|
+
],
|
|
2752
|
+
"squad": [
|
|
2753
|
+
" ",
|
|
2754
|
+
" \u25C6 \u25C6 \u25C6 \u25C6 ",
|
|
2755
|
+
" ",
|
|
2756
|
+
" \u25C6 \u25C6 \u25C6 \u25C6 ",
|
|
2757
|
+
" ",
|
|
2758
|
+
" \u25C6 \u25C6 ",
|
|
2759
|
+
" ",
|
|
2760
|
+
" \xB7 10 strong \xB7 "
|
|
2761
|
+
],
|
|
2762
|
+
"battalion": [
|
|
2763
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2764
|
+
" ",
|
|
2765
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2766
|
+
" ",
|
|
2767
|
+
" \u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6\u25C6 ",
|
|
2768
|
+
" ",
|
|
2769
|
+
" \xB7 25 strong \xB7 "
|
|
2770
|
+
],
|
|
2771
|
+
"swarm": [
|
|
2772
|
+
" \u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7 ",
|
|
2773
|
+
" \xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6 ",
|
|
2774
|
+
" \u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7 ",
|
|
2775
|
+
" \xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6 ",
|
|
2776
|
+
" \u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7 ",
|
|
2777
|
+
" \xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6\xB7\u25C6 ",
|
|
2778
|
+
" \xB7 50 strong \xB7 "
|
|
2779
|
+
],
|
|
2780
|
+
"deep-dive": [
|
|
2781
|
+
" \u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248 ",
|
|
2782
|
+
" \u2193 ",
|
|
2783
|
+
" \u2571\u2502\u2572 ",
|
|
2784
|
+
" \u2502 ",
|
|
2785
|
+
" \u2502 ",
|
|
2786
|
+
" \u25BC ",
|
|
2787
|
+
" \xB7 \xB7 \xB7 \xB7 \xB7 \xB7 \xB7 ",
|
|
2788
|
+
" 15 deep "
|
|
2789
|
+
],
|
|
2790
|
+
"abyss": [
|
|
2791
|
+
" \u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248 ",
|
|
2792
|
+
" \u2502 ",
|
|
2793
|
+
" \u2502 ",
|
|
2794
|
+
" \u2502 ",
|
|
2795
|
+
" \u25BC ",
|
|
2796
|
+
" \u2502 ",
|
|
2797
|
+
" \u2502 ",
|
|
2798
|
+
" \u25BC ",
|
|
2799
|
+
" 25 deep "
|
|
2800
|
+
],
|
|
2801
|
+
"eternal-recurrence": [
|
|
2802
|
+
" \u256D\u2500\u2500\u2192\u2500\u2500\u256E ",
|
|
2803
|
+
" \u2571 \u221E \u2572 ",
|
|
2804
|
+
" \u2502 \u256D\u2500\u2500\u2500\u256E \u2502 ",
|
|
2805
|
+
" \u2502 \u2502 \u221E \u2502 \u2502 ",
|
|
2806
|
+
" \u2502 \u2570\u2500\u2500\u2500\u256F \u2502 ",
|
|
2807
|
+
" \u2572 \u221E \u2571 ",
|
|
2808
|
+
" \u2570\u2500\u2500\u2190\u2500\u2500\u256F ",
|
|
2809
|
+
" 40 cycles "
|
|
2810
|
+
],
|
|
2811
|
+
"endurance": [
|
|
2812
|
+
" ",
|
|
2813
|
+
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 ",
|
|
2814
|
+
" \u2551\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2551 ",
|
|
2815
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D ",
|
|
2816
|
+
" ",
|
|
2817
|
+
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 ",
|
|
2818
|
+
" \u2551\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593 \u2551 ",
|
|
2819
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D ",
|
|
2820
|
+
" 4 hours "
|
|
2821
|
+
],
|
|
2822
|
+
"ultramarathon": [
|
|
2823
|
+
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 ",
|
|
2824
|
+
" \u2551\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2551 ",
|
|
2825
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D ",
|
|
2826
|
+
" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2192 ",
|
|
2827
|
+
" \xB7 ",
|
|
2828
|
+
" \xB7 ",
|
|
2829
|
+
" \xB7 ",
|
|
2830
|
+
" \xB7 ",
|
|
2831
|
+
" 6 hours "
|
|
2832
|
+
],
|
|
2833
|
+
"one-shot": [
|
|
2834
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
2835
|
+
" \u2502 \u256D\u2500\u2500\u2500\u256E \u2502 ",
|
|
2836
|
+
" \u2502 \u2502 \u25C9 \u2502 \u2502 ",
|
|
2837
|
+
" \u2502 \u2570\u2500\u2500\u2500\u256F \u2502 ",
|
|
2838
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F ",
|
|
2839
|
+
" \u2191 ",
|
|
2840
|
+
" \u2571\u2502 ",
|
|
2841
|
+
" \u2571 \u2502 ",
|
|
2842
|
+
" \u2192 \u25C9 \u2502 "
|
|
2843
|
+
],
|
|
2844
|
+
"flash": [
|
|
2845
|
+
" \u2571\u2571 ",
|
|
2846
|
+
" \u2571\u2571 ",
|
|
2847
|
+
" \u2571\u2571 ",
|
|
2848
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2849
|
+
" \u2571\u2571 ",
|
|
2850
|
+
" \u2571\u2571 ",
|
|
2851
|
+
" \u2571\u2571 ",
|
|
2852
|
+
" \u2571\u2571 ",
|
|
2853
|
+
" < 2 min "
|
|
2854
|
+
],
|
|
2855
|
+
// ── Time ──────────────────────────────────────────────────────────────────
|
|
2856
|
+
"night-owl": [
|
|
2857
|
+
" \u263D ",
|
|
2858
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u256E \xB7 ",
|
|
2859
|
+
" \u2571 \u25C9 \u25C9 \u2572 \xB7 ",
|
|
2860
|
+
" \u2502 \u25BD \u2502 \xB7 ",
|
|
2861
|
+
" \u2502 \u2571\u2500\u2500\u2500\u2572 \u2502 ",
|
|
2862
|
+
" \u2572\u2571 \u2572\u2571 ",
|
|
2863
|
+
" \u2571\u2572 \u2571\u2572 \xB7 ",
|
|
2864
|
+
" \u2571 \u2572\u2500\u2500\u2500\u2571 \u2572 \xB7 ",
|
|
2865
|
+
" \u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594 "
|
|
2866
|
+
],
|
|
2867
|
+
"dawn-patrol": [
|
|
2868
|
+
" ",
|
|
2869
|
+
" \u2500 \u2500 \u2500 \u2500 \u2500 \u2500 \u2500 \u2500 ",
|
|
2870
|
+
" \u2572 \u2502 \u2571 ",
|
|
2871
|
+
" \u2572 \u2502 \u2571 ",
|
|
2872
|
+
" \u2500\u2500\u2500\u2500\u25D1\u2500\u2500\u2500\u2500 ",
|
|
2873
|
+
" \u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593 ",
|
|
2874
|
+
" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 ",
|
|
2875
|
+
" "
|
|
2876
|
+
],
|
|
2877
|
+
"early-bird": [
|
|
2878
|
+
" \u2571\u2571 ",
|
|
2879
|
+
" \u25E0 \u2571\u2571 ",
|
|
2880
|
+
" \u2571 \u2572 \u2571\u2571 ",
|
|
2881
|
+
" \u2502 \u25C9 \u2572>\u2571 ",
|
|
2882
|
+
" \u2502 \u2550\u2571 ",
|
|
2883
|
+
" \u2572 \u2571 ",
|
|
2884
|
+
" \u2572\u2571\u2572 ",
|
|
2885
|
+
" \u2572 \u2572 ",
|
|
2886
|
+
" \u2594\u2594 "
|
|
2887
|
+
],
|
|
2888
|
+
"weekend-warrior": [
|
|
2889
|
+
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557 ",
|
|
2890
|
+
" \u2551 S M T W T \u2551 ",
|
|
2891
|
+
" \u2551 \u2551 ",
|
|
2892
|
+
" \u2551 \u25C6 \u2551 ",
|
|
2893
|
+
" \u2551 \u25C6 \u2551 ",
|
|
2894
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D "
|
|
2895
|
+
],
|
|
2896
|
+
"all-nighter": [
|
|
2897
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
2898
|
+
" \u2571 12 \u2572 ",
|
|
2899
|
+
" \u2502 \xB7 \u2502 \u2502 ",
|
|
2900
|
+
" \u25029 \u2502 3 \u2502 ",
|
|
2901
|
+
" \u2502 \xB7 \u2502 ",
|
|
2902
|
+
" \u2572 6 \u2571 ",
|
|
2903
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F ",
|
|
2904
|
+
" \u221E \u221E \u221E "
|
|
2905
|
+
],
|
|
2906
|
+
"witching-hour": [
|
|
2907
|
+
" \xB7 \xB7 \u2726 \xB7 \xB7 ",
|
|
2908
|
+
" \xB7 \u2571\u2572 \xB7 ",
|
|
2909
|
+
" \u2571 \u2572 ",
|
|
2910
|
+
" \u2502 3:00 \u2502 ",
|
|
2911
|
+
" \u2502 AM \u2502 ",
|
|
2912
|
+
" \u2572 \u2571 ",
|
|
2913
|
+
" \xB7 \u2572\u2571 \xB7 ",
|
|
2914
|
+
" \xB7 \xB7 \u2726 \xB7 \xB7 "
|
|
2915
|
+
],
|
|
2916
|
+
// ── Behavioral ────────────────────────────────────────────────────────────
|
|
2917
|
+
"sisyphean": [
|
|
2918
|
+
" \u2571 ",
|
|
2919
|
+
" \u2571 \u25C9 ",
|
|
2920
|
+
" \u2571 \u25C9\u25C9\u25C9 ",
|
|
2921
|
+
" \u2571 \u25C9\u25C9\u25C9 ",
|
|
2922
|
+
" \u2571 \u25C9 ",
|
|
2923
|
+
" \u2571 ; ",
|
|
2924
|
+
" \u2571 (>.<) ",
|
|
2925
|
+
" \u2571 \u2571\u2571 \u2572\u2572 ",
|
|
2926
|
+
" \u2571 \u2571 \u2572 "
|
|
2927
|
+
],
|
|
2928
|
+
"stubborn": [
|
|
2929
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2930
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2931
|
+
" \u25C9 ",
|
|
2932
|
+
" \u25C9\u25C9\u25C9 ",
|
|
2933
|
+
" (>.<) ",
|
|
2934
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2935
|
+
" \u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571\u2571 ",
|
|
2936
|
+
" \u2713 "
|
|
2937
|
+
],
|
|
2938
|
+
"creature-of-habit": [
|
|
2939
|
+
" \u256D\u2500\u2500\u2500\u256E \u256D\u2500\u2500\u2500\u256E ",
|
|
2940
|
+
" \u2502 \u2192 \u2502\u2192\u2502 \u2192 \u2502\u2192 ",
|
|
2941
|
+
" \u2570\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u256F ",
|
|
2942
|
+
" \u256D\u2500\u2500\u2500\u256E \u256D\u2500\u2500\u2500\u256E ",
|
|
2943
|
+
" \u2502 \u2192 \u2502\u2192\u2502 \u2192 \u2502\u2192 ",
|
|
2944
|
+
" \u2570\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u256F ",
|
|
2945
|
+
" \u256D\u2500\u2500\u2500\u256E \u256D\u2500\u2500\u2500\u256E ",
|
|
2946
|
+
" \u2502 \u2192 \u2502\u2192\u2502 \u2192 \u2502\u2192 ",
|
|
2947
|
+
" \u2570\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u256F "
|
|
2948
|
+
],
|
|
2949
|
+
"loyal": [
|
|
2950
|
+
" \u2571\u2572 ",
|
|
2951
|
+
" \u2571 \u2572 ",
|
|
2952
|
+
" \u2571 \u2665\u2665 \u2572 ",
|
|
2953
|
+
" \u2571 \u2665\u2665 \u2572 ",
|
|
2954
|
+
" \u2572 50 \u2571 ",
|
|
2955
|
+
" \u2572 \u2571 ",
|
|
2956
|
+
" \u2572 \u2571 ",
|
|
2957
|
+
" \u2572\u2571 "
|
|
2958
|
+
],
|
|
2959
|
+
"wanderer": [
|
|
2960
|
+
" \xB7 \xB7 \xB7 ",
|
|
2961
|
+
" \u2572 \u2502 \u2571 ",
|
|
2962
|
+
" \u2572 \u2502 \u2571 ",
|
|
2963
|
+
" \xB7 + \xB7 ",
|
|
2964
|
+
" \u2571 \u2502 \u2572 ",
|
|
2965
|
+
" \u2571 \u2502 \u2572 ",
|
|
2966
|
+
" \xB7 \xB7 \xB7 "
|
|
2967
|
+
],
|
|
2968
|
+
"streak": [
|
|
2969
|
+
" \u2554\u2550\u2550\u2557\u2554\u2550\u2550\u2557\u2554\u2550\u2550\u2557\u2554\u2550\u2550\u2557 ",
|
|
2970
|
+
" \u2551M \u2551\u2551T \u2551\u2551W \u2551\u2551T \u2551 ",
|
|
2971
|
+
" \u2551\u25C6 \u2551\u2551\u25C6 \u2551\u2551\u25C6 \u2551\u2551\u25C6 \u2551 ",
|
|
2972
|
+
" \u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D ",
|
|
2973
|
+
" \u2554\u2550\u2550\u2557\u2554\u2550\u2550\u2557\u2554\u2550\u2550\u2557 ",
|
|
2974
|
+
" \u2551F \u2551\u2551S \u2551\u2551S \u2551 ",
|
|
2975
|
+
" \u2551\u25C6 \u2551\u2551\u25C6 \u2551\u2551\u25C6 \u2551 ",
|
|
2976
|
+
" \u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D "
|
|
2977
|
+
],
|
|
2978
|
+
"hot-streak": [
|
|
2979
|
+
" \u2571\u2572 ",
|
|
2980
|
+
" \u2571\u2571\u2572\u2572 ",
|
|
2981
|
+
" \u2571\u2571\u25C6\u25C6\u2572\u2572 ",
|
|
2982
|
+
" \u2571\u2571 \u25C6\u25C6 \u2572\u2572 ",
|
|
2983
|
+
" \u2572\u2572 \u25C6\u25C6 \u2571\u2571 ",
|
|
2984
|
+
" \u2572\u2572\u25C6\u25C6\u2571\u2571 ",
|
|
2985
|
+
" \u2572\u2572\u2571\u2571 ",
|
|
2986
|
+
" \xD77 clean "
|
|
2987
|
+
],
|
|
2988
|
+
"momentum": [
|
|
2989
|
+
" \u25C9 \u25C9 ",
|
|
2990
|
+
" \u2502\u2572 \u2571\u2502 ",
|
|
2991
|
+
" \u2502 \u2572 \u2571 \u2502 ",
|
|
2992
|
+
" \u2502 \u2572 \u2571 \u2502 ",
|
|
2993
|
+
" \u2502 \u25C9\u25C9 \u2502 ",
|
|
2994
|
+
" \u2502 \u2571 \u2572 \u2502 ",
|
|
2995
|
+
" \u2502 \u2571 \u2572 \u2502 ",
|
|
2996
|
+
" \u2502\u2571 \u2572\u2502 ",
|
|
2997
|
+
" \u25C9 \u25C9 "
|
|
2998
|
+
],
|
|
2999
|
+
"patient-one": [
|
|
3000
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
3001
|
+
" \u2502 \u203E.\u203E \u2502 ",
|
|
3002
|
+
" \u2502 \u2502 ",
|
|
3003
|
+
" \u2502 zzz \u2502 ",
|
|
3004
|
+
" \u2502 zz \u2502 ",
|
|
3005
|
+
" \u2502 z \u2502 ",
|
|
3006
|
+
" \u2502 \u2502 ",
|
|
3007
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F ",
|
|
3008
|
+
" 30 min+ "
|
|
3009
|
+
],
|
|
3010
|
+
"message-in-a-bottle": [
|
|
3011
|
+
" \u256D\u2500\u256E ",
|
|
3012
|
+
" \u2502\xD7\u2502 ",
|
|
3013
|
+
" \u256D\u2500\u2534\u2500\u2534\u2500\u256E ",
|
|
3014
|
+
" \u2502 \u2591\u2591\u2591 \u2502 ",
|
|
3015
|
+
" \u2502 \u2591\u2591\u2591 \u2502 ",
|
|
3016
|
+
" \u2502 \u2591\u2591\u2591 \u2502 ",
|
|
3017
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u256F ",
|
|
3018
|
+
" \u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248\u2248 ",
|
|
3019
|
+
" \u2248\u2248\u2248\u2248\u2248\u2248\u2248 "
|
|
3020
|
+
],
|
|
3021
|
+
"comeback-kid": [
|
|
3022
|
+
" \u2571\u2572 \u2571\u2572 ",
|
|
3023
|
+
" \u2571 \u2572 \u2571 \u2572 ",
|
|
3024
|
+
" \u2571 \u2572 \u2571 \u2572 ",
|
|
3025
|
+
" \u2571 \u2573 \u2572 ",
|
|
3026
|
+
" \u2572 \u2571\u2572 \u2571 ",
|
|
3027
|
+
" \u2572 \u2571 \u2572 \u2571 ",
|
|
3028
|
+
" \u2572 \u2571 \u2572 \u2571 ",
|
|
3029
|
+
" \u2572\u2571 \u2572\u2571 \u2713 "
|
|
3030
|
+
],
|
|
3031
|
+
"pair-programming": [
|
|
3032
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u256E\u256D\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
3033
|
+
" \u2502 \u25C9 \u25C9 \u2502\u2502 \u25C9 \u25C9 \u2502 ",
|
|
3034
|
+
" \u2502 \u25BD \u2502\u2502 \u25BD \u2502 ",
|
|
3035
|
+
" \u2570\u2500\u2500\u252C\u2500\u2500\u256F\u2570\u2500\u2500\u252C\u2500\u2500\u256F ",
|
|
3036
|
+
" \u2502 \u2571\u2500\u2500\u2572 \u2502 ",
|
|
3037
|
+
" \u2502\u2571 \u2572\u2502 ",
|
|
3038
|
+
" \u2571 \u2550\u2550 \u2572 ",
|
|
3039
|
+
" \u2571 \u2550\u2550\u2550\u2550 \u2572 ",
|
|
3040
|
+
" \u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594 "
|
|
3041
|
+
],
|
|
3042
|
+
"overdrive": [
|
|
3043
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
3044
|
+
" \u2571 \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u256E \u2572 ",
|
|
3045
|
+
" \u2502 \u2571 \xD76 \u2572 \u2502 ",
|
|
3046
|
+
" \u2502 \u2502 \u25C9 \u2502 \u2502 ",
|
|
3047
|
+
" \u2502 \u2572 \u2571 \u2502 ",
|
|
3048
|
+
" \u2572 \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u256F \u2571 ",
|
|
3049
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F ",
|
|
3050
|
+
" same day \xD76 "
|
|
3051
|
+
],
|
|
3052
|
+
"iron-streak": [
|
|
3053
|
+
" \u2554\u2550\u2550\u2557\u2500\u2554\u2550\u2550\u2557\u2500\u2554\u2550\u2550\u2557 ",
|
|
3054
|
+
" \u2551\u25C6 \u2551 \u2551\u25C6 \u2551 \u2551\u25C6 \u2551 ",
|
|
3055
|
+
" \u255A\u2550\u2550\u255D\u2500\u255A\u2550\u2550\u255D\u2500\u255A\u2550\u2550\u255D ",
|
|
3056
|
+
" \u2502 \u2502 ",
|
|
3057
|
+
" \u2554\u2550\u2550\u2557\u2500\u2554\u2550\u2550\u2557\u2500\u2554\u2550\u2550\u2557 ",
|
|
3058
|
+
" \u2551\u25C6 \u2551 \u2551\u25C6 \u2551 \u2551\u25C6 \u2551 ",
|
|
3059
|
+
" \u255A\u2550\u2550\u255D\u2500\u255A\u2550\u2550\u255D\u2500\u255A\u2550\u2550\u255D ",
|
|
3060
|
+
" 14 day chain "
|
|
3061
|
+
],
|
|
3062
|
+
"deep-conversation": [
|
|
3063
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E ",
|
|
3064
|
+
" \u2571 \u256D\u2500\u2500\u256E 20 \u2572 ",
|
|
3065
|
+
" \u2502 \u2502 \u2502 \u2502 ",
|
|
3066
|
+
" \u2502 \u2570\u2500\u2500\u256F \u2502 ",
|
|
3067
|
+
" \u2502 \xB7 \xB7 \xB7 \xB7 \xB7 \u2502 ",
|
|
3068
|
+
" \u2572 \u2571 ",
|
|
3069
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F ",
|
|
3070
|
+
" \u2572 ",
|
|
3071
|
+
" \u25CF "
|
|
3072
|
+
],
|
|
3073
|
+
"one-must-imagine": [
|
|
3074
|
+
" \u25C9\u25C9\u25C9\u25C9\u25C9 ",
|
|
3075
|
+
" \u2571 \u25C9\u25C9\u25C9\u25C9 ",
|
|
3076
|
+
" \u2571 \u25C9 \u2571 \u2190\u2500\u256E ",
|
|
3077
|
+
"\u2571 (>.<) \u2502 ",
|
|
3078
|
+
" \u2571\u2571 \u2572\u2572 \u2502 ",
|
|
3079
|
+
" \u2571 \u2572 \u2502 ",
|
|
3080
|
+
" \u2571 \u2572\u2500\u256F ",
|
|
3081
|
+
" \u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594 ",
|
|
3082
|
+
" \xD710 restarts "
|
|
3083
|
+
]
|
|
3084
|
+
};
|
|
3085
|
+
var CARD_WIDTH = 34;
|
|
3086
|
+
var CARD_HEIGHT = 18;
|
|
3087
|
+
var CARD_INNER = CARD_WIDTH - 2;
|
|
3088
|
+
function centerLine(text, width) {
|
|
3089
|
+
const stripped = stripAnsiForWidth(text);
|
|
3090
|
+
if (stripped.length >= width) return text.slice(0, width);
|
|
3091
|
+
const pad = Math.floor((width - stripped.length) / 2);
|
|
3092
|
+
return " ".repeat(pad) + text + " ".repeat(width - stripped.length - pad);
|
|
3093
|
+
}
|
|
3094
|
+
function stripAnsiForWidth(s) {
|
|
3095
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
3096
|
+
}
|
|
3097
|
+
function renderBadgeCard(def, unlock, opts) {
|
|
3098
|
+
const dim = opts?.dim === true || unlock === null;
|
|
3099
|
+
const art = BADGE_ART[def.id] ?? [];
|
|
3100
|
+
const lines = [];
|
|
3101
|
+
const category = def.category.toUpperCase();
|
|
3102
|
+
const borderLabel = ` ${category} `;
|
|
3103
|
+
const topPad = CARD_INNER - borderLabel.length - 2;
|
|
3104
|
+
const topLeft = Math.floor(topPad / 2);
|
|
3105
|
+
const topRight = topPad - topLeft;
|
|
3106
|
+
lines.push(`\u250C${"\u2500".repeat(topLeft)}${borderLabel}${"\u2500".repeat(topRight)}\u2510`);
|
|
3107
|
+
lines.push(`\u2502${" ".repeat(CARD_INNER)}\u2502`);
|
|
3108
|
+
const artMaxLines = 9;
|
|
3109
|
+
const artSlice = art.slice(0, artMaxLines);
|
|
3110
|
+
for (const artLine of artSlice) {
|
|
3111
|
+
const centered = centerLine(artLine, CARD_INNER);
|
|
3112
|
+
lines.push(`\u2502${dim ? dimText(centered) : centered}\u2502`);
|
|
3113
|
+
}
|
|
3114
|
+
for (let i = artSlice.length; i < artMaxLines; i++) {
|
|
3115
|
+
lines.push(`\u2502${" ".repeat(CARD_INNER)}\u2502`);
|
|
3116
|
+
}
|
|
3117
|
+
lines.push(`\u2502${" ".repeat(CARD_INNER)}\u2502`);
|
|
3118
|
+
const nameText = unlock !== null ? def.name : `? ${def.name} ?`;
|
|
3119
|
+
lines.push(`\u2502${centerLine(nameText, CARD_INNER)}\u2502`);
|
|
3120
|
+
const descLines = wrapText2(def.description, CARD_INNER - 4);
|
|
3121
|
+
for (const dl of descLines.slice(0, 2)) {
|
|
3122
|
+
const centered = centerLine(dl, CARD_INNER);
|
|
3123
|
+
lines.push(`\u2502${dim ? dimText(centered) : centered}\u2502`);
|
|
3124
|
+
}
|
|
3125
|
+
const usedContent = 1 + 1 + artMaxLines + 1 + 1 + Math.min(descLines.length, 2);
|
|
3126
|
+
const remaining = CARD_HEIGHT - 2 - usedContent;
|
|
3127
|
+
for (let i = 0; i < remaining; i++) {
|
|
3128
|
+
if (i === remaining - 1 && unlock !== null) {
|
|
3129
|
+
const dateStr = unlock.unlockedAt.slice(0, 10);
|
|
3130
|
+
lines.push(`\u2502${centerLine(dimText(dateStr), CARD_INNER)}\u2502`);
|
|
3131
|
+
} else {
|
|
3132
|
+
lines.push(`\u2502${" ".repeat(CARD_INNER)}\u2502`);
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
lines.push(`\u2514${"\u2500".repeat(CARD_INNER)}\u2518`);
|
|
3136
|
+
return { lines, width: CARD_WIDTH, height: lines.length };
|
|
3137
|
+
}
|
|
3138
|
+
function dimText(text) {
|
|
3139
|
+
return `\x1B[2m${text}\x1B[22m`;
|
|
3140
|
+
}
|
|
3141
|
+
function wrapText2(text, maxWidth) {
|
|
3142
|
+
const words = text.split(" ");
|
|
3143
|
+
const lines = [];
|
|
3144
|
+
let current = "";
|
|
3145
|
+
for (const word of words) {
|
|
3146
|
+
if (current.length + word.length + 1 > maxWidth && current.length > 0) {
|
|
3147
|
+
lines.push(current);
|
|
3148
|
+
current = word;
|
|
3149
|
+
} else {
|
|
3150
|
+
current = current.length > 0 ? `${current} ${word}` : word;
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
if (current.length > 0) lines.push(current);
|
|
3154
|
+
return lines;
|
|
3155
|
+
}
|
|
3156
|
+
function createBadgeGallery(unlockedAchievements, startIndex) {
|
|
3157
|
+
const unlocked = /* @__PURE__ */ new Map();
|
|
3158
|
+
for (const a of unlockedAchievements) {
|
|
3159
|
+
unlocked.set(a.id, a);
|
|
3160
|
+
}
|
|
3161
|
+
const sorted = [...ACHIEVEMENTS].sort((a, b) => {
|
|
3162
|
+
const aUnlocked = unlocked.has(a.id);
|
|
3163
|
+
const bUnlocked = unlocked.has(b.id);
|
|
3164
|
+
if (aUnlocked && !bUnlocked) return -1;
|
|
3165
|
+
if (!aUnlocked && bUnlocked) return 1;
|
|
3166
|
+
if (aUnlocked && bUnlocked) {
|
|
3167
|
+
const aDate = unlocked.get(a.id).unlockedAt;
|
|
3168
|
+
const bDate = unlocked.get(b.id).unlockedAt;
|
|
3169
|
+
return aDate.localeCompare(bDate);
|
|
3170
|
+
}
|
|
3171
|
+
return 0;
|
|
3172
|
+
});
|
|
3173
|
+
return {
|
|
3174
|
+
achievements: sorted,
|
|
3175
|
+
unlocked,
|
|
3176
|
+
currentIndex: startIndex ?? 0,
|
|
3177
|
+
total: sorted.length
|
|
3178
|
+
};
|
|
3179
|
+
}
|
|
3180
|
+
function galleryNext(gallery) {
|
|
3181
|
+
return (gallery.currentIndex + 1) % gallery.total;
|
|
3182
|
+
}
|
|
3183
|
+
function galleryPrev(gallery) {
|
|
3184
|
+
return (gallery.currentIndex - 1 + gallery.total) % gallery.total;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
744
3187
|
// src/tui/panels/overlays.ts
|
|
745
3188
|
var HELP_WIDTH = 62;
|
|
746
3189
|
var COMPANION_WIDTH = 52;
|
|
@@ -865,7 +3308,7 @@ var MOOD_ICONS = {
|
|
|
865
3308
|
excited: "\u2726",
|
|
866
3309
|
existential: "\u25C9"
|
|
867
3310
|
};
|
|
868
|
-
var
|
|
3311
|
+
var MOOD_COLORS2 = {
|
|
869
3312
|
happy: "green",
|
|
870
3313
|
grinding: "yellow",
|
|
871
3314
|
frustrated: "red",
|
|
@@ -879,7 +3322,7 @@ function statBar(value, max, width, color) {
|
|
|
879
3322
|
const bar = ansiColor("\u2593".repeat(filled), color) + ansiDim("\u2591".repeat(width - filled));
|
|
880
3323
|
return bar;
|
|
881
3324
|
}
|
|
882
|
-
function
|
|
3325
|
+
function wrapText3(text, maxWidth) {
|
|
883
3326
|
const words = text.split(" ");
|
|
884
3327
|
const lines = [];
|
|
885
3328
|
let current = "";
|
|
@@ -902,7 +3345,7 @@ function renderProfilePage(buf, rows, cols, companion) {
|
|
|
902
3345
|
const endH = Math.floor(companion.stats.endurance / 36e5);
|
|
903
3346
|
const intensity = companion.debugMood?.scores[companion.mood] ?? 0;
|
|
904
3347
|
const face = getMoodFace(companion.mood, intensity);
|
|
905
|
-
const moodColor =
|
|
3348
|
+
const moodColor = MOOD_COLORS2[companion.mood];
|
|
906
3349
|
const moodIcon = MOOD_ICONS[companion.mood];
|
|
907
3350
|
const faceColored = ansiColor(`(${face})`, moodColor, true);
|
|
908
3351
|
const repoNicknames = Object.values(companion.repos).map((r) => r.nickname).filter((n) => n !== null);
|
|
@@ -933,7 +3376,7 @@ function renderProfilePage(buf, rows, cols, companion) {
|
|
|
933
3376
|
contentLines.push(" ".padEnd(innerWidth));
|
|
934
3377
|
if (companion.lastCommentary) {
|
|
935
3378
|
const raw = companion.lastCommentary.text;
|
|
936
|
-
const wrapped =
|
|
3379
|
+
const wrapped = wrapText3(raw, innerWidth - 6);
|
|
937
3380
|
contentLines.push(` ${ansiDim("\u250A")} ${ansiColor(wrapped[0] ?? "", "white")}`.padEnd(innerWidth));
|
|
938
3381
|
for (let i = 1; i < wrapped.length; i++) {
|
|
939
3382
|
contentLines.push(` ${ansiDim("\u250A")} ${ansiColor(wrapped[i] ?? "", "white")}`.padEnd(innerWidth));
|
|
@@ -1144,8 +3587,50 @@ function renderCompanionDebugOverlay(buf, rows, cols, companion) {
|
|
|
1144
3587
|
}
|
|
1145
3588
|
|
|
1146
3589
|
// src/tui/panels/mounted-humanloop.ts
|
|
1147
|
-
|
|
3590
|
+
init_ask_store();
|
|
3591
|
+
init_paths();
|
|
3592
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
1148
3593
|
import { mountPanel } from "@crouton-kit/humanloop";
|
|
3594
|
+
|
|
3595
|
+
// src/shared/client.ts
|
|
3596
|
+
init_paths();
|
|
3597
|
+
import { connect } from "net";
|
|
3598
|
+
function rawSend(request, timeoutMs = 1e4) {
|
|
3599
|
+
const sock = socketPath();
|
|
3600
|
+
return new Promise((resolve2, reject) => {
|
|
3601
|
+
const socket = connect(sock);
|
|
3602
|
+
let data = "";
|
|
3603
|
+
const timeout = setTimeout(() => {
|
|
3604
|
+
socket.destroy();
|
|
3605
|
+
reject(new Error(`Request timed out after ${(timeoutMs / 1e3).toFixed(0)}s. The daemon may be overloaded.
|
|
3606
|
+
Check: sisyphus admin doctor
|
|
3607
|
+
Logs: tail -20 ~/.sisyphus/daemon.log`));
|
|
3608
|
+
}, timeoutMs);
|
|
3609
|
+
socket.on("connect", () => {
|
|
3610
|
+
socket.write(JSON.stringify(request) + "\n");
|
|
3611
|
+
});
|
|
3612
|
+
socket.on("data", (chunk) => {
|
|
3613
|
+
data += chunk.toString();
|
|
3614
|
+
const newlineIdx = data.indexOf("\n");
|
|
3615
|
+
if (newlineIdx !== -1) {
|
|
3616
|
+
clearTimeout(timeout);
|
|
3617
|
+
const line = data.slice(0, newlineIdx);
|
|
3618
|
+
socket.destroy();
|
|
3619
|
+
try {
|
|
3620
|
+
resolve2(JSON.parse(line));
|
|
3621
|
+
} catch {
|
|
3622
|
+
reject(new Error(`Invalid JSON response from daemon: ${line}`));
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
});
|
|
3626
|
+
socket.on("error", (err) => {
|
|
3627
|
+
clearTimeout(timeout);
|
|
3628
|
+
reject(err);
|
|
3629
|
+
});
|
|
3630
|
+
});
|
|
3631
|
+
}
|
|
3632
|
+
|
|
3633
|
+
// src/tui/panels/mounted-humanloop.ts
|
|
1149
3634
|
async function dispatchOrphanResolution(orphanTarget, selectedOptionId, deps) {
|
|
1150
3635
|
if (selectedOptionId === "takeover" && orphanTarget.kind === "agent") {
|
|
1151
3636
|
await deps.onOrphanTakeover?.({
|
|
@@ -1203,7 +3688,7 @@ function mountResolutionPanel(opts, state2) {
|
|
|
1203
3688
|
}, 6e4);
|
|
1204
3689
|
if (res.ok) {
|
|
1205
3690
|
const ansiPath = res.data.ansiPath;
|
|
1206
|
-
const ansi =
|
|
3691
|
+
const ansi = readFileSync9(ansiPath, "utf-8");
|
|
1207
3692
|
state2.visuals.set(qid, { status: "ready", content: ansi, visible: true });
|
|
1208
3693
|
} else {
|
|
1209
3694
|
state2.visuals.set(qid, { status: "error", content: "", visible: true, error: res.error });
|
|
@@ -1383,6 +3868,116 @@ function enterResolutionMode(state2, askId2, daemonSend, onOrphanTakeover) {
|
|
|
1383
3868
|
requestRender();
|
|
1384
3869
|
}
|
|
1385
3870
|
|
|
3871
|
+
// src/shared/keymap.ts
|
|
3872
|
+
var MENU_FOR_MODE = {
|
|
3873
|
+
"leader": "topLevel",
|
|
3874
|
+
"copy-menu": "copy",
|
|
3875
|
+
"open-menu": "open",
|
|
3876
|
+
"agent-menu": "agent",
|
|
3877
|
+
"session-menu": "session",
|
|
3878
|
+
"go-menu": "go",
|
|
3879
|
+
"companion-menu": "companion"
|
|
3880
|
+
};
|
|
3881
|
+
var KEYMAP = {
|
|
3882
|
+
version: 1,
|
|
3883
|
+
topLevel: {
|
|
3884
|
+
title: " Sisyphus ",
|
|
3885
|
+
items: [
|
|
3886
|
+
{ key: "s", label: " Cycle session", action: { type: "script", name: "sisyphus-cycle" } },
|
|
3887
|
+
{ key: "h", label: " Home / dashboard", action: { type: "script", name: "sisyphus-home" } },
|
|
3888
|
+
{ key: "n", label: " New session", action: { type: "popup", name: "sisyphus-new", popup: { w: "80%", h: "60%", cwd: "current" } } },
|
|
3889
|
+
{ key: "m", label: " Message orchestrator", action: { type: "popup", name: "sisyphus-msg", popup: { w: "80%", h: "60%", cwd: "current" } } },
|
|
3890
|
+
{ key: "t", label: " Status (where am I?)", action: { type: "popup", name: "sisyphus-status-popup", popup: { w: "90%", h: "90%", cwd: "current" } } },
|
|
3891
|
+
{ key: "l", label: " Session picker", action: { type: "popup", name: "sisyphus-pick-session", popup: { w: "60%", h: "60%", cwd: "current" } } },
|
|
3892
|
+
{ key: "z", label: " Zoom pane", action: { type: "tmux", cmd: "resize-pane -Z" } },
|
|
3893
|
+
{ key: "x", label: " Kill pane (smart)", action: { type: "script", name: "sisyphus-kill-pane" } },
|
|
3894
|
+
{ key: "?", label: " Full help reference", action: { type: "popup", name: "sisyphus-help", popup: { w: "80", h: "32", title: " Keybindings " } } },
|
|
3895
|
+
{ key: "/", label: " Search / filter", action: { type: "script", name: "sisyphus-search-reports" }, tuiAction: "search" },
|
|
3896
|
+
{ key: " ", label: " Open popup explicitly", action: { type: "tui", action: "show-leader" } },
|
|
3897
|
+
{ key: "y", label: " Yank \u203A", action: { type: "submenu", ref: "copy" } },
|
|
3898
|
+
{ key: "c", label: " Companion \u203A", action: { type: "submenu", ref: "companion" } },
|
|
3899
|
+
{ key: "o", label: " Open \u203A", action: { type: "submenu", ref: "open" } },
|
|
3900
|
+
{ key: "a", label: " Agent \u203A", action: { type: "submenu", ref: "agent" } },
|
|
3901
|
+
{ key: "S", label: " Session \u203A", action: { type: "submenu", ref: "session" } },
|
|
3902
|
+
{ key: "g", label: " Go \u203A", action: { type: "submenu", ref: "go" } }
|
|
3903
|
+
]
|
|
3904
|
+
},
|
|
3905
|
+
submenus: {
|
|
3906
|
+
companion: {
|
|
3907
|
+
title: " Companion ",
|
|
3908
|
+
items: [
|
|
3909
|
+
{ key: "p", label: " profile (overlay)", action: { type: "tui", action: "companion-overlay" } },
|
|
3910
|
+
{ key: "d", label: " debug (mood signals)", action: { type: "tui", action: "companion-debug" } },
|
|
3911
|
+
{ key: "t", label: " open in tmux pane", action: { type: "tui", action: "companion-pane" } }
|
|
3912
|
+
]
|
|
3913
|
+
},
|
|
3914
|
+
copy: {
|
|
3915
|
+
title: " Copy ",
|
|
3916
|
+
items: [
|
|
3917
|
+
{ key: "p", label: " session dir path", action: { type: "script", name: "sisyphus-copy-path" } },
|
|
3918
|
+
{ key: "i", label: " session UUID", action: { type: "script", name: "sisyphus-copy-id" } },
|
|
3919
|
+
{ key: "c", label: " full session context XML", action: { type: "script", name: "sisyphus-copy-context" } },
|
|
3920
|
+
{ key: "l", label: " logs (last 200 lines)", action: { type: "script", name: "sisyphus-copy-logs" } },
|
|
3921
|
+
{ key: "r", label: " latest report content", action: { type: "script", name: "sisyphus-copy-latest-report" } },
|
|
3922
|
+
{ key: "a", label: " agent ID (picker)", action: { type: "script", name: "sisyphus-copy-agent-id" } }
|
|
3923
|
+
]
|
|
3924
|
+
},
|
|
3925
|
+
open: {
|
|
3926
|
+
title: " Open ",
|
|
3927
|
+
items: [
|
|
3928
|
+
{ key: "g", label: " goal.md", action: { type: "popup", name: "sisyphus-open-goal", popup: { w: "95%", h: "95%", cwd: "current" } } },
|
|
3929
|
+
{ key: "r", label: " roadmap.md", action: { type: "popup", name: "sisyphus-open-roadmap", popup: { w: "95%", h: "95%", cwd: "current" } } },
|
|
3930
|
+
{ key: "s", label: " strategy.md", action: { type: "popup", name: "sisyphus-open-strategy", popup: { w: "95%", h: "95%", cwd: "current" } } },
|
|
3931
|
+
{ key: "l", label: " logs popup (tail)", action: { type: "popup", name: "sisyphus-open-logs", popup: { w: "90%", h: "90%", cwd: "current" } } },
|
|
3932
|
+
{ key: "d", label: " session dir in file mgr", action: { type: "script", name: "sisyphus-open-dir" } },
|
|
3933
|
+
{ key: "R", label: " latest report file", action: { type: "popup", name: "sisyphus-open-latest-report", popup: { w: "95%", h: "95%", cwd: "current" } } },
|
|
3934
|
+
{ key: "c", label: " scratch", action: { type: "popup", name: "sisyphus-open-scratch", popup: { w: "95%", h: "95%", cwd: "current" } } },
|
|
3935
|
+
{ key: "e", label: " edit context file", action: { type: "popup", name: "sisyphus-edit-context-file", popup: { w: "95%", h: "95%", cwd: "current" } }, tuiAction: "edit-context-file" }
|
|
3936
|
+
]
|
|
3937
|
+
},
|
|
3938
|
+
agent: {
|
|
3939
|
+
title: " Agent ",
|
|
3940
|
+
items: [
|
|
3941
|
+
{ key: "s", label: " spawn agent", action: { type: "popup", name: "sisyphus-spawn-agent", popup: { w: "80%", h: "70%", cwd: "current" } } },
|
|
3942
|
+
{ key: "m", label: " message agent (picker)", action: { type: "popup", name: "sisyphus-msg-agent", popup: { w: "80%", h: "60%", cwd: "current" } } },
|
|
3943
|
+
{ key: "r", label: " restart agent (picker)", action: { type: "popup", name: "sisyphus-restart-agent-popup", popup: { w: "70%", h: "50%", cwd: "current" } } },
|
|
3944
|
+
{ key: "R", label: " re-run agent (picker)", action: { type: "popup", name: "sisyphus-rerun-agent", popup: { w: "70%", h: "50%", cwd: "current" } } },
|
|
3945
|
+
{ key: "j", label: " jump to agent's pane", action: { type: "popup", name: "sisyphus-jump-to-pane", popup: { w: "60%", h: "60%" } } },
|
|
3946
|
+
{ key: "o", label: " open claude --resume", action: { type: "popup", name: "sisyphus-open-claude-agent", popup: { w: "60%", h: "60%", cwd: "current" } } },
|
|
3947
|
+
{ key: "t", label: " tail agent logs (picker)", action: { type: "popup", name: "sisyphus-tail-agent-logs", popup: { w: "90%", h: "90%", cwd: "current" } } },
|
|
3948
|
+
{ key: "k", label: " kill agent (picker)", action: { type: "popup", name: "sisyphus-kill-agent", popup: { w: "60%", h: "40%", cwd: "current" } } },
|
|
3949
|
+
{ key: "e", label: " quick-spawn Explore", action: { type: "script", name: "sisyphus-quick-spawn-explore" } },
|
|
3950
|
+
{ key: "d", label: " quick-spawn Debug", action: { type: "script", name: "sisyphus-quick-spawn-debug" } }
|
|
3951
|
+
]
|
|
3952
|
+
},
|
|
3953
|
+
session: {
|
|
3954
|
+
title: " Session ",
|
|
3955
|
+
items: [
|
|
3956
|
+
{ key: "n", label: " new session", action: { type: "popup", name: "sisyphus-new", popup: { w: "80%", h: "60%", cwd: "current" } } },
|
|
3957
|
+
{ key: "r", label: " resume", action: { type: "popup", name: "sisyphus-resume-session", popup: { w: "80%", h: "60%", cwd: "current" } } },
|
|
3958
|
+
{ key: "c", label: " continue", action: { type: "popup", name: "sisyphus-continue-session", popup: { w: "50", h: "5", borderStyle: "fg=yellow", title: " Continue Session ", cwd: "current" } } },
|
|
3959
|
+
{ key: "b", label: " rollback (prompts cycle)", action: { type: "popup", name: "sisyphus-rollback-session", popup: { w: "50", h: "5", title: " Rollback ", cwd: "current" } } },
|
|
3960
|
+
{ key: "k", label: " kill", action: { type: "popup", name: "sisyphus-kill-session", popup: { w: "40", h: "5", borderStyle: "fg=red", title: " Kill Session ", cwd: "current" } } },
|
|
3961
|
+
{ key: "d", label: " delete (confirms)", action: { type: "popup", name: "sisyphus-delete-session", popup: { w: "40", h: "5", borderStyle: "fg=red", title: " Delete Session ", cwd: "current" } } },
|
|
3962
|
+
{ key: "e", label: " export to ~/Downloads", action: { type: "popup", name: "sisyphus-export-session", popup: { w: "60", h: "8", title: " Export Session ", cwd: "current" } } },
|
|
3963
|
+
{ key: "w", label: " go to session window", action: { type: "popup", name: "sisyphus-go-to-window", popup: { w: "70%", h: "60%", cwd: "current" } } },
|
|
3964
|
+
{ key: "C", label: " clone (sisyphus session clone)", action: { type: "popup", name: "sisyphus-clone-session", popup: { w: "60%", h: "60%", cwd: "current" } } },
|
|
3965
|
+
{ key: "i", label: " history", action: { type: "popup", name: "sisyphus-history", popup: { w: "95%", h: "95%", cwd: "current" } } }
|
|
3966
|
+
]
|
|
3967
|
+
},
|
|
3968
|
+
go: {
|
|
3969
|
+
title: " Go ",
|
|
3970
|
+
items: [
|
|
3971
|
+
{ key: "w", label: " go to session window", action: { type: "popup", name: "sisyphus-go-to-window", popup: { w: "70%", h: "60%", cwd: "current" } } },
|
|
3972
|
+
{ key: "p", label: " jump to pane (picker)", action: { type: "popup", name: "sisyphus-jump-to-pane", popup: { w: "60%", h: "60%" } } },
|
|
3973
|
+
{ key: "s", label: " session picker", action: { type: "popup", name: "sisyphus-pick-session", popup: { w: "60%", h: "60%", cwd: "current" } } },
|
|
3974
|
+
{ key: "n", label: " next session", action: { type: "script", name: "sisyphus-cycle" } },
|
|
3975
|
+
{ key: "r", label: " reconnect", action: { type: "popup", name: "sisyphus-reconnect", popup: { w: "80%", h: "40%", cwd: "current" } } }
|
|
3976
|
+
]
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
};
|
|
3980
|
+
|
|
1386
3981
|
// src/tui/input.ts
|
|
1387
3982
|
function dispatchComposeAction(action, content, state2, actions) {
|
|
1388
3983
|
switch (action.kind) {
|
|
@@ -1446,12 +4041,16 @@ var ENTER_FOR_REF = {
|
|
|
1446
4041
|
open: "enter-open-menu",
|
|
1447
4042
|
agent: "enter-agent-menu",
|
|
1448
4043
|
session: "enter-session-menu",
|
|
1449
|
-
go: "enter-go-menu"
|
|
4044
|
+
go: "enter-go-menu",
|
|
4045
|
+
companion: "enter-companion-menu"
|
|
1450
4046
|
};
|
|
1451
4047
|
var TUI_ACTION_FOR_NAME = {
|
|
1452
4048
|
"search": "search",
|
|
1453
4049
|
"edit-context-file": "edit-context-file",
|
|
1454
|
-
"show-leader": "help"
|
|
4050
|
+
"show-leader": "help",
|
|
4051
|
+
"companion-overlay": "companion-overlay",
|
|
4052
|
+
"companion-debug": "companion-debug",
|
|
4053
|
+
"companion-pane": "companion-pane"
|
|
1455
4054
|
};
|
|
1456
4055
|
var TUI_HANDLERS = {
|
|
1457
4056
|
"sisyphus-copy-path": "copy-path",
|
|
@@ -1499,18 +4098,18 @@ var TUI_HANDLERS = {
|
|
|
1499
4098
|
function findLatestReport(cwd2, sessionId2) {
|
|
1500
4099
|
const dir = reportsDir(cwd2, sessionId2);
|
|
1501
4100
|
try {
|
|
1502
|
-
const files =
|
|
4101
|
+
const files = readdirSync5(dir);
|
|
1503
4102
|
if (files.length === 0) return null;
|
|
1504
4103
|
let latestFile = files[0];
|
|
1505
|
-
let latestMtime =
|
|
4104
|
+
let latestMtime = statSync3(join11(dir, latestFile)).mtimeMs;
|
|
1506
4105
|
for (let i = 1; i < files.length; i++) {
|
|
1507
|
-
const m =
|
|
4106
|
+
const m = statSync3(join11(dir, files[i])).mtimeMs;
|
|
1508
4107
|
if (m > latestMtime) {
|
|
1509
4108
|
latestMtime = m;
|
|
1510
4109
|
latestFile = files[i];
|
|
1511
4110
|
}
|
|
1512
4111
|
}
|
|
1513
|
-
return
|
|
4112
|
+
return join11(dir, latestFile);
|
|
1514
4113
|
} catch {
|
|
1515
4114
|
return null;
|
|
1516
4115
|
}
|
|
@@ -1758,6 +4357,10 @@ function handleLeaderAction(action, state2, actions) {
|
|
|
1758
4357
|
state2.mode = "help";
|
|
1759
4358
|
requestRender();
|
|
1760
4359
|
return;
|
|
4360
|
+
case "enter-companion-menu":
|
|
4361
|
+
state2.mode = "companion-menu";
|
|
4362
|
+
requestRender();
|
|
4363
|
+
return;
|
|
1761
4364
|
case "companion-overlay":
|
|
1762
4365
|
state2.mode = "companion-overlay";
|
|
1763
4366
|
requestRender();
|
|
@@ -1766,6 +4369,13 @@ function handleLeaderAction(action, state2, actions) {
|
|
|
1766
4369
|
state2.mode = "companion-debug";
|
|
1767
4370
|
requestRender();
|
|
1768
4371
|
return;
|
|
4372
|
+
case "companion-pane":
|
|
4373
|
+
try {
|
|
4374
|
+
actions.openCompanionPane(state2.cwd);
|
|
4375
|
+
} catch {
|
|
4376
|
+
notify(state2, "Failed to open companion pane");
|
|
4377
|
+
}
|
|
4378
|
+
return;
|
|
1769
4379
|
case "shell-command": {
|
|
1770
4380
|
if (!selectedSessionId) {
|
|
1771
4381
|
notify(state2, "No session selected");
|
|
@@ -1849,7 +4459,7 @@ function handleLeaderAction(action, state2, actions) {
|
|
|
1849
4459
|
break;
|
|
1850
4460
|
}
|
|
1851
4461
|
try {
|
|
1852
|
-
const content =
|
|
4462
|
+
const content = readFileSync10(latest, "utf-8");
|
|
1853
4463
|
actions.copyToClipboard(content);
|
|
1854
4464
|
notify(state2, `Copied latest report (${content.length} chars)`);
|
|
1855
4465
|
} catch {
|
|
@@ -1909,7 +4519,7 @@ function handleLeaderAction(action, state2, actions) {
|
|
|
1909
4519
|
}
|
|
1910
4520
|
const editor = actions.resolveEditor();
|
|
1911
4521
|
try {
|
|
1912
|
-
actions.openEditorPopup(state2.cwd, editor,
|
|
4522
|
+
actions.openEditorPopup(state2.cwd, editor, join11(sessionDir(state2.cwd, selectedSessionId), "scratch.md"));
|
|
1913
4523
|
} catch {
|
|
1914
4524
|
notify(state2, "Failed to open scratch");
|
|
1915
4525
|
}
|
|
@@ -2705,7 +5315,7 @@ function handleKeypress(input, key, state2, actions) {
|
|
|
2705
5315
|
}
|
|
2706
5316
|
if (state2.mode === "search") {
|
|
2707
5317
|
handleSearchKey(input, key, state2);
|
|
2708
|
-
} else if (state2.mode === "leader" || state2.mode === "copy-menu" || state2.mode === "open-menu" || state2.mode === "agent-menu" || state2.mode === "session-menu" || state2.mode === "go-menu" || state2.mode === "help" || state2.mode === "companion-overlay" || state2.mode === "companion-debug") {
|
|
5318
|
+
} else if (state2.mode === "leader" || state2.mode === "copy-menu" || state2.mode === "open-menu" || state2.mode === "agent-menu" || state2.mode === "session-menu" || state2.mode === "go-menu" || state2.mode === "companion-menu" || state2.mode === "help" || state2.mode === "companion-overlay" || state2.mode === "companion-debug") {
|
|
2709
5319
|
handleLeaderKey(input, key, state2, actions);
|
|
2710
5320
|
} else if (state2.mode === "report-detail") {
|
|
2711
5321
|
handleReportDetailKey(input, key, state2, actions);
|
|
@@ -2714,6 +5324,10 @@ function handleKeypress(input, key, state2, actions) {
|
|
|
2714
5324
|
}
|
|
2715
5325
|
}
|
|
2716
5326
|
|
|
5327
|
+
// src/tui/app.ts
|
|
5328
|
+
init_render();
|
|
5329
|
+
init_terminal();
|
|
5330
|
+
|
|
2717
5331
|
// src/tui/lib/tree-render.ts
|
|
2718
5332
|
function renderTreePrefix(node, nodes, index) {
|
|
2719
5333
|
if (node.depth === 0) {
|
|
@@ -2784,6 +5398,24 @@ function precomputePrefixes(nodes) {
|
|
|
2784
5398
|
}
|
|
2785
5399
|
}
|
|
2786
5400
|
|
|
5401
|
+
// src/tui/lib/reports.ts
|
|
5402
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
5403
|
+
function loadReportContent(report) {
|
|
5404
|
+
try {
|
|
5405
|
+
return readFileSync11(report.filePath, "utf-8");
|
|
5406
|
+
} catch {
|
|
5407
|
+
return report.summary;
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
function resolveReports(reports) {
|
|
5411
|
+
return [...reports].reverse().map((r) => ({
|
|
5412
|
+
type: r.type,
|
|
5413
|
+
timestamp: r.timestamp,
|
|
5414
|
+
content: loadReportContent(r),
|
|
5415
|
+
summary: r.summary
|
|
5416
|
+
}));
|
|
5417
|
+
}
|
|
5418
|
+
|
|
2787
5419
|
// src/tui/lib/client.ts
|
|
2788
5420
|
function send(request) {
|
|
2789
5421
|
return rawSend(request, 8e3);
|
|
@@ -2795,10 +5427,28 @@ async function inboxList() {
|
|
|
2795
5427
|
}
|
|
2796
5428
|
|
|
2797
5429
|
// src/tui/lib/tmux.ts
|
|
2798
|
-
|
|
2799
|
-
import {
|
|
2800
|
-
import {
|
|
5430
|
+
init_paths();
|
|
5431
|
+
import { execSync as execSync3 } from "child_process";
|
|
5432
|
+
import { join as join12 } from "path";
|
|
5433
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, mkdtempSync, rmSync as rmSync4, cpSync as cpSync2, existsSync as existsSync8, mkdirSync as mkdirSync8 } from "fs";
|
|
2801
5434
|
import { tmpdir } from "os";
|
|
5435
|
+
init_shell();
|
|
5436
|
+
|
|
5437
|
+
// src/shared/exec.ts
|
|
5438
|
+
import { execSync as execSync2 } from "child_process";
|
|
5439
|
+
var EXEC_ENV = execEnv();
|
|
5440
|
+
function exec(cmd, cwd2, timeoutMs = 3e4) {
|
|
5441
|
+
return execSync2(cmd, { encoding: "utf-8", env: EXEC_ENV, cwd: cwd2, timeout: timeoutMs }).trim();
|
|
5442
|
+
}
|
|
5443
|
+
function execSafe(cmd, cwd2, timeoutMs) {
|
|
5444
|
+
try {
|
|
5445
|
+
return execSync2(cmd, { encoding: "utf-8", env: EXEC_ENV, cwd: cwd2, stdio: ["pipe", "pipe", "pipe"], timeout: timeoutMs }).trim();
|
|
5446
|
+
} catch {
|
|
5447
|
+
return null;
|
|
5448
|
+
}
|
|
5449
|
+
}
|
|
5450
|
+
|
|
5451
|
+
// src/tui/lib/tmux.ts
|
|
2802
5452
|
function getWindowId() {
|
|
2803
5453
|
const pane = process.env["TMUX_PANE"];
|
|
2804
5454
|
if (pane) {
|
|
@@ -2814,7 +5464,7 @@ function selectPane(paneId) {
|
|
|
2814
5464
|
}
|
|
2815
5465
|
function listAllWindowIds() {
|
|
2816
5466
|
try {
|
|
2817
|
-
const output =
|
|
5467
|
+
const output = execSync3('tmux list-windows -a -F "#{window_id}"', { encoding: "utf-8", env: EXEC_ENV });
|
|
2818
5468
|
return new Set(output.trim().split("\n").filter(Boolean));
|
|
2819
5469
|
} catch {
|
|
2820
5470
|
return /* @__PURE__ */ new Set();
|
|
@@ -2834,10 +5484,10 @@ function registerDashboardWindow() {
|
|
|
2834
5484
|
}
|
|
2835
5485
|
var companionPaneId = null;
|
|
2836
5486
|
function setupCompanionPlugin() {
|
|
2837
|
-
const srcDir =
|
|
2838
|
-
const destDir =
|
|
2839
|
-
if (!
|
|
2840
|
-
|
|
5487
|
+
const srcDir = join12(import.meta.dirname, "templates", "companion-plugin");
|
|
5488
|
+
const destDir = join12(globalDir(), "companion-plugin");
|
|
5489
|
+
if (!existsSync8(destDir)) mkdirSync8(destDir, { recursive: true });
|
|
5490
|
+
cpSync2(srcDir, destDir, { recursive: true });
|
|
2841
5491
|
return destDir;
|
|
2842
5492
|
}
|
|
2843
5493
|
function paneExists(paneId) {
|
|
@@ -2849,18 +5499,18 @@ function openCompanionPane(cwd2) {
|
|
|
2849
5499
|
return;
|
|
2850
5500
|
}
|
|
2851
5501
|
const pluginDir = setupCompanionPlugin();
|
|
2852
|
-
const templatePath =
|
|
5502
|
+
const templatePath = join12(import.meta.dirname, "templates", "dashboard-claude.md");
|
|
2853
5503
|
let template;
|
|
2854
5504
|
try {
|
|
2855
|
-
template =
|
|
5505
|
+
template = readFileSync12(templatePath, "utf-8");
|
|
2856
5506
|
} catch {
|
|
2857
5507
|
template = `You are a Sisyphus dashboard companion. Help the user manage multi-agent sessions.
|
|
2858
5508
|
Project: ${cwd2}
|
|
2859
5509
|
Run \`sisyphus list\` and \`sisyphus status\` to see current state.`;
|
|
2860
5510
|
}
|
|
2861
5511
|
const rendered = template.replace(/\{\{CWD\}\}/g, cwd2);
|
|
2862
|
-
const promptPath =
|
|
2863
|
-
|
|
5512
|
+
const promptPath = join12(globalDir(), "dashboard-companion-prompt.md");
|
|
5513
|
+
writeFileSync9(promptPath, rendered, "utf-8");
|
|
2864
5514
|
const pathEnv = augmentedPath();
|
|
2865
5515
|
const claudeCmd = `SISYPHUS_COMPANION_CWD=${shellQuote(cwd2)} PATH=${shellQuote(pathEnv)} claude --dangerously-skip-permissions --plugin-dir ${shellQuote(pluginDir)} --append-system-prompt "$(cat ${shellQuote(promptPath)})"`;
|
|
2866
5516
|
const result = exec(
|
|
@@ -2873,55 +5523,55 @@ function switchToSession(sessionName) {
|
|
|
2873
5523
|
execSafe(`tmux switch-client -t ${shellQuote(sessionName)}`);
|
|
2874
5524
|
}
|
|
2875
5525
|
function editInPopup(cwd2, editor, opts) {
|
|
2876
|
-
const tmpDir = mkdtempSync(
|
|
2877
|
-
const filePath =
|
|
5526
|
+
const tmpDir = mkdtempSync(join12(tmpdir(), "sisyphus-"));
|
|
5527
|
+
const filePath = join12(tmpDir, "input.md");
|
|
2878
5528
|
try {
|
|
2879
|
-
|
|
5529
|
+
writeFileSync9(filePath, opts?.content ? opts.content : "", "utf-8");
|
|
2880
5530
|
openEditorPopup(cwd2, editor, filePath, opts?.size);
|
|
2881
|
-
const result =
|
|
5531
|
+
const result = readFileSync12(filePath, "utf-8").trim();
|
|
2882
5532
|
return result || null;
|
|
2883
5533
|
} finally {
|
|
2884
|
-
|
|
5534
|
+
rmSync4(tmpDir, { recursive: true, force: true });
|
|
2885
5535
|
}
|
|
2886
5536
|
}
|
|
2887
5537
|
function promptInPopup(prompt, opts) {
|
|
2888
5538
|
const { w = "50%", h = "3" } = opts ?? {};
|
|
2889
|
-
const tmpDir = mkdtempSync(
|
|
2890
|
-
const outFile =
|
|
5539
|
+
const tmpDir = mkdtempSync(join12(tmpdir(), "sisyphus-"));
|
|
5540
|
+
const outFile = join12(tmpDir, "result");
|
|
2891
5541
|
try {
|
|
2892
5542
|
const script = `printf ${shellQuote(prompt + " ")} && read -r line && printf '%s' "$line" > ${shellQuote(outFile)}`;
|
|
2893
|
-
|
|
5543
|
+
execSync3(
|
|
2894
5544
|
`tmux display-popup -E -w ${w} -h ${h} ${shellQuote(`bash -c ${shellQuote(script)}`)}`,
|
|
2895
5545
|
{ stdio: "inherit", env: EXEC_ENV }
|
|
2896
5546
|
);
|
|
2897
|
-
if (!
|
|
2898
|
-
const result =
|
|
5547
|
+
if (!existsSync8(outFile)) return null;
|
|
5548
|
+
const result = readFileSync12(outFile, "utf-8").trim();
|
|
2899
5549
|
return result || null;
|
|
2900
5550
|
} finally {
|
|
2901
|
-
|
|
5551
|
+
rmSync4(tmpDir, { recursive: true, force: true });
|
|
2902
5552
|
}
|
|
2903
5553
|
}
|
|
2904
5554
|
function openLogPopup() {
|
|
2905
|
-
|
|
5555
|
+
execSync3(
|
|
2906
5556
|
`tmux display-popup -E -w 90% -h 80% ${shellQuote("tail -f ~/.sisyphus/daemon.log")}`,
|
|
2907
5557
|
{ stdio: "inherit", env: EXEC_ENV }
|
|
2908
5558
|
);
|
|
2909
5559
|
}
|
|
2910
5560
|
function openShellPopup(cwd2, command) {
|
|
2911
|
-
|
|
5561
|
+
execSync3(
|
|
2912
5562
|
`tmux display-popup -E -w 90% -h 80% -d ${shellQuote(cwd2)} ${shellQuote(`sh -c '${command.replace(/'/g, "'\\''")}; echo; echo "Press enter to close"; read'`)}`,
|
|
2913
5563
|
{ stdio: "inherit", env: EXEC_ENV }
|
|
2914
5564
|
);
|
|
2915
5565
|
}
|
|
2916
5566
|
function openInFileManager(path) {
|
|
2917
|
-
|
|
5567
|
+
execSync3(`open ${shellQuote(path)}`, { stdio: "inherit", env: EXEC_ENV });
|
|
2918
5568
|
}
|
|
2919
5569
|
function openClaudeResumePopup(cwd2, claudeSessionId, resumeEnv, resumeArgs) {
|
|
2920
5570
|
const pathEnv = augmentedPath();
|
|
2921
5571
|
const envPrefix = resumeEnv ? `${resumeEnv} && ` : "";
|
|
2922
5572
|
const args2 = resumeArgs ? `${resumeArgs} --resume ${shellQuote(claudeSessionId)}` : `--resume ${shellQuote(claudeSessionId)}`;
|
|
2923
5573
|
const cmd = `${envPrefix}PATH=${shellQuote(pathEnv)} claude ${args2}`;
|
|
2924
|
-
|
|
5574
|
+
execSync3(
|
|
2925
5575
|
`tmux display-popup -E -w 90% -h 80% -d ${shellQuote(cwd2)} ${shellQuote(cmd)}`,
|
|
2926
5576
|
{ stdio: "inherit", env: EXEC_ENV }
|
|
2927
5577
|
);
|
|
@@ -2981,23 +5631,83 @@ function openEditorPopup(cwd2, editor, filePath, size) {
|
|
|
2981
5631
|
const { w = "90%", h = "90%" } = size ?? {};
|
|
2982
5632
|
const editorBin = editor.split(/\s+/)[0].split("/").pop();
|
|
2983
5633
|
if (TERMINAL_EDITORS.has(editorBin)) {
|
|
2984
|
-
|
|
5634
|
+
execSync3(
|
|
2985
5635
|
`tmux display-popup -E -w ${w} -h ${h} -d ${shellQuote(cwd2)} ${shellQuote(`${editor} ${shellQuote(filePath)}`)}`,
|
|
2986
5636
|
{ stdio: "inherit", env: EXEC_ENV }
|
|
2987
5637
|
);
|
|
2988
5638
|
} else {
|
|
2989
|
-
|
|
5639
|
+
execSync3(`${editor} ${shellQuote(filePath)}`, { stdio: "inherit", cwd: cwd2, env: EXEC_ENV });
|
|
2990
5640
|
}
|
|
2991
5641
|
}
|
|
2992
5642
|
|
|
2993
5643
|
// src/tui/lib/clipboard.ts
|
|
2994
|
-
import { execSync as
|
|
5644
|
+
import { execSync as execSync4 } from "child_process";
|
|
2995
5645
|
function copyToClipboard(text) {
|
|
2996
|
-
|
|
5646
|
+
execSync4("pbcopy", { input: text });
|
|
5647
|
+
}
|
|
5648
|
+
|
|
5649
|
+
// src/tui/lib/context.ts
|
|
5650
|
+
init_paths();
|
|
5651
|
+
import { readFileSync as readFileSync13, readdirSync as readdirSync6 } from "fs";
|
|
5652
|
+
function readFileSafe(filePath) {
|
|
5653
|
+
try {
|
|
5654
|
+
return readFileSync13(filePath, "utf-8");
|
|
5655
|
+
} catch {
|
|
5656
|
+
return null;
|
|
5657
|
+
}
|
|
5658
|
+
}
|
|
5659
|
+
function escapeXml(s) {
|
|
5660
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
5661
|
+
}
|
|
5662
|
+
function buildSessionContext(session, cwd2) {
|
|
5663
|
+
const goal = readFileSafe(goalPath(cwd2, session.id));
|
|
5664
|
+
const roadmap = readFileSafe(roadmapPath(cwd2, session.id));
|
|
5665
|
+
const agentsXml = session.agents.map((agent) => {
|
|
5666
|
+
const reportBlocks = resolveReports(agent.reports);
|
|
5667
|
+
const reportsXml = [...reportBlocks].reverse().map((block) => {
|
|
5668
|
+
return ` <report type="${block.type}" time="${escapeXml(block.timestamp)}">${escapeXml(block.content)}</report>`;
|
|
5669
|
+
}).join("\n");
|
|
5670
|
+
return [
|
|
5671
|
+
` <agent id="${escapeXml(agent.id)}" name="${escapeXml(agent.name)}" type="${escapeXml(agent.agentType)}" status="${escapeXml(agent.status)}">`,
|
|
5672
|
+
` <instruction>${escapeXml(agent.instruction)}</instruction>`,
|
|
5673
|
+
...reportsXml ? [reportsXml] : [],
|
|
5674
|
+
` </agent>`
|
|
5675
|
+
].join("\n");
|
|
5676
|
+
}).join("\n");
|
|
5677
|
+
const cyclesXml = session.orchestratorCycles.map((cycle) => {
|
|
5678
|
+
const agents = cycle.agentsSpawned.join(", ");
|
|
5679
|
+
const mode = cycle.mode ? ` mode="${escapeXml(cycle.mode)}"` : "";
|
|
5680
|
+
return ` <cycle number="${cycle.cycle}"${mode} agents="${escapeXml(agents)}" />`;
|
|
5681
|
+
}).join("\n");
|
|
5682
|
+
const lines = [
|
|
5683
|
+
"<context>",
|
|
5684
|
+
`<session id="${escapeXml(session.id)}" status="${escapeXml(session.status)}">`,
|
|
5685
|
+
` <task>${escapeXml(session.task)}</task>`,
|
|
5686
|
+
` <cwd>${escapeXml(session.cwd)}</cwd>`
|
|
5687
|
+
];
|
|
5688
|
+
if (goal) lines.push(` <goal>${escapeXml(goal)}</goal>`);
|
|
5689
|
+
if (roadmap) lines.push(` <roadmap>${escapeXml(roadmap)}</roadmap>`);
|
|
5690
|
+
if (session.agents.length > 0) {
|
|
5691
|
+
lines.push(" <agents>");
|
|
5692
|
+
lines.push(agentsXml);
|
|
5693
|
+
lines.push(" </agents>");
|
|
5694
|
+
}
|
|
5695
|
+
if (session.orchestratorCycles.length > 0) {
|
|
5696
|
+
lines.push(" <cycles>");
|
|
5697
|
+
lines.push(cyclesXml);
|
|
5698
|
+
lines.push(" </cycles>");
|
|
5699
|
+
}
|
|
5700
|
+
if (session.completionReport) {
|
|
5701
|
+
lines.push(` <completion-report>${escapeXml(session.completionReport)}</completion-report>`);
|
|
5702
|
+
}
|
|
5703
|
+
lines.push("</session>");
|
|
5704
|
+
lines.push("</context>");
|
|
5705
|
+
return lines.join("\n");
|
|
2997
5706
|
}
|
|
2998
5707
|
|
|
2999
5708
|
// src/tui/panels/tree.ts
|
|
3000
|
-
|
|
5709
|
+
init_render();
|
|
5710
|
+
import stringWidth4 from "string-width";
|
|
3001
5711
|
function renderNodeContent(node, maxWidth) {
|
|
3002
5712
|
switch (node.type) {
|
|
3003
5713
|
case "section": {
|
|
@@ -3171,7 +5881,7 @@ function renderTreePanel(buf, rect, nodes, cursorIndex, focused, companion) {
|
|
|
3171
5881
|
let current = "";
|
|
3172
5882
|
let currentWidth = 0;
|
|
3173
5883
|
for (const word of words) {
|
|
3174
|
-
const wordWidth =
|
|
5884
|
+
const wordWidth = stringWidth4(word);
|
|
3175
5885
|
if (currentWidth + wordWidth + 1 > innerW && currentWidth > 0) {
|
|
3176
5886
|
_companionCommentaryLines.push(current);
|
|
3177
5887
|
current = word;
|
|
@@ -3266,8 +5976,16 @@ function renderTreePanel(buf, rect, nodes, cursorIndex, focused, companion) {
|
|
|
3266
5976
|
}
|
|
3267
5977
|
}
|
|
3268
5978
|
|
|
5979
|
+
// src/tui/panels/detail.ts
|
|
5980
|
+
init_render();
|
|
5981
|
+
|
|
5982
|
+
// src/shared/utils.ts
|
|
5983
|
+
function computeActiveTimeMs(session) {
|
|
5984
|
+
return session.activeMs;
|
|
5985
|
+
}
|
|
5986
|
+
|
|
3269
5987
|
// src/tui/panels/cycle-flow.ts
|
|
3270
|
-
import
|
|
5988
|
+
import stringWidth5 from "string-width";
|
|
3271
5989
|
var BG_TINTS = {
|
|
3272
5990
|
yellow: "48;2;40;35;20",
|
|
3273
5991
|
blue: "48;2;20;25;45",
|
|
@@ -3304,7 +6022,7 @@ function getCurrentPhase(session) {
|
|
|
3304
6022
|
return "orchestrator";
|
|
3305
6023
|
}
|
|
3306
6024
|
function padTo(text, w) {
|
|
3307
|
-
const tw =
|
|
6025
|
+
const tw = stringWidth5(text);
|
|
3308
6026
|
if (tw >= w) return truncate(text, w);
|
|
3309
6027
|
return text + " ".repeat(w - tw);
|
|
3310
6028
|
}
|
|
@@ -3327,8 +6045,8 @@ function buildOrchestratorNode(cycle, agents, width, bright, showConnectorBottom
|
|
|
3327
6045
|
rightText = `${dur} ${time}`;
|
|
3328
6046
|
}
|
|
3329
6047
|
const leftContent = `${icon} ${cycleLabel} ${modeLabel}`;
|
|
3330
|
-
const leftW =
|
|
3331
|
-
const rightW =
|
|
6048
|
+
const leftW = stringWidth5(leftContent);
|
|
6049
|
+
const rightW = stringWidth5(rightText);
|
|
3332
6050
|
const gap = Math.max(1, inner - 2 - leftW - rightW);
|
|
3333
6051
|
lines.push([seg("\u256D" + "\u2500".repeat(inner) + "\u256E", { color: "yellow", dim })]);
|
|
3334
6052
|
const contentSegs = [
|
|
@@ -3345,7 +6063,7 @@ function buildOrchestratorNode(cycle, agents, width, bright, showConnectorBottom
|
|
|
3345
6063
|
contentSegs.push(seg(rightText, { bg: bg2, dim }));
|
|
3346
6064
|
}
|
|
3347
6065
|
contentSegs.push(seg(" ", { bg: bg2 }));
|
|
3348
|
-
const usedWidth = 1 + 1 + 1 + 1 +
|
|
6066
|
+
const usedWidth = 1 + 1 + 1 + 1 + stringWidth5(cycleLabel) + 2 + stringWidth5(modeLabel) + gap + stringWidth5(rightText) + 1;
|
|
3349
6067
|
if (usedWidth < inner) {
|
|
3350
6068
|
contentSegs.push(seg(" ".repeat(inner - usedWidth), { bg: bg2 }));
|
|
3351
6069
|
}
|
|
@@ -3506,7 +6224,7 @@ function buildAgentBoxRows(agents, boxWidth, totalWidth, bright, maxPerRow) {
|
|
|
3506
6224
|
const dim = !bright;
|
|
3507
6225
|
const icon = agentStatusIcon(a.status);
|
|
3508
6226
|
const iconColor = statusColor(a.status);
|
|
3509
|
-
const idPadded = padTo(` ${a.id}`, innerW -
|
|
6227
|
+
const idPadded = padTo(` ${a.id}`, innerW - stringWidth5(icon));
|
|
3510
6228
|
line1Segs.push(seg("\u2502", { color: borderColor, dim }));
|
|
3511
6229
|
line1Segs.push(seg(icon, { bg: agentBg, color: iconColor, bold: bright }));
|
|
3512
6230
|
line1Segs.push(seg(idPadded, { bg: agentBg, dim, bold: bright && a.status === "running" }));
|
|
@@ -3642,7 +6360,7 @@ function buildCompleteNode(session, width) {
|
|
|
3642
6360
|
const cycles = session.orchestratorCycles.length;
|
|
3643
6361
|
const leftText = "\u25C9 complete";
|
|
3644
6362
|
const rightText = `${dur} total`;
|
|
3645
|
-
const gap = Math.max(1, inner - 2 -
|
|
6363
|
+
const gap = Math.max(1, inner - 2 - stringWidth5(leftText) - stringWidth5(rightText));
|
|
3646
6364
|
let summaryParts = `${cycles} cycle${cycles !== 1 ? "s" : ""} \xB7 ${totalAgents} agent${totalAgents !== 1 ? "s" : ""}`;
|
|
3647
6365
|
if (totalAgents > 0) {
|
|
3648
6366
|
const parts = [];
|
|
@@ -4558,8 +7276,11 @@ function renderDigestRows(rect, state2) {
|
|
|
4558
7276
|
return buildPanelRows(rect, lines, state2.digestScroll, focused, "cyan", state2.digestRenderedCache);
|
|
4559
7277
|
}
|
|
4560
7278
|
|
|
7279
|
+
// src/tui/panels/stacked-detail.ts
|
|
7280
|
+
init_render();
|
|
7281
|
+
|
|
4561
7282
|
// src/tui/lib/markdown-highlight.ts
|
|
4562
|
-
import
|
|
7283
|
+
import stringWidth6 from "string-width";
|
|
4563
7284
|
|
|
4564
7285
|
// src/tui/lib/gloam.ts
|
|
4565
7286
|
function fg(r, g, b) {
|
|
@@ -4665,7 +7386,7 @@ function tokenizeInline(line, baseFg, baseStyle) {
|
|
|
4665
7386
|
}
|
|
4666
7387
|
function segsDisplayWidth(segs) {
|
|
4667
7388
|
let w = 0;
|
|
4668
|
-
for (const s of segs) w +=
|
|
7389
|
+
for (const s of segs) w += stringWidth6(s.text);
|
|
4669
7390
|
return w;
|
|
4670
7391
|
}
|
|
4671
7392
|
function segsToAtoms(segs) {
|
|
@@ -4678,7 +7399,7 @@ function segsToAtoms(segs) {
|
|
|
4678
7399
|
const piece = m[0];
|
|
4679
7400
|
atoms.push({
|
|
4680
7401
|
text: piece,
|
|
4681
|
-
width:
|
|
7402
|
+
width: stringWidth6(piece),
|
|
4682
7403
|
style,
|
|
4683
7404
|
space: /^\s+$/.test(piece)
|
|
4684
7405
|
});
|
|
@@ -4701,7 +7422,7 @@ function wrapSegs(segs, width, contIndent) {
|
|
|
4701
7422
|
while (current.length > 0) {
|
|
4702
7423
|
const last = current[current.length - 1];
|
|
4703
7424
|
if (/^\s+$/.test(last.text) && !last.bg) {
|
|
4704
|
-
currentWidth -=
|
|
7425
|
+
currentWidth -= stringWidth6(last.text);
|
|
4705
7426
|
current.pop();
|
|
4706
7427
|
} else break;
|
|
4707
7428
|
}
|
|
@@ -4723,14 +7444,14 @@ function wrapSegs(segs, width, contIndent) {
|
|
|
4723
7444
|
flushLine();
|
|
4724
7445
|
if (contIndent) {
|
|
4725
7446
|
current.push({ text: contIndent });
|
|
4726
|
-
currentWidth =
|
|
7447
|
+
currentWidth = stringWidth6(contIndent);
|
|
4727
7448
|
}
|
|
4728
7449
|
continue;
|
|
4729
7450
|
}
|
|
4730
7451
|
let cut = 0;
|
|
4731
7452
|
let cutW = 0;
|
|
4732
7453
|
for (let k = 0; k < remaining.length; k++) {
|
|
4733
|
-
const cw =
|
|
7454
|
+
const cw = stringWidth6(remaining[k]);
|
|
4734
7455
|
if (cutW + cw > spaceLeft) break;
|
|
4735
7456
|
cutW += cw;
|
|
4736
7457
|
cut = k + 1;
|
|
@@ -4739,7 +7460,7 @@ function wrapSegs(segs, width, contIndent) {
|
|
|
4739
7460
|
flushLine();
|
|
4740
7461
|
if (contIndent) {
|
|
4741
7462
|
current.push({ text: contIndent });
|
|
4742
|
-
currentWidth =
|
|
7463
|
+
currentWidth = stringWidth6(contIndent);
|
|
4743
7464
|
}
|
|
4744
7465
|
continue;
|
|
4745
7466
|
}
|
|
@@ -4750,7 +7471,7 @@ function wrapSegs(segs, width, contIndent) {
|
|
|
4750
7471
|
flushLine();
|
|
4751
7472
|
if (contIndent) {
|
|
4752
7473
|
current.push({ text: contIndent });
|
|
4753
|
-
currentWidth =
|
|
7474
|
+
currentWidth = stringWidth6(contIndent);
|
|
4754
7475
|
}
|
|
4755
7476
|
}
|
|
4756
7477
|
}
|
|
@@ -4760,7 +7481,7 @@ function wrapSegs(segs, width, contIndent) {
|
|
|
4760
7481
|
flushLine();
|
|
4761
7482
|
if (contIndent) {
|
|
4762
7483
|
current.push({ text: contIndent });
|
|
4763
|
-
currentWidth =
|
|
7484
|
+
currentWidth = stringWidth6(contIndent);
|
|
4764
7485
|
}
|
|
4765
7486
|
}
|
|
4766
7487
|
pushAtom(atom);
|
|
@@ -4831,7 +7552,7 @@ function buildCodeFenceLine(fence, innerW) {
|
|
|
4831
7552
|
return [
|
|
4832
7553
|
{ text: " ", fg: GLOAM.fg4 },
|
|
4833
7554
|
{
|
|
4834
|
-
text: fence + " ".repeat(Math.max(0, innerW - 2 -
|
|
7555
|
+
text: fence + " ".repeat(Math.max(0, innerW - 2 - stringWidth6(fence))),
|
|
4835
7556
|
fg: GLOAM.fg4,
|
|
4836
7557
|
bg: GLOAM.bg_bg1
|
|
4837
7558
|
}
|
|
@@ -4839,7 +7560,7 @@ function buildCodeFenceLine(fence, innerW) {
|
|
|
4839
7560
|
}
|
|
4840
7561
|
function buildCodeLine(content, innerW) {
|
|
4841
7562
|
const cleaned = stripDisplayHazards(content);
|
|
4842
|
-
const cw =
|
|
7563
|
+
const cw = stringWidth6(cleaned);
|
|
4843
7564
|
const padW = Math.max(0, innerW - 2 - cw);
|
|
4844
7565
|
return [
|
|
4845
7566
|
{ text: " ", bg: GLOAM.bg_bg1 },
|
|
@@ -4888,7 +7609,7 @@ function parseTableSeparator(line) {
|
|
|
4888
7609
|
return aligns;
|
|
4889
7610
|
}
|
|
4890
7611
|
function padCell(text, width, align) {
|
|
4891
|
-
const w =
|
|
7612
|
+
const w = stringWidth6(text);
|
|
4892
7613
|
const pad = Math.max(0, width - w);
|
|
4893
7614
|
let left = 0;
|
|
4894
7615
|
let right = 0;
|
|
@@ -4913,7 +7634,7 @@ function wrapCell(text, width, align) {
|
|
|
4913
7634
|
};
|
|
4914
7635
|
for (const piece of cleaned.match(/\s+|\S+/g) ?? []) {
|
|
4915
7636
|
const isSpace = /^\s+$/.test(piece);
|
|
4916
|
-
const pw =
|
|
7637
|
+
const pw = stringWidth6(piece);
|
|
4917
7638
|
if (isSpace) {
|
|
4918
7639
|
if (curW === 0) continue;
|
|
4919
7640
|
if (curW + pw > width) flush();
|
|
@@ -4935,7 +7656,7 @@ function wrapCell(text, width, align) {
|
|
|
4935
7656
|
let cut = 0;
|
|
4936
7657
|
let cutW = 0;
|
|
4937
7658
|
for (let k = 0; k < rem.length; k++) {
|
|
4938
|
-
const cw =
|
|
7659
|
+
const cw = stringWidth6(rem[k]);
|
|
4939
7660
|
if (cutW + cw > width) break;
|
|
4940
7661
|
cutW += cw;
|
|
4941
7662
|
cut = k + 1;
|
|
@@ -4944,7 +7665,7 @@ function wrapCell(text, width, align) {
|
|
|
4944
7665
|
const slice = rem.slice(0, cut);
|
|
4945
7666
|
if (cut === rem.length) {
|
|
4946
7667
|
cur = slice;
|
|
4947
|
-
curW =
|
|
7668
|
+
curW = stringWidth6(slice);
|
|
4948
7669
|
} else {
|
|
4949
7670
|
out.push(padCell(slice, width, align));
|
|
4950
7671
|
}
|
|
@@ -4977,7 +7698,7 @@ function buildTableLines(headers, alignsIn, rowsIn, innerW) {
|
|
|
4977
7698
|
const naturalW = new Array(ncols).fill(0);
|
|
4978
7699
|
const measure = (cells) => {
|
|
4979
7700
|
for (let i = 0; i < ncols; i++) {
|
|
4980
|
-
const w =
|
|
7701
|
+
const w = stringWidth6(cleanMarkdown(cells[i]));
|
|
4981
7702
|
if (w > naturalW[i]) naturalW[i] = w;
|
|
4982
7703
|
}
|
|
4983
7704
|
};
|
|
@@ -5348,6 +8069,7 @@ function renderCycleLogMode(rect, state2, focused) {
|
|
|
5348
8069
|
}
|
|
5349
8070
|
|
|
5350
8071
|
// src/tui/panels/bottom.ts
|
|
8072
|
+
init_render();
|
|
5351
8073
|
var B = ansiBold;
|
|
5352
8074
|
var D = ansiDim;
|
|
5353
8075
|
var SEP = D("\u2502 ");
|
|
@@ -5392,6 +8114,7 @@ function renderStatusLine(buf, y, state2, cursorNodeType) {
|
|
|
5392
8114
|
}
|
|
5393
8115
|
|
|
5394
8116
|
// src/tui/panels/cross-session-inbox.ts
|
|
8117
|
+
init_render();
|
|
5395
8118
|
var KIND_ICON = {
|
|
5396
8119
|
notify: "\u2709",
|
|
5397
8120
|
validation: "\u2713",
|
|
@@ -5456,38 +8179,42 @@ function renderCrossSessionInboxRows(rect, state2) {
|
|
|
5456
8179
|
return buildPanelRows(rect, lines, state2.crossSessionInboxScroll, focused, "red", state2.inboxRenderedCache);
|
|
5457
8180
|
}
|
|
5458
8181
|
|
|
8182
|
+
// src/tui/app.ts
|
|
8183
|
+
init_paths();
|
|
8184
|
+
|
|
5459
8185
|
// src/tui/lib/popup-compose.ts
|
|
5460
|
-
|
|
5461
|
-
import {
|
|
5462
|
-
import {
|
|
5463
|
-
import {
|
|
8186
|
+
init_shell();
|
|
8187
|
+
import { execSync as execSync5 } from "child_process";
|
|
8188
|
+
import { mkdtempSync as mkdtempSync2, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10, readFileSync as readFileSync14, rmSync as rmSync5, existsSync as existsSync9, cpSync as cpSync3 } from "fs";
|
|
8189
|
+
import { join as join13 } from "path";
|
|
8190
|
+
import { tmpdir as tmpdir2, homedir as homedir4 } from "os";
|
|
5464
8191
|
var initLuaEnsured = false;
|
|
5465
8192
|
function ensureSisyphusInitLua() {
|
|
5466
8193
|
if (initLuaEnsured) return;
|
|
5467
8194
|
initLuaEnsured = true;
|
|
5468
8195
|
try {
|
|
5469
|
-
const destDir =
|
|
5470
|
-
const destPath =
|
|
5471
|
-
if (
|
|
5472
|
-
|
|
5473
|
-
const srcPath =
|
|
5474
|
-
|
|
8196
|
+
const destDir = join13(homedir4(), ".config", "sisyphus");
|
|
8197
|
+
const destPath = join13(destDir, "init.lua");
|
|
8198
|
+
if (existsSync9(destPath)) return;
|
|
8199
|
+
mkdirSync9(destDir, { recursive: true });
|
|
8200
|
+
const srcPath = join13(import.meta.dirname, "templates", "sisyphus-init.lua");
|
|
8201
|
+
cpSync3(srcPath, destPath);
|
|
5475
8202
|
} catch {
|
|
5476
8203
|
}
|
|
5477
8204
|
}
|
|
5478
8205
|
function composeViaPopup(action, state2, actions) {
|
|
5479
|
-
const tmpDir = mkdtempSync2(
|
|
5480
|
-
const tempFile =
|
|
8206
|
+
const tmpDir = mkdtempSync2(join13(tmpdir2(), "sisyphus-popup-"));
|
|
8207
|
+
const tempFile = join13(tmpDir, "compose.md");
|
|
5481
8208
|
try {
|
|
5482
|
-
|
|
8209
|
+
writeFileSync10(tempFile, "", "utf-8");
|
|
5483
8210
|
const cmd = `NVIM_APPNAME=sisyphus nvim ${shellQuote(tempFile)}`;
|
|
5484
|
-
|
|
8211
|
+
execSync5(
|
|
5485
8212
|
`tmux display-popup -E -w 90% -h 90% -d ${shellQuote(state2.cwd)} ${shellQuote(cmd)}`,
|
|
5486
8213
|
{ stdio: "inherit", env: EXEC_ENV }
|
|
5487
8214
|
);
|
|
5488
8215
|
let rawContent = "";
|
|
5489
8216
|
try {
|
|
5490
|
-
rawContent =
|
|
8217
|
+
rawContent = readFileSync14(tempFile, "utf-8");
|
|
5491
8218
|
} catch {
|
|
5492
8219
|
}
|
|
5493
8220
|
const required = !OPTIONAL_COMPOSE.has(action.kind);
|
|
@@ -5498,19 +8225,21 @@ function composeViaPopup(action, state2, actions) {
|
|
|
5498
8225
|
} catch (err) {
|
|
5499
8226
|
notify(state2, `Failed to open compose popup: ${err.message}`);
|
|
5500
8227
|
} finally {
|
|
5501
|
-
|
|
8228
|
+
rmSync5(tmpDir, { recursive: true, force: true });
|
|
5502
8229
|
}
|
|
5503
8230
|
}
|
|
5504
8231
|
|
|
5505
8232
|
// src/tui/app.ts
|
|
8233
|
+
init_config();
|
|
8234
|
+
init_paths();
|
|
5506
8235
|
var _cachedCompanion = null;
|
|
5507
8236
|
var _companionMtime = 0;
|
|
5508
8237
|
function getCompanion() {
|
|
5509
8238
|
try {
|
|
5510
|
-
const { mtimeMs } =
|
|
8239
|
+
const { mtimeMs } = statSync4(companionPath());
|
|
5511
8240
|
if (_cachedCompanion && mtimeMs === _companionMtime) return _cachedCompanion;
|
|
5512
8241
|
_companionMtime = mtimeMs;
|
|
5513
|
-
_cachedCompanion = JSON.parse(
|
|
8242
|
+
_cachedCompanion = normalizeCompanion(JSON.parse(readFileSync15(companionPath(), "utf-8")));
|
|
5514
8243
|
return _cachedCompanion;
|
|
5515
8244
|
} catch {
|
|
5516
8245
|
return _cachedCompanion;
|
|
@@ -5637,52 +8366,52 @@ function startApp(state2, cleanup2) {
|
|
|
5637
8366
|
}
|
|
5638
8367
|
try {
|
|
5639
8368
|
const pp = roadmapPath(state2.cwd, state2.selectedSessionId);
|
|
5640
|
-
if (
|
|
5641
|
-
planContent =
|
|
8369
|
+
if (existsSync10(pp)) {
|
|
8370
|
+
planContent = readFileSync15(pp, "utf-8");
|
|
5642
8371
|
}
|
|
5643
8372
|
} catch {
|
|
5644
8373
|
}
|
|
5645
8374
|
try {
|
|
5646
8375
|
const gp = goalPath(state2.cwd, state2.selectedSessionId);
|
|
5647
|
-
if (
|
|
5648
|
-
goalContent =
|
|
8376
|
+
if (existsSync10(gp)) {
|
|
8377
|
+
goalContent = readFileSync15(gp, "utf-8");
|
|
5649
8378
|
}
|
|
5650
8379
|
} catch {
|
|
5651
8380
|
}
|
|
5652
8381
|
try {
|
|
5653
8382
|
const sp = strategyPath(state2.cwd, state2.selectedSessionId);
|
|
5654
|
-
if (
|
|
5655
|
-
strategyContent =
|
|
8383
|
+
if (existsSync10(sp)) {
|
|
8384
|
+
strategyContent = readFileSync15(sp, "utf-8");
|
|
5656
8385
|
}
|
|
5657
8386
|
} catch {
|
|
5658
8387
|
}
|
|
5659
8388
|
try {
|
|
5660
|
-
const cp =
|
|
5661
|
-
if (
|
|
5662
|
-
completionSummaryContent =
|
|
8389
|
+
const cp = join14(contextDir(state2.cwd, state2.selectedSessionId), "completion-summary.md");
|
|
8390
|
+
if (existsSync10(cp)) {
|
|
8391
|
+
completionSummaryContent = readFileSync15(cp, "utf-8");
|
|
5663
8392
|
}
|
|
5664
8393
|
} catch {
|
|
5665
8394
|
}
|
|
5666
8395
|
try {
|
|
5667
8396
|
const ld = logsDir(state2.cwd, state2.selectedSessionId);
|
|
5668
|
-
if (
|
|
8397
|
+
if (existsSync10(ld)) {
|
|
5669
8398
|
if (state2.selectedSessionId !== cachedLogSessionId) {
|
|
5670
8399
|
cachedLogFiles = /* @__PURE__ */ new Map();
|
|
5671
8400
|
cachedLogSessionId = state2.selectedSessionId;
|
|
5672
8401
|
}
|
|
5673
|
-
const files =
|
|
8402
|
+
const files = readdirSync7(ld).filter((f) => f.startsWith("cycle-")).sort();
|
|
5674
8403
|
const fileSet = new Set(files);
|
|
5675
8404
|
for (const key of cachedLogFiles.keys()) {
|
|
5676
8405
|
if (!fileSet.has(key)) cachedLogFiles.delete(key);
|
|
5677
8406
|
}
|
|
5678
8407
|
for (const f of files) {
|
|
5679
|
-
const filePath =
|
|
5680
|
-
const mtime =
|
|
8408
|
+
const filePath = join14(ld, f);
|
|
8409
|
+
const mtime = statSync4(filePath).mtimeMs;
|
|
5681
8410
|
const cached = cachedLogFiles.get(f);
|
|
5682
8411
|
if (!cached || cached.mtime !== mtime) {
|
|
5683
8412
|
const match = f.match(/cycle-(\d+)\.md$/);
|
|
5684
8413
|
const cycle = match ? parseInt(match[1], 10) : 0;
|
|
5685
|
-
const content =
|
|
8414
|
+
const content = readFileSync15(filePath, "utf-8");
|
|
5686
8415
|
cachedLogFiles.set(f, { mtime, cycle, content });
|
|
5687
8416
|
}
|
|
5688
8417
|
}
|
|
@@ -5696,13 +8425,13 @@ function startApp(state2, cleanup2) {
|
|
|
5696
8425
|
}
|
|
5697
8426
|
try {
|
|
5698
8427
|
const cd = contextDir(state2.cwd, state2.selectedSessionId);
|
|
5699
|
-
if (
|
|
5700
|
-
const entries =
|
|
8428
|
+
if (existsSync10(cd)) {
|
|
8429
|
+
const entries = readdirSync7(cd, { withFileTypes: true }).filter((e) => !e.name.startsWith("."));
|
|
5701
8430
|
const flat = [];
|
|
5702
8431
|
for (const e of entries) {
|
|
5703
8432
|
if (e.isDirectory()) {
|
|
5704
8433
|
try {
|
|
5705
|
-
const sub =
|
|
8434
|
+
const sub = readdirSync7(join14(cd, e.name)).filter((f) => !f.startsWith(".")).map((f) => `${e.name}/${f}`);
|
|
5706
8435
|
flat.push(...sub);
|
|
5707
8436
|
} catch {
|
|
5708
8437
|
}
|
|
@@ -5716,8 +8445,8 @@ function startApp(state2, cleanup2) {
|
|
|
5716
8445
|
}
|
|
5717
8446
|
try {
|
|
5718
8447
|
const dp = digestPath(state2.cwd, state2.selectedSessionId);
|
|
5719
|
-
if (
|
|
5720
|
-
const raw = JSON.parse(
|
|
8448
|
+
if (existsSync10(dp)) {
|
|
8449
|
+
const raw = JSON.parse(readFileSync15(dp, "utf-8"));
|
|
5721
8450
|
if (raw && typeof raw.recentWork === "string" && typeof raw.currentActivity === "string" && typeof raw.whatsNext === "string" && Array.isArray(raw.unusualEvents)) {
|
|
5722
8451
|
digestData = raw;
|
|
5723
8452
|
}
|
|
@@ -5860,8 +8589,8 @@ function startApp(state2, cleanup2) {
|
|
|
5860
8589
|
if (cursorNode.filePath !== cachedContextFilePath) {
|
|
5861
8590
|
cachedContextFilePath = cursorNode.filePath;
|
|
5862
8591
|
try {
|
|
5863
|
-
if (
|
|
5864
|
-
cachedContextFileContent =
|
|
8592
|
+
if (existsSync10(cursorNode.filePath)) {
|
|
8593
|
+
cachedContextFileContent = readFileSync15(cursorNode.filePath, "utf-8");
|
|
5865
8594
|
} else {
|
|
5866
8595
|
cachedContextFileContent = null;
|
|
5867
8596
|
}
|
|
@@ -5877,7 +8606,7 @@ function startApp(state2, cleanup2) {
|
|
|
5877
8606
|
const treeFocused = state2.mode === "navigate" && state2.focusPane === "tree";
|
|
5878
8607
|
const treeInputs = `${state2.treeCacheKey}:${state2.cursorIndex}:${treeFocused}`;
|
|
5879
8608
|
const bottomInputs = `${state2.notification}:${state2.error}:${state2.mode}:${state2.searchText}:${cursorNode?.type}`;
|
|
5880
|
-
const overlayMode = state2.mode === "leader" || state2.mode === "copy-menu" || state2.mode === "open-menu" || state2.mode === "agent-menu" || state2.mode === "session-menu" || state2.mode === "go-menu" || state2.mode === "help" || state2.mode === "companion-overlay" || state2.mode === "companion-debug" ? state2.mode : "";
|
|
8609
|
+
const overlayMode = state2.mode === "leader" || state2.mode === "copy-menu" || state2.mode === "open-menu" || state2.mode === "agent-menu" || state2.mode === "session-menu" || state2.mode === "go-menu" || state2.mode === "companion-menu" || state2.mode === "help" || state2.mode === "companion-overlay" || state2.mode === "companion-debug" ? state2.mode : "";
|
|
5881
8610
|
let companionFP = "";
|
|
5882
8611
|
if (state2.mode === "companion-overlay" || state2.mode === "companion-debug") {
|
|
5883
8612
|
const c = getCompanion();
|
|
@@ -5947,7 +8676,8 @@ function startApp(state2, cleanup2) {
|
|
|
5947
8676
|
open: "green",
|
|
5948
8677
|
agent: "blue",
|
|
5949
8678
|
session: "red",
|
|
5950
|
-
go: "yellow"
|
|
8679
|
+
go: "yellow",
|
|
8680
|
+
companion: "magenta"
|
|
5951
8681
|
};
|
|
5952
8682
|
const menuId = MENU_FOR_MODE[state2.mode];
|
|
5953
8683
|
if (menuId) {
|
|
@@ -6063,8 +8793,8 @@ var cwd = getArg("cwd") ?? process.cwd();
|
|
|
6063
8793
|
var askId = getArg("ask");
|
|
6064
8794
|
var sessionId = getArg("session-id");
|
|
6065
8795
|
if (askId && sessionId) {
|
|
6066
|
-
const { runSingleAsk } = await
|
|
6067
|
-
await
|
|
8796
|
+
const { runSingleAsk: runSingleAsk2 } = await Promise.resolve().then(() => (init_single_ask(), single_ask_exports));
|
|
8797
|
+
await runSingleAsk2({ cwd, sessionId, askId });
|
|
6068
8798
|
process.exit(0);
|
|
6069
8799
|
}
|
|
6070
8800
|
registerDashboardWindow();
|