diff --git a/src/models-resolver.ts b/src/models-resolver.ts index 8d39a4072..db9a61a45 100644 --- a/src/models-resolver.ts +++ b/src/models-resolver.ts @@ -37,19 +37,4 @@ export function resolveModelsJsonPath(): string { return GSD_MODELS_PATH } -/** - * Check if both GSD and PI models.json files exist. - */ -export function hasBothModelsFiles(): boolean { - return existsSync(GSD_MODELS_PATH) && existsSync(PI_MODELS_PATH) -} -/** - * Get the paths to both models.json files. - */ -export function getModelsPaths(): { gsd: string; pi: string } { - return { - gsd: GSD_MODELS_PATH, - pi: PI_MODELS_PATH, - } -} diff --git a/src/resource-loader.ts b/src/resource-loader.ts index ed32d7ab0..d5fdc9a7f 100644 --- a/src/resource-loader.ts +++ b/src/resource-loader.ts @@ -116,14 +116,6 @@ export function readManagedResourceVersion(agentDir: string): string | null { } } -export function readManagedResourceSyncedAt(agentDir: string): number | null { - try { - const manifest = JSON.parse(readFileSync(getManagedResourceManifestPath(agentDir), 'utf-8')) as ManagedResourceManifest - return typeof manifest?.syncedAt === 'number' ? manifest.syncedAt : null - } catch { - return null - } -} export function getNewerManagedResourceVersion(agentDir: string, currentVersion: string): string | null { const managedVersion = readManagedResourceVersion(agentDir) diff --git a/src/resources/extensions/bg-shell/overlay.ts b/src/resources/extensions/bg-shell/overlay.ts index ed8c45c74..7c3599c1f 100644 --- a/src/resources/extensions/bg-shell/overlay.ts +++ b/src/resources/extensions/bg-shell/overlay.ts @@ -328,12 +328,9 @@ export class BgManagerOverlay { return this.box(inner, width); } - private renderOutput(width: number): string[] { + private processStatusHeader(p: typeof this.viewingProcess, activeTab: "output" | "events"): { statusIcon: string; headerLine: string } { const th = this.theme; - const p = this.viewingProcess; - if (!p) return [""]; - const inner: string[] = []; - + if (!p) return { statusIcon: "", headerLine: "" }; const statusIcon = p.alive ? (p.status === "ready" ? th.fg("success", "●") : p.status === "error" ? th.fg("error", "●") @@ -343,9 +340,21 @@ export class BgManagerOverlay { const uptime = th.fg("dim", formatUptime(Date.now() - p.startedAt)); const typeTag = th.fg("dim", `[${p.processType}]`); const portInfo = p.ports.length > 0 ? th.fg("dim", ` :${p.ports.join(",")}`) : ""; - const tabIndicator = th.fg("accent", "[Output]") + " " + th.fg("dim", "Events"); + const tabIndicator = activeTab === "output" + ? th.fg("accent", "[Output]") + " " + th.fg("dim", "Events") + : th.fg("dim", "Output") + " " + th.fg("accent", "[Events]"); + const headerLine = `${statusIcon} ${name} ${typeTag} ${uptime}${portInfo} ${tabIndicator}`; + return { statusIcon, headerLine }; + } - inner.push(`${statusIcon} ${name} ${typeTag} ${uptime}${portInfo} ${tabIndicator}`); + private renderOutput(width: number): string[] { + const th = this.theme; + const p = this.viewingProcess; + if (!p) return [""]; + const inner: string[] = []; + + const { headerLine } = this.processStatusHeader(p, "output"); + inner.push(headerLine); inner.push(""); // Unified buffer is already chronologically interleaved @@ -384,16 +393,8 @@ export class BgManagerOverlay { if (!p) return [""]; const inner: string[] = []; - const statusIcon = p.alive - ? (p.status === "ready" ? th.fg("success", "●") - : p.status === "error" ? th.fg("error", "●") - : th.fg("warning", "●")) - : th.fg("dim", "○"); - const name = th.fg("muted", p.label); - const uptime = th.fg("dim", formatUptime(Date.now() - p.startedAt)); - const tabIndicator = th.fg("dim", "Output") + " " + th.fg("accent", "[Events]"); - - inner.push(`${statusIcon} ${name} ${uptime} ${tabIndicator}`); + const { headerLine } = this.processStatusHeader(p, "events"); + inner.push(headerLine); inner.push(""); if (p.events.length === 0) { diff --git a/src/resources/extensions/get-secrets-from-user.ts b/src/resources/extensions/get-secrets-from-user.ts index 08e68e55e..e889a947d 100644 --- a/src/resources/extensions/get-secrets-from-user.ts +++ b/src/resources/extensions/get-secrets-from-user.ts @@ -369,32 +369,14 @@ async function applySecrets( } } - if (destination === "vercel" && opts.exec) { + if ((destination === "vercel" || destination === "convex") && opts.exec) { const env = opts.environment ?? "development"; for (const { key, value } of provided) { + const cmd = destination === "vercel" + ? `printf %s ${shellEscapeSingle(value)} | vercel env add ${key} ${env}` + : `npx convex env set ${key} ${shellEscapeSingle(value)}`; try { - const result = await opts.exec("sh", [ - "-c", - `printf %s ${shellEscapeSingle(value)} | vercel env add ${key} ${env}`, - ]); - if (result.code !== 0) { - errors.push(`${key}: ${result.stderr.slice(0, 200)}`); - } else { - applied.push(key); - } - } catch (err: any) { - errors.push(`${key}: ${err.message}`); - } - } - } - - if (destination === "convex" && opts.exec) { - for (const { key, value } of provided) { - try { - const result = await opts.exec("sh", [ - "-c", - `npx convex env set ${key} ${shellEscapeSingle(value)}`, - ]); + const result = await opts.exec("sh", ["-c", cmd]); if (result.code !== 0) { errors.push(`${key}: ${result.stderr.slice(0, 200)}`); } else { diff --git a/src/resources/extensions/gsd/guided-flow.ts b/src/resources/extensions/gsd/guided-flow.ts index 76fad5447..b63c77278 100644 --- a/src/resources/extensions/gsd/guided-flow.ts +++ b/src/resources/extensions/gsd/guided-flow.ts @@ -870,7 +870,7 @@ export async function showDiscuss( const draftFile = resolveMilestoneFile(basePath, mid, "CONTEXT-DRAFT"); const draftContent = draftFile ? await loadFile(draftFile) : null; - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `GSD — ${mid}: ${milestoneTitle}`, summary: ["This milestone has a draft context from a prior discussion.", "It needs a dedicated discussion before auto-planning can begin."], actions: [ @@ -947,7 +947,7 @@ export async function showDiscuss( recommended: i === 0, })); - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: "GSD — Discuss a slice", summary: [ `${mid}: ${milestoneTitle}`, @@ -1056,7 +1056,7 @@ export async function showSmartEntry( const crashLock = readCrashLock(basePath); if (crashLock) { clearLock(basePath); - const resume = await showNextAction(ctx as any, { + const resume = await showNextAction(ctx, { title: "GSD — Interrupted Session Detected", summary: [formatCrashInfo(crashLock)], actions: [ @@ -1116,7 +1116,7 @@ export async function showSmartEntry( basePath )); } else { - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: "GSD — Get Shit Done", summary: ["No active milestone."], actions: [ @@ -1146,7 +1146,7 @@ export async function showSmartEntry( // ── All milestones complete → New milestone ────────────────────────── if (state.phase === "complete") { - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `GSD — ${milestoneId}: ${milestoneTitle}`, summary: ["All milestones complete."], actions: [ @@ -1187,7 +1187,7 @@ export async function showSmartEntry( const draftFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT-DRAFT"); const draftContent = draftFile ? await loadFile(draftFile) : null; - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `GSD — ${milestoneId}: ${milestoneTitle}`, summary: ["This milestone has a draft context from a prior discussion.", "It needs a dedicated discussion before auto-planning can begin."], actions: [ @@ -1278,7 +1278,7 @@ export async function showSmartEntry( }, ]; - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `GSD — ${milestoneId}: ${milestoneTitle}`, summary: [hasContext ? "Context captured. Ready to create roadmap." : "New milestone — no roadmap yet."], actions, @@ -1315,7 +1315,7 @@ export async function showSmartEntry( } else if (choice === "discard_milestone") { const mDir = resolveMilestonePath(basePath, milestoneId); if (!mDir) return; - const confirmed = await showConfirm(ctx as any, { + const confirmed = await showConfirm(ctx, { title: "Discard milestone?", message: `This will permanently delete ${milestoneId} and all its contents.`, confirmLabel: "Discard", @@ -1342,7 +1342,7 @@ export async function showSmartEntry( }, ]; - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `GSD — ${milestoneId}: ${milestoneTitle}`, summary: ["Roadmap exists. Ready to execute."], actions, @@ -1400,7 +1400,7 @@ export async function showSmartEntry( ? `${sliceId}: ${sliceTitle} (${summaryParts.join(", ")})` : `${sliceId}: ${sliceTitle} — ready for planning.`; - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `GSD — ${milestoneId} / ${sliceId}: ${sliceTitle}`, summary: [summaryLine], actions, @@ -1431,7 +1431,7 @@ export async function showSmartEntry( // ── All tasks done → Complete slice ────────────────────────────────── if (state.phase === "summarizing") { - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `GSD — ${milestoneId} / ${sliceId}: ${sliceTitle}`, summary: ["All tasks complete. Ready for slice summary."], actions: [ @@ -1475,7 +1475,7 @@ export async function showSmartEntry( const hasInterrupted = !!(continueFile && await loadFile(continueFile)) || !!(sDir && await loadFile(join(sDir, "continue.md"))); - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `GSD — ${milestoneId} / ${sliceId}: ${sliceTitle}`, summary: [ hasInterrupted diff --git a/src/resources/extensions/gsd/migrate/command.ts b/src/resources/extensions/gsd/migrate/command.ts index ef4e1f409..60bbe1285 100644 --- a/src/resources/extensions/gsd/migrate/command.ts +++ b/src/resources/extensions/gsd/migrate/command.ts @@ -151,7 +151,7 @@ export async function handleMigrate( } // ── Confirmation via showNextAction ──────────────────────────────────────── - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: "Migration preview", summary: lines, actions: [ @@ -187,7 +187,7 @@ export async function handleMigrate( ); // ── Post-write review offer ──────────────────────────────────────────────── - const reviewChoice = await showNextAction(ctx as any, { + const reviewChoice = await showNextAction(ctx, { title: "Migration written", summary: [ `${result.paths.length} files written to .gsd/`, diff --git a/src/resources/extensions/gsd/triage-ui.ts b/src/resources/extensions/gsd/triage-ui.ts index ce7473a0e..e713732ec 100644 --- a/src/resources/extensions/gsd/triage-ui.ts +++ b/src/resources/extensions/gsd/triage-ui.ts @@ -135,7 +135,7 @@ export async function showTriageConfirmation( recommended: cls === proposed, })); - const choice = await showNextAction(ctx as any, { + const choice = await showNextAction(ctx, { title: `Triage: ${result.captureId}`, summary, actions,