gsd-pi 2.45.0-dev.6b9da3e → 2.45.0-dev.fdcf73c

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 (109) hide show
  1. package/dist/help-text.js +1 -1
  2. package/dist/loader.js +34 -0
  3. package/dist/resources/extensions/gsd/auto/phases.js +16 -10
  4. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  5. package/dist/resources/extensions/gsd/auto-worktree.js +5 -4
  6. package/dist/resources/extensions/gsd/auto.js +4 -5
  7. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +15 -12
  8. package/dist/resources/extensions/gsd/db-writer.js +9 -9
  9. package/dist/resources/extensions/gsd/doctor-checks.js +1 -1
  10. package/dist/resources/extensions/gsd/doctor.js +2 -2
  11. package/dist/resources/extensions/gsd/gsd-db.js +5 -1
  12. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  13. package/dist/resources/extensions/gsd/preferences.js +8 -4
  14. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +20 -7
  15. package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -0
  16. package/dist/resources/extensions/gsd/workflow-logger.js +138 -0
  17. package/dist/resources/extensions/gsd/worktree-manager.js +4 -3
  18. package/dist/resources/extensions/gsd/worktree-resolver.js +37 -0
  19. package/dist/resources/extensions/voice/index.js +11 -16
  20. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  21. package/dist/web/standalone/.next/BUILD_ID +1 -1
  22. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  23. package/dist/web/standalone/.next/build-manifest.json +2 -2
  24. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  25. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  26. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  34. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/index.html +1 -1
  42. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  49. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  50. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  51. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  52. package/package.json +2 -1
  53. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  54. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  55. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  56. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  57. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  58. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  59. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  60. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  61. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  62. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  63. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  64. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  65. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  66. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  67. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  68. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  69. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +2 -1
  70. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  71. package/packages/pi-coding-agent/dist/core/model-registry.js +20 -2
  72. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  73. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  74. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  75. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  76. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  77. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  78. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  79. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  80. package/packages/pi-coding-agent/src/core/model-registry.ts +30 -3
  81. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  82. package/src/resources/extensions/gsd/auto/phases.ts +16 -12
  83. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  84. package/src/resources/extensions/gsd/auto-worktree.ts +8 -5
  85. package/src/resources/extensions/gsd/auto.ts +3 -3
  86. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -12
  87. package/src/resources/extensions/gsd/db-writer.ts +9 -17
  88. package/src/resources/extensions/gsd/doctor-checks.ts +1 -1
  89. package/src/resources/extensions/gsd/doctor.ts +2 -2
  90. package/src/resources/extensions/gsd/gsd-db.ts +5 -1
  91. package/src/resources/extensions/gsd/journal.ts +6 -1
  92. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  93. package/src/resources/extensions/gsd/preferences.ts +7 -3
  94. package/src/resources/extensions/gsd/prompts/complete-milestone.md +20 -7
  95. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +96 -0
  96. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -1
  97. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +42 -3
  98. package/src/resources/extensions/gsd/tests/preferences.test.ts +7 -9
  99. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  100. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  101. package/src/resources/extensions/gsd/tools/complete-milestone.ts +6 -0
  102. package/src/resources/extensions/gsd/workflow-logger.ts +193 -0
  103. package/src/resources/extensions/gsd/worktree-manager.ts +4 -9
  104. package/src/resources/extensions/gsd/worktree-resolver.ts +37 -0
  105. package/src/resources/extensions/voice/index.ts +11 -21
  106. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  107. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  108. /package/dist/web/standalone/.next/static/{rzO54ZboyINyEt7cVM_uS → zWYDSwB-terOjfhmWzqk1}/_buildManifest.js +0 -0
  109. /package/dist/web/standalone/.next/static/{rzO54ZboyINyEt7cVM_uS → zWYDSwB-terOjfhmWzqk1}/_ssgManifest.js +0 -0
