@galinum/cli 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/dist/agent.js +43 -0
  3. package/dist/agent.js.map +1 -0
  4. package/dist/api.js +36 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/args.js +32 -0
  7. package/dist/args.js.map +1 -0
  8. package/dist/bin.js +7 -0
  9. package/dist/bin.js.map +1 -0
  10. package/{src → dist}/cli.js +22 -27
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands/fetch.js +27 -0
  13. package/dist/commands/fetch.js.map +1 -0
  14. package/dist/commands/identify.js +23 -0
  15. package/dist/commands/identify.js.map +1 -0
  16. package/dist/commands/listen.js +39 -0
  17. package/dist/commands/listen.js.map +1 -0
  18. package/dist/commands/subscribe.js +39 -0
  19. package/dist/commands/subscribe.js.map +1 -0
  20. package/dist/commands/subscriptions.js +12 -0
  21. package/dist/commands/subscriptions.js.map +1 -0
  22. package/dist/commands/unsubscribe.js +17 -0
  23. package/dist/commands/unsubscribe.js.map +1 -0
  24. package/dist/config.js +49 -0
  25. package/dist/config.js.map +1 -0
  26. package/{src → dist}/constants.js +1 -1
  27. package/dist/constants.js.map +1 -0
  28. package/dist/messages.js +38 -0
  29. package/dist/messages.js.map +1 -0
  30. package/dist/types.js +2 -0
  31. package/dist/types.js.map +1 -0
  32. package/package.json +11 -6
  33. package/bin/galinum.js +0 -7
  34. package/src/agent.js +0 -49
  35. package/src/api.js +0 -34
  36. package/src/args.js +0 -35
  37. package/src/commands/fetch.js +0 -25
  38. package/src/commands/identify.js +0 -30
  39. package/src/commands/listen.js +0 -37
  40. package/src/commands/subscribe.js +0 -47
  41. package/src/commands/subscriptions.js +0 -12
  42. package/src/commands/unsubscribe.js +0 -17
  43. package/src/config.js +0 -46
  44. package/src/messages.js +0 -40
package/README.md CHANGED
@@ -16,7 +16,7 @@ Agents typically have no inbox. They run, they exit, and any message that arrive
16
16
  npm install -g @galinum/cli
