@stamn/cli 0.1.0-alpha.0 → 0.1.0-alpha.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/dist/bin.js +10 -2
- package/dist/bin.js.map +1 -1
- package/dist/chunk-ECKKSWUQ.js +342 -0
- package/dist/chunk-ECKKSWUQ.js.map +1 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +9 -1
- package/package.json +1 -1
- package/dist/chunk-7DSOXMQ6.js +0 -206
- package/dist/chunk-7DSOXMQ6.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createDefaultAdapter,
|
|
4
|
+
handleAgentList,
|
|
5
|
+
handleAgentRegister,
|
|
6
|
+
handleAgentSelect,
|
|
4
7
|
handleConfig,
|
|
5
8
|
handleLogin,
|
|
9
|
+
handleLogout,
|
|
6
10
|
handleStatus,
|
|
7
11
|
handleUninstall
|
|
8
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ECKKSWUQ.js";
|
|
9
13
|
|
|
10
14
|
// src/bin.ts
|
|
11
15
|
import { Command } from "commander";
|
|
12
16
|
var adapter = createDefaultAdapter();
|
|
13
17
|
var program = new Command();
|
|
14
18
|
program.name("stamn").description("Stamn CLI").version("0.1.0-alpha.0");
|
|
19
|
+
program.command("login").description("Authenticate with Stamn").action(() => handleLogin({}, adapter));
|
|
20
|
+
program.command("logout").description("Clear auth session").action(() => handleLogout({}, adapter));
|
|
15
21
|
var agent = program.command("agent").description("Agent management");
|
|
16
|
-
agent.command("
|
|
22
|
+
agent.command("register").description("Register a new agent or reconnect to an existing one").option("--name <name>", "Agent name").action((opts) => handleAgentRegister(opts, adapter));
|
|
23
|
+
agent.command("list").description("List agents under your account").action(() => handleAgentList({}, adapter));
|
|
24
|
+
agent.command("select").description("Set active agent").argument("<nameOrId>", "Agent name or ID").action((nameOrId) => handleAgentSelect({ nameOrId }, adapter));
|
|
17
25
|
agent.command("config").description("View or update agent configuration").option("--name <name>", "Agent display name").option("--personality", "Open editor to set agent personality").action(
|
|
18
26
|
(opts) => handleConfig(opts, adapter)
|
|
19
27
|
);
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport {\n handleLogin,\n handleConfig,\n handleStatus,\n handleUninstall,\n} from \"@/commands\";\nimport { createDefaultAdapter } from \"@/config\";\n\nconst adapter = createDefaultAdapter();\n\nconst program = new Command();\n\nprogram.name(\"stamn\").description(\"Stamn CLI\").version(\"0.1.0-alpha.0\");\n\nconst agent = program.command(\"agent\").description(\"Agent management\");\n\nagent\n .command(\"
|
|
1
|
+
{"version":3,"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport {\n handleLogin,\n handleAgentRegister,\n handleAgentList,\n handleAgentSelect,\n handleLogout,\n handleConfig,\n handleStatus,\n handleUninstall,\n} from \"@/commands\";\nimport { createDefaultAdapter } from \"@/config\";\n\nconst adapter = createDefaultAdapter();\n\nconst program = new Command();\n\nprogram.name(\"stamn\").description(\"Stamn CLI\").version(\"0.1.0-alpha.0\");\n\nprogram\n .command(\"login\")\n .description(\"Authenticate with Stamn\")\n .action(() => handleLogin({}, adapter));\n\nprogram\n .command(\"logout\")\n .description(\"Clear auth session\")\n .action(() => handleLogout({}, adapter));\n\nconst agent = program.command(\"agent\").description(\"Agent management\");\n\nagent\n .command(\"register\")\n .description(\"Register a new agent or reconnect to an existing one\")\n .option(\"--name <name>\", \"Agent name\")\n .action((opts: { name?: string }) => handleAgentRegister(opts, adapter));\n\nagent\n .command(\"list\")\n .description(\"List agents under your account\")\n .action(() => handleAgentList({}, adapter));\n\nagent\n .command(\"select\")\n .description(\"Set active agent\")\n .argument(\"<nameOrId>\", \"Agent name or ID\")\n .action((nameOrId: string) => handleAgentSelect({ nameOrId }, adapter));\n\nagent\n .command(\"config\")\n .description(\"View or update agent configuration\")\n .option(\"--name <name>\", \"Agent display name\")\n .option(\"--personality\", \"Open editor to set agent personality\")\n .action((opts: { name?: string; personality?: boolean }) =>\n handleConfig(opts, adapter),\n );\n\nprogram\n .command(\"status\")\n .description(\"Show connection status and server health\")\n .action(() => handleStatus(adapter));\n\nprogram\n .command(\"uninstall\")\n .description(\"Remove CLI\")\n .action(() => handleUninstall(adapter));\n\nprogram.parse();\n"],"mappings":";;;;;;;;;;;;;;AACA,SAAS,eAAe;AAaxB,IAAM,UAAU,qBAAqB;AAErC,IAAM,UAAU,IAAI,QAAQ;AAE5B,QAAQ,KAAK,OAAO,EAAE,YAAY,WAAW,EAAE,QAAQ,eAAe;AAEtE,QACG,QAAQ,OAAO,EACf,YAAY,yBAAyB,EACrC,OAAO,MAAM,YAAY,CAAC,GAAG,OAAO,CAAC;AAExC,QACG,QAAQ,QAAQ,EAChB,YAAY,oBAAoB,EAChC,OAAO,MAAM,aAAa,CAAC,GAAG,OAAO,CAAC;AAEzC,IAAM,QAAQ,QAAQ,QAAQ,OAAO,EAAE,YAAY,kBAAkB;AAErE,MACG,QAAQ,UAAU,EAClB,YAAY,sDAAsD,EAClE,OAAO,iBAAiB,YAAY,EACpC,OAAO,CAAC,SAA4B,oBAAoB,MAAM,OAAO,CAAC;AAEzE,MACG,QAAQ,MAAM,EACd,YAAY,gCAAgC,EAC5C,OAAO,MAAM,gBAAgB,CAAC,GAAG,OAAO,CAAC;AAE5C,MACG,QAAQ,QAAQ,EAChB,YAAY,kBAAkB,EAC9B,SAAS,cAAc,kBAAkB,EACzC,OAAO,CAAC,aAAqB,kBAAkB,EAAE,SAAS,GAAG,OAAO,CAAC;AAExE,MACG,QAAQ,QAAQ,EAChB,YAAY,oCAAoC,EAChD,OAAO,iBAAiB,oBAAoB,EAC5C,OAAO,iBAAiB,sCAAsC,EAC9D;AAAA,EAAO,CAAC,SACP,aAAa,MAAM,OAAO;AAC5B;AAEF,QACG,QAAQ,QAAQ,EAChB,YAAY,0CAA0C,EACtD,OAAO,MAAM,aAAa,OAAO,CAAC;AAErC,QACG,QAAQ,WAAW,EACnB,YAAY,YAAY,EACxB,OAAO,MAAM,gBAAgB,OAAO,CAAC;AAExC,QAAQ,MAAM;","names":[]}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// src/commands/login.ts
|
|
2
|
+
import { intro, outro, spinner, log, note, cancel } from "@clack/prompts";
|
|
3
|
+
import { StamnClient } from "@stamn/sdk";
|
|
4
|
+
async function handleLogin(_opts, adapter) {
|
|
5
|
+
intro("Stamn Login");
|
|
6
|
+
const existing = adapter.readConfig();
|
|
7
|
+
if (existing?.apiKey) {
|
|
8
|
+
const s2 = spinner();
|
|
9
|
+
s2.start("Checking existing session...");
|
|
10
|
+
try {
|
|
11
|
+
const client2 = new StamnClient({ apiKey: existing.apiKey });
|
|
12
|
+
await client2.participants.list();
|
|
13
|
+
s2.stop("Session valid.");
|
|
14
|
+
log.info("Already logged in.");
|
|
15
|
+
outro("Run `stamn agent register` to create an agent, or `stamn agent list` to see existing ones.");
|
|
16
|
+
return;
|
|
17
|
+
} catch {
|
|
18
|
+
s2.stop("Session expired.");
|
|
19
|
+
log.warn("Existing session is invalid. Re-authenticating...");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const client = new StamnClient();
|
|
23
|
+
const s = spinner();
|
|
24
|
+
try {
|
|
25
|
+
s.start("Initiating device flow...");
|
|
26
|
+
const flow = await client.auth.initiateDeviceFlow();
|
|
27
|
+
s.stop("Device flow initiated.");
|
|
28
|
+
const label = (str) => str.padEnd(7);
|
|
29
|
+
note(
|
|
30
|
+
`${label("Open:")} ${flow.verificationUri}
|
|
31
|
+
${label("Code:")} ${flow.userCode}`,
|
|
32
|
+
"Authorize in your browser"
|
|
33
|
+
);
|
|
34
|
+
s.start("Waiting for approval...");
|
|
35
|
+
const apiKey = await client.auth.pollForApproval(flow.deviceCode);
|
|
36
|
+
s.stop("Approved!");
|
|
37
|
+
adapter.writeConfig({ apiKey });
|
|
38
|
+
log.success("Logged in successfully.");
|
|
39
|
+
log.info(`Config written to ${adapter.getConfigPath()}`);
|
|
40
|
+
outro("Now run `stamn agent register` to create or reconnect an agent.");
|
|
41
|
+
} catch (err) {
|
|
42
|
+
s.stop("Failed.");
|
|
43
|
+
cancel(`Login failed: ${err.message}`);
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/commands/agent-register.ts
|
|
49
|
+
import { intro as intro2, outro as outro2, spinner as spinner2, log as log2, cancel as cancel2, text } from "@clack/prompts";
|
|
50
|
+
import { StamnClient as StamnClient2 } from "@stamn/sdk";
|
|
51
|
+
async function handleAgentRegister(opts, adapter) {
|
|
52
|
+
intro2("Stamn Agent Register");
|
|
53
|
+
const config = adapter.readConfig();
|
|
54
|
+
if (!config?.apiKey) {
|
|
55
|
+
cancel2("Not logged in. Run `stamn login` first.");
|
|
56
|
+
process.exitCode = 1;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
let name = opts.name;
|
|
60
|
+
if (!name) {
|
|
61
|
+
const input = await text({
|
|
62
|
+
message: "What should we call this agent?",
|
|
63
|
+
placeholder: "my-agent",
|
|
64
|
+
validate: (value) => {
|
|
65
|
+
if (!value?.trim()) return "Name is required.";
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
if (typeof input === "symbol") {
|
|
69
|
+
cancel2("Cancelled.");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
name = input;
|
|
73
|
+
}
|
|
74
|
+
const client = new StamnClient2({ apiKey: config.apiKey });
|
|
75
|
+
const s = spinner2();
|
|
76
|
+
try {
|
|
77
|
+
s.start("Checking existing agents...");
|
|
78
|
+
const agents = await client.participants.list();
|
|
79
|
+
const match = agents.find((a) => a.name === name);
|
|
80
|
+
if (match) {
|
|
81
|
+
s.stop("Agent found.");
|
|
82
|
+
adapter.writeConfig({ agentId: match.id, agentName: match.name });
|
|
83
|
+
log2.success(`Agent "${match.name}" (${match.id}) already exists. Selected as active.`);
|
|
84
|
+
outro2("Done!");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
s.start("Registering agent...");
|
|
88
|
+
const participant = await client.participants.create({ name });
|
|
89
|
+
s.stop("Agent registered.");
|
|
90
|
+
adapter.writeConfig({ agentId: participant.id, agentName: participant.name });
|
|
91
|
+
log2.success(`Agent "${participant.name}" (${participant.id})`);
|
|
92
|
+
outro2("Done!");
|
|
93
|
+
} catch (err) {
|
|
94
|
+
s.stop("Failed.");
|
|
95
|
+
cancel2(`Registration failed: ${err.message}`);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/commands/agent-list.ts
|
|
101
|
+
import { intro as intro3, spinner as spinner3, log as log3, cancel as cancel3 } from "@clack/prompts";
|
|
102
|
+
import { StamnClient as StamnClient3 } from "@stamn/sdk";
|
|
103
|
+
async function handleAgentList(_opts, adapter) {
|
|
104
|
+
intro3("Stamn Agents");
|
|
105
|
+
const config = adapter.readConfig();
|
|
106
|
+
if (!config?.apiKey) {
|
|
107
|
+
cancel3("Not logged in. Run `stamn login` first.");
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const client = new StamnClient3({ apiKey: config.apiKey });
|
|
112
|
+
const s = spinner3();
|
|
113
|
+
try {
|
|
114
|
+
s.start("Fetching agents...");
|
|
115
|
+
const agents = await client.participants.list();
|
|
116
|
+
s.stop(`${agents.length} agent${agents.length === 1 ? "" : "s"} found.`);
|
|
117
|
+
if (agents.length === 0) {
|
|
118
|
+
log3.info("No agents found. Run `stamn agent register` to create one.");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
for (const agent of agents) {
|
|
122
|
+
const active = agent.id === config.agentId ? " (active)" : "";
|
|
123
|
+
log3.info(` ${agent.name} \u2014 ${agent.id}${active}`);
|
|
124
|
+
}
|
|
125
|
+
} catch (err) {
|
|
126
|
+
s.stop("Failed.");
|
|
127
|
+
cancel3(`Failed to list agents: ${err.message}`);
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/commands/agent-select.ts
|
|
133
|
+
import { intro as intro4, outro as outro3, spinner as spinner4, log as log4, cancel as cancel4 } from "@clack/prompts";
|
|
134
|
+
import { StamnClient as StamnClient4 } from "@stamn/sdk";
|
|
135
|
+
async function handleAgentSelect(opts, adapter) {
|
|
136
|
+
intro4("Stamn Agent Select");
|
|
137
|
+
const config = adapter.readConfig();
|
|
138
|
+
if (!config?.apiKey) {
|
|
139
|
+
cancel4("Not logged in. Run `stamn login` first.");
|
|
140
|
+
process.exitCode = 1;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const client = new StamnClient4({ apiKey: config.apiKey });
|
|
144
|
+
const s = spinner4();
|
|
145
|
+
try {
|
|
146
|
+
s.start("Fetching agents...");
|
|
147
|
+
const agents = await client.participants.list();
|
|
148
|
+
s.stop(`${agents.length} agent${agents.length === 1 ? "" : "s"} found.`);
|
|
149
|
+
const match = agents.find((a) => a.id === opts.nameOrId || a.name === opts.nameOrId);
|
|
150
|
+
if (!match) {
|
|
151
|
+
cancel4(`Agent "${opts.nameOrId}" not found. Run \`stamn agent list\` to see available agents.`);
|
|
152
|
+
process.exitCode = 1;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
adapter.writeConfig({ agentId: match.id, agentName: match.name });
|
|
156
|
+
log4.success(`Active agent set to "${match.name}" (${match.id})`);
|
|
157
|
+
outro3("Done!");
|
|
158
|
+
} catch (err) {
|
|
159
|
+
s.stop("Failed.");
|
|
160
|
+
cancel4(`Failed to select agent: ${err.message}`);
|
|
161
|
+
process.exitCode = 1;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/commands/logout.ts
|
|
166
|
+
import { intro as intro5, outro as outro4, log as log5, cancel as cancel5, confirm } from "@clack/prompts";
|
|
167
|
+
async function handleLogout(_opts, adapter) {
|
|
168
|
+
intro5("Stamn Logout");
|
|
169
|
+
const config = adapter.readConfig();
|
|
170
|
+
if (!config?.apiKey) {
|
|
171
|
+
log5.info("Not logged in.");
|
|
172
|
+
outro4("Nothing to do.");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const shouldContinue = await confirm({
|
|
176
|
+
message: "This will clear your auth session. Your agents will not be deleted. Continue?"
|
|
177
|
+
});
|
|
178
|
+
if (!shouldContinue || typeof shouldContinue === "symbol") {
|
|
179
|
+
cancel5("Cancelled.");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
adapter.writeConfig({ apiKey: "", agentId: "", agentName: "" });
|
|
183
|
+
log5.success("Logged out.");
|
|
184
|
+
outro4("Run `stamn login` to authenticate again.");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/commands/config.ts
|
|
188
|
+
import { execSync } from "child_process";
|
|
189
|
+
import { mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
190
|
+
import { join } from "path";
|
|
191
|
+
import { tmpdir } from "os";
|
|
192
|
+
import { log as log6 } from "@clack/prompts";
|
|
193
|
+
function openEditor(initial) {
|
|
194
|
+
const editor = process.env.EDITOR || process.env.VISUAL || "vi";
|
|
195
|
+
const tmpFile = join(tmpdir(), `stamn-personality-${Date.now()}.md`);
|
|
196
|
+
mkdirSync(tmpdir(), { recursive: true });
|
|
197
|
+
writeFileSync(tmpFile, initial, "utf-8");
|
|
198
|
+
try {
|
|
199
|
+
execSync(`${editor} "${tmpFile}"`, { stdio: "inherit" });
|
|
200
|
+
const result = readFileSync(tmpFile, "utf-8").trim();
|
|
201
|
+
return result || null;
|
|
202
|
+
} catch {
|
|
203
|
+
return null;
|
|
204
|
+
} finally {
|
|
205
|
+
try {
|
|
206
|
+
unlinkSync(tmpFile);
|
|
207
|
+
} catch {
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function handleConfig(opts, adapter) {
|
|
212
|
+
if (!opts.name && !opts.personality) {
|
|
213
|
+
const config = adapter.readConfig();
|
|
214
|
+
if (!config) {
|
|
215
|
+
log6.warn("No config found. Run `stamn login` first.");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
log6.info(`Name: ${config.agentName ?? "(not set)"}`);
|
|
219
|
+
log6.info(`Personality: ${config.personality ? "configured" : "(not set)"}`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (opts.name) {
|
|
223
|
+
adapter.writeConfig({ agentName: opts.name });
|
|
224
|
+
log6.success(`Name set: "${opts.name}"`);
|
|
225
|
+
}
|
|
226
|
+
if (opts.personality) {
|
|
227
|
+
const existing = adapter.readConfig()?.personality ?? "";
|
|
228
|
+
const text2 = openEditor(existing);
|
|
229
|
+
if (!text2) {
|
|
230
|
+
log6.warn("Editor closed without saving. Personality unchanged.");
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
adapter.writeConfig({ personality: text2 });
|
|
234
|
+
log6.success("Personality updated.");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// src/commands/status.ts
|
|
239
|
+
import { intro as intro6, outro as outro5, log as log7 } from "@clack/prompts";
|
|
240
|
+
import { StamnClient as StamnClient5 } from "@stamn/sdk";
|
|
241
|
+
async function handleStatus(adapter) {
|
|
242
|
+
const config = adapter.readConfig();
|
|
243
|
+
const status = adapter.readStatusFile();
|
|
244
|
+
const label = (str) => str.padEnd(14);
|
|
245
|
+
intro6("Stamn Status");
|
|
246
|
+
log7.info(`${label("Agent ID:")} ${config?.agentId || "(not configured)"}`);
|
|
247
|
+
log7.info(
|
|
248
|
+
`${label("Agent Name:")} ${config?.agentName || "(not configured)"}`
|
|
249
|
+
);
|
|
250
|
+
log7.info(`${label("Connected:")} ${status?.connected ? "yes" : "no"}`);
|
|
251
|
+
if (status?.connected && status.connectedAt) {
|
|
252
|
+
log7.info(
|
|
253
|
+
`${label("Since:")} ${new Date(status.connectedAt).toLocaleString()}`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (config?.apiKey) {
|
|
257
|
+
const client = new StamnClient5({ apiKey: config.apiKey });
|
|
258
|
+
const health = await client.health.check();
|
|
259
|
+
log7.info(`${label("Server:")} ${health.ok ? "healthy" : "unhealthy"}`);
|
|
260
|
+
}
|
|
261
|
+
outro5("");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/commands/uninstall.ts
|
|
265
|
+
import { intro as intro7, outro as outro6, confirm as confirm2, log as log8, cancel as cancel6 } from "@clack/prompts";
|
|
266
|
+
async function handleUninstall(adapter) {
|
|
267
|
+
intro7("Stamn Uninstall");
|
|
268
|
+
const shouldContinue = await confirm2({
|
|
269
|
+
message: "This will remove all Stamn config and data. Continue?"
|
|
270
|
+
});
|
|
271
|
+
if (!shouldContinue || typeof shouldContinue === "symbol") {
|
|
272
|
+
cancel6("Uninstall cancelled.");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
adapter.uninstall?.();
|
|
277
|
+
log8.success("Removed Stamn config");
|
|
278
|
+
outro6("Stamn config removed.");
|
|
279
|
+
} catch (err) {
|
|
280
|
+
cancel6(`Failed to remove config: ${err.message}`);
|
|
281
|
+
process.exitCode = 1;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/config.ts
|
|
286
|
+
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
287
|
+
import { dirname, join as join2 } from "path";
|
|
288
|
+
import { homedir } from "os";
|
|
289
|
+
function readJsonFile(filePath) {
|
|
290
|
+
try {
|
|
291
|
+
const raw = readFileSync2(filePath, "utf-8");
|
|
292
|
+
return JSON.parse(raw);
|
|
293
|
+
} catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
function writeJsonFile(filePath, data) {
|
|
298
|
+
mkdirSync2(dirname(filePath), { recursive: true });
|
|
299
|
+
writeFileSync2(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
300
|
+
}
|
|
301
|
+
function getConfigPath() {
|
|
302
|
+
return join2(homedir(), ".stamn", "config.json");
|
|
303
|
+
}
|
|
304
|
+
function readConfig() {
|
|
305
|
+
return readJsonFile(getConfigPath());
|
|
306
|
+
}
|
|
307
|
+
function writeConfig(updates) {
|
|
308
|
+
const existing = readConfig() ?? {};
|
|
309
|
+
writeJsonFile(getConfigPath(), { ...existing, ...updates });
|
|
310
|
+
}
|
|
311
|
+
function readStatusFile() {
|
|
312
|
+
return readJsonFile(join2(homedir(), ".stamn", "status.json"));
|
|
313
|
+
}
|
|
314
|
+
function createDefaultAdapter() {
|
|
315
|
+
return {
|
|
316
|
+
readConfig,
|
|
317
|
+
writeConfig,
|
|
318
|
+
readStatusFile,
|
|
319
|
+
getConfigPath,
|
|
320
|
+
uninstall() {
|
|
321
|
+
const configDir = dirname(getConfigPath());
|
|
322
|
+
if (existsSync(configDir)) {
|
|
323
|
+
rmSync(configDir, { recursive: true, force: true });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export {
|
|
330
|
+
handleLogin,
|
|
331
|
+
handleAgentRegister,
|
|
332
|
+
handleAgentList,
|
|
333
|
+
handleAgentSelect,
|
|
334
|
+
handleLogout,
|
|
335
|
+
handleConfig,
|
|
336
|
+
handleStatus,
|
|
337
|
+
handleUninstall,
|
|
338
|
+
readJsonFile,
|
|
339
|
+
writeJsonFile,
|
|
340
|
+
createDefaultAdapter
|
|
341
|
+
};
|
|
342
|
+
//# sourceMappingURL=chunk-ECKKSWUQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/login.ts","../src/commands/agent-register.ts","../src/commands/agent-list.ts","../src/commands/agent-select.ts","../src/commands/logout.ts","../src/commands/config.ts","../src/commands/status.ts","../src/commands/uninstall.ts","../src/config.ts"],"sourcesContent":["import { intro, outro, spinner, log, note, cancel } from '@clack/prompts';\nimport { StamnClient } from '@stamn/sdk';\nimport type { ConfigAdapter } from '@/types';\n\nexport async function handleLogin(_opts: Record<string, never>, adapter: ConfigAdapter): Promise<void> {\n intro('Stamn Login');\n\n const existing = adapter.readConfig();\n\n if (existing?.apiKey) {\n const s = spinner();\n s.start('Checking existing session...');\n try {\n const client = new StamnClient({ apiKey: existing.apiKey });\n await client.participants.list();\n s.stop('Session valid.');\n log.info('Already logged in.');\n outro('Run `stamn agent register` to create an agent, or `stamn agent list` to see existing ones.');\n return;\n } catch {\n s.stop('Session expired.');\n log.warn('Existing session is invalid. Re-authenticating...');\n }\n }\n\n const client = new StamnClient();\n const s = spinner();\n\n try {\n s.start(\"Initiating device flow...\");\n const flow = await client.auth.initiateDeviceFlow();\n s.stop(\"Device flow initiated.\");\n\n const label = (str: string) => str.padEnd(7);\n note(\n `${label(\"Open:\")} ${flow.verificationUri}\\n${label(\"Code:\")} ${flow.userCode}`,\n \"Authorize in your browser\",\n );\n\n s.start(\"Waiting for approval...\");\n const apiKey = await client.auth.pollForApproval(flow.deviceCode);\n s.stop(\"Approved!\");\n\n adapter.writeConfig({ apiKey });\n\n log.success('Logged in successfully.');\n log.info(`Config written to ${adapter.getConfigPath()}`);\n\n outro('Now run `stamn agent register` to create or reconnect an agent.');\n } catch (err) {\n s.stop(\"Failed.\");\n cancel(`Login failed: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n}\n","import { intro, outro, spinner, log, cancel, text } from '@clack/prompts';\nimport { StamnClient } from '@stamn/sdk';\nimport type { ConfigAdapter } from '@/types';\n\nexport async function handleAgentRegister(opts: { name?: string }, adapter: ConfigAdapter): Promise<void> {\n intro('Stamn Agent Register');\n\n const config = adapter.readConfig();\n if (!config?.apiKey) {\n cancel('Not logged in. Run `stamn login` first.');\n process.exitCode = 1;\n return;\n }\n\n let name = opts.name;\n if (!name) {\n const input = await text({\n message: 'What should we call this agent?',\n placeholder: 'my-agent',\n validate: (value) => {\n if (!value?.trim()) return 'Name is required.';\n },\n });\n if (typeof input === 'symbol') {\n cancel('Cancelled.');\n return;\n }\n name = input;\n }\n\n const client = new StamnClient({ apiKey: config.apiKey });\n const s = spinner();\n\n try {\n s.start('Checking existing agents...');\n const agents = await client.participants.list();\n const match = agents.find((a) => a.name === name);\n\n if (match) {\n s.stop('Agent found.');\n adapter.writeConfig({ agentId: match.id, agentName: match.name });\n log.success(`Agent \"${match.name}\" (${match.id}) already exists. Selected as active.`);\n outro('Done!');\n return;\n }\n\n s.start('Registering agent...');\n const participant = await client.participants.create({ name });\n s.stop('Agent registered.');\n\n adapter.writeConfig({ agentId: participant.id, agentName: participant.name });\n\n log.success(`Agent \"${participant.name}\" (${participant.id})`);\n outro('Done!');\n } catch (err) {\n s.stop('Failed.');\n cancel(`Registration failed: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n}\n","import { intro, spinner, log, cancel } from '@clack/prompts';\nimport { StamnClient } from '@stamn/sdk';\nimport type { ConfigAdapter } from '@/types';\n\nexport async function handleAgentList(_opts: Record<string, never>, adapter: ConfigAdapter): Promise<void> {\n intro('Stamn Agents');\n\n const config = adapter.readConfig();\n if (!config?.apiKey) {\n cancel('Not logged in. Run `stamn login` first.');\n process.exitCode = 1;\n return;\n }\n\n const client = new StamnClient({ apiKey: config.apiKey });\n const s = spinner();\n\n try {\n s.start('Fetching agents...');\n const agents = await client.participants.list();\n s.stop(`${agents.length} agent${agents.length === 1 ? '' : 's'} found.`);\n\n if (agents.length === 0) {\n log.info('No agents found. Run `stamn agent register` to create one.');\n return;\n }\n\n for (const agent of agents) {\n const active = agent.id === config.agentId ? ' (active)' : '';\n log.info(` ${agent.name} — ${agent.id}${active}`);\n }\n } catch (err) {\n s.stop('Failed.');\n cancel(`Failed to list agents: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n}\n","import { intro, outro, spinner, log, cancel } from '@clack/prompts';\nimport { StamnClient } from '@stamn/sdk';\nimport type { ConfigAdapter } from '@/types';\n\nexport async function handleAgentSelect(opts: { nameOrId: string }, adapter: ConfigAdapter): Promise<void> {\n intro('Stamn Agent Select');\n\n const config = adapter.readConfig();\n if (!config?.apiKey) {\n cancel('Not logged in. Run `stamn login` first.');\n process.exitCode = 1;\n return;\n }\n\n const client = new StamnClient({ apiKey: config.apiKey });\n const s = spinner();\n\n try {\n s.start('Fetching agents...');\n const agents = await client.participants.list();\n s.stop(`${agents.length} agent${agents.length === 1 ? '' : 's'} found.`);\n\n const match = agents.find((a) => a.id === opts.nameOrId || a.name === opts.nameOrId);\n\n if (!match) {\n cancel(`Agent \"${opts.nameOrId}\" not found. Run \\`stamn agent list\\` to see available agents.`);\n process.exitCode = 1;\n return;\n }\n\n adapter.writeConfig({ agentId: match.id, agentName: match.name });\n log.success(`Active agent set to \"${match.name}\" (${match.id})`);\n outro('Done!');\n } catch (err) {\n s.stop('Failed.');\n cancel(`Failed to select agent: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n}\n","import { intro, outro, log, cancel, confirm } from '@clack/prompts';\nimport type { ConfigAdapter } from '@/types';\n\nexport async function handleLogout(_opts: Record<string, never>, adapter: ConfigAdapter): Promise<void> {\n intro('Stamn Logout');\n\n const config = adapter.readConfig();\n if (!config?.apiKey) {\n log.info('Not logged in.');\n outro('Nothing to do.');\n return;\n }\n\n const shouldContinue = await confirm({\n message: 'This will clear your auth session. Your agents will not be deleted. Continue?',\n });\n\n if (!shouldContinue || typeof shouldContinue === 'symbol') {\n cancel('Cancelled.');\n return;\n }\n\n adapter.writeConfig({ apiKey: '', agentId: '', agentName: '' } as any);\n log.success('Logged out.');\n outro('Run `stamn login` to authenticate again.');\n}\n","import { execSync } from \"child_process\";\nimport { mkdirSync, readFileSync, writeFileSync, unlinkSync } from \"fs\";\nimport { join } from \"path\";\nimport { tmpdir } from \"os\";\nimport { log } from \"@clack/prompts\";\nimport type { ConfigAdapter } from \"@/types\";\n\nfunction openEditor(initial: string): string | null {\n const editor = process.env.EDITOR || process.env.VISUAL || \"vi\";\n const tmpFile = join(tmpdir(), `stamn-personality-${Date.now()}.md`);\n\n mkdirSync(tmpdir(), { recursive: true });\n writeFileSync(tmpFile, initial, \"utf-8\");\n\n try {\n execSync(`${editor} \"${tmpFile}\"`, { stdio: \"inherit\" });\n const result = readFileSync(tmpFile, \"utf-8\").trim();\n return result || null;\n } catch {\n return null;\n } finally {\n try {\n unlinkSync(tmpFile);\n } catch {}\n }\n}\n\nexport function handleConfig(\n opts: { name?: string; personality?: boolean },\n adapter: ConfigAdapter,\n): void {\n if (!opts.name && !opts.personality) {\n const config = adapter.readConfig();\n if (!config) {\n log.warn(\"No config found. Run `stamn login` first.\");\n return;\n }\n log.info(`Name: ${config.agentName ?? \"(not set)\"}`);\n log.info(`Personality: ${config.personality ? \"configured\" : \"(not set)\"}`);\n return;\n }\n\n if (opts.name) {\n adapter.writeConfig({ agentName: opts.name });\n log.success(`Name set: \"${opts.name}\"`);\n }\n\n if (opts.personality) {\n const existing = adapter.readConfig()?.personality ?? \"\";\n const text = openEditor(existing);\n if (!text) {\n log.warn(\"Editor closed without saving. Personality unchanged.\");\n return;\n }\n adapter.writeConfig({ personality: text });\n log.success(\"Personality updated.\");\n }\n}\n","import { intro, outro, log } from \"@clack/prompts\";\nimport { StamnClient } from \"@stamn/sdk\";\nimport type { StamnConfig, ConfigAdapter } from \"@/types\";\n\nexport async function handleStatus(adapter: ConfigAdapter): Promise<void> {\n const config = adapter.readConfig();\n const status = adapter.readStatusFile();\n const label = (str: string) => str.padEnd(14);\n\n intro(\"Stamn Status\");\n\n log.info(`${label(\"Agent ID:\")} ${config?.agentId || \"(not configured)\"}`);\n log.info(\n `${label(\"Agent Name:\")} ${config?.agentName || \"(not configured)\"}`,\n );\n log.info(`${label(\"Connected:\")} ${status?.connected ? \"yes\" : \"no\"}`);\n\n if (status?.connected && status.connectedAt) {\n log.info(\n `${label(\"Since:\")} ${new Date(status.connectedAt).toLocaleString()}`,\n );\n }\n\n if (config?.apiKey) {\n const client = new StamnClient({ apiKey: config.apiKey });\n const health = await client.health.check();\n log.info(`${label(\"Server:\")} ${health.ok ? \"healthy\" : \"unhealthy\"}`);\n }\n\n outro(\"\");\n}\n","import { intro, outro, confirm, log, cancel } from \"@clack/prompts\";\nimport type { ConfigAdapter } from \"@/types\";\n\nexport async function handleUninstall(adapter: ConfigAdapter): Promise<void> {\n intro(\"Stamn Uninstall\");\n\n const shouldContinue = await confirm({\n message: \"This will remove all Stamn config and data. Continue?\",\n });\n\n if (!shouldContinue || typeof shouldContinue === \"symbol\") {\n cancel(\"Uninstall cancelled.\");\n return;\n }\n\n try {\n adapter.uninstall?.();\n log.success(\"Removed Stamn config\");\n outro(\"Stamn config removed.\");\n } catch (err) {\n cancel(`Failed to remove config: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n}\n","import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { homedir } from \"os\";\nimport type { StamnConfig, StamnStatusFile, ConfigAdapter } from \"@/types\";\n\nexport function readJsonFile<T>(filePath: string): T | null {\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\nexport function writeJsonFile(filePath: string, data: unknown): void {\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(data, null, 2) + \"\\n\", \"utf-8\");\n}\n\nexport function getConfigPath(): string {\n return join(homedir(), \".stamn\", \"config.json\");\n}\n\nexport function readConfig(): StamnConfig | null {\n return readJsonFile<StamnConfig>(getConfigPath());\n}\n\nexport function writeConfig(updates: Partial<StamnConfig>): void {\n const existing = readConfig() ?? {};\n writeJsonFile(getConfigPath(), { ...existing, ...updates });\n}\n\nexport function readStatusFile(): StamnStatusFile | null {\n return readJsonFile<StamnStatusFile>(join(homedir(), \".stamn\", \"status.json\"));\n}\n\nexport function createDefaultAdapter(): ConfigAdapter {\n return {\n readConfig,\n writeConfig,\n readStatusFile,\n getConfigPath,\n uninstall() {\n const configDir = dirname(getConfigPath());\n if (existsSync(configDir)) {\n rmSync(configDir, { recursive: true, force: true });\n }\n },\n };\n}\n"],"mappings":"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","names":["s","client","intro","outro","spinner","log","cancel","StamnClient","intro","spinner","log","cancel","StamnClient","intro","outro","spinner","log","cancel","StamnClient","intro","outro","log","cancel","log","text","intro","outro","log","StamnClient","intro","outro","confirm","log","cancel","mkdirSync","readFileSync","writeFileSync","join"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -29,10 +29,20 @@ interface ConfigAdapter {
|
|
|
29
29
|
uninstall?(): void;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
declare function handleLogin(
|
|
32
|
+
declare function handleLogin(_opts: Record<string, never>, adapter: ConfigAdapter): Promise<void>;
|
|
33
|
+
|
|
34
|
+
declare function handleAgentRegister(opts: {
|
|
33
35
|
name?: string;
|
|
34
36
|
}, adapter: ConfigAdapter): Promise<void>;
|
|
35
37
|
|
|
38
|
+
declare function handleAgentList(_opts: Record<string, never>, adapter: ConfigAdapter): Promise<void>;
|
|
39
|
+
|
|
40
|
+
declare function handleAgentSelect(opts: {
|
|
41
|
+
nameOrId: string;
|
|
42
|
+
}, adapter: ConfigAdapter): Promise<void>;
|
|
43
|
+
|
|
44
|
+
declare function handleLogout(_opts: Record<string, never>, adapter: ConfigAdapter): Promise<void>;
|
|
45
|
+
|
|
36
46
|
declare function handleConfig(opts: {
|
|
37
47
|
name?: string;
|
|
38
48
|
personality?: boolean;
|
|
@@ -46,4 +56,4 @@ declare function readJsonFile<T>(filePath: string): T | null;
|
|
|
46
56
|
declare function writeJsonFile(filePath: string, data: unknown): void;
|
|
47
57
|
declare function createDefaultAdapter(): ConfigAdapter;
|
|
48
58
|
|
|
49
|
-
export { type ConfigAdapter, type ServiceConfig, type StamnConfig, type StamnStatusFile, createDefaultAdapter, handleConfig, handleLogin, handleStatus, handleUninstall, readJsonFile, writeJsonFile };
|
|
59
|
+
export { type ConfigAdapter, type ServiceConfig, type StamnConfig, type StamnStatusFile, createDefaultAdapter, handleAgentList, handleAgentRegister, handleAgentSelect, handleConfig, handleLogin, handleLogout, handleStatus, handleUninstall, readJsonFile, writeJsonFile };
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createDefaultAdapter,
|
|
3
|
+
handleAgentList,
|
|
4
|
+
handleAgentRegister,
|
|
5
|
+
handleAgentSelect,
|
|
3
6
|
handleConfig,
|
|
4
7
|
handleLogin,
|
|
8
|
+
handleLogout,
|
|
5
9
|
handleStatus,
|
|
6
10
|
handleUninstall,
|
|
7
11
|
readJsonFile,
|
|
8
12
|
writeJsonFile
|
|
9
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ECKKSWUQ.js";
|
|
10
14
|
export {
|
|
11
15
|
createDefaultAdapter,
|
|
16
|
+
handleAgentList,
|
|
17
|
+
handleAgentRegister,
|
|
18
|
+
handleAgentSelect,
|
|
12
19
|
handleConfig,
|
|
13
20
|
handleLogin,
|
|
21
|
+
handleLogout,
|
|
14
22
|
handleStatus,
|
|
15
23
|
handleUninstall,
|
|
16
24
|
readJsonFile,
|
package/package.json
CHANGED
package/dist/chunk-7DSOXMQ6.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
// src/commands/login.ts
|
|
2
|
-
import { intro, outro, spinner, log, note, cancel, text } from "@clack/prompts";
|
|
3
|
-
import { StamnClient } from "@stamn/sdk";
|
|
4
|
-
async function handleLogin(opts, adapter) {
|
|
5
|
-
const client = new StamnClient();
|
|
6
|
-
intro("Stamn Device Login");
|
|
7
|
-
let name = opts.name;
|
|
8
|
-
if (!name) {
|
|
9
|
-
const input = await text({
|
|
10
|
-
message: "What should we call this agent?",
|
|
11
|
-
placeholder: "my-agent",
|
|
12
|
-
validate: (value) => {
|
|
13
|
-
if (!value?.trim()) return "Name is required.";
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
if (typeof input === "symbol") {
|
|
17
|
-
cancel("Login cancelled.");
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
name = input;
|
|
21
|
-
}
|
|
22
|
-
const s = spinner();
|
|
23
|
-
try {
|
|
24
|
-
s.start("Initiating device flow...");
|
|
25
|
-
const flow = await client.auth.initiateDeviceFlow();
|
|
26
|
-
s.stop("Device flow initiated.");
|
|
27
|
-
const label = (str) => str.padEnd(7);
|
|
28
|
-
note(
|
|
29
|
-
`${label("Open:")} ${flow.verificationUri}
|
|
30
|
-
${label("Code:")} ${flow.userCode}`,
|
|
31
|
-
"Authorize in your browser"
|
|
32
|
-
);
|
|
33
|
-
s.start("Waiting for approval...");
|
|
34
|
-
const apiKey = await client.auth.pollForApproval(flow.deviceCode);
|
|
35
|
-
s.stop("Approved!");
|
|
36
|
-
client.setApiKey(apiKey);
|
|
37
|
-
s.start("Registering agent...");
|
|
38
|
-
const participant = await client.participants.create({ name });
|
|
39
|
-
s.stop("Agent registered.");
|
|
40
|
-
adapter.writeConfig({
|
|
41
|
-
apiKey,
|
|
42
|
-
agentId: participant.id,
|
|
43
|
-
agentName: participant.name
|
|
44
|
-
});
|
|
45
|
-
log.success(`Agent "${participant.name}" (${participant.id})`);
|
|
46
|
-
log.info(`Config written to ${adapter.getConfigPath()}`);
|
|
47
|
-
outro("Done! You can now use stamn commands.");
|
|
48
|
-
} catch (err) {
|
|
49
|
-
s.stop("Failed.");
|
|
50
|
-
cancel(`Login failed: ${err.message}`);
|
|
51
|
-
process.exitCode = 1;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/commands/config.ts
|
|
56
|
-
import { execSync } from "child_process";
|
|
57
|
-
import { mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
58
|
-
import { join } from "path";
|
|
59
|
-
import { tmpdir } from "os";
|
|
60
|
-
import { log as log2 } from "@clack/prompts";
|
|
61
|
-
function openEditor(initial) {
|
|
62
|
-
const editor = process.env.EDITOR || process.env.VISUAL || "vi";
|
|
63
|
-
const tmpFile = join(tmpdir(), `stamn-personality-${Date.now()}.md`);
|
|
64
|
-
mkdirSync(tmpdir(), { recursive: true });
|
|
65
|
-
writeFileSync(tmpFile, initial, "utf-8");
|
|
66
|
-
try {
|
|
67
|
-
execSync(`${editor} "${tmpFile}"`, { stdio: "inherit" });
|
|
68
|
-
const result = readFileSync(tmpFile, "utf-8").trim();
|
|
69
|
-
return result || null;
|
|
70
|
-
} catch {
|
|
71
|
-
return null;
|
|
72
|
-
} finally {
|
|
73
|
-
try {
|
|
74
|
-
unlinkSync(tmpFile);
|
|
75
|
-
} catch {
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function handleConfig(opts, adapter) {
|
|
80
|
-
if (!opts.name && !opts.personality) {
|
|
81
|
-
const config = adapter.readConfig();
|
|
82
|
-
if (!config) {
|
|
83
|
-
log2.warn("No config found. Run `stamn agent login` first.");
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
log2.info(`Name: ${config.agentName ?? "(not set)"}`);
|
|
87
|
-
log2.info(`Personality: ${config.personality ? "configured" : "(not set)"}`);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
if (opts.name) {
|
|
91
|
-
adapter.writeConfig({ agentName: opts.name });
|
|
92
|
-
log2.success(`Name set: "${opts.name}"`);
|
|
93
|
-
}
|
|
94
|
-
if (opts.personality) {
|
|
95
|
-
const existing = adapter.readConfig()?.personality ?? "";
|
|
96
|
-
const text2 = openEditor(existing);
|
|
97
|
-
if (!text2) {
|
|
98
|
-
log2.warn("Editor closed without saving. Personality unchanged.");
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
adapter.writeConfig({ personality: text2 });
|
|
102
|
-
log2.success("Personality updated.");
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// src/commands/status.ts
|
|
107
|
-
import { intro as intro2, outro as outro2, log as log3 } from "@clack/prompts";
|
|
108
|
-
import { StamnClient as StamnClient2 } from "@stamn/sdk";
|
|
109
|
-
async function handleStatus(adapter) {
|
|
110
|
-
const config = adapter.readConfig();
|
|
111
|
-
const status = adapter.readStatusFile();
|
|
112
|
-
const label = (str) => str.padEnd(14);
|
|
113
|
-
intro2("Stamn Status");
|
|
114
|
-
log3.info(`${label("Agent ID:")} ${config?.agentId || "(not configured)"}`);
|
|
115
|
-
log3.info(
|
|
116
|
-
`${label("Agent Name:")} ${config?.agentName || "(not configured)"}`
|
|
117
|
-
);
|
|
118
|
-
log3.info(`${label("Connected:")} ${status?.connected ? "yes" : "no"}`);
|
|
119
|
-
if (status?.connected && status.connectedAt) {
|
|
120
|
-
log3.info(
|
|
121
|
-
`${label("Since:")} ${new Date(status.connectedAt).toLocaleString()}`
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
if (config?.apiKey) {
|
|
125
|
-
const client = new StamnClient2({ apiKey: config.apiKey });
|
|
126
|
-
const health = await client.health.check();
|
|
127
|
-
log3.info(`${label("Server:")} ${health.ok ? "healthy" : "unhealthy"}`);
|
|
128
|
-
}
|
|
129
|
-
outro2("");
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// src/commands/uninstall.ts
|
|
133
|
-
import { intro as intro3, outro as outro3, confirm, log as log4, cancel as cancel2 } from "@clack/prompts";
|
|
134
|
-
async function handleUninstall(adapter) {
|
|
135
|
-
intro3("Stamn Uninstall");
|
|
136
|
-
const shouldContinue = await confirm({
|
|
137
|
-
message: "This will remove all Stamn config and data. Continue?"
|
|
138
|
-
});
|
|
139
|
-
if (!shouldContinue || typeof shouldContinue === "symbol") {
|
|
140
|
-
cancel2("Uninstall cancelled.");
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
adapter.uninstall?.();
|
|
145
|
-
log4.success("Removed Stamn config");
|
|
146
|
-
outro3("Stamn config removed.");
|
|
147
|
-
} catch (err) {
|
|
148
|
-
cancel2(`Failed to remove config: ${err.message}`);
|
|
149
|
-
process.exitCode = 1;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// src/config.ts
|
|
154
|
-
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
155
|
-
import { dirname, join as join2 } from "path";
|
|
156
|
-
import { homedir } from "os";
|
|
157
|
-
function readJsonFile(filePath) {
|
|
158
|
-
try {
|
|
159
|
-
const raw = readFileSync2(filePath, "utf-8");
|
|
160
|
-
return JSON.parse(raw);
|
|
161
|
-
} catch {
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
function writeJsonFile(filePath, data) {
|
|
166
|
-
mkdirSync2(dirname(filePath), { recursive: true });
|
|
167
|
-
writeFileSync2(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
168
|
-
}
|
|
169
|
-
function getConfigPath() {
|
|
170
|
-
return join2(homedir(), ".stamn", "config.json");
|
|
171
|
-
}
|
|
172
|
-
function readConfig() {
|
|
173
|
-
return readJsonFile(getConfigPath());
|
|
174
|
-
}
|
|
175
|
-
function writeConfig(updates) {
|
|
176
|
-
const existing = readConfig() ?? {};
|
|
177
|
-
writeJsonFile(getConfigPath(), { ...existing, ...updates });
|
|
178
|
-
}
|
|
179
|
-
function readStatusFile() {
|
|
180
|
-
return readJsonFile(join2(homedir(), ".stamn", "status.json"));
|
|
181
|
-
}
|
|
182
|
-
function createDefaultAdapter() {
|
|
183
|
-
return {
|
|
184
|
-
readConfig,
|
|
185
|
-
writeConfig,
|
|
186
|
-
readStatusFile,
|
|
187
|
-
getConfigPath,
|
|
188
|
-
uninstall() {
|
|
189
|
-
const configDir = dirname(getConfigPath());
|
|
190
|
-
if (existsSync(configDir)) {
|
|
191
|
-
rmSync(configDir, { recursive: true, force: true });
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export {
|
|
198
|
-
handleLogin,
|
|
199
|
-
handleConfig,
|
|
200
|
-
handleStatus,
|
|
201
|
-
handleUninstall,
|
|
202
|
-
readJsonFile,
|
|
203
|
-
writeJsonFile,
|
|
204
|
-
createDefaultAdapter
|
|
205
|
-
};
|
|
206
|
-
//# sourceMappingURL=chunk-7DSOXMQ6.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/login.ts","../src/commands/config.ts","../src/commands/status.ts","../src/commands/uninstall.ts","../src/config.ts"],"sourcesContent":["import { intro, outro, spinner, log, note, cancel, text } from \"@clack/prompts\";\nimport { StamnClient } from \"@stamn/sdk\";\nimport type { ConfigAdapter } from \"@/types\";\n\nexport async function handleLogin(\n opts: { name?: string },\n adapter: ConfigAdapter,\n): Promise<void> {\n const client = new StamnClient();\n\n intro(\"Stamn Device Login\");\n\n let name = opts.name;\n if (!name) {\n const input = await text({\n message: \"What should we call this agent?\",\n placeholder: \"my-agent\",\n validate: (value) => {\n if (!value?.trim()) return \"Name is required.\";\n },\n });\n if (typeof input === \"symbol\") {\n cancel(\"Login cancelled.\");\n return;\n }\n name = input;\n }\n\n const s = spinner();\n\n try {\n s.start(\"Initiating device flow...\");\n const flow = await client.auth.initiateDeviceFlow();\n s.stop(\"Device flow initiated.\");\n\n const label = (str: string) => str.padEnd(7);\n note(\n `${label(\"Open:\")} ${flow.verificationUri}\\n${label(\"Code:\")} ${flow.userCode}`,\n \"Authorize in your browser\",\n );\n\n s.start(\"Waiting for approval...\");\n const apiKey = await client.auth.pollForApproval(flow.deviceCode);\n s.stop(\"Approved!\");\n\n client.setApiKey(apiKey);\n\n s.start(\"Registering agent...\");\n const participant = await client.participants.create({ name });\n s.stop(\"Agent registered.\");\n\n adapter.writeConfig({\n apiKey,\n agentId: participant.id,\n agentName: participant.name,\n });\n\n log.success(`Agent \"${participant.name}\" (${participant.id})`);\n log.info(`Config written to ${adapter.getConfigPath()}`);\n\n outro(\"Done! You can now use stamn commands.\");\n } catch (err) {\n s.stop(\"Failed.\");\n cancel(`Login failed: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n}\n","import { execSync } from \"child_process\";\nimport { mkdirSync, readFileSync, writeFileSync, unlinkSync } from \"fs\";\nimport { join } from \"path\";\nimport { tmpdir } from \"os\";\nimport { log } from \"@clack/prompts\";\nimport type { ConfigAdapter } from \"@/types\";\n\nfunction openEditor(initial: string): string | null {\n const editor = process.env.EDITOR || process.env.VISUAL || \"vi\";\n const tmpFile = join(tmpdir(), `stamn-personality-${Date.now()}.md`);\n\n mkdirSync(tmpdir(), { recursive: true });\n writeFileSync(tmpFile, initial, \"utf-8\");\n\n try {\n execSync(`${editor} \"${tmpFile}\"`, { stdio: \"inherit\" });\n const result = readFileSync(tmpFile, \"utf-8\").trim();\n return result || null;\n } catch {\n return null;\n } finally {\n try {\n unlinkSync(tmpFile);\n } catch {}\n }\n}\n\nexport function handleConfig(\n opts: { name?: string; personality?: boolean },\n adapter: ConfigAdapter,\n): void {\n if (!opts.name && !opts.personality) {\n const config = adapter.readConfig();\n if (!config) {\n log.warn(\"No config found. Run `stamn agent login` first.\");\n return;\n }\n log.info(`Name: ${config.agentName ?? \"(not set)\"}`);\n log.info(`Personality: ${config.personality ? \"configured\" : \"(not set)\"}`);\n return;\n }\n\n if (opts.name) {\n adapter.writeConfig({ agentName: opts.name });\n log.success(`Name set: \"${opts.name}\"`);\n }\n\n if (opts.personality) {\n const existing = adapter.readConfig()?.personality ?? \"\";\n const text = openEditor(existing);\n if (!text) {\n log.warn(\"Editor closed without saving. Personality unchanged.\");\n return;\n }\n adapter.writeConfig({ personality: text });\n log.success(\"Personality updated.\");\n }\n}\n","import { intro, outro, log } from \"@clack/prompts\";\nimport { StamnClient } from \"@stamn/sdk\";\nimport type { StamnConfig, ConfigAdapter } from \"@/types\";\n\nexport async function handleStatus(adapter: ConfigAdapter): Promise<void> {\n const config = adapter.readConfig();\n const status = adapter.readStatusFile();\n const label = (str: string) => str.padEnd(14);\n\n intro(\"Stamn Status\");\n\n log.info(`${label(\"Agent ID:\")} ${config?.agentId || \"(not configured)\"}`);\n log.info(\n `${label(\"Agent Name:\")} ${config?.agentName || \"(not configured)\"}`,\n );\n log.info(`${label(\"Connected:\")} ${status?.connected ? \"yes\" : \"no\"}`);\n\n if (status?.connected && status.connectedAt) {\n log.info(\n `${label(\"Since:\")} ${new Date(status.connectedAt).toLocaleString()}`,\n );\n }\n\n if (config?.apiKey) {\n const client = new StamnClient({ apiKey: config.apiKey });\n const health = await client.health.check();\n log.info(`${label(\"Server:\")} ${health.ok ? \"healthy\" : \"unhealthy\"}`);\n }\n\n outro(\"\");\n}\n","import { intro, outro, confirm, log, cancel } from \"@clack/prompts\";\nimport type { ConfigAdapter } from \"@/types\";\n\nexport async function handleUninstall(adapter: ConfigAdapter): Promise<void> {\n intro(\"Stamn Uninstall\");\n\n const shouldContinue = await confirm({\n message: \"This will remove all Stamn config and data. Continue?\",\n });\n\n if (!shouldContinue || typeof shouldContinue === \"symbol\") {\n cancel(\"Uninstall cancelled.\");\n return;\n }\n\n try {\n adapter.uninstall?.();\n log.success(\"Removed Stamn config\");\n outro(\"Stamn config removed.\");\n } catch (err) {\n cancel(`Failed to remove config: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n}\n","import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { homedir } from \"os\";\nimport type { StamnConfig, StamnStatusFile, ConfigAdapter } from \"@/types\";\n\nexport function readJsonFile<T>(filePath: string): T | null {\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\nexport function writeJsonFile(filePath: string, data: unknown): void {\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(data, null, 2) + \"\\n\", \"utf-8\");\n}\n\nexport function getConfigPath(): string {\n return join(homedir(), \".stamn\", \"config.json\");\n}\n\nexport function readConfig(): StamnConfig | null {\n return readJsonFile<StamnConfig>(getConfigPath());\n}\n\nexport function writeConfig(updates: Partial<StamnConfig>): void {\n const existing = readConfig() ?? {};\n writeJsonFile(getConfigPath(), { ...existing, ...updates });\n}\n\nexport function readStatusFile(): StamnStatusFile | null {\n return readJsonFile<StamnStatusFile>(join(homedir(), \".stamn\", \"status.json\"));\n}\n\nexport function createDefaultAdapter(): ConfigAdapter {\n return {\n readConfig,\n writeConfig,\n readStatusFile,\n getConfigPath,\n uninstall() {\n const configDir = dirname(getConfigPath());\n if (existsSync(configDir)) {\n rmSync(configDir, { recursive: true, force: true });\n }\n },\n };\n}\n"],"mappings":"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","names":["log","text","intro","outro","log","StamnClient","intro","outro","log","cancel","mkdirSync","readFileSync","writeFileSync","join"]}
|