azcodr 1.0.0 → 1.1.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/lib/index.d.ts ADDED
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Enterprise Multi-Tenant Architecture & Agentic Engineering Starter Template
3
+ * Programmatic API Definitions
4
+ */
5
+
6
+ export interface ScaffoldOptions {
7
+ /** Target directory path where template should be scaffolded (default: process.cwd()) */
8
+ targetDir?: string;
9
+ /** Force overwrite if target directory is non-empty (default: false) */
10
+ force?: boolean;
11
+ /** Skip git repository initialization (default: false) */
12
+ noGit?: boolean;
13
+ /** Custom template root directory (default: azcodr root) */
14
+ templateDir?: string;
15
+ /** Simulate scaffolding without writing files or running git (default: false) */
16
+ dryRun?: boolean;
17
+ /** Suppress console output messages (default: false) */
18
+ silent?: boolean;
19
+ }
20
+
21
+ export interface ScaffoldResult {
22
+ /** Whether the scaffolding succeeded */
23
+ success: boolean;
24
+ /** Absolute resolved path of the target directory */
25
+ targetDir: string;
26
+ /** Whether git init was successfully executed */
27
+ gitInitialized: boolean;
28
+ /** Whether execution ran in dry-run simulation mode */
29
+ dryRun: boolean;
30
+ /** List of files, directories, and symlinks created or simulated */
31
+ actions: string[];
32
+ }
33
+
34
+ export interface LogChangeOptions {
35
+ /** Short title describing the architectural change */
36
+ title: string;
37
+ /** Category of change (Architecture | Rule | Skill | Infrastructure | CLI | Knowledge Hub) */
38
+ category?: string;
39
+ /** Target file(s) affected by the change */
40
+ targetFiles?: string;
41
+ /** Architectural rationale for upstream template incorporation */
42
+ rationale?: string;
43
+ /** Detailed description of the change */
44
+ description?: string;
45
+ /** Working directory containing changes.md (default: process.cwd()) */
46
+ targetDir?: string;
47
+ }
48
+
49
+ export interface LogChangeResult {
50
+ /** Whether the log entry was successfully recorded */
51
+ success: boolean;
52
+ /** Absolute path to changes.md */
53
+ filePath: string;
54
+ /** Markdown entry text that was appended */
55
+ entry: string;
56
+ }
57
+
58
+ export interface ValidateTargetOptions {
59
+ /** Custom template root directory */
60
+ templateDir?: string;
61
+ /** Force allow non-empty directory */
62
+ force?: boolean;
63
+ }
64
+
65
+ export interface InitGitOptions {
66
+ /** If true, skips git initialization */
67
+ noGit?: boolean;
68
+ /** If true, simulates git initialization without executing */
69
+ dryRun?: boolean;
70
+ }
71
+
72
+ export interface CopyTemplateOptions {
73
+ /** If true, simulates copy without writing to disk */
74
+ dryRun?: boolean;
75
+ }
76
+
77
+ /**
78
+ * High-level orchestration function to scaffold the azcodr workspace into targetDir.
79
+ */
80
+ export function scaffold(options?: ScaffoldOptions): ScaffoldResult;
81
+
82
+ /**
83
+ * Appends a standardized upstream change entry to changes.md.
84
+ */
85
+ export function logChange(options: LogChangeOptions): LogChangeResult;
86
+
87
+ /**
88
+ * Validates the target directory to ensure it is suitable for scaffolding.
89
+ */
90
+ export function validateTarget(targetDir: string, options?: ValidateTargetOptions): void;
91
+
92
+ /**
93
+ * Copies template items into target directory and sets up symlinks and permissions.
94
+ */
95
+ export function copyTemplate(
96
+ targetDir: string,
97
+ templateDir?: string,
98
+ options?: CopyTemplateOptions
99
+ ): string[];
100
+
101
+ /**
102
+ * Safely creates or updates a symbolic link, falling back to a file copy if symlinks are unsupported.
103
+ */
104
+ export function ensureSymlink(
105
+ targetDir: string,
106
+ linkName: string,
107
+ targetFileName: string,
108
+ dryRun?: boolean
109
+ ): boolean;
110
+
111
+ /**
112
+ * Detects whether linkName and targetFileName refer to the same entry on a case-insensitive filesystem.
113
+ */
114
+ export function isSameCaseInsensitiveFile(
115
+ targetDir: string,
116
+ linkName: string,
117
+ targetFileName: string
118
+ ): boolean;
119
+
120
+ /**
121
+ * Ensures all bash scripts in skill directories have executable permissions (0o755).
122
+ */
123
+ export function makeScriptsExecutable(targetDir: string, dryRun?: boolean): string[];
124
+
125
+ /**
126
+ * Initializes a git repository in the target directory if not already inside one.
127
+ */
128
+ export function initGit(targetDir: string, options?: InitGitOptions): boolean;
129
+
130
+ /**
131
+ * Returns the root path to the azcodr template files.
132
+ */
133
+ export function getTemplateDir(): string;
134
+
135
+ /**
136
+ * Array of essential template files and directories copied during scaffolding.
137
+ */
138
+ export const TEMPLATE_ITEMS: readonly string[];
139
+
140
+ declare const defaultExport: {
141
+ scaffold: typeof scaffold;
142
+ logChange: typeof logChange;
143
+ validateTarget: typeof validateTarget;
144
+ copyTemplate: typeof copyTemplate;
145
+ ensureSymlink: typeof ensureSymlink;
146
+ isSameCaseInsensitiveFile: typeof isSameCaseInsensitiveFile;
147
+ makeScriptsExecutable: typeof makeScriptsExecutable;
148
+ initGit: typeof initGit;
149
+ getTemplateDir: typeof getTemplateDir;
150
+ TEMPLATE_ITEMS: typeof TEMPLATE_ITEMS;
151
+ };
152
+
153
+ export default defaultExport;
package/lib/scaffold.js CHANGED
@@ -2,15 +2,17 @@
2
2
 
