@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.
- package/README.md +1 -1
- package/dist/agent.js +43 -0
- package/dist/agent.js.map +1 -0
- package/dist/api.js +36 -0
- package/dist/api.js.map +1 -0
- package/dist/args.js +32 -0
- package/dist/args.js.map +1 -0
- package/dist/bin.js +7 -0
- package/dist/bin.js.map +1 -0
- package/{src → dist}/cli.js +22 -27
- package/dist/cli.js.map +1 -0
- package/dist/commands/fetch.js +27 -0
- package/dist/commands/fetch.js.map +1 -0
- package/dist/commands/identify.js +23 -0
- package/dist/commands/identify.js.map +1 -0
- package/dist/commands/listen.js +39 -0
- package/dist/commands/listen.js.map +1 -0
- package/dist/commands/subscribe.js +39 -0
- package/dist/commands/subscribe.js.map +1 -0
- package/dist/commands/subscriptions.js +12 -0
- package/dist/commands/subscriptions.js.map +1 -0
- package/dist/commands/unsubscribe.js +17 -0
- package/dist/commands/unsubscribe.js.map +1 -0
- package/dist/config.js +49 -0
- package/dist/config.js.map +1 -0
- package/{src → dist}/constants.js +1 -1
- package/dist/constants.js.map +1 -0
- package/dist/messages.js +38 -0
- package/dist/messages.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +11 -6
- package/bin/galinum.js +0 -7
- package/src/agent.js +0 -49
- package/src/api.js +0 -34
- package/src/args.js +0 -35
- package/src/commands/fetch.js +0 -25
- package/src/commands/identify.js +0 -30
- package/src/commands/listen.js +0 -37
- package/src/commands/subscribe.js +0 -47
- package/src/commands/subscriptions.js +0 -12
- package/src/commands/unsubscribe.js +0 -17
- package/src/config.js +0 -46
- 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.
|
|
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
|
package/dist/api.js.map
ADDED
|
@@ -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
|
package/dist/args.js.map
ADDED
|
@@ -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
package/dist/bin.js.map
ADDED
|
@@ -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"}
|
package/{src → dist}/cli.js
RENAMED
|
@@ -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
|
-
|
|
11
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
package/dist/cli.js.map
ADDED
|
@@ -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"}
|
package/dist/messages.js
ADDED
|
@@ -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 @@
|
|
|
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.
|
|
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
|
|
27
|
+
"galinum": "./dist/bin.js"
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
|
-
"
|
|
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
|
-
"
|
|
40
|
-
"
|
|
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
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
|
-
}
|
package/src/commands/fetch.js
DELETED
|
@@ -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
|
-
}
|
package/src/commands/identify.js
DELETED
|
@@ -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
|
-
}
|
package/src/commands/listen.js
DELETED
|
@@ -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
|
-
}
|