@dadado/agent-kit-cli 6.3.0 → 6.5.0
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/dashboard/dashboard-data.mjs +14 -2
- package/dashboard/dashboard.html +190 -32
- package/dashboard/lib/chat-sessions.d.mts +63 -0
- package/dashboard/lib/chat-sessions.mjs +430 -0
- package/dashboard/{logo-cursor.svg → logo-bare-metal.svg} +1 -1
- package/dashboard/logo-marketplace.svg +1 -1
- package/dashboard/serve.mjs +5 -1
- package/dashboard/social-preview.svg +2 -2
- package/dist/{add-VA2W7I6P.js → add-IT6XFPKT.js} +2 -2
- package/dist/{chunk-NNKOWUWM.js → chunk-236IYK6L.js} +64 -28
- package/dist/{chunk-YRFSTHR5.js → chunk-2OIPMQHA.js} +13 -219
- package/dist/{chunk-JEI6HACW.js → chunk-2TCRKQHD.js} +35 -379
- package/dist/{chunk-U26MRIWN.js → chunk-34BBPQKI.js} +1 -1
- package/dist/{chunk-GUQYNUV4.js → chunk-4XZXM2ZA.js} +1 -1
- package/dist/{chunk-Z7RYIHHX.js → chunk-5LQP4JGH.js} +3 -3
- package/dist/{chunk-6KUSG7BJ.js → chunk-5WSFO35Y.js} +4 -1
- package/dist/{chunk-MAPOQEA2.js → chunk-6RRG3WOE.js} +8 -1
- package/dist/{chunk-OWWFKGKS.js → chunk-EI3VQ7FU.js} +2 -2
- package/dist/{chunk-QTBTKEXK.js → chunk-FM32XR7A.js} +1 -1
- package/dist/{chunk-KVY425NM.js → chunk-GIZNM73K.js} +4 -2
- package/dist/{chunk-MO63KZBP.js → chunk-HKYJG2FJ.js} +8 -6
- package/dist/{chunk-SV2BR2LZ.js → chunk-I2D75F4I.js} +7 -7
- package/dist/{chunk-25J2SMJQ.js → chunk-IN4MQ3P3.js} +1 -1
- package/dist/{chunk-OVOXRH5W.js → chunk-MEZUW3LL.js} +1 -1
- package/dist/chunk-MTLQN57O.js +380 -0
- package/dist/chunk-R6WH5P7R.js +223 -0
- package/dist/{chunk-VQBI3JVS.js → chunk-TNO7GTAJ.js} +2 -2
- package/dist/{chunk-Z7ABX5QI.js → chunk-U7XOLYDG.js} +4 -2
- package/dist/{chunk-WMVMBPCR.js → chunk-WOGBBJCX.js} +1 -1
- package/dist/{chunk-6GYKOHIL.js → chunk-YIOTJQHL.js} +2 -2
- package/dist/{contribute-NLM2BN6Z.js → contribute-V7PV5UMK.js} +3 -3
- package/dist/{countdown-QXJD6TDB.js → countdown-YONBTSJ2.js} +10 -8
- package/dist/{diff-HHG4JEDE.js → diff-GWIHGH65.js} +4 -4
- package/dist/{doctor-TWF2M3S3.js → doctor-FLIQCVFN.js} +8 -8
- package/dist/engine-info-UQNVNOA2.js +89 -0
- package/dist/{ground-control-NMYYIVCV.js → ground-control-6W2AKTKI.js} +5 -4
- package/dist/{guard-EHXF76ID.js → guard-ZZRQW3DJ.js} +107 -8
- package/dist/{hook-VP7FHRSZ.js → hook-2SX2V2T6.js} +10 -4
- package/dist/index.js +26 -22
- package/dist/{init-UOTV4ASJ.js → init-4B2IRH27.js} +11 -11
- package/dist/{install-VCHPXQV3.js → install-3JVTG35O.js} +11 -11
- package/dist/{run-R66G276Q.js → run-AYT6CRHI.js} +12 -9
- package/dist/{run-plan-24Z5K4P3.js → run-plan-5XIISG3W.js} +11 -7
- package/dist/sessions-O7MYEMCT.js +343 -0
- package/dist/{setup-global-M6LKGJHQ.js → setup-global-6JM5XTAT.js} +5 -5
- package/dist/{status-5UKVIKOI.js → status-PMAI7NH3.js} +6 -6
- package/dist/{update-VQBGEUWS.js → update-3PLY4FZA.js} +9 -9
- package/package.json +1 -1
|
@@ -2,21 +2,22 @@ import {
|
|
|
2
2
|
runPlanLoop,
|
|
3
3
|
shouldUseLiveTui,
|
|
4
4
|
withLiveTui
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2OIPMQHA.js";
|
|
6
|
+
import "./chunk-R6WH5P7R.js";
|
|
6
7
|
import {
|
|
7
8
|
REVIEW_PACK_SLASH,
|
|
8
9
|
runReviewJob
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-HKYJG2FJ.js";
|
|
10
11
|
import {
|
|
11
12
|
detectAgentBackend,
|
|
12
13
|
listDetectBackendIds
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-4XZXM2ZA.js";
|
|
15
|
+
import "./chunk-FM32XR7A.js";
|
|
15
16
|
import {
|
|
16
17
|
LAND_ON_GATE_DESCRIPTION,
|
|
17
18
|
classifyGateExit,
|
|
18
19
|
landGateExit
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-GIZNM73K.js";
|
|
20
21
|
import "./chunk-3LLXDHIU.js";
|
|
21
22
|
import {
|
|
22
23
|
negatedFlag
|
|
@@ -32,15 +33,17 @@ import {
|
|
|
32
33
|
readCommandFile,
|
|
33
34
|
runHeadlessDispatch,
|
|
34
35
|
unknownSlashMessage
|
|
35
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-U7XOLYDG.js";
|
|
37
|
+
import {
|
|
38
|
+
getBackend
|
|
39
|
+
} from "./chunk-2TCRKQHD.js";
|
|
36
40
|
import {
|
|
37
41
|
HITL_UNANSWERED_EXIT_CODE,
|
|
38
42
|
formatHitlSummary,
|
|
39
|
-
getBackend,
|
|
40
43
|
hitlExitCode
|
|
41
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-MTLQN57O.js";
|
|
42
45
|
import "./chunk-WGLPZXNU.js";
|
|
43
|
-
import "./chunk-
|
|
46
|
+
import "./chunk-6RRG3WOE.js";
|
|
44
47
|
import "./chunk-QTON2GQX.js";
|
|
45
48
|
import {
|
|
46
49
|
logger
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
DRIVER_EVENTS_FORMATS,
|
|
3
2
|
runPlanLoop
|
|
4
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2OIPMQHA.js";
|
|
4
|
+
import {
|
|
5
|
+
DRIVER_EVENTS_FORMATS
|
|
6
|
+
} from "./chunk-R6WH5P7R.js";
|
|
5
7
|
import {
|
|
6
8
|
detectAgentBackend,
|
|
7
9
|
listDetectBackendIds
|
|
8
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-4XZXM2ZA.js";
|
|
9
11
|
import {
|
|
10
12
|
LAND_ON_GATE_DESCRIPTION
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-GIZNM73K.js";
|
|
12
14
|
import "./chunk-3LLXDHIU.js";
|
|
13
15
|
import {
|
|
14
16
|
negatedFlag
|
|
@@ -16,11 +18,13 @@ import {
|
|
|
16
18
|
import "./chunk-L5V3W3DY.js";
|
|
17
19
|
import "./chunk-MUTTNRX4.js";
|
|
18
20
|
import {
|
|
19
|
-
HITL_UNANSWERED_EXIT_CODE,
|
|
20
21
|
getBackend
|
|
21
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-2TCRKQHD.js";
|
|
23
|
+
import {
|
|
24
|
+
HITL_UNANSWERED_EXIT_CODE
|
|
25
|
+
} from "./chunk-MTLQN57O.js";
|
|
22
26
|
import "./chunk-WGLPZXNU.js";
|
|
23
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-6RRG3WOE.js";
|
|
24
28
|
import "./chunk-QTON2GQX.js";
|
|
25
29
|
import {
|
|
26
30
|
logger
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// src/commands/sessions.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
|
|
5
|
+
// ../../dashboard/lib/chat-sessions.mjs
|
|
6
|
+
import {
|
|
7
|
+
closeSync,
|
|
8
|
+
existsSync,
|
|
9
|
+
fstatSync,
|
|
10
|
+
openSync,
|
|
11
|
+
readdirSync,
|
|
12
|
+
readSync,
|
|
13
|
+
realpathSync,
|
|
14
|
+
statSync
|
|
15
|
+
} from "fs";
|
|
16
|
+
import { join } from "path";
|
|
17
|
+
var CHAT_SESSIONS_CAP = 200;
|
|
18
|
+
var CHAT_TITLE_MAX = 80;
|
|
19
|
+
var CHAT_NAMED_TITLE_MAX = 200;
|
|
20
|
+
var CHAT_FULL_SCAN_MAX_BYTES = 64 * 1024 * 1024;
|
|
21
|
+
var CHAT_HEAD_BYTES = 2 * 1024 * 1024;
|
|
22
|
+
var CHAT_TAIL_BYTES = 8 * 1024 * 1024;
|
|
23
|
+
var CHAT_SCAN_BUDGET_BYTES = 256 * 1024 * 1024;
|
|
24
|
+
var BUDGET_HEAD_BYTES = 256 * 1024;
|
|
25
|
+
var BUDGET_TAIL_BYTES = 1024 * 1024;
|
|
26
|
+
var CHAT_VENDORS = Object.freeze(["claude", "codex", "cursor"]);
|
|
27
|
+
var SESSION_FILE_RE = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
|
|
28
|
+
var SLUG_MAX = 200;
|
|
29
|
+
var READ_CHUNK = 1024 * 1024;
|
|
30
|
+
var NEWLINE = 10;
|
|
31
|
+
var MARK_CUSTOM = Buffer.from('"type":"custom-title"');
|
|
32
|
+
var MARK_AI = Buffer.from('"type":"ai-title"');
|
|
33
|
+
var MARK_USER = Buffer.from('"type":"user"');
|
|
34
|
+
var NON_PROMPT_PREFIXES = [
|
|
35
|
+
"<command-name>",
|
|
36
|
+
"<command-message>",
|
|
37
|
+
"<command-args>",
|
|
38
|
+
"<local-command-",
|
|
39
|
+
"<bash-input>",
|
|
40
|
+
"<bash-stdout>",
|
|
41
|
+
"<bash-stderr>",
|
|
42
|
+
"<system-reminder>",
|
|
43
|
+
"<task-notification>",
|
|
44
|
+
"Caveat:",
|
|
45
|
+
"[Request interrupted"
|
|
46
|
+
];
|
|
47
|
+
function slugHash(value) {
|
|
48
|
+
let h = 0;
|
|
49
|
+
for (let i = 0; i < value.length; i++) h = (h << 5) - h + value.charCodeAt(i) | 0;
|
|
50
|
+
return h;
|
|
51
|
+
}
|
|
52
|
+
function claudeProjectSlug(cwd) {
|
|
53
|
+
const raw = String(cwd ?? "");
|
|
54
|
+
const slug = raw.replace(/[^a-zA-Z0-9]/g, "-");
|
|
55
|
+
if (slug.length <= SLUG_MAX) return slug;
|
|
56
|
+
return `${slug.slice(0, SLUG_MAX)}-${Math.abs(slugHash(raw)).toString(36)}`;
|
|
57
|
+
}
|
|
58
|
+
function claudeProjectDir(cwd, opts = {}) {
|
|
59
|
+
const home = opts.home === void 0 ? process.env.HOME : opts.home;
|
|
60
|
+
if (typeof home !== "string" || !home.trim() || !home.startsWith("/")) return null;
|
|
61
|
+
return join(home, ".claude", "projects", claudeProjectSlug(cwd));
|
|
62
|
+
}
|
|
63
|
+
function cleanChatTitle(value, max = CHAT_TITLE_MAX) {
|
|
64
|
+
const text = String(value ?? "").replace(/[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, " ").replace(/\s+/g, " ").trim();
|
|
65
|
+
const chars = [...text];
|
|
66
|
+
if (chars.length <= max) return text;
|
|
67
|
+
return `${chars.slice(0, max - 1).join("").trimEnd()}\u2026`;
|
|
68
|
+
}
|
|
69
|
+
function promptText(record) {
|
|
70
|
+
if (record?.type !== "user" || record.isMeta === true || record.isSidechain === true) {
|
|
71
|
+
return "";
|
|
72
|
+
}
|
|
73
|
+
const content = record.message?.content;
|
|
74
|
+
let text = "";
|
|
75
|
+
if (typeof content === "string") {
|
|
76
|
+
text = content;
|
|
77
|
+
} else if (Array.isArray(content)) {
|
|
78
|
+
if (content.some((part) => part && part.type === "tool_result")) return "";
|
|
79
|
+
text = content.filter((part) => part && part.type === "text" && typeof part.text === "string").map((part) => part.text).join(" ");
|
|
80
|
+
}
|
|
81
|
+
const trimmed = text.trim();
|
|
82
|
+
if (!trimmed) return "";
|
|
83
|
+
if (NON_PROMPT_PREFIXES.some((prefix) => trimmed.startsWith(prefix))) return "";
|
|
84
|
+
return trimmed;
|
|
85
|
+
}
|
|
86
|
+
function parseRecord(line) {
|
|
87
|
+
try {
|
|
88
|
+
const value = JSON.parse(line.toString("utf8"));
|
|
89
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
90
|
+
} catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function forEachLine(fd, start, end, onLine) {
|
|
95
|
+
const buf = Buffer.allocUnsafe(READ_CHUNK);
|
|
96
|
+
let pending = [];
|
|
97
|
+
let skipFirst = start > 0;
|
|
98
|
+
let pos = start;
|
|
99
|
+
while (pos < end) {
|
|
100
|
+
const n = readSync(fd, buf, 0, Math.min(READ_CHUNK, end - pos), pos);
|
|
101
|
+
if (n <= 0) break;
|
|
102
|
+
pos += n;
|
|
103
|
+
let from = 0;
|
|
104
|
+
for (; ; ) {
|
|
105
|
+
const nl = buf.indexOf(NEWLINE, from);
|
|
106
|
+
if (nl === -1 || nl >= n) {
|
|
107
|
+
if (from < n) pending.push(Buffer.from(buf.subarray(from, n)));
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
const piece = buf.subarray(from, nl);
|
|
111
|
+
const line = pending.length ? Buffer.concat([...pending, piece]) : piece;
|
|
112
|
+
pending = [];
|
|
113
|
+
from = nl + 1;
|
|
114
|
+
if (skipFirst) {
|
|
115
|
+
skipFirst = false;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
onLine(line);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (pending.length && !skipFirst) onLine(Buffer.concat(pending));
|
|
122
|
+
}
|
|
123
|
+
function readChatTitle(filePath, window = {}) {
|
|
124
|
+
const fullScanMax = window.fullScanMaxBytes ?? CHAT_FULL_SCAN_MAX_BYTES;
|
|
125
|
+
const headBytes = window.headBytes ?? CHAT_HEAD_BYTES;
|
|
126
|
+
const tailBytes = window.tailBytes ?? CHAT_TAIL_BYTES;
|
|
127
|
+
let custom = "";
|
|
128
|
+
let ai = "";
|
|
129
|
+
let prompt = "";
|
|
130
|
+
let fd;
|
|
131
|
+
try {
|
|
132
|
+
fd = openSync(filePath, "r");
|
|
133
|
+
} catch {
|
|
134
|
+
return { title: null, titleSource: "none" };
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
const size = fstatSync(fd).size;
|
|
138
|
+
const visit = (line) => {
|
|
139
|
+
if (line.indexOf(MARK_CUSTOM) !== -1) {
|
|
140
|
+
const rec = parseRecord(line);
|
|
141
|
+
if (rec?.type === "custom-title" && typeof rec.customTitle === "string") {
|
|
142
|
+
const t = cleanChatTitle(rec.customTitle, CHAT_NAMED_TITLE_MAX);
|
|
143
|
+
if (t) custom = t;
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (line.indexOf(MARK_AI) !== -1) {
|
|
148
|
+
const rec = parseRecord(line);
|
|
149
|
+
if (rec?.type === "ai-title" && typeof rec.aiTitle === "string") {
|
|
150
|
+
const t = cleanChatTitle(rec.aiTitle, CHAT_NAMED_TITLE_MAX);
|
|
151
|
+
if (t) ai = t;
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (!prompt && line.indexOf(MARK_USER) !== -1) {
|
|
156
|
+
prompt = cleanChatTitle(promptText(parseRecord(line)));
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
if (size <= fullScanMax || size <= headBytes + tailBytes) {
|
|
160
|
+
forEachLine(fd, 0, size, visit);
|
|
161
|
+
} else {
|
|
162
|
+
forEachLine(fd, 0, headBytes, visit);
|
|
163
|
+
forEachLine(fd, size - tailBytes, size, visit);
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
} finally {
|
|
167
|
+
closeSync(fd);
|
|
168
|
+
}
|
|
169
|
+
if (custom) return { title: custom, titleSource: "custom" };
|
|
170
|
+
if (ai) return { title: ai, titleSource: "ai" };
|
|
171
|
+
if (prompt) return { title: prompt, titleSource: "first-prompt" };
|
|
172
|
+
return { title: null, titleSource: "none" };
|
|
173
|
+
}
|
|
174
|
+
var defaultTitleCache = /* @__PURE__ */ new Map();
|
|
175
|
+
function envelope(vendor, status, projectDir, sessions = [], total = 0) {
|
|
176
|
+
return { vendor, status, projectDir, sessions, total };
|
|
177
|
+
}
|
|
178
|
+
function claudeProjectDirCandidates(cwd, home) {
|
|
179
|
+
const out = [];
|
|
180
|
+
const first = claudeProjectDir(cwd, { home });
|
|
181
|
+
if (!first) return out;
|
|
182
|
+
out.push(first);
|
|
183
|
+
try {
|
|
184
|
+
const real = realpathSync(cwd);
|
|
185
|
+
const second = claudeProjectDir(real, { home });
|
|
186
|
+
if (second && second !== first) out.push(second);
|
|
187
|
+
} catch {
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
function listClaudeSessions(opts) {
|
|
192
|
+
const cap = Number.isInteger(opts?.cap) && opts.cap >= 0 ? opts.cap : CHAT_SESSIONS_CAP;
|
|
193
|
+
const cache = opts?.cache ?? defaultTitleCache;
|
|
194
|
+
const candidates = claudeProjectDirCandidates(String(opts?.cwd ?? ""), opts?.home);
|
|
195
|
+
if (candidates.length === 0) return envelope("claude", "none", null);
|
|
196
|
+
const projectDir = candidates.find((dir) => existsSync(dir)) ?? candidates[0];
|
|
197
|
+
let entries;
|
|
198
|
+
try {
|
|
199
|
+
entries = readdirSync(projectDir, { withFileTypes: true });
|
|
200
|
+
} catch {
|
|
201
|
+
return envelope("claude", "none", projectDir);
|
|
202
|
+
}
|
|
203
|
+
const found = [];
|
|
204
|
+
for (const entry of entries) {
|
|
205
|
+
if (!entry.isFile()) continue;
|
|
206
|
+
const m = SESSION_FILE_RE.exec(entry.name);
|
|
207
|
+
if (!m) continue;
|
|
208
|
+
const path2 = join(projectDir, entry.name);
|
|
209
|
+
try {
|
|
210
|
+
const st = statSync(path2);
|
|
211
|
+
found.push({ id: m[1], path: path2, mtimeMs: st.mtimeMs, size: st.size });
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (found.length === 0) return envelope("claude", "none", projectDir);
|
|
216
|
+
found.sort((a, b) => b.mtimeMs - a.mtimeMs || (a.id < b.id ? -1 : 1));
|
|
217
|
+
let budget = opts?.scanBudgetBytes ?? CHAT_SCAN_BUDGET_BYTES;
|
|
218
|
+
const sessions = found.slice(0, cap).map((f) => {
|
|
219
|
+
const key = `${f.path}\0${f.mtimeMs}\0${f.size}`;
|
|
220
|
+
let title = cache.get(key);
|
|
221
|
+
if (!title) {
|
|
222
|
+
const cost = f.size <= CHAT_FULL_SCAN_MAX_BYTES ? f.size : CHAT_HEAD_BYTES + CHAT_TAIL_BYTES;
|
|
223
|
+
if (cost <= budget) {
|
|
224
|
+
title = readChatTitle(f.path);
|
|
225
|
+
budget -= cost;
|
|
226
|
+
cache.set(key, title);
|
|
227
|
+
} else {
|
|
228
|
+
title = readChatTitle(f.path, {
|
|
229
|
+
fullScanMaxBytes: 0,
|
|
230
|
+
headBytes: BUDGET_HEAD_BYTES,
|
|
231
|
+
tailBytes: BUDGET_TAIL_BYTES
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
id: f.id,
|
|
237
|
+
title: title.title,
|
|
238
|
+
titleSource: title.titleSource,
|
|
239
|
+
modified: Math.floor(f.mtimeMs),
|
|
240
|
+
sizeBytes: f.size
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
return envelope("claude", "ok", projectDir, sessions, found.length);
|
|
244
|
+
}
|
|
245
|
+
function listChatSessions(opts) {
|
|
246
|
+
return CHAT_VENDORS.map(
|
|
247
|
+
(vendor) => vendor === "claude" ? listClaudeSessions(opts) : envelope(vendor, "unsupported", null)
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
function collectChats(opts) {
|
|
251
|
+
if (opts?.withhold) return { withheld: true, vendors: [] };
|
|
252
|
+
return { withheld: false, vendors: listChatSessions(opts) };
|
|
253
|
+
}
|
|
254
|
+
function shellQuote(value) {
|
|
255
|
+
const s = String(value ?? "");
|
|
256
|
+
if (/^[A-Za-z0-9_./-]+$/.test(s)) return s;
|
|
257
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
258
|
+
}
|
|
259
|
+
function formatChatAge(modifiedMs, nowMs = Date.now()) {
|
|
260
|
+
const secs = Math.floor(Math.max(0, nowMs - modifiedMs) / 1e3);
|
|
261
|
+
if (secs < 5) return "just now";
|
|
262
|
+
if (secs < 60) return `${secs}s ago`;
|
|
263
|
+
const mins = Math.floor(secs / 60);
|
|
264
|
+
if (mins < 60) return `${mins}m ago`;
|
|
265
|
+
const hrs = Math.floor(mins / 60);
|
|
266
|
+
if (hrs < 24) return `${hrs}h ago`;
|
|
267
|
+
return `${Math.floor(hrs / 24)}d ago`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/commands/sessions.ts
|
|
271
|
+
var VENDOR_LABEL = {
|
|
272
|
+
claude: "Claude Code",
|
|
273
|
+
codex: "Codex",
|
|
274
|
+
cursor: "Cursor"
|
|
275
|
+
};
|
|
276
|
+
var TITLE_COLUMN = 48;
|
|
277
|
+
function vendorLabel(vendor) {
|
|
278
|
+
return VENDOR_LABEL[vendor] ?? vendor;
|
|
279
|
+
}
|
|
280
|
+
function renderChatSessions(chats, opts) {
|
|
281
|
+
const now = opts.now ?? Date.now();
|
|
282
|
+
const needsCd = path.resolve(opts.cwd ?? opts.workspace) !== path.resolve(opts.workspace);
|
|
283
|
+
const lines = [];
|
|
284
|
+
const claude = chats.vendors.find((v) => v.vendor === "claude");
|
|
285
|
+
if (claude?.status !== "ok") {
|
|
286
|
+
lines.push(`No saved Claude Code chats for ${opts.workspace}.`);
|
|
287
|
+
lines.push(
|
|
288
|
+
"The agent CLI saves sessions per folder: start `claude` in this folder to create one."
|
|
289
|
+
);
|
|
290
|
+
} else {
|
|
291
|
+
const shown = claude.sessions.length;
|
|
292
|
+
const count = shown < claude.total ? `${shown} newest of ${claude.total}` : `${claude.total} saved`;
|
|
293
|
+
lines.push(`Claude Code chats for ${opts.workspace} (${count})`);
|
|
294
|
+
lines.push("");
|
|
295
|
+
const ageWidth = Math.max(...claude.sessions.map((s) => formatChatAge(s.modified, now).length));
|
|
296
|
+
for (const s of claude.sessions) {
|
|
297
|
+
const title = cleanChatTitle(s.title ?? "(untitled)", TITLE_COLUMN).padEnd(TITLE_COLUMN);
|
|
298
|
+
const age = formatChatAge(s.modified, now).padEnd(ageWidth);
|
|
299
|
+
lines.push(` ${title} ${age} ${s.id.slice(0, 8)} claude --resume ${s.id}`);
|
|
300
|
+
}
|
|
301
|
+
if (needsCd) {
|
|
302
|
+
lines.push("");
|
|
303
|
+
lines.push(`Resume from that folder: cd ${shellQuote(opts.workspace)} first.`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const unsupported = chats.vendors.filter((v) => v.status === "unsupported");
|
|
307
|
+
if (unsupported.length > 0) {
|
|
308
|
+
lines.push("");
|
|
309
|
+
lines.push(unsupported.map((v) => `${vendorLabel(v.vendor)}: not supported yet`).join(" \xB7 "));
|
|
310
|
+
}
|
|
311
|
+
return lines.join("\n");
|
|
312
|
+
}
|
|
313
|
+
var sessionsCommand = defineCommand({
|
|
314
|
+
meta: {
|
|
315
|
+
name: "sessions",
|
|
316
|
+
description: "List this folder's saved agent chats with the command that resumes each one"
|
|
317
|
+
},
|
|
318
|
+
args: {
|
|
319
|
+
json: {
|
|
320
|
+
type: "boolean",
|
|
321
|
+
description: "Print {withheld, vendors[]} as JSON (one envelope per vendor)",
|
|
322
|
+
default: false
|
|
323
|
+
},
|
|
324
|
+
cwd: {
|
|
325
|
+
type: "string",
|
|
326
|
+
description: "Workspace folder whose chats to list (default: current directory)"
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
run({ args }) {
|
|
330
|
+
const cwd = process.cwd();
|
|
331
|
+
const workspace = path.resolve(cwd, typeof args.cwd === "string" && args.cwd ? args.cwd : ".");
|
|
332
|
+
const chats = collectChats({ cwd: workspace });
|
|
333
|
+
process.stdout.write(
|
|
334
|
+
args.json ? `${JSON.stringify(chats, null, 2)}
|
|
335
|
+
` : `${renderChatSessions(chats, { workspace, cwd })}
|
|
336
|
+
`
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
export {
|
|
341
|
+
renderChatSessions,
|
|
342
|
+
sessionsCommand
|
|
343
|
+
};
|
|
@@ -2,15 +2,15 @@ import {
|
|
|
2
2
|
classifyInstallError,
|
|
3
3
|
isNonInteractive,
|
|
4
4
|
pathCliStatus
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-EI3VQ7FU.js";
|
|
6
6
|
import {
|
|
7
7
|
assessEnvironment
|
|
8
8
|
} from "./chunk-B3VR5YBQ.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-YIOTJQHL.js";
|
|
10
10
|
import "./chunk-PFEUZXVT.js";
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-TNO7GTAJ.js";
|
|
12
|
+
import "./chunk-IN4MQ3P3.js";
|
|
13
|
+
import "./chunk-5WSFO35Y.js";
|
|
14
14
|
import {
|
|
15
15
|
KIT_VERSION,
|
|
16
16
|
pinnedCliSpec
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
detectWorkspaceParent,
|
|
3
3
|
workspaceParentAdvisoryLines
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MEZUW3LL.js";
|
|
5
5
|
import {
|
|
6
6
|
createReadinessReport
|
|
7
7
|
} from "./chunk-PNFF6OU3.js";
|
|
@@ -15,19 +15,19 @@ import {
|
|
|
15
15
|
import {
|
|
16
16
|
npxPinned,
|
|
17
17
|
pathCliStatus
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-EI3VQ7FU.js";
|
|
19
19
|
import {
|
|
20
20
|
assessEnvironment
|
|
21
21
|
} from "./chunk-B3VR5YBQ.js";
|
|
22
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-YIOTJQHL.js";
|
|
23
23
|
import "./chunk-PFEUZXVT.js";
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
import "./chunk-TNO7GTAJ.js";
|
|
25
|
+
import "./chunk-IN4MQ3P3.js";
|
|
26
26
|
import {
|
|
27
27
|
MANIFEST_RELATIVE_PATH,
|
|
28
28
|
loadAgentKitManifest,
|
|
29
29
|
resolveProtectedGlobs
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-5WSFO35Y.js";
|
|
31
31
|
import {
|
|
32
32
|
KIT_VERSION
|
|
33
33
|
} from "./chunk-7HDQEK6T.js";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
formatRerunFlags,
|
|
5
5
|
formatStaleCliRefusal,
|
|
6
6
|
syncFromManifest
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5LQP4JGH.js";
|
|
8
8
|
import {
|
|
9
9
|
formatSkippedSymlinks,
|
|
10
10
|
logApplyStats
|
|
@@ -12,15 +12,15 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
REGISTRY_CLI_ARGS,
|
|
14
14
|
resolveRegistryFromCli
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-34BBPQKI.js";
|
|
16
16
|
import {
|
|
17
17
|
CLAUDE_SETTINGS_REL,
|
|
18
18
|
formatClaudeSettingsDrift,
|
|
19
19
|
generateClaudeCommandAdapters,
|
|
20
20
|
planClaudeSettingsDrift,
|
|
21
21
|
writeClaudeSessionStartHook
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import "./chunk-
|
|
22
|
+
} from "./chunk-236IYK6L.js";
|
|
23
|
+
import "./chunk-6RRG3WOE.js";
|
|
24
24
|
import {
|
|
25
25
|
withCliProgress
|
|
26
26
|
} from "./chunk-QTON2GQX.js";
|
|
@@ -32,14 +32,14 @@ import {
|
|
|
32
32
|
confirmProjectRoot,
|
|
33
33
|
isNonInteractive,
|
|
34
34
|
syncPathCliToRuntime
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-EI3VQ7FU.js";
|
|
36
36
|
import "./chunk-B3VR5YBQ.js";
|
|
37
37
|
import {
|
|
38
38
|
checkForUpdates
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-YIOTJQHL.js";
|
|
40
40
|
import "./chunk-PFEUZXVT.js";
|
|
41
|
-
import "./chunk-
|
|
42
|
-
import "./chunk-
|
|
41
|
+
import "./chunk-TNO7GTAJ.js";
|
|
42
|
+
import "./chunk-IN4MQ3P3.js";
|
|
43
43
|
import {
|
|
44
44
|
buildManifest,
|
|
45
45
|
isProtectedPath,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
resolveProtectedGlobs,
|
|
48
48
|
saveManifest,
|
|
49
49
|
seedManagedHashLedger
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-5WSFO35Y.js";
|
|
51
51
|
import {
|
|
52
52
|
KIT_VERSION
|
|
53
53
|
} from "./chunk-7HDQEK6T.js";
|
package/package.json
CHANGED