3
3
  const fs = require('node:fs');
4
4
  const path = require('node:path');
5
- const { execSync } = require('node:child_process');
5
+ const cp = require('node:child_process');
6
6
 
7
7
  const TEMPLATE_ITEMS = [
8
8
  'AGENTS.md',
9
9
  'memory.md',
10
+ 'changes.md',
10
11
  'README.md',
11
12
  'docs',
12
13
  '.agents',
13
- '.gitignore'
14
+ '.gitignore',
15
+ '.editorconfig'
14
16
  ];
15
17
 
16
18
  /**
@@ -24,7 +26,7 @@ function getTemplateDir() {
24
26
  * Validates the target directory to ensure it is suitable for scaffolding.
25
27
  */
26
28
  function validateTarget(targetDir, options = {}) {
27
- const { templateDir = getTemplateDir(), force = false } = options;
29
+ const { templateDir = getTemplateDir(), force = false, dryRun = false } = options;
28
30
  const resolvedTarget = path.resolve(targetDir);
29
31
  const resolvedTemplate = path.resolve(templateDir);
30
32
 
@@ -33,7 +35,9 @@ function validateTarget(targetDir, options = {}) {
33
35
  }
34
36
 
35
37
  if (!fs.existsSync(resolvedTarget)) {
36
- fs.mkdirSync(resolvedTarget, { recursive: true });
38
+ if (!dryRun) {
39
+ fs.mkdirSync(resolvedTarget, { recursive: true });
40
+ }
37
41
  return;
38
42
  }
39
43
 
@@ -46,10 +50,35 @@ function validateTarget(targetDir, options = {}) {
46
50
  }
47
51
  }
48
52
 
