spectoflow 0.16.3 → 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 +5 -59
- 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
|
@@ -23,65 +23,11 @@ const paint = (code) => (s) => (useColor ? `\x1b[${code}m${s}\x1b[0m` : String(s
|
|
|
23
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 NAME = [
|
|
54
|
-
' _ __ _',
|
|
55
|
-
' ____ __ ___ __| |_ ___ / _| |_____ __ __',
|
|
56
|
-
" (_-< '_ \\/ -_) _| _/ _ \\ _| / _ \\ V V /",
|
|
57
|
-
' /__/ .__/\\___\\__|\\__\\___/_| |_\\___/\\_/\\_/',
|
|
58
|
-
' |_|',
|
|
59
|
-
];
|
|
60
|
-
const NAME_W = Math.max(...NAME.map((l) => l.length));
|
|
61
|
-
const TAGLINE = 'agent-agnostic spec-driven development · real-time control plane';
|
|
62
|
-
const INDENT = ' ';
|
|
63
|
-
|
|
64
|
-
// Amber wordmark, indented. `centerUnder` centres it below the hexagon's true midpoint.
|
|
65
|
-
function nameBlock(centerUnder) {
|
|
66
|
-
let pad = INDENT;
|
|
67
|
-
if (centerUnder) {
|
|
68
|
-
let lo = Infinity, hi = 0;
|
|
69
|
-
for (const l of LOGO) { const i = l.search(/#/); if (i >= 0) { lo = Math.min(lo, i); hi = Math.max(hi, l.length - 1); } }
|
|
70
|
-
const cx = INDENT.length + (lo + hi) / 2;
|
|
71
|
-
pad = ' '.repeat(Math.max(0, Math.round(cx - NAME_W / 2)));
|
|
72
|
-
}
|
|
73
|
-
return NAME.map((l) => pad + c.amber(l)).join('\n');
|
|
74
|
-
}
|
|
75
|
-
// Full logo — white hexagon + centered amber wordmark + version. For init and update.
|
|
76
|
-
function logo() {
|
|
77
|
-
const art = LOGO.map((l) => INDENT + c.white(l)).join('\n');
|
|
78
|
-
return `\n${art}\n\n${nameBlock(true)}\n\n${INDENT}${c.dim('v' + VERSION + ' · ' + TAGLINE)}\n`;
|
|
79
|
-
}
|
|
80
|
-
// Just the amber wordmark + version. For help and the explore commands.
|
|
81
|
-
function wordmark() {
|
|
82
|
-
return `\n${nameBlock(false)}\n\n${INDENT}${c.dim('v' + VERSION + ' · ' + TAGLINE)}\n`;
|
|
83
|
-
}
|
|
84
|
-
// 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)
|
|
85
31
|
const brandLine = () => `${c.amber('spectoflow')} ${c.dim('v' + VERSION)}`;
|
|
86
32
|
|
|
87
33
|
// ---- framework introspection (list agents / skills / workflow) --------------
|
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": {
|