pikiclaw 0.2.55 → 0.2.56
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/bot-command-ui.js +4 -2
- package/dist/bot-commands.js +36 -1
- package/dist/code-agent.js +107 -8
- package/dist/dashboard-ui.js +7 -7
- package/dist/dashboard.js +1 -0
- package/dist/driver-claude.js +7 -1
- package/dist/driver-codex.js +15 -1
- package/dist/driver-gemini.js +7 -1
- package/package.json +1 -1
package/dist/bot-command-ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeAgent } from './bot.js';
|
|
2
|
-
import {
|
|
2
|
+
import { getSessionStatusForChat } from './session-status.js';
|
|
3
|
+
import { getAgentsListData, getModelsListData, getSessionsPageData, getSkillsListData, summarizeSessionRun, modelMatchesSelection, resolveSkillPrompt, } from './bot-commands.js';
|
|
3
4
|
function chunkRows(items, columns) {
|
|
4
5
|
const rows = [];
|
|
5
6
|
const size = Math.max(1, columns);
|
|
@@ -219,13 +220,14 @@ export async function executeCommandAction(bot, chatId, action, opts = {}) {
|
|
|
219
220
|
return { kind: 'noop', message: 'Session not found' };
|
|
220
221
|
const runtime = bot.adoptExistingSessionForChat(chatId, session);
|
|
221
222
|
const displayId = session.sessionId || action.sessionId;
|
|
223
|
+
const sessionStatus = getSessionStatusForChat(bot, chat, session);
|
|
222
224
|
return {
|
|
223
225
|
kind: 'notice',
|
|
224
226
|
callbackText: `Switched: ${displayId.slice(0, 12)}`,
|
|
225
227
|
notice: {
|
|
226
228
|
title: 'Session Switched',
|
|
227
229
|
value: displayId,
|
|
228
|
-
detail:
|
|
230
|
+
detail: summarizeSessionRun({ ...session, running: sessionStatus.isRunning }).noticeDetail,
|
|
229
231
|
valueMode: 'code',
|
|
230
232
|
},
|
|
231
233
|
session: runtime,
|
package/dist/bot-commands.js
CHANGED
|
@@ -37,6 +37,28 @@ export function getStartData(bot, chatId) {
|
|
|
37
37
|
commands,
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
+
export function summarizeSessionRun(session) {
|
|
41
|
+
if (session.running || session.runState === 'running') {
|
|
42
|
+
return {
|
|
43
|
+
state: 'running',
|
|
44
|
+
shortLabel: 'running',
|
|
45
|
+
noticeDetail: 'Status: running',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (session.runState === 'incomplete') {
|
|
49
|
+
const detail = String(session.runDetail || '').trim();
|
|
50
|
+
return {
|
|
51
|
+
state: 'incomplete',
|
|
52
|
+
shortLabel: 'unfinished',
|
|
53
|
+
noticeDetail: detail ? `Status: unfinished · ${detail}` : 'Status: unfinished',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
state: 'completed',
|
|
58
|
+
shortLabel: 'done',
|
|
59
|
+
noticeDetail: 'Status: completed',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
40
62
|
export async function getSessionsPageData(bot, chatId, page, pageSize = 5) {
|
|
41
63
|
const cs = bot.chat(chatId);
|
|
42
64
|
const res = await bot.fetchSessions(cs.agent);
|
|
@@ -51,11 +73,24 @@ export async function getSessionsPageData(bot, chatId, page, pageSize = 5) {
|
|
|
51
73
|
if (!sessionKey)
|
|
52
74
|
continue;
|
|
53
75
|
const status = getSessionStatusForChat(bot, cs, s);
|
|
76
|
+
const runSummary = summarizeSessionRun({
|
|
77
|
+
running: status.isRunning,
|
|
78
|
+
runState: status.isRunning ? 'running' : s.runState,
|
|
79
|
+
runDetail: s.runDetail,
|
|
80
|
+
});
|
|
54
81
|
const title = s.title ? s.title.replace(/\n/g, ' ').slice(0, 10) : sessionKey.slice(0, 10);
|
|
55
82
|
const time = s.createdAt
|
|
56
83
|
? new Date(s.createdAt).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })
|
|
57
84
|
: '?';
|
|
58
|
-
entries.push({
|
|
85
|
+
entries.push({
|
|
86
|
+
key: sessionKey,
|
|
87
|
+
title,
|
|
88
|
+
time: `${time} · ${runSummary.shortLabel}`,
|
|
89
|
+
isCurrent: status.isCurrent,
|
|
90
|
+
isRunning: status.isRunning,
|
|
91
|
+
runState: runSummary.state,
|
|
92
|
+
runDetail: s.runDetail,
|
|
93
|
+
});
|
|
59
94
|
}
|
|
60
95
|
return { agent: cs.agent, total, page: pg, totalPages, sessions: entries };
|
|
61
96
|
}
|
package/dist/code-agent.js
CHANGED
|
@@ -464,6 +464,54 @@ function nextPendingSessionId() { return `pending_${crypto.randomBytes(6).toStri
|
|
|
464
464
|
export function isPendingSessionId(sessionId) {
|
|
465
465
|
return typeof sessionId === 'string' && sessionId.startsWith('pending_');
|
|
466
466
|
}
|
|
467
|
+
function normalizeSessionRunState(rawState) {
|
|
468
|
+
const state = typeof rawState === 'string' ? rawState.trim().toLowerCase() : '';
|
|
469
|
+
if (state === 'completed' || state === 'incomplete')
|
|
470
|
+
return state;
|
|
471
|
+
if (state === 'running')
|
|
472
|
+
return 'incomplete';
|
|
473
|
+
return 'completed';
|
|
474
|
+
}
|
|
475
|
+
function normalizeSessionRunDetail(rawState, rawDetail) {
|
|
476
|
+
const detail = typeof rawDetail === 'string' ? rawDetail.trim() : '';
|
|
477
|
+
if (detail)
|
|
478
|
+
return shortValue(detail, 180);
|
|
479
|
+
const state = typeof rawState === 'string' ? rawState.trim().toLowerCase() : '';
|
|
480
|
+
if (state === 'running')
|
|
481
|
+
return 'Last run stopped before completion.';
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
function normalizeSessionRunUpdatedAt(rawUpdatedAt, fallback) {
|
|
485
|
+
return typeof rawUpdatedAt === 'string' && rawUpdatedAt.trim() ? rawUpdatedAt : fallback;
|
|
486
|
+
}
|
|
487
|
+
function setSessionRunState(record, runState, runDetail, runUpdatedAt) {
|
|
488
|
+
record.runState = runState;
|
|
489
|
+
record.runDetail = runDetail ? shortValue(runDetail, 180) : null;
|
|
490
|
+
record.runUpdatedAt = runUpdatedAt || new Date().toISOString();
|
|
491
|
+
}
|
|
492
|
+
function incompleteRunDetail(result) {
|
|
493
|
+
if (result.stopReason === 'interrupted')
|
|
494
|
+
return 'Interrupted by user.';
|
|
495
|
+
if (result.stopReason === 'timeout')
|
|
496
|
+
return 'Timed out before completion.';
|
|
497
|
+
if (result.stopReason === 'max_tokens')
|
|
498
|
+
return 'Stopped before completion: max tokens reached.';
|
|
499
|
+
const error = normalizeErrorMessage(result.error);
|
|
500
|
+
if (error)
|
|
501
|
+
return shortValue(error, 180);
|
|
502
|
+
const stopReason = normalizeErrorMessage(result.stopReason);
|
|
503
|
+
if (stopReason)
|
|
504
|
+
return `Stopped before completion: ${shortValue(stopReason, 120)}`;
|
|
505
|
+
const message = firstNonEmptyLine(result.message || '');
|
|
506
|
+
return message ? shortValue(message, 180) : 'Last run did not complete.';
|
|
507
|
+
}
|
|
508
|
+
function applySessionRunResult(record, result) {
|
|
509
|
+
if (result.ok && !result.incomplete) {
|
|
510
|
+
setSessionRunState(record, 'completed', null);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
setSessionRunState(record, 'incomplete', incompleteRunDetail(result));
|
|
514
|
+
}
|
|
467
515
|
function normalizeSessionRecord(raw, workdir) {
|
|
468
516
|
// Support both new format (sessionId) and legacy format (localSessionId + engineSessionId)
|
|
469
517
|
const sessionId = typeof raw?.sessionId === 'string' ? raw.sessionId.trim()
|
|
@@ -484,6 +532,9 @@ function normalizeSessionRecord(raw, workdir) {
|
|
|
484
532
|
title: typeof raw?.title === 'string' && raw.title.trim() ? raw.title.trim() : null,
|
|
485
533
|
model: typeof raw?.model === 'string' && raw.model.trim() ? raw.model.trim() : null,
|
|
486
534
|
stagedFiles: Array.isArray(raw?.stagedFiles) ? dedupeStrings(raw.stagedFiles.filter((v) => typeof v === 'string')) : [],
|
|
535
|
+
runState: normalizeSessionRunState(raw?.runState),
|
|
536
|
+
runDetail: normalizeSessionRunDetail(raw?.runState, raw?.runDetail),
|
|
537
|
+
runUpdatedAt: normalizeSessionRunUpdatedAt(raw?.runUpdatedAt, typeof raw?.updatedAt === 'string' && raw.updatedAt.trim() ? raw.updatedAt : new Date().toISOString()),
|
|
487
538
|
};
|
|
488
539
|
}
|
|
489
540
|
function loadSessionIndex(workdir) {
|
|
@@ -502,6 +553,7 @@ function writeSessionMeta(record) {
|
|
|
502
553
|
workspacePath: record.workspacePath,
|
|
503
554
|
createdAt: record.createdAt, updatedAt: record.updatedAt,
|
|
504
555
|
title: record.title, model: record.model, stagedFiles: record.stagedFiles,
|
|
556
|
+
runState: record.runState, runDetail: record.runDetail, runUpdatedAt: record.runUpdatedAt,
|
|
505
557
|
});
|
|
506
558
|
}
|
|
507
559
|
function copyPath(sourcePath, targetPath) {
|
|
@@ -583,8 +635,25 @@ export function promoteSessionId(workdir, agent, pendingId, nativeId) {
|
|
|
583
635
|
record.workspacePath = sessionWorkspacePath(resolvedWorkdir, agent, nativeId);
|
|
584
636
|
saveSessionRecord(resolvedWorkdir, record);
|
|
585
637
|
}
|
|
638
|
+
function syncManagedSessionIdentity(session, workdir, nativeId) {
|
|
639
|
+
const resolvedId = nativeId.trim();
|
|
640
|
+
if (!resolvedId || session.sessionId === resolvedId)
|
|
641
|
+
return false;
|
|
642
|
+
const resolvedWorkdir = path.resolve(workdir);
|
|
643
|
+
const previousId = session.sessionId;
|
|
644
|
+
if (isPendingSessionId(previousId)) {
|
|
645
|
+
promoteSessionId(resolvedWorkdir, session.record.agent, previousId, resolvedId);
|
|
646
|
+
}
|
|
647
|
+
session.sessionId = resolvedId;
|
|
648
|
+
session.workspacePath = sessionWorkspacePath(resolvedWorkdir, session.record.agent, resolvedId);
|
|
649
|
+
session.record.sessionId = resolvedId;
|
|
650
|
+
session.record.workspacePath = session.workspacePath;
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
586
653
|
function summarizePromptTitle(prompt) {
|
|
587
|
-
const
|
|
654
|
+
const raw = String(prompt || '').replace(/\r\n?/g, '\n');
|
|
655
|
+
const text = firstNonEmptyLine(raw).replace(/\s+/g, ' ').trim()
|
|
656
|
+
|| raw.replace(/\s+/g, ' ').trim();
|
|
588
657
|
if (!text)
|
|
589
658
|
return null;
|
|
590
659
|
return text.length <= 120 ? text : `${text.slice(0, 117).trimEnd()}...`;
|
|
@@ -635,6 +704,7 @@ function ensureSessionWorkspace(opts) {
|
|
|
635
704
|
workspacePath: sessionWorkspacePath(workdir, opts.agent, sessionId),
|
|
636
705
|
createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
|
|
637
706
|
title: summarizePromptTitle(opts.title) || null, model: null, stagedFiles: [],
|
|
707
|
+
runState: 'completed', runDetail: null, runUpdatedAt: new Date().toISOString(),
|
|
638
708
|
};
|
|
639
709
|
}
|
|
640
710
|
if (!record.title && opts.title)
|
|
@@ -799,6 +869,7 @@ function prepareStreamOpts(opts) {
|
|
|
799
869
|
session.record.stagedFiles = [];
|
|
800
870
|
if (!session.record.title)
|
|
801
871
|
session.record.title = summarizePromptTitle(opts.prompt) || importedFiles[0] || null;
|
|
872
|
+
setSessionRunState(session.record, 'running', null);
|
|
802
873
|
saveSessionRecord(opts.workdir, session.record);
|
|
803
874
|
const attachmentPaths = attachmentRelPaths.map(relPath => path.join(session.workspacePath, relPath));
|
|
804
875
|
// For pending sessions, pass null sessionId to the CLI so it creates a new session
|
|
@@ -811,20 +882,21 @@ function prepareStreamOpts(opts) {
|
|
|
811
882
|
...opts,
|
|
812
883
|
sessionId: effectiveSessionId,
|
|
813
884
|
attachments: attachmentPaths.length ? attachmentPaths : undefined,
|
|
885
|
+
onSessionId: (nativeSessionId) => {
|
|
886
|
+
if (!syncManagedSessionIdentity(session, opts.workdir, nativeSessionId))
|
|
887
|
+
return;
|
|
888
|
+
saveSessionRecord(opts.workdir, session.record);
|
|
889
|
+
},
|
|
814
890
|
},
|
|
815
891
|
};
|
|
816
892
|
}
|
|
817
893
|
function finalizeStreamResult(result, workdir, prompt, session) {
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
if (result.sessionId && isPendingSessionId(pendingId)) {
|
|
821
|
-
promoteSessionId(workdir, session.record.agent, pendingId, result.sessionId);
|
|
822
|
-
session.sessionId = result.sessionId;
|
|
823
|
-
}
|
|
824
|
-
session.record.sessionId = result.sessionId || session.record.sessionId;
|
|
894
|
+
if (result.sessionId)
|
|
895
|
+
syncManagedSessionIdentity(session, workdir, result.sessionId);
|
|
825
896
|
session.record.model = result.model || session.record.model;
|
|
826
897
|
if (!session.record.title)
|
|
827
898
|
session.record.title = summarizePromptTitle(prompt);
|
|
899
|
+
applySessionRunResult(session.record, result);
|
|
828
900
|
saveSessionRecord(workdir, session.record);
|
|
829
901
|
return { ...result, sessionId: session.sessionId, workspacePath: session.workspacePath };
|
|
830
902
|
}
|
|
@@ -885,6 +957,33 @@ export async function doStream(opts) {
|
|
|
885
957
|
const result = await driver.doStream(prepared);
|
|
886
958
|
return finalizeStreamResult(result, opts.workdir, opts.prompt, session);
|
|
887
959
|
}
|
|
960
|
+
catch (error) {
|
|
961
|
+
const failedResult = {
|
|
962
|
+
ok: false,
|
|
963
|
+
message: normalizeErrorMessage(error) || 'Agent stream failed.',
|
|
964
|
+
thinking: null,
|
|
965
|
+
sessionId: session.sessionId,
|
|
966
|
+
workspacePath: session.workspacePath,
|
|
967
|
+
model: session.record.model,
|
|
968
|
+
thinkingEffort: prepared.thinkingEffort,
|
|
969
|
+
elapsedS: 0,
|
|
970
|
+
inputTokens: null,
|
|
971
|
+
outputTokens: null,
|
|
972
|
+
cachedInputTokens: null,
|
|
973
|
+
cacheCreationInputTokens: null,
|
|
974
|
+
contextWindow: null,
|
|
975
|
+
contextUsedTokens: null,
|
|
976
|
+
contextPercent: null,
|
|
977
|
+
codexCumulative: null,
|
|
978
|
+
error: normalizeErrorMessage(error) || 'Agent stream failed.',
|
|
979
|
+
stopReason: null,
|
|
980
|
+
incomplete: true,
|
|
981
|
+
activity: null,
|
|
982
|
+
};
|
|
983
|
+
applySessionRunResult(session.record, failedResult);
|
|
984
|
+
saveSessionRecord(opts.workdir, session.record);
|
|
985
|
+
throw error;
|
|
986
|
+
}
|
|
888
987
|
finally {
|
|
889
988
|
if (bridge) {
|
|
890
989
|
await bridge.stop().catch(() => { });
|