mindforge-cc 11.3.1 → 11.5.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 (475) hide show
  1. package/.agent/CLAUDE.md +13 -0
  2. package/.agent/hooks/lib/hook-flags.js +78 -0
  3. package/.agent/hooks/lib/pretooluse-visible-output.js +46 -0
  4. package/.agent/hooks/mindforge-block-no-verify.js +552 -0
  5. package/.agent/hooks/mindforge-config-protection.js +144 -0
  6. package/.agent/hooks/run-with-flags.js +207 -0
  7. package/.agent/mindforge/checkpoint.md +76 -0
  8. package/.agent/mindforge/harness-audit.md +59 -0
  9. package/.agent/mindforge/instinct.md +46 -0
  10. package/.agent/mindforge/orch-add-feature.md +43 -0
  11. package/.agent/mindforge/orch-build-mvp.md +48 -0
  12. package/.agent/mindforge/orch-change-feature.md +45 -0
  13. package/.agent/mindforge/orch-fix-defect.md +43 -0
  14. package/.agent/mindforge/orch-refine-code.md +43 -0
  15. package/.agent/skills/mindforge-add-backlog/SKILL.md +2 -2
  16. package/.agent/skills/mindforge-add-phase/SKILL.md +2 -2
  17. package/.agent/skills/mindforge-add-tests/SKILL.md +2 -2
  18. package/.agent/skills/mindforge-add-todo/SKILL.md +2 -2
  19. package/.agent/skills/mindforge-audit-milestone/SKILL.md +2 -2
  20. package/.agent/skills/mindforge-audit-uat/SKILL.md +2 -2
  21. package/.agent/skills/mindforge-autonomous/SKILL.md +2 -2
  22. package/.agent/skills/mindforge-brainstorming/SKILL.md +1 -1
  23. package/.agent/skills/mindforge-check-todos/SKILL.md +2 -2
  24. package/.agent/skills/mindforge-cleanup/SKILL.md +2 -2
  25. package/.agent/skills/mindforge-complete-milestone/SKILL.md +2 -2
  26. package/.agent/skills/mindforge-debug/SKILL.md +2 -2
  27. package/.agent/skills/mindforge-debug_extended/SKILL.md +2 -2
  28. package/.agent/skills/mindforge-discuss-phase/SKILL.md +2 -2
  29. package/.agent/skills/mindforge-do/SKILL.md +2 -2
  30. package/.agent/skills/mindforge-execute-phase/SKILL.md +2 -2
  31. package/.agent/skills/mindforge-execute-phase_extended/SKILL.md +2 -2
  32. package/.agent/skills/mindforge-fast/SKILL.md +2 -2
  33. package/.agent/skills/mindforge-forensics/SKILL.md +2 -2
  34. package/.agent/skills/mindforge-health/SKILL.md +2 -2
  35. package/.agent/skills/mindforge-help/SKILL.md +2 -2
  36. package/.agent/skills/mindforge-insert-phase/SKILL.md +2 -2
  37. package/.agent/skills/mindforge-join-discord/SKILL.md +2 -2
  38. package/.agent/skills/mindforge-list-phase-assumptions/SKILL.md +2 -2
  39. package/.agent/skills/mindforge-list-workspaces/SKILL.md +2 -2
  40. package/.agent/skills/mindforge-manager/SKILL.md +2 -2
  41. package/.agent/skills/mindforge-map-codebase/SKILL.md +2 -2
  42. package/.agent/skills/mindforge-milestone-summary/SKILL.md +2 -2
  43. package/.agent/skills/mindforge-neural-orchestrator/SKILL.md +2 -2
  44. package/.agent/skills/mindforge-new-milestone/SKILL.md +2 -2
  45. package/.agent/skills/mindforge-new-project/SKILL.md +2 -2
  46. package/.agent/skills/mindforge-new-workspace/SKILL.md +2 -2
  47. package/.agent/skills/mindforge-next/SKILL.md +2 -2
  48. package/.agent/skills/mindforge-note/SKILL.md +2 -2
  49. package/.agent/skills/mindforge-parallel-mesh_extended/SKILL.md +2 -2
  50. package/.agent/skills/mindforge-pause-work/SKILL.md +2 -2
  51. package/.agent/skills/mindforge-plan-milestone-gaps/SKILL.md +2 -2
  52. package/.agent/skills/mindforge-plan-phase/SKILL.md +2 -2
  53. package/.agent/skills/mindforge-plan-phase_extended/SKILL.md +2 -2
  54. package/.agent/skills/mindforge-plant-seed/SKILL.md +2 -2
  55. package/.agent/skills/mindforge-pr-branch/SKILL.md +2 -2
  56. package/.agent/skills/mindforge-profile-user/SKILL.md +2 -2
  57. package/.agent/skills/mindforge-progress/SKILL.md +2 -2
  58. package/.agent/skills/mindforge-quick/SKILL.md +2 -2
  59. package/.agent/skills/mindforge-reapply-patches/SKILL.md +2 -2
  60. package/.agent/skills/mindforge-remove-phase/SKILL.md +2 -2
  61. package/.agent/skills/mindforge-remove-workspace/SKILL.md +2 -2
  62. package/.agent/skills/mindforge-research-phase/SKILL.md +2 -2
  63. package/.agent/skills/mindforge-resume-work/SKILL.md +2 -2
  64. package/.agent/skills/mindforge-review/SKILL.md +2 -2
  65. package/.agent/skills/mindforge-review-backlog/SKILL.md +2 -2
  66. package/.agent/skills/mindforge-review-inbound/SKILL.md +2 -2
  67. package/.agent/skills/mindforge-review-request/SKILL.md +2 -2
  68. package/.agent/skills/mindforge-session-report/SKILL.md +2 -2
  69. package/.agent/skills/mindforge-set-profile/SKILL.md +2 -2
  70. package/.agent/skills/mindforge-settings/SKILL.md +2 -2
  71. package/.agent/skills/mindforge-ship/SKILL.md +2 -2
  72. package/.agent/skills/mindforge-ship_extended/SKILL.md +2 -2
  73. package/.agent/skills/mindforge-skill-creation/SKILL.md +2 -2
  74. package/.agent/skills/mindforge-stats/SKILL.md +2 -2
  75. package/.agent/skills/mindforge-swarm-execution/SKILL.md +2 -2
  76. package/.agent/skills/mindforge-system-architecture/SKILL.md +2 -2
  77. package/.agent/skills/mindforge-tdd/SKILL.md +2 -2
  78. package/.agent/skills/mindforge-tdd_extended/SKILL.md +2 -2
  79. package/.agent/skills/mindforge-thread/SKILL.md +2 -2
  80. package/.agent/skills/mindforge-ui-phase/SKILL.md +2 -2
  81. package/.agent/skills/mindforge-ui-review/SKILL.md +2 -2
  82. package/.agent/skills/mindforge-update/SKILL.md +2 -2
  83. package/.agent/skills/mindforge-validate-phase/SKILL.md +2 -2
  84. package/.agent/skills/mindforge-verify-work/SKILL.md +2 -2
  85. package/.agent/skills/mindforge-verify-work_extended/SKILL.md +2 -2
  86. package/.agent/skills/mindforge-workspace-isolated/SKILL.md +2 -2
  87. package/.agent/skills/mindforge-workstreams/SKILL.md +2 -2
  88. package/.claude/CLAUDE.md +13 -0
  89. package/.claude/commands/mindforge/add-backlog.md +2 -2
  90. package/.claude/commands/mindforge/agent-deploy.md +1 -1
  91. package/.claude/commands/mindforge/agent-design.md +1 -1
  92. package/.claude/commands/mindforge/agent.md +2 -2
  93. package/.claude/commands/mindforge/ai-cost.md +1 -1
  94. package/.claude/commands/mindforge/ai-safety.md +1 -1
  95. package/.claude/commands/mindforge/approve.md +1 -1
  96. package/.claude/commands/mindforge/audit.md +1 -1
  97. package/.claude/commands/mindforge/auto.md +1 -1
  98. package/.claude/commands/mindforge/benchmark.md +1 -1
  99. package/.claude/commands/mindforge/browse.md +1 -1
  100. package/.claude/commands/mindforge/build-opt.md +1 -1
  101. package/.claude/commands/mindforge/cache.md +1 -1
  102. package/.claude/commands/mindforge/causal.md +1 -1
  103. package/.claude/commands/mindforge/cdn.md +1 -1
  104. package/.claude/commands/mindforge/change.md +1 -1
  105. package/.claude/commands/mindforge/checkpoint.md +76 -0
  106. package/.claude/commands/mindforge/cli.md +1 -1
  107. package/.claude/commands/mindforge/cluster-instincts.md +1 -1
  108. package/.claude/commands/mindforge/communicate.md +1 -1
  109. package/.claude/commands/mindforge/complete-milestone.md +1 -1
  110. package/.claude/commands/mindforge/compliance.md +1 -1
  111. package/.claude/commands/mindforge/consult.md +1 -1
  112. package/.claude/commands/mindforge/contract-test.md +1 -1
  113. package/.claude/commands/mindforge/cost-report.md +1 -1
  114. package/.claude/commands/mindforge/costs.md +1 -1
  115. package/.claude/commands/mindforge/council.md +1 -1
  116. package/.claude/commands/mindforge/create-skill.md +1 -1
  117. package/.claude/commands/mindforge/cross-review.md +1 -1
  118. package/.claude/commands/mindforge/dashboard.md +1 -1
  119. package/.claude/commands/mindforge/data-mesh.md +1 -1
  120. package/.claude/commands/mindforge/data-pipeline.md +1 -1
  121. package/.claude/commands/mindforge/de-slop.md +1 -1
  122. package/.claude/commands/mindforge/debug.md +1 -1
  123. package/.claude/commands/mindforge/degrade.md +1 -1
  124. package/.claude/commands/mindforge/delegate.md +1 -1
  125. package/.claude/commands/mindforge/deploy.md +1 -1
  126. package/.claude/commands/mindforge/discuss-phase.md +1 -1
  127. package/.claude/commands/mindforge/dmux.md +1 -1
  128. package/.claude/commands/mindforge/do.md +2 -2
  129. package/.claude/commands/mindforge/ecommerce.md +1 -1
  130. package/.claude/commands/mindforge/edge.md +1 -1
  131. package/.claude/commands/mindforge/edtech.md +1 -1
  132. package/.claude/commands/mindforge/embeddings.md +1 -1
  133. package/.claude/commands/mindforge/environments.md +1 -1
  134. package/.claude/commands/mindforge/eval.md +1 -1
  135. package/.claude/commands/mindforge/events.md +1 -1
  136. package/.claude/commands/mindforge/evolve-skills.md +1 -1
  137. package/.claude/commands/mindforge/execute-phase.md +48 -7
  138. package/.claude/commands/mindforge/feature-flags.md +1 -1
  139. package/.claude/commands/mindforge/feature-store.md +1 -1
  140. package/.claude/commands/mindforge/finops.md +1 -1
  141. package/.claude/commands/mindforge/fintech.md +1 -1
  142. package/.claude/commands/mindforge/flutter.md +1 -1
  143. package/.claude/commands/mindforge/gaming.md +1 -1
  144. package/.claude/commands/mindforge/graphql.md +1 -1
  145. package/.claude/commands/mindforge/harness-audit.md +59 -0
  146. package/.claude/commands/mindforge/health.md +1 -1
  147. package/.claude/commands/mindforge/healthcare.md +1 -1
  148. package/.claude/commands/mindforge/help.md +1 -1
  149. package/.claude/commands/mindforge/hire.md +1 -1
  150. package/.claude/commands/mindforge/i18n.md +1 -1
  151. package/.claude/commands/mindforge/idempotent.md +1 -1
  152. package/.claude/commands/mindforge/init-org.md +1 -1
  153. package/.claude/commands/mindforge/init-project.md +1 -1
  154. package/.claude/commands/mindforge/install-skill.md +1 -1
  155. package/.claude/commands/mindforge/instinct.md +46 -0
  156. package/.claude/commands/mindforge/introspect.md +1 -1
  157. package/.claude/commands/mindforge/iot.md +1 -1
  158. package/.claude/commands/mindforge/knowledge-graph.md +1 -1
  159. package/.claude/commands/mindforge/lakehouse.md +1 -1
  160. package/.claude/commands/mindforge/lead.md +1 -1
  161. package/.claude/commands/mindforge/learn-instinct.md +1 -1
  162. package/.claude/commands/mindforge/learn.md +1 -1
  163. package/.claude/commands/mindforge/learning.md +1 -1
  164. package/.claude/commands/mindforge/llm-route.md +1 -1
  165. package/.claude/commands/mindforge/load-test.md +1 -1
  166. package/.claude/commands/mindforge/logistics.md +1 -1
  167. package/.claude/commands/mindforge/map-codebase.md +1 -1
  168. package/.claude/commands/mindforge/marketplace.md +1 -1
  169. package/.claude/commands/mindforge/meeting-design.md +1 -1
  170. package/.claude/commands/mindforge/metrics.md +1 -1
  171. package/.claude/commands/mindforge/migrate.md +1 -1
  172. package/.claude/commands/mindforge/migration-mgmt.md +1 -1
  173. package/.claude/commands/mindforge/milestone.md +1 -1
  174. package/.claude/commands/mindforge/mobile.md +1 -1
  175. package/.claude/commands/mindforge/monorepo.md +1 -1
  176. package/.claude/commands/mindforge/multi-tenant.md +1 -1
  177. package/.claude/commands/mindforge/multimodal.md +1 -1
  178. package/.claude/commands/mindforge/new-runtime.md +1 -1
  179. package/.claude/commands/mindforge/next.md +1 -1
  180. package/.claude/commands/mindforge/note.md +2 -2
  181. package/.claude/commands/mindforge/observability-platform.md +1 -1
  182. package/.claude/commands/mindforge/offline.md +1 -1
  183. package/.claude/commands/mindforge/onboard.md +1 -1
  184. package/.claude/commands/mindforge/orch-add-feature.md +43 -0
  185. package/.claude/commands/mindforge/orch-build-mvp.md +48 -0
  186. package/.claude/commands/mindforge/orch-change-feature.md +45 -0
  187. package/.claude/commands/mindforge/orch-fix-defect.md +43 -0
  188. package/.claude/commands/mindforge/orch-refine-code.md +43 -0
  189. package/.claude/commands/mindforge/plan-phase.md +1 -1
  190. package/.claude/commands/mindforge/plan-write.md +11 -0
  191. package/.claude/commands/mindforge/plant-seed.md +2 -2
  192. package/.claude/commands/mindforge/platform.md +1 -1
  193. package/.claude/commands/mindforge/plugins.md +1 -1
  194. package/.claude/commands/mindforge/pr-review.md +1 -1
  195. package/.claude/commands/mindforge/privacy-eng.md +1 -1
  196. package/.claude/commands/mindforge/product-spec.md +76 -0
  197. package/.claude/commands/mindforge/profile-team.md +1 -1
  198. package/.claude/commands/mindforge/publish-skill.md +1 -1
  199. package/.claude/commands/mindforge/push-notify.md +1 -1
  200. package/.claude/commands/mindforge/pwa.md +1 -1
  201. package/.claude/commands/mindforge/qa.md +1 -1
  202. package/.claude/commands/mindforge/quality-audit.md +1 -1
  203. package/.claude/commands/mindforge/queue.md +1 -1
  204. package/.claude/commands/mindforge/quick.md +1 -1
  205. package/.claude/commands/mindforge/rag.md +1 -1
  206. package/.claude/commands/mindforge/rate-limit.md +1 -1
  207. package/.claude/commands/mindforge/react-native.md +1 -1
  208. package/.claude/commands/mindforge/realtime-analytics.md +1 -1
  209. package/.claude/commands/mindforge/record-learning.md +1 -1
  210. package/.claude/commands/mindforge/release.md +1 -1
  211. package/.claude/commands/mindforge/remember.md +1 -1
  212. package/.claude/commands/mindforge/research.md +1 -1
  213. package/.claude/commands/mindforge/retrospective.md +1 -1
  214. package/.claude/commands/mindforge/review-backlog.md +2 -2
  215. package/.claude/commands/mindforge/review.md +1 -1
  216. package/.claude/commands/mindforge/rfc.md +1 -1
  217. package/.claude/commands/mindforge/santa.md +1 -1
  218. package/.claude/commands/mindforge/secrets-mgmt.md +1 -1
  219. package/.claude/commands/mindforge/secrets.md +1 -1
  220. package/.claude/commands/mindforge/security-scan.md +1 -1
  221. package/.claude/commands/mindforge/serverless.md +1 -1
  222. package/.claude/commands/mindforge/session-report.md +2 -2
  223. package/.claude/commands/mindforge/ship.md +1 -1
  224. package/.claude/commands/mindforge/skills.md +1 -1
  225. package/.claude/commands/mindforge/status.md +1 -1
  226. package/.claude/commands/mindforge/steer.md +1 -1
  227. package/.claude/commands/mindforge/stream.md +1 -1
  228. package/.claude/commands/mindforge/sync-confluence.md +1 -1
  229. package/.claude/commands/mindforge/sync-jira.md +1 -1
  230. package/.claude/commands/mindforge/tech-debt.md +1 -1
  231. package/.claude/commands/mindforge/threat-model.md +1 -1
  232. package/.claude/commands/mindforge/tokens.md +1 -1
  233. package/.claude/commands/mindforge/ui-phase.md +2 -2
  234. package/.claude/commands/mindforge/ui-review.md +2 -2
  235. package/.claude/commands/mindforge/update.md +1 -1
  236. package/.claude/commands/mindforge/validate-phase.md +2 -2
  237. package/.claude/commands/mindforge/verify-loop.md +1 -1
  238. package/.claude/commands/mindforge/verify-phase.md +1 -1
  239. package/.claude/commands/mindforge/vibe-check.md +1 -1
  240. package/.claude/commands/mindforge/workspace.md +1 -1
  241. package/.claude/commands/mindforge/workstreams.md +2 -2
  242. package/.claude/commands/mindforge/zero-trust.md +1 -1
  243. package/.mindforge/config.json +2 -2
  244. package/.mindforge/engine/instincts/instinct-schema.md +17 -9
  245. package/.mindforge/imported-agents.jsonl +10 -0
  246. package/.mindforge/manifests/install-components.json +36 -0
  247. package/.mindforge/manifests/install-modules.json +193 -0
  248. package/.mindforge/manifests/install-profiles.json +57 -0
  249. package/.mindforge/memory/sync-manifest.json +1 -1
  250. package/.mindforge/personas/gan-evaluator.md +226 -0
  251. package/.mindforge/personas/gan-generator.md +151 -0
  252. package/.mindforge/personas/gan-planner.md +118 -0
  253. package/.mindforge/personas/harness-optimizer.md +55 -0
  254. package/.mindforge/personas/loop-operator.md +58 -0
  255. package/.mindforge/schemas/hooks.schema.json +199 -0
  256. package/.mindforge/schemas/install-modules.schema.json +44 -0
  257. package/.mindforge/schemas/install-state.schema.json +95 -0
  258. package/.mindforge/schemas/plugin.schema.json +75 -0
  259. package/.mindforge/schemas/provenance.schema.json +31 -0
  260. package/.mindforge/skills/agent-architecture-audit/SKILL.md +272 -0
  261. package/.mindforge/skills/continuous-learning/SKILL.md +16 -0
  262. package/.mindforge/skills/orch-pipeline/SKILL.md +284 -0
  263. package/.mindforge/skills/writing-plans/SKILL.md +76 -0
  264. package/CHANGELOG.md +111 -0
  265. package/MINDFORGE.md +3 -3
  266. package/README.md +25 -3
  267. package/RELEASENOTES.md +131 -1
  268. package/SECURITY.md +16 -0
  269. package/bin/autonomous/auto-runner.js +46 -5
  270. package/bin/autonomous/handoff-schema.js +114 -0
  271. package/bin/autonomous/session-guardian.sh +138 -0
  272. package/bin/autonomous/supervisor.js +98 -0
  273. package/bin/change-classifier.js +19 -5
  274. package/bin/governance/approve.js +61 -28
  275. package/bin/governance/config-manager.js +3 -1
  276. package/bin/governance/rbac-manager.js +14 -6
  277. package/bin/harness-audit.js +520 -0
  278. package/bin/hooks/instinct-capture-hook.js +16 -1
  279. package/bin/hooks/lib/detect-project.js +72 -0
  280. package/bin/installer/harness-adapter-compliance.js +321 -0
  281. package/bin/installer/install-manifests.js +200 -0
  282. package/bin/installer/install-state.js +243 -0
  283. package/bin/installer-core.js +1 -1
  284. package/bin/learning/instinct-cli.js +359 -0
  285. package/bin/learning/lib/ssrf-guard.js +252 -0
  286. package/bin/memory/eis-client.js +31 -10
  287. package/bin/models/llm-errors.js +79 -0
  288. package/bin/models/model-client.js +39 -4
  289. package/bin/models/ollama-provider.js +115 -0
  290. package/bin/models/openai-provider.js +40 -9
  291. package/bin/models/profiles-loader.js +147 -0
  292. package/bin/models/provider-registry.js +59 -0
  293. package/bin/revops/market-evaluator.js +23 -2
  294. package/bin/revops/router-steering-v2.js +17 -2
  295. package/bin/security/trust-boundaries.js +15 -3
  296. package/bin/utils/readiness-gate.js +169 -0
  297. package/bin/worktree/engine.js +497 -0
  298. package/docs/getting-started.md +1 -1
  299. package/docs/troubleshooting.md +1 -1
  300. package/docs/user-guide.md +1 -1
  301. package/package.json +8 -2
  302. package/subagents/categories/01-core-development/.claude-plugin/plugin.json +2 -2
  303. package/subagents/categories/01-core-development/api-designer-cc.md +1 -1
  304. package/subagents/categories/01-core-development/backend-developer.md +1 -1
  305. package/subagents/categories/01-core-development/design-bridge.md +1 -1
  306. package/subagents/categories/01-core-development/electron-pro.md +1 -1
  307. package/subagents/categories/01-core-development/frontend-developer.md +1 -1
  308. package/subagents/categories/01-core-development/fullstack-developer.md +1 -1
  309. package/subagents/categories/01-core-development/graphql-architect.md +1 -1
  310. package/subagents/categories/01-core-development/microservices-architect.md +1 -1
  311. package/subagents/categories/01-core-development/mobile-developer.md +1 -1
  312. package/subagents/categories/01-core-development/ui-designer.md +1 -1
  313. package/subagents/categories/01-core-development/websocket-engineer.md +1 -1
  314. package/subagents/categories/02-language-specialists/.claude-plugin/plugin.json +2 -2
  315. package/subagents/categories/02-language-specialists/angular-architect.md +1 -1
  316. package/subagents/categories/02-language-specialists/cpp-pro.md +1 -1
  317. package/subagents/categories/02-language-specialists/csharp-developer.md +1 -1
  318. package/subagents/categories/02-language-specialists/django-developer.md +1 -1
  319. package/subagents/categories/02-language-specialists/dotnet-core-expert.md +1 -1
  320. package/subagents/categories/02-language-specialists/dotnet-framework-48-expert.md +1 -1
  321. package/subagents/categories/02-language-specialists/elixir-expert.md +1 -1
  322. package/subagents/categories/02-language-specialists/expo-react-native-expert.md +1 -1
  323. package/subagents/categories/02-language-specialists/fastapi-developer.md +1 -1
  324. package/subagents/categories/02-language-specialists/flutter-expert.md +1 -1
  325. package/subagents/categories/02-language-specialists/golang-pro.md +1 -1
  326. package/subagents/categories/02-language-specialists/java-architect.md +1 -1
  327. package/subagents/categories/02-language-specialists/javascript-pro.md +1 -1
  328. package/subagents/categories/02-language-specialists/kotlin-specialist.md +1 -1
  329. package/subagents/categories/02-language-specialists/laravel-specialist.md +1 -1
  330. package/subagents/categories/02-language-specialists/nextjs-developer.md +1 -1
  331. package/subagents/categories/02-language-specialists/node-specialist.md +1 -1
  332. package/subagents/categories/02-language-specialists/php-pro.md +1 -1
  333. package/subagents/categories/02-language-specialists/powershell-51-expert.md +1 -1
  334. package/subagents/categories/02-language-specialists/powershell-7-expert.md +1 -1
  335. package/subagents/categories/02-language-specialists/python-pro.md +1 -1
  336. package/subagents/categories/02-language-specialists/rails-expert.md +1 -1
  337. package/subagents/categories/02-language-specialists/react-specialist-cc.md +1 -1
  338. package/subagents/categories/02-language-specialists/rust-engineer.md +1 -1
  339. package/subagents/categories/02-language-specialists/spring-boot-engineer.md +1 -1
  340. package/subagents/categories/02-language-specialists/sql-pro.md +1 -1
  341. package/subagents/categories/02-language-specialists/swift-expert.md +1 -1
  342. package/subagents/categories/02-language-specialists/symfony-specialist.md +1 -1
  343. package/subagents/categories/02-language-specialists/typescript-pro.md +1 -1
  344. package/subagents/categories/02-language-specialists/vue-expert.md +1 -1
  345. package/subagents/categories/03-infrastructure/.claude-plugin/plugin.json +5 -5
  346. package/subagents/categories/03-infrastructure/azure-infra-engineer.md +1 -1
  347. package/subagents/categories/03-infrastructure/cloud-architect-cc.md +1 -1
  348. package/subagents/categories/03-infrastructure/database-administrator.md +1 -1
  349. package/subagents/categories/03-infrastructure/deployment-engineer.md +1 -1
  350. package/subagents/categories/03-infrastructure/devops-engineer-cc.md +1 -1
  351. package/subagents/categories/03-infrastructure/devops-incident-responder.md +1 -1
  352. package/subagents/categories/03-infrastructure/docker-expert.md +1 -1
  353. package/subagents/categories/03-infrastructure/incident-responder.md +1 -1
  354. package/subagents/categories/03-infrastructure/kubernetes-specialist.md +1 -1
  355. package/subagents/categories/03-infrastructure/network-engineer.md +1 -1
  356. package/subagents/categories/03-infrastructure/platform-engineer-cc.md +1 -1
  357. package/subagents/categories/03-infrastructure/security-engineer.md +1 -1
  358. package/subagents/categories/03-infrastructure/sre-engineer.md +1 -1
  359. package/subagents/categories/03-infrastructure/terraform-engineer.md +1 -1
  360. package/subagents/categories/03-infrastructure/terragrunt-expert.md +2 -2
  361. package/subagents/categories/03-infrastructure/windows-infra-admin.md +1 -1
  362. package/subagents/categories/04-quality-security/.claude-plugin/plugin.json +15 -5
  363. package/subagents/categories/04-quality-security/accessibility-tester-cc.md +1 -1
  364. package/subagents/categories/04-quality-security/ad-security-reviewer.md +1 -1
  365. package/subagents/categories/04-quality-security/ai-writing-auditor.md +1 -1
  366. package/subagents/categories/04-quality-security/architect-reviewer.md +1 -1
  367. package/subagents/categories/04-quality-security/chaos-engineer-cc.md +1 -1
  368. package/subagents/categories/04-quality-security/code-reviewer.md +1 -1
  369. package/subagents/categories/04-quality-security/compliance-auditor-cc.md +1 -1
  370. package/subagents/categories/04-quality-security/debugger-cc.md +1 -1
  371. package/subagents/categories/04-quality-security/error-detective.md +1 -1
  372. package/subagents/categories/04-quality-security/gdpr-ccpa-compliance.md +2 -2
  373. package/subagents/categories/04-quality-security/go-build-resolver.md +105 -0
  374. package/subagents/categories/04-quality-security/go-reviewer.md +87 -0
  375. package/subagents/categories/04-quality-security/penetration-tester.md +1 -1
  376. package/subagents/categories/04-quality-security/performance-engineer.md +1 -1
  377. package/subagents/categories/04-quality-security/powershell-security-hardening.md +1 -1
  378. package/subagents/categories/04-quality-security/python-reviewer.md +109 -0
  379. package/subagents/categories/04-quality-security/qa-expert.md +1 -1
  380. package/subagents/categories/04-quality-security/react-build-resolver.md +215 -0
  381. package/subagents/categories/04-quality-security/react-reviewer.md +167 -0
  382. package/subagents/categories/04-quality-security/rust-build-resolver.md +159 -0
  383. package/subagents/categories/04-quality-security/rust-reviewer.md +105 -0
  384. package/subagents/categories/04-quality-security/security-auditor.md +1 -1
  385. package/subagents/categories/04-quality-security/silent-failure-hunter.md +67 -0
  386. package/subagents/categories/04-quality-security/test-automator.md +1 -1
  387. package/subagents/categories/04-quality-security/type-design-analyzer.md +58 -0
  388. package/subagents/categories/04-quality-security/typescript-reviewer.md +126 -0
  389. package/subagents/categories/04-quality-security/ui-ux-tester.md +1 -1
  390. package/subagents/categories/05-data-ai/.claude-plugin/plugin.json +4 -4
  391. package/subagents/categories/05-data-ai/ai-engineer.md +1 -1
  392. package/subagents/categories/05-data-ai/data-analyst.md +1 -1
  393. package/subagents/categories/05-data-ai/data-engineer-cc.md +1 -1
  394. package/subagents/categories/05-data-ai/data-scientist.md +1 -1
  395. package/subagents/categories/05-data-ai/database-optimizer.md +1 -1
  396. package/subagents/categories/05-data-ai/llm-architect.md +1 -1
  397. package/subagents/categories/05-data-ai/machine-learning-engineer.md +1 -1
  398. package/subagents/categories/05-data-ai/ml-engineer-cc.md +1 -1
  399. package/subagents/categories/05-data-ai/mlops-engineer.md +1 -1
  400. package/subagents/categories/05-data-ai/nlp-engineer.md +1 -1
  401. package/subagents/categories/05-data-ai/postgres-pro.md +1 -1
  402. package/subagents/categories/05-data-ai/prompt-engineer-cc.md +1 -1
  403. package/subagents/categories/05-data-ai/reinforcement-learning-engineer.md +1 -1
  404. package/subagents/categories/06-developer-experience/.claude-plugin/plugin.json +2 -2
  405. package/subagents/categories/06-developer-experience/build-engineer-cc.md +1 -1
  406. package/subagents/categories/06-developer-experience/cli-developer.md +1 -1
  407. package/subagents/categories/06-developer-experience/dependency-manager.md +1 -1
  408. package/subagents/categories/06-developer-experience/documentation-engineer.md +1 -1
  409. package/subagents/categories/06-developer-experience/dx-optimizer.md +1 -1
  410. package/subagents/categories/06-developer-experience/git-workflow-manager.md +1 -1
  411. package/subagents/categories/06-developer-experience/legacy-modernizer.md +1 -1
  412. package/subagents/categories/06-developer-experience/mcp-developer.md +1 -1
  413. package/subagents/categories/06-developer-experience/powershell-module-architect.md +1 -1
  414. package/subagents/categories/06-developer-experience/powershell-ui-architect.md +1 -1
  415. package/subagents/categories/06-developer-experience/readme-generator.md +1 -1
  416. package/subagents/categories/06-developer-experience/refactoring-specialist.md +1 -1
  417. package/subagents/categories/06-developer-experience/slack-expert.md +1 -1
  418. package/subagents/categories/06-developer-experience/tooling-engineer.md +1 -1
  419. package/subagents/categories/06-developer-experience/visual-asset-generator.md +1 -1
  420. package/subagents/categories/07-specialized-domains/.claude-plugin/plugin.json +2 -2
  421. package/subagents/categories/07-specialized-domains/api-documenter.md +1 -1
  422. package/subagents/categories/07-specialized-domains/blockchain-developer.md +1 -1
  423. package/subagents/categories/07-specialized-domains/embedded-systems.md +1 -1
  424. package/subagents/categories/07-specialized-domains/fintech-engineer.md +1 -1
  425. package/subagents/categories/07-specialized-domains/game-developer.md +1 -1
  426. package/subagents/categories/07-specialized-domains/healthcare-admin.md +1 -1
  427. package/subagents/categories/07-specialized-domains/hipaa-compliance.md +2 -2
  428. package/subagents/categories/07-specialized-domains/iot-engineer.md +1 -1
  429. package/subagents/categories/07-specialized-domains/m365-admin.md +1 -1
  430. package/subagents/categories/07-specialized-domains/mobile-app-developer.md +1 -1
  431. package/subagents/categories/07-specialized-domains/payment-integration.md +1 -1
  432. package/subagents/categories/07-specialized-domains/quant-analyst.md +1 -1
  433. package/subagents/categories/07-specialized-domains/risk-manager.md +1 -1
  434. package/subagents/categories/07-specialized-domains/seo-specialist-cc.md +1 -1
  435. package/subagents/categories/08-business-product/.claude-plugin/plugin.json +3 -3
  436. package/subagents/categories/08-business-product/assumption-mapping.md +2 -2
  437. package/subagents/categories/08-business-product/backlog-grooming.md +2 -2
  438. package/subagents/categories/08-business-product/business-analyst-cc.md +1 -1
  439. package/subagents/categories/08-business-product/content-marketer.md +1 -1
  440. package/subagents/categories/08-business-product/content-quality-editor.md +1 -1
  441. package/subagents/categories/08-business-product/customer-success-manager.md +1 -1
  442. package/subagents/categories/08-business-product/growth-loops.md +2 -2
  443. package/subagents/categories/08-business-product/legal-advisor.md +1 -1
  444. package/subagents/categories/08-business-product/license-engineer.md +1 -1
  445. package/subagents/categories/08-business-product/product-manager-cc.md +1 -1
  446. package/subagents/categories/08-business-product/project-manager.md +1 -1
  447. package/subagents/categories/08-business-product/sales-engineer.md +1 -1
  448. package/subagents/categories/08-business-product/scrum-master.md +1 -1
  449. package/subagents/categories/08-business-product/technical-writer.md +1 -1
  450. package/subagents/categories/08-business-product/ux-researcher.md +1 -1
  451. package/subagents/categories/08-business-product/wordpress-master.md +1 -1
  452. package/subagents/categories/09-meta-orchestration/.claude-plugin/plugin.json +1 -1
  453. package/subagents/categories/09-meta-orchestration/agent-installer.md +1 -1
  454. package/subagents/categories/09-meta-orchestration/agent-organizer.md +1 -1
  455. package/subagents/categories/09-meta-orchestration/codebase-orchestrator.md +1 -1
  456. package/subagents/categories/09-meta-orchestration/context-manager.md +1 -1
  457. package/subagents/categories/09-meta-orchestration/error-coordinator.md +1 -1
  458. package/subagents/categories/09-meta-orchestration/it-ops-orchestrator.md +1 -1
  459. package/subagents/categories/09-meta-orchestration/knowledge-synthesizer.md +1 -1
  460. package/subagents/categories/09-meta-orchestration/multi-agent-coordinator.md +1 -1
  461. package/subagents/categories/09-meta-orchestration/performance-monitor.md +1 -1
  462. package/subagents/categories/09-meta-orchestration/task-distributor.md +1 -1
  463. package/subagents/categories/09-meta-orchestration/workflow-orchestrator.md +1 -1
  464. package/subagents/categories/10-research-analysis/.claude-plugin/plugin.json +1 -1
  465. package/subagents/categories/10-research-analysis/ab-test-analysis.md +2 -2
  466. package/subagents/categories/10-research-analysis/cohort-analysis.md +2 -2
  467. package/subagents/categories/10-research-analysis/competitive-analyst.md +1 -1
  468. package/subagents/categories/10-research-analysis/data-researcher.md +1 -1
  469. package/subagents/categories/10-research-analysis/first-principles-thinking.md +2 -2
  470. package/subagents/categories/10-research-analysis/market-researcher.md +1 -1
  471. package/subagents/categories/10-research-analysis/project-idea-validator.md +1 -1
  472. package/subagents/categories/10-research-analysis/research-analyst.md +1 -1
  473. package/subagents/categories/10-research-analysis/scientific-literature-researcher.md +1 -1
  474. package/subagents/categories/10-research-analysis/search-specialist.md +1 -1
  475. package/subagents/categories/10-research-analysis/trend-analyst.md +1 -1