@@ -0,0 +1,138 @@
1
+ // GSD Extension — Workflow Logger
2
+ // Centralized warning/error accumulator for the workflow engine pipeline.
3
+ // Captures structured entries that the auto-loop can drain after each unit
4
+ // to surface root causes for stuck loops, silent degradation, and blocked writes.
5
+ //
6
+ // Stderr policy: every logWarning/logError call writes immediately to stderr
7
+ // for terminal visibility. This is intentional — unlike debug-logger (which is
8
+ // opt-in and zero-overhead when disabled), workflow-logger covers operational
9
+ // warnings/errors that should always be visible. There is no disable flag.
10
+ //
11
+ // Singleton safety: _buffer is module-level and shared across all calls within
12
+ // a process. The auto-loop must call _resetLogs() (or drainAndSummarize()) at
13
+ // the start of each unit to prevent log bleed between units running in the same
14
+ // Node process.
15
+ // ─── Buffer ─────────────────────────────────────────────────────────────
16
+ const MAX_BUFFER = 100;
17
+ let _buffer = [];
18
+ // ─── Public API ─────────────────────────────────────────────────────────
19
+ /**
20
+ * Record a warning. Also writes to stderr for terminal visibility.
21
+ */
22
+ export function logWarning(component, message, context) {
23
+ _push("warn", component, message, context);
24
+ }
25
+ /**
26
+ * Record an error. Also writes to stderr for terminal visibility.
27
+ */
28
+ export function logError(component, message, context) {
29
+ _push("error", component, message, context);
30
+ }
31
+ /**
32
+ * Drain all accumulated entries and clear the buffer.
33
+ * Returns entries oldest-first.
34
+ *
35
+ * WARNING: Call summarizeLogs() or drainAndSummarize() BEFORE calling this
36
+ * if you need a summary — drainLogs() clears the buffer immediately.
37
+ */
38
+ export function drainLogs() {
39
+ const entries = _buffer;
40
+ _buffer = [];
41
+ return entries;
42
+ }
43
+ /**
44
+ * Atomically summarize then drain — the safe way to consume logs.
45
+ * Use this in the auto-loop instead of calling summarizeLogs() + drainLogs()
46
+ * separately to avoid the ordering footgun.
47
+ */
48
+ export function drainAndSummarize() {
49
+ const summary = summarizeLogs();
50
+ const logs = drainLogs();
51
+ return { logs, summary };
52
+ }
53
+ /**
54
+ * Peek at current entries without clearing.
55
+ */
56
+ export function peekLogs() {
57
+ return _buffer;
58
+ }
59
+ /**
60
+ * Returns true if the buffer contains any error-severity entries.
61
+ */
62
+ export function hasErrors() {
63
+ return _buffer.some((e) => e.severity === "error");
64
+ }
65
+ /**
66
+ * Returns true if the buffer contains any warn-severity entries.
67
+ * Use hasAnyIssues() if you want to check for either severity.
68
+ */
69
+ export function hasWarnings() {
70
+ return _buffer.some((e) => e.severity === "warn");
71
+ }
72
+ /**
73
+ * Returns true if the buffer contains any entries (warn or error).
74
+ */
75
+ export function hasAnyIssues() {
76
+ return _buffer.length > 0;
77
+ }
78
+ /**
79
+ * Get a one-line summary of accumulated issues for stuck detection messages.
80
+ * Returns null if no entries.
81
+ *
82
+ * Must be called BEFORE drainLogs() — use drainAndSummarize() for safe ordering.
83
+ */
84
+ export function summarizeLogs() {
85
+ if (_buffer.length === 0)
86
+ return null;
87
+ const errors = _buffer.filter((e) => e.severity === "error");
88
+ const warns = _buffer.filter((e) => e.severity === "warn");
89
+ const parts = [];
90
+ if (errors.length > 0) {
91
+ parts.push(`${errors.length} error(s): ${errors.map((e) => e.message).join("; ")}`);
92
+ }
93
+ if (warns.length > 0) {
94
+ parts.push(`${warns.length} warning(s): ${warns.map((e) => e.message).join("; ")}`);
95
+ }
96
+ return parts.join(" | ");
97
+ }
98
+ /**
99
+ * Format entries for display (used by auto-loop post-unit notification).
100
+ * Note: context fields are not included in the formatted output.
101
+ */
102
+ export function formatForNotification(entries) {
103
+ if (entries.length === 0)
104
+ return "";
105
+ if (entries.length === 1) {
106
+ const e = entries[0];
107
+ return `[${e.component}] ${e.message}`;
108
+ }
109
+ return entries
110
+ .map((e) => `[${e.component}] ${e.message}`)
111
+ .join("\n");
112
+ }
113
+ /**
114
+ * Reset buffer. Call at the start of each auto-loop unit to prevent log bleed
115
+ * between units running in the same process. Also used in tests via _resetLogs().
116
+ */
117
+ export function _resetLogs() {
118
+ _buffer = [];
119
+ }
120
+ // ─── Internal ───────────────────────────────────────────────────────────
121
+ function _push(severity, component, message, context) {
122
+ const entry = {
123
+ ts: new Date().toISOString(),
124
+ severity,
125
+ component,
126
+ message,
127
+ ...(context ? { context } : {}),
128
+ };
129
+ // Always forward to stderr so terminal watchers see it (see module header for policy)
130
+ const prefix = severity === "error" ? "ERROR" : "WARN";
131
+ const ctxStr = context ? ` ${JSON.stringify(context)}` : "";
132
+ process.stderr.write(`[gsd:${component}] ${prefix}: ${message}${ctxStr}\n`);
133
+ // Buffer for auto-loop to drain
134
+ _buffer.push(entry);
135
+ if (_buffer.length > MAX_BUFFER) {
136
+ _buffer.shift();
137
+ }
138
+ }
@@ -18,6 +18,7 @@ import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync } from "node:
18
18
  import { execFileSync } from "node:child_process";
