hanoman 0.9.38 → 0.9.40

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 (34) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/cli.js +95 -4
  3. package/dist/server.js +1461 -451
  4. package/docs/agent-integration.md +6 -0
  5. package/package.json +2 -1
  6. package/prisma/migrations/20261101090000_runtime_account/migration.sql +18 -0
  7. package/prisma/schema.prisma +19 -0
  8. package/skills/codex-image/SKILL.md +225 -0
  9. package/skills/codex-image/references/sprite-sheets.md +60 -0
  10. package/skills/codex-image/scripts/codex-image.sh +253 -0
  11. package/skills/codex-image/scripts/normalize-set.py +104 -0
  12. package/web/assets/{DalangHanomanScreen-wpAO0xvb.js → DalangHanomanScreen-WQ2B2G0F.js} +1 -1
  13. package/web/assets/{DocPreviewModal-CbhkDUJ2.js → DocPreviewModal-DkuSjeL9.js} +1 -1
  14. package/web/assets/{DocsWorkspace-CcB0LGFV.js → DocsWorkspace-BJ71xmQ_.js} +1 -1
  15. package/web/assets/{IdeScreen-DI4v3ZkU.js → IdeScreen-Bc4gR6md.js} +1 -1
  16. package/web/assets/{LeadScreen-BdS_xX_f.js → LeadScreen-BmRdOMoJ.js} +1 -1
  17. package/web/assets/{ReviewScreen-Ddw5U2sM.js → ReviewScreen-C83FuzRB.js} +1 -1
  18. package/web/assets/{SchedulerScreen-D6LGVrhM.js → SchedulerScreen-BKnqWV7j.js} +1 -1
  19. package/web/assets/{SettingsScreen-DQZ3K43g.css → SettingsScreen-B7CruwHq.css} +1 -1
  20. package/web/assets/SettingsScreen-FrgI5pzO.js +62 -0
  21. package/web/assets/{TeamScreen-BkxPDI5P.js → TeamScreen-Dgrvomt0.js} +1 -1
  22. package/web/assets/TerminalScreen-D2KSQ13m.js +2 -0
  23. package/web/assets/{TriageScreen-B-HdZsEt.js → TriageScreen-DrPERvDs.js} +1 -1
  24. package/web/assets/{VpsScreen-CWp29NL_.js → VpsScreen-7sDyg5MI.js} +2 -2
  25. package/web/assets/fields-BNhNDKOP.js +1 -0
  26. package/web/assets/{index-B4b6i2tH.css → index-B0VYqeq_.css} +1 -1
  27. package/web/assets/{index-C4Py9MJV.js → index-NoTUDPfb.js} +212 -212
  28. package/web/assets/{live-CBa_7-hn.js → live-B4ZwQ4kB.js} +1 -1
  29. package/web/assets/{sched-lead-shared-CQIoYIzG.js → sched-lead-shared-CZ0_L34F.js} +1 -1
  30. package/web/assets/{settings-rebase-C3611gs8.js → settings-rebase-DwTIHvhF.js} +1 -1
  31. package/web/index.html +2 -2
  32. package/web/assets/SettingsScreen-CFNcg1T8.js +0 -62
  33. package/web/assets/TerminalScreen-CEQFK9Rc.js +0 -2
  34. package/web/assets/fields-BY7SYerd.js +0 -1
package/dist/server.js CHANGED
@@ -4164,6 +4164,36 @@ var init_enums = __esm({
4164
4164
  }
4165
4165
  });
4166
4166
 
4167
+ // ../shared/src/runtime-accounts.ts
4168
+ function runtimeOfBuiltin(id2) {
4169
+ if (!isBuiltinAccountId(id2)) return null;
4170
+ const r = zAgent.safeParse(id2.slice(BUILTIN_ACCOUNT_PREFIX.length));
4171
+ return r.success ? r.data : null;
4172
+ }
4173
+ var BUILTIN_ACCOUNT_PREFIX, BUILTIN_ACCOUNT_LABEL, builtinAccountId, isBuiltinAccountId, zAccountId, zAccountLabel, zRuntimeAccountCreate, zRuntimeAccountPatch, zRuntimeAccountDefault, zRuntimeAccountLogin, zRuntimeAccountDefaults;
4174
+ var init_runtime_accounts = __esm({
4175
+ "../shared/src/runtime-accounts.ts"() {
4176
+ "use strict";
4177
+ init_zod();
4178
+ init_enums();
4179
+ BUILTIN_ACCOUNT_PREFIX = "default:";
4180
+ BUILTIN_ACCOUNT_LABEL = "Default";
4181
+ builtinAccountId = (runtime) => `${BUILTIN_ACCOUNT_PREFIX}${runtime}`;
4182
+ isBuiltinAccountId = (id2) => id2.startsWith(BUILTIN_ACCOUNT_PREFIX);
4183
+ zAccountId = external_exports.string().min(1).max(80);
4184
+ zAccountLabel = external_exports.string().trim().min(1).max(40);
4185
+ zRuntimeAccountCreate = external_exports.object({ runtime: zAgent, label: zAccountLabel }).strict();
4186
+ zRuntimeAccountPatch = external_exports.object({ label: zAccountLabel }).strict();
4187
+ zRuntimeAccountDefault = external_exports.object({ runtime: zAgent, accountId: zAccountId }).strict();
4188
+ zRuntimeAccountLogin = external_exports.object({ deviceAuth: external_exports.boolean().optional() }).strict();
4189
+ zRuntimeAccountDefaults = external_exports.object({
4190
+ claude: zAccountId.optional(),
4191
+ codex: zAccountId.optional(),
4192
+ antigravity: zAccountId.optional()
4193
+ });
4194
+ }
4195
+ });
4196
+
4167
4197
  // ../shared/src/spec-source.ts
