archmantic 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 (175) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +172 -0
  3. package/dist/agent.d.ts +20 -0
  4. package/dist/agent.d.ts.map +1 -0
  5. package/dist/agent.js +239 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/analyze/datamodel.d.ts +9 -0
  8. package/dist/analyze/datamodel.d.ts.map +1 -0
  9. package/dist/analyze/datamodel.js +19 -0
  10. package/dist/analyze/datamodel.js.map +1 -0
  11. package/dist/analyze/derive.d.ts +21 -0
  12. package/dist/analyze/derive.d.ts.map +1 -0
  13. package/dist/analyze/derive.js +211 -0
  14. package/dist/analyze/derive.js.map +1 -0
  15. package/dist/analyze/drizzle.d.ts +3 -0
  16. package/dist/analyze/drizzle.d.ts.map +1 -0
  17. package/dist/analyze/drizzle.js +83 -0
  18. package/dist/analyze/drizzle.js.map +1 -0
  19. package/dist/analyze/endpoints.d.ts +3 -0
  20. package/dist/analyze/endpoints.d.ts.map +1 -0
  21. package/dist/analyze/endpoints.js +167 -0
  22. package/dist/analyze/endpoints.js.map +1 -0
  23. package/dist/analyze/fs-util.d.ts +3 -0
  24. package/dist/analyze/fs-util.d.ts.map +1 -0
  25. package/dist/analyze/fs-util.js +44 -0
  26. package/dist/analyze/fs-util.js.map +1 -0
  27. package/dist/analyze/incremental.d.ts +12 -0
  28. package/dist/analyze/incremental.d.ts.map +1 -0
  29. package/dist/analyze/incremental.js +102 -0
  30. package/dist/analyze/incremental.js.map +1 -0
  31. package/dist/analyze/index.d.ts +5 -0
  32. package/dist/analyze/index.d.ts.map +1 -0
  33. package/dist/analyze/index.js +49 -0
  34. package/dist/analyze/index.js.map +1 -0
  35. package/dist/analyze/parse-util.d.ts +10 -0
  36. package/dist/analyze/parse-util.d.ts.map +1 -0
  37. package/dist/analyze/parse-util.js +47 -0
  38. package/dist/analyze/parse-util.js.map +1 -0
  39. package/dist/analyze/prisma.d.ts +4 -0
  40. package/dist/analyze/prisma.d.ts.map +1 -0
  41. package/dist/analyze/prisma.js +97 -0
  42. package/dist/analyze/prisma.js.map +1 -0
  43. package/dist/analyze/sql.d.ts +3 -0
  44. package/dist/analyze/sql.d.ts.map +1 -0
  45. package/dist/analyze/sql.js +110 -0
  46. package/dist/analyze/sql.js.map +1 -0
  47. package/dist/analyze/stack.d.ts +4 -0
  48. package/dist/analyze/stack.d.ts.map +1 -0
  49. package/dist/analyze/stack.js +94 -0
  50. package/dist/analyze/stack.js.map +1 -0
  51. package/dist/analyze/tier0.d.ts +7 -0
  52. package/dist/analyze/tier0.d.ts.map +1 -0
  53. package/dist/analyze/tier0.js +57 -0
  54. package/dist/analyze/tier0.js.map +1 -0
  55. package/dist/analyze/tier1.d.ts +13 -0
  56. package/dist/analyze/tier1.d.ts.map +1 -0
  57. package/dist/analyze/tier1.js +144 -0
  58. package/dist/analyze/tier1.js.map +1 -0
  59. package/dist/analyze/tier2.d.ts +14 -0
  60. package/dist/analyze/tier2.d.ts.map +1 -0
  61. package/dist/analyze/tier2.js +231 -0
  62. package/dist/analyze/tier2.js.map +1 -0
  63. package/dist/analyze/walk.d.ts +3 -0
  64. package/dist/analyze/walk.d.ts.map +1 -0
  65. package/dist/analyze/walk.js +50 -0
  66. package/dist/analyze/walk.js.map +1 -0
  67. package/dist/auth.d.ts +12 -0
  68. package/dist/auth.d.ts.map +1 -0
  69. package/dist/auth.js +61 -0
  70. package/dist/auth.js.map +1 -0
  71. package/dist/cli.d.ts +3 -0
  72. package/dist/cli.d.ts.map +1 -0
  73. package/dist/cli.js +787 -0
  74. package/dist/cli.js.map +1 -0
  75. package/dist/cloud/api.d.ts +20 -0
  76. package/dist/cloud/api.d.ts.map +1 -0
  77. package/dist/cloud/api.js +81 -0
  78. package/dist/cloud/api.js.map +1 -0
  79. package/dist/cloud/index.d.ts +4 -0
  80. package/dist/cloud/index.d.ts.map +1 -0
  81. package/dist/cloud/index.js +20 -0
  82. package/dist/cloud/index.js.map +1 -0
  83. package/dist/cloud/store.d.ts +34 -0
  84. package/dist/cloud/store.d.ts.map +1 -0
  85. package/dist/cloud/store.js +137 -0
  86. package/dist/cloud/store.js.map +1 -0
  87. package/dist/diff/history.d.ts +9 -0
  88. package/dist/diff/history.d.ts.map +1 -0
  89. package/dist/diff/history.js +44 -0
  90. package/dist/diff/history.js.map +1 -0
  91. package/dist/diff/index.d.ts +5 -0
  92. package/dist/diff/index.d.ts.map +1 -0
  93. package/dist/diff/index.js +26 -0
  94. package/dist/diff/index.js.map +1 -0
  95. package/dist/diff/model-diff.d.ts +44 -0
  96. package/dist/diff/model-diff.d.ts.map +1 -0
  97. package/dist/diff/model-diff.js +153 -0
  98. package/dist/diff/model-diff.js.map +1 -0
  99. package/dist/diff/snapshot.d.ts +8 -0
  100. package/dist/diff/snapshot.d.ts.map +1 -0
  101. package/dist/diff/snapshot.js +50 -0
  102. package/dist/diff/snapshot.js.map +1 -0
  103. package/dist/env.d.ts +2 -0
  104. package/dist/env.d.ts.map +1 -0
  105. package/dist/env.js +44 -0
  106. package/dist/env.js.map +1 -0
  107. package/dist/index.d.ts +7 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +23 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/ir/naming.d.ts +12 -0
  112. package/dist/ir/naming.d.ts.map +1 -0
  113. package/dist/ir/naming.js +31 -0
  114. package/dist/ir/naming.js.map +1 -0
  115. package/dist/ir/types.d.ts +149 -0
  116. package/dist/ir/types.d.ts.map +1 -0
  117. package/dist/ir/types.js +72 -0
  118. package/dist/ir/types.js.map +1 -0
  119. package/dist/mcp/bench.d.ts +25 -0
  120. package/dist/mcp/bench.d.ts.map +1 -0
  121. package/dist/mcp/bench.js +115 -0
  122. package/dist/mcp/bench.js.map +1 -0
  123. package/dist/mcp/queries.d.ts +22 -0
  124. package/dist/mcp/queries.d.ts.map +1 -0
  125. package/dist/mcp/queries.js +147 -0
  126. package/dist/mcp/queries.js.map +1 -0
  127. package/dist/mcp/server.d.ts +2 -0
  128. package/dist/mcp/server.d.ts.map +1 -0
  129. package/dist/mcp/server.js +147 -0
  130. package/dist/mcp/server.js.map +1 -0
  131. package/dist/mcp/usage.d.ts +23 -0
  132. package/dist/mcp/usage.d.ts.map +1 -0
  133. package/dist/mcp/usage.js +125 -0
  134. package/dist/mcp/usage.js.map +1 -0
  135. package/dist/project/bpmn-parse.d.ts +17 -0
  136. package/dist/project/bpmn-parse.d.ts.map +1 -0
  137. package/dist/project/bpmn-parse.js +60 -0
  138. package/dist/project/bpmn-parse.js.map +1 -0
  139. package/dist/project/bpmn.d.ts +11 -0
  140. package/dist/project/bpmn.d.ts.map +1 -0
  141. package/dist/project/bpmn.js +89 -0
  142. package/dist/project/bpmn.js.map +1 -0
  143. package/dist/project/capability.d.ts +16 -0
  144. package/dist/project/capability.d.ts.map +1 -0
  145. package/dist/project/capability.js +38 -0
  146. package/dist/project/capability.js.map +1 -0
  147. package/dist/project/erd.d.ts +17 -0
  148. package/dist/project/erd.d.ts.map +1 -0
  149. package/dist/project/erd.js +0 -0
  150. package/dist/project/erd.js.map +1 -0
  151. package/dist/project/html.d.ts +12 -0
  152. package/dist/project/html.d.ts.map +1 -0
  153. package/dist/project/html.js +166 -0
  154. package/dist/project/html.js.map +1 -0
  155. package/dist/project/index.d.ts +19 -0
  156. package/dist/project/index.d.ts.map +1 -0
  157. package/dist/project/index.js +113 -0
  158. package/dist/project/index.js.map +1 -0
  159. package/dist/project/mermaid.d.ts +20 -0
  160. package/dist/project/mermaid.d.ts.map +1 -0
  161. package/dist/project/mermaid.js +89 -0
  162. package/dist/project/mermaid.js.map +1 -0
  163. package/dist/project/spec.d.ts +69 -0
  164. package/dist/project/spec.d.ts.map +1 -0
  165. package/dist/project/spec.js +164 -0
  166. package/dist/project/spec.js.map +1 -0
  167. package/dist/project/trust.d.ts +35 -0
  168. package/dist/project/trust.d.ts.map +1 -0
  169. package/dist/project/trust.js +48 -0
  170. package/dist/project/trust.js.map +1 -0
  171. package/dist/system.d.ts +61 -0
  172. package/dist/system.d.ts.map +1 -0
  173. package/dist/system.js +161 -0
  174. package/dist/system.js.map +1 -0
  175. package/package.json +58 -0