19
19
  import { join, resolve, sep } from "node:path";
20
20
  import { GSDError, GSD_PARSE_ERROR, GSD_STALE_STATE, GSD_LOCK_HELD, GSD_GIT_ERROR, GSD_MERGE_CONFLICT } from "./errors.js";
21
+ import { logWarning } from "./workflow-logger.js";
21
22
  import { nativeBranchDelete, nativeBranchExists, nativeBranchForceReset, nativeCommit, nativeDetectMainBranch, nativeDiffContent, nativeDiffNameStatus, nativeDiffNumstat, nativeGetCurrentBranch, nativeLogOneline, nativeMergeSquash, nativeWorktreeAdd, nativeWorktreeList, nativeWorktreePrune, nativeWorktreeRemove, } from "./native-git-bridge.js";
22
23
  // ─── Path Helpers ──────────────────────────────────────────────────────────
23
24
  function normalizePathForComparison(path) {
@@ -85,7 +86,7 @@ export function createWorktree(basePath, name, opts = {}) {
85
86
  // worktree can be created in its place.
86
87
  const gitFilePath = join(wtPath, ".git");
87
88
  if (!existsSync(gitFilePath)) {
88
- console.error(`[GSD] Removing stale worktree directory (no .git file): ${wtPath}`);
89
+ logWarning("reconcile", `Removing stale worktree directory (no .git file): ${wtPath}`, { worktree: name });
89
90
  rmSync(wtPath, { recursive: true, force: true });
90
91
  }
91
92
  else {
@@ -256,11 +257,11 @@ export function removeWorktree(basePath, name, opts = {}) {
256
257
  // The stash is created in the worktree before it's torn down.
257
258
  try {
258
259
  execFileSync("git", ["stash", "push", "-m", "gsd: auto-stash submodule changes before worktree teardown"], { cwd: resolvedWtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
259
- process.stderr.write(`[GSD] WARNING: Stashed uncommitted submodule changes in ${resolvedWtPath} before worktree teardown.\n`);
260
+ logWarning("reconcile", `Stashed uncommitted submodule changes before worktree teardown`, { worktree: name, path: resolvedWtPath });
260
261
  }
261
262
  catch {
262
263
  // Stash failed — warn the user that submodule changes may be lost
263
- process.stderr.write(`[GSD] WARNING: Submodule changes detected in ${resolvedWtPath} — stash failed, changes may be lost during force removal.\n`);
264
+ logWarning("reconcile", `Submodule changes detected — stash failed, changes may be lost during force removal`, { worktree: name, path: resolvedWtPath });
264
265
  }
265
266
  }
266
267
  }
@@ -13,9 +13,11 @@
13
13
  * `process.chdir()` internally — this class MUST NOT double-chdir.
14
14
  */
15
15
  import { existsSync, unlinkSync } from "node:fs";
16
+ import { randomUUID } from "node:crypto";
16
17
  import { join } from "node:path";
17
18
  import { debugLog } from "./debug-logger.js";
18
19
  import { MergeConflictError } from "./git-service.js";
20
+ import { emitJournalEvent } from "./journal.js";
19
21
  // ─── WorktreeResolver ──────────────────────────────────────────────────────
20
22
  export class WorktreeResolver {
21
23
  s;
@@ -77,6 +79,13 @@ export class WorktreeResolver {
77
79
  skipped: true,
78
80
  reason: "isolation-disabled",
79
81
  });
82
+ emitJournalEvent(this.s.originalBasePath || this.s.basePath, {
83
+ ts: new Date().toISOString(),
84
+ flowId: randomUUID(),
85
+ seq: 0,
86
+ eventType: "worktree-skip",
87
+ data: { milestoneId, reason: "isolation-disabled" },
88
+ });
80
89
  return;
81
90
  }
82
91
  const basePath = this.s.originalBasePath || this.s.basePath;
@@ -102,6 +111,13 @@ export class WorktreeResolver {
102
111
  result: "success",
103
112
  wtPath,
104
113
  });
114
+ emitJournalEvent(this.s.originalBasePath || this.s.basePath, {
115
+ ts: new Date().toISOString(),
116
+ flowId: randomUUID(),
117
+ seq: 0,
118
+ eventType: "worktree-enter",
119
+ data: { milestoneId, wtPath, created: !existingPath },
120
+ });
105
121
  ctx.notify(`Entered worktree for ${milestoneId} at ${wtPath}`, "info");
106
122
  }
107
123
  catch (err) {
@@ -112,6 +128,13 @@ export class WorktreeResolver {
112
128
  result: "error",
113
129
  error: msg,
114
130
  });
131
+ emitJournalEvent(this.s.originalBasePath || this.s.basePath, {
132
+ ts: new Date().toISOString(),
133
+ flowId: randomUUID(),
134
+ seq: 0,
135
+ eventType: "worktree-create-failed",
136
+ data: { milestoneId, error: msg, fallback: "project-root" },
137
+ });
115
138
  ctx.notify(`Auto-worktree creation for ${milestoneId} failed: ${msg}. Continuing in project root.`, "warning");
116
139
  // Do NOT update s.basePath — stay in project root
117
140
  }
