gsd-pi 2.73.1-dev.d987996 → 2.74.0-dev.2b524c3
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/dist/cli-web-branch.d.ts +4 -3
- package/dist/cli-web-branch.js +10 -7
- package/dist/cli.js +99 -206
- package/dist/logo.d.ts +1 -1
- package/dist/logo.js +1 -1
- package/dist/onboarding.js +59 -53
- package/dist/resource-loader.js +2 -2
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +68 -4
- package/dist/resources/extensions/gsd/auto/phases.js +15 -9
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +54 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +41 -1
- package/dist/resources/extensions/gsd/auto-start.js +23 -6
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
- package/dist/resources/extensions/gsd/auto-verification.js +88 -3
- package/dist/resources/extensions/gsd/auto.js +29 -8
- package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/notification-widget.js +2 -2
- package/dist/resources/extensions/gsd/preferences-models.js +43 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +22 -0
- package/dist/resources/extensions/gsd/state.js +61 -14
- package/dist/update-check.d.ts +1 -0
- package/dist/update-check.js +13 -5
- package/dist/update-cmd.js +4 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -2
- package/packages/pi-ai/dist/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.js +12 -0
- package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
- package/packages/pi-ai/src/index.ts +4 -0
- package/packages/pi-ai/src/utils/overflow.ts +14 -1
- package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +313 -8
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
- package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +61 -28
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +9 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +94 -16
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +11 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +355 -8
- package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
- package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +74 -32
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +113 -21
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +11 -3
- package/packages/pi-tui/dist/__tests__/tui.test.js +60 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +8 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +32 -3
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
- package/packages/pi-tui/src/tui.ts +31 -3
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +107 -5
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +111 -2
- package/src/resources/extensions/gsd/auto/phases.ts +22 -9
- package/src/resources/extensions/gsd/auto-dispatch.ts +10 -4
- package/src/resources/extensions/gsd/auto-model-selection.ts +85 -11
- package/src/resources/extensions/gsd/auto-post-unit.ts +47 -1
- package/src/resources/extensions/gsd/auto-start.ts +30 -6
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
- package/src/resources/extensions/gsd/auto-verification.ts +98 -3
- package/src/resources/extensions/gsd/auto.ts +31 -14
- package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/notification-widget.ts +2 -2
- package/src/resources/extensions/gsd/preferences-models.ts +41 -0
- package/src/resources/extensions/gsd/preferences-types.ts +12 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +23 -0
- package/src/resources/extensions/gsd/state.ts +71 -15
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
- /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → YzIEI9sxJy4t5xgClF08g}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → YzIEI9sxJy4t5xgClF08g}/_ssgManifest.js +0 -0
|
@@ -55,7 +55,7 @@ import { initRegistry, convertDispatchRules } from "./rule-registry.js";
|
|
|
55
55
|
import { emitJournalEvent as _emitJournalEvent } from "./journal.js";
|
|
56
56
|
import { updateProgressWidget as _updateProgressWidget, updateSliceProgressCache, clearSliceProgressCache, hideFooter, } from "./auto-dashboard.js";
|
|
57
57
|
import { registerSigtermHandler as _registerSigtermHandler, deregisterSigtermHandler as _deregisterSigtermHandler, } from "./auto-supervisor.js";
|
|
58
|
-
import { isDbAvailable } from "./gsd-db.js";
|
|
58
|
+
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
59
59
|
import { countPendingCaptures } from "./captures.js";
|
|
60
60
|
import { clearCmuxSidebar, logCmuxEvent, syncCmuxSidebar } from "../cmux/index.js";
|
|
61
61
|
// ── Extracted modules ──────────────────────────────────────────────────────
|
|
@@ -63,6 +63,7 @@ import { startUnitSupervision } from "./auto-timers.js";
|
|
|
63
63
|
import { runPostUnitVerification } from "./auto-verification.js";
|
|
64
64
|
import { postUnitPreVerification, postUnitPostVerification, } from "./auto-post-unit.js";
|
|
65
65
|
import { bootstrapAutoSession, openProjectDbIfPresent } from "./auto-start.js";
|
|
66
|
+
import { initHealthWidget } from "./health-widget.js";
|
|
66
67
|
import { autoLoop, resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight } from "./auto-loop.js";
|
|
67
68
|
import { WorktreeResolver, } from "./worktree-resolver.js";
|
|
68
69
|
import { reorderForCaching } from "./prompt-ordering.js";
|
|
@@ -397,6 +398,8 @@ function handleLostSessionLock(ctx, lockStatus) {
|
|
|
397
398
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
398
399
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
399
400
|
ctx?.ui.setFooter(undefined);
|
|
401
|
+
if (ctx)
|
|
402
|
+
initHealthWidget(ctx);
|
|
400
403
|
}
|
|
401
404
|
/**
|
|
402
405
|
* Lightweight cleanup after autoLoop exits via step-wizard break.
|
|
@@ -431,6 +434,7 @@ function cleanupAfterLoopExit(ctx) {
|
|
|
431
434
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
432
435
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
433
436
|
ctx.ui.setFooter(undefined);
|
|
437
|
+
initHealthWidget(ctx);
|
|
434
438
|
}
|
|
435
439
|
// Restore CWD out of worktree back to original project root
|
|
436
440
|
if (s.originalBasePath) {
|
|
@@ -501,17 +505,30 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
501
505
|
? { notify: ctx.ui.notify.bind(ctx.ui) }
|
|
502
506
|
: { notify: () => { } };
|
|
503
507
|
const resolver = buildResolver();
|
|
504
|
-
// Check if the milestone is complete
|
|
508
|
+
// Check if the milestone is complete. DB status is the authoritative
|
|
509
|
+
// signal — only a successful gsd_complete_milestone call flips it to
|
|
510
|
+
// "complete" (tools/complete-milestone.ts). SUMMARY file presence is
|
|
511
|
+
// NOT sufficient: a blocker placeholder stub or a partial write can
|
|
512
|
+
// leave a file behind without the milestone actually being done,
|
|
513
|
+
// which previously caused stopAuto to merge a failed milestone and
|
|
514
|
+
// emit a misleading metadata-only merge warning (#4175).
|
|
515
|
+
// DB-unavailable projects fall back to SUMMARY-file presence.
|
|
505
516
|
let milestoneComplete = false;
|
|
506
517
|
try {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const wtSummaryPath = resolveMilestoneFile(s.basePath, s.currentMilestoneId, "SUMMARY");
|
|
511
|
-
milestoneComplete = wtSummaryPath !== null;
|
|
518
|
+
if (isDbAvailable()) {
|
|
519
|
+
const dbRow = getMilestone(s.currentMilestoneId);
|
|
520
|
+
milestoneComplete = dbRow?.status === "complete";
|
|
512
521
|
}
|
|
513
522
|
else {
|
|
514
|
-
|
|
523
|
+
const summaryPath = resolveMilestoneFile(s.originalBasePath || s.basePath, s.currentMilestoneId, "SUMMARY");
|
|
524
|
+
if (!summaryPath) {
|
|
525
|
+
// Also check in the worktree path (SUMMARY may not be synced yet)
|
|
526
|
+
const wtSummaryPath = resolveMilestoneFile(s.basePath, s.currentMilestoneId, "SUMMARY");
|
|
527
|
+
milestoneComplete = wtSummaryPath !== null;
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
milestoneComplete = true;
|
|
531
|
+
}
|
|
515
532
|
}
|
|
516
533
|
}
|
|
517
534
|
catch (err) {
|
|
@@ -676,6 +693,8 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
676
693
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
677
694
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
678
695
|
ctx?.ui.setFooter(undefined);
|
|
696
|
+
if (ctx)
|
|
697
|
+
initHealthWidget(ctx);
|
|
679
698
|
restoreProjectRootEnv();
|
|
680
699
|
restoreMilestoneLockEnv();
|
|
681
700
|
// Reset all session state in one call
|
|
@@ -762,6 +781,8 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
|
|
|
762
781
|
ctx?.ui.setStatus("gsd-auto", "paused");
|
|
763
782
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
764
783
|
ctx?.ui.setFooter(undefined);
|
|
784
|
+
if (ctx)
|
|
785
|
+
initHealthWidget(ctx);
|
|
765
786
|
const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
|
|
766
787
|
ctx?.ui.notify(`${s.stepMode ? "Step" : "Auto"}-mode paused (Escape). Type to interact, or ${resumeCmd} to resume.`, "info");
|
|
767
788
|
}
|
|
@@ -17,6 +17,11 @@ import { projectRoot } from "./commands/context.js";
|
|
|
17
17
|
import { loadPrompt } from "./prompt-loader.js";
|
|
18
18
|
const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/gsd-pi/latest";
|
|
19
19
|
const UPDATE_FETCH_TIMEOUT_MS = 5000;
|
|
20
|
+
function resolveInstallCommand(pkg) {
|
|
21
|
+
if ('bun' in process.versions)
|
|
22
|
+
return `bun add -g ${pkg}`;
|
|
23
|
+
return `npm install -g ${pkg}`;
|
|
24
|
+
}
|
|
20
25
|
async function fetchLatestVersionForCommand() {
|
|
21
26
|
const controller = new AbortController();
|
|
22
27
|
const timeout = setTimeout(() => controller.abort(), UPDATE_FETCH_TIMEOUT_MS);
|
|
@@ -344,13 +349,14 @@ export async function handleUpdate(ctx) {
|
|
|
344
349
|
return;
|
|
345
350
|
}
|
|
346
351
|
ctx.ui.notify(`Updating: v${current} → v${latest}...`, "info");
|
|
352
|
+
const installCmd = resolveInstallCommand(`${NPM_PACKAGE}@latest`);
|
|
347
353
|
try {
|
|
348
|
-
execSync(
|
|
354
|
+
execSync(installCmd, {
|
|
349
355
|
stdio: ["ignore", "pipe", "ignore"],
|
|
350
356
|
});
|
|
351
357
|
ctx.ui.notify(`Updated to v${latest}. Restart your GSD session to use the new version.`, "info");
|
|
352
358
|
}
|
|
353
359
|
catch {
|
|
354
|
-
ctx.ui.notify(`Update failed. Try manually:
|
|
360
|
+
ctx.ui.notify(`Update failed. Try manually: ${installCmd}`, "error");
|
|
355
361
|
}
|
|
356
362
|
}
|
|
@@ -157,7 +157,7 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
|
|
|
157
157
|
|
|
158
158
|
- `phases`: fine-grained control over which phases run. Usually set by `token_profile`, but can be overridden. Keys:
|
|
159
159
|
- `skip_research`: boolean — skip milestone-level research. Default: `false`.
|
|
160
|
-
- `reassess_after_slice`: boolean — run roadmap reassessment after each completed slice. Default: `
|
|
160
|
+
- `reassess_after_slice`: boolean — run roadmap reassessment after each completed slice. Default: `true`.
|
|
161
161
|
- `skip_reassess`: boolean — force-disable roadmap reassessment even if `reassess_after_slice` is enabled. Default: `false`.
|
|
162
162
|
- `skip_slice_research`: boolean — skip per-slice research. Default: `false`.
|
|
163
163
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// GSD Extension — Notification Widget
|
|
2
2
|
// Always-on ambient widget rendered belowEditor showing unread count and
|
|
3
|
-
// the most recent notification message. Refreshes every
|
|
3
|
+
// the most recent notification message. Refreshes every 30 seconds.
|
|
4
4
|
// Widget key: "gsd-notifications", placement: "belowEditor"
|
|
5
5
|
import { getUnreadCount, onNotificationStoreChange } from "./notification-store.js";
|
|
6
6
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
@@ -12,7 +12,7 @@ export function buildNotificationWidgetLines() {
|
|
|
12
12
|
return [` 🔔 Notifications: ${unread} unread (${formattedShortcutPair("notifications")})`];
|
|
13
13
|
}
|
|
14
14
|
// ─── Widget init ────────────────────────────────────────────────────────
|
|
15
|
-
const REFRESH_INTERVAL_MS =
|
|
15
|
+
const REFRESH_INTERVAL_MS = 30_000;
|
|
16
16
|
/**
|
|
17
17
|
* Initialize the always-on notification widget (belowEditor).
|
|
18
18
|
* Call once from session_start after the notification store is initialized.
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* and dynamic routing configuration.
|
|
7
7
|
*/
|
|
8
8
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
9
11
|
import { defaultRoutingConfig } from "./model-router.js";
|
|
10
12
|
import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
11
13
|
/**
|
|
@@ -161,6 +163,47 @@ export function resolveDefaultSessionModel(sessionProvider) {
|
|
|
161
163
|
}
|
|
162
164
|
return undefined;
|
|
163
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Returns true if `provider` is defined as a custom provider in the user's
|
|
168
|
+
* `~/.gsd/agent/models.json` (Ollama, vLLM, LM Studio, OpenAI-compatible
|
|
169
|
+
* proxies, etc.).
|
|
170
|
+
*
|
|
171
|
+
* Used by auto-mode bootstrap to decide whether the session model
|
|
172
|
+
* (set via `/gsd model`) should override `PREFERENCES.md`. Custom providers
|
|
173
|
+
* are never reachable from `PREFERENCES.md` (which only knows built-in
|
|
174
|
+
* providers), so when the user has explicitly selected one, it must take
|
|
175
|
+
* priority — otherwise auto-mode tries to start the built-in provider from
|
|
176
|
+
* PREFERENCES.md and fails with "Not logged in · Please run /login" (#4122).
|
|
177
|
+
*
|
|
178
|
+
* Reads models.json directly with a lightweight JSON parse to avoid
|
|
179
|
+
* pulling in the full model-registry at this call site. Falls back to
|
|
180
|
+
* `~/.pi/agent/models.json` for parity with `resolveModelsJsonPath()`.
|
|
181
|
+
* Any read or parse error yields `false` (treat as not-custom) so a
|
|
182
|
+
* malformed models.json never breaks the session bootstrap.
|
|
183
|
+
*/
|
|
184
|
+
export function isCustomProvider(provider) {
|
|
185
|
+
if (!provider)
|
|
186
|
+
return false;
|
|
187
|
+
const candidates = [
|
|
188
|
+
join(homedir(), ".gsd", "agent", "models.json"),
|
|
189
|
+
join(homedir(), ".pi", "agent", "models.json"),
|
|
190
|
+
];
|
|
191
|
+
for (const path of candidates) {
|
|
192
|
+
if (!existsSync(path))
|
|
193
|
+
continue;
|
|
194
|
+
try {
|
|
195
|
+
const raw = readFileSync(path, "utf-8");
|
|
196
|
+
const parsed = JSON.parse(raw);
|
|
197
|
+
if (parsed?.providers && Object.prototype.hasOwnProperty.call(parsed.providers, provider)) {
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// Ignore — malformed models.json must not break bootstrap.
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
164
207
|
/**
|
|
165
208
|
* Determines the next fallback model to try when the current model fails.
|
|
166
209
|
* If the current model is not in the configured list, returns the primary model.
|
|
@@ -155,6 +155,28 @@ export function validatePreferences(preferences) {
|
|
|
155
155
|
errors.push(`search_provider must be one of: brave, tavily, ollama, native, auto`);
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
+
// ─── Flat-rate Providers ────────────────────────────────────────────
|
|
159
|
+
// User-declared flat-rate providers for dynamic routing suppression.
|
|
160
|
+
// Built-in providers (github-copilot, copilot, claude-code) and any
|
|
161
|
+
// externalCli provider are already auto-detected; this list layers on
|
|
162
|
+
// top for private subscription proxies and custom CLI wrappers.
|
|
163
|
+
if (preferences.flat_rate_providers !== undefined) {
|
|
164
|
+
if (Array.isArray(preferences.flat_rate_providers)) {
|
|
165
|
+
const allStrings = preferences.flat_rate_providers.every((item) => typeof item === "string");
|
|
166
|
+
if (allStrings) {
|
|
167
|
+
// Strip empty/whitespace-only entries to avoid false matches.
|
|
168
|
+
validated.flat_rate_providers = preferences.flat_rate_providers
|
|
169
|
+
.map((s) => s.trim())
|
|
170
|
+
.filter((s) => s.length > 0);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
errors.push("flat_rate_providers must be an array of strings");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
errors.push("flat_rate_providers must be an array of strings");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
158
180
|
// ─── Phase Skip Preferences ─────────────────────────────────────────
|
|
159
181
|
if (preferences.phases !== undefined) {
|
|
160
182
|
if (typeof preferences.phases === "object" && preferences.phases !== null) {
|
|
@@ -312,6 +312,10 @@ function reconcileDiskToDb(basePath) {
|
|
|
312
312
|
function buildCompletenessSet(basePath, milestones) {
|
|
313
313
|
const completeMilestoneIds = new Set();
|
|
314
314
|
const parkedMilestoneIds = new Set();
|
|
315
|
+
// DB-authoritative: a milestone is only "complete" when its DB row says so.
|
|
316
|
+
// SUMMARY-file presence is NOT a completion signal here — an orphan SUMMARY
|
|
317
|
+
// (crashed complete-milestone turn, partial merge, manual edit) must not
|
|
318
|
+
// flip derived state to complete and cascade into a false auto-merge (#4179).
|
|
315
319
|
for (const m of milestones) {
|
|
316
320
|
const parkedFile = resolveMilestoneFile(basePath, m.id, "PARKED");
|
|
317
321
|
if (parkedFile || m.status === 'parked') {
|
|
@@ -322,11 +326,6 @@ function buildCompletenessSet(basePath, milestones) {
|
|
|
322
326
|
completeMilestoneIds.add(m.id);
|
|
323
327
|
continue;
|
|
324
328
|
}
|
|
325
|
-
const summaryFile = resolveMilestoneFile(basePath, m.id, "SUMMARY");
|
|
326
|
-
if (summaryFile) {
|
|
327
|
-
completeMilestoneIds.add(m.id);
|
|
328
|
-
continue;
|
|
329
|
-
}
|
|
330
329
|
}
|
|
331
330
|
return { completeMilestoneIds, parkedMilestoneIds };
|
|
332
331
|
}
|
|
@@ -347,17 +346,22 @@ async function buildRegistryAndFindActive(basePath, milestones, completeMileston
|
|
|
347
346
|
if (isGhostMilestone(basePath, m.id))
|
|
348
347
|
continue;
|
|
349
348
|
}
|
|
350
|
-
|
|
351
|
-
|
|
349
|
+
// DB-authoritative completeness (#4179): only trust completeMilestoneIds,
|
|
350
|
+
// which is itself derived from DB status. SUMMARY-file presence alone must
|
|
351
|
+
// not imply completion. The summary file may still be consulted below as a
|
|
352
|
+
// title source for legitimately-complete milestones whose DB row has no title.
|
|
353
|
+
if (completeMilestoneIds.has(m.id)) {
|
|
352
354
|
let title = stripMilestonePrefix(m.title) || m.id;
|
|
353
|
-
if (
|
|
354
|
-
const
|
|
355
|
-
if (
|
|
356
|
-
|
|
355
|
+
if (!m.title) {
|
|
356
|
+
const summaryFile = resolveMilestoneFile(basePath, m.id, "SUMMARY");
|
|
357
|
+
if (summaryFile) {
|
|
358
|
+
const summaryContent = await loadFile(summaryFile);
|
|
359
|
+
if (summaryContent) {
|
|
360
|
+
title = parseSummary(summaryContent).title || m.id;
|
|
361
|
+
}
|
|
357
362
|
}
|
|
358
363
|
}
|
|
359
364
|
registry.push({ id: m.id, title, status: 'complete' });
|
|
360
|
-
completeMilestoneIds.add(m.id);
|
|
361
365
|
continue;
|
|
362
366
|
}
|
|
363
367
|
const allSlicesDone = slices.length > 0 && slices.every(s => isStatusDone(s.status));
|
|
@@ -391,7 +395,14 @@ async function buildRegistryAndFindActive(basePath, milestones, completeMileston
|
|
|
391
395
|
const validationFile = resolveMilestoneFile(basePath, m.id, "VALIDATION");
|
|
392
396
|
const validationContent = validationFile ? await loadFile(validationFile) : null;
|
|
393
397
|
const validationTerminal = validationContent ? isValidationTerminal(validationContent) : false;
|
|
394
|
-
|
|
398
|
+
// DB-authoritative (#4179): completeness is already decided by
|
|
399
|
+
// completeMilestoneIds above. If we reached this branch, the DB says
|
|
400
|
+
// the milestone is NOT complete — so any SUMMARY file on disk is an
|
|
401
|
+
// orphan (crashed complete-milestone, partial merge, manual edit) and
|
|
402
|
+
// must not short-circuit this path. When validation is terminal, fall
|
|
403
|
+
// through to the default active-push below so `complete-milestone` can
|
|
404
|
+
// re-run idempotently.
|
|
405
|
+
if (!validationTerminal) {
|
|
395
406
|
activeMilestone = { id: m.id, title };
|
|
396
407
|
activeMilestoneSlices = slices;
|
|
397
408
|
activeMilestoneFound = true;
|
|
@@ -516,6 +527,9 @@ function resolveSliceDependencies(activeMilestoneSlices) {
|
|
|
516
527
|
return { activeSlice: null, activeSliceRow: null };
|
|
517
528
|
}
|
|
518
529
|
}
|
|
530
|
+
// First pass: find a slice with ALL dependencies satisfied (strict)
|
|
531
|
+
let bestFallback = null;
|
|
532
|
+
let bestFallbackSatisfied = -1;
|
|
519
533
|
for (const s of activeMilestoneSlices) {
|
|
520
534
|
if (isStatusDone(s.status))
|
|
521
535
|
continue;
|
|
@@ -524,6 +538,23 @@ function resolveSliceDependencies(activeMilestoneSlices) {
|
|
|
524
538
|
if (s.depends.every(dep => doneSliceIds.has(dep))) {
|
|
525
539
|
return { activeSlice: { id: s.id, title: s.title }, activeSliceRow: s };
|
|
526
540
|
}
|
|
541
|
+
// Track the slice with the most satisfied dependencies as fallback
|
|
542
|
+
const satisfied = s.depends.filter(dep => doneSliceIds.has(dep)).length;
|
|
543
|
+
if (satisfied > bestFallbackSatisfied || (satisfied === bestFallbackSatisfied && !bestFallback)) {
|
|
544
|
+
bestFallback = s;
|
|
545
|
+
bestFallbackSatisfied = satisfied;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
// Fallback: if no slice has all deps met but there ARE incomplete non-deferred
|
|
549
|
+
// slices, pick the one with the most deps satisfied. This prevents hard-blocking
|
|
550
|
+
// when dependency metadata is stale (e.g. after reassessment added/removed slices)
|
|
551
|
+
// or when deps reference slices from previous milestones.
|
|
552
|
+
if (bestFallback) {
|
|
553
|
+
const unmet = bestFallback.depends.filter(dep => !doneSliceIds.has(dep));
|
|
554
|
+
logWarning("state", `No slice has all deps satisfied — falling back to ${bestFallback.id} ` +
|
|
555
|
+
`(${bestFallbackSatisfied}/${bestFallback.depends.length} deps met, ` +
|
|
556
|
+
`unmet: ${unmet.join(", ")})`, { mid: activeMilestoneSlices[0]?.milestone_id, sid: bestFallback.id });
|
|
557
|
+
return { activeSlice: { id: bestFallback.id, title: bestFallback.title }, activeSliceRow: bestFallback };
|
|
527
558
|
}
|
|
528
559
|
return { activeSlice: null, activeSliceRow: null };
|
|
529
560
|
}
|
|
@@ -567,7 +598,7 @@ async function reconcileSliceTasks(basePath, milestoneId, sliceId, planFile) {
|
|
|
567
598
|
const summaryPath = resolveTaskFile(basePath, milestoneId, sliceId, t.id, "SUMMARY");
|
|
568
599
|
if (summaryPath && existsSync(summaryPath)) {
|
|
569
600
|
try {
|
|
570
|
-
updateTaskStatus(milestoneId, sliceId, t.id, "complete");
|
|
601
|
+
updateTaskStatus(milestoneId, sliceId, t.id, "complete", new Date().toISOString());
|
|
571
602
|
logWarning("reconcile", `task ${milestoneId}/${sliceId}/${t.id} status reconciled from "${t.status}" to "complete" (#2514)`, { mid: milestoneId, sid: sliceId, tid: t.id });
|
|
572
603
|
reconciled = true;
|
|
573
604
|
}
|
|
@@ -1269,6 +1300,8 @@ export async function _deriveStateImpl(basePath) {
|
|
|
1269
1300
|
}
|
|
1270
1301
|
}
|
|
1271
1302
|
else {
|
|
1303
|
+
let bestFallbackLegacy = null;
|
|
1304
|
+
let bestFallbackLegacySatisfied = -1;
|
|
1272
1305
|
for (const s of activeRoadmap.slices) {
|
|
1273
1306
|
if (s.done)
|
|
1274
1307
|
continue;
|
|
@@ -1276,6 +1309,20 @@ export async function _deriveStateImpl(basePath) {
|
|
|
1276
1309
|
activeSlice = { id: s.id, title: s.title };
|
|
1277
1310
|
break;
|
|
1278
1311
|
}
|
|
1312
|
+
// Track best fallback
|
|
1313
|
+
const satisfied = s.depends.filter(dep => doneSliceIds.has(dep)).length;
|
|
1314
|
+
if (satisfied > bestFallbackLegacySatisfied) {
|
|
1315
|
+
bestFallbackLegacy = s;
|
|
1316
|
+
bestFallbackLegacySatisfied = satisfied;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
// Fallback: if no slice has all deps met, pick the one with the most deps satisfied
|
|
1320
|
+
if (!activeSlice && bestFallbackLegacy) {
|
|
1321
|
+
const unmet = bestFallbackLegacy.depends.filter(dep => !doneSliceIds.has(dep));
|
|
1322
|
+
logWarning("state", `No slice has all deps satisfied — falling back to ${bestFallbackLegacy.id} ` +
|
|
1323
|
+
`(${bestFallbackLegacySatisfied}/${bestFallbackLegacy.depends.length} deps met, ` +
|
|
1324
|
+
`unmet: ${unmet.join(", ")})`);
|
|
1325
|
+
activeSlice = { id: bestFallbackLegacy.id, title: bestFallbackLegacy.title };
|
|
1279
1326
|
}
|
|
1280
1327
|
}
|
|
1281
1328
|
if (!activeSlice) {
|
package/dist/update-check.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare function compareSemver(a: string, b: string): number;
|
|
|
9
9
|
export declare function readUpdateCache(cachePath?: string): UpdateCheckCache | null;
|
|
10
10
|
export declare function writeUpdateCache(cache: UpdateCheckCache, cachePath?: string): void;
|
|
11
11
|
export declare function fetchLatestVersionFromRegistry(registryUrl?: string, fetchTimeoutMs?: number): Promise<string | null>;
|
|
12
|
+
export declare function resolveInstallCommand(pkg: string): string;
|
|
12
13
|
export interface UpdateCheckOptions {
|
|
13
14
|
currentVersion?: string;
|
|
14
15
|
cachePath?: string;
|
package/dist/update-check.js
CHANGED
|
@@ -66,9 +66,16 @@ export async function fetchLatestVersionFromRegistry(registryUrl = DEFAULT_REGIS
|
|
|
66
66
|
clearTimeout(timeout);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
export function resolveInstallCommand(pkg) {
|
|
70
|
+
if ('bun' in process.versions) {
|
|
71
|
+
return `bun add -g ${pkg}`;
|
|
72
|
+
}
|
|
73
|
+
return `npm install -g ${pkg}`;
|
|
74
|
+
}
|
|
69
75
|
function printUpdateBanner(current, latest) {
|
|
76
|
+
const installCmd = resolveInstallCommand('gsd-pi');
|
|
70
77
|
process.stderr.write(` ${chalk.yellow('Update available:')} ${chalk.dim(`v${current}`)} → ${chalk.bold(`v${latest}`)}\n` +
|
|
71
|
-
` ${chalk.dim('Run')}
|
|
78
|
+
` ${chalk.dim('Run')} ${installCmd} ${chalk.dim('or')} /gsd update ${chalk.dim('to upgrade')}\n\n`);
|
|
72
79
|
}
|
|
73
80
|
/**
|
|
74
81
|
* Non-blocking update check. Queries npm registry at most once per 24h,
|
|
@@ -152,7 +159,7 @@ export async function checkAndPromptForUpdates(options = {}) {
|
|
|
152
159
|
const readline = await import('node:readline');
|
|
153
160
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
154
161
|
const choice = await new Promise((resolve) => {
|
|
155
|
-
process.stderr.write(` ${chalk.bold('[1]')} Update now ${chalk.dim(
|
|
162
|
+
process.stderr.write(` ${chalk.bold('[1]')} Update now ${chalk.dim(resolveInstallCommand(`${NPM_PACKAGE_NAME}@latest`))}\n` +
|
|
156
163
|
` ${chalk.bold('[2]')} Skip\n\n`);
|
|
157
164
|
// Default to skip if the user doesn't respond within PROMPT_TIMEOUT_MS
|
|
158
165
|
const timer = setTimeout(() => {
|
|
@@ -173,14 +180,15 @@ export async function checkAndPromptForUpdates(options = {}) {
|
|
|
173
180
|
process.stdin.setRawMode(false);
|
|
174
181
|
process.stdin.pause();
|
|
175
182
|
if (choice === '1') {
|
|
176
|
-
|
|
183
|
+
const installCmd = resolveInstallCommand(`${NPM_PACKAGE_NAME}@latest`);
|
|
184
|
+
process.stderr.write(`\n ${chalk.dim('Running:')} ${installCmd}\n\n`);
|
|
177
185
|
try {
|
|
178
|
-
execSync(
|
|
186
|
+
execSync(installCmd, { stdio: 'inherit' });
|
|
179
187
|
process.stderr.write(`\n ${chalk.green.bold(`✓ Updated to v${latestVersion}`)}\n\n`);
|
|
180
188
|
return true;
|
|
181
189
|
}
|
|
182
190
|
catch {
|
|
183
|
-
process.stderr.write(`\n ${chalk.yellow(`Update failed. You can run:
|
|
191
|
+
process.stderr.write(`\n ${chalk.yellow(`Update failed. You can run: ${installCmd}`)}\n\n`);
|
|
184
192
|
}
|
|
185
193
|
}
|
|
186
194
|
else {
|
package/dist/update-cmd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
|
-
import { compareSemver, fetchLatestVersionFromRegistry } from './update-check.js';
|
|
2
|
+
import { compareSemver, fetchLatestVersionFromRegistry, resolveInstallCommand } from './update-check.js';
|
|
3
3
|
const NPM_PACKAGE = 'gsd-pi';
|
|
4
4
|
export async function runUpdate() {
|
|
5
5
|
const current = process.env.GSD_VERSION || '0.0.0';
|
|
@@ -21,14 +21,15 @@ export async function runUpdate() {
|
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
process.stdout.write(`${dim}Updating:${reset} v${current} → ${bold}v${latest}${reset}\n`);
|
|
24
|
+
const installCmd = resolveInstallCommand(`${NPM_PACKAGE}@latest`);
|
|
24
25
|
try {
|
|
25
|
-
execSync(
|
|
26
|
+
execSync(installCmd, {
|
|
26
27
|
stdio: 'inherit',
|
|
27
28
|
});
|
|
28
29
|
process.stdout.write(`\n${green}${bold}Updated to v${latest}${reset}\n`);
|
|
29
30
|
}
|
|
30
31
|
catch {
|
|
31
|
-
process.stderr.write(`\n${yellow}Update failed. Try manually:
|
|
32
|
+
process.stderr.write(`\n${yellow}Update failed. Try manually: ${installCmd}${reset}\n`);
|
|
32
33
|
process.exit(1);
|
|
33
34
|
}
|
|
34
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
YzIEI9sxJy4t5xgClF08g
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"/_not-found/page": "/_not-found",
|
|
3
3
|
"/_global-error/page": "/_global-error",
|
|
4
|
-
"/api/bridge-terminal/input/route": "/api/bridge-terminal/input",
|
|
5
4
|
"/api/boot/route": "/api/boot",
|
|
5
|
+
"/api/bridge-terminal/input/route": "/api/bridge-terminal/input",
|
|
6
6
|
"/api/bridge-terminal/resize/route": "/api/bridge-terminal/resize",
|
|
7
7
|
"/api/bridge-terminal/stream/route": "/api/bridge-terminal/stream",
|
|
8
|
-
"/api/dev-mode/route": "/api/dev-mode",
|
|
9
8
|
"/api/cleanup/route": "/api/cleanup",
|
|
9
|
+
"/api/dev-mode/route": "/api/dev-mode",
|
|
10
10
|
"/api/doctor/route": "/api/doctor",
|
|
11
11
|
"/api/export-data/route": "/api/export-data",
|
|
12
|
-
"/api/browse-directories/route": "/api/browse-directories",
|
|
13
12
|
"/api/captures/route": "/api/captures",
|
|
14
13
|
"/api/forensics/route": "/api/forensics",
|
|
14
|
+
"/api/browse-directories/route": "/api/browse-directories",
|
|
15
15
|
"/api/git/route": "/api/git",
|
|
16
16
|
"/api/history/route": "/api/history",
|
|
17
17
|
"/api/hooks/route": "/api/hooks",
|
|
@@ -21,26 +21,26 @@
|
|
|
21
21
|
"/api/live-state/route": "/api/live-state",
|
|
22
22
|
"/api/notifications/route": "/api/notifications",
|
|
23
23
|
"/api/preferences/route": "/api/preferences",
|
|
24
|
-
"/api/recovery/route": "/api/recovery",
|
|
25
24
|
"/api/onboarding/route": "/api/onboarding",
|
|
25
|
+
"/api/recovery/route": "/api/recovery",
|
|
26
26
|
"/api/projects/route": "/api/projects",
|
|
27
27
|
"/api/session/browser/route": "/api/session/browser",
|
|
28
28
|
"/api/session/command/route": "/api/session/command",
|
|
29
29
|
"/api/session/events/route": "/api/session/events",
|
|
30
|
-
"/api/session/manage/route": "/api/session/manage",
|
|
31
30
|
"/api/settings-data/route": "/api/settings-data",
|
|
32
31
|
"/api/shutdown/route": "/api/shutdown",
|
|
32
|
+
"/api/session/manage/route": "/api/session/manage",
|
|
33
33
|
"/api/skill-health/route": "/api/skill-health",
|
|
34
34
|
"/api/steer/route": "/api/steer",
|
|
35
35
|
"/api/terminal/input/route": "/api/terminal/input",
|
|
36
|
-
"/api/terminal/resize/route": "/api/terminal/resize",
|
|
37
|
-
"/api/files/route": "/api/files",
|
|
38
36
|
"/api/switch-root/route": "/api/switch-root",
|
|
37
|
+
"/api/files/route": "/api/files",
|
|
38
|
+
"/api/terminal/resize/route": "/api/terminal/resize",
|
|
39
39
|
"/api/terminal/sessions/route": "/api/terminal/sessions",
|
|
40
|
-
"/api/
|
|
40
|
+
"/api/undo/route": "/api/undo",
|
|
41
41
|
"/api/terminal/stream/route": "/api/terminal/stream",
|
|
42
|
+
"/api/terminal/upload/route": "/api/terminal/upload",
|
|
42
43
|
"/api/visualizer/route": "/api/visualizer",
|
|
43
|
-
"/api/undo/route": "/api/undo",
|
|
44
44
|
"/api/update/route": "/api/update",
|
|
45
45
|
"/api/remote-questions/route": "/api/remote-questions",
|
|
46
46
|
"/page": "/"
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
],
|
|
5
5
|
"devFiles": [],
|
|
6
6
|
"lowPriorityFiles": [
|
|
7
|
-
"static/
|
|
8
|
-
"static/
|
|
7
|
+
"static/YzIEI9sxJy4t5xgClF08g/_buildManifest.js",
|
|
8
|
+
"static/YzIEI9sxJy4t5xgClF08g/_ssgManifest.js"
|
|
9
9
|
],
|
|
10
10
|
"rootMainFiles": [
|
|
11
11
|
"static/chunks/webpack-b868033a5834586d.js",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"dynamicRoutes": {},
|
|
79
79
|
"notFoundRoutes": [],
|
|
80
80
|
"preview": {
|
|
81
|
-
"previewModeId": "
|
|
82
|
-
"previewModeSigningKey": "
|
|
83
|
-
"previewModeEncryptionKey": "
|
|
81
|
+
"previewModeId": "9d5401bd57ef1915ed4de809746cc37e",
|
|
82
|
+
"previewModeSigningKey": "913181b782202bf148f9e4d57ab24be5fbb83cc03ce81062e835e53cbe47c142",
|
|
83
|
+
"previewModeEncryptionKey": "5bdc70fb239b1d5eeebc0b3b3aa05b858f80bb575d50736a6cfce429779b9dbd"
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><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-b868033a5834586d.js"/><script src="/_next/static/chunks/4bd1b696-e356ca5ba0218e27.js" async=""></script><script src="/_next/static/chunks/3794-42fdce068d44fa4f.js" async=""></script><script src="/_next/static/chunks/main-app-fdab67f7802d7832.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: This page couldn’t load</title><style>:root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }</style><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;display:flex;align-items:center;justify-content:center"><div style="margin-top:-32px;max-width:325px;padding:32px 28px;text-align:left"><svg width="32" height="32" viewBox="-0.2 -1.5 32 32" fill="none" style="margin-bottom:24px"><path d="M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z" fill="var(--next-error-title)"></path></svg><h1 style="font-size:24px;font-weight:500;letter-spacing:-0.02em;line-height:32px;margin:0 0 12px 0;color:var(--next-error-title)">This page couldn’t load</h1><p style="font-size:14px;font-weight:400;line-height:21px;margin:0 0 20px 0;color:var(--next-error-message)">A server error occurred. Reload to try again.</p><form style="margin:0"><button type="submit" style="display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;font-size:14px;font-weight:500;line-height:20px;border-radius:6px;cursor:pointer;color:var(--next-error-btn-text);background:var(--next-error-btn-bg);border:var(--next-error-btn-border)">Reload</button></form></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-b868033a5834586d.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\"\n8:I[90484,[],\"ViewportBoundary\"]\na:I[90484,[],\"MetadataBoundary\"]\nc:I[27123,[],\"default\",1]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"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: This page couldn’t load\"}],[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }\"}}]]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"display\":\"flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"marginTop\":\"-32px\",\"maxWidth\":\"325px\",\"padding\":\"32px 28px\",\"textAlign\":\"left\"},\"children\":[[\"$\",\"svg\",null,{\"width\":\"32\",\"height\":\"32\",\"viewBox\":\"-0.2 -1.5 32 32\",\"fill\":\"none\",\"style\":{\"marginBottom\":\"24px\"},\"children\":[\"$\",\"path\",null,{\"d\":\"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z\",\"fill\":\"var(--next-error-title)\"}]}],[\"$\",\"h1\",null,{\"style\":{\"fontSize\":\"24px\",\"fontWeight\":500,\"letterSpacing\":\"-0.02em\",\"lineHeight\":\"32px\",\"margin\":\"0 0 12px 0\",\"color\":\"var(--next-error-title)\"},\"children\":\"This page couldn’t load\"}],[\"$\",\"p\",null,{\"style\":{\"fontSize\":\"14px\",\"fontWeight\":400,\"lineHeight\":\"21px\",\"margin\":\"0 0 20px 0\",\"color\":\"var(--next-error-message)\"},\"children\":\"A server error occurred. Reload to try again.\"}],[\"$\",\"form\",null,{\"style\":{\"margin\":0},\"children\":[\"$\",\"button\",null,{\"type\":\"submit\",\"style\":{\"display\":\"inline-flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\",\"height\":\"32px\",\"padding\":\"0 12px\",\"fontSize\":\"14px\",\"fontWeight\":500,\"lineHeight\":\"20px\",\"borderRadius\":\"6px\",\"cursor\":\"pointer\",\"color\":\"var(--next-error-btn-text)\",\"background\":\"var(--next-error-btn-bg)\",\"border\":\"var(--next-error-btn-border)\"},\"children\":\"Reload\"}]}]]}]}]}]]}],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$@7\"]},null,false,\"$@7\"],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"
|
|
1
|
+
<!DOCTYPE html><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-b868033a5834586d.js"/><script src="/_next/static/chunks/4bd1b696-e356ca5ba0218e27.js" async=""></script><script src="/_next/static/chunks/3794-42fdce068d44fa4f.js" async=""></script><script src="/_next/static/chunks/main-app-fdab67f7802d7832.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: This page couldn’t load</title><style>:root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }</style><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;display:flex;align-items:center;justify-content:center"><div style="margin-top:-32px;max-width:325px;padding:32px 28px;text-align:left"><svg width="32" height="32" viewBox="-0.2 -1.5 32 32" fill="none" style="margin-bottom:24px"><path d="M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z" fill="var(--next-error-title)"></path></svg><h1 style="font-size:24px;font-weight:500;letter-spacing:-0.02em;line-height:32px;margin:0 0 12px 0;color:var(--next-error-title)">This page couldn’t load</h1><p style="font-size:14px;font-weight:400;line-height:21px;margin:0 0 20px 0;color:var(--next-error-message)">A server error occurred. Reload to try again.</p><form style="margin:0"><button type="submit" style="display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;font-size:14px;font-weight:500;line-height:20px;border-radius:6px;cursor:pointer;color:var(--next-error-btn-text);background:var(--next-error-btn-bg);border:var(--next-error-btn-border)">Reload</button></form></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-b868033a5834586d.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\"\n8:I[90484,[],\"ViewportBoundary\"]\na:I[90484,[],\"MetadataBoundary\"]\nc:I[27123,[],\"default\",1]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"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: This page couldn’t load\"}],[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }\"}}]]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"display\":\"flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"marginTop\":\"-32px\",\"maxWidth\":\"325px\",\"padding\":\"32px 28px\",\"textAlign\":\"left\"},\"children\":[[\"$\",\"svg\",null,{\"width\":\"32\",\"height\":\"32\",\"viewBox\":\"-0.2 -1.5 32 32\",\"fill\":\"none\",\"style\":{\"marginBottom\":\"24px\"},\"children\":[\"$\",\"path\",null,{\"d\":\"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z\",\"fill\":\"var(--next-error-title)\"}]}],[\"$\",\"h1\",null,{\"style\":{\"fontSize\":\"24px\",\"fontWeight\":500,\"letterSpacing\":\"-0.02em\",\"lineHeight\":\"32px\",\"margin\":\"0 0 12px 0\",\"color\":\"var(--next-error-title)\"},\"children\":\"This page couldn’t load\"}],[\"$\",\"p\",null,{\"style\":{\"fontSize\":\"14px\",\"fontWeight\":400,\"lineHeight\":\"21px\",\"margin\":\"0 0 20px 0\",\"color\":\"var(--next-error-message)\"},\"children\":\"A server error occurred. Reload to try again.\"}],[\"$\",\"form\",null,{\"style\":{\"margin\":0},\"children\":[\"$\",\"button\",null,{\"type\":\"submit\",\"style\":{\"display\":\"inline-flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\",\"height\":\"32px\",\"padding\":\"0 12px\",\"fontSize\":\"14px\",\"fontWeight\":500,\"lineHeight\":\"20px\",\"borderRadius\":\"6px\",\"cursor\":\"pointer\",\"color\":\"var(--next-error-btn-text)\",\"background\":\"var(--next-error-btn-bg)\",\"border\":\"var(--next-error-btn-border)\"},\"children\":\"Reload\"}]}]]}]}]}]]}],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$@7\"]},null,false,\"$@7\"],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"YzIEI9sxJy4t5xgClF08g\"}\n"])</script><script>self.__next_f.push([1,"d:[]\n7:\"$Wd\"\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"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\nb:[]\n"])</script></body></html>
|