azcodr 1.0.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/.agents/skills/agentic-architect/SKILL.md +118 -0
- package/.agents/skills/agentic-architect/references/agents_md_template.md +59 -0
- package/.agents/skills/agentic-architect/references/refinement_workflow.md +32 -0
- package/.agents/skills/agentic-architect/references/skill_architecture_inquiry.md +63 -0
- package/.agents/skills/agentic-architect/references/skill_template.md +55 -0
- package/.agents/skills/agentic-architect/scripts/validate_agentic_configs.sh +163 -0
- package/.agents/skills/clean-code-refactor/SKILL.md +91 -0
- package/.agents/skills/clean-code-refactor/references/clean_code_smells.md +27 -0
- package/.agents/skills/clean-code-refactor/references/design_patterns_ts.md +65 -0
- package/.agents/skills/compliance-audit/SKILL.md +120 -0
- package/.agents/skills/compliance-audit/references/owasp_top10_controls.md +16 -0
- package/.agents/skills/compliance-audit/references/soc2_iso_controls.md +28 -0
- package/.agents/skills/lets-build/SKILL.md +164 -0
- package/.agents/skills/lets-build/references/architecture_interview_matrix.md +188 -0
- package/.agents/skills/lets-build/references/hexagonal_bootstrap_scaffolds.md +113 -0
- package/.agents/skills/lets-build/references/project_readme_template.md +79 -0
- package/.agents/skills/lets-build/scripts/bootstrap_workspace.sh +68 -0
- package/.agents/skills/merge-ai/SKILL.md +90 -0
- package/.agents/skills/merge-ai/scripts/audit_divergence.sh +108 -0
- package/.agents/skills/merge-ai/scripts/resolve_repo.sh +177 -0
- package/.agents/skills/product-analyst/SKILL.md +143 -0
- package/.agents/skills/product-analyst/references/backlog_ordering_techniques.md +107 -0
- package/.agents/skills/product-analyst/references/gherkin_patterns.md +46 -0
- package/.agents/skills/product-analyst/references/invest_checklist.md +38 -0
- package/.agents/skills/product-analyst/references/okr_alignment_guide.md +76 -0
- package/.agents/skills/product-analyst/references/smart_tasks.md +59 -0
- package/.agents/skills/relentless-questioner/SKILL.md +120 -0
- package/.agents/skills/relentless-questioner/references/adaptive_question_trees.md +84 -0
- package/.gitignore +20 -0
- package/AGENTS.md +119 -0
- package/LICENSE +21 -0
- package/README.md +184 -0
- package/bin/azcodr.js +151 -0
- package/docs/knowledge/dos_and_donts.md +540 -0
- package/docs/knowledge/issue_log.md +25 -0
- package/docs/knowledge/knowledge_graph.md +188 -0
- package/docs/knowledge/lessons_learned.md +107 -0
- package/docs/knowledge/ubiquitous_language.md +23 -0
- package/docs/rules/accessibility.md +31 -0
- package/docs/rules/advanced_api_patterns.md +104 -0
- package/docs/rules/agentic_configuration.md +168 -0
- package/docs/rules/api_versioning.md +128 -0
- package/docs/rules/application_security.md +23 -0
- package/docs/rules/architecture_decision_records.md +42 -0
- package/docs/rules/authentication.md +76 -0
- package/docs/rules/authorization.md +75 -0
- package/docs/rules/caching.md +52 -0
- package/docs/rules/clean_code.md +25 -0
- package/docs/rules/cloud_native.md +43 -0
- package/docs/rules/compliance.md +25 -0
- package/docs/rules/container_infrastructure.md +32 -0
- package/docs/rules/continuous_deployment.md +24 -0
- package/docs/rules/continuous_integration.md +20 -0
- package/docs/rules/continuous_learning.md +29 -0
- package/docs/rules/database_integrity.md +88 -0
- package/docs/rules/database_migrations.md +41 -0
- package/docs/rules/database_operations.md +27 -0
- package/docs/rules/database_performance.md +44 -0
- package/docs/rules/database_transactions.md +81 -0
- package/docs/rules/design_patterns.md +40 -0
- package/docs/rules/devsecops.md +33 -0
- package/docs/rules/domain_driven_design.md +84 -0
- package/docs/rules/domain_expertise.md +42 -0
- package/docs/rules/error_handling.md +39 -0
- package/docs/rules/feature_flags.md +42 -0
- package/docs/rules/gof_design_patterns_reference.md +70 -0
- package/docs/rules/multitenancy_isolation.md +86 -0
- package/docs/rules/product_ownership.md +150 -0
- package/docs/rules/project_management.md +66 -0
- package/docs/rules/react.md +88 -0
- package/docs/rules/relentless_questioning.md +48 -0
- package/docs/rules/requirements_engineering.md +113 -0
- package/docs/rules/rest_api_conventions.md +62 -0
- package/docs/rules/server_driven_ui.md +71 -0
- package/docs/rules/tenant_dynamic_schemas.md +88 -0
- package/docs/rules/tenant_pluggable_logic.md +59 -0
- package/docs/rules/test_driven_development.md +106 -0
- package/docs/rules/test_isolation.md +26 -0
- package/docs/rules/transactional_email.md +20 -0
- package/docs/rules/typescript.md +55 -0
- package/docs/rules/ui_navigation.md +20 -0
- package/docs/rules/ui_ux_architecture.md +168 -0
- package/docs/rules/upstream_synchronization.md +66 -0
- package/docs/rules/workflow_state_machines.md +118 -0
- package/docs/rules/workspace_isolation.md +25 -0
- package/lib/index.js +5 -0
- package/lib/scaffold.js +177 -0
- package/memory.md +262 -0
- package/package.json +49 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Upstream Baseline Synchronization & AI Knowledge Merging
|
|
2
|
+
|
|
3
|
+
> **Core Mandate:** Upstream template/baseline workspaces (`azcodr`) must remain strictly untouched until the user explicitly requests merging. When merging via `/merge-ai`, strictly filter out all domain-specific entities, stacks, and models, keeping the baseline 100% generic.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. The Baseline-Project Decoupling Principle
|
|
8
|
+
|
|
9
|
+
Workspaces operate under a strict unidirectional and on-demand bidirectional flow:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
[Upstream Generic Baseline: azcodr]
|
|
13
|
+
│
|
|
14
|
+
▼ (One-time fork / clone at project inception)
|
|
15
|
+
[Derived Project Workspace: my-app / others]
|
|
16
|
+
│
|
|
17
|
+
│ (Accumulates project code, specificities, and institutional lessons)
|
|
18
|
+
│
|
|
19
|
+
▼ (ONLY when user explicitly triggers /merge-ai)
|
|
20
|
+
[Distillation & Filter: Purge Domain Specificities, Colocate DOs/DONTs]
|
|
21
|
+
│
|
|
22
|
+
▼
|
|
23
|
+
[Clean Merge into Upstream Baseline: azcodr]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **Pristine Upstream Mandate:** Never edit, commit, or push changes to an upstream baseline repository (`azcodr`) during routine project development, feature implementation, or bug fixes.
|
|
27
|
+
- **Explicit Trigger Requirement:** Synchronization into the baseline template may occur **only and exclusively** when the user explicitly issues the `/merge-ai` slash command or direct merge directive.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 2. Zero-Contamination Invariant (Generic vs. Specific)
|
|
32
|
+
|
|
33
|
+
When merging knowledge, rules, or skills back to the baseline, enforce strict domain filtering:
|
|
34
|
+
|
|
35
|
+
| Element Category | Keep in Specific Project Workspace | Allow in Generic Baseline (`azcodr`) |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| **Domain Entities** | Concrete business models (`Order`, `Customer`, `Invoice`, `Account`, etc.) | Abstract archetypes (`Entity`, `Aggregate`, `ValueObject`, `Resource`) |
|
|
38
|
+
| **Tech Stack / Adapters** | Concrete choices (Prisma, SQLite dev, PostgreSQL prod, Vite React) | Hexagonal Ports, abstract repository contracts, polyglot adapter guidance |
|
|
39
|
+
| **Architectural Rules** | Specific entity validation, specific route paths | Universal invariants (5-Phase Agile Lifecycle, SemVer trigger matrix, FK dropdowns) |
|
|
40
|
+
| **ADRs** | Stack decisions (`ADR-006: Target Tech Stack for Project`) | Generic architecture patterns (`ADR-007` to `ADR-010`) |
|
|
41
|
+
| **Test Suites** | Concrete domain tests (`order_domain.test.ts`, domain-specific suites) | Boundary smoke test pattern (`scripts/smoke_test.sh`), 100% coverage gate |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 3. Direct Rule Colocation Protocol
|
|
46
|
+
|
|
47
|
+
To prevent token bloat and documentation rot:
|
|
48
|
+
1. **Never Duplicate in a Consolidated List:** Never dump merged rules into a monolithic `dos_and_donts.md`.
|
|
49
|
+
2. **Colocate at Source:** Embed DO's and DONT's directly into the relevant atomic rule (`docs/rules/<domain>.md`) and skill (`.agents/skills/<skill>/SKILL.md`).
|
|
50
|
+
3. **Index-Only Directory:** Maintain `docs/knowledge/dos_and_donts.md` strictly as a clean reference table pointing to atomic rules.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 4. Invariants, DO's & DONT's
|
|
55
|
+
|
|
56
|
+
### DO's:
|
|
57
|
+
- **DO:** Leave the upstream baseline repository (`azcodr`) completely alone during regular development.
|
|
58
|
+
- **DO:** Require an explicit `/merge-ai` command before proposing or executing any upstream synchronization.
|
|
59
|
+
- **DO:** Distill all lessons and post-mortems into generic, domain-agnostic language before merging.
|
|
60
|
+
- **DO:** Colocate DOs and DONTs directly inside the relevant atomic rules and skills.
|
|
61
|
+
- **DO:** Run `validate_agentic_configs.sh` on the upstream baseline before and after any merge.
|
|
62
|
+
|
|
63
|
+
### DONT's:
|
|
64
|
+
- **DONT:** Never touch or edit the upstream baseline template automatically without explicit user command.
|
|
65
|
+
- **DONT:** Never contaminate the baseline template with project-specific domain models, entity names, or framework setups.
|
|
66
|
+
- **DONT:** Never overwrite upstream baseline files with raw project copies; merge generic concepts surgically.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Workflow Engines, State Machines & State Configurability
|
|
2
|
+
|
|
3
|
+
> **Core Mandate:** Separate non-negotiable core domain invariants (Aggregate Root FSM) from tenant-configurable operational workflows (Metadata-Driven State Machines / Orchestration Engines).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. The Fallacy of Universal Configurability
|
|
8
|
+
|
|
9
|
+
A common architectural anti-pattern is the **"Universal Workflow Fallacy"** (a variant of the *Inner Platform Effect*), which presumes that *every* status and state transition in a system should be dynamically configurable by end-users or tenants.
|
|
10
|
+
|
|
11
|
+
### The Architectural Invariant
|
|
12
|
+
1. **Core Invariant States (Hard FSM / In-Aggregate)**:
|
|
13
|
+
- Fundamental lifecycle states governed by business integrity, accounting invariants, or legal rules.
|
|
14
|
+
- Enforced **strictly within the Aggregate Root** in compiled code.
|
|
15
|
+
- Cannot be bypassed or arbitrarily restructured by tenant configuration.
|
|
16
|
+
- *Examples*:
|
|
17
|
+
- A `Payment` or `Transaction` with status `SETTLED` cannot transition back to `PENDING` without a compensating `REFUND` or reversal ledger entry.
|
|
18
|
+
- An `Order` cannot become `FULFILLED` without valid payment authorization and inventory deduction.
|
|
19
|
+
2. **Operational / Business Process Stages (Soft FSM / Configurable Orchestration)**:
|
|
20
|
+
- Tenant-specific pipeline stages, review checklists, approval tiers, and sub-statuses.
|
|
21
|
+
- Managed via **Declarative State Transition Matrices**, **Workflow Engines** (Temporal / Camunda BPMN), or **CEL (Common Expression Language)** transition guards.
|
|
22
|
+
- *Examples*:
|
|
23
|
+
- An application/lead review pipeline: Tenant A uses `[NEW -> REVIEW -> ACCEPTED]`; Tenant B uses `[NEW -> VETTING -> INTERVIEW -> APPROVAL -> ACCEPTED]`.
|
|
24
|
+
- A support/ticket resolution lifecycle.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. State Machine Architectural Patterns
|
|
29
|
+
|
|
30
|
+
### Pattern A: In-Aggregate State Machine (Hard Invariants)
|
|
31
|
+
Model states as **Discriminated Unions** or the GoF **State Pattern** encapsulated inside the domain entity. Public mutations must be explicit domain actions:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// Correct: Explicit domain command asserting state invariant
|
|
35
|
+
export class OrderAggregate {
|
|
36
|
+
private constructor(private state: OrderState) {}
|
|
37
|
+
|
|
38
|
+
fulfill(actorId: string): Result<void, DomainError> {
|
|
39
|
+
if (this.state.status !== 'PAID') {
|
|
40
|
+
return err(new DomainError(`Cannot fulfill order in status: ${this.state.status}`));
|
|
41
|
+
}
|
|
42
|
+
this.state.status = 'FULFILLED';
|
|
43
|
+
this.state.updatedAt = new Date();
|
|
44
|
+
this.state.updatedBy = actorId;
|
|
45
|
+
return ok(undefined);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Pattern B: Declarative State Transition Matrix (Configurable FSM)
|
|
51
|
+
For tenant-configurable operational stages, store transitions as declarative metadata:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"workflow": "resource_review_pipeline",
|
|
56
|
+
"tenantId": "org_123",
|
|
57
|
+
"initialState": "SUBMITTED",
|
|
58
|
+
"transitions": [
|
|
59
|
+
{
|
|
60
|
+
"from": "SUBMITTED",
|
|
61
|
+
"to": "UNDER_REVIEW",
|
|
62
|
+
"event": "START_REVIEW",
|
|
63
|
+
"allowedRoles": ["MANAGER", "REVIEWER"],
|
|
64
|
+
"guard": "resource.score >= 60"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"from": "UNDER_REVIEW",
|
|
68
|
+
"to": "APPROVED",
|
|
69
|
+
"event": "APPROVE",
|
|
70
|
+
"allowedRoles": ["ADMIN"],
|
|
71
|
+
"guard": "resource.verified == true"
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Pattern C: Durable Distributed Orchestration (Temporal / BPMN)
|
|
78
|
+
When a state transition requires coordination across multiple aggregates or asynchronous third parties (e.g. external payment gateway, background verification API, webhook delivery):
|
|
79
|
+
- Use a **Durable Workflow Engine** (Temporal or Camunda BPMN 2.0).
|
|
80
|
+
- The workflow coordinates activities by sending commands to Aggregate Roots and awaiting Domain Events.
|
|
81
|
+
- **Invariant**: The workflow engine never mutates aggregate state directly; it issues domain commands.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 3. Mandatory State Transition Audit Trail
|
|
86
|
+
|
|
87
|
+
Every state change across any entity or workflow MUST be immutably recorded in a transition log:
|
|
88
|
+
|
|
89
|
+
| Field | Type | Description |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `transitionId` | String (UUIDv7) | Unique identifier of the transition record. |
|
|
92
|
+
| `entityType` | String | Name of the entity (`Order`, `Application`, `Invoice`). |
|
|
93
|
+
| `entityId` | String | Target entity identifier. |
|
|
94
|
+
| `fromState` | String | Pre-transition state value. |
|
|
95
|
+
| `toState` | String | Post-transition state value. |
|
|
96
|
+
| `event` | String | Domain event or action triggering transition. |
|
|
97
|
+
| `actorId` | String | User ID or `SYSTEM` triggering the change. |
|
|
98
|
+
| `reason` | String? | Optional justification or audit comment. |
|
|
99
|
+
| `metadata` | JSON? | Snapshot of transition context or rule evaluation. |
|
|
100
|
+
| `createdAt` | DateTime | Immutable timestamp of transition. |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 4. Invariants (DO's & DONT's)
|
|
105
|
+
|
|
106
|
+
### DO
|
|
107
|
+
- **DO** enforce core business invariants inside Aggregate Roots using strongly-typed state transitions.
|
|
108
|
+
- **DO** decouple core domain state from operational display stages or tenant-specific sub-statuses.
|
|
109
|
+
- **DO** use non-Turing complete expression languages (CEL) to evaluate dynamic transition guards.
|
|
110
|
+
- **DO** maintain an immutable transition history table for all status alterations.
|
|
111
|
+
- **DO** validate state transition graphs at creation time to prevent dead-end or unreachable states.
|
|
112
|
+
|
|
113
|
+
### DONT
|
|
114
|
+
- **DONT** make financial or legal integrity states (e.g., `SETTLED`, `CANCELLED`, `REFUNDED`) freely rewritable by tenant configuration.
|
|
115
|
+
- **DONT** expose generic status setters (`entity.setStatus(newStatus)`) on domain models.
|
|
116
|
+
- **DONT** execute untrusted scripts or dynamic strings in the host runtime for workflow evaluations.
|
|
117
|
+
- **DONT** allow a workflow orchestrator to bypass aggregate invariants by directly updating database columns.
|
|
118
|
+
- **DONT** delete historical state transitions; status audit logs must be append-only.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Workspace Isolation & Zero Global Context Interference
|
|
2
|
+
|
|
3
|
+
> **Core Mandate:** Enforce strict workspace containment within the workspace root (`./`), strictly prohibiting any leakage, interference, or unverified assumptions from global configurations, external directories, or sibling projects.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Principle of Workspace Sovereignty
|
|
8
|
+
|
|
9
|
+
- **Ground Truth Boundary**: Only files, dependencies, configuration files (`package.json`, `tsconfig.json`, `docker-compose.yml`), and verified command executions within the local workspace (`./`) constitute project truth.
|
|
10
|
+
- **Zero Global Contamination**: Never import, execute, or assume tools, environment variables, or conventions from global system directories (e.g. `~/.config`, `/tmp`, `~/.gemini/antigravity-cli`, or parent directories) unless explicitly defined within local workspace configuration.
|
|
11
|
+
- **Sibling Project Isolation**: Strictly ignore all external or legacy projects. Do not read from or write to directories outside the local repository (`./`).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Dependency & Tooling Isolation
|
|
16
|
+
|
|
17
|
+
- **Local Package Manager**: Standardize strictly on local workspace dependencies managed via `npm` within this workspace. Never rely on global npm packages (`npm install -g`).
|
|
18
|
+
- **Container Network Containment**: All Docker containers and bridge networks must be named and scoped specifically to this project (e.g. `azcodr_network`, `azcodr_postgres`) to prevent port collisions or cross-project data leakage.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 3. Subagent & Execution Context Sandboxing
|
|
23
|
+
|
|
24
|
+
- When spawning subagents or executing commands, ensure the working directory (`Cwd`) is anchored strictly to the workspace root (`./`).
|
|
25
|
+
- Subagents must never carry over assumptions from other workspaces or global memory pools.
|
package/lib/index.js
ADDED
package/lib/scaffold.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { execSync } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
const TEMPLATE_ITEMS = [
|
|
8
|
+
'AGENTS.md',
|
|
9
|
+
'memory.md',
|
|
10
|
+
'README.md',
|
|
11
|
+
'docs',
|
|
12
|
+
'.agents',
|
|
13
|
+
'.gitignore'
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns the root path to the azcodr template files.
|
|
18
|
+
*/
|
|
19
|
+
function getTemplateDir() {
|
|
20
|
+
return path.resolve(__dirname, '..');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Validates the target directory to ensure it is suitable for scaffolding.
|
|
25
|
+
*/
|
|
26
|
+
function validateTarget(targetDir, options = {}) {
|
|
27
|
+
const { templateDir = getTemplateDir(), force = false } = options;
|
|
28
|
+
const resolvedTarget = path.resolve(targetDir);
|
|
29
|
+
const resolvedTemplate = path.resolve(templateDir);
|
|
30
|
+
|
|
31
|
+
if (resolvedTarget === resolvedTemplate) {
|
|
32
|
+
throw new Error(`Cannot scaffold into the azcodr template directory itself: ${resolvedTarget}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!fs.existsSync(resolvedTarget)) {
|
|
36
|
+
fs.mkdirSync(resolvedTarget, { recursive: true });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const entries = fs.readdirSync(resolvedTarget);
|
|
41
|
+
if (entries.length > 0 && !force) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Target directory is not empty (${entries.length} items found: ${resolvedTarget}). ` +
|
|
44
|
+
`Use --force to overwrite existing files.`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Safely creates or updates a symbolic link, falling back to a file copy if symlinks are unsupported.
|
|
51
|
+
*/
|
|
52
|
+
function ensureSymlink(targetDir, linkName, targetFileName) {
|
|
53
|
+
const linkPath = path.join(targetDir, linkName);
|
|
54
|
+
try {
|
|
55
|
+
const stat = fs.lstatSync(linkPath);
|
|
56
|
+
if (stat) {
|
|
57
|
+
fs.rmSync(linkPath, { force: true });
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// Path does not exist, proceed
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
fs.symlinkSync(targetFileName, linkPath);
|
|
65
|
+
} catch {
|
|
66
|
+
// Fallback if environment (e.g., certain Windows configs) prevents symlink creation
|
|
67
|
+
const sourceFile = path.join(targetDir, targetFileName);
|
|
68
|
+
if (fs.existsSync(sourceFile)) {
|
|
69
|
+
fs.copyFileSync(sourceFile, linkPath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Ensures all bash scripts in skill directories have executable permissions (0o755).
|
|
76
|
+
*/
|
|
77
|
+
function makeScriptsExecutable(targetDir) {
|
|
78
|
+
const skillsDir = path.join(targetDir, '.agents', 'skills');
|
|
79
|
+
if (!fs.existsSync(skillsDir)) return;
|
|
80
|
+
|
|
81
|
+
const skills = fs.readdirSync(skillsDir);
|
|
82
|
+
for (const skill of skills) {
|
|
83
|
+
const scriptsDir = path.join(skillsDir, skill, 'scripts');
|
|
84
|
+
if (fs.existsSync(scriptsDir) && fs.statSync(scriptsDir).isDirectory()) {
|
|
85
|
+
const files = fs.readdirSync(scriptsDir);
|
|
86
|
+
for (const file of files) {
|
|
87
|
+
if (file.endsWith('.sh')) {
|
|
88
|
+
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
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Recursively copies template files into the target directory and sets up symlinks and permissions.
|
|
102
|
+
*/
|
|
103
|
+
function copyTemplate(targetDir, templateDir = getTemplateDir()) {
|
|
104
|
+
const resolvedTarget = path.resolve(targetDir);
|
|
105
|
+
const resolvedTemplate = path.resolve(templateDir);
|
|
106
|
+
|
|
107
|
+
if (!fs.existsSync(resolvedTarget)) {
|
|
108
|
+
fs.mkdirSync(resolvedTarget, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (const item of TEMPLATE_ITEMS) {
|
|
112
|
+
const srcPath = path.join(resolvedTemplate, item);
|
|
113
|
+
if (!fs.existsSync(srcPath)) continue;
|
|
114
|
+
|
|
115
|
+
const destPath = path.join(resolvedTarget, item);
|
|
116
|
+
fs.cpSync(srcPath, destPath, { recursive: true, force: true, dereference: false });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Ensure harness parity symlinks per AGENTS.md mandate
|
|
120
|
+
ensureSymlink(resolvedTarget, 'CLAUDE.md', 'AGENTS.md');
|
|
121
|
+
ensureSymlink(resolvedTarget, 'agents.md', 'AGENTS.md');
|
|
122
|
+
|
|
123
|
+
// Ensure scripts are executable
|
|
124
|
+
makeScriptsExecutable(resolvedTarget);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Initializes a git repository in the target directory if not already inside one.
|
|
129
|
+
*/
|
|
130
|
+
function initGit(targetDir, options = {}) {
|
|
131
|
+
const { noGit = false } = options;
|
|
132
|
+
if (noGit) return false;
|
|
133
|
+
|
|
134
|
+
const gitDir = path.join(targetDir, '.git');
|
|
135
|
+
if (fs.existsSync(gitDir)) return false;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
execSync('git init -q', { cwd: targetDir, stdio: 'ignore' });
|
|
139
|
+
return true;
|
|
140
|
+
} catch {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* High-level orchestration function to scaffold the azcodr workspace into targetDir.
|
|
147
|
+
*/
|
|
148
|
+
function scaffold(options = {}) {
|
|
149
|
+
const {
|
|
150
|
+
targetDir = process.cwd(),
|
|
151
|
+
force = false,
|
|
152
|
+
noGit = false,
|
|
153
|
+
templateDir = getTemplateDir()
|
|
154
|
+
} = options;
|
|
155
|
+
|
|
156
|
+
const resolvedTarget = path.resolve(targetDir);
|
|
157
|
+
validateTarget(resolvedTarget, { templateDir, force });
|
|
158
|
+
copyTemplate(resolvedTarget, templateDir);
|
|
159
|
+
const gitInitialized = initGit(resolvedTarget, { noGit });
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
targetDir: resolvedTarget,
|
|
164
|
+
gitInitialized
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = {
|
|
169
|
+
scaffold,
|
|
170
|
+
validateTarget,
|
|
171
|
+
copyTemplate,
|
|
172
|
+
ensureSymlink,
|
|
173
|
+
makeScriptsExecutable,
|
|
174
|
+
initGit,
|
|
175
|
+
getTemplateDir,
|
|
176
|
+
TEMPLATE_ITEMS
|
|
177
|
+
};
|