gsd-pi 2.8.2 → 2.9.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.
Files changed (193) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.js +5 -0
  3. package/dist/loader.js +1 -1
  4. package/dist/update-check.d.ts +24 -0
  5. package/dist/update-check.js +93 -0
  6. package/node_modules/@gsd/pi-coding-agent/dist/core/extensions/types.d.ts +4 -2
  7. package/node_modules/@gsd/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  8. package/node_modules/@gsd/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  9. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/client.d.ts +46 -0
  10. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -0
  11. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/client.js +758 -0
  12. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/client.js.map +1 -0
  13. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/config.d.ts +23 -0
  14. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -0
  15. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/config.js +267 -0
  16. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/config.js.map +1 -0
  17. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/edits.d.ts +17 -0
  18. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/edits.d.ts.map +1 -0
  19. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/edits.js +101 -0
  20. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/edits.js.map +1 -0
  21. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/helpers.d.ts +15 -0
  22. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/helpers.d.ts.map +1 -0
  23. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/helpers.js +46 -0
  24. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/helpers.js.map +1 -0
  25. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/index.d.ts +35 -0
  26. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -0
  27. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/index.js +709 -0
  28. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/index.js.map +1 -0
  29. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/lsp-integration.test.d.ts +2 -0
  30. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/lsp-integration.test.d.ts.map +1 -0
  31. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +308 -0
  32. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -0
  33. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/lspmux.d.ts +34 -0
  34. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -0
  35. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/lspmux.js +136 -0
  36. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -0
  37. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/types.d.ts +262 -0
  38. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -0
  39. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/types.js +64 -0
  40. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/types.js.map +1 -0
  41. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/utils.d.ts +50 -0
  42. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -0
  43. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/utils.js +574 -0
  44. package/node_modules/@gsd/pi-coding-agent/dist/core/lsp/utils.js.map +1 -0
  45. package/node_modules/@gsd/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  46. package/node_modules/@gsd/pi-coding-agent/dist/core/slash-commands.js +1 -0
  47. package/node_modules/@gsd/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  48. package/node_modules/@gsd/pi-coding-agent/dist/core/tools/index.d.ts +13 -0
  49. package/node_modules/@gsd/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  50. package/node_modules/@gsd/pi-coding-agent/dist/core/tools/index.js +4 -0
  51. package/node_modules/@gsd/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  52. package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +10 -1
  53. package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  54. package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +2 -2
  55. package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  56. package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  57. package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  58. package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/interactive-mode.js +80 -1
  59. package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  60. package/node_modules/@gsd/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  61. package/node_modules/@gsd/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  62. package/node_modules/@gsd/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +5 -0
  63. package/node_modules/@gsd/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  64. package/node_modules/@gsd/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  65. package/node_modules/@gsd/pi-coding-agent/src/core/extensions/types.ts +4 -2
  66. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/client.ts +880 -0
  67. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/config.ts +325 -0
  68. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/defaults.json +456 -0
  69. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/edits.ts +109 -0
  70. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/helpers.ts +54 -0
  71. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/index.ts +943 -0
  72. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +407 -0
  73. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/lsp.md +33 -0
  74. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/lspmux.ts +199 -0
  75. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/types.ts +421 -0
  76. package/node_modules/@gsd/pi-coding-agent/src/core/lsp/utils.ts +682 -0
  77. package/node_modules/@gsd/pi-coding-agent/src/core/slash-commands.ts +1 -0
  78. package/node_modules/@gsd/pi-coding-agent/src/core/tools/index.ts +10 -0
  79. package/node_modules/@gsd/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +2 -2
  80. package/node_modules/@gsd/pi-coding-agent/src/modes/interactive/interactive-mode.ts +94 -2
  81. package/node_modules/@gsd/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -2
  82. package/node_modules/@gsd/pi-coding-agent/src/modes/rpc/rpc-types.ts +2 -1
  83. package/package.json +1 -1
  84. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +4 -2
  85. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  86. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  87. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +46 -0
  88. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -0
  89. package/packages/pi-coding-agent/dist/core/lsp/client.js +758 -0
  90. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -0
  91. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +23 -0
  92. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -0
  93. package/packages/pi-coding-agent/dist/core/lsp/config.js +267 -0
  94. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -0
  95. package/packages/pi-coding-agent/dist/core/lsp/edits.d.ts +17 -0
  96. package/packages/pi-coding-agent/dist/core/lsp/edits.d.ts.map +1 -0
  97. package/packages/pi-coding-agent/dist/core/lsp/edits.js +101 -0
  98. package/packages/pi-coding-agent/dist/core/lsp/edits.js.map +1 -0
  99. package/packages/pi-coding-agent/dist/core/lsp/helpers.d.ts +15 -0
  100. package/packages/pi-coding-agent/dist/core/lsp/helpers.d.ts.map +1 -0
  101. package/packages/pi-coding-agent/dist/core/lsp/helpers.js +46 -0
  102. package/packages/pi-coding-agent/dist/core/lsp/helpers.js.map +1 -0
  103. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts +35 -0
  104. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -0
  105. package/packages/pi-coding-agent/dist/core/lsp/index.js +709 -0
  106. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -0
  107. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.d.ts +2 -0
  108. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.d.ts.map +1 -0
  109. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +308 -0
  110. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -0
  111. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts +34 -0
  112. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -0
  113. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +136 -0
  114. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -0
  115. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +262 -0
  116. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -0
  117. package/packages/pi-coding-agent/dist/core/lsp/types.js +64 -0
  118. package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -0
  119. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +50 -0
  120. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -0
  121. package/packages/pi-coding-agent/dist/core/lsp/utils.js +574 -0
  122. package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -0
  123. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  124. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  125. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  126. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +13 -0
  127. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/tools/index.js +4 -0
  129. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +10 -1
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +2 -2
  133. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +80 -1
  137. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  139. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +5 -0
  141. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  143. package/packages/pi-coding-agent/src/core/extensions/types.ts +4 -2
  144. package/packages/pi-coding-agent/src/core/lsp/client.ts +880 -0
  145. package/packages/pi-coding-agent/src/core/lsp/config.ts +325 -0
  146. package/packages/pi-coding-agent/src/core/lsp/defaults.json +456 -0
  147. package/packages/pi-coding-agent/src/core/lsp/edits.ts +109 -0
  148. package/packages/pi-coding-agent/src/core/lsp/helpers.ts +54 -0
  149. package/packages/pi-coding-agent/src/core/lsp/index.ts +943 -0
  150. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +407 -0
  151. package/packages/pi-coding-agent/src/core/lsp/lsp.md +33 -0
  152. package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +199 -0
  153. package/packages/pi-coding-agent/src/core/lsp/types.ts +421 -0
  154. package/packages/pi-coding-agent/src/core/lsp/utils.ts +682 -0
  155. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  156. package/packages/pi-coding-agent/src/core/tools/index.ts +10 -0
  157. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +2 -2
  158. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +94 -2
  159. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -2
  160. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +2 -1
  161. package/src/resources/extensions/ask-user-questions.ts +42 -2
  162. package/src/resources/extensions/bg-shell/index.ts +34 -37
  163. package/src/resources/extensions/browser-tools/core.d.ts +205 -0
  164. package/src/resources/extensions/browser-tools/index.ts +2 -2
  165. package/src/resources/extensions/browser-tools/refs.ts +1 -1
  166. package/src/resources/extensions/browser-tools/tools/session.ts +1 -1
  167. package/src/resources/extensions/context7/index.ts +2 -2
  168. package/src/resources/extensions/get-secrets-from-user.ts +3 -2
  169. package/src/resources/extensions/google-search/index.ts +1 -1
  170. package/src/resources/extensions/gsd/auto.ts +126 -12
  171. package/src/resources/extensions/gsd/commands.ts +218 -3
  172. package/src/resources/extensions/gsd/doctor.ts +1 -1
  173. package/src/resources/extensions/gsd/git-service.ts +163 -13
  174. package/src/resources/extensions/gsd/guided-flow.ts +19 -9
  175. package/src/resources/extensions/gsd/index.ts +17 -7
  176. package/src/resources/extensions/gsd/preferences.ts +1 -1
  177. package/src/resources/extensions/gsd/tests/git-service.test.ts +226 -0
  178. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +2 -2
  179. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +1 -1
  180. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +10 -10
  181. package/src/resources/extensions/gsd/tests/next-milestone-id.test.ts +87 -0
  182. package/src/resources/extensions/gsd/tests/worktree.test.ts +352 -0
  183. package/src/resources/extensions/gsd/types.ts +1 -0
  184. package/src/resources/extensions/gsd/worktree.ts +20 -1
  185. package/src/resources/extensions/mac-tools/index.ts +1 -1
  186. package/src/resources/extensions/search-the-web/command-search-provider.ts +1 -1
  187. package/src/resources/extensions/search-the-web/format.ts +1 -1
  188. package/src/resources/extensions/search-the-web/index.ts +5 -5
  189. package/src/resources/extensions/search-the-web/native-search.ts +5 -6
  190. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +7 -7
  191. package/src/resources/extensions/search-the-web/tool-llm-context.ts +11 -11
  192. package/src/resources/extensions/search-the-web/tool-search.ts +10 -10
  193. package/src/resources/extensions/shared/interview-ui.ts +2 -2
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Type declarations for core.js — runtime-neutral helper logic for browser-tools.
3
+ */
4
+
5
+ export interface ActionTimeline {
6
+ limit: number;
7
+ nextId: number;
8
+ entries: ActionEntry[];
9
+ }
10
+
11
+ export interface ActionEntry {
12
+ id: number;
13
+ tool: string;
14
+ paramsSummary: string;
15
+ startedAt: number;
16
+ finishedAt: number | null;
17
+ status: string;
18
+ beforeUrl: string;
19
+ afterUrl: string;
20
+ verificationSummary?: string;
21
+ warningSummary?: string;
22
+ diffSummary?: string;
23
+ changed?: boolean;
24
+ error?: string;
25
+ }
26
+
27
+ export interface ActionPartial {
28
+ tool: string;
29
+ paramsSummary?: string;
30
+ startedAt?: number;
31
+ beforeUrl?: string;
32
+ afterUrl?: string;
33
+ verificationSummary?: string;
34
+ warningSummary?: string;
35
+ diffSummary?: string;
36
+ changed?: boolean;
37
+ error?: string;
38
+ }
39
+
40
+ export interface ActionUpdates {
41
+ finishedAt?: number;
42
+ status?: string;
43
+ afterUrl?: string;
44
+ verificationSummary?: string;
45
+ warningSummary?: string;
46
+ diffSummary?: string;
47
+ changed?: boolean;
48
+ error?: string;
49
+ }
50
+
51
+ export interface DiffResult {
52
+ changed: boolean;
53
+ changes: Array<{ type: string; before: unknown; after: unknown }>;
54
+ summary: string;
55
+ }
56
+
57
+ export interface Threshold {
58
+ op: string;
59
+ n: number;
60
+ }
61
+
62
+ export interface PageRegistry {
63
+ pages: PageEntry[];
64
+ activePageId: number | null;
65
+ nextId: number;
66
+ }
67
+
68
+ export interface PageEntry {
69
+ id: number;
70
+ page: any;
71
+ title: string;
72
+ url: string;
73
+ opener: number | null;
74
+ }
75
+
76
+ export interface PageListEntry {
77
+ id: number;
78
+ title: string;
79
+ url: string;
80
+ opener: number | null;
81
+ isActive: boolean;
82
+ }
83
+
84
+ export interface SnapshotModeConfig {
85
+ tags: string[];
86
+ roles: string[];
87
+ selectors: string[];
88
+ ariaAttributes: string[];
89
+ useInteractiveFilter: boolean;
90
+ visibleOnly?: boolean;
91
+ containerExpand?: boolean;
92
+ }
93
+
94
+ export interface AssertionCheckResult {
95
+ name: string;
96
+ passed: boolean;
97
+ actual: unknown;
98
+ expected: unknown;
99
+ selector?: string;
100
+ text?: string;
101
+ }
102
+
103
+ export interface AssertionEvaluation {
104
+ verified: boolean;
105
+ checks: AssertionCheckResult[];
106
+ summary: string;
107
+ agentHint: string;
108
+ }
109
+
110
+ export interface WaitValidationError {
111
+ error: string;
112
+ }
113
+
114
+ export interface BatchStepResult {
115
+ ok: boolean;
116
+ stopReason: string | null;
117
+ failedStepIndex: number | null;
118
+ stepResults: unknown[];
119
+ summary: string;
120
+ }
121
+
122
+ export interface FormattedTimeline {
123
+ entries: Array<{
124
+ id: number | null;
125
+ tool: string;
126
+ status: string;
127
+ durationMs: number | null;
128
+ beforeUrl: string;
129
+ afterUrl: string;
130
+ line: string;
131
+ }>;
132
+ retained: number;
133
+ totalRecorded: number;
134
+ bounded: boolean;
135
+ summary: string;
136
+ }
137
+
138
+ export interface FailureHypothesis {
139
+ hasFailures: boolean;
140
+ categories: string[];
141
+ summary: string;
142
+ signals: Array<{ category: string; source: string; detail: string }>;
143
+ }
144
+
145
+ export interface SessionSummary {
146
+ counts: {
147
+ pages: number;
148
+ actions: { total: number; retained: number; success: number; error: number; running: number };
149
+ waits: { total: number; success: number; error: number; running: number };
150
+ assertions: { total: number; passed: number; failed: number; running: number };
151
+ consoleErrors: number;
152
+ failedRequests: number;
153
+ dialogs: number;
154
+ };
155
+ activePage: { id: number | null; title: string; url: string } | null;
156
+ caveats: string[];
157
+ failureHypothesis: FailureHypothesis;
158
+ summary: string;
159
+ }
160
+
161
+ export function createActionTimeline(limit?: number): ActionTimeline;
162
+ export function beginAction(timeline: ActionTimeline, partial: ActionPartial): ActionEntry;
163
+ export function finishAction(timeline: ActionTimeline, actionId: number, updates?: ActionUpdates): ActionEntry | null;
164
+ export function findAction(timeline: ActionTimeline, actionId: number): ActionEntry | null;
165
+ export function toActionParamsSummary(params: unknown): string;
166
+ export function diffCompactStates(before: unknown, after: unknown): DiffResult;
167
+ export function includesNeedle(haystack: string, needle: string): boolean;
168
+ export function parseThreshold(value: string | null | undefined): Threshold | null;
169
+ export function meetsThreshold(count: number, threshold: Threshold): boolean;
170
+ export function getEntriesSince(
171
+ entries: Array<{ timestamp?: number }>,
172
+ sinceActionId: number | undefined,
173
+ timeline: ActionTimeline,
174
+ ): unknown[];
175
+ export function evaluateAssertionChecks(args: { checks: unknown[]; state: unknown }): AssertionEvaluation;
176
+ export function validateWaitParams(params: { condition: string; value?: string; threshold?: string }): WaitValidationError | null;
177
+ export function createRegionStableScript(selector: string): string;
178
+ export function createPageRegistry(): PageRegistry;
179
+ export function registryAddPage(
180
+ registry: PageRegistry,
181
+ info: { page: unknown; title?: string; url?: string; opener?: number | null },
182
+ ): PageEntry;
183
+ export function registryRemovePage(registry: PageRegistry, pageId: number): { removed: PageEntry; newActiveId: number | null };
184
+ export function registrySetActive(registry: PageRegistry, pageId: number): void;
185
+ export function registryGetActive(registry: PageRegistry): PageEntry;
186
+ export function registryGetPage(registry: PageRegistry, pageId: number): PageEntry | null;
187
+ export function registryListPages(registry: PageRegistry): PageListEntry[];
188
+ export function createBoundedLogPusher(maxSize: number): (array: unknown[], entry: unknown) => void;
189
+ export function runBatchSteps(args: {
190
+ steps: unknown[];
191
+ executeStep: (step: unknown, index: number) => Promise<{ ok: boolean; [key: string]: unknown }>;
192
+ stopOnFailure?: boolean;
193
+ }): Promise<BatchStepResult>;
194
+
195
+ export declare const SNAPSHOT_MODES: Record<string, SnapshotModeConfig>;
196
+ export function getSnapshotModeConfig(mode: string): SnapshotModeConfig | null;
197
+ export function computeContentHash(text: string): string;
198
+ export function computeStructuralSignature(tag: string, role: string, childTags: string[]): string;
199
+ export function matchFingerprint(
200
+ stored: { contentHash?: string; structuralSignature?: string },
201
+ candidate: { contentHash?: string; structuralSignature?: string },
202
+ ): boolean;
203
+ export function formatTimelineEntries(entries?: unknown[], options?: Record<string, unknown>): FormattedTimeline;
204
+ export function buildFailureHypothesis(session?: Record<string, unknown>): FailureHypothesis;
205
+ export function summarizeBrowserSession(session?: Record<string, unknown>): SessionSummary;
@@ -28,11 +28,11 @@ export default function (pi: ExtensionAPI) {
28
28
  parseRef: u.parseRef, formatVersionedRef: u.formatVersionedRef, staleRefGuidance: u.staleRefGuidance,
29
29
  beginTrackedAction: u.beginTrackedAction, finishTrackedAction: u.finishTrackedAction,
30
30
  truncateText: u.truncateText, verificationFromChecks: u.verificationFromChecks,
31
- verificationLine: u.verificationLine, collectAssertionState: u.collectAssertionState,
31
+ verificationLine: u.verificationLine, collectAssertionState: (p, checks, target?) => u.collectAssertionState(p, checks, captureCompactPageState, target),
32
32
  formatAssertionText: u.formatAssertionText, formatDiffText: u.formatDiffText,
33
33
  getUrlHash: u.getUrlHash,
34
34
  captureClickTargetState: u.captureClickTargetState, readInputLikeValue: u.readInputLikeValue,
35
- firstErrorLine: u.firstErrorLine, captureAccessibilityMarkdown: u.captureAccessibilityMarkdown,
35
+ firstErrorLine: u.firstErrorLine, captureAccessibilityMarkdown: (selector?) => u.captureAccessibilityMarkdown(getActiveTarget(), selector),
36
36
  resolveAccessibilityScope: u.resolveAccessibilityScope,
37
37
  getLivePagesSnapshot: u.createGetLivePagesSnapshot(ensureBrowser),
38
38
  getSinceTimestamp: u.getSinceTimestamp, getConsoleEntriesSince: u.getConsoleEntriesSince,
@@ -124,7 +124,7 @@ export async function buildRefSnapshot(
124
124
  sib = sib.previousElementSibling;
125
125
  }
126
126
  // Check if the parent itself is a heading (unlikely but possible)
127
- const parent = current.parentElement;
127
+ const parent: Element | null = current.parentElement;
128
128
  if (parent && (headingTags.has(parent.tagName) || parent.getAttribute("role") === "heading")) {
129
129
  return (parent.textContent || "").trim().replace(/\s+/g, " ").slice(0, 80);
130
130
  }
@@ -379,7 +379,7 @@ export function registerSessionTools(pi: ExtensionAPI, deps: ToolDeps): void {
379
379
  console: consoleLogs.length,
380
380
  network: networkLogs.length,
381
381
  dialog: dialogLogs.length,
382
- actions: timeline.count,
382
+ actions: timeline.retained,
383
383
  pages: pages.length,
384
384
  },
385
385
  elapsedMs: Date.now() - startedAt,
@@ -233,7 +233,7 @@ export default function (pi: ExtensionAPI) {
233
233
  renderResult(result, { isPartial }, theme) {
234
234
  const d = result.details as ResolveDetails | undefined;
235
235
  if (isPartial) return new Text(theme.fg("warning", "Searching Context7..."), 0, 0);
236
- if (result.isError || d?.error) {
236
+ if ((result as any).isError || d?.error) {
237
237
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
238
238
  }
239
239
  let text = theme.fg("success", `${d?.resultCount ?? 0} ${d?.resultCount === 1 ? "library" : "libraries"} found`);
@@ -388,7 +388,7 @@ export default function (pi: ExtensionAPI) {
388
388
  const d = result.details as DocsDetails | undefined;
389
389
 
390
390
  if (isPartial) return new Text(theme.fg("warning", "Fetching documentation..."), 0, 0);
391
- if (result.isError || d?.error) {
391
+ if ((result as any).isError || d?.error) {
392
392
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
393
393
  }
394
394
 
@@ -160,7 +160,7 @@ async function collectOneSecret(
160
160
  ): Promise<string | null> {
161
161
  if (!ctx.hasUI) return null;
162
162
 
163
- return ctx.ui.custom<string | null>((tui: any, theme: any, _kb: any, done: (r: string | null) => void) => {
163
+ return ctx.ui.custom((tui: any, theme: any, _kb: any, done: (r: string | null) => void) => {
164
164
  let value = "";
165
165
  let cachedLines: string[] | undefined;
166
166
 
@@ -286,7 +286,7 @@ export async function showSecretsSummary(
286
286
 
287
287
  const existingSet = new Set(existingKeys);
288
288
 
289
- await ctx.ui.custom<void>((tui: any, theme: Theme, _kb: any, done: () => void) => {
289
+ await (ctx.ui.custom as Function)((tui: any, theme: Theme, _kb: any, done: () => void) => {
290
290
  let cachedLines: string[] | undefined;
291
291
 
292
292
  function handleInput(_data: string) {
@@ -549,6 +549,7 @@ export default function secureEnv(pi: ExtensionAPI) {
549
549
  return {
550
550
  content: [{ type: "text", text: "Error: UI not available (interactive mode required for secure env collection)." }],
551
551
  isError: true,
552
+ details: undefined as unknown,
552
553
  };
553
554
  }
554
555
 
@@ -261,7 +261,7 @@ export default function (pi: ExtensionAPI) {
261
261
  const d = result.details as SearchDetails | undefined;
262
262
 
263
263
  if (isPartial) return new Text(theme.fg("warning", "Searching Google..."), 0, 0);
264
- if (result.isError || d?.error) {
264
+ if ((result as any).isError || d?.error) {
265
265
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
266
266
  }
267
267
 
@@ -60,10 +60,12 @@ import { readdirSync, readFileSync, existsSync, mkdirSync, writeFileSync } from
60
60
  import { execSync, execFileSync } from "node:child_process";
61
61
  import {
62
62
  autoCommitCurrentBranch,
63
+ captureIntegrationBranch,
63
64
  ensureSliceBranch,
64
65
  getCurrentBranch,
65
66
  getMainBranch,
66
67
  parseSliceBranch,
68
+ setActiveMilestoneId,
67
69
  switchToMain,
68
70
  mergeSliceToMain,
69
71
  } from "./worktree.ts";
@@ -152,6 +154,7 @@ let currentMilestoneId: string | null = null;
152
154
 
153
155
  /** Model the user had selected before auto-mode started */
154
156
  let originalModelId: string | null = null;
157
+ let originalModelProvider: string | null = null;
155
158
 
156
159
  /** Progress-aware timeout supervision */
157
160
  let unitTimeoutHandle: ReturnType<typeof setTimeout> | null = null;
@@ -257,6 +260,11 @@ export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI): Promi
257
260
  ctx?.ui.notify("Auto-mode stopped.", "info");
258
261
  }
259
262
 
263
+ // Sync disk state so next resume starts from accurate state
264
+ if (basePath) {
265
+ try { await rebuildState(basePath); } catch { /* non-fatal */ }
266
+ }
267
+
260
268
  resetMetrics();
261
269
  active = false;
262
270
  paused = false;
@@ -272,10 +280,11 @@ export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI): Promi
272
280
  ctx?.ui.setFooter(undefined);
273
281
 
274
282
  // Restore the user's original model
275
- if (pi && ctx && originalModelId) {
276
- const original = ctx.modelRegistry.find("anthropic", originalModelId);
283
+ if (pi && ctx && originalModelId && originalModelProvider) {
284
+ const original = ctx.modelRegistry.find(originalModelProvider, originalModelId);
277
285
  if (original) await pi.setModel(original);
278
286
  originalModelId = null;
287
+ originalModelProvider = null;
279
288
  }
280
289
 
281
290
  cmdCtx = null;
@@ -354,6 +363,8 @@ export async function startAuto(
354
363
  unitDispatchCount.clear();
355
364
  // Re-initialize metrics in case ledger was lost during pause
356
365
  if (!getLedger()) initMetrics(base);
366
+ // Ensure milestone ID is set on git service for integration branch resolution
367
+ if (currentMilestoneId) setActiveMilestoneId(base, currentMilestoneId);
357
368
  ctx.ui.setStatus("gsd-auto", stepMode ? "next" : "auto");
358
369
  ctx.ui.setFooter(hideFooter);
359
370
  ctx.ui.notify(stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "info");
@@ -459,6 +470,16 @@ export async function startAuto(
459
470
  currentUnit = null;
460
471
  currentMilestoneId = state.activeMilestone?.id ?? null;
461
472
  originalModelId = ctx.model?.id ?? null;
473
+ originalModelProvider = ctx.model?.provider ?? null;
474
+
475
+ // Capture the integration branch — records the branch the user was on when
476
+ // auto-mode started. Slice branches will merge back to this branch instead
477
+ // of the repo's default (main/master). Idempotent: only writes if not
478
+ // already recorded, so restarts/resumes don't overwrite.
479
+ if (currentMilestoneId) {
480
+ captureIntegrationBranch(base, currentMilestoneId);
481
+ setActiveMilestoneId(base, currentMilestoneId);
482
+ }
462
483
 
463
484
  // Initialize metrics — loads existing ledger from disk
464
485
  initMetrics(base);
@@ -994,8 +1015,13 @@ async function dispatchNextUnit(
994
1015
  // Reset stuck detection for new milestone
995
1016
  unitDispatchCount.clear();
996
1017
  unitRecoveryCount.clear();
1018
+ // Capture integration branch for the new milestone and update git service
1019
+ captureIntegrationBranch(basePath, mid);
1020
+ }
1021
+ if (mid) {
1022
+ currentMilestoneId = mid;
1023
+ setActiveMilestoneId(basePath, mid);
997
1024
  }
998
- if (mid) currentMilestoneId = mid;
999
1025
 
1000
1026
  if (!mid) {
1001
1027
  // Save final session before stopping
@@ -1008,6 +1034,14 @@ async function dispatchNextUnit(
1008
1034
  return;
1009
1035
  }
1010
1036
 
1037
+ // Guard: mid/midTitle must be defined strings from this point onward.
1038
+ // The !mid check above returns early if mid is falsy; midTitle comes from
1039
+ // the same object so it should always be present when mid is.
1040
+ if (!midTitle) {
1041
+ await stopAuto(ctx, pi);
1042
+ return;
1043
+ }
1044
+
1011
1045
  // ── General merge guard: merge completed slice branches before advancing ──
1012
1046
  // If we're on a gsd/MID/SID branch and that slice is done (roadmap [x]),
1013
1047
  // merge to main before dispatching the next unit. This handles:
@@ -1080,6 +1114,17 @@ async function dispatchNextUnit(
1080
1114
  }
1081
1115
  }
1082
1116
 
1117
+ // After merge, mid/midTitle may have been re-derived and could be undefined
1118
+ if (!mid || !midTitle) {
1119
+ if (currentUnit) {
1120
+ const modelId = ctx.model?.id ?? "unknown";
1121
+ snapshotUnitMetrics(ctx, currentUnit.type, currentUnit.id, currentUnit.startedAt, modelId);
1122
+ saveActivityLog(ctx, basePath, currentUnit.type, currentUnit.id);
1123
+ }
1124
+ await stopAuto(ctx, pi);
1125
+ return;
1126
+ }
1127
+
1083
1128
  // Determine next unit
1084
1129
  let unitType: string;
1085
1130
  let unitId: string;
@@ -1181,7 +1226,7 @@ async function dispatchNextUnit(
1181
1226
 
1182
1227
  // Research before roadmap if no research exists
1183
1228
  const researchFile = resolveMilestoneFile(basePath, mid, "RESEARCH");
1184
- const hasResearch = !!(researchFile && await loadFile(researchFile));
1229
+ const hasResearch = !!researchFile;
1185
1230
 
1186
1231
  if (!hasResearch) {
1187
1232
  unitType = "research-milestone";
@@ -1198,13 +1243,13 @@ async function dispatchNextUnit(
1198
1243
  const sid = state.activeSlice!.id;
1199
1244
  const sTitle = state.activeSlice!.title;
1200
1245
  const researchFile = resolveSliceFile(basePath, mid, sid, "RESEARCH");
1201
- const hasResearch = !!(researchFile && await loadFile(researchFile));
1246
+ const hasResearch = !!researchFile;
1202
1247
 
1203
1248
  if (!hasResearch) {
1204
1249
  // Skip slice research for S01 when milestone research already exists —
1205
1250
  // the milestone research already covers the same ground for the first slice.
1206
1251
  const milestoneResearchFile = resolveMilestoneFile(basePath, mid, "RESEARCH");
1207
- const hasMilestoneResearch = !!(milestoneResearchFile && await loadFile(milestoneResearchFile));
1252
+ const hasMilestoneResearch = !!milestoneResearchFile;
1208
1253
  if (hasMilestoneResearch && sid === "S01") {
1209
1254
  unitType = "plan-slice";
1210
1255
  unitId = `${mid}/${sid}`;
@@ -1312,6 +1357,26 @@ async function dispatchNextUnit(
1312
1357
  }
1313
1358
  unitDispatchCount.set(dispatchKey, prevCount + 1);
1314
1359
  if (prevCount > 0) {
1360
+ // Self-repair: if summary exists but checkbox not marked, fix it and re-derive
1361
+ if (unitType === "execute-task") {
1362
+ const status = await inspectExecuteTaskDurability(basePath, unitId);
1363
+ if (status?.summaryExists && !status.taskChecked) {
1364
+ const [mid, sid, tid] = unitId.split("/");
1365
+ if (mid && sid && tid) {
1366
+ const repaired = skipExecuteTask(basePath, mid, sid, tid, status, "self-repair", 0);
1367
+ if (repaired) {
1368
+ ctx.ui.notify(
1369
+ `Self-repaired ${unitId}: summary existed but checkbox was unmarked. Marked [x] and advancing.`,
1370
+ "warning",
1371
+ );
1372
+ unitDispatchCount.delete(dispatchKey);
1373
+ await new Promise(r => setImmediate(r));
1374
+ await dispatchNextUnit(ctx, pi);
1375
+ return;
1376
+ }
1377
+ }
1378
+ }
1379
+ }
1315
1380
  ctx.ui.notify(
1316
1381
  `${unitType} ${unitId} didn't produce expected artifact. Retrying (${prevCount + 1}/${MAX_UNIT_DISPATCHES}).`,
1317
1382
  "warning",
@@ -1414,14 +1479,46 @@ async function dispatchNextUnit(
1414
1479
  // Try primary model, then fallbacks in order if setting fails
1415
1480
  const modelConfig = resolveModelWithFallbacksForUnit(unitType);
1416
1481
  if (modelConfig) {
1417
- const allModels = ctx.modelRegistry.getAll();
1482
+ const availableModels = ctx.modelRegistry.getAvailable();
1418
1483
  const modelsToTry = [modelConfig.primary, ...modelConfig.fallbacks];
1419
1484
  let modelSet = false;
1420
1485
 
1421
1486
  for (const modelId of modelsToTry) {
1422
- const model = allModels.find(m => m.id === modelId);
1487
+ // Support "provider/model" format for explicit provider targeting
1488
+ const slashIdx = modelId.indexOf("/");
1489
+ let model;
1490
+ if (slashIdx !== -1) {
1491
+ const provider = modelId.substring(0, slashIdx);
1492
+ const id = modelId.substring(slashIdx + 1);
1493
+ model = availableModels.find(
1494
+ m => m.provider.toLowerCase() === provider.toLowerCase()
1495
+ && m.id.toLowerCase() === id.toLowerCase(),
1496
+ );
1497
+ } else {
1498
+ // For bare IDs, prefer the current session's provider, then first available match
1499
+ const currentProvider = ctx.model?.provider;
1500
+ const exactProviderMatch = availableModels.find(
1501
+ m => m.id === modelId && m.provider === currentProvider,
1502
+ );
1503
+ const anyMatch = availableModels.find(m => m.id === modelId);
1504
+ model = exactProviderMatch ?? anyMatch;
1505
+
1506
+ // Warn if the ID is ambiguous across providers
1507
+ if (anyMatch && !exactProviderMatch) {
1508
+ const providers = availableModels
1509
+ .filter(m => m.id === modelId)
1510
+ .map(m => m.provider);
1511
+ if (providers.length > 1) {
1512
+ ctx.ui.notify(
1513
+ `Model ID "${modelId}" exists in multiple providers (${providers.join(", ")}). ` +
1514
+ `Resolved to ${anyMatch.provider}. Use "provider/model" format for explicit targeting.`,
1515
+ "warning",
1516
+ );
1517
+ }
1518
+ }
1519
+ }
1423
1520
  if (!model) {
1424
- ctx.ui.notify(`Model ${modelId} not found in registry, trying fallback.`, "warning");
1521
+ ctx.ui.notify(`Model ${modelId} not found in available models, trying fallback.`, "warning");
1425
1522
  continue;
1426
1523
  }
1427
1524
 
@@ -1462,9 +1559,9 @@ async function dispatchNextUnit(
1462
1559
  // soft timeout; only idle/stalled tasks pause early.
1463
1560
  clearUnitTimeout();
1464
1561
  const supervisor = resolveAutoSupervisorConfig();
1465
- const softTimeoutMs = supervisor.soft_timeout_minutes * 60 * 1000;
1466
- const idleTimeoutMs = supervisor.idle_timeout_minutes * 60 * 1000;
1467
- const hardTimeoutMs = supervisor.hard_timeout_minutes * 60 * 1000;
1562
+ const softTimeoutMs = (supervisor.soft_timeout_minutes ?? 0) * 60 * 1000;
1563
+ const idleTimeoutMs = (supervisor.idle_timeout_minutes ?? 0) * 60 * 1000;
1564
+ const hardTimeoutMs = (supervisor.hard_timeout_minutes ?? 0) * 60 * 1000;
1468
1565
 
1469
1566
  wrapupWarningHandle = setTimeout(() => {
1470
1567
  wrapupWarningHandle = null;
@@ -2772,6 +2869,23 @@ function verifyExpectedArtifact(unitType: string, unitId: string, base: string):
2772
2869
  if (!absPath) return true;
2773
2870
  if (!existsSync(absPath)) return false;
2774
2871
 
2872
+ // execute-task must also have its checkbox marked [x] in the slice plan
2873
+ if (unitType === "execute-task") {
2874
+ const parts = unitId.split("/");
2875
+ const mid = parts[0];
2876
+ const sid = parts[1];
2877
+ const tid = parts[2];
2878
+ if (mid && sid && tid) {
2879
+ const planAbs = resolveSliceFile(base, mid, sid, "PLAN");
2880
+ if (planAbs && existsSync(planAbs)) {
2881
+ const planContent = readFileSync(planAbs, "utf-8");
2882
+ const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2883
+ const re = new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m");
2884
+ if (!re.test(planContent)) return false;
2885
+ }
2886
+ }
2887
+ }
2888
+
2775
2889
  // complete-slice must also produce a UAT file
2776
2890
  if (unitType === "complete-slice") {
2777
2891
  const parts = unitId.split("/");