all-hands-cli 0.1.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 (305) hide show
  1. package/.allhands/README.md +75 -0
  2. package/.allhands/agents/compounder.yaml +15 -0
  3. package/.allhands/agents/coordinator.yaml +17 -0
  4. package/.allhands/agents/documentor.yaml +15 -0
  5. package/.allhands/agents/e2e-test-planner.yaml +17 -0
  6. package/.allhands/agents/emergent.yaml +22 -0
  7. package/.allhands/agents/executor.yaml +14 -0
  8. package/.allhands/agents/ideation.yaml +11 -0
  9. package/.allhands/agents/initiative-steering.yaml +19 -0
  10. package/.allhands/agents/judge.yaml +13 -0
  11. package/.allhands/agents/planner.yaml +19 -0
  12. package/.allhands/agents/pr-reviewer.yaml +15 -0
  13. package/.allhands/docs.json +5 -0
  14. package/.allhands/docs.local.json +26 -0
  15. package/.allhands/flows/COMPOUNDING.md +203 -0
  16. package/.allhands/flows/COORDINATION.md +89 -0
  17. package/.allhands/flows/CORE.md +87 -0
  18. package/.allhands/flows/DOCUMENTATION.md +218 -0
  19. package/.allhands/flows/E2E_TEST_PLAN_BUILDING.md +140 -0
  20. package/.allhands/flows/EMERGENT_PLANNING.md +57 -0
  21. package/.allhands/flows/IDEATION_SCOPING.md +154 -0
  22. package/.allhands/flows/INITIATIVE_STEERING.md +110 -0
  23. package/.allhands/flows/JUDGE_REVIEWING.md +79 -0
  24. package/.allhands/flows/PROMPT_TASK_EXECUTION.md +68 -0
  25. package/.allhands/flows/PR_REVIEWING.md +43 -0
  26. package/.allhands/flows/SPEC_PLANNING.md +216 -0
  27. package/.allhands/flows/harness/WRITING_HARNESS_FLOWS.md +27 -0
  28. package/.allhands/flows/harness/WRITING_HARNESS_KNOWLEDGE.md +27 -0
  29. package/.allhands/flows/harness/WRITING_HARNESS_ORCHESTRATION.md +27 -0
  30. package/.allhands/flows/harness/WRITING_HARNESS_SKILLS.md +27 -0
  31. package/.allhands/flows/harness/WRITING_HARNESS_TOOLS.md +27 -0
  32. package/.allhands/flows/harness/WRITING_HARNESS_VALIDATION_TOOLING.md +27 -0
  33. package/.allhands/flows/shared/CODEBASE_UNDERSTANDING.md +72 -0
  34. package/.allhands/flows/shared/CREATE_HARNESS_SPEC.md +48 -0
  35. package/.allhands/flows/shared/CREATE_SPEC.md +41 -0
  36. package/.allhands/flows/shared/CREATE_VALIDATION_TOOLING_SPEC.md +70 -0
  37. package/.allhands/flows/shared/DOCUMENTATION_DISCOVERY.md +123 -0
  38. package/.allhands/flows/shared/DOCUMENTATION_WRITER.md +101 -0
  39. package/.allhands/flows/shared/EMERGENT_REFINEMENT_ANALYSIS.md +76 -0
  40. package/.allhands/flows/shared/EXTERNAL_TECH_GUIDANCE.md +97 -0
  41. package/.allhands/flows/shared/IDEATION_CODEBASE_GROUNDING.md +49 -0
  42. package/.allhands/flows/shared/PLAN_DEEPENING.md +152 -0
  43. package/.allhands/flows/shared/PROMPT_TASKS_CURATION.md +113 -0
  44. package/.allhands/flows/shared/PROMPT_VALIDATION_REVIEW.MD +99 -0
  45. package/.allhands/flows/shared/QUICK_PREMORTEM.md +70 -0
  46. package/.allhands/flows/shared/RESEARCH_GUIDANCE.md +38 -0
  47. package/.allhands/flows/shared/REVIEW_OPTIONS_BREAKDOWN.md +68 -0
  48. package/.allhands/flows/shared/SKILL_EXTRACTION.md +84 -0
  49. package/.allhands/flows/shared/SPEC_FLOW_ANALYSIS.md +119 -0
  50. package/.allhands/flows/shared/TDD_WORKFLOW.md +109 -0
  51. package/.allhands/flows/shared/UTILIZE_VALIDATION_TOOLING.md +84 -0
  52. package/.allhands/flows/shared/WRITING_HARNESS_FLOWS.md +11 -0
  53. package/.allhands/flows/shared/WRITING_HARNESS_MCP_TOOLS.md +84 -0
  54. package/.allhands/flows/shared/jury/ARCHITECTURE_REVIEW.md +91 -0
  55. package/.allhands/flows/shared/jury/BEST_PRACTICES_REVIEW.md +80 -0
  56. package/.allhands/flows/shared/jury/CLAIM_VERIFICATION_REVIEW.md +101 -0
  57. package/.allhands/flows/shared/jury/EXPECTATIONS_FIT_REVIEW.md +78 -0
  58. package/.allhands/flows/shared/jury/MAINTAINABILITY_REVIEW.md +110 -0
  59. package/.allhands/flows/shared/jury/PROMPTS_EXPECTATIONS_FIT.md +74 -0
  60. package/.allhands/flows/shared/jury/PROMPTS_FLOW_ANALYSIS.md +92 -0
  61. package/.allhands/flows/shared/jury/PROMPTS_YAGNI.md +78 -0
  62. package/.allhands/flows/shared/jury/PROMPT_PREMORTEM.md +125 -0
  63. package/.allhands/flows/shared/jury/SECURITY_REVIEW.md +86 -0
  64. package/.allhands/flows/shared/jury/YAGNI_REVIEW.md +82 -0
  65. package/.allhands/flows/wip/DEBUG_INVESTIGATION.md +162 -0
  66. package/.allhands/flows/wip/MEMORY_RECALL.md +62 -0
  67. package/.allhands/harness/ah +131 -0
  68. package/.allhands/harness/package-lock.json +5292 -0
  69. package/.allhands/harness/package.json +52 -0
  70. package/.allhands/harness/src/__tests__/e2e/commands.test.ts +307 -0
  71. package/.allhands/harness/src/__tests__/e2e/event-loop.test.ts +539 -0
  72. package/.allhands/harness/src/__tests__/e2e/hooks.test.ts +427 -0
  73. package/.allhands/harness/src/__tests__/e2e/new-initiative-routing.test.ts +137 -0
  74. package/.allhands/harness/src/__tests__/e2e/run-e2e.ts +109 -0
  75. package/.allhands/harness/src/__tests__/e2e/specs-type.test.ts +210 -0
  76. package/.allhands/harness/src/__tests__/e2e/validation-hooks.test.ts +669 -0
  77. package/.allhands/harness/src/__tests__/e2e/validation-path-consistency.test.ts +354 -0
  78. package/.allhands/harness/src/__tests__/e2e/validation.test.ts +528 -0
  79. package/.allhands/harness/src/__tests__/harness/assertions.ts +318 -0
  80. package/.allhands/harness/src/__tests__/harness/cli-runner.ts +359 -0
  81. package/.allhands/harness/src/__tests__/harness/fixture.ts +384 -0
  82. package/.allhands/harness/src/__tests__/harness/hook-runner.ts +411 -0
  83. package/.allhands/harness/src/__tests__/harness/index.ts +122 -0
  84. package/.allhands/harness/src/cli.ts +36 -0
  85. package/.allhands/harness/src/commands/complexity.ts +177 -0
  86. package/.allhands/harness/src/commands/context7.ts +202 -0
  87. package/.allhands/harness/src/commands/docs.ts +557 -0
  88. package/.allhands/harness/src/commands/hooks.ts +24 -0
  89. package/.allhands/harness/src/commands/index.ts +51 -0
  90. package/.allhands/harness/src/commands/knowledge.ts +382 -0
  91. package/.allhands/harness/src/commands/memories.ts +302 -0
  92. package/.allhands/harness/src/commands/notify.ts +61 -0
  93. package/.allhands/harness/src/commands/oracle.ts +158 -0
  94. package/.allhands/harness/src/commands/perplexity.ts +220 -0
  95. package/.allhands/harness/src/commands/planning.ts +245 -0
  96. package/.allhands/harness/src/commands/schema.ts +73 -0
  97. package/.allhands/harness/src/commands/skills.ts +128 -0
  98. package/.allhands/harness/src/commands/solutions.ts +353 -0
  99. package/.allhands/harness/src/commands/spawn.ts +158 -0
  100. package/.allhands/harness/src/commands/specs.ts +532 -0
  101. package/.allhands/harness/src/commands/tavily.ts +226 -0
  102. package/.allhands/harness/src/commands/tools.ts +579 -0
  103. package/.allhands/harness/src/commands/trace.ts +327 -0
  104. package/.allhands/harness/src/commands/tui.ts +960 -0
  105. package/.allhands/harness/src/commands/validate.ts +143 -0
  106. package/.allhands/harness/src/commands/validation-tools.ts +108 -0
  107. package/.allhands/harness/src/hooks/context.ts +1442 -0
  108. package/.allhands/harness/src/hooks/enforcement.ts +170 -0
  109. package/.allhands/harness/src/hooks/index.ts +54 -0
  110. package/.allhands/harness/src/hooks/lifecycle.ts +229 -0
  111. package/.allhands/harness/src/hooks/notification.ts +104 -0
  112. package/.allhands/harness/src/hooks/observability.ts +551 -0
  113. package/.allhands/harness/src/hooks/session.ts +88 -0
  114. package/.allhands/harness/src/hooks/shared.ts +815 -0
  115. package/.allhands/harness/src/hooks/transcript-parser.ts +208 -0
  116. package/.allhands/harness/src/hooks/validation.ts +617 -0
  117. package/.allhands/harness/src/lib/__tests__/ctags.test.ts +244 -0
  118. package/.allhands/harness/src/lib/__tests__/docs-validation.test.ts +344 -0
  119. package/.allhands/harness/src/lib/__tests__/mcp-runtime.test.ts +190 -0
  120. package/.allhands/harness/src/lib/__tests__/schema.test.ts +861 -0
  121. package/.allhands/harness/src/lib/base-command.ts +198 -0
  122. package/.allhands/harness/src/lib/cli-daemon.ts +343 -0
  123. package/.allhands/harness/src/lib/compaction.ts +313 -0
  124. package/.allhands/harness/src/lib/ctags.ts +497 -0
  125. package/.allhands/harness/src/lib/docs-validation.ts +907 -0
  126. package/.allhands/harness/src/lib/event-loop.ts +662 -0
  127. package/.allhands/harness/src/lib/flows.ts +155 -0
  128. package/.allhands/harness/src/lib/git.ts +276 -0
  129. package/.allhands/harness/src/lib/knowledge-worker.ts +72 -0
  130. package/.allhands/harness/src/lib/knowledge.ts +810 -0
  131. package/.allhands/harness/src/lib/llm.ts +255 -0
  132. package/.allhands/harness/src/lib/mcp-client.ts +432 -0
  133. package/.allhands/harness/src/lib/mcp-daemon.ts +486 -0
  134. package/.allhands/harness/src/lib/mcp-runtime.ts +418 -0
  135. package/.allhands/harness/src/lib/notification.ts +115 -0
  136. package/.allhands/harness/src/lib/opencode/index.ts +70 -0
  137. package/.allhands/harness/src/lib/opencode/profiles.ts +300 -0
  138. package/.allhands/harness/src/lib/opencode/prompts/codesearch.md +98 -0
  139. package/.allhands/harness/src/lib/opencode/prompts/knowledge-aggregator.md +67 -0
  140. package/.allhands/harness/src/lib/opencode/runner.ts +281 -0
  141. package/.allhands/harness/src/lib/oracle.ts +926 -0
  142. package/.allhands/harness/src/lib/planning-utils.ts +150 -0
  143. package/.allhands/harness/src/lib/planning.ts +605 -0
  144. package/.allhands/harness/src/lib/pr-review.ts +225 -0
  145. package/.allhands/harness/src/lib/prompts.ts +522 -0
  146. package/.allhands/harness/src/lib/schema.ts +418 -0
  147. package/.allhands/harness/src/lib/schemas/agent-profile.ts +141 -0
  148. package/.allhands/harness/src/lib/schemas/template-vars.ts +138 -0
  149. package/.allhands/harness/src/lib/session.ts +164 -0
  150. package/.allhands/harness/src/lib/specs.ts +348 -0
  151. package/.allhands/harness/src/lib/tldr.ts +829 -0
  152. package/.allhands/harness/src/lib/tmux.ts +1051 -0
  153. package/.allhands/harness/src/lib/trace-store.ts +714 -0
  154. package/.allhands/harness/src/mcp/__tests__/index.test.ts +46 -0
  155. package/.allhands/harness/src/mcp/_template.ts +47 -0
  156. package/.allhands/harness/src/mcp/filesystem.ts +33 -0
  157. package/.allhands/harness/src/mcp/index.ts +69 -0
  158. package/.allhands/harness/src/mcp/playwright.ts +34 -0
  159. package/.allhands/harness/src/mcp/xcodebuild.ts +29 -0
  160. package/.allhands/harness/src/schemas/docs.schema.json +44 -0
  161. package/.allhands/harness/src/schemas/settings.schema.json +214 -0
  162. package/.allhands/harness/src/tui/actions.ts +227 -0
  163. package/.allhands/harness/src/tui/file-viewer-modal.ts +270 -0
  164. package/.allhands/harness/src/tui/index.ts +1574 -0
  165. package/.allhands/harness/src/tui/modal.ts +232 -0
  166. package/.allhands/harness/src/tui/prompts-pane.ts +186 -0
  167. package/.allhands/harness/src/tui/status-pane.ts +434 -0
  168. package/.allhands/harness/tsconfig.json +22 -0
  169. package/.allhands/harness/vitest.config.ts +13 -0
  170. package/.allhands/pillars.md +33 -0
  171. package/.allhands/principles.md +88 -0
  172. package/.allhands/schemas/alignment.yaml +51 -0
  173. package/.allhands/schemas/documentation.yaml +10 -0
  174. package/.allhands/schemas/prompt.yaml +92 -0
  175. package/.allhands/schemas/skill.yaml +34 -0
  176. package/.allhands/schemas/solution.yaml +131 -0
  177. package/.allhands/schemas/spec.yaml +67 -0
  178. package/.allhands/schemas/validation-suite.yaml +49 -0
  179. package/.allhands/schemas/workflow.yaml +51 -0
  180. package/.allhands/settings.json +57 -0
  181. package/.allhands/skills/claude-code-patterns/SKILL.md +60 -0
  182. package/.allhands/skills/claude-code-patterns/docs/context-hygiene.md +19 -0
  183. package/.allhands/skills/harness-maintenance/SKILL.md +449 -0
  184. package/.allhands/skills/harness-maintenance/references/core-architecture.md +187 -0
  185. package/.allhands/skills/harness-maintenance/references/harness-skills.md +87 -0
  186. package/.allhands/skills/harness-maintenance/references/knowledge-compounding.md +78 -0
  187. package/.allhands/skills/harness-maintenance/references/tools-commands-mcp-hooks.md +115 -0
  188. package/.allhands/skills/harness-maintenance/references/validation-tooling.md +77 -0
  189. package/.allhands/skills/harness-maintenance/references/writing-flows.md +84 -0
  190. package/.allhands/validation/browser-automation.md +109 -0
  191. package/.allhands/validation/xcode-automation.md +195 -0
  192. package/.allhands/workflows/documentation.md +86 -0
  193. package/.allhands/workflows/investigation.md +81 -0
  194. package/.allhands/workflows/milestone.md +91 -0
  195. package/.allhands/workflows/optimization.md +85 -0
  196. package/.allhands/workflows/refactor.md +99 -0
  197. package/.allhands/workflows/triage.md +81 -0
  198. package/.claude/README.md +1 -0
  199. package/.claude/agents/explorer.md +10 -0
  200. package/.claude/agents/researcher.md +11 -0
  201. package/.claude/agents/task-runner.md +8 -0
  202. package/.claude/settings.json +231 -0
  203. package/.env.ai.example +7 -0
  204. package/.github/workflows/npm-publish.yml +69 -0
  205. package/.internal.json +45 -0
  206. package/.tldr/config.json +11 -0
  207. package/.tldrignore +90 -0
  208. package/CLAUDE.md +6 -0
  209. package/README.md +98 -0
  210. package/bin/sync-cli.js +7552 -0
  211. package/concerns.md +7 -0
  212. package/docs/README.md +41 -0
  213. package/docs/agents/README.md +24 -0
  214. package/docs/agents/agent-configuration-system.md +86 -0
  215. package/docs/agents/execution-agents.md +50 -0
  216. package/docs/agents/knowledge-agents.md +61 -0
  217. package/docs/agents/orchestration-agent.md +57 -0
  218. package/docs/agents/planning-agents.md +84 -0
  219. package/docs/agents/quality-review-agents.md +67 -0
  220. package/docs/agents/workflow-agent-orchestration.md +69 -0
  221. package/docs/flows/README.md +44 -0
  222. package/docs/flows/compounding.md +126 -0
  223. package/docs/flows/coordination.md +72 -0
  224. package/docs/flows/core-harness-integration.md +63 -0
  225. package/docs/flows/documentation-orchestration.md +98 -0
  226. package/docs/flows/e2e-test-plan-building.md +83 -0
  227. package/docs/flows/emergent-refinement.md +104 -0
  228. package/docs/flows/flow-authoring-and-mcp-tools.md +89 -0
  229. package/docs/flows/judge-reviewing.md +112 -0
  230. package/docs/flows/plan-deepening-and-research.md +107 -0
  231. package/docs/flows/plan-review-jury.md +114 -0
  232. package/docs/flows/pr-reviewing.md +54 -0
  233. package/docs/flows/prompt-task-execution.md +119 -0
  234. package/docs/flows/spec-planning.md +162 -0
  235. package/docs/flows/type-specific-scoping-flows.md +49 -0
  236. package/docs/flows/validation-and-skills-integration.md +145 -0
  237. package/docs/flows/wip/wip-flows.md +102 -0
  238. package/docs/harness/README.md +23 -0
  239. package/docs/harness/agent-profiles.md +84 -0
  240. package/docs/harness/cli/README.md +24 -0
  241. package/docs/harness/cli/cli-entry-and-command-discovery.md +91 -0
  242. package/docs/harness/cli/docs-command.md +87 -0
  243. package/docs/harness/cli/knowledge-command.md +91 -0
  244. package/docs/harness/cli/minor-cli-commands.md +65 -0
  245. package/docs/harness/cli/oracle-command.md +113 -0
  246. package/docs/harness/cli/planning-command.md +95 -0
  247. package/docs/harness/cli/schema-and-validation-commands.md +154 -0
  248. package/docs/harness/cli/search-commands.md +97 -0
  249. package/docs/harness/cli/spawn-command.md +136 -0
  250. package/docs/harness/cli/specs-command.md +102 -0
  251. package/docs/harness/cli/tools-command.md +122 -0
  252. package/docs/harness/cli/trace-command.md +122 -0
  253. package/docs/harness/cli-daemon.md +92 -0
  254. package/docs/harness/event-loop.md +184 -0
  255. package/docs/harness/hooks/README.md +15 -0
  256. package/docs/harness/hooks/context-hooks.md +96 -0
  257. package/docs/harness/hooks/lifecycle-and-observability-hooks.md +135 -0
  258. package/docs/harness/hooks/validation-hooks.md +97 -0
  259. package/docs/harness/test-harness.md +149 -0
  260. package/docs/harness/tui.md +176 -0
  261. package/docs/memories.md +20 -0
  262. package/docs/solutions/agentic-issues/premature-agent-deletion-tui-action-dependency-20260130.md +49 -0
  263. package/docs/solutions/agentic-issues/ref-anchor-scope-mismatch-skill-references-20260131.md +55 -0
  264. package/docs/solutions/agentic-issues/tautological-tests-routing-20260131.md +52 -0
  265. package/docs/solutions/integration_issue/blocktool-output-format-mismatch-hook-runner-20260130.md +52 -0
  266. package/docs/solutions/integration_issue/dual-validation-path-divergence-schema-20260130.md +66 -0
  267. package/docs/solutions/security-issues/unsanitized-domain-path-join-20260131.md +52 -0
  268. package/docs/solutions/test-failures/event-loop-mock-ordering-checkAgentWindows-20260130.md +63 -0
  269. package/docs/sync-cli/README.md +19 -0
  270. package/docs/sync-cli/cli-entrypoint-and-commands.md +39 -0
  271. package/docs/sync-cli/commands/README.md +11 -0
  272. package/docs/sync-cli/commands/pull-manifest-command.md +36 -0
  273. package/docs/sync-cli/commands/push-command.md +84 -0
  274. package/docs/sync-cli/commands/sync-command.md +71 -0
  275. package/docs/sync-cli/systems/README.md +14 -0
  276. package/docs/sync-cli/systems/git-and-github-integration.md +49 -0
  277. package/docs/sync-cli/systems/interactive-ui.md +43 -0
  278. package/docs/sync-cli/systems/manifest-and-distribution.md +51 -0
  279. package/docs/sync-cli/systems/path-resolution.md +42 -0
  280. package/package.json +46 -0
  281. package/scripts/install-shim.sh +40 -0
  282. package/scripts/pre-pack.sh +25 -0
  283. package/specs/harness-maintenance-skill.spec.md +138 -0
  284. package/specs/roadmap/git-spec-lifecycle-management.spec.md +113 -0
  285. package/specs/sync-init-flag.spec.md +117 -0
  286. package/specs/unified-workflow-orchestration.spec.md +250 -0
  287. package/specs/validation-tooling-practice.spec.md +98 -0
  288. package/specs/workflow-domain-configuration.spec.md +265 -0
  289. package/src/commands/pull-manifest.ts +31 -0
  290. package/src/commands/push.ts +344 -0
  291. package/src/commands/sync.ts +289 -0
  292. package/src/lib/constants.ts +10 -0
  293. package/src/lib/dotfiles.ts +36 -0
  294. package/src/lib/fs-utils.ts +18 -0
  295. package/src/lib/gh.ts +40 -0
  296. package/src/lib/git.ts +63 -0
  297. package/src/lib/gitignore.ts +167 -0
  298. package/src/lib/manifest.ts +121 -0
  299. package/src/lib/marker-sync.ts +39 -0
  300. package/src/lib/paths.ts +38 -0
  301. package/src/lib/target-lines.ts +66 -0
  302. package/src/lib/ui.ts +78 -0
  303. package/src/sync-cli.ts +120 -0
  304. package/target-lines.json +23 -0
  305. package/tsconfig.json +20 -0