17
17
  ```
18
18
 
19
- Requires Node.js 20 or later. Zero runtime dependencies.
19
+ Requires Node.js 20 or later. Written in TypeScript; zero runtime dependencies.
20
20
 
21
21
  ## Quick start
22
22
 
package/dist/agent.js ADDED
@@ -0,0 +1,43 @@
1
+ import { normalizeBaseUrl, requestJson } from "./api.js";
2
+ import { saveConfig } from "./config.js";
3
+ export function agentPayload(args) {
4
+ return {
5
+ name: typeof args.name === "string" ? args.name : "agent",
6
+ harness: typeof args.harness === "string" ? args.harness : null,
7
+ contact_email: typeof args.email === "string" ? args.email : null,
8
+ };
9
+ }
10
+ export function sameAgentMetadata(agent, payload) {
11
+ return (agent.name === payload.name &&
12
+ (agent.harness ?? null) === payload.harness &&
13
+ (agent.contact_email ?? null) === payload.contact_email);
14
+ }
15
+ export async function createAgent(args, payload) {
16
+ const baseUrl = normalizeBaseUrl(args["base-url"]);
17
+ const data = (await requestJson(`${baseUrl}/api/agents/identify`, {
18
+ method: "POST",
19
+ body: JSON.stringify(payload),
20
+ }));
21
+ if (!data?.id || !data?.name || !data?.key) {
22
+ throw new Error("Server response missing agent identity");
23
+ }
24
+ return {
25
+ id: data.id,
26
+ name: data.name,
27
+ harness: data.harness ?? null,
28
+ contact_email: data.contact_email ?? null,
29
+ key: data.key,
30
+ };
31
+ }
32
+ export async function ensureIdentified(args, config) {
33
+ if (config.agent?.key)
34
+ return config.agent;
35
+ if (config.agent) {
36
+ throw new Error(`Stored identity ${config.agent.id} has no agent key. Re-run \`galinum identify --reset\` to create a new identity.`);
37
+ }
38
+ config.agent = await createAgent(args, agentPayload({ ...args, name: "agent", _: args._ }));
39
+ await saveConfig(args, config);
40
+ console.log(`Identified as ${config.agent.id}.`);
41
+ return config.agent;
42
+ }
43
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,OAAO;QACL,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;QACzD,OAAO,EAAE,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QAC/D,aAAa,EAAE,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;KAClE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAoB,EAAE,OAAwB;IAC9E,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI;QAC3B,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,OAAO,CAAC,OAAO;QAC3C,CAAC,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,KAAK,OAAO,CAAC,aAAa,CACxD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAgB,EAChB,OAAwB;IAExB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,CAAC,MAAM,WAAW,CAAC,GAAG,OAAO,sBAAsB,EAAE;QAChE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAkC,CAAC;IAErC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;QAC7B,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI;QACzC,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAgB,EAChB,MAAc;IAEd,IAAI,MAAM,CAAC,KAAK,EAAE,GAAG;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC;IAC3C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,mBAAmB,MAAM,CAAC,KAAK,CAAC,EAAE,kFAAkF,CACrH,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,KAAK,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5F,MAAM,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC"}
package/dist/api.js ADDED
@@ -0,0 +1,36 @@
1
+ import { DEFAULT_BASE_URL } from "./constants.js";
2
+ export class GalinumRequestError extends Error {
3
+ status;
4
+ data;
5
+ constructor(status, data) {
6
+ const detail = data && typeof data === "object" && "error" in data
7
+ ? `: ${String(data.error)}`
8
+ : "";
9
+ super(`Galinum request failed (${status})${detail}`);
10
+ this.status = status;
11
+ this.data = data;
12
+ }
13
+ }
14
+ export function normalizeBaseUrl(value) {
15
+ const raw = typeof value === "string" && value.length > 0 ? value : DEFAULT_BASE_URL;
16
+ const url = new URL(raw);
17
+ url.pathname = "";
18
+ url.search = "";
19
+ url.hash = "";
20
+ return url.toString().replace(/\/$/, "");
21
+ }
22
+ export async function requestJson(url, options = {}) {
23
+ const res = await fetch(url, {
24
+ ...options,
25
+ headers: {
26
+ "Content-Type": "application/json",
27
+ ...(options.headers ?? {}),
28
+ },
29
+ });
30
+ const data = (await res.json().catch(() => null));
31
+ if (!res.ok) {
32
+ throw new GalinumRequestError(res.status, data);
33
+ }
34
+ return data;
35
+ }
36
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,MAAM,CAAS;IACf,IAAI,CAAU;IAEvB,YAAY,MAAc,EAAE,IAAa;QACvC,MAAM,MAAM,GACV,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI;YACjD,CAAC,CAAC,KAAK,MAAM,CAAE,IAA2B,CAAC,KAAK,CAAC,EAAE;YACnD,CAAC,CAAC,EAAE,CAAC;QACT,KAAK,CAAC,2BAA2B,MAAM,IAAI,MAAM,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACrF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,UAAuB,EAAE;IACtE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,GAAG,OAAO;QACV,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;SAC3B;KACF,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAY,CAAC;IAC7D,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/args.js ADDED
@@ -0,0 +1,32 @@
1
+ import path from "node:path";
2
+ import { DEFAULT_CONFIG_PATH } from "./constants.js";
3
+ export function parseArgs(argv) {
4
+ const args = { _: [] };
5
+ for (let i = 0; i < argv.length; i += 1) {
6
+ const arg = argv[i];
7
+ if (!arg.startsWith("--")) {
8
+ args._.push(arg);
9
+ continue;
10
+ }
11
+ const key = arg.slice(2);
12
+ const next = argv[i + 1];
13
+ if (!next || next.startsWith("--")) {
14
+ args[key] = true;
15
+ continue;
16
+ }
17
+ args[key] = next;
18
+ i += 1;
19
+ }
20
+ return args;
21
+ }
22
+ export function invocationName() {
23
+ const argv1 = process.argv[1] ?? "";
24
+ const base = path.basename(argv1);
25
+ if (base === "galinum" || base === "galinum-cli")
26
+ return base;
27
+ return `node ${argv1}`;
28
+ }
29
+ export function configPath(args) {
30
+ return typeof args.config === "string" ? args.config : DEFAULT_CONFIG_PATH;
31
+ }
32
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAGrD,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,IAAI,GAAe,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjB,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YACjB,SAAS;QACX,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QACjB,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC;IAC9D,OAAO,QAAQ,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAgB;IACzC,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC;AAC7E,CAAC"}
package/dist/bin.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { run } from "./cli.js";
3
+ run(process.argv.slice(2)).catch((err) => {
4
+ console.error(err instanceof Error ? err.message : String(err));
5
+ process.exitCode = 1;
6
+ });
7
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAChD,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -5,10 +5,9 @@ import { listSubscriptions } from "./commands/subscriptions.js";
5
5
  import { unsubscribe } from "./commands/unsubscribe.js";
6
6
  import { fetchMessages } from "./commands/fetch.js";
7
7
  import { listen } from "./commands/listen.js";