@@ -194,6 +217,13 @@ export class WorktreeResolver {
194
217
  mode,
195
218
  basePath: this.s.basePath,
196
219
  });
220
+ emitJournalEvent(this.s.originalBasePath || this.s.basePath, {
221
+ ts: new Date().toISOString(),
222
+ flowId: randomUUID(),
223
+ seq: 0,
224
+ eventType: "worktree-merge-start",
225
+ data: { milestoneId, mode },
226
+ });
197
227
  if (mode === "none") {
198
228
  debugLog("WorktreeResolver", {
199
229
  action: "mergeAndExit",
@@ -285,6 +315,13 @@ export class WorktreeResolver {
285
315
  error: msg,
286
316
  fallback: "chdir-to-project-root",
287
317
  });
318
+ emitJournalEvent(this.s.originalBasePath || this.s.basePath, {
319
+ ts: new Date().toISOString(),
320
+ flowId: randomUUID(),
321
+ seq: 0,
322
+ eventType: "worktree-merge-failed",
323
+ data: { milestoneId, error: msg },
324
+ });
288
325
  // Surface a clear, actionable error. The worktree and milestone branch are
289
326
  // intentionally preserved — nothing has been deleted. The user can retry
290
327
  // /gsd dispatch complete-milestone or merge manually once the underlying issue is fixed
@@ -2,22 +2,15 @@ import { shortcutDesc } from "../shared/mod.js";
2
2
  import { isKeyRelease, Key, matchesKey, truncateToWidth, visibleWidth } from "@gsd/pi-tui";
3
3
  import { spawn, execFileSync } from "node:child_process";
4
4
  import * as fs from "node:fs";
5
- import * as os from "node:os";
6
5
  import * as path from "node:path";
7
6
  import * as readline from "node:readline";
7
+ import { linuxPython, diagnoseSounddeviceError, ensureVoiceVenv } from "./linux-ready.js";
8
8
  const __extensionDir = import.meta.dirname;
9
9
  const SWIFT_SRC = path.join(__extensionDir, "speech-recognizer.swift");
10
10
  const RECOGNIZER_BIN = path.join(__extensionDir, "speech-recognizer");
11
11
  const PYTHON_SCRIPT = path.join(__extensionDir, "speech-recognizer.py");
12
12
  const IS_DARWIN = process.platform === "darwin";
13
13
  const IS_LINUX = process.platform === "linux";
14
- const VOICE_VENV_PYTHON = path.join(process.env.HOME || process.env.USERPROFILE || os.homedir(), ".gsd", "voice-venv", "bin", "python3");
15
- /** Return the python3 binary path — prefer venv if it exists, else system. */
16
- function linuxPython() {
17
- if (fs.existsSync(VOICE_VENV_PYTHON))
18
- return VOICE_VENV_PYTHON;
19
- return "python3";
20
- }
21
14
  function ensureBinary() {
22
15
  if (fs.existsSync(RECOGNIZER_BIN))
23
16
  return true;
@@ -58,19 +51,21 @@ function ensureLinuxReady(ctx) {
58
51
  }
59
52
  catch (err) {
60
53
  const stderr = err?.stderr?.toString() ?? "";
61
- if (stderr.includes("sounddevice") || stderr.includes("PortAudio") || stderr.includes("portaudio")) {
62
- ctx.ui.notify("Voice: install libportaudio2 with: sudo apt install libportaudio2", "error");
63
- }
64
- else if (stderr.includes("No module") || stderr.includes("ModuleNotFoundError")) {
65
- // Deps missing the Python script handles auto-install on first run,
66
- // so we let it through. The script's own ensure_deps() will pip install.
67
- ctx.ui.notify("Voice: installing dependencies on first run — this may take a moment", "info");
54
+ const diagnosis = diagnoseSounddeviceError(stderr);
55
+ if (diagnosis === "missing-module") {
56
+ // Module not installed — auto-create venv (handles PEP 668 systems
57
+ // where system pip is blocked). See #2403.
58
+ if (!ensureVoiceVenv({ notify: (msg, level) => ctx.ui.notify(msg, level) })) {
59
+ return false;
60
+ }
68
61
  linuxReady = true;
69
62
  return true;
70
63
  }
64
+ else if (diagnosis === "missing-portaudio") {
65
+ ctx.ui.notify("Voice: install libportaudio2 with: sudo apt install libportaudio2", "error");
66
+ }
71
67
  else {
72
68
  ctx.ui.notify(`Voice: dependency check failed — ${stderr.split("\n")[0] || "unknown error"}`, "error");
73
- return false;
74
69
  }
75
70
  return false;
76
71
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * linux-ready.ts — Linux voice readiness logic (extracted for testability).
3
+ *
4
+ * Handles:
5
+ * - Detecting system vs venv python3
6
+ * - Diagnosing sounddevice import errors (portaudio vs missing module)
7
+ * - Auto-creating venv on PEP 668 systems
8
+ */
9
+ import { execFileSync } from "node:child_process";
10
+ import * as fs from "node:fs";
11
+ import * as os from "node:os";
12
+ import * as path from "node:path";
13
+ export const VOICE_VENV_DIR = path.join(process.env.HOME || process.env.USERPROFILE || os.homedir(), ".gsd", "voice-venv");
14
+ export const VOICE_VENV_PYTHON = path.join(VOICE_VENV_DIR, "bin", "python3");
15
+ /** Return the python3 binary path — prefer venv if it exists, else system. */
16
+ export function linuxPython() {
17
+ if (fs.existsSync(VOICE_VENV_PYTHON))
18
+ return VOICE_VENV_PYTHON;
19
+ return "python3";
20
+ }
21
+ /**
22
+ * Diagnose a sounddevice import error from its stderr output.
23
+ *
24
+ * Returns:
25
+ * - "missing-module" — sounddevice python package not installed
26
+ * - "missing-portaudio" — libportaudio2 native library not found
27
+ * - "unknown" — unrecognized error
28
+ *
29
+ * IMPORTANT: Check "No module" / "ModuleNotFoundError" BEFORE checking for the
30
+ * word "sounddevice", because `ModuleNotFoundError: No module named 'sounddevice'`
31
+ * contains both strings. The more specific check must come first.
32
+ */
33
+ export function diagnoseSounddeviceError(stderr) {
34
+ // Check for missing Python module FIRST — the error message
35
+ // "ModuleNotFoundError: No module named 'sounddevice'" contains the word
36
+ // "sounddevice", so the old order (checking "sounddevice" first) was wrong.
37
+ if (stderr.includes("No module") || stderr.includes("ModuleNotFoundError")) {
38
+ return "missing-module";
39
+ }
40
+ // Now check for native portaudio library issues.
41
+ if (stderr.includes("PortAudio") || stderr.includes("portaudio")) {
42
+ return "missing-portaudio";
43
+ }
44
+ return "unknown";
45
+ }
46
+ /**
47
+ * Auto-create the voice venv if it doesn't exist.
48
+ * Uses execFileSync internally (no shell, safe from injection).
49
+ *
50
+ * Returns true on success, false on failure.
51
+ */
52
+ export function ensureVoiceVenv(cb) {
53
+ const exists = cb.exists ?? fs.existsSync;
54
+ const execFile = cb.execFile ?? execFileSync;
55
+ if (exists(VOICE_VENV_PYTHON))
56
+ return true;
57
+ cb.notify("Voice: setting up Python environment — one-time setup", "info");
58
+ try {
59
+ execFile("python3", ["-m", "venv", VOICE_VENV_DIR], { timeout: 30000 });
60
+ execFile(path.join(VOICE_VENV_DIR, "bin", "pip"), ["install", "sounddevice", "requests", "--quiet"], { timeout: 120000 });
61
+ return true;
62
+ }
63
+ catch {
64
+ cb.notify("Voice: failed to create Python venv — run: python3 -m venv ~/.gsd/voice-venv", "error");
65
+ return false;
66
+ }
67
+ }
@@ -1 +1 @@
1
- rzO54ZboyINyEt7cVM_uS
1
+ zWYDSwB-terOjfhmWzqk1
@@ -1,45 +1,45 @@
1
1
  {
2
- "/_not-found/page": "/_not-found",
3
2
  "/_global-error/page": "/_global-error",
3
+ "/_not-found/page": "/_not-found",
4
+ "/api/bridge-terminal/resize/route": "/api/bridge-terminal/resize",
4
5
  "/api/bridge-terminal/input/route": "/api/bridge-terminal/input",
5
6
  "/api/boot/route": "/api/boot",
6
- "/api/bridge-terminal/resize/route": "/api/bridge-terminal/resize",
7
- "/api/bridge-terminal/stream/route": "/api/bridge-terminal/stream",
8
- "/api/cleanup/route": "/api/cleanup",
9
7
  "/api/dev-mode/route": "/api/dev-mode",
10
- "/api/export-data/route": "/api/export-data",
11
8
  "/api/browse-directories/route": "/api/browse-directories",
12
- "/api/doctor/route": "/api/doctor",
13
- "/api/captures/route": "/api/captures",
9
+ "/api/export-data/route": "/api/export-data",
10
+ "/api/cleanup/route": "/api/cleanup",
14
11
  "/api/forensics/route": "/api/forensics",
12
+ "/api/doctor/route": "/api/doctor",
15
13
  "/api/git/route": "/api/git",
16
14
  "/api/history/route": "/api/history",
17
- "/api/inspect/route": "/api/inspect",
15
+ "/api/bridge-terminal/stream/route": "/api/bridge-terminal/stream",
18
16
  "/api/hooks/route": "/api/hooks",
19
- "/api/knowledge/route": "/api/knowledge",
17
+ "/api/inspect/route": "/api/inspect",
20
18
  "/api/live-state/route": "/api/live-state",
21
19
  "/api/preferences/route": "/api/preferences",
22
- "/api/recovery/route": "/api/recovery",
20
+ "/api/projects/route": "/api/projects",
23
21
  "/api/onboarding/route": "/api/onboarding",
22
+ "/api/recovery/route": "/api/recovery",
23
+ "/api/captures/route": "/api/captures",
24
24
  "/api/session/browser/route": "/api/session/browser",
25
- "/api/projects/route": "/api/projects",
26
25
  "/api/session/command/route": "/api/session/command",
26
+ "/api/session/events/route": "/api/session/events",
27
27
  "/api/session/manage/route": "/api/session/manage",
28
- "/api/settings-data/route": "/api/settings-data",
29
28
  "/api/shutdown/route": "/api/shutdown",
29
+ "/api/settings-data/route": "/api/settings-data",
30
+ "/api/knowledge/route": "/api/knowledge",
30
31
  "/api/skill-health/route": "/api/skill-health",
31
- "/api/session/events/route": "/api/session/events",
32
32
  "/api/steer/route": "/api/steer",
33
+ "/api/files/route": "/api/files",
33
34
  "/api/terminal/input/route": "/api/terminal/input",
34
35
  "/api/switch-root/route": "/api/switch-root",
35
36
  "/api/terminal/resize/route": "/api/terminal/resize",
36
- "/api/files/route": "/api/files",
37
- "/api/terminal/sessions/route": "/api/terminal/sessions",
38
37
  "/api/terminal/stream/route": "/api/terminal/stream",
39
- "/api/undo/route": "/api/undo",
38
+ "/api/terminal/sessions/route": "/api/terminal/sessions",
40
39
  "/api/terminal/upload/route": "/api/terminal/upload",
40
+ "/api/undo/route": "/api/undo",
41
+ "/api/update/route": "/api/update",
41
42
  "/api/remote-questions/route": "/api/remote-questions",
42
43
  "/api/visualizer/route": "/api/visualizer",
43
- "/api/update/route": "/api/update",
44
44
  "/page": "/"
45
45
  }
@@ -4,8 +4,8 @@
4
4
  ],
5
5
  "devFiles": [],
6
6
  "lowPriorityFiles": [
7
- "static/rzO54ZboyINyEt7cVM_uS/_buildManifest.js",
8
- "static/rzO54ZboyINyEt7cVM_uS/_ssgManifest.js"
7
+ "static/zWYDSwB-terOjfhmWzqk1/_buildManifest.js",
8
+ "static/zWYDSwB-terOjfhmWzqk1/_ssgManifest.js"
9
9
  ],
10
10
  "rootMainFiles": [
11
11
  "static/chunks/webpack-0a4cd455ec4197d2.js",
@@ -78,8 +78,8 @@
78
78
  "dynamicRoutes": {},
79
79
  "notFoundRoutes": [],
80
80
  "preview": {
81
- "previewModeId": "a845a1e886ac7dc38e65f6eefa1b2f8f",
82
- "previewModeSigningKey": "c433c6b7a91507cf44cccb0d458e6ca0a103bc9fdd7abdac091d99ed96e7bb5e",
83
- "previewModeEncryptionKey": "8749e82dbeed7929b97f869099dd340f7392acc2573cc0dea7ec2c8d25ca44ee"
81
+ "previewModeId": "cf4d5d78c74a67ed917c9171afd61d0b",
82
+ "previewModeSigningKey": "fc306d9119bb4c07ab2d3b214cfcdf8dc6524f3fcf803567b3ab7958fcf13057",
83
+ "previewModeEncryptionKey": "e3207cb64939ad76e542dfc07ac0d2bce48e0f4c04b9cf9db4e9ff0994b68c20"
84
84
  }
85
85
  }
@@ -1,2 +1,2 @@
1
- <!DOCTYPE html><!--rzO54ZboyINyEt7cVM_uS--><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-0a4cd455ec4197d2.js"/><script src="/_next/static/chunks/4bd1b696-e5d7c65570c947b7.js" async=""></script><script src="/_next/static/chunks/3794-337d1ca25ad99a89.js" async=""></script><script src="/_next/static/chunks/main-app-fdab67f7802d7832.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: Internal Server Error.</title><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}
2
- @media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-0a4cd455ec4197d2.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[57121,[],\"\"]\n3:I[74581,[],\"\"]\n4:I[90484,[],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n7:I[90484,[],\"ViewportBoundary\"]\n9:I[90484,[],\"MetadataBoundary\"]\nb:I[27123,[],\"\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"rzO54ZboyINyEt7cVM_uS\",\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"_global-error\",{\"children\":[\"__PAGE__\",{}]}]}],[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"title\",null,{\"children\":\"500: Internal Server Error.\"}]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"lineHeight\":\"48px\"},\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"paddingRight\":23,\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\"},\"children\":\"500\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"28px\"},\"children\":\"Internal Server Error.\"}]}]]}]}]}]]}],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,false]},null,false,false]},null,false,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L7\",null,{\"children\":\"$L8\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$La\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$b\",[]],\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\na:[]\n"])</script></body></html>
1
+ <!DOCTYPE html><!--zWYDSwB_terOjfhmWzqk1--><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-0a4cd455ec4197d2.js"/><script src="/_next/static/chunks/4bd1b696-e5d7c65570c947b7.js" async=""></script><script src="/_next/static/chunks/3794-337d1ca25ad99a89.js" async=""></script><script src="/_next/static/chunks/main-app-fdab67f7802d7832.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: Internal Server Error.</title><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}
2
+ @media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-0a4cd455ec4197d2.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[57121,[],\"\"]\n3:I[74581,[],\"\"]\n4:I[90484,[],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n7:I[90484,[],\"ViewportBoundary\"]\n9:I[90484,[],\"MetadataBoundary\"]\nb:I[27123,[],\"\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"zWYDSwB-terOjfhmWzqk1\",\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"_global-error\",{\"children\":[\"__PAGE__\",{}]}]}],[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"title\",null,{\"children\":\"500: Internal Server Error.\"}]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"lineHeight\":\"48px\"},\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"paddingRight\":23,\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\"},\"children\":\"500\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"28px\"},\"children\":\"Internal Server Error.\"}]}]]}]}]}]]}],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,false]},null,false,false]},null,false,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L7\",null,{\"children\":\"$L8\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$La\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$b\",[]],\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\na:[]\n"])</script></body></html>
@@ -6,7 +6,7 @@
6
6
  7:I[90484,[],"ViewportBoundary"]
