pi-supernova 0.0.3 → 0.0.4
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/CHANGELOG.md +6 -0
- package/index.js +15 -13
- package/omp-frame.js +13 -57
- package/package.json +1 -1
- package/render.js +2 -5
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
- Native adapters are now included in `nova.search` / `nova.describe` with schemas matching the callable adapter, even when the host catalog omits parameters or the adapter name.
|
|
8
8
|
|
|
9
|
+
## [0.0.4] - 2026-09-03
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- OMP no longer hangs on "Loading plugins…" — removed top-level import of `@oh-my-pi/pi-coding-agent/tui` from the extension (portable framed chrome only).
|
|
14
|
+
|
|
9
15
|
## [0.0.3] - 2026-09-03
|
|
10
16
|
|
|
11
17
|
### Changed
|
package/index.js
CHANGED
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
let Type;
|
|
3
|
-
try {
|
|
4
|
-
Type = (await import("typebox")).Type;
|
|
5
|
-
} catch {
|
|
6
|
-
Type = {
|
|
7
|
-
Object: (props, opts) => ({ type: "object", properties: props || {}, additionalProperties: false, ...opts }),
|
|
8
|
-
String: (opts) => ({ type: "string", ...opts }),
|
|
9
|
-
Integer: (opts) => ({ type: "integer", ...opts }),
|
|
10
|
-
Optional: (s) => ({ ...s }),
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
|
|
1
|
+
import { createRequire } from "node:module";
|
|
14
2
|
import { isString, isFunction } from "./decode.js";
|
|
15
3
|
import { buildCatalog, searchCatalog, describeTool, mergeNativeToolDefinitions } from "./catalog.js";
|
|
16
4
|
import { loadConfig } from "./config.js";
|
|
@@ -25,6 +13,20 @@ import {
|
|
|
25
13
|
|
|
26
14
|
export { extractOperationsFromCode, renderSupernovaCall, renderSupernovaResult, SafeText };
|
|
27
15
|
|
|
16
|
+
// Sync only — never top-level await. Dynamic import of host/deps hung OMP plugin load.
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
let Type;
|
|
19
|
+
try {
|
|
20
|
+
Type = require("typebox").Type;
|
|
21
|
+
} catch {
|
|
22
|
+
Type = {
|
|
23
|
+
Object: (props, opts) => ({ type: "object", properties: props || {}, additionalProperties: false, ...opts }),
|
|
24
|
+
String: (opts) => ({ type: "string", ...opts }),
|
|
25
|
+
Integer: (opts) => ({ type: "integer", ...opts }),
|
|
26
|
+
Optional: (s) => ({ ...s }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
28
30
|
function result(text, details) {
|
|
29
31
|
return { content: [{ type: "text", text }], details };
|
|
30
32
|
}
|
package/omp-frame.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OMP-
|
|
2
|
+
* OMP-style rounded tool chrome for supernova.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* portable rounded frame that matches that look when the import is unavailable
|
|
7
|
-
* (Pi path-install / unit tests).
|
|
4
|
+
* Intentionally self-contained — never dynamic-imports `@oh-my-pi/pi-coding-agent`
|
|
5
|
+
* (that hung OMP plugin load). Geometry matches native write/edit framedBlock.
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
8
|
import { clampLine, measureWidth, wrapPlainToWidth } from "./render-measure.js";
|
|
@@ -20,32 +18,12 @@ const DEFAULT_BOX = {
|
|
|
20
18
|
teeRight: "├",
|
|
21
19
|
};
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
let hostMarkFramed = null;
|
|
26
|
-
let hostResolved = false;
|
|
27
|
-
|
|
28
|
-
export async function ensureOmpChrome() {
|
|
29
|
-
if (hostResolved) return;
|
|
30
|
-
hostResolved = true;
|
|
31
|
-
for (const spec of ["@oh-my-pi/pi-coding-agent/tui", "@oh-my-pi/pi-coding-agent/tui/index.js"]) {
|
|
32
|
-
try {
|
|
33
|
-
const tui = await import(spec);
|
|
34
|
-
if (typeof tui.framedBlock === "function") hostFramedBlock = tui.framedBlock;
|
|
35
|
-
if (typeof tui.renderStatusLine === "function") hostRenderStatusLine = tui.renderStatusLine;
|
|
36
|
-
if (typeof tui.markFramedBlockComponent === "function") hostMarkFramed = tui.markFramedBlockComponent;
|
|
37
|
-
if (hostFramedBlock && hostRenderStatusLine) return;
|
|
38
|
-
} catch {
|
|
39
|
-
// Pi / tests / plain node — use portable frame.
|
|
40
|
-
}
|
|
41
|
-
}
|
|
21
|
+
export function hasHostFramedBlock() {
|
|
22
|
+
return false;
|
|
42
23
|
}
|
|
43
24
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
export function hasHostFramedBlock() {
|
|
48
|
-
return typeof hostFramedBlock === "function" && typeof hostRenderStatusLine === "function";
|
|
25
|
+
export async function ensureOmpChrome() {
|
|
26
|
+
// No-op: portable frame only. Kept so call sites stay stable.
|
|
49
27
|
}
|
|
50
28
|
|
|
51
29
|
function boxOf(theme) {
|
|
@@ -69,8 +47,6 @@ function borderPaint(theme, state, borderColor) {
|
|
|
69
47
|
}
|
|
70
48
|
|
|
71
49
|
function statusHeader(theme, { title, description, state, spinnerFrame, icon, iconOverride }) {
|
|
72
|
-
// Match native Write/Edit: framed call heads omit the pending hourglass; only
|
|
73
|
-
// pass an icon when the caller sets one (error / running / success glyph).
|
|
74
50
|
const resolvedIcon =
|
|
75
51
|
iconOverride !== undefined
|
|
76
52
|
? undefined
|
|
@@ -79,21 +55,12 @@ function statusHeader(theme, { title, description, state, spinnerFrame, icon, ic
|
|
|
79
55
|
: state === "error"
|
|
80
56
|
? "error"
|
|
81
57
|
: undefined;
|
|
82
|
-
if (hostRenderStatusLine) {
|
|
83
|
-
return hostRenderStatusLine(
|
|
84
|
-
{
|
|
85
|
-
icon: resolvedIcon,
|
|
86
|
-
iconOverride,
|
|
87
|
-
spinnerFrame,
|
|
88
|
-
title,
|
|
89
|
-
description,
|
|
90
|
-
},
|
|
91
|
-
theme,
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
58
|
const titleText = theme?.fg ? theme.fg("accent", title) : title;
|
|
95
59
|
const descText = description ? (theme?.fg ? theme.fg("muted", description) : description) : "";
|
|
96
|
-
|
|
60
|
+
let prefix = "";
|
|
61
|
+
if (iconOverride) prefix = `${iconOverride} `;
|
|
62
|
+
else if (resolvedIcon === "error") prefix = theme?.fg ? theme.fg("error", "✗ ") : "✗ ";
|
|
63
|
+
else if (resolvedIcon === "running" || spinnerFrame) prefix = theme?.fg ? theme.fg("dim", "… ") : "… ";
|
|
97
64
|
return descText ? `${prefix}${titleText}: ${descText}` : `${prefix}${titleText}`;
|
|
98
65
|
}
|
|
99
66
|
|
|
@@ -135,9 +102,6 @@ function bgFnForState(theme, state) {
|
|
|
135
102
|
return undefined;
|
|
136
103
|
}
|
|
137
104
|
|
|
138
|
-
/**
|
|
139
|
-
* Portable rounded frame matching OMP output-block geometry.
|
|
140
|
-
*/
|
|
141
105
|
export function renderPortableFrame(theme, { header, sections = [], state = "pending", borderColor, width }) {
|
|
142
106
|
const w = Math.max(8, width | 0);
|
|
143
107
|
const box = boxOf(theme);
|
|
@@ -161,7 +125,7 @@ export function renderPortableFrame(theme, { header, sections = [], state = "pen
|
|
|
161
125
|
return padLine(`${border(left)}${trimmed}${border(h.repeat(fill))}${border(right)}`, w, bgFn);
|
|
162
126
|
};
|
|
163
127
|
|
|
164
|
-
const contentWidth = Math.max(1, w - 2 - 2);
|
|
128
|
+
const contentWidth = Math.max(1, w - 2 - 2);
|
|
165
129
|
const lines = [];
|
|
166
130
|
lines.push(paintBar(box.topLeft, box.topRight, header));
|
|
167
131
|
|
|
@@ -188,7 +152,7 @@ export function createPortableFramedComponent(theme, build) {
|
|
|
188
152
|
let cacheWidth;
|
|
189
153
|
let cacheKey;
|
|
190
154
|
let cacheLines;
|
|
191
|
-
|
|
155
|
+
return {
|
|
192
156
|
render(width) {
|
|
193
157
|
const opts = build(width);
|
|
194
158
|
const key = `${opts.state}|${opts.borderColor}|${opts.header}|${(opts.sections || [])
|
|
@@ -206,17 +170,9 @@ export function createPortableFramedComponent(theme, build) {
|
|
|
206
170
|
cacheWidth = undefined;
|
|
207
171
|
},
|
|
208
172
|
};
|
|
209
|
-
if (hostMarkFramed) return hostMarkFramed(comp);
|
|
210
|
-
return comp;
|
|
211
173
|
}
|
|
212
174
|
|
|
213
|
-
/**
|
|
214
|
-
* Build a framed nova card. Uses host framedBlock when available (OMP).
|
|
215
|
-
*/
|
|
216
175
|
export function novaFramedBlock(theme, build) {
|
|
217
|
-
if (hostFramedBlock) {
|
|
218
|
-
return hostFramedBlock(theme, build);
|
|
219
|
-
}
|
|
220
176
|
return createPortableFramedComponent(theme, build);
|
|
221
177
|
}
|
|
222
178
|
|
package/package.json
CHANGED
package/render.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
wrapPlainToWidth,
|
|
20
20
|
fitPath,
|
|
21
21
|
} from "./render-measure.js";
|
|
22
|
-
import {
|
|
22
|
+
import { novaFramedBlock, novaStatusLine } from "./omp-frame.js";
|
|
23
23
|
|
|
24
24
|
export { measureWidth, hardTruncate, clampLine, wrapPlainToWidth, fitPath };
|
|
25
25
|
|
|
@@ -348,7 +348,6 @@ function detectResultHost(options, ctxOrArgs) {
|
|
|
348
348
|
) {
|
|
349
349
|
return "omp";
|
|
350
350
|
}
|
|
351
|
-
if (hasHostFramedBlock()) return "omp";
|
|
352
351
|
return "pi";
|
|
353
352
|
}
|
|
354
353
|
|
|
@@ -445,7 +444,7 @@ function formatOpBodyLine(theme, op) {
|
|
|
445
444
|
}
|
|
446
445
|
|
|
447
446
|
function shouldUseOmpFrame(host) {
|
|
448
|
-
return host === "omp"
|
|
447
|
+
return host === "omp";
|
|
449
448
|
}
|
|
450
449
|
|
|
451
450
|
/**
|
|
@@ -529,7 +528,6 @@ export function renderSupernovaCall(a, b, c) {
|
|
|
529
528
|
const timeStr = formatElapsed(context?.state);
|
|
530
529
|
|
|
531
530
|
if (shouldUseOmpFrame(host)) {
|
|
532
|
-
void ensureOmpChrome();
|
|
533
531
|
return renderOmpCallCard(theme, {
|
|
534
532
|
ops,
|
|
535
533
|
timeStr,
|
|
@@ -642,7 +640,6 @@ export function renderSupernovaResult(resultArg, optionsArg, themeArg, contextAr
|
|
|
642
640
|
const useOmp = shouldUseOmpFrame(host);
|
|
643
641
|
|
|
644
642
|
if (useOmp) {
|
|
645
|
-
void ensureOmpChrome();
|
|
646
643
|
if (isPartial && !isErr) {
|
|
647
644
|
// Streaming partials stay quiet until body content exists — same as Pi.
|
|
648
645
|
const partialBody = buildResultBody(theme, { payload, context, expanded });
|