@polderlabs/bizar-omp 0.8.1 → 0.9.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 +284 -338
- package/dist/cli/doctor.d.ts +4 -4
- package/dist/core/types.d.ts +29 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/extension.d.ts.map +1 -1
- package/dist/extension.js +47 -11
- package/dist/extension.js.map +1 -1
- package/dist/omp/compatibility.d.ts +15 -5
- package/dist/omp/compatibility.d.ts.map +1 -1
- package/dist/omp/compatibility.js +12 -2
- package/dist/omp/compatibility.js.map +1 -1
- package/dist/omp/dispatch-lifecycle.d.ts +14 -0
- package/dist/omp/dispatch-lifecycle.d.ts.map +1 -1
- package/dist/omp/dispatch-lifecycle.js +10 -1
- package/dist/omp/dispatch-lifecycle.js.map +1 -1
- package/dist/omp/omb-sessions.d.ts +8 -1
- package/dist/omp/omb-sessions.d.ts.map +1 -1
- package/dist/omp/omb-sessions.js +20 -17
- package/dist/omp/omb-sessions.js.map +1 -1
- package/dist/omp/rpc.d.ts +3 -0
- package/dist/omp/rpc.d.ts.map +1 -1
- package/dist/omp/session-ownership.d.ts +64 -0
- package/dist/omp/session-ownership.d.ts.map +1 -0
- package/dist/omp/session-ownership.js +269 -0
- package/dist/omp/session-ownership.js.map +1 -0
- package/dist/omp/task-model-selector.d.ts +58 -0
- package/dist/omp/task-model-selector.d.ts.map +1 -0
- package/dist/omp/task-model-selector.js +144 -0
- package/dist/omp/task-model-selector.js.map +1 -0
- package/dist/scripts/emit-compatibility-receipt.js +13 -3
- package/dist/scripts/emit-compatibility-receipt.js.map +1 -1
- package/docs/assets/bizar-omp-banner.svg +51 -18
- package/docs/compatibility/baseline.json +9 -8
- package/docs/compatibility/supported-surfaces.json +11 -3
- package/docs/releases/0.9.0.md +35 -0
- package/docs/releases/support-matrix.md +1 -1
- package/package.json +1 -1
- package/skills/omp-native-development/SKILL.md +5 -3
- package/skills/omp-native-development/assets/tests/acceptance-matrix.json +417 -0
- package/skills/omp-native-development/references/accuracy-and-versioning.md +1 -1
- package/skills/omp-native-development/references/bizar-integration-contract.md +1 -1
- package/skills/omp-native-development/references/developer-handoff.md +3 -1
- package/skills/omp-native-development/references/execution-and-lifecycle.md +4 -0
- package/skills/omp-native-development/references/native-validation-matrix.md +25 -0
- package/skills/omp-native-development/references/sessions-sdk-rpc.md +17 -0
- package/skills/omp-native-development/references/settings-providers-security.md +11 -0
- package/skills/omp-native-development/references/source-manifest.json +20 -4
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { closeSync, existsSync, mkdirSync, openSync, readSync } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { OwnershipError } from "../core/errors.js";
|
|
7
|
+
import { acquireLease } from "../storage/lease.js";
|
|
8
|
+
/**
|
|
9
|
+
* Session ownership, keyed the way OMP 18.5 keys it.
|
|
10
|
+
*
|
|
11
|
+
* OMP moved ownership from the journal's path to the session id in its header:
|
|
12
|
+
* `tryAcquireSessionLease(sessionId)` holds an OS-backed lease — an abstract
|
|
13
|
+
* Unix socket on Linux, a named mutex on Windows — under OMP's own
|
|
14
|
+
* session-owners directory. Because the key is the id rather than the path,
|
|
15
|
+
* every process that reaches one journal, through a hard link, a symlink, or
|
|
16
|
+
* after a move, meets the same lease; and a journal that has been replaced by a
|
|
17
|
+
* different session is detected instead of being written into.
|
|
18
|
+
*
|
|
19
|
+
* Bizar previously keyed a private lease on the journal's inode. That protects
|
|
20
|
+
* processes which cooperate with Bizar's own lock, but it is a different
|
|
21
|
+
* ownership domain from OMP's: a plain `omp` process never took it, so
|
|
22
|
+
* claiming "already open in another OMP or OMB process" asserted more than
|
|
23
|
+
* Bizar could prove.
|
|
24
|
+
*
|
|
25
|
+
* So this module keeps the two apart rather than conflating them:
|
|
26
|
+
*
|
|
27
|
+
* 1. It reads and validates the journal's native session id before any
|
|
28
|
+
* ownership operation, because an id is what both domains key on.
|
|
29
|
+
* 2. It takes OMP's **native** lease through OMP's own exported function when
|
|
30
|
+
* that runtime is reachable, so a plain OMP process holding the journal is
|
|
31
|
+
* observed instead of guessed at. Bizar does not reimplement OMP's lock
|
|
32
|
+
* format — an abstract socket cannot be reimplemented from the outside.
|
|
33
|
+
*
|
|
34
|
+
* The Bizar-private lease remains, but only for Bizar-owned state OMP itself
|
|
35
|
+
* does not own, and it is keyed by the same session id so both agree on which
|
|
36
|
+
* journal is being claimed.
|
|
37
|
+
*
|
|
38
|
+
* Acquisition is synchronous because every caller is synchronous — session
|
|
39
|
+
* start, session switch, delete, and migration all sit on synchronous
|
|
40
|
+
* extension handlers. The native module is therefore loaded with
|
|
41
|
+
* `createRequire` rather than a dynamic `import()`, which would only resolve
|
|
42
|
+
* later and leave the native path permanently unexercised.
|
|
43
|
+
*/
|
|
44
|
+
/** Bytes read to find a header; the fixed-width title slot plus one line fits well inside. */
|
|
45
|
+
const HEADER_PREFIX_BYTES = 64 * 1024;
|
|
46
|
+
const NATIVE_SESSION_STORAGE = ["src", "session", "session-storage.ts"];
|
|
47
|
+
/**
|
|
48
|
+
* The session id in the header of the journal at `journalPath`.
|
|
49
|
+
*
|
|
50
|
+
* OMP writes a fixed-width title slot ahead of the JSONL entries, so the first
|
|
51
|
+
* line is not necessarily the header. This scans the bounded prefix for the
|
|
52
|
+
* first entry that is actually a session header, the same tolerance the
|
|
53
|
+
* repository's existing journal reader applies, rather than assuming a fixed
|
|
54
|
+
* line position. Anything that never yields a session header reports
|
|
55
|
+
* `undefined` instead of a guessed id.
|
|
56
|
+
*/
|
|
57
|
+
export function readJournalSessionId(journalPath) {
|
|
58
|
+
let prefix;
|
|
59
|
+
try {
|
|
60
|
+
const fd = openSync(journalPath, "r");
|
|
61
|
+
try {
|
|
62
|
+
const buffer = Buffer.alloc(HEADER_PREFIX_BYTES);
|
|
63
|
+
prefix = buffer.toString("utf8", 0, readSync(fd, buffer, 0, buffer.length, 0));
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
closeSync(fd);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
for (const line of prefix.split("\n")) {
|
|
73
|
+
const id = sessionIdFromLine(line);
|
|
74
|
+
if (id !== undefined)
|
|
75
|
+
return id;
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
function sessionIdFromLine(line) {
|
|
80
|
+
try {
|
|
81
|
+
const entry = JSON.parse(line);
|
|
82
|
+
if (entry === null || typeof entry !== "object")
|
|
83
|
+
return undefined;
|
|
84
|
+
const record = entry;
|
|
85
|
+
if (record.type !== "session" || typeof record.id !== "string" || !record.id.trim())
|
|
86
|
+
return undefined;
|
|
87
|
+
return record.id.trim();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Where OMP's own package lives, or `undefined` when it is not reachable.
|
|
95
|
+
*
|
|
96
|
+
* An OMP installed as a self-contained binary exposes no importable module at
|
|
97
|
+
* all, which is a real supported shape rather than a failure.
|
|
98
|
+
*/
|
|
99
|
+
function resolveOmpPackageRoot(env) {
|
|
100
|
+
const configured = env.BIZAR_OMP_PACKAGE_ROOT?.trim();
|
|
101
|
+
if (configured)
|
|
102
|
+
return resolve(configured);
|
|
103
|
+
try {
|
|
104
|
+
return dirname(createRequire(import.meta.url).resolve("@oh-my-pi/pi-coding-agent/package.json"));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Not resolvable from Bizar; fall through to the executable's own tree.
|
|
108
|
+
}
|
|
109
|
+
for (const executable of [env.OMP_PATH?.trim(), "/usr/local/bin/omp", "/usr/bin/omp"].filter((value) => Boolean(value))) {
|
|
110
|
+
let dir = dirname(resolve(executable));
|
|
111
|
+
for (let depth = 0; depth < 6; depth += 1) {
|
|
112
|
+
const root = join(dir, "node_modules", "@oh-my-pi", "pi-coding-agent");
|
|
113
|
+
if (existsSync(join(root, "package.json")))
|
|
114
|
+
return root;
|
|
115
|
+
const parent = dirname(dir);
|
|
116
|
+
if (parent === dir)
|
|
117
|
+
break;
|
|
118
|
+
dir = parent;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Narrow a loaded module to the lease function, or `undefined` when the export
|
|
125
|
+
* is absent. A shape check is required because the module comes from outside
|
|
126
|
+
* this package and a missing export must degrade, not throw.
|
|
127
|
+
*/
|
|
128
|
+
function asNativeSessionStorage(loaded) {
|
|
129
|
+
if (loaded === null || typeof loaded !== "object")
|
|
130
|
+
return undefined;
|
|
131
|
+
const candidate = loaded;
|
|
132
|
+
const acquire = candidate.tryAcquireSessionLease;
|
|
133
|
+
if (typeof acquire !== "function")
|
|
134
|
+
return undefined;
|
|
135
|
+
return { tryAcquireSessionLease: (sessionId) => acquire.call(loaded, sessionId) };
|
|
136
|
+
}
|
|
137
|
+
const nativeModuleCache = {};
|
|
138
|
+
/**
|
|
139
|
+
* Native leases this process already holds, so a second claim on the same
|
|
140
|
+
* session is a re-entry rather than self-collision.
|
|
141
|
+
*
|
|
142
|
+
* OMP keeps an equivalent process-local map, because one logical migration can
|
|
143
|
+
* legitimately need to claim the same session more than once — for example the
|
|
144
|
+
* source and its staged copy. Without this, Bizar would report its own
|
|
145
|
+
* re-entry as "another OMP process owns it".
|
|
146
|
+
*/
|
|
147
|
+
const heldNativeLeases = new Map();
|
|
148
|
+
/**
|
|
149
|
+
* Take OMP's own ownership lease for `sessionId` through OMP's exported
|
|
150
|
+
* function, resolved from the installed OMP runtime.
|
|
151
|
+
*
|
|
152
|
+
* A runtime that is not reachable is reported as `unavailable`, never as
|
|
153
|
+
* "nobody owns it". That distinction matters: Bizar must not conclude a
|
|
154
|
+
* journal is free because it failed to find the module.
|
|
155
|
+
*/
|
|
156
|
+
export function probeNativeSessionLease(sessionId, env = process.env) {
|
|
157
|
+
const root = resolveOmpPackageRoot(env);
|
|
158
|
+
const reentry = heldNativeLeases.get(sessionId);
|
|
159
|
+
if (reentry) {
|
|
160
|
+
reentry.depth += 1;
|
|
161
|
+
return { status: "acquired", release: () => releaseHeldNativeLease(sessionId, reentry) };
|
|
162
|
+
}
|
|
163
|
+
if (!root)
|
|
164
|
+
return { status: "unavailable", reason: "the installed OMP runtime exposes no importable session-storage module" };
|
|
165
|
+
if (nativeModuleCache.root !== root) {
|
|
166
|
+
nativeModuleCache.root = root;
|
|
167
|
+
try {
|
|
168
|
+
// A plain path, not a `file://` URL: Node's CommonJS resolver rejects a
|
|
169
|
+
// URL string here, and it loads a `.ts` source with its JavaScript loader.
|
|
170
|
+
const loaded = createRequire(import.meta.url)(join(root, ...NATIVE_SESSION_STORAGE));
|
|
171
|
+
nativeModuleCache.storage = asNativeSessionStorage(loaded);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
nativeModuleCache.storage = undefined;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const storage = nativeModuleCache.storage;
|
|
178
|
+
if (!storage)
|
|
179
|
+
return { status: "unavailable", reason: "the installed OMP runtime exports no session ownership lease" };
|
|
180
|
+
let handle;
|
|
181
|
+
try {
|
|
182
|
+
handle = storage.tryAcquireSessionLease(sessionId);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
// OMP's own `claimSession` swallows a failed probe and carries on. Bizar's
|
|
186
|
+
// delete, migrate and resume callers depend on a throw to refuse, so a
|
|
187
|
+
// failed probe fails closed here instead of downgrading to the Bizar lock.
|
|
188
|
+
return { status: "probe-failed", reason: error instanceof Error ? error.message : String(error) };
|
|
189
|
+
}
|
|
190
|
+
if (handle === null)
|
|
191
|
+
return { status: "held-by-another-process" };
|
|
192
|
+
// Bound to its handle: OMP's FileLock.release reaches a native exclusive
|
|
193
|
+
// reference through `this`, so an unbound copy throws "Failed to unwrap
|
|
194
|
+
// exclusive reference of FileLock" instead of releasing the lease.
|
|
195
|
+
const held = { release: handle.release.bind(handle), depth: 1 };
|
|
196
|
+
heldNativeLeases.set(sessionId, held);
|
|
197
|
+
return { status: "acquired", release: () => releaseHeldNativeLease(sessionId, held) };
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Test seam: drop every memoized module and held-claim so another runtime, or
|
|
201
|
+
* the next case, starts from a clean process-local state.
|
|
202
|
+
*/
|
|
203
|
+
export function resetNativeSessionLeaseProbe() {
|
|
204
|
+
nativeModuleCache.root = undefined;
|
|
205
|
+
nativeModuleCache.storage = undefined;
|
|
206
|
+
heldNativeLeases.clear();
|
|
207
|
+
}
|
|
208
|
+
/** Drop one level of this process's claim, releasing OMP's lease at zero. */
|
|
209
|
+
function releaseHeldNativeLease(sessionId, held) {
|
|
210
|
+
// A double release must not drive the counter negative, which would leave
|
|
211
|
+
// the map claiming a claim that no longer exists.
|
|
212
|
+
if (held.depth <= 0)
|
|
213
|
+
return;
|
|
214
|
+
held.depth -= 1;
|
|
215
|
+
if (held.depth > 0)
|
|
216
|
+
return;
|
|
217
|
+
heldNativeLeases.delete(sessionId);
|
|
218
|
+
held.release();
|
|
219
|
+
}
|
|
220
|
+
/** Bizar's own cooperating-process lease, keyed by the same native session id. */
|
|
221
|
+
function sessionLeasePath(sessionId, env) {
|
|
222
|
+
const root = sessionLeaseRoot(env);
|
|
223
|
+
return join(root, `${createHash("sha256").update(`session:${sessionId}`).digest("hex")}.lock`);
|
|
224
|
+
}
|
|
225
|
+
/** Create Bizar's lease root, which `acquireLease` requires to already exist. */
|
|
226
|
+
function sessionLeaseRoot(env) {
|
|
227
|
+
const root = join(env.XDG_STATE_HOME || join(env.HOME || homedir(), ".local", "state"), "bizar-omp", "session-leases");
|
|
228
|
+
mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
229
|
+
return root;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Claim exclusive write access to a native OMP journal.
|
|
233
|
+
*
|
|
234
|
+
* The journal's native session id is read first and is required: ownership in
|
|
235
|
+
* both domains is keyed on it, so a journal with no readable id cannot be
|
|
236
|
+
* proven to be the one Bizar recorded. Refusing there is deliberate — the
|
|
237
|
+
* alternative is mutating a file whose identity Bizar never established.
|
|
238
|
+
*
|
|
239
|
+
* When OMP's native lease is reachable it is taken too, so a plain `omp`
|
|
240
|
+
* process holding this journal blocks the operation. When it is not reachable
|
|
241
|
+
* the message names only Bizar-owned state, because that is all Bizar can
|
|
242
|
+
* actually prove at that moment.
|
|
243
|
+
*/
|
|
244
|
+
export function acquireSessionOwnership(journalPath, env = process.env) {
|
|
245
|
+
const sessionId = readJournalSessionId(journalPath);
|
|
246
|
+
if (!sessionId)
|
|
247
|
+
throw new OwnershipError(`Refusing to modify a session journal with no readable native session id: ${journalPath}`);
|
|
248
|
+
const native = probeNativeSessionLease(sessionId, env);
|
|
249
|
+
if (native.status === "held-by-another-process") {
|
|
250
|
+
throw new OwnershipError("This OMP session is open in another OMP process; close it there before resuming or deleting it.");
|
|
251
|
+
}
|
|
252
|
+
if (native.status === "probe-failed") {
|
|
253
|
+
throw new OwnershipError(`Refusing to modify a session journal because OMP's ownership lease could not be probed: ${native.reason}`);
|
|
254
|
+
}
|
|
255
|
+
const lease = acquireLease(sessionLeasePath(sessionId, env), native.status === "acquired"
|
|
256
|
+
? "This OMP session is already open in another OMP or OMB process; close it there before resuming."
|
|
257
|
+
: "This session is already open in another OMB process; close it there before resuming.");
|
|
258
|
+
if (native.status === "acquired") {
|
|
259
|
+
const releaseNative = native.release;
|
|
260
|
+
return { release() { try {
|
|
261
|
+
lease.release();
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
releaseNative();
|
|
265
|
+
} } };
|
|
266
|
+
}
|
|
267
|
+
return lease;
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=session-ownership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-ownership.js","sourceRoot":"","sources":["../../src/omp/session-ownership.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ObservedRouting, RoutingSource } from "../core/types.js";
|
|
2
|
+
export interface RequestedModelRouting {
|
|
3
|
+
/** Exact per-call selectors, in the order the caller supplied them. */
|
|
4
|
+
selectors: string[];
|
|
5
|
+
/** The native routing source Bizar admitted for this dispatch. */
|
|
6
|
+
source: RoutingSource;
|
|
7
|
+
/** The caller-supplied `effort`, kept separate from model identity. */
|
|
8
|
+
effort?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Normalize a requested per-call `model` into the ordered selector list Bizar
|
|
12
|
+
* journals, or refuse a selector OMP documents as invalid.
|
|
13
|
+
*
|
|
14
|
+
* Returns an empty list when no selector was requested, which is the signal
|
|
15
|
+
* that the specialist's own frontmatter and exact-agent override remain
|
|
16
|
+
* authoritative.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeRequestedModelSelectors(value: unknown): string[];
|
|
19
|
+
/**
|
|
20
|
+
* Build the routing record for one dispatch.
|
|
21
|
+
*
|
|
22
|
+
* Specialist identity and model routing stay separate fields: a
|
|
23
|
+
* `bizar-implementer` remains the implementer whichever selector it runs on.
|
|
24
|
+
* With no requested selector the source stays `specialist-default`, so the
|
|
25
|
+
* specialist's own model role keeps working exactly as before.
|
|
26
|
+
*/
|
|
27
|
+
export declare function requestedRouting(input: {
|
|
28
|
+
model?: unknown;
|
|
29
|
+
effort?: unknown;
|
|
30
|
+
}): RequestedModelRouting;
|
|
31
|
+
/**
|
|
32
|
+
* Select the settled result belonging to one dispatch.
|
|
33
|
+
*
|
|
34
|
+
* A call settles into `details.results`, one entry per spawn, and each entry
|
|
35
|
+
* carries the wire `name` it was spawned under. Matching is by that identity,
|
|
36
|
+
* never by position: `admitNativeTasks` skips tasks that name no work item, so
|
|
37
|
+
* the admitted dispatches are fewer than the spawns and indexing by admission
|
|
38
|
+
* order would hand a dispatch whichever spawn happened to come first.
|
|
39
|
+
*
|
|
40
|
+
* A single-entry batch is used directly, because there is only one candidate
|
|
41
|
+
* and the host may omit `name`. A purely background call returns `results: []`
|
|
42
|
+
* and leaves its routing on the progress snapshot, so an absent match stays
|
|
43
|
+
* unobserved: recording another spawn's routing would be a false provenance
|
|
44
|
+
* claim, which is the exact failure this contract exists to prevent.
|
|
45
|
+
*/
|
|
46
|
+
export declare function settledResultFor(details: unknown, workItemId: string): unknown;
|
|
47
|
+
/**
|
|
48
|
+
* Read the native routing OMP actually used for one settled spawn.
|
|
49
|
+
*
|
|
50
|
+
* These are the host's own flat fields on the settled result, siblings of
|
|
51
|
+
* `structuredOutput`, so the journal can distinguish the selector Bizar
|
|
52
|
+
* admitted from the model, identity, effort and fallback state OMP resolved.
|
|
53
|
+
* Every field is optional: the host omits routing it did not resolve, and an
|
|
54
|
+
* absent field must leave the dispatch on what was requested rather than
|
|
55
|
+
* inventing an observation.
|
|
56
|
+
*/
|
|
57
|
+
export declare function readObservedRouting(result: unknown): ObservedRouting | undefined;
|
|
58
|
+
//# sourceMappingURL=task-model-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-model-selector.d.ts","sourceRoot":"","sources":["../../src/omp/task-model-selector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA2BvE,MAAM,WAAW,qBAAqB;IACpC,uEAAuE;IACvE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kEAAkE;IAClE,MAAM,EAAE,aAAa,CAAC;IACtB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA4BD;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAQzE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,qBAAqB,CAKpG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAO9E;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAehF"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { ContractError } from "../core/errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Per-call `model` selector policy for managed Bizar dispatches.
|
|
4
|
+
*
|
|
5
|
+
* OMP 18.5 made `model` a public, highest-precedence field on every `task`
|
|
6
|
+
* item: it outranks `task.agentModelOverrides[agentName]` and the agent
|
|
7
|
+
* definition's own `model`. A managed run that dropped the field would admit a
|
|
8
|
+
* dispatch, journal a Bizar-computed role, and then let the host execute a
|
|
9
|
+
* different model than the journal claims — a provenance failure, not just a
|
|
10
|
+
* missing feature.
|
|
11
|
+
*
|
|
12
|
+
* Bizar therefore records what was requested instead of ignoring it, and
|
|
13
|
+
* refuses only the selectors OMP documents as ambiguous or structurally empty.
|
|
14
|
+
*
|
|
15
|
+
* What this module deliberately does **not** do is resolve the selector.
|
|
16
|
+
* Deciding whether `provider/model:level` names a live model, whether the
|
|
17
|
+
* suffix is a valid thinking level, or whether it has working credentials all
|
|
18
|
+
* require OMP's model catalog and credential store. Re-deciding any of that
|
|
19
|
+
* here would create the second model resolver this package must not own; those
|
|
20
|
+
* cases fail natively at OMP preflight and Bizar reports the refusal as a
|
|
21
|
+
* failed dispatch rather than a settled one.
|
|
22
|
+
*/
|
|
23
|
+
/** Selectors OMP documents as ambiguous and therefore refuses. */
|
|
24
|
+
const AMBIGUOUS_LITERALS = { default: true, inherit: true };
|
|
25
|
+
/**
|
|
26
|
+
* Whether one selector is the bare `default`/`inherit` literal OMP calls
|
|
27
|
+
* ambiguous, optionally carrying a thinking suffix.
|
|
28
|
+
*
|
|
29
|
+
* The suffix is stripped only to recognise that reserved word. A registered
|
|
30
|
+
* model id that legitimately ends in `:max` keeps its suffix and is left for
|
|
31
|
+
* OMP to resolve, because Bizar cannot tell an id from a selector without the
|
|
32
|
+
* catalog. `@default` is the documented way to inherit the parent session's
|
|
33
|
+
* model, so it is deliberately not ambiguous.
|
|
34
|
+
*/
|
|
35
|
+
function isAmbiguousLiteral(selector) {
|
|
36
|
+
const trimmed = selector.trim();
|
|
37
|
+
const withoutSuffix = trimmed.includes(":") ? trimmed.slice(0, trimmed.lastIndexOf(":")) : trimmed;
|
|
38
|
+
return AMBIGUOUS_LITERALS[withoutSuffix] === true;
|
|
39
|
+
}
|
|
40
|
+
function normalizeSelector(entry, field) {
|
|
41
|
+
if (typeof entry !== "string")
|
|
42
|
+
throw new ContractError(`${field} must be a selector string, received ${entry === null ? "null" : typeof entry}`);
|
|
43
|
+
const trimmed = entry.trim();
|
|
44
|
+
// OMP rejects blank and separator-only selectors; mirroring that here keeps
|
|
45
|
+
// the refusal at admission instead of leaving a dispatch nothing can settle.
|
|
46
|
+
if (trimmed.replace(/[\s,]/g, "").length === 0)
|
|
47
|
+
throw new ContractError(`${field} was blank; use a concrete provider/model selector or a role alias such as @bizar_build`);
|
|
48
|
+
if (isAmbiguousLiteral(trimmed))
|
|
49
|
+
throw new ContractError(`${field} used the ambiguous literal "${trimmed}"; OMP refuses it at preflight. Use @default to inherit the parent session's model.`);
|
|
50
|
+
return trimmed;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Normalize a requested per-call `model` into the ordered selector list Bizar
|
|
54
|
+
* journals, or refuse a selector OMP documents as invalid.
|
|
55
|
+
*
|
|
56
|
+
* Returns an empty list when no selector was requested, which is the signal
|
|
57
|
+
* that the specialist's own frontmatter and exact-agent override remain
|
|
58
|
+
* authoritative.
|
|
59
|
+
*/
|
|
60
|
+
export function normalizeRequestedModelSelectors(value) {
|
|
61
|
+
if (value === undefined || value === null)
|
|
62
|
+
return [];
|
|
63
|
+
if (Array.isArray(value)) {
|
|
64
|
+
if (value.length === 0)
|
|
65
|
+
throw new ContractError("model was given as an empty array; supply an ordered, non-empty selector list or omit the field");
|
|
66
|
+
return value.map((entry, index) => normalizeSelector(entry, `model[${index}]`));
|
|
67
|
+
}
|
|
68
|
+
if (typeof value === "string")
|
|
69
|
+
return [normalizeSelector(value, "model")];
|
|
70
|
+
throw new ContractError(`model must be a selector string or an ordered array of selectors, received ${typeof value}`);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build the routing record for one dispatch.
|
|
74
|
+
*
|
|
75
|
+
* Specialist identity and model routing stay separate fields: a
|
|
76
|
+
* `bizar-implementer` remains the implementer whichever selector it runs on.
|
|
77
|
+
* With no requested selector the source stays `specialist-default`, so the
|
|
78
|
+
* specialist's own model role keeps working exactly as before.
|
|
79
|
+
*/
|
|
80
|
+
export function requestedRouting(input) {
|
|
81
|
+
const selectors = normalizeRequestedModelSelectors(input.model);
|
|
82
|
+
const routing = { selectors, source: selectors.length > 0 ? "explicit-per-call" : "specialist-default" };
|
|
83
|
+
if (typeof input.effort === "string" && input.effort.trim())
|
|
84
|
+
routing.effort = input.effort.trim();
|
|
85
|
+
return routing;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Select the settled result belonging to one dispatch.
|
|
89
|
+
*
|
|
90
|
+
* A call settles into `details.results`, one entry per spawn, and each entry
|
|
91
|
+
* carries the wire `name` it was spawned under. Matching is by that identity,
|
|
92
|
+
* never by position: `admitNativeTasks` skips tasks that name no work item, so
|
|
93
|
+
* the admitted dispatches are fewer than the spawns and indexing by admission
|
|
94
|
+
* order would hand a dispatch whichever spawn happened to come first.
|
|
95
|
+
*
|
|
96
|
+
* A single-entry batch is used directly, because there is only one candidate
|
|
97
|
+
* and the host may omit `name`. A purely background call returns `results: []`
|
|
98
|
+
* and leaves its routing on the progress snapshot, so an absent match stays
|
|
99
|
+
* unobserved: recording another spawn's routing would be a false provenance
|
|
100
|
+
* claim, which is the exact failure this contract exists to prevent.
|
|
101
|
+
*/
|
|
102
|
+
export function settledResultFor(details, workItemId) {
|
|
103
|
+
if (details === null || typeof details !== "object")
|
|
104
|
+
return undefined;
|
|
105
|
+
const results = details.results;
|
|
106
|
+
if (!Array.isArray(results))
|
|
107
|
+
return undefined;
|
|
108
|
+
if (results.length === 1)
|
|
109
|
+
return results[0];
|
|
110
|
+
const named = results.find(result => result !== null && typeof result === "object" && result.name === workItemId);
|
|
111
|
+
return named;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Read the native routing OMP actually used for one settled spawn.
|
|
115
|
+
*
|
|
116
|
+
* These are the host's own flat fields on the settled result, siblings of
|
|
117
|
+
* `structuredOutput`, so the journal can distinguish the selector Bizar
|
|
118
|
+
* admitted from the model, identity, effort and fallback state OMP resolved.
|
|
119
|
+
* Every field is optional: the host omits routing it did not resolve, and an
|
|
120
|
+
* absent field must leave the dispatch on what was requested rather than
|
|
121
|
+
* inventing an observation.
|
|
122
|
+
*/
|
|
123
|
+
export function readObservedRouting(result) {
|
|
124
|
+
if (result === null || typeof result !== "object")
|
|
125
|
+
return undefined;
|
|
126
|
+
const record = result;
|
|
127
|
+
const observed = {};
|
|
128
|
+
for (const key of ["modelRole", "resolvedModel", "resolvedModelIdentity", "resolvedThinkingLevel", "resolvedModelRoute"]) {
|
|
129
|
+
const value = record[key];
|
|
130
|
+
if (typeof value === "string" && value.trim())
|
|
131
|
+
observed[key] = value.trim();
|
|
132
|
+
}
|
|
133
|
+
// A per-spawn override may be a single selector or the ordered list the
|
|
134
|
+
// caller supplied, so it is recorded as sent rather than collapsed.
|
|
135
|
+
const override = record.modelOverride;
|
|
136
|
+
if (typeof override === "string" && override.trim())
|
|
137
|
+
observed.modelOverride = override.trim();
|
|
138
|
+
else if (Array.isArray(override))
|
|
139
|
+
observed.modelOverride = override.map(selector => String(selector));
|
|
140
|
+
if (typeof record.resolvedModelIsFallback === "boolean")
|
|
141
|
+
observed.resolvedModelIsFallback = record.resolvedModelIsFallback;
|
|
142
|
+
return Object.keys(observed).length > 0 ? observed : undefined;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=task-model-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-model-selector.js","sourceRoot":"","sources":["../../src/omp/task-model-selector.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,10 +16,21 @@ const root = resolve(here, "..", "..");
|
|
|
16
16
|
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
17
17
|
if (typeof pkg.version !== "string")
|
|
18
18
|
throw new Error("package.json has no version");
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Null by default, and the release path passes --no-commit for the same reason.
|
|
21
|
+
*
|
|
22
|
+
* A receipt that is committed into the repository cannot name the commit that
|
|
23
|
+
* contains it, so any value here refers to a *parent* -- a tree that does not
|
|
24
|
+
* contain the OMP baseline this receipt asserts. A reader who follows that
|
|
25
|
+
* commit lands on a tree contradicting the receipt. Provenance is therefore
|
|
26
|
+
* opt-in via --commit, for callers writing a throwaway file outside the repo.
|
|
27
|
+
*/
|
|
28
|
+
const flags = new Set(["--no-commit", "--commit"]);
|
|
29
|
+
const target = process.argv.slice(2).find(arg => !flags.has(arg)) ?? join(root, "compatibility-receipt.json");
|
|
30
|
+
const wantsCommit = process.argv.includes("--commit") && !process.argv.includes("--no-commit");
|
|
20
31
|
let commit = null;
|
|
21
32
|
try {
|
|
22
|
-
if (
|
|
33
|
+
if (wantsCommit) {
|
|
23
34
|
commit = execFileSync("git", ["rev-parse", "HEAD"], { cwd: root, encoding: "utf8", timeout: 10_000 }).trim();
|
|
24
35
|
}
|
|
25
36
|
}
|
|
@@ -27,7 +38,6 @@ catch {
|
|
|
27
38
|
commit = null;
|
|
28
39
|
}
|
|
29
40
|
const receipt = buildCompatibilityReceipt({ packageVersion: pkg.version, commit });
|
|
30
|
-
const target = process.argv.slice(2).find(arg => arg !== "--no-commit") ?? join(root, "compatibility-receipt.json");
|
|
31
41
|
writeFileSync(target, renderCompatibilityReceipt(receipt));
|
|
32
42
|
process.stdout.write(`wrote ${target}\n`);
|
|
33
43
|
//# sourceMappingURL=emit-compatibility-receipt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit-compatibility-receipt.js","sourceRoot":"","sources":["../../src/scripts/emit-compatibility-receipt.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAExG,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,iCAAiC;AACjC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAEvC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAyB,CAAC;AACjG,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;IAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;AAEpF
|
|
1
|
+
{"version":3,"file":"emit-compatibility-receipt.js","sourceRoot":"","sources":["../../src/scripts/emit-compatibility-receipt.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAExG,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,iCAAiC;AACjC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAEvC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAyB,CAAC;AACjG,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;IAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;AAEpF;;;;;;;;GAQG;AACH,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC;AACnD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAC;AAC9G,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AAC/F,IAAI,MAAM,GAAkB,IAAI,CAAC;AACjC,IAAI,CAAC;IACH,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/G,CAAC;AACH,CAAC;AAAC,MAAM,CAAC;IACP,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC;AAED,MAAM,OAAO,GAAG,yBAAyB,CAAC,EAAE,cAAc,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AACnF,aAAa,CAAC,MAAM,EAAE,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,MAAM,IAAI,CAAC,CAAC"}
|
|
@@ -1,20 +1,53 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0
|
|
2
|
-
<title id="title">
|
|
3
|
-
<desc id="desc">
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<rect
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 360" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">BizarOMP</title>
|
|
3
|
+
<desc id="desc">Native workflow, evidence, and session control for oh-my-pi.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<pattern id="grid" width="32" height="32" patternUnits="userSpaceOnUse">
|
|
6
|
+
<path d="M32 0H0V32" fill="none" stroke="#171a21" stroke-width="1"/>
|
|
7
|
+
</pattern>
|
|
8
|
+
<clipPath id="frame"><rect x="1" y="1" width="1398" height="358" rx="18"/></clipPath>
|
|
9
|
+
</defs>
|
|
10
|
+
<rect width="1400" height="360" rx="18" fill="#07080a"/>
|
|
11
|
+
<g clip-path="url(#frame)">
|
|
12
|
+
<rect width="1400" height="360" fill="url(#grid)" opacity=".55"/>
|
|
13
|
+
<circle cx="232" cy="-34" r="248" fill="#ff2ea6" opacity=".055"/>
|
|
14
|
+
<circle cx="1268" cy="392" r="290" fill="#00b4ff" opacity=".05"/>
|
|
12
15
|
</g>
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
<rect x="1" y="1" width="1398" height="358" rx="18" fill="none" stroke="#232833" stroke-width="2"/>
|
|
17
|
+
<g font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace">
|
|
18
|
+
<g transform="translate(72 58)">
|
|
19
|
+
<rect width="48" height="48" rx="11" fill="#111319" stroke="#343946"/>
|
|
20
|
+
<path d="M14 16l9 8-9 8" fill="none" stroke="#ff2ea6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
|
21
|
+
<path d="M28 32h8" stroke="#00b4ff" stroke-width="3" stroke-linecap="round"/>
|
|
22
|
+
<text x="68" y="19" fill="#8b93a7" font-size="13" font-weight="700" letter-spacing="2.2">POLDERLABS / OMP NATIVE</text>
|
|
23
|
+
<text x="68" y="42" fill="#5f6678" font-size="12" letter-spacing="1.4">OPERATOR WORKFLOW SYSTEM</text>
|
|
24
|
+
</g>
|
|
25
|
+
<text x="72" y="182" fill="#f3f4f7" font-size="62" font-weight="760" letter-spacing="-2.6">BIZAR</text>
|
|
26
|
+
<text x="282" y="182" fill="#ff2ea6" font-size="62" font-weight="760" letter-spacing="-2.6">OMP</text>
|
|
27
|
+
<text x="74" y="221" fill="#a9afbd" font-size="18" letter-spacing=".25">Native workflow, evidence, and session control for oh-my-pi.</text>
|
|
28
|
+
<g transform="translate(72 265)" font-size="12" font-weight="700" letter-spacing="1.1">
|
|
29
|
+
<rect width="112" height="31" rx="7" fill="#0f1116" stroke="#2c303b"/><text x="18" y="20" fill="#e7e9ee">SESSIONS</text>
|
|
30
|
+
<rect x="124" width="122" height="31" rx="7" fill="#0f1116" stroke="#2c303b"/><text x="142" y="20" fill="#e7e9ee">WORKFLOWS</text>
|
|
31
|
+
<rect x="258" width="118" height="31" rx="7" fill="#0f1116" stroke="#2c303b"/><text x="276" y="20" fill="#e7e9ee">EVIDENCE</text>
|
|
32
|
+
<rect x="388" width="98" height="31" rx="7" fill="#0f1116" stroke="#2c303b"/><text x="406" y="20" fill="#e7e9ee">MOBILE</text>
|
|
33
|
+
</g>
|
|
34
|
+
<g transform="translate(900 48)">
|
|
35
|
+
<rect width="424" height="264" rx="14" fill="#0d0f13" stroke="#2a2e38"/>
|
|
36
|
+
<path d="M0 44h424" stroke="#232833"/>
|
|
37
|
+
<circle cx="22" cy="22" r="4" fill="#ff2ea6"/><circle cx="38" cy="22" r="4" fill="#4b5262"/><circle cx="54" cy="22" r="4" fill="#4b5262"/>
|
|
38
|
+
<text x="80" y="27" fill="#7f8798" font-size="11" letter-spacing="1.5">OMB / SESSION CONTROL</text>
|
|
39
|
+
<text x="24" y="79" fill="#00b4ff" font-size="14">$</text><text x="43" y="79" fill="#f0f1f4" font-size="14">omb</text>
|
|
40
|
+
<text x="24" y="111" fill="#626a7c" font-size="11">HOST</text><text x="104" y="111" fill="#d8dbe2" font-size="12">local / project</text>
|
|
41
|
+
<text x="24" y="138" fill="#626a7c" font-size="11">SESSION</text><text x="104" y="138" fill="#d8dbe2" font-size="12">working</text><circle cx="184" cy="134" r="4" fill="#34d399"/>
|
|
42
|
+
<text x="24" y="165" fill="#626a7c" font-size="11">RUNTIME</text><text x="104" y="165" fill="#d8dbe2" font-size="12">OMP native</text>
|
|
43
|
+
<path d="M24 194h376" stroke="#232833"/>
|
|
44
|
+
<g transform="translate(24 214)">
|
|
45
|
+
<text x="0" y="0" fill="#9198a8" font-size="11">PLAN</text><path d="M42 -4h38" stroke="#343946"/><circle cx="88" cy="-4" r="3" fill="#ff2ea6"/>
|
|
46
|
+
<text x="104" y="0" fill="#9198a8" font-size="11">RUN</text><path d="M136 -4h38" stroke="#343946"/><circle cx="182" cy="-4" r="3" fill="#ff2ea6"/>
|
|
47
|
+
<text x="198" y="0" fill="#9198a8" font-size="11">VERIFY</text><path d="M250 -4h38" stroke="#343946"/><circle cx="296" cy="-4" r="3" fill="#00b4ff"/>
|
|
48
|
+
<text x="312" y="0" fill="#cdd1da" font-size="11">INTEGRATE</text>
|
|
49
|
+
</g>
|
|
50
|
+
<text x="24" y="247" fill="#5d6576" font-size="10" letter-spacing="1.2">OMP OWNS THE RUNTIME · BIZAR OWNS THE PROOF</text>
|
|
51
|
+
</g>
|
|
17
52
|
</g>
|
|
18
|
-
|
|
19
|
-
<text x="1080" y="244" text-anchor="end" fill="#64748b" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="14">POLDERLABS</text>
|
|
20
|
-
</svg>
|
|
53
|
+
</svg>
|