notoken-core 1.0.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 (118) hide show
  1. package/config/file-hints.json +255 -0
  2. package/config/hosts.json +14 -0
  3. package/config/intents.json +3920 -0
  4. package/config/playbooks.json +112 -0
  5. package/config/rules.json +100 -0
  6. package/dist/agents/agentSpawner.d.ts +56 -0
  7. package/dist/agents/agentSpawner.js +180 -0
  8. package/dist/agents/planner.d.ts +40 -0
  9. package/dist/agents/planner.js +175 -0
  10. package/dist/agents/playbookRunner.d.ts +45 -0
  11. package/dist/agents/playbookRunner.js +120 -0
  12. package/dist/agents/taskRunner.d.ts +61 -0
  13. package/dist/agents/taskRunner.js +142 -0
  14. package/dist/context/history.d.ts +36 -0
  15. package/dist/context/history.js +115 -0
  16. package/dist/conversation/coreference.d.ts +27 -0
  17. package/dist/conversation/coreference.js +147 -0
  18. package/dist/conversation/secrets.d.ts +43 -0
  19. package/dist/conversation/secrets.js +129 -0
  20. package/dist/conversation/store.d.ts +94 -0
  21. package/dist/conversation/store.js +184 -0
  22. package/dist/execution/git.d.ts +11 -0
  23. package/dist/execution/git.js +146 -0
  24. package/dist/execution/ssh.d.ts +2 -0
  25. package/dist/execution/ssh.js +17 -0
  26. package/dist/handlers/executor.d.ts +8 -0
  27. package/dist/handlers/executor.js +216 -0
  28. package/dist/healing/claudeHealer.d.ts +17 -0
  29. package/dist/healing/claudeHealer.js +300 -0
  30. package/dist/healing/patchPromoter.d.ts +25 -0
  31. package/dist/healing/patchPromoter.js +118 -0
  32. package/dist/healing/ruleBuilder.d.ts +5 -0
  33. package/dist/healing/ruleBuilder.js +111 -0
  34. package/dist/healing/ruleRepairer.d.ts +8 -0
  35. package/dist/healing/ruleRepairer.js +29 -0
  36. package/dist/healing/ruleValidator.d.ts +22 -0
  37. package/dist/healing/ruleValidator.js +145 -0
  38. package/dist/healing/runHealer.d.ts +11 -0
  39. package/dist/healing/runHealer.js +74 -0
  40. package/dist/index.d.ts +51 -0
  41. package/dist/index.js +62 -0
  42. package/dist/intents/catalog.d.ts +4 -0
  43. package/dist/intents/catalog.js +7 -0
  44. package/dist/nlp/disambiguate.d.ts +2 -0
  45. package/dist/nlp/disambiguate.js +46 -0
  46. package/dist/nlp/fuzzyResolver.d.ts +14 -0
  47. package/dist/nlp/fuzzyResolver.js +108 -0
  48. package/dist/nlp/llmFallback.d.ts +63 -0
  49. package/dist/nlp/llmFallback.js +338 -0
  50. package/dist/nlp/llmParser.d.ts +8 -0
  51. package/dist/nlp/llmParser.js +118 -0
  52. package/dist/nlp/multiClassifier.d.ts +39 -0
  53. package/dist/nlp/multiClassifier.js +181 -0
  54. package/dist/nlp/parseIntent.d.ts +2 -0
  55. package/dist/nlp/parseIntent.js +34 -0
  56. package/dist/nlp/ruleParser.d.ts +2 -0
  57. package/dist/nlp/ruleParser.js +234 -0
  58. package/dist/nlp/semantic.d.ts +104 -0
  59. package/dist/nlp/semantic.js +419 -0
  60. package/dist/nlp/uncertainty.d.ts +42 -0
  61. package/dist/nlp/uncertainty.js +103 -0
  62. package/dist/parsers/apacheParser.d.ts +50 -0
  63. package/dist/parsers/apacheParser.js +152 -0
  64. package/dist/parsers/bindParser.d.ts +40 -0
  65. package/dist/parsers/bindParser.js +189 -0
  66. package/dist/parsers/envFile.d.ts +39 -0
  67. package/dist/parsers/envFile.js +128 -0
  68. package/dist/parsers/fileFinder.d.ts +30 -0
  69. package/dist/parsers/fileFinder.js +226 -0
  70. package/dist/parsers/index.d.ts +27 -0
  71. package/dist/parsers/index.js +193 -0
  72. package/dist/parsers/jsonParser.d.ts +16 -0
  73. package/dist/parsers/jsonParser.js +57 -0
  74. package/dist/parsers/nginxParser.d.ts +47 -0
  75. package/dist/parsers/nginxParser.js +161 -0
  76. package/dist/parsers/passwd.d.ts +25 -0
  77. package/dist/parsers/passwd.js +41 -0
  78. package/dist/parsers/shadow.d.ts +23 -0
  79. package/dist/parsers/shadow.js +50 -0
  80. package/dist/parsers/yamlParser.d.ts +13 -0
  81. package/dist/parsers/yamlParser.js +54 -0
  82. package/dist/policy/confirm.d.ts +2 -0
  83. package/dist/policy/confirm.js +29 -0
  84. package/dist/policy/safety.d.ts +4 -0
  85. package/dist/policy/safety.js +32 -0
  86. package/dist/types/intent.d.ts +205 -0
  87. package/dist/types/intent.js +32 -0
  88. package/dist/types/rules.d.ts +237 -0
  89. package/dist/types/rules.js +50 -0
  90. package/dist/utils/analysis.d.ts +25 -0
  91. package/dist/utils/analysis.js +307 -0
  92. package/dist/utils/autoBackup.d.ts +43 -0
  93. package/dist/utils/autoBackup.js +144 -0
  94. package/dist/utils/config.d.ts +11 -0
  95. package/dist/utils/config.js +32 -0
  96. package/dist/utils/dirAnalysis.d.ts +23 -0
  97. package/dist/utils/dirAnalysis.js +192 -0
  98. package/dist/utils/explain.d.ts +8 -0
  99. package/dist/utils/explain.js +145 -0
  100. package/dist/utils/logger.d.ts +5 -0
  101. package/dist/utils/logger.js +29 -0
  102. package/dist/utils/output.d.ts +2 -0
  103. package/dist/utils/output.js +26 -0
  104. package/dist/utils/paths.d.ts +26 -0
  105. package/dist/utils/paths.js +47 -0
  106. package/dist/utils/permissions.d.ts +64 -0
  107. package/dist/utils/permissions.js +298 -0
  108. package/dist/utils/platform.d.ts +53 -0
  109. package/dist/utils/platform.js +253 -0
  110. package/dist/utils/smartFile.d.ts +29 -0
  111. package/dist/utils/smartFile.js +188 -0
  112. package/dist/utils/spinner.d.ts +53 -0
  113. package/dist/utils/spinner.js +140 -0
  114. package/dist/utils/verbose.d.ts +27 -0
  115. package/dist/utils/verbose.js +131 -0
  116. package/dist/utils/wslPaths.d.ts +31 -0
  117. package/dist/utils/wslPaths.js +145 -0
  118. package/package.json +39 -0
