azcodr 1.0.0 → 1.0.1
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/AGENTS.md +1 -2
- package/README.md +3 -3
- package/bin/azcodr.js +82 -4
- package/changes.md +36 -0
- package/docs/rules/upstream_synchronization.md +28 -26
- package/lib/scaffold.js +46 -0
- package/package.json +2 -1
- package/.agents/skills/merge-ai/SKILL.md +0 -90
- package/.agents/skills/merge-ai/scripts/audit_divergence.sh +0 -108
- package/.agents/skills/merge-ai/scripts/resolve_repo.sh +0 -177
package/AGENTS.md
CHANGED
|
@@ -100,7 +100,7 @@ To prevent context bloat and keep prompt overhead minimal, detailed engineering
|
|
|
100
100
|
| **Relentless Questioning** | [docs/rules/relentless_questioning.md](./docs/rules/relentless_questioning.md) | Dynamic context-aware interrogation loops, adaptive decision trees. |
|
|
101
101
|
| **Workspace Isolation** | [docs/rules/workspace_isolation.md](./docs/rules/workspace_isolation.md) | Strict workspace sovereignty, zero global contamination, local ground truth. |
|
|
102
102
|
| **Continuous Learning** | [docs/rules/continuous_learning.md](./docs/rules/continuous_learning.md) | Automated defect post-mortems, DO's/DONT's logging, dynamic rule updates. |
|
|
103
|
-
| **Upstream Sync** | [docs/rules/upstream_synchronization.md](./docs/rules/upstream_synchronization.md) |
|
|
103
|
+
| **Upstream Sync** | [docs/rules/upstream_synchronization.md](./docs/rules/upstream_synchronization.md) | Logging generic architecture improvements to changes.md; zero baseline pollution. |
|
|
104
104
|
---
|
|
105
105
|
|
|
106
106
|
## 4. Agent Configuration & Workspace Architecture
|
|
@@ -113,7 +113,6 @@ To prevent context bloat and keep prompt overhead minimal, detailed engineering
|
|
|
113
113
|
- [`clean-code-refactor`](.agents/skills/clean-code-refactor/SKILL.md): Refactoring code smells with Clean Code, SOLID, and design patterns.
|
|
114
114
|
- [`lets-build`](.agents/skills/lets-build/SKILL.md): Conducting architecture interviews to finalize stack, frameworks, package managers, and bootstrapping projects.
|
|
115
115
|
- [`relentless-questioner`](.agents/skills/relentless-questioner/SKILL.md): Dynamic context-aware interrogation loops before planning and coding.
|
|
116
|
-
- [`merge-ai`](.agents/skills/merge-ai/SKILL.md): Auditing, filtering, and merging generic rules and skills to upstream baseline.
|
|
117
116
|
- **Relentless Skill Architecture Inquiry:** Never author or update skills on assumptions. Interrogate all 7 inquiry branches (placement, trigger intent, domain truth, gotchas/anti-patterns, determinism, progressive bloat, verification loop) defined in [docs/rules/agentic_configuration.md](./docs/rules/agentic_configuration.md) before writing `SKILL.md`.
|
|
118
117
|
- **Workspace Memory & Knowledge Hub:** Consult [`memory.md`](./memory.md) for ADRs, and [`docs/knowledge/`](./docs/knowledge/knowledge_graph.md) for system topologies, issue logs, and DO's/DONT's.
|
|
119
118
|
- **Harness Parity & Symlinks:** `AGENTS.md`, `CLAUDE.md`, and `agents.md` must remain identical via filesystem symbolic links to eliminate configuration divergence across different agent harnesses.
|
package/README.md
CHANGED
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
│ ├── clean-code-refactor/ # Refactoring code smells with GoF & Clean Code
|
|
32
32
|
│ ├── compliance-audit/ # SOC 2, ISO 27001 & OWASP open-source audits
|
|
33
33
|
│ ├── lets-build/ # Architecture interview & project bootstrapper
|
|
34
|
-
│ ├── merge-ai/ # Auditing & merging generic AI knowledge to upstream
|
|
35
34
|
│ ├── product-analyst/ # INVEST user stories & Gherkin criteria
|
|
36
35
|
│ └── relentless-questioner/ # Context-aware dynamic interrogation loop
|
|
37
36
|
├── docs/
|
|
@@ -45,6 +44,7 @@
|
|
|
45
44
|
├── AGENTS.md # Lean root agentic configuration (< 120 lines)
|
|
46
45
|
├── CLAUDE.md -> AGENTS.md # Filesystem symlink for harness parity
|
|
47
46
|
├── agents.md -> AGENTS.md # Filesystem symlink for harness parity
|
|
47
|
+
├── changes.md # Upstream changes ledger
|
|
48
48
|
├── memory.md # Master memory hub & Lightweight ADR ledger
|
|
49
49
|
└── README.md # Project documentation
|
|
50
50
|
```
|
|
@@ -103,7 +103,7 @@ The architecture enforces 47 atomic, single-responsibility domain rules. Read on
|
|
|
103
103
|
| **Relentless Questioning** | [`relentless_questioning.md`](./docs/rules/relentless_questioning.md) | Dynamic context-aware interrogation loops, adaptive decision trees. |
|
|
104
104
|
| **Workspace Isolation** | [`workspace_isolation.md`](./docs/rules/workspace_isolation.md) | Strict workspace sovereignty, zero global contamination, local ground truth. |
|
|
105
105
|
| **Continuous Learning** | [`continuous_learning.md`](./docs/rules/continuous_learning.md) | Automated defect post-mortems, DO's/DONT's logging, dynamic rule updates. |
|
|
106
|
-
| **Upstream Sync** | [`upstream_synchronization.md`](./docs/rules/upstream_synchronization.md) |
|
|
106
|
+
| **Upstream Sync** | [`upstream_synchronization.md`](./docs/rules/upstream_synchronization.md) | Logging generic architecture improvements to changes.md; zero baseline pollution. |
|
|
107
107
|
|
|
108
108
|
---
|
|
109
109
|
|
|
@@ -113,7 +113,6 @@ The architecture enforces 47 atomic, single-responsibility domain rules. Read on
|
|
|
113
113
|
- [`clean-code-refactor`](.agents/skills/clean-code-refactor/SKILL.md): Refactoring code smells with Clean Code, SOLID, and modern design patterns.
|
|
114
114
|
- [`compliance-audit`](.agents/skills/compliance-audit/SKILL.md): Conducting SOC 2, ISO 27001, and OWASP audits using open-source scanners.
|
|
115
115
|
- [`lets-build`](.agents/skills/lets-build/SKILL.md): Conducting architecture interviews to finalize stack, frameworks, package managers, and bootstrapping projects.
|
|
116
|
-
- [`merge-ai`](.agents/skills/merge-ai/SKILL.md): Auditing, filtering, and merging generic rules and skills to upstream baseline.
|
|
117
116
|
- [`product-analyst`](.agents/skills/product-analyst/SKILL.md): Aligning OKRs, backlog ordering (Kano/MoSCoW/RICE), INVEST stories, and Gherkin criteria.
|
|
118
117
|
- [`relentless-questioner`](.agents/skills/relentless-questioner/SKILL.md): Dynamic context-aware interrogation loops before planning and coding.
|
|
119
118
|
|
|
@@ -182,3 +181,4 @@ Once confirmed, the agent automatically executes:
|
|
|
182
181
|
- 🐛 **[Coding Issue Log](./docs/knowledge/issue_log.md)**: Defect post-mortems and preventative rules.
|
|
183
182
|
- 💡 **[Institutional Lessons Learned](./docs/knowledge/lessons_learned.md)**: Strategic engineering insights.
|
|
184
183
|
- 📜 **[Lightweight ADR Ledger](./memory.md)**: Formal Architectural Decision Records.
|
|
184
|
+
- 📝 **[Upstream Changes Ledger](./changes.md)**: Record candidate improvements and generic patterns for the upstream azcodr template.
|
package/bin/azcodr.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
const readline = require('node:readline');
|
|
6
|
-
const { scaffold, getTemplateDir } = require('../lib/scaffold.js');
|
|
6
|
+
const { scaffold, logChange, getTemplateDir } = require('../lib/scaffold.js');
|
|
7
7
|
const pkg = require('../package.json');
|
|
8
8
|
|
|
9
9
|
const args = process.argv.slice(2);
|
|
@@ -15,19 +15,28 @@ Enterprise Multi-Tenant Architecture & Agentic Engineering Starter Template
|
|
|
15
15
|
|
|
16
16
|
Usage:
|
|
17
17
|
npx azcodr [directory] [options]
|
|
18
|
+
npx azcodr change <title> [options]
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
directory
|
|
20
|
+
Commands:
|
|
21
|
+
[directory] Scaffold azcodr template into directory (default: current directory)
|
|
22
|
+
change <title> Log a generic architectural change to changes.md
|
|
21
23
|
|
|
22
|
-
Options:
|
|
24
|
+
Scaffold Options:
|
|
23
25
|
-f, --force Overwrite existing files in target directory without confirmation
|
|
24
26
|
--no-git Do not initialize a git repository
|
|
25
27
|
-v, --version Display version number
|
|
26
28
|
-h, --help Display this help message
|
|
27
29
|
|
|
30
|
+
Change Options:
|
|
31
|
+
-c, --category Category (Rule | Skill | Infrastructure | CLI | Knowledge Hub)
|
|
32
|
+
-f, --files Target file(s) affected (e.g. "docs/rules/caching.md")
|
|
33
|
+
-r, --rationale Rationale for upstream template incorporation
|
|
34
|
+
-d, --desc Detailed description of the change
|
|
35
|
+
|
|
28
36
|
Examples:
|
|
29
37
|
npx azcodr my-project
|
|
30
38
|
npx azcodr . --force
|
|
39
|
+
npx azcodr change "Add Wasm plugin interface" -c Architecture
|
|
31
40
|
`);
|
|
32
41
|
}
|
|
33
42
|
|
|
@@ -49,7 +58,75 @@ function askQuestion(query) {
|
|
|
49
58
|
});
|
|
50
59
|
}
|
|
51
60
|
|
|
61
|
+
async function handleLogChange() {
|
|
62
|
+
let title = null;
|
|
63
|
+
let category = 'Architecture';
|
|
64
|
+
let targetFiles = 'docs/rules/';
|
|
65
|
+
let rationale = 'Generic architectural enhancement';
|
|
66
|
+
let description = '';
|
|
67
|
+
|
|
68
|
+
for (let i = 1; i < args.length; i++) {
|
|
69
|
+
const a = args[i];
|
|
70
|
+
if (a === '-c' || a === '--category') {
|
|
71
|
+
category = args[++i] || category;
|
|
72
|
+
} else if (a === '-f' || a === '--files') {
|
|
73
|
+
targetFiles = args[++i] || targetFiles;
|
|
74
|
+
} else if (a === '-r' || a === '--rationale') {
|
|
75
|
+
rationale = args[++i] || rationale;
|
|
76
|
+
} else if (a === '-d' || a === '--desc' || a === '--description') {
|
|
77
|
+
description = args[++i] || description;
|
|
78
|
+
} else if (!a.startsWith('-')) {
|
|
79
|
+
if (!title) {
|
|
80
|
+
title = a;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!title) {
|
|
86
|
+
if (process.stdin.isTTY) {
|
|
87
|
+
title = await askQuestion('? Change title: ');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!title) {
|
|
92
|
+
console.error('❌ Error: A title is required to log an upstream change.');
|
|
93
|
+
console.error('Usage: npx azcodr change "<title>" [-c Category] [-f Files] [-r Rationale] [-d Description]');
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const res = logChange({
|
|
99
|
+
title,
|
|
100
|
+
category,
|
|
101
|
+
targetFiles,
|
|
102
|
+
rationale,
|
|
103
|
+
description,
|
|
104
|
+
targetDir: process.cwd()
|
|
105
|
+
});
|
|
106
|
+
console.log(`\n✅ Upstream change logged to ${res.filePath}\n`);
|
|
107
|
+
process.exit(0);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error(`\n❌ Failed to log change: ${err.message}\n`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
52
114
|
async function main() {
|
|
115
|
+
if (args.length > 0 && (args[0] === '-h' || args[0] === '--help')) {
|
|
116
|
+
printHelp();
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (args.length > 0 && (args[0] === '-v' || args[0] === '--version')) {
|
|
121
|
+
printVersion();
|
|
122
|
+
process.exit(0);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (args.length > 0 && (args[0] === 'change' || args[0] === 'log-change')) {
|
|
126
|
+
await handleLogChange();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
53
130
|
let targetDir = null;
|
|
54
131
|
let force = false;
|
|
55
132
|
let noGit = false;
|
|
@@ -127,6 +204,7 @@ async function main() {
|
|
|
127
204
|
console.log(' ✅ Progressive disclosure rules copied (docs/rules/)');
|
|
128
205
|
console.log(' ✅ Workspace knowledge hub and ADR ledger copied (docs/knowledge/, memory.md)');
|
|
129
206
|
console.log(' ✅ Specialized agentic skills copied (.agents/skills/)');
|
|
207
|
+
console.log(' ✅ Upstream changes ledger initialized (changes.md)');
|
|
130
208
|
console.log(' ✅ Agent directives and harness symlinks established (AGENTS.md, CLAUDE.md, agents.md)');
|
|
131
209
|
if (result.gitInitialized) {
|
|
132
210
|
console.log(' ✅ Git repository initialized');
|
package/changes.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Upstream Changes Ledger (`changes.md`)
|
|
2
|
+
|
|
3
|
+
> **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. No automated git merging or external repo mutation is performed.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Specification & Protocol
|
|
8
|
+
|
|
9
|
+
When an AI agent or engineer discovers a generic architectural improvement, bug fix, or rule refinement during project development, append an entry below using this atomic format:
|
|
10
|
+
|
|
11
|
+
```markdown
|
|
12
|
+
### [YYYY-MM-DD] <Title of Change>
|
|
13
|
+
- **Category:** Rule | Skill | Infrastructure | CLI | Knowledge Hub
|
|
14
|
+
- **Target File(s):** `docs/rules/...`, `.agents/skills/...`, etc.
|
|
15
|
+
- **Rationale:** Why this improvement is necessary or valuable across all enterprise projects.
|
|
16
|
+
- **Description:** Concise summary of the mutation or invariant added.
|
|
17
|
+
- **Domain Filter Verification:** Verified 100% generic; purged of all project-specific business entities and models.
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. Upstream Changes Log
|
|
23
|
+
|
|
24
|
+
### [2026-09-25] Initialized npx Scaffolder CLI and npm Package
|
|
25
|
+
- **Category:** CLI & Infrastructure
|
|
26
|
+
- **Target File(s):** `bin/azcodr.js`, `lib/scaffold.js`, `package.json`, `tests/`
|
|
27
|
+
- **Rationale:** Eliminate manual `cp -r` copying; enable anyone to pull and scaffold the azcodr architecture template via `npx azcodr`.
|
|
28
|
+
- **Description:** Implemented zero-dependency Node.js CLI executable with Outside-In TDD, harness parity symlink generation, script execution bit setting, and full test suite passing with 100% agentic config validation.
|
|
29
|
+
- **Domain Filter Verification:** Verified 100% generic; no project-specific business models.
|
|
30
|
+
|
|
31
|
+
### [2026-09-25] Streamlined Upstream Sync Protocol to changes.md Ledger
|
|
32
|
+
- **Category:** Rule & Process
|
|
33
|
+
- **Target File(s):** `docs/rules/upstream_synchronization.md`, `changes.md`, `AGENTS.md`
|
|
34
|
+
- **Rationale:** Remove fragile git repo resolution and merge scripts; replace with atomic change logging in `changes.md`.
|
|
35
|
+
- **Description:** Retired `merge-ai` skill and removed machine-specific hardcoded paths. All upstream improvements are now recorded atomically in `changes.md`.
|
|
36
|
+
- **Domain Filter Verification:** Verified 100% generic.
|
|
@@ -1,40 +1,37 @@
|
|
|
1
|
-
# Upstream Baseline Synchronization &
|
|
1
|
+
# Upstream Baseline Synchronization & changes.md Ledger
|
|
2
2
|
|
|
3
|
-
> **Core Mandate:** Upstream template/baseline workspaces (`azcodr`) must remain strictly untouched
|
|
3
|
+
> **Core Mandate:** Upstream template/baseline workspaces (`azcodr`) must remain strictly untouched during project development. When generic architectural improvements, rule refinements, or post-mortems are identified, record them solely into the `changes.md` ledger with zero automated repo merging or baseline contamination.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## 1. The Baseline-Project Decoupling Principle
|
|
8
8
|
|
|
9
|
-
Workspaces operate under a
|
|
9
|
+
Workspaces operate under a clean, decoupled flow:
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
[Upstream Generic Baseline: azcodr]
|
|
13
13
|
│
|
|
14
|
-
▼ (
|
|
14
|
+
▼ (Scaffolded via npx azcodr)
|
|
15
15
|
[Derived Project Workspace: my-app / others]
|
|
16
16
|
│
|
|
17
17
|
│ (Accumulates project code, specificities, and institutional lessons)
|
|
18
18
|
│
|
|
19
|
-
▼ (
|
|
20
|
-
[
|
|
21
|
-
│
|
|
22
|
-
▼
|
|
23
|
-
[Clean Merge into Upstream Baseline: azcodr]
|
|
19
|
+
▼ (Record reusable improvements)
|
|
20
|
+
[Upstream Changes Ledger: changes.md]
|
|
24
21
|
```
|
|
25
22
|
|
|
26
|
-
- **Pristine Upstream Mandate:** Never edit, commit, or
|
|
27
|
-
- **
|
|
23
|
+
- **Pristine Upstream Mandate:** Never edit, commit, or attempt automated git merges to an upstream baseline repository during routine project development, feature implementation, or bug fixes.
|
|
24
|
+
- **Ledger-Only Synchronization:** When generic architectural discoveries or defect post-mortems occur, document them cleanly in `changes.md` at the workspace root. No automated merge AI or remote repo synchronization is executed.
|
|
28
25
|
|
|
29
26
|
---
|
|
30
27
|
|
|
31
28
|
## 2. Zero-Contamination Invariant (Generic vs. Specific)
|
|
32
29
|
|
|
33
|
-
When
|
|
30
|
+
When logging proposed changes into `changes.md`, enforce strict domain filtering:
|
|
34
31
|
|
|
35
|
-
| Element Category | Keep in Specific Project Workspace | Allow in
|
|
32
|
+
| Element Category | Keep in Specific Project Workspace | Allow in changes.md for Upstream (`azcodr`) |
|
|
36
33
|
|---|---|---|
|
|
37
|
-
| **Domain Entities** | Concrete business models (`Order`, `Customer`, `Invoice`,
|
|
34
|
+
| **Domain Entities** | Concrete business models (`Order`, `Customer`, `Invoice`, etc.) | Abstract archetypes (`Entity`, `Aggregate`, `ValueObject`, `Resource`) |
|
|
38
35
|
| **Tech Stack / Adapters** | Concrete choices (Prisma, SQLite dev, PostgreSQL prod, Vite React) | Hexagonal Ports, abstract repository contracts, polyglot adapter guidance |
|
|
39
36
|
| **Architectural Rules** | Specific entity validation, specific route paths | Universal invariants (5-Phase Agile Lifecycle, SemVer trigger matrix, FK dropdowns) |
|
|
40
37
|
| **ADRs** | Stack decisions (`ADR-006: Target Tech Stack for Project`) | Generic architecture patterns (`ADR-007` to `ADR-010`) |
|
|
@@ -42,25 +39,30 @@ When merging knowledge, rules, or skills back to the baseline, enforce strict do
|
|
|
42
39
|
|
|
43
40
|
---
|
|
44
41
|
|
|
45
|
-
## 3.
|
|
42
|
+
## 3. Atomic changes.md Entry Protocol
|
|
43
|
+
|
|
44
|
+
Every upstream-bound proposal logged to `changes.md` must follow the standardized format:
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
```markdown
|
|
47
|
+
### [YYYY-MM-DD] <Title of Change>
|
|
48
|
+
- **Category:** Rule | Skill | Infrastructure | CLI | Knowledge Hub
|
|
49
|
+
- **Target File(s):** `docs/rules/...`, `.agents/skills/...`, etc.
|
|
50
|
+
- **Rationale:** Why this improvement is necessary or valuable across all enterprise projects.
|
|
51
|
+
- **Description:** Concise summary of the mutation or invariant added.
|
|
52
|
+
- **Domain Filter Verification:** Verified 100% generic; purged of all project-specific business entities and models.
|
|
53
|
+
```
|
|
51
54
|
|
|
52
55
|
---
|
|
53
56
|
|
|
54
57
|
## 4. Invariants, DO's & DONT's
|
|
55
58
|
|
|
56
59
|
### DO's:
|
|
57
|
-
- **DO:**
|
|
58
|
-
- **DO:**
|
|
59
|
-
- **DO:** Distill all lessons and post-mortems into generic, domain-agnostic language before merging.
|
|
60
|
+
- **DO:** Record candidate generic architectural improvements in `changes.md`.
|
|
61
|
+
- **DO:** Distill all lessons and post-mortems into generic, domain-agnostic language before logging.
|
|
60
62
|
- **DO:** Colocate DOs and DONTs directly inside the relevant atomic rules and skills.
|
|
61
|
-
- **DO:**
|
|
63
|
+
- **DO:** Verify that all entries in `changes.md` are 100% stack- and domain-agnostic.
|
|
62
64
|
|
|
63
65
|
### DONT's:
|
|
64
|
-
- **DONT:** Never
|
|
65
|
-
- **DONT:** Never contaminate
|
|
66
|
-
- **DONT:** Never
|
|
66
|
+
- **DONT:** Never execute automated upstream git cloning or merge AI workflows during project work.
|
|
67
|
+
- **DONT:** Never contaminate `changes.md` with project-specific business logic, schemas, or customer requirements.
|
|
68
|
+
- **DONT:** Never leave machine-specific or absolute user paths in scripts or documentation.
|
package/lib/scaffold.js
CHANGED
|
@@ -7,6 +7,7 @@ const { execSync } = require('node:child_process');
|
|
|
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',
|
|
@@ -165,8 +166,53 @@ function scaffold(options = {}) {
|
|
|
165
166
|
};
|
|
166
167
|
}
|
|
167
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Appends a standardized upstream change entry to changes.md.
|
|
171
|
+
*/
|
|
172
|
+
function logChange(options = {}) {
|
|
173
|
+
const {
|
|
174
|
+
title,
|
|
175
|
+
category = 'Architecture',
|
|
176
|
+
targetFiles = 'docs/rules/',
|
|
177
|
+
rationale = 'Generic architectural enhancement',
|
|
178
|
+
description = '',
|
|
179
|
+
targetDir = process.cwd()
|
|
180
|
+
} = options;
|
|
181
|
+
|
|
182
|
+
if (!title || typeof title !== 'string' || !title.trim()) {
|
|
183
|
+
throw new Error('A change title is required to log an upstream change.');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const cleanTitle = title.trim();
|
|
187
|
+
const changesFilePath = path.join(path.resolve(targetDir), 'changes.md');
|
|
188
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
189
|
+
|
|
190
|
+
const entry = `\n### [${today}] ${cleanTitle}\n` +
|
|
191
|
+
`- **Category:** ${category}\n` +
|
|
192
|
+
`- **Target File(s):** ${targetFiles}\n` +
|
|
193
|
+
`- **Rationale:** ${rationale}\n` +
|
|
194
|
+
`- **Description:** ${description || cleanTitle}\n` +
|
|
195
|
+
`- **Domain Filter Verification:** Verified 100% generic; purged of all project-specific business entities and models.\n`;
|
|
196
|
+
|
|
197
|
+
if (fs.existsSync(changesFilePath)) {
|
|
198
|
+
fs.appendFileSync(changesFilePath, entry, 'utf-8');
|
|
199
|
+
} else {
|
|
200
|
+
const initialHeader = `# Upstream Changes Ledger (\`changes.md\`)\n\n` +
|
|
201
|
+
`> **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` +
|
|
202
|
+
`---\n\n## Upstream Changes Log\n`;
|
|
203
|
+
fs.writeFileSync(changesFilePath, initialHeader + entry, 'utf-8');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
success: true,
|
|
208
|
+
filePath: changesFilePath,
|
|
209
|
+
entry
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
168
213
|
module.exports = {
|
|
169
214
|
scaffold,
|
|
215
|
+
logChange,
|
|
170
216
|
validateTarget,
|
|
171
217
|
copyTemplate,
|
|
172
218
|
ensureSymlink,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azcodr",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Enterprise Multi-Tenant Architecture & Agentic Engineering Starter Template",
|
|
5
5
|
"bin": {
|
|
6
6
|
"azcodr": "bin/azcodr.js"
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"lib",
|
|
12
12
|
"AGENTS.md",
|
|
13
13
|
"memory.md",
|
|
14
|
+
"changes.md",
|
|
14
15
|
"README.md",
|
|
15
16
|
"docs",
|
|
16
17
|
".agents",
|
|
@@ -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 "=================================================================="
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
# ==============================================================================
|
|
5
|
-
# resolve_repo.sh
|
|
6
|
-
# Deterministically resolves whether a remote Git URL is cloned locally,
|
|
7
|
-
# EVEN IF CLONED UNDER A COMPLETELY DIFFERENT FOLDER NAME.
|
|
8
|
-
#
|
|
9
|
-
# Usage: ./resolve_repo.sh <REPO_URL> [--check-only] [--dest-dir <DIR>]
|
|
10
|
-
# ==============================================================================
|
|
11
|
-
|
|
12
|
-
REPO_URL="${1:-}"
|
|
13
|
-
CHECK_ONLY=false
|
|
14
|
-
DEST_DIR=""
|
|
15
|
-
|
|
16
|
-
if [ -z "$REPO_URL" ]; then
|
|
17
|
-
echo "Usage: $0 <REPO_URL> [--check-only] [--dest-dir <DIR>]" >&2
|
|
18
|
-
exit 1
|
|
19
|
-
fi
|
|
20
|
-
|
|
21
|
-
shift || true
|
|
22
|
-
while [[ $# -gt 0 ]]; do
|
|
23
|
-
case "$1" in
|
|
24
|
-
--check-only)
|
|
25
|
-
CHECK_ONLY=true
|
|
26
|
-
shift
|
|
27
|
-
;;
|
|
28
|
-
--dest-dir)
|
|
29
|
-
DEST_DIR="$2"
|
|
30
|
-
shift 2
|
|
31
|
-
;;
|
|
32
|
-
*)
|
|
33
|
-
echo "Unknown option: $1" >&2
|
|
34
|
-
exit 1
|
|
35
|
-
;;
|
|
36
|
-
esac
|
|
37
|
-
done
|
|
38
|
-
|
|
39
|
-
normalize_git_url() {
|
|
40
|
-
local url="$1"
|
|
41
|
-
url="${url%.git}"
|
|
42
|
-
url="${url%/}"
|
|
43
|
-
url=$(echo "$url" | sed -E 's/^(https?:\/\/|ssh:\/\/git@|ssh:\/\/|git@)//')
|
|
44
|
-
url=$(echo "$url" | sed -E 's/:/\//')
|
|
45
|
-
echo "$url" | tr '[:upper:]' '[:lower:]'
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
TARGET_NORM=$(normalize_git_url "$REPO_URL")
|
|
49
|
-
REPO_NAME=$(basename "$TARGET_NORM")
|
|
50
|
-
CURRENT_DIR="$(pwd)"
|
|
51
|
-
|
|
52
|
-
# Check if a specific directory matches the target URL by inspecting its remotes
|
|
53
|
-
matches_target_url() {
|
|
54
|
-
local dir="$1"
|
|
55
|
-
if [ ! -d "$dir/.git" ]; then
|
|
56
|
-
return 1
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
# Check all configured remotes (origin, upstream, etc.)
|
|
60
|
-
local remotes
|
|
61
|
-
remotes=$(git -C "$dir" config --get-regexp '^remote\..*\.url' 2>/dev/null | awk '{print $2}' || true)
|
|
62
|
-
for r in $remotes; do
|
|
63
|
-
local r_norm
|
|
64
|
-
r_norm=$(normalize_git_url "$r")
|
|
65
|
-
if [ "$r_norm" = "$TARGET_NORM" ]; then
|
|
66
|
-
return 0
|
|
67
|
-
fi
|
|
68
|
-
done
|
|
69
|
-
return 1
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
FOUND_PATH=""
|
|
73
|
-
|
|
74
|
-
# ------------------------------------------------------------------------------
|
|
75
|
-
# Pass 1: Fast Probe of Standard Conventions
|
|
76
|
-
# ------------------------------------------------------------------------------
|
|
77
|
-
FAST_CANDIDATES=(
|
|
78
|
-
"${DEST_DIR:-}"
|
|
79
|
-
"$HOME/projects/$REPO_NAME"
|
|
80
|
-
"$(dirname "$CURRENT_DIR")/$REPO_NAME"
|
|
81
|
-
"$CURRENT_DIR/$REPO_NAME"
|
|
82
|
-
"$CURRENT_DIR"
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
for cand in "${FAST_CANDIDATES[@]}"; do
|
|
86
|
-
[ -z "$cand" ] && continue
|
|
87
|
-
if matches_target_url "$cand"; then
|
|
88
|
-
FOUND_PATH="$(cd "$cand" && pwd)"
|
|
89
|
-
break
|
|
90
|
-
fi
|
|
91
|
-
done
|
|
92
|
-
|
|
93
|
-
# ------------------------------------------------------------------------------
|
|
94
|
-
# Pass 2: Deep Scan Across Sibling & Project Roots (Handles ANY folder name!)
|
|
95
|
-
# ------------------------------------------------------------------------------
|
|
96
|
-
if [ -z "$FOUND_PATH" ]; then
|
|
97
|
-
SEARCH_ROOTS=()
|
|
98
|
-
PARENT_DIR="$(dirname "$CURRENT_DIR")"
|
|
99
|
-
SEARCH_ROOTS+=("$PARENT_DIR")
|
|
100
|
-
[ -d "$HOME/projects" ] && [ "$HOME/projects" != "$PARENT_DIR" ] && SEARCH_ROOTS+=("$HOME/projects")
|
|
101
|
-
[ -d "$HOME/workspace" ] && SEARCH_ROOTS+=("$HOME/workspace")
|
|
102
|
-
[ -d "$HOME/dev" ] && SEARCH_ROOTS+=("$HOME/dev")
|
|
103
|
-
[ -d "$HOME/code" ] && SEARCH_ROOTS+=("$HOME/code")
|
|
104
|
-
|
|
105
|
-
for root in "${SEARCH_ROOTS[@]}"; do
|
|
106
|
-
[ ! -d "$root" ] && continue
|
|
107
|
-
# Search maxdepth 2 for any .git directory
|
|
108
|
-
while IFS= read -r gitdir; do
|
|
109
|
-
repo_candidate="$(dirname "$gitdir")"
|
|
110
|
-
if matches_target_url "$repo_candidate"; then
|
|
111
|
-
FOUND_PATH="$(cd "$repo_candidate" && pwd)"
|
|
112
|
-
break 2
|
|
113
|
-
fi
|
|
114
|
-
done < <(find "$root" -maxdepth 2 -name ".git" -type d 2>/dev/null || true)
|
|
115
|
-
done
|
|
116
|
-
fi
|
|
117
|
-
|
|
118
|
-
# ------------------------------------------------------------------------------
|
|
119
|
-
# Output Resolution
|
|
120
|
-
# ------------------------------------------------------------------------------
|
|
121
|
-
if [ -n "$FOUND_PATH" ]; then
|
|
122
|
-
BRANCH=$(git -C "$FOUND_PATH" branch --show-current 2>/dev/null || true)
|
|
123
|
-
if [ -z "$BRANCH" ]; then
|
|
124
|
-
BRANCH=$(git -C "$FOUND_PATH" rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
|
125
|
-
fi
|
|
126
|
-
PORCELAIN=$(git -C "$FOUND_PATH" status --porcelain 2>/dev/null || true)
|
|
127
|
-
IS_CLEAN="true"
|
|
128
|
-
if [ -n "$PORCELAIN" ]; then
|
|
129
|
-
IS_CLEAN="false"
|
|
130
|
-
fi
|
|
131
|
-
FOLDER_NAME=$(basename "$FOUND_PATH")
|
|
132
|
-
|
|
133
|
-
echo "STATUS=ALREADY_CLONED"
|
|
134
|
-
echo "LOCAL_PATH=$FOUND_PATH"
|
|
135
|
-
echo "LOCAL_FOLDER_NAME=$FOLDER_NAME"
|
|
136
|
-
echo "CANONICAL_SLUG=$TARGET_NORM"
|
|
137
|
-
echo "CURRENT_BRANCH=$BRANCH"
|
|
138
|
-
echo "IS_CLEAN=$IS_CLEAN"
|
|
139
|
-
exit 0
|
|
140
|
-
fi
|
|
141
|
-
|
|
142
|
-
if [ "$CHECK_ONLY" = true ]; then
|
|
143
|
-
echo "STATUS=NOT_CLONED"
|
|
144
|
-
echo "LOCAL_PATH="
|
|
145
|
-
echo "LOCAL_FOLDER_NAME="
|
|
146
|
-
echo "CANONICAL_SLUG=$TARGET_NORM"
|
|
147
|
-
exit 1
|
|
148
|
-
fi
|
|
149
|
-
|
|
150
|
-
# ------------------------------------------------------------------------------
|
|
151
|
-
# Fallback: Fresh Clone
|
|
152
|
-
# ------------------------------------------------------------------------------
|
|
153
|
-
if [ -z "$DEST_DIR" ]; then
|
|
154
|
-
if [ -d "$HOME/projects" ]; then
|
|
155
|
-
DEST_DIR="$HOME/projects/$REPO_NAME"
|
|
156
|
-
else
|
|
157
|
-
DEST_DIR="$(dirname "$CURRENT_DIR")/$REPO_NAME"
|
|
158
|
-
fi
|
|
159
|
-
fi
|
|
160
|
-
|
|
161
|
-
echo "📥 Repository '$REPO_URL' not found locally under any folder name. Cloning into '$DEST_DIR'..." >&2
|
|
162
|
-
mkdir -p "$(dirname "$DEST_DIR")"
|
|
163
|
-
git clone "$REPO_URL" "$DEST_DIR" >&2
|
|
164
|
-
|
|
165
|
-
FINAL_PATH="$(cd "$DEST_DIR" && pwd)"
|
|
166
|
-
BRANCH=$(git -C "$FINAL_PATH" branch --show-current 2>/dev/null || true)
|
|
167
|
-
if [ -z "$BRANCH" ]; then
|
|
168
|
-
BRANCH=$(git -C "$FINAL_PATH" rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
|
169
|
-
fi
|
|
170
|
-
|
|
171
|
-
echo "STATUS=CLONED_FRESH"
|
|
172
|
-
echo "LOCAL_PATH=$FINAL_PATH"
|
|
173
|
-
echo "LOCAL_FOLDER_NAME=$(basename "$FINAL_PATH")"
|
|
174
|
-
echo "CANONICAL_SLUG=$TARGET_NORM"
|
|
175
|
-
echo "CURRENT_BRANCH=$BRANCH"
|
|
176
|
-
echo "IS_CLEAN=true"
|
|
177
|
-
exit 0
|