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.
- package/dist/build-info.json +3 -3
- package/dist/cli.js +95 -4
- package/dist/server.js +1461 -451
- package/docs/agent-integration.md +6 -0
- package/package.json +2 -1
- package/prisma/migrations/20261101090000_runtime_account/migration.sql +18 -0
- package/prisma/schema.prisma +19 -0
- package/skills/codex-image/SKILL.md +225 -0
- package/skills/codex-image/references/sprite-sheets.md +60 -0
- package/skills/codex-image/scripts/codex-image.sh +253 -0
- package/skills/codex-image/scripts/normalize-set.py +104 -0
- package/web/assets/{DalangHanomanScreen-wpAO0xvb.js → DalangHanomanScreen-WQ2B2G0F.js} +1 -1
- package/web/assets/{DocPreviewModal-CbhkDUJ2.js → DocPreviewModal-DkuSjeL9.js} +1 -1
- package/web/assets/{DocsWorkspace-CcB0LGFV.js → DocsWorkspace-BJ71xmQ_.js} +1 -1
- package/web/assets/{IdeScreen-DI4v3ZkU.js → IdeScreen-Bc4gR6md.js} +1 -1
- package/web/assets/{LeadScreen-BdS_xX_f.js → LeadScreen-BmRdOMoJ.js} +1 -1
- package/web/assets/{ReviewScreen-Ddw5U2sM.js → ReviewScreen-C83FuzRB.js} +1 -1
- package/web/assets/{SchedulerScreen-D6LGVrhM.js → SchedulerScreen-BKnqWV7j.js} +1 -1
- package/web/assets/{SettingsScreen-DQZ3K43g.css → SettingsScreen-B7CruwHq.css} +1 -1
- package/web/assets/SettingsScreen-FrgI5pzO.js +62 -0
- package/web/assets/{TeamScreen-BkxPDI5P.js → TeamScreen-Dgrvomt0.js} +1 -1
- package/web/assets/TerminalScreen-D2KSQ13m.js +2 -0
- package/web/assets/{TriageScreen-B-HdZsEt.js → TriageScreen-DrPERvDs.js} +1 -1
- package/web/assets/{VpsScreen-CWp29NL_.js → VpsScreen-7sDyg5MI.js} +2 -2
- package/web/assets/fields-BNhNDKOP.js +1 -0
- package/web/assets/{index-B4b6i2tH.css → index-B0VYqeq_.css} +1 -1
- package/web/assets/{index-C4Py9MJV.js → index-NoTUDPfb.js} +212 -212
- package/web/assets/{live-CBa_7-hn.js → live-B4ZwQ4kB.js} +1 -1
- package/web/assets/{sched-lead-shared-CQIoYIzG.js → sched-lead-shared-CZ0_L34F.js} +1 -1
- package/web/assets/{settings-rebase-C3611gs8.js → settings-rebase-DwTIHvhF.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/SettingsScreen-CFNcg1T8.js +0 -62
- package/web/assets/TerminalScreen-CEQFK9Rc.js +0 -2
- 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
|
|
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
|
-
...
|
|
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
|
|
20133
|
+
const cache7 = join6(home3, "plugins", "cache");
|
|
20038
20134
|
const out4 = [];
|
|
20039
|
-
for (const marketplace of dirsIn(
|
|
20040
|
-
for (const pkg of dirsIn(join6(
|
|
20041
|
-
for (const version of dirsIn(join6(
|
|
20042
|
-
out4.push({ pkg, marketplace, dir: join6(
|
|
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(
|
|
20311
|
+
function repairSpawnHelper(resolve26, notify) {
|
|
20216
20312
|
let ptyDir;
|
|
20217
20313
|
try {
|
|
20218
|
-
ptyDir = dirname5(
|
|
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(
|
|
20237
|
-
return repairSpawnHelper(
|
|
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((
|
|
25098
|
+
return new Promise((resolve26, reject2) => {
|
|
25003
25099
|
this.close((err, data) => {
|
|
25004
|
-
return err ? reject2(err) :
|
|
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((
|
|
25138
|
+
return new Promise((resolve26, reject2) => {
|
|
25043
25139
|
this.destroy(err, (err2, data) => {
|
|
25044
|
-
return err2 ? reject2(err2) :
|
|
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((
|
|
28542
|
-
res =
|
|
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((
|
|
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 =
|
|
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((
|
|
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 =
|
|
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((
|
|
31243
|
+
return new Promise((resolve26) => {
|
|
31148
31244
|
if (this[kSize]) {
|
|
31149
|
-
this[kClosedResolve] =
|
|
31245
|
+
this[kClosedResolve] = resolve26;
|
|
31150
31246
|
} else {
|
|
31151
|
-
|
|
31247
|
+
resolve26(null);
|
|
31152
31248
|
}
|
|
31153
31249
|
});
|
|
31154
31250
|
}
|
|
31155
31251
|
[kDestroy](err) {
|
|
31156
|
-
return new Promise((
|
|
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
|
-
|
|
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((
|
|
31577
|
-
this[kClosedResolve] =
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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((
|
|
32791
|
-
finalSocket.once("secureConnect",
|
|
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((
|
|
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
|
-
|
|
33983
|
+
resolve26(null);
|
|
33888
33984
|
}
|
|
33889
33985
|
});
|
|
33890
33986
|
} else {
|
|
33891
|
-
this.on("close",
|
|
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((
|
|
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:
|
|
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:
|
|
34104
|
+
const { type, body, resolve: resolve26, stream, length } = consume3;
|
|
34009
34105
|
try {
|
|
34010
34106
|
if (type === "text") {
|
|
34011
|
-
|
|
34107
|
+
resolve26(chunksDecode(body, length, encoding));
|
|
34012
34108
|
} else if (type === "json") {
|
|
34013
|
-
|
|
34109
|
+
resolve26(JSON.parse(chunksDecode(body, length, encoding)));
|
|
34014
34110
|
} else if (type === "arrayBuffer") {
|
|
34015
|
-
|
|
34111
|
+
resolve26(chunksConcat(body, length).buffer);
|
|
34016
34112
|
} else if (type === "blob") {
|
|
34017
|
-
|
|
34113
|
+
resolve26(new Blob(body, { type: stream[kContentType] }));
|
|
34018
34114
|
} else if (type === "bytes") {
|
|
34019
|
-
|
|
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((
|
|
34305
|
+
return new Promise((resolve26, reject2) => {
|
|
34210
34306
|
request.call(this, opts2, (err, data) => {
|
|
34211
|
-
return err ? reject2(err) :
|
|
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((
|
|
34519
|
+
return new Promise((resolve26, reject2) => {
|
|
34424
34520
|
stream.call(this, opts2, factory, (err, data) => {
|
|
34425
|
-
return err ? reject2(err) :
|
|
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((
|
|
34809
|
+
return new Promise((resolve26, reject2) => {
|
|
34714
34810
|
upgrade.call(this, opts2, (err, data) => {
|
|
34715
|
-
return err ? reject2(err) :
|
|
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((
|
|
34904
|
+
return new Promise((resolve26, reject2) => {
|
|
34809
34905
|
connect2.call(this, opts2, (err, data) => {
|
|
34810
|
-
return err ? reject2(err) :
|
|
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:
|
|
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
|
|
36265
|
-
if (!
|
|
36266
|
-
const currentCallCount =
|
|
36267
|
-
const responseIndex = Math.min(currentCallCount,
|
|
36268
|
-
|
|
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
|
-
...
|
|
36271
|
-
response:
|
|
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(
|
|
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:
|
|
36290
|
-
this.#snapshots.set(hash4,
|
|
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 =
|
|
36410
|
+
const resolvedPath = resolve26(path);
|
|
36315
36411
|
await mkdir13(dirname20(resolvedPath), { recursive: true });
|
|
36316
|
-
const data = Array.from(this.#snapshots.entries()).map(([hash4,
|
|
36412
|
+
const data = Array.from(this.#snapshots.entries()).map(([hash4, snapshot4]) => ({
|
|
36317
36413
|
hash: hash4,
|
|
36318
|
-
snapshot:
|
|
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
|
|
36349
|
-
|
|
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
|
|
36371
|
-
if (!
|
|
36466
|
+
const snapshot4 = this.#snapshots.get(hash4);
|
|
36467
|
+
if (!snapshot4) return null;
|
|
36372
36468
|
return {
|
|
36373
36469
|
hash: hash4,
|
|
36374
|
-
request:
|
|
36375
|
-
responseCount:
|
|
36470
|
+
request: snapshot4.request,
|
|
36471
|
+
responseCount: snapshot4.responses ? snapshot4.responses.length : snapshot4.response ? 1 : 0,
|
|
36376
36472
|
// .response for legacy snapshots
|
|
36377
|
-
callCount:
|
|
36378
|
-
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:
|
|
36390
|
-
this.#snapshots.set(hash4,
|
|
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
|
|
36528
|
-
if (
|
|
36529
|
-
return this.#replaySnapshot(
|
|
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(
|
|
36695
|
+
#replaySnapshot(snapshot4, handler) {
|
|
36600
36696
|
try {
|
|
36601
|
-
const { response } =
|
|
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
|
|
36660
|
-
const { request, responses, response } =
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
44293
|
-
const backupCache = [...
|
|
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 =
|
|
44416
|
+
const idx = cache7.indexOf(requestResponse);
|
|
44321
44417
|
assert(idx !== -1);
|
|
44322
|
-
|
|
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 =
|
|
44448
|
+
const idx = cache7.indexOf(requestResponse);
|
|
44353
44449
|
assert(idx !== -1);
|
|
44354
|
-
|
|
44450
|
+
cache7.splice(idx, 1);
|
|
44355
44451
|
}
|
|
44356
|
-
|
|
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
|
|
44534
|
-
return await
|
|
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
|
|
44539
|
-
const response = await
|
|
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
|
|
44570
|
-
return new Cache(kConstruct,
|
|
44665
|
+
const cache8 = this.#caches.get(cacheName);
|
|
44666
|
+
return new Cache(kConstruct, cache8);
|
|
44571
44667
|
}
|
|
44572
|
-
const
|
|
44573
|
-
this.#caches.set(cacheName,
|
|
44574
|
-
return new Cache(kConstruct,
|
|
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((
|
|
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 = () =>
|
|
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((
|
|
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
|
-
|
|
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 (
|
|
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((
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
|
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
|
|
49937
|
-
const repair = () => ensureSpawnHelper(
|
|
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((
|
|
50506
|
-
release =
|
|
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((
|
|
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
|
-
|
|
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
|
|
55885
|
-
const afterEntity =
|
|
55886
|
-
const afterId =
|
|
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((
|
|
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:
|
|
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((
|
|
59043
|
+
return new Promise((resolve26) => {
|
|
58912
59044
|
const timer11 = setTimeout(() => {
|
|
58913
59045
|
waiters.delete(id2);
|
|
58914
|
-
void closeEvent(id2, "late").catch(() => false).finally(() =>
|
|
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
|
-
|
|
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/
|
|
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 {
|
|
59068
|
-
|
|
59069
|
-
|
|
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
|
|
59074
|
-
const base3 = ["find-generic-password", "-s",
|
|
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
|
|
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
|
|
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
|
|
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
|
|
59131
|
-
|
|
59132
|
-
lastOk = dto;
|
|
59133
|
-
return dto;
|
|
59294
|
+
if (!res.ok) return null;
|
|
59295
|
+
return mapWindows(await res.json());
|
|
59134
59296
|
} catch {
|
|
59135
|
-
return
|
|
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,
|
|
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
|
-
|
|
59161
|
-
|
|
59335
|
+
securityRun2 = (args) => execFileSync7("security", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
59336
|
+
osAccount2 = () => {
|
|
59162
59337
|
try {
|
|
59163
|
-
return
|
|
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
|
|
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
|
|
59471
|
+
function parseAgyToken(raw) {
|
|
59297
59472
|
try {
|
|
59298
|
-
let
|
|
59473
|
+
let s2 = raw.trim();
|
|
59299
59474
|
const prefix = "go-keyring-base64:";
|
|
59300
|
-
if (
|
|
59301
|
-
const tok = JSON.parse(
|
|
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
|
|
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
|
|
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
|
|
59546
|
+
if (!res.ok) return null;
|
|
59370
59547
|
const windows = mapQuota(await res.json());
|
|
59371
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
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) =>
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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:
|
|
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 =
|
|
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:
|
|
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 =
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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) =>
|
|
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((
|
|
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
|
|
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) =>
|
|
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
|
|
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 (
|
|
68436
|
+
if (cache4 && now - cache4.at < TTL_MS6) return cache4.version;
|
|
68250
68437
|
const version = await probeCodexVersion();
|
|
68251
|
-
|
|
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
|
-
|
|
68450
|
+
cache4 = null;
|
|
68264
68451
|
}
|
|
68265
|
-
var run3, CODEX_MIN_CLIENT,
|
|
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(
|
|
68459
|
+
run3 = promisify17(execFile18);
|
|
68273
68460
|
CODEX_MIN_CLIENT = "0.144.0";
|
|
68274
|
-
|
|
68275
|
-
|
|
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
|
|
68286
|
-
import { homedir as
|
|
68287
|
-
import { join as
|
|
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(
|
|
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(
|
|
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 ||
|
|
68495
|
+
home = () => process.env.HOME || homedir16();
|
|
68309
68496
|
readJson2 = (path) => {
|
|
68310
68497
|
try {
|
|
68311
|
-
return JSON.parse(
|
|
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 =
|
|
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
|
|
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) =>
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
68562
|
-
const project =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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((
|
|
71366
|
+
return new Promise((resolve26, reject2) => {
|
|
71180
71367
|
stream.on("data", () => {
|
|
71181
71368
|
});
|
|
71182
71369
|
stream.on("close", () => {
|
|
71183
|
-
|
|
71370
|
+
resolve26();
|
|
71184
71371
|
});
|
|
71185
71372
|
stream.on("end", () => {
|
|
71186
|
-
|
|
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((
|
|
71822
|
+
return new Promise((resolve26, reject2) => {
|
|
71636
71823
|
handle((val) => {
|
|
71637
71824
|
if (val instanceof Error) return reject2(val);
|
|
71638
|
-
|
|
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
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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)
|
|
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((
|
|
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
|
|
78585
|
-
import { execFileSync as
|
|
78586
|
-
import { randomUUID as
|
|
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
|
|
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) =>
|
|
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
|
|
78921
|
+
import { randomBytes as randomBytes5, createHash as createHash19 } from "node:crypto";
|
|
78729
78922
|
var newDeviceToken = () => randomBytes5(32).toString("base64url");
|
|
78730
|
-
var tokenHash = (token) =>
|
|
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
|
|
79044
|
-
import { execFileSync as
|
|
79045
|
-
import { homedir as
|
|
79046
|
-
import { readFileSync as
|
|
79047
|
-
import { isAbsolute as isAbsolute12, relative as relative8, resolve as
|
|
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
|
|
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 =
|
|
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 =
|
|
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) =>
|
|
79946
|
+
var hash3 = (value) => createHash20("sha256").update(value).digest("hex");
|
|
79206
79947
|
var defaultGitStatus = (cwd) => {
|
|
79207
79948
|
try {
|
|
79208
|
-
return
|
|
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
|
|
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
|
-
|
|
79237
|
-
|
|
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(
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
|
79604
|
-
import { join as
|
|
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) =>
|
|
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
|
-
|
|
79617
|
-
|
|
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(
|
|
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
|
|
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-${
|
|
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
|
-
|
|
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 (!
|
|
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
|
|
80349
|
-
import { homedir as
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
80579
|
-
const path =
|
|
80580
|
-
|
|
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((
|
|
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)
|
|
80620
|
-
|
|
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
|
|
80641
|
-
import { join as
|
|
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
|
|
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:
|
|
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 = () =>
|
|
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
|
|
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:
|
|
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
|
|
80991
|
-
import { chmodSync as
|
|
80992
|
-
import { homedir as
|
|
80993
|
-
import { join as
|
|
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 =
|
|
81753
|
+
const legacy = join50(homedir13(), ".hanoman");
|
|
80999
81754
|
if (legacy === dir2) return;
|
|
81000
|
-
if (!KEY_FILES.every((f) =>
|
|
81001
|
-
|
|
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(
|
|
81004
|
-
|
|
81758
|
+
copyFileSync(join50(legacy, f), join50(dir2, f));
|
|
81759
|
+
chmodSync12(join50(dir2, f), 384);
|
|
81005
81760
|
}
|
|
81006
|
-
for (const f of KEY_FILES) unlinkSync5(
|
|
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 =
|
|
81766
|
+
const privPath = join50(dir2, KEY_FILES[0]);
|
|
81012
81767
|
const pubPath = `${privPath}.pub`;
|
|
81013
|
-
if (!
|
|
81014
|
-
if (!
|
|
81015
|
-
|
|
81016
|
-
|
|
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:
|
|
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 && !
|
|
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:
|
|
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}`,
|
|
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}`,
|
|
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
|
|
82297
|
+
import { execFile as execFile19 } from "node:child_process";
|
|
81340
82298
|
import { promisify as promisify18 } from "node:util";
|
|
81341
|
-
var run4 = promisify18(
|
|
81342
|
-
var
|
|
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
|
|
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
|
-
|
|
82349
|
+
cache7 = void 0;
|
|
81392
82350
|
pending2 = void 0;
|
|
81393
82351
|
}
|
|
81394
|
-
if (
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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((
|
|
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
|
|
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(
|
|
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
|
|
82631
|
+
const cached4 = parseCachedCatalog(await deps.read());
|
|
81674
82632
|
if (!current()) return state;
|
|
81675
|
-
state =
|
|
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}.${
|
|
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 = () =>
|
|
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
|
|
81923
|
-
const total = input + output +
|
|
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:
|
|
82889
|
+
cached: cached4,
|
|
81932
82890
|
total,
|
|
81933
|
-
cacheHitPct: input +
|
|
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
|
|
82927
|
-
import { join as
|
|
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) =>
|
|
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
|
-
|
|
82959
|
-
const file =
|
|
82960
|
-
|
|
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
|
|
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 =
|
|
84977
|
+
const dir2 = join55(resolveDataDirs().home, "remote-transcripts", deviceId);
|
|
84017
84978
|
await mkdir10(dir2, { recursive: true, mode: 448 });
|
|
84018
|
-
const final =
|
|
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
|
|
85534
|
+
import { createHash as createHash22, randomBytes as randomBytes7 } from "node:crypto";
|
|
84574
85535
|
function hashAccessKey(key) {
|
|
84575
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
87042
|
+
const nextStatus2 = p3.status ?? existing.status;
|
|
86082
87043
|
const nextVerdict = p3.verdict === void 0 ? existing.verdict : p3.verdict;
|
|
86083
|
-
if ((
|
|
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
|
|
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 ??
|
|
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")
|
|
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())
|
|
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)
|
|
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)
|
|
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))
|
|
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")
|
|
86675
|
-
if (used.has(qaCodeKey(code)))
|
|
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))
|
|
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)
|
|
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))
|
|
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)
|
|
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)
|
|
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")
|
|
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))
|
|
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)
|
|
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((
|
|
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", () =>
|
|
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
|
|
87422
|
-
import { execFileSync as
|
|
87423
|
-
import { join as
|
|
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-${
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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((
|
|
87772
|
-
|
|
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
|
-
|
|
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
|
|
89326
|
+
var cache6 = [];
|
|
88366
89327
|
function webhooksActive() {
|
|
88367
|
-
return
|
|
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
|
-
|
|
89333
|
+
cache6 = rows.map(normalize2);
|
|
88373
89334
|
} catch {
|
|
88374
|
-
|
|
89335
|
+
cache6 = [];
|
|
88375
89336
|
}
|
|
88376
89337
|
}
|
|
88377
89338
|
function matchingEndpoints(eventType, projectId) {
|
|
88378
|
-
return
|
|
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
|
|
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
|
|
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
|
|
89410
|
+
if (!guard.ok) return fail5(guard.error);
|
|
88450
89411
|
const secret = secretOf(o.endpoint);
|
|
88451
|
-
if (!secret) return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
90026
|
+
tulis(join58("dokumen", `${prd.slug.replaceAll("/", "-")}.md`), isi);
|
|
89066
90027
|
}
|
|
89067
90028
|
}
|
|
89068
|
-
return { dir: dir2, files: files2, cleanup: () =>
|
|
90029
|
+
return { dir: dir2, files: files2, cleanup: () => rmSync16(dir2, { recursive: true, force: true }) };
|
|
89069
90030
|
} catch (error) {
|
|
89070
|
-
|
|
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((
|
|
89149
|
-
const child =
|
|
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
|
-
))) :
|
|
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
|
|
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
|
|
89593
|
-
var
|
|
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) =>
|
|
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 +
|
|
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 =
|
|
89644
|
-
const want =
|
|
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
|
|
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:
|
|
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
|
|
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 =
|
|
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,
|
|
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,
|
|
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
|
|
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 =
|
|
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
|
|
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:
|
|
92195
|
+
startSpec: prodResumeStart,
|
|
91229
92196
|
recordFail: recordFailure,
|
|
91230
92197
|
recordDeferred: recordFailure
|
|
91231
92198
|
};
|
|
91232
|
-
async function resumeReconciledSessions(cutoff, deps =
|
|
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
|
|
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_${
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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:
|
|
92766
|
+
const { join: join61 } = await import("node:path");
|
|
91758
92767
|
const { resolveDataDirs: resolveDataDirs2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
|
|
91759
|
-
const root =
|
|
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(
|
|
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(
|
|
92789
|
+
const st2 = await stat8(join61(root, dev, f)).catch(() => null);
|
|
91781
92790
|
if (!st2 || Date.now() - st2.mtimeMs < gracePeriodMs) continue;
|
|
91782
|
-
await unlink6(
|
|
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();
|