@stamn/agent 0.6.0 → 0.8.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.
@@ -266,7 +266,7 @@ var WSClient = class {
266
266
  const payload = {
267
267
  agentId: this.options.config.agentId,
268
268
  status,
269
- version: "0.6.0",
269
+ version: "0.8.0",
270
270
  platform: `${process.platform}-${process.arch}`,
271
271
  nodeVersion: process.versions.node
272
272
  };
@@ -373,4 +373,4 @@ export {
373
373
  WSClient,
374
374
  SpendClient
375
375
  };
376
- //# sourceMappingURL=chunk-DJ3HR5OC.js.map
376
+ //# sourceMappingURL=chunk-6EKA3TV7.js.map
@@ -0,0 +1,8 @@
1
+ import { Command } from '@oclif/core';
2
+
3
+ declare class Login extends Command {
4
+ static description: string;
5
+ run(): Promise<void>;
6
+ }
7
+
8
+ export { Login as default };
@@ -0,0 +1,34 @@
1
+ import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+ import {
3
+ ConfigStore
4
+ } from "../chunk-KQC5O25P.js";
5
+ import "../chunk-JVIBUEVN.js";
6
+
7
+ // src/commands/login.ts
8
+ import { Command } from "@oclif/core";
9
+ var Login = class extends Command {
10
+ static description = "Log in to Stamn via the dashboard (device code flow)";
11
+ async run() {
12
+ if (!process.stdout.isTTY) {
13
+ this.error(
14
+ "Interactive login requires a terminal. Use `stamn start` with an existing config."
15
+ );
16
+ }
17
+ const { runDeviceLogin } = await import("../ui/device-login.js");
18
+ try {
19
+ const result = await runDeviceLogin();
20
+ const store = new ConfigStore();
21
+ store.set("apiKey", result.apiKey);
22
+ store.set("agentId", result.agentId);
23
+ store.set("agentName", result.agentName);
24
+ this.log(`
25
+ Agent "${result.agentName}" ready. Run \`stamn start\` to connect.`);
26
+ } catch (err) {
27
+ this.error(err.message || "Login cancelled.");
28
+ }
29
+ }
30
+ };
31
+ export {
32
+ Login as default
33
+ };
34
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commands/login.ts"],"sourcesContent":["import { Command } from '@oclif/core';\nimport { ConfigStore } from '../config/config-store.js';\n\nexport default class Login extends Command {\n static override description =\n 'Log in to Stamn via the dashboard (device code flow)';\n\n async run(): Promise<void> {\n if (!process.stdout.isTTY) {\n this.error(\n 'Interactive login requires a terminal. Use `stamn start` with an existing config.',\n );\n }\n\n const { runDeviceLogin } = await import('../ui/device-login.js');\n\n try {\n const result = await runDeviceLogin();\n const store = new ConfigStore();\n store.set('apiKey', result.apiKey);\n store.set('agentId', result.agentId);\n store.set('agentName', result.agentName);\n this.log(`\\nAgent \"${result.agentName}\" ready. Run \\`stamn start\\` to connect.`);\n } catch (err) {\n this.error((err as Error).message || 'Login cancelled.');\n }\n }\n}\n"],"mappings":";;;;;;;AAAA,SAAS,eAAe;AAGxB,IAAqB,QAArB,cAAmC,QAAQ;AAAA,EACzC,OAAgB,cACd;AAAA,EAEF,MAAM,MAAqB;AACzB,QAAI,CAAC,QAAQ,OAAO,OAAO;AACzB,WAAK;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,UAAM,EAAE,eAAe,IAAI,MAAM,OAAO,uBAAuB;AAE/D,QAAI;AACF,YAAM,SAAS,MAAM,eAAe;AACpC,YAAM,QAAQ,IAAI,YAAY;AAC9B,YAAM,IAAI,UAAU,OAAO,MAAM;AACjC,YAAM,IAAI,WAAW,OAAO,OAAO;AACnC,YAAM,IAAI,aAAa,OAAO,SAAS;AACvC,WAAK,IAAI;AAAA,SAAY,OAAO,SAAS,0CAA0C;AAAA,IACjF,SAAS,KAAK;AACZ,WAAK,MAAO,IAAc,WAAW,kBAAkB;AAAA,IACzD;AAAA,EACF;AACF;","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  SpendClient,
4
4
  WSClient,
5
5
  createLogger
6
- } from "../chunk-DJ3HR5OC.js";
6
+ } from "../chunk-6EKA3TV7.js";
7
7
  import {
8
8
  ConfigStore
9
9
  } from "../chunk-KQC5O25P.js";
@@ -6,7 +6,7 @@ import {
6
6
  SpendClient,
7
7
  WSClient,
8
8
  createLogger
9
- } from "../chunk-DJ3HR5OC.js";
9
+ } from "../chunk-6EKA3TV7.js";
10
10
  import {
11
11
  ConfigStore
12
12
  } from "../chunk-KQC5O25P.js";
