@tuan_son.dinh/gsd 2.6.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 (227) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +453 -0
  3. package/dist/app-paths.d.ts +4 -0
  4. package/dist/app-paths.js +6 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +269 -0
  7. package/dist/loader.d.ts +2 -0
  8. package/dist/loader.js +70 -0
  9. package/dist/logo.d.ts +16 -0
  10. package/dist/logo.js +25 -0
  11. package/dist/onboarding.d.ts +43 -0
  12. package/dist/onboarding.js +418 -0
  13. package/dist/pi-migration.d.ts +14 -0
  14. package/dist/pi-migration.js +57 -0
  15. package/dist/resource-loader.d.ts +22 -0
  16. package/dist/resource-loader.js +60 -0
  17. package/dist/tool-bootstrap.d.ts +4 -0
  18. package/dist/tool-bootstrap.js +74 -0
  19. package/dist/wizard.d.ts +7 -0
  20. package/dist/wizard.js +25 -0
  21. package/package.json +60 -0
  22. package/patches/@mariozechner+pi-coding-agent+0.57.1.patch +108 -0
  23. package/patches/@mariozechner+pi-tui+0.57.1.patch +47 -0
  24. package/pkg/dist/modes/interactive/theme/dark.json +85 -0
  25. package/pkg/dist/modes/interactive/theme/light.json +84 -0
  26. package/pkg/dist/modes/interactive/theme/theme-schema.json +335 -0
  27. package/pkg/dist/modes/interactive/theme/theme.d.ts +78 -0
  28. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -0
  29. package/pkg/dist/modes/interactive/theme/theme.js +949 -0
  30. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -0
  31. package/pkg/package.json +8 -0
  32. package/scripts/postinstall.js +127 -0
  33. package/src/resources/GSD-WORKFLOW.md +661 -0
  34. package/src/resources/agents/researcher.md +29 -0
  35. package/src/resources/agents/scout.md +56 -0
  36. package/src/resources/agents/worker.md +31 -0
  37. package/src/resources/extensions/ask-user-questions.ts +249 -0
  38. package/src/resources/extensions/bg-shell/index.ts +2808 -0
  39. package/src/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
  40. package/src/resources/extensions/browser-tools/core.js +1057 -0
  41. package/src/resources/extensions/browser-tools/index.ts +4989 -0
  42. package/src/resources/extensions/browser-tools/package.json +20 -0
  43. package/src/resources/extensions/context7/index.ts +428 -0
  44. package/src/resources/extensions/context7/package.json +11 -0
  45. package/src/resources/extensions/get-secrets-from-user.ts +352 -0
  46. package/src/resources/extensions/google-search/index.ts +323 -0
  47. package/src/resources/extensions/google-search/package.json +9 -0
  48. package/src/resources/extensions/gsd/activity-log.ts +69 -0
  49. package/src/resources/extensions/gsd/auto.ts +2744 -0
  50. package/src/resources/extensions/gsd/commands.ts +313 -0
  51. package/src/resources/extensions/gsd/crash-recovery.ts +85 -0
  52. package/src/resources/extensions/gsd/dashboard-overlay.ts +521 -0
  53. package/src/resources/extensions/gsd/docs/preferences-reference.md +176 -0
  54. package/src/resources/extensions/gsd/doctor.ts +690 -0
  55. package/src/resources/extensions/gsd/files.ts +732 -0
  56. package/src/resources/extensions/gsd/git-service.ts +597 -0
  57. package/src/resources/extensions/gsd/gitignore.ts +168 -0
  58. package/src/resources/extensions/gsd/guided-flow.ts +817 -0
  59. package/src/resources/extensions/gsd/index.ts +558 -0
  60. package/src/resources/extensions/gsd/metrics.ts +374 -0
  61. package/src/resources/extensions/gsd/migrate/command.ts +218 -0
  62. package/src/resources/extensions/gsd/migrate/index.ts +42 -0
  63. package/src/resources/extensions/gsd/migrate/parser.ts +323 -0
  64. package/src/resources/extensions/gsd/migrate/parsers.ts +624 -0
  65. package/src/resources/extensions/gsd/migrate/preview.ts +48 -0
  66. package/src/resources/extensions/gsd/migrate/transformer.ts +346 -0
  67. package/src/resources/extensions/gsd/migrate/types.ts +370 -0
  68. package/src/resources/extensions/gsd/migrate/validator.ts +55 -0
  69. package/src/resources/extensions/gsd/migrate/writer.ts +539 -0
  70. package/src/resources/extensions/gsd/observability-validator.ts +408 -0
  71. package/src/resources/extensions/gsd/package.json +11 -0
  72. package/src/resources/extensions/gsd/paths.ts +308 -0
  73. package/src/resources/extensions/gsd/preferences.ts +757 -0
  74. package/src/resources/extensions/gsd/prompt-loader.ts +50 -0
  75. package/src/resources/extensions/gsd/prompts/complete-milestone.md +25 -0
  76. package/src/resources/extensions/gsd/prompts/complete-slice.md +29 -0
  77. package/src/resources/extensions/gsd/prompts/discuss.md +189 -0
  78. package/src/resources/extensions/gsd/prompts/doctor-heal.md +29 -0
  79. package/src/resources/extensions/gsd/prompts/execute-task.md +61 -0
  80. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -0
  81. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -0
  82. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +59 -0
  83. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -0
  84. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +23 -0
  85. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -0
  86. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +11 -0
  87. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -0
  88. package/src/resources/extensions/gsd/prompts/plan-milestone.md +65 -0
  89. package/src/resources/extensions/gsd/prompts/plan-slice.md +51 -0
  90. package/src/resources/extensions/gsd/prompts/queue.md +85 -0
  91. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +48 -0
  92. package/src/resources/extensions/gsd/prompts/replan-slice.md +39 -0
  93. package/src/resources/extensions/gsd/prompts/research-milestone.md +37 -0
  94. package/src/resources/extensions/gsd/prompts/research-slice.md +28 -0
  95. package/src/resources/extensions/gsd/prompts/review-migration.md +66 -0
  96. package/src/resources/extensions/gsd/prompts/run-uat.md +109 -0
  97. package/src/resources/extensions/gsd/prompts/system.md +187 -0
  98. package/src/resources/extensions/gsd/prompts/worktree-merge.md +123 -0
  99. package/src/resources/extensions/gsd/session-forensics.ts +487 -0
  100. package/src/resources/extensions/gsd/skill-discovery.ts +137 -0
  101. package/src/resources/extensions/gsd/state.ts +460 -0
  102. package/src/resources/extensions/gsd/templates/context.md +76 -0
  103. package/src/resources/extensions/gsd/templates/decisions.md +8 -0
  104. package/src/resources/extensions/gsd/templates/milestone-summary.md +73 -0
  105. package/src/resources/extensions/gsd/templates/plan.md +131 -0
  106. package/src/resources/extensions/gsd/templates/preferences.md +24 -0
  107. package/src/resources/extensions/gsd/templates/project.md +31 -0
  108. package/src/resources/extensions/gsd/templates/reassessment.md +28 -0
  109. package/src/resources/extensions/gsd/templates/requirements.md +81 -0
  110. package/src/resources/extensions/gsd/templates/research.md +46 -0
  111. package/src/resources/extensions/gsd/templates/roadmap.md +118 -0
  112. package/src/resources/extensions/gsd/templates/slice-context.md +58 -0
  113. package/src/resources/extensions/gsd/templates/slice-summary.md +99 -0
  114. package/src/resources/extensions/gsd/templates/state.md +19 -0
  115. package/src/resources/extensions/gsd/templates/task-plan.md +52 -0
  116. package/src/resources/extensions/gsd/templates/task-summary.md +57 -0
  117. package/src/resources/extensions/gsd/templates/uat.md +54 -0
  118. package/src/resources/extensions/gsd/tests/activity-log-prune.test.ts +327 -0
  119. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +56 -0
  120. package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +53 -0
  121. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +225 -0
  122. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +160 -0
  123. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +341 -0
  124. package/src/resources/extensions/gsd/tests/derive-state.test.ts +689 -0
  125. package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +38 -0
  126. package/src/resources/extensions/gsd/tests/doctor.test.ts +505 -0
  127. package/src/resources/extensions/gsd/tests/git-service.test.ts +1313 -0
  128. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +308 -0
  129. package/src/resources/extensions/gsd/tests/metrics-io.test.ts +201 -0
  130. package/src/resources/extensions/gsd/tests/metrics.test.ts +217 -0
  131. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +390 -0
  132. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +786 -0
  133. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +657 -0
  134. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +443 -0
  135. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +318 -0
  136. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +420 -0
  137. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +309 -0
  138. package/src/resources/extensions/gsd/tests/parsers.test.ts +1351 -0
  139. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +163 -0
  140. package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +386 -0
  141. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +171 -0
  142. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +155 -0
  143. package/src/resources/extensions/gsd/tests/remote-status.test.ts +99 -0
  144. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +521 -0
  145. package/src/resources/extensions/gsd/tests/requirements.test.ts +125 -0
  146. package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +34 -0
  147. package/src/resources/extensions/gsd/tests/resolve-ts.mjs +11 -0
  148. package/src/resources/extensions/gsd/tests/run-uat.test.ts +348 -0
  149. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +247 -0
  150. package/src/resources/extensions/gsd/tests/workflow-config.test.mjs +53 -0
  151. package/src/resources/extensions/gsd/tests/workspace-index.test.ts +94 -0
  152. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +253 -0
  153. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +160 -0
  154. package/src/resources/extensions/gsd/tests/worktree.test.ts +264 -0
  155. package/src/resources/extensions/gsd/types.ts +159 -0
  156. package/src/resources/extensions/gsd/unit-runtime.ts +184 -0
  157. package/src/resources/extensions/gsd/workspace-index.ts +203 -0
  158. package/src/resources/extensions/gsd/worktree-command.ts +845 -0
  159. package/src/resources/extensions/gsd/worktree-manager.ts +392 -0
  160. package/src/resources/extensions/gsd/worktree.ts +183 -0
  161. package/src/resources/extensions/mac-tools/index.ts +852 -0
  162. package/src/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
  163. package/src/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
  164. package/src/resources/extensions/mcporter/index.ts +429 -0
  165. package/src/resources/extensions/remote-questions/config.ts +81 -0
  166. package/src/resources/extensions/remote-questions/discord-adapter.ts +128 -0
  167. package/src/resources/extensions/remote-questions/format.ts +163 -0
  168. package/src/resources/extensions/remote-questions/manager.ts +192 -0
  169. package/src/resources/extensions/remote-questions/remote-command.ts +307 -0
  170. package/src/resources/extensions/remote-questions/slack-adapter.ts +92 -0
  171. package/src/resources/extensions/remote-questions/status.ts +31 -0
  172. package/src/resources/extensions/remote-questions/store.ts +77 -0
  173. package/src/resources/extensions/remote-questions/types.ts +75 -0
  174. package/src/resources/extensions/search-the-web/cache.ts +78 -0
  175. package/src/resources/extensions/search-the-web/command-search-provider.ts +95 -0
  176. package/src/resources/extensions/search-the-web/format.ts +258 -0
  177. package/src/resources/extensions/search-the-web/http.ts +238 -0
  178. package/src/resources/extensions/search-the-web/index.ts +65 -0
  179. package/src/resources/extensions/search-the-web/native-search.ts +157 -0
  180. package/src/resources/extensions/search-the-web/provider.ts +118 -0
  181. package/src/resources/extensions/search-the-web/tavily.ts +116 -0
  182. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +519 -0
  183. package/src/resources/extensions/search-the-web/tool-llm-context.ts +561 -0
  184. package/src/resources/extensions/search-the-web/tool-search.ts +576 -0
  185. package/src/resources/extensions/search-the-web/url-utils.ts +91 -0
  186. package/src/resources/extensions/shared/confirm-ui.ts +126 -0
  187. package/src/resources/extensions/shared/interview-ui.ts +613 -0
  188. package/src/resources/extensions/shared/next-action-ui.ts +197 -0
  189. package/src/resources/extensions/shared/progress-widget.ts +282 -0
  190. package/src/resources/extensions/shared/terminal.ts +23 -0
  191. package/src/resources/extensions/shared/thinking-widget.ts +107 -0
  192. package/src/resources/extensions/shared/ui.ts +400 -0
  193. package/src/resources/extensions/shared/wizard-ui.ts +551 -0
  194. package/src/resources/extensions/slash-commands/audit.ts +88 -0
  195. package/src/resources/extensions/slash-commands/clear.ts +10 -0
  196. package/src/resources/extensions/slash-commands/create-extension.ts +297 -0
  197. package/src/resources/extensions/slash-commands/create-slash-command.ts +234 -0
  198. package/src/resources/extensions/slash-commands/index.ts +12 -0
  199. package/src/resources/extensions/subagent/agents.ts +126 -0
  200. package/src/resources/extensions/subagent/index.ts +1020 -0
  201. package/src/resources/extensions/voice/index.ts +195 -0
  202. package/src/resources/extensions/voice/speech-recognizer.swift +154 -0
  203. package/src/resources/skills/debug-like-expert/SKILL.md +231 -0
  204. package/src/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
  205. package/src/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
  206. package/src/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
  207. package/src/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
  208. package/src/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
  209. package/src/resources/skills/frontend-design/SKILL.md +45 -0
  210. package/src/resources/skills/swiftui/SKILL.md +208 -0
  211. package/src/resources/skills/swiftui/references/animations.md +921 -0
  212. package/src/resources/skills/swiftui/references/architecture.md +1561 -0
  213. package/src/resources/skills/swiftui/references/layout-system.md +1186 -0
  214. package/src/resources/skills/swiftui/references/navigation.md +1492 -0
  215. package/src/resources/skills/swiftui/references/networking-async.md +214 -0
  216. package/src/resources/skills/swiftui/references/performance.md +1706 -0
  217. package/src/resources/skills/swiftui/references/platform-integration.md +204 -0
  218. package/src/resources/skills/swiftui/references/state-management.md +1443 -0
  219. package/src/resources/skills/swiftui/references/swiftdata.md +297 -0
  220. package/src/resources/skills/swiftui/references/testing-debugging.md +247 -0
  221. package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
  222. package/src/resources/skills/swiftui/workflows/add-feature.md +191 -0
  223. package/src/resources/skills/swiftui/workflows/build-new-app.md +311 -0
  224. package/src/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
  225. package/src/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
  226. package/src/resources/skills/swiftui/workflows/ship-app.md +203 -0
  227. package/src/resources/skills/swiftui/workflows/write-tests.md +235 -0
