@prestyj/cli 5.30.0 → 5.30.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 +54 -39
- package/assets/skills/bulletproof/SKILL.md +1 -1
- package/assets/skills/clarify/SKILL.md +1 -1
- package/assets/skills/code-review/SKILL.md +1 -1
- package/assets/skills/compliance-guard/SKILL.md +1 -1
- package/assets/skills/durable/SKILL.md +1 -1
- package/assets/skills/evidence-led-ui/SKILL.md +1 -1
- package/assets/skills/lean/SKILL.md +1 -1
- package/assets/skills/refactoring/SKILL.md +1 -1
- package/assets/skills/root-cause/SKILL.md +1 -1
- package/assets/skills/shared-language/SKILL.md +1 -1
- package/assets/skills/tdd/SKILL.md +1 -1
- package/dist/app-sidecar/app-settings.d.ts +63 -0
- package/dist/app-sidecar/app-settings.js +147 -0
- package/dist/app-sidecar/app-settings.js.map +1 -0
- package/dist/app-sidecar/attachments.d.ts +11 -0
- package/dist/app-sidecar/attachments.js +47 -0
- package/dist/app-sidecar/attachments.js.map +1 -0
- package/dist/app-sidecar/auth-routes.d.ts +3 -0
- package/dist/app-sidecar/auth-routes.js +293 -0
- package/dist/app-sidecar/auth-routes.js.map +1 -0
- package/dist/app-sidecar/autopilot-runner.d.ts +62 -0
- package/dist/app-sidecar/autopilot-runner.js +373 -0
- package/dist/app-sidecar/autopilot-runner.js.map +1 -0
- package/dist/app-sidecar/file-search.d.ts +15 -0
- package/dist/app-sidecar/file-search.js +103 -0
- package/dist/app-sidecar/file-search.js.map +1 -0
- package/dist/app-sidecar/hf-pull-manager.d.ts +20 -0
- package/dist/app-sidecar/hf-pull-manager.js +224 -0
- package/dist/app-sidecar/hf-pull-manager.js.map +1 -0
- package/dist/app-sidecar/history-routes.d.ts +3 -0
- package/dist/app-sidecar/history-routes.js +375 -0
- package/dist/app-sidecar/history-routes.js.map +1 -0
- package/dist/app-sidecar/history.d.ts +67 -0
- package/dist/app-sidecar/history.js +23 -0
- package/dist/app-sidecar/history.js.map +1 -0
- package/dist/app-sidecar/http.d.ts +5 -0
- package/dist/app-sidecar/http.js +27 -0
- package/dist/app-sidecar/http.js.map +1 -0
- package/dist/app-sidecar/integration-routes.d.ts +3 -0
- package/dist/app-sidecar/integration-routes.js +286 -0
- package/dist/app-sidecar/integration-routes.js.map +1 -0
- package/dist/app-sidecar/json-mode.d.ts +10 -0
- package/dist/app-sidecar/json-mode.js +73 -0
- package/dist/app-sidecar/json-mode.js.map +1 -0
- package/dist/app-sidecar/keep-awake.d.ts +4 -0
- package/dist/app-sidecar/keep-awake.js +5 -0
- package/dist/app-sidecar/keep-awake.js.map +1 -0
- package/dist/app-sidecar/mcp-routes.d.ts +3 -0
- package/dist/app-sidecar/mcp-routes.js +185 -0
- package/dist/app-sidecar/mcp-routes.js.map +1 -0
- package/dist/app-sidecar/mcp-rows.d.ts +31 -0
- package/dist/app-sidecar/mcp-rows.js +77 -0
- package/dist/app-sidecar/mcp-rows.js.map +1 -0
- package/dist/app-sidecar/nolan-context.d.ts +20 -0
- package/dist/app-sidecar/nolan-context.js +55 -0
- package/dist/app-sidecar/nolan-context.js.map +1 -0
- package/dist/app-sidecar/progress-manager.d.ts +10 -0
- package/dist/app-sidecar/progress-manager.js +116 -0
- package/dist/app-sidecar/progress-manager.js.map +1 -0
- package/dist/app-sidecar/prompt-routes.d.ts +3 -0
- package/dist/app-sidecar/prompt-routes.js +355 -0
- package/dist/app-sidecar/prompt-routes.js.map +1 -0
- package/dist/app-sidecar/repo-polls.d.ts +18 -0
- package/dist/app-sidecar/repo-polls.js +45 -0
- package/dist/app-sidecar/repo-polls.js.map +1 -0
- package/dist/app-sidecar/route-context.d.ts +147 -0
- package/dist/app-sidecar/route-context.js +2 -0
- package/dist/app-sidecar/route-context.js.map +1 -0
- package/dist/app-sidecar/run-control-routes.d.ts +3 -0
- package/dist/app-sidecar/run-control-routes.js +437 -0
- package/dist/app-sidecar/run-control-routes.js.map +1 -0
- package/dist/app-sidecar/session-routes.d.ts +3 -0
- package/dist/app-sidecar/session-routes.js +115 -0
- package/dist/app-sidecar/session-routes.js.map +1 -0
- package/dist/app-sidecar/session-types.d.ts +39 -0
- package/dist/app-sidecar/session-types.js +5 -0
- package/dist/app-sidecar/session-types.js.map +1 -0
- package/dist/app-sidecar/task-routes.d.ts +3 -0
- package/dist/app-sidecar/task-routes.js +232 -0
- package/dist/app-sidecar/task-routes.js.map +1 -0
- package/dist/app-sidecar/usage.d.ts +19 -0
- package/dist/app-sidecar/usage.js +153 -0
- package/dist/app-sidecar/usage.js.map +1 -0
- package/dist/app-sidecar/workspace-routes.d.ts +3 -0
- package/dist/app-sidecar/workspace-routes.js +374 -0
- package/dist/app-sidecar/workspace-routes.js.map +1 -0
- package/dist/app-sidecar.js +541 -3971
- package/dist/app-sidecar.js.map +1 -1
- package/dist/chat-agents/jiwa.js +2 -0
- package/dist/chat-agents/jiwa.js.map +1 -1
- package/dist/chat-agents/memory.js +2 -0
- package/dist/chat-agents/memory.js.map +1 -1
- package/dist/cli/auth.js +13 -9
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli.js +10 -11
- package/dist/cli.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/core/acceptance-checks.js +3 -9
- package/dist/core/acceptance-checks.js.map +1 -1
- package/dist/core/agent-session/helpers.d.ts +26 -0
- package/dist/core/agent-session/helpers.js +47 -0
- package/dist/core/agent-session/helpers.js.map +1 -0
- package/dist/core/agent-session/mcp-tools.d.ts +68 -0
- package/dist/core/agent-session/mcp-tools.js +195 -0
- package/dist/core/agent-session/mcp-tools.js.map +1 -0
- package/dist/core/agent-session/run-loop-monitor.d.ts +63 -0
- package/dist/core/agent-session/run-loop-monitor.js +164 -0
- package/dist/core/agent-session/run-loop-monitor.js.map +1 -0
- package/dist/core/agent-session/transcript-markers.d.ts +57 -0
- package/dist/core/agent-session/transcript-markers.js +166 -0
- package/dist/core/agent-session/transcript-markers.js.map +1 -0
- package/dist/core/agent-session/verification-tracker.d.ts +50 -0
- package/dist/core/agent-session/verification-tracker.js +269 -0
- package/dist/core/agent-session/verification-tracker.js.map +1 -0
- package/dist/core/agent-session.d.ts +27 -87
- package/dist/core/agent-session.js +166 -713
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-providers.js +3 -3
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/autopilot-cycle.d.ts +8 -2
- package/dist/core/autopilot-cycle.js +22 -3
- package/dist/core/autopilot-cycle.js.map +1 -1
- package/dist/core/bundled-agents.js +6 -6
- package/dist/core/bundled-agents.js.map +1 -1
- package/dist/core/checklist-git.d.ts +19 -0
- package/dist/core/checklist-git.js +54 -0
- package/dist/core/checklist-git.js.map +1 -0
- package/dist/core/checklist-items.d.ts +10 -1
- package/dist/core/checklist-items.js +22 -0
- package/dist/core/checklist-items.js.map +1 -1
- package/dist/core/checklist-prompt.d.ts +14 -3
- package/dist/core/checklist-prompt.js +38 -8
- package/dist/core/checklist-prompt.js.map +1 -1
- package/dist/core/checklist-snapshot.d.ts +5 -1
- package/dist/core/checklist-snapshot.js +20 -3
- package/dist/core/checklist-snapshot.js.map +1 -1
- package/dist/core/checklist-store.d.ts +5 -1
- package/dist/core/checklist-store.js +35 -4
- package/dist/core/checklist-store.js.map +1 -1
- package/dist/core/context-limits.js +1 -1
- package/dist/core/context-limits.js.map +1 -1
- package/dist/core/event-bus.d.ts +1 -1
- package/dist/core/event-bus.js +39 -13
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/extensions/plugin-bundles.js +4 -2
- package/dist/core/extensions/plugin-bundles.js.map +1 -1
- package/dist/core/hashline.d.ts +10 -8
- package/dist/core/hashline.js.map +1 -1
- package/dist/core/mcp/client.js +2 -0
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/loopback.d.ts +2 -2
- package/dist/core/mcp/loopback.js +2 -2
- package/dist/core/mcp/shared-pool.js +4 -3
- package/dist/core/mcp/shared-pool.js.map +1 -1
- package/dist/core/persistent-shell.js +2 -1
- package/dist/core/persistent-shell.js.map +1 -1
- package/dist/core/plan-handoff.d.ts +30 -0
- package/dist/core/plan-handoff.js +10 -0
- package/dist/core/plan-handoff.js.map +1 -0
- package/dist/core/plan-submission-gate.d.ts +28 -0
- package/dist/core/plan-submission-gate.js +27 -0
- package/dist/core/plan-submission-gate.js.map +1 -0
- package/dist/core/process-manager.js +9 -1
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/project-health-scan.d.ts +109 -0
- package/dist/core/project-health-scan.js +673 -0
- package/dist/core/project-health-scan.js.map +1 -0
- package/dist/core/project-health-score.d.ts +41 -0
- package/dist/core/project-health-score.js +257 -0
- package/dist/core/project-health-score.js.map +1 -0
- package/dist/core/prompt-commands.js +44 -6
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-storage.d.ts +1 -0
- package/dist/core/session-storage.js +1 -1
- package/dist/core/session-storage.js.map +1 -1
- package/dist/core/skills.js +6 -9
- package/dist/core/skills.js.map +1 -1
- package/dist/core/style-packs/index.js +2 -11
- package/dist/core/style-packs/index.js.map +1 -1
- package/dist/core/style-packs/packs.d.ts +3 -12
- package/dist/core/style-packs/packs.js +132 -173
- package/dist/core/style-packs/packs.js.map +1 -1
- package/dist/core/subagent-manager.js +11 -6
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-receipt.js +3 -4
- package/dist/core/subagent-receipt.js.map +1 -1
- package/dist/core/ui-adoption.js +2 -0
- package/dist/core/ui-adoption.js.map +1 -1
- package/dist/core/ui-registry.js +5 -4
- package/dist/core/ui-registry.js.map +1 -1
- package/dist/core/verification-evidence.d.ts +21 -2
- package/dist/core/verification-evidence.js +283 -8
- package/dist/core/verification-evidence.js.map +1 -1
- package/dist/core/verification-gate.js +4 -2
- package/dist/core/verification-gate.js.map +1 -1
- package/dist/core/verify-commands.js +2 -3
- package/dist/core/verify-commands.js.map +1 -1
- package/dist/modes/agent-home-mode.js +1 -4
- package/dist/modes/agent-home-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.js +13 -8
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/system-prompt.js +70 -87
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/ask-user.js +13 -74
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/bash.d.ts +3 -1
- package/dist/tools/bash.js +28 -84
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/checklist.d.ts +7 -14
- package/dist/tools/checklist.js +22 -41
- package/dist/tools/checklist.js.map +1 -1
- package/dist/tools/code-nav.js +7 -29
- package/dist/tools/code-nav.js.map +1 -1
- package/dist/tools/edit.d.ts +4 -9
- package/dist/tools/edit.js +175 -65
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/enter-plan.js +2 -7
- package/dist/tools/enter-plan.js.map +1 -1
- package/dist/tools/exit-plan.js +2 -3
- package/dist/tools/exit-plan.js.map +1 -1
- package/dist/tools/find.js +3 -4
- package/dist/tools/find.js.map +1 -1
- package/dist/tools/grep.js +9 -20
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/index.js +10 -7
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/ls.js +3 -3
- package/dist/tools/ls.js.map +1 -1
- package/dist/tools/prompt-hints.js +34 -47
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/read-only-bash.js +3 -0
- package/dist/tools/read-only-bash.js.map +1 -1
- package/dist/tools/read.js +8 -20
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/search-code.js +4 -12
- package/dist/tools/search-code.js.map +1 -1
- package/dist/tools/skill.js +13 -7
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/subagent-control.js +7 -22
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent.js +1 -1
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/task-output.js +4 -15
- package/dist/tools/task-output.js.map +1 -1
- package/dist/tools/task-send.js +5 -17
- package/dist/tools/task-send.js.map +1 -1
- package/dist/tools/task-stop.js +2 -2
- package/dist/tools/task-stop.js.map +1 -1
- package/dist/tools/tool-search.js +2 -7
- package/dist/tools/tool-search.js.map +1 -1
- package/dist/tools/tool-tiers.d.ts +21 -4
- package/dist/tools/tool-tiers.js +44 -17
- package/dist/tools/tool-tiers.js.map +1 -1
- package/dist/tools/web-fetch.js +7 -33
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/write.js +3 -4
- package/dist/tools/write.js.map +1 -1
- package/dist/ui/App.js +20 -26
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/Footer.js +1 -2
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/components/InputArea.js +0 -2
- package/dist/ui/components/InputArea.js.map +1 -1
- package/dist/ui/components/ToolExecution.js +4 -3
- package/dist/ui/components/ToolExecution.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +7 -6
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/sessions.js +1 -5
- package/dist/ui/sessions.js.map +1 -1
- package/dist/ui/utils/highlight.d.ts +0 -5
- package/dist/ui/utils/highlight.js +3 -49
- package/dist/ui/utils/highlight.js.map +1 -1
- package/dist/ui/utils/markdown-renderer.d.ts +6 -0
- package/dist/ui/utils/markdown-renderer.js +21 -5
- package/dist/ui/utils/markdown-renderer.js.map +1 -1
- package/dist/utils/process.js +3 -3
- package/dist/utils/process.js.map +1 -1
- package/dist/utils/shared-poll.d.ts +37 -0
- package/dist/utils/shared-poll.js +104 -0
- package/dist/utils/shared-poll.js.map +1 -0
- package/package.json +8 -8
- package/dist/core/api-benchmark.d.ts +0 -63
- package/dist/core/api-benchmark.js +0 -381
- package/dist/core/api-benchmark.js.map +0 -1
- package/dist/core/bash-spawn-benchmark.d.ts +0 -1
- package/dist/core/bash-spawn-benchmark.js +0 -139
- package/dist/core/bash-spawn-benchmark.js.map +0 -1
- package/dist/core/cache-warm-benchmark.d.ts +0 -21
- package/dist/core/cache-warm-benchmark.js +0 -170
- package/dist/core/cache-warm-benchmark.js.map +0 -1
- package/dist/core/fast-apply-benchmark.d.ts +0 -25
- package/dist/core/fast-apply-benchmark.js +0 -284
- package/dist/core/fast-apply-benchmark.js.map +0 -1
- package/dist/core/hashline-edit-benchmark.d.ts +0 -88
- package/dist/core/hashline-edit-benchmark.js +0 -518
- package/dist/core/hashline-edit-benchmark.js.map +0 -1
- package/dist/core/semantic-search-benchmark.d.ts +0 -36
- package/dist/core/semantic-search-benchmark.js +0 -211
- package/dist/core/semantic-search-benchmark.js.map +0 -1
- package/dist/core/speed-benchmark.d.ts +0 -132
- package/dist/core/speed-benchmark.js +0 -410
- package/dist/core/speed-benchmark.js.map +0 -1
- package/dist/ui/activity-phrases.d.ts +0 -10
- package/dist/ui/activity-phrases.js +0 -184
- package/dist/ui/activity-phrases.js.map +0 -1
- package/dist/ui/components/PlanApproval.d.ts +0 -7
- package/dist/ui/components/PlanApproval.js +0 -60
- package/dist/ui/components/PlanApproval.js.map +0 -1
- package/dist/ui/components/PlanBanner.d.ts +0 -5
- package/dist/ui/components/PlanBanner.js +0 -31
- package/dist/ui/components/PlanBanner.js.map +0 -1
- package/dist/ui/components/PlanProgress.d.ts +0 -6
- package/dist/ui/components/PlanProgress.js +0 -30
- package/dist/ui/components/PlanProgress.js.map +0 -1
- package/dist/ui/hooks/useMinDisplayTime.d.ts +0 -10
- package/dist/ui/hooks/useMinDisplayTime.js +0 -34
- package/dist/ui/hooks/useMinDisplayTime.js.map +0 -1
- package/dist/ui/hooks/useSessionManager.d.ts +0 -12
- package/dist/ui/hooks/useSessionManager.js +0 -43
- package/dist/ui/hooks/useSessionManager.js.map +0 -1
- package/dist/ui/hooks/useSlashCommands.d.ts +0 -6
- package/dist/ui/hooks/useSlashCommands.js +0 -11
- package/dist/ui/hooks/useSlashCommands.js.map +0 -1
- package/dist/ui/terminal-history-spacing.d.ts +0 -1
- package/dist/ui/terminal-history-spacing.js +0 -2
- package/dist/ui/terminal-history-spacing.js.map +0 -1
- package/dist/ui/utils/markdown-cache.d.ts +0 -10
- package/dist/ui/utils/markdown-cache.js +0 -58
- package/dist/ui/utils/markdown-cache.js.map +0 -1
- package/dist/ui/utils/token-to-ansi.d.ts +0 -8
- package/dist/ui/utils/token-to-ansi.js +0 -323
- package/dist/ui/utils/token-to-ansi.js.map +0 -1
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { loadTasksSync, saveTasksSync, pruneDoneTasksSync, } from "../core/task-store.js";
|
|
3
|
+
import { readChecklistSnapshot } from "../core/checklist-snapshot.js";
|
|
4
|
+
import { log } from "../core/logger.js";
|
|
5
|
+
import { RADIO_STATIONS, getCurrentStation, getRadioVolume, playRadio, setRadioVolume, stopRadio, } from "../core/radio.js";
|
|
6
|
+
import { readBody, json } from "./http.js";
|
|
7
|
+
export function handleTaskRoutes(ctx, req, res, url, method) {
|
|
8
|
+
if (method === "GET" && url === "/tasks") {
|
|
9
|
+
json(res, 200, { tasks: pruneDoneTasksSync(ctx.cwd) });
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
if (method === "GET" && url === "/checklist") {
|
|
13
|
+
const controller = new AbortController();
|
|
14
|
+
res.once("close", () => controller.abort());
|
|
15
|
+
void (async () => {
|
|
16
|
+
try {
|
|
17
|
+
const result = await readChecklistSnapshot(ctx.cwd, new Date(), controller.signal);
|
|
18
|
+
if (res.destroyed)
|
|
19
|
+
return;
|
|
20
|
+
if (!result.ok) {
|
|
21
|
+
log("WARN", "app-sidecar", "checklist read failed", { error: result.error });
|
|
22
|
+
json(res, 500, { error: result.error });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
json(res, 200, result.value);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
log("WARN", "app-sidecar", "checklist snapshot failed", { error: String(error) });
|
|
29
|
+
if (!res.destroyed)
|
|
30
|
+
json(res, 500, { error: "Could not read the project checklist" });
|
|
31
|
+
}
|
|
32
|
+
})();
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
// ── Radio (app-wide) ──────────────────────────────────────
|
|
36
|
+
// Radio is now APP-WIDE: all windows share one daemon process, and the
|
|
37
|
+
// player lives in `core/radio.ts` module-level singletons (one stream for
|
|
38
|
+
// the whole app). Any window's /radio reads/controls that single stream —
|
|
39
|
+
// starting a station in one window replaces whatever was playing, and every
|
|
40
|
+
// window's footer reflects the same `current`. This intentionally prevents
|
|
41
|
+
// duplicate audio across windows (the original per-window goal), now for
|
|
42
|
+
// free. (To restore per-window radio, key playback by sessionId.)
|
|
43
|
+
if (method === "GET" && url === "/radio") {
|
|
44
|
+
json(res, 200, {
|
|
45
|
+
stations: RADIO_STATIONS,
|
|
46
|
+
current: getCurrentStation(),
|
|
47
|
+
volume: getRadioVolume(),
|
|
48
|
+
});
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (method === "POST" && url === "/radio/volume") {
|
|
52
|
+
void readBody(req, res).then((raw) => {
|
|
53
|
+
if (raw === null)
|
|
54
|
+
return;
|
|
55
|
+
let volume;
|
|
56
|
+
try {
|
|
57
|
+
volume = Number(JSON.parse(raw).volume);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!Number.isFinite(volume)) {
|
|
64
|
+
json(res, 400, { error: "volume must be a number" });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const result = setRadioVolume(volume);
|
|
68
|
+
if (!result.ok) {
|
|
69
|
+
json(res, 400, { error: result.error ?? "Radio volume failed to update." });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
json(res, 200, { current: getCurrentStation(), volume: getRadioVolume() });
|
|
73
|
+
});
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (method === "POST" && url === "/radio") {
|
|
77
|
+
void readBody(req, res).then((raw) => {
|
|
78
|
+
if (raw === null)
|
|
79
|
+
return;
|
|
80
|
+
let station;
|
|
81
|
+
try {
|
|
82
|
+
station = JSON.parse(raw).station ?? "";
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (!station || station === "off") {
|
|
89
|
+
stopRadio();
|
|
90
|
+
json(res, 200, { current: null });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const result = playRadio(station);
|
|
94
|
+
if (!result.ok) {
|
|
95
|
+
json(res, 400, { error: result.error ?? "Radio failed to start." });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
json(res, 200, { current: getCurrentStation() });
|
|
99
|
+
});
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
if (method === "POST" && url === "/tasks/run") {
|
|
103
|
+
void readBody(req, res).then((raw) => {
|
|
104
|
+
if (raw === null)
|
|
105
|
+
return;
|
|
106
|
+
let id;
|
|
107
|
+
let all;
|
|
108
|
+
try {
|
|
109
|
+
const body = JSON.parse(raw);
|
|
110
|
+
id = body.id ?? null;
|
|
111
|
+
all = Boolean(body.all);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (ctx.running) {
|
|
118
|
+
json(res, 409, { error: "cannot run a task while the agent is running" });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
json(res, 202, { accepted: true });
|
|
122
|
+
void ctx.runTasks(id, all);
|
|
123
|
+
});
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
if (method === "POST" && url === "/tasks/add") {
|
|
127
|
+
void readBody(req, res).then((raw) => {
|
|
128
|
+
if (raw === null)
|
|
129
|
+
return;
|
|
130
|
+
let title;
|
|
131
|
+
let prompt;
|
|
132
|
+
try {
|
|
133
|
+
const body = JSON.parse(raw);
|
|
134
|
+
title = (body.title ?? "").trim();
|
|
135
|
+
prompt = (body.prompt ?? "").trim();
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (!title) {
|
|
142
|
+
json(res, 400, { error: "missing task title" });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const tasks = loadTasksSync(ctx.cwd);
|
|
146
|
+
const newTask = {
|
|
147
|
+
id: randomUUID(),
|
|
148
|
+
title,
|
|
149
|
+
prompt: prompt || title,
|
|
150
|
+
status: "pending",
|
|
151
|
+
createdAt: new Date().toISOString(),
|
|
152
|
+
};
|
|
153
|
+
const next = [...tasks, newTask];
|
|
154
|
+
saveTasksSync(ctx.cwd, next);
|
|
155
|
+
ctx.broadcast("tasks_list", { tasks: next });
|
|
156
|
+
json(res, 200, { tasks: next });
|
|
157
|
+
});
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
if (method === "POST" && url === "/tasks/update") {
|
|
161
|
+
void readBody(req, res).then((raw) => {
|
|
162
|
+
if (raw === null)
|
|
163
|
+
return;
|
|
164
|
+
let id;
|
|
165
|
+
let status;
|
|
166
|
+
let title;
|
|
167
|
+
let prompt;
|
|
168
|
+
try {
|
|
169
|
+
const body = JSON.parse(raw);
|
|
170
|
+
id = (body.id ?? "").trim();
|
|
171
|
+
status = body.status;
|
|
172
|
+
title = body.title;
|
|
173
|
+
prompt = body.prompt;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (!id) {
|
|
180
|
+
json(res, 400, { error: "missing task id" });
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (status && status !== "pending" && status !== "in-progress" && status !== "done") {
|
|
184
|
+
json(res, 400, { error: `invalid status: ${status}` });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const tasks = loadTasksSync(ctx.cwd);
|
|
188
|
+
const task = tasks.find((t) => t.id === id || t.id.startsWith(id));
|
|
189
|
+
if (!task) {
|
|
190
|
+
json(res, 404, { error: `no task found matching id "${id}"` });
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const next = tasks.map((t) => t.id === task.id
|
|
194
|
+
? {
|
|
195
|
+
...t,
|
|
196
|
+
...(status ? { status: status } : {}),
|
|
197
|
+
...(typeof title === "string" && title.trim() ? { title: title.trim() } : {}),
|
|
198
|
+
...(typeof prompt === "string" && prompt.trim() ? { prompt: prompt.trim() } : {}),
|
|
199
|
+
}
|
|
200
|
+
: t);
|
|
201
|
+
saveTasksSync(ctx.cwd, next);
|
|
202
|
+
ctx.broadcast("tasks_list", { tasks: next });
|
|
203
|
+
json(res, 200, { tasks: next });
|
|
204
|
+
});
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
if (method === "POST" && url === "/tasks/delete") {
|
|
208
|
+
void readBody(req, res).then((raw) => {
|
|
209
|
+
if (raw === null)
|
|
210
|
+
return;
|
|
211
|
+
let id;
|
|
212
|
+
try {
|
|
213
|
+
id = JSON.parse(raw).id ?? "";
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (!id.trim()) {
|
|
220
|
+
json(res, 400, { error: "missing task id" });
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const remaining = loadTasksSync(ctx.cwd).filter((t) => t.id !== id && !t.id.startsWith(id));
|
|
224
|
+
saveTasksSync(ctx.cwd, remaining);
|
|
225
|
+
ctx.broadcast("tasks_list", { tasks: remaining });
|
|
226
|
+
json(res, 200, { tasks: remaining });
|
|
227
|
+
});
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
//# 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 "@prestyj/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 "@prestyj/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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"}
|