@aslomon/effectum 0.2.1 → 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.
@@ -0,0 +1,96 @@
1
+ /**
2
+ * App type definitions and intent-based tag mappings.
3
+ * Used by the recommendation engine to derive setup from project intent.
4
+ */
5
+ "use strict";
6
+
7
+ /** @type {Array<{ value: string, label: string, hint: string }>} */
8
+ const APP_TYPE_CHOICES = [
9
+ {
10
+ value: "web-app",
11
+ label: "Web App",
12
+ hint: "Full-stack web application with UI",
13
+ },
14
+ {
15
+ value: "api-backend",
16
+ label: "API / Backend",
17
+ hint: "REST or GraphQL API service",
18
+ },
19
+ {
20
+ value: "mobile-app",
21
+ label: "Mobile App",
22
+ hint: "iOS, Android, or cross-platform",
23
+ },
24
+ {
25
+ value: "desktop-app",
26
+ label: "Desktop App",
27
+ hint: "Native or Electron desktop application",
28
+ },
29
+ {
30
+ value: "cli-tool",
31
+ label: "CLI Tool",
32
+ hint: "Command-line interface tool",
33
+ },
34
+ {
35
+ value: "automation-agent",
36
+ label: "Automation / Agent System",
37
+ hint: "AI agents, bots, automation workflows",
38
+ },
39
+ {
40
+ value: "data-ml",
41
+ label: "Data / ML Tool",
42
+ hint: "Data pipeline, ML model, analytics",
43
+ },
44
+ {
45
+ value: "library-sdk",
46
+ label: "Library / SDK",
47
+ hint: "Reusable package or framework",
48
+ },
49
+ {
50
+ value: "other",
51
+ label: "Other",
52
+ hint: "Something else entirely",
53
+ },
54
+ ];
55
+
56
+ /**
57
+ * Tags implicitly associated with each app type.
58
+ * These are combined with stack and description tags to drive recommendations.
59
+ * @type {Record<string, string[]>}
60
+ */
61
+ const APP_TYPE_TAGS = {
62
+ "web-app": [
63
+ "frontend-heavy",
64
+ "auth-needed",
65
+ "db-needed",
66
+ "multi-user",
67
+ "ui-design",
68
+ ],
69
+ "api-backend": [
70
+ "api-first",
71
+ "db-needed",
72
+ "auth-needed",
73
+ "backend-heavy",
74
+ "docs-needed",
75
+ ],
76
+ "mobile-app": ["frontend-heavy", "native-ui", "offline-capable", "ui-design"],
77
+ "desktop-app": ["frontend-heavy", "native-ui", "local-storage", "ui-design"],
78
+ "cli-tool": ["terminal-ui", "scripting", "no-frontend", "docs-needed"],
79
+ "automation-agent": [
80
+ "ai-agent",
81
+ "automation",
82
+ "api-first",
83
+ "background-jobs",
84
+ ],
85
+ "data-ml": [
86
+ "data-pipeline",
87
+ "analytics",
88
+ "backend-heavy",
89
+ "compute-heavy",
90
+ "docs-needed",
91
+ ],
92
+ "library-sdk": ["api-design", "testing-heavy", "docs-needed", "no-frontend"],
93
+ other: [],
94
+ };
95
+
96
+ module.exports = { APP_TYPE_CHOICES, APP_TYPE_TAGS };
package/bin/lib/config.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Read/write .effectum.json configuration file.
3
+ * v0.4.0 schema — supports appType, description, recommended setup, mode.
3
4
  */
4
5
  "use strict";
5
6
 
@@ -7,6 +8,7 @@ const fs = require("fs");
7
8
  const path = require("path");
8
9
 
9
10
  const CONFIG_FILENAME = ".effectum.json";
11
+ const CONFIG_VERSION = "0.4.0";
10
12
 
11
13
  /**
12
14
  * Read .effectum.json from a directory.
@@ -27,17 +29,28 @@ function readConfig(dir) {
27
29
  * Write .effectum.json to a directory.
28
30
  * @param {string} dir
29
31
  * @param {object} config
32
+ * @returns {string} path to the written file
30
33
  */
