@openacp/cli 0.6.10 → 2026.326.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{action-detect-P7ZE4NEM.js → action-detect-QPA775HB.js} +2 -2
- package/dist/adapter-6ANPBSVU.js +16 -0
- package/dist/{discord-OMC52Y54.js → adapter-77ZCVABT.js} +520 -365
- package/dist/adapter-77ZCVABT.js.map +1 -0
- package/dist/{adapter-ZOANORGM.js → adapter-PQGHVG4K.js} +300 -93
- package/dist/adapter-PQGHVG4K.js.map +1 -0
- package/dist/{admin-6SYB6XCZ.js → admin-GBPZFFAU.js} +3 -3
- package/dist/agent-catalog-YHBFERYO.js +11 -0
- package/dist/{agent-dependencies-4OWBMZWZ.js → agent-dependencies-WS7Z2DFW.js} +2 -2
- package/dist/agent-registry-5LZT7CUB.js +9 -0
- package/dist/agent-store-VSHNY5GT.js +9 -0
- package/dist/{agents-QO7DKARJ.js → agents-BWU4MRRD.js} +3 -3
- package/dist/{api-client-CFQT5U7D.js → api-client-AQPNKXI2.js} +2 -2
- package/dist/api-server-3PYLRBCN.js +8 -0
- package/dist/api-server-CHVSUDBX.js +11 -0
- package/dist/{autostart-X33OGMX6.js → autostart-6JS565RY.js} +3 -3
- package/dist/chunk-2CX4IEEC.js +124 -0
- package/dist/chunk-2CX4IEEC.js.map +1 -0
- package/dist/{chunk-O7CPGUAI.js → chunk-4KGLKKQK.js} +4 -4
- package/dist/chunk-4KGLKKQK.js.map +1 -0
- package/dist/{chunk-W3EYKZNQ.js → chunk-4WXALZA3.js} +2 -2
- package/dist/chunk-4WXALZA3.js.map +1 -0
- package/dist/chunk-5OCGO27U.js +125 -0
- package/dist/chunk-5OCGO27U.js.map +1 -0
- package/dist/{chunk-OWP7RZ62.js → chunk-5ZOFBTOR.js} +118 -262
- package/dist/chunk-5ZOFBTOR.js.map +1 -0
- package/dist/chunk-6RXVEXF3.js +23 -0
- package/dist/chunk-6RXVEXF3.js.map +1 -0
- package/dist/{chunk-34M4OS5P.js → chunk-A6Y4GZM3.js} +3 -3
- package/dist/chunk-A6Y4GZM3.js.map +1 -0
- package/dist/chunk-AD3X6DGK.js +166 -0
- package/dist/chunk-AD3X6DGK.js.map +1 -0
- package/dist/{chunk-7QJS2XBD.js → chunk-AFKX424Q.js} +2 -2
- package/dist/chunk-AFKX424Q.js.map +1 -0
- package/dist/chunk-APS6UEFU.js +259 -0
- package/dist/chunk-APS6UEFU.js.map +1 -0
- package/dist/chunk-BLQUXO7S.js +113 -0
- package/dist/chunk-BLQUXO7S.js.map +1 -0
- package/dist/{chunk-WTZDAYZX.js → chunk-BQ6FR32N.js} +3 -3
- package/dist/chunk-BQ6FR32N.js.map +1 -0
- package/dist/chunk-FNRSWA2K.js +1 -0
- package/dist/chunk-FQEBWOZR.js +3557 -0
- package/dist/chunk-FQEBWOZR.js.map +1 -0
- package/dist/{chunk-4CTX774K.js → chunk-GJOY37U7.js} +4 -4
- package/dist/chunk-GJOY37U7.js.map +1 -0
- package/dist/{chunk-I7WC6E5S.js → chunk-HVBNCPAY.js} +2 -2
- package/dist/chunk-HVBNCPAY.js.map +1 -0
- package/dist/{chunk-2HMQOC7N.js → chunk-I3CGU5W7.js} +4 -4
- package/dist/chunk-I3CGU5W7.js.map +1 -0
- package/dist/{chunk-NVPG6JCL.js → chunk-L7YNNBI5.js} +3 -3
- package/dist/chunk-L7YNNBI5.js.map +1 -0
- package/dist/chunk-LGFWH3AE.js +26 -0
- package/dist/chunk-LGFWH3AE.js.map +1 -0
- package/dist/chunk-MLF4W5R6.js +101 -0
- package/dist/chunk-MLF4W5R6.js.map +1 -0
- package/dist/{chunk-KIRH7TUJ.js → chunk-MTSDOSXS.js} +3 -3
- package/dist/chunk-MTSDOSXS.js.map +1 -0
- package/dist/{chunk-J4SJTKIK.js → chunk-NAM4ERUW.js} +3 -3
- package/dist/chunk-NAM4ERUW.js.map +1 -0
- package/dist/{chunk-MKHUZLII.js → chunk-NBFIBGAT.js} +39 -25
- package/dist/chunk-NBFIBGAT.js.map +1 -0
- package/dist/{chunk-BNLGTZ34.js → chunk-O5RG4YZY.js} +3 -3
- package/dist/chunk-O5RG4YZY.js.map +1 -0
- package/dist/{chunk-JHYXKVV2.js → chunk-ODUM3D6X.js} +2 -2
- package/dist/chunk-ODUM3D6X.js.map +1 -0
- package/dist/chunk-OYSAN7UX.js +15 -0
- package/dist/chunk-OYSAN7UX.js.map +1 -0
- package/dist/chunk-P4SNGQNI.js +158 -0
- package/dist/chunk-P4SNGQNI.js.map +1 -0
- package/dist/{chunk-2CJ46J3C.js → chunk-PPSMUECX.js} +3 -3
- package/dist/chunk-PPSMUECX.js.map +1 -0
- package/dist/chunk-Q6ZXJTZB.js +56 -0
- package/dist/chunk-Q6ZXJTZB.js.map +1 -0
- package/dist/{chunk-XANPHG7W.js → chunk-QSDZDHNS.js} +7 -7
- package/dist/chunk-QSDZDHNS.js.map +1 -0
- package/dist/{chunk-33RP6K2O.js → chunk-QVMEF6FB.js} +6 -6
- package/dist/chunk-QVMEF6FB.js.map +1 -0
- package/dist/chunk-QWP76EBW.js +536 -0
- package/dist/chunk-QWP76EBW.js.map +1 -0
- package/dist/{chunk-V5GZQEIY.js → chunk-RBYBSSGO.js} +4 -4
- package/dist/chunk-RBYBSSGO.js.map +1 -0
- package/dist/{chunk-CS3KCJ5D.js → chunk-RKB2ZK6S.js} +555 -383
- package/dist/chunk-RKB2ZK6S.js.map +1 -0
- package/dist/{chunk-UKT3G5IA.js → chunk-SHTGQGAU.js} +7 -7
- package/dist/chunk-SHTGQGAU.js.map +1 -0
- package/dist/chunk-SNPYTMPR.js +51 -0
- package/dist/chunk-SNPYTMPR.js.map +1 -0
- package/dist/chunk-UB2QB6DE.js +124 -0
- package/dist/chunk-UB2QB6DE.js.map +1 -0
- package/dist/chunk-UNJUWWQO.js +1108 -0
- package/dist/chunk-UNJUWWQO.js.map +1 -0
- package/dist/chunk-V2M243KZ.js +445 -0
- package/dist/chunk-V2M243KZ.js.map +1 -0
- package/dist/chunk-V5JT5TPD.js +97 -0
- package/dist/chunk-V5JT5TPD.js.map +1 -0
- package/dist/chunk-W26AUH5B.js +61 -0
- package/dist/chunk-W26AUH5B.js.map +1 -0
- package/dist/chunk-WAAD23KY.js +222 -0
- package/dist/chunk-WAAD23KY.js.map +1 -0
- package/dist/chunk-WIIZNPCR.js +150 -0
- package/dist/chunk-WIIZNPCR.js.map +1 -0
- package/dist/chunk-WQCJTU2C.js +84 -0
- package/dist/chunk-WQCJTU2C.js.map +1 -0
- package/dist/chunk-WVLDNYOJ.js +150 -0
- package/dist/chunk-WVLDNYOJ.js.map +1 -0
- package/dist/chunk-WXVT3AOY.js +22 -0
- package/dist/chunk-WXVT3AOY.js.map +1 -0
- package/dist/{chunk-GAK6PIBW.js → chunk-XMMAGAT4.js} +2 -2
- package/dist/chunk-XMMAGAT4.js.map +1 -0
- package/dist/chunk-Y64XWMJ4.js +212 -0
- package/dist/chunk-Y64XWMJ4.js.map +1 -0
- package/dist/chunk-YEULD3SG.js +62 -0
- package/dist/chunk-YEULD3SG.js.map +1 -0
- package/dist/chunk-ZHGPZBS4.js +49 -0
- package/dist/chunk-ZHGPZBS4.js.map +1 -0
- package/dist/{chunk-JKBFUAJK.js → chunk-ZSLHHQPQ.js} +2 -2
- package/dist/chunk-ZSLHHQPQ.js.map +1 -0
- package/dist/cli.js +496 -150
- package/dist/cli.js.map +1 -1
- package/dist/{config-6S355X75.js → config-I4FMCJGZ.js} +3 -3
- package/dist/config-editor-HNEKXRLQ.js +11 -0
- package/dist/{config-registry-AHYI4MYL.js → config-registry-CUMNXFGK.js} +2 -2
- package/dist/context-XM6E22LM.js +10 -0
- package/dist/core-plugins-VEUNFTMB.js +27 -0
- package/dist/{daemon-4CS6HMB5.js → daemon-PXO5QPCR.js} +4 -4
- package/dist/dev-loader-RDC5E2CW.js +50 -0
- package/dist/dev-loader-RDC5E2CW.js.map +1 -0
- package/dist/discord-NOJQ5PZO.js +8 -0
- package/dist/doctor-H72BZOPA.js +10 -0
- package/dist/{doctor-OLYBO3V3.js → doctor-RF6BHMCC.js} +5 -5
- package/dist/file-service-EUODJAIT.js +9 -0
- package/dist/file-service-EUODJAIT.js.map +1 -0
- package/dist/index.d.ts +1293 -188
- package/dist/index.js +387 -48
- package/dist/index.js.map +1 -1
- package/dist/{install-cloudflared-Z7VCGOVG.js → install-cloudflared-AN24L4DP.js} +5 -5
- package/dist/install-cloudflared-AN24L4DP.js.map +1 -0
- package/dist/install-context-XPWTFT3J.js +78 -0
- package/dist/install-context-XPWTFT3J.js.map +1 -0
- package/dist/{install-jq-HUYSQWKR.js → install-jq-CRVDJGF3.js} +5 -5
- package/dist/install-jq-CRVDJGF3.js.map +1 -0
- package/dist/{integrate-PNEHRY2I.js → integrate-5C6KSU6D.js} +2 -2
- package/dist/integrate-5C6KSU6D.js.map +1 -0
- package/dist/{log-NXABYJTT.js → log-LZ7FTRKG.js} +2 -2
- package/dist/log-LZ7FTRKG.js.map +1 -0
- package/dist/main-T5WVCCFN.js +715 -0
- package/dist/main-T5WVCCFN.js.map +1 -0
- package/dist/{menu-YY5MKHEK.js → menu-YDQ2LWAR.js} +2 -2
- package/dist/menu-YDQ2LWAR.js.map +1 -0
- package/dist/{new-session-FEO4J4VU.js → new-session-AVQCNXRG.js} +5 -5
- package/dist/new-session-AVQCNXRG.js.map +1 -0
- package/dist/notifications-D5BRDNSU.js +9 -0
- package/dist/notifications-D5BRDNSU.js.map +1 -0
- package/dist/plugin-create-JVCVUG6V.js +331 -0
- package/dist/plugin-create-JVCVUG6V.js.map +1 -0
- package/dist/plugin-registry-WB3DR67H.js +8 -0
- package/dist/plugin-registry-WB3DR67H.js.map +1 -0
- package/dist/{post-upgrade-CJG5I7M2.js → post-upgrade-XLHZ6ZB7.js} +8 -8
- package/dist/post-upgrade-XLHZ6ZB7.js.map +1 -0
- package/dist/read-text-file-IRZM3QLM.js +8 -0
- package/dist/read-text-file-IRZM3QLM.js.map +1 -0
- package/dist/security-YNRBW6S7.js +9 -0
- package/dist/security-YNRBW6S7.js.map +1 -0
- package/dist/{session-IUSI7P5S.js → session-KZFA6Z26.js} +4 -4
- package/dist/session-KZFA6Z26.js.map +1 -0
- package/dist/{settings-RQPAM4KC.js → settings-MFYM7CZO.js} +4 -4
- package/dist/settings-MFYM7CZO.js.map +1 -0
- package/dist/settings-manager-MD2U4ZV2.js +8 -0
- package/dist/settings-manager-MD2U4ZV2.js.map +1 -0
- package/dist/{chunk-LCRLAV4G.js → setup-BAI2F24H.js} +154 -492
- package/dist/setup-BAI2F24H.js.map +1 -0
- package/dist/slack-KH7E3VBS.js +8 -0
- package/dist/slack-KH7E3VBS.js.map +1 -0
- package/dist/speech-2GHQNRIO.js +9 -0
- package/dist/speech-2GHQNRIO.js.map +1 -0
- package/dist/telegram-ZDC3JQF2.js +8 -0
- package/dist/telegram-ZDC3JQF2.js.map +1 -0
- package/dist/tunnel-M47I7H4B.js +8 -0
- package/dist/tunnel-M47I7H4B.js.map +1 -0
- package/dist/{tunnel-service-CJLUH6SZ.js → tunnel-service-WADYHREX.js} +17 -17
- package/dist/tunnel-service-WADYHREX.js.map +1 -0
- package/dist/usage-WYNK6ZC5.js +10 -0
- package/dist/usage-WYNK6ZC5.js.map +1 -0
- package/dist/validators-6CLEZUBD.js +8 -0
- package/dist/validators-6CLEZUBD.js.map +1 -0
- package/dist/validators-WSTBNKRW.js +12 -0
- package/dist/validators-WSTBNKRW.js.map +1 -0
- package/package.json +1 -1
- package/dist/adapter-ZOANORGM.js.map +0 -1
- package/dist/agent-catalog-FC3HGDEQ.js +0 -11
- package/dist/agent-registry-WT4NXPYG.js +0 -9
- package/dist/agent-store-VZLFPTZU.js +0 -9
- package/dist/chunk-2CJ46J3C.js.map +0 -1
- package/dist/chunk-2HMQOC7N.js.map +0 -1
- package/dist/chunk-33RP6K2O.js.map +0 -1
- package/dist/chunk-34M4OS5P.js.map +0 -1
- package/dist/chunk-4CTX774K.js.map +0 -1
- package/dist/chunk-7QJS2XBD.js.map +0 -1
- package/dist/chunk-BNLGTZ34.js.map +0 -1
- package/dist/chunk-CS3KCJ5D.js.map +0 -1
- package/dist/chunk-GAK6PIBW.js.map +0 -1
- package/dist/chunk-I7WC6E5S.js.map +0 -1
- package/dist/chunk-J4SJTKIK.js.map +0 -1
- package/dist/chunk-JHYXKVV2.js.map +0 -1
- package/dist/chunk-JKBFUAJK.js.map +0 -1
- package/dist/chunk-KIRH7TUJ.js.map +0 -1
- package/dist/chunk-LBIKITQT.js +0 -22
- package/dist/chunk-LBIKITQT.js.map +0 -1
- package/dist/chunk-LCRLAV4G.js.map +0 -1
- package/dist/chunk-LGP2YGRL.js +0 -4880
- package/dist/chunk-LGP2YGRL.js.map +0 -1
- package/dist/chunk-MKHUZLII.js.map +0 -1
- package/dist/chunk-NAMYZIS5.js +0 -1
- package/dist/chunk-NVPG6JCL.js.map +0 -1
- package/dist/chunk-O7CPGUAI.js.map +0 -1
- package/dist/chunk-OWP7RZ62.js.map +0 -1
- package/dist/chunk-UKT3G5IA.js.map +0 -1
- package/dist/chunk-V5GZQEIY.js.map +0 -1
- package/dist/chunk-VOIJ6OY4.js +0 -63
- package/dist/chunk-VOIJ6OY4.js.map +0 -1
- package/dist/chunk-W3EYKZNQ.js.map +0 -1
- package/dist/chunk-WTZDAYZX.js.map +0 -1
- package/dist/chunk-XANPHG7W.js.map +0 -1
- package/dist/config-editor-QQTZMWGD.js +0 -13
- package/dist/discord-OMC52Y54.js.map +0 -1
- package/dist/doctor-HZZ5BSHB.js +0 -10
- package/dist/install-cloudflared-Z7VCGOVG.js.map +0 -1
- package/dist/install-jq-HUYSQWKR.js.map +0 -1
- package/dist/integrate-PNEHRY2I.js.map +0 -1
- package/dist/main-XOZCLFUK.js +0 -238
- package/dist/main-XOZCLFUK.js.map +0 -1
- package/dist/post-upgrade-CJG5I7M2.js.map +0 -1
- package/dist/setup-XHS4OMPM.js +0 -37
- package/dist/tunnel-service-CJLUH6SZ.js.map +0 -1
- /package/dist/{action-detect-P7ZE4NEM.js.map → action-detect-QPA775HB.js.map} +0 -0
- /package/dist/{admin-6SYB6XCZ.js.map → adapter-6ANPBSVU.js.map} +0 -0
- /package/dist/{agent-catalog-FC3HGDEQ.js.map → admin-GBPZFFAU.js.map} +0 -0
- /package/dist/{agent-dependencies-4OWBMZWZ.js.map → agent-catalog-YHBFERYO.js.map} +0 -0
- /package/dist/{agent-registry-WT4NXPYG.js.map → agent-dependencies-WS7Z2DFW.js.map} +0 -0
- /package/dist/{agent-store-VZLFPTZU.js.map → agent-registry-5LZT7CUB.js.map} +0 -0
- /package/dist/{agents-QO7DKARJ.js.map → agent-store-VSHNY5GT.js.map} +0 -0
- /package/dist/{api-client-CFQT5U7D.js.map → agents-BWU4MRRD.js.map} +0 -0
- /package/dist/{autostart-X33OGMX6.js.map → api-client-AQPNKXI2.js.map} +0 -0
- /package/dist/{chunk-NAMYZIS5.js.map → api-server-3PYLRBCN.js.map} +0 -0
- /package/dist/{config-6S355X75.js.map → api-server-CHVSUDBX.js.map} +0 -0
- /package/dist/{config-editor-QQTZMWGD.js.map → autostart-6JS565RY.js.map} +0 -0
- /package/dist/{config-registry-AHYI4MYL.js.map → chunk-FNRSWA2K.js.map} +0 -0
- /package/dist/{daemon-4CS6HMB5.js.map → config-I4FMCJGZ.js.map} +0 -0
- /package/dist/{doctor-HZZ5BSHB.js.map → config-editor-HNEKXRLQ.js.map} +0 -0
- /package/dist/{doctor-OLYBO3V3.js.map → config-registry-CUMNXFGK.js.map} +0 -0
- /package/dist/{log-NXABYJTT.js.map → context-XM6E22LM.js.map} +0 -0
- /package/dist/{menu-YY5MKHEK.js.map → core-plugins-VEUNFTMB.js.map} +0 -0
- /package/dist/{new-session-FEO4J4VU.js.map → daemon-PXO5QPCR.js.map} +0 -0
- /package/dist/{session-IUSI7P5S.js.map → discord-NOJQ5PZO.js.map} +0 -0
- /package/dist/{settings-RQPAM4KC.js.map → doctor-H72BZOPA.js.map} +0 -0
- /package/dist/{setup-XHS4OMPM.js.map → doctor-RF6BHMCC.js.map} +0 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CheckpointReader,
|
|
3
|
+
DEFAULT_MAX_TOKENS,
|
|
4
|
+
TOKENS_PER_TURN_ESTIMATE
|
|
5
|
+
} from "./chunk-APS6UEFU.js";
|
|
6
|
+
|
|
7
|
+
// src/plugins/context/context-manager.ts
|
|
8
|
+
import * as os from "os";
|
|
9
|
+
import * as path2 from "path";
|
|
10
|
+
|
|
11
|
+
// src/plugins/context/context-cache.ts
|
|
12
|
+
import * as fs from "fs";
|
|
13
|
+
import * as path from "path";
|
|
14
|
+
import * as crypto from "crypto";
|
|
15
|
+
var DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
16
|
+
var ContextCache = class {
|
|
17
|
+
constructor(cacheDir, ttlMs = DEFAULT_TTL_MS) {
|
|
18
|
+
this.cacheDir = cacheDir;
|
|
19
|
+
this.ttlMs = ttlMs;
|
|
20
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
keyHash(repoPath, queryKey) {
|
|
23
|
+
return crypto.createHash("sha256").update(`${repoPath}:${queryKey}`).digest("hex").slice(0, 16);
|
|
24
|
+
}
|
|
25
|
+
filePath(repoPath, queryKey) {
|
|
26
|
+
return path.join(this.cacheDir, `${this.keyHash(repoPath, queryKey)}.json`);
|
|
27
|
+
}
|
|
28
|
+
get(repoPath, queryKey) {
|
|
29
|
+
const fp = this.filePath(repoPath, queryKey);
|
|
30
|
+
try {
|
|
31
|
+
const stat = fs.statSync(fp);
|
|
32
|
+
if (Date.now() - stat.mtimeMs > this.ttlMs) {
|
|
33
|
+
fs.unlinkSync(fp);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return JSON.parse(fs.readFileSync(fp, "utf-8"));
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
set(repoPath, queryKey, result) {
|
|
42
|
+
fs.writeFileSync(this.filePath(repoPath, queryKey), JSON.stringify(result));
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// src/plugins/context/context-manager.ts
|
|
47
|
+
var ContextManager = class {
|
|
48
|
+
providers = [];
|
|
49
|
+
cache;
|
|
50
|
+
constructor() {
|
|
51
|
+
this.cache = new ContextCache(path2.join(os.homedir(), ".openacp", "cache", "entire"));
|
|
52
|
+
}
|
|
53
|
+
register(provider) {
|
|
54
|
+
this.providers.push(provider);
|
|
55
|
+
}
|
|
56
|
+
async getProvider(repoPath) {
|
|
57
|
+
for (const provider of this.providers) {
|
|
58
|
+
if (await provider.isAvailable(repoPath)) return provider;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
async listSessions(query) {
|
|
63
|
+
const provider = await this.getProvider(query.repoPath);
|
|
64
|
+
if (!provider) return null;
|
|
65
|
+
return provider.listSessions(query);
|
|
66
|
+
}
|
|
67
|
+
async buildContext(query, options) {
|
|
68
|
+
const queryKey = `${query.type}:${query.value}:${options?.limit ?? ""}:${options?.maxTokens ?? ""}`;
|
|
69
|
+
const cached = this.cache.get(query.repoPath, queryKey);
|
|
70
|
+
if (cached) return cached;
|
|
71
|
+
const provider = await this.getProvider(query.repoPath);
|
|
72
|
+
if (!provider) return null;
|
|
73
|
+
const result = await provider.buildContext(query, options);
|
|
74
|
+
if (result) this.cache.set(query.repoPath, queryKey, result);
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// src/plugins/context/entire/message-cleaner.ts
|
|
80
|
+
var SYSTEM_TAG_PATTERNS = [
|
|
81
|
+
/<system-reminder>[\s\S]*?<\/system-reminder>/g,
|
|
82
|
+
/<local-command-caveat>[\s\S]*?<\/local-command-caveat>/g,
|
|
83
|
+
/<local-command-stdout>[\s\S]*?<\/local-command-stdout>/g,
|
|
84
|
+
/<command-name>[\s\S]*?<\/command-name>/g,
|
|
85
|
+
/<command-message>[\s\S]*?<\/command-message>/g,
|
|
86
|
+
/<user-prompt-submit-hook>[\s\S]*?<\/user-prompt-submit-hook>/g,
|
|
87
|
+
/<ide_selection>[\s\S]*?<\/ide_selection>/g,
|
|
88
|
+
/<ide_context>[\s\S]*?<\/ide_context>/g,
|
|
89
|
+
/<ide_opened_file>[\s\S]*?<\/ide_opened_file>/g,
|
|
90
|
+
/<cursor_context>[\s\S]*?<\/cursor_context>/g,
|
|
91
|
+
/<attached_files>[\s\S]*?<\/attached_files>/g,
|
|
92
|
+
/<repo_context>[\s\S]*?<\/repo_context>/g,
|
|
93
|
+
/<task-notification>[\s\S]*?<\/task-notification>/g
|
|
94
|
+
];
|
|
95
|
+
var COMMAND_ARGS_RE = /<command-args>([\s\S]*?)<\/command-args>/;
|
|
96
|
+
function cleanSystemTags(text) {
|
|
97
|
+
const argsMatch = COMMAND_ARGS_RE.exec(text);
|
|
98
|
+
const userArgs = argsMatch?.[1]?.trim() ?? "";
|
|
99
|
+
text = text.replace(/<command-args>[\s\S]*?<\/command-args>/g, "");
|
|
100
|
+
for (const pat of SYSTEM_TAG_PATTERNS) {
|
|
101
|
+
text = text.replace(new RegExp(pat.source, pat.flags), "");
|
|
102
|
+
}
|
|
103
|
+
text = text.trim();
|
|
104
|
+
if (!text && userArgs) return userArgs;
|
|
105
|
+
if (text && userArgs && text !== userArgs) return `${text}
|
|
106
|
+
${userArgs}`;
|
|
107
|
+
return text || userArgs;
|
|
108
|
+
}
|
|
109
|
+
var SKILL_INDICATORS = [
|
|
110
|
+
"Base directory for this skill:",
|
|
111
|
+
"<HARD-GATE>",
|
|
112
|
+
"## Checklist",
|
|
113
|
+
"## Process Flow",
|
|
114
|
+
"## Key Principles",
|
|
115
|
+
"digraph brainstorming",
|
|
116
|
+
"You MUST create a task for each"
|
|
117
|
+
];
|
|
118
|
+
function isSkillPrompt(text) {
|
|
119
|
+
for (const indicator of SKILL_INDICATORS) {
|
|
120
|
+
if (text.includes(indicator)) return true;
|
|
121
|
+
}
|
|
122
|
+
if (text.length > 2e3) {
|
|
123
|
+
const headerCount = (text.match(/## /g) || []).length;
|
|
124
|
+
if (headerCount >= 3) return true;
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
function isNoiseMessage(text) {
|
|
129
|
+
const cleaned = cleanSystemTags(text);
|
|
130
|
+
if (!cleaned) return true;
|
|
131
|
+
if (/^(ready|ready\.)$/i.test(cleaned)) return true;
|
|
132
|
+
if (cleaned.includes("Tell your human partner that this command is deprecated")) return true;
|
|
133
|
+
if (cleaned.startsWith("Read the output file to retrieve the result:")) return true;
|
|
134
|
+
if (/^(opus|sonnet|haiku|claude)(\[.*\])?$/i.test(cleaned)) return true;
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/plugins/context/entire/conversation-builder.ts
|
|
139
|
+
function selectMode(totalTurns) {
|
|
140
|
+
if (totalTurns <= 10) return "full";
|
|
141
|
+
if (totalTurns <= 25) return "balanced";
|
|
142
|
+
return "compact";
|
|
143
|
+
}
|
|
144
|
+
function estimateTokens(text) {
|
|
145
|
+
return Math.floor(text.length / 4);
|
|
146
|
+
}
|
|
147
|
+
function shortenPath(fp) {
|
|
148
|
+
const parts = fp.split("/");
|
|
149
|
+
if (parts.length >= 2) return parts.slice(-2).join("/");
|
|
150
|
+
return fp;
|
|
151
|
+
}
|
|
152
|
+
function countLines(s) {
|
|
153
|
+
const trimmed = s.trim();
|
|
154
|
+
if (!trimmed) return 0;
|
|
155
|
+
return trimmed.split("\n").length;
|
|
156
|
+
}
|
|
157
|
+
function extractText(content) {
|
|
158
|
+
if (typeof content === "string") return content;
|
|
159
|
+
if (Array.isArray(content)) {
|
|
160
|
+
return content.filter((b) => typeof b === "object" && b !== null && b.type === "text").map((b) => b.text).join("\n");
|
|
161
|
+
}
|
|
162
|
+
return "";
|
|
163
|
+
}
|
|
164
|
+
function extractContentBlocks(content) {
|
|
165
|
+
if (typeof content === "string") return [{ type: "text", text: content }];
|
|
166
|
+
if (Array.isArray(content)) {
|
|
167
|
+
return content.filter((b) => typeof b === "object" && b !== null);
|
|
168
|
+
}
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
function isToolResultOnly(content) {
|
|
172
|
+
if (typeof content === "string") return false;
|
|
173
|
+
if (!Array.isArray(content)) return true;
|
|
174
|
+
for (const block of content) {
|
|
175
|
+
if (typeof block === "object" && block !== null) {
|
|
176
|
+
const b = block;
|
|
177
|
+
if (b.type === "text" && typeof b.text === "string" && b.text.trim()) return false;
|
|
178
|
+
if (b.type === "image") return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
function hasImage(content) {
|
|
184
|
+
if (!Array.isArray(content)) return false;
|
|
185
|
+
return content.some((b) => typeof b === "object" && b !== null && b.type === "image");
|
|
186
|
+
}
|
|
187
|
+
function formatEditFull(filePath, oldStr, newStr) {
|
|
188
|
+
const lines = [];
|
|
189
|
+
lines.push(`\u270F\uFE0F \`${filePath}\``);
|
|
190
|
+
lines.push("```diff");
|
|
191
|
+
for (const line of oldStr.split("\n")) lines.push(`- ${line}`);
|
|
192
|
+
for (const line of newStr.split("\n")) lines.push(`+ ${line}`);
|
|
193
|
+
lines.push("```");
|
|
194
|
+
return lines.join("\n");
|
|
195
|
+
}
|
|
196
|
+
function formatEditBalanced(filePath, oldStr, newStr, maxDiffLines = 12) {
|
|
197
|
+
const oldLines = oldStr.split("\n");
|
|
198
|
+
const newLines = newStr.split("\n");
|
|
199
|
+
const total = oldLines.length + newLines.length;
|
|
200
|
+
const lines = [];
|
|
201
|
+
lines.push(`\u270F\uFE0F \`${filePath}\``);
|
|
202
|
+
lines.push("```diff");
|
|
203
|
+
if (total <= maxDiffLines) {
|
|
204
|
+
for (const line of oldLines) lines.push(`- ${line}`);
|
|
205
|
+
for (const line of newLines) lines.push(`+ ${line}`);
|
|
206
|
+
} else {
|
|
207
|
+
const half = Math.floor(maxDiffLines / 2);
|
|
208
|
+
for (const line of oldLines.slice(0, half)) lines.push(`- ${line}`);
|
|
209
|
+
if (oldLines.length > half) lines.push(` ... (-${oldLines.length} lines total)`);
|
|
210
|
+
for (const line of newLines.slice(0, half)) lines.push(`+ ${line}`);
|
|
211
|
+
if (newLines.length > half) lines.push(` ... (+${newLines.length} lines total)`);
|
|
212
|
+
}
|
|
213
|
+
lines.push("```");
|
|
214
|
+
return lines.join("\n");
|
|
215
|
+
}
|
|
216
|
+
function formatEditCompact(filePath, oldStr, newStr) {
|
|
217
|
+
const oldLines = countLines(oldStr);
|
|
218
|
+
const newLines = countLines(newStr);
|
|
219
|
+
let firstNew = "";
|
|
220
|
+
for (const line of newStr.split("\n")) {
|
|
221
|
+
const stripped = line.trim();
|
|
222
|
+
if (stripped && !stripped.startsWith("//") && !stripped.startsWith("*")) {
|
|
223
|
+
firstNew = stripped.slice(0, 80);
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (firstNew) {
|
|
228
|
+
return `\u270F\uFE0F \`${filePath}\` (-${oldLines}/+${newLines} lines): \`${firstNew}\``;
|
|
229
|
+
}
|
|
230
|
+
return `\u270F\uFE0F \`${filePath}\` (-${oldLines}/+${newLines} lines)`;
|
|
231
|
+
}
|
|
232
|
+
function formatWriteFull(filePath, content) {
|
|
233
|
+
const lines = [];
|
|
234
|
+
lines.push(`\u{1F4DD} \`${filePath}\``);
|
|
235
|
+
lines.push("```");
|
|
236
|
+
lines.push(content);
|
|
237
|
+
lines.push("```");
|
|
238
|
+
return lines.join("\n");
|
|
239
|
+
}
|
|
240
|
+
function formatWriteBalanced(filePath, content, maxLines = 15) {
|
|
241
|
+
const contentLines = content.split("\n");
|
|
242
|
+
const lines = [];
|
|
243
|
+
lines.push(`\u{1F4DD} \`${filePath}\` (${contentLines.length} lines)`);
|
|
244
|
+
lines.push("```");
|
|
245
|
+
for (const line of contentLines.slice(0, maxLines)) lines.push(line);
|
|
246
|
+
if (contentLines.length > maxLines) lines.push(`... (${contentLines.length - maxLines} more lines)`);
|
|
247
|
+
lines.push("```");
|
|
248
|
+
return lines.join("\n");
|
|
249
|
+
}
|
|
250
|
+
function formatWriteCompact(filePath, content) {
|
|
251
|
+
const numLines = countLines(content);
|
|
252
|
+
return `\u{1F4DD} \`${filePath}\` (${numLines} lines written)`;
|
|
253
|
+
}
|
|
254
|
+
function parseJsonlToTurns(jsonl) {
|
|
255
|
+
const events = [];
|
|
256
|
+
for (const rawLine of jsonl.split("\n")) {
|
|
257
|
+
const line = rawLine.trim();
|
|
258
|
+
if (!line) continue;
|
|
259
|
+
try {
|
|
260
|
+
events.push(JSON.parse(line));
|
|
261
|
+
} catch {
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
let branch = "unknown";
|
|
265
|
+
for (const e of events) {
|
|
266
|
+
if (e.gitBranch) {
|
|
267
|
+
branch = e.gitBranch;
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const convEvents = events.filter((e) => e.type === "user" || e.type === "assistant");
|
|
272
|
+
const turns = [];
|
|
273
|
+
let currentTurn = null;
|
|
274
|
+
for (const e of convEvents) {
|
|
275
|
+
const etype = e.type;
|
|
276
|
+
const content = e.message?.content ?? [];
|
|
277
|
+
const ts = e.timestamp ?? "";
|
|
278
|
+
if (etype === "user") {
|
|
279
|
+
if (isToolResultOnly(content)) continue;
|
|
280
|
+
const text = extractText(content);
|
|
281
|
+
if (isSkillPrompt(text)) continue;
|
|
282
|
+
if (isNoiseMessage(text)) continue;
|
|
283
|
+
const cleaned = cleanSystemTags(text);
|
|
284
|
+
if (!cleaned) continue;
|
|
285
|
+
if (currentTurn) turns.push(currentTurn);
|
|
286
|
+
const imgSuffix = hasImage(content) ? " [image]" : "";
|
|
287
|
+
currentTurn = {
|
|
288
|
+
userText: cleaned + imgSuffix,
|
|
289
|
+
userTimestamp: ts,
|
|
290
|
+
assistantParts: []
|
|
291
|
+
};
|
|
292
|
+
} else if (etype === "assistant" && currentTurn) {
|
|
293
|
+
const blocks = extractContentBlocks(content);
|
|
294
|
+
let pendingText = null;
|
|
295
|
+
for (const block of blocks) {
|
|
296
|
+
const btype = block.type;
|
|
297
|
+
if (btype === "text") {
|
|
298
|
+
const text = typeof block.text === "string" ? block.text.trim() : "";
|
|
299
|
+
if (text) pendingText = text;
|
|
300
|
+
} else if (btype === "tool_use") {
|
|
301
|
+
const name = typeof block.name === "string" ? block.name : "";
|
|
302
|
+
const inp = typeof block.input === "object" && block.input !== null ? block.input : {};
|
|
303
|
+
if (name === "Edit") {
|
|
304
|
+
if (pendingText) {
|
|
305
|
+
currentTurn.assistantParts.push({ type: "text", content: pendingText });
|
|
306
|
+
pendingText = null;
|
|
307
|
+
}
|
|
308
|
+
currentTurn.assistantParts.push({
|
|
309
|
+
type: "edit",
|
|
310
|
+
file: shortenPath(inp.file_path ?? ""),
|
|
311
|
+
old: inp.old_string ?? "",
|
|
312
|
+
new: inp.new_string ?? ""
|
|
313
|
+
});
|
|
314
|
+
} else if (name === "Write") {
|
|
315
|
+
if (pendingText) {
|
|
316
|
+
currentTurn.assistantParts.push({ type: "text", content: pendingText });
|
|
317
|
+
pendingText = null;
|
|
318
|
+
}
|
|
319
|
+
currentTurn.assistantParts.push({
|
|
320
|
+
type: "write",
|
|
321
|
+
file: shortenPath(inp.file_path ?? ""),
|
|
322
|
+
fileContent: inp.content ?? ""
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (pendingText) {
|
|
328
|
+
currentTurn.assistantParts.push({ type: "text", content: pendingText });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (currentTurn) turns.push(currentTurn);
|
|
333
|
+
const firstTimestamp = turns[0]?.userTimestamp ?? "";
|
|
334
|
+
const lastTimestamp = turns[turns.length - 1]?.userTimestamp ?? "";
|
|
335
|
+
return { turns, branch, firstTimestamp, lastTimestamp };
|
|
336
|
+
}
|
|
337
|
+
function buildSessionMarkdown(turns, mode) {
|
|
338
|
+
const out = [];
|
|
339
|
+
for (let i = 0; i < turns.length; i++) {
|
|
340
|
+
const turn = turns[i];
|
|
341
|
+
const userText = turn.userText.trim();
|
|
342
|
+
if (!userText) continue;
|
|
343
|
+
out.push(`**User [${i + 1}]:**`);
|
|
344
|
+
out.push(userText);
|
|
345
|
+
out.push("");
|
|
346
|
+
let hasContent = false;
|
|
347
|
+
for (const part of turn.assistantParts) {
|
|
348
|
+
if (part.type === "text") {
|
|
349
|
+
if (!hasContent) {
|
|
350
|
+
out.push("**Assistant:**");
|
|
351
|
+
hasContent = true;
|
|
352
|
+
}
|
|
353
|
+
out.push(part.content ?? "");
|
|
354
|
+
out.push("");
|
|
355
|
+
} else if (part.type === "edit") {
|
|
356
|
+
if (!hasContent) {
|
|
357
|
+
out.push("**Assistant:**");
|
|
358
|
+
hasContent = true;
|
|
359
|
+
}
|
|
360
|
+
const file = part.file ?? "";
|
|
361
|
+
const oldStr = part.old ?? "";
|
|
362
|
+
const newStr = part.new ?? "";
|
|
363
|
+
if (mode === "full") {
|
|
364
|
+
out.push(formatEditFull(file, oldStr, newStr));
|
|
365
|
+
} else if (mode === "balanced") {
|
|
366
|
+
out.push(formatEditBalanced(file, oldStr, newStr));
|
|
367
|
+
} else {
|
|
368
|
+
out.push(formatEditCompact(file, oldStr, newStr));
|
|
369
|
+
}
|
|
370
|
+
out.push("");
|
|
371
|
+
} else if (part.type === "write") {
|
|
372
|
+
if (!hasContent) {
|
|
373
|
+
out.push("**Assistant:**");
|
|
374
|
+
hasContent = true;
|
|
375
|
+
}
|
|
376
|
+
const file = part.file ?? "";
|
|
377
|
+
const content = part.fileContent ?? "";
|
|
378
|
+
if (mode === "full") {
|
|
379
|
+
out.push(formatWriteFull(file, content));
|
|
380
|
+
} else if (mode === "balanced") {
|
|
381
|
+
out.push(formatWriteBalanced(file, content));
|
|
382
|
+
} else {
|
|
383
|
+
out.push(formatWriteCompact(file, content));
|
|
384
|
+
}
|
|
385
|
+
out.push("");
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
out.push("---");
|
|
389
|
+
out.push("");
|
|
390
|
+
}
|
|
391
|
+
return out.join("\n");
|
|
392
|
+
}
|
|
393
|
+
var DISCLAIMER = `> **Note:** This conversation history may contain outdated information. File contents, code, and project state may have changed since these sessions were recorded. Use this as context only \u2014 always verify against current files before acting.`;
|
|
394
|
+
function mergeSessionsMarkdown(sessions, mode, title) {
|
|
395
|
+
const sorted = [...sessions].sort((a, b) => a.startTime.localeCompare(b.startTime));
|
|
396
|
+
const totalTurns = sorted.reduce((sum, s) => sum + s.turns, 0);
|
|
397
|
+
const overallStart = sorted[0]?.startTime.slice(0, 16) ?? "?";
|
|
398
|
+
const overallEnd = sorted[sorted.length - 1]?.endTime.slice(0, 16) ?? "?";
|
|
399
|
+
const out = [];
|
|
400
|
+
out.push(`# Conversation History from ${title}`);
|
|
401
|
+
out.push(`${sorted.length} sessions | ${totalTurns} turns | ${overallStart} \u2192 ${overallEnd} | mode: ${mode}`);
|
|
402
|
+
out.push("");
|
|
403
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
404
|
+
const s = sorted[i];
|
|
405
|
+
const start = s.startTime.slice(0, 16);
|
|
406
|
+
const end = s.endTime.slice(0, 16);
|
|
407
|
+
out.push(`## Session Conversation History ${i + 1} \u2014 ${start} \u2192 ${end} (${s.agent}, ${s.turns} turns, branch: ${s.branch})`);
|
|
408
|
+
out.push("");
|
|
409
|
+
out.push(s.markdown);
|
|
410
|
+
}
|
|
411
|
+
out.push(DISCLAIMER);
|
|
412
|
+
out.push("");
|
|
413
|
+
return out.join("\n");
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/plugins/context/entire/entire-provider.ts
|
|
417
|
+
var EntireProvider = class {
|
|
418
|
+
name = "entire";
|
|
419
|
+
async isAvailable(repoPath) {
|
|
420
|
+
return new CheckpointReader(repoPath).hasEntireBranch();
|
|
421
|
+
}
|
|
422
|
+
async listSessions(query) {
|
|
423
|
+
const reader = new CheckpointReader(query.repoPath);
|
|
424
|
+
const sessions = await this.resolveSessions(reader, query);
|
|
425
|
+
const estimatedTokens = sessions.reduce((sum, s) => sum + s.turnCount * TOKENS_PER_TURN_ESTIMATE, 0);
|
|
426
|
+
return { sessions, estimatedTokens };
|
|
427
|
+
}
|
|
428
|
+
async buildContext(query, options) {
|
|
429
|
+
const maxTokens = options?.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
430
|
+
const reader = new CheckpointReader(query.repoPath);
|
|
431
|
+
let sessions = await this.resolveSessions(reader, query);
|
|
432
|
+
if (options?.limit && sessions.length > options.limit) {
|
|
433
|
+
sessions = sessions.slice(-options.limit);
|
|
434
|
+
}
|
|
435
|
+
if (sessions.length === 0) {
|
|
436
|
+
return { markdown: "", tokenEstimate: 0, sessionCount: 0, totalTurns: 0, mode: "full", truncated: false, timeRange: { start: "", end: "" } };
|
|
437
|
+
}
|
|
438
|
+
const parsedSessions = [];
|
|
439
|
+
for (const sess of sessions) {
|
|
440
|
+
const jsonl = reader.getTranscript(sess.transcriptPath);
|
|
441
|
+
if (jsonl) parsedSessions.push({ session: sess, jsonl });
|
|
442
|
+
}
|
|
443
|
+
if (parsedSessions.length === 0) {
|
|
444
|
+
return { markdown: "", tokenEstimate: 0, sessionCount: 0, totalTurns: 0, mode: "full", truncated: false, timeRange: { start: "", end: "" } };
|
|
445
|
+
}
|
|
446
|
+
const totalTurns = parsedSessions.reduce((sum, ps) => {
|
|
447
|
+
const parsed = parseJsonlToTurns(ps.jsonl);
|
|
448
|
+
return sum + parsed.turns.length;
|
|
449
|
+
}, 0);
|
|
450
|
+
let mode = selectMode(totalTurns);
|
|
451
|
+
const title = this.buildTitle(query);
|
|
452
|
+
let sessionMarkdowns = this.buildSessionMarkdowns(parsedSessions, mode);
|
|
453
|
+
let merged = mergeSessionsMarkdown(sessionMarkdowns, mode, title);
|
|
454
|
+
let tokens = estimateTokens(merged);
|
|
455
|
+
if (tokens > maxTokens && mode !== "compact") {
|
|
456
|
+
mode = "compact";
|
|
457
|
+
sessionMarkdowns = this.buildSessionMarkdowns(parsedSessions, "compact");
|
|
458
|
+
merged = mergeSessionsMarkdown(sessionMarkdowns, "compact", title);
|
|
459
|
+
tokens = estimateTokens(merged);
|
|
460
|
+
}
|
|
461
|
+
let truncated = false;
|
|
462
|
+
while (tokens > maxTokens && sessionMarkdowns.length > 1) {
|
|
463
|
+
sessionMarkdowns = sessionMarkdowns.slice(1);
|
|
464
|
+
truncated = true;
|
|
465
|
+
merged = mergeSessionsMarkdown(sessionMarkdowns, mode, title);
|
|
466
|
+
tokens = estimateTokens(merged);
|
|
467
|
+
}
|
|
468
|
+
const allTimes = sessionMarkdowns.flatMap((s) => [s.startTime, s.endTime]).filter(Boolean).sort();
|
|
469
|
+
const finalTurns = sessionMarkdowns.reduce((sum, s) => sum + s.turns, 0);
|
|
470
|
+
return {
|
|
471
|
+
markdown: merged,
|
|
472
|
+
tokenEstimate: tokens,
|
|
473
|
+
sessionCount: sessionMarkdowns.length,
|
|
474
|
+
totalTurns: finalTurns,
|
|
475
|
+
mode,
|
|
476
|
+
truncated,
|
|
477
|
+
timeRange: { start: allTimes[0] ?? "", end: allTimes[allTimes.length - 1] ?? "" }
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
buildSessionMarkdowns(parsedSessions, mode) {
|
|
481
|
+
return parsedSessions.map((ps) => {
|
|
482
|
+
const parsed = parseJsonlToTurns(ps.jsonl);
|
|
483
|
+
return {
|
|
484
|
+
markdown: buildSessionMarkdown(parsed.turns, mode),
|
|
485
|
+
startTime: parsed.firstTimestamp,
|
|
486
|
+
endTime: parsed.lastTimestamp,
|
|
487
|
+
agent: ps.session.agent,
|
|
488
|
+
turns: parsed.turns.length,
|
|
489
|
+
branch: ps.session.branch,
|
|
490
|
+
files: ps.session.filesTouched.map((f) => f.split("/").pop() ?? f)
|
|
491
|
+
};
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
async resolveSessions(reader, query) {
|
|
495
|
+
switch (query.type) {
|
|
496
|
+
case "branch":
|
|
497
|
+
return reader.resolveByBranch(query.value);
|
|
498
|
+
case "commit":
|
|
499
|
+
return reader.resolveByCommit(query.value);
|
|
500
|
+
case "pr":
|
|
501
|
+
return reader.resolveByPr(query.value);
|
|
502
|
+
case "checkpoint":
|
|
503
|
+
return reader.resolveByCheckpoint(query.value);
|
|
504
|
+
case "session":
|
|
505
|
+
return reader.resolveBySessionId(query.value);
|
|
506
|
+
case "latest":
|
|
507
|
+
return reader.resolveLatest(parseInt(query.value) || 5);
|
|
508
|
+
default:
|
|
509
|
+
return [];
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
buildTitle(query) {
|
|
513
|
+
switch (query.type) {
|
|
514
|
+
case "pr":
|
|
515
|
+
return `PR #${query.value.replace(/.*\/pull\//, "")}`;
|
|
516
|
+
case "branch":
|
|
517
|
+
return `branch \`${query.value}\``;
|
|
518
|
+
case "commit":
|
|
519
|
+
return `commit \`${query.value.slice(0, 8)}\``;
|
|
520
|
+
case "checkpoint":
|
|
521
|
+
return `checkpoint \`${query.value}\``;
|
|
522
|
+
case "session":
|
|
523
|
+
return `session \`${query.value.slice(0, 8)}...\``;
|
|
524
|
+
case "latest":
|
|
525
|
+
return `latest ${query.value} sessions`;
|
|
526
|
+
default:
|
|
527
|
+
return "unknown";
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
export {
|
|
533
|
+
ContextManager,
|
|
534
|
+
EntireProvider
|
|
535
|
+
};
|
|
536
|
+
//# sourceMappingURL=chunk-QWP76EBW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/context/context-manager.ts","../../src/plugins/context/context-cache.ts","../../src/plugins/context/entire/message-cleaner.ts","../../src/plugins/context/entire/conversation-builder.ts","../../src/plugins/context/entire/entire-provider.ts"],"sourcesContent":["import * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ContextProvider, ContextQuery, ContextOptions, ContextResult, SessionListResult } from \"./context-provider.js\";\nimport { ContextCache } from \"./context-cache.js\";\n\nexport class ContextManager {\n private providers: ContextProvider[] = [];\n private cache: ContextCache;\n\n constructor() {\n this.cache = new ContextCache(path.join(os.homedir(), \".openacp\", \"cache\", \"entire\"));\n }\n\n register(provider: ContextProvider): void {\n this.providers.push(provider);\n }\n\n async getProvider(repoPath: string): Promise<ContextProvider | null> {\n for (const provider of this.providers) {\n if (await provider.isAvailable(repoPath)) return provider;\n }\n return null;\n }\n\n async listSessions(query: ContextQuery): Promise<SessionListResult | null> {\n const provider = await this.getProvider(query.repoPath);\n if (!provider) return null;\n return provider.listSessions(query);\n }\n\n async buildContext(query: ContextQuery, options?: ContextOptions): Promise<ContextResult | null> {\n const queryKey = `${query.type}:${query.value}:${options?.limit ?? \"\"}:${options?.maxTokens ?? \"\"}`;\n const cached = this.cache.get(query.repoPath, queryKey);\n if (cached) return cached;\n\n const provider = await this.getProvider(query.repoPath);\n if (!provider) return null;\n const result = await provider.buildContext(query, options);\n if (result) this.cache.set(query.repoPath, queryKey, result);\n return result;\n }\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as crypto from \"node:crypto\";\nimport type { ContextResult } from \"./context-provider.js\";\n\nconst DEFAULT_TTL_MS = 60 * 60 * 1000;\n\nexport class ContextCache {\n constructor(private cacheDir: string, private ttlMs: number = DEFAULT_TTL_MS) {\n fs.mkdirSync(cacheDir, { recursive: true });\n }\n\n private keyHash(repoPath: string, queryKey: string): string {\n return crypto.createHash(\"sha256\").update(`${repoPath}:${queryKey}`).digest(\"hex\").slice(0, 16);\n }\n\n private filePath(repoPath: string, queryKey: string): string {\n return path.join(this.cacheDir, `${this.keyHash(repoPath, queryKey)}.json`);\n }\n\n get(repoPath: string, queryKey: string): ContextResult | null {\n const fp = this.filePath(repoPath, queryKey);\n try {\n const stat = fs.statSync(fp);\n if (Date.now() - stat.mtimeMs > this.ttlMs) { fs.unlinkSync(fp); return null; }\n return JSON.parse(fs.readFileSync(fp, \"utf-8\")) as ContextResult;\n } catch { return null; }\n }\n\n set(repoPath: string, queryKey: string, result: ContextResult): void {\n fs.writeFileSync(this.filePath(repoPath, queryKey), JSON.stringify(result));\n }\n}\n","const SYSTEM_TAG_PATTERNS: RegExp[] = [\n /<system-reminder>[\\s\\S]*?<\\/system-reminder>/g,\n /<local-command-caveat>[\\s\\S]*?<\\/local-command-caveat>/g,\n /<local-command-stdout>[\\s\\S]*?<\\/local-command-stdout>/g,\n /<command-name>[\\s\\S]*?<\\/command-name>/g,\n /<command-message>[\\s\\S]*?<\\/command-message>/g,\n /<user-prompt-submit-hook>[\\s\\S]*?<\\/user-prompt-submit-hook>/g,\n /<ide_selection>[\\s\\S]*?<\\/ide_selection>/g,\n /<ide_context>[\\s\\S]*?<\\/ide_context>/g,\n /<ide_opened_file>[\\s\\S]*?<\\/ide_opened_file>/g,\n /<cursor_context>[\\s\\S]*?<\\/cursor_context>/g,\n /<attached_files>[\\s\\S]*?<\\/attached_files>/g,\n /<repo_context>[\\s\\S]*?<\\/repo_context>/g,\n /<task-notification>[\\s\\S]*?<\\/task-notification>/g,\n];\n\nconst COMMAND_ARGS_RE = /<command-args>([\\s\\S]*?)<\\/command-args>/;\n\nexport function cleanSystemTags(text: string): string {\n const argsMatch = COMMAND_ARGS_RE.exec(text);\n const userArgs = argsMatch?.[1]?.trim() ?? \"\";\n text = text.replace(/<command-args>[\\s\\S]*?<\\/command-args>/g, \"\");\n for (const pat of SYSTEM_TAG_PATTERNS) {\n text = text.replace(new RegExp(pat.source, pat.flags), \"\");\n }\n text = text.trim();\n if (!text && userArgs) return userArgs;\n if (text && userArgs && text !== userArgs) return `${text}\\n${userArgs}`;\n return text || userArgs;\n}\n\nconst SKILL_INDICATORS = [\n \"Base directory for this skill:\",\n \"<HARD-GATE>\",\n \"## Checklist\",\n \"## Process Flow\",\n \"## Key Principles\",\n \"digraph brainstorming\",\n \"You MUST create a task for each\",\n];\n\nexport function isSkillPrompt(text: string): boolean {\n for (const indicator of SKILL_INDICATORS) {\n if (text.includes(indicator)) return true;\n }\n if (text.length > 2000) {\n const headerCount = (text.match(/## /g) || []).length;\n if (headerCount >= 3) return true;\n }\n return false;\n}\n\nexport function isNoiseMessage(text: string): boolean {\n const cleaned = cleanSystemTags(text);\n if (!cleaned) return true;\n if (/^(ready|ready\\.)$/i.test(cleaned)) return true;\n if (cleaned.includes(\"Tell your human partner that this command is deprecated\")) return true;\n if (cleaned.startsWith(\"Read the output file to retrieve the result:\")) return true;\n if (/^(opus|sonnet|haiku|claude)(\\[.*\\])?$/i.test(cleaned)) return true;\n return false;\n}\n","import type { ContextMode } from \"../context-provider.js\";\nimport { cleanSystemTags, isSkillPrompt, isNoiseMessage } from \"./message-cleaner.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface AssistantPart {\n type: \"text\" | \"edit\" | \"write\";\n content?: string;\n file?: string;\n old?: string;\n new?: string;\n fileContent?: string;\n}\n\nexport interface Turn {\n userText: string;\n userTimestamp: string;\n assistantParts: AssistantPart[];\n}\n\nexport interface ParseResult {\n turns: Turn[];\n branch: string;\n firstTimestamp: string;\n lastTimestamp: string;\n}\n\nexport interface SessionMarkdownInput {\n markdown: string;\n startTime: string;\n endTime: string;\n agent: string;\n turns: number;\n branch: string;\n files: string[];\n}\n\n// ─── Mode selection ────────────────────────────────────────────────────────────\n\n/**\n * Select rendering mode based on total turn count.\n * ≤10 → full\n * 11-25 → balanced\n * >25 → compact\n */\nexport function selectMode(totalTurns: number): ContextMode {\n if (totalTurns <= 10) return \"full\";\n if (totalTurns <= 25) return \"balanced\";\n return \"compact\";\n}\n\n// ─── Token estimation ─────────────────────────────────────────────────────────\n\nexport function estimateTokens(text: string): number {\n return Math.floor(text.length / 4);\n}\n\n// ─── Path helpers ─────────────────────────────────────────────────────────────\n\nfunction shortenPath(fp: string): string {\n const parts = fp.split(\"/\");\n if (parts.length >= 2) return parts.slice(-2).join(\"/\");\n return fp;\n}\n\nfunction countLines(s: string): number {\n const trimmed = s.trim();\n if (!trimmed) return 0;\n return trimmed.split(\"\\n\").length;\n}\n\n// ─── Content extraction ───────────────────────────────────────────────────────\n\ntype ContentBlock = { type: string; [key: string]: unknown };\n\nfunction extractText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .filter((b): b is ContentBlock => typeof b === \"object\" && b !== null && (b as ContentBlock).type === \"text\")\n .map((b) => (b as unknown as { text: string }).text)\n .join(\"\\n\");\n }\n return \"\";\n}\n\nfunction extractContentBlocks(content: unknown): ContentBlock[] {\n if (typeof content === \"string\") return [{ type: \"text\", text: content }];\n if (Array.isArray(content)) {\n return content.filter((b): b is ContentBlock => typeof b === \"object\" && b !== null);\n }\n return [];\n}\n\nfunction isToolResultOnly(content: unknown): boolean {\n if (typeof content === \"string\") return false;\n if (!Array.isArray(content)) return true;\n for (const block of content) {\n if (typeof block === \"object\" && block !== null) {\n const b = block as ContentBlock;\n if (b.type === \"text\" && typeof b.text === \"string\" && (b.text as string).trim()) return false;\n if (b.type === \"image\") return false;\n }\n }\n return true;\n}\n\nfunction hasImage(content: unknown): boolean {\n if (!Array.isArray(content)) return false;\n return content.some((b) => typeof b === \"object\" && b !== null && (b as ContentBlock).type === \"image\");\n}\n\n// ─── Format functions ─────────────────────────────────────────────────────────\n\nfunction formatEditFull(filePath: string, oldStr: string, newStr: string): string {\n const lines: string[] = [];\n lines.push(`✏️ \\`${filePath}\\``);\n lines.push(\"```diff\");\n for (const line of oldStr.split(\"\\n\")) lines.push(`- ${line}`);\n for (const line of newStr.split(\"\\n\")) lines.push(`+ ${line}`);\n lines.push(\"```\");\n return lines.join(\"\\n\");\n}\n\nfunction formatEditBalanced(filePath: string, oldStr: string, newStr: string, maxDiffLines = 12): string {\n const oldLines = oldStr.split(\"\\n\");\n const newLines = newStr.split(\"\\n\");\n const total = oldLines.length + newLines.length;\n const lines: string[] = [];\n lines.push(`✏️ \\`${filePath}\\``);\n lines.push(\"```diff\");\n if (total <= maxDiffLines) {\n for (const line of oldLines) lines.push(`- ${line}`);\n for (const line of newLines) lines.push(`+ ${line}`);\n } else {\n const half = Math.floor(maxDiffLines / 2);\n for (const line of oldLines.slice(0, half)) lines.push(`- ${line}`);\n if (oldLines.length > half) lines.push(` ... (-${oldLines.length} lines total)`);\n for (const line of newLines.slice(0, half)) lines.push(`+ ${line}`);\n if (newLines.length > half) lines.push(` ... (+${newLines.length} lines total)`);\n }\n lines.push(\"```\");\n return lines.join(\"\\n\");\n}\n\nfunction formatEditCompact(filePath: string, oldStr: string, newStr: string): string {\n const oldLines = countLines(oldStr);\n const newLines = countLines(newStr);\n let firstNew = \"\";\n for (const line of newStr.split(\"\\n\")) {\n const stripped = line.trim();\n if (stripped && !stripped.startsWith(\"//\") && !stripped.startsWith(\"*\")) {\n firstNew = stripped.slice(0, 80);\n break;\n }\n }\n if (firstNew) {\n return `✏️ \\`${filePath}\\` (-${oldLines}/+${newLines} lines): \\`${firstNew}\\``;\n }\n return `✏️ \\`${filePath}\\` (-${oldLines}/+${newLines} lines)`;\n}\n\nfunction formatWriteFull(filePath: string, content: string): string {\n const lines: string[] = [];\n lines.push(`📝 \\`${filePath}\\``);\n lines.push(\"```\");\n lines.push(content);\n lines.push(\"```\");\n return lines.join(\"\\n\");\n}\n\nfunction formatWriteBalanced(filePath: string, content: string, maxLines = 15): string {\n const contentLines = content.split(\"\\n\");\n const lines: string[] = [];\n lines.push(`📝 \\`${filePath}\\` (${contentLines.length} lines)`);\n lines.push(\"```\");\n for (const line of contentLines.slice(0, maxLines)) lines.push(line);\n if (contentLines.length > maxLines) lines.push(`... (${contentLines.length - maxLines} more lines)`);\n lines.push(\"```\");\n return lines.join(\"\\n\");\n}\n\nfunction formatWriteCompact(filePath: string, content: string): string {\n const numLines = countLines(content);\n return `📝 \\`${filePath}\\` (${numLines} lines written)`;\n}\n\n// ─── Parser ───────────────────────────────────────────────────────────────────\n\ninterface RawEvent {\n type?: string;\n message?: { role?: string; content?: unknown };\n timestamp?: string;\n uuid?: string;\n parentUuid?: string | null;\n sessionId?: string;\n gitBranch?: string;\n}\n\nexport function parseJsonlToTurns(jsonl: string): ParseResult {\n const events: RawEvent[] = [];\n for (const rawLine of jsonl.split(\"\\n\")) {\n const line = rawLine.trim();\n if (!line) continue;\n try {\n events.push(JSON.parse(line) as RawEvent);\n } catch {\n // skip invalid JSON lines\n }\n }\n\n // Extract gitBranch from first event that has it\n let branch = \"unknown\";\n for (const e of events) {\n if (e.gitBranch) {\n branch = e.gitBranch;\n break;\n }\n }\n\n const convEvents = events.filter((e) => e.type === \"user\" || e.type === \"assistant\");\n\n const turns: Turn[] = [];\n let currentTurn: Turn | null = null;\n\n for (const e of convEvents) {\n const etype = e.type;\n const content = e.message?.content ?? [];\n const ts = e.timestamp ?? \"\";\n\n if (etype === \"user\") {\n if (isToolResultOnly(content)) continue;\n\n const text = extractText(content);\n\n if (isSkillPrompt(text)) continue;\n if (isNoiseMessage(text)) continue;\n\n const cleaned = cleanSystemTags(text);\n if (!cleaned) continue;\n\n // Push previous turn if any\n if (currentTurn) turns.push(currentTurn);\n\n const imgSuffix = hasImage(content) ? \" [image]\" : \"\";\n currentTurn = {\n userText: cleaned + imgSuffix,\n userTimestamp: ts,\n assistantParts: [],\n };\n } else if (etype === \"assistant\" && currentTurn) {\n const blocks = extractContentBlocks(content);\n let pendingText: string | null = null;\n\n for (const block of blocks) {\n const btype = block.type;\n\n if (btype === \"text\") {\n const text = typeof block.text === \"string\" ? (block.text as string).trim() : \"\";\n if (text) pendingText = text;\n } else if (btype === \"tool_use\") {\n const name = typeof block.name === \"string\" ? block.name : \"\";\n const inp = (typeof block.input === \"object\" && block.input !== null ? block.input : {}) as Record<string, string>;\n\n if (name === \"Edit\") {\n if (pendingText) {\n currentTurn.assistantParts.push({ type: \"text\", content: pendingText });\n pendingText = null;\n }\n currentTurn.assistantParts.push({\n type: \"edit\",\n file: shortenPath(inp.file_path ?? \"\"),\n old: inp.old_string ?? \"\",\n new: inp.new_string ?? \"\",\n });\n } else if (name === \"Write\") {\n if (pendingText) {\n currentTurn.assistantParts.push({ type: \"text\", content: pendingText });\n pendingText = null;\n }\n currentTurn.assistantParts.push({\n type: \"write\",\n file: shortenPath(inp.file_path ?? \"\"),\n fileContent: inp.content ?? \"\",\n });\n }\n // Skip Read, Bash, Grep, Glob, etc.\n }\n }\n\n if (pendingText) {\n currentTurn.assistantParts.push({ type: \"text\", content: pendingText });\n }\n }\n }\n\n if (currentTurn) turns.push(currentTurn);\n\n const firstTimestamp = turns[0]?.userTimestamp ?? \"\";\n const lastTimestamp = turns[turns.length - 1]?.userTimestamp ?? \"\";\n\n return { turns, branch, firstTimestamp, lastTimestamp };\n}\n\n// ─── Markdown builder ─────────────────────────────────────────────────────────\n\nexport function buildSessionMarkdown(turns: Turn[], mode: ContextMode): string {\n const out: string[] = [];\n\n for (let i = 0; i < turns.length; i++) {\n const turn = turns[i];\n const userText = turn.userText.trim();\n if (!userText) continue;\n\n out.push(`**User [${i + 1}]:**`);\n out.push(userText);\n out.push(\"\");\n\n let hasContent = false;\n\n for (const part of turn.assistantParts) {\n if (part.type === \"text\") {\n if (!hasContent) {\n out.push(\"**Assistant:**\");\n hasContent = true;\n }\n out.push(part.content ?? \"\");\n out.push(\"\");\n } else if (part.type === \"edit\") {\n if (!hasContent) {\n out.push(\"**Assistant:**\");\n hasContent = true;\n }\n const file = part.file ?? \"\";\n const oldStr = part.old ?? \"\";\n const newStr = part.new ?? \"\";\n if (mode === \"full\") {\n out.push(formatEditFull(file, oldStr, newStr));\n } else if (mode === \"balanced\") {\n out.push(formatEditBalanced(file, oldStr, newStr));\n } else {\n out.push(formatEditCompact(file, oldStr, newStr));\n }\n out.push(\"\");\n } else if (part.type === \"write\") {\n if (!hasContent) {\n out.push(\"**Assistant:**\");\n hasContent = true;\n }\n const file = part.file ?? \"\";\n const content = part.fileContent ?? \"\";\n if (mode === \"full\") {\n out.push(formatWriteFull(file, content));\n } else if (mode === \"balanced\") {\n out.push(formatWriteBalanced(file, content));\n } else {\n out.push(formatWriteCompact(file, content));\n }\n out.push(\"\");\n }\n }\n\n out.push(\"---\");\n out.push(\"\");\n }\n\n return out.join(\"\\n\");\n}\n\n// ─── Session merger ───────────────────────────────────────────────────────────\n\nconst DISCLAIMER = `> **Note:** This conversation history may contain outdated information. File contents, code, and project state may have changed since these sessions were recorded. Use this as context only — always verify against current files before acting.`;\n\nexport function mergeSessionsMarkdown(\n sessions: SessionMarkdownInput[],\n mode: ContextMode,\n title: string\n): string {\n // Sort sessions chronologically (oldest first)\n const sorted = [...sessions].sort((a, b) => a.startTime.localeCompare(b.startTime));\n\n const totalTurns = sorted.reduce((sum, s) => sum + s.turns, 0);\n const overallStart = sorted[0]?.startTime.slice(0, 16) ?? \"?\";\n const overallEnd = sorted[sorted.length - 1]?.endTime.slice(0, 16) ?? \"?\";\n\n const out: string[] = [];\n out.push(`# Conversation History from ${title}`);\n out.push(`${sorted.length} sessions | ${totalTurns} turns | ${overallStart} → ${overallEnd} | mode: ${mode}`);\n out.push(\"\");\n\n for (let i = 0; i < sorted.length; i++) {\n const s = sorted[i];\n const start = s.startTime.slice(0, 16);\n const end = s.endTime.slice(0, 16);\n out.push(`## Session Conversation History ${i + 1} — ${start} → ${end} (${s.agent}, ${s.turns} turns, branch: ${s.branch})`);\n out.push(\"\");\n out.push(s.markdown);\n }\n\n out.push(DISCLAIMER);\n out.push(\"\");\n\n return out.join(\"\\n\");\n}\n","import type { ContextProvider, ContextQuery, ContextOptions, ContextResult, SessionListResult, SessionInfo } from \"../context-provider.js\";\nimport type { ContextMode } from \"../context-provider.js\";\nimport { DEFAULT_MAX_TOKENS, TOKENS_PER_TURN_ESTIMATE } from \"../context-provider.js\";\nimport { CheckpointReader } from \"./checkpoint-reader.js\";\nimport { parseJsonlToTurns, buildSessionMarkdown, mergeSessionsMarkdown, selectMode, estimateTokens, type SessionMarkdownInput } from \"./conversation-builder.js\";\n\nexport class EntireProvider implements ContextProvider {\n readonly name = \"entire\";\n\n async isAvailable(repoPath: string): Promise<boolean> {\n return new CheckpointReader(repoPath).hasEntireBranch();\n }\n\n async listSessions(query: ContextQuery): Promise<SessionListResult> {\n const reader = new CheckpointReader(query.repoPath);\n const sessions = await this.resolveSessions(reader, query);\n const estimatedTokens = sessions.reduce((sum, s) => sum + s.turnCount * TOKENS_PER_TURN_ESTIMATE, 0);\n return { sessions, estimatedTokens };\n }\n\n async buildContext(query: ContextQuery, options?: ContextOptions): Promise<ContextResult> {\n const maxTokens = options?.maxTokens ?? DEFAULT_MAX_TOKENS;\n const reader = new CheckpointReader(query.repoPath);\n let sessions = await this.resolveSessions(reader, query);\n\n if (options?.limit && sessions.length > options.limit) {\n sessions = sessions.slice(-options.limit);\n }\n\n if (sessions.length === 0) {\n return { markdown: \"\", tokenEstimate: 0, sessionCount: 0, totalTurns: 0, mode: \"full\", truncated: false, timeRange: { start: \"\", end: \"\" } };\n }\n\n // Rebuild each session, cache parsed turns for potential re-render\n const parsedSessions: { session: SessionInfo; jsonl: string; }[] = [];\n for (const sess of sessions) {\n const jsonl = reader.getTranscript(sess.transcriptPath);\n if (jsonl) parsedSessions.push({ session: sess, jsonl });\n }\n\n if (parsedSessions.length === 0) {\n return { markdown: \"\", tokenEstimate: 0, sessionCount: 0, totalTurns: 0, mode: \"full\", truncated: false, timeRange: { start: \"\", end: \"\" } };\n }\n\n const totalTurns = parsedSessions.reduce((sum, ps) => {\n const parsed = parseJsonlToTurns(ps.jsonl);\n return sum + parsed.turns.length;\n }, 0);\n\n let mode = selectMode(totalTurns);\n const title = this.buildTitle(query);\n\n // Build markdown for each session\n let sessionMarkdowns = this.buildSessionMarkdowns(parsedSessions, mode);\n let merged = mergeSessionsMarkdown(sessionMarkdowns, mode, title);\n let tokens = estimateTokens(merged);\n\n // Auto-downgrade to compact if over budget\n if (tokens > maxTokens && mode !== \"compact\") {\n mode = \"compact\";\n sessionMarkdowns = this.buildSessionMarkdowns(parsedSessions, \"compact\");\n merged = mergeSessionsMarkdown(sessionMarkdowns, \"compact\", title);\n tokens = estimateTokens(merged);\n }\n\n // Truncate oldest sessions if still over budget\n let truncated = false;\n while (tokens > maxTokens && sessionMarkdowns.length > 1) {\n sessionMarkdowns = sessionMarkdowns.slice(1);\n truncated = true;\n merged = mergeSessionsMarkdown(sessionMarkdowns, mode, title);\n tokens = estimateTokens(merged);\n }\n\n const allTimes = sessionMarkdowns.flatMap(s => [s.startTime, s.endTime]).filter(Boolean).sort();\n const finalTurns = sessionMarkdowns.reduce((sum, s) => sum + s.turns, 0);\n\n return {\n markdown: merged,\n tokenEstimate: tokens,\n sessionCount: sessionMarkdowns.length,\n totalTurns: finalTurns,\n mode,\n truncated,\n timeRange: { start: allTimes[0] ?? \"\", end: allTimes[allTimes.length - 1] ?? \"\" },\n };\n }\n\n private buildSessionMarkdowns(parsedSessions: { session: SessionInfo; jsonl: string }[], mode: ContextMode): SessionMarkdownInput[] {\n return parsedSessions.map(ps => {\n const parsed = parseJsonlToTurns(ps.jsonl);\n return {\n markdown: buildSessionMarkdown(parsed.turns, mode),\n startTime: parsed.firstTimestamp,\n endTime: parsed.lastTimestamp,\n agent: ps.session.agent,\n turns: parsed.turns.length,\n branch: ps.session.branch,\n files: ps.session.filesTouched.map(f => f.split(\"/\").pop() ?? f),\n };\n });\n }\n\n private async resolveSessions(reader: CheckpointReader, query: ContextQuery): Promise<SessionInfo[]> {\n switch (query.type) {\n case \"branch\": return reader.resolveByBranch(query.value);\n case \"commit\": return reader.resolveByCommit(query.value);\n case \"pr\": return reader.resolveByPr(query.value);\n case \"checkpoint\": return reader.resolveByCheckpoint(query.value);\n case \"session\": return reader.resolveBySessionId(query.value);\n case \"latest\": return reader.resolveLatest(parseInt(query.value) || 5);\n default: return [];\n }\n }\n\n private buildTitle(query: ContextQuery): string {\n switch (query.type) {\n case \"pr\": return `PR #${query.value.replace(/.*\\/pull\\//, \"\")}`;\n case \"branch\": return `branch \\`${query.value}\\``;\n case \"commit\": return `commit \\`${query.value.slice(0, 8)}\\``;\n case \"checkpoint\": return `checkpoint \\`${query.value}\\``;\n case \"session\": return `session \\`${query.value.slice(0, 8)}...\\``;\n case \"latest\": return `latest ${query.value} sessions`;\n default: return \"unknown\";\n }\n }\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
commandExists
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ZSLHHQPQ.js";
|
|
4
4
|
import {
|
|
5
5
|
createChildLogger
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XMMAGAT4.js";
|
|
7
7
|
|
|
8
|
-
// src/core/install-binary.ts
|
|
8
|
+
// src/core/utils/install-binary.ts
|
|
9
9
|
import fs from "fs";
|
|
10
10
|
import path from "path";
|
|
11
11
|
import https from "https";
|
|
@@ -98,4 +98,4 @@ async function ensureBinary(spec) {
|
|
|
98
98
|
export {
|
|
99
99
|
ensureBinary
|
|
100
100
|
};
|
|
101
|
-
//# sourceMappingURL=chunk-
|
|
101
|
+
//# sourceMappingURL=chunk-RBYBSSGO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/utils/install-binary.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport https from 'node:https'\nimport os from 'node:os'\nimport { execSync } from 'node:child_process'\nimport { createChildLogger } from './log.js'\nimport { commandExists } from '../agents/agent-dependencies.js'\n\nconst log = createChildLogger({ module: 'binary-installer' })\n\nconst BIN_DIR = path.join(os.homedir(), '.openacp', 'bin')\nconst IS_WINDOWS = os.platform() === 'win32'\n\nexport interface BinarySpec {\n name: string\n /** GitHub base URL for releases, e.g. \"https://github.com/jqlang/jq/releases/latest/download\" */\n githubBaseUrl: string\n /** Platform → arch → filename mapping */\n platforms: Record<string, Record<string, string>>\n /** If true, downloaded file is a .tgz archive that needs extraction */\n isArchive?: (url: string) => boolean\n}\n\nfunction downloadFile(url: string, dest: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const file = fs.createWriteStream(dest)\n\n const cleanup = () => {\n try { if (fs.existsSync(dest)) fs.unlinkSync(dest) } catch { /* ignore */ }\n }\n\n https.get(url, (response) => {\n if (response.statusCode === 301 || response.statusCode === 302) {\n file.close(() => {\n cleanup()\n downloadFile(response.headers.location!, dest).then(resolve).catch(reject)\n })\n return\n }\n\n if (response.statusCode !== 200) {\n file.close(() => {\n cleanup()\n reject(new Error(`Download failed with status ${response.statusCode}`))\n })\n return\n }\n\n response.pipe(file)\n file.on('finish', () => file.close(() => resolve(dest)))\n file.on('error', (err) => {\n file.close(() => {\n cleanup()\n reject(err)\n })\n })\n }).on('error', (err) => {\n file.close(() => {\n cleanup()\n reject(err)\n })\n })\n })\n}\n\nfunction getDownloadUrl(spec: BinarySpec): string {\n const platform = os.platform()\n const arch = os.arch()\n const mapping = spec.platforms[platform]\n if (!mapping) throw new Error(`${spec.name}: unsupported platform ${platform}`)\n const binary = mapping[arch]\n if (!binary) throw new Error(`${spec.name}: unsupported architecture ${arch} for ${platform}`)\n return `${spec.githubBaseUrl}/${binary}`\n}\n\n/**\n * Ensure a binary is available.\n * 1. Check PATH first (respects user's system install)\n * 2. Check ~/.openacp/bin/\n * 3. Download from GitHub releases\n */\nexport async function ensureBinary(spec: BinarySpec): Promise<string> {\n const binName = IS_WINDOWS ? `${spec.name}.exe` : spec.name\n const binPath = path.join(BIN_DIR, binName)\n\n // 1. Check PATH first\n if (commandExists(spec.name)) {\n log.debug({ name: spec.name }, 'Found in PATH')\n return spec.name\n }\n\n // 2. Check our bin directory\n if (fs.existsSync(binPath)) {\n if (!IS_WINDOWS) fs.chmodSync(binPath, '755')\n log.debug({ name: spec.name, path: binPath }, 'Found in ~/.openacp/bin')\n return binPath\n }\n\n // 3. Download\n log.info({ name: spec.name }, 'Not found, downloading from GitHub...')\n fs.mkdirSync(BIN_DIR, { recursive: true })\n\n const url = getDownloadUrl(spec)\n const isArchive = spec.isArchive?.(url) ?? false\n const downloadDest = isArchive ? path.join(BIN_DIR, `${spec.name}.tgz`) : binPath\n\n await downloadFile(url, downloadDest)\n\n if (isArchive) {\n execSync(`tar -xzf \"${downloadDest}\" -C \"${BIN_DIR}\"`, { stdio: 'pipe' })\n try { fs.unlinkSync(downloadDest) } catch { /* ignore */ }\n }\n\n if (!IS_WINDOWS) {\n fs.chmodSync(binPath, '755')\n }\n\n log.info({ name: spec.name, path: binPath }, 'Installed successfully')\n return binPath\n}\n"],"mappings":";;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,WAAW;AAClB,OAAO,QAAQ;AACf,SAAS,gBAAgB;AAIzB,IAAM,MAAM,kBAAkB,EAAE,QAAQ,mBAAmB,CAAC;AAE5D,IAAM,UAAU,KAAK,KAAK,GAAG,QAAQ,GAAG,YAAY,KAAK;AACzD,IAAM,aAAa,GAAG,SAAS,MAAM;AAYrC,SAAS,aAAa,KAAa,MAA+B;AAChE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,OAAO,GAAG,kBAAkB,IAAI;AAEtC,UAAM,UAAU,MAAM;AACpB,UAAI;AAAE,YAAI,GAAG,WAAW,IAAI,EAAG,IAAG,WAAW,IAAI;AAAA,MAAE,QAAQ;AAAA,MAAe;AAAA,IAC5E;AAEA,UAAM,IAAI,KAAK,CAAC,aAAa;AAC3B,UAAI,SAAS,eAAe,OAAO,SAAS,eAAe,KAAK;AAC9D,aAAK,MAAM,MAAM;AACf,kBAAQ;AACR,uBAAa,SAAS,QAAQ,UAAW,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,MAAM;AAAA,QAC3E,CAAC;AACD;AAAA,MACF;AAEA,UAAI,SAAS,eAAe,KAAK;AAC/B,aAAK,MAAM,MAAM;AACf,kBAAQ;AACR,iBAAO,IAAI,MAAM,+BAA+B,SAAS,UAAU,EAAE,CAAC;AAAA,QACxE,CAAC;AACD;AAAA,MACF;AAEA,eAAS,KAAK,IAAI;AAClB,WAAK,GAAG,UAAU,MAAM,KAAK,MAAM,MAAM,QAAQ,IAAI,CAAC,CAAC;AACvD,WAAK,GAAG,SAAS,CAAC,QAAQ;AACxB,aAAK,MAAM,MAAM;AACf,kBAAQ;AACR,iBAAO,GAAG;AAAA,QACZ,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC,EAAE,GAAG,SAAS,CAAC,QAAQ;AACtB,WAAK,MAAM,MAAM;AACf,gBAAQ;AACR,eAAO,GAAG;AAAA,MACZ,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,eAAe,MAA0B;AAChD,QAAM,WAAW,GAAG,SAAS;AAC7B,QAAM,OAAO,GAAG,KAAK;AACrB,QAAM,UAAU,KAAK,UAAU,QAAQ;AACvC,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,GAAG,KAAK,IAAI,0BAA0B,QAAQ,EAAE;AAC9E,QAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,GAAG,KAAK,IAAI,8BAA8B,IAAI,QAAQ,QAAQ,EAAE;AAC7F,SAAO,GAAG,KAAK,aAAa,IAAI,MAAM;AACxC;AAQA,eAAsB,aAAa,MAAmC;AACpE,QAAM,UAAU,aAAa,GAAG,KAAK,IAAI,SAAS,KAAK;AACvD,QAAM,UAAU,KAAK,KAAK,SAAS,OAAO;AAG1C,MAAI,cAAc,KAAK,IAAI,GAAG;AAC5B,QAAI,MAAM,EAAE,MAAM,KAAK,KAAK,GAAG,eAAe;AAC9C,WAAO,KAAK;AAAA,EACd;AAGA,MAAI,GAAG,WAAW,OAAO,GAAG;AAC1B,QAAI,CAAC,WAAY,IAAG,UAAU,SAAS,KAAK;AAC5C,QAAI,MAAM,EAAE,MAAM,KAAK,MAAM,MAAM,QAAQ,GAAG,yBAAyB;AACvE,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,uCAAuC;AACrE,KAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEzC,QAAM,MAAM,eAAe,IAAI;AAC/B,QAAM,YAAY,KAAK,YAAY,GAAG,KAAK;AAC3C,QAAM,eAAe,YAAY,KAAK,KAAK,SAAS,GAAG,KAAK,IAAI,MAAM,IAAI;AAE1E,QAAM,aAAa,KAAK,YAAY;AAEpC,MAAI,WAAW;AACb,aAAS,aAAa,YAAY,SAAS,OAAO,KAAK,EAAE,OAAO,OAAO,CAAC;AACxE,QAAI;AAAE,SAAG,WAAW,YAAY;AAAA,IAAE,QAAQ;AAAA,IAAe;AAAA,EAC3D;AAEA,MAAI,CAAC,YAAY;AACf,OAAG,UAAU,SAAS,KAAK;AAAA,EAC7B;AAEA,MAAI,KAAK,EAAE,MAAM,KAAK,MAAM,MAAM,QAAQ,GAAG,wBAAwB;AACrE,SAAO;AACT;","names":[]}
|