azcodr 2.5.1 → 2.7.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.
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "safety-guard": {
3
- "enabled": false,
3
+ "enabled": true,
4
4
  "PreToolUse": [
5
5
  {
6
6
  "matcher": "run_command",
7
7
  "hooks": [
8
8
  {
9
9
  "type": "command",
10
- "command": "./.agents/scripts/safety_guard.sh",
10
+ "command": "node .agents/scripts/safety_guard.js",
11
11
  "timeout": 15
12
12
  }
13
13
  ]
@@ -15,14 +15,14 @@
15
15
  ]
16
16
  },
17
17
  "architectural-guard": {
18
- "enabled": false,
18
+ "enabled": true,
19
19
  "PreToolUse": [
20
20
  {
21
21
  "matcher": "run_command",
22
22
  "hooks": [
23
23
  {
24
24
  "type": "command",
25
- "command": "./.agents/scripts/agent_guard.js",
25
+ "command": "node .agents/scripts/agent_guard.js",
26
26
  "timeout": 15
27
27
  }
28
28
  ]
@@ -30,7 +30,7 @@
30
30
  ]
31
31
  },
32
32
  "post-tool-lint": {
33
- "enabled": false,
33
+ "enabled": true,
34
34
  "PostToolUse": [
35
35
  {
36
36
  "matcher": "run_command",
@@ -45,11 +45,11 @@
45
45
  ]
46
46
  },
47
47
  "stop-verifier": {
48
- "enabled": false,
48
+ "enabled": true,
49
49
  "Stop": [
50
50
  {
51
51
  "type": "command",
52
- "command": "./.agents/scripts/verify_completion.sh",
52
+ "command": "node .agents/scripts/verify_completion.js",
53
53
  "timeout": 120
54
54
  }
55
55
  ]
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "safety-guard": {
3
- "enabled": false,
3
+ "enabled": true,
4
4
  "PreToolUse": [
5
5
  {
6
6
  "matcher": "run_command",
7
7
  "hooks": [
8
8
  {
9
9
  "type": "command",
10
- "command": "./.agents/scripts/safety_guard.sh",
10
+ "command": "node .agents/scripts/safety_guard.js",
11
11
  "timeout": 15
12
12
  }
13
13
  ]
@@ -15,14 +15,14 @@
15
15
  ]
16
16
  },
17
17
  "architectural-guard": {
18
- "enabled": false,
18
+ "enabled": true,
19
19
  "PreToolUse": [
20
20
  {
21
21
  "matcher": "run_command",
22
22
  "hooks": [
23
23
  {
24
24
  "type": "command",
25
- "command": "./.agents/scripts/agent_guard.js",
25
+ "command": "node .agents/scripts/agent_guard.js",
26
26
  "timeout": 15
27
27
  }
28
28
  ]
@@ -30,7 +30,7 @@
30
30
  ]
31
31
  },
32
32
  "post-tool-lint": {
33
- "enabled": false,
33
+ "enabled": true,
34
34
  "PostToolUse": [
35
35
  {
36
36
  "matcher": "run_command",
@@ -45,12 +45,12 @@
45
45
  ]
46
46
  },
47
47
  "stop-verifier": {
48
- "enabled": false,
48
+ "enabled": true,
49
49
  "Stop": [
50
50
  {
51
51
  "type": "command",
52
- "command": "./.agents/scripts/verify_completion.sh",
53
- "timeout": 15
52
+ "command": "node .agents/scripts/verify_completion.js",
53
+ "timeout": 120
54
54
  }
55
55
  ]
56
56
  }
@@ -0,0 +1,158 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export const DEFAULT_BOUNDARY_RULES = [
4
+ {
5
+ fromLayer: 'domain',
6
+ disallowImportsFrom: ['infrastructure', 'infra', 'adapters', 'cli', 'transport', 'controllers']
7
+ },
8
+ {
9
+ fromLayer: 'core',
10
+ disallowImportsFrom: ['infrastructure', 'infra', 'adapters', 'presentation', 'ui']
11
+ }
12
+ ];
13
+ function isSkippedDir(name) {
14
+ return name.startsWith('.') || name === 'node_modules' || name === 'lib';
15
+ }
16
+ function isEligibleSource(name) {
17
+ const isScript = name.endsWith('.ts') || name.endsWith('.js');
18
+ if (!isScript || name.endsWith('.d.ts'))
19
+ return false;
20
+ return !name.includes('.test.') && !name.includes('.spec.');
21
+ }
22
+ export function findSourceFiles(dir) {
23
+ if (!fs.existsSync(dir))
24
+ return [];
25
+ const results = [];
26
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
27
+ for (const entry of entries) {
28
+ if (isSkippedDir(entry.name))
29
+ continue;
30
+ const full = path.join(dir, entry.name);
31
+ if (entry.isDirectory()) {
32
+ results.push(...findSourceFiles(full));
33
+ }
34
+ else if (isEligibleSource(entry.name)) {
35
+ results.push(path.resolve(full));
36
+ }
37
+ }
38
+ return results.sort();
39
+ }
40
+ function resolveImportTarget(sourceFile, specifier) {
41
+ const dir = path.dirname(sourceFile);
42
+ const candidate = path.resolve(dir, specifier);
43
+ if (fs.existsSync(candidate))
44
+ return candidate;
45
+ if (specifier.endsWith('.js')) {
46
+ const tsCandidate = path.resolve(dir, specifier.slice(0, -3) + '.ts');
47
+ if (fs.existsSync(tsCandidate))
48
+ return tsCandidate;
49
+ }
50
+ return null;
51
+ }
52
+ export function extractLocalImports(filePath) {
53
+ if (!fs.existsSync(filePath))
54
+ return [];
55
+ const content = fs.readFileSync(filePath, 'utf-8');
56
+ const imports = [];
57
+ const regex = /(?:import|export)\s+(?:(?:[\s\S]*?from\s+)|)['"](\.[^'"]+)['"]|import\s*\(\s*['"](\.[^'"]+)['"]\s*\)/g;
58
+ for (const match of content.matchAll(regex)) {
59
+ const spec = match[1] ?? match[2];
60
+ if (spec) {
61
+ const resolved = resolveImportTarget(filePath, spec);
62
+ if (resolved && !imports.includes(resolved)) {
63
+ imports.push(resolved);
64
+ }
65
+ }
66
+ }
67
+ return imports.sort();
68
+ }
69
+ export function buildDependencyGraph(files) {
70
+ const graph = new Map();
71
+ for (const file of files) {
72
+ graph.set(file, extractLocalImports(file));
73
+ }
74
+ return graph;
75
+ }
76
+ export function detectDependencyCycles(graph) {
77
+ const cycles = [];
78
+ const visited = new Set();
79
+ const inStack = new Set();
80
+ const pathStack = [];
81
+ function dfs(node) {
82
+ visited.add(node);
83
+ inStack.add(node);
84
+ pathStack.push(node);
85
+ for (const neighbor of graph.get(node) ?? []) {
86
+ if (!visited.has(neighbor)) {
87
+ dfs(neighbor);
88
+ }
89
+ else if (inStack.has(neighbor)) {
90
+ const startIdx = pathStack.indexOf(neighbor);
91
+ if (startIdx !== -1) {
92
+ cycles.push([...pathStack.slice(startIdx), neighbor]);
93
+ }
94
+ }
95
+ }
96
+ inStack.delete(node);
97
+ pathStack.pop();
98
+ }
99
+ for (const node of graph.keys()) {
100
+ if (!visited.has(node))
101
+ dfs(node);
102
+ }
103
+ return cycles;
104
+ }
105
+ function hasLayerSegment(pathStr, segment) {
106
+ return new RegExp(`(^|[/\\\\])${segment}([/\\\\]|$)`, 'i').test(pathStr);
107
+ }
108
+ export function detectBoundaryViolations(graph, rules = DEFAULT_BOUNDARY_RULES) {
109
+ const violations = [];
110
+ for (const [file, imports] of graph.entries()) {
111
+ for (const rule of rules) {
112
+ if (hasLayerSegment(file, rule.fromLayer)) {
113
+ for (const imported of imports) {
114
+ for (const disallowed of rule.disallowImportsFrom) {
115
+ if (hasLayerSegment(imported, disallowed)) {
116
+ violations.push({
117
+ file,
118
+ importedFile: imported,
119
+ fromLayer: rule.fromLayer,
120
+ toLayer: disallowed
121
+ });
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ return violations;
129
+ }
130
+ /**
131
+ * Inspects a source tree for architectural boundary violations and circular dependency cycles.
132
+ *
133
+ * @param sourceDir - Directory containing source code (e.g. src/).
134
+ * @param rules - Architectural boundary rules.
135
+ * @returns Report summarizing cycle and boundary findings.
136
+ */
137
+ export function inspectBoundaries(sourceDir, rules = DEFAULT_BOUNDARY_RULES) {
138
+ const files = findSourceFiles(sourceDir);
139
+ const graph = buildDependencyGraph(files);
140
+ const cycles = detectDependencyCycles(graph);
141
+ const violations = detectBoundaryViolations(graph, rules);
142
+ return {
143
+ moduleCount: files.length,
144
+ cycles,
145
+ violations,
146
+ ok: cycles.length === 0 && violations.length === 0
147
+ };
148
+ }
149
+ export default {
150
+ DEFAULT_BOUNDARY_RULES,
151
+ findSourceFiles,
152
+ extractLocalImports,
153
+ buildDependencyGraph,
154
+ detectDependencyCycles,
155
+ detectBoundaryViolations,
156
+ inspectBoundaries
157
+ };
158
+ //# sourceMappingURL=boundaries.js.map
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cross-platform architectural boundary & cycle guard.
5
+ *
6
+ * Ships inside scaffolded projects so structural drift (circular imports and
7
+ * Clean/Hexagonal layer breaches) is machine-checked with zero third-party
8
+ * dependencies. The engine is vendored under `.agents/lib/` and byte-locked to
9
+ * `lib/boundaries.js`; this wrapper only resolves it and reports the verdict.
10
+ */
11
+ import fs from 'node:fs';
12
+ import path from 'node:path';
13
+ import process from 'node:process';
14
+ import { fileURLToPath, pathToFileURL } from 'node:url';
15
+
16
+ const selfDir = path.dirname(fileURLToPath(import.meta.url));
17
+
18
+ // Resolution order (first existing file wins):
19
+ // 1. AZCODR_BOUNDARY_ENGINE override (tests, embedders).
20
+ // 2. ../lib/boundaries.js — vendored engine inside `.agents/`
21
+ // (present in scaffolded projects; `.agents` is copied recursively).
22
+ // 3. ../../lib/boundaries.js — azcodr repo dev layout (fallback only).
23
+ const engineCandidates = [
24
+ process.env.AZCODR_BOUNDARY_ENGINE,
25
+ path.resolve(selfDir, '../lib/boundaries.js'),
26
+ path.resolve(selfDir, '../../lib/boundaries.js')
27
+ ].filter(Boolean);
28
+
29
+ async function getEngine() {
30
+ const tried = [];
31
+ for (const candidate of engineCandidates) {
32
+ if (!fs.existsSync(candidate)) {
33
+ tried.push(candidate);
34
+ continue;
35
+ }
36
+ try {
37
+ return await import(pathToFileURL(candidate).href);
38
+ } catch (err) {
39
+ tried.push(`${candidate} (unreadable: ${err.message})`);
40
+ }
41
+ }
42
+ // Fail CLOSED: a guard with no engine is a broken install, never a silent pass.
43
+ console.error(
44
+ '🚨 Boundary Guard misconfigured: engine module not found, refusing to fail open. Tried:\n' +
45
+ tried.map((t) => ` - ${t}`).join('\n')
46
+ );
47
+ process.exit(2);
48
+ }
49
+
50
+ function resolveTarget(positional) {
51
+ const explicit = positional[0];
52
+ if (explicit) return path.resolve(explicit);
53
+ const srcDir = path.resolve(process.cwd(), 'src');
54
+ return fs.existsSync(srcDir) ? srcDir : process.cwd();
55
+ }
56
+
57
+ function rel(p) {
58
+ return path.relative(process.cwd(), p) || '.';
59
+ }
60
+
61
+ function printReport(report) {
62
+ console.log('🔍 Inspecting Architectural Boundaries in: ' + rel(report.targetDir));
63
+ console.log('--------------------------------------------------------------');
64
+ if (report.ok) {
65
+ console.log(`✅ No cycles or boundary violations across ${report.moduleCount} module(s).`);
66
+ return;
67
+ }
68
+ for (const cycle of report.cycles) {
69
+ console.error(' - Circular Dependency: ' + cycle.map(rel).join(' -> '));
70
+ }
71
+ for (const v of report.violations) {
72
+ console.error(` - Layer Boundary Breach: ${rel(v.file)} imports ${rel(v.importedFile)} (${v.fromLayer} -> ${v.toLayer})`);
73
+ }
74
+ }
75
+
76
+ function emit(report, silent) {
77
+ if (!silent) printReport(report);
78
+ }
79
+
80
+ async function main() {
81
+ const args = process.argv.slice(2).filter((a) => a !== '--silent');
82
+ const silent = process.argv.includes('--silent');
83
+ const { inspectBoundaries } = await getEngine();
84
+ const target = resolveTarget(args);
85
+ const report = inspectBoundaries(target);
86
+ emit({ ...report, targetDir: target }, silent);
87
+ process.exit(report.ok ? 0 : 1);
88
+ }
89
+
90
+ main().catch((err) => {
91
+ console.error(`🚨 Boundary Guard crashed: ${err?.message || err}`);
92
+ process.exit(2);
93
+ });
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Pre-flight Desktop Distribution Doctor (Milestone 4).
5
+ * Prevents hybrid desktop build defects: missing custom-protocol, hollow CSS, dev-url embedding.
6
+ */
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import process from 'node:process';
10
+
11
+ function findCargoToml(targetDir) {
12
+ const candidates = [
13
+ path.join(targetDir, 'Cargo.toml'),
14
+ path.join(targetDir, 'src-tauri', 'Cargo.toml')
15
+ ];
16
+ for (const c of candidates) {
17
+ if (fs.existsSync(c)) return c;
18
+ }
19
+ return null;
20
+ }
21
+
22
+ function verifyCargoTauri(cargoPath) {
23
+ const content = fs.readFileSync(cargoPath, 'utf-8');
24
+ if (!content.includes('tauri')) return { ok: true, skipped: true };
25
+
26
+ const hasProtocol = content.includes('custom-protocol');
27
+ if (!hasProtocol) {
28
+ return {
29
+ ok: false,
30
+ reason: "Missing 'custom-protocol' feature in Cargo.toml dependencies. Tauri release binaries cannot embed frontend dist assets without it."
31
+ };
32
+ }
33
+ return { ok: true, message: 'Custom protocol enabled in Cargo.toml.' };
34
+ }
35
+
36
+ function collectCssFiles(dir) {
37
+ const files = [];
38
+ if (!fs.existsSync(dir)) return files;
39
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
40
+ for (const entry of entries) {
41
+ const full = path.join(dir, entry.name);
42
+ if (entry.isDirectory()) files.push(...collectCssFiles(full));
43
+ else if (entry.name.endsWith('.css')) files.push(full);
44
+ }
45
+ return files;
46
+ }
47
+
48
+ function verifyCssDensity(targetDir, minBytes = 5000) {
49
+ const searchDirs = [
50
+ path.join(targetDir, 'dist'),
51
+ path.join(targetDir, 'client', 'dist'),
52
+ path.join(targetDir, 'build')
53
+ ];
54
+ let foundAny = false;
55
+ let totalBytes = 0;
56
+
57
+ for (const dir of searchDirs) {
58
+ const cssList = collectCssFiles(dir);
59
+ if (cssList.length > 0) {
60
+ foundAny = true;
61
+ for (const f of cssList) totalBytes += fs.statSync(f).size;
62
+ }
63
+ }
64
+
65
+ if (!foundAny) return { ok: true, skipped: true };
66
+ if (totalBytes < minBytes) {
67
+ return {
68
+ ok: false,
69
+ reason: `Hollow CSS bundle detected (${totalBytes} bytes < ${minBytes} bytes). Check that postcss.config.js is configured for Tailwind.`
70
+ };
71
+ }
72
+ return { ok: true, message: `CSS bundle density verified (${totalBytes} bytes).` };
73
+ }
74
+
75
+ function main() {
76
+ const targetDir = path.resolve(process.argv[2] || process.cwd());
77
+ const cargoPath = findCargoToml(targetDir);
78
+ const cssResult = verifyCssDensity(targetDir);
79
+
80
+ if (!cargoPath && cssResult.skipped) {
81
+ console.log('ℹ️ No desktop artifacts found in: ' + targetDir);
82
+ process.exit(0);
83
+ }
84
+
85
+ let failed = false;
86
+ console.log('🩺 Desktop Distribution Doctor inspecting: ' + targetDir);
87
+
88
+ if (cargoPath) {
89
+ const cargoRes = verifyCargoTauri(cargoPath);
90
+ if (!cargoRes.ok) {
91
+ console.error(`🚨 ${cargoRes.reason}`);
92
+ failed = true;
93
+ } else if (cargoRes.message) {
94
+ console.log(`✅ ${cargoRes.message}`);
95
+ }
96
+ }
97
+
98
+ if (!cssResult.ok) {
99
+ console.error(`🚨 ${cssResult.reason}`);
100
+ failed = true;
101
+ } else if (cssResult.message) {
102
+ console.log(`✅ ${cssResult.message}`);
103
+ }
104
+
105
+ process.exit(failed ? 1 : 0);
106
+ }
107
+
108
+ main();
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cross-platform PreToolUse safety guard in pure Node.js.
5
+ * Blocks high-severity destructive shell commands (rm -rf, force push, drop db).
6
+ */
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import process from 'node:process';
10
+ import { fileURLToPath, pathToFileURL } from 'node:url';
11
+
12
+ const selfDir = path.dirname(fileURLToPath(import.meta.url));
13
+
14
+ const candidates = [
15
+ process.env.AZCODR_GUARD_ENGINE,
16
+ path.resolve(selfDir, '../lib/agent-guard-command.js'),
17
+ path.resolve(selfDir, '../../lib/agent-guard-command.js')
18
+ ].filter(Boolean);
19
+
20
+ async function getCommandModule() {
21
+ const tried = [];
22
+ for (const candidate of candidates) {
23
+ if (!fs.existsSync(candidate)) {
24
+ tried.push(candidate);
25
+ continue;
26
+ }
27
+ try {
28
+ return await import(pathToFileURL(candidate).href);
29
+ } catch (err) {
30
+ tried.push(`${candidate} (${err.message})`);
31
+ }
32
+ }
33
+ console.error(
34
+ '🚨 Safety Guard misconfigured: command engine not found. Tried:\n' +
35
+ tried.map((t) => ` - ${t}`).join('\n')
36
+ );
37
+ process.exit(2);
38
+ }
39
+
40
+ async function readStdin(timeoutMs = 1500) {
41
+ if (process.stdin.isTTY) return '';
42
+ return new Promise((resolve) => {
43
+ let acc = '';
44
+ const timer = setTimeout(() => resolve(acc), timeoutMs);
45
+ process.stdin.setEncoding('utf-8');
46
+ process.stdin.on('data', (chunk) => { acc += chunk; });
47
+ process.stdin.on('end', () => {
48
+ clearTimeout(timer);
49
+ resolve(acc);
50
+ });
51
+ process.stdin.on('error', () => {
52
+ clearTimeout(timer);
53
+ resolve(acc);
54
+ });
55
+ });
56
+ }
57
+
58
+ async function main() {
59
+ const argvInput = process.argv.slice(2).join(' ').trim();
60
+ const stdinInput = (await readStdin()).trim();
61
+ const rawInput = argvInput || stdinInput;
62
+
63
+ if (!rawInput) {
64
+ process.exit(0);
65
+ }
66
+
67
+ const { inspectCommand } = await getCommandModule();
68
+ const decision = inspectCommand(rawInput);
69
+
70
+ if (decision.blocked) {
71
+ console.error(`🚨 Safety Guard: ${decision.reason}`);
72
+ console.error(` command: ${decision.command || rawInput.slice(0, 300)}`);
73
+ process.exit(1);
74
+ }
75
+
76
+ process.exit(0);
77
+ }
78
+
79
+ main().catch((err) => {
80
+ console.error(`🚨 Safety Guard crashed: ${err?.message || err}`);
81
+ process.exit(2);
82
+ });
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cross-platform Boundary & Environment Smoke Test (Milestone 3).
5
+ * Verifies boundaries and diagnoses port occupancy before dev launch.
6
+ */
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import net from 'node:net';
10
+ import process from 'node:process';
11
+ import { spawnSync } from 'node:child_process';
12
+
13
+ function parseMonitoredPorts(argv) {
14
+ const customIndex = argv.indexOf('--ports');
15
+ if (customIndex !== -1 && argv[customIndex + 1]) {
16
+ return argv[customIndex + 1].split(',').map((p) => parseInt(p.trim(), 10)).filter(Boolean);
17
+ }
18
+ return [5173, 3000, 4000, 8080];
19
+ }
20
+
21
+ function checkPort(port, host = '127.0.0.1') {
22
+ return new Promise((resolve) => {
23
+ const server = net.createServer();
24
+ server.once('error', (err) => {
25
+ resolve({ port, available: false, error: err.code });
26
+ });
27
+ server.once('listening', () => {
28
+ server.close(() => resolve({ port, available: true }));
29
+ });
30
+ server.listen(port, host);
31
+ });
32
+ }
33
+
34
+ async function runPortDoctor(ports) {
35
+ console.log('🩺 Port doctor inspecting local dev ports...');
36
+ const results = await Promise.all(ports.map((p) => checkPort(p)));
37
+ for (const r of results) {
38
+ if (!r.available) {
39
+ console.log(`⚠️ Port ${r.port} is occupied (${r.error}). Check for background services to prevent collisions.`);
40
+ } else {
41
+ console.log(`✅ Port ${r.port} is free.`);
42
+ }
43
+ }
44
+ }
45
+
46
+ function runBoundaryGuard(targetDir) {
47
+ const guardPath = path.resolve(process.cwd(), '.agents', 'scripts', 'boundary_guard.js');
48
+ if (!fs.existsSync(guardPath)) {
49
+ console.log('ℹ️ Boundary guard script not found, skipping static graph check.');
50
+ return true;
51
+ }
52
+ console.log('🔍 Boundary smoke verification running on: ' + targetDir);
53
+ const res = spawnSync('node', [guardPath, targetDir], { stdio: 'inherit', shell: true });
54
+ return res.status === 0;
55
+ }
56
+
57
+ async function main() {
58
+ const positional = process.argv.slice(2).filter((a) => !a.startsWith('--'));
59
+ const targetDir = path.resolve(positional[0] || process.cwd());
60
+ const ports = parseMonitoredPorts(process.argv);
61
+
62
+ console.log('🚀 Running Full-Stack Smoke Verification...');
63
+ const boundaryPassed = runBoundaryGuard(targetDir);
64
+ await runPortDoctor(ports);
65
+
66
+ if (!boundaryPassed) {
67
+ console.error('🚨 Boundary verification failed!');
68
+ process.exit(1);
69
+ }
70
+
71
+ console.log('✅ Smoke verification passed cleanly!');
72
+ process.exit(0);
73
+ }
74
+
75
+ main().catch((err) => {
76
+ console.error(`🚨 Smoke verification crashed: ${err?.message || err}`);
77
+ process.exit(2);
78
+ });
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cross-platform Stop hook in pure Node.js.
5
+ * Blocks premature agent exit when verification gates (validate, coverage, test, lint) fail.
6
+ */
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import process from 'node:process';
10
+ import { spawnSync } from 'node:child_process';
11
+
12
+ function loadPackageJson() {
13
+ const pkgPath = path.resolve(process.cwd(), 'package.json');
14
+ if (!fs.existsSync(pkgPath)) return null;
15
+ try {
16
+ return JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ function runNpmScript(name, label) {
23
+ console.error(label);
24
+ const result = spawnSync('npm', ['run', name, '--silent'], {
25
+ stdio: 'inherit',
26
+ shell: true
27
+ });
28
+ return result.status === 0;
29
+ }
30
+
31
+ function verifyCoverageGate() {
32
+ const [major, minor] = process.versions.node.split('.').map(Number);
33
+ const eligible = (major > 22 || (major === 22 && minor >= 8));
34
+ if (!eligible) {
35
+ console.error(`⚠️ Skipping coverage gate: needs Node >= 22.8 (current: ${process.version})`);
36
+ return true;
37
+ }
38
+ return runNpmScript('test:coverage', '📈 Running coverage gate...');
39
+ }
40
+
41
+ function main() {
42
+ const pkg = loadPackageJson();
43
+ if (!pkg || !pkg.scripts) {
44
+ console.error('⚠️ Stop Verifier: no verifiable package.json found -- nothing checked.');
45
+ process.exit(0);
46
+ }
47
+
48
+ const scripts = pkg.scripts;
49
+ let ranAny = false;
50
+ let failed = false;
51
+
52
+ if (typeof scripts.validate === 'string') {
53
+ ranAny = true;
54
+ if (!runNpmScript('validate', '🔍 Running architecture validation...')) failed = true;
55
+ }
56
+ if (typeof scripts['test:coverage'] === 'string') {
57
+ ranAny = true;
58
+ if (!verifyCoverageGate()) failed = true;
59
+ }
60
+ if (typeof scripts.test === 'string') {
61
+ ranAny = true;
62
+ if (!runNpmScript('test', '🧪 Running test suite...')) failed = true;
63
+ }
64
+ if (typeof scripts.lint === 'string') {
65
+ ranAny = true;
66
+ if (!runNpmScript('lint', '🔎 Running lint...')) failed = true;
67
+ }
68
+
69
+ if (!ranAny) {
70
+ console.error('⚠️ Stop Verifier: no verifiable scripts found in package.json.');
71
+ }
72
+
73
+ process.exit(failed ? 1 : 0);
74
+ }
75
+
76
+ main();
@@ -567,7 +567,14 @@ if [[ ! -f "${SMOKE_TEST}" ]]; then
567
567
  # ==============================================================================
568
568
  set -euo pipefail
569
569
 
570
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
571
+
570
572
  echo "Running boundary smoke verification..."
573
+ if [[ -f "${ROOT}/.agents/scripts/boundary_guard.js" ]] && command -v node >/dev/null 2>&1; then
574
+ node "${ROOT}/.agents/scripts/boundary_guard.js" "${ROOT}/src"
575
+ else
576
+ echo "⚠️ Boundary guard skipped (node or guard script unavailable)."
577
+ fi
571
578
  # Extend with project-specific runtime health checks (e.g. ping health endpoint, CLI --help)
572
579
  echo "✅ Boundary smoke verification passed!"
573
580
  EOF
@@ -576,3 +583,9 @@ fi
576
583
 
577
584
  echo "--------------------------------------------------------------"
578
585
  echo "✅ Topology '${TOPOLOGY}' scaffolded with strict YAGNI (0 speculative folders)!"
586
+ echo ""
587
+ echo "🛑 MANDATORY HANDOVER GATE (ADR-008):"
588
+ echo " Bootstrapping is COMPLETE. Zero application domain entities have been created."
589
+ echo " DO NOT fabricate domain models, entities, or features during lets-build."
590
+ echo " Next: invoke 'product-analyst' & 'relentless-questioner' to conduct formal"
591
+ echo " stakeholder domain analysis, INVEST story decomposition, and Gherkin criteria."
package/.gitignore CHANGED
@@ -35,6 +35,7 @@ Thumbs.db
35
35
  .tmp/
36
36
  .tmp-scratch/
37
37
  opencode.json
38
+ .agents/.agents/
38
39
 
39
40
  # Case-insensitive filesystem parity (agents.md is generated/symlinked on Linux, native on macOS/Windows)
40
41
  agents.md
package/CONTRIBUTING.md CHANGED
@@ -60,9 +60,9 @@ Before submitting any code changes, all 5 quality gates must pass with zero erro
60
60
  npm run validate
61
61
  ```
62
62
  Validates root harness parity, progressive disclosure rules, skill formats, markdown links, ADR ledger consistency, and toolchain gate presence.
63
- 6. **Vendored Guard Sync:** after any change under `src/agent-guard*.ts` and `npm run build`, re-copy the four compiled engine files into `.agents/lib/` (byte-equality is enforced by `tests/agent-guard.test.ts`):
63
+ 6. **Vendored Engine Sync:** after any change under `src/agent-guard*.ts` or `src/boundaries.ts` and `npm run build`, re-copy the compiled engine files into `.agents/lib/` (byte-equality is enforced by `tests/agent-guard.test.ts` and `tests/boundary-guard.test.ts`):
64
64
  ```bash
65
- node -e "const fs=require('fs');for(const f of['agent-guard.js','agent-guard-command.js','agent-guard-file.js','agent-guard-tdd.js'])fs.copyFileSync('lib/'+f,'.agents/lib/'+f)"
65
+ node -e "const fs=require('fs');for(const f of['agent-guard.js','agent-guard-command.js','agent-guard-file.js','agent-guard-tdd.js','boundaries.js'])fs.copyFileSync('lib/'+f,'.agents/lib/'+f)"
66
66
  ```
67
67
 
68
68
  ---
package/README.md CHANGED
@@ -9,8 +9,6 @@
9
9
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
10
10
 
11
11
  > CI-enforced 100% gate (lines / branches / functions / statements) + 100% mutant kill on guards; the public report is the `coverage-report` artifact on every CI run.
12
- [![Dependencies](https://img.shields.io/badge/dependencies-0-success.svg)](https://www.npmjs.com/package/azcodr)
13
- [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
14
12
 
15
13
  > **Production-oriented architecture governance and topology-scoped scaffolding for AI-assisted development (early release).**
16
14
  > *AI agents move fast. Architecture drifts. Azcodr turns architectural intent into executable constraints your agent cannot skip.*
@@ -38,7 +36,7 @@
38
36
 
39
37
  ## ⚡ 60-Second Demo: See Drift Prevention in Action
40
38
 
41
- Azcodr turns architectural philosophy into machine-checked constraints your agent cannot skip.
39
+ Azcodr turns architectural philosophy into machine-checked constraints. In a fresh scaffold the runtime hooks ship **enabled by default**, and the boundary engine runs in CI, so drift is caught both while the agent edits and after it commits.
42
40
 
43
41
  ### 1. Standalone Architectural Check
44
42
  Run the validator on any repository without scaffolding:
@@ -67,7 +65,7 @@ When an AI coding agent attempts to dump new logic into a file already exceeding
67
65
  ```
68
66
 
69
67
  ### 3. Zero-Dependency Boundary & Cycle Enforcement
70
- Inspect dependency cycles and layer boundaries on demand without third-party linters:
68
+ Inspect dependency cycles and layer boundaries on demand without third-party linters. The same engine is vendored into every scaffolded project (`.agents/scripts/boundary_guard.js`) and runs in the generated CI:
71
69
  ```bash
72
70
  npx azcodr boundaries [directory]
73
71
  ```
@@ -80,17 +78,17 @@ npx azcodr boundaries [directory]
80
78
  Action Required: Invert dependencies via Ports or extract shared modules.
81
79
  ```
82
80
 
83
- ### 4. Empirical Benchmark Proof (3 Arms, 10 Sequential Tickets)
84
- In an automated empirical trial across 10 sequential tickets with 3 architectural traps ([`benchmark/RESULTS.md`](https://github.com/prosubodh/azcodr/blob/main/benchmark/RESULTS.md)):
81
+ ### 4. Detector Validation on Synthetic Fixtures (Not a Live-Agent Trial)
82
+ The evaluator's ability to detect the 3 trap classes is exercised against **hand-written fixtures**, not live agent output ([`benchmark/RESULTS.md`](https://github.com/prosubodh/azcodr/blob/main/benchmark/RESULTS.md)):
85
83
 
86
84
  | Metric | Arm A (Control) | Arm B (Hooks Only) | Arm C (Full Azcodr) |
87
85
  |---|:---:|:---:|:---:|
88
86
  | **Files >300 Lines** | 1 (365 lines in `auth.ts`) | **0** (Modularized) | **0** (Modularized) |
89
87
  | **Circular Dependency Cycles** | 1 (`billing <-> tenant`) | 1 (`billing <-> tenant`) | **0** (Decoupled Port) |
90
88
  | **Layer Boundary Breaches** | 1 (`domain -> infra`) | 1 (`domain -> infra`) | **0** (Hexagonal Port) |
91
- | **Overall Drift Reduction** | ❌ FAILED | ❌ FAILED | ✅ **100% DRIFT-FREE** |
89
+ | **Detected drift-free** | ❌ FAILED | ❌ FAILED | ✅ **0 detector violations** |
92
90
 
93
- Run the empirical benchmark yourself:
91
+ These fixtures are committed by hand to prove the detector fires; they are **not evidence** that an AI agent drifts. Real-agent results (tokens, completion, review minutes) are planned and not yet measured. Run the detector yourself:
94
92
  ```bash
95
93
  node benchmark/run-benchmark.js
96
94
  ```
@@ -128,6 +128,27 @@ names the test that locks it:
128
128
  `npm run lint` fails until the pinned tool lands instead of echoing
129
129
  success.
130
130
 
131
+ ## Addendum (2026-10-09): boundaries shipped, starter CI generated, hooks on
132
+
133
+ 6. **Boundary engine now ships in the scaffold.** `lib/boundaries.js` is
134
+ vendored into `.agents/lib/boundaries.js` (byte-locked by
135
+ `tests/boundary-guard.test.ts`, re-copied after every build per
136
+ `CONTRIBUTING.md`) and a vendored-first runner `.agents/scripts/boundary_guard.js`
137
+ exits 0/1 on a repo's cycle & layer verdict (exit 2 on a missing engine).
138
+ The starter `package.json` gains a `boundaries` script pointing at it.
139
+ 7. **Generated CI is now green out of the box.** azcodr's own dev workflows
140
+ (`ci.yml`, `publish.yml`) call scripts a fresh project does not have, so
141
+ shipping them verbatim made a scaffolded repo's CI fail on every push. The
142
+ scaffolder now replaces them with a starter `.github/workflows/ci.yml` that
143
+ only needs Node, the vendored boundary guard, and `scripts/validate-cli.js`.
144
+ Locked by `tests/scaffold-ci.test.ts`.
145
+ 8. **Hooks ship enabled.** `.agents/hooks.json` (+`.example`) now ships all four
146
+ hooks `enabled: true` (safety, architectural, post-tool-lint, stop-verifier),
147
+ amending ADR-020 which deliberately shipped them disabled. The trade-off is
148
+ recorded in the 2026-10-09 ADR: default-on means a harness that loads the
149
+ file blocks immediately, at the cost that lint/stop hooks can interrupt
150
+ worthless-but-harmless sessions in a bare scaffold.
151
+
131
152
  ## Reproduce
132
153
 
133
154
  ```bash
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC9F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAW3C,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAmCD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,IAAI,CAW3F;AA4FD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,MAAyB,EACtC,OAAO,GAAE,mBAAwB,GAChC,MAAM,EAAE,CAcV;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,cAAc,CActE;AAED,OAAO,EACL,aAAa,EAAE,sBAAsB,EAAE,yBAAyB,EAChE,qBAAqB,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAC3D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB,EAC5D,CAAC;AAEF,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AAE5F,wBAKE"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC9F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGhD,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAW3C,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAmCD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,IAAI,CAW3F;AA8FD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,MAAyB,EACtC,OAAO,GAAE,mBAAwB,GAChC,MAAM,EAAE,CAeV;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,cAAc,CActE;AAED,OAAO,EACL,aAAa,EAAE,sBAAsB,EAAE,yBAAyB,EAChE,qBAAqB,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAC3D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB,EAC5D,CAAC;AAEF,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AAE5F,wBAKE"}
package/lib/scaffold.js CHANGED
@@ -7,6 +7,7 @@ import { assertInside, isProtectedTarget, getTemplateDir } from './guards.js';
7
7
  import { ensureSymlink, ensureSymlinkOrPointer, isSameCaseInsensitiveFile } from './links.js';
8
8
  import { makeScriptsExecutable } from './permissions.js';
9
9
  import { isInsideGitWorkTree, initGit } from './repo.js';
10
+ import { writeStarterCi } from './starter-ci.js';
10
11
  export { getTemplateDir };
11
12
  /**
12
13
  * Canonical list of template files and directories copied into a new workspace.
@@ -131,6 +132,8 @@ function starterPackageJson(resolvedTarget) {
131
132
  test: 'node --test',
132
133
  'test:coverage': 'jest --coverage',
133
134
  lint: 'echo "No linter configured yet. Run /lets-build to configure toolchain."',
135
+ boundaries: 'node .agents/scripts/boundary_guard.js',
136
+ smoke: 'node .agents/scripts/smoke_test.js',
134
137
  validate: 'node scripts/validate-cli.js'
135
138
  }
136
139
  };
@@ -173,6 +176,7 @@ export function copyTemplate(targetDir, templateDir = getTemplateDir(), options
173
176
  actions.push(...ensureHarnessParity(resolvedTarget, dryRun));
174
177
  actions.push(...ensureCopilotParity(resolvedTarget, dryRun));
175
178
  actions.push(...ensureStarterPackageJson(resolvedTarget, dryRun));
179
+ actions.push(...writeStarterCi(resolvedTarget, dryRun));
176
180
  const inspectDir = dryRun ? resolvedTemplate : resolvedTarget;
177
181
  actions.push(...chmodTemplateScripts(inspectDir, dryRun));
178
182
  return actions;
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * azcodr's own release/CI workflows. They target this repository's scripts
3
+ * (build, mutation, benchmark) and must never run inside a scaffolded project;
4
+ * `writeStarterCi` removes them from the target and installs a starter CI.
5
+ */
6
+ export declare const AZCODR_DEV_WORKFLOWS: readonly string[];
7
+ /**
8
+ * Starter governance CI written into every scaffolded project. It depends only
9
+ * on Node + the vendored guard engine, so it is green out of the box (unlike
10
+ * azcodr's own dev workflows, which call scripts a fresh project does not have).
11
+ */
12
+ export declare const STARTER_CI = "name: ci\n\non:\n push:\n branches: [main]\n pull_request:\n\npermissions:\n contents: read\n\njobs:\n governance:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: 22.x\n - name: Architectural boundary & cycle check\n run: node .agents/scripts/boundary_guard.js\n - name: Governance validation\n run: node scripts/validate-cli.js\n";
13
+ /**
14
+ * Writes the starter governance CI into a scaffold target and removes azcodr's
15
+ * own dev workflows from it, so a generated project's CI is green out of the
16
+ * box instead of calling scripts a fresh project does not have.
17
+ *
18
+ * @param resolvedTarget - Absolute path to the scaffold target directory.
19
+ * @param dryRun - Record the action without touching the filesystem.
20
+ * @returns Recorded scaffolding action descriptions.
21
+ */
22
+ export declare function writeStarterCi(resolvedTarget: string, dryRun: boolean): string[];
23
+ declare const _default: {
24
+ STARTER_CI: string;
25
+ AZCODR_DEV_WORKFLOWS: readonly string[];
26
+ writeStarterCi: typeof writeStarterCi;
27
+ };
28
+ export default _default;
29
+ //# sourceMappingURL=starter-ci.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"starter-ci.d.ts","sourceRoot":"","sources":["../src/starter-ci.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAA8B,CAAC;AAEjF;;;;GAIG;AACH,eAAO,MAAM,UAAU,sdAsBtB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,CAUhF;;;;;;AAED,wBAAoE"}
@@ -0,0 +1,59 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * azcodr's own release/CI workflows. They target this repository's scripts
5
+ * (build, mutation, benchmark) and must never run inside a scaffolded project;
6
+ * `writeStarterCi` removes them from the target and installs a starter CI.
7
+ */
8
+ export const AZCODR_DEV_WORKFLOWS = ['ci.yml', 'publish.yml'];
9
+ /**
10
+ * Starter governance CI written into every scaffolded project. It depends only
11
+ * on Node + the vendored guard engine, so it is green out of the box (unlike
12
+ * azcodr's own dev workflows, which call scripts a fresh project does not have).
13
+ */
14
+ export const STARTER_CI = `name: ci
15
+
16
+ on:
17
+ push:
18
+ branches: [main]
19
+ pull_request:
20
+
21
+ permissions:
22
+ contents: read
23
+
24
+ jobs:
25
+ governance:
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: actions/setup-node@v4
30
+ with:
31
+ node-version: 22.x
32
+ - name: Architectural boundary & cycle check
33
+ run: node .agents/scripts/boundary_guard.js
34
+ - name: Governance validation
35
+ run: node scripts/validate-cli.js
36
+ `;
37
+ /**
38
+ * Writes the starter governance CI into a scaffold target and removes azcodr's
39
+ * own dev workflows from it, so a generated project's CI is green out of the
40
+ * box instead of calling scripts a fresh project does not have.
41
+ *
42
+ * @param resolvedTarget - Absolute path to the scaffold target directory.
43
+ * @param dryRun - Record the action without touching the filesystem.
44
+ * @returns Recorded scaffolding action descriptions.
45
+ */
46
+ export function writeStarterCi(resolvedTarget, dryRun) {
47
+ const actions = ['generate: .github/workflows/ci.yml (starter governance CI)'];
48
+ if (dryRun)
49
+ return actions;
50
+ const workflowsDir = path.join(resolvedTarget, '.github', 'workflows');
51
+ fs.mkdirSync(workflowsDir, { recursive: true });
52
+ for (const name of AZCODR_DEV_WORKFLOWS) {
53
+ fs.rmSync(path.join(workflowsDir, name), { force: true });
54
+ }
55
+ fs.writeFileSync(path.join(workflowsDir, 'ci.yml'), STARTER_CI, 'utf-8');
56
+ return actions;
57
+ }
58
+ export default { STARTER_CI, AZCODR_DEV_WORKFLOWS, writeStarterCi };
59
+ //# sourceMappingURL=starter-ci.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"starter-ci.js","sourceRoot":"","sources":["../src/starter-ci.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;AAEjF;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBzB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,cAAsB,EAAE,MAAe;IACpE,MAAM,OAAO,GAAG,CAAC,4DAA4D,CAAC,CAAC;IAC/E,IAAI,MAAM;QAAE,OAAO,OAAO,CAAC;IAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IACvE,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,oBAAoB,EAAE,CAAC;QACxC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IACzE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,eAAe,EAAE,UAAU,EAAE,oBAAoB,EAAE,cAAc,EAAE,CAAC"}
package/memory.md CHANGED
@@ -37,6 +37,8 @@
37
37
  | [ADR-018](./memory.md#adr-018-first-class-architectural-boundary-and-cycle-inspection-cli-subcommand) | First-Class Architectural Boundary and Cycle Inspection CLI Subcommand | 2026-10-08 | ACCEPTED | [`clean_code.md`](./docs/rules/clean_code.md) |
38
38
  | [ADR-019](./memory.md#adr-019-honest-claims-100-percent-all-metrics-gate-and-benchmark-limits-on-the-record) | Honest claims, 100% all-metrics gate, and benchmark limits on the record | 2026-10-08 | ACCEPTED | [`test_driven_development.md`](./docs/rules/test_driven_development.md) |
39
39
  | [ADR-020](./memory.md#adr-020-generated-projects-get-deterministic-enforcement) | Generated projects get deterministic enforcement | 2026-10-08 | ACCEPTED | [`clean_code.md`](./docs/rules/clean_code.md) |
40
+ | [ADR-021](./memory.md#adr-021-default-on-guards-boundaries-and-starter-ci-ship-in-the-scaffold) | Default-on guards; boundaries & starter CI ship in the scaffold | 2026-10-09 | ACCEPTED | [`clean_code.md`](./docs/rules/clean_code.md) |
41
+ | [ADR-022](./memory.md#adr-022-cross-platform-hook-resolution-scaffolding-handover-gate-desktop-doctor--smoke-standard) | Cross-platform hook resolution, scaffolding handover gate, desktop doctor & smoke standard | 2026-10-10 | ACCEPTED | [`agentic_configuration.md`](./docs/rules/agentic_configuration.md) |
40
42
 
41
43
  ---
42
44
 
@@ -133,6 +135,20 @@
133
135
  - **Consequences:** ✅ The catastrophic `--force` paths are closed, locked by `tests/protected-target.test.js` (14 tests, including symlink-alias and fault-injection cases for the two defensive catches). ✅ Only the exact protected directories are blocked: `~/my-project` and any normal subdirectory still scaffold. ✅ New stable error code follows the existing contract (branch on `code`, never message). ⚠️ A user who genuinely wants a project AT `~` must pick a subdirectory; that friction is the point.
134
136
  - **Enforced In:** `lib/scaffold.js` (`isProtectedTarget`, `validateTarget`), `bin/azcodr.js` (fail-fast), `lib/index.d.ts`, `tests/protected-target.test.js`, `tests/error-codes.test.js`, `README.md` (security notes)
135
137
 
138
+ #### ADR-022: Cross-Platform Hook Resolution, Scaffolding Handover Gate, Desktop Doctor & Smoke Standard
139
+ - **Date:** 2026-10-10 | **Status:** ACCEPTED
140
+ - **Context:** Retrospectives across `thebrowser` and `sthanori` revealed recurring operational and architectural friction: (1) Running on Windows hosts under Antigravity/cmd.exe, hook commands specified as POSIX paths (`./.agents/...`) failed with `'.' is not recognized as an internal or external command`, and Antigravity sets CWD to `.agents/`, breaking relative paths. (2) During scaffolding, eager agents fabricated domain entities without user discovery, violating the bootstrapping boundary (ISSUE-005). (3) Hybrid desktop builds suffered silent defects (missing `custom-protocol`, hollow <5KB CSS bundles due to missing PostCSS, and background WebView2 process lock crashes `0x800700AA`). (4) In-memory unit test suites gave false confidence while live reverse proxies, TCP sockets, and Content-Types failed (ISSUE-004), alongside local dev port collisions (port 5173 RPMS collision in `thebrowser`).
141
+ - **Decision:** (1) Standardize all lifecycle hook commands in `.agents/hooks.json` (+`.example`) on cross-platform `node` runtime invocations (`node .agents/scripts/...`), supported by forwarders resolving seamlessly whether CWD is workspace root or `.agents/`. (2) Ship pure Node.js implementations for `safety_guard.js` and `verify_completion.js`, eliminating bash dependencies on Windows. (3) Enforce the mandatory Phase 5 Handover Gate in `bootstrap_workspace.sh` and `/lets-build`, halting code generation after technical plumbing and `/healthz`. (4) Author `.agents/scripts/desktop_doctor.js` (verifying `Cargo.toml` Tauri `custom-protocol` and CSS bundle density ≥ 5KB) and `.agents/scripts/smoke_test.js` (boundary graph check and port collision doctoring). Wire `smoke` into starter `package.json`.
142
+ - **Consequences:** ✅ Zero Windows cmd shell syntax errors during PreToolUse/PostToolUse/Stop hook execution. ✅ Full cross-platform test and verification parity across Windows, macOS, and Linux. ✅ Deterministic prevention of premature domain scaffolding, hybrid desktop build defects, and silent port collisions. ✅ 100.00% test coverage and Clean Code fitness functions preserved across all 49 test suites and 560 tests.
143
+ - **Enforced In:** `.agents/hooks.json`, `.agents/hooks.json.example`, `.agents/scripts/safety_guard.js`, `.agents/scripts/verify_completion.js`, `.agents/scripts/desktop_doctor.js`, `.agents/scripts/smoke_test.js`, `.agents/skills/lets-build/scripts/bootstrap_workspace.sh`, `src/scaffold.ts`, `tests/hooks-default.test.ts`, `tests/desktop-doctor.test.ts`, `tests/smoke-test.test.ts`, `tests/bootstrap-toolchain.test.ts`
144
+
145
+ #### ADR-021: Default-On Guards; Boundaries & Starter CI Ship in the Scaffold
146
+ - **Date:** 2026-10-09 | **Status:** ACCEPTED
147
+ - **Context:** The 2026-10-08 consolidated external review left three open severity items: (1) the benchmark read as a live-agent trial while its fixtures were synthetic ("100% drift elimination" over fixtures no agent produced); (2) "your agent cannot skip" was false because every shipped hook in `.agents/hooks.json` was `enabled: false`; (3) the boundary engine — the component that stopped the cycle and the layer breach in the results — was not wired into generated projects or their CI. A further finding from the review's follow-up audit: scaffolded projects inherited azcodr's own `ci.yml`/`publish.yml`, which call scripts (build, mutation, benchmark) a fresh project does not have, so generated CI failed on every push out of the box.
148
+ - **Decision:** (1) Retitle the benchmark as detector validation on synthetic fixtures, pre-register the real-agent trial in `benchmark/REAL-AGENT-RUNBOOK.md` with a result template, and stop narrating "the agent" in `benchmark/RESULTS.md`. (2) Ship all four hooks with `enabled: true` in `.agents/hooks.json` (+`.example`), amending ADR-020 — default-off contradicts the tagline; the cost that lint/stop hooks can interrupt a bare scaffold is accepted and recorded. (3) Vendor `lib/boundaries.js` into `.agents/lib/boundaries.js` (byte-locked by test), add a vendored-first runner `.agents/scripts/boundary_guard.js` (exit 0/1 verdict, exit 2 on missing engine), point the starter `package.json` `boundaries` script at it, and make `bootstrap_workspace.sh`'s smoke test execute it. (4) The scaffolder writes a starter `.github/workflows/ci.yml` (boundary guard + `validate-cli.js`; Node only) and removes azcodr's dev-only workflows from the target, so a scaffolded repo's CI is green out of the box. (5) Remove the personal author email from `package.json` (role-scoped `+security`/`+conduct` addresses stay: they are functional routing, not identity).
149
+ - **Consequences:** ✅ Enforcement is on by default where the harness loads the file; boundary checks run in generated CI. ✅ Generated CI no longer fails because of azcodr's own scripts. ✅ The benchmark headline no longer overclaims. ⚠️ Default-on hooks can interrupt a harnessed session in a bare scaffold; ⚠️ live-agent drift-reduction evidence is still unmeasured; ⚠️ azcodr's dev workflows no longer propagate into user projects.
150
+ - **Enforced In:** `.agents/hooks.json`, `.agents/hooks.json.example`, `.agents/scripts/boundary_guard.js`, `.agents/lib/boundaries.js`, `src/scaffold.ts`, `src/starter-ci.ts`, `.agents/skills/lets-build/scripts/bootstrap_workspace.sh`, `benchmark/RESULTS.md`, `benchmark/REAL-AGENT-RUNBOOK.md`, `package.json`, `tests/boundary-guard.test.ts`, `tests/scaffold-ci.test.ts`, `tests/hooks-default.test.ts`
151
+
136
152
  #### ADR-009: memory.md Is Append-Only; the Scaffolder Never Rewrites the Ledger
137
153
  - **Date:** 2026-10-07 | **Status:** ACCEPTED
138
154
  - **Context:** `.agents/skills/lets-build/scripts/bootstrap_workspace.sh` overwrote `memory.md` with a heredoc whenever the file contained any ADR heading that was not the untouched "No decisions recorded yet" placeholder. Reproduced directly: a project whose ADR read "we will never drop SQLite support" was silently replaced with an empty template after one `/lets-build` run — no error, no backup. It also fired on *high* numbering, so a mature project's ledger was equally destroyed. The intent was to strip template ADRs leaked from this repo; the trigger was the presence of real ones. ADRs are immutable history by rule (`docs/rules/agentic_configuration.md`), so a scaffolder rewriting them was a category error. Two further determinism defects in the same script: Topologies D (Canvas Game) and F (Systems Library) were documented in `SKILL.md` but had no `case` arm, so they fell through to a generic tree and **exited 0** — a wrong-but-successful scaffold the agent would report as done; and the `$LANGUAGE` argument was echoed and never used, so every language produced an identical tree while the skill claimed determinism.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "azcodr",
3
- "version": "2.5.1",
4
- "description": "Architecture governance toolkit with topology-scoped scaffolding for AI-assisted development (early release)",
3
+ "version": "2.7.0",
4
+ "description": "Architecture governance toolkit, with an optional starter (early release)",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "azcodr": "bin/azcodr.js"
@@ -44,7 +44,7 @@
44
44
  "agents",
45
45
  "npx"
46
46
  ],
47
- "author": "Subodh Khanal <prosubodh+git@gmail.com>",
47
+ "author": "Subodh Khanal",
48
48
  "license": "MIT",
49
49
  "repository": {
50
50
  "type": "git",
package/src/scaffold.ts CHANGED
@@ -10,6 +10,7 @@ import type { EnsureSymlinkOptions } from './links.js';
10
10
  import { makeScriptsExecutable } from './permissions.js';
11
11
  import { isInsideGitWorkTree, initGit } from './repo.js';
12
12
  import type { InitGitOptions } from './repo.js';
13
+ import { writeStarterCi } from './starter-ci.js';
13
14
 
14
15
  export { getTemplateDir };
15
16
 
@@ -189,6 +190,8 @@ function starterPackageJson(resolvedTarget: string): Record<string, unknown> {
189
190
  test: 'node --test',
190
191
  'test:coverage': 'jest --coverage',
191
192
  lint: 'echo "No linter configured yet. Run /lets-build to configure toolchain."',
193
+ boundaries: 'node .agents/scripts/boundary_guard.js',
194
+ smoke: 'node .agents/scripts/smoke_test.js',
192
195
  validate: 'node scripts/validate-cli.js'
193
196
  }
194
197
  };
@@ -236,6 +239,7 @@ export function copyTemplate(
236
239
  actions.push(...ensureHarnessParity(resolvedTarget, dryRun));
237
240
  actions.push(...ensureCopilotParity(resolvedTarget, dryRun));
238
241
  actions.push(...ensureStarterPackageJson(resolvedTarget, dryRun));
242
+ actions.push(...writeStarterCi(resolvedTarget, dryRun));
239
243
  const inspectDir = dryRun ? resolvedTemplate : resolvedTarget;
240
244
  actions.push(...chmodTemplateScripts(inspectDir, dryRun));
241
245
  return actions;
@@ -0,0 +1,61 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ /**
5
+ * azcodr's own release/CI workflows. They target this repository's scripts
6
+ * (build, mutation, benchmark) and must never run inside a scaffolded project;
7
+ * `writeStarterCi` removes them from the target and installs a starter CI.
8
+ */
9
+ export const AZCODR_DEV_WORKFLOWS: readonly string[] = ['ci.yml', 'publish.yml'];
10
+
11
+ /**
12
+ * Starter governance CI written into every scaffolded project. It depends only
13
+ * on Node + the vendored guard engine, so it is green out of the box (unlike
14
+ * azcodr's own dev workflows, which call scripts a fresh project does not have).
15
+ */
16
+ export const STARTER_CI = `name: ci
17
+
18
+ on:
19
+ push:
20
+ branches: [main]
21
+ pull_request:
22
+
23
+ permissions:
24
+ contents: read
25
+
26
+ jobs:
27
+ governance:
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: actions/setup-node@v4
32
+ with:
33
+ node-version: 22.x
34
+ - name: Architectural boundary & cycle check
35
+ run: node .agents/scripts/boundary_guard.js
36
+ - name: Governance validation
37
+ run: node scripts/validate-cli.js
38
+ `;
39
+
40
+ /**
41
+ * Writes the starter governance CI into a scaffold target and removes azcodr's
42
+ * own dev workflows from it, so a generated project's CI is green out of the
43
+ * box instead of calling scripts a fresh project does not have.
44
+ *
45
+ * @param resolvedTarget - Absolute path to the scaffold target directory.
46
+ * @param dryRun - Record the action without touching the filesystem.
47
+ * @returns Recorded scaffolding action descriptions.
48
+ */
49
+ export function writeStarterCi(resolvedTarget: string, dryRun: boolean): string[] {
50
+ const actions = ['generate: .github/workflows/ci.yml (starter governance CI)'];
51
+ if (dryRun) return actions;
52
+ const workflowsDir = path.join(resolvedTarget, '.github', 'workflows');
53
+ fs.mkdirSync(workflowsDir, { recursive: true });
54
+ for (const name of AZCODR_DEV_WORKFLOWS) {
55
+ fs.rmSync(path.join(workflowsDir, name), { force: true });
56
+ }
57
+ fs.writeFileSync(path.join(workflowsDir, 'ci.yml'), STARTER_CI, 'utf-8');
58
+ return actions;
59
+ }
60
+
61
+ export default { STARTER_CI, AZCODR_DEV_WORKFLOWS, writeStarterCi };