jinzd-ai-cli 0.4.278 → 0.4.280
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{batch-7Y4NAA6N.js → batch-F27NOTWC.js} +2 -2
- package/dist/{chunk-LTZFUYBT.js → chunk-B3FHA6IN.js} +3 -3
- package/dist/{chunk-WOXIKQRI.js → chunk-CP5LAA52.js} +4 -4
- package/dist/{chunk-2BYQP6JX.js → chunk-EOP775JU.js} +1 -1
- package/dist/{chunk-JJCNNQTU.js → chunk-IIO2SMEJ.js} +354 -3
- package/dist/{chunk-H7QC5VMQ.js → chunk-LPZNOYRJ.js} +1 -1
- package/dist/{chunk-LOXEYWC3.js → chunk-NHJ4GHL4.js} +1 -1
- package/dist/{chunk-SJCOE4C7.js → chunk-PN42JO74.js} +1 -1
- package/dist/{chunk-LXXQTWT2.js → chunk-PUC277TH.js} +1 -1
- package/dist/{chunk-4Z6GAYB5.js → chunk-TAIZZY3N.js} +3 -3
- package/dist/{chunk-X3722RFA.js → chunk-UBPRUSAF.js} +1 -1
- package/dist/{chunk-L3CPM472.js → chunk-UMWDNNPS.js} +1 -1
- package/dist/{chunk-RFSKPCYC.js → chunk-V7EZ4SDC.js} +1 -1
- package/dist/{chunk-SB4XONS4.js → chunk-VQCFEA4Z.js} +1 -1
- package/dist/{ci-WDF2CYR4.js → ci-HJ4OVHCM.js} +4 -4
- package/dist/{ci-format-7B5VAZGA.js → ci-format-NKJRZ3QI.js} +2 -2
- package/dist/{constants-DC3TNLTL.js → constants-6LCZOBJC.js} +1 -1
- package/dist/{doctor-cli-CDDG5XOY.js → doctor-cli-7JGPC5G4.js} +4 -4
- package/dist/electron-server.js +525 -140
- package/dist/{hub-TO7ODOIA.js → hub-NX7HYN7V.js} +1 -1
- package/dist/index.js +151 -429
- package/dist/{persistent-memory-JCENBMCJ.js → persistent-memory-E6WECUTW.js} +2 -2
- package/dist/{persistent-memory-BU63CSGK.js → persistent-memory-MHHX7F25.js} +2 -2
- package/dist/{pr-GVSZYX6I.js → pr-GLUFBQLI.js} +4 -4
- package/dist/{run-tests-2Q5MJHXB.js → run-tests-LWAFPVS3.js} +2 -2
- package/dist/{run-tests-R4IQS6IF.js → run-tests-YPJDOEJA.js} +2 -2
- package/dist/{server-KAURBKFI.js → server-CXXYIPMU.js} +226 -145
- package/dist/{server-WXLE53HG.js → server-P6DI27CY.js} +5 -5
- package/dist/{task-orchestrator-RJ6FXYY5.js → task-orchestrator-FW4LBPTS.js} +5 -5
- package/dist/{usage-V3R7DA7M.js → usage-CJUHQDT2.js} +2 -2
- package/dist/web/client/app.js +14 -2
- package/dist/web/client/app.js.br +0 -0
- package/dist/web/client/app.js.gz +0 -0
- package/package.json +1 -1
package/dist/electron-server.js
CHANGED
|
@@ -40,14 +40,14 @@ import {
|
|
|
40
40
|
touchMemoryReferences,
|
|
41
41
|
updateMemoryApproval,
|
|
42
42
|
updateMemoryEntry
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-PUC277TH.js";
|
|
44
44
|
import {
|
|
45
45
|
redactJson,
|
|
46
46
|
scanString
|
|
47
47
|
} from "./chunk-FSC6KEWU.js";
|
|
48
48
|
import {
|
|
49
49
|
runTestsTool
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-NHJ4GHL4.js";
|
|
51
51
|
import {
|
|
52
52
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
53
53
|
APP_NAME,
|
|
@@ -80,7 +80,7 @@ import {
|
|
|
80
80
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
81
81
|
VERSION,
|
|
82
82
|
buildUserIdentityPrompt
|
|
83
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-PN42JO74.js";
|
|
84
84
|
import {
|
|
85
85
|
hasSemanticIndex,
|
|
86
86
|
semanticSearch
|
|
@@ -14370,6 +14370,101 @@ function decideModel(input) {
|
|
|
14370
14370
|
return pickModel(input.userInput, input.currentModel, input.routingConfig, input.availableModels);
|
|
14371
14371
|
}
|
|
14372
14372
|
|
|
14373
|
+
// src/core/session-export.ts
|
|
14374
|
+
function defaultExportFilename(session, format) {
|
|
14375
|
+
const dateTag = session.created.toISOString().slice(0, 10);
|
|
14376
|
+
return `session-${dateTag}-${session.id.slice(0, 8)}.${format === "json" ? "json" : "md"}`;
|
|
14377
|
+
}
|
|
14378
|
+
function markdownHeading(msg) {
|
|
14379
|
+
switch (msg.role) {
|
|
14380
|
+
case "user":
|
|
14381
|
+
return "## \u{1F464} You";
|
|
14382
|
+
case "assistant":
|
|
14383
|
+
return "## \u{1F916} Assistant";
|
|
14384
|
+
case "tool":
|
|
14385
|
+
return `### \u{1F527} Tool result: ${msg.toolName ?? "tool"}${msg.isError ? " (error)" : ""}`;
|
|
14386
|
+
default:
|
|
14387
|
+
return `## \u2699 ${msg.role}`;
|
|
14388
|
+
}
|
|
14389
|
+
}
|
|
14390
|
+
function buildSessionExport(session, format, outFile) {
|
|
14391
|
+
const filename = outFile || defaultExportFilename(session, format);
|
|
14392
|
+
if (format === "json") {
|
|
14393
|
+
const payload = session.toJSON ? session.toJSON() : {
|
|
14394
|
+
id: session.id,
|
|
14395
|
+
title: session.title ?? null,
|
|
14396
|
+
provider: session.provider,
|
|
14397
|
+
model: session.model,
|
|
14398
|
+
created: session.created.toISOString(),
|
|
14399
|
+
messages: session.messages
|
|
14400
|
+
};
|
|
14401
|
+
return { filename, content: JSON.stringify(payload, null, 2), messageCount: session.messages.length };
|
|
14402
|
+
}
|
|
14403
|
+
const dateStr = session.created.toISOString().replace("T", " ").slice(0, 19);
|
|
14404
|
+
let md = `# ${session.title ?? "Conversation Export"}
|
|
14405
|
+
|
|
14406
|
+
`;
|
|
14407
|
+
md += `| Field | Value |
|
|
14408
|
+
|----------|-------|
|
|
14409
|
+
`;
|
|
14410
|
+
md += `| Provider | ${session.provider} |
|
|
14411
|
+
`;
|
|
14412
|
+
md += `| Model | ${session.model} |
|
|
14413
|
+
`;
|
|
14414
|
+
md += `| Date | ${dateStr} |
|
|
14415
|
+
`;
|
|
14416
|
+
md += `| Session | ${session.id.slice(0, 8)} |
|
|
14417
|
+
|
|
14418
|
+
---
|
|
14419
|
+
|
|
14420
|
+
`;
|
|
14421
|
+
for (const msg of session.messages) {
|
|
14422
|
+
const text = getContentText(msg.content);
|
|
14423
|
+
md += `${markdownHeading(msg)}
|
|
14424
|
+
|
|
14425
|
+
`;
|
|
14426
|
+
if (text.trim()) md += `${text}
|
|
14427
|
+
|
|
14428
|
+
`;
|
|
14429
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
14430
|
+
for (const tc of msg.toolCalls) {
|
|
14431
|
+
md += `\`\`\`json
|
|
14432
|
+
${JSON.stringify({ tool: tc.name, arguments: tc.arguments ?? {} }, null, 2)}
|
|
14433
|
+
\`\`\`
|
|
14434
|
+
|
|
14435
|
+
`;
|
|
14436
|
+
}
|
|
14437
|
+
}
|
|
14438
|
+
md += `---
|
|
14439
|
+
|
|
14440
|
+
`;
|
|
14441
|
+
}
|
|
14442
|
+
return { filename, content: md, messageCount: session.messages.length };
|
|
14443
|
+
}
|
|
14444
|
+
function parseCheckpointCommand(args) {
|
|
14445
|
+
const sub = args[0]?.toLowerCase();
|
|
14446
|
+
if (!sub || sub === "list") return { kind: "list" };
|
|
14447
|
+
const name = args.slice(1).join(" ").trim();
|
|
14448
|
+
if (sub === "save" || sub === "restore" || sub === "delete") {
|
|
14449
|
+
if (!name) return { kind: "usage", message: `Usage: /checkpoint ${sub} <name>` };
|
|
14450
|
+
return { kind: sub, name };
|
|
14451
|
+
}
|
|
14452
|
+
return { kind: "unknown", message: `Unknown subcommand: ${sub}. Use save/restore/list/delete.` };
|
|
14453
|
+
}
|
|
14454
|
+
function formatCheckpointList(checkpoints) {
|
|
14455
|
+
if (checkpoints.length === 0) {
|
|
14456
|
+
return ["No checkpoints. Use /checkpoint save <name> to create one."];
|
|
14457
|
+
}
|
|
14458
|
+
return [
|
|
14459
|
+
`Checkpoints (${checkpoints.length}):`,
|
|
14460
|
+
...checkpoints.map((cp) => ` ${cp.name.padEnd(20)} msg #${cp.messageIndex} ${cp.timestamp.toLocaleString()}`)
|
|
14461
|
+
];
|
|
14462
|
+
}
|
|
14463
|
+
var checkpointSavedMessage = (name, messageCount) => `\u2713 Checkpoint "${name}" saved at message #${messageCount}`;
|
|
14464
|
+
var checkpointRestoredMessage = (name, messageCount) => `\u2713 Restored to checkpoint "${name}" (${messageCount} messages, token usage reset)`;
|
|
14465
|
+
var checkpointDeletedMessage = (name) => `\u2713 Deleted checkpoint "${name}"`;
|
|
14466
|
+
var checkpointNotFoundMessage = (name) => `Checkpoint "${name}" not found.`;
|
|
14467
|
+
|
|
14373
14468
|
// src/core/context-files.ts
|
|
14374
14469
|
import { existsSync as existsSync25, readFileSync as readFileSync20 } from "fs";
|
|
14375
14470
|
import { join as join19, relative as relative4, resolve as resolve8 } from "path";
|
|
@@ -16407,6 +16502,232 @@ function lastAssistantText(messages) {
|
|
|
16407
16502
|
return void 0;
|
|
16408
16503
|
}
|
|
16409
16504
|
|
|
16505
|
+
// src/core/session-command.ts
|
|
16506
|
+
var DEFAULT_SESSION_LIST_LIMIT = 50;
|
|
16507
|
+
function parseSessionListArgs(args) {
|
|
16508
|
+
let limit = DEFAULT_SESSION_LIST_LIMIT;
|
|
16509
|
+
let all = false;
|
|
16510
|
+
const filter = {};
|
|
16511
|
+
const warnings = [];
|
|
16512
|
+
let search = null;
|
|
16513
|
+
let days = null;
|
|
16514
|
+
let since = null;
|
|
16515
|
+
let sort = { field: "updated", order: "desc" };
|
|
16516
|
+
let json = false;
|
|
16517
|
+
let stale = null;
|
|
16518
|
+
let verbose = false;
|
|
16519
|
+
for (let i = 1; i < args.length; i++) {
|
|
16520
|
+
const a = args[i];
|
|
16521
|
+
if (a === "--all" || a === "-a") {
|
|
16522
|
+
all = true;
|
|
16523
|
+
} else if ((a === "--limit" || a === "-n") && i + 1 < args.length) {
|
|
16524
|
+
const n = Number(args[i + 1]);
|
|
16525
|
+
if (Number.isFinite(n) && n > 0) {
|
|
16526
|
+
limit = n;
|
|
16527
|
+
i++;
|
|
16528
|
+
}
|
|
16529
|
+
} else if (a === "--filter" && i + 1 < args.length) {
|
|
16530
|
+
const val = args[++i];
|
|
16531
|
+
const eq = val.indexOf("=");
|
|
16532
|
+
if (eq > 0) {
|
|
16533
|
+
const key = val.slice(0, eq);
|
|
16534
|
+
const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
|
|
16535
|
+
if (key === "provider") filter.provider = vals;
|
|
16536
|
+
else if (key === "model") filter.model = vals;
|
|
16537
|
+
else if (key === "messages") {
|
|
16538
|
+
const n = Number(vals[0]);
|
|
16539
|
+
if (Number.isFinite(n) && n >= 0) filter.messages = n;
|
|
16540
|
+
else warnings.push(`Invalid filter value for "messages": expected a non-negative integer, got "${vals[0]}"`);
|
|
16541
|
+
} else {
|
|
16542
|
+
warnings.push(`Unknown filter key: "${key}". Supported keys: provider, model, messages`);
|
|
16543
|
+
}
|
|
16544
|
+
} else {
|
|
16545
|
+
warnings.push(`Invalid --filter syntax: "${val}". Expected key=value`);
|
|
16546
|
+
}
|
|
16547
|
+
} else if ((a === "--search" || a === "-s") && i + 1 < args.length) {
|
|
16548
|
+
search = args[++i];
|
|
16549
|
+
} else if (a === "--days" && i + 1 < args.length) {
|
|
16550
|
+
const n = Number(args[++i]);
|
|
16551
|
+
if (Number.isFinite(n) && n > 0) days = n;
|
|
16552
|
+
} else if (a === "--since" && i + 1 < args.length) {
|
|
16553
|
+
since = args[++i];
|
|
16554
|
+
} else if (a === "--sort" && i + 1 < args.length) {
|
|
16555
|
+
const sv = args[++i];
|
|
16556
|
+
const colon = sv.indexOf(":");
|
|
16557
|
+
const field = colon > 0 ? sv.slice(0, colon) : sv;
|
|
16558
|
+
const order = colon > 0 ? sv.slice(colon + 1) : "desc";
|
|
16559
|
+
if (field === "updated" || field === "created" || field === "messages" || field === "size") {
|
|
16560
|
+
sort = { field, order: order === "asc" ? "asc" : "desc" };
|
|
16561
|
+
}
|
|
16562
|
+
} else if (a === "--json") {
|
|
16563
|
+
json = true;
|
|
16564
|
+
} else if (a === "--verbose" || a === "-v") {
|
|
16565
|
+
verbose = true;
|
|
16566
|
+
} else if (a === "--stale" && i + 1 < args.length) {
|
|
16567
|
+
const n = Number(args[++i]);
|
|
16568
|
+
if (Number.isFinite(n) && n > 0) stale = n;
|
|
16569
|
+
}
|
|
16570
|
+
}
|
|
16571
|
+
if (all) limit = -1;
|
|
16572
|
+
return { limit, all, filter, search, days, since, sort, json, stale, verbose, warnings };
|
|
16573
|
+
}
|
|
16574
|
+
function sessionListNeedsFileSize(opts) {
|
|
16575
|
+
return opts.verbose || opts.sort.field === "size";
|
|
16576
|
+
}
|
|
16577
|
+
function selectSessions(sessions, opts, now = Date.now()) {
|
|
16578
|
+
let matched = sessions;
|
|
16579
|
+
const hasFilters = !!opts.filter.provider || !!opts.filter.model || opts.filter.messages !== void 0;
|
|
16580
|
+
const hasSearch = !!opts.search;
|
|
16581
|
+
const hasTimeFilter = opts.days !== null || opts.since !== null;
|
|
16582
|
+
const hasStale = opts.stale !== null;
|
|
16583
|
+
if (hasFilters) {
|
|
16584
|
+
const p = opts.filter.provider;
|
|
16585
|
+
const m = opts.filter.model;
|
|
16586
|
+
const msg = opts.filter.messages;
|
|
16587
|
+
matched = matched.filter((s) => {
|
|
16588
|
+
if (p && !p.includes(s.provider.toLowerCase())) return false;
|
|
16589
|
+
if (m && !m.some((kw) => s.model.toLowerCase().includes(kw))) return false;
|
|
16590
|
+
if (msg !== void 0 && s.messageCount !== msg) return false;
|
|
16591
|
+
return true;
|
|
16592
|
+
});
|
|
16593
|
+
}
|
|
16594
|
+
if (hasSearch) {
|
|
16595
|
+
const q = opts.search.toLowerCase();
|
|
16596
|
+
matched = matched.filter(
|
|
16597
|
+
(s) => (s.title ?? "").toLowerCase().includes(q) || s.id.toLowerCase().includes(q)
|
|
16598
|
+
);
|
|
16599
|
+
}
|
|
16600
|
+
if (hasTimeFilter) {
|
|
16601
|
+
let cutoff = 0;
|
|
16602
|
+
if (opts.since) cutoff = new Date(opts.since).getTime();
|
|
16603
|
+
else if (opts.days !== null) cutoff = now - opts.days * 24 * 60 * 60 * 1e3;
|
|
16604
|
+
if (!Number.isNaN(cutoff)) {
|
|
16605
|
+
matched = matched.filter((s) => s.updated.getTime() >= cutoff);
|
|
16606
|
+
}
|
|
16607
|
+
}
|
|
16608
|
+
const staleCutoff = hasStale ? now - opts.stale * 24 * 60 * 60 * 1e3 : null;
|
|
16609
|
+
if (staleCutoff !== null) {
|
|
16610
|
+
matched = matched.filter((s) => s.updated.getTime() < staleCutoff);
|
|
16611
|
+
}
|
|
16612
|
+
const defaultSort = opts.sort.field === "updated" && opts.sort.order === "desc";
|
|
16613
|
+
if (!defaultSort) {
|
|
16614
|
+
const mul = opts.sort.order === "asc" ? 1 : -1;
|
|
16615
|
+
matched = [...matched].sort((a, b) => {
|
|
16616
|
+
switch (opts.sort.field) {
|
|
16617
|
+
case "created":
|
|
16618
|
+
return (a.created.getTime() - b.created.getTime()) * mul;
|
|
16619
|
+
case "messages":
|
|
16620
|
+
return (a.messageCount - b.messageCount) * mul;
|
|
16621
|
+
case "size":
|
|
16622
|
+
return ((a.fileSize ?? 0) - (b.fileSize ?? 0)) * mul;
|
|
16623
|
+
default:
|
|
16624
|
+
return (a.updated.getTime() - b.updated.getTime()) * mul;
|
|
16625
|
+
}
|
|
16626
|
+
});
|
|
16627
|
+
}
|
|
16628
|
+
const filterTags = [];
|
|
16629
|
+
if (hasFilters) filterTags.push("filtered");
|
|
16630
|
+
if (hasSearch) filterTags.push("searched");
|
|
16631
|
+
if (hasTimeFilter) filterTags.push("time-limited");
|
|
16632
|
+
if (hasStale) filterTags.push(`stale >${opts.stale}d`);
|
|
16633
|
+
return {
|
|
16634
|
+
matched,
|
|
16635
|
+
shown: opts.limit > 0 ? matched.slice(0, opts.limit) : matched,
|
|
16636
|
+
totalCount: matched.length,
|
|
16637
|
+
totalMessages: matched.reduce((sum, s) => sum + s.messageCount, 0),
|
|
16638
|
+
staleCutoff,
|
|
16639
|
+
filterTags,
|
|
16640
|
+
needsFileSize: sessionListNeedsFileSize(opts)
|
|
16641
|
+
};
|
|
16642
|
+
}
|
|
16643
|
+
function sessionListSummary(view) {
|
|
16644
|
+
const tag = view.filterTags.length > 0 ? ` (${view.filterTags.join(", ")})` : "";
|
|
16645
|
+
return `${view.shown.length} of ${view.totalCount} sessions${tag} \xB7 ${view.totalMessages} messages total`;
|
|
16646
|
+
}
|
|
16647
|
+
function sessionListJsonRow(s, includeFileSize) {
|
|
16648
|
+
return {
|
|
16649
|
+
id: s.id,
|
|
16650
|
+
title: s.title ?? null,
|
|
16651
|
+
provider: s.provider,
|
|
16652
|
+
model: s.model,
|
|
16653
|
+
messageCount: s.messageCount,
|
|
16654
|
+
created: s.created.toISOString(),
|
|
16655
|
+
updated: s.updated.toISOString(),
|
|
16656
|
+
...includeFileSize ? { fileSize: s.fileSize } : {},
|
|
16657
|
+
...s.branchCount !== void 0 ? { branchCount: s.branchCount, activeBranch: s.activeBranch } : {}
|
|
16658
|
+
};
|
|
16659
|
+
}
|
|
16660
|
+
function resolveSessionRef(sessions, prefix, policy) {
|
|
16661
|
+
const matches2 = sessions.filter((s) => s.id.startsWith(prefix));
|
|
16662
|
+
if (matches2.length === 0) {
|
|
16663
|
+
return { status: "not-found", message: `Session '${prefix}' not found.` };
|
|
16664
|
+
}
|
|
16665
|
+
if (matches2.length > 1 && policy === "strict") {
|
|
16666
|
+
return {
|
|
16667
|
+
status: "ambiguous",
|
|
16668
|
+
matches: matches2,
|
|
16669
|
+
message: `Ambiguous prefix '${prefix}' matches ${matches2.length} sessions \u2014 be more specific:`
|
|
16670
|
+
};
|
|
16671
|
+
}
|
|
16672
|
+
return {
|
|
16673
|
+
status: "ok",
|
|
16674
|
+
match: matches2[0],
|
|
16675
|
+
ambiguousWith: matches2.length > 1 ? matches2 : [],
|
|
16676
|
+
message: matches2.length > 1 ? `\u26A0 Ambiguous prefix '${prefix}' matches ${matches2.length} sessions \u2014 loading most recent:` : void 0
|
|
16677
|
+
};
|
|
16678
|
+
}
|
|
16679
|
+
function formatSessionSummaryLine(s, titleWidth = 60) {
|
|
16680
|
+
const title = s.title ?? "(untitled)";
|
|
16681
|
+
const shown = title.length > titleWidth ? `${title.slice(0, titleWidth - 1)}\u2026` : title;
|
|
16682
|
+
return `${s.id.slice(0, 12)} ${s.provider}/${s.model} ${String(s.messageCount).padStart(4)} msgs ${s.updated.toISOString().slice(0, 10)} ${shown}`;
|
|
16683
|
+
}
|
|
16684
|
+
function parseBatchDeleteArgs(args) {
|
|
16685
|
+
let messages;
|
|
16686
|
+
let dryRun = false;
|
|
16687
|
+
for (let i = 1; i < args.length; i++) {
|
|
16688
|
+
if (args[i] === "--filter" && i + 1 < args.length) {
|
|
16689
|
+
const val = args[++i];
|
|
16690
|
+
const eq = val.indexOf("=");
|
|
16691
|
+
if (eq <= 0) {
|
|
16692
|
+
return { dryRun, error: `Invalid --filter syntax: "${val}". Expected key=value (e.g., messages=0)` };
|
|
16693
|
+
}
|
|
16694
|
+
const key = val.slice(0, eq);
|
|
16695
|
+
const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
|
|
16696
|
+
if (key !== "messages") {
|
|
16697
|
+
return { dryRun, error: `Unsupported filter key for delete: "${key}". Only "messages" is supported.` };
|
|
16698
|
+
}
|
|
16699
|
+
const n = Number(vals[0]);
|
|
16700
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
16701
|
+
return { dryRun, error: `Invalid filter value for "messages": expected a non-negative integer, got "${vals[0]}"` };
|
|
16702
|
+
}
|
|
16703
|
+
messages = n;
|
|
16704
|
+
} else if (args[i] === "--dry-run") {
|
|
16705
|
+
dryRun = true;
|
|
16706
|
+
}
|
|
16707
|
+
}
|
|
16708
|
+
if (messages === void 0) {
|
|
16709
|
+
return { dryRun, error: "Usage: /session delete --filter messages=N [--dry-run]" };
|
|
16710
|
+
}
|
|
16711
|
+
return { messages, dryRun };
|
|
16712
|
+
}
|
|
16713
|
+
function parseCleanArgs(args) {
|
|
16714
|
+
let staleDays = 90;
|
|
16715
|
+
let dryRun = false;
|
|
16716
|
+
for (let i = 1; i < args.length; i++) {
|
|
16717
|
+
if (args[i] === "--stale" && i + 1 < args.length) {
|
|
16718
|
+
const n = Number(args[++i]);
|
|
16719
|
+
if (Number.isFinite(n) && n > 0) staleDays = n;
|
|
16720
|
+
} else if (args[i] === "--dry-run") {
|
|
16721
|
+
dryRun = true;
|
|
16722
|
+
}
|
|
16723
|
+
}
|
|
16724
|
+
return { staleDays, dryRun };
|
|
16725
|
+
}
|
|
16726
|
+
function selectStaleSessions(sessions, staleDays, now = Date.now()) {
|
|
16727
|
+
const cutoff = now - staleDays * 24 * 60 * 60 * 1e3;
|
|
16728
|
+
return sessions.filter((s) => s.updated.getTime() < cutoff);
|
|
16729
|
+
}
|
|
16730
|
+
|
|
16410
16731
|
// src/web/commands/session-commands.ts
|
|
16411
16732
|
async function handleClear(_args, ctx) {
|
|
16412
16733
|
ctx.saveIfNeeded();
|
|
@@ -16430,7 +16751,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
|
|
|
16430
16751
|
Cost: ${formatCost(cost)}` : "";
|
|
16431
16752
|
let memoryLine = "";
|
|
16432
16753
|
try {
|
|
16433
|
-
const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-
|
|
16754
|
+
const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-E6WECUTW.js");
|
|
16434
16755
|
const pending = countPendingMemories2(ctx.config.getConfigDir());
|
|
16435
16756
|
if (pending > 0) memoryLine = `
|
|
16436
16757
|
Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
|
|
@@ -16473,11 +16794,17 @@ async function handleSession(args, ctx) {
|
|
|
16473
16794
|
ctx.sendSessionList();
|
|
16474
16795
|
return;
|
|
16475
16796
|
}
|
|
16476
|
-
const
|
|
16477
|
-
|
|
16478
|
-
|
|
16797
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "most-recent");
|
|
16798
|
+
if (ref.status === "ok") {
|
|
16799
|
+
const found = ref.match;
|
|
16479
16800
|
ctx.sessions.loadSession(found.id);
|
|
16480
16801
|
ctx.resetWebSessionUsage();
|
|
16802
|
+
if (ref.message) {
|
|
16803
|
+
ctx.send({
|
|
16804
|
+
type: "info",
|
|
16805
|
+
message: [ref.message, ...ref.ambiguousWith.slice(0, 5).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
|
|
16806
|
+
});
|
|
16807
|
+
}
|
|
16481
16808
|
ctx.send({ type: "info", message: `Loaded session: ${found.id.slice(0, 8)} "${found.title ?? ""}" (${found.messageCount} messages)` });
|
|
16482
16809
|
const loadedSession = ctx.sessions.current;
|
|
16483
16810
|
if (loadedSession && loadedSession.messages.length > 0) {
|
|
@@ -16507,52 +16834,81 @@ async function handleSession(args, ctx) {
|
|
|
16507
16834
|
return;
|
|
16508
16835
|
}
|
|
16509
16836
|
if (sub === "list") {
|
|
16510
|
-
|
|
16837
|
+
if (args.length <= 1) {
|
|
16838
|
+
ctx.sendSessionList();
|
|
16839
|
+
return;
|
|
16840
|
+
}
|
|
16841
|
+
const opts = parseSessionListArgs(args);
|
|
16842
|
+
const all = ctx.sessions.listSessions({ includeFileSize: sessionListNeedsFileSize(opts) });
|
|
16843
|
+
if (all.length === 0) {
|
|
16844
|
+
ctx.send({ type: "info", message: "No saved sessions." });
|
|
16845
|
+
return;
|
|
16846
|
+
}
|
|
16847
|
+
const view = selectSessions(all, opts);
|
|
16848
|
+
if (view.totalCount === 0) {
|
|
16849
|
+
ctx.send({
|
|
16850
|
+
type: "info",
|
|
16851
|
+
message: [...opts.warnings.map((w) => `\u26A0 ${w}`), "No sessions match the filter criteria."].join("\n")
|
|
16852
|
+
});
|
|
16853
|
+
return;
|
|
16854
|
+
}
|
|
16855
|
+
if (opts.json) {
|
|
16856
|
+
ctx.send({
|
|
16857
|
+
type: "info",
|
|
16858
|
+
message: JSON.stringify(view.shown.map((s) => sessionListJsonRow(s, view.needsFileSize)), null, 2)
|
|
16859
|
+
});
|
|
16860
|
+
return;
|
|
16861
|
+
}
|
|
16862
|
+
const lines = [
|
|
16863
|
+
...opts.warnings.map((w) => `\u26A0 ${w}`),
|
|
16864
|
+
...view.shown.map((s) => formatSessionSummaryLine(s)),
|
|
16865
|
+
`\u2500\u2500 ${sessionListSummary(view)}`
|
|
16866
|
+
];
|
|
16867
|
+
if (view.shown.length < view.totalCount) lines.push("Use --all to show all, or --limit N to change count.");
|
|
16868
|
+
ctx.send({ type: "info", message: lines.join("\n") });
|
|
16511
16869
|
return;
|
|
16512
16870
|
}
|
|
16513
16871
|
if (sub === "delete" && args[1]) {
|
|
16514
16872
|
const targetId = args[1];
|
|
16515
16873
|
if (targetId === "--filter") {
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16519
|
-
const val = args[i + 1];
|
|
16520
|
-
i++;
|
|
16521
|
-
const eq = val.indexOf("=");
|
|
16522
|
-
if (eq > 0) {
|
|
16523
|
-
const key = val.slice(0, eq);
|
|
16524
|
-
const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
|
|
16525
|
-
if (key === "messages") {
|
|
16526
|
-
const n = Number(vals[0]);
|
|
16527
|
-
if (Number.isFinite(n) && n >= 0) filterMessages = n;
|
|
16528
|
-
}
|
|
16529
|
-
}
|
|
16530
|
-
}
|
|
16531
|
-
}
|
|
16532
|
-
if (filterMessages === void 0) {
|
|
16533
|
-
ctx.send({ type: "error", message: "Usage: /session delete --filter messages=N" });
|
|
16874
|
+
const opts = parseBatchDeleteArgs(args);
|
|
16875
|
+
if (opts.error) {
|
|
16876
|
+
ctx.send({ type: "error", message: opts.error });
|
|
16534
16877
|
return;
|
|
16535
16878
|
}
|
|
16536
|
-
const
|
|
16537
|
-
const matches2 = list2.filter((s) => s.messageCount === filterMessages);
|
|
16879
|
+
const matches2 = ctx.sessions.listSessions().filter((s) => s.messageCount === opts.messages);
|
|
16538
16880
|
if (matches2.length === 0) {
|
|
16539
|
-
ctx.send({ type: "info", message: `No sessions with ${
|
|
16881
|
+
ctx.send({ type: "info", message: `No sessions with ${opts.messages} message(s) found.` });
|
|
16882
|
+
return;
|
|
16883
|
+
}
|
|
16884
|
+
const preview = [
|
|
16885
|
+
`Found ${matches2.length} session(s) with ${opts.messages} message(s):`,
|
|
16886
|
+
...matches2.slice(0, 20).map((s) => ` ${formatSessionSummaryLine(s)}`),
|
|
16887
|
+
...matches2.length > 20 ? [` ... and ${matches2.length - 20} more`] : []
|
|
16888
|
+
];
|
|
16889
|
+
if (opts.dryRun) {
|
|
16890
|
+
ctx.send({
|
|
16891
|
+
type: "info",
|
|
16892
|
+
message: [...preview, "--dry-run: no sessions were deleted. Remove --dry-run to actually delete."].join("\n")
|
|
16893
|
+
});
|
|
16540
16894
|
return;
|
|
16541
16895
|
}
|
|
16542
16896
|
let deleted = 0;
|
|
16543
16897
|
let failed = 0;
|
|
16544
16898
|
for (const s of matches2) {
|
|
16545
|
-
if (ctx.sessions.deleteSession(s.id))
|
|
16546
|
-
|
|
16547
|
-
} else {
|
|
16548
|
-
failed++;
|
|
16549
|
-
}
|
|
16899
|
+
if (ctx.sessions.deleteSession(s.id)) deleted++;
|
|
16900
|
+
else failed++;
|
|
16550
16901
|
}
|
|
16551
16902
|
if (!ctx.sessions.current) {
|
|
16552
|
-
ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
16903
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
16904
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
16553
16905
|
ctx.resetWebSessionUsage();
|
|
16554
16906
|
}
|
|
16555
|
-
ctx.send({
|
|
16907
|
+
ctx.send({
|
|
16908
|
+
type: "info",
|
|
16909
|
+
message: [...preview, `Deleted ${deleted} session(s)${failed > 0 ? `, ${failed} failed` : ""}.`].join("\n")
|
|
16910
|
+
});
|
|
16911
|
+
ctx.sendStatus();
|
|
16556
16912
|
ctx.sendSessionList();
|
|
16557
16913
|
return;
|
|
16558
16914
|
}
|
|
@@ -16561,20 +16917,79 @@ async function handleSession(args, ctx) {
|
|
|
16561
16917
|
ctx.unsavedSessions.delete(cachedKey);
|
|
16562
16918
|
if (ctx.sessions.current?.id === cachedKey) {
|
|
16563
16919
|
ctx.sessions.clearCurrent();
|
|
16920
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
16921
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
16922
|
+
ctx.resetWebSessionUsage();
|
|
16923
|
+
ctx.sendStatus();
|
|
16564
16924
|
}
|
|
16565
16925
|
ctx.send({ type: "info", message: `Deleted session: ${cachedKey.slice(0, 8)}` });
|
|
16566
16926
|
ctx.sendSessionList();
|
|
16567
16927
|
return;
|
|
16568
16928
|
}
|
|
16569
|
-
const
|
|
16570
|
-
|
|
16571
|
-
if (found) {
|
|
16572
|
-
ctx.sessions.deleteSession(found.id);
|
|
16573
|
-
ctx.send({ type: "info", message: `Deleted session: ${found.id.slice(0, 8)}` });
|
|
16574
|
-
ctx.sendSessionList();
|
|
16575
|
-
} else {
|
|
16929
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "strict");
|
|
16930
|
+
if (ref.status === "not-found") {
|
|
16576
16931
|
ctx.send({ type: "error", message: `Session not found: ${targetId}` });
|
|
16932
|
+
return;
|
|
16577
16933
|
}
|
|
16934
|
+
if (ref.status === "ambiguous") {
|
|
16935
|
+
ctx.send({
|
|
16936
|
+
type: "error",
|
|
16937
|
+
message: [ref.message, ...ref.matches.slice(0, 10).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
|
|
16938
|
+
});
|
|
16939
|
+
return;
|
|
16940
|
+
}
|
|
16941
|
+
const wasCurrent = ctx.sessions.current?.id === ref.match.id;
|
|
16942
|
+
if (!ctx.sessions.deleteSession(ref.match.id)) {
|
|
16943
|
+
ctx.send({ type: "error", message: "Delete failed \u2014 session file not found on disk." });
|
|
16944
|
+
return;
|
|
16945
|
+
}
|
|
16946
|
+
ctx.send({ type: "info", message: `Deleted session: ${ref.match.id.slice(0, 8)}` });
|
|
16947
|
+
if (wasCurrent) {
|
|
16948
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
16949
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
16950
|
+
ctx.resetWebSessionUsage();
|
|
16951
|
+
ctx.send({ type: "info", message: "Current session was deleted \u2014 started a fresh session." });
|
|
16952
|
+
ctx.sendStatus();
|
|
16953
|
+
}
|
|
16954
|
+
ctx.sendSessionList();
|
|
16955
|
+
return;
|
|
16956
|
+
}
|
|
16957
|
+
if (sub === "clean") {
|
|
16958
|
+
const opts = parseCleanArgs(args);
|
|
16959
|
+
const stale = selectStaleSessions(ctx.sessions.listSessions(), opts.staleDays);
|
|
16960
|
+
if (stale.length === 0) {
|
|
16961
|
+
ctx.send({ type: "info", message: `No sessions older than ${opts.staleDays} days found.` });
|
|
16962
|
+
return;
|
|
16963
|
+
}
|
|
16964
|
+
const preview = [
|
|
16965
|
+
`Found ${stale.length} session(s) not updated in ${opts.staleDays}+ days:`,
|
|
16966
|
+
...stale.slice(0, 20).map((s) => ` ${formatSessionSummaryLine(s)}`),
|
|
16967
|
+
...stale.length > 20 ? [` ... and ${stale.length - 20} more`] : []
|
|
16968
|
+
];
|
|
16969
|
+
if (opts.dryRun) {
|
|
16970
|
+
ctx.send({
|
|
16971
|
+
type: "info",
|
|
16972
|
+
message: [...preview, "--dry-run: no sessions were deleted. Remove --dry-run to actually delete."].join("\n")
|
|
16973
|
+
});
|
|
16974
|
+
return;
|
|
16975
|
+
}
|
|
16976
|
+
let deleted = 0;
|
|
16977
|
+
let failed = 0;
|
|
16978
|
+
for (const s of stale) {
|
|
16979
|
+
if (ctx.sessions.deleteSession(s.id)) deleted++;
|
|
16980
|
+
else failed++;
|
|
16981
|
+
}
|
|
16982
|
+
if (!ctx.sessions.current) {
|
|
16983
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
16984
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
16985
|
+
ctx.resetWebSessionUsage();
|
|
16986
|
+
ctx.sendStatus();
|
|
16987
|
+
}
|
|
16988
|
+
ctx.send({
|
|
16989
|
+
type: "info",
|
|
16990
|
+
message: [...preview, `Cleaned up: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`].join("\n")
|
|
16991
|
+
});
|
|
16992
|
+
ctx.sendSessionList();
|
|
16578
16993
|
return;
|
|
16579
16994
|
}
|
|
16580
16995
|
if (sub === "batch-delete") {
|
|
@@ -16598,6 +17013,12 @@ async function handleSession(args, ctx) {
|
|
|
16598
17013
|
deleted++;
|
|
16599
17014
|
}
|
|
16600
17015
|
}
|
|
17016
|
+
if (!ctx.sessions.current) {
|
|
17017
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
17018
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
17019
|
+
ctx.resetWebSessionUsage();
|
|
17020
|
+
ctx.sendStatus();
|
|
17021
|
+
}
|
|
16601
17022
|
ctx.send({ type: "info", message: `Deleted ${deleted} session(s).` });
|
|
16602
17023
|
ctx.sendSessionList();
|
|
16603
17024
|
return;
|
|
@@ -16611,26 +17032,40 @@ async function handleSession(args, ctx) {
|
|
|
16611
17032
|
}
|
|
16612
17033
|
const cachedKey = ctx.unsavedSessions.has(targetId) ? targetId : [...ctx.unsavedSessions.keys()].find((k) => k.startsWith(targetId));
|
|
16613
17034
|
if (cachedKey) {
|
|
16614
|
-
const
|
|
16615
|
-
|
|
17035
|
+
const session2 = ctx.unsavedSessions.get(cachedKey);
|
|
17036
|
+
session2.title = newTitle;
|
|
16616
17037
|
ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
|
|
16617
17038
|
ctx.sendSessionList();
|
|
16618
17039
|
return;
|
|
16619
17040
|
}
|
|
16620
|
-
const
|
|
16621
|
-
|
|
16622
|
-
if (found) {
|
|
16623
|
-
const session = ctx.sessions.loadSession(found.id);
|
|
16624
|
-
session.title = newTitle;
|
|
16625
|
-
ctx.sessions.save();
|
|
16626
|
-
ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
|
|
16627
|
-
ctx.sendSessionList();
|
|
16628
|
-
} else {
|
|
17041
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "strict");
|
|
17042
|
+
if (ref.status === "not-found") {
|
|
16629
17043
|
ctx.send({ type: "error", message: `Session not found: ${targetId}` });
|
|
17044
|
+
return;
|
|
17045
|
+
}
|
|
17046
|
+
if (ref.status === "ambiguous") {
|
|
17047
|
+
ctx.send({
|
|
17048
|
+
type: "error",
|
|
17049
|
+
message: [ref.message, ...ref.matches.slice(0, 10).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
|
|
17050
|
+
});
|
|
17051
|
+
return;
|
|
16630
17052
|
}
|
|
17053
|
+
const priorId = ctx.sessions.current?.id ?? null;
|
|
17054
|
+
const isCurrent = priorId === ref.match.id;
|
|
17055
|
+
const session = isCurrent ? ctx.sessions.current : ctx.sessions.loadSession(ref.match.id);
|
|
17056
|
+
session.title = newTitle;
|
|
17057
|
+
ctx.sessions.save();
|
|
17058
|
+
if (!isCurrent && priorId) {
|
|
17059
|
+
ctx.sessions.loadSession(priorId);
|
|
17060
|
+
}
|
|
17061
|
+
ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
|
|
17062
|
+
ctx.sendSessionList();
|
|
16631
17063
|
return;
|
|
16632
17064
|
}
|
|
16633
|
-
ctx.send({
|
|
17065
|
+
ctx.send({
|
|
17066
|
+
type: "info",
|
|
17067
|
+
message: "Usage: /session new | list [--filter k=v] [--search kw] [--limit N|--all] [--sort f[:o]] [--json] | load <id> | delete <id> | delete --filter messages=N [--dry-run] | clean --stale N [--dry-run] | rename <id> <title>"
|
|
17068
|
+
});
|
|
16634
17069
|
}
|
|
16635
17070
|
async function handleExport(args, ctx) {
|
|
16636
17071
|
const format = args[0] === "json" ? "json" : "md";
|
|
@@ -16677,56 +17112,36 @@ async function handleCheckpoint(args, ctx) {
|
|
|
16677
17112
|
ctx.send({ type: "error", message: "No active session." });
|
|
16678
17113
|
return;
|
|
16679
17114
|
}
|
|
16680
|
-
const
|
|
16681
|
-
if (
|
|
16682
|
-
|
|
16683
|
-
if (cps.length === 0) {
|
|
16684
|
-
ctx.send({ type: "info", message: "No checkpoints. Use /checkpoint save <name> to create one." });
|
|
16685
|
-
} else {
|
|
16686
|
-
const lines = [`\u{1F4CC} Checkpoints (${cps.length}):`, ""];
|
|
16687
|
-
for (const cp of cps) {
|
|
16688
|
-
const ts = cp.timestamp.toLocaleString();
|
|
16689
|
-
lines.push(` ${cp.name.padEnd(20)} msg #${cp.messageIndex} ${ts}`);
|
|
16690
|
-
}
|
|
16691
|
-
ctx.send({ type: "info", message: lines.join("\n") });
|
|
16692
|
-
}
|
|
17115
|
+
const intent = parseCheckpointCommand(args);
|
|
17116
|
+
if (intent.kind === "list") {
|
|
17117
|
+
ctx.send({ type: "info", message: formatCheckpointList(session.checkpoints).join("\n") });
|
|
16693
17118
|
return;
|
|
16694
17119
|
}
|
|
16695
|
-
|
|
16696
|
-
|
|
16697
|
-
|
|
16698
|
-
|
|
16699
|
-
|
|
16700
|
-
|
|
16701
|
-
session.
|
|
16702
|
-
|
|
16703
|
-
}
|
|
16704
|
-
|
|
16705
|
-
|
|
16706
|
-
|
|
16707
|
-
}
|
|
16708
|
-
const ok = session.restoreCheckpoint(cpName);
|
|
16709
|
-
if (ok) {
|
|
16710
|
-
ctx.send({ type: "info", message: `\u2713 Restored to checkpoint "${cpName}" (${session.messages.length} messages)` });
|
|
16711
|
-
ctx.sendSessionMessages();
|
|
16712
|
-
ctx.sendStatus();
|
|
16713
|
-
} else {
|
|
16714
|
-
ctx.send({ type: "error", message: `Checkpoint "${cpName}" not found.` });
|
|
16715
|
-
}
|
|
16716
|
-
} else if (sub === "delete") {
|
|
16717
|
-
if (!cpName) {
|
|
16718
|
-
ctx.send({ type: "error", message: "Usage: /checkpoint delete <name>" });
|
|
17120
|
+
if (intent.kind === "usage" || intent.kind === "unknown") {
|
|
17121
|
+
ctx.send({ type: "error", message: intent.message });
|
|
17122
|
+
return;
|
|
17123
|
+
}
|
|
17124
|
+
if (intent.kind === "save") {
|
|
17125
|
+
session.createCheckpoint(intent.name);
|
|
17126
|
+
ctx.send({ type: "info", message: checkpointSavedMessage(intent.name, session.messages.length) });
|
|
17127
|
+
return;
|
|
17128
|
+
}
|
|
17129
|
+
if (intent.kind === "restore") {
|
|
17130
|
+
if (!session.restoreCheckpoint(intent.name)) {
|
|
17131
|
+
ctx.send({ type: "error", message: checkpointNotFoundMessage(intent.name) });
|
|
16719
17132
|
return;
|
|
16720
17133
|
}
|
|
16721
|
-
|
|
16722
|
-
|
|
16723
|
-
|
|
16724
|
-
|
|
16725
|
-
|
|
16726
|
-
|
|
16727
|
-
|
|
16728
|
-
ctx.send({ type: "error", message:
|
|
17134
|
+
ctx.resetWebSessionUsage();
|
|
17135
|
+
ctx.send({ type: "info", message: checkpointRestoredMessage(intent.name, session.messages.length) });
|
|
17136
|
+
ctx.sendSessionMessages();
|
|
17137
|
+
ctx.sendStatus();
|
|
17138
|
+
return;
|
|
17139
|
+
}
|
|
17140
|
+
if (!session.deleteCheckpoint(intent.name)) {
|
|
17141
|
+
ctx.send({ type: "error", message: checkpointNotFoundMessage(intent.name) });
|
|
17142
|
+
return;
|
|
16729
17143
|
}
|
|
17144
|
+
ctx.send({ type: "info", message: checkpointDeletedMessage(intent.name) });
|
|
16730
17145
|
}
|
|
16731
17146
|
async function handleBranch(args, ctx) {
|
|
16732
17147
|
const session = ctx.sessions.current;
|
|
@@ -17243,7 +17658,7 @@ async function handleTest(args, ctx) {
|
|
|
17243
17658
|
const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
|
|
17244
17659
|
testArgs = isCommand ? { command: argStr } : { filter: argStr };
|
|
17245
17660
|
}
|
|
17246
|
-
const runTests = ctx.runTests ?? (await import("./run-tests-
|
|
17661
|
+
const runTests = ctx.runTests ?? (await import("./run-tests-LWAFPVS3.js")).executeTests;
|
|
17247
17662
|
const report = await runTests(testArgs);
|
|
17248
17663
|
ctx.send({ type: "info", message: report });
|
|
17249
17664
|
} catch (err) {
|
|
@@ -17579,7 +17994,7 @@ async function handleMemory(args, ctx) {
|
|
|
17579
17994
|
ctx.handleMemoryManage(sub, args[1], sub === "expire" ? args[2] : void 0);
|
|
17580
17995
|
} else if (sub === "export") {
|
|
17581
17996
|
if (args[1] === "md") {
|
|
17582
|
-
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-
|
|
17997
|
+
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-E6WECUTW.js");
|
|
17583
17998
|
ctx.send({
|
|
17584
17999
|
type: "export_data",
|
|
17585
18000
|
format: "md",
|
|
@@ -18023,7 +18438,7 @@ async function handleHelp(_args, ctx) {
|
|
|
18023
18438
|
" /think [on|off] \u2014 Toggle extended thinking mode",
|
|
18024
18439
|
" /plan [execute|exit|status] \u2014 Read-only planning mode (bare /plan enters it)",
|
|
18025
18440
|
" /route [on|off|show|test <msg>] \u2014 Smart model routing",
|
|
18026
|
-
" /session new|list|load
|
|
18441
|
+
" /session new|list [filters]|load <id>|delete <id>|delete --filter messages=N [--dry-run]|clean --stale N [--dry-run]|rename <id> <title> \u2014 Session management",
|
|
18027
18442
|
" /system [prompt|clear] \u2014 Set/view/reset system prompt",
|
|
18028
18443
|
" /context [status|reload] \u2014 Show/reload context layers",
|
|
18029
18444
|
" /status \u2014 Show session info & token usage",
|
|
@@ -19424,43 +19839,13 @@ ${summaryContent}`,
|
|
|
19424
19839
|
this.send({ type: "info", message: "No messages to export." });
|
|
19425
19840
|
return;
|
|
19426
19841
|
}
|
|
19427
|
-
const
|
|
19428
|
-
|
|
19429
|
-
|
|
19430
|
-
|
|
19431
|
-
|
|
19432
|
-
|
|
19433
|
-
|
|
19434
|
-
exported: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19435
|
-
messages: session.messages.map((m) => ({
|
|
19436
|
-
role: m.role,
|
|
19437
|
-
content: getContentText(m.content),
|
|
19438
|
-
timestamp: m.timestamp?.toISOString()
|
|
19439
|
-
}))
|
|
19440
|
-
};
|
|
19441
|
-
this.send({
|
|
19442
|
-
type: "export_data",
|
|
19443
|
-
format: "json",
|
|
19444
|
-
filename: `aicli-${timestamp}.json`,
|
|
19445
|
-
content: JSON.stringify(data, null, 2)
|
|
19446
|
-
});
|
|
19447
|
-
} else {
|
|
19448
|
-
const lines = [`# ${title}`, "", `> Exported: ${(/* @__PURE__ */ new Date()).toLocaleString()} | Provider: ${this.currentProvider} | Model: ${this.currentModel}`, ""];
|
|
19449
|
-
for (const m of session.messages) {
|
|
19450
|
-
const text = getContentText(m.content);
|
|
19451
|
-
if (m.role === "user") {
|
|
19452
|
-
lines.push(`## \u{1F9D1} User`, "", text, "");
|
|
19453
|
-
} else if (m.role === "assistant") {
|
|
19454
|
-
lines.push(`## \u{1F916} Assistant`, "", text, "");
|
|
19455
|
-
}
|
|
19456
|
-
}
|
|
19457
|
-
this.send({
|
|
19458
|
-
type: "export_data",
|
|
19459
|
-
format: "md",
|
|
19460
|
-
filename: `aicli-${timestamp}.md`,
|
|
19461
|
-
content: lines.join("\n")
|
|
19462
|
-
});
|
|
19463
|
-
}
|
|
19842
|
+
const exported = buildSessionExport(session, format);
|
|
19843
|
+
this.send({
|
|
19844
|
+
type: "export_data",
|
|
19845
|
+
format,
|
|
19846
|
+
filename: exported.filename,
|
|
19847
|
+
content: exported.content
|
|
19848
|
+
});
|
|
19464
19849
|
}
|
|
19465
19850
|
memoryShow(args = []) {
|
|
19466
19851
|
const configDir = this.config.getConfigDir();
|