7
7
  9:I[90484,[],"MetadataBoundary"]
8
8
  b:I[27123,[],""]
9
- 0:{"P":null,"b":"rzO54ZboyINyEt7cVM_uS","c":["","_global-error"],"q":"","i":false,"f":[[["",{"children":["_global-error",{"children":["__PAGE__",{}]}]}],[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],null,["$","$L4",null,{"children":["$","$5",null,{"name":"Next.MetadataOutlet","children":"$@6"}]}]]}],{},null,false,false]},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$L7",null,{"children":"$L8"}],["$","div",null,{"hidden":true,"children":["$","$L9",null,{"children":["$","$5",null,{"name":"Next.Metadata","children":"$La"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$b",[]],"S":true}
9
+ 0:{"P":null,"b":"zWYDSwB-terOjfhmWzqk1","c":["","_global-error"],"q":"","i":false,"f":[[["",{"children":["_global-error",{"children":["__PAGE__",{}]}]}],[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],null,["$","$L4",null,{"children":["$","$5",null,{"name":"Next.MetadataOutlet","children":"$@6"}]}]]}],{},null,false,false]},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$L7",null,{"children":"$L8"}],["$","div",null,{"hidden":true,"children":["$","$L9",null,{"children":["$","$5",null,{"name":"Next.Metadata","children":"$La"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$b",[]],"S":true}
10
10
  8:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
