spectoflow 0.16.2 → 0.16.4
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/postinstall.js +21 -0
- package/bin/spectoflow.js +15 -42
- package/lib/brand.js +64 -0
- package/package.json +2 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/*
|
|
4
|
+
* Printed after `npm install -g spectoflow`: the brand welcome + first steps.
|
|
5
|
+
* Guarded to a GLOBAL, interactive (TTY) install so it never spams CI, dependency installs, or logs,
|
|
6
|
+
* and wrapped so a banner can never fail an install. Note: npm may buffer lifecycle-script output —
|
|
7
|
+
* if it doesn't appear, `spectoflow` (no args) and `spectoflow init` show the same brand.
|
|
8
|
+
*/
|
|
9
|
+
try {
|
|
10
|
+
if (process.env.npm_config_global === 'true' && process.stdout.isTTY) {
|
|
11
|
+
const brand = require('../lib/brand');
|
|
12
|
+
const version = require('../package.json').version;
|
|
13
|
+
const useColor = !process.env.NO_COLOR;
|
|
14
|
+
const paint = (code) => (s) => (useColor ? `\x1b[${code}m${s}\x1b[0m` : String(s));
|
|
15
|
+
const c = { white: paint('97'), amber: paint('38;5;179'), dim: paint('2'), bold: paint('1'), g: paint('32') };
|
|
16
|
+
process.stdout.write(brand.logo(c, version));
|
|
17
|
+
process.stdout.write(`\n ${c.bold('Get started')}\n`);
|
|
18
|
+
process.stdout.write(` ${c.g('spectoflow init')} scaffold a project in the current folder\n`);
|
|
19
|
+
process.stdout.write(` ${c.g('spectoflow --help')} all commands\n\n`);
|
|
20
|
+
}
|
|
21
|
+
} catch { /* never break an install over a welcome banner */ }
|
package/bin/spectoflow.js
CHANGED
|
@@ -20,46 +20,14 @@ const cmd = argv[0] || 'help';
|
|
|
20
20
|
// Tiny ANSI colouriser — no dependency; disabled when not a TTY or NO_COLOR is set.
|
|
21
21
|
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
22
22
|
const paint = (code) => (s) => (useColor ? `\x1b[${code}m${s}\x1b[0m` : String(s));
|
|
23
|
-
const c = { g: paint('32'), cy: paint('36'), b: paint('34'), y: paint('33'), dim: paint('2'), bold: paint('1'), amber: paint('38;5;179') };
|
|
23
|
+
const c = { g: paint('32'), cy: paint('36'), b: paint('34'), y: paint('33'), dim: paint('2'), bold: paint('1'), amber: paint('38;5;179'), white: paint('97') };
|
|
24
24
|
|
|
25
25
|
// ---- branding ---------------------------------------------------------------
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
' ####### ######',
|
|
32
|
-
' ###### ######',
|
|
33
|
-
' ###### #### ######',
|
|
34
|
-
' ##### ###### ####',
|
|
35
|
-
' ### ###### ####',
|
|
36
|
-
' ### ##### ####',
|
|
37
|
-
' ### #### ## ####',
|
|
38
|
-
' ### #### ######### ####',
|
|
39
|
-
' ### #### ####### ##### ####',
|
|
40
|
-
' ### ######## ### ####',
|
|
41
|
-
' ### ## ### ####',
|
|
42
|
-
' ### #### ####',
|
|
43
|
-
' ### ###### ####',
|
|
44
|
-
' ### ###### ####',
|
|
45
|
-
' #### ###### ####',
|
|
46
|
-
' ###### ### ######',
|
|
47
|
-
' ###### ######',
|
|
48
|
-
' ###### ######',
|
|
49
|
-
' ###### ######',
|
|
50
|
-
' ##########',
|
|
51
|
-
' ####',
|
|
52
|
-
];
|
|
53
|
-
const LOGO_W = 41; // widest logo line, for centering the wordmark under it
|
|
54
|
-
const NAME = 's p e c t o f l o w';
|
|
55
|
-
const TAGLINE = 'agent-agnostic spec-driven development · real-time control plane';
|
|
56
|
-
// Full logo block — hexagon mark + centered wordmark + version. For init, help and list.
|
|
57
|
-
function logo() {
|
|
58
|
-
const art = LOGO.map((l) => ' ' + c.amber(l)).join('\n');
|
|
59
|
-
const pad = ' '.repeat(Math.max(0, Math.round((2 + LOGO_W - NAME.length) / 2)));
|
|
60
|
-
return `\n${art}\n\n${pad}${c.bold(c.amber(NAME))}\n ${c.dim('v' + VERSION + ' · ' + TAGLINE)}\n`;
|
|
61
|
-
}
|
|
62
|
-
// One-line brand — for the header of secondary command outputs.
|
|
26
|
+
// Shared ASCII brand (white hexagon + amber wordmark) lives in lib/brand.js so the CLI and the
|
|
27
|
+
// postinstall welcome render the exact same art.
|
|
28
|
+
const brand = require('../lib/brand');
|
|
29
|
+
const logo = () => brand.logo(c, VERSION); // white hexagon + centered amber wordmark (init/update)
|
|
30
|
+
const wordmark = () => brand.wordmark(c, VERSION); // amber wordmark alone (help + explore)
|
|
63
31
|
const brandLine = () => `${c.amber('spectoflow')} ${c.dim('v' + VERSION)}`;
|
|
64
32
|
|
|
65
33
|
// ---- framework introspection (list agents / skills / workflow) --------------
|
|
@@ -266,7 +234,7 @@ function update() {
|
|
|
266
234
|
const detail = note ? c.dim(note) : c.dim(list.slice(0, 6).join(', ') + (list.length > 6 ? ` +${list.length - 6} more` : ''));
|
|
267
235
|
console.log(` ${sym} ${painter(label.padEnd(9))} ${n} ${detail}`);
|
|
268
236
|
};
|
|
269
|
-
console.log(
|
|
237
|
+
console.log(logo());
|
|
270
238
|
console.log(` ${c.bold('spectoflow update')} ${c.dim(from)} ${c.amber('→')} ${c.bold(r.toVersion)}${dryRun ? c.dim(' (dry-run)') : ''}`);
|
|
271
239
|
console.log('');
|
|
272
240
|
row(c.g('✓'), 'refreshed', r.refreshed, c.g);
|
|
@@ -403,7 +371,7 @@ function printWorkflow(withBrand = true) {
|
|
|
403
371
|
}
|
|
404
372
|
function listAll() {
|
|
405
373
|
const { scope } = frameworkSource();
|
|
406
|
-
console.log(
|
|
374
|
+
console.log(wordmark());
|
|
407
375
|
console.log(`${c.bold('Agents')} ${c.dim('— stable team personas (' + scope + ')')}`);
|
|
408
376
|
printAgents(false);
|
|
409
377
|
console.log(`\n${c.bold('Skills')} ${c.dim('— evolving procedures')}`);
|
|
@@ -414,7 +382,7 @@ function listAll() {
|
|
|
414
382
|
}
|
|
415
383
|
|
|
416
384
|
// ---- help (global + per-command) --------------------------------------------
|
|
417
|
-
const help = () => console.log(`${
|
|
385
|
+
const help = () => console.log(`${wordmark()}
|
|
418
386
|
${c.dim('Usage:')} spectoflow ${c.g('<command>')} ${c.dim('[options]')} ${c.dim('· append -h to any command for its help')}
|
|
419
387
|
|
|
420
388
|
${c.bold('Project')}
|
|
@@ -473,7 +441,12 @@ const HELP = {
|
|
|
473
441
|
const showHelp = (name) => console.log('\n' + HELP[name].trim() + '\n');
|
|
474
442
|
|
|
475
443
|
// ---- dispatch ---------------------------------------------------------------
|
|
476
|
-
const fns = {
|
|
444
|
+
const fns = {
|
|
445
|
+
init, update, dashboard, stop: stopDashboard, status, list: listAll, help, version,
|
|
446
|
+
agents: () => { console.log(wordmark()); printAgents(false); },
|
|
447
|
+
skills: () => { console.log(wordmark()); printSkills(false); },
|
|
448
|
+
workflow: () => { console.log(wordmark()); printWorkflow(false); },
|
|
449
|
+
};
|
|
477
450
|
const wantsHelp = argv.slice(1).some((a) => a === '-h' || a === '--help');
|
|
478
451
|
|
|
479
452
|
if (['-v', '-V', '--version', 'version'].includes(cmd)) version();
|
package/lib/brand.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* Shared spectoflow ASCII brand — used by the CLI (bin/spectoflow.js) and the postinstall welcome
|
|
4
|
+
* (bin/postinstall.js). The hexagon mark is drawn WHITE; the compact figlet wordmark is drawn AMBER
|
|
5
|
+
* and centred under the mark. Callers pass their own colouriser `c` (with .white/.amber/.dim) and the
|
|
6
|
+
* version string, so this stays presentation-agnostic and zero-dependency.
|
|
7
|
+
*/
|
|
8
|
+
const LOGO = [
|
|
9
|
+
' ########',
|
|
10
|
+
' ###### #######',
|
|
11
|
+
' ####### ######',
|
|
12
|
+
' ###### ######',
|
|
13
|
+
' ###### #### ######',
|
|
14
|
+
' ##### ###### ####',
|
|
15
|
+
' #### ###### ####',
|
|
16
|
+
' #### ##### ####',
|
|
17
|
+
' #### #### ## ####',
|
|
18
|
+
' #### #### ######### ####',
|
|
19
|
+
' #### #### ####### ##### ####',
|
|
20
|
+
' #### ######## ### ####',
|
|
21
|
+
' #### ## ### ####',
|
|
22
|
+
' #### #### ####',
|
|
23
|
+
' #### ###### ####',
|
|
24
|
+
' #### ###### ####',
|
|
25
|
+
' #### ###### ####',
|
|
26
|
+
' ###### ### ######',
|
|
27
|
+
' ###### ######',
|
|
28
|
+
' ###### ######',
|
|
29
|
+
' ###### ######',
|
|
30
|
+
' ##########',
|
|
31
|
+
' ####',
|
|
32
|
+
];
|
|
33
|
+
const NAME = [
|
|
34
|
+
' _ __ _',
|
|
35
|
+
' ____ __ ___ __| |_ ___ / _| |_____ __ __',
|
|
36
|
+
" (_-< '_ \\/ -_) _| _/ _ \\ _| / _ \\ V V /",
|
|
37
|
+
' /__/ .__/\\___\\__|\\__\\___/_| |_\\___/\\_/\\_/',
|
|
38
|
+
' |_|',
|
|
39
|
+
];
|
|
40
|
+
const NAME_W = Math.max(...NAME.map((l) => l.length));
|
|
41
|
+
const TAGLINE = 'agent-agnostic spec-driven development · real-time control plane';
|
|
42
|
+
const INDENT = ' ';
|
|
43
|
+
|
|
44
|
+
// Amber wordmark; when `centerUnder`, centred beneath the hexagon's true horizontal midpoint.
|
|
45
|
+
function nameBlock(c, centerUnder) {
|
|
46
|
+
let pad = INDENT;
|
|
47
|
+
if (centerUnder) {
|
|
48
|
+
let lo = Infinity, hi = 0;
|
|
49
|
+
for (const l of LOGO) { const i = l.search(/#/); if (i >= 0) { lo = Math.min(lo, i); hi = Math.max(hi, l.length - 1); } }
|
|
50
|
+
pad = ' '.repeat(Math.max(0, Math.round(INDENT.length + (lo + hi) / 2 - NAME_W / 2)));
|
|
51
|
+
}
|
|
52
|
+
return NAME.map((l) => pad + c.amber(l)).join('\n');
|
|
53
|
+
}
|
|
54
|
+
// White hexagon + centred amber wordmark + version. For init, update and the install welcome.
|
|
55
|
+
function logo(c, version) {
|
|
56
|
+
const art = LOGO.map((l) => INDENT + c.white(l)).join('\n');
|
|
57
|
+
return `\n${art}\n\n${nameBlock(c, true)}\n\n${INDENT}${c.dim('v' + version + ' · ' + TAGLINE)}\n`;
|
|
58
|
+
}
|
|
59
|
+
// Just the amber wordmark + version. For help and the explore commands.
|
|
60
|
+
function wordmark(c, version) {
|
|
61
|
+
return `\n${nameBlock(c, false)}\n\n${INDENT}${c.dim('v' + version + ' · ' + TAGLINE)}\n`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { LOGO, NAME, TAGLINE, logo, wordmark };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spectoflow",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "Agent-agnostic spec-driven development framework + real-time local control plane. Markdown artifacts, intent router, workflow-by-scope.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spec-driven-development",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
],
|
|
41
41
|
"scripts": {
|
|
42
42
|
"status": "node bin/spectoflow.js status",
|
|
43
|
+
"postinstall": "node bin/postinstall.js",
|
|
43
44
|
"test": "node --test"
|
|
44
45
|
},
|
|
45
46
|
"engines": {
|