@@ -0,0 +1,418 @@
1
+ /**
2
+ * MCP Runtime - Lazy-loaded MCP server integration via mcptools CLI.
3
+ *
4
+ * This module provides:
5
+ * - Type definitions for MCP server configs
6
+ * - Env var interpolation (${VAR_NAME} -> process.env.VAR_NAME)
7
+ * - mcptools CLI wrapper for tool discovery and execution
8
+ * - SWR (stale-while-revalidate) caching for tool schemas
9
+ */
10
+
11
+ import { execSync, spawn } from 'child_process';
12
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
13
+ import { dirname, join } from 'path';
14
+ import { fileURLToPath } from 'url';
15
+
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ // Path: harness/src/lib/ -> harness/src/ -> harness/
18
+ const HARNESS_ROOT = join(__dirname, '..', '..');
19
+ const CACHE_DIR = join(HARNESS_ROOT, '.cache', 'mcp');
20
+
21
+ /**
22
+ * MCP server configuration - one per server wrapper file.
23
+ */
24
+ export interface McpServerConfig {
25
+ /** Server identifier (used in CLI: ah tools <name>:tool) */
26
+ name: string;
27
+
28
+ /** Human-readable description of what this server provides */
29
+ description: string;
30
+
31
+ /** Transport type - stdio (command) or http/sse (url) */
32
+ type?: 'stdio' | 'http' | 'sse';
33
+
34
+ /** Command to execute (stdio transport) */
35
+ command?: string;
36
+
37
+ /** Arguments for command (stdio transport) */
38
+ args?: string[];
39
+
40
+ /** Environment variables - values can use ${VAR_NAME} for interpolation */
41
+ env?: Record<string, string>;
42
+
43
+ /** URL endpoint (http/sse transport) */
44
+ url?: string;
45
+
46
+ /** HTTP headers (http/sse transport) */
47
+ headers?: Record<string, string>;
48
+
49
+ /** Tools to hide from discovery (default: show all) */
50
+ hiddenTools?: string[];
51
+
52
+ /** Extra hints for specific tools (shown in --help) */
53
+ toolHints?: Record<string, string>;
54
+
55
+ /**
56
+ * Whether this server maintains state between tool calls.
57
+ *
58
+ * Stateful servers (e.g., Playwright, XcodeBuild) keep a persistent session
59
+ * that survives between CLI invocations. The session is automatically started
60
+ * on first tool call and cleaned up after inactivity timeout.
61
+ *
62
+ * Use --restart flag if the server gets into a bad state.
63
+ *
64
+ * Stateless servers (e.g., fetch, filesystem) create a fresh connection
65
+ * for each tool call.
66
+ */
67
+ stateful?: boolean;
68
+
69
+ /**
70
+ * Inactivity timeout for stateful sessions in milliseconds.
71
+ * After this period of no tool calls, the session is automatically closed.
72
+ * Default: 120000 (2 minutes). Only applies when stateful: true.
73
+ */
74
+ stateful_session_timeout?: number;
75
+ }
76
+
77
+ /**
78
+ * Default timeout for stateful MCP sessions (2 minutes).
79
+ */
80
+ export const DAEMON_DEFAULT_MCP_TIMEOUT = 120000;
81
+
82
+ /**
83
+ * Tool schema from MCP server discovery.
84
+ */
85
+ export interface McpToolSchema {
86
+ name: string;
87
+ description?: string;
88
+ inputSchema?: {
89
+ type: string;
90
+ properties?: Record<string, {
91
+ type: string;
92
+ description?: string;
93
+ items?: { type: string };
94
+ }>;
95
+ required?: string[];
96
+ };
97
+ }
98
+
99
+ /**
100
+ * Cached tool discovery result.
101
+ */
102
+ interface ToolCache {
103
+ timestamp: number;
104
+ tools: McpToolSchema[];
105
+ }
106
+
107
+ /**
108
+ * Check if mcptools CLI is available.
109
+ */
110
+ export function isMcpToolsInstalled(): boolean {
111
+ try {
112
+ execSync('mcp version', { stdio: 'ignore' });
113
+ return true;
114
+ } catch {
115
+ return false;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Interpolate environment variables in a string.
121
+ * Replaces ${VAR_NAME} with process.env.VAR_NAME.
122
+ */
123
+ export function interpolateEnv(value: string): string {
124
+ return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
125
+ const envValue = process.env[varName];
126
+ if (envValue === undefined) {
127
+ throw new Error(`Environment variable ${varName} is not set`);
128
+ }
129
+ return envValue;
130
+ });
131
+ }
132
+
133
+ /**
134
+ * Interpolate all env vars in a config's env object.
135
+ */
136
+ export function resolveEnvVars(env: Record<string, string> | undefined): Record<string, string> {
137
+ if (!env) return {};
138
+
139
+ const resolved: Record<string, string> = {};
140
+ for (const [key, value] of Object.entries(env)) {
141
+ resolved[key] = interpolateEnv(value);
142
+ }
143
+ return resolved;
144
+ }
145
+
146
+ /**
147
+ * Build the mcptools server command from config.
148
+ */
149
+ export function buildServerCommand(config: McpServerConfig): string[] {
150
+ if (config.type === 'http' || config.type === 'sse') {
151
+ if (!config.url) {
152
+ throw new Error(`Server ${config.name} requires 'url' for ${config.type} transport`);
153
+ }
154
+ return [config.url];
155
+ }
156
+
157
+ // Default to stdio
158
+ if (!config.command) {
159
+ throw new Error(`Server ${config.name} requires 'command' for stdio transport`);
160
+ }
161
+
162
+ return [config.command, ...(config.args ?? [])];
163
+ }
164
+
165
+ /**
166
+ * Get cache file path for a server.
167
+ */
168
+ function getCachePath(serverName: string): string {
169
+ return join(CACHE_DIR, `${serverName}.json`);
170
+ }
171
+
172
+ /**
173
+ * Load cached tools for a server.
174
+ */
175
+ function loadCache(serverName: string): ToolCache | null {
176
+ const cachePath = getCachePath(serverName);
177
+ if (!existsSync(cachePath)) return null;
178
+
179
+ try {
180
+ const data = readFileSync(cachePath, 'utf-8');
181
+ return JSON.parse(data) as ToolCache;
182
+ } catch {
183
+ return null;
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Save tools to cache.
189
+ */
190
+ function saveCache(serverName: string, tools: McpToolSchema[]): void {
191
+ if (!existsSync(CACHE_DIR)) {
192
+ mkdirSync(CACHE_DIR, { recursive: true });
193
+ }
194
+
195
+ const cache: ToolCache = {
196
+ timestamp: Date.now(),
197
+ tools,
198
+ };
199
+
200
+ writeFileSync(getCachePath(serverName), JSON.stringify(cache, null, 2));
201
+ }
202
+
203
+ /**
204
+ * Discover tools from an MCP server via mcptools CLI.
205
+ */
206
+ export async function discoverTools(config: McpServerConfig): Promise<McpToolSchema[]> {
207
+ const serverCmd = buildServerCommand(config);
208
+ const env = resolveEnvVars(config.env);
209
+
210
+ return new Promise((resolve, reject) => {
211
+ const args = ['tools', '--format', 'json', ...serverCmd];
212
+
213
+ const proc = spawn('mcp', args, {
214
+ env: { ...process.env, ...env },
215
+ stdio: ['ignore', 'pipe', 'pipe'],
216
+ });
217
+
218
+ let stdout = '';
219
+ let stderr = '';
220
+
221
+ proc.stdout.on('data', (data) => {
222
+ stdout += data.toString();
223
+ });
224
+
225
+ proc.stderr.on('data', (data) => {
226
+ stderr += data.toString();
227
+ });
228
+
229
+ proc.on('close', (code) => {
230
+ if (code !== 0) {
231
+ reject(new Error(`mcp tools failed: ${stderr || 'unknown error'}`));
232
+ return;
233
+ }
234
+
235
+ try {
236
+ const parsed = JSON.parse(stdout);
237
+ // mcptools returns { tools: [...] } wrapper
238
+ const tools = (parsed.tools ?? parsed) as McpToolSchema[];
239
+
240
+ // Filter out hidden tools
241
+ const filtered = config.hiddenTools?.length
242
+ ? tools.filter((t) => !config.hiddenTools!.includes(t.name))
243
+ : tools;
244
+
245
+ resolve(filtered);
246
+ } catch (e) {
247
+ reject(new Error(`Failed to parse tool discovery: ${e}`));
248
+ }
249
+ });
250
+
251
+ proc.on('error', (err) => {
252
+ reject(new Error(`Failed to spawn mcp: ${err.message}`));
253
+ });
254
+ });
255
+ }
256
+
257
+ /**
258
+ * Get tools with SWR caching.
259
+ *
260
+ * Returns cached tools immediately, triggers background refresh.
261
+ * If no cache exists, performs blocking discovery.
262
+ */
263
+ export async function getToolsWithCache(
264
+ config: McpServerConfig,
265
+ forceRefresh = false
266
+ ): Promise<McpToolSchema[]> {
267
+ const cache = loadCache(config.name);
268
+
269
+ if (forceRefresh || !cache) {
270
+ // No cache or force refresh - blocking discovery
271
+ const tools = await discoverTools(config);
272
+ saveCache(config.name, tools);
273
+ return tools;
274
+ }
275
+
276
+ // Return cached immediately, refresh in background (SWR pattern)
277
+ discoverTools(config)
278
+ .then((tools) => saveCache(config.name, tools))
279
+ .catch(() => {
280
+ // Silent fail on background refresh - cache still valid
281
+ });
282
+
283
+ return cache.tools;
284
+ }
285
+
286
+ /**
287
+ * Call a tool on an MCP server.
288
+ */
289
+ export async function callTool(
290
+ config: McpServerConfig,
291
+ toolName: string,
292
+ params: Record<string, unknown>
293
+ ): Promise<unknown> {
294
+ const serverCmd = buildServerCommand(config);
295
+ const env = resolveEnvVars(config.env);
296
+
297
+ return new Promise((resolve, reject) => {
298
+ const args = [
299
+ 'call',
300
+ toolName,
301
+ '--params',
302
+ JSON.stringify(params),
303
+ '--format',
304
+ 'json',
305
+ ...serverCmd,
306
+ ];
307
+
308
+ const proc = spawn('mcp', args, {
309
+ env: { ...process.env, ...env },
310
+ stdio: ['ignore', 'pipe', 'pipe'],
311
+ });
312
+
313
+ let stdout = '';
314
+ let stderr = '';
315
+
316
+ proc.stdout.on('data', (data) => {
317
+ stdout += data.toString();
318
+ });
319
+
320
+ proc.stderr.on('data', (data) => {
321
+ stderr += data.toString();
322
+ });
323
+
324
+ proc.on('close', (code) => {
325
+ if (code !== 0) {
326
+ reject(new Error(`Tool call failed: ${stderr || 'unknown error'}`));
327
+ return;
328
+ }
329
+
330
+ try {
331
+ const result = JSON.parse(stdout);
332
+ resolve(result);
333
+ } catch {
334
+ // Not JSON - return raw output
335
+ resolve(stdout.trim());
336
+ }
337
+ });
338
+
339
+ proc.on('error', (err) => {
340
+ reject(new Error(`Failed to spawn mcp: ${err.message}`));
341
+ });
342
+ });
343
+ }
344
+
345
+ /**
346
+ * Format tool schema for human-readable help output.
347
+ */
348
+ export function formatToolHelp(
349
+ tool: McpToolSchema,
350
+ hint?: string
351
+ ): string {
352
+ const lines: string[] = [];
353
+
354
+ // Tool signature
355
+ const params: string[] = [];
356
+ const props = tool.inputSchema?.properties ?? {};
357
+ const required = new Set(tool.inputSchema?.required ?? []);
358
+
359
+ for (const [name, schema] of Object.entries(props)) {
360
+ let typeStr = schema.type;
361
+ if (schema.items?.type) {
362
+ typeStr = `${schema.items.type}[]`;
363
+ }
364
+
365
+ if (required.has(name)) {
366
+ params.push(`${name}:${typeStr}`);
367
+ } else {
368
+ params.push(`[${name}:${typeStr}]`);
369
+ }
370
+ }
371
+
372
+ lines.push(`${tool.name}(${params.join(', ')})`);
373
+
374
+ // Description
375
+ if (tool.description) {
376
+ lines.push(` ${tool.description}`);
377
+ }
378
+
379
+ // Parameter details
380
+ if (Object.keys(props).length > 0) {
381
+ lines.push('');
382
+ lines.push(' Parameters:');
383
+ for (const [name, schema] of Object.entries(props)) {
384
+ const reqStr = required.has(name) ? '(required)' : '(optional)';
385
+ const desc = schema.description || '';
386
+ lines.push(` ${name} ${reqStr} ${desc}`);
387
+ }
388
+ }
389
+
390
+ // Custom hint
391
+ if (hint) {
392
+ lines.push('');
393
+ lines.push(` Hint: ${hint}`);
394
+ }
395
+
396
+ return lines.join('\n');
397
+ }
398
+
399
+ /**
400
+ * Format all tools from a server for help output.
401
+ */
402
+ export function formatServerHelp(
403
+ config: McpServerConfig,
404
+ tools: McpToolSchema[]
405
+ ): string {
406
+ const lines: string[] = [];
407
+
408
+ lines.push(`${config.name} - ${config.description}`);
409
+ lines.push('');
410
+ lines.push(`Tools (${tools.length}):`);
411
+
412
+ for (const tool of tools) {
413
+ lines.push('');
414
+ lines.push(formatToolHelp(tool, config.toolHints?.[tool.name]));
415
+ }
416
+
417
+ return lines.join('\n');
418
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * System notification utilities using jamf/Notifier (macOS).
3
+ *
4
+ * Notification structure:
5
+ * - title: Event type (what happened)
6
+ * - subtitle: Branch/feature context (auto-detected)
7
+ * - message: Specific details for the user
8
+ *
9
+ * Requires: https://github.com/jamf/Notifier installed at:
10
+ * /Applications/Utilities/Notifier.app
11
+ * or available in PATH as 'notifier'
12
+ *
13
+ * This is designed to be used from Claude Code hooks via:
14
+ * ah notify send "Title" "Message"
15
+ */
16
+
17
+ import { spawnSync } from "child_process";
18
+ import { existsSync } from "fs";
19
+ import { getBranch, getRepoName } from "./git.js";
20
+
21
+ export interface NotifyOptions {
22
+ title: string; // Event type (required)
23
+ message: string; // Specific details (required)
24
+ sound?: string; // macOS sound name
25
+ type?: "banner" | "alert"; // banner auto-dismisses, alert persists
26
+ }
27
+
28
+ const NOTIFIER_DEFAULT_PATH = "/Applications/Utilities/Notifier.app/Contents/MacOS/Notifier";
29
+
30
+ /**
31
+ * Find the notifier binary path.
32
+ */
33
+ function getNotifierPath(): string | null {
34
+ // Check default install location
35
+ if (existsSync(NOTIFIER_DEFAULT_PATH)) {
36
+ return NOTIFIER_DEFAULT_PATH;
37
+ }
38
+ // Check if 'notifier' is in PATH
39
+ const result = spawnSync("which", ["notifier"], { encoding: "utf-8" });
40
+ if (result.status === 0 && result.stdout.trim()) {
41
+ return "notifier";
42
+ }
43
+ return null;
44
+ }
45
+
46
+ /**
47
+ * Send a system notification via jamf/Notifier.
48
+ *
49
+ * Layout:
50
+ * Title: event type (e.g., "Agent Stopped", "Plan Gate")
51
+ * Subtitle: repo + branch name (auto-detected)
52
+ * Message: specific details
53
+ */
54
+ export function sendNotification(options: NotifyOptions): boolean {
55
+ const notifierPath = getNotifierPath();
56
+ if (!notifierPath) {
57
+ // Notifier not installed - silently skip
58
+ return false;
59
+ }
60
+
61
+ const repo = getRepoName();
62
+ const branch = getBranch() || "unknown";
63
+ const subtitle = repo ? `${repo} ${branch}` : branch;
64
+ const notifType = options.type || "banner";
65
+
66
+ const args: string[] = [
67
+ "--type", notifType,
68
+ "--title", options.title,
69
+ "--subtitle", subtitle,
70
+ "--message", options.message,
71
+ ];
72
+
73
+ if (options.sound) {
74
+ args.push("--sound", options.sound);
75
+ }
76
+
77
+ try {
78
+ const result = spawnSync(notifierPath, args, {
79
+ stdio: "ignore",
80
+ timeout: 5000,
81
+ });
82
+
83
+ return result.status === 0;
84
+ } catch {
85
+ return false;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Send a gate notification. Uses alert type (persists until dismissed).
91
+ */
92
+ export function sendGateNotification(
93
+ gateType: string,
94
+ message: string
95
+ ): boolean {
96
+ return sendNotification({
97
+ title: `${gateType} Gate`,
98
+ message,
99
+ type: "alert",
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Send a hook notification. Uses banner type (auto-dismisses).
105
+ */
106
+ export function sendHookNotification(
107
+ hookType: string,
108
+ message: string
109
+ ): boolean {
110
+ return sendNotification({
111
+ title: hookType,
112
+ message,
113
+ type: "banner",
114
+ });
115
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * OpenCode SDK integration for All Hands.
3
+ *
4
+ * This module provides:
5
+ * - Agent profiles: YAML-defined configurations for TUI-spawned agents
6
+ * - Agent runner: OpenCode SDK wrapper for sub-agent execution
7
+ */
8
+
9
+ // Re-export profile management
10
+ export * from './profiles.js';
11
+
12
+ // MCP server configuration (matches opencode SDK McpLocalConfig)
13
+ export interface McpServerConfig {
14
+ type: "local";
15
+ command: string[]; // Command and args as array: ["uvx", "--from", "pkg", "server"]
16
+ environment?: Record<string, string>;
17
+ enabled?: boolean;
18
+ }
19
+
20
+ // Agent configuration
21
+ export interface AgentConfig {
22
+ name: string;
23
+ systemPrompt: string;
24
+ model?: string;
25
+ timeoutMs?: number;
26
+ steps?: number; // Hard limit on agent iterations
27
+ mcp?: Record<string, McpServerConfig>; // MCP servers to enable
28
+ }
29
+
30
+ // Agent execution result
31
+ export interface AgentResult<T = unknown> {
32
+ success: boolean;
33
+ data?: T;
34
+ error?: string;
35
+ metadata?: {
36
+ model: string;
37
+ tokens_used?: number;
38
+ duration_ms: number;
39
+ };
40
+ }
41
+
42
+ // Search result type (mirrors KnowledgeService.SearchResult)
43
+ export interface SearchResult {
44
+ resource_path: string;
45
+ similarity: number;
46
+ token_count: number;
47
+ description: string;
48
+ relevant_files: string[];
49
+ full_resource_context?: string;
50
+ }
51
+
52
+ // Knowledge aggregator input
53
+ export interface AggregatorInput {
54
+ query: string;
55
+ full_results: SearchResult[];
56
+ minimized_results: SearchResult[];
57
+ }
58
+
59
+ // Knowledge aggregator output
60
+ export interface AggregatorOutput {
61
+ insight: string;
62
+ lsp_entry_points: Array<{
63
+ file: string;
64
+ symbol: string | null;
65
+ why: string;
66
+ }>;
67
+ design_notes?: string[];
68
+ }
69
+
70
+ export { AgentRunner } from "./runner.js";