hanoman 0.1.53 → 0.1.55
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 +23 -0
- package/dist/server.js +120 -76
- package/package.json +1 -1
- package/web/assets/{index-ChXVk9Y2.css → index-BvWb4bQR.css} +1 -1
- package/web/assets/{index-fCgQsVLZ.js → index-CZB7jrsl.js} +1544 -1544
- package/web/index.html +2 -2
package/dist/build-info.json
CHANGED
package/dist/cli.js
CHANGED
|
@@ -7284,6 +7284,28 @@ var init_terminal_workspace = __esm({
|
|
|
7284
7284
|
}
|
|
7285
7285
|
});
|
|
7286
7286
|
|
|
7287
|
+
// ../shared/src/terminal-io.ts
|
|
7288
|
+
var TERMINAL_RESPONSE;
|
|
7289
|
+
var init_terminal_io = __esm({
|
|
7290
|
+
"../shared/src/terminal-io.ts"() {
|
|
7291
|
+
"use strict";
|
|
7292
|
+
TERMINAL_RESPONSE = new RegExp([
|
|
7293
|
+
"\\x1b\\[[?>][0-9;]*c",
|
|
7294
|
+
// balasan DA
|
|
7295
|
+
"\\x1b\\[\\??[0-9]+;[0-9]+R",
|
|
7296
|
+
// CPR / DECXCPR
|
|
7297
|
+
"\\x1b\\[\\??[0-9;]*n",
|
|
7298
|
+
// balasan DSR
|
|
7299
|
+
"\\x1b\\[\\??[0-9;]*\\$y",
|
|
7300
|
+
// DECRPM
|
|
7301
|
+
"\\x1b\\][0-9][0-9;]*;[^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)",
|
|
7302
|
+
// balasan warna OSC
|
|
7303
|
+
"\\x1bP[0-9]*[$+>][a-z|][^\\x1b]*\\x1b\\\\"
|
|
7304
|
+
// DECRPSS / XTGETTCAP / XTVERSION
|
|
7305
|
+
].join("|"), "g");
|
|
7306
|
+
}
|
|
7307
|
+
});
|
|
7308
|
+
|
|
7287
7309
|
// ../shared/src/index.ts
|
|
7288
7310
|
var init_src = __esm({
|
|
7289
7311
|
"../shared/src/index.ts"() {
|
|
@@ -7318,6 +7340,7 @@ var init_src = __esm({
|
|
|
7318
7340
|
init_changelog();
|
|
7319
7341
|
init_cron_expr();
|
|
7320
7342
|
init_terminal_workspace();
|
|
7343
|
+
init_terminal_io();
|
|
7321
7344
|
}
|
|
7322
7345
|
});
|
|
7323
7346
|
|
package/dist/server.js
CHANGED
|
@@ -7889,6 +7889,29 @@ var init_terminal_workspace = __esm({
|
|
|
7889
7889
|
}
|
|
7890
7890
|
});
|
|
7891
7891
|
|
|
7892
|
+
// ../shared/src/terminal-io.ts
|
|
7893
|
+
var TERMINAL_RESPONSE, isTerminalResponse;
|
|
7894
|
+
var init_terminal_io = __esm({
|
|
7895
|
+
"../shared/src/terminal-io.ts"() {
|
|
7896
|
+
"use strict";
|
|
7897
|
+
TERMINAL_RESPONSE = new RegExp([
|
|
7898
|
+
"\\x1b\\[[?>][0-9;]*c",
|
|
7899
|
+
// balasan DA
|
|
7900
|
+
"\\x1b\\[\\??[0-9]+;[0-9]+R",
|
|
7901
|
+
// CPR / DECXCPR
|
|
7902
|
+
"\\x1b\\[\\??[0-9;]*n",
|
|
7903
|
+
// balasan DSR
|
|
7904
|
+
"\\x1b\\[\\??[0-9;]*\\$y",
|
|
7905
|
+
// DECRPM
|
|
7906
|
+
"\\x1b\\][0-9][0-9;]*;[^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)",
|
|
7907
|
+
// balasan warna OSC
|
|
7908
|
+
"\\x1bP[0-9]*[$+>][a-z|][^\\x1b]*\\x1b\\\\"
|
|
7909
|
+
// DECRPSS / XTGETTCAP / XTVERSION
|
|
7910
|
+
].join("|"), "g");
|
|
7911
|
+
isTerminalResponse = (d) => d.length > 0 && d.replace(TERMINAL_RESPONSE, "") === "";
|
|
7912
|
+
}
|
|
7913
|
+
});
|
|
7914
|
+
|
|
7892
7915
|
// ../shared/src/index.ts
|
|
7893
7916
|
var init_src = __esm({
|
|
7894
7917
|
"../shared/src/index.ts"() {
|
|
@@ -7923,6 +7946,7 @@ var init_src = __esm({
|
|
|
7923
7946
|
init_changelog();
|
|
7924
7947
|
init_cron_expr();
|
|
7925
7948
|
init_terminal_workspace();
|
|
7949
|
+
init_terminal_io();
|
|
7926
7950
|
}
|
|
7927
7951
|
});
|
|
7928
7952
|
|
|
@@ -10736,7 +10760,7 @@ function spawnPty(...args) {
|
|
|
10736
10760
|
);
|
|
10737
10761
|
}
|
|
10738
10762
|
}
|
|
10739
|
-
var socket, PREFIX, MAX_SCROLLBACK, SCROLLBACK_SLACK, POLL_MS, markerFilled, attached, claudeBin, shellBin, codexBin, agentBin, rootBypassEnv, frame, name, promptFilePath, goalGatePath, goalStatePath, agentsFilePath, askpassDenyPath, ASKPASS_DENY, NO_SERVER, TmuxError, sq, idFor, FMT, listSessions, liveDecisions, getSession, hooks, emitBirth, emitDeath, customAgentSource, customAgentsFor, sleep, paneText, dialogIO, DIALOG_CAPTURE_LINES, GOAL_ARMED_MARKERS, goalArmed, COALESCE_MS, COALESCE_MAX_BYTES, trimScrollback, phaseKey, paneComplete, sessionFinished, poll, TERMINAL_QUERY, stripTerminalQueries,
|
|
10763
|
+
var socket, PREFIX, MAX_SCROLLBACK, SCROLLBACK_SLACK, POLL_MS, markerFilled, attached, claudeBin, shellBin, codexBin, agentBin, rootBypassEnv, frame, name, promptFilePath, goalGatePath, goalStatePath, agentsFilePath, askpassDenyPath, ASKPASS_DENY, NO_SERVER, TmuxError, sq, idFor, FMT, listSessions, liveDecisions, getSession, hooks, emitBirth, emitDeath, customAgentSource, customAgentsFor, sleep, paneText, dialogIO, DIALOG_CAPTURE_LINES, GOAL_ARMED_MARKERS, goalArmed, COALESCE_MS, COALESCE_MAX_BYTES, trimScrollback, phaseKey, paneComplete, sessionFinished, poll, TERMINAL_QUERY, stripTerminalQueries, detach;
|
|
10740
10764
|
var init_pty = __esm({
|
|
10741
10765
|
"src/services/pty.ts"() {
|
|
10742
10766
|
"use strict";
|
|
@@ -10898,21 +10922,6 @@ exit 1
|
|
|
10898
10922
|
// XTWINOPS laporan — berparameter TUNGGAL
|
|
10899
10923
|
].join("|"), "g");
|
|
10900
10924
|
stripTerminalQueries = (s2) => s2.replace(TERMINAL_QUERY, "");
|
|
10901
|
-
TERMINAL_RESPONSE = new RegExp([
|
|
10902
|
-
"\\x1b\\[[?>][0-9;]*c",
|
|
10903
|
-
// balasan DA
|
|
10904
|
-
"\\x1b\\[\\??[0-9]+;[0-9]+R",
|
|
10905
|
-
// CPR / DECXCPR
|
|
10906
|
-
"\\x1b\\[\\??[0-9;]*n",
|
|
10907
|
-
// balasan DSR
|
|
10908
|
-
"\\x1b\\[\\??[0-9;]*\\$y",
|
|
10909
|
-
// DECRPM
|
|
10910
|
-
"\\x1b\\][0-9][0-9;]*;[^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)",
|
|
10911
|
-
// balasan warna OSC
|
|
10912
|
-
"\\x1bP[0-9]*[$+>][a-z|][^\\x1b]*\\x1b\\\\"
|
|
10913
|
-
// DECRPSS / XTGETTCAP / XTVERSION
|
|
10914
|
-
].join("|"), "g");
|
|
10915
|
-
isTerminalResponse = (d) => d.length > 0 && d.replace(TERMINAL_RESPONSE, "") === "";
|
|
10916
10925
|
detach = (id, c) => {
|
|
10917
10926
|
attached.get(id)?.clients.delete(c);
|
|
10918
10927
|
};
|
|
@@ -39250,6 +39259,33 @@ function installCommand(m, agent, shell = shellBin()) {
|
|
|
39250
39259
|
return [shell, "-lc", `${m.install[agent].join(" && ")}; exec '${shell}' -l`];
|
|
39251
39260
|
}
|
|
39252
39261
|
|
|
39262
|
+
// src/services/terminal-diag.ts
|
|
39263
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, statSync as statSync3, rmSync as rmSync4 } from "node:fs";
|
|
39264
|
+
import { join as join15 } from "node:path";
|
|
39265
|
+
var DIAG_MAX_BYTES = 2 * 1024 * 1024;
|
|
39266
|
+
var KINDS = /* @__PURE__ */ new Set(["key", "comp", "data", "ack", "pred"]);
|
|
39267
|
+
var ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
39268
|
+
function diagFile(home3, sessionId2) {
|
|
39269
|
+
if (!ID.test(sessionId2)) throw new Error(`id sesi tak sah untuk diag: ${sessionId2}`);
|
|
39270
|
+
return join15(home3, "diag", `${sessionId2}.jsonl`);
|
|
39271
|
+
}
|
|
39272
|
+
function usable(ev) {
|
|
39273
|
+
if (!ev || typeof ev !== "object") return false;
|
|
39274
|
+
const e = ev;
|
|
39275
|
+
return typeof e.t === "number" && typeof e.k === "string" && KINDS.has(e.k) && typeof e.v === "string" && (e.n === void 0 || typeof e.n === "number");
|
|
39276
|
+
}
|
|
39277
|
+
function appendDiag(home3, sessionId2, events2) {
|
|
39278
|
+
const file = diagFile(home3, sessionId2);
|
|
39279
|
+
const rows = events2.filter(usable);
|
|
39280
|
+
if (!rows.length) return;
|
|
39281
|
+
mkdirSync8(join15(home3, "diag"), { recursive: true });
|
|
39282
|
+
try {
|
|
39283
|
+
if (statSync3(file).size > DIAG_MAX_BYTES) rmSync4(file);
|
|
39284
|
+
} catch {
|
|
39285
|
+
}
|
|
39286
|
+
appendFileSync2(file, rows.map((r) => JSON.stringify(r)).join("\n") + "\n");
|
|
39287
|
+
}
|
|
39288
|
+
|
|
39253
39289
|
// src/routes/terminal.ts
|
|
39254
39290
|
init_notifications();
|
|
39255
39291
|
init_stage_machine();
|
|
@@ -39595,8 +39631,16 @@ async function terminal_default(app2, opts) {
|
|
|
39595
39631
|
} catch {
|
|
39596
39632
|
return;
|
|
39597
39633
|
}
|
|
39598
|
-
if (m.t === "in" && typeof m.d === "string")
|
|
39599
|
-
|
|
39634
|
+
if (m.t === "in" && typeof m.d === "string") {
|
|
39635
|
+
writeTo(id, m.d, client);
|
|
39636
|
+
if (typeof m.seq === "number") socket2.send(JSON.stringify({ t: "ack", seq: m.seq }));
|
|
39637
|
+
} else if (m.t === "resize" && m.cols && m.rows) resize(id, m.cols, m.rows);
|
|
39638
|
+
else if (m.t === "diag" && Array.isArray(m.ev)) {
|
|
39639
|
+
try {
|
|
39640
|
+
appendDiag(resolveHome(), id, m.ev);
|
|
39641
|
+
} catch {
|
|
39642
|
+
}
|
|
39643
|
+
}
|
|
39600
39644
|
});
|
|
39601
39645
|
const revalidate = setInterval(() => {
|
|
39602
39646
|
void revalidateWsPrincipal(req, principal).then((ok2) => {
|
|
@@ -39790,9 +39834,9 @@ import { readFileSync as readFileSync8 } from "node:fs";
|
|
|
39790
39834
|
// src/services/vps-ssh.ts
|
|
39791
39835
|
init_config2();
|
|
39792
39836
|
import { spawn as spawn4 } from "node:child_process";
|
|
39793
|
-
import { mkdtempSync, rmSync as
|
|
39837
|
+
import { mkdtempSync, rmSync as rmSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
39794
39838
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
39795
|
-
import { dirname as dirname10, join as
|
|
39839
|
+
import { dirname as dirname10, join as join16 } from "node:path";
|
|
39796
39840
|
var sshBin = () => effectiveStr("HANOMAN_SSH_BIN") ?? "ssh";
|
|
39797
39841
|
function consoleArgv(t) {
|
|
39798
39842
|
return [
|
|
@@ -39807,8 +39851,8 @@ function consoleArgv(t) {
|
|
|
39807
39851
|
];
|
|
39808
39852
|
}
|
|
39809
39853
|
function askpassScript() {
|
|
39810
|
-
const dir2 = mkdtempSync(
|
|
39811
|
-
const path2 =
|
|
39854
|
+
const dir2 = mkdtempSync(join16(tmpdir3(), "hanoman-askpass-"));
|
|
39855
|
+
const path2 = join16(dir2, "askpass.sh");
|
|
39812
39856
|
writeFileSync4(path2, `#!/bin/sh
|
|
39813
39857
|
printf '%s' "$HANOMAN_SSH_PASSWORD"
|
|
39814
39858
|
`, { mode: 448 });
|
|
@@ -39848,7 +39892,7 @@ function sshExec(t, remoteCmd, opts = {}) {
|
|
|
39848
39892
|
const timer9 = setTimeout(() => p.kill("SIGKILL"), opts.timeoutMs ?? 6e4);
|
|
39849
39893
|
const done = (r) => {
|
|
39850
39894
|
clearTimeout(timer9);
|
|
39851
|
-
if (askpass)
|
|
39895
|
+
if (askpass) rmSync5(dirname10(askpass), { recursive: true, force: true });
|
|
39852
39896
|
resolve21(r);
|
|
39853
39897
|
};
|
|
39854
39898
|
p.stdout.on("data", (d) => {
|
|
@@ -39869,15 +39913,15 @@ function sshExec(t, remoteCmd, opts = {}) {
|
|
|
39869
39913
|
// src/services/vps-audit.ts
|
|
39870
39914
|
init_db();
|
|
39871
39915
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
39872
|
-
import { join as
|
|
39916
|
+
import { join as join18 } from "node:path";
|
|
39873
39917
|
|
|
39874
39918
|
// src/runner/deps.ts
|
|
39875
39919
|
import { existsSync as existsSync11 } from "node:fs";
|
|
39876
|
-
import { dirname as dirname11, join as
|
|
39920
|
+
import { dirname as dirname11, join as join17 } from "node:path";
|
|
39877
39921
|
function repoRootFrom(startDir) {
|
|
39878
39922
|
let dir2 = startDir;
|
|
39879
39923
|
for (let i = 0; i < 8; i++) {
|
|
39880
|
-
if (existsSync11(
|
|
39924
|
+
if (existsSync11(join17(dir2, "pnpm-workspace.yaml"))) return dir2;
|
|
39881
39925
|
const parent = dirname11(dir2);
|
|
39882
39926
|
if (parent === dir2) break;
|
|
39883
39927
|
dir2 = parent;
|
|
@@ -39983,7 +40027,7 @@ function parseHealth(out4) {
|
|
|
39983
40027
|
return { uptime: h.uptime ?? "", disk: h.disk ?? "", mem: h.mem ?? "", load: h.load ?? "" };
|
|
39984
40028
|
}
|
|
39985
40029
|
var target = (v) => ({ host: v.host, port: v.port, user: v.user, keyPath: v.keyPath });
|
|
39986
|
-
var scriptPath = (f) =>
|
|
40030
|
+
var scriptPath = (f) => join18(repoRoot(), "server", "scripts", "vps", f);
|
|
39987
40031
|
async function itemStatesOf(vpsId) {
|
|
39988
40032
|
const rows = await prisma.vpsItemState.findMany({ where: { vpsId } });
|
|
39989
40033
|
return Object.fromEntries(rows.map((s2) => [s2.itemId, { na: s2.na, attested: s2.attested }]));
|
|
@@ -40131,31 +40175,31 @@ async function buildChecklist(vpsId) {
|
|
|
40131
40175
|
init_src2();
|
|
40132
40176
|
init_config2();
|
|
40133
40177
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
40134
|
-
import { chmodSync as chmodSync3, copyFileSync, existsSync as existsSync12, mkdirSync as
|
|
40178
|
+
import { chmodSync as chmodSync3, copyFileSync, existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync9, unlinkSync as unlinkSync2 } from "node:fs";
|
|
40135
40179
|
import { homedir as homedir5 } from "node:os";
|
|
40136
|
-
import { join as
|
|
40180
|
+
import { join as join19 } from "node:path";
|
|
40137
40181
|
var keyDir = () => effectiveStr("HANOMAN_SSH_KEY_DIR") ?? resolveDataDirs().sshKeys;
|
|
40138
40182
|
var KEY_FILES = ["id_ed25519", "id_ed25519.pub"];
|
|
40139
40183
|
function adoptLegacyKey(dir2) {
|
|
40140
40184
|
if (effectiveStr("HANOMAN_SSH_KEY_DIR")) return;
|
|
40141
|
-
const legacy =
|
|
40185
|
+
const legacy = join19(homedir5(), ".hanoman");
|
|
40142
40186
|
if (legacy === dir2) return;
|
|
40143
|
-
if (!KEY_FILES.every((f) => existsSync12(
|
|
40144
|
-
|
|
40187
|
+
if (!KEY_FILES.every((f) => existsSync12(join19(legacy, f)))) return;
|
|
40188
|
+
mkdirSync9(dir2, { recursive: true, mode: 448 });
|
|
40145
40189
|
for (const f of KEY_FILES) {
|
|
40146
|
-
copyFileSync(
|
|
40147
|
-
chmodSync3(
|
|
40190
|
+
copyFileSync(join19(legacy, f), join19(dir2, f));
|
|
40191
|
+
chmodSync3(join19(dir2, f), 384);
|
|
40148
40192
|
}
|
|
40149
|
-
for (const f of KEY_FILES) unlinkSync2(
|
|
40193
|
+
for (const f of KEY_FILES) unlinkSync2(join19(legacy, f));
|
|
40150
40194
|
console.log(`vps: key SSH dipindah dari ${legacy} ke ${dir2} (SPEC-846 \u2014 satu batas backup)`);
|
|
40151
40195
|
}
|
|
40152
40196
|
function ensureHanomanKey() {
|
|
40153
40197
|
const dir2 = keyDir();
|
|
40154
|
-
const privPath =
|
|
40198
|
+
const privPath = join19(dir2, KEY_FILES[0]);
|
|
40155
40199
|
const pubPath = `${privPath}.pub`;
|
|
40156
40200
|
if (!existsSync12(privPath)) adoptLegacyKey(dir2);
|
|
40157
40201
|
if (!existsSync12(privPath)) {
|
|
40158
|
-
|
|
40202
|
+
mkdirSync9(dir2, { recursive: true, mode: 448 });
|
|
40159
40203
|
execFileSync2(
|
|
40160
40204
|
"ssh-keygen",
|
|
40161
40205
|
["-t", "ed25519", "-N", "", "-C", "hanoman", "-f", privPath],
|
|
@@ -40390,7 +40434,7 @@ init_config2();
|
|
|
40390
40434
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
40391
40435
|
import { readFileSync as readFileSync11 } from "node:fs";
|
|
40392
40436
|
import { homedir as homedir7 } from "node:os";
|
|
40393
|
-
import { join as
|
|
40437
|
+
import { join as join20 } from "node:path";
|
|
40394
40438
|
var USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
40395
40439
|
var TTL_MS2 = 3e4;
|
|
40396
40440
|
var lastOk = null;
|
|
@@ -40403,7 +40447,7 @@ var LABELS = {
|
|
|
40403
40447
|
var humanize = (k) => k.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
40404
40448
|
var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
40405
40449
|
function credsFile() {
|
|
40406
|
-
return
|
|
40450
|
+
return join20(effectiveStr("CLAUDE_CONFIG_DIR") ?? join20(homedir7(), ".claude"), ".credentials.json");
|
|
40407
40451
|
}
|
|
40408
40452
|
function readAccessToken() {
|
|
40409
40453
|
if (process.platform === "darwin" && !effectiveStr("CLAUDE_CONFIG_DIR")) {
|
|
@@ -40477,14 +40521,14 @@ async function getLimits() {
|
|
|
40477
40521
|
// src/services/codex-limits.ts
|
|
40478
40522
|
import { open as open3, readdir as readdir4, stat as stat2 } from "node:fs/promises";
|
|
40479
40523
|
import { homedir as homedir8 } from "node:os";
|
|
40480
|
-
import { join as
|
|
40524
|
+
import { join as join21 } from "node:path";
|
|
40481
40525
|
var TTL_MS3 = 3e4;
|
|
40482
40526
|
var STALE_AFTER_MS = 12 * 36e5;
|
|
40483
40527
|
var TAIL_BYTES = 512 * 1024;
|
|
40484
40528
|
var MAX_FILES = 8;
|
|
40485
40529
|
var cache3 = null;
|
|
40486
40530
|
var freshUntil2 = 0;
|
|
40487
|
-
var codexSessionsDir = () =>
|
|
40531
|
+
var codexSessionsDir = () => join21(process.env.CODEX_HOME ?? join21(homedir8(), ".codex"), "sessions");
|
|
40488
40532
|
var UNAVAILABLE = { status: "unavailable", windows: [], fetchedAt: null, plan: null };
|
|
40489
40533
|
function windowLabel(minutes) {
|
|
40490
40534
|
if (minutes === 300) return "Sesi 5 jam";
|
|
@@ -40517,7 +40561,7 @@ async function recentRollouts(dir2) {
|
|
|
40517
40561
|
return [];
|
|
40518
40562
|
}
|
|
40519
40563
|
const stamped = await Promise.all(entries.map(async (rel) => {
|
|
40520
|
-
const full =
|
|
40564
|
+
const full = join21(dir2, rel);
|
|
40521
40565
|
try {
|
|
40522
40566
|
return { full, mtime: (await stat2(full)).mtimeMs };
|
|
40523
40567
|
} catch {
|
|
@@ -41188,7 +41232,7 @@ init_config2();
|
|
|
41188
41232
|
init_src2();
|
|
41189
41233
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
41190
41234
|
import { mkdir as mkdir5, writeFile as writeFile4, readFile as readFile4, unlink as unlink4, readdir as readdir5, stat as stat3 } from "node:fs/promises";
|
|
41191
|
-
import { join as
|
|
41235
|
+
import { join as join22, resolve as resolve19, basename as basename6 } from "node:path";
|
|
41192
41236
|
var MAX_TRANSCRIPT_BYTES = 1024 * 1024;
|
|
41193
41237
|
function transcriptDir() {
|
|
41194
41238
|
return resolve19(effectiveStr("HANOMAN_TRANSCRIPT_DIR")?.trim() || resolveDataDirs().transcripts);
|
|
@@ -41209,13 +41253,13 @@ async function saveTranscript(text) {
|
|
|
41209
41253
|
const dir2 = transcriptDir();
|
|
41210
41254
|
await mkdir5(dir2, { recursive: true, mode: 448 });
|
|
41211
41255
|
const key = `${randomUUID7()}.log`;
|
|
41212
|
-
await writeFile4(
|
|
41256
|
+
await writeFile4(join22(dir2, key), body, { encoding: "utf8", mode: 384 });
|
|
41213
41257
|
return { key, bytes: Buffer.byteLength(body, "utf8"), truncated };
|
|
41214
41258
|
}
|
|
41215
41259
|
async function readTranscript(key) {
|
|
41216
41260
|
if (!key) return null;
|
|
41217
41261
|
try {
|
|
41218
|
-
return await readFile4(
|
|
41262
|
+
return await readFile4(join22(transcriptDir(), basename6(key)), "utf8");
|
|
41219
41263
|
} catch {
|
|
41220
41264
|
return null;
|
|
41221
41265
|
}
|
|
@@ -41223,7 +41267,7 @@ async function readTranscript(key) {
|
|
|
41223
41267
|
async function deleteTranscript(key) {
|
|
41224
41268
|
if (!key) return;
|
|
41225
41269
|
try {
|
|
41226
|
-
await unlink4(
|
|
41270
|
+
await unlink4(join22(transcriptDir(), basename6(key)));
|
|
41227
41271
|
} catch (e) {
|
|
41228
41272
|
if (e.code !== "ENOENT") throw e;
|
|
41229
41273
|
}
|
|
@@ -41241,7 +41285,7 @@ async function listTranscripts() {
|
|
|
41241
41285
|
for (const name2 of names) {
|
|
41242
41286
|
if (!name2.endsWith(".log")) continue;
|
|
41243
41287
|
try {
|
|
41244
|
-
rows.push({ key: name2, mtimeMs: (await stat3(
|
|
41288
|
+
rows.push({ key: name2, mtimeMs: (await stat3(join22(dir2, name2))).mtimeMs });
|
|
41245
41289
|
} catch {
|
|
41246
41290
|
}
|
|
41247
41291
|
}
|
|
@@ -42701,9 +42745,9 @@ init_pty();
|
|
|
42701
42745
|
init_session_sandbox();
|
|
42702
42746
|
import { execFile as execFile12 } from "node:child_process";
|
|
42703
42747
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
42704
|
-
import { mkdirSync as
|
|
42748
|
+
import { mkdirSync as mkdirSync10, rmSync as rmSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
42705
42749
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
42706
|
-
import { join as
|
|
42750
|
+
import { join as join23 } from "node:path";
|
|
42707
42751
|
var binFor = (agent) => agent === "codex" ? effectiveStr("HANOMAN_CODEX_BIN") ?? "codex" : effectiveStr("HANOMAN_CLAUDE_BIN") ?? "claude";
|
|
42708
42752
|
function leadArgv(o) {
|
|
42709
42753
|
if (o.agent === "codex") {
|
|
@@ -42731,12 +42775,12 @@ function leadProcess(prompt, o, env = process.env) {
|
|
|
42731
42775
|
const mode = env.HANOMAN_SESSION_SANDBOX ?? (env.NODE_ENV === "production" ? "required" : "off");
|
|
42732
42776
|
if (mode === "off") return { file, args: directArgs, cwd: o.cwd, cleanup: () => {
|
|
42733
42777
|
} };
|
|
42734
|
-
const promptDir =
|
|
42735
|
-
|
|
42736
|
-
const promptFile =
|
|
42778
|
+
const promptDir = join23(tmpdir4(), "hanoman-prompts");
|
|
42779
|
+
mkdirSync10(promptDir, { recursive: true, mode: 448 });
|
|
42780
|
+
const promptFile = join23(promptDir, `oneshot-${randomUUID9()}`);
|
|
42737
42781
|
writeFileSync5(promptFile, prompt, { flag: "wx", mode: 384 });
|
|
42738
|
-
const workspace = o.cwd ??
|
|
42739
|
-
if (!o.cwd)
|
|
42782
|
+
const workspace = o.cwd ?? join23(tmpdir4(), `hanoman-oneshot-${randomUUID9()}`);
|
|
42783
|
+
if (!o.cwd) mkdirSync10(workspace, { recursive: false, mode: 448 });
|
|
42740
42784
|
try {
|
|
42741
42785
|
const argsWithoutPrompt = directArgs.slice(0, -1);
|
|
42742
42786
|
const command = [file, ...argsWithoutPrompt].map(shellQuote).join(" ") + ` "$(cat ${shellQuote(promptFile)})"`;
|
|
@@ -42753,13 +42797,13 @@ function leadProcess(prompt, o, env = process.env) {
|
|
|
42753
42797
|
args: sandbox.slice(1),
|
|
42754
42798
|
promptFile,
|
|
42755
42799
|
cleanup: () => {
|
|
42756
|
-
|
|
42757
|
-
if (!o.cwd)
|
|
42800
|
+
rmSync6(promptFile, { force: true });
|
|
42801
|
+
if (!o.cwd) rmSync6(workspace, { recursive: true, force: true });
|
|
42758
42802
|
}
|
|
42759
42803
|
};
|
|
42760
42804
|
} catch (error) {
|
|
42761
|
-
|
|
42762
|
-
if (!o.cwd)
|
|
42805
|
+
rmSync6(promptFile, { force: true });
|
|
42806
|
+
if (!o.cwd) rmSync6(workspace, { recursive: true, force: true });
|
|
42763
42807
|
throw error;
|
|
42764
42808
|
}
|
|
42765
42809
|
}
|
|
@@ -44261,9 +44305,9 @@ var US2 = "";
|
|
|
44261
44305
|
var RS = "";
|
|
44262
44306
|
var NO_REPO = "project ini belum ditautkan ke repo di mesin ini";
|
|
44263
44307
|
var NO_TAG = "repo project ini belum punya tag rilis";
|
|
44264
|
-
var
|
|
44308
|
+
var usable2 = (repoDir) => !!repoDir && existsSync15(repoDir);
|
|
44265
44309
|
async function listTags(repoDir) {
|
|
44266
|
-
if (!
|
|
44310
|
+
if (!usable2(repoDir)) return { tags: [], head: null, reason: NO_REPO };
|
|
44267
44311
|
try {
|
|
44268
44312
|
const { stdout } = await exec10("git", ["tag", "--list", "--sort=-creatordate"], { cwd: repoDir, ...GIT8 });
|
|
44269
44313
|
const tags = stdout.split("\n").map((s2) => s2.trim()).filter(Boolean);
|
|
@@ -44291,7 +44335,7 @@ async function logRange(repoDir, range) {
|
|
|
44291
44335
|
}).filter((x) => x !== null);
|
|
44292
44336
|
}
|
|
44293
44337
|
async function collectCommits(repoDir, fromSha, toSha) {
|
|
44294
|
-
if (!
|
|
44338
|
+
if (!usable2(repoDir)) return { ok: false, reason: NO_REPO };
|
|
44295
44339
|
for (const rev of [fromSha, toSha])
|
|
44296
44340
|
if (!await revExists(repoDir, rev)) return { ok: false, reason: `revisi "${rev}" tak dikenal di repo project` };
|
|
44297
44341
|
try {
|
|
@@ -44306,7 +44350,7 @@ async function collectCommits(repoDir, fromSha, toSha) {
|
|
|
44306
44350
|
async function collectVersions(repoDir, fromTag, toTag) {
|
|
44307
44351
|
const { tags, reason } = await listTags(repoDir);
|
|
44308
44352
|
if (reason) return { ok: false, reason };
|
|
44309
|
-
if (!
|
|
44353
|
+
if (!usable2(repoDir)) return { ok: false, reason: NO_REPO };
|
|
44310
44354
|
if (!tags.includes(toTag)) return { ok: false, reason: `tag "${toTag}" tak ada di repo project` };
|
|
44311
44355
|
if (fromTag && !tags.includes(fromTag)) return { ok: false, reason: `tag "${fromTag}" tak ada di repo project` };
|
|
44312
44356
|
const prev = fromTag ?? await previousTag(repoDir, toTag);
|
|
@@ -44524,7 +44568,7 @@ init_db();
|
|
|
44524
44568
|
init_src();
|
|
44525
44569
|
import { readFileSync as readFileSync13 } from "node:fs";
|
|
44526
44570
|
import { homedir as homedir9 } from "node:os";
|
|
44527
|
-
import { join as
|
|
44571
|
+
import { join as join24 } from "node:path";
|
|
44528
44572
|
var home = () => process.env.HOME || homedir9();
|
|
44529
44573
|
var readJson2 = (path2) => {
|
|
44530
44574
|
try {
|
|
@@ -44541,7 +44585,7 @@ var serversOf = (node) => {
|
|
|
44541
44585
|
var codexServers = () => {
|
|
44542
44586
|
let text;
|
|
44543
44587
|
try {
|
|
44544
|
-
text = readFileSync13(
|
|
44588
|
+
text = readFileSync13(join24(home(), ".codex", "config.toml"), "utf8");
|
|
44545
44589
|
} catch {
|
|
44546
44590
|
return [];
|
|
44547
44591
|
}
|
|
@@ -44554,12 +44598,12 @@ var codexServers = () => {
|
|
|
44554
44598
|
};
|
|
44555
44599
|
function mcpServerNames(repoDir) {
|
|
44556
44600
|
const names = [];
|
|
44557
|
-
const claudeJson = readJson2(
|
|
44601
|
+
const claudeJson = readJson2(join24(home(), ".claude.json"));
|
|
44558
44602
|
names.push(...serversOf(claudeJson));
|
|
44559
44603
|
if (repoDir) {
|
|
44560
44604
|
const projects = claudeJson?.projects;
|
|
44561
44605
|
if (projects && typeof projects === "object") names.push(...serversOf(projects[repoDir]));
|
|
44562
|
-
names.push(...serversOf(readJson2(
|
|
44606
|
+
names.push(...serversOf(readJson2(join24(repoDir, ".mcp.json"))));
|
|
44563
44607
|
}
|
|
44564
44608
|
names.push(...codexServers());
|
|
44565
44609
|
return [...new Set(names.filter(Boolean))].sort((a, b) => a.localeCompare(b));
|
|
@@ -46043,9 +46087,9 @@ ${baru}`;
|
|
|
46043
46087
|
// src/services/portal-chat/workspace.ts
|
|
46044
46088
|
init_src();
|
|
46045
46089
|
init_db();
|
|
46046
|
-
import { mkdirSync as
|
|
46090
|
+
import { mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync2, rmSync as rmSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
46047
46091
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
46048
|
-
import { join as
|
|
46092
|
+
import { join as join25 } from "node:path";
|
|
46049
46093
|
var STAGE_LABEL = {
|
|
46050
46094
|
brainstorming: "Dirumuskan",
|
|
46051
46095
|
objective: "Dirumuskan",
|
|
@@ -46100,7 +46144,7 @@ ${c.body}
|
|
|
46100
46144
|
${baris.join("\n")}`;
|
|
46101
46145
|
}
|
|
46102
46146
|
async function buildChatWorkspace(projectId) {
|
|
46103
|
-
const dir2 = mkdtempSync2(
|
|
46147
|
+
const dir2 = mkdtempSync2(join25(tmpdir5(), "hanoman-portal-chat-"));
|
|
46104
46148
|
try {
|
|
46105
46149
|
const project = await prisma.project.findUnique({
|
|
46106
46150
|
where: { id: projectId },
|
|
@@ -46121,7 +46165,7 @@ async function buildChatWorkspace(projectId) {
|
|
|
46121
46165
|
});
|
|
46122
46166
|
const files = [];
|
|
46123
46167
|
const tulis = (rel, isi) => {
|
|
46124
|
-
writeFileSync7(
|
|
46168
|
+
writeFileSync7(join25(dir2, rel), isi, { mode: 384 });
|
|
46125
46169
|
files.push(rel);
|
|
46126
46170
|
};
|
|
46127
46171
|
tulis("project.md", renderProjectDoc(project));
|
|
@@ -46130,16 +46174,16 @@ async function buildChatWorkspace(projectId) {
|
|
|
46130
46174
|
tulis("catatan-rilis.md", renderChangelogDoc(changelogs));
|
|
46131
46175
|
const prds = await listPrds(projectId);
|
|
46132
46176
|
if (prds.length) {
|
|
46133
|
-
|
|
46177
|
+
mkdirSync11(join25(dir2, "dokumen"), { mode: 448 });
|
|
46134
46178
|
for (const prd of prds) {
|
|
46135
46179
|
const isi = await readPrd(projectId, prd.path);
|
|
46136
46180
|
if (!isi) continue;
|
|
46137
|
-
tulis(
|
|
46181
|
+
tulis(join25("dokumen", `${prd.slug.replaceAll("/", "-")}.md`), isi);
|
|
46138
46182
|
}
|
|
46139
46183
|
}
|
|
46140
|
-
return { dir: dir2, files, cleanup: () =>
|
|
46184
|
+
return { dir: dir2, files, cleanup: () => rmSync7(dir2, { recursive: true, force: true }) };
|
|
46141
46185
|
} catch (error) {
|
|
46142
|
-
|
|
46186
|
+
rmSync7(dir2, { recursive: true, force: true });
|
|
46143
46187
|
throw error;
|
|
46144
46188
|
}
|
|
46145
46189
|
}
|
|
@@ -46646,13 +46690,13 @@ init_db();
|
|
|
46646
46690
|
// src/services/bootstrap.ts
|
|
46647
46691
|
import { createHash as createHash9, randomBytes as randomBytes10, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
|
|
46648
46692
|
import { chmod, lstat as lstat3, mkdir as mkdir6, readFile as readFile5, unlink as unlink5, writeFile as writeFile5 } from "node:fs/promises";
|
|
46649
|
-
import { join as
|
|
46693
|
+
import { join as join26 } from "node:path";
|
|
46650
46694
|
var TTL_MS5 = 15 * 6e4;
|
|
46651
46695
|
var SETUP_TOKEN_FILE = "setup.token";
|
|
46652
46696
|
var BootstrapError = class extends Error {
|
|
46653
46697
|
code = "BOOTSTRAP_PROOF";
|
|
46654
46698
|
};
|
|
46655
|
-
var tokenPath = (home3) =>
|
|
46699
|
+
var tokenPath = (home3) => join26(home3, SETUP_TOKEN_FILE);
|
|
46656
46700
|
async function readStored(home3) {
|
|
46657
46701
|
try {
|
|
46658
46702
|
const info = await lstat3(tokenPath(home3));
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@import"https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Serif:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;1,400&display=swap";:root{--ink-900: #17130c;--ink-800: #241d13;--ink-700: #3a3125;--ink-600: #574b3a;--ink-500: #6f6250;--ink-400: #90826c;--ink-300: #b3a794;--ink-200: #d6ccb9;--bone-000: #fffdf8;--bone-100: #faf6ec;--bone-200: #f2ebdc;--bone-300: #e8dfcc;--bone-400: #dccfb6;--brass-700: #7a5417;--brass-600: #97671f;--brass-500: #b8863b;--brass-400: #cf9d55;--brass-300: #e3c988;--brass-100: #f3e6c4;--brass-050: #faf2df;--wind-700: #2f5560;--wind-600: #3f6e7a;--wind-500: #517f8c;--wind-100: #dbe7ea;--wind-050: #eef4f5;--leaf-600: #4d6b30;--leaf-500: #5f8340;--leaf-100: #e6eed7;--amber-600: #b3771a;--amber-500: #cf8f28;--amber-100: #f7e9c9;--clay-600: #a23b2e;--clay-500: #bd4a3a;--clay-100: #f5dcd6;--term-bg: #1c1810;--term-fg: #e9e0cd;--term-dim: #8f8467;--term-line: #2c2618;--surface-page: var(--bone-100);--surface-panel: var(--bone-200);--surface-card: var(--bone-000);--surface-sunken: var(--bone-200);--surface-inverse: var(--ink-900);--surface-code: var(--term-bg);--text-strong: var(--ink-900);--text-body: var(--ink-700);--text-muted: var(--ink-500);--text-subtle: var(--ink-400);--text-on-brass: var(--ink-900);--text-on-dark: var(--term-fg);--text-link: var(--wind-600);--border-hair: var(--bone-300);--border-strong: var(--bone-400);--border-focus: var(--brass-500);--accent: var(--brass-500);--accent-hover: var(--brass-600);--accent-press: var(--brass-700);--accent-tint: var(--brass-100);--accent-on: var(--ink-900);--info: var(--wind-600);--info-tint: var(--wind-100);--status-ok: var(--leaf-600);--status-ok-tint: var(--leaf-100);--status-warn: var(--amber-600);--status-warn-tint: var(--amber-100);--status-err: var(--clay-600);--status-err-tint: var(--clay-100);--ring: 0 0 0 3px color-mix(in srgb, var(--brass-500) 45%, transparent)}:root{--font-serif: "IBM Plex Serif", Georgia, "Times New Roman", serif;--font-sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;--font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;--font-display: var(--font-serif);--font-body: var(--font-sans);--font-ui: var(--font-sans);--font-code: var(--font-mono);--text-2xs: 11px;--text-xs: 12px;--text-sm: 13px;--text-md: 14px;--text-base:16px;--text-lg: 18px;--text-xl: 20px;--text-2xl: 24px;--text-3xl: 30px;--text-4xl: 38px;--text-5xl: 48px;--text-6xl: 62px;--weight-regular: 400;--weight-medium: 500;--weight-semibold: 600;--weight-bold: 700;--leading-tight: 1.12;--leading-snug: 1.3;--leading-normal: 1.5;--leading-relaxed:1.65;--tracking-tight: -.02em;--tracking-normal: 0;--tracking-wide: .02em;--tracking-caps: .14em}:root{--space-0: 0;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-5: 20px;--space-6: 24px;--space-7: 32px;--space-8: 40px;--space-9: 48px;--space-10: 64px;--space-11: 80px;--space-12: 96px;--radius-xs: 3px;--radius-sm: 5px;--radius-md: 8px;--radius-lg: 12px;--radius-xl: 16px;--radius-pill: 999px;--border-thin: 1px;--border-med: 1.5px;--border-thick:2px;--content-max: 1200px;--sidebar-w: 248px;--topbar-h: 56px;--page-gutter-x: 28px;--page-gutter-y: 24px;--touch-target: 44px;--safe-top: env(safe-area-inset-top, 0px);--safe-right: env(safe-area-inset-right, 0px);--safe-bottom: env(safe-area-inset-bottom, 0px);--safe-left: env(safe-area-inset-left, 0px)}@media (min-width: 768px) and (max-width: 1199px){:root{--sidebar-w: 72px;--page-gutter-x: 20px;--page-gutter-y: 20px}}@media (max-width: 767px){:root{--sidebar-w: 0px;--page-gutter-x: 14px;--page-gutter-y: 14px}}:root{--shadow-xs: 0 1px 1px rgba(35, 27, 15, .05);--shadow-sm: 0 1px 2px rgba(35, 27, 15, .06), 0 1px 1px rgba(35, 27, 15, .04);--shadow-md: 0 2px 4px rgba(35, 27, 15, .07), 0 4px 12px rgba(35, 27, 15, .06);--shadow-lg: 0 8px 24px rgba(35, 27, 15, .1), 0 2px 6px rgba(35, 27, 15, .06);--shadow-xl: 0 20px 48px rgba(35, 27, 15, .16), 0 4px 12px rgba(35, 27, 15, .08);--shadow-inset: inset 0 1px 2px rgba(35, 27, 15, .08);--shadow-gild: 0 1px 0 rgba(255, 253, 248, .6) inset, 0 0 0 1px var(--brass-300);--elevation-flat: none;--elevation-raised: var(--shadow-sm);--elevation-float: var(--shadow-md);--elevation-overlay:var(--shadow-lg);--elevation-modal: var(--shadow-xl);--ease-out: cubic-bezier(.22, .61, .36, 1);--ease-inout: cubic-bezier(.65, 0, .35, 1);--dur-fast: .12s;--dur-base: .18s;--dur-slow: .28s;--dur-pet-active: 2.24s;--dur-pet-attention: 5.04s;--dur-pet-calm: 5.6s;--dur-pet-heavy: 6.72s;--dur-pet-flourish: .84s;--transition-base: all var(--dur-base) var(--ease-out);--transition-fast: all var(--dur-fast) var(--ease-out)}*,*:before,*:after{box-sizing:border-box}body{margin:0;background:var(--surface-page);color:var(--text-body);font-family:var(--font-body);font-size:var(--text-base);line-height:var(--leading-normal);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}h1,h2,h3,h4{font-family:var(--font-display);color:var(--text-strong);line-height:var(--leading-tight);letter-spacing:var(--tracking-tight);font-weight:var(--weight-semibold);margin:0 0 var(--space-3)}p{margin:0 0 var(--space-3)}a{color:var(--text-link);text-decoration:none;border-bottom:1px solid color-mix(in srgb,var(--text-link) 35%,transparent);transition:var(--transition-fast)}a:hover{color:var(--wind-700);border-bottom-color:var(--wind-700)}code,kbd,samp,pre{font-family:var(--font-code);font-size:.92em}.hn-eyebrow{font-family:var(--font-mono);font-size:var(--text-2xs);font-weight:var(--weight-medium);letter-spacing:var(--tracking-caps);text-transform:uppercase;color:var(--text-muted)}::selection{background:var(--brass-100);color:var(--ink-900)}html,body{margin:0;height:100%;background:var(--surface-page)}#root{height:100vh;height:100dvh;overflow:hidden;max-width:100%}.hn-dynamic-viewport{height:100vh;height:100dvh;min-height:100vh;min-height:100dvh}button:focus-visible,a[href]:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[role=button]:focus-visible,[role=tab]:focus-visible,[role=checkbox]:focus-visible,[role=radio]:focus-visible,[role=switch]:focus-visible{outline:2px solid var(--border-focus)!important;outline-offset:2px}.hn-select select:focus,.hn-select select:focus-visible{outline:none!important}.hn-shell{display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;background:var(--surface-page);color:var(--text-body)}.hn-shell-sidebar{width:var(--sidebar-w);flex:0 0 auto;display:flex;min-height:0;flex-direction:column;box-sizing:border-box;border-right:1px solid var(--border-hair);background:var(--bone-100);padding:18px 14px}.hn-shell-wordmark{padding:2px 4px 20px}.hn-shell-workspace{padding:0 10px 8px}.hn-shell-nav{display:flex;min-height:0;flex-direction:column;gap:2px;overflow-y:auto}.hn-shell-column{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column}.hn-shell-topbar{min-height:var(--topbar-h);flex:0 0 auto;display:flex;align-items:center;gap:16px;padding:0 22px;border-bottom:1px solid var(--border-hair);background:color-mix(in srgb,var(--bone-100) 80%,transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);position:relative;z-index:90}.hn-shell-menu{display:none;width:var(--touch-target);height:var(--touch-target);flex:0 0 auto;align-items:center;justify-content:center;border:1px solid var(--border-hair);border-radius:var(--radius-sm);background:var(--surface-card);color:var(--text-body)}.hn-shell-heading{min-width:0}.hn-shell-tools{margin-left:auto;display:flex;min-width:0;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:10px}.hn-shell-search{width:220px}.hn-shell-main{flex:1;min-width:0;min-height:0;overflow-x:hidden;overflow-y:auto}.hn-shell-content{width:100%;min-width:0;min-height:100%;margin:0 auto;padding:var(--page-gutter-y) var(--page-gutter-x) calc(32px + var(--safe-bottom));box-sizing:border-box;display:flex;flex-direction:column}.hn-shell-backdrop{display:none}.hn-viewport-popover{box-sizing:border-box;max-width:calc(100vw - var(--safe-left) - var(--safe-right) - 28px)}.hn-modal-overlay{box-sizing:border-box;padding:calc(24px + var(--safe-top)) calc(24px + var(--safe-right)) calc(24px + var(--safe-bottom)) calc(24px + var(--safe-left))}.hn-modal-panel{min-width:0}.hn-modal-footer{flex-wrap:wrap;padding-bottom:calc(14px + var(--safe-bottom))}.hn-board-local-overflow{max-width:100%;overscroll-behavior-inline:contain}.hn-row-actions{flex-wrap:wrap}.hn-topbar-label-short{display:none}.hn-grid-mobile,.hn-stack-mobile,.hn-wrap-mobile,.hn-dense-row,.hn-vps-row{min-width:0}@media (min-width: 768px) and (max-width: 1199px){.hn-shell-sidebar{width:var(--sidebar-w);padding:14px 8px}.hn-shell-sidebar .hn-nav-label,.hn-shell-sidebar .hn-shell-workspace,.hn-shell-sidebar .hn-shell-wordmark>div>div>span:last-child{display:none}.hn-shell-sidebar nav button{justify-content:center;padding-inline:0}.hn-shell-wordmark{display:flex;justify-content:center;padding-inline:0}}@media (max-width: 767px){.hn-shell-menu{display:inline-flex}.hn-shell-sidebar{position:fixed;z-index:120;inset:0 auto 0 0;width:min(320px,calc(100vw - 48px));padding:calc(14px + var(--safe-top)) 14px calc(14px + var(--safe-bottom)) calc(14px + var(--safe-left));box-shadow:var(--shadow-xl);transform:translate(-105%);transition:transform var(--transition-fast)}.hn-shell[data-nav-open=true] .hn-shell-sidebar{transform:translate(0)}.hn-shell-backdrop{display:block;position:fixed;z-index:119;top:0;right:0;bottom:0;left:0;width:100%;height:100%;border:0;background:color-mix(in srgb,var(--ink-900) 42%,transparent)}.hn-shell-topbar{align-items:flex-start;flex-wrap:wrap;gap:8px 10px;padding:calc(6px + var(--safe-top)) var(--page-gutter-x) 8px;-webkit-backdrop-filter:none;backdrop-filter:none}.hn-shell-heading{flex:1 1 calc(100% - 54px);align-self:center}.hn-shell-tools{flex:1 1 100%;margin-left:0;justify-content:flex-start;gap:6px}.hn-shell-search{flex:1 1 100%;width:100%}.hn-topbar-label{display:none}.hn-topbar-label-short{display:inline}.hn-shell button{min-width:var(--touch-target);min-height:var(--touch-target)}.hn-viewport-popover{position:fixed!important;inset:auto max(var(--page-gutter-x),var(--safe-right)) calc(var(--page-gutter-y) + var(--safe-bottom)) max(var(--page-gutter-x),var(--safe-left))!important;width:auto!important;max-width:none;max-height:calc(100dvh - var(--safe-top) - var(--safe-bottom) - var(--page-gutter-y) - var(--page-gutter-y))!important;overflow:auto}.hn-modal-overlay{align-items:flex-end!important;padding:var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left)}.hn-modal-panel{width:100%!important;max-width:100%!important;max-height:calc(100dvh - var(--safe-top) - var(--safe-bottom))!important;border-radius:var(--radius-lg) var(--radius-lg) 0 0!important}.hn-modal-header,.hn-modal-body,.hn-modal-footer{padding-inline:var(--page-gutter-x)!important}.hn-modal-footer>*{min-height:var(--touch-target)}.hn-stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))!important}.hn-project-header{display:none!important}.hn-project-row{grid-template-columns:minmax(0,1fr)!important;align-items:stretch!important;gap:10px!important;margin-bottom:10px;padding:14px!important;border:1px solid var(--border-hair);border-left-width:3px;border-radius:var(--radius-md)}.hn-project-row>[data-label]{min-width:0}.hn-project-row>[data-label]:before{content:attr(data-label);display:block;margin-bottom:4px;color:var(--text-subtle);font:var(--weight-semibold) var(--text-2xs)/1.2 var(--font-mono);letter-spacing:.08em;text-transform:uppercase}.hn-project-row>[data-label=Aktivitas]{white-space:normal!important}.hn-backlog-topline,.hn-backlog-view-actions,.hn-backlog-filters{align-items:stretch!important}.hn-backlog-topline>*,.hn-backlog-view-actions>*,.hn-backlog-filters>*{max-width:100%}.hn-backlog-view-actions{flex-wrap:wrap}.hn-backlog-filters .hn-touch-target{flex:1 1 145px!important;width:auto!important}.hn-backlog-grid{grid-template-columns:minmax(0,1fr)!important}.hn-backlog-row{align-items:flex-start!important;flex-wrap:wrap}.hn-backlog-row>div{flex-basis:100%!important}.hn-card-footer{align-items:flex-start!important;flex-direction:column}.hn-grid-mobile{grid-template-columns:minmax(0,1fr)!important}.hn-stack-mobile{align-items:stretch!important;flex-direction:column}.hn-wrap-mobile,.hn-dense-row,.hn-vps-row{align-items:flex-start!important;flex-wrap:wrap}.hn-vps-row>div{flex-basis:calc(100% - 32px)}.hn-vps-row>button{flex:1 1 auto}.hn-dense-row>[style*="flex: 1"]{min-width:min(220px,100%)}.hn-picker-row{flex-wrap:wrap}.hn-picker-row>.hn-picker-title{order:2;flex:1 1 100%!important;min-width:100%!important;white-space:normal!important;overflow:visible!important}.hn-card-header{align-items:stretch!important;flex-direction:column}.hn-card-actions{max-width:100%}.hn-card-actions>*{max-width:100%}.hn-settings-layout{width:100%}.hn-portal-header{height:auto!important;min-height:var(--topbar-h);flex-wrap:wrap;padding:max(8px,var(--safe-top)) max(var(--page-gutter-x),var(--safe-right)) 8px max(var(--page-gutter-x),var(--safe-left))!important}.hn-portal-header>div{flex-basis:1px}.hn-portal-content{box-sizing:border-box;padding:16px max(var(--page-gutter-x),var(--safe-right)) calc(24px + var(--safe-bottom)) max(var(--page-gutter-x),var(--safe-left))!important}.hn-portal-toolbar{align-items:stretch!important;flex-direction:column}.hn-portal-row{align-items:flex-start!important;flex-wrap:wrap;min-height:var(--touch-target)}.hn-portal-row>span:nth-child(2){flex-basis:calc(100% - 110px)}}.hn-responsive-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:10px;min-width:0;max-width:100%}@media (max-width: 767px){.hn-setting-row{align-items:stretch!important;flex-direction:column}.hn-setting-control{width:100%}.hn-setting-control>.hn-touch-target,.hn-setting-control>div{width:100%!important;max-width:100%}.hn-setting-control>div{flex-wrap:wrap}.hn-setting-control>div>div.hn-touch-target{flex:1 1 200px;width:auto!important;max-width:100%}}.hn-local-overflow{max-width:100%;min-width:0;overflow:auto;overscroll-behavior-inline:contain;-webkit-overflow-scrolling:touch}.hn-tabs{max-width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-inline:contain}@media (pointer: coarse),(max-width: 767px){button:not(.hn-shell-backdrop){min-width:var(--touch-target);min-height:var(--touch-target)}input,select,textarea{min-width:var(--touch-target);min-height:var(--touch-target)}.hn-touch-target,.hn-project-open,.hn-terminal-unplaced-action,[role=button][tabindex="0"]{min-width:var(--touch-target)!important;min-height:var(--touch-target)!important}.hn-tabs [role=tab]{min-height:var(--touch-target)}.hn-choice-target{min-width:var(--touch-target);min-height:var(--touch-target)}.hn-choice-control{min-width:var(--touch-target);min-height:var(--touch-target);outline-offset:8px}}.hn-responsive-panels{display:flex;flex:1 1 auto;min-width:0;min-height:0;flex-direction:column;gap:12px}.hn-panel-switcher{flex:0 0 auto;max-width:100%;overflow-x:auto;overscroll-behavior-inline:contain}.hn-panels-grid{display:grid;grid-template-columns:minmax(0,1fr);flex:1 1 auto;min-width:0;min-height:0;gap:16px}.hn-responsive-panel{min-width:0;min-height:0}.hn-panel-flex{display:flex;min-width:0;min-height:0;flex-direction:column}.hn-panel-flex>*{min-width:0}.hn-graph-action{display:inline-grid;min-width:28px;min-height:28px;place-items:center;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--text-muted);cursor:pointer}.hn-graph-action:hover{background:var(--bone-200)}.hn-terminal-actions{display:inline-flex;flex:0 0 auto;align-items:center;gap:2px}.hn-terminal-action{display:inline-grid;min-width:28px;min-height:28px;padding:0;place-items:center;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--text-subtle);font:inherit;cursor:pointer}.hn-terminal-action--text{padding-inline:5px}.hn-terminal-action:hover{background:var(--bone-300);color:var(--text-strong)}.hn-terminal-keys{display:flex;flex:0 0 auto;gap:4px;max-width:100%;padding:4px 2px;overflow-x:auto;overscroll-behavior-inline:contain;border-top:1px solid var(--border-hair)}.hn-terminal-key{flex:0 0 auto;min-width:40px;min-height:32px;padding:0 8px;border:1px solid var(--border-hair);border-radius:var(--radius-sm);background:var(--surface-card);color:var(--text-body);font:var(--weight-medium) var(--text-sm)/1 var(--font-mono);cursor:pointer}.hn-terminal-key:hover{background:var(--bone-200);color:var(--text-strong)}@media (max-width: 767px){.hn-terminal-cell-header{flex-wrap:wrap}}@media (pointer: coarse),(max-width: 767px){.hn-graph-action,.hn-terminal-action,.hn-terminal-key,.hn-terminal-group-control{min-width:var(--touch-target);min-height:var(--touch-target)}}.hn-responsive-panel[aria-hidden=true]{display:none}@media (min-width: 768px){.hn-responsive-panels--tablet .hn-panel-switcher{display:none}.hn-responsive-panels--tablet .hn-panels-grid{grid-template-columns:minmax(0,var(--hn-master-width, 280px)) minmax(0,1fr)}.hn-responsive-panels--tablet .hn-responsive-panel[aria-hidden=true]{display:block}}@media (min-width: 1200px){.hn-responsive-panels--desktop .hn-panel-switcher{display:none}.hn-responsive-panels--desktop .hn-panels-grid{grid-template-columns:minmax(0,var(--hn-master-width, 300px)) minmax(0,1fr)}.hn-responsive-panels--desktop .hn-responsive-panel[aria-hidden=true]{display:block}}@media (prefers-reduced-motion: reduce){*,*:before,*:after{animation:none!important;scroll-behavior:auto!important;transition:none!important}}button{--accent-on: #fff}a{color:var(--text-link);text-decoration:none}a:hover{color:var(--wind-700);text-decoration:underline}.hn-md{color:var(--text-body);font-family:var(--font-sans);font-size:15px;line-height:1.72;overflow-wrap:anywhere}.hn-md>:first-child{margin-top:8px}.hn-md h1,.hn-md h2,.hn-md h3,.hn-md h4{font-family:var(--font-display);font-weight:600;letter-spacing:-.02em;color:var(--ink-900);line-height:1.2;margin:1.6em 0 .5em}.hn-md h1{font-size:30px;margin-top:.4em;padding-bottom:.34em;border-bottom:1px solid var(--border-hair)}.hn-md h2{font-size:22px}.hn-md h3{font-size:18px}.hn-md h4{font-size:15px}.hn-md p{margin:.7em 0}.hn-md ul,.hn-md ol{margin:.6em 0;padding-left:1.5em}.hn-md li{margin:.28em 0}.hn-md li::marker{color:var(--brass-500)}.hn-md ul.contains-task-list,.hn-md li.task-list-item{list-style:none}.hn-md li.task-list-item{padding-left:0}.hn-md input[type=checkbox]{accent-color:var(--brass-500);margin-right:8px;transform:translateY(1px)}.hn-md strong{font-weight:600;color:var(--ink-900)}.hn-md em{color:var(--text-muted)}.hn-md a{color:var(--text-link)}.hn-md hr{border:none;border-top:1px solid var(--border-hair);margin:1.6em 0}.hn-md code{font-family:var(--font-mono);font-size:.86em;background:var(--bone-200);color:var(--ink-800);padding:1.5px 5px;border-radius:var(--radius-xs);border:1px solid var(--border-hair)}.hn-md pre{background:var(--surface-code);border:1px solid var(--term-line);border-radius:var(--radius-lg);padding:14px 16px;overflow:auto;margin:1em 0;white-space:pre-wrap;overflow-wrap:anywhere}.hn-md pre code{background:transparent;border:none;padding:0;color:var(--term-fg);font-size:12.5px;line-height:1.7}.hn-md blockquote{margin:1em 0;padding:4px 16px;border-left:3px solid var(--brass-500);background:var(--brass-050);color:var(--text-body);border-radius:0 var(--radius-sm) var(--radius-sm) 0}.hn-md blockquote p{margin:.4em 0}.hn-md table{border-collapse:collapse;width:100%;margin:1em 0;font-size:14px;table-layout:fixed}.hn-md th,.hn-md td{overflow-wrap:anywhere}.hn-md th{font-family:var(--font-mono);font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);text-align:left;padding:8px 12px;background:var(--bone-100);border:1px solid var(--border-hair)}.hn-md td{padding:8px 12px;border:1px solid var(--border-hair);color:var(--text-body)}.hn-md td code{font-size:.82em}.hn-md img{max-width:100%;border-radius:var(--radius-sm)}@keyframes hn-fade-in{0%{opacity:0}to{opacity:1}}@keyframes hn-modal-in{0%{opacity:0;transform:translateY(8px) scale(.99)}to{opacity:1;transform:none}}@keyframes hn-toast-in{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}.hn-pet-reactor{transform-origin:50% 86%}.hn-pet-stage:not([data-reduced-motion=true]):hover .hn-pet-reactor{transform:translateY(-2px) scale(1.035) rotate(-1deg)}@keyframes hn-pet-idle-ready{0%,to{transform:translateY(0) scale(1)}50%{transform:translateY(-2px) scale(1.018)}}@keyframes hn-pet-idle-working{0%,to{transform:translateY(0) rotate(0) scale(1)}20%{transform:translateY(-2px) rotate(-.8deg) scale(1.018)}40%{transform:translateY(0) rotate(.6deg) scale(1)}60%{transform:translateY(-3px) rotate(-.5deg) scale(1.022)}80%{transform:translateY(-1px) rotate(.4deg) scale(1.008)}}@keyframes hn-pet-idle-waiting{0%,64%,to{transform:translateY(0) rotate(0)}70%{transform:translateY(-1px) rotate(-2deg)}76%{transform:translateY(-2px) rotate(3deg)}82%{transform:translateY(-1px) rotate(-2deg)}88%{transform:translateY(0) rotate(0)}}@keyframes hn-pet-idle-blocked{0%,to{transform:translateY(1px) scaleY(.99)}50%{transform:translateY(3px) scale(.99,.97)}}@keyframes hn-pet-idle-review{0%,64%,to{transform:translateY(0) rotate(0) scale(1)}74%{transform:translateY(-1px) rotate(-1.6deg) scale(1.012)}84%{transform:translateY(-1px) rotate(.8deg) scale(1.006)}}@keyframes hn-pet-idle-shipped{0%,to{transform:translateY(0) scale(1)}50%{transform:translateY(-2px) scale(1.015)}}@keyframes hn-pet-idle-docs{0%,66%,to{transform:translateY(0) rotate(0) scale(1)}72%{transform:translateY(-1px) rotate(-1.8deg) scale(1.01)}78%{transform:translateY(-1px) rotate(1.5deg) scale(1.012)}84%{transform:translateY(0) rotate(-.7deg) scale(1)}}@keyframes hn-pet-celebrate{0%{transform:translateY(3px) scale(.92) rotate(0)}38%{transform:translateY(-5px) scale(1.08) rotate(-3deg)}62%{transform:translateY(-2px) scale(1.03) rotate(3deg)}to{transform:translateY(0) scale(1) rotate(0)}}@keyframes hn-pet-pose-in{0%{opacity:0;transform:translateY(4px) scale(.76,.92)}62%{opacity:1;transform:translateY(-2px) scale(1.07,.97)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes hn-pet-pose-out{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(3px) scale(.86,1.04)}}@keyframes hn-pet-click{0%,to{transform:translateY(0) scale(1) rotate(0)}38%{transform:translateY(2px) scale(.9,1.06) rotate(-2deg)}72%{transform:translateY(-3px) scale(1.06,.96) rotate(1.5deg)}}@keyframes hn-pet-panel-in{0%{opacity:0;transform:translateY(6px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes hn-pet-panel-out{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(5px) scale(.985)}}@keyframes hn-pet-reveal{0%{opacity:0;transform:translateY(7px) scale(.86)}70%{opacity:1;transform:translateY(-1px) scale(1.035)}to{opacity:1;transform:translateY(0) scale(1)}}/**
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Serif:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;1,400&display=swap";:root{--ink-900: #17130c;--ink-800: #241d13;--ink-700: #3a3125;--ink-600: #574b3a;--ink-500: #6f6250;--ink-400: #90826c;--ink-300: #b3a794;--ink-200: #d6ccb9;--bone-000: #fffdf8;--bone-100: #faf6ec;--bone-200: #f2ebdc;--bone-300: #e8dfcc;--bone-400: #dccfb6;--brass-700: #7a5417;--brass-600: #97671f;--brass-500: #b8863b;--brass-400: #cf9d55;--brass-300: #e3c988;--brass-100: #f3e6c4;--brass-050: #faf2df;--wind-700: #2f5560;--wind-600: #3f6e7a;--wind-500: #517f8c;--wind-100: #dbe7ea;--wind-050: #eef4f5;--leaf-600: #4d6b30;--leaf-500: #5f8340;--leaf-100: #e6eed7;--amber-600: #b3771a;--amber-500: #cf8f28;--amber-100: #f7e9c9;--clay-600: #a23b2e;--clay-500: #bd4a3a;--clay-100: #f5dcd6;--term-bg: #1c1810;--term-fg: #e9e0cd;--term-dim: #8f8467;--term-line: #2c2618;--surface-page: var(--bone-100);--surface-panel: var(--bone-200);--surface-card: var(--bone-000);--surface-sunken: var(--bone-200);--surface-inverse: var(--ink-900);--surface-code: var(--term-bg);--text-strong: var(--ink-900);--text-body: var(--ink-700);--text-muted: var(--ink-500);--text-subtle: var(--ink-400);--text-on-brass: var(--ink-900);--text-on-dark: var(--term-fg);--text-link: var(--wind-600);--border-hair: var(--bone-300);--border-strong: var(--bone-400);--border-focus: var(--brass-500);--accent: var(--brass-500);--accent-hover: var(--brass-600);--accent-press: var(--brass-700);--accent-tint: var(--brass-100);--accent-on: var(--ink-900);--info: var(--wind-600);--info-tint: var(--wind-100);--status-ok: var(--leaf-600);--status-ok-tint: var(--leaf-100);--status-warn: var(--amber-600);--status-warn-tint: var(--amber-100);--status-err: var(--clay-600);--status-err-tint: var(--clay-100);--ring: 0 0 0 3px color-mix(in srgb, var(--brass-500) 45%, transparent)}:root{--font-serif: "IBM Plex Serif", Georgia, "Times New Roman", serif;--font-sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;--font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;--font-display: var(--font-serif);--font-body: var(--font-sans);--font-ui: var(--font-sans);--font-code: var(--font-mono);--text-2xs: 11px;--text-xs: 12px;--text-sm: 13px;--text-md: 14px;--text-base:16px;--text-lg: 18px;--text-xl: 20px;--text-2xl: 24px;--text-3xl: 30px;--text-4xl: 38px;--text-5xl: 48px;--text-6xl: 62px;--weight-regular: 400;--weight-medium: 500;--weight-semibold: 600;--weight-bold: 700;--leading-tight: 1.12;--leading-snug: 1.3;--leading-normal: 1.5;--leading-relaxed:1.65;--tracking-tight: -.02em;--tracking-normal: 0;--tracking-wide: .02em;--tracking-caps: .14em}:root{--space-0: 0;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-5: 20px;--space-6: 24px;--space-7: 32px;--space-8: 40px;--space-9: 48px;--space-10: 64px;--space-11: 80px;--space-12: 96px;--radius-xs: 3px;--radius-sm: 5px;--radius-md: 8px;--radius-lg: 12px;--radius-xl: 16px;--radius-pill: 999px;--border-thin: 1px;--border-med: 1.5px;--border-thick:2px;--content-max: 1200px;--sidebar-w: 248px;--topbar-h: 56px;--page-gutter-x: 28px;--page-gutter-y: 24px;--touch-target: 44px;--safe-top: env(safe-area-inset-top, 0px);--safe-right: env(safe-area-inset-right, 0px);--safe-bottom: env(safe-area-inset-bottom, 0px);--safe-left: env(safe-area-inset-left, 0px)}@media (min-width: 768px) and (max-width: 1199px){:root{--sidebar-w: 72px;--page-gutter-x: 20px;--page-gutter-y: 20px}}@media (max-width: 767px){:root{--sidebar-w: 0px;--page-gutter-x: 14px;--page-gutter-y: 14px}}:root{--shadow-xs: 0 1px 1px rgba(35, 27, 15, .05);--shadow-sm: 0 1px 2px rgba(35, 27, 15, .06), 0 1px 1px rgba(35, 27, 15, .04);--shadow-md: 0 2px 4px rgba(35, 27, 15, .07), 0 4px 12px rgba(35, 27, 15, .06);--shadow-lg: 0 8px 24px rgba(35, 27, 15, .1), 0 2px 6px rgba(35, 27, 15, .06);--shadow-xl: 0 20px 48px rgba(35, 27, 15, .16), 0 4px 12px rgba(35, 27, 15, .08);--shadow-inset: inset 0 1px 2px rgba(35, 27, 15, .08);--shadow-gild: 0 1px 0 rgba(255, 253, 248, .6) inset, 0 0 0 1px var(--brass-300);--elevation-flat: none;--elevation-raised: var(--shadow-sm);--elevation-float: var(--shadow-md);--elevation-overlay:var(--shadow-lg);--elevation-modal: var(--shadow-xl);--ease-out: cubic-bezier(.22, .61, .36, 1);--ease-inout: cubic-bezier(.65, 0, .35, 1);--dur-fast: .12s;--dur-base: .18s;--dur-slow: .28s;--dur-pet-active: 2.24s;--dur-pet-attention: 5.04s;--dur-pet-calm: 5.6s;--dur-pet-heavy: 6.72s;--dur-pet-flourish: .84s;--transition-base: all var(--dur-base) var(--ease-out);--transition-fast: all var(--dur-fast) var(--ease-out)}*,*:before,*:after{box-sizing:border-box}body{margin:0;background:var(--surface-page);color:var(--text-body);font-family:var(--font-body);font-size:var(--text-base);line-height:var(--leading-normal);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}h1,h2,h3,h4{font-family:var(--font-display);color:var(--text-strong);line-height:var(--leading-tight);letter-spacing:var(--tracking-tight);font-weight:var(--weight-semibold);margin:0 0 var(--space-3)}p{margin:0 0 var(--space-3)}a{color:var(--text-link);text-decoration:none;border-bottom:1px solid color-mix(in srgb,var(--text-link) 35%,transparent);transition:var(--transition-fast)}a:hover{color:var(--wind-700);border-bottom-color:var(--wind-700)}code,kbd,samp,pre{font-family:var(--font-code);font-size:.92em}.hn-eyebrow{font-family:var(--font-mono);font-size:var(--text-2xs);font-weight:var(--weight-medium);letter-spacing:var(--tracking-caps);text-transform:uppercase;color:var(--text-muted)}::selection{background:var(--brass-100);color:var(--ink-900)}html,body{margin:0;height:100%;background:var(--surface-page)}#root{height:100vh;height:100dvh;overflow:hidden;max-width:100%}.hn-dynamic-viewport{height:100vh;height:100dvh;min-height:100vh;min-height:100dvh}button:focus-visible,a[href]:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[role=button]:focus-visible,[role=tab]:focus-visible,[role=checkbox]:focus-visible,[role=radio]:focus-visible,[role=switch]:focus-visible{outline:2px solid var(--border-focus)!important;outline-offset:2px}.hn-select select:focus,.hn-select select:focus-visible{outline:none!important}.hn-shell{display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;background:var(--surface-page);color:var(--text-body)}.hn-shell-sidebar{width:var(--sidebar-w);flex:0 0 auto;display:flex;min-height:0;flex-direction:column;box-sizing:border-box;border-right:1px solid var(--border-hair);background:var(--bone-100);padding:18px 14px}.hn-shell-wordmark{padding:2px 4px 20px}.hn-shell-workspace{padding:0 10px 8px}.hn-shell-nav{display:flex;min-height:0;flex-direction:column;gap:2px;overflow-y:auto}.hn-shell-column{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column}.hn-shell-topbar{min-height:var(--topbar-h);flex:0 0 auto;display:flex;align-items:center;gap:16px;padding:0 22px;border-bottom:1px solid var(--border-hair);background:color-mix(in srgb,var(--bone-100) 80%,transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);position:relative;z-index:90}.hn-shell-menu{display:none;width:var(--touch-target);height:var(--touch-target);flex:0 0 auto;align-items:center;justify-content:center;border:1px solid var(--border-hair);border-radius:var(--radius-sm);background:var(--surface-card);color:var(--text-body)}.hn-shell-heading{min-width:0}.hn-shell-tools{margin-left:auto;display:flex;min-width:0;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:10px}.hn-shell-search{width:220px}.hn-shell-main{flex:1;min-width:0;min-height:0;overflow-x:hidden;overflow-y:auto}.hn-shell-content{width:100%;min-width:0;min-height:100%;margin:0 auto;padding:var(--page-gutter-y) var(--page-gutter-x) calc(32px + var(--safe-bottom));box-sizing:border-box;display:flex;flex-direction:column}.hn-shell-backdrop{display:none}.hn-viewport-popover{box-sizing:border-box;max-width:calc(100vw - var(--safe-left) - var(--safe-right) - 28px)}.hn-modal-overlay{box-sizing:border-box;padding:calc(24px + var(--safe-top)) calc(24px + var(--safe-right)) calc(24px + var(--safe-bottom)) calc(24px + var(--safe-left))}.hn-modal-panel{min-width:0}.hn-modal-footer{flex-wrap:wrap;padding-bottom:calc(14px + var(--safe-bottom))}.hn-board-local-overflow{max-width:100%;overscroll-behavior-inline:contain}.hn-row-actions{flex-wrap:wrap}.hn-topbar-label-short{display:none}.hn-grid-mobile,.hn-stack-mobile,.hn-wrap-mobile,.hn-dense-row,.hn-vps-row{min-width:0}@media (min-width: 768px) and (max-width: 1199px){.hn-shell-sidebar{width:var(--sidebar-w);padding:14px 8px}.hn-shell-sidebar .hn-nav-label,.hn-shell-sidebar .hn-shell-workspace,.hn-shell-sidebar .hn-shell-wordmark>div>div>span:last-child{display:none}.hn-shell-sidebar nav button{justify-content:center;padding-inline:0}.hn-shell-wordmark{display:flex;justify-content:center;padding-inline:0}}@media (max-width: 767px){.hn-shell-menu{display:inline-flex}.hn-shell-sidebar{position:fixed;z-index:120;inset:0 auto 0 0;width:min(320px,calc(100vw - 48px));padding:calc(14px + var(--safe-top)) 14px calc(14px + var(--safe-bottom)) calc(14px + var(--safe-left));box-shadow:var(--shadow-xl);transform:translate(-105%);transition:transform var(--transition-fast)}.hn-shell[data-nav-open=true] .hn-shell-sidebar{transform:translate(0)}.hn-shell-backdrop{display:block;position:fixed;z-index:119;top:0;right:0;bottom:0;left:0;width:100%;height:100%;border:0;background:color-mix(in srgb,var(--ink-900) 42%,transparent)}.hn-shell-topbar{align-items:flex-start;flex-wrap:wrap;gap:8px 10px;padding:calc(6px + var(--safe-top)) var(--page-gutter-x) 8px;-webkit-backdrop-filter:none;backdrop-filter:none}.hn-shell-heading{flex:1 1 calc(100% - 54px);align-self:center}.hn-shell-tools{flex:1 1 100%;margin-left:0;justify-content:flex-start;gap:6px}.hn-shell-search{flex:1 1 100%;width:100%}.hn-topbar-label{display:none}.hn-topbar-label-short{display:inline}.hn-shell button{min-width:var(--touch-target);min-height:var(--touch-target)}.hn-viewport-popover{position:fixed!important;inset:auto max(var(--page-gutter-x),var(--safe-right)) calc(var(--page-gutter-y) + var(--safe-bottom)) max(var(--page-gutter-x),var(--safe-left))!important;width:auto!important;max-width:none;max-height:calc(100dvh - var(--safe-top) - var(--safe-bottom) - var(--page-gutter-y) - var(--page-gutter-y))!important;overflow:auto}.hn-modal-overlay{align-items:flex-end!important;padding:var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left)}.hn-modal-panel{width:100%!important;max-width:100%!important;max-height:calc(100dvh - var(--safe-top) - var(--safe-bottom))!important;border-radius:var(--radius-lg) var(--radius-lg) 0 0!important}.hn-modal-header,.hn-modal-body,.hn-modal-footer{padding-inline:var(--page-gutter-x)!important}.hn-modal-footer>*{min-height:var(--touch-target)}.hn-stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))!important}.hn-project-header{display:none!important}.hn-project-row{grid-template-columns:minmax(0,1fr)!important;align-items:stretch!important;gap:10px!important;margin-bottom:10px;padding:14px!important;border:1px solid var(--border-hair);border-left-width:3px;border-radius:var(--radius-md)}.hn-project-row>[data-label]{min-width:0}.hn-project-row>[data-label]:before{content:attr(data-label);display:block;margin-bottom:4px;color:var(--text-subtle);font:var(--weight-semibold) var(--text-2xs)/1.2 var(--font-mono);letter-spacing:.08em;text-transform:uppercase}.hn-project-row>[data-label=Aktivitas]{white-space:normal!important}.hn-backlog-topline,.hn-backlog-view-actions,.hn-backlog-filters{align-items:stretch!important}.hn-backlog-topline>*,.hn-backlog-view-actions>*,.hn-backlog-filters>*{max-width:100%}.hn-backlog-view-actions{flex-wrap:wrap}.hn-backlog-filters .hn-touch-target{flex:1 1 145px!important;width:auto!important}.hn-backlog-grid{grid-template-columns:minmax(0,1fr)!important}.hn-backlog-row{align-items:flex-start!important;flex-wrap:wrap}.hn-backlog-row>div{flex-basis:100%!important}.hn-card-footer{align-items:flex-start!important;flex-direction:column}.hn-grid-mobile{grid-template-columns:minmax(0,1fr)!important}.hn-stack-mobile{align-items:stretch!important;flex-direction:column}.hn-wrap-mobile,.hn-dense-row,.hn-vps-row{align-items:flex-start!important;flex-wrap:wrap}.hn-vps-row>div{flex-basis:calc(100% - 32px)}.hn-vps-row>button{flex:1 1 auto}.hn-dense-row>[style*="flex: 1"]{min-width:min(220px,100%)}.hn-picker-row{flex-wrap:wrap}.hn-picker-row>.hn-picker-title{order:2;flex:1 1 100%!important;min-width:100%!important;white-space:normal!important;overflow:visible!important}.hn-card-header{align-items:stretch!important;flex-direction:column}.hn-card-actions{max-width:100%}.hn-card-actions>*{max-width:100%}.hn-settings-layout{width:100%}.hn-portal-header{height:auto!important;min-height:var(--topbar-h);flex-wrap:wrap;padding:max(8px,var(--safe-top)) max(var(--page-gutter-x),var(--safe-right)) 8px max(var(--page-gutter-x),var(--safe-left))!important}.hn-portal-header>div{flex-basis:1px}.hn-portal-content{box-sizing:border-box;padding:16px max(var(--page-gutter-x),var(--safe-right)) calc(24px + var(--safe-bottom)) max(var(--page-gutter-x),var(--safe-left))!important}.hn-portal-toolbar{align-items:stretch!important;flex-direction:column}.hn-portal-row{align-items:flex-start!important;flex-wrap:wrap;min-height:var(--touch-target)}.hn-portal-row>span:nth-child(2){flex-basis:calc(100% - 110px)}}.hn-responsive-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:10px;min-width:0;max-width:100%}@media (max-width: 767px){.hn-setting-row{align-items:stretch!important;flex-direction:column}.hn-setting-control{width:100%}.hn-setting-control>.hn-touch-target,.hn-setting-control>div{width:100%!important;max-width:100%}.hn-setting-control>div{flex-wrap:wrap}.hn-setting-control>div>div.hn-touch-target{flex:1 1 200px;width:auto!important;max-width:100%}}.hn-local-overflow{max-width:100%;min-width:0;overflow:auto;overscroll-behavior-inline:contain;-webkit-overflow-scrolling:touch}.hn-tabs{max-width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-inline:contain}.hn-ide-head{display:flex;align-items:center;flex-wrap:wrap;gap:12px;min-width:0}.hn-ide-head>.hn-tabs{flex:0 0 auto}.hn-ide-toolbar{display:flex;align-items:center;flex:1 1 480px;flex-wrap:nowrap;gap:10px;min-width:0;max-width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-inline:contain}.hn-ide-toolbar>*{flex:0 0 auto}.hn-ide-toolbar>:first-child{margin-inline-start:auto}@media (pointer: coarse),(max-width: 767px){button:not(.hn-shell-backdrop){min-width:var(--touch-target);min-height:var(--touch-target)}input,select,textarea{min-width:var(--touch-target);min-height:var(--touch-target)}.hn-touch-target,.hn-project-open,.hn-terminal-unplaced-action,[role=button][tabindex="0"]{min-width:var(--touch-target)!important;min-height:var(--touch-target)!important}.hn-tabs [role=tab]{min-height:var(--touch-target)}.hn-choice-target{min-width:var(--touch-target);min-height:var(--touch-target)}.hn-choice-control{min-width:var(--touch-target);min-height:var(--touch-target);outline-offset:8px}}.hn-responsive-panels{display:flex;flex:1 1 auto;min-width:0;min-height:0;flex-direction:column;gap:12px}.hn-panel-switcher{flex:0 0 auto;max-width:100%;overflow-x:auto;overscroll-behavior-inline:contain}.hn-panels-grid{display:grid;grid-template-columns:minmax(0,1fr);flex:1 1 auto;min-width:0;min-height:0;gap:16px}.hn-responsive-panel{min-width:0;min-height:0}.hn-panel-flex{display:flex;min-width:0;min-height:0;flex-direction:column}.hn-panel-flex>*{min-width:0}.hn-graph-action{display:inline-grid;min-width:28px;min-height:28px;place-items:center;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--text-muted);cursor:pointer}.hn-graph-action:hover{background:var(--bone-200)}.hn-terminal-actions{display:inline-flex;flex:0 0 auto;align-items:center;gap:2px}.hn-terminal-action{display:inline-grid;min-width:28px;min-height:28px;padding:0;place-items:center;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--text-subtle);font:inherit;cursor:pointer}.hn-terminal-action--text{padding-inline:5px}.hn-terminal-action:hover{background:var(--bone-300);color:var(--text-strong)}.hn-terminal-keys{display:flex;flex:0 0 auto;gap:4px;max-width:100%;padding:4px 2px;overflow-x:auto;overscroll-behavior-inline:contain;border-top:1px solid var(--border-hair)}.hn-terminal-key{flex:0 0 auto;min-width:40px;min-height:32px;padding:0 8px;border:1px solid var(--border-hair);border-radius:var(--radius-sm);background:var(--surface-card);color:var(--text-body);font:var(--weight-medium) var(--text-sm)/1 var(--font-mono);cursor:pointer}.hn-terminal-key:hover{background:var(--bone-200);color:var(--text-strong)}@media (max-width: 767px){.hn-terminal-cell-header{flex-wrap:wrap}}@media (pointer: coarse),(max-width: 767px){.hn-graph-action,.hn-terminal-action,.hn-terminal-key,.hn-terminal-group-control{min-width:var(--touch-target);min-height:var(--touch-target)}}.hn-responsive-panel[aria-hidden=true]{display:none}@media (min-width: 768px){.hn-responsive-panels--tablet .hn-panel-switcher{display:none}.hn-responsive-panels--tablet .hn-panels-grid{grid-template-columns:minmax(0,var(--hn-master-width, 280px)) minmax(0,1fr)}.hn-responsive-panels--tablet .hn-responsive-panel[aria-hidden=true]{display:block}}@media (min-width: 1200px){.hn-responsive-panels--desktop .hn-panel-switcher{display:none}.hn-responsive-panels--desktop .hn-panels-grid{grid-template-columns:minmax(0,var(--hn-master-width, 300px)) minmax(0,1fr)}.hn-responsive-panels--desktop .hn-responsive-panel[aria-hidden=true]{display:block}}@media (prefers-reduced-motion: reduce){*,*:before,*:after{animation:none!important;scroll-behavior:auto!important;transition:none!important}}button{--accent-on: #fff}a{color:var(--text-link);text-decoration:none}a:hover{color:var(--wind-700);text-decoration:underline}.hn-md{color:var(--text-body);font-family:var(--font-sans);font-size:15px;line-height:1.72;overflow-wrap:anywhere}.hn-md>:first-child{margin-top:8px}.hn-md h1,.hn-md h2,.hn-md h3,.hn-md h4{font-family:var(--font-display);font-weight:600;letter-spacing:-.02em;color:var(--ink-900);line-height:1.2;margin:1.6em 0 .5em}.hn-md h1{font-size:30px;margin-top:.4em;padding-bottom:.34em;border-bottom:1px solid var(--border-hair)}.hn-md h2{font-size:22px}.hn-md h3{font-size:18px}.hn-md h4{font-size:15px}.hn-md p{margin:.7em 0}.hn-md ul,.hn-md ol{margin:.6em 0;padding-left:1.5em}.hn-md li{margin:.28em 0}.hn-md li::marker{color:var(--brass-500)}.hn-md ul.contains-task-list,.hn-md li.task-list-item{list-style:none}.hn-md li.task-list-item{padding-left:0}.hn-md input[type=checkbox]{accent-color:var(--brass-500);margin-right:8px;transform:translateY(1px)}.hn-md strong{font-weight:600;color:var(--ink-900)}.hn-md em{color:var(--text-muted)}.hn-md a{color:var(--text-link)}.hn-md hr{border:none;border-top:1px solid var(--border-hair);margin:1.6em 0}.hn-md code{font-family:var(--font-mono);font-size:.86em;background:var(--bone-200);color:var(--ink-800);padding:1.5px 5px;border-radius:var(--radius-xs);border:1px solid var(--border-hair)}.hn-md pre{background:var(--surface-code);border:1px solid var(--term-line);border-radius:var(--radius-lg);padding:14px 16px;overflow:auto;margin:1em 0;white-space:pre-wrap;overflow-wrap:anywhere}.hn-md pre code{background:transparent;border:none;padding:0;color:var(--term-fg);font-size:12.5px;line-height:1.7}.hn-md blockquote{margin:1em 0;padding:4px 16px;border-left:3px solid var(--brass-500);background:var(--brass-050);color:var(--text-body);border-radius:0 var(--radius-sm) var(--radius-sm) 0}.hn-md blockquote p{margin:.4em 0}.hn-md table{border-collapse:collapse;width:100%;margin:1em 0;font-size:14px;table-layout:fixed}.hn-md th,.hn-md td{overflow-wrap:anywhere}.hn-md th{font-family:var(--font-mono);font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);text-align:left;padding:8px 12px;background:var(--bone-100);border:1px solid var(--border-hair)}.hn-md td{padding:8px 12px;border:1px solid var(--border-hair);color:var(--text-body)}.hn-md td code{font-size:.82em}.hn-md img{max-width:100%;border-radius:var(--radius-sm)}@keyframes hn-fade-in{0%{opacity:0}to{opacity:1}}@keyframes hn-modal-in{0%{opacity:0;transform:translateY(8px) scale(.99)}to{opacity:1;transform:none}}@keyframes hn-toast-in{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}.hn-pet-reactor{transform-origin:50% 86%}.hn-pet-stage:not([data-reduced-motion=true]):hover .hn-pet-reactor{transform:translateY(-2px) scale(1.035) rotate(-1deg)}@keyframes hn-pet-idle-ready{0%,to{transform:translateY(0) scale(1)}50%{transform:translateY(-2px) scale(1.018)}}@keyframes hn-pet-idle-working{0%,to{transform:translateY(0) rotate(0) scale(1)}20%{transform:translateY(-2px) rotate(-.8deg) scale(1.018)}40%{transform:translateY(0) rotate(.6deg) scale(1)}60%{transform:translateY(-3px) rotate(-.5deg) scale(1.022)}80%{transform:translateY(-1px) rotate(.4deg) scale(1.008)}}@keyframes hn-pet-idle-waiting{0%,64%,to{transform:translateY(0) rotate(0)}70%{transform:translateY(-1px) rotate(-2deg)}76%{transform:translateY(-2px) rotate(3deg)}82%{transform:translateY(-1px) rotate(-2deg)}88%{transform:translateY(0) rotate(0)}}@keyframes hn-pet-idle-blocked{0%,to{transform:translateY(1px) scaleY(.99)}50%{transform:translateY(3px) scale(.99,.97)}}@keyframes hn-pet-idle-review{0%,64%,to{transform:translateY(0) rotate(0) scale(1)}74%{transform:translateY(-1px) rotate(-1.6deg) scale(1.012)}84%{transform:translateY(-1px) rotate(.8deg) scale(1.006)}}@keyframes hn-pet-idle-shipped{0%,to{transform:translateY(0) scale(1)}50%{transform:translateY(-2px) scale(1.015)}}@keyframes hn-pet-idle-docs{0%,66%,to{transform:translateY(0) rotate(0) scale(1)}72%{transform:translateY(-1px) rotate(-1.8deg) scale(1.01)}78%{transform:translateY(-1px) rotate(1.5deg) scale(1.012)}84%{transform:translateY(0) rotate(-.7deg) scale(1)}}@keyframes hn-pet-celebrate{0%{transform:translateY(3px) scale(.92) rotate(0)}38%{transform:translateY(-5px) scale(1.08) rotate(-3deg)}62%{transform:translateY(-2px) scale(1.03) rotate(3deg)}to{transform:translateY(0) scale(1) rotate(0)}}@keyframes hn-pet-pose-in{0%{opacity:0;transform:translateY(4px) scale(.76,.92)}62%{opacity:1;transform:translateY(-2px) scale(1.07,.97)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes hn-pet-pose-out{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(3px) scale(.86,1.04)}}@keyframes hn-pet-click{0%,to{transform:translateY(0) scale(1) rotate(0)}38%{transform:translateY(2px) scale(.9,1.06) rotate(-2deg)}72%{transform:translateY(-3px) scale(1.06,.96) rotate(1.5deg)}}@keyframes hn-pet-panel-in{0%{opacity:0;transform:translateY(6px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes hn-pet-panel-out{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(5px) scale(.985)}}@keyframes hn-pet-reveal{0%{opacity:0;transform:translateY(7px) scale(.86)}70%{opacity:1;transform:translateY(-1px) scale(1.035)}to{opacity:1;transform:translateY(0) scale(1)}}/**
|
|
2
2
|
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
3
|
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
4
|
* https://github.com/chjj/term.js
|