mindforge-cc 1.0.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 (324) hide show
  1. package/.agent/CLAUDE.md +462 -0
  2. package/.agent/forge/help.md +7 -0
  3. package/.agent/forge/init-project.md +32 -0
  4. package/.agent/forge/plan-phase.md +30 -0
  5. package/.agent/mindforge/approve.md +18 -0
  6. package/.agent/mindforge/audit.md +30 -0
  7. package/.agent/mindforge/benchmark.md +33 -0
  8. package/.agent/mindforge/complete-milestone.md +18 -0
  9. package/.agent/mindforge/debug.md +126 -0
  10. package/.agent/mindforge/discuss-phase.md +138 -0
  11. package/.agent/mindforge/execute-phase.md +165 -0
  12. package/.agent/mindforge/health.md +21 -0
  13. package/.agent/mindforge/help.md +23 -0
  14. package/.agent/mindforge/init-org.md +131 -0
  15. package/.agent/mindforge/init-project.md +155 -0
  16. package/.agent/mindforge/install-skill.md +15 -0
  17. package/.agent/mindforge/map-codebase.md +298 -0
  18. package/.agent/mindforge/metrics.md +22 -0
  19. package/.agent/mindforge/migrate.md +40 -0
  20. package/.agent/mindforge/milestone.md +12 -0
  21. package/.agent/mindforge/next.md +105 -0
  22. package/.agent/mindforge/plan-phase.md +125 -0
  23. package/.agent/mindforge/plugins.md +40 -0
  24. package/.agent/mindforge/pr-review.md +41 -0
  25. package/.agent/mindforge/profile-team.md +23 -0
  26. package/.agent/mindforge/publish-skill.md +19 -0
  27. package/.agent/mindforge/quick.md +135 -0
  28. package/.agent/mindforge/release.md +10 -0
  29. package/.agent/mindforge/retrospective.md +26 -0
  30. package/.agent/mindforge/review.md +157 -0
  31. package/.agent/mindforge/security-scan.md +233 -0
  32. package/.agent/mindforge/ship.md +100 -0
  33. package/.agent/mindforge/skills.md +141 -0
  34. package/.agent/mindforge/status.md +104 -0
  35. package/.agent/mindforge/sync-confluence.md +11 -0
  36. package/.agent/mindforge/sync-jira.md +12 -0
  37. package/.agent/mindforge/tokens.md +8 -0
  38. package/.agent/mindforge/update.md +42 -0
  39. package/.agent/mindforge/verify-phase.md +62 -0
  40. package/.agent/mindforge/workspace.md +29 -0
  41. package/.claude/CLAUDE.md +462 -0
  42. package/.claude/commands/forge/help.md +7 -0
  43. package/.claude/commands/forge/init-project.md +32 -0
  44. package/.claude/commands/forge/plan-phase.md +30 -0
  45. package/.claude/commands/mindforge/approve.md +18 -0
  46. package/.claude/commands/mindforge/audit.md +30 -0
  47. package/.claude/commands/mindforge/benchmark.md +33 -0
  48. package/.claude/commands/mindforge/complete-milestone.md +18 -0
  49. package/.claude/commands/mindforge/debug.md +126 -0
  50. package/.claude/commands/mindforge/discuss-phase.md +138 -0
  51. package/.claude/commands/mindforge/execute-phase.md +165 -0
  52. package/.claude/commands/mindforge/health.md +21 -0
  53. package/.claude/commands/mindforge/help.md +23 -0
  54. package/.claude/commands/mindforge/init-org.md +131 -0
  55. package/.claude/commands/mindforge/init-project.md +155 -0
  56. package/.claude/commands/mindforge/install-skill.md +15 -0
  57. package/.claude/commands/mindforge/map-codebase.md +298 -0
  58. package/.claude/commands/mindforge/metrics.md +22 -0
  59. package/.claude/commands/mindforge/migrate.md +40 -0
  60. package/.claude/commands/mindforge/milestone.md +12 -0
  61. package/.claude/commands/mindforge/next.md +105 -0
  62. package/.claude/commands/mindforge/plan-phase.md +125 -0
  63. package/.claude/commands/mindforge/plugins.md +40 -0
  64. package/.claude/commands/mindforge/pr-review.md +41 -0
  65. package/.claude/commands/mindforge/profile-team.md +23 -0
  66. package/.claude/commands/mindforge/publish-skill.md +19 -0
  67. package/.claude/commands/mindforge/quick.md +135 -0
  68. package/.claude/commands/mindforge/release.md +10 -0
  69. package/.claude/commands/mindforge/retrospective.md +26 -0
  70. package/.claude/commands/mindforge/review.md +157 -0
  71. package/.claude/commands/mindforge/security-scan.md +233 -0
  72. package/.claude/commands/mindforge/ship.md +100 -0
  73. package/.claude/commands/mindforge/skills.md +141 -0
  74. package/.claude/commands/mindforge/status.md +104 -0
  75. package/.claude/commands/mindforge/sync-confluence.md +11 -0
  76. package/.claude/commands/mindforge/sync-jira.md +12 -0
  77. package/.claude/commands/mindforge/tokens.md +8 -0
  78. package/.claude/commands/mindforge/update.md +42 -0
  79. package/.claude/commands/mindforge/verify-phase.md +62 -0
  80. package/.claude/commands/mindforge/workspace.md +29 -0
  81. package/.forge/org/CONVENTIONS.md +0 -0
  82. package/.forge/org/ORG.md +0 -0
  83. package/.forge/org/SECURITY.md +0 -0
  84. package/.forge/org/TOOLS.md +0 -0
  85. package/.forge/personas/analyst.md +0 -0
  86. package/.forge/personas/architect.md +0 -0
  87. package/.forge/personas/debug-specialist.md +0 -0
  88. package/.forge/personas/developer.md +26 -0
  89. package/.forge/personas/qa-engineer.md +0 -0
  90. package/.forge/personas/release-manager.md +0 -0
  91. package/.forge/personas/security-reviewer.md +33 -0
  92. package/.forge/personas/tech-writer.md +0 -0
  93. package/.forge/skills/api-design/SKILL.md +0 -0
  94. package/.forge/skills/code-quality/SKILL.md +0 -0
  95. package/.forge/skills/documentation/SKILL.md +0 -0
  96. package/.forge/skills/security-review/SKILL.md +23 -0
  97. package/.forge/skills/testing-standards/SKILL.md +27 -0
  98. package/.github/workflows/mindforge-ci.yml +224 -0
  99. package/.gitlab-ci-mindforge.yml +18 -0
  100. package/.mindforge/MINDFORGE-SCHEMA.json +165 -0
  101. package/.mindforge/audit/AUDIT-SCHEMA.md +451 -0
  102. package/.mindforge/ci/ci-config-schema.md +21 -0
  103. package/.mindforge/ci/ci-mode.md +179 -0
  104. package/.mindforge/ci/github-actions-adapter.md +224 -0
  105. package/.mindforge/ci/gitlab-ci-adapter.md +31 -0
  106. package/.mindforge/ci/jenkins-adapter.md +44 -0
  107. package/.mindforge/distribution/registry-client.md +166 -0
  108. package/.mindforge/distribution/registry-schema.md +96 -0
  109. package/.mindforge/distribution/skill-publisher.md +44 -0
  110. package/.mindforge/distribution/skill-validator.md +74 -0
  111. package/.mindforge/engine/compaction-protocol.md +182 -0
  112. package/.mindforge/engine/context-injector.md +128 -0
  113. package/.mindforge/engine/dependency-parser.md +113 -0
  114. package/.mindforge/engine/skills/conflict-resolver.md +69 -0
  115. package/.mindforge/engine/skills/loader.md +184 -0
  116. package/.mindforge/engine/skills/registry.md +98 -0
  117. package/.mindforge/engine/skills/versioning.md +75 -0
  118. package/.mindforge/engine/verification-pipeline.md +111 -0
  119. package/.mindforge/engine/wave-executor.md +235 -0
  120. package/.mindforge/governance/GOVERNANCE-CONFIG.md +17 -0
  121. package/.mindforge/governance/approval-workflow.md +37 -0
  122. package/.mindforge/governance/change-classifier.md +63 -0
  123. package/.mindforge/governance/compliance-gates.md +31 -0
  124. package/.mindforge/integrations/confluence.md +27 -0
  125. package/.mindforge/integrations/connection-manager.md +163 -0
  126. package/.mindforge/integrations/github.md +25 -0
  127. package/.mindforge/integrations/gitlab.md +13 -0
  128. package/.mindforge/integrations/jira.md +102 -0
  129. package/.mindforge/integrations/slack.md +41 -0
  130. package/.mindforge/intelligence/antipattern-detector.md +75 -0
  131. package/.mindforge/intelligence/difficulty-scorer.md +55 -0
  132. package/.mindforge/intelligence/health-engine.md +208 -0
  133. package/.mindforge/intelligence/skill-gap-analyser.md +40 -0
  134. package/.mindforge/intelligence/smart-compaction.md +71 -0
  135. package/.mindforge/metrics/METRICS-SCHEMA.md +42 -0
  136. package/.mindforge/metrics/quality-tracker.md +32 -0
  137. package/.mindforge/monorepo/cross-package-planner.md +114 -0
  138. package/.mindforge/monorepo/dependency-graph-builder.md +32 -0
  139. package/.mindforge/monorepo/workspace-detector.md +129 -0
  140. package/.mindforge/org/CONVENTIONS.md +62 -0
  141. package/.mindforge/org/ORG.md +51 -0
  142. package/.mindforge/org/SECURITY.md +50 -0
  143. package/.mindforge/org/TOOLS.md +53 -0
  144. package/.mindforge/org/integrations/INTEGRATIONS-CONFIG.md +58 -0
  145. package/.mindforge/org/skills/MANIFEST.md +38 -0
  146. package/.mindforge/personas/analyst.md +52 -0
  147. package/.mindforge/personas/architect.md +75 -0
  148. package/.mindforge/personas/debug-specialist.md +52 -0
  149. package/.mindforge/personas/developer.md +85 -0
  150. package/.mindforge/personas/overrides/README.md +85 -0
  151. package/.mindforge/personas/qa-engineer.md +61 -0
  152. package/.mindforge/personas/release-manager.md +76 -0
  153. package/.mindforge/personas/security-reviewer.md +91 -0
  154. package/.mindforge/personas/tech-writer.md +51 -0
  155. package/.mindforge/plugins/PLUGINS-MANIFEST.md +23 -0
  156. package/.mindforge/plugins/plugin-loader.md +93 -0
  157. package/.mindforge/plugins/plugin-registry.md +44 -0
  158. package/.mindforge/plugins/plugin-schema.md +68 -0
  159. package/.mindforge/pr-review/ai-reviewer.md +266 -0
  160. package/.mindforge/pr-review/finding-formatter.md +46 -0
  161. package/.mindforge/pr-review/review-prompt-templates.md +44 -0
  162. package/.mindforge/production/compatibility-layer.md +39 -0
  163. package/.mindforge/production/migration-engine.md +52 -0
  164. package/.mindforge/production/production-checklist.md +165 -0
  165. package/.mindforge/production/token-optimiser.md +68 -0
  166. package/.mindforge/skills/accessibility/SKILL.md +106 -0
  167. package/.mindforge/skills/api-design/SKILL.md +98 -0
  168. package/.mindforge/skills/code-quality/SKILL.md +88 -0
  169. package/.mindforge/skills/data-privacy/SKILL.md +126 -0
  170. package/.mindforge/skills/database-patterns/SKILL.md +192 -0
  171. package/.mindforge/skills/documentation/SKILL.md +91 -0
  172. package/.mindforge/skills/incident-response/SKILL.md +180 -0
  173. package/.mindforge/skills/performance/SKILL.md +120 -0
  174. package/.mindforge/skills/security-review/SKILL.md +83 -0
  175. package/.mindforge/skills/testing-standards/SKILL.md +97 -0
  176. package/.mindforge/team/TEAM-PROFILE.md +42 -0
  177. package/.mindforge/team/multi-handoff.md +23 -0
  178. package/.mindforge/team/profiles/README.md +13 -0
  179. package/.mindforge/team/session-merger.md +18 -0
  180. package/.planning/ARCHITECTURE.md +0 -0
  181. package/.planning/AUDIT.jsonl +0 -0
  182. package/.planning/HANDOFF.json +28 -0
  183. package/.planning/PROJECT.md +33 -0
  184. package/.planning/RELEASE-CHECKLIST.md +68 -0
  185. package/.planning/REQUIREMENTS.md +0 -0
  186. package/.planning/ROADMAP.md +0 -0
  187. package/.planning/STATE.md +31 -0
  188. package/.planning/approvals/.gitkeep +1 -0
  189. package/.planning/archive/.gitkeep +1 -0
  190. package/.planning/audit-archive/.gitkeep +1 -0
  191. package/.planning/decisions/.gitkeep +0 -0
  192. package/.planning/decisions/ADR-001-handoff-tracking.md +41 -0
  193. package/.planning/decisions/ADR-002-markdown-commands.md +46 -0
  194. package/.planning/decisions/ADR-003-skills-trigger-model.md +37 -0
  195. package/.planning/decisions/ADR-004-wave-parallelism-model.md +45 -0
  196. package/.planning/decisions/ADR-005-append-only-audit-log.md +51 -0
  197. package/.planning/decisions/ADR-006-tiered-skills-system.md +22 -0
  198. package/.planning/decisions/ADR-007-trigger-keyword-model.md +22 -0
  199. package/.planning/decisions/ADR-008-just-in-time-skill-loading.md +29 -0
  200. package/.planning/decisions/ADR-009-enterprise-integration-retry-policy.md +8 -0
  201. package/.planning/decisions/ADR-010-governance-tier-escalation.md +8 -0
  202. package/.planning/decisions/ADR-011-multi-developer-handoff-contract.md +8 -0
  203. package/.planning/decisions/ADR-012-intelligence-feedback-loops.md +19 -0
  204. package/.planning/decisions/ADR-013-mindforge-md-constitution.md +16 -0
  205. package/.planning/decisions/ADR-014-metrics-as-signals-not-evaluation.md +15 -0
  206. package/.planning/decisions/ADR-015-npm-based-skill-registry.md +26 -0
  207. package/.planning/decisions/ADR-016-ci-exit-code-0-on-timeout.md +27 -0
  208. package/.planning/decisions/ADR-017-sdk-localhost-only.md +28 -0
  209. package/.planning/decisions/ADR-018-installer-self-install-detection.md +15 -0
  210. package/.planning/decisions/ADR-019-self-update-scope-preservation.md +14 -0
  211. package/.planning/decisions/ADR-020-v1.0.0-stable-interface-contract.md +23 -0
  212. package/.planning/jira-sync.json +9 -0
  213. package/.planning/milestones/.gitkeep +1 -0
  214. package/.planning/phases/day1/REVIEW-DAY1.md +50 -0
  215. package/.planning/phases/day1/SECURITY-REVIEW-DAY1.md +15 -0
  216. package/.planning/phases/day2/REVIEW-DAY2.md +521 -0
  217. package/.planning/phases/day3/REVIEW-DAY3.md +234 -0
  218. package/.planning/slack-threads.json +6 -0
  219. package/CHANGELOG.md +175 -0
  220. package/LICENSE +21 -0
  221. package/MINDFORGE.md +76 -0
  222. package/README.md +182 -0
  223. package/RELEASENOTES.md +41 -0
  224. package/SECURITY.md +4 -0
  225. package/bin/install.js +120 -0
  226. package/bin/installer-core.js +292 -0
  227. package/bin/migrations/0.1.0-to-0.5.0.js +37 -0
  228. package/bin/migrations/0.5.0-to-0.6.0.js +17 -0
  229. package/bin/migrations/0.6.0-to-1.0.0.js +100 -0
  230. package/bin/migrations/migrate.js +151 -0
  231. package/bin/migrations/schema-versions.js +64 -0
  232. package/bin/updater/changelog-fetcher.js +62 -0
  233. package/bin/updater/self-update.js +169 -0
  234. package/bin/updater/version-comparator.js +68 -0
  235. package/bin/validate-config.js +92 -0
  236. package/bin/wizard/config-generator.js +112 -0
  237. package/bin/wizard/environment-detector.js +76 -0
  238. package/bin/wizard/setup-wizard.js +237 -0
  239. package/docs/Context/Master-Context.md +701 -0
  240. package/docs/architecture/README.md +35 -0
  241. package/docs/architecture/decision-records-index.md +26 -0
  242. package/docs/ci-cd-integration.md +30 -0
  243. package/docs/ci-quickstart.md +78 -0
  244. package/docs/commands-reference.md +11 -0
  245. package/docs/contributing/CONTRIBUTING.md +38 -0
  246. package/docs/contributing/plugin-authoring.md +50 -0
  247. package/docs/contributing/skill-authoring.md +41 -0
  248. package/docs/enterprise-setup.md +25 -0
  249. package/docs/faq.md +38 -0
  250. package/docs/getting-started.md +36 -0
  251. package/docs/governance-guide.md +23 -0
  252. package/docs/mindforge-md-reference.md +53 -0
  253. package/docs/monorepo-guide.md +26 -0
  254. package/docs/persona-customisation.md +56 -0
  255. package/docs/quick-verify.md +33 -0
  256. package/docs/reference/audit-events.md +53 -0
  257. package/docs/reference/commands.md +82 -0
  258. package/docs/reference/config-reference.md +64 -0
  259. package/docs/reference/sdk-api.md +48 -0
  260. package/docs/reference/skills-api.md +57 -0
  261. package/docs/release-checklist-guide.md +37 -0
  262. package/docs/requirements.md +29 -0
  263. package/docs/sdk-reference.md +27 -0
  264. package/docs/security/SECURITY.md +42 -0
  265. package/docs/security/penetration-test-results.md +31 -0
  266. package/docs/security/threat-model.md +142 -0
  267. package/docs/skills-authoring-guide.md +119 -0
  268. package/docs/skills-publishing-guide.md +21 -0
  269. package/docs/team-setup-guide.md +21 -0
  270. package/docs/troubleshooting.md +119 -0
  271. package/docs/tutorial.md +195 -0
  272. package/docs/upgrade.md +44 -0
  273. package/docs/user-guide.md +131 -0
  274. package/docs/usp-features.md +214 -0
  275. package/eslint.config.mjs +31 -0
  276. package/examples/starter-project/.planning/AUDIT.jsonl +1 -0
  277. package/examples/starter-project/.planning/HANDOFF.json +23 -0
  278. package/examples/starter-project/.planning/PROJECT.md +27 -0
  279. package/examples/starter-project/.planning/STATE.md +10 -0
  280. package/examples/starter-project/MINDFORGE.md +40 -0
  281. package/examples/starter-project/README.md +14 -0
  282. package/implementation-roadmap/day-1-imp/DAY1-HARDEN.md +823 -0
  283. package/implementation-roadmap/day-1-imp/DAY1-IMPLEMENT.md +2459 -0
  284. package/implementation-roadmap/day-1-imp/DAY1-REVIEW.md +288 -0
  285. package/implementation-roadmap/day-2-imp/DAY2-HARDEN.md +954 -0
  286. package/implementation-roadmap/day-2-imp/DAY2-IMPLEMENT.md +2347 -0
  287. package/implementation-roadmap/day-2-imp/DAY2-REVIEW.md +422 -0
  288. package/implementation-roadmap/day-3-imp/DAY3-HARDEN.md +870 -0
  289. package/implementation-roadmap/day-3-imp/DAY3-IMPLEMENT.md +2798 -0
  290. package/implementation-roadmap/day-3-imp/DAY3-REVIEW.md +484 -0
  291. package/implementation-roadmap/day-4-imp/DAY4-HARDEN.md +1087 -0
  292. package/implementation-roadmap/day-4-imp/DAY4-IMPLEMENT.md +2874 -0
  293. package/implementation-roadmap/day-4-imp/DAY4-REVIEW.md +386 -0
  294. package/implementation-roadmap/day-5-imp/DAY5-HARDEN.md +1078 -0
  295. package/implementation-roadmap/day-5-imp/DAY5-IMPLEMENT.md +3151 -0
  296. package/implementation-roadmap/day-5-imp/DAY5-REVIEW.md +345 -0
  297. package/implementation-roadmap/day-6-imp/DAY6-COMPLETE.md +3919 -0
  298. package/implementation-roadmap/day-7-imp-prod/DAY7-PRODUCTION-FINAL.md +4513 -0
  299. package/package.json +31 -0
  300. package/sdk/README.md +69 -0
  301. package/sdk/eslint.config.mjs +34 -0
  302. package/sdk/package-lock.json +1507 -0
  303. package/sdk/package.json +30 -0
  304. package/sdk/src/client.ts +133 -0
  305. package/sdk/src/commands.ts +63 -0
  306. package/sdk/src/events.ts +166 -0
  307. package/sdk/src/index.ts +22 -0
  308. package/sdk/src/types.ts +87 -0
  309. package/sdk/tsconfig.json +13 -0
  310. package/tests/audit.test.js +206 -0
  311. package/tests/ci-mode.test.js +162 -0
  312. package/tests/compaction.test.js +161 -0
  313. package/tests/distribution.test.js +205 -0
  314. package/tests/e2e.test.js +618 -0
  315. package/tests/governance.test.js +130 -0
  316. package/tests/install.test.js +209 -0
  317. package/tests/integrations.test.js +128 -0
  318. package/tests/intelligence.test.js +117 -0
  319. package/tests/metrics.test.js +96 -0
  320. package/tests/migration.test.js +309 -0
  321. package/tests/production.test.js +416 -0
  322. package/tests/sdk.test.js +200 -0
  323. package/tests/skills-platform.test.js +403 -0
  324. package/tests/wave-engine.test.js +338 -0
