pi-ui-extend 1.0.41 → 1.0.45

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 (236) hide show
  1. package/README.md +50 -13
  2. package/dist/app/app.d.ts +13 -0
  3. package/dist/app/app.js +158 -8
  4. package/dist/app/cli/install.js +2 -2
  5. package/dist/app/commands/command-controller.d.ts +4 -0
  6. package/dist/app/commands/command-controller.js +11 -0
  7. package/dist/app/commands/command-git-actions.d.ts +25 -0
  8. package/dist/app/commands/command-git-actions.js +381 -0
  9. package/dist/app/commands/command-host.d.ts +4 -0
  10. package/dist/app/commands/command-host.js +5 -2
  11. package/dist/app/commands/command-model-actions.d.ts +1 -0
  12. package/dist/app/commands/command-model-actions.js +57 -35
  13. package/dist/app/commands/command-navigation-actions.d.ts +1 -0
  14. package/dist/app/commands/command-navigation-actions.js +16 -3
  15. package/dist/app/commands/command-registry.d.ts +2 -0
  16. package/dist/app/commands/command-registry.js +15 -1
  17. package/dist/app/commands/command-session-actions.js +9 -3
  18. package/dist/app/commands/reload-context-inventory.d.ts +11 -0
  19. package/dist/app/commands/reload-context-inventory.js +70 -0
  20. package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
  21. package/dist/app/extensions/extension-actions-controller.js +6 -0
  22. package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
  23. package/dist/app/extensions/subagent-catalog-state.js +23 -0
  24. package/dist/app/input/autocomplete-controller.js +61 -34
  25. package/dist/app/input/input-action-controller.d.ts +2 -0
  26. package/dist/app/input/input-action-controller.js +8 -1
  27. package/dist/app/input/input-controller.d.ts +2 -1
  28. package/dist/app/input/input-controller.js +7 -2
  29. package/dist/app/input/prompt-enhancer-controller.js +53 -35
  30. package/dist/app/input/voice-controller.d.ts +41 -45
  31. package/dist/app/input/voice-controller.js +351 -419
  32. package/dist/app/model/model-usage-controller.js +17 -7
  33. package/dist/app/model/model-usage-status.d.ts +4 -1
  34. package/dist/app/model/model-usage-status.js +270 -46
  35. package/dist/app/popup/menu-items-controller.d.ts +13 -3
  36. package/dist/app/popup/menu-items-controller.js +37 -21
  37. package/dist/app/popup/popup-action-controller.d.ts +12 -2
  38. package/dist/app/popup/popup-action-controller.js +77 -24
  39. package/dist/app/popup/popup-menu-controller.d.ts +36 -14
  40. package/dist/app/popup/popup-menu-controller.js +239 -69
  41. package/dist/app/rendering/dcp-stats.d.ts +9 -4
  42. package/dist/app/rendering/dcp-stats.js +40 -425
  43. package/dist/app/rendering/editor-panels.js +10 -4
  44. package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
  45. package/dist/app/rendering/popup-menu-renderer.js +42 -37
  46. package/dist/app/rendering/render-controller.js +23 -2
  47. package/dist/app/rendering/status-line-renderer.d.ts +5 -0
  48. package/dist/app/rendering/status-line-renderer.js +41 -5
  49. package/dist/app/rendering/tab-line-renderer.js +26 -20
  50. package/dist/app/runtime.d.ts +12 -1
  51. package/dist/app/runtime.js +120 -12
  52. package/dist/app/screen/mouse-controller.d.ts +2 -0
  53. package/dist/app/screen/mouse-controller.js +17 -7
  54. package/dist/app/screen/status-controller.d.ts +4 -0
  55. package/dist/app/screen/status-controller.js +5 -0
  56. package/dist/app/session/lazy-session-manager.js +34 -0
  57. package/dist/app/session/session-event-controller.d.ts +1 -0
  58. package/dist/app/session/session-event-controller.js +10 -1
  59. package/dist/app/session/session-history.d.ts +1 -0
  60. package/dist/app/session/session-history.js +12 -1
  61. package/dist/app/session/session-lifecycle-controller.d.ts +7 -1
  62. package/dist/app/session/session-lifecycle-controller.js +16 -1
  63. package/dist/app/session/tabs-controller.d.ts +26 -1
  64. package/dist/app/session/tabs-controller.js +454 -147
  65. package/dist/app/subagents/subagents-files.js +60 -1
  66. package/dist/app/subagents/subagents-model.d.ts +1 -0
  67. package/dist/app/subagents/subagents-model.js +18 -2
  68. package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
  69. package/dist/app/subagents/subagents-widget-controller.js +6 -0
  70. package/dist/app/types.d.ts +16 -1
  71. package/dist/app/workspace/workspace-actions-controller.js +10 -2
  72. package/dist/app/workspace/workspace-undo.d.ts +1 -0
  73. package/dist/app/workspace/workspace-undo.js +1 -0
  74. package/dist/bundled-extensions/question/index.js +9 -1
  75. package/dist/bundled-extensions/question/remote.d.ts +4 -0
  76. package/dist/bundled-extensions/question/remote.js +33 -0
  77. package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
  78. package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
  79. package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
  80. package/dist/bundled-extensions/telegram-connector/config.js +87 -0
  81. package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
  82. package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
  83. package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
  84. package/dist/bundled-extensions/telegram-connector/index.js +195 -0
  85. package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
  86. package/dist/bundled-extensions/terminal-bell/index.js +0 -76
  87. package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
  88. package/dist/bundled-extensions/workspace-undo/index.js +191 -0
  89. package/dist/config.d.ts +21 -2
  90. package/dist/config.js +159 -32
  91. package/dist/default-pix-config.js +25 -5
  92. package/dist/schemas/index.d.ts +1 -0
  93. package/dist/schemas/index.js +1 -0
  94. package/dist/schemas/pi-tools-suite-schema.d.ts +88 -62
  95. package/dist/schemas/pi-tools-suite-schema.js +54 -83
  96. package/dist/schemas/pix-schema.d.ts +19 -2
  97. package/dist/schemas/pix-schema.js +47 -5
  98. package/dist/schemas/tasks-schema.d.ts +18 -0
  99. package/dist/schemas/tasks-schema.js +41 -0
  100. package/docs/concurrency.md +9 -1
  101. package/docs/desktop-mvp.md +22 -6
  102. package/docs/desktop-task-manager.md +148 -84
  103. package/docs/release.md +30 -6
  104. package/external/pi-tools-suite/README.md +197 -84
  105. package/external/pi-tools-suite/docs/evals.md +1 -1
  106. package/external/pi-tools-suite/docs/session-recovery.md +47 -14
  107. package/external/pi-tools-suite/docs/subagent-model-pools.md +48 -30
  108. package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
  109. package/external/pi-tools-suite/package.json +6 -1
  110. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
  111. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
  112. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
  113. package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
  114. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
  115. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
  116. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
  117. package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
  118. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
  119. package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
  120. package/external/pi-tools-suite/src/async-subagents/agents/research.md +5 -3
  121. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
  122. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
  123. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
  124. package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
  125. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
  126. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
  127. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
  128. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
  129. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
  130. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
  131. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
  132. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
  133. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
  134. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
  135. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
  136. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
  137. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
  138. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
  139. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
  140. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
  141. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
  142. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
  143. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
  144. package/external/pi-tools-suite/src/async-subagents/commands.ts +15 -71
  145. package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
  146. package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +5 -4
  147. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
  148. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +8 -5
  149. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
  150. package/external/pi-tools-suite/src/async-subagents/core/config.ts +160 -327
  151. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
  152. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
  153. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +21 -5
  154. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +40 -26
  155. package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
  156. package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
  157. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
  158. package/external/pi-tools-suite/src/async-subagents/index.ts +69 -5
  159. package/external/pi-tools-suite/src/async-subagents/lib.ts +16 -9
  160. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +8 -5
  161. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +5 -4
  162. package/external/pi-tools-suite/src/async-subagents/types.ts +1 -0
  163. package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
  164. package/external/pi-tools-suite/src/config.ts +55 -1
  165. package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
  166. package/external/pi-tools-suite/src/context-gateway/config.ts +77 -3
  167. package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
  168. package/external/pi-tools-suite/src/context-gateway/enforcement.ts +222 -0
  169. package/external/pi-tools-suite/src/context-gateway/index.ts +206 -19
  170. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +7 -7
  171. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +101 -28
  172. package/external/pi-tools-suite/src/context-gateway/types.ts +16 -3
  173. package/external/pi-tools-suite/src/context-inventory.ts +99 -0
  174. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
  175. package/external/pi-tools-suite/src/dcp/auto-compress.ts +128 -49
  176. package/external/pi-tools-suite/src/dcp/commands.ts +32 -156
  177. package/external/pi-tools-suite/src/dcp/compress-tool.ts +177 -46
  178. package/external/pi-tools-suite/src/dcp/compression-blocks.ts +6 -58
  179. package/external/pi-tools-suite/src/dcp/compression-preview.ts +9 -0
  180. package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
  181. package/external/pi-tools-suite/src/dcp/config.ts +114 -17
  182. package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
  183. package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
  184. package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
  185. package/external/pi-tools-suite/src/dcp/index.ts +338 -66
  186. package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
  187. package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
  188. package/external/pi-tools-suite/src/dcp/prompts.ts +83 -192
  189. package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
  190. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +93 -3
  191. package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +6 -10
  192. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
  193. package/external/pi-tools-suite/src/dcp/pruner-tools.ts +6 -3
  194. package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
  195. package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
  196. package/external/pi-tools-suite/src/dcp/state.ts +9 -0
  197. package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
  198. package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
  199. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +78 -22
  200. package/external/pi-tools-suite/src/index.ts +7 -1
  201. package/external/pi-tools-suite/src/lib/project.ts +36 -1
  202. package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
  203. package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
  204. package/external/pi-tools-suite/src/resource-registry/index.ts +2551 -0
  205. package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
  206. package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
  207. package/external/pi-tools-suite/src/todo/index.ts +21 -0
  208. package/external/pi-tools-suite/src/todo/todo.ts +19 -1
  209. package/external/pi-tools-suite/src/tool-descriptions.ts +47 -19
  210. package/package.json +10 -9
  211. package/schemas/pi-tools-suite.json +466 -287
  212. package/schemas/pix.json +129 -11
  213. package/schemas/tasks.json +131 -0
  214. package/skills/simplify/SKILL.md +33 -5
  215. package/docs/desktop-markdown-media.md +0 -77
  216. package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -177
  217. package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
  218. package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
  219. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -54
  220. package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
  221. package/skills/playwright-cli/SKILL.md +0 -420
  222. package/skills/playwright-cli/references/element-attributes.md +0 -23
  223. package/skills/playwright-cli/references/playwright-tests.md +0 -50
  224. package/skills/playwright-cli/references/request-mocking.md +0 -87
  225. package/skills/playwright-cli/references/running-code.md +0 -241
  226. package/skills/playwright-cli/references/session-management.md +0 -273
  227. package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
  228. package/skills/playwright-cli/references/storage-state.md +0 -290
  229. package/skills/playwright-cli/references/test-generation.md +0 -142
  230. package/skills/playwright-cli/references/tracing.md +0 -154
  231. package/skills/playwright-cli/references/video-recording.md +0 -147
  232. package/skills/spec-lite/SKILL.md +0 -140
  233. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
  234. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
  235. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
  236. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