@@ -0,0 +1,252 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * MindForge — SSRF + path-traversal + id-validation guards for instinct import.
5
+ *
6
+ * Ported from ECC's instinct-cli.py (_validate_import_url / _fetch_import_url /
7
+ * _validate_file_path / _validate_instinct_id). Node has no stdlib IP
8
+ * classification (Python used `ipaddress`), so isPublicAddress is hand-written
9
+ * to cover IPv4 + IPv6 private/loopback/link-local/multicast/reserved/
10
+ * unspecified, INCLUDING IPv4-mapped IPv6 (::ffff:x) and IPv6 ULA/link-local.
11
+ *
12
+ * Layer-3 hardening OVER the donor: 3xx redirects are REJECTED (the donor's
13
+ * urlopen followed them, so an allowed host could 302 to a private one).
14
+ */
15
+
16
+ const dns = require('dns').promises;
17
+ const https = require('https');
18
+ const net = require('net');
19
+ const path = require('path');
20
+ const fs = require('fs');
21
+
22
+ const DEFAULT_MAX_BYTES = 2 * 1024 * 1024; // 2 MB
23
+ const DEFAULT_TIMEOUT_MS = 15000;
24
+
25
+ // A remote instinct import is plain HTTPS, so only the standard HTTPS port is
26
+ // meaningful. Allowing an explicit non-standard port would let an allowed
27
+ // public host be used to reach an internal service co-located on it
28
+ // (e.g. https://public-host:6379/) — the destination port is otherwise carried
29
+ // through unchecked. An empty port means the URL uses the https default (443).
30
+ const ALLOWED_IMPORT_PORTS = new Set(['', '443']);
31
+
32
+ // System dirs an import/export path must never target (port of the py list;
33
+ // macOS resolves /etc -> /private/etc, so both forms are blocked).
34
+ const BLOCKED_PREFIXES = [
35
+ '/etc', '/usr', '/bin', '/sbin', '/proc', '/sys',
36
+ '/var/log', '/var/run', '/var/lib', '/var/spool',
37
+ '/private/etc', '/private/var/log', '/private/var/run', '/private/var/db',
38
+ ];
39
+
40
+ /**
41
+ * True if `ip` is a public, routable address (NOT private/loopback/link-local/
42
+ * multicast/reserved/unspecified). Handles IPv4, IPv6, and IPv4-mapped IPv6.
43
+ */
44
+ function isPublicAddress(ip) {
45
+ const v = net.isIP(ip);
46
+ if (v === 4) return isPublicV4(ip);
47
+ if (v === 6) {
48
+ // Unwrap IPv4-mapped IPv6 (::ffff:127.0.0.1) and classify the V4 part.
49
+ const mapped = ip.match(/::ffff:(\d+\.\d+\.\d+\.\d+)$/i);
50
+ if (mapped) return isPublicV4(mapped[1]);
51
+ return isPublicV6(ip);
52
+ }
53
+ return false; // not a valid IP literal → treat as non-public (fail closed)
54
+ }
55
+
56
+ function isPublicV4(ip) {
57
+ const o = ip.split('.').map(Number);
58
+ if (o.length !== 4 || o.some(n => !Number.isInteger(n) || n < 0 || n > 255)) return false;
59
+ const [a, b] = o;
60
+ if (a === 10) return false; // 10/8 private
61
+ if (a === 172 && b >= 16 && b <= 31) return false; // 172.16/12 private
62
+ if (a === 192 && b === 168) return false; // 192.168/16 private
63
+ if (a === 127) return false; // 127/8 loopback
64
+ if (a === 169 && b === 254) return false; // 169.254/16 link-local
65
+ if (a === 0) return false; // 0.0.0.0/8 unspecified/reserved
66
+ if (a >= 224) return false; // 224/4 multicast + 240/4 reserved
67
+ if (a === 100 && b >= 64 && b <= 127) return false; // 100.64/10 CGNAT (treat as non-public)
68
+ return true;
69
+ }
70
+
71
+ function isPublicV6(ip) {
72
+ const lower = ip.toLowerCase();
73
+ if (lower === '::1') return false; // loopback
74
+ if (lower === '::') return false; // unspecified
75
+ // Classify by the FIRST 16-bit hextet as a NUMBER, not a string prefix.
76
+ // String prefixes silently miss sub-ranges: e.g. fe80::/10 spans fe80-febf,
77
+ // and `startsWith('fe9'|'fea'|'feb')` left fe81-fe8f (fe8x) reachable as
78
+ // "public" — an SSRF hole. Numeric masks check the actual bit ranges.
79
+ const firstHextet = lower.startsWith('::') ? 0 : parseInt(lower.split(':')[0] || '0', 16);
80
+ if (Number.isNaN(firstHextet)) return false; // unparseable → fail closed
81
+ if ((firstHextet & 0xffc0) === 0xfe80) return false; // fe80::/10 link-local (fe80-febf)
82
+ if ((firstHextet & 0xffc0) === 0xfec0) return false; // fec0::/10 site-local (deprecated, non-routable)
83
+ if ((firstHextet & 0xfe00) === 0xfc00) return false; // fc00::/7 unique-local (fc00-fdff)
84
+ if ((firstHextet & 0xff00) === 0xff00) return false; // ff00::/8 multicast
85
+ return true;
86
+ }
87
+
88
+ /**
89
+ * Validate a remote import URL: https only, resolvable hostname, and EVERY
90
+ * resolved address must be public. Returns the normalized URL string.
91
+ */
92
+ async function validateImportUrl(source) {
93
+ let parsed;
94
+ try {
95
+ parsed = new URL(source);
96
+ } catch {
97
+ throw new Error('invalid import URL');
98
+ }
99
+ if (parsed.protocol !== 'https:') {
100
+ throw new Error('remote instinct imports require https URLs');
101
+ }
102
+ if (!parsed.hostname) {
103
+ throw new Error('remote import URL is missing a hostname');
104
+ }
105
+ // Port allowlist: only the standard HTTPS port (or none) is permitted. This
106
+ // blocks using an allowed public host to reach an internal service port
107
+ // (6379/27017/8080/...) without maintaining a per-service blocklist.
108
+ if (!ALLOWED_IMPORT_PORTS.has(parsed.port)) {
109
+ throw new Error(`remote import port not allowed: ${parsed.port} (only the standard https port is permitted)`);
110
+ }
111
+
112
+ let addrs;
113
+ try {
114
+ addrs = await dns.lookup(parsed.hostname, { all: true });
115
+ } catch {
116
+ throw new Error(`remote import host could not be resolved: ${parsed.hostname}`);
117
+ }
118
+ if (!addrs.length) {
119
+ throw new Error(`remote import host could not be resolved: ${parsed.hostname}`);
120
+ }
121
+ for (const { address } of addrs) {
122
+ if (!isPublicAddress(address)) {
123
+ throw new Error(`remote import host resolves to a non-public address: ${address}`);
124
+ }
125
+ }
126
+ return parsed.toString();
127
+ }
128
+
129
+ /**
130
+ * Fetch a validated remote instinct file with bounded size + timeout, an allowed
131
+ * Content-Type, and NO redirect following (3xx is rejected). Resolves the body.
132
+ */
133
+ async function fetchImportUrl(source, opts = {}) {
134
+ const maxBytes = opts.maxBytes || DEFAULT_MAX_BYTES;
135
+ const timeoutMs = opts.timeoutMs || DEFAULT_TIMEOUT_MS;
136
+ const url = await validateImportUrl(source);
137
+
138
+ return new Promise((resolve, reject) => {
139
+ const req = https.get(url, { headers: { 'User-Agent': 'MindForge-instinct-import/1' } }, res => {
140
+ const status = res.statusCode || 0;
141
+ if (status >= 300 && status < 400) {
142
+ res.destroy();
143
+ return reject(new Error(`remote import returned a ${status} redirect — refusing to follow (SSRF guard)`));
144
+ }
145
+ if (status !== 200) {
146
+ res.destroy();
147
+ return reject(new Error(`remote import failed with status ${status}`));
148
+ }
149
+ const ctype = (res.headers['content-type'] || '').toLowerCase();
150
+ const allowed = ['text/', 'markdown', 'yaml', 'json', 'octet-stream'];
151
+ if (ctype && !allowed.some(a => ctype.includes(a))) {
152
+ res.destroy();
153
+ return reject(new Error(`unsupported remote content type: ${ctype}`));
154
+ }
155
+ let bytes = 0;
156
+ const chunks = [];
157
+ res.on('data', chunk => {
158
+ bytes += chunk.length;
159
+ if (bytes > maxBytes) {
160
+ res.destroy();
161
+ return reject(new Error(`remote import exceeds ${maxBytes} bytes`));
162
+ }
163
+ chunks.push(chunk);
164
+ });
165
+ res.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
166
+ });
167
+ req.setTimeout(timeoutMs, () => {
168
+ req.destroy();
169
+ reject(new Error(`remote import timed out after ${timeoutMs}ms`));
170
+ });
171
+ req.on('error', err => reject(new Error(`remote import failed: ${err.message}`)));
172
+ });
173
+ }
174
+
175
+ /**
176
+ * Resolve + validate a filesystem path, blocking system dirs (both import-from
177
+ * and export-to). Returns the resolved absolute path.
178
+ */
179
+ function validateFilePath(pathStr, { mustExist = false } = {}) {
180
+ if (typeof pathStr !== 'string' || !pathStr) {
181
+ throw new Error('path must be a non-empty string');
182
+ }
183
+ // expanduser
184
+ const expanded = pathStr.startsWith('~')
185
+ ? path.join(require('os').homedir(), pathStr.slice(1))
186
+ : pathStr;
187
+ const lexical = path.resolve(expanded);
188
+
189
+ // Canonicalize BEFORE the system-dir check. path.resolve() only normalizes
190
+ // lexically — it does NOT follow symlinks — so a symlink planted in a writable
191
+ // dir (e.g. /tmp/x -> /etc) would pass the prefix check while the subsequent
192
+ // fs.read/writeFileSync followed the link into a blocked dir. Resolve the real
193
+ // path so the check sees the actual on-disk target. Export targets may not
194
+ // exist yet, so fall back to realpath-ing the deepest existing ancestor and
195
+ // re-joining the not-yet-created tail (a symlinked ancestor is still caught).
196
+ const resolved = canonicalize(lexical);
197
+
198
+ for (const prefix of BLOCKED_PREFIXES) {
199
+ if (resolved === prefix || resolved.startsWith(prefix + path.sep)) {
200
+ throw new Error(`path '${resolved}' targets a system directory`);
201
+ }
202
+ }
203
+ if (mustExist && !fs.existsSync(resolved)) {
204
+ throw new Error(`path does not exist: ${resolved}`);
205
+ }
206
+ return resolved;
207
+ }
208
+
209
+ /**
210
+ * Resolve symlinks in an absolute path, tolerating a not-yet-created tail.
211
+ * Walks up to the deepest existing ancestor, realpath()s THAT (catching a
212
+ * symlinked parent), then re-appends the non-existent remainder.
213
+ */
214
+ function canonicalize(absPath) {
215
+ let existing = absPath;
216
+ const tail = [];
217
+ // Find the deepest ancestor that exists on disk.
218
+ while (!fs.existsSync(existing)) {
219
+ const parent = path.dirname(existing);
220
+ if (parent === existing) break; // reached filesystem root
221
+ tail.unshift(path.basename(existing));
222
+ existing = parent;
223
+ }
224
+ try {
225
+ const realExisting = fs.realpathSync(existing);
226
+ return tail.length ? path.join(realExisting, ...tail) : realExisting;
227
+ } catch {
228
+ return absPath; // realpath failed (race/permission) → fall back, fail closed downstream
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Validate an instinct id before using it anywhere id-sensitive.
234
+ */
235
+ function validateInstinctId(id) {
236
+ if (typeof id !== 'string' || !id || id.length > 128) return false;
237
+ if (id.includes('/') || id.includes('\\')) return false;
238
+ if (id.includes('..')) return false;
239
+ if (id.startsWith('.')) return false;
240
+ return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(id);
241
+ }
242
+
243
+ module.exports = {
244
+ DEFAULT_MAX_BYTES,
245
+ DEFAULT_TIMEOUT_MS,
246
+ BLOCKED_PREFIXES,
247
+ isPublicAddress,
248
+ validateImportUrl,
249
+ fetchImportUrl,
250
+ validateFilePath,
251
+ validateInstinctId,
252
+ };
@@ -150,20 +150,41 @@ class EISClient {
150
150
  }
151
151
 
152
152
  /**
153
- * [HARDEN] Generates a cryptographically signed auth header using the agent's DID.
154
- * This attaches OUTBOUND provenance to locally-originated requests (it signs
155
- * what this node sends). It does NOT verify the provenance of inbound remote
156
- * entries that is verifyRemoteProvenance's job, which fails closed unless a
157
- * signature is cryptographically verified against a resolvable public key.
153
+ * Lazily registers (once) this client's outbound node identity in the ZTAI
154
+ * trust registry and returns its DID. ZTAI is a SINGLETON instance (exported
155
+ * as `new ZTAIManager()`), so we call it directly never `new ZTAI()`. The
156
+ * DID is cached so every header from this client shares one resolvable key.
157
+ */
158
+ async _getNodeDid() {
159
+ if (!this._nodeDid) {
160
+ // Tier 3: the enclave provider signs with real Ed25519 (see ztai-manager).
161
+ this._nodeDid = await ZTAI.registerAgent(`eis-client:${this.orgId}`, 3);
162
+ }
163
+ return this._nodeDid;
164
+ }
165
+
166
+ /**
167
+ * [HARDEN] Generates a cryptographically signed auth header using this node's
168
+ * DID. Attaches OUTBOUND provenance to locally-originated requests (it signs
169
+ * what this node sends). It does NOT verify inbound remote entries — that is
170
+ * verifyRemoteProvenance's job, which fails closed unless a signature is
171
+ * cryptographically verified against a resolvable public key.
172
+ *
173
+ * FAIL-CLOSED: uses the real ZTAI API (registerAgent -> signData) and asserts
174
+ * the produced signature is a non-empty string. A signing failure THROWS
175
+ * rather than shipping a malformed `ZTAI-v5 <did>:` header with an empty sig.
158
176
  */
159
177
  async getAuthHeader(action, resource) {
160
- const manager = new ZTAI();
161
- const identity = manager.getIdentity();
178
+ const did = await this._getNodeDid();
162
179
  const payload = `${this.orgId}:${action}:${resource}:${Date.now()}`;
163
- const signature = manager.sign(payload);
164
-
180
+ const signature = await ZTAI.signData(did, payload);
181
+
182
+ if (typeof signature !== 'string' || signature.length === 0) {
183
+ throw new Error('EIS auth header signing failed: ZTAI produced an empty signature');
184
+ }
185
+
165
186
  return {
166
- 'Authorization': `ZTAI-v5 ${identity.did}:${signature}`,
187
+ 'Authorization': `ZTAI-v5 ${did}:${signature}`,
167
188
  'X-MF-Org': this.orgId,
168
189
  'X-MF-Timestamp': Date.now().toString()
169
190
  };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * MindForge — Typed cross-provider LLM error taxonomy.
3
+ *
4
+ * Adapted from ECC (src/llm/core/interface.py LLMError hierarchy). Named error
5
+ * classes carrying { provider, code, retryable } so the model-client fallback /
6
+ * circuit breaker can branch on error TYPE instead of a raw count:
7
+ * - ContextLengthError -> escalate to a larger-context model
8
+ * - AuthenticationError -> skip this provider permanently (bad/missing key)
9
+ * - RateLimitError -> circuit-break + back off, retryable
10
+ * - ModelNotFoundError -> skip the model, try fallback
11
+ *
12
+ * mapHttpStatus() turns a provider HTTP status into the right typed error so all
13
+ * providers classify failures consistently.
14
+ */
15
+ 'use strict';
16
+
17
+ class LLMError extends Error {
18
+ constructor(message, { provider = null, code = null, retryable = false, status = null } = {}) {
19
+ super(message);
20
+ this.name = this.constructor.name;
21
+ this.provider = provider;
22
+ this.code = code;
23
+ this.retryable = retryable;
24
+ this.status = status;
25
+ }
26
+ }
27
+
28
+ class AuthenticationError extends LLMError {
29
+ constructor(message, opts = {}) { super(message, { ...opts, retryable: false }); }
30
+ }
31
+ class RateLimitError extends LLMError {
32
+ constructor(message, opts = {}) { super(message, { ...opts, retryable: true }); }
33
+ }
34
+ class ContextLengthError extends LLMError {
35
+ constructor(message, opts = {}) { super(message, { ...opts, retryable: false }); }
36
+ }
37
+ class ModelNotFoundError extends LLMError {
38
+ constructor(message, opts = {}) { super(message, { ...opts, retryable: false }); }
39
+ }
40
+ class ServiceUnavailableError extends LLMError {
41
+ constructor(message, opts = {}) { super(message, { ...opts, retryable: true }); }
42
+ }
43
+
44
+ /**
45
+ * Classify a provider failure into a typed error. Prefers HTTP status, then
46
+ * falls back to string heuristics on the message (ECC astraflow.py approach) for
47
+ * providers that don't surface a clean status.
48
+ */
49
+ function classifyError(message, { provider = null, status = null } = {}) {
50
+ const msg = String(message || '');
51
+ const lower = msg.toLowerCase();
52
+
53
+ if (status === 401 || status === 403 || /\b401\b|\b403\b|unauthorized|invalid api key|authentication/.test(lower)) {
54
+ return new AuthenticationError(msg, { provider, code: 'auth', status });
55
+ }
56
+ if (status === 429 || /\b429\b|rate.?limit|too many requests/.test(lower)) {
57
+ return new RateLimitError(msg, { provider, code: 'rate_limit', status });
58
+ }
59
+ if (status === 404 || /\b404\b|model.*not.*found|no such model/.test(lower)) {
60
+ return new ModelNotFoundError(msg, { provider, code: 'model_not_found', status });
61
+ }
62
+ if (/context.*length|maximum context|context window|too long|token limit/.test(lower)) {
63
+ return new ContextLengthError(msg, { provider, code: 'context_length', status });
64
+ }
65
+ if (status === 503 || status === 502 || status === 408 || /\b50[23]\b|timeout|unavailable|connection/.test(lower)) {
66
+ return new ServiceUnavailableError(msg, { provider, code: 'unavailable', status });
67
+ }
68
+ return new LLMError(msg, { provider, code: 'unknown', status, retryable: false });
69
+ }
70
+
71
+ module.exports = {
72
+ LLMError,
73
+ AuthenticationError,
74
+ RateLimitError,
75
+ ContextLengthError,
76
+ ModelNotFoundError,
77
+ ServiceUnavailableError,
78
+ classifyError,
79
+ };
@@ -9,11 +9,17 @@ const CostTracker = require('./cost-tracker');
9
9
  const AnthropicProvider = require('./anthropic-provider');
10
10
  const OpenAIProvider = require('./openai-provider');
11
11
  const GeminiProvider = require('./gemini-provider');
12
-
13
- // v9: Fallback chains aligned to Claude 4.x family
12
+ const OllamaProvider = require('./ollama-provider');
13
+ const { resolveProvider } = require('./provider-registry');
14
+ const { LLMError } = require('./llm-errors');
15
+
16
+ // v9: Fallback chains aligned to Claude 4.x family.
17
+ // llama-3-70b-local is the sovereign last-resort — only reachable when
18
+ // OLLAMA_BASE_URL is set (see _getProvider); otherwise _getProvider returns
19
+ // null and the chain skips it, leaving cloud routing unchanged.
14
20
  const FALLBACK_CHAINS = {
15
21
  'claude-opus-4-7': ['claude-sonnet-4-6', 'gemini-2.5-pro'],
16
- 'claude-sonnet-4-6': ['claude-haiku-4-5', 'gemini-2.5-pro'],
22
+ 'claude-sonnet-4-6': ['claude-haiku-4-5', 'gemini-2.5-pro', 'llama-3-70b-local'],
17
23
  'gemini-2.5-pro': ['claude-sonnet-4-6'],
18
24
  };
19
25
 
@@ -72,10 +78,27 @@ class ModelClient {
72
78
 
73
79
  } catch (err) {
74
80
  const safeMsg = (err.message || '').replace(/sk-[a-zA-Z0-9_-]+/g, 'sk-***').replace(/key-[a-zA-Z0-9_-]+/g, 'key-***');
75
- process.stderr.write(`[model-client] ${currentModel} failed: ${safeMsg}\n`);
81
+ process.stderr.write(`[model-client] ${currentModel} failed (${err.name || 'Error'}/${err.code || 'unknown'}): ${safeMsg}\n`);
82
+
83
+ // Context-aware fallback: branch on the typed-error taxonomy instead of
84
+ // blindly trying the next model.
85
+ // - ContextLengthError: this model's window is too small — keep trying
86
+ // the chain (later entries may have larger context); don't abort.
87
+ // - AuthenticationError: the provider's key is bad/missing — trying it
88
+ // again is pointless, but other providers in the chain may work, so
89
+ // continue to the next attempt.
90
+ // - Otherwise: continue through the chain as before.
91
+ const isTyped = err instanceof LLMError;
92
+ const isAuth = isTyped && err.name === 'AuthenticationError';
93
+ if (isAuth) {
94
+ process.stderr.write(`[model-client] ${currentModel}: auth failure — skipping this provider for the rest of this call\n`);
95
+ }
96
+
76
97
  if (attempts.indexOf(currentModel) === attempts.length - 1) {
77
98
  const safeErr = new Error(safeMsg);
78
99
  safeErr.code = err.code;
100
+ safeErr.name = err.name;
101
+ safeErr.retryable = isTyped ? err.retryable : undefined;
79
102
  throw safeErr;
80
103
  }
81
104
  }
@@ -103,6 +126,12 @@ class ModelClient {
103
126
  }
104
127
 
105
128
  static _getProvider(modelId) {
129
+ // Consult the pluggable registry first (honors MINDFORGE_LLM_PROVIDER
130
+ // override for sovereignty/offline test isolation). Falls through to the
131
+ // built-in prefix routing when nothing is registered.
132
+ const registered = resolveProvider(modelId);
133
+ if (registered) return registered;
134
+
106
135
  if (modelId.startsWith('claude') || modelId.startsWith('anthropic.claude')) {
107
136
  if (!process.env.ANTHROPIC_API_KEY) return null;
108
137
  return new AnthropicProvider(process.env.ANTHROPIC_API_KEY);
@@ -115,6 +144,12 @@ class ModelClient {
115
144
  if (!process.env.GOOGLE_API_KEY) return null;
116
145
  return new GeminiProvider(process.env.GOOGLE_API_KEY);
117
146
  }
147
+ // Sovereign local models (e.g. llama-3-70b-local). Gated on OLLAMA_BASE_URL
148
+ // being explicitly set, so cloud routing is unchanged unless opted in.
149
+ if (modelId.includes('local') || modelId.includes('llama')) {
150
+ if (!process.env.OLLAMA_BASE_URL) return null;
151
+ return new OllamaProvider(process.env.OLLAMA_BASE_URL);
152
+ }
118
153
  return null;
119
154
  }
120
155
  }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * MindForge — Ollama / local-model Provider
3
+ *
4
+ * Adapted from ECC (src/llm/providers/ollama.py). Talks to a local Ollama
5
+ * server (default http://localhost:11434) so the sovereign `llama-3-70b-local`
6
+ * entry in revops.market_registry is actually reachable — previously a dead
7
+ * link the MIR cost-arbitrage math could pick but never execute.
8
+ *
9
+ * Mirrors AnthropicProvider.complete() return shape so it drops into
10
+ * model-client.js unchanged. GATED on OLLAMA_BASE_URL: model-client only
11
+ * constructs this provider when OLLAMA_BASE_URL is set, so cloud routing is
12
+ * unchanged unless the operator explicitly opts in.
13
+ */
14
+ 'use strict';
15
+
16
+ const http = require('http');
17
+ const { URL } = require('url');
18
+
19
+ class OllamaProvider {
20
+ constructor(baseUrl) {
21
+ this.baseUrl = baseUrl || process.env.OLLAMA_BASE_URL || 'http://localhost:11434';
22
+ }
23
+
24
+ async complete(params) {
25
+ const { model, systemPrompt, userMessage, temperature = 0.7 } = params;
26
+
27
+ const messages = [];
28
+ if (systemPrompt) messages.push({ role: 'system', content: systemPrompt });
29
+ messages.push({ role: 'user', content: userMessage });
30
+
31
+ const payload = JSON.stringify({
32
+ model,
33
+ messages,
34
+ stream: false,
35
+ options: temperature !== 1.0 ? { temperature } : undefined,
36
+ });
37
+
38
+ const url = new URL('/api/chat', this.baseUrl);
39
+
40
+ return new Promise((resolve, reject) => {
41
+ const req = http.request({
42
+ hostname: url.hostname,
43
+ port: url.port || 11434,
44
+ path: url.pathname,
45
+ method: 'POST',
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ 'Content-Length': Buffer.byteLength(payload),
49
+ },
50
+ timeout: 120_000,
51
+ }, res => {
52
+ let body = '';
53
+ res.on('data', chunk => body += chunk);
54
+ res.on('end', () => {
55
+ try {
56
+ if (res.statusCode !== 200) {
57
+ return reject(Object.assign(
58
+ new Error(`Ollama API error (${res.statusCode})`),
59
+ { status: res.statusCode }
60
+ ));
61
+ }
62
+ const json = JSON.parse(body);
63
+ const content = json.message?.content || '';
64
+
65
+ // Ollama reports token counts as prompt_eval_count / eval_count.
66
+ const inputTokens = json.prompt_eval_count || 0;
67
+ const outputTokens = json.eval_count || 0;
68
+
69
+ // Price via the registry id (e.g. llama-3-70b-local). Local models
70
+ // are effectively free, but we still record for MIR/ROI accounting.
71
+ let cost = 0;
72
+ try {
73
+ const { priceCall } = require('./pricing-registry');
74
+ cost = priceCall(model, { input_tokens: inputTokens, output_tokens: outputTokens });
75
+ } catch (_e) {
76
+ cost = 0;
77
+ }
78
+
79
+ resolve({
80
+ model,
81
+ content,
82
+ input_tokens: inputTokens,
83
+ output_tokens: outputTokens,
84
+ cost_usd: cost,
85
+ provider: 'ollama',
86
+ });
87
+ } catch (e) {
88
+ reject(new Error('Failed to parse Ollama response: ' + e.message));
89
+ }
90
+ });
91
+ });
92
+
93
+ req.on('error', err => {
94
+ // Connection refused = local server not running. Surface as a clear,
95
+ // retryable-by-fallback error rather than a cryptic ECONNREFUSED.
96
+ reject(Object.assign(
97
+ new Error(`Ollama connection failed (${this.baseUrl}): ${err.message}`),
98
+ { status: 503 }
99
+ ));
100
+ });
101
+ req.on('timeout', () => {
102
+ req.destroy();
103
+ reject(Object.assign(new Error('Ollama timeout'), { status: 408 }));
104
+ });
105
+ req.write(payload);
106
+ req.end();
107
+ });
108
+ }
109
+
110
+ validateConfig() {
111
+ return Boolean(this.baseUrl);
112
+ }
113
+ }
114
+
115
+ module.exports = OllamaProvider;
@@ -1,13 +1,36 @@
1
1
  /**
2
- * MindForge v2 — OpenAI Provider
2
+ * MindForge v2 — OpenAI-compatible Provider
3
+ *
4
+ * Wave 3 (3.6): parameterized for an arbitrary OpenAI-compatible base URL, so a
5
+ * single class backs OpenAI + Azure OpenAI + Together / Groq / OpenRouter / vLLM.
6
+ * baseUrl/apiKeyEnv are driven from an optional `base_url` field per model in
7
+ * revops.market_registry; default stays api.openai.com so existing behavior is
8
+ * unchanged. Errors are classified via the typed llm-errors taxonomy.
3
9
  */
4
10
  'use strict';
5
11
 
6
12
  const https = require('https');
13
+ const http = require('http');
14
+ const { URL } = require('url');
15
+ const { classifyError } = require('./llm-errors');
7
16
 
8
17
  class OpenAIProvider {
9
- constructor(apiKey) {
18
+ /**
19
+ * @param {string} apiKey
20
+ * @param {object} [opts]
21
+ * @param {string} [opts.baseUrl] e.g. "https://api.groq.com/openai/v1". Defaults
22
+ * to OpenAI. Accepts with or without a trailing /v1.
23
+ */
24
+ constructor(apiKey, opts = {}) {
10
25
  this.apiKey = apiKey;
26
+ this.baseUrl = opts.baseUrl || process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1';
27
+ }
28
+
29
+ _endpoint(pathSuffix) {
30
+ const base = this.baseUrl.replace(/\/+$/, '');
31
+ // Allow base with or without /v1; chat path is appended after the base.
32
+ const full = /\/v\d+$/.test(base) ? `${base}${pathSuffix}` : `${base}/v1${pathSuffix}`;
33
+ return new URL(full);
11
34
  }
12
35
 
13
36
  async complete(params) {
@@ -23,10 +46,14 @@ class OpenAIProvider {
23
46
  temperature,
24
47
  });
25
48
 
49
+ const url = this._endpoint('/chat/completions');
50
+ const transport = url.protocol === 'http:' ? http : https;
51
+
26
52
  return new Promise((resolve, reject) => {
27
- const req = https.request({
28
- hostname: 'api.openai.com',
29
- path: '/v1/chat/completions',
53
+ const req = transport.request({
54
+ hostname: url.hostname,
55
+ port: url.port || undefined,
56
+ path: url.pathname,
30
57
  method: 'POST',
31
58
  headers: {
32
59
  'Content-Type': 'application/json',
@@ -41,7 +68,7 @@ class OpenAIProvider {
41
68
  try {
42
69
  const json = JSON.parse(body);
43
70
  if (res.statusCode !== 200) {
44
- return reject(Object.assign(new Error(json.error?.message || 'OpenAI API error'), { status: res.statusCode }));
71
+ return reject(classifyError(json.error?.message || 'OpenAI API error', { provider: 'openai', status: res.statusCode }));
45
72
  }
46
73
 
47
74
  const inputTokens = json.usage.prompt_tokens;
@@ -88,10 +115,14 @@ class OpenAIProvider {
88
115
  stream: true,
89
116
  });
90
117
 
118
+ const url = this._endpoint('/chat/completions');
119
+ const transport = url.protocol === 'http:' ? http : https;
120
+
91
121
  return new Promise((resolve, reject) => {
92
- const req = https.request({
93
- hostname: 'api.openai.com',
94
- path: '/v1/chat/completions',
122
+ const req = transport.request({
123
+ hostname: url.hostname,
124
+ port: url.port || undefined,
125
+ path: url.pathname,
95
126
  method: 'POST',
96
127
  headers: {
97
128
  'Content-Type': 'application/json',