@agent-api/app-engine 0.0.8 → 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/README.md +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/terminal.d.ts +1 -0
- package/dist/workbench/view-model.d.ts +7 -0
- package/dist/workbench/view-model.js +75 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,7 +44,8 @@ Host applications should call `configureAgentAppRuntime()` during startup so con
|
|
|
44
44
|
- `@agent-api/app-engine/core`: UI-neutral APIs for auth, config, profiles, conversations, updates, local workdir setup, and agent turns.
|
|
45
45
|
- `@agent-api/app-engine/workbench`: optional app/workbench state controllers for apps that want Agent API's conversation workflow.
|
|
46
46
|
- `@agent-api/app-engine/terminal`: optional terminal-facing helpers for transcript wrapping, input viewport rendering, and spinner glyphs.
|
|
47
|
-
|
|
47
|
+
|
|
48
|
+
The root `@agent-api/app-engine` entry is intentionally empty. Use an explicit subpath so your application depends on a clear API layer.
|
|
48
49
|
|
|
49
50
|
## Boundaries
|
|
50
51
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export {};
|
package/dist/terminal.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export type { WorkbenchInputController } from "./workbench/input-controller.js";
|
|
|
2
2
|
export { createWorkbenchInputController } from "./workbench/input-controller.js";
|
|
3
3
|
export type { WorkbenchRenderModel } from "./workbench/render-model.js";
|
|
4
4
|
export { buildWorkbenchRenderModel, busySpinner, pendingLocalLabel, } from "./workbench/render-model.js";
|
|
5
|
+
export type { TranscriptLine, TranscriptSpan, TranscriptViewModel, } from "./workbench/view-model.js";
|
|
5
6
|
export { buildTranscriptLines, buildTranscriptViewModel, elapsedDots, spinnerGlyph, } from "./workbench/view-model.js";
|
|
6
7
|
export { activityColor } from "./workbench/state.js";
|
|
@@ -5,6 +5,13 @@ export type TranscriptLine = {
|
|
|
5
5
|
color?: string;
|
|
6
6
|
bold?: boolean;
|
|
7
7
|
inverse?: boolean;
|
|
8
|
+
spans?: TranscriptSpan[];
|
|
9
|
+
};
|
|
10
|
+
export type TranscriptSpan = {
|
|
11
|
+
text: string;
|
|
12
|
+
color?: string;
|
|
13
|
+
bold?: boolean;
|
|
14
|
+
inverse?: boolean;
|
|
8
15
|
};
|
|
9
16
|
export interface TranscriptViewModel {
|
|
10
17
|
lines: TranscriptLine[];
|
|
@@ -80,16 +80,85 @@ function markdownTranscriptLine(line, options) {
|
|
|
80
80
|
return [{ text: "─".repeat(Math.min(48, options.width)), color: "gray" }];
|
|
81
81
|
const bullet = /^(\s*)[-*]\s+(.+)$/.exec(line);
|
|
82
82
|
if (bullet)
|
|
83
|
-
return
|
|
83
|
+
return wrapMarkdownInline(`${bullet[1]}• ${bullet[2]}`, options.width);
|
|
84
84
|
const numbered = /^(\s*)(\d+\.)\s+(.+)$/.exec(line);
|
|
85
85
|
if (numbered)
|
|
86
|
-
return
|
|
86
|
+
return wrapMarkdownInline(`${numbered[1]}${numbered[2]} ${numbered[3]}`, options.width);
|
|
87
87
|
const quote = /^\s*>\s?(.+)$/.exec(line);
|
|
88
88
|
if (quote)
|
|
89
|
-
return
|
|
90
|
-
return
|
|
89
|
+
return wrapMarkdownInline(`│ ${quote[1]}`, options.width).map((item) => ({ ...item, color: "gray" }));
|
|
90
|
+
return wrapMarkdownInline(line, options.width);
|
|
91
91
|
}
|
|
92
|
-
function
|
|
92
|
+
function wrapMarkdownInline(text, width) {
|
|
93
|
+
return wrapTranscriptSpans(markdownInlineSpans(text), width);
|
|
94
|
+
}
|
|
95
|
+
function markdownInlineSpans(text) {
|
|
96
|
+
const spans = [];
|
|
97
|
+
const pattern = /(\*\*([^*]+)\*\*)|(\[([^\]]+)\]\(([^)]+)\))/g;
|
|
98
|
+
let lastIndex = 0;
|
|
99
|
+
for (const match of text.matchAll(pattern)) {
|
|
100
|
+
const index = match.index ?? 0;
|
|
101
|
+
if (index > lastIndex) {
|
|
102
|
+
spans.push({ text: text.slice(lastIndex, index) });
|
|
103
|
+
}
|
|
104
|
+
if (match[2]) {
|
|
105
|
+
spans.push({ text: match[2], bold: true });
|
|
106
|
+
}
|
|
107
|
+
else if (match[4]) {
|
|
108
|
+
spans.push({ text: match[4], color: "cyan" });
|
|
109
|
+
if (match[5])
|
|
110
|
+
spans.push({ text: ` (${match[5]})`, color: "gray" });
|
|
111
|
+
}
|
|
112
|
+
lastIndex = index + match[0].length;
|
|
113
|
+
}
|
|
114
|
+
if (lastIndex < text.length) {
|
|
115
|
+
spans.push({ text: text.slice(lastIndex) });
|
|
116
|
+
}
|
|
117
|
+
return spans.length > 0 ? spans : [{ text }];
|
|
118
|
+
}
|
|
119
|
+
function wrapTranscriptSpans(spans, width) {
|
|
120
|
+
const text = spans.map((span) => span.text).join("");
|
|
121
|
+
const wrapped = wrapTranscriptText(text, width, { trimStart: false });
|
|
122
|
+
const lines = [];
|
|
123
|
+
let offset = 0;
|
|
124
|
+
for (const line of wrapped) {
|
|
125
|
+
const lineSpans = sliceSpans(spans, offset, line.length);
|
|
126
|
+
offset += line.length;
|
|
127
|
+
while (text[offset] === " ")
|
|
128
|
+
offset += 1;
|
|
129
|
+
lines.push({
|
|
130
|
+
text: line,
|
|
131
|
+
spans: lineSpans.length > 0 ? lineSpans : undefined,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return lines;
|
|
135
|
+
}
|
|
136
|
+
function sliceSpans(spans, offset, length) {
|
|
137
|
+
const output = [];
|
|
138
|
+
let position = 0;
|
|
139
|
+
let remaining = length;
|
|
140
|
+
for (const span of spans) {
|
|
141
|
+
if (remaining <= 0)
|
|
142
|
+
break;
|
|
143
|
+
const spanEnd = position + span.text.length;
|
|
144
|
+
if (spanEnd <= offset) {
|
|
145
|
+
position = spanEnd;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (position >= offset + length)
|
|
149
|
+
break;
|
|
150
|
+
const start = Math.max(0, offset - position);
|
|
151
|
+
const end = Math.min(span.text.length, start + remaining);
|
|
152
|
+
const text = span.text.slice(start, end);
|
|
153
|
+
if (text) {
|
|
154
|
+
output.push({ ...span, text });
|
|
155
|
+
remaining -= text.length;
|
|
156
|
+
}
|
|
157
|
+
position = spanEnd;
|
|
158
|
+
}
|
|
159
|
+
return output;
|
|
160
|
+
}
|
|
161
|
+
function wrapTranscriptText(text, width, options = {}) {
|
|
93
162
|
const max = Math.max(12, width);
|
|
94
163
|
if (text.length === 0)
|
|
95
164
|
return [""];
|
|
@@ -105,7 +174,7 @@ function wrapTranscriptText(text, width) {
|
|
|
105
174
|
const chunk = useSoftBreak ? soft : hard.text;
|
|
106
175
|
const index = useSoftBreak ? softBreak : hard.length;
|
|
107
176
|
lines.push(chunk.trimEnd());
|
|
108
|
-
rest = rest.slice(index).trimStart();
|
|
177
|
+
rest = options.trimStart === false ? rest.slice(index) : rest.slice(index).trimStart();
|
|
109
178
|
}
|
|
110
179
|
lines.push(rest);
|
|
111
180
|
return lines;
|
package/package.json
CHANGED