@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.
Files changed (98) hide show
  1. package/dist/assets/{abnfDiagram-O67JEVCF-B8LdsCr1.js → abnfDiagram-O67JEVCF-B8-8zzMS.js} +1 -1
  2. package/dist/assets/{arc-DU5fSmKU.js → arc-CSHQ9Dx3.js} +1 -1
  3. package/dist/assets/{architectureDiagram-NJMV4G6O-DdQSIFKv.js → architectureDiagram-NJMV4G6O-BCHM9rXW.js} +1 -1
  4. package/dist/assets/{blockDiagram-BEXU5L5S-CaPcGYSS.js → blockDiagram-BEXU5L5S-B-5uxPFN.js} +1 -1
  5. package/dist/assets/{c4Diagram-YGBWAQC7-unt0ePgO.js → c4Diagram-YGBWAQC7-CuKNM_MR.js} +1 -1
  6. package/dist/assets/channel-bPN03jIt.js +1 -0
  7. package/dist/assets/{chunk-2Q5K7J3B-Babg5Fzu.js → chunk-2Q5K7J3B-BNF02GM4.js} +1 -1
  8. package/dist/assets/{chunk-3FUC2YCW-D1-dWVHo.js → chunk-3FUC2YCW-uEWgBd4M.js} +2 -2
  9. package/dist/assets/{chunk-5VM5RSS4-DU7nSMbT.js → chunk-5VM5RSS4-eSZuXctY.js} +1 -1
  10. package/dist/assets/{chunk-GTNCS2PH-QIjCJIhV.js → chunk-GTNCS2PH-CslS8nRS.js} +1 -1
  11. package/dist/assets/{chunk-GWA4HPMP-pSByUE5R.js → chunk-GWA4HPMP-w71-MeKj.js} +1 -1
  12. package/dist/assets/{chunk-JWPE2WC7-Dj2AaR1b.js → chunk-JWPE2WC7-Bjju7WGh.js} +1 -1
  13. package/dist/assets/{chunk-NETBCI7D-pZbN0-FP.js → chunk-NETBCI7D-HxrroD4M.js} +1 -1
  14. package/dist/assets/{chunk-WEXAMYUT-Bqarwe4D.js → chunk-WEXAMYUT-D7Rz470x.js} +1 -1
  15. package/dist/assets/{chunk-XXDRQBXY-WV8lm3aa.js → chunk-XXDRQBXY-BWKnAeyM.js} +1 -1
  16. package/dist/assets/{classDiagram-v2-NBCMYWYE-BANBtky1.js → classDiagram-v2-NBCMYWYE-CeBDRHmP.js} +1 -1
  17. package/dist/assets/{cose-bilkent-JH36ORCC-CtrktgBC.js → cose-bilkent-JH36ORCC-BBbRKlvr.js} +1 -1
  18. package/dist/assets/{cynefin-OW5HDTMX-DnhVVfba.js → cynefin-OW5HDTMX-W02cnJ0B.js} +1 -1
  19. package/dist/assets/{cynefinDiagram-VND7K2PF-B42SRR6x.js → cynefinDiagram-VND7K2PF-Cs47eaxd.js} +1 -1
  20. package/dist/assets/{dagre-6A5THRUB-DM--vFMK.js → dagre-6A5THRUB-8mG18hzT.js} +1 -1
  21. package/dist/assets/{diagram-22UHCM2B-ZBupBrPU.js → diagram-22UHCM2B-DF4Qrw67.js} +1 -1
  22. package/dist/assets/{diagram-3UASUU5V-BPQzNIOd.js → diagram-3UASUU5V-3BAVoed1.js} +1 -1
  23. package/dist/assets/{diagram-ATOU4E4O-5kO8vf8Z.js → diagram-ATOU4E4O-CKO3pECE.js} +1 -1
  24. package/dist/assets/{diagram-CDSNMT55-DtxogB86.js → diagram-CDSNMT55-CZhrGvur.js} +1 -1
  25. package/dist/assets/{diagram-MLGK6HIB-Co9-nYw_.js → diagram-MLGK6HIB-C07l9pdQ.js} +1 -1
  26. package/dist/assets/{diagram-MPIPVDR6-DWRuMh5y.js → diagram-MPIPVDR6-D3or4lkZ.js} +1 -1
  27. package/dist/assets/{ebnfDiagram-ZINNZB2B-DU_nmoG9.js → ebnfDiagram-ZINNZB2B-DV2epXp_.js} +1 -1
  28. package/dist/assets/{elk-276RUBZZ-Bcje7S94.js → elk-276RUBZZ-DlvEn4-1.js} +1 -1
  29. package/dist/assets/{erDiagram-OPXOYQCR-9aCo_2CI.js → erDiagram-OPXOYQCR-CB6X7Wt5.js} +1 -1
  30. package/dist/assets/{flowDiagram-KWPJA3E3-D4FYFyc5.js → flowDiagram-KWPJA3E3-C3bqz4lC.js} +1 -1
  31. package/dist/assets/{ganttDiagram-FUAMR5RP-WQHX5rbx.js → ganttDiagram-FUAMR5RP-yo_Evhab.js} +1 -1
  32. package/dist/assets/{gitGraphDiagram-X574FWY7-DRyzBdiV.js → gitGraphDiagram-X574FWY7-Cq2oUlap.js} +1 -1
  33. package/dist/assets/{index-CG1OvRgO.js → index-CG4AFPb4.js} +1 -1
  34. package/dist/assets/{index-D_8SD_0K.js → index-CMcr5k3Z.js} +205 -200
  35. package/dist/assets/index-CZjRcUdn.css +1 -0
  36. package/dist/assets/{infoDiagram-VRGFBTTK-D7SOmp4n.js → infoDiagram-VRGFBTTK-Y3ZrY7qL.js} +1 -1
  37. package/dist/assets/{ishikawaDiagram-OU5B5YK6-CdxOnDVX.js → ishikawaDiagram-OU5B5YK6-BpOtSfyi.js} +1 -1
  38. package/dist/assets/{journeyDiagram-ZHPQQLJL-CH7477Oa.js → journeyDiagram-ZHPQQLJL-UQM727le.js} +1 -1
  39. package/dist/assets/{kanban-definition-PNTS6WVX-BdpVvkHd.js → kanban-definition-PNTS6WVX-C3s5oHpY.js} +1 -1
  40. package/dist/assets/{linear-DTGq6qn5.js → linear-hX6nFOQr.js} +1 -1
  41. package/dist/assets/{mermaid.core-Sn2sv0Ti.js → mermaid.core-DZObGLN7.js} +5 -5
  42. package/dist/assets/{mindmap-definition-NLK3R4M7-koCmkYuq.js → mindmap-definition-NLK3R4M7-Br-i2E3P.js} +1 -1
  43. package/dist/assets/{pegDiagram-GJSIUBJH-C3sqhm8e.js → pegDiagram-GJSIUBJH-D5SERB-N.js} +1 -1
  44. package/dist/assets/{pieDiagram-5QR66LMP-BELBK122.js → pieDiagram-5QR66LMP-BPNf4J3D.js} +1 -1
  45. package/dist/assets/{quadrantDiagram-O4NWA36T-Cksi5LSm.js → quadrantDiagram-O4NWA36T-Bm_Wh7Jr.js} +1 -1
  46. package/dist/assets/{railroadDiagram-XR7U4H2S-f1av_EZW.js → railroadDiagram-XR7U4H2S-D6bo0abD.js} +1 -1
  47. package/dist/assets/{requirementDiagram-PLB6GJNP-CW4O5nER.js → requirementDiagram-PLB6GJNP--1n5rkV7.js} +1 -1
  48. package/dist/assets/{sankeyDiagram-IPEJSGJF-Dz8ADHNY.js → sankeyDiagram-IPEJSGJF-Ct4tP2kK.js} +1 -1
  49. package/dist/assets/{sequenceDiagram-PO4LG4MO-Cc3HE0iZ.js → sequenceDiagram-PO4LG4MO-CCG7O5fR.js} +1 -1
  50. package/dist/assets/{sizeCapture-INFHLROL-gdaZNHnK.js → sizeCapture-INFHLROL-CJJJra9c.js} +1 -1
  51. package/dist/assets/{stateDiagram-v2-GCMORJYK--u8LCnab.js → stateDiagram-v2-GCMORJYK-BMdRvVEX.js} +1 -1
  52. package/dist/assets/{swimlanes-2SLR337P-4MAw4kdO.js → swimlanes-2SLR337P-B1wnogip.js} +1 -1
  53. package/dist/assets/swimlanesDiagram-TC7HE7FX-DWyjdGGR.js +8 -0
  54. package/dist/assets/{timeline-definition-EJHVYXUP-CL89YkCT.js → timeline-definition-EJHVYXUP-l-3yhXUP.js} +1 -1
  55. package/dist/assets/{usecaseDiagram-POWQR4AR-C92l7YQe.js → usecaseDiagram-POWQR4AR-DtwtCOoJ.js} +1 -1
  56. package/dist/assets/{vennDiagram-UO4OBE2U-17siYhSj.js → vennDiagram-UO4OBE2U-BZAEce1B.js} +1 -1
  57. package/dist/assets/{wardleyDiagram-VNRHLVJA-CNwa9VmN.js → wardleyDiagram-VNRHLVJA-Na_BCMMO.js} +1 -1
  58. package/dist/assets/{xychartDiagram-PMCCYNJV-Dnu6Xzih.js → xychartDiagram-PMCCYNJV-BW9dlUfE.js} +1 -1
  59. package/dist/index.html +2 -2
  60. package/dist-server/container-mcp.js +68 -14
  61. package/dist-server/index.js +5633 -4562
  62. package/dist-server/openmausbot.js +140 -81
  63. package/dist-server/pair-cli.js +140 -81
  64. package/dist-server/server/app-installers.js +107 -7
  65. package/dist-server/server/avatar-subscription.js +51 -0
  66. package/dist-server/server/cli-help.js +74 -0
  67. package/dist-server/server/cli.js +37 -78
  68. package/dist-server/server/colima-docker.js +136 -0
  69. package/dist-server/server/container-computer.js +31 -63
  70. package/dist-server/server/container-mcp.js +5 -0
  71. package/dist-server/server/device-routing.js +60 -0
  72. package/dist-server/server/drivers/claude.js +13 -11
  73. package/dist-server/server/drivers/local-inject.js +3 -4
  74. package/dist-server/server/engine-failover.js +22 -12
  75. package/dist-server/server/engine-tiers.js +5 -14
  76. package/dist-server/server/index.js +124 -120
  77. package/dist-server/server/personal-goal-runtime.js +86 -0
  78. package/dist-server/server/personal-goal-turn.js +125 -0
  79. package/dist-server/server/personal-goals.js +195 -0
  80. package/dist-server/server/port-in-use.js +21 -0
  81. package/dist-server/server/routes/local-models.js +3 -2
  82. package/dist-server/server/session-fallback.js +76 -0
  83. package/dist-server/server/skill-fetch.js +14 -0
  84. package/dist-server/server/vault/routes.js +43 -0
  85. package/dist-server/server/vault/runtime.js +48 -0
  86. package/dist-server/server/vault/store.js +177 -0
  87. package/dist-server/shared/desktop-private-port.js +1 -0
  88. package/dist-server/shared/engine-choices.js +15 -0
  89. package/dist-server/shared/engine-tiers.js +74 -2
  90. package/dist-server/shared/local-models.js +1 -3
  91. package/dist-server/shared/personal-goal.js +43 -0
  92. package/dist-server/shared/subscription-bots.js +3 -0
  93. package/dist-server/shared/vault.js +59 -0
  94. package/dist-server/vps-container-mcp.js +4 -2
  95. package/package.json +1 -1
  96. package/dist/assets/channel-GBaPOaz-.js +0 -1
  97. package/dist/assets/index-C8YP7Zxj.css +0 -1
  98. 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
- research: "Plata",
119
+ // Research and Routine ask for the cheapest class (Erick, 2026-10-25).
120
+ research: "Añejo",
49
121
  writing: "Plata",
50
- routine: "Reposado",
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 !== "darwin")
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, win32 as win323 } from "node:path";
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@chibitek/chibi",
3
- "version": "0.1.155",
3
+ "version": "0.1.158",
4
4
  "description": "Atomic by Chibitek: run your AI team's server anywhere and pair your devices to it",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -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};