@kenkaiiii/ggcoder 5.74.3 → 5.75.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/README.md +1 -1
  2. package/assets/skills/bulletproof/SKILL.md +1 -1
  3. package/assets/skills/clarify/SKILL.md +1 -1
  4. package/assets/skills/code-review/SKILL.md +1 -1
  5. package/assets/skills/compliance-guard/SKILL.md +1 -1
  6. package/assets/skills/durable/SKILL.md +1 -1
  7. package/assets/skills/evidence-led-ui/SKILL.md +1 -1
  8. package/assets/skills/lean/SKILL.md +1 -1
  9. package/assets/skills/refactoring/SKILL.md +1 -1
  10. package/assets/skills/root-cause/SKILL.md +1 -1
  11. package/assets/skills/shared-language/SKILL.md +1 -1
  12. package/assets/skills/tdd/SKILL.md +1 -1
  13. package/dist/app-sidecar/app-settings.d.ts +65 -0
  14. package/dist/app-sidecar/app-settings.js +147 -0
  15. package/dist/app-sidecar/app-settings.js.map +1 -0
  16. package/dist/app-sidecar/attachments.d.ts +11 -0
  17. package/dist/app-sidecar/attachments.js +47 -0
  18. package/dist/app-sidecar/attachments.js.map +1 -0
  19. package/dist/app-sidecar/auth-routes.d.ts +3 -0
  20. package/dist/app-sidecar/auth-routes.js +290 -0
  21. package/dist/app-sidecar/auth-routes.js.map +1 -0
  22. package/dist/app-sidecar/autopilot-runner.d.ts +61 -0
  23. package/dist/app-sidecar/autopilot-runner.js +367 -0
  24. package/dist/app-sidecar/autopilot-runner.js.map +1 -0
  25. package/dist/app-sidecar/file-search.d.ts +15 -0
  26. package/dist/app-sidecar/file-search.js +103 -0
  27. package/dist/app-sidecar/file-search.js.map +1 -0
  28. package/dist/app-sidecar/hf-pull-manager.d.ts +20 -0
  29. package/dist/app-sidecar/hf-pull-manager.js +224 -0
  30. package/dist/app-sidecar/hf-pull-manager.js.map +1 -0
  31. package/dist/app-sidecar/history-routes.d.ts +3 -0
  32. package/dist/app-sidecar/history-routes.js +375 -0
  33. package/dist/app-sidecar/history-routes.js.map +1 -0
  34. package/dist/app-sidecar/history.d.ts +67 -0
  35. package/dist/app-sidecar/history.js +23 -0
  36. package/dist/app-sidecar/history.js.map +1 -0
  37. package/dist/app-sidecar/http.d.ts +5 -0
  38. package/dist/app-sidecar/http.js +27 -0
  39. package/dist/app-sidecar/http.js.map +1 -0
  40. package/dist/app-sidecar/integration-routes.d.ts +3 -0
  41. package/dist/app-sidecar/integration-routes.js +286 -0
  42. package/dist/app-sidecar/integration-routes.js.map +1 -0
  43. package/dist/app-sidecar/json-mode.d.ts +10 -0
  44. package/dist/app-sidecar/json-mode.js +73 -0
  45. package/dist/app-sidecar/json-mode.js.map +1 -0
  46. package/dist/app-sidecar/keep-awake.d.ts +4 -0
  47. package/dist/app-sidecar/keep-awake.js +5 -0
  48. package/dist/app-sidecar/keep-awake.js.map +1 -0
  49. package/dist/app-sidecar/ken-context.d.ts +20 -0
  50. package/dist/app-sidecar/ken-context.js +55 -0
  51. package/dist/app-sidecar/ken-context.js.map +1 -0
  52. package/dist/app-sidecar/mcp-routes.d.ts +3 -0
  53. package/dist/app-sidecar/mcp-routes.js +185 -0
  54. package/dist/app-sidecar/mcp-routes.js.map +1 -0
  55. package/dist/app-sidecar/mcp-rows.d.ts +31 -0
  56. package/dist/app-sidecar/mcp-rows.js +77 -0
  57. package/dist/app-sidecar/mcp-rows.js.map +1 -0
  58. package/dist/app-sidecar/progress-manager.d.ts +10 -0
  59. package/dist/app-sidecar/progress-manager.js +116 -0
  60. package/dist/app-sidecar/progress-manager.js.map +1 -0
  61. package/dist/app-sidecar/prompt-routes.d.ts +3 -0
  62. package/dist/app-sidecar/prompt-routes.js +354 -0
  63. package/dist/app-sidecar/prompt-routes.js.map +1 -0
  64. package/dist/app-sidecar/repo-polls.d.ts +15 -0
  65. package/dist/app-sidecar/repo-polls.js +25 -0
  66. package/dist/app-sidecar/repo-polls.js.map +1 -0
  67. package/dist/app-sidecar/route-context.d.ts +145 -0
  68. package/dist/app-sidecar/route-context.js +2 -0
  69. package/dist/app-sidecar/route-context.js.map +1 -0
  70. package/dist/app-sidecar/run-control-routes.d.ts +3 -0
  71. package/dist/app-sidecar/run-control-routes.js +430 -0
  72. package/dist/app-sidecar/run-control-routes.js.map +1 -0
  73. package/dist/app-sidecar/session-routes.d.ts +3 -0
  74. package/dist/app-sidecar/session-routes.js +115 -0
  75. package/dist/app-sidecar/session-routes.js.map +1 -0
  76. package/dist/app-sidecar/session-types.d.ts +39 -0
  77. package/dist/app-sidecar/session-types.js +5 -0
  78. package/dist/app-sidecar/session-types.js.map +1 -0
  79. package/dist/app-sidecar/task-routes.d.ts +3 -0
  80. package/dist/app-sidecar/task-routes.js +149 -0
  81. package/dist/app-sidecar/task-routes.js.map +1 -0
  82. package/dist/app-sidecar/usage.d.ts +19 -0
  83. package/dist/app-sidecar/usage.js +153 -0
  84. package/dist/app-sidecar/usage.js.map +1 -0
  85. package/dist/app-sidecar/workspace-routes.d.ts +3 -0
  86. package/dist/app-sidecar/workspace-routes.js +244 -0
  87. package/dist/app-sidecar/workspace-routes.js.map +1 -0
  88. package/dist/app-sidecar.js +467 -3775
  89. package/dist/app-sidecar.js.map +1 -1
  90. package/dist/cli.js +2 -2
  91. package/dist/cli.js.map +1 -1
  92. package/dist/config.js +1 -1
  93. package/dist/core/acceptance-checks.js +3 -9
  94. package/dist/core/acceptance-checks.js.map +1 -1
  95. package/dist/core/agent-session/helpers.d.ts +26 -0
  96. package/dist/core/agent-session/helpers.js +47 -0
  97. package/dist/core/agent-session/helpers.js.map +1 -0
  98. package/dist/core/agent-session/mcp-tools.d.ts +68 -0
  99. package/dist/core/agent-session/mcp-tools.js +195 -0
  100. package/dist/core/agent-session/mcp-tools.js.map +1 -0
  101. package/dist/core/agent-session/run-loop-monitor.d.ts +63 -0
  102. package/dist/core/agent-session/run-loop-monitor.js +164 -0
  103. package/dist/core/agent-session/run-loop-monitor.js.map +1 -0
  104. package/dist/core/agent-session/transcript-markers.d.ts +57 -0
  105. package/dist/core/agent-session/transcript-markers.js +166 -0
  106. package/dist/core/agent-session/transcript-markers.js.map +1 -0
  107. package/dist/core/agent-session/verification-tracker.d.ts +46 -0
  108. package/dist/core/agent-session/verification-tracker.js +246 -0
  109. package/dist/core/agent-session/verification-tracker.js.map +1 -0
  110. package/dist/core/agent-session.d.ts +21 -87
  111. package/dist/core/agent-session.js +141 -712
  112. package/dist/core/agent-session.js.map +1 -1
  113. package/dist/core/auth-providers.js +3 -3
  114. package/dist/core/auth-providers.js.map +1 -1
  115. package/dist/core/bundled-agents.js +6 -6
  116. package/dist/core/bundled-agents.js.map +1 -1
  117. package/dist/core/checklist-git.d.ts +19 -0
  118. package/dist/core/checklist-git.js +54 -0
  119. package/dist/core/checklist-git.js.map +1 -0
  120. package/dist/core/checklist-items.d.ts +10 -1
  121. package/dist/core/checklist-items.js +22 -0
  122. package/dist/core/checklist-items.js.map +1 -1
  123. package/dist/core/checklist-prompt.d.ts +5 -1
  124. package/dist/core/checklist-prompt.js +16 -5
  125. package/dist/core/checklist-prompt.js.map +1 -1
  126. package/dist/core/checklist-snapshot.d.ts +5 -1
  127. package/dist/core/checklist-snapshot.js +19 -2
  128. package/dist/core/checklist-snapshot.js.map +1 -1
  129. package/dist/core/context-limits.js +1 -1
  130. package/dist/core/context-limits.js.map +1 -1
  131. package/dist/core/skills.js +6 -9
  132. package/dist/core/skills.js.map +1 -1
  133. package/dist/core/style-packs/index.js +2 -11
  134. package/dist/core/style-packs/index.js.map +1 -1
  135. package/dist/core/style-packs/packs.d.ts +3 -12
  136. package/dist/core/style-packs/packs.js +132 -173
  137. package/dist/core/style-packs/packs.js.map +1 -1
  138. package/dist/system-prompt.js +55 -78
  139. package/dist/system-prompt.js.map +1 -1
  140. package/dist/tools/ask-user.js +13 -74
  141. package/dist/tools/ask-user.js.map +1 -1
  142. package/dist/tools/bash.js +13 -78
  143. package/dist/tools/bash.js.map +1 -1
  144. package/dist/tools/checklist.d.ts +2 -10
  145. package/dist/tools/checklist.js +7 -39
  146. package/dist/tools/checklist.js.map +1 -1
  147. package/dist/tools/code-nav.js +7 -29
  148. package/dist/tools/code-nav.js.map +1 -1
  149. package/dist/tools/edit.d.ts +3 -9
  150. package/dist/tools/edit.js +92 -65
  151. package/dist/tools/edit.js.map +1 -1
  152. package/dist/tools/enter-plan.js +2 -7
  153. package/dist/tools/enter-plan.js.map +1 -1
  154. package/dist/tools/exit-plan.js +2 -3
  155. package/dist/tools/exit-plan.js.map +1 -1
  156. package/dist/tools/find.js +3 -4
  157. package/dist/tools/find.js.map +1 -1
  158. package/dist/tools/grep.js +6 -18
  159. package/dist/tools/grep.js.map +1 -1
  160. package/dist/tools/ls.js +3 -3
  161. package/dist/tools/ls.js.map +1 -1
  162. package/dist/tools/prompt-hints.js +34 -47
  163. package/dist/tools/prompt-hints.js.map +1 -1
  164. package/dist/tools/read.js +8 -20
  165. package/dist/tools/read.js.map +1 -1
  166. package/dist/tools/search-code.js +4 -12
  167. package/dist/tools/search-code.js.map +1 -1
  168. package/dist/tools/skill.js +13 -7
  169. package/dist/tools/skill.js.map +1 -1
  170. package/dist/tools/subagent-control.js +7 -22
  171. package/dist/tools/subagent-control.js.map +1 -1
  172. package/dist/tools/subagent.js +4 -7
  173. package/dist/tools/subagent.js.map +1 -1
  174. package/dist/tools/task-output.js +4 -15
  175. package/dist/tools/task-output.js.map +1 -1
  176. package/dist/tools/task-send.js +5 -17
  177. package/dist/tools/task-send.js.map +1 -1
  178. package/dist/tools/task-stop.js +2 -2
  179. package/dist/tools/task-stop.js.map +1 -1
  180. package/dist/tools/tool-search.js +2 -7
  181. package/dist/tools/tool-search.js.map +1 -1
  182. package/dist/tools/tool-tiers.d.ts +17 -4
  183. package/dist/tools/tool-tiers.js +38 -15
  184. package/dist/tools/tool-tiers.js.map +1 -1
  185. package/dist/tools/web-fetch.js +7 -33
  186. package/dist/tools/web-fetch.js.map +1 -1
  187. package/dist/tools/write.js +3 -4
  188. package/dist/tools/write.js.map +1 -1
  189. package/dist/ui/components/Footer.js +1 -2
  190. package/dist/ui/components/Footer.js.map +1 -1
  191. package/dist/utils/shared-poll.d.ts +37 -0
  192. package/dist/utils/shared-poll.js +104 -0
  193. package/dist/utils/shared-poll.js.map +1 -0
  194. package/package.json +7 -4
  195. package/dist/core/api-benchmark.d.ts +0 -63
  196. package/dist/core/api-benchmark.js +0 -381
  197. package/dist/core/api-benchmark.js.map +0 -1
  198. package/dist/core/bash-spawn-benchmark.d.ts +0 -1
  199. package/dist/core/bash-spawn-benchmark.js +0 -139
  200. package/dist/core/bash-spawn-benchmark.js.map +0 -1
  201. package/dist/core/cache-warm-benchmark.d.ts +0 -21
  202. package/dist/core/cache-warm-benchmark.js +0 -170
  203. package/dist/core/cache-warm-benchmark.js.map +0 -1
  204. package/dist/core/fast-apply-benchmark.d.ts +0 -25
  205. package/dist/core/fast-apply-benchmark.js +0 -284
  206. package/dist/core/fast-apply-benchmark.js.map +0 -1
  207. package/dist/core/hashline-edit-benchmark.d.ts +0 -88
  208. package/dist/core/hashline-edit-benchmark.js +0 -518
  209. package/dist/core/hashline-edit-benchmark.js.map +0 -1
  210. package/dist/core/semantic-search-benchmark.d.ts +0 -36
  211. package/dist/core/semantic-search-benchmark.js +0 -211
  212. package/dist/core/semantic-search-benchmark.js.map +0 -1
  213. package/dist/core/speed-benchmark.d.ts +0 -132
  214. package/dist/core/speed-benchmark.js +0 -410
  215. package/dist/core/speed-benchmark.js.map +0 -1