11
11
  6:null
12
12
  a:[]
@@ -6,7 +6,7 @@
6
6
  7:I[90484,[],"ViewportBoundary"]
7
7
  9:I[90484,[],"MetadataBoundary"]
8
8
  b:I[27123,[],""]
9
- 0:{"P":null,"b":"rzO54ZboyINyEt7cVM_uS","c":["","_global-error"],"q":"","i":false,"f":[[["",{"children":["_global-error",{"children":["__PAGE__",{}]}]}],[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],null,["$","$L4",null,{"children":["$","$5",null,{"name":"Next.MetadataOutlet","children":"$@6"}]}]]}],{},null,false,false]},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$L7",null,{"children":"$L8"}],["$","div",null,{"hidden":true,"children":["$","$L9",null,{"children":["$","$5",null,{"name":"Next.Metadata","children":"$La"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$b",[]],"S":true}
9
+ 0:{"P":null,"b":"zWYDSwB-terOjfhmWzqk1","c":["","_global-error"],"q":"","i":false,"f":[[["",{"children":["_global-error",{"children":["__PAGE__",{}]}]}],[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],null,["$","$L4",null,{"children":["$","$5",null,{"name":"Next.MetadataOutlet","children":"$@6"}]}]]}],{},null,false,false]},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$L7",null,{"children":"$L8"}],["$","div",null,{"hidden":true,"children":["$","$L9",null,{"children":["$","$5",null,{"name":"Next.Metadata","children":"$La"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$b",[]],"S":true}
10
10
  8:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
