@ora-ai/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 +21 -0
- package/README.md +102 -0
- package/dist/auth-commands.d.ts +39 -0
- package/dist/auth-commands.d.ts.map +1 -0
- package/dist/auth-commands.js +116 -0
- package/dist/auth-commands.js.map +1 -0
- package/dist/core/auth.d.ts +41 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +110 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/config.d.ts +26 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +51 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/http.d.ts +46 -0
- package/dist/core/http.d.ts.map +1 -0
- package/dist/core/http.js +82 -0
- package/dist/core/http.js.map +1 -0
- package/dist/core/login.d.ts +14 -0
- package/dist/core/login.d.ts.map +1 -0
- package/dist/core/login.js +70 -0
- package/dist/core/login.js.map +1 -0
- package/dist/core/output.d.ts +18 -0
- package/dist/core/output.d.ts.map +1 -0
- package/dist/core/output.js +94 -0
- package/dist/core/output.js.map +1 -0
- package/dist/core/run-operation.d.ts +57 -0
- package/dist/core/run-operation.d.ts.map +1 -0
- package/dist/core/run-operation.js +119 -0
- package/dist/core/run-operation.js.map +1 -0
- package/dist/core/sse.d.ts +13 -0
- package/dist/core/sse.d.ts.map +1 -0
- package/dist/core/sse.js +63 -0
- package/dist/core/sse.js.map +1 -0
- package/dist/generated/operations.d.ts +47 -0
- package/dist/generated/operations.d.ts.map +1 -0
- package/dist/generated/operations.js +2050 -0
- package/dist/generated/operations.js.map +1 -0
- package/dist/generated/types.d.ts +1039 -0
- package/dist/generated/types.d.ts.map +1 -0
- package/dist/generated/types.js +5 -0
- package/dist/generated/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive/derive-prompts.d.ts +44 -0
- package/dist/interactive/derive-prompts.d.ts.map +1 -0
- package/dist/interactive/derive-prompts.js +58 -0
- package/dist/interactive/derive-prompts.js.map +1 -0
- package/dist/interactive/inquirer-prompter.d.ts +11 -0
- package/dist/interactive/inquirer-prompter.d.ts.map +1 -0
- package/dist/interactive/inquirer-prompter.js +64 -0
- package/dist/interactive/inquirer-prompter.js.map +1 -0
- package/dist/interactive/menu.d.ts +25 -0
- package/dist/interactive/menu.d.ts.map +1 -0
- package/dist/interactive/menu.js +57 -0
- package/dist/interactive/menu.js.map +1 -0
- package/dist/interactive/prompter.d.ts +25 -0
- package/dist/interactive/prompter.d.ts.map +1 -0
- package/dist/interactive/prompter.js +14 -0
- package/dist/interactive/prompter.js.map +1 -0
- package/dist/interactive/session.d.ts +19 -0
- package/dist/interactive/session.d.ts.map +1 -0
- package/dist/interactive/session.js +204 -0
- package/dist/interactive/session.js.map +1 -0
- package/dist/program.d.ts +81 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +178 -0
- package/dist/program.js.map +1 -0
- package/dist/render/ansi.d.ts +13 -0
- package/dist/render/ansi.d.ts.map +1 -0
- package/dist/render/ansi.js +34 -0
- package/dist/render/ansi.js.map +1 -0
- package/dist/render/banner.d.ts +7 -0
- package/dist/render/banner.d.ts.map +1 -0
- package/dist/render/banner.js +18 -0
- package/dist/render/banner.js.map +1 -0
- package/dist/render/glyphs.d.ts +39 -0
- package/dist/render/glyphs.d.ts.map +1 -0
- package/dist/render/glyphs.js +83 -0
- package/dist/render/glyphs.js.map +1 -0
- package/dist/render/index.d.ts +13 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +24 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/insight-lines.d.ts +8 -0
- package/dist/render/insight-lines.d.ts.map +1 -0
- package/dist/render/insight-lines.js +62 -0
- package/dist/render/insight-lines.js.map +1 -0
- package/dist/render/insight.d.ts +9 -0
- package/dist/render/insight.d.ts.map +1 -0
- package/dist/render/insight.js +68 -0
- package/dist/render/insight.js.map +1 -0
- package/dist/render/journey-graph.d.ts +73 -0
- package/dist/render/journey-graph.d.ts.map +1 -0
- package/dist/render/journey-graph.js +250 -0
- package/dist/render/journey-graph.js.map +1 -0
- package/dist/render/journey.d.ts +14 -0
- package/dist/render/journey.d.ts.map +1 -0
- package/dist/render/journey.js +67 -0
- package/dist/render/journey.js.map +1 -0
- package/dist/render/live-panel.d.ts +34 -0
- package/dist/render/live-panel.d.ts.map +1 -0
- package/dist/render/live-panel.js +84 -0
- package/dist/render/live-panel.js.map +1 -0
- package/dist/render/mode.d.ts +19 -0
- package/dist/render/mode.d.ts.map +1 -0
- package/dist/render/mode.js +23 -0
- package/dist/render/mode.js.map +1 -0
- package/dist/render/registry.d.ts +17 -0
- package/dist/render/registry.d.ts.map +1 -0
- package/dist/render/registry.js +34 -0
- package/dist/render/registry.js.map +1 -0
- package/dist/render/run-list.d.ts +11 -0
- package/dist/render/run-list.d.ts.map +1 -0
- package/dist/render/run-list.js +53 -0
- package/dist/render/run-list.js.map +1 -0
- package/dist/render/spinner.d.ts +14 -0
- package/dist/render/spinner.d.ts.map +1 -0
- package/dist/render/spinner.js +37 -0
- package/dist/render/spinner.js.map +1 -0
- package/dist/render/table.d.ts +20 -0
- package/dist/render/table.d.ts.map +1 -0
- package/dist/render/table.js +29 -0
- package/dist/render/table.js.map +1 -0
- package/dist/render/trajectory.d.ts +19 -0
- package/dist/render/trajectory.d.ts.map +1 -0
- package/dist/render/trajectory.js +75 -0
- package/dist/render/trajectory.js.map +1 -0
- package/dist/render/tunnel.d.ts +10 -0
- package/dist/render/tunnel.d.ts.map +1 -0
- package/dist/render/tunnel.js +108 -0
- package/dist/render/tunnel.js.map +1 -0
- package/dist/render/usage.d.ts +29 -0
- package/dist/render/usage.d.ts.map +1 -0
- package/dist/render/usage.js +83 -0
- package/dist/render/usage.js.map +1 -0
- package/dist/tunnel-command.d.ts +15 -0
- package/dist/tunnel-command.d.ts.map +1 -0
- package/dist/tunnel-command.js +267 -0
- package/dist/tunnel-command.js.map +1 -0
- package/dist/watch.d.ts +53 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +305 -0
- package/dist/watch.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of the CLI's rich-mode visual language: the brand accent
|
|
3
|
+
* color and the glyph set Task 6's renderers draw event streams with.
|
|
4
|
+
*
|
|
5
|
+
* The accent purple (#7C3AED) matches the internal dev CLI's brand color
|
|
6
|
+
* (utils/ora-dev-cli/src/lib/ui) — same company, same look — but this module
|
|
7
|
+
* takes NONE of that CLI's dependencies (figlet, inquirer, npm's `ora`
|
|
8
|
+
* spinner package): chalk is enough for a hex color and a \r-rewrite.
|
|
9
|
+
*/
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
export const accent = chalk.hex("#7C3AED");
|
|
12
|
+
export const GLYPHS = {
|
|
13
|
+
thought: "◇",
|
|
14
|
+
tool: "⚙",
|
|
15
|
+
ok: "✔",
|
|
16
|
+
error: "✖",
|
|
17
|
+
stageDone: "●",
|
|
18
|
+
stageRunning: "◐",
|
|
19
|
+
stagePending: "○",
|
|
20
|
+
};
|
|
21
|
+
/** Maps a stream/event kind (step/trajectory/result/insight/run) to its glyph. */
|
|
22
|
+
export function eventGlyph(event) {
|
|
23
|
+
switch (event) {
|
|
24
|
+
case "step":
|
|
25
|
+
return GLYPHS.tool;
|
|
26
|
+
case "trajectory":
|
|
27
|
+
return GLYPHS.thought;
|
|
28
|
+
case "result":
|
|
29
|
+
return GLYPHS.ok;
|
|
30
|
+
case "insight":
|
|
31
|
+
return GLYPHS.stageDone;
|
|
32
|
+
case "run":
|
|
33
|
+
return GLYPHS.stageRunning;
|
|
34
|
+
default:
|
|
35
|
+
return GLYPHS.stagePending;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Maps a run/agent lifecycle STATUS to its glyph, distinguishing success from
|
|
40
|
+
* failure — run-list.ts's status column. Shared here (not duplicated in
|
|
41
|
+
* run-list.ts) because journey.ts needs the SAME "is this terminal/running/
|
|
42
|
+
* pending" reading, just without the success/failure split (see
|
|
43
|
+
* `progressGlyph` below). An unrecognized status degrades to `stagePending`
|
|
44
|
+
* rather than throwing — a CLI must never crash on a value it doesn't know
|
|
45
|
+
* about yet.
|
|
46
|
+
*/
|
|
47
|
+
export function outcomeGlyph(status) {
|
|
48
|
+
switch (status) {
|
|
49
|
+
case "succeeded":
|
|
50
|
+
return GLYPHS.ok;
|
|
51
|
+
case "failed":
|
|
52
|
+
case "error":
|
|
53
|
+
case "timeout":
|
|
54
|
+
return GLYPHS.error;
|
|
55
|
+
case "running":
|
|
56
|
+
case "started":
|
|
57
|
+
case "in_progress":
|
|
58
|
+
return GLYPHS.stageRunning;
|
|
59
|
+
default:
|
|
60
|
+
return GLYPHS.stagePending;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Maps a journey stage's (agent run's) status to its PROGRESS marker only —
|
|
65
|
+
* done vs running vs not-started, never success vs failure: a journey stage
|
|
66
|
+
* marker answers "did this agent finish", and the outcome (succeeded/failed)
|
|
67
|
+
* is printed alongside the marker, not folded into it. See journey.ts.
|
|
68
|
+
*/
|
|
69
|
+
export function progressGlyph(status) {
|
|
70
|
+
switch (status) {
|
|
71
|
+
case "succeeded":
|
|
72
|
+
case "failed":
|
|
73
|
+
case "completed":
|
|
74
|
+
return GLYPHS.stageDone;
|
|
75
|
+
case "running":
|
|
76
|
+
case "started":
|
|
77
|
+
case "in_progress":
|
|
78
|
+
return GLYPHS.stageRunning;
|
|
79
|
+
default:
|
|
80
|
+
return GLYPHS.stagePending;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=glyphs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glyphs.js","sourceRoot":"","sources":["../../src/render/glyphs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAE3C,MAAM,CAAC,MAAM,MAAM,GAQf;IACF,OAAO,EAAE,GAAG;IACZ,IAAI,EAAE,GAAG;IACT,EAAE,EAAE,GAAG;IACP,KAAK,EAAE,GAAG;IACV,SAAS,EAAE,GAAG;IACd,YAAY,EAAE,GAAG;IACjB,YAAY,EAAE,GAAG;CAClB,CAAC;AAEF,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,MAAM;YACT,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,KAAK,YAAY;YACf,OAAO,MAAM,CAAC,OAAO,CAAC;QACxB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC,SAAS,CAAC;QAC1B,KAAK,KAAK;YACR,OAAO,MAAM,CAAC,YAAY,CAAC;QAC7B;YACE,OAAO,MAAM,CAAC,YAAY,CAAC;IAC/B,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,WAAW;YACd,OAAO,MAAM,CAAC,EAAE,CAAC;QACnB,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC,KAAK,CAAC;QACtB,KAAK,SAAS,CAAC;QACf,KAAK,SAAS,CAAC;QACf,KAAK,aAAa;YAChB,OAAO,MAAM,CAAC,YAAY,CAAC;QAC7B;YACE,OAAO,MAAM,CAAC,YAAY,CAAC;IAC/B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,QAAQ,CAAC;QACd,KAAK,WAAW;YACd,OAAO,MAAM,CAAC,SAAS,CAAC;QAC1B,KAAK,SAAS,CAAC;QACf,KAAK,SAAS,CAAC;QACf,KAAK,aAAa;YAChB,OAAO,MAAM,CAAC,YAAY,CAAC;QAC7B;YACE,OAAO,MAAM,CAAC,YAAY,CAAC;IAC/B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect registration for the rich-renderer registry (see registry.ts's
|
|
3
|
+
* Registry-of-Strategies note). core/output.ts imports this module for its
|
|
4
|
+
* side effects ONLY — never a named export — so a normal program boot is
|
|
5
|
+
* enough to populate the registry exactly once.
|
|
6
|
+
*
|
|
7
|
+
* Registration order IS match priority (registry.ts: first canRender wins).
|
|
8
|
+
* The four captured shapes are mutually exclusive (see renderers.test.ts's
|
|
9
|
+
* rejection matrix), so today's order doesn't change any outcome — it is
|
|
10
|
+
* pinned anyway as the documented contract for the next renderer added here.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect registration for the rich-renderer registry (see registry.ts's
|
|
3
|
+
* Registry-of-Strategies note). core/output.ts imports this module for its
|
|
4
|
+
* side effects ONLY — never a named export — so a normal program boot is
|
|
5
|
+
* enough to populate the registry exactly once.
|
|
6
|
+
*
|
|
7
|
+
* Registration order IS match priority (registry.ts: first canRender wins).
|
|
8
|
+
* The four captured shapes are mutually exclusive (see renderers.test.ts's
|
|
9
|
+
* rejection matrix), so today's order doesn't change any outcome — it is
|
|
10
|
+
* pinned anyway as the documented contract for the next renderer added here.
|
|
11
|
+
*/
|
|
12
|
+
import { insightRenderer } from "./insight.js";
|
|
13
|
+
import { journeyRenderer } from "./journey.js";
|
|
14
|
+
import { registerRenderer } from "./registry.js";
|
|
15
|
+
import { runListRenderer } from "./run-list.js";
|
|
16
|
+
import { tunnelCardRenderer, tunnelListRenderer } from "./tunnel.js";
|
|
17
|
+
import { trajectoryRenderer } from "./trajectory.js";
|
|
18
|
+
registerRenderer(trajectoryRenderer);
|
|
19
|
+
registerRenderer(insightRenderer);
|
|
20
|
+
registerRenderer(journeyRenderer);
|
|
21
|
+
registerRenderer(runListRenderer);
|
|
22
|
+
registerRenderer(tunnelListRenderer);
|
|
23
|
+
registerRenderer(tunnelCardRenderer);
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;AACrC,gBAAgB,CAAC,eAAe,CAAC,CAAC;AAClC,gBAAgB,CAAC,eAAe,CAAC,CAAC;AAClC,gBAAgB,CAAC,eAAe,CAAC,CAAC;AAClC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;AACrC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The run-finale insight section, in the reference visual style
|
|
3
|
+
* (eralabs-ai/ora-cli): a Visibility gauge bar, the summary flowed dim, and
|
|
4
|
+
* Friction / Recommendations lists with priority dots. Used for the stream's
|
|
5
|
+
* `insight` event; the one-shot `runs insight` command keeps the box card.
|
|
6
|
+
*/
|
|
7
|
+
export declare function insightLines(raw: unknown): string[];
|
|
8
|
+
//# sourceMappingURL=insight-lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insight-lines.d.ts","sourceRoot":"","sources":["../../src/render/insight-lines.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA6BH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAoCnD"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The run-finale insight section, in the reference visual style
|
|
3
|
+
* (eralabs-ai/ora-cli): a Visibility gauge bar, the summary flowed dim, and
|
|
4
|
+
* Friction / Recommendations lists with priority dots. Used for the stream's
|
|
5
|
+
* `insight` event; the one-shot `runs insight` command keeps the box card.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { flow, stdoutWidth } from "./ansi.js";
|
|
9
|
+
const wide = () => stdoutWidth(60, 120);
|
|
10
|
+
function gauge(score, cells = 22) {
|
|
11
|
+
const bound = Math.min(100, Math.max(0, score));
|
|
12
|
+
const lit = Math.round((bound / 100) * cells);
|
|
13
|
+
const paint = bound >= 70 ? chalk.green : bound >= 50 ? chalk.yellow : chalk.red;
|
|
14
|
+
return paint("█".repeat(lit)) + chalk.dim("░".repeat(cells - lit));
|
|
15
|
+
}
|
|
16
|
+
function priorityDot(priority) {
|
|
17
|
+
if (priority === "high")
|
|
18
|
+
return chalk.red("● high ");
|
|
19
|
+
if (priority === "medium")
|
|
20
|
+
return chalk.yellow("● medium");
|
|
21
|
+
if (priority === "low")
|
|
22
|
+
return chalk.dim("● low ");
|
|
23
|
+
return chalk.dim("● ");
|
|
24
|
+
}
|
|
25
|
+
export function insightLines(raw) {
|
|
26
|
+
const insight = (typeof raw === "object" && raw !== null ? raw : {});
|
|
27
|
+
const rows = [""];
|
|
28
|
+
if (typeof insight.visibility_score === "number") {
|
|
29
|
+
const score = insight.visibility_score;
|
|
30
|
+
const paint = score >= 70 ? chalk.green : score >= 50 ? chalk.yellow : chalk.red;
|
|
31
|
+
const verdict = insight.intent_satisfied
|
|
32
|
+
? chalk.green("✓ intent satisfied")
|
|
33
|
+
: chalk.yellow("✗ intent not satisfied");
|
|
34
|
+
rows.push(` ${chalk.bold("Visibility")} ${gauge(score)} ${paint(chalk.bold(`${score}/100`))} ${verdict}`);
|
|
35
|
+
}
|
|
36
|
+
if (typeof insight.summary === "string" && insight.summary) {
|
|
37
|
+
rows.push("");
|
|
38
|
+
for (const line of flow(insight.summary, wide() - 4))
|
|
39
|
+
rows.push(` ${chalk.dim(line)}`);
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(insight.friction_points) && insight.friction_points.length) {
|
|
42
|
+
rows.push("", ` ${chalk.bold("Friction")}`);
|
|
43
|
+
for (const point of insight.friction_points) {
|
|
44
|
+
const [first, ...rest] = flow(String(point), wide() - 6);
|
|
45
|
+
rows.push(` ${chalk.yellow("·")} ${first}`);
|
|
46
|
+
for (const line of rest)
|
|
47
|
+
rows.push(` ${line}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(insight.recommendations) && insight.recommendations.length) {
|
|
51
|
+
rows.push("", ` ${chalk.bold("Recommendations")}`);
|
|
52
|
+
for (const rec of insight.recommendations) {
|
|
53
|
+
const r = (typeof rec === "object" && rec !== null ? rec : {});
|
|
54
|
+
rows.push(` ${priorityDot(r.priority)} ${chalk.bold(String(r.title ?? ""))}`);
|
|
55
|
+
for (const line of flow(String(r.detail ?? ""), wide() - 8))
|
|
56
|
+
rows.push(` ${chalk.dim(line)}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
rows.push("");
|
|
60
|
+
return rows;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=insight-lines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insight-lines.js","sourceRoot":"","sources":["../../src/render/insight-lines.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rich renderer for a run's stored insight artifact (`GET .../runs/:id/insight`
|
|
3
|
+
* — insight-service's analytical write-up). A box-drawn card: title, wrapped
|
|
4
|
+
* summary, outcome/visibility line, and a verdict line (satisfied/not, with
|
|
5
|
+
* its glyph) — the one thing a human scanning many runs wants first.
|
|
6
|
+
*/
|
|
7
|
+
import type { Renderer } from "./registry.js";
|
|
8
|
+
export declare const insightRenderer: Renderer;
|
|
9
|
+
//# sourceMappingURL=insight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insight.d.ts","sourceRoot":"","sources":["../../src/render/insight.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAqE9C,eAAO,MAAM,eAAe,EAAE,QAI7B,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rich renderer for a run's stored insight artifact (`GET .../runs/:id/insight`
|
|
3
|
+
* — insight-service's analytical write-up). A box-drawn card: title, wrapped
|
|
4
|
+
* summary, outcome/visibility line, and a verdict line (satisfied/not, with
|
|
5
|
+
* its glyph) — the one thing a human scanning many runs wants first.
|
|
6
|
+
*/
|
|
7
|
+
import { GLYPHS, accent } from "./glyphs.js";
|
|
8
|
+
const WIDTH = 72;
|
|
9
|
+
const INNER = WIDTH - 4;
|
|
10
|
+
const TOP = `┌${"─".repeat(WIDTH - 2)}┐`;
|
|
11
|
+
const BOTTOM = `└${"─".repeat(WIDTH - 2)}┘`;
|
|
12
|
+
const DIVIDER = `├${"─".repeat(WIDTH - 2)}┤`;
|
|
13
|
+
/**
|
|
14
|
+
* `visibility_score` + `intent_satisfied` + `summary` together are unique to
|
|
15
|
+
* the insight artifact — trajectory carries no score/verdict fields, and
|
|
16
|
+
* journey/run-list carry neither. Pinned on the live-captured fixture
|
|
17
|
+
* (__fixtures__/insight.json).
|
|
18
|
+
*/
|
|
19
|
+
function isInsight(data) {
|
|
20
|
+
if (typeof data !== "object" || data === null)
|
|
21
|
+
return false;
|
|
22
|
+
const d = data;
|
|
23
|
+
return (typeof d.visibility_score === "number" && typeof d.intent_satisfied === "boolean" && typeof d.summary === "string");
|
|
24
|
+
}
|
|
25
|
+
/** Greedy word-wrap to `width` columns — good enough for a fixed-width card, no hyphenation. */
|
|
26
|
+
function wrap(text, width) {
|
|
27
|
+
const lines = [];
|
|
28
|
+
let cur = "";
|
|
29
|
+
for (const word of text.split(/\s+/)) {
|
|
30
|
+
const next = cur ? `${cur} ${word}` : word;
|
|
31
|
+
if (next.length > width && cur) {
|
|
32
|
+
lines.push(cur);
|
|
33
|
+
cur = word;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
cur = next;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (cur)
|
|
40
|
+
lines.push(cur);
|
|
41
|
+
return lines;
|
|
42
|
+
}
|
|
43
|
+
// Padding is computed on the PLAIN text, then the color is applied — chalk's
|
|
44
|
+
// ANSI codes are zero-width in a real terminal, so coloring after padding
|
|
45
|
+
// keeps the box's right border aligned regardless of chalk.level.
|
|
46
|
+
function boxLine(text, colorFn = (s) => s) {
|
|
47
|
+
const clipped = text.length > INNER ? text.slice(0, INNER) : text;
|
|
48
|
+
return `│ ${colorFn(clipped.padEnd(INNER))} │`;
|
|
49
|
+
}
|
|
50
|
+
function render(data) {
|
|
51
|
+
const d = data;
|
|
52
|
+
const verdict = d.intent_satisfied ? `${GLYPHS.ok} satisfied` : `${GLYPHS.error} not satisfied`;
|
|
53
|
+
return [
|
|
54
|
+
TOP,
|
|
55
|
+
boxLine(`Insight — ${d.intent}`, accent.bold),
|
|
56
|
+
DIVIDER,
|
|
57
|
+
...wrap(d.summary, INNER).map((line) => boxLine(line)),
|
|
58
|
+
boxLine(`Outcome: ${d.outcome} Visibility: ${d.visibility_score}`),
|
|
59
|
+
boxLine(`Verdict: ${verdict}`),
|
|
60
|
+
BOTTOM,
|
|
61
|
+
].join("\n");
|
|
62
|
+
}
|
|
63
|
+
export const insightRenderer = {
|
|
64
|
+
name: "insight",
|
|
65
|
+
canRender: isInsight,
|
|
66
|
+
render,
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=insight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insight.js","sourceRoot":"","sources":["../../src/render/insight.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The journey GRAPH — the same picture the ora product shows, in the
|
|
3
|
+
* terminal: the intent at the root (◆), every tool action as a rounded box
|
|
4
|
+
* beneath it, and edges taken from ora's own per-step attribution rather than
|
|
5
|
+
* guessed. The agent's reasoning shows up in the graph itself as (…) markers
|
|
6
|
+
* on the edge above the action it produced.
|
|
7
|
+
*
|
|
8
|
+
* Ported from the standalone eralabs-ai/ora-cli renderer, adapted to the
|
|
9
|
+
* platform's trajectory step shape (`@ora/trace-normalize` TrajectoryData
|
|
10
|
+
* steps — the `runs.trajectory` artifact and the run stream's `step` events).
|
|
11
|
+
*
|
|
12
|
+
* Two deliberate choices, learned from user feedback on the product:
|
|
13
|
+
* · No synthetic "homepage" node — it would claim a fetch that never
|
|
14
|
+
* happened. A real homepage fetch appears as an ordinary fetch box.
|
|
15
|
+
* · Reasoning is placed, not just counted.
|
|
16
|
+
*/
|
|
17
|
+
/** The step fields the graph reads — structural, every field optional-safe. */
|
|
18
|
+
export interface GraphStep {
|
|
19
|
+
id?: unknown;
|
|
20
|
+
type?: unknown;
|
|
21
|
+
kind?: unknown;
|
|
22
|
+
tool?: unknown;
|
|
23
|
+
action?: unknown;
|
|
24
|
+
input?: unknown;
|
|
25
|
+
input_display?: unknown;
|
|
26
|
+
output_structured?: unknown;
|
|
27
|
+
attribution?: unknown;
|
|
28
|
+
thinking?: unknown;
|
|
29
|
+
text?: unknown;
|
|
30
|
+
elapsed_ms?: unknown;
|
|
31
|
+
}
|
|
32
|
+
export type NodeTone = "root" | "ok" | "redirect" | "error" | "active";
|
|
33
|
+
export interface GraphNode {
|
|
34
|
+
id: number;
|
|
35
|
+
kind: "intent" | "search" | "fetch";
|
|
36
|
+
icon: string;
|
|
37
|
+
label: string;
|
|
38
|
+
meta?: string;
|
|
39
|
+
tone: NodeTone;
|
|
40
|
+
/** One-line reasoning notes attached above this box. */
|
|
41
|
+
notes: string[];
|
|
42
|
+
children: GraphNode[];
|
|
43
|
+
}
|
|
44
|
+
export interface JourneyTree {
|
|
45
|
+
root: GraphNode;
|
|
46
|
+
/** Reasoning with no action after it yet — drawn under the graph. */
|
|
47
|
+
looseNotes: string[];
|
|
48
|
+
}
|
|
49
|
+
/** Pull host + path out of free-form text like `GET https://x.dev/docs`. */
|
|
50
|
+
export declare function splitUrl(text?: string): {
|
|
51
|
+
host?: string;
|
|
52
|
+
path?: string;
|
|
53
|
+
};
|
|
54
|
+
export declare function isSearchStep(step: GraphStep): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* One pass over the trajectory. Reasoning queues up and attaches to the next
|
|
57
|
+
* action's box. Parents are picked strongest-signal-first:
|
|
58
|
+
* 1. attribution.referrer.step_id — ora's explicit "found on step N" edge
|
|
59
|
+
* 2. attribution.kind "web_search" → newest search box
|
|
60
|
+
* 3. attribution.kind "previous_artifact" → previous fetch box
|
|
61
|
+
* 4. anything else (prior knowledge, direct) → the intent root
|
|
62
|
+
* Searches always hang off the root.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildJourneyTree(steps: GraphStep[], intent: string, settled: boolean): JourneyTree;
|
|
65
|
+
/** "9 steps · 3 reasoning · 1 search" — zero parts omitted (except the total). */
|
|
66
|
+
export declare function journeySummary(steps: GraphStep[]): string;
|
|
67
|
+
/** Does a stream event payload look like a real trajectory step? (The graph
|
|
68
|
+
* only takes over for genuine steps — anything else keeps the glyph line.) */
|
|
69
|
+
export declare function isTrajectoryStep(data: unknown): data is GraphStep;
|
|
70
|
+
/** Present-tense caption for whatever the agent is doing right now. */
|
|
71
|
+
export declare function activityLabel(step: GraphStep): string;
|
|
72
|
+
export declare function drawJourneyTree(tree: JourneyTree): string[];
|
|
73
|
+
//# sourceMappingURL=journey-graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journey-graph.d.ts","sourceRoot":"","sources":["../../src/render/journey-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,+EAA+E;AAC/E,MAAM,WAAW,SAAS;IACxB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEvE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,wDAAwD;IACxD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,SAAS,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,qEAAqE;IACrE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAIxE;AAOD,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAErD;AA6DD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,EAAE,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACf,WAAW,CA+Db;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CAOzD;AAsDD;+EAC+E;AAC/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,SAAS,CAIjE;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAWrD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE,CAO3D"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The journey GRAPH — the same picture the ora product shows, in the
|
|
3
|
+
* terminal: the intent at the root (◆), every tool action as a rounded box
|
|
4
|
+
* beneath it, and edges taken from ora's own per-step attribution rather than
|
|
5
|
+
* guessed. The agent's reasoning shows up in the graph itself as (…) markers
|
|
6
|
+
* on the edge above the action it produced.
|
|
7
|
+
*
|
|
8
|
+
* Ported from the standalone eralabs-ai/ora-cli renderer, adapted to the
|
|
9
|
+
* platform's trajectory step shape (`@ora/trace-normalize` TrajectoryData
|
|
10
|
+
* steps — the `runs.trajectory` artifact and the run stream's `step` events).
|
|
11
|
+
*
|
|
12
|
+
* Two deliberate choices, learned from user feedback on the product:
|
|
13
|
+
* · No synthetic "homepage" node — it would claim a fetch that never
|
|
14
|
+
* happened. A real homepage fetch appears as an ordinary fetch box.
|
|
15
|
+
* · Reasoning is placed, not just counted.
|
|
16
|
+
*/
|
|
17
|
+
import chalk from "chalk";
|
|
18
|
+
import { squeeze, stdoutWidth } from "./ansi.js";
|
|
19
|
+
/** Pull host + path out of free-form text like `GET https://x.dev/docs`. */
|
|
20
|
+
export function splitUrl(text) {
|
|
21
|
+
if (!text)
|
|
22
|
+
return {};
|
|
23
|
+
const hit = text.match(/https?:\/\/([^/\s]+)(\/\S*)?/i);
|
|
24
|
+
return hit ? { host: hit[1], path: hit[2] ?? "/" } : {};
|
|
25
|
+
}
|
|
26
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
27
|
+
const num = (v) => (typeof v === "number" ? v : undefined);
|
|
28
|
+
const rec = (v) => typeof v === "object" && v !== null ? v : undefined;
|
|
29
|
+
export function isSearchStep(step) {
|
|
30
|
+
return /search/i.test(`${str(step.tool) ?? ""} ${str(step.action) ?? ""}`);
|
|
31
|
+
}
|
|
32
|
+
// ⚠ Icon set is fixed on purpose: 🔍 🌐 📄 have .length === 2 AND occupy two
|
|
33
|
+
// columns, while ◆ is 1/1 — so plain .length still equals display width and
|
|
34
|
+
// the box borders line up. Vet any new icon against both properties.
|
|
35
|
+
function iconFor(step) {
|
|
36
|
+
if (isSearchStep(step))
|
|
37
|
+
return "🔍";
|
|
38
|
+
const hint = `${str(step.tool) ?? ""} ${str(step.action) ?? ""}`.toLowerCase();
|
|
39
|
+
if (/fetch|http|get/.test(hint))
|
|
40
|
+
return "🌐";
|
|
41
|
+
if (/read|open|view/.test(hint))
|
|
42
|
+
return "📄";
|
|
43
|
+
return "🌐";
|
|
44
|
+
}
|
|
45
|
+
function nodeFor(step, labelCap, deltaMs) {
|
|
46
|
+
const id = num(step.id) ?? -2;
|
|
47
|
+
const input = rec(step.input);
|
|
48
|
+
const outputStructured = rec(step.output_structured);
|
|
49
|
+
if (isSearchStep(step)) {
|
|
50
|
+
const query = str(step.input_display) ?? str(input?.query) ?? "search";
|
|
51
|
+
const links = outputStructured?.links;
|
|
52
|
+
const hits = Array.isArray(links) ? links.length : undefined;
|
|
53
|
+
return {
|
|
54
|
+
id,
|
|
55
|
+
kind: "search",
|
|
56
|
+
icon: "🔍",
|
|
57
|
+
label: squeeze(`"${query}"`, labelCap),
|
|
58
|
+
meta: hits ? `${hits} results` : undefined,
|
|
59
|
+
tone: "ok",
|
|
60
|
+
notes: [],
|
|
61
|
+
children: [],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const { host, path } = splitUrl(str(step.input_display) ?? str(input?.url) ?? "");
|
|
65
|
+
const code = num(outputStructured?.status);
|
|
66
|
+
const bounced = code != null && code >= 300 && code < 400;
|
|
67
|
+
const failed = code != null && code >= 400;
|
|
68
|
+
let meta;
|
|
69
|
+
if (bounced)
|
|
70
|
+
meta = `↳ ${code}`;
|
|
71
|
+
else if (failed)
|
|
72
|
+
meta = `✗ ${code}`;
|
|
73
|
+
else {
|
|
74
|
+
const chips = ["✓"];
|
|
75
|
+
if (code)
|
|
76
|
+
chips.push(String(code));
|
|
77
|
+
if (deltaMs != null && deltaMs > 0)
|
|
78
|
+
chips.push(`${(deltaMs / 1000).toFixed(1)}s`);
|
|
79
|
+
meta = chips.join(" ");
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
id,
|
|
83
|
+
kind: "fetch",
|
|
84
|
+
icon: iconFor(step),
|
|
85
|
+
label: squeeze(`${host ?? "?"}${path ?? ""}`, labelCap),
|
|
86
|
+
meta,
|
|
87
|
+
tone: bounced ? "redirect" : failed ? "error" : "ok",
|
|
88
|
+
notes: [],
|
|
89
|
+
children: [],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* One pass over the trajectory. Reasoning queues up and attaches to the next
|
|
94
|
+
* action's box. Parents are picked strongest-signal-first:
|
|
95
|
+
* 1. attribution.referrer.step_id — ora's explicit "found on step N" edge
|
|
96
|
+
* 2. attribution.kind "web_search" → newest search box
|
|
97
|
+
* 3. attribution.kind "previous_artifact" → previous fetch box
|
|
98
|
+
* 4. anything else (prior knowledge, direct) → the intent root
|
|
99
|
+
* Searches always hang off the root.
|
|
100
|
+
*/
|
|
101
|
+
export function buildJourneyTree(steps, intent, settled) {
|
|
102
|
+
const wide = stdoutWidth(60, 120);
|
|
103
|
+
const labelCap = Math.min(52, Math.max(24, wide - 40));
|
|
104
|
+
const noteCap = Math.max(30, wide - 24);
|
|
105
|
+
const root = {
|
|
106
|
+
id: -1,
|
|
107
|
+
kind: "intent",
|
|
108
|
+
icon: "◆",
|
|
109
|
+
label: squeeze(intent, noteCap),
|
|
110
|
+
tone: "root",
|
|
111
|
+
notes: [],
|
|
112
|
+
children: [],
|
|
113
|
+
};
|
|
114
|
+
const nodesByStep = new Map();
|
|
115
|
+
let queuedNotes = [];
|
|
116
|
+
let recentSearch;
|
|
117
|
+
let recentFetch;
|
|
118
|
+
let newest;
|
|
119
|
+
let prevElapsed;
|
|
120
|
+
for (const step of steps) {
|
|
121
|
+
if (step.type === "text" && step.kind === "reasoning") {
|
|
122
|
+
const note = (str(step.thinking) ?? str(step.text) ?? "").trim();
|
|
123
|
+
if (note)
|
|
124
|
+
queuedNotes.push(squeeze(note, noteCap));
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (step.type !== "tool_call")
|
|
128
|
+
continue;
|
|
129
|
+
const elapsed = num(step.elapsed_ms);
|
|
130
|
+
const deltaMs = elapsed != null && prevElapsed != null ? elapsed - prevElapsed : undefined;
|
|
131
|
+
if (elapsed != null)
|
|
132
|
+
prevElapsed = elapsed;
|
|
133
|
+
const node = nodeFor(step, labelCap, deltaMs);
|
|
134
|
+
node.notes = queuedNotes;
|
|
135
|
+
queuedNotes = [];
|
|
136
|
+
const stepId = num(step.id);
|
|
137
|
+
if (stepId != null)
|
|
138
|
+
nodesByStep.set(stepId, node);
|
|
139
|
+
let parent = root;
|
|
140
|
+
if (!isSearchStep(step)) {
|
|
141
|
+
const attribution = rec(step.attribution);
|
|
142
|
+
const referrer = rec(attribution?.referrer);
|
|
143
|
+
const refStep = num(referrer?.step_id);
|
|
144
|
+
const via = str(attribution?.kind);
|
|
145
|
+
const referred = refStep != null ? nodesByStep.get(refStep) : undefined;
|
|
146
|
+
if (referred && referred !== node)
|
|
147
|
+
parent = referred;
|
|
148
|
+
else if (via === "web_search" && recentSearch)
|
|
149
|
+
parent = recentSearch;
|
|
150
|
+
else if (via === "previous_artifact" && recentFetch)
|
|
151
|
+
parent = recentFetch;
|
|
152
|
+
}
|
|
153
|
+
parent.children.push(node);
|
|
154
|
+
if (isSearchStep(step))
|
|
155
|
+
recentSearch = node;
|
|
156
|
+
else
|
|
157
|
+
recentFetch = node;
|
|
158
|
+
newest = node;
|
|
159
|
+
}
|
|
160
|
+
if (newest && !settled) {
|
|
161
|
+
newest.tone = "active";
|
|
162
|
+
newest.meta = "…";
|
|
163
|
+
}
|
|
164
|
+
return { root, looseNotes: queuedNotes };
|
|
165
|
+
}
|
|
166
|
+
/** "9 steps · 3 reasoning · 1 search" — zero parts omitted (except the total). */
|
|
167
|
+
export function journeySummary(steps) {
|
|
168
|
+
const thinking = steps.filter((s) => s.kind === "reasoning").length;
|
|
169
|
+
const searching = steps.filter((s) => s.type === "tool_call" && isSearchStep(s)).length;
|
|
170
|
+
const parts = [`${chalk.bold(String(steps.length))} steps`];
|
|
171
|
+
if (thinking)
|
|
172
|
+
parts.push(`${chalk.bold(String(thinking))} reasoning`);
|
|
173
|
+
if (searching)
|
|
174
|
+
parts.push(`${chalk.bold(String(searching))} search${searching === 1 ? "" : "es"}`);
|
|
175
|
+
return parts.join(chalk.dim(" · "));
|
|
176
|
+
}
|
|
177
|
+
function tonePalette(tone) {
|
|
178
|
+
switch (tone) {
|
|
179
|
+
case "root":
|
|
180
|
+
return { frame: chalk.dim, ink: (s) => chalk.bold(s) };
|
|
181
|
+
case "active":
|
|
182
|
+
return { frame: chalk.cyan, ink: (s) => chalk.cyan.bold(s) };
|
|
183
|
+
case "redirect":
|
|
184
|
+
return { frame: chalk.yellow, ink: chalk.yellow };
|
|
185
|
+
case "error":
|
|
186
|
+
return { frame: chalk.red, ink: chalk.red };
|
|
187
|
+
default:
|
|
188
|
+
return { frame: chalk.green, ink: chalk.green };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const noteLine = (note) => chalk.dim(`(…) ${note}`);
|
|
192
|
+
function drawNode(node, joined) {
|
|
193
|
+
const { frame, ink } = tonePalette(node.tone);
|
|
194
|
+
const bare = `${node.icon} ${node.label}${node.meta ? ` ${node.meta}` : ""}`;
|
|
195
|
+
const span = bare.length + 2; // one space of padding each side
|
|
196
|
+
const dressed = `${node.icon} ${ink(node.label)}${node.meta ? ` ${chalk.dim(node.meta)}` : ""}`;
|
|
197
|
+
const branching = node.children.length > 0;
|
|
198
|
+
const out = node.notes.map(noteLine);
|
|
199
|
+
out.push(frame(`╭${"─".repeat(span)}╮`));
|
|
200
|
+
out.push(`${frame(joined ? "┤" : "│")} ${dressed} ${frame("│")}`);
|
|
201
|
+
out.push(frame(branching ? `╰─┬${"─".repeat(span - 2)}╯` : `╰${"─".repeat(span)}╯`));
|
|
202
|
+
node.children.forEach((child, idx) => {
|
|
203
|
+
const closing = idx === node.children.length - 1;
|
|
204
|
+
const block = drawNode(child, true);
|
|
205
|
+
const doorway = child.notes.length + 1; // the child's mid (border) line
|
|
206
|
+
block.forEach((row, at) => {
|
|
207
|
+
let lead;
|
|
208
|
+
if (at === doorway)
|
|
209
|
+
lead = closing ? " ╰──" : " ├──";
|
|
210
|
+
else if (at < doorway)
|
|
211
|
+
lead = " │ ";
|
|
212
|
+
else
|
|
213
|
+
lead = closing ? " " : " │ ";
|
|
214
|
+
out.push(chalk.dim(lead) + row);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
/** Does a stream event payload look like a real trajectory step? (The graph
|
|
220
|
+
* only takes over for genuine steps — anything else keeps the glyph line.) */
|
|
221
|
+
export function isTrajectoryStep(data) {
|
|
222
|
+
if (typeof data !== "object" || data === null)
|
|
223
|
+
return false;
|
|
224
|
+
const d = data;
|
|
225
|
+
return d.type === "tool_call" || (d.type === "text" && typeof d.kind === "string");
|
|
226
|
+
}
|
|
227
|
+
/** Present-tense caption for whatever the agent is doing right now. */
|
|
228
|
+
export function activityLabel(step) {
|
|
229
|
+
if (step.type === "tool_call") {
|
|
230
|
+
const detail = (typeof step.input_display === "string" ? step.input_display : undefined) ?? "";
|
|
231
|
+
if (isSearchStep(step))
|
|
232
|
+
return detail ? `searching ${squeeze(detail, 40)}` : "searching…";
|
|
233
|
+
const { host } = splitUrl(detail);
|
|
234
|
+
return host ? `fetching ${host}` : "fetching…";
|
|
235
|
+
}
|
|
236
|
+
if (step.type === "text" && step.kind === "reasoning")
|
|
237
|
+
return "deciding next step…";
|
|
238
|
+
if (step.type === "text")
|
|
239
|
+
return "writing the answer…";
|
|
240
|
+
return "working…";
|
|
241
|
+
}
|
|
242
|
+
export function drawJourneyTree(tree) {
|
|
243
|
+
const rows = drawNode(tree.root, false);
|
|
244
|
+
if (tree.looseNotes.length) {
|
|
245
|
+
rows.push("");
|
|
246
|
+
rows.push(...tree.looseNotes.map(noteLine));
|
|
247
|
+
}
|
|
248
|
+
return rows;
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=journey-graph.js.map
|