@qoren/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +162 -0
- package/dist/args.d.ts +5 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +23 -0
- package/dist/args.js.map +1 -0
- package/dist/commands/account.d.ts +4 -0
- package/dist/commands/account.d.ts.map +1 -0
- package/dist/commands/account.js +154 -0
- package/dist/commands/account.js.map +1 -0
- package/dist/commands/agent.d.ts +27 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +968 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/api.d.ts +4 -0
- package/dist/commands/api.d.ts.map +1 -0
- package/dist/commands/api.js +66 -0
- package/dist/commands/api.js.map +1 -0
- package/dist/commands/approvals.d.ts +11 -0
- package/dist/commands/approvals.d.ts.map +1 -0
- package/dist/commands/approvals.js +140 -0
- package/dist/commands/approvals.js.map +1 -0
- package/dist/commands/auth.d.ts +4 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +215 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/clients.d.ts +62 -0
- package/dist/commands/clients.d.ts.map +1 -0
- package/dist/commands/clients.js +311 -0
- package/dist/commands/clients.js.map +1 -0
- package/dist/commands/console.d.ts +4 -0
- package/dist/commands/console.d.ts.map +1 -0
- package/dist/commands/console.js +26 -0
- package/dist/commands/console.js.map +1 -0
- package/dist/commands/customAgent.d.ts +42 -0
- package/dist/commands/customAgent.d.ts.map +1 -0
- package/dist/commands/customAgent.js +449 -0
- package/dist/commands/customAgent.js.map +1 -0
- package/dist/commands/designer.d.ts +32 -0
- package/dist/commands/designer.d.ts.map +1 -0
- package/dist/commands/designer.js +682 -0
- package/dist/commands/designer.js.map +1 -0
- package/dist/commands/env.d.ts +15 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/env.js +245 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/interactive.d.ts +4 -0
- package/dist/commands/interactive.d.ts.map +1 -0
- package/dist/commands/interactive.js +30 -0
- package/dist/commands/interactive.js.map +1 -0
- package/dist/commands/jobs.d.ts +4 -0
- package/dist/commands/jobs.d.ts.map +1 -0
- package/dist/commands/jobs.js +59 -0
- package/dist/commands/jobs.js.map +1 -0
- package/dist/commands/secrets.d.ts +15 -0
- package/dist/commands/secrets.d.ts.map +1 -0
- package/dist/commands/secrets.js +164 -0
- package/dist/commands/secrets.js.map +1 -0
- package/dist/commands/webhook.d.ts +4 -0
- package/dist/commands/webhook.d.ts.map +1 -0
- package/dist/commands/webhook.js +275 -0
- package/dist/commands/webhook.js.map +1 -0
- package/dist/config.d.ts +38 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +117 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +52 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +163 -0
- package/dist/context.js.map +1 -0
- package/dist/duration.d.ts +9 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +30 -0
- package/dist/duration.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/issues.d.ts +10 -0
- package/dist/issues.d.ts.map +1 -0
- package/dist/issues.js +45 -0
- package/dist/issues.js.map +1 -0
- package/dist/jobProgress.d.ts +12 -0
- package/dist/jobProgress.d.ts.map +1 -0
- package/dist/jobProgress.js +56 -0
- package/dist/jobProgress.js.map +1 -0
- package/dist/loopback.d.ts +28 -0
- package/dist/loopback.d.ts.map +1 -0
- package/dist/loopback.js +110 -0
- package/dist/loopback.js.map +1 -0
- package/dist/migrate/apply.d.ts +29 -0
- package/dist/migrate/apply.d.ts.map +1 -0
- package/dist/migrate/apply.js +135 -0
- package/dist/migrate/apply.js.map +1 -0
- package/dist/migrate/bundle.d.ts +89 -0
- package/dist/migrate/bundle.d.ts.map +1 -0
- package/dist/migrate/bundle.js +681 -0
- package/dist/migrate/bundle.js.map +1 -0
- package/dist/migrate/tar.d.ts +9 -0
- package/dist/migrate/tar.d.ts.map +1 -0
- package/dist/migrate/tar.js +89 -0
- package/dist/migrate/tar.js.map +1 -0
- package/dist/output.d.ts +46 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +152 -0
- package/dist/output.js.map +1 -0
- package/dist/program.d.ts +17 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +89 -0
- package/dist/program.js.map +1 -0
- package/dist/runtimes.d.ts +11 -0
- package/dist/runtimes.d.ts.map +1 -0
- package/dist/runtimes.js +20 -0
- package/dist/runtimes.js.map +1 -0
- package/dist/slug.d.ts +3 -0
- package/dist/slug.d.ts.map +1 -0
- package/dist/slug.js +15 -0
- package/dist/slug.js.map +1 -0
- package/dist/taskChain.d.ts +20 -0
- package/dist/taskChain.d.ts.map +1 -0
- package/dist/taskChain.js +40 -0
- package/dist/taskChain.js.map +1 -0
- package/dist/taskDelivery.d.ts +33 -0
- package/dist/taskDelivery.d.ts.map +1 -0
- package/dist/taskDelivery.js +67 -0
- package/dist/taskDelivery.js.map +1 -0
- package/dist/tui/app.d.ts +5 -0
- package/dist/tui/app.d.ts.map +1 -0
- package/dist/tui/app.js +130 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/index.d.ts +12 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +34 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/model.d.ts +110 -0
- package/dist/tui/model.d.ts.map +1 -0
- package/dist/tui/model.js +257 -0
- package/dist/tui/model.js.map +1 -0
- package/dist/tui/overlay.d.ts +66 -0
- package/dist/tui/overlay.d.ts.map +1 -0
- package/dist/tui/overlay.js +216 -0
- package/dist/tui/overlay.js.map +1 -0
- package/dist/tui/panes/account.d.ts +5 -0
- package/dist/tui/panes/account.d.ts.map +1 -0
- package/dist/tui/panes/account.js +108 -0
- package/dist/tui/panes/account.js.map +1 -0
- package/dist/tui/panes/agents.d.ts +9 -0
- package/dist/tui/panes/agents.d.ts.map +1 -0
- package/dist/tui/panes/agents.js +340 -0
- package/dist/tui/panes/agents.js.map +1 -0
- package/dist/tui/panes/chat.d.ts +14 -0
- package/dist/tui/panes/chat.d.ts.map +1 -0
- package/dist/tui/panes/chat.js +169 -0
- package/dist/tui/panes/chat.js.map +1 -0
- package/dist/tui/panes/environments.d.ts +6 -0
- package/dist/tui/panes/environments.d.ts.map +1 -0
- package/dist/tui/panes/environments.js +364 -0
- package/dist/tui/panes/environments.js.map +1 -0
- package/dist/tui/panes/jobs.d.ts +5 -0
- package/dist/tui/panes/jobs.d.ts.map +1 -0
- package/dist/tui/panes/jobs.js +104 -0
- package/dist/tui/panes/jobs.js.map +1 -0
- package/dist/tui/store.d.ts +40 -0
- package/dist/tui/store.d.ts.map +1 -0
- package/dist/tui/store.js +124 -0
- package/dist/tui/store.js.map +1 -0
- package/dist/tui/ui.d.ts +95 -0
- package/dist/tui/ui.d.ts.map +1 -0
- package/dist/tui/ui.js +144 -0
- package/dist/tui/ui.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { extname } from "node:path";
|
|
3
|
+
import { orgSlug, requireContext, run, } from "../context.js";
|
|
4
|
+
import { age, details, dim, emit, note, table } from "../output.js";
|
|
5
|
+
import { gated, resolveClient } from "./clients.js";
|
|
6
|
+
// The vault: API keys and other values agents receive by NAME at setup.
|
|
7
|
+
//
|
|
8
|
+
// echo "$HUBSPOT_KEY" | qoren secrets set HUBSPOT_API_KEY --client Acme
|
|
9
|
+
//
|
|
10
|
+
// A secret is agency-wide, or belongs to one of your clients (--client). The
|
|
11
|
+
// same name can be saved once agency-wide and once per client. An agent gets
|
|
12
|
+
// its own client's secret first, then the agency-wide one, and never another
|
|
13
|
+
// client's, so client B's agent can't end up with client A's key.
|
|
14
|
+
//
|
|
15
|
+
// Values go in on stdin, from --file, or with --value (which leaves the value
|
|
16
|
+
// in your shell history). They never come back out except through `reveal`,
|
|
17
|
+
// which is audited.
|
|
18
|
+
/** "all clients" for an agency-wide row, else the client's name. */
|
|
19
|
+
export const scopeLabel = (s) => s.customerId ? (s.customerName ?? s.customerId) : "all clients";
|
|
20
|
+
/** The agents a row is used by, two by name and the rest counted. */
|
|
21
|
+
export function usedByLabel(agents) {
|
|
22
|
+
if (agents.length === 0)
|
|
23
|
+
return "none";
|
|
24
|
+
const shown = agents.slice(0, 2).map((a) => a.name).join(", ");
|
|
25
|
+
return agents.length > 2 ? `${shown} +${agents.length - 2}` : shown;
|
|
26
|
+
}
|
|
27
|
+
/** The rows `secrets list` prints, narrowed to one client when asked: that
|
|
28
|
+
* client's own secrets plus the agency-wide ones its agents can fall back to,
|
|
29
|
+
* with the agency-wide row left out where the client has its own. */
|
|
30
|
+
export function secretsFor(rows, customerId) {
|
|
31
|
+
if (customerId === undefined)
|
|
32
|
+
return rows;
|
|
33
|
+
if (customerId === null)
|
|
34
|
+
return rows.filter((r) => !r.customerId);
|
|
35
|
+
const own = new Set(rows.filter((r) => r.customerId === customerId).map((r) => r.name));
|
|
36
|
+
return rows.filter((r) => r.customerId === customerId || (!r.customerId && !own.has(r.name)));
|
|
37
|
+
}
|
|
38
|
+
/** The scope a --client / --agency pair asks for: undefined = every scope. */
|
|
39
|
+
async function scopeOf(ctx, options) {
|
|
40
|
+
if (options.client && options.agency) {
|
|
41
|
+
throw new Error("Pass --client or --agency, not both.");
|
|
42
|
+
}
|
|
43
|
+
if (options.agency)
|
|
44
|
+
return { id: null, name: "all clients" };
|
|
45
|
+
if (!options.client)
|
|
46
|
+
return undefined;
|
|
47
|
+
const client = await resolveClient(ctx, options.client);
|
|
48
|
+
return { id: client.id, name: client.name };
|
|
49
|
+
}
|
|
50
|
+
async function readStdin() {
|
|
51
|
+
const chunks = [];
|
|
52
|
+
for await (const chunk of process.stdin) {
|
|
53
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk);
|
|
54
|
+
}
|
|
55
|
+
return Buffer.concat(chunks).toString("utf8").replace(/\r?\n$/, "");
|
|
56
|
+
}
|
|
57
|
+
export function secretsCommands(program, global) {
|
|
58
|
+
const secrets = program
|
|
59
|
+
.command("secrets")
|
|
60
|
+
.alias("secret")
|
|
61
|
+
.alias("vault")
|
|
62
|
+
.description("Keys your agents receive by name, agency-wide or per client");
|
|
63
|
+
secrets
|
|
64
|
+
.command("list")
|
|
65
|
+
.alias("ls")
|
|
66
|
+
.description("Secret names and who they belong to. Never values")
|
|
67
|
+
.option("--client <client>", "only what an agent of this client would get (id or exact name)")
|
|
68
|
+
.option("--agency", "only the agency-wide secrets")
|
|
69
|
+
.action((options) => run(async () => {
|
|
70
|
+
const ctx = requireContext(global());
|
|
71
|
+
const scope = await scopeOf(ctx, options);
|
|
72
|
+
const rows = secretsFor(await ctx.qoren.secrets.list(await orgSlug(ctx)), scope?.id);
|
|
73
|
+
emit(rows, () => {
|
|
74
|
+
if (scope)
|
|
75
|
+
note(dim(`As an agent of ${scope.name} sees them`));
|
|
76
|
+
table(rows, [
|
|
77
|
+
{ header: "name", value: (s) => s.name },
|
|
78
|
+
{ header: "client", value: (s) => scopeLabel(s) },
|
|
79
|
+
{ header: "kind", value: (s) => s.kind ?? "value" },
|
|
80
|
+
// Absent on a control plane older than the batched used-by list: leave the cell blank.
|
|
81
|
+
{ header: "used by", value: (s) => (s.usedBy ? usedByLabel(s.usedBy) : "") },
|
|
82
|
+
{ header: "description", value: (s) => s.description ?? "" },
|
|
83
|
+
{ header: "updated", value: (s) => age(s.updatedAt) },
|
|
84
|
+
]);
|
|
85
|
+
});
|
|
86
|
+
})());
|
|
87
|
+
secrets
|
|
88
|
+
.command("set <name>")
|
|
89
|
+
.description("Save or replace a secret. Reads the value from stdin unless --value or --file")
|
|
90
|
+
.option("--client <client>", "save it for one client only (id or exact name)")
|
|
91
|
+
.option("--value <value>", "the value (stays in your shell history; prefer stdin)")
|
|
92
|
+
.option("--file <path>", "store this file's contents as a file secret")
|
|
93
|
+
.option("--description <text>", "a note shown beside the name")
|
|
94
|
+
.action((name, options) => run(async () => {
|
|
95
|
+
const ctx = requireContext(global());
|
|
96
|
+
if (options.value !== undefined && options.file) {
|
|
97
|
+
throw new Error("Pass --value or --file, not both.");
|
|
98
|
+
}
|
|
99
|
+
let value;
|
|
100
|
+
if (options.file)
|
|
101
|
+
value = await readFile(options.file, "utf8");
|
|
102
|
+
else if (options.value !== undefined)
|
|
103
|
+
value = options.value;
|
|
104
|
+
else if (process.stdin.isTTY) {
|
|
105
|
+
throw new Error("Pipe the value on stdin, or pass --file or --value.");
|
|
106
|
+
}
|
|
107
|
+
else
|
|
108
|
+
value = await readStdin();
|
|
109
|
+
if (!value)
|
|
110
|
+
throw new Error("The value is empty.");
|
|
111
|
+
const scope = await scopeOf(ctx, { client: options.client });
|
|
112
|
+
const saved = (await gated(ctx.qoren.secrets.set(await orgSlug(ctx), {
|
|
113
|
+
name,
|
|
114
|
+
value,
|
|
115
|
+
description: options.description,
|
|
116
|
+
...(options.file
|
|
117
|
+
? { kind: "file", fileExt: extname(options.file).replace(/^\./, "") || undefined }
|
|
118
|
+
: {}),
|
|
119
|
+
customerId: scope?.id ?? null,
|
|
120
|
+
})));
|
|
121
|
+
emit(saved, () => details([
|
|
122
|
+
["Saved", saved.name],
|
|
123
|
+
["For", scopeLabel(saved)],
|
|
124
|
+
["Kind", saved.kind ?? "value"],
|
|
125
|
+
]));
|
|
126
|
+
})());
|
|
127
|
+
secrets
|
|
128
|
+
.command("rm <name>")
|
|
129
|
+
.alias("remove")
|
|
130
|
+
.description("Delete one secret. Agents that already have it keep their copy")
|
|
131
|
+
.option("--client <client>", "the client's secret (id or exact name); default is the agency-wide one")
|
|
132
|
+
.action((name, options) => run(async () => {
|
|
133
|
+
const ctx = requireContext(global());
|
|
134
|
+
const scope = await scopeOf(ctx, options);
|
|
135
|
+
const result = await ctx.qoren.secrets.remove(await orgSlug(ctx), name, scope?.id ?? null);
|
|
136
|
+
emit(result, () => note(`Deleted ${name.toUpperCase()} (${scope?.name ?? "all clients"}).`));
|
|
137
|
+
})());
|
|
138
|
+
secrets
|
|
139
|
+
.command("reveal <name>")
|
|
140
|
+
.description("Print one value. Every reveal is recorded in the audit log")
|
|
141
|
+
.option("--client <client>", "the client's secret (id or exact name); default is the agency-wide one")
|
|
142
|
+
.action((name, options) => run(async () => {
|
|
143
|
+
const ctx = requireContext(global());
|
|
144
|
+
const scope = await scopeOf(ctx, options);
|
|
145
|
+
const revealed = await ctx.qoren.secrets.reveal(await orgSlug(ctx), name, scope?.id ?? null);
|
|
146
|
+
emit(revealed, () => process.stdout.write(`${revealed.value}\n`));
|
|
147
|
+
})());
|
|
148
|
+
secrets
|
|
149
|
+
.command("used-by <name>")
|
|
150
|
+
.description("Agents that have this secret injected")
|
|
151
|
+
.option("--client <client>", "the client's secret (id or exact name); default is the agency-wide one")
|
|
152
|
+
.action((name, options) => run(async () => {
|
|
153
|
+
const ctx = requireContext(global());
|
|
154
|
+
const scope = await scopeOf(ctx, options);
|
|
155
|
+
const agents = await ctx.qoren.secrets.usedBy(await orgSlug(ctx), name, scope?.id ?? null);
|
|
156
|
+
emit(agents, () => table(agents, [
|
|
157
|
+
{ header: "id", value: (a) => a.id },
|
|
158
|
+
{ header: "agent", value: (a) => a.name },
|
|
159
|
+
{ header: "environment", value: (a) => a.machineName },
|
|
160
|
+
{ header: "status", value: (a) => a.status },
|
|
161
|
+
]));
|
|
162
|
+
})());
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/commands/secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/commands/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAgFxE,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,aAAa,QAwT5B"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { requireContext, run } from "../context.js";
|
|
2
|
+
import { age, bold, details, dim, emit, note, statusColor, table, warn, } from "../output.js";
|
|
3
|
+
// Webhook triggers: what wakes an agent when you are not there.
|
|
4
|
+
//
|
|
5
|
+
// The shape of the whole thing in one line:
|
|
6
|
+
//
|
|
7
|
+
// qoren webhook create <agent> --name "Bookings" --source cal \
|
|
8
|
+
// --event BOOKING_CREATED --rules "Add the attendee to the CRM and brief me."
|
|
9
|
+
//
|
|
10
|
+
// That prints a URL and a secret, once. Paste both into cal.com's webhook
|
|
11
|
+
// settings and the agent starts getting bookings.
|
|
12
|
+
//
|
|
13
|
+
// `deliveries` is the command you will actually live in: it says whether an
|
|
14
|
+
// event arrived, whether it was acted on, and if not, why not.
|
|
15
|
+
const SOURCES = [
|
|
16
|
+
"cal",
|
|
17
|
+
"github",
|
|
18
|
+
"stripe",
|
|
19
|
+
"generic",
|
|
20
|
+
"none",
|
|
21
|
+
];
|
|
22
|
+
function triggerTable(rows) {
|
|
23
|
+
table(rows, [
|
|
24
|
+
{ header: "id", value: (t) => t.id },
|
|
25
|
+
{ header: "name", value: (t) => t.name },
|
|
26
|
+
{ header: "source", value: (t) => t.source },
|
|
27
|
+
{ header: "status", value: (t) => statusColor(t.status) },
|
|
28
|
+
{ header: "events", value: (t) => t.events.join(", ") || "all" },
|
|
29
|
+
{ header: "autonomy", value: (t) => t.autonomy },
|
|
30
|
+
{ header: "deliveries", value: (t) => String(t.deliveryCount) },
|
|
31
|
+
{ header: "last", value: (t) => age(t.lastDeliveryAt) },
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
function deliveryTable(rows) {
|
|
35
|
+
table(rows, [
|
|
36
|
+
{ header: "id", value: (d) => d.id },
|
|
37
|
+
{ header: "event", value: (d) => d.eventType },
|
|
38
|
+
{ header: "status", value: (d) => statusColor(d.status) },
|
|
39
|
+
{ header: "summary", value: (d) => d.summary ?? d.error ?? "" },
|
|
40
|
+
{ header: "when", value: (d) => age(d.createdAt) },
|
|
41
|
+
]);
|
|
42
|
+
}
|
|
43
|
+
/** Print the URL and secret with the one instruction that matters: this is the
|
|
44
|
+
* only time either is readable. Goes to stderr via `note` so `--json` still
|
|
45
|
+
* pipes clean data — a script storing the secret reads it from the JSON. */
|
|
46
|
+
function printSecret(value, what) {
|
|
47
|
+
note(`${what}. Copy both of these into your webhook settings now:`);
|
|
48
|
+
details([
|
|
49
|
+
["URL", value.url],
|
|
50
|
+
["Secret", value.secret],
|
|
51
|
+
...(value.signatureHeader
|
|
52
|
+
? [["Signature header", value.signatureHeader]]
|
|
53
|
+
: []),
|
|
54
|
+
]);
|
|
55
|
+
warn("Neither is readable again. Lose them and you rotate.");
|
|
56
|
+
if (value.url.startsWith("/")) {
|
|
57
|
+
warn("That URL has no host: the control plane has no public URL configured. Fix that, then rotate to get a complete one.");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function webhookCommands(program, global) {
|
|
61
|
+
const webhook = program
|
|
62
|
+
.command("webhook")
|
|
63
|
+
.alias("webhooks")
|
|
64
|
+
.alias("trigger")
|
|
65
|
+
.description("Let an outside service wake an agent");
|
|
66
|
+
webhook
|
|
67
|
+
.command("sources")
|
|
68
|
+
.description("Services Qoren can receive webhooks from")
|
|
69
|
+
.action(() => run(async () => {
|
|
70
|
+
const ctx = requireContext(global());
|
|
71
|
+
const sources = await ctx.qoren.webhooks.sources();
|
|
72
|
+
emit(sources, () => table(sources, [
|
|
73
|
+
{ header: "source", value: (s) => s.source },
|
|
74
|
+
{ header: "name", value: (s) => s.label },
|
|
75
|
+
{ header: "verified", value: (s) => (s.verified ? "yes" : "no") },
|
|
76
|
+
{
|
|
77
|
+
header: "known events",
|
|
78
|
+
value: (s) => (s.events.length ? String(s.events.length) : "any"),
|
|
79
|
+
},
|
|
80
|
+
]));
|
|
81
|
+
})());
|
|
82
|
+
webhook
|
|
83
|
+
.command("ls <agentId>")
|
|
84
|
+
.alias("list")
|
|
85
|
+
.description("List an agent's triggers")
|
|
86
|
+
.action((agentId) => run(async () => {
|
|
87
|
+
const ctx = requireContext(global());
|
|
88
|
+
const triggers = await ctx.qoren.webhooks.list(agentId);
|
|
89
|
+
emit(triggers, () => triggers.length
|
|
90
|
+
? triggerTable(triggers)
|
|
91
|
+
: note(`No triggers yet. ${dim(`qoren webhook create ${agentId} --name … --source cal`)}`));
|
|
92
|
+
})());
|
|
93
|
+
webhook
|
|
94
|
+
.command("get <id>")
|
|
95
|
+
.description("Show one trigger")
|
|
96
|
+
.action((id) => run(async () => {
|
|
97
|
+
const ctx = requireContext(global());
|
|
98
|
+
const t = await ctx.qoren.webhooks.get(id);
|
|
99
|
+
emit(t, () => details([
|
|
100
|
+
["Id", t.id],
|
|
101
|
+
["Name", t.name],
|
|
102
|
+
["Agent", t.agentSlug ?? t.agentId],
|
|
103
|
+
["Source", t.source],
|
|
104
|
+
["Status", statusColor(t.status)],
|
|
105
|
+
["Events", t.events.join(", ") || "all"],
|
|
106
|
+
["Autonomy", t.autonomy],
|
|
107
|
+
["Rules", t.instructions ?? ""],
|
|
108
|
+
["Limit", `${t.maxPerHour}/hour`],
|
|
109
|
+
["Deliveries", `${t.deliveryCount} (${t.failureCount} failed)`],
|
|
110
|
+
["Last delivery", t.lastDeliveryAt ?? "never"],
|
|
111
|
+
]));
|
|
112
|
+
})());
|
|
113
|
+
webhook
|
|
114
|
+
.command("create <agentId>")
|
|
115
|
+
.description("Create a trigger and print its URL and secret")
|
|
116
|
+
.requiredOption("--name <name>", "what this trigger is for")
|
|
117
|
+
.option(`--source <source>`, SOURCES.join(" | "), "cal")
|
|
118
|
+
.option("--event <name...>", "only act on these events (repeatable; omit for all)")
|
|
119
|
+
.option("--rules <text>", "what the agent should do when this fires")
|
|
120
|
+
.option("--propose", "let the agent only propose actions, not take them")
|
|
121
|
+
.option("--max-per-hour <n>", "paid turns per hour before throttling")
|
|
122
|
+
.option("--secret <secret>", "the secret the sender already has")
|
|
123
|
+
.option("--header <name>", "custom source: header carrying the signature")
|
|
124
|
+
.option("--encoding <encoding>", "custom source: hex | base64")
|
|
125
|
+
.option("--prefix <prefix>", "custom source: signature prefix, e.g. sha256=")
|
|
126
|
+
.option("--event-path <path>", "custom source: path to the event name")
|
|
127
|
+
.action((agentId, options) => run(async () => {
|
|
128
|
+
const ctx = requireContext(global());
|
|
129
|
+
const body = {
|
|
130
|
+
name: options.name,
|
|
131
|
+
source: options.source,
|
|
132
|
+
...(options.event ? { events: options.event } : {}),
|
|
133
|
+
...(options.rules !== undefined
|
|
134
|
+
? { instructions: options.rules }
|
|
135
|
+
: {}),
|
|
136
|
+
...(options.propose ? { autonomy: "propose" } : {}),
|
|
137
|
+
...(options.maxPerHour !== undefined
|
|
138
|
+
? { maxPerHour: Number(options.maxPerHour) }
|
|
139
|
+
: {}),
|
|
140
|
+
...(options.secret !== undefined
|
|
141
|
+
? { secret: options.secret }
|
|
142
|
+
: {}),
|
|
143
|
+
...(options.header !== undefined
|
|
144
|
+
? { headerName: options.header }
|
|
145
|
+
: {}),
|
|
146
|
+
...(options.encoding !== undefined
|
|
147
|
+
? { encoding: options.encoding }
|
|
148
|
+
: {}),
|
|
149
|
+
...(options.prefix !== undefined
|
|
150
|
+
? { signaturePrefix: options.prefix }
|
|
151
|
+
: {}),
|
|
152
|
+
...(options.eventPath !== undefined
|
|
153
|
+
? { eventPath: options.eventPath }
|
|
154
|
+
: {}),
|
|
155
|
+
};
|
|
156
|
+
const created = await ctx.qoren.webhooks.create(agentId, body);
|
|
157
|
+
emit(created, () => {
|
|
158
|
+
printSecret(created, `Trigger ${bold(options.name)} created`);
|
|
159
|
+
if (!options.event?.length) {
|
|
160
|
+
warn("This trigger fires on every event the source sends, and each one is a paid agent turn. Narrow it with --event.");
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
})());
|
|
164
|
+
webhook
|
|
165
|
+
.command("rules <id> <text>")
|
|
166
|
+
.description("Rewrite what the agent should do when this trigger fires")
|
|
167
|
+
.action((id, text) => run(async () => {
|
|
168
|
+
const ctx = requireContext(global());
|
|
169
|
+
const t = await ctx.qoren.webhooks.update(id, { instructions: text });
|
|
170
|
+
emit(t, () => note(`Updated the rules for ${bold(t.name)}.`));
|
|
171
|
+
})());
|
|
172
|
+
webhook
|
|
173
|
+
.command("events <id> [names...]")
|
|
174
|
+
.description("Set which events this trigger acts on (none = all)")
|
|
175
|
+
.action((id, names) => run(async () => {
|
|
176
|
+
const ctx = requireContext(global());
|
|
177
|
+
const t = await ctx.qoren.webhooks.update(id, { events: names });
|
|
178
|
+
emit(t, () => note(names.length
|
|
179
|
+
? `${bold(t.name)} now acts on ${names.join(", ")}.`
|
|
180
|
+
: `${bold(t.name)} now acts on every event the source sends.`));
|
|
181
|
+
})());
|
|
182
|
+
webhook
|
|
183
|
+
.command("pause <id>")
|
|
184
|
+
.description("Stop deliveries without changing the URL")
|
|
185
|
+
.action((id) => run(async () => {
|
|
186
|
+
const ctx = requireContext(global());
|
|
187
|
+
const t = await ctx.qoren.webhooks.update(id, { status: "paused" });
|
|
188
|
+
emit(t, () => note(`${bold(t.name)} is paused. Its URL still answers, and ignores.`));
|
|
189
|
+
})());
|
|
190
|
+
webhook
|
|
191
|
+
.command("resume <id>")
|
|
192
|
+
.description("Start accepting deliveries again")
|
|
193
|
+
.action((id) => run(async () => {
|
|
194
|
+
const ctx = requireContext(global());
|
|
195
|
+
const t = await ctx.qoren.webhooks.update(id, { status: "active" });
|
|
196
|
+
emit(t, () => note(`${bold(t.name)} is live again.`));
|
|
197
|
+
})());
|
|
198
|
+
webhook
|
|
199
|
+
.command("rotate <id>")
|
|
200
|
+
.description("Issue a new URL and secret, invalidating the old pair")
|
|
201
|
+
.action((id) => run(async () => {
|
|
202
|
+
const ctx = requireContext(global());
|
|
203
|
+
const rotated = await ctx.qoren.webhooks.rotate(id);
|
|
204
|
+
emit(rotated, () => {
|
|
205
|
+
printSecret(rotated, "Rotated");
|
|
206
|
+
warn("The old URL now 404s, so the sender stops working until you paste these in.");
|
|
207
|
+
});
|
|
208
|
+
})());
|
|
209
|
+
webhook
|
|
210
|
+
.command("test <id>")
|
|
211
|
+
.description("Send a sample event through the real path")
|
|
212
|
+
.option("--event <name>", "event name to simulate")
|
|
213
|
+
.action((id, options) => run(async () => {
|
|
214
|
+
const ctx = requireContext(global());
|
|
215
|
+
const delivery = await ctx.qoren.webhooks.test(id, options.event !== undefined ? { eventType: options.event } : {});
|
|
216
|
+
emit(delivery, () => note(`Delivery ${bold(delivery.id)} is ${delivery.status}. ${dim(`qoren webhook delivery ${id} ${delivery.id}`)}`));
|
|
217
|
+
})());
|
|
218
|
+
webhook
|
|
219
|
+
.command("deliveries <id>")
|
|
220
|
+
.alias("log")
|
|
221
|
+
.description("What this trigger has received, newest first")
|
|
222
|
+
.option("--limit <n>", "how many to show", "20")
|
|
223
|
+
.action((id, options) => run(async () => {
|
|
224
|
+
const ctx = requireContext(global());
|
|
225
|
+
const rows = await ctx.qoren.webhooks.deliveries(id, Number(options.limit));
|
|
226
|
+
emit(rows, () => rows.length
|
|
227
|
+
? deliveryTable(rows)
|
|
228
|
+
: note("Nothing has arrived at this trigger yet."));
|
|
229
|
+
})());
|
|
230
|
+
webhook
|
|
231
|
+
.command("delivery <id> <deliveryId>")
|
|
232
|
+
.description("One delivery: the payload, the prompt, and the agent's reply")
|
|
233
|
+
.action((id, deliveryId) => run(async () => {
|
|
234
|
+
const ctx = requireContext(global());
|
|
235
|
+
const d = await ctx.qoren.webhooks.delivery(id, deliveryId);
|
|
236
|
+
emit(d, () => {
|
|
237
|
+
details([
|
|
238
|
+
["Id", d.delivery.id],
|
|
239
|
+
["Event", d.delivery.eventType],
|
|
240
|
+
["Status", statusColor(d.delivery.status)],
|
|
241
|
+
["Summary", d.delivery.summary ?? ""],
|
|
242
|
+
["Error", d.delivery.error ?? ""],
|
|
243
|
+
["Job", d.delivery.jobId ?? "never reached the agent"],
|
|
244
|
+
["Received", d.delivery.createdAt],
|
|
245
|
+
["Finished", d.delivery.finishedAt ?? ""],
|
|
246
|
+
]);
|
|
247
|
+
if (d.payload) {
|
|
248
|
+
note("Payload");
|
|
249
|
+
process.stdout.write(`${d.payload}\n`);
|
|
250
|
+
}
|
|
251
|
+
if (d.agentResult) {
|
|
252
|
+
note("The agent replied");
|
|
253
|
+
process.stdout.write(`${d.agentResult}\n`);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
})());
|
|
257
|
+
webhook
|
|
258
|
+
.command("replay <id> <deliveryId>")
|
|
259
|
+
.description("Run a past delivery's payload through the agent again")
|
|
260
|
+
.action((id, deliveryId) => run(async () => {
|
|
261
|
+
const ctx = requireContext(global());
|
|
262
|
+
const replayed = await ctx.qoren.webhooks.replay(id, deliveryId);
|
|
263
|
+
emit(replayed, () => note(`Replayed as delivery ${bold(replayed.id)}.`));
|
|
264
|
+
})());
|
|
265
|
+
webhook
|
|
266
|
+
.command("rm <id>")
|
|
267
|
+
.alias("delete")
|
|
268
|
+
.description("Delete a trigger and its delivery log")
|
|
269
|
+
.action((id) => run(async () => {
|
|
270
|
+
const ctx = requireContext(global());
|
|
271
|
+
const result = await ctx.qoren.webhooks.remove(id);
|
|
272
|
+
emit(result, () => note(`Removed ${bold(result.removed)}. Its URL now 404s.`));
|
|
273
|
+
})());
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/commands/webhook.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare const DEFAULT_BASE_URL = "https://qoren.sh";
|
|
2
|
+
export type Profile = {
|
|
3
|
+
token: string;
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
/** Cached from `GET /clients` so environment commands don't re-resolve the
|
|
6
|
+
* org's fleet tenant on every invocation. Refreshed on a miss. */
|
|
7
|
+
orgSlug?: string;
|
|
8
|
+
email?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function configDir(): string;
|
|
11
|
+
export declare function configPath(): string;
|
|
12
|
+
/** The name of the profile a command should use. */
|
|
13
|
+
export declare function profileName(explicit?: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* The credentials to run with, or null when there are none.
|
|
16
|
+
*
|
|
17
|
+
* Resolution order, highest first:
|
|
18
|
+
* 1. QOREN_TOKEN / QOREN_API_URL (CI, and any deliberate override)
|
|
19
|
+
* 2. --api-url (a flag beats stored config)
|
|
20
|
+
* 3. the named profile
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveProfile(options: {
|
|
23
|
+
profile?: string;
|
|
24
|
+
baseUrl?: string;
|
|
25
|
+
}): Profile | null;
|
|
26
|
+
/** The base URL to talk to even when there is no stored login (so `qoren login`
|
|
27
|
+
* knows where to send the browser). */
|
|
28
|
+
export declare function resolveBaseUrl(explicit?: string): string;
|
|
29
|
+
/** Store a profile and make it current. */
|
|
30
|
+
export declare function saveProfile(name: string, profile: Profile): void;
|
|
31
|
+
/** Update fields on an existing profile, e.g. caching the resolved org slug.
|
|
32
|
+
* A no-op when the profile isn't stored (an env-token session has no file). */
|
|
33
|
+
export declare function patchProfile(name: string, patch: Partial<Profile>): void;
|
|
34
|
+
/** Forget a profile. Returns false when there was nothing to forget. */
|
|
35
|
+
export declare function removeProfile(name: string): boolean;
|
|
36
|
+
/** Every stored profile name, for `qoren logout --all` and diagnostics. */
|
|
37
|
+
export declare function listProfiles(): string[];
|
|
38
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB;sEACkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAQF,wBAAgB,SAAS,IAAI,MAAM,CAGlC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAsBD,oDAAoD;AACpD,wBAAgB,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,GAAG,IAAI,CAgBjB;AAED;uCACuC;AACvC,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAOhE;AAED;+EAC+E;AAC/E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAQxE;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAWnD;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
// Where the CLI keeps its credentials.
|
|
5
|
+
//
|
|
6
|
+
// One file, `~/.config/qoren/config.json`, holding named profiles so a person
|
|
7
|
+
// who works across accounts can switch with --profile rather than logging out.
|
|
8
|
+
// It is written 0600 and its directory 0700: it holds bearer tokens, and a
|
|
9
|
+
// world-readable token is the same as a published one.
|
|
10
|
+
//
|
|
11
|
+
// Environment variables win over the file, always. That is what makes CI work
|
|
12
|
+
// without a login step, and it means a script can never accidentally pick up a
|
|
13
|
+
// developer's personal profile — set QOREN_TOKEN and the file is not consulted.
|
|
14
|
+
export const DEFAULT_BASE_URL = "https://qoren.sh";
|
|
15
|
+
export function configDir() {
|
|
16
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
17
|
+
return xdg ? join(xdg, "qoren") : join(homedir(), ".config", "qoren");
|
|
18
|
+
}
|
|
19
|
+
export function configPath() {
|
|
20
|
+
return join(configDir(), "config.json");
|
|
21
|
+
}
|
|
22
|
+
function readFile() {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(readFileSync(configPath(), "utf8"));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Missing, unreadable or corrupt all mean the same thing to a CLI: there is
|
|
28
|
+
// no stored login. Refusing to run would only strand someone whose file got
|
|
29
|
+
// truncated, when `qoren login` fixes it.
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function writeFileAtomically(config) {
|
|
34
|
+
const path = configPath();
|
|
35
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
36
|
+
writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
|
|
37
|
+
// writeFileSync's mode only applies when it CREATES the file, so an existing
|
|
38
|
+
// file keeps whatever permissions it had. Set them every time.
|
|
39
|
+
chmodSync(path, 0o600);
|
|
40
|
+
}
|
|
41
|
+
/** The name of the profile a command should use. */
|
|
42
|
+
export function profileName(explicit) {
|
|
43
|
+
return explicit ?? process.env.QOREN_PROFILE?.trim() ?? readFile().current ?? "default";
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The credentials to run with, or null when there are none.
|
|
47
|
+
*
|
|
48
|
+
* Resolution order, highest first:
|
|
49
|
+
* 1. QOREN_TOKEN / QOREN_API_URL (CI, and any deliberate override)
|
|
50
|
+
* 2. --api-url (a flag beats stored config)
|
|
51
|
+
* 3. the named profile
|
|
52
|
+
*/
|
|
53
|
+
export function resolveProfile(options) {
|
|
54
|
+
const envToken = process.env.QOREN_TOKEN?.trim();
|
|
55
|
+
const envUrl = process.env.QOREN_API_URL?.trim();
|
|
56
|
+
if (envToken) {
|
|
57
|
+
return {
|
|
58
|
+
token: envToken,
|
|
59
|
+
baseUrl: options.baseUrl ?? envUrl ?? DEFAULT_BASE_URL,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const stored = readFile().profiles?.[profileName(options.profile)];
|
|
63
|
+
if (!stored)
|
|
64
|
+
return null;
|
|
65
|
+
return {
|
|
66
|
+
...stored,
|
|
67
|
+
baseUrl: options.baseUrl ?? envUrl ?? stored.baseUrl ?? DEFAULT_BASE_URL,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** The base URL to talk to even when there is no stored login (so `qoren login`
|
|
71
|
+
* knows where to send the browser). */
|
|
72
|
+
export function resolveBaseUrl(explicit) {
|
|
73
|
+
return (explicit ??
|
|
74
|
+
process.env.QOREN_API_URL?.trim() ??
|
|
75
|
+
resolveProfile({})?.baseUrl ??
|
|
76
|
+
DEFAULT_BASE_URL);
|
|
77
|
+
}
|
|
78
|
+
/** Store a profile and make it current. */
|
|
79
|
+
export function saveProfile(name, profile) {
|
|
80
|
+
const config = readFile();
|
|
81
|
+
writeFileAtomically({
|
|
82
|
+
...config,
|
|
83
|
+
current: name,
|
|
84
|
+
profiles: { ...config.profiles, [name]: profile },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/** Update fields on an existing profile, e.g. caching the resolved org slug.
|
|
88
|
+
* A no-op when the profile isn't stored (an env-token session has no file). */
|
|
89
|
+
export function patchProfile(name, patch) {
|
|
90
|
+
const config = readFile();
|
|
91
|
+
const existing = config.profiles?.[name];
|
|
92
|
+
if (!existing)
|
|
93
|
+
return;
|
|
94
|
+
writeFileAtomically({
|
|
95
|
+
...config,
|
|
96
|
+
profiles: { ...config.profiles, [name]: { ...existing, ...patch } },
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/** Forget a profile. Returns false when there was nothing to forget. */
|
|
100
|
+
export function removeProfile(name) {
|
|
101
|
+
const config = readFile();
|
|
102
|
+
if (!config.profiles?.[name])
|
|
103
|
+
return false;
|
|
104
|
+
const profiles = { ...config.profiles };
|
|
105
|
+
delete profiles[name];
|
|
106
|
+
writeFileAtomically({
|
|
107
|
+
...config,
|
|
108
|
+
profiles,
|
|
109
|
+
...(config.current === name ? { current: undefined } : {}),
|
|
110
|
+
});
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
/** Every stored profile name, for `qoren logout --all` and diagnostics. */
|
|
114
|
+
export function listProfiles() {
|
|
115
|
+
return Object.keys(readFile().profiles ?? {});
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=config.js.map
|