@aexol/spectral 0.9.133 → 0.9.134
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/package.json +9 -3
- package/scripts/postinstall.mjs +186 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aexol/spectral",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.134",
|
|
4
4
|
"description": "AI coding agent for Aexol with relay-based browser access.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"dist",
|
|
23
|
+
"scripts/postinstall.mjs",
|
|
23
24
|
"README.md",
|
|
24
25
|
"CHANGELOG.md",
|
|
25
26
|
"LICENSE"
|
|
@@ -33,7 +34,12 @@
|
|
|
33
34
|
"build:standalone": "bash scripts/build-standalone.sh",
|
|
34
35
|
"build:standalone:all": "bash scripts/build-standalone.sh --all",
|
|
35
36
|
"build:electron": "bash scripts/build-electron.sh",
|
|
36
|
-
"build:electron:all": "bash scripts/build-electron.sh --all"
|
|
37
|
+
"build:electron:all": "bash scripts/build-electron.sh --all",
|
|
38
|
+
"postinstall": "node scripts/postinstall.mjs"
|
|
39
|
+
},
|
|
40
|
+
"overrides": {
|
|
41
|
+
"glob": "^13.0.0",
|
|
42
|
+
"encoding-sniffer": "^1.0.0"
|
|
37
43
|
},
|
|
38
44
|
"engines": {
|
|
39
45
|
"node": ">=20"
|
|
@@ -80,7 +86,7 @@
|
|
|
80
86
|
"cross-spawn": "^7.0.6",
|
|
81
87
|
"diff": "^8.0.0",
|
|
82
88
|
"get-east-asian-width": "^1.3.0",
|
|
83
|
-
"glob": "^
|
|
89
|
+
"glob": "^13.0.0",
|
|
84
90
|
"highlight.js": "^11.11.0",
|
|
85
91
|
"hosted-git-info": "^8.0.0",
|
|
86
92
|
"ignore": "^7.0.0",
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aexol/spectral — postinstall welcome message.
|
|
3
|
+
*
|
|
4
|
+
* Shows a colorful, Polish-language welcome with a brief spinner and box-drawn
|
|
5
|
+
* next-steps panel. Designed to be:
|
|
6
|
+
* - fast (< 2s total)
|
|
7
|
+
* - safe (any error → silent exit 0; never breaks `npm install`)
|
|
8
|
+
* - quiet during monorepo/dev installs (full message only for end users)
|
|
9
|
+
*
|
|
10
|
+
* Tagline: "Agent kodujący który nigdy nie śpi"
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
+
import { dirname, join } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
|
|
17
|
+
// picocolors is a direct dependency of @aexol/spectral and used across the CLI.
|
|
18
|
+
// Fallback to identity functions if (somehow) unavailable so colors degrade
|
|
19
|
+
// gracefully rather than crashing the install.
|
|
20
|
+
let pc = null;
|
|
21
|
+
try {
|
|
22
|
+
pc = (await import("picocolors")).default;
|
|
23
|
+
} catch {
|
|
24
|
+
pc = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Wrap a string in an ANSI color; no-op when picocolors is missing. */
|
|
28
|
+
const c = (style, s) => {
|
|
29
|
+
if (!pc) return s;
|
|
30
|
+
const fn = pc[style];
|
|
31
|
+
return typeof fn === "function" ? fn(s) : s;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const write = (s) => process.stdout.write(s);
|
|
35
|
+
|
|
36
|
+
// Strip ANSI escapes so we can measure visible width for box padding.
|
|
37
|
+
const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
38
|
+
|
|
39
|
+
// ─── Dev install detection ──────────────────────────────────────────────────
|
|
40
|
+
// In the monorepo, `../deno.json` + `../AGENTS.md` exist relative to this
|
|
41
|
+
// script. End-user installs (from npm) live under
|
|
42
|
+
// node_modules/@aexol/spectral/ and have no monorepo root above them.
|
|
43
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
44
|
+
const monorepoRoot = join(__dirname, "..", "..");
|
|
45
|
+
const isMonorepoDevInstall =
|
|
46
|
+
existsSync(join(monorepoRoot, "deno.json")) &&
|
|
47
|
+
existsSync(join(monorepoRoot, "AGENTS.md"));
|
|
48
|
+
|
|
49
|
+
// Read own package.json (shipped in the tarball) for version display.
|
|
50
|
+
function readVersion() {
|
|
51
|
+
try {
|
|
52
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8"));
|
|
53
|
+
return pkg.version || "";
|
|
54
|
+
} catch {
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ─── Spinner ──────────────────────────────────────────────────────────────────
|
|
60
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
61
|
+
|
|
62
|
+
function spin(message, ms = 900) {
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
const interactive =
|
|
65
|
+
process.stdout.isTTY && !process.env.CI && !process.env.NO_COLOR;
|
|
66
|
+
if (!interactive) {
|
|
67
|
+
// Non-interactive (npm logs / CI): print a single static line, brief wait.
|
|
68
|
+
write(c("dim", "• " + message) + "\n");
|
|
69
|
+
setTimeout(resolve, Math.min(ms, 200));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
let i = 0;
|
|
73
|
+
const timer = setInterval(() => {
|
|
74
|
+
write("\r\x1b[K"); // clear line
|
|
75
|
+
write(
|
|
76
|
+
c("cyan", SPINNER_FRAMES[i % SPINNER_FRAMES.length]) +
|
|
77
|
+
" " +
|
|
78
|
+
c("dim", message),
|
|
79
|
+
);
|
|
80
|
+
i++;
|
|
81
|
+
}, 80);
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
clearInterval(timer);
|
|
84
|
+
write("\r\x1b[K"); // clear spinner line
|
|
85
|
+
resolve();
|
|
86
|
+
}, ms);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ─── Box drawing ─────────────────────────────────────────────────────────────
|
|
91
|
+
/** Render `lines` inside a rounded Unicode box with `borderColor`. */
|
|
92
|
+
function box(lines, { borderColor = "cyan" } = {}) {
|
|
93
|
+
const width = Math.max(...lines.map((l) => stripAnsi(l).length)) + 4;
|
|
94
|
+
const top = c(borderColor, "╭" + "─".repeat(width - 2) + "╮");
|
|
95
|
+
const bottom = c(borderColor, "╰" + "─".repeat(width - 2) + "╯");
|
|
96
|
+
const rule = c(borderColor, "├" + "─".repeat(width - 2) + "┤");
|
|
97
|
+
const pad = (s) => {
|
|
98
|
+
const visible = stripAnsi(s).length;
|
|
99
|
+
const spaces = Math.max(0, width - 2 - 1 - visible);
|
|
100
|
+
return (
|
|
101
|
+
c(borderColor, "│") +
|
|
102
|
+
" " +
|
|
103
|
+
s +
|
|
104
|
+
" ".repeat(spaces) +
|
|
105
|
+
" " +
|
|
106
|
+
c(borderColor, "│")
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
return [top, ...lines.map(pad), bottom].join("\n");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ─── Welcome panel ───────────────────────────────────────────────────────────
|
|
113
|
+
function renderWelcome() {
|
|
114
|
+
const version = readVersion();
|
|
115
|
+
const versionStr = version ? c("dim", `v${version}`) : "";
|
|
116
|
+
|
|
117
|
+
const headerLine =
|
|
118
|
+
" " +
|
|
119
|
+
c("green", "✅") +
|
|
120
|
+
" " +
|
|
121
|
+
c("magenta", c("bold", "@aexol/spectral")) +
|
|
122
|
+
" installed successfully " +
|
|
123
|
+
versionStr;
|
|
124
|
+
|
|
125
|
+
const blank = " ";
|
|
126
|
+
const tagline =
|
|
127
|
+
" " + c("italic", c("dim", "Coding agent that never sleeps 🌙"));
|
|
128
|
+
|
|
129
|
+
const stepsTitle = " " + c("bold", "Next steps:");
|
|
130
|
+
const step1 =
|
|
131
|
+
" " +
|
|
132
|
+
c("cyan", "1.") +
|
|
133
|
+
" " +
|
|
134
|
+
c("yellow", c("bold", "spectral login")) +
|
|
135
|
+
c("dim", " — log in to your Aexol account");
|
|
136
|
+
const step2 =
|
|
137
|
+
" " +
|
|
138
|
+
c("cyan", "2.") +
|
|
139
|
+
" " +
|
|
140
|
+
c("yellow", c("bold", "spectral serve")) +
|
|
141
|
+
c("dim", " — start the agent in your projects folder");
|
|
142
|
+
|
|
143
|
+
const tip =
|
|
144
|
+
" " +
|
|
145
|
+
c("blue", "💡") +
|
|
146
|
+
" " +
|
|
147
|
+
c("dim", "Run ") +
|
|
148
|
+
c("yellow", "spectral serve") +
|
|
149
|
+
c("dim", " in the directory where you keep your projects.");
|
|
150
|
+
|
|
151
|
+
const lines = [
|
|
152
|
+
headerLine,
|
|
153
|
+
blank,
|
|
154
|
+
tagline,
|
|
155
|
+
blank,
|
|
156
|
+
stepsTitle,
|
|
157
|
+
step1,
|
|
158
|
+
step2,
|
|
159
|
+
blank,
|
|
160
|
+
tip,
|
|
161
|
+
];
|
|
162
|
+
return box(lines, { borderColor: "magenta" });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ─── Dev (short) message ─────────────────────────────────────────────────────
|
|
166
|
+
function renderDevHint() {
|
|
167
|
+
return (
|
|
168
|
+
c("dim", " ↻ @aexol/spectral — dev install (monorepo), skipping welcome") +
|
|
169
|
+
"\n"
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
174
|
+
try {
|
|
175
|
+
if (isMonorepoDevInstall) {
|
|
176
|
+
write(renderDevHint());
|
|
177
|
+
} else {
|
|
178
|
+
// Total runtime < ~1.2s: spinner ~900ms, then synchronous render.
|
|
179
|
+
await spin("Setting up @aexol/spectral…", 900);
|
|
180
|
+
write("\n" + renderWelcome() + "\n\n");
|
|
181
|
+
}
|
|
182
|
+
} catch {
|
|
183
|
+
// Never break `npm install`. Silent failure.
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
process.exit(0);
|