53
+ /**
54
+ * Detects whether linkName and targetFileName refer to the same entry on a case-insensitive filesystem.
55
+ */
56
+ function isSameCaseInsensitiveFile(targetDir, linkName, targetFileName) {
57
+ if (linkName.toLowerCase() !== targetFileName.toLowerCase()) {
58
+ return false;
59
+ }
60
+ const targetPath = path.join(targetDir, targetFileName);
61
+ const linkPath = path.join(targetDir, linkName);
62
+ try {
63
+ if (fs.existsSync(targetPath) && fs.existsSync(linkPath)) {
64
+ return !fs.lstatSync(linkPath).isSymbolicLink();
65
+ }
66
+ } catch {
67
+ return false;
68
+ }
69
+ return false;
70
+ }
71
+
49
72
  /**
50
73
  * Safely creates or updates a symbolic link, falling back to a file copy if symlinks are unsupported.
51
74
  */
52
- function ensureSymlink(targetDir, linkName, targetFileName) {
75
+ function ensureSymlink(targetDir, linkName, targetFileName, dryRun = false) {
76
+ if (dryRun) return true;
77
+
78
+ if (isSameCaseInsensitiveFile(targetDir, linkName, targetFileName)) {
79
+ return true;
80
+ }
81
+
53
82
  const linkPath = path.join(targetDir, linkName);
54
83
  try {
55
84
  const stat = fs.lstatSync(linkPath);
@@ -62,21 +91,24 @@ function ensureSymlink(targetDir, linkName, targetFileName) {
62
91
 
63
92
  try {
64
93
  fs.symlinkSync(targetFileName, linkPath);
94
+ return true;
65
95
  } catch {
66
96
  // Fallback if environment (e.g., certain Windows configs) prevents symlink creation
67
97
  const sourceFile = path.join(targetDir, targetFileName);
68
98
  if (fs.existsSync(sourceFile)) {
69
99
  fs.copyFileSync(sourceFile, linkPath);
70
100
  }
101
+ return true;
71
102
  }
72
103
  }
73
104
 
74
105
  /**
75
106
  * Ensures all bash scripts in skill directories have executable permissions (0o755).
76
107
  */
77
- function makeScriptsExecutable(targetDir) {
108
+ function makeScriptsExecutable(targetDir, dryRun = false) {
109
+ const modified = [];
78
110
  const skillsDir = path.join(targetDir, '.agents', 'skills');
79
- if (!fs.existsSync(skillsDir)) return;
111
+ if (!fs.existsSync(skillsDir)) return modified;
80
112
 
81
113
  const skills = fs.readdirSync(skillsDir);
82
114
  for (const skill of skills) {
@@ -86,25 +118,31 @@ function makeScriptsExecutable(targetDir) {
86
118
  for (const file of files) {
87
119
  if (file.endsWith('.sh')) {
88
120
  const filePath = path.join(scriptsDir, file);
89
- try {
90
- fs.chmodSync(filePath, 0o755);
91
- } catch {
92
- // Non-critical if filesystem does not support POSIX permissions
121
+ modified.push(filePath);
122
+ if (!dryRun) {
123
+ try {
124
+ fs.chmodSync(filePath, 0o755);
125
+ } catch {
126
+ // Non-critical if filesystem does not support POSIX permissions
127
+ }
93
128
  }
94
129
  }
95
130
  }
96
131
  }
97
132
  }
133
+ return modified;
98
134
  }
99
135
 
100
136
  /**
101
137
  * Recursively copies template files into the target directory and sets up symlinks and permissions.
102
138
  */
103
- function copyTemplate(targetDir, templateDir = getTemplateDir()) {
139
+ function copyTemplate(targetDir, templateDir = getTemplateDir(), options = {}) {
140
+ const { dryRun = false } = options;
104
141
  const resolvedTarget = path.resolve(targetDir);
105
142
  const resolvedTemplate = path.resolve(templateDir);
143
+ const actions = [];
106
144
 
107
- if (!fs.existsSync(resolvedTarget)) {
145
+ if (!dryRun && !fs.existsSync(resolvedTarget)) {
108
146
  fs.mkdirSync(resolvedTarget, { recursive: true });
109
147
  }
110
148
 
@@ -113,29 +151,46 @@ function copyTemplate(targetDir, templateDir = getTemplateDir()) {
113
151
  if (!fs.existsSync(srcPath)) continue;
114
152
 
115
153
  const destPath = path.join(resolvedTarget, item);
116
- fs.cpSync(srcPath, destPath, { recursive: true, force: true, dereference: false });
154
+ actions.push(`copy: ${item} -> ${destPath}`);
155
+
156
+ if (!dryRun) {
157
+ fs.cpSync(srcPath, destPath, { recursive: true, force: true, dereference: false });
158
+ }
117
159
  }
118
160
 
119
161
  // Ensure harness parity symlinks per AGENTS.md mandate
120
- ensureSymlink(resolvedTarget, 'CLAUDE.md', 'AGENTS.md');
121
- ensureSymlink(resolvedTarget, 'agents.md', 'AGENTS.md');
162
+ actions.push(`symlink: CLAUDE.md -> AGENTS.md`);
163
+ ensureSymlink(resolvedTarget, 'CLAUDE.md', 'AGENTS.md', dryRun);
164
+
165
+ actions.push(`symlink: agents.md -> AGENTS.md`);
166
+ ensureSymlink(resolvedTarget, 'agents.md', 'AGENTS.md', dryRun);
122
167
 
123
168
  // Ensure scripts are executable
124
- makeScriptsExecutable(resolvedTarget);
169
+ const inspectDir = dryRun ? resolvedTemplate : resolvedTarget;
170
+ const scripts = makeScriptsExecutable(inspectDir, dryRun);
171
+ for (const script of scripts) {
172
+ actions.push(`chmod: +x ${path.relative(inspectDir, script)}`);
173
+ }
174
+
175
+ return actions;
125
176
  }
126
177
 
127
178
  /**
128
179
  * Initializes a git repository in the target directory if not already inside one.
129
180
  */
130
181
  function initGit(targetDir, options = {}) {
131
- const { noGit = false } = options;
182
+ const { noGit = false, dryRun = false } = options;
132
183
  if (noGit) return false;
133
184
 
134
185
  const gitDir = path.join(targetDir, '.git');
135
186
  if (fs.existsSync(gitDir)) return false;
136
187
 
188
+ if (dryRun) {
189
+ return true;
190
+ }
191
+
137
192
  try {
138
- execSync('git init -q', { cwd: targetDir, stdio: 'ignore' });
193
+ cp.execSync('git init -q', { cwd: targetDir, stdio: 'ignore' });
139
194
  return true;
140
195
  } catch {
141
196
  return false;
@@ -150,26 +205,79 @@ function scaffold(options = {}) {
150
205
  targetDir = process.cwd(),
151
206
  force = false,
152
207
  noGit = false,
153
- templateDir = getTemplateDir()
208
+ templateDir = getTemplateDir(),
209
+ dryRun = false,
210
+ silent = false
154
211
  } = options;
155
212
 
156
213
  const resolvedTarget = path.resolve(targetDir);
157
- validateTarget(resolvedTarget, { templateDir, force });
158
- copyTemplate(resolvedTarget, templateDir);
159
- const gitInitialized = initGit(resolvedTarget, { noGit });
214
+ validateTarget(resolvedTarget, { templateDir, force, dryRun });
215
+ const actions = copyTemplate(resolvedTarget, templateDir, { dryRun });
216
+ const gitInitialized = initGit(resolvedTarget, { noGit, dryRun });
217
+ if (gitInitialized) {
218
+ actions.push('git: initialize repository');
219
+ }
160
220
 
161
221
  return {
162
222
  success: true,
163
223
  targetDir: resolvedTarget,
164
- gitInitialized
224
+ gitInitialized,
225
+ dryRun,
226
+ actions
227
+ };
228
+ }
229
+
230
+ /**
231
+ * Appends a standardized upstream change entry to changes.md.
232
+ */
233
+ function logChange(options = {}) {
234
+ const {
235
+ title,
236
+ category = 'Architecture',
237
+ targetFiles = 'docs/rules/',
238
+ rationale = 'Generic architectural enhancement',
239
+ description = '',
240
+ targetDir = process.cwd()
241
+ } = options;
242
+
243
+ if (!title || typeof title !== 'string' || !title.trim()) {
244
+ throw new Error('A change title is required to log an upstream change.');
245
+ }
246
+
247
+ const cleanTitle = title.trim();
248
+ const changesFilePath = path.join(path.resolve(targetDir), 'changes.md');
249
+ const today = new Date().toISOString().slice(0, 10);
250
+
251
+ const entry = `\n### [${today}] ${cleanTitle}\n` +
252
+ `- **Category:** ${category}\n` +
253
+ `- **Target File(s):** ${targetFiles}\n` +
254
+ `- **Rationale:** ${rationale}\n` +
255
+ `- **Description:** ${description || cleanTitle}\n` +
256
+ `- **Domain Filter Verification:** Verified 100% generic; purged of all project-specific business entities and models.\n`;
257
+
258
+ if (fs.existsSync(changesFilePath)) {
259
+ fs.appendFileSync(changesFilePath, entry, 'utf-8');
260
+ } else {
261
+ const initialHeader = `# Upstream Changes Ledger (\`changes.md\`)\n\n` +
262
+ `> **Core Purpose:** Record candidate improvements, generic architectural updates, defect post-mortems, and rule enhancements discovered in this workspace that should be incorporated into the upstream \`azcodr\` baseline template.\n\n` +
263
+ `---\n\n## Upstream Changes Log\n`;
264
+ fs.writeFileSync(changesFilePath, initialHeader + entry, 'utf-8');
265
+ }
266
+
267
+ return {
268
+ success: true,
269
+ filePath: changesFilePath,
270
+ entry
165
271
  };
166
272
  }
167
273
 
168
274
  module.exports = {
169
275
  scaffold,
276
+ logChange,
170
277
  validateTarget,
171
278
  copyTemplate,
172
279
  ensureSymlink,
280
+ isSameCaseInsensitiveFile,
173
281
  makeScriptsExecutable,
174
282
  initGit,
175
283
  getTemplateDir,
package/package.json CHANGED
@@ -1,20 +1,30 @@
1
1
  {
2
2
  "name": "azcodr",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Enterprise Multi-Tenant Architecture & Agentic Engineering Starter Template",
5
5
  "bin": {
6
6
  "azcodr": "bin/azcodr.js"
7
7
  },
8
8
  "main": "./lib/index.js",
9
+ "types": "./lib/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./lib/index.d.ts",
13
+ "default": "./lib/index.js"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
9
17
  "files": [
10
18
  "bin",
11
19
  "lib",
12
20
  "AGENTS.md",
13
21
  "memory.md",
22
+ "changes.md",
14
23
  "README.md",
15
24
  "docs",
16
25
  ".agents",
17
26
  ".gitignore",
27
+ ".editorconfig",
18
28
  "LICENSE"
19
29
  ],
20
30
  "keywords": [
@@ -41,9 +51,10 @@
41
51
  "node": ">=18.0.0"
42
52
  },
43
53
  "scripts": {
44
- "test": "node --test tests/**/*.test.js",
45
- "test:coverage": "node --test --experimental-test-coverage tests/**/*.test.js",
54
+ "test": "node --test",
55
+ "test:coverage": "node scripts/test_coverage.js",
56
+ "lint": "node --check bin/azcodr.js lib/index.js lib/scaffold.js tests/cli.test.js tests/scaffold.test.js scripts/test_coverage.js",
46
57
  "validate": "bash .agents/skills/agentic-architect/scripts/validate_agentic_configs.sh",
47
- "prepublishOnly": "npm test && npm run validate"
58
+ "prepublishOnly": "npm run test:coverage && npm run validate"
48
59
  }
49
60
  }
@@ -1,90 +0,0 @@
1
- ---
2
- name: merge-ai
3
- description: Use when the user invokes /merge-ai or asks to merge generic AI rules, skills, lessons learned, and post-mortems from the current workspace back into the generic azcodr baseline repository. Do not use for merging application business logic or routine Git branches.
4
- ---
5
-
6
- # Merge AI Knowledge, Rules & Skills Skill (`/merge-ai`)
7
-
8
- > **Core Philosophy:** Upstream baseline repositories (e.g. `https://github.com/org/azcodr`) must remain pristine, generic, and untouched until the user explicitly triggers `/merge-ai`. When triggered from any project workspace (e.g. `https://github.com/org/my-project`), detect if the baseline repo is already cloned locally (apply directly) or clone it first, purge all project-specific domain models, colocate DOs and DONTs into atomic rules, and synchronize the generic baseline.
9
-
10
- ---
11
-
12
- ## 1. When to Use This Skill
13
- - The user issues `/merge-ai` or requests syncing AI rules, skills, issue logs, and lessons learned back into the generic baseline repository.
14
- - User references repository URLs (e.g. Source: `https://github.com/org/my-project`, Target: `https://github.com/org/azcodr`).
15
- - Auditing divergences between the current project workspace and the generic baseline repository.
16
- - Exporting newly discovered architectural patterns, defect post-mortems, or reusable skills to the generic starter.
17
- - **DO NOT USE** during routine project feature development or bug fixes.
18
- - **DO NOT USE** to merge application domain entities, business logic, or project-specific data models.
19
- - **DO NOT USE** without explicit user invocation.
20
-
21
- ---
22
-
23
- ## 2. Step-by-Step Execution Workflow
24
-
25
- ### Phase 1: Target Baseline Repository Resolution (URL or Local)
26
- When `/merge-ai` is triggered with repository URLs (e.g. `/merge-ai https://github.com/org/my-project https://github.com/org/azcodr`):
27
- 1. **Execute Repo Resolver Script:**
28
- ```bash
29
- # Discovers existing local clone or automatically clones fresh
30
- eval $(bash .agents/skills/merge-ai/scripts/resolve_repo.sh "$TARGET_REPO_URL")
31
- ```
32
- - **If already cloned locally:** Discovers its directory, verifies clean working tree, and exports `STATUS=ALREADY_CLONED` and `LOCAL_PATH` (e.g. `/path/to/azcodr`).
33
- - **If not cloned locally:** Automatically executes `git clone "$TARGET_REPO_URL"` to `$HOME/projects/<name>` and exports `STATUS=CLONED_FRESH` and `LOCAL_PATH`.
34
- 2. Set `$BASELINE_DIR="$LOCAL_PATH"`.
35
- 3. If `STATUS=ALREADY_CLONED`, ensure the repository is on branch `main` (`git -C "$BASELINE_DIR" pull --ff-only`).
36
-
37
- ---
38
-
39
- ### Phase 2: Divergence Audit & Domain Purging
40
- 1. Run the divergence audit script:
41
- ```bash
42
- bash .agents/skills/merge-ai/scripts/audit_divergence.sh "$BASELINE_DIR"
43
- ```
44
- 2. Systematically filter out all project-specific elements before proposing changes:
45
- - **Purge Business Domain Entities:** Replace project-specific nouns with universal architectural archetypes (`Entity`, `Aggregate`, `ValueObject`, `Resource`, `Transaction`).
46
- - **Purge Concrete Stack Specifics:** Keep core rules stack-agnostic (Hexagonal Ports, abstract repositories). Keep project-specific setups (e.g. SQLite dev / Postgres prod, React Vite client) in the project workspace.
47
- - **Colocate DOs & DONTs into Atomic Rules:** Embed DOs and DONTs directly inside their governing atomic rule files in `docs/rules/` (`## Invariants, DO's & DONT's`). Keep `docs/knowledge/dos_and_donts.md` strictly as a clean cross-reference index directory.
48
- - **Transform ADRs & Post-Mortems:** Port universal decisions (ADR-007 CRUD & Selectors, ADR-008 Bootstrapping Decoupling, ADR-009 Agile Domain TDD, ADR-010 M:N Skill Composability) as generic ADRs in `memory.md`. Port universal post-mortems (`ISSUE-004`, `ISSUE-005`) into `issue_log.md` and `lessons_learned.md`.
49
-
50
- ---
51
-
52
- ### Phase 3: Dry-Run Review & Explicit User Confirmation
53
- 1. Present a concise, structured dry-run report to the user summarizing:
54
- - Target baseline repo URL and resolved local directory (`$BASELINE_DIR`).
55
- - Generic rules, skills, post-mortems, and ADRs to be merged.
56
- - Domain-specific elements purged.
57
- 2. **STOP AND ASK FOR EXPLICIT CONFIRMATION** before modifying `$BASELINE_DIR`.
58
-
59
- ---
60
-
61
- ### Phase 4: Apply Merge, Validate & Sync
62
- Upon user confirmation:
63
- 1. Apply the generic updates to `$BASELINE_DIR`:
64
- - `AGENTS.md` (Unified Agent Cognitive & Agile Domain Lifecycle).
65
- - `docs/rules/` (Updated atomic rules with colocated DOs/DONTs).
66
- - `.agents/skills/` (Updated generic skills, e.g. decoupled `lets-build`).
67
- - `docs/knowledge/` (Index-only `dos_and_donts.md`, generic post-mortems in `issue_log.md`, `lessons_learned.md`, `knowledge_graph.md`).
68
- - `memory.md` (Generic ADRs).
69
- 2. Validate agentic configuration integrity in the baseline:
70
- ```bash
71
- bash "$BASELINE_DIR/.agents/skills/agentic-architect/scripts/validate_agentic_configs.sh"
72
- ```
73
- *Requirement: 0 warnings, AGENTS.md <= 120 lines, valid symlinks.*
74
- 3. Commit and push the baseline repository to remote:
75
- ```bash
76
- git -C "$BASELINE_DIR" add -A
77
- git -C "$BASELINE_DIR" commit -m "feat(ai-sync): merge generic rules, skills, and lifecycle improvements from workspace"
78
- git -C "$BASELINE_DIR" push origin main
79
- ```
80
- 4. Confirm successful synchronization with the remote generic baseline URL.
81
-
82
- ---
83
-
84
- ## 3. Gotchas & What NOT to Do
85
-
86
- - **MAJOR DONT: Never touch, edit, or commit to the baseline repository (`azcodr`) during routine feature development.** The baseline must be left completely alone until `/merge-ai` is explicitly invoked.
87
- - **DO NOT** copy application domain models, database tables, or framework-specific configs to the baseline.
88
- - **DO NOT** create monolithic DO/DONT lists. Always colocate directives in atomic rules.
89
- - **DO NOT** execute the merge without presenting a dry-run summary and receiving explicit approval.
90
- - **DO NOT** push to the baseline repository if `validate_agentic_configs.sh` fails or reports warnings.
@@ -1,108 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- BASELINE_DIR="${1:-/home/prosubodh/projects/azcodr}"
5
- CURRENT_DIR="$(pwd)"
6
-
7
- echo "=================================================================="
8
- echo "🔍 Auditing AI Knowledge & Rule Divergence"
9
- echo "Current Workspace: $CURRENT_DIR"
10
- echo "Baseline Template: $BASELINE_DIR"
11
- echo "=================================================================="
12
-
13
- if [ ! -d "$BASELINE_DIR" ]; then
14
- echo "❌ Error: Baseline directory '$BASELINE_DIR' does not exist."
15
- exit 1
16
- fi
17
-
18
- echo ""
19
- echo "--- 1. Checking Core Directives (AGENTS.md) ---"
20
- if diff -q "$CURRENT_DIR/AGENTS.md" "$BASELINE_DIR/AGENTS.md" > /dev/null 2>&1; then
21
- echo "✅ AGENTS.md is identical."
22
- else
23
- echo "âš ī¸ AGENTS.md differs between workspaces."
24
- fi
25
-
26
- echo ""
27
- echo "--- 2. Checking Atomic Rules (docs/rules/) ---"
28
- DIFF_RULES=$(diff -qr "$CURRENT_DIR/docs/rules" "$BASELINE_DIR/docs/rules" 2>/dev/null || true)
29
- if [ -z "$DIFF_RULES" ]; then
30
- echo "✅ All atomic rules in docs/rules/ are identical."
31
- else
32
- echo "$DIFF_RULES"
33
- fi
34
-
35
- echo ""
36
- echo "--- 3. Checking Specialized Skills (.agents/skills/) ---"
37
- DIFF_SKILLS=$(diff -qr "$CURRENT_DIR/.agents/skills" "$BASELINE_DIR/.agents/skills" 2>/dev/null || true)
38
- if [ -z "$DIFF_SKILLS" ]; then
39
- echo "✅ All skills in .agents/skills/ are identical."
40
- else
41
- echo "$DIFF_SKILLS"
42
- fi
43
-
44
- echo ""
45
- echo "--- 4. Checking Knowledge Hub (docs/knowledge/) ---"
46
- DIFF_KNOW=$(diff -qr "$CURRENT_DIR/docs/knowledge" "$BASELINE_DIR/docs/knowledge" 2>/dev/null || true)
47
- if [ -z "$DIFF_KNOW" ]; then
48
- echo "✅ All knowledge files in docs/knowledge/ are identical."
49
- else
50
- echo "$DIFF_KNOW"
51
- fi
52
-
53
- echo ""
54
- echo "--- 5. Checking Architecture Decision Records (memory.md) ---"
55
- if [ -f "$CURRENT_DIR/memory.md" ] && [ -f "$BASELINE_DIR/memory.md" ]; then
56
- mapfile -t BASELINE_ADRS < <(grep -E '^### ADR-[0-9]+:' "$BASELINE_DIR/memory.md" 2>/dev/null | sed -E 's/^### ADR-[0-9]+:[[:space:]]*//' || true)
57
- mapfile -t CURRENT_ADRS < <(grep -E '^### ADR-[0-9]+:' "$CURRENT_DIR/memory.md" 2>/dev/null | sed -E 's/^### ADR-[0-9]+:[[:space:]]*//' || true)
58
-
59
- MISSING_IN_CURRENT=()
60
- for b_adr in "${BASELINE_ADRS[@]}"; do
61
- [ -z "$b_adr" ] && continue
62
- found=false
63
- for c_adr in "${CURRENT_ADRS[@]}"; do
64
- if [ "$b_adr" = "$c_adr" ]; then
65
- found=true
66
- break
67
- fi
68
- done
69
- if [ "$found" = false ]; then
70
- MISSING_IN_CURRENT+=("$b_adr")
71
- fi
72
- done
73
-
74
- EXTRA_IN_CURRENT=()
75
- for c_adr in "${CURRENT_ADRS[@]}"; do
76
- [ -z "$c_adr" ] && continue
77
- found=false
78
- for b_adr in "${BASELINE_ADRS[@]}"; do
79
- if [ "$c_adr" = "$b_adr" ]; then
80
- found=true
81
- break
82
- fi
83
- done
84
- if [ "$found" = false ]; then
85
- EXTRA_IN_CURRENT+=("$c_adr")
86
- fi
87
- done
88
-
89
- if [ ${#MISSING_IN_CURRENT[@]} -gt 0 ]; then
90
- echo "âš ī¸ Workspace is missing ${#MISSING_IN_CURRENT[@]} baseline ADR(s):"
91
- for m in "${MISSING_IN_CURRENT[@]}"; do
92
- echo " - $m"
93
- done
94
- elif [ ${#EXTRA_IN_CURRENT[@]} -eq 0 ]; then
95
- echo "✅ memory.md ADRs are 100% identical."
96
- else
97
- echo "✅ All generic baseline ADRs are synchronized."
98
- for e in "${EXTRA_IN_CURRENT[@]}"; do
99
- echo " â„šī¸ Project-specific ADR retained in workspace: $e"
100
- done
101
- fi
102
- else
103
- echo "âš ī¸ memory.md not found in one or both workspaces."
104
- fi
105
-
106
- echo "=================================================================="
107
- echo "Audit complete. Run /merge-ai to filter and merge generic changes."
108
- echo "=================================================================="