@kenkaiiii/ggcoder 5.24.0 → 5.26.0

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.
Files changed (122) hide show
  1. package/dist/app-sidecar.js +330 -12
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +3 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config.d.ts +2 -0
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +3 -0
  9. package/dist/config.js.map +1 -1
  10. package/dist/config.test.js +12 -0
  11. package/dist/config.test.js.map +1 -1
  12. package/dist/core/agent-notifications.d.ts +62 -0
  13. package/dist/core/agent-notifications.d.ts.map +1 -0
  14. package/dist/core/agent-notifications.js +92 -0
  15. package/dist/core/agent-notifications.js.map +1 -0
  16. package/dist/core/agent-notifications.test.d.ts +2 -0
  17. package/dist/core/agent-notifications.test.d.ts.map +1 -0
  18. package/dist/core/agent-notifications.test.js +97 -0
  19. package/dist/core/agent-notifications.test.js.map +1 -0
  20. package/dist/core/agent-session-add-dir.test.js +16 -0
  21. package/dist/core/agent-session-add-dir.test.js.map +1 -1
  22. package/dist/core/agent-session-model-switch.test.d.ts +2 -0
  23. package/dist/core/agent-session-model-switch.test.d.ts.map +1 -0
  24. package/dist/core/agent-session-model-switch.test.js +161 -0
  25. package/dist/core/agent-session-model-switch.test.js.map +1 -0
  26. package/dist/core/agent-session-notifications.test.d.ts +2 -0
  27. package/dist/core/agent-session-notifications.test.d.ts.map +1 -0
  28. package/dist/core/agent-session-notifications.test.js +114 -0
  29. package/dist/core/agent-session-notifications.test.js.map +1 -0
  30. package/dist/core/agent-session.d.ts +76 -6
  31. package/dist/core/agent-session.d.ts.map +1 -1
  32. package/dist/core/agent-session.js +246 -25
  33. package/dist/core/agent-session.js.map +1 -1
  34. package/dist/core/event-bus.d.ts +6 -0
  35. package/dist/core/event-bus.d.ts.map +1 -1
  36. package/dist/core/event-bus.js +7 -0
  37. package/dist/core/event-bus.js.map +1 -1
  38. package/dist/core/local-endpoint-store.d.ts +50 -0
  39. package/dist/core/local-endpoint-store.d.ts.map +1 -0
  40. package/dist/core/local-endpoint-store.js +201 -0
  41. package/dist/core/local-endpoint-store.js.map +1 -0
  42. package/dist/core/local-endpoint-store.test.d.ts +2 -0
  43. package/dist/core/local-endpoint-store.test.d.ts.map +1 -0
  44. package/dist/core/local-endpoint-store.test.js +131 -0
  45. package/dist/core/local-endpoint-store.test.js.map +1 -0
  46. package/dist/core/memory/compaction-notes.d.ts +31 -0
  47. package/dist/core/memory/compaction-notes.d.ts.map +1 -0
  48. package/dist/core/memory/compaction-notes.js +162 -0
  49. package/dist/core/memory/compaction-notes.js.map +1 -0
  50. package/dist/core/memory/compaction-notes.test.d.ts +2 -0
  51. package/dist/core/memory/compaction-notes.test.d.ts.map +1 -0
  52. package/dist/core/memory/compaction-notes.test.js +110 -0
  53. package/dist/core/memory/compaction-notes.test.js.map +1 -0
  54. package/dist/core/memory/journal.d.ts +55 -0
  55. package/dist/core/memory/journal.d.ts.map +1 -0
  56. package/dist/core/memory/journal.js +212 -0
  57. package/dist/core/memory/journal.js.map +1 -0
  58. package/dist/core/memory/journal.test.d.ts +2 -0
  59. package/dist/core/memory/journal.test.d.ts.map +1 -0
  60. package/dist/core/memory/journal.test.js +184 -0
  61. package/dist/core/memory/journal.test.js.map +1 -0
  62. package/dist/core/process-manager-notifications.test.d.ts +2 -0
  63. package/dist/core/process-manager-notifications.test.d.ts.map +1 -0
  64. package/dist/core/process-manager-notifications.test.js +113 -0
  65. package/dist/core/process-manager-notifications.test.js.map +1 -0
  66. package/dist/core/process-manager.d.ts +29 -0
  67. package/dist/core/process-manager.d.ts.map +1 -1
  68. package/dist/core/process-manager.js +123 -0
  69. package/dist/core/process-manager.js.map +1 -1
  70. package/dist/core/session-manager.d.ts +3 -1
  71. package/dist/core/session-manager.d.ts.map +1 -1
  72. package/dist/core/session-manager.js +2 -1
  73. package/dist/core/session-manager.js.map +1 -1
  74. package/dist/core/settings-manager.d.ts +1 -0
  75. package/dist/core/settings-manager.d.ts.map +1 -1
  76. package/dist/core/settings-manager.js +7 -0
  77. package/dist/core/settings-manager.js.map +1 -1
  78. package/dist/core/slash-commands.d.ts +8 -0
  79. package/dist/core/slash-commands.d.ts.map +1 -1
  80. package/dist/core/slash-commands.js +17 -1
  81. package/dist/core/slash-commands.js.map +1 -1
  82. package/dist/core/slash-commands.test.js +11 -0
  83. package/dist/core/slash-commands.test.js.map +1 -1
  84. package/dist/core/steering.d.ts +12 -0
  85. package/dist/core/steering.d.ts.map +1 -1
  86. package/dist/core/steering.js +16 -0
  87. package/dist/core/steering.js.map +1 -1
  88. package/dist/core/subagent-manager.d.ts +13 -0
  89. package/dist/core/subagent-manager.d.ts.map +1 -1
  90. package/dist/core/subagent-manager.js +30 -0
  91. package/dist/core/subagent-manager.js.map +1 -1
  92. package/dist/core/subagent-manager.test.js +16 -0
  93. package/dist/core/subagent-manager.test.js.map +1 -1
  94. package/dist/modes/json-mode.d.ts.map +1 -1
  95. package/dist/modes/json-mode.js +5 -0
  96. package/dist/modes/json-mode.js.map +1 -1
  97. package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
  98. package/dist/modes/subagent-worker-mode.js +3 -1
  99. package/dist/modes/subagent-worker-mode.js.map +1 -1
  100. package/dist/tools/index.d.ts +8 -0
  101. package/dist/tools/index.d.ts.map +1 -1
  102. package/dist/tools/index.js +2 -1
  103. package/dist/tools/index.js.map +1 -1
  104. package/dist/tools/subagent-control.d.ts.map +1 -1
  105. package/dist/tools/subagent-control.js +6 -2
  106. package/dist/tools/subagent-control.js.map +1 -1
  107. package/dist/tools/subagent-shared.d.ts +6 -0
  108. package/dist/tools/subagent-shared.d.ts.map +1 -1
  109. package/dist/tools/subagent-shared.js +6 -0
  110. package/dist/tools/subagent-shared.js.map +1 -1
  111. package/dist/tools/task-output.d.ts.map +1 -1
  112. package/dist/tools/task-output.js +3 -1
  113. package/dist/tools/task-output.js.map +1 -1
  114. package/dist/ui/App.d.ts +2 -0
  115. package/dist/ui/App.d.ts.map +1 -1
  116. package/dist/ui/App.js +35 -1
  117. package/dist/ui/App.js.map +1 -1
  118. package/dist/ui/render.d.ts +2 -0
  119. package/dist/ui/render.d.ts.map +1 -1
  120. package/dist/ui/render.js +1 -0
  121. package/dist/ui/render.js.map +1 -1
  122. package/package.json +4 -4
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Persistence for user-added local model endpoints.
3
+ *
4
+ * The four well-known servers (Ollama, LM Studio, llama.cpp, vLLM) are probed
5
+ * without configuration; this store holds only the extra endpoints a user typed
6
+ * in — a moved port, a remote self-hosted box, an OpenAI-compatible gateway.
7
+ *
8
+ * Endpoints live in `~/.gg/gg-app.json` under `localEndpoints`; each one's key
9
+ * (and, for keyed servers, its token) lives in `~/.gg/auth.json` as a
10
+ * `local:<id>` credential, which is also what carries the baseUrl into the
11
+ * stream call. The two are kept in sync here so the UI never has to.
12
+ */
13
+ import fs from "node:fs/promises";
14
+ import os from "node:os";
15
+ import path from "node:path";
16
+ import { AuthStorage, DEFAULT_LOCAL_ENDPOINTS, clearLocalDiscoveryCache, } from "@kenkaiiii/gg-core";
17
+ export class LocalEndpointError extends Error {
18
+ }
19
+ const RESERVED_IDS = new Set(DEFAULT_LOCAL_ENDPOINTS.map((e) => e.id));
20
+ const MAX_CUSTOM_ENDPOINTS = 20;
21
+ function appSettingsFile(override) {
22
+ return override ?? path.join(os.homedir(), ".gg", "gg-app.json");
23
+ }
24
+ /**
25
+ * Normalize a user-typed URL into the OpenAI-compatible base we call.
26
+ * Accepts `host:port`, a bare root, or a full `/v1` URL, and tolerates a pasted
27
+ * `/v1/chat/completions` or `/v1/models` (people copy from docs).
28
+ */
29
+ export function normalizeLocalBaseUrl(input) {
30
+ const trimmed = input.trim();
31
+ if (!trimmed)
32
+ throw new LocalEndpointError("Endpoint URL is required.");
33
+ const scheme = /^([a-z][a-z0-9+.-]*):\/\//i.exec(trimmed)?.[1]?.toLowerCase();
34
+ if (scheme && scheme !== "http" && scheme !== "https") {
35
+ throw new LocalEndpointError("Endpoint URL must use http or https.");
36
+ }
37
+ // Bare `host:port` is the common case — assume plain http, like the servers do.
38
+ const withScheme = scheme ? trimmed : `http://${trimmed}`;
39
+ let url;
40
+ try {
41
+ url = new URL(withScheme);
42
+ }
43
+ catch {
44
+ throw new LocalEndpointError(`"${input}" is not a valid URL.`);
45
+ }
46
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
47
+ throw new LocalEndpointError("Endpoint URL must use http or https.");
48
+ }
49
+ if (!url.hostname)
50
+ throw new LocalEndpointError("Endpoint URL is missing a host.");
51
+ let pathname = url.pathname.replace(/\/+$/, "");
52
+ pathname = pathname.replace(/\/(?:chat\/completions|completions|models)$/, "");
53
+ if (!/\/v\d+$/.test(pathname))
54
+ pathname = `${pathname}/v1`;
55
+ return `${url.protocol}//${url.host}${pathname}`;
56
+ }
57
+ /** Slug derived from the URL, e.g. `custom-192-168-1-4-8000`. Stable per host:port. */
58
+ function endpointIdFor(baseUrl) {
59
+ const { host } = new URL(baseUrl);
60
+ const slug = host
61
+ .replace(/[^a-z0-9]+/gi, "-")
62
+ .replace(/^-|-$/g, "")
63
+ .toLowerCase();
64
+ return `custom-${slug || "endpoint"}`;
65
+ }
66
+ function labelFor(baseUrl, label) {
67
+ const trimmed = label?.trim();
68
+ if (trimmed)
69
+ return trimmed;
70
+ return new URL(baseUrl).host;
71
+ }
72
+ // ── settings file I/O ──────────────────────────────────────
73
+ /**
74
+ * Read/modify/write the whole settings object rather than a typed subset, so a
75
+ * key written by another part of the app (or a newer version) survives.
76
+ */
77
+ async function readSettings(file) {
78
+ try {
79
+ const raw = JSON.parse(await fs.readFile(appSettingsFile(file), "utf-8"));
80
+ return raw && typeof raw === "object" ? raw : {};
81
+ }
82
+ catch {
83
+ return {};
84
+ }
85
+ }
86
+ async function writeSettings(settings, file) {
87
+ const target = appSettingsFile(file);
88
+ await fs.mkdir(path.dirname(target), { recursive: true });
89
+ await fs.writeFile(target, JSON.stringify(settings, null, 2), "utf-8");
90
+ }
91
+ function parseStored(value) {
92
+ if (!Array.isArray(value))
93
+ return [];
94
+ const endpoints = [];
95
+ for (const entry of value) {
96
+ if (!entry || typeof entry !== "object")
97
+ continue;
98
+ const { id, label, baseUrl, apiKey } = entry;
99
+ if (typeof id !== "string" || typeof baseUrl !== "string")
100
+ continue;
101
+ endpoints.push({
102
+ id,
103
+ label: typeof label === "string" && label ? label : baseUrl,
104
+ baseUrl,
105
+ kind: "custom",
106
+ custom: true,
107
+ ...(typeof apiKey === "string" && apiKey ? { apiKey } : {}),
108
+ });
109
+ }
110
+ return endpoints;
111
+ }
112
+ /** User-added endpoints, in insertion order. Never throws on a corrupt file. */
113
+ export async function listCustomEndpoints(options = {}) {
114
+ return parseStored((await readSettings(options.settingsFile))["localEndpoints"]);
115
+ }
116
+ /** Well-known endpoints first, then the user's own — the probe/scan order. */
117
+ export async function listAllEndpoints(options = {}) {
118
+ return [...DEFAULT_LOCAL_ENDPOINTS, ...(await listCustomEndpoints(options))];
119
+ }
120
+ /**
121
+ * Add a custom endpoint and write its `local:<id>` credential. Re-adding the
122
+ * same host updates it (that's how a user fixes a mistyped key) instead of
123
+ * creating a second row for the same server.
124
+ */
125
+ export async function addCustomEndpoint(input, options = {}) {
126
+ const auth = options.auth ?? new AuthStorage();
127
+ const baseUrl = normalizeLocalBaseUrl(input.baseUrl);
128
+ const id = endpointIdFor(baseUrl);
129
+ if (RESERVED_IDS.has(id)) {
130
+ throw new LocalEndpointError(`"${id}" is a built-in endpoint id.`);
131
+ }
132
+ const existing = await listCustomEndpoints(options);
133
+ const builtIn = DEFAULT_LOCAL_ENDPOINTS.find((e) => e.baseUrl === baseUrl);
134
+ if (builtIn) {
135
+ throw new LocalEndpointError(`${baseUrl} is already probed automatically as ${builtIn.label}.`);
136
+ }
137
+ if (!existing.some((e) => e.id === id) && existing.length >= MAX_CUSTOM_ENDPOINTS) {
138
+ throw new LocalEndpointError(`At most ${MAX_CUSTOM_ENDPOINTS} custom endpoints.`);
139
+ }
140
+ const endpoint = {
141
+ id,
142
+ label: labelFor(baseUrl, input.label),
143
+ baseUrl,
144
+ kind: "custom",
145
+ custom: true,
146
+ ...(input.apiKey?.trim() ? { apiKey: input.apiKey.trim() } : {}),
147
+ };
148
+ const next = existing.some((e) => e.id === id)
149
+ ? existing.map((e) => (e.id === id ? endpoint : e))
150
+ : [...existing, endpoint];
151
+ const settings = await readSettings(options.settingsFile);
152
+ settings["localEndpoints"] = next.map(({ id: eid, label, baseUrl: url, apiKey }) => ({
153
+ id: eid,
154
+ label,
155
+ baseUrl: url,
156
+ ...(apiKey ? { apiKey } : {}),
157
+ }));
158
+ await writeSettings(settings, options.settingsFile);
159
+ await auth.setLocalEndpoint(id, baseUrl, endpoint.apiKey);
160
+ clearLocalDiscoveryCache();
161
+ return endpoint;
162
+ }
163
+ /**
164
+ * Remove a custom endpoint and its credential. Built-in endpoints can't be
165
+ * removed (they're discovered, not configured) — that's an error, not a no-op,
166
+ * so a UI bug doesn't silently do nothing.
167
+ */
168
+ export async function removeCustomEndpoint(id, options = {}) {
169
+ const auth = options.auth ?? new AuthStorage();
170
+ if (RESERVED_IDS.has(id)) {
171
+ throw new LocalEndpointError(`${id} is a built-in endpoint and can't be removed.`);
172
+ }
173
+ const existing = await listCustomEndpoints(options);
174
+ if (!existing.some((e) => e.id === id)) {
175
+ throw new LocalEndpointError(`Unknown local endpoint "${id}".`);
176
+ }
177
+ const settings = await readSettings(options.settingsFile);
178
+ settings["localEndpoints"] = existing
179
+ .filter((e) => e.id !== id)
180
+ .map(({ id: eid, label, baseUrl, apiKey }) => ({
181
+ id: eid,
182
+ label,
183
+ baseUrl,
184
+ ...(apiKey ? { apiKey } : {}),
185
+ }));
186
+ await writeSettings(settings, options.settingsFile);
187
+ await auth.removeLocalEndpoint(id);
188
+ clearLocalDiscoveryCache();
189
+ }
190
+ /**
191
+ * Make sure every endpoint we're about to serve models from has a credential
192
+ * carrying its baseUrl — otherwise `stream()` has no endpoint to talk to.
193
+ * Called after each scan, so a fresh install works with zero setup.
194
+ */
195
+ export async function syncEndpointCredentials(endpoints, options = {}) {
196
+ const auth = options.auth ?? new AuthStorage();
197
+ for (const endpoint of endpoints) {
198
+ await auth.setLocalEndpoint(endpoint.id, endpoint.baseUrl, endpoint.apiKey);
199
+ }
200
+ }
201
+ //# sourceMappingURL=local-endpoint-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-endpoint-store.js","sourceRoot":"","sources":["../../src/core/local-endpoint-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=local-endpoint-store.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-endpoint-store.test.d.ts","sourceRoot":"","sources":["../../src/core/local-endpoint-store.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,131 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { AuthStorage } from "@kenkaiiii/gg-core";
6
+ import { LocalEndpointError, addCustomEndpoint, listAllEndpoints, listCustomEndpoints, normalizeLocalBaseUrl, removeCustomEndpoint, syncEndpointCredentials, } from "./local-endpoint-store.js";
7
+ let dir;
8
+ let opts;
9
+ let auth;
10
+ // Both file paths are injected rather than redirected via $HOME: os.homedir()
11
+ // reads USERPROFILE on Windows, so a HOME override silently writes to the real
12
+ // ~/.gg there — which leaks state between tests and pollutes the user's files.
13
+ beforeEach(async () => {
14
+ dir = await fs.mkdtemp(path.join(os.tmpdir(), "gg-local-endpoints-"));
15
+ auth = new AuthStorage(path.join(dir, "auth.json"));
16
+ opts = { settingsFile: path.join(dir, "gg-app.json"), auth };
17
+ });
18
+ afterEach(async () => {
19
+ await fs.rm(dir, { recursive: true, force: true });
20
+ });
21
+ async function settings() {
22
+ return JSON.parse(await fs.readFile(opts.settingsFile, "utf-8"));
23
+ }
24
+ describe("normalizeLocalBaseUrl", () => {
25
+ it("accepts the shapes users actually paste", () => {
26
+ expect(normalizeLocalBaseUrl("127.0.0.1:1234")).toBe("http://127.0.0.1:1234/v1");
27
+ expect(normalizeLocalBaseUrl("http://localhost:8000")).toBe("http://localhost:8000/v1");
28
+ expect(normalizeLocalBaseUrl("http://localhost:8000/v1")).toBe("http://localhost:8000/v1");
29
+ expect(normalizeLocalBaseUrl(" http://localhost:8000/v1/ ")).toBe("http://localhost:8000/v1");
30
+ expect(normalizeLocalBaseUrl("http://box.lan:8080/v1/chat/completions")).toBe("http://box.lan:8080/v1");
31
+ expect(normalizeLocalBaseUrl("http://box.lan:8080/v1/models")).toBe("http://box.lan:8080/v1");
32
+ // A gateway on a sub-path keeps the path.
33
+ expect(normalizeLocalBaseUrl("https://gw.example.com/openai")).toBe("https://gw.example.com/openai/v1");
34
+ });
35
+ it("rejects empty, malformed, and non-http URLs", () => {
36
+ expect(() => normalizeLocalBaseUrl(" ")).toThrow(LocalEndpointError);
37
+ expect(() => normalizeLocalBaseUrl("http://")).toThrow(LocalEndpointError);
38
+ expect(() => normalizeLocalBaseUrl("ftp://host/v1")).toThrow(LocalEndpointError);
39
+ });
40
+ });
41
+ describe("custom endpoints", () => {
42
+ it("adds an endpoint, persists it, and writes its auth credential", async () => {
43
+ const endpoint = await addCustomEndpoint({ label: "Workstation", baseUrl: "192.168.1.4:8000", apiKey: "secret" }, opts);
44
+ expect(endpoint).toMatchObject({
45
+ id: "custom-192-168-1-4-8000",
46
+ label: "Workstation",
47
+ baseUrl: "http://192.168.1.4:8000/v1",
48
+ kind: "custom",
49
+ custom: true,
50
+ apiKey: "secret",
51
+ });
52
+ expect(await listCustomEndpoints(opts)).toEqual([endpoint]);
53
+ const creds = await auth.getCredentials("local:custom-192-168-1-4-8000");
54
+ expect(creds).toMatchObject({ accessToken: "secret", baseUrl: "http://192.168.1.4:8000/v1" });
55
+ expect(creds.expiresAt).toBeGreaterThan(Date.now());
56
+ expect(await auth.hasProviderAuth("local")).toBe(true);
57
+ });
58
+ it("defaults the label to the host and the key to a placeholder", async () => {
59
+ await addCustomEndpoint({ baseUrl: "http://localhost:9999" }, opts);
60
+ const stored = (await listCustomEndpoints(opts))[0];
61
+ expect(stored.label).toBe("localhost:9999");
62
+ expect(stored.apiKey).toBeUndefined();
63
+ expect(await auth.getCredentials("local:custom-localhost-9999")).toMatchObject({
64
+ accessToken: "local",
65
+ });
66
+ });
67
+ it("updates in place when the same host is re-added", async () => {
68
+ await addCustomEndpoint({ baseUrl: "http://localhost:9999", apiKey: "wrong" }, opts);
69
+ await addCustomEndpoint({ label: "Fixed", baseUrl: "http://localhost:9999/v1", apiKey: "right" }, opts);
70
+ const stored = await listCustomEndpoints(opts);
71
+ expect(stored).toHaveLength(1);
72
+ expect(stored[0]).toMatchObject({ label: "Fixed", apiKey: "right" });
73
+ expect(await auth.getCredentials("local:custom-localhost-9999")).toMatchObject({
74
+ accessToken: "right",
75
+ });
76
+ });
77
+ it("refuses a URL already covered by a built-in endpoint", async () => {
78
+ await expect(addCustomEndpoint({ baseUrl: "http://127.0.0.1:11434/v1" }, opts)).rejects.toThrow(/already probed automatically as Ollama/);
79
+ });
80
+ it("removes an endpoint and its credential", async () => {
81
+ await addCustomEndpoint({ baseUrl: "http://localhost:9999" }, opts);
82
+ await removeCustomEndpoint("custom-localhost-9999", opts);
83
+ expect(await listCustomEndpoints(opts)).toEqual([]);
84
+ expect(await auth.getCredentials("local:custom-localhost-9999")).toBeUndefined();
85
+ expect(await auth.hasProviderAuth("local")).toBe(false);
86
+ });
87
+ it("refuses to remove a built-in or unknown endpoint", async () => {
88
+ await expect(removeCustomEndpoint("ollama", opts)).rejects.toThrow(/built-in/);
89
+ await expect(removeCustomEndpoint("custom-nope", opts)).rejects.toThrow(/Unknown local/);
90
+ });
91
+ it("preserves unrelated gg-app.json keys", async () => {
92
+ await fs.writeFile(opts.settingsFile, JSON.stringify({ projectsRoot: "/tmp/projects", autopilot: { "/a": true } }), "utf-8");
93
+ await addCustomEndpoint({ baseUrl: "http://localhost:9999" }, opts);
94
+ expect(await settings()).toMatchObject({
95
+ projectsRoot: "/tmp/projects",
96
+ autopilot: { "/a": true },
97
+ });
98
+ await removeCustomEndpoint("custom-localhost-9999", opts);
99
+ expect(await settings()).toMatchObject({ projectsRoot: "/tmp/projects" });
100
+ });
101
+ it("ignores a corrupt settings file instead of throwing", async () => {
102
+ await fs.writeFile(opts.settingsFile, "{not json", "utf-8");
103
+ expect(await listCustomEndpoints(opts)).toEqual([]);
104
+ });
105
+ it("lists built-in endpoints before custom ones", async () => {
106
+ await addCustomEndpoint({ baseUrl: "http://localhost:9999" }, opts);
107
+ expect((await listAllEndpoints(opts)).map((e) => e.id)).toEqual([
108
+ "ollama",
109
+ "lmstudio",
110
+ "llamacpp",
111
+ "vllm",
112
+ "custom-localhost-9999",
113
+ ]);
114
+ });
115
+ });
116
+ describe("syncEndpointCredentials", () => {
117
+ it("writes a baseUrl-carrying credential for every endpoint", async () => {
118
+ await syncEndpointCredentials(await listAllEndpoints(opts), opts);
119
+ expect((await auth.listLocalEndpointIds()).sort()).toEqual([
120
+ "llamacpp",
121
+ "lmstudio",
122
+ "ollama",
123
+ "vllm",
124
+ ]);
125
+ expect(await auth.getCredentials("local:ollama")).toMatchObject({
126
+ baseUrl: "http://127.0.0.1:11434/v1",
127
+ accessToken: "local",
128
+ });
129
+ });
130
+ });
131
+ //# sourceMappingURL=local-endpoint-store.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-endpoint-store.test.js","sourceRoot":"","sources":["../../src/core/local-endpoint-store.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Turn the detail compaction is about to throw away into durable journal
3
+ * entries.
4
+ *
5
+ * Compaction is one-way: the summary replaces the messages and the specifics
6
+ * are gone for good. That is the actual hole the journal exists to fill — an
7
+ * entry written here survives the summary, the session and the next restart.
8
+ *
9
+ * **Every entry must be a past-tense record of something that already
10
+ * happened.** Bench G showed that an injected note suppresses verification
11
+ * entirely (5/5 checks → 0/5), so an entry that can later become false will be
12
+ * asserted with full confidence and never re-checked. History cannot become
13
+ * false, which is what makes this writer safe while a free-form "save a fact"
14
+ * tool was not. Do not add a producer here that records current state.
15
+ *
16
+ * Deliberately conservative: at most a handful of bounded entries per
17
+ * compaction. A journal that floods itself is one nobody can afford to read.
18
+ */
19
+ import type { Message } from "@kenkaiiii/gg-ai";
20
+ /** Max notes written per compaction. A flooded log is an unreadable log. */
21
+ export declare const MAX_NOTES_PER_COMPACTION = 3;
22
+ export interface CompactionNote {
23
+ text: string;
24
+ tag: string;
25
+ }
26
+ /**
27
+ * Build the notes to persist for one compaction. `dropped` are the messages
28
+ * being replaced; `summary` is the text replacing them.
29
+ */
30
+ export declare function buildCompactionNotes(dropped: readonly Message[], summary: string): CompactionNote[];
31
+ //# sourceMappingURL=compaction-notes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compaction-notes.d.ts","sourceRoot":"","sources":["../../../src/core/memory/compaction-notes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,kBAAkB,CAAC;AAK7D,4EAA4E;AAC5E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAM1C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAoID;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,OAAO,EAAE,MAAM,GACd,cAAc,EAAE,CA0BlB"}
@@ -0,0 +1,162 @@
1
+ // Single source of truth for entry truncation — both writers must cut at the
2
+ // same boundaries, or an entry's rendering would depend on which path made it.
3
+ import { clampEntryText } from "./journal.js";
4
+ /** Max notes written per compaction. A flooded log is an unreadable log. */
5
+ export const MAX_NOTES_PER_COMPACTION = 3;
6
+ /** Max file paths named in the files note. */
7
+ const MAX_FILES_LISTED = 8;
8
+ /** Max chars of the summary carried into a note. */
9
+ const SUMMARY_NOTE_CHARS = 360;
10
+ /**
11
+ * Sections of the compactor's summary worth keeping in a durable journal.
12
+ *
13
+ * The compactor emits seven labelled sections. Most must NOT be journalled:
14
+ *
15
+ * - `Primary Request and Intent` / `User Messages` — already captured verbatim,
16
+ * and far more cheaply, by the `request` entry. Live measurement (bench H)
17
+ * showed 64% of the request entry's words repeated inside the summary.
18
+ * - `Files Touched` — already captured exactly by the `files` entry.
19
+ * - `Current Work` / `Next Step` — in-flight state. True at the moment of
20
+ * compaction, false minutes later, and bench G proved a stale entry is
21
+ * asserted with full confidence and never re-checked. Journalling these
22
+ * would reintroduce exactly the failure this design exists to avoid.
23
+ *
24
+ * That leaves the two sections that are pure, permanent history — what was
25
+ * actually done, and what went wrong and how it was fixed. Those are also the
26
+ * only parts a future session cannot cheaply re-derive by reading the code.
27
+ */
28
+ const DURABLE_SUMMARY_SECTIONS = ["What Was Done", "Errors and Fixes"];
29
+ const SECTION_HEADING = /^#{1,6}\s*(.+?)\s*$/;
30
+ /** Split a compactor summary into `heading -> body` pairs. */
31
+ function splitSections(summary) {
32
+ const sections = new Map();
33
+ let heading = null;
34
+ let body = [];
35
+ const flush = () => {
36
+ if (heading)
37
+ sections.set(heading.toLowerCase(), body.join(" ").trim());
38
+ };
39
+ for (const line of summary.split("\n")) {
40
+ const match = SECTION_HEADING.exec(line);
41
+ if (match && line.trimStart().startsWith("#")) {
42
+ flush();
43
+ heading = match[1];
44
+ body = [];
45
+ continue;
46
+ }
47
+ body.push(line);
48
+ }
49
+ flush();
50
+ return sections;
51
+ }
52
+ /** Strip markdown so an entry stays one clean, diffable line. */
53
+ function toProse(text) {
54
+ return text
55
+ .replace(/<(read|modified)-files>[\s\S]*?<\/\1-files>/g, " ")
56
+ .replace(/^\s*[-*]\s+/gm, " ")
57
+ .replace(/^\s*\d+\.\s+/gm, " ")
58
+ .replace(/[`*_>#]/g, "")
59
+ .replace(/\s+/g, " ")
60
+ .trim();
61
+ }
62
+ /**
63
+ * The durable, non-duplicated part of a compaction summary. Falls back to the
64
+ * whole summary when the expected headings are absent (the compactor's
65
+ * extractive fallback path emits unstructured prose).
66
+ */
67
+ function summaryToProse(summary) {
68
+ const stripped = summary.replace(/^\[Previous conversation summary\]/, "");
69
+ const sections = splitSections(stripped);
70
+ if (sections.size > 0) {
71
+ const kept = DURABLE_SUMMARY_SECTIONS.map((name) => sections.get(name.toLowerCase()))
72
+ .filter((body) => Boolean(body && body.trim()))
73
+ .map(toProse)
74
+ .filter(Boolean);
75
+ if (kept.length > 0)
76
+ return kept.join(" ");
77
+ }
78
+ return toProse(stripped);
79
+ }
80
+ const MUTATING_TOOLS = new Set(["write", "edit"]);
81
+ /**
82
+ * Safety net for the structural de-duplication above: drop any entry whose text
83
+ * already appears verbatim inside another entry. Every journal entry is paid
84
+ * for on every subsequent turn, so a duplicate is not a cosmetic problem.
85
+ */
86
+ function dropContainedNotes(notes) {
87
+ return notes.filter((note, index) => notes.every((other, otherIndex) => otherIndex === index ||
88
+ !other.text.includes(note.text) ||
89
+ // Identical texts: keep the first occurrence only.
90
+ (other.text === note.text && otherIndex > index)));
91
+ }
92
+ function textOf(content) {
93
+ if (typeof content === "string")
94
+ return content;
95
+ if (!Array.isArray(content))
96
+ return "";
97
+ return content
98
+ .filter((part) => part.type === "text")
99
+ .map((part) => part.text)
100
+ .join(" ");
101
+ }
102
+ /** Files the discarded span actually changed, in first-touch order. */
103
+ function changedFiles(dropped) {
104
+ const files = [];
105
+ for (const message of dropped) {
106
+ if (message.role !== "assistant" || !Array.isArray(message.content))
107
+ continue;
108
+ for (const part of message.content) {
109
+ if (part.type !== "tool_call" || !MUTATING_TOOLS.has(part.name))
110
+ continue;
111
+ const target = part.args?.file_path;
112
+ if (typeof target !== "string" || files.includes(target))
113
+ continue;
114
+ files.push(target);
115
+ if (files.length >= MAX_FILES_LISTED)
116
+ return files;
117
+ }
118
+ }
119
+ return files;
120
+ }
121
+ /** The first real user request in the discarded span, if there was one. */
122
+ function firstUserRequest(dropped) {
123
+ for (const message of dropped) {
124
+ if (message.role !== "user")
125
+ continue;
126
+ const text = textOf(message.content).trim();
127
+ // Harness-injected framing (steering, loop-break, compaction summary) is
128
+ // not something worth remembering across sessions.
129
+ if (!text || text.startsWith("["))
130
+ continue;
131
+ return text;
132
+ }
133
+ return undefined;
134
+ }
135
+ /**
136
+ * Build the notes to persist for one compaction. `dropped` are the messages
137
+ * being replaced; `summary` is the text replacing them.
138
+ */
139
+ export function buildCompactionNotes(dropped, summary) {
140
+ const notes = [];
141
+ // Past tense throughout: these describe a session that is already over.
142
+ const request = firstUserRequest(dropped);
143
+ if (request) {
144
+ notes.push({
145
+ tag: "request",
146
+ text: clampEntryText(`Was asked to: ${request}`, SUMMARY_NOTE_CHARS),
147
+ });
148
+ }
149
+ const files = changedFiles(dropped);
150
+ if (files.length > 0) {
151
+ notes.push({
152
+ tag: "files",
153
+ text: clampEntryText(`Edited: ${files.join(", ")}`, SUMMARY_NOTE_CHARS),
154
+ });
155
+ }
156
+ const summaryText = clampEntryText(summaryToProse(summary), SUMMARY_NOTE_CHARS);
157
+ if (summaryText) {
158
+ notes.push({ tag: "summary", text: summaryText });
159
+ }
160
+ return dropContainedNotes(notes).slice(0, MAX_NOTES_PER_COMPACTION);
161
+ }
162
+ //# sourceMappingURL=compaction-notes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compaction-notes.js","sourceRoot":"","sources":["../../../src/core/memory/compaction-notes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compaction-notes.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compaction-notes.test.d.ts","sourceRoot":"","sources":["../../../src/core/memory/compaction-notes.test.ts"],"names":[],"mappings":""}