@@ -38,19 +38,19 @@ var Start = class _Start extends Command {
38
38
  if (!config.apiKey || !config.agentId) {
39
39
  if (flags.daemon || !process.stdout.isTTY) {
40
40
  this.error(
41
- "Not registered. Run `stamn start` interactively first."
41
+ "Not registered. Run `stamn login` interactively first."
42
42
  );
43
43
  }
44
- const { runSetup } = await import("../ui/setup.js");
44
+ const { runDeviceLogin } = await import("../ui/device-login.js");
45
45
  try {
46
- const result = await runSetup();
46
+ const result = await runDeviceLogin();
47
47
  configStore.set("apiKey", result.apiKey);
48
48
  configStore.set("agentId", result.agentId);
49
49
  configStore.set("agentName", result.agentName);
50
50
  config.apiKey = result.apiKey;
51
51
  config.agentId = result.agentId;
52
- } catch {
53
- this.error("Setup cancelled.");
52
+ } catch (err) {
53
+ this.error(err.message || "Login cancelled.");
54
54
  }
55
55
  }
56
56
  const dm = new DaemonManager();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/start.ts"],"sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport { ConfigStore } from '../config/config-store.js';\nimport { SERVER_URL, type AgentConfig } from '../config/config-schema.js';\nimport { createLogger } from '../logging/logger.js';\nimport { WSClient } from '../ws/ws-client.js';\nimport { SpendClient } from '../spend/spend-client.js';\nimport { DaemonManager } from '../daemon/daemon-manager.js';\n\nexport default class Start extends Command {\n static override description = 'Start the Stamn agent daemon';\n\n static override flags = {\n daemon: Flags.boolean({\n char: 'd',\n description: 'Run as background daemon',\n default: false,\n }),\n 'log-level': Flags.string({\n description: 'Override log level',\n options: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'],\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Start);\n const configStore = new ConfigStore();\n const config = { ...configStore.getAll() };\n\n // Apply flag overrides\n if (flags['log-level'])\n config.logLevel = flags['log-level'] as AgentConfig['logLevel'];\n\n // Interactive setup when not registered\n if (!config.apiKey || !config.agentId) {\n if (flags.daemon || !process.stdout.isTTY) {\n this.error(\n 'Not registered. Run `stamn start` interactively first.',\n );\n }\n\n const { runSetup } = await import('../ui/setup.js');\n try {\n const result = await runSetup();\n configStore.set('apiKey', result.apiKey);\n configStore.set('agentId', result.agentId);\n configStore.set('agentName', result.agentName);\n config.apiKey = result.apiKey;\n config.agentId = result.agentId;\n } catch {\n this.error('Setup cancelled.');\n }\n }\n\n // Check for existing daemon\n const dm = new DaemonManager();\n const { running, pid } = dm.isRunning();\n if (running) {\n this.error(`Daemon already running (PID ${pid})`);\n }\n\n // Daemonize if requested\n if (flags.daemon) {\n const { daemonizeProcess } = await import('../daemon/process.js');\n await daemonizeProcess();\n }\n\n // Write PID\n dm.writePid(process.pid);\n\n const logger = createLogger(config);\n logger.info(\n { agentId: config.agentId, server: SERVER_URL },\n 'Starting Stamn agent',\n );\n\n // Create WebSocket client\n const client = new WSClient({\n config,\n logger,\n onCommand: (command, params) => {\n logger.info({ command, params }, 'Received command');\n if (command === 'shutdown') {\n shutdown();\n }\n },\n onDisconnect: () => {\n logger.warn('Disconnected from server');\n },\n onConnected: () => {\n logger.info('Agent is online and ready — spend capability active');\n },\n });\n\n // Create spend client — available for plugin/task integration\n const spendClient = new SpendClient(client, logger);\n\n // Expose on process for external plugin access\n (globalThis as Record<string, unknown>).__stamnSpendClient = spendClient;\n\n // Graceful shutdown\n const shutdown = () => {\n logger.info('Shutting down...');\n client.disconnect();\n dm.removePid();\n process.exit(0);\n };\n\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n\n // Connect\n client.connect();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,SAAS,SAAS,aAAa;AAQ/B,IAAqB,QAArB,MAAqB,eAAc,QAAQ;AAAA,EACzC,OAAgB,cAAc;AAAA,EAE9B,OAAgB,QAAQ;AAAA,IACtB,QAAQ,MAAM,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,aAAa,MAAM,OAAO;AAAA,MACxB,aAAa;AAAA,MACb,SAAS,CAAC,SAAS,SAAS,QAAQ,QAAQ,SAAS,OAAO;AAAA,IAC9D,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,MAAK;AACxC,UAAM,cAAc,IAAI,YAAY;AACpC,UAAM,SAAS,EAAE,GAAG,YAAY,OAAO,EAAE;AAGzC,QAAI,MAAM,WAAW;AACnB,aAAO,WAAW,MAAM,WAAW;AAGrC,QAAI,CAAC,OAAO,UAAU,CAAC,OAAO,SAAS;AACrC,UAAI,MAAM,UAAU,CAAC,QAAQ,OAAO,OAAO;AACzC,aAAK;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,YAAM,EAAE,SAAS,IAAI,MAAM,OAAO,gBAAgB;AAClD,UAAI;AACF,cAAM,SAAS,MAAM,SAAS;AAC9B,oBAAY,IAAI,UAAU,OAAO,MAAM;AACvC,oBAAY,IAAI,WAAW,OAAO,OAAO;AACzC,oBAAY,IAAI,aAAa,OAAO,SAAS;AAC7C,eAAO,SAAS,OAAO;AACvB,eAAO,UAAU,OAAO;AAAA,MAC1B,QAAQ;AACN,aAAK,MAAM,kBAAkB;AAAA,MAC/B;AAAA,IACF;AAGA,UAAM,KAAK,IAAI,cAAc;AAC7B,UAAM,EAAE,SAAS,IAAI,IAAI,GAAG,UAAU;AACtC,QAAI,SAAS;AACX,WAAK,MAAM,+BAA+B,GAAG,GAAG;AAAA,IAClD;AAGA,QAAI,MAAM,QAAQ;AAChB,YAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,wBAAsB;AAChE,YAAM,iBAAiB;AAAA,IACzB;AAGA,OAAG,SAAS,QAAQ,GAAG;AAEvB,UAAM,SAAS,aAAa,MAAM;AAClC,WAAO;AAAA,MACL,EAAE,SAAS,OAAO,SAAS,QAAQ,WAAW;AAAA,MAC9C;AAAA,IACF;AAGA,UAAM,SAAS,IAAI,SAAS;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,WAAW,CAAC,SAAS,WAAW;AAC9B,eAAO,KAAK,EAAE,SAAS,OAAO,GAAG,kBAAkB;AACnD,YAAI,YAAY,YAAY;AAC1B,mBAAS;AAAA,QACX;AAAA,MACF;AAAA,MACA,cAAc,MAAM;AAClB,eAAO,KAAK,0BAA0B;AAAA,MACxC;AAAA,MACA,aAAa,MAAM;AACjB,eAAO,KAAK,0DAAqD;AAAA,MACnE;AAAA,IACF,CAAC;AAGD,UAAM,cAAc,IAAI,YAAY,QAAQ,MAAM;AAGlD,IAAC,WAAuC,qBAAqB;AAG7D,UAAM,WAAW,MAAM;AACrB,aAAO,KAAK,kBAAkB;AAC9B,aAAO,WAAW;AAClB,SAAG,UAAU;AACb,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,YAAQ,GAAG,WAAW,QAAQ;AAC9B,YAAQ,GAAG,UAAU,QAAQ;AAG7B,WAAO,QAAQ;AAAA,EACjB;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/commands/start.ts"],"sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport { ConfigStore } from '../config/config-store.js';\nimport { SERVER_URL, type AgentConfig } from '../config/config-schema.js';\nimport { createLogger } from '../logging/logger.js';\nimport { WSClient } from '../ws/ws-client.js';\nimport { SpendClient } from '../spend/spend-client.js';\nimport { DaemonManager } from '../daemon/daemon-manager.js';\n\nexport default class Start extends Command {\n static override description = 'Start the Stamn agent daemon';\n\n static override flags = {\n daemon: Flags.boolean({\n char: 'd',\n description: 'Run as background daemon',\n default: false,\n }),\n 'log-level': Flags.string({\n description: 'Override log level',\n options: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'],\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Start);\n const configStore = new ConfigStore();\n const config = { ...configStore.getAll() };\n\n // Apply flag overrides\n if (flags['log-level'])\n config.logLevel = flags['log-level'] as AgentConfig['logLevel'];\n\n // Interactive login when not registered\n if (!config.apiKey || !config.agentId) {\n if (flags.daemon || !process.stdout.isTTY) {\n this.error(\n 'Not registered. Run `stamn login` interactively first.',\n );\n }\n\n const { runDeviceLogin } = await import('../ui/device-login.js');\n try {\n const result = await runDeviceLogin();\n configStore.set('apiKey', result.apiKey);\n configStore.set('agentId', result.agentId);\n configStore.set('agentName', result.agentName);\n config.apiKey = result.apiKey;\n config.agentId = result.agentId;\n } catch (err) {\n this.error((err as Error).message || 'Login cancelled.');\n }\n }\n\n // Check for existing daemon\n const dm = new DaemonManager();\n const { running, pid } = dm.isRunning();\n if (running) {\n this.error(`Daemon already running (PID ${pid})`);\n }\n\n // Daemonize if requested\n if (flags.daemon) {\n const { daemonizeProcess } = await import('../daemon/process.js');\n await daemonizeProcess();\n }\n\n // Write PID\n dm.writePid(process.pid);\n\n const logger = createLogger(config);\n logger.info(\n { agentId: config.agentId, server: SERVER_URL },\n 'Starting Stamn agent',\n );\n\n // Create WebSocket client\n const client = new WSClient({\n config,\n logger,\n onCommand: (command, params) => {\n logger.info({ command, params }, 'Received command');\n if (command === 'shutdown') {\n shutdown();\n }\n },\n onDisconnect: () => {\n logger.warn('Disconnected from server');\n },\n onConnected: () => {\n logger.info('Agent is online and ready — spend capability active');\n },\n });\n\n // Create spend client — available for plugin/task integration\n const spendClient = new SpendClient(client, logger);\n\n // Expose on process for external plugin access\n (globalThis as Record<string, unknown>).__stamnSpendClient = spendClient;\n\n // Graceful shutdown\n const shutdown = () => {\n logger.info('Shutting down...');\n client.disconnect();\n dm.removePid();\n process.exit(0);\n };\n\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n\n // Connect\n client.connect();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,SAAS,SAAS,aAAa;AAQ/B,IAAqB,QAArB,MAAqB,eAAc,QAAQ;AAAA,EACzC,OAAgB,cAAc;AAAA,EAE9B,OAAgB,QAAQ;AAAA,IACtB,QAAQ,MAAM,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,aAAa,MAAM,OAAO;AAAA,MACxB,aAAa;AAAA,MACb,SAAS,CAAC,SAAS,SAAS,QAAQ,QAAQ,SAAS,OAAO;AAAA,IAC9D,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,MAAK;AACxC,UAAM,cAAc,IAAI,YAAY;AACpC,UAAM,SAAS,EAAE,GAAG,YAAY,OAAO,EAAE;AAGzC,QAAI,MAAM,WAAW;AACnB,aAAO,WAAW,MAAM,WAAW;AAGrC,QAAI,CAAC,OAAO,UAAU,CAAC,OAAO,SAAS;AACrC,UAAI,MAAM,UAAU,CAAC,QAAQ,OAAO,OAAO;AACzC,aAAK;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,YAAM,EAAE,eAAe,IAAI,MAAM,OAAO,uBAAuB;AAC/D,UAAI;AACF,cAAM,SAAS,MAAM,eAAe;AACpC,oBAAY,IAAI,UAAU,OAAO,MAAM;AACvC,oBAAY,IAAI,WAAW,OAAO,OAAO;AACzC,oBAAY,IAAI,aAAa,OAAO,SAAS;AAC7C,eAAO,SAAS,OAAO;AACvB,eAAO,UAAU,OAAO;AAAA,MAC1B,SAAS,KAAK;AACZ,aAAK,MAAO,IAAc,WAAW,kBAAkB;AAAA,MACzD;AAAA,IACF;AAGA,UAAM,KAAK,IAAI,cAAc;AAC7B,UAAM,EAAE,SAAS,IAAI,IAAI,GAAG,UAAU;AACtC,QAAI,SAAS;AACX,WAAK,MAAM,+BAA+B,GAAG,GAAG;AAAA,IAClD;AAGA,QAAI,MAAM,QAAQ;AAChB,YAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,wBAAsB;AAChE,YAAM,iBAAiB;AAAA,IACzB;AAGA,OAAG,SAAS,QAAQ,GAAG;AAEvB,UAAM,SAAS,aAAa,MAAM;AAClC,WAAO;AAAA,MACL,EAAE,SAAS,OAAO,SAAS,QAAQ,WAAW;AAAA,MAC9C;AAAA,IACF;AAGA,UAAM,SAAS,IAAI,SAAS;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,WAAW,CAAC,SAAS,WAAW;AAC9B,eAAO,KAAK,EAAE,SAAS,OAAO,GAAG,kBAAkB;AACnD,YAAI,YAAY,YAAY;AAC1B,mBAAS;AAAA,QACX;AAAA,MACF;AAAA,MACA,cAAc,MAAM;AAClB,eAAO,KAAK,0BAA0B;AAAA,MACxC;AAAA,MACA,aAAa,MAAM;AACjB,eAAO,KAAK,0DAAqD;AAAA,MACnE;AAAA,IACF,CAAC;AAGD,UAAM,cAAc,IAAI,YAAY,QAAQ,MAAM;AAGlD,IAAC,WAAuC,qBAAqB;AAG7D,UAAM,WAAW,MAAM;AACrB,aAAO,KAAK,kBAAkB;AAC9B,aAAO,WAAW;AAClB,SAAG,UAAU;AACb,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,YAAQ,GAAG,WAAW,QAAQ;AAC9B,YAAQ,GAAG,UAAU,QAAQ;AAG7B,WAAO,QAAQ;AAAA,EACjB;AACF;","names":[]}
@@ -0,0 +1,8 @@
1
+ import { Command } from '@oclif/core';
2
+
3
+ declare class Uninstall extends Command {
4
+ static description: string;
5
+ run(): Promise<void>;
6
+ }
7
+
8
+ export { Uninstall as default };
@@ -0,0 +1,33 @@
1
+ import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+ import {
3
+ DaemonManager
4
+ } from "../chunk-DCE6ICKM.js";
5
+ import {
6
+ ConfigStore
7
+ } from "../chunk-KQC5O25P.js";
8
+ import "../chunk-JVIBUEVN.js";
9
+
10
+ // src/commands/uninstall.ts
11
+ import { Command } from "@oclif/core";
12
+ import { execSync } from "child_process";
13
+ var Uninstall = class extends Command {
14
+ static description = "Uninstall the Stamn agent";
15
+ async run() {
16
+ const dm = new DaemonManager();
17
+ const { running } = dm.isRunning();
18
+ if (running) {
19
+ this.log("Stopping daemon...");
20
+ dm.stop();
21
+ }
22
+ this.log("Removing config...");
23
+ const store = new ConfigStore();
24
+ store.clear();
25
+ this.log("Uninstalling...");
26
+ execSync("npm rm -g @stamn/agent", { stdio: "inherit" });
27
+ this.log("Done.");
28
+ }
29
+ };
30
+ export {
31
+ Uninstall as default
32
+ };
33
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commands/uninstall.ts"],"sourcesContent":["import { Command } from '@oclif/core';\nimport { execSync } from 'child_process';\nimport { ConfigStore } from '../config/config-store.js';\nimport { DaemonManager } from '../daemon/daemon-manager.js';\n\nexport default class Uninstall extends Command {\n static override description = 'Uninstall the Stamn agent';\n\n async run(): Promise<void> {\n const dm = new DaemonManager();\n const { running } = dm.isRunning();\n\n if (running) {\n this.log('Stopping daemon...');\n dm.stop();\n }\n\n this.log('Removing config...');\n const store = new ConfigStore();\n store.clear();\n\n this.log('Uninstalling...');\n execSync('npm rm -g @stamn/agent', { stdio: 'inherit' });\n\n this.log('Done.');\n }\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,eAAe;AACxB,SAAS,gBAAgB;AAIzB,IAAqB,YAArB,cAAuC,QAAQ;AAAA,EAC7C,OAAgB,cAAc;AAAA,EAE9B,MAAM,MAAqB;AACzB,UAAM,KAAK,IAAI,cAAc;AAC7B,UAAM,EAAE,QAAQ,IAAI,GAAG,UAAU;AAEjC,QAAI,SAAS;AACX,WAAK,IAAI,oBAAoB;AAC7B,SAAG,KAAK;AAAA,IACV;AAEA,SAAK,IAAI,oBAAoB;AAC7B,UAAM,QAAQ,IAAI,YAAY;AAC9B,UAAM,MAAM;AAEZ,SAAK,IAAI,iBAAiB;AAC1B,aAAS,0BAA0B,EAAE,OAAO,UAAU,CAAC;AAEvD,SAAK,IAAI,OAAO;AAAA,EAClB;AACF;","names":[]}
@@ -6,13 +6,13 @@ import { execSync } from "child_process";
6
6
  var Update = class extends Command {
7
7
  static description = "Update the Stamn agent to the latest version";
8
8
  async run() {
9
- this.log(`Current version: ${"0.6.0"}`);
9
+ this.log(`Current version: ${"0.8.0"}`);
10
10
  this.log("Checking for updates...");
11
11
  try {
12
12
  const latest = execSync("npm view @stamn/agent version", {
13
13
  encoding: "utf-8"
14
14
  }).trim();
15
- if (latest === "0.6.0") {
15
+ if (latest === "0.8.0") {
16
16
  this.log("Already on the latest version.");
17
17
  return;
18
18
  }
@@ -0,0 +1,8 @@
1
+ interface LoginResult {
2
+ agentId: string;
3
+ apiKey: string;
4
+ agentName: string;
5
+ }
6
+ declare function runDeviceLogin(): Promise<LoginResult>;
7
+
8
+ export { type LoginResult, runDeviceLogin };
@@ -0,0 +1,153 @@
1
+ import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+
3
+ // src/ui/device-login.tsx
4
+ import { render } from "ink";
5
+
6
+ // src/ui/components/device-login-wizard.tsx
7
+ import { useState, useEffect } from "react";
8
+ import { Box, Text } from "ink";
9
+ import { Spinner, StatusMessage } from "@inkjs/ui";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ var POLL_INTERVAL_MS = 5e3;
12
+ function DeviceLoginWizard({ onComplete, onError }) {
13
+ const [step, setStep] = useState("requesting");
14
+ const [flow, setFlow] = useState(null);
15
+ useEffect(() => {
16
+ let cancelled = false;
17
+ const initiate = async () => {
18
+ try {
19
+ const { SERVER_URL } = await import("../config-schema-BR4LGISX.js");
20
+ const res = await fetch(`${SERVER_URL}/v1/auth/device-codes`, {
21
+ method: "POST"
22
+ });
23
+ if (!res.ok) {
24
+ const body = await res.text();
25
+ throw new Error(body || `HTTP ${res.status}`);
26
+ }
27
+ const json = await res.json();
28
+ if (!cancelled) {
29
+ setFlow(json.data);
30
+ setStep("waiting");
31
+ }
32
+ } catch (err) {
33
+ if (cancelled) return;
34
+ const msg = err.message;
35
+ if (msg === "fetch failed" || msg.includes("ECONNREFUSED") || msg.includes("ENOTFOUND")) {
36
+ onError("Could not connect to Stamn. Check your network.");
37
+ } else {
38
+ onError(msg);
39
+ }
40
+ }
41
+ };
42
+ initiate();
43
+ return () => {
44
+ cancelled = true;
45
+ };
46
+ }, []);
47
+ useEffect(() => {
48
+ if (step !== "waiting" || !flow) return;
49
+ let cancelled = false;
50
+ const poll = async () => {
51
+ try {
52
+ const { SERVER_URL } = await import("../config-schema-BR4LGISX.js");
53
+ const res = await fetch(
54
+ `${SERVER_URL}/v1/auth/device-codes/${flow.deviceCode}`
55
+ );
56
+ if (!res.ok) return;
57
+ const json = await res.json();
58
+ if (cancelled) return;
59
+ if (json.data.status === "approved" && json.data.apiKey) {
60
+ setStep("registering");
61
+ await registerAgent(json.data.apiKey);
62
+ } else if (json.data.status === "expired") {
63
+ onError("Login code expired. Run `stamn login` again.");
64
+ }
65
+ } catch {
66
+ }
67
+ };
68
+ const interval = setInterval(poll, POLL_INTERVAL_MS);
69
+ poll();
70
+ return () => {
71
+ cancelled = true;
72
+ clearInterval(interval);
73
+ };
74
+ }, [step, flow]);
75
+ const registerAgent = async (apiKey) => {
76
+ try {
77
+ const { SERVER_URL } = await import("../config-schema-BR4LGISX.js");
78
+ const res = await fetch(`${SERVER_URL}/v1/agents/register`, {
79
+ method: "POST",
80
+ headers: {
81
+ "Content-Type": "application/json",
82
+ Authorization: `Bearer ${apiKey}`
83
+ },
84
+ body: JSON.stringify({
85
+ platform: `${process.platform}-${process.arch}`
86
+ })
87
+ });
88
+ if (!res.ok) {
89
+ const body = await res.text();
90
+ throw new Error(body || `HTTP ${res.status}`);
91
+ }
92
+ const json = await res.json();
93
+ setStep("done");
94
+ onComplete({
95
+ agentId: json.data.id,
96
+ apiKey,
97
+ agentName: json.data.name
98
+ });
99
+ } catch (err) {
100
+ onError(err.message || "Registration failed");
101
+ }
102
+ };
103
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
104
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
105
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "stamn" }),
106
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " login" })
107
+ ] }),
108
+ step === "requesting" && /* @__PURE__ */ jsx(Spinner, { label: "Requesting login code..." }),
109
+ step === "waiting" && flow && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
110
+ /* @__PURE__ */ jsxs(Text, { children: [
111
+ "Open",
112
+ " ",
113
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: flow.verificationUri })
114
+ ] }),
115
+ /* @__PURE__ */ jsxs(Text, { children: [
116
+ "and enter code:",
117
+ " ",
118
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: flow.userCode })
119
+ ] }),
120
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Spinner, { label: "Waiting for approval..." }) }),
121
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press Ctrl+C to cancel" }) })
122
+ ] }),
123
+ step === "registering" && /* @__PURE__ */ jsx(Spinner, { label: "Approved! Registering agent..." }),
124
+ step === "done" && /* @__PURE__ */ jsx(StatusMessage, { variant: "success", children: "Logged in and agent registered." })
125
+ ] });
126
+ }
127
+
128
+ // src/ui/device-login.tsx
129
+ import { jsx as jsx2 } from "react/jsx-runtime";
130
+ function runDeviceLogin() {
131
+ return new Promise((resolve, reject) => {
132
+ const { unmount, waitUntilExit } = render(
133
+ /* @__PURE__ */ jsx2(
134
+ DeviceLoginWizard,
135
+ {
136
+ onComplete: (result) => {
137
+ unmount();
138
+ resolve(result);
139
+ },
140
+ onError: (message) => {
141
+ unmount();
142
+ reject(new Error(message));
143
+ }
144
+ }
145
+ )
146
+ );
147
+ waitUntilExit().catch(reject);
148
+ });
149
+ }
150
+ export {
151
+ runDeviceLogin
152
+ };
153
+ //# sourceMappingURL=device-login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/device-login.tsx","../../src/ui/components/device-login-wizard.tsx"],"sourcesContent":["import { render } from 'ink';\nimport { DeviceLoginWizard } from './components/device-login-wizard.js';\n\nexport interface LoginResult {\n agentId: string;\n apiKey: string;\n agentName: string;\n}\n\nexport function runDeviceLogin(): Promise<LoginResult> {\n return new Promise((resolve, reject) => {\n const { unmount, waitUntilExit } = render(\n <DeviceLoginWizard\n onComplete={(result) => {\n unmount();\n resolve(result);\n }}\n onError={(message) => {\n unmount();\n reject(new Error(message));\n }}\n />,\n );\n\n waitUntilExit().catch(reject);\n });\n}\n","import { useState, useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport { Spinner, StatusMessage } from '@inkjs/ui';\n\ntype Step = 'requesting' | 'waiting' | 'registering' | 'done';\n\ninterface DeviceFlowData {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n expiresIn: number;\n}\n\ninterface Props {\n onComplete: (result: {\n agentId: string;\n apiKey: string;\n agentName: string;\n }) => void;\n onError: (message: string) => void;\n}\n\ndeclare const AGENT_VERSION: string;\n\nconst POLL_INTERVAL_MS = 5_000;\n\nexport function DeviceLoginWizard({ onComplete, onError }: Props) {\n const [step, setStep] = useState<Step>('requesting');\n const [flow, setFlow] = useState<DeviceFlowData | null>(null);\n\n // Step 1: Initiate device flow\n useEffect(() => {\n let cancelled = false;\n\n const initiate = async () => {\n try {\n const { SERVER_URL } = await import(\n '../../config/config-schema.js'\n );\n const res = await fetch(`${SERVER_URL}/v1/auth/device-codes`, {\n method: 'POST',\n });\n\n if (!res.ok) {\n const body = await res.text();\n throw new Error(body || `HTTP ${res.status}`);\n }\n\n const json = (await res.json()) as { data: DeviceFlowData };\n if (!cancelled) {\n setFlow(json.data);\n setStep('waiting');\n }\n } catch (err) {\n if (cancelled) return;\n const msg = (err as Error).message;\n if (\n msg === 'fetch failed' ||\n msg.includes('ECONNREFUSED') ||\n msg.includes('ENOTFOUND')\n ) {\n onError('Could not connect to Stamn. Check your network.');\n } else {\n onError(msg);\n }\n }\n };\n\n initiate();\n return () => {\n cancelled = true;\n };\n }, []);\n\n // Step 2: Poll for approval\n useEffect(() => {\n if (step !== 'waiting' || !flow) return;\n\n let cancelled = false;\n\n const poll = async () => {\n try {\n const { SERVER_URL } = await import(\n '../../config/config-schema.js'\n );\n const res = await fetch(\n `${SERVER_URL}/v1/auth/device-codes/${flow.deviceCode}`,\n );\n\n if (!res.ok) return;\n\n const json = (await res.json()) as {\n data: { status: string; apiKey?: string };\n };\n\n if (cancelled) return;\n\n if (json.data.status === 'approved' && json.data.apiKey) {\n setStep('registering');\n await registerAgent(json.data.apiKey);\n } else if (json.data.status === 'expired') {\n onError('Login code expired. Run `stamn login` again.');\n }\n } catch {\n // Silently retry on network errors during polling\n }\n };\n\n const interval = setInterval(poll, POLL_INTERVAL_MS);\n // First poll immediately\n poll();\n\n return () => {\n cancelled = true;\n clearInterval(interval);\n };\n }, [step, flow]);\n\n const registerAgent = async (apiKey: string) => {\n try {\n const { SERVER_URL } = await import(\n '../../config/config-schema.js'\n );\n const res = await fetch(`${SERVER_URL}/v1/agents/register`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n platform: `${process.platform}-${process.arch}`,\n }),\n });\n\n if (!res.ok) {\n const body = await res.text();\n throw new Error(body || `HTTP ${res.status}`);\n }\n\n const json = (await res.json()) as {\n data: { id: string; name: string };\n };\n\n setStep('done');\n onComplete({\n agentId: json.data.id,\n apiKey,\n agentName: json.data.name,\n });\n } catch (err) {\n onError((err as Error).message || 'Registration failed');\n }\n };\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n stamn\n </Text>\n <Text dimColor> login</Text>\n </Box>\n\n {step === 'requesting' && (\n <Spinner label=\"Requesting login code...\" />\n )}\n\n {step === 'waiting' && flow && (\n <Box flexDirection=\"column\">\n <Text>\n Open{' '}\n <Text bold color=\"cyan\">\n {flow.verificationUri}\n </Text>\n </Text>\n <Text>\n and enter code:{' '}\n <Text bold color=\"yellow\">\n {flow.userCode}\n </Text>\n </Text>\n <Box marginTop={1}>\n <Spinner label=\"Waiting for approval...\" />\n </Box>\n <Box marginTop={1}>\n <Text dimColor>Press Ctrl+C to cancel</Text>\n </Box>\n </Box>\n )}\n\n {step === 'registering' && (\n <Spinner label=\"Approved! Registering agent...\" />\n )}\n\n {step === 'done' && (\n <StatusMessage variant=\"success\">\n Logged in and agent registered.\n </StatusMessage>\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":["jsx"]}
package/dist/ui/setup.js CHANGED
@@ -8,7 +8,7 @@ import { useState } from "react";
8
8
  import { Box, Text } from "ink";
