gsd-pi 2.23.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/cli.js +12 -3
- package/dist/headless.d.ts +4 -0
- package/dist/headless.js +118 -10
- package/dist/help-text.js +22 -7
- package/dist/models-resolver.d.ts +0 -11
- package/dist/models-resolver.js +0 -15
- package/dist/resource-loader.d.ts +0 -1
- package/dist/resource-loader.js +64 -18
- package/dist/resources/GSD-WORKFLOW.md +12 -9
- package/dist/resources/extensions/bg-shell/overlay.ts +18 -17
- package/dist/resources/extensions/get-secrets-from-user.ts +5 -23
- package/dist/resources/extensions/gsd/activity-log.ts +5 -3
- package/dist/resources/extensions/gsd/auto-dispatch.ts +51 -2
- package/dist/resources/extensions/gsd/auto-prompts.ts +87 -0
- package/dist/resources/extensions/gsd/auto-recovery.ts +41 -2
- package/dist/resources/extensions/gsd/auto-worktree.ts +134 -4
- package/dist/resources/extensions/gsd/auto.ts +307 -77
- package/dist/resources/extensions/gsd/cache.ts +3 -1
- package/dist/resources/extensions/gsd/commands.ts +176 -10
- package/dist/resources/extensions/gsd/complexity.ts +1 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +38 -0
- package/dist/resources/extensions/gsd/doctor.ts +58 -11
- package/dist/resources/extensions/gsd/exit-command.ts +2 -2
- package/dist/resources/extensions/gsd/git-service.ts +74 -14
- package/dist/resources/extensions/gsd/gitignore.ts +1 -0
- package/dist/resources/extensions/gsd/gsd-db.ts +78 -1
- package/dist/resources/extensions/gsd/guided-flow.ts +109 -12
- package/dist/resources/extensions/gsd/index.ts +48 -2
- package/dist/resources/extensions/gsd/memory-extractor.ts +352 -0
- package/dist/resources/extensions/gsd/memory-store.ts +441 -0
- package/dist/resources/extensions/gsd/migrate/command.ts +2 -2
- package/dist/resources/extensions/gsd/parallel-eligibility.ts +233 -0
- package/dist/resources/extensions/gsd/parallel-merge.ts +156 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.ts +496 -0
- package/dist/resources/extensions/gsd/preferences.ts +65 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +86 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +4 -4
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +40 -61
- package/dist/resources/extensions/gsd/provider-error-pause.ts +29 -2
- package/dist/resources/extensions/gsd/session-status-io.ts +197 -0
- package/dist/resources/extensions/gsd/state.ts +72 -30
- package/dist/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +81 -0
- package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +20 -3
- package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +256 -2
- package/dist/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +34 -0
- package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +8 -1
- package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +9 -15
- package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +9 -0
- package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +8 -0
- package/dist/resources/extensions/gsd/tests/derive-state.test.ts +14 -0
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +70 -4
- package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
- package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +8 -0
- package/dist/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
- package/dist/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
- package/dist/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
- package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +5 -5
- package/dist/resources/extensions/gsd/tests/parallel-orchestration.test.ts +656 -0
- package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +354 -0
- package/dist/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +316 -0
- package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
- package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
- package/dist/resources/extensions/gsd/tests/worker-registry.test.ts +148 -0
- package/dist/resources/extensions/gsd/triage-ui.ts +1 -1
- package/dist/resources/extensions/gsd/types.ts +15 -1
- package/dist/resources/extensions/gsd/visualizer-data.ts +291 -10
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +237 -28
- package/dist/resources/extensions/gsd/visualizer-views.ts +462 -48
- package/dist/resources/extensions/gsd/worktree.ts +9 -2
- package/dist/resources/extensions/search-the-web/native-search.ts +15 -5
- package/dist/resources/extensions/subagent/index.ts +5 -0
- package/dist/resources/extensions/subagent/worker-registry.ts +99 -0
- package/dist/update-check.d.ts +9 -0
- package/dist/update-check.js +97 -0
- package/package.json +6 -1
- package/packages/pi-agent-core/dist/agent-loop.js +2 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +55 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js +12 -4
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js +21 -9
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/mistral.js +3 -0
- package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +12 -4
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +12 -4
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +23 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic.ts +59 -9
- package/packages/pi-ai/src/providers/azure-openai-responses.ts +16 -4
- package/packages/pi-ai/src/providers/google-vertex.ts +32 -17
- package/packages/pi-ai/src/providers/mistral.ts +3 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +16 -4
- package/packages/pi-ai/src/providers/openai-responses.ts +16 -4
- package/packages/pi-ai/src/types.ts +19 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- 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 +72 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/settings-manager.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +84 -0
- package/scripts/postinstall.js +7 -109
- package/src/resources/GSD-WORKFLOW.md +12 -9
- package/src/resources/extensions/bg-shell/overlay.ts +18 -17
- package/src/resources/extensions/get-secrets-from-user.ts +5 -23
- package/src/resources/extensions/gsd/activity-log.ts +5 -3
- package/src/resources/extensions/gsd/auto-dispatch.ts +51 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +87 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +41 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +134 -4
- package/src/resources/extensions/gsd/auto.ts +307 -77
- package/src/resources/extensions/gsd/cache.ts +3 -1
- package/src/resources/extensions/gsd/commands.ts +176 -10
- package/src/resources/extensions/gsd/complexity.ts +1 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +38 -0
- package/src/resources/extensions/gsd/doctor.ts +58 -11
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +74 -14
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +78 -1
- package/src/resources/extensions/gsd/guided-flow.ts +109 -12
- package/src/resources/extensions/gsd/index.ts +48 -2
- package/src/resources/extensions/gsd/memory-extractor.ts +352 -0
- package/src/resources/extensions/gsd/memory-store.ts +441 -0
- package/src/resources/extensions/gsd/migrate/command.ts +2 -2
- package/src/resources/extensions/gsd/parallel-eligibility.ts +233 -0
- package/src/resources/extensions/gsd/parallel-merge.ts +156 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +496 -0
- package/src/resources/extensions/gsd/preferences.ts +65 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +86 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +4 -4
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +40 -61
- package/src/resources/extensions/gsd/provider-error-pause.ts +29 -2
- package/src/resources/extensions/gsd/session-status-io.ts +197 -0
- package/src/resources/extensions/gsd/state.ts +72 -30
- package/src/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +20 -3
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +256 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +70 -4
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +656 -0
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +354 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +148 -0
- package/src/resources/extensions/gsd/triage-ui.ts +1 -1
- package/src/resources/extensions/gsd/types.ts +15 -1
- package/src/resources/extensions/gsd/visualizer-data.ts +291 -10
- package/src/resources/extensions/gsd/visualizer-overlay.ts +237 -28
- package/src/resources/extensions/gsd/visualizer-views.ts +462 -48
- package/src/resources/extensions/gsd/worktree.ts +9 -2
- package/src/resources/extensions/search-the-web/native-search.ts +15 -5
- package/src/resources/extensions/subagent/index.ts +5 -0
- package/src/resources/extensions/subagent/worker-registry.ts +99 -0
package/README.md
CHANGED
|
@@ -36,7 +36,8 @@ Full documentation is available in the [`docs/`](./docs/) directory:
|
|
|
36
36
|
- **[Skills](./docs/skills.md)** — bundled skills, discovery, custom authoring
|
|
37
37
|
- **[Commands Reference](./docs/commands.md)** — all commands and keyboard shortcuts
|
|
38
38
|
- **[Architecture](./docs/architecture.md)** — system design and dispatch pipeline
|
|
39
|
-
- **[Troubleshooting](./docs/troubleshooting.md)** — common issues, doctor, recovery
|
|
39
|
+
- **[Troubleshooting](./docs/troubleshooting.md)** — common issues, doctor, forensics, recovery
|
|
40
|
+
- **[VS Code Extension](./vscode-extension/README.md)** — chat participant, sidebar dashboard, RPC integration
|
|
40
41
|
- **[Migration from v1](./docs/migration.md)** — `.planning` → `.gsd` migration
|
|
41
42
|
|
|
42
43
|
---
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { loadStoredEnvKeys } from './wizard.js';
|
|
|
8
8
|
import { getPiDefaultModelAndProvider, migratePiCredentials } from './pi-migration.js';
|
|
9
9
|
import { shouldRunOnboarding, runOnboarding } from './onboarding.js';
|
|
10
10
|
import chalk from 'chalk';
|
|
11
|
-
import { checkForUpdates } from './update-check.js';
|
|
11
|
+
import { checkForUpdates, checkAndPromptForUpdates } from './update-check.js';
|
|
12
12
|
import { printHelp, printSubcommandHelp } from './help-text.js';
|
|
13
13
|
function exitIfManagedResourcesAreNewer(currentAgentDir) {
|
|
14
14
|
const currentVersion = process.env.GSD_VERSION || '0.0.0';
|
|
@@ -169,9 +169,18 @@ if (!isPrintMode && shouldRunOnboarding(authStorage, settingsManager.getDefaultP
|
|
|
169
169
|
process.stdin.setRawMode(false);
|
|
170
170
|
process.stdin.pause();
|
|
171
171
|
}
|
|
172
|
-
//
|
|
172
|
+
// Update check — interactive prompt when stdin is a TTY, passive banner otherwise
|
|
173
173
|
if (!isPrintMode) {
|
|
174
|
-
|
|
174
|
+
if (process.stdin.isTTY) {
|
|
175
|
+
const updated = await checkAndPromptForUpdates().catch(() => false);
|
|
176
|
+
if (updated) {
|
|
177
|
+
// User chose to update — exit so they relaunch with the new version
|
|
178
|
+
process.exit(0);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
checkForUpdates().catch(() => { });
|
|
183
|
+
}
|
|
175
184
|
}
|
|
176
185
|
// Warn if terminal is too narrow for readable output
|
|
177
186
|
if (!isPrintMode && process.stdout.columns && process.stdout.columns < 40) {
|
package/dist/headless.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ export interface HeadlessOptions {
|
|
|
16
16
|
model?: string;
|
|
17
17
|
command: string;
|
|
18
18
|
commandArgs: string[];
|
|
19
|
+
context?: string;
|
|
20
|
+
contextText?: string;
|
|
21
|
+
auto?: boolean;
|
|
22
|
+
verbose?: boolean;
|
|
19
23
|
}
|
|
20
24
|
export declare function parseHeadlessArgs(argv: string[]): HeadlessOptions;
|
|
21
25
|
export declare function runHeadless(options: HeadlessOptions): Promise<void>;
|
package/dist/headless.js
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* 1 — error or timeout
|
|
11
11
|
* 2 — blocked (command reported a blocker)
|
|
12
12
|
*/
|
|
13
|
-
import { existsSync } from 'node:fs';
|
|
14
|
-
import { join } from 'node:path';
|
|
13
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
14
|
+
import { join, resolve } from 'node:path';
|
|
15
15
|
// RpcClient is not in @gsd/pi-coding-agent's public exports — import from dist directly.
|
|
16
16
|
// This relative path resolves correctly from both src/ (via tsx) and dist/ (compiled).
|
|
17
17
|
import { RpcClient } from '../packages/pi-coding-agent/dist/modes/rpc/rpc-client.js';
|
|
@@ -46,6 +46,18 @@ export function parseHeadlessArgs(argv) {
|
|
|
46
46
|
// --model can also be passed from the main CLI; headless-specific takes precedence
|
|
47
47
|
options.model = args[++i];
|
|
48
48
|
}
|
|
49
|
+
else if (arg === '--context' && i + 1 < args.length) {
|
|
50
|
+
options.context = args[++i];
|
|
51
|
+
}
|
|
52
|
+
else if (arg === '--context-text' && i + 1 < args.length) {
|
|
53
|
+
options.contextText = args[++i];
|
|
54
|
+
}
|
|
55
|
+
else if (arg === '--auto') {
|
|
56
|
+
options.auto = true;
|
|
57
|
+
}
|
|
58
|
+
else if (arg === '--verbose') {
|
|
59
|
+
options.verbose = true;
|
|
60
|
+
}
|
|
49
61
|
}
|
|
50
62
|
else if (!positionalStarted) {
|
|
51
63
|
positionalStarted = true;
|
|
@@ -99,18 +111,23 @@ function handleExtensionUIRequest(event, writeToStdin) {
|
|
|
99
111
|
// ---------------------------------------------------------------------------
|
|
100
112
|
// Progress Formatter
|
|
101
113
|
// ---------------------------------------------------------------------------
|
|
102
|
-
function formatProgress(event) {
|
|
114
|
+
function formatProgress(event, verbose) {
|
|
103
115
|
const type = String(event.type ?? '');
|
|
104
116
|
switch (type) {
|
|
105
117
|
case 'tool_execution_start':
|
|
106
|
-
|
|
118
|
+
if (verbose)
|
|
119
|
+
return ` [tool] ${event.toolName ?? 'unknown'}`;
|
|
120
|
+
return null;
|
|
107
121
|
case 'agent_start':
|
|
108
|
-
return '[agent]
|
|
122
|
+
return '[agent] Session started';
|
|
109
123
|
case 'agent_end':
|
|
110
|
-
return '[agent]
|
|
124
|
+
return '[agent] Session ended';
|
|
111
125
|
case 'extension_ui_request':
|
|
112
126
|
if (event.method === 'notify') {
|
|
113
|
-
return `[gsd]
|
|
127
|
+
return `[gsd] ${event.message ?? ''}`;
|
|
128
|
+
}
|
|
129
|
+
if (event.method === 'setStatus') {
|
|
130
|
+
return `[status] ${event.message ?? ''}`;
|
|
114
131
|
}
|
|
115
132
|
return null;
|
|
116
133
|
default:
|
|
@@ -133,6 +150,11 @@ function isBlockedNotification(event) {
|
|
|
133
150
|
return false;
|
|
134
151
|
return String(event.message ?? '').toLowerCase().includes('blocked');
|
|
135
152
|
}
|
|
153
|
+
function isMilestoneReadyNotification(event) {
|
|
154
|
+
if (event.type !== 'extension_ui_request' || event.method !== 'notify')
|
|
155
|
+
return false;
|
|
156
|
+
return /milestone\s+m\d+.*ready/i.test(String(event.message ?? ''));
|
|
157
|
+
}
|
|
136
158
|
// ---------------------------------------------------------------------------
|
|
137
159
|
// Quick Command Detection
|
|
138
160
|
// ---------------------------------------------------------------------------
|
|
@@ -148,11 +170,69 @@ function isQuickCommand(command) {
|
|
|
148
170
|
// ---------------------------------------------------------------------------
|
|
149
171
|
// Main Orchestrator
|
|
150
172
|
// ---------------------------------------------------------------------------
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Context Loading (new-milestone)
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
async function readStdin() {
|
|
177
|
+
const chunks = [];
|
|
178
|
+
for await (const chunk of process.stdin) {
|
|
179
|
+
chunks.push(chunk);
|
|
180
|
+
}
|
|
181
|
+
return Buffer.concat(chunks).toString('utf-8');
|
|
182
|
+
}
|
|
183
|
+
async function loadContext(options) {
|
|
184
|
+
if (options.contextText)
|
|
185
|
+
return options.contextText;
|
|
186
|
+
if (options.context === '-') {
|
|
187
|
+
return readStdin();
|
|
188
|
+
}
|
|
189
|
+
if (options.context) {
|
|
190
|
+
return readFileSync(resolve(options.context), 'utf-8');
|
|
191
|
+
}
|
|
192
|
+
throw new Error('No context provided. Use --context <file> or --context-text <text>');
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Bootstrap .gsd/ directory structure for headless new-milestone.
|
|
196
|
+
* Mirrors the bootstrap logic from guided-flow.ts showSmartEntry().
|
|
197
|
+
*/
|
|
198
|
+
function bootstrapGsdProject(basePath) {
|
|
199
|
+
const gsdDir = join(basePath, '.gsd');
|
|
200
|
+
mkdirSync(join(gsdDir, 'milestones'), { recursive: true });
|
|
201
|
+
mkdirSync(join(gsdDir, 'runtime'), { recursive: true });
|
|
202
|
+
}
|
|
151
203
|
export async function runHeadless(options) {
|
|
152
204
|
const startTime = Date.now();
|
|
153
|
-
|
|
205
|
+
const isNewMilestone = options.command === 'new-milestone';
|
|
206
|
+
// For new-milestone, load context and bootstrap .gsd/ before spawning RPC child
|
|
207
|
+
if (isNewMilestone) {
|
|
208
|
+
if (!options.context && !options.contextText) {
|
|
209
|
+
process.stderr.write('[headless] Error: new-milestone requires --context <file> or --context-text <text>\n');
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
let contextContent;
|
|
213
|
+
try {
|
|
214
|
+
contextContent = await loadContext(options);
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
process.stderr.write(`[headless] Error loading context: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
// Bootstrap .gsd/ if needed
|
|
221
|
+
const gsdDir = join(process.cwd(), '.gsd');
|
|
222
|
+
if (!existsSync(gsdDir)) {
|
|
223
|
+
if (!options.json) {
|
|
224
|
+
process.stderr.write('[headless] Bootstrapping .gsd/ project structure...\n');
|
|
225
|
+
}
|
|
226
|
+
bootstrapGsdProject(process.cwd());
|
|
227
|
+
}
|
|
228
|
+
// Write context to temp file for the RPC child to read
|
|
229
|
+
const runtimeDir = join(gsdDir, 'runtime');
|
|
230
|
+
mkdirSync(runtimeDir, { recursive: true });
|
|
231
|
+
writeFileSync(join(runtimeDir, 'headless-context.md'), contextContent, 'utf-8');
|
|
232
|
+
}
|
|
233
|
+
// Validate .gsd/ directory (skip for new-milestone since we just bootstrapped it)
|
|
154
234
|
const gsdDir = join(process.cwd(), '.gsd');
|
|
155
|
-
if (!existsSync(gsdDir)) {
|
|
235
|
+
if (!isNewMilestone && !existsSync(gsdDir)) {
|
|
156
236
|
process.stderr.write('[headless] Error: No .gsd/ directory found in current directory.\n');
|
|
157
237
|
process.stderr.write("[headless] Run 'gsd' interactively first to initialize a project.\n");
|
|
158
238
|
process.exit(1);
|
|
@@ -178,6 +258,7 @@ export async function runHeadless(options) {
|
|
|
178
258
|
let blocked = false;
|
|
179
259
|
let completed = false;
|
|
180
260
|
let exitCode = 0;
|
|
261
|
+
let milestoneReady = false; // tracks "Milestone X ready." for auto-chaining
|
|
181
262
|
const recentEvents = [];
|
|
182
263
|
function trackEvent(event) {
|
|
183
264
|
totalEvents++;
|
|
@@ -231,7 +312,7 @@ export async function runHeadless(options) {
|
|
|
231
312
|
}
|
|
232
313
|
else {
|
|
233
314
|
// Progress output to stderr
|
|
234
|
-
const line = formatProgress(eventObj);
|
|
315
|
+
const line = formatProgress(eventObj, !!options.verbose);
|
|
235
316
|
if (line)
|
|
236
317
|
process.stderr.write(line + '\n');
|
|
237
318
|
}
|
|
@@ -241,6 +322,10 @@ export async function runHeadless(options) {
|
|
|
241
322
|
if (isBlockedNotification(eventObj)) {
|
|
242
323
|
blocked = true;
|
|
243
324
|
}
|
|
325
|
+
// Detect "Milestone X ready." for auto-mode chaining
|
|
326
|
+
if (isMilestoneReadyNotification(eventObj)) {
|
|
327
|
+
milestoneReady = true;
|
|
328
|
+
}
|
|
244
329
|
if (isTerminalNotification(eventObj)) {
|
|
245
330
|
completed = true;
|
|
246
331
|
}
|
|
@@ -319,6 +404,29 @@ export async function runHeadless(options) {
|
|
|
319
404
|
if (exitCode === 0 || exitCode === 2) {
|
|
320
405
|
await completionPromise;
|
|
321
406
|
}
|
|
407
|
+
// Auto-mode chaining: if --auto and milestone creation succeeded, send /gsd auto
|
|
408
|
+
if (isNewMilestone && options.auto && milestoneReady && !blocked && exitCode === 0) {
|
|
409
|
+
if (!options.json) {
|
|
410
|
+
process.stderr.write('[headless] Milestone ready — chaining into auto-mode...\n');
|
|
411
|
+
}
|
|
412
|
+
// Reset completion state for the auto-mode phase
|
|
413
|
+
completed = false;
|
|
414
|
+
milestoneReady = false;
|
|
415
|
+
blocked = false;
|
|
416
|
+
const autoCompletionPromise = new Promise((resolve) => {
|
|
417
|
+
resolveCompletion = resolve;
|
|
418
|
+
});
|
|
419
|
+
try {
|
|
420
|
+
await client.prompt('/gsd auto');
|
|
421
|
+
}
|
|
422
|
+
catch (err) {
|
|
423
|
+
process.stderr.write(`[headless] Error: Failed to start auto-mode: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
424
|
+
exitCode = 1;
|
|
425
|
+
}
|
|
426
|
+
if (exitCode === 0 || exitCode === 2) {
|
|
427
|
+
await autoCompletionPromise;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
322
430
|
// Cleanup
|
|
323
431
|
clearTimeout(timeoutTimer);
|
|
324
432
|
if (idleTimer)
|
package/dist/help-text.js
CHANGED
|
@@ -35,15 +35,30 @@ const SUBCOMMAND_HELP = {
|
|
|
35
35
|
'Run /gsd commands without the TUI. Default command: auto',
|
|
36
36
|
'',
|
|
37
37
|
'Flags:',
|
|
38
|
-
' --timeout N
|
|
39
|
-
' --json
|
|
40
|
-
' --model ID
|
|
38
|
+
' --timeout N Overall timeout in ms (default: 300000)',
|
|
39
|
+
' --json JSONL event stream to stdout',
|
|
40
|
+
' --model ID Override model',
|
|
41
|
+
'',
|
|
42
|
+
'Commands:',
|
|
43
|
+
' auto Run all queued units continuously (default)',
|
|
44
|
+
' next Run one unit',
|
|
45
|
+
' status Show progress dashboard',
|
|
46
|
+
' new-milestone Create a milestone from a specification document',
|
|
47
|
+
'',
|
|
48
|
+
'new-milestone flags:',
|
|
49
|
+
' --context <path> Path to spec/PRD file (use \'-\' for stdin)',
|
|
50
|
+
' --context-text <txt> Inline specification text',
|
|
51
|
+
' --auto Start auto-mode after milestone creation',
|
|
52
|
+
' --verbose Show tool calls in progress output',
|
|
41
53
|
'',
|
|
42
54
|
'Examples:',
|
|
43
|
-
' gsd headless
|
|
44
|
-
' gsd headless next
|
|
45
|
-
' gsd headless --json status
|
|
46
|
-
' gsd headless --timeout 60000
|
|
55
|
+
' gsd headless Run /gsd auto',
|
|
56
|
+
' gsd headless next Run one unit',
|
|
57
|
+
' gsd headless --json status Machine-readable status',
|
|
58
|
+
' gsd headless --timeout 60000 With 1-minute timeout',
|
|
59
|
+
' gsd headless new-milestone --context spec.md Create milestone from file',
|
|
60
|
+
' cat spec.md | gsd headless new-milestone --context - From stdin',
|
|
61
|
+
' gsd headless new-milestone --context spec.md --auto Create + auto-execute',
|
|
47
62
|
'',
|
|
48
63
|
'Exit codes: 0 = complete, 1 = error/timeout, 2 = blocked',
|
|
49
64
|
].join('\n'),
|
|
@@ -19,14 +19,3 @@
|
|
|
19
19
|
* @returns The path to use for models.json
|
|
20
20
|
*/
|
|
21
21
|
export declare function resolveModelsJsonPath(): string;
|
|
22
|
-
/**
|
|
23
|
-
* Check if both GSD and PI models.json files exist.
|
|
24
|
-
*/
|
|
25
|
-
export declare function hasBothModelsFiles(): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Get the paths to both models.json files.
|
|
28
|
-
*/
|
|
29
|
-
export declare function getModelsPaths(): {
|
|
30
|
-
gsd: string;
|
|
31
|
-
pi: string;
|
|
32
|
-
};
|
package/dist/models-resolver.js
CHANGED
|
@@ -33,18 +33,3 @@ export function resolveModelsJsonPath() {
|
|
|
33
33
|
}
|
|
34
34
|
return GSD_MODELS_PATH;
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Check if both GSD and PI models.json files exist.
|
|
38
|
-
*/
|
|
39
|
-
export function hasBothModelsFiles() {
|
|
40
|
-
return existsSync(GSD_MODELS_PATH) && existsSync(PI_MODELS_PATH);
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Get the paths to both models.json files.
|
|
44
|
-
*/
|
|
45
|
-
export function getModelsPaths() {
|
|
46
|
-
return {
|
|
47
|
-
gsd: GSD_MODELS_PATH,
|
|
48
|
-
pi: PI_MODELS_PATH,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { DefaultResourceLoader } from '@gsd/pi-coding-agent';
|
|
2
2
|
export declare function discoverExtensionEntryPaths(extensionsDir: string): string[];
|
|
3
3
|
export declare function readManagedResourceVersion(agentDir: string): string | null;
|
|
4
|
-
export declare function readManagedResourceSyncedAt(agentDir: string): number | null;
|
|
5
4
|
export declare function getNewerManagedResourceVersion(agentDir: string, currentVersion: string): string | null;
|
|
6
5
|
/**
|
|
7
6
|
* Syncs all bundled resources to agentDir (~/.gsd/agent/) on every launch.
|
package/dist/resource-loader.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DefaultResourceLoader } from '@gsd/pi-coding-agent';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { compareSemver } from './update-check.js';
|
|
@@ -97,15 +97,6 @@ export function readManagedResourceVersion(agentDir) {
|
|
|
97
97
|
return null;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
export function readManagedResourceSyncedAt(agentDir) {
|
|
101
|
-
try {
|
|
102
|
-
const manifest = JSON.parse(readFileSync(getManagedResourceManifestPath(agentDir), 'utf-8'));
|
|
103
|
-
return typeof manifest?.syncedAt === 'number' ? manifest.syncedAt : null;
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
100
|
export function getNewerManagedResourceVersion(agentDir, currentVersion) {
|
|
110
101
|
const managedVersion = readManagedResourceVersion(agentDir);
|
|
111
102
|
if (!managedVersion) {
|
|
@@ -113,6 +104,38 @@ export function getNewerManagedResourceVersion(agentDir, currentVersion) {
|
|
|
113
104
|
}
|
|
114
105
|
return compareSemver(managedVersion, currentVersion) > 0 ? managedVersion : null;
|
|
115
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Recursively makes all files and directories under dirPath owner-writable.
|
|
109
|
+
*
|
|
110
|
+
* Files copied from the Nix store inherit read-only modes (0444/0555).
|
|
111
|
+
* Calling this before cpSync prevents overwrite failures on subsequent upgrades,
|
|
112
|
+
* and calling it after ensures the next run can overwrite the copies too.
|
|
113
|
+
*
|
|
114
|
+
* Preserves existing permission bits (including executability) and only adds
|
|
115
|
+
* owner-write (and for directories, owner-exec) without widening group/other
|
|
116
|
+
* permissions.
|
|
117
|
+
*/
|
|
118
|
+
function makeTreeWritable(dirPath) {
|
|
119
|
+
if (!existsSync(dirPath))
|
|
120
|
+
return;
|
|
121
|
+
const stats = statSync(dirPath);
|
|
122
|
+
const isDir = stats.isDirectory();
|
|
123
|
+
const currentMode = stats.mode & 0o777;
|
|
124
|
+
// Ensure owner-write; for directories also ensure owner-exec so they remain traversable.
|
|
125
|
+
let newMode = currentMode | 0o200;
|
|
126
|
+
if (isDir) {
|
|
127
|
+
newMode |= 0o100;
|
|
128
|
+
}
|
|
129
|
+
if (newMode !== currentMode) {
|
|
130
|
+
chmodSync(dirPath, newMode);
|
|
131
|
+
}
|
|
132
|
+
if (isDir) {
|
|
133
|
+
for (const entry of readdirSync(dirPath, { withFileTypes: true })) {
|
|
134
|
+
const entryPath = join(dirPath, entry.name);
|
|
135
|
+
makeTreeWritable(entryPath);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
116
139
|
/**
|
|
117
140
|
* Syncs all bundled resources to agentDir (~/.gsd/agent/) on every launch.
|
|
118
141
|
*
|
|
@@ -130,26 +153,49 @@ export function getNewerManagedResourceVersion(agentDir, currentVersion) {
|
|
|
130
153
|
*/
|
|
131
154
|
export function initResources(agentDir) {
|
|
132
155
|
mkdirSync(agentDir, { recursive: true });
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (managedVersion && managedVersion === currentVersion) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
// Sync extensions — overwrite so updates land on next launch
|
|
156
|
+
// Sync extensions — clean bundled subdirs first to remove stale leftover files,
|
|
157
|
+
// then overwrite so updates land on next launch. Only bundled subdirs are removed;
|
|
158
|
+
// user-created extension directories are preserved.
|
|
140
159
|
const destExtensions = join(agentDir, 'extensions');
|
|
160
|
+
makeTreeWritable(destExtensions);
|
|
161
|
+
for (const entry of readdirSync(bundledExtensionsDir, { withFileTypes: true })) {
|
|
162
|
+
if (entry.isDirectory()) {
|
|
163
|
+
const target = join(destExtensions, entry.name);
|
|
164
|
+
if (existsSync(target))
|
|
165
|
+
rmSync(target, { recursive: true, force: true });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
141
168
|
cpSync(bundledExtensionsDir, destExtensions, { recursive: true, force: true });
|
|
169
|
+
makeTreeWritable(destExtensions);
|
|
142
170
|
// Sync agents
|
|
143
171
|
const destAgents = join(agentDir, 'agents');
|
|
144
172
|
const srcAgents = join(resourcesDir, 'agents');
|
|
145
173
|
if (existsSync(srcAgents)) {
|
|
174
|
+
makeTreeWritable(destAgents);
|
|
175
|
+
for (const entry of readdirSync(srcAgents, { withFileTypes: true })) {
|
|
176
|
+
if (entry.isDirectory()) {
|
|
177
|
+
const target = join(destAgents, entry.name);
|
|
178
|
+
if (existsSync(target))
|
|
179
|
+
rmSync(target, { recursive: true, force: true });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
146
182
|
cpSync(srcAgents, destAgents, { recursive: true, force: true });
|
|
183
|
+
makeTreeWritable(destAgents);
|
|
147
184
|
}
|
|
148
|
-
// Sync skills
|
|
185
|
+
// Sync skills
|
|
149
186
|
const destSkills = join(agentDir, 'skills');
|
|
150
187
|
const srcSkills = join(resourcesDir, 'skills');
|
|
151
188
|
if (existsSync(srcSkills)) {
|
|
189
|
+
makeTreeWritable(destSkills);
|
|
190
|
+
for (const entry of readdirSync(srcSkills, { withFileTypes: true })) {
|
|
191
|
+
if (entry.isDirectory()) {
|
|
192
|
+
const target = join(destSkills, entry.name);
|
|
193
|
+
if (existsSync(target))
|
|
194
|
+
rmSync(target, { recursive: true, force: true });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
152
197
|
cpSync(srcSkills, destSkills, { recursive: true, force: true });
|
|
198
|
+
makeTreeWritable(destSkills);
|
|
153
199
|
}
|
|
154
200
|
writeManagedResourceManifest(agentDir);
|
|
155
201
|
}
|
|
@@ -565,25 +565,28 @@ One commit per slice. Individually revertable. Reads like a changelog.
|
|
|
565
565
|
|
|
566
566
|
```
|
|
567
567
|
gsd/M001/S01:
|
|
568
|
-
test(S01): round-trip tests passing
|
|
568
|
+
test(S01/T03): round-trip tests passing
|
|
569
569
|
feat(S01/T03): file writer with round-trip fidelity
|
|
570
|
-
chore(S01/T03): auto-commit after task
|
|
571
570
|
feat(S01/T02): markdown parser for plan files
|
|
572
|
-
chore(S01/T02): auto-commit after task
|
|
573
571
|
feat(S01/T01): core types and interfaces
|
|
574
|
-
|
|
572
|
+
docs(S01): add slice plan
|
|
575
573
|
```
|
|
576
574
|
|
|
577
575
|
### Commit Conventions
|
|
578
576
|
|
|
579
577
|
| When | Format | Example |
|
|
580
578
|
|------|--------|---------|
|
|
581
|
-
|
|
|
582
|
-
|
|
|
583
|
-
|
|
|
584
|
-
|
|
|
579
|
+
| Task completed | `{type}(S01/T02): <one-liner from summary>` | Type inferred from title (`feat`, `fix`, `test`, etc.) |
|
|
580
|
+
| Plan/docs committed | `docs(S01): add slice plan` | Planning artifacts |
|
|
581
|
+
| Slice squash to main | `type(M001/S01): <slice title>` | Type inferred from title |
|
|
582
|
+
| State rebuild | `chore(S01/T02): auto-commit after state-rebuild` | Bookkeeping only |
|
|
585
583
|
|
|
586
|
-
|
|
584
|
+
The system reads the task summary after execution and builds a meaningful commit message:
|
|
585
|
+
- **Subject**: `{type}({sliceId}/{taskId}): {one-liner}` — the one-liner from the summary frontmatter
|
|
586
|
+
- **Type**: Inferred from the task title and one-liner (`feat`, `fix`, `test`, `refactor`, `docs`, `perf`, `chore`)
|
|
587
|
+
- **Body**: Key files from the summary frontmatter (up to 8 files listed)
|
|
588
|
+
|
|
589
|
+
Commit types: `feat`, `fix`, `test`, `refactor`, `docs`, `perf`, `chore`
|
|
587
590
|
|
|
588
591
|
### Squash Merge Message
|
|
589
592
|
|
|
@@ -328,12 +328,9 @@ export class BgManagerOverlay {
|
|
|
328
328
|
return this.box(inner, width);
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
private
|
|
331
|
+
private processStatusHeader(p: typeof this.viewingProcess, activeTab: "output" | "events"): { statusIcon: string; headerLine: string } {
|
|
332
332
|
const th = this.theme;
|
|
333
|
-
|
|
334
|
-
if (!p) return [""];
|
|
335
|
-
const inner: string[] = [];
|
|
336
|
-
|
|
333
|
+
if (!p) return { statusIcon: "", headerLine: "" };
|
|
337
334
|
const statusIcon = p.alive
|
|
338
335
|
? (p.status === "ready" ? th.fg("success", "●")
|
|
339
336
|
: p.status === "error" ? th.fg("error", "●")
|
|
@@ -343,9 +340,21 @@ export class BgManagerOverlay {
|
|
|
343
340
|
const uptime = th.fg("dim", formatUptime(Date.now() - p.startedAt));
|
|
344
341
|
const typeTag = th.fg("dim", `[${p.processType}]`);
|
|
345
342
|
const portInfo = p.ports.length > 0 ? th.fg("dim", ` :${p.ports.join(",")}`) : "";
|
|
346
|
-
const tabIndicator =
|
|
343
|
+
const tabIndicator = activeTab === "output"
|
|
344
|
+
? th.fg("accent", "[Output]") + " " + th.fg("dim", "Events")
|
|
345
|
+
: th.fg("dim", "Output") + " " + th.fg("accent", "[Events]");
|
|
346
|
+
const headerLine = `${statusIcon} ${name} ${typeTag} ${uptime}${portInfo} ${tabIndicator}`;
|
|
347
|
+
return { statusIcon, headerLine };
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private renderOutput(width: number): string[] {
|
|
351
|
+
const th = this.theme;
|
|
352
|
+
const p = this.viewingProcess;
|
|
353
|
+
if (!p) return [""];
|
|
354
|
+
const inner: string[] = [];
|
|
347
355
|
|
|
348
|
-
|
|
356
|
+
const { headerLine } = this.processStatusHeader(p, "output");
|
|
357
|
+
inner.push(headerLine);
|
|
349
358
|
inner.push("");
|
|
350
359
|
|
|
351
360
|
// Unified buffer is already chronologically interleaved
|
|
@@ -384,16 +393,8 @@ export class BgManagerOverlay {
|
|
|
384
393
|
if (!p) return [""];
|
|
385
394
|
const inner: string[] = [];
|
|
386
395
|
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
: p.status === "error" ? th.fg("error", "●")
|
|
390
|
-
: th.fg("warning", "●"))
|
|
391
|
-
: th.fg("dim", "○");
|
|
392
|
-
const name = th.fg("muted", p.label);
|
|
393
|
-
const uptime = th.fg("dim", formatUptime(Date.now() - p.startedAt));
|
|
394
|
-
const tabIndicator = th.fg("dim", "Output") + " " + th.fg("accent", "[Events]");
|
|
395
|
-
|
|
396
|
-
inner.push(`${statusIcon} ${name} ${uptime} ${tabIndicator}`);
|
|
396
|
+
const { headerLine } = this.processStatusHeader(p, "events");
|
|
397
|
+
inner.push(headerLine);
|
|
397
398
|
inner.push("");
|
|
398
399
|
|
|
399
400
|
if (p.events.length === 0) {
|
|
@@ -369,32 +369,14 @@ async function applySecrets(
|
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
-
if (destination === "vercel" && opts.exec) {
|
|
372
|
+
if ((destination === "vercel" || destination === "convex") && opts.exec) {
|
|
373
373
|
const env = opts.environment ?? "development";
|
|
374
374
|
for (const { key, value } of provided) {
|
|
375
|
+
const cmd = destination === "vercel"
|
|
376
|
+
? `printf %s ${shellEscapeSingle(value)} | vercel env add ${key} ${env}`
|
|
377
|
+
: `npx convex env set ${key} ${shellEscapeSingle(value)}`;
|
|
375
378
|
try {
|
|
376
|
-
const result = await opts.exec("sh", [
|
|
377
|
-
"-c",
|
|
378
|
-
`printf %s ${shellEscapeSingle(value)} | vercel env add ${key} ${env}`,
|
|
379
|
-
]);
|
|
380
|
-
if (result.code !== 0) {
|
|
381
|
-
errors.push(`${key}: ${result.stderr.slice(0, 200)}`);
|
|
382
|
-
} else {
|
|
383
|
-
applied.push(key);
|
|
384
|
-
}
|
|
385
|
-
} catch (err: any) {
|
|
386
|
-
errors.push(`${key}: ${err.message}`);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if (destination === "convex" && opts.exec) {
|
|
392
|
-
for (const { key, value } of provided) {
|
|
393
|
-
try {
|
|
394
|
-
const result = await opts.exec("sh", [
|
|
395
|
-
"-c",
|
|
396
|
-
`npx convex env set ${key} ${shellEscapeSingle(value)}`,
|
|
397
|
-
]);
|
|
379
|
+
const result = await opts.exec("sh", ["-c", cmd]);
|
|
398
380
|
if (result.code !== 0) {
|
|
399
381
|
errors.push(`${key}: ${result.stderr.slice(0, 200)}`);
|
|
400
382
|
} else {
|
|
@@ -103,10 +103,10 @@ export function saveActivityLog(
|
|
|
103
103
|
basePath: string,
|
|
104
104
|
unitType: string,
|
|
105
105
|
unitId: string,
|
|
106
|
-
):
|
|
106
|
+
): string | null {
|
|
107
107
|
try {
|
|
108
108
|
const entries = ctx.sessionManager.getEntries();
|
|
109
|
-
if (!entries || entries.length === 0) return;
|
|
109
|
+
if (!entries || entries.length === 0) return null;
|
|
110
110
|
|
|
111
111
|
const activityDir = join(gsdRoot(basePath), "activity");
|
|
112
112
|
mkdirSync(activityDir, { recursive: true });
|
|
@@ -116,7 +116,7 @@ export function saveActivityLog(
|
|
|
116
116
|
const unitKey = `${unitType}\0${safeUnitId}`;
|
|
117
117
|
// Use lightweight fingerprint instead of serializing all entries (#611)
|
|
118
118
|
const key = snapshotKey(unitType, safeUnitId, entries);
|
|
119
|
-
if (state.lastSnapshotKeyByUnit.get(unitKey) === key) return;
|
|
119
|
+
if (state.lastSnapshotKeyByUnit.get(unitKey) === key) return null;
|
|
120
120
|
|
|
121
121
|
const filePath = nextActivityFilePath(activityDir, state, unitType, safeUnitId);
|
|
122
122
|
// Stream entries to disk line-by-line instead of building one massive string (#611).
|
|
@@ -131,9 +131,11 @@ export function saveActivityLog(
|
|
|
131
131
|
}
|
|
132
132
|
state.nextSeq += 1;
|
|
133
133
|
state.lastSnapshotKeyByUnit.set(unitKey, key);
|
|
134
|
+
return filePath;
|
|
134
135
|
} catch (e) {
|
|
135
136
|
// Don't let logging failures break auto-mode
|
|
136
137
|
void e;
|
|
138
|
+
return null;
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
|