package/dist/cli.js ADDED
@@ -0,0 +1,787 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ /**
5
+ * Archmantic CLI (early scaffold).
6
+ *
7
+ * Commands (stubs unless noted):
8
+ * archmantic init [name] write an empty .archmantic/model.json [implemented]
9
+ * archmantic analyze run the tiered analysis pipeline [stub → M1]
10
+ * archmantic mcp start the MCP server over the model [stub → M5]
11
+ * archmantic view [name] preview a diagram [stub → M2]
12
+ * archmantic --version | --help
13
+ *
14
+ * Intentionally zero-dependency for now: builds with `tsc`, runs on plain Node.
15
+ */
16
+ const node_fs_1 = require("node:fs");
17
+ const node_path_1 = require("node:path");
18
+ const node_child_process_1 = require("node:child_process");
19
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
20
+ const pkg = require("../package.json");
21
+ const types_js_1 = require("./ir/types.js");
22
+ const index_js_1 = require("./analyze/index.js");
23
+ const tier2_js_1 = require("./analyze/tier2.js");
24
+ const incremental_js_1 = require("./analyze/incremental.js");
25
+ const index_js_2 = require("./project/index.js");
26
+ const env_js_1 = require("./env.js");
27
+ const auth_js_1 = require("./auth.js");
28
+ const agent_js_1 = require("./agent.js");
29
+ const system_js_1 = require("./system.js");
30
+ const index_js_3 = require("./cloud/index.js");
31
+ const server_js_1 = require("./mcp/server.js");
32
+ const usage_js_1 = require("./mcp/usage.js");
33
+ const bench_js_1 = require("./mcp/bench.js");
34
+ const index_js_4 = require("./diff/index.js");
35
+ const MODEL_DIR = ".archmantic";
36
+ const MODEL_FILE = "model.json";
37
+ function cmdInit(args) {
38
+ const project = args[0] ?? (0, node_path_1.basename)(process.cwd());
39
+ const dir = (0, node_path_1.join)(process.cwd(), MODEL_DIR);
40
+ const file = (0, node_path_1.join)(dir, MODEL_FILE);
41
+ if ((0, node_fs_1.existsSync)(file)) {
42
+ console.error(`✗ ${MODEL_DIR}/${MODEL_FILE} already exists — not overwriting.`);
43
+ return 1;
44
+ }
45
+ const model = { ...(0, types_js_1.createEmptyModel)(project), generatedAt: new Date().toISOString() };
46
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
47
+ (0, node_fs_1.writeFileSync)(file, (0, types_js_1.serializeModel)(model), "utf8");
48
+ console.log(`✓ Initialized Archmantic model for "${project}"`);
49
+ console.log(` → ${MODEL_DIR}/${MODEL_FILE}`);
50
+ console.log(` Next: \`archmantic analyze\` to reverse-engineer the model (coming in M1).`);
51
+ return 0;
52
+ }
53
+ function parseTier(args) {
54
+ const i = args.indexOf("--tier");
55
+ if (i !== -1 && args[i + 1])
56
+ return Number(args[i + 1]) || 1;
57
+ const inline = args.find((a) => a.startsWith("--tier="));
58
+ if (inline)
59
+ return Number(inline.split("=")[1]) || 1;
60
+ return 1;
61
+ }
62
+ async function cmdAnalyze(args) {
63
+ const root = process.cwd();
64
+ const tier = parseTier(args);
65
+ const model = { ...(0, index_js_1.analyzeRepo)(root), generatedAt: new Date().toISOString() };
66
+ const externalSystems = model.systems.filter((s) => s.kind === "external").length;
67
+ const internalDeps = model.relations.filter((r) => r.to.startsWith("comp:")).length;
68
+ const externalDeps = model.relations.filter((r) => r.to.startsWith("sys:ext:")).length;
69
+ console.log(`✓ Analyzed "${model.project}" (Tier 0 + Tier 1 + structural derivation)`);
70
+ console.log(` components: ${model.components.length}`);
71
+ console.log(` dependencies: ${internalDeps} internal, ${externalDeps} external`);
72
+ console.log(` external systems: ${externalSystems}`);
73
+ console.log(` capabilities: ${model.capabilities.length}`);
74
+ console.log(` processes: ${model.processes.length}, flows: ${model.flows.length}`);
75
+ if (tier >= 2) {
76
+ const t2 = await (0, tier2_js_1.tier2)(root, model);
77
+ if (!t2.ran) {
78
+ console.log(`\n⚠ Tier 2 (LLM) skipped: ${t2.reason}`);
79
+ }
80
+ else {
81
+ console.log(`\n✓ Tier 2 (LLM semantic pass)`);
82
+ console.log(` refined: ${t2.capabilitiesRefined} capabilities, ${t2.componentsRefined} components` +
83
+ `${t2.processRefined ? ", 1 process" : ""}`);
84
+ console.log(` LLM usage: ${t2.calls} calls · ${t2.inputTokens} in / ${t2.outputTokens} out tokens · ~$${t2.estCostUsd.toFixed(4)}`);
85
+ if (t2.reason)
86
+ console.log(` note: ${t2.reason}`);
87
+ }
88
+ }
89
+ const dir = (0, node_path_1.join)(root, MODEL_DIR);
90
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
91
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, MODEL_FILE), (0, types_js_1.serializeModel)(model), "utf8");
92
+ console.log(` → ${MODEL_DIR}/${MODEL_FILE}`);
93
+ console.log(` Every element is grounded with file:line provenance.`);
94
+ console.log(` Next: \`archmantic view\` for the capability map, diagrams & trust report.`);
95
+ return 0;
96
+ }
97
+ function cmdView() {
98
+ const file = (0, node_path_1.join)(process.cwd(), MODEL_DIR, MODEL_FILE);
99
+ if (!(0, node_fs_1.existsSync)(file)) {
100
+ console.error(`✗ No model found at ${MODEL_DIR}/${MODEL_FILE}.`);
101
+ console.error(` Run \`archmantic analyze\` first.`);
102
+ return 1;
103
+ }
104
+ let model;
105
+ try {
106
+ model = JSON.parse((0, node_fs_1.readFileSync)(file, "utf8"));
107
+ }
108
+ catch {
109
+ console.error(`✗ ${MODEL_DIR}/${MODEL_FILE} is not valid JSON — re-run \`archmantic analyze\`.`);
110
+ return 1;
111
+ }
112
+ console.log((0, index_js_2.terminalPreview)(model));
113
+ const dir = (0, node_path_1.join)(process.cwd(), MODEL_DIR);
114
+ const artifacts = (0, index_js_2.projectionArtifacts)(model);
115
+ for (const [name, content] of Object.entries(artifacts)) {
116
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, name), content, "utf8");
117
+ }
118
+ console.log(`\n${Object.keys(artifacts).length} projections written to ${MODEL_DIR}/`);
119
+ console.log(` Open ${MODEL_DIR}/view.html in a browser for the full interactive view.`);
120
+ return 0;
121
+ }
122
+ /** Drift (USP 4): the committed model snapshot vs a fresh analysis of the code. */
123
+ function cmdDrift(args) {
124
+ const check = args.includes("--check");
125
+ const root = process.cwd();
126
+ const file = (0, node_path_1.join)(root, MODEL_DIR, MODEL_FILE);
127
+ if (!(0, node_fs_1.existsSync)(file)) {
128
+ console.error(`✗ No committed model at ${MODEL_DIR}/${MODEL_FILE} to compare against.`);
129
+ console.error(` Run \`archmantic analyze\` (and commit the model) first.`);
130
+ return 1;
131
+ }
132
+ let snapshot;
133
+ try {
134
+ snapshot = JSON.parse((0, node_fs_1.readFileSync)(file, "utf8"));
135
+ }
136
+ catch {
137
+ console.error(`✗ ${MODEL_DIR}/${MODEL_FILE} is not valid JSON — re-run \`archmantic analyze\`.`);
138
+ return 1;
139
+ }
140
+ const fresh = (0, index_js_1.analyzeRepo)(root);
141
+ const diff = (0, index_js_4.diffModels)(snapshot, fresh, "committed model", "working tree");
142
+ console.log((0, index_js_4.renderDiffText)(diff));
143
+ if ((0, index_js_4.hasChanges)(diff)) {
144
+ console.log(`\nThe committed model is out of date. Run \`archmantic analyze\` to refresh it.`);
145
+ }
146
+ return check && (0, index_js_4.hasChanges)(diff) ? 1 : 0;
147
+ }
148
+ /** Pick a sensible base ref when none is given (a PR's target branch, usually). */
149
+ function defaultBaseRef(root) {
150
+ for (const ref of ["origin/main", "main", "origin/master", "master", "HEAD~1"]) {
151
+ try {
152
+ (0, index_js_4.resolveRef)(root, ref);
153
+ return ref;
154
+ }
155
+ catch {
156
+ /* try next */
157
+ }
158
+ }
159
+ return undefined;
160
+ }
161
+ /** PR architecture diff (USP 5): how the working tree reshapes a base ref. */
162
+ function cmdDiff(args) {
163
+ const root = process.cwd();
164
+ const baseRef = args.find((a) => !a.startsWith("-")) ?? defaultBaseRef(root);
165
+ if (!baseRef) {
166
+ console.error(`✗ No base ref to compare against (no main/master/previous commit found).`);
167
+ console.error(` Usage: archmantic diff [<git-ref>]`);
168
+ return 1;
169
+ }
170
+ let base;
171
+ try {
172
+ base = (0, index_js_4.analyzeAtRef)(root, baseRef);
173
+ }
174
+ catch (err) {
175
+ if (err instanceof index_js_4.GitRefError) {
176
+ console.error(`✗ ${err.message}`);
177
+ return 1;
178
+ }
179
+ throw err;
180
+ }
181
+ const head = (0, index_js_1.analyzeRepo)(root);
182
+ const diff = (0, index_js_4.diffModels)(base, head, baseRef, "working tree");
183
+ console.log((0, index_js_4.renderDiffText)(diff));
184
+ const dir = (0, node_path_1.join)(root, MODEL_DIR);
185
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
186
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "pr-diff.md"), (0, index_js_4.renderDiffMarkdown)(diff) + "\n", "utf8");
187
+ console.log(`\nMarkdown report (PR-comment ready) → ${MODEL_DIR}/pr-diff.md`);
188
+ return 0;
189
+ }
190
+ /** Architecture history: how the architecture changed over the last N commits. */
191
+ function cmdLog(args) {
192
+ const root = process.cwd();
193
+ const i = args.indexOf("-n");
194
+ const n = i !== -1 && args[i + 1] ? Math.max(1, Number(args[i + 1]) || 5) : 5;
195
+ let changes;
196
+ try {
197
+ changes = (0, index_js_4.architectureLog)(root, n);
198
+ }
199
+ catch (err) {
200
+ console.error(`✗ ${err instanceof Error ? err.message : String(err)}`);
201
+ return 1;
202
+ }
203
+ if (!changes.length) {
204
+ console.log("Not enough commit history to show architecture changes.");
205
+ return 0;
206
+ }
207
+ const DIM = "\x1b[2m";
208
+ const BOLD = "\x1b[1m";
209
+ const GREEN = "\x1b[32m";
210
+ const RESET = "\x1b[0m";
211
+ console.log(`${BOLD}Architecture history${RESET} ${DIM}(last ${changes.length} commits, newest first)${RESET}\n`);
212
+ for (const c of changes) {
213
+ const summary = (0, index_js_4.summarizeChange)(c.diff);
214
+ console.log(`${BOLD}${c.sha.slice(0, 7)}${RESET} ${c.subject}`);
215
+ console.log(` ${(0, index_js_4.hasChanges)(c.diff) ? GREEN + summary + RESET : DIM + summary + RESET} ${DIM}(${c.diff.driftPct}% drift)${RESET}`);
216
+ }
217
+ return 0;
218
+ }
219
+ function printHookSnippet() {
220
+ console.log(`# Keep the Archmantic model in sync on every commit.
221
+ # Save as .git/hooks/pre-commit and \`chmod +x\` it:
222
+
223
+ #!/bin/sh
224
+ npx archmantic update >/dev/null 2>&1
225
+ git add .archmantic/model.json`);
226
+ }
227
+ /** M6: git-diff-driven incremental re-analysis — patch the IR, refresh projections, fast. */
228
+ function cmdUpdate(args) {
229
+ if (args.includes("--hook")) {
230
+ printHookSnippet();
231
+ return 0;
232
+ }
233
+ const root = process.cwd();
234
+ const file = (0, node_path_1.join)(root, MODEL_DIR, MODEL_FILE);
235
+ if (!(0, node_fs_1.existsSync)(file)) {
236
+ console.error(`✗ No model at ${MODEL_DIR}/${MODEL_FILE}. Run \`archmantic analyze\` first.`);
237
+ return 1;
238
+ }
239
+ let base;
240
+ try {
241
+ base = JSON.parse((0, node_fs_1.readFileSync)(file, "utf8"));
242
+ }
243
+ catch {
244
+ console.error(`✗ ${MODEL_DIR}/${MODEL_FILE} is not valid JSON — run \`archmantic analyze\`.`);
245
+ return 1;
246
+ }
247
+ const start = Date.now();
248
+ const { model: updated, recomputed, removed, fullFallback } = (0, incremental_js_1.incrementalUpdate)(root, base);
249
+ const model = { ...updated, generatedAt: new Date().toISOString() };
250
+ const ms = Date.now() - start;
251
+ const dir = (0, node_path_1.join)(root, MODEL_DIR);
252
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
253
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, MODEL_FILE), (0, types_js_1.serializeModel)(model), "utf8");
254
+ for (const [name, content] of Object.entries((0, index_js_2.projectionArtifacts)(model))) {
255
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, name), content, "utf8");
256
+ }
257
+ console.log(`✓ Incremental update${fullFallback ? " (no git — full recompute)" : ""}`);
258
+ console.log(` recomputed ${recomputed.length} of ${model.components.length} files` +
259
+ (removed.length ? `, removed ${removed.length}` : "") +
260
+ ` in ${ms}ms`);
261
+ const diff = (0, index_js_4.diffModels)(base, model, "previous model", "updated");
262
+ console.log((0, index_js_4.hasChanges)(diff) ? "\n" + (0, index_js_4.renderDiffText)(diff) : " No architecture changes since the last model.");
263
+ console.log(`\n → refreshed ${MODEL_DIR}/${MODEL_FILE} + projections (\`archmantic update --hook\` for a git hook)`);
264
+ return 0;
265
+ }
266
+ /** Start the MCP server over stdio (USP 7). Stays alive until the client disconnects. */
267
+ async function cmdMcp() {
268
+ await (0, server_js_1.startMcpServer)(process.cwd());
269
+ return new Promise(() => { }); // never resolve — keep the process alive for stdio
270
+ }
271
+ /** Token-savings benchmark: MCP queries vs raw file reads (the second proof). */
272
+ async function cmdBench(args) {
273
+ const root = process.cwd();
274
+ const file = (0, node_path_1.join)(root, MODEL_DIR, MODEL_FILE);
275
+ if (!(0, node_fs_1.existsSync)(file)) {
276
+ console.error(`✗ No model at ${MODEL_DIR}/${MODEL_FILE}. Run \`archmantic analyze\` first.`);
277
+ return 1;
278
+ }
279
+ const model = JSON.parse((0, node_fs_1.readFileSync)(file, "utf8"));
280
+ let counter = bench_js_1.estimateCounter;
281
+ let mode = "estimate";
282
+ if (args.includes("--exact")) {
283
+ if (!(0, auth_js_1.hasAnthropicCredentials)()) {
284
+ console.log(`⚠ --exact needs a credential (${auth_js_1.NO_CREDENTIAL_HINT}); using offline estimate instead.\n`);
285
+ }
286
+ else {
287
+ const { default: Anthropic } = await import("@anthropic-ai/sdk");
288
+ const client = new Anthropic();
289
+ counter = async (t) => t ? (await client.messages.countTokens({ model: "claude-opus-4-8", messages: [{ role: "user", content: t }] })).input_tokens : 0;
290
+ mode = "exact";
291
+ }
292
+ }
293
+ console.log((0, bench_js_1.renderBench)(await (0, bench_js_1.runBenchmark)(root, model, counter, mode)));
294
+ return 0;
295
+ }
296
+ /** Emit an agent-consumable build spec (Markdown + JSON) from the model. */
297
+ function cmdSpec() {
298
+ const root = process.cwd();
299
+ const file = (0, node_path_1.join)(root, MODEL_DIR, MODEL_FILE);
300
+ if (!(0, node_fs_1.existsSync)(file)) {
301
+ console.error(`✗ No model at ${MODEL_DIR}/${MODEL_FILE}. Run \`archmantic analyze\` first.`);
302
+ return 1;
303
+ }
304
+ let model;
305
+ try {
306
+ model = JSON.parse((0, node_fs_1.readFileSync)(file, "utf8"));
307
+ }
308
+ catch {
309
+ console.error(`✗ ${MODEL_DIR}/${MODEL_FILE} is not valid JSON — run \`archmantic analyze\`.`);
310
+ return 1;
311
+ }
312
+ const dir = (0, node_path_1.join)(root, MODEL_DIR);
313
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
314
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "build-spec.md"), (0, index_js_2.buildSpecMarkdown)(model) + "\n", "utf8");
315
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "build-spec.json"), JSON.stringify((0, index_js_2.buildSpecJson)(model), null, 2) + "\n", "utf8");
316
+ console.log(`✓ Build spec for "${model.project}"`);
317
+ console.log(` ${model.capabilities.length} capabilities, ${model.components.length} components`);
318
+ console.log(` → ${MODEL_DIR}/build-spec.md (hand to a coding agent to implement/verify)`);
319
+ console.log(` → ${MODEL_DIR}/build-spec.json (machine-readable)`);
320
+ return 0;
321
+ }
322
+ /** Default verification command for the autonomous build, from package.json scripts. */
323
+ function defaultCheckCommand(root) {
324
+ try {
325
+ const pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(root, "package.json"), "utf8"));
326
+ const s = pkg.scripts ?? {};
327
+ const parts = [];
328
+ if (s.build)
329
+ parts.push("npm run build");
330
+ if (s.test)
331
+ parts.push("npm test");
332
+ if (parts.length)
333
+ return parts.join(" && ");
334
+ }
335
+ catch {
336
+ /* fall through */
337
+ }
338
+ return "npm run build";
339
+ }
340
+ /** Multi-repo unified system view across several repos' committed models. */
341
+ function cmdSystem(args) {
342
+ const root = process.cwd();
343
+ const ri = args.indexOf("--repos");
344
+ const reposArg = ri !== -1 ? args[ri + 1] : undefined;
345
+ if (!reposArg) {
346
+ console.error(`✗ Usage: archmantic system [name] --repos <pathA,pathB,...>`);
347
+ console.error(` Each repo needs a committed ${MODEL_DIR}/${MODEL_FILE} (run \`archmantic analyze\` there).`);
348
+ console.error(` Declare links per repo in ${MODEL_DIR}/config.json: { "system": "...", "consumes": ["other-service"] }`);
349
+ return 1;
350
+ }
351
+ const models = [];
352
+ for (const p of reposArg.split(",").map((s) => s.trim()).filter(Boolean)) {
353
+ const mf = (0, node_path_1.join)(p, MODEL_DIR, MODEL_FILE);
354
+ if (!(0, node_fs_1.existsSync)(mf)) {
355
+ console.error(` ⚠ skipping ${p}: no ${MODEL_DIR}/${MODEL_FILE} (run \`archmantic analyze\` there)`);
356
+ continue;
357
+ }
358
+ try {
359
+ models.push(JSON.parse((0, node_fs_1.readFileSync)(mf, "utf8")));
360
+ }
361
+ catch {
362
+ console.error(` ⚠ skipping ${p}: invalid model.json`);
363
+ }
364
+ }
365
+ if (!models.length) {
366
+ console.error(`✗ No valid repo models found.`);
367
+ return 1;
368
+ }
369
+ const name = args.find((a) => !a.startsWith("--") && a !== reposArg) ?? models.find((m) => m.system)?.system ?? "system";
370
+ const view = (0, system_js_1.buildSystemView)(models, name);
371
+ const dir = (0, node_path_1.join)(root, MODEL_DIR);
372
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
373
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "system-context.mmd"), view.mermaid + "\n", "utf8");
374
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "system.html"), (0, system_js_1.systemHtml)(view), "utf8");
375
+ console.log(`✓ Unified system view: "${name}"`);
376
+ console.log(` ${view.totals.services} services · ${view.totals.components} components · ${view.totals.capabilities} capabilities`);
377
+ for (const s of view.services) {
378
+ console.log(` • ${s.project} (${s.components} comp, ${s.capabilities} cap)${s.consumes.length ? ` → ${s.consumes.join(", ")}` : ""}`);
379
+ }
380
+ if (view.crossServiceEdges.length) {
381
+ console.log(` cross-service calls: ${view.crossServiceEdges.map((e) => `${e.from}→${e.to}`).join(", ")}`);
382
+ }
383
+ const GREEN = "\x1b[32m";
384
+ const YELLOW = "\x1b[33m";
385
+ const RED = "\x1b[31m";
386
+ const DIM = "\x1b[2m";
387
+ const RESET = "\x1b[0m";
388
+ const la = (0, system_js_1.analyzeLinks)(models);
389
+ if (la.counts.inferred || la.counts.dangling) {
390
+ console.log(`\n Cross-repo links: ${GREEN}${la.counts.connected} connected${RESET} · ${YELLOW}${la.counts.inferred} inferred${RESET} · ${RED}${la.counts.dangling} dangling${RESET}`);
391
+ for (const l of la.links.filter((l) => l.status === "inferred")) {
392
+ console.log(` ${YELLOW}? ${l.from} → ${l.to}${RESET} ${DIM}${l.reason}${RESET}`);
393
+ }
394
+ for (const l of la.links.filter((l) => l.status === "dangling")) {
395
+ console.log(` ${RED}⚠ ${l.from} → ${l.to}${RESET} ${DIM}${l.reason}${RESET}`);
396
+ }
397
+ }
398
+ console.log(` → ${MODEL_DIR}/system.html (open in a browser) + system-context.mmd`);
399
+ return 0;
400
+ }
401
+ /** Agent hand-off: run the build spec through Claude. Plan-only, or --apply to edit the repo. */
402
+ async function cmdHandoff(args) {
403
+ const root = process.cwd();
404
+ const file = (0, node_path_1.join)(root, MODEL_DIR, MODEL_FILE);
405
+ if (!(0, node_fs_1.existsSync)(file)) {
406
+ console.error(`✗ No model at ${MODEL_DIR}/${MODEL_FILE}. Run \`archmantic analyze\` first.`);
407
+ return 1;
408
+ }
409
+ let model;
410
+ try {
411
+ model = JSON.parse((0, node_fs_1.readFileSync)(file, "utf8"));
412
+ }
413
+ catch {
414
+ console.error(`✗ ${MODEL_DIR}/${MODEL_FILE} is not valid JSON — run \`archmantic analyze\`.`);
415
+ return 1;
416
+ }
417
+ const spec = (0, index_js_2.buildSpecMarkdown)(model);
418
+ if (args.includes("--apply")) {
419
+ const ci = args.indexOf("--check");
420
+ const checkCommand = ci !== -1 && args[ci + 1] ? args[ci + 1] : defaultCheckCommand(root);
421
+ console.log(`⚠ Autonomous build: an agent will EDIT files in this repo to realize the model.`);
422
+ console.log(` Commit or stash first; review with \`git diff\` afterward.`);
423
+ console.log(` Verification: ${checkCommand}\n`);
424
+ const r = await (0, agent_js_1.runAutonomousBuild)(root, spec, model.project, checkCommand);
425
+ if (!r.ran) {
426
+ console.log(`⚠ Autonomous build skipped: ${r.reason}`);
427
+ return 0;
428
+ }
429
+ console.log(`\n✓ Autonomous build — ${r.filesChanged.length} file(s) changed in ${r.turns} turn(s)`);
430
+ for (const f of r.filesChanged)
431
+ console.log(` • ${f}`);
432
+ if (r.checkPassed === true)
433
+ console.log(` ✓ verification passed`);
434
+ else if (r.checkPassed === false)
435
+ console.log(` ⚠ verification still failing — review the diff and output`);
436
+ console.log(` LLM: ${r.inputTokens} in / ${r.outputTokens} out tokens · ~$${r.estCostUsd.toFixed(4)}`);
437
+ if (r.summary)
438
+ console.log(`\n${r.summary}`);
439
+ console.log(`\n Review with \`git diff\` before committing.`);
440
+ return 0;
441
+ }
442
+ const r = await (0, agent_js_1.runHandoff)(spec, model.project);
443
+ if (!r.ran) {
444
+ console.log(`⚠ Agent hand-off skipped: ${r.reason}`);
445
+ return 0;
446
+ }
447
+ const dir = (0, node_path_1.join)(root, MODEL_DIR);
448
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
449
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "build-plan.md"), (r.plan ?? "") + "\n", "utf8");
450
+ console.log(`✓ Agent hand-off — implementation plan for "${model.project}"`);
451
+ console.log(` LLM: ${r.inputTokens} in / ${r.outputTokens} out tokens · ~$${r.estCostUsd.toFixed(4)}`);
452
+ console.log(` → ${MODEL_DIR}/build-plan.md (hand to a coding agent, or run \`handoff --apply\`)`);
453
+ return 0;
454
+ }
455
+ /** Edit-then-build: merge a human BPMN canvas edit back into the IR's process. */
456
+ async function cmdApply(args) {
457
+ const root = process.cwd();
458
+ const file = (0, node_path_1.join)(root, MODEL_DIR, MODEL_FILE);
459
+ if (!(0, node_fs_1.existsSync)(file)) {
460
+ console.error(`✗ No model at ${MODEL_DIR}/${MODEL_FILE}. Run \`archmantic analyze\` first.`);
461
+ return 1;
462
+ }
463
+ let model;
464
+ try {
465
+ model = JSON.parse((0, node_fs_1.readFileSync)(file, "utf8"));
466
+ }
467
+ catch {
468
+ console.error(`✗ ${MODEL_DIR}/${MODEL_FILE} is not valid JSON — run \`archmantic analyze\`.`);
469
+ return 1;
470
+ }
471
+ // Edit source: a local .bpmn file (self-host) or the saved cloud canvas edit.
472
+ const fromIdx = args.indexOf("--from");
473
+ const fromFile = fromIdx !== -1 ? args[fromIdx + 1] : undefined;
474
+ let xml = null;
475
+ if (fromFile) {
476
+ if (!(0, node_fs_1.existsSync)(fromFile)) {
477
+ console.error(`✗ File not found: ${fromFile}`);
478
+ return 1;
479
+ }
480
+ xml = (0, node_fs_1.readFileSync)(fromFile, "utf8");
481
+ }
482
+ else if ((0, index_js_3.hasApiToken)()) {
483
+ try {
484
+ xml = await (0, index_js_3.pullProcessEditApi)(model.project);
485
+ }
486
+ catch (err) {
487
+ if (err instanceof index_js_3.ApiError) {
488
+ console.error(`✗ ${err.message}`);
489
+ return 1;
490
+ }
491
+ throw err;
492
+ }
493
+ }
494
+ else {
495
+ console.error(`✗ No edit source. Pass \`--from <file.bpmn>\`, or set ARCHMANTIC_TOKEN to fetch your saved canvas edit.`);
496
+ return 1;
497
+ }
498
+ if (!xml) {
499
+ console.log(`No saved canvas edit for "${model.project}". Edit the process in the web app and Save first.`);
500
+ return 0;
501
+ }
502
+ const parsed = (0, index_js_2.parseBpmnProcess)(xml);
503
+ if (!parsed || !parsed.tasks.length) {
504
+ console.error(`✗ Could not parse a process from the BPMN.`);
505
+ return 1;
506
+ }
507
+ const human = { source: "human", ref: "canvas-edit", confidence: 1 };
508
+ const procId = model.processes[0]?.id ?? `proc:${model.project}`;
509
+ model.processes = [
510
+ {
511
+ id: procId,
512
+ name: parsed.name,
513
+ description: "Human-edited process (from the BPMN canvas).",
514
+ tasks: parsed.tasks.map((t, i) => ({ id: `task:edit:${i + 1}`, name: t.name, provenance: [human] })),
515
+ provenance: [human],
516
+ confidence: 1,
517
+ },
518
+ ];
519
+ const dir = (0, node_path_1.join)(root, MODEL_DIR);
520
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
521
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, MODEL_FILE), (0, types_js_1.serializeModel)({ ...model, generatedAt: new Date().toISOString() }), "utf8");
522
+ console.log(`✓ Applied canvas edit to "${model.project}" — process "${parsed.name}" (${parsed.tasks.length} steps), human-authored.`);
523
+ console.log(` Steps: ${parsed.tasks.map((t) => t.name).join(" → ")}`);
524
+ console.log(` Next: \`archmantic spec\` to emit a build spec reflecting your edit.`);
525
+ return 0;
526
+ }
527
+ // ── Cloud knowledge (shared team model over Neon) ────────────────────────────
528
+ function currentCommit(root) {
529
+ try {
530
+ return (0, node_child_process_1.execFileSync)("git", ["-C", root, "rev-parse", "HEAD"], { encoding: "utf8" }).trim();
531
+ }
532
+ catch {
533
+ return "working-tree";
534
+ }
535
+ }
536
+ function resolveProject(root) {
537
+ const mf = (0, node_path_1.join)(root, MODEL_DIR, MODEL_FILE);
538
+ if ((0, node_fs_1.existsSync)(mf)) {
539
+ try {
540
+ return JSON.parse((0, node_fs_1.readFileSync)(mf, "utf8")).project;
541
+ }
542
+ catch {
543
+ /* fall through */
544
+ }
545
+ }
546
+ const pkg = (0, node_path_1.join)(root, "package.json");
547
+ if ((0, node_fs_1.existsSync)(pkg)) {
548
+ try {
549
+ const name = JSON.parse((0, node_fs_1.readFileSync)(pkg, "utf8")).name;
550
+ if (name)
551
+ return name;
552
+ }
553
+ catch {
554
+ /* fall through */
555
+ }
556
+ }
557
+ return (0, node_path_1.basename)(root);
558
+ }
559
+ /** Push the committed model to the shared cloud store under the current commit. */
560
+ async function cmdPush() {
561
+ const root = process.cwd();
562
+ const file = (0, node_path_1.join)(root, MODEL_DIR, MODEL_FILE);
563
+ if (!(0, node_fs_1.existsSync)(file)) {
564
+ console.error(`✗ No model at ${MODEL_DIR}/${MODEL_FILE}. Run \`archmantic analyze\` first.`);
565
+ return 1;
566
+ }
567
+ let model;
568
+ try {
569
+ model = JSON.parse((0, node_fs_1.readFileSync)(file, "utf8"));
570
+ }
571
+ catch {
572
+ console.error(`✗ ${MODEL_DIR}/${MODEL_FILE} is not valid JSON — run \`archmantic analyze\`.`);
573
+ return 1;
574
+ }
575
+ const commit = currentCommit(root);
576
+ const viaApi = (0, index_js_3.hasApiToken)();
577
+ try {
578
+ if (viaApi)
579
+ await (0, index_js_3.pushModelApi)(model, commit);
580
+ else
581
+ await (0, index_js_3.pushModel)(model, commit);
582
+ }
583
+ catch (err) {
584
+ if (err instanceof index_js_3.NoDatabaseError || err instanceof index_js_3.ApiError) {
585
+ console.error(`✗ ${err.message}`);
586
+ return 1;
587
+ }
588
+ throw err;
589
+ }
590
+ console.log(`✓ Pushed "${model.project}" @ ${commit.slice(0, 7)} ${viaApi ? "via the Archmantic API (org-scoped)" : "to the cloud store (direct)"}.`);
591
+ console.log(` Teammates can \`archmantic pull\` to get the shared model.`);
592
+ return 0;
593
+ }
594
+ /** Pull the latest shared model from the cloud into .archmantic/model.json. */
595
+ async function cmdPull() {
596
+ const root = process.cwd();
597
+ const project = resolveProject(root);
598
+ let model;
599
+ try {
600
+ model = (0, index_js_3.hasApiToken)() ? await (0, index_js_3.pullLatestApi)(project) : await (0, index_js_3.pullLatest)(project);
601
+ }
602
+ catch (err) {
603
+ if (err instanceof index_js_3.NoDatabaseError || err instanceof index_js_3.ApiError) {
604
+ console.error(`✗ ${err.message}`);
605
+ return 1;
606
+ }
607
+ throw err;
608
+ }
609
+ if (!model) {
610
+ console.log(`No shared model for "${project}" yet. Run \`archmantic push\` first.`);
611
+ return 0;
612
+ }
613
+ const dir = (0, node_path_1.join)(root, MODEL_DIR);
614
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
615
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, MODEL_FILE), (0, types_js_1.serializeModel)(model), "utf8");
616
+ console.log(`✓ Pulled "${project}" → ${MODEL_DIR}/${MODEL_FILE} (${model.components.length} components, ${model.capabilities.length} capabilities)`);
617
+ console.log(` Run \`archmantic view\` to render it.`);
618
+ return 0;
619
+ }
620
+ /** List the per-commit snapshots stored in the cloud for this project. */
621
+ async function cmdCloudLog() {
622
+ const root = process.cwd();
623
+ const project = resolveProject(root);
624
+ let snaps;
625
+ try {
626
+ snaps = await (0, index_js_3.history)(project);
627
+ }
628
+ catch (err) {
629
+ if (err instanceof index_js_3.NoDatabaseError) {
630
+ console.error(`✗ ${err.message}`);
631
+ return 1;
632
+ }
633
+ throw err;
634
+ }
635
+ if (!snaps.length) {
636
+ console.log(`No cloud snapshots for "${project}" yet.`);
637
+ return 0;
638
+ }
639
+ console.log(`Cloud knowledge history for "${project}" (${snaps.length} snapshots, newest first):`);
640
+ for (const s of snaps)
641
+ console.log(` ${s.commit_sha.slice(0, 7)} pushed ${s.pushed_at}`);
642
+ return 0;
643
+ }
644
+ function notImplemented(name, milestone) {
645
+ console.log(`\`archmantic ${name}\` is not implemented yet (planned for ${milestone}).`);
646
+ console.log("See docs/MVP_PLAN.md for the roadmap.");
647
+ return 0;
648
+ }
649
+ /** Show local MCP usage stats; `--sync` re-pushes the local log to the cloud. */
650
+ async function cmdUsage(args) {
651
+ const root = process.cwd();
652
+ const events = (0, usage_js_1.readUsageLog)(root);
653
+ if (!events.length) {
654
+ console.log(`No MCP usage recorded yet (${MODEL_DIR}/usage.jsonl is empty).`);
655
+ console.log(` Usage is recorded automatically while \`archmantic mcp\` serves an agent.`);
656
+ return 0;
657
+ }
658
+ const calls = events.length;
659
+ const tokensOut = events.reduce((n, e) => n + e.tokensOut, 0);
660
+ const tokensSaved = events.reduce((n, e) => n + e.tokensSaved, 0);
661
+ const savedPct = tokensOut + tokensSaved === 0 ? 0 : Math.round((tokensSaved / (tokensOut + tokensSaved)) * 1000) / 10;
662
+ const byTool = new Map();
663
+ for (const e of events) {
664
+ const t = byTool.get(e.tool) ?? { calls: 0, saved: 0 };
665
+ t.calls++;
666
+ t.saved += e.tokensSaved;
667
+ byTool.set(e.tool, t);
668
+ }
669
+ const BOLD = "\x1b[1m";
670
+ const DIM = "\x1b[2m";
671
+ const GREEN = "\x1b[32m";
672
+ const RESET = "\x1b[0m";
673
+ console.log(`${BOLD}MCP usage${RESET} ${DIM}— proof your agents read the model, not the files${RESET}`);
674
+ console.log(` ${BOLD}${calls}${RESET} tool calls · ${tokensOut.toLocaleString()} tokens served · ` +
675
+ `${GREEN}${BOLD}~${tokensSaved.toLocaleString()} tokens saved${RESET} ${DIM}(${savedPct}% fewer vs reading files)${RESET}`);
676
+ console.log(`\n ${BOLD}By tool${RESET}`);
677
+ for (const [tool, t] of [...byTool.entries()].sort((a, b) => b[1].calls - a[1].calls)) {
678
+ console.log(` ${tool.padEnd(20)} ${String(t.calls).padStart(4)} calls ${DIM}~${t.saved.toLocaleString()} saved${RESET}`);
679
+ }
680
+ if (args.includes("--sync")) {
681
+ const viaApi = (0, index_js_3.hasApiToken)();
682
+ if (!viaApi && !process.env.DATABASE_URL) {
683
+ console.error(`\n✗ No cloud credentials — set ARCHMANTIC_TOKEN or DATABASE_URL to sync.`);
684
+ return 1;
685
+ }
686
+ try {
687
+ if (viaApi)
688
+ await (0, index_js_3.recordUsageApi)(events);
689
+ else
690
+ await (0, index_js_3.recordUsage)(events);
691
+ }
692
+ catch (err) {
693
+ if (err instanceof index_js_3.NoDatabaseError || err instanceof index_js_3.ApiError) {
694
+ console.error(`\n✗ ${err.message}`);
695
+ return 1;
696
+ }
697
+ throw err;
698
+ }
699
+ console.log(`\n✓ Synced ${calls} events to the cloud ${viaApi ? "(org-scoped API)" : "(direct)"} — see the web /usage dashboard.`);
700
+ }
701
+ return 0;
702
+ }
703
+ function printHelp() {
704
+ console.log(`Archmantic v${pkg.version} — living architecture model for humans + agents
705
+
706
+ Usage: archmantic <command> [options] (short alias: amt)
707
+
708
+ Commands:
709
+ init [name] Create an empty .archmantic/model.json (defaults name to the folder)
710
+ analyze [--tier N] Reverse-engineer the model (--tier 2 adds the LLM pass, BYOK)
711
+ update [--hook] Incrementally re-analyze only what changed (git-diff driven)
712
+ view Capability map + diagrams + trust report (writes view.html)
713
+ spec Emit an agent-ready build spec (build-spec.md + .json)
714
+ apply [--from f] Merge a human BPMN canvas edit back into the model (edit-then-build)
715
+ handoff [--apply] [--check "<cmd>"] Build spec → plan; --apply: agent edits repo + self-verifies (BYOK)
716
+ system [name] --repos a,b,c Unified cross-service view across multiple repos
717
+ drift [--check] Compare the committed model vs the code (--check exits 1 on drift)
718
+ diff [<ref>] Architecture diff: a git ref → working tree (writes pr-diff.md)
719
+ log [-n N] Architecture history: how the architecture changed per commit
720
+ mcp Start the MCP server exposing the model to AI agents (stdio)
721
+ bench [--exact] Token-savings benchmark: MCP queries vs raw file reads
722
+ push Share the model to the team cloud store (Neon) @ this commit
723
+ pull Fetch the team's latest shared model into .archmantic/
724
+ cloud-log List per-commit snapshots stored in the cloud
725
+ usage [--sync] MCP usage + token savings (--sync pushes the local log to the cloud)
726
+
727
+ Options:
728
+ -v, --version Print version
729
+ -h, --help Show this help`);
730
+ }
731
+ async function main(argv) {
732
+ const [command, ...rest] = argv;
733
+ if (command === "-v" || command === "--version") {
734
+ console.log(pkg.version);
735
+ return 0;
736
+ }
737
+ if (!command || command === "-h" || command === "--help" || command === "help") {
738
+ printHelp();
739
+ return 0;
740
+ }
741
+ (0, env_js_1.loadEnv)(process.cwd());
742
+ switch (command) {
743
+ case "init":
744
+ return cmdInit(rest);
745
+ case "analyze":
746
+ return cmdAnalyze(rest);
747
+ case "update":
748
+ return cmdUpdate(rest);
749
+ case "mcp":
750
+ return cmdMcp();
751
+ case "bench":
752
+ return cmdBench(rest);
753
+ case "push":
754
+ return cmdPush();
755
+ case "pull":
756
+ return cmdPull();
757
+ case "cloud-log":
758
+ return cmdCloudLog();
759
+ case "usage":
760
+ return cmdUsage(rest);
761
+ case "view":
762
+ return cmdView();
763
+ case "spec":
764
+ return cmdSpec();
765
+ case "apply":
766
+ return cmdApply(rest);
767
+ case "handoff":
768
+ return cmdHandoff(rest);
769
+ case "system":
770
+ return cmdSystem(rest);
771
+ case "drift":
772
+ return cmdDrift(rest);
773
+ case "diff":
774
+ return cmdDiff(rest);
775
+ case "log":
776
+ return cmdLog(rest);
777
+ default:
778
+ console.error(`Unknown command: ${command}\n`);
779
+ printHelp();
780
+ return 1;
781
+ }
782
+ }
783
+ main(process.argv.slice(2)).then((code) => process.exit(code), (err) => {
784
+ console.error(err instanceof Error ? err.message : err);
785
+ process.exit(1);
786
+ });
787
+ //# sourceMappingURL=cli.js.map