analyzthis_design 1.1.0 → 1.2.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/bin/cli.js +122 -36
- package/lib/install.js +1 -0
- package/lib/knowledge.js +250 -0
- package/package.json +1 -1
- package/skills/design-critic/SKILL.md +13 -0
- package/skills/knowledge-bank/SKILL.md +37 -0
- package/skills/ux-ideator/SKILL.md +13 -0
package/bin/cli.js
CHANGED
|
@@ -2,80 +2,97 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const os
|
|
6
|
-
const fs
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const fs = require('fs');
|
|
7
7
|
const { install, remove, SKILLS, TARGET_DIRS } = require('../lib/install');
|
|
8
|
+
const { connect, disconnect, sync, status } = require('../lib/knowledge');
|
|
8
9
|
|
|
9
10
|
const HELP = `
|
|
10
|
-
Analyzthis_Design — 7 AI design personas
|
|
11
|
+
Analyzthis_Design — 7 AI design personas with a personal knowledge bank
|
|
11
12
|
|
|
12
13
|
Usage:
|
|
13
14
|
npx analyzthis_design [command] [options]
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
install Copy all skills to the target AI tool's
|
|
16
|
+
── Skill commands ───────────────────────────────────────────
|
|
17
|
+
install Copy all skills to the target AI tool's directory (default)
|
|
17
18
|
remove Delete installed skills from the target AI tool's directory
|
|
18
19
|
list Show installed skills for a target
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
── Knowledge bank commands ──────────────────────────────────
|
|
22
|
+
connect Register a vault or knowledge folder as a source
|
|
23
|
+
sync Read all sources and build the knowledge-bank skill
|
|
24
|
+
disconnect Remove a source from the registry
|
|
25
|
+
status Show connected sources and last sync time
|
|
26
|
+
|
|
27
|
+
── Options ──────────────────────────────────────────────────
|
|
28
|
+
--target AI tool: cursor | claude | codex | all (default: cursor)
|
|
22
29
|
--force Overwrite existing skills on install
|
|
30
|
+
--vault Path to Obsidian vault or markdown folder (connect command)
|
|
31
|
+
--tags Comma-separated tags to filter by, e.g. design,brand,ux
|
|
32
|
+
--include Comma-separated sub-folder names to include, e.g. Design,Brand
|
|
23
33
|
--help Show this help message
|
|
24
34
|
|
|
25
|
-
Examples
|
|
26
|
-
npx analyzthis_design
|
|
27
|
-
npx analyzthis_design --target
|
|
28
|
-
|
|
29
|
-
npx analyzthis_design --
|
|
30
|
-
npx analyzthis_design
|
|
35
|
+
── Examples ─────────────────────────────────────────────────
|
|
36
|
+
npx analyzthis_design # install for Cursor
|
|
37
|
+
npx analyzthis_design --target all # install for all tools
|
|
38
|
+
|
|
39
|
+
npx analyzthis_design connect --vault ~/Documents/MyVault
|
|
40
|
+
npx analyzthis_design connect --vault ~/docs --tags design,brand,product
|
|
41
|
+
npx analyzthis_design connect --vault ~/vault --include Design,Research
|
|
42
|
+
npx analyzthis_design sync # sync to Cursor
|
|
43
|
+
npx analyzthis_design sync --target all # sync to all tools
|
|
44
|
+
npx analyzthis_design status # show sources
|
|
45
|
+
npx analyzthis_design disconnect --vault ~/Documents/MyVault
|
|
31
46
|
|
|
32
|
-
Install paths
|
|
47
|
+
── Install paths ────────────────────────────────────────────
|
|
33
48
|
Cursor → ~/.cursor/skills/
|
|
34
49
|
Claude → ~/.claude/commands/
|
|
35
50
|
Codex → ~/.codex/skills/
|
|
36
51
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Meera Business Agent (retention, ARR, GTM)
|
|
40
|
-
Priya Feasibility Agent (effort sizing, risks)
|
|
41
|
-
Zara Delight Agent (Peak-End, one moment)
|
|
42
|
-
Noor IA Architect (Concept A, minimalist)
|
|
43
|
-
Anuj Power-User Advocate (Concept B, dense)
|
|
44
|
-
Raj Arbitrator (stalemate only)
|
|
45
|
-
|
|
46
|
-
Orchestrating skills:
|
|
47
|
-
design-critic 4-persona critique → SHIP/REVISE/BLOCK
|
|
48
|
-
ux-ideator 6-phase ideation workflow
|
|
49
|
-
design-personas Session context template
|
|
52
|
+
── Knowledge bank config ────────────────────────────────────
|
|
53
|
+
Config → ~/.analyzthis_design/config.json
|
|
50
54
|
|
|
51
55
|
Docs: https://github.com/rishikeshjoshi/analyzthis_design
|
|
52
56
|
`;
|
|
53
57
|
|
|
58
|
+
// ─── Parse args ──────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
54
60
|
const [,, cmd, ...flags] = process.argv;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
|
|
62
|
+
function getFlag(name) {
|
|
63
|
+
// Supports both --flag=value and --flag value
|
|
64
|
+
const eq = flags.find(f => f.startsWith(`--${name}=`));
|
|
65
|
+
if (eq) return eq.split('=').slice(1).join('=');
|
|
66
|
+
const idx = flags.indexOf(`--${name}`);
|
|
67
|
+
if (idx !== -1 && flags[idx + 1] && !flags[idx + 1].startsWith('--')) return flags[idx + 1];
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const force = flags.includes('--force');
|
|
72
|
+
const targetVal = getFlag('target') || 'cursor';
|
|
73
|
+
const vaultVal = getFlag('vault');
|
|
74
|
+
const tagsVal = getFlag('tags');
|
|
75
|
+
const includeVal = getFlag('include');
|
|
76
|
+
|
|
77
|
+
// ─── Commands ────────────────────────────────────────────────────────────────
|
|
60
78
|
|
|
61
79
|
switch (cmd) {
|
|
62
80
|
case undefined:
|
|
63
81
|
case 'install':
|
|
64
|
-
install({ force, target });
|
|
82
|
+
install({ force, target: targetVal });
|
|
65
83
|
break;
|
|
66
84
|
|
|
67
85
|
case 'remove':
|
|
68
86
|
case 'uninstall':
|
|
69
|
-
remove({ target });
|
|
87
|
+
remove({ target: targetVal });
|
|
70
88
|
break;
|
|
71
89
|
|
|
72
90
|
case 'list': {
|
|
73
|
-
const targets =
|
|
91
|
+
const targets = targetVal === 'all' ? Object.keys(TARGET_DIRS) : [targetVal];
|
|
74
92
|
for (const t of targets) {
|
|
75
93
|
const dir = TARGET_DIRS[t];
|
|
76
94
|
console.log(`\nInstalled Analyzthis_Design skills [${t}] (${dir}):\n`);
|
|
77
95
|
for (const skill of SKILLS) {
|
|
78
|
-
// Check both directory and flat .md forms
|
|
79
96
|
const asDir = path.join(dir, skill);
|
|
80
97
|
const asFile = path.join(dir, `${skill}.md`);
|
|
81
98
|
const exists = fs.existsSync(asDir) || fs.existsSync(asFile);
|
|
@@ -86,6 +103,75 @@ switch (cmd) {
|
|
|
86
103
|
break;
|
|
87
104
|
}
|
|
88
105
|
|
|
106
|
+
// ── Knowledge bank ──────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
case 'connect': {
|
|
109
|
+
if (!vaultVal) {
|
|
110
|
+
console.error('\n ✗ --vault is required. Example: npx analyzthis_design connect --vault ~/Documents/MyVault\n');
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const tags = tagsVal ? tagsVal.split(',').map(t => t.trim()) : [];
|
|
115
|
+
const include = includeVal ? includeVal.split(',').map(t => t.trim()) : [];
|
|
116
|
+
const abs = connect({ vaultPath: vaultVal, tags, include });
|
|
117
|
+
console.log(`\n✅ Connected: ${abs}`);
|
|
118
|
+
if (tags.length) console.log(` Tags filter: ${tags.join(', ')}`);
|
|
119
|
+
if (include.length) console.log(` Folder filter: ${include.join(', ')}`);
|
|
120
|
+
console.log(`\n Run "npx analyzthis_design sync" to build the knowledge bank.\n`);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
case 'disconnect': {
|
|
129
|
+
if (!vaultVal) {
|
|
130
|
+
console.error('\n ✗ --vault is required. Example: npx analyzthis_design disconnect --vault ~/Documents/MyVault\n');
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
disconnect(vaultVal);
|
|
134
|
+
console.log(`\n🗑 Disconnected: ${path.resolve(vaultVal)}\n`);
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
case 'sync': {
|
|
139
|
+
const targets = targetVal === 'all' ? Object.keys(TARGET_DIRS) : [targetVal];
|
|
140
|
+
console.log('\n⏳ Syncing knowledge bank...\n');
|
|
141
|
+
try {
|
|
142
|
+
const result = sync({ targets });
|
|
143
|
+
if (result.message) {
|
|
144
|
+
console.log(` ⚠ ${result.message}\n`);
|
|
145
|
+
} else {
|
|
146
|
+
console.log(`✅ Synced ${result.synced} note(s) into the knowledge bank.`);
|
|
147
|
+
for (const t of result.copiedTo) console.log(` • ${t}`);
|
|
148
|
+
console.log(`\n💡 The knowledge bank is now active. All personas will read it first.\n`);
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
console.error(`\n ✗ Sync failed: ${err.message}\n`);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
case 'status': {
|
|
158
|
+
const cfg = status();
|
|
159
|
+
if (!cfg.sources || cfg.sources.length === 0) {
|
|
160
|
+
console.log('\n No knowledge sources connected.\n Run: npx analyzthis_design connect --vault /path/to/vault\n');
|
|
161
|
+
} else {
|
|
162
|
+
console.log(`\n📚 Knowledge bank sources (${cfg.sources.length}):\n`);
|
|
163
|
+
for (const s of cfg.sources) {
|
|
164
|
+
console.log(` • ${s.path}`);
|
|
165
|
+
if (s.tags.length) console.log(` Tags: ${s.tags.join(', ')}`);
|
|
166
|
+
if (s.include.length) console.log(` Folders: ${s.include.join(', ')}`);
|
|
167
|
+
console.log(` Added: ${s.addedAt}`);
|
|
168
|
+
}
|
|
169
|
+
if (cfg.lastSync) console.log(`\n Last sync: ${cfg.lastSync}`);
|
|
170
|
+
console.log('');
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
|
|
89
175
|
case '--help':
|
|
90
176
|
case 'help':
|
|
91
177
|
case '-h':
|
package/lib/install.js
CHANGED
package/lib/knowledge.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
const CONFIG_DIR = path.join(os.homedir(), '.analyzthis_design');
|
|
9
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
10
|
+
const KNOWLEDGE_SKILL = path.join(__dirname, '..', 'skills', 'knowledge-bank', 'SKILL.md');
|
|
11
|
+
|
|
12
|
+
// Keywords used to auto-group vault notes into categories
|
|
13
|
+
const CATEGORIES = {
|
|
14
|
+
brand: ['brand', 'color', 'typography', 'logo', 'visual', 'style', 'tone', 'voice', 'identity'],
|
|
15
|
+
product: ['product', 'feature', 'roadmap', 'vision', 'goal', 'north-star', 'metric', 'kpi', 'okr'],
|
|
16
|
+
design: ['design', 'ux', 'ui', 'wireframe', 'component', 'pattern', 'system', 'figma', 'layout'],
|
|
17
|
+
research: ['research', 'user', 'interview', 'survey', 'insight', 'pain', 'feedback', 'analytics', 'data'],
|
|
18
|
+
tech: ['tech', 'stack', 'api', 'backend', 'frontend', 'infrastructure', 'constraint', 'architecture'],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// ─── Config helpers ──────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
function loadConfig() {
|
|
24
|
+
if (!fs.existsSync(CONFIG_FILE)) return { sources: [] };
|
|
25
|
+
try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); }
|
|
26
|
+
catch { return { sources: [] }; }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function saveConfig(config) {
|
|
30
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
31
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ─── Vault reading ───────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
// Recursively collect all .md files under a directory
|
|
37
|
+
function readMarkdownFiles(dir) {
|
|
38
|
+
const files = [];
|
|
39
|
+
if (!fs.existsSync(dir)) return files;
|
|
40
|
+
const walk = (cur) => {
|
|
41
|
+
for (const entry of fs.readdirSync(cur, { withFileTypes: true })) {
|
|
42
|
+
const full = path.join(cur, entry.name);
|
|
43
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) walk(full);
|
|
44
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) files.push(full);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
walk(dir);
|
|
48
|
+
return files;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Parse YAML-ish frontmatter from a markdown file
|
|
52
|
+
function parseFrontmatter(raw) {
|
|
53
|
+
const m = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
54
|
+
if (!m) return { meta: {}, body: raw };
|
|
55
|
+
const meta = {};
|
|
56
|
+
for (const line of m[1].split('\n')) {
|
|
57
|
+
const [k, ...v] = line.split(':');
|
|
58
|
+
if (k && v.length) meta[k.trim()] = v.join(':').trim();
|
|
59
|
+
}
|
|
60
|
+
return { meta, body: m[2] };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Collect tags from frontmatter and inline #hashtags
|
|
64
|
+
function extractTags(meta, body) {
|
|
65
|
+
const tags = [];
|
|
66
|
+
if (meta.tags) tags.push(...meta.tags.replace(/[\[\]]/g, '').split(',').map(t => t.trim().toLowerCase()));
|
|
67
|
+
const inline = body.match(/#(\w+)/g) || [];
|
|
68
|
+
tags.push(...inline.map(t => t.slice(1).toLowerCase()));
|
|
69
|
+
return [...new Set(tags)];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Strip Obsidian-specific syntax so the AI reads clean markdown
|
|
73
|
+
function cleanObsidian(text) {
|
|
74
|
+
return text
|
|
75
|
+
.replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g, '$2') // [[note|alias]] → alias
|
|
76
|
+
.replace(/\[\[([^\]]+)\]\]/g, '$1') // [[note]] → note text
|
|
77
|
+
.replace(/!\[\[([^\]]+)\]\]/g, '') // ![[embed]] → remove
|
|
78
|
+
.replace(/%%[\s\S]*?%%/g, '') // %% comments %% → remove
|
|
79
|
+
.trim();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Map a note to a section category
|
|
83
|
+
function categorize(title, tags, body) {
|
|
84
|
+
const text = `${title} ${tags.join(' ')} ${body.substring(0, 500)}`.toLowerCase();
|
|
85
|
+
for (const [cat, keywords] of Object.entries(CATEGORIES)) {
|
|
86
|
+
if (keywords.some(k => text.includes(k))) return cat;
|
|
87
|
+
}
|
|
88
|
+
return 'other';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Register a vault or folder as a knowledge source.
|
|
95
|
+
* Options:
|
|
96
|
+
* include — array of sub-folder prefixes to include, e.g. ['Design', 'Brand']
|
|
97
|
+
* tags — array of tags to filter by, e.g. ['ux', 'design', 'brand']
|
|
98
|
+
*/
|
|
99
|
+
function connect({ vaultPath, include = [], tags = [] }) {
|
|
100
|
+
const abs = path.resolve(vaultPath);
|
|
101
|
+
if (!fs.existsSync(abs)) throw new Error(`Path does not exist: ${abs}`);
|
|
102
|
+
|
|
103
|
+
const config = loadConfig();
|
|
104
|
+
// Replace any existing entry with the same path
|
|
105
|
+
config.sources = config.sources.filter(s => s.path !== abs);
|
|
106
|
+
config.sources.push({ path: abs, include, tags, addedAt: new Date().toISOString() });
|
|
107
|
+
saveConfig(config);
|
|
108
|
+
return abs;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Remove a vault/folder from the knowledge sources list.
|
|
113
|
+
*/
|
|
114
|
+
function disconnect(vaultPath) {
|
|
115
|
+
const abs = path.resolve(vaultPath);
|
|
116
|
+
const config = loadConfig();
|
|
117
|
+
config.sources = config.sources.filter(s => s.path !== abs);
|
|
118
|
+
saveConfig(config);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Read all connected sources, filter notes, build knowledge-bank.md,
|
|
123
|
+
* and copy it to all requested target AI tool directories.
|
|
124
|
+
*
|
|
125
|
+
* targets — array of tool names: 'cursor', 'claude', 'codex'
|
|
126
|
+
*/
|
|
127
|
+
function sync({ targets = ['cursor'] } = {}) {
|
|
128
|
+
const config = loadConfig();
|
|
129
|
+
|
|
130
|
+
if (!config.sources || config.sources.length === 0) {
|
|
131
|
+
return { synced: 0, message: 'No sources connected. Run: npx analyzthis_design connect --vault /path/to/vault' };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const sections = { brand: [], product: [], design: [], research: [], tech: [], other: [] };
|
|
135
|
+
let totalFiles = 0;
|
|
136
|
+
|
|
137
|
+
for (const source of config.sources) {
|
|
138
|
+
const files = readMarkdownFiles(source.path);
|
|
139
|
+
|
|
140
|
+
for (const filePath of files) {
|
|
141
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
142
|
+
const { meta, body } = parseFrontmatter(raw);
|
|
143
|
+
const tags = extractTags(meta, body);
|
|
144
|
+
|
|
145
|
+
// Tag filter: skip file if it doesn't carry one of the required tags
|
|
146
|
+
if (source.tags.length > 0 && !source.tags.some(t => tags.includes(t.toLowerCase()))) continue;
|
|
147
|
+
|
|
148
|
+
// Include-folder filter: skip file if it's not inside one of the allowed sub-paths
|
|
149
|
+
if (source.include.length > 0) {
|
|
150
|
+
const rel = path.relative(source.path, filePath);
|
|
151
|
+
const ok = source.include.some(p => rel.startsWith(p.replace('/**', '').replace('/*', '')));
|
|
152
|
+
if (!ok) continue;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const title = meta.title || path.basename(filePath, '.md');
|
|
156
|
+
const cleaned = cleanObsidian(body);
|
|
157
|
+
if (!cleaned.trim()) continue;
|
|
158
|
+
|
|
159
|
+
const cat = categorize(title, tags, cleaned);
|
|
160
|
+
sections[cat].push({ title, content: cleaned });
|
|
161
|
+
totalFiles++;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Build the knowledge-bank markdown
|
|
166
|
+
const sourceList = config.sources.map(s => s.path).join(', ');
|
|
167
|
+
const date = new Date().toISOString().split('T')[0];
|
|
168
|
+
|
|
169
|
+
const sectionDefs = [
|
|
170
|
+
{ key: 'brand', heading: '## Brand & Design Guidelines' },
|
|
171
|
+
{ key: 'product', heading: '## Product Context' },
|
|
172
|
+
{ key: 'design', heading: '## Design Decisions & Patterns' },
|
|
173
|
+
{ key: 'research', heading: '## Research & User Insights' },
|
|
174
|
+
{ key: 'tech', heading: '## Technical Context' },
|
|
175
|
+
{ key: 'other', heading: '## Additional Context' },
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
let md = `---
|
|
179
|
+
name: knowledge-bank
|
|
180
|
+
description: Personal knowledge bank — takes precedence over all built-in persona defaults.
|
|
181
|
+
disable-model-invocation: true
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
# Knowledge Bank
|
|
185
|
+
|
|
186
|
+
> Last synced: ${date}
|
|
187
|
+
> Sources: ${sourceList}
|
|
188
|
+
> Files loaded: ${totalFiles}
|
|
189
|
+
|
|
190
|
+
**INSTRUCTION TO ALL PERSONAS:** This knowledge bank contains project-specific context that overrides your built-in defaults. Read every section below before forming any opinion. When this knowledge bank conflicts with your built-in knowledge, this knowledge bank wins.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
`;
|
|
195
|
+
|
|
196
|
+
let hasContent = false;
|
|
197
|
+
for (const { key, heading } of sectionDefs) {
|
|
198
|
+
if (sections[key].length === 0) continue;
|
|
199
|
+
hasContent = true;
|
|
200
|
+
md += `${heading}\n\n`;
|
|
201
|
+
for (const note of sections[key]) {
|
|
202
|
+
md += `### ${note.title}\n\n${note.content}\n\n`;
|
|
203
|
+
}
|
|
204
|
+
md += '---\n\n';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!hasContent) {
|
|
208
|
+
md += `_No matching files found. Check your --tags or --include filters, or remove filters to include all notes._\n`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Write to the package's own skills/knowledge-bank/SKILL.md
|
|
212
|
+
fs.mkdirSync(path.dirname(KNOWLEDGE_SKILL), { recursive: true });
|
|
213
|
+
fs.writeFileSync(KNOWLEDGE_SKILL, md);
|
|
214
|
+
|
|
215
|
+
// Copy to each target AI tool's skills directory
|
|
216
|
+
const { TARGET_DIRS } = require('./install');
|
|
217
|
+
const copiedTo = [];
|
|
218
|
+
|
|
219
|
+
for (const target of targets) {
|
|
220
|
+
const dir = TARGET_DIRS[target];
|
|
221
|
+
if (!dir) continue;
|
|
222
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
223
|
+
|
|
224
|
+
if (target === 'cursor') {
|
|
225
|
+
// Cursor expects a sub-directory with SKILL.md inside
|
|
226
|
+
const dest = path.join(dir, 'knowledge-bank');
|
|
227
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
228
|
+
fs.copyFileSync(KNOWLEDGE_SKILL, path.join(dest, 'SKILL.md'));
|
|
229
|
+
} else {
|
|
230
|
+
// Claude/Codex: flat .md file
|
|
231
|
+
fs.copyFileSync(KNOWLEDGE_SKILL, path.join(dir, 'knowledge-bank.md'));
|
|
232
|
+
}
|
|
233
|
+
copiedTo.push(`${target} → ${dir}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Persist lastSync timestamp
|
|
237
|
+
config.lastSync = new Date().toISOString();
|
|
238
|
+
saveConfig(config);
|
|
239
|
+
|
|
240
|
+
return { synced: totalFiles, copiedTo };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Return current config (sources list, lastSync).
|
|
245
|
+
*/
|
|
246
|
+
function status() {
|
|
247
|
+
return loadConfig();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
module.exports = { connect, disconnect, sync, status };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "analyzthis_design",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "7 AI design personas for Cursor — run structured UX critiques and ideation sessions with Arjun (UX), Meera (Business), Priya (Feasibility), Zara (Delight), Noor (IA), Anuj (Power-User), and Raj (Arbitrator).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cursor",
|
|
@@ -9,6 +9,19 @@ Four specialist personas evaluate a design independently across UX, business, fe
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## Step -1: Load knowledge bank (highest priority)
|
|
13
|
+
|
|
14
|
+
Before anything else, read `~/.cursor/skills/knowledge-bank/SKILL.md` (or `~/.claude/commands/knowledge-bank.md` / `~/.codex/skills/knowledge-bank.md` depending on your tool).
|
|
15
|
+
|
|
16
|
+
If the knowledge bank has content (i.e. it is not the "No knowledge bank connected yet" placeholder):
|
|
17
|
+
- Treat every section in the knowledge bank as **ground truth** for this project
|
|
18
|
+
- Brand guidelines, design decisions, product context, and research insights override your built-in defaults
|
|
19
|
+
- Reference specific knowledge bank entries when scoring or critiquing — quote them directly when relevant
|
|
20
|
+
|
|
21
|
+
If the knowledge bank is empty or missing, proceed without it.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
12
25
|
## Step 0: Gather session context
|
|
13
26
|
|
|
14
27
|
Before starting, ask the user for (or read from `_session-context` if available):
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: knowledge-bank
|
|
3
|
+
description: Personal knowledge bank. Takes precedence over all built-in persona defaults. Connect your Obsidian vault or any markdown folder, then sync. All 7 personas read this first.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Knowledge Bank
|
|
8
|
+
|
|
9
|
+
> No knowledge bank connected yet.
|
|
10
|
+
|
|
11
|
+
To populate this with your own project knowledge, run:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Connect an Obsidian vault (all notes)
|
|
15
|
+
npx analyzthis_design connect --vault /path/to/your/obsidian
|
|
16
|
+
|
|
17
|
+
# Connect a folder, filtering to only notes tagged #design or #brand
|
|
18
|
+
npx analyzthis_design connect --vault /path/to/docs --tags design,brand,product
|
|
19
|
+
|
|
20
|
+
# Connect a vault but only include specific sub-folders
|
|
21
|
+
npx analyzthis_design connect --vault /path/to/vault --include Design,Brand,Research
|
|
22
|
+
|
|
23
|
+
# After connecting, sync to generate the knowledge bank
|
|
24
|
+
npx analyzthis_design sync
|
|
25
|
+
|
|
26
|
+
# Sync to all AI tools at once
|
|
27
|
+
npx analyzthis_design sync --target all
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Once synced, this file is replaced with your actual vault content, grouped into:
|
|
31
|
+
- Brand & Design Guidelines
|
|
32
|
+
- Product Context
|
|
33
|
+
- Design Decisions & Patterns
|
|
34
|
+
- Research & User Insights
|
|
35
|
+
- Technical Context
|
|
36
|
+
|
|
37
|
+
**All 7 personas (Arjun, Meera, Priya, Zara, Noor, Anuj, Raj) will read this knowledge bank before any critique or ideation begins. Your project-specific knowledge takes full precedence over their built-in defaults.**
|
|
@@ -9,6 +9,19 @@ Seven personas collaborate across 6 phases to produce a single, deliberated, imp
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## Step -1: Load knowledge bank (highest priority)
|
|
13
|
+
|
|
14
|
+
Before anything else, read `~/.cursor/skills/knowledge-bank/SKILL.md` (or `~/.claude/commands/knowledge-bank.md` / `~/.codex/skills/knowledge-bank.md` depending on your tool).
|
|
15
|
+
|
|
16
|
+
If the knowledge bank has content (i.e. it is not the "No knowledge bank connected yet" placeholder):
|
|
17
|
+
- Treat every section as **ground truth** — brand guidelines, product decisions, research insights, and technical constraints override built-in persona defaults
|
|
18
|
+
- All 7 personas must reference applicable knowledge bank entries during their respective phases
|
|
19
|
+
- Design decisions already made in the knowledge bank are non-negotiable constraints — do not re-debate them
|
|
20
|
+
|
|
21
|
+
If the knowledge bank is empty or missing, proceed without it.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
12
25
|
## Step 0: Load session context
|
|
13
26
|
|
|
14
27
|
Read session context from the user or from `_session-context`:
|