9
9
  import { TextInput, Spinner, StatusMessage } from "@inkjs/ui";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
- function SetupWizard({ onComplete }) {
11
+ function SetupWizard({ onComplete, onError }) {
12
12
  const [step, setStep] = useState("api-key");
13
13
  const [error, setError] = useState("");
14
14
  const register = async (apiKey) => {
@@ -37,8 +37,12 @@ function SetupWizard({ onComplete }) {
37
37
  agentName: json.data.name
38
38
  });
39
39
  } catch (err) {
40
- setError(err.message);
41
- setStep("error");
40
+ const msg = err.message;
41
+ if (msg === "fetch failed" || msg.includes("ECONNREFUSED") || msg.includes("ENOTFOUND")) {
42
+ onError("Could not connect to Stamn. Is the server running?");
43
+ } else {
44
+ onError(msg);
45
+ }
42
46
  }
43
47
  };
44
48
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
@@ -69,13 +73,6 @@ function SetupWizard({ onComplete }) {
69
73
  ] }),
70
74
  step === "registering" && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Spinner, { label: "Registering agent..." }) }),
71
75
  step === "done" && /* @__PURE__ */ jsx(StatusMessage, { variant: "success", children: "Agent registered. Starting..." }),
72
- step === "error" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
73
- /* @__PURE__ */ jsxs(StatusMessage, { variant: "error", children: [
74
- "Registration failed: ",
75
- error
76
- ] }),
77
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Check your API key and try again." })
78
- ] }),
79
76
  step === "api-key" && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press Ctrl+C to cancel" }) })