4168
4198
  function payloadShapeFor(source) {
4169
4199
  return source === "qa" ? "qa" : GOAL_SHAPED_SOURCES.has(source) ? "goal" : "brief";
@@ -5482,6 +5512,7 @@ var init_entities = __esm({
5482
5512
  init_method_catalog();
5483
5513
  init_relay();
5484
5514
  init_logs();
5515
+ init_runtime_accounts();
5485
5516
  init_runtime_defaults();
5486
5517
  zProject = external_exports.object({
5487
5518
  id: external_exports.string(),
@@ -5805,6 +5836,10 @@ var init_entities = __esm({
5805
5836
  // lajur log ke hub (SPEC-1217)
5806
5837
  logRetention: zLogRetention.default(LOG_RETENTION_DEFAULTS),
5807
5838
  // retensi log di hub (SPEC-1217)
5839
+ // ADR-0234 · default akun runtime per mesin. LOCAL (setting tak ada di SYNCED) dan TAK ditulis
5840
+ // `PUT /settings` (routes/settings.ts mempertahankan nilai tersimpan) — pengelolanya
5841
+ // `PUT /api/runtime-accounts/default`. Absen = akun bawaan `default:<runtime>`.
5842
+ accounts: zRuntimeAccountDefaults.default({}),
5808
5843
  // SPEC-881 · ADR-0136 · sidik jari isi bawaan yang TERAKHIR ditulis seed di mesin ini, per nama
5809
5844
  // agen. Dipakai seed untuk membedakan "belum pernah disunting operator" dari "sudah". WAJIB
5810
5845
  // dideklarasikan di sini: zod membuang kunci tak dikenal dan `PUT /settings` menulis balik hasil
@@ -5868,7 +5903,7 @@ function resolvePhasePlan(input) {
5868
5903
  if (!input.nativeAgents || cfg?.enabled === false) return null;
5869
5904
  const cells = cfg?.[input.runtime] ?? {};
5870
5905
  const coerce3 = input.runtime === "codex" ? coerceCodexEffort : coerceClaudeEffort;
5871
- const resolve25 = (key, fallback3) => {
5906
+ const resolve26 = (key, fallback3) => {
5872
5907
  const cell4 = cells[key];
5873
5908
  const override = input.phaseOverrides?.[key];
5874
5909
  if (input.runtime === "antigravity") {
@@ -5892,7 +5927,7 @@ function resolvePhasePlan(input) {
5892
5927
  phases: FLOW_PHASES[input.flow].map((phase) => ({
5893
5928
  phase,
5894
5929
  agentName: phaseAgentName(phase),
5895
- ...resolve25(phase, phase === REVIEWER_CELL ? REVIEWER_DEFAULTS[input.runtime] : input.orchestrator)
5930
+ ...resolve26(phase, phase === REVIEWER_CELL ? REVIEWER_DEFAULTS[input.runtime] : input.orchestrator)
5896
5931
  })),
5897
5932
  // Amandemen ADR-0170 P2 · cara Execute mengerjakan plan; hanya dipakai sesi claude.
5898
5933
  executeMode: cfg?.executeMode ?? "inline"
@@ -7721,6 +7756,7 @@ var init_dto = __esm({
7721
7756
  init_entities();
7722
7757
  init_lead();
7723
7758
  init_auto_merge();
7759
+ init_runtime_accounts();
7724
7760
  init_handled_by();
7725
7761
  init_prd_status();
7726
7762
  init_enums();
@@ -7762,7 +7798,9 @@ var init_dto = __esm({
7762
7798
  endedReason: external_exports.string().nullable(),
7763
7799
  reconciledAt: external_exports.string().nullable(),
7764
7800
  exitCode: external_exports.number().nullable(),
7765
- transcriptBytes: external_exports.number().nullable()
7801
+ transcriptBytes: external_exports.number().nullable(),
7802
+ // ADR-0234 · akun runtime saat sesi lahir. null/absen = akun bawaan (atau baris lama).
7803
+ accountId: external_exports.string().nullable().optional()
7766
7804
  });
7767
7805
  zCreateProject = external_exports.object({
7768
7806
  name: external_exports.string().min(1),
@@ -8129,6 +8167,8 @@ var init_dto = __esm({
8129
8167
  agent: zAgent.optional(),
8130
8168
  model: external_exports.string().optional(),
8131
8169
  effort: external_exports.string().optional(),
8170
+ account: zAccountId.optional(),
8171
+ // ADR-0234 · akun runtime pilihan form "Sesi baru"
8132
8172
  force: external_exports.boolean().optional(),
8133
8173
  // ADR-0232 · opsional: `worktree:true` → sesi lahir di `.worktrees/<id>` pada branch baru
8134
8174
  // `term/<id>` dari `branchFrom` (kosong → HEAD repo), alih-alih langsung di repoDir. Tanpa
@@ -8153,6 +8193,8 @@ var init_dto = __esm({
8153
8193
  goal: external_exports.boolean().optional(),
8154
8194
  goalCondition: external_exports.string().max(4e3).optional(),
8155
8195
  agent: zAgent.optional(),
8196
+ account: zAccountId.optional(),
8197
+ // ADR-0234 · akun runtime pilihan picker Start
8156
8198
  verifyScope: zVerifyScope.optional(),
8157
8199
  // SPEC-734 · ADR-0113 — metode workflow per SESI: undefined → Spec.payload.method →
8158
8200
  // Setting.method → "superpowers". LENIENT (`z.string()`, bukan `z.enum`): id yang tak dikenal
@@ -8505,6 +8547,13 @@ var init_api = __esm({
8505
8547
  // ADR-0204 · tandai satu notifikasi terbaca (POST, idempoten).
8506
8548
  notificationRead: (id2) => `${API}/notifications/${encodeURIComponent(id2)}/read`,
8507
8549
  limits: `${API}/limits`,
8550
+ // ADR-0234 · akun runtime & limit per akun.
8551
+ limitsAccounts: `${API}/limits/accounts`,
8552
+ runtimeAccounts: `${API}/runtime-accounts`,
8553
+ runtimeAccount: (id2) => `${API}/runtime-accounts/${encodeURIComponent(id2)}`,
8554
+ runtimeAccountsDefault: `${API}/runtime-accounts/default`,
8555
+ runtimeAccountLogin: (id2) => `${API}/runtime-accounts/${encodeURIComponent(id2)}/login`,
8556
+ runtimeAccountCheck: (id2) => `${API}/runtime-accounts/${encodeURIComponent(id2)}/check`,
8508
8557
  // SPEC-339 · versi codex CLI (peringatan lunak model GPT-5.6).
8509
8558
  codexVersion: `${API}/codex/version`,
8510
8559
  antigravityVersion: `${API}/antigravity/version`,
@@ -12305,6 +12354,38 @@ var init_settings = __esm({
12305
12354
  sampleMethod: "POST",
12306
12355
  build: (a) => ({ method: "POST", path: `/scheduler/queue/${enc(String(a.item))}/requeue` }),
12307
12356
  shape: (raw) => raw
12357
+ },
12358
+ // ADR-0234 · akun runtime. Hanya baca & set default — tambah/hapus/login akun tetap di dashboard
12359
+ // (COOKIE_ONLY: pengelolaan kredensial dan login OAuth butuh manusia di browser).
12360
+ {
12361
+ name: "hanoman_runtime_accounts_list",
12362
+ title: "Daftar akun runtime",
12363
+ description: "Akun langganan Claude Code/Codex/Antigravity yang terdaftar di mesin ini \u2014 termasuk akun bawaan `default:<runtime>` \u2014 dengan status login (belum-login|aktif|perlu-login-ulang), email & paket, drift konfigurasi, dan akun mana yang jadi default tiap runtime. `id`-nya dipakai di `account` pada hanoman_session_create. Menambah/menghapus/login akun hanya lewat dashboard.",
12364
+ inputSchema: obj({ properties: {} }),
12365
+ mode: "read",
12366
+ capability: "settings:read",
12367
+ samplePath: "/runtime-accounts",
12368
+ sampleMethod: "GET",
12369
+ build: () => ({ method: "GET", path: "/runtime-accounts" }),
12370
+ shape: (raw) => raw
12371
+ },
12372
+ {
12373
+ name: "hanoman_runtime_account_default_set",
12374
+ title: "Set akun default runtime",
12375
+ description: "Menjadikan satu akun sebagai default runtime-nya untuk SETIAP sesi baru di mesin ini, termasuk sesi otomatis (scheduler, lead, reverse/prd). `accountId` dari hanoman_runtime_accounts_list; `default:<runtime>` mengembalikan ke akun bawaan. Sesi yang sedang berjalan tak berubah. Ditolak 409 bila runtime akun tak cocok atau sandbox sesi aktif (hanya akun bawaan).",
12376
+ inputSchema: obj({
12377
+ properties: {
12378
+ runtime: enumStr(["claude", "codex", "antigravity"], "Runtime yang default-nya diubah."),
12379
+ accountId: str("Id akun dari hanoman_runtime_accounts_list.")
12380
+ },
12381
+ required: ["runtime", "accountId"]
12382
+ }),
12383
+ mode: "write",
12384
+ capability: "settings:write",
12385
+ samplePath: "/runtime-accounts/default",
12386
+ sampleMethod: "PUT",
12387
+ build: (a) => ({ method: "PUT", path: "/runtime-accounts/default", body: { runtime: String(a.runtime), accountId: String(a.accountId) } }),
12388
+ shape: (raw) => raw
12308
12389
  }
12309
12390
  ];
12310
12391
  }
@@ -13263,6 +13344,7 @@ var init_sessions = __esm({
13263
13344
  ),
13264
13345
  shell: bool("true = terminal shell biasa di repo project, tanpa agen. Hanya dengan `project`."),
13265
13346
  agent: enumStr(["claude", "codex", "antigravity"], "Mesin sesi. Kosong = default global."),
13347
+ account: str("Id akun runtime dari hanoman_runtime_accounts_list (ADR-0234). Kosong = akun default runtime di mesin ini."),
13266
13348
  model: str("Model. Kosong = default global."),
13267
13349
  effort: str("Effort. Kosong = default global."),
13268
13350
  goal: bool("Mode goal per-sesi. Kosong = ikut setelan global."),
@@ -13299,7 +13381,7 @@ var init_sessions = __esm({
13299
13381
  build: (a) => {
13300
13382
  if (s(a.spec)) {
13301
13383
  const body2 = { spec: String(a.spec), flow: String(a.flow) };
13302
- for (const k of ["model", "effort", "goalCondition", "agent", "verifyScope", "method"])
13384
+ for (const k of ["model", "effort", "goalCondition", "agent", "account", "verifyScope", "method"])
13303
13385
  if (s(a[k]) !== void 0) body2[k] = s(a[k]);
13304
13386
  if (a.phaseOverrides && typeof a.phaseOverrides === "object" && !Array.isArray(a.phaseOverrides)) body2.phaseOverrides = a.phaseOverrides;
13305
13387
  for (const k of ["goal", "force"]) if (typeof a[k] === "boolean") body2[k] = a[k];
@@ -13311,7 +13393,7 @@ var init_sessions = __esm({
13311
13393
  if (flow2 === "breakdown") return { method: "POST", path: "/terminal/sessions", body: { project, flow: flow2, prdPath: String(a.prdPath) } };
13312
13394
  if (flow2 === "reverse" || flow2 === "scaffold") return { method: "POST", path: "/terminal/sessions", body: { project, flow: flow2 } };
13313
13395
  const body = { project };
13314
- for (const k of ["agent", "model", "effort", "branchFrom"]) if (s(a[k]) !== void 0) body[k] = s(a[k]);
13396
+ for (const k of ["agent", "account", "model", "effort", "branchFrom"]) if (s(a[k]) !== void 0) body[k] = s(a[k]);
13315
13397
  if (typeof a.worktree === "boolean") body.worktree = a.worktree;
13316
13398
  return { method: "POST", path: "/terminal/sessions", body };
13317
13399
  },
@@ -14481,6 +14563,19 @@ var init_system = __esm({
14481
14563
  build: () => ({ method: "GET", path: "/limits/antigravity" }),
14482
14564
  shape: (raw) => raw
14483
14565
  },
14566
+ // ADR-0234 · limit per akun runtime. GLOBAL_READ → tanpa email (identitas di hanoman_runtime_accounts_list).
14567
+ {
14568
+ name: "hanoman_limits_accounts",
14569
+ title: "Limit langganan per akun runtime",
14570
+ description: "Limit (window 5 jam, mingguan, dst) untuk SETIAP akun runtime terdaftar di mesin ini \u2014 Claude, Codex, Antigravity \u2014 termasuk akun bawaan `default:<runtime>`. Tanpa email. `limits.status` stale = data terakhir (akun belum dipakai sejak tokennya kedaluwarsa); window yang `resetsAt`-nya sudah lewat berarti sudah reset. `isDefault` menandai akun yang dipakai sesi baru.",
14571
+ inputSchema: obj({ properties: {} }),
14572
+ mode: "read",
14573
+ capability: null,
14574
+ samplePath: "/limits/accounts",
14575
+ sampleMethod: "GET",
14576
+ build: () => ({ method: "GET", path: "/limits/accounts" }),
14577
+ shape: (raw) => raw
14578
+ },
14484
14579
  {
14485
14580
  name: "hanoman_overview_get",
14486
14581
  title: "Ringkasan kinerja hari ini (Overview)",
@@ -17124,6 +17219,7 @@ var init_src = __esm({
17124
17219
  "../shared/src/index.ts"() {
17125
17220
  "use strict";
17126
17221
  init_enums();
17222
+ init_runtime_accounts();
17127
17223
  init_spec_source();
17128
17224
  init_method_catalog();
17129
17225
  init_method_status();
@@ -20034,12 +20130,12 @@ function manifestRoots(home3) {
20034
20130
  return out4;
20035
20131
  }
20036
20132
  function cacheRoots(home3) {
20037
- const cache6 = join6(home3, "plugins", "cache");
20133
+ const cache7 = join6(home3, "plugins", "cache");
20038
20134
  const out4 = [];
20039
- for (const marketplace of dirsIn(cache6))
20040
- for (const pkg of dirsIn(join6(cache6, marketplace)))
20041
- for (const version of dirsIn(join6(cache6, marketplace, pkg)))
20042
- out4.push({ pkg, marketplace, dir: join6(cache6, marketplace, pkg, version) });
20135
+ for (const marketplace of dirsIn(cache7))
20136
+ for (const pkg of dirsIn(join6(cache7, marketplace)))
20137
+ for (const version of dirsIn(join6(cache7, marketplace, pkg)))
20138
+ out4.push({ pkg, marketplace, dir: join6(cache7, marketplace, pkg, version) });
20043
20139
  return out4;
20044
20140
  }
20045
20141
  function disabledPlugins(agent, home3) {
@@ -20212,10 +20308,10 @@ function ensureSpawnHelpersExecutable(paths3, ops) {
20212
20308
  }
20213
20309
  return fixed;
20214
20310
  }
20215
- function repairSpawnHelper(resolve25, notify) {
20311
+ function repairSpawnHelper(resolve26, notify) {
20216
20312
  let ptyDir;
20217
20313
  try {
20218
- ptyDir = dirname5(resolve25("node-pty/package.json"));
20314
+ ptyDir = dirname5(resolve26("node-pty/package.json"));
20219
20315
  } catch {
20220
20316
  return [];
20221
20317
  }
@@ -20233,8 +20329,8 @@ function repairSpawnHelper(resolve25, notify) {
20233
20329
  if (fixed.length) notify?.("hanoman \xB7 memperbaiki izin `spawn-helper` node-pty (hilang setelah pemasangan/pembaruan paket)\n");
20234
20330
  return fixed;
20235
20331
  }
20236
- function ensureSpawnHelper(resolve25, notify) {
20237
- return repairSpawnHelper(resolve25, notify);
20332
+ function ensureSpawnHelper(resolve26, notify) {
20333
+ return repairSpawnHelper(resolve26, notify);
20238
20334
  }
20239
20335
  function spawnWithHelperRecovery(doSpawn, repair) {
20240
20336
  repair();
@@ -24999,9 +25095,9 @@ var require_dispatcher_base = __commonJS({
24999
25095
  }
25000
25096
  close(callback) {
25001
25097
  if (callback === void 0) {
25002
- return new Promise((resolve25, reject2) => {
25098
+ return new Promise((resolve26, reject2) => {
25003
25099
  this.close((err, data) => {
25004
- return err ? reject2(err) : resolve25(data);
25100
+ return err ? reject2(err) : resolve26(data);
25005
25101
  });
25006
25102
  });
25007
25103
  }
@@ -25039,9 +25135,9 @@ var require_dispatcher_base = __commonJS({
25039
25135
  err = null;
25040
25136
  }
25041
25137
  if (callback === void 0) {
25042
- return new Promise((resolve25, reject2) => {
25138
+ return new Promise((resolve26, reject2) => {
25043
25139
  this.destroy(err, (err2, data) => {
25044
- return err2 ? reject2(err2) : resolve25(data);
25140
+ return err2 ? reject2(err2) : resolve26(data);
25045
25141
  });
25046
25142
  });
25047
25143
  }
@@ -28538,8 +28634,8 @@ var require_promise = __commonJS({
28538
28634
  function createDeferredPromise() {
28539
28635
  let res;
28540
28636
  let rej;
28541
- const promise = new Promise((resolve25, reject2) => {
28542
- res = resolve25;
28637
+ const promise = new Promise((resolve26, reject2) => {
28638
+ res = resolve26;
28543
28639
  rej = reject2;
28544
28640
  });
28545
28641
  return { promise, resolve: res, reject: rej };
@@ -29942,12 +30038,12 @@ upgrade: ${upgrade}\r
29942
30038
  cb();
29943
30039
  }
29944
30040
  }
29945
- const waitForDrain = () => new Promise((resolve25, reject2) => {
30041
+ const waitForDrain = () => new Promise((resolve26, reject2) => {
29946
30042
  assert(callback === null);
29947
30043
  if (socket2[kError]) {
29948
30044
  reject2(socket2[kError]);
29949
30045
  } else {
29950
- callback = resolve25;
30046
+ callback = resolve26;
29951
30047
  }
29952
30048
  });
29953
30049
  socket2.on("close", onDrain).on("drain", onDrain);
@@ -30823,12 +30919,12 @@ var require_client_h2 = __commonJS({
30823
30919
  cb();
30824
30920
  }
30825
30921
  }
30826
- const waitForDrain = () => new Promise((resolve25, reject2) => {
30922
+ const waitForDrain = () => new Promise((resolve26, reject2) => {
30827
30923
  assert(callback === null);
30828
30924
  if (socket2[kError]) {
30829
30925
  reject2(socket2[kError]);
30830
30926
  } else {
30831
- callback = resolve25;
30927
+ callback = resolve26;
30832
30928
  }
30833
30929
  });
30834
30930
  h2stream.on("close", onDrain).on("drain", onDrain);
@@ -31144,16 +31240,16 @@ var require_client = __commonJS({
31144
31240
  return this[kNeedDrain] < 2;
31145
31241
  }
31146
31242
  [kClose]() {
31147
- return new Promise((resolve25) => {
31243
+ return new Promise((resolve26) => {
31148
31244
  if (this[kSize]) {
31149
- this[kClosedResolve] = resolve25;
31245
+ this[kClosedResolve] = resolve26;
31150
31246
  } else {
31151
- resolve25(null);
31247
+ resolve26(null);
31152
31248
  }
31153
31249
  });
31154
31250
  }
31155
31251
  [kDestroy](err) {
31156
- return new Promise((resolve25) => {
31252
+ return new Promise((resolve26) => {
31157
31253
  const requests = this[kQueue].splice(this[kPendingIdx]);
31158
31254
  for (let i = 0; i < requests.length; i++) {
31159
31255
  const request = requests[i];
@@ -31166,7 +31262,7 @@ var require_client = __commonJS({
31166
31262
  this[kClosedResolve]();
31167
31263
  this[kClosedResolve] = null;
31168
31264
  }
31169
- resolve25(null);
31265
+ resolve26(null);
31170
31266
  };
31171
31267
  if (this[kHTTPContext]) {
31172
31268
  this[kHTTPContext].destroy(err, callback);
@@ -31573,8 +31669,8 @@ var require_pool_base = __commonJS({
31573
31669
  }
31574
31670
  return Promise.all(closeAll);
31575
31671
  } else {
31576
- return new Promise((resolve25) => {
31577
- this[kClosedResolve] = resolve25;
31672
+ return new Promise((resolve26) => {
31673
+ this[kClosedResolve] = resolve26;
31578
31674
  });
31579
31675
  }
31580
31676
  }
@@ -32693,7 +32789,7 @@ var require_socks5_proxy_agent = __commonJS({
32693
32789
  const proxyHost = this[kProxyUrl].hostname;
32694
32790
  const proxyPort = parseInt(this[kProxyUrl].port) || 1080;
32695
32791
  debug2("creating SOCKS5 connection to", proxyHost, proxyPort);
32696
- const socket2 = await new Promise((resolve25, reject2) => {
32792
+ const socket2 = await new Promise((resolve26, reject2) => {
32697
32793
  this[kConnector]({
32698
32794
  hostname: proxyHost,
32699
32795
  host: proxyHost,
@@ -32703,7 +32799,7 @@ var require_socks5_proxy_agent = __commonJS({
32703
32799
  if (err) {
32704
32800
  reject2(err);
32705
32801
  } else {
32706
- resolve25(socket3);
32802
+ resolve26(socket3);
32707
32803
  }
32708
32804
  });
32709
32805
  });
@@ -32713,14 +32809,14 @@ var require_socks5_proxy_agent = __commonJS({
32713
32809
  socket2.destroy();
32714
32810
  });
32715
32811
  await socks5Client.handshake();
32716
- await new Promise((resolve25, reject2) => {
32812
+ await new Promise((resolve26, reject2) => {
32717
32813
  const timeout2 = setTimeout(() => {
32718
32814
  reject2(new Error("SOCKS5 authentication timeout"));
32719
32815
  }, 5e3);
32720
32816
  const onAuthenticated = () => {
32721
32817
  clearTimeout(timeout2);
32722
32818
  socks5Client.removeListener("error", onError);
32723
- resolve25();
32819
+ resolve26();
32724
32820
  };
32725
32821
  const onError = (err) => {
32726
32822
  clearTimeout(timeout2);
@@ -32729,14 +32825,14 @@ var require_socks5_proxy_agent = __commonJS({
32729
32825
  };
32730
32826
  if (socks5Client.state === STATES.AUTHENTICATED) {
32731
32827
  clearTimeout(timeout2);
32732
- resolve25();
32828
+ resolve26();
32733
32829
  } else {
32734
32830
  socks5Client.once("authenticated", onAuthenticated);
32735
32831
  socks5Client.once("error", onError);
32736
32832
  }
32737
32833
  });
32738
32834
  await socks5Client.connect(targetHost, targetPort);
32739
- await new Promise((resolve25, reject2) => {
32835
+ await new Promise((resolve26, reject2) => {
32740
32836
  const timeout2 = setTimeout(() => {
32741
32837
  reject2(new Error("SOCKS5 connection timeout"));
32742
32838
  }, 5e3);
@@ -32744,7 +32840,7 @@ var require_socks5_proxy_agent = __commonJS({
32744
32840
  debug2("SOCKS5 tunnel established to", targetHost, targetPort, "via", info);
32745
32841
  clearTimeout(timeout2);
32746
32842
  socks5Client.removeListener("error", onError);
32747
- resolve25();
32843
+ resolve26();
32748
32844
  };
32749
32845
  const onError = (err) => {
32750
32846
  clearTimeout(timeout2);
@@ -32787,8 +32883,8 @@ var require_socks5_proxy_agent = __commonJS({
32787
32883
  socket: socket2,
32788
32884
  servername: this[kRequestTls]?.servername || targetHost
32789
32885
  });
32790
- await new Promise((resolve25, reject2) => {
32791
- finalSocket.once("secureConnect", resolve25);
32886
+ await new Promise((resolve26, reject2) => {
32887
+ finalSocket.once("secureConnect", resolve26);
32792
32888
  finalSocket.once("error", reject2);
32793
32889
  });
32794
32890
  }
@@ -33870,7 +33966,7 @@ var require_readable = __commonJS({
33870
33966
  if (this._readableState.closeEmitted) {
33871
33967
  return Promise.resolve(null);
33872
33968
  }
33873
- return new Promise((resolve25, reject2) => {
33969
+ return new Promise((resolve26, reject2) => {
33874
33970
  if (this[kContentLength] && this[kContentLength] > limit || this[kBytesRead] > limit) {
33875
33971
  this.destroy(new AbortError2());
33876
33972
  }
@@ -33884,11 +33980,11 @@ var require_readable = __commonJS({
33884
33980
  if (signal.aborted) {
33885
33981
  reject2(signal.reason ?? new AbortError2());
33886
33982
  } else {
33887
- resolve25(null);
33983
+ resolve26(null);
33888
33984
  }
33889
33985
  });
33890
33986
  } else {
33891
- this.on("close", resolve25);
33987
+ this.on("close", resolve26);
33892
33988
  }
33893
33989
  this.on("error", noop).on("data", () => {
33894
33990
  if (this[kBytesRead] > limit) {
@@ -33916,7 +34012,7 @@ var require_readable = __commonJS({
33916
34012
  }
33917
34013
  function consume2(stream, type) {
33918
34014
  assert(!stream[kConsume]);
33919
- return new Promise((resolve25, reject2) => {
34015
+ return new Promise((resolve26, reject2) => {
33920
34016
  if (isUnusable(stream)) {
33921
34017
  const rState = stream._readableState;
33922
34018
  if (rState.destroyed && rState.closeEmitted === false) {
@@ -33931,7 +34027,7 @@ var require_readable = __commonJS({
33931
34027
  stream[kConsume] = {
33932
34028
  type,
33933
34029
  stream,
33934
- resolve: resolve25,
34030
+ resolve: resolve26,
33935
34031
  reject: reject2,
33936
34032
  length: 0,
33937
34033
  body: []
@@ -34005,18 +34101,18 @@ var require_readable = __commonJS({
34005
34101
  return buffer;
34006
34102
  }
34007
34103
  function consumeEnd(consume3, encoding) {
34008
- const { type, body, resolve: resolve25, stream, length } = consume3;
34104
+ const { type, body, resolve: resolve26, stream, length } = consume3;
34009
34105
  try {
34010
34106
  if (type === "text") {
34011
- resolve25(chunksDecode(body, length, encoding));
34107
+ resolve26(chunksDecode(body, length, encoding));
34012
34108
  } else if (type === "json") {
34013
- resolve25(JSON.parse(chunksDecode(body, length, encoding)));
34109
+ resolve26(JSON.parse(chunksDecode(body, length, encoding)));
34014
34110
  } else if (type === "arrayBuffer") {
34015
- resolve25(chunksConcat(body, length).buffer);
34111
+ resolve26(chunksConcat(body, length).buffer);
34016
34112
  } else if (type === "blob") {
34017
- resolve25(new Blob(body, { type: stream[kContentType] }));
34113
+ resolve26(new Blob(body, { type: stream[kContentType] }));
34018
34114
  } else if (type === "bytes") {
34019
- resolve25(chunksConcat(body, length));
34115
+ resolve26(chunksConcat(body, length));
34020
34116
  }
34021
34117
  consumeFinish(consume3);
34022
34118
  } catch (err) {
@@ -34206,9 +34302,9 @@ var require_api_request = __commonJS({
34206
34302
  };
34207
34303
  function request(opts2, callback) {
34208
34304
  if (callback === void 0) {
34209
- return new Promise((resolve25, reject2) => {
34305
+ return new Promise((resolve26, reject2) => {
34210
34306
  request.call(this, opts2, (err, data) => {
34211
- return err ? reject2(err) : resolve25(data);
34307
+ return err ? reject2(err) : resolve26(data);
34212
34308
  });
34213
34309
  });
34214
34310
  }
@@ -34420,9 +34516,9 @@ var require_api_stream = __commonJS({
34420
34516
  };
34421
34517
  function stream(opts2, factory, callback) {
34422
34518
  if (callback === void 0) {
34423
- return new Promise((resolve25, reject2) => {
34519
+ return new Promise((resolve26, reject2) => {
34424
34520
  stream.call(this, opts2, factory, (err, data) => {
34425
- return err ? reject2(err) : resolve25(data);
34521
+ return err ? reject2(err) : resolve26(data);
34426
34522
  });
34427
34523
  });
34428
34524
  }
@@ -34710,9 +34806,9 @@ var require_api_upgrade = __commonJS({
34710
34806
  };
34711
34807
  function upgrade(opts2, callback) {
34712
34808
  if (callback === void 0) {
34713
- return new Promise((resolve25, reject2) => {
34809
+ return new Promise((resolve26, reject2) => {
34714
34810
  upgrade.call(this, opts2, (err, data) => {
34715
- return err ? reject2(err) : resolve25(data);
34811
+ return err ? reject2(err) : resolve26(data);
34716
34812
  });
34717
34813
  });
34718
34814
  }
@@ -34805,9 +34901,9 @@ var require_api_connect = __commonJS({
34805
34901
  };
34806
34902
  function connect2(opts2, callback) {
34807
34903
  if (callback === void 0) {
34808
- return new Promise((resolve25, reject2) => {
34904
+ return new Promise((resolve26, reject2) => {
34809
34905
  connect2.call(this, opts2, (err, data) => {
34810
- return err ? reject2(err) : resolve25(data);
34906
+ return err ? reject2(err) : resolve26(data);
34811
34907
  });
34812
34908
  });
34813
34909
  }
@@ -36081,7 +36177,7 @@ var require_snapshot_recorder = __commonJS({
36081
36177
  "../node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
36082
36178
  "use strict";
36083
36179
  var { writeFile: writeFile9, readFile: readFile12, mkdir: mkdir13 } = __require("node:fs/promises");
36084
- var { dirname: dirname20, resolve: resolve25 } = __require("node:path");
36180
+ var { dirname: dirname20, resolve: resolve26 } = __require("node:path");
36085
36181
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
36086
36182
  var { InvalidArgumentError, UndiciError } = require_errors();
36087
36183
  var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
@@ -36261,14 +36357,14 @@ var require_snapshot_recorder = __commonJS({
36261
36357
  }
36262
36358
  const request = formatRequestKey(requestOpts, this.#headerFilters, this.matchOptions);
36263
36359
  const hash4 = createRequestHash(request);
36264
- const snapshot3 = this.#snapshots.get(hash4);
36265
- if (!snapshot3) return void 0;
36266
- const currentCallCount = snapshot3.callCount || 0;
36267
- const responseIndex = Math.min(currentCallCount, snapshot3.responses.length - 1);
36268
- snapshot3.callCount = currentCallCount + 1;
36360
+ const snapshot4 = this.#snapshots.get(hash4);
36361
+ if (!snapshot4) return void 0;
36362
+ const currentCallCount = snapshot4.callCount || 0;
36363
+ const responseIndex = Math.min(currentCallCount, snapshot4.responses.length - 1);
36364
+ snapshot4.callCount = currentCallCount + 1;
36269
36365
  return {
36270
- ...snapshot3,
36271
- response: snapshot3.responses[responseIndex]
36366
+ ...snapshot4,
36367
+ response: snapshot4.responses[responseIndex]
36272
36368
  };
36273
36369
  }
36274
36370
  /**
@@ -36282,12 +36378,12 @@ var require_snapshot_recorder = __commonJS({
36282
36378
  throw new InvalidArgumentError("Snapshot path is required");
36283
36379
  }
36284
36380
  try {
36285
- const data = await readFile12(resolve25(path), "utf8");
36381
+ const data = await readFile12(resolve26(path), "utf8");
36286
36382
  const parsed = JSON.parse(data);
36287
36383
  if (Array.isArray(parsed)) {
36288
36384
  this.#snapshots.clear();
36289
- for (const { hash: hash4, snapshot: snapshot3 } of parsed) {
36290
- this.#snapshots.set(hash4, snapshot3);
36385
+ for (const { hash: hash4, snapshot: snapshot4 } of parsed) {
36386
+ this.#snapshots.set(hash4, snapshot4);
36291
36387
  }
36292
36388
  } else {
36293
36389
  this.#snapshots = new Map(Object.entries(parsed));
@@ -36311,11 +36407,11 @@ var require_snapshot_recorder = __commonJS({
36311
36407
  if (!path) {
36312
36408
  throw new InvalidArgumentError("Snapshot path is required");
36313
36409
  }
36314
- const resolvedPath = resolve25(path);
36410
+ const resolvedPath = resolve26(path);
36315
36411
  await mkdir13(dirname20(resolvedPath), { recursive: true });
36316
- const data = Array.from(this.#snapshots.entries()).map(([hash4, snapshot3]) => ({
36412
+ const data = Array.from(this.#snapshots.entries()).map(([hash4, snapshot4]) => ({
36317
36413
  hash: hash4,
36318
- snapshot: snapshot3
36414
+ snapshot: snapshot4
36319
36415
  }));
36320
36416
  await writeFile9(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
36321
36417
  }
@@ -36345,8 +36441,8 @@ var require_snapshot_recorder = __commonJS({
36345
36441
  * @returns {void}
36346
36442
  */
36347
36443
  resetCallCounts() {
36348
- for (const snapshot3 of this.#snapshots.values()) {
36349
- snapshot3.callCount = 0;
36444
+ for (const snapshot4 of this.#snapshots.values()) {
36445
+ snapshot4.callCount = 0;
36350
36446
  }
36351
36447
  }
36352
36448
  /**
@@ -36367,15 +36463,15 @@ var require_snapshot_recorder = __commonJS({
36367
36463
  getSnapshotInfo(requestOpts) {
36368
36464
  const request = formatRequestKey(requestOpts, this.#headerFilters, this.matchOptions);
36369
36465
  const hash4 = createRequestHash(request);
36370
- const snapshot3 = this.#snapshots.get(hash4);
36371
- if (!snapshot3) return null;
36466
+ const snapshot4 = this.#snapshots.get(hash4);
36467
+ if (!snapshot4) return null;
36372
36468
  return {
36373
36469
  hash: hash4,
36374
- request: snapshot3.request,
36375
- responseCount: snapshot3.responses ? snapshot3.responses.length : snapshot3.response ? 1 : 0,
36470
+ request: snapshot4.request,
36471
+ responseCount: snapshot4.responses ? snapshot4.responses.length : snapshot4.response ? 1 : 0,
36376
36472
  // .response for legacy snapshots
36377
- callCount: snapshot3.callCount || 0,
36378
- timestamp: snapshot3.timestamp
36473
+ callCount: snapshot4.callCount || 0,
36474
+ timestamp: snapshot4.timestamp
36379
36475
  };
36380
36476
  }
36381
36477
  /**
@@ -36386,8 +36482,8 @@ var require_snapshot_recorder = __commonJS({
36386
36482
  replaceSnapshots(snapshotData) {
36387
36483
  this.#snapshots.clear();
36388
36484
  if (Array.isArray(snapshotData)) {
36389
- for (const { hash: hash4, snapshot: snapshot3 } of snapshotData) {
36390
- this.#snapshots.set(hash4, snapshot3);
36485
+ for (const { hash: hash4, snapshot: snapshot4 } of snapshotData) {
36486
+ this.#snapshots.set(hash4, snapshot4);
36391
36487
  }
36392
36488
  } else if (snapshotData && typeof snapshotData === "object") {
36393
36489
  this.#snapshots = new Map(Object.entries(snapshotData));
@@ -36524,9 +36620,9 @@ var require_snapshot_agent = __commonJS({
36524
36620
  if (!this[kSnapshotLoaded]) {
36525
36621
  return this.#asyncDispatch(opts2, handler);
36526
36622
  }
36527
- const snapshot3 = this[kSnapshotRecorder].findSnapshot(opts2);
36528
- if (snapshot3) {
36529
- return this.#replaySnapshot(snapshot3, handler);
36623
+ const snapshot4 = this[kSnapshotRecorder].findSnapshot(opts2);
36624
+ if (snapshot4) {
36625
+ return this.#replaySnapshot(snapshot4, handler);
36530
36626
  } else if (mode === "update") {
36531
36627
  return this.#recordAndReplay(opts2, handler);
36532
36628
  } else {
@@ -36596,9 +36692,9 @@ var require_snapshot_agent = __commonJS({
36596
36692
  * @param {Object} handler - The handler to call with the response data.
36597
36693
  * @returns {void}
36598
36694
  */
36599
- #replaySnapshot(snapshot3, handler) {
36695
+ #replaySnapshot(snapshot4, handler) {
36600
36696
  try {
36601
- const { response } = snapshot3;
36697
+ const { response } = snapshot4;
36602
36698
  const controller = {
36603
36699
  pause() {
36604
36700
  },
@@ -36656,8 +36752,8 @@ var require_snapshot_agent = __commonJS({
36656
36752
  * @returns {void}
36657
36753
  */
36658
36754
  #setupMockInterceptors() {
36659
- for (const snapshot3 of this[kSnapshotRecorder].getSnapshots()) {
36660
- const { request, responses, response } = snapshot3;
36755
+ for (const snapshot4 of this[kSnapshotRecorder].getSnapshots()) {
36756
+ const { request, responses, response } = snapshot4;
36661
36757
  const url2 = new URL(request.url);
36662
36758
  const mockPool = this.get(url2.origin);
36663
36759
  const responseData = responses ? responses[0] : response;
@@ -43737,7 +43833,7 @@ var require_fetch = __commonJS({
43737
43833
  const agent = fetchParams.controller.dispatcher;
43738
43834
  const path = url2.pathname + url2.search;
43739
43835
  const hasTrailingQuestionMark = url2.search.length === 0 && url2.href[url2.href.length - url2.hash.length - 1] === "?";
43740
- return new Promise((resolve25, reject2) => agent.dispatch(
43836
+ return new Promise((resolve26, reject2) => agent.dispatch(
43741
43837
  {
43742
43838
  path: hasTrailingQuestionMark ? `${path}?` : path,
43743
43839
  origin: url2.origin,
@@ -43825,7 +43921,7 @@ var require_fetch = __commonJS({
43825
43921
  }
43826
43922
  }
43827
43923
  const onError = this.onError.bind(this);
43828
- resolve25({
43924
+ resolve26({
43829
43925
  status: status2,
43830
43926
  statusText,
43831
43927
  headersList,
@@ -43878,7 +43974,7 @@ var require_fetch = __commonJS({
43878
43974
  headersList.append(headerName, String(value), true);
43879
43975
  }
43880
43976
  }
43881
- resolve25({
43977
+ resolve26({
43882
43978
  status: status2,
43883
43979
  statusText: STATUS_CODES[status2],
43884
43980
  headersList,
@@ -43902,7 +43998,7 @@ var require_fetch = __commonJS({
43902
43998
  headersList.append(nameStr, value.toString("latin1"), true);
43903
43999
  }
43904
44000
  }
43905
- resolve25({
44001
+ resolve26({
43906
44002
  status: status2,
43907
44003
  statusText: STATUS_CODES[status2],
43908
44004
  headersList,
@@ -44289,8 +44385,8 @@ var require_cache3 = __commonJS({
44289
44385
  * @returns {requestResponseList}
44290
44386
  */
44291
44387
  #batchCacheOperations(operations) {
44292
- const cache6 = this.#relevantRequestResponseList;
44293
- const backupCache = [...cache6];
44388
+ const cache7 = this.#relevantRequestResponseList;
44389
+ const backupCache = [...cache7];
44294
44390
  const addedItems = [];
44295
44391
  const resultList = [];
44296
44392
  try {
@@ -44317,9 +44413,9 @@ var require_cache3 = __commonJS({
44317
44413
  return [];
44318
44414
  }
44319
44415
  for (const requestResponse of requestResponses) {
44320
- const idx = cache6.indexOf(requestResponse);
44416
+ const idx = cache7.indexOf(requestResponse);
44321
44417
  assert(idx !== -1);
44322
- cache6.splice(idx, 1);
44418
+ cache7.splice(idx, 1);
44323
44419
  }
44324
44420
  } else if (operation.type === "put") {
44325
44421
  if (operation.response == null) {
@@ -44349,11 +44445,11 @@ var require_cache3 = __commonJS({
44349
44445
  }
44350
44446
  requestResponses = this.#queryCache(operation.request);
44351
44447
  for (const requestResponse of requestResponses) {
44352
- const idx = cache6.indexOf(requestResponse);
44448
+ const idx = cache7.indexOf(requestResponse);
44353
44449
  assert(idx !== -1);
44354
- cache6.splice(idx, 1);
44450
+ cache7.splice(idx, 1);
44355
44451
  }
44356
- cache6.push([operation.request, operation.response]);
44452
+ cache7.push([operation.request, operation.response]);
44357
44453
  addedItems.push([operation.request, operation.response]);
44358
44454
  }
44359
44455
  resultList.push([operation.request, operation.response]);
@@ -44530,13 +44626,13 @@ var require_cachestorage = __commonJS({
44530
44626
  if (options2.cacheName != null) {
44531
44627
  if (this.#caches.has(options2.cacheName)) {
44532
44628
  const cacheList = this.#caches.get(options2.cacheName);
44533
- const cache6 = new Cache(kConstruct, cacheList);
44534
- return await cache6.match(request, options2);
44629
+ const cache7 = new Cache(kConstruct, cacheList);
44630
+ return await cache7.match(request, options2);
44535
44631
  }
44536
44632
  } else {
44537
44633
  for (const cacheList of this.#caches.values()) {
44538
- const cache6 = new Cache(kConstruct, cacheList);
44539
- const response = await cache6.match(request, options2);
44634
+ const cache7 = new Cache(kConstruct, cacheList);
44635
+ const response = await cache7.match(request, options2);
44540
44636
  if (response !== void 0) {
44541
44637
  return response;
44542
44638
  }
@@ -44566,12 +44662,12 @@ var require_cachestorage = __commonJS({
44566
44662
  webidl.argumentLengthCheck(arguments, 1, prefix);
44567
44663
  cacheName = webidl.converters.DOMString(cacheName, prefix, "cacheName");
44568
44664
  if (this.#caches.has(cacheName)) {
44569
- const cache7 = this.#caches.get(cacheName);
44570
- return new Cache(kConstruct, cache7);
44665
+ const cache8 = this.#caches.get(cacheName);
44666
+ return new Cache(kConstruct, cache8);
44571
44667
  }
44572
- const cache6 = [];
44573
- this.#caches.set(cacheName, cache6);
44574
- return new Cache(kConstruct, cache6);
44668
+ const cache7 = [];
44669
+ this.#caches.set(cacheName, cache7);
44670
+ return new Cache(kConstruct, cache7);
44575
44671
  }
44576
44672
  /**
44577
44673
  * @see https://w3c.github.io/ServiceWorker/#cache-storage-delete
@@ -48243,7 +48339,7 @@ import { request as httpsRequest } from "node:https";
48243
48339
  import { isIP } from "node:net";
48244
48340
  import { createGunzip } from "node:zlib";
48245
48341
  async function pinnedRequest(input) {
48246
- return new Promise((resolve25, reject2) => {
48342
+ return new Promise((resolve26, reject2) => {
48247
48343
  const transport = input.url.protocol === "https:" ? httpsRequest : httpRequest;
48248
48344
  const req = transport({
48249
48345
  protocol: input.url.protocol,
@@ -48265,7 +48361,7 @@ async function pinnedRequest(input) {
48265
48361
  const capTerurai = input.maxDecodedBytes ?? input.maxResponseBytes;
48266
48362
  const chunks = [];
48267
48363
  let kabel = 0, terurai = 0;
48268
- const selesai = () => resolve25({
48364
+ const selesai = () => resolve26({
48269
48365
  status: response.statusCode ?? 0,
48270
48366
  headers: response.headers,
48271
48367
  body: Buffer.concat(chunks)
@@ -48308,12 +48404,12 @@ async function pinnedRequest(input) {
48308
48404
  });
48309
48405
  }
48310
48406
  function withLookupTimeout(p3, ms) {
48311
- return new Promise((resolve25, reject2) => {
48407
+ return new Promise((resolve26, reject2) => {
48312
48408
  const timer11 = setTimeout(() => reject2(Object.assign(new Error("outbound timeout"), { name: "AbortError" })), ms);
48313
48409
  timer11.unref?.();
48314
48410
  p3.then((v) => {
48315
48411
  clearTimeout(timer11);
48316
- resolve25(v);
48412
+ resolve26(v);
48317
48413
  }, (e) => {
48318
48414
  clearTimeout(timer11);
48319
48415
  reject2(e);
@@ -48798,9 +48894,12 @@ var init_session_event_token = __esm({
48798
48894
  });
48799
48895
 
48800
48896
  // src/services/session-sandbox.ts
48897
+ function sessionSandboxOn(env = process.env) {
48898
+ return resolveHardening(env) || env.HANOMAN_SESSION_SANDBOX !== void 0 && env.HANOMAN_SESSION_SANDBOX !== "off";
48899
+ }
48801
48900
  function assertAntigravityLaunch(agent, goal, env = process.env) {
48802
48901
  if (agent !== "antigravity") return;
48803
- if (resolveHardening(env) || env.HANOMAN_SESSION_SANDBOX !== void 0 && env.HANOMAN_SESSION_SANDBOX !== "off")
48902
+ if (sessionSandboxOn(env))
48804
48903
  throw new RuntimeLaunchError(409, "antigravity-sandbox-unsupported", "Antigravity CLI hanya tersedia pada host/lab; sandbox belum didukung.");
48805
48904
  if (goal) throw new RuntimeLaunchError(409, "antigravity-goal-unsupported", "Antigravity CLI belum mendukung enforcement goal native.");
48806
48905
  }
@@ -49036,14 +49135,14 @@ function tmux(...args) {
49036
49135
  }
49037
49136
  }
49038
49137
  function tmuxAsync(...args) {
49039
- return new Promise((resolve25, reject2) => {
49138
+ return new Promise((resolve26, reject2) => {
49040
49139
  execFile2(
49041
49140
  "tmux",
49042
49141
  ["-L", socket(), "-f", "/dev/null", ...args],
49043
49142
  { encoding: "utf8", env: agentEnvironment(null, process.env) },
49044
49143
  (e, stdout, stderr) => {
49045
49144
  if (!e) {
49046
- resolve25(stdout);
49145
+ resolve26(stdout);
49047
49146
  return;
49048
49147
  }
49049
49148
  const err = e;
@@ -49108,7 +49207,8 @@ function parsePanes(out4) {
49108
49207
  doneAtBirth,
49109
49208
  paneWidth,
49110
49209
  paneHeight,
49111
- customName
49210
+ customName,
49211
+ accountRaw
49112
49212
  ] = line.split(" ");
49113
49213
  if (!n2?.startsWith(PREFIX)) return [];
49114
49214
  const exited = dead === "1";
@@ -49150,6 +49250,8 @@ function parsePanes(out4) {
49150
49250
  // SPEC-1218 · AC-C2 · kosong (tmux lama tanpa kolom ini) → undefined, bukan NaN.
49151
49251
  width: paneWidth ? Number(paneWidth) : void 0,
49152
49252
  height: paneHeight ? Number(paneHeight) : void 0,
49253
+ // ADR-0234 · sesi lama / akun bawaan tanpa opsi ini → undefined.
49254
+ accountId: accountRaw || void 0,
49153
49255
  name: customName?.trim() || void 0
49154
49256
  }];
49155
49257
  });
@@ -49193,6 +49295,12 @@ function registerSessionHooks(h2) {
49193
49295
  hooks.delete(h2);
49194
49296
  };
49195
49297
  }
49298
+ function registerAccountResolver(r) {
49299
+ accountResolver = r;
49300
+ return () => {
49301
+ if (accountResolver === r) accountResolver = () => null;
49302
+ };
49303
+ }
49196
49304
  function registerCustomAgentSource(fn) {
49197
49305
  customAgentSource = fn;
49198
49306
  }
@@ -49426,6 +49534,7 @@ function createSession(projectId, cwd, opts2 = {}) {
49426
49534
  promptArg = `"$(cat ${sq(promptFile)})"`;
49427
49535
  }
49428
49536
  const agent = opts2.agent ?? "claude";
49537
+ const account = opts2.command ? null : accountResolver(agent, opts2.accountId);
49429
49538
  let argv;
49430
49539
  if (opts2.command) {
49431
49540
  argv = opts2.command.map(sq).join(" ");
@@ -49492,10 +49601,13 @@ function createSession(projectId, cwd, opts2 = {}) {
49492
49601
  for (const [k, v] of Object.entries(agentEnvironment(runtime, opts2.env ?? {}))) {
49493
49602
  if (v !== void 0 && !(runtime === "antigravity" && ANTIGRAVITY_ENV_KEYS.some((key) => key === k))) envPairs.push(`${k}=${sq(v)}`);
49494
49603
  }
49604
+ for (const [k, v] of Object.entries(account?.env ?? {})) envPairs.push(`${k}=${sq(v)}`);
49495
49605
  const unsets = [
49496
49606
  ...runtime === "antigravity" ? [] : ANTIGRAVITY_ENV_KEYS,
49497
49607
  ...runtime === "antigravity" ? ["CLAUDE_CODE_OAUTH_TOKEN", "ANTHROPIC_API_KEY"] : [],
49498
- ...!opts2.command ? [...suppressedInheritKeys(), ...hanomanDbInheritUnsets()] : []
49608
+ ...!opts2.command ? [...suppressedInheritKeys(), ...hanomanDbInheritUnsets()] : [],
49609
+ // ADR-0234 · kredensial env yang mengalahkan login akun (CLAUDE_CODE_OAUTH_TOKEN dst).
49610
+ ...account?.unset ?? []
49499
49611
  ].flatMap((key) => ["-u", key]);
49500
49612
  let cmd = unsets.length ? ["env", ...unsets, ...envPairs, argv].join(" ") : envPairs.length ? `${envPairs.join(" ")} ${argv}` : argv;
49501
49613
  if (!opts2.command) {
@@ -49590,6 +49702,7 @@ function createSession(projectId, cwd, opts2 = {}) {
49590
49702
  if (opts2.flow) tmux("set-option", "-t", name(id2), "@hanoman_flow", opts2.flow);
49591
49703
  if (opts2.branch) tmux("set-option", "-t", name(id2), "@hanoman_branch", opts2.branch);
49592
49704
  tmux("set-option", "-t", name(id2), "@hanoman_agent", agent);
49705
+ if (account) tmux("set-option", "-t", name(id2), "@hanoman_account", account.id);
49593
49706
  const kind = sessionKind({ ...opts2, id: id2 }, projectId, cwd);
49594
49707
  tmux(
49595
49708
  "set-option",
@@ -49636,9 +49749,21 @@ function createSession(projectId, cwd, opts2 = {}) {
49636
49749
  model: opts2.model,
49637
49750
  effort: opts2.effort,
49638
49751
  branch: opts2.branch,
49639
- cwd
49752
+ cwd,
49753
+ accountId: account?.id
49640
49754
  });
49641
- return { id: id2, projectId, specId: opts2.specId, flow: opts2.flow, cwd, branch: opts2.branch, exited: false, decision: false, agent };
49755
+ return {
49756
+ id: id2,
49757
+ projectId,
49758
+ specId: opts2.specId,
49759
+ flow: opts2.flow,
49760
+ cwd,
49761
+ branch: opts2.branch,
49762
+ exited: false,
49763
+ decision: false,
49764
+ agent,
49765
+ ...account ? { accountId: account.id } : {}
49766
+ };
49642
49767
  }
49643
49768
  function capturePane(id2, lines2 = 200) {
49644
49769
  try {
@@ -49825,10 +49950,10 @@ function startPoll() {
49825
49950
  poll = setInterval(() => {
49826
49951
  if (polling) return;
49827
49952
  polling = true;
49828
- const snapshot3 = [...attached.entries()];
49953
+ const snapshot4 = [...attached.entries()];
49829
49954
  listPanesAsync().then(async (panes) => {
49830
49955
  const live = new Map(panes.map((p3) => [p3.id, p3]));
49831
- for (const [id2, a] of snapshot3) {
49956
+ for (const [id2, a] of snapshot4) {
49832
49957
  if (attached.get(id2) !== a) continue;
49833
49958
  const p3 = live.get(id2);
49834
49959
  if (!p3) end(id2, 0);
@@ -49933,8 +50058,8 @@ function detachAll() {
49933
50058
  for (const id2 of [...attached.keys()]) drop(id2);
49934
50059
  }
49935
50060
  function spawnPty(...args) {
49936
- const resolve25 = createRequire(import.meta.url).resolve;
49937
- const repair = () => ensureSpawnHelper(resolve25, (m) => process.stdout.write(m));
50061
+ const resolve26 = createRequire(import.meta.url).resolve;
50062
+ const repair = () => ensureSpawnHelper(resolve26, (m) => process.stdout.write(m));
49938
50063
  try {
49939
50064
  return spawnWithHelperRecovery(() => spawn("tmux", ["-L", socket(), "-f", "/dev/null", ...args], {
49940
50065
  name: "xterm-256color",
@@ -49950,7 +50075,7 @@ function spawnPty(...args) {
49950
50075
  );
49951
50076
  }
49952
50077
  }
49953
- var socket, PREFIX, MAX_SCROLLBACK, SCROLLBACK_SLACK, POLL_MS, markerFilled, markerFilledAsync, clearMarker, PANE_QUIET_MS, paneQuiet, MARKER_STALE_SLACK_S, markerOnset, markerCurrent, decisionOnset, attached, phaseInvocations, PHASE_DONE_SEEN_OPT, phaseDoneSeen, claudeBin, shellBin, codexBin, agentBin, rootBypassEnv, frame, name, promptFilePath, goalGatePath, goalStatePath, agentTempDir, agentsFilePath, phaseContextFilePath, AGENTS_ARG_SAFE_BYTES, agentContractFilePath, askpassDenyPath, ASKPASS_DENY, SUBAGENT_CONCURRENCY_CAP, NO_SERVER, TmuxError, sq, idFor, FMT, toSessionInfo, listSessions, listSessionsAsync, decisionsOf, getSession, getSessionAsync, hooks, emitBirth, emitDeath, customAgentSource, codexNativeAgentSupport, nativeAgentsAvailable, customAgentsFor, runGitDiff, sleep, paneText, paneIO, DIALOG_CAPTURE_LINES, GOAL_ARMED_MARKERS, goalArmed, COALESCE_MS, COALESCE_MAX_BYTES, trimScrollback, phaseKey, sessionFinishedAsync, poll, polling, TERMINAL_QUERY, stripTerminalQueries, CAPTURE_ARGS, detach;
50078
+ var socket, PREFIX, MAX_SCROLLBACK, SCROLLBACK_SLACK, POLL_MS, markerFilled, markerFilledAsync, clearMarker, PANE_QUIET_MS, paneQuiet, MARKER_STALE_SLACK_S, markerOnset, markerCurrent, decisionOnset, attached, phaseInvocations, PHASE_DONE_SEEN_OPT, phaseDoneSeen, claudeBin, shellBin, codexBin, agentBin, rootBypassEnv, frame, name, promptFilePath, goalGatePath, goalStatePath, agentTempDir, agentsFilePath, phaseContextFilePath, AGENTS_ARG_SAFE_BYTES, agentContractFilePath, askpassDenyPath, ASKPASS_DENY, SUBAGENT_CONCURRENCY_CAP, NO_SERVER, TmuxError, sq, idFor, FMT, toSessionInfo, listSessions, listSessionsAsync, decisionsOf, getSession, getSessionAsync, hooks, accountResolver, emitBirth, emitDeath, customAgentSource, codexNativeAgentSupport, nativeAgentsAvailable, customAgentsFor, runGitDiff, sleep, paneText, paneIO, DIALOG_CAPTURE_LINES, GOAL_ARMED_MARKERS, goalArmed, COALESCE_MS, COALESCE_MAX_BYTES, trimScrollback, phaseKey, sessionFinishedAsync, poll, polling, TERMINAL_QUERY, stripTerminalQueries, CAPTURE_ARGS, detach;
49954
50079
  var init_pty = __esm({
49955
50080
  "src/services/pty.ts"() {
49956
50081
  "use strict";
@@ -50087,7 +50212,9 @@ exit 1
50087
50212
  "#{pane_width}",
50088
50213
  "#{pane_height}",
50089
50214
  // Nama kustom sesi (rename dari UI/MCP) — di UJUNG juga. Opsi tmux, jadi selamat dari restart API.
50090
- "#{@hanoman_name}"
50215
+ "#{@hanoman_name}",
50216
+ // ADR-0234 · akun runtime sesi (`RuntimeAccount.id` / `default:<runtime>`) — di UJUNG juga.
50217
+ "#{@hanoman_account}"
50091
50218
  ].join(" ");
50092
50219
  toSessionInfo = ({
50093
50220
  id: id2,
@@ -50105,7 +50232,8 @@ exit 1
50105
50232
  model,
50106
50233
  effort: effort2,
50107
50234
  orchestrated,
50108
- name: name2
50235
+ name: name2,
50236
+ accountId
50109
50237
  }) => ({
50110
50238
  id: id2,
50111
50239
  projectId,
@@ -50123,7 +50251,8 @@ exit 1
50123
50251
  ...model ? { model } : {},
50124
50252
  ...effort2 ? { effort: effort2 } : {},
50125
50253
  ...orchestrated ? { orchestrated: true } : {},
50126
- ...name2 ? { name: name2 } : {}
50254
+ ...name2 ? { name: name2 } : {},
50255
+ ...accountId ? { accountId } : {}
50127
50256
  });
50128
50257
  listSessions = () => listPanes().map(toSessionInfo);
50129
50258
  listSessionsAsync = async () => (await listPanesAsync()).map(toSessionInfo);
@@ -50140,6 +50269,7 @@ exit 1
50140
50269
  getSession = (id2) => listPanes().find((p3) => p3.id === id2);
50141
50270
  getSessionAsync = async (id2) => (await listPanesAsync()).find((p3) => p3.id === id2);
50142
50271
  hooks = /* @__PURE__ */ new Set();
50272
+ accountResolver = () => null;
50143
50273
  emitBirth = (b) => {
50144
50274
  for (const h2 of hooks) {
50145
50275
  try {
@@ -50502,8 +50632,8 @@ function createLaunchGate(deps) {
50502
50632
  async run(opts2, start, reuse) {
50503
50633
  const previous = tail2;
50504
50634
  let release;
50505
- tail2 = new Promise((resolve25) => {
50506
- release = resolve25;
50635
+ tail2 = new Promise((resolve26) => {
50636
+ release = resolve26;
50507
50637
  });
50508
50638
  await previous;
50509
50639
  try {
@@ -50672,6 +50802,8 @@ var init_settings3 = __esm({
50672
50802
  // SPEC-1215 · ADR-0166
50673
50803
  logRetention: LOG_RETENTION_DEFAULTS,
50674
50804
  // SPEC-1215 · ADR-0166
50805
+ accounts: {},
50806
+ // ADR-0234 · default akun runtime (absen = akun bawaan)
50675
50807
  builtinAgents: {},
50676
50808
  // SPEC-881 · ADR-0136 · sidik jari seed (lokal, tak disync)
50677
50809
  builtinAgentPolicies: {},
@@ -53625,7 +53757,7 @@ function readByobReaderWithSignal(reader, buffer, signal) {
53625
53757
  return reader.read(buffer);
53626
53758
  }
53627
53759
  signal.throwIfAborted();
53628
- return new Promise((resolve25, reject2) => {
53760
+ return new Promise((resolve26, reject2) => {
53629
53761
  const cleanup = () => {
53630
53762
  signal.removeEventListener("abort", onAbort);
53631
53763
  };
@@ -53645,7 +53777,7 @@ function readByobReaderWithSignal(reader, buffer, signal) {
53645
53777
  try {
53646
53778
  const result = await reader.read(buffer);
53647
53779
  cleanup();
53648
- resolve25(result);
53780
+ resolve26(result);
53649
53781
  } catch (error) {
53650
53782
  cleanup();
53651
53783
  reject2(error);
@@ -55881,9 +56013,9 @@ async function pull(sinceCursor, limit = 500, maxBytes = PULL_MAX_BYTES, opts2 =
55881
56013
  async function bootstrapSnapshot(after, maxBytes = PULL_MAX_BYTES, opts2 = {}) {
55882
56014
  const tip = await prisma.syncLog.findFirst({ orderBy: { seq: "desc" }, select: { seq: true } });
55883
56015
  const cursor = tip ? String(tip.seq) : "0";
55884
- const sep11 = after ? after.indexOf(":") : -1;
55885
- const afterEntity = sep11 > 0 ? after.slice(0, sep11) : null;
55886
- const afterId = sep11 > 0 ? after.slice(sep11 + 1) : null;
56016
+ const sep12 = after ? after.indexOf(":") : -1;
56017
+ const afterEntity = sep12 > 0 ? after.slice(0, sep12) : null;
56018
+ const afterId = sep12 > 0 ? after.slice(sep12 + 1) : null;
55887
56019
  const startAt = afterEntity ? BOOTSTRAP_ORDER.indexOf(afterEntity) : 0;
55888
56020
  if (startAt < 0) throw new Error("bootstrap cursor tak dikenal");
55889
56021
  const records = [];
@@ -57939,13 +58071,13 @@ function requestRelay(deviceId, r, opts2 = {}) {
57939
58071
  if (r.body !== void 0 && utf8Bytes(JSON.stringify(r.body)) > RELAY_REQUEST_BODY_MAX_BYTES)
57940
58072
  return Promise.reject(new RelayError("too-large"));
57941
58073
  const id2 = `r${++counter}`;
57942
- return new Promise((resolve25, reject2) => {
58074
+ return new Promise((resolve26, reject2) => {
57943
58075
  const timer11 = setTimeout(() => {
57944
58076
  sendCancel(link2, id2);
57945
58077
  settle(link2, id2, new RelayError("timeout"));
57946
58078
  }, opts2.timeoutMs ?? RELAY_REQ_TIMEOUT_MS);
57947
58079
  timer11.unref?.();
57948
- link2.pending.set(id2, { resolve: resolve25, reject: reject2, timer: timer11, contentType: null, chunks: [], bytes: 0 });
58080
+ link2.pending.set(id2, { resolve: resolve26, reject: reject2, timer: timer11, contentType: null, chunks: [], bytes: 0 });
57949
58081
  try {
57950
58082
  link2.socket.send(JSON.stringify({
57951
58083
  t: "req",
@@ -58908,15 +59040,15 @@ async function openEvent(i) {
58908
59040
  return e;
58909
59041
  }
58910
59042
  function awaitEvent(id2, timeoutMs) {
58911
- return new Promise((resolve25) => {
59043
+ return new Promise((resolve26) => {
58912
59044
  const timer11 = setTimeout(() => {
58913
59045
  waiters.delete(id2);
58914
- void closeEvent(id2, "late").catch(() => false).finally(() => resolve25({ status: "late" }));
59046
+ void closeEvent(id2, "late").catch(() => false).finally(() => resolve26({ status: "late" }));
58915
59047
  }, timeoutMs);
58916
59048
  waiters.set(id2, (o) => {
58917
59049
  clearTimeout(timer11);
58918
59050
  waiters.delete(id2);
58919
- resolve25(o);
59051
+ resolve26(o);
58920
59052
  });
58921
59053
  });
58922
59054
  }
@@ -59062,16 +59194,15 @@ var init_project_config = __esm({
59062
59194
  }
59063
59195
  });
59064
59196
 
59065
- // src/services/limits.ts
59197
+ // src/services/runtime-accounts/keychain.ts
59198
+ import { createHash as createHash14 } from "node:crypto";
59066
59199
  import { execFileSync as execFileSync6 } from "node:child_process";
59067
- import { readFileSync as readFileSync18 } from "node:fs";
59068
- import { homedir as homedir6, userInfo } from "node:os";
59069
- import { join as join34 } from "node:path";
59070
- function credsFile() {
59071
- return join34(effectiveStr("CLAUDE_CONFIG_DIR") ?? join34(homedir6(), ".claude"), ".credentials.json");
59200
+ import { userInfo } from "node:os";
59201
+ function claudeKeychainService(configDir) {
59202
+ return `Claude Code-credentials-${createHash14("sha256").update(configDir).digest("hex").slice(0, 8)}`;
59072
59203
  }
59073
- function keychainAccessToken(run6 = securityRun, account = osAccount()) {
59074
- const base3 = ["find-generic-password", "-s", "Claude Code-credentials"];
59204
+ function readClaudeKeychainToken(service, run6 = securityRun, account = osAccount()) {
59205
+ const base3 = ["find-generic-password", "-s", service];
59075
59206
  for (const scope of account ? [["-a", account], []] : [[]]) {
59076
59207
  try {
59077
59208
  const tok = JSON.parse(run6([...base3, ...scope, "-w"]))?.claudeAiOauth?.accessToken;
@@ -59081,6 +59212,45 @@ function keychainAccessToken(run6 = securityRun, account = osAccount()) {
59081
59212
  }
59082
59213
  return null;
59083
59214
  }
59215
+ function deleteClaudeKeychainEntry(service, run6 = securityRun) {
59216
+ for (let i = 0; i < 4; i++) {
59217
+ try {
59218
+ run6(["delete-generic-password", "-s", service]);
59219
+ } catch {
59220
+ return;
59221
+ }
59222
+ }
59223
+ }
59224
+ var securityRun, osAccount;
59225
+ var init_keychain = __esm({
59226
+ "src/services/runtime-accounts/keychain.ts"() {
59227
+ "use strict";
59228
+ securityRun = (args, input) => execFileSync6("security", args, {
59229
+ encoding: "utf8",
59230
+ input,
59231
+ stdio: [input === void 0 ? "ignore" : "pipe", "pipe", "ignore"]
59232
+ });
59233
+ osAccount = () => {
59234
+ try {
59235
+ return userInfo().username || null;
59236
+ } catch {
59237
+ return null;
59238
+ }
59239
+ };
59240
+ }
59241
+ });
59242
+
59243
+ // src/services/limits.ts
59244
+ import { execFileSync as execFileSync7 } from "node:child_process";
59245
+ import { readFileSync as readFileSync18 } from "node:fs";
59246
+ import { homedir as homedir6, userInfo as userInfo2 } from "node:os";
59247
+ import { join as join34 } from "node:path";
59248
+ function credsFile() {
59249
+ return join34(effectiveStr("CLAUDE_CONFIG_DIR") ?? join34(homedir6(), ".claude"), ".credentials.json");
59250
+ }
59251
+ function keychainAccessToken(run6 = securityRun2, account = osAccount2()) {
59252
+ return readClaudeKeychainToken("Claude Code-credentials", run6, account);
59253
+ }
59084
59254
  function readAccessToken() {
59085
59255
  if (process.platform === "darwin" && !effectiveStr("CLAUDE_CONFIG_DIR")) {
59086
59256
  const tok = keychainAccessToken();
@@ -59114,38 +59284,43 @@ function mapWindows(json) {
59114
59284
  };
59115
59285
  });
59116
59286
  }
59117
- function fallback() {
59118
- return lastOk ? { ...lastOk, status: "stale" } : { status: "unavailable", windows: [], fetchedAt: null };
59119
- }
59120
- async function fetchUsage() {
59121
- const token = readAccessToken();
59122
- if (!token) return fallback();
59287
+ async function fetchClaudeWindows(token, fetchImpl = fetch) {
59123
59288
  try {
59124
- const res = await fetch(USAGE_URL, {
59289
+ const res = await fetchImpl(USAGE_URL, {
59125
59290
  headers: { authorization: `Bearer ${token}`, "anthropic-beta": "oauth-2025-04-20" },
59126
- // SPEC-197 · tanpa timeout, endpoint yang menggantung menahan request ~300s dan poll 60s
59127
- // menumpuk koneksi. AbortError ditangkap catch di bawah → fallback (stale/unavailable).
59291
+ // SPEC-197 · tanpa timeout, endpoint yang menggantung menahan request ~300s dan poll menumpuk koneksi.
59128
59292
  signal: AbortSignal.timeout(5e3)
59129
59293
  });
59130
- if (!res.ok) return fallback();
59131
- const dto = { status: "ok", windows: mapWindows(await res.json()), fetchedAt: nowIso() };
59132
- lastOk = dto;
59133
- return dto;
59294
+ if (!res.ok) return null;
59295
+ return mapWindows(await res.json());
59134
59296
  } catch {
59135
- return fallback();
59297
+ return null;
59136
59298
  }
59137
59299
  }
59300
+ function fallback() {
59301
+ return lastOk ? { ...lastOk, status: "stale" } : { status: "unavailable", windows: [], fetchedAt: null };
59302
+ }
59303
+ async function fetchUsage() {
59304
+ const token = readAccessToken();
59305
+ if (!token) return fallback();
59306
+ const windows = await fetchClaudeWindows(token);
59307
+ if (!windows) return fallback();
59308
+ const dto = { status: "ok", windows, fetchedAt: nowIso() };
59309
+ lastOk = dto;
59310
+ return dto;
59311
+ }
59138
59312
  async function getLimits() {
59139
59313
  if (lastOk && Date.now() < freshUntil) return lastOk;
59140
59314
  const dto = await fetchUsage();
59141
59315
  if (dto.status === "ok") freshUntil = Date.now() + TTL_MS2;
59142
59316
  return dto;
59143
59317
  }
59144
- var USAGE_URL, TTL_MS2, lastOk, freshUntil, LABELS, humanize, nowIso, securityRun, osAccount;
59318
+ var USAGE_URL, TTL_MS2, lastOk, freshUntil, LABELS, humanize, nowIso, securityRun2, osAccount2;
59145
59319
  var init_limits = __esm({
59146
59320
  "src/services/limits.ts"() {
59147
59321
  "use strict";
59148
59322
  init_config2();
59323
+ init_keychain();
59149
59324
  USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
59150
59325
  TTL_MS2 = 3e4;
59151
59326
  lastOk = null;
@@ -59157,10 +59332,10 @@ var init_limits = __esm({
59157
59332
  };
59158
59333
  humanize = (k) => k.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
59159
59334
  nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
59160
- securityRun = (args) => execFileSync6("security", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
59161
- osAccount = () => {
59335
+ securityRun2 = (args) => execFileSync7("security", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
59336
+ osAccount2 = () => {
59162
59337
  try {
59163
- return userInfo().username || null;
59338
+ return userInfo2().username || null;
59164
59339
  } catch {
59165
59340
  return null;
59166
59341
  }
@@ -59289,16 +59464,16 @@ var init_codex_limits = __esm({
59289
59464
  });
59290
59465
 
59291
59466
  // src/services/antigravity-limits.ts
59292
- import { execFileSync as execFileSync7 } from "node:child_process";
59467
+ import { execFileSync as execFileSync8 } from "node:child_process";
59293
59468
  import { readFileSync as readFileSync19 } from "node:fs";
59294
59469
  import { homedir as homedir8 } from "node:os";
59295
59470
  import { join as join36 } from "node:path";
59296
- function readAgyToken(run6 = securityRun2) {
59471
+ function parseAgyToken(raw) {
59297
59472
  try {
59298
- let raw = run6(["find-generic-password", "-s", "gemini", "-a", "antigravity", "-w"]).trim();
59473
+ let s2 = raw.trim();
59299
59474
  const prefix = "go-keyring-base64:";
59300
- if (raw.startsWith(prefix)) raw = Buffer.from(raw.slice(prefix.length), "base64").toString("utf8");
59301
- const tok = JSON.parse(raw)?.token;
59475
+ if (s2.startsWith(prefix)) s2 = Buffer.from(s2.slice(prefix.length), "base64").toString("utf8");
59476
+ const tok = JSON.parse(s2)?.token;
59302
59477
  if (typeof tok?.access_token !== "string" || !tok.access_token) return null;
59303
59478
  const expiry = typeof tok.expiry === "string" ? Date.parse(tok.expiry) : NaN;
59304
59479
  return { accessToken: tok.access_token, expiry: Number.isFinite(expiry) ? expiry : null };
@@ -59306,6 +59481,13 @@ function readAgyToken(run6 = securityRun2) {
59306
59481
  return null;
59307
59482
  }
59308
59483
  }
59484
+ function readAgyToken(run6 = securityRun3) {
59485
+ try {
59486
+ return parseAgyToken(run6(["find-generic-password", "-s", "gemini", "-a", "antigravity", "-w"]));
59487
+ } catch {
59488
+ return null;
59489
+ }
59490
+ }
59309
59491
  function defaultProject() {
59310
59492
  try {
59311
59493
  return readFileSync19(join36(agyHome(), "cache", "default_project_id.txt"), "utf8").trim() || null;
@@ -59348,14 +59530,9 @@ function mapQuota(json) {
59348
59530
  function fallback2() {
59349
59531
  return lastOk2 ? { ...lastOk2, status: "stale" } : UNAVAILABLE2;
59350
59532
  }
59351
- async function fetchQuota(deps) {
59352
- if (deps.platform !== "darwin") return fallback2();
59353
- const tok = deps.token();
59354
- if (!tok) return fallback2();
59355
- if (tok.expiry !== null && tok.expiry - EXPIRY_SKEW_MS <= deps.now()) return fallback2();
59356
- const project = deps.project();
59533
+ async function fetchAgyWindows(tok, project, f) {
59357
59534
  try {
59358
- const res = await deps.fetch(QUOTA_URL, {
59535
+ const res = await f(QUOTA_URL, {
59359
59536
  method: "POST",
59360
59537
  headers: {
59361
59538
  authorization: `Bearer ${tok.accessToken}`,
@@ -59366,27 +59543,31 @@ async function fetchQuota(deps) {
59366
59543
  // Endpoint yang menggantung tak boleh menumpuk koneksi di bawah siar 30 dtk (SPEC-197).
59367
59544
  signal: AbortSignal.timeout(5e3)
59368
59545
  });
59369
- if (!res.ok) return fallback2();
59546
+ if (!res.ok) return null;
59370
59547
  const windows = mapQuota(await res.json());
59371
- if (!windows.length) return fallback2();
59372
- const dto = {
59373
- status: "ok",
59374
- windows,
59375
- fetchedAt: new Date(deps.now()).toISOString()
59376
- };
59377
- lastOk2 = dto;
59378
- return dto;
59548
+ return windows.length ? windows : null;
59379
59549
  } catch {
59380
- return fallback2();
59550
+ return null;
59381
59551
  }
59382
59552
  }
59553
+ async function fetchQuota(deps) {
59554
+ if (deps.platform !== "darwin") return fallback2();
59555
+ const tok = deps.token();
59556
+ if (!tok) return fallback2();
59557
+ if (tok.expiry !== null && tok.expiry - EXPIRY_SKEW_MS <= deps.now()) return fallback2();
59558
+ const windows = await fetchAgyWindows(tok, deps.project(), deps.fetch);
59559
+ if (!windows) return fallback2();
59560
+ const dto = { status: "ok", windows, fetchedAt: new Date(deps.now()).toISOString() };
59561
+ lastOk2 = dto;
59562
+ return dto;
59563
+ }
59383
59564
  async function getAntigravityLimits(deps = prodDeps) {
59384
59565
  if (lastOk2 && deps.now() < freshUntil3) return lastOk2;
59385
59566
  const dto = await fetchQuota(deps);
59386
59567
  if (dto.status === "ok") freshUntil3 = deps.now() + TTL_MS4;
59387
59568
  return dto;
59388
59569
  }
59389
- var QUOTA_URL, USER_AGENT, TTL_MS4, EXPIRY_SKEW_MS, lastOk2, freshUntil3, UNAVAILABLE2, securityRun2, agyHome, severityOf2, prodDeps;
59570
+ var QUOTA_URL, USER_AGENT, TTL_MS4, EXPIRY_SKEW_MS, lastOk2, freshUntil3, UNAVAILABLE2, securityRun3, agyHome, severityOf2, prodDeps;
59390
59571
  var init_antigravity_limits = __esm({
59391
59572
  "src/services/antigravity-limits.ts"() {
59392
59573
  "use strict";
@@ -59398,7 +59579,7 @@ var init_antigravity_limits = __esm({
59398
59579
  lastOk2 = null;
59399
59580
  freshUntil3 = 0;
59400
59581
  UNAVAILABLE2 = { status: "unavailable", windows: [], fetchedAt: null };
59401
- securityRun2 = (args) => execFileSync7("security", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
59582
+ securityRun3 = (args) => execFileSync8("security", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
59402
59583
  agyHome = () => join36(homedir8(), ".gemini", "antigravity-cli");
59403
59584
  severityOf2 = (pct3) => pct3 >= 90 ? "critical" : pct3 >= 70 ? "warning" : "normal";
59404
59585
  prodDeps = {
@@ -59498,7 +59679,7 @@ var init_budget = __esm({
59498
59679
  });
59499
59680
 
59500
59681
  // src/services/session-dialog.ts
59501
- import { createHash as createHash14 } from "node:crypto";
59682
+ import { createHash as createHash15 } from "node:crypto";
59502
59683
  function readSessionDialog(io) {
59503
59684
  const text2 = io.capture();
59504
59685
  const s2 = answerable(text2);
@@ -59554,7 +59735,7 @@ var init_session_dialog2 = __esm({
59554
59735
  init_tui_dialog();
59555
59736
  init_pty();
59556
59737
  DIALOG_CHUNK_MS = 50;
59557
- screenHashOf = (paneText2) => createHash14("sha256").update(dialogKey(paneText2)).digest("hex").slice(0, 16);
59738
+ screenHashOf = (paneText2) => createHash15("sha256").update(dialogKey(paneText2)).digest("hex").slice(0, 16);
59558
59739
  answerable = (paneText2) => {
59559
59740
  const s2 = readDialogScreen(paneText2);
59560
59741
  if (s2?.kind !== "question") return null;
@@ -61451,6 +61632,11 @@ function capabilityForRoute(method, path) {
61451
61632
  if (top === "webhooks") return rw("webhooks");
61452
61633
  if (top === "client-accounts") return rw("clients");
61453
61634
  if (top === "portal") return read2 ? "portal:read" : "COOKIE_ONLY";
61635
+ if (top === "runtime-accounts") {
61636
+ if (read2 && seg.length === 1) return "settings:read";
61637
+ if (method === "PUT" && seg.length === 2 && seg[1] === "default") return "settings:write";
61638
+ return "COOKIE_ONLY";
61639
+ }
61454
61640
  if (top === "settings" || top === "config") return rw("settings");
61455
61641
  if (top === "specs") {
61456
61642
  if (method === "DELETE" && seg.length === 3 && seg[2] === "worktree") return "ide:git";
@@ -61651,7 +61837,7 @@ function createRelayDispatcher(o) {
61651
61837
  send(i === 0 ? { t: "res", id: id2, status: status2, contentType, part, end: end2 } : { t: "res", id: id2, part, end: end2 });
61652
61838
  });
61653
61839
  };
61654
- const fail4 = (id2, status2, error) => reply(id2, status2, JSON_TYPE, JSON.stringify({ error }));
61840
+ const fail5 = (id2, status2, error) => reply(id2, status2, JSON_TYPE, JSON.stringify({ error }));
61655
61841
  async function handleReq(f) {
61656
61842
  const started2 = now();
61657
61843
  const record2 = (status2, extra = {}) => audit({
@@ -61662,19 +61848,19 @@ function createRelayDispatcher(o) {
61662
61848
  });
61663
61849
  if (inflight4.has(f.id)) return;
61664
61850
  if (inflight4.size >= RELAY_MAX_INFLIGHT) {
61665
- fail4(f.id, 429, "relay-busy");
61851
+ fail5(f.id, 429, "relay-busy");
61666
61852
  record2(429);
61667
61853
  return;
61668
61854
  }
61669
61855
  const payload = f.body === void 0 ? void 0 : JSON.stringify(f.body);
61670
61856
  if (payload !== void 0 && utf8Bytes(payload) > RELAY_REQUEST_BODY_MAX_BYTES) {
61671
- fail4(f.id, 413, "relay-body-too-large");
61857
+ fail5(f.id, 413, "relay-body-too-large");
61672
61858
  record2(413);
61673
61859
  return;
61674
61860
  }
61675
61861
  const url2 = f.query ? `${f.path}?${f.query.replace(/^\?/, "")}` : f.path;
61676
61862
  if (!relayRouteAllowed(f.method, url2) || !relayBodyAllowed(f.method, f.path, f.body)) {
61677
- fail4(f.id, 403, "relay route not allowed");
61863
+ fail5(f.id, 403, "relay route not allowed");
61678
61864
  record2(403);
61679
61865
  return;
61680
61866
  }
@@ -61722,13 +61908,13 @@ function createRelayDispatcher(o) {
61722
61908
  });
61723
61909
  if (entry2.cancelled) return;
61724
61910
  if (utf8Bytes(res.body) > RELAY_RESPONSE_MAX_BYTES) {
61725
- fail4(f.id, 502, "relay-response-too-large");
61911
+ fail5(f.id, 502, "relay-response-too-large");
61726
61912
  return;
61727
61913
  }
61728
61914
  reply(f.id, res.statusCode, String(res.headers["content-type"] ?? "application/octet-stream"), res.body);
61729
61915
  } catch {
61730
61916
  record2(502);
61731
- if (!entry2.cancelled) fail4(f.id, 502, "relay-dispatch-failed");
61917
+ if (!entry2.cancelled) fail5(f.id, 502, "relay-dispatch-failed");
61732
61918
  } finally {
61733
61919
  inflight4.delete(f.id);
61734
61920
  }
@@ -64097,7 +64283,7 @@ var require_websocket2 = __commonJS({
64097
64283
  var http = __require("http");
64098
64284
  var net = __require("net");
64099
64285
  var tls = __require("tls");
64100
- var { randomBytes: randomBytes12, createHash: createHash24 } = __require("crypto");
64286
+ var { randomBytes: randomBytes12, createHash: createHash25 } = __require("crypto");
64101
64287
  var { Duplex, Readable } = __require("stream");
64102
64288
  var { URL: URL2 } = __require("url");
64103
64289
  var PerMessageDeflate2 = require_permessage_deflate2();
@@ -64765,7 +64951,7 @@ var require_websocket2 = __commonJS({
64765
64951
  abortHandshake(websocket2, socket2, "Invalid Upgrade header");
64766
64952
  return;
64767
64953
  }
64768
- const digest3 = createHash24("sha1").update(key + GUID).digest("base64");
64954
+ const digest3 = createHash25("sha1").update(key + GUID).digest("base64");
64769
64955
  if (res.headers["sec-websocket-accept"] !== digest3) {
64770
64956
  abortHandshake(websocket2, socket2, "Invalid Sec-WebSocket-Accept header");
64771
64957
  return;
@@ -65134,7 +65320,7 @@ var require_websocket_server = __commonJS({
65134
65320
  var EventEmitter = __require("events");
65135
65321
  var http = __require("http");
65136
65322
  var { Duplex } = __require("stream");
65137
- var { createHash: createHash24 } = __require("crypto");
65323
+ var { createHash: createHash25 } = __require("crypto");
65138
65324
  var extension2 = require_extension();
65139
65325
  var PerMessageDeflate2 = require_permessage_deflate2();
65140
65326
  var subprotocol2 = require_subprotocol();
@@ -65441,7 +65627,7 @@ var require_websocket_server = __commonJS({
65441
65627
  );
65442
65628
  }
65443
65629
  if (this._state > RUNNING) return abortHandshake(socket2, 503);
65444
- const digest3 = createHash24("sha1").update(key + GUID).digest("base64");
65630
+ const digest3 = createHash25("sha1").update(key + GUID).digest("base64");
65445
65631
  const headers = [
65446
65632
  "HTTP/1.1 101 Switching Protocols",
65447
65633
  "Upgrade: websocket",
@@ -66716,6 +66902,7 @@ async function startSpecSession(spec, opts2) {
66716
66902
  goal,
66717
66903
  agent,
66718
66904
  askVia,
66905
+ accountId: opts2.accountId,
66719
66906
  phaseFile: phaseFilePath(repoDir, id2),
66720
66907
  decisionFile: decisionFilePath(repoDir, id2),
66721
66908
  attachmentsDir: attachments.items.length ? attachments.dir : void 0,
@@ -66772,7 +66959,7 @@ var init_session_launch = __esm({
66772
66959
  import { spawn as spawn4 } from "node:child_process";
66773
66960
  function runVerify(cwd, command, timeoutMs) {
66774
66961
  const env = Object.fromEntries(Object.entries(process.env).filter(([k]) => !STRIP.test(k)));
66775
- return new Promise((resolve25) => {
66962
+ return new Promise((resolve26) => {
66776
66963
  const child = spawn4("sh", ["-c", command], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
66777
66964
  let out4 = "";
66778
66965
  const keep = (b) => {
@@ -66785,12 +66972,12 @@ function runVerify(cwd, command, timeoutMs) {
66785
66972
  }, timeoutMs);
66786
66973
  child.on("close", (code, signal) => {
66787
66974
  clearTimeout(timer11);
66788
- resolve25({ ok: code === 0 && !signal, code, tail: signal ? `${out4}
66975
+ resolve26({ ok: code === 0 && !signal, code, tail: signal ? `${out4}
66789
66976
  [dihentikan: ${signal}]` : out4 });
66790
66977
  });
66791
66978
  child.on("error", (e) => {
66792
66979
  clearTimeout(timer11);
66793
- resolve25({ ok: false, code: null, tail: e.message });
66980
+ resolve26({ ok: false, code: null, tail: e.message });
66794
66981
  });
66795
66982
  });
66796
66983
  }
@@ -67298,7 +67485,7 @@ var init_approvals = __esm({
67298
67485
  });
67299
67486
 
67300
67487
  // src/services/telegram/gateway.ts
67301
- import { createHash as createHash15 } from "node:crypto";
67488
+ import { createHash as createHash16 } from "node:crypto";
67302
67489
  var digestRaw, TelegramGateway;
67303
67490
  var init_gateway = __esm({
67304
67491
  "src/services/telegram/gateway.ts"() {
@@ -67307,7 +67494,7 @@ var init_gateway = __esm({
67307
67494
  init_protocol();
67308
67495
  init_runtime();
67309
67496
  init_typing();
67310
- digestRaw = (update2) => createHash15("sha256").update(JSON.stringify(update2)).digest("hex");
67497
+ digestRaw = (update2) => createHash16("sha256").update(JSON.stringify(update2)).digest("hex");
67311
67498
  TelegramGateway = class {
67312
67499
  constructor(deps) {
67313
67500
  this.deps = deps;
@@ -67508,7 +67695,7 @@ var init_gateway = __esm({
67508
67695
  const message = sanitizeTelegramOutput(error.message, this.deps.exactSecrets).slice(0, 500);
67509
67696
  updateTelegramRuntimeStatus({ running: false, readiness: "error", lastError: message });
67510
67697
  if (error instanceof TelegramApiError && error.code === 409) return;
67511
- await new Promise((resolve25) => setTimeout(resolve25, 1e3));
67698
+ await new Promise((resolve26) => setTimeout(resolve26, 1e3));
67512
67699
  }
67513
67700
  }
67514
67701
  }
@@ -67631,14 +67818,14 @@ var init_engine_command = __esm({
67631
67818
  });
67632
67819
 
67633
67820
  // src/services/telegram/session.ts
67634
- import { createHash as createHash16 } from "node:crypto";
67821
+ import { createHash as createHash17 } from "node:crypto";
67635
67822
  var chatHash, telegramOperatorSessionId, formatTelegramTurn, TelegramSessionCoordinator;
67636
67823
  var init_session = __esm({
67637
67824
  "src/services/telegram/session.ts"() {
67638
67825
  "use strict";
67639
67826
  init_src2();
67640
67827
  init_engine_command();
67641
- chatHash = (chatId) => createHash16("sha256").update(chatId).digest("hex").slice(0, 16);
67828
+ chatHash = (chatId) => createHash17("sha256").update(chatId).digest("hex").slice(0, 16);
67642
67829
  telegramOperatorSessionId = (chatId) => `telegram-${chatHash(chatId)}`;
67643
67830
  formatTelegramTurn = (input) => `[Telegram update ${input.updateId} \xB7 chat ${input.chatId} \xB7 kind ${input.kind}]
67644
67831
  ${input.text}`;
@@ -68231,7 +68418,7 @@ var init_bootstrap = __esm({
68231
68418
  });
68232
68419
 
68233
68420
  // src/services/codex-version.ts
68234
- import { execFile as execFile17 } from "node:child_process";
68421
+ import { execFile as execFile18 } from "node:child_process";
68235
68422
  import { promisify as promisify17 } from "node:util";
68236
68423
  async function probeCodexVersion(env = process.env, execute = runVersion) {
68237
68424
  const probe = codexNativeVersionProbe(env, codexBin2());
@@ -68246,9 +68433,9 @@ function parseCodexVersion(out4) {
68246
68433
  return m ? `${m[1]}.${m[2]}.${m[3]}` : null;
68247
68434
  }
68248
68435
  async function getCodexVersion(now = Date.now()) {
68249
- if (cache3 && now - cache3.at < TTL_MS5) return cache3.version;
68436
+ if (cache4 && now - cache4.at < TTL_MS6) return cache4.version;
68250
68437
  const version = await probeCodexVersion();
68251
- cache3 = { at: now, version };
68438
+ cache4 = { at: now, version };
68252
68439
  return version;
68253
68440
  }
68254
68441
  async function codexVersionInfo() {
@@ -68260,19 +68447,19 @@ async function codexVersionInfo() {
68260
68447
  };
68261
68448
  }
68262
68449
  function _resetCodexVersionCache() {
68263
- cache3 = null;
68450
+ cache4 = null;
68264
68451
  }
68265
- var run3, CODEX_MIN_CLIENT, TTL_MS5, cache3, codexBin2, runVersion;
68452
+ var run3, CODEX_MIN_CLIENT, TTL_MS6, cache4, codexBin2, runVersion;
68266
68453
  var init_codex_version = __esm({
68267
68454
  "src/services/codex-version.ts"() {
68268
68455
  "use strict";
68269
68456
  init_src();
68270
68457
  init_src2();
68271
68458
  init_config2();
68272
- run3 = promisify17(execFile17);
68459
+ run3 = promisify17(execFile18);
68273
68460
  CODEX_MIN_CLIENT = "0.144.0";
68274
- TTL_MS5 = 5 * 6e4;
68275
- cache3 = null;
68461
+ TTL_MS6 = 5 * 6e4;
68462
+ cache4 = null;
68276
68463
  codexBin2 = () => effectiveStr("HANOMAN_CODEX_BIN") ?? "codex";
68277
68464
  runVersion = async (bin, args) => {
68278
68465
  const { stdout } = await run3(bin, args, { timeout: 1e4 });
@@ -68282,17 +68469,17 @@ var init_codex_version = __esm({
68282
68469
  });
68283
68470
 
68284
68471
  // src/services/agent-tool-catalog.ts
68285
- import { readFileSync as readFileSync27 } from "node:fs";
68286
- import { homedir as homedir13 } from "node:os";
68287
- import { join as join51 } from "node:path";
68472
+ import { readFileSync as readFileSync31 } from "node:fs";
68473
+ import { homedir as homedir16 } from "node:os";
68474
+ import { join as join56 } from "node:path";
68288
68475
  function mcpServerNames(repoDir) {
68289
68476
  const names = [];
68290
- const claudeJson = readJson2(join51(home(), ".claude.json"));
68477
+ const claudeJson = readJson2(join56(home(), ".claude.json"));
68291
68478
  names.push(...serversOf(claudeJson));
68292
68479
  if (repoDir) {
68293
68480
  const projects = claudeJson?.projects;
68294
68481
  if (projects && typeof projects === "object") names.push(...serversOf(projects[repoDir]));
68295
- names.push(...serversOf(readJson2(join51(repoDir, ".mcp.json"))));
68482
+ names.push(...serversOf(readJson2(join56(repoDir, ".mcp.json"))));
68296
68483
  }
68297
68484
  names.push(...codexServers());
68298
68485
  return [...new Set(names.filter(Boolean))].sort((a, b) => a.localeCompare(b));
@@ -68305,10 +68492,10 @@ var init_agent_tool_catalog = __esm({
68305
68492
  "src/services/agent-tool-catalog.ts"() {
68306
68493
  "use strict";
68307
68494
  init_src();
68308
- home = () => process.env.HOME || homedir13();
68495
+ home = () => process.env.HOME || homedir16();
68309
68496
  readJson2 = (path) => {
68310
68497
  try {
68311
- return JSON.parse(readFileSync27(path, "utf8"));
68498
+ return JSON.parse(readFileSync31(path, "utf8"));
68312
68499
  } catch {
68313
68500
  return null;
68314
68501
  }
@@ -68321,7 +68508,7 @@ var init_agent_tool_catalog = __esm({
68321
68508
  codexServers = () => {
68322
68509
  let text2;
68323
68510
  try {
68324
- text2 = readFileSync27(join51(home(), ".codex", "config.toml"), "utf8");
68511
+ text2 = readFileSync31(join56(home(), ".codex", "config.toml"), "utf8");
68325
68512
  } catch {
68326
68513
  return [];
68327
68514
  }
@@ -68337,7 +68524,7 @@ var init_agent_tool_catalog = __esm({
68337
68524
  });
68338
68525
 
68339
68526
  // src/services/builtin-agents.ts
68340
- import { createHash as createHash20 } from "node:crypto";
68527
+ import { createHash as createHash21 } from "node:crypto";
68341
68528
  async function seedBuiltinAgents() {
68342
68529
  try {
68343
68530
  const setting = await getSetting();
@@ -68439,7 +68626,7 @@ var init_builtin_agents2 = __esm({
68439
68626
  init_settings3();
68440
68627
  init_tombstone();
68441
68628
  init_sync_notify();
68442
- digest2 = (parts) => createHash20("sha256").update(parts.join(" ")).digest("hex").slice(0, 16);
68629
+ digest2 = (parts) => createHash21("sha256").update(parts.join(" ")).digest("hex").slice(0, 16);
68443
68630
  legacyFingerprint = (name2, description, instructions, tools) => digest2([name2, description, instructions, [...tools].join(",")]);
68444
68631
  mentionPart = (v) => {
68445
68632
  const m = mentionsOf(v);
@@ -68537,7 +68724,7 @@ function toRuntimeDef(row, runtime) {
68537
68724
  }
68538
68725
  async function loadCustomAgents() {
68539
68726
  try {
68540
- cache4 = await prisma.customAgent.findMany();
68727
+ cache5 = await prisma.customAgent.findMany();
68541
68728
  const projects = await prisma.project.findMany({ select: { id: true, repoDir: true } });
68542
68729
  const bindings = await prisma.localBinding.findMany({ select: { projectId: true, repoDir: true } });
68543
68730
  const next = /* @__PURE__ */ new Map();
@@ -68545,7 +68732,7 @@ async function loadCustomAgents() {
68545
68732
  for (const b of bindings) next.set(b.projectId, b.repoDir ?? null);
68546
68733
  repoDirCache = next;
68547
68734
  } catch {
68548
- cache4 = [];
68735
+ cache5 = [];
68549
68736
  repoDirCache = /* @__PURE__ */ new Map();
68550
68737
  }
68551
68738
  }
@@ -68558,10 +68745,10 @@ function agentDefsFor(contextOrProjectId, legacyAgent) {
68558
68745
  changedFiles: []
68559
68746
  } : contextOrProjectId;
68560
68747
  const { projectId } = context;
68561
- const globals = cache4.filter((r) => r.projectId === null).map(asCustomAgent);
68562
- const project = cache4.filter((r) => r.projectId === projectId).map(asCustomAgent);
68748
+ const globals = cache5.filter((r) => r.projectId === null).map(asCustomAgent);
68749
+ const project = cache5.filter((r) => r.projectId === projectId).map(asCustomAgent);
68563
68750
  const effectiveIds = new Set(effectiveAgents(globals, project).map((agent) => agent.id));
68564
- const effectiveRows = cache4.filter((row) => effectiveIds.has(row.id));
68751
+ const effectiveRows = cache5.filter((row) => effectiveIds.has(row.id));
68565
68752
  const eff = selectAgentRows(effectiveRows, context);
68566
68753
  const needsCatalog = eff.some((row) => (toolsOf(row.tools) ?? []).includes(ALL_TOOLS));
68567
68754
  const catalogIds = needsCatalog ? agentToolIds(repoDirCache.get(projectId) ?? null) : [];
@@ -68617,7 +68804,7 @@ async function installCustomAgents() {
68617
68804
  codexSupportRefreshTimer.unref();
68618
68805
  }
68619
68806
  }
68620
- var cache4, codexNativeSupport, codexSupportRefreshTimer, codexSupportRefreshTail, repoDirCache, asCustomAgent, defaultCodexSupportProbe;
68807
+ var cache5, codexNativeSupport, codexSupportRefreshTimer, codexSupportRefreshTail, repoDirCache, asCustomAgent, defaultCodexSupportProbe;
68621
68808
  var init_custom_agents2 = __esm({
68622
68809
  "src/services/custom-agents.ts"() {
68623
68810
  "use strict";
@@ -68629,7 +68816,7 @@ var init_custom_agents2 = __esm({
68629
68816
  init_builtin_agents2();
68630
68817
  init_runtime_defaults2();
68631
68818
  init_codex_version();
68632
- cache4 = [];
68819
+ cache5 = [];
68633
68820
  codexNativeSupport = { version: null, ok: false };
68634
68821
  codexSupportRefreshTimer = null;
68635
68822
  codexSupportRefreshTail = Promise.resolve();
@@ -71176,14 +71363,14 @@ var require_stream_consumer = __commonJS({
71176
71363
  "../node_modules/.pnpm/@fastify+multipart@10.1.0/node_modules/@fastify/multipart/lib/stream-consumer.js"(exports, module) {
71177
71364
  "use strict";
71178
71365
  module.exports = function streamToNull(stream) {
71179
- return new Promise((resolve25, reject2) => {
71366
+ return new Promise((resolve26, reject2) => {
71180
71367
  stream.on("data", () => {
71181
71368
  });
71182
71369
  stream.on("close", () => {
71183
- resolve25();
71370
+ resolve26();
71184
71371
  });
71185
71372
  stream.on("end", () => {
71186
- resolve25();
71373
+ resolve26();
71187
71374
  });
71188
71375
  stream.on("error", (error) => {
71189
71376
  reject2(error);
@@ -71632,10 +71819,10 @@ var require_multipart2 = __commonJS({
71632
71819
  }
71633
71820
  };
71634
71821
  const parts = () => {
71635
- return new Promise((resolve25, reject2) => {
71822
+ return new Promise((resolve26, reject2) => {
71636
71823
  handle((val) => {
71637
71824
  if (val instanceof Error) return reject2(val);
71638
- resolve25(val);
71825
+ resolve26(val);
71639
71826
  });
71640
71827
  });
71641
71828
  };
@@ -71941,7 +72128,7 @@ import websocket from "@fastify/websocket";
71941
72128
  import cookie from "@fastify/cookie";
71942
72129
  import { fileURLToPath as fileURLToPath6 } from "node:url";
71943
72130
  import { dirname as dirname19 } from "node:path";
71944
- import { existsSync as existsSync25 } from "node:fs";
72131
+ import { existsSync as existsSync26 } from "node:fs";
71945
72132
 
71946
72133
  // src/web-dir.ts
71947
72134
  import { resolve as resolve11 } from "node:path";
@@ -72029,11 +72216,11 @@ var UploadError = class extends Error {
72029
72216
  }
72030
72217
  };
72031
72218
  function timeout(promise, ms, code) {
72032
- return new Promise((resolve25, reject2) => {
72219
+ return new Promise((resolve26, reject2) => {
72033
72220
  const timer11 = setTimeout(() => reject2(new UploadError(code, "upload operation timed out")), ms);
72034
72221
  promise.then((value) => {
72035
72222
  clearTimeout(timer11);
72036
- resolve25(value);
72223
+ resolve26(value);
72037
72224
  }, (error) => {
72038
72225
  clearTimeout(timer11);
72039
72226
  reject2(error);
@@ -72056,7 +72243,7 @@ function scannerFromEnv(path) {
72056
72243
  return Promise.resolve();
72057
72244
  }
72058
72245
  if (!isAbsolute9(command)) return Promise.reject(new UploadError("UPLOAD_SCAN", "scanner path must be absolute"));
72059
- return new Promise((resolve25, reject2) => {
72246
+ return new Promise((resolve26, reject2) => {
72060
72247
  const child = spawn2(command, [path], { shell: false, stdio: "ignore" });
72061
72248
  const timer11 = setTimeout(() => {
72062
72249
  child.kill("SIGKILL");
@@ -72068,7 +72255,7 @@ function scannerFromEnv(path) {
72068
72255
  });
72069
72256
  child.once("exit", (code) => {
72070
72257
  clearTimeout(timer11);
72071
- if (code === 0) resolve25();
72258
+ if (code === 0) resolve26();
72072
72259
  else reject2(new UploadError("UPLOAD_SCAN", `scanner exit ${code}`));
72073
72260
  });
72074
72261
  });
@@ -74091,7 +74278,8 @@ var view4 = (r) => ({
74091
74278
  endedReason: r.endedReason,
74092
74279
  reconciledAt: r.reconciledAt?.toISOString() ?? null,
74093
74280
  exitCode: r.exitCode,
74094
- transcriptBytes: r.transcriptBytes
74281
+ transcriptBytes: r.transcriptBytes,
74282
+ accountId: r.accountId
74095
74283
  });
74096
74284
  async function titleFor(specId) {
74097
74285
  if (!specId) return null;
@@ -74112,7 +74300,9 @@ async function beginSession(b) {
74112
74300
  model: b.model ?? null,
74113
74301
  effort: b.effort ?? null,
74114
74302
  branch: b.branch ?? null,
74115
- cwd: b.cwd
74303
+ cwd: b.cwd,
74304
+ accountId: b.accountId ?? null
74305
+ // ADR-0234
74116
74306
  }
74117
74307
  });
74118
74308
  }
@@ -74274,7 +74464,7 @@ async function reconciledSpecIdsSince(cutoff) {
74274
74464
  async function reconciledRuntimesSince(cutoff) {
74275
74465
  const rows = await prisma.sessionHistory.findMany({
74276
74466
  where: { endedReason: RECONCILED, reconciledAt: { gte: cutoff }, specId: { not: null } },
74277
- select: { specId: true, agent: true, model: true, effort: true },
74467
+ select: { specId: true, agent: true, model: true, effort: true, accountId: true },
74278
74468
  orderBy: { startedAt: "desc" }
74279
74469
  });
74280
74470
  const out4 = /* @__PURE__ */ new Map();
@@ -74284,7 +74474,8 @@ async function reconciledRuntimesSince(cutoff) {
74284
74474
  // `agent` kolom String — nilai asing jatuh ke claude, cermin pembacaan @hanoman_agent (pty.ts).
74285
74475
  agent: r.agent === "antigravity" ? "antigravity" : r.agent === "codex" ? "codex" : "claude",
74286
74476
  ...r.model ? { model: r.model } : {},
74287
- ...r.effort ? { effort: r.effort } : {}
74477
+ ...r.effort ? { effort: r.effort } : {},
74478
+ ...r.accountId ? { accountId: r.accountId } : {}
74288
74479
  });
74289
74480
  }
74290
74481
  return out4;
@@ -77033,7 +77224,7 @@ function renderDocPdf(text2, name2, meta) {
77033
77224
  });
77034
77225
  const chunks = [];
77035
77226
  doc.on("data", (c) => chunks.push(c));
77036
- const done = new Promise((resolve25) => doc.on("end", () => resolve25(Buffer.concat(chunks))));
77227
+ const done = new Promise((resolve26) => doc.on("end", () => resolve26(Buffer.concat(chunks))));
77037
77228
  doc.font("Helvetica-Bold").fontSize(8).fillColor(BRASS).text(toWinAnsi(meta.eyebrow.toUpperCase()), { characterSpacing: 0.8 });
77038
77229
  doc.moveDown(0.25);
77039
77230
  doc.font("Helvetica-Bold").fontSize(17).fillColor(STRONG).text(toWinAnsi(name2.split("/").pop() ?? name2));
@@ -77754,7 +77945,9 @@ async function settings_default(app3) {
77754
77945
  builtinRuntimeDefaults: markRuntimeDefaultsUserEdited(before2, runtimePreserved),
77755
77946
  remoteControl: before2.remoteControl,
77756
77947
  logShipping: before2.logShipping,
77757
- logRetention: before2.logRetention
77948
+ logRetention: before2.logRetention,
77949
+ // ADR-0234 · pilihan akun runtime milik PUT /runtime-accounts/default, bukan form Settings.
77950
+ accounts: before2.accounts
77758
77951
  };
77759
77952
  const row = await prisma.setting.upsert({
77760
77953
  where: { id: 1 },
@@ -78581,9 +78774,9 @@ init_src();
78581
78774
  init_src2();
78582
78775
  init_session_phases();
78583
78776
  init_spec_review2();
78584
- import { existsSync as existsSync21 } from "node:fs";
78585
- import { execFileSync as execFileSync9 } from "node:child_process";
78586
- import { randomUUID as randomUUID13 } from "node:crypto";
78777
+ import { existsSync as existsSync22 } from "node:fs";
78778
+ import { execFileSync as execFileSync10 } from "node:child_process";
78779
+ import { randomUUID as randomUUID14 } from "node:crypto";
78587
78780
  init_integrate();
78588
78781
  init_settings3();
78589
78782
  init_codex_trust();
@@ -78646,7 +78839,7 @@ function setBounded(map, key, value, maxKeys) {
78646
78839
  // src/services/auth.ts
78647
78840
  init_src2();
78648
78841
  init_db();
78649
- import { randomBytes as randomBytes4, scrypt as scryptCb, timingSafeEqual as timingSafeEqual4, createHash as createHash17 } from "node:crypto";
78842
+ import { randomBytes as randomBytes4, scrypt as scryptCb, timingSafeEqual as timingSafeEqual4, createHash as createHash18 } from "node:crypto";
78650
78843
  import { promisify as promisify16 } from "node:util";
78651
78844
  var scrypt = promisify16(scryptCb);
78652
78845
  var COOKIE_NAME = "hn_session";
@@ -78664,7 +78857,7 @@ async function verifyPassword(pw, stored) {
78664
78857
  return key.length === want.length && timingSafeEqual4(key, want);
78665
78858
  }
78666
78859
  var newSessionToken = () => randomBytes4(32).toString("base64url");
78667
- var sessionId = (token) => createHash17("sha256").update(token).digest("hex");
78860
+ var sessionId = (token) => createHash18("sha256").update(token).digest("hex");
78668
78861
  async function createSession2(userId) {
78669
78862
  const token = newSessionToken();
78670
78863
  await prisma.session.create({
@@ -78725,9 +78918,9 @@ function cookieOpts(req) {
78725
78918
 
78726
78919
  // src/services/device-token.ts
78727
78920
  init_db();
78728
- import { randomBytes as randomBytes5, createHash as createHash18 } from "node:crypto";
78921
+ import { randomBytes as randomBytes5, createHash as createHash19 } from "node:crypto";
78729
78922
  var newDeviceToken = () => randomBytes5(32).toString("base64url");
78730
- var tokenHash = (token) => createHash18("sha256").update(token).digest("hex");
78923
+ var tokenHash = (token) => createHash19("sha256").update(token).digest("hex");
78731
78924
  async function issueDeviceToken(userId, name2) {
78732
78925
  const token = newDeviceToken();
78733
78926
  const row = await prisma.deviceToken.create({ data: { userId, name: name2, tokenHash: tokenHash(token) } });
@@ -78966,6 +79159,554 @@ function appendDiag(home3, sessionId2, events) {
78966
79159
  appendFileSync4(file, rows.map((r) => JSON.stringify(r)).join("\n") + "\n");
78967
79160
  }
78968
79161
 
79162
+ // src/services/runtime-accounts/registry.ts
79163
+ init_src();
79164
+ init_db();
79165
+ init_settings3();
79166
+ import { randomUUID as randomUUID12 } from "node:crypto";
79167
+ import { rmSync as rmSync12 } from "node:fs";
79168
+
79169
+ // src/services/runtime-accounts/home.ts
79170
+ import { chmodSync as chmodSync10, existsSync as existsSync21, lstatSync as lstatSync10, mkdirSync as mkdirSync18, readFileSync as readFileSync20, readlinkSync as readlinkSync3, renameSync as renameSync7, symlinkSync as symlinkSync2, writeFileSync as writeFileSync18 } from "node:fs";
79171
+ import { join as join43 } from "node:path";
79172
+
79173
+ // src/services/runtime-accounts/paths.ts
79174
+ init_src2();
79175
+ import { homedir as homedir10 } from "node:os";
79176
+ import { join as join42, resolve as resolve23, sep as sep11 } from "node:path";
79177
+ var accountsRoot = (env = process.env) => join42(resolveHome(env), "accounts");
79178
+ var accountHomeDir = (runtime, id2, env = process.env) => join42(accountsRoot(env), runtime, id2);
79179
+ var baseHome = (runtime, env = process.env) => agentSkillHome(runtime, env);
79180
+ function baseClaudeJson(env = process.env, osHome = homedir10()) {
79181
+ const own = env.HANOMAN_CLAUDE_HOME?.trim() || env.CLAUDE_CONFIG_DIR?.trim();
79182
+ return own ? join42(own, ".claude.json") : join42(osHome, ".claude.json");
79183
+ }
79184
+ function insideAccountsRoot(path, env = process.env) {
79185
+ return resolve23(path).startsWith(resolve23(accountsRoot(env)) + sep11);
79186
+ }
79187
+
79188
+ // src/services/runtime-accounts/home.ts
79189
+ var SHARED_ENTRIES = {
79190
+ claude: ["skills", "plugins", "agents", "commands", "hooks", "output-styles", "settings.json", "CLAUDE.md", "projects"],
79191
+ codex: ["config.toml", "skills", "plugins", "AGENTS.md", "hooks.json", "prompts", "rules"],
79192
+ // Mode tukar agy: home akun hanya menyimpan slot token, tak ada aset bersama.
79193
+ antigravity: []
79194
+ };
79195
+ var MIRRORED_CLAUDE_KEYS = [
79196
+ "mcpServers",
79197
+ "hasCompletedOnboarding",
79198
+ "lastOnboardingVersion",
79199
+ "theme",
79200
+ "bypassPermissionsModeAccepted",
79201
+ "projects"
79202
+ ];
79203
+ function classify(target3, link2) {
79204
+ let st2 = null;
79205
+ try {
79206
+ st2 = lstatSync10(link2);
79207
+ } catch {
79208
+ st2 = null;
79209
+ }
79210
+ if (!st2) return existsSync21(target3) ? "absent" : "no-target";
79211
+ if (st2.isSymbolicLink()) return readlinkSync3(link2) === target3 ? "ok" : "drift";
79212
+ return "drift";
79213
+ }
79214
+ function inspectAccountHome(runtime, homeDir, base3 = baseHome(runtime)) {
79215
+ return SHARED_ENTRIES[runtime].filter((e) => classify(join43(base3, e), join43(homeDir, e)) === "drift");
79216
+ }
79217
+ function ensureAccountHome(runtime, homeDir, base3 = baseHome(runtime)) {
79218
+ mkdirSync18(homeDir, { recursive: true, mode: 448 });
79219
+ chmodSync10(homeDir, 448);
79220
+ const linked = [], drift = [];
79221
+ for (const entry2 of SHARED_ENTRIES[runtime]) {
79222
+ const target3 = join43(base3, entry2), link2 = join43(homeDir, entry2);
79223
+ const state = classify(target3, link2);
79224
+ if (state === "drift") drift.push(entry2);
79225
+ else if (state === "absent") {
79226
+ symlinkSync2(target3, link2);
79227
+ linked.push(entry2);
79228
+ }
79229
+ }
79230
+ return { linked, drift };
79231
+ }
79232
+ function mirrorClaudeJson(accountHome, baseJsonPath = baseClaudeJson()) {
79233
+ let base3;
79234
+ try {
79235
+ base3 = JSON.parse(readFileSync20(baseJsonPath, "utf8"));
79236
+ } catch {
79237
+ return;
79238
+ }
79239
+ const path = join43(accountHome, ".claude.json");
79240
+ let acct = {};
79241
+ try {
79242
+ acct = JSON.parse(readFileSync20(path, "utf8"));
79243
+ } catch {
79244
+ acct = {};
79245
+ }
79246
+ let changed = false;
79247
+ for (const k of MIRRORED_CLAUDE_KEYS) {
79248
+ if (!(k in base3) || JSON.stringify(acct[k]) === JSON.stringify(base3[k])) continue;
79249
+ acct[k] = base3[k];
79250
+ changed = true;
79251
+ }
79252
+ if (!changed) return;
79253
+ const tmp = `${path}.hanoman-${process.pid}.tmp`;
79254
+ writeFileSync18(tmp, JSON.stringify(acct, null, 2), { mode: 384 });
79255
+ renameSync7(tmp, path);
79256
+ }
79257
+ function prepareAccountHome(runtime, homeDir) {
79258
+ const r = ensureAccountHome(runtime, homeDir);
79259
+ if (runtime === "claude") mirrorClaudeJson(homeDir);
79260
+ return r;
79261
+ }
79262
+
79263
+ // src/services/runtime-accounts/registry.ts
79264
+ init_keychain();
79265
+
79266
+ // src/services/runtime-accounts/identity.ts
79267
+ init_pty();
79268
+ import { execFile as execFile17 } from "node:child_process";
79269
+ import { readFileSync as readFileSync21 } from "node:fs";
79270
+ import { join as join44 } from "node:path";
79271
+ var NONE2 = { loggedIn: false, identity: null };
79272
+ var execOut = (bin, args, env) => new Promise((res, rej) => {
79273
+ execFile17(bin, args, { env, encoding: "utf8", timeout: 15e3 }, (err, stdout) => stdout ? res(stdout) : rej(err));
79274
+ });
79275
+ async function probeClaudeLogin(homeDir, run6 = execOut, bin = agentBin("claude")) {
79276
+ const env = { ...process.env };
79277
+ if (homeDir) {
79278
+ env.CLAUDE_CONFIG_DIR = homeDir;
79279
+ delete env.CLAUDE_CODE_OAUTH_TOKEN;
79280
+ delete env.ANTHROPIC_API_KEY;
79281
+ }
79282
+ try {
79283
+ const j = JSON.parse(await run6(bin, ["auth", "status", "--json"], env));
79284
+ if (j.loggedIn !== true) return NONE2;
79285
+ return { loggedIn: true, identity: {
79286
+ ...typeof j.email === "string" && j.email ? { email: j.email } : {},
79287
+ ...typeof j.subscriptionType === "string" && j.subscriptionType ? { plan: j.subscriptionType } : {}
79288
+ } };
79289
+ } catch {
79290
+ return NONE2;
79291
+ }
79292
+ }
79293
+ function decodeJwtClaims(token) {
79294
+ const part = token.split(".")[1];
79295
+ if (!part) return null;
79296
+ try {
79297
+ const v = JSON.parse(Buffer.from(part, "base64url").toString("utf8"));
79298
+ return v && typeof v === "object" ? v : null;
79299
+ } catch {
79300
+ return null;
79301
+ }
79302
+ }
79303
+ function probeCodexLogin(codexHome2) {
79304
+ let j;
79305
+ try {
79306
+ j = JSON.parse(readFileSync21(join44(codexHome2, "auth.json"), "utf8"));
79307
+ } catch {
79308
+ return NONE2;
79309
+ }
79310
+ const access = j.tokens?.access_token;
79311
+ if (typeof access !== "string" || !access) return NONE2;
79312
+ const claims = typeof j.tokens?.id_token === "string" ? decodeJwtClaims(j.tokens.id_token) : null;
79313
+ const auth = claims?.["https://api.openai.com/auth"];
79314
+ return { loggedIn: true, identity: {
79315
+ ...typeof claims?.email === "string" ? { email: claims.email } : {},
79316
+ ...typeof auth?.chatgpt_plan_type === "string" ? { plan: auth.chatgpt_plan_type } : {}
79317
+ } };
79318
+ }
79319
+ function nextStatus(loggedIn, everLoggedIn) {
79320
+ return loggedIn ? "aktif" : everLoggedIn ? "perlu-login-ulang" : "belum-login";
79321
+ }
79322
+
79323
+ // src/services/runtime-accounts/registry.ts
79324
+ var AccountError = class extends Error {
79325
+ constructor(code, status2, message) {
79326
+ super(message);
79327
+ this.code = code;
79328
+ this.status = status2;
79329
+ }
79330
+ };
79331
+ var probes = {
79332
+ claude: (home3) => probeClaudeLogin(home3),
79333
+ codex: async (home3) => probeCodexLogin(home3),
79334
+ // Mode tukar agy (antigravity-swap.ts) memasang probe slot-nya lewat setProbe saat boot.
79335
+ antigravity: async () => ({ loggedIn: false, identity: null })
79336
+ };
79337
+ function setProbe(runtime, fn) {
79338
+ probes[runtime] = fn;
79339
+ }
79340
+ var RUNTIMES = zAgent.options;
79341
+ var snapshot2 = { rows: [], defaults: {}, builtin: {} };
79342
+ var accountSnapshot = () => snapshot2;
79343
+ var toRow = (r) => ({
79344
+ id: r.id,
79345
+ runtime: zAgent.parse(r.runtime),
79346
+ label: r.label,
79347
+ homeDir: r.homeDir,
79348
+ identity: r.identity && typeof r.identity === "object" && !Array.isArray(r.identity) ? r.identity : null,
79349
+ status: r.status === "aktif" || r.status === "perlu-login-ulang" ? r.status : "belum-login",
79350
+ createdAt: r.createdAt,
79351
+ lastLoginAt: r.lastLoginAt
79352
+ });
79353
+ async function refreshSnapshot() {
79354
+ const [rows, setting] = await Promise.all([
79355
+ prisma.runtimeAccount.findMany({ orderBy: { createdAt: "asc" } }),
79356
+ getSetting()
79357
+ ]);
79358
+ snapshot2 = { ...snapshot2, rows: rows.map(toRow), defaults: setting.accounts ?? {} };
79359
+ }
79360
+ var defaultOf = (runtime) => snapshot2.defaults[runtime] ?? builtinAccountId(runtime);
79361
+ function accountExists(id2) {
79362
+ return isBuiltinAccountId(id2) ? runtimeOfBuiltin(id2) !== null : snapshot2.rows.some((r) => r.id === id2);
79363
+ }
79364
+ function listAccountDTOs() {
79365
+ const out4 = [];
79366
+ for (const runtime of RUNTIMES) {
79367
+ const def2 = defaultOf(runtime);
79368
+ const b = snapshot2.builtin[runtime];
79369
+ out4.push({
79370
+ id: builtinAccountId(runtime),
79371
+ runtime,
79372
+ label: BUILTIN_ACCOUNT_LABEL,
79373
+ builtin: true,
79374
+ isDefault: def2 === builtinAccountId(runtime),
79375
+ // Belum diprobe = anggap aktif: akun bawaan adalah perilaku hanoman selama ini.
79376
+ status: b?.status ?? "aktif",
79377
+ identity: b?.identity ?? null,
79378
+ drift: [],
79379
+ createdAt: null,
79380
+ lastLoginAt: null
79381
+ });
79382
+ for (const r of snapshot2.rows.filter((x) => x.runtime === runtime)) {
79383
+ out4.push({
79384
+ id: r.id,
79385
+ runtime,
79386
+ label: r.label,
79387
+ builtin: false,
79388
+ isDefault: def2 === r.id,
79389
+ status: r.status,
79390
+ identity: r.identity,
79391
+ drift: inspectAccountHome(runtime, r.homeDir),
79392
+ createdAt: r.createdAt.toISOString(),
79393
+ lastLoginAt: r.lastLoginAt?.toISOString() ?? null
79394
+ });
79395
+ }
79396
+ }
79397
+ return out4;
79398
+ }
79399
+ var dtoOf = (id2) => {
79400
+ const d = listAccountDTOs().find((a) => a.id === id2);
79401
+ if (!d) throw new AccountError("account-not-found", 404, `akun ${id2} tak ditemukan`);
79402
+ return d;
79403
+ };
79404
+ var labelTaken = (runtime, label2) => new AccountError("account-label-taken", 409, `label "${label2}" sudah dipakai di ${runtime}`);
79405
+ var isUniqueViolation = (e) => e.code === "P2002";
79406
+ async function createAccount(runtime, label2) {
79407
+ if (label2.toLowerCase() === BUILTIN_ACCOUNT_LABEL.toLowerCase()) throw labelTaken(runtime, label2);
79408
+ const id2 = randomUUID12().replace(/-/g, "").slice(0, 8);
79409
+ const homeDir = accountHomeDir(runtime, id2);
79410
+ try {
79411
+ await prisma.runtimeAccount.create({ data: { id: id2, runtime, label: label2, homeDir, status: "belum-login" } });
79412
+ } catch (e) {
79413
+ if (isUniqueViolation(e)) throw labelTaken(runtime, label2);
79414
+ throw e;
79415
+ }
79416
+ ensureAccountHome(runtime, homeDir, baseHome(runtime));
79417
+ await refreshSnapshot();
79418
+ return dtoOf(id2);
79419
+ }
79420
+ async function rowOrThrow(id2) {
79421
+ const r = await prisma.runtimeAccount.findUnique({ where: { id: id2 } });
79422
+ if (!r) throw new AccountError("account-not-found", 404, `akun ${id2} tak ditemukan`);
79423
+ return toRow(r);
79424
+ }
79425
+ async function renameAccount(id2, label2) {
79426
+ const row = await rowOrThrow(id2);
79427
+ if (label2.toLowerCase() === BUILTIN_ACCOUNT_LABEL.toLowerCase()) throw labelTaken(row.runtime, label2);
79428
+ try {
79429
+ await prisma.runtimeAccount.update({ where: { id: id2 }, data: { label: label2 } });
79430
+ } catch (e) {
79431
+ if (isUniqueViolation(e)) throw labelTaken(row.runtime, label2);
79432
+ throw e;
79433
+ }
79434
+ await refreshSnapshot();
79435
+ return dtoOf(id2);
79436
+ }
79437
+ async function writeDefaults(accounts) {
79438
+ const s2 = await getSetting();
79439
+ const data = { ...s2, accounts };
79440
+ await prisma.setting.upsert({ where: { id: 1 }, update: { data }, create: { id: 1, data } });
79441
+ }
79442
+ async function deleteAccount(id2, liveAccountIds2) {
79443
+ const row = await rowOrThrow(id2);
79444
+ if (liveAccountIds2().includes(id2)) throw new AccountError("account-in-use", 409, `akun "${row.label}" masih dipakai sesi yang hidup`);
79445
+ await prisma.runtimeAccount.delete({ where: { id: id2 } });
79446
+ const s2 = await getSetting();
79447
+ if (s2.accounts?.[row.runtime] === id2) {
79448
+ const next = { ...s2.accounts };
79449
+ delete next[row.runtime];
79450
+ await writeDefaults(next);
79451
+ }
79452
+ if (row.runtime === "claude" && process.platform === "darwin") deleteClaudeKeychainEntry(claudeKeychainService(row.homeDir));
79453
+ if (insideAccountsRoot(row.homeDir)) rmSync12(row.homeDir, { recursive: true, force: true });
79454
+ await refreshSnapshot();
79455
+ }
79456
+ async function setDefaultAccount(runtime, accountId, sandbox) {
79457
+ if (isBuiltinAccountId(accountId)) {
79458
+ if (accountId !== builtinAccountId(runtime))
79459
+ throw new AccountError("account-runtime-mismatch", 409, `${accountId} bukan akun bawaan ${runtime}`);
79460
+ } else {
79461
+ const row = await rowOrThrow(accountId);
79462
+ if (row.runtime !== runtime) throw new AccountError("account-runtime-mismatch", 409, `akun "${row.label}" milik ${row.runtime}, bukan ${runtime}`);
79463
+ if (sandbox) throw new AccountError("account-sandbox-unsupported", 409, "sandbox sesi hanya mendukung akun bawaan");
79464
+ }
79465
+ const s2 = await getSetting();
79466
+ const next = { ...s2.accounts ?? {} };
79467
+ if (isBuiltinAccountId(accountId)) delete next[runtime];
79468
+ else next[runtime] = accountId;
79469
+ await writeDefaults(next);
79470
+ await refreshSnapshot();
79471
+ }
79472
+ async function probeBuiltin(runtime, use2 = probes) {
79473
+ const p3 = runtime === "claude" ? await use2.claude(null) : runtime === "codex" ? await use2.codex(baseHome("codex")) : await use2.antigravity(null, builtinAccountId("antigravity"));
79474
+ snapshot2 = { ...snapshot2, builtin: { ...snapshot2.builtin, [runtime]: {
79475
+ status: nextStatus(p3.loggedIn, true),
79476
+ identity: p3.identity
79477
+ } } };
79478
+ }
79479
+ async function checkAccount(id2, override) {
79480
+ const use2 = override ?? probes;
79481
+ const builtin = runtimeOfBuiltin(id2);
79482
+ if (builtin) {
79483
+ await probeBuiltin(builtin, use2);
79484
+ return dtoOf(id2);
79485
+ }
79486
+ const row = await rowOrThrow(id2);
79487
+ const p3 = row.runtime === "claude" ? await use2.claude(row.homeDir) : row.runtime === "codex" ? await use2.codex(row.homeDir) : await use2.antigravity(row.homeDir, row.id);
79488
+ const ever = row.lastLoginAt !== null || row.status !== "belum-login";
79489
+ await prisma.runtimeAccount.update({ where: { id: id2 }, data: {
79490
+ status: nextStatus(p3.loggedIn, ever),
79491
+ ...p3.loggedIn ? { identity: p3.identity ?? {} } : {},
79492
+ ...p3.loggedIn && row.status !== "aktif" ? { lastLoginAt: /* @__PURE__ */ new Date() } : {}
79493
+ } });
79494
+ await refreshSnapshot();
79495
+ return dtoOf(id2);
79496
+ }
79497
+ async function refreshAllStatuses() {
79498
+ for (const runtime of RUNTIMES) {
79499
+ try {
79500
+ await probeBuiltin(runtime);
79501
+ } catch (e) {
79502
+ console.error(`akun runtime (status ${runtime} bawaan):`, e);
79503
+ }
79504
+ }
79505
+ for (const r of snapshot2.rows) {
79506
+ try {
79507
+ await checkAccount(r.id);
79508
+ } catch (e) {
79509
+ console.error(`akun runtime (status ${r.label}):`, e);
79510
+ }
79511
+ }
79512
+ }
79513
+
79514
+ // src/services/runtime-accounts/resolver.ts
79515
+ init_src();
79516
+ init_session_sandbox();
79517
+ init_db();
79518
+
79519
+ // src/services/runtime-accounts/antigravity-swap.ts
79520
+ init_src();
79521
+ init_secret_box();
79522
+ init_antigravity_limits();
79523
+ init_pty();
79524
+ init_keychain();
79525
+ import { chmodSync as chmodSync11, mkdirSync as mkdirSync19, readFileSync as readFileSync22, rmSync as rmSync13, writeFileSync as writeFileSync19 } from "node:fs";
79526
+ import { homedir as homedir11 } from "node:os";
79527
+ import { join as join45 } from "node:path";
79528
+ var BUILTIN = builtinAccountId("antigravity");
79529
+ var isAgyLoginSession = (sessionId2) => sessionId2 === "acct-login-default-antigravity" || accountSnapshot().rows.some((r) => r.runtime === "antigravity" && sessionId2 === `acct-login-${r.id}`);
79530
+ var liveAgySessions = () => listSessions().filter((s2) => !s2.exited && (s2.agent === "antigravity" || isAgyLoginSession(s2.id)));
79531
+ var fsAgyIo = () => ({
79532
+ run: securityRun,
79533
+ readFile: (p3) => {
79534
+ try {
79535
+ return readFileSync22(p3, "utf8");
79536
+ } catch {
79537
+ return null;
79538
+ }
79539
+ },
79540
+ writeFile: (p3, s2) => {
79541
+ writeFileSync19(p3, s2, { mode: 384 });
79542
+ chmodSync11(p3, 384);
79543
+ },
79544
+ removeFile: (p3) => rmSync13(p3, { force: true }),
79545
+ tokenFile: join45(homedir11(), ".gemini", "antigravity-cli", "antigravity-oauth-token"),
79546
+ accountsDir: join45(accountsRoot(), "antigravity"),
79547
+ // Sesi agy hidup memakai akun yang AKTIF saat ini (satu Keychain), apa pun @hanoman_account-nya.
79548
+ liveAgyAccountIds: () => liveAgySessions().map((s2) => s2.accountId ?? BUILTIN)
79549
+ });
79550
+ var slotDir = (io, id2) => join45(io.accountsDir, isBuiltinAccountId(id2) ? "default" : id2);
79551
+ var activeFile = (io) => join45(io.accountsDir, "active");
79552
+ function activeAgyAccount(io = fsAgyIo()) {
79553
+ return io.readFile(activeFile(io))?.trim() || BUILTIN;
79554
+ }
79555
+ function readSlot(accountId, io = fsAgyIo()) {
79556
+ let raw;
79557
+ try {
79558
+ raw = readFileSync22(join45(slotDir(io, accountId), "slot.enc"), "utf8");
79559
+ } catch {
79560
+ return null;
79561
+ }
79562
+ const plain = decryptSecret(raw);
79563
+ if (!plain) return null;
79564
+ try {
79565
+ return JSON.parse(plain);
79566
+ } catch {
79567
+ return null;
79568
+ }
79569
+ }
79570
+ function writeSlot(accountId, slot, io) {
79571
+ const d = slotDir(io, accountId);
79572
+ mkdirSync19(d, { recursive: true, mode: 448 });
79573
+ const p3 = join45(d, "slot.enc");
79574
+ writeFileSync19(p3, encryptSecret(JSON.stringify(slot)), { mode: 384 });
79575
+ chmodSync11(p3, 384);
79576
+ }
79577
+ function readKeychain(io) {
79578
+ try {
79579
+ return io.run(["find-generic-password", "-s", "gemini", "-a", "antigravity", "-w"]).trim() || null;
79580
+ } catch {
79581
+ return null;
79582
+ }
79583
+ }
79584
+ var shq2 = (s2) => `'${s2.replace(/'/g, "'\\''")}'`;
79585
+ function writeKeychain(value, io) {
79586
+ try {
79587
+ io.run(["delete-generic-password", "-s", "gemini", "-a", "antigravity"]);
79588
+ } catch {
79589
+ }
79590
+ if (value) io.run(["-i"], `add-generic-password -U -s gemini -a antigravity -w ${shq2(value)}
79591
+ `);
79592
+ }
79593
+ function captureActiveSlot(io = fsAgyIo()) {
79594
+ writeSlot(activeAgyAccount(io), { keychain: readKeychain(io), file: io.readFile(io.tokenFile) }, io);
79595
+ }
79596
+ function activateAgyAccount(targetId, io = fsAgyIo()) {
79597
+ if (activeAgyAccount(io) === targetId) return;
79598
+ if (io.liveAgyAccountIds().length > 0)
79599
+ throw new AccountError("antigravity-account-busy", 409, "masih ada sesi Antigravity yang berjalan dengan akun lain \u2014 tutup dulu sesinya");
79600
+ captureActiveSlot(io);
79601
+ const slot = readSlot(targetId, io) ?? { keychain: null, file: null };
79602
+ writeKeychain(slot.keychain, io);
79603
+ if (slot.file) io.writeFile(io.tokenFile, slot.file);
79604
+ else io.removeFile(io.tokenFile);
79605
+ mkdirSync19(io.accountsDir, { recursive: true, mode: 448 });
79606
+ io.writeFile(activeFile(io), targetId);
79607
+ }
79608
+ function emailOf(raw) {
79609
+ try {
79610
+ let s2 = raw.trim();
79611
+ const prefix = "go-keyring-base64:";
79612
+ if (s2.startsWith(prefix)) s2 = Buffer.from(s2.slice(prefix.length), "base64").toString("utf8");
79613
+ const e = JSON.parse(s2).id_token_email;
79614
+ return typeof e === "string" && e ? e : void 0;
79615
+ } catch {
79616
+ return void 0;
79617
+ }
79618
+ }
79619
+ function rawLogin(accountId, io) {
79620
+ if (activeAgyAccount(io) === accountId) return readKeychain(io) ?? io.readFile(io.tokenFile);
79621
+ const s2 = readSlot(accountId, io);
79622
+ return s2?.keychain ?? s2?.file ?? null;
79623
+ }
79624
+ function probeAgyLogin(accountId, io = fsAgyIo()) {
79625
+ const raw = rawLogin(accountId, io);
79626
+ if (!raw || !parseAgyToken(raw)) return { loggedIn: false, identity: null };
79627
+ const email = emailOf(raw);
79628
+ return { loggedIn: true, identity: email ? { email } : {} };
79629
+ }
79630
+ var UNAVAILABLE3 = { status: "unavailable", windows: [], fetchedAt: null };
79631
+ async function agyAccountLimits(accountId, io = fsAgyIo()) {
79632
+ if (process.platform !== "darwin") return UNAVAILABLE3;
79633
+ const raw = rawLogin(accountId, io);
79634
+ const tok = raw ? parseAgyToken(raw) : null;
79635
+ if (!tok || tok.expiry !== null && tok.expiry - EXPIRY_SKEW_MS <= Date.now()) return UNAVAILABLE3;
79636
+ const windows = await fetchAgyWindows(tok, defaultProject(), fetch);
79637
+ return windows ? { status: "ok", windows, fetchedAt: (/* @__PURE__ */ new Date()).toISOString() } : UNAVAILABLE3;
79638
+ }
79639
+
79640
+ // src/services/runtime-accounts/resolver.ts
79641
+ function accountEnv(runtime, homeDir) {
79642
+ if (runtime === "claude") return { env: { CLAUDE_CONFIG_DIR: homeDir }, unset: ["CLAUDE_CODE_OAUTH_TOKEN", "ANTHROPIC_API_KEY"] };
79643
+ if (runtime === "codex") return { env: { CODEX_HOME: homeDir }, unset: [] };
79644
+ return { env: {}, unset: [] };
79645
+ }
79646
+ var prodDeps3 = () => ({
79647
+ sandbox: sessionSandboxOn(),
79648
+ warn: (m) => console.warn(m),
79649
+ ...process.platform === "darwin" ? { activateAgy: (id2) => activateAgyAccount(id2) } : {}
79650
+ });
79651
+ var AGY_BUILTIN = builtinAccountId("antigravity");
79652
+ function resolveAgy(requested, deps) {
79653
+ const snap = accountSnapshot();
79654
+ const rows = snap.rows.filter((r) => r.runtime === "antigravity");
79655
+ if (!rows.length || !deps.activateAgy) return null;
79656
+ const target3 = requested ?? snap.defaults.antigravity ?? AGY_BUILTIN;
79657
+ const row = rows.find((r) => r.id === target3);
79658
+ if (!isBuiltinAccountId(target3) && !row) deps.warn(`hanoman: akun Antigravity ${target3} tak ditemukan \u2014 memakai akun bawaan`);
79659
+ if (row && !requested && row.status !== "aktif")
79660
+ deps.warn(`hanoman: akun default Antigravity "${row.label}" berstatus ${row.status} \u2014 sesi memakai akun bawaan`);
79661
+ const id2 = row && (requested || row.status === "aktif") ? row.id : AGY_BUILTIN;
79662
+ deps.activateAgy(id2);
79663
+ return id2 === AGY_BUILTIN ? null : { id: id2, env: {}, unset: [] };
79664
+ }
79665
+ function resolveLaunchAccount(agent, requested, deps = prodDeps3()) {
79666
+ if (deps.sandbox) return null;
79667
+ if (agent === "antigravity") return resolveAgy(requested, deps);
79668
+ const snap = accountSnapshot();
79669
+ const id2 = requested ?? snap.defaults[agent];
79670
+ if (!id2 || isBuiltinAccountId(id2)) return null;
79671
+ const row = snap.rows.find((r) => r.id === id2 && r.runtime === agent);
79672
+ if (!row) {
79673
+ deps.warn(`hanoman: akun runtime ${id2} tak ditemukan untuk ${agent} \u2014 memakai akun bawaan`);
79674
+ return null;
79675
+ }
79676
+ if (!requested && row.status !== "aktif") {
79677
+ deps.warn(`hanoman: akun default ${agent} "${row.label}" berstatus ${row.status} \u2014 sesi memakai akun bawaan`);
79678
+ return null;
79679
+ }
79680
+ try {
79681
+ prepareAccountHome(agent, row.homeDir);
79682
+ } catch (e) {
79683
+ deps.warn(`hanoman: menyiapkan home akun "${row.label}" gagal: ${e.message}`);
79684
+ }
79685
+ return { id: row.id, ...accountEnv(agent, row.homeDir) };
79686
+ }
79687
+ async function assertLaunchAccount(agent, requested, sandbox = sessionSandboxOn()) {
79688
+ if (!requested) return;
79689
+ if (isBuiltinAccountId(requested)) {
79690
+ if (requested !== builtinAccountId(agent))
79691
+ throw new AccountError("account-runtime-mismatch", 409, `${requested} bukan akun bawaan ${agent}`);
79692
+ assertAgyFree(agent, requested);
79693
+ return;
79694
+ }
79695
+ const row = await prisma.runtimeAccount.findUnique({ where: { id: requested } });
79696
+ if (!row) throw new AccountError("account-not-found", 404, `akun ${requested} tak ditemukan`);
79697
+ if (row.runtime !== agent) throw new AccountError("account-runtime-mismatch", 409, `akun "${row.label}" milik ${row.runtime}, bukan ${agent}`);
79698
+ if (sandbox) throw new AccountError("account-sandbox-unsupported", 409, "sandbox sesi hanya mendukung akun bawaan");
79699
+ if (row.status !== "aktif") throw new AccountError("account-not-logged-in", 409, `akun "${row.label}" belum login`);
79700
+ assertAgyFree(agent, requested);
79701
+ }
79702
+ function assertAgyFree(agent, requested) {
79703
+ if (agent !== "antigravity" || process.platform !== "darwin") return;
79704
+ if (!accountSnapshot().rows.some((r) => r.runtime === "antigravity")) return;
79705
+ if (activeAgyAccount() === requested) return;
79706
+ if (liveAgySessions().length > 0)
79707
+ throw new AccountError("antigravity-account-busy", 409, "masih ada sesi Antigravity yang berjalan dengan akun lain \u2014 tutup dulu sesinya");
79708
+ }
79709
+
78969
79710
  // src/routes/terminal.ts
78970
79711
  init_notifications2();
78971
79712
  init_stage_machine();
@@ -79040,11 +79781,11 @@ init_uploads();
79040
79781
  // src/services/agent-invocations.ts
79041
79782
  init_src();
79042
79783
  init_db();
79043
- import { createHash as createHash19, randomUUID as randomUUID12 } from "node:crypto";
79044
- import { execFileSync as execFileSync8 } from "node:child_process";
79045
- import { homedir as homedir10 } from "node:os";
79046
- import { readFileSync as readFileSync20, realpathSync as realpathSync11, statSync as statSync7 } from "node:fs";
79047
- import { isAbsolute as isAbsolute12, relative as relative8, resolve as resolve23 } from "node:path";
79784
+ import { createHash as createHash20, randomUUID as randomUUID13 } from "node:crypto";
79785
+ import { execFileSync as execFileSync9 } from "node:child_process";
79786
+ import { homedir as homedir12 } from "node:os";
79787
+ import { readFileSync as readFileSync23, realpathSync as realpathSync11, statSync as statSync7 } from "node:fs";
79788
+ import { isAbsolute as isAbsolute12, relative as relative8, resolve as resolve24 } from "node:path";
79048
79789
 
79049
79790
  // src/services/session-event-relay.ts
79050
79791
  init_session_event_token();
@@ -79052,7 +79793,7 @@ init_session_event_spool();
79052
79793
  init_ingress_policy();
79053
79794
  import { constants as constants4 } from "node:fs";
79054
79795
  import { mkdir as mkdir8, open as open4, readdir as readdir9, rm as rm7 } from "node:fs/promises";
79055
- import { join as join42 } from "node:path";
79796
+ import { join as join46 } from "node:path";
79056
79797
  var MAX_EVENT_BYTES = 1e6;
79057
79798
  var MAX_FILES_PER_DRAIN = 1e3;
79058
79799
  var SESSION_ID_RE = /^[a-z0-9_-]+$/;
@@ -79103,7 +79844,7 @@ async function drainSpool(app3, root, observation, host2) {
79103
79844
  let readBuffer;
79104
79845
  for (const session of await readdir9(root, { withFileTypes: true })) {
79105
79846
  if (!session.isDirectory() || !SESSION_ID_RE.test(session.name)) continue;
79106
- const dir2 = join42(root, session.name);
79847
+ const dir2 = join46(root, session.name);
79107
79848
  let entries4;
79108
79849
  try {
79109
79850
  entries4 = await readdir9(dir2, { withFileTypes: true });
@@ -79115,7 +79856,7 @@ async function drainSpool(app3, root, observation, host2) {
79115
79856
  if (!entry2.isFile() || !entry2.name.endsWith(".json")) continue;
79116
79857
  const eventAt = /^(\d{1,15})-/.exec(entry2.name)?.[1];
79117
79858
  if (++examined > MAX_FILES_PER_DRAIN) return delivered;
79118
- const path = join42(dir2, entry2.name);
79859
+ const path = join46(dir2, entry2.name);
79119
79860
  let payload;
79120
79861
  let handle;
79121
79862
  try {
@@ -79202,10 +79943,10 @@ var MAX_TRANSCRIPT_BYTES2 = 10 * 1024 * 1024;
79202
79943
  var ANSI2 = /[\u001b\u009b](?:\][^\u0007]*(?:\u0007|\u001b\\)|\[[0-?]*[ -/]*[@-~]|[@-_])/g;
79203
79944
  var snapshotHashes = /* @__PURE__ */ new Map();
79204
79945
  var keyOf = (x) => `${x.sessionId}\0${x.runtimeInvocationId}`;
79205
- var hash3 = (value) => createHash19("sha256").update(value).digest("hex");
79946
+ var hash3 = (value) => createHash20("sha256").update(value).digest("hex");
79206
79947
  var defaultGitStatus = (cwd) => {
79207
79948
  try {
79208
- return execFileSync8("git", ["-C", cwd, "status", "--porcelain=v1", "-z"], {
79949
+ return execFileSync9("git", ["-C", cwd, "status", "--porcelain=v1", "-z"], {
79209
79950
  encoding: "utf8",
79210
79951
  stdio: ["ignore", "pipe", "ignore"]
79211
79952
  });
@@ -79213,7 +79954,7 @@ var defaultGitStatus = (cwd) => {
79213
79954
  return null;
79214
79955
  }
79215
79956
  };
79216
- function snapshot2(cwd, run6 = defaultGitStatus) {
79957
+ function snapshot3(cwd, run6 = defaultGitStatus) {
79217
79958
  try {
79218
79959
  const value = run6(cwd);
79219
79960
  return value === null ? null : hash3(value);
@@ -79233,8 +79974,11 @@ var utf8Prefix = (value, maxBytes) => {
79233
79974
  return out4;
79234
79975
  };
79235
79976
  var transcriptRoots = () => [
79236
- resolve23(process.env.CLAUDE_CONFIG_DIR ?? `${homedir10()}/.claude`),
79237
- resolve23(process.env.CODEX_HOME ?? `${homedir10()}/.codex`)
79977
+ resolve24(process.env.CLAUDE_CONFIG_DIR ?? `${homedir12()}/.claude`),
79978
+ resolve24(process.env.CODEX_HOME ?? `${homedir12()}/.codex`),
79979
+ // ADR-0234 · home akun runtime (CLAUDE_CONFIG_DIR/CODEX_HOME per sesi). Transkrip claude akun lewat
79980
+ // symlink `projects/` tetap berada di bawah akar ini.
79981
+ resolve24(accountsRoot())
79238
79982
  ];
79239
79983
  var inside = (path, root) => {
79240
79984
  const rel = relative8(root, path);
@@ -79315,7 +80059,7 @@ function transcriptUsage(path, roots = transcriptRoots()) {
79315
80059
  if (!safeRoots.some((root) => inside(real2, root))) return EMPTY_USAGE;
79316
80060
  const info = statSync7(real2);
79317
80061
  if (!info.isFile() || info.size > MAX_TRANSCRIPT_BYTES2) return EMPTY_USAGE;
79318
- return usageFromText(readFileSync20(real2, "utf8"));
80062
+ return usageFromText(readFileSync23(real2, "utf8"));
79319
80063
  } catch {
79320
80064
  return EMPTY_USAGE;
79321
80065
  }
@@ -79333,7 +80077,7 @@ async function startAgentInvocation(input, io = {}) {
79333
80077
  where: { id: existing.id },
79334
80078
  data: { status: "running", endedAt: null, durationMs: null }
79335
80079
  });
79336
- const before3 = snapshot2(input.cwd, io.gitStatus);
80080
+ const before3 = snapshot3(input.cwd, io.gitStatus);
79337
80081
  if (before3 !== null) snapshotHashes.set(keyOf(input), before3);
79338
80082
  return { row: row2, duplicate: false };
79339
80083
  }
@@ -79344,7 +80088,7 @@ async function startAgentInvocation(input, io = {}) {
79344
80088
  } },
79345
80089
  update: {},
79346
80090
  create: {
79347
- id: randomUUID12(),
80091
+ id: randomUUID13(),
79348
80092
  sessionId: input.sessionId,
79349
80093
  projectId: input.projectId,
79350
80094
  specId: input.specId ?? null,
@@ -79360,7 +80104,7 @@ async function startAgentInvocation(input, io = {}) {
79360
80104
  startedAt
79361
80105
  }
79362
80106
  });
79363
- const before2 = snapshot2(input.cwd, io.gitStatus);
80107
+ const before2 = snapshot3(input.cwd, io.gitStatus);
79364
80108
  if (before2 !== null) snapshotHashes.set(keyOf(input), before2);
79365
80109
  return { row, duplicate: existing !== null };
79366
80110
  }
@@ -79376,7 +80120,7 @@ async function stopAgentInvocation(input, io = {}) {
79376
80120
  const cleanResult = input.result === void 0 ? null : stripAnsi(input.result);
79377
80121
  const usage2 = transcriptUsage(input.transcriptPath, io.transcriptRoots);
79378
80122
  const before2 = snapshotHashes.get(keyOf(input));
79379
- const after = snapshot2(input.cwd, io.gitStatus);
80123
+ const after = snapshot3(input.cwd, io.gitStatus);
79380
80124
  snapshotHashes.delete(keyOf(input));
79381
80125
  const evidence = {
79382
80126
  // Stop tanpa start lazim setelah restart server di tengah invocation. Waktu start dan status
@@ -79398,7 +80142,7 @@ async function stopAgentInvocation(input, io = {}) {
79398
80142
  }
79399
80143
  const row = await prisma.agentInvocation.create({
79400
80144
  data: {
79401
- id: randomUUID12(),
80145
+ id: randomUUID13(),
79402
80146
  sessionId: input.sessionId,
79403
80147
  projectId: input.projectId,
79404
80148
  specId: input.specId ?? null,
@@ -79600,25 +80344,25 @@ init_ask();
79600
80344
  // src/services/decision-guard.ts
79601
80345
  init_src2();
79602
80346
  init_db();
79603
- import { mkdirSync as mkdirSync18, readFileSync as readFileSync21, readdirSync as readdirSync11, rmSync as rmSync12, statSync as statSync8, writeFileSync as writeFileSync18 } from "node:fs";
79604
- import { join as join43 } from "node:path";
80347
+ import { mkdirSync as mkdirSync20, readFileSync as readFileSync24, readdirSync as readdirSync11, rmSync as rmSync14, statSync as statSync8, writeFileSync as writeFileSync20 } from "node:fs";
80348
+ import { join as join47 } from "node:path";
79605
80349
  var SESSION_HEADER = "x-hanoman-session";
79606
80350
  var SAFE_ID = /^[A-Za-z0-9._-]{1,200}$/;
79607
80351
  var launchers = /* @__PURE__ */ new Map();
79608
80352
  var STALE_MS = 30 * 24 * 60 * 6e4;
79609
- var launcherDir = (env = process.env) => join43(resolveHome(env), "session-launchers");
80353
+ var launcherDir = (env = process.env) => join47(resolveHome(env), "session-launchers");
79610
80354
  function recordLauncher(sessionId2, agentId, env = process.env) {
79611
80355
  if (!SAFE_ID.test(sessionId2)) return;
79612
80356
  const known2 = launchersFor(sessionId2, env);
79613
80357
  known2.add(agentId);
79614
80358
  try {
79615
80359
  const dir2 = launcherDir(env);
79616
- mkdirSync18(dir2, { recursive: true, mode: 448 });
79617
- writeFileSync18(join43(dir2, sessionId2), [...known2].join("\n"), { mode: 384 });
80360
+ mkdirSync20(dir2, { recursive: true, mode: 448 });
80361
+ writeFileSync20(join47(dir2, sessionId2), [...known2].join("\n"), { mode: 384 });
79618
80362
  const now = Date.now();
79619
80363
  for (const f of readdirSync11(dir2)) {
79620
80364
  try {
79621
- if (now - statSync8(join43(dir2, f)).mtimeMs > STALE_MS) rmSync12(join43(dir2, f), { force: true });
80365
+ if (now - statSync8(join47(dir2, f)).mtimeMs > STALE_MS) rmSync14(join47(dir2, f), { force: true });
79622
80366
  } catch {
79623
80367
  }
79624
80368
  }
@@ -79630,7 +80374,7 @@ function launchersFor(sessionId2, env) {
79630
80374
  if (hot) return hot;
79631
80375
  const ids = /* @__PURE__ */ new Set();
79632
80376
  try {
79633
- for (const l of readFileSync21(join43(launcherDir(env), sessionId2), "utf8").split("\n")) if (l.trim()) ids.add(l.trim());
80377
+ for (const l of readFileSync24(join47(launcherDir(env), sessionId2), "utf8").split("\n")) if (l.trim()) ids.add(l.trim());
79634
80378
  } catch {
79635
80379
  }
79636
80380
  launchers.set(sessionId2, ids);
@@ -79703,6 +80447,7 @@ async function terminal_default(app3, opts2) {
79703
80447
  const setting = await getSetting();
79704
80448
  const agent2 = parsed.data.agent ?? setting.agent;
79705
80449
  validatePhaseOverrides(agent2, parsed.data.phaseOverrides);
80450
+ await assertLaunchAccount(agent2, parsed.data.account);
79706
80451
  const requestedGoal = parsed.data.flow === "goal" || parsed.data.flow === "no_effort" || (parsed.data.goal ?? setting.goal.enabled);
79707
80452
  if (agent2 === "antigravity") await withSessionAdmission({ id: sessionIdForSpec(spec.id), force: parsed.data.force }, async () => {
79708
80453
  assertAntigravityLaunch(agent2, requestedGoal);
@@ -79719,6 +80464,8 @@ async function terminal_default(app3, opts2) {
79719
80464
  // SPEC-332 · ADR-0073
79720
80465
  agent: parsed.data.agent,
79721
80466
  // SPEC-338 · ADR-0074
80467
+ accountId: parsed.data.account,
80468
+ // ADR-0234
79722
80469
  verifyScope: parsed.data.verifyScope,
79723
80470
  // SPEC-376 · ADR-0080
79724
80471
  method: parsed.data.method,
@@ -79732,6 +80479,7 @@ async function terminal_default(app3, opts2) {
79732
80479
  });
79733
80480
  return reply.code(201).send(r.resumed ? { id: r.id, resumed: true } : { id: r.id });
79734
80481
  } catch (e) {
80482
+ if (e instanceof AccountError) return reply.code(e.status).send({ error: e.code, message: e.message });
79735
80483
  if (e instanceof LaunchError) {
79736
80484
  if (e.kind === "blocked")
79737
80485
  return reply.code(409).send({ error: e.message, blocked: true, blockers: e.blockers });
@@ -79943,21 +80691,28 @@ async function terminal_default(app3, opts2) {
79943
80691
  return reply.code(result.code).send(result.body);
79944
80692
  }
79945
80693
  const { agent, model, effort: effort2 } = await terminalAgentDefaults(parsed.data);
80694
+ const account = parsed.data.account;
80695
+ try {
80696
+ await assertLaunchAccount(agent, account);
80697
+ } catch (e) {
80698
+ if (e instanceof AccountError) return reply.code(e.status).send({ error: e.code, message: e.message });
80699
+ throw e;
80700
+ }
79946
80701
  if (agent === "codex") ensureCodexTrust(repoDir);
79947
80702
  if (parsed.data.worktree) {
79948
- const id2 = `term-${randomUUID13().slice(0, 8)}`;
80703
+ const id2 = `term-${randomUUID14().slice(0, 8)}`;
79949
80704
  const branch = `term/${id2.slice("term-".length)}`;
79950
80705
  const from = parsed.data.branchFrom ?? "HEAD";
79951
80706
  const result = await withSessionAdmission({ id: id2, exempt: false, force: parsed.data.force }, async () => {
79952
80707
  const wt = `${repoDir}/.worktrees/${id2}`;
79953
80708
  try {
79954
80709
  realGit.addWorktree(repoDir, wt, from);
79955
- execFileSync9("git", ["switch", "-q", "-c", branch], { cwd: wt, stdio: "pipe" });
80710
+ execFileSync10("git", ["switch", "-q", "-c", branch], { cwd: wt, stdio: "pipe" });
79956
80711
  } catch (e) {
79957
80712
  if (ownsWorktree(repoDir, wt)) realGit.removeWorktree(repoDir, wt);
79958
80713
  return { code: 422, body: { error: `gagal membuat worktree dari "${from}": ${e.message}` } };
79959
80714
  }
79960
- const s3 = createSession(project.id, wt, { id: id2, agent, model, effort: effort2, branch });
80715
+ const s3 = createSession(project.id, wt, { id: id2, agent, model, effort: effort2, branch, accountId: account });
79961
80716
  return { code: 201, body: { id: s3.id } };
79962
80717
  }, (pane) => ({ code: 201, body: { id: pane.id } }));
79963
80718
  return reply.code(result.code).send(result.body);
@@ -79967,7 +80722,7 @@ async function terminal_default(app3, opts2) {
79967
80722
  const s2 = await createOperatorSession(
79968
80723
  project.id,
79969
80724
  repoDir,
79970
- { agent, model, effort: effort2 },
80725
+ { agent, model, effort: effort2, accountId: account },
79971
80726
  { exempt: false, force: parsed.data.force }
79972
80727
  );
79973
80728
  return reply.code(201).send({ id: s2.id });
@@ -80082,7 +80837,7 @@ async function terminal_default(app3, opts2) {
80082
80837
  if (!repoDir) return { ok: false, code: 409, msg: "project belum punya repoDir" };
80083
80838
  if (!s2.cwd.includes("/.worktrees/"))
80084
80839
  return { ok: false, code: 409, msg: "belum ada worktree untuk di-review \u2014 jalankan/lanjutkan sesi dulu", empty: "no-worktree" };
80085
- if (!existsSync21(s2.cwd))
80840
+ if (!existsSync22(s2.cwd))
80086
80841
  return { ok: false, code: 409, msg: "belum ada worktree untuk di-review \u2014 jalankan/lanjutkan sesi dulu", empty: "no-commit" };
80087
80842
  return { ok: true, id: s2.id, repoDir };
80088
80843
  };
@@ -80345,8 +81100,8 @@ async function terminalWorkspaceRoutes(app3) {
80345
81100
  // src/routes/vps.ts
80346
81101
  init_db();
80347
81102
  init_src();
80348
- import { readFileSync as readFileSync26, existsSync as existsSync24 } from "node:fs";
80349
- import { homedir as homedir12 } from "node:os";
81103
+ import { readFileSync as readFileSync29, existsSync as existsSync25 } from "node:fs";
81104
+ import { homedir as homedir14 } from "node:os";
80350
81105
 
80351
81106
  // src/vps/catalog/catalog.data.ts
80352
81107
  var RAW_SECTIONS = [{ "id": "ssh", "title": "SSH Hardening", "icon": "\u{1F511}", "count": 14 }, { "id": "firewall", "title": "Firewall & Network", "icon": "\u{1F525}", "count": 14 }, { "id": "aapanel", "title": "aaPanel Security", "icon": "\u{1F5A5}\uFE0F", "count": 14 }, { "id": "user", "title": "User & Permission Management", "icon": "\u{1F464}", "count": 14 }, { "id": "system", "title": "System Hardening (OS Level)", "icon": "\u2699\uFE0F", "count": 16 }, { "id": "webserver", "title": "Web Server Hardening", "icon": "\u{1F310}", "count": 14 }, { "id": "database", "title": "Database Security", "icon": "\u{1F5C4}\uFE0F", "count": 15 }, { "id": "ssl", "title": "SSL/TLS & Enkripsi", "icon": "\u{1F512}", "count": 13 }, { "id": "ids", "title": "Intrusion Detection & Prevention", "icon": "\u{1F6A8}", "count": 9 }, { "id": "logging", "title": "Logging & Monitoring", "icon": "\u{1F4CA}", "count": 13 }, { "id": "backup", "title": "Backup & Disaster Recovery", "icon": "\u{1F4BE}", "count": 12 }, { "id": "ddos", "title": "DDoS Protection", "icon": "\u{1F30A}", "count": 11 }, { "id": "kernel", "title": "Kernel Hardening", "icon": "\u{1F9E0}", "count": 12 }, { "id": "malware", "title": "File Integrity & Malware Detection", "icon": "\u{1F9A0}", "count": 7 }, { "id": "enterprise", "title": "Advanced Enterprise & Government Level", "icon": "\u{1F3E2}", "count": 31 }, { "id": "checklist", "title": "Checklist Rutin", "icon": "\u2705", "count": 23 }];
@@ -80553,14 +81308,14 @@ function resolveComponents(ids, profile) {
80553
81308
  }
80554
81309
 
80555
81310
  // src/services/vps-provision.ts
80556
- import { readFileSync as readFileSync23 } from "node:fs";
81311
+ import { readFileSync as readFileSync26 } from "node:fs";
80557
81312
 
80558
81313
  // src/services/vps-ssh.ts
80559
81314
  init_config2();
80560
81315
  import { spawn as spawn6 } from "node:child_process";
80561
- import { mkdtempSync as mkdtempSync4, rmSync as rmSync13, writeFileSync as writeFileSync19 } from "node:fs";
81316
+ import { mkdtempSync as mkdtempSync4, rmSync as rmSync15, writeFileSync as writeFileSync21 } from "node:fs";
80562
81317
  import { tmpdir as tmpdir7 } from "node:os";
80563
- import { dirname as dirname17, join as join44 } from "node:path";
81318
+ import { dirname as dirname17, join as join48 } from "node:path";
80564
81319
  var sshBin = () => effectiveStr("HANOMAN_SSH_BIN") ?? "ssh";
80565
81320
  function consoleArgv(t) {
80566
81321
  return [
@@ -80575,9 +81330,9 @@ function consoleArgv(t) {
80575
81330
  ];
80576
81331
  }
80577
81332
  function askpassScript() {
80578
- const dir2 = mkdtempSync4(join44(tmpdir7(), "hanoman-askpass-"));
80579
- const path = join44(dir2, "askpass.sh");
80580
- writeFileSync19(path, `#!/bin/sh
81333
+ const dir2 = mkdtempSync4(join48(tmpdir7(), "hanoman-askpass-"));
81334
+ const path = join48(dir2, "askpass.sh");
81335
+ writeFileSync21(path, `#!/bin/sh
80581
81336
  printf '%s' "$HANOMAN_SSH_PASSWORD"
80582
81337
  `, { mode: 448 });
80583
81338
  return path;
@@ -80610,14 +81365,14 @@ function sshExec(t, remoteCmd, opts2 = {}) {
80610
81365
  SSH_ASKPASS_REQUIRE: "force",
80611
81366
  HANOMAN_SSH_PASSWORD: opts2.password
80612
81367
  } : process.env;
80613
- return new Promise((resolve25) => {
81368
+ return new Promise((resolve26) => {
80614
81369
  const p3 = spawn6(sshBin(), args, { stdio: ["pipe", "pipe", "pipe"], env });
80615
81370
  let out4 = "";
80616
81371
  const timer11 = setTimeout(() => p3.kill("SIGKILL"), opts2.timeoutMs ?? 6e4);
80617
81372
  const done = (r) => {
80618
81373
  clearTimeout(timer11);
80619
- if (askpass) rmSync13(dirname17(askpass), { recursive: true, force: true });
80620
- resolve25(r);
81374
+ if (askpass) rmSync15(dirname17(askpass), { recursive: true, force: true });
81375
+ resolve26(r);
80621
81376
  };
80622
81377
  p3.stdout.on("data", (d) => {
80623
81378
  out4 += d;
@@ -80637,8 +81392,8 @@ function sshExec(t, remoteCmd, opts2 = {}) {
80637
81392
  // src/services/vps-audit.ts
80638
81393
  init_db();
80639
81394
  init_deps();
80640
- import { existsSync as existsSync22, readFileSync as readFileSync22 } from "node:fs";
80641
- import { join as join45 } from "node:path";
81395
+ import { existsSync as existsSync23, readFileSync as readFileSync25 } from "node:fs";
81396
+ import { join as join49 } from "node:path";
80642
81397
  import { fileURLToPath as fileURLToPath5 } from "node:url";
80643
81398
  init_sync_notify();
80644
81399
 
@@ -80743,7 +81498,7 @@ var packagedScript = (f) => fileURLToPath5(new URL(`../scripts/vps/${f}`, import
80743
81498
  var moduleDir2 = () => fileURLToPath5(new URL(".", import.meta.url));
80744
81499
  var scriptPath = (f) => {
80745
81500
  const packed = packagedScript(f);
80746
- return existsSync22(packed) ? packed : join45(repoRoot(moduleDir2()), "server", "scripts", "vps", f);
81501
+ return existsSync23(packed) ? packed : join49(repoRoot(moduleDir2()), "server", "scripts", "vps", f);
80747
81502
  };
80748
81503
  async function itemStatesOf(vpsId) {
80749
81504
  const rows = await prisma.vpsItemState.findMany({ where: { vpsId } });
@@ -80753,7 +81508,7 @@ async function runAudit(v) {
80753
81508
  const r = await sshExec(
80754
81509
  target2(v),
80755
81510
  "sudo -n bash -s",
80756
- { stdin: readFileSync22(scriptPath("audit.sh"), "utf8"), timeoutMs: 6e4 }
81511
+ { stdin: readFileSync25(scriptPath("audit.sh"), "utf8"), timeoutMs: 6e4 }
80757
81512
  );
80758
81513
  const audit = parseAudit(r.out);
80759
81514
  if (r.code !== 0 || audit.length === 0) return { ok: false, out: r.out };
@@ -80833,7 +81588,7 @@ function parseProvisionSteps(out4) {
80833
81588
  return m ? [{ item: m[1], status: m[2], detail: (m[3] ?? "").trim() }] : [];
80834
81589
  });
80835
81590
  }
80836
- var script = () => readFileSync23(scriptPath("provision.sh"), "utf8");
81591
+ var script = () => readFileSync26(scriptPath("provision.sh"), "utf8");
80837
81592
  async function probeComponents(v) {
80838
81593
  const r = await sshExec(v, "env MODE=probe bash -s", { stdin: script(), timeoutMs: PROBE_TIMEOUT_MS });
80839
81594
  const components2 = parseComponents(r.out);
@@ -80860,7 +81615,7 @@ async function readSetupToken(v, home3 = "/var/lib/hanoman") {
80860
81615
  }
80861
81616
 
80862
81617
  // src/services/vps-remediate.ts
80863
- import { readFileSync as readFileSync24 } from "node:fs";
81618
+ import { readFileSync as readFileSync27 } from "node:fs";
80864
81619
  function parseSteps2(out4) {
80865
81620
  return out4.split("\n").flatMap((line) => {
80866
81621
  const m = line.match(/^STEP (\S+) (would|ok|fail)(?: (.*))?$/);
@@ -80871,7 +81626,7 @@ async function remediate(v, items, dryRun) {
80871
81626
  const r = await sshExec(
80872
81627
  v,
80873
81628
  `sudo -n env ITEMS=${items.join(",")} SSH_PORT=${v.port} DRY_RUN=${dryRun ? "1" : ""} bash -s`,
80874
- { stdin: readFileSync24(scriptPath("remediate.sh"), "utf8"), timeoutMs: 3e5 }
81629
+ { stdin: readFileSync27(scriptPath("remediate.sh"), "utf8"), timeoutMs: 3e5 }
80875
81630
  );
80876
81631
  return { ok: r.code === 0, steps: parseSteps2(r.out), out: r.out };
80877
81632
  }
@@ -80987,39 +81742,39 @@ async function listVpsWithScore() {
80987
81742
  // src/services/vps-key.ts
80988
81743
  init_src2();
80989
81744
  init_config2();
80990
- import { execFileSync as execFileSync10 } from "node:child_process";
80991
- import { chmodSync as chmodSync10, copyFileSync, existsSync as existsSync23, mkdirSync as mkdirSync19, readFileSync as readFileSync25, unlinkSync as unlinkSync5 } from "node:fs";
80992
- import { homedir as homedir11 } from "node:os";
80993
- import { join as join46 } from "node:path";
81745
+ import { execFileSync as execFileSync11 } from "node:child_process";
81746
+ import { chmodSync as chmodSync12, copyFileSync, existsSync as existsSync24, mkdirSync as mkdirSync21, readFileSync as readFileSync28, unlinkSync as unlinkSync5 } from "node:fs";
81747
+ import { homedir as homedir13 } from "node:os";
81748
+ import { join as join50 } from "node:path";
80994
81749
  var keyDir = () => effectiveStr("HANOMAN_SSH_KEY_DIR") ?? resolveDataDirs().sshKeys;
80995
81750
  var KEY_FILES = ["id_ed25519", "id_ed25519.pub"];
80996
81751
  function adoptLegacyKey(dir2) {
80997
81752
  if (effectiveStr("HANOMAN_SSH_KEY_DIR")) return;
80998
- const legacy = join46(homedir11(), ".hanoman");
81753
+ const legacy = join50(homedir13(), ".hanoman");
80999
81754
  if (legacy === dir2) return;
81000
- if (!KEY_FILES.every((f) => existsSync23(join46(legacy, f)))) return;
81001
- mkdirSync19(dir2, { recursive: true, mode: 448 });
81755
+ if (!KEY_FILES.every((f) => existsSync24(join50(legacy, f)))) return;
81756
+ mkdirSync21(dir2, { recursive: true, mode: 448 });
81002
81757
  for (const f of KEY_FILES) {
81003
- copyFileSync(join46(legacy, f), join46(dir2, f));
81004
- chmodSync10(join46(dir2, f), 384);
81758
+ copyFileSync(join50(legacy, f), join50(dir2, f));
81759
+ chmodSync12(join50(dir2, f), 384);
81005
81760
  }
81006
- for (const f of KEY_FILES) unlinkSync5(join46(legacy, f));
81761
+ for (const f of KEY_FILES) unlinkSync5(join50(legacy, f));
81007
81762
  console.log(`vps: key SSH dipindah dari ${legacy} ke ${dir2} (SPEC-846 \u2014 satu batas backup)`);
81008
81763
  }
81009
81764
  function ensureHanomanKey() {
81010
81765
  const dir2 = keyDir();
81011
- const privPath = join46(dir2, KEY_FILES[0]);
81766
+ const privPath = join50(dir2, KEY_FILES[0]);
81012
81767
  const pubPath = `${privPath}.pub`;
81013
- if (!existsSync23(privPath)) adoptLegacyKey(dir2);
81014
- if (!existsSync23(privPath)) {
81015
- mkdirSync19(dir2, { recursive: true, mode: 448 });
81016
- execFileSync10(
81768
+ if (!existsSync24(privPath)) adoptLegacyKey(dir2);
81769
+ if (!existsSync24(privPath)) {
81770
+ mkdirSync21(dir2, { recursive: true, mode: 448 });
81771
+ execFileSync11(
81017
81772
  "ssh-keygen",
81018
81773
  ["-t", "ed25519", "-N", "", "-C", "hanoman", "-f", privPath],
81019
81774
  { stdio: ["ignore", "ignore", "pipe"] }
81020
81775
  );
81021
81776
  }
81022
- return { privPath, pubPath, pub: readFileSync25(pubPath, "utf8").trim() };
81777
+ return { privPath, pubPath, pub: readFileSync28(pubPath, "utf8").trim() };
81023
81778
  }
81024
81779
 
81025
81780
  // src/services/vps-bootstrap.ts
@@ -81039,7 +81794,7 @@ init_session_launch_gate();
81039
81794
  init_settings3();
81040
81795
  init_sync_notify();
81041
81796
  function keyMissing(v) {
81042
- return !!v.keyPath && !existsSync24(v.keyPath);
81797
+ return !!v.keyPath && !existsSync25(v.keyPath);
81043
81798
  }
81044
81799
  async function vps_default(app3) {
81045
81800
  app3.get("/vps", async () => listVpsWithScore());
@@ -81267,7 +82022,7 @@ async function vps_default(app3) {
81267
82022
  const r = await sshExec(
81268
82023
  v,
81269
82024
  `sudo -n env SSH_PORT=${v.port} SSH_USER=${v.user} bash -s`,
81270
- { stdin: readFileSync26(scriptPath("harden.sh"), "utf8"), timeoutMs: 3e5 }
82025
+ { stdin: readFileSync29(scriptPath("harden.sh"), "utf8"), timeoutMs: 3e5 }
81271
82026
  );
81272
82027
  if (r.code !== 0) return reply.code(502).send({ error: "harden gagal lewat ssh", transcript: r.out });
81273
82028
  const verify = await sshExec(v, "true", { timeoutMs: 3e4 });
@@ -81292,7 +82047,7 @@ async function vps_default(app3) {
81292
82047
  const v = await prisma.vps.findUnique({ where: { id: req.params.id } });
81293
82048
  if (!v) return reply.code(404).send({ error: "not found" });
81294
82049
  if (keyMissing(v)) return reply.code(409).send({ error: "key VPS tidak ada di mesin ini", keyMissing: true });
81295
- const s2 = await createOperatorSession(`vps-console:${v.id}`, homedir12(), { id: `vpsc-${v.id}`, command: consoleArgv(v) });
82050
+ const s2 = await createOperatorSession(`vps-console:${v.id}`, homedir14(), { id: `vpsc-${v.id}`, command: consoleArgv(v) });
81296
82051
  return reply.code(201).send({ id: s2.id });
81297
82052
  });
81298
82053
  app3.post("/vps/:id/session", async (req, reply) => {
@@ -81301,7 +82056,7 @@ async function vps_default(app3) {
81301
82056
  if (keyMissing(v)) return reply.code(409).send({ error: "key VPS tidak ada di mesin ini", keyMissing: true });
81302
82057
  const checks = v.audit ?? [];
81303
82058
  const { model, effort: effort2 } = await sessionModel();
81304
- const s2 = await createAgentSession(`vps:${v.id}`, homedir12(), {
82059
+ const s2 = await createAgentSession(`vps:${v.id}`, homedir14(), {
81305
82060
  model,
81306
82061
  effort: effort2,
81307
82062
  prompt: [
@@ -81320,10 +82075,213 @@ async function vps_default(app3) {
81320
82075
  init_limits();
81321
82076
  init_codex_limits();
81322
82077
  init_antigravity_limits();
82078
+
82079
+ // src/services/runtime-accounts/limits.ts
82080
+ init_config2();
82081
+ init_limits();
82082
+ init_codex_limits();
82083
+ init_antigravity_limits();
82084
+ init_keychain();
82085
+ import { readFileSync as readFileSync30 } from "node:fs";
82086
+ import { join as join51 } from "node:path";
82087
+ var TTL_MS5 = 3e4;
82088
+ var UNAVAILABLE4 = { status: "unavailable", windows: [], fetchedAt: null };
82089
+ function readClaudeAccountToken(homeDir, platform2 = process.platform) {
82090
+ if (platform2 === "darwin") {
82091
+ const t = readClaudeKeychainToken(claudeKeychainService(homeDir));
82092
+ if (t) return t;
82093
+ }
82094
+ try {
82095
+ const t = JSON.parse(readFileSync30(join51(homeDir, ".credentials.json"), "utf8"))?.claudeAiOauth?.accessToken;
82096
+ return typeof t === "string" && t ? t : null;
82097
+ } catch {
82098
+ return null;
82099
+ }
82100
+ }
82101
+ var antigravityAccount = async (_row) => UNAVAILABLE4;
82102
+ var antigravityBuiltin = () => getAntigravityLimits();
82103
+ function setAntigravityAccountLimits(account, builtin) {
82104
+ antigravityAccount = account;
82105
+ if (builtin) antigravityBuiltin = builtin;
82106
+ }
82107
+ var prodDeps4 = () => ({
82108
+ now: Date.now,
82109
+ fetchEnabled: effectiveStr("HANOMAN_ACCOUNT_LIMITS_FETCH") !== "0",
82110
+ builtin: { claude: getLimits, codex: () => getCodexLimits(), antigravity: () => antigravityBuiltin() },
82111
+ claudeToken: (h2) => readClaudeAccountToken(h2),
82112
+ claudeWindows: (t) => fetchClaudeWindows(t),
82113
+ codexLimits: (d) => getCodexLimits(d),
82114
+ antigravity: (row) => antigravityAccount(row)
82115
+ });
82116
+ var cache3 = /* @__PURE__ */ new Map();
82117
+ async function cached3(key, now, load2) {
82118
+ const e = cache3.get(key);
82119
+ if (e && now < e.freshUntil) return e.last;
82120
+ const dto = await load2();
82121
+ if (dto.status !== "unavailable") {
82122
+ cache3.set(key, { last: dto, freshUntil: now + TTL_MS5 });
82123
+ return dto;
82124
+ }
82125
+ return e ? { ...e.last, status: "stale" } : dto;
82126
+ }
82127
+ async function loadRow(row, d) {
82128
+ if (row.runtime === "claude") {
82129
+ const tok = d.claudeToken(row.homeDir);
82130
+ if (!tok) return UNAVAILABLE4;
82131
+ const windows = await d.claudeWindows(tok);
82132
+ return windows ? { status: "ok", windows, fetchedAt: new Date(d.now()).toISOString() } : UNAVAILABLE4;
82133
+ }
82134
+ if (row.runtime === "codex") {
82135
+ const c = await d.codexLimits(join51(row.homeDir, "sessions"));
82136
+ return { status: c.status, windows: c.windows, fetchedAt: c.fetchedAt };
82137
+ }
82138
+ return d.antigravity(row);
82139
+ }
82140
+ async function getAccountLimits(deps = prodDeps4()) {
82141
+ const rows = new Map(accountSnapshot().rows.map((r) => [r.id, r]));
82142
+ return Promise.all(listAccountDTOs().map(async (a) => {
82143
+ let limits2;
82144
+ const row = rows.get(a.id);
82145
+ if (a.builtin) {
82146
+ const b = await deps.builtin[a.runtime]();
82147
+ limits2 = { status: b.status, windows: b.windows, fetchedAt: b.fetchedAt };
82148
+ } else if (!deps.fetchEnabled || !row) limits2 = UNAVAILABLE4;
82149
+ else limits2 = await cached3(a.id, deps.now(), () => loadRow(row, deps));
82150
+ return { accountId: a.id, runtime: a.runtime, label: a.label, builtin: a.builtin, isDefault: a.isDefault, loginStatus: a.status, limits: limits2 };
82151
+ }));
82152
+ }
82153
+
82154
+ // src/routes/limits.ts
81323
82155
  async function limits(app3) {
81324
82156
  app3.get("/limits", async () => getLimits());
81325
82157
  app3.get("/limits/codex", async () => getCodexLimits());
81326
82158
  app3.get("/limits/antigravity", async () => getAntigravityLimits());
82159
+ app3.get("/limits/accounts", async () => getAccountLimits());
82160
+ }
82161
+
82162
+ // src/routes/runtime-accounts.ts
82163
+ init_src();
82164
+ init_pty();
82165
+ init_session_sandbox();
82166
+
82167
+ // src/services/runtime-accounts/login.ts
82168
+ init_src();
82169
+ init_pty();
82170
+ init_session_launch_gate();
82171
+ import { homedir as homedir15 } from "node:os";
82172
+ var LOGIN_PREFIX = "acct-login-";
82173
+ var loginSessionId = (accountId) => `${LOGIN_PREFIX}${accountId.replace(/[^a-z0-9]/gi, "-")}`;
82174
+ function accountIdForLoginSession(sessionId2) {
82175
+ if (!sessionId2.startsWith(LOGIN_PREFIX)) return null;
82176
+ const ids = [...zAgent.options.map((r) => builtinAccountId(r)), ...accountSnapshot().rows.map((r) => r.id)];
82177
+ return ids.find((id2) => loginSessionId(id2) === sessionId2) ?? null;
82178
+ }
82179
+ function loginArgv(runtime, opts2) {
82180
+ if (runtime === "claude") return [agentBin("claude"), "auth", "login", "--claudeai"];
82181
+ if (runtime === "codex") return [agentBin("codex"), "login", ...opts2.deviceAuth ? ["--device-auth"] : []];
82182
+ return antigravityLogin(opts2);
82183
+ }
82184
+ var antigravityLogin = (_opts) => {
82185
+ throw new AccountError("account-not-found", 404, "login Antigravity belum didukung");
82186
+ };
82187
+ function setAntigravityLogin(fn) {
82188
+ antigravityLogin = fn;
82189
+ }
82190
+ var beforeLogin = (_runtime, _accountId) => {
82191
+ };
82192
+ function setBeforeLogin(fn) {
82193
+ beforeLogin = fn;
82194
+ }
82195
+ async function openLoginSession(accountId, opts2) {
82196
+ const builtin = runtimeOfBuiltin(accountId);
82197
+ let runtime, homeDir = null, env = {};
82198
+ if (builtin) runtime = builtin;
82199
+ else {
82200
+ const row = accountSnapshot().rows.find((r) => r.id === accountId);
82201
+ if (!row) throw new AccountError("account-not-found", 404, `akun ${accountId} tak ditemukan`);
82202
+ runtime = row.runtime;
82203
+ homeDir = row.homeDir;
82204
+ prepareAccountHome(runtime, homeDir);
82205
+ env = accountEnv(runtime, homeDir).env;
82206
+ }
82207
+ const argv = loginArgv(runtime, opts2);
82208
+ beforeLogin(runtime, accountId);
82209
+ const s2 = await createOperatorSession(`account:${accountId}`, homeDir ?? homedir15(), {
82210
+ id: loginSessionId(accountId),
82211
+ command: argv,
82212
+ env
82213
+ });
82214
+ return { id: s2.id };
82215
+ }
82216
+
82217
+ // src/routes/runtime-accounts.ts
82218
+ var fail2 = (reply, e) => {
82219
+ if (e instanceof AccountError) return reply.code(e.status).send({ error: e.code, message: e.message });
82220
+ throw e;
82221
+ };
82222
+ var liveAccountIds = () => listSessions().filter((s2) => !s2.exited && s2.accountId).map((s2) => s2.accountId);
82223
+ var builtinRefused = (reply) => reply.code(400).send({ error: "akun bawaan tak bisa diubah atau dihapus" });
82224
+ var listBody = () => ({ accounts: listAccountDTOs(), sandbox: sessionSandboxOn() });
82225
+ async function runtime_accounts_default(app3) {
82226
+ app3.get("/runtime-accounts", async () => listBody());
82227
+ app3.post("/runtime-accounts", async (req, reply) => {
82228
+ const p3 = zRuntimeAccountCreate.safeParse(req.body);
82229
+ if (!p3.success) return reply.code(400).send({ error: "invalid body" });
82230
+ try {
82231
+ return reply.code(201).send(await createAccount(p3.data.runtime, p3.data.label));
82232
+ } catch (e) {
82233
+ return fail2(reply, e);
82234
+ }
82235
+ });
82236
+ app3.patch("/runtime-accounts/:id", async (req, reply) => {
82237
+ const { id: id2 } = req.params;
82238
+ if (isBuiltinAccountId(id2)) return builtinRefused(reply);
82239
+ const p3 = zRuntimeAccountPatch.safeParse(req.body);
82240
+ if (!p3.success) return reply.code(400).send({ error: "invalid body" });
82241
+ try {
82242
+ return await renameAccount(id2, p3.data.label);
82243
+ } catch (e) {
82244
+ return fail2(reply, e);
82245
+ }
82246
+ });
82247
+ app3.delete("/runtime-accounts/:id", async (req, reply) => {
82248
+ const { id: id2 } = req.params;
82249
+ if (isBuiltinAccountId(id2)) return builtinRefused(reply);
82250
+ try {
82251
+ await deleteAccount(id2, liveAccountIds);
82252
+ return reply.code(204).send();
82253
+ } catch (e) {
82254
+ return fail2(reply, e);
82255
+ }
82256
+ });
82257
+ app3.put("/runtime-accounts/default", async (req, reply) => {
82258
+ const p3 = zRuntimeAccountDefault.safeParse(req.body);
82259
+ if (!p3.success) return reply.code(400).send({ error: "invalid body" });
82260
+ try {
82261
+ await setDefaultAccount(p3.data.runtime, p3.data.accountId, sessionSandboxOn());
82262
+ return listBody();
82263
+ } catch (e) {
82264
+ return fail2(reply, e);
82265
+ }
82266
+ });
82267
+ app3.post("/runtime-accounts/:id/login", async (req, reply) => {
82268
+ const { id: id2 } = req.params;
82269
+ const p3 = zRuntimeAccountLogin.safeParse(req.body ?? {});
82270
+ if (!p3.success) return reply.code(400).send({ error: "invalid body" });
82271
+ try {
82272
+ return reply.code(201).send(await openLoginSession(id2, p3.data));
82273
+ } catch (e) {
82274
+ return fail2(reply, e);
82275
+ }
82276
+ });
82277
+ app3.post("/runtime-accounts/:id/check", async (req, reply) => {
82278
+ const { id: id2 } = req.params;
82279
+ try {
82280
+ return await checkAccount(id2);
82281
+ } catch (e) {
82282
+ return fail2(reply, e);
82283
+ }
82284
+ });
81327
82285
  }
81328
82286
 
81329
82287
  // src/routes/codex.ts
@@ -81336,10 +82294,10 @@ async function codex(app3) {
81336
82294
  init_src2();
81337
82295
  init_antigravity_runtime();
81338
82296
  init_session_sandbox();
81339
- import { execFile as execFile18 } from "node:child_process";
82297
+ import { execFile as execFile19 } from "node:child_process";
81340
82298
  import { promisify as promisify18 } from "node:util";
81341
- var run4 = promisify18(execFile18);
81342
- var TTL_MS6 = 5 * 6e4;
82299
+ var run4 = promisify18(execFile19);
82300
+ var TTL_MS7 = 5 * 6e4;
81343
82301
  var unavailable = (error) => ({ version: null, error });
81344
82302
  var CHANGED2 = "Konfigurasi runtime berubah; periksa versi kembali.";
81345
82303
  function parseAntigravityVersion(output) {
@@ -81381,22 +82339,22 @@ function createAntigravityVersionService(deps = {}) {
81381
82339
  const now = deps.now ?? Date.now;
81382
82340
  const probe = deps.probe ?? probeAntigravityVersion;
81383
82341
  let currentKey, generation2 = 0;
81384
- let cache6;
82342
+ let cache7;
81385
82343
  let pending2;
81386
82344
  return () => {
81387
82345
  const nextKey = key();
81388
82346
  if (nextKey !== currentKey) {
81389
82347
  currentKey = nextKey;
81390
82348
  generation2++;
81391
- cache6 = void 0;
82349
+ cache7 = void 0;
81392
82350
  pending2 = void 0;
81393
82351
  }
81394
- if (cache6 && now() - cache6.at < TTL_MS6) return Promise.resolve(cache6.info);
82352
+ if (cache7 && now() - cache7.at < TTL_MS7) return Promise.resolve(cache7.info);
81395
82353
  if (pending2) return pending2;
81396
82354
  const startedGeneration = generation2;
81397
82355
  const request = probe().catch(() => unavailable("Versi Antigravity tidak dapat diperiksa.")).then((info) => {
81398
82356
  if (startedGeneration !== generation2 || key() !== nextKey) return unavailable(CHANGED2);
81399
- cache6 = { at: now(), info };
82357
+ cache7 = { at: now(), info };
81400
82358
  return info;
81401
82359
  }).finally(() => {
81402
82360
  if (pending2 === request) pending2 = void 0;
@@ -81415,9 +82373,9 @@ async function antigravity(app3) {
81415
82373
  // src/services/model-catalog.ts
81416
82374
  init_src2();
81417
82375
  init_src();
81418
- import { randomUUID as randomUUID14 } from "node:crypto";
82376
+ import { randomUUID as randomUUID15 } from "node:crypto";
81419
82377
  import { readFile as readFile9, writeFile as writeFile6, rename as rename5, mkdir as mkdir9, rm as rm9 } from "node:fs/promises";
81420
- import { dirname as dirname18, join as join48 } from "node:path";
82378
+ import { dirname as dirname18, join as join53 } from "node:path";
81421
82379
 
81422
82380
  // src/services/model-catalog-parser.ts
81423
82381
  init_zod();
@@ -81524,7 +82482,7 @@ init_session_sandbox();
81524
82482
  import { spawn as spawn7 } from "node:child_process";
81525
82483
  import { mkdtemp as mkdtemp2, rm as rm8 } from "node:fs/promises";
81526
82484
  import { tmpdir as tmpdir8 } from "node:os";
81527
- import { join as join47 } from "node:path";
82485
+ import { join as join52 } from "node:path";
81528
82486
  var MAX_BYTES = 4 * 1024 * 1024;
81529
82487
  var TIMEOUT_MS = 2e4;
81530
82488
  var quote3 = (s2) => "'" + s2.replaceAll("'", "'\\''") + "'";
@@ -81559,7 +82517,7 @@ function catalogCommand(agent, cwd, env) {
81559
82517
  return { bin: sandbox[0], args: sandbox.slice(1) };
81560
82518
  }
81561
82519
  function runCatalogCommand(command, agent, cwd, env, timeoutMs = TIMEOUT_MS) {
81562
- return new Promise((resolve25, reject2) => {
82520
+ return new Promise((resolve26, reject2) => {
81563
82521
  assertAntigravityLaunch(agent, void 0, env);
81564
82522
  const child = spawn7(command.bin, command.args, { cwd, env: agentEnvironment(agent, env), stdio: ["pipe", "pipe", "pipe"] });
81565
82523
  let buffer = "", bytes = 0, settled = false;
@@ -81575,7 +82533,7 @@ function runCatalogCommand(command, agent, cwd, env, timeoutMs = TIMEOUT_MS) {
81575
82533
  killTimer.unref();
81576
82534
  }
81577
82535
  if (error) reject2(error);
81578
- else resolve25(result);
82536
+ else resolve26(result);
81579
82537
  };
81580
82538
  const timer11 = setTimeout(() => finish(new Error("Pemeriksaan model melewati batas waktu")), timeoutMs);
81581
82539
  child.on("error", () => finish(new Error("CLI model tidak dapat dijalankan")));
@@ -81623,7 +82581,7 @@ function runCatalogCommand(command, agent, cwd, env, timeoutMs = TIMEOUT_MS) {
81623
82581
  }
81624
82582
  async function probeModelCatalog(agent) {
81625
82583
  assertAntigravityLaunch(agent);
81626
- const cwd = await mkdtemp2(join47(tmpdir8(), "hanoman-models-"));
82584
+ const cwd = await mkdtemp2(join52(tmpdir8(), "hanoman-models-"));
81627
82585
  const env = agentEnvironment(agent, process.env);
81628
82586
  for (const key of ["HANOMAN_CLAUDE_BIN", "HANOMAN_CODEX_BIN", "HANOMAN_PODMAN_BIN", "HANOMAN_ANTIGRAVITY_BIN"]) {
81629
82587
  const value = effectiveStr(key);
@@ -81670,9 +82628,9 @@ function createModelCatalogService(deps) {
81670
82628
  if (!initialized) {
81671
82629
  initialized = true;
81672
82630
  try {
81673
- const cached3 = parseCachedCatalog(await deps.read());
82631
+ const cached4 = parseCachedCatalog(await deps.read());
81674
82632
  if (!current()) return state;
81675
- state = cached3;
82633
+ state = cached4;
81676
82634
  for (const agent of ["claude", "codex", "antigravity"]) {
81677
82635
  if (state.providers[agent].updatedAt) state.providers[agent].source = "cache";
81678
82636
  }
@@ -81726,7 +82684,7 @@ function createModelCatalogService(deps) {
81726
82684
  async function writeModelCatalogCache(file, catalog, current = () => true) {
81727
82685
  const sanitized = parseCachedCatalog(catalog);
81728
82686
  await mkdir9(dirname18(file), { recursive: true });
81729
- const temp = `${file}.${process.pid}.${randomUUID14()}.tmp`;
82687
+ const temp = `${file}.${process.pid}.${randomUUID15()}.tmp`;
81730
82688
  try {
81731
82689
  await writeFile6(temp, JSON.stringify(sanitized), { mode: 384, flag: "wx" });
81732
82690
  if (current()) await rename5(temp, file);
@@ -81734,7 +82692,7 @@ async function writeModelCatalogCache(file, catalog, current = () => true) {
81734
82692
  await rm9(temp, { force: true });
81735
82693
  }
81736
82694
  }
81737
- var cacheFile = () => join48(resolveHome(), "model-catalog.json");
82695
+ var cacheFile = () => join53(resolveHome(), "model-catalog.json");
81738
82696
  var modelCatalogService = createModelCatalogService({
81739
82697
  probe: probeModelCatalog,
81740
82698
  key: catalogProbeKey,
@@ -81919,8 +82877,8 @@ function tokenStats(now, invs, landedToday) {
81919
82877
  const today = invs.filter((i) => i.startedAt.getTime() >= t0);
81920
82878
  const input = today.reduce((n2, i) => n2 + (i.inputTokens ?? 0), 0);
81921
82879
  const output = today.reduce((n2, i) => n2 + (i.outputTokens ?? 0), 0);
81922
- const cached3 = today.reduce((n2, i) => n2 + (i.cachedTokens ?? 0), 0);
81923
- const total = input + output + cached3;
82880
+ const cached4 = today.reduce((n2, i) => n2 + (i.cachedTokens ?? 0), 0);
82881
+ const total = input + output + cached4;
81924
82882
  const byAgent = /* @__PURE__ */ new Map();
81925
82883
  for (const i of today) byAgent.set(i.agentName, (byAgent.get(i.agentName) ?? 0) + invTotal(i));
81926
82884
  let topAgent = null;
@@ -81928,9 +82886,9 @@ function tokenStats(now, invs, landedToday) {
81928
82886
  return {
81929
82887
  input,
81930
82888
  output,
81931
- cached: cached3,
82889
+ cached: cached4,
81932
82890
  total,
81933
- cacheHitPct: input + cached3 > 0 ? Math.round(cached3 / (input + cached3) * 100) : null,
82891
+ cacheHitPct: input + cached4 > 0 ? Math.round(cached4 / (input + cached4) * 100) : null,
81934
82892
  perLanded: landedToday && landedToday > 0 ? Math.round(total / landedToday) : null,
81935
82893
  topAgent,
81936
82894
  yesterdayTotal: invs.filter((i) => i.startedAt.getTime() >= y0 && i.startedAt.getTime() < t0).reduce((n2, i) => n2 + invTotal(i), 0)
@@ -82923,8 +83881,8 @@ init_db();
82923
83881
  init_pty();
82924
83882
  init_config5();
82925
83883
  init_inbox();
82926
- import { mkdirSync as mkdirSync20, writeFileSync as writeFileSync20 } from "node:fs";
82927
- import { join as join49 } from "node:path";
83884
+ import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync22 } from "node:fs";
83885
+ import { join as join54 } from "node:path";
82928
83886
  init_human_input();
82929
83887
  var idle = /* @__PURE__ */ new Set();
82930
83888
  var sending = /* @__PURE__ */ new Set();
@@ -82935,7 +83893,7 @@ function isLeadIdle(id2) {
82935
83893
  return idle.has(id2);
82936
83894
  }
82937
83895
  var HUMAN_QUIET_MS = 12e4;
82938
- var batchDir = (projectId) => join49(resolveHome(), "lead-batches", projectId);
83896
+ var batchDir = (projectId) => join54(resolveHome(), "lead-batches", projectId);
82939
83897
  var briefFn = async () => "(situasi tak tersedia \u2014 panggil /brief)";
82940
83898
  function setBriefBuilder(fn) {
82941
83899
  briefFn = fn;
@@ -82955,9 +83913,9 @@ var prodCourierDeps = {
82955
83913
  brief: (p3) => briefFn(p3).catch(() => "(situasi tak tersedia \u2014 panggil /brief)"),
82956
83914
  write: (projectId, text2) => {
82957
83915
  const dir2 = batchDir(projectId);
82958
- mkdirSync20(dir2, { recursive: true });
82959
- const file = join49(dir2, `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.md`);
82960
- writeFileSync20(file, text2);
83916
+ mkdirSync22(dir2, { recursive: true });
83917
+ const file = join54(dir2, `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.md`);
83918
+ writeFileSync22(file, text2);
82961
83919
  return file;
82962
83920
  },
82963
83921
  send: (id2, line) => sendToPane(id2, line),
@@ -83327,6 +84285,9 @@ var GROUPS = [
83327
84285
  // ADR-0224 · limit Antigravity — grup TERPISAH. Panggilan jaringan ber-cache 60 dtk di service, dan
83328
84286
  // nol panggilan saat token agy kedaluwarsa; dedup signature membuat frame lahir saat isinya berubah.
83329
84287
  { everyTicks: 30, last: "", build: async () => ({ t: "antigravityLimits", limits: await getAntigravityLimits() }) },
84288
+ // ADR-0234 · limit per akun runtime — grup TERPISAH. Akun bawaan memakai cache service lama; akun
84289
+ // terdaftar ber-cache 30 dtk per akun. Dedup signature: frame lahir saat isinya berubah.
84290
+ { everyTicks: 30, last: "", build: async () => ({ t: "accountLimits", accounts: await getAccountLimits() }) },
83330
84291
  // SPEC-214 · deteksi update jarang berubah; recompute tiap 300 dtk, dedup signature → siar hanya
83331
84292
  // saat status berubah. getUpdateStatus cache 15s + fetch ter-gate (server.ts) → attach tak menahan.
83332
84293
  { everyTicks: 300, last: "", build: async () => ({ t: "update", update: await getUpdateStatus() }) },
@@ -83755,7 +84716,7 @@ init_src();
83755
84716
  init_db();
83756
84717
  import { gunzipSync, gzipSync } from "node:zlib";
83757
84718
  import { mkdir as mkdir10, rename as rename6, writeFile as writeFile7 } from "node:fs/promises";
83758
- import { join as join50 } from "node:path";
84719
+ import { join as join55 } from "node:path";
83759
84720
 
83760
84721
  // src/services/device-auth.ts
83761
84722
  function bearerToken2(req) {
@@ -84013,9 +84974,9 @@ async function sync_default(app3) {
84013
84974
  const deviceId = req.device.id;
84014
84975
  const withTranscriptKey = await Promise.all(parsed.data.entries.map(async (e) => {
84015
84976
  if (!e.transcript) return e;
84016
- const dir2 = join50(resolveDataDirs().home, "remote-transcripts", deviceId);
84977
+ const dir2 = join55(resolveDataDirs().home, "remote-transcripts", deviceId);
84017
84978
  await mkdir10(dir2, { recursive: true, mode: 448 });
84018
- const final = join50(dir2, `${e.seq}.txt`);
84979
+ const final = join55(dir2, `${e.seq}.txt`);
84019
84980
  const tmp = `${final}.tmp`;
84020
84981
  await writeFile7(tmp, e.transcript, { encoding: "utf8", mode: 384 });
84021
84982
  await rename6(tmp, final);
@@ -84570,9 +85531,9 @@ init_db();
84570
85531
  init_db();
84571
85532
  init_uploads();
84572
85533
  init_src();
84573
- import { createHash as createHash21, randomBytes as randomBytes7 } from "node:crypto";
85534
+ import { createHash as createHash22, randomBytes as randomBytes7 } from "node:crypto";
84574
85535
  function hashAccessKey(key) {
84575
- return createHash21("sha256").update(key).digest("hex");
85536
+ return createHash22("sha256").update(key).digest("hex");
84576
85537
  }
84577
85538
  function generateAccessKey() {
84578
85539
  const key = "hnm_tkt_" + randomBytes7(24).toString("hex");
@@ -85625,7 +86586,7 @@ init_skill_library2();
85625
86586
  init_skill_inject();
85626
86587
  init_local_binding();
85627
86588
  import { basename as basename11 } from "node:path";
85628
- var fail2 = (reply, e) => {
86589
+ var fail3 = (reply, e) => {
85629
86590
  if (e instanceof SkillError) return reply.code(e.status).send({ error: e.message });
85630
86591
  throw e;
85631
86592
  };
@@ -85651,7 +86612,7 @@ async function skills(app3) {
85651
86612
  try {
85652
86613
  return skillTree((await resolveSkill(req.params.key)).dir);
85653
86614
  } catch (e) {
85654
- return fail2(reply, e);
86615
+ return fail3(reply, e);
85655
86616
  }
85656
86617
  });
85657
86618
  app3.get("/skills/:key/file", async (req, reply) => {
@@ -85659,7 +86620,7 @@ async function skills(app3) {
85659
86620
  const s2 = await resolveSkill(req.params.key);
85660
86621
  return readSkillFile(s2.dir, String(req.query.path ?? ""));
85661
86622
  } catch (e) {
85662
- return fail2(reply, e);
86623
+ return fail3(reply, e);
85663
86624
  }
85664
86625
  });
85665
86626
  app3.put("/skills/:key/file", async (req, reply) => {
@@ -85670,7 +86631,7 @@ async function skills(app3) {
85670
86631
  const base3 = typeof b.baseHash === "string" ? b.baseHash : null;
85671
86632
  return writeSkillFile(s2.dir, String(req.query.path ?? ""), b.content, base3);
85672
86633
  } catch (e) {
85673
- return fail2(reply, e);
86634
+ return fail3(reply, e);
85674
86635
  }
85675
86636
  });
85676
86637
  app3.post("/skills/:key/entry", async (req, reply) => {
@@ -85681,7 +86642,7 @@ async function skills(app3) {
85681
86642
  createSkillEntry(s2.dir, b.path, b.kind);
85682
86643
  return reply.code(201).send({ ok: true });
85683
86644
  } catch (e) {
85684
- return fail2(reply, e);
86645
+ return fail3(reply, e);
85685
86646
  }
85686
86647
  });
85687
86648
  app3.delete("/skills/:key/entry", async (req, reply) => {
@@ -85690,7 +86651,7 @@ async function skills(app3) {
85690
86651
  deleteSkillEntry(s2.dir, String(req.query.path ?? ""));
85691
86652
  return reply.code(204).send();
85692
86653
  } catch (e) {
85693
- return fail2(reply, e);
86654
+ return fail3(reply, e);
85694
86655
  }
85695
86656
  });
85696
86657
  app3.post("/skills", async (req, reply) => {
@@ -85702,7 +86663,7 @@ async function skills(app3) {
85702
86663
  await releaseInjected(layer, b.projectId, dir2);
85703
86664
  return reply.code(201).send(await resolveSkill(created(layer, b.source, b.projectId, dir2)));
85704
86665
  } catch (e) {
85705
- return fail2(reply, e);
86666
+ return fail3(reply, e);
85706
86667
  }
85707
86668
  });
85708
86669
  app3.post("/skills/:key/fork", async (req, reply) => {
@@ -85714,7 +86675,7 @@ async function skills(app3) {
85714
86675
  await releaseInjected(layer, b?.projectId, dir2);
85715
86676
  return reply.code(201).send(await resolveSkill(created(layer, b?.source, b?.projectId, dir2)));
85716
86677
  } catch (e) {
85717
- return fail2(reply, e);
86678
+ return fail3(reply, e);
85718
86679
  }
85719
86680
  });
85720
86681
  app3.delete("/skills/:key", async (req, reply) => {
@@ -85722,7 +86683,7 @@ async function skills(app3) {
85722
86683
  deleteSkillDir((await editable(req.params.key)).dir);
85723
86684
  return reply.code(204).send();
85724
86685
  } catch (e) {
85725
- return fail2(reply, e);
86686
+ return fail3(reply, e);
85726
86687
  }
85727
86688
  });
85728
86689
  }
@@ -86078,9 +87039,9 @@ async function qa(app3) {
86078
87039
  const keys2 = Object.keys(p3).filter((k) => p3[k] !== void 0);
86079
87040
  if (!(keys2.length === 1 && keys2[0] === "status" && p3.status !== "closed")) return locked(reply);
86080
87041
  }
86081
- const nextStatus = p3.status ?? existing.status;
87042
+ const nextStatus2 = p3.status ?? existing.status;
86082
87043
  const nextVerdict = p3.verdict === void 0 ? existing.verdict : p3.verdict;
86083
- if ((nextStatus === "submitted" || nextStatus === "closed") && !nextVerdict)
87044
+ if ((nextStatus2 === "submitted" || nextStatus2 === "closed") && !nextVerdict)
86084
87045
  return reply.code(400).send({ error: "verdict wajib diisi sebelum laporan di-submit atau di-close" });
86085
87046
  await prisma.qaReport.update({ where: { id: rid }, data: {
86086
87047
  title: p3.title,
@@ -86618,25 +87579,25 @@ function qaTemplateWorkbook() {
86618
87579
  });
86619
87580
  }
86620
87581
  var norm3 = (s2) => s2.trim().toLowerCase();
86621
- function fail3(sheet, row, message) {
87582
+ function fail4(sheet, row, message) {
86622
87583
  throw new XlsxError(`${sheet}, baris ${row}: ${message}`);
86623
87584
  }
86624
87585
  var choice = (s2, allowed, sheet, row) => {
86625
87586
  const v = allowed.find((a) => norm3(a) === norm3(s2));
86626
- return v ?? fail3(sheet, row, `nilai "${s2}" tidak dikenal; pilih ${allowed.join(", ")}`);
87587
+ return v ?? fail4(sheet, row, `nilai "${s2}" tidak dikenal; pilih ${allowed.join(", ")}`);
86627
87588
  };
86628
87589
  function parseQaWorkbook(buf) {
86629
87590
  const read2 = (sheet) => readXlsx(buf, { sheet, required: true });
86630
87591
  const summary = read2("Ringkasan");
86631
- if (norm3(summary[0]?.[0] ?? "") !== "kolom" || norm3(summary[0]?.[1] ?? "") !== "nilai") fail3("Ringkasan", 1, "butuh kolom Kolom dan Nilai");
87592
+ if (norm3(summary[0]?.[0] ?? "") !== "kolom" || norm3(summary[0]?.[1] ?? "") !== "nilai") fail4("Ringkasan", 1, "butuh kolom Kolom dan Nilai");
86632
87593
  const fields = new Map(summary.slice(1).map((r) => [norm3(r[0] ?? ""), r[1] ?? ""]));
86633
87594
  const val = (k) => fields.get(norm3(k)) ?? "";
86634
87595
  const rowOf = (k) => Math.max(1, summary.findIndex((r) => norm3(r[0] ?? "") === norm3(k)) + 1);
86635
- if (!val("Judul").trim()) fail3("Ringkasan", rowOf("Judul"), "Judul wajib diisi");
87596
+ if (!val("Judul").trim()) fail4("Ringkasan", rowOf("Judul"), "Judul wajib diisi");
86636
87597
  const environment = /* @__PURE__ */ Object.create(null);
86637
87598
  for (const line of val("Lingkungan").split(/\r\n|\r|\n|;(?=\s*[^=:;\s]+\s*[=:])/).filter((l) => l.trim())) {
86638
87599
  const match = /^\s*([^=:]+)[=:]\s*(.*)$/.exec(line);
86639
- if (!match) fail3("Ringkasan", rowOf("Lingkungan"), "Lingkungan: gunakan kunci=nilai, satu per baris");
87600
+ if (!match) fail4("Ringkasan", rowOf("Lingkungan"), "Lingkungan: gunakan kunci=nilai, satu per baris");
86640
87601
  environment[match[1].trim()] = match[2];
86641
87602
  }
86642
87603
  const base3 = zCreateQaReport.safeParse({
@@ -86648,7 +87609,7 @@ function parseQaWorkbook(buf) {
86648
87609
  environment,
86649
87610
  verdict: val("Keputusan") ? choice(val("Keputusan"), QA_VERDICTS, "Ringkasan", rowOf("Keputusan")) : null
86650
87611
  });
86651
- if (!base3.success) fail3("Ringkasan", 1, base3.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join("; "));
87612
+ if (!base3.success) fail4("Ringkasan", 1, base3.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join("; "));
86652
87613
  const parsed = {
86653
87614
  ...base3.data,
86654
87615
  reportId: val("Ref") || null,
@@ -86666,13 +87627,13 @@ function parseQaWorkbook(buf) {
86666
87627
  }
86667
87628
  const rows = read2("Temuan");
86668
87629
  const headers = rows[0]?.map(norm3) ?? [];
86669
- for (const h2 of ["judul", "severity", "prioritas", "langkah", "expected", "actual"]) if (!headers.includes(h2)) fail3("Temuan", 1, `kolom ${h2} wajib ada`);
87630
+ for (const h2 of ["judul", "severity", "prioritas", "langkah", "expected", "actual"]) if (!headers.includes(h2)) fail4("Temuan", 1, `kolom ${h2} wajib ada`);
86670
87631
  const getF = (r, k) => r[headers.indexOf(norm3(k))] ?? "";
86671
87632
  const findingRows = rows.slice(1).map((r, i) => ({ r, row: i + 2 })).filter(({ r }) => !r.every((v) => !v.trim()));
86672
87633
  const used = /* @__PURE__ */ new Map();
86673
87634
  const claim = (sheet, row, code) => {
86674
- if (norm3(code) === "laporan") fail3(sheet, row, 'Kode "Laporan" dicadangkan untuk lampiran laporan');
86675
- if (used.has(qaCodeKey(code))) fail3(sheet, row, `Kode ${code} dipakai ${used.get(qaCodeKey(code))}; kode harus unik`);
87635
+ if (norm3(code) === "laporan") fail4(sheet, row, 'Kode "Laporan" dicadangkan untuk lampiran laporan');
87636
+ if (used.has(qaCodeKey(code))) fail4(sheet, row, `Kode ${code} dipakai ${used.get(qaCodeKey(code))}; kode harus unik`);
86676
87637
  used.set(qaCodeKey(code), `${sheet}`);
86677
87638
  };
86678
87639
  for (const c of cases) if (c.code.trim()) claim("Test case", c.row, c.code.trim());
@@ -86690,10 +87651,10 @@ function parseQaWorkbook(buf) {
86690
87651
  for (const c of cases) {
86691
87652
  const customCode = c.code.trim() || null;
86692
87653
  const code = customCode ?? autoCode("TC-", caseCounter);
86693
- if (c.ref && refs2.has(c.ref)) fail3("Test case", c.row, "Ref berulang");
87654
+ if (c.ref && refs2.has(c.ref)) fail4("Test case", c.row, "Ref berulang");
86694
87655
  if (c.ref) refs2.add(c.ref);
86695
87656
  const result = zCreateQaCase.safeParse({ title: c.title, steps: c.steps ?? "", expected: c.expected ?? "", actual: c.actual ?? "", status: c.status ?? "todo" });
86696
- if (!result.success) fail3("Test case", c.row, result.error.issues.map((e) => `${e.path}: ${e.message}`).join("; "));
87657
+ if (!result.success) fail4("Test case", c.row, result.error.issues.map((e) => `${e.path}: ${e.message}`).join("; "));
86697
87658
  caseByKey.set(qaCodeKey(code), code);
86698
87659
  parsed.cases.push({ ...result.data, id: c.ref, code, customCode, attachments: [] });
86699
87660
  }
@@ -86704,11 +87665,11 @@ function parseQaWorkbook(buf) {
86704
87665
  const customCode = get("Kode").trim() || null;
86705
87666
  const code = customCode ?? autoCode("F-", findingCounter);
86706
87667
  const id2 = get("Ref") || null;
86707
- if (id2 && findingRefs.has(id2)) fail3("Temuan", row, "Ref berulang");
87668
+ if (id2 && findingRefs.has(id2)) fail4("Temuan", row, "Ref berulang");
86708
87669
  if (id2) findingRefs.add(id2);
86709
87670
  const caseRef = get("Test case").trim();
86710
87671
  const caseCode = caseRef ? caseByKey.get(qaCodeKey(caseRef)) ?? null : null;
86711
- if (caseRef && !caseCode) fail3("Temuan", row, `Test case ${caseRef} tidak ditemukan`);
87672
+ if (caseRef && !caseCode) fail4("Temuan", row, `Test case ${caseRef} tidak ditemukan`);
86712
87673
  const status2 = choice(get("Status") || "open", QA_FINDING_STATUSES, "Temuan", row);
86713
87674
  const result = zCreateQaFinding.safeParse({
86714
87675
  title: get("Judul"),
@@ -86720,17 +87681,17 @@ function parseQaWorkbook(buf) {
86720
87681
  actual: get("Actual"),
86721
87682
  status: status2 === "sent" ? "open" : status2
86722
87683
  });
86723
- if (!result.success) fail3("Temuan", row, result.error.issues.map((e) => `${e.path}: ${e.message}`).join("; "));
87684
+ if (!result.success) fail4("Temuan", row, result.error.issues.map((e) => `${e.path}: ${e.message}`).join("; "));
86724
87685
  parsed.findings.push({ ...result.data, status: status2, id: id2, code, customCode, caseId: null, caseCode, attachments: [] });
86725
87686
  }
86726
87687
  const attachments = read2("Lampiran");
86727
- if (norm3(attachments[0]?.[0] ?? "") !== "pemilik" || norm3(attachments[0]?.[1] ?? "") !== "berkas") fail3("Lampiran", 1, "butuh kolom Pemilik dan Berkas");
87688
+ if (norm3(attachments[0]?.[0] ?? "") !== "pemilik" || norm3(attachments[0]?.[1] ?? "") !== "berkas") fail4("Lampiran", 1, "butuh kolom Pemilik dan Berkas");
86728
87689
  for (let i = 1; i < attachments.length; i++) {
86729
87690
  const [owner = "", path = ""] = attachments[i];
86730
87691
  if (!owner.trim() && !path.trim()) continue;
86731
- if (!path.trim() || path.includes("\\") || path.startsWith("/") || path.split("/").some((p3) => p3 === ".." || p3 === "." || !p3)) fail3("Lampiran", i + 1, "Berkas harus nama berkas atau path relatif yang aman");
87692
+ if (!path.trim() || path.includes("\\") || path.startsWith("/") || path.split("/").some((p3) => p3 === ".." || p3 === "." || !p3)) fail4("Lampiran", i + 1, "Berkas harus nama berkas atau path relatif yang aman");
86732
87693
  const target3 = norm3(owner) === "laporan" ? parsed.attachments : parsed.cases.find((c) => qaCodeKey(c.code) === qaCodeKey(owner))?.attachments ?? parsed.findings.find((f) => qaCodeKey(f.code) === qaCodeKey(owner))?.attachments;
86733
- if (!target3) fail3("Lampiran", i + 1, `Pemilik "${owner}" tidak ditemukan; gunakan Laporan atau Kode TC/F yang ada`);
87694
+ if (!target3) fail4("Lampiran", i + 1, `Pemilik "${owner}" tidak ditemukan; gunakan Laporan atau Kode TC/F yang ada`);
86734
87695
  target3.push(path.trim());
86735
87696
  }
86736
87697
  return parsed;
@@ -87159,11 +88120,11 @@ var humanSize3 = (n2) => n2 >= 1024 * 1024 ? `${(n2 / 1024 / 1024).toFixed(1)} M
87159
88120
  var day3 = (iso5) => iso5.slice(0, 16).replace("T", " ");
87160
88121
  var T = (s2) => toWinAnsi(s2 ?? "");
87161
88122
  function writeQaPdf(d, images) {
87162
- return new Promise((resolve25, reject2) => {
88123
+ return new Promise((resolve26, reject2) => {
87163
88124
  const doc = new PDFDocument2({ size: "A4", margin: M, bufferPages: true, info: { Title: T(`${d.code} ${d.title}`), Author: T(d.tester || "hanoman"), Subject: "Laporan QA" } });
87164
88125
  const chunks = [];
87165
88126
  doc.on("data", (c) => chunks.push(c));
87166
- doc.on("end", () => resolve25(Buffer.concat(chunks)));
88127
+ doc.on("end", () => resolve26(Buffer.concat(chunks)));
87167
88128
  doc.on("error", reject2);
87168
88129
  const room = (h2) => {
87169
88130
  if (doc.y + h2 > BOTTOM) doc.addPage();
@@ -87418,9 +88379,9 @@ init_codex_trust();
87418
88379
  init_qa_attachment_transfer();
87419
88380
  init_uploads();
87420
88381
  init_ask_via2();
87421
- import { createHash as createHash22 } from "node:crypto";
87422
- import { execFileSync as execFileSync11 } from "node:child_process";
87423
- import { join as join52 } from "node:path";
88382
+ import { createHash as createHash23 } from "node:crypto";
88383
+ import { execFileSync as execFileSync12 } from "node:child_process";
88384
+ import { join as join57 } from "node:path";
87424
88385
  var QaSessionError = class extends Error {
87425
88386
  constructor(code, message, needsBind = false) {
87426
88387
  super(message);
@@ -87428,7 +88389,7 @@ var QaSessionError = class extends Error {
87428
88389
  this.needsBind = needsBind;
87429
88390
  }
87430
88391
  };
87431
- var qaSessionId = (findingId) => `qa-${createHash22("sha256").update(findingId).digest("hex").slice(0, 24)}`;
88392
+ var qaSessionId = (findingId) => `qa-${createHash23("sha256").update(findingId).digest("hex").slice(0, 24)}`;
87432
88393
  async function startQaFindingSession(d, fid) {
87433
88394
  const f = d.findings.find((x) => x.id === fid);
87434
88395
  if (!f) throw new QaSessionError(404, "temuan tidak ditemukan");
@@ -87447,14 +88408,14 @@ async function startQaFindingSession(d, fid) {
87447
88408
  const saved = await saveSessionUpload(id2, bytes, a.mimeType);
87448
88409
  files2.push(`${JSON.stringify(a.filename)} (${a.mimeType}): ${saved.path}`);
87449
88410
  }
87450
- const wt = join52(repoDir, ".worktrees", id2);
88411
+ const wt = join57(repoDir, ".worktrees", id2);
87451
88412
  const branch = `qa/${id2.slice(3)}`;
87452
88413
  const reused = realGit.worktreeAlive(wt);
87453
88414
  try {
87454
88415
  if (!reused) {
87455
88416
  const base3 = realGit.revParse(repoDir, branch) ? branch : "HEAD";
87456
88417
  realGit.addWorktree(repoDir, wt, base3);
87457
- execFileSync11("git", ["checkout", "-B", branch], { cwd: wt, encoding: "utf8" });
88418
+ execFileSync12("git", ["checkout", "-B", branch], { cwd: wt, encoding: "utf8" });
87458
88419
  }
87459
88420
  } catch (e) {
87460
88421
  throw new QaSessionError(422, `Gagal membuat worktree QA: ${e.message}`);
@@ -87728,7 +88689,7 @@ async function resolveGithubRepo(projectId) {
87728
88689
 
87729
88690
  // src/services/github-fetch.ts
87730
88691
  init_config2();
87731
- import { execFile as execFile19 } from "node:child_process";
88692
+ import { execFile as execFile20 } from "node:child_process";
87732
88693
  var labelNames = (l) => (l ?? []).map((x) => typeof x === "string" ? x : x.name ?? "").filter(Boolean);
87733
88694
  var norm4 = (s2) => s2.toLowerCase() === "closed" ? "closed" : "open";
87734
88695
  function issueFromGh(raw) {
@@ -87768,15 +88729,15 @@ function issuesFromRest(raw) {
87768
88729
  }
87769
88730
  var GH_FIELDS = "number,title,body,author,labels,url,state,createdAt,updatedAt";
87770
88731
  var API2 = "https://api.github.com";
87771
- var defaultRunGh = (args, env) => new Promise((resolve25, reject2) => {
87772
- execFile19(
88732
+ var defaultRunGh = (args, env) => new Promise((resolve26, reject2) => {
88733
+ execFile20(
87773
88734
  args[0],
87774
88735
  args.slice(1),
87775
88736
  { env, maxBuffer: 1 << 26, encoding: "utf8", timeout: 6e4 },
87776
88737
  (err, stdout, stderr) => {
87777
88738
  const e = err;
87778
88739
  if (e && (e.code === "ENOENT" || e.code === "EACCES")) return reject2(e);
87779
- resolve25({ code: err ? Number(err.code ?? 1) : 0, stdout, stderr });
88740
+ resolve26({ code: err ? Number(err.code ?? 1) : 0, stdout, stderr });
87780
88741
  }
87781
88742
  );
87782
88743
  });
@@ -88362,20 +89323,20 @@ var normalize2 = (r) => ({
88362
89323
  events: strings(r.events),
88363
89324
  projectIds: Array.isArray(r.projectIds) ? strings(r.projectIds) : null
88364
89325
  });
88365
- var cache5 = [];
89326
+ var cache6 = [];
88366
89327
  function webhooksActive() {
88367
- return cache5.length > 0;
89328
+ return cache6.length > 0;
88368
89329
  }
88369
89330
  async function refreshWebhookCache() {
88370
89331
  try {
88371
89332
  const rows = await prisma.webhookEndpoint.findMany({ where: { enabled: true } });
88372
- cache5 = rows.map(normalize2);
89333
+ cache6 = rows.map(normalize2);
88373
89334
  } catch {
88374
- cache5 = [];
89335
+ cache6 = [];
88375
89336
  }
88376
89337
  }
88377
89338
  function matchingEndpoints(eventType, projectId) {
88378
- return cache5.filter((e) => {
89339
+ return cache6.filter((e) => {
88379
89340
  if (!matchesEvent(e.events, eventType)) return false;
88380
89341
  if (e.projectIds === null) return true;
88381
89342
  return projectId !== null && e.projectIds.includes(projectId);
@@ -88442,13 +89403,13 @@ init_ssrf();
88442
89403
  init_safe_outbound_request();
88443
89404
  async function sendOnce(o, deps = {}) {
88444
89405
  const started2 = Date.now();
88445
- const fail4 = (error, httpStatus = null, gone = false) => ({ ok: false, httpStatus, durationMs: Date.now() - started2, error, gone });
89406
+ const fail5 = (error, httpStatus = null, gone = false) => ({ ok: false, httpStatus, durationMs: Date.now() - started2, error, gone });
88446
89407
  const parsed = validateWebhookUrl(o.endpoint.url);
88447
- if (!parsed.ok) return fail4(`URL tak sah: ${parsed.error}`);
89408
+ if (!parsed.ok) return fail5(`URL tak sah: ${parsed.error}`);
88448
89409
  const guard = await checkDestination(parsed.url, o.endpoint.allowPrivate, deps.lookup);
88449
- if (!guard.ok) return fail4(guard.error);
89410
+ if (!guard.ok) return fail5(guard.error);
88450
89411
  const secret = secretOf(o.endpoint);
88451
- if (!secret) return fail4("secret tak bisa dibuka \u2014 rotasi secret endpoint ini");
89412
+ if (!secret) return fail5("secret tak bisa dibuka \u2014 rotasi secret endpoint ini");
88452
89413
  const headers = signedHeaders({
88453
89414
  secret,
88454
89415
  body: o.body,
@@ -88491,7 +89452,7 @@ async function sendOnce(o, deps = {}) {
88491
89452
  return { ok: false, httpStatus: res.status, durationMs, error: `HTTP ${res.status}`, gone: false };
88492
89453
  } catch (e) {
88493
89454
  const msg = e.name === "AbortError" ? `timeout ${WEBHOOK_TIMEOUT_MS} ms` : e.message;
88494
- return fail4(msg);
89455
+ return fail5(msg);
88495
89456
  } finally {
88496
89457
  clearTimeout(timer11);
88497
89458
  }
@@ -88878,7 +89839,7 @@ init_settings3();
88878
89839
  // src/services/portal-chat/turn.ts
88879
89840
  init_src();
88880
89841
  init_db();
88881
- import { execFile as execFile20 } from "node:child_process";
89842
+ import { execFile as execFile21 } from "node:child_process";
88882
89843
 
88883
89844
  // src/services/portal-chat/guard-input.ts
88884
89845
  import { randomBytes as randomBytes10 } from "node:crypto";
@@ -88990,9 +89951,9 @@ ${baru}`;
88990
89951
  // src/services/portal-chat/workspace.ts
88991
89952
  init_src();
88992
89953
  init_db();
88993
- import { mkdirSync as mkdirSync21, mkdtempSync as mkdtempSync5, rmSync as rmSync14, writeFileSync as writeFileSync21 } from "node:fs";
89954
+ import { mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync5, rmSync as rmSync16, writeFileSync as writeFileSync23 } from "node:fs";
88994
89955
  import { tmpdir as tmpdir9 } from "node:os";
88995
- import { join as join53 } from "node:path";
89956
+ import { join as join58 } from "node:path";
88996
89957
  var STAGE_LABEL = {
88997
89958
  brainstorming: "Dirumuskan",
88998
89959
  objective: "Dirumuskan",
@@ -89035,7 +89996,7 @@ function renderTicketDoc(tickets2) {
89035
89996
  ${baris.join("\n")}`;
89036
89997
  }
89037
89998
  async function buildChatWorkspace(projectId) {
89038
- const dir2 = mkdtempSync5(join53(tmpdir9(), "hanoman-portal-chat-"));
89999
+ const dir2 = mkdtempSync5(join58(tmpdir9(), "hanoman-portal-chat-"));
89039
90000
  try {
89040
90001
  const project = await prisma.project.findUnique({
89041
90002
  where: { id: projectId },
@@ -89050,7 +90011,7 @@ async function buildChatWorkspace(projectId) {
89050
90011
  });
89051
90012
  const files2 = [];
89052
90013
  const tulis = (rel, isi) => {
89053
- writeFileSync21(join53(dir2, rel), isi, { mode: 384 });
90014
+ writeFileSync23(join58(dir2, rel), isi, { mode: 384 });
89054
90015
  files2.push(rel);
89055
90016
  };
89056
90017
  tulis("project.md", renderProjectDoc(project));
@@ -89058,16 +90019,16 @@ async function buildChatWorkspace(projectId) {
89058
90019
  tulis("laporan.md", renderTicketDoc(tickets2.map((t) => toPortalTicket(t, null))));
89059
90020
  const prds = await listPrds(projectId);
89060
90021
  if (prds.length) {
89061
- mkdirSync21(join53(dir2, "dokumen"), { mode: 448 });
90022
+ mkdirSync23(join58(dir2, "dokumen"), { mode: 448 });
89062
90023
  for (const prd of prds) {
89063
90024
  const isi = await readPrd(projectId, prd.path);
89064
90025
  if (!isi) continue;
89065
- tulis(join53("dokumen", `${prd.slug.replaceAll("/", "-")}.md`), isi);
90026
+ tulis(join58("dokumen", `${prd.slug.replaceAll("/", "-")}.md`), isi);
89066
90027
  }
89067
90028
  }
89068
- return { dir: dir2, files: files2, cleanup: () => rmSync14(dir2, { recursive: true, force: true }) };
90029
+ return { dir: dir2, files: files2, cleanup: () => rmSync16(dir2, { recursive: true, force: true }) };
89069
90030
  } catch (error) {
89070
- rmSync14(dir2, { recursive: true, force: true });
90031
+ rmSync16(dir2, { recursive: true, force: true });
89071
90032
  throw error;
89072
90033
  }
89073
90034
  }
@@ -89145,8 +90106,8 @@ function chatFailureReason(err, stdout, stderr, timeoutMs) {
89145
90106
  return `chat portal gagal (${bagaimana}): ${detail2}`;
89146
90107
  }
89147
90108
  function runProcess(p3, timeoutMs) {
89148
- return new Promise((resolve25, reject2) => {
89149
- const child = execFile20(p3.file, p3.args, {
90109
+ return new Promise((resolve26, reject2) => {
90110
+ const child = execFile21(p3.file, p3.args, {
89150
90111
  cwd: p3.cwd,
89151
90112
  timeout: timeoutMs,
89152
90113
  maxBuffer: 16 * 1024 * 1024,
@@ -89157,7 +90118,7 @@ function runProcess(p3, timeoutMs) {
89157
90118
  stdout,
89158
90119
  stderr,
89159
90120
  timeoutMs
89160
- ))) : resolve25(stdout));
90121
+ ))) : resolve26(stdout));
89161
90122
  child.stdin?.end();
89162
90123
  });
89163
90124
  }
@@ -89587,15 +90548,15 @@ init_src();
89587
90548
  init_db();
89588
90549
 
89589
90550
  // src/services/bootstrap.ts
89590
- import { createHash as createHash23, randomBytes as randomBytes11, timingSafeEqual as timingSafeEqual5 } from "node:crypto";
90551
+ import { createHash as createHash24, randomBytes as randomBytes11, timingSafeEqual as timingSafeEqual5 } from "node:crypto";
89591
90552
  import { chmod as chmod2, lstat as lstat3, mkdir as mkdir11, readFile as readFile10, unlink as unlink5, writeFile as writeFile8 } from "node:fs/promises";
89592
- import { join as join54 } from "node:path";
89593
- var TTL_MS7 = 15 * 6e4;
90553
+ import { join as join59 } from "node:path";
90554
+ var TTL_MS8 = 15 * 6e4;
89594
90555
  var SETUP_TOKEN_FILE = "setup.token";
89595
90556
  var BootstrapError = class extends Error {
89596
90557
  code = "BOOTSTRAP_PROOF";
89597
90558
  };
89598
- var tokenPath = (home3) => join54(home3, SETUP_TOKEN_FILE);
90559
+ var tokenPath = (home3) => join59(home3, SETUP_TOKEN_FILE);
89599
90560
  async function readStored(home3) {
89600
90561
  try {
89601
90562
  const info = await lstat3(tokenPath(home3));
@@ -89627,7 +90588,7 @@ async function ensureSetupToken(home3, now = Date.now()) {
89627
90588
  });
89628
90589
  }
89629
90590
  const token = randomBytes11(32).toString("base64url");
89630
- const expiresAt = now + TTL_MS7;
90591
+ const expiresAt = now + TTL_MS8;
89631
90592
  try {
89632
90593
  await writeFile8(tokenPath(home3), `${token}
89633
90594
  ${new Date(expiresAt).toISOString()}
@@ -89640,8 +90601,8 @@ ${new Date(expiresAt).toISOString()}
89640
90601
  }
89641
90602
  async function verifySetupToken(candidate, home3, now = Date.now()) {
89642
90603
  const stored = await readStored(home3);
89643
- const got = createHash23("sha256").update(candidate).digest();
89644
- const want = createHash23("sha256").update(stored.token).digest();
90604
+ const got = createHash24("sha256").update(candidate).digest();
90605
+ const want = createHash24("sha256").update(stored.token).digest();
89645
90606
  if (stored.expiresAt <= now || !timingSafeEqual5(got, want)) throw new BootstrapError("invalid setup proof");
89646
90607
  }
89647
90608
  async function consumeSetupToken(home3) {
@@ -90060,7 +91021,7 @@ init_event_log();
90060
91021
 
90061
91022
  // src/services/remote-access-request.ts
90062
91023
  init_src();
90063
- import { randomUUID as randomUUID15 } from "node:crypto";
91024
+ import { randomUUID as randomUUID16 } from "node:crypto";
90064
91025
  var REQUEST_TIER_LABEL = { lihat: "Lihat", kerja: "Kerja", tulis: "Tulis" };
90065
91026
  var entries3 = [];
90066
91027
  var accepted = [];
@@ -90084,7 +91045,7 @@ function createAccessRequest(input, now = Date.now()) {
90084
91045
  return { ok: false, reason: "rate-limited", retryAfterMs: accepted[0] + ACCESS_REQUEST_WINDOW_MS - now };
90085
91046
  accepted.push(now);
90086
91047
  const entry2 = {
90087
- id: randomUUID15(),
91048
+ id: randomUUID16(),
90088
91049
  tier: input.tier,
90089
91050
  state: "pending",
90090
91051
  requestedAt: now,
@@ -90433,7 +91394,7 @@ init_event_log();
90433
91394
  init_transcript_store();
90434
91395
  init_src2();
90435
91396
  import { readFile as readFile11 } from "node:fs/promises";
90436
- import { join as join55 } from "node:path";
91397
+ import { join as join60 } from "node:path";
90437
91398
  function decodeCursor(c) {
90438
91399
  if (!c) return null;
90439
91400
  try {
@@ -90471,7 +91432,7 @@ async function readRemoteTranscript(id2) {
90471
91432
  const row = await prisma.logEntry.findUnique({ where: { id: id2 } });
90472
91433
  if (!row || row.lane !== "transcript" || !row.transcriptKey) return null;
90473
91434
  if (row.deviceId === "local") return readTranscript(row.transcriptKey);
90474
- const path = join55(resolveDataDirs().home, "remote-transcripts", row.transcriptKey);
91435
+ const path = join60(resolveDataDirs().home, "remote-transcripts", row.transcriptKey);
90475
91436
  try {
90476
91437
  return await readFile11(path, "utf8");
90477
91438
  } catch {
@@ -90668,7 +91629,7 @@ var SETUP_PUBLIC = /* @__PURE__ */ new Set([
90668
91629
  "POST /api/setup"
90669
91630
  ]);
90670
91631
  function buildApp({ requireAuth = true, agentDocFile, env = process.env } = {}) {
90671
- const docFile = agentDocFile !== void 0 ? agentDocFile : pickGuideFile(dirname19(fileURLToPath6(import.meta.url)), env, existsSync25);
91632
+ const docFile = agentDocFile !== void 0 ? agentDocFile : pickGuideFile(dirname19(fileURLToPath6(import.meta.url)), env, existsSync26);
90672
91633
  const ingress = loadIngressPolicy(env);
90673
91634
  const app3 = Fastify({ logger: false, trustProxy: trustProxyFromEnv(env) });
90674
91635
  app3.setErrorHandler((error, _req, reply) => {
@@ -90773,6 +91734,7 @@ function buildApp({ requireAuth = true, agentDocFile, env = process.env } = {})
90773
91734
  await api.register(terminalWorkspaceRoutes);
90774
91735
  await api.register(vps_default);
90775
91736
  await api.register(limits);
91737
+ await api.register(runtime_accounts_default);
90776
91738
  await api.register(update);
90777
91739
  await api.register(events_default, wsOptions);
90778
91740
  await api.register(ws_tickets_default, { allowTestPrincipal: !requireAuth && env.NODE_ENV === "test" });
@@ -90817,7 +91779,7 @@ function buildApp({ requireAuth = true, agentDocFile, env = process.env } = {})
90817
91779
  await api.register(qaBacklog);
90818
91780
  }, { prefix: "/api" });
90819
91781
  if (shouldServeWeb(env)) {
90820
- const dist = pickWebDir(dirname19(fileURLToPath6(import.meta.url)), env, existsSync25);
91782
+ const dist = pickWebDir(dirname19(fileURLToPath6(import.meta.url)), env, existsSync26);
90821
91783
  if (dist) {
90822
91784
  app3.register(fastifyStatic, { root: dist });
90823
91785
  app3.setNotFoundHandler((req, reply) => req.url.startsWith("/api") ? reply.code(404).send({ error: "not found" }) : req.url.startsWith("/assets/") ? reply.code(404).type("text/plain").send("not found") : reply.sendFile("index.html"));
@@ -91149,7 +92111,7 @@ async function tick4(now, deps, end2 = prodEnd) {
91149
92111
  console.error("scheduler drain:", e);
91150
92112
  }
91151
92113
  }
91152
- var prodDeps3 = {
92114
+ var prodDeps5 = {
91153
92115
  liveCount: async () => (await listSessionsAsync()).filter((s2) => !s2.exited).length,
91154
92116
  isLive: async (specId) => {
91155
92117
  const s2 = await getSessionAsync(sessionIdForSpec(specId));
@@ -91183,7 +92145,7 @@ var prodDeps3 = {
91183
92145
  };
91184
92146
  var TICK_MS3 = 1e4;
91185
92147
  var timer7;
91186
- function startScheduler(deps = prodDeps3) {
92148
+ function startScheduler(deps = prodDeps5) {
91187
92149
  if (timer7) return;
91188
92150
  timer7 = setInterval(() => void tick4(Date.now(), deps), TICK_MS3);
91189
92151
  timer7.unref();
@@ -91220,16 +92182,21 @@ init_db();
91220
92182
  init_session_launch();
91221
92183
  init_session_admission2();
91222
92184
  init_notifications2();
91223
- var prodDeps4 = {
92185
+ var prodResumeStart = async (spec, runtime) => {
92186
+ if (runtime?.accountId && !accountExists(runtime.accountId))
92187
+ throw new Error(`akun runtime ${runtime.accountId} sudah dihapus \u2014 lanjutkan manual dan pilih akun lain`);
92188
+ return startSpecSession(spec, { flow: flowForSource(spec.source), ...runtime ?? {} });
92189
+ };
92190
+ var prodDeps6 = {
91224
92191
  // ADR-0170 · mengamandemen ADR-0169 keputusan #4: `bypassCapacity` DICABUT. Auto-resume kini
91225
92192
  // tunduk cap/beban host seperti "Lanjutkan" manual — mesin 8 GB operator sudah dua kali kernel
91226
92193
  // panic akibat batch sesi paralel tepat SAAT boot (memori mac-mini-8gb-panic-agen-paralel),
91227
92194
  // titik waktu paling rawan menumpuk kandidat resume. Gerbang dependency ADR-0093 tak berubah.
91228
- startSpec: (spec, runtime) => startSpecSession(spec, { flow: flowForSource(spec.source), ...runtime ?? {} }),
92195
+ startSpec: prodResumeStart,
91229
92196
  recordFail: recordFailure,
91230
92197
  recordDeferred: recordFailure
91231
92198
  };
91232
- async function resumeReconciledSessions(cutoff, deps = prodDeps4) {
92199
+ async function resumeReconciledSessions(cutoff, deps = prodDeps6) {
91233
92200
  const report = { resumed: [], failed: [], deferred: [] };
91234
92201
  const specIds = await reconciledSpecIdsSince(cutoff);
91235
92202
  if (!specIds.length) return report;
@@ -91258,6 +92225,48 @@ async function resumeReconciledSessions(cutoff, deps = prodDeps4) {
91258
92225
  return report;
91259
92226
  }
91260
92227
 
92228
+ // src/services/runtime-accounts/install.ts
92229
+ init_src();
92230
+ init_pty();
92231
+ init_antigravity_limits();
92232
+ async function installRuntimeAccounts() {
92233
+ await refreshSnapshot();
92234
+ registerAccountResolver((agent, requested) => resolveLaunchAccount(agent, requested));
92235
+ registerSessionHooks({
92236
+ // Sesi login ditutup operator → baca ulang status akun itu.
92237
+ onDeath: (d) => {
92238
+ const id2 = accountIdForLoginSession(d.sessionId);
92239
+ if (id2) void checkAccount(id2).catch((e) => console.error("akun runtime (periksa sesudah login):", e));
92240
+ }
92241
+ });
92242
+ installAntigravitySwap();
92243
+ void refreshAllStatuses().catch((e) => console.error("akun runtime (status boot):", e));
92244
+ }
92245
+ var AGY_BUILTIN2 = builtinAccountId("antigravity");
92246
+ var darwin = process.platform === "darwin";
92247
+ function installAntigravitySwap() {
92248
+ setProbe("antigravity", async (_home, accountId) => darwin ? probeAgyLogin(accountId) : { loggedIn: isBuiltinAccountId(accountId), identity: null });
92249
+ setAntigravityAccountLimits(
92250
+ (row) => agyAccountLimits(row.id),
92251
+ // Akun bawaan saat akun lain aktif: Keychain memuat login akun LAIN — baca slot bawaan, bukan Keychain.
92252
+ () => !darwin || activeAgyAccount() === AGY_BUILTIN2 ? getAntigravityLimits() : agyAccountLimits(AGY_BUILTIN2)
92253
+ );
92254
+ setAntigravityLogin(() => [agentBin("antigravity")]);
92255
+ setBeforeLogin((runtime, accountId) => {
92256
+ if (runtime === "antigravity" && darwin) activateAgyAccount(accountId);
92257
+ });
92258
+ registerSessionHooks({
92259
+ onDeath: () => {
92260
+ if (!darwin || !accountSnapshot().rows.some((r) => r.runtime === "antigravity")) return;
92261
+ try {
92262
+ captureActiveSlot();
92263
+ } catch (e) {
92264
+ console.error("akun agy (tangkap slot):", e);
92265
+ }
92266
+ }
92267
+ });
92268
+ }
92269
+
91261
92270
  // src/server.ts
91262
92271
  init_event_log();
91263
92272
  init_settings3();
@@ -91273,7 +92282,7 @@ init_tap();
91273
92282
  init_src();
91274
92283
  init_db();
91275
92284
  init_actor();
91276
- import { randomUUID as randomUUID16 } from "node:crypto";
92285
+ import { randomUUID as randomUUID17 } from "node:crypto";
91277
92286
  function skipped(def2, row) {
91278
92287
  if (!def2.skipWhen || !row) return false;
91279
92288
  return row[def2.skipWhen.field] === def2.skipWhen.equals;
@@ -91339,7 +92348,7 @@ async function emitWebhook(i) {
91339
92348
  const targets = matchingEndpoints(type, projectId);
91340
92349
  if (!targets.length) return;
91341
92350
  const name2 = projectId ? (await prisma.project.findUnique({ where: { id: projectId }, select: { name: true } }))?.name ?? null : null;
91342
- const env = buildEnvelope(i, name2, (/* @__PURE__ */ new Date()).toISOString(), `evt_${randomUUID16().replace(/-/g, "")}`);
92351
+ const env = buildEnvelope(i, name2, (/* @__PURE__ */ new Date()).toISOString(), `evt_${randomUUID17().replace(/-/g, "")}`);
91343
92352
  if (!env) return;
91344
92353
  await enqueueEnvelope(env, targets);
91345
92354
  } catch (e) {
@@ -91535,13 +92544,13 @@ init_src();
91535
92544
  init_db();
91536
92545
  init_integrate();
91537
92546
  init_local_binding();
91538
- import { execFile as execFile21 } from "node:child_process";
92547
+ import { execFile as execFile22 } from "node:child_process";
91539
92548
  import { promisify as promisify19 } from "node:util";
91540
92549
  init_notifications2();
91541
92550
  var AUTO_MERGE_WINDOW_MS = 24 * 60 * 60 * 1e3;
91542
92551
  var AUTO_MERGE_GRACE_MS = 15 * 60 * 1e3;
91543
92552
  var TICK_MS5 = 6e4;
91544
- var exec11 = promisify19(execFile21);
92553
+ var exec11 = promisify19(execFile22);
91545
92554
  var GIT8 = { timeout: 3e4, maxBuffer: 1 << 24, encoding: "utf8" };
91546
92555
  var gitOut = async (cwd, args) => {
91547
92556
  try {
@@ -91654,13 +92663,13 @@ init_src2();
91654
92663
 
91655
92664
  // src/services/secure-home.ts
91656
92665
  import { chmod as chmod3, lstat as lstat4, mkdir as mkdir12 } from "node:fs/promises";
91657
- import { isAbsolute as isAbsolute13, resolve as resolve24 } from "node:path";
92666
+ import { isAbsolute as isAbsolute13, resolve as resolve25 } from "node:path";
91658
92667
  var HomePermissionError = class extends Error {
91659
92668
  code = "HOME_SYMLINK";
91660
92669
  };
91661
92670
  async function assertNoSymlink(path, allowMissing) {
91662
92671
  try {
91663
- const info = await lstat4(resolve24(path));
92672
+ const info = await lstat4(resolve25(path));
91664
92673
  if (info.isSymbolicLink()) throw new HomePermissionError(`symlink ditolak: ${path}`);
91665
92674
  } catch (error) {
91666
92675
  if (error.code === "ENOENT" && allowMissing) return;
@@ -91754,9 +92763,9 @@ async function pruneLogs(now, retention, opts2 = {}) {
91754
92763
  }
91755
92764
  async function reconcileRemoteTranscripts() {
91756
92765
  const { readdir: readdir10, unlink: unlink6, stat: stat8 } = await import("node:fs/promises");
91757
- const { join: join56 } = await import("node:path");
92766
+ const { join: join61 } = await import("node:path");
91758
92767
  const { resolveDataDirs: resolveDataDirs2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
91759
- const root = join56(resolveDataDirs2().home, "remote-transcripts");
92768
+ const root = join61(resolveDataDirs2().home, "remote-transcripts");
91760
92769
  let deviceDirs;
91761
92770
  try {
91762
92771
  deviceDirs = await readdir10(root);
@@ -91770,16 +92779,16 @@ async function reconcileRemoteTranscripts() {
91770
92779
  for (const dev of deviceDirs) {
91771
92780
  let files2;
91772
92781
  try {
91773
- files2 = await readdir10(join56(root, dev));
92782
+ files2 = await readdir10(join61(root, dev));
91774
92783
  } catch {
91775
92784
  continue;
91776
92785
  }
91777
92786
  for (const f of files2) {
91778
92787
  const key = `${dev}/${f}`;
91779
92788
  if (referenced.has(key)) continue;
91780
- const st2 = await stat8(join56(root, dev, f)).catch(() => null);
92789
+ const st2 = await stat8(join61(root, dev, f)).catch(() => null);
91781
92790
  if (!st2 || Date.now() - st2.mtimeMs < gracePeriodMs) continue;
91782
- await unlink6(join56(root, dev, f)).catch(() => {
92791
+ await unlink6(join61(root, dev, f)).catch(() => {
91783
92792
  });
91784
92793
  orphans++;
91785
92794
  }
@@ -92022,6 +93031,7 @@ bootstrapReady.then(async () => {
92022
93031
  console.log(`hanoman api ${host}:${port}`);
92023
93032
  await installWebhooks();
92024
93033
  installSessionHistory();
93034
+ await installRuntimeAccounts();
92025
93035
  installEventTap({ transcriptEnabled: async () => (await getSetting()).logShipping.transcript });
92026
93036
  const bootSetting = await getSetting();
92027
93037
  if (bootSetting.logShipping.server) installConsoleTap();