cdalkit 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,1403 +1,91 @@
1
- // src/cli.ts
2
- import { createRequire } from "module";
3
- import { runMain as cittyRunMain, defineCommand as defineCommand14 } from "citty";
1
+ import {
2
+ BootstrapError,
3
+ installProWithCore
4
+ } from "./chunk-22BBUYVB.js";
4
5
 
5
- // src/commands/audit.ts
6
- import { writeFileSync } from "fs";
7
- import { resolve } from "path";
8
- import { renderHtmlReport, renderTerminalReport, runAudit } from "@cdal/audit";
9
- import { defineCommand } from "citty";
6
+ // src/cli.ts
7
+ import { auditCommand } from "@cdal/audit/command";
8
+ import { runMain as cittyRunMain, defineCommand } from "citty";
10
9
  import pc from "picocolors";
11
- var auditCommand = defineCommand({
12
- meta: {
13
- name: "audit",
14
- description: "Audit repository for AI agent hygiene, type silencing, test isolation and gates (100% offline)"
15
- },
16
- args: {
17
- path: {
18
- type: "positional",
19
- description: "Path to repository root to audit",
20
- required: false,
21
- default: "."
22
- },
23
- html: {
24
- type: "string",
25
- description: "Path to save standalone single-file HTML report (e.g. audit-report.html)",
26
- required: false
27
- },
28
- json: {
29
- type: "boolean",
30
- description: "Output machine-readable JSON report (schema: audit.v1)",
31
- default: false
32
- },
33
- lang: {
34
- type: "string",
35
- description: "Report language (en or pl)",
36
- default: "en"
37
- },
38
- failUnder: {
39
- type: "string",
40
- description: "Exit with code 1 if audit score is below this threshold (0-100)",
41
- required: false
42
- }
43
- },
44
- async run({ args }) {
45
- const targetDir = resolve(args.path || ".");
46
- const lang = args.lang === "pl" ? "pl" : "en";
47
- if (!args.json) {
48
- console.log(pc.bold(pc.cyan("\n\u{1F50D} Running CDAL Repository AI Hygiene Audit...\n")));
49
- }
50
- const report = await runAudit({
51
- cwd: targetDir,
52
- lang
53
- });
54
- if (args.html) {
55
- const htmlContent = renderHtmlReport(report, lang);
56
- const outPath = resolve(args.html);
57
- writeFileSync(outPath, htmlContent, "utf8");
58
- if (!args.json) {
59
- console.log(pc.green(` \u2714 Wygenerowano raport HTML: ${outPath}`));
60
- }
61
- }
62
- if (args.json) {
63
- console.log(JSON.stringify(report, null, 2));
64
- } else {
65
- console.log(renderTerminalReport(report, lang));
66
- }
67
- if (args.failUnder) {
68
- const threshold = Number.parseInt(args.failUnder, 10);
69
- if (!Number.isNaN(threshold) && report.score < threshold) {
70
- console.error(
71
- pc.red(
72
- `
73
- \u274C Audit score ${report.score} is below threshold ${threshold}. Failing quality gate.`
74
- )
75
- );
76
- process.exit(1);
77
- }
78
- }
79
- }
80
- });
81
-
82
- // src/commands/codegen.ts
83
- import { runCodegen } from "@cdal/core";
84
- import { defineCommand as defineCommand2 } from "citty";
85
- import pc2 from "picocolors";
86
-
87
- // src/kinds.ts
88
- import { loadConfig } from "@cdal/core";
89
- import { policies, requirements, stateMachine } from "@cdal/kinds";
90
- async function resolveCommandKinds(cwd = process.cwd()) {
91
- const { config } = await loadConfig(cwd);
92
- const configured = (config.kinds ?? []).filter(
93
- (kind) => typeof kind.load === "function"
94
- );
95
- if (configured.length > 0) return configured;
96
- return [requirements(), stateMachine(), policies()];
97
- }
98
-
99
- // src/commands/codegen.ts
100
- var codegenCommand = defineCommand2({
101
- meta: {
102
- name: "codegen",
103
- description: "Emit TypeScript types and documentation from contracts (with --check drift detection)"
104
- },
105
- args: {
106
- check: {
107
- type: "boolean",
108
- description: "Check for drift between contracts and generated files without modifying disk",
109
- default: false
110
- },
111
- dir: {
112
- type: "string",
113
- description: "Custom path to contracts directory"
114
- }
115
- },
116
- async run({ args }) {
117
- try {
118
- const kinds = await resolveCommandKinds();
119
- const res = await runCodegen({
120
- contractsDir: args.dir,
121
- check: Boolean(args.check),
122
- kinds
123
- });
124
- if (args.check) {
125
- if (!res.drift) {
126
- console.log(pc2.green("\u2705 Codegen check: all generated files are in sync byte-for-byte."));
127
- } else {
128
- console.error(pc2.red("\u274C Codegen check failed: drift detected in generated files:"));
129
- for (const f of res.files) {
130
- if (f.status === "drift") {
131
- console.error(pc2.red(` - [DRIFT] ${f.path} (${f.fullPath})`));
132
- } else if (f.status === "missing") {
133
- console.error(pc2.red(` - [MISSING] ${f.path} (${f.fullPath})`));
134
- }
135
- }
136
- console.error(
137
- pc2.yellow("\nRun `cdal codegen` to synchronize generated files with contracts.")
138
- );
139
- process.exit(1);
140
- }
141
- } else {
142
- console.log(pc2.green(`\u2705 Emitted ${res.files.length} contract artifact(s):`));
143
- for (const f of res.files) {
144
- console.log(pc2.cyan(` - ${f.path} -> ${f.fullPath}`));
145
- }
146
- }
147
- } catch (err) {
148
- const msg = err instanceof Error ? err.message : String(err);
149
- console.error(pc2.red(`\u274C Fatal error during codegen: ${msg}`));
150
- process.exit(1);
151
- }
152
- }
153
- });
154
-
155
- // src/commands/doctor.ts
156
- import { spawnSync } from "child_process";
157
- import { existsSync, readFileSync } from "fs";
158
- import { join } from "path";
159
- import { syncAdapters } from "@cdal/adapters";
160
- import { loadConfig as loadConfig2, runCodegen as runCodegen2 } from "@cdal/core";
161
- import { defineCommand as defineCommand3 } from "citty";
162
- import pc3 from "picocolors";
163
- function inspectClaudeHooks(settings) {
164
- const groups = settings.hooks?.PreToolUse;
165
- if (!Array.isArray(groups)) return "missing";
166
- let legacy = false;
167
- for (const group of groups) {
168
- if (typeof group.command === "string" && /cdal(kit)? hook/.test(group.command)) legacy = true;
169
- const handlers = Array.isArray(group.hooks) ? group.hooks : [];
170
- for (const handler of handlers) {
171
- if (handler.type === "command" && typeof handler.command === "string" && /cdal(kit)? hook guard-paths/.test(handler.command)) {
172
- return "ok";
173
- }
174
- }
175
- }
176
- return legacy ? "legacy-format" : "missing";
177
- }
178
- function runDoctorChecks(cwd, customConfig) {
179
- const checks = [];
180
- const nodeVer = process.version;
181
- const match = /^v(\d+)\.(\d+)\./.exec(nodeVer);
182
- const major = match?.[1] ? Number.parseInt(match[1], 10) : 0;
183
- const minor = match?.[2] ? Number.parseInt(match[2], 10) : 0;
184
- if (major > 20 || major === 20 && minor >= 9) {
185
- checks.push({
186
- name: "Node.js Runtime",
187
- status: "ok",
188
- message: `Node ${nodeVer} satisfies engines.node >= 20.9.0 LTS`
189
- });
190
- } else {
191
- checks.push({
192
- name: "Node.js Runtime",
193
- status: "error",
194
- message: `Current Node ${nodeVer} is below required >= 20.9.0`,
195
- recommendation: "Upgrade Node.js to Node 22 LTS or Node 20.9+."
196
- });
197
- }
198
- const gitVersionRes = spawnSync("git", ["--version"], { encoding: "utf8" });
199
- if (gitVersionRes.status !== 0) {
200
- checks.push({
201
- name: "Git Binary",
202
- status: "error",
203
- message: "git binary is not available in PATH",
204
- recommendation: "Install Git or add it to PATH."
205
- });
206
- } else {
207
- checks.push({
208
- name: "Git Binary",
209
- status: "ok",
210
- message: `Git is available (${gitVersionRes.stdout.trim()})`
211
- });
212
- const gitRepoRes = spawnSync("git", ["rev-parse", "--is-inside-work-tree"], {
213
- cwd,
214
- encoding: "utf8"
215
- });
216
- if (gitRepoRes.status !== 0) {
217
- checks.push({
218
- name: "Git Repository",
219
- status: "error",
220
- message: "Current directory is not inside a git working tree",
221
- recommendation: "Initialize git with `git init`."
222
- });
223
- } else {
224
- checks.push({
225
- name: "Git Repository",
226
- status: "ok",
227
- message: "Inside active git working tree"
228
- });
229
- }
230
- }
231
- let configObj = null;
232
- try {
233
- const loaded = loadConfigSync(cwd, customConfig);
234
- configObj = loaded.config;
235
- checks.push({
236
- name: "Configuration",
237
- status: "ok",
238
- message: `Configuration loaded cleanly (${loaded.filepath ? loaded.filepath : "default config"})`
239
- });
240
- } catch (err) {
241
- const msg = err instanceof Error ? err.message : String(err);
242
- checks.push({
243
- name: "Configuration",
244
- status: "error",
245
- message: `Failed to load cdal.config.mjs: ${msg}`,
246
- recommendation: "Run `cdal init` or fix configuration errors."
247
- });
248
- }
249
- const settingsPath = join(cwd, ".claude/settings.json");
250
- if (existsSync(settingsPath)) {
251
- try {
252
- const settings = JSON.parse(readFileSync(settingsPath, "utf8"));
253
- const wiring = inspectClaudeHooks(settings);
254
- if (wiring === "ok") {
255
- checks.push({
256
- name: "Claude Code Hooks",
257
- status: "ok",
258
- message: ".claude/settings.json correctly wires CDAL pre-tool hooks"
259
- });
260
- } else {
261
- checks.push({
262
- name: "Claude Code Hooks",
263
- status: "warn",
264
- message: wiring === "legacy-format" ? ".claude/settings.json uses a hook format Claude Code ignores, so the CDAL gates never run" : ".claude/settings.json exists but does not wire the CDAL guard-paths hook",
265
- recommendation: "Run `npx cdalkit sync` to regenerate the hook wiring."
266
- });
267
- }
268
- } catch {
269
- checks.push({
270
- name: "Claude Code Hooks",
271
- status: "warn",
272
- message: "Could not read .claude/settings.json"
273
- });
274
- }
275
- } else {
276
- checks.push({
277
- name: "Claude Code Hooks",
278
- status: "warn",
279
- message: "No .claude/settings.json found in workspace",
280
- recommendation: "Run `cdal init` or `cdal sync` to generate hook wiring."
281
- });
282
- }
283
- if (configObj) {
284
- try {
285
- const syncRes = syncAdapters({ cwd, config: configObj, check: true });
286
- if (syncRes.inSync) {
287
- checks.push({
288
- name: "Runtime Adapters Sync",
289
- status: "ok",
290
- message: `All ${syncRes.totalFiles} adapter file(s) are in sync without drift`
291
- });
292
- } else {
293
- checks.push({
294
- name: "Runtime Adapters Sync",
295
- status: "error",
296
- message: `${syncRes.driftedFiles.length} adapter file(s) drifted from configuration: ${syncRes.driftedFiles.join(", ")}`,
297
- recommendation: "Run `cdal sync` to synchronize runtime files."
298
- });
299
- }
300
- } catch (err) {
301
- checks.push({
302
- name: "Runtime Adapters Sync",
303
- status: "warn",
304
- message: `Could not check adapter sync: ${String(err)}`
305
- });
306
- }
307
- }
308
- const healthy = checks.every((c) => c.status !== "error");
309
- return { checks, healthy };
310
- }
311
- function loadConfigSync(cwd, customConfig) {
312
- const configPath = customConfig || join(cwd, "cdal.config.mjs");
313
- if (existsSync(configPath)) {
314
- return { config: null, filepath: configPath };
315
- }
316
- return { config: null, filepath: null };
317
- }
318
- var doctorCommand = defineCommand3({
319
- meta: {
320
- name: "doctor",
321
- description: "Diagnose CDAL installation, environment health, hook wiring, and configuration drift"
322
- },
323
- args: {
324
- config: {
325
- type: "string",
326
- description: "Path to cdal.config.mjs"
327
- },
328
- cwd: {
329
- type: "string",
330
- description: "Working directory path"
331
- }
332
- },
333
- async run({ args }) {
334
- const cwd = args.cwd || process.cwd();
335
- console.log(pc3.bold(pc3.cyan("\n\u{1FA7A} Running CDAL Diagnostic Doctor...\n")));
336
- let resolvedConfig = null;
337
- try {
338
- const loaded = await loadConfig2(args.config || cwd);
339
- resolvedConfig = loaded.config;
340
- } catch (err) {
341
- console.error(pc3.red(`\u26A0\uFE0F Configuration error: ${String(err)}`));
342
- }
343
- const { checks, healthy } = runDoctorChecks(cwd, args.config);
344
- if (resolvedConfig) {
345
- try {
346
- const codegenRes = await runCodegen2({
347
- contractsDir: resolvedConfig.contractsDir,
348
- kinds: resolvedConfig.kinds,
349
- check: true
350
- });
351
- if (!codegenRes.drift) {
352
- checks.push({
353
- name: "Contract Codegen Sync",
354
- status: "ok",
355
- message: "Generated contract artifacts match contracts byte-for-byte"
356
- });
357
- } else {
358
- checks.push({
359
- name: "Contract Codegen Sync",
360
- status: "error",
361
- message: "Generated contract code drifted from contract sources",
362
- recommendation: "Run `cdal codegen` to regenerate artifacts."
363
- });
364
- }
365
- } catch {
366
- }
367
- }
368
- for (const check of checks) {
369
- if (check.status === "ok") {
370
- console.log(pc3.green(` \u2713 [OK] ${pc3.bold(check.name)}: ${check.message}`));
371
- } else if (check.status === "warn") {
372
- console.log(pc3.yellow(` \u26A0\uFE0F [WARN] ${pc3.bold(check.name)}: ${check.message}`));
373
- if (check.recommendation) {
374
- console.log(pc3.dim(` Recommendation: ${check.recommendation}`));
375
- }
376
- } else {
377
- console.log(pc3.red(` \u274C [FAIL] ${pc3.bold(check.name)}: ${check.message}`));
378
- if (check.recommendation) {
379
- console.log(pc3.yellow(` Recommendation: ${check.recommendation}`));
380
- }
381
- }
382
- }
383
- if (healthy) {
384
- console.log(
385
- pc3.bold(pc3.green("\n\u2705 Doctor report: Environment and CDAL quality gates are healthy!\n"))
386
- );
387
- } else {
388
- console.log(pc3.bold(pc3.red("\n\u274C Doctor report: Some critical diagnostic checks failed.\n")));
389
- process.exit(1);
390
- }
391
- }
392
- });
393
-
394
- // src/commands/hook.ts
395
- import fs from "fs";
396
- import { executeHook } from "@cdal/adapters";
397
- import { loadConfig as loadConfig3 } from "@cdal/core";
398
- import { defineCommand as defineCommand4 } from "citty";
399
- var VALID_HOOKS = /* @__PURE__ */ new Set([
400
- "guard-paths",
401
- "guard-forbidden",
402
- "guard-bash",
403
- "session-context",
404
- "log-subagent"
405
- ]);
406
- var hookCommand = defineCommand4({
407
- meta: {
408
- name: "hook",
409
- description: "Entrypoint for agent runtime hooks (Claude Code, Antigravity, etc.)"
410
- },
411
- args: {
412
- name: {
413
- type: "positional",
414
- description: "Hook name to execute: guard-paths, guard-forbidden, guard-bash, session-context, log-subagent",
415
- required: true
416
- },
417
- role: {
418
- type: "positional",
419
- description: "Fallback agent role name if not specified in hook payload",
420
- required: false
421
- },
422
- runtime: {
423
- type: "string",
424
- description: "Target runtime adapter (claude-code, antigravity)",
425
- default: "claude-code"
426
- },
427
- config: {
428
- type: "string",
429
- description: "Path to cdal.config.mjs"
430
- }
431
- },
432
- async run({ args }) {
433
- const hookName = args.name;
434
- if (!VALID_HOOKS.has(hookName)) {
435
- process.stderr.write(
436
- `Unknown hook name "${hookName}". Valid hooks: ${Array.from(VALID_HOOKS).join(", ")}
437
- `
438
- );
439
- process.exit(1);
440
- }
441
- let rawPayload = "";
442
- try {
443
- rawPayload = fs.readFileSync(0, "utf8");
444
- } catch {
445
- }
446
- const cwd = process.cwd();
447
- const { config } = await loadConfig3(args.config);
448
- const result = await executeHook(hookName, rawPayload, {
449
- cwd,
450
- config,
451
- fallbackRole: args.role,
452
- runtime: args.runtime
453
- });
454
- if (result.stdout) {
455
- process.stdout.write(`${result.stdout}
456
- `);
457
- }
458
- if (result.stderr) {
459
- process.stderr.write(result.stderr);
460
- }
461
- process.exit(result.exitCode);
462
- }
463
- });
464
-
465
- // src/commands/init.ts
466
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
467
- import { join as join2 } from "path";
468
- import { syncAdapters as syncAdapters2 } from "@cdal/adapters";
469
- import { resolveConfig } from "@cdal/core";
470
- import { defineCommand as defineCommand5 } from "citty";
471
- import pc4 from "picocolors";
472
- var initCommand = defineCommand5({
473
- meta: {
474
- name: "init",
475
- description: "Initialize CDAL quality gates, starter contracts, and runtime adapters in the repository"
476
- },
477
- args: {
478
- yes: {
479
- type: "boolean",
480
- description: "Accept default recommendations non-interactively",
481
- alias: "y",
482
- default: false
483
- },
484
- preset: {
485
- type: "string",
486
- description: "Preset configuration to apply (e.g. typescript-strict, nextjs, node-service)",
487
- default: "typescript-strict"
488
- },
489
- runtime: {
490
- type: "string",
491
- description: "Comma-separated runtimes to enable (claude-code, agents-md, antigravity)",
492
- default: "claude-code,agents-md"
493
- },
494
- cwd: {
495
- type: "string",
496
- description: "Target directory to initialize"
497
- }
498
- },
499
- async run({ args }) {
500
- const cwd = args.cwd || process.cwd();
501
- console.log(pc4.bold(pc4.cyan("\n\u{1F680} Initializing Contract-Driven Agentic Loop (CDAL)...\n")));
502
- const preset = args.preset || "typescript-strict";
503
- const rawRuntimes = (args.runtime || "claude-code,agents-md").split(",").map((r) => r.trim()).filter(Boolean);
504
- const contractsDir = join2(cwd, "contracts");
505
- if (!existsSync2(contractsDir)) {
506
- mkdirSync(contractsDir, { recursive: true });
507
- }
508
- const sampleContractPath = join2(contractsDir, "requirements.contract.mjs");
509
- if (!existsSync2(sampleContractPath)) {
510
- const sampleContractContent = `// @origin: cdal init
511
- export const REQUIREMENTS = [
512
- {
513
- id: 'REQ-CORE-INIT-1',
514
- statement: 'System must initialize workspace with contract-driven quality gates.',
515
- acceptance: [
516
- 'cdal validate succeeds without errors',
517
- 'Test cases are marked with @REQ tags',
518
- ],
519
- status: 'ACTIVE',
520
- priority: 'CRITICAL',
521
- },
10
+ var PRO_COMMANDS = [
11
+ "init",
12
+ "validate",
13
+ "codegen",
14
+ "plan",
15
+ "window",
16
+ "trace",
17
+ "phase",
18
+ "selftest",
19
+ "sync",
20
+ "verify",
21
+ "doctor",
22
+ "hook"
522
23
  ];
523
- `;
524
- writeFileSync2(sampleContractPath, sampleContractContent, "utf8");
525
- console.log(
526
- pc4.green(` \u2713 Created starter contract: ${pc4.bold("contracts/requirements.contract.mjs")}`)
527
- );
528
- }
529
- const configPath = join2(cwd, "cdal.config.mjs");
530
- if (!existsSync2(configPath)) {
531
- const runtimesFormatted = rawRuntimes.map((r) => `'${r}'`).join(", ");
532
- const configContent = `import { defineConfig } from '@cdal/core';
533
- import { policies, requirements, stateMachine } from '@cdal/kinds';
534
-
535
- export default defineConfig({
536
- contractsDir: 'contracts',
537
- generated: {
538
- ts: 'src/generated/contracts',
539
- docs: 'docs/generated',
540
- },
541
- kinds: [requirements(), stateMachine(), policies()],
542
- presets: ['${preset}'],
543
- runtimes: [${runtimesFormatted}],
544
- verify: [
545
- 'cdal validate --strict',
546
- 'cdal codegen --check',
547
- 'cdal trace --enforce',
548
- 'cdal selftest',
549
- ],
550
- });
551
- `;
552
- writeFileSync2(configPath, configContent, "utf8");
553
- console.log(pc4.green(` \u2713 Created configuration: ${pc4.bold("cdal.config.mjs")}`));
554
- } else {
555
- console.log(
556
- pc4.dim(" \u2139 cdal.config.mjs already exists (preserving existing configuration).")
24
+ function proOnly(name) {
25
+ return defineCommand({
26
+ meta: { name, description: "Part of CDAL Pro (run `cdalkit pro install` after purchase)" },
27
+ run() {
28
+ console.error(
29
+ `${pc.bold(`cdalkit ${name}`)} is part of CDAL Pro.
30
+ Already bought it? Run ${pc.cyan("npx cdalkit pro install")} in your project; it installs the full CDAL into it.
31
+ Not yet: ${pc.cyan("https://cdalkit.tech/pricing")}. The repository audit stays free: ${pc.cyan("npx cdalkit audit")}`
557
32
  );
33
+ process.exit(1);
558
34
  }
559
- const pkgPath = join2(cwd, "package.json");
560
- if (existsSync2(pkgPath)) {
561
- try {
562
- const pkgRaw = readFileSync2(pkgPath, "utf8");
563
- const pkg = JSON.parse(pkgRaw);
564
- pkg.scripts = pkg.scripts || {};
565
- let updated = false;
566
- if (!pkg.scripts.verify) {
567
- pkg.scripts.verify = "cdal verify";
568
- updated = true;
569
- }
570
- if (!pkg.scripts.selftest) {
571
- pkg.scripts.selftest = "cdal selftest";
572
- updated = true;
573
- }
574
- if (!pkg.scripts.trace) {
575
- pkg.scripts.trace = "cdal trace";
576
- updated = true;
577
- }
578
- if (updated) {
579
- writeFileSync2(pkgPath, `${JSON.stringify(pkg, null, 2)}
580
- `, "utf8");
581
- console.log(
582
- pc4.green(` \u2713 Added verify/selftest/trace scripts to ${pc4.bold("package.json")}`)
583
- );
584
- }
585
- } catch {
586
- console.log(pc4.yellow(" \u26A0\uFE0F Could not update package.json scripts automatically."));
587
- }
588
- }
589
- const resolvedConfig = resolveConfig({
590
- presets: [preset],
591
- runtimes: rawRuntimes
592
- });
593
- const syncRes = syncAdapters2({
594
- cwd,
595
- config: resolvedConfig,
596
- check: false
597
- });
598
- console.log(
599
- pc4.green(
600
- ` \u2713 Generated ${syncRes.updatedFiles.length} runtime adapter file(s) across [${rawRuntimes.join(", ")}].`
601
- )
602
- );
603
- console.log(pc4.bold(pc4.green("\n\u{1F389} CDAL initialized successfully!")));
604
- console.log(pc4.cyan("Next steps:"));
605
- console.log(pc4.dim(" 1. Review contracts in contracts/*.contract.mjs"));
606
- console.log(pc4.dim(" 2. Run `npx cdalkit doctor` to verify environment health"));
607
- console.log(pc4.dim(" 3. Run `npx cdalkit verify` to test the loop gate\n"));
608
- }
609
- });
610
-
611
- // src/commands/phase.ts
612
- import { checkPhase, loadConfig as loadConfig4 } from "@cdal/core";
613
- import { defineCommand as defineCommand6 } from "citty";
614
- import pc5 from "picocolors";
615
- var phaseCommand = defineCommand6({
616
- meta: {
617
- name: "phase",
618
- description: "Verify git diff against active loop phase (contract, red, green)"
619
- },
620
- args: {
621
- phase: {
622
- type: "positional",
623
- description: "Phase to verify: contract, red, green",
624
- required: true
625
- },
626
- base: {
627
- type: "string",
628
- description: "Base git reference to compare against (e.g. main or origin/main)"
629
- },
630
- json: {
631
- type: "boolean",
632
- description: "Output as JSON payload",
633
- default: false
634
- },
635
- config: {
636
- type: "string",
637
- description: "Path to cdal.config.mjs"
638
- }
639
- },
640
- async run({ args }) {
641
- const rawPhase = (args.phase || "").toLowerCase();
642
- if (!["contract", "red", "green"].includes(rawPhase)) {
643
- console.error(pc5.red(`Invalid phase "${rawPhase}". Valid phases are: contract, red, green.`));
644
- process.exit(2);
645
- }
646
- const phase = rawPhase;
647
- const cwd = process.cwd();
648
- const { config: resolvedConfig } = await loadConfig4(args.config);
649
- const result = checkPhase(phase, {
650
- cwd,
651
- base: args.base,
652
- protectedPaths: resolvedConfig?.protectedPaths
653
- });
654
- if (args.json) {
655
- console.log(JSON.stringify(result, null, 2));
656
- process.exit(result.ok ? 0 : 1);
657
- }
658
- console.log(pc5.bold(`
659
- Phase: ${result.label}`));
660
- console.log(` Modified files in diff: ${result.files.length}
661
- `);
662
- if (result.violations.length === 0) {
663
- if (result.files.length === 0) {
664
- if (phase === "red") {
665
- console.log(
666
- pc5.yellow(
667
- " \u26A0 No changes found in working tree. Phase RED requires at least one test."
668
- )
669
- );
670
- process.exit(1);
671
- }
672
- console.log(pc5.dim(" No changes found in working tree."));
673
- process.exit(0);
674
- }
675
- console.log(pc5.green(" \u2714 All changes are within active phase scopes."));
676
- process.exit(0);
677
- }
678
- console.log(
679
- pc5.red(` \u2717 ${result.violations.length} file(s) outside of permitted phase scope:
680
- `)
681
- );
682
- for (const v of result.violations) {
683
- console.log(` - ${v}`);
684
- }
685
- console.log(pc5.dim(`
686
- ${result.why}
687
- `));
688
- process.exit(1);
689
- }
690
- });
691
-
692
- // src/commands/pro.ts
693
- import { execFileSync } from "child_process";
694
- import { existsSync as existsSync4, mkdtempSync, rmSync } from "fs";
695
- import { tmpdir } from "os";
696
- import { join as join4, resolve as resolve3 } from "path";
697
- import { defineCommand as defineCommand7 } from "citty";
698
- import pc6 from "picocolors";
699
-
700
- // src/pro/install.ts
701
- import {
702
- copyFileSync,
703
- existsSync as existsSync3,
704
- mkdirSync as mkdirSync2,
705
- readFileSync as readFileSync3,
706
- readdirSync,
707
- statSync,
708
- writeFileSync as writeFileSync3
709
- } from "fs";
710
- import { dirname, isAbsolute, join as join3, relative, resolve as resolve2, sep } from "path";
711
- var PRO_MANIFEST_FILE = "pro.manifest.json";
712
- var PRO_RECORD_FILE = ".cdal/pro.json";
713
- var GENERATED_MARKERS = ["CDAL GENERATED", "GENERATED by cdal sync"];
714
- function isGeneratedFile(path2) {
715
- const content = readFileSync3(path2, "utf8");
716
- return GENERATED_MARKERS.some((marker) => content.includes(marker));
717
- }
718
- var ProInstallError = class extends Error {
719
- constructor(message) {
720
- super(message);
721
- this.name = "ProInstallError";
722
- }
723
- };
724
- function toPosix(path2) {
725
- return path2.split(sep).join("/");
726
- }
727
- function resolveInside(root, rel, label) {
728
- if (typeof rel !== "string" || rel.length === 0 || isAbsolute(rel)) {
729
- throw new ProInstallError(`Invalid ${label} path in ${PRO_MANIFEST_FILE}: "${rel}"`);
730
- }
731
- const full = resolve2(root, rel);
732
- const fromRoot = relative(root, full);
733
- if (fromRoot.startsWith("..") || isAbsolute(fromRoot)) {
734
- throw new ProInstallError(`${label} path "${rel}" escapes its directory`);
735
- }
736
- return full;
737
- }
738
- function readProManifest(sourceDir) {
739
- const manifestPath = join3(sourceDir, PRO_MANIFEST_FILE);
740
- if (!existsSync3(manifestPath)) {
741
- throw new ProInstallError(`No ${PRO_MANIFEST_FILE} found in ${sourceDir}`);
742
- }
743
- let manifest;
744
- try {
745
- manifest = JSON.parse(readFileSync3(manifestPath, "utf8"));
746
- } catch (err) {
747
- throw new ProInstallError(
748
- `${PRO_MANIFEST_FILE} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`
749
- );
750
- }
751
- if (!manifest.name || !manifest.version || !Array.isArray(manifest.install)) {
752
- throw new ProInstallError(`${PRO_MANIFEST_FILE} must define name, version and install[]`);
753
- }
754
- return manifest;
755
- }
756
- function listFiles(dir) {
757
- const files = [];
758
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
759
- const full = join3(dir, entry.name);
760
- if (entry.isDirectory()) files.push(...listFiles(full));
761
- else if (entry.isFile()) files.push(full);
762
- }
763
- return files;
764
- }
765
- function installPro(options) {
766
- const sourceDir = resolve2(options.sourceDir);
767
- const targetDir = resolve2(options.targetDir);
768
- const manifest = readProManifest(sourceDir);
769
- const plan = [];
770
- for (const mapping of manifest.install) {
771
- const from = resolveInside(sourceDir, mapping.from, "from");
772
- const to = resolveInside(targetDir, mapping.to, "to");
773
- if (!existsSync3(from)) {
774
- throw new ProInstallError(`Manifest source "${mapping.from}" does not exist`);
775
- }
776
- const sources = statSync(from).isDirectory() ? listFiles(from) : [from];
777
- for (const src of sources) {
778
- const dest = statSync(from).isDirectory() ? join3(to, relative(from, src)) : to;
779
- plan.push({ src, dest, rel: toPosix(relative(targetDir, dest)) });
780
- }
781
- }
782
- const written = [];
783
- const skipped = [];
784
- for (const { src, dest, rel } of plan) {
785
- if (existsSync3(dest) && !options.force && !isGeneratedFile(dest)) {
786
- skipped.push(rel);
787
- continue;
788
- }
789
- written.push(rel);
790
- if (!options.dryRun) {
791
- mkdirSync2(dirname(dest), { recursive: true });
792
- copyFileSync(src, dest);
793
- }
794
- }
795
- if (!options.dryRun) {
796
- const recordPath = join3(targetDir, PRO_RECORD_FILE);
797
- mkdirSync2(dirname(recordPath), { recursive: true });
798
- writeFileSync3(
799
- recordPath,
800
- `${JSON.stringify(
801
- {
802
- name: manifest.name,
803
- version: manifest.version,
804
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
805
- files: plan.map((p) => p.rel).sort()
806
- },
807
- null,
808
- 2
809
- )}
810
- `,
811
- "utf8"
812
- );
813
- }
814
- return { name: manifest.name, version: manifest.version, written, skipped };
815
- }
816
-
817
- // src/commands/pro.ts
818
- var PRO_REPOSITORY_URL = "https://github.com/cdalkit/cdal-pro.git";
819
- function resolveSource(from) {
820
- const local = resolve3(from);
821
- if (existsSync4(local)) return { dir: local, cleanup: () => {
822
- } };
823
- const dir = mkdtempSync(join4(tmpdir(), "cdal-pro-"));
824
- const cleanup = () => rmSync(dir, { recursive: true, force: true });
825
- try {
826
- execFileSync("git", ["clone", "--depth", "1", "--quiet", from, dir], {
827
- stdio: ["ignore", "ignore", "pipe"]
828
- });
829
- } catch {
830
- cleanup();
831
- throw new ProInstallError(
832
- `Could not clone ${from}.
833
- CDAL Pro is delivered as a private GitHub repository: accept the invitation sent after your purchase, make sure git can access GitHub as that account, then run this command again.`
834
- );
835
- }
836
- return { dir, cleanup };
35
+ });
837
36
  }
838
- var installCommand = defineCommand7({
37
+ var proInstall = defineCommand({
839
38
  meta: {
840
39
  name: "install",
841
- description: "Install CDAL Pro content (agent roles, templates, presets) into this project"
40
+ description: "Install CDAL Pro (the CDAL core, agent roles, templates and presets) into this project"
842
41
  },
843
42
  args: {
844
- from: {
845
- type: "string",
846
- description: "Local copy or git URL of the cdal-pro repository",
847
- default: PRO_REPOSITORY_URL
848
- },
849
- cwd: {
850
- type: "string",
851
- description: "Project directory to install into",
852
- default: "."
853
- },
854
- force: {
855
- type: "boolean",
856
- description: "Overwrite files that already exist in the project",
857
- default: false
858
- },
859
- dryRun: {
860
- type: "boolean",
861
- description: "Show what would be installed without writing anything",
862
- default: false
863
- }
43
+ team: { type: "boolean", description: "Also install CDAL Pro Team", default: false },
44
+ from: { type: "string", description: "Local copy or git URL of cdal-pro (default: GitHub)" },
45
+ teamFrom: { type: "string", description: "Local copy or git URL of cdal-pro-team" },
46
+ cwd: { type: "string", description: "Project directory", default: "." },
47
+ force: { type: "boolean", description: "Overwrite files that already exist", default: false }
864
48
  },
865
49
  run({ args }) {
866
- let source;
867
50
  try {
868
- source = resolveSource(args.from);
869
- const result = installPro({
870
- sourceDir: source.dir,
871
- targetDir: resolve3(args.cwd),
51
+ const manifest = installProWithCore({
52
+ cwd: args.cwd,
53
+ from: args.from,
54
+ team: args.team,
55
+ teamFrom: args.teamFrom,
872
56
  force: args.force,
873
- dryRun: args.dryRun
57
+ log: (line) => console.log(pc.dim(line))
874
58
  });
875
- const verb = args.dryRun ? "Would install" : "Installed";
876
- console.log(pc6.green(`\u2714 ${verb} ${result.name} ${result.version}`));
877
- console.log(` ${result.written.length} file(s) ${args.dryRun ? "to write" : "written"}`);
878
- if (result.skipped.length > 0) {
879
- console.log(
880
- pc6.yellow(
881
- ` ${result.skipped.length} existing file(s) kept \u2014 rerun with --force to overwrite:`
882
- )
883
- );
884
- for (const file of result.skipped) console.log(pc6.dim(` ${file}`));
885
- }
886
- if (!args.dryRun) {
887
- console.log(pc6.dim(" Run `npx cdalkit sync` to wire the new roles into your runtimes."));
888
- }
889
- } catch (err) {
890
- const message = err instanceof Error ? err.message : String(err);
891
- console.error(pc6.red(`\u2716 ${message}`));
892
- process.exit(1);
893
- } finally {
894
- source?.cleanup();
895
- }
896
- }
897
- });
898
- var proCommand = defineCommand7({
899
- meta: {
900
- name: "pro",
901
- description: "CDAL Pro: install licensed agent roles, templates and presets"
902
- },
903
- subCommands: {
904
- install: installCommand
905
- }
906
- });
907
-
908
- // src/commands/selftest.ts
909
- import { loadConfig as loadConfig5, runSelftest } from "@cdal/core";
910
- import { defineCommand as defineCommand8 } from "citty";
911
- import pc7 from "picocolors";
912
- var selftestCommand = defineCommand8({
913
- meta: {
914
- name: "selftest",
915
- description: "Run mutation testing on contract invariant rules and content guardrails"
916
- },
917
- args: {
918
- json: {
919
- type: "boolean",
920
- description: "Output as JSON payload (selftest.v1)",
921
- default: false
922
- },
923
- config: {
924
- type: "string",
925
- description: "Path to cdal.config.mjs"
926
- }
927
- },
928
- async run({ args }) {
929
- const cwd = process.cwd();
930
- const { config: resolvedConfig } = await loadConfig5(args.config);
931
- if (!args.json) {
932
- console.log(pc7.bold(pc7.cyan("\n cdal selftest \u2014 mutation testing of quality gates")));
59
+ console.log(pc.green(`\u2714 CDAL Pro is installed (core ${manifest.version}).`));
933
60
  console.log(
934
- pc7.dim(" Testing whether validator and guardrails actually fire red when violated\n")
61
+ " Commit the result (including .cdal/vendor/) so your teammates get the same setup."
935
62
  );
936
- }
937
- const report = await runSelftest({
938
- cwd,
939
- config: resolvedConfig
940
- });
941
- if (args.json) {
942
- console.log(JSON.stringify(report, null, 2));
943
- process.exit(report.ok ? 0 : 1);
944
- }
945
- if (report.mutationResults.length > 0) {
946
- console.log(
947
- pc7.bold(
948
- ` Contract Invariant Mutations (${report.mutationsPassed}/${report.mutationsTotal}):`
949
- )
950
- );
951
- for (const m of report.mutationResults) {
952
- if (m.passed) {
953
- console.log(
954
- ` ${pc7.green("\u2714")} ${pc7.cyan(m.rule.padEnd(26))} detected in ${pc7.dim(m.file)}`
955
- );
956
- } else {
957
- console.log(
958
- ` ${pc7.red("\u2717")} ${pc7.red(m.rule.padEnd(26))} ${pc7.bold("MISSED")}: ${m.error ?? "rule dead"}`
959
- );
960
- }
961
- }
962
- console.log("");
963
- }
964
- if (report.probeResults.length > 0) {
965
- console.log(
966
- pc7.bold(` Forbidden Content Probes (${report.probesPassed}/${report.probesTotal}):`)
967
- );
968
- for (const p of report.probeResults) {
969
- const action = p.fires ? "detected" : "allowed";
970
- if (p.passed) {
971
- console.log(
972
- ` ${pc7.green("\u2714")} ${pc7.cyan(p.rule.padEnd(30))} ${pc7.green(action)}: ${p.desc}`
973
- );
974
- } else {
975
- console.log(
976
- ` ${pc7.red("\u2717")} ${pc7.red(p.rule.padEnd(30))} ${pc7.bold("FAILED")}: ${p.error ?? "unexpected behavior"}`
977
- );
978
- }
979
- }
980
- console.log("");
981
- }
982
- console.log(
983
- pc7.bold(
984
- ` Summary: ${report.mutationsPassed}/${report.mutationsTotal} contract rules verified via mutation.`
985
- )
986
- );
987
- console.log(
988
- pc7.bold(
989
- ` ${report.probesPassed}/${report.probesTotal} content guardrail probes verified.
990
- `
991
- )
992
- );
993
- if (report.failures.length > 0) {
994
- console.log(pc7.bold(pc7.red(" CRITICAL GATE FAILURES:")));
995
- for (const f of report.failures) {
996
- console.log(` - ${pc7.red(f)}`);
997
- }
998
- console.log("");
999
- process.exit(1);
1000
- }
1001
- console.log(pc7.green(pc7.bold(" \u2714 Every quality gate rule is verified active and firing.\n")));
1002
- process.exit(0);
1003
- }
1004
- });
1005
-
1006
- // src/commands/sync.ts
1007
- import { syncAdapters as syncAdapters3 } from "@cdal/adapters";
1008
- import { loadConfig as loadConfig6 } from "@cdal/core";
1009
- import { defineCommand as defineCommand9 } from "citty";
1010
- import pc8 from "picocolors";
1011
- var syncCommand = defineCommand9({
1012
- meta: {
1013
- name: "sync",
1014
- description: "Synchronize agent definitions, commands, hooks and rules across configured runtimes (with --check drift detection)"
1015
- },
1016
- args: {
1017
- check: {
1018
- type: "boolean",
1019
- description: "Check for drift between cdal.config.mjs and runtime files without modifying disk",
1020
- default: false
1021
- },
1022
- config: {
1023
- type: "string",
1024
- description: "Custom path to cdal.config.mjs"
1025
- },
1026
- cwd: {
1027
- type: "string",
1028
- description: "Working directory path"
1029
- }
1030
- },
1031
- async run({ args }) {
1032
- try {
1033
- const cwd = args.cwd || process.cwd();
1034
- const { config } = await loadConfig6(args.config || cwd);
1035
- const res = syncAdapters3({
1036
- cwd,
1037
- config,
1038
- check: Boolean(args.check)
1039
- });
1040
- if (args.check) {
1041
- if (res.inSync) {
1042
- console.log(
1043
- pc8.green(
1044
- `\u2705 Sync check passed: all ${res.totalFiles} adapter file(s) are in sync across [${config.runtimes.join(", ")}].`
1045
- )
1046
- );
1047
- } else {
1048
- console.error(
1049
- pc8.red(
1050
- `\u274C Sync check failed: ${res.driftedFiles.length} adapter file(s) drifted from configuration:`
1051
- )
1052
- );
1053
- for (const file of res.driftedFiles) {
1054
- console.error(pc8.red(` - [DRIFT] ${file}`));
1055
- }
1056
- console.error(
1057
- pc8.yellow(
1058
- "\nRun `npx cdalkit sync` to synchronize runtime files with cdal.config.mjs."
1059
- )
1060
- );
1061
- process.exit(1);
1062
- }
1063
- } else {
1064
- console.log(
1065
- pc8.green(
1066
- `\u2705 Synchronized ${res.updatedFiles.length} adapter file(s) across [${config.runtimes.join(", ")}]:`
1067
- )
1068
- );
1069
- for (const file of res.updatedFiles) {
1070
- console.log(pc8.cyan(` - ${file}`));
1071
- }
1072
- if (res.updatedFiles.length === 0) {
1073
- console.log(pc8.dim(" (All files were already up-to-date)"));
1074
- }
1075
- }
1076
- if (res.preservedFiles.length > 0) {
1077
- console.log(
1078
- pc8.dim(
1079
- ` ${res.preservedFiles.length} file(s) marked cdal:preserve were left untouched.`
1080
- )
1081
- );
1082
- }
63
+ console.log(" Next: open your editor and describe what you want to build.");
1083
64
  } catch (err) {
1084
- const msg = err instanceof Error ? err.message : String(err);
1085
- console.error(pc8.red(`\u274C Fatal error during sync: ${msg}`));
1086
- process.exit(1);
1087
- }
1088
- }
1089
- });
1090
-
1091
- // src/commands/trace.ts
1092
- import path from "path";
1093
- import { pathToFileURL } from "url";
1094
- import {
1095
- formatTraceMarkdown,
1096
- formatTraceText,
1097
- loadConfig as loadConfig7,
1098
- scanTrace
1099
- } from "@cdal/core";
1100
- import { defineCommand as defineCommand10 } from "citty";
1101
- import pc9 from "picocolors";
1102
- var traceCommand = defineCommand10({
1103
- meta: {
1104
- name: "trace",
1105
- description: "Inspect requirement-to-test traceability matrix (@REQ tags)"
1106
- },
1107
- args: {
1108
- enforce: {
1109
- type: "boolean",
1110
- description: "Exit with code 1 if any implementing/done requirement lacks tests, tests fail, or unknown @REQ tags exist",
1111
- default: false
1112
- },
1113
- markdown: {
1114
- type: "boolean",
1115
- description: "Output as Markdown table ready for pull request description",
1116
- default: false
1117
- },
1118
- json: {
1119
- type: "boolean",
1120
- description: "Output as structured JSON (trace.v1)",
1121
- default: false
1122
- },
1123
- results: {
1124
- type: "string",
1125
- description: "Path to test execution JSON results file (vitest or playwright json reporter)"
1126
- },
1127
- config: {
1128
- type: "string",
1129
- description: "Path to cdal.config.mjs"
1130
- }
1131
- },
1132
- async run({ args }) {
1133
- const cwd = process.cwd();
1134
- const { config: resolvedConfig } = await loadConfig7(args.config);
1135
- const contractsDir = resolvedConfig?.contractsDir ?? "contracts";
1136
- const reqContractPath = path.resolve(cwd, contractsDir, "requirements.contract.mjs");
1137
- let requirements2 = [];
1138
- try {
1139
- const imported = await import(pathToFileURL(reqContractPath).href);
1140
- requirements2 = imported.REQUIREMENTS || imported.default?.REQUIREMENTS || imported.default || [];
1141
- } catch (err) {
1142
- const errorMsg = err instanceof Error ? err.message : String(err);
1143
- console.error(pc9.red(`Failed to load requirements from "${reqContractPath}": ${errorMsg}`));
1144
- process.exit(1);
1145
- }
1146
- if (!Array.isArray(requirements2) || requirements2.length === 0) {
1147
- console.warn(pc9.yellow(`No requirements found in "${reqContractPath}".`));
1148
- if (args.enforce) process.exit(1);
1149
- return;
1150
- }
1151
- const report = scanTrace(requirements2, {
1152
- cwd,
1153
- resultsFile: args.results
1154
- });
1155
- if (args.json) {
1156
- console.log(JSON.stringify(report, null, 2));
1157
- } else if (args.markdown) {
1158
- console.log(formatTraceMarkdown(report));
1159
- } else {
1160
- console.log(formatTraceText(report));
1161
- }
1162
- if (args.enforce && !report.ok) {
1163
- process.exit(1);
1164
- }
1165
- }
1166
- });
1167
-
1168
- // src/commands/validate.ts
1169
- import { formatFindingsText, runValidation } from "@cdal/core";
1170
- import { defineCommand as defineCommand11 } from "citty";
1171
- import pc10 from "picocolors";
1172
- var validateCommand = defineCommand11({
1173
- meta: {
1174
- name: "validate",
1175
- description: "Validate contract invariants across all registered contract kinds"
1176
- },
1177
- args: {
1178
- strict: {
1179
- type: "boolean",
1180
- description: "Treat warnings as failures (exit 1)",
1181
- default: false
1182
- },
1183
- json: {
1184
- type: "boolean",
1185
- description: "Output findings using machine-readable findings.v1 JSON schema",
1186
- default: false
1187
- },
1188
- dir: {
1189
- type: "string",
1190
- description: "Custom path to contracts directory"
1191
- }
1192
- },
1193
- async run({ args }) {
1194
- try {
1195
- const kinds = await resolveCommandKinds();
1196
- const report = await runValidation({
1197
- contractsDir: args.dir,
1198
- strict: Boolean(args.strict),
1199
- kinds
1200
- });
1201
- if (args.json) {
1202
- console.log(JSON.stringify(report, null, 2));
1203
- } else {
1204
- const text = formatFindingsText(report, Boolean(args.strict));
1205
- if (report.valid) {
1206
- console.log(pc10.green(text));
1207
- } else {
1208
- console.error(pc10.red(text));
1209
- }
1210
- }
1211
- if (!report.valid) {
1212
- process.exit(1);
1213
- }
1214
- } catch (err) {
1215
- const msg = err instanceof Error ? err.message : String(err);
1216
- console.error(pc10.red(`\u274C Fatal error during contract validation: ${msg}`));
1217
- process.exit(1);
1218
- }
1219
- }
1220
- });
1221
-
1222
- // src/commands/verify.ts
1223
- import { spawnSync as spawnSync2 } from "child_process";
1224
- import { loadConfig as loadConfig8 } from "@cdal/core";
1225
- import { defineCommand as defineCommand12 } from "citty";
1226
- import pc11 from "picocolors";
1227
- var verifyCommand = defineCommand12({
1228
- meta: {
1229
- name: "verify",
1230
- description: "Run deterministic CDAL verification pipeline defined in configuration"
1231
- },
1232
- args: {
1233
- fast: {
1234
- type: "boolean",
1235
- description: "Run fast subset of verification steps (contract checks & selftest)",
1236
- default: false
1237
- },
1238
- full: {
1239
- type: "boolean",
1240
- description: "Force execution of all verification steps",
1241
- default: false
1242
- },
1243
- clean: {
1244
- type: "boolean",
1245
- description: "Clear temporary caches before running verification",
1246
- default: false
1247
- },
1248
- config: {
1249
- type: "string",
1250
- description: "Path to cdal.config.mjs"
1251
- },
1252
- cwd: {
1253
- type: "string",
1254
- description: "Working directory path"
1255
- }
1256
- },
1257
- async run({ args }) {
1258
- const cwd = args.cwd || process.cwd();
1259
- const { config } = await loadConfig8(args.config || cwd);
1260
- let steps = [...config.verify];
1261
- if (args.fast) {
1262
- steps = steps.filter(
1263
- (s) => s.includes("validate") || s.includes("codegen") || s.includes("selftest") || s.includes("typecheck")
65
+ const message = err instanceof Error ? err.message : String(err);
66
+ console.error(
67
+ pc.red(`\u2716 ${err instanceof BootstrapError ? message : `Installation failed: ${message}`}`)
1264
68
  );
1265
- if (steps.length === 0) {
1266
- steps = [config.verify[0] ?? "cdal validate --strict"];
1267
- }
1268
- }
1269
- console.log(
1270
- pc11.bold(pc11.cyan(`
1271
- \u26A1 Running CDAL Verification Pipeline (${steps.length} step(s))...
1272
- `))
1273
- );
1274
- for (let i = 0; i < steps.length; i++) {
1275
- const step = steps[i];
1276
- if (!step) continue;
1277
- console.log(pc11.bold(pc11.blue(`[${i + 1}/${steps.length}] \u25B6 ${step}`)));
1278
- const start = Date.now();
1279
- const res = spawnSync2(step, {
1280
- cwd,
1281
- shell: true,
1282
- stdio: "inherit"
1283
- });
1284
- const duration = Date.now() - start;
1285
- if (res.status !== 0) {
1286
- console.error(
1287
- pc11.bold(
1288
- pc11.red(
1289
- `
1290
- \u274C Verification failed at step: "${step}" (exit code ${res.status ?? 1}, took ${duration}ms)`
1291
- )
1292
- )
1293
- );
1294
- process.exit(res.status ?? 1);
1295
- }
1296
- console.log(pc11.green(` \u2713 Step passed in ${duration}ms
1297
- `));
1298
- }
1299
- console.log(
1300
- pc11.bold(
1301
- pc11.green(`\u2705 Full verification pipeline succeeded (${steps.length} step(s) passed).`)
1302
- )
1303
- );
1304
- }
1305
- });
1306
-
1307
- // src/commands/window.ts
1308
- import { closeContractWindow, getContractWindowStatus, openContractWindow } from "@cdal/core";
1309
- import { defineCommand as defineCommand13 } from "citty";
1310
- import pc12 from "picocolors";
1311
- var windowCommand = defineCommand13({
1312
- meta: {
1313
- name: "window",
1314
- description: "Manage contract window for protected path modifications"
1315
- },
1316
- args: {
1317
- action: {
1318
- type: "positional",
1319
- description: "Action to perform: open, close, status",
1320
- required: true
1321
- },
1322
- ticket: {
1323
- type: "positional",
1324
- description: "Ticket or reason ID (required for open)",
1325
- required: false
1326
- },
1327
- duration: {
1328
- type: "string",
1329
- description: "Window duration in minutes (default: 60)",
1330
- default: "60"
1331
- }
1332
- },
1333
- run({ args }) {
1334
- const action = args.action.toLowerCase();
1335
- if (action === "open") {
1336
- const ticket = args.ticket;
1337
- if (!ticket) {
1338
- console.error(
1339
- pc12.red(
1340
- 'Error: "cdal window open" requires a ticket or work order argument. Example: cdal window open WO-123'
1341
- )
1342
- );
1343
- process.exit(1);
1344
- }
1345
- const durationMinutes = Number.parseInt(args.duration, 10) || 60;
1346
- const status = openContractWindow(ticket, { durationMinutes });
1347
- console.log(pc12.green(`\u2714 Contract window opened for ticket: ${pc12.bold(status.ticket)}`));
1348
- console.log(pc12.dim(` Expires at: ${status.expiresAt}`));
1349
- return;
1350
- }
1351
- if (action === "close") {
1352
- closeContractWindow();
1353
- console.log(pc12.green("\u2714 Contract window closed. Protected paths are locked."));
1354
- return;
1355
- }
1356
- if (action === "status") {
1357
- const status = getContractWindowStatus();
1358
- if (status.open) {
1359
- console.log(pc12.green(`Contract window is ${pc12.bold("OPEN")}`));
1360
- console.log(` Ticket: ${status.ticket ?? "none"}`);
1361
- console.log(` Opened at: ${status.openedAt ?? "unknown"}`);
1362
- console.log(` Expires at: ${status.expiresAt ?? "unknown"}`);
1363
- } else {
1364
- console.log(pc12.yellow(`Contract window is ${pc12.bold("CLOSED")}`));
1365
- }
1366
- return;
69
+ process.exit(1);
1367
70
  }
1368
- console.error(pc12.red(`Unknown action "${action}". Available actions: open, close, status`));
1369
- process.exit(1);
1370
71
  }
1371
72
  });
1372
-
1373
- // src/cli.ts
1374
- var { version } = createRequire(import.meta.url)("../package.json");
1375
- var main = defineCommand14({
73
+ var main = defineCommand({
1376
74
  meta: {
1377
- name: "cdal",
1378
- version,
1379
- description: "Contract-Driven Agentic Loop (CDAL) Quality Gates & Audit CLI"
75
+ name: "cdalkit",
76
+ description: "CDAL: the free repository audit, and the installer for CDAL Pro"
1380
77
  },
1381
78
  subCommands: {
1382
- init: initCommand,
1383
- validate: validateCommand,
1384
- codegen: codegenCommand,
1385
- window: windowCommand,
1386
- trace: traceCommand,
1387
- phase: phaseCommand,
1388
- selftest: selftestCommand,
1389
- sync: syncCommand,
1390
- verify: verifyCommand,
1391
- doctor: doctorCommand,
1392
- hook: hookCommand,
1393
79
  audit: auditCommand,
1394
- pro: proCommand
80
+ pro: defineCommand({
81
+ meta: { name: "pro", description: "Install CDAL Pro into this project" },
82
+ subCommands: { install: proInstall }
83
+ }),
84
+ ...Object.fromEntries(PRO_COMMANDS.map((name) => [name, proOnly(name)]))
1395
85
  }
1396
86
  });
1397
- function runMain() {
1398
- cittyRunMain(main);
1399
- }
87
+ var runMain = () => cittyRunMain(main);
1400
88
  export {
89
+ proOnly,
1401
90
  runMain
1402
91
  };
1403
- //# sourceMappingURL=cli.js.map