@sigmashake/ssg 0.29.86 → 0.29.89
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/cleanup-globals.cjs +102 -90
- package/bin/ssg.cjs +107 -77
- package/package.json +5 -4
- package/public/assets/app.css +1 -1
- package/public/assets/app.js +30 -31
- package/public/index.html +1 -1
package/bin/cleanup-globals.cjs
CHANGED
|
@@ -3,53 +3,55 @@
|
|
|
3
3
|
// Also registers a per-install canary for distribution tracking.
|
|
4
4
|
// This runs on `postinstall` to ensure npm takes precedence
|
|
5
5
|
|
|
6
|
-
const fs = require(
|
|
7
|
-
const path = require(
|
|
8
|
-
const os = require(
|
|
9
|
-
const https = require(
|
|
10
|
-
const crypto = require(
|
|
6
|
+
const fs = require("node:fs");
|
|
7
|
+
const path = require("node:path");
|
|
8
|
+
const os = require("node:os");
|
|
9
|
+
const https = require("node:https");
|
|
10
|
+
const crypto = require("node:crypto");
|
|
11
11
|
|
|
12
12
|
// Only run cleanup if installed globally via npm (or we assume global if running in a global node_modules directory)
|
|
13
|
-
const isGlobal =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const isGlobal =
|
|
14
|
+
process.env.npm_config_global === "true" ||
|
|
15
|
+
__dirname.includes("/lib/node_modules/") ||
|
|
16
|
+
__dirname.includes("\\npm\\node_modules\\");
|
|
17
17
|
|
|
18
18
|
if (!isGlobal) {
|
|
19
|
-
|
|
19
|
+
process.exit(0);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const homedir = os.homedir();
|
|
23
23
|
const targets = [
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
path.join(homedir, ".local", "bin", "ssg"),
|
|
25
|
+
path.join(homedir, ".local", "bin", "libssg_eval.so"),
|
|
26
|
+
path.join(homedir, ".bun", "bin", "ssg"),
|
|
27
27
|
];
|
|
28
28
|
|
|
29
29
|
let cleaned = false;
|
|
30
30
|
|
|
31
31
|
for (const target of targets) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
try {
|
|
33
|
+
if (!fs.existsSync(target)) continue;
|
|
34
|
+
|
|
35
|
+
// Do not delete if it actually belongs to this exact npm installation (symlink loopback check)
|
|
36
|
+
// Sometimes package managers like bun map symlinks directly to the node_modules bin.
|
|
37
|
+
const realPath = fs.realpathSync(target);
|
|
38
|
+
if (realPath.includes(__dirname)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Attempt to remove the conflicting binary
|
|
43
|
+
fs.rmSync(target, { force: true });
|
|
44
|
+
console.log(`[ssg-cleanup] Removed conflicting global binary: ${target}`);
|
|
45
|
+
cleaned = true;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.warn(`[ssg-cleanup] Could not remove ${target}: ${e.message}`);
|
|
48
|
+
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
if (cleaned) {
|
|
52
|
-
|
|
52
|
+
console.log(
|
|
53
|
+
"[ssg-cleanup] Successfully cleaned up old binary conflicts designed for local development.",
|
|
54
|
+
);
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
// ── Per-install canary registration ─────────────────────────────────────────
|
|
@@ -57,63 +59,73 @@ if (cleaned) {
|
|
|
57
59
|
// the source installation if a cracked binary appears in the wild.
|
|
58
60
|
// Fire-and-forget: never blocks or fails the install.
|
|
59
61
|
(function registerCanary() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
62
|
+
try {
|
|
63
|
+
const homedir = os.homedir();
|
|
64
|
+
const ssgDir = path.join(homedir, ".sigmashake");
|
|
65
|
+
const canaryPath = path.join(ssgDir, ".canary");
|
|
66
|
+
|
|
67
|
+
// Skip if canary already registered for this install
|
|
68
|
+
if (fs.existsSync(canaryPath)) return;
|
|
69
|
+
|
|
70
|
+
const pkg = require("../package.json");
|
|
71
|
+
const version = pkg.version;
|
|
72
|
+
const platform = process.platform;
|
|
73
|
+
const arch = process.arch;
|
|
74
|
+
|
|
75
|
+
// Generate a stable machine fingerprint (same signals as fingerprint.ts)
|
|
76
|
+
let machineId = "";
|
|
77
|
+
try {
|
|
78
|
+
if (process.platform === "linux") {
|
|
79
|
+
const p = "/etc/machine-id";
|
|
80
|
+
if (fs.existsSync(p)) machineId = fs.readFileSync(p, "utf8").trim();
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
/* ignore */
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const fingerprint = crypto
|
|
87
|
+
.createHash("sha256")
|
|
88
|
+
.update([machineId, platform, arch, os.hostname(), homedir].join("|"))
|
|
89
|
+
.digest("hex");
|
|
90
|
+
|
|
91
|
+
const payload = JSON.stringify({ fingerprint, version, platform, arch });
|
|
92
|
+
|
|
93
|
+
const req = https.request(
|
|
94
|
+
{
|
|
95
|
+
hostname: "api.sigmashake.com",
|
|
96
|
+
path: "/v1/install/register",
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
"Content-Length": Buffer.byteLength(payload),
|
|
101
|
+
},
|
|
102
|
+
timeout: 5000,
|
|
103
|
+
},
|
|
104
|
+
(res) => {
|
|
105
|
+
const chunks = [];
|
|
106
|
+
res.on("data", (c) => chunks.push(c));
|
|
107
|
+
res.on("end", () => {
|
|
108
|
+
try {
|
|
109
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
110
|
+
if (body?.canary_id) {
|
|
111
|
+
fs.mkdirSync(ssgDir, { recursive: true });
|
|
112
|
+
fs.writeFileSync(canaryPath, body.canary_id, { mode: 0o600 });
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
/* ignore parse errors */
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
);
|
|
120
|
+
req.on("error", () => {
|
|
121
|
+
/* non-blocking, ignore network errors */
|
|
122
|
+
});
|
|
123
|
+
req.on("timeout", () => {
|
|
124
|
+
req.destroy();
|
|
125
|
+
});
|
|
126
|
+
req.write(payload);
|
|
127
|
+
req.end();
|
|
128
|
+
} catch {
|
|
129
|
+
/* never crash the install */
|
|
130
|
+
}
|
|
119
131
|
})();
|
package/bin/ssg.cjs
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// bin/ssg.cjs — launcher for @sigmashake/ssg
|
|
3
3
|
// Resolves the native binary from the platform-specific optional dependency,
|
|
4
4
|
// falls back to a local dist/ build (dev environment), then to Bun + source.
|
|
5
|
-
|
|
5
|
+
"use strict";
|
|
6
6
|
|
|
7
|
-
const {execFileSync, spawnSync} = require(
|
|
8
|
-
const path = require(
|
|
9
|
-
const fs = require(
|
|
7
|
+
const { execFileSync, spawnSync } = require("node:child_process");
|
|
8
|
+
const path = require("node:path");
|
|
9
|
+
const fs = require("node:fs");
|
|
10
10
|
|
|
11
|
-
const ext = process.platform ===
|
|
11
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
12
12
|
const platformPkg = `@sigmashake/ssg-${process.platform}-${process.arch}`;
|
|
13
13
|
let binaryPath;
|
|
14
14
|
|
|
@@ -18,30 +18,32 @@ let binaryPath;
|
|
|
18
18
|
let hookBinPath;
|
|
19
19
|
let evalServerBinPath;
|
|
20
20
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
const pkgRoot = path.dirname(require.resolve(`${platformPkg}/package.json`));
|
|
22
|
+
const candidate = path.join(pkgRoot, "bin", `ssg${ext}`);
|
|
23
|
+
if (fs.existsSync(candidate)) binaryPath = candidate;
|
|
24
|
+
const hookCandidate = path.join(pkgRoot, "bin", `ssg-hook-fast${ext}`);
|
|
25
|
+
if (fs.existsSync(hookCandidate)) hookBinPath = hookCandidate;
|
|
26
|
+
const sidecarCandidate = path.join(pkgRoot, "bin", `ssg-eval-server${ext}`);
|
|
27
|
+
if (fs.existsSync(sidecarCandidate)) evalServerBinPath = sidecarCandidate;
|
|
28
28
|
} catch {}
|
|
29
29
|
|
|
30
30
|
// 2. Check if binary was bundled in the root (dev: local npm pack or manual build)
|
|
31
31
|
if (!binaryPath) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const rootBin = path.resolve(__dirname, "..", `ssg${ext}`);
|
|
33
|
+
if (fs.existsSync(rootBin)) {
|
|
34
|
+
binaryPath = rootBin;
|
|
35
|
+
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// 3. Fall back to local dist/ (dev build / bun build --compile)
|
|
39
39
|
if (!binaryPath) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
const devBin = path.resolve(
|
|
41
|
+
__dirname,
|
|
42
|
+
"..",
|
|
43
|
+
"dist",
|
|
44
|
+
`ssg-${process.platform}-${process.arch}${ext}`,
|
|
45
|
+
);
|
|
46
|
+
if (fs.existsSync(devBin)) binaryPath = devBin;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
// 2.5 Hook-eval fast-path short-circuit (perf):
|
|
@@ -60,79 +62,107 @@ if (!binaryPath) {
|
|
|
60
62
|
// full bun-startup cost on macOS (~1.3 s), even though the actual eval
|
|
61
63
|
// only takes ~40 ms.
|
|
62
64
|
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
hookBinPath &&
|
|
66
|
+
process.env.SSG_HOOK_NO_FAST !== "1" &&
|
|
67
|
+
process.argv.length === 4 &&
|
|
68
|
+
process.argv[2] === "hook" &&
|
|
69
|
+
process.argv[3] === "eval"
|
|
68
70
|
) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
const env = {
|
|
72
|
+
...process.env,
|
|
73
|
+
SSG_PUBLIC_DIR: path.resolve(__dirname, "..", "public"),
|
|
74
|
+
};
|
|
75
|
+
if (evalServerBinPath) env.SSG_EVAL_SERVER_BIN = evalServerBinPath;
|
|
76
|
+
const r = spawnSync(hookBinPath, [], {
|
|
77
|
+
stdio: "inherit",
|
|
78
|
+
env,
|
|
79
|
+
windowsHide: true,
|
|
80
|
+
});
|
|
81
|
+
// status 99 = sentinel for "needs JS path" (ask mode, TTY) — fall through.
|
|
82
|
+
// null/undefined status with error → fall through and let bun ssg handle.
|
|
83
|
+
if (
|
|
84
|
+
r.status !== 99 &&
|
|
85
|
+
r.status !== null &&
|
|
86
|
+
r.status !== undefined &&
|
|
87
|
+
!r.error
|
|
88
|
+
) {
|
|
89
|
+
process.exit(r.status);
|
|
90
|
+
}
|
|
91
|
+
// Otherwise fall through to the bun ssg below (handles ask mode, TTY,
|
|
92
|
+
// and surface any error diagnostics consistently with the rest of the CLI).
|
|
79
93
|
}
|
|
80
94
|
|
|
81
95
|
// 3. Run binary if found
|
|
82
96
|
if (binaryPath) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
const env = {
|
|
98
|
+
...process.env,
|
|
99
|
+
SSG_PUBLIC_DIR: path.resolve(__dirname, "..", "public"),
|
|
100
|
+
};
|
|
101
|
+
if (hookBinPath) env.SSG_HOOK_FAST_BIN = hookBinPath;
|
|
102
|
+
if (evalServerBinPath) env.SSG_EVAL_SERVER_BIN = evalServerBinPath;
|
|
103
|
+
const result = spawnSync(binaryPath, process.argv.slice(2), {
|
|
104
|
+
stdio: "inherit",
|
|
105
|
+
env,
|
|
106
|
+
windowsHide: true,
|
|
107
|
+
});
|
|
108
|
+
process.exit(result.status ?? 1);
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
// 4. Last resort: run TypeScript source via Bun (unsupported platform / dev)
|
|
95
|
-
const src = path.resolve(__dirname,
|
|
96
|
-
const isWin = process.platform ===
|
|
97
|
-
const bunExe = isWin ?
|
|
112
|
+
const src = path.resolve(__dirname, "..", "src", "cli.ts");
|
|
113
|
+
const isWin = process.platform === "win32";
|
|
114
|
+
const bunExe = isWin ? "bun.exe" : "bun";
|
|
98
115
|
|
|
99
116
|
let bunPath;
|
|
100
117
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
// `where` on Windows, `which` everywhere else.
|
|
119
|
+
bunPath = execFileSync(isWin ? "where" : "which", [bunExe], {
|
|
120
|
+
encoding: "utf8",
|
|
121
|
+
})
|
|
122
|
+
.trim()
|
|
123
|
+
.split(/\r?\n/)[0];
|
|
105
124
|
} catch {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
126
|
+
const candidates = isWin
|
|
127
|
+
? [
|
|
128
|
+
path.join(home, ".bun", "bin", "bun.exe"),
|
|
129
|
+
path.join(
|
|
130
|
+
process.env.LOCALAPPDATA ?? "",
|
|
131
|
+
"Programs",
|
|
132
|
+
"bun",
|
|
133
|
+
"bin",
|
|
134
|
+
"bun.exe",
|
|
135
|
+
),
|
|
136
|
+
"C:\\Program Files\\bun\\bin\\bun.exe",
|
|
137
|
+
]
|
|
138
|
+
: [
|
|
139
|
+
path.join(home, ".bun", "bin", "bun"),
|
|
140
|
+
"/usr/local/bin/bun",
|
|
141
|
+
"/opt/homebrew/bin/bun",
|
|
142
|
+
];
|
|
143
|
+
bunPath = candidates.find((p) => {
|
|
144
|
+
try {
|
|
145
|
+
fs.accessSync(p, fs.constants.X_OK);
|
|
146
|
+
return true;
|
|
147
|
+
} catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
121
151
|
}
|
|
122
152
|
|
|
123
153
|
if (!bunPath) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
154
|
+
process.stderr.write(
|
|
155
|
+
`ssg: no pre-compiled binary for ${process.platform}-${process.arch}.\n` +
|
|
156
|
+
`Expected platform package: ${platformPkg}\n` +
|
|
157
|
+
"Install Bun to run from source (https://bun.sh):\n\n" +
|
|
158
|
+
" curl -fsSL https://bun.sh/install | bash\n\n",
|
|
159
|
+
);
|
|
160
|
+
process.exit(1);
|
|
131
161
|
}
|
|
132
162
|
|
|
133
163
|
const result = spawnSync(bunPath, [src, ...process.argv.slice(2)], {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
164
|
+
stdio: "inherit",
|
|
165
|
+
env: process.env,
|
|
166
|
+
windowsHide: true,
|
|
137
167
|
});
|
|
138
168
|
process.exit(result.status ?? 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigmashake/ssg",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.89",
|
|
4
4
|
"description": "AI Agent Governance CLI — evaluate tool calls against rules, block dangerous operations, and surface blocked commands",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
16
16
|
"optionalDependencies": {
|
|
17
|
-
"@sigmashake/ssg-linux-x64": "0.29.
|
|
18
|
-
"@sigmashake/ssg-linux-arm64": "0.29.
|
|
17
|
+
"@sigmashake/ssg-linux-x64": "0.29.89",
|
|
18
|
+
"@sigmashake/ssg-linux-arm64": "0.29.89",
|
|
19
19
|
"@sigmashake/ssg-darwin-arm64": "0.29.82",
|
|
20
20
|
"@sigmashake/ssg-darwin-x64": "0.29.82",
|
|
21
21
|
"@sigmashake/ssg-win32-x64": "0.29.85"
|
|
@@ -107,7 +107,8 @@
|
|
|
107
107
|
"check:rust-audit:windows": "cd native/rust-audit && cargo zigbuild --target x86_64-pc-windows-gnu",
|
|
108
108
|
"check:rust-audit:all": "bun run check:rust-audit:linux-x64 && bun run check:rust-audit:linux-arm64 && bun run check:rust-audit:darwin-arm64 && bun run check:rust-audit:darwin-x64 && bun run check:rust-audit:windows",
|
|
109
109
|
"test:regression": "bun test test/regression",
|
|
110
|
-
"test:configuration": "bun test test/configuration"
|
|
110
|
+
"test:configuration": "bun test test/configuration",
|
|
111
|
+
"typecheck": "bun run typecheck:client && bun run compile"
|
|
111
112
|
},
|
|
112
113
|
"keywords": [
|
|
113
114
|
"ai",
|