@@ -0,0 +1,27 @@
1
+ import type { ParsedCommand } from "../types/intent.js";
2
+ /**
3
+ * Generate a verbose, human-friendly restatement of the parsed command.
4
+ *
5
+ * Example output:
6
+ *
7
+ * I understand you want to:
8
+ * Action: restart nginx
9
+ * Environment: prod
10
+ * Risk: high — confirmation required
11
+ * Command: sudo systemctl restart nginx && ...
12
+ */
13
+ export declare function formatVerbose(parsed: ParsedCommand): string;
14
+ /**
15
+ * Format a background task notification.
16
+ */
17
+ export declare function formatTaskNotification(id: number, name: string, status: "completed" | "failed", duration?: number): string;
18
+ /**
19
+ * Format the background jobs list.
20
+ */
21
+ export declare function formatJobsList(tasks: Array<{
22
+ id: number;
23
+ rawText: string;
24
+ status: string;
25
+ startedAt: Date;
26
+ completedAt?: Date;
27
+ }>): string;
@@ -0,0 +1,131 @@
1
+ import { getIntentDef } from "./config.js";
2
+ const c = {
3
+ reset: "\x1b[0m",
4
+ bold: "\x1b[1m",
5
+ dim: "\x1b[2m",
6
+ green: "\x1b[32m",
7
+ yellow: "\x1b[33m",
8
+ red: "\x1b[31m",
9
+ cyan: "\x1b[36m",
10
+ magenta: "\x1b[35m",
11
+ white: "\x1b[37m",
12
+ };
13
+ const RISK_COLOR = {
14
+ low: c.green,
15
+ medium: c.yellow,
16
+ high: c.red,
17
+ };
18
+ /**
19
+ * Generate a verbose, human-friendly restatement of the parsed command.
20
+ *
21
+ * Example output:
22
+ *
23
+ * I understand you want to:
24
+ * Action: restart nginx
25
+ * Environment: prod
26
+ * Risk: high — confirmation required
27
+ * Command: sudo systemctl restart nginx && ...
28
+ */
29
+ export function formatVerbose(parsed) {
30
+ const { intent } = parsed;
31
+ const def = getIntentDef(intent.intent);
32
+ const lines = [];
33
+ lines.push(`${c.bold}I understand you want to:${c.reset}`);
34
+ lines.push("");
35
+ // Action description
36
+ if (def) {
37
+ lines.push(` ${c.cyan}Action:${c.reset} ${def.description}`);
38
+ }
39
+ lines.push(` ${c.cyan}Intent:${c.reset} ${c.bold}${intent.intent}${c.reset}`);
40
+ lines.push(` ${c.cyan}Confidence:${c.reset} ${formatConfidence(intent.confidence)}`);
41
+ // Fields
42
+ // Fields — show explicit values, skip internal/empty ones
43
+ const fields = Object.entries(intent.fields).filter(([k, v]) => v !== undefined && v !== "" && k !== "logPath");
44
+ if (fields.length > 0) {
45
+ lines.push("");
46
+ for (const [key, value] of fields) {
47
+ const label = key.charAt(0).toUpperCase() + key.slice(1);
48
+ lines.push(` ${c.cyan}${label}:${c.reset}${" ".repeat(Math.max(1, 12 - label.length))}${c.bold}${value}${c.reset}`);
49
+ }
50
+ }
51
+ // Risk + confirmation
52
+ if (def) {
53
+ const riskColor = RISK_COLOR[def.riskLevel] ?? c.white;
54
+ const confirm = def.requiresConfirmation ? " — confirmation required" : "";
55
+ lines.push("");
56
+ lines.push(` ${c.cyan}Risk:${c.reset} ${riskColor}${def.riskLevel}${confirm}${c.reset}`);
57
+ }
58
+ // Show the resolved command template
59
+ if (def) {
60
+ const command = previewCommand(def, intent.fields);
61
+ if (command.length < 120) {
62
+ lines.push(` ${c.cyan}Command:${c.reset} ${c.dim}${command}${c.reset}`);
63
+ }
64
+ else {
65
+ lines.push(` ${c.cyan}Command:${c.reset} ${c.dim}${command.slice(0, 117)}...${c.reset}`);
66
+ }
67
+ }
68
+ // Warnings
69
+ if (parsed.needsClarification) {
70
+ lines.push("");
71
+ lines.push(` ${c.yellow}⚠ Clarification needed${c.reset}`);
72
+ if (parsed.missingFields.length > 0) {
73
+ lines.push(` Missing: ${parsed.missingFields.join(", ")}`);
74
+ }
75
+ for (const a of parsed.ambiguousFields) {
76
+ lines.push(` ${a.field}: did you mean ${a.candidates.join(" or ")}?`);
77
+ }
78
+ }
79
+ return lines.join("\n");
80
+ }
81
+ function formatConfidence(conf) {
82
+ const pct = (conf * 100).toFixed(0);
83
+ if (conf >= 0.8)
84
+ return `${c.green}${pct}%${c.reset}`;
85
+ if (conf >= 0.6)
86
+ return `${c.yellow}${pct}%${c.reset}`;
87
+ return `${c.red}${pct}%${c.reset}`;
88
+ }
89
+ function previewCommand(def, fields) {
90
+ let cmd = def.command;
91
+ for (const [key, value] of Object.entries(fields)) {
92
+ if (value !== undefined && value !== null) {
93
+ cmd = cmd.replaceAll(`{{${key}}}`, String(value));
94
+ }
95
+ }
96
+ for (const [name, fieldDef] of Object.entries(def.fields)) {
97
+ if (fieldDef.default !== undefined) {
98
+ cmd = cmd.replaceAll(`{{${name}}}`, String(fieldDef.default));
99
+ }
100
+ }
101
+ cmd = cmd.replace(/\{\{[a-zA-Z_]+\}\}/g, "").trim();
102
+ return cmd;
103
+ }
104
+ /**
105
+ * Format a background task notification.
106
+ */
107
+ export function formatTaskNotification(id, name, status, duration) {
108
+ const icon = status === "completed" ? `${c.green}✓${c.reset}` : `${c.red}✗${c.reset}`;
109
+ const dur = duration ? ` (${(duration / 1000).toFixed(1)}s)` : "";
110
+ return `\n${icon} ${c.dim}[bg #${id}]${c.reset} ${name} ${status}${dur}`;
111
+ }
112
+ /**
113
+ * Format the background jobs list.
114
+ */
115
+ export function formatJobsList(tasks) {
116
+ if (tasks.length === 0)
117
+ return `${c.dim}No background tasks.${c.reset}`;
118
+ const lines = [];
119
+ lines.push(`${c.bold}Background tasks:${c.reset}`);
120
+ for (const t of tasks) {
121
+ const statusColor = t.status === "running" ? c.cyan :
122
+ t.status === "completed" ? c.green :
123
+ t.status === "failed" ? c.red :
124
+ c.yellow;
125
+ const duration = t.completedAt
126
+ ? `${((t.completedAt.getTime() - t.startedAt.getTime()) / 1000).toFixed(1)}s`
127
+ : `${((Date.now() - t.startedAt.getTime()) / 1000).toFixed(0)}s...`;
128
+ lines.push(` ${c.dim}#${t.id}${c.reset} ${statusColor}${t.status.padEnd(10)}${c.reset} ${t.rawText} ${c.dim}(${duration})${c.reset}`);
129
+ }
130
+ return lines.join("\n");
131
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Windows/WSL path support.
3
+ *
4
+ * Handles:
5
+ * - Detecting WSL environment
6
+ * - Converting between Windows (C:\Users\...) and Linux (/mnt/c/Users/...) paths
7
+ * - Resolving ~ and %USERPROFILE% across platforms
8
+ * - Path normalization for cross-platform commands
9
+ */
10
+ declare const isWSL: any;
11
+ declare const isWindows: boolean;
12
+ /**
13
+ * Convert a Windows path to WSL Linux path.
14
+ * C:\Users\dino\docs → /mnt/c/Users/dino/docs
15
+ */
16
+ export declare function winToLinux(winPath: string): string;
17
+ /**
18
+ * Convert a WSL Linux path to Windows path.
19
+ * /mnt/c/Users/dino/docs → C:\Users\dino\docs
20
+ */
21
+ export declare function linuxToWin(linuxPath: string): string;
22
+ /**
23
+ * Normalize a path for the current platform.
24
+ * Accepts either Windows or Linux format, returns appropriate format.
25
+ */
26
+ export declare function normalizePath(inputPath: string): string;
27
+ /**
28
+ * Get common user directories in the correct format.
29
+ */
30
+ export declare function getUserDirs(): Record<string, string>;
31
+ export { isWSL, isWindows };
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Windows/WSL path support.
3
+ *
4
+ * Handles:
5
+ * - Detecting WSL environment
6
+ * - Converting between Windows (C:\Users\...) and Linux (/mnt/c/Users/...) paths
7
+ * - Resolving ~ and %USERPROFILE% across platforms
8
+ * - Path normalization for cross-platform commands
9
+ */
10
+ import { execSync } from "node:child_process";
11
+ import { platform as osPlatform } from "node:os";
12
+ import { resolve } from "node:path";
13
+ const isWSL = osPlatform() === "linux" && (process.env.WSL_DISTRO_NAME !== undefined ||
14
+ process.env.WSLENV !== undefined ||
15
+ (() => { try {
16
+ return require("os").release().toLowerCase().includes("microsoft");
17
+ }
18
+ catch {
19
+ return false;
20
+ } })());
21
+ const isWindows = osPlatform() === "win32";
22
+ /**
23
+ * Convert a Windows path to WSL Linux path.
24
+ * C:\Users\dino\docs → /mnt/c/Users/dino/docs
25
+ */
26
+ export function winToLinux(winPath) {
27
+ if (!winPath)
28
+ return winPath;
29
+ // Already a Linux path
30
+ if (winPath.startsWith("/"))
31
+ return winPath;
32
+ // Try wslpath if available (most reliable)
33
+ if (isWSL) {
34
+ try {
35
+ return execSync(`wslpath -u ${JSON.stringify(winPath)}`, { encoding: "utf-8", timeout: 3000 }).trim();
36
+ }
37
+ catch { }
38
+ }
39
+ // Manual conversion: C:\Users\... → /mnt/c/Users/...
40
+ const match = winPath.match(/^([A-Za-z]):[\\\/](.*)/);
41
+ if (match) {
42
+ const drive = match[1].toLowerCase();
43
+ const rest = match[2].replace(/\\/g, "/");
44
+ return `/mnt/${drive}/${rest}`;
45
+ }
46
+ // UNC path: \\server\share → /mnt/server/share (approximation)
47
+ if (winPath.startsWith("\\\\")) {
48
+ return winPath.replace(/\\/g, "/").replace(/^\/\//, "/mnt/");
49
+ }
50
+ return winPath;
51
+ }
52
+ /**
53
+ * Convert a WSL Linux path to Windows path.
54
+ * /mnt/c/Users/dino/docs → C:\Users\dino\docs
55
+ */
56
+ export function linuxToWin(linuxPath) {
57
+ if (!linuxPath)
58
+ return linuxPath;
59
+ // Already a Windows path
60
+ if (/^[A-Za-z]:/.test(linuxPath))
61
+ return linuxPath;
62
+ // Try wslpath if available
63
+ if (isWSL) {
64
+ try {
65
+ return execSync(`wslpath -w ${JSON.stringify(linuxPath)}`, { encoding: "utf-8", timeout: 3000 }).trim();
66
+ }
67
+ catch { }
68
+ }
69
+ // Manual: /mnt/c/Users/... → C:\Users\...
70
+ const match = linuxPath.match(/^\/mnt\/([a-z])\/(.*)/);
71
+ if (match) {
72
+ const drive = match[1].toUpperCase();
73
+ const rest = match[2].replace(/\//g, "\\");
74
+ return `${drive}:\\${rest}`;
75
+ }
76
+ return linuxPath;
77
+ }
78
+ /**
79
+ * Normalize a path for the current platform.
80
+ * Accepts either Windows or Linux format, returns appropriate format.
81
+ */
82
+ export function normalizePath(inputPath) {
83
+ if (!inputPath)
84
+ return inputPath;
85
+ // Expand ~ to home directory
86
+ if (inputPath.startsWith("~")) {
87
+ const home = process.env.HOME || process.env.USERPROFILE || "";
88
+ inputPath = resolve(home, inputPath.slice(2));
89
+ }
90
+ // Expand %USERPROFILE% (Windows env var)
91
+ if (inputPath.includes("%USERPROFILE%")) {
92
+ const profile = process.env.USERPROFILE || process.env.HOME || "";
93
+ inputPath = inputPath.replace(/%USERPROFILE%/gi, profile);
94
+ }
95
+ // On WSL: convert Windows paths to Linux paths
96
+ if (isWSL && /^[A-Za-z]:/.test(inputPath)) {
97
+ return winToLinux(inputPath);
98
+ }
99
+ // On Windows: convert Linux-style /mnt/c paths
100
+ if (isWindows && inputPath.startsWith("/mnt/")) {
101
+ return linuxToWin(inputPath);
102
+ }
103
+ return inputPath;
104
+ }
105
+ /**
106
+ * Get common user directories in the correct format.
107
+ */
108
+ export function getUserDirs() {
109
+ const home = process.env.HOME || process.env.USERPROFILE || "";
110
+ if (isWindows) {
111
+ const profile = process.env.USERPROFILE || "";
112
+ return {
113
+ home: profile,
114
+ documents: resolve(profile, "Documents"),
115
+ downloads: resolve(profile, "Downloads"),
116
+ desktop: resolve(profile, "Desktop"),
117
+ };
118
+ }
119
+ if (isWSL) {
120
+ // In WSL, get both Linux home and Windows home
121
+ const winHome = tryExec("wslpath -u \"$(cmd.exe /c 'echo %USERPROFILE%' 2>/dev/null | tr -d '\\r')\"");
122
+ return {
123
+ home,
124
+ documents: winHome ? `${winHome}/Documents` : resolve(home, "Documents"),
125
+ downloads: winHome ? `${winHome}/Downloads` : resolve(home, "Downloads"),
126
+ desktop: winHome ? `${winHome}/Desktop` : resolve(home, "Desktop"),
127
+ winHome: winHome || "",
128
+ };
129
+ }
130
+ return {
131
+ home,
132
+ documents: resolve(home, "Documents"),
133
+ downloads: resolve(home, "Downloads"),
134
+ desktop: resolve(home, "Desktop"),
135
+ };
136
+ }
137
+ export { isWSL, isWindows };
138
+ function tryExec(cmd) {
139
+ try {
140
+ return execSync(cmd, { encoding: "utf-8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"] }).trim() || null;
141
+ }
142
+ catch {
143
+ return null;
144
+ }
145
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "notoken-core",
3
+ "version": "1.0.0",
4
+ "description": "Shared engine for notoken — NLP parsing, execution, detection, analysis",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Dino Bartolome",
8
+ "homepage": "https://notoken.sh",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/offset25/notoken-cli",
12
+ "directory": "packages/core"
13
+ },
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": "./dist/index.js"
18
+ },
19
+ "files": ["dist/", "config/"],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "test": "vitest run"
23
+ },
24
+ "dependencies": {
25
+ "compromise": "^14.15.0",
26
+ "dotenv": "^17.3.1",
27
+ "simple-git": "^3.33.0",
28
+ "yaml": "^2.8.3",
29
+ "zod": "^3.22.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^20.0.0",
33
+ "typescript": "^5.3.0",
34
+ "vitest": "^1.6.1"
35
+ },
36
+ "engines": {
37
+ "node": ">=18"
38
+ }
39
+ }