@chibitek/chibi 0.1.155 → 0.1.158
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/dist/assets/{abnfDiagram-O67JEVCF-B8LdsCr1.js → abnfDiagram-O67JEVCF-B8-8zzMS.js} +1 -1
- package/dist/assets/{arc-DU5fSmKU.js → arc-CSHQ9Dx3.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-DdQSIFKv.js → architectureDiagram-NJMV4G6O-BCHM9rXW.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-CaPcGYSS.js → blockDiagram-BEXU5L5S-B-5uxPFN.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-unt0ePgO.js → c4Diagram-YGBWAQC7-CuKNM_MR.js} +1 -1
- package/dist/assets/channel-bPN03jIt.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-Babg5Fzu.js → chunk-2Q5K7J3B-BNF02GM4.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-D1-dWVHo.js → chunk-3FUC2YCW-uEWgBd4M.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-DU7nSMbT.js → chunk-5VM5RSS4-eSZuXctY.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-QIjCJIhV.js → chunk-GTNCS2PH-CslS8nRS.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-pSByUE5R.js → chunk-GWA4HPMP-w71-MeKj.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-Dj2AaR1b.js → chunk-JWPE2WC7-Bjju7WGh.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-pZbN0-FP.js → chunk-NETBCI7D-HxrroD4M.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-Bqarwe4D.js → chunk-WEXAMYUT-D7Rz470x.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-WV8lm3aa.js → chunk-XXDRQBXY-BWKnAeyM.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-BANBtky1.js → classDiagram-v2-NBCMYWYE-CeBDRHmP.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-CtrktgBC.js → cose-bilkent-JH36ORCC-BBbRKlvr.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-DnhVVfba.js → cynefin-OW5HDTMX-W02cnJ0B.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-B42SRR6x.js → cynefinDiagram-VND7K2PF-Cs47eaxd.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-DM--vFMK.js → dagre-6A5THRUB-8mG18hzT.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-ZBupBrPU.js → diagram-22UHCM2B-DF4Qrw67.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-BPQzNIOd.js → diagram-3UASUU5V-3BAVoed1.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-5kO8vf8Z.js → diagram-ATOU4E4O-CKO3pECE.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-DtxogB86.js → diagram-CDSNMT55-CZhrGvur.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-Co9-nYw_.js → diagram-MLGK6HIB-C07l9pdQ.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-DWRuMh5y.js → diagram-MPIPVDR6-D3or4lkZ.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-DU_nmoG9.js → ebnfDiagram-ZINNZB2B-DV2epXp_.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-Bcje7S94.js → elk-276RUBZZ-DlvEn4-1.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-9aCo_2CI.js → erDiagram-OPXOYQCR-CB6X7Wt5.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-D4FYFyc5.js → flowDiagram-KWPJA3E3-C3bqz4lC.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-WQHX5rbx.js → ganttDiagram-FUAMR5RP-yo_Evhab.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-DRyzBdiV.js → gitGraphDiagram-X574FWY7-Cq2oUlap.js} +1 -1
- package/dist/assets/{index-CG1OvRgO.js → index-CG4AFPb4.js} +1 -1
- package/dist/assets/{index-D_8SD_0K.js → index-CMcr5k3Z.js} +205 -200
- package/dist/assets/index-CZjRcUdn.css +1 -0
- package/dist/assets/{infoDiagram-VRGFBTTK-D7SOmp4n.js → infoDiagram-VRGFBTTK-Y3ZrY7qL.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-CdxOnDVX.js → ishikawaDiagram-OU5B5YK6-BpOtSfyi.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-CH7477Oa.js → journeyDiagram-ZHPQQLJL-UQM727le.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-BdpVvkHd.js → kanban-definition-PNTS6WVX-C3s5oHpY.js} +1 -1
- package/dist/assets/{linear-DTGq6qn5.js → linear-hX6nFOQr.js} +1 -1
- package/dist/assets/{mermaid.core-Sn2sv0Ti.js → mermaid.core-DZObGLN7.js} +5 -5
- package/dist/assets/{mindmap-definition-NLK3R4M7-koCmkYuq.js → mindmap-definition-NLK3R4M7-Br-i2E3P.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-C3sqhm8e.js → pegDiagram-GJSIUBJH-D5SERB-N.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-BELBK122.js → pieDiagram-5QR66LMP-BPNf4J3D.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-Cksi5LSm.js → quadrantDiagram-O4NWA36T-Bm_Wh7Jr.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-f1av_EZW.js → railroadDiagram-XR7U4H2S-D6bo0abD.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-CW4O5nER.js → requirementDiagram-PLB6GJNP--1n5rkV7.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-Dz8ADHNY.js → sankeyDiagram-IPEJSGJF-Ct4tP2kK.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-Cc3HE0iZ.js → sequenceDiagram-PO4LG4MO-CCG7O5fR.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-gdaZNHnK.js → sizeCapture-INFHLROL-CJJJra9c.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK--u8LCnab.js → stateDiagram-v2-GCMORJYK-BMdRvVEX.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-4MAw4kdO.js → swimlanes-2SLR337P-B1wnogip.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-DWyjdGGR.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-CL89YkCT.js → timeline-definition-EJHVYXUP-l-3yhXUP.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-C92l7YQe.js → usecaseDiagram-POWQR4AR-DtwtCOoJ.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-17siYhSj.js → vennDiagram-UO4OBE2U-BZAEce1B.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-CNwa9VmN.js → wardleyDiagram-VNRHLVJA-Na_BCMMO.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-Dnu6Xzih.js → xychartDiagram-PMCCYNJV-BW9dlUfE.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/container-mcp.js +68 -14
- package/dist-server/index.js +5633 -4562
- package/dist-server/openmausbot.js +140 -81
- package/dist-server/pair-cli.js +140 -81
- package/dist-server/server/app-installers.js +107 -7
- package/dist-server/server/avatar-subscription.js +51 -0
- package/dist-server/server/cli-help.js +74 -0
- package/dist-server/server/cli.js +37 -78
- package/dist-server/server/colima-docker.js +136 -0
- package/dist-server/server/container-computer.js +31 -63
- package/dist-server/server/container-mcp.js +5 -0
- package/dist-server/server/device-routing.js +60 -0
- package/dist-server/server/drivers/claude.js +13 -11
- package/dist-server/server/drivers/local-inject.js +3 -4
- package/dist-server/server/engine-failover.js +22 -12
- package/dist-server/server/engine-tiers.js +5 -14
- package/dist-server/server/index.js +124 -120
- package/dist-server/server/personal-goal-runtime.js +86 -0
- package/dist-server/server/personal-goal-turn.js +125 -0
- package/dist-server/server/personal-goals.js +195 -0
- package/dist-server/server/port-in-use.js +21 -0
- package/dist-server/server/routes/local-models.js +3 -2
- package/dist-server/server/session-fallback.js +76 -0
- package/dist-server/server/skill-fetch.js +14 -0
- package/dist-server/server/vault/routes.js +43 -0
- package/dist-server/server/vault/runtime.js +48 -0
- package/dist-server/server/vault/store.js +177 -0
- package/dist-server/shared/desktop-private-port.js +1 -0
- package/dist-server/shared/engine-choices.js +15 -0
- package/dist-server/shared/engine-tiers.js +74 -2
- package/dist-server/shared/local-models.js +1 -3
- package/dist-server/shared/personal-goal.js +43 -0
- package/dist-server/shared/subscription-bots.js +3 -0
- package/dist-server/shared/vault.js +59 -0
- package/dist-server/vps-container-mcp.js +4 -2
- package/package.json +1 -1
- package/dist/assets/channel-GBaPOaz-.js +0 -1
- package/dist/assets/index-C8YP7Zxj.css +0 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-CamSa0NE.js +0 -8
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// Native Vault persistence. No API/OAuth credentials are stored here.
|
|
2
|
+
// The caller supplies a key from the trusted runtime; this module never
|
|
3
|
+
// creates a plaintext key file or returns stored secrets to a model.
|
|
4
|
+
import { createCipheriv, createDecipheriv, randomBytes, randomUUID } from "node:crypto";
|
|
5
|
+
import { lstatSync, mkdirSync, readFileSync, rmdirSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { vaultInputSchema, vaultMetadata } from "../../shared/vault.js";
|
|
9
|
+
import { writeFileAtomic } from "../atomic.js";
|
|
10
|
+
const MAX_BYTES = 16 * 1024 * 1024;
|
|
11
|
+
const MAX_ITEMS = 1000;
|
|
12
|
+
const AAD = Buffer.from("atomic-native-vault:v1");
|
|
13
|
+
const identity = z.string().uuid();
|
|
14
|
+
const metadataSchema = z.object({
|
|
15
|
+
id: identity, ownerId: identity, createdAt: z.number().int().nonnegative(), updatedAt: z.number().int().nonnegative(),
|
|
16
|
+
});
|
|
17
|
+
const envelopeSchema = z.object({
|
|
18
|
+
version: z.literal(1), iv: z.string().regex(/^[0-9a-f]{24}$/),
|
|
19
|
+
tag: z.string().regex(/^[0-9a-f]{32}$/), data: z.string().regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/),
|
|
20
|
+
}).strict();
|
|
21
|
+
export class VaultError extends Error {
|
|
22
|
+
}
|
|
23
|
+
function owner(value) {
|
|
24
|
+
if (!identity.safeParse(value).success)
|
|
25
|
+
throw new VaultError("Invalid Vault owner.");
|
|
26
|
+
}
|
|
27
|
+
export class VaultStore {
|
|
28
|
+
#directory;
|
|
29
|
+
#file;
|
|
30
|
+
#key;
|
|
31
|
+
constructor(directory, key) {
|
|
32
|
+
if (key.length !== 32)
|
|
33
|
+
throw new VaultError("Vault encryption is unavailable.");
|
|
34
|
+
this.#directory = directory;
|
|
35
|
+
this.#file = join(directory, "vault.enc");
|
|
36
|
+
this.#key = Buffer.from(key);
|
|
37
|
+
}
|
|
38
|
+
read() {
|
|
39
|
+
try {
|
|
40
|
+
let stat;
|
|
41
|
+
try {
|
|
42
|
+
stat = lstatSync(this.#file);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error.code === "ENOENT")
|
|
46
|
+
return [];
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_BYTES)
|
|
50
|
+
throw new Error();
|
|
51
|
+
const envelope = envelopeSchema.parse(JSON.parse(readFileSync(this.#file, "utf8")));
|
|
52
|
+
const decipher = createDecipheriv("aes-256-gcm", this.#key, Buffer.from(envelope.iv, "hex"));
|
|
53
|
+
decipher.setAAD(AAD);
|
|
54
|
+
decipher.setAuthTag(Buffer.from(envelope.tag, "hex"));
|
|
55
|
+
const plain = Buffer.concat([decipher.update(Buffer.from(envelope.data, "base64")), decipher.final()]);
|
|
56
|
+
try {
|
|
57
|
+
// Separate metadata before the strict input schema validates each item.
|
|
58
|
+
const raw = JSON.parse(plain.toString("utf8"));
|
|
59
|
+
if (!Array.isArray(raw) || raw.length > MAX_ITEMS)
|
|
60
|
+
throw new Error();
|
|
61
|
+
const items = raw.map((value) => {
|
|
62
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
63
|
+
throw new Error();
|
|
64
|
+
const { id, ownerId, createdAt, updatedAt, ...input } = value;
|
|
65
|
+
const metadata = metadataSchema.parse({ id, ownerId, createdAt, updatedAt });
|
|
66
|
+
return { ...vaultInputSchema.parse(input), ...metadata };
|
|
67
|
+
});
|
|
68
|
+
if (new Set(items.map((item) => item.id)).size !== items.length)
|
|
69
|
+
throw new Error();
|
|
70
|
+
return items;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
plain.fill(0);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new VaultError("Vault is locked or unreadable.");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
write(items) {
|
|
81
|
+
const iv = randomBytes(12);
|
|
82
|
+
const cipher = createCipheriv("aes-256-gcm", this.#key, iv);
|
|
83
|
+
cipher.setAAD(AAD);
|
|
84
|
+
const plain = Buffer.from(JSON.stringify(items));
|
|
85
|
+
try {
|
|
86
|
+
const encrypted = Buffer.concat([cipher.update(plain), cipher.final()]);
|
|
87
|
+
const envelope = JSON.stringify({ version: 1, iv: iv.toString("hex"), tag: cipher.getAuthTag().toString("hex"), data: encrypted.toString("base64") });
|
|
88
|
+
if (Buffer.byteLength(envelope) > MAX_BYTES)
|
|
89
|
+
throw new VaultError("Vault has reached its size limit.");
|
|
90
|
+
writeFileAtomic(this.#file, envelope, { mode: 0o600 });
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
plain.fill(0);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Cross-process writes refuse contention instead of losing an update.
|
|
97
|
+
* A crash leaves the lock in place for explicit recovery, never guessing
|
|
98
|
+
* that an older process has stopped writing. */
|
|
99
|
+
mutate(fn) {
|
|
100
|
+
const lock = join(this.#directory, "write.lock");
|
|
101
|
+
try {
|
|
102
|
+
mkdirSync(this.#directory, { recursive: true, mode: 0o700 });
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
throw new VaultError("Vault could not be saved.");
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
mkdirSync(lock, { mode: 0o700 });
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
throw new VaultError("Vault is busy or needs recovery.");
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const items = this.read();
|
|
115
|
+
const result = fn(items);
|
|
116
|
+
this.write(items);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (error instanceof VaultError)
|
|
121
|
+
throw error;
|
|
122
|
+
throw new VaultError("Vault could not be saved.");
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
rmdirSync(lock);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
list(ownerId) {
|
|
129
|
+
owner(ownerId);
|
|
130
|
+
return this.read().filter((item) => item.ownerId === ownerId).map(vaultMetadata);
|
|
131
|
+
}
|
|
132
|
+
create(ownerId, input) {
|
|
133
|
+
owner(ownerId);
|
|
134
|
+
const parsed = vaultInputSchema.safeParse(input);
|
|
135
|
+
if (!parsed.success)
|
|
136
|
+
throw new VaultError("Invalid Vault item.");
|
|
137
|
+
return this.mutate((items) => {
|
|
138
|
+
if (items.length >= MAX_ITEMS)
|
|
139
|
+
throw new VaultError("Vault has reached its item limit.");
|
|
140
|
+
const now = Date.now();
|
|
141
|
+
const item = { ...parsed.data, id: randomUUID(), ownerId, createdAt: now, updatedAt: now };
|
|
142
|
+
items.push(item);
|
|
143
|
+
return vaultMetadata(item);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
update(ownerId, id, input) {
|
|
147
|
+
owner(ownerId);
|
|
148
|
+
if (!input || typeof input !== "object" || Array.isArray(input))
|
|
149
|
+
throw new VaultError("Invalid Vault item.");
|
|
150
|
+
return this.mutate((items) => {
|
|
151
|
+
const index = items.findIndex((item) => item.id === id && item.ownerId === ownerId);
|
|
152
|
+
const current = items[index];
|
|
153
|
+
if (!current)
|
|
154
|
+
throw new VaultError("Vault item is unavailable.");
|
|
155
|
+
const { id: _id, ownerId: _owner, createdAt: _created, updatedAt: _updated, ...previous } = current;
|
|
156
|
+
// A blank password is invalid; omission preserves it, so metadata can
|
|
157
|
+
// be edited without ever reading the saved secret back to the UI.
|
|
158
|
+
const parsed = vaultInputSchema.safeParse({ ...previous, ...input });
|
|
159
|
+
if (!parsed.success)
|
|
160
|
+
throw new VaultError("Invalid Vault item.");
|
|
161
|
+
if (current.kind !== parsed.data.kind)
|
|
162
|
+
throw new VaultError("A Vault item's category cannot change.");
|
|
163
|
+
const item = { ...parsed.data, id, ownerId, createdAt: current.createdAt, updatedAt: Date.now() };
|
|
164
|
+
items[index] = item;
|
|
165
|
+
return vaultMetadata(item);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
remove(ownerId, id) {
|
|
169
|
+
owner(ownerId);
|
|
170
|
+
this.mutate((items) => {
|
|
171
|
+
const index = items.findIndex((item) => item.id === id && item.ownerId === ownerId);
|
|
172
|
+
if (index < 0)
|
|
173
|
+
throw new VaultError("Vault item is unavailable.");
|
|
174
|
+
items.splice(index, 1);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -295,6 +295,21 @@ export function choiceFor(choices, engine, instanceId, model) {
|
|
|
295
295
|
}
|
|
296
296
|
return mine.find((choice) => !choice.host) ?? mine[0];
|
|
297
297
|
}
|
|
298
|
+
/** Back to "any account of this provider": the rung names the driver again
|
|
299
|
+
* (a ladder rung may name a driver kind), keeping the rung's model when the
|
|
300
|
+
* driver still offers it. When that exact route is already on the ladder,
|
|
301
|
+
* the driver's first model no rung uses takes its place; undefined when no
|
|
302
|
+
* free route is left, which leaves the rung unchanged. */
|
|
303
|
+
export function anyAccountEntry(entry, engine, others) {
|
|
304
|
+
if (!engine)
|
|
305
|
+
return undefined;
|
|
306
|
+
const used = (model) => others.some((other) => other.engine === engine.driverKind && other.model === model);
|
|
307
|
+
const keep = entry.model && engine.models.some((model) => model.id === entry.model) ? entry.model : undefined;
|
|
308
|
+
if (!used(keep))
|
|
309
|
+
return keep ? { engine: engine.driverKind, model: keep } : { engine: engine.driverKind };
|
|
310
|
+
const alternate = engine.models.map((model) => model.id).find((id) => !used(id));
|
|
311
|
+
return alternate ? { engine: engine.driverKind, model: alternate } : undefined;
|
|
312
|
+
}
|
|
298
313
|
/** Providers with accounts the person should name: brand and how many accounts it has. */
|
|
299
314
|
export function accountsToName(choices) {
|
|
300
315
|
const out = new Map();
|
|
@@ -29,6 +29,77 @@ export function toModelClass(value) {
|
|
|
29
29
|
/** The class one below, or undefined for Añejo. */
|
|
30
30
|
export const classBelow = (modelClass) => MODEL_CLASSES[MODEL_CLASSES.indexOf(modelClass) + 1];
|
|
31
31
|
export const DEFAULT_CLASS_BANDS = { Mezcal: 50, Plata: 44, Reposado: 38 };
|
|
32
|
+
/** Hand-written ladders, used only when no model has a class yet (the
|
|
33
|
+
* server always has the bundled baseline, so in practice the generated
|
|
34
|
+
* ladders below apply). Pay-per-token engines need no rung: they form the
|
|
35
|
+
* automatic last band of every ladder (resolveLadder).
|
|
36
|
+
*
|
|
37
|
+
* Erick's own ladders (2026-10-25), each per-install instance id
|
|
38
|
+
* ("claude-<uuid>") reduced to its driver kind so a fresh install matches
|
|
39
|
+
* whatever account it has (matchesEngine); the exact engine+model
|
|
40
|
+
* duplicates that collapse created are dropped. */
|
|
41
|
+
export const DEFAULT_LADDERS = {
|
|
42
|
+
orchestrator: [
|
|
43
|
+
{ engine: "claudeAgent", model: "claude-opus-5-5", modelClass: "Plata" },
|
|
44
|
+
{ engine: "codex", model: "gpt-6-sol" },
|
|
45
|
+
{ engine: "opencodeGo", model: "opencode-go/gemini-4-argon" },
|
|
46
|
+
{ engine: "hermes", model: "nous:x-ai/grok-4.6" },
|
|
47
|
+
{ engine: "ollamaCloud", model: "glm-5.3" },
|
|
48
|
+
{ engine: "museCode", model: "muse-spark-1.2" },
|
|
49
|
+
{ engine: "hermesAgent", model: "openai-codex:gpt-6-sol", modelClass: "Plata" },
|
|
50
|
+
{ engine: "antigravity", model: "gemini-3.8-flash-medium" },
|
|
51
|
+
{ engine: "cursorAgent", model: "auto" },
|
|
52
|
+
{ engine: "hermesAgent", model: "huggingface:deepseek-ai/DeepSeek-R1-0528", modelClass: "Plata" },
|
|
53
|
+
{ engine: "hermesAgent", model: "opencode-go:deepseek-v4-flash", modelClass: "Plata" },
|
|
54
|
+
{ engine: "hermesAgent", model: "deepinfra:anthropic/claude-opus-5", modelClass: "Plata" },
|
|
55
|
+
{ engine: "hermesAgent", model: "nous:meta/muse-spark-1.3", modelClass: "Plata" },
|
|
56
|
+
{ engine: "hermesAgent", model: "openrouter:openai/gpt-6-sol", modelClass: "Plata" },
|
|
57
|
+
{ engine: "hermesAgent", model: "openai-codex:gpt-6.1-sol", modelClass: "Plata" },
|
|
58
|
+
],
|
|
59
|
+
engineering: [
|
|
60
|
+
{ engine: "codex", model: "gpt-6-astra", modelClass: "Mezcal" },
|
|
61
|
+
{ engine: "claude", model: "claude-opus-5-5" },
|
|
62
|
+
{ engine: "claudeAgent", model: "claude-opus-5-5" },
|
|
63
|
+
{ engine: "opencodeGo", model: "opencode-go/gemini-4-argon" },
|
|
64
|
+
{ engine: "ollamaCloud", model: "kimi-k3" },
|
|
65
|
+
{ engine: "hermesAgent", model: "openai-codex:gpt-6-astra", modelClass: "Mezcal" },
|
|
66
|
+
{ engine: "grok", model: "grok-4.7" },
|
|
67
|
+
{ engine: "grokAgent", model: "grok-4.7" },
|
|
68
|
+
{ engine: "kimi", model: "kimi-code/k3" },
|
|
69
|
+
{ engine: "openai-compat", model: "qwen3.7-plus" },
|
|
70
|
+
{ engine: "hermesAgent", model: "nous:anthropic/claude-opus-5.5" },
|
|
71
|
+
{ engine: "hermesAgent", model: "opencode-zen:claude-fable-5-1", modelClass: "Mezcal" },
|
|
72
|
+
{ engine: "cursorAgent", model: "auto" },
|
|
73
|
+
],
|
|
74
|
+
research: [
|
|
75
|
+
{ engine: "openai-compat", model: "MiniMax-M2.5" },
|
|
76
|
+
{ engine: "vibe", model: "mistral-medium-3.5" },
|
|
77
|
+
{ engine: "antigravityAgent", model: "gemini-3.8-flash-low" },
|
|
78
|
+
{ engine: "cursorAgent", model: "auto" },
|
|
79
|
+
{ engine: "hermesAgent", model: "openrouter:x-ai/grok-4.7", modelClass: "Plata" },
|
|
80
|
+
{ engine: "hermesAgent", model: "custom:local-(localhost:11434):deepseek-v4-pro:cloud" },
|
|
81
|
+
{ engine: "hermesAgent", model: "openrouter:meta/muse-spark-1.3", modelClass: "Plata" },
|
|
82
|
+
{ engine: "hermesAgent", model: "opencode-zen:muse-spark-1.3", modelClass: "Plata" },
|
|
83
|
+
{ engine: "claudeAgent", model: "claude-opus-5", modelClass: "Plata" },
|
|
84
|
+
{ engine: "cursorAgent", model: "claude-opus-5-high", modelClass: "Plata" },
|
|
85
|
+
{ engine: "opencodeGo", model: "opencode/claude-opus-5", modelClass: "Plata" },
|
|
86
|
+
],
|
|
87
|
+
writing: [
|
|
88
|
+
{ engine: "claudeAgent", model: "claude-sonnet-5-5" },
|
|
89
|
+
{ engine: "claude", model: "claude-sonnet-5-5" },
|
|
90
|
+
{ engine: "codex", model: "gpt-5.6-luna" },
|
|
91
|
+
{ engine: "antigravity", model: "gemini-3.8-flash-high" },
|
|
92
|
+
{ engine: "antigravityAgent", model: "gemini-3.8-flash-high" },
|
|
93
|
+
{ engine: "hermes", model: "nous:moonshotai/kimi-k3" },
|
|
94
|
+
],
|
|
95
|
+
routine: [
|
|
96
|
+
{ engine: "antigravityAgent", model: "gemini-3.8-flash-low" },
|
|
97
|
+
{ engine: "antigravity", model: "gemini-3.8-flash-low" },
|
|
98
|
+
{ engine: "openai-compat", model: "MiniMax-M2.5" },
|
|
99
|
+
{ engine: "cursor", model: "auto" },
|
|
100
|
+
{ engine: "mistral", model: "mistral-medium", modelClass: "Añejo" },
|
|
101
|
+
],
|
|
102
|
+
};
|
|
32
103
|
export function classForScore(score, bands = DEFAULT_CLASS_BANDS) {
|
|
33
104
|
if (score >= bands.Mezcal)
|
|
34
105
|
return "Mezcal";
|
|
@@ -45,9 +116,10 @@ export const DEFAULT_TIER_CLASSES = {
|
|
|
45
116
|
// puts Claude's rungs first in its ladder.
|
|
46
117
|
orchestrator: "Plata",
|
|
47
118
|
engineering: "Mezcal",
|
|
48
|
-
|
|
119
|
+
// Research and Routine ask for the cheapest class (Erick, 2026-10-25).
|
|
120
|
+
research: "Añejo",
|
|
49
121
|
writing: "Plata",
|
|
50
|
-
routine: "
|
|
122
|
+
routine: "Añejo",
|
|
51
123
|
};
|
|
52
124
|
/** A person's class choice at an API boundary: a class, or null for
|
|
53
125
|
* "Automatic (by tier)"; undefined when the value is neither. */
|
|
@@ -53,9 +53,7 @@ export const LIGHT_LOCAL_MODEL = "gemma4:e2b-it-qat";
|
|
|
53
53
|
const SIXTEEN_GB = 15.5 * GB;
|
|
54
54
|
const EIGHT_GB = 7.5 * GB;
|
|
55
55
|
export function recommendLocalModel(machine) {
|
|
56
|
-
if (machine.platform
|
|
57
|
-
return { kind: "none", reason: "notMac" };
|
|
58
|
-
if (machine.arch !== "arm64")
|
|
56
|
+
if (machine.platform === "darwin" && machine.arch !== "arm64")
|
|
59
57
|
return { kind: "none", reason: "intel" };
|
|
60
58
|
const model = (tag) => SUGGESTED_LOCAL_MODELS.find((entry) => entry.tag === tag);
|
|
61
59
|
if (machine.memoryBytes >= SIXTEEN_GB)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export function parseGoalCommand(text) {
|
|
2
|
+
const match = /^\/goal(?:\s+([\s\S]*))?$/i.exec(text.trim());
|
|
3
|
+
if (!match)
|
|
4
|
+
return null;
|
|
5
|
+
let rest = (match[1] ?? "").trim();
|
|
6
|
+
const action = /^(status|pause|resume|stop|help)(?:\s|$)/i.exec(rest);
|
|
7
|
+
if (action)
|
|
8
|
+
rest = rest.slice(action[0].length).trim();
|
|
9
|
+
let maxTurns;
|
|
10
|
+
let tokenBudget;
|
|
11
|
+
const criteria = [];
|
|
12
|
+
while (rest.startsWith("--")) {
|
|
13
|
+
const flag = /^--(turns|tokens|done)\s+(?:"([^"\n]+)"|'([^'\n]+)'|(\S+))(?:\s|$)/.exec(rest);
|
|
14
|
+
if (!flag)
|
|
15
|
+
throw new Error('Use --turns N, --tokens N, or --done "completion criterion" before the objective.');
|
|
16
|
+
const value = flag[2] ?? flag[3] ?? flag[4];
|
|
17
|
+
if (flag[1] === "done")
|
|
18
|
+
criteria.push(value);
|
|
19
|
+
else {
|
|
20
|
+
const number = Number(value);
|
|
21
|
+
if (!/^\d+$/.test(value) || !Number.isSafeInteger(number) || number < 1 || (flag[1] === "turns" && number > 1000)) {
|
|
22
|
+
throw new Error("Budgets must be positive whole numbers; the turn limit cannot exceed 1000.");
|
|
23
|
+
}
|
|
24
|
+
if (flag[1] === "turns")
|
|
25
|
+
maxTurns = number;
|
|
26
|
+
else
|
|
27
|
+
tokenBudget = number;
|
|
28
|
+
}
|
|
29
|
+
rest = rest.slice(flag[0].length).trim();
|
|
30
|
+
}
|
|
31
|
+
if (action) {
|
|
32
|
+
if (rest || criteria.length || (action[1].toLowerCase() !== "resume" && (maxTurns || tokenBudget))) {
|
|
33
|
+
throw new Error("Only /goal resume accepts --turns and --tokens; other controls take no arguments.");
|
|
34
|
+
}
|
|
35
|
+
return { action: action[1].toLowerCase(), maxTurns, tokenBudget };
|
|
36
|
+
}
|
|
37
|
+
if (!rest)
|
|
38
|
+
return { action: "help" };
|
|
39
|
+
if (rest.length > 20_000 || criteria.length > 20 || criteria.some((item) => item.length > 2000))
|
|
40
|
+
throw new Error("Goal or completion criteria are too long.");
|
|
41
|
+
return { action: "start", objective: rest, maxTurns: maxTurns ?? 20, tokenBudget, criteria };
|
|
42
|
+
}
|
|
43
|
+
export const GOAL_HELP = 'Start: /goal [--turns 20] [--tokens N] [--done "criterion"] objective\nControls: /goal status, /goal pause, /goal resume [--turns N] [--tokens N], /goal stop. Resume budgets are total ceilings, not additional allowances. Token limits are checked between turns; a running turn can exceed the limit.';
|
|
@@ -88,6 +88,9 @@ export function subscriptionProviderForEngine(engine) {
|
|
|
88
88
|
export function isProviderModel(provider, model) {
|
|
89
89
|
return provider.ownModels ? provider.ownModels.test(model) : true;
|
|
90
90
|
}
|
|
91
|
+
/** Turns one conversation of a company subscription bot may run on another
|
|
92
|
+
* provider's subscription when its own has no account free (server/session-fallback.ts). */
|
|
93
|
+
export const SESSION_FALLBACK_TURNS = 50;
|
|
91
94
|
export function isSubscriptionBot(bot) {
|
|
92
95
|
const value = bot?.subscription;
|
|
93
96
|
return Boolean(value && typeof value.instanceId === "string" && subscriptionProvider(value.provider));
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Only absolute HTTPS origins can receive a saved item. Paths never broaden
|
|
3
|
+
* authority to sibling domains, frames, ports or subdomains. */
|
|
4
|
+
export function vaultOrigin(raw) {
|
|
5
|
+
if (raw.length > 2048 || [...raw].some((c) => c.charCodeAt(0) <= 32 || c.charCodeAt(0) === 127) || raw.includes("\\"))
|
|
6
|
+
return null;
|
|
7
|
+
try {
|
|
8
|
+
const url = new URL(raw);
|
|
9
|
+
if (url.protocol !== "https:" || !url.hostname || url.username || url.password || url.hostname.endsWith("."))
|
|
10
|
+
return null;
|
|
11
|
+
return url.origin;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const text = (max) => z.string().max(max);
|
|
18
|
+
const origin = z.string().refine((value) => vaultOrigin(value) !== null).transform((value) => vaultOrigin(value));
|
|
19
|
+
const address = z.object({
|
|
20
|
+
name: text(200), line1: text(300), line2: text(300), city: text(200),
|
|
21
|
+
region: text(200), postalCode: text(40), country: text(100),
|
|
22
|
+
}).strict();
|
|
23
|
+
const base = {
|
|
24
|
+
label: z.string().trim().min(1).max(200), hints: text(1000),
|
|
25
|
+
botIds: z.array(z.string().uuid()).max(100).refine((ids) => new Set(ids).size === ids.length),
|
|
26
|
+
expiresAt: z.number().int().positive().max(Number.MAX_SAFE_INTEGER).nullable(),
|
|
27
|
+
};
|
|
28
|
+
/** Reject unknown fields rather than accidentally persisting secrets in
|
|
29
|
+
* metadata. CVC is deliberately absent: it belongs to a single secure use. */
|
|
30
|
+
export const vaultInputSchema = z.discriminatedUnion("kind", [
|
|
31
|
+
z.object({ ...base, kind: z.literal("login"), website: origin,
|
|
32
|
+
username: z.string().min(1).max(320), password: z.string().min(1).max(4096),
|
|
33
|
+
}).strict(),
|
|
34
|
+
z.object({ ...base, kind: z.literal("card"), origins: z.array(origin).min(1).max(50),
|
|
35
|
+
number: z.string().regex(/^\d{12,19}$/), expiryMonth: z.number().int().min(1).max(12),
|
|
36
|
+
expiryYear: z.number().int().min(2000).max(9999), billing: address,
|
|
37
|
+
}).strict(),
|
|
38
|
+
z.object({ ...base, kind: z.literal("contact"), origins: z.array(origin).min(1).max(50),
|
|
39
|
+
address, email: z.union([z.literal(""), z.string().email().max(320)]), phone: text(80),
|
|
40
|
+
}).strict(),
|
|
41
|
+
]);
|
|
42
|
+
/** Explicit allowlist. Never spread a stored item into a response. */
|
|
43
|
+
export function vaultMetadata(item) {
|
|
44
|
+
return {
|
|
45
|
+
id: item.id, kind: item.kind, label: item.label, hints: item.hints,
|
|
46
|
+
botIds: [...item.botIds], expiresAt: item.expiresAt,
|
|
47
|
+
origins: item.kind === "login" ? [item.website] : [...item.origins],
|
|
48
|
+
...(item.kind === "login" ? { username: item.username } : {}),
|
|
49
|
+
...(item.kind === "card" ? { lastFour: item.number.slice(-4), expiryMonth: item.expiryMonth, expiryYear: item.expiryYear, billing: { ...item.billing } } : {}),
|
|
50
|
+
...(item.kind === "contact" ? { address: { ...item.address }, email: item.email, phone: item.phone } : {}),
|
|
51
|
+
createdAt: item.createdAt, updatedAt: item.updatedAt,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function vaultUseAllowed(item, actor, now) {
|
|
55
|
+
const destination = vaultOrigin(actor.destination);
|
|
56
|
+
return Number.isSafeInteger(now) && now >= 0 && item.ownerId === actor.ownerId && item.botIds.includes(actor.botId)
|
|
57
|
+
&& (item.expiresAt === null || now < item.expiresAt) && destination !== null
|
|
58
|
+
&& (item.kind === "login" ? item.website === destination : item.origins.includes(destination));
|
|
59
|
+
}
|
|
@@ -1016,9 +1016,12 @@ function runMcpBridge(options) {
|
|
|
1016
1016
|
|
|
1017
1017
|
// server/container-computer.ts
|
|
1018
1018
|
import { execFile as execFile3 } from "node:child_process";
|
|
1019
|
-
import { dirname as dirname4, join as join5, resolve
|
|
1019
|
+
import { dirname as dirname4, join as join5, resolve } from "node:path";
|
|
1020
1020
|
import { promisify } from "node:util";
|
|
1021
1021
|
|
|
1022
|
+
// server/colima-docker.ts
|
|
1023
|
+
var COLIMA_START_TIMEOUT_MS = 4 * 6e4;
|
|
1024
|
+
|
|
1022
1025
|
// server/config.ts
|
|
1023
1026
|
import { homedir as homedir2 } from "node:os";
|
|
1024
1027
|
import { join as join3 } from "node:path";
|
|
@@ -17187,7 +17190,6 @@ var CUA_SOCKET = "/run/user/1000/openmausbot-cua.sock";
|
|
|
17187
17190
|
var CUA_EXECUTABLE = "/usr/local/libexec/openmausbot/cua-driver";
|
|
17188
17191
|
var MEMORY_BYTES = 4 * 1024 * 1024 * 1024;
|
|
17189
17192
|
var SHM_BYTES = 512 * 1024 * 1024;
|
|
17190
|
-
var COLIMA_START_TIMEOUT_MS = 4 * 6e4;
|
|
17191
17193
|
function cuaExecArgs(args2, options = {}) {
|
|
17192
17194
|
return [
|
|
17193
17195
|
"exec",
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as a,C as n}from"./mermaid.core-Sn2sv0Ti.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|