31
34
  function writeConfig(dir, config) {
32
35
  const filePath = path.join(dir, CONFIG_FILENAME);
33
36
  const now = new Date().toISOString();
37
+
38
+ // Preserve createdAt from existing config if upgrading
39
+ let existingCreatedAt;
40
+ if (fs.existsSync(filePath)) {
41
+ try {
42
+ const existing = JSON.parse(fs.readFileSync(filePath, "utf8"));
43
+ existingCreatedAt = existing.createdAt;
44
+ } catch (_) {}
45
+ }
46
+
34
47
  const data = {
35
- version: "0.2.0",
48
+ version: CONFIG_VERSION,
36
49
  ...config,
37
50
  updatedAt: now,
38
51
  };
39
52
  if (!data.createdAt) {
40
- data.createdAt = now;
53
+ data.createdAt = existingCreatedAt || now;
41
54
  }
42
55
  fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf8");
43
56
  return filePath;
@@ -52,4 +65,10 @@ function configExists(dir) {
52
65
  return fs.existsSync(path.join(dir, CONFIG_FILENAME));
53
66
  }
54
67
 
55
- module.exports = { readConfig, writeConfig, configExists, CONFIG_FILENAME };
68
+ module.exports = {
69
+ readConfig,
70
+ writeConfig,
71
+ configExists,
72
+ CONFIG_FILENAME,
73
+ CONFIG_VERSION,
74
+ };
@@ -1,9 +1,17 @@
1
1
  /**
2
2
  * Shared constants for the Effectum CLI.
3
- * Autonomy levels, formatter mappings, MCP server definitions, stack choices, language choices.
3
+ * Autonomy levels, formatter mappings, MCP server definitions, stack choices.
4
+ *
5
+ * Language and app-type definitions have moved to their own modules:
6
+ * - languages.js (LANGUAGE_CHOICES, LANGUAGE_INSTRUCTIONS)
7
+ * - app-types.js (APP_TYPE_CHOICES, APP_TYPE_TAGS)
4
8
  */
5
9
  "use strict";
6
10
 
11
+ // Re-export from new modules for backward compatibility
12
+ const { LANGUAGE_CHOICES, LANGUAGE_INSTRUCTIONS } = require("./languages");
13
+ const { APP_TYPE_CHOICES, APP_TYPE_TAGS } = require("./app-types");
14
+
7
15
  /** @type {Record<string, { defaultMode: string, permissions: { allow: string[] } }>} */
8
16
  const AUTONOMY_MAP = {
9
17
  conservative: {
@@ -72,7 +80,7 @@ const FORMATTER_MAP = {
72
80
  },
73
81
  };
74
82
 
75
- /** @type {Array<{ key: string, label: string, package: string, desc: string, config: object }>} */
83
+ /** @type {Array<{ key: string, label: string, package: string, desc: string, config?: object, configFn?: function }>} */
76
84
  const MCP_SERVERS = [
77
85
  {
78
86
  key: "context7",
@@ -140,33 +148,6 @@ const STACK_CHOICES = [
140
148
  },
141
149
  ];
142
150
 
143
- /** @type {Array<{ value: string, label: string, hint: string }>} */
144
- const LANGUAGE_CHOICES = [
145
- {
146
- value: "english",
147
- label: "English",
148
- hint: "Communicate in English",
149
- },
150
- {
151
- value: "german",
152
- label: "Deutsch (du/informal)",
153
- hint: "German, informal",
154
- },
155
- {
156
- value: "custom",
157
- label: "Custom",
158
- hint: "Enter your own language instruction",
159
- },
160
- ];
161
-
162
- /** @type {Record<string, string>} */
163
- const LANGUAGE_INSTRUCTIONS = {
164
- english:
165
- "Speak English with the user. All code, comments, commits, and docs in English.",
166
- german:
167
- "Speak German (du/informal) with the user. All code, comments, commits, and docs in English.",
168
- };
169
-
170
151
  /** @type {Array<{ value: string, label: string, hint: string }>} */
171
152
  const AUTONOMY_CHOICES = [
172
153
  {
@@ -191,7 +172,10 @@ module.exports = {
191
172
  FORMATTER_MAP,
192
173
  MCP_SERVERS,
193
174
  STACK_CHOICES,
175
+ AUTONOMY_CHOICES,
176
+ // Re-exported from languages.js / app-types.js
194
177
  LANGUAGE_CHOICES,
195
178
  LANGUAGE_INSTRUCTIONS,
196
- AUTONOMY_CHOICES,
179
+ APP_TYPE_CHOICES,
180
+ APP_TYPE_TAGS,
197
181
  };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Foundation modules — always installed, not toggleable.
3
+ * These are the safety and context hooks that every Effectum setup requires.
4
+ */
5
+ "use strict";
6
+
7
+ /**
8
+ * Foundation hooks that are always active in every Effectum installation.
9
+ * Users cannot deselect these — they are not part of the recommendation flow.
10
+ * @type {Array<{ key: string, label: string, desc: string }>}
11
+ */
12
+ const FOUNDATION_HOOKS = [
13
+ {
14
+ key: "file-protection",
15
+ label: "File Protection",
16
+ desc: "Block writes to .env, .git, lock files, secrets/",
17
+ },
18
+ {
19
+ key: "destructive-blocker",
20
+ label: "Destructive Command Blocker",
21
+ desc: "Block rm -rf /, DROP TABLE, force push, reset --hard",
22
+ },
23
+ {
24
+ key: "git-context",
25
+ label: "Git Context Loader",
26
+ desc: "Load git status and recent commits at session start",
27
+ },
28
+ {
29
+ key: "guardrails-injection",
30
+ label: "Guardrails Injection",
31
+ desc: "Inject guardrails.md at session start and after compaction",
32
+ },
33
+ {
34
+ key: "post-compaction",
35
+ label: "Post-Compaction Context",
36
+ desc: "Restore context after memory compaction",
37
+ },
38
+ {
39
+ key: "error-logger",
40
+ label: "Error Logger",
41
+ desc: "Log tool failures to .claude/logs/tool-failures.jsonl",
42
+ },
43
+ {
44
+ key: "transcript-backup",
45
+ label: "Transcript Backup",
46
+ desc: "Backup transcripts before context compaction",
47
+ },
48
+ {
49
+ key: "auto-formatter",
50
+ label: "Auto-Formatter",
51
+ desc: "Stack-aware code formatting on every Edit/Write",
52
+ },
53
+ ];
54
+
55
+ /**
56
+ * Format the foundation hooks for display.
57
+ * @returns {string}
58
+ */
59
+ function formatFoundationDisplay() {
60
+ return FOUNDATION_HOOKS.map((h) => ` ${h.label} — ${h.desc}`).join("\n");
61
+ }
62
+
63
+ module.exports = { FOUNDATION_HOOKS, formatFoundationDisplay };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Extended language definitions for the Effectum CLI.
3
+ * Supports 15+ languages plus custom instructions.
4
+ */
5
+ "use strict";
6
+
7
+ /** @type {Array<{ value: string, label: string, hint: string }>} */
8
+ const LANGUAGE_CHOICES = [
9
+ { value: "english", label: "English", hint: "English" },
10
+ { value: "german", label: "Deutsch", hint: "German (du/informal)" },
11
+ { value: "french", label: "Fran\u00e7ais", hint: "French" },
12
+ { value: "spanish", label: "Espa\u00f1ol", hint: "Spanish" },
13
+ { value: "italian", label: "Italiano", hint: "Italian" },
14
+ { value: "portuguese", label: "Portugu\u00eas", hint: "Portuguese" },
15
+ { value: "dutch", label: "Nederlands", hint: "Dutch" },
16
+ { value: "polish", label: "Polski", hint: "Polish" },
17
+ { value: "turkish", label: "T\u00fcrk\u00e7e", hint: "Turkish" },
18
+ {
19
+ value: "arabic",
20
+ label: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629",
21
+ hint: "Arabic",
22
+ },
23
+ {
24
+ value: "hindi",
25
+ label: "\u0939\u093f\u0928\u094d\u0926\u0940",
26
+ hint: "Hindi",
27
+ },
28
+ { value: "chinese", label: "\u4e2d\u6587", hint: "Chinese (Simplified)" },
29
+ { value: "japanese", label: "\u65e5\u672c\u8a9e", hint: "Japanese" },
30
+ { value: "korean", label: "\ud55c\uad6d\uc5b4", hint: "Korean" },
31
+ {
32
+ value: "russian",
33
+ label: "\u0420\u0443\u0441\u0441\u043a\u0438\u0439",
34
+ hint: "Russian",
35
+ },
36
+ {
37
+ value: "custom",
38
+ label: "Custom",
39
+ hint: "Enter your own language instruction",
40
+ },
41
+ ];
42
+
43
+ /** @type {Record<string, string>} */
44
+ const LANGUAGE_INSTRUCTIONS = {
45
+ english:
46
+ "Speak English with the user. All code, comments, commits, and docs in English.",
47
+ german:
48
+ "Speak German (du/informal) with the user. All code, comments, commits, and docs in English.",
49
+ french:
50
+ "Speak French with the user. All code, comments, commits, and docs in English.",
51
+ spanish:
52
+ "Speak Spanish with the user. All code, comments, commits, and docs in English.",
53
+ italian:
54
+ "Speak Italian with the user. All code, comments, commits, and docs in English.",
55
+ portuguese:
56
+ "Speak Portuguese with the user. All code, comments, commits, and docs in English.",
57
+ dutch:
58
+ "Speak Dutch with the user. All code, comments, commits, and docs in English.",
59
+ polish:
60
+ "Speak Polish with the user. All code, comments, commits, and docs in English.",
61
+ turkish:
62
+ "Speak Turkish with the user. All code, comments, commits, and docs in English.",
63
+ arabic:
64
+ "Speak Arabic with the user. All code, comments, commits, and docs in English.",
65
+ hindi:
66
+ "Speak Hindi with the user. All code, comments, commits, and docs in English.",
67
+ chinese:
68
+ "Speak Chinese (Simplified) with the user. All code, comments, commits, and docs in English.",
69
+ japanese:
70
+ "Speak Japanese with the user. All code, comments, commits, and docs in English.",
71
+ korean:
72
+ "Speak Korean with the user. All code, comments, commits, and docs in English.",
73
+ russian:
74
+ "Speak Russian with the user. All code, comments, commits, and docs in English.",
75
+ };
76
+
77
+ module.exports = { LANGUAGE_CHOICES, LANGUAGE_INSTRUCTIONS };