11
11
  6:null
12
12
  a:[]
@@ -1,5 +1,5 @@
1
1
  1:"$Sreact.fragment"
2
2
  2:I[90484,[],"OutletBoundary"]
3
3
  3:"$Sreact.suspense"
4
- 0:{"buildId":"rzO54ZboyINyEt7cVM_uS","rsc":["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],null,["$","$L2",null,{"children":["$","$3",null,{"name":"Next.MetadataOutlet","children":"$@4"}]}]]}],"loading":null,"isPartial":false}
4
+ 0:{"buildId":"zWYDSwB-terOjfhmWzqk1","rsc":["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],null,["$","$L2",null,{"children":["$","$3",null,{"name":"Next.MetadataOutlet","children":"$@4"}]}]]}],"loading":null,"isPartial":false}
5
5
  4:null
@@ -1,4 +1,4 @@
1
1
  1:"$Sreact.fragment"
2
2
  2:I[57121,[],""]
3
3
  3:I[74581,[],""]
4
- 0:{"buildId":"rzO54ZboyINyEt7cVM_uS","rsc":["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}]}]]}],"loading":null,"isPartial":false}
4
+ 0:{"buildId":"zWYDSwB-terOjfhmWzqk1","rsc":["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}]}]]}],"loading":null,"isPartial":false}
@@ -2,4 +2,4 @@
2
2
  2:I[90484,[],"ViewportBoundary"]
3
3
  3:I[90484,[],"MetadataBoundary"]
4
4
  4:"$Sreact.suspense"
5
- 0:{"buildId":"rzO54ZboyINyEt7cVM_uS","rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false}
5
+ 0:{"buildId":"zWYDSwB-terOjfhmWzqk1","rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false}
@@ -1,4 +1,4 @@
1
1
  1:"$Sreact.fragment"
2
2
  2:I[57121,[],""]
3
3
  3:I[74581,[],""]
4
- 0:{"buildId":"rzO54ZboyINyEt7cVM_uS","rsc":["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}]}]]}],"loading":null,"isPartial":false}
4
+ 0:{"buildId":"zWYDSwB-terOjfhmWzqk1","rsc":["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}]}]]}],"loading":null,"isPartial":false}
@@ -1 +1 @@
1
- 0:{"buildId":"rzO54ZboyINyEt7cVM_uS","tree":{"name":"","paramType":null,"paramKey":"","hasRuntimePrefetch":false,"slots":{"children":{"name":"_global-error","paramType":null,"paramKey":"_global-error","hasRuntimePrefetch":false,"slots":{"children":{"name":"__PAGE__","paramType":null,"paramKey":"__PAGE__","hasRuntimePrefetch":false,"slots":null,"isRootLayout":false}},"isRootLayout":false}},"isRootLayout":false},"staleTime":300}
1
+ 0:{"buildId":"zWYDSwB-terOjfhmWzqk1","tree":{"name":"","paramType":null,"paramKey":"","hasRuntimePrefetch":false,"slots":{"children":{"name":"_global-error","paramType":null,"paramKey":"_global-error","hasRuntimePrefetch":false,"slots":{"children":{"name":"__PAGE__","paramType":null,"paramKey":"__PAGE__","hasRuntimePrefetch":false,"slots":null,"isRootLayout":false}},"isRootLayout":false}},"isRootLayout":false},"staleTime":300}