80
77
  ] });
81
78
  }
@@ -91,6 +88,10 @@ function runSetup() {
91
88
  onComplete: (result) => {
92
89
  unmount();
93
90
  resolve(result);
91
+ },
92
+ onError: (message) => {
93
+ unmount();
94
+ reject(new Error(message));
94
95
  }
95
96
  }
96
97
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/setup.tsx","../../src/ui/components/setup-wizard.tsx"],"sourcesContent":["import { render } from 'ink';\nimport { SetupWizard } from './components/setup-wizard.js';\n\nexport interface SetupResult {\n agentId: string;\n apiKey: string;\n agentName: string;\n}\n\nexport function runSetup(): Promise<SetupResult> {\n return new Promise((resolve, reject) => {\n const { unmount, waitUntilExit } = render(\n <SetupWizard\n onComplete={(result) => {\n unmount();\n resolve(result);\n }}\n />,\n );\n\n waitUntilExit().catch(reject);\n });\n}\n","import { useState } from 'react';\nimport { Box, Text } from 'ink';\nimport { TextInput, Spinner, StatusMessage } from '@inkjs/ui';\n\ntype Step = 'api-key' | 'registering' | 'done' | 'error';\n\ninterface Props {\n onComplete: (result: { agentId: string; apiKey: string; agentName: string }) => void;\n}\n\ndeclare const AGENT_VERSION: string;\n\nexport function SetupWizard({ onComplete }: Props) {\n const [step, setStep] = useState<Step>('api-key');\n const [error, setError] = useState('');\n\n const register = async (apiKey: string) => {\n setStep('registering');\n\n try {\n const { SERVER_URL } = await import('../../config/config-schema.js');\n const res = await fetch(`${SERVER_URL}/v1/agents/register`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n platform: `${process.platform}-${process.arch}`,\n }),\n });\n\n if (!res.ok) {\n const body = await res.text();\n throw new Error(body || `HTTP ${res.status}`);\n }\n\n const json = (await res.json()) as {\n data: { id: string; name: string };\n };\n setStep('done');\n onComplete({\n agentId: json.data.id,\n apiKey,\n agentName: json.data.name,\n });\n } catch (err) {\n setError((err as Error).message);\n setStep('error');\n }\n };\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n stamn\n </Text>\n <Text dimColor> setup</Text>\n </Box>\n\n {step === 'api-key' && (\n <Box flexDirection=\"column\">\n <Text>Enter your API key from the Stamn dashboard.</Text>\n <Box marginTop={1}>\n <Text color=\"cyan\">{\"> \"}</Text>\n <TextInput\n placeholder=\"sk-...\"\n onSubmit={(value: string) => {\n if (!value.trim()) {\n setError('API key cannot be empty');\n return;\n }\n setError('');\n register(value.trim());\n }}\n />\n </Box>\n {error && step === 'api-key' && (\n <StatusMessage variant=\"error\">{error}</StatusMessage>\n )}\n </Box>\n )}\n\n {step === 'registering' && (\n <Box>\n <Spinner label=\"Registering agent...\" />\n </Box>\n )}\n\n {step === 'done' && (\n <StatusMessage variant=\"success\">\n Agent registered. Starting...\n </StatusMessage>\n )}\n\n {step === 'error' && (\n <Box flexDirection=\"column\">\n <StatusMessage variant=\"error\">\n Registration failed: {error}\n </StatusMessage>\n <Text dimColor>Check your API key and try again.</Text>\n </Box>\n )}\n\n {step === 'api-key' && (\n <Box marginTop={1}>\n <Text dimColor>Press Ctrl+C to cancel</Text>\n </Box>\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":["jsx"]}
1
+ {"version":3,"sources":["../../src/ui/setup.tsx","../../src/ui/components/setup-wizard.tsx"],"sourcesContent":["import { render } from 'ink';\nimport { SetupWizard } from './components/setup-wizard.js';\n\nexport interface SetupResult {\n agentId: string;\n apiKey: string;\n agentName: string;\n}\n\nexport function runSetup(): Promise<SetupResult> {\n return new Promise((resolve, reject) => {\n const { unmount, waitUntilExit } = render(\n <SetupWizard\n onComplete={(result) => {\n unmount();\n resolve(result);\n }}\n onError={(message) => {\n unmount();\n reject(new Error(message));\n }}\n />,\n );\n\n waitUntilExit().catch(reject);\n });\n}\n","import { useState } from 'react';\nimport { Box, Text } from 'ink';\nimport { TextInput, Spinner, StatusMessage } from '@inkjs/ui';\n\ntype Step = 'api-key' | 'registering' | 'done';\n\ninterface Props {\n onComplete: (result: { agentId: string; apiKey: string; agentName: string }) => void;\n onError: (message: string) => void;\n}\n\ndeclare const AGENT_VERSION: string;\n\nexport function SetupWizard({ onComplete, onError }: Props) {\n const [step, setStep] = useState<Step>('api-key');\n const [error, setError] = useState('');\n\n const register = async (apiKey: string) => {\n setStep('registering');\n\n try {\n const { SERVER_URL } = await import('../../config/config-schema.js');\n const res = await fetch(`${SERVER_URL}/v1/agents/register`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n platform: `${process.platform}-${process.arch}`,\n }),\n });\n\n if (!res.ok) {\n const body = await res.text();\n throw new Error(body || `HTTP ${res.status}`);\n }\n\n const json = (await res.json()) as {\n data: { id: string; name: string };\n };\n setStep('done');\n onComplete({\n agentId: json.data.id,\n apiKey,\n agentName: json.data.name,\n });\n } catch (err) {\n const msg = (err as Error).message;\n if (msg === 'fetch failed' || msg.includes('ECONNREFUSED') || msg.includes('ENOTFOUND')) {\n onError('Could not connect to Stamn. Is the server running?');\n } else {\n onError(msg);\n }\n }\n };\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n stamn\n </Text>\n <Text dimColor> setup</Text>\n </Box>\n\n {step === 'api-key' && (\n <Box flexDirection=\"column\">\n <Text>Enter your API key from the Stamn dashboard.</Text>\n <Box marginTop={1}>\n <Text color=\"cyan\">{\"> \"}</Text>\n <TextInput\n placeholder=\"sk-...\"\n onSubmit={(value: string) => {\n if (!value.trim()) {\n setError('API key cannot be empty');\n return;\n }\n setError('');\n register(value.trim());\n }}\n />\n </Box>\n {error && step === 'api-key' && (\n <StatusMessage variant=\"error\">{error}</StatusMessage>\n )}\n </Box>\n )}\n\n {step === 'registering' && (\n <Box>\n <Spinner label=\"Registering agent...\" />\n </Box>\n )}\n\n {step === 'done' && (\n <StatusMessage variant=\"success\">\n Agent registered. Starting...\n </StatusMessage>\n )}\n\n {step === 'api-key' && (\n <Box marginTop={1}>\n <Text dimColor>Press Ctrl+C to cancel</Text>\n </Box>\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":["jsx"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamn/agent",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Stamn Agent Daemon CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",