@hiai-gg/hiai-opencode 0.1.9 → 0.2.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 (134) hide show
  1. package/.env.example +0 -19
  2. package/AGENTS.md +214 -54
  3. package/ARCHITECTURE.md +9 -11
  4. package/LICENSE.md +4 -3
  5. package/README.md +68 -135
  6. package/assets/cli/hiai-opencode.mjs +137 -86
  7. package/config/.logs/subtask2.log +2 -0
  8. package/config/.mcp.json +45 -0
  9. package/config/.opencode/palace/knowledge_graph.sqlite3 +0 -0
  10. package/config/.opencode/palace/knowledge_graph.sqlite3-shm +0 -0
  11. package/config/.opencode/palace/knowledge_graph.sqlite3-wal +0 -0
  12. package/config/hiai-opencode.schema.json +176 -62
  13. package/dist/agents/builtin-agents/{guard-agent.d.ts → manager-agent.d.ts} +1 -1
  14. package/dist/agents/dynamic-agent-policy-sections.d.ts +2 -0
  15. package/dist/agents/{guard → manager}/agent.d.ts +7 -7
  16. package/dist/agents/manager/default-prompt-sections.d.ts +5 -0
  17. package/dist/agents/manager/default.d.ts +2 -0
  18. package/dist/agents/manager/index.d.ts +2 -0
  19. package/dist/agents/{guard → manager}/prompt-section-builder.d.ts +1 -1
  20. package/dist/agents/{guard → manager}/shared-prompt.d.ts +2 -2
  21. package/dist/agents/prompt-library/index.d.ts +0 -1
  22. package/dist/agents/strategist/behavioral-summary.d.ts +1 -1
  23. package/dist/agents/strategist/high-accuracy-mode.d.ts +1 -1
  24. package/dist/agents/strategist/identity-constraints.d.ts +1 -1
  25. package/dist/agents/strategist/index.d.ts +1 -1
  26. package/dist/agents/strategist/interview-mode.d.ts +1 -1
  27. package/dist/agents/strategist/plan-generation.d.ts +1 -1
  28. package/dist/agents/strategist/plan-template.d.ts +1 -1
  29. package/dist/agents/strategist/system-prompt.d.ts +3 -3
  30. package/dist/agents/types.d.ts +2 -2
  31. package/dist/agents/writer.d.ts +7 -0
  32. package/dist/config/index.d.ts +4 -6
  33. package/dist/config/platform-schema.d.ts +64 -56
  34. package/dist/config/schema/agent-names.d.ts +9 -10
  35. package/dist/config/schema/agent-overrides.d.ts +2 -258
  36. package/dist/config/schema/browser-automation.d.ts +0 -4
  37. package/dist/config/schema/{oh-my-opencode-config.d.ts → hiai-opencode-config.d.ts} +2 -261
  38. package/dist/config/schema/hooks.d.ts +1 -1
  39. package/dist/config/schema/index.d.ts +2 -2
  40. package/dist/config/types.d.ts +7 -5
  41. package/dist/create-hooks.d.ts +3 -0
  42. package/dist/features/boulder-state/constants.d.ts +1 -1
  43. package/dist/features/boulder-state/types.d.ts +1 -1
  44. package/dist/features/builtin-commands/templates/refactor.d.ts +1 -1
  45. package/dist/features/builtin-skills/skills/{playwright.d.ts → agent-browser.d.ts} +0 -1
  46. package/dist/features/builtin-skills/skills/index.d.ts +1 -2
  47. package/dist/hooks/critic-plans-only/agent-matcher.d.ts +1 -0
  48. package/dist/hooks/critic-plans-only/constants.d.ts +6 -0
  49. package/dist/hooks/critic-plans-only/hook.d.ts +11 -0
  50. package/dist/hooks/critic-plans-only/index.d.ts +3 -0
  51. package/dist/hooks/critic-plans-only/path-policy.d.ts +1 -0
  52. package/dist/hooks/index.d.ts +2 -1
  53. package/dist/hooks/json-error-recovery/hook.d.ts +1 -1
  54. package/dist/hooks/manager/hook-name.d.ts +1 -0
  55. package/dist/hooks/{guard → manager}/system-reminder-templates.d.ts +2 -2
  56. package/dist/hooks/mempalace-auto-save/constants.d.ts +1 -0
  57. package/dist/hooks/mempalace-auto-save/handler.d.ts +13 -0
  58. package/dist/hooks/mempalace-auto-save/index.d.ts +15 -0
  59. package/dist/hooks/mempalace-auto-save/types.d.ts +16 -0
  60. package/dist/hooks/strategist-md-only/constants.d.ts +2 -2
  61. package/dist/index.js +1266 -1920
  62. package/dist/internals/plugins/pty/pty/tools/list.d.ts +2 -5
  63. package/dist/mcp/registry.d.ts +1 -1
  64. package/dist/mcp/types.d.ts +0 -4
  65. package/dist/plugin/hooks/create-continuation-hooks.d.ts +4 -0
  66. package/dist/plugin/tool-registry.d.ts +4 -2
  67. package/dist/plugin-handlers/agent-priority-order.d.ts +2 -2
  68. package/dist/shared/agent-display-names.d.ts +2 -2
  69. package/dist/shared/system-directive.d.ts +2 -2
  70. package/dist/tools/agent-browser/constants.d.ts +16 -0
  71. package/dist/tools/agent-browser/index.d.ts +4 -0
  72. package/dist/tools/agent-browser/integration.d.ts +2 -0
  73. package/dist/tools/agent-browser/tools.d.ts +2 -0
  74. package/dist/tools/agent-browser/types.d.ts +80 -0
  75. package/dist/tools/call-hiai-agent/background-agent-executor.d.ts +5 -0
  76. package/dist/tools/{call-omo-agent → call-hiai-agent}/background-executor.d.ts +2 -2
  77. package/dist/tools/call-hiai-agent/constants.d.ts +3 -0
  78. package/dist/tools/{call-omo-agent → call-hiai-agent}/index.d.ts +1 -1
  79. package/dist/tools/{call-omo-agent → call-hiai-agent}/session-creator.d.ts +2 -2
  80. package/dist/tools/{call-omo-agent → call-hiai-agent}/subagent-session-creator.d.ts +2 -2
  81. package/dist/tools/{call-omo-agent → call-hiai-agent}/sync-executor.d.ts +2 -2
  82. package/dist/tools/{call-omo-agent → call-hiai-agent}/tools.d.ts +1 -1
  83. package/dist/tools/{call-omo-agent → call-hiai-agent}/types.d.ts +2 -2
  84. package/dist/tools/delegate-task/constants.d.ts +1 -1
  85. package/dist/tools/delegate-task/sub-agent.d.ts +1 -1
  86. package/dist/tools/index.d.ts +2 -1
  87. package/dist/tools/task/todo-sync.d.ts +1 -1
  88. package/docs/HOOKS.md +126 -0
  89. package/docs/HOOK_TIMINGS.md +58 -0
  90. package/docs/PERMISSIONS.md +84 -0
  91. package/docs/quickstart.md +60 -0
  92. package/hiai-opencode.json +10 -22
  93. package/package.json +13 -11
  94. package/skills/firecrawl-cli/SKILL.md +314 -0
  95. package/skills/firecrawl-cli/rules/install.md +98 -0
  96. package/assets/mcp/playwright.mjs +0 -83
  97. package/assets/mcp/rag.mjs +0 -236
  98. package/dist/agents/brainstormer.d.ts +0 -7
  99. package/dist/agents/guard/default-prompt-sections.d.ts +0 -6
  100. package/dist/agents/guard/default.d.ts +0 -2
  101. package/dist/agents/guard/index.d.ts +0 -2
  102. package/dist/agents/platform-manager.d.ts +0 -7
  103. package/dist/agents/prompt-library/platform.d.ts +0 -1
  104. package/dist/features/builtin-skills/skills/playwright-cli.d.ts +0 -10
  105. package/dist/hooks/guard/hook-name.d.ts +0 -1
  106. package/dist/tools/call-omo-agent/background-agent-executor.d.ts +0 -5
  107. package/dist/tools/call-omo-agent/constants.d.ts +0 -3
  108. /package/dist/hooks/{guard → manager}/background-launch-session-tracking.d.ts +0 -0
  109. /package/dist/hooks/{guard → manager}/bob-path.d.ts +0 -0
  110. /package/dist/hooks/{guard → manager}/boulder-continuation-injector.d.ts +0 -0
  111. /package/dist/hooks/{guard → manager}/boulder-session-lineage.d.ts +0 -0
  112. /package/dist/hooks/{guard → manager}/event-handler.d.ts +0 -0
  113. /package/dist/hooks/{guard → manager}/final-wave-approval-gate.d.ts +0 -0
  114. /package/dist/hooks/{guard → manager}/final-wave-plan-state.d.ts +0 -0
  115. /package/dist/hooks/{guard → manager}/guard-hook.d.ts +0 -0
  116. /package/dist/hooks/{guard → manager}/idle-event.d.ts +0 -0
  117. /package/dist/hooks/{guard → manager}/index.d.ts +0 -0
  118. /package/dist/hooks/{guard → manager}/is-abort-error.d.ts +0 -0
  119. /package/dist/hooks/{guard → manager}/recent-model-resolver.d.ts +0 -0
  120. /package/dist/hooks/{guard → manager}/resolve-active-boulder-session.d.ts +0 -0
  121. /package/dist/hooks/{guard → manager}/session-last-agent.d.ts +0 -0
  122. /package/dist/hooks/{guard → manager}/subagent-session-id.d.ts +0 -0
  123. /package/dist/hooks/{guard → manager}/task-context.d.ts +0 -0
  124. /package/dist/hooks/{guard → manager}/tool-execute-after.d.ts +0 -0
  125. /package/dist/hooks/{guard → manager}/tool-execute-before.d.ts +0 -0
  126. /package/dist/hooks/{guard → manager}/types.d.ts +0 -0
  127. /package/dist/hooks/{guard → manager}/verification-reminders.d.ts +0 -0
  128. /package/dist/hooks/{guard → manager}/write-edit-tool-policy.d.ts +0 -0
  129. /package/dist/tools/{call-omo-agent → call-hiai-agent}/agent-resolver.d.ts +0 -0
  130. /package/dist/tools/{call-omo-agent → call-hiai-agent}/completion-poller.d.ts +0 -0
  131. /package/dist/tools/{call-omo-agent → call-hiai-agent}/message-dir.d.ts +0 -0
  132. /package/dist/tools/{call-omo-agent → call-hiai-agent}/message-processor.d.ts +0 -0
  133. /package/dist/tools/{call-omo-agent → call-hiai-agent}/message-storage-directory.d.ts +0 -0
  134. /package/dist/tools/{call-omo-agent → call-hiai-agent}/tool-context-with-metadata.d.ts +0 -0
