cdalkit 0.1.7 → 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/LICENSE.md +14 -0
- package/README.md +14 -22
- package/dist/chunk-22BBUYVB.js +132 -0
- package/dist/cli.d.ts +6 -2
- package/dist/cli.js +60 -1396
- package/dist/index.d.ts +34 -4
- package/dist/index.js +20 -6
- package/package.json +7 -22
- package/LICENSE +0 -176
- package/dist/cli.js.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,1427 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
BootstrapError,
|
|
3
|
+
installProWithCore
|
|
4
|
+
} from "./chunk-22BBUYVB.js";
|
|
4
5
|
|
|
5
|
-
// src/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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: 'TODO',
|
|
520
|
-
priority: 'CRITICAL',
|
|
521
|
-
source: 'cdal.config.mjs',
|
|
522
|
-
},
|
|
523
|
-
{
|
|
524
|
-
id: 'REQ-CORE-INIT-2',
|
|
525
|
-
statement: 'Every implemented requirement is proven by a test tagged with its ID.',
|
|
526
|
-
acceptance: ['cdal trace --enforce passes'],
|
|
527
|
-
status: 'TODO',
|
|
528
|
-
priority: 'HIGH',
|
|
529
|
-
source: 'cdal.config.mjs',
|
|
530
|
-
},
|
|
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"
|
|
531
23
|
];
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
const runtimesFormatted = rawRuntimes.map((r) => `'${r}'`).join(", ");
|
|
541
|
-
const configContent = `import { defineConfig } from '@cdal/core';
|
|
542
|
-
import { policies, requirements, stateMachine } from '@cdal/kinds';
|
|
543
|
-
|
|
544
|
-
export default defineConfig({
|
|
545
|
-
contractsDir: 'contracts',
|
|
546
|
-
generated: {
|
|
547
|
-
ts: 'src/generated/contracts',
|
|
548
|
-
docs: 'docs/generated',
|
|
549
|
-
},
|
|
550
|
-
kinds: [requirements(), stateMachine(), policies()],
|
|
551
|
-
presets: ['${preset}'],
|
|
552
|
-
runtimes: [${runtimesFormatted}],
|
|
553
|
-
verify: [
|
|
554
|
-
'cdal validate --strict',
|
|
555
|
-
'cdal codegen --check',
|
|
556
|
-
'cdal trace --enforce',
|
|
557
|
-
'cdal selftest',
|
|
558
|
-
],
|
|
559
|
-
});
|
|
560
|
-
`;
|
|
561
|
-
writeFileSync2(configPath, configContent, "utf8");
|
|
562
|
-
console.log(pc4.green(` \u2713 Created configuration: ${pc4.bold("cdal.config.mjs")}`));
|
|
563
|
-
} else {
|
|
564
|
-
console.log(
|
|
565
|
-
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")}`
|
|
566
32
|
);
|
|
33
|
+
process.exit(1);
|
|
567
34
|
}
|
|
568
|
-
|
|
569
|
-
if (existsSync2(pkgPath)) {
|
|
570
|
-
try {
|
|
571
|
-
const pkgRaw = readFileSync2(pkgPath, "utf8");
|
|
572
|
-
const pkg = JSON.parse(pkgRaw);
|
|
573
|
-
pkg.scripts = pkg.scripts || {};
|
|
574
|
-
let updated = false;
|
|
575
|
-
if (!pkg.scripts.verify) {
|
|
576
|
-
pkg.scripts.verify = "cdal verify";
|
|
577
|
-
updated = true;
|
|
578
|
-
}
|
|
579
|
-
if (!pkg.scripts.selftest) {
|
|
580
|
-
pkg.scripts.selftest = "cdal selftest";
|
|
581
|
-
updated = true;
|
|
582
|
-
}
|
|
583
|
-
if (!pkg.scripts.trace) {
|
|
584
|
-
pkg.scripts.trace = "cdal trace";
|
|
585
|
-
updated = true;
|
|
586
|
-
}
|
|
587
|
-
if (updated) {
|
|
588
|
-
writeFileSync2(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
589
|
-
`, "utf8");
|
|
590
|
-
console.log(
|
|
591
|
-
pc4.green(` \u2713 Added verify/selftest/trace scripts to ${pc4.bold("package.json")}`)
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
} catch {
|
|
595
|
-
console.log(pc4.yellow(" \u26A0\uFE0F Could not update package.json scripts automatically."));
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
const resolvedConfig = resolveConfig({
|
|
599
|
-
presets: [preset],
|
|
600
|
-
runtimes: rawRuntimes
|
|
601
|
-
});
|
|
602
|
-
const syncRes = syncAdapters2({
|
|
603
|
-
cwd,
|
|
604
|
-
config: resolvedConfig,
|
|
605
|
-
check: false
|
|
606
|
-
});
|
|
607
|
-
console.log(
|
|
608
|
-
pc4.green(
|
|
609
|
-
` \u2713 Generated ${syncRes.updatedFiles.length} runtime adapter file(s) across [${rawRuntimes.join(", ")}].`
|
|
610
|
-
)
|
|
611
|
-
);
|
|
612
|
-
console.log(pc4.bold(pc4.green("\n\u{1F389} CDAL initialized successfully!")));
|
|
613
|
-
console.log(pc4.cyan("Next steps:"));
|
|
614
|
-
console.log(pc4.dim(" 1. Review contracts in contracts/*.contract.mjs"));
|
|
615
|
-
console.log(pc4.dim(" 2. Run `npx cdalkit doctor` to verify environment health"));
|
|
616
|
-
console.log(pc4.dim(" 3. Run `npx cdalkit verify` to test the loop gate\n"));
|
|
617
|
-
}
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
// src/commands/phase.ts
|
|
621
|
-
import { checkPhase, loadConfig as loadConfig4 } from "@cdal/core";
|
|
622
|
-
import { defineCommand as defineCommand6 } from "citty";
|
|
623
|
-
import pc5 from "picocolors";
|
|
624
|
-
var phaseCommand = defineCommand6({
|
|
625
|
-
meta: {
|
|
626
|
-
name: "phase",
|
|
627
|
-
description: "Verify git diff against active loop phase (contract, red, green)"
|
|
628
|
-
},
|
|
629
|
-
args: {
|
|
630
|
-
phase: {
|
|
631
|
-
type: "positional",
|
|
632
|
-
description: "Phase to verify: contract, red, green",
|
|
633
|
-
required: true
|
|
634
|
-
},
|
|
635
|
-
base: {
|
|
636
|
-
type: "string",
|
|
637
|
-
description: "Base git reference to compare against (e.g. main or origin/main)"
|
|
638
|
-
},
|
|
639
|
-
json: {
|
|
640
|
-
type: "boolean",
|
|
641
|
-
description: "Output as JSON payload",
|
|
642
|
-
default: false
|
|
643
|
-
},
|
|
644
|
-
config: {
|
|
645
|
-
type: "string",
|
|
646
|
-
description: "Path to cdal.config.mjs"
|
|
647
|
-
}
|
|
648
|
-
},
|
|
649
|
-
async run({ args }) {
|
|
650
|
-
const rawPhase = (args.phase || "").toLowerCase();
|
|
651
|
-
if (!["contract", "red", "green"].includes(rawPhase)) {
|
|
652
|
-
console.error(pc5.red(`Invalid phase "${rawPhase}". Valid phases are: contract, red, green.`));
|
|
653
|
-
process.exit(2);
|
|
654
|
-
}
|
|
655
|
-
const phase = rawPhase;
|
|
656
|
-
const cwd = process.cwd();
|
|
657
|
-
const { config: resolvedConfig } = await loadConfig4(args.config);
|
|
658
|
-
const result = checkPhase(phase, {
|
|
659
|
-
cwd,
|
|
660
|
-
base: args.base,
|
|
661
|
-
protectedPaths: resolvedConfig?.protectedPaths
|
|
662
|
-
});
|
|
663
|
-
if (args.json) {
|
|
664
|
-
console.log(JSON.stringify(result, null, 2));
|
|
665
|
-
process.exit(result.ok ? 0 : 1);
|
|
666
|
-
}
|
|
667
|
-
console.log(pc5.bold(`
|
|
668
|
-
Phase: ${result.label}`));
|
|
669
|
-
console.log(` Modified files in diff: ${result.files.length}
|
|
670
|
-
`);
|
|
671
|
-
if (result.violations.length === 0) {
|
|
672
|
-
if (result.files.length === 0) {
|
|
673
|
-
if (phase === "red") {
|
|
674
|
-
console.log(
|
|
675
|
-
pc5.yellow(
|
|
676
|
-
" \u26A0 No changes found in working tree. Phase RED requires at least one test."
|
|
677
|
-
)
|
|
678
|
-
);
|
|
679
|
-
process.exit(1);
|
|
680
|
-
}
|
|
681
|
-
console.log(pc5.dim(" No changes found in working tree."));
|
|
682
|
-
process.exit(0);
|
|
683
|
-
}
|
|
684
|
-
console.log(pc5.green(" \u2714 All changes are within active phase scopes."));
|
|
685
|
-
process.exit(0);
|
|
686
|
-
}
|
|
687
|
-
console.log(
|
|
688
|
-
pc5.red(` \u2717 ${result.violations.length} file(s) outside of permitted phase scope:
|
|
689
|
-
`)
|
|
690
|
-
);
|
|
691
|
-
for (const v of result.violations) {
|
|
692
|
-
console.log(` - ${v}`);
|
|
693
|
-
}
|
|
694
|
-
console.log(pc5.dim(`
|
|
695
|
-
${result.why}
|
|
696
|
-
`));
|
|
697
|
-
process.exit(1);
|
|
698
|
-
}
|
|
699
|
-
});
|
|
700
|
-
|
|
701
|
-
// src/commands/pro.ts
|
|
702
|
-
import { execFileSync } from "child_process";
|
|
703
|
-
import { existsSync as existsSync4, mkdtempSync, rmSync } from "fs";
|
|
704
|
-
import { tmpdir } from "os";
|
|
705
|
-
import { join as join4, resolve as resolve3 } from "path";
|
|
706
|
-
import { defineCommand as defineCommand7 } from "citty";
|
|
707
|
-
import pc6 from "picocolors";
|
|
708
|
-
|
|
709
|
-
// src/pro/install.ts
|
|
710
|
-
import {
|
|
711
|
-
copyFileSync,
|
|
712
|
-
existsSync as existsSync3,
|
|
713
|
-
mkdirSync as mkdirSync2,
|
|
714
|
-
readFileSync as readFileSync3,
|
|
715
|
-
readdirSync,
|
|
716
|
-
statSync,
|
|
717
|
-
writeFileSync as writeFileSync3
|
|
718
|
-
} from "fs";
|
|
719
|
-
import { dirname, isAbsolute, join as join3, relative, resolve as resolve2, sep } from "path";
|
|
720
|
-
var PRO_MANIFEST_FILE = "pro.manifest.json";
|
|
721
|
-
var PRO_RECORD_FILE = ".cdal/pro.json";
|
|
722
|
-
function proRecordFile(name) {
|
|
723
|
-
return name === "cdal-pro" ? PRO_RECORD_FILE : `.cdal/${name.replace(/^cdal-/, "")}.json`;
|
|
724
|
-
}
|
|
725
|
-
var GENERATED_MARKERS = ["CDAL GENERATED", "GENERATED by cdal sync"];
|
|
726
|
-
function isGeneratedFile(path2) {
|
|
727
|
-
const content = readFileSync3(path2, "utf8");
|
|
728
|
-
return GENERATED_MARKERS.some((marker) => content.includes(marker));
|
|
729
|
-
}
|
|
730
|
-
var ProInstallError = class extends Error {
|
|
731
|
-
constructor(message) {
|
|
732
|
-
super(message);
|
|
733
|
-
this.name = "ProInstallError";
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
function toPosix(path2) {
|
|
737
|
-
return path2.split(sep).join("/");
|
|
738
|
-
}
|
|
739
|
-
function resolveInside(root, rel, label) {
|
|
740
|
-
if (typeof rel !== "string" || rel.length === 0 || isAbsolute(rel)) {
|
|
741
|
-
throw new ProInstallError(`Invalid ${label} path in ${PRO_MANIFEST_FILE}: "${rel}"`);
|
|
742
|
-
}
|
|
743
|
-
const full = resolve2(root, rel);
|
|
744
|
-
const fromRoot = relative(root, full);
|
|
745
|
-
if (fromRoot.startsWith("..") || isAbsolute(fromRoot)) {
|
|
746
|
-
throw new ProInstallError(`${label} path "${rel}" escapes its directory`);
|
|
747
|
-
}
|
|
748
|
-
return full;
|
|
749
|
-
}
|
|
750
|
-
function readProManifest(sourceDir) {
|
|
751
|
-
const manifestPath = join3(sourceDir, PRO_MANIFEST_FILE);
|
|
752
|
-
if (!existsSync3(manifestPath)) {
|
|
753
|
-
throw new ProInstallError(`No ${PRO_MANIFEST_FILE} found in ${sourceDir}`);
|
|
754
|
-
}
|
|
755
|
-
let manifest;
|
|
756
|
-
try {
|
|
757
|
-
manifest = JSON.parse(readFileSync3(manifestPath, "utf8"));
|
|
758
|
-
} catch (err) {
|
|
759
|
-
throw new ProInstallError(
|
|
760
|
-
`${PRO_MANIFEST_FILE} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
761
|
-
);
|
|
762
|
-
}
|
|
763
|
-
if (!manifest.name || !manifest.version || !Array.isArray(manifest.install)) {
|
|
764
|
-
throw new ProInstallError(`${PRO_MANIFEST_FILE} must define name, version and install[]`);
|
|
765
|
-
}
|
|
766
|
-
return manifest;
|
|
767
|
-
}
|
|
768
|
-
function listFiles(dir) {
|
|
769
|
-
const files = [];
|
|
770
|
-
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
771
|
-
const full = join3(dir, entry.name);
|
|
772
|
-
if (entry.isDirectory()) files.push(...listFiles(full));
|
|
773
|
-
else if (entry.isFile()) files.push(full);
|
|
774
|
-
}
|
|
775
|
-
return files;
|
|
776
|
-
}
|
|
777
|
-
function installPro(options) {
|
|
778
|
-
const sourceDir = resolve2(options.sourceDir);
|
|
779
|
-
const targetDir = resolve2(options.targetDir);
|
|
780
|
-
const manifest = readProManifest(sourceDir);
|
|
781
|
-
const plan = [];
|
|
782
|
-
for (const mapping of manifest.install) {
|
|
783
|
-
const from = resolveInside(sourceDir, mapping.from, "from");
|
|
784
|
-
const to = resolveInside(targetDir, mapping.to, "to");
|
|
785
|
-
if (!existsSync3(from)) {
|
|
786
|
-
throw new ProInstallError(`Manifest source "${mapping.from}" does not exist`);
|
|
787
|
-
}
|
|
788
|
-
const sources = statSync(from).isDirectory() ? listFiles(from) : [from];
|
|
789
|
-
for (const src of sources) {
|
|
790
|
-
const dest = statSync(from).isDirectory() ? join3(to, relative(from, src)) : to;
|
|
791
|
-
plan.push({ src, dest, rel: toPosix(relative(targetDir, dest)) });
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
const written = [];
|
|
795
|
-
const skipped = [];
|
|
796
|
-
for (const { src, dest, rel } of plan) {
|
|
797
|
-
if (existsSync3(dest) && !options.force && !isGeneratedFile(dest)) {
|
|
798
|
-
skipped.push(rel);
|
|
799
|
-
continue;
|
|
800
|
-
}
|
|
801
|
-
written.push(rel);
|
|
802
|
-
if (!options.dryRun) {
|
|
803
|
-
mkdirSync2(dirname(dest), { recursive: true });
|
|
804
|
-
copyFileSync(src, dest);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
if (!options.dryRun) {
|
|
808
|
-
const recordPath = join3(targetDir, proRecordFile(manifest.name));
|
|
809
|
-
mkdirSync2(dirname(recordPath), { recursive: true });
|
|
810
|
-
writeFileSync3(
|
|
811
|
-
recordPath,
|
|
812
|
-
`${JSON.stringify(
|
|
813
|
-
{
|
|
814
|
-
name: manifest.name,
|
|
815
|
-
version: manifest.version,
|
|
816
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
817
|
-
files: plan.map((p) => p.rel).sort()
|
|
818
|
-
},
|
|
819
|
-
null,
|
|
820
|
-
2
|
|
821
|
-
)}
|
|
822
|
-
`,
|
|
823
|
-
"utf8"
|
|
824
|
-
);
|
|
825
|
-
}
|
|
826
|
-
return { name: manifest.name, version: manifest.version, written, skipped };
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// src/commands/pro.ts
|
|
830
|
-
var PRO_REPOSITORY_URL = "https://github.com/cdalkit/cdal-pro.git";
|
|
831
|
-
var PRO_TEAM_REPOSITORY_URL = "https://github.com/cdalkit/cdal-pro-team.git";
|
|
832
|
-
function proRepositoryUrl(team) {
|
|
833
|
-
return team ? PRO_TEAM_REPOSITORY_URL : PRO_REPOSITORY_URL;
|
|
834
|
-
}
|
|
835
|
-
function resolveSource(from) {
|
|
836
|
-
const local = resolve3(from);
|
|
837
|
-
if (existsSync4(local)) return { dir: local, cleanup: () => {
|
|
838
|
-
} };
|
|
839
|
-
const dir = mkdtempSync(join4(tmpdir(), "cdal-pro-"));
|
|
840
|
-
const cleanup = () => rmSync(dir, { recursive: true, force: true });
|
|
841
|
-
try {
|
|
842
|
-
execFileSync("git", ["clone", "--depth", "1", "--quiet", from, dir], {
|
|
843
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
844
|
-
});
|
|
845
|
-
} catch {
|
|
846
|
-
cleanup();
|
|
847
|
-
throw new ProInstallError(
|
|
848
|
-
`Could not clone ${from}.
|
|
849
|
-
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.`
|
|
850
|
-
);
|
|
851
|
-
}
|
|
852
|
-
return { dir, cleanup };
|
|
35
|
+
});
|
|
853
36
|
}
|
|
854
|
-
var
|
|
37
|
+
var proInstall = defineCommand({
|
|
855
38
|
meta: {
|
|
856
39
|
name: "install",
|
|
857
|
-
description: "Install CDAL Pro
|
|
40
|
+
description: "Install CDAL Pro (the CDAL core, agent roles, templates and presets) into this project"
|
|
858
41
|
},
|
|
859
42
|
args: {
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
},
|
|
864
|
-
|
|
865
|
-
type: "boolean",
|
|
866
|
-
description: "Install CDAL Pro Team (editor guards, presets, playbook) from cdal-pro-team",
|
|
867
|
-
default: false
|
|
868
|
-
},
|
|
869
|
-
cwd: {
|
|
870
|
-
type: "string",
|
|
871
|
-
description: "Project directory to install into",
|
|
872
|
-
default: "."
|
|
873
|
-
},
|
|
874
|
-
force: {
|
|
875
|
-
type: "boolean",
|
|
876
|
-
description: "Overwrite files that already exist in the project",
|
|
877
|
-
default: false
|
|
878
|
-
},
|
|
879
|
-
dryRun: {
|
|
880
|
-
type: "boolean",
|
|
881
|
-
description: "Show what would be installed without writing anything",
|
|
882
|
-
default: false
|
|
883
|
-
}
|
|
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 }
|
|
884
48
|
},
|
|
885
49
|
run({ args }) {
|
|
886
|
-
let source;
|
|
887
50
|
try {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
51
|
+
const manifest = installProWithCore({
|
|
52
|
+
cwd: args.cwd,
|
|
53
|
+
from: args.from,
|
|
54
|
+
team: args.team,
|
|
55
|
+
teamFrom: args.teamFrom,
|
|
892
56
|
force: args.force,
|
|
893
|
-
|
|
57
|
+
log: (line) => console.log(pc.dim(line))
|
|
894
58
|
});
|
|
895
|
-
|
|
896
|
-
console.log(pc6.green(`\u2714 ${verb} ${result.name} ${result.version}`));
|
|
897
|
-
console.log(` ${result.written.length} file(s) ${args.dryRun ? "to write" : "written"}`);
|
|
898
|
-
if (result.skipped.length > 0) {
|
|
899
|
-
console.log(
|
|
900
|
-
pc6.yellow(
|
|
901
|
-
` ${result.skipped.length} existing file(s) kept \u2014 rerun with --force to overwrite:`
|
|
902
|
-
)
|
|
903
|
-
);
|
|
904
|
-
for (const file of result.skipped) console.log(pc6.dim(` ${file}`));
|
|
905
|
-
}
|
|
906
|
-
if (!args.dryRun) {
|
|
907
|
-
console.log(pc6.dim(" Run `npx cdalkit sync` to wire the new roles into your runtimes."));
|
|
908
|
-
}
|
|
909
|
-
} catch (err) {
|
|
910
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
911
|
-
console.error(pc6.red(`\u2716 ${message}`));
|
|
912
|
-
process.exit(1);
|
|
913
|
-
} finally {
|
|
914
|
-
source?.cleanup();
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
});
|
|
918
|
-
var proCommand = defineCommand7({
|
|
919
|
-
meta: {
|
|
920
|
-
name: "pro",
|
|
921
|
-
description: "CDAL Pro: install licensed agent roles, templates and presets"
|
|
922
|
-
},
|
|
923
|
-
subCommands: {
|
|
924
|
-
install: installCommand
|
|
925
|
-
}
|
|
926
|
-
});
|
|
927
|
-
|
|
928
|
-
// src/commands/selftest.ts
|
|
929
|
-
import { loadConfig as loadConfig5, runSelftest } from "@cdal/core";
|
|
930
|
-
import { defineCommand as defineCommand8 } from "citty";
|
|
931
|
-
import pc7 from "picocolors";
|
|
932
|
-
var selftestCommand = defineCommand8({
|
|
933
|
-
meta: {
|
|
934
|
-
name: "selftest",
|
|
935
|
-
description: "Run mutation testing on contract invariant rules and content guardrails"
|
|
936
|
-
},
|
|
937
|
-
args: {
|
|
938
|
-
json: {
|
|
939
|
-
type: "boolean",
|
|
940
|
-
description: "Output as JSON payload (selftest.v1)",
|
|
941
|
-
default: false
|
|
942
|
-
},
|
|
943
|
-
config: {
|
|
944
|
-
type: "string",
|
|
945
|
-
description: "Path to cdal.config.mjs"
|
|
946
|
-
}
|
|
947
|
-
},
|
|
948
|
-
async run({ args }) {
|
|
949
|
-
const cwd = process.cwd();
|
|
950
|
-
const { config: resolvedConfig } = await loadConfig5(args.config);
|
|
951
|
-
if (!args.json) {
|
|
952
|
-
console.log(pc7.bold(pc7.cyan("\n cdal selftest \u2014 mutation testing of quality gates")));
|
|
953
|
-
console.log(
|
|
954
|
-
pc7.dim(" Testing whether validator and guardrails actually fire red when violated\n")
|
|
955
|
-
);
|
|
956
|
-
}
|
|
957
|
-
const report = await runSelftest({
|
|
958
|
-
cwd,
|
|
959
|
-
config: resolvedConfig
|
|
960
|
-
});
|
|
961
|
-
if (args.json) {
|
|
962
|
-
console.log(JSON.stringify(report, null, 2));
|
|
963
|
-
process.exit(report.ok ? 0 : 1);
|
|
964
|
-
}
|
|
965
|
-
if (report.mutationResults.length > 0) {
|
|
966
|
-
console.log(
|
|
967
|
-
pc7.bold(
|
|
968
|
-
` Contract Invariant Mutations (${report.mutationsPassed}/${report.mutationsTotal}):`
|
|
969
|
-
)
|
|
970
|
-
);
|
|
971
|
-
for (const m of report.mutationResults) {
|
|
972
|
-
if (m.passed) {
|
|
973
|
-
console.log(
|
|
974
|
-
` ${pc7.green("\u2714")} ${pc7.cyan(m.rule.padEnd(26))} detected in ${pc7.dim(m.file)}`
|
|
975
|
-
);
|
|
976
|
-
} else {
|
|
977
|
-
console.log(
|
|
978
|
-
` ${pc7.red("\u2717")} ${pc7.red(m.rule.padEnd(26))} ${pc7.bold("MISSED")}: ${m.error ?? "rule dead"}`
|
|
979
|
-
);
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
console.log("");
|
|
983
|
-
}
|
|
984
|
-
if (report.probeResults.length > 0) {
|
|
59
|
+
console.log(pc.green(`\u2714 CDAL Pro is installed (core ${manifest.version}).`));
|
|
985
60
|
console.log(
|
|
986
|
-
|
|
61
|
+
" Commit the result (including .cdal/vendor/) so your teammates get the same setup."
|
|
987
62
|
);
|
|
988
|
-
|
|
989
|
-
const action = p.fires ? "detected" : "allowed";
|
|
990
|
-
if (p.passed) {
|
|
991
|
-
console.log(
|
|
992
|
-
` ${pc7.green("\u2714")} ${pc7.cyan(p.rule.padEnd(30))} ${pc7.green(action)}: ${p.desc}`
|
|
993
|
-
);
|
|
994
|
-
} else {
|
|
995
|
-
console.log(
|
|
996
|
-
` ${pc7.red("\u2717")} ${pc7.red(p.rule.padEnd(30))} ${pc7.bold("FAILED")}: ${p.error ?? "unexpected behavior"}`
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
console.log("");
|
|
1001
|
-
}
|
|
1002
|
-
console.log(
|
|
1003
|
-
pc7.bold(
|
|
1004
|
-
` Summary: ${report.mutationsPassed}/${report.mutationsTotal} contract rules verified via mutation.`
|
|
1005
|
-
)
|
|
1006
|
-
);
|
|
1007
|
-
console.log(
|
|
1008
|
-
pc7.bold(
|
|
1009
|
-
` ${report.probesPassed}/${report.probesTotal} content guardrail probes verified.
|
|
1010
|
-
`
|
|
1011
|
-
)
|
|
1012
|
-
);
|
|
1013
|
-
if (report.skippedKinds.length > 0) {
|
|
1014
|
-
console.log(pc7.dim(` Skipped (no contract file yet): ${report.skippedKinds.join(", ")}
|
|
1015
|
-
`));
|
|
1016
|
-
}
|
|
1017
|
-
if (report.failures.length > 0) {
|
|
1018
|
-
console.log(pc7.bold(pc7.red(" CRITICAL GATE FAILURES:")));
|
|
1019
|
-
for (const f of report.failures) {
|
|
1020
|
-
console.log(` - ${pc7.red(f)}`);
|
|
1021
|
-
}
|
|
1022
|
-
console.log("");
|
|
1023
|
-
process.exit(1);
|
|
1024
|
-
}
|
|
1025
|
-
console.log(pc7.green(pc7.bold(" \u2714 Every quality gate rule is verified active and firing.\n")));
|
|
1026
|
-
process.exit(0);
|
|
1027
|
-
}
|
|
1028
|
-
});
|
|
1029
|
-
|
|
1030
|
-
// src/commands/sync.ts
|
|
1031
|
-
import { syncAdapters as syncAdapters3 } from "@cdal/adapters";
|
|
1032
|
-
import { loadConfig as loadConfig6 } from "@cdal/core";
|
|
1033
|
-
import { defineCommand as defineCommand9 } from "citty";
|
|
1034
|
-
import pc8 from "picocolors";
|
|
1035
|
-
var syncCommand = defineCommand9({
|
|
1036
|
-
meta: {
|
|
1037
|
-
name: "sync",
|
|
1038
|
-
description: "Synchronize agent definitions, commands, hooks and rules across configured runtimes (with --check drift detection)"
|
|
1039
|
-
},
|
|
1040
|
-
args: {
|
|
1041
|
-
check: {
|
|
1042
|
-
type: "boolean",
|
|
1043
|
-
description: "Check for drift between cdal.config.mjs and runtime files without modifying disk",
|
|
1044
|
-
default: false
|
|
1045
|
-
},
|
|
1046
|
-
config: {
|
|
1047
|
-
type: "string",
|
|
1048
|
-
description: "Custom path to cdal.config.mjs"
|
|
1049
|
-
},
|
|
1050
|
-
cwd: {
|
|
1051
|
-
type: "string",
|
|
1052
|
-
description: "Working directory path"
|
|
1053
|
-
}
|
|
1054
|
-
},
|
|
1055
|
-
async run({ args }) {
|
|
1056
|
-
try {
|
|
1057
|
-
const cwd = args.cwd || process.cwd();
|
|
1058
|
-
const { config } = await loadConfig6(args.config || cwd);
|
|
1059
|
-
const res = syncAdapters3({
|
|
1060
|
-
cwd,
|
|
1061
|
-
config,
|
|
1062
|
-
check: Boolean(args.check)
|
|
1063
|
-
});
|
|
1064
|
-
if (args.check) {
|
|
1065
|
-
if (res.inSync) {
|
|
1066
|
-
console.log(
|
|
1067
|
-
pc8.green(
|
|
1068
|
-
`\u2705 Sync check passed: all ${res.totalFiles} adapter file(s) are in sync across [${config.runtimes.join(", ")}].`
|
|
1069
|
-
)
|
|
1070
|
-
);
|
|
1071
|
-
} else {
|
|
1072
|
-
console.error(
|
|
1073
|
-
pc8.red(
|
|
1074
|
-
`\u274C Sync check failed: ${res.driftedFiles.length} adapter file(s) drifted from configuration:`
|
|
1075
|
-
)
|
|
1076
|
-
);
|
|
1077
|
-
for (const file of res.driftedFiles) {
|
|
1078
|
-
console.error(pc8.red(` - [DRIFT] ${file}`));
|
|
1079
|
-
}
|
|
1080
|
-
console.error(
|
|
1081
|
-
pc8.yellow(
|
|
1082
|
-
"\nRun `npx cdalkit sync` to synchronize runtime files with cdal.config.mjs."
|
|
1083
|
-
)
|
|
1084
|
-
);
|
|
1085
|
-
process.exit(1);
|
|
1086
|
-
}
|
|
1087
|
-
} else {
|
|
1088
|
-
console.log(
|
|
1089
|
-
pc8.green(
|
|
1090
|
-
`\u2705 Synchronized ${res.updatedFiles.length} adapter file(s) across [${config.runtimes.join(", ")}]:`
|
|
1091
|
-
)
|
|
1092
|
-
);
|
|
1093
|
-
for (const file of res.updatedFiles) {
|
|
1094
|
-
console.log(pc8.cyan(` - ${file}`));
|
|
1095
|
-
}
|
|
1096
|
-
if (res.updatedFiles.length === 0) {
|
|
1097
|
-
console.log(pc8.dim(" (All files were already up-to-date)"));
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
if (res.preservedFiles.length > 0) {
|
|
1101
|
-
console.log(
|
|
1102
|
-
pc8.dim(
|
|
1103
|
-
` ${res.preservedFiles.length} file(s) marked cdal:preserve were left untouched.`
|
|
1104
|
-
)
|
|
1105
|
-
);
|
|
1106
|
-
}
|
|
1107
|
-
} catch (err) {
|
|
1108
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1109
|
-
console.error(pc8.red(`\u274C Fatal error during sync: ${msg}`));
|
|
1110
|
-
process.exit(1);
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
});
|
|
1114
|
-
|
|
1115
|
-
// src/commands/trace.ts
|
|
1116
|
-
import path from "path";
|
|
1117
|
-
import { pathToFileURL } from "url";
|
|
1118
|
-
import {
|
|
1119
|
-
formatTraceMarkdown,
|
|
1120
|
-
formatTraceText,
|
|
1121
|
-
loadConfig as loadConfig7,
|
|
1122
|
-
scanTrace
|
|
1123
|
-
} from "@cdal/core";
|
|
1124
|
-
import { defineCommand as defineCommand10 } from "citty";
|
|
1125
|
-
import pc9 from "picocolors";
|
|
1126
|
-
var traceCommand = defineCommand10({
|
|
1127
|
-
meta: {
|
|
1128
|
-
name: "trace",
|
|
1129
|
-
description: "Inspect requirement-to-test traceability matrix (@REQ tags)"
|
|
1130
|
-
},
|
|
1131
|
-
args: {
|
|
1132
|
-
enforce: {
|
|
1133
|
-
type: "boolean",
|
|
1134
|
-
description: "Exit with code 1 if any implementing/done requirement lacks tests, tests fail, or unknown @REQ tags exist",
|
|
1135
|
-
default: false
|
|
1136
|
-
},
|
|
1137
|
-
markdown: {
|
|
1138
|
-
type: "boolean",
|
|
1139
|
-
description: "Output as Markdown table ready for pull request description",
|
|
1140
|
-
default: false
|
|
1141
|
-
},
|
|
1142
|
-
json: {
|
|
1143
|
-
type: "boolean",
|
|
1144
|
-
description: "Output as structured JSON (trace.v1)",
|
|
1145
|
-
default: false
|
|
1146
|
-
},
|
|
1147
|
-
results: {
|
|
1148
|
-
type: "string",
|
|
1149
|
-
description: "Path to test execution JSON results file (vitest or playwright json reporter)"
|
|
1150
|
-
},
|
|
1151
|
-
config: {
|
|
1152
|
-
type: "string",
|
|
1153
|
-
description: "Path to cdal.config.mjs"
|
|
1154
|
-
}
|
|
1155
|
-
},
|
|
1156
|
-
async run({ args }) {
|
|
1157
|
-
const cwd = process.cwd();
|
|
1158
|
-
const { config: resolvedConfig } = await loadConfig7(args.config);
|
|
1159
|
-
const contractsDir = resolvedConfig?.contractsDir ?? "contracts";
|
|
1160
|
-
const reqContractPath = path.resolve(cwd, contractsDir, "requirements.contract.mjs");
|
|
1161
|
-
let requirements2 = [];
|
|
1162
|
-
try {
|
|
1163
|
-
const imported = await import(pathToFileURL(reqContractPath).href);
|
|
1164
|
-
requirements2 = imported.REQUIREMENTS || imported.default?.REQUIREMENTS || imported.default || [];
|
|
1165
|
-
} catch (err) {
|
|
1166
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1167
|
-
console.error(pc9.red(`Failed to load requirements from "${reqContractPath}": ${errorMsg}`));
|
|
1168
|
-
process.exit(1);
|
|
1169
|
-
}
|
|
1170
|
-
if (!Array.isArray(requirements2) || requirements2.length === 0) {
|
|
1171
|
-
console.warn(pc9.yellow(`No requirements found in "${reqContractPath}".`));
|
|
1172
|
-
if (args.enforce) process.exit(1);
|
|
1173
|
-
return;
|
|
1174
|
-
}
|
|
1175
|
-
const report = scanTrace(requirements2, {
|
|
1176
|
-
cwd,
|
|
1177
|
-
resultsFile: args.results
|
|
1178
|
-
});
|
|
1179
|
-
if (args.json) {
|
|
1180
|
-
console.log(JSON.stringify(report, null, 2));
|
|
1181
|
-
} else if (args.markdown) {
|
|
1182
|
-
console.log(formatTraceMarkdown(report));
|
|
1183
|
-
} else {
|
|
1184
|
-
console.log(formatTraceText(report));
|
|
1185
|
-
}
|
|
1186
|
-
if (args.enforce && !report.ok) {
|
|
1187
|
-
process.exit(1);
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
});
|
|
1191
|
-
|
|
1192
|
-
// src/commands/validate.ts
|
|
1193
|
-
import { formatFindingsText, runValidation } from "@cdal/core";
|
|
1194
|
-
import { defineCommand as defineCommand11 } from "citty";
|
|
1195
|
-
import pc10 from "picocolors";
|
|
1196
|
-
var validateCommand = defineCommand11({
|
|
1197
|
-
meta: {
|
|
1198
|
-
name: "validate",
|
|
1199
|
-
description: "Validate contract invariants across all registered contract kinds"
|
|
1200
|
-
},
|
|
1201
|
-
args: {
|
|
1202
|
-
strict: {
|
|
1203
|
-
type: "boolean",
|
|
1204
|
-
description: "Treat warnings as failures (exit 1)",
|
|
1205
|
-
default: false
|
|
1206
|
-
},
|
|
1207
|
-
json: {
|
|
1208
|
-
type: "boolean",
|
|
1209
|
-
description: "Output findings using machine-readable findings.v1 JSON schema",
|
|
1210
|
-
default: false
|
|
1211
|
-
},
|
|
1212
|
-
dir: {
|
|
1213
|
-
type: "string",
|
|
1214
|
-
description: "Custom path to contracts directory"
|
|
1215
|
-
}
|
|
1216
|
-
},
|
|
1217
|
-
async run({ args }) {
|
|
1218
|
-
try {
|
|
1219
|
-
const kinds = await resolveCommandKinds();
|
|
1220
|
-
const report = await runValidation({
|
|
1221
|
-
contractsDir: args.dir,
|
|
1222
|
-
strict: Boolean(args.strict),
|
|
1223
|
-
kinds
|
|
1224
|
-
});
|
|
1225
|
-
if (args.json) {
|
|
1226
|
-
console.log(JSON.stringify(report, null, 2));
|
|
1227
|
-
} else {
|
|
1228
|
-
const text = formatFindingsText(report, Boolean(args.strict));
|
|
1229
|
-
if (report.valid) {
|
|
1230
|
-
console.log(pc10.green(text));
|
|
1231
|
-
} else {
|
|
1232
|
-
console.error(pc10.red(text));
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
if (!report.valid) {
|
|
1236
|
-
process.exit(1);
|
|
1237
|
-
}
|
|
63
|
+
console.log(" Next: open your editor and describe what you want to build.");
|
|
1238
64
|
} catch (err) {
|
|
1239
|
-
const
|
|
1240
|
-
console.error(
|
|
1241
|
-
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
});
|
|
1245
|
-
|
|
1246
|
-
// src/commands/verify.ts
|
|
1247
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
1248
|
-
import { loadConfig as loadConfig8 } from "@cdal/core";
|
|
1249
|
-
import { defineCommand as defineCommand12 } from "citty";
|
|
1250
|
-
import pc11 from "picocolors";
|
|
1251
|
-
var verifyCommand = defineCommand12({
|
|
1252
|
-
meta: {
|
|
1253
|
-
name: "verify",
|
|
1254
|
-
description: "Run deterministic CDAL verification pipeline defined in configuration"
|
|
1255
|
-
},
|
|
1256
|
-
args: {
|
|
1257
|
-
fast: {
|
|
1258
|
-
type: "boolean",
|
|
1259
|
-
description: "Run fast subset of verification steps (contract checks & selftest)",
|
|
1260
|
-
default: false
|
|
1261
|
-
},
|
|
1262
|
-
full: {
|
|
1263
|
-
type: "boolean",
|
|
1264
|
-
description: "Force execution of all verification steps",
|
|
1265
|
-
default: false
|
|
1266
|
-
},
|
|
1267
|
-
clean: {
|
|
1268
|
-
type: "boolean",
|
|
1269
|
-
description: "Clear temporary caches before running verification",
|
|
1270
|
-
default: false
|
|
1271
|
-
},
|
|
1272
|
-
config: {
|
|
1273
|
-
type: "string",
|
|
1274
|
-
description: "Path to cdal.config.mjs"
|
|
1275
|
-
},
|
|
1276
|
-
cwd: {
|
|
1277
|
-
type: "string",
|
|
1278
|
-
description: "Working directory path"
|
|
1279
|
-
}
|
|
1280
|
-
},
|
|
1281
|
-
async run({ args }) {
|
|
1282
|
-
const cwd = args.cwd || process.cwd();
|
|
1283
|
-
const { config } = await loadConfig8(args.config || cwd);
|
|
1284
|
-
let steps = [...config.verify];
|
|
1285
|
-
if (args.fast) {
|
|
1286
|
-
steps = steps.filter(
|
|
1287
|
-
(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}`}`)
|
|
1288
68
|
);
|
|
1289
|
-
|
|
1290
|
-
steps = [config.verify[0] ?? "cdal validate --strict"];
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
console.log(
|
|
1294
|
-
pc11.bold(pc11.cyan(`
|
|
1295
|
-
\u26A1 Running CDAL Verification Pipeline (${steps.length} step(s))...
|
|
1296
|
-
`))
|
|
1297
|
-
);
|
|
1298
|
-
for (let i = 0; i < steps.length; i++) {
|
|
1299
|
-
const step = steps[i];
|
|
1300
|
-
if (!step) continue;
|
|
1301
|
-
console.log(pc11.bold(pc11.blue(`[${i + 1}/${steps.length}] \u25B6 ${step}`)));
|
|
1302
|
-
const start = Date.now();
|
|
1303
|
-
const res = spawnSync2(step, {
|
|
1304
|
-
cwd,
|
|
1305
|
-
shell: true,
|
|
1306
|
-
stdio: "inherit"
|
|
1307
|
-
});
|
|
1308
|
-
const duration = Date.now() - start;
|
|
1309
|
-
if (res.status !== 0) {
|
|
1310
|
-
console.error(
|
|
1311
|
-
pc11.bold(
|
|
1312
|
-
pc11.red(
|
|
1313
|
-
`
|
|
1314
|
-
\u274C Verification failed at step: "${step}" (exit code ${res.status ?? 1}, took ${duration}ms)`
|
|
1315
|
-
)
|
|
1316
|
-
)
|
|
1317
|
-
);
|
|
1318
|
-
process.exit(res.status ?? 1);
|
|
1319
|
-
}
|
|
1320
|
-
console.log(pc11.green(` \u2713 Step passed in ${duration}ms
|
|
1321
|
-
`));
|
|
1322
|
-
}
|
|
1323
|
-
console.log(
|
|
1324
|
-
pc11.bold(
|
|
1325
|
-
pc11.green(`\u2705 Full verification pipeline succeeded (${steps.length} step(s) passed).`)
|
|
1326
|
-
)
|
|
1327
|
-
);
|
|
1328
|
-
}
|
|
1329
|
-
});
|
|
1330
|
-
|
|
1331
|
-
// src/commands/window.ts
|
|
1332
|
-
import { closeContractWindow, getContractWindowStatus, openContractWindow } from "@cdal/core";
|
|
1333
|
-
import { defineCommand as defineCommand13 } from "citty";
|
|
1334
|
-
import pc12 from "picocolors";
|
|
1335
|
-
var windowCommand = defineCommand13({
|
|
1336
|
-
meta: {
|
|
1337
|
-
name: "window",
|
|
1338
|
-
description: "Manage contract window for protected path modifications"
|
|
1339
|
-
},
|
|
1340
|
-
args: {
|
|
1341
|
-
action: {
|
|
1342
|
-
type: "positional",
|
|
1343
|
-
description: "Action to perform: open, close, status",
|
|
1344
|
-
required: true
|
|
1345
|
-
},
|
|
1346
|
-
ticket: {
|
|
1347
|
-
type: "positional",
|
|
1348
|
-
description: "Ticket or reason ID (required for open)",
|
|
1349
|
-
required: false
|
|
1350
|
-
},
|
|
1351
|
-
duration: {
|
|
1352
|
-
type: "string",
|
|
1353
|
-
description: "Window duration in minutes (default: 60)",
|
|
1354
|
-
default: "60"
|
|
1355
|
-
}
|
|
1356
|
-
},
|
|
1357
|
-
run({ args }) {
|
|
1358
|
-
const action = args.action.toLowerCase();
|
|
1359
|
-
if (action === "open") {
|
|
1360
|
-
const ticket = args.ticket;
|
|
1361
|
-
if (!ticket) {
|
|
1362
|
-
console.error(
|
|
1363
|
-
pc12.red(
|
|
1364
|
-
'Error: "cdal window open" requires a ticket or work order argument. Example: cdal window open WO-123'
|
|
1365
|
-
)
|
|
1366
|
-
);
|
|
1367
|
-
process.exit(1);
|
|
1368
|
-
}
|
|
1369
|
-
const durationMinutes = Number.parseInt(args.duration, 10) || 60;
|
|
1370
|
-
const status = openContractWindow(ticket, { durationMinutes });
|
|
1371
|
-
console.log(pc12.green(`\u2714 Contract window opened for ticket: ${pc12.bold(status.ticket)}`));
|
|
1372
|
-
console.log(pc12.dim(` Expires at: ${status.expiresAt}`));
|
|
1373
|
-
return;
|
|
1374
|
-
}
|
|
1375
|
-
if (action === "close") {
|
|
1376
|
-
closeContractWindow();
|
|
1377
|
-
console.log(pc12.green("\u2714 Contract window closed. Protected paths are locked."));
|
|
1378
|
-
return;
|
|
1379
|
-
}
|
|
1380
|
-
if (action === "status") {
|
|
1381
|
-
const status = getContractWindowStatus();
|
|
1382
|
-
if (status.open) {
|
|
1383
|
-
console.log(pc12.green(`Contract window is ${pc12.bold("OPEN")}`));
|
|
1384
|
-
console.log(` Ticket: ${status.ticket ?? "none"}`);
|
|
1385
|
-
console.log(` Opened at: ${status.openedAt ?? "unknown"}`);
|
|
1386
|
-
console.log(` Expires at: ${status.expiresAt ?? "unknown"}`);
|
|
1387
|
-
} else {
|
|
1388
|
-
console.log(pc12.yellow(`Contract window is ${pc12.bold("CLOSED")}`));
|
|
1389
|
-
}
|
|
1390
|
-
return;
|
|
69
|
+
process.exit(1);
|
|
1391
70
|
}
|
|
1392
|
-
console.error(pc12.red(`Unknown action "${action}". Available actions: open, close, status`));
|
|
1393
|
-
process.exit(1);
|
|
1394
71
|
}
|
|
1395
72
|
});
|
|
1396
|
-
|
|
1397
|
-
// src/cli.ts
|
|
1398
|
-
var { version } = createRequire(import.meta.url)("../package.json");
|
|
1399
|
-
var main = defineCommand14({
|
|
73
|
+
var main = defineCommand({
|
|
1400
74
|
meta: {
|
|
1401
|
-
name: "
|
|
1402
|
-
|
|
1403
|
-
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"
|
|
1404
77
|
},
|
|
1405
78
|
subCommands: {
|
|
1406
|
-
init: initCommand,
|
|
1407
|
-
validate: validateCommand,
|
|
1408
|
-
codegen: codegenCommand,
|
|
1409
|
-
window: windowCommand,
|
|
1410
|
-
trace: traceCommand,
|
|
1411
|
-
phase: phaseCommand,
|
|
1412
|
-
selftest: selftestCommand,
|
|
1413
|
-
sync: syncCommand,
|
|
1414
|
-
verify: verifyCommand,
|
|
1415
|
-
doctor: doctorCommand,
|
|
1416
|
-
hook: hookCommand,
|
|
1417
79
|
audit: auditCommand,
|
|
1418
|
-
pro:
|
|
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)]))
|
|
1419
85
|
}
|
|
1420
86
|
});
|
|
1421
|
-
|
|
1422
|
-
cittyRunMain(main);
|
|
1423
|
-
}
|
|
87
|
+
var runMain = () => cittyRunMain(main);
|
|
1424
88
|
export {
|
|
89
|
+
proOnly,
|
|
1425
90
|
runMain
|
|
1426
91
|
};
|
|
1427
|
-
//# sourceMappingURL=cli.js.map
|