@odla-ai/cli 0.25.9 → 0.25.11
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 -2
- package/dist/bin.cjs +82 -24
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-HXUVCUEM.js → chunk-FYSV7POZ.js} +83 -25
- package/dist/chunk-FYSV7POZ.js.map +1 -0
- package/dist/index.cjs +82 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-HXUVCUEM.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -5990,7 +5990,7 @@ Usage:
|
|
|
5990
5990
|
odla-ai pm handoff --app <id> [--json]
|
|
5991
5991
|
odla-ai discuss groups [--json]
|
|
5992
5992
|
odla-ai discuss list [--app <id>] [--q <text>] [--state open|resolved|all] [--json]
|
|
5993
|
-
odla-ai discuss read <topic> [--json]
|
|
5993
|
+
odla-ai discuss read <topic> [--limit <n> --offset <n>] [--json]
|
|
5994
5994
|
odla-ai discuss post --app <id> --subject "..." --body "..." [--markup "... @[Label](kind/id)"] [--mutation-id <id>]
|
|
5995
5995
|
odla-ai discuss reply <topic> --body "..." [--markup "..."] [--mutation-id <id>]
|
|
5996
5996
|
odla-ai discuss resolve <topic> [--reopen] [--mutation-id <id>]
|
|
@@ -8208,22 +8208,59 @@ async function discussList(ctx, parsed) {
|
|
|
8208
8208
|
}
|
|
8209
8209
|
});
|
|
8210
8210
|
}
|
|
8211
|
-
async function discussRead(ctx, id) {
|
|
8212
|
-
const
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8211
|
+
async function discussRead(ctx, id, parsed) {
|
|
8212
|
+
const requestedLimit = stringOpt(parsed.options.limit);
|
|
8213
|
+
const requestedOffset = stringOpt(parsed.options.offset);
|
|
8214
|
+
if (requestedLimit !== void 0 || requestedOffset !== void 0) {
|
|
8215
|
+
const query = new URLSearchParams({
|
|
8216
|
+
limit: requestedLimit ?? "200",
|
|
8217
|
+
offset: requestedOffset ?? "0"
|
|
8218
|
+
});
|
|
8219
|
+
const page = await request(ctx, "GET", `/topics/${encodeURIComponent(id)}?${query}`);
|
|
8220
|
+
emit(ctx, page, () => renderRead(ctx, page.topic, page.posts));
|
|
8221
|
+
return;
|
|
8222
|
+
}
|
|
8223
|
+
for (let scan = 0; scan < 3; scan++) {
|
|
8224
|
+
const posts = /* @__PURE__ */ new Map();
|
|
8225
|
+
let topic = null;
|
|
8226
|
+
let offset = 0;
|
|
8227
|
+
for (; ; ) {
|
|
8228
|
+
const page = await request(
|
|
8229
|
+
ctx,
|
|
8230
|
+
"GET",
|
|
8231
|
+
`/topics/${encodeURIComponent(id)}?limit=200&offset=${offset}`
|
|
8232
|
+
);
|
|
8233
|
+
topic = page.topic;
|
|
8234
|
+
for (const post of page.posts) posts.set(post.id, post);
|
|
8235
|
+
if (posts.size > 1e4) throw new Error("discuss read failed: conversation exceeds 10000 posts");
|
|
8236
|
+
if (!page.page?.hasMore) break;
|
|
8237
|
+
if (page.page.nextOffset === null || page.page.nextOffset <= offset) {
|
|
8238
|
+
throw new Error("discuss read failed: registry returned a non-advancing post page");
|
|
8239
|
+
}
|
|
8240
|
+
offset = page.page.nextOffset;
|
|
8225
8241
|
}
|
|
8226
|
-
|
|
8242
|
+
const ordered = [...posts.values()].sort(
|
|
8243
|
+
(a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
|
|
8244
|
+
);
|
|
8245
|
+
const expected = Number.isInteger(topic.replyCount) ? topic.replyCount + 1 : ordered.length;
|
|
8246
|
+
if (ordered.length === expected) {
|
|
8247
|
+
const result = { topic, posts: ordered };
|
|
8248
|
+
emit(ctx, result, () => renderRead(ctx, result.topic, result.posts));
|
|
8249
|
+
return;
|
|
8250
|
+
}
|
|
8251
|
+
if (offset === 0) throw new Error("discuss read failed: registry did not provide forward post pages");
|
|
8252
|
+
}
|
|
8253
|
+
throw new Error("discuss read failed: conversation changed during every complete-read attempt");
|
|
8254
|
+
}
|
|
8255
|
+
function renderRead(ctx, topic, posts) {
|
|
8256
|
+
ctx.out.log(`${topic.subject} [${state(topic)}] ${topic.appId ?? ""}`);
|
|
8257
|
+
for (const post of posts) {
|
|
8258
|
+
const who = post.authorKind === "bot" ? `${post.authorId} (agent)` : post.authorId;
|
|
8259
|
+
ctx.out.log(`
|
|
8260
|
+
\u2014 ${who}`);
|
|
8261
|
+
ctx.out.log(bodyWithRefs(post));
|
|
8262
|
+
for (const file of post.attachments ?? []) ctx.out.log(` [attachment] ${file.name} (${file.size} bytes)`);
|
|
8263
|
+
}
|
|
8227
8264
|
}
|
|
8228
8265
|
async function discussPost(ctx, parsed) {
|
|
8229
8266
|
const appId = stringOpt(parsed.options.app);
|
|
@@ -8550,7 +8587,7 @@ async function discussCommand(parsed, deps = {}) {
|
|
|
8550
8587
|
case "topics":
|
|
8551
8588
|
return discussList(ctx, parsed);
|
|
8552
8589
|
case "read":
|
|
8553
|
-
return discussRead(ctx, requireId(id, "read"));
|
|
8590
|
+
return discussRead(ctx, requireId(id, "read"), parsed);
|
|
8554
8591
|
case "post":
|
|
8555
8592
|
return discussPost(ctx, parsed);
|
|
8556
8593
|
case "reply":
|
|
@@ -8877,6 +8914,7 @@ function statusVerdict(reads) {
|
|
|
8877
8914
|
sourceHttp(reasons, "canary", reads.canary);
|
|
8878
8915
|
sourceHttp(reasons, "collector", reads.collector);
|
|
8879
8916
|
sourceHttp(reasons, "provider", reads.provider);
|
|
8917
|
+
sourceHttp(reasons, "provider", reads.providerHistory, "provider_history_");
|
|
8880
8918
|
const liveStatus = String(reads.liveSync.body.status ?? "");
|
|
8881
8919
|
if (liveStatus === "partial") {
|
|
8882
8920
|
reasons.push({
|
|
@@ -8948,6 +8986,14 @@ function statusVerdict(reads) {
|
|
|
8948
8986
|
severity: "degraded"
|
|
8949
8987
|
});
|
|
8950
8988
|
}
|
|
8989
|
+
const providerHistoryStatus = String(reads.providerHistory.body.status ?? "");
|
|
8990
|
+
if (providerHistoryStatus && providerHistoryStatus !== "observed" && providerHistoryStatus !== "no_data") {
|
|
8991
|
+
reasons.push({
|
|
8992
|
+
source: "provider",
|
|
8993
|
+
code: `provider_history_${providerHistoryStatus}`,
|
|
8994
|
+
severity: "degraded"
|
|
8995
|
+
});
|
|
8996
|
+
}
|
|
8951
8997
|
return {
|
|
8952
8998
|
status: reasons.some((reason) => reason.severity === "unhealthy") ? "unhealthy" : reasons.length > 0 ? "degraded" : "healthy",
|
|
8953
8999
|
reasons
|
|
@@ -8967,11 +9013,11 @@ function collectorReason(read3, fallback) {
|
|
|
8967
9013
|
);
|
|
8968
9014
|
return typeof first?.code === "string" && first.code ? first.code : fallback;
|
|
8969
9015
|
}
|
|
8970
|
-
function sourceHttp(reasons, source, read3) {
|
|
9016
|
+
function sourceHttp(reasons, source, read3, prefix = "") {
|
|
8971
9017
|
if (read3.httpStatus >= 200 && read3.httpStatus < 300) return;
|
|
8972
9018
|
reasons.push({
|
|
8973
9019
|
source,
|
|
8974
|
-
code:
|
|
9020
|
+
code: `${prefix}http_${read3.httpStatus}`,
|
|
8975
9021
|
severity: read3.httpStatus >= 500 && read3.httpStatus !== 501 ? "unhealthy" : "degraded"
|
|
8976
9022
|
});
|
|
8977
9023
|
}
|
|
@@ -9013,7 +9059,7 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
9013
9059
|
const base = `${cfg.platformUrl}/o11y/${encodeURIComponent(appId)}`;
|
|
9014
9060
|
const query = new URLSearchParams({ env, minutes: String(minutes) });
|
|
9015
9061
|
const headers = { authorization: `Bearer ${token}` };
|
|
9016
|
-
const [application, liveSync, canary, collector, provider] = await Promise.all([
|
|
9062
|
+
const [application, liveSync, canary, collector, provider, providerHistory] = await Promise.all([
|
|
9017
9063
|
read2(`${base}/metrics/red?${query}`, headers, doFetch),
|
|
9018
9064
|
read2(
|
|
9019
9065
|
`${base}/live-sync/health?${query}`,
|
|
@@ -9026,17 +9072,19 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
9026
9072
|
doFetch
|
|
9027
9073
|
),
|
|
9028
9074
|
read2(`${base}/self-health?${query}`, headers, doFetch),
|
|
9029
|
-
read2(`${base}/provider/cloudflare?${query}`, headers, doFetch)
|
|
9075
|
+
read2(`${base}/provider/cloudflare?${query}`, headers, doFetch),
|
|
9076
|
+
read2(`${base}/provider/cloudflare/history?${query}`, headers, doFetch)
|
|
9030
9077
|
]);
|
|
9031
9078
|
const verdict = statusVerdict({
|
|
9032
9079
|
application,
|
|
9033
9080
|
liveSync,
|
|
9034
9081
|
canary,
|
|
9035
9082
|
collector,
|
|
9036
|
-
provider
|
|
9083
|
+
provider,
|
|
9084
|
+
providerHistory
|
|
9037
9085
|
});
|
|
9038
9086
|
const status = {
|
|
9039
|
-
schemaVersion:
|
|
9087
|
+
schemaVersion: 5,
|
|
9040
9088
|
scope: { appId, env, minutes },
|
|
9041
9089
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9042
9090
|
verdict,
|
|
@@ -9044,7 +9092,8 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
9044
9092
|
liveSync,
|
|
9045
9093
|
canary,
|
|
9046
9094
|
collector,
|
|
9047
|
-
provider
|
|
9095
|
+
provider,
|
|
9096
|
+
providerHistory
|
|
9048
9097
|
};
|
|
9049
9098
|
if (parsed.options.json === true) {
|
|
9050
9099
|
out.log(JSON.stringify(status, null, 2));
|
|
@@ -9104,6 +9153,11 @@ function printStatus2(status, out) {
|
|
|
9104
9153
|
out.log(
|
|
9105
9154
|
`cloudflare ${status.provider.httpStatus} ${String(status.provider.body.status ?? status.provider.body.error ?? "unavailable")} ${numeric3(providerMetrics.requests)} invocations ${numeric3(providerMetrics.errors)} runtime errors`
|
|
9106
9155
|
);
|
|
9156
|
+
const providerPoints = Array.isArray(status.providerHistory.body.points) ? status.providerHistory.body.points.length : 0;
|
|
9157
|
+
const providerFreshness = record6(status.providerHistory.body.freshness) ? status.providerHistory.body.freshness : {};
|
|
9158
|
+
out.log(
|
|
9159
|
+
`cloudflare-history ${status.providerHistory.httpStatus} ${String(status.providerHistory.body.status ?? status.providerHistory.body.error ?? "unavailable")} ${providerPoints} snapshots ${optionalAge(providerFreshness.ageMs)} old`
|
|
9160
|
+
);
|
|
9107
9161
|
out.log(
|
|
9108
9162
|
`verdict ${status.verdict.status} ${status.verdict.reasons.map((reason) => `${reason.source}:${reason.code}`).join(", ") || "all required signals healthy"}`
|
|
9109
9163
|
);
|
|
@@ -9122,6 +9176,10 @@ function numeric3(value) {
|
|
|
9122
9176
|
function optionalNumeric(value) {
|
|
9123
9177
|
return typeof value === "number" && Number.isFinite(value) ? `${value} ms` : "\u2014";
|
|
9124
9178
|
}
|
|
9179
|
+
function optionalAge(value) {
|
|
9180
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return "unknown";
|
|
9181
|
+
return `${Math.max(0, Math.round(value / 1e3))}s`;
|
|
9182
|
+
}
|
|
9125
9183
|
|
|
9126
9184
|
// src/record.ts
|
|
9127
9185
|
import { appendFileSync } from "fs";
|
|
@@ -10713,4 +10771,4 @@ export {
|
|
|
10713
10771
|
exitCodeFor,
|
|
10714
10772
|
runCli
|
|
10715
10773
|
};
|
|
10716
|
-
//# sourceMappingURL=chunk-
|
|
10774
|
+
//# sourceMappingURL=chunk-FYSV7POZ.js.map
|