notoken-core 1.6.0 → 1.8.1
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/config/ascii-art.json +12 -0
- package/config/chat-responses.json +1019 -0
- package/config/cheat-sheets.json +94 -0
- package/config/concept-clusters.json +31 -0
- package/config/daily-tips.json +105 -0
- package/config/entities.json +93 -0
- package/config/history-today.json +9762 -0
- package/config/image-prompts.json +20 -0
- package/config/intent-vectors.json +1 -0
- package/config/intents.json +5749 -85
- package/config/ollama-models.json +193 -0
- package/config/rules.json +32 -1
- package/config/startup-quotes.json +45 -0
- package/dist/automation/discordPatchright.d.ts +35 -0
- package/dist/automation/discordPatchright.js +437 -0
- package/dist/automation/discordSetup.d.ts +31 -0
- package/dist/automation/discordSetup.js +338 -0
- package/dist/automation/smAutomation.d.ts +82 -0
- package/dist/automation/smAutomation.js +448 -0
- package/dist/conversation/coreference.js +44 -4
- package/dist/conversation/pendingActions.d.ts +55 -0
- package/dist/conversation/pendingActions.js +127 -0
- package/dist/conversation/store.d.ts +72 -0
- package/dist/conversation/store.js +140 -1
- package/dist/conversation/topicTracker.d.ts +36 -0
- package/dist/conversation/topicTracker.js +141 -0
- package/dist/execution/ssh.d.ts +42 -1
- package/dist/execution/ssh.js +538 -3
- package/dist/handlers/executor.d.ts +2 -0
- package/dist/handlers/executor.js +4669 -31
- package/dist/index.d.ts +39 -5
- package/dist/index.js +56 -4
- package/dist/nlp/batchParser.d.ts +30 -0
- package/dist/nlp/batchParser.js +77 -0
- package/dist/nlp/conceptExpansion.d.ts +54 -0
- package/dist/nlp/conceptExpansion.js +136 -0
- package/dist/nlp/conceptRouter.d.ts +49 -0
- package/dist/nlp/conceptRouter.js +302 -0
- package/dist/nlp/confidenceCalibrator.d.ts +62 -0
- package/dist/nlp/confidenceCalibrator.js +116 -0
- package/dist/nlp/correctionLearner.d.ts +45 -0
- package/dist/nlp/correctionLearner.js +207 -0
- package/dist/nlp/entitySpellCorrect.d.ts +35 -0
- package/dist/nlp/entitySpellCorrect.js +141 -0
- package/dist/nlp/knowledgeGraph.d.ts +70 -0
- package/dist/nlp/knowledgeGraph.js +380 -0
- package/dist/nlp/llmFallback.d.ts +47 -0
- package/dist/nlp/llmFallback.js +175 -36
- package/dist/nlp/llmParser.d.ts +5 -1
- package/dist/nlp/llmParser.js +43 -24
- package/dist/nlp/multiClassifier.js +91 -6
- package/dist/nlp/multiIntent.d.ts +43 -0
- package/dist/nlp/multiIntent.js +154 -0
- package/dist/nlp/parseIntent.d.ts +6 -1
- package/dist/nlp/parseIntent.js +199 -6
- package/dist/nlp/ruleParser.js +348 -0
- package/dist/nlp/semanticSimilarity.d.ts +30 -0
- package/dist/nlp/semanticSimilarity.js +174 -0
- package/dist/nlp/vocabularyBuilder.d.ts +43 -0
- package/dist/nlp/vocabularyBuilder.js +224 -0
- package/dist/nlp/wikidata.d.ts +49 -0
- package/dist/nlp/wikidata.js +228 -0
- package/dist/policy/confirm.d.ts +10 -0
- package/dist/policy/confirm.js +39 -0
- package/dist/policy/safety.js +6 -4
- package/dist/types/intent.d.ts +8 -0
- package/dist/types/intent.js +1 -0
- package/dist/utils/achievements.d.ts +38 -0
- package/dist/utils/achievements.js +126 -0
- package/dist/utils/aliases.d.ts +5 -0
- package/dist/utils/aliases.js +39 -0
- package/dist/utils/analysis.js +71 -15
- package/dist/utils/bookmarks.d.ts +13 -0
- package/dist/utils/bookmarks.js +51 -0
- package/dist/utils/browser.d.ts +64 -0
- package/dist/utils/browser.js +364 -0
- package/dist/utils/commandHistory.d.ts +20 -0
- package/dist/utils/commandHistory.js +108 -0
- package/dist/utils/completer.d.ts +17 -0
- package/dist/utils/completer.js +79 -0
- package/dist/utils/config.js +32 -2
- package/dist/utils/dbQuery.d.ts +25 -0
- package/dist/utils/dbQuery.js +248 -0
- package/dist/utils/devTools.d.ts +35 -0
- package/dist/utils/devTools.js +95 -0
- package/dist/utils/discordDiag.d.ts +35 -0
- package/dist/utils/discordDiag.js +834 -0
- package/dist/utils/diskCleanup.d.ts +36 -0
- package/dist/utils/diskCleanup.js +775 -0
- package/dist/utils/entityResolver.d.ts +107 -0
- package/dist/utils/entityResolver.js +468 -0
- package/dist/utils/imageGen.d.ts +92 -0
- package/dist/utils/imageGen.js +2031 -0
- package/dist/utils/installTracker.d.ts +57 -0
- package/dist/utils/installTracker.js +160 -0
- package/dist/utils/multiExec.d.ts +21 -0
- package/dist/utils/multiExec.js +141 -0
- package/dist/utils/openclawDiag.d.ts +127 -0
- package/dist/utils/openclawDiag.js +1535 -0
- package/dist/utils/openclawLogParser.d.ts +65 -0
- package/dist/utils/openclawLogParser.js +168 -0
- package/dist/utils/output.js +4 -0
- package/dist/utils/platform.js +2 -1
- package/dist/utils/progressReporter.d.ts +50 -0
- package/dist/utils/progressReporter.js +58 -0
- package/dist/utils/projectDetect.d.ts +44 -0
- package/dist/utils/projectDetect.js +319 -0
- package/dist/utils/projectScanner.d.ts +44 -0
- package/dist/utils/projectScanner.js +312 -0
- package/dist/utils/shellCompat.d.ts +78 -0
- package/dist/utils/shellCompat.js +186 -0
- package/dist/utils/smartArchive.d.ts +16 -0
- package/dist/utils/smartArchive.js +172 -0
- package/dist/utils/smartRetry.d.ts +26 -0
- package/dist/utils/smartRetry.js +114 -0
- package/dist/utils/snippets.d.ts +13 -0
- package/dist/utils/snippets.js +53 -0
- package/dist/utils/stabilityMatrixManager.d.ts +80 -0
- package/dist/utils/stabilityMatrixManager.js +268 -0
- package/dist/utils/teachMode.d.ts +41 -0
- package/dist/utils/teachMode.js +100 -0
- package/dist/utils/timer.d.ts +22 -0
- package/dist/utils/timer.js +52 -0
- package/dist/utils/updater.d.ts +1 -0
- package/dist/utils/updater.js +1 -1
- package/dist/utils/userContext.d.ts +57 -0
- package/dist/utils/userContext.js +133 -0
- package/dist/utils/version.d.ts +20 -0
- package/dist/utils/version.js +212 -0
- package/package.json +6 -3
|
@@ -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;
|
|
@@ -0,0 +1,268 @@
|
|
|
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
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from "node:fs";
|
|
14
|
+
import { resolve } from "node:path";
|
|
15
|
+
import { execSync } from "node:child_process";
|
|
16
|
+
import { homedir } from "node:os";
|
|
17
|
+
const c = {
|
|
18
|
+
reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
|
|
19
|
+
green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m",
|
|
20
|
+
};
|
|
21
|
+
function tryExec(cmd, timeout = 5000) {
|
|
22
|
+
try {
|
|
23
|
+
return execSync(cmd, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout }).trim() || null;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function findStabilityMatrix() {
|
|
30
|
+
const candidates = [
|
|
31
|
+
// WSL paths to Windows drives
|
|
32
|
+
"/mnt/d/notoken/ai/StabilityMatrix",
|
|
33
|
+
"/mnt/c/notoken/ai/StabilityMatrix",
|
|
34
|
+
"/mnt/d/StabilityMatrix",
|
|
35
|
+
resolve(homedir(), "StabilityMatrix"),
|
|
36
|
+
resolve(homedir(), "AppData", "Local", "StabilityMatrix"),
|
|
37
|
+
// Native Windows paths
|
|
38
|
+
"D:\\notoken\\ai\\StabilityMatrix",
|
|
39
|
+
"C:\\notoken\\ai\\StabilityMatrix",
|
|
40
|
+
];
|
|
41
|
+
for (const p of candidates) {
|
|
42
|
+
const settingsPath = resolve(p, "Data", "settings.json");
|
|
43
|
+
if (existsSync(settingsPath)) {
|
|
44
|
+
const isWSL = p.startsWith("/mnt/");
|
|
45
|
+
return {
|
|
46
|
+
path: p,
|
|
47
|
+
platform: isWSL ? "wsl" : "windows",
|
|
48
|
+
settingsPath,
|
|
49
|
+
packagesDir: resolve(p, "Data", "Packages"),
|
|
50
|
+
modelsDir: resolve(p, "Data", "Models"),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Also check if SM exe exists without settings yet
|
|
54
|
+
if (existsSync(resolve(p, "StabilityMatrix.exe"))) {
|
|
55
|
+
const isWSL = p.startsWith("/mnt/");
|
|
56
|
+
return {
|
|
57
|
+
path: p,
|
|
58
|
+
platform: isWSL ? "wsl" : "windows",
|
|
59
|
+
settingsPath: resolve(p, "Data", "settings.json"),
|
|
60
|
+
packagesDir: resolve(p, "Data", "Packages"),
|
|
61
|
+
modelsDir: resolve(p, "Data", "Models"),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
export function readSMSettings(sm) {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(readFileSync(sm.settingsPath, "utf-8"));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function writeSMSettings(sm, settings) {
|
|
76
|
+
mkdirSync(resolve(sm.settingsPath, ".."), { recursive: true });
|
|
77
|
+
writeFileSync(sm.settingsPath, JSON.stringify(settings, null, 2));
|
|
78
|
+
}
|
|
79
|
+
// ─── Package Management ────────────────────────────────────────────────────
|
|
80
|
+
export function getInstalledPackages(sm) {
|
|
81
|
+
const settings = readSMSettings(sm);
|
|
82
|
+
return settings?.InstalledPackages ?? [];
|
|
83
|
+
}
|
|
84
|
+
export function getActivePackage(sm) {
|
|
85
|
+
const settings = readSMSettings(sm);
|
|
86
|
+
if (!settings)
|
|
87
|
+
return null;
|
|
88
|
+
return settings.InstalledPackages.find(p => p.Id === settings.ActiveInstalledPackage) ?? null;
|
|
89
|
+
}
|
|
90
|
+
export function isPackageRunning(sm) {
|
|
91
|
+
// Check common ports
|
|
92
|
+
for (const port of [7860, 7861, 8188, 9090]) {
|
|
93
|
+
const check = tryExec(`curl -sf --max-time 2 http://localhost:${port}/sdapi/v1/sd-models 2>/dev/null`);
|
|
94
|
+
if (check)
|
|
95
|
+
return { running: true, port, url: `http://localhost:${port}` };
|
|
96
|
+
// ComfyUI
|
|
97
|
+
const comfyCheck = tryExec(`curl -sf --max-time 2 http://localhost:${port}/system_stats 2>/dev/null`);
|
|
98
|
+
if (comfyCheck)
|
|
99
|
+
return { running: true, port, url: `http://localhost:${port}` };
|
|
100
|
+
}
|
|
101
|
+
return { running: false, port: 0, url: "" };
|
|
102
|
+
}
|
|
103
|
+
export function launchPackage(sm, pkg) {
|
|
104
|
+
const active = pkg ?? getActivePackage(sm);
|
|
105
|
+
if (!active)
|
|
106
|
+
return { success: false, message: "No active package found in Stability Matrix" };
|
|
107
|
+
const pkgDir = resolve(sm.packagesDir, active.LibraryPath.replace(/\\/g, "/"));
|
|
108
|
+
if (!existsSync(pkgDir))
|
|
109
|
+
return { success: false, message: `Package directory not found: ${pkgDir}` };
|
|
110
|
+
// Build launch args
|
|
111
|
+
const args = active.LaunchArgs
|
|
112
|
+
.filter(a => a.OptionValue === true)
|
|
113
|
+
.map(a => a.Name)
|
|
114
|
+
.join(" ");
|
|
115
|
+
const launchCmd = active.LaunchCommand;
|
|
116
|
+
const pythonDir = resolve(sm.path, "Data", "Assets", `python-${active.PythonVersion}`);
|
|
117
|
+
const venvDir = resolve(pkgDir, "venv");
|
|
118
|
+
// Launch via Windows PowerShell (SM packages run on Windows)
|
|
119
|
+
if (sm.platform === "wsl") {
|
|
120
|
+
const winPkgDir = tryExec(`wslpath -w "${pkgDir}"`);
|
|
121
|
+
if (!winPkgDir)
|
|
122
|
+
return { success: false, message: "Could not convert path" };
|
|
123
|
+
try {
|
|
124
|
+
execSync(`/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -Command "Start-Process -WorkingDirectory '${winPkgDir}' -FilePath 'python' -ArgumentList '${launchCmd} --api ${args}' -WindowStyle Normal" 2>/dev/null`, { stdio: "ignore", timeout: 10000 });
|
|
125
|
+
return { success: true, message: `${c.green}✓${c.reset} Launched ${active.DisplayName} (${launchCmd} --api ${args})` };
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
return { success: false, message: `Launch failed: ${err instanceof Error ? err.message : err}` };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Native Windows
|
|
132
|
+
try {
|
|
133
|
+
execSync(`start "" /D "${pkgDir}" python ${launchCmd} --api ${args}`, { stdio: "ignore", shell: "cmd.exe", timeout: 10000 });
|
|
134
|
+
return { success: true, message: `${c.green}✓${c.reset} Launched ${active.DisplayName}` };
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
return { success: false, message: `Launch failed: ${err instanceof Error ? err.message : err}` };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export function stopPackage() {
|
|
141
|
+
// Kill python processes running SD
|
|
142
|
+
try {
|
|
143
|
+
const killed = tryExec("pkill -f 'launch.py\\|webui.py\\|main.py' 2>/dev/null");
|
|
144
|
+
// Also try Windows side
|
|
145
|
+
tryExec(`/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -Command "Get-Process python -ErrorAction SilentlyContinue | Where-Object {\\$_.CommandLine -like '*launch.py*'} | Stop-Process -Force" 2>/dev/null`);
|
|
146
|
+
return { success: true, message: `${c.green}✓${c.reset} Stopped SD processes` };
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return { success: false, message: "Could not stop processes" };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export function listModels(sm) {
|
|
153
|
+
const models = [];
|
|
154
|
+
const modelsDir = sm.modelsDir;
|
|
155
|
+
if (!existsSync(modelsDir))
|
|
156
|
+
return models;
|
|
157
|
+
const typeMap = {
|
|
158
|
+
"StableDiffusion": "checkpoint",
|
|
159
|
+
"Lora": "lora",
|
|
160
|
+
"VAE": "vae",
|
|
161
|
+
"TextualInversion": "embedding",
|
|
162
|
+
"ControlNet": "controlnet",
|
|
163
|
+
};
|
|
164
|
+
for (const [dirName, type] of Object.entries(typeMap)) {
|
|
165
|
+
const typeDir = resolve(modelsDir, dirName);
|
|
166
|
+
if (!existsSync(typeDir))
|
|
167
|
+
continue;
|
|
168
|
+
try {
|
|
169
|
+
for (const file of readdirSync(typeDir, { recursive: true })) {
|
|
170
|
+
const fName = String(file);
|
|
171
|
+
if (fName.endsWith(".safetensors") || fName.endsWith(".ckpt") || fName.endsWith(".pt")) {
|
|
172
|
+
const fullPath = resolve(typeDir, fName);
|
|
173
|
+
const size = tryExec(`du -sh "${fullPath}" 2>/dev/null`)?.split("\t")[0] ?? "?";
|
|
174
|
+
models.push({ name: fName, path: fullPath, size, type });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch { }
|
|
179
|
+
}
|
|
180
|
+
return models;
|
|
181
|
+
}
|
|
182
|
+
export async function downloadModel(sm, url, name) {
|
|
183
|
+
const modelsDir = resolve(sm.modelsDir, "StableDiffusion");
|
|
184
|
+
mkdirSync(modelsDir, { recursive: true });
|
|
185
|
+
const fileName = name ?? url.split("/").pop() ?? "model.safetensors";
|
|
186
|
+
const destPath = resolve(modelsDir, fileName);
|
|
187
|
+
if (existsSync(destPath)) {
|
|
188
|
+
return { success: true, message: `${c.green}✓${c.reset} Model already exists: ${fileName}` };
|
|
189
|
+
}
|
|
190
|
+
console.log(`${c.dim}Downloading model to ${destPath}...${c.reset}`);
|
|
191
|
+
try {
|
|
192
|
+
execSync(`curl -L --progress-bar -o "${destPath}" "${url}"`, { stdio: "inherit", timeout: 600000 });
|
|
193
|
+
return { success: true, message: `${c.green}✓${c.reset} Model downloaded: ${fileName}` };
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
return { success: false, message: `Download failed: ${err instanceof Error ? err.message : err}` };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ─── Status Formatting ─────────────────────────────────────────────────────
|
|
200
|
+
export function formatSMStatus(sm) {
|
|
201
|
+
const lines = [];
|
|
202
|
+
const settings = readSMSettings(sm);
|
|
203
|
+
const packages = getInstalledPackages(sm);
|
|
204
|
+
const active = getActivePackage(sm);
|
|
205
|
+
const running = isPackageRunning(sm);
|
|
206
|
+
const models = listModels(sm);
|
|
207
|
+
lines.push(`${c.bold}${c.cyan}Stability Matrix${c.reset}`);
|
|
208
|
+
lines.push(` ${c.dim}Location: ${sm.path} (${sm.platform})${c.reset}`);
|
|
209
|
+
if (settings?.PreferredGpu) {
|
|
210
|
+
const gpu = settings.PreferredGpu;
|
|
211
|
+
const vram = (gpu.MemoryBytes / 1073741824).toFixed(1);
|
|
212
|
+
lines.push(` ${c.dim}GPU: ${gpu.Name} (${vram}GB)${c.reset}`);
|
|
213
|
+
}
|
|
214
|
+
lines.push("");
|
|
215
|
+
// Packages
|
|
216
|
+
lines.push(`${c.bold}Installed Packages:${c.reset}`);
|
|
217
|
+
if (packages.length === 0) {
|
|
218
|
+
lines.push(` ${c.dim}None — open SM and click "+" to install one${c.reset}`);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
for (const pkg of packages) {
|
|
222
|
+
const isActive = pkg.Id === settings?.ActiveInstalledPackage;
|
|
223
|
+
const icon = isActive ? (running.running ? `${c.green}⬤${c.reset}` : `${c.yellow}⬤${c.reset}`) : `${c.dim}○${c.reset}`;
|
|
224
|
+
const status = isActive && running.running ? `${c.green}running${c.reset} at ${running.url}` :
|
|
225
|
+
isActive ? `${c.yellow}active (stopped)${c.reset}` : `${c.dim}inactive${c.reset}`;
|
|
226
|
+
lines.push(` ${icon} ${c.bold}${pkg.DisplayName}${c.reset} — ${status}`);
|
|
227
|
+
lines.push(` ${c.dim}Python ${pkg.PythonVersion} | ${pkg.LaunchCommand} | Branch: ${pkg.Version.InstalledBranch}${c.reset}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
lines.push("");
|
|
231
|
+
// Models
|
|
232
|
+
if (models.length > 0) {
|
|
233
|
+
lines.push(`${c.bold}Models:${c.reset}`);
|
|
234
|
+
for (const m of models) {
|
|
235
|
+
lines.push(` ${c.dim}${m.type}:${c.reset} ${m.name} (${m.size})`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
lines.push(`${c.bold}Models:${c.reset} ${c.dim}None yet — SM will download on first launch${c.reset}`);
|
|
240
|
+
}
|
|
241
|
+
return lines.join("\n");
|
|
242
|
+
}
|
|
243
|
+
// ─── Configure Launch Args ─────────────────────────────────────────────────
|
|
244
|
+
export function setLaunchArgs(sm, args) {
|
|
245
|
+
const settings = readSMSettings(sm);
|
|
246
|
+
if (!settings)
|
|
247
|
+
return;
|
|
248
|
+
const active = settings.InstalledPackages.find(p => p.Id === settings.ActiveInstalledPackage);
|
|
249
|
+
if (!active)
|
|
250
|
+
return;
|
|
251
|
+
for (const [name, value] of Object.entries(args)) {
|
|
252
|
+
const existing = active.LaunchArgs.find(a => a.Name === name);
|
|
253
|
+
if (existing) {
|
|
254
|
+
existing.OptionValue = value;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
active.LaunchArgs.push({ Name: name, Type: "Bool", OptionValue: value });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Ensure --api is always enabled for NoToken integration
|
|
261
|
+
if (!active.LaunchArgs.find(a => a.Name === "--api")) {
|
|
262
|
+
active.LaunchArgs.push({ Name: "--api", Type: "Bool", OptionValue: true });
|
|
263
|
+
}
|
|
264
|
+
writeSMSettings(sm, settings);
|
|
265
|
+
}
|
|
266
|
+
export function enableAPI(sm) {
|
|
267
|
+
setLaunchArgs(sm, { "--api": true, "--listen": true });
|
|
268
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Teach Mode — let users define custom command mappings.
|
|
3
|
+
*
|
|
4
|
+
* "remember that deploy means git pull && npm install && pm2 restart"
|
|
5
|
+
* Next time: "deploy" → runs that command chain
|
|
6
|
+
*
|
|
7
|
+
* Stored in ~/.notoken/learned-commands.json
|
|
8
|
+
*/
|
|
9
|
+
interface LearnedCommand {
|
|
10
|
+
trigger: string;
|
|
11
|
+
command: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
learnedAt: string;
|
|
14
|
+
usedCount: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Teach a new command.
|
|
18
|
+
* "remember that deploy means git pull && npm install && pm2 restart api"
|
|
19
|
+
*/
|
|
20
|
+
export declare function teachCommand(trigger: string, command: string, description?: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Look up a learned command by trigger.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getLearnedCommand(trigger: string): LearnedCommand | null;
|
|
25
|
+
/**
|
|
26
|
+
* List all learned commands.
|
|
27
|
+
*/
|
|
28
|
+
export declare function listLearnedCommands(): LearnedCommand[];
|
|
29
|
+
/**
|
|
30
|
+
* Forget a learned command.
|
|
31
|
+
*/
|
|
32
|
+
export declare function forgetCommand(trigger: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Parse a "remember that X means Y" statement.
|
|
35
|
+
* Returns { trigger, command } or null.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseTeachStatement(text: string): {
|
|
38
|
+
trigger: string;
|
|
39
|
+
command: string;
|
|
40
|
+
} | null;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Teach Mode — let users define custom command mappings.
|
|
3
|
+
*
|
|
4
|
+
* "remember that deploy means git pull && npm install && pm2 restart"
|
|
5
|
+
* Next time: "deploy" → runs that command chain
|
|
6
|
+
*
|
|
7
|
+
* Stored in ~/.notoken/learned-commands.json
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
|
+
const LEARNED_PATH = resolve(homedir(), ".notoken", "learned-commands.json");
|
|
13
|
+
let _commands = null;
|
|
14
|
+
function load() {
|
|
15
|
+
if (_commands)
|
|
16
|
+
return _commands;
|
|
17
|
+
if (existsSync(LEARNED_PATH)) {
|
|
18
|
+
try {
|
|
19
|
+
_commands = JSON.parse(readFileSync(LEARNED_PATH, "utf-8"));
|
|
20
|
+
return _commands;
|
|
21
|
+
}
|
|
22
|
+
catch { }
|
|
23
|
+
}
|
|
24
|
+
_commands = [];
|
|
25
|
+
return _commands;
|
|
26
|
+
}
|
|
27
|
+
function save() {
|
|
28
|
+
const dir = resolve(LEARNED_PATH, "..");
|
|
29
|
+
if (!existsSync(dir))
|
|
30
|
+
mkdirSync(dir, { recursive: true });
|
|
31
|
+
writeFileSync(LEARNED_PATH, JSON.stringify(load(), null, 2));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Teach a new command.
|
|
35
|
+
* "remember that deploy means git pull && npm install && pm2 restart api"
|
|
36
|
+
*/
|
|
37
|
+
export function teachCommand(trigger, command, description) {
|
|
38
|
+
const cmds = load();
|
|
39
|
+
const existing = cmds.findIndex(c => c.trigger.toLowerCase() === trigger.toLowerCase());
|
|
40
|
+
if (existing >= 0) {
|
|
41
|
+
cmds[existing].command = command;
|
|
42
|
+
cmds[existing].description = description;
|
|
43
|
+
cmds[existing].learnedAt = new Date().toISOString();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
cmds.push({ trigger: trigger.toLowerCase(), command, description, learnedAt: new Date().toISOString(), usedCount: 0 });
|
|
47
|
+
}
|
|
48
|
+
save();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Look up a learned command by trigger.
|
|
52
|
+
*/
|
|
53
|
+
export function getLearnedCommand(trigger) {
|
|
54
|
+
const cmds = load();
|
|
55
|
+
const found = cmds.find(c => c.trigger.toLowerCase() === trigger.toLowerCase());
|
|
56
|
+
if (found) {
|
|
57
|
+
found.usedCount++;
|
|
58
|
+
if (found.usedCount % 5 === 0)
|
|
59
|
+
save(); // periodic save
|
|
60
|
+
}
|
|
61
|
+
return found ?? null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* List all learned commands.
|
|
65
|
+
*/
|
|
66
|
+
export function listLearnedCommands() {
|
|
67
|
+
return [...load()].sort((a, b) => b.usedCount - a.usedCount);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Forget a learned command.
|
|
71
|
+
*/
|
|
72
|
+
export function forgetCommand(trigger) {
|
|
73
|
+
const cmds = load();
|
|
74
|
+
const idx = cmds.findIndex(c => c.trigger.toLowerCase() === trigger.toLowerCase());
|
|
75
|
+
if (idx >= 0) {
|
|
76
|
+
cmds.splice(idx, 1);
|
|
77
|
+
save();
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Parse a "remember that X means Y" statement.
|
|
84
|
+
* Returns { trigger, command } or null.
|
|
85
|
+
*/
|
|
86
|
+
export function parseTeachStatement(text) {
|
|
87
|
+
// "remember that deploy means git pull && npm install"
|
|
88
|
+
const m1 = text.match(/^remember\s+(?:that\s+)?(.+?)\s+(?:means|is|equals|does|runs|executes)\s+(.+)$/i);
|
|
89
|
+
if (m1)
|
|
90
|
+
return { trigger: m1[1].trim(), command: m1[2].trim() };
|
|
91
|
+
// "when I say deploy, run git pull && npm install"
|
|
92
|
+
const m2 = text.match(/^when\s+(?:i\s+)?say\s+(.+?),?\s+(?:run|execute|do)\s+(.+)$/i);
|
|
93
|
+
if (m2)
|
|
94
|
+
return { trigger: m2[1].trim(), command: m2[2].trim() };
|
|
95
|
+
// "teach: deploy = git pull && npm install"
|
|
96
|
+
const m3 = text.match(/^teach:?\s+(.+?)\s*=\s*(.+)$/i);
|
|
97
|
+
if (m3)
|
|
98
|
+
return { trigger: m3[1].trim(), command: m3[2].trim() };
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timer / Reminders — lightweight in-process countdown timers.
|
|
3
|
+
*
|
|
4
|
+
* When a timer expires it pushes a message to `pendingNotifications`
|
|
5
|
+
* so the next REPL tick can display it.
|
|
6
|
+
*/
|
|
7
|
+
export interface Timer {
|
|
8
|
+
id: number;
|
|
9
|
+
label: string;
|
|
10
|
+
endsAt: number;
|
|
11
|
+
timeout: NodeJS.Timeout;
|
|
12
|
+
}
|
|
13
|
+
/** Messages ready for the REPL to display on next tick. */
|
|
14
|
+
export declare const pendingNotifications: string[];
|
|
15
|
+
/** Start a countdown timer. Returns the timer ID. */
|
|
16
|
+
export declare function startTimer(minutes: number, label?: string): number;
|
|
17
|
+
/** List active timers with remaining time. */
|
|
18
|
+
export declare function listTimers(): string;
|
|
19
|
+
/** Cancel a timer by ID. Returns true if found. */
|
|
20
|
+
export declare function cancelTimer(id: number): boolean;
|
|
21
|
+
/** Drain all pending notifications (caller should display them). */
|
|
22
|
+
export declare function drainNotifications(): string[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timer / Reminders — lightweight in-process countdown timers.
|
|
3
|
+
*
|
|
4
|
+
* When a timer expires it pushes a message to `pendingNotifications`
|
|
5
|
+
* so the next REPL tick can display it.
|
|
6
|
+
*/
|
|
7
|
+
let nextId = 1;
|
|
8
|
+
const timers = new Map();
|
|
9
|
+
/** Messages ready for the REPL to display on next tick. */
|
|
10
|
+
export const pendingNotifications = [];
|
|
11
|
+
/** Start a countdown timer. Returns the timer ID. */
|
|
12
|
+
export function startTimer(minutes, label) {
|
|
13
|
+
const id = nextId++;
|
|
14
|
+
const tag = label ?? `Timer #${id}`;
|
|
15
|
+
const ms = minutes * 60_000;
|
|
16
|
+
const endsAt = Date.now() + ms;
|
|
17
|
+
const timeout = setTimeout(() => {
|
|
18
|
+
timers.delete(id);
|
|
19
|
+
pendingNotifications.push(`\x1b[33m⏰ ${tag} — ${minutes} min timer finished!\x1b[0m`);
|
|
20
|
+
}, ms);
|
|
21
|
+
// Allow the Node process to exit even if timers are running
|
|
22
|
+
if (timeout.unref)
|
|
23
|
+
timeout.unref();
|
|
24
|
+
timers.set(id, { id, label: tag, endsAt, timeout });
|
|
25
|
+
return id;
|
|
26
|
+
}
|
|
27
|
+
/** List active timers with remaining time. */
|
|
28
|
+
export function listTimers() {
|
|
29
|
+
if (timers.size === 0)
|
|
30
|
+
return "No active timers.";
|
|
31
|
+
const lines = [];
|
|
32
|
+
for (const t of timers.values()) {
|
|
33
|
+
const remaining = Math.max(0, Math.ceil((t.endsAt - Date.now()) / 1000));
|
|
34
|
+
const m = Math.floor(remaining / 60);
|
|
35
|
+
const s = remaining % 60;
|
|
36
|
+
lines.push(` #${t.id} ${t.label} — ${m}m ${s}s remaining`);
|
|
37
|
+
}
|
|
38
|
+
return `Active timers:\n${lines.join("\n")}`;
|
|
39
|
+
}
|
|
40
|
+
/** Cancel a timer by ID. Returns true if found. */
|
|
41
|
+
export function cancelTimer(id) {
|
|
42
|
+
const t = timers.get(id);
|
|
43
|
+
if (!t)
|
|
44
|
+
return false;
|
|
45
|
+
clearTimeout(t.timeout);
|
|
46
|
+
timers.delete(id);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/** Drain all pending notifications (caller should display them). */
|
|
50
|
+
export function drainNotifications() {
|
|
51
|
+
return pendingNotifications.splice(0, pendingNotifications.length);
|
|
52
|
+
}
|
package/dist/utils/updater.d.ts
CHANGED
package/dist/utils/updater.js
CHANGED
|
@@ -113,7 +113,7 @@ function getInstalledVersion() {
|
|
|
113
113
|
return "0.0.0";
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
function isNewer(latest, current) {
|
|
116
|
+
export function isNewer(latest, current) {
|
|
117
117
|
const l = latest.split(".").map(Number);
|
|
118
118
|
const c = current.split(".").map(Number);
|
|
119
119
|
for (let i = 0; i < 3; i++) {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Context — detect who's running notoken and where their configs live.
|
|
3
|
+
*
|
|
4
|
+
* Handles: root, regular user, WSL user running as root, Windows user
|
|
5
|
+
* Prevents: auth conflicts, wrong config paths, stale tokens from other users
|
|
6
|
+
*/
|
|
7
|
+
export interface UserContext {
|
|
8
|
+
/** Effective user running the process */
|
|
9
|
+
effectiveUser: string;
|
|
10
|
+
/** Logged-in user (may differ from effective in sudo/WSL) */
|
|
11
|
+
loginUser: string;
|
|
12
|
+
/** Home directory of the effective user */
|
|
13
|
+
homeDir: string;
|
|
14
|
+
/** Home directory of the login user (for finding their configs) */
|
|
15
|
+
loginHomeDir: string;
|
|
16
|
+
/** Whether running as root */
|
|
17
|
+
isRoot: boolean;
|
|
18
|
+
/** Whether running in WSL */
|
|
19
|
+
isWSL: boolean;
|
|
20
|
+
/** Whether running on native Windows */
|
|
21
|
+
isWindows: boolean;
|
|
22
|
+
/** Windows user profile path (if in WSL or Windows) */
|
|
23
|
+
windowsProfile: string | null;
|
|
24
|
+
/** Path to this user's OpenClaw config */
|
|
25
|
+
openclawHome: string;
|
|
26
|
+
/** Path to this user's Claude credentials */
|
|
27
|
+
claudeCredsPath: string;
|
|
28
|
+
/** Path to this user's Codex auth */
|
|
29
|
+
codexAuthPath: string;
|
|
30
|
+
/** Path to this user's notoken data */
|
|
31
|
+
notokenHome: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Detect the current user context.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getUserContext(): UserContext;
|
|
37
|
+
/**
|
|
38
|
+
* Get the right OpenClaw auth profiles path for the current user.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getAuthProfilesPath(): string;
|
|
41
|
+
/**
|
|
42
|
+
* Detect if there's a user mismatch (running as root but configs belong to another user).
|
|
43
|
+
*/
|
|
44
|
+
export declare function detectUserMismatch(): {
|
|
45
|
+
mismatch: boolean;
|
|
46
|
+
message: string;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Find the freshest Claude token across all users.
|
|
50
|
+
*/
|
|
51
|
+
export declare function findFreshestClaudeToken(): {
|
|
52
|
+
token: string;
|
|
53
|
+
expires: number;
|
|
54
|
+
source: string;
|
|
55
|
+
} | null;
|
|
56
|
+
/** Reset cache (for testing). */
|
|
57
|
+
export declare function resetUserContext(): void;
|