thufir 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analyze.d.ts +28 -0
- package/dist/analyze.js +62 -0
- package/dist/api.d.ts +15 -0
- package/dist/api.js +30 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +183 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +10 -0
- package/dist/prompts.d.ts +22 -0
- package/dist/prompts.js +547 -0
- package/dist/scaffold.d.ts +13 -0
- package/dist/scaffold.js +352 -0
- package/dist/templates/agents/base.md +350 -0
- package/dist/templates/claude-md.md +1 -0
- package/dist/templates/cursorrules.md +1 -0
- package/dist/templates/gitignore.md +54 -0
- package/dist/templates/skill-triggers.md +5 -0
- package/dist/templates/skills/gstack.md +17 -0
- package/dist/templates/skills/superpowers.md +16 -0
- package/dist/templates/traits/compassion.md +13 -0
- package/dist/templates/traits/consultant.md +36 -0
- package/dist/templates/traits/first-principles.md +8 -0
- package/dist/templates/traits/mbb-problem-solving.md +9 -0
- package/dist/templates/traits/mentat-core.md +33 -0
- package/dist/templates/traits/parts.md +13 -0
- package/dist/templates/traits/psychology.md +32 -0
- package/dist/templates/traits/systemic.md +13 -0
- package/dist/templates/traits/thufir-personality.md +9 -0
- package/dist/templates/traits/top-down.md +9 -0
- package/dist/templates/traits/zelazny.md +9 -0
- package/dist/ui/ascii.d.ts +12 -0
- package/dist/ui/ascii.js +205 -0
- package/dist/version-check.d.ts +2 -0
- package/dist/version-check.js +27 -0
- package/package.json +38 -0
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, appendFileSync } from 'node:fs';
|
|
2
|
+
import { join, dirname, basename } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
function getTemplatesDir() {
|
|
7
|
+
const distTemplates = join(__dirname, 'templates');
|
|
8
|
+
if (existsSync(distTemplates))
|
|
9
|
+
return distTemplates;
|
|
10
|
+
return join(__dirname, '..', 'src', 'templates');
|
|
11
|
+
}
|
|
12
|
+
function readTemplate(relativePath) {
|
|
13
|
+
return readFileSync(join(getTemplatesDir(), relativePath), 'utf-8');
|
|
14
|
+
}
|
|
15
|
+
const TRAIT_FILES = {
|
|
16
|
+
'mentat-core': 'traits/mentat-core.md',
|
|
17
|
+
'consultant': 'traits/consultant.md',
|
|
18
|
+
'psychology': 'traits/psychology.md',
|
|
19
|
+
// Legacy trait IDs (map to new packages for backward compat)
|
|
20
|
+
'thufir': 'traits/mentat-core.md',
|
|
21
|
+
'first-principles': 'traits/mentat-core.md',
|
|
22
|
+
'mbb': 'traits/consultant.md',
|
|
23
|
+
'zelazny': 'traits/consultant.md',
|
|
24
|
+
'top-down': 'traits/consultant.md',
|
|
25
|
+
'compassion': 'traits/psychology.md',
|
|
26
|
+
'systemic': 'traits/psychology.md',
|
|
27
|
+
'parts': 'traits/psychology.md',
|
|
28
|
+
};
|
|
29
|
+
const SKILL_FILES = {
|
|
30
|
+
'superpowers': 'skills/superpowers.md',
|
|
31
|
+
'gstack': 'skills/gstack.md',
|
|
32
|
+
};
|
|
33
|
+
const TRIGGER_LINES = {
|
|
34
|
+
'brainstorming': { situation: 'Creative work starting — new feature, component, or behavior change', skill: 'Brainstorming', how: 'Use the brainstorming skill before writing any code' },
|
|
35
|
+
'plans': { situation: 'Multi-step task with a spec or requirements', skill: 'Implementation Plans', how: 'Create a detailed implementation plan before coding' },
|
|
36
|
+
'ceo-review': { situation: 'Reviewing product requirements or finding better solutions', skill: 'CEO/Product Review', how: '`/plan-ceo-review` — founder-mode review, finds the 10-star product' },
|
|
37
|
+
'eng-review': { situation: 'Locking architecture, mapping edge cases', skill: 'Engineering Review', how: '`/plan-eng-review` — architecture and technical planning' },
|
|
38
|
+
'tdd': { situation: 'Implementing a feature or bugfix', skill: 'Test-Driven Development', how: 'Write failing tests first, then implement' },
|
|
39
|
+
'code-review': { situation: 'Completing a task or receiving feedback', skill: 'Code Review', how: 'Review work against requirements; verify feedback before implementing' },
|
|
40
|
+
'verification': { situation: 'About to claim work is complete', skill: 'Verification', how: 'Run verification commands, confirm output before claiming success' },
|
|
41
|
+
'debugging': { situation: 'Bug, test failure, or unexpected behavior', skill: 'Systematic Debugging', how: "Follow the debugging skill's scientific method" },
|
|
42
|
+
'browse': { situation: 'Need to test a frontend feature or verify a deployment', skill: 'Browser Automation', how: '`/gstack` or `/browse` — opens persistent headless browser' },
|
|
43
|
+
'qa': { situation: 'Frontend feature complete, needs systematic testing', skill: 'QA Testing', how: '`/qa` — tests app, finds bugs, fixes them, re-verifies' },
|
|
44
|
+
'design-review': { situation: 'Design audit needed', skill: 'Design Audit', how: '`/plan-design-review` — 80-item design audit' },
|
|
45
|
+
'shipping': { situation: 'Ready to create a PR and ship', skill: 'Shipping', how: '`/ship` — runs tests, resolves comments, pushes, opens PR' },
|
|
46
|
+
'parallel': { situation: '2+ independent tasks that can run in parallel', skill: 'Parallel Agents', how: 'Use subagents for independent work streams' },
|
|
47
|
+
'retro': { situation: 'Want a development retrospective', skill: 'Retrospective', how: '`/retro` — analyzes commit history, work patterns, per-person metrics' },
|
|
48
|
+
};
|
|
49
|
+
function buildTraitsSection(selectedTraits) {
|
|
50
|
+
// Always include mentat-core
|
|
51
|
+
const allTraits = ['mentat-core', ...selectedTraits.filter(t => t !== 'mentat-core')];
|
|
52
|
+
// Deduplicate file paths (legacy IDs may map to same file)
|
|
53
|
+
const seen = new Set();
|
|
54
|
+
const traitContents = allTraits
|
|
55
|
+
.filter((t) => t in TRAIT_FILES)
|
|
56
|
+
.filter((t) => {
|
|
57
|
+
const file = TRAIT_FILES[t];
|
|
58
|
+
if (seen.has(file))
|
|
59
|
+
return false;
|
|
60
|
+
seen.add(file);
|
|
61
|
+
return true;
|
|
62
|
+
})
|
|
63
|
+
.map((t) => readTemplate(TRAIT_FILES[t]).trim())
|
|
64
|
+
.join('\n\n');
|
|
65
|
+
if (!traitContents)
|
|
66
|
+
return '';
|
|
67
|
+
return `---
|
|
68
|
+
|
|
69
|
+
## Personality & Thinking
|
|
70
|
+
|
|
71
|
+
These traits guide how your AI colleague thinks and communicates.
|
|
72
|
+
|
|
73
|
+
${traitContents}
|
|
74
|
+
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
function buildSkillTriggersSection(selectedPackages, selectedTriggers) {
|
|
78
|
+
if (!selectedPackages || selectedPackages.length === 0)
|
|
79
|
+
return '';
|
|
80
|
+
if (!selectedTriggers || selectedTriggers.length === 0)
|
|
81
|
+
return '';
|
|
82
|
+
const hasSP = selectedPackages.includes('superpowers');
|
|
83
|
+
const hasGS = selectedPackages.includes('gstack');
|
|
84
|
+
// Categorize triggers
|
|
85
|
+
const planningTriggers = ['brainstorming', 'plans', 'ceo-review', 'eng-review'].filter(t => selectedTriggers.includes(t));
|
|
86
|
+
const qualityTriggers = ['tdd', 'code-review', 'verification', 'debugging'].filter(t => selectedTriggers.includes(t));
|
|
87
|
+
const browserTriggers = ['browse', 'qa', 'design-review'].filter(t => selectedTriggers.includes(t));
|
|
88
|
+
const workflowTriggers = ['shipping', 'parallel', 'retro'].filter(t => selectedTriggers.includes(t));
|
|
89
|
+
// Filter to only triggers relevant to selected packages
|
|
90
|
+
// superpowers: brainstorming, plans, tdd, code-review, verification, debugging, parallel
|
|
91
|
+
// gstack: ceo-review, eng-review, browse, qa, design-review, shipping, retro
|
|
92
|
+
// Some triggers are useful with either package
|
|
93
|
+
const spTriggers = new Set(['brainstorming', 'plans', 'tdd', 'code-review', 'verification', 'debugging', 'parallel']);
|
|
94
|
+
const gsTriggers = new Set(['ceo-review', 'eng-review', 'browse', 'qa', 'design-review', 'shipping', 'retro']);
|
|
95
|
+
const isRelevant = (t) => (hasSP && spTriggers.has(t)) || (hasGS && gsTriggers.has(t));
|
|
96
|
+
let content = '---\n\n## Skill Invocation Guide\n\nWhen these situations arise, invoke the relevant skill:\n\n';
|
|
97
|
+
const sections = [
|
|
98
|
+
{ name: 'Planning & Strategy', triggers: planningTriggers.filter(isRelevant) },
|
|
99
|
+
{ name: 'Code Quality', triggers: qualityTriggers.filter(isRelevant) },
|
|
100
|
+
{ name: 'Browser & Testing', triggers: browserTriggers.filter(isRelevant) },
|
|
101
|
+
{ name: 'Workflow', triggers: workflowTriggers.filter(isRelevant) },
|
|
102
|
+
];
|
|
103
|
+
let hasContent = false;
|
|
104
|
+
for (const section of sections) {
|
|
105
|
+
if (section.triggers.length === 0)
|
|
106
|
+
continue;
|
|
107
|
+
hasContent = true;
|
|
108
|
+
content += `### ${section.name}\n\n`;
|
|
109
|
+
content += '| Situation | Skill to invoke | How |\n';
|
|
110
|
+
content += '|-----------|----------------|-----|\n';
|
|
111
|
+
for (const id of section.triggers) {
|
|
112
|
+
const t = TRIGGER_LINES[id];
|
|
113
|
+
if (t)
|
|
114
|
+
content += `| ${t.situation} | ${t.skill} | ${t.how} |\n`;
|
|
115
|
+
}
|
|
116
|
+
content += '\n';
|
|
117
|
+
}
|
|
118
|
+
if (!hasContent)
|
|
119
|
+
return '';
|
|
120
|
+
if (hasGS) {
|
|
121
|
+
content += '**Note:** gstack requires Bun. Run: `git clone https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup`\n\n';
|
|
122
|
+
}
|
|
123
|
+
return content;
|
|
124
|
+
}
|
|
125
|
+
function substitute(content, answers) {
|
|
126
|
+
const date = new Date().toISOString().split('T')[0];
|
|
127
|
+
const traitsSection = buildTraitsSection(answers.traits);
|
|
128
|
+
const skillTriggersSection = buildSkillTriggersSection(answers.skillPackages, answers.skillTriggers);
|
|
129
|
+
return content
|
|
130
|
+
.replace(/\{\{colleague_name\}\}/g, answers.colleagueName)
|
|
131
|
+
.replace(/\{\{user_name\}\}/g, answers.userName)
|
|
132
|
+
.replace(/\{\{project_description\}\}/g, answers.projectDescription)
|
|
133
|
+
.replace(/\{\{project_type\}\}/g, answers.projectFocus)
|
|
134
|
+
.replace(/\{\{traits_section\}\}/g, traitsSection)
|
|
135
|
+
.replace(/\{\{skill_triggers_section\}\}/g, skillTriggersSection)
|
|
136
|
+
.replace(/\{\{created_date\}\}/g, date);
|
|
137
|
+
}
|
|
138
|
+
function writeFile(cwd, relativePath, content) {
|
|
139
|
+
const fullPath = join(cwd, relativePath);
|
|
140
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
141
|
+
writeFileSync(fullPath, content, 'utf-8');
|
|
142
|
+
}
|
|
143
|
+
/** Files that are always Thufir-managed and safe to overwrite */
|
|
144
|
+
const THUFIR_MANAGED_FILES = ['AGENTS.md', 'CLAUDE.md', '.cursorrules'];
|
|
145
|
+
/** Doc files that should be skipped during realign if they already exist (user content) */
|
|
146
|
+
const USER_CONTENT_DOCS = [
|
|
147
|
+
'business/overview.md',
|
|
148
|
+
'business/audience.md',
|
|
149
|
+
'decisions/001-project-kickoff.md',
|
|
150
|
+
];
|
|
151
|
+
/** Doc files that are always regenerated (indexes, Thufir content) */
|
|
152
|
+
const THUFIR_DOCS = [
|
|
153
|
+
'_meta.md',
|
|
154
|
+
'business/_meta.md',
|
|
155
|
+
'decisions/_meta.md',
|
|
156
|
+
'plans/_meta.md',
|
|
157
|
+
'workflows/_meta.md',
|
|
158
|
+
'workflows/getting-started.md',
|
|
159
|
+
];
|
|
160
|
+
export function scaffold(cwd, answers, analysis, isRealign = false) {
|
|
161
|
+
const files = [];
|
|
162
|
+
let gitInitialized = false;
|
|
163
|
+
if (!analysis.isGitRepo) {
|
|
164
|
+
execSync('git init', { cwd, stdio: 'ignore' });
|
|
165
|
+
gitInitialized = true;
|
|
166
|
+
}
|
|
167
|
+
// AGENTS.md
|
|
168
|
+
const agentsTemplate = readTemplate('agents/base.md');
|
|
169
|
+
writeFile(cwd, 'AGENTS.md', substitute(agentsTemplate, answers));
|
|
170
|
+
files.push('AGENTS.md');
|
|
171
|
+
// CLAUDE.md
|
|
172
|
+
writeFile(cwd, 'CLAUDE.md', readTemplate('claude-md.md'));
|
|
173
|
+
files.push('CLAUDE.md');
|
|
174
|
+
// .cursorrules
|
|
175
|
+
writeFile(cwd, '.cursorrules', readTemplate('cursorrules.md'));
|
|
176
|
+
files.push('.cursorrules');
|
|
177
|
+
// .gitignore
|
|
178
|
+
const gitignorePath = join(cwd, '.gitignore');
|
|
179
|
+
const gitignoreContent = readTemplate('gitignore.md');
|
|
180
|
+
if (existsSync(gitignorePath)) {
|
|
181
|
+
const existing = readFileSync(gitignorePath, 'utf-8');
|
|
182
|
+
if (!existing.includes('# Thufir defaults')) {
|
|
183
|
+
appendFileSync(gitignorePath, '\n# Thufir defaults\n' + gitignoreContent + '\n');
|
|
184
|
+
}
|
|
185
|
+
// Ensure .thufir.local is gitignored
|
|
186
|
+
if (!existing.includes('.thufir.local')) {
|
|
187
|
+
appendFileSync(gitignorePath, '\n# Thufir local config (tokens)\n.thufir.local\n');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
writeFile(cwd, '.gitignore', gitignoreContent + '\n\n# Thufir local config (tokens)\n.thufir.local\n');
|
|
192
|
+
}
|
|
193
|
+
files.push('.gitignore');
|
|
194
|
+
// docs/ structure
|
|
195
|
+
if (isRealign) {
|
|
196
|
+
// During realign: always regenerate indexes and Thufir content
|
|
197
|
+
for (const docFile of THUFIR_DOCS) {
|
|
198
|
+
const template = readTemplate('docs/' + docFile);
|
|
199
|
+
writeFile(cwd, 'docs/' + docFile, substitute(template, answers));
|
|
200
|
+
files.push('docs/' + docFile);
|
|
201
|
+
}
|
|
202
|
+
// Only create user content docs if they don't already exist
|
|
203
|
+
for (const docFile of USER_CONTENT_DOCS) {
|
|
204
|
+
if (!existsSync(join(cwd, 'docs', docFile))) {
|
|
205
|
+
const template = readTemplate('docs/' + docFile);
|
|
206
|
+
writeFile(cwd, 'docs/' + docFile, substitute(template, answers));
|
|
207
|
+
files.push('docs/' + docFile);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// Fresh install: create everything
|
|
213
|
+
const allDocFiles = [...THUFIR_DOCS, ...USER_CONTENT_DOCS];
|
|
214
|
+
for (const docFile of allDocFiles) {
|
|
215
|
+
const template = readTemplate('docs/' + docFile);
|
|
216
|
+
writeFile(cwd, 'docs/' + docFile, substitute(template, answers));
|
|
217
|
+
files.push('docs/' + docFile);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// .thufir marker — full settings
|
|
221
|
+
const date = new Date().toISOString().split('T')[0];
|
|
222
|
+
const marker = JSON.stringify({
|
|
223
|
+
version: '1.3.0',
|
|
224
|
+
initialized: isRealign ? answers._originalInitialized || date : date,
|
|
225
|
+
last_realigned: date,
|
|
226
|
+
colleague_name: answers.colleagueName,
|
|
227
|
+
user_name: answers.userName,
|
|
228
|
+
project_mode: answers.projectMode,
|
|
229
|
+
project_focus: answers.projectFocus,
|
|
230
|
+
project_description: answers.projectDescription,
|
|
231
|
+
traits: answers.traits,
|
|
232
|
+
skillPackages: answers.skillPackages,
|
|
233
|
+
skillTriggers: answers.skillTriggers,
|
|
234
|
+
}, null, 2);
|
|
235
|
+
writeFile(cwd, '.thufir', marker);
|
|
236
|
+
files.push('.thufir');
|
|
237
|
+
// .thufir.local — token storage (not committed)
|
|
238
|
+
const localConfig = JSON.stringify({ token: answers.token }, null, 2);
|
|
239
|
+
writeFile(cwd, '.thufir.local', localConfig);
|
|
240
|
+
return { filesCreated: files, gitInitialized };
|
|
241
|
+
}
|
|
242
|
+
export function backupAgentFiles(cwd) {
|
|
243
|
+
const backupDir = join(cwd, '.thufir-backup');
|
|
244
|
+
mkdirSync(backupDir, { recursive: true });
|
|
245
|
+
const filesToBackup = ['AGENTS.md', 'CLAUDE.md', '.cursorrules', '.cursor/rules/onboarding.mdc', '.cursor/rules/documentation.mdc', '.cursor/rules/project-context.mdc'];
|
|
246
|
+
const backedUp = [];
|
|
247
|
+
for (const file of filesToBackup) {
|
|
248
|
+
const src = join(cwd, file);
|
|
249
|
+
if (existsSync(src)) {
|
|
250
|
+
const dest = join(backupDir, file.replace(/\//g, '__'));
|
|
251
|
+
const content = readFileSync(src, 'utf-8');
|
|
252
|
+
writeFileSync(dest, content, 'utf-8');
|
|
253
|
+
backedUp.push(file);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// Also backup any existing docs/_meta.md files
|
|
257
|
+
const docsDir = join(cwd, 'docs');
|
|
258
|
+
if (existsSync(docsDir)) {
|
|
259
|
+
try {
|
|
260
|
+
const metaContent = readFileSync(join(docsDir, '_meta.md'), 'utf-8');
|
|
261
|
+
writeFileSync(join(backupDir, 'docs___meta.md'), metaContent, 'utf-8');
|
|
262
|
+
backedUp.push('docs/_meta.md');
|
|
263
|
+
}
|
|
264
|
+
catch { }
|
|
265
|
+
}
|
|
266
|
+
return backedUp;
|
|
267
|
+
}
|
|
268
|
+
export function generateMergePrompt(cwd, answers, backedUpFiles) {
|
|
269
|
+
const backupDir = join(cwd, '.thufir-backup');
|
|
270
|
+
// Read all backup contents to include in the prompt
|
|
271
|
+
let backupSummary = '';
|
|
272
|
+
for (const file of backedUpFiles) {
|
|
273
|
+
const backupPath = join(backupDir, file.replace(/\//g, '__'));
|
|
274
|
+
if (existsSync(backupPath)) {
|
|
275
|
+
const content = readFileSync(backupPath, 'utf-8');
|
|
276
|
+
backupSummary += `\n### Original ${file}\n\`\`\`\n${content.slice(0, 3000)}\n\`\`\`\n`;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return `# Thufir Merge — Reorganization Plan
|
|
280
|
+
|
|
281
|
+
You are helping merge Thufir conventions into this existing repository. Thufir has already:
|
|
282
|
+
1. Backed up the original agent files to \`.thufir-backup/\`
|
|
283
|
+
2. Written new Thufir-managed files (AGENTS.md, CLAUDE.md, .cursorrules)
|
|
284
|
+
3. Created the docs/ structure with entity system
|
|
285
|
+
|
|
286
|
+
## Your Task
|
|
287
|
+
|
|
288
|
+
Review the backed-up original files and merge their intentions into the new Thufir structure. The original files contain valuable context that should NOT be lost.
|
|
289
|
+
|
|
290
|
+
## Backed-Up Original Files
|
|
291
|
+
${backupSummary}
|
|
292
|
+
|
|
293
|
+
## What to Do
|
|
294
|
+
|
|
295
|
+
1. **Read the new AGENTS.md** that Thufir just created. It has the standard structure.
|
|
296
|
+
|
|
297
|
+
2. **Read each backed-up file** in \`.thufir-backup/\`. Extract:
|
|
298
|
+
- Custom instructions and rules the user had
|
|
299
|
+
- Project-specific context (tech stack, conventions, preferences)
|
|
300
|
+
- Any documented workflows or procedures
|
|
301
|
+
- References to specific files, APIs, or tools
|
|
302
|
+
|
|
303
|
+
3. **Merge extracted content into the new structure:**
|
|
304
|
+
- Custom instructions → Add to AGENTS.md in the appropriate section (e.g., "When the Project Needs Code" for tech stack info)
|
|
305
|
+
- Workflows → Create files in \`docs/workflows/\`
|
|
306
|
+
- Project context → Update \`docs/business/overview.md\`
|
|
307
|
+
- Decision-like content → Create decision records in \`docs/decisions/\`
|
|
308
|
+
|
|
309
|
+
4. **Preserve the Thufir structure.** The new AGENTS.md sections must stay intact. Add custom content WITHIN sections, don't restructure.
|
|
310
|
+
|
|
311
|
+
5. **Minimal reorganization.** Keep things where they make sense. Don't move files unless they clearly belong elsewhere.
|
|
312
|
+
|
|
313
|
+
## Key Principle
|
|
314
|
+
|
|
315
|
+
The user's original agent files had intentions — they wrote those instructions for a reason. Every instruction should find a home in the new structure. Nothing should be lost.
|
|
316
|
+
|
|
317
|
+
## Colleague Details
|
|
318
|
+
- Name: ${answers.colleagueName}
|
|
319
|
+
- User: ${answers.userName}
|
|
320
|
+
- Project: ${answers.projectDescription}
|
|
321
|
+
- Focus: ${answers.projectFocus}
|
|
322
|
+
|
|
323
|
+
## When Done
|
|
324
|
+
|
|
325
|
+
After merging, check:
|
|
326
|
+
- [ ] All original custom instructions are preserved somewhere in the new structure
|
|
327
|
+
- [ ] AGENTS.md is coherent and not duplicated
|
|
328
|
+
- [ ] docs/ structure has _meta.md indexes updated
|
|
329
|
+
- [ ] No files were deleted (only reorganized)
|
|
330
|
+
|
|
331
|
+
Commit your changes with: \`git add -A && git commit -m "feat: merge Thufir conventions into existing repo"\`
|
|
332
|
+
`;
|
|
333
|
+
}
|
|
334
|
+
export function createInitialCommit(cwd, files, colleagueName) {
|
|
335
|
+
for (const file of files) {
|
|
336
|
+
execSync('git add "' + file + '"', { cwd, stdio: 'ignore' });
|
|
337
|
+
}
|
|
338
|
+
execSync('git commit -m "feat: initialize ' + colleagueName + ' AI colleague"', { cwd, stdio: 'ignore' });
|
|
339
|
+
}
|
|
340
|
+
export function setupGitHub(cwd, mode, repoName) {
|
|
341
|
+
try {
|
|
342
|
+
if (mode === 'create') {
|
|
343
|
+
const name = repoName || basename(cwd);
|
|
344
|
+
execSync('gh repo create ' + name + ' --private --source=. --push', { cwd, stdio: 'inherit' });
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|