serpentstack 0.2.5 → 0.2.9
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/bin/serpentstack.js +76 -29
- package/lib/commands/persistent.js +318 -286
- package/lib/commands/skills-init.js +61 -23
- package/lib/commands/skills-update.js +10 -8
- package/lib/commands/stack-new.js +56 -21
- package/lib/utils/agent-utils.js +1 -1
- package/lib/utils/config.js +14 -7
- package/lib/utils/fs-helpers.js +1 -1
- package/lib/utils/models.js +181 -0
- package/lib/utils/ui.js +70 -49
- package/package.json +3 -3
package/bin/serpentstack.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { error, bold, dim, green, cyan, getVersion, printHeader } from '../lib/utils/ui.js';
|
|
3
|
+
import { error, bold, dim, green, cyan, yellow, getVersion, printHeader, divider } from '../lib/utils/ui.js';
|
|
4
|
+
|
|
5
|
+
// Short flag aliases
|
|
6
|
+
const FLAG_ALIASES = { f: 'force', h: 'help', v: 'version', a: 'all' };
|
|
4
7
|
|
|
5
8
|
function parseArgs(args) {
|
|
6
9
|
const flags = {};
|
|
@@ -9,6 +12,13 @@ function parseArgs(args) {
|
|
|
9
12
|
if (arg.startsWith('--')) {
|
|
10
13
|
const [key, val] = arg.slice(2).split('=');
|
|
11
14
|
flags[key] = val ?? true;
|
|
15
|
+
} else if (arg.startsWith('-') && arg.length > 1 && !arg.startsWith('--')) {
|
|
16
|
+
// Short flags: -f, -h, -v, -a, or combined like -fa
|
|
17
|
+
for (const ch of arg.slice(1)) {
|
|
18
|
+
const long = FLAG_ALIASES[ch];
|
|
19
|
+
if (long) flags[long] = true;
|
|
20
|
+
else flags[ch] = true;
|
|
21
|
+
}
|
|
12
22
|
} else {
|
|
13
23
|
positional.push(arg);
|
|
14
24
|
}
|
|
@@ -16,35 +26,67 @@ function parseArgs(args) {
|
|
|
16
26
|
return { flags, positional };
|
|
17
27
|
}
|
|
18
28
|
|
|
29
|
+
// Known commands for fuzzy matching on typos
|
|
30
|
+
const KNOWN_COMMANDS = ['stack', 'skills', 'persistent'];
|
|
31
|
+
|
|
32
|
+
function suggestCommand(input) {
|
|
33
|
+
const lower = input.toLowerCase();
|
|
34
|
+
let best = null, bestDist = 3; // threshold: edit distance ≤ 2
|
|
35
|
+
for (const cmd of KNOWN_COMMANDS) {
|
|
36
|
+
if (cmd.startsWith(lower) || lower.startsWith(cmd)) return cmd;
|
|
37
|
+
const d = editDistance(lower, cmd);
|
|
38
|
+
if (d < bestDist) { bestDist = d; best = cmd; }
|
|
39
|
+
}
|
|
40
|
+
return best;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function editDistance(a, b) {
|
|
44
|
+
const m = a.length, n = b.length;
|
|
45
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1));
|
|
46
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
47
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
48
|
+
for (let i = 1; i <= m; i++)
|
|
49
|
+
for (let j = 1; j <= n; j++)
|
|
50
|
+
dp[i][j] = Math.min(
|
|
51
|
+
dp[i - 1][j] + 1,
|
|
52
|
+
dp[i][j - 1] + 1,
|
|
53
|
+
dp[i - 1][j - 1] + (a[i - 1] !== b[j - 1] ? 1 : 0),
|
|
54
|
+
);
|
|
55
|
+
return dp[m][n];
|
|
56
|
+
}
|
|
57
|
+
|
|
19
58
|
function showHelp() {
|
|
20
59
|
printHeader();
|
|
21
|
-
console.log(` ${
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
${cyan('stack
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
${cyan('
|
|
31
|
-
${cyan('
|
|
32
|
-
${cyan('persistent')}
|
|
33
|
-
|
|
34
|
-
${
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
--
|
|
39
|
-
|
|
40
|
-
${
|
|
41
|
-
${
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
${dim('
|
|
47
|
-
`);
|
|
60
|
+
console.log(` ${dim('Deployable fullstack templates + AI agent skills for any project')}`);
|
|
61
|
+
console.log();
|
|
62
|
+
|
|
63
|
+
divider('New projects');
|
|
64
|
+
console.log(` ${cyan('stack new')} ${dim('<name>')} Scaffold a full project from the template`);
|
|
65
|
+
console.log(` ${cyan('stack update')} Update template-level files to latest`);
|
|
66
|
+
console.log();
|
|
67
|
+
|
|
68
|
+
divider('Any project');
|
|
69
|
+
console.log(` ${cyan('skills')} Download all skills + persistent agent configs`);
|
|
70
|
+
console.log(` ${cyan('skills update')} Update base skills to latest versions`);
|
|
71
|
+
console.log(` ${cyan('persistent')} Manage and launch persistent background agents`);
|
|
72
|
+
console.log(` ${cyan('persistent')} ${dim('--stop')} Stop all running agents`);
|
|
73
|
+
console.log(` ${cyan('persistent')} ${dim('--reconfigure')} Change models, enable/disable agents`);
|
|
74
|
+
console.log();
|
|
75
|
+
|
|
76
|
+
divider('Options');
|
|
77
|
+
console.log(` ${bold('-f')}, ${bold('--force')} Overwrite existing files`);
|
|
78
|
+
console.log(` ${bold('-a')}, ${bold('--all')} Include new files in updates`);
|
|
79
|
+
console.log(` ${bold('-v')}, ${bold('--version')} Show version`);
|
|
80
|
+
console.log(` ${bold('-h')}, ${bold('--help')} Show this help`);
|
|
81
|
+
console.log();
|
|
82
|
+
|
|
83
|
+
console.log(` ${dim('Examples:')}`);
|
|
84
|
+
console.log(` ${dim('$')} serpentstack stack new my-saas-app`);
|
|
85
|
+
console.log(` ${dim('$')} serpentstack skills`);
|
|
86
|
+
console.log(` ${dim('$')} serpentstack persistent`);
|
|
87
|
+
console.log();
|
|
88
|
+
console.log(` ${dim('Docs:')} ${cyan('https://github.com/Benja-Pauls/SerpentStack')}`);
|
|
89
|
+
console.log();
|
|
48
90
|
}
|
|
49
91
|
|
|
50
92
|
async function main() {
|
|
@@ -95,7 +137,12 @@ async function main() {
|
|
|
95
137
|
await persistent({ stop: !!flags.stop, reconfigure: !!flags.reconfigure });
|
|
96
138
|
} else {
|
|
97
139
|
error(`Unknown command: ${bold(noun)}`);
|
|
98
|
-
|
|
140
|
+
const suggestion = suggestCommand(noun);
|
|
141
|
+
if (suggestion) {
|
|
142
|
+
console.log(`\n Did you mean ${bold(suggestion)}? Run ${bold(`serpentstack ${suggestion}`)} or ${bold('serpentstack --help')}.\n`);
|
|
143
|
+
} else {
|
|
144
|
+
console.log(`\n Run ${bold('serpentstack --help')} to see available commands.\n`);
|
|
145
|
+
}
|
|
99
146
|
process.exit(1);
|
|
100
147
|
}
|
|
101
148
|
}
|