@@ -15,22 +15,6 @@ const PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..")
15
15
  const MCP_EXPORT_MARKER = "hiai-opencode"
16
16
 
17
17
  const MCP_REGISTRY = {
18
- playwright: {
19
- defaultEnabled: true,
20
- requiredEnv: [],
21
- check: checkNodeNpx,
22
- },
23
- rag: {
24
- defaultEnabled: true,
25
- requiredEnv: [],
26
- check: checkRag,
27
- },
28
- firecrawl: {
29
- defaultEnabled: true,
30
- requiredEnv: ["FIRECRAWL_API_KEY"],
31
- authFallback: "firecrawl",
32
- check: checkNodeNpx,
33
- },
34
18
  mempalace: {
35
19
  defaultEnabled: true,
36
20
  requiredEnv: [],
@@ -52,6 +36,11 @@ const MCP_REGISTRY = {
52
36
  requiredEnv: [],
53
37
  check: checkNodeNpx,
54
38
  },
39
+ grep_app: {
40
+ defaultEnabled: true,
41
+ requiredEnv: [],
42
+ check: checkRemoteOptionalKey,
43
+ },
55
44
  }
56
45
 
57
46
  function usage() {
@@ -135,6 +124,46 @@ function candidateOpenCodeConfigPaths() {
135
124
  return paths
136
125
  }
137
126
 
127
+ function checkPgvectorConnectivity() {
128
+ const result = spawnSync("docker", ["exec", "ai-core-postgres", "psql", "-U", "aiuser", "-d", "ai_orchestration", "-c", "SELECT COUNT(*) FROM pg_extension WHERE extname = 'vector';"], {
129
+ encoding: "utf-8",
130
+ timeout: 10000,
131
+ })
132
+ if (result.status === 0 && result.stdout.includes("1 row")) {
133
+ return { level: "ok", detail: "pgvector extension active" }
134
+ }
135
+ if (result.status === 0 && result.stdout.includes("0 rows")) {
136
+ return { level: "warn", detail: "pgvector extension not installed (vector search unavailable)" }
137
+ }
138
+ return { level: "error", detail: "pgvector connectivity check failed (docker exec psql)" }
139
+ }
140
+
141
+ function checkDelegationPermissions(config) {
142
+ const readOnly = config?.delegation?.read_only ?? []
143
+ const noPty = config?.delegation?.no_pty ?? []
144
+ const writeDenied = readOnly.filter((a) => a.toLowerCase().includes("manager"))
145
+ const ptyDenied = noPty.filter((a) => a.toLowerCase().includes("strategist"))
146
+ const detail = [
147
+ writeDenied.length > 0 ? `manager write deny: [${writeDenied.join(", ")}]` : null,
148
+ ptyDenied.length > 0 ? `strategist pty deny: [${ptyDenied.join(", ")}]` : null,
149
+ ].filter(Boolean).join(" | ") || "delegation permissions not configured"
150
+ return { level: detail.includes("deny") ? "ok" : "warn", detail }
151
+ }
152
+
153
+ function checkMemPalaceHookStatus() {
154
+ const hookPath = join(PACKAGE_ROOT, "src", "hooks", "mempalace-auto-save", "handler.ts")
155
+ const handlerPath = join(PACKAGE_ROOT, "src", "hooks", "mempalace-auto-save", "index.ts")
156
+ const hookExists = existsSync(hookPath)
157
+ const handlerExists = existsSync(handlerPath)
158
+ if (hookExists && handlerExists) {
159
+ return { level: "ok", detail: "mem palace auto-save hook installed" }
160
+ }
161
+ if (hookExists) {
162
+ return { level: "warn", detail: "mem palace auto-save hook partial (handler.ts only)" }
163
+ }
164
+ return { level: "warn", detail: "mem palace auto-save hook not found" }
165
+ }
166
+
138
167
  function checkOpenCodePluginRegistration() {
139
168
  for (const path of candidateOpenCodeConfigPaths()) {
140
169
  if (!existsSync(path)) continue
@@ -152,10 +181,13 @@ function checkOpenCodePluginRegistration() {
152
181
  }
153
182
  }
154
183
 
155
- if (plugins.includes("@hiai-gg/hiai-opencode")) {
184
+ const dcpRegistered = plugins.includes("@tarquinen/opencode-dcp@latest") || plugins.includes("@tarquinen/opencode-dcp")
185
+ const hiaiRegistered = plugins.includes("@hiai-gg/hiai-opencode")
186
+
187
+ if (hiaiRegistered) {
156
188
  return {
157
- level: "ok",
158
- detail: `plugin registered in ${path}`,
189
+ level: dcpRegistered ? "ok" : "warn",
190
+ detail: `plugin registered in ${path}${dcpRegistered ? "; DCP (opencode-dcp) also registered" : "; DCP (opencode-dcp) not found — optional for Dynamic Context Pruning"}`,
159
191
  }
160
192
  }
161
193
 
@@ -188,13 +220,6 @@ function assetPath(...segments) {
188
220
  function createMcpExport(config) {
189
221
  const servers = {}
190
222
 
191
- if (enabled(config, "playwright")) {
192
- servers.playwright = {
193
- command: "node",
194
- args: [assetPath("mcp", "playwright.mjs")],
195
- }
196
- }
197
-
198
223
  if (enabled(config, "stitch")) {
199
224
  servers.stitch = {
200
225
  type: "http",
@@ -215,29 +240,6 @@ function createMcpExport(config) {
215
240
  }
216
241
  }
217
242
 
218
- if (enabled(config, "firecrawl")) {
219
- servers.firecrawl = {
220
- command: "node",
221
- args: [assetPath("runtime", "npm-package-runner.mjs"), "firecrawl-mcp"],
222
- env: {
223
- FIRECRAWL_API_KEY: config?.auth?.firecrawl || "${FIRECRAWL_API_KEY}",
224
- },
225
- }
226
- }
227
-
228
- if (enabled(config, "rag")) {
229
- servers.rag = {
230
- command: "node",
231
- args: [assetPath("mcp", "rag.mjs")],
232
- env: {
233
- OPENCODE_RAG_URL:
234
- process.env.OPENCODE_RAG_URL
235
- || resolveEnvTemplate(config?.mcp?.rag?.environment?.OPENCODE_RAG_URL)
236
- || DEFAULT_RAG_URL,
237
- },
238
- }
239
- }
240
-
241
243
  if (enabled(config, "mempalace")) {
242
244
  const mempalacePython =
243
245
  process.env.MEMPALACE_PYTHON?.trim()
@@ -470,27 +472,6 @@ function checkMempalace(config) {
470
472
  }
471
473
  }
472
474
 
473
- async function checkRag(config) {
474
- const url =
475
- process.env.OPENCODE_RAG_URL?.trim()
476
- || resolveEnvTemplate(config?.mcp?.rag?.environment?.OPENCODE_RAG_URL)
477
- || DEFAULT_RAG_URL
478
-
479
- try {
480
- const controller = new AbortController()
481
- const timeout = setTimeout(() => controller.abort(), 2500)
482
- const response = await fetch(url, { method: "GET", signal: controller.signal })
483
- clearTimeout(timeout)
484
-
485
- if (response.status < 500) {
486
- return { level: "ok", detail: `enabled, ${url} reachable` }
487
- }
488
- return { level: "warn", detail: `enabled, ${url} returned ${response.status}` }
489
- } catch {
490
- return { level: "warn", detail: `enabled, ${url} not reachable` }
491
- }
492
- }
493
-
494
475
  function checkRemoteKeyOnly() {
495
476
  return { level: "ok", detail: "remote endpoint configured" }
496
477
  }
@@ -614,27 +595,82 @@ function checkSkillMaterialization() {
614
595
  }
615
596
  }
616
597
 
598
+ const REQUIRED_MODEL_SLOTS = [
599
+ "bob", "coder", "strategist", "manager", "critic",
600
+ "designer", "researcher", "writer", "vision", "sub"
601
+ ]
602
+
603
+ const DEPRECATED_MODEL_KEYS = {
604
+ "guard": "manager",
605
+ "brainstormer": "writer"
606
+ }
607
+
617
608
  function getAgentSummary(config) {
618
609
  const visible = [
619
- "Bob",
620
- "Coder",
621
- "Strategist",
622
- "Guard",
623
- "Critic",
624
- "Designer",
625
- "Researcher",
626
- "Manager",
627
- "Brainstormer",
628
- "Vision",
610
+ "Bob", "Coder", "Strategist", "Manager", "Critic",
611
+ "Designer", "Researcher", "Writer", "Vision"
629
612
  ]
630
613
  const hidden = ["Agent Skills", "Sub", "build", "plan"]
631
- const modelCount = Object.keys(config?.models ?? {}).length
614
+
615
+ const models = config?.models ?? {}
616
+ const modelKeys = Object.keys(models)
617
+
618
+ // Check for missing required slots
619
+ const missing = REQUIRED_MODEL_SLOTS.filter(slot => !(slot in models))
620
+ const missingDetail = missing.length > 0
621
+ ? `; missing=[${missing.join(", ")}]`
622
+ : ""
623
+
624
+ // Check for deprecated keys
625
+ const deprecated = modelKeys.filter(k => k in DEPRECATED_MODEL_KEYS)
626
+ const deprecatedDetail = deprecated.length > 0
627
+ ? `; deprecated keys=[${deprecated.join(" → " + DEPRECATED_MODEL_KEYS[deprecated[0]] + ", ")}]`
628
+ : ""
629
+
630
+ // Check for empty model values
631
+ const emptySlots = modelKeys.filter(k => {
632
+ const v = models[k]
633
+ if (typeof v === "string") return v.trim() === ""
634
+ if (v && typeof v === "object") return !v.model || v.model.trim() === ""
635
+ return true
636
+ })
637
+ const emptyDetail = emptySlots.length > 0
638
+ ? `; empty=[${emptySlots.join(", ")}]`
639
+ : ""
640
+
641
+ const issues = []
642
+ if (missing.length > 0) issues.push(`${missing.length} required slot(s) missing: ${missing.join(", ")}`)
643
+ if (deprecated.length > 0) issues.push(`${deprecated.length} deprecated key(s): ${deprecated.map(k => `${k}→${DEPRECATED_MODEL_KEYS[k]}`).join(", ")}`)
644
+ if (emptySlots.length > 0) issues.push(`${emptySlots.length} empty model value(s): ${emptySlots.join(", ")}`)
645
+
646
+ const level = issues.length === 0 ? "ok" : (missing.length > 0 ? "fail" : "warn")
647
+ const issueDetail = issues.length > 0 ? ` (${issues.join("; ")})` : ""
648
+
632
649
  return {
633
- level: modelCount >= 10 ? "ok" : "warn",
634
- detail: `visible=${visible.length} [${visible.join(", ")}]; hidden=${hidden.length} [${hidden.join(", ")}]; model slots configured=${modelCount}/10`,
650
+ level,
651
+ detail: `visible=${visible.length} [${visible.join(", ")}]; hidden=${hidden.length} [${hidden.join(", ")}]; model slots=${modelKeys.length}/${REQUIRED_MODEL_SLOTS.length}${missingDetail}${deprecatedDetail}${emptyDetail}${issueDetail}`,
635
652
  }
636
653
  }
637
654
 
655
+ function checkModelSlotValues(config) {
656
+ const results = []
657
+ const models = config?.models ?? {}
658
+
659
+ for (const slot of REQUIRED_MODEL_SLOTS) {
660
+ const value = models[slot]
661
+ if (!value) {
662
+ results.push({ level: "fail", check: `Model slot '${slot}'`, detail: "missing — no model configured" })
663
+ continue
664
+ }
665
+ const model = typeof value === "string" ? value : value.model
666
+ if (!model || model.trim() === "") {
667
+ results.push({ level: "fail", check: `Model slot '${slot}'`, detail: "empty model value" })
668
+ }
669
+ }
670
+
671
+ return results
672
+ }
673
+
638
674
  function getLspDefaults() {
639
675
  return {
640
676
  typescript: ["typescript-language-server", "--stdio"],
@@ -687,7 +723,7 @@ async function probeStdioMcp(serverName, serverConfig) {
687
723
  stderr: "pipe",
688
724
  })
689
725
 
690
- const timeoutMs = 12000
726
+ const timeoutMs = 60000
691
727
  const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs))
692
728
 
693
729
  try {
@@ -806,6 +842,12 @@ async function mcpStatus(options = {}) {
806
842
  const agents = getAgentSummary(config)
807
843
  console.log(`${statusIcon(agents.level)} Agent count and naming - ${agents.detail}`)
808
844
 
845
+ // Model slot value validation
846
+ const modelIssues = checkModelSlotValues(config)
847
+ for (const issue of modelIssues) {
848
+ console.log(`${statusIcon(issue.level)} ${issue.check}: ${issue.detail}`)
849
+ }
850
+
809
851
  const lsp = checkLspAvailability(config)
810
852
  console.log(`${statusIcon(lsp.level)} LSP runtime availability - ${lsp.detail}`)
811
853
 
@@ -813,6 +855,15 @@ async function mcpStatus(options = {}) {
813
855
  const mempalacePythonIcon = mempalacePython.value ? "✅" : "⚠️ "
814
856
  console.log(`${mempalacePythonIcon} MemPalace python selection - ${mempalacePython.source}${mempalacePython.value ? ` (${mempalacePython.value})` : ""}`)
815
857
 
858
+ const pgvector = checkPgvectorConnectivity()
859
+ console.log(`${statusIcon(pgvector.level)} pgvector connectivity - ${pgvector.detail}`)
860
+
861
+ const delegation = checkDelegationPermissions(config)
862
+ console.log(`${statusIcon(delegation.level)} Delegation permissions - ${delegation.detail}`)
863
+
864
+ const mempalaceHook = checkMemPalaceHookStatus()
865
+ console.log(`${statusIcon(mempalaceHook.level)} MemPalace auto-save hook - ${mempalaceHook.detail}`)
866
+
816
867
  console.log("")
817
868
  console.log("MCP Tool Probes:")
818
869
  const probeResults = await probeMcpServers(config)
@@ -843,8 +894,8 @@ async function runDiagnose(outputPath) {
843
894
  sections.push("ENVIRONMENT (keys only, no values):")
844
895
  const envKeys = [
845
896
  "FIRECRAWL_API_KEY", "STITCH_AI_API_KEY", "CONTEXT7_API_KEY",
846
- "EXA_API_KEY", "TAVILY_API_KEY", "OPENCODE_RAG_URL",
847
- "MEMPALACE_PYTHON", "HIAI_PLAYWRIGHT_INSTALL_BROWSERS", "HIAI_MCP_AUTO_INSTALL",
897
+ "OPENCODE_RAG_URL",
898
+ "MEMPALACE_PYTHON", "HIAI_MCP_AUTO_INSTALL",
848
899
  ]
849
900
  for (const key of envKeys) {
850
901
  const hasValue = !!process.env[key]?.trim()
@@ -0,0 +1,2 @@
1
+ [2026-05-10T20:57:26.010Z] Plugin initialized: 0 commands []
2
+ [2026-05-10T20:57:26.138Z] Registered /subtask command
@@ -0,0 +1,45 @@
1
+ {
2
+ "_meta": {
3
+ "generatedBy": "hiai-opencode",
4
+ "version": 1,
5
+ "generatedAt": "2026-05-11T00:00:00.000Z"
6
+ },
7
+ "mcpServers": {
8
+ "stitch": {
9
+ "type": "http",
10
+ "url": "https://stitch.googleapis.com/mcp",
11
+ "headers": {
12
+ "X-Goog-Api-Key": "{env:STITCH_AI_API_KEY}"
13
+ }
14
+ },
15
+ "sequential-thinking": {
16
+ "command": "node",
17
+ "args": [
18
+ "{pluginRoot}/assets/runtime/npm-package-runner.mjs",
19
+ "@modelcontextprotocol/server-sequential-thinking"
20
+ ]
21
+ },
22
+ "context7": {
23
+ "type": "http",
24
+ "url": "https://mcp.context7.com/mcp",
25
+ "headers": {
26
+ "X-API-KEY": "{env:CONTEXT7_API_KEY}"
27
+ }
28
+ },
29
+ "mempalace": {
30
+ "command": "node",
31
+ "args": [
32
+ "{pluginRoot}/assets/mcp/mempalace.mjs",
33
+ "--palace",
34
+ "./.opencode/palace"
35
+ ],
36
+ "env": {
37
+ "MEMPALACE_PYTHON": "{env:MEMPALACE_PYTHON}"
38
+ }
39
+ },
40
+ "grep_app": {
41
+ "type": "http",
42
+ "url": "https://mcp.grep.app"
43
+ }
44
+ }
45
+ }
@@ -1,24 +1,55 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "title": "hiai-opencode Configuration",
4
- "description": "User-facing hiai-opencode config. Users choose 10 primary agent models, service auth placeholders, and enable/disable MCP/LSP integrations. Internal routing derives hidden agents and task categories from these model slots.",
4
+ "description": "User-facing hiai-opencode config. Users choose 10+ primary agent models, service auth placeholders, and enable/disable MCP/LSP integrations. Internal routing derives hidden agents and task categories from these model slots.",
5
5
  "type": "object",
6
+ "additionalProperties": false,
6
7
  "properties": {
7
- "$schema": { "type": "string" },
8
+ "$schema": {
9
+ "type": "string"
10
+ },
11
+ "version": {
12
+ "type": "string",
13
+ "description": "Config format version. Semantic versioning; bump on breaking schema changes."
14
+ },
8
15
  "models": {
9
16
  "type": "object",
10
17
  "description": "The only user-facing model source of truth. Use fully qualified OpenCode model IDs.",
18
+ "additionalProperties": false,
11
19
  "properties": {
12
- "bob": { "$ref": "#/definitions/modelSlot" },
13
- "coder": { "$ref": "#/definitions/modelSlot" },
14
- "strategist": { "$ref": "#/definitions/modelSlot" },
15
- "guard": { "$ref": "#/definitions/modelSlot" },
16
- "critic": { "$ref": "#/definitions/modelSlot" },
17
- "designer": { "$ref": "#/definitions/modelSlot" },
18
- "researcher": { "$ref": "#/definitions/modelSlot" },
19
- "manager": { "$ref": "#/definitions/modelSlot" },
20
- "brainstormer": { "$ref": "#/definitions/modelSlot" },
21
- "vision": { "$ref": "#/definitions/modelSlot" }
20
+ "bob": {
21
+ "$ref": "#/definitions/modelSlot"
22
+ },
23
+ "coder": {
24
+ "$ref": "#/definitions/modelSlot"
25
+ },
26
+ "strategist": {
27
+ "$ref": "#/definitions/modelSlot"
28
+ },
29
+ "guard": {
30
+ "$ref": "#/definitions/modelSlot"
31
+ },
32
+ "critic": {
33
+ "$ref": "#/definitions/modelSlot"
34
+ },
35
+ "designer": {
36
+ "$ref": "#/definitions/modelSlot"
37
+ },
38
+ "researcher": {
39
+ "$ref": "#/definitions/modelSlot"
40
+ },
41
+ "manager": {
42
+ "$ref": "#/definitions/modelSlot"
43
+ },
44
+ "brainstormer": {
45
+ "$ref": "#/definitions/modelSlot"
46
+ },
47
+ "vision": {
48
+ "$ref": "#/definitions/modelSlot"
49
+ },
50
+ "sub": {
51
+ "$ref": "#/definitions/modelSlot"
52
+ }
22
53
  },
23
54
  "required": [
24
55
  "bob",
@@ -35,73 +66,159 @@
35
66
  },
36
67
  "auth": {
37
68
  "type": "object",
38
- "additionalProperties": { "type": "string" },
69
+ "description": "Service auth placeholders. Keys: stitch, context7. Others are not valid.",
70
+ "additionalProperties": false,
39
71
  "properties": {
40
- "stitch": { "type": "string" },
41
- "firecrawl": { "type": "string" },
42
- "context7": { "type": "string" }
72
+ "stitch": {
73
+ "type": "string",
74
+ "description": "Stitch AI API key placeholder, e.g. {env:HIAI_STITCH_AUTH}"
75
+ },
76
+ "context7": {
77
+ "type": "string",
78
+ "description": "Context7 API key placeholder, e.g. {env:HIAI_CONTEXT7_AUTH}"
79
+ }
43
80
  }
44
81
  },
45
82
  "mcp": {
46
83
  "type": "object",
47
84
  "additionalProperties": false,
48
85
  "properties": {
49
- "playwright": { "$ref": "#/definitions/toggle" },
50
- "stitch": { "$ref": "#/definitions/toggle" },
51
- "sequential-thinking": { "$ref": "#/definitions/toggle" },
52
- "firecrawl": { "$ref": "#/definitions/toggle" },
53
- "rag": { "$ref": "#/definitions/toggle" },
54
- "mempalace": { "$ref": "#/definitions/mempalaceToggle" },
55
- "context7": { "$ref": "#/definitions/toggle" },
56
- "websearch": { "$ref": "#/definitions/websearchToggle" },
57
- "grep_app": { "$ref": "#/definitions/toggle" }
86
+ "playwright": {
87
+ "$ref": "#/definitions/toggle"
88
+ },
89
+ "stitch": {
90
+ "$ref": "#/definitions/toggle"
91
+ },
92
+ "sequential-thinking": {
93
+ "$ref": "#/definitions/toggle"
94
+ },
95
+ "mempalace": {
96
+ "$ref": "#/definitions/mempalaceToggle"
97
+ },
98
+ "context7": {
99
+ "$ref": "#/definitions/toggle"
100
+ },
101
+ "grep_app": {
102
+ "$ref": "#/definitions/toggle"
103
+ }
58
104
  }
59
105
  },
60
106
  "lsp": {
61
107
  "type": "object",
62
108
  "additionalProperties": false,
63
109
  "properties": {
64
- "typescript": { "$ref": "#/definitions/toggle" },
65
- "svelte": { "$ref": "#/definitions/toggle" },
66
- "eslint": { "$ref": "#/definitions/toggle" },
67
- "bash": { "$ref": "#/definitions/toggle" },
68
- "pyright": { "$ref": "#/definitions/toggle" }
110
+ "typescript": {
111
+ "$ref": "#/definitions/toggle"
112
+ },
113
+ "svelte": {
114
+ "$ref": "#/definitions/toggle"
115
+ },
116
+ "eslint": {
117
+ "$ref": "#/definitions/toggle"
118
+ },
119
+ "bash": {
120
+ "$ref": "#/definitions/toggle"
121
+ },
122
+ "pyright": {
123
+ "$ref": "#/definitions/toggle"
124
+ }
69
125
  }
70
126
  },
71
127
  "skill_discovery": {
72
128
  "type": "object",
73
129
  "description": "Controls external skill folder scanning. Defaults keep installs deterministic.",
130
+ "additionalProperties": false,
74
131
  "properties": {
75
- "config_sources": { "type": "boolean", "default": true },
76
- "project_opencode": { "type": "boolean", "default": true },
77
- "global_opencode": { "type": "boolean", "default": false },
78
- "project_claude": { "type": "boolean", "default": false },
79
- "global_claude": { "type": "boolean", "default": false },
80
- "project_agents": { "type": "boolean", "default": false },
81
- "global_agents": { "type": "boolean", "default": false }
132
+ "config_sources": {
133
+ "type": "boolean",
134
+ "default": true
135
+ },
136
+ "project_opencode": {
137
+ "type": "boolean",
138
+ "default": true
139
+ },
140
+ "global_opencode": {
141
+ "type": "boolean",
142
+ "default": false
143
+ },
144
+ "project_claude": {
145
+ "type": "boolean",
146
+ "default": false
147
+ },
148
+ "global_claude": {
149
+ "type": "boolean",
150
+ "default": false
151
+ },
152
+ "project_agents": {
153
+ "type": "boolean",
154
+ "default": false
155
+ },
156
+ "global_agents": {
157
+ "type": "boolean",
158
+ "default": false
159
+ }
82
160
  }
83
161
  },
84
162
  "subtask2": {
85
163
  "type": "object",
164
+ "additionalProperties": false,
86
165
  "properties": {
87
- "replace_generic": { "type": "boolean" }
166
+ "replace_generic": {
167
+ "type": "boolean"
168
+ }
88
169
  }
89
- }
170
+ },
171
+ "ralph_loop": {
172
+ "type": "object",
173
+ "description": "Ralph-loop continuation engine config. Auto-start threshold 0 disables auto-start.",
174
+ "additionalProperties": false,
175
+ "properties": {
176
+ "enabled": {
177
+ "type": "boolean",
178
+ "default": false,
179
+ "description": "Whether ralph-loop is enabled."
180
+ },
181
+ "auto_start_threshold": {
182
+ "type": "number",
183
+ "minimum": 0,
184
+ "maximum": 100,
185
+ "default": 0,
186
+ "description": "Auto-start ralph-loop when this many or more open todos exist in a single session. 0 disables auto-start."
187
+ }
188
+ }
189
+ }
190
+ }
90
191
  },
91
- "required": ["models"],
192
+ "required": [
193
+ "models"
194
+ ],
92
195
  "definitions": {
93
196
  "modelSlot": {
94
197
  "oneOf": [
95
- { "type": "string" },
198
+ {
199
+ "type": "string"
200
+ },
96
201
  {
97
202
  "type": "object",
98
203
  "properties": {
99
- "model": { "type": "string" },
204
+ "model": {
205
+ "type": "string"
206
+ },
100
207
  "recommended": {
101
- "enum": ["xhigh", "high", "middle", "fast", "vision", "writing", "design"]
208
+ "enum": [
209
+ "xhigh",
210
+ "high",
211
+ "middle",
212
+ "fast",
213
+ "vision",
214
+ "writing",
215
+ "design"
216
+ ]
102
217
  }
103
218
  },
104
- "required": ["model"],
219
+ "required": [
220
+ "model"
221
+ ],
105
222
  "additionalProperties": false
106
223
  }
107
224
  ]
@@ -109,35 +226,32 @@
109
226
  "toggle": {
110
227
  "type": "object",
111
228
  "properties": {
112
- "enabled": { "type": "boolean", "default": true }
229
+ "enabled": {
230
+ "type": "boolean",
231
+ "default": true
232
+ }
113
233
  },
114
- "required": ["enabled"],
234
+ "required": [
235
+ "enabled"
236
+ ],
115
237
  "additionalProperties": false
116
238
  },
117
239
  "mempalaceToggle": {
118
240
  "type": "object",
119
241
  "properties": {
120
- "enabled": { "type": "boolean", "default": true },
242
+ "enabled": {
243
+ "type": "boolean",
244
+ "default": true
245
+ },
121
246
  "pythonPath": {
122
247
  "type": "string",
123
248
  "description": "Optional explicit Python executable for MemPalace (for example: ./.venv/bin/python)."
124
249
  }
125
250
  },
126
- "required": ["enabled"],
127
- "additionalProperties": false
128
- },
129
- "websearchToggle": {
130
- "type": "object",
131
- "properties": {
132
- "enabled": { "type": "boolean", "default": true },
133
- "provider": {
134
- "enum": ["exa", "tavily"],
135
- "default": "exa",
136
- "description": "Remote web search MCP provider. Exa works without an API key but can use EXA_API_KEY. Tavily requires TAVILY_API_KEY."
137
- }
138
- },
139
- "required": ["enabled"],
251
+ "required": [
252
+ "enabled"
253
+ ],
140
254
  "additionalProperties": false
141
255
  }
142
256
  }
143
- }
257
+ }