@odla-ai/cli 0.25.7 → 0.25.9
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 +24 -0
- package/dist/bin.cjs +294 -53
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-5U3EXWCR.js → chunk-HXUVCUEM.js} +295 -54
- package/dist/chunk-HXUVCUEM.js.map +1 -0
- package/dist/index.cjs +294 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/SKILL.md +4 -0
- package/dist/chunk-5U3EXWCR.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1617,6 +1617,7 @@ var CAPABILITIES = {
|
|
|
1617
1617
|
"apply Google Calendar booking config, then drive state-bound consent, status, discovery, and disconnect flows (bookings run live through the platform proxy)",
|
|
1618
1618
|
"validate integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes",
|
|
1619
1619
|
"read one versioned o11y status envelope spanning application RED, current live-sync freshness/load, the protected commit-to-visible canary, collector ingest/scheduler trust, provider-owned runtime metrics, and a bounded machine verdict",
|
|
1620
|
+
"inspect durable agent wakeups as a versioned JSON envelope and explicitly requeue one dead-lettered job with a scoped environment credential",
|
|
1620
1621
|
"run app-attributed hosted security discovery and independent validation without provider keys",
|
|
1621
1622
|
"connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys",
|
|
1622
1623
|
"let admins manage system AI policy and credentials, inspect attributed usage, and read immutable admin changes through separate short-lived capability-only approvals"
|
|
@@ -4034,13 +4035,13 @@ async function createConversionRegistry(config) {
|
|
|
4034
4035
|
policies.set(policy.conversionId, Object.freeze(policy));
|
|
4035
4036
|
}
|
|
4036
4037
|
const outputCounts = /* @__PURE__ */ new Map();
|
|
4037
|
-
const
|
|
4038
|
+
const get = (id, kind) => {
|
|
4038
4039
|
const policy = policies.get(id);
|
|
4039
4040
|
if (!policy || policy.output.kind !== kind) throw new CamelError("conversion_rejected", "Conversion policy is missing or has the wrong output kind.");
|
|
4040
4041
|
return policy;
|
|
4041
4042
|
};
|
|
4042
4043
|
const checked = (source, id, kind) => {
|
|
4043
|
-
const policy =
|
|
4044
|
+
const policy = get(id, kind);
|
|
4044
4045
|
if (utf8Length(source.value) > policy.maximumSourceBytes) throw new CamelError("limit_exceeded", "Unsafe conversion input exceeds its byte bound.");
|
|
4045
4046
|
return policy;
|
|
4046
4047
|
};
|
|
@@ -5994,7 +5995,9 @@ Usage:
|
|
|
5994
5995
|
odla-ai discuss reply <topic> --body "..." [--markup "..."] [--mutation-id <id>]
|
|
5995
5996
|
odla-ai discuss resolve <topic> [--reopen] [--mutation-id <id>]
|
|
5996
5997
|
odla-ai discuss who --q <text> [--app <id>] [--kinds user,pm:task] [--json]
|
|
5997
|
-
odla-ai discuss watch [<topic>] [--by <authorId>] [--self <authorId>] [--interval <s>] [--timeout <s>] [--json]
|
|
5998
|
+
odla-ai discuss watch [<topic>] [--cursor <cursor>] [--by <authorId>] [--self <authorId>] [--interval <s>] [--timeout <s>] [--json|--jsonl]
|
|
5999
|
+
odla-ai agent jobs [--env dev] [--state pending|running|succeeded|dead_letter] [--limit 50] [--email <email>] [--json]
|
|
6000
|
+
odla-ai agent retry <job-id> [--env dev] [--email <email>] [--json]
|
|
5998
6001
|
odla-ai o11y status [--app <id>] [--env prod] [--minutes 60] [--json]
|
|
5999
6002
|
odla-ai whoami [--json]
|
|
6000
6003
|
odla-ai runbook ask "<question>" [--app <id>] [--all] [--json]
|
|
@@ -6042,6 +6045,8 @@ Usage:
|
|
|
6042
6045
|
odla-ai version
|
|
6043
6046
|
|
|
6044
6047
|
Commands:
|
|
6048
|
+
agent Inspect durable agent wakeups and explicitly requeue a
|
|
6049
|
+
dead-lettered job; JSON output is stable for remote operators.
|
|
6045
6050
|
runbook odla's operational procedures, stored in the database and read at
|
|
6046
6051
|
the moment they are followed. "ask" gives a written, cited answer;
|
|
6047
6052
|
"search" the passages behind it; "get" the whole document.
|
|
@@ -6817,6 +6822,7 @@ var PM_ENTITIES = Object.fromEntries(
|
|
|
6817
6822
|
["goal", "conformance", "task", "kanban", "decision", "bug"].map((entity) => [entity, PM_ACTIONS])
|
|
6818
6823
|
);
|
|
6819
6824
|
var COMMAND_SURFACE = {
|
|
6825
|
+
agent: { jobs: {}, retry: {} },
|
|
6820
6826
|
admin: {
|
|
6821
6827
|
ai: {
|
|
6822
6828
|
show: {},
|
|
@@ -7353,11 +7359,6 @@ async function adminCommand(parsed) {
|
|
|
7353
7359
|
});
|
|
7354
7360
|
}
|
|
7355
7361
|
|
|
7356
|
-
// src/app-export.ts
|
|
7357
|
-
import { createWriteStream } from "fs";
|
|
7358
|
-
import { Readable } from "stream";
|
|
7359
|
-
import { pipeline } from "stream/promises";
|
|
7360
|
-
|
|
7361
7362
|
// src/tenant.ts
|
|
7362
7363
|
import { tenantIdFor as tenantIdFor5 } from "@odla-ai/apps";
|
|
7363
7364
|
function resolveEnv(cfg, requested) {
|
|
@@ -7382,7 +7383,90 @@ function bothTenants(cfg) {
|
|
|
7382
7383
|
return { sandbox: tenantIdFor5(cfg.app.id, "dev"), live: tenantIdFor5(cfg.app.id, "prod") };
|
|
7383
7384
|
}
|
|
7384
7385
|
|
|
7386
|
+
// src/agent-command.ts
|
|
7387
|
+
async function agentCommand(parsed, deps = {}) {
|
|
7388
|
+
const action = parsed.positionals[1];
|
|
7389
|
+
if (action !== "jobs" && action !== "retry") {
|
|
7390
|
+
throw new Error(`unknown agent action "${action ?? ""}". Try "odla-ai agent jobs --json".`);
|
|
7391
|
+
}
|
|
7392
|
+
assertArgs(parsed, ["config", "env", "state", "limit", "json", "token", "email"], action === "jobs" ? 2 : 3);
|
|
7393
|
+
if (action === "retry" && (parsed.options.state !== void 0 || parsed.options.limit !== void 0)) {
|
|
7394
|
+
throw new Error('--state and --limit are supported only by "agent jobs"');
|
|
7395
|
+
}
|
|
7396
|
+
const cfg = await loadProjectConfig(stringOpt(parsed.options.config) ?? "odla.config.mjs");
|
|
7397
|
+
const { env, tenant } = resolveTenant(cfg, stringOpt(parsed.options.env));
|
|
7398
|
+
const doFetch = deps.fetch ?? fetch;
|
|
7399
|
+
const out = deps.stdout ?? console;
|
|
7400
|
+
const credential2 = await getDeveloperToken(
|
|
7401
|
+
cfg,
|
|
7402
|
+
{
|
|
7403
|
+
configPath: cfg.configPath,
|
|
7404
|
+
token: stringOpt(parsed.options.token),
|
|
7405
|
+
email: stringOpt(parsed.options.email),
|
|
7406
|
+
open: false
|
|
7407
|
+
},
|
|
7408
|
+
doFetch,
|
|
7409
|
+
out
|
|
7410
|
+
);
|
|
7411
|
+
const base = `${cfg.dbEndpoint}/app/${encodeURIComponent(tenant)}/admin/agent-jobs`;
|
|
7412
|
+
const headers = { authorization: `Bearer ${credential2}` };
|
|
7413
|
+
if (action === "retry") {
|
|
7414
|
+
const id = parsed.positionals[2];
|
|
7415
|
+
const res2 = await doFetch(`${base}/${encodeURIComponent(id)}/retry`, { method: "POST", headers });
|
|
7416
|
+
const body2 = await readJson(res2);
|
|
7417
|
+
if (!res2.ok) throw new Error(`agent retry failed (${res2.status}): ${errorMessage(body2)}`);
|
|
7418
|
+
const result2 = { v: 1, appId: cfg.app.id, env, tenant, ...body2 };
|
|
7419
|
+
if (parsed.options.json === true) out.log(JSON.stringify(result2, null, 2));
|
|
7420
|
+
else out.log(`${tenant}: requeued ${id}`);
|
|
7421
|
+
return;
|
|
7422
|
+
}
|
|
7423
|
+
const state2 = stringOpt(parsed.options.state);
|
|
7424
|
+
const allowed = ["pending", "running", "succeeded", "dead_letter"];
|
|
7425
|
+
if (state2 && !allowed.includes(state2)) {
|
|
7426
|
+
throw new Error(`--state must be one of ${allowed.join(", ")}`);
|
|
7427
|
+
}
|
|
7428
|
+
const url = new URL(base);
|
|
7429
|
+
if (state2) url.searchParams.set("state", state2);
|
|
7430
|
+
const limit = numberOpt(parsed.options.limit, "--limit");
|
|
7431
|
+
if (limit) url.searchParams.set("limit", String(limit));
|
|
7432
|
+
const res = await doFetch(url, { headers });
|
|
7433
|
+
const body = await readJson(res);
|
|
7434
|
+
if (!res.ok) throw new Error(`agent jobs failed (${res.status}): ${errorMessage(body)}`);
|
|
7435
|
+
const result = { v: 1, appId: cfg.app.id, env, tenant, jobs: body.jobs ?? [], summary: body.summary };
|
|
7436
|
+
if (parsed.options.json === true) {
|
|
7437
|
+
out.log(JSON.stringify(result, null, 2));
|
|
7438
|
+
return;
|
|
7439
|
+
}
|
|
7440
|
+
const summary = body.summary;
|
|
7441
|
+
out.log(
|
|
7442
|
+
`${tenant}: ${summary?.pending ?? 0} pending, ${summary?.running ?? 0} running, ${summary?.deadLetter ?? 0} dead-letter, ${summary?.succeeded ?? 0} succeeded`
|
|
7443
|
+
);
|
|
7444
|
+
for (const job of body.jobs ?? []) {
|
|
7445
|
+
out.log(
|
|
7446
|
+
[job.state, job.id, job.triggerId, `${job.entityNs}/${job.entityId}`, `attempts=${job.attempts}`, job.lastErrorCode ?? ""].filter(Boolean).join(" ")
|
|
7447
|
+
);
|
|
7448
|
+
}
|
|
7449
|
+
}
|
|
7450
|
+
async function readJson(res) {
|
|
7451
|
+
try {
|
|
7452
|
+
return await res.json();
|
|
7453
|
+
} catch {
|
|
7454
|
+
return {};
|
|
7455
|
+
}
|
|
7456
|
+
}
|
|
7457
|
+
function errorMessage(body) {
|
|
7458
|
+
const error = body.error;
|
|
7459
|
+
if (typeof error === "string") return error;
|
|
7460
|
+
if (error && typeof error === "object" && typeof error.message === "string") {
|
|
7461
|
+
return error.message;
|
|
7462
|
+
}
|
|
7463
|
+
return "request failed";
|
|
7464
|
+
}
|
|
7465
|
+
|
|
7385
7466
|
// src/app-export.ts
|
|
7467
|
+
import { createWriteStream } from "fs";
|
|
7468
|
+
import { Readable } from "stream";
|
|
7469
|
+
import { pipeline } from "stream/promises";
|
|
7386
7470
|
async function appExport(options) {
|
|
7387
7471
|
const cfg = await loadProjectConfig(options.configPath);
|
|
7388
7472
|
const out = options.stdout ?? console;
|
|
@@ -8188,61 +8272,214 @@ async function discussWho(ctx, parsed) {
|
|
|
8188
8272
|
});
|
|
8189
8273
|
}
|
|
8190
8274
|
|
|
8275
|
+
// src/discuss-watch-http.ts
|
|
8276
|
+
var WatchRequestError = class extends Error {
|
|
8277
|
+
constructor(message2, retryable, status, code) {
|
|
8278
|
+
super(message2);
|
|
8279
|
+
this.retryable = retryable;
|
|
8280
|
+
this.status = status;
|
|
8281
|
+
this.code = code;
|
|
8282
|
+
this.name = "WatchRequestError";
|
|
8283
|
+
}
|
|
8284
|
+
retryable;
|
|
8285
|
+
status;
|
|
8286
|
+
code;
|
|
8287
|
+
};
|
|
8288
|
+
var WatchCheckpointError = class extends Error {
|
|
8289
|
+
constructor(cursor, streamId) {
|
|
8290
|
+
super("discussion cursor requires a new checkpoint");
|
|
8291
|
+
this.cursor = cursor;
|
|
8292
|
+
this.streamId = streamId;
|
|
8293
|
+
this.name = "WatchCheckpointError";
|
|
8294
|
+
}
|
|
8295
|
+
cursor;
|
|
8296
|
+
streamId;
|
|
8297
|
+
code = "checkpoint_required";
|
|
8298
|
+
};
|
|
8299
|
+
var WatchRemoteError = class extends Error {
|
|
8300
|
+
constructor(cursor, cause) {
|
|
8301
|
+
super("discussion watch dependency remained unavailable", { cause });
|
|
8302
|
+
this.cursor = cursor;
|
|
8303
|
+
this.name = "WatchRemoteError";
|
|
8304
|
+
}
|
|
8305
|
+
cursor;
|
|
8306
|
+
code = "remote_unavailable";
|
|
8307
|
+
};
|
|
8308
|
+
var WatchTimeoutError = class extends Error {
|
|
8309
|
+
constructor(cursor) {
|
|
8310
|
+
super("nothing new before the timeout");
|
|
8311
|
+
this.cursor = cursor;
|
|
8312
|
+
this.name = "WatchTimeoutError";
|
|
8313
|
+
}
|
|
8314
|
+
cursor;
|
|
8315
|
+
code = "watch_timeout";
|
|
8316
|
+
};
|
|
8317
|
+
function requestPath(topicId, app, cursor) {
|
|
8318
|
+
const params = new URLSearchParams();
|
|
8319
|
+
if (topicId) params.set("topic", topicId);
|
|
8320
|
+
if (app) params.set("app", app);
|
|
8321
|
+
if (cursor) params.set("cursor", cursor);
|
|
8322
|
+
return `/watch?${params}`;
|
|
8323
|
+
}
|
|
8324
|
+
async function getWatchPage(ctx, path) {
|
|
8325
|
+
let res;
|
|
8326
|
+
try {
|
|
8327
|
+
res = await ctx.doFetch(`${ctx.platformUrl}/registry/discuss${path}`, {
|
|
8328
|
+
headers: { authorization: `Bearer ${ctx.token}` }
|
|
8329
|
+
});
|
|
8330
|
+
} catch (error) {
|
|
8331
|
+
throw new WatchRequestError(
|
|
8332
|
+
`discuss watch request failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
8333
|
+
true
|
|
8334
|
+
);
|
|
8335
|
+
}
|
|
8336
|
+
const data = await res.json().catch(() => ({}));
|
|
8337
|
+
if (res.status === 409 && data.code === "checkpoint_required") {
|
|
8338
|
+
throw new WatchCheckpointError(data.cursor, data.streamId);
|
|
8339
|
+
}
|
|
8340
|
+
if (!res.ok) {
|
|
8341
|
+
throw new WatchRequestError(
|
|
8342
|
+
`discuss watch failed: ${data.error ?? `registry returned ${res.status}`}`,
|
|
8343
|
+
res.status === 429 || res.status >= 500,
|
|
8344
|
+
res.status,
|
|
8345
|
+
data.code ?? (res.status === 401 || res.status === 403 ? "auth_failed" : void 0)
|
|
8346
|
+
);
|
|
8347
|
+
}
|
|
8348
|
+
return data;
|
|
8349
|
+
}
|
|
8350
|
+
|
|
8191
8351
|
// src/discuss-watch.ts
|
|
8192
8352
|
var DEFAULT_INTERVAL_MS = 15e3;
|
|
8193
|
-
var
|
|
8353
|
+
var MAX_CONSECUTIVE_FAILURES = 5;
|
|
8354
|
+
var MAX_BACKOFF_MS = 3e4;
|
|
8194
8355
|
function numberOpt2(parsed, flag, fallback) {
|
|
8195
8356
|
const raw = stringOpt(parsed.options[flag]);
|
|
8196
8357
|
const value = raw == null ? NaN : Number(raw);
|
|
8197
8358
|
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
8198
8359
|
}
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
headers: { authorization: `Bearer ${ctx.token}` }
|
|
8202
|
-
});
|
|
8203
|
-
const data = await res.json().catch(() => ({}));
|
|
8204
|
-
if (!res.ok) throw new Error(`discuss watch failed: ${data.error ?? `registry returned ${res.status}`}`);
|
|
8205
|
-
return data;
|
|
8360
|
+
function jsonl(ctx, parsed, value) {
|
|
8361
|
+
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...value }));
|
|
8206
8362
|
}
|
|
8207
8363
|
async function discussWatch(ctx, topicId, parsed) {
|
|
8364
|
+
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
8208
8365
|
const sleep = ctx.sleep ?? ((ms) => new Promise((resolve11) => setTimeout(resolve11, ms)));
|
|
8209
8366
|
const now = ctx.now ?? Date.now;
|
|
8210
|
-
const intervalMs = numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) * 1e3;
|
|
8211
|
-
const
|
|
8367
|
+
const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
|
|
8368
|
+
const timeoutSeconds = numberOpt2(parsed, "timeout");
|
|
8369
|
+
const deadline = timeoutSeconds === void 0 ? void 0 : now() + timeoutSeconds * 1e3;
|
|
8212
8370
|
const by = stringOpt(parsed.options.by);
|
|
8213
8371
|
const self = stringOpt(parsed.options.self);
|
|
8214
|
-
const
|
|
8215
|
-
|
|
8216
|
-
let
|
|
8217
|
-
let
|
|
8218
|
-
if (topicId) {
|
|
8219
|
-
const first = await get(ctx, `/topics/${encodeURIComponent(topicId)}`);
|
|
8220
|
-
seen = new Set(first.posts.map((post) => post.id));
|
|
8221
|
-
}
|
|
8372
|
+
const app = stringOpt(parsed.options.app);
|
|
8373
|
+
let cursor = stringOpt(parsed.options.cursor);
|
|
8374
|
+
let firstSuccess = true;
|
|
8375
|
+
let consecutiveFailures = 0;
|
|
8222
8376
|
for (; ; ) {
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8377
|
+
let page;
|
|
8378
|
+
try {
|
|
8379
|
+
page = await getWatchPage(ctx, requestPath(topicId, app, cursor));
|
|
8380
|
+
consecutiveFailures = 0;
|
|
8381
|
+
} catch (error) {
|
|
8382
|
+
if (!(error instanceof WatchRequestError) || !error.retryable) {
|
|
8383
|
+
if (error instanceof WatchCheckpointError) {
|
|
8384
|
+
jsonl(ctx, parsed, {
|
|
8385
|
+
type: "status",
|
|
8386
|
+
state: "checkpoint_required",
|
|
8387
|
+
retryable: false,
|
|
8388
|
+
...error.cursor ? { cursor: error.cursor } : {},
|
|
8389
|
+
...error.streamId ? { streamId: error.streamId } : {}
|
|
8390
|
+
});
|
|
8391
|
+
}
|
|
8392
|
+
throw error;
|
|
8393
|
+
}
|
|
8394
|
+
consecutiveFailures++;
|
|
8395
|
+
jsonl(ctx, parsed, {
|
|
8396
|
+
type: "status",
|
|
8397
|
+
state: "degraded",
|
|
8398
|
+
retryable: true,
|
|
8399
|
+
attempt: consecutiveFailures,
|
|
8400
|
+
...cursor ? { cursor } : {},
|
|
8401
|
+
...error.status ? { status: error.status } : {}
|
|
8402
|
+
});
|
|
8403
|
+
if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
|
|
8404
|
+
throw new WatchRemoteError(cursor, error);
|
|
8405
|
+
}
|
|
8406
|
+
if (deadline !== void 0 && now() >= deadline) {
|
|
8407
|
+
const result = report2(ctx, parsed, { found: false, cursor: cursor ?? "" });
|
|
8408
|
+
throw new WatchTimeoutError(result.cursor);
|
|
8409
|
+
}
|
|
8410
|
+
const base = Math.min(intervalMs, 1e3);
|
|
8411
|
+
const backoff = Math.min(MAX_BACKOFF_MS, base * 2 ** (consecutiveFailures - 1));
|
|
8412
|
+
await sleep(deadline === void 0 ? backoff : Math.min(backoff, Math.max(0, deadline - now())));
|
|
8413
|
+
continue;
|
|
8414
|
+
}
|
|
8415
|
+
cursor = page.cursor;
|
|
8416
|
+
const baseline = firstSuccess && page.events.length === 0;
|
|
8417
|
+
if (baseline) {
|
|
8418
|
+
jsonl(ctx, parsed, {
|
|
8419
|
+
type: "checkpoint",
|
|
8420
|
+
streamId: page.streamId,
|
|
8421
|
+
cursor,
|
|
8422
|
+
serverTime: page.serverTime
|
|
8423
|
+
});
|
|
8424
|
+
}
|
|
8425
|
+
firstSuccess = false;
|
|
8426
|
+
const matching = page.events.filter((event) => {
|
|
8427
|
+
if (topicId && (event.type !== "message" || event.action !== "created")) return false;
|
|
8428
|
+
return (!by || event.actor.id === by) && (!self || event.actor.id !== self);
|
|
8429
|
+
});
|
|
8430
|
+
for (const event of matching) {
|
|
8431
|
+
jsonl(ctx, parsed, {
|
|
8432
|
+
type: "event",
|
|
8433
|
+
streamId: page.streamId,
|
|
8434
|
+
eventId: event.id,
|
|
8435
|
+
cursor: event.cursor,
|
|
8436
|
+
event
|
|
8437
|
+
});
|
|
8438
|
+
}
|
|
8439
|
+
if (matching.length > 0) {
|
|
8440
|
+
jsonl(ctx, parsed, {
|
|
8441
|
+
type: "checkpoint",
|
|
8442
|
+
streamId: page.streamId,
|
|
8443
|
+
cursor,
|
|
8444
|
+
serverTime: page.serverTime
|
|
8445
|
+
});
|
|
8446
|
+
const posts = topicId ? matching.filter((event) => event.type === "message").map((event) => event.payload) : void 0;
|
|
8447
|
+
const topics = topicId ? void 0 : matching.filter((event) => event.type === "activity").map((event) => event.payload);
|
|
8448
|
+
return report2(ctx, parsed, {
|
|
8449
|
+
found: true,
|
|
8450
|
+
cursor,
|
|
8451
|
+
events: matching,
|
|
8452
|
+
...posts && posts.length > 0 ? { posts } : {},
|
|
8453
|
+
...topics && topics.length > 0 ? { topics } : {}
|
|
8454
|
+
});
|
|
8237
8455
|
}
|
|
8238
|
-
if (
|
|
8239
|
-
|
|
8456
|
+
if (page.events.length > 0) {
|
|
8457
|
+
jsonl(ctx, parsed, {
|
|
8458
|
+
type: "checkpoint",
|
|
8459
|
+
streamId: page.streamId,
|
|
8460
|
+
cursor,
|
|
8461
|
+
serverTime: page.serverTime
|
|
8462
|
+
});
|
|
8463
|
+
} else if (!baseline) {
|
|
8464
|
+
jsonl(ctx, parsed, {
|
|
8465
|
+
type: "heartbeat",
|
|
8466
|
+
streamId: page.streamId,
|
|
8467
|
+
cursor,
|
|
8468
|
+
serverTime: page.serverTime
|
|
8469
|
+
});
|
|
8470
|
+
}
|
|
8471
|
+
if (page.hasMore) continue;
|
|
8472
|
+
if (deadline !== void 0 && now() >= deadline) {
|
|
8473
|
+
return report2(ctx, parsed, { found: false, cursor });
|
|
8474
|
+
}
|
|
8475
|
+
const wait2 = deadline === void 0 ? intervalMs : Math.min(intervalMs, Math.max(0, deadline - now()));
|
|
8476
|
+
await sleep(wait2);
|
|
8240
8477
|
}
|
|
8241
8478
|
}
|
|
8242
|
-
function report2(ctx, result) {
|
|
8479
|
+
function report2(ctx, parsed, result) {
|
|
8243
8480
|
if (ctx.json) {
|
|
8244
8481
|
ctx.out.log(JSON.stringify(result, null, 2));
|
|
8245
|
-
} else if (result.found) {
|
|
8482
|
+
} else if (parsed.options.jsonl !== true && result.found) {
|
|
8246
8483
|
for (const post of result.posts ?? []) {
|
|
8247
8484
|
const who = post.authorKind === "bot" ? `${post.authorId} (agent)` : post.authorId;
|
|
8248
8485
|
ctx.out.log(`\u2014 ${who}
|
|
@@ -8254,13 +8491,6 @@ ${post.body}`);
|
|
|
8254
8491
|
}
|
|
8255
8492
|
return result;
|
|
8256
8493
|
}
|
|
8257
|
-
var WatchTimeoutError = class extends Error {
|
|
8258
|
-
code = "watch_timeout";
|
|
8259
|
-
constructor() {
|
|
8260
|
-
super("nothing new before the timeout");
|
|
8261
|
-
this.name = "WatchTimeoutError";
|
|
8262
|
-
}
|
|
8263
|
-
};
|
|
8264
8494
|
|
|
8265
8495
|
// src/discuss-command.ts
|
|
8266
8496
|
var ALLOWED = [
|
|
@@ -8282,6 +8512,8 @@ var ALLOWED = [
|
|
|
8282
8512
|
"self",
|
|
8283
8513
|
"interval",
|
|
8284
8514
|
"timeout",
|
|
8515
|
+
"cursor",
|
|
8516
|
+
"jsonl",
|
|
8285
8517
|
"mutation-id"
|
|
8286
8518
|
];
|
|
8287
8519
|
function requireId(id, action) {
|
|
@@ -8329,7 +8561,7 @@ async function discussCommand(parsed, deps = {}) {
|
|
|
8329
8561
|
return discussWho(ctx, parsed);
|
|
8330
8562
|
case "watch": {
|
|
8331
8563
|
const result = await discussWatch(ctx, id, parsed);
|
|
8332
|
-
if (!result.found) throw new WatchTimeoutError();
|
|
8564
|
+
if (!result.found) throw new WatchTimeoutError(result.cursor);
|
|
8333
8565
|
return;
|
|
8334
8566
|
}
|
|
8335
8567
|
default:
|
|
@@ -10293,7 +10525,12 @@ async function securityStatus(parsed, dependencies) {
|
|
|
10293
10525
|
// src/cli.ts
|
|
10294
10526
|
function exitCodeFor(err) {
|
|
10295
10527
|
const code = err?.code;
|
|
10296
|
-
|
|
10528
|
+
if (code === "handshake_pending" || code === "watch_timeout") return 75;
|
|
10529
|
+
if (code === "checkpoint_required") return 3;
|
|
10530
|
+
if (code === "remote_unavailable") return 6;
|
|
10531
|
+
if (code === "auth_failed") return 5;
|
|
10532
|
+
if (code === "invalid_cursor") return 2;
|
|
10533
|
+
return 1;
|
|
10297
10534
|
}
|
|
10298
10535
|
async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
10299
10536
|
const runtime = {
|
|
@@ -10333,6 +10570,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
10333
10570
|
await adminCommand(parsed);
|
|
10334
10571
|
return;
|
|
10335
10572
|
}
|
|
10573
|
+
if (command === "agent") {
|
|
10574
|
+
await agentCommand(parsed, runtime);
|
|
10575
|
+
return;
|
|
10576
|
+
}
|
|
10336
10577
|
if (command === "app") {
|
|
10337
10578
|
await appCommand(parsed, runtime);
|
|
10338
10579
|
return;
|
|
@@ -10472,4 +10713,4 @@ export {
|
|
|
10472
10713
|
exitCodeFor,
|
|
10473
10714
|
runCli
|
|
10474
10715
|
};
|
|
10475
|
-
//# sourceMappingURL=chunk-
|
|
10716
|
+
//# sourceMappingURL=chunk-HXUVCUEM.js.map
|