8
-
9
8
  function usage() {
10
- const bin = invocationName();
11
- console.log(`Usage:
9
+ const bin = invocationName();
10
+ console.log(`Usage:
12
11
  ${bin} identify --name name [--harness value] [--email email] [--reset]
13
12
  ${bin} subscribe <invite-code>
14
13
  ${bin} subscriptions
@@ -29,31 +28,27 @@ Global flags:
29
28
  --base-url <url> Override Galinum API base URL.
30
29
  `);
31
30
  }
32
-
33
31
  const COMMANDS = {
34
- identify,
35
- subscribe,
36
- subscriptions: listSubscriptions,
37
- unsubscribe,
38
- fetch: fetchMessages,
39
- listen,
32
+ identify,
33
+ subscribe,
34
+ subscriptions: listSubscriptions,
35
+ unsubscribe,
36
+ fetch: fetchMessages,
37
+ listen,
40
38
  };
41
-
42
39
  export async function run(argv) {
43
- const args = parseArgs(argv);
44
- const command = args._[0];
45
-
46
- if (!command || command === "help" || args.help) {
47
- usage();
48
- return;
49
- }
50
-
51
- const handler = COMMANDS[command];
52
- if (!handler) {
53
- usage();
54
- process.exitCode = 1;
55
- return;
56
- }
57
-
58
- await handler(args);
40
+ const args = parseArgs(argv);
41
+ const command = args._[0];
42
+ if (!command || command === "help" || args.help) {
43
+ usage();
44
+ return;
45
+ }
46
+ const handler = COMMANDS[command];
47
+ if (!handler) {
48
+ usage();
49
+ process.exitCode = 1;
50
+ return;
51
+ }
52
+ await handler(args);
59
53
  }
54
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C,SAAS,KAAK;IACZ,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC;IACV,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;;;;;;;;;;;;;CAaN,CAAC,CAAC;AACH,CAAC;AAID,MAAM,QAAQ,GAAmC;IAC/C,QAAQ;IACR,SAAS;IACT,aAAa,EAAE,iBAAiB;IAChC,WAAW;IACX,KAAK,EAAE,aAAa;IACpB,MAAM;CACP,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc;IACtC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1B,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAChD,KAAK,EAAE,CAAC;QACR,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,KAAK,EAAE,CAAC;QACR,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { loadConfig } from "../config.js";
2
+ import { fetchSubscription } from "../messages.js";
3
+ export async function fetchMessages(args) {
4
+ const orgSlug = args._[1];
5
+ const quiet = args.quiet === true;
6
+ const config = await loadConfig(args);
7
+ if (config.subscriptions.length === 0) {
8
+ if (!quiet) {
9
+ console.log("No subscriptions. Use `galinum subscribe <invite-code>` first.");
10
+ }
11
+ return 0;
12
+ }
13
+ const targets = orgSlug
14
+ ? config.subscriptions.filter((s) => s.org === orgSlug)
15
+ : config.subscriptions;
16
+ if (targets.length === 0) {
17
+ if (!quiet)
18
+ console.log(`Not subscribed to "${orgSlug}".`);
19
+ return 0;
20
+ }
21
+ let total = 0;
22
+ for (const sub of targets) {
23
+ total += await fetchSubscription(sub, quiet);
24
+ }
25
+ return total;
26
+ }
27
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/commands/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAgB;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,OAAO,GAAG,OAAO;QACrB,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC;QACvD,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;IACzB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,IAAI,CAAC,CAAC;QAC3D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,KAAK,IAAI,MAAM,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { configPath } from "../args.js";
2
+ import { loadConfig, saveConfig } from "../config.js";
3
+ import { agentPayload, createAgent, sameAgentMetadata } from "../agent.js";
4
+ export async function identify(args) {
5
+ const config = await loadConfig(args);
6
+ const payload = agentPayload(args);
7
+ if (config.agent && !args.reset) {
8
+ if (!config.agent.key) {
9
+ throw new Error(`Stored identity ${config.agent.id} predates agent auth and has no key. Re-run with --reset to create a new identity.`);
10
+ }
11
+ if (sameAgentMetadata(config.agent, payload)) {
12
+ console.log(`Already identified as ${config.agent.id}.`);
13
+ return config.agent;
14
+ }
15
+ throw new Error(`Already identified as ${config.agent.id}. To update metadata, edit ${configPath(args)} or re-run with --reset.`);
16
+ }
17
+ config.agent = await createAgent(args, payload);
18
+ const file = await saveConfig(args, config);
19
+ console.log(`Identified as ${config.agent.id}.`);
20
+ console.log(`Config: ${file}`);
21
+ return config.agent;
22
+ }
23
+ //# sourceMappingURL=identify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identify.js","sourceRoot":"","sources":["../../src/commands/identify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG3E,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAgB;IAC7C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,mBAAmB,MAAM,CAAC,KAAK,CAAC,EAAE,oFAAoF,CACvH,CAAC;QACJ,CAAC;QACD,IAAI,iBAAiB,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,yBAAyB,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;YACzD,OAAO,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,yBAAyB,MAAM,CAAC,KAAK,CAAC,EAAE,8BAA8B,UAAU,CAAC,IAAI,CAAC,0BAA0B,CACjH,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { DEFAULT_POLL_INTERVAL_MS } from "../constants.js";
2
+ import { fetchMessages } from "./fetch.js";
3
+ function sleep(ms, signal) {
4
+ return new Promise((resolve) => {
5
+ const timer = setTimeout(resolve, ms);
6
+ if (signal) {
7
+ const onAbort = () => {
8
+ clearTimeout(timer);
9
+ resolve();
10
+ };
11
+ signal.addEventListener("abort", onAbort, { once: true });
12
+ }
13
+ });
14
+ }
15
+ export async function listen(args) {
16
+ const raw = args["interval-seconds"];
17
+ const intervalSeconds = typeof raw === "string" ? Number(raw) : 30;
18
+ const intervalMs = Number.isFinite(intervalSeconds)
19
+ ? Math.max(5, intervalSeconds) * 1000
20
+ : DEFAULT_POLL_INTERVAL_MS;
21
+ console.log("Listening for Galinum messages.");
22
+ console.log("Press Ctrl+C to stop.");
23
+ const controller = new AbortController();
24
+ const stop = () => controller.abort();
25
+ process.once("SIGINT", stop);
26
+ process.once("SIGTERM", stop);
27
+ const innerArgs = {
28
+ ...args,
29
+ _: ["fetch", ...(args._[1] ? [args._[1]] : [])],
30
+ quiet: true,
31
+ };
32
+ while (!controller.signal.aborted) {
33
+ await fetchMessages(innerArgs);
34
+ if (controller.signal.aborted)
35
+ break;
36
+ await sleep(intervalMs, controller.signal);
37
+ }
38
+ }
39
+ //# sourceMappingURL=listen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listen.js","sourceRoot":"","sources":["../../src/commands/listen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,SAAS,KAAK,CAAC,EAAU,EAAE,MAAoB;IAC7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACtC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,GAAG,EAAE;gBACnB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAgB;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACrC,MAAM,eAAe,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC;QACjD,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,IAAI;QACrC,CAAC,CAAC,wBAAwB,CAAC;IAE7B,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IAErC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAE9B,MAAM,SAAS,GAAe;QAC5B,GAAG,IAAI;QACP,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/C,KAAK,EAAE,IAAI;KACZ,CAAC;IACF,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM;QACrC,MAAM,KAAK,CAAC,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { INVITE_CODE_REGEX } from "../constants.js";
2
+ import { normalizeBaseUrl, requestJson } from "../api.js";
3
+ import { loadConfig, saveConfig } from "../config.js";
4
+ import { ensureIdentified } from "../agent.js";
5
+ export async function subscribe(args) {
6
+ const inviteCode = args._[1];
7
+ if (!inviteCode) {
8
+ throw new Error("Invite code is required. Usage: galinum subscribe <invite-code>");
9
+ }
10
+ if (!INVITE_CODE_REGEX.test(inviteCode)) {
11
+ throw new Error(`Invalid invite code "${inviteCode}". Expected format: inv_<16-128 url-safe chars>.`);
12
+ }
13
+ const baseUrl = normalizeBaseUrl(args["base-url"]);
14
+ const config = await loadConfig(args);
15
+ const agent = await ensureIdentified(args, config);
16
+ const data = (await requestJson(`${baseUrl}/api/agent-inboxes`, {
17
+ method: "POST",
18
+ headers: { Authorization: `Bearer ${agent.key}` },
19
+ body: JSON.stringify({ invite_code: inviteCode }),
20
+ }));
21
+ const org = data?.organization?.id;
22
+ if (!org || !data?.id || !data?.key) {
23
+ throw new Error("Server response missing inbox credentials");
24
+ }
25
+ const existing = config.subscriptions.findIndex((s) => s.org === org);
26
+ if (existing !== -1)
27
+ config.subscriptions.splice(existing, 1);
28
+ config.subscriptions.push({
29
+ org,
30
+ baseUrl,
31
+ inboxId: data.id,
32
+ key: data.key,
33
+ });
34
+ const file = await saveConfig(args, config);
35
+ console.log(`Subscribed to ${org}.`);
36
+ console.log(`Inbox ID: ${data.id}`);
37
+ console.log(`Config: ${file}`);
38
+ }
39
+ //# sourceMappingURL=subscribe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribe.js","sourceRoot":"","sources":["../../src/commands/subscribe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAS/C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAgB;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,wBAAwB,UAAU,kDAAkD,CACrF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAEnD,MAAM,IAAI,GAAG,CAAC,MAAM,WAAW,CAAC,GAAG,OAAO,oBAAoB,EAAE;QAC9D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,CAAC,GAAG,EAAE,EAAE;QACjD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;KAClD,CAAC,CAA6B,CAAC;IAEhC,MAAM,GAAG,GAAG,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC;IACnC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IACtE,IAAI,QAAQ,KAAK,CAAC,CAAC;QAAE,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAE9D,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;QACxB,GAAG;QACH,OAAO;QACP,OAAO,EAAE,IAAI,CAAC,EAAE;QAChB,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,GAAG,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { loadConfig } from "../config.js";
2
+ export async function listSubscriptions(args) {
3
+ const config = await loadConfig(args);
4
+ if (config.subscriptions.length === 0) {
5
+ console.log("No subscriptions. Use `galinum subscribe <invite-code>` to add one.");
6
+ return;
7
+ }
8
+ for (const sub of config.subscriptions) {
9
+ console.log(`${sub.org}\t${sub.inboxId}\t${sub.baseUrl}`);
10
+ }
11
+ }
12
+ //# sourceMappingURL=subscriptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../../src/commands/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAgB;IACtD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC;QACnF,OAAO;IACT,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { loadConfig, saveConfig } from "../config.js";
2
+ export async function unsubscribe(args) {
3
+ const orgSlug = args._[1];
4
+ if (!orgSlug) {
5
+ throw new Error("Organization slug is required. Usage: galinum unsubscribe <slug>");
6
+ }
7
+ const config = await loadConfig(args);
8
+ const idx = config.subscriptions.findIndex((s) => s.org === orgSlug);
9
+ if (idx === -1) {
10
+ console.log(`Not subscribed to "${orgSlug}".`);
11
+ return;
12
+ }
13
+ config.subscriptions.splice(idx, 1);
14
+ await saveConfig(args, config);
15
+ console.log(`Unsubscribed from ${orgSlug}.`);
16
+ }
17
+ //# sourceMappingURL=unsubscribe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unsubscribe.js","sourceRoot":"","sources":["../../src/commands/unsubscribe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGtD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAgB;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC;IACrE,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,IAAI,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IACD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACpC,MAAM,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,GAAG,CAAC,CAAC;AAC/C,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,49 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { configPath } from "./args.js";
4
+ function emptyConfig() {
5
+ return { subscriptions: [] };
6
+ }
7
+ function normalizeAgent(agent) {
8
+ if (!agent || typeof agent !== "object")
9
+ return null;
10
+ const a = agent;
11
+ if (typeof a.id !== "string" || typeof a.name !== "string")
12
+ return null;
13
+ return {
14
+ id: a.id,
15
+ name: a.name,
16
+ harness: typeof a.harness === "string" ? a.harness : null,
17
+ contact_email: typeof a.contact_email === "string" ? a.contact_email : null,
18
+ key: typeof a.key === "string" ? a.key : null,
19
+ };
20
+ }
21
+ function normalizeConfig(parsed) {
22
+ const p = (parsed && typeof parsed === "object" ? parsed : {});
23
+ const subscriptions = Array.isArray(p.subscriptions)
24
+ ? p.subscriptions
25
+ : [];
26
+ const config = { subscriptions };
27
+ const agent = normalizeAgent(p.agent);
28
+ if (agent)
29
+ config.agent = agent;
30
+ return config;
31
+ }
32
+ export async function loadConfig(args) {
33
+ const file = configPath(args);
34
+ try {
35
+ const parsed = JSON.parse(await readFile(file, "utf8"));
36
+ return normalizeConfig(parsed);
37
+ }
38
+ catch {
39
+ return emptyConfig();
40
+ }
41
+ }
42
+ export async function saveConfig(args, config) {
43
+ const file = configPath(args);
44
+ // Restrict permissions — config holds bearer tokens.
45
+ await mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
46
+ await writeFile(file, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
47
+ return file;
48
+ }
49
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,SAAS,WAAW;IAClB,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACrD,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACxE,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QACzD,aAAa,EAAE,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI;QAC3E,GAAG,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;KAC9C,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,MAAe;IACtC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAA4B,CAAC;IAC1F,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;QAClD,CAAC,CAAE,CAAC,CAAC,aAAgC;QACrC,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,MAAM,GAAW,EAAE,aAAa,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,KAAK;QAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;IAChC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAgB;IAC/C,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QACxD,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAgB,EAAE,MAAc;IAC/D,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,qDAAqD;IACrD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/E,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import os from "node:os";
2
2
  import path from "node:path";
3
-
4
3
  export const DEFAULT_BASE_URL = "https://galinum.com";
5
4
  export const DEFAULT_CONFIG_PATH = path.join(os.homedir(), ".galinum", "config.json");
6
5
  export const DEFAULT_POLL_INTERVAL_MS = 30_000;
7
6
  export const INVITE_CODE_REGEX = /^inv_[A-Za-z0-9_-]{16,128}$/;
7
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AACtD,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;AACtF,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAAG,6BAA6B,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { requestJson } from "./api.js";
2
+ export function printMessage(orgSlug, message) {
3
+ console.log("");
4
+ console.log(`[${orgSlug}] [${message.created_at}] ${message.title}`);
5
+ console.log(`Type: ${message.type}`);
6
+ console.log(message.body);
7
+ if (message.payload !== null && message.payload !== undefined) {
8
+ console.log("Payload:");
9
+ console.log(JSON.stringify(message.payload, null, 2));
10
+ }
11
+ }
12
+ async function ackMessages(subscription, messageIds) {
13
+ if (messageIds.length === 0)
14
+ return;
15
+ const url = `${subscription.baseUrl}/api/agent-inbox/messages?inbox_id=${encodeURIComponent(subscription.inboxId)}`;
16
+ await requestJson(url, {
17
+ method: "POST",
18
+ headers: { Authorization: `Bearer ${subscription.key}` },
19
+ body: JSON.stringify({ message_ids: messageIds }),
20
+ });
21
+ }
22
+ export async function fetchSubscription(subscription, quiet) {
23
+ const url = `${subscription.baseUrl}/api/agent-inbox/messages?inbox_id=${encodeURIComponent(subscription.inboxId)}`;
24
+ const data = (await requestJson(url, {
25
+ headers: { Authorization: `Bearer ${subscription.key}` },
26
+ }));
27
+ const messages = Array.isArray(data?.messages) ? data.messages : [];
28
+ if (messages.length === 0) {
29
+ if (!quiet)
30
+ console.log(`[${subscription.org}] No pending messages.`);
31
+ return 0;
32
+ }
33
+ for (const message of messages)
34
+ printMessage(subscription.org, message);
35
+ await ackMessages(subscription, messages.map((m) => m.id));
36
+ return messages.length;
37
+ }
38
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGvC,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,OAAqB;IACjE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,SAAS,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,YAA0B,EAAE,UAAoB;IACzE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACpC,MAAM,GAAG,GAAG,GAAG,YAAY,CAAC,OAAO,sCAAsC,kBAAkB,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;IACpH,MAAM,WAAW,CAAC,GAAG,EAAE;QACrB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,YAAY,CAAC,GAAG,EAAE,EAAE;QACxD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;KAClD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,YAA0B,EAC1B,KAAc;IAEd,MAAM,GAAG,GAAG,GAAG,YAAY,CAAC,OAAO,sCAAsC,kBAAkB,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;IACpH,MAAM,IAAI,GAAG,CAAC,MAAM,WAAW,CAAC,GAAG,EAAE;QACnC,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,YAAY,CAAC,GAAG,EAAE,EAAE;KACzD,CAAC,CAAyC,CAAC;IAE5C,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,GAAG,wBAAwB,CAAC,CAAC;QACtE,OAAO,CAAC,CAAC;IACX,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,YAAY,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACxE,MAAM,WAAW,CACf,YAAY,EACZ,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC1B,CAAC;IACF,OAAO,QAAQ,CAAC,MAAM,CAAC;AACzB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@galinum/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Universal agent inbox CLI — receive durable messages from any product that integrates with the Galinum SDK, in any agent harness.",
5
5
  "keywords": [
6
6
  "agents",
@@ -24,11 +24,10 @@
24
24
  },
25
25
  "type": "module",
26
26
  "bin": {
27
- "galinum": "./bin/galinum.js"
27
+ "galinum": "./dist/bin.js"
28
28
  },
29
29
  "files": [
30
- "bin",
31
- "src",
30
+ "dist",
32
31
  "LICENSE",
33
32
  "README.md"
34
33
  ],
@@ -36,8 +35,14 @@
36
35
  "node": ">=20"
37
36
  },
38
37
  "scripts": {
39
- "test": "node --test test/*.test.js",
40
- "start": "node bin/galinum.js"
38
+ "build": "tsc && chmod +x dist/bin.js",
39
+ "typecheck": "tsc --noEmit",
40
+ "test": "tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js",
41
+ "prepublishOnly": "npm run test && npm run build"
42
+ },
43
+ "devDependencies": {
44
+ "typescript": "^5.6.0",
45
+ "@types/node": "^20.0.0"
41
46
  },
42
47
  "publishConfig": {
43
48
  "access": "public"
package/bin/galinum.js DELETED
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env node
2
- import { run } from "../src/cli.js";
3
-
4
- run(process.argv.slice(2)).catch((err) => {
5
- console.error(err instanceof Error ? err.message : String(err));
6
- process.exitCode = 1;
7
- });
package/src/agent.js DELETED
@@ -1,49 +0,0 @@
1
- import { normalizeBaseUrl, requestJson } from "./api.js";
2
- import { saveConfig } from "./config.js";
3
-
4
- export function agentPayload(args) {
5
- return {
6
- name: args.name || "agent",
7
- harness: args.harness || null,
8
- contact_email: args.email || null,
9
- };
10
- }
11
-
12
- export function sameAgentMetadata(agent, payload) {
13
- return (
14
- agent.name === payload.name &&
15
- (agent.harness ?? null) === payload.harness &&
16
- (agent.contact_email ?? null) === payload.contact_email
17
- );
18
- }
19
-
20
- export async function createAgent(args, payload) {
21
- const baseUrl = normalizeBaseUrl(args["base-url"]);
22
- const data = await requestJson(`${baseUrl}/api/agents/identify`, {
23
- method: "POST",
24
- body: JSON.stringify(payload),
25
- });
26
- if (!data?.id || !data?.name || !data?.key) {
27
- throw new Error("Server response missing agent identity");
28
- }
29
- return {
30
- id: data.id,
31
- name: data.name,
32
- harness: data.harness ?? null,
33
- contact_email: data.contact_email ?? null,
34
- key: data.key,
35
- };
36
- }
37
-
38
- export async function ensureIdentified(args, config) {
39
- if (config.agent?.key) return config.agent;
40
- if (config.agent) {
41
- throw new Error(
42
- `Stored identity ${config.agent.id} has no agent key. Re-run \`galinum identify --reset\` to create a new identity.`,
43
- );
44
- }
45
- config.agent = await createAgent(args, agentPayload({ ...args, name: "agent" }));
46
- await saveConfig(args, config);
47
- console.log(`Identified as ${config.agent.id}.`);
48
- return config.agent;
49
- }
package/src/api.js DELETED
@@ -1,34 +0,0 @@
1
- import { DEFAULT_BASE_URL } from "./constants.js";
2
-
3
- export class GalinumRequestError extends Error {
4
- constructor(status, data) {
5
- const detail = data?.error ? `: ${data.error}` : "";
6
- super(`Galinum request failed (${status})${detail}`);
7
- this.status = status;
8
- this.data = data;
9
- }
10
- }
11
-
12
- export function normalizeBaseUrl(value) {
13
- const url = new URL(value || DEFAULT_BASE_URL);
14
- url.pathname = "";
15
- url.search = "";
16
- url.hash = "";
17
- return url.toString().replace(/\/$/, "");
18
- }
19
-
20
- export async function requestJson(url, options = {}) {
21
- const res = await fetch(url, {
22
- ...options,
23
- headers: {
24
- "Content-Type": "application/json",
25
- ...(options.headers ?? {}),
26
- },
27
- });
28
-
29
- const data = await res.json().catch(() => null);
30
- if (!res.ok) {
31
- throw new GalinumRequestError(res.status, data);
32
- }
33
- return data;
34
- }
package/src/args.js DELETED
@@ -1,35 +0,0 @@
1
- import path from "node:path";
2
- import { DEFAULT_CONFIG_PATH } from "./constants.js";
3
-
4
- export function parseArgs(argv) {
5
- const args = { _: [] };
6
- for (let i = 0; i < argv.length; i += 1) {
7
- const arg = argv[i];
8
- if (!arg.startsWith("--")) {
9
- args._.push(arg);
10
- continue;
11
- }
12
-
13
- const key = arg.slice(2);
14
- const next = argv[i + 1];
15
- if (!next || next.startsWith("--")) {
16
- args[key] = true;
17
- continue;
18
- }
19
-
20
- args[key] = next;
21
- i += 1;
22
- }
23
- return args;
24
- }
25
-
26
- export function invocationName() {
27
- const argv1 = process.argv[1] ?? "";
28
- const base = path.basename(argv1);
29
- if (base === "galinum" || base === "galinum-cli") return base;
30
- return `node ${argv1}`;
31
- }
32
-
33
- export function configPath(args) {
34
- return typeof args.config === "string" ? args.config : DEFAULT_CONFIG_PATH;
35
- }
@@ -1,25 +0,0 @@
1
- import { loadConfig } from "../config.js";
2
- import { fetchSubscription } from "../messages.js";
3
-
4
- export async function fetchMessages(args) {
5
- const orgSlug = args._[1];
6
- const config = await loadConfig(args);
7
- if (config.subscriptions.length === 0) {
8
- if (!args.quiet) {
9
- console.log("No subscriptions. Use `galinum subscribe <invite-code>` first.");
10
- }
11
- return 0;
12
- }
13
- const targets = orgSlug
14
- ? config.subscriptions.filter((s) => s.org === orgSlug)
15
- : config.subscriptions;
16
- if (targets.length === 0) {
17
- if (!args.quiet) console.log(`Not subscribed to "${orgSlug}".`);
18
- return 0;
19
- }
20
- let total = 0;
21
- for (const sub of targets) {
22
- total += await fetchSubscription(sub, args.quiet);
23
- }
24
- return total;
25
- }
@@ -1,30 +0,0 @@
1
- import { configPath } from "../args.js";
2
- import { loadConfig, saveConfig } from "../config.js";
3
- import { agentPayload, createAgent, sameAgentMetadata } from "../agent.js";
4
-
5
- export async function identify(args) {
6
- const config = await loadConfig(args);
7
- const payload = agentPayload(args);
8
-
9
- if (config.agent && !args.reset) {
10
- if (!config.agent.key) {
11
- throw new Error(
12
- `Stored identity ${config.agent.id} predates agent auth and has no key. Re-run with --reset to create a new identity.`,
13
- );
14
- }
15
- if (sameAgentMetadata(config.agent, payload)) {
16
- console.log(`Already identified as ${config.agent.id}.`);
17
- return config.agent;
18
- }
19
- throw new Error(
20
- `Already identified as ${config.agent.id}. To update metadata, edit ${configPath(args)} or re-run with --reset.`,
21
- );
22
- }
23
-
24
- config.agent = await createAgent(args, payload);
25
- const file = await saveConfig(args, config);
26
-
27
- console.log(`Identified as ${config.agent.id}.`);
28
- console.log(`Config: ${file}`);
29
- return config.agent;
30
- }
@@ -1,37 +0,0 @@
1
- import { DEFAULT_POLL_INTERVAL_MS } from "../constants.js";
2
- import { fetchMessages } from "./fetch.js";
3
-
4
- function sleep(ms, signal) {
5
- return new Promise((resolve) => {
6
- const timer = setTimeout(resolve, ms);
7
- if (signal) {
8
- const onAbort = () => {
9
- clearTimeout(timer);
10
- resolve();
11
- };
12
- signal.addEventListener("abort", onAbort, { once: true });
13
- }
14
- });
15
- }
16
-
17
- export async function listen(args) {
18
- const intervalSeconds = Number(args["interval-seconds"] ?? "30");
19
- const intervalMs = Number.isFinite(intervalSeconds)
20
- ? Math.max(5, intervalSeconds) * 1000
21
- : DEFAULT_POLL_INTERVAL_MS;
22
-
23
- console.log("Listening for Galinum messages.");
24
- console.log("Press Ctrl+C to stop.");
25
-
26
- const controller = new AbortController();
27
- const stop = () => controller.abort();
28
- process.once("SIGINT", stop);
29
- process.once("SIGTERM", stop);
30
-
31
- const innerArgs = { ...args, _: ["fetch", ...(args._[1] ? [args._[1]] : [])], quiet: true };
32
- while (!controller.signal.aborted) {
33
- await fetchMessages(innerArgs);
34
- if (controller.signal.aborted) break;
35
- await sleep(intervalMs, controller.signal);
36
- }
37
- }
@@ -1,47 +0,0 @@
1
- import { INVITE_CODE_REGEX } from "../constants.js";
2
- import { normalizeBaseUrl, requestJson } from "../api.js";
3
- import { loadConfig, saveConfig } from "../config.js";
4
- import { ensureIdentified } from "../agent.js";
5
-
6
- export async function subscribe(args) {
7
- const inviteCode = args._[1];
8
- if (!inviteCode) {
9
- throw new Error("Invite code is required. Usage: galinum subscribe <invite-code>");
10
- }
11
- if (!INVITE_CODE_REGEX.test(inviteCode)) {
12
- throw new Error(
13
- `Invalid invite code "${inviteCode}". Expected format: inv_<16-128 url-safe chars>.`,
14
- );
15
- }
16
-
17
- const baseUrl = normalizeBaseUrl(args["base-url"]);
18
- const config = await loadConfig(args);
19
- const agent = await ensureIdentified(args, config);
20
-
21
- const data = await requestJson(`${baseUrl}/api/agent-inboxes`, {
22
- method: "POST",
23
- headers: { Authorization: `Bearer ${agent.key}` },
24
- body: JSON.stringify({ invite_code: inviteCode }),
25
- });
26
-
27
- const org = data.organization?.id;
28
- if (!org || !data.id || !data.key) {
29
- throw new Error("Server response missing inbox credentials");
30
- }
31
-
32
- const existing = config.subscriptions.findIndex((s) => s.org === org);
33
- if (existing !== -1) config.subscriptions.splice(existing, 1);
34
-
35
- config.subscriptions.push({
36
- org,
37
- baseUrl,
38
- inboxId: data.id,
39
- key: data.key,
40
- });
41
-
42
- const file = await saveConfig(args, config);
43
-
44
- console.log(`Subscribed to ${org}.`);
45
- console.log(`Inbox ID: ${data.id}`);
46
- console.log(`Config: ${file}`);
47
- }
@@ -1,12 +0,0 @@
1
- import { loadConfig } from "../config.js";
2
-
3
- export async function listSubscriptions(args) {
4
- const config = await loadConfig(args);
5
- if (config.subscriptions.length === 0) {
6
- console.log("No subscriptions. Use `galinum subscribe <invite-code>` to add one.");
7
- return;
8
- }
9
- for (const sub of config.subscriptions) {
10
- console.log(`${sub.org}\t${sub.inboxId}\t${sub.baseUrl}`);
11
- }
12
- }
@@ -1,17 +0,0 @@
1
- import { loadConfig, saveConfig } from "../config.js";
2
-
3
- export async function unsubscribe(args) {
4
- const orgSlug = args._[1];
5
- if (!orgSlug) {
6
- throw new Error("Organization slug is required. Usage: galinum unsubscribe <slug>");
7
- }
8
- const config = await loadConfig(args);
9
- const idx = config.subscriptions.findIndex((s) => s.org === orgSlug);
10
- if (idx === -1) {
11
- console.log(`Not subscribed to "${orgSlug}".`);
12
- return;
13
- }
14
- config.subscriptions.splice(idx, 1);
15
- await saveConfig(args, config);
16
- console.log(`Unsubscribed from ${orgSlug}.`);
17
- }
package/src/config.js DELETED
@@ -1,46 +0,0 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { configPath } from "./args.js";
4
-
5
- function emptyConfig() {
6
- return { subscriptions: [] };
7
- }
8
-
9
- function normalizeAgent(agent) {
10
- if (!agent || typeof agent !== "object") return null;
11
- if (typeof agent.id !== "string" || typeof agent.name !== "string") return null;
12
- return {
13
- id: agent.id,
14
- name: agent.name,
15
- harness: typeof agent.harness === "string" ? agent.harness : null,
16
- contact_email: typeof agent.contact_email === "string" ? agent.contact_email : null,
17
- key: typeof agent.key === "string" ? agent.key : null,
18
- };
19
- }
20
-
21
- function normalizeConfig(parsed) {
22
- const config = {
23
- subscriptions: Array.isArray(parsed?.subscriptions) ? parsed.subscriptions : [],
24
- };
25
- const agent = normalizeAgent(parsed?.agent);
26
- if (agent) config.agent = agent;
27
- return config;
28
- }
29
-
30
- export async function loadConfig(args) {
31
- const file = configPath(args);
32
- try {
33
- const parsed = JSON.parse(await readFile(file, "utf8"));
34
- return normalizeConfig(parsed);
35
- } catch {
36
- return emptyConfig();
37
- }
38
- }
39
-
40
- export async function saveConfig(args, config) {
41
- const file = configPath(args);
42
- // Restrict permissions — config holds bearer tokens.
43
- await mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
44
- await writeFile(file, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
45
- return file;
46
- }
package/src/messages.js DELETED
@@ -1,40 +0,0 @@
1
- import { requestJson } from "./api.js";
2
-
3
- export function printMessage(orgSlug, message) {
4
- console.log("");
5
- console.log(`[${orgSlug}] [${message.created_at}] ${message.title}`);
6
- console.log(`Type: ${message.type}`);
7
- console.log(message.body);
8
- if (message.payload !== null && message.payload !== undefined) {
9
- console.log("Payload:");
10
- console.log(JSON.stringify(message.payload, null, 2));
11
- }
12
- }
13
-
14
- async function ackMessages(subscription, messageIds) {
15
- if (messageIds.length === 0) return;
16
- const url = `${subscription.baseUrl}/api/agent-inbox/messages?inbox_id=${encodeURIComponent(subscription.inboxId)}`;
17
- await requestJson(url, {
18
- method: "POST",
19
- headers: { Authorization: `Bearer ${subscription.key}` },
20
- body: JSON.stringify({ message_ids: messageIds }),
21
- });
22
- }
23
-
24
- export async function fetchSubscription(subscription, quiet) {
25
- const url = `${subscription.baseUrl}/api/agent-inbox/messages?inbox_id=${encodeURIComponent(subscription.inboxId)}`;
26
- const data = await requestJson(url, {
27
- headers: { Authorization: `Bearer ${subscription.key}` },
28
- });
29
- const messages = Array.isArray(data.messages) ? data.messages : [];
30
- if (messages.length === 0) {
31
- if (!quiet) console.log(`[${subscription.org}] No pending messages.`);
32
- return 0;
33
- }
34
- for (const message of messages) printMessage(subscription.org, message);
35
- await ackMessages(
36
- subscription,
37
- messages.map((m) => m.id),
38
- );
39
- return messages.length;
40
- }