pikiloom 0.4.15 → 0.4.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dashboard/dist/assets/{AgentTab-CKoy_-w4.js → AgentTab-CDVhy5K1.js} +1 -1
- package/dashboard/dist/assets/{DirBrowser-DpbuN0OL.js → DirBrowser-BElI1-4D.js} +1 -1
- package/dashboard/dist/assets/{ExtensionsTab-ymr7K8dU.js → ExtensionsTab-BB8ipJ77.js} +1 -1
- package/dashboard/dist/assets/{IMAccessTab-CaTtCn3l.js → IMAccessTab-IZt_yXoG.js} +1 -1
- package/dashboard/dist/assets/{Modal-DA-9kJxp.js → Modal-C1EAGSL1.js} +1 -1
- package/dashboard/dist/assets/{Modals-BkLIRnNK.js → Modals-DYUV5yR9.js} +1 -1
- package/dashboard/dist/assets/{Select-B0pZtuzF.js → Select-BnsbE6Qv.js} +1 -1
- package/dashboard/dist/assets/SessionPanel-Ca_TVTT1.js +1 -0
- package/dashboard/dist/assets/{SystemTab-B9TcGMzc.js → SystemTab-Dk6k2OTt.js} +1 -1
- package/dashboard/dist/assets/index-CK-3CNRp.js +3 -0
- package/dashboard/dist/assets/index-CnJsD381.js +23 -0
- package/dashboard/dist/assets/index-dzfjF9Js.css +1 -0
- package/dashboard/dist/assets/{shared-i_XUH0xm.js → shared-CZVD0MJD.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/agent/artifacts.js +160 -0
- package/dist/agent/images.js +51 -24
- package/dist/agent/index.js +4 -2
- package/dist/agent/mcp/bridge.js +201 -7
- package/dist/agent/mcp/extensions.js +20 -9
- package/dist/agent/mcp/tools/workspace.js +4 -3
- package/dist/agent/stream.js +3 -2
- package/dist/bot/bot.js +83 -4
- package/dist/bot/commands.js +48 -2
- package/dist/bot/menu.js +1 -0
- package/dist/bot/session-hub.js +1 -1
- package/dist/channels/dingtalk/bot.js +9 -1
- package/dist/channels/discord/bot.js +9 -1
- package/dist/channels/feishu/bot.js +8 -1
- package/dist/channels/slack/bot.js +9 -1
- package/dist/channels/telegram/bot.js +8 -1
- package/dist/channels/wecom/bot.js +9 -1
- package/dist/channels/weixin/bot.js +9 -1
- package/dist/cli/main.js +1 -0
- package/dist/dashboard/routes/config.js +134 -12
- package/dist/dashboard/routes/sessions.js +108 -27
- package/package.json +1 -1
- package/dashboard/dist/assets/SessionPanel-CYQtZZNX.js +0 -1
- package/dashboard/dist/assets/index-BCYshErN.js +0 -3
- package/dashboard/dist/assets/index-C5irxzzD.js +0 -23
- package/dashboard/dist/assets/index-FD86DEDF.css +0 -1
package/dist/bot/bot.js
CHANGED
|
@@ -7,7 +7,7 @@ import os from 'node:os';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { execSync, spawn } from 'node:child_process';
|
|
9
9
|
import { getActiveUserConfig, loadWorkspaces, onUserConfigChange, resolveUserWorkdir, setUserWorkdir, updateUserConfig } from '../core/config/user-config.js';
|
|
10
|
-
import { doStream, ensureManagedSession, findManagedThreadSession, getSessionStoredConfig, getUsage, initializeProjectSkills, listAgents, resolveAgentModels, resolveDefaultAgent, listSkills, stageSessionFiles, reconcileOrphanedRunningSessions, getAgentBoundModelId, setAgentBoundModelId, collapseSkillPrompt, readGoal, accountTurn, shouldContinueAfterTurn, renderContinuationPrompt, renderBudgetLimitPrompt, bumpContinuationCount, pauseGoal, resumeGoal, setGoal as setGoalState, clearGoal as clearGoalState, setCodexGoal, getCodexGoal, clearCodexGoal, pauseCodexGoal, resumeCodexGoal, getClaudeNativeGoal, buildClaudeSetGoalPrompt, buildClaudeClearGoalPrompt, isPendingSessionId, } from '../agent/index.js';
|
|
10
|
+
import { doStream, ensureManagedSession, findManagedThreadSession, getSessionStoredConfig, getUsage, initializeProjectSkills, listAgents, resolveAgentModels, resolveDefaultAgent, listSkills, stageSessionFiles, reconcileOrphanedRunningSessions, getAgentBoundModelId, setAgentBoundModelId, collapseSkillPrompt, readGoal, accountTurn, shouldContinueAfterTurn, renderContinuationPrompt, renderBudgetLimitPrompt, bumpContinuationCount, pauseGoal, resumeGoal, setGoal as setGoalState, clearGoal as clearGoalState, setCodexGoal, getCodexGoal, clearCodexGoal, pauseCodexGoal, resumeCodexGoal, getClaudeNativeGoal, buildClaudeSetGoalPrompt, buildClaudeClearGoalPrompt, deliverArtifact, attachmentUrl, isPendingSessionId, } from '../agent/index.js';
|
|
11
11
|
import { compactForHandover, describeHandoverRef } from '../agent/handover.js';
|
|
12
12
|
import { getActiveProfileId, setActiveProfile } from '../model/index.js';
|
|
13
13
|
import { querySessions, querySessionTail, updateSession, } from './session-hub.js';
|
|
@@ -58,10 +58,14 @@ function appendExtraPrompt(base, extra) {
|
|
|
58
58
|
return lhs;
|
|
59
59
|
return `${lhs}\n\n${rhs}`;
|
|
60
60
|
}
|
|
61
|
+
// NOTE: the `[Artifact Return]` header is a load-bearing marker — both
|
|
62
|
+
// `stripInjectedPrompts` (bot/streaming.ts) and Gemini's
|
|
63
|
+
// `GEMINI_SYSTEM_BLOCK_SENTINELS` key on it to strip this injected block from
|
|
64
|
+
// displayed user messages. Keep the token in sync if you ever change it.
|
|
61
65
|
function buildMcpDeliveryPrompt() {
|
|
62
66
|
return [
|
|
63
67
|
'[Artifact Return]',
|
|
64
|
-
'
|
|
68
|
+
'To hand a file to the user — a screenshot, report, archive, generated asset, anything they asked you to "send" — call the `im_send_file` tool with the file path and a short caption. It is delivered through whatever terminal the user is on (an IM chat or the web dashboard) and stays retrievable even when they are connected remotely. Do NOT just print a local filesystem path: a remote user cannot open paths on this machine.',
|
|
65
69
|
].join('\n');
|
|
66
70
|
}
|
|
67
71
|
function buildClaudeAskUserPrompt() {
|
|
@@ -360,6 +364,14 @@ export class Bot {
|
|
|
360
364
|
}
|
|
361
365
|
break;
|
|
362
366
|
}
|
|
367
|
+
case 'artifact': {
|
|
368
|
+
const snap = this.streamSnapshots.get(sessionKey);
|
|
369
|
+
if (snap) {
|
|
370
|
+
snap.artifacts = [...(snap.artifacts || []), event.artifact];
|
|
371
|
+
snap.updatedAt = now;
|
|
372
|
+
}
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
363
375
|
case 'done': {
|
|
364
376
|
const prev = this.streamSnapshots.get(sessionKey);
|
|
365
377
|
this.streamSnapshots.set(sessionKey, {
|
|
@@ -375,6 +387,7 @@ export class Bot {
|
|
|
375
387
|
model: prev?.model ?? null,
|
|
376
388
|
effort: prev?.effort ?? null,
|
|
377
389
|
previewMeta: prev?.previewMeta ?? null,
|
|
390
|
+
artifacts: prev?.artifacts,
|
|
378
391
|
startedAt: prev?.startedAt,
|
|
379
392
|
queuedTaskIds: prev?.queuedTaskIds,
|
|
380
393
|
updatedAt: now,
|
|
@@ -482,6 +495,58 @@ export class Bot {
|
|
|
482
495
|
emitStreamCancelled(taskId, fallbackKey) {
|
|
483
496
|
this.emitStream(this.liveSessionKey(taskId, fallbackKey), { type: 'cancelled', taskId });
|
|
484
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Wrap a per-turn `im_send_file` callback so every artifact delivery is
|
|
500
|
+
* recorded to the session's durable manifest (agent/artifacts.ts) and
|
|
501
|
+
* mirrored live into the running turn's snapshot — on top of whatever
|
|
502
|
+
* terminal-specific push the caller supplied (`inner`, e.g. an IM chat
|
|
503
|
+
* upload). The returned callback is always safe to register, so the tool is
|
|
504
|
+
* available for dashboard / headless turns that have no `inner` (the
|
|
505
|
+
* dashboard serves the recorded copy over HTTP). Recording is best-effort and
|
|
506
|
+
* never propagates an error back into the delivery result.
|
|
507
|
+
*/
|
|
508
|
+
buildArtifactSendFile(agent, sessionKey, cs, inner) {
|
|
509
|
+
return async (filePath, sendOpts) => {
|
|
510
|
+
// Terminal-specific push first (IM chat). Dashboard / headless has no inner.
|
|
511
|
+
const result = inner ? await inner(filePath, sendOpts) : { ok: true };
|
|
512
|
+
if (!result.ok)
|
|
513
|
+
return result;
|
|
514
|
+
try {
|
|
515
|
+
// Resolve the freshest session id at delivery time — send_file fires
|
|
516
|
+
// late in a turn, after a pending→native promotion has normally already
|
|
517
|
+
// happened, so the manifest lands under the canonical id.
|
|
518
|
+
let sid = '';
|
|
519
|
+
if (sessionKey) {
|
|
520
|
+
const rt = this.getSessionRuntimeByKey(sessionKey, { allowAnyWorkdir: true });
|
|
521
|
+
if (rt?.sessionId)
|
|
522
|
+
sid = rt.sessionId;
|
|
523
|
+
}
|
|
524
|
+
if (!sid && typeof cs.sessionId === 'string')
|
|
525
|
+
sid = cs.sessionId;
|
|
526
|
+
if (!sid || isPendingSessionId(sid))
|
|
527
|
+
return result;
|
|
528
|
+
const kind = sendOpts?.kind === 'photo' ? 'photo' : 'document';
|
|
529
|
+
const record = deliverArtifact(agent, sid, filePath, { kind, caption: sendOpts?.caption });
|
|
530
|
+
if (record && sessionKey) {
|
|
531
|
+
this.emitStream(this.resolveSessionKey(sessionKey), {
|
|
532
|
+
type: 'artifact',
|
|
533
|
+
artifact: {
|
|
534
|
+
url: attachmentUrl(agent, sid, record.path, { downloadName: record.fileName }),
|
|
535
|
+
fileName: record.fileName,
|
|
536
|
+
fileSize: record.fileSize,
|
|
537
|
+
mime: record.fileMime,
|
|
538
|
+
kind: record.kind,
|
|
539
|
+
...(record.caption ? { caption: record.caption } : {}),
|
|
540
|
+
},
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
catch (e) {
|
|
545
|
+
this.warn(`[runStream] artifact record failed: ${e?.message || e}`);
|
|
546
|
+
}
|
|
547
|
+
return result;
|
|
548
|
+
};
|
|
549
|
+
}
|
|
485
550
|
keepAliveProc = null;
|
|
486
551
|
keepAlivePulseTimer = null;
|
|
487
552
|
sessionChains = new Map();
|
|
@@ -2376,7 +2441,21 @@ export class Bot {
|
|
|
2376
2441
|
// falls back to the agent's in-memory flag (IM /mode) when unspecified.
|
|
2377
2442
|
// Default off — never read from a persisted config default.
|
|
2378
2443
|
const workflowEnabled = cs.agent === 'claude' && (extras?.workflowEnabled ?? this.claudeWorkflowEnabled);
|
|
2379
|
-
|
|
2444
|
+
// ── Artifact delivery (terminal-agnostic) ──
|
|
2445
|
+
// `im_send_file` is the single "hand a file to the user" verb. Whatever the
|
|
2446
|
+
// caller wired as `mcpSendFile` (an IM channel push, or nothing for a
|
|
2447
|
+
// dashboard / headless turn) is wrapped so every delivery ALSO records the
|
|
2448
|
+
// file into the session's delivered-artifact manifest — the durable SSOT
|
|
2449
|
+
// that survives reload + workspace cleanup and is servable over HTTP — and
|
|
2450
|
+
// surfaces it live in the running turn's snapshot for any watching
|
|
2451
|
+
// dashboard. Always provided, so the tool + delivery prompt light up even
|
|
2452
|
+
// when there is no IM channel (the dashboard is the delivery surface then).
|
|
2453
|
+
const deliverySessionKey = ('key' in cs && typeof cs.key === 'string') ? cs.key : null;
|
|
2454
|
+
const wrappedSendFile = this.buildArtifactSendFile(cs.agent, deliverySessionKey, cs, mcpSendFile);
|
|
2455
|
+
const mcpSystemPrompt = appendExtraPrompt(appendExtraPrompt(appendExtraPrompt(
|
|
2456
|
+
// Always-on: `wrappedSendFile` is provided for every turn (see above),
|
|
2457
|
+
// so artifact delivery is available regardless of terminal.
|
|
2458
|
+
buildMcpDeliveryPrompt(), onInteraction && cs.agent === 'claude' ? buildClaudeAskUserPrompt() : ''), buildBrowserAutomationPrompt(browserEnabled)), workflowEnabled ? buildWorkflowOptInPrompt() : '');
|
|
2380
2459
|
// mcpSystemPrompt carries behaviour directives (use im_ask_user instead of
|
|
2381
2460
|
// built-in AskUserQuestion, browser automation status, artifact delivery)
|
|
2382
2461
|
// that must apply on every turn, not just the first — on resume the CLI
|
|
@@ -2433,7 +2512,7 @@ export class Bot {
|
|
|
2433
2512
|
// a Profile is bound).
|
|
2434
2513
|
hermesModel: cs.agent === 'hermes' && resolvedModel ? resolvedModel : undefined,
|
|
2435
2514
|
// MCP bridge
|
|
2436
|
-
mcpSendFile,
|
|
2515
|
+
mcpSendFile: wrappedSendFile,
|
|
2437
2516
|
abortSignal,
|
|
2438
2517
|
onInteraction,
|
|
2439
2518
|
onSteerReady,
|
package/dist/bot/commands.js
CHANGED
|
@@ -247,6 +247,52 @@ export async function getSessionsPageData(bot, chatId, page, pageSize = 5) {
|
|
|
247
247
|
sessions: entries,
|
|
248
248
|
};
|
|
249
249
|
}
|
|
250
|
+
export async function getSessionsDigestData(bot, chatId, limit = 8) {
|
|
251
|
+
const pageData = await getSessionsPageData(bot, chatId, 0, Math.max(1, limit));
|
|
252
|
+
const entries = pageData.sessions.map((session, index) => ({
|
|
253
|
+
index: index + 1,
|
|
254
|
+
agent: session.agent,
|
|
255
|
+
title: session.title,
|
|
256
|
+
time: session.time,
|
|
257
|
+
runState: session.runState,
|
|
258
|
+
runDetail: session.runDetail,
|
|
259
|
+
isCurrent: session.isCurrent,
|
|
260
|
+
sessionKey: session.key,
|
|
261
|
+
}));
|
|
262
|
+
return {
|
|
263
|
+
workspaceName: pageData.workspaceName,
|
|
264
|
+
agentTotals: pageData.agentTotals,
|
|
265
|
+
total: pageData.total,
|
|
266
|
+
entries,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
export function formatSessionsDigestText(data) {
|
|
270
|
+
if (!data.entries.length) {
|
|
271
|
+
return data.workspaceName
|
|
272
|
+
? `No sessions in ${data.workspaceName} yet. Send a message to start.`
|
|
273
|
+
: 'No sessions yet. Send a message to start.';
|
|
274
|
+
}
|
|
275
|
+
const agentBits = Object.entries(data.agentTotals)
|
|
276
|
+
.map(([agent, count]) => `${agent}×${count}`)
|
|
277
|
+
.join(' · ');
|
|
278
|
+
const lines = [
|
|
279
|
+
`Session digest — ${data.workspaceName || 'workspace'} (${data.total} total${agentBits ? ` · ${agentBits}` : ''})`,
|
|
280
|
+
'',
|
|
281
|
+
];
|
|
282
|
+
for (const entry of data.entries) {
|
|
283
|
+
const flags = [
|
|
284
|
+
entry.isCurrent ? 'current' : null,
|
|
285
|
+
entry.runState === 'running' ? 'running' : null,
|
|
286
|
+
entry.runState === 'incomplete' ? 'unfinished' : null,
|
|
287
|
+
].filter(Boolean).join(', ');
|
|
288
|
+
const flagSuffix = flags ? ` [${flags}]` : '';
|
|
289
|
+
lines.push(`${entry.index}. ${entry.agent} · ${entry.title}${flagSuffix}`);
|
|
290
|
+
const detail = entry.runDetail ? ` · ${entry.runDetail}` : '';
|
|
291
|
+
lines.push(` ${entry.time}${detail}`);
|
|
292
|
+
}
|
|
293
|
+
lines.push('', 'Switch: /sessions <#> · Browse: /sessions');
|
|
294
|
+
return lines.join('\n');
|
|
295
|
+
}
|
|
250
296
|
export function extractLastSessionTurn(messages) {
|
|
251
297
|
if (!messages.length)
|
|
252
298
|
return null;
|
|
@@ -479,10 +525,10 @@ export function resolveSkillPrompt(bot, chatId, cmd, args) {
|
|
|
479
525
|
const paths = getProjectSkillPaths(wd, skill.name);
|
|
480
526
|
const skillFile = paths.claudeSkillFile || paths.sharedSkillFile || paths.agentsSkillFile;
|
|
481
527
|
if (skillFile) {
|
|
482
|
-
prompt = `${workdirHint}Read the skill definition at \`${skillFile}\` and execute the instructions defined there.${suffix}`;
|
|
528
|
+
prompt = `${workdirHint}Read the skill definition at \`${relSkillPath(wd, skillFile)}\` and execute the instructions defined there.${suffix}`;
|
|
483
529
|
}
|
|
484
530
|
else {
|
|
485
|
-
const fallbackPath =
|
|
531
|
+
const fallbackPath = relSkillPath(wd, path.join(wd, '.pikiloom', 'skills', skill.name, 'SKILL.md'));
|
|
486
532
|
prompt = `${workdirHint}Read the skill definition at \`${fallbackPath}\` and execute the instructions defined there.${suffix}`;
|
|
487
533
|
}
|
|
488
534
|
return { prompt, skillName: skill.name };
|
package/dist/bot/menu.js
CHANGED
|
@@ -31,6 +31,7 @@ export function indexSkillsByCommand(skills) {
|
|
|
31
31
|
export function buildDefaultMenuCommands(agentCount, skills = []) {
|
|
32
32
|
const commands = [
|
|
33
33
|
{ command: 'sessions', description: 'Switch sessions' },
|
|
34
|
+
{ command: 'digest', description: 'Recent session digest' },
|
|
34
35
|
];
|
|
35
36
|
if (agentCount > 1) {
|
|
36
37
|
commands.push({ command: 'agents', description: 'Switch agents' });
|
package/dist/bot/session-hub.js
CHANGED
|
@@ -121,7 +121,7 @@ function imageBlocksFromManagedRecord(record) {
|
|
|
121
121
|
const abs = path.isAbsolute(rel) ? rel : path.join(record.workspacePath, rel);
|
|
122
122
|
blocks.push({
|
|
123
123
|
type: 'image',
|
|
124
|
-
// `file://` sentinel — `
|
|
124
|
+
// `file://` sentinel — `rewriteAttachmentBlocksForTransport` (dashboard
|
|
125
125
|
// response layer) converts it to a proper /attachment URL.
|
|
126
126
|
content: `file://${abs}`,
|
|
127
127
|
imagePath: abs,
|
|
@@ -9,7 +9,7 @@ import { BOT_SHUTDOWN_FORCE_EXIT_MS, buildSessionTaskId } from '../../bot/orches
|
|
|
9
9
|
import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
10
10
|
import { expandTilde } from '../../core/platform.js';
|
|
11
11
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
12
|
-
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
12
|
+
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
13
13
|
import { DingtalkChannel } from './channel.js';
|
|
14
14
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
15
15
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -127,6 +127,7 @@ export class DingtalkBot extends Bot {
|
|
|
127
127
|
'/switch [path] - Change workdir',
|
|
128
128
|
'/workspaces [#] - Pick saved workspace',
|
|
129
129
|
'/sessions [new|#] - List/switch sessions',
|
|
130
|
+
'/digest - Recent session digest',
|
|
130
131
|
'/skills - List project skills',
|
|
131
132
|
'/stop - Stop current task',
|
|
132
133
|
'/restart - Restart pikiloom',
|
|
@@ -160,6 +161,9 @@ export class DingtalkBot extends Bot {
|
|
|
160
161
|
case 'sessions':
|
|
161
162
|
await this.cmdSessions(ctx, args);
|
|
162
163
|
return true;
|
|
164
|
+
case 'digest':
|
|
165
|
+
await this.cmdDigest(ctx);
|
|
166
|
+
return true;
|
|
163
167
|
case 'skills':
|
|
164
168
|
await this.cmdSkills(ctx);
|
|
165
169
|
return true;
|
|
@@ -187,6 +191,10 @@ export class DingtalkBot extends Bot {
|
|
|
187
191
|
lines.push('', 'Ready. Send a message to start.');
|
|
188
192
|
await ctx.reply(lines.join('\n'));
|
|
189
193
|
}
|
|
194
|
+
async cmdDigest(ctx) {
|
|
195
|
+
const data = await getSessionsDigestData(this, ctx.chatId);
|
|
196
|
+
await ctx.reply(formatSessionsDigestText(data));
|
|
197
|
+
}
|
|
190
198
|
async cmdStatus(ctx) {
|
|
191
199
|
const d = await getStatusDataAsync(this, ctx.chatId);
|
|
192
200
|
const gitLine = formatGitStatusLine(d.git);
|
|
@@ -13,7 +13,7 @@ import { BOT_SHUTDOWN_FORCE_EXIT_MS, buildSessionTaskId } from '../../bot/orches
|
|
|
13
13
|
import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
14
14
|
import { expandTilde } from '../../core/platform.js';
|
|
15
15
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
16
|
-
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
16
|
+
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
17
17
|
import { DiscordChannel } from './channel.js';
|
|
18
18
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
19
19
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -123,6 +123,7 @@ export class DiscordBot extends Bot {
|
|
|
123
123
|
'/switch [path] - Change workdir',
|
|
124
124
|
'/workspaces [#] - Pick saved workspace',
|
|
125
125
|
'/sessions [new|#] - List/switch sessions',
|
|
126
|
+
'/digest - Recent session digest',
|
|
126
127
|
'/skills - List project skills',
|
|
127
128
|
'/stop - Stop current task',
|
|
128
129
|
'/restart - Restart pikiloom',
|
|
@@ -156,6 +157,9 @@ export class DiscordBot extends Bot {
|
|
|
156
157
|
case 'sessions':
|
|
157
158
|
await this.cmdSessions(ctx, args);
|
|
158
159
|
return true;
|
|
160
|
+
case 'digest':
|
|
161
|
+
await this.cmdDigest(ctx);
|
|
162
|
+
return true;
|
|
159
163
|
case 'skills':
|
|
160
164
|
await this.cmdSkills(ctx);
|
|
161
165
|
return true;
|
|
@@ -183,6 +187,10 @@ export class DiscordBot extends Bot {
|
|
|
183
187
|
lines.push('', 'Ready. Send a message to start.');
|
|
184
188
|
await ctx.reply(lines.join('\n'));
|
|
185
189
|
}
|
|
190
|
+
async cmdDigest(ctx) {
|
|
191
|
+
const data = await getSessionsDigestData(this, ctx.chatId);
|
|
192
|
+
await ctx.reply(formatSessionsDigestText(data));
|
|
193
|
+
}
|
|
186
194
|
async cmdStatus(ctx) {
|
|
187
195
|
const d = await getStatusDataAsync(this, ctx.chatId);
|
|
188
196
|
const gitLine = formatGitStatusLine(d.git);
|
|
@@ -15,7 +15,7 @@ import { stageSessionFiles, } from '../../agent/index.js';
|
|
|
15
15
|
import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
16
16
|
import { expandTilde } from '../../core/platform.js';
|
|
17
17
|
import { SKILL_CMD_PREFIX, } from '../../bot/menu.js';
|
|
18
|
-
import { getStartData, getSessionsPageData, getModelsListData, getSessionTurnPreviewData, getStatusDataAsync, getHostDataSync, getWorkspacesData, resolveSkillPrompt, handleGoalCommand, } from '../../bot/commands.js';
|
|
18
|
+
import { getStartData, getSessionsPageData, getModelsListData, getSessionTurnPreviewData, getStatusDataAsync, getHostDataSync, getWorkspacesData, resolveSkillPrompt, handleGoalCommand, getSessionsDigestData, formatSessionsDigestText, } from '../../bot/commands.js';
|
|
19
19
|
import { buildAgentsCommandView, buildModelsCommandView, buildModeCommandView, buildSessionsCommandView, buildSkillsCommandView, decodeCommandAction, executeCommandAction, } from '../../bot/command-ui.js';
|
|
20
20
|
import { LivePreview } from '../telegram/live-preview.js';
|
|
21
21
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
@@ -355,6 +355,10 @@ export class FeishuBot extends Bot {
|
|
|
355
355
|
}
|
|
356
356
|
await this.sendCommandView(ctx, await buildSessionsCommandView(this, ctx.chatId, 0, this.sessionsPageSize));
|
|
357
357
|
}
|
|
358
|
+
async cmdDigest(ctx) {
|
|
359
|
+
const data = await getSessionsDigestData(this, ctx.chatId);
|
|
360
|
+
await ctx.reply(formatSessionsDigestText(data));
|
|
361
|
+
}
|
|
358
362
|
async cmdStatus(ctx) {
|
|
359
363
|
const d = await getStatusDataAsync(this, ctx.chatId);
|
|
360
364
|
await ctx.reply(renderStatus(d));
|
|
@@ -962,6 +966,9 @@ export class FeishuBot extends Bot {
|
|
|
962
966
|
case 'sessions':
|
|
963
967
|
await this.cmdSessions(ctx, args);
|
|
964
968
|
return;
|
|
969
|
+
case 'digest':
|
|
970
|
+
await this.cmdDigest(ctx);
|
|
971
|
+
return;
|
|
965
972
|
case 'agents':
|
|
966
973
|
await this.cmdAgents(ctx, args);
|
|
967
974
|
return;
|
|
@@ -13,7 +13,7 @@ import { BOT_SHUTDOWN_FORCE_EXIT_MS, buildSessionTaskId } from '../../bot/orches
|
|
|
13
13
|
import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
14
14
|
import { expandTilde } from '../../core/platform.js';
|
|
15
15
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
16
|
-
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
16
|
+
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
17
17
|
import { SlackChannel } from './channel.js';
|
|
18
18
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
19
19
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -131,6 +131,7 @@ export class SlackBot extends Bot {
|
|
|
131
131
|
'/switch [path] - Change workdir',
|
|
132
132
|
'/workspaces [#] - Pick saved workspace',
|
|
133
133
|
'/sessions [new|#] - List/switch sessions',
|
|
134
|
+
'/digest - Recent session digest',
|
|
134
135
|
'/skills - List project skills',
|
|
135
136
|
'/stop - Stop current task',
|
|
136
137
|
'/restart - Restart pikiloom',
|
|
@@ -165,6 +166,9 @@ export class SlackBot extends Bot {
|
|
|
165
166
|
case 'sessions':
|
|
166
167
|
await this.cmdSessions(ctx, args);
|
|
167
168
|
return true;
|
|
169
|
+
case 'digest':
|
|
170
|
+
await this.cmdDigest(ctx);
|
|
171
|
+
return true;
|
|
168
172
|
case 'skills':
|
|
169
173
|
await this.cmdSkills(ctx);
|
|
170
174
|
return true;
|
|
@@ -192,6 +196,10 @@ export class SlackBot extends Bot {
|
|
|
192
196
|
lines.push('', 'Ready. Send a message to start.');
|
|
193
197
|
await ctx.reply(lines.join('\n'));
|
|
194
198
|
}
|
|
199
|
+
async cmdDigest(ctx) {
|
|
200
|
+
const data = await getSessionsDigestData(this, ctx.chatId);
|
|
201
|
+
await ctx.reply(formatSessionsDigestText(data));
|
|
202
|
+
}
|
|
195
203
|
async cmdStatus(ctx) {
|
|
196
204
|
const d = await getStatusDataAsync(this, ctx.chatId);
|
|
197
205
|
const gitLine = formatGitStatusLine(d.git);
|
|
@@ -14,7 +14,7 @@ import { BOT_SHUTDOWN_FORCE_EXIT_MS, SessionMessageRegistry, buildBotMenuState,
|
|
|
14
14
|
import { stageSessionFiles, } from '../../agent/index.js';
|
|
15
15
|
import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
16
16
|
import { SKILL_CMD_PREFIX, } from '../../bot/menu.js';
|
|
17
|
-
import { getStartData, getStatusDataAsync, getHostDataSync, getSessionTurnPreviewData, getWorkspacesData, resolveSkillPrompt, summarizePromptForStatus, handleGoalCommand, } from '../../bot/commands.js';
|
|
17
|
+
import { getStartData, getStatusDataAsync, getHostDataSync, getSessionTurnPreviewData, getWorkspacesData, resolveSkillPrompt, summarizePromptForStatus, handleGoalCommand, getSessionsDigestData, formatSessionsDigestText, } from '../../bot/commands.js';
|
|
18
18
|
import { buildAgentsCommandView, buildModelsCommandView, buildModeCommandView, buildSessionsCommandView, buildSkillsCommandView, decodeCommandAction, executeCommandAction, } from '../../bot/command-ui.js';
|
|
19
19
|
import { buildSwitchWorkdirView, buildWorkspacesView, resolveRegisteredPath } from './directory.js';
|
|
20
20
|
import { LivePreview } from './live-preview.js';
|
|
@@ -353,6 +353,10 @@ export class TelegramBot extends Bot {
|
|
|
353
353
|
async cmdSessions(ctx) {
|
|
354
354
|
await this.sendCommandView(ctx, await buildSessionsCommandView(this, ctx.chatId, 0, this.sessionsPageSize));
|
|
355
355
|
}
|
|
356
|
+
async cmdDigest(ctx) {
|
|
357
|
+
const data = await getSessionsDigestData(this, ctx.chatId);
|
|
358
|
+
await ctx.reply(formatSessionsDigestText(data));
|
|
359
|
+
}
|
|
356
360
|
async cmdStatus(ctx) {
|
|
357
361
|
const d = await getStatusDataAsync(this, ctx.chatId);
|
|
358
362
|
const gitLine = formatGitStatusLine(d.git);
|
|
@@ -1167,6 +1171,9 @@ export class TelegramBot extends Bot {
|
|
|
1167
1171
|
case 'sessions':
|
|
1168
1172
|
await this.cmdSessions(ctx);
|
|
1169
1173
|
return;
|
|
1174
|
+
case 'digest':
|
|
1175
|
+
await this.cmdDigest(ctx);
|
|
1176
|
+
return;
|
|
1170
1177
|
case 'agents':
|
|
1171
1178
|
await this.cmdAgents(ctx);
|
|
1172
1179
|
return;
|
|
@@ -9,7 +9,7 @@ import { BOT_SHUTDOWN_FORCE_EXIT_MS, buildSessionTaskId } from '../../bot/orches
|
|
|
9
9
|
import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
10
10
|
import { expandTilde } from '../../core/platform.js';
|
|
11
11
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
12
|
-
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
12
|
+
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
13
13
|
import { WeComChannel } from './channel.js';
|
|
14
14
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
15
15
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -135,6 +135,7 @@ export class WeComBot extends Bot {
|
|
|
135
135
|
'/switch [path] - Change workdir',
|
|
136
136
|
'/workspaces [#] - Pick saved workspace',
|
|
137
137
|
'/sessions [new|#] - List/switch sessions',
|
|
138
|
+
'/digest - Recent session digest',
|
|
138
139
|
'/skills - List project skills',
|
|
139
140
|
'/stop - Stop current task',
|
|
140
141
|
'/restart - Restart pikiloom',
|
|
@@ -168,6 +169,9 @@ export class WeComBot extends Bot {
|
|
|
168
169
|
case 'sessions':
|
|
169
170
|
await this.cmdSessions(ctx, args);
|
|
170
171
|
return true;
|
|
172
|
+
case 'digest':
|
|
173
|
+
await this.cmdDigest(ctx);
|
|
174
|
+
return true;
|
|
171
175
|
case 'skills':
|
|
172
176
|
await this.cmdSkills(ctx);
|
|
173
177
|
return true;
|
|
@@ -195,6 +199,10 @@ export class WeComBot extends Bot {
|
|
|
195
199
|
lines.push('', 'Ready. Send a message to start.');
|
|
196
200
|
await ctx.reply(lines.join('\n'));
|
|
197
201
|
}
|
|
202
|
+
async cmdDigest(ctx) {
|
|
203
|
+
const data = await getSessionsDigestData(this, ctx.chatId);
|
|
204
|
+
await ctx.reply(formatSessionsDigestText(data));
|
|
205
|
+
}
|
|
198
206
|
async cmdStatus(ctx) {
|
|
199
207
|
const d = await getStatusDataAsync(this, ctx.chatId);
|
|
200
208
|
const gitLine = formatGitStatusLine(d.git);
|
|
@@ -11,7 +11,7 @@ import { BOT_SHUTDOWN_FORCE_EXIT_MS, buildSessionTaskId } from '../../bot/orches
|
|
|
11
11
|
import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
12
12
|
import { expandTilde } from '../../core/platform.js';
|
|
13
13
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
14
|
-
import { getStatusDataAsync, getHostDataSync, getModelsListData, getSessionsPageData, getStartData, getWorkspacesData, handleGoalCommand, } from '../../bot/commands.js';
|
|
14
|
+
import { getStatusDataAsync, getHostDataSync, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, handleGoalCommand, } from '../../bot/commands.js';
|
|
15
15
|
import { WeixinChannel } from './channel.js';
|
|
16
16
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
17
17
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -175,6 +175,7 @@ export class WeixinBot extends Bot {
|
|
|
175
175
|
'/switch [path] - Change workdir',
|
|
176
176
|
'/workspaces [#] - Pick saved workspace',
|
|
177
177
|
'/sessions [new|#] - List/switch sessions',
|
|
178
|
+
'/digest - Recent session digest',
|
|
178
179
|
'/skills - List & run project skills',
|
|
179
180
|
'/cancel - Cancel an active interactive prompt',
|
|
180
181
|
'/stop - Stop current task',
|
|
@@ -210,6 +211,9 @@ export class WeixinBot extends Bot {
|
|
|
210
211
|
case 'sessions':
|
|
211
212
|
await this.cmdSessions(ctx, args);
|
|
212
213
|
return true;
|
|
214
|
+
case 'digest':
|
|
215
|
+
await this.cmdDigest(ctx);
|
|
216
|
+
return true;
|
|
213
217
|
case 'skills':
|
|
214
218
|
await this.cmdSkills(ctx);
|
|
215
219
|
return true;
|
|
@@ -241,6 +245,10 @@ export class WeixinBot extends Bot {
|
|
|
241
245
|
lines.push('', 'Ready. Send a message to start.');
|
|
242
246
|
await ctx.reply(lines.join('\n'));
|
|
243
247
|
}
|
|
248
|
+
async cmdDigest(ctx) {
|
|
249
|
+
const data = await getSessionsDigestData(this, ctx.chatId);
|
|
250
|
+
await ctx.reply(formatSessionsDigestText(data));
|
|
251
|
+
}
|
|
244
252
|
async cmdStatus(ctx) {
|
|
245
253
|
const d = await getStatusDataAsync(this, ctx.chatId);
|
|
246
254
|
const gitLine = formatGitStatusLine(d.git);
|
package/dist/cli/main.js
CHANGED
|
@@ -292,6 +292,7 @@ Environment variables (per agent):
|
|
|
292
292
|
|
|
293
293
|
Bot commands (available once running):
|
|
294
294
|
/sessions List or switch coding sessions
|
|
295
|
+
/digest Show a compact digest of recent sessions
|
|
295
296
|
/agents List or switch AI agents
|
|
296
297
|
/models List or switch models
|
|
297
298
|
/status Bot status, uptime, and token usage
|