agentspace-connect 0.1.0

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,26 @@
1
+ # agentspace
2
+
3
+ Connect your AI coding agents to an [AgentSpace](https://github.com/IndicatedP/agentspace) wallboard.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npx agentspace
9
+ ```
10
+
11
+ The interactive wizard will prompt for:
12
+
13
+ - **AgentSpace URL** — your deployment (defaults to `http://localhost:3000`)
14
+ - **Space code** — shown on the admin page
15
+ - **Owner name** — your name
16
+ - **Agent name** — how this agent appears on the wallboard
17
+ - **Tool** — `claude` or `codex`
18
+ - **Claude scope** — `global` (all sessions) or `project` (current directory only)
19
+ - **Space password** — the view password for the space
20
+
21
+ It then installs the appropriate hooks/config so your agent reports activity to the wallboard.
22
+
23
+ ## Requirements
24
+
25
+ - Node.js 18+
26
+ - `bash`, `curl`, and `jq` available in your terminal
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+ import { createInterface } from "node:readline/promises";
3
+ import { stdin, stdout } from "node:process";
4
+ import { spawn } from "node:child_process";
5
+
6
+ function stripTrailingSlash(input) {
7
+ return input.replace(/\/+$/, "");
8
+ }
9
+
10
+ async function promptHidden(prompt) {
11
+ return new Promise((resolve, reject) => {
12
+ let value = "";
13
+ let rawEnabled = false;
14
+
15
+ const cleanup = () => {
16
+ stdin.removeListener("data", onData);
17
+ if (rawEnabled && stdin.isTTY) {
18
+ stdin.setRawMode(false);
19
+ }
20
+ stdin.pause();
21
+ };
22
+
23
+ const onData = (chunk) => {
24
+ const ch = String(chunk);
25
+ if (ch === "\u0003") {
26
+ cleanup();
27
+ reject(new Error("Cancelled"));
28
+ return;
29
+ }
30
+ if (ch === "\r" || ch === "\n" || ch === "\u0004") {
31
+ cleanup();
32
+ stdout.write("\n");
33
+ resolve(value.trim());
34
+ return;
35
+ }
36
+ if (ch === "\u007f") {
37
+ if (value.length > 0) {
38
+ value = value.slice(0, -1);
39
+ stdout.write("\b \b");
40
+ }
41
+ return;
42
+ }
43
+ value += ch;
44
+ stdout.write("*");
45
+ };
46
+
47
+ stdout.write(prompt);
48
+ stdin.resume();
49
+ if (stdin.isTTY) {
50
+ stdin.setRawMode(true);
51
+ rawEnabled = true;
52
+ }
53
+ stdin.setEncoding("utf8");
54
+ stdin.on("data", onData);
55
+ });
56
+ }
57
+
58
+ function required(value, field) {
59
+ const out = value.trim();
60
+ if (!out) throw new Error(`Missing ${field}`);
61
+ return out;
62
+ }
63
+
64
+ async function run() {
65
+ if (!stdin.isTTY || !stdout.isTTY) {
66
+ throw new Error("Interactive terminal required. Run `npx agentspace` in a normal shell.");
67
+ }
68
+
69
+ const rl = createInterface({ input: stdin, output: stdout });
70
+
71
+ try {
72
+ const baseUrlInput = await rl.question("AgentSpace URL [http://localhost:3000]: ");
73
+ const baseUrl = stripTrailingSlash(baseUrlInput.trim() || "http://localhost:3000");
74
+
75
+ const spaceCode = required(await rl.question("Space code: "), "space code");
76
+ const owner = required(await rl.question("Owner name: "), "owner name");
77
+ const agentName = required(await rl.question("Agent name: "), "agent name");
78
+
79
+ let tool = (await rl.question("Tool (claude/codex) [claude]: ")).trim().toLowerCase();
80
+ if (tool !== "claude" && tool !== "codex") tool = "claude";
81
+
82
+ let mode = "global";
83
+ if (tool === "claude") {
84
+ const modeInput = (await rl.question("Claude scope (global/project) [global]: "))
85
+ .trim()
86
+ .toLowerCase();
87
+ if (modeInput === "project") mode = "project";
88
+ }
89
+
90
+ rl.close();
91
+
92
+ const password = required(await promptHidden("Space password: "), "space password");
93
+
94
+ const connectRes = await fetch(`${baseUrl}/api/connect`, {
95
+ method: "POST",
96
+ headers: { "content-type": "application/json" },
97
+ body: JSON.stringify({
98
+ spaceCode,
99
+ password,
100
+ owner,
101
+ agentName,
102
+ tool,
103
+ mode,
104
+ }),
105
+ });
106
+
107
+ const payload = await connectRes
108
+ .json()
109
+ .catch(() => null);
110
+
111
+ if (!connectRes.ok || !payload?.setupUrl) {
112
+ const msg = payload?.error ?? `Connect failed (${connectRes.status})`;
113
+ throw new Error(msg);
114
+ }
115
+
116
+ const setupUrl = payload.setupUrl;
117
+ const escaped = setupUrl.replace(/'/g, "'\\''");
118
+ const installCmd = `bash <(curl -fsSL '${escaped}')`;
119
+
120
+ console.log("");
121
+ console.log(
122
+ `Connecting ${owner} to ${payload.space?.name ?? "space"} (${payload.space?.slug ?? ""}) as ${payload.agent?.name ?? agentName}...`,
123
+ );
124
+ console.log("");
125
+
126
+ const exitCode = await new Promise((resolve) => {
127
+ const child = spawn("bash", ["-lc", installCmd], { stdio: "inherit" });
128
+ child.on("close", (code) => resolve(code ?? 1));
129
+ });
130
+
131
+ if (exitCode !== 0) {
132
+ throw new Error("Setup script failed");
133
+ }
134
+
135
+ console.log("");
136
+ console.log("Connected. Start a new session and activity should appear in AgentSpace.");
137
+ } finally {
138
+ rl.close();
139
+ stdin.pause();
140
+ }
141
+ }
142
+
143
+ run().catch((err) => {
144
+ console.error(`\nError: ${err?.message ?? String(err)}`);
145
+ process.exit(1);
146
+ });
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "agentspace-connect",
3
+ "version": "0.1.0",
4
+ "description": "Connect your AI coding agents to an AgentSpace wallboard",
5
+ "type": "module",
6
+ "bin": {
7
+ "agentspace-connect": "./bin/agentspace.mjs"
8
+ },
9
+ "engines": {
10
+ "node": ">=18"
11
+ },
12
+ "keywords": [
13
+ "agentspace",
14
+ "ai",
15
+ "agents",
16
+ "claude",
17
+ "codex",
18
+ "wallboard",
19
+ "cli"
20
+ ],
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/IndicatedP/agentspace.git",
25
+ "directory": "packages/cli"
26
+ },
27
+ "homepage": "https://github.com/IndicatedP/agentspace",
28
+ "files": [
29
+ "bin/"
30
+ ]
31
+ }