gsd-pi 2.44.0-dev.73f2fd5 → 2.44.0-dev.8894d5b
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/resources/extensions/gsd/auto/infra-errors.js +0 -3
- package/dist/resources/extensions/gsd/auto/phases.js +36 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +1 -24
- package/dist/resources/extensions/gsd/auto-timers.js +3 -57
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -4
- package/dist/resources/extensions/gsd/auto-worktree.js +6 -9
- package/dist/resources/extensions/gsd/auto.js +3 -30
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +0 -136
- package/dist/resources/extensions/gsd/commands/catalog.js +1 -6
- package/dist/resources/extensions/gsd/commands/handlers/core.js +0 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +0 -5
- package/dist/resources/extensions/gsd/db-writer.js +16 -34
- package/dist/resources/extensions/gsd/doctor.js +0 -8
- package/dist/resources/extensions/gsd/git-service.js +3 -8
- package/dist/resources/extensions/gsd/gsd-db.js +1 -12
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +4 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +14 -3
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +37 -7
- package/dist/resources/extensions/gsd/provider-error-pause.js +0 -7
- package/dist/resources/extensions/gsd/tools/plan-slice.js +0 -1
- package/dist/resources/extensions/gsd/tools/plan-task.js +0 -1
- package/dist/resources/extensions/gsd/tools/replan-slice.js +0 -2
- package/dist/resources/extensions/gsd/worktree-resolver.js +0 -6
- package/dist/resources/extensions/mcp-client/index.js +0 -14
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +20 -20
- 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 +2 -2
- 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 +20 -20
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +1 -3
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +1 -15
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +0 -11
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -20
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +0 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +0 -6
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +0 -17
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -3
- 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 +1 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +0 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.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 +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +2 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- 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 +8 -17
- 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 +3 -7
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.ts +1 -15
- package/packages/pi-coding-agent/src/core/model-registry.ts +1 -21
- package/packages/pi-coding-agent/src/core/settings-manager.ts +0 -9
- package/packages/pi-coding-agent/src/main.ts +0 -19
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +0 -10
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +0 -15
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +3 -18
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +7 -16
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +1 -8
- package/src/resources/extensions/gsd/auto/infra-errors.ts +0 -3
- package/src/resources/extensions/gsd/auto/phases.ts +48 -45
- package/src/resources/extensions/gsd/auto-prompts.ts +1 -24
- package/src/resources/extensions/gsd/auto-timers.ts +3 -64
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -5
- package/src/resources/extensions/gsd/auto-worktree.ts +6 -9
- package/src/resources/extensions/gsd/auto.ts +3 -37
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +0 -129
- package/src/resources/extensions/gsd/commands/catalog.ts +1 -6
- package/src/resources/extensions/gsd/commands/handlers/core.ts +0 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +0 -5
- package/src/resources/extensions/gsd/db-writer.ts +17 -39
- package/src/resources/extensions/gsd/doctor.ts +1 -7
- package/src/resources/extensions/gsd/git-service.ts +2 -6
- package/src/resources/extensions/gsd/gsd-db.ts +1 -16
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +4 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +14 -3
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +37 -7
- package/src/resources/extensions/gsd/provider-error-pause.ts +0 -9
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -20
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -11
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -2
- package/src/resources/extensions/gsd/tools/plan-slice.ts +0 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +0 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +0 -3
- package/src/resources/extensions/gsd/worktree-resolver.ts +0 -7
- package/src/resources/extensions/mcp-client/index.ts +0 -20
- package/dist/resources/extensions/gsd/commands-mcp-status.js +0 -187
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +0 -88
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +0 -15
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/local-model-check.js +0 -41
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +0 -32
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +0 -15
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +0 -40
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +0 -1
- package/packages/pi-coding-agent/src/core/local-model-check.ts +0 -45
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +0 -38
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +0 -48
- package/src/resources/extensions/gsd/commands-mcp-status.ts +0 -247
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +0 -88
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +0 -114
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +0 -120
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +0 -66
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +0 -67
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +0 -49
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +0 -127
- /package/dist/web/standalone/.next/static/{kxxAA66bah_yhPYqLBHE2 → oZMtyM-zfu6Inx-S59cOl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{kxxAA66bah_yhPYqLBHE2 → oZMtyM-zfu6Inx-S59cOl}/_ssgManifest.js +0 -0
|
@@ -744,21 +744,7 @@ export class AuthStorage {
|
|
|
744
744
|
* @param providerId - The provider to get an API key for
|
|
745
745
|
* @param sessionId - Optional session ID for sticky credential selection
|
|
746
746
|
*/
|
|
747
|
-
async getApiKey(providerId: string, sessionId?: string
|
|
748
|
-
// If the model has a local baseUrl, return a dummy key to avoid auth blocking
|
|
749
|
-
if (options?.baseUrl) {
|
|
750
|
-
try {
|
|
751
|
-
const hostname = new URL(options.baseUrl).hostname;
|
|
752
|
-
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
|
|
753
|
-
return "local-no-key-needed";
|
|
754
|
-
}
|
|
755
|
-
} catch {
|
|
756
|
-
if (options.baseUrl.startsWith("unix:")) {
|
|
757
|
-
return "local-no-key-needed";
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
|
|
747
|
+
async getApiKey(providerId: string, sessionId?: string): Promise<string | undefined> {
|
|
762
748
|
// Runtime override takes highest priority
|
|
763
749
|
const runtimeKey = this.runtimeOverrides.get(providerId);
|
|
764
750
|
if (runtimeKey) {
|
|
@@ -28,7 +28,6 @@ import { ModelDiscoveryCache } from "./discovery-cache.js";
|
|
|
28
28
|
import type { DiscoveredModel, DiscoveryResult } from "./model-discovery.js";
|
|
29
29
|
import { getDefaultTTL, getDiscoverableProviders, getDiscoveryAdapter } from "./model-discovery.js";
|
|
30
30
|
import { clearConfigValueCache, resolveConfigValue, resolveHeaders } from "./resolve-config-value.js";
|
|
31
|
-
import { isLocalModel } from "./local-model-check.js";
|
|
32
31
|
|
|
33
32
|
const Ajv = (AjvModule as any).default || AjvModule;
|
|
34
33
|
const ajv = new Ajv();
|
|
@@ -558,7 +557,7 @@ export class ModelRegistry {
|
|
|
558
557
|
async getApiKey(model: Model<Api>, sessionId?: string): Promise<string | undefined> {
|
|
559
558
|
const authMode = this.getProviderAuthMode(model.provider);
|
|
560
559
|
if (authMode === "externalCli" || authMode === "none") return undefined;
|
|
561
|
-
return this.authStorage.getApiKey(model.provider, sessionId
|
|
560
|
+
return this.authStorage.getApiKey(model.provider, sessionId);
|
|
562
561
|
}
|
|
563
562
|
|
|
564
563
|
/**
|
|
@@ -808,25 +807,6 @@ export class ModelRegistry {
|
|
|
808
807
|
}
|
|
809
808
|
return converted;
|
|
810
809
|
}
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* Check if a model's baseUrl points to a local endpoint.
|
|
814
|
-
* Delegates to standalone isLocalModel() function.
|
|
815
|
-
*/
|
|
816
|
-
static isLocalModel(model: Model<Api>): boolean {
|
|
817
|
-
return isLocalModel(model);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
/**
|
|
821
|
-
* Check if all models in the registry are local.
|
|
822
|
-
* Returns true only if every model passes isLocalModel().
|
|
823
|
-
* Returns false if there are no models.
|
|
824
|
-
*/
|
|
825
|
-
isAllLocalChain(): boolean {
|
|
826
|
-
const models = this.getAll();
|
|
827
|
-
if (models.length === 0) return false;
|
|
828
|
-
return models.every((m) => isLocalModel(m));
|
|
829
|
-
}
|
|
830
810
|
}
|
|
831
811
|
|
|
832
812
|
/**
|
|
@@ -151,7 +151,6 @@ export interface Settings {
|
|
|
151
151
|
fallback?: FallbackSettings;
|
|
152
152
|
modelDiscovery?: ModelDiscoverySettings;
|
|
153
153
|
editMode?: "standard" | "hashline"; // Edit tool mode: "standard" (text match) or "hashline" (LINE#ID anchors). Default: "standard"
|
|
154
|
-
timestampFormat?: "date-time-iso" | "date-time-us"; // Timestamp display format for messages. Default: "date-time-iso"
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
|
|
@@ -1088,12 +1087,4 @@ export class SettingsManager {
|
|
|
1088
1087
|
setEditMode(mode: "standard" | "hashline"): void {
|
|
1089
1088
|
this.setGlobalSetting("editMode", mode);
|
|
1090
1089
|
}
|
|
1091
|
-
|
|
1092
|
-
getTimestampFormat(): "date-time-iso" | "date-time-us" {
|
|
1093
|
-
return this.settings.timestampFormat ?? "date-time-iso";
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
setTimestampFormat(format: "date-time-iso" | "date-time-us"): void {
|
|
1097
|
-
this.setGlobalSetting("timestampFormat", format);
|
|
1098
|
-
}
|
|
1099
1090
|
}
|
|
@@ -391,25 +391,6 @@ export async function main(args: string[]) {
|
|
|
391
391
|
const authStorage = AuthStorage.create();
|
|
392
392
|
const modelRegistry = new ModelRegistry(authStorage, getModelsPath());
|
|
393
393
|
|
|
394
|
-
// Offline mode validation / auto-detection
|
|
395
|
-
if (offlineMode) {
|
|
396
|
-
// --offline flag: validate all models are local
|
|
397
|
-
if (!modelRegistry.isAllLocalChain()) {
|
|
398
|
-
const remoteModel = modelRegistry.getAll().find((m) => !ModelRegistry.isLocalModel(m));
|
|
399
|
-
if (remoteModel) {
|
|
400
|
-
console.error(
|
|
401
|
-
`Error: --offline requires all configured models to be local. Found remote model: ${remoteModel.name} (${remoteModel.baseUrl || "cloud API"})`,
|
|
402
|
-
);
|
|
403
|
-
process.exit(1);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
} else if (modelRegistry.isAllLocalChain() && modelRegistry.getAll().length > 0) {
|
|
407
|
-
// Auto-detect: all models are local, enable offline mode
|
|
408
|
-
process.env.PI_OFFLINE = "1";
|
|
409
|
-
process.env.PI_SKIP_VERSION_CHECK = "1";
|
|
410
|
-
console.log("[gsd] All configured models are local \u2014 enabling offline mode automatically.");
|
|
411
|
-
}
|
|
412
|
-
|
|
413
394
|
const resourceLoader = new DefaultResourceLoader({
|
|
414
395
|
cwd,
|
|
415
396
|
agentDir,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { AssistantMessage } from "@gsd/pi-ai";
|
|
2
2
|
import { Container, Markdown, type MarkdownTheme, Spacer, Text } from "@gsd/pi-tui";
|
|
3
3
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
4
|
-
import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Component that renders a complete assistant message
|
|
@@ -11,19 +10,16 @@ export class AssistantMessageComponent extends Container {
|
|
|
11
10
|
private hideThinkingBlock: boolean;
|
|
12
11
|
private markdownTheme: MarkdownTheme;
|
|
13
12
|
private lastMessage?: AssistantMessage;
|
|
14
|
-
private timestampFormat: TimestampFormat;
|
|
15
13
|
|
|
16
14
|
constructor(
|
|
17
15
|
message?: AssistantMessage,
|
|
18
16
|
hideThinkingBlock = false,
|
|
19
17
|
markdownTheme: MarkdownTheme = getMarkdownTheme(),
|
|
20
|
-
timestampFormat: TimestampFormat = "date-time-iso",
|
|
21
18
|
) {
|
|
22
19
|
super();
|
|
23
20
|
|
|
24
21
|
this.hideThinkingBlock = hideThinkingBlock;
|
|
25
22
|
this.markdownTheme = markdownTheme;
|
|
26
|
-
this.timestampFormat = timestampFormat;
|
|
27
23
|
|
|
28
24
|
// Container for text/thinking content
|
|
29
25
|
this.contentContainer = new Container();
|
|
@@ -115,11 +111,5 @@ export class AssistantMessageComponent extends Container {
|
|
|
115
111
|
this.contentContainer.addChild(new Text(theme.fg("error", `Error: ${errorMsg}`), 1, 0));
|
|
116
112
|
}
|
|
117
113
|
}
|
|
118
|
-
|
|
119
|
-
// Show timestamp when the message is complete (has a stop reason)
|
|
120
|
-
if (message.stopReason && message.timestamp) {
|
|
121
|
-
const timeStr = formatTimestamp(message.timestamp, this.timestampFormat);
|
|
122
|
-
this.contentContainer.addChild(new Text(theme.fg("dim", timeStr), 1, 0));
|
|
123
|
-
}
|
|
124
114
|
}
|
|
125
115
|
}
|
|
@@ -45,7 +45,6 @@ export interface SettingsConfig {
|
|
|
45
45
|
respectGitignoreInPicker: boolean;
|
|
46
46
|
quietStartup: boolean;
|
|
47
47
|
clearOnShrink: boolean;
|
|
48
|
-
timestampFormat: "date-time-iso" | "date-time-us";
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
export interface SettingsCallbacks {
|
|
@@ -70,7 +69,6 @@ export interface SettingsCallbacks {
|
|
|
70
69
|
onRespectGitignoreInPickerChange: (enabled: boolean) => void;
|
|
71
70
|
onQuietStartupChange: (enabled: boolean) => void;
|
|
72
71
|
onClearOnShrinkChange: (enabled: boolean) => void;
|
|
73
|
-
onTimestampFormatChange: (format: "date-time-iso" | "date-time-us") => void;
|
|
74
72
|
onCancel: () => void;
|
|
75
73
|
}
|
|
76
74
|
|
|
@@ -357,16 +355,6 @@ export class SettingsSelectorComponent extends Container {
|
|
|
357
355
|
values: ["true", "false"],
|
|
358
356
|
});
|
|
359
357
|
|
|
360
|
-
// Timestamp format (insert after respect-gitignore-in-picker)
|
|
361
|
-
const gitignoreIndex = items.findIndex((item) => item.id === "respect-gitignore-in-picker");
|
|
362
|
-
items.splice(gitignoreIndex + 1, 0, {
|
|
363
|
-
id: "timestamp-format",
|
|
364
|
-
label: "Timestamp format",
|
|
365
|
-
description: "Date/time format for message timestamps",
|
|
366
|
-
currentValue: config.timestampFormat,
|
|
367
|
-
values: ["date-time-iso", "date-time-us"],
|
|
368
|
-
});
|
|
369
|
-
|
|
370
358
|
// Add borders
|
|
371
359
|
this.addChild(new DynamicBorder());
|
|
372
360
|
|
|
@@ -432,9 +420,6 @@ export class SettingsSelectorComponent extends Container {
|
|
|
432
420
|
case "respect-gitignore-in-picker":
|
|
433
421
|
callbacks.onRespectGitignoreInPickerChange(newValue === "true");
|
|
434
422
|
break;
|
|
435
|
-
case "timestamp-format":
|
|
436
|
-
callbacks.onTimestampFormatChange(newValue as "date-time-iso" | "date-time-us");
|
|
437
|
-
break;
|
|
438
423
|
}
|
|
439
424
|
},
|
|
440
425
|
callbacks.onCancel,
|
|
@@ -895,9 +895,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
895
895
|
// Server-side Anthropic web search
|
|
896
896
|
text = theme.fg("toolTitle", theme.bold("web search"));
|
|
897
897
|
|
|
898
|
-
if (
|
|
899
|
-
text += "\n\n" + theme.fg("muted", "\u{1F50C} Offline \u{2014} web search unavailable");
|
|
900
|
-
} else if (this.result) {
|
|
898
|
+
if (this.result) {
|
|
901
899
|
const output = this.getTextOutput().trim();
|
|
902
900
|
if (output) {
|
|
903
901
|
const lines = output.split("\n");
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
import { Container, Markdown, type MarkdownTheme, Spacer
|
|
1
|
+
import { Container, Markdown, type MarkdownTheme, Spacer } from "@gsd/pi-tui";
|
|
2
2
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
3
|
-
import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
|
|
4
3
|
|
|
5
4
|
const OSC133_ZONE_START = "\x1b]133;A\x07";
|
|
6
5
|
const OSC133_ZONE_END = "\x1b]133;B\x07";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
|
-
* Component that renders a user message
|
|
8
|
+
* Component that renders a user message
|
|
10
9
|
*/
|
|
11
10
|
export class UserMessageComponent extends Container {
|
|
12
|
-
|
|
13
|
-
private timestampFormat: TimestampFormat;
|
|
14
|
-
|
|
15
|
-
constructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), timestamp?: number, timestampFormat: TimestampFormat = "date-time-iso") {
|
|
11
|
+
constructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme()) {
|
|
16
12
|
super();
|
|
17
|
-
this.timestamp = timestamp;
|
|
18
|
-
this.timestampFormat = timestampFormat;
|
|
19
13
|
this.addChild(new Spacer(1));
|
|
20
14
|
this.addChild(
|
|
21
15
|
new Markdown(text, 1, 1, markdownTheme, {
|
|
@@ -31,15 +25,6 @@ export class UserMessageComponent extends Container {
|
|
|
31
25
|
return lines;
|
|
32
26
|
}
|
|
33
27
|
|
|
34
|
-
// Insert right-aligned timestamp above the message content
|
|
35
|
-
if (this.timestamp) {
|
|
36
|
-
const timeStr = formatTimestamp(this.timestamp, this.timestampFormat);
|
|
37
|
-
const label = theme.fg("dim", timeStr);
|
|
38
|
-
const padding = Math.max(0, width - timeStr.length - 1);
|
|
39
|
-
const timestampLine = " ".repeat(padding) + label;
|
|
40
|
-
lines.splice(0, 0, timestampLine);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
28
|
lines[0] = OSC133_ZONE_START + lines[0];
|
|
44
29
|
lines[lines.length - 1] = lines[lines.length - 1] + OSC133_ZONE_END;
|
|
45
30
|
return lines;
|
|
@@ -100,7 +100,6 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
100
100
|
undefined,
|
|
101
101
|
host.hideThinkingBlock,
|
|
102
102
|
host.getMarkdownThemeWithSettings(),
|
|
103
|
-
host.settingsManager.getTimestampFormat(),
|
|
104
103
|
);
|
|
105
104
|
host.streamingMessage = event.message;
|
|
106
105
|
host.chatContainer.addChild(host.streamingComponent);
|
|
@@ -145,21 +144,13 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
145
144
|
} else if (content.type === "webSearchResult") {
|
|
146
145
|
const component = host.pendingTools.get(content.toolUseId);
|
|
147
146
|
if (component) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const searchContent = content.content;
|
|
156
|
-
const isError = searchContent && typeof searchContent === "object" && "type" in (searchContent as any) && (searchContent as any).type === "web_search_tool_result_error";
|
|
157
|
-
component.updateResult({
|
|
158
|
-
content: [{ type: "text", text: host.formatWebSearchResult(searchContent) }],
|
|
159
|
-
isError: !!isError,
|
|
160
|
-
});
|
|
161
|
-
host.pendingTools.delete(content.toolUseId);
|
|
162
|
-
}
|
|
147
|
+
const searchContent = content.content;
|
|
148
|
+
const isError = searchContent && typeof searchContent === "object" && "type" in (searchContent as any) && (searchContent as any).type === "web_search_tool_result_error";
|
|
149
|
+
component.updateResult({
|
|
150
|
+
content: [{ type: "text", text: host.formatWebSearchResult(searchContent) }],
|
|
151
|
+
isError: !!isError,
|
|
152
|
+
});
|
|
153
|
+
host.pendingTools.delete(content.toolUseId);
|
|
163
154
|
}
|
|
164
155
|
}
|
|
165
156
|
}
|
|
@@ -2099,13 +2099,11 @@ export class InteractiveMode {
|
|
|
2099
2099
|
const userComponent = new UserMessageComponent(
|
|
2100
2100
|
skillBlock.userMessage,
|
|
2101
2101
|
this.getMarkdownThemeWithSettings(),
|
|
2102
|
-
message.timestamp,
|
|
2103
|
-
this.settingsManager.getTimestampFormat(),
|
|
2104
2102
|
);
|
|
2105
2103
|
this.chatContainer.addChild(userComponent);
|
|
2106
2104
|
}
|
|
2107
2105
|
} else {
|
|
2108
|
-
const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings()
|
|
2106
|
+
const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings());
|
|
2109
2107
|
this.chatContainer.addChild(userComponent);
|
|
2110
2108
|
}
|
|
2111
2109
|
if (options?.populateHistory) {
|
|
@@ -2119,7 +2117,6 @@ export class InteractiveMode {
|
|
|
2119
2117
|
message,
|
|
2120
2118
|
this.hideThinkingBlock,
|
|
2121
2119
|
this.getMarkdownThemeWithSettings(),
|
|
2122
|
-
this.settingsManager.getTimestampFormat(),
|
|
2123
2120
|
);
|
|
2124
2121
|
this.chatContainer.addChild(assistantComponent);
|
|
2125
2122
|
break;
|
|
@@ -2798,7 +2795,6 @@ export class InteractiveMode {
|
|
|
2798
2795
|
respectGitignoreInPicker: this.settingsManager.getRespectGitignoreInPicker(),
|
|
2799
2796
|
quietStartup: this.settingsManager.getQuietStartup(),
|
|
2800
2797
|
clearOnShrink: this.settingsManager.getClearOnShrink(),
|
|
2801
|
-
timestampFormat: this.settingsManager.getTimestampFormat(),
|
|
2802
2798
|
},
|
|
2803
2799
|
{
|
|
2804
2800
|
onAutoCompactChange: (enabled) => {
|
|
@@ -2902,9 +2898,6 @@ export class InteractiveMode {
|
|
|
2902
2898
|
this.settingsManager.setRespectGitignoreInPicker(enabled);
|
|
2903
2899
|
this.autocompleteProvider?.setRespectGitignore(enabled);
|
|
2904
2900
|
},
|
|
2905
|
-
onTimestampFormatChange: (format) => {
|
|
2906
|
-
this.settingsManager.setTimestampFormat(format);
|
|
2907
|
-
},
|
|
2908
2901
|
onCancel: () => {
|
|
2909
2902
|
done();
|
|
2910
2903
|
this.ui.requestRender();
|
|
@@ -18,9 +18,6 @@ export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
|
|
|
18
18
|
"EDQUOT", // disk quota exceeded
|
|
19
19
|
"EMFILE", // too many open files (process)
|
|
20
20
|
"ENFILE", // too many open files (system)
|
|
21
|
-
"ECONNREFUSED", // connection refused (offline / local server down)
|
|
22
|
-
"ENOTFOUND", // DNS lookup failed (offline / no network)
|
|
23
|
-
"ENETUNREACH", // network unreachable (offline / no route)
|
|
24
21
|
]);
|
|
25
22
|
|
|
26
23
|
/**
|
|
@@ -27,9 +27,7 @@ import { debugLog } from "../debug-logger.js";
|
|
|
27
27
|
import { gsdRoot } from "../paths.js";
|
|
28
28
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
29
29
|
import { PROJECT_FILES } from "../detection.js";
|
|
30
|
-
import { MergeConflictError } from "../git-service.js";
|
|
31
30
|
import { join } from "node:path";
|
|
32
|
-
import { existsSync, cpSync } from "node:fs";
|
|
33
31
|
|
|
34
32
|
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
35
33
|
|
|
@@ -235,23 +233,26 @@ export async function runPreDispatch(
|
|
|
235
233
|
loopState.stuckRecoveryAttempts = 0;
|
|
236
234
|
|
|
237
235
|
// Worktree lifecycle on milestone transition — merge current, enter next
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
236
|
+
deps.resolver.mergeAndExit(s.currentMilestoneId!, ctx.ui);
|
|
237
|
+
|
|
238
|
+
// Opt-in: create draft PR on milestone completion
|
|
239
|
+
if (prefs?.git?.auto_pr) {
|
|
240
|
+
try {
|
|
241
|
+
const { createDraftPR } = await import("../git-service.js");
|
|
242
|
+
const prUrl = createDraftPR(
|
|
243
|
+
s.basePath,
|
|
244
|
+
s.currentMilestoneId!,
|
|
245
|
+
`[GSD] ${s.currentMilestoneId} complete`,
|
|
246
|
+
`Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
|
|
246
247
|
);
|
|
247
|
-
|
|
248
|
-
|
|
248
|
+
if (prUrl) {
|
|
249
|
+
ctx.ui.notify(`Draft PR created: ${prUrl}`, "info");
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
// Non-fatal — PR creation is best-effort
|
|
249
253
|
}
|
|
250
|
-
// Non-conflict errors — log and continue
|
|
251
254
|
}
|
|
252
255
|
|
|
253
|
-
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
254
|
-
|
|
255
256
|
deps.invalidateAllCaches();
|
|
256
257
|
|
|
257
258
|
state = await deps.deriveState(s.basePath);
|
|
@@ -278,17 +279,9 @@ export async function runPreDispatch(
|
|
|
278
279
|
// Reset completed-units tracking for the new milestone — stale entries
|
|
279
280
|
// from the previous milestone cause the dispatch loop to skip units
|
|
280
281
|
// that haven't actually been completed in the new milestone's context.
|
|
281
|
-
// Archive the old completed-units.json instead of wiping it (#2313).
|
|
282
282
|
s.completedUnits = [];
|
|
283
283
|
try {
|
|
284
284
|
const completedKeysPath = join(gsdRoot(s.basePath), "completed-units.json");
|
|
285
|
-
if (existsSync(completedKeysPath) && s.currentMilestoneId) {
|
|
286
|
-
const archivePath = join(
|
|
287
|
-
gsdRoot(s.basePath),
|
|
288
|
-
`completed-units-${s.currentMilestoneId}.json`,
|
|
289
|
-
);
|
|
290
|
-
cpSync(completedKeysPath, archivePath);
|
|
291
|
-
}
|
|
292
285
|
atomicWriteSync(completedKeysPath, JSON.stringify([], null, 2));
|
|
293
286
|
} catch { /* non-fatal */ }
|
|
294
287
|
|
|
@@ -329,20 +322,25 @@ export async function runPreDispatch(
|
|
|
329
322
|
if (incomplete.length === 0 && state.registry.length > 0) {
|
|
330
323
|
// All milestones complete — merge milestone branch before stopping
|
|
331
324
|
if (s.currentMilestoneId) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
325
|
+
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
326
|
+
|
|
327
|
+
// Opt-in: create draft PR on milestone completion
|
|
328
|
+
if (prefs?.git?.auto_pr) {
|
|
329
|
+
try {
|
|
330
|
+
const { createDraftPR } = await import("../git-service.js");
|
|
331
|
+
const prUrl = createDraftPR(
|
|
332
|
+
s.basePath,
|
|
333
|
+
s.currentMilestoneId,
|
|
334
|
+
`[GSD] ${s.currentMilestoneId} complete`,
|
|
335
|
+
`Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
|
|
339
336
|
);
|
|
340
|
-
|
|
341
|
-
|
|
337
|
+
if (prUrl) {
|
|
338
|
+
ctx.ui.notify(`Draft PR created: ${prUrl}`, "info");
|
|
339
|
+
}
|
|
340
|
+
} catch {
|
|
341
|
+
// Non-fatal — PR creation is best-effort
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
|
-
|
|
345
|
-
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
346
344
|
}
|
|
347
345
|
deps.sendDesktopNotification(
|
|
348
346
|
"GSD",
|
|
@@ -424,20 +422,25 @@ export async function runPreDispatch(
|
|
|
424
422
|
if (state.phase === "complete") {
|
|
425
423
|
// Milestone merge on complete (before closeout so branch state is clean)
|
|
426
424
|
if (s.currentMilestoneId) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
425
|
+
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
426
|
+
|
|
427
|
+
// Opt-in: create draft PR on milestone completion
|
|
428
|
+
if (prefs?.git?.auto_pr) {
|
|
429
|
+
try {
|
|
430
|
+
const { createDraftPR } = await import("../git-service.js");
|
|
431
|
+
const prUrl = createDraftPR(
|
|
432
|
+
s.basePath,
|
|
433
|
+
s.currentMilestoneId,
|
|
434
|
+
`[GSD] ${s.currentMilestoneId} complete`,
|
|
435
|
+
`Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
|
|
434
436
|
);
|
|
435
|
-
|
|
436
|
-
|
|
437
|
+
if (prUrl) {
|
|
438
|
+
ctx.ui.notify(`Draft PR created: ${prUrl}`, "info");
|
|
439
|
+
}
|
|
440
|
+
} catch {
|
|
441
|
+
// Non-fatal — PR creation is best-effort
|
|
437
442
|
}
|
|
438
443
|
}
|
|
439
|
-
|
|
440
|
-
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
441
444
|
}
|
|
442
445
|
deps.sendDesktopNotification(
|
|
443
446
|
"GSD",
|
|
@@ -1307,12 +1307,6 @@ export async function buildCompleteMilestonePrompt(
|
|
|
1307
1307
|
roadmapPath: roadmapRel,
|
|
1308
1308
|
inlinedContext,
|
|
1309
1309
|
milestoneSummaryPath,
|
|
1310
|
-
skillActivation: buildSkillActivationBlock({
|
|
1311
|
-
base,
|
|
1312
|
-
milestoneId: mid,
|
|
1313
|
-
milestoneTitle: midTitle,
|
|
1314
|
-
extraContext: [inlinedContext],
|
|
1315
|
-
}),
|
|
1316
1310
|
});
|
|
1317
1311
|
}
|
|
1318
1312
|
|
|
@@ -1396,12 +1390,6 @@ export async function buildValidateMilestonePrompt(
|
|
|
1396
1390
|
inlinedContext,
|
|
1397
1391
|
validationPath: validationOutputPath,
|
|
1398
1392
|
remediationRound: String(remediationRound),
|
|
1399
|
-
skillActivation: buildSkillActivationBlock({
|
|
1400
|
-
base,
|
|
1401
|
-
milestoneId: mid,
|
|
1402
|
-
milestoneTitle: midTitle,
|
|
1403
|
-
extraContext: [inlinedContext],
|
|
1404
|
-
}),
|
|
1405
1393
|
});
|
|
1406
1394
|
}
|
|
1407
1395
|
|
|
@@ -1512,12 +1500,6 @@ export async function buildRunUatPrompt(
|
|
|
1512
1500
|
uatResultPath,
|
|
1513
1501
|
uatType,
|
|
1514
1502
|
inlinedContext,
|
|
1515
|
-
skillActivation: buildSkillActivationBlock({
|
|
1516
|
-
base,
|
|
1517
|
-
milestoneId: mid,
|
|
1518
|
-
sliceId,
|
|
1519
|
-
extraContext: [inlinedContext],
|
|
1520
|
-
}),
|
|
1521
1503
|
});
|
|
1522
1504
|
}
|
|
1523
1505
|
|
|
@@ -1570,16 +1552,11 @@ export async function buildReassessRoadmapPrompt(
|
|
|
1570
1552
|
milestoneTitle: midTitle,
|
|
1571
1553
|
completedSliceId,
|
|
1572
1554
|
roadmapPath: roadmapRel,
|
|
1555
|
+
completedSliceSummaryPath: summaryRel,
|
|
1573
1556
|
assessmentPath,
|
|
1574
1557
|
inlinedContext,
|
|
1575
1558
|
deferredCaptures,
|
|
1576
1559
|
commitInstruction: reassessCommitInstruction,
|
|
1577
|
-
skillActivation: buildSkillActivationBlock({
|
|
1578
|
-
base,
|
|
1579
|
-
milestoneId: mid,
|
|
1580
|
-
milestoneTitle: midTitle,
|
|
1581
|
-
extraContext: [inlinedContext, deferredCaptures],
|
|
1582
|
-
}),
|
|
1583
1560
|
});
|
|
1584
1561
|
}
|
|
1585
1562
|
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
10
10
|
import { readUnitRuntimeRecord, writeUnitRuntimeRecord } from "./unit-runtime.js";
|
|
11
|
-
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
12
11
|
import { resolveAutoSupervisorConfig } from "./preferences.js";
|
|
13
12
|
import type { GSDPreferences } from "./preferences.js";
|
|
14
13
|
import { computeBudgets, resolveExecutorContextWindow } from "./context-budget.js";
|
|
@@ -33,8 +32,6 @@ export interface SupervisionContext {
|
|
|
33
32
|
buildSnapshotOpts: () => CloseoutOptions & Record<string, unknown>;
|
|
34
33
|
buildRecoveryContext: () => RecoveryContext;
|
|
35
34
|
pauseAuto: (ctx?: ExtensionContext, pi?: ExtensionAPI) => Promise<void>;
|
|
36
|
-
/** Optional task estimate string (e.g. "30m", "2h") for timeout scaling (#2243). */
|
|
37
|
-
taskEstimate?: string;
|
|
38
35
|
}
|
|
39
36
|
|
|
40
37
|
/**
|
|
@@ -44,71 +41,13 @@ export interface SupervisionContext {
|
|
|
44
41
|
* 3. Hard timeout (pause + recovery)
|
|
45
42
|
* 4. Context-pressure monitor (continue-here)
|
|
46
43
|
*/
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Parse a task estimate string (e.g. "30m", "2h", "1h30m") into minutes.
|
|
50
|
-
* Returns null if the string cannot be parsed.
|
|
51
|
-
*/
|
|
52
|
-
export function parseEstimateMinutes(estimate: string): number | null {
|
|
53
|
-
if (!estimate || typeof estimate !== "string") return null;
|
|
54
|
-
const trimmed = estimate.trim();
|
|
55
|
-
if (!trimmed) return null;
|
|
56
|
-
|
|
57
|
-
let totalMinutes = 0;
|
|
58
|
-
let matched = false;
|
|
59
|
-
|
|
60
|
-
// Match hours component
|
|
61
|
-
const hoursMatch = trimmed.match(/(\d+)\s*h/i);
|
|
62
|
-
if (hoursMatch) {
|
|
63
|
-
totalMinutes += Number(hoursMatch[1]) * 60;
|
|
64
|
-
matched = true;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Match minutes component
|
|
68
|
-
const minutesMatch = trimmed.match(/(\d+)\s*m/i);
|
|
69
|
-
if (minutesMatch) {
|
|
70
|
-
totalMinutes += Number(minutesMatch[1]);
|
|
71
|
-
matched = true;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return matched ? totalMinutes : null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
44
|
export function startUnitSupervision(sctx: SupervisionContext): void {
|
|
78
45
|
const { s, ctx, pi, unitType, unitId, prefs, buildSnapshotOpts, buildRecoveryContext, pauseAuto } = sctx;
|
|
79
46
|
|
|
80
47
|
const supervisor = resolveAutoSupervisorConfig();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// so longer tasks don't get prematurely timed out.
|
|
85
|
-
let taskEstimate = sctx.taskEstimate;
|
|
86
|
-
if (!taskEstimate && unitType === "task" && isDbAvailable()) {
|
|
87
|
-
// Look up the task estimate from the DB (#2243).
|
|
88
|
-
try {
|
|
89
|
-
if (s.currentMilestoneId) {
|
|
90
|
-
const slices = getMilestoneSlices(s.currentMilestoneId);
|
|
91
|
-
for (const slice of slices) {
|
|
92
|
-
const tasks = getSliceTasks(s.currentMilestoneId, slice.id);
|
|
93
|
-
const task = tasks.find(t => t.id === unitId);
|
|
94
|
-
if (task?.estimate) {
|
|
95
|
-
taskEstimate = task.estimate;
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
} catch {
|
|
101
|
-
// Non-fatal — fall through with no estimate
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
const estimateMinutes = taskEstimate ? parseEstimateMinutes(taskEstimate) : null;
|
|
105
|
-
const timeoutScale = estimateMinutes && estimateMinutes > 0
|
|
106
|
-
? Math.max(1, estimateMinutes / 10) // 10min task = 1x, 30min = 3x, 2h = 12x
|
|
107
|
-
: 1;
|
|
108
|
-
|
|
109
|
-
const softTimeoutMs = (supervisor.soft_timeout_minutes ?? 0) * 60 * 1000 * timeoutScale;
|
|
110
|
-
const idleTimeoutMs = (supervisor.idle_timeout_minutes ?? 0) * 60 * 1000; // idle not scaled — idle is idle
|
|
111
|
-
const hardTimeoutMs = (supervisor.hard_timeout_minutes ?? 0) * 60 * 1000 * timeoutScale;
|
|
48
|
+
const softTimeoutMs = (supervisor.soft_timeout_minutes ?? 0) * 60 * 1000;
|
|
49
|
+
const idleTimeoutMs = (supervisor.idle_timeout_minutes ?? 0) * 60 * 1000;
|
|
50
|
+
const hardTimeoutMs = (supervisor.hard_timeout_minutes ?? 0) * 60 * 1000;
|
|
112
51
|
|
|
113
52
|
// ── 1. Soft timeout warning ──
|
|
114
53
|
s.wrapupWarningHandle = setTimeout(() => {
|
|
@@ -93,11 +93,6 @@ export function syncStateToProjectRoot(
|
|
|
93
93
|
{ force: true },
|
|
94
94
|
);
|
|
95
95
|
|
|
96
|
-
// 3. metrics.json — session cost/token tracking (#2313).
|
|
97
|
-
// Without this, metrics accumulated in the worktree are invisible from the
|
|
98
|
-
// project root and never appear in the dashboard or skill-health reports.
|
|
99
|
-
safeCopy(join(wtGsd, "metrics.json"), join(prGsd, "metrics.json"), { force: true });
|
|
100
|
-
|
|
101
96
|
// 4. Runtime records — unit dispatch state used by selfHealRuntimeRecords().
|
|
102
97
|
// Without this, a crash during a unit leaves the runtime record only in the
|
|
103
98
|
// worktree. If the next session resolves basePath before worktree re-entry,
|