@aslomon/effectum 0.2.0 → 0.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/README.md +23 -16
- package/bin/install.js +187 -112
- package/bin/lib/app-types.js +96 -0
- package/bin/lib/config.js +22 -3
- package/bin/lib/constants.js +14 -30
- package/bin/lib/foundation.js +63 -0
- package/bin/lib/languages.js +77 -0
- package/bin/lib/recommendation.js +392 -0
- package/bin/lib/specializations.js +123 -0
- package/bin/lib/template.js +2 -1
- package/bin/lib/ui.js +375 -21
- package/bin/reconfigure.js +32 -6
- package/package.json +2 -2
package/bin/lib/ui.js
CHANGED
|
@@ -1,21 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared @clack/prompts helpers and display utilities.
|
|
3
|
+
* Uses dynamic import() because @clack/prompts is ESM-only.
|
|
4
|
+
*
|
|
5
|
+
* Supports the 9-step intelligent setup flow:
|
|
6
|
+
* 1. Install Scope 2. Project Basics 3. App Type 4. Description
|
|
7
|
+
* 5. Language 6. Autonomy 7. Recommendation Preview 8. Decision 9. Install
|
|
3
8
|
*/
|
|
4
9
|
"use strict";
|
|
5
10
|
|
|
6
|
-
const
|
|
11
|
+
const { STACK_CHOICES, AUTONOMY_CHOICES, MCP_SERVERS } = require("./constants");
|
|
12
|
+
const { LANGUAGE_CHOICES } = require("./languages");
|
|
13
|
+
const { APP_TYPE_CHOICES } = require("./app-types");
|
|
14
|
+
const { FOUNDATION_HOOKS } = require("./foundation");
|
|
7
15
|
const {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
getAllCommands,
|
|
17
|
+
getAllHooks,
|
|
18
|
+
getAllSkills,
|
|
19
|
+
getAllMcps,
|
|
20
|
+
getAllSubagents,
|
|
21
|
+
} = require("./recommendation");
|
|
22
|
+
|
|
23
|
+
/** @type {import("@clack/prompts")} */
|
|
24
|
+
let p;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Initialize @clack/prompts (ESM module). Must be called once before using prompts.
|
|
28
|
+
* @returns {Promise<import("@clack/prompts")>}
|
|
29
|
+
*/
|
|
30
|
+
async function initClack() {
|
|
31
|
+
if (!p) {
|
|
32
|
+
p = await import("@clack/prompts");
|
|
33
|
+
}
|
|
34
|
+
return p;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get the loaded clack instance.
|
|
39
|
+
* @returns {import("@clack/prompts")}
|
|
40
|
+
*/
|
|
41
|
+
function getClack() {
|
|
42
|
+
if (!p) throw new Error("Call initClack() before using prompts");
|
|
43
|
+
return p;
|
|
44
|
+
}
|
|
13
45
|
|
|
14
46
|
/**
|
|
15
47
|
* Print the Effectum banner via clack intro.
|
|
16
48
|
*/
|
|
17
49
|
function printBanner() {
|
|
18
|
-
p.intro("EFFECTUM —
|
|
50
|
+
p.intro("EFFECTUM — Intelligent Setup for Claude Code");
|
|
19
51
|
}
|
|
20
52
|
|
|
21
53
|
/**
|
|
@@ -29,6 +61,35 @@ function handleCancel(value) {
|
|
|
29
61
|
}
|
|
30
62
|
}
|
|
31
63
|
|
|
64
|
+
// ─── Step 1: Install Scope ──────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Ask for install scope.
|
|
68
|
+
* @returns {Promise<string>} "local" or "global"
|
|
69
|
+
*/
|
|
70
|
+
async function askScope() {
|
|
71
|
+
const value = await p.select({
|
|
72
|
+
message: "Install scope",
|
|
73
|
+
options: [
|
|
74
|
+
{
|
|
75
|
+
value: "local",
|
|
76
|
+
label: "Local",
|
|
77
|
+
hint: "This project only (./.claude/)",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
value: "global",
|
|
81
|
+
label: "Global",
|
|
82
|
+
hint: "All projects (~/.claude/)",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
initialValue: "local",
|
|
86
|
+
});
|
|
87
|
+
handleCancel(value);
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ─── Step 2: Project Basics ─────────────────────────────────────────────────
|
|
92
|
+
|
|
32
93
|
/**
|
|
33
94
|
* Ask for project name with a detected default.
|
|
34
95
|
* @param {string} detected
|
|
@@ -66,6 +127,47 @@ async function askStack(detected) {
|
|
|
66
127
|
return value;
|
|
67
128
|
}
|
|
68
129
|
|
|
130
|
+
// ─── Step 3: App Type ───────────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Ask for app type selection.
|
|
134
|
+
* @returns {Promise<string>}
|
|
135
|
+
*/
|
|
136
|
+
async function askAppType() {
|
|
137
|
+
const value = await p.select({
|
|
138
|
+
message: "What are you building?",
|
|
139
|
+
options: APP_TYPE_CHOICES.map((c) => ({
|
|
140
|
+
value: c.value,
|
|
141
|
+
label: c.label,
|
|
142
|
+
hint: c.hint,
|
|
143
|
+
})),
|
|
144
|
+
initialValue: "web-app",
|
|
145
|
+
});
|
|
146
|
+
handleCancel(value);
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ─── Step 4: Description ────────────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Ask for a free-text project description.
|
|
154
|
+
* @returns {Promise<string>}
|
|
155
|
+
*/
|
|
156
|
+
async function askDescription() {
|
|
157
|
+
const value = await p.text({
|
|
158
|
+
message: "Describe what you want to build (one sentence)",
|
|
159
|
+
placeholder: "e.g. An internal CRM dashboard with auth and analytics",
|
|
160
|
+
validate: (v) => {
|
|
161
|
+
if (!v.trim())
|
|
162
|
+
return "A short description helps generate better recommendations";
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
handleCancel(value);
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ─── Step 5: Language ───────────────────────────────────────────────────────
|
|
170
|
+
|
|
69
171
|
/**
|
|
70
172
|
* Ask for communication language.
|
|
71
173
|
* @returns {Promise<{ language: string, customLanguage?: string }>}
|
|
@@ -97,13 +199,15 @@ async function askLanguage() {
|
|
|
97
199
|
return { language: value };
|
|
98
200
|
}
|
|
99
201
|
|
|
202
|
+
// ─── Step 6: Autonomy ───────────────────────────────────────────────────────
|
|
203
|
+
|
|
100
204
|
/**
|
|
101
205
|
* Ask for autonomy level.
|
|
102
206
|
* @returns {Promise<string>}
|
|
103
207
|
*/
|
|
104
208
|
async function askAutonomy() {
|
|
105
209
|
const value = await p.select({
|
|
106
|
-
message: "
|
|
210
|
+
message: "How should Claude work?",
|
|
107
211
|
options: AUTONOMY_CHOICES.map((c) => ({
|
|
108
212
|
value: c.value,
|
|
109
213
|
label: c.label,
|
|
@@ -115,6 +219,232 @@ async function askAutonomy() {
|
|
|
115
219
|
return value;
|
|
116
220
|
}
|
|
117
221
|
|
|
222
|
+
// ─── Step 7: Recommendation Preview ─────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Display the recommendation preview.
|
|
226
|
+
* @param {object} rec - recommendation from recommend()
|
|
227
|
+
*/
|
|
228
|
+
function showRecommendation(rec) {
|
|
229
|
+
const lines = [];
|
|
230
|
+
|
|
231
|
+
lines.push("FOUNDATION (always active)");
|
|
232
|
+
for (const h of FOUNDATION_HOOKS) {
|
|
233
|
+
lines.push(` + ${h.label}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
lines.push("");
|
|
237
|
+
lines.push("RECOMMENDED COMMANDS");
|
|
238
|
+
for (const key of rec.commands) {
|
|
239
|
+
lines.push(` + /${key}`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
lines.push("");
|
|
243
|
+
lines.push("RECOMMENDED HOOKS");
|
|
244
|
+
for (const key of rec.hooks) {
|
|
245
|
+
lines.push(` + ${key}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (rec.skills.length > 0) {
|
|
249
|
+
lines.push("");
|
|
250
|
+
lines.push("RECOMMENDED SKILLS");
|
|
251
|
+
for (const key of rec.skills) {
|
|
252
|
+
lines.push(` + ${key}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
lines.push("");
|
|
257
|
+
lines.push("RECOMMENDED MCP SERVERS");
|
|
258
|
+
for (const key of rec.mcps) {
|
|
259
|
+
const server = MCP_SERVERS.find((s) => s.key === key);
|
|
260
|
+
lines.push(` + ${server ? server.label : key}`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
lines.push("");
|
|
264
|
+
lines.push("RECOMMENDED SUBAGENT SPECIALIZATIONS");
|
|
265
|
+
for (const key of rec.subagents) {
|
|
266
|
+
lines.push(` + ${key}`);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
lines.push("");
|
|
270
|
+
lines.push("AGENT TEAMS: disabled (experimental, enable manually)");
|
|
271
|
+
|
|
272
|
+
p.note(lines.join("\n"), "Recommended Setup");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ─── Step 8: Decision ───────────────────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Ask user how to proceed with the recommendation.
|
|
279
|
+
* @returns {Promise<string>} "recommended" | "customize" | "manual"
|
|
280
|
+
*/
|
|
281
|
+
async function askSetupMode() {
|
|
282
|
+
const value = await p.select({
|
|
283
|
+
message: "How do you want to proceed?",
|
|
284
|
+
options: [
|
|
285
|
+
{
|
|
286
|
+
value: "recommended",
|
|
287
|
+
label: "Use Recommended",
|
|
288
|
+
hint: "Install the recommended setup as-is",
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
value: "customize",
|
|
292
|
+
label: "Customize",
|
|
293
|
+
hint: "Start from recommendations, toggle items on/off",
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
value: "manual",
|
|
297
|
+
label: "Manual Selection",
|
|
298
|
+
hint: "Choose everything yourself from scratch",
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
initialValue: "recommended",
|
|
302
|
+
});
|
|
303
|
+
handleCancel(value);
|
|
304
|
+
return value;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Let user customize the recommended setup by toggling items.
|
|
309
|
+
* @param {object} rec - current recommendation
|
|
310
|
+
* @returns {Promise<object>} modified recommendation
|
|
311
|
+
*/
|
|
312
|
+
async function askCustomize(rec) {
|
|
313
|
+
const result = { ...rec };
|
|
314
|
+
|
|
315
|
+
// Commands
|
|
316
|
+
const commands = await p.multiselect({
|
|
317
|
+
message: "Commands (space to toggle)",
|
|
318
|
+
options: getAllCommands().map((c) => ({
|
|
319
|
+
value: c.key,
|
|
320
|
+
label: c.label,
|
|
321
|
+
})),
|
|
322
|
+
initialValues: rec.commands,
|
|
323
|
+
required: false,
|
|
324
|
+
});
|
|
325
|
+
handleCancel(commands);
|
|
326
|
+
result.commands = commands;
|
|
327
|
+
|
|
328
|
+
// Skills
|
|
329
|
+
const skills = await p.multiselect({
|
|
330
|
+
message: "Skills (space to toggle)",
|
|
331
|
+
options: getAllSkills().map((s) => ({
|
|
332
|
+
value: s.key,
|
|
333
|
+
label: s.label,
|
|
334
|
+
})),
|
|
335
|
+
initialValues: rec.skills,
|
|
336
|
+
required: false,
|
|
337
|
+
});
|
|
338
|
+
handleCancel(skills);
|
|
339
|
+
result.skills = skills;
|
|
340
|
+
|
|
341
|
+
// MCP servers
|
|
342
|
+
const mcps = await p.multiselect({
|
|
343
|
+
message: "MCP servers (space to toggle)",
|
|
344
|
+
options: getAllMcps().map((m) => ({
|
|
345
|
+
value: m.key,
|
|
346
|
+
label: m.label,
|
|
347
|
+
hint: m.desc,
|
|
348
|
+
})),
|
|
349
|
+
initialValues: rec.mcps,
|
|
350
|
+
required: false,
|
|
351
|
+
});
|
|
352
|
+
handleCancel(mcps);
|
|
353
|
+
result.mcps = mcps;
|
|
354
|
+
|
|
355
|
+
// Subagent specializations
|
|
356
|
+
const subagents = await p.multiselect({
|
|
357
|
+
message: "Subagent specializations (space to toggle)",
|
|
358
|
+
options: getAllSubagents().map((s) => ({
|
|
359
|
+
value: s.key,
|
|
360
|
+
label: s.label,
|
|
361
|
+
})),
|
|
362
|
+
initialValues: rec.subagents,
|
|
363
|
+
required: false,
|
|
364
|
+
});
|
|
365
|
+
handleCancel(subagents);
|
|
366
|
+
result.subagents = subagents;
|
|
367
|
+
|
|
368
|
+
// Agent Teams (experimental)
|
|
369
|
+
const agentTeams = await p.confirm({
|
|
370
|
+
message: "Enable Agent Teams? (experimental, advanced)",
|
|
371
|
+
initialValue: false,
|
|
372
|
+
});
|
|
373
|
+
handleCancel(agentTeams);
|
|
374
|
+
result.agentTeams = agentTeams;
|
|
375
|
+
|
|
376
|
+
return result;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Full manual selection — nothing pre-selected.
|
|
381
|
+
* @returns {Promise<object>} user-selected setup
|
|
382
|
+
*/
|
|
383
|
+
async function askManual() {
|
|
384
|
+
const commands = await p.multiselect({
|
|
385
|
+
message: "Select commands",
|
|
386
|
+
options: getAllCommands().map((c) => ({
|
|
387
|
+
value: c.key,
|
|
388
|
+
label: c.label,
|
|
389
|
+
})),
|
|
390
|
+
initialValues: [],
|
|
391
|
+
required: false,
|
|
392
|
+
});
|
|
393
|
+
handleCancel(commands);
|
|
394
|
+
|
|
395
|
+
const skills = await p.multiselect({
|
|
396
|
+
message: "Select skills",
|
|
397
|
+
options: getAllSkills().map((s) => ({
|
|
398
|
+
value: s.key,
|
|
399
|
+
label: s.label,
|
|
400
|
+
})),
|
|
401
|
+
initialValues: [],
|
|
402
|
+
required: false,
|
|
403
|
+
});
|
|
404
|
+
handleCancel(skills);
|
|
405
|
+
|
|
406
|
+
const mcps = await p.multiselect({
|
|
407
|
+
message: "Select MCP servers",
|
|
408
|
+
options: getAllMcps().map((m) => ({
|
|
409
|
+
value: m.key,
|
|
410
|
+
label: m.label,
|
|
411
|
+
hint: m.desc,
|
|
412
|
+
})),
|
|
413
|
+
initialValues: [],
|
|
414
|
+
required: false,
|
|
415
|
+
});
|
|
416
|
+
handleCancel(mcps);
|
|
417
|
+
|
|
418
|
+
const subagents = await p.multiselect({
|
|
419
|
+
message: "Select subagent specializations",
|
|
420
|
+
options: getAllSubagents().map((s) => ({
|
|
421
|
+
value: s.key,
|
|
422
|
+
label: s.label,
|
|
423
|
+
})),
|
|
424
|
+
initialValues: [],
|
|
425
|
+
required: false,
|
|
426
|
+
});
|
|
427
|
+
handleCancel(subagents);
|
|
428
|
+
|
|
429
|
+
const agentTeams = await p.confirm({
|
|
430
|
+
message: "Enable Agent Teams? (experimental, advanced)",
|
|
431
|
+
initialValue: false,
|
|
432
|
+
});
|
|
433
|
+
handleCancel(agentTeams);
|
|
434
|
+
|
|
435
|
+
return {
|
|
436
|
+
commands,
|
|
437
|
+
hooks: getAllHooks().map((h) => h.key),
|
|
438
|
+
skills,
|
|
439
|
+
mcps,
|
|
440
|
+
subagents,
|
|
441
|
+
agentTeams,
|
|
442
|
+
tags: [],
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// ─── Legacy prompts (kept for backward compat) ──────────────────────────────
|
|
447
|
+
|
|
118
448
|
/**
|
|
119
449
|
* Ask which MCP servers to install via multi-select.
|
|
120
450
|
* @returns {Promise<string[]>}
|
|
@@ -169,6 +499,8 @@ async function askGitBranch() {
|
|
|
169
499
|
return { create: true, name };
|
|
170
500
|
}
|
|
171
501
|
|
|
502
|
+
// ─── Display helpers ────────────────────────────────────────────────────────
|
|
503
|
+
|
|
172
504
|
/**
|
|
173
505
|
* Display a summary note.
|
|
174
506
|
* @param {object} config
|
|
@@ -176,17 +508,29 @@ async function askGitBranch() {
|
|
|
176
508
|
*/
|
|
177
509
|
function showSummary(config, files) {
|
|
178
510
|
const lines = [
|
|
179
|
-
`Project:
|
|
180
|
-
`Stack:
|
|
181
|
-
`
|
|
182
|
-
`
|
|
183
|
-
`
|
|
184
|
-
`
|
|
185
|
-
`
|
|
186
|
-
""
|
|
187
|
-
`Files created/updated:`,
|
|
188
|
-
...files.map((f) => ` ${f}`),
|
|
511
|
+
`Project: ${config.projectName}`,
|
|
512
|
+
`Stack: ${config.stack}`,
|
|
513
|
+
`App Type: ${config.appType || "n/a"}`,
|
|
514
|
+
`Language: ${config.language}`,
|
|
515
|
+
`Autonomy: ${config.autonomyLevel}`,
|
|
516
|
+
`Pkg Manager: ${config.packageManager}`,
|
|
517
|
+
`Formatter: ${config.formatter}`,
|
|
518
|
+
`Mode: ${config.mode || "recommended"}`,
|
|
189
519
|
];
|
|
520
|
+
|
|
521
|
+
if (config.recommended) {
|
|
522
|
+
lines.push(
|
|
523
|
+
`Commands: ${config.recommended.commands.length}`,
|
|
524
|
+
`Skills: ${config.recommended.skills.length}`,
|
|
525
|
+
`MCPs: ${config.recommended.mcps.length}`,
|
|
526
|
+
`Subagents: ${config.recommended.subagents.length}`,
|
|
527
|
+
`Agent Teams: ${config.recommended.agentTeams ? "enabled" : "disabled"}`,
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
lines.push("", `Files created/updated:`);
|
|
532
|
+
lines.push(...files.map((f) => ` ${f}`));
|
|
533
|
+
|
|
190
534
|
p.note(lines.join("\n"), "Configuration Summary");
|
|
191
535
|
}
|
|
192
536
|
|
|
@@ -196,9 +540,7 @@ function showSummary(config, files) {
|
|
|
196
540
|
*/
|
|
197
541
|
function showOutro(isGlobal) {
|
|
198
542
|
if (isGlobal) {
|
|
199
|
-
p.outro(
|
|
200
|
-
"Effectum ready! In any project, run: npx @aslomon/effectum init",
|
|
201
|
-
);
|
|
543
|
+
p.outro("Effectum ready! In any project, run: npx @aslomon/effectum init");
|
|
202
544
|
} else {
|
|
203
545
|
p.outro(
|
|
204
546
|
"Effectum ready! Open Claude Code here and start building. Try /plan or /prd:new",
|
|
@@ -207,15 +549,27 @@ function showOutro(isGlobal) {
|
|
|
207
549
|
}
|
|
208
550
|
|
|
209
551
|
module.exports = {
|
|
552
|
+
initClack,
|
|
553
|
+
getClack,
|
|
210
554
|
printBanner,
|
|
211
555
|
handleCancel,
|
|
556
|
+
// Step prompts
|
|
557
|
+
askScope,
|
|
212
558
|
askProjectName,
|
|
213
559
|
askStack,
|
|
560
|
+
askAppType,
|
|
561
|
+
askDescription,
|
|
214
562
|
askLanguage,
|
|
215
563
|
askAutonomy,
|
|
564
|
+
showRecommendation,
|
|
565
|
+
askSetupMode,
|
|
566
|
+
askCustomize,
|
|
567
|
+
askManual,
|
|
568
|
+
// Legacy / utility prompts
|
|
216
569
|
askMcpServers,
|
|
217
570
|
askPlaywright,
|
|
218
571
|
askGitBranch,
|
|
572
|
+
// Display
|
|
219
573
|
showSummary,
|
|
220
574
|
showOutro,
|
|
221
575
|
};
|
package/bin/reconfigure.js
CHANGED
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Reconfigure — re-apply settings from .effectum.json.
|
|
4
4
|
* Reads the saved config and regenerates CLAUDE.md, settings.json, guardrails.md.
|
|
5
|
+
* Supports v0.4.0 config schema with appType, description, recommended setup.
|
|
5
6
|
*/
|
|
6
7
|
"use strict";
|
|
7
8
|
|
|
8
9
|
const fs = require("fs");
|
|
9
10
|
const path = require("path");
|
|
10
|
-
const p = require("@clack/prompts");
|
|
11
|
-
|
|
12
11
|
const { readConfig } = require("./lib/config");
|
|
13
12
|
const { loadStackPreset } = require("./lib/stack-parser");
|
|
14
13
|
const {
|
|
15
14
|
buildSubstitutionMap,
|
|
16
15
|
renderTemplate,
|
|
17
16
|
findTemplatePath,
|
|
18
|
-
findRemainingPlaceholders,
|
|
19
|
-
substituteAll,
|
|
20
17
|
} = require("./lib/template");
|
|
21
18
|
const { AUTONOMY_MAP, FORMATTER_MAP } = require("./lib/constants");
|
|
22
19
|
const { ensureDir, deepMerge, findRepoRoot } = require("./lib/utils");
|
|
20
|
+
const { initClack } = require("./lib/ui");
|
|
21
|
+
const { recommend } = require("./lib/recommendation");
|
|
22
|
+
const { writeConfig } = require("./lib/config");
|
|
23
23
|
|
|
24
24
|
// ─── Main ─────────────────────────────────────────────────────────────────
|
|
25
25
|
|
|
@@ -29,6 +29,7 @@ async function main() {
|
|
|
29
29
|
const targetDir = process.cwd();
|
|
30
30
|
const repoRoot = findRepoRoot();
|
|
31
31
|
|
|
32
|
+
const p = await initClack();
|
|
32
33
|
p.intro("EFFECTUM — Reconfigure");
|
|
33
34
|
|
|
34
35
|
// Read existing config
|
|
@@ -40,7 +41,24 @@ async function main() {
|
|
|
40
41
|
process.exit(1);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
// Re-run recommendation engine with current config values
|
|
45
|
+
if (config.appType || config.description) {
|
|
46
|
+
const rec = recommend({
|
|
47
|
+
stack: config.stack,
|
|
48
|
+
appType: config.appType || "web-app",
|
|
49
|
+
description: config.description || "",
|
|
50
|
+
autonomyLevel: config.autonomyLevel || "standard",
|
|
51
|
+
language: config.language || "english",
|
|
52
|
+
});
|
|
53
|
+
config.recommended = rec;
|
|
54
|
+
// Persist updated recommendations
|
|
55
|
+
writeConfig(targetDir, config);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const configInfo = [`"${config.projectName}" (${config.stack})`];
|
|
59
|
+
if (config.appType) configInfo.push(`type: ${config.appType}`);
|
|
60
|
+
if (config.mode) configInfo.push(`mode: ${config.mode}`);
|
|
61
|
+
p.log.info(`Reconfiguring ${configInfo.join(", ")}`);
|
|
44
62
|
|
|
45
63
|
if (dryRun) {
|
|
46
64
|
p.note(JSON.stringify(config, null, 2), "Current Configuration");
|
|
@@ -94,6 +112,14 @@ async function main() {
|
|
|
94
112
|
deny: settingsObj.permissions?.deny || [],
|
|
95
113
|
};
|
|
96
114
|
|
|
115
|
+
// Apply Agent Teams env var from saved config
|
|
116
|
+
if (settingsObj.env && config.recommended) {
|
|
117
|
+
settingsObj.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = config.recommended
|
|
118
|
+
.agentTeams
|
|
119
|
+
? "1"
|
|
120
|
+
: "0";
|
|
121
|
+
}
|
|
122
|
+
|
|
97
123
|
const formatter = FORMATTER_MAP[config.stack] || FORMATTER_MAP.generic;
|
|
98
124
|
if (settingsObj.hooks?.PostToolUse) {
|
|
99
125
|
for (const group of settingsObj.hooks.PostToolUse) {
|
|
@@ -165,6 +191,6 @@ async function main() {
|
|
|
165
191
|
}
|
|
166
192
|
|
|
167
193
|
main().catch((err) => {
|
|
168
|
-
|
|
194
|
+
console.error(`Fatal error: ${err.message}`);
|
|
169
195
|
process.exit(1);
|
|
170
196
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aslomon/effectum",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Autonomous development system for Claude Code
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Autonomous development system for Claude Code \u2014 describe what you want, get production-ready code",
|
|
5
5
|
"bin": {
|
|
6
6
|
"effectum": "bin/effectum.js"
|
|
7
7
|
},
|