@@ -0,0 +1,149 @@
1
+ import { loadTasksSync, saveTasksSync, pruneDoneTasksSync } from "../core/tasks-store.js";
2
+ import { readChecklistSnapshot } from "../core/checklist-snapshot.js";
3
+ import { log } from "../core/logger.js";
4
+ import { RADIO_STATIONS, getCurrentStation, getRadioVolume, playRadio, setRadioVolume, stopRadio, } from "../core/radio.js";
5
+ import { readBody, json } from "./http.js";
6
+ export function handleTaskRoutes(ctx, req, res, url, method) {
7
+ if (method === "GET" && url === "/tasks") {
8
+ json(res, 200, { tasks: pruneDoneTasksSync(ctx.cwd) });
9
+ return true;
10
+ }
11
+ if (method === "GET" && url === "/checklist") {
12
+ const controller = new AbortController();
13
+ res.once("close", () => controller.abort());
14
+ void (async () => {
15
+ try {
16
+ const result = await readChecklistSnapshot(ctx.cwd, new Date(), controller.signal);
17
+ if (res.destroyed)
18
+ return;
19
+ if (!result.ok) {
20
+ log("WARN", "app-sidecar", "checklist read failed", { error: result.error });
21
+ json(res, 500, { error: result.error });
22
+ return;
23
+ }
24
+ json(res, 200, result.value);
25
+ }
26
+ catch (error) {
27
+ log("WARN", "app-sidecar", "checklist snapshot failed", { error: String(error) });
28
+ if (!res.destroyed)
29
+ json(res, 500, { error: "Could not read the project checklist" });
30
+ }
31
+ })();
32
+ return true;
33
+ }
34
+ // ── Radio (app-wide) ──────────────────────────────────────
35
+ // Radio is now APP-WIDE: all windows share one daemon process, and the
36
+ // player lives in `core/radio.ts` module-level singletons (one stream for
37
+ // the whole app). Any window's /radio reads/controls that single stream —
38
+ // starting a station in one window replaces whatever was playing, and every
39
+ // window's footer reflects the same `current`. This intentionally prevents
40
+ // duplicate audio across windows (the original per-window goal), now for
41
+ // free. (To restore per-window radio, key playback by sessionId.)
42
+ if (method === "GET" && url === "/radio") {
43
+ json(res, 200, {
44
+ stations: RADIO_STATIONS,
45
+ current: getCurrentStation(),
46
+ volume: getRadioVolume(),
47
+ });
48
+ return true;
49
+ }
50
+ if (method === "POST" && url === "/radio/volume") {
51
+ void readBody(req, res).then((raw) => {
52
+ if (raw === null)
53
+ return;
54
+ let volume;
55
+ try {
56
+ volume = Number(JSON.parse(raw).volume);
57
+ }
58
+ catch {
59
+ json(res, 400, { error: "invalid JSON body" });
60
+ return;
61
+ }
62
+ if (!Number.isFinite(volume)) {
63
+ json(res, 400, { error: "volume must be a number" });
64
+ return;
65
+ }
66
+ const result = setRadioVolume(volume);
67
+ if (!result.ok) {
68
+ json(res, 400, { error: result.error ?? "Radio volume failed to update." });
69
+ return;
70
+ }
71
+ json(res, 200, { current: getCurrentStation(), volume: getRadioVolume() });
72
+ });
73
+ return true;
74
+ }
75
+ if (method === "POST" && url === "/radio") {
76
+ void readBody(req, res).then((raw) => {
77
+ if (raw === null)
78
+ return;
79
+ let station;
80
+ try {
81
+ station = JSON.parse(raw).station ?? "";
82
+ }
83
+ catch {
84
+ json(res, 400, { error: "invalid JSON body" });
85
+ return;
86
+ }
87
+ if (!station || station === "off") {
88
+ stopRadio();
89
+ json(res, 200, { current: null });
90
+ return;
91
+ }
92
+ const result = playRadio(station);
93
+ if (!result.ok) {
94
+ json(res, 400, { error: result.error ?? "Radio failed to start." });
95
+ return;
96
+ }
97
+ json(res, 200, { current: getCurrentStation() });
98
+ });
99
+ return true;
100
+ }
101
+ if (method === "POST" && url === "/tasks/run") {
102
+ void readBody(req, res).then((raw) => {
103
+ if (raw === null)
104
+ return;
105
+ let id;
106
+ let all;
107
+ try {
108
+ const body = JSON.parse(raw);
109
+ id = body.id ?? null;
110
+ all = Boolean(body.all);
111
+ }
112
+ catch {
113
+ json(res, 400, { error: "invalid JSON body" });
114
+ return;
115
+ }
116
+ if (ctx.running) {
117
+ json(res, 409, { error: "cannot run a task while the agent is running" });
118
+ return;
119
+ }
120
+ json(res, 202, { accepted: true });
121
+ void ctx.runTasks(id, all);
122
+ });
123
+ return true;
124
+ }
125
+ if (method === "POST" && url === "/tasks/delete") {
126
+ void readBody(req, res).then((raw) => {
127
+ if (raw === null)
128
+ return;
129
+ let id;
130
+ try {
131
+ id = JSON.parse(raw).id ?? "";
132
+ }
133
+ catch {
134
+ json(res, 400, { error: "invalid JSON body" });
135
+ return;
136
+ }
137
+ if (!id.trim()) {
138
+ json(res, 400, { error: "missing task id" });
139
+ return;
140
+ }
141
+ const remaining = loadTasksSync(ctx.cwd).filter((t) => t.id !== id && !t.id.startsWith(id));
142
+ saveTasksSync(ctx.cwd, remaining);
143
+ json(res, 200, { tasks: remaining });
144
+ });
145
+ return true;
146
+ }
147
+ return false;
148
+ }
149
+ //# sourceMappingURL=task-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-routes.js","sourceRoot":"","sources":["../../src/app-sidecar/task-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type SubscriptionUsageProvider, type SubscriptionUsageSnapshot } from "@kenkaiiii/gg-core";
2
+ import type { AuthStorage } from "../core/auth-storage.js";
3
+ export type UsageResult = (SubscriptionUsageSnapshot & {
4
+ connected: true;
5
+ error?: never;
6
+ stale?: boolean;
7
+ }) | {
8
+ provider: SubscriptionUsageProvider;
9
+ displayName: string;
10
+ connected: boolean;
11
+ windows: [];
12
+ fetchedAt: number;
13
+ error?: string;
14
+ stale?: boolean;
15
+ };
16
+ /** Daemon-level subscription-usage fetcher with caching, 429 backoff and last-good replay. */
17
+ export declare function createUsageService(auth: AuthStorage): {
18
+ subscriptionUsage: (provider: SubscriptionUsageProvider) => Promise<UsageResult>;
19
+ };
@@ -0,0 +1,153 @@
1
+ import { fetchSubscriptionUsage, SubscriptionUsageError, oauthStorageKey, } from "@kenkaiiii/gg-core";
2
+ import { log } from "../core/logger.js";
3
+ /** Daemon-level subscription-usage fetcher with caching, 429 backoff and last-good replay. */
4
+ export function createUsageService(auth) {
5
+ const usageCache = new Map();
6
+ const usageRequests = new Map();
7
+ // Last snapshot that actually carried windows, per provider. Replayed while a
8
+ // fetch is failing so the title meter never blinks out of existence. Bounded
9
+ // by USAGE_LAST_GOOD_MAX_AGE_MS — a provider that never recovers must stop
10
+ // reporting rather than freeze a percentage (and a long-past reset time) on
11
+ // screen forever. The 429 backoff alone runs to 24h, far past any usefulness.
12
+ const usageLastGood = new Map();
13
+ const USAGE_LAST_GOOD_MAX_AGE_MS = 30 * 60_000;
14
+ // 429 backoff: quota endpoints are auxiliary UI data. Honor Retry-After when
15
+ // provided; otherwise retain the unavailable snapshot for 30 minutes. Clamp
16
+ // the provider value so a malformed header can neither hammer the endpoint
17
+ // nor suppress usage data forever.
18
+ const usageRateLimitedUntil = new Map();
19
+ // Providers currently in a logged rate-limit episode (cleared on success).
20
+ const usageRateLimitLogged = new Set();
21
+ const USAGE_RATE_LIMIT_FALLBACK_BACKOFF_MS = 30 * 60_000;
22
+ const USAGE_RATE_LIMIT_MIN_BACKOFF_MS = 60_000;
23
+ const USAGE_RATE_LIMIT_MAX_BACKOFF_MS = 24 * 60 * 60_000;
24
+ function clearUsageRateLimit(provider) {
25
+ usageRateLimitedUntil.delete(provider);
26
+ if (usageRateLimitLogged.delete(provider)) {
27
+ log("INFO", "app-sidecar", "subscription usage recovered", { provider });
28
+ }
29
+ }
30
+ async function fetchUsageProvider(provider) {
31
+ const displayName = provider === "anthropic" ? "Anthropic" : provider === "openai" ? "Codex" : "Kimi";
32
+ // Kimi plan usage is tracked on the OAuth credential specifically — the
33
+ // Moonshot platform API key is metered per-token, not per plan window.
34
+ const authKey = oauthStorageKey(provider) ?? provider;
35
+ if (!(await auth.hasProviderAuth(authKey))) {
36
+ // Logged out: drop the replay cache so a later login on a DIFFERENT
37
+ // account can never inherit the previous one's numbers.
38
+ usageLastGood.delete(provider);
39
+ return { provider, displayName, connected: false, windows: [], fetchedAt: Date.now() };
40
+ }
41
+ try {
42
+ let credentials = await auth.resolveCredentials(authKey);
43
+ try {
44
+ const snapshot = {
45
+ ...(await fetchSubscriptionUsage(provider, credentials)),
46
+ connected: true,
47
+ };
48
+ clearUsageRateLimit(provider);
49
+ return snapshot;
50
+ }
51
+ catch (error) {
52
+ // A provider can revoke an access token before its stored expiry. Refresh
53
+ // once on 401, matching inference auth recovery, then retry the usage call.
54
+ if (error instanceof SubscriptionUsageError && error.status === 401) {
55
+ // Name the rejected token. This poller runs on a timer alongside live
56
+ // agent runs, so an unconditional refresh here would invalidate the
57
+ // token those runs are holding and fail them mid-turn — a background
58
+ // status check must never be able to log out the foreground.
59
+ credentials = await auth.resolveCredentials(authKey, {
60
+ forceRefresh: true,
61
+ rejectedToken: credentials.accessToken,
62
+ });
63
+ const snapshot = {
64
+ ...(await fetchSubscriptionUsage(provider, credentials)),
65
+ connected: true,
66
+ };
67
+ clearUsageRateLimit(provider);
68
+ return snapshot;
69
+ }
70
+ throw error;
71
+ }
72
+ }
73
+ catch (error) {
74
+ const message = error instanceof Error ? error.message : String(error);
75
+ if (error instanceof SubscriptionUsageError && error.status === 429) {
76
+ const backoffMs = Math.min(USAGE_RATE_LIMIT_MAX_BACKOFF_MS, Math.max(USAGE_RATE_LIMIT_MIN_BACKOFF_MS, error.retryAfterMs ?? USAGE_RATE_LIMIT_FALLBACK_BACKOFF_MS));
77
+ usageRateLimitedUntil.set(provider, Date.now() + backoffMs);
78
+ // Rate limits on this auxiliary endpoint are expected (every GG process
79
+ // on the machine polls it) and already handled by the backoff plus the
80
+ // last-good replay. Log the transition, not every retry.
81
+ if (!usageRateLimitLogged.has(provider)) {
82
+ usageRateLimitLogged.add(provider);
83
+ log("INFO", "app-sidecar", "subscription usage rate-limited; backing off", {
84
+ provider,
85
+ backoffMs: String(backoffMs),
86
+ });
87
+ }
88
+ }
89
+ else {
90
+ log("WARN", "app-sidecar", "subscription usage fetch failed", { provider, message });
91
+ }
92
+ const connected = await auth.hasProviderAuth(authKey);
93
+ // Transient failures (notably the 429s these auxiliary quota endpoints
94
+ // hand out) must not blank the meter. Keep serving the last good
95
+ // snapshot, flagged `stale`, so the bar stays put instead of flickering
96
+ // out for the whole backoff window and back in on the next success.
97
+ // Past the max age it's dropped — no data beats confidently wrong data.
98
+ const lastGood = usageLastGood.get(provider);
99
+ if (lastGood && Date.now() - lastGood.fetchedAt >= USAGE_LAST_GOOD_MAX_AGE_MS) {
100
+ usageLastGood.delete(provider);
101
+ }
102
+ else if (connected && lastGood) {
103
+ return { ...lastGood, stale: true };
104
+ }
105
+ return {
106
+ provider,
107
+ displayName,
108
+ connected,
109
+ windows: [],
110
+ fetchedAt: Date.now(),
111
+ error: connected ? "Usage is temporarily unavailable." : undefined,
112
+ };
113
+ }
114
+ }
115
+ async function subscriptionUsage(provider) {
116
+ const cached = usageCache.get(provider);
117
+ if (cached && cached.expiresAt > Date.now())
118
+ return cached.result;
119
+ const inFlight = usageRequests.get(provider);
120
+ if (inFlight)
121
+ return inFlight;
122
+ const request = fetchUsageProvider(provider);
123
+ usageRequests.set(provider, request);
124
+ try {
125
+ const result = await request;
126
+ // Never re-store a replay — it would keep its original `fetchedAt`, but
127
+ // writing it back muddies the "last GOOD" contract for no gain.
128
+ if (result.connected && !result.error && !result.stale && result.windows.length > 0) {
129
+ usageLastGood.set(provider, result);
130
+ }
131
+ // Anthropic can return utilization before it assigns reset timestamps
132
+ // (notably before the account's first active request). Retry that partial
133
+ // snapshot quickly; complete snapshots keep the normal one-minute cache.
134
+ const missingReset = result.connected &&
135
+ result.windows.length > 0 &&
136
+ result.windows.some((window) => window.resetsAt === undefined);
137
+ const rateLimitedUntil = usageRateLimitedUntil.get(provider) ?? 0;
138
+ usageCache.set(provider, {
139
+ result,
140
+ expiresAt: rateLimitedUntil > Date.now()
141
+ ? rateLimitedUntil
142
+ : Date.now() + (missingReset ? 10_000 : 60_000),
143
+ });
144
+ return result;
145
+ }
146
+ finally {
147
+ if (usageRequests.get(provider) === request)
148
+ usageRequests.delete(provider);
149
+ }
150
+ }
151
+ return { subscriptionUsage };
152
+ }
153
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/app-sidecar/usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type http from "node:http";
2
+ import type { SessionRouteContext } from "./route-context.js";
3
+ export declare function handleWorkspaceRoutes(ctx: SessionRouteContext, req: http.IncomingMessage, res: http.ServerResponse, url: string, method: string): boolean;
@@ -0,0 +1,244 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { sessionToMarkdown, defaultExportFilename } from "../core/session-export.js";
4
+ import { installPlugin, listInstalledPlugins, removePlugin, } from "../core/extensions/plugin-bundles.js";
5
+ import { discoverProjects } from "../core/project-discovery.js";
6
+ import { listSidecarSessions } from "../app-sidecar-sessions.js";
7
+ import { log } from "../core/logger.js";
8
+ import { readBody, json } from "./http.js";
9
+ import { parseToolDetail } from "./history.js";
10
+ import { searchProjectFiles } from "./file-search.js";
11
+ import { appSettingsFile, loadAppSettings, saveAppSettings, isValidProjectName, } from "./app-settings.js";
12
+ export function handleWorkspaceRoutes(ctx, req, res, url, method) {
13
+ if (method === "GET" && url === "/plugins") {
14
+ void listInstalledPlugins(ctx.paths.extensionsDir)
15
+ .then((plugins) => json(res, 200, { plugins }))
16
+ .catch((error) => {
17
+ json(res, 500, { error: error instanceof Error ? error.message : String(error) });
18
+ });
19
+ return true;
20
+ }
21
+ if (method === "POST" && url === "/plugins/install") {
22
+ void readBody(req, res).then(async (raw) => {
23
+ if (raw === null)
24
+ return;
25
+ try {
26
+ const bundlePath = JSON.parse(raw).bundlePath;
27
+ if (typeof bundlePath !== "string" || !path.isAbsolute(bundlePath)) {
28
+ json(res, 400, { error: "bundlePath must be an absolute path" });
29
+ return;
30
+ }
31
+ const plugin = await installPlugin(bundlePath, ctx.paths.extensionsDir);
32
+ json(res, 200, { plugin, restartRequired: true });
33
+ }
34
+ catch (error) {
35
+ json(res, 400, { error: error instanceof Error ? error.message : String(error) });
36
+ }
37
+ });
38
+ return true;
39
+ }
40
+ if (method === "DELETE" && url.startsWith("/plugins/")) {
41
+ const pluginId = decodeURIComponent(url.slice("/plugins/".length));
42
+ void removePlugin(pluginId, ctx.paths.extensionsDir)
43
+ .then(() => json(res, 200, { removed: pluginId, restartRequired: true }))
44
+ .catch((error) => {
45
+ json(res, 400, { error: error instanceof Error ? error.message : String(error) });
46
+ });
47
+ return true;
48
+ }
49
+ if (method === "GET" && url === "/settings") {
50
+ // `configured` is true only when the user explicitly saved a projects root
51
+ // (the gg-app.json file exists with a value) — not when we fall back to the
52
+ // default. The home screen gates "Your Projects" on this.
53
+ void (async () => {
54
+ const s = await loadAppSettings();
55
+ let configured;
56
+ try {
57
+ const raw = JSON.parse(await fs.readFile(appSettingsFile(), "utf-8"));
58
+ configured = typeof raw.projectsRoot === "string" && raw.projectsRoot.trim().length > 0;
59
+ }
60
+ catch {
61
+ configured = false;
62
+ }
63
+ // Only projectsRoot + configured flag are webview-facing; the
64
+ // per-project model map is internal persistence, never shipped out.
65
+ json(res, 200, { projectsRoot: s.projectsRoot, configured });
66
+ })();
67
+ return true;
68
+ }
69
+ if (method === "POST" && url === "/settings") {
70
+ void readBody(req, res).then(async (raw) => {
71
+ if (raw === null)
72
+ return;
73
+ let projectsRoot;
74
+ try {
75
+ projectsRoot = JSON.parse(raw).projectsRoot ?? "";
76
+ }
77
+ catch {
78
+ json(res, 400, { error: "invalid JSON body" });
79
+ return;
80
+ }
81
+ if (!projectsRoot.trim()) {
82
+ json(res, 400, { error: "projectsRoot is required" });
83
+ return;
84
+ }
85
+ // Read-modify-write so the per-project model map survives a projectsRoot
86
+ // change (a naive overwrite would drop every window's saved model).
87
+ const s = await loadAppSettings();
88
+ s.projectsRoot = projectsRoot;
89
+ await saveAppSettings(s);
90
+ json(res, 200, { projectsRoot });
91
+ });
92
+ return true;
93
+ }
94
+ if (method === "POST" && url === "/create-project") {
95
+ void readBody(req, res).then(async (raw) => {
96
+ if (raw === null)
97
+ return;
98
+ let name;
99
+ try {
100
+ name = JSON.parse(raw).name ?? "";
101
+ }
102
+ catch {
103
+ json(res, 400, { error: "invalid JSON body" });
104
+ return;
105
+ }
106
+ name = name.trim();
107
+ if (!isValidProjectName(name)) {
108
+ json(res, 400, {
109
+ error: "Project name must be lowercase letters, digits, and dashes (e.g. my-project).",
110
+ });
111
+ return;
112
+ }
113
+ const { projectsRoot } = await loadAppSettings();
114
+ const dir = path.join(projectsRoot, name);
115
+ try {
116
+ // Refuse to clobber an existing directory.
117
+ const exists = await fs
118
+ .stat(dir)
119
+ .then(() => true)
120
+ .catch(() => false);
121
+ if (exists) {
122
+ json(res, 409, { error: `A folder named "${name}" already exists.` });
123
+ return;
124
+ }
125
+ await fs.mkdir(dir, { recursive: true });
126
+ json(res, 200, { path: dir });
127
+ }
128
+ catch (err) {
129
+ json(res, 500, { error: err instanceof Error ? err.message : String(err) });
130
+ }
131
+ });
132
+ return true;
133
+ }
134
+ // Dismiss a project from the picker (or restore it with hidden:false). The
135
+ // path is kept rather than the row: sessions in scratch dirs keep
136
+ // re-surfacing, so the user's decision has to outlive any one scan.
137
+ if (method === "POST" && url === "/projects/hidden") {
138
+ void readBody(req, res).then(async (raw) => {
139
+ if (raw === null)
140
+ return;
141
+ let body;
142
+ try {
143
+ body = JSON.parse(raw);
144
+ }
145
+ catch {
146
+ json(res, 400, { error: "invalid JSON body" });
147
+ return;
148
+ }
149
+ const target = body.path?.trim();
150
+ if (!target) {
151
+ json(res, 400, { error: "path is required" });
152
+ return;
153
+ }
154
+ const key = path.resolve(target);
155
+ try {
156
+ const settings = await loadAppSettings();
157
+ const current = new Set((settings.hiddenProjects ?? []).map((p) => path.resolve(p)));
158
+ if (body.hidden === false)
159
+ current.delete(key);
160
+ else
161
+ current.add(key);
162
+ settings.hiddenProjects = current.size > 0 ? Array.from(current) : undefined;
163
+ await saveAppSettings(settings);
164
+ json(res, 200, { hidden: Array.from(current) });
165
+ }
166
+ catch (err) {
167
+ json(res, 500, { error: err instanceof Error ? err.message : String(err) });
168
+ }
169
+ });
170
+ return true;
171
+ }
172
+ if (method === "GET" && url === "/projects") {
173
+ // Session stores (ggcoder + Claude Code + Codex) for projects with
174
+ // history, plus a filesystem scan of the configured projects folder so
175
+ // projects you have not opened yet are still listed.
176
+ void loadAppSettings()
177
+ .then(({ projectsRoot, projectRoots, hiddenProjects }) => discoverProjects({
178
+ projectsRoot,
179
+ extraRoots: projectRoots,
180
+ hiddenPaths: hiddenProjects,
181
+ }))
182
+ .then((projects) => json(res, 200, { projects }))
183
+ .catch((err) => {
184
+ log("ERROR", "app-sidecar", "discoverProjects failed", {
185
+ message: err instanceof Error ? err.message : String(err),
186
+ });
187
+ json(res, 200, { projects: [] });
188
+ });
189
+ return true;
190
+ }
191
+ if (method === "GET" && url.startsWith("/sessions")) {
192
+ const target = new URL(url, `http://${ctx.host}`).searchParams.get("cwd");
193
+ if (!target) {
194
+ json(res, 400, { error: "missing cwd query param" });
195
+ return true;
196
+ }
197
+ const requestedAgent = new URL(url, `http://${ctx.host}`).searchParams.get("chatAgent");
198
+ // An omitted chatAgent means coding history; chat callers identify one
199
+ // agent or request the combined, recency-sorted "all" listing; the
200
+ // reserved value "motion" lists Motion sessions.
201
+ void listSidecarSessions(target, requestedAgent, ctx.paths.sessionsDir)
202
+ .then((sessions) => json(res, 200, { sessions }))
203
+ .catch(() => json(res, 200, { sessions: [] }));
204
+ return true;
205
+ }
206
+ if (method === "GET" && url.startsWith("/files")) {
207
+ const q = new URL(url, `http://${ctx.host}`).searchParams.get("q") ?? "";
208
+ void searchProjectFiles(ctx.cwd, q)
209
+ .then((files) => json(res, 200, { files }))
210
+ .catch((err) => {
211
+ log("ERROR", "app-sidecar", "searchProjectFiles failed", {
212
+ message: err instanceof Error ? err.message : String(err),
213
+ });
214
+ json(res, 200, { files: [] });
215
+ });
216
+ return true;
217
+ }
218
+ // Markdown transcript export for the app's download button. Serialized
219
+ // here rather than in the webview because the webview's transcript model
220
+ // deliberately keeps tool activity in the LiveToolPanel — exporting from
221
+ // there would hand the user a coding session with the coding missing.
222
+ // `?name=1` asks for the suggested filename only (the save dialog needs it
223
+ // before there is a path), so the markdown never crosses IPC twice.
224
+ if (method === "GET" && (url === "/export" || url.startsWith("/export?"))) {
225
+ const query = new URLSearchParams(url.slice(url.indexOf("?") + 1));
226
+ const st = ctx.session.getState();
227
+ const filename = defaultExportFilename(ctx.mode);
228
+ if (query.get("name") === "1") {
229
+ json(res, 200, { filename });
230
+ return true;
231
+ }
232
+ const markdown = sessionToMarkdown({
233
+ mode: ctx.mode,
234
+ cwd: ctx.cwd,
235
+ provider: st.provider,
236
+ model: st.model,
237
+ ...(st.sessionId ? { sessionId: st.sessionId } : {}),
238
+ }, ctx.session.getMessages(), { toolDetail: parseToolDetail(query.get("tools")) });
239
+ json(res, 200, { filename, markdown });
240
+ return true;
241
+ }
242
+ return false;
243
+ }
244
+ //# sourceMappingURL=workspace-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-routes.js","sourceRoot":"","sources":["../../src/app-sidecar/workspace-routes.ts"],"names":[],"mappings":"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"}