@oh-my-pi/pi-coding-agent 16.0.2 → 16.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 +53 -0
- package/README.md +0 -1
- package/dist/cli.js +580 -359
- package/dist/types/advisor/advise-tool.d.ts +30 -1
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/commands/install.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/config/model-resolver.d.ts +8 -0
- package/dist/types/config/settings-schema.d.ts +1 -11
- package/dist/types/edit/file-snapshot-store.d.ts +2 -0
- package/dist/types/eval/js/shared/runtime.d.ts +1 -0
- package/dist/types/eval/js/worker-core.d.ts +1 -0
- package/dist/types/extensibility/extensions/loader.d.ts +2 -2
- package/dist/types/goals/runtime.d.ts +0 -1
- package/dist/types/mcp/tool-bridge.d.ts +3 -0
- package/dist/types/modes/components/custom-editor.d.ts +14 -4
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +3 -2
- package/dist/types/modes/theme/mermaid-cache.d.ts +18 -1
- package/dist/types/modes/types.d.ts +1 -1
- package/dist/types/registry/agent-lifecycle.d.ts +16 -1
- package/dist/types/sdk.d.ts +8 -0
- package/dist/types/session/agent-session.d.ts +20 -8
- package/dist/types/session/session-dump-format.d.ts +8 -2
- package/dist/types/session/session-entries.d.ts +4 -0
- package/dist/types/session/session-history-format.d.ts +2 -0
- package/dist/types/session/session-manager.d.ts +22 -0
- package/dist/types/stt/downloader.d.ts +5 -5
- package/dist/types/task/executor.d.ts +6 -0
- package/dist/types/task/persisted-revive.d.ts +36 -0
- package/dist/types/tiny/models.d.ts +8 -0
- package/dist/types/tools/builtin-names.d.ts +1 -1
- package/dist/types/tools/index.d.ts +0 -1
- package/package.json +12 -12
- package/src/advisor/__tests__/advisor.test.ts +150 -50
- package/src/advisor/advise-tool.ts +48 -6
- package/src/advisor/runtime.ts +10 -3
- package/src/auto-thinking/classifier.ts +12 -3
- package/src/cli/args.ts +3 -0
- package/src/cli/flag-tables.ts +1 -0
- package/src/cli.ts +2 -2
- package/src/commands/install.ts +3 -3
- package/src/commands/launch.ts +3 -0
- package/src/config/model-resolver.ts +28 -11
- package/src/config/settings-schema.ts +1 -12
- package/src/edit/file-snapshot-store.ts +12 -3
- package/src/eval/agent-bridge.ts +2 -0
- package/src/eval/js/context-manager.ts +2 -1
- package/src/eval/js/shared/runtime.ts +189 -15
- package/src/eval/js/worker-core.ts +19 -0
- package/src/export/html/index.ts +1 -1
- package/src/export/html/tool-views.generated.js +34 -35
- package/src/extensibility/extensions/loader.ts +21 -9
- package/src/goals/runtime.ts +1 -23
- package/src/internal-urls/docs-index.generated.ts +82 -84
- package/src/main.ts +26 -4
- package/src/mcp/render.ts +11 -1
- package/src/mcp/tool-bridge.ts +3 -0
- package/src/modes/components/custom-editor.test.ts +63 -18
- package/src/modes/components/custom-editor.ts +63 -15
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/controllers/command-controller.ts +2 -2
- package/src/modes/controllers/input-controller.ts +15 -9
- package/src/modes/controllers/selector-controller.ts +13 -8
- package/src/modes/controllers/tan-command-controller.ts +1 -0
- package/src/modes/interactive-mode.ts +4 -2
- package/src/modes/setup-wizard/wizard-overlay.ts +26 -4
- package/src/modes/theme/mermaid-cache.ts +74 -11
- package/src/modes/theme/theme.ts +14 -1
- package/src/modes/types.ts +1 -1
- package/src/prompts/system/system-prompt.md +4 -1
- package/src/registry/agent-lifecycle.ts +60 -8
- package/src/sdk.ts +20 -26
- package/src/session/agent-session.ts +253 -82
- package/src/session/artifacts.ts +19 -1
- package/src/session/session-dump-format.ts +167 -23
- package/src/session/session-entries.ts +4 -0
- package/src/session/session-history-format.ts +37 -3
- package/src/session/session-manager.ts +94 -4
- package/src/slash-commands/builtin-registry.ts +4 -7
- package/src/stt/asr-client.ts +6 -0
- package/src/stt/downloader.ts +13 -6
- package/src/stt/stt-controller.ts +52 -11
- package/src/task/executor.ts +18 -2
- package/src/task/index.ts +2 -2
- package/src/task/persisted-revive.ts +128 -0
- package/src/tiny/models.ts +10 -0
- package/src/tiny/worker.ts +4 -3
- package/src/tools/builtin-names.ts +0 -1
- package/src/tools/index.ts +0 -4
- package/src/tools/output-meta.ts +17 -3
- package/src/tools/read.ts +26 -0
- package/src/utils/title-generator.ts +4 -4
- package/dist/types/tools/render-mermaid.d.ts +0 -38
- package/src/prompts/tools/render-mermaid.md +0 -9
- package/src/tools/render-mermaid.ts +0 -69
|
@@ -564,7 +564,7 @@ function spawnInlineWorker(): WorkerHandle {
|
|
|
564
564
|
},
|
|
565
565
|
close: () => {},
|
|
566
566
|
};
|
|
567
|
-
new WorkerCore(workerTransport);
|
|
567
|
+
const core = new WorkerCore(workerTransport);
|
|
568
568
|
return {
|
|
569
569
|
mode: "inline",
|
|
570
570
|
send: msg =>
|
|
@@ -600,6 +600,7 @@ function spawnInlineWorker(): WorkerHandle {
|
|
|
600
600
|
async terminate() {
|
|
601
601
|
hostListeners.clear();
|
|
602
602
|
workerListeners.clear();
|
|
603
|
+
core.dispose();
|
|
603
604
|
},
|
|
604
605
|
};
|
|
605
606
|
}
|
|
@@ -55,6 +55,32 @@ export interface RuntimeOptions {
|
|
|
55
55
|
const BASE64_STRICT_RE = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
56
56
|
const DECIMAL_CSV_RE = /^\d{1,3}(?:,\d{1,3})*$/;
|
|
57
57
|
|
|
58
|
+
const PRELUDE_GLOBAL_KEYS = [
|
|
59
|
+
"__omp_js_prelude_loaded__",
|
|
60
|
+
"console",
|
|
61
|
+
"print",
|
|
62
|
+
"display",
|
|
63
|
+
"tool",
|
|
64
|
+
"completion",
|
|
65
|
+
"output",
|
|
66
|
+
"agent",
|
|
67
|
+
"parallel",
|
|
68
|
+
"pipeline",
|
|
69
|
+
"log",
|
|
70
|
+
"phase",
|
|
71
|
+
"budget",
|
|
72
|
+
"__pool",
|
|
73
|
+
"read",
|
|
74
|
+
"write",
|
|
75
|
+
"append",
|
|
76
|
+
"sort",
|
|
77
|
+
"uniq",
|
|
78
|
+
"counter",
|
|
79
|
+
"diff",
|
|
80
|
+
"tree",
|
|
81
|
+
"env",
|
|
82
|
+
];
|
|
83
|
+
|
|
58
84
|
function isStrictBase64(s: string): boolean {
|
|
59
85
|
if (s.length === 0 || s.length % 4 !== 0) return false;
|
|
60
86
|
return BASE64_STRICT_RE.test(s);
|
|
@@ -125,6 +151,22 @@ function describeDataType(data: unknown): string {
|
|
|
125
151
|
* concern.
|
|
126
152
|
*/
|
|
127
153
|
export class JsRuntime {
|
|
154
|
+
#globalOwner = Symbol("JsRuntime globals");
|
|
155
|
+
#ownedGlobalKeys = new Set<string>();
|
|
156
|
+
#disposed = false;
|
|
157
|
+
#runHookResolver = () => this.#als.getStore()?.hooks;
|
|
158
|
+
|
|
159
|
+
#ownGlobal(key: string): void {
|
|
160
|
+
if (this.#ownedGlobalKeys.has(key)) return;
|
|
161
|
+
claimGlobalKey(key, this.#globalOwner);
|
|
162
|
+
this.#ownedGlobalKeys.add(key);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
#activateGlobals(action: string): void {
|
|
166
|
+
if (this.#disposed) throw new Error(`Cannot ${action} on a disposed JS runtime`);
|
|
167
|
+
activateGlobalOwner(this.#globalOwner, this.#ownedGlobalKeys, action);
|
|
168
|
+
}
|
|
169
|
+
|
|
128
170
|
readonly helpers: HelperBundle;
|
|
129
171
|
#cwd: string;
|
|
130
172
|
readonly sessionId: string;
|
|
@@ -153,6 +195,7 @@ export class JsRuntime {
|
|
|
153
195
|
}
|
|
154
196
|
|
|
155
197
|
setCwd(cwd: string): void {
|
|
198
|
+
this.#activateGlobals("set cwd");
|
|
156
199
|
this.#cwd = cwd;
|
|
157
200
|
const session = (globalThis as { __omp_session__?: { cwd?: string } }).__omp_session__;
|
|
158
201
|
if (session) session.cwd = cwd;
|
|
@@ -164,6 +207,7 @@ export class JsRuntime {
|
|
|
164
207
|
* cleanup it wants.
|
|
165
208
|
*/
|
|
166
209
|
setRunScope(scope: Record<string, unknown>): void {
|
|
210
|
+
this.#activateGlobals("set run scope");
|
|
167
211
|
Object.assign(globalThis, scope);
|
|
168
212
|
}
|
|
169
213
|
|
|
@@ -173,6 +217,8 @@ export class JsRuntime {
|
|
|
173
217
|
hooks: RuntimeHooks,
|
|
174
218
|
options: { runId?: string; cwd?: string } = {},
|
|
175
219
|
): Promise<unknown> {
|
|
220
|
+
this.#activateGlobals("run code");
|
|
221
|
+
const leaveRun = enterGlobalRun(this.#globalOwner, "run code");
|
|
176
222
|
const context: RunContext = {
|
|
177
223
|
runId: options.runId ?? crypto.randomUUID(),
|
|
178
224
|
hooks,
|
|
@@ -180,21 +226,25 @@ export class JsRuntime {
|
|
|
180
226
|
finalExpressionSet: false,
|
|
181
227
|
finalExpressionValue: undefined,
|
|
182
228
|
};
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
229
|
+
try {
|
|
230
|
+
return await this.#als.run(context, async () => {
|
|
231
|
+
const wrapped = await wrapCode(code);
|
|
232
|
+
const value = indirectEval(wrapped.source, filename);
|
|
233
|
+
if (wrapped.finalExpressionReturned) {
|
|
234
|
+
const awaited = await awaitMaybePromise(value);
|
|
235
|
+
if (context.finalExpressionSet) {
|
|
236
|
+
const finalValue = context.finalExpressionValue;
|
|
237
|
+
context.finalExpressionSet = false;
|
|
238
|
+
context.finalExpressionValue = undefined;
|
|
239
|
+
return await awaitMaybePromise(finalValue);
|
|
240
|
+
}
|
|
241
|
+
return awaited;
|
|
193
242
|
}
|
|
194
|
-
return
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
243
|
+
return await awaitMaybePromise(value);
|
|
244
|
+
});
|
|
245
|
+
} finally {
|
|
246
|
+
leaveRun();
|
|
247
|
+
}
|
|
198
248
|
}
|
|
199
249
|
|
|
200
250
|
displayValue(value: unknown, hooks: RuntimeHooks | undefined = this.#als.getStore()?.hooks): void {
|
|
@@ -338,13 +388,137 @@ export class JsRuntime {
|
|
|
338
388
|
createRequire,
|
|
339
389
|
fs,
|
|
340
390
|
};
|
|
391
|
+
|
|
392
|
+
const allGlobalKeys = new Set<string>([
|
|
393
|
+
...Object.keys(injected),
|
|
394
|
+
...Object.keys(extraGlobals ?? {}),
|
|
395
|
+
...PRELUDE_GLOBAL_KEYS,
|
|
396
|
+
]);
|
|
397
|
+
|
|
398
|
+
for (const key of allGlobalKeys) {
|
|
399
|
+
this.#ownGlobal(key);
|
|
400
|
+
}
|
|
401
|
+
|
|
341
402
|
Object.assign(globalThis, injected, extraGlobals ?? {});
|
|
342
403
|
// Prelude assigns console bridge + short aliases (`read`, `write`, `tool`, `display`, ...)
|
|
343
404
|
// onto globalThis. Must run after helpers are in place.
|
|
344
405
|
indirectEval(JAVASCRIPT_PRELUDE_SOURCE);
|
|
345
|
-
|
|
406
|
+
for (const key of allGlobalKeys) recordGlobalValue(key, this.#globalOwner);
|
|
407
|
+
RUN_HOOK_RESOLVERS.add(this.#runHookResolver);
|
|
346
408
|
patchStdioOnce();
|
|
347
409
|
}
|
|
410
|
+
|
|
411
|
+
dispose(): void {
|
|
412
|
+
if (this.#disposed) return;
|
|
413
|
+
this.#disposed = true;
|
|
414
|
+
RUN_HOOK_RESOLVERS.delete(this.#runHookResolver);
|
|
415
|
+
for (const key of this.#ownedGlobalKeys) releaseGlobalKey(key, this.#globalOwner);
|
|
416
|
+
this.#ownedGlobalKeys.clear();
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
interface GlobalSnapshot {
|
|
421
|
+
exists: boolean;
|
|
422
|
+
value: unknown;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
interface GlobalOwnerEntry {
|
|
426
|
+
owner: symbol;
|
|
427
|
+
value: unknown;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
interface GlobalStack {
|
|
431
|
+
base: GlobalSnapshot;
|
|
432
|
+
entries: GlobalOwnerEntry[];
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Inline fallback and cmux tabs can create multiple JsRuntime instances in one Bun realm.
|
|
436
|
+
// Track reserved helper globals by owner so disposing one runtime restores the next active
|
|
437
|
+
// owner (or the original process global after the last owner), not a stale snapshot.
|
|
438
|
+
const GLOBAL_STACKS = new Map<string, GlobalStack>();
|
|
439
|
+
|
|
440
|
+
function snapshotGlobal(key: string): GlobalSnapshot {
|
|
441
|
+
return {
|
|
442
|
+
exists: key in globalThis,
|
|
443
|
+
value: (globalThis as Record<string, unknown>)[key],
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function restoreGlobal(key: string, state: GlobalSnapshot): void {
|
|
448
|
+
if (state.exists) {
|
|
449
|
+
(globalThis as Record<string, unknown>)[key] = state.value;
|
|
450
|
+
} else {
|
|
451
|
+
delete (globalThis as Record<string, unknown>)[key];
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function claimGlobalKey(key: string, owner: symbol): void {
|
|
456
|
+
let stack = GLOBAL_STACKS.get(key);
|
|
457
|
+
if (!stack) {
|
|
458
|
+
stack = { base: snapshotGlobal(key), entries: [] };
|
|
459
|
+
GLOBAL_STACKS.set(key, stack);
|
|
460
|
+
}
|
|
461
|
+
stack.entries.push({ owner, value: (globalThis as Record<string, unknown>)[key] });
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function recordGlobalValue(key: string, owner: symbol): void {
|
|
465
|
+
const stack = GLOBAL_STACKS.get(key);
|
|
466
|
+
const entry = stack?.entries.findLast(item => item.owner === owner);
|
|
467
|
+
if (entry) entry.value = (globalThis as Record<string, unknown>)[key];
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function releaseGlobalKey(key: string, owner: symbol): void {
|
|
471
|
+
const stack = GLOBAL_STACKS.get(key);
|
|
472
|
+
if (!stack) return;
|
|
473
|
+
const index = stack.entries.findIndex(entry => entry.owner === owner);
|
|
474
|
+
if (index === -1) return;
|
|
475
|
+
const wasTop = index === stack.entries.length - 1;
|
|
476
|
+
stack.entries.splice(index, 1);
|
|
477
|
+
if (!wasTop) return;
|
|
478
|
+
const next = stack.entries.at(-1);
|
|
479
|
+
if (next) {
|
|
480
|
+
(globalThis as Record<string, unknown>)[key] = next.value;
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
restoreGlobal(key, stack.base);
|
|
484
|
+
GLOBAL_STACKS.delete(key);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Plain globalThis cannot safely serve two different runtimes at the same instant:
|
|
488
|
+
// helpers dereference reserved globals on every call. Sequential cmux tab revisits
|
|
489
|
+
// re-activate their owner stack; overlapping cross-runtime runs fail explicitly.
|
|
490
|
+
let activeGlobalRunOwner: symbol | null = null;
|
|
491
|
+
let activeGlobalRunDepth = 0;
|
|
492
|
+
|
|
493
|
+
function assertCanUseGlobalOwner(owner: symbol, action: string): void {
|
|
494
|
+
if (activeGlobalRunOwner === null || activeGlobalRunOwner === owner) return;
|
|
495
|
+
throw new Error(`Cannot ${action} while another same-realm JS runtime is running`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function activateGlobalOwner(owner: symbol, keys: Iterable<string>, action: string): void {
|
|
499
|
+
assertCanUseGlobalOwner(owner, action);
|
|
500
|
+
for (const key of keys) {
|
|
501
|
+
const stack = GLOBAL_STACKS.get(key);
|
|
502
|
+
const index = stack?.entries.findIndex(entry => entry.owner === owner) ?? -1;
|
|
503
|
+
if (!stack || index === -1) throw new Error(`Cannot ${action} on a disposed JS runtime`);
|
|
504
|
+
const entry = stack.entries[index];
|
|
505
|
+
stack.entries.splice(index, 1);
|
|
506
|
+
stack.entries.push(entry);
|
|
507
|
+
(globalThis as Record<string, unknown>)[key] = entry.value;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function enterGlobalRun(owner: symbol, action: string): () => void {
|
|
512
|
+
assertCanUseGlobalOwner(owner, action);
|
|
513
|
+
activeGlobalRunOwner = owner;
|
|
514
|
+
activeGlobalRunDepth++;
|
|
515
|
+
let left = false;
|
|
516
|
+
return () => {
|
|
517
|
+
if (left) return;
|
|
518
|
+
left = true;
|
|
519
|
+
activeGlobalRunDepth--;
|
|
520
|
+
if (activeGlobalRunDepth === 0) activeGlobalRunOwner = null;
|
|
521
|
+
};
|
|
348
522
|
}
|
|
349
523
|
|
|
350
524
|
/** Resolvers for each live runtime's active-run hooks (one per JsRuntime instance). */
|
|
@@ -124,9 +124,28 @@ export class WorkerCore {
|
|
|
124
124
|
active.pendingTools.clear();
|
|
125
125
|
}
|
|
126
126
|
this.#runs.clear();
|
|
127
|
+
this.#runtime?.dispose?.();
|
|
127
128
|
this.#runtime = null;
|
|
128
129
|
this.#transport.send({ type: "closed" });
|
|
129
130
|
this.#unsubscribe();
|
|
130
131
|
this.#transport.close();
|
|
131
132
|
}
|
|
133
|
+
|
|
134
|
+
dispose(): void {
|
|
135
|
+
for (const active of this.#runs.values()) {
|
|
136
|
+
for (const pending of active.pendingTools.values()) {
|
|
137
|
+
pending.reject(new ToolError("JS worker closed"));
|
|
138
|
+
}
|
|
139
|
+
active.pendingTools.clear();
|
|
140
|
+
}
|
|
141
|
+
this.#runs.clear();
|
|
142
|
+
this.#runtime?.dispose?.();
|
|
143
|
+
this.#runtime = null;
|
|
144
|
+
this.#unsubscribe();
|
|
145
|
+
try {
|
|
146
|
+
this.#transport.close();
|
|
147
|
+
} catch {
|
|
148
|
+
// Ignore
|
|
149
|
+
}
|
|
150
|
+
}
|
|
132
151
|
}
|
package/src/export/html/index.ts
CHANGED
|
@@ -242,7 +242,7 @@ export async function exportFromFile(inputPath: string, options?: ExportOptions
|
|
|
242
242
|
|
|
243
243
|
let sm: SessionManager;
|
|
244
244
|
try {
|
|
245
|
-
sm = await SessionManager.open(inputPath);
|
|
245
|
+
sm = await SessionManager.open(inputPath, undefined, undefined, { suppressBreadcrumb: true });
|
|
246
246
|
} catch (err) {
|
|
247
247
|
if (isEnoent(err)) throw new Error(`File not found: ${inputPath}`);
|
|
248
248
|
throw err;
|