@pshch/gary-the-gardener 1.2.0 → 1.3.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/_gs-gardener/VERSION +1 -1
- package/_gs-gardener/core/config.yaml +2 -2
- package/bin/cli.js +243 -161
- package/package.json +2 -2
package/_gs-gardener/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.3.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Garden System Configuration
|
|
2
|
-
# Version: 1.
|
|
2
|
+
# Version: 1.3.0
|
|
3
3
|
|
|
4
4
|
project_name: ai-bootstrap
|
|
5
5
|
user_name: User
|
|
@@ -22,4 +22,4 @@ references_directory: "{project-root}/docs/references"
|
|
|
22
22
|
agents_max_lines: 150
|
|
23
23
|
|
|
24
24
|
# Garden System Version
|
|
25
|
-
version: "1.
|
|
25
|
+
version: "1.3.0"
|
package/bin/cli.js
CHANGED
|
@@ -18,15 +18,10 @@ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
|
18
18
|
const { values, positionals } = parseArgs({
|
|
19
19
|
args: process.argv.slice(2),
|
|
20
20
|
options: {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
junie: { type: 'boolean', default: false },
|
|
26
|
-
all: { type: 'boolean', default: false },
|
|
27
|
-
force: { type: 'boolean', short: 'f', default: false },
|
|
28
|
-
help: { type: 'boolean', short: 'h', default: false },
|
|
29
|
-
version: { type: 'boolean', short: 'v', default: false },
|
|
21
|
+
force: { type: 'boolean', short: 'f', default: false },
|
|
22
|
+
'dry-run': { type: 'boolean', short: 'n', default: false },
|
|
23
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
24
|
+
version: { type: 'boolean', short: 'v', default: false },
|
|
30
25
|
},
|
|
31
26
|
allowPositionals: true,
|
|
32
27
|
strict: false,
|
|
@@ -41,45 +36,34 @@ if (values.version) {
|
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
// ── Help ────────────────────────────────────────────────────────────
|
|
44
|
-
if (values.help
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
${bold('USAGE')}
|
|
49
|
-
npx @pshch/gary-the-gardener ${green('install')} [options]
|
|
50
|
-
|
|
51
|
-
${bold('COMMANDS')}
|
|
52
|
-
${green('install')} Install Garden System into the current project
|
|
53
|
-
|
|
54
|
-
${bold('TOOL OPTIONS')} ${dim('(pick which AI tools to set up)')}
|
|
55
|
-
--claude Claude Code — skills, commands, CLAUDE.md wrapper
|
|
56
|
-
--copilot GitHub Copilot — .github/copilot-instructions.md wrapper
|
|
57
|
-
--cursor Cursor — .cursor/rules/agents.mdc wrapper
|
|
58
|
-
--codex OpenAI Codex — codex.md wrapper
|
|
59
|
-
--junie JetBrains Junie — .junie/guidelines.md wrapper
|
|
60
|
-
--all All of the above
|
|
61
|
-
|
|
62
|
-
${dim('If no tool flags given, defaults to --claude only.')}
|
|
39
|
+
if (values.help) {
|
|
40
|
+
printHelp();
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
63
43
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-v, --version Show version
|
|
67
|
-
-h, --help Show this help
|
|
44
|
+
// ── Route commands ──────────────────────────────────────────────────
|
|
45
|
+
const dryRun = values['dry-run'];
|
|
68
46
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
`);
|
|
75
|
-
|
|
47
|
+
if (command === 'status') {
|
|
48
|
+
runStatus();
|
|
49
|
+
} else if (command === 'install' || !command) {
|
|
50
|
+
runInstall(values.force, dryRun);
|
|
51
|
+
} else {
|
|
52
|
+
console.error(red(`Unknown command: ${command}`));
|
|
53
|
+
console.error('Run "npx @pshch/gary-the-gardener --help" for usage.');
|
|
54
|
+
process.exit(1);
|
|
76
55
|
}
|
|
77
56
|
|
|
78
|
-
//
|
|
79
|
-
|
|
57
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
58
|
+
// ── Core functions ────────────────────────────────────────────────
|
|
59
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
60
|
+
|
|
61
|
+
function runInstall(force, dryRun) {
|
|
80
62
|
const dest = process.cwd();
|
|
81
63
|
|
|
82
|
-
console.log(`\n🪴 ${bold('Gary the Gardener')} v${VERSION}
|
|
64
|
+
console.log(`\n🪴 ${bold('Gary the Gardener')} v${VERSION}`);
|
|
65
|
+
if (dryRun) console.log(yellow(` (dry run — no files will be written)`));
|
|
66
|
+
console.log('');
|
|
83
67
|
|
|
84
68
|
// Sanity check: don't install into the package itself
|
|
85
69
|
if (existsSync(join(dest, 'bin', 'cli.js')) && existsSync(join(dest, '_gs-gardener', 'core'))) {
|
|
@@ -90,117 +74,76 @@ if (command === 'install') {
|
|
|
90
74
|
}
|
|
91
75
|
}
|
|
92
76
|
|
|
93
|
-
//
|
|
94
|
-
const tools = new Set();
|
|
95
|
-
if (values.all) {
|
|
96
|
-
tools.add('claude').add('copilot').add('cursor').add('codex').add('junie');
|
|
97
|
-
} else {
|
|
98
|
-
if (values.claude) tools.add('claude');
|
|
99
|
-
if (values.copilot) tools.add('copilot');
|
|
100
|
-
if (values.cursor) tools.add('cursor');
|
|
101
|
-
if (values.codex) tools.add('codex');
|
|
102
|
-
if (values.junie) tools.add('junie');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Default to claude if nothing specified
|
|
106
|
-
if (tools.size === 0) tools.add('claude');
|
|
107
|
-
|
|
108
|
-
// ── 1. Copy core Garden System ──────────────────────────────────
|
|
77
|
+
// ── Detect existing installation ──────────────────────────────────
|
|
109
78
|
const coreSrc = join(PKG_ROOT, '_gs-gardener');
|
|
110
79
|
const coreDest = join(dest, '_gs-gardener');
|
|
80
|
+
const configPath = join(coreDest, 'core', 'config.yaml');
|
|
111
81
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
console.log(` ${green('✓')} Installing core system → ${dim('_gs-gardener/')}`);
|
|
116
|
-
cpSync(coreSrc, coreDest, { recursive: true, force: values.force });
|
|
82
|
+
const installedVersion = readInstalledVersion(coreDest);
|
|
83
|
+
const isUpgrade = installedVersion && installedVersion !== VERSION;
|
|
84
|
+
const isCurrent = installedVersion === VERSION;
|
|
117
85
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
# Version: ${VERSION}
|
|
123
|
-
|
|
124
|
-
project_name: ${projectName}
|
|
125
|
-
user_name: User
|
|
126
|
-
communication_language: English
|
|
127
|
-
output_folder: "{project-root}/docs"
|
|
128
|
-
|
|
129
|
-
# Coverage tracking
|
|
130
|
-
agents_file: "{project-root}/AGENTS.md"
|
|
131
|
-
wrapper_files:
|
|
132
|
-
- "{project-root}/CLAUDE.md"
|
|
133
|
-
- "{project-root}/.github/copilot-instructions.md"
|
|
134
|
-
- "{project-root}/.cursor/rules/agents.mdc"
|
|
135
|
-
- "{project-root}/.junie/guidelines.md"
|
|
136
|
-
|
|
137
|
-
# Content layers
|
|
138
|
-
docs_directory: "{project-root}/docs"
|
|
139
|
-
references_directory: "{project-root}/docs/references"
|
|
140
|
-
|
|
141
|
-
# Constraints
|
|
142
|
-
agents_max_lines: 150
|
|
143
|
-
|
|
144
|
-
# Garden System Version
|
|
145
|
-
version: "${VERSION}"
|
|
146
|
-
`;
|
|
147
|
-
writeFileSync(configPath, defaultConfig);
|
|
86
|
+
if (isUpgrade) {
|
|
87
|
+
console.log(` Upgrading ${dim(`v${installedVersion}`)} → ${green(`v${VERSION}`)}\n`);
|
|
88
|
+
} else if (isCurrent && !force) {
|
|
89
|
+
console.log(` Already up to date ${dim(`(v${VERSION})`)}\n`);
|
|
148
90
|
}
|
|
149
91
|
|
|
150
|
-
// ──
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
|
|
92
|
+
// ── 1. Core Garden System ─────────────────────────────────────────
|
|
93
|
+
if (isCurrent && !force) {
|
|
94
|
+
console.log(` ${green('✓')} Core system → ${dim('_gs-gardener/ (unchanged)')}`);
|
|
95
|
+
} else {
|
|
96
|
+
// Save user config before overwriting
|
|
97
|
+
const savedConfig = isUpgrade ? safeReadFile(configPath) : null;
|
|
98
|
+
|
|
99
|
+
if (!dryRun) {
|
|
100
|
+
cpSync(coreSrc, coreDest, { recursive: true, force: true });
|
|
101
|
+
|
|
102
|
+
if (savedConfig) {
|
|
103
|
+
// Restore user config, only bump the version line
|
|
104
|
+
const updated = savedConfig
|
|
105
|
+
.replace(/^# Version: .+$/m, `# Version: ${VERSION}`)
|
|
106
|
+
.replace(/^version: .+$/m, `version: "${VERSION}"`);
|
|
107
|
+
writeFileSync(configPath, updated);
|
|
108
|
+
console.log(` ${green('✓')} Core system → ${dim('_gs-gardener/ (upgraded, config preserved)')}`);
|
|
109
|
+
} else {
|
|
110
|
+
// Fresh install — write default config
|
|
111
|
+
const projectName = basename(dest);
|
|
112
|
+
writeFileSync(configPath, defaultConfig(projectName));
|
|
113
|
+
console.log(` ${green('✓')} Core system → ${dim('_gs-gardener/')}`);
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
const label = isUpgrade ? '(would upgrade, config preserved)' : '';
|
|
117
|
+
console.log(` ${green('✓')} Core system → ${dim(`_gs-gardener/ ${label}`)}`);
|
|
163
118
|
}
|
|
164
|
-
console.log(` ${green('✓')} Claude Code — ${copied} skill commands → ${dim('.claude/commands/')}`);
|
|
165
|
-
|
|
166
|
-
// Create CLAUDE.md wrapper
|
|
167
|
-
installWrapper(dest, 'CLAUDE.md',
|
|
168
|
-
`# CLAUDE.md\n\nFollow all instructions in the root AGENTS.md file as the primary context for this repository.\n`,
|
|
169
|
-
values.force);
|
|
170
119
|
}
|
|
171
120
|
|
|
172
|
-
// ──
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
121
|
+
// ── 2. Claude Code skill commands ─────────────────────────────────
|
|
122
|
+
const cmdSrc = join(PKG_ROOT, '.claude', 'commands');
|
|
123
|
+
const cmdDest = join(dest, '.claude', 'commands');
|
|
124
|
+
if (!dryRun) mkdirSync(cmdDest, { recursive: true });
|
|
125
|
+
|
|
126
|
+
const gardenCmds = readdirSync(cmdSrc).filter(f => f.startsWith('garden-') && f.endsWith('.md'));
|
|
127
|
+
const shouldUpdateCmds = isUpgrade || force || !installedVersion;
|
|
128
|
+
let copied = 0;
|
|
129
|
+
for (const file of gardenCmds) {
|
|
130
|
+
const destFile = join(cmdDest, file);
|
|
131
|
+
if (existsSync(destFile) && !shouldUpdateCmds) continue;
|
|
132
|
+
if (!dryRun) cpSync(join(cmdSrc, file), destFile, { force: true });
|
|
133
|
+
copied++;
|
|
178
134
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
installWrapper(dest, '.cursor/rules/agents.mdc',
|
|
184
|
-
`---\ndescription: Primary repository context sourced from AGENTS.md\nglobs:\nalwaysApply: true\n---\n\nFollow all instructions in the root AGENTS.md file as the primary context for this repository.\n`,
|
|
185
|
-
values.force);
|
|
135
|
+
if (isCurrent && !force) {
|
|
136
|
+
console.log(` ${green('✓')} ${gardenCmds.length} skill commands → ${dim('.claude/commands/ (unchanged)')}`);
|
|
137
|
+
} else {
|
|
138
|
+
console.log(` ${green('✓')} ${copied} skill commands → ${dim('.claude/commands/')}`);
|
|
186
139
|
}
|
|
187
140
|
|
|
188
|
-
// ──
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
values.force);
|
|
193
|
-
}
|
|
141
|
+
// ── 3. CLAUDE.md ──────────────────────────────────────────────────
|
|
142
|
+
installWrapper(dest, 'CLAUDE.md',
|
|
143
|
+
`# CLAUDE.md\n\nFollow all instructions in the root AGENTS.md file as the primary context for this repository.\n`,
|
|
144
|
+
force, dryRun);
|
|
194
145
|
|
|
195
|
-
// ──
|
|
196
|
-
if (tools.has('junie')) {
|
|
197
|
-
mkdirSync(join(dest, '.junie'), { recursive: true });
|
|
198
|
-
installWrapper(dest, '.junie/guidelines.md',
|
|
199
|
-
`# Junie Guidelines\n\nFollow all instructions in the root AGENTS.md file as the primary context for this repository.\n`,
|
|
200
|
-
values.force);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// ── 7. Create .aiignore if missing ──────────────────────────────
|
|
146
|
+
// ── 4. .aiignore ──────────────────────────────────────────────────
|
|
204
147
|
installWrapper(dest, '.aiignore',
|
|
205
148
|
`# AI Agent Ignore File
|
|
206
149
|
# Prevents AI tools from reading sensitive or irrelevant files
|
|
@@ -230,44 +173,148 @@ __pycache__/
|
|
|
230
173
|
.vscode/launch.json
|
|
231
174
|
.DS_Store
|
|
232
175
|
`,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
// ── Summary
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if (
|
|
240
|
-
console.log(`\n${bold(
|
|
241
|
-
console.log(` 1. Run ${green('claude /garden-bootstrap')} to generate AGENTS.md`);
|
|
242
|
-
console.log(` 2. Run ${green('claude /garden-audit')} to verify accuracy`);
|
|
243
|
-
console.log(` 3. Run ${green('claude /garden-extend')} to add guardrails & principles`);
|
|
176
|
+
force, dryRun);
|
|
177
|
+
|
|
178
|
+
// ── Summary ───────────────────────────────────────────────────────
|
|
179
|
+
if (dryRun) {
|
|
180
|
+
console.log(`\n${yellow(bold('Dry run complete'))} — nothing was written.\n`);
|
|
181
|
+
console.log(`Run without ${dim('--dry-run')} to install.\n`);
|
|
182
|
+
} else if (isUpgrade) {
|
|
183
|
+
console.log(`\n🌱 ${bold(`Upgrade complete!`)} ${dim(`(v${installedVersion} → v${VERSION})`)}\n`);
|
|
244
184
|
} else {
|
|
245
|
-
console.log(`\n${bold('
|
|
246
|
-
console.log(` 1. Run ${green('claude /garden-agent-gardener')} for interactive maintenance`);
|
|
247
|
-
console.log(` 2. Run ${green('claude /garden-audit')} to check for drift`);
|
|
185
|
+
console.log(`\n🌱 ${bold('Installation complete!')}\n`);
|
|
248
186
|
}
|
|
249
187
|
|
|
188
|
+
console.log(`${bold('Installed:')}`);
|
|
189
|
+
console.log(` Core system, ${gardenCmds.length} skill commands, CLAUDE.md, .aiignore\n`);
|
|
190
|
+
|
|
191
|
+
console.log(`${bold('Next steps:')}`);
|
|
192
|
+
console.log(` 1. Run ${green('claude /garden-bootstrap')} to set up AI-ready documentation`);
|
|
193
|
+
console.log(` ${dim('Creates AGENTS.md + wrappers for your AI tools (Copilot, Cursor, etc.)')}`);
|
|
194
|
+
console.log(` 2. Run ${green('claude /garden-audit')} to verify accuracy`);
|
|
195
|
+
console.log(` 3. Run ${green('claude /garden-extend')} to add guardrails & principles`);
|
|
196
|
+
|
|
197
|
+
console.log(`\n${dim('Gary currently runs on Claude Code. Wrappers for other tools are')}`);
|
|
198
|
+
console.log(`${dim('created by the agent during bootstrap — run /garden-bootstrap to start.')}`);
|
|
199
|
+
|
|
250
200
|
console.log(`\n🪴 Happy gardening!\n`);
|
|
201
|
+
}
|
|
251
202
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
203
|
+
function runStatus() {
|
|
204
|
+
const dest = process.cwd();
|
|
205
|
+
|
|
206
|
+
console.log(`\n🪴 ${bold('Garden System — Status')}\n`);
|
|
207
|
+
|
|
208
|
+
// Core system
|
|
209
|
+
const coreInstalled = existsSync(join(dest, '_gs-gardener', 'core'));
|
|
210
|
+
let coreVersion = '';
|
|
211
|
+
if (coreInstalled) {
|
|
212
|
+
try {
|
|
213
|
+
coreVersion = readFileSync(join(dest, '_gs-gardener', 'VERSION'), 'utf8').trim();
|
|
214
|
+
} catch { /* ignore */ }
|
|
215
|
+
}
|
|
216
|
+
statusLine('Core system', coreInstalled, coreInstalled ? `v${coreVersion}` : null);
|
|
217
|
+
|
|
218
|
+
// Claude Code
|
|
219
|
+
const claudeMd = existsSync(join(dest, 'CLAUDE.md'));
|
|
220
|
+
const cmdDir = join(dest, '.claude', 'commands');
|
|
221
|
+
let cmdCount = 0;
|
|
222
|
+
if (existsSync(cmdDir)) {
|
|
223
|
+
cmdCount = readdirSync(cmdDir).filter(f => f.startsWith('garden-') && f.endsWith('.md')).length;
|
|
224
|
+
}
|
|
225
|
+
statusLine('Claude Code', claudeMd || cmdCount > 0,
|
|
226
|
+
(claudeMd || cmdCount > 0) ? `CLAUDE.md + ${cmdCount} commands` : null);
|
|
227
|
+
|
|
228
|
+
// AGENTS.md
|
|
229
|
+
const agentsExists = existsSync(join(dest, 'AGENTS.md'));
|
|
230
|
+
console.log(` ${agentsExists ? green('✓') : '○'} ${('AGENTS.md').padEnd(15)} ${agentsExists ? green('present') : yellow('not yet created (run /garden-bootstrap)')}`);
|
|
231
|
+
|
|
232
|
+
// .aiignore
|
|
233
|
+
statusLine('.aiignore', existsSync(join(dest, '.aiignore')), 'present');
|
|
234
|
+
|
|
235
|
+
// Wrappers (produced by the agent, not the CLI)
|
|
236
|
+
console.log(`\n ${dim('Wrappers (created by /garden-bootstrap):')}`);
|
|
237
|
+
wrapperLine('Copilot', join(dest, '.github', 'copilot-instructions.md'));
|
|
238
|
+
wrapperLine('Cursor', join(dest, '.cursor', 'rules', 'agents.mdc'));
|
|
239
|
+
wrapperLine('Codex', join(dest, 'codex.md'));
|
|
240
|
+
wrapperLine('Junie', join(dest, '.junie', 'guidelines.md'));
|
|
241
|
+
|
|
242
|
+
console.log('');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
246
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
247
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
248
|
+
|
|
249
|
+
function readInstalledVersion(coreDest) {
|
|
250
|
+
try {
|
|
251
|
+
return readFileSync(join(coreDest, 'VERSION'), 'utf8').trim();
|
|
252
|
+
} catch {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function safeReadFile(filePath) {
|
|
258
|
+
try {
|
|
259
|
+
return readFileSync(filePath, 'utf8');
|
|
260
|
+
} catch {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
256
263
|
}
|
|
257
264
|
|
|
258
|
-
|
|
265
|
+
function defaultConfig(projectName) {
|
|
266
|
+
return `# Garden System Configuration
|
|
267
|
+
# Version: ${VERSION}
|
|
268
|
+
|
|
269
|
+
project_name: ${projectName}
|
|
270
|
+
user_name: User
|
|
271
|
+
communication_language: English
|
|
272
|
+
output_folder: "{project-root}/docs"
|
|
273
|
+
|
|
274
|
+
# Coverage tracking
|
|
275
|
+
agents_file: "{project-root}/AGENTS.md"
|
|
276
|
+
wrapper_files:
|
|
277
|
+
- "{project-root}/CLAUDE.md"
|
|
278
|
+
- "{project-root}/.github/copilot-instructions.md"
|
|
279
|
+
- "{project-root}/.cursor/rules/agents.mdc"
|
|
280
|
+
- "{project-root}/.junie/guidelines.md"
|
|
281
|
+
|
|
282
|
+
# Content layers
|
|
283
|
+
docs_directory: "{project-root}/docs"
|
|
284
|
+
references_directory: "{project-root}/docs/references"
|
|
259
285
|
|
|
260
|
-
|
|
286
|
+
# Constraints
|
|
287
|
+
agents_max_lines: 150
|
|
288
|
+
|
|
289
|
+
# Garden System Version
|
|
290
|
+
version: "${VERSION}"
|
|
291
|
+
`;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function installWrapper(dest, relPath, content, force, dryRun) {
|
|
261
295
|
const fullPath = join(dest, relPath);
|
|
262
296
|
if (existsSync(fullPath) && !force) {
|
|
263
297
|
console.log(` ${yellow('⚠')} ${relPath} already exists — skipping`);
|
|
264
298
|
return false;
|
|
265
299
|
}
|
|
266
|
-
writeFileSync(fullPath, content);
|
|
300
|
+
if (!dryRun) writeFileSync(fullPath, content);
|
|
267
301
|
console.log(` ${green('✓')} ${relPath}`);
|
|
268
302
|
return true;
|
|
269
303
|
}
|
|
270
304
|
|
|
305
|
+
function statusLine(label, installed, detail) {
|
|
306
|
+
const icon = installed ? green('✓') : '✗';
|
|
307
|
+
const text = installed ? green(detail || 'installed') : dim('not installed');
|
|
308
|
+
console.log(` ${icon} ${label.padEnd(15)} ${text}`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function wrapperLine(label, filePath) {
|
|
312
|
+
const exists = existsSync(filePath);
|
|
313
|
+
const icon = exists ? green('✓') : dim('·');
|
|
314
|
+
const text = exists ? green('present') : dim('—');
|
|
315
|
+
console.log(` ${icon} ${label.padEnd(13)} ${text}`);
|
|
316
|
+
}
|
|
317
|
+
|
|
271
318
|
function safeReadJson(path) {
|
|
272
319
|
try {
|
|
273
320
|
return JSON.parse(readFileSync(path, 'utf8'));
|
|
@@ -275,3 +322,38 @@ function safeReadJson(path) {
|
|
|
275
322
|
return null;
|
|
276
323
|
}
|
|
277
324
|
}
|
|
325
|
+
|
|
326
|
+
function printHelp() {
|
|
327
|
+
console.log(`
|
|
328
|
+
${bold('gary-the-gardener')} v${VERSION} — Garden System installer
|
|
329
|
+
|
|
330
|
+
${bold('USAGE')}
|
|
331
|
+
npx @pshch/gary-the-gardener [command] [options]
|
|
332
|
+
|
|
333
|
+
${bold('COMMANDS')}
|
|
334
|
+
${green('install')} Install Gary the Gardener ${dim('(default if no command given)')}
|
|
335
|
+
${green('status')} Show what's currently installed
|
|
336
|
+
|
|
337
|
+
${bold('WHAT GETS INSTALLED')}
|
|
338
|
+
The installer sets up Gary the Gardener agent for Claude Code:
|
|
339
|
+
• Core system ${dim('(_gs-gardener/)')}
|
|
340
|
+
• Skill commands ${dim('(.claude/commands/garden-*.md)')}
|
|
341
|
+
• CLAUDE.md ${dim('(points Claude to AGENTS.md)')}
|
|
342
|
+
• .aiignore ${dim('(keeps secrets out of AI context)')}
|
|
343
|
+
|
|
344
|
+
After installing, run ${green('claude /garden-bootstrap')} to generate
|
|
345
|
+
AGENTS.md and wrappers for your other AI tools (Copilot, Cursor, etc.).
|
|
346
|
+
|
|
347
|
+
${bold('OPTIONS')}
|
|
348
|
+
-n, --dry-run Show what would be installed, without writing files
|
|
349
|
+
-f, --force Overwrite existing files
|
|
350
|
+
-v, --version Show version
|
|
351
|
+
-h, --help Show this help
|
|
352
|
+
|
|
353
|
+
${bold('EXAMPLES')}
|
|
354
|
+
npx @pshch/gary-the-gardener ${dim('# install the agent')}
|
|
355
|
+
npx @pshch/gary-the-gardener install ${dim('# same as above')}
|
|
356
|
+
npx @pshch/gary-the-gardener status ${dim('# check install state')}
|
|
357
|
+
npx @pshch/gary-the-gardener -f ${dim('# reinstall / upgrade')}
|
|
358
|
+
`);
|
|
359
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pshch/gary-the-gardener",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Gary the Gardener — AI agent that maintains documentation and config for Claude, Copilot, Cursor, Codex, and Junie",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"gary-the-gardener": "./bin/cli.js",
|