omegon 0.6.11 → 0.6.13
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/bin/omegon.mjs
CHANGED
|
@@ -52,10 +52,14 @@ function injectBundledResourceArgs(argv) {
|
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
// Omegon is the sole authority for bundled resources.
|
|
56
|
+
// Suppress pi's auto-discovery of skills, prompts, and themes (which scans
|
|
57
|
+
// ~/.pi/agent/*, installed packages, and project .pi/ dirs) so only our
|
|
58
|
+
// manifest-declared resources load. The --no-* flags disable discovery
|
|
59
|
+
// but still allow CLI-injected paths (our --extension manifest).
|
|
60
|
+
// Extensions are NOT suppressed — project-local .pi/extensions/ should still work.
|
|
61
|
+
injected.push("--no-skills", "--no-prompt-templates", "--no-themes");
|
|
55
62
|
pushPair("--extension", omegonRoot);
|
|
56
|
-
pushPair("--skill", join(omegonRoot, "skills"));
|
|
57
|
-
pushPair("--prompt-template", join(omegonRoot, "prompts"));
|
|
58
|
-
pushPair("--theme", join(omegonRoot, "themes"));
|
|
59
63
|
return injected;
|
|
60
64
|
}
|
|
61
65
|
|
|
@@ -46,46 +46,9 @@ function hasCmd(cmd: string): boolean {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/**
|
|
50
|
-
* Detect immutable/atomic Linux distros (Bazzite, Silverblue, Kinoite, etc.)
|
|
51
|
-
* where dnf/apt are unavailable or aliased to guides. These distros typically
|
|
52
|
-
* use Homebrew (Linuxbrew) or Flatpak for user-space packages.
|
|
53
|
-
*/
|
|
54
|
-
function isImmutableLinux(): boolean {
|
|
55
|
-
if (process.platform !== "linux") return false;
|
|
56
|
-
try {
|
|
57
|
-
const osRelease = execSync("cat /etc/os-release 2>/dev/null", { encoding: "utf-8" });
|
|
58
|
-
// Bazzite, Silverblue, Kinoite, Aurora, Bluefin — all Fedora Atomic variants
|
|
59
|
-
return /VARIANT_ID=.*(silverblue|kinoite|bazzite|aurora|bluefin|atomic)/i.test(osRelease)
|
|
60
|
-
|| /ostree/i.test(osRelease);
|
|
61
|
-
} catch {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Cached immutable Linux detection */
|
|
67
|
-
const _isImmutable = isImmutableLinux();
|
|
68
|
-
|
|
69
49
|
/** Get the best install command for the current platform */
|
|
70
50
|
export function bestInstallCmd(dep: Dep): string | undefined {
|
|
71
51
|
const plat = process.platform === "darwin" ? "darwin" : "linux";
|
|
72
|
-
|
|
73
|
-
// On immutable Linux (Bazzite, Silverblue, etc.), dnf/apt are unavailable
|
|
74
|
-
// or aliased to documentation guides. Prefer brew commands.
|
|
75
|
-
// On regular Linux, prefer non-brew (apt/dnf) unless brew is the only option.
|
|
76
|
-
const hasBrew = hasCmd("brew");
|
|
77
|
-
if (plat === "linux" && (_isImmutable || !hasBrew)) {
|
|
78
|
-
// Immutable: must use brew (skip apt/dnf). Regular without brew: skip brew commands.
|
|
79
|
-
const candidates = dep.install.filter((o) => o.platform === plat || o.platform === "any");
|
|
80
|
-
if (_isImmutable && hasBrew) {
|
|
81
|
-
const brewCmd = candidates.find((o) => o.cmd.startsWith("brew "));
|
|
82
|
-
if (brewCmd) return brewCmd.cmd;
|
|
83
|
-
} else if (!_isImmutable) {
|
|
84
|
-
const nonBrew = candidates.find((o) => !o.cmd.startsWith("brew "));
|
|
85
|
-
if (nonBrew) return nonBrew.cmd;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
52
|
return (
|
|
90
53
|
dep.install.find((o) => o.platform === plat)?.cmd ??
|
|
91
54
|
dep.install.find((o) => o.platform === "any")?.cmd ??
|
|
@@ -108,6 +71,18 @@ export function installHints(dep: Dep): string[] {
|
|
|
108
71
|
*/
|
|
109
72
|
export const DEPS: Dep[] = [
|
|
110
73
|
// --- Core: most users want these ---
|
|
74
|
+
{
|
|
75
|
+
id: "nix",
|
|
76
|
+
name: "Nix",
|
|
77
|
+
purpose: "Universal package manager — installs all other dependencies on any OS",
|
|
78
|
+
usedBy: ["bootstrap"],
|
|
79
|
+
tier: "core",
|
|
80
|
+
check: () => hasCmd("nix"),
|
|
81
|
+
install: [
|
|
82
|
+
{ platform: "any", cmd: "curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install" },
|
|
83
|
+
],
|
|
84
|
+
url: "https://zero-to-nix.com",
|
|
85
|
+
},
|
|
111
86
|
{
|
|
112
87
|
id: "ollama",
|
|
113
88
|
name: "Ollama",
|
|
@@ -115,9 +90,9 @@ export const DEPS: Dep[] = [
|
|
|
115
90
|
usedBy: ["local-inference", "project-memory", "cleave", "offline-driver"],
|
|
116
91
|
tier: "core",
|
|
117
92
|
check: () => hasCmd("ollama"),
|
|
93
|
+
requires: ["nix"],
|
|
118
94
|
install: [
|
|
119
|
-
{ platform: "
|
|
120
|
-
{ platform: "linux", cmd: "curl -fsSL https://ollama.com/install.sh | sh" },
|
|
95
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#ollama" },
|
|
121
96
|
],
|
|
122
97
|
url: "https://ollama.com",
|
|
123
98
|
},
|
|
@@ -128,9 +103,9 @@ export const DEPS: Dep[] = [
|
|
|
128
103
|
usedBy: ["render", "view"],
|
|
129
104
|
tier: "core",
|
|
130
105
|
check: () => hasCmd("d2"),
|
|
106
|
+
requires: ["nix"],
|
|
131
107
|
install: [
|
|
132
|
-
{ platform: "
|
|
133
|
-
{ platform: "linux", cmd: "curl -fsSL https://d2lang.com/install.sh | sh" },
|
|
108
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#d2" },
|
|
134
109
|
],
|
|
135
110
|
url: "https://d2lang.com",
|
|
136
111
|
},
|
|
@@ -143,10 +118,9 @@ export const DEPS: Dep[] = [
|
|
|
143
118
|
usedBy: ["01-auth"],
|
|
144
119
|
tier: "recommended",
|
|
145
120
|
check: () => hasCmd("gh"),
|
|
121
|
+
requires: ["nix"],
|
|
146
122
|
install: [
|
|
147
|
-
{ platform: "
|
|
148
|
-
{ platform: "linux", cmd: "brew install gh" },
|
|
149
|
-
{ platform: "linux", cmd: "sudo apt install gh || sudo dnf install gh" },
|
|
123
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#gh" },
|
|
150
124
|
],
|
|
151
125
|
url: "https://cli.github.com",
|
|
152
126
|
},
|
|
@@ -157,9 +131,9 @@ export const DEPS: Dep[] = [
|
|
|
157
131
|
usedBy: ["view"],
|
|
158
132
|
tier: "recommended",
|
|
159
133
|
check: () => hasCmd("pandoc"),
|
|
134
|
+
requires: ["nix"],
|
|
160
135
|
install: [
|
|
161
|
-
{ platform: "
|
|
162
|
-
{ platform: "linux", cmd: "sudo apt install pandoc || sudo dnf install pandoc" },
|
|
136
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#pandoc" },
|
|
163
137
|
],
|
|
164
138
|
url: "https://pandoc.org",
|
|
165
139
|
},
|
|
@@ -171,9 +145,7 @@ export const DEPS: Dep[] = [
|
|
|
171
145
|
tier: "recommended",
|
|
172
146
|
check: () => hasCmd("cargo"),
|
|
173
147
|
install: [
|
|
174
|
-
|
|
175
|
-
// "1) Proceed / 2) Customise / 3) Cancel" prompt that otherwise hangs.
|
|
176
|
-
{ platform: "any", cmd: "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y" },
|
|
148
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#rustup && rustup default stable" },
|
|
177
149
|
],
|
|
178
150
|
url: "https://rustup.rs",
|
|
179
151
|
},
|
|
@@ -199,10 +171,9 @@ export const DEPS: Dep[] = [
|
|
|
199
171
|
usedBy: ["view"],
|
|
200
172
|
tier: "optional",
|
|
201
173
|
check: () => hasCmd("rsvg-convert"),
|
|
174
|
+
requires: ["nix"],
|
|
202
175
|
install: [
|
|
203
|
-
{ platform: "
|
|
204
|
-
{ platform: "linux", cmd: "brew install librsvg" },
|
|
205
|
-
{ platform: "linux", cmd: "sudo apt install librsvg2-bin" },
|
|
176
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#librsvg" },
|
|
206
177
|
],
|
|
207
178
|
},
|
|
208
179
|
{
|
|
@@ -212,10 +183,9 @@ export const DEPS: Dep[] = [
|
|
|
212
183
|
usedBy: ["view"],
|
|
213
184
|
tier: "optional",
|
|
214
185
|
check: () => hasCmd("pdftoppm"),
|
|
186
|
+
requires: ["nix"],
|
|
215
187
|
install: [
|
|
216
|
-
{ platform: "
|
|
217
|
-
{ platform: "linux", cmd: "brew install poppler" },
|
|
218
|
-
{ platform: "linux", cmd: "sudo apt install poppler-utils" },
|
|
188
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#poppler_utils" },
|
|
219
189
|
],
|
|
220
190
|
},
|
|
221
191
|
{
|
|
@@ -225,9 +195,9 @@ export const DEPS: Dep[] = [
|
|
|
225
195
|
usedBy: ["render"],
|
|
226
196
|
tier: "optional",
|
|
227
197
|
check: () => hasCmd("uv"),
|
|
198
|
+
requires: ["nix"],
|
|
228
199
|
install: [
|
|
229
|
-
{ platform: "
|
|
230
|
-
{ platform: "any", cmd: "curl -LsSf https://astral.sh/uv/install.sh | sh" },
|
|
200
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#uv" },
|
|
231
201
|
],
|
|
232
202
|
url: "https://docs.astral.sh/uv/",
|
|
233
203
|
},
|
|
@@ -238,10 +208,9 @@ export const DEPS: Dep[] = [
|
|
|
238
208
|
usedBy: ["01-auth"],
|
|
239
209
|
tier: "optional",
|
|
240
210
|
check: () => hasCmd("aws"),
|
|
211
|
+
requires: ["nix"],
|
|
241
212
|
install: [
|
|
242
|
-
{ platform: "
|
|
243
|
-
{ platform: "linux", cmd: "brew install awscli" },
|
|
244
|
-
{ platform: "linux", cmd: "sudo apt install awscli" },
|
|
213
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#awscli2" },
|
|
245
214
|
],
|
|
246
215
|
},
|
|
247
216
|
{
|
|
@@ -251,10 +220,9 @@ export const DEPS: Dep[] = [
|
|
|
251
220
|
usedBy: ["01-auth"],
|
|
252
221
|
tier: "optional",
|
|
253
222
|
check: () => hasCmd("kubectl"),
|
|
223
|
+
requires: ["nix"],
|
|
254
224
|
install: [
|
|
255
|
-
{ platform: "
|
|
256
|
-
{ platform: "linux", cmd: "brew install kubectl" },
|
|
257
|
-
{ platform: "linux", cmd: "sudo apt install kubectl" },
|
|
225
|
+
{ platform: "any", cmd: "nix profile install nixpkgs#kubectl" },
|
|
258
226
|
],
|
|
259
227
|
},
|
|
260
228
|
];
|
|
@@ -269,13 +237,40 @@ export function checkAll(): DepStatus[] {
|
|
|
269
237
|
}));
|
|
270
238
|
}
|
|
271
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Detect whether the terminal supports Unicode emoji rendering.
|
|
242
|
+
*
|
|
243
|
+
* Returns true for modern terminals (Windows Terminal, VS Code, xterm-256color,
|
|
244
|
+
* iTerm2, etc.) and false for legacy consoles (Windows conhost.exe) where emoji
|
|
245
|
+
* render as blank boxes. Errs on the side of ASCII when uncertain.
|
|
246
|
+
*/
|
|
247
|
+
function supportsEmoji(): boolean {
|
|
248
|
+
// Windows Terminal sets WT_SESSION; conhost.exe does not
|
|
249
|
+
if (process.env["WT_SESSION"]) return true;
|
|
250
|
+
// VS Code integrated terminal
|
|
251
|
+
if (process.env["TERM_PROGRAM"] === "vscode") return true;
|
|
252
|
+
// iTerm2, Hyper, and other macOS/Linux terminals advertising 256-color
|
|
253
|
+
if (process.env["TERM_PROGRAM"] === "iTerm.app") return true;
|
|
254
|
+
// xterm-256color and similar modern TERM values
|
|
255
|
+
const term = process.env["TERM"] ?? "";
|
|
256
|
+
if (term.includes("256color") || term === "xterm-kitty") return true;
|
|
257
|
+
// COLORTERM=truecolor or 24bit signals a modern terminal
|
|
258
|
+
const colorterm = process.env["COLORTERM"] ?? "";
|
|
259
|
+
if (colorterm === "truecolor" || colorterm === "24bit") return true;
|
|
260
|
+
// CI environments typically render emoji correctly
|
|
261
|
+
if (process.env["CI"]) return true;
|
|
262
|
+
// Non-Windows: default to emoji; on Windows without the above signals, use ASCII
|
|
263
|
+
return process.platform !== "win32";
|
|
264
|
+
}
|
|
265
|
+
|
|
272
266
|
/** Format a single dep status as a line, with install hint if missing */
|
|
273
267
|
function formatStatus(s: DepStatus): string {
|
|
274
|
-
const
|
|
268
|
+
const emoji = supportsEmoji();
|
|
269
|
+
const icon = s.available ? (emoji ? "✅" : "[ok]") : (emoji ? "❌" : "[x]");
|
|
275
270
|
let line = `${icon} ${s.dep.name} — ${s.dep.purpose}`;
|
|
276
271
|
if (!s.available) {
|
|
277
272
|
const cmd = bestInstallCmd(s.dep);
|
|
278
|
-
if (cmd) line += `\n → \`${cmd}\``;
|
|
273
|
+
if (cmd) line += `\n ${emoji ? "→" : "->"} \`${cmd}\``;
|
|
279
274
|
}
|
|
280
275
|
return line;
|
|
281
276
|
}
|
|
@@ -303,10 +298,11 @@ export function formatReport(statuses: DepStatus[]): string {
|
|
|
303
298
|
}
|
|
304
299
|
|
|
305
300
|
const missing = statuses.filter((s) => !s.available);
|
|
301
|
+
const emoji = supportsEmoji();
|
|
306
302
|
if (missing.length === 0) {
|
|
307
|
-
lines.push("🎉 All dependencies are available!");
|
|
303
|
+
lines.push(emoji ? "🎉 All dependencies are available!" : "[ok] All dependencies are available!");
|
|
308
304
|
} else {
|
|
309
|
-
lines.push(
|
|
305
|
+
lines.push(`${emoji ? "⚠️ " : "[!] "}**${missing.length} missing** — run \`/bootstrap\` to install interactively.`);
|
|
310
306
|
}
|
|
311
307
|
|
|
312
308
|
return lines.join("\n");
|
|
@@ -25,6 +25,7 @@ import { dirname, join } from "node:path";
|
|
|
25
25
|
import { fileURLToPath } from "node:url";
|
|
26
26
|
import { homedir, tmpdir } from "node:os";
|
|
27
27
|
import type { ExtensionAPI } from "@styrene-lab/pi-coding-agent";
|
|
28
|
+
import { resolveOmegonSubprocess } from "../lib/omegon-subprocess.ts";
|
|
28
29
|
import { checkAllProviders, type AuthResult } from "../01-auth/auth.ts";
|
|
29
30
|
import { loadPiConfig } from "../lib/model-preferences.ts";
|
|
30
31
|
import {
|
|
@@ -362,11 +363,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
362
363
|
|
|
363
364
|
if (sub === "status") {
|
|
364
365
|
const statuses = checkAll();
|
|
365
|
-
cmdCtx.say(formatReport(statuses));
|
|
366
366
|
const profile = loadOperatorProfile(getConfigRoot(cmdCtx));
|
|
367
|
-
|
|
367
|
+
const profileLine = profile
|
|
368
368
|
? `\nOperator capability profile: ${profile.setupComplete ? "configured" : "defaulted"}`
|
|
369
|
-
: "\nOperator capability profile: not configured"
|
|
369
|
+
: "\nOperator capability profile: not configured";
|
|
370
|
+
// Merge into a single say() call — the pi TUI showStatus() deduplication
|
|
371
|
+
// pattern replaces the previous notification when two consecutive say()
|
|
372
|
+
// calls are made synchronously, so splitting these would silently discard
|
|
373
|
+
// the dependency report.
|
|
374
|
+
cmdCtx.say(formatReport(statuses) + profileLine);
|
|
370
375
|
return;
|
|
371
376
|
}
|
|
372
377
|
|
|
@@ -409,10 +414,48 @@ export default function (pi: ExtensionAPI) {
|
|
|
409
414
|
await ctx.reload();
|
|
410
415
|
},
|
|
411
416
|
});
|
|
417
|
+
|
|
418
|
+
// --- /restart: full process restart ---
|
|
419
|
+
pi.registerCommand("restart", {
|
|
420
|
+
description: "Restart Omegon (clears cache, spawns fresh process)",
|
|
421
|
+
handler: async (_args, ctx) => {
|
|
422
|
+
clearJitiCache(ctx);
|
|
423
|
+
ctx.ui.notify("Restarting Omegon…", "info");
|
|
424
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
425
|
+
restartOmegon();
|
|
426
|
+
},
|
|
427
|
+
});
|
|
412
428
|
}
|
|
413
429
|
|
|
414
430
|
// ── /update helpers ──────────────────────────────────────────────────────
|
|
415
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Replace the current Omegon process with a fresh instance.
|
|
434
|
+
*
|
|
435
|
+
* Spawns a new detached Omegon process with inherited stdio, then exits
|
|
436
|
+
* the current process. The user sees the terminal briefly reset and the
|
|
437
|
+
* new session starts automatically — no manual re-launch needed.
|
|
438
|
+
*/
|
|
439
|
+
function restartOmegon(): never {
|
|
440
|
+
const { command, argvPrefix } = resolveOmegonSubprocess();
|
|
441
|
+
// Pass through any user-facing args from the original invocation
|
|
442
|
+
// (skip argv[0]=node, argv[1]=omegon.mjs which argvPrefix covers)
|
|
443
|
+
const userArgs = process.argv.slice(2).filter(a =>
|
|
444
|
+
// Strip injected resource flags — the new process injects its own
|
|
445
|
+
!a.startsWith("--extensions-dir=") &&
|
|
446
|
+
!a.startsWith("--themes-dir=") &&
|
|
447
|
+
!a.startsWith("--skills-dir=") &&
|
|
448
|
+
!a.startsWith("--prompts-dir=")
|
|
449
|
+
);
|
|
450
|
+
const child = spawn(command, [...argvPrefix, ...userArgs], {
|
|
451
|
+
stdio: "inherit",
|
|
452
|
+
detached: true,
|
|
453
|
+
env: process.env,
|
|
454
|
+
});
|
|
455
|
+
child.unref();
|
|
456
|
+
process.exit(0);
|
|
457
|
+
}
|
|
458
|
+
|
|
416
459
|
/** Run a command, collect stdout+stderr, resolve with exit code. */
|
|
417
460
|
function run(
|
|
418
461
|
cmd: string, args: string[], opts?: { cwd?: string },
|
|
@@ -609,11 +652,15 @@ async function updateDevMode(
|
|
|
609
652
|
}
|
|
610
653
|
steps.push(formatVerification(verification));
|
|
611
654
|
|
|
612
|
-
// ── Step 7: clear cache +
|
|
655
|
+
// ── Step 7: clear cache + restart ────────────────────────────────
|
|
613
656
|
const cleared = clearJitiCache(ctx);
|
|
614
657
|
if (cleared > 0) steps.push(`✓ cleared ${cleared} cached transpilations`);
|
|
615
|
-
steps.push("✓ update complete —
|
|
658
|
+
steps.push("✓ update complete — restarting Omegon…");
|
|
616
659
|
ctx.ui.notify(steps.join("\n"), "info");
|
|
660
|
+
|
|
661
|
+
// Brief pause so the user sees the summary before the terminal resets
|
|
662
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
663
|
+
restartOmegon();
|
|
617
664
|
}
|
|
618
665
|
|
|
619
666
|
/** Installed mode: npm install -g omegon@latest → verify → cache clear → restart handoff. */
|
|
@@ -687,9 +734,12 @@ async function updateInstalledMode(
|
|
|
687
734
|
`✅ Updated to ${PKG}@${latestVersion}.` +
|
|
688
735
|
`\n${formatVerification(verification)}` +
|
|
689
736
|
(cleared > 0 ? `\nCleared ${cleared} cached transpilations.` : "") +
|
|
690
|
-
"\
|
|
737
|
+
"\nRestarting Omegon…",
|
|
691
738
|
"info"
|
|
692
739
|
);
|
|
740
|
+
|
|
741
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
742
|
+
restartOmegon();
|
|
693
743
|
}
|
|
694
744
|
|
|
695
745
|
async function interactiveSetup(pi: ExtensionAPI, ctx: CommandContext): Promise<void> {
|
|
@@ -973,6 +1023,21 @@ function patchPathForCargo(): void {
|
|
|
973
1023
|
}
|
|
974
1024
|
}
|
|
975
1025
|
|
|
1026
|
+
/** After Determinate Nix install, add nix to PATH so subsequent installs work. */
|
|
1027
|
+
function patchPathForNix(): void {
|
|
1028
|
+
const nixPaths = [
|
|
1029
|
+
"/nix/var/nix/profiles/default/bin",
|
|
1030
|
+
join(homedir(), ".nix-profile", "bin"),
|
|
1031
|
+
];
|
|
1032
|
+
const current = process.env.PATH ?? "";
|
|
1033
|
+
const parts = current.split(":");
|
|
1034
|
+
for (const nixBin of nixPaths) {
|
|
1035
|
+
if (existsSync(nixBin) && !parts.includes(nixBin)) {
|
|
1036
|
+
process.env.PATH = `${nixBin}:${process.env.PATH}`;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
976
1041
|
async function installDeps(ctx: CommandContext, deps: DepStatus[]): Promise<void> {
|
|
977
1042
|
// Sort so prerequisites come first (e.g., cargo before mdserve)
|
|
978
1043
|
const sorted = sortByRequires(deps);
|
|
@@ -1008,8 +1073,11 @@ async function installDeps(ctx: CommandContext, deps: DepStatus[]): Promise<void
|
|
|
1008
1073
|
(line) => ctx.ui.notify(line),
|
|
1009
1074
|
);
|
|
1010
1075
|
|
|
1011
|
-
//
|
|
1012
|
-
// of the install sequence
|
|
1076
|
+
// Patch PATH immediately after installing bootstrapping deps so the rest
|
|
1077
|
+
// of the install sequence can find them without a new shell.
|
|
1078
|
+
if (dep.id === "nix" && exitCode === 0) {
|
|
1079
|
+
patchPathForNix();
|
|
1080
|
+
}
|
|
1013
1081
|
if (dep.id === "cargo" && exitCode === 0) {
|
|
1014
1082
|
patchPathForCargo();
|
|
1015
1083
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* clipboard-diag — Diagnostic command for clipboard image paste.
|
|
3
|
+
*
|
|
4
|
+
* Registers /cliptest to diagnose why Ctrl+V image paste may fail.
|
|
5
|
+
*/
|
|
6
|
+
import type { ExtensionAPI } from "../../vendor/pi-mono/packages/coding-agent/src/core/extensions/types.js";
|
|
7
|
+
|
|
8
|
+
export default function clipboardDiag(pi: ExtensionAPI) {
|
|
9
|
+
pi.registerCommand("cliptest", {
|
|
10
|
+
description: "Test clipboard image access (diagnostic)",
|
|
11
|
+
async handler() {
|
|
12
|
+
const lines: string[] = ["**Clipboard Image Diagnostic**", ""];
|
|
13
|
+
|
|
14
|
+
// 1. Check native module
|
|
15
|
+
let clipModule: string | null = null;
|
|
16
|
+
let clipboard: { hasImage: () => boolean; getImageBinary: () => Promise<unknown> } | null = null;
|
|
17
|
+
const candidates = ["@cwilson613/clipboard", "@mariozechner/clipboard"];
|
|
18
|
+
for (const name of candidates) {
|
|
19
|
+
try {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
21
|
+
const mod = require(name);
|
|
22
|
+
clipboard = mod;
|
|
23
|
+
clipModule = name;
|
|
24
|
+
break;
|
|
25
|
+
} catch {
|
|
26
|
+
// next
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!clipboard) {
|
|
31
|
+
lines.push("❌ No clipboard native module found");
|
|
32
|
+
lines.push(` Tried: ${candidates.join(", ")}`);
|
|
33
|
+
} else {
|
|
34
|
+
lines.push(`✓ Module: ${clipModule}`);
|
|
35
|
+
|
|
36
|
+
// 2. Check hasImage
|
|
37
|
+
try {
|
|
38
|
+
const has = clipboard.hasImage();
|
|
39
|
+
lines.push(`${has ? "✓" : "❌"} hasImage(): ${has}`);
|
|
40
|
+
|
|
41
|
+
// 3. Try reading
|
|
42
|
+
if (has) {
|
|
43
|
+
try {
|
|
44
|
+
const data = await clipboard.getImageBinary();
|
|
45
|
+
const len = Array.isArray(data) ? data.length : (data as Uint8Array)?.length ?? 0;
|
|
46
|
+
lines.push(`${len > 0 ? "✓" : "❌"} getImageBinary(): ${len} bytes`);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
lines.push(`❌ getImageBinary() threw: ${e instanceof Error ? e.message : String(e)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch (e) {
|
|
52
|
+
lines.push(`❌ hasImage() threw: ${e instanceof Error ? e.message : String(e)}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 4. Platform info
|
|
57
|
+
lines.push("");
|
|
58
|
+
lines.push(`Platform: ${process.platform}, TERM: ${process.env.TERM ?? "unset"}`);
|
|
59
|
+
lines.push(`DISPLAY: ${process.env.DISPLAY ?? "unset"}, WAYLAND: ${process.env.WAYLAND_DISPLAY ?? "unset"}`);
|
|
60
|
+
|
|
61
|
+
pi.sendMessage({ customType: "view", content: lines.join("\n"), display: true });
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omegon",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.13",
|
|
4
4
|
"description": "Omegon — an opinionated distribution of pi (by Mario Zechner) with extensions for lifecycle management, memory, orchestration, and visualization",
|
|
5
5
|
"bin": {
|
|
6
6
|
"omegon": "bin/omegon.mjs",
|
|
@@ -73,13 +73,17 @@
|
|
|
73
73
|
"./extensions/tool-profile",
|
|
74
74
|
"./extensions/vault",
|
|
75
75
|
"./extensions/version-check.ts",
|
|
76
|
-
"./extensions/web-ui"
|
|
76
|
+
"./extensions/web-ui",
|
|
77
|
+
"./extensions/clipboard-diag/index.ts"
|
|
77
78
|
],
|
|
78
79
|
"skills": [
|
|
79
80
|
"./skills"
|
|
80
81
|
],
|
|
81
82
|
"prompts": [
|
|
82
83
|
"./prompts"
|
|
84
|
+
],
|
|
85
|
+
"themes": [
|
|
86
|
+
"./themes"
|
|
83
87
|
]
|
|
84
88
|
},
|
|
85
89
|
"dependencies": {
|