notoken-core 1.6.0 → 1.8.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.
Files changed (123) hide show
  1. package/config/ascii-art.json +12 -0
  2. package/config/chat-responses.json +1019 -0
  3. package/config/cheat-sheets.json +94 -0
  4. package/config/concept-clusters.json +31 -0
  5. package/config/daily-tips.json +105 -0
  6. package/config/entities.json +93 -0
  7. package/config/history-today.json +9762 -0
  8. package/config/image-prompts.json +20 -0
  9. package/config/intent-vectors.json +1 -0
  10. package/config/intents.json +5354 -85
  11. package/config/ollama-models.json +193 -0
  12. package/config/rules.json +32 -1
  13. package/config/startup-quotes.json +45 -0
  14. package/dist/automation/discordPatchright.d.ts +35 -0
  15. package/dist/automation/discordPatchright.js +424 -0
  16. package/dist/automation/discordSetup.d.ts +31 -0
  17. package/dist/automation/discordSetup.js +338 -0
  18. package/dist/automation/smAutomation.d.ts +82 -0
  19. package/dist/automation/smAutomation.js +448 -0
  20. package/dist/conversation/coreference.js +44 -4
  21. package/dist/conversation/pendingActions.d.ts +55 -0
  22. package/dist/conversation/pendingActions.js +127 -0
  23. package/dist/conversation/store.d.ts +72 -0
  24. package/dist/conversation/store.js +140 -1
  25. package/dist/conversation/topicTracker.d.ts +36 -0
  26. package/dist/conversation/topicTracker.js +141 -0
  27. package/dist/execution/ssh.d.ts +42 -1
  28. package/dist/execution/ssh.js +538 -3
  29. package/dist/handlers/executor.d.ts +2 -0
  30. package/dist/handlers/executor.js +4234 -31
  31. package/dist/index.d.ts +35 -4
  32. package/dist/index.js +51 -3
  33. package/dist/nlp/batchParser.d.ts +30 -0
  34. package/dist/nlp/batchParser.js +77 -0
  35. package/dist/nlp/conceptExpansion.d.ts +54 -0
  36. package/dist/nlp/conceptExpansion.js +136 -0
  37. package/dist/nlp/conceptRouter.d.ts +49 -0
  38. package/dist/nlp/conceptRouter.js +302 -0
  39. package/dist/nlp/confidenceCalibrator.d.ts +62 -0
  40. package/dist/nlp/confidenceCalibrator.js +116 -0
  41. package/dist/nlp/correctionLearner.d.ts +45 -0
  42. package/dist/nlp/correctionLearner.js +207 -0
  43. package/dist/nlp/entitySpellCorrect.d.ts +35 -0
  44. package/dist/nlp/entitySpellCorrect.js +141 -0
  45. package/dist/nlp/knowledgeGraph.d.ts +70 -0
  46. package/dist/nlp/knowledgeGraph.js +380 -0
  47. package/dist/nlp/llmFallback.js +28 -1
  48. package/dist/nlp/multiClassifier.js +91 -6
  49. package/dist/nlp/multiIntent.d.ts +43 -0
  50. package/dist/nlp/multiIntent.js +154 -0
  51. package/dist/nlp/parseIntent.d.ts +6 -1
  52. package/dist/nlp/parseIntent.js +180 -5
  53. package/dist/nlp/ruleParser.js +317 -0
  54. package/dist/nlp/semanticSimilarity.d.ts +30 -0
  55. package/dist/nlp/semanticSimilarity.js +174 -0
  56. package/dist/nlp/vocabularyBuilder.d.ts +43 -0
  57. package/dist/nlp/vocabularyBuilder.js +224 -0
  58. package/dist/nlp/wikidata.d.ts +49 -0
  59. package/dist/nlp/wikidata.js +228 -0
  60. package/dist/policy/confirm.d.ts +10 -0
  61. package/dist/policy/confirm.js +39 -0
  62. package/dist/policy/safety.js +6 -4
  63. package/dist/types/intent.d.ts +8 -0
  64. package/dist/types/intent.js +1 -0
  65. package/dist/utils/achievements.d.ts +38 -0
  66. package/dist/utils/achievements.js +126 -0
  67. package/dist/utils/aliases.d.ts +5 -0
  68. package/dist/utils/aliases.js +39 -0
  69. package/dist/utils/analysis.js +71 -15
  70. package/dist/utils/bookmarks.d.ts +13 -0
  71. package/dist/utils/bookmarks.js +51 -0
  72. package/dist/utils/browser.d.ts +64 -0
  73. package/dist/utils/browser.js +364 -0
  74. package/dist/utils/commandHistory.d.ts +20 -0
  75. package/dist/utils/commandHistory.js +108 -0
  76. package/dist/utils/completer.d.ts +17 -0
  77. package/dist/utils/completer.js +79 -0
  78. package/dist/utils/config.js +32 -2
  79. package/dist/utils/dbQuery.d.ts +25 -0
  80. package/dist/utils/dbQuery.js +248 -0
  81. package/dist/utils/devTools.d.ts +35 -0
  82. package/dist/utils/devTools.js +95 -0
  83. package/dist/utils/discordDiag.d.ts +35 -0
  84. package/dist/utils/discordDiag.js +826 -0
  85. package/dist/utils/diskCleanup.d.ts +36 -0
  86. package/dist/utils/diskCleanup.js +775 -0
  87. package/dist/utils/entityResolver.d.ts +107 -0
  88. package/dist/utils/entityResolver.js +468 -0
  89. package/dist/utils/imageGen.d.ts +92 -0
  90. package/dist/utils/imageGen.js +2031 -0
  91. package/dist/utils/installTracker.d.ts +57 -0
  92. package/dist/utils/installTracker.js +160 -0
  93. package/dist/utils/multiExec.d.ts +21 -0
  94. package/dist/utils/multiExec.js +141 -0
  95. package/dist/utils/openclawDiag.d.ts +29 -0
  96. package/dist/utils/openclawDiag.js +1035 -0
  97. package/dist/utils/output.js +4 -0
  98. package/dist/utils/platform.js +2 -1
  99. package/dist/utils/progressReporter.d.ts +50 -0
  100. package/dist/utils/progressReporter.js +58 -0
  101. package/dist/utils/projectDetect.d.ts +44 -0
  102. package/dist/utils/projectDetect.js +319 -0
  103. package/dist/utils/projectScanner.d.ts +44 -0
  104. package/dist/utils/projectScanner.js +312 -0
  105. package/dist/utils/shellCompat.d.ts +78 -0
  106. package/dist/utils/shellCompat.js +186 -0
  107. package/dist/utils/smartArchive.d.ts +16 -0
  108. package/dist/utils/smartArchive.js +172 -0
  109. package/dist/utils/smartRetry.d.ts +26 -0
  110. package/dist/utils/smartRetry.js +114 -0
  111. package/dist/utils/snippets.d.ts +13 -0
  112. package/dist/utils/snippets.js +53 -0
  113. package/dist/utils/stabilityMatrixManager.d.ts +80 -0
  114. package/dist/utils/stabilityMatrixManager.js +268 -0
  115. package/dist/utils/teachMode.d.ts +41 -0
  116. package/dist/utils/teachMode.js +100 -0
  117. package/dist/utils/timer.d.ts +22 -0
  118. package/dist/utils/timer.js +52 -0
  119. package/dist/utils/updater.d.ts +1 -0
  120. package/dist/utils/updater.js +1 -1
  121. package/dist/utils/version.d.ts +20 -0
  122. package/dist/utils/version.js +212 -0
  123. package/package.json +6 -3
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Smart archive creation.
3
+ *
4
+ * Auto-excludes heavy/non-essential directories (node_modules, .git, etc.)
5
+ * unless the user explicitly requests them. Checks disk space before archiving.
6
+ */
7
+ import { exec } from "node:child_process";
8
+ import { promisify } from "node:util";
9
+ import { existsSync, statSync } from "node:fs";
10
+ import { resolve, basename } from "node:path";
11
+ import { detectLocalPlatform } from "./platform.js";
12
+ import { askForConfirmation } from "../policy/confirm.js";
13
+ const execAsync = promisify(exec);
14
+ const c = {
15
+ reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
16
+ green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m",
17
+ };
18
+ /** Directories that are safe to exclude by default (regenerable/cached). */
19
+ const DEFAULT_EXCLUDES = [
20
+ "node_modules",
21
+ ".git",
22
+ ".next",
23
+ ".nuxt",
24
+ "dist",
25
+ "build",
26
+ "__pycache__",
27
+ ".venv",
28
+ "venv",
29
+ ".env.local",
30
+ ".cache",
31
+ ".turbo",
32
+ "vendor", // PHP composer
33
+ "target", // Rust cargo
34
+ ".gradle",
35
+ ".idea",
36
+ ".vscode",
37
+ "*.pyc",
38
+ "*.o",
39
+ "*.class",
40
+ ".DS_Store",
41
+ "Thumbs.db",
42
+ ];
43
+ /** Estimate the size of a directory (excluding default excludes). */
44
+ async function estimateSize(source, excludes) {
45
+ const plat = detectLocalPlatform();
46
+ try {
47
+ // Total size
48
+ const { stdout: totalOut } = await execAsync(`du -sb "${source}" 2>/dev/null | cut -f1`, { timeout: 30_000 });
49
+ const totalBytes = parseInt(totalOut.trim()) || 0;
50
+ // Size of excluded dirs
51
+ let excludedBytes = 0;
52
+ for (const ex of excludes) {
53
+ if (ex.startsWith("*"))
54
+ continue; // skip glob patterns
55
+ const exPath = resolve(source, ex);
56
+ if (existsSync(exPath)) {
57
+ try {
58
+ const { stdout } = await execAsync(`du -sb "${exPath}" 2>/dev/null | cut -f1`, { timeout: 10_000 });
59
+ excludedBytes += parseInt(stdout.trim()) || 0;
60
+ }
61
+ catch { }
62
+ }
63
+ }
64
+ return {
65
+ totalGB: totalBytes / 1073741824,
66
+ excludedGB: excludedBytes / 1073741824,
67
+ };
68
+ }
69
+ catch {
70
+ return { totalGB: 0, excludedGB: 0 };
71
+ }
72
+ }
73
+ /** Check available disk space at a path. */
74
+ async function getAvailableSpaceGB(path) {
75
+ try {
76
+ const { stdout } = await execAsync(`df -B1 "${path}" 2>/dev/null | tail -1 | awk '{print $4}'`, { timeout: 5000 });
77
+ return parseInt(stdout.trim()) / 1073741824;
78
+ }
79
+ catch {
80
+ return -1; // unknown
81
+ }
82
+ }
83
+ /**
84
+ * Smart archive: checks space, shows what will be excluded, asks before creating.
85
+ */
86
+ export async function smartArchive(options) {
87
+ const source = resolve(options.source);
88
+ const lines = [];
89
+ if (!existsSync(source)) {
90
+ return `${c.red}✗ Source not found: ${source}${c.reset}`;
91
+ }
92
+ // Determine destination
93
+ const destName = options.destination || `${basename(source)}.tar.gz`;
94
+ const dest = resolve(destName.endsWith(".tar.gz") || destName.endsWith(".tgz") ? destName : destName + ".tar.gz");
95
+ // Determine exclusions
96
+ const excludes = options.includeAll ? [] : DEFAULT_EXCLUDES;
97
+ const foundExcludes = [];
98
+ // Check which excludable dirs actually exist in source
99
+ if (!options.includeAll) {
100
+ for (const ex of DEFAULT_EXCLUDES) {
101
+ if (ex.startsWith("*"))
102
+ continue;
103
+ const exPath = resolve(source, ex);
104
+ if (existsSync(exPath)) {
105
+ try {
106
+ const stat = statSync(exPath);
107
+ if (stat.isDirectory()) {
108
+ const { stdout } = await execAsync(`du -sb "${exPath}" 2>/dev/null | cut -f1`, { timeout: 10_000 });
109
+ const sizeGB = parseInt(stdout.trim()) / 1073741824;
110
+ foundExcludes.push({ name: ex, sizeGB });
111
+ }
112
+ }
113
+ catch { }
114
+ }
115
+ }
116
+ }
117
+ // Estimate sizes
118
+ const sizes = await estimateSize(source, options.includeAll ? [] : DEFAULT_EXCLUDES.filter(e => !e.startsWith("*")));
119
+ const archiveEstimateGB = (sizes.totalGB - sizes.excludedGB) * 0.3; // rough compression ratio
120
+ const availableGB = await getAvailableSpaceGB(resolve(dest, ".."));
121
+ lines.push(`\n${c.bold}${c.cyan}── Smart Archive ──${c.reset}\n`);
122
+ lines.push(` Source: ${c.bold}${source}${c.reset}`);
123
+ lines.push(` Destination: ${c.bold}${dest}${c.reset}`);
124
+ lines.push(` Source size: ${c.bold}${sizes.totalGB.toFixed(2)} GB${c.reset}`);
125
+ if (foundExcludes.length > 0) {
126
+ const totalExcluded = foundExcludes.reduce((s, e) => s + e.sizeGB, 0);
127
+ lines.push(`\n ${c.bold}Auto-excluding (${totalExcluded.toFixed(2)} GB saved):${c.reset}`);
128
+ for (const ex of foundExcludes.sort((a, b) => b.sizeGB - a.sizeGB)) {
129
+ const sizeStr = ex.sizeGB >= 1 ? `${ex.sizeGB.toFixed(2)} GB` : `${(ex.sizeGB * 1024).toFixed(0)} MB`;
130
+ lines.push(` ${c.yellow}${sizeStr.padStart(10)}${c.reset} ${ex.name}/`);
131
+ }
132
+ lines.push(`\n ${c.dim}To include everything: add "include all" or "with node_modules"${c.reset}`);
133
+ }
134
+ lines.push(`\n Estimated archive: ${c.bold}~${archiveEstimateGB.toFixed(2)} GB${c.reset} ${c.dim}(compressed)${c.reset}`);
135
+ // Space check
136
+ if (availableGB >= 0) {
137
+ lines.push(` Available space: ${c.bold}${availableGB.toFixed(2)} GB${c.reset}`);
138
+ if (archiveEstimateGB > availableGB * 0.9) {
139
+ lines.push(`\n ${c.red}${c.bold}⚠ NOT ENOUGH SPACE!${c.reset} Archive (~${archiveEstimateGB.toFixed(2)} GB) may exceed available space (${availableGB.toFixed(2)} GB).`);
140
+ lines.push(` ${c.yellow}Free up space first: notoken "free up space"${c.reset}`);
141
+ return lines.join("\n");
142
+ }
143
+ else if (archiveEstimateGB > availableGB * 0.5) {
144
+ lines.push(` ${c.yellow}⚠ This will use ${Math.round((archiveEstimateGB / availableGB) * 100)}% of remaining space.${c.reset}`);
145
+ }
146
+ else {
147
+ lines.push(` ${c.green}✓ Plenty of space.${c.reset}`);
148
+ }
149
+ }
150
+ console.log(lines.join("\n"));
151
+ // Confirm
152
+ const ok = await askForConfirmation(`\nCreate archive?`);
153
+ if (!ok) {
154
+ return `${c.dim}Cancelled.${c.reset}`;
155
+ }
156
+ // Build tar command
157
+ const excludeFlags = excludes.map((e) => `--exclude='${e}'`).join(" ");
158
+ const tarCmd = `tar -czf "${dest}" ${excludeFlags} -C "${resolve(source, "..")}" "${basename(source)}"`;
159
+ console.log(`\n${c.dim}→ ${tarCmd}${c.reset}`);
160
+ try {
161
+ await execAsync(tarCmd, { timeout: 600_000 }); // 10 min timeout for large archives
162
+ // Show result
163
+ const stat = statSync(dest);
164
+ const resultGB = stat.size / 1073741824;
165
+ const sizeStr = resultGB >= 1 ? `${resultGB.toFixed(2)} GB` : `${(resultGB * 1024).toFixed(0)} MB`;
166
+ return `\n${c.green}${c.bold}✓ Archive created: ${dest}${c.reset}\n Size: ${c.bold}${sizeStr}${c.reset}`;
167
+ }
168
+ catch (err) {
169
+ const msg = err instanceof Error ? err.message : String(err);
170
+ return `\n${c.red}✗ Archive failed: ${msg.split("\n")[0]}${c.reset}`;
171
+ }
172
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Smart Retry — analyzes command failures and suggests fixes.
3
+ *
4
+ * When a command fails, this module inspects the error message,
5
+ * identifies common patterns, and suggests an actionable fix
6
+ * that can be registered as a pending action.
7
+ */
8
+ export interface FailureAnalysis {
9
+ /** Whether this failure has an automated fix */
10
+ canFix: boolean;
11
+ /** Short human-friendly suggestion shown to the user */
12
+ suggestion: string;
13
+ /** The command/intent text to execute as the fix */
14
+ fixCommand: string;
15
+ /** Why this fix should help */
16
+ explanation: string;
17
+ }
18
+ /**
19
+ * Analyze a command failure and suggest a fix.
20
+ *
21
+ * @param intent - The intent name or raw text that failed
22
+ * @param error - The error (string or Error)
23
+ * @param fields - Parsed intent fields (service name, tool, path, etc.)
24
+ * @returns A FailureAnalysis if a known pattern matches, or null
25
+ */
26
+ export declare function analyzeFailure(intent: string, error: string | Error, fields?: Record<string, unknown>): FailureAnalysis | null;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Smart Retry — analyzes command failures and suggests fixes.
3
+ *
4
+ * When a command fails, this module inspects the error message,
5
+ * identifies common patterns, and suggests an actionable fix
6
+ * that can be registered as a pending action.
7
+ */
8
+ const patterns = [
9
+ {
10
+ pattern: /command not found[:\s]*(\S+)|(\S+):\s*not found|'(\S+)' is not recognized/i,
11
+ build: (m) => {
12
+ const tool = (m[1] || m[2] || m[3]).replace(/['"]/g, "");
13
+ return {
14
+ canFix: true,
15
+ suggestion: `${tool} is not installed. Install it?`,
16
+ fixCommand: `install ${tool}`,
17
+ explanation: `The command "${tool}" was not found on this system. Installing it should fix the issue.`,
18
+ };
19
+ },
20
+ },
21
+ {
22
+ pattern: /connection refused|ECONNREFUSED/i,
23
+ build: (_m, _intent, fields) => {
24
+ const service = fields.service || fields.tool || "the service";
25
+ return {
26
+ canFix: true,
27
+ suggestion: `Can't connect — ${service} may not be running. Start it?`,
28
+ fixCommand: `start ${service}`,
29
+ explanation: `Connection was refused, which usually means the target service is not running.`,
30
+ };
31
+ },
32
+ },
33
+ {
34
+ pattern: /permission denied|EACCES|access denied/i,
35
+ build: (_m, intent) => ({
36
+ canFix: true,
37
+ suggestion: "Permission denied. Retry with elevated privileges?",
38
+ fixCommand: `sudo ${intent}`,
39
+ explanation: "The command failed due to insufficient permissions. Running with sudo may resolve it.",
40
+ }),
41
+ },
42
+ {
43
+ pattern: /no such file or directory[:\s]*(.+)|ENOENT[:\s]*(.+)/i,
44
+ build: (m) => {
45
+ const raw = (m[1] || m[2] || "").trim().replace(/['"]/g, "");
46
+ const filename = raw.split("/").pop() || raw;
47
+ return {
48
+ canFix: true,
49
+ suggestion: `File not found: ${filename}. Search for it?`,
50
+ fixCommand: `find ${filename}`,
51
+ explanation: `The path "${raw}" does not exist. A search may locate the correct path.`,
52
+ };
53
+ },
54
+ },
55
+ {
56
+ pattern: /address already in use|port.*already in use|EADDRINUSE/i,
57
+ build: () => ({
58
+ canFix: true,
59
+ suggestion: "Port already in use. Check what's using it?",
60
+ fixCommand: "check ports",
61
+ explanation: "Another process is occupying the required port.",
62
+ }),
63
+ },
64
+ {
65
+ pattern: /no space left|disk full|ENOSPC/i,
66
+ build: () => ({
67
+ canFix: true,
68
+ suggestion: "Disk is full. Free up space?",
69
+ fixCommand: "free up space",
70
+ explanation: "The disk has no remaining space. Clearing caches or temp files may help.",
71
+ }),
72
+ },
73
+ {
74
+ pattern: /timed?\s*out|ETIMEDOUT|ESOCKETTIMEDOUT/i,
75
+ build: (_m, intent) => ({
76
+ canFix: true,
77
+ suggestion: "Command timed out. Try again?",
78
+ fixCommand: intent,
79
+ explanation: "The operation exceeded its time limit. A retry may succeed if the issue was transient.",
80
+ }),
81
+ },
82
+ {
83
+ pattern: /ECONNREFUSED/i,
84
+ build: (_m, _intent, fields) => {
85
+ const service = fields.service || fields.tool || "the service";
86
+ return {
87
+ canFix: true,
88
+ suggestion: `Can't connect to ${service}. Check if it's running?`,
89
+ fixCommand: `check status ${service}`,
90
+ explanation: "The connection was actively refused — the target service may be down.",
91
+ };
92
+ },
93
+ },
94
+ ];
95
+ /**
96
+ * Analyze a command failure and suggest a fix.
97
+ *
98
+ * @param intent - The intent name or raw text that failed
99
+ * @param error - The error (string or Error)
100
+ * @param fields - Parsed intent fields (service name, tool, path, etc.)
101
+ * @returns A FailureAnalysis if a known pattern matches, or null
102
+ */
103
+ export function analyzeFailure(intent, error, fields = {}) {
104
+ const message = error instanceof Error ? error.message : String(error);
105
+ if (!message)
106
+ return null;
107
+ for (const { pattern, build } of patterns) {
108
+ const match = message.match(pattern);
109
+ if (match) {
110
+ return build(match, intent, fields);
111
+ }
112
+ }
113
+ return null;
114
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Snippets — save, list, read, and run code snippets.
3
+ *
4
+ * Each snippet is a file under ~/.notoken/snippets/<name>.<ext>
5
+ */
6
+ /** Save a code snippet. */
7
+ export declare function saveSnippet(name: string, code: string, language?: string): void;
8
+ /** List saved snippets. */
9
+ export declare function listSnippets(): string;
10
+ /** Read a snippet by name (matches any extension). */
11
+ export declare function getSnippet(name: string): string | undefined;
12
+ /** Run a snippet, auto-detecting interpreter from extension. */
13
+ export declare function runSnippet(name: string): string;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Snippets — save, list, read, and run code snippets.
3
+ *
4
+ * Each snippet is a file under ~/.notoken/snippets/<name>.<ext>
5
+ */
6
+ import { readFileSync, writeFileSync, mkdirSync, readdirSync } from "node:fs";
7
+ import { resolve, extname, basename } from "node:path";
8
+ import { execSync } from "node:child_process";
9
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? ".";
10
+ const dir = resolve(home, ".notoken", "snippets");
11
+ function ensureDir() { mkdirSync(dir, { recursive: true }); }
12
+ function extFor(lang) {
13
+ if (!lang)
14
+ return ".sh";
15
+ const map = { bash: ".sh", sh: ".sh", node: ".js", javascript: ".js", python: ".py", ts: ".ts", typescript: ".ts" };
16
+ return map[lang.toLowerCase()] ?? `.${lang}`;
17
+ }
18
+ /** Save a code snippet. */
19
+ export function saveSnippet(name, code, language) {
20
+ ensureDir();
21
+ writeFileSync(resolve(dir, `${name}${extFor(language)}`), code, "utf-8");
22
+ }
23
+ /** List saved snippets. */
24
+ export function listSnippets() {
25
+ ensureDir();
26
+ const files = readdirSync(dir);
27
+ if (files.length === 0)
28
+ return "No snippets saved.";
29
+ return files.map((f) => ` ${basename(f, extname(f))} (${extname(f).slice(1)})`).join("\n");
30
+ }
31
+ /** Read a snippet by name (matches any extension). */
32
+ export function getSnippet(name) {
33
+ ensureDir();
34
+ const hit = readdirSync(dir).find((f) => basename(f, extname(f)) === name);
35
+ return hit ? readFileSync(resolve(dir, hit), "utf-8") : undefined;
36
+ }
37
+ /** Run a snippet, auto-detecting interpreter from extension. */
38
+ export function runSnippet(name) {
39
+ ensureDir();
40
+ const hit = readdirSync(dir).find((f) => basename(f, extname(f)) === name);
41
+ if (!hit)
42
+ return `Snippet "${name}" not found.`;
43
+ const fp = resolve(dir, hit);
44
+ const ext = extname(hit);
45
+ const runners = { ".sh": "bash", ".js": "node", ".py": "python3", ".ts": "npx tsx" };
46
+ const runner = runners[ext] ?? "bash";
47
+ try {
48
+ return execSync(`${runner} "${fp}"`, { encoding: "utf-8", timeout: 30_000 }).trim();
49
+ }
50
+ catch (e) {
51
+ return `Error: ${e.message?.split("\n")[0] ?? e}`;
52
+ }
53
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Stability Matrix Manager.
3
+ *
4
+ * Controls Stability Matrix without browser automation — reads/writes
5
+ * settings.json directly, launches packages via their launch commands,
6
+ * and manages models via the shared folder structure.
7
+ *
8
+ * SM stores config in:
9
+ * <SM_DIR>/Data/settings.json — main config
10
+ * <SM_DIR>/Packages/<name>/ — installed packages
11
+ * <SM_DIR>/Models/ — shared models folder
12
+ */
13
+ export interface SMLocation {
14
+ path: string;
15
+ platform: "windows" | "wsl";
16
+ settingsPath: string;
17
+ packagesDir: string;
18
+ modelsDir: string;
19
+ }
20
+ export declare function findStabilityMatrix(): SMLocation | null;
21
+ export interface SMSettings {
22
+ InstalledPackages: SMPackage[];
23
+ ActiveInstalledPackage: string;
24
+ FirstLaunchSetupComplete: boolean;
25
+ Theme: string;
26
+ PreferredGpu?: {
27
+ Name: string;
28
+ MemoryBytes: number;
29
+ IsNvidia: boolean;
30
+ };
31
+ [key: string]: unknown;
32
+ }
33
+ export interface SMPackage {
34
+ Id: string;
35
+ DisplayName: string;
36
+ PackageName: string;
37
+ Version: {
38
+ InstalledBranch: string;
39
+ InstalledCommitSha: string;
40
+ };
41
+ LibraryPath: string;
42
+ LaunchCommand: string;
43
+ LaunchArgs: Array<{
44
+ Name: string;
45
+ Type: string;
46
+ OptionValue: unknown;
47
+ }>;
48
+ PythonVersion: string;
49
+ }
50
+ export declare function readSMSettings(sm: SMLocation): SMSettings | null;
51
+ export declare function writeSMSettings(sm: SMLocation, settings: SMSettings): void;
52
+ export declare function getInstalledPackages(sm: SMLocation): SMPackage[];
53
+ export declare function getActivePackage(sm: SMLocation): SMPackage | null;
54
+ export declare function isPackageRunning(sm: SMLocation): {
55
+ running: boolean;
56
+ port: number;
57
+ url: string;
58
+ };
59
+ export declare function launchPackage(sm: SMLocation, pkg?: SMPackage): {
60
+ success: boolean;
61
+ message: string;
62
+ };
63
+ export declare function stopPackage(): {
64
+ success: boolean;
65
+ message: string;
66
+ };
67
+ export interface ModelInfo {
68
+ name: string;
69
+ path: string;
70
+ size: string;
71
+ type: "checkpoint" | "lora" | "vae" | "embedding" | "controlnet" | "other";
72
+ }
73
+ export declare function listModels(sm: SMLocation): ModelInfo[];
74
+ export declare function downloadModel(sm: SMLocation, url: string, name?: string): Promise<{
75
+ success: boolean;
76
+ message: string;
77
+ }>;
78
+ export declare function formatSMStatus(sm: SMLocation): string;
79
+ export declare function setLaunchArgs(sm: SMLocation, args: Record<string, boolean>): void;
80
+ export declare function enableAPI(sm: SMLocation): void;