@obedience-corp/agent-stream-dbg 0.1.1

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/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # @obedience-corp/agent-stream-dbg
2
+
3
+ npm distribution of the [agent-stream-dbg](https://github.com/Obedience-Corp/agent-stream-dbg) Go CLI.
4
+
5
+ Same model as [`@obedience-corp/festival`](https://www.npmjs.com/package/@obedience-corp/festival):
6
+ on install, download the matching GitHub Release archive and verify `checksums.txt`.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install -g @obedience-corp/agent-stream-dbg
12
+ npx @obedience-corp/agent-stream-dbg --help
13
+ ```
14
+
15
+ Also works with pnpm / bun.
16
+
17
+ ## Requirements
18
+
19
+ - Node.js 18+
20
+ - macOS or Linux (`x64` / `arm64`)
21
+ - Network access to GitHub Releases on install
22
+
23
+ ## Alternatives
24
+
25
+ ```bash
26
+ go install github.com/Obedience-Corp/agent-stream-dbg/cmd/agent-stream-dbg@latest
27
+
28
+ brew tap Obedience-Corp/tap
29
+ brew trust Obedience-Corp/tap
30
+ brew install agent-stream-dbg
31
+ ```
32
+
33
+ ## Maintainers
34
+
35
+ Releases are automated via GoReleaser + this package’s `scripts/publish_npm_package.sh`
36
+ (on tag push). Do not hand-edit package version on `main` (stays `0.0.0`); publish
37
+ sets the version from the git tag.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { runBinary } = require("../lib/run");
4
+
5
+ runBinary().catch((err) => {
6
+ console.error(`Failed to run agent-stream-dbg: ${err.message}`);
7
+ process.exit(1);
8
+ });
package/install.js ADDED
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env node
2
+ // Festival-style npm installer: download GoReleaser archive + checksums.txt.
3
+
4
+ const crypto = require("crypto");
5
+ const fs = require("fs");
6
+ const https = require("https");
7
+ const path = require("path");
8
+ const { spawnSync } = require("child_process");
9
+
10
+ const REPO = "Obedience-Corp/agent-stream-dbg";
11
+ const BINARY = "agent-stream-dbg";
12
+ const DOWNLOAD_ATTEMPTS = 3;
13
+ const DOWNLOAD_TIMEOUT_MS = 60_000;
14
+ const RETRY_BASE_DELAY_MS = 750;
15
+
16
+ const PLATFORM_MAP = {
17
+ darwin: "macOS",
18
+ linux: "linux",
19
+ };
20
+
21
+ const ARCH_MAP = {
22
+ x64: "x86_64",
23
+ arm64: "arm64",
24
+ };
25
+
26
+ function packageVersion() {
27
+ return require("./package.json").version;
28
+ }
29
+
30
+ function releaseTag(version = packageVersion()) {
31
+ return `v${version}`;
32
+ }
33
+
34
+ function targetForCurrentPlatform() {
35
+ const platform = PLATFORM_MAP[process.platform];
36
+ const arch = ARCH_MAP[process.arch];
37
+ if (!platform || !arch) {
38
+ throw new Error(
39
+ `Unsupported platform: ${process.platform}/${process.arch}. Supported: macOS/Linux x64/arm64.`,
40
+ );
41
+ }
42
+ return `${platform}-${arch}`;
43
+ }
44
+
45
+ function archiveName(version = packageVersion()) {
46
+ return `agent-stream-dbg-${version}-${targetForCurrentPlatform()}.tar.gz`;
47
+ }
48
+
49
+ function releaseURL(asset, version = packageVersion()) {
50
+ return `https://github.com/${REPO}/releases/download/${releaseTag(version)}/${asset}`;
51
+ }
52
+
53
+ function binaryPath() {
54
+ const name =
55
+ process.platform === "win32" ? `${BINARY}.exe` : `${BINARY}-bin`;
56
+ return path.join(__dirname, "bin", name);
57
+ }
58
+
59
+ function haveInstallArtifacts() {
60
+ return fs.existsSync(binaryPath());
61
+ }
62
+
63
+ function sleep(ms) {
64
+ return new Promise((resolve) => setTimeout(resolve, ms));
65
+ }
66
+
67
+ function downloadOnce(url, dest) {
68
+ return new Promise((resolve, reject) => {
69
+ let settled = false;
70
+ const fail = (err) => {
71
+ if (settled) return;
72
+ settled = true;
73
+ fs.rmSync(dest, { force: true });
74
+ reject(err);
75
+ };
76
+ const done = () => {
77
+ if (settled) return;
78
+ settled = true;
79
+ resolve();
80
+ };
81
+
82
+ const follow = (nextURL, redirects = 0) => {
83
+ if (redirects > 10) {
84
+ fail(new Error("too many redirects"));
85
+ return;
86
+ }
87
+ const request = https
88
+ .get(
89
+ nextURL,
90
+ { headers: { "User-Agent": "agent-stream-dbg-npm" } },
91
+ (response) => {
92
+ if (
93
+ response.statusCode >= 300 &&
94
+ response.statusCode < 400 &&
95
+ response.headers.location
96
+ ) {
97
+ response.resume();
98
+ follow(response.headers.location, redirects + 1);
99
+ return;
100
+ }
101
+ if (response.statusCode !== 200) {
102
+ response.resume();
103
+ fail(
104
+ new Error(
105
+ `failed to download ${url}: HTTP ${response.statusCode}`,
106
+ ),
107
+ );
108
+ return;
109
+ }
110
+ const file = fs.createWriteStream(dest);
111
+ response.pipe(file);
112
+ file.on("finish", () => file.close(done));
113
+ file.on("error", fail);
114
+ },
115
+ )
116
+ .on("error", fail);
117
+ request.setTimeout(DOWNLOAD_TIMEOUT_MS, () => {
118
+ request.destroy(
119
+ new Error(`download timeout after ${DOWNLOAD_TIMEOUT_MS / 1000}s`),
120
+ );
121
+ });
122
+ };
123
+ follow(url);
124
+ });
125
+ }
126
+
127
+ async function download(url, dest, attempts = DOWNLOAD_ATTEMPTS) {
128
+ let lastErr;
129
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
130
+ try {
131
+ await downloadOnce(url, dest);
132
+ return;
133
+ } catch (err) {
134
+ lastErr = err;
135
+ if (attempt === attempts) break;
136
+ const delay = RETRY_BASE_DELAY_MS * 2 ** (attempt - 1);
137
+ console.warn(
138
+ `Download failed (${attempt}/${attempts}) for ${path.basename(dest)}: ${err.message}. Retrying in ${delay}ms...`,
139
+ );
140
+ await sleep(delay);
141
+ }
142
+ }
143
+ throw lastErr;
144
+ }
145
+
146
+ function sha256(filePath) {
147
+ return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
148
+ }
149
+
150
+ function expectedChecksum(checksumsPath, filename) {
151
+ for (const line of fs.readFileSync(checksumsPath, "utf8").split(/\r?\n/)) {
152
+ const parts = line.trim().split(/\s+/);
153
+ if (parts.length >= 2 && parts[1] === filename) {
154
+ return parts[0];
155
+ }
156
+ }
157
+ throw new Error(`checksum for ${filename} not found in checksums.txt`);
158
+ }
159
+
160
+ function verifyChecksum(archivePath, checksumsPath, filename) {
161
+ const expected = expectedChecksum(checksumsPath, filename);
162
+ const actual = sha256(archivePath);
163
+ if (actual !== expected) {
164
+ throw new Error(
165
+ `checksum mismatch for ${filename}: expected ${expected}, got ${actual}`,
166
+ );
167
+ }
168
+ }
169
+
170
+ function extractArchive(archivePath, destDir) {
171
+ const result = spawnSync("tar", ["-xzf", archivePath, "-C", destDir], {
172
+ stdio: "inherit",
173
+ });
174
+ if (result.error) throw result.error;
175
+ if (result.status !== 0) {
176
+ throw new Error(`tar exited with status ${result.status}`);
177
+ }
178
+ }
179
+
180
+ async function install(options = {}) {
181
+ const force = options.force === true;
182
+ if (!force && haveInstallArtifacts()) {
183
+ return;
184
+ }
185
+
186
+ const version = packageVersion();
187
+ if (version === "0.0.0") {
188
+ throw new Error(
189
+ "package version is 0.0.0 (dev checkout). Publish a release or install with Go/Homebrew.",
190
+ );
191
+ }
192
+
193
+ const filename = archiveName(version);
194
+ const binDir = path.join(__dirname, "bin");
195
+ const tempDir = path.join(__dirname, ".tmp-extract");
196
+ const archivePath = path.join(__dirname, filename);
197
+ const checksumsPath = path.join(__dirname, "checksums.txt");
198
+
199
+ console.log(
200
+ `Installing agent-stream-dbg ${version} (${targetForCurrentPlatform()})...`,
201
+ );
202
+
203
+ fs.mkdirSync(binDir, { recursive: true });
204
+ fs.rmSync(tempDir, { recursive: true, force: true });
205
+ fs.mkdirSync(tempDir, { recursive: true });
206
+
207
+ try {
208
+ await download(releaseURL(filename, version), archivePath);
209
+ await download(releaseURL("checksums.txt", version), checksumsPath);
210
+ verifyChecksum(archivePath, checksumsPath, filename);
211
+ extractArchive(archivePath, tempDir);
212
+
213
+ const extractedPath = path.join(tempDir, BINARY);
214
+ const targetPath = binaryPath();
215
+ if (!fs.existsSync(extractedPath)) {
216
+ throw new Error(`${BINARY} not found in ${filename}`);
217
+ }
218
+ fs.renameSync(extractedPath, targetPath);
219
+ if (process.platform !== "win32") {
220
+ fs.chmodSync(targetPath, 0o755);
221
+ }
222
+ console.log("Installed agent-stream-dbg successfully");
223
+ } finally {
224
+ fs.rmSync(tempDir, { recursive: true, force: true });
225
+ fs.rmSync(archivePath, { force: true });
226
+ fs.rmSync(checksumsPath, { force: true });
227
+ }
228
+ }
229
+
230
+ async function main() {
231
+ try {
232
+ await install({ force: false });
233
+ } catch (err) {
234
+ console.error(`Failed to install agent-stream-dbg: ${err.message}`);
235
+ console.error(
236
+ [
237
+ "",
238
+ "Fallbacks:",
239
+ " go install github.com/Obedience-Corp/agent-stream-dbg/cmd/agent-stream-dbg@latest",
240
+ " brew tap Obedience-Corp/tap && brew trust Obedience-Corp/tap && brew install agent-stream-dbg",
241
+ "",
242
+ ].join("\n"),
243
+ );
244
+ process.exit(1);
245
+ }
246
+ }
247
+
248
+ if (require.main === module) {
249
+ main();
250
+ }
251
+
252
+ module.exports = {
253
+ archiveName,
254
+ binaryPath,
255
+ install,
256
+ targetForCurrentPlatform,
257
+ };
package/lib/run.js ADDED
@@ -0,0 +1,27 @@
1
+ const fs = require("fs");
2
+ const { spawnSync } = require("child_process");
3
+
4
+ const { binaryPath, install } = require("../install");
5
+
6
+ async function runBinary() {
7
+ const target = binaryPath();
8
+
9
+ if (!fs.existsSync(target)) {
10
+ await install();
11
+ }
12
+
13
+ const result = spawnSync(target, process.argv.slice(2), {
14
+ stdio: "inherit",
15
+ shell: false,
16
+ });
17
+
18
+ if (result.error) {
19
+ throw result.error;
20
+ }
21
+
22
+ process.exit(result.status ?? 1);
23
+ }
24
+
25
+ module.exports = {
26
+ runBinary,
27
+ };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@obedience-corp/agent-stream-dbg",
3
+ "version": "0.1.1",
4
+ "description": "TUI debugger for multi-agent event streams (SSE, gRPC, ACP) — Go binary via npm",
5
+ "license": "Apache-2.0",
6
+ "author": "Obedience Corp",
7
+ "homepage": "https://github.com/Obedience-Corp/agent-stream-dbg#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Obedience-Corp/agent-stream-dbg.git",
11
+ "directory": "npm"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Obedience-Corp/agent-stream-dbg/issues"
15
+ },
16
+ "keywords": [
17
+ "agents",
18
+ "debugging",
19
+ "tui",
20
+ "grpc",
21
+ "sse",
22
+ "acp",
23
+ "cli"
24
+ ],
25
+ "bin": {
26
+ "agent-stream-dbg": "bin/agent-stream-dbg"
27
+ },
28
+ "scripts": {
29
+ "postinstall": "node install.js"
30
+ },
31
+ "files": [
32
+ "README.md",
33
+ "bin",
34
+ "install.js",
35
+ "lib"
36
+ ],
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "os": [
41
+ "darwin",
42
+ "linux"
43
+ ],
44
+ "cpu": [
45
+ "x64",
46
+ "arm64"
47
+ ]
48
+ }