@@ -0,0 +1,416 @@
1
+ /**
2
+ * MindForge Day 7 — Production Readiness Tests
3
+ * Verifies the installer, updater, migration engine, plugin system,
4
+ * token optimiser, and all 36 commands exist.
5
+ *
6
+ * Run: node tests/production.test.js
7
+ */
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const assert = require('assert');
13
+ let passed = 0, failed = 0;
14
+
15
+ function test(name, fn) {
16
+ try { fn(); console.log(` ✅ ${name}`); passed++; }
17
+ catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
18
+ }
19
+
20
+ const read = p => fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : '';
21
+ const exists = p => fs.existsSync(p);
22
+
23
+ // ── Installer completeness ─────────────────────────────────────────────────────
24
+ console.log('\nMindForge Day 7 — Production Readiness Tests\n');
25
+ console.log('Installer:');
26
+
27
+ test('bin/install.js exists with shebang', () => {
28
+ const c = read('bin/install.js');
29
+ assert.ok(c.includes('#!/usr/bin/env node'), 'Missing shebang');
30
+ assert.ok(c.length > 500, 'install.js seems too short');
31
+ });
32
+
33
+ test('bin/installer-core.js exists and exports run()', () => {
34
+ const c = read('bin/installer-core.js');
35
+ assert.ok(c.includes('module.exports'), 'Missing module.exports');
36
+ assert.ok(c.includes('async function run') || c.includes('function run'), 'Missing run function');
37
+ });
38
+
39
+ test('installer handles --version flag correctly', () => {
40
+ const c = read('bin/install.js');
41
+ assert.ok(c.includes("'--version'") || c.includes('"--version"'), 'Missing --version');
42
+ assert.ok(c.includes('process.exit(0)'), 'Should exit 0 for --version');
43
+ });
44
+
45
+ test('installer has Node.js version gate (≥ 18)', () => {
46
+ const combined = read('bin/install.js') + read('bin/installer-core.js');
47
+ assert.ok(combined.includes('18'), 'Should check for Node.js 18');
48
+ assert.ok(combined.includes('process.exit(1)') || combined.includes('exit(1)'), 'Should exit 1 for old node');
49
+ });
50
+
51
+ test('installer has CI mode detection', () => {
52
+ const c = read('bin/install.js');
53
+ assert.ok(c.includes("process.env.CI"), 'Should detect CI environment');
54
+ assert.ok(c.includes('IS_NON_INTERACTIVE'), 'Should have non-interactive flag');
55
+ });
56
+
57
+ test('installer backs up existing CLAUDE.md', () => {
58
+ const c = read('bin/installer-core.js');
59
+ assert.ok(c.includes('backup') || c.includes('.backup-'), 'Should back up CLAUDE.md');
60
+ });
61
+
62
+ test('installer has self-install detection', () => {
63
+ const c = read('bin/installer-core.js');
64
+ assert.ok(
65
+ c.includes('isSelfInstall') || c.includes("'mindforge-cc'"),
66
+ 'Should detect self-install scenario'
67
+ );
68
+ });
69
+
70
+ test('installer excludes sensitive files (*.env, *.key, *.pem)', () => {
71
+ const c = read('bin/installer-core.js');
72
+ assert.ok(
73
+ c.includes('.env') || c.includes('SENSITIVE_EXCLUDE') || c.includes('.key'),
74
+ 'Should have sensitive file exclusion list'
75
+ );
76
+ });
77
+
78
+ test('installer verifies install after completing', () => {
79
+ const c = read('bin/installer-core.js');
80
+ assert.ok(
81
+ c.includes('verifyInstall') || c.includes('verification'),
82
+ 'Should verify install after completing'
83
+ );
84
+ });
85
+
86
+ // ── Self-update system ─────────────────────────────────────────────────────────
87
+ console.log('\nSelf-update system:');
88
+
89
+ ['version-comparator.js', 'changelog-fetcher.js', 'self-update.js'].forEach(f => {
90
+ test(`bin/updater/${f} exists`, () => {
91
+ assert.ok(exists(`bin/updater/${f}`), `Missing: bin/updater/${f}`);
92
+ });
93
+ });
94
+
95
+ test('compareSemver: 1.0.0 > 0.6.0', () => {
96
+ const { compareSemver } = require('../bin/updater/version-comparator');
97
+ assert.ok(compareSemver('1.0.0', '0.6.0') > 0);
98
+ });
99
+
100
+ test('compareSemver: 0.6.0 < 1.0.0', () => {
101
+ const { compareSemver } = require('../bin/updater/version-comparator');
102
+ assert.ok(compareSemver('0.6.0', '1.0.0') < 0);
103
+ });
104
+
105
+ test('compareSemver: 1.0.0 == 1.0.0', () => {
106
+ const { compareSemver } = require('../bin/updater/version-comparator');
107
+ assert.strictEqual(compareSemver('1.0.0', '1.0.0'), 0);
108
+ });
109
+
110
+ test('compareSemver handles v prefix', () => {
111
+ const { compareSemver } = require('../bin/updater/version-comparator');
112
+ assert.ok(compareSemver('v1.0.0', 'v0.6.0') > 0);
113
+ });
114
+
115
+ test('upgradeType: 0.6.0 → 1.0.0 is major', () => {
116
+ const { upgradeType } = require('../bin/updater/version-comparator');
117
+ assert.strictEqual(upgradeType('0.6.0', '1.0.0'), 'major');
118
+ });
119
+
120
+ test('upgradeType: 1.0.0 → 1.1.0 is minor', () => {
121
+ const { upgradeType } = require('../bin/updater/version-comparator');
122
+ assert.strictEqual(upgradeType('1.0.0', '1.1.0'), 'minor');
123
+ });
124
+
125
+ test('upgradeType: 1.0.0 → 1.0.1 is patch', () => {
126
+ const { upgradeType } = require('../bin/updater/version-comparator');
127
+ assert.strictEqual(upgradeType('1.0.0', '1.0.1'), 'patch');
128
+ });
129
+
130
+ test('upgradeType: 1.0.0 → 1.0.0 is none', () => {
131
+ const { upgradeType } = require('../bin/updater/version-comparator');
132
+ assert.strictEqual(upgradeType('1.0.0', '1.0.0'), 'none');
133
+ });
134
+
135
+ test('self-update has scope detection', () => {
136
+ const c = read('bin/updater/self-update.js');
137
+ assert.ok(c.includes('detectInstallScope'), 'Should have detectInstallScope()');
138
+ });
139
+
140
+ test('self-update reads schema_version before applying update', () => {
141
+ const c = read('bin/updater/self-update.js');
142
+ assert.ok(
143
+ c.includes('readHandoffSchemaVersion') || c.includes('schema_version'),
144
+ 'Should read schema_version from HANDOFF before updating'
145
+ );
146
+ });
147
+
148
+ // ── Migration engine ────────────────────────────────────────────────────────────
149
+ console.log('\nMigration engine:');
150
+
151
+ ['migrate.js', 'schema-versions.js', '0.1.0-to-0.5.0.js', '0.5.0-to-0.6.0.js', '0.6.0-to-1.0.0.js'].forEach(f => {
152
+ test(`bin/migrations/${f} exists`, () => {
153
+ assert.ok(exists(`bin/migrations/${f}`), `Missing: ${f}`);
154
+ });
155
+ });
156
+
157
+ test('migrate.js creates backup before migrating', () => {
158
+ const c = read('bin/migrations/migrate.js');
159
+ assert.ok(c.includes('backup') || c.includes('Backup'), 'Should create backup');
160
+ });
161
+
162
+ test('migrate.js aborts if backup fails', () => {
163
+ const c = read('bin/migrations/migrate.js');
164
+ assert.ok(
165
+ c.includes('backupErr') || c.includes('Migration aborted'),
166
+ 'Should abort if backup creation fails'
167
+ );
168
+ });
169
+
170
+ test('migrate.js restores from backup on migration failure', () => {
171
+ const c = read('bin/migrations/migrate.js');
172
+ assert.ok(
173
+ c.includes('Restoring') || c.includes('restoreFromBackup') || c.includes('restore'),
174
+ 'Should restore from backup on failure'
175
+ );
176
+ });
177
+
178
+ test('0.6.0-to-1.0.0 migration adds plugin_api_version', () => {
179
+ const c = read('bin/migrations/0.6.0-to-1.0.0.js');
180
+ assert.ok(c.includes('plugin_api_version'), 'Should add plugin_api_version field');
181
+ });
182
+
183
+ test('0.6.0-to-1.0.0 migration backfills session_id in AUDIT.jsonl', () => {
184
+ const c = read('bin/migrations/0.6.0-to-1.0.0.js');
185
+ assert.ok(c.includes('session_id'), 'Should backfill session_id');
186
+ });
187
+
188
+ test('0.6.0-to-1.0.0 migration converts VERIFY_PASS_RATE_WARNING_THRESHOLD', () => {
189
+ const c = read('bin/migrations/0.6.0-to-1.0.0.js');
190
+ assert.ok(
191
+ c.includes('VERIFY_PASS_RATE') || c.includes('val / 100'),
192
+ 'Should convert percentage to decimal'
193
+ );
194
+ });
195
+
196
+ test('migration preserves invalid AUDIT.jsonl lines (no crash)', () => {
197
+ const c = read('bin/migrations/0.6.0-to-1.0.0.js');
198
+ assert.ok(c.includes('catch') || c.includes('try'), 'Should handle parse errors gracefully');
199
+ });
200
+
201
+ // ── Plugin system ────────────────────────────────────────────────────────────────
202
+ console.log('\nPlugin system:');
203
+
204
+ ['plugin-schema.md', 'plugin-loader.md', 'PLUGINS-MANIFEST.md'].forEach(f => {
205
+ test(`.mindforge/plugins/${f} exists`, () => {
206
+ assert.ok(exists(`.mindforge/plugins/${f}`));
207
+ });
208
+ });
209
+
210
+ test('plugin schema defines permission model', () => {
211
+ const c = read('.mindforge/plugins/plugin-schema.md');
212
+ assert.ok(c.includes('permissions'), 'Should define permissions');
213
+ assert.ok(c.includes('write_state'), 'Should include write_state permission');
214
+ assert.ok(c.includes('network_access'), 'Should include network_access permission');
215
+ });
216
+
217
+ test('plugin loader has injection guard step', () => {
218
+ const c = read('.mindforge/plugins/plugin-loader.md');
219
+ assert.ok(c.includes('injection guard') || c.includes('Injection'), 'Should run injection guard');
220
+ });
221
+
222
+ test('plugin loader documents advisory permission model', () => {
223
+ const c = read('.mindforge/plugins/plugin-loader.md');
224
+ assert.ok(
225
+ c.includes('advisory') || c.includes('not OS-enforced') || c.includes('not enforced'),
226
+ 'Should explain that permissions are advisory'
227
+ );
228
+ });
229
+
230
+ test('plugin schema lists all 36 reserved command names', () => {
231
+ const c = read('.mindforge/plugins/plugin-schema.md');
232
+ assert.ok(
233
+ c.includes('Reserved command names') || c.includes('reserved'),
234
+ 'Should list reserved command names'
235
+ );
236
+ // Check a few specific reserved names are mentioned
237
+ assert.ok(c.includes('health'), 'Should list health as reserved');
238
+ assert.ok(c.includes('security-scan'), 'Should list security-scan as reserved');
239
+ });
240
+
241
+ // ── Token optimiser ─────────────────────────────────────────────────────────────
242
+ console.log('\nToken optimiser:');
243
+
244
+ test('token-optimiser.md exists', () => {
245
+ assert.ok(exists('.mindforge/production/token-optimiser.md'));
246
+ });
247
+
248
+ test('token optimiser defines efficiency formula', () => {
249
+ const c = read('.mindforge/production/token-optimiser.md');
250
+ assert.ok(c.includes('token_efficiency') || c.includes('efficiency'), 'Should define efficiency');
251
+ assert.ok(c.includes('useful_output') || c.includes('output_tokens'), 'Should define useful output');
252
+ });
253
+
254
+ test('token optimiser has lean plan strategy', () => {
255
+ const c = read('.mindforge/production/token-optimiser.md');
256
+ assert.ok(c.includes('Strategy 1') || c.includes('Lean'), 'Should have lean plan strategy');
257
+ });
258
+
259
+ // ── Production checklist ────────────────────────────────────────────────────────
260
+ console.log('\nProduction checklist:');
261
+
262
+ test('production-checklist.md has exactly 50 checkbox items', () => {
263
+ const c = read('.mindforge/production/production-checklist.md');
264
+ const boxes = (c.match(/- \[ \]/g) || []).length;
265
+ assert.ok(boxes >= 50, `Expected >= 50 items, found ${boxes}`);
266
+ });
267
+
268
+ // ── Documentation completeness ──────────────────────────────────────────────────
269
+ console.log('\nDocumentation:');
270
+
271
+ const DOC_FILES = [
272
+ 'docs/reference/commands.md',
273
+ 'docs/security/SECURITY.md',
274
+ 'docs/security/threat-model.md',
275
+ 'docs/architecture/decision-records-index.md',
276
+ 'docs/contributing/CONTRIBUTING.md',
277
+ ];
278
+ DOC_FILES.forEach(f => test(`${f} exists`, () => assert.ok(exists(f), `Missing: ${f}`)));
279
+
280
+ test('threat model covers all 7 threat actors', () => {
281
+ const c = read('docs/security/threat-model.md');
282
+ for (let i = 1; i <= 7; i++) {
283
+ assert.ok(c.includes(`Threat Actor ${i}`), `Missing Threat Actor ${i}`);
284
+ }
285
+ });
286
+
287
+ test('ADR index lists all 20 ADRs', () => {
288
+ const c = read('docs/architecture/decision-records-index.md');
289
+ for (let i = 1; i <= 20; i++) {
290
+ const adrRef = `ADR-${String(i).padStart(3, '0')}`;
291
+ assert.ok(c.includes(adrRef) || c.includes(`ADR-${i}`), `Missing ${adrRef} in index`);
292
+ }
293
+ });
294
+
295
+ test('SECURITY.md has responsible disclosure policy', () => {
296
+ const c = read('docs/security/SECURITY.md');
297
+ assert.ok(c.includes('disclosure') || c.includes('24 hours'), 'Should have disclosure timeline');
298
+ });
299
+
300
+ // ── All 36 commands ─────────────────────────────────────────────────────────────
301
+ console.log('\nAll 36 commands:');
302
+
303
+ const ALL_COMMANDS = [
304
+ // Day 1
305
+ 'help', 'init-project', 'plan-phase', 'execute-phase', 'verify-phase', 'ship',
306
+ // Day 2
307
+ 'next', 'quick', 'status', 'debug',
308
+ // Day 3
309
+ 'skills', 'review', 'security-scan', 'map-codebase', 'discuss-phase',
310
+ // Day 4
311
+ 'audit', 'milestone', 'complete-milestone', 'approve', 'sync-jira', 'sync-confluence',
312
+ // Day 5
313
+ 'health', 'retrospective', 'profile-team', 'metrics',
314
+ // Day 6
315
+ 'init-org', 'install-skill', 'publish-skill', 'pr-review', 'workspace', 'benchmark',
316
+ // Day 7
317
+ 'update', 'migrate', 'plugins', 'tokens', 'release',
318
+ ];
319
+
320
+ assert.strictEqual(ALL_COMMANDS.length, 36, `Expected 36 commands, have ${ALL_COMMANDS.length}`);
321
+ console.log(` (verifying all ${ALL_COMMANDS.length} commands)`);
322
+
323
+ test('all 36 commands in .claude/commands/mindforge/', () => {
324
+ const missing = ALL_COMMANDS.filter(cmd => !exists(`.claude/commands/mindforge/${cmd}.md`));
325
+ assert.strictEqual(missing.length, 0, `Missing: ${missing.join(', ')}`);
326
+ });
327
+
328
+ test('all 36 commands mirrored to .agent/mindforge/', () => {
329
+ const missing = ALL_COMMANDS.filter(cmd => !exists(`.agent/mindforge/${cmd}.md`));
330
+ assert.strictEqual(missing.length, 0, `Missing agent mirror: ${missing.join(', ')}`);
331
+ });
332
+
333
+ test('no command file is empty (> 100 chars)', () => {
334
+ const tiny = ALL_COMMANDS.filter(cmd => {
335
+ const p = `.claude/commands/mindforge/${cmd}.md`;
336
+ return exists(p) && fs.statSync(p).size < 100;
337
+ });
338
+ assert.strictEqual(tiny.length, 0, `Too small: ${tiny.join(', ')}`);
339
+ });
340
+
341
+ // ── Hardening tests ───────────────────────────────────────────────────────────
342
+ console.log('\nHardening tests:');
343
+
344
+ test('SENSITIVE_EXCLUDE properly excludes .env and .key files', () => {
345
+ const SENSITIVE_EXCLUDE = [
346
+ '.env', /^\.env\..*/, /\.key$/, /\.pem$/, 'secrets', /^secrets$/
347
+ ];
348
+ const shouldExclude = (name) =>
349
+ SENSITIVE_EXCLUDE.some(p => typeof p === 'string' ? p === name : p.test(name));
350
+
351
+ assert.ok(shouldExclude('.env'), '.env should be excluded');
352
+ assert.ok(shouldExclude('.env.local'), '.env.local should be excluded');
353
+ assert.ok(shouldExclude('private.key'), 'private.key should be excluded');
354
+ assert.ok(shouldExclude('certificate.pem'), 'certificate.pem should be excluded');
355
+ assert.ok(shouldExclude('secrets'), 'secrets directory should be excluded');
356
+ assert.ok(!shouldExclude('package.json'), 'package.json should NOT be excluded');
357
+ assert.ok(!shouldExclude('.mindforge'), '.mindforge should NOT be excluded');
358
+ assert.ok(!shouldExclude('src'), 'src should NOT be excluded');
359
+ });
360
+
361
+ test('SENSITIVE_EXCLUDE uses regex for .key and .pem (not glob strings)', () => {
362
+ const c = fs.readFileSync('bin/installer-core.js', 'utf8');
363
+ // Should use regex pattern /\.key$/ not string '*.key'
364
+ assert.ok(!c.includes("'*.key'"), 'Should not use glob string for .key');
365
+ assert.ok(!c.includes("'*.pem'"), 'Should not use glob string for .pem');
366
+ assert.ok(
367
+ c.includes('\\.key$') || c.includes('/\\.key$/') || c.includes('/.key$/'),
368
+ 'Should use regex for .key'
369
+ );
370
+ });
371
+
372
+ test('migration filter uses toVersion range check (not fromVersion)', () => {
373
+ const c = fs.readFileSync('bin/migrations/migrate.js', 'utf8');
374
+ // The correct filter uses compareSemver(m.toVersion, fromVersion) > 0
375
+ assert.ok(
376
+ c.includes('m.toVersion') && c.includes('> 0'),
377
+ 'Should use toVersion range check for migration filter'
378
+ );
379
+ });
380
+
381
+ test('migration has CI auto-delete of backup', () => {
382
+ const c = fs.readFileSync('bin/migrations/migrate.js', 'utf8');
383
+ assert.ok(
384
+ c.includes('CI') && (c.includes('auto-deleted') || c.includes('rmSync')),
385
+ 'Should auto-delete backup in CI mode'
386
+ );
387
+ });
388
+
389
+ // ── Final version check ────────────────────────────────────────────────────────
390
+ console.log('\nVersion:');
391
+
392
+ test('package.json version is 1.0.0', () => {
393
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
394
+ assert.strictEqual(pkg.version, '1.0.0', `Expected 1.0.0, got ${pkg.version}`);
395
+ });
396
+
397
+ test('CHANGELOG.md has v1.0.0 entry', () => {
398
+ const c = read('CHANGELOG.md');
399
+ assert.ok(c.includes('1.0.0'), 'CHANGELOG.md should have 1.0.0 entry');
400
+ });
401
+
402
+ test('all 20 ADR files present in .planning/decisions/', () => {
403
+ if (!exists('.planning/decisions/')) return; // Skip if no decisions dir yet
404
+ const adrs = fs.readdirSync('.planning/decisions/').filter(f => f.startsWith('ADR-') && f.endsWith('.md'));
405
+ assert.ok(adrs.length >= 20, `Expected >= 20 ADRs, found ${adrs.length}`);
406
+ });
407
+
408
+ // ── Results ─────────────────────────────────────────────────────────────────────
409
+ console.log(`\n${'─'.repeat(55)}`);
410
+ console.log(`Results: ${passed} passed, ${failed} failed`);
411
+ if (failed > 0) {
412
+ console.error(`\n❌ ${failed} test(s) failed — not production ready.\n`);
413
+ process.exit(1);
414
+ } else {
415
+ console.log(`\n✅ All production readiness tests passed.\n`);
416
+ }
@@ -0,0 +1,200 @@
1
+ /**
2
+ * MindForge Day 6 — SDK Tests
3
+ * Run: node tests/sdk.test.js
4
+ */
5
+ 'use strict';
6
+ const fs = require('fs'), path = require('path'), assert = require('assert');
7
+ let passed = 0, failed = 0;
8
+ function test(name, fn) {
9
+ try { fn(); console.log(` ✅ ${name}`); passed++; }
10
+ catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
11
+ }
12
+ const read = p => fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : '';
13
+
14
+ // ── Lightweight SDK client simulation (without TypeScript compilation) ─────────
15
+ class MockMindForgeClient {
16
+ constructor(config = {}) {
17
+ this.projectRoot = config.projectRoot || process.cwd();
18
+ }
19
+ isInitialised() {
20
+ return fs.existsSync(path.join(this.projectRoot, '.planning', 'PROJECT.md'));
21
+ }
22
+ readHandoff() {
23
+ const p = path.join(this.projectRoot, '.planning', 'HANDOFF.json');
24
+ if (!fs.existsSync(p)) return null;
25
+ try { return JSON.parse(fs.readFileSync(p, 'utf8')); }
26
+ catch { return null; }
27
+ }
28
+ readAuditLog(filter = {}) {
29
+ const p = path.join(this.projectRoot, '.planning', 'AUDIT.jsonl');
30
+ if (!fs.existsSync(p)) return [];
31
+ return fs.readFileSync(p, 'utf8')
32
+ .split('\n').filter(Boolean)
33
+ .map(l => { try { return JSON.parse(l); } catch { return null; } })
34
+ .filter(Boolean)
35
+ .filter(e => !filter.event || e.event === filter.event);
36
+ }
37
+ async health() {
38
+ const warnings = [], errors = [], info = [];
39
+ const handoff = this.readHandoff();
40
+ if (handoff && !handoff.schema_version) {
41
+ errors.push({ category: 'state', message: 'HANDOFF.json missing schema_version' });
42
+ }
43
+ return {
44
+ overallStatus: errors.length > 0 ? 'error' : warnings.length > 0 ? 'warning' : 'healthy',
45
+ errors, warnings, informational: info,
46
+ timestamp: new Date().toISOString(),
47
+ };
48
+ }
49
+ }
50
+
51
+ // ── Command builder simulation ────────────────────────────────────────────────
52
+ const commands = {
53
+ health: (opts = {}) => `/mindforge:health ${(opts.flags||[]).join(' ')}`.trim(),
54
+ planPhase: (n, opts = {}) => `/mindforge:plan-phase ${n} ${(opts.flags||[]).join(' ')}`.trim(),
55
+ executePhase: (n, opts = {}) => `/mindforge:execute-phase ${n} ${(opts.flags||[]).join(' ')}`.trim(),
56
+ audit: (f = {}) => {
57
+ const parts = ['/mindforge:audit'];
58
+ if (f.phase) parts.push(`--phase ${f.phase}`);
59
+ if (f.event) parts.push(`--event ${f.event}`);
60
+ return parts.join(' ');
61
+ },
62
+ };
63
+
64
+ console.log('\nMindForge Day 6 — SDK Tests\n');
65
+
66
+ console.log('SDK source files:');
67
+ ['index.ts','client.ts','types.ts','events.ts','commands.ts'].forEach(f => {
68
+ test(`sdk/src/${f} exists`, () => {
69
+ assert.ok(fs.existsSync(`sdk/src/${f}`), `Missing: sdk/src/${f}`);
70
+ });
71
+ });
72
+
73
+ console.log('\nSDK type exports:');
74
+ test('index.ts exports VERSION', () => {
75
+ const c = read('sdk/src/index.ts');
76
+ assert.ok(c.includes("VERSION"), 'Should export VERSION');
77
+ });
78
+
79
+ test('types.ts defines MindForgeConfig', () => {
80
+ const c = read('sdk/src/types.ts');
81
+ assert.ok(c.includes('MindForgeConfig'), 'Should define MindForgeConfig');
82
+ });
83
+
84
+ test('types.ts defines all result types', () => {
85
+ const c = read('sdk/src/types.ts');
86
+ ['PhaseResult','TaskResult','SecurityFinding','GateResult','HealthReport'].forEach(t => {
87
+ assert.ok(c.includes(t), `Should define ${t}`);
88
+ });
89
+ });
90
+
91
+ test('events.ts defines MindForgeEventStream', () => {
92
+ const c = read('sdk/src/events.ts');
93
+ assert.ok(c.includes('MindForgeEventStream'), 'Should define MindForgeEventStream');
94
+ assert.ok(c.includes('watchAuditLog'), 'Should have watchAuditLog method');
95
+ });
96
+
97
+ console.log('\nSDK client behaviour:');
98
+
99
+ test('client.isInitialised() returns false when PROJECT.md missing', () => {
100
+ const client = new MockMindForgeClient({ projectRoot: '/tmp/nonexistent-project' });
101
+ assert.strictEqual(client.isInitialised(), false);
102
+ });
103
+
104
+ test('client.isInitialised() returns true when PROJECT.md exists', () => {
105
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
106
+ // May be true or false depending on whether we're in a MindForge project
107
+ assert.ok(typeof client.isInitialised() === 'boolean');
108
+ });
109
+
110
+ test('client.readHandoff() returns null when HANDOFF.json missing', () => {
111
+ const client = new MockMindForgeClient({ projectRoot: '/tmp/nonexistent-project' });
112
+ assert.strictEqual(client.readHandoff(), null);
113
+ });
114
+
115
+ test('client.readHandoff() parses valid HANDOFF.json', () => {
116
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
117
+ const handoff = client.readHandoff();
118
+ if (handoff) {
119
+ assert.ok(typeof handoff === 'object', 'HANDOFF.json should parse to object');
120
+ assert.ok(handoff.schema_version, 'HANDOFF.json should have schema_version');
121
+ }
122
+ // null is acceptable if not in a MindForge project
123
+ });
124
+
125
+ test('client.readAuditLog() returns array', () => {
126
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
127
+ const log = client.readAuditLog();
128
+ assert.ok(Array.isArray(log), 'readAuditLog should return array');
129
+ });
130
+
131
+ test('client.readAuditLog() filters by event type', () => {
132
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
133
+ const secFindings = client.readAuditLog({ event: 'security_finding' });
134
+ assert.ok(Array.isArray(secFindings));
135
+ secFindings.forEach(e => {
136
+ assert.strictEqual(e.event, 'security_finding', 'All entries should match filter');
137
+ });
138
+ });
139
+
140
+ test('client.health() returns HealthReport shape', async () => {
141
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
142
+ const report = await client.health();
143
+ assert.ok(['healthy','warning','error'].includes(report.overallStatus));
144
+ assert.ok(Array.isArray(report.errors));
145
+ assert.ok(Array.isArray(report.warnings));
146
+ assert.ok(report.timestamp);
147
+ });
148
+
149
+ console.log('\nCommand builders:');
150
+ test('commands.health() builds correct string', () => {
151
+ assert.strictEqual(commands.health(), '/mindforge:health');
152
+ assert.strictEqual(commands.health({ flags: ['--repair'] }), '/mindforge:health --repair');
153
+ });
154
+
155
+ test('commands.planPhase() builds correct string', () => {
156
+ assert.strictEqual(commands.planPhase(3), '/mindforge:plan-phase 3');
157
+ });
158
+
159
+ test('commands.audit() builds filter string', () => {
160
+ const cmd = commands.audit({ phase: 3, event: 'security_finding' });
161
+ assert.ok(cmd.includes('--phase 3'));
162
+ assert.ok(cmd.includes('--event security_finding'));
163
+ });
164
+
165
+ test('commands.executePhase() includes phase number', () => {
166
+ const cmd = commands.executePhase(2);
167
+ assert.ok(cmd.includes('2'));
168
+ assert.ok(cmd.startsWith('/mindforge:execute-phase'));
169
+ });
170
+
171
+ console.log('\nHardening-prompted SDK tests:');
172
+
173
+ test('SDK SSE server binds to 127.0.0.1 (localhost only)', () => {
174
+ const c = read('sdk/src/events.ts');
175
+ assert.ok(
176
+ c.includes("'127.0.0.1'") || c.includes('"127.0.0.1"'),
177
+ 'SSE server should bind to 127.0.0.1 only'
178
+ );
179
+ });
180
+
181
+ test('SDK SSE server rejects non-localhost connections', () => {
182
+ const c = read('sdk/src/events.ts');
183
+ assert.ok(
184
+ c.includes('isLocalhost') || c.includes('remoteAddress') || c.includes('Forbidden'),
185
+ 'SSE server should reject non-localhost connections'
186
+ );
187
+ });
188
+
189
+ test('SDK has inotify fallback for Linux', () => {
190
+ const c = read('sdk/src/events.ts');
191
+ assert.ok(
192
+ c.includes('ENOSPC') || c.includes('polling') || c.includes('watchFile'),
193
+ 'SDK should handle Linux inotify limits'
194
+ );
195
+ });
196
+
197
+ console.log(`\n${'─'.repeat(50)}`);
198
+ console.log(`Results: ${passed} passed, ${failed} failed`);
199
+ if (failed > 0) { console.error(`\n❌ ${failed} test(s) failed.\n`); process.exit(1); }
200
+ else { console.log(`\n✅ All SDK tests passed.\n`); }