@openacp/cli 2026.330.3 → 2026.331.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/README.md +19 -1
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +25134 -278
- package/dist/cli.js.map +1 -1
- package/dist/data/registry-snapshot.json +1 -1
- package/dist/index.d.ts +259 -30
- package/dist/index.js +17632 -404
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/adapter-AWSI4GML.js +0 -13
- package/dist/adapter-AWSI4GML.js.map +0 -1
- package/dist/agent-catalog-SZQQERV7.js +0 -10
- package/dist/agent-catalog-SZQQERV7.js.map +0 -1
- package/dist/agent-dependencies-ED2ZTUHG.js +0 -23
- package/dist/agent-dependencies-ED2ZTUHG.js.map +0 -1
- package/dist/agent-registry-YOGP656W.js +0 -8
- package/dist/agent-registry-YOGP656W.js.map +0 -1
- package/dist/agent-store-5UHZH2XI.js +0 -8
- package/dist/agent-store-5UHZH2XI.js.map +0 -1
- package/dist/api-client-XTLRRFPX.js +0 -13
- package/dist/api-client-XTLRRFPX.js.map +0 -1
- package/dist/api-server-5VNYFWJE.js +0 -7
- package/dist/api-server-5VNYFWJE.js.map +0 -1
- package/dist/api-server-JLBDKCU4.js +0 -10
- package/dist/api-server-JLBDKCU4.js.map +0 -1
- package/dist/autostart-CUPZMKKC.js +0 -22
- package/dist/autostart-CUPZMKKC.js.map +0 -1
- package/dist/chunk-237WYH6H.js +0 -235
- package/dist/chunk-237WYH6H.js.map +0 -1
- package/dist/chunk-2HEFALTZ.js +0 -44
- package/dist/chunk-2HEFALTZ.js.map +0 -1
- package/dist/chunk-2KT6TROD.js +0 -129
- package/dist/chunk-2KT6TROD.js.map +0 -1
- package/dist/chunk-2R5XM3ES.js +0 -154
- package/dist/chunk-2R5XM3ES.js.map +0 -1
- package/dist/chunk-3EWTPOF7.js +0 -51
- package/dist/chunk-3EWTPOF7.js.map +0 -1
- package/dist/chunk-3NAFXVQM.js +0 -67
- 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-566W6INH.js +0 -83
- package/dist/chunk-566W6INH.js.map +0 -1
- package/dist/chunk-5HKQCYOI.js +0 -145
- package/dist/chunk-5HKQCYOI.js.map +0 -1
- package/dist/chunk-5OCGO27U.js +0 -125
- package/dist/chunk-5OCGO27U.js.map +0 -1
- package/dist/chunk-5WGVYX3C.js +0 -55
- package/dist/chunk-5WGVYX3C.js.map +0 -1
- package/dist/chunk-7ZCQF6QM.js +0 -27
- package/dist/chunk-7ZCQF6QM.js.map +0 -1
- package/dist/chunk-AFKX424Q.js +0 -92
- package/dist/chunk-AFKX424Q.js.map +0 -1
- package/dist/chunk-APS6UEFU.js +0 -259
- package/dist/chunk-APS6UEFU.js.map +0 -1
- package/dist/chunk-BTJHGSLM.js +0 -1116
- package/dist/chunk-BTJHGSLM.js.map +0 -1
- package/dist/chunk-CDAUYTVP.js +0 -41
- package/dist/chunk-CDAUYTVP.js.map +0 -1
- package/dist/chunk-FCTC7KDT.js +0 -101
- package/dist/chunk-FCTC7KDT.js.map +0 -1
- package/dist/chunk-FNRSWA2K.js +0 -1
- package/dist/chunk-FNRSWA2K.js.map +0 -1
- package/dist/chunk-GEOXPGCO.js +0 -650
- package/dist/chunk-GEOXPGCO.js.map +0 -1
- package/dist/chunk-IZ5UEZF7.js +0 -138
- package/dist/chunk-IZ5UEZF7.js.map +0 -1
- package/dist/chunk-KDU3ZEWT.js +0 -97
- package/dist/chunk-KDU3ZEWT.js.map +0 -1
- package/dist/chunk-LGFWH3AE.js +0 -26
- package/dist/chunk-LGFWH3AE.js.map +0 -1
- package/dist/chunk-MITTQMGZ.js +0 -543
- package/dist/chunk-MITTQMGZ.js.map +0 -1
- package/dist/chunk-MLF4W5R6.js +0 -101
- package/dist/chunk-MLF4W5R6.js.map +0 -1
- package/dist/chunk-MPGEHTGE.js +0 -679
- package/dist/chunk-MPGEHTGE.js.map +0 -1
- package/dist/chunk-OYSAN7UX.js +0 -15
- package/dist/chunk-OYSAN7UX.js.map +0 -1
- package/dist/chunk-PA6MNBG4.js +0 -190
- package/dist/chunk-PA6MNBG4.js.map +0 -1
- package/dist/chunk-QWVHCTCA.js +0 -172
- package/dist/chunk-QWVHCTCA.js.map +0 -1
- package/dist/chunk-R6KZYF7D.js +0 -231
- package/dist/chunk-R6KZYF7D.js.map +0 -1
- package/dist/chunk-S64CB6J3.js +0 -98
- package/dist/chunk-S64CB6J3.js.map +0 -1
- package/dist/chunk-TMVTSWVH.js +0 -228
- package/dist/chunk-TMVTSWVH.js.map +0 -1
- package/dist/chunk-UCIZM5SW.js +0 -3917
- package/dist/chunk-UCIZM5SW.js.map +0 -1
- package/dist/chunk-UWH7KIAA.js +0 -701
- package/dist/chunk-UWH7KIAA.js.map +0 -1
- package/dist/chunk-V2YZWYXT.js +0 -484
- package/dist/chunk-V2YZWYXT.js.map +0 -1
- package/dist/chunk-W26AUH5B.js +0 -61
- package/dist/chunk-W26AUH5B.js.map +0 -1
- package/dist/chunk-W4LK6WJP.js +0 -446
- package/dist/chunk-W4LK6WJP.js.map +0 -1
- package/dist/chunk-WQCJTU2C.js +0 -84
- package/dist/chunk-WQCJTU2C.js.map +0 -1
- package/dist/chunk-XBZIHNKV.js +0 -6410
- package/dist/chunk-XBZIHNKV.js.map +0 -1
- package/dist/chunk-ZSLHHQPQ.js +0 -282
- package/dist/chunk-ZSLHHQPQ.js.map +0 -1
- package/dist/config-KN6NKKPF.js +0 -20
- package/dist/config-KN6NKKPF.js.map +0 -1
- package/dist/config-editor-76RVZS4B.js +0 -10
- package/dist/config-editor-76RVZS4B.js.map +0 -1
- package/dist/config-registry-ZXAIJNYB.js +0 -17
- package/dist/config-registry-ZXAIJNYB.js.map +0 -1
- package/dist/context-NXXW62NJ.js +0 -9
- package/dist/context-NXXW62NJ.js.map +0 -1
- package/dist/core-plugins-BPZY7SEB.js +0 -22
- package/dist/core-plugins-BPZY7SEB.js.map +0 -1
- package/dist/daemon-XFEMMJSZ.js +0 -29
- package/dist/daemon-XFEMMJSZ.js.map +0 -1
- package/dist/dev-loader-7P3HZCIA.js +0 -37
- package/dist/dev-loader-7P3HZCIA.js.map +0 -1
- package/dist/doctor-AV6AUO22.js +0 -9
- package/dist/doctor-AV6AUO22.js.map +0 -1
- package/dist/file-service-HHB3JQIO.js +0 -8
- package/dist/file-service-HHB3JQIO.js.map +0 -1
- package/dist/install-cloudflared-JRJ4BSOM.js +0 -32
- package/dist/install-cloudflared-JRJ4BSOM.js.map +0 -1
- package/dist/install-context-EHYV5WRY.js +0 -77
- package/dist/install-context-EHYV5WRY.js.map +0 -1
- package/dist/install-jq-ISTGT263.js +0 -31
- package/dist/install-jq-ISTGT263.js.map +0 -1
- package/dist/integrate-JIEZYDOR.js +0 -371
- package/dist/integrate-JIEZYDOR.js.map +0 -1
- package/dist/log-YZ243M5G.js +0 -25
- package/dist/log-YZ243M5G.js.map +0 -1
- package/dist/main-VEJCG5PY.js +0 -654
- package/dist/main-VEJCG5PY.js.map +0 -1
- package/dist/menu-ALFN37IR.js +0 -15
- package/dist/menu-ALFN37IR.js.map +0 -1
- package/dist/notifications-MO23S7S3.js +0 -8
- package/dist/notifications-MO23S7S3.js.map +0 -1
- package/dist/plugin-create-EHL76ZZG.js +0 -966
- package/dist/plugin-create-EHL76ZZG.js.map +0 -1
- package/dist/plugin-installer-VSTYZSXC.js +0 -9
- package/dist/plugin-installer-VSTYZSXC.js.map +0 -1
- package/dist/plugin-registry-6J3YSFHF.js +0 -7
- package/dist/plugin-registry-6J3YSFHF.js.map +0 -1
- package/dist/plugin-search-MGKAL5JM.js +0 -39
- package/dist/plugin-search-MGKAL5JM.js.map +0 -1
- package/dist/post-upgrade-Y26S2ZQ7.js +0 -79
- package/dist/post-upgrade-Y26S2ZQ7.js.map +0 -1
- package/dist/read-text-file-DJBTITIB.js +0 -7
- package/dist/read-text-file-DJBTITIB.js.map +0 -1
- package/dist/registry-client-GTBWLXYU.js +0 -7
- package/dist/registry-client-GTBWLXYU.js.map +0 -1
- package/dist/security-2BA265LN.js +0 -8
- package/dist/security-2BA265LN.js.map +0 -1
- package/dist/settings-manager-B4UN2LAC.js +0 -7
- package/dist/settings-manager-B4UN2LAC.js.map +0 -1
- package/dist/setup-DISPNDEK.js +0 -802
- package/dist/setup-DISPNDEK.js.map +0 -1
- package/dist/speech-SG62JYIF.js +0 -9
- package/dist/speech-SG62JYIF.js.map +0 -1
- package/dist/suggest-RST5VOHB.js +0 -36
- package/dist/suggest-RST5VOHB.js.map +0 -1
- package/dist/telegram-L3YM6SQJ.js +0 -7
- package/dist/telegram-L3YM6SQJ.js.map +0 -1
- package/dist/tunnel-HWJ27WDH.js +0 -7
- package/dist/tunnel-HWJ27WDH.js.map +0 -1
- package/dist/tunnel-service-ZMO4THKE.js +0 -1261
- package/dist/tunnel-service-ZMO4THKE.js.map +0 -1
- package/dist/validators-GITLOFXC.js +0 -11
- package/dist/validators-GITLOFXC.js.map +0 -1
- package/dist/version-AXXV6IV2.js +0 -15
- package/dist/version-AXXV6IV2.js.map +0 -1
package/dist/chunk-5OCGO27U.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SecurityGuard
|
|
3
|
-
} from "./chunk-LGFWH3AE.js";
|
|
4
|
-
|
|
5
|
-
// src/plugins/security/index.ts
|
|
6
|
-
function createSecurityPlugin() {
|
|
7
|
-
return {
|
|
8
|
-
name: "@openacp/security",
|
|
9
|
-
version: "1.0.0",
|
|
10
|
-
description: "User access control and session limits",
|
|
11
|
-
essential: false,
|
|
12
|
-
permissions: ["services:register", "middleware:register", "kernel:access", "commands:register"],
|
|
13
|
-
async install(ctx) {
|
|
14
|
-
const { settings, legacyConfig, terminal } = ctx;
|
|
15
|
-
if (legacyConfig) {
|
|
16
|
-
const securityCfg = legacyConfig.security;
|
|
17
|
-
if (securityCfg) {
|
|
18
|
-
await settings.setAll({
|
|
19
|
-
allowedUserIds: securityCfg.allowedUserIds ?? [],
|
|
20
|
-
maxConcurrentSessions: securityCfg.maxConcurrentSessions ?? 20,
|
|
21
|
-
sessionTimeoutMinutes: securityCfg.sessionTimeoutMinutes ?? 60
|
|
22
|
-
});
|
|
23
|
-
terminal.log.success("Security settings migrated from legacy config");
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
await settings.setAll({
|
|
28
|
-
allowedUserIds: [],
|
|
29
|
-
maxConcurrentSessions: 20,
|
|
30
|
-
sessionTimeoutMinutes: 60
|
|
31
|
-
});
|
|
32
|
-
terminal.log.success("Security defaults saved");
|
|
33
|
-
},
|
|
34
|
-
async configure(ctx) {
|
|
35
|
-
const { terminal, settings } = ctx;
|
|
36
|
-
const current = await settings.getAll();
|
|
37
|
-
const choice = await terminal.select({
|
|
38
|
-
message: "What to configure?",
|
|
39
|
-
options: [
|
|
40
|
-
{ value: "allowedUsers", label: "Edit allowed user IDs" },
|
|
41
|
-
{ value: "maxSessions", label: `Max concurrent sessions (current: ${current.maxConcurrentSessions ?? 20})` },
|
|
42
|
-
{ value: "timeout", label: `Session timeout minutes (current: ${current.sessionTimeoutMinutes ?? 60})` },
|
|
43
|
-
{ value: "done", label: "Done" }
|
|
44
|
-
]
|
|
45
|
-
});
|
|
46
|
-
if (choice === "allowedUsers") {
|
|
47
|
-
const currentIds = current.allowedUserIds ?? [];
|
|
48
|
-
const val = await terminal.text({
|
|
49
|
-
message: "Allowed user IDs (comma-separated, empty = allow all):",
|
|
50
|
-
defaultValue: currentIds.join(", ")
|
|
51
|
-
});
|
|
52
|
-
const ids = val.split(",").map((s) => s.trim()).filter(Boolean);
|
|
53
|
-
await settings.set("allowedUserIds", ids);
|
|
54
|
-
terminal.log.success("Allowed user IDs updated");
|
|
55
|
-
} else if (choice === "maxSessions") {
|
|
56
|
-
const val = await terminal.text({
|
|
57
|
-
message: "Max concurrent sessions:",
|
|
58
|
-
defaultValue: String(current.maxConcurrentSessions ?? 20),
|
|
59
|
-
validate: (v) => {
|
|
60
|
-
const n = Number(v.trim());
|
|
61
|
-
if (isNaN(n) || n < 1) return "Must be a positive number";
|
|
62
|
-
return void 0;
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
await settings.set("maxConcurrentSessions", Number(val.trim()));
|
|
66
|
-
terminal.log.success("Max sessions updated");
|
|
67
|
-
} else if (choice === "timeout") {
|
|
68
|
-
const val = await terminal.text({
|
|
69
|
-
message: "Session timeout (minutes):",
|
|
70
|
-
defaultValue: String(current.sessionTimeoutMinutes ?? 60),
|
|
71
|
-
validate: (v) => {
|
|
72
|
-
const n = Number(v.trim());
|
|
73
|
-
if (isNaN(n) || n < 1) return "Must be a positive number";
|
|
74
|
-
return void 0;
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
await settings.set("sessionTimeoutMinutes", Number(val.trim()));
|
|
78
|
-
terminal.log.success("Session timeout updated");
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
async uninstall(ctx, opts) {
|
|
82
|
-
if (opts.purge) {
|
|
83
|
-
await ctx.settings.clear();
|
|
84
|
-
ctx.terminal.log.success("Security settings cleared");
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
async setup(ctx) {
|
|
88
|
-
const core = ctx.core;
|
|
89
|
-
const guard = new SecurityGuard(core.configManager, core.sessionManager);
|
|
90
|
-
ctx.registerMiddleware("message:incoming", {
|
|
91
|
-
handler: async (payload, next) => {
|
|
92
|
-
const access = guard.checkAccess(payload);
|
|
93
|
-
if (!access.allowed) {
|
|
94
|
-
ctx.log.info(`Access denied: ${access.reason}`);
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
return next();
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
ctx.registerService("security", guard);
|
|
101
|
-
ctx.registerCommand({
|
|
102
|
-
name: "dangerous",
|
|
103
|
-
description: "Toggle dangerous mode (auto-approve all permissions)",
|
|
104
|
-
usage: "on|off",
|
|
105
|
-
category: "plugin",
|
|
106
|
-
handler: async (args) => {
|
|
107
|
-
const mode = args.raw.trim().toLowerCase();
|
|
108
|
-
if (mode === "on") return { type: "text", text: "Dangerous mode enabled \u2014 all permissions will be auto-approved." };
|
|
109
|
-
if (mode === "off") return { type: "text", text: "Dangerous mode disabled \u2014 permissions require manual approval." };
|
|
110
|
-
return { type: "menu", title: "Dangerous Mode", options: [
|
|
111
|
-
{ label: "Enable", command: "/dangerous on" },
|
|
112
|
-
{ label: "Disable", command: "/dangerous off" }
|
|
113
|
-
] };
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
ctx.log.info("Security service ready");
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
var security_default = createSecurityPlugin();
|
|
121
|
-
|
|
122
|
-
export {
|
|
123
|
-
security_default
|
|
124
|
-
};
|
|
125
|
-
//# sourceMappingURL=chunk-5OCGO27U.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/security/index.ts"],"sourcesContent":["import type { OpenACPPlugin, InstallContext, MiddlewarePayloadMap } from '../../core/plugin/types.js'\nimport { SecurityGuard } from './security-guard.js'\nimport type { IncomingMessage } from '../../core/types.js'\n\n// Structural type for the core fields SecurityGuard needs, avoiding\n// a direct dependency on OpenACPCore's full interface.\ninterface SecurityCoreAccess {\n configManager: ConstructorParameters<typeof SecurityGuard>[0]\n sessionManager: ConstructorParameters<typeof SecurityGuard>[1]\n}\n\n// Factory function pattern (closure for state)\nfunction createSecurityPlugin(): OpenACPPlugin {\n return {\n name: '@openacp/security',\n version: '1.0.0',\n description: 'User access control and session limits',\n essential: false,\n permissions: ['services:register', 'middleware:register', 'kernel:access', 'commands:register'],\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 securityCfg = legacyConfig.security as Record<string, unknown> | undefined\n if (securityCfg) {\n await settings.setAll({\n allowedUserIds: securityCfg.allowedUserIds ?? [],\n maxConcurrentSessions: securityCfg.maxConcurrentSessions ?? 20,\n sessionTimeoutMinutes: securityCfg.sessionTimeoutMinutes ?? 60,\n })\n terminal.log.success('Security settings migrated from legacy config')\n return\n }\n }\n\n // Save defaults (no interactive prompts needed)\n await settings.setAll({\n allowedUserIds: [],\n maxConcurrentSessions: 20,\n sessionTimeoutMinutes: 60,\n })\n terminal.log.success('Security 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: 'allowedUsers', label: 'Edit allowed user IDs' },\n { value: 'maxSessions', label: `Max concurrent sessions (current: ${current.maxConcurrentSessions ?? 20})` },\n { value: 'timeout', label: `Session timeout minutes (current: ${current.sessionTimeoutMinutes ?? 60})` },\n { value: 'done', label: 'Done' },\n ],\n })\n\n if (choice === 'allowedUsers') {\n const currentIds = (current.allowedUserIds as string[]) ?? []\n const val = await terminal.text({\n message: 'Allowed user IDs (comma-separated, empty = allow all):',\n defaultValue: currentIds.join(', '),\n })\n const ids = val.split(',').map((s) => s.trim()).filter(Boolean)\n await settings.set('allowedUserIds', ids)\n terminal.log.success('Allowed user IDs updated')\n } else if (choice === 'maxSessions') {\n const val = await terminal.text({\n message: 'Max concurrent sessions:',\n defaultValue: String(current.maxConcurrentSessions ?? 20),\n validate: (v) => {\n const n = Number(v.trim())\n if (isNaN(n) || n < 1) return 'Must be a positive number'\n return undefined\n },\n })\n await settings.set('maxConcurrentSessions', Number(val.trim()))\n terminal.log.success('Max sessions updated')\n } else if (choice === 'timeout') {\n const val = await terminal.text({\n message: 'Session timeout (minutes):',\n defaultValue: String(current.sessionTimeoutMinutes ?? 60),\n validate: (v) => {\n const n = Number(v.trim())\n if (isNaN(n) || n < 1) return 'Must be a positive number'\n return undefined\n },\n })\n await settings.set('sessionTimeoutMinutes', Number(val.trim()))\n terminal.log.success('Session timeout 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('Security settings cleared')\n }\n },\n\n async setup(ctx) {\n const core = ctx.core as SecurityCoreAccess\n const guard = new SecurityGuard(core.configManager, core.sessionManager)\n\n // Register middleware for message:incoming — block unauthorized users\n ctx.registerMiddleware('message:incoming', {\n handler: async (payload: MiddlewarePayloadMap['message:incoming'], next) => {\n const access = guard.checkAccess(payload as unknown as IncomingMessage)\n if (!access.allowed) {\n ctx.log.info(`Access denied: ${access.reason}`)\n return null // block\n }\n return next()\n }\n })\n\n // Register SecurityGuard as the service directly\n ctx.registerService('security', guard)\n\n ctx.registerCommand({\n name: 'dangerous',\n description: 'Toggle dangerous mode (auto-approve all permissions)',\n usage: 'on|off',\n category: 'plugin',\n handler: async (args) => {\n const mode = args.raw.trim().toLowerCase()\n if (mode === 'on') return { type: 'text', text: 'Dangerous mode enabled — all permissions will be auto-approved.' }\n if (mode === 'off') return { type: 'text', text: 'Dangerous mode disabled — permissions require manual approval.' }\n return { type: 'menu', title: 'Dangerous Mode', options: [\n { label: 'Enable', command: '/dangerous on' },\n { label: 'Disable', command: '/dangerous off' },\n ]}\n },\n })\n\n ctx.log.info('Security service ready')\n },\n }\n}\n\nexport default createSecurityPlugin()\n"],"mappings":"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","names":[]}
|
package/dist/chunk-5WGVYX3C.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// src/core/plugin/plugin-installer.ts
|
|
2
|
-
import { exec } from "child_process";
|
|
3
|
-
import { promisify } from "util";
|
|
4
|
-
import * as fs from "fs/promises";
|
|
5
|
-
import * as os from "os";
|
|
6
|
-
import * as path from "path";
|
|
7
|
-
import { pathToFileURL } from "url";
|
|
8
|
-
var execAsync = promisify(exec);
|
|
9
|
-
async function importFromDir(packageName, dir) {
|
|
10
|
-
const pkgDir = path.join(dir, "node_modules", ...packageName.split("/"));
|
|
11
|
-
const pkgJsonPath = path.join(pkgDir, "package.json");
|
|
12
|
-
let pkgJson;
|
|
13
|
-
try {
|
|
14
|
-
pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, "utf-8"));
|
|
15
|
-
} catch (err) {
|
|
16
|
-
throw new Error(`Cannot read package.json for "${packageName}" at ${pkgJsonPath}: ${err.message}`);
|
|
17
|
-
}
|
|
18
|
-
let entry;
|
|
19
|
-
const exportsMain = pkgJson.exports?.["."];
|
|
20
|
-
if (typeof exportsMain === "string") {
|
|
21
|
-
entry = exportsMain;
|
|
22
|
-
} else if (exportsMain?.import) {
|
|
23
|
-
entry = exportsMain.import;
|
|
24
|
-
} else {
|
|
25
|
-
entry = pkgJson.main ?? "index.js";
|
|
26
|
-
}
|
|
27
|
-
const entryPath = path.join(pkgDir, entry);
|
|
28
|
-
try {
|
|
29
|
-
await fs.access(entryPath);
|
|
30
|
-
} catch {
|
|
31
|
-
throw new Error(`Entry point "${entry}" not found for "${packageName}" at ${entryPath}`);
|
|
32
|
-
}
|
|
33
|
-
return import(pathToFileURL(entryPath).href);
|
|
34
|
-
}
|
|
35
|
-
var VALID_NPM_NAME = /^(@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*(@[\w.^~>=<|-]+)?$/i;
|
|
36
|
-
async function installNpmPlugin(packageName, pluginsDir) {
|
|
37
|
-
if (!VALID_NPM_NAME.test(packageName)) {
|
|
38
|
-
throw new Error(`Invalid package name: "${packageName}". Must be a valid npm package name.`);
|
|
39
|
-
}
|
|
40
|
-
const dir = pluginsDir ?? path.join(os.homedir(), ".openacp", "plugins");
|
|
41
|
-
try {
|
|
42
|
-
return await importFromDir(packageName, dir);
|
|
43
|
-
} catch {
|
|
44
|
-
}
|
|
45
|
-
await execAsync(`npm install ${packageName} --prefix "${dir}" --save`, {
|
|
46
|
-
timeout: 6e4
|
|
47
|
-
});
|
|
48
|
-
return await importFromDir(packageName, dir);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export {
|
|
52
|
-
importFromDir,
|
|
53
|
-
installNpmPlugin
|
|
54
|
-
};
|
|
55
|
-
//# sourceMappingURL=chunk-5WGVYX3C.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/plugin/plugin-installer.ts"],"sourcesContent":["import { exec } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport * as fs from 'node:fs/promises'\nimport * as os from 'node:os'\nimport * as path from 'node:path'\nimport { pathToFileURL } from 'node:url'\n\nconst execAsync = promisify(exec)\n\n/**\n * Import a package resolved from a specific directory (not the project root).\n * Reads the package's package.json to find the ESM entry point, then imports by file path.\n */\nexport async function importFromDir(packageName: string, dir: string): Promise<any> {\n const pkgDir = path.join(dir, 'node_modules', ...packageName.split('/'))\n const pkgJsonPath = path.join(pkgDir, 'package.json')\n\n let pkgJson: Record<string, any>\n try {\n pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8'))\n } catch (err) {\n throw new Error(`Cannot read package.json for \"${packageName}\" at ${pkgJsonPath}: ${(err as Error).message}`)\n }\n\n // Resolve entry: exports[\".\"].import > main > index.js\n let entry: string\n const exportsMain = pkgJson.exports?.['.']\n if (typeof exportsMain === 'string') {\n entry = exportsMain\n } else if (exportsMain?.import) {\n entry = exportsMain.import\n } else {\n entry = pkgJson.main ?? 'index.js'\n }\n\n const entryPath = path.join(pkgDir, entry)\n try {\n await fs.access(entryPath)\n } catch {\n throw new Error(`Entry point \"${entry}\" not found for \"${packageName}\" at ${entryPath}`)\n }\n\n return import(pathToFileURL(entryPath).href)\n}\n\n/** Valid npm package name: optional @scope/, alphanumeric/hyphens/dots, optional @version */\nconst VALID_NPM_NAME = /^(@[a-z0-9][\\w.-]*\\/)?[a-z0-9][\\w.-]*(@[\\w.^~>=<|-]+)?$/i;\n\n/**\n * Install an npm package to the plugins directory and return the loaded module.\n * Tries to import first; if not installed, runs npm install asynchronously.\n */\nexport async function installNpmPlugin(packageName: string, pluginsDir?: string): Promise<any> {\n if (!VALID_NPM_NAME.test(packageName)) {\n throw new Error(`Invalid package name: \"${packageName}\". Must be a valid npm package name.`);\n }\n\n const dir = pluginsDir ?? path.join(os.homedir(), '.openacp', 'plugins')\n\n // Try import from plugins dir first — already installed\n try {\n return await importFromDir(packageName, dir)\n } catch {\n // Not installed, proceed with install\n }\n\n await execAsync(`npm install ${packageName} --prefix \"${dir}\" --save`, {\n timeout: 60000,\n })\n\n return await importFromDir(packageName, dir)\n}\n"],"mappings":";AAAA,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,qBAAqB;AAE9B,IAAM,YAAY,UAAU,IAAI;AAMhC,eAAsB,cAAc,aAAqB,KAA2B;AAClF,QAAM,SAAc,UAAK,KAAK,gBAAgB,GAAG,YAAY,MAAM,GAAG,CAAC;AACvE,QAAM,cAAmB,UAAK,QAAQ,cAAc;AAEpD,MAAI;AACJ,MAAI;AACF,cAAU,KAAK,MAAM,MAAS,YAAS,aAAa,OAAO,CAAC;AAAA,EAC9D,SAAS,KAAK;AACZ,UAAM,IAAI,MAAM,iCAAiC,WAAW,QAAQ,WAAW,KAAM,IAAc,OAAO,EAAE;AAAA,EAC9G;AAGA,MAAI;AACJ,QAAM,cAAc,QAAQ,UAAU,GAAG;AACzC,MAAI,OAAO,gBAAgB,UAAU;AACnC,YAAQ;AAAA,EACV,WAAW,aAAa,QAAQ;AAC9B,YAAQ,YAAY;AAAA,EACtB,OAAO;AACL,YAAQ,QAAQ,QAAQ;AAAA,EAC1B;AAEA,QAAM,YAAiB,UAAK,QAAQ,KAAK;AACzC,MAAI;AACF,UAAS,UAAO,SAAS;AAAA,EAC3B,QAAQ;AACN,UAAM,IAAI,MAAM,gBAAgB,KAAK,oBAAoB,WAAW,QAAQ,SAAS,EAAE;AAAA,EACzF;AAEA,SAAO,OAAO,cAAc,SAAS,EAAE;AACzC;AAGA,IAAM,iBAAiB;AAMvB,eAAsB,iBAAiB,aAAqB,YAAmC;AAC7F,MAAI,CAAC,eAAe,KAAK,WAAW,GAAG;AACrC,UAAM,IAAI,MAAM,0BAA0B,WAAW,sCAAsC;AAAA,EAC7F;AAEA,QAAM,MAAM,cAAmB,UAAQ,WAAQ,GAAG,YAAY,SAAS;AAGvE,MAAI;AACF,WAAO,MAAM,cAAc,aAAa,GAAG;AAAA,EAC7C,QAAQ;AAAA,EAER;AAEA,QAAM,UAAU,eAAe,WAAW,cAAc,GAAG,YAAY;AAAA,IACrE,SAAS;AAAA,EACX,CAAC;AAED,SAAO,MAAM,cAAc,aAAa,GAAG;AAC7C;","names":[]}
|
package/dist/chunk-7ZCQF6QM.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// src/plugins/notifications/notification.ts
|
|
2
|
-
var NotificationManager = class {
|
|
3
|
-
constructor(adapters) {
|
|
4
|
-
this.adapters = adapters;
|
|
5
|
-
}
|
|
6
|
-
async notify(channelId, notification) {
|
|
7
|
-
const adapter = this.adapters.get(channelId);
|
|
8
|
-
if (!adapter) return;
|
|
9
|
-
try {
|
|
10
|
-
await adapter.sendNotification(notification);
|
|
11
|
-
} catch {
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
async notifyAll(notification) {
|
|
15
|
-
for (const adapter of this.adapters.values()) {
|
|
16
|
-
try {
|
|
17
|
-
await adapter.sendNotification(notification);
|
|
18
|
-
} catch {
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export {
|
|
25
|
-
NotificationManager
|
|
26
|
-
};
|
|
27
|
-
//# sourceMappingURL=chunk-7ZCQF6QM.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/notifications/notification.ts"],"sourcesContent":["import type { IChannelAdapter } from '../../core/channel.js'\nimport type { NotificationMessage } from '../../core/types.js'\n\nexport class NotificationManager {\n constructor(private adapters: Map<string, IChannelAdapter>) {}\n\n async notify(channelId: string, notification: NotificationMessage): Promise<void> {\n const adapter = this.adapters.get(channelId)\n if (!adapter) return\n try {\n await adapter.sendNotification(notification)\n } catch {\n // Don't let notification failures crash the caller\n }\n }\n\n async notifyAll(notification: NotificationMessage): Promise<void> {\n for (const adapter of this.adapters.values()) {\n try {\n await adapter.sendNotification(notification)\n } catch {\n // Continue to next adapter\n }\n }\n }\n}\n"],"mappings":";AAGO,IAAM,sBAAN,MAA0B;AAAA,EAC/B,YAAoB,UAAwC;AAAxC;AAAA,EAAyC;AAAA,EAE7D,MAAM,OAAO,WAAmB,cAAkD;AAChF,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,QAAS;AACd,QAAI;AACF,YAAM,QAAQ,iBAAiB,YAAY;AAAA,IAC7C,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,cAAkD;AAChE,eAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC5C,UAAI;AACF,cAAM,QAAQ,iBAAiB,YAAY;AAAA,MAC7C,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/dist/chunk-AFKX424Q.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// src/plugins/telegram/commands/menu.ts
|
|
2
|
-
import { InlineKeyboard } from "grammy";
|
|
3
|
-
function buildMenuKeyboard() {
|
|
4
|
-
return new InlineKeyboard().text("\u{1F195} New Session", "m:new").text("\u{1F4CB} Sessions", "m:topics").row().text("\u{1F4CA} Status", "m:status").text("\u{1F916} Agents", "m:agents").row().text("\u2699\uFE0F Settings", "m:settings").text("\u{1F517} Integrate", "m:integrate").row().text("\u{1F504} Restart", "m:restart").text("\u2B06\uFE0F Update", "m:update").row().text("\u2753 Help", "m:help").text("\u{1FA7A} Doctor", "m:doctor");
|
|
5
|
-
}
|
|
6
|
-
async function handleMenu(ctx) {
|
|
7
|
-
await ctx.reply(`<b>OpenACP Menu</b>
|
|
8
|
-
Choose an action:`, {
|
|
9
|
-
parse_mode: "HTML",
|
|
10
|
-
reply_markup: buildMenuKeyboard()
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
async function handleHelp(ctx) {
|
|
14
|
-
await ctx.reply(
|
|
15
|
-
`\u{1F4D6} <b>OpenACP Help</b>
|
|
16
|
-
|
|
17
|
-
\u{1F680} <b>Getting Started</b>
|
|
18
|
-
Tap \u{1F195} New Session to start coding with AI.
|
|
19
|
-
Each session gets its own topic \u2014 chat there to work with the agent.
|
|
20
|
-
|
|
21
|
-
\u{1F4A1} <b>Common Tasks</b>
|
|
22
|
-
/new [agent] [workspace] \u2014 Create new session
|
|
23
|
-
/cancel \u2014 Cancel session (in session topic)
|
|
24
|
-
/status \u2014 Show session or system status
|
|
25
|
-
/sessions \u2014 List all sessions
|
|
26
|
-
/agents \u2014 Browse & install agents
|
|
27
|
-
/install <name> \u2014 Install an agent
|
|
28
|
-
|
|
29
|
-
\u2699\uFE0F <b>System</b>
|
|
30
|
-
/restart \u2014 Restart OpenACP
|
|
31
|
-
/update \u2014 Update to latest version
|
|
32
|
-
/integrate \u2014 Manage agent integrations
|
|
33
|
-
/menu \u2014 Show action menu
|
|
34
|
-
|
|
35
|
-
\u{1F512} <b>Session Options</b>
|
|
36
|
-
/enable_dangerous \u2014 Auto-approve permissions
|
|
37
|
-
/disable_dangerous \u2014 Restore permission prompts
|
|
38
|
-
/handoff \u2014 Continue session in terminal
|
|
39
|
-
/archive \u2014 Archive session topic
|
|
40
|
-
/clear \u2014 Clear assistant history
|
|
41
|
-
|
|
42
|
-
\u{1F4AC} Need help? Just ask me in this topic!`,
|
|
43
|
-
{ parse_mode: "HTML" }
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
async function handleClear(ctx, assistant) {
|
|
47
|
-
if (!assistant) {
|
|
48
|
-
await ctx.reply("\u26A0\uFE0F Assistant is not available.", { parse_mode: "HTML" });
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const threadId = ctx.message?.message_thread_id;
|
|
52
|
-
if (threadId !== assistant.topicId) {
|
|
53
|
-
await ctx.reply("\u2139\uFE0F /clear only works in the Assistant topic.", { parse_mode: "HTML" });
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
await ctx.reply("\u{1F504} Clearing assistant history...", { parse_mode: "HTML" });
|
|
57
|
-
try {
|
|
58
|
-
await assistant.respawn();
|
|
59
|
-
await ctx.reply("\u2705 Assistant history cleared.", { parse_mode: "HTML" });
|
|
60
|
-
} catch (err) {
|
|
61
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
62
|
-
await ctx.reply(`\u274C Failed to clear: <code>${message}</code>`, { parse_mode: "HTML" });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
var TELEGRAM_MSG_LIMIT = 4096;
|
|
66
|
-
function buildSkillMessages(commands) {
|
|
67
|
-
const sorted = [...commands].sort((a, b) => a.name.localeCompare(b.name));
|
|
68
|
-
const header = "\u{1F6E0} <b>Available Skills</b>\n";
|
|
69
|
-
const lines = sorted.map((c) => `<code>/${c.name}</code>`);
|
|
70
|
-
const messages = [];
|
|
71
|
-
let current = header;
|
|
72
|
-
for (const line of lines) {
|
|
73
|
-
const candidate = current + "\n" + line;
|
|
74
|
-
if (candidate.length > TELEGRAM_MSG_LIMIT) {
|
|
75
|
-
messages.push(current);
|
|
76
|
-
current = line;
|
|
77
|
-
} else {
|
|
78
|
-
current = candidate;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
if (current) messages.push(current);
|
|
82
|
-
return messages;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export {
|
|
86
|
-
buildMenuKeyboard,
|
|
87
|
-
handleMenu,
|
|
88
|
-
handleHelp,
|
|
89
|
-
handleClear,
|
|
90
|
-
buildSkillMessages
|
|
91
|
-
};
|
|
92
|
-
//# sourceMappingURL=chunk-AFKX424Q.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/telegram/commands/menu.ts"],"sourcesContent":["import type { Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { AgentCommand } from \"../../../core/index.js\";\nimport type { CommandsAssistantContext } from \"../types.js\";\n\nexport function buildMenuKeyboard(): InlineKeyboard {\n return new InlineKeyboard()\n .text(\"🆕 New Session\", \"m:new\")\n .text(\"📋 Sessions\", \"m:topics\")\n .row()\n .text(\"📊 Status\", \"m:status\")\n .text(\"🤖 Agents\", \"m:agents\")\n .row()\n .text(\"⚙️ Settings\", \"m:settings\")\n .text(\"🔗 Integrate\", \"m:integrate\")\n .row()\n .text(\"🔄 Restart\", \"m:restart\")\n .text(\"⬆️ Update\", \"m:update\")\n .row()\n .text(\"❓ Help\", \"m:help\")\n .text(\"🩺 Doctor\", \"m:doctor\");\n}\n\nexport async function handleMenu(ctx: Context): Promise<void> {\n await ctx.reply(`<b>OpenACP Menu</b>\\nChoose an action:`, {\n parse_mode: \"HTML\",\n reply_markup: buildMenuKeyboard(),\n });\n}\n\nexport async function handleHelp(ctx: Context): Promise<void> {\n await ctx.reply(\n `📖 <b>OpenACP Help</b>\\n\\n` +\n `🚀 <b>Getting Started</b>\\n` +\n `Tap 🆕 New Session to start coding with AI.\\n` +\n `Each session gets its own topic — chat there to work with the agent.\\n\\n` +\n `💡 <b>Common Tasks</b>\\n` +\n `/new [agent] [workspace] — Create new session\\n` +\n `/cancel — Cancel session (in session topic)\\n` +\n `/status — Show session or system status\\n` +\n `/sessions — List all sessions\\n` +\n `/agents — Browse & install agents\\n` +\n `/install <name> — Install an agent\\n\\n` +\n `⚙️ <b>System</b>\\n` +\n `/restart — Restart OpenACP\\n` +\n `/update — Update to latest version\\n` +\n `/integrate — Manage agent integrations\\n` +\n `/menu — Show action menu\\n\\n` +\n `🔒 <b>Session Options</b>\\n` +\n `/enable_dangerous — Auto-approve permissions\\n` +\n `/disable_dangerous — Restore permission prompts\\n` +\n `/handoff — Continue session in terminal\\n` +\n `/archive — Archive session topic\\n` +\n `/clear — Clear assistant history\\n\\n` +\n `💬 Need help? Just ask me in this topic!`,\n { parse_mode: \"HTML\" },\n );\n}\n\nexport async function handleClear(ctx: Context, assistant?: CommandsAssistantContext): Promise<void> {\n if (!assistant) {\n await ctx.reply(\"⚠️ Assistant is not available.\", { parse_mode: \"HTML\" });\n return;\n }\n\n const threadId = ctx.message?.message_thread_id;\n if (threadId !== assistant.topicId) {\n await ctx.reply(\"ℹ️ /clear only works in the Assistant topic.\", { parse_mode: \"HTML\" });\n return;\n }\n\n await ctx.reply(\"🔄 Clearing assistant history...\", { parse_mode: \"HTML\" });\n\n try {\n await assistant.respawn();\n await ctx.reply(\"✅ Assistant history cleared.\", { parse_mode: \"HTML\" });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n await ctx.reply(`❌ Failed to clear: <code>${message}</code>`, { parse_mode: \"HTML\" });\n }\n}\n\nconst TELEGRAM_MSG_LIMIT = 4096;\n\n/**\n * Build plain-text skill command messages. Each command is on its own line\n * wrapped in <code> for tap-to-copy. If the list exceeds Telegram's message\n * limit, it is split into multiple messages (cut at line boundaries).\n */\nexport function buildSkillMessages(commands: AgentCommand[]): string[] {\n const sorted = [...commands].sort((a, b) => a.name.localeCompare(b.name));\n const header = \"🛠 <b>Available Skills</b>\\n\";\n const lines = sorted.map((c) => `<code>/${c.name}</code>`);\n\n const messages: string[] = [];\n let current = header;\n\n for (const line of lines) {\n const candidate = current + \"\\n\" + line;\n if (candidate.length > TELEGRAM_MSG_LIMIT) {\n messages.push(current);\n current = line;\n } else {\n current = candidate;\n }\n }\n if (current) messages.push(current);\n return messages;\n}\n"],"mappings":";AACA,SAAS,sBAAsB;AAIxB,SAAS,oBAAoC;AAClD,SAAO,IAAI,eAAe,EACvB,KAAK,yBAAkB,OAAO,EAC9B,KAAK,sBAAe,UAAU,EAC9B,IAAI,EACJ,KAAK,oBAAa,UAAU,EAC5B,KAAK,oBAAa,UAAU,EAC5B,IAAI,EACJ,KAAK,yBAAe,YAAY,EAChC,KAAK,uBAAgB,aAAa,EAClC,IAAI,EACJ,KAAK,qBAAc,WAAW,EAC9B,KAAK,uBAAa,UAAU,EAC5B,IAAI,EACJ,KAAK,eAAU,QAAQ,EACvB,KAAK,oBAAa,UAAU;AACjC;AAEA,eAAsB,WAAW,KAA6B;AAC5D,QAAM,IAAI,MAAM;AAAA,oBAA0C;AAAA,IACxD,YAAY;AAAA,IACZ,cAAc,kBAAkB;AAAA,EAClC,CAAC;AACH;AAEA,eAAsB,WAAW,KAA6B;AAC5D,QAAM,IAAI;AAAA,IACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuBA,EAAE,YAAY,OAAO;AAAA,EACvB;AACF;AAEA,eAAsB,YAAY,KAAc,WAAqD;AACnG,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,4CAAkC,EAAE,YAAY,OAAO,CAAC;AACxE;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,SAAS;AAC9B,MAAI,aAAa,UAAU,SAAS;AAClC,UAAM,IAAI,MAAM,0DAAgD,EAAE,YAAY,OAAO,CAAC;AACtF;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,2CAAoC,EAAE,YAAY,OAAO,CAAC;AAE1E,MAAI;AACF,UAAM,UAAU,QAAQ;AACxB,UAAM,IAAI,MAAM,qCAAgC,EAAE,YAAY,OAAO,CAAC;AAAA,EACxE,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,UAAM,IAAI,MAAM,iCAA4B,OAAO,WAAW,EAAE,YAAY,OAAO,CAAC;AAAA,EACtF;AACF;AAEA,IAAM,qBAAqB;AAOpB,SAAS,mBAAmB,UAAoC;AACrE,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AACxE,QAAM,SAAS;AACf,QAAM,QAAQ,OAAO,IAAI,CAAC,MAAM,UAAU,EAAE,IAAI,SAAS;AAEzD,QAAM,WAAqB,CAAC;AAC5B,MAAI,UAAU;AAEd,aAAW,QAAQ,OAAO;AACxB,UAAM,YAAY,UAAU,OAAO;AACnC,QAAI,UAAU,SAAS,oBAAoB;AACzC,eAAS,KAAK,OAAO;AACrB,gBAAU;AAAA,IACZ,OAAO;AACL,gBAAU;AAAA,IACZ;AAAA,EACF;AACA,MAAI,QAAS,UAAS,KAAK,OAAO;AAClC,SAAO;AACT;","names":[]}
|
package/dist/chunk-APS6UEFU.js
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
// src/plugins/context/context-provider.ts
|
|
2
|
-
var DEFAULT_MAX_TOKENS = 3e4;
|
|
3
|
-
var TOKENS_PER_TURN_ESTIMATE = 400;
|
|
4
|
-
|
|
5
|
-
// src/plugins/context/entire/checkpoint-reader.ts
|
|
6
|
-
import { execFileSync } from "child_process";
|
|
7
|
-
var ENTIRE_BRANCH = "origin/entire/checkpoints/v1";
|
|
8
|
-
var CHECKPOINT_ID_RE = /^[0-9a-f]{12}$/;
|
|
9
|
-
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
10
|
-
var CheckpointReader = class _CheckpointReader {
|
|
11
|
-
constructor(repoPath) {
|
|
12
|
-
this.repoPath = repoPath;
|
|
13
|
-
}
|
|
14
|
-
// ─── Git execution ───────────────────────────────────────────────────────────
|
|
15
|
-
/**
|
|
16
|
-
* Run a git command in the repo directory.
|
|
17
|
-
* Returns trimmed stdout on success, empty string on failure.
|
|
18
|
-
*/
|
|
19
|
-
git(...args) {
|
|
20
|
-
try {
|
|
21
|
-
return execFileSync("git", ["-C", this.repoPath, ...args], {
|
|
22
|
-
encoding: "utf-8"
|
|
23
|
-
}).trim();
|
|
24
|
-
} catch {
|
|
25
|
-
return "";
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
// ─── Static helpers ──────────────────────────────────────────────────────────
|
|
29
|
-
/**
|
|
30
|
-
* Convert a 12-char checkpoint ID to its shard path: "f634acf05138" → "f6/34acf05138"
|
|
31
|
-
*/
|
|
32
|
-
static shardPath(cpId) {
|
|
33
|
-
return `${cpId.slice(0, 2)}/${cpId.slice(2)}`;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Returns true when value looks like a 12-char lowercase hex checkpoint ID.
|
|
37
|
-
*/
|
|
38
|
-
static isCheckpointId(value) {
|
|
39
|
-
return CHECKPOINT_ID_RE.test(value);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Returns true when value looks like a UUID (session ID).
|
|
43
|
-
*/
|
|
44
|
-
static isSessionId(value) {
|
|
45
|
-
return SESSION_ID_RE.test(value);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Parse checkpoint-level metadata JSON. Returns null on error.
|
|
49
|
-
*/
|
|
50
|
-
static parseCheckpointMeta(json) {
|
|
51
|
-
try {
|
|
52
|
-
const parsed = JSON.parse(json);
|
|
53
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
54
|
-
if (!Array.isArray(parsed.sessions)) return null;
|
|
55
|
-
return parsed;
|
|
56
|
-
} catch {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Extract Entire-Checkpoint trailer IDs from `git log --format="%H|%(trailers:...)"` output.
|
|
62
|
-
* Each line is: `<hash>|<trailer_value_or_empty>`. Returns only non-empty trailer values.
|
|
63
|
-
* Uses the last pipe on each line to locate the trailer value, to be robust against
|
|
64
|
-
* subject lines that contain pipes.
|
|
65
|
-
*/
|
|
66
|
-
static parseCheckpointTrailers(output) {
|
|
67
|
-
const ids = [];
|
|
68
|
-
for (const line of output.split("\n")) {
|
|
69
|
-
const pipe = line.lastIndexOf("|");
|
|
70
|
-
if (pipe === -1) continue;
|
|
71
|
-
const trailerId = line.slice(pipe + 1).trim();
|
|
72
|
-
if (trailerId) ids.push(trailerId);
|
|
73
|
-
}
|
|
74
|
-
return ids;
|
|
75
|
-
}
|
|
76
|
-
// ─── Branch check ────────────────────────────────────────────────────────────
|
|
77
|
-
async hasEntireBranch() {
|
|
78
|
-
const out = this.git("branch", "-r");
|
|
79
|
-
return out.includes("entire/checkpoints/v1");
|
|
80
|
-
}
|
|
81
|
-
// ─── Core session fetching ───────────────────────────────────────────────────
|
|
82
|
-
listAllCheckpointIds() {
|
|
83
|
-
const out = this.git(
|
|
84
|
-
"ls-tree",
|
|
85
|
-
"-r",
|
|
86
|
-
ENTIRE_BRANCH,
|
|
87
|
-
"--name-only"
|
|
88
|
-
);
|
|
89
|
-
if (!out) return [];
|
|
90
|
-
const ids = /* @__PURE__ */ new Set();
|
|
91
|
-
for (const file of out.split("\n")) {
|
|
92
|
-
const parts = file.split("/");
|
|
93
|
-
if (parts.length === 3 && parts[2] === "metadata.json") {
|
|
94
|
-
ids.add(parts[0] + parts[1]);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return [...ids];
|
|
98
|
-
}
|
|
99
|
-
fetchCheckpointMeta(cpId) {
|
|
100
|
-
const shard = _CheckpointReader.shardPath(cpId);
|
|
101
|
-
const raw = this.git("show", `${ENTIRE_BRANCH}:${shard}/metadata.json`);
|
|
102
|
-
if (!raw) return null;
|
|
103
|
-
return _CheckpointReader.parseCheckpointMeta(raw);
|
|
104
|
-
}
|
|
105
|
-
fetchSessionMeta(metaPath) {
|
|
106
|
-
const normalized = metaPath.startsWith("/") ? metaPath.slice(1) : metaPath;
|
|
107
|
-
const raw = this.git("show", `${ENTIRE_BRANCH}:${normalized}`);
|
|
108
|
-
if (!raw) return {};
|
|
109
|
-
try {
|
|
110
|
-
return JSON.parse(raw);
|
|
111
|
-
} catch {
|
|
112
|
-
return {};
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Build SessionInfo[] from a single checkpoint's metadata.
|
|
117
|
-
*/
|
|
118
|
-
buildSessionsForCheckpoint(cpId, cpMeta) {
|
|
119
|
-
const sessions = [];
|
|
120
|
-
for (let idx = 0; idx < cpMeta.sessions.length; idx++) {
|
|
121
|
-
const sess = cpMeta.sessions[idx];
|
|
122
|
-
const transcriptPath = (sess.transcript ?? "").replace(/^\//, "");
|
|
123
|
-
const metaPath = sess.metadata ?? "";
|
|
124
|
-
const smeta = this.fetchSessionMeta(metaPath);
|
|
125
|
-
const createdAt = smeta.created_at ?? "";
|
|
126
|
-
sessions.push({
|
|
127
|
-
checkpointId: cpId,
|
|
128
|
-
sessionIndex: String(idx),
|
|
129
|
-
transcriptPath,
|
|
130
|
-
createdAt,
|
|
131
|
-
endedAt: createdAt,
|
|
132
|
-
// will be filled from JSONL by conversation builder
|
|
133
|
-
branch: smeta.branch ?? cpMeta.branch ?? "",
|
|
134
|
-
agent: smeta.agent ?? "",
|
|
135
|
-
turnCount: smeta.session_metrics?.turn_count ?? 0,
|
|
136
|
-
filesTouched: smeta.files_touched ?? cpMeta.files_touched ?? [],
|
|
137
|
-
sessionId: smeta.session_id ?? ""
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
return sessions;
|
|
141
|
-
}
|
|
142
|
-
getSessionsForCheckpoint(cpId) {
|
|
143
|
-
const meta = this.fetchCheckpointMeta(cpId);
|
|
144
|
-
if (!meta) return [];
|
|
145
|
-
return this.buildSessionsForCheckpoint(cpId, meta);
|
|
146
|
-
}
|
|
147
|
-
// ─── Public resolvers ────────────────────────────────────────────────────────
|
|
148
|
-
/**
|
|
149
|
-
* All sessions recorded on a given branch, sorted by createdAt ascending.
|
|
150
|
-
*/
|
|
151
|
-
async resolveByBranch(branchName) {
|
|
152
|
-
const cpIds = this.listAllCheckpointIds();
|
|
153
|
-
const sessions = [];
|
|
154
|
-
for (const cpId of cpIds) {
|
|
155
|
-
const meta = this.fetchCheckpointMeta(cpId);
|
|
156
|
-
if (!meta) continue;
|
|
157
|
-
if (meta.branch !== branchName) continue;
|
|
158
|
-
sessions.push(...this.buildSessionsForCheckpoint(cpId, meta));
|
|
159
|
-
}
|
|
160
|
-
sessions.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
161
|
-
return sessions;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Sessions linked to a specific commit via the Entire-Checkpoint git trailer.
|
|
165
|
-
*/
|
|
166
|
-
async resolveByCommit(commitHash) {
|
|
167
|
-
const fullHash = this.git("rev-parse", commitHash);
|
|
168
|
-
if (!fullHash) return [];
|
|
169
|
-
const cpId = this.git(
|
|
170
|
-
"log",
|
|
171
|
-
"-1",
|
|
172
|
-
"--format=%(trailers:key=Entire-Checkpoint,valueonly)",
|
|
173
|
-
fullHash
|
|
174
|
-
);
|
|
175
|
-
if (!cpId) return [];
|
|
176
|
-
return this.getSessionsForCheckpoint(cpId.trim());
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* All sessions from a merged PR (by number or GitHub URL).
|
|
180
|
-
*/
|
|
181
|
-
async resolveByPr(prInput) {
|
|
182
|
-
let prNumber;
|
|
183
|
-
if (/^\d+$/.test(prInput)) {
|
|
184
|
-
prNumber = prInput;
|
|
185
|
-
} else {
|
|
186
|
-
const m = /\/pull\/(\d+)/.exec(prInput);
|
|
187
|
-
if (!m) return [];
|
|
188
|
-
prNumber = m[1];
|
|
189
|
-
}
|
|
190
|
-
const mergeOut = this.git(
|
|
191
|
-
"log",
|
|
192
|
-
"--all",
|
|
193
|
-
"--oneline",
|
|
194
|
-
"--grep",
|
|
195
|
-
`Merge pull request #${prNumber}`
|
|
196
|
-
);
|
|
197
|
-
if (!mergeOut) return [];
|
|
198
|
-
const mergeCommit = mergeOut.split("\n")[0].split(" ")[0];
|
|
199
|
-
const logOut = this.git(
|
|
200
|
-
"log",
|
|
201
|
-
"--format=%H|%(trailers:key=Entire-Checkpoint,valueonly)",
|
|
202
|
-
`${mergeCommit}^2`,
|
|
203
|
-
"--not",
|
|
204
|
-
`${mergeCommit}^1`
|
|
205
|
-
);
|
|
206
|
-
if (!logOut) return [];
|
|
207
|
-
const cpIds = _CheckpointReader.parseCheckpointTrailers(logOut);
|
|
208
|
-
const sessions = [];
|
|
209
|
-
for (const cpId of cpIds) {
|
|
210
|
-
sessions.push(...this.getSessionsForCheckpoint(cpId));
|
|
211
|
-
}
|
|
212
|
-
sessions.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
213
|
-
return sessions;
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Sessions matching a specific checkpoint ID.
|
|
217
|
-
*/
|
|
218
|
-
async resolveByCheckpoint(checkpointId) {
|
|
219
|
-
return this.getSessionsForCheckpoint(checkpointId);
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Find a session by its UUID.
|
|
223
|
-
*/
|
|
224
|
-
async resolveBySessionId(sessionId) {
|
|
225
|
-
const cpIds = this.listAllCheckpointIds();
|
|
226
|
-
for (const cpId of cpIds) {
|
|
227
|
-
const sessions = this.getSessionsForCheckpoint(cpId);
|
|
228
|
-
const match = sessions.find((s) => s.sessionId === sessionId);
|
|
229
|
-
if (match) return [match];
|
|
230
|
-
}
|
|
231
|
-
return [];
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Latest N sessions across all checkpoints, sorted by createdAt descending.
|
|
235
|
-
*/
|
|
236
|
-
async resolveLatest(count) {
|
|
237
|
-
const cpIds = this.listAllCheckpointIds();
|
|
238
|
-
const all = [];
|
|
239
|
-
for (const cpId of cpIds) {
|
|
240
|
-
all.push(...this.getSessionsForCheckpoint(cpId));
|
|
241
|
-
}
|
|
242
|
-
all.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
243
|
-
return all.slice(0, count);
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Read the full JSONL transcript content from the entire branch.
|
|
247
|
-
*/
|
|
248
|
-
getTranscript(transcriptPath) {
|
|
249
|
-
const normalized = transcriptPath.startsWith("/") ? transcriptPath.slice(1) : transcriptPath;
|
|
250
|
-
return this.git("show", `${ENTIRE_BRANCH}:${normalized}`);
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
export {
|
|
255
|
-
DEFAULT_MAX_TOKENS,
|
|
256
|
-
TOKENS_PER_TURN_ESTIMATE,
|
|
257
|
-
CheckpointReader
|
|
258
|
-
};
|
|
259
|
-
//# sourceMappingURL=chunk-APS6UEFU.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/context/context-provider.ts","../../src/plugins/context/entire/checkpoint-reader.ts"],"sourcesContent":["// NOTE: This interface is designed around Entire as the first provider.\n// It may evolve when additional providers (Cursor history, Zed, etc.) are added.\n// Providers may only support a subset of query types and should return empty results\n// for unsupported types rather than throwing.\n\nexport interface ContextProvider {\n readonly name: string;\n isAvailable(repoPath: string): Promise<boolean>;\n listSessions(query: ContextQuery): Promise<SessionListResult>;\n buildContext(query: ContextQuery, options?: ContextOptions): Promise<ContextResult>;\n}\n\nexport interface ContextQuery {\n repoPath: string;\n type: \"branch\" | \"commit\" | \"pr\" | \"latest\" | \"checkpoint\" | \"session\";\n value: string;\n}\n\nexport interface ContextOptions {\n maxTokens?: number;\n limit?: number;\n}\n\nexport interface SessionInfo {\n checkpointId: string;\n sessionIndex: string;\n transcriptPath: string;\n createdAt: string;\n endedAt: string;\n branch: string;\n agent: string;\n turnCount: number;\n filesTouched: string[];\n sessionId: string;\n}\n\nexport interface SessionListResult {\n sessions: SessionInfo[];\n estimatedTokens: number;\n}\n\nexport type ContextMode = \"full\" | \"balanced\" | \"compact\";\n\nexport interface ContextResult {\n markdown: string;\n tokenEstimate: number;\n sessionCount: number;\n totalTurns: number;\n mode: ContextMode;\n truncated: boolean;\n timeRange: { start: string; end: string };\n}\n\nexport const DEFAULT_MAX_TOKENS = 30_000;\nexport const TOKENS_PER_TURN_ESTIMATE = 400;\n","import { execFileSync } from \"child_process\";\nimport type { SessionInfo } from \"../context-provider.js\";\n\n// ─── Internal types ────────────────────────────────────────────────────────────\n\ninterface CheckpointMeta {\n checkpoint_id?: string;\n branch?: string;\n files_touched?: string[];\n sessions: Array<{\n metadata: string;\n transcript: string;\n }>;\n}\n\ninterface SessionMeta {\n session_id?: string;\n created_at?: string;\n branch?: string;\n agent?: string;\n files_touched?: string[];\n session_metrics?: {\n turn_count?: number;\n };\n}\n\n// ─── CheckpointReader ─────────────────────────────────────────────────────────\n\nconst ENTIRE_BRANCH = \"origin/entire/checkpoints/v1\";\nconst CHECKPOINT_ID_RE = /^[0-9a-f]{12}$/;\nconst SESSION_ID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\n\nexport class CheckpointReader {\n constructor(private readonly repoPath: string) {}\n\n // ─── Git execution ───────────────────────────────────────────────────────────\n\n /**\n * Run a git command in the repo directory.\n * Returns trimmed stdout on success, empty string on failure.\n */\n private git(...args: string[]): string {\n try {\n return execFileSync(\"git\", [\"-C\", this.repoPath, ...args], {\n encoding: \"utf-8\",\n }).trim();\n } catch {\n return \"\";\n }\n }\n\n // ─── Static helpers ──────────────────────────────────────────────────────────\n\n /**\n * Convert a 12-char checkpoint ID to its shard path: \"f634acf05138\" → \"f6/34acf05138\"\n */\n static shardPath(cpId: string): string {\n return `${cpId.slice(0, 2)}/${cpId.slice(2)}`;\n }\n\n /**\n * Returns true when value looks like a 12-char lowercase hex checkpoint ID.\n */\n static isCheckpointId(value: string): boolean {\n return CHECKPOINT_ID_RE.test(value);\n }\n\n /**\n * Returns true when value looks like a UUID (session ID).\n */\n static isSessionId(value: string): boolean {\n return SESSION_ID_RE.test(value);\n }\n\n /**\n * Parse checkpoint-level metadata JSON. Returns null on error.\n */\n static parseCheckpointMeta(json: string): CheckpointMeta | null {\n try {\n const parsed = JSON.parse(json) as CheckpointMeta;\n if (!parsed || typeof parsed !== \"object\") return null;\n if (!Array.isArray(parsed.sessions)) return null;\n return parsed;\n } catch {\n return null;\n }\n }\n\n /**\n * Extract Entire-Checkpoint trailer IDs from `git log --format=\"%H|%(trailers:...)\"` output.\n * Each line is: `<hash>|<trailer_value_or_empty>`. Returns only non-empty trailer values.\n * Uses the last pipe on each line to locate the trailer value, to be robust against\n * subject lines that contain pipes.\n */\n static parseCheckpointTrailers(output: string): string[] {\n const ids: string[] = [];\n for (const line of output.split(\"\\n\")) {\n const pipe = line.lastIndexOf(\"|\");\n if (pipe === -1) continue;\n const trailerId = line.slice(pipe + 1).trim();\n if (trailerId) ids.push(trailerId);\n }\n return ids;\n }\n\n // ─── Branch check ────────────────────────────────────────────────────────────\n\n async hasEntireBranch(): Promise<boolean> {\n const out = this.git(\"branch\", \"-r\");\n return out.includes(\"entire/checkpoints/v1\");\n }\n\n // ─── Core session fetching ───────────────────────────────────────────────────\n\n private listAllCheckpointIds(): string[] {\n const out = this.git(\n \"ls-tree\",\n \"-r\",\n ENTIRE_BRANCH,\n \"--name-only\"\n );\n if (!out) return [];\n\n const ids = new Set<string>();\n for (const file of out.split(\"\\n\")) {\n const parts = file.split(\"/\");\n // Checkpoint-level metadata: XX/YYYYYYYYYY/metadata.json (3 parts)\n if (parts.length === 3 && parts[2] === \"metadata.json\") {\n ids.add(parts[0] + parts[1]);\n }\n }\n return [...ids];\n }\n\n private fetchCheckpointMeta(cpId: string): CheckpointMeta | null {\n const shard = CheckpointReader.shardPath(cpId);\n const raw = this.git(\"show\", `${ENTIRE_BRANCH}:${shard}/metadata.json`);\n if (!raw) return null;\n return CheckpointReader.parseCheckpointMeta(raw);\n }\n\n private fetchSessionMeta(metaPath: string): SessionMeta {\n const normalized = metaPath.startsWith(\"/\") ? metaPath.slice(1) : metaPath;\n const raw = this.git(\"show\", `${ENTIRE_BRANCH}:${normalized}`);\n if (!raw) return {};\n try {\n return JSON.parse(raw) as SessionMeta;\n } catch {\n return {};\n }\n }\n\n /**\n * Build SessionInfo[] from a single checkpoint's metadata.\n */\n private buildSessionsForCheckpoint(\n cpId: string,\n cpMeta: CheckpointMeta\n ): SessionInfo[] {\n const sessions: SessionInfo[] = [];\n\n for (let idx = 0; idx < cpMeta.sessions.length; idx++) {\n const sess = cpMeta.sessions[idx];\n const transcriptPath = (sess.transcript ?? \"\").replace(/^\\//, \"\");\n const metaPath = sess.metadata ?? \"\";\n\n const smeta = this.fetchSessionMeta(metaPath);\n const createdAt = smeta.created_at ?? \"\";\n\n sessions.push({\n checkpointId: cpId,\n sessionIndex: String(idx),\n transcriptPath,\n createdAt,\n endedAt: createdAt, // will be filled from JSONL by conversation builder\n branch: smeta.branch ?? cpMeta.branch ?? \"\",\n agent: smeta.agent ?? \"\",\n turnCount: smeta.session_metrics?.turn_count ?? 0,\n filesTouched: smeta.files_touched ?? cpMeta.files_touched ?? [],\n sessionId: smeta.session_id ?? \"\",\n });\n }\n\n return sessions;\n }\n\n private getSessionsForCheckpoint(cpId: string): SessionInfo[] {\n const meta = this.fetchCheckpointMeta(cpId);\n if (!meta) return [];\n return this.buildSessionsForCheckpoint(cpId, meta);\n }\n\n // ─── Public resolvers ────────────────────────────────────────────────────────\n\n /**\n * All sessions recorded on a given branch, sorted by createdAt ascending.\n */\n async resolveByBranch(branchName: string): Promise<SessionInfo[]> {\n const cpIds = this.listAllCheckpointIds();\n const sessions: SessionInfo[] = [];\n\n for (const cpId of cpIds) {\n const meta = this.fetchCheckpointMeta(cpId);\n if (!meta) continue;\n if (meta.branch !== branchName) continue;\n sessions.push(...this.buildSessionsForCheckpoint(cpId, meta));\n }\n\n sessions.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n return sessions;\n }\n\n /**\n * Sessions linked to a specific commit via the Entire-Checkpoint git trailer.\n */\n async resolveByCommit(commitHash: string): Promise<SessionInfo[]> {\n const fullHash = this.git(\"rev-parse\", commitHash);\n if (!fullHash) return [];\n\n const cpId = this.git(\n \"log\",\n \"-1\",\n \"--format=%(trailers:key=Entire-Checkpoint,valueonly)\",\n fullHash\n );\n if (!cpId) return [];\n\n return this.getSessionsForCheckpoint(cpId.trim());\n }\n\n /**\n * All sessions from a merged PR (by number or GitHub URL).\n */\n async resolveByPr(prInput: string): Promise<SessionInfo[]> {\n let prNumber: string;\n\n if (/^\\d+$/.test(prInput)) {\n prNumber = prInput;\n } else {\n const m = /\\/pull\\/(\\d+)/.exec(prInput);\n if (!m) return [];\n prNumber = m[1];\n }\n\n const mergeOut = this.git(\n \"log\",\n \"--all\",\n \"--oneline\",\n \"--grep\",\n `Merge pull request #${prNumber}`\n );\n if (!mergeOut) return [];\n\n const mergeCommit = mergeOut.split(\"\\n\")[0].split(\" \")[0];\n\n const logOut = this.git(\n \"log\",\n \"--format=%H|%(trailers:key=Entire-Checkpoint,valueonly)\",\n `${mergeCommit}^2`,\n \"--not\",\n `${mergeCommit}^1`\n );\n if (!logOut) return [];\n\n const cpIds = CheckpointReader.parseCheckpointTrailers(logOut);\n const sessions: SessionInfo[] = [];\n\n for (const cpId of cpIds) {\n sessions.push(...this.getSessionsForCheckpoint(cpId));\n }\n\n sessions.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n return sessions;\n }\n\n /**\n * Sessions matching a specific checkpoint ID.\n */\n async resolveByCheckpoint(checkpointId: string): Promise<SessionInfo[]> {\n return this.getSessionsForCheckpoint(checkpointId);\n }\n\n /**\n * Find a session by its UUID.\n */\n async resolveBySessionId(sessionId: string): Promise<SessionInfo[]> {\n const cpIds = this.listAllCheckpointIds();\n\n for (const cpId of cpIds) {\n const sessions = this.getSessionsForCheckpoint(cpId);\n const match = sessions.find((s) => s.sessionId === sessionId);\n if (match) return [match];\n }\n\n return [];\n }\n\n /**\n * Latest N sessions across all checkpoints, sorted by createdAt descending.\n */\n async resolveLatest(count: number): Promise<SessionInfo[]> {\n const cpIds = this.listAllCheckpointIds();\n const all: SessionInfo[] = [];\n\n for (const cpId of cpIds) {\n all.push(...this.getSessionsForCheckpoint(cpId));\n }\n\n all.sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n return all.slice(0, count);\n }\n\n /**\n * Read the full JSONL transcript content from the entire branch.\n */\n getTranscript(transcriptPath: string): string {\n const normalized = transcriptPath.startsWith(\"/\")\n ? transcriptPath.slice(1)\n : transcriptPath;\n return this.git(\"show\", `${ENTIRE_BRANCH}:${normalized}`);\n }\n}\n"],"mappings":"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","names":[]}
|