@geraldmaron/construct 1.0.6 → 1.0.7

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 (123) hide show
  1. package/README.md +19 -17
  2. package/agents/contracts.json +617 -2
  3. package/agents/contracts.schema.json +83 -0
  4. package/agents/prompts/cx-accessibility.md +2 -0
  5. package/agents/prompts/cx-ai-engineer.md +2 -0
  6. package/agents/prompts/cx-architect.md +2 -0
  7. package/agents/prompts/cx-business-strategist.md +2 -0
  8. package/agents/prompts/cx-data-analyst.md +2 -0
  9. package/agents/prompts/cx-data-engineer.md +2 -0
  10. package/agents/prompts/cx-debugger.md +2 -0
  11. package/agents/prompts/cx-designer.md +2 -0
  12. package/agents/prompts/cx-devil-advocate.md +2 -0
  13. package/agents/prompts/cx-docs-keeper.md +2 -0
  14. package/agents/prompts/cx-engineer.md +2 -0
  15. package/agents/prompts/cx-evaluator.md +2 -0
  16. package/agents/prompts/cx-explorer.md +2 -0
  17. package/agents/prompts/cx-legal-compliance.md +2 -0
  18. package/agents/prompts/cx-operations.md +2 -0
  19. package/agents/prompts/cx-orchestrator.md +2 -0
  20. package/agents/prompts/cx-platform-engineer.md +2 -0
  21. package/agents/prompts/cx-product-manager.md +2 -0
  22. package/agents/prompts/cx-qa.md +2 -0
  23. package/agents/prompts/cx-rd-lead.md +2 -0
  24. package/agents/prompts/cx-release-manager.md +2 -0
  25. package/agents/prompts/cx-researcher.md +2 -0
  26. package/agents/prompts/cx-reviewer.md +2 -0
  27. package/agents/prompts/cx-security.md +2 -0
  28. package/agents/prompts/cx-sre.md +2 -0
  29. package/agents/prompts/cx-test-automation.md +2 -0
  30. package/agents/prompts/cx-trace-reviewer.md +2 -0
  31. package/agents/prompts/cx-ux-researcher.md +2 -0
  32. package/agents/registry.json +8 -3
  33. package/bin/construct +209 -32
  34. package/commands/build/feature.md +1 -1
  35. package/commands/build/fix.md +1 -1
  36. package/commands/design/access.md +1 -1
  37. package/commands/design/flow.md +1 -1
  38. package/commands/design/ui.md +1 -1
  39. package/commands/measure/experiment.md +1 -1
  40. package/commands/measure/metrics.md +1 -1
  41. package/commands/measure/results.md +1 -1
  42. package/commands/plan/api.md +1 -1
  43. package/commands/plan/challenge.md +1 -1
  44. package/commands/plan/decide.md +1 -1
  45. package/commands/plan/feature.md +1 -1
  46. package/commands/plan/requirements.md +1 -1
  47. package/commands/remember/context.md +1 -1
  48. package/commands/remember/handoff.md +1 -1
  49. package/commands/remember/runbook.md +1 -1
  50. package/commands/review/code.md +1 -1
  51. package/commands/review/quality.md +1 -1
  52. package/commands/review/security.md +1 -1
  53. package/commands/ship/ready.md +1 -1
  54. package/commands/ship/release.md +1 -1
  55. package/commands/ship/status.md +1 -1
  56. package/commands/understand/docs.md +1 -1
  57. package/commands/understand/this.md +1 -1
  58. package/commands/understand/why.md +1 -1
  59. package/commands/work/clean.md +1 -1
  60. package/commands/work/drive.md +1 -1
  61. package/commands/work/optimize-prompts.md +1 -1
  62. package/commands/work/parallel-review.md +1 -1
  63. package/lib/auto-docs.mjs +7 -7
  64. package/lib/boundary.mjs +126 -0
  65. package/lib/cache-strategy-google.js +26 -31
  66. package/lib/comment-lint.mjs +134 -0
  67. package/lib/contracts/validate.mjs +323 -0
  68. package/lib/daemons/contract.mjs +210 -0
  69. package/lib/docs-verify.mjs +59 -6
  70. package/lib/doctor/cli.mjs +16 -1
  71. package/lib/doctor/index.mjs +3 -1
  72. package/lib/doctor/watchers/consistency.mjs +310 -0
  73. package/lib/doctor/watchers/mcp-protocol.mjs +232 -0
  74. package/lib/document-extract.mjs +211 -1
  75. package/lib/embed/cli.mjs +124 -3
  76. package/lib/embed/daemon.mjs +43 -4
  77. package/lib/embed/docs-lifecycle.mjs +1 -1
  78. package/lib/embed/inbox.mjs +2 -0
  79. package/lib/embed/scheduler.mjs +33 -5
  80. package/lib/evaluator-optimizer.mjs +2 -3
  81. package/lib/hooks/comment-lint.mjs +16 -0
  82. package/lib/hooks/mcp-audit.mjs +2 -1
  83. package/lib/hooks/proactive-activation.mjs +0 -14
  84. package/lib/hooks/rule-verifier.mjs +217 -0
  85. package/lib/hooks/session-optimize.mjs +2 -1
  86. package/lib/init-unified.mjs +55 -65
  87. package/lib/intake/classify.mjs +108 -24
  88. package/lib/intake/daemon.mjs +121 -0
  89. package/lib/intake/filesystem-queue.mjs +6 -1
  90. package/lib/intake/intake-config.mjs +2 -1
  91. package/lib/intake/prepare.mjs +0 -1
  92. package/lib/intake/session-prelude.mjs +7 -1
  93. package/lib/intake/traceability.mjs +90 -0
  94. package/lib/knowledge/research-store.mjs +2 -0
  95. package/lib/maintenance/cleanup.mjs +315 -0
  96. package/lib/mcp/memory-bridge.mjs +276 -0
  97. package/lib/mcp/server.mjs +2 -0
  98. package/lib/mcp/tools/workflow.mjs +25 -0
  99. package/lib/mcp-catalog.json +12 -8
  100. package/lib/mcp-platform-config.mjs +16 -8
  101. package/lib/migrations/index.mjs +106 -0
  102. package/lib/migrations/v1-baseline.mjs +33 -0
  103. package/lib/observation-store.mjs +9 -4
  104. package/lib/outcomes/record.mjs +2 -0
  105. package/lib/profiles/rebrand.mjs +46 -0
  106. package/lib/project-init-shared.mjs +12 -0
  107. package/lib/provider-capabilities.js +20 -7
  108. package/lib/providers/auth-manager.mjs +58 -17
  109. package/lib/reflect.mjs +49 -12
  110. package/lib/server/index.mjs +22 -28
  111. package/lib/session-store.mjs +6 -4
  112. package/lib/setup.mjs +14 -3
  113. package/lib/telemetry/client.mjs +5 -1
  114. package/lib/version.mjs +51 -0
  115. package/lib/worker/trace.mjs +5 -1
  116. package/package.json +4 -1
  117. package/personas/construct.md +3 -1
  118. package/rules/common/development-workflow.md +2 -1
  119. package/rules/common/no-fabrication.md +69 -0
  120. package/rules/common/review-before-change.md +58 -0
  121. package/scripts/sync-agents.mjs +45 -14
  122. package/templates/docs/construct_guide.md +6 -6
  123. package/templates/docs/skill-artifact.md +1 -1
