ai-development-framework 0.1.0 → 0.1.2

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/cli/update.js CHANGED
@@ -1,58 +1,123 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { execFileSync } = require('child_process');
4
+ const readline = require('readline');
5
+ const { PROTECTED_FILES, PROTECTED_DIRS, CUSTOMIZABLE_FILES, toProjectRelative } = require('./protected-files');
4
6
 
5
7
  const REPO = 'cristian-robert/AIDevelopmentFramework';
6
8
  const BRANCH = 'main';
7
9
  const TARBALL_URL = 'https://github.com/' + REPO + '/archive/refs/heads/' + BRANCH + '.tar.gz';
8
10
 
9
- // Files that are project-specific and should NOT be overwritten
10
- var PROTECTED_FILES = [
11
- '.claude/agents/architect-agent/index.md',
12
- '.claude/agents/architect-agent/shared/patterns.md',
13
- '.claude/agents/architect-agent/decisions/log.md',
14
- '.claude/agents/tester-agent/test-patterns.md',
15
- '.claude/agents/tester-agent/auth-state.md',
16
- '.claude/agents/mobile-tester-agent/screen-patterns.md',
17
- '.claude/references/code-patterns.md',
18
- '.claude/settings.local.json',
19
- ];
20
-
21
- // Directories with project-specific content that should NOT be overwritten
22
- var PROTECTED_DIRS = [
23
- '.claude/agents/architect-agent/modules',
24
- '.claude/agents/architect-agent/frontend',
25
- ];
26
-
27
- function copyDirRecursive(src, dest, protectedFiles, protectedDirs) {
11
+ const rl = readline.createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout,
14
+ });
15
+
16
+ function ask(question) {
17
+ return new Promise(function (resolve) {
18
+ rl.question(question, resolve);
19
+ });
20
+ }
21
+
22
+ function isTemplateContent(filePath) {
23
+ try {
24
+ var content = fs.readFileSync(filePath, 'utf-8');
25
+ if (content.includes('> Populated by /create-rules')) return true;
26
+ if (content.includes('> Populated when /create-rules')) return true;
27
+ if (content.includes('> No decisions recorded yet')) return true;
28
+ if (content.includes('Run `/create-rules` to populate')) return true;
29
+ if (content.includes('> This section is populated as the project grows')) return true;
30
+ return false;
31
+ } catch (e) {
32
+ return false;
33
+ }
34
+ }
35
+
36
+ function copyDirWithProtection(src, dest, projectRoot, customizedAction) {
28
37
  if (!fs.existsSync(dest)) {
29
38
  fs.mkdirSync(dest, { recursive: true });
30
39
  }
31
40
  var entries = fs.readdirSync(src, { withFileTypes: true });
41
+ var stats = { updated: 0, skipped: 0, backedUp: 0 };
32
42
  for (var i = 0; i < entries.length; i++) {
33
43
  var entry = entries[i];
34
44
  var srcPath = path.join(src, entry.name);
35
45
  var destPath = path.join(dest, entry.name);
36
- var relativePath = path.relative(process.cwd(), destPath);
46
+ var projectRelPath = toProjectRelative(destPath, projectRoot);
37
47
 
38
48
  if (entry.isDirectory()) {
39
- // Skip protected directories entirely
40
- if (protectedDirs.some(function (d) { return relativePath.startsWith(d); })) {
49
+ var isProtectedDir = PROTECTED_DIRS.some(function (d) {
50
+ return projectRelPath === d || projectRelPath.startsWith(d + '/');
51
+ });
52
+ if (isProtectedDir && fs.existsSync(destPath)) {
53
+ console.log(' Skipped (project-specific): ' + projectRelPath + '/');
54
+ try {
55
+ var dirFiles = fs.readdirSync(destPath, { recursive: true });
56
+ stats.skipped += dirFiles.length || 1;
57
+ } catch (e) {
58
+ stats.skipped++;
59
+ }
41
60
  continue;
42
61
  }
43
- copyDirRecursive(srcPath, destPath, protectedFiles, protectedDirs);
62
+ var sub = copyDirWithProtection(srcPath, destPath, projectRoot, customizedAction);
63
+ stats.updated += sub.updated;
64
+ stats.skipped += sub.skipped;
65
+ stats.backedUp += sub.backedUp;
44
66
  } else {
45
- // Skip protected files
46
- if (protectedFiles.indexOf(relativePath) !== -1) {
47
- console.log(' Skipped (project-specific): ' + relativePath);
67
+ if (!fs.existsSync(destPath)) {
68
+ // New file always install
69
+ var destDir = path.dirname(destPath);
70
+ if (!fs.existsSync(destDir)) {
71
+ fs.mkdirSync(destDir, { recursive: true });
72
+ }
73
+ fs.copyFileSync(srcPath, destPath);
74
+ stats.updated++;
48
75
  continue;
49
76
  }
77
+
78
+ // Protected file — skip if it has real content, update if still template
79
+ if (PROTECTED_FILES.indexOf(projectRelPath) !== -1) {
80
+ if (!isTemplateContent(destPath)) {
81
+ console.log(' Skipped (project-specific): ' + projectRelPath);
82
+ stats.skipped++;
83
+ } else {
84
+ fs.copyFileSync(srcPath, destPath);
85
+ stats.updated++;
86
+ }
87
+ continue;
88
+ }
89
+
90
+ // Customizable file — apply chosen action
91
+ if (CUSTOMIZABLE_FILES.indexOf(projectRelPath) !== -1) {
92
+ var srcContent = fs.readFileSync(srcPath, 'utf-8');
93
+ var destContent = fs.readFileSync(destPath, 'utf-8');
94
+ if (srcContent !== destContent) {
95
+ if (customizedAction === 'keep') {
96
+ console.log(' Skipped (customized): ' + projectRelPath);
97
+ stats.skipped++;
98
+ continue;
99
+ } else if (customizedAction === 'backup') {
100
+ var timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
101
+ var backupPath = destPath + '.' + timestamp + '.backup';
102
+ fs.copyFileSync(destPath, backupPath);
103
+ console.log(' Backed up: ' + projectRelPath);
104
+ fs.copyFileSync(srcPath, destPath);
105
+ stats.backedUp++;
106
+ stats.updated++;
107
+ continue;
108
+ }
109
+ // 'overwrite' falls through
110
+ }
111
+ }
112
+
50
113
  fs.copyFileSync(srcPath, destPath);
114
+ stats.updated++;
51
115
  }
52
116
  }
117
+ return stats;
53
118
  }
54
119
 
55
- function main() {
120
+ async function main() {
56
121
  console.log('');
57
122
  console.log(' AIDevelopmentFramework — Update');
58
123
  console.log('');
@@ -62,6 +127,7 @@ function main() {
62
127
  process.exit(1);
63
128
  }
64
129
 
130
+ var projectRoot = process.cwd();
65
131
  var tmpDir = path.join(require('os').tmpdir(), 'ai-framework-update-' + Date.now());
66
132
  fs.mkdirSync(tmpDir, { recursive: true });
67
133
 
@@ -71,40 +137,63 @@ function main() {
71
137
  execFileSync('curl', ['-sL', TARBALL_URL, '-o', path.join(tmpDir, 'framework.tar.gz')]);
72
138
  execFileSync('tar', ['-xzf', path.join(tmpDir, 'framework.tar.gz'), '-C', tmpDir, '--strip-components=1']);
73
139
 
140
+ // Ask about customized files
141
+ var customizedAction = 'keep';
142
+ console.log('');
143
+ var choice = await ask(
144
+ ' How should customized rules/hooks be handled?\n' +
145
+ ' 1. Keep mine — preserve your customizations (default)\n' +
146
+ ' 2. Use framework — overwrite with latest framework versions\n' +
147
+ ' 3. Backup + update — save yours as .backup, install new versions\n' +
148
+ ' Choice (1/2/3): '
149
+ );
150
+
151
+ if (choice === '2') customizedAction = 'overwrite';
152
+ else if (choice === '3') customizedAction = 'backup';
153
+
74
154
  var sourceClaudeDir = path.join(tmpDir, '.claude');
75
- var targetClaudeDir = path.join(process.cwd(), '.claude');
155
+ var targetClaudeDir = path.join(projectRoot, '.claude');
76
156
 
77
157
  if (fs.existsSync(sourceClaudeDir)) {
78
- console.log('Updating .claude/ (preserving project-specific files)...');
79
- copyDirRecursive(sourceClaudeDir, targetClaudeDir, PROTECTED_FILES, PROTECTED_DIRS);
80
- }
158
+ console.log('');
159
+ console.log('Updating .claude/ ...');
160
+ console.log('');
161
+ var stats = copyDirWithProtection(sourceClaudeDir, targetClaudeDir, projectRoot, customizedAction);
81
162
 
82
- // Update docs (but not docs/plans/ which contains project plans)
83
- var sourceDocsDir = path.join(tmpDir, 'docs');
84
- var targetDocsDir = path.join(process.cwd(), 'docs');
85
- if (fs.existsSync(sourceDocsDir)) {
86
- console.log('Updating docs/...');
87
- var docEntries = fs.readdirSync(sourceDocsDir, { withFileTypes: true });
88
- for (var i = 0; i < docEntries.length; i++) {
89
- var entry = docEntries[i];
90
- if (entry.isFile()) {
91
- fs.copyFileSync(
92
- path.join(sourceDocsDir, entry.name),
93
- path.join(targetDocsDir, entry.name)
94
- );
163
+ // Update docs (but not docs/plans/ or docs/superpowers/)
164
+ var sourceDocsDir = path.join(tmpDir, 'docs');
165
+ var targetDocsDir = path.join(projectRoot, 'docs');
166
+ if (fs.existsSync(sourceDocsDir)) {
167
+ console.log('');
168
+ console.log('Updating docs/...');
169
+ if (!fs.existsSync(targetDocsDir)) {
170
+ fs.mkdirSync(targetDocsDir, { recursive: true });
171
+ }
172
+ var docEntries = fs.readdirSync(sourceDocsDir, { withFileTypes: true });
173
+ for (var i = 0; i < docEntries.length; i++) {
174
+ var entry = docEntries[i];
175
+ if (entry.isFile()) {
176
+ fs.copyFileSync(
177
+ path.join(sourceDocsDir, entry.name),
178
+ path.join(targetDocsDir, entry.name)
179
+ );
180
+ stats.updated++;
181
+ }
95
182
  }
96
- // Skip docs/plans/ and docs/superpowers/ — project-specific
97
183
  }
98
- }
99
184
 
100
- console.log('');
101
- console.log('Update complete!');
102
- console.log('');
103
- console.log('Updated: commands, agent protocols, rules templates, hooks, skills, docs');
104
- console.log('Preserved: agent knowledge bases, test patterns, auth state, code patterns, settings, plans');
105
- console.log('');
106
- console.log('Run /setup to check if new plugins are required.');
107
- console.log('');
185
+ console.log('');
186
+ console.log('Update complete!');
187
+ console.log('');
188
+ console.log(' Updated: ' + stats.updated + ' files');
189
+ console.log(' Skipped: ' + stats.skipped + ' files (preserved your customizations)');
190
+ if (stats.backedUp > 0) {
191
+ console.log(' Backed up: ' + stats.backedUp + ' files (saved as .backup)');
192
+ }
193
+ console.log('');
194
+ console.log('Run /setup to check if new plugins are required.');
195
+ console.log('');
196
+ }
108
197
  } catch (err) {
109
198
  console.error('Update failed: ' + err.message);
110
199
  process.exit(1);
@@ -112,8 +201,9 @@ function main() {
112
201
  try {
113
202
  fs.rmSync(tmpDir, { recursive: true, force: true });
114
203
  } catch (e) {
115
- // ignore cleanup errors
204
+ // ignore
116
205
  }
206
+ rl.close();
117
207
  }
118
208
  }
119
209
 
@@ -26,6 +26,62 @@ Hooks are shell scripts in `.claude/hooks/`. Edit existing hooks or add new ones
26
26
 
27
27
  Each project gets its own `.claude/` folder. Customize CLAUDE.md, rules, and agent knowledge bases per project. The framework's commands stay the same.
28
28
 
29
+ ## Configuring the Knowledge Base
30
+
31
+ The framework includes an optional project knowledge base (Obsidian-compatible) that gives the agent persistent project understanding across sessions.
32
+
33
+ ### Enable
34
+
35
+ Add to your project's `CLAUDE.md`:
36
+
37
+ ```markdown
38
+ ## Knowledge Base
39
+
40
+ Path: .obsidian/
41
+ ```
42
+
43
+ ### Custom Path
44
+
45
+ Use any folder name:
46
+
47
+ ```markdown
48
+ ## Knowledge Base
49
+
50
+ Path: knowledge/
51
+ ```
52
+
53
+ **Note:** The framework's `.gitignore` only covers Obsidian config files under `.obsidian/`. If you use a custom path and open it as an Obsidian vault, add these entries to your `.gitignore` (replacing `knowledge/` with your path):
54
+
55
+ ```
56
+ knowledge/app.json
57
+ knowledge/appearance.json
58
+ knowledge/core-plugins.json
59
+ knowledge/core-plugins-migration.json
60
+ knowledge/workspace.json
61
+ knowledge/workspace-mobile.json
62
+ knowledge/hotkeys.json
63
+ knowledge/plugins/
64
+ knowledge/themes/
65
+ ```
66
+
67
+ ### Disable
68
+
69
+ Remove the `## Knowledge Base` section from CLAUDE.md. All knowledge operations are skipped — commands work exactly as before.
70
+
71
+ ### What It Does
72
+
73
+ Pipeline commands automatically read from and write to the knowledge base:
74
+ - `/start` creates the structure when starting a new project
75
+ - `/prime` loads relevant notes for context before work
76
+ - `/create-prd` seeds the knowledge base from the PRD
77
+ - `/plan-project` creates feature notes alongside GitHub issues
78
+ - `/execute` reads related feature notes before implementing
79
+ - `/ship` updates feature notes after completing work
80
+
81
+ ### Obsidian
82
+
83
+ If you have [Obsidian](https://obsidian.md/) installed, open your project folder as a vault. The `.obsidian/` directory makes it a valid vault. Notes are navigable, linkable, and searchable through Obsidian's UI. Obsidian is not required — the notes are plain markdown.
84
+
29
85
  ## Contributing
30
86
 
31
87
  1. Fork the repository
@@ -0,0 +1,209 @@
1
+ # Knowledge Base Integration Design
2
+
3
+ **Date:** 2026-04-04
4
+ **Status:** Approved
5
+
6
+ ## Problem
7
+
8
+ The agent starts each session with no project-level context beyond what it can read from code and git history. It doesn't know what features are planned, why decisions were made, or how features relate to each other. This leads to:
9
+
10
+ - Agent trying to implement entire projects in one shot instead of following the issue-based pipeline
11
+ - No persistent project understanding across sessions
12
+ - Brainstorming insights lost after the session ends
13
+ - No automatic check for related features/decisions before starting work
14
+
15
+ ## Solution
16
+
17
+ Add an optional, Obsidian-compatible knowledge base (`.obsidian/` by default) that pipeline commands read from and write to at natural checkpoints. The knowledge base complements the existing architect-agent (code-level knowledge) with project-level understanding.
18
+
19
+ ## Design
20
+
21
+ ### Knowledge Base Structure
22
+
23
+ Default path: `.obsidian/` (configurable via `Knowledge Base: <path>` in project CLAUDE.md).
24
+
25
+ ```
26
+ .obsidian/
27
+ ├── app.json # Obsidian config (gitignored)
28
+ ├── appearance.json # Obsidian config (gitignored)
29
+ ├── core-plugins.json # Obsidian config (gitignored)
30
+ ├── workspace.json # Obsidian config (gitignored)
31
+ ├── overview.md # Project vision, goals, tech stack, target users
32
+ ├── architecture/
33
+ │ └── system-design.md # High-level architecture, component diagram
34
+ ├── features/
35
+ │ ├── feature-name.md # One per feature area, links to GitHub issues
36
+ │ └── ...
37
+ ├── decisions/
38
+ │ └── NNN-title.md # ADR format: context, decision, consequences
39
+ ├── config/
40
+ │ └── integrations.md # Third-party services, env var names (never store actual secrets)
41
+ └── research/
42
+ └── ... # Brainstorming notes, tech comparisons
43
+ ```
44
+
45
+ ### Gitignore Rules
46
+
47
+ Obsidian config files are gitignored (machine-specific). Notes are committed.
48
+
49
+ ```
50
+ .obsidian/app.json
51
+ .obsidian/appearance.json
52
+ .obsidian/core-plugins.json
53
+ .obsidian/core-plugins-migration.json
54
+ .obsidian/workspace.json
55
+ .obsidian/hotkeys.json
56
+ .obsidian/plugins/
57
+ .obsidian/themes/
58
+ ```
59
+
60
+ ### Feature Note Template
61
+
62
+ ```markdown
63
+ # Feature: [Name]
64
+
65
+ ## Summary
66
+ [1-2 sentences: what this feature does and why]
67
+
68
+ ## GitHub Issues
69
+ - #N — [title] (status)
70
+ - #N — [title] (status)
71
+
72
+ ## Key Decisions
73
+ - [Decision and why]
74
+
75
+ ## Implementation Notes
76
+ [Updated after work is completed — endpoints created, components built, patterns used]
77
+ ```
78
+
79
+ ### Decision Record Template
80
+
81
+ ```markdown
82
+ # NNN: [Title]
83
+
84
+ **Date:** YYYY-MM-DD
85
+ **Status:** Accepted
86
+
87
+ ## Context
88
+ [What situation led to this decision]
89
+
90
+ ## Decision
91
+ [What we chose and why]
92
+
93
+ ## Consequences
94
+ [What this means for future work — both positive and negative]
95
+ ```
96
+
97
+ ## Command Integration
98
+
99
+ ### `/start` — New L0 Behavior
100
+
101
+ Detects empty project → routes to new flow:
102
+ 1. Brainstorm functionalities (interactive)
103
+ 2. Create `.obsidian/` structure with `overview.md`
104
+ 3. Create feature notes in `.obsidian/features/`
105
+ 4. Create GitHub issues linked to feature notes
106
+ 5. STOP — ask user which issue to work on
107
+
108
+ ### `/prime` — Smart Knowledge Loading
109
+
110
+ Add to existing context loading:
111
+ 1. Read `.obsidian/overview.md` (always)
112
+ 2. If working on a specific issue → read the linked feature note
113
+ 3. Scan other feature note filenames + summaries → pull in related ones
114
+ 4. Include knowledge context in session summary output
115
+
116
+ ### `/create-prd` — Knowledge Base Seeding
117
+
118
+ Add after saving PRD:
119
+ 1. Create `.obsidian/overview.md` extracted from PRD (vision, goals, tech stack, users)
120
+ 2. Create `.obsidian/architecture/system-design.md` from PRD's architecture section
121
+
122
+ ### `/plan-project` — Feature Notes Alongside Issues
123
+
124
+ Add after creating each GitHub issue:
125
+ 1. Create `.obsidian/features/<feature-name>.md` with the feature template
126
+ 2. Link the GitHub issue numbers in the note
127
+ 3. If architectural decisions were made during brainstorming, create `.obsidian/decisions/NNN-title.md`
128
+
129
+ ### `/ship` — Knowledge Update Checkpoint
130
+
131
+ Add before committing:
132
+ 1. Read the feature note for the issue being completed
133
+ 2. Update `## Implementation Notes` with what was built
134
+ 3. Update `## GitHub Issues` status if issue is being closed
135
+ 4. If a significant decision was made, create a decision record
136
+ 5. Commit knowledge updates alongside code
137
+
138
+ ### `/execute` — Knowledge-Aware Context
139
+
140
+ Add to mandatory file reading step:
141
+ 1. Check `.obsidian/` for the feature note linked to the current issue
142
+ 2. Read related feature notes (smart/targeted scan)
143
+ 3. Check `.obsidian/decisions/` for relevant past decisions
144
+
145
+ ## Read-Before-Work Flow (Smart/Targeted)
146
+
147
+ When the agent starts work on an issue:
148
+
149
+ 1. **Always read:** `overview.md` + directly linked feature note
150
+ 2. **Scan for related:** list `.obsidian/features/`, read first 5 lines of each, pull in notes with clear dependency/overlap
151
+ 3. **Check decisions:** scan `.obsidian/decisions/` titles, read relevant ones
152
+ 4. **Check codebase:** existing `/prime` behavior (code structure, git history, architect-agent)
153
+
154
+ ### Issue-to-Feature Linking
155
+
156
+ - Feature notes list issue numbers in `## GitHub Issues`
157
+ - Agent greps `.obsidian/features/*.md` for the current issue number
158
+ - Fallback: keyword matching between issue title and feature note filenames/summaries
159
+
160
+ ## Write-After-Work Flow (End of Issue)
161
+
162
+ Triggered by `/ship`:
163
+
164
+ ### Updated:
165
+ - **Feature note:** `## Implementation Notes`, `## GitHub Issues` status, `## Key Decisions`
166
+ - **Decision records:** only when a technology/approach was chosen over alternatives, a pattern was established, or something was intentionally excluded
167
+
168
+ ### Updated only when significant:
169
+ - **Overview:** only when new integration added or scope changed
170
+
171
+ ### Not updated:
172
+ - Bug fixes (L3) unless they reveal a design decision
173
+ - Unrelated feature notes
174
+ - No full rewrites — only append/update relevant sections
175
+
176
+ ## Configuration & Optionality
177
+
178
+ ### CLAUDE.md Configuration
179
+
180
+ ```markdown
181
+ ## Knowledge Base
182
+
183
+ Path: .obsidian/
184
+ ```
185
+
186
+ When path is set → commands read/write from it.
187
+ When absent → knowledge operations skipped entirely. Zero impact.
188
+
189
+ ### `/init-claude-md` Integration
190
+
191
+ During setup, ask:
192
+ 1. Yes, use `.obsidian/` (default)
193
+ 2. Yes, custom path
194
+ 3. No — skip knowledge base
195
+
196
+ ### Guard Behavior
197
+
198
+ Every command that touches the knowledge base:
199
+ 1. Read project CLAUDE.md → look for `Knowledge Base` path
200
+ 2. If not found → skip all knowledge operations
201
+ 3. If found → check folder exists
202
+ 4. If folder doesn't exist → create it with initial structure
203
+
204
+ ## Relationship to Existing Systems
205
+
206
+ - **architect-agent:** Keeps code-level knowledge (modules, endpoints, patterns). Knowledge base holds project-level understanding. Agent reads both.
207
+ - **docs/plans/:** Untouched. Superpowers skills write here. Knowledge base is additive.
208
+ - **docs/superpowers/plans/:** Untouched. Same reason.
209
+ - **Obsidian:** Optional. The `.obsidian/` folder works as plain markdown without Obsidian installed. Obsidian users get a navigable vault for free.