@@ -0,0 +1,195 @@
1
+ import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
2
+ import { shortcutDesc } from "../shared/terminal.js";
3
+ import type { AssistantMessage } from "@mariozechner/pi-ai";
4
+ import { isKeyRelease, Key, matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
5
+ import { spawn, execSync, type ChildProcess } from "node:child_process";
6
+ import * as fs from "node:fs";
7
+ import * as path from "node:path";
8
+ import * as readline from "node:readline";
9
+
10
+ const SWIFT_SRC = path.join(__dirname, "speech-recognizer.swift");
11
+ const RECOGNIZER_BIN = path.join(__dirname, "speech-recognizer");
12
+
13
+ function ensureBinary(): boolean {
14
+ if (fs.existsSync(RECOGNIZER_BIN)) return true;
15
+ try {
16
+ execSync(`swiftc "${SWIFT_SRC}" -o "${RECOGNIZER_BIN}" -framework Speech -framework AVFoundation`, {
17
+ timeout: 60000,
18
+ });
19
+ return true;
20
+ } catch {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ export default function (pi: ExtensionAPI) {
26
+ if (process.platform !== "darwin") return;
27
+
28
+ let active = false;
29
+ let recognizerProcess: ChildProcess | null = null;
30
+ let flashOn = true;
31
+ let flashTimer: ReturnType<typeof setInterval> | null = null;
32
+ let footerTui: { requestRender: () => void } | null = null;
33
+
34
+ function setVoiceFooter(ctx: ExtensionContext, on: boolean) {
35
+ if (!on) {
36
+ stopFlash();
37
+ ctx.ui.setFooter(undefined);
38
+ return;
39
+ }
40
+
41
+ flashOn = true;
42
+ flashTimer = setInterval(() => {
43
+ flashOn = !flashOn;
44
+ footerTui?.requestRender();
45
+ }, 500);
46
+
47
+ ctx.ui.setFooter((tui, theme, footerData) => {
48
+ footerTui = tui;
49
+ const branchUnsub = footerData.onBranchChange(() => tui.requestRender());
50
+
51
+ return {
52
+ dispose: branchUnsub,
53
+ invalidate() {},
54
+ render(width: number): string[] {
55
+ // Row 1: pwd (branch) ... ● transcribing
56
+ let pwd = process.cwd();
57
+ const home = process.env.HOME || process.env.USERPROFILE;
58
+ if (home && pwd.startsWith(home)) pwd = `~${pwd.slice(home.length)}`;
59
+ const branch = footerData.getGitBranch();
60
+ if (branch) pwd = `${pwd} (${branch})`;
61
+
62
+ const dot = flashOn ? theme.fg("error", "●") : theme.fg("dim", "●");
63
+ const voiceTag = `${dot} ${theme.fg("error", "transcribing")}`;
64
+ const voiceTagWidth = visibleWidth(voiceTag);
65
+
66
+ const maxPwdWidth = width - voiceTagWidth - 2;
67
+ const pwdStr = truncateToWidth(theme.fg("dim", pwd), maxPwdWidth, theme.fg("dim", "..."));
68
+ const pad1 = " ".repeat(Math.max(1, width - visibleWidth(pwdStr) - voiceTagWidth));
69
+ const row1 = truncateToWidth(pwdStr + pad1 + voiceTag, width);
70
+
71
+ // Row 2: stats ... model
72
+ let totalInput = 0, totalOutput = 0, totalCost = 0;
73
+ for (const entry of ctx.sessionManager.getEntries()) {
74
+ if (entry.type === "message" && entry.message.role === "assistant") {
75
+ const m = entry.message as AssistantMessage;
76
+ totalInput += m.usage.input;
77
+ totalOutput += m.usage.output;
78
+ totalCost += m.usage.cost.total;
79
+ }
80
+ }
81
+
82
+ const fmt = (n: number) => n < 1000 ? `${n}` : n < 10000 ? `${(n / 1000).toFixed(1)}k` : `${Math.round(n / 1000)}k`;
83
+ const parts: string[] = [];
84
+ if (totalInput) parts.push(`↑${fmt(totalInput)}`);
85
+ if (totalOutput) parts.push(`↓${fmt(totalOutput)}`);
86
+ if (totalCost) parts.push(`$${totalCost.toFixed(3)}`);
87
+
88
+ const usage = ctx.getContextUsage();
89
+ const ctxPct = usage?.percent !== null && usage?.percent !== undefined ? `${usage.percent.toFixed(1)}%` : "?";
90
+ const ctxWin = usage?.contextWindow ?? ctx.model?.contextWindow ?? 0;
91
+ parts.push(`${ctxPct}/${fmt(ctxWin)}`);
92
+
93
+ const statsLeft = theme.fg("dim", parts.join(" "));
94
+ const modelRight = theme.fg("dim", ctx.model?.id || "no-model");
95
+ const statsLeftW = visibleWidth(statsLeft);
96
+ const modelRightW = visibleWidth(modelRight);
97
+ const pad2 = " ".repeat(Math.max(2, width - statsLeftW - modelRightW));
98
+ const row2 = truncateToWidth(statsLeft + pad2 + modelRight, width);
99
+
100
+ return [row1, row2];
101
+ },
102
+ };
103
+ });
104
+ }
105
+
106
+ function stopFlash() {
107
+ if (flashTimer) { clearInterval(flashTimer); flashTimer = null; }
108
+ footerTui = null;
109
+ }
110
+
111
+ async function toggleVoice(ctx: ExtensionContext) {
112
+ if (active) {
113
+ killRecognizer();
114
+ active = false;
115
+ setVoiceFooter(ctx, false);
116
+ return;
117
+ }
118
+
119
+ if (!ensureBinary()) {
120
+ ctx.ui.notify("Voice: failed to compile speech recognizer (need Xcode CLI tools)", "error");
121
+ return;
122
+ }
123
+
124
+ active = true;
125
+ setVoiceFooter(ctx, true);
126
+ await runVoiceSession(ctx);
127
+ }
128
+
129
+ pi.registerCommand("voice", {
130
+ description: "Toggle voice mode",
131
+ handler: async (_args, ctx) => toggleVoice(ctx),
132
+ });
133
+
134
+ pi.registerShortcut("ctrl+alt+v", {
135
+ description: shortcutDesc("Toggle voice mode", "/voice"),
136
+ handler: async (ctx) => toggleVoice(ctx),
137
+ });
138
+
139
+ function killRecognizer() {
140
+ if (recognizerProcess) { recognizerProcess.kill("SIGTERM"); recognizerProcess = null; }
141
+ }
142
+
143
+ function startRecognizer(
144
+ onPartial: (text: string) => void,
145
+ onFinal: (text: string) => void,
146
+ onError: (msg: string) => void,
147
+ onReady: () => void,
148
+ ) {
149
+ recognizerProcess = spawn(RECOGNIZER_BIN, [], { stdio: ["pipe", "pipe", "pipe"] });
150
+ const rl = readline.createInterface({ input: recognizerProcess.stdout! });
151
+ rl.on("line", (line: string) => {
152
+ if (line === "READY") { onReady(); return; }
153
+ if (line.startsWith("PARTIAL:")) onPartial(line.slice(8));
154
+ else if (line.startsWith("FINAL:")) onFinal(line.slice(6));
155
+ else if (line.startsWith("ERROR:")) onError(line.slice(6));
156
+ });
157
+ recognizerProcess.on("error", (err) => onError(err.message));
158
+ recognizerProcess.on("exit", () => { recognizerProcess = null; });
159
+ }
160
+
161
+ async function runVoiceSession(ctx: ExtensionContext): Promise<void> {
162
+ return new Promise<void>((resolve) => {
163
+ // The Swift recognizer handles accumulation across pause-induced
164
+ // transcription resets. Both PARTIAL and FINAL messages contain
165
+ // the full accumulated text, so we just pass them through.
166
+ startRecognizer(
167
+ (text) => {
168
+ ctx.ui.setEditorText(text);
169
+ },
170
+ (text) => {
171
+ ctx.ui.setEditorText(text);
172
+ },
173
+ (msg) => ctx.ui.notify(`Voice: ${msg}`, "error"),
174
+ () => {},
175
+ );
176
+
177
+ ctx.ui.custom<void>(
178
+ (_tui, _theme, _kb, done) => ({
179
+ render(): string[] { return []; },
180
+ handleInput(data: string) {
181
+ if (isKeyRelease(data)) return;
182
+ if (matchesKey(data, Key.escape) || matchesKey(data, Key.enter)) {
183
+ killRecognizer();
184
+ active = false;
185
+ setVoiceFooter(ctx, false);
186
+ done();
187
+ }
188
+ },
189
+ invalidate() {},
190
+ }),
191
+ { overlay: true, overlayOptions: { anchor: "bottom-center", width: "100%" } },
192
+ ).then(() => resolve());
193
+ });
194
+ }
195
+ }
@@ -0,0 +1,154 @@
1
+ import Foundation
2
+ import Speech
3
+ import AVFoundation
4
+
5
+ // Unbuffered stdout
6
+ setbuf(stdout, nil)
7
+
8
+ guard SFSpeechRecognizer.authorizationStatus() == .authorized ||
9
+ SFSpeechRecognizer.authorizationStatus() == .notDetermined else {
10
+ print("ERROR:Speech recognition not authorized")
11
+ exit(1)
12
+ }
13
+
14
+ SFSpeechRecognizer.requestAuthorization { status in
15
+ guard status == .authorized else {
16
+ print("ERROR:Speech recognition denied")
17
+ exit(1)
18
+ }
19
+ }
20
+
21
+ let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))!
22
+ guard recognizer.isAvailable else {
23
+ print("ERROR:Speech recognizer not available")
24
+ exit(1)
25
+ }
26
+
27
+ let audioEngine = AVAudioEngine()
28
+ let request = SFSpeechAudioBufferRecognitionRequest()
29
+ request.shouldReportPartialResults = true
30
+ request.requiresOnDeviceRecognition = true
31
+
32
+ let node = audioEngine.inputNode
33
+ let format = node.outputFormat(forBus: 0)
34
+
35
+ node.installTap(onBus: 0, bufferSize: 1024, format: format) { buffer, _ in
36
+ request.append(buffer)
37
+ }
38
+
39
+ audioEngine.prepare()
40
+ do {
41
+ try audioEngine.start()
42
+ print("READY")
43
+ } catch {
44
+ print("ERROR:Failed to start audio engine: \(error.localizedDescription)")
45
+ exit(1)
46
+ }
47
+
48
+ // Accumulated finalized text from previous recognition segments.
49
+ // On-device recognition (especially macOS/iOS 18+) can reset
50
+ // bestTranscription.formattedString after a pause, discarding
51
+ // previous text. We detect this by tracking the last known good
52
+ // text and noticing when the new text is shorter / doesn't start
53
+ // with the previous text. When that happens we treat the previous
54
+ // text as finalized and start accumulating the new segment on top.
55
+ var accumulated = ""
56
+ var lastPartialText = ""
57
+ var lastEmitted = ""
58
+
59
+ recognizer.recognitionTask(with: request) { result, error in
60
+ if let result = result {
61
+ let text = result.bestTranscription.formattedString
62
+
63
+ if result.isFinal {
64
+ // True final from the recognizer — commit everything
65
+ let full: String
66
+ // Check if the final text already includes accumulated content
67
+ // (some OS versions give cumulative finals, others reset)
68
+ if !accumulated.isEmpty && !text.lowercased().hasPrefix(accumulated.lowercased()) {
69
+ full = accumulated + " " + text
70
+ } else if !accumulated.isEmpty && text.count < accumulated.count {
71
+ // Final is shorter than what we accumulated — use accumulated + new
72
+ full = accumulated + " " + text
73
+ } else {
74
+ full = text
75
+ }
76
+ accumulated = ""
77
+ lastPartialText = ""
78
+ if full != lastEmitted {
79
+ lastEmitted = full
80
+ print("FINAL:\(full)")
81
+ }
82
+ return
83
+ }
84
+
85
+ // Detect transcription reset: if the new partial text is significantly
86
+ // shorter than what we had, or doesn't start with the previous text,
87
+ // the recognizer has reset after a pause. Finalize what we had.
88
+ let prevText = lastPartialText
89
+ if !prevText.isEmpty && !text.isEmpty {
90
+ let prevWords = prevText.split(separator: " ")
91
+ let newWords = text.split(separator: " ")
92
+
93
+ // Reset detection: new text has fewer words than previous AND
94
+ // the first few words don't match (i.e. it's truly new speech,
95
+ // not just the recognizer revising the last word)
96
+ let looksLikeReset: Bool
97
+ if newWords.count < prevWords.count / 2 {
98
+ // Significant drop in word count — likely a reset
99
+ looksLikeReset = true
100
+ } else if newWords.count < prevWords.count &&
101
+ !prevWords.isEmpty && !newWords.isEmpty &&
102
+ newWords[0] != prevWords[0] {
103
+ // Different starting word + fewer words — reset
104
+ looksLikeReset = true
105
+ } else {
106
+ looksLikeReset = false
107
+ }
108
+
109
+ if looksLikeReset {
110
+ // Commit the previous partial text to accumulated
111
+ if accumulated.isEmpty {
112
+ accumulated = prevText
113
+ } else {
114
+ accumulated = accumulated + " " + prevText
115
+ }
116
+ // Emit a FINAL for the committed text so the TS side updates
117
+ print("FINAL:\(accumulated)")
118
+ lastEmitted = accumulated
119
+ }
120
+ }
121
+
122
+ lastPartialText = text
123
+
124
+ // Build the full display text
125
+ let displayText: String
126
+ if accumulated.isEmpty {
127
+ displayText = text
128
+ } else {
129
+ displayText = accumulated + " " + text
130
+ }
131
+
132
+ if displayText != lastEmitted {
133
+ lastEmitted = displayText
134
+ print("PARTIAL:\(displayText)")
135
+ }
136
+ }
137
+ if let error = error {
138
+ // Task finished errors are normal on kill
139
+ let nsError = error as NSError
140
+ if nsError.code != 216 { // kAFAssistantErrorDomain code for cancelled
141
+ print("ERROR:\(error.localizedDescription)")
142
+ }
143
+ }
144
+ }
145
+
146
+ // Handle SIGTERM/SIGINT gracefully
147
+ signal(SIGTERM) { _ in
148
+ exit(0)
149
+ }
150
+ signal(SIGINT) { _ in
151
+ exit(0)
152
+ }
153
+
154
+ RunLoop.current.run()
@@ -0,0 +1,231 @@
1
+ ---
2
+ name: debug-like-expert
3
+ description: Deep analysis debugging mode for complex issues. Activates methodical investigation protocol with evidence gathering, hypothesis testing, and rigorous verification. Use when standard troubleshooting fails or when issues require systematic root cause analysis.
4
+ ---
5
+
6
+ <objective>
7
+ Deep analysis debugging mode for complex issues. This skill activates methodical investigation protocols with evidence gathering, hypothesis testing, and rigorous verification when standard troubleshooting has failed.
8
+
9
+ The skill emphasizes treating code you wrote with MORE skepticism than unfamiliar code, as cognitive biases about "how it should work" can blind you to actual implementation errors. Use scientific method to systematically identify root causes rather than applying quick fixes.
10
+ </objective>
11
+
12
+ <context>
13
+ This skill activates when standard troubleshooting has failed. The issue requires methodical investigation, not quick fixes. You are entering the mindset of a senior engineer who debugs with scientific rigor.
14
+
15
+ **Important**: If you wrote or modified any of the code being debugged, you have cognitive biases about how it works. Your mental model of "how it should work" may be wrong. Treat code you wrote with MORE skepticism than unfamiliar code - you're blind to your own assumptions.
16
+ </context>
17
+
18
+ <core_principle>
19
+ **VERIFY, DON'T ASSUME.** Every hypothesis must be tested. Every "fix" must be validated. No solutions without evidence.
20
+
21
+ **ESPECIALLY**: Code you designed or implemented is guilty until proven innocent. Your intent doesn't matter - only the code's actual behavior matters. Question your own design decisions as rigorously as you'd question anyone else's.
22
+ </core_principle>
23
+
24
+ <analysis_only_rule>
25
+ **THIS SKILL IS READ-ONLY. DO NOT MODIFY CODE.**
26
+
27
+ The entire purpose is deep analysis and diagnosis. Making changes during investigation:
28
+ - Pollutes the evidence
29
+ - Introduces new variables
30
+ - Makes root cause harder to isolate
31
+
32
+ You are a diagnostician, not a surgeon. Present findings, then let the user decide.
33
+ </analysis_only_rule>
34
+
35
+ <quick_start>
36
+
37
+ <evidence_gathering>
38
+
39
+ Before proposing any solution:
40
+
41
+ **A. Document Current State**
42
+ - What is the EXACT error message or unexpected behavior?
43
+ - What are the EXACT steps to reproduce?
44
+ - What is the ACTUAL output vs EXPECTED output?
45
+ - When did this start working incorrectly (if known)?
46
+
47
+ **B. Map the System**
48
+ - Trace the execution path from entry point to failure point
49
+ - Identify all components involved
50
+ - Read relevant source files completely, not just scanning
51
+ - Note dependencies, imports, configurations affecting this area
52
+
53
+ **C. Gather External Knowledge (when needed)**
54
+ - Use MCP servers for API documentation, library details, or domain knowledge
55
+ - Use web search for error messages, framework-specific behaviors, or recent changes
56
+ - Check official docs for intended behavior vs what you observe
57
+ - Look for known issues, breaking changes, or version-specific quirks
58
+
59
+ See [references/when-to-research.md](references/when-to-research.md) for detailed guidance on research strategy.
60
+
61
+ </evidence_gathering>
62
+
63
+ <root_cause_analysis>
64
+
65
+ **A. Form Hypotheses**
66
+
67
+ Based on evidence, list possible causes:
68
+ 1. [Hypothesis 1] - because [specific evidence]
69
+ 2. [Hypothesis 2] - because [specific evidence]
70
+ 3. [Hypothesis 3] - because [specific evidence]
71
+
72
+ **B. Test Each Hypothesis**
73
+
74
+ For each hypothesis:
75
+ - What would prove this true?
76
+ - What would prove this false?
77
+ - Design a minimal test
78
+ - Execute and document results
79
+
80
+ See [references/hypothesis-testing.md](references/hypothesis-testing.md) for scientific method application.
81
+
82
+ **C. Eliminate or Confirm**
83
+
84
+ Don't move forward until you can answer:
85
+ - Which hypothesis is supported by evidence?
86
+ - What evidence contradicts other hypotheses?
87
+ - What additional information is needed?
88
+
89
+ </root_cause_analysis>
90
+
91
+ <solution_proposal>
92
+
93
+ **Only after confirming root cause:**
94
+
95
+ **A. Design Recommended Fix**
96
+ - What is the MINIMAL change that would address the root cause?
97
+ - What are potential side effects?
98
+ - What could this break?
99
+ - What tests should run after implementation?
100
+
101
+ **B. Document, Don't Implement**
102
+ - Describe the fix with enough detail for implementation
103
+ - Include specific file paths, line numbers, and code snippets
104
+ - Explain WHY this addresses the root cause
105
+ - Note any prerequisites or dependencies
106
+
107
+ **DO NOT make any code changes. Present your recommendations only.**
108
+
109
+ See [references/verification-patterns.md](references/verification-patterns.md) for verification approaches to use after implementation.
110
+
111
+ </solution_proposal>
112
+
113
+ </quick_start>
114
+
115
+ <critical_rules>
116
+
117
+ 1. **NO DRIVE-BY FIXES**: If you can't explain WHY a change works, don't make it
118
+ 2. **VERIFY EVERYTHING**: Test your assumptions. Read the actual code. Check the actual behavior
119
+ 3. **USE ALL TOOLS**:
120
+ - MCP servers for external knowledge
121
+ - Web search for error messages, docs, known issues
122
+ - Extended thinking ("think deeply") for complex reasoning
123
+ - File reading for complete context
124
+ 4. **THINK OUT LOUD**: Document your reasoning at each step
125
+ 5. **ONE VARIABLE**: Change one thing at a time, verify, then proceed
126
+ 6. **COMPLETE READS**: Don't skim code. Read entire relevant files
127
+ 7. **CHASE DEPENDENCIES**: If the issue involves libraries, configs, or external systems, investigate those too
128
+ 8. **QUESTION PREVIOUS WORK**: Maybe the earlier "fix" was wrong. Re-examine with fresh eyes
129
+
130
+ </critical_rules>
131
+
132
+ <success_criteria>
133
+
134
+ Before completing:
135
+ - [ ] Do you understand WHY the issue occurred?
136
+ - [ ] Have you identified a root cause with evidence?
137
+ - [ ] Have you documented your reasoning?
138
+ - [ ] Can you explain the issue to someone else?
139
+ - [ ] Is your recommended fix specific and actionable?
140
+
141
+ If you can't answer "yes" to all of these, keep investigating.
142
+
143
+ **CRITICAL**: Present findings via decision gate. Do NOT implement changes.
144
+
145
+ </success_criteria>
146
+
147
+ <output_format>
148
+
149
+ ```markdown
150
+ ## Issue: [Problem Description]
151
+
152
+ ### Evidence
153
+ [What you observed - exact errors, behaviors, outputs]
154
+
155
+ ### Investigation
156
+ [What you checked, what you found, what you ruled out]
157
+
158
+ ### Root Cause
159
+ [The actual underlying problem with evidence]
160
+
161
+ ### Recommended Fix
162
+ [What SHOULD be changed and WHY - specific files, lines, code]
163
+
164
+ ### Verification Plan
165
+ [How to confirm the fix works after implementation]
166
+
167
+ ### Risk Assessment
168
+ [Potential side effects, what could break, confidence level]
169
+ ```
170
+
171
+ </output_format>
172
+
173
+ <advanced_topics>
174
+
175
+ For deeper topics, see reference files:
176
+
177
+ **Debugging mindset**: [references/debugging-mindset.md](references/debugging-mindset.md)
178
+ - First principles thinking applied to debugging
179
+ - Cognitive biases that lead to bad fixes
180
+ - The discipline of systematic investigation
181
+ - When to stop and restart with fresh assumptions
182
+
183
+ **Investigation techniques**: [references/investigation-techniques.md](references/investigation-techniques.md)
184
+ - Binary search / divide and conquer
185
+ - Rubber duck debugging
186
+ - Minimal reproduction
187
+ - Working backwards from desired state
188
+ - Adding observability before changing code
189
+
190
+ **Hypothesis testing**: [references/hypothesis-testing.md](references/hypothesis-testing.md)
191
+ - Forming falsifiable hypotheses
192
+ - Designing experiments that prove/disprove
193
+ - What makes evidence strong vs weak
194
+ - Recovering from wrong hypotheses gracefully
195
+
196
+ **Verification patterns**: [references/verification-patterns.md](references/verification-patterns.md)
197
+ - Definition of "verified" (not just "it ran")
198
+ - Testing reproduction steps
199
+ - Regression testing adjacent functionality
200
+ - When to write tests before fixing
201
+
202
+ **Research strategy**: [references/when-to-research.md](references/when-to-research.md)
203
+ - Signals that you need external knowledge
204
+ - What to search for vs what to reason about
205
+ - Balancing research time vs experimentation
206
+
207
+ </advanced_topics>
208
+
209
+ <decision_gate>
210
+
211
+ **After presenting findings, ALWAYS offer these options:**
212
+
213
+ ```
214
+ ─────────────────────────────────────────
215
+ ANALYSIS COMPLETE
216
+
217
+ What would you like to do?
218
+
219
+ 1. **Fix it now** - I'll implement the recommended changes
220
+ 2. **Create findings document** - Save analysis to a markdown file
221
+ 3. **Explore further** - Investigate additional hypotheses
222
+ 4. **Get second opinion** - Review with different assumptions
223
+ 5. **Other** - Tell me what you need
224
+ ─────────────────────────────────────────
225
+ ```
226
+
227
+ **Wait for user response before taking any action.**
228
+
229
+ This gate is MANDATORY. Never skip it. Never auto-implement.
230
+
231
+ </decision_gate>