@@ -1,6 +1,6 @@
1
1
  import path from "node:path";
2
- import { REPO_DISCOVERY_TOOLS } from "../tool-descriptions";
3
- import { directoryExists, findIndexedProjectRoot, findProjectRoot } from "../lib/project.js";
2
+ import { REPO_DISCOVERY_TOOLS, REPO_KNOWLEDGE_TOOL_DESCRIPTION } from "../tool-descriptions";
3
+ import { commandAvailable, directoryExists, findProjectRoot, hasAvailableIndexedProjectRoot } from "../lib/project.js";
4
4
  import {
5
5
  applyNativeCompactPolicy,
6
6
  describeNativeCompactArgs,
@@ -12,6 +12,21 @@ import {
12
12
  } from "./native-compact.js";
13
13
 
14
14
  const IDX_COMMANDS = ["architecture", "structure", "ast", "search", "explain", "deps"] as const;
15
+ const REPO_KNOWLEDGE_ACTIONS = [
16
+ "context",
17
+ "search",
18
+ "show",
19
+ "status",
20
+ "audit",
21
+ "discover",
22
+ "impact",
23
+ "catalog",
24
+ "record",
25
+ "verify",
26
+ "relate",
27
+ "remove",
28
+ ] as const;
29
+ const REPO_KNOWLEDGE_MUTATING_ACTIONS = new Set<string>(["record", "verify", "relate", "remove"]);
15
30
  const TARGET_COMMANDS = new Set<string>(["ast", "search", "explain", "deps"]);
16
31
  const DEFAULT_MAX_LINES = 2000;
17
32
  const DEFAULT_MAX_BYTES = 50_000;
@@ -22,6 +37,12 @@ const SYSTEM_CUSTOM_MESSAGE_TYPE = "pix-system";
22
37
  const idxExecutionQueues = new Map<string, Promise<void>>();
23
38
 
24
39
  type IdxCommand = (typeof IDX_COMMANDS)[number];
40
+ type RepoKnowledgeAction = (typeof REPO_KNOWLEDGE_ACTIONS)[number];
41
+ type KnowledgeClassification = "spec" | "spec-like" | "meta-index" | "design-only" | "guide" | "other";
42
+ type KnowledgeBehaviorType = "as-is" | "change" | "mixed" | "unknown";
43
+ type KnowledgeLifecycle = "active" | "proposed" | "historical" | "superseded" | "unknown";
44
+ type KnowledgeRelationKind = "implements" | "tests" | "related" | "supersedes" | "superseded-by";
45
+ type KnowledgeRelationAction = "add" | "remove";
25
46
 
26
47
  type RepoDiscoveryParams = {
27
48
  command: IdxCommand;
@@ -34,6 +55,39 @@ type RepoDiscoveryParams = {
34
55
 
35
56
  type RepoDiscoveryWrapperParams = Omit<RepoDiscoveryParams, "command">;
36
57
 
58
+ type RepoKnowledgeParams = {
59
+ action: RepoKnowledgeAction;
60
+ query?: string;
61
+ path?: string;
62
+ paths?: string[];
63
+ classification?: KnowledgeClassification;
64
+ behaviorType?: KnowledgeBehaviorType;
65
+ lifecycle?: KnowledgeLifecycle;
66
+ confidence?: "high" | "medium" | "low" | "unknown";
67
+ summary?: string;
68
+ topics?: string[];
69
+ includeSecondary?: boolean;
70
+ pathPrefix?: string;
71
+ limit?: number;
72
+ budget?: number;
73
+ maxSpecs?: number;
74
+ maxCode?: number;
75
+ maxTests?: number;
76
+ includeAll?: boolean;
77
+ allUnclassified?: boolean;
78
+ base?: string;
79
+ semantic?: boolean;
80
+ relationAction?: KnowledgeRelationAction;
81
+ relationKind?: KnowledgeRelationKind;
82
+ targetPaths?: string[];
83
+ sourceReviewed?: boolean;
84
+ evidenceReviewed?: boolean;
85
+ metadataOnlyConfirmed?: boolean;
86
+ maxLines?: number;
87
+ maxBytes?: number;
88
+ outputMode?: RepoDiscoveryOutputMode;
89
+ };
90
+
37
91
  type ExecResult = {
38
92
  stdout: string;
39
93
  stderr: string;
@@ -108,6 +162,16 @@ function positiveInteger(value: number | undefined, fallback: number): number {
108
162
 
109
163
  function ensureIndexedProject(cwd: string, toolName: string) {
110
164
  const projectRoot = findProjectRoot(cwd);
165
+ if (!commandAvailable("idx")) {
166
+ return {
167
+ projectRoot,
168
+ error: [
169
+ `${toolName} is unavailable because idx is not on PATH.`,
170
+ "Do not initialize, install, or create project-local index state implicitly.",
171
+ "If the user wants indexed repository tools, ask for explicit permission to run /idx-init, then /reload.",
172
+ ].join("\n"),
173
+ };
174
+ }
111
175
  const indexerDir = path.join(projectRoot, ".indexer-cli");
112
176
  if (directoryExists(indexerDir)) return { projectRoot, initialized: false };
113
177
 
@@ -124,7 +188,6 @@ function ensureIndexedProject(cwd: string, toolName: string) {
124
188
  async function initializeIndexedProject(pi: ExtensionAPI, cwd: string, signal: AbortSignal | undefined) {
125
189
  const projectRoot = findProjectRoot(cwd);
126
190
  const indexerDir = path.join(projectRoot, ".indexer-cli");
127
- if (directoryExists(indexerDir)) return { projectRoot, initialized: false, alreadyIndexed: true, output: "Project is already indexed." };
128
191
 
129
192
  const idxCli = await ensureIdxCliAvailable(pi, projectRoot, signal);
130
193
  if (!idxCli.available) {
@@ -137,6 +200,17 @@ async function initializeIndexedProject(pi: ExtensionAPI, cwd: string, signal: A
137
200
  installedIdx: idxCli.installed,
138
201
  };
139
202
  }
203
+ if (directoryExists(indexerDir)) {
204
+ return {
205
+ projectRoot,
206
+ initialized: false,
207
+ alreadyIndexed: true,
208
+ output: idxCli.installed
209
+ ? `idx was installed and the project is already indexed: ${projectRoot}. Run /reload to expose repo_* tools.`
210
+ : "Project is already indexed.",
211
+ installedIdx: idxCli.installed,
212
+ };
213
+ }
140
214
 
141
215
  const init = await pi.exec("idx", ["init"], { cwd: projectRoot, signal, timeout: 600_000 });
142
216
  const initOutput = [init.stdout, init.stderr].filter(Boolean).join(init.stdout && init.stderr ? "\n" : "").trim() || "No output";
@@ -322,6 +396,159 @@ async function executeRepoDiscovery(
322
396
  });
323
397
  }
324
398
 
399
+ function nonEmpty(value: unknown): value is string {
400
+ return typeof value === "string" && value.trim().length > 0;
401
+ }
402
+
403
+ function normalizedStrings(value: unknown): string[] {
404
+ if (!Array.isArray(value)) return [];
405
+ return [...new Set(value.filter((item): item is string => nonEmpty(item)).map((item) => item.trim()))];
406
+ }
407
+
408
+ function positiveBounded(value: number | undefined, fallback: number, maximum: number): number {
409
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) return fallback;
410
+ return Math.min(value, maximum);
411
+ }
412
+
413
+ function buildRepoKnowledgeArgs(params: RepoKnowledgeParams): string[] | string {
414
+ if (!REPO_KNOWLEDGE_ACTIONS.includes(params.action)) {
415
+ return `Invalid repo_knowledge action. Use one of: ${REPO_KNOWLEDGE_ACTIONS.join(", ")}.`;
416
+ }
417
+
418
+ const query = params.query?.trim();
419
+ const sourcePath = params.path?.trim();
420
+ const paths = normalizedStrings(params.paths);
421
+ const topics = normalizedStrings(params.topics);
422
+ const targets = normalizedStrings(params.targetPaths);
423
+
424
+ switch (params.action) {
425
+ case "context": {
426
+ if (!query) return "repo_knowledge action=context requires query.";
427
+ const args = [
428
+ "context",
429
+ query,
430
+ "--budget",
431
+ String(positiveBounded(params.budget, 1400, 8000)),
432
+ "--max-specs",
433
+ String(positiveBounded(params.maxSpecs, 4, 20)),
434
+ "--max-code",
435
+ String(positiveBounded(params.maxCode, 6, 30)),
436
+ "--max-tests",
437
+ String(positiveBounded(params.maxTests, 4, 20)),
438
+ ];
439
+ if (params.includeSecondary) args.push("--include-secondary");
440
+ if (nonEmpty(params.pathPrefix)) args.push("--path-prefix", params.pathPrefix.trim());
441
+ return args;
442
+ }
443
+ case "search": {
444
+ if (!query) return "repo_knowledge action=search requires query.";
445
+ const args = ["wiki", "search", query, "--limit", String(positiveBounded(params.limit, 5, 20))];
446
+ if (params.includeSecondary) args.push("--include-secondary");
447
+ if (nonEmpty(params.pathPrefix)) args.push("--path-prefix", params.pathPrefix.trim());
448
+ return args;
449
+ }
450
+ case "show":
451
+ return sourcePath ? ["wiki", "show", "--path", sourcePath] : "repo_knowledge action=show requires path.";
452
+ case "status":
453
+ case "audit":
454
+ return ["wiki", params.action, "--candidate-limit", String(positiveBounded(params.limit, 20, 100))];
455
+ case "discover": {
456
+ if (params.includeAll && params.allUnclassified) return "repo_knowledge discover cannot combine includeAll and allUnclassified.";
457
+ const args = ["wiki", "discover", "--limit", String(positiveBounded(params.limit, 40, 200))];
458
+ if (params.includeAll) args.push("--all");
459
+ if (params.allUnclassified) args.push("--all-unclassified");
460
+ return args;
461
+ }
462
+ case "impact": {
463
+ const args = ["wiki", "impact", ...paths];
464
+ if (nonEmpty(params.base)) args.push("--base", params.base.trim());
465
+ args.push("--semantic-limit", String(positiveBounded(params.limit, 5, 20)));
466
+ if (params.semantic === false) args.push("--no-semantic");
467
+ return args;
468
+ }
469
+ case "catalog":
470
+ return ["wiki", "catalog"];
471
+ case "record": {
472
+ if (!sourcePath) return "repo_knowledge action=record requires path.";
473
+ if (!params.classification) return "repo_knowledge action=record requires classification.";
474
+ if (params.sourceReviewed !== true) return "repo_knowledge record refused: read/classify the source first, then retry with sourceReviewed=true.";
475
+ if (["spec", "spec-like"].includes(params.classification) && (!params.behaviorType || !params.lifecycle)) {
476
+ return "repo_knowledge record for primary knowledge requires behaviorType and lifecycle.";
477
+ }
478
+ const args = ["wiki", "record", "--path", sourcePath, "--classification", params.classification];
479
+ if (params.behaviorType) args.push("--type", params.behaviorType);
480
+ if (params.lifecycle) args.push("--lifecycle", params.lifecycle);
481
+ if (params.confidence) args.push("--confidence", params.confidence);
482
+ if (nonEmpty(params.summary)) args.push("--summary", params.summary.trim());
483
+ for (const topic of topics) args.push("--topic", topic);
484
+ return args;
485
+ }
486
+ case "verify":
487
+ if (!sourcePath) return "repo_knowledge action=verify requires path.";
488
+ if (params.evidenceReviewed !== true) return "repo_knowledge verify refused: inspect the primary source and relevant code/tests first, then retry with evidenceReviewed=true.";
489
+ return ["wiki", "verify", "--path", sourcePath];
490
+ case "relate": {
491
+ if (!sourcePath) return "repo_knowledge action=relate requires path.";
492
+ if (params.evidenceReviewed !== true) return "repo_knowledge relate refused: review concrete evidence first; semantic/graph similarity alone is insufficient. Retry with evidenceReviewed=true.";
493
+ if (!params.relationAction || !params.relationKind || targets.length === 0) {
494
+ return "repo_knowledge relate requires relationAction, relationKind, and targetPaths.";
495
+ }
496
+ const flags: Record<KnowledgeRelationKind, Record<KnowledgeRelationAction, string>> = {
497
+ implements: { add: "--add-code", remove: "--remove-code" },
498
+ tests: { add: "--add-test", remove: "--remove-test" },
499
+ related: { add: "--add-related-spec", remove: "--remove-related-spec" },
500
+ supersedes: { add: "--add-supersedes", remove: "--remove-supersedes" },
501
+ "superseded-by": { add: "--add-superseded-by", remove: "--remove-superseded-by" },
502
+ };
503
+ const args = ["wiki", "relate", "--path", sourcePath];
504
+ const flag = flags[params.relationKind][params.relationAction];
505
+ for (const target of targets) args.push(flag, target);
506
+ return args;
507
+ }
508
+ case "remove":
509
+ if (!sourcePath) return "repo_knowledge action=remove requires path.";
510
+ if (params.metadataOnlyConfirmed !== true) return "repo_knowledge remove refused: confirm that only knowledge metadata should be removed and the source document must remain, then retry with metadataOnlyConfirmed=true.";
511
+ return ["wiki", "remove", "--path", sourcePath];
512
+ }
513
+ }
514
+
515
+ async function executeRepoKnowledge(
516
+ pi: ExtensionAPI,
517
+ params: RepoKnowledgeParams,
518
+ signal: AbortSignal | undefined,
519
+ ctx: ToolContext,
520
+ profile: RepoDiscoveryProfile,
521
+ ) {
522
+ if (signal?.aborted) return textResult("repo_knowledge cancelled");
523
+ const idxArgs = buildRepoKnowledgeArgs(params);
524
+ if (typeof idxArgs === "string") return textResult(idxArgs, true, { action: params.action });
525
+
526
+ const indexedProject = ensureIndexedProject(ctx.cwd, "repo_knowledge");
527
+ if (indexedProject.error) return textResult(indexedProject.error, true, { projectRoot: indexedProject.projectRoot, action: params.action });
528
+
529
+ const result = await runQueuedIdx(indexedProject.projectRoot, () =>
530
+ pi.exec("idx", idxArgs, { cwd: indexedProject.projectRoot, signal, timeout: 180_000 }),
531
+ );
532
+ const exitCode = result.code ?? 0;
533
+ const combined = [result.stdout, result.stderr].filter(Boolean).join(result.stdout && result.stderr ? "\n" : "");
534
+ const output = combined.trim() ? combined : "No output";
535
+ const native = profile === "native-compact";
536
+ const maxLines = positiveInteger(params.maxLines, native ? 400 : 600);
537
+ const maxBytes = positiveInteger(params.maxBytes, native ? 12_000 : 20_000);
538
+ const truncated = native
539
+ ? truncateNativeCompactOutput(output, Math.min(maxLines, params.outputMode === "full" ? 2_000 : 400), Math.min(maxBytes, params.outputMode === "full" ? 50_000 : 12_000), params.outputMode ?? "compact")
540
+ : truncateOutput(output, Math.min(maxLines, 2_000), Math.min(maxBytes, 50_000));
541
+
542
+ return textResult(truncated.text, exitCode !== 0, {
543
+ action: params.action,
544
+ mutating: REPO_KNOWLEDGE_MUTATING_ACTIONS.has(params.action),
545
+ command: ["idx", ...idxArgs],
546
+ cwd: indexedProject.projectRoot,
547
+ exitCode,
548
+ truncation: truncated.truncation,
549
+ });
550
+ }
551
+
325
552
  const BASELINE_REPO_TOOL_PROPERTIES = {
326
553
  maxLines: numberSchema("Returned line cap, keeps top lines (default 2000). Prefer native limits/cursors before raising.", DEFAULT_MAX_LINES),
327
554
  maxBytes: numberSchema("Returned byte cap, keeps top bytes (default 50000). Narrow the query before raising.", DEFAULT_MAX_BYTES),
@@ -382,6 +609,62 @@ function repoToolParameters(command: IdxCommand, targetDescription: string | und
382
609
  };
383
610
  }
384
611
 
612
+ function repoKnowledgeParameters(profile: RepoDiscoveryProfile) {
613
+ const outputProperties = profile === "native-compact"
614
+ ? NATIVE_COMPACT_REPO_TOOL_PROPERTIES
615
+ : {
616
+ maxLines: numberSchema("Returned line cap for knowledge output (default 600; max delivery 2000). Narrow the action/query first.", 600),
617
+ maxBytes: numberSchema("Returned byte cap for knowledge output (default 20000; max delivery 50000). Narrow before raising.", 20_000),
618
+ };
619
+ return {
620
+ type: "object",
621
+ properties: {
622
+ action: {
623
+ type: "string",
624
+ enum: [...REPO_KNOWLEDGE_ACTIONS],
625
+ description: "Knowledge action. record/verify/relate/remove mutate idx knowledge metadata; source spec files are edited with normal file tools.",
626
+ },
627
+ query: stringSchema("Behavior/contract query for context or search."),
628
+ path: stringSchema("Project-relative primary knowledge path for show/record/verify/relate/remove."),
629
+ paths: { type: "array", items: stringSchema("Project-relative task-changed path"), description: "Task-scoped changed paths for impact. Prefer this over whole-worktree fallback." },
630
+ classification: { type: "string", enum: ["spec", "spec-like", "meta-index", "design-only", "guide", "other"] },
631
+ behaviorType: { type: "string", enum: ["as-is", "change", "mixed", "unknown"] },
632
+ lifecycle: { type: "string", enum: ["active", "proposed", "historical", "superseded", "unknown"] },
633
+ confidence: { type: "string", enum: ["high", "medium", "low", "unknown"] },
634
+ summary: stringSchema("Compact retrieval summary based on the reviewed primary source; never invent behavior."),
635
+ topics: { type: "array", items: stringSchema("Retrieval topic") },
636
+ includeSecondary: { type: "boolean", description: "Include design-only secondary knowledge for context/search." },
637
+ pathPrefix: stringSchema("Optional project-relative scope for context/search."),
638
+ limit: boundedIntegerSchema("Result/candidate/semantic limit depending on action.", 5, 200),
639
+ budget: boundedIntegerSchema("Context token budget; context only.", 1400, 8000),
640
+ maxSpecs: boundedIntegerSchema("Maximum primary specs in context.", 4, 20),
641
+ maxCode: boundedIntegerSchema("Maximum implementation ranges/files in context.", 6, 30),
642
+ maxTests: boundedIntegerSchema("Maximum test hints in context.", 4, 20),
643
+ includeAll: { type: "boolean", description: "discover: include unchanged already-classified documents." },
644
+ allUnclassified: { type: "boolean", description: "discover: include all unclassified document-like files regardless heuristic score." },
645
+ base: stringSchema("Git base for impact when task-scoped paths are omitted; default HEAD."),
646
+ semantic: { type: "boolean", description: "impact semantic candidate retrieval; default true." },
647
+ relationAction: { type: "string", enum: ["add", "remove"] },
648
+ relationKind: { type: "string", enum: ["implements", "tests", "related", "supersedes", "superseded-by"] },
649
+ targetPaths: { type: "array", items: stringSchema("Reviewed relation target path") },
650
+ sourceReviewed: { type: "boolean", description: "Required true for record only after reading/classifying the source document." },
651
+ evidenceReviewed: { type: "boolean", description: "Required true for verify/relate only after reviewing concrete primary source + relevant code/tests/evidence." },
652
+ metadataOnlyConfirmed: { type: "boolean", description: "Required true for remove; confirms only idx metadata is removed and the source file stays untouched." },
653
+ ...outputProperties,
654
+ ...(profile === "native-compact" ? {
655
+ outputMode: {
656
+ type: "string",
657
+ enum: ["compact", "full"],
658
+ default: "compact",
659
+ description: "Knowledge output delivery mode. Keep compact unless this same result is actually truncated and broader output is necessary.",
660
+ },
661
+ } : {}),
662
+ },
663
+ required: ["action"],
664
+ additionalProperties: false,
665
+ };
666
+ }
667
+
385
668
  function registerRepoCommandTool(
386
669
  pi: ExtensionAPI,
387
670
  options: {
@@ -409,6 +692,22 @@ function registerRepoCommandTool(
409
692
  });
410
693
  }
411
694
 
695
+ function registerRepoKnowledgeTool(pi: ExtensionAPI, profile: RepoDiscoveryProfile) {
696
+ pi.registerTool({
697
+ ...REPO_KNOWLEDGE_TOOL_DESCRIPTION,
698
+ parameters: repoKnowledgeParameters(profile),
699
+ async execute(
700
+ _toolCallId: string,
701
+ params: RepoKnowledgeParams,
702
+ signal: AbortSignal | undefined,
703
+ _onUpdate: unknown,
704
+ ctx: ToolContext,
705
+ ) {
706
+ return executeRepoKnowledge(pi, params, signal, ctx, profile);
707
+ },
708
+ });
709
+ }
710
+
412
711
  export type RepoDiscoveryExtensionOptions = {
413
712
  profile?: RepoDiscoveryProfile;
414
713
  cwd?: string;
@@ -490,8 +789,9 @@ export default function repoDiscoveryExtension(pi: ExtensionAPI, options: RepoDi
490
789
  },
491
790
  });
492
791
 
493
- if (!findIndexedProjectRoot(registrationCwd)) return;
792
+ if (!hasAvailableIndexedProjectRoot(registrationCwd)) return;
494
793
 
495
794
  for (const tool of REPO_DISCOVERY_TOOLS) registerRepoCommandTool(pi, tool, profile);
795
+ registerRepoKnowledgeTool(pi, profile);
496
796
 
497
797
  }