@openacp/cli 2026.330.2 → 2026.331.1
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 +17 -0
- package/dist/adapter-ELG3VRZ3.js +14 -0
- package/dist/{agent-catalog-SZQQERV7.js → agent-catalog-UYD26QDK.js} +3 -3
- package/dist/{api-client-XTLRRFPX.js → api-client-PEMHYL5U.js} +2 -2
- package/dist/{api-server-JLBDKCU4.js → api-server-DATG2KBR.js} +3 -3
- package/dist/api-server-L5Z7XACW.js +7 -0
- package/dist/chunk-23SRIVG4.js +50 -0
- package/dist/chunk-23SRIVG4.js.map +1 -0
- package/dist/{chunk-YIGBJFJL.js → chunk-7GXEMMEV.js} +15 -15
- package/dist/{chunk-QWVHCTCA.js → chunk-7U6IZIJP.js} +37 -23
- package/dist/chunk-7U6IZIJP.js.map +1 -0
- package/dist/{chunk-FCTC7KDT.js → chunk-7YIKTRSM.js} +14 -10
- package/dist/chunk-7YIKTRSM.js.map +1 -0
- package/dist/{chunk-MITTQMGZ.js → chunk-BYCJQPMN.js} +5 -5
- package/dist/chunk-BYCJQPMN.js.map +1 -0
- package/dist/{chunk-5ZNBNIK3.js → chunk-EWVXSTQK.js} +193 -53
- package/dist/chunk-EWVXSTQK.js.map +1 -0
- package/dist/{chunk-UWH7KIAA.js → chunk-FPKQYCQS.js} +88 -13
- package/dist/chunk-FPKQYCQS.js.map +1 -0
- package/dist/{chunk-GEOXPGCO.js → chunk-K6UY5M75.js} +12 -9
- package/dist/chunk-K6UY5M75.js.map +1 -0
- package/dist/{chunk-KDU3ZEWT.js → chunk-KGAQW6F4.js} +12 -3
- package/dist/chunk-KGAQW6F4.js.map +1 -0
- package/dist/{chunk-7RKPIM3E.js → chunk-LRV56K2M.js} +205 -16
- package/dist/chunk-LRV56K2M.js.map +1 -0
- package/dist/{chunk-V2YZWYXT.js → chunk-MDJHCCFS.js} +18 -17
- package/dist/chunk-MDJHCCFS.js.map +1 -0
- package/dist/chunk-NHD5XDD2.js +686 -0
- package/dist/chunk-NHD5XDD2.js.map +1 -0
- package/dist/{chunk-APS6UEFU.js → chunk-NJX75BLK.js} +1 -1
- package/dist/chunk-NJX75BLK.js.map +1 -0
- package/dist/{chunk-5HKQCYOI.js → chunk-NOEAJNTK.js} +14 -3
- package/dist/chunk-NOEAJNTK.js.map +1 -0
- package/dist/chunk-ON7HB5O7.js +58 -0
- package/dist/chunk-ON7HB5O7.js.map +1 -0
- package/dist/{chunk-5OCGO27U.js → chunk-OSBZXY2W.js} +2 -1
- package/dist/chunk-OSBZXY2W.js.map +1 -0
- package/dist/{chunk-PA6MNBG4.js → chunk-P3HHJANC.js} +32 -13
- package/dist/chunk-P3HHJANC.js.map +1 -0
- package/dist/{chunk-BTJHGSLM.js → chunk-R2YLDQLI.js} +9 -10
- package/dist/chunk-R2YLDQLI.js.map +1 -0
- package/dist/{chunk-CFUJGWOP.js → chunk-SSLVNCEA.js} +27 -3
- package/dist/chunk-SSLVNCEA.js.map +1 -0
- package/dist/{chunk-MPGEHTGE.js → chunk-TGP34LQN.js} +9 -7
- package/dist/chunk-TGP34LQN.js.map +1 -0
- package/dist/{chunk-TMVTSWVH.js → chunk-VUSCVRJL.js} +2 -1
- package/dist/chunk-VUSCVRJL.js.map +1 -0
- package/dist/chunk-XRJUS6FE.js +53 -0
- package/dist/chunk-XRJUS6FE.js.map +1 -0
- package/dist/{chunk-W4LK6WJP.js → chunk-YZCKSNRN.js} +24 -17
- package/dist/chunk-YZCKSNRN.js.map +1 -0
- package/dist/{chunk-3NAFXVQM.js → chunk-ZIRH6QWW.js} +7 -5
- package/dist/chunk-ZIRH6QWW.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +334 -140
- package/dist/cli.js.map +1 -1
- package/dist/config-X4UP7H6R.js +13 -0
- package/dist/config-editor-7BENRVG5.js +11 -0
- package/dist/{config-registry-ZXAIJNYB.js → config-registry-M3FFWEVM.js} +3 -2
- package/dist/context-FVGCU5TI.js +9 -0
- package/dist/core-plugins-JSY2I44L.js +25 -0
- package/dist/{daemon-XFEMMJSZ.js → daemon-UOSRDEXW.js} +8 -3
- package/dist/doctor-6DLACBR4.js +10 -0
- package/dist/{file-service-HHB3JQIO.js → file-service-FQQYME7M.js} +2 -2
- package/dist/index.d.ts +265 -32
- package/dist/index.js +44 -33
- package/dist/index.js.map +1 -1
- package/dist/{install-cloudflared-JRJ4BSOM.js → install-cloudflared-LNS5L5FR.js} +5 -4
- package/dist/install-cloudflared-LNS5L5FR.js.map +1 -0
- package/dist/{install-context-EHYV5WRY.js → install-context-KZO5FR4D.js} +4 -3
- package/dist/install-context-KZO5FR4D.js.map +1 -0
- package/dist/{install-jq-ISTGT263.js → install-jq-SN4IA5K4.js} +3 -3
- package/dist/instance-context-FLCE7VZ4.js +13 -0
- package/dist/instance-registry-SW5FWKHO.js +7 -0
- package/dist/{main-L2M4NTJY.js → main-D7M2AKRM.js} +91 -48
- package/dist/main-D7M2AKRM.js.map +1 -0
- package/dist/{plugin-create-EHL76ZZG.js → plugin-create-HFKS23JY.js} +4 -2
- package/dist/{plugin-create-EHL76ZZG.js.map → plugin-create-HFKS23JY.js.map} +1 -1
- package/dist/{post-upgrade-Y26S2ZQ7.js → post-upgrade-F4YPMTUT.js} +6 -6
- package/dist/{security-2BA265LN.js → security-O4XGN2CM.js} +2 -2
- package/dist/{setup-E6BNEYCS.js → setup-44WLBIOT.js} +209 -22
- package/dist/setup-44WLBIOT.js.map +1 -0
- package/dist/{speech-SG62JYIF.js → speech-GHTSWDAN.js} +2 -2
- package/dist/telegram-D7ASLVEB.js +7 -0
- package/dist/telegram-D7ASLVEB.js.map +1 -0
- package/dist/tunnel-ALJDPFDQ.js +10 -0
- package/dist/tunnel-ALJDPFDQ.js.map +1 -0
- package/dist/{tunnel-service-ZMO4THKE.js → tunnel-service-TBAHDXMF.js} +41 -547
- package/dist/tunnel-service-TBAHDXMF.js.map +1 -0
- package/package.json +1 -1
- package/dist/adapter-4U6MC5ZS.js +0 -13
- package/dist/api-server-5VNYFWJE.js +0 -7
- package/dist/chunk-3NAFXVQM.js.map +0 -1
- package/dist/chunk-4WXALZA3.js +0 -45
- package/dist/chunk-4WXALZA3.js.map +0 -1
- package/dist/chunk-5HKQCYOI.js.map +0 -1
- package/dist/chunk-5OCGO27U.js.map +0 -1
- package/dist/chunk-5ZNBNIK3.js.map +0 -1
- package/dist/chunk-7RKPIM3E.js.map +0 -1
- package/dist/chunk-APS6UEFU.js.map +0 -1
- package/dist/chunk-BTJHGSLM.js.map +0 -1
- package/dist/chunk-CFUJGWOP.js.map +0 -1
- package/dist/chunk-FCTC7KDT.js.map +0 -1
- package/dist/chunk-GEOXPGCO.js.map +0 -1
- package/dist/chunk-KDU3ZEWT.js.map +0 -1
- package/dist/chunk-MITTQMGZ.js.map +0 -1
- package/dist/chunk-MPGEHTGE.js.map +0 -1
- package/dist/chunk-PA6MNBG4.js.map +0 -1
- package/dist/chunk-QWVHCTCA.js.map +0 -1
- package/dist/chunk-TMVTSWVH.js.map +0 -1
- package/dist/chunk-UWH7KIAA.js.map +0 -1
- package/dist/chunk-V2YZWYXT.js.map +0 -1
- package/dist/chunk-W4LK6WJP.js.map +0 -1
- package/dist/config-KN6NKKPF.js +0 -20
- package/dist/config-editor-76RVZS4B.js +0 -10
- package/dist/context-NXXW62NJ.js +0 -9
- package/dist/core-plugins-OCHKGCIZ.js +0 -22
- package/dist/doctor-AV6AUO22.js +0 -9
- package/dist/install-cloudflared-JRJ4BSOM.js.map +0 -1
- package/dist/install-context-EHYV5WRY.js.map +0 -1
- package/dist/main-L2M4NTJY.js.map +0 -1
- package/dist/setup-E6BNEYCS.js.map +0 -1
- package/dist/telegram-EAVRDNFU.js +0 -7
- package/dist/tunnel-HWJ27WDH.js +0 -7
- package/dist/tunnel-service-ZMO4THKE.js.map +0 -1
- /package/dist/{adapter-4U6MC5ZS.js.map → adapter-ELG3VRZ3.js.map} +0 -0
- /package/dist/{agent-catalog-SZQQERV7.js.map → agent-catalog-UYD26QDK.js.map} +0 -0
- /package/dist/{api-client-XTLRRFPX.js.map → api-client-PEMHYL5U.js.map} +0 -0
- /package/dist/{api-server-5VNYFWJE.js.map → api-server-DATG2KBR.js.map} +0 -0
- /package/dist/{api-server-JLBDKCU4.js.map → api-server-L5Z7XACW.js.map} +0 -0
- /package/dist/{chunk-YIGBJFJL.js.map → chunk-7GXEMMEV.js.map} +0 -0
- /package/dist/{config-KN6NKKPF.js.map → config-X4UP7H6R.js.map} +0 -0
- /package/dist/{config-editor-76RVZS4B.js.map → config-editor-7BENRVG5.js.map} +0 -0
- /package/dist/{config-registry-ZXAIJNYB.js.map → config-registry-M3FFWEVM.js.map} +0 -0
- /package/dist/{context-NXXW62NJ.js.map → context-FVGCU5TI.js.map} +0 -0
- /package/dist/{core-plugins-OCHKGCIZ.js.map → core-plugins-JSY2I44L.js.map} +0 -0
- /package/dist/{daemon-XFEMMJSZ.js.map → daemon-UOSRDEXW.js.map} +0 -0
- /package/dist/{doctor-AV6AUO22.js.map → doctor-6DLACBR4.js.map} +0 -0
- /package/dist/{file-service-HHB3JQIO.js.map → file-service-FQQYME7M.js.map} +0 -0
- /package/dist/{install-jq-ISTGT263.js.map → install-jq-SN4IA5K4.js.map} +0 -0
- /package/dist/{security-2BA265LN.js.map → instance-context-FLCE7VZ4.js.map} +0 -0
- /package/dist/{speech-SG62JYIF.js.map → instance-registry-SW5FWKHO.js.map} +0 -0
- /package/dist/{post-upgrade-Y26S2ZQ7.js.map → post-upgrade-F4YPMTUT.js.map} +0 -0
- /package/dist/{telegram-EAVRDNFU.js.map → security-O4XGN2CM.js.map} +0 -0
- /package/dist/{tunnel-HWJ27WDH.js.map → speech-GHTSWDAN.js.map} +0 -0
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ContextManager,
|
|
3
3
|
EntireProvider
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BYCJQPMN.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_MAX_TOKENS,
|
|
7
7
|
TOKENS_PER_TURN_ESTIMATE
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NJX75BLK.js";
|
|
9
9
|
|
|
10
10
|
// src/plugins/context/index.ts
|
|
11
|
-
import * as os from "os";
|
|
12
11
|
import * as path2 from "path";
|
|
13
12
|
|
|
14
13
|
// src/plugins/context/history/history-context-builder.ts
|
|
@@ -243,19 +242,20 @@ var HistoryProvider = class {
|
|
|
243
242
|
return { ...EMPTY_RESULT };
|
|
244
243
|
}
|
|
245
244
|
const totalTurns = loaded.reduce((sum, s) => sum + s.history.turns.length, 0);
|
|
245
|
+
const labelAgent = options?.labelAgent ?? false;
|
|
246
246
|
let mode = selectLevel(totalTurns);
|
|
247
|
-
let markdown = this.buildMergedMarkdown(loaded, mode, query);
|
|
247
|
+
let markdown = this.buildMergedMarkdown(loaded, mode, query, labelAgent);
|
|
248
248
|
let tokenEstimate = estimateTokens(markdown);
|
|
249
249
|
if (tokenEstimate > maxTokens && mode !== "compact") {
|
|
250
250
|
mode = "compact";
|
|
251
|
-
markdown = this.buildMergedMarkdown(loaded, mode, query);
|
|
251
|
+
markdown = this.buildMergedMarkdown(loaded, mode, query, labelAgent);
|
|
252
252
|
tokenEstimate = estimateTokens(markdown);
|
|
253
253
|
}
|
|
254
254
|
let truncated = false;
|
|
255
255
|
let activeSessions = [...loaded];
|
|
256
256
|
while (tokenEstimate > maxTokens && activeSessions.length > 1) {
|
|
257
257
|
activeSessions = activeSessions.slice(0, activeSessions.length - 1);
|
|
258
|
-
markdown = this.buildMergedMarkdown(activeSessions, mode, query);
|
|
258
|
+
markdown = this.buildMergedMarkdown(activeSessions, mode, query, labelAgent);
|
|
259
259
|
tokenEstimate = estimateTokens(markdown);
|
|
260
260
|
truncated = true;
|
|
261
261
|
}
|
|
@@ -300,7 +300,7 @@ var HistoryProvider = class {
|
|
|
300
300
|
sessionId: record.sessionId
|
|
301
301
|
};
|
|
302
302
|
}
|
|
303
|
-
buildMergedMarkdown(sessions, mode, query) {
|
|
303
|
+
buildMergedMarkdown(sessions, mode, query, labelAgent = false) {
|
|
304
304
|
if (sessions.length === 0) return "";
|
|
305
305
|
const totalTurns = sessions.reduce((sum, s) => sum + s.history.turns.length, 0);
|
|
306
306
|
const title = query.type === "session" ? query.value : `latest ${sessions.length} sessions`;
|
|
@@ -310,11 +310,19 @@ var HistoryProvider = class {
|
|
|
310
310
|
parts.push("");
|
|
311
311
|
for (let i = 0; i < sessions.length; i++) {
|
|
312
312
|
const { record, history } = sessions[i];
|
|
313
|
-
const sessionMd = buildHistoryMarkdown(history.turns, mode);
|
|
314
313
|
parts.push(`## Session ${i + 1} \u2014 ${record.agentName} \xB7 ${record.sessionId} (${history.turns.length} turns)`);
|
|
315
314
|
parts.push("");
|
|
316
|
-
if (
|
|
317
|
-
|
|
315
|
+
if (labelAgent && history.turns.length > 0) {
|
|
316
|
+
const agentTimeline = this.buildAgentTimeline(record);
|
|
317
|
+
const labeledMd = this.buildLabeledHistoryMarkdown(history.turns, mode, agentTimeline);
|
|
318
|
+
if (labeledMd) {
|
|
319
|
+
parts.push(labeledMd);
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
const sessionMd = buildHistoryMarkdown(history.turns, mode);
|
|
323
|
+
if (sessionMd) {
|
|
324
|
+
parts.push(sessionMd);
|
|
325
|
+
}
|
|
318
326
|
}
|
|
319
327
|
}
|
|
320
328
|
parts.push(
|
|
@@ -322,6 +330,72 @@ var HistoryProvider = class {
|
|
|
322
330
|
);
|
|
323
331
|
return parts.join("\n");
|
|
324
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Build a timeline of agent boundaries from the session record.
|
|
335
|
+
* Returns sorted entries: [{ agentName, startedAt }] where startedAt is the
|
|
336
|
+
* ISO timestamp when that agent started handling the session.
|
|
337
|
+
*
|
|
338
|
+
* The first agent runs from session creation until the first switch.
|
|
339
|
+
* Each agentSwitchHistory entry records when the *previous* agent was switched away,
|
|
340
|
+
* so the next agent starts at that switchedAt timestamp.
|
|
341
|
+
*/
|
|
342
|
+
buildAgentTimeline(record) {
|
|
343
|
+
const timeline = [];
|
|
344
|
+
const firstAgentName = record.firstAgent ?? record.agentName;
|
|
345
|
+
timeline.push({ agentName: firstAgentName, switchedAt: 0 });
|
|
346
|
+
if (record.agentSwitchHistory && record.agentSwitchHistory.length > 0) {
|
|
347
|
+
for (let i = 0; i < record.agentSwitchHistory.length; i++) {
|
|
348
|
+
const entry = record.agentSwitchHistory[i];
|
|
349
|
+
const switchTime = new Date(entry.switchedAt).getTime();
|
|
350
|
+
const nextAgent = i < record.agentSwitchHistory.length - 1 ? record.agentSwitchHistory[i + 1].agentName : record.agentName;
|
|
351
|
+
timeline.push({ agentName: nextAgent, switchedAt: switchTime });
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return timeline;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Determine which agent produced a turn based on its timestamp and the agent timeline.
|
|
358
|
+
*/
|
|
359
|
+
resolveAgentForTurn(turnTimestamp, timeline) {
|
|
360
|
+
const turnTime = new Date(turnTimestamp).getTime();
|
|
361
|
+
for (let i = timeline.length - 1; i >= 0; i--) {
|
|
362
|
+
if (turnTime >= timeline[i].switchedAt) {
|
|
363
|
+
return timeline[i].agentName;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return timeline[0].agentName;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Build history markdown with agent labels inserted at agent boundaries.
|
|
370
|
+
*/
|
|
371
|
+
buildLabeledHistoryMarkdown(turns, mode, agentTimeline) {
|
|
372
|
+
if (agentTimeline.length <= 1) {
|
|
373
|
+
const label = `### [${agentTimeline[0]?.agentName ?? "unknown"}]
|
|
374
|
+
`;
|
|
375
|
+
const md = buildHistoryMarkdown(turns, mode);
|
|
376
|
+
return md ? label + "\n" + md : label;
|
|
377
|
+
}
|
|
378
|
+
const segments = [];
|
|
379
|
+
let currentAgent = "";
|
|
380
|
+
for (const turn of turns) {
|
|
381
|
+
const agent = this.resolveAgentForTurn(turn.timestamp, agentTimeline);
|
|
382
|
+
if (agent !== currentAgent) {
|
|
383
|
+
segments.push({ agentName: agent, turns: [] });
|
|
384
|
+
currentAgent = agent;
|
|
385
|
+
}
|
|
386
|
+
segments[segments.length - 1].turns.push(turn);
|
|
387
|
+
}
|
|
388
|
+
const parts = [];
|
|
389
|
+
for (const segment of segments) {
|
|
390
|
+
parts.push(`### [${segment.agentName}]`);
|
|
391
|
+
parts.push("");
|
|
392
|
+
const md = buildHistoryMarkdown(segment.turns, mode);
|
|
393
|
+
if (md) {
|
|
394
|
+
parts.push(md);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return parts.join("\n");
|
|
398
|
+
}
|
|
325
399
|
computeTimeRange(records) {
|
|
326
400
|
if (records.length === 0) return { start: "", end: "" };
|
|
327
401
|
const dates = records.map((r) => r.createdAt).filter(Boolean);
|
|
@@ -646,12 +720,13 @@ var contextPlugin = {
|
|
|
646
720
|
}
|
|
647
721
|
},
|
|
648
722
|
async setup(ctx) {
|
|
649
|
-
const historyDir = path2.join(
|
|
723
|
+
const historyDir = path2.join(ctx.instanceRoot, "history");
|
|
650
724
|
const store = new HistoryStore(historyDir);
|
|
651
725
|
const recorder = new HistoryRecorder(store);
|
|
652
726
|
const sessionManager = ctx.sessions;
|
|
653
727
|
const getRecords = () => sessionManager.listRecords();
|
|
654
|
-
const
|
|
728
|
+
const cachePath = path2.join(ctx.instanceRoot, "cache", "entire");
|
|
729
|
+
const manager = new ContextManager(cachePath);
|
|
655
730
|
manager.register(new HistoryProvider(store, getRecords));
|
|
656
731
|
manager.register(new EntireProvider());
|
|
657
732
|
ctx.registerService("context", manager);
|
|
@@ -698,4 +773,4 @@ var context_default = contextPlugin;
|
|
|
698
773
|
export {
|
|
699
774
|
context_default
|
|
700
775
|
};
|
|
701
|
-
//# sourceMappingURL=chunk-
|
|
776
|
+
//# sourceMappingURL=chunk-FPKQYCQS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/context/index.ts","../../src/plugins/context/history/history-context-builder.ts","../../src/plugins/context/history/history-provider.ts","../../src/plugins/context/history/history-recorder.ts","../../src/plugins/context/history/history-store.ts"],"sourcesContent":["import * as path from 'node:path'\nimport type { OpenACPPlugin, InstallContext } from '../../core/plugin/types.js'\nimport type { SessionRecord } from '../../core/types.js'\nimport { ContextManager } from './context-manager.js'\nimport { EntireProvider } from './entire/entire-provider.js'\nimport { HistoryProvider } from './history/history-provider.js'\nimport { HistoryRecorder } from './history/history-recorder.js'\nimport { HistoryStore } from './history/history-store.js'\n\nconst contextPlugin: OpenACPPlugin = {\n name: '@openacp/context',\n version: '1.0.0',\n description: 'Conversation context management with pluggable providers',\n essential: false,\n permissions: ['services:register', 'middleware:register', 'kernel:access'],\n\n async install(ctx: InstallContext) {\n const { settings, terminal } = ctx\n\n // No interactive prompts needed — save defaults\n await settings.setAll({ enabled: true })\n terminal.log.success('Context defaults saved')\n },\n\n async configure(ctx: InstallContext) {\n const { terminal, settings } = ctx\n const current = await settings.getAll()\n\n const toggle = await terminal.confirm({\n message: `Context service is ${current.enabled !== false ? 'enabled' : 'disabled'}. Toggle?`,\n initialValue: false,\n })\n if (toggle) {\n const newState = current.enabled === false\n await settings.set('enabled', newState)\n terminal.log.success(`Context service ${newState ? 'enabled' : 'disabled'}`)\n }\n },\n\n async uninstall(ctx: InstallContext, opts: { purge: boolean }) {\n if (opts.purge) {\n await ctx.settings.clear()\n ctx.terminal.log.success('Context settings cleared')\n }\n },\n\n async setup(ctx) {\n // History recording and context\n const historyDir = path.join(ctx.instanceRoot, 'history')\n const store = new HistoryStore(historyDir)\n const recorder = new HistoryRecorder(store)\n\n // Access session records via SessionManager (kernel:access)\n const sessionManager = ctx.sessions as { listRecords(): SessionRecord[] }\n const getRecords = () => sessionManager.listRecords()\n\n // Register providers — local first (priority), entire as fallback\n const cachePath = path.join(ctx.instanceRoot, 'cache', 'entire')\n const manager = new ContextManager(cachePath)\n manager.register(new HistoryProvider(store, getRecords))\n manager.register(new EntireProvider())\n ctx.registerService('context', manager)\n\n // Middleware: capture user prompts\n ctx.registerMiddleware('agent:beforePrompt', {\n priority: 200,\n handler: async (payload, next) => {\n recorder.onBeforePrompt(payload.sessionId, payload.text, payload.attachments)\n return next()\n },\n })\n\n // Middleware: capture agent events\n ctx.registerMiddleware('agent:afterEvent', {\n priority: 200,\n handler: async (payload, next) => {\n recorder.onAfterEvent(payload.sessionId, payload.event)\n return next()\n },\n })\n\n // Middleware: finalize turn and write to disk\n ctx.registerMiddleware('turn:end', {\n priority: 200,\n handler: async (payload, next) => {\n await recorder.onTurnEnd(payload.sessionId, payload.stopReason)\n return next()\n },\n })\n\n // Middleware: capture permission resolutions\n ctx.registerMiddleware('permission:afterResolve', {\n priority: 200,\n handler: async (payload, next) => {\n recorder.onPermissionResolved(payload.sessionId, payload.requestId, payload.decision)\n return next()\n },\n })\n\n // Middleware: clean up recorder memory on session destroy\n ctx.registerMiddleware('session:afterDestroy', {\n priority: 200,\n handler: async (payload, next) => {\n recorder.finalize(payload.sessionId)\n return next()\n },\n })\n\n ctx.log.info('Context service ready (local history + entire providers)')\n },\n}\n\nexport default contextPlugin\n","import type { ContextMode } from \"../context-provider.js\";\nimport type { Turn, Step, ToolCallStep } from \"./types.js\";\n\nexport function selectLevel(turnCount: number): ContextMode {\n if (turnCount <= 10) return \"full\";\n if (turnCount <= 25) return \"balanced\";\n return \"compact\";\n}\n\nexport function estimateTokens(text: string): number {\n return Math.floor(text.length / 4);\n}\n\nexport function buildHistoryMarkdown(turns: Turn[], mode: ContextMode): string {\n if (turns.length === 0) return \"\";\n switch (mode) {\n case \"full\":\n return buildFull(turns);\n case \"balanced\":\n return buildBalanced(turns);\n case \"compact\":\n return buildCompact(turns);\n }\n}\n\n// ─── Full Mode ───────────────────────────────────────────────────────────────\n\nfunction buildFull(turns: Turn[]): string {\n const out: string[] = [];\n let userIndex = 0;\n\n for (const turn of turns) {\n if (turn.role === \"user\") {\n userIndex++;\n out.push(`**User [${userIndex}]:**`);\n out.push(turn.content ?? \"\");\n if (turn.attachments?.length) {\n out.push(turn.attachments.map((a) => `[${a.type}: ${a.fileName}]`).join(\" \"));\n }\n out.push(\"\");\n } else if (turn.role === \"assistant\" && turn.steps?.length) {\n out.push(\"**Assistant:**\");\n\n for (const step of turn.steps) {\n out.push(renderStepFull(step));\n }\n\n if (turn.usage) {\n const parts: string[] = [];\n if (turn.usage.tokensUsed) parts.push(`${turn.usage.tokensUsed.toLocaleString()} tokens`);\n if (turn.usage.cost) parts.push(`$${turn.usage.cost.amount.toFixed(4)}`);\n if (parts.length) out.push(`**Usage**: ${parts.join(\", \")}`);\n }\n\n out.push(\"\");\n out.push(\"---\");\n out.push(\"\");\n }\n }\n\n return out.join(\"\\n\");\n}\n\nfunction renderStepFull(step: Step): string {\n switch (step.type) {\n case \"thinking\":\n return `> **Thinking**: ${step.content}\\n`;\n case \"text\":\n return `${step.content}\\n`;\n case \"tool_call\":\n return renderToolCallFull(step);\n case \"plan\":\n return renderPlan(step.entries);\n case \"image\":\n return `[Image: ${step.mimeType}]\\n`;\n case \"audio\":\n return `[Audio: ${step.mimeType}]\\n`;\n case \"resource\":\n return `[Resource: ${step.name}] ${step.uri}\\n`;\n case \"resource_link\":\n return `[Resource Link: ${step.name}] ${step.uri}\\n`;\n case \"mode_change\":\n return `*Mode changed to: ${step.modeId}*\\n`;\n case \"config_change\":\n return `*Config ${step.configId} set to: ${step.value}*\\n`;\n }\n}\n\nfunction renderToolCallFull(step: ToolCallStep): string {\n const lines: string[] = [];\n const loc = step.locations?.[0];\n const locStr = loc ? (loc.line ? `${loc.path}:${loc.line}` : loc.path) : \"\";\n\n if (step.diff) {\n lines.push(`**[${step.name}]** \\`${locStr || step.diff.path}\\``);\n lines.push(\"```diff\");\n if (step.diff.oldText) {\n for (const line of step.diff.oldText.split(\"\\n\")) lines.push(`- ${line}`);\n }\n for (const line of step.diff.newText.split(\"\\n\")) lines.push(`+ ${line}`);\n lines.push(\"```\");\n } else {\n lines.push(`**[${step.name}]** \\`${locStr}\\``);\n }\n\n if (step.permission) {\n lines.push(`*Permission: ${step.permission.outcome}*`);\n }\n\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\nfunction renderPlan(entries: { content: string; priority: string; status: string }[]): string {\n const lines = [\"**Plan:**\"];\n for (const e of entries) {\n const icon = e.status === \"completed\" || e.status === \"done\" ? \"✅\" : e.status === \"in_progress\" ? \"🔄\" : \"⬜\";\n lines.push(`${icon} ${e.content} (${e.priority})`);\n }\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\n// ─── Balanced Mode ───────────────────────────────────────────────────────────\n\nfunction buildBalanced(turns: Turn[]): string {\n const out: string[] = [];\n let userIndex = 0;\n\n for (const turn of turns) {\n if (turn.role === \"user\") {\n userIndex++;\n out.push(`**User [${userIndex}]:**`);\n out.push(turn.content ?? \"\");\n out.push(\"\");\n } else if (turn.role === \"assistant\" && turn.steps?.length) {\n out.push(\"**Assistant:**\");\n\n for (const step of turn.steps) {\n if (step.type === \"thinking\") continue;\n\n if (step.type === \"text\") {\n out.push(step.content);\n } else if (step.type === \"tool_call\") {\n out.push(renderToolCallBalanced(step));\n } else if (step.type === \"plan\") {\n out.push(renderPlan(step.entries));\n } else {\n out.push(renderStepFull(step));\n }\n }\n\n out.push(\"\");\n out.push(\"---\");\n out.push(\"\");\n }\n }\n\n return out.join(\"\\n\");\n}\n\nfunction renderToolCallBalanced(step: ToolCallStep): string {\n const loc = step.locations?.[0];\n const locStr = loc ? (loc.line ? `${loc.path}:${loc.line}` : loc.path) : \"\";\n\n if (step.diff) {\n const oldLines = step.diff.oldText?.split(\"\\n\").length ?? 0;\n const newLines = step.diff.newText.split(\"\\n\").length;\n return `- ${step.name} \\`${locStr || step.diff.path}\\` (-${oldLines}/+${newLines} lines)`;\n }\n\n return `- ${step.name} \\`${locStr}\\``;\n}\n\n// ─── Compact Mode ────────────────────────────────────────────────────────────\n\nfunction buildCompact(turns: Turn[]): string {\n const out: string[] = [];\n let i = 0;\n\n while (i < turns.length) {\n const turn = turns[i];\n if (turn.role === \"user\") {\n const userText = (turn.content ?? \"\").slice(0, 100);\n const nextTurn = turns[i + 1];\n if (nextTurn?.role === \"assistant\" && nextTurn.steps?.length) {\n const tools = nextTurn.steps\n .filter((s) => s.type === \"tool_call\")\n .map((s) => (s as ToolCallStep).name);\n const texts = nextTurn.steps\n .filter((s) => s.type === \"text\")\n .map((s) => (s as { content: string }).content.slice(0, 80));\n const parts: string[] = [];\n if (tools.length) parts.push(tools.join(\", \"));\n if (texts.length) parts.push(texts.join(\" \"));\n out.push(`User: ${userText} → Assistant: ${parts.join(\" | \")}`);\n i += 2;\n } else {\n out.push(`User: ${userText}`);\n i++;\n }\n } else {\n i++;\n }\n }\n\n return out.join(\"\\n\");\n}\n","import type { SessionRecord } from \"../../../core/types.js\";\nimport type {\n ContextProvider,\n ContextQuery,\n ContextOptions,\n ContextResult,\n ContextMode,\n SessionInfo,\n SessionListResult,\n} from \"../context-provider.js\";\nimport { DEFAULT_MAX_TOKENS, TOKENS_PER_TURN_ESTIMATE } from \"../context-provider.js\";\nimport { HistoryStore } from \"./history-store.js\";\nimport {\n buildHistoryMarkdown,\n selectLevel,\n estimateTokens,\n} from \"./history-context-builder.js\";\n\nconst EMPTY_RESULT: ContextResult = {\n markdown: \"\",\n tokenEstimate: 0,\n sessionCount: 0,\n totalTurns: 0,\n mode: \"full\",\n truncated: false,\n timeRange: { start: \"\", end: \"\" },\n};\n\nexport class HistoryProvider implements ContextProvider {\n readonly name = \"local\";\n\n constructor(\n private readonly store: HistoryStore,\n private readonly getSessionRecords: () => SessionRecord[]\n ) {}\n\n async isAvailable(_repoPath: string): Promise<boolean> {\n return true;\n }\n\n async listSessions(query: ContextQuery): Promise<SessionListResult> {\n if (!this.isSupportedType(query.type)) {\n return { sessions: [], estimatedTokens: 0 };\n }\n\n const candidates = await this.resolveCandidates(query);\n const sessions: SessionInfo[] = [];\n let estimatedTokens = 0;\n\n for (const record of candidates) {\n const history = await this.store.read(record.sessionId);\n if (!history) continue;\n const turnCount = history.turns.length;\n const tokenEstimate = turnCount * TOKENS_PER_TURN_ESTIMATE;\n sessions.push(this.toSessionInfo(record, turnCount));\n estimatedTokens += tokenEstimate;\n }\n\n return { sessions, estimatedTokens };\n }\n\n async buildContext(query: ContextQuery, options?: ContextOptions): Promise<ContextResult> {\n if (!this.isSupportedType(query.type)) {\n return { ...EMPTY_RESULT };\n }\n\n const maxTokens = options?.maxTokens ?? DEFAULT_MAX_TOKENS;\n const candidates = await this.resolveCandidates(query, options?.limit);\n\n // Load histories for sessions that have files\n type LoadedSession = {\n record: SessionRecord;\n history: import(\"./types.js\").SessionHistory;\n };\n\n const loaded: LoadedSession[] = [];\n for (const record of candidates) {\n const history = await this.store.read(record.sessionId);\n if (history) {\n loaded.push({ record, history });\n }\n }\n\n if (loaded.length === 0) {\n return { ...EMPTY_RESULT };\n }\n\n const totalTurns = loaded.reduce((sum, s) => sum + s.history.turns.length, 0);\n const labelAgent = options?.labelAgent ?? false;\n\n // Auto-select mode based on total turn count\n let mode: ContextMode = selectLevel(totalTurns);\n\n // Build markdown with selected mode\n let markdown = this.buildMergedMarkdown(loaded, mode, query, labelAgent);\n let tokenEstimate = estimateTokens(markdown);\n\n // Downgrade to compact if over budget\n if (tokenEstimate > maxTokens && mode !== \"compact\") {\n mode = \"compact\";\n markdown = this.buildMergedMarkdown(loaded, mode, query, labelAgent);\n tokenEstimate = estimateTokens(markdown);\n }\n\n // Truncate oldest sessions if still over budget\n let truncated = false;\n let activeSessions = [...loaded];\n while (tokenEstimate > maxTokens && activeSessions.length > 1) {\n // Remove the oldest session (last in list, sorted newest-first)\n activeSessions = activeSessions.slice(0, activeSessions.length - 1);\n markdown = this.buildMergedMarkdown(activeSessions, mode, query, labelAgent);\n tokenEstimate = estimateTokens(markdown);\n truncated = true;\n }\n\n const timeRange = this.computeTimeRange(activeSessions.map((s) => s.record));\n\n return {\n markdown,\n tokenEstimate,\n sessionCount: activeSessions.length,\n totalTurns: activeSessions.reduce((sum, s) => sum + s.history.turns.length, 0),\n mode,\n truncated,\n timeRange,\n };\n }\n\n // ─── Private helpers ─────────────────────────────────────────────────────────\n\n private isSupportedType(type: ContextQuery[\"type\"]): boolean {\n return type === \"session\" || type === \"latest\";\n }\n\n private async resolveCandidates(query: ContextQuery, limit?: number): Promise<SessionRecord[]> {\n const all = this.getSessionRecords();\n\n if (query.type === \"session\") {\n const found = all.find((r) => r.sessionId === query.value);\n return found ? [found] : [];\n }\n\n // latest: sort by lastActiveAt descending, take N\n const n = limit ?? (parseInt(query.value, 10) || 5);\n const sorted = [...all].sort(\n (a, b) => new Date(b.lastActiveAt).getTime() - new Date(a.lastActiveAt).getTime()\n );\n return sorted.slice(0, n);\n }\n\n private toSessionInfo(record: SessionRecord, turnCount: number): SessionInfo {\n return {\n checkpointId: \"\",\n sessionIndex: \"\",\n transcriptPath: \"\",\n createdAt: record.createdAt,\n endedAt: record.lastActiveAt,\n branch: \"\",\n agent: record.agentName,\n turnCount,\n filesTouched: [],\n sessionId: record.sessionId,\n };\n }\n\n private buildMergedMarkdown(\n sessions: Array<{ record: SessionRecord; history: import(\"./types.js\").SessionHistory }>,\n mode: ContextMode,\n query: ContextQuery,\n labelAgent = false\n ): string {\n if (sessions.length === 0) return \"\";\n\n const totalTurns = sessions.reduce((sum, s) => sum + s.history.turns.length, 0);\n const title = query.type === \"session\" ? query.value : `latest ${sessions.length} sessions`;\n\n const parts: string[] = [];\n parts.push(`# Conversation History — ${title}`);\n parts.push(`${sessions.length} sessions | ${totalTurns} turns | mode: ${mode}`);\n parts.push(\"\");\n\n for (let i = 0; i < sessions.length; i++) {\n const { record, history } = sessions[i];\n\n parts.push(`## Session ${i + 1} — ${record.agentName} · ${record.sessionId} (${history.turns.length} turns)`);\n parts.push(\"\");\n\n if (labelAgent && history.turns.length > 0) {\n const agentTimeline = this.buildAgentTimeline(record);\n const labeledMd = this.buildLabeledHistoryMarkdown(history.turns, mode, agentTimeline);\n if (labeledMd) {\n parts.push(labeledMd);\n }\n } else {\n const sessionMd = buildHistoryMarkdown(history.turns, mode);\n if (sessionMd) {\n parts.push(sessionMd);\n }\n }\n }\n\n parts.push(\n \"> **Note:** This conversation history may contain outdated information. Verify current state before acting on past context.\"\n );\n\n return parts.join(\"\\n\");\n }\n\n /**\n * Build a timeline of agent boundaries from the session record.\n * Returns sorted entries: [{ agentName, startedAt }] where startedAt is the\n * ISO timestamp when that agent started handling the session.\n *\n * The first agent runs from session creation until the first switch.\n * Each agentSwitchHistory entry records when the *previous* agent was switched away,\n * so the next agent starts at that switchedAt timestamp.\n */\n private buildAgentTimeline(record: SessionRecord): Array<{ agentName: string; switchedAt: number }> {\n const timeline: Array<{ agentName: string; switchedAt: number }> = [];\n\n // The first agent starts at the beginning of time (0)\n const firstAgentName = record.firstAgent ?? record.agentName;\n timeline.push({ agentName: firstAgentName, switchedAt: 0 });\n\n if (record.agentSwitchHistory && record.agentSwitchHistory.length > 0) {\n // Each entry in agentSwitchHistory records a *completed* agent stint:\n // { agentName: \"claude\", switchedAt: \"...\", ... } means claude was active\n // and was switched away at switchedAt. The next agent in sequence starts at that time.\n //\n // To reconstruct: after the last switchHistory entry, the current record.agentName is active.\n // But we need to map turns to agents, so we build boundaries.\n\n for (let i = 0; i < record.agentSwitchHistory.length; i++) {\n const entry = record.agentSwitchHistory[i];\n const switchTime = new Date(entry.switchedAt).getTime();\n\n // Determine which agent comes after this switch\n const nextAgent = i < record.agentSwitchHistory.length - 1\n ? record.agentSwitchHistory[i + 1].agentName\n : record.agentName; // current agent is the last one\n\n timeline.push({ agentName: nextAgent, switchedAt: switchTime });\n }\n }\n\n return timeline;\n }\n\n /**\n * Determine which agent produced a turn based on its timestamp and the agent timeline.\n */\n private resolveAgentForTurn(\n turnTimestamp: string,\n timeline: Array<{ agentName: string; switchedAt: number }>\n ): string {\n const turnTime = new Date(turnTimestamp).getTime();\n\n // Walk backward through the timeline to find the last boundary before this turn\n for (let i = timeline.length - 1; i >= 0; i--) {\n if (turnTime >= timeline[i].switchedAt) {\n return timeline[i].agentName;\n }\n }\n\n // Fallback to first agent\n return timeline[0].agentName;\n }\n\n /**\n * Build history markdown with agent labels inserted at agent boundaries.\n */\n private buildLabeledHistoryMarkdown(\n turns: import(\"./types.js\").Turn[],\n mode: ContextMode,\n agentTimeline: Array<{ agentName: string; switchedAt: number }>\n ): string {\n // If there's only one agent (no switches), just add a single label\n if (agentTimeline.length <= 1) {\n const label = `### [${agentTimeline[0]?.agentName ?? \"unknown\"}]\\n`;\n const md = buildHistoryMarkdown(turns, mode);\n return md ? label + \"\\n\" + md : label;\n }\n\n // Group turns by agent segments, then render each segment with a label\n const segments: Array<{ agentName: string; turns: import(\"./types.js\").Turn[] }> = [];\n let currentAgent = \"\";\n\n for (const turn of turns) {\n const agent = this.resolveAgentForTurn(turn.timestamp, agentTimeline);\n if (agent !== currentAgent) {\n segments.push({ agentName: agent, turns: [] });\n currentAgent = agent;\n }\n segments[segments.length - 1].turns.push(turn);\n }\n\n const parts: string[] = [];\n for (const segment of segments) {\n parts.push(`### [${segment.agentName}]`);\n parts.push(\"\");\n const md = buildHistoryMarkdown(segment.turns, mode);\n if (md) {\n parts.push(md);\n }\n }\n\n return parts.join(\"\\n\");\n }\n\n private computeTimeRange(\n records: SessionRecord[]\n ): { start: string; end: string } {\n if (records.length === 0) return { start: \"\", end: \"\" };\n\n const dates = records.map((r) => r.createdAt).filter(Boolean);\n const ends = records.map((r) => r.lastActiveAt).filter(Boolean);\n\n const start = dates.sort()[0] ?? \"\";\n const end = ends.sort().reverse()[0] ?? \"\";\n\n return { start, end };\n }\n}\n","import type { AgentEvent, Attachment } from \"../../../core/types.js\";\nimport type { HistoryStore } from \"./history-store.js\";\nimport type {\n HistoryAttachment,\n ResourceLinkStep,\n ResourceStep,\n SessionHistory,\n Step,\n ToolCallStep,\n Turn,\n} from \"./types.js\";\n\nexport interface RecorderState {\n history: SessionHistory;\n currentAssistantTurn: Turn | null;\n}\n\nfunction toHistoryAttachment(att: Attachment): HistoryAttachment {\n return {\n type: att.type,\n fileName: att.fileName,\n mimeType: att.mimeType,\n size: att.size,\n };\n}\n\nfunction extractDiff(\n content: unknown,\n): { path: string; oldText?: string; newText: string } | null {\n if (!Array.isArray(content)) return null;\n for (const item of content) {\n if (\n item &&\n typeof item === \"object\" &&\n (item as Record<string, unknown>).type === \"diff\"\n ) {\n const d = item as Record<string, unknown>;\n if (typeof d.path === \"string\" && typeof d.newText === \"string\") {\n const result: { path: string; oldText?: string; newText: string } = {\n path: d.path,\n newText: d.newText,\n };\n if (typeof d.oldText === \"string\") result.oldText = d.oldText;\n return result;\n }\n }\n }\n return null;\n}\n\nfunction extractLocations(\n locations: unknown,\n): { path: string; line?: number }[] | undefined {\n if (!Array.isArray(locations)) return undefined;\n const result: { path: string; line?: number }[] = [];\n for (const loc of locations) {\n if (loc && typeof loc === \"object\" && typeof (loc as any).path === \"string\") {\n const entry: { path: string; line?: number } = { path: (loc as any).path };\n if (typeof (loc as any).line === \"number\") entry.line = (loc as any).line;\n result.push(entry);\n }\n }\n return result.length > 0 ? result : undefined;\n}\n\nconst IGNORED_TYPES = new Set([\n \"session_end\",\n \"error\",\n \"system_message\",\n \"commands_update\",\n \"session_info_update\",\n \"model_update\",\n \"user_message_chunk\",\n \"tts_strip\",\n]);\n\nexport class HistoryRecorder {\n private states = new Map<string, RecorderState>();\n\n constructor(private readonly store: HistoryStore) {}\n\n onBeforePrompt(\n sessionId: string,\n text: string,\n attachments: Attachment[] | undefined,\n ): void {\n let state = this.states.get(sessionId);\n if (!state) {\n state = {\n history: { version: 1, sessionId, turns: [] },\n currentAssistantTurn: null,\n };\n this.states.set(sessionId, state);\n }\n\n const userTurn: Turn = {\n index: state.history.turns.length,\n role: \"user\",\n timestamp: new Date().toISOString(),\n content: text,\n };\n if (attachments && attachments.length > 0) {\n userTurn.attachments = attachments.map(toHistoryAttachment);\n }\n state.history.turns.push(userTurn);\n\n const assistantTurn: Turn = {\n index: state.history.turns.length,\n role: \"assistant\",\n timestamp: new Date().toISOString(),\n steps: [],\n };\n state.history.turns.push(assistantTurn);\n state.currentAssistantTurn = assistantTurn;\n }\n\n onAfterEvent(sessionId: string, event: AgentEvent): void {\n const state = this.states.get(sessionId);\n if (!state || !state.currentAssistantTurn) return;\n\n const turn = state.currentAssistantTurn;\n const steps = turn.steps!;\n\n if (IGNORED_TYPES.has(event.type)) return;\n\n switch (event.type) {\n case \"text\": {\n const last = steps[steps.length - 1];\n if (last && last.type === \"text\") {\n last.content += event.content;\n } else {\n steps.push({ type: \"text\", content: event.content });\n }\n break;\n }\n\n case \"thought\": {\n const last = steps[steps.length - 1];\n if (last && last.type === \"thinking\") {\n last.content += event.content;\n } else {\n steps.push({ type: \"thinking\", content: event.content });\n }\n break;\n }\n\n case \"tool_call\": {\n const step: ToolCallStep = {\n type: \"tool_call\",\n id: event.id,\n name: event.name,\n status: event.status,\n };\n if (event.kind) step.kind = event.kind;\n steps.push(step);\n break;\n }\n\n case \"tool_update\": {\n const existing = this.findToolCall(steps, event.id);\n if (!existing) break;\n existing.status = event.status;\n if (event.rawInput !== undefined) existing.input = event.rawInput;\n if (event.rawOutput !== undefined) existing.output = event.rawOutput;\n if (event.content !== undefined) {\n const diff = extractDiff(event.content);\n if (diff) existing.diff = diff;\n }\n if (event.locations !== undefined) {\n const locs = extractLocations(event.locations);\n if (locs) existing.locations = locs;\n }\n break;\n }\n\n case \"plan\": {\n steps.push({\n type: \"plan\",\n entries: event.entries.map((e) => ({\n content: e.content,\n priority: e.priority,\n status: e.status,\n })),\n });\n break;\n }\n\n case \"usage\": {\n turn.usage = {};\n if (event.tokensUsed !== undefined) turn.usage.tokensUsed = event.tokensUsed;\n if (event.contextSize !== undefined) turn.usage.contextSize = event.contextSize;\n if (event.cost) turn.usage.cost = event.cost;\n break;\n }\n\n case \"image_content\": {\n steps.push({\n type: \"image\",\n mimeType: event.mimeType,\n filePath: \"\",\n });\n break;\n }\n\n case \"audio_content\": {\n steps.push({\n type: \"audio\",\n mimeType: event.mimeType,\n filePath: \"\",\n });\n break;\n }\n\n case \"resource_content\": {\n const step: ResourceStep = {\n type: \"resource\",\n uri: event.uri,\n name: event.name,\n };\n if (event.text !== undefined) step.text = event.text;\n steps.push(step);\n break;\n }\n\n case \"resource_link\": {\n const step: ResourceLinkStep = {\n type: \"resource_link\",\n uri: event.uri,\n name: event.name,\n };\n if (event.title !== undefined) step.title = event.title;\n if (event.description !== undefined)\n step.description = event.description;\n steps.push(step);\n break;\n }\n\n case \"current_mode_update\": {\n steps.push({ type: \"mode_change\", modeId: event.modeId });\n break;\n }\n\n case \"config_option_update\": {\n for (const opt of event.options) {\n steps.push({\n type: \"config_change\",\n configId: opt.id,\n value: String(opt.currentValue),\n });\n }\n break;\n }\n }\n }\n\n onPermissionResolved(\n sessionId: string,\n requestId: string,\n decision: string,\n ): void {\n const state = this.states.get(sessionId);\n if (!state || !state.currentAssistantTurn) return;\n const step = this.findToolCall(state.currentAssistantTurn.steps!, requestId);\n if (!step) return;\n step.permission = { requested: true, outcome: decision };\n }\n\n async onTurnEnd(sessionId: string, stopReason: string): Promise<void> {\n const state = this.states.get(sessionId);\n if (!state || !state.currentAssistantTurn) return;\n state.currentAssistantTurn.stopReason = stopReason;\n state.currentAssistantTurn = null;\n await this.store.write(state.history);\n }\n\n finalize(sessionId: string): void {\n this.states.delete(sessionId);\n }\n\n getState(sessionId: string): RecorderState | undefined {\n return this.states.get(sessionId);\n }\n\n private findToolCall(steps: Step[], id: string): ToolCallStep | undefined {\n for (let i = steps.length - 1; i >= 0; i--) {\n const s = steps[i];\n if (s.type === \"tool_call\" && s.id === id) return s;\n }\n return undefined;\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { SessionHistory } from \"./types.js\";\n\nexport class HistoryStore {\n constructor(private readonly dir: string) {}\n\n async write(history: SessionHistory): Promise<void> {\n await fs.promises.mkdir(this.dir, { recursive: true });\n const filePath = this.filePath(history.sessionId);\n await fs.promises.writeFile(filePath, JSON.stringify(history, null, 2));\n }\n\n async read(sessionId: string): Promise<SessionHistory | null> {\n const filePath = this.filePath(sessionId);\n try {\n const raw = await fs.promises.readFile(filePath, \"utf-8\");\n return JSON.parse(raw) as SessionHistory;\n } catch {\n return null;\n }\n }\n\n async exists(sessionId: string): Promise<boolean> {\n try {\n await fs.promises.access(this.filePath(sessionId));\n return true;\n } catch {\n return false;\n }\n }\n\n async list(): Promise<string[]> {\n try {\n const files = await fs.promises.readdir(this.dir);\n return files\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => f.replace(/\\.json$/, \"\"));\n } catch {\n return [];\n }\n }\n\n async delete(sessionId: string): Promise<void> {\n try {\n await fs.promises.unlink(this.filePath(sessionId));\n } catch {\n // file may not exist — safe to ignore\n }\n }\n\n private filePath(sessionId: string): string {\n return path.join(this.dir, `${sessionId}.json`);\n }\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -3,12 +3,14 @@ import {
|
|
|
3
3
|
ConfigSchema,
|
|
4
4
|
applyMigrations,
|
|
5
5
|
expandHome
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YZCKSNRN.js";
|
|
7
|
+
import {
|
|
8
|
+
getGlobalRoot
|
|
9
|
+
} from "./chunk-ON7HB5O7.js";
|
|
7
10
|
|
|
8
11
|
// src/core/doctor/index.ts
|
|
9
12
|
import * as fs8 from "fs";
|
|
10
13
|
import * as path4 from "path";
|
|
11
|
-
import * as os2 from "os";
|
|
12
14
|
|
|
13
15
|
// src/core/doctor/checks/config.ts
|
|
14
16
|
import * as fs from "fs";
|
|
@@ -493,9 +495,6 @@ import * as fs7 from "fs";
|
|
|
493
495
|
import * as path3 from "path";
|
|
494
496
|
import * as os from "os";
|
|
495
497
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
496
|
-
var BIN_DIR = path3.join(os.homedir(), ".openacp", "bin");
|
|
497
|
-
var BIN_NAME = os.platform() === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
498
|
-
var BIN_PATH = path3.join(BIN_DIR, BIN_NAME);
|
|
499
498
|
var tunnelCheck = {
|
|
500
499
|
name: "Tunnel",
|
|
501
500
|
order: 8,
|
|
@@ -512,8 +511,10 @@ var tunnelCheck = {
|
|
|
512
511
|
const provider = ctx.config.tunnel.provider;
|
|
513
512
|
results.push({ status: "pass", message: `Tunnel provider: ${provider}` });
|
|
514
513
|
if (provider === "cloudflare") {
|
|
514
|
+
const binName = os.platform() === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
515
|
+
const binPath = path3.join(ctx.dataDir, "bin", binName);
|
|
515
516
|
let found = false;
|
|
516
|
-
if (fs7.existsSync(
|
|
517
|
+
if (fs7.existsSync(binPath)) {
|
|
517
518
|
found = true;
|
|
518
519
|
} else {
|
|
519
520
|
try {
|
|
@@ -532,7 +533,7 @@ var tunnelCheck = {
|
|
|
532
533
|
fixRisk: "safe",
|
|
533
534
|
fix: async () => {
|
|
534
535
|
try {
|
|
535
|
-
const { ensureCloudflared } = await import("./install-cloudflared-
|
|
536
|
+
const { ensureCloudflared } = await import("./install-cloudflared-LNS5L5FR.js");
|
|
536
537
|
await ensureCloudflared();
|
|
537
538
|
return { success: true, message: "installed cloudflared" };
|
|
538
539
|
} catch (err) {
|
|
@@ -566,8 +567,10 @@ var ALL_CHECKS = [
|
|
|
566
567
|
var CHECK_TIMEOUT_MS = 1e4;
|
|
567
568
|
var DoctorEngine = class {
|
|
568
569
|
dryRun;
|
|
570
|
+
dataDir;
|
|
569
571
|
constructor(options) {
|
|
570
572
|
this.dryRun = options?.dryRun ?? false;
|
|
573
|
+
this.dataDir = options?.dataDir ?? getGlobalRoot();
|
|
571
574
|
}
|
|
572
575
|
async runAll() {
|
|
573
576
|
const ctx = await this.buildContext();
|
|
@@ -617,7 +620,7 @@ var DoctorEngine = class {
|
|
|
617
620
|
return { categories, summary, pendingFixes };
|
|
618
621
|
}
|
|
619
622
|
async buildContext() {
|
|
620
|
-
const dataDir =
|
|
623
|
+
const dataDir = this.dataDir;
|
|
621
624
|
const configPath = process.env.OPENACP_CONFIG_PATH || path4.join(dataDir, "config.json");
|
|
622
625
|
let config = null;
|
|
623
626
|
let rawConfig = null;
|
|
@@ -647,4 +650,4 @@ var DoctorEngine = class {
|
|
|
647
650
|
export {
|
|
648
651
|
DoctorEngine
|
|
649
652
|
};
|
|
650
|
-
//# sourceMappingURL=chunk-
|
|
653
|
+
//# sourceMappingURL=chunk-K6UY5M75.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/doctor/index.ts","../../src/core/doctor/checks/config.ts","../../src/core/doctor/checks/agents.ts","../../src/core/doctor/checks/telegram.ts","../../src/core/doctor/checks/storage.ts","../../src/core/doctor/checks/workspace.ts","../../src/core/doctor/checks/plugins.ts","../../src/core/doctor/checks/daemon.ts","../../src/core/doctor/checks/tunnel.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { DoctorCheck, DoctorContext, DoctorReport, CategoryResult, PendingFix, CheckResult } from \"./types.js\";\nimport { ConfigManager, expandHome } from \"../config/config.js\";\nimport { getGlobalRoot } from \"../instance-context.js\";\n\nimport { configCheck } from \"./checks/config.js\";\nimport { agentsCheck } from \"./checks/agents.js\";\nimport { telegramCheck } from \"./checks/telegram.js\";\nimport { storageCheck } from \"./checks/storage.js\";\nimport { workspaceCheck } from \"./checks/workspace.js\";\nimport { pluginsCheck } from \"./checks/plugins.js\";\nimport { daemonCheck } from \"./checks/daemon.js\";\nimport { tunnelCheck } from \"./checks/tunnel.js\";\n\nconst ALL_CHECKS: DoctorCheck[] = [\n configCheck,\n agentsCheck,\n telegramCheck,\n storageCheck,\n workspaceCheck,\n pluginsCheck,\n daemonCheck,\n tunnelCheck,\n];\n\nconst CHECK_TIMEOUT_MS = 10_000;\n\nexport class DoctorEngine {\n private dryRun: boolean;\n private dataDir: string;\n\n constructor(options?: { dryRun?: boolean; dataDir?: string }) {\n this.dryRun = options?.dryRun ?? false;\n this.dataDir = options?.dataDir ?? getGlobalRoot();\n }\n\n async runAll(): Promise<DoctorReport> {\n const ctx = await this.buildContext();\n const checks = [...ALL_CHECKS].sort((a, b) => a.order - b.order);\n\n const categories: CategoryResult[] = [];\n const pendingFixes: PendingFix[] = [];\n const summary = { passed: 0, warnings: 0, failed: 0, fixed: 0 };\n\n for (const check of checks) {\n let results: CheckResult[];\n try {\n results = await Promise.race([\n check.run(ctx),\n new Promise<CheckResult[]>((_, reject) =>\n setTimeout(() => reject(new Error(\"timeout\")), CHECK_TIMEOUT_MS),\n ),\n ]);\n } catch {\n results = [{ status: \"fail\", message: `${check.name} check timed out` }];\n }\n\n for (const result of results) {\n if (result.fixable && result.fix) {\n if (result.fixRisk === \"safe\" && !this.dryRun) {\n try {\n const fixResult = await result.fix();\n if (fixResult.success) {\n result.message += ` → Fixed (${fixResult.message})`;\n result.status = \"warn\";\n delete result.fix;\n summary.fixed++;\n }\n } catch {\n // Fix failed, leave as-is\n }\n } else if (result.fixRisk === \"risky\") {\n pendingFixes.push({\n category: check.name,\n message: result.message,\n fix: result.fix,\n });\n }\n }\n\n if (result.status === \"pass\") summary.passed++;\n else if (result.status === \"warn\") summary.warnings++;\n else if (result.status === \"fail\") summary.failed++;\n }\n\n categories.push({ name: check.name, results });\n }\n\n return { categories, summary, pendingFixes };\n }\n\n private async buildContext(): Promise<DoctorContext> {\n const dataDir = this.dataDir;\n const configPath = process.env.OPENACP_CONFIG_PATH || path.join(dataDir, \"config.json\");\n\n let config = null;\n let rawConfig: unknown = null;\n\n try {\n const content = fs.readFileSync(configPath, \"utf-8\");\n rawConfig = JSON.parse(content);\n const cm = new ConfigManager();\n await cm.load();\n config = cm.get();\n } catch {\n // Config may not exist or may be invalid — checks will handle this\n }\n\n const logsDir = config\n ? expandHome(config.logging.logDir)\n : path.join(dataDir, \"logs\");\n\n return {\n config,\n rawConfig,\n configPath,\n dataDir,\n sessionsPath: path.join(dataDir, \"sessions.json\"),\n pidPath: path.join(dataDir, \"openacp.pid\"),\n portFilePath: path.join(dataDir, \"api.port\"),\n pluginsDir: path.join(dataDir, \"plugins\"),\n logsDir,\n };\n }\n}\n\nexport type { DoctorReport, CategoryResult, PendingFix, CheckResult, DoctorContext } from \"./types.js\";\n","import * as fs from \"node:fs\";\nimport { ConfigSchema } from \"../../config/config.js\";\nimport { applyMigrations } from \"../../config/config-migrations.js\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const configCheck: DoctorCheck = {\n name: \"Config\",\n order: 1,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!fs.existsSync(ctx.configPath)) {\n results.push({ status: \"fail\", message: \"Config file not found\" });\n return results;\n }\n results.push({ status: \"pass\", message: \"Config file exists\" });\n\n let raw: Record<string, unknown>;\n try {\n raw = JSON.parse(fs.readFileSync(ctx.configPath, \"utf-8\"));\n } catch (err) {\n results.push({\n status: \"fail\",\n message: `Config JSON invalid: ${err instanceof Error ? err.message : String(err)}`,\n });\n return results;\n }\n results.push({ status: \"pass\", message: \"JSON valid\" });\n\n const testRaw = structuredClone(raw);\n const { changed } = applyMigrations(testRaw);\n if (changed) {\n results.push({\n status: \"warn\",\n message: \"Pending config migrations\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n applyMigrations(raw);\n fs.writeFileSync(ctx.configPath, JSON.stringify(raw, null, 2));\n return { success: true, message: \"applied migrations\" };\n },\n });\n }\n\n const result = ConfigSchema.safeParse(raw);\n if (!result.success) {\n for (const issue of result.error.issues) {\n results.push({\n status: \"fail\",\n message: `Validation: ${issue.path.join(\".\")} — ${issue.message}`,\n });\n }\n } else {\n results.push({ status: \"pass\", message: \"Schema valid\" });\n }\n\n return results;\n },\n};\n","import { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nfunction commandExists(cmd: string): boolean {\n try {\n execFileSync(\"which\", [cmd], { stdio: \"pipe\" });\n return true;\n } catch {\n // not in PATH\n }\n let dir = process.cwd();\n while (true) {\n const binPath = path.join(dir, \"node_modules\", \".bin\", cmd);\n if (fs.existsSync(binPath)) return true;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nexport const agentsCheck: DoctorCheck = {\n name: \"Agents\",\n order: 2,\n async run(ctx) {\n const results: CheckResult[] = [];\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check agents — config not loaded\" });\n return results;\n }\n\n const agents = ctx.config.agents;\n const defaultAgent = ctx.config.defaultAgent;\n\n if (!agents[defaultAgent]) {\n results.push({\n status: \"fail\",\n message: `Default agent \"${defaultAgent}\" not found in agents config`,\n });\n }\n\n for (const [name, agent] of Object.entries(agents)) {\n const isDefault = name === defaultAgent;\n if (commandExists(agent.command)) {\n results.push({\n status: \"pass\",\n message: `${agent.command} found${isDefault ? \" (default)\" : \"\"}`,\n });\n } else {\n results.push({\n status: isDefault ? \"fail\" : \"warn\",\n message: `${agent.command} not found in PATH${isDefault ? \" (default agent!)\" : \"\"}`,\n });\n }\n }\n\n return results;\n },\n};\n","import type { DoctorCheck, CheckResult } from \"../types.js\";\n\nconst BOT_TOKEN_REGEX = /^\\d+:[A-Za-z0-9_-]{35,}$/;\n\nexport const telegramCheck: DoctorCheck = {\n name: \"Telegram\",\n order: 3,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check Telegram — config not loaded\" });\n return results;\n }\n\n const tgConfig = ctx.config.channels.telegram as Record<string, unknown> | undefined;\n if (!tgConfig || !tgConfig.enabled) {\n results.push({ status: \"pass\", message: \"Telegram not enabled (skipped)\" });\n return results;\n }\n\n const botToken = tgConfig.botToken as string | undefined;\n const chatId = tgConfig.chatId as number | undefined;\n\n if (!botToken || !BOT_TOKEN_REGEX.test(botToken)) {\n results.push({ status: \"fail\", message: \"Bot token format invalid\" });\n return results;\n }\n results.push({ status: \"pass\", message: \"Bot token format valid\" });\n\n let botId: number | undefined;\n try {\n const res = await fetch(`https://api.telegram.org/bot${botToken}/getMe`);\n const data = (await res.json()) as { ok: boolean; result?: { id: number; username: string }; description?: string };\n if (data.ok && data.result) {\n botId = data.result.id;\n results.push({ status: \"pass\", message: `Bot token valid (@${data.result.username})` });\n } else {\n results.push({ status: \"fail\", message: `Bot token rejected: ${data.description || \"unknown error\"}` });\n return results;\n }\n } catch (err) {\n results.push({ status: \"fail\", message: `Cannot reach Telegram API: ${err instanceof Error ? err.message : String(err)}` });\n return results;\n }\n\n if (!chatId || chatId === 0) {\n results.push({ status: \"fail\", message: \"Chat ID not configured\" });\n return results;\n }\n\n try {\n const res = await fetch(`https://api.telegram.org/bot${botToken}/getChat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId }),\n });\n const data = (await res.json()) as {\n ok: boolean;\n result?: { type: string; is_forum?: boolean; title: string };\n description?: string;\n };\n if (!data.ok || !data.result) {\n results.push({ status: \"fail\", message: `Chat ID invalid: ${data.description || \"unknown error\"}` });\n return results;\n }\n if (data.result.type !== \"supergroup\") {\n results.push({ status: \"fail\", message: `Chat is \"${data.result.type}\", must be a supergroup` });\n return results;\n }\n if (!data.result.is_forum) {\n results.push({ status: \"warn\", message: \"Chat does not have topics enabled\" });\n } else {\n results.push({ status: \"pass\", message: `Chat is supergroup with topics (\"${data.result.title}\")` });\n }\n } catch (err) {\n results.push({ status: \"fail\", message: `Cannot validate chat: ${err instanceof Error ? err.message : String(err)}` });\n return results;\n }\n\n try {\n const res = await fetch(`https://api.telegram.org/bot${botToken}/getChatMember`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId, user_id: botId }),\n });\n const data = (await res.json()) as { ok: boolean; result?: { status: string }; description?: string };\n if (!data.ok || !data.result) {\n results.push({ status: \"fail\", message: `Cannot check bot membership: ${data.description || \"unknown\"}` });\n } else if (data.result.status === \"administrator\" || data.result.status === \"creator\") {\n results.push({ status: \"pass\", message: \"Bot is admin in group\" });\n } else {\n results.push({\n status: \"fail\",\n message: `Bot is \"${data.result.status}\" — must be admin. Promote bot in group settings.`,\n });\n }\n } catch (err) {\n results.push({ status: \"fail\", message: `Admin check failed: ${err instanceof Error ? err.message : String(err)}` });\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const storageCheck: DoctorCheck = {\n name: \"Storage\",\n order: 4,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!fs.existsSync(ctx.dataDir)) {\n results.push({\n status: \"fail\",\n message: \"Data directory ~/.openacp does not exist\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.mkdirSync(ctx.dataDir, { recursive: true });\n return { success: true, message: \"created directory\" };\n },\n });\n } else {\n try {\n fs.accessSync(ctx.dataDir, fs.constants.W_OK);\n results.push({ status: \"pass\", message: \"Data directory exists and writable\" });\n } catch {\n results.push({ status: \"fail\", message: \"Data directory not writable\" });\n }\n }\n\n if (fs.existsSync(ctx.sessionsPath)) {\n try {\n const content = fs.readFileSync(ctx.sessionsPath, \"utf-8\");\n const data = JSON.parse(content);\n if (typeof data === \"object\" && data !== null && \"sessions\" in data) {\n results.push({ status: \"pass\", message: \"Sessions file valid\" });\n } else {\n results.push({\n status: \"fail\",\n message: \"Sessions file has invalid structure\",\n fixable: true,\n fixRisk: \"risky\",\n fix: async () => {\n fs.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));\n return { success: true, message: \"reset sessions file\" };\n },\n });\n }\n } catch {\n results.push({\n status: \"fail\",\n message: \"Sessions file corrupt (invalid JSON)\",\n fixable: true,\n fixRisk: \"risky\",\n fix: async () => {\n fs.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));\n return { success: true, message: \"reset sessions file\" };\n },\n });\n }\n } else {\n results.push({ status: \"pass\", message: \"Sessions file not present yet (created on first session)\" });\n }\n\n if (!fs.existsSync(ctx.logsDir)) {\n results.push({\n status: \"warn\",\n message: \"Log directory does not exist\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.mkdirSync(ctx.logsDir, { recursive: true });\n return { success: true, message: \"created log directory\" };\n },\n });\n } else {\n try {\n fs.accessSync(ctx.logsDir, fs.constants.W_OK);\n results.push({ status: \"pass\", message: \"Log directory exists and writable\" });\n } catch {\n results.push({ status: \"fail\", message: \"Log directory not writable\" });\n }\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport { expandHome } from \"../../config/config.js\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const workspaceCheck: DoctorCheck = {\n name: \"Workspace\",\n order: 5,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check workspace — config not loaded\" });\n return results;\n }\n\n const baseDir = expandHome(ctx.config.workspace.baseDir);\n\n if (!fs.existsSync(baseDir)) {\n results.push({\n status: \"warn\",\n message: `Workspace directory does not exist: ${baseDir}`,\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.mkdirSync(baseDir, { recursive: true });\n return { success: true, message: \"created directory\" };\n },\n });\n } else {\n try {\n fs.accessSync(baseDir, fs.constants.W_OK);\n results.push({ status: \"pass\", message: `Workspace directory exists: ${baseDir}` });\n } catch {\n results.push({ status: \"fail\", message: `Workspace directory not writable: ${baseDir}` });\n }\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const pluginsCheck: DoctorCheck = {\n name: \"Plugins\",\n order: 6,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!fs.existsSync(ctx.pluginsDir)) {\n results.push({\n status: \"warn\",\n message: \"Plugins directory does not exist\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.mkdirSync(ctx.pluginsDir, { recursive: true });\n fs.writeFileSync(\n path.join(ctx.pluginsDir, \"package.json\"),\n JSON.stringify({ name: \"openacp-plugins\", private: true, dependencies: {} }, null, 2),\n );\n return { success: true, message: \"initialized plugins directory\" };\n },\n });\n return results;\n }\n results.push({ status: \"pass\", message: \"Plugins directory exists\" });\n\n const pkgPath = path.join(ctx.pluginsDir, \"package.json\");\n if (!fs.existsSync(pkgPath)) {\n results.push({\n status: \"warn\",\n message: \"Plugins package.json missing\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.writeFileSync(\n pkgPath,\n JSON.stringify({ name: \"openacp-plugins\", private: true, dependencies: {} }, null, 2),\n );\n return { success: true, message: \"created package.json\" };\n },\n });\n return results;\n }\n\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n const deps = pkg.dependencies || {};\n const count = Object.keys(deps).length;\n results.push({ status: \"pass\", message: `Plugins package.json valid (${count} plugins)` });\n } catch {\n results.push({\n status: \"fail\",\n message: \"Plugins package.json is invalid JSON\",\n fixable: true,\n fixRisk: \"risky\",\n fix: async () => {\n fs.writeFileSync(\n pkgPath,\n JSON.stringify({ name: \"openacp-plugins\", private: true, dependencies: {} }, null, 2),\n );\n return { success: true, message: \"reset package.json\" };\n },\n });\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport * as net from \"node:net\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction checkPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once(\"error\", () => resolve(true));\n server.once(\"listening\", () => {\n server.close();\n resolve(false);\n });\n server.listen(port, \"127.0.0.1\");\n });\n}\n\nexport const daemonCheck: DoctorCheck = {\n name: \"Daemon\",\n order: 7,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (fs.existsSync(ctx.pidPath)) {\n const content = fs.readFileSync(ctx.pidPath, \"utf-8\").trim();\n const pid = parseInt(content, 10);\n if (isNaN(pid)) {\n results.push({\n status: \"warn\",\n message: \"PID file contains invalid data\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.unlinkSync(ctx.pidPath);\n return { success: true, message: \"removed invalid PID file\" };\n },\n });\n } else if (!isProcessAlive(pid)) {\n results.push({\n status: \"warn\",\n message: `Stale PID file (PID ${pid} not running)`,\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.unlinkSync(ctx.pidPath);\n return { success: true, message: \"removed stale PID file\" };\n },\n });\n } else {\n results.push({ status: \"pass\", message: `Daemon running (PID ${pid})` });\n }\n }\n\n if (fs.existsSync(ctx.portFilePath)) {\n const content = fs.readFileSync(ctx.portFilePath, \"utf-8\").trim();\n const port = parseInt(content, 10);\n if (isNaN(port)) {\n results.push({\n status: \"warn\",\n message: \"Port file contains invalid data\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.unlinkSync(ctx.portFilePath);\n return { success: true, message: \"removed invalid port file\" };\n },\n });\n } else {\n results.push({ status: \"pass\", message: `Port file valid (port ${port})` });\n }\n }\n\n if (ctx.config) {\n const apiPort = ctx.config.api.port;\n const inUse = await checkPortInUse(apiPort);\n if (inUse) {\n if (fs.existsSync(ctx.pidPath)) {\n const pid = parseInt(fs.readFileSync(ctx.pidPath, \"utf-8\").trim(), 10);\n if (!isNaN(pid) && isProcessAlive(pid)) {\n results.push({ status: \"pass\", message: `API port ${apiPort} in use by OpenACP daemon` });\n } else {\n results.push({ status: \"warn\", message: `API port ${apiPort} in use by another process` });\n }\n } else {\n results.push({ status: \"warn\", message: `API port ${apiPort} in use by another process` });\n }\n } else {\n results.push({ status: \"pass\", message: `API port ${apiPort} available` });\n }\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { execFileSync } from \"node:child_process\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const tunnelCheck: DoctorCheck = {\n name: \"Tunnel\",\n order: 8,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check tunnel — config not loaded\" });\n return results;\n }\n\n if (!ctx.config.tunnel.enabled) {\n results.push({ status: \"pass\", message: \"Tunnel not enabled (skipped)\" });\n return results;\n }\n\n const provider = ctx.config.tunnel.provider;\n results.push({ status: \"pass\", message: `Tunnel provider: ${provider}` });\n\n if (provider === \"cloudflare\") {\n const binName = os.platform() === \"win32\" ? \"cloudflared.exe\" : \"cloudflared\";\n const binPath = path.join(ctx.dataDir, \"bin\", binName);\n let found = false;\n if (fs.existsSync(binPath)) {\n found = true;\n } else {\n try {\n execFileSync(\"which\", [\"cloudflared\"], { stdio: \"pipe\" });\n found = true;\n } catch {\n // not found\n }\n }\n\n if (found) {\n results.push({ status: \"pass\", message: \"cloudflared binary found\" });\n } else {\n results.push({\n status: \"warn\",\n message: \"cloudflared binary not found\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n try {\n const { ensureCloudflared } = await import(\"../../../plugins/tunnel/providers/install-cloudflared.js\");\n await ensureCloudflared();\n return { success: true, message: \"installed cloudflared\" };\n } catch (err) {\n return { success: false, message: err instanceof Error ? err.message : String(err) };\n }\n },\n });\n }\n }\n\n const tunnelPort = ctx.config.tunnel.port;\n if (tunnelPort < 1 || tunnelPort > 65535) {\n results.push({ status: \"fail\", message: `Invalid tunnel port: ${tunnelPort}` });\n } else {\n results.push({ status: \"pass\", message: `Tunnel port: ${tunnelPort}` });\n }\n\n return results;\n },\n};\n"],"mappings":"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","names":["fs","path","fs","fs","fs","fs","path","fs","fs","path","execFileSync"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/plugins/api-server/index.ts
|
|
2
|
+
import path from "path";
|
|
2
3
|
function createApiServerPlugin() {
|
|
3
4
|
let server = null;
|
|
4
5
|
return {
|
|
@@ -64,14 +65,22 @@ function createApiServerPlugin() {
|
|
|
64
65
|
ctx.terminal.log.success("API server settings cleared");
|
|
65
66
|
}
|
|
66
67
|
},
|
|
68
|
+
inheritableKeys: ["host"],
|
|
67
69
|
async setup(ctx) {
|
|
68
70
|
const config = ctx.pluginConfig;
|
|
69
|
-
const { ApiServer } = await import("./api-server-
|
|
71
|
+
const { ApiServer } = await import("./api-server-DATG2KBR.js");
|
|
70
72
|
const apiConfig = {
|
|
71
73
|
port: config.port ?? 0,
|
|
72
74
|
host: config.host ?? "127.0.0.1"
|
|
73
75
|
};
|
|
74
|
-
|
|
76
|
+
const instanceRoot = ctx.instanceRoot;
|
|
77
|
+
server = new ApiServer(
|
|
78
|
+
ctx.core,
|
|
79
|
+
apiConfig,
|
|
80
|
+
path.join(instanceRoot, "api.port"),
|
|
81
|
+
void 0,
|
|
82
|
+
path.join(instanceRoot, "api-secret")
|
|
83
|
+
);
|
|
75
84
|
ctx.registerService("api-server", server);
|
|
76
85
|
ctx.on("system:ready", async () => {
|
|
77
86
|
try {
|
|
@@ -94,4 +103,4 @@ var api_server_default = createApiServerPlugin();
|
|
|
94
103
|
export {
|
|
95
104
|
api_server_default
|
|
96
105
|
};
|
|
97
|
-
//# sourceMappingURL=chunk-
|
|
106
|
+
//# sourceMappingURL=chunk-KGAQW6F4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/api-server/index.ts"],"sourcesContent":["import path from 'node:path'\nimport type { OpenACPPlugin, InstallContext } from '../../core/plugin/types.js'\nimport type { OpenACPCore } from '../../core/core.js'\nimport type { ApiConfig } from './api-server.js'\n\nfunction createApiServerPlugin(): OpenACPPlugin {\n let server: { start(): Promise<void>; stop?(): Promise<void> } | null = null\n\n return {\n name: '@openacp/api-server',\n version: '1.0.0',\n description: 'REST API + SSE streaming server',\n essential: false,\n permissions: ['services:register', 'kernel:access', 'events:read'],\n\n async install(ctx: InstallContext) {\n const { settings, legacyConfig, terminal } = ctx\n\n // Migrate from legacy config if present\n if (legacyConfig) {\n const apiCfg = legacyConfig.api as Record<string, unknown> | undefined\n if (apiCfg) {\n await settings.setAll({\n port: apiCfg.port ?? 21420,\n host: apiCfg.host ?? '127.0.0.1',\n })\n terminal.log.success('API server settings migrated from legacy config')\n return\n }\n }\n\n // Save defaults\n await settings.setAll({\n port: 21420,\n host: '127.0.0.1',\n })\n terminal.log.success('API server defaults saved')\n },\n\n async configure(ctx: InstallContext) {\n const { terminal, settings } = ctx\n const current = await settings.getAll()\n\n const choice = await terminal.select({\n message: 'What to configure?',\n options: [\n { value: 'port', label: `Change port (current: ${current.port ?? 21420})` },\n { value: 'host', label: `Change host (current: ${current.host ?? '127.0.0.1'})` },\n { value: 'done', label: 'Done' },\n ],\n })\n\n if (choice === 'port') {\n const val = await terminal.text({\n message: 'API port:',\n defaultValue: String(current.port ?? 21420),\n validate: (v) => {\n const n = Number(v.trim())\n if (isNaN(n) || n < 1 || n > 65535) return 'Port must be 1-65535'\n return undefined\n },\n })\n await settings.set('port', Number(val.trim()))\n terminal.log.success('Port updated')\n } else if (choice === 'host') {\n const val = await terminal.text({\n message: 'API host:',\n defaultValue: (current.host as string) ?? '127.0.0.1',\n })\n await settings.set('host', val.trim())\n terminal.log.success('Host updated')\n }\n },\n\n async uninstall(ctx: InstallContext, opts: { purge: boolean }) {\n if (opts.purge) {\n await ctx.settings.clear()\n ctx.terminal.log.success('API server settings cleared')\n }\n },\n\n inheritableKeys: ['host'],\n\n async setup(ctx) {\n const config = ctx.pluginConfig as Record<string, unknown>\n\n // Lazy import to avoid loading unless needed\n const { ApiServer } = await import('./api-server.js')\n\n const apiConfig: ApiConfig = {\n port: (config.port as number) ?? 0,\n host: (config.host as string) ?? '127.0.0.1',\n }\n\n const instanceRoot = ctx.instanceRoot\n server = new ApiServer(\n ctx.core as OpenACPCore,\n apiConfig,\n path.join(instanceRoot, 'api.port'),\n undefined,\n path.join(instanceRoot, 'api-secret'),\n )\n\n ctx.registerService('api-server', server)\n\n // Start on system:ready\n ctx.on('system:ready', async () => {\n try {\n await server!.start()\n ctx.log.info('API server started')\n } catch (err) {\n ctx.log.error(`API server failed to start: ${err}`)\n }\n })\n },\n\n async teardown() {\n if (server) {\n await server.stop?.()\n }\n },\n }\n}\n\nexport default createApiServerPlugin()\n"],"mappings":"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","names":[]}
|