@odla-ai/cli 0.25.8 → 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 +13 -0
- package/dist/bin.cjs +201 -48
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-PM5FBL3S.js → chunk-HXUVCUEM.js} +202 -49
- package/dist/chunk-HXUVCUEM.js.map +1 -0
- package/dist/index.cjs +201 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-PM5FBL3S.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -4035,13 +4035,13 @@ async function createConversionRegistry(config) {
|
|
|
4035
4035
|
policies.set(policy.conversionId, Object.freeze(policy));
|
|
4036
4036
|
}
|
|
4037
4037
|
const outputCounts = /* @__PURE__ */ new Map();
|
|
4038
|
-
const
|
|
4038
|
+
const get = (id, kind) => {
|
|
4039
4039
|
const policy = policies.get(id);
|
|
4040
4040
|
if (!policy || policy.output.kind !== kind) throw new CamelError("conversion_rejected", "Conversion policy is missing or has the wrong output kind.");
|
|
4041
4041
|
return policy;
|
|
4042
4042
|
};
|
|
4043
4043
|
const checked = (source, id, kind) => {
|
|
4044
|
-
const policy =
|
|
4044
|
+
const policy = get(id, kind);
|
|
4045
4045
|
if (utf8Length(source.value) > policy.maximumSourceBytes) throw new CamelError("limit_exceeded", "Unsafe conversion input exceeds its byte bound.");
|
|
4046
4046
|
return policy;
|
|
4047
4047
|
};
|
|
@@ -5995,7 +5995,7 @@ Usage:
|
|
|
5995
5995
|
odla-ai discuss reply <topic> --body "..." [--markup "..."] [--mutation-id <id>]
|
|
5996
5996
|
odla-ai discuss resolve <topic> [--reopen] [--mutation-id <id>]
|
|
5997
5997
|
odla-ai discuss who --q <text> [--app <id>] [--kinds user,pm:task] [--json]
|
|
5998
|
-
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
5999
|
odla-ai agent jobs [--env dev] [--state pending|running|succeeded|dead_letter] [--limit 50] [--email <email>] [--json]
|
|
6000
6000
|
odla-ai agent retry <job-id> [--env dev] [--email <email>] [--json]
|
|
6001
6001
|
odla-ai o11y status [--app <id>] [--env prod] [--minutes 60] [--json]
|
|
@@ -8272,61 +8272,214 @@ async function discussWho(ctx, parsed) {
|
|
|
8272
8272
|
});
|
|
8273
8273
|
}
|
|
8274
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
|
+
|
|
8275
8351
|
// src/discuss-watch.ts
|
|
8276
8352
|
var DEFAULT_INTERVAL_MS = 15e3;
|
|
8277
|
-
var
|
|
8353
|
+
var MAX_CONSECUTIVE_FAILURES = 5;
|
|
8354
|
+
var MAX_BACKOFF_MS = 3e4;
|
|
8278
8355
|
function numberOpt2(parsed, flag, fallback) {
|
|
8279
8356
|
const raw = stringOpt(parsed.options[flag]);
|
|
8280
8357
|
const value = raw == null ? NaN : Number(raw);
|
|
8281
8358
|
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
8282
8359
|
}
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
headers: { authorization: `Bearer ${ctx.token}` }
|
|
8286
|
-
});
|
|
8287
|
-
const data = await res.json().catch(() => ({}));
|
|
8288
|
-
if (!res.ok) throw new Error(`discuss watch failed: ${data.error ?? `registry returned ${res.status}`}`);
|
|
8289
|
-
return data;
|
|
8360
|
+
function jsonl(ctx, parsed, value) {
|
|
8361
|
+
if (parsed.options.jsonl === true) ctx.out.log(JSON.stringify({ v: 1, ...value }));
|
|
8290
8362
|
}
|
|
8291
8363
|
async function discussWatch(ctx, topicId, parsed) {
|
|
8364
|
+
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
8292
8365
|
const sleep = ctx.sleep ?? ((ms) => new Promise((resolve11) => setTimeout(resolve11, ms)));
|
|
8293
8366
|
const now = ctx.now ?? Date.now;
|
|
8294
|
-
const intervalMs = numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) * 1e3;
|
|
8295
|
-
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;
|
|
8296
8370
|
const by = stringOpt(parsed.options.by);
|
|
8297
8371
|
const self = stringOpt(parsed.options.self);
|
|
8298
|
-
const
|
|
8299
|
-
|
|
8300
|
-
let
|
|
8301
|
-
let
|
|
8302
|
-
if (topicId) {
|
|
8303
|
-
const first = await get(ctx, `/topics/${encodeURIComponent(topicId)}`);
|
|
8304
|
-
seen = new Set(first.posts.map((post) => post.id));
|
|
8305
|
-
}
|
|
8372
|
+
const app = stringOpt(parsed.options.app);
|
|
8373
|
+
let cursor = stringOpt(parsed.options.cursor);
|
|
8374
|
+
let firstSuccess = true;
|
|
8375
|
+
let consecutiveFailures = 0;
|
|
8306
8376
|
for (; ; ) {
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
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
|
+
});
|
|
8321
8424
|
}
|
|
8322
|
-
|
|
8323
|
-
|
|
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
|
+
});
|
|
8455
|
+
}
|
|
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);
|
|
8324
8477
|
}
|
|
8325
8478
|
}
|
|
8326
|
-
function report2(ctx, result) {
|
|
8479
|
+
function report2(ctx, parsed, result) {
|
|
8327
8480
|
if (ctx.json) {
|
|
8328
8481
|
ctx.out.log(JSON.stringify(result, null, 2));
|
|
8329
|
-
} else if (result.found) {
|
|
8482
|
+
} else if (parsed.options.jsonl !== true && result.found) {
|
|
8330
8483
|
for (const post of result.posts ?? []) {
|
|
8331
8484
|
const who = post.authorKind === "bot" ? `${post.authorId} (agent)` : post.authorId;
|
|
8332
8485
|
ctx.out.log(`\u2014 ${who}
|
|
@@ -8338,13 +8491,6 @@ ${post.body}`);
|
|
|
8338
8491
|
}
|
|
8339
8492
|
return result;
|
|
8340
8493
|
}
|
|
8341
|
-
var WatchTimeoutError = class extends Error {
|
|
8342
|
-
code = "watch_timeout";
|
|
8343
|
-
constructor() {
|
|
8344
|
-
super("nothing new before the timeout");
|
|
8345
|
-
this.name = "WatchTimeoutError";
|
|
8346
|
-
}
|
|
8347
|
-
};
|
|
8348
8494
|
|
|
8349
8495
|
// src/discuss-command.ts
|
|
8350
8496
|
var ALLOWED = [
|
|
@@ -8366,6 +8512,8 @@ var ALLOWED = [
|
|
|
8366
8512
|
"self",
|
|
8367
8513
|
"interval",
|
|
8368
8514
|
"timeout",
|
|
8515
|
+
"cursor",
|
|
8516
|
+
"jsonl",
|
|
8369
8517
|
"mutation-id"
|
|
8370
8518
|
];
|
|
8371
8519
|
function requireId(id, action) {
|
|
@@ -8413,7 +8561,7 @@ async function discussCommand(parsed, deps = {}) {
|
|
|
8413
8561
|
return discussWho(ctx, parsed);
|
|
8414
8562
|
case "watch": {
|
|
8415
8563
|
const result = await discussWatch(ctx, id, parsed);
|
|
8416
|
-
if (!result.found) throw new WatchTimeoutError();
|
|
8564
|
+
if (!result.found) throw new WatchTimeoutError(result.cursor);
|
|
8417
8565
|
return;
|
|
8418
8566
|
}
|
|
8419
8567
|
default:
|
|
@@ -10377,7 +10525,12 @@ async function securityStatus(parsed, dependencies) {
|
|
|
10377
10525
|
// src/cli.ts
|
|
10378
10526
|
function exitCodeFor(err) {
|
|
10379
10527
|
const code = err?.code;
|
|
10380
|
-
|
|
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;
|
|
10381
10534
|
}
|
|
10382
10535
|
async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
10383
10536
|
const runtime = {
|
|
@@ -10560,4 +10713,4 @@ export {
|
|
|
10560
10713
|
exitCodeFor,
|
|
10561
10714
|
runCli
|
|
10562
10715
|
};
|
|
10563
|
-
//# sourceMappingURL=chunk-
|
|
10716
|
+
//# sourceMappingURL=chunk-HXUVCUEM.js.map
|