@@ -0,0 +1,58 @@
1
+ <!--
2
+ rules/common/review-before-change.md: audit the current state before authoring anything new.
3
+
4
+ Applies to every specialist on every platform. Pairs with framing.md (frame the
5
+ problem) and development-workflow.md step 0 (research and reuse before code).
6
+ This rule extends the same discipline to artifacts: docs, strategy, PRDs, ADRs,
7
+ RFCs, rules, templates, and any other durable file. Read before scaffolding.
8
+ -->
9
+ # Review Before Change
10
+
11
+ Before creating or rewriting a durable artifact, check what already exists.
12
+
13
+ This rule exists because the most common waste in Construct is duplicated effort: a new strategy doc landing next to a PRD that already covers it, a new rule re-stating a section of `framing.md`, a new diagram drawn while an equivalent one sits two folders away. The fix is not more process. It is a fifteen-second audit before the first write.
14
+
15
+ ## When this applies
16
+
17
+ Any time the work would produce or significantly rewrite one of:
18
+
19
+ - A doc under `docs/`, including concepts, cookbook, providers, runbooks, ADRs, RFCs, PRDs, memos, runbooks, decisions.
20
+ - A rule under `rules/` or a skill under `skills/`.
21
+ - A template under `templates/`.
22
+ - A top-level repo doc (README, CHANGELOG, STRATEGY, AGENTS, CONTRIBUTING).
23
+ - A profile under `profiles/` or a registered agent.
24
+
25
+ It does not apply to local-only working files (`plan.md`, `.cx/` state, draft scratch).
26
+
27
+ ## The audit
28
+
29
+ Before writing, answer all three:
30
+
31
+ 1. **Does an artifact for this already exist?** Search by topic, not filename. `grep -rli "<topic>" docs/ rules/ skills/` is the floor. If something close exists, the default is to extend or supersede, not to create a sibling.
32
+ 2. **Is there a template or canonical shape for this artifact type?** Check `templates/docs/` and the matching `skills/docs/*-workflow.md`. If a shape exists, use it; do not invent a new structure.
33
+ 3. **What is the canonical home for this kind of content?** A strategy doc belongs in one place. A new ADR does not live in `docs/notes/`. If you have to think about where to put it, the location is wrong.
34
+
35
+ If any answer surfaces an existing artifact, you have two valid moves:
36
+
37
+ - **Extend it.** Add the missing section to the existing file.
38
+ - **Supersede it.** Replace the old artifact and mark it superseded. Do not leave two competing sources of truth.
39
+
40
+ Creating a new sibling artifact "because the old one didn't quite fit" is the failure mode this rule prevents. If the old one doesn't fit, fix it.
41
+
42
+ ## Documenting the audit
43
+
44
+ For artifacts that go through a review cycle (strategy, PRD, ADR, RFC), the framing or problem-statement section should briefly note what existing artifacts were reviewed and why a new one is warranted. One sentence is enough. The point is to leave evidence that the audit happened.
45
+
46
+ ## Anti-patterns
47
+
48
+ - Creating `docs/notes/strategy.md` because you didn't notice `STRATEGY.md` at the root.
49
+ - Writing a new rule that paraphrases an existing one.
50
+ - Adding a new template alongside `templates/docs/strategy.md` because the existing one "needed a couple of tweaks."
51
+ - Drafting an ADR for a decision already captured in an existing ADR.
52
+ - Producing a recipe in `docs/cookbook/` for a workflow already documented in `docs/concepts/`.
53
+
54
+ ## Related
55
+
56
+ - `rules/common/framing.md`: frame the underlying problem before reaching for inputs.
57
+ - `rules/common/development-workflow.md`: step 0 covers the same discipline for code.
58
+ - `rules/common/doc-ownership.md`: which specialist owns which artifact type.
@@ -121,6 +121,18 @@ if (validationErrors.length > 0) {
121
121
  process.exit(1);
122
122
  }
123
123
 
124
+ // Sync-time contract validation: contracts.json shape, schema refs, and
125
+ // producer/consumer name resolution against the registry above.
126
+ {
127
+ const { validateContractsFile } = await import("../lib/contracts/validate.mjs");
128
+ const contractsResult = validateContractsFile();
129
+ if (!contractsResult.ok) {
130
+ console.error("Contract validation failed:");
131
+ for (const err of contractsResult.errors) console.error(` - ${err}`);
132
+ process.exit(1);
133
+ }
134
+ }
135
+
124
136
  // --- Dry-run + lockfile + two-phase write infrastructure ---
125
137
 
126
138
  const DRY_RUN = process.argv.includes("--dry-run");
@@ -671,9 +683,13 @@ ${agentList || "(all specialists are internal — routed through Construct)"}`;
671
683
  if (!settings.mcpServers) settings.mcpServers = {};
672
684
  const registryMcp = registry.mcpServers ?? {};
673
685
  for (const [id, mcpDef] of Object.entries(registryMcp)) {
674
- const existing = JSON.stringify(settings.mcpServers[id] ?? "");
686
+ const existingEntry = settings.mcpServers[id];
687
+ const existing = JSON.stringify(existingEntry ?? "");
675
688
  const hasPlaceholder = existing.includes("__");
676
- if (settings.mcpServers[id] && !hasPlaceholder) continue;
689
+ const registryWantsCommand = !mcpDef.type && Array.isArray(mcpDef.args);
690
+ const existingIsRemote = existingEntry && (existingEntry.type === 'http' || existingEntry.type === 'remote');
691
+ const transportMismatch = registryWantsCommand && existingIsRemote;
692
+ if (existingEntry && !hasPlaceholder && !transportMismatch) continue;
677
693
  settings.mcpServers[id] = buildClaudeMcpEntry(id, mcpDef, process.env);
678
694
  }
679
695
  if (!DRY_RUN) fs.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2) + "\n");
@@ -711,8 +727,8 @@ function hasCodexMcpTable(text, id) {
711
727
  return new RegExp(`^\\[mcp_servers\\.(?:${escapeRegExp(id)}|${escapeRegExp(tomlString(id))})\\]`, "m").test(text);
712
728
  }
713
729
 
714
- function isCodexMcpSupported(id) {
715
- return id !== "memory";
730
+ function isCodexMcpSupported() {
731
+ return true;
716
732
  }
717
733
 
718
734
  function syncCodex(entries) {
@@ -834,9 +850,13 @@ function syncVSCode() {
834
850
  if (!settings["github.copilot.mcpServers"]) settings["github.copilot.mcpServers"] = {};
835
851
  const mcpServers = settings["github.copilot.mcpServers"];
836
852
  for (const [id, mcpDef] of Object.entries(registryMcp)) {
837
- const existing = JSON.stringify(mcpServers[id] ?? "");
853
+ const existingEntry = mcpServers[id];
854
+ const existing = JSON.stringify(existingEntry ?? "");
838
855
  const hasPlaceholder = existing.includes("__");
839
- if (mcpServers[id] && !hasPlaceholder) continue;
856
+ const registryWantsCommand = !mcpDef.type && Array.isArray(mcpDef.args);
857
+ const existingIsRemote = existingEntry && (existingEntry.type === 'http' || existingEntry.type === 'remote');
858
+ const transportMismatch = registryWantsCommand && existingIsRemote;
859
+ if (existingEntry && !hasPlaceholder && !transportMismatch) continue;
840
860
  mcpServers[id] = buildClaudeMcpEntry(id, mcpDef, process.env);
841
861
  }
842
862
  settings["github.copilot.mcpServers"] = mcpServers;
@@ -862,9 +882,13 @@ function syncCursor() {
862
882
  const config = JSON.parse(fs.readFileSync(cursorMcpPath, "utf8"));
863
883
  if (!config.mcpServers) config.mcpServers = {};
864
884
  for (const [id, mcpDef] of Object.entries(registryMcp)) {
865
- const existing = JSON.stringify(config.mcpServers[id] ?? "");
885
+ const existingEntry = config.mcpServers[id];
886
+ const existing = JSON.stringify(existingEntry ?? "");
866
887
  const hasPlaceholder = existing.includes("__");
867
- if (config.mcpServers[id] && !hasPlaceholder) continue;
888
+ const registryWantsCommand = !mcpDef.type && Array.isArray(mcpDef.args);
889
+ const existingIsRemote = existingEntry && (existingEntry.type === 'http' || existingEntry.type === 'remote');
890
+ const transportMismatch = registryWantsCommand && existingIsRemote;
891
+ if (existingEntry && !hasPlaceholder && !transportMismatch) continue;
868
892
  config.mcpServers[id] = buildClaudeMcpEntry(id, mcpDef, process.env);
869
893
  }
870
894
  if (!DRY_RUN) fs.writeFileSync(cursorMcpPath, JSON.stringify(config, null, 2) + "\n");
@@ -963,14 +987,21 @@ function syncOpencode(entries) {
963
987
  for (const [id, mcpDef] of Object.entries(registryMcp)) {
964
988
  const openCodeId = getOpenCodeMcpId(id);
965
989
  if (openCodeId !== id) delete config.mcp[id];
966
- if (id === 'memory' && config.mcp.cass && !config.mcp[openCodeId]) {
967
- config.mcp[openCodeId] = config.mcp.cass;
968
- }
969
990
  if (id === 'memory') delete config.mcp.cass;
970
- const existing = JSON.stringify(config.mcp[openCodeId] ?? "");
971
- const hasPlaceholder = existing.includes("__") && existing.includes("__");
991
+
992
+ // Migrate the legacy cass-memory HTTP entry to the stdio bridge. cm v0.2.x
993
+ // rejects the MCP handshake (OpenCode surfaces 405 on the SSE GET), so
994
+ // any remote/http memory entry must be rewritten when the registry
995
+ // defines a command-based bridge.
996
+ const existingEntry = config.mcp[openCodeId];
997
+ const registryWantsCommand = !mcpDef.type && Array.isArray(mcpDef.args);
998
+ const existingIsRemote = existingEntry && (existingEntry.type === 'remote' || existingEntry.type === 'http');
999
+ const transportMismatch = registryWantsCommand && existingIsRemote;
1000
+
1001
+ const existing = JSON.stringify(existingEntry ?? "");
1002
+ const hasPlaceholder = existing.includes("__");
972
1003
  const argsHaveTemplates = (mcpDef.args ?? []).some((a) => typeof a === 'string' && a.includes('__'));
973
- if (!config.mcp[openCodeId] || hasPlaceholder || argsHaveTemplates) {
1004
+ if (!existingEntry || hasPlaceholder || argsHaveTemplates || transportMismatch) {
974
1005
  config.mcp[openCodeId] = buildOpenCodeMcpEntry(id, mcpDef, process.env).entry;
975
1006
  }
976
1007
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  This file was generated by `construct init` to help you get oriented. It's safe to edit: Construct only writes it once, then leaves it alone.
4
4
 
5
- **Full docs:** [https://geraldmaron.github.io/construct/v2/](https://geraldmaron.github.io/construct/v2/)
5
+ **Full docs:** [https://geraldmaron.github.io/construct/](https://geraldmaron.github.io/construct/)
6
6
 
7
7
  ## What Construct is doing in your project
8
8
 
@@ -117,7 +117,7 @@ All ports bind to `127.0.0.1` only; nothing is reachable from other machines on
117
117
  | `construct search "..."` | Hybrid file + SQL + semantic search over project state |
118
118
  | `construct uninstall` | Interactive teardown: never touches Docker or your code |
119
119
 
120
- Full reference: <https://geraldmaron.github.io/construct/v2/docs/reference/cli>
120
+ Full reference: <https://geraldmaron.github.io/construct/docs/reference/cli>
121
121
 
122
122
  ## Updating Construct
123
123
 
@@ -134,13 +134,13 @@ construct doctor # most issues surface here with a fix hint
134
134
  construct down && construct up # restart local services
135
135
  ```
136
136
 
137
- Troubleshooting guide: <https://geraldmaron.github.io/construct/v2/docs/operations/troubleshooting>
137
+ Troubleshooting guide: <https://geraldmaron.github.io/construct/docs/operations/troubleshooting>
138
138
 
139
139
  ## Next steps
140
140
 
141
- - [Connect your editor](https://geraldmaron.github.io/construct/v2/docs/start/connect-your-editor) if you haven't already.
142
- - [Run your first task](https://geraldmaron.github.io/construct/v2/docs/start/first-task) to feel the flow.
143
- - Skim [the architecture](https://geraldmaron.github.io/construct/v2/docs/concepts/architecture) when you have 10 minutes: it'll save you hours later.
141
+ - [Connect your editor](https://geraldmaron.github.io/construct/docs/start/connect-your-editor) if you haven't already.
142
+ - [Run your first task](https://geraldmaron.github.io/construct/docs/start/first-task) to feel the flow.
143
+ - Skim [the architecture](https://geraldmaron.github.io/construct/docs/concepts/architecture) when you have 10 minutes: it'll save you hours later.
144
144
 
145
145
  If you'd rather have a teammate walk you through it, the persona itself can:
146
146
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: <verb-led-id>
3
- scope: <one paragraph: what it covers, what it does not>
3
+ scope: "<one paragraph: what it covers, what it does not>"
4
4
  observable_outcome: <how someone outside the role tells this skill happened>
5
5
  provenance:
6
6
  - <citation: post-mortem, public framework, competency model>