hanoman 0.1.4 → 0.1.5

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/cli.js CHANGED
@@ -63,6 +63,13 @@ var init_verify_scope = __esm({
63
63
  }
64
64
  });
65
65
 
66
+ // ../runner/src/goal-spec.ts
67
+ var init_goal_spec = __esm({
68
+ "../runner/src/goal-spec.ts"() {
69
+ "use strict";
70
+ }
71
+ });
72
+
66
73
  // ../runner/src/prompt.ts
67
74
  var ESCALATION_CONTRACT, REVERSE_PHASE_GUIDE, SCAFFOLD_PHASE_GUIDE;
68
75
  var init_prompt = __esm({
@@ -70,6 +77,7 @@ var init_prompt = __esm({
70
77
  "use strict";
71
78
  init_reverse_standard();
72
79
  init_verify_scope();
80
+ init_goal_spec();
73
81
  ESCALATION_CONTRACT = [
74
82
  "REKOMENDASI ESKALASI (wajib, terbaca mesin). Di bagian akhir dokumen audit, tulis bagian",
75
83
  "`## Rekomendasi eskalasi` berisi penjelasan singkat untuk manusia, LALU tepat SATU blok ```json",
@@ -126,6 +134,7 @@ var init_goal = __esm({
126
134
  "../runner/src/goal.ts"() {
127
135
  "use strict";
128
136
  init_prompt();
137
+ init_goal_spec();
129
138
  }
130
139
  });
131
140
 
@@ -213,6 +222,7 @@ var init_src = __esm({
213
222
  init_git();
214
223
  init_settings();
215
224
  init_goal();
225
+ init_goal_spec();
216
226
  init_codex_settings();
217
227
  init_agent_cli();
218
228
  init_verify_scope();
@@ -220,834 +230,506 @@ var init_src = __esm({
220
230
  }
221
231
  });
222
232
 
223
- // src/layout.ts
224
- import { join as join2, resolve as resolve2 } from "node:path";
225
- function resolveLayout(distDir2, exists) {
226
- const pkg = resolve2(distDir2, "..");
227
- if (exists(join2(pkg, "prisma", "schema.prisma"))) {
228
- return {
229
- root: pkg,
230
- schema: join2(pkg, "prisma", "schema.prisma"),
231
- server: join2(pkg, "dist", "server.js"),
232
- web: exists(join2(pkg, "web")) ? join2(pkg, "web") : null
233
- };
234
- }
235
- const repo = resolve2(distDir2, "../..");
236
- if (exists(join2(repo, "server", "prisma", "schema.prisma"))) {
237
- return {
238
- root: repo,
239
- schema: join2(repo, "server", "prisma", "schema.prisma"),
240
- server: join2(repo, "server", "dist", "server.js"),
241
- web: exists(join2(repo, "src", "dist")) ? join2(repo, "src", "dist") : null
233
+ // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
234
+ var util, objectUtil, ZodParsedType, getParsedType;
235
+ var init_util = __esm({
236
+ "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js"() {
237
+ (function(util2) {
238
+ util2.assertEqual = (_) => {
239
+ };
240
+ function assertIs(_arg) {
241
+ }
242
+ util2.assertIs = assertIs;
243
+ function assertNever(_x) {
244
+ throw new Error();
245
+ }
246
+ util2.assertNever = assertNever;
247
+ util2.arrayToEnum = (items) => {
248
+ const obj = {};
249
+ for (const item of items) {
250
+ obj[item] = item;
251
+ }
252
+ return obj;
253
+ };
254
+ util2.getValidEnumValues = (obj) => {
255
+ const validKeys = util2.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
256
+ const filtered = {};
257
+ for (const k of validKeys) {
258
+ filtered[k] = obj[k];
259
+ }
260
+ return util2.objectValues(filtered);
261
+ };
262
+ util2.objectValues = (obj) => {
263
+ return util2.objectKeys(obj).map(function(e) {
264
+ return obj[e];
265
+ });
266
+ };
267
+ util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => {
268
+ const keys = [];
269
+ for (const key in object) {
270
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
271
+ keys.push(key);
272
+ }
273
+ }
274
+ return keys;
275
+ };
276
+ util2.find = (arr, checker) => {
277
+ for (const item of arr) {
278
+ if (checker(item))
279
+ return item;
280
+ }
281
+ return void 0;
282
+ };
283
+ util2.isInteger = typeof Number.isInteger === "function" ? (val) => Number.isInteger(val) : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val;
284
+ function joinValues(array, separator = " | ") {
285
+ return array.map((val) => typeof val === "string" ? `'${val}'` : val).join(separator);
286
+ }
287
+ util2.joinValues = joinValues;
288
+ util2.jsonStringifyReplacer = (_, value) => {
289
+ if (typeof value === "bigint") {
290
+ return value.toString();
291
+ }
292
+ return value;
293
+ };
294
+ })(util || (util = {}));
295
+ (function(objectUtil2) {
296
+ objectUtil2.mergeShapes = (first, second) => {
297
+ return {
298
+ ...first,
299
+ ...second
300
+ // second overwrites first
301
+ };
302
+ };
303
+ })(objectUtil || (objectUtil = {}));
304
+ ZodParsedType = util.arrayToEnum([
305
+ "string",
306
+ "nan",
307
+ "number",
308
+ "integer",
309
+ "float",
310
+ "boolean",
311
+ "date",
312
+ "bigint",
313
+ "symbol",
314
+ "function",
315
+ "undefined",
316
+ "null",
317
+ "array",
318
+ "object",
319
+ "unknown",
320
+ "promise",
321
+ "void",
322
+ "never",
323
+ "map",
324
+ "set"
325
+ ]);
326
+ getParsedType = (data) => {
327
+ const t = typeof data;
328
+ switch (t) {
329
+ case "undefined":
330
+ return ZodParsedType.undefined;
331
+ case "string":
332
+ return ZodParsedType.string;
333
+ case "number":
334
+ return Number.isNaN(data) ? ZodParsedType.nan : ZodParsedType.number;
335
+ case "boolean":
336
+ return ZodParsedType.boolean;
337
+ case "function":
338
+ return ZodParsedType.function;
339
+ case "bigint":
340
+ return ZodParsedType.bigint;
341
+ case "symbol":
342
+ return ZodParsedType.symbol;
343
+ case "object":
344
+ if (Array.isArray(data)) {
345
+ return ZodParsedType.array;
346
+ }
347
+ if (data === null) {
348
+ return ZodParsedType.null;
349
+ }
350
+ if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") {
351
+ return ZodParsedType.promise;
352
+ }
353
+ if (typeof Map !== "undefined" && data instanceof Map) {
354
+ return ZodParsedType.map;
355
+ }
356
+ if (typeof Set !== "undefined" && data instanceof Set) {
357
+ return ZodParsedType.set;
358
+ }
359
+ if (typeof Date !== "undefined" && data instanceof Date) {
360
+ return ZodParsedType.date;
361
+ }
362
+ return ZodParsedType.object;
363
+ default:
364
+ return ZodParsedType.unknown;
365
+ }
242
366
  };
243
367
  }
244
- throw new Error(`hanoman: prisma/schema.prisma tak ditemukan dari ${distDir2} \u2014 instalasi rusak?`);
245
- }
246
- var init_layout = __esm({
247
- "src/layout.ts"() {
248
- "use strict";
249
- }
250
368
  });
251
369
 
252
- // src/commands/start.ts
253
- var start_exports = {};
254
- __export(start_exports, {
255
- applyMigrations: () => applyMigrations,
256
- default: () => start,
257
- distDir: () => distDir,
258
- ensurePrismaClient: () => ensurePrismaClient,
259
- ensureSpawnHelpersExecutable: () => ensureSpawnHelpersExecutable,
260
- migrateFailureHint: () => migrateFailureHint,
261
- parseStartArgs: () => parseStartArgs,
262
- prismaClientUsable: () => prismaClientUsable,
263
- repairSpawnHelper: () => repairSpawnHelper,
264
- spawnHelperPaths: () => spawnHelperPaths
265
- });
266
- import { spawn, execFileSync } from "node:child_process";
267
- import { createRequire } from "node:module";
268
- import { existsSync, mkdirSync, readdirSync, statSync, chmodSync } from "node:fs";
269
- import { dirname as dirname2, join as join3, resolve as resolvePath } from "node:path";
270
- import { fileURLToPath } from "node:url";
271
- function parseStartArgs(argv) {
272
- const out = { port: null, host: null, db: null, migrate: true };
273
- const value = (i, flag, inline) => {
274
- const v = inline ?? argv[i + 1];
275
- if (v === void 0 || v.startsWith("--")) throw new Error(`${flag} butuh nilai`);
276
- return v;
277
- };
278
- for (let i = 0; i < argv.length; i++) {
279
- const raw = argv[i];
280
- const eq = raw.indexOf("=");
281
- const flag = eq === -1 ? raw : raw.slice(0, eq);
282
- const inline = eq === -1 ? void 0 : raw.slice(eq + 1);
283
- if (flag === "--no-migrate") {
284
- out.migrate = false;
285
- continue;
286
- }
287
- if (flag === "--port") {
288
- const v = value(i, "--port", inline);
289
- const n = Number(v);
290
- if (!Number.isInteger(n) || n <= 0) throw new Error(`--port harus angka, dapat "${v}"`);
291
- out.port = n;
292
- if (inline === void 0) i++;
293
- continue;
294
- }
295
- if (flag === "--host") {
296
- out.host = value(i, "--host", inline);
297
- if (inline === void 0) i++;
298
- continue;
299
- }
300
- if (flag === "--db") {
301
- out.db = value(i, "--db", inline);
302
- if (inline === void 0) i++;
303
- continue;
304
- }
305
- throw new Error(`argumen tak dikenal untuk start: ${raw}`);
306
- }
307
- return out;
308
- }
309
- function distDir() {
310
- return dirname2(fileURLToPath(import.meta.url));
311
- }
312
- function runPrisma(args, dbUrl) {
313
- const prismaCli = prismaCliPath(createRequire(import.meta.url).resolve);
314
- try {
315
- const out = execFileSync(process.execPath, [prismaCli, ...args], {
316
- env: { ...process.env, DATABASE_URL: dbUrl },
317
- encoding: "utf8",
318
- stdio: ["ignore", "pipe", "pipe"]
319
- });
320
- process.stdout.write(out);
321
- return out;
322
- } catch (e) {
323
- const err = e;
324
- const output = `${err.stdout ?? ""}${err.stderr ?? ""}`;
325
- process.stderr.write(output);
326
- throw Object.assign(new Error("prisma gagal"), { output });
327
- }
328
- }
329
- function migrateFailureHint(output, dbFile) {
330
- if (!output.includes("P3005")) return null;
331
- return `hanoman: berkas DB ${dbFile} sudah berisi tabel, tapi tak punya riwayat migrasi hanoman.
332
- Biasanya ia bukan DB hanoman versi ini \u2014 mis. sisa prototipe lama atau berkas tool lain.
333
- Pilih salah satu:
334
- \u2022 Pindahkan berkas itu, lalu jalankan ulang: mv "${dbFile}" "${dbFile}.lama"
335
- \u2022 Pakai berkas lain: hanoman --db /path/baru.db (atau HANOMAN_DATABASE_URL=file:/path/baru.db)
336
- Isi berkas lama tidak diubah oleh hanoman \u2014 periksa dulu sebelum menghapusnya.`;
337
- }
338
- function applyMigrations(schema, dbUrl) {
339
- runPrisma(["migrate", "deploy", "--schema", schema], dbUrl);
340
- }
341
- async function prismaClientUsable() {
342
- try {
343
- const { PrismaClient } = await import("@prisma/client");
344
- new PrismaClient();
345
- return true;
346
- } catch {
347
- return false;
370
+ // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js
371
+ var ZodIssueCode, quotelessJson, ZodError;
372
+ var init_ZodError = __esm({
373
+ "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js"() {
374
+ init_util();
375
+ ZodIssueCode = util.arrayToEnum([
376
+ "invalid_type",
377
+ "invalid_literal",
378
+ "custom",
379
+ "invalid_union",
380
+ "invalid_union_discriminator",
381
+ "invalid_enum_value",
382
+ "unrecognized_keys",
383
+ "invalid_arguments",
384
+ "invalid_return_type",
385
+ "invalid_date",
386
+ "invalid_string",
387
+ "too_small",
388
+ "too_big",
389
+ "invalid_intersection_types",
390
+ "not_multiple_of",
391
+ "not_finite"
392
+ ]);
393
+ quotelessJson = (obj) => {
394
+ const json = JSON.stringify(obj, null, 2);
395
+ return json.replace(/"([^"]+)":/g, "$1:");
396
+ };
397
+ ZodError = class _ZodError extends Error {
398
+ get errors() {
399
+ return this.issues;
400
+ }
401
+ constructor(issues) {
402
+ super();
403
+ this.issues = [];
404
+ this.addIssue = (sub) => {
405
+ this.issues = [...this.issues, sub];
406
+ };
407
+ this.addIssues = (subs = []) => {
408
+ this.issues = [...this.issues, ...subs];
409
+ };
410
+ const actualProto = new.target.prototype;
411
+ if (Object.setPrototypeOf) {
412
+ Object.setPrototypeOf(this, actualProto);
413
+ } else {
414
+ this.__proto__ = actualProto;
415
+ }
416
+ this.name = "ZodError";
417
+ this.issues = issues;
418
+ }
419
+ format(_mapper) {
420
+ const mapper = _mapper || function(issue) {
421
+ return issue.message;
422
+ };
423
+ const fieldErrors = { _errors: [] };
424
+ const processError = (error) => {
425
+ for (const issue of error.issues) {
426
+ if (issue.code === "invalid_union") {
427
+ issue.unionErrors.map(processError);
428
+ } else if (issue.code === "invalid_return_type") {
429
+ processError(issue.returnTypeError);
430
+ } else if (issue.code === "invalid_arguments") {
431
+ processError(issue.argumentsError);
432
+ } else if (issue.path.length === 0) {
433
+ fieldErrors._errors.push(mapper(issue));
434
+ } else {
435
+ let curr = fieldErrors;
436
+ let i = 0;
437
+ while (i < issue.path.length) {
438
+ const el = issue.path[i];
439
+ const terminal = i === issue.path.length - 1;
440
+ if (!terminal) {
441
+ curr[el] = curr[el] || { _errors: [] };
442
+ } else {
443
+ curr[el] = curr[el] || { _errors: [] };
444
+ curr[el]._errors.push(mapper(issue));
445
+ }
446
+ curr = curr[el];
447
+ i++;
448
+ }
449
+ }
450
+ }
451
+ };
452
+ processError(this);
453
+ return fieldErrors;
454
+ }
455
+ static assert(value) {
456
+ if (!(value instanceof _ZodError)) {
457
+ throw new Error(`Not a ZodError: ${value}`);
458
+ }
459
+ }
460
+ toString() {
461
+ return this.message;
462
+ }
463
+ get message() {
464
+ return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);
465
+ }
466
+ get isEmpty() {
467
+ return this.issues.length === 0;
468
+ }
469
+ flatten(mapper = (issue) => issue.message) {
470
+ const fieldErrors = {};
471
+ const formErrors = [];
472
+ for (const sub of this.issues) {
473
+ if (sub.path.length > 0) {
474
+ const firstEl = sub.path[0];
475
+ fieldErrors[firstEl] = fieldErrors[firstEl] || [];
476
+ fieldErrors[firstEl].push(mapper(sub));
477
+ } else {
478
+ formErrors.push(mapper(sub));
479
+ }
480
+ }
481
+ return { formErrors, fieldErrors };
482
+ }
483
+ get formErrors() {
484
+ return this.flatten();
485
+ }
486
+ };
487
+ ZodError.create = (issues) => {
488
+ const error = new ZodError(issues);
489
+ return error;
490
+ };
348
491
  }
349
- }
350
- async function ensurePrismaClient(schema, dbUrl, ctx) {
351
- if (await prismaClientUsable()) return true;
352
- ctx.stdout("hanoman \xB7 menyiapkan Prisma client (sekali per instalasi)\n");
353
- try {
354
- runPrisma(["generate", "--schema", schema], dbUrl);
355
- return true;
356
- } catch {
357
- ctx.stderr("hanoman: `prisma generate` gagal \u2014 jalankan manual di direktori paket, atau pasang ulang tanpa --ignore-scripts\n");
358
- return false;
492
+ });
493
+
494
+ // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js
495
+ var errorMap, en_default;
496
+ var init_en = __esm({
497
+ "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js"() {
498
+ init_ZodError();
499
+ init_util();
500
+ errorMap = (issue, _ctx) => {
501
+ let message;
502
+ switch (issue.code) {
503
+ case ZodIssueCode.invalid_type:
504
+ if (issue.received === ZodParsedType.undefined) {
505
+ message = "Required";
506
+ } else {
507
+ message = `Expected ${issue.expected}, received ${issue.received}`;
508
+ }
509
+ break;
510
+ case ZodIssueCode.invalid_literal:
511
+ message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`;
512
+ break;
513
+ case ZodIssueCode.unrecognized_keys:
514
+ message = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, ", ")}`;
515
+ break;
516
+ case ZodIssueCode.invalid_union:
517
+ message = `Invalid input`;
518
+ break;
519
+ case ZodIssueCode.invalid_union_discriminator:
520
+ message = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`;
521
+ break;
522
+ case ZodIssueCode.invalid_enum_value:
523
+ message = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`;
524
+ break;
525
+ case ZodIssueCode.invalid_arguments:
526
+ message = `Invalid function arguments`;
527
+ break;
528
+ case ZodIssueCode.invalid_return_type:
529
+ message = `Invalid function return type`;
530
+ break;
531
+ case ZodIssueCode.invalid_date:
532
+ message = `Invalid date`;
533
+ break;
534
+ case ZodIssueCode.invalid_string:
535
+ if (typeof issue.validation === "object") {
536
+ if ("includes" in issue.validation) {
537
+ message = `Invalid input: must include "${issue.validation.includes}"`;
538
+ if (typeof issue.validation.position === "number") {
539
+ message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`;
540
+ }
541
+ } else if ("startsWith" in issue.validation) {
542
+ message = `Invalid input: must start with "${issue.validation.startsWith}"`;
543
+ } else if ("endsWith" in issue.validation) {
544
+ message = `Invalid input: must end with "${issue.validation.endsWith}"`;
545
+ } else {
546
+ util.assertNever(issue.validation);
547
+ }
548
+ } else if (issue.validation !== "regex") {
549
+ message = `Invalid ${issue.validation}`;
550
+ } else {
551
+ message = "Invalid";
552
+ }
553
+ break;
554
+ case ZodIssueCode.too_small:
555
+ if (issue.type === "array")
556
+ message = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`;
557
+ else if (issue.type === "string")
558
+ message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;
559
+ else if (issue.type === "number")
560
+ message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
561
+ else if (issue.type === "bigint")
562
+ message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
563
+ else if (issue.type === "date")
564
+ message = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`;
565
+ else
566
+ message = "Invalid input";
567
+ break;
568
+ case ZodIssueCode.too_big:
569
+ if (issue.type === "array")
570
+ message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`;
571
+ else if (issue.type === "string")
572
+ message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`;
573
+ else if (issue.type === "number")
574
+ message = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
575
+ else if (issue.type === "bigint")
576
+ message = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
577
+ else if (issue.type === "date")
578
+ message = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`;
579
+ else
580
+ message = "Invalid input";
581
+ break;
582
+ case ZodIssueCode.custom:
583
+ message = `Invalid input`;
584
+ break;
585
+ case ZodIssueCode.invalid_intersection_types:
586
+ message = `Intersection results could not be merged`;
587
+ break;
588
+ case ZodIssueCode.not_multiple_of:
589
+ message = `Number must be a multiple of ${issue.multipleOf}`;
590
+ break;
591
+ case ZodIssueCode.not_finite:
592
+ message = "Number must be finite";
593
+ break;
594
+ default:
595
+ message = _ctx.defaultError;
596
+ util.assertNever(issue);
597
+ }
598
+ return { message };
599
+ };
600
+ en_default = errorMap;
359
601
  }
602
+ });
603
+
604
+ // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js
605
+ function setErrorMap(map) {
606
+ overrideErrorMap = map;
360
607
  }
361
- function spawnHelperPaths(ptyDir, listDir, exists) {
362
- const dirs = [join3(ptyDir, "build", "Release")];
363
- for (const name of listDir(join3(ptyDir, "prebuilds"))) dirs.push(join3(ptyDir, "prebuilds", name));
364
- return dirs.map((d) => join3(d, "spawn-helper")).filter(exists);
608
+ function getErrorMap() {
609
+ return overrideErrorMap;
365
610
  }
366
- function ensureSpawnHelpersExecutable(paths2, ops) {
367
- const fixed = [];
368
- for (const p of paths2) {
369
- try {
370
- const mode = ops.mode(p) & 4095;
371
- if ((mode & 73) === 73) continue;
372
- ops.chmod(p, mode | 73);
373
- fixed.push(p);
374
- } catch {
375
- }
376
- }
377
- return fixed;
378
- }
379
- function repairSpawnHelper(ctx) {
380
- let ptyDir;
381
- try {
382
- ptyDir = dirname2(createRequire(import.meta.url).resolve("node-pty/package.json"));
383
- } catch {
384
- return;
385
- }
386
- const paths2 = spawnHelperPaths(ptyDir, (d) => {
387
- try {
388
- return readdirSync(d);
389
- } catch {
390
- return [];
391
- }
392
- }, existsSync);
393
- const fixed = ensureSpawnHelpersExecutable(paths2, {
394
- mode: (p) => statSync(p).mode,
395
- chmod: (p, m) => chmodSync(p, m)
396
- });
397
- if (fixed.length) ctx.stdout("hanoman \xB7 memperbaiki izin `spawn-helper` node-pty (sekali per instalasi)\n");
398
- }
399
- async function start(argv, ctx) {
400
- let opts;
401
- try {
402
- opts = parseStartArgs(argv);
403
- } catch (e) {
404
- ctx.stderr(`${e.message}
405
- `);
406
- return 2;
407
- }
408
- let layout;
409
- let dbUrl;
410
- try {
411
- layout = resolveLayout(distDir(), existsSync);
412
- dbUrl = opts.db ? `file:${resolvePath(opts.db)}` : resolveDbUrl(ctx.env, dirname2(layout.schema));
413
- } catch (e) {
414
- ctx.stderr(`${e.message}
415
- `);
416
- return 1;
417
- }
418
- const notice = dbUrlNotice(ctx.env);
419
- if (notice) ctx.stderr(`${notice}
420
- `);
421
- const home = resolveHome(ctx.env);
422
- mkdirSync(home, { recursive: true });
423
- mkdirSync(dirname2(dbFilePath(dbUrl)), { recursive: true });
424
- if (!existsSync(layout.server)) {
425
- ctx.stderr(`hanoman: bundle server tak ada di ${layout.server} \u2014 jalankan \`pnpm build\` dulu
426
- `);
427
- return 1;
428
- }
429
- if (!await ensurePrismaClient(layout.schema, dbUrl, ctx)) return 1;
430
- repairSpawnHelper(ctx);
431
- if (opts.migrate) {
432
- ctx.stdout(`hanoman \xB7 menerapkan migrasi ke ${dbFilePath(dbUrl)}
433
- `);
434
- try {
435
- applyMigrations(layout.schema, dbUrl);
436
- } catch (e) {
437
- const hint = migrateFailureHint(String(e.output ?? ""), dbFilePath(dbUrl));
438
- ctx.stderr(hint ? `
439
- ${hint}
440
- ` : "hanoman: `prisma migrate deploy` gagal \u2014 lihat keluaran di atas\n");
441
- return 1;
442
- }
443
- }
444
- const port = opts.port ?? Number(ctx.env.PORT ?? 8787);
445
- const host = opts.host ?? ctx.env.HOST ?? "127.0.0.1";
446
- ctx.stdout(`hanoman \xB7 http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}
447
- `);
448
- const child = spawn(process.execPath, [layout.server], {
449
- stdio: "inherit",
450
- env: {
451
- ...process.env,
452
- NODE_ENV: "production",
453
- DATABASE_URL: dbUrl,
454
- PORT: String(port),
455
- HOST: host,
456
- HANOMAN_HOME: home,
457
- ...layout.web ? { HANOMAN_WEB_DIR: layout.web } : {}
458
- }
459
- });
460
- for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => child.kill(sig));
461
- return await new Promise((res) => child.on("exit", (code) => res(code ?? 0)));
462
- }
463
- var init_start = __esm({
464
- "src/commands/start.ts"() {
465
- "use strict";
466
- init_src();
467
- init_layout();
611
+ var overrideErrorMap;
612
+ var init_errors = __esm({
613
+ "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js"() {
614
+ init_en();
615
+ overrideErrorMap = en_default;
468
616
  }
469
617
  });
470
618
 
471
- // src/commands/doctor.ts
472
- var doctor_exports = {};
473
- __export(doctor_exports, {
474
- default: () => doctor,
475
- doctorReport: () => doctorReport
476
- });
477
- import { execFileSync as execFileSync2 } from "node:child_process";
478
- import { accessSync, constants, existsSync as existsSync2 } from "node:fs";
479
- import { dirname as dirname3 } from "node:path";
480
- function doctorReport(p) {
481
- const major = Number(/^v?(\d+)/.exec(p.node)?.[1] ?? 0);
482
- const rows = [
483
- { mark: major >= 20 ? "\u2713" : "\u2717", text: `node ${p.node} (butuh \u2265 20)`, fatal: major < 20 },
484
- { mark: p.git ? "\u2713" : "\u2717", text: p.git ?? "git \u2014 TAK ADA (wajib: worktree per sesi)", fatal: !p.git },
485
- { mark: p.tmux ? "\u2713" : "\u2717", text: p.tmux ?? "tmux \u2014 TAK ADA (wajib: sesi agen hidup di tmux)", fatal: !p.tmux },
486
- { mark: p.claude ? "\u2713" : "\xB7", text: p.claude ? `claude ${p.claude}` : "claude \u2014 tak ada", fatal: false },
487
- { mark: p.codex ? "\u2713" : "\xB7", text: p.codex ? `codex ${p.codex}` : "codex \u2014 tak ada", fatal: false },
488
- { mark: p.homeWritable ? "\u2713" : "\u2717", text: `data dir ${p.homeWritable ? "bisa ditulis" : "TAK bisa ditulis"}`, fatal: !p.homeWritable },
489
- { mark: p.web ? "\u2713" : "!", text: p.web ? "aset dashboard ada" : "aset dashboard tak ada \u2014 API jalan, dashboard tidak", fatal: false },
490
- { mark: "\xB7", text: `db ${p.db}`, fatal: false }
491
- ];
492
- if (!p.claude && !p.codex) {
493
- rows.push({ mark: "\u2717", text: "tak ada CLI agen (claude ATAU codex wajib ada)", fatal: true });
494
- }
495
- return { lines: rows.map((r) => ` ${r.mark} ${r.text}`), ok: !rows.some((r) => r.fatal) };
496
- }
497
- function version(bin, args) {
498
- try {
499
- return execFileSync2(bin, args, { encoding: "utf8", timeout: 1e4, stdio: ["ignore", "pipe", "ignore"] }).trim().split("\n")[0] ?? null;
500
- } catch {
501
- return null;
502
- }
503
- }
504
- async function doctor(_argv, ctx) {
505
- let layout;
506
- let db;
507
- try {
508
- layout = resolveLayout(distDir(), existsSync2);
509
- db = dbFilePath(resolveDbUrl(ctx.env, dirname3(layout.schema)));
510
- } catch (e) {
511
- ctx.stderr(`${e.message}
512
- `);
513
- return 1;
514
- }
515
- const home = resolveHome(ctx.env);
516
- let homeWritable = false;
517
- try {
518
- accessSync(existsSync2(home) ? home : dirname3(home), constants.W_OK);
519
- homeWritable = true;
520
- } catch {
521
- }
522
- const r = doctorReport({
523
- node: process.version,
524
- git: version("git", ["--version"]),
525
- tmux: version("tmux", ["-V"]),
526
- claude: version(ctx.env.HANOMAN_CLAUDE_BIN ?? "claude", ["--version"]),
527
- codex: version(ctx.env.HANOMAN_CODEX_BIN ?? "codex", ["--version"]),
528
- homeWritable,
529
- web: layout.web !== null,
530
- db
619
+ // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
620
+ function addIssueToContext(ctx, issueData) {
621
+ const overrideMap = getErrorMap();
622
+ const issue = makeIssue({
623
+ issueData,
624
+ data: ctx.data,
625
+ path: ctx.path,
626
+ errorMaps: [
627
+ ctx.common.contextualErrorMap,
628
+ // contextual error map is first priority
629
+ ctx.schemaErrorMap,
630
+ // then schema-bound map if available
631
+ overrideMap,
632
+ // then global override map
633
+ overrideMap === en_default ? void 0 : en_default
634
+ // then global default map
635
+ ].filter((x) => !!x)
531
636
  });
532
- ctx.stdout(`hanoman doctor
533
- ${r.lines.join("\n")}
534
- `);
535
- const notice = dbUrlNotice(ctx.env);
536
- if (notice) ctx.stdout(`
537
- ${notice}
538
- `);
539
- if (!r.ok) ctx.stderr("\nada prasyarat yang belum terpenuhi \u2014 hanoman tak akan bisa menjalankan sesi\n");
540
- return r.ok ? 0 : 1;
637
+ ctx.common.issues.push(issue);
541
638
  }
542
- var init_doctor = __esm({
543
- "src/commands/doctor.ts"() {
544
- "use strict";
545
- init_src();
546
- init_layout();
547
- init_start();
548
- }
549
- });
550
-
551
- // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
552
- var util, objectUtil, ZodParsedType, getParsedType;
553
- var init_util = __esm({
554
- "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js"() {
555
- (function(util2) {
556
- util2.assertEqual = (_) => {
639
+ var makeIssue, EMPTY_PATH, ParseStatus, INVALID, DIRTY, OK, isAborted, isDirty, isValid, isAsync;
640
+ var init_parseUtil = __esm({
641
+ "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js"() {
642
+ init_errors();
643
+ init_en();
644
+ makeIssue = (params) => {
645
+ const { data, path, errorMaps, issueData } = params;
646
+ const fullPath = [...path, ...issueData.path || []];
647
+ const fullIssue = {
648
+ ...issueData,
649
+ path: fullPath
557
650
  };
558
- function assertIs(_arg) {
651
+ if (issueData.message !== void 0) {
652
+ return {
653
+ ...issueData,
654
+ path: fullPath,
655
+ message: issueData.message
656
+ };
559
657
  }
560
- util2.assertIs = assertIs;
561
- function assertNever(_x) {
562
- throw new Error();
658
+ let errorMessage = "";
659
+ const maps = errorMaps.filter((m) => !!m).slice().reverse();
660
+ for (const map of maps) {
661
+ errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message;
563
662
  }
564
- util2.assertNever = assertNever;
565
- util2.arrayToEnum = (items) => {
566
- const obj = {};
567
- for (const item of items) {
568
- obj[item] = item;
569
- }
570
- return obj;
663
+ return {
664
+ ...issueData,
665
+ path: fullPath,
666
+ message: errorMessage
571
667
  };
572
- util2.getValidEnumValues = (obj) => {
573
- const validKeys = util2.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
574
- const filtered = {};
575
- for (const k of validKeys) {
576
- filtered[k] = obj[k];
668
+ };
669
+ EMPTY_PATH = [];
670
+ ParseStatus = class _ParseStatus {
671
+ constructor() {
672
+ this.value = "valid";
673
+ }
674
+ dirty() {
675
+ if (this.value === "valid")
676
+ this.value = "dirty";
677
+ }
678
+ abort() {
679
+ if (this.value !== "aborted")
680
+ this.value = "aborted";
681
+ }
682
+ static mergeArray(status, results) {
683
+ const arrayValue = [];
684
+ for (const s of results) {
685
+ if (s.status === "aborted")
686
+ return INVALID;
687
+ if (s.status === "dirty")
688
+ status.dirty();
689
+ arrayValue.push(s.value);
577
690
  }
578
- return util2.objectValues(filtered);
579
- };
580
- util2.objectValues = (obj) => {
581
- return util2.objectKeys(obj).map(function(e) {
582
- return obj[e];
583
- });
584
- };
585
- util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => {
586
- const keys = [];
587
- for (const key in object) {
588
- if (Object.prototype.hasOwnProperty.call(object, key)) {
589
- keys.push(key);
590
- }
591
- }
592
- return keys;
593
- };
594
- util2.find = (arr, checker) => {
595
- for (const item of arr) {
596
- if (checker(item))
597
- return item;
598
- }
599
- return void 0;
600
- };
601
- util2.isInteger = typeof Number.isInteger === "function" ? (val) => Number.isInteger(val) : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val;
602
- function joinValues(array, separator = " | ") {
603
- return array.map((val) => typeof val === "string" ? `'${val}'` : val).join(separator);
604
- }
605
- util2.joinValues = joinValues;
606
- util2.jsonStringifyReplacer = (_, value) => {
607
- if (typeof value === "bigint") {
608
- return value.toString();
609
- }
610
- return value;
611
- };
612
- })(util || (util = {}));
613
- (function(objectUtil2) {
614
- objectUtil2.mergeShapes = (first, second) => {
615
- return {
616
- ...first,
617
- ...second
618
- // second overwrites first
619
- };
620
- };
621
- })(objectUtil || (objectUtil = {}));
622
- ZodParsedType = util.arrayToEnum([
623
- "string",
624
- "nan",
625
- "number",
626
- "integer",
627
- "float",
628
- "boolean",
629
- "date",
630
- "bigint",
631
- "symbol",
632
- "function",
633
- "undefined",
634
- "null",
635
- "array",
636
- "object",
637
- "unknown",
638
- "promise",
639
- "void",
640
- "never",
641
- "map",
642
- "set"
643
- ]);
644
- getParsedType = (data) => {
645
- const t = typeof data;
646
- switch (t) {
647
- case "undefined":
648
- return ZodParsedType.undefined;
649
- case "string":
650
- return ZodParsedType.string;
651
- case "number":
652
- return Number.isNaN(data) ? ZodParsedType.nan : ZodParsedType.number;
653
- case "boolean":
654
- return ZodParsedType.boolean;
655
- case "function":
656
- return ZodParsedType.function;
657
- case "bigint":
658
- return ZodParsedType.bigint;
659
- case "symbol":
660
- return ZodParsedType.symbol;
661
- case "object":
662
- if (Array.isArray(data)) {
663
- return ZodParsedType.array;
664
- }
665
- if (data === null) {
666
- return ZodParsedType.null;
667
- }
668
- if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") {
669
- return ZodParsedType.promise;
670
- }
671
- if (typeof Map !== "undefined" && data instanceof Map) {
672
- return ZodParsedType.map;
673
- }
674
- if (typeof Set !== "undefined" && data instanceof Set) {
675
- return ZodParsedType.set;
676
- }
677
- if (typeof Date !== "undefined" && data instanceof Date) {
678
- return ZodParsedType.date;
679
- }
680
- return ZodParsedType.object;
681
- default:
682
- return ZodParsedType.unknown;
683
- }
684
- };
685
- }
686
- });
687
-
688
- // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js
689
- var ZodIssueCode, quotelessJson, ZodError;
690
- var init_ZodError = __esm({
691
- "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js"() {
692
- init_util();
693
- ZodIssueCode = util.arrayToEnum([
694
- "invalid_type",
695
- "invalid_literal",
696
- "custom",
697
- "invalid_union",
698
- "invalid_union_discriminator",
699
- "invalid_enum_value",
700
- "unrecognized_keys",
701
- "invalid_arguments",
702
- "invalid_return_type",
703
- "invalid_date",
704
- "invalid_string",
705
- "too_small",
706
- "too_big",
707
- "invalid_intersection_types",
708
- "not_multiple_of",
709
- "not_finite"
710
- ]);
711
- quotelessJson = (obj) => {
712
- const json = JSON.stringify(obj, null, 2);
713
- return json.replace(/"([^"]+)":/g, "$1:");
714
- };
715
- ZodError = class _ZodError extends Error {
716
- get errors() {
717
- return this.issues;
718
- }
719
- constructor(issues) {
720
- super();
721
- this.issues = [];
722
- this.addIssue = (sub) => {
723
- this.issues = [...this.issues, sub];
724
- };
725
- this.addIssues = (subs = []) => {
726
- this.issues = [...this.issues, ...subs];
727
- };
728
- const actualProto = new.target.prototype;
729
- if (Object.setPrototypeOf) {
730
- Object.setPrototypeOf(this, actualProto);
731
- } else {
732
- this.__proto__ = actualProto;
733
- }
734
- this.name = "ZodError";
735
- this.issues = issues;
736
- }
737
- format(_mapper) {
738
- const mapper = _mapper || function(issue) {
739
- return issue.message;
740
- };
741
- const fieldErrors = { _errors: [] };
742
- const processError = (error) => {
743
- for (const issue of error.issues) {
744
- if (issue.code === "invalid_union") {
745
- issue.unionErrors.map(processError);
746
- } else if (issue.code === "invalid_return_type") {
747
- processError(issue.returnTypeError);
748
- } else if (issue.code === "invalid_arguments") {
749
- processError(issue.argumentsError);
750
- } else if (issue.path.length === 0) {
751
- fieldErrors._errors.push(mapper(issue));
752
- } else {
753
- let curr = fieldErrors;
754
- let i = 0;
755
- while (i < issue.path.length) {
756
- const el = issue.path[i];
757
- const terminal = i === issue.path.length - 1;
758
- if (!terminal) {
759
- curr[el] = curr[el] || { _errors: [] };
760
- } else {
761
- curr[el] = curr[el] || { _errors: [] };
762
- curr[el]._errors.push(mapper(issue));
763
- }
764
- curr = curr[el];
765
- i++;
766
- }
767
- }
768
- }
769
- };
770
- processError(this);
771
- return fieldErrors;
691
+ return { status: status.value, value: arrayValue };
772
692
  }
773
- static assert(value) {
774
- if (!(value instanceof _ZodError)) {
775
- throw new Error(`Not a ZodError: ${value}`);
693
+ static async mergeObjectAsync(status, pairs) {
694
+ const syncPairs = [];
695
+ for (const pair of pairs) {
696
+ const key = await pair.key;
697
+ const value = await pair.value;
698
+ syncPairs.push({
699
+ key,
700
+ value
701
+ });
776
702
  }
703
+ return _ParseStatus.mergeObjectSync(status, syncPairs);
777
704
  }
778
- toString() {
779
- return this.message;
780
- }
781
- get message() {
782
- return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);
783
- }
784
- get isEmpty() {
785
- return this.issues.length === 0;
786
- }
787
- flatten(mapper = (issue) => issue.message) {
788
- const fieldErrors = {};
789
- const formErrors = [];
790
- for (const sub of this.issues) {
791
- if (sub.path.length > 0) {
792
- const firstEl = sub.path[0];
793
- fieldErrors[firstEl] = fieldErrors[firstEl] || [];
794
- fieldErrors[firstEl].push(mapper(sub));
795
- } else {
796
- formErrors.push(mapper(sub));
705
+ static mergeObjectSync(status, pairs) {
706
+ const finalObject = {};
707
+ for (const pair of pairs) {
708
+ const { key, value } = pair;
709
+ if (key.status === "aborted")
710
+ return INVALID;
711
+ if (value.status === "aborted")
712
+ return INVALID;
713
+ if (key.status === "dirty")
714
+ status.dirty();
715
+ if (value.status === "dirty")
716
+ status.dirty();
717
+ if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) {
718
+ finalObject[key.value] = value.value;
797
719
  }
798
720
  }
799
- return { formErrors, fieldErrors };
800
- }
801
- get formErrors() {
802
- return this.flatten();
721
+ return { status: status.value, value: finalObject };
803
722
  }
804
723
  };
805
- ZodError.create = (issues) => {
806
- const error = new ZodError(issues);
807
- return error;
808
- };
809
- }
810
- });
811
-
812
- // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js
813
- var errorMap, en_default;
814
- var init_en = __esm({
815
- "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js"() {
816
- init_ZodError();
817
- init_util();
818
- errorMap = (issue, _ctx) => {
819
- let message;
820
- switch (issue.code) {
821
- case ZodIssueCode.invalid_type:
822
- if (issue.received === ZodParsedType.undefined) {
823
- message = "Required";
824
- } else {
825
- message = `Expected ${issue.expected}, received ${issue.received}`;
826
- }
827
- break;
828
- case ZodIssueCode.invalid_literal:
829
- message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`;
830
- break;
831
- case ZodIssueCode.unrecognized_keys:
832
- message = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, ", ")}`;
833
- break;
834
- case ZodIssueCode.invalid_union:
835
- message = `Invalid input`;
836
- break;
837
- case ZodIssueCode.invalid_union_discriminator:
838
- message = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`;
839
- break;
840
- case ZodIssueCode.invalid_enum_value:
841
- message = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`;
842
- break;
843
- case ZodIssueCode.invalid_arguments:
844
- message = `Invalid function arguments`;
845
- break;
846
- case ZodIssueCode.invalid_return_type:
847
- message = `Invalid function return type`;
848
- break;
849
- case ZodIssueCode.invalid_date:
850
- message = `Invalid date`;
851
- break;
852
- case ZodIssueCode.invalid_string:
853
- if (typeof issue.validation === "object") {
854
- if ("includes" in issue.validation) {
855
- message = `Invalid input: must include "${issue.validation.includes}"`;
856
- if (typeof issue.validation.position === "number") {
857
- message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`;
858
- }
859
- } else if ("startsWith" in issue.validation) {
860
- message = `Invalid input: must start with "${issue.validation.startsWith}"`;
861
- } else if ("endsWith" in issue.validation) {
862
- message = `Invalid input: must end with "${issue.validation.endsWith}"`;
863
- } else {
864
- util.assertNever(issue.validation);
865
- }
866
- } else if (issue.validation !== "regex") {
867
- message = `Invalid ${issue.validation}`;
868
- } else {
869
- message = "Invalid";
870
- }
871
- break;
872
- case ZodIssueCode.too_small:
873
- if (issue.type === "array")
874
- message = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`;
875
- else if (issue.type === "string")
876
- message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;
877
- else if (issue.type === "number")
878
- message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
879
- else if (issue.type === "bigint")
880
- message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
881
- else if (issue.type === "date")
882
- message = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`;
883
- else
884
- message = "Invalid input";
885
- break;
886
- case ZodIssueCode.too_big:
887
- if (issue.type === "array")
888
- message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`;
889
- else if (issue.type === "string")
890
- message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`;
891
- else if (issue.type === "number")
892
- message = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
893
- else if (issue.type === "bigint")
894
- message = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
895
- else if (issue.type === "date")
896
- message = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`;
897
- else
898
- message = "Invalid input";
899
- break;
900
- case ZodIssueCode.custom:
901
- message = `Invalid input`;
902
- break;
903
- case ZodIssueCode.invalid_intersection_types:
904
- message = `Intersection results could not be merged`;
905
- break;
906
- case ZodIssueCode.not_multiple_of:
907
- message = `Number must be a multiple of ${issue.multipleOf}`;
908
- break;
909
- case ZodIssueCode.not_finite:
910
- message = "Number must be finite";
911
- break;
912
- default:
913
- message = _ctx.defaultError;
914
- util.assertNever(issue);
915
- }
916
- return { message };
917
- };
918
- en_default = errorMap;
919
- }
920
- });
921
-
922
- // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js
923
- function setErrorMap(map) {
924
- overrideErrorMap = map;
925
- }
926
- function getErrorMap() {
927
- return overrideErrorMap;
928
- }
929
- var overrideErrorMap;
930
- var init_errors = __esm({
931
- "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js"() {
932
- init_en();
933
- overrideErrorMap = en_default;
934
- }
935
- });
936
-
937
- // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
938
- function addIssueToContext(ctx, issueData) {
939
- const overrideMap = getErrorMap();
940
- const issue = makeIssue({
941
- issueData,
942
- data: ctx.data,
943
- path: ctx.path,
944
- errorMaps: [
945
- ctx.common.contextualErrorMap,
946
- // contextual error map is first priority
947
- ctx.schemaErrorMap,
948
- // then schema-bound map if available
949
- overrideMap,
950
- // then global override map
951
- overrideMap === en_default ? void 0 : en_default
952
- // then global default map
953
- ].filter((x) => !!x)
954
- });
955
- ctx.common.issues.push(issue);
956
- }
957
- var makeIssue, EMPTY_PATH, ParseStatus, INVALID, DIRTY, OK, isAborted, isDirty, isValid, isAsync;
958
- var init_parseUtil = __esm({
959
- "../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js"() {
960
- init_errors();
961
- init_en();
962
- makeIssue = (params) => {
963
- const { data, path, errorMaps, issueData } = params;
964
- const fullPath = [...path, ...issueData.path || []];
965
- const fullIssue = {
966
- ...issueData,
967
- path: fullPath
968
- };
969
- if (issueData.message !== void 0) {
970
- return {
971
- ...issueData,
972
- path: fullPath,
973
- message: issueData.message
974
- };
975
- }
976
- let errorMessage = "";
977
- const maps = errorMaps.filter((m) => !!m).slice().reverse();
978
- for (const map of maps) {
979
- errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message;
980
- }
981
- return {
982
- ...issueData,
983
- path: fullPath,
984
- message: errorMessage
985
- };
986
- };
987
- EMPTY_PATH = [];
988
- ParseStatus = class _ParseStatus {
989
- constructor() {
990
- this.value = "valid";
991
- }
992
- dirty() {
993
- if (this.value === "valid")
994
- this.value = "dirty";
995
- }
996
- abort() {
997
- if (this.value !== "aborted")
998
- this.value = "aborted";
999
- }
1000
- static mergeArray(status, results) {
1001
- const arrayValue = [];
1002
- for (const s of results) {
1003
- if (s.status === "aborted")
1004
- return INVALID;
1005
- if (s.status === "dirty")
1006
- status.dirty();
1007
- arrayValue.push(s.value);
1008
- }
1009
- return { status: status.value, value: arrayValue };
1010
- }
1011
- static async mergeObjectAsync(status, pairs) {
1012
- const syncPairs = [];
1013
- for (const pair of pairs) {
1014
- const key = await pair.key;
1015
- const value = await pair.value;
1016
- syncPairs.push({
1017
- key,
1018
- value
1019
- });
1020
- }
1021
- return _ParseStatus.mergeObjectSync(status, syncPairs);
1022
- }
1023
- static mergeObjectSync(status, pairs) {
1024
- const finalObject = {};
1025
- for (const pair of pairs) {
1026
- const { key, value } = pair;
1027
- if (key.status === "aborted")
1028
- return INVALID;
1029
- if (value.status === "aborted")
1030
- return INVALID;
1031
- if (key.status === "dirty")
1032
- status.dirty();
1033
- if (value.status === "dirty")
1034
- status.dirty();
1035
- if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) {
1036
- finalObject[key.value] = value.value;
1037
- }
1038
- }
1039
- return { status: status.value, value: finalObject };
1040
- }
1041
- };
1042
- INVALID = Object.freeze({
1043
- status: "aborted"
1044
- });
1045
- DIRTY = (value) => ({ status: "dirty", value });
1046
- OK = (value) => ({ status: "valid", value });
1047
- isAborted = (x) => x.status === "aborted";
1048
- isDirty = (x) => x.status === "dirty";
1049
- isValid = (x) => x.status === "valid";
1050
- isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
724
+ INVALID = Object.freeze({
725
+ status: "aborted"
726
+ });
727
+ DIRTY = (value) => ({ status: "dirty", value });
728
+ OK = (value) => ({ status: "valid", value });
729
+ isAborted = (x) => x.status === "aborted";
730
+ isDirty = (x) => x.status === "dirty";
731
+ isValid = (x) => x.status === "valid";
732
+ isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
1051
733
  }
1052
734
  });
1053
735
 
@@ -4661,7 +4343,7 @@ var init_enums = __esm({
4661
4343
  "use strict";
4662
4344
  init_zod();
4663
4345
  zStage = external_exports.enum(["brainstorming", "objective", "spec-ready", "planned", "executing", "done"]);
4664
- zSpecSource = external_exports.enum(["brief", "qa", "audit", "cross-audit", "help"]);
4346
+ zSpecSource = external_exports.enum(["brief", "qa", "audit", "cross-audit", "help", "goal"]);
4665
4347
  zDocStatus = external_exports.enum(["ok", "drift", "broken"]);
4666
4348
  zPriority = external_exports.enum(["tinggi", "sedang", "rendah"]);
4667
4349
  zProjectKind = external_exports.enum(["from-scratch", "existing"]);
@@ -4677,7 +4359,7 @@ var init_enums = __esm({
4677
4359
  });
4678
4360
 
4679
4361
  // ../shared/src/entities.ts
4680
- var zProject, zBriefPayload, zQaPayload, zSpec, NOTIFY_SOUNDS, zCodex, CODEX_DEFAULTS, zSourceCommon, zScheduler, SCHEDULER_DEFAULTS, zGoal, GOAL_DEFAULTS, zConflict, CONFLICT_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
4362
+ var zProject, zBriefPayload, zQaPayload, zGoalPayload, zSpec, NOTIFY_SOUNDS, zCodex, CODEX_DEFAULTS, zSourceCommon, zScheduler, SCHEDULER_DEFAULTS, zGoal, GOAL_DEFAULTS, zConflict, CONFLICT_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
4681
4363
  var init_entities = __esm({
4682
4364
  "../shared/src/entities.ts"() {
4683
4365
  "use strict";
@@ -4716,6 +4398,12 @@ var init_entities = __esm({
4716
4398
  // SPEC-244 · qa dinaikkan dari audit → sinyal skip fase Audit (ADR-0059)
4717
4399
  fromErrorGroup: external_exports.string().optional()
4718
4400
  });
4401
+ zGoalPayload = external_exports.object({
4402
+ goal: external_exports.string(),
4403
+ done: external_exports.string(),
4404
+ constraints: external_exports.string(),
4405
+ priority: zPriority
4406
+ });
4719
4407
  zSpec = external_exports.object({
4720
4408
  id: external_exports.string(),
4721
4409
  projectId: external_exports.string(),
@@ -4725,7 +4413,8 @@ var init_entities = __esm({
4725
4413
  priority: zPriority,
4726
4414
  author: external_exports.string(),
4727
4415
  objective: external_exports.string(),
4728
- payload: external_exports.union([zBriefPayload, zQaPayload]).nullable(),
4416
+ payload: external_exports.union([zBriefPayload, zQaPayload, zGoalPayload]).nullable(),
4417
+ // SPEC-407 · +goal
4729
4418
  branchFrom: external_exports.string().nullable(),
4730
4419
  // SPEC-143 · null = default project (main)
4731
4420
  baseSha: external_exports.string().nullable()
@@ -4899,7 +4588,7 @@ var init_agent = __esm({
4899
4588
  });
4900
4589
 
4901
4590
  // ../shared/src/dto.ts
4902
- var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zCreateLink, zUpdateProject, zCreateSpec, zPatchSpec, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerState, zFlow, zPrdBrief, zPrdDoc, zBreakdownItem, zBreakdownDoc, zBatchCreateSpec, zEscalationTarget, zEscalationPrefill, zAuditEscalation, zAuditEscalationView, zTerminalSession, zDocFileContent, zDocIndexCat, zDocIndex, HOST_RE, USER_RE, zCreateVps, zPatchVps, zLogin, zSignup, zChangePassword, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, zStackFrame, zSymbolicatedFrame, zSourceMapUpload, zIngestPayload, zErrorGroupView, zErrorEventView, zErrorGroupDetail, zIngestKeyView, zTicketView, zTicketAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus;
4591
+ var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zCreateLink, zUpdateProject, zCreateSpec, zPatchSpec, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerState, zFlow, zPrdBrief, zPrdDoc, zBreakdownItem, zBreakdownDoc, zBatchCreateSpec, zEscalationTarget, zEscalationPrefill, zAuditEscalation, zAuditEscalationView, zTerminalSession, zDocFileContent, zDocIndexCat, zDocIndex, HOST_RE, USER_RE, zCreateVps, zPatchVps, zLogin, zSignup, zChangePassword, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, UPDATE_RESTART_EXIT, zUpdateApplyBody, zStackFrame, zSymbolicatedFrame, zSourceMapUpload, zIngestPayload, zErrorGroupView, zErrorEventView, zErrorGroupDetail, zIngestKeyView, zTicketView, zTicketAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus;
4903
4592
  var init_dto = __esm({
4904
4593
  "../shared/src/dto.ts"() {
4905
4594
  "use strict";
@@ -4968,11 +4657,12 @@ var init_dto = __esm({
4968
4657
  source: zSpecSource,
4969
4658
  title: external_exports.string().min(1),
4970
4659
  priority: zPriority,
4971
- payload: external_exports.union([zBriefPayload, zQaPayload]),
4660
+ payload: external_exports.union([zBriefPayload, zQaPayload, zGoalPayload]),
4972
4661
  branchFrom: external_exports.string().min(1).optional()
4973
4662
  }).superRefine((o, ctx) => {
4974
- const isQa = "severity" in o.payload;
4975
- if (o.source === "qa" !== isQa)
4663
+ const shape = "severity" in o.payload ? "qa" : "goal" in o.payload ? "goal" : "brief";
4664
+ const want = o.source === "qa" ? "qa" : o.source === "goal" ? "goal" : "brief";
4665
+ if (shape !== want)
4976
4666
  ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["payload"], message: "bentuk payload tak cocok dengan source" });
4977
4667
  });
4978
4668
  zPatchSpec = external_exports.object({
@@ -4982,7 +4672,8 @@ var init_dto = __esm({
4982
4672
  // SPEC-186 · edit konten selagi item belum dimulai. Ditolak server bila sudah mulai.
4983
4673
  title: external_exports.string().min(1).optional(),
4984
4674
  priority: zPriority.optional(),
4985
- payload: external_exports.union([zBriefPayload, zQaPayload]).optional()
4675
+ payload: external_exports.union([zBriefPayload, zQaPayload, zGoalPayload]).optional()
4676
+ // SPEC-407 · +goal
4986
4677
  });
4987
4678
  zIntegrate = external_exports.object({
4988
4679
  op: external_exports.enum(["merge", "rebase"]),
@@ -5047,7 +4738,7 @@ var init_dto = __esm({
5047
4738
  queue: external_exports.array(zSchedulerQueueItem),
5048
4739
  sessions: external_exports.array(zSchedulerSessionView)
5049
4740
  });
5050
- zFlow = external_exports.enum(["feature", "qa", "scaffold", "reverse", "prd", "audit", "breakdown", "cross-audit"]);
4741
+ zFlow = external_exports.enum(["feature", "qa", "scaffold", "reverse", "prd", "audit", "breakdown", "cross-audit", "goal"]);
5051
4742
  zPrdBrief = external_exports.object({
5052
4743
  title: external_exports.string().min(1),
5053
4744
  context: external_exports.string(),
@@ -5193,6 +4884,8 @@ var init_dto = __esm({
5193
4884
  });
5194
4885
  zAttest = external_exports.object({ note: external_exports.string().max(500).optional() });
5195
4886
  zRemediate = external_exports.object({ items: external_exports.array(external_exports.string()).min(1).max(64) });
4887
+ UPDATE_RESTART_EXIT = 75;
4888
+ zUpdateApplyBody = external_exports.object({ confirm: external_exports.boolean().optional() });
5196
4889
  zStackFrame = external_exports.object({
5197
4890
  function: external_exports.string().max(500).optional(),
5198
4891
  filename: external_exports.string().max(2e3).optional(),
@@ -5303,515 +4996,933 @@ var init_dto = __esm({
5303
4996
  createdAt: external_exports.string()
5304
4997
  });
5305
4998
  }
5306
- });
5307
-
5308
- // ../shared/src/api.ts
5309
- var API, paths;
5310
- var init_api = __esm({
5311
- "../shared/src/api.ts"() {
4999
+ });
5000
+
5001
+ // ../shared/src/api.ts
5002
+ var API, paths;
5003
+ var init_api = __esm({
5004
+ "../shared/src/api.ts"() {
5005
+ "use strict";
5006
+ API = "/api";
5007
+ paths = {
5008
+ projects: `${API}/projects`,
5009
+ project: (id) => `${API}/projects/${id}`,
5010
+ // SPEC-255 · ADR-0064 · rename slug project (efek: DSN, Help Center, sync).
5011
+ projectRename: (id) => `${API}/projects/${encodeURIComponent(id)}/rename`,
5012
+ branches: (id) => `${API}/projects/${id}/branches`,
5013
+ // SPEC-360 · ADR-0077 · branch ter-merge (nilai turunan git) + hapus batch local/origin.
5014
+ branchesUnused: (id, base) => `${API}/projects/${id}/branches/unused${base ? `?base=${encodeURIComponent(base)}` : ""}`,
5015
+ branchesDelete: (id) => `${API}/projects/${id}/branches/delete`,
5016
+ // SPEC-217 · path per-mesin (LocalBinding, tak disync) + clone dari gitRemote
5017
+ binding: (id) => `${API}/projects/${id}/binding`,
5018
+ clone: (id) => `${API}/projects/${id}/clone`,
5019
+ specs: `${API}/specs`,
5020
+ spec: (id) => `${API}/specs/${id}`,
5021
+ specDocs: (id) => `${API}/specs/${id}/docs`,
5022
+ specDocFile: (id, path) => `${API}/specs/${id}/docs/${path}`,
5023
+ // SPEC-340 · ADR-0076 · rekomendasi tindak lanjut audit (turunan blok json dokumen audit).
5024
+ specEscalation: (id) => `${API}/specs/${id}/escalation`,
5025
+ specIntegrate: (id) => `${API}/specs/${id}/integrate`,
5026
+ specReview: (id) => `${API}/specs/${id}/review`,
5027
+ specReviewFile: (id, path) => `${API}/specs/${id}/review/${path}`,
5028
+ settings: `${API}/settings`,
5029
+ notifications: `${API}/notifications`,
5030
+ limits: `${API}/limits`,
5031
+ // SPEC-339 · versi codex CLI (peringatan lunak model GPT-5.6).
5032
+ codexVersion: `${API}/codex/version`,
5033
+ docs: (id) => `${API}/projects/${id}/docs`,
5034
+ docFile: (id, path) => `${API}/projects/${id}/docs/${path}`,
5035
+ // SPEC-210 · dokumen PRD project (freshest-wins: worktree sesi prd hidup > repoDir)
5036
+ prds: (id) => `${API}/projects/${id}/prds`,
5037
+ allPrds: `${API}/prds`,
5038
+ // perbaikan SPEC-210 · daftar PRD lintas-project (filter "Semua project")
5039
+ prdFile: (id, path) => `${API}/projects/${id}/prds/${path}`,
5040
+ // SPEC-273 · manifest breakdown sebuah PRD (freshest-wins) + materialize batch.
5041
+ breakdown: (id, prd) => `${API}/projects/${id}/breakdown?prd=${encodeURIComponent(prd)}`,
5042
+ specsBatch: `${API}/specs/batch`,
5043
+ // SPEC-182 · IDE Visual
5044
+ ideTree: (id, ref = "") => `${API}/projects/${id}/tree${ref ? `?ref=${encodeURIComponent(ref)}` : ""}`,
5045
+ ideFile: (id, path, ref = "") => `${API}/projects/${id}/file${path ? `?path=${encodeURIComponent(path)}${ref ? `&ref=${encodeURIComponent(ref)}` : ""}` : ""}`,
5046
+ ideGraph: (id, limit = 200, opts) => {
5047
+ const p = new URLSearchParams({ limit: String(limit) });
5048
+ if (opts?.branches?.length) p.set("branches", opts.branches.join(","));
5049
+ if (opts?.showRemote === false) p.set("showRemote", "false");
5050
+ if (opts?.showTags === false) p.set("showTags", "false");
5051
+ return `${API}/projects/${id}/graph?${p.toString()}`;
5052
+ },
5053
+ ideStatus: (id) => `${API}/projects/${id}/status`,
5054
+ // SPEC-233 · status working tree
5055
+ ideSearch: (id, q, by = "all") => `${API}/projects/${id}/graph/search?q=${encodeURIComponent(q)}&by=${by}`,
5056
+ // SPEC-233
5057
+ ideStashes: (id) => `${API}/projects/${id}/stashes`,
5058
+ // SPEC-233 · daftar stash
5059
+ // SPEC-233 · remote mgmt + pr-url + archive
5060
+ ideRemotes: (id) => `${API}/projects/${id}/remotes`,
5061
+ ideRemote: (id, name) => `${API}/projects/${id}/remotes/${encodeURIComponent(name)}`,
5062
+ idePrUrl: (id, branch, base) => `${API}/projects/${id}/pr-url?branch=${encodeURIComponent(branch)}${base ? `&base=${encodeURIComponent(base)}` : ""}`,
5063
+ ideArchive: (id, ref, format = "zip") => `${API}/projects/${id}/archive?ref=${encodeURIComponent(ref)}&format=${format}`,
5064
+ ideCommit: (id, sha) => `${API}/projects/${id}/commit/${sha}`,
5065
+ // SPEC-233 · diff satu file di commit (vs parent)
5066
+ ideCommitFile: (id, sha, path) => `${API}/projects/${id}/commit/${sha}/file?path=${encodeURIComponent(path)}`,
5067
+ // SPEC-233 · compare dua commit
5068
+ ideCompare: (id, from, to) => `${API}/projects/${id}/compare?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`,
5069
+ ideCompareFile: (id, from, to, path) => `${API}/projects/${id}/compare/file?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}&path=${encodeURIComponent(path)}`,
5070
+ ideGit: (id) => `${API}/projects/${id}/git`,
5071
+ ideGitMerge: (id) => `${API}/projects/${id}/git/merge`,
5072
+ // SPEC-229 · merge git graph isolasi
5073
+ // SPEC-234 · status working tree (staged/unstaged) + diff satu file working tree
5074
+ // catat: /working-status dibedakan dari /status milik SPEC-233 (repoStatus graph) — beda bentuk respons.
5075
+ ideWorkingStatus: (id) => `${API}/projects/${id}/working-status`,
5076
+ ideFileDiff: (id, path, staged) => `${API}/projects/${id}/file-diff?path=${encodeURIComponent(path)}${staged ? "&staged=1" : ""}`,
5077
+ ideGitRebase: (id) => `${API}/projects/${id}/git/rebase`,
5078
+ // SPEC-233 · rebase isolasi
5079
+ ideGitPull: (id) => `${API}/projects/${id}/git/pull`,
5080
+ // SPEC-233 · pull isolasi
5081
+ ideGitDrop: (id) => `${API}/projects/${id}/git/drop`,
5082
+ // SPEC-233 · drop commit isolasi
5083
+ fsBrowse: (path) => `${API}/fs/browse${path ? `?path=${encodeURIComponent(path)}` : ""}`,
5084
+ terminalSessions: `${API}/terminal/sessions`,
5085
+ terminalSession: (id) => `${API}/terminal/sessions/${id}`,
5086
+ terminalPhases: (id) => `${API}/terminal/sessions/${id}/phases`,
5087
+ // SPEC-230 · review + integrate ber-skop sesi (sesi project-level PRD, tanpa Spec).
5088
+ sessionReview: (id) => `${API}/terminal/sessions/${id}/review`,
5089
+ sessionReviewFile: (id, path) => `${API}/terminal/sessions/${id}/review/${path}`,
5090
+ sessionIntegrate: (id) => `${API}/terminal/sessions/${id}/integrate`,
5091
+ terminalWs: (id) => `${API}/terminal/sessions/${id}/ws`,
5092
+ // SPEC-362 · ADR-0079 · riwayat sesi. Di bawah prefix /terminal supaya ikut capability
5093
+ // `sessions` yang sudah ada (services/agent-capabilities.ts) tanpa menambah domain baru.
5094
+ sessionHistory: (qs = "") => `${API}/terminal/history${qs}`,
5095
+ sessionHistoryItem: (id) => `${API}/terminal/history/${encodeURIComponent(id)}`,
5096
+ sessionTranscript: (id) => `${API}/terminal/history/${encodeURIComponent(id)}/transcript`,
5097
+ eventsWs: `${API}/events/ws`,
5098
+ // SPEC-199 · WebSocket siar dashboard (global, bukan per-sesi)
5099
+ vps: `${API}/vps`,
5100
+ vpsOne: (id) => `${API}/vps/${id}`,
5101
+ vpsAudit: (id) => `${API}/vps/${id}/audit`,
5102
+ vpsHarden: (id) => `${API}/vps/${id}/harden`,
5103
+ vpsSession: (id) => `${API}/vps/${id}/session`,
5104
+ vpsTest: (id) => `${API}/vps/${id}/test`,
5105
+ vpsConsole: (id) => `${API}/vps/${id}/console`,
5106
+ // SPEC-220 · kepatuhan checklist
5107
+ vpsChecklist: (id) => `${API}/vps/${id}/checklist`,
5108
+ vpsItemNa: (id, itemId) => `${API}/vps/${id}/items/${itemId}/na`,
5109
+ vpsItemNaBulk: (id) => `${API}/vps/${id}/items/na-bulk`,
5110
+ vpsItemAttest: (id, itemId) => `${API}/vps/${id}/items/${itemId}/attest`,
5111
+ vpsRemediatePreview: (id) => `${API}/vps/${id}/remediate/preview`,
5112
+ vpsRemediate: (id) => `${API}/vps/${id}/remediate`,
5113
+ // SPEC-169 · auth
5114
+ authStatus: `${API}/auth/status`,
5115
+ authSetup: `${API}/auth/setup`,
5116
+ authLogin: `${API}/auth/login`,
5117
+ authLogout: `${API}/auth/logout`,
5118
+ authUsers: `${API}/auth/users`,
5119
+ authUser: (id) => `${API}/auth/users/${id}`,
5120
+ authChangePassword: `${API}/auth/change-password`,
5121
+ // SPEC-213 · device token + activity log
5122
+ deviceTokens: `${API}/device-tokens`,
5123
+ deviceToken: (id) => `${API}/device-tokens/${id}`,
5124
+ sessionResults: (projectId) => `${API}/session-results${projectId ? `?projectId=${encodeURIComponent(projectId)}` : ""}`,
5125
+ // SPEC-215 · config runtime
5126
+ config: `${API}/config`,
5127
+ configKey: (key) => `${API}/config/${encodeURIComponent(key)}`,
5128
+ // SPEC-299 · panel scheduler (daun #6) — konsumen read-only fondasi SPEC-294/ADR-0072.
5129
+ schedulerConfig: `${API}/scheduler/config`,
5130
+ schedulerState: `${API}/scheduler/state`,
5131
+ // SPEC-268 · ADR-0066 · pemicu sync manual (cookie-authed)
5132
+ syncNow: `${API}/sync/now`,
5133
+ // SPEC-270 · ADR-0067 · antrean konflik rekonsil (cookie-authed)
5134
+ syncConflicts: `${API}/sync/conflicts`,
5135
+ syncConflictResolve: (entity, recordId) => `${API}/sync/conflicts/${encodeURIComponent(entity)}/${encodeURIComponent(recordId)}/resolve`,
5136
+ // SPEC-257 · ADR-0065 · agent token (kelola cookie-only) + katalog capability
5137
+ agentTokens: `${API}/agent-tokens`,
5138
+ agentToken: (id) => `${API}/agent-tokens/${id}`,
5139
+ agentCapabilities: `${API}/agent-tokens/capabilities`,
5140
+ // SPEC-249 · error monitoring. ingest publik ber-DSN (bypass gate cookie, ADR-0060).
5141
+ ingest: (slug) => `${API}/ingest/${encodeURIComponent(slug)}`,
5142
+ errors: `${API}/errors`,
5143
+ errorsGuide: `${API}/errors/integration-guide`,
5144
+ error: (id) => `${API}/errors/${id}`,
5145
+ errorEscalate: (id) => `${API}/errors/${id}/escalate`,
5146
+ errorUnlink: (id) => `${API}/errors/${id}/unlink`,
5147
+ // SPEC-271 · lepas tautan backlog
5148
+ projectIngestKey: (id) => `${API}/projects/${encodeURIComponent(id)}/ingest-key`,
5149
+ // SPEC-253 · Help Center publik (bypass gate cookie; otorisasi helpEnabled + kunci opaque tiket).
5150
+ help: (slug) => `${API}/help/${encodeURIComponent(slug)}`,
5151
+ helpTickets: (slug) => `${API}/help/${encodeURIComponent(slug)}/tickets`,
5152
+ helpStatus: (slug, key) => `${API}/help/${encodeURIComponent(slug)}/tickets/${encodeURIComponent(key)}`,
5153
+ // SPEC-253 · triase (di belakang gate cookie)
5154
+ projectHelpCenter: (id) => `${API}/projects/${encodeURIComponent(id)}/help-center`,
5155
+ tickets: `${API}/tickets`,
5156
+ ticket: (id) => `${API}/tickets/${id}`,
5157
+ ticketAttachment: (id, attId) => `${API}/tickets/${id}/attachments/${attId}`,
5158
+ ticketAccept: (id) => `${API}/tickets/${id}/accept`,
5159
+ ticketUnlink: (id) => `${API}/tickets/${id}/unlink`,
5160
+ // SPEC-271 · lepas tautan backlog
5161
+ ticketReject: (id) => `${API}/tickets/${id}/reject`,
5162
+ // SPEC-337 · ADR-0075 · relasi integrasi antar project (LOCAL-only) + log lintas project.
5163
+ projectLinks: (id) => `${API}/projects/${encodeURIComponent(id)}/links`,
5164
+ projectLink: (id, linkId) => `${API}/projects/${encodeURIComponent(id)}/links/${encodeURIComponent(linkId)}`,
5165
+ // SPEC-361 · ADR-0078 · unduh dokumen: query ditempelkan ke URL endpoint dokumen yang sudah ada
5166
+ // (tak ada endpoint ekspor terpisah). `base` bisa sudah membawa query, mis. ideFile(?path=…).
5167
+ download: (base, fmt) => `${base}${base.includes("?") ? "&" : "?"}download=${fmt}`
5168
+ };
5169
+ }
5170
+ });
5171
+
5172
+ // ../shared/src/coverage.ts
5173
+ function coverageOf(docs) {
5174
+ const byCat = /* @__PURE__ */ new Map();
5175
+ for (const d of docs) byCat.set(d.category, (byCat.get(d.category) ?? true) && d.linked);
5176
+ if (byCat.size === 0) return 0;
5177
+ const linked = [...byCat.values()].filter(Boolean).length;
5178
+ return Math.round(linked / byCat.size * 100);
5179
+ }
5180
+ function isExternalLink(target) {
5181
+ return !target || /^(https?:|#|mailto:)/.test(target);
5182
+ }
5183
+ function resolveLink(fromRel, target) {
5184
+ const clean = target.trim().split(/\s+/)[0].split("#")[0].split("\\").join("/");
5185
+ if (!clean) return "";
5186
+ if (clean.startsWith("/")) return clean.slice(1).split("/").filter((p) => p && p !== ".").join("/");
5187
+ const dir = fromRel.includes("/") ? fromRel.slice(0, fromRel.lastIndexOf("/")) : "";
5188
+ const parts = (dir ? dir.split("/") : []).concat(clean.replace(/^\.\//, "").split("/"));
5189
+ const out = [];
5190
+ for (const p of parts) {
5191
+ if (p === "" || p === ".") continue;
5192
+ if (p === "..") out.pop();
5193
+ else out.push(p);
5194
+ }
5195
+ return out.join("/");
5196
+ }
5197
+ function linkedSetFrom(indexRel, docs, read) {
5198
+ const inCorpus = new Set(docs);
5199
+ const seen = /* @__PURE__ */ new Set();
5200
+ const queue = [indexRel];
5201
+ let i = 0;
5202
+ while (i < queue.length) {
5203
+ const cur = queue[i++];
5204
+ if (seen.has(cur)) continue;
5205
+ seen.add(cur);
5206
+ const md = read(cur);
5207
+ if (md === null) continue;
5208
+ for (const m of md.matchAll(LINK_RE)) {
5209
+ const target = m[1].trim();
5210
+ if (isExternalLink(target)) continue;
5211
+ const rel = resolveLink(cur, target);
5212
+ if (rel && inCorpus.has(rel) && !seen.has(rel)) queue.push(rel);
5213
+ }
5214
+ }
5215
+ return new Set([...seen].filter((p) => inCorpus.has(p)));
5216
+ }
5217
+ var LINK_RE;
5218
+ var init_coverage = __esm({
5219
+ "../shared/src/coverage.ts"() {
5220
+ "use strict";
5221
+ LINK_RE = /\]\(([^)]+)\)/g;
5222
+ }
5223
+ });
5224
+
5225
+ // ../shared/src/ticket-status.ts
5226
+ var init_ticket_status = __esm({
5227
+ "../shared/src/ticket-status.ts"() {
5228
+ "use strict";
5229
+ }
5230
+ });
5231
+
5232
+ // ../shared/src/session-kind.ts
5233
+ var SESSION_KINDS, zSessionKind;
5234
+ var init_session_kind = __esm({
5235
+ "../shared/src/session-kind.ts"() {
5236
+ "use strict";
5237
+ init_zod();
5238
+ SESSION_KINDS = [
5239
+ "spec",
5240
+ "reverse",
5241
+ "prd",
5242
+ "scaffold",
5243
+ "breakdown",
5244
+ "cross-audit",
5245
+ "vps",
5246
+ "shell",
5247
+ "worktree",
5248
+ "terminal"
5249
+ ];
5250
+ zSessionKind = external_exports.enum(SESSION_KINDS);
5251
+ }
5252
+ });
5253
+
5254
+ // ../shared/src/config.ts
5255
+ var zHanomanConfig;
5256
+ var init_config = __esm({
5257
+ "../shared/src/config.ts"() {
5258
+ "use strict";
5259
+ init_zod();
5260
+ zHanomanConfig = external_exports.object({
5261
+ docsDir: external_exports.string().default("internal/docs")
5262
+ });
5263
+ }
5264
+ });
5265
+
5266
+ // ../shared/src/config-registry.ts
5267
+ var CONFIG_REGISTRY, BY_KEY;
5268
+ var init_config_registry = __esm({
5269
+ "../shared/src/config-registry.ts"() {
5270
+ "use strict";
5271
+ CONFIG_REGISTRY = [
5272
+ // sync
5273
+ {
5274
+ key: "SYNC_SERVER_URL",
5275
+ group: "sync",
5276
+ label: "URL hub",
5277
+ kind: "url",
5278
+ apply: "live",
5279
+ category: "knob",
5280
+ help: "Base URL hub tujuan sync (REST + WS). Kosong = instance ini murni HUB."
5281
+ },
5282
+ {
5283
+ key: "SYNC_DEVICE_TOKEN",
5284
+ group: "sync",
5285
+ label: "Device token",
5286
+ kind: "secret",
5287
+ apply: "live",
5288
+ category: "credential",
5289
+ help: "Token yang diterbitkan hub (tab Perangkat di hub). Dikirim sebagai Bearer."
5290
+ },
5291
+ {
5292
+ key: "SYNC_TICK_MS",
5293
+ group: "sync",
5294
+ label: "Interval sync (ms)",
5295
+ kind: "int",
5296
+ apply: "live",
5297
+ category: "knob",
5298
+ default: "15000",
5299
+ min: 1e3
5300
+ },
5301
+ // claude
5302
+ {
5303
+ key: "CLAUDE_CODE_OAUTH_TOKEN",
5304
+ group: "claude",
5305
+ label: "Claude OAuth token",
5306
+ kind: "secret",
5307
+ apply: "new-session",
5308
+ category: "credential",
5309
+ inheritEnv: true,
5310
+ help: "Token `claude setup-token`. Diwarisi proses claude yang di-spawn."
5311
+ },
5312
+ { key: "ANTHROPIC_API_KEY", group: "claude", label: "Anthropic API key", kind: "secret", apply: "new-session", category: "credential", inheritEnv: true },
5313
+ { key: "HANOMAN_CLAUDE_BIN", group: "claude", label: "Biner claude", kind: "path", apply: "new-session", category: "knob", default: "claude" },
5314
+ // codex (SPEC-338 · ADR-0074)
5315
+ { key: "HANOMAN_CODEX_BIN", group: "claude", label: "Biner codex", kind: "path", apply: "new-session", category: "knob", default: "codex" },
5316
+ {
5317
+ key: "CLAUDE_CONFIG_DIR",
5318
+ group: "claude",
5319
+ label: "Dir config Claude",
5320
+ kind: "path",
5321
+ apply: "new-session",
5322
+ category: "knob",
5323
+ help: "Default ~/.claude. Sumber .credentials.json untuk panel usage/limit."
5324
+ },
5325
+ // vps
5326
+ { key: "HANOMAN_SSH_KEY_DIR", group: "vps", label: "Dir key SSH", kind: "path", apply: "new-session", category: "knob", help: "Default ~/.hanoman." },
5327
+ { key: "HANOMAN_SSH_BIN", group: "vps", label: "Biner ssh", kind: "path", apply: "new-session", category: "knob", default: "ssh" },
5328
+ // runtime
5329
+ { key: "HANOMAN_EVENTS_TICK_MS", group: "runtime", label: "Interval events (ms)", kind: "int", apply: "live", category: "knob", default: "1000", min: 100 },
5330
+ { key: "HANOMAN_UPDATE_FETCH", group: "runtime", label: "Deteksi update saat boot", kind: "bool", apply: "live", category: "knob", default: "1" },
5331
+ // SPEC-398 · ADR-0087 · deteksi update kini membandingkan semver dengan registry npm, bukan
5332
+ // menghitung commit di repo git (HANOMAN_REPO_ROOT dicabut bersama jalur git itu).
5333
+ {
5334
+ key: "HANOMAN_NPM_REGISTRY",
5335
+ group: "runtime",
5336
+ label: "Registry npm",
5337
+ kind: "string",
5338
+ apply: "live",
5339
+ category: "knob",
5340
+ default: "https://registry.npmjs.org",
5341
+ help: "Sumber versi terbaru paket `hanoman`."
5342
+ },
5343
+ {
5344
+ key: "HANOMAN_TMUX_SOCKET",
5345
+ group: "runtime",
5346
+ label: "Socket tmux",
5347
+ kind: "string",
5348
+ apply: "restart",
5349
+ category: "knob",
5350
+ default: "hanoman",
5351
+ help: "Mengubah ini TIDAK memindahkan sesi tmux yang sudah hidup \u2014 berlaku setelah restart."
5352
+ },
5353
+ // gitGraph (SPEC-233 · preferensi tampilan git graph; semua live, dikonsumsi client)
5354
+ { key: "gitGraph.style", group: "gitGraph", label: "Gaya graph", kind: "string", apply: "live", category: "knob", default: "rounded", help: "rounded | angular" },
5355
+ { key: "gitGraph.colours", group: "gitGraph", label: "Warna lane (CSV)", kind: "string", apply: "live", category: "knob", help: "Daftar warna hex dipisah koma; kosong = palet bawaan." },
5356
+ { key: "gitGraph.dateType", group: "gitGraph", label: "Jenis tanggal", kind: "string", apply: "live", category: "knob", default: "author", help: "author | commit" },
5357
+ { key: "gitGraph.commitsInitialLoad", group: "gitGraph", label: "Muat awal", kind: "int", apply: "live", category: "knob", default: "200", min: 1 },
5358
+ { key: "gitGraph.commitsLoadMore", group: "gitGraph", label: "Muat lagi", kind: "int", apply: "live", category: "knob", default: "100", min: 1 },
5359
+ { key: "gitGraph.showRemoteBranches", group: "gitGraph", label: "Tampilkan remote", kind: "bool", apply: "live", category: "knob", default: "1" },
5360
+ { key: "gitGraph.showTags", group: "gitGraph", label: "Tampilkan tag", kind: "bool", apply: "live", category: "knob", default: "1" },
5361
+ { key: "gitGraph.showStashes", group: "gitGraph", label: "Tampilkan stash", kind: "bool", apply: "live", category: "knob", default: "1" },
5362
+ { key: "gitGraph.showUncommitted", group: "gitGraph", label: "Tampilkan uncommitted", kind: "bool", apply: "live", category: "knob", default: "1" },
5363
+ { key: "gitGraph.muteMergeCommits", group: "gitGraph", label: "Redupkan merge commit", kind: "bool", apply: "live", category: "knob", default: "1" },
5364
+ { key: "gitGraph.fetchAvatars", group: "gitGraph", label: "Ambil avatar (gravatar)", kind: "bool", apply: "live", category: "knob", default: "0", help: "Jaringan eksternal ke gravatar.com." },
5365
+ { key: "gitGraph.combineLocalRemote", group: "gitGraph", label: "Gabung label local+remote", kind: "bool", apply: "live", category: "knob", default: "0" },
5366
+ { key: "gitGraph.markdown", group: "gitGraph", label: "Render markdown pesan", kind: "bool", apply: "live", category: "knob", default: "1" },
5367
+ { key: "gitGraph.emoji", group: "gitGraph", label: "Render emoji shortcode", kind: "bool", apply: "live", category: "knob", default: "1" },
5368
+ { key: "gitGraph.issueLinkPattern", group: "gitGraph", label: "Pola link issue", kind: "string", apply: "live", category: "knob", help: "URL dengan $1 untuk nomor issue, mis. https://github.com/acme/app/issues/$1" },
5369
+ // bootstrap (read-only)
5370
+ { key: "DATABASE_URL", group: "bootstrap", label: "DATABASE_URL", kind: "secret", apply: "restart", category: "bootstrap" },
5371
+ { key: "TEST_DATABASE_URL", group: "bootstrap", label: "TEST_DATABASE_URL", kind: "secret", apply: "restart", category: "bootstrap" },
5372
+ { key: "PORT", group: "bootstrap", label: "PORT", kind: "int", apply: "restart", category: "bootstrap", default: "8787" },
5373
+ { key: "HOST", group: "bootstrap", label: "HOST", kind: "string", apply: "restart", category: "bootstrap", default: "127.0.0.1" },
5374
+ { key: "NODE_ENV", group: "bootstrap", label: "NODE_ENV", kind: "string", apply: "restart", category: "bootstrap" },
5375
+ // SPEC-398 · ADR-0086/0087 · lokasi data & aset, dibaca sekali saat boot (CLI yang menyetelnya).
5376
+ { key: "HANOMAN_HOME", group: "bootstrap", label: "HANOMAN_HOME", kind: "path", apply: "restart", category: "bootstrap" },
5377
+ { key: "HANOMAN_WEB_DIR", group: "bootstrap", label: "HANOMAN_WEB_DIR", kind: "path", apply: "restart", category: "bootstrap" }
5378
+ ];
5379
+ BY_KEY = new Map(CONFIG_REGISTRY.map((e) => [e.key, e]));
5380
+ }
5381
+ });
5382
+
5383
+ // ../shared/src/semver.ts
5384
+ function parse(v) {
5385
+ const m = RE.exec(v.trim());
5386
+ return m ? { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ?? null } : null;
5387
+ }
5388
+ function preKey(pre) {
5389
+ return pre.split(".").map((s) => /^\d+$/.test(s) ? s.padStart(12, "0") : s).join(".");
5390
+ }
5391
+ function compareSemver(a, b) {
5392
+ const pa = parse(a), pb = parse(b);
5393
+ if (!pa || !pb) return 0;
5394
+ for (let i = 0; i < 3; i++) {
5395
+ const d = pa.nums[i] - pb.nums[i];
5396
+ if (d !== 0) return d < 0 ? -1 : 1;
5397
+ }
5398
+ if (pa.pre === pb.pre) return 0;
5399
+ if (pa.pre === null) return 1;
5400
+ if (pb.pre === null) return -1;
5401
+ const ka = preKey(pa.pre), kb = preKey(pb.pre);
5402
+ return ka < kb ? -1 : ka > kb ? 1 : 0;
5403
+ }
5404
+ var RE;
5405
+ var init_semver = __esm({
5406
+ "../shared/src/semver.ts"() {
5407
+ "use strict";
5408
+ RE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/;
5409
+ }
5410
+ });
5411
+
5412
+ // ../shared/src/index.ts
5413
+ var init_src2 = __esm({
5414
+ "../shared/src/index.ts"() {
5415
+ "use strict";
5416
+ init_enums();
5417
+ init_entities();
5418
+ init_agent();
5419
+ init_dto();
5420
+ init_api();
5421
+ init_coverage();
5422
+ init_ticket_status();
5423
+ init_session_kind();
5424
+ init_config();
5425
+ init_config_registry();
5426
+ init_semver();
5427
+ }
5428
+ });
5429
+
5430
+ // src/layout.ts
5431
+ import { join as join2, resolve as resolve2 } from "node:path";
5432
+ function resolveLayout(distDir2, exists) {
5433
+ const pkg = resolve2(distDir2, "..");
5434
+ if (exists(join2(pkg, "prisma", "schema.prisma"))) {
5435
+ return {
5436
+ root: pkg,
5437
+ schema: join2(pkg, "prisma", "schema.prisma"),
5438
+ server: join2(pkg, "dist", "server.js"),
5439
+ web: exists(join2(pkg, "web")) ? join2(pkg, "web") : null
5440
+ };
5441
+ }
5442
+ const repo = resolve2(distDir2, "../..");
5443
+ if (exists(join2(repo, "server", "prisma", "schema.prisma"))) {
5444
+ return {
5445
+ root: repo,
5446
+ schema: join2(repo, "server", "prisma", "schema.prisma"),
5447
+ server: join2(repo, "server", "dist", "server.js"),
5448
+ web: exists(join2(repo, "src", "dist")) ? join2(repo, "src", "dist") : null
5449
+ };
5450
+ }
5451
+ throw new Error(`hanoman: prisma/schema.prisma tak ditemukan dari ${distDir2} \u2014 instalasi rusak?`);
5452
+ }
5453
+ var init_layout = __esm({
5454
+ "src/layout.ts"() {
5455
+ "use strict";
5456
+ }
5457
+ });
5458
+
5459
+ // src/commands/update.ts
5460
+ var update_exports = {};
5461
+ __export(update_exports, {
5462
+ INSTALL_ARGS: () => INSTALL_ARGS,
5463
+ PKG: () => PKG,
5464
+ default: () => update,
5465
+ planUpdate: () => planUpdate
5466
+ });
5467
+ import { execFileSync } from "node:child_process";
5468
+ function planUpdate(current, latest) {
5469
+ if (!latest) return { action: "unknown", current, latest: null };
5470
+ return compareSemver(latest, current) > 0 ? { action: "install", current, latest } : { action: "up-to-date", current, latest };
5471
+ }
5472
+ async function latestVersion(registry) {
5473
+ try {
5474
+ const res = await fetch(`${registry.replace(/\/+$/, "")}/${PKG}/latest`, { signal: AbortSignal.timeout(1e4) });
5475
+ if (!res.ok) return null;
5476
+ const body = await res.json();
5477
+ return typeof body.version === "string" ? body.version : null;
5478
+ } catch {
5479
+ return null;
5480
+ }
5481
+ }
5482
+ async function update(argv, ctx) {
5483
+ const check = argv.includes("--check");
5484
+ const current = currentVersion();
5485
+ const latest = await latestVersion(ctx.env.HANOMAN_NPM_REGISTRY ?? DEFAULT_REGISTRY);
5486
+ const plan = planUpdate(current, latest);
5487
+ if (plan.action === "unknown") {
5488
+ ctx.stderr(`hanoman ${current} \xB7 registry npm tak terjangkau \u2014 coba lagi nanti
5489
+ `);
5490
+ return 1;
5491
+ }
5492
+ if (plan.action === "up-to-date") {
5493
+ ctx.stdout(`hanoman ${current} sudah terkini
5494
+ `);
5495
+ return 0;
5496
+ }
5497
+ ctx.stdout(`hanoman ${plan.current} \u2192 ${plan.latest}
5498
+ `);
5499
+ if (check) {
5500
+ ctx.stdout(`jalankan: npm ${INSTALL_ARGS.join(" ")}
5501
+ `);
5502
+ return 0;
5503
+ }
5504
+ try {
5505
+ execFileSync("npm", [...INSTALL_ARGS], { stdio: "inherit" });
5506
+ } catch {
5507
+ ctx.stderr("npm i -g gagal \u2014 jalankan manual (mungkin butuh sudo)\n");
5508
+ return 1;
5509
+ }
5510
+ ctx.stdout(`terpasang hanoman ${plan.latest} \xB7 restart instance yang berjalan
5511
+ `);
5512
+ return 0;
5513
+ }
5514
+ var PKG, INSTALL_ARGS, DEFAULT_REGISTRY;
5515
+ var init_update = __esm({
5516
+ "src/commands/update.ts"() {
5312
5517
  "use strict";
5313
- API = "/api";
5314
- paths = {
5315
- projects: `${API}/projects`,
5316
- project: (id) => `${API}/projects/${id}`,
5317
- // SPEC-255 · ADR-0064 · rename slug project (efek: DSN, Help Center, sync).
5318
- projectRename: (id) => `${API}/projects/${encodeURIComponent(id)}/rename`,
5319
- branches: (id) => `${API}/projects/${id}/branches`,
5320
- // SPEC-360 · ADR-0077 · branch ter-merge (nilai turunan git) + hapus batch local/origin.
5321
- branchesUnused: (id, base) => `${API}/projects/${id}/branches/unused${base ? `?base=${encodeURIComponent(base)}` : ""}`,
5322
- branchesDelete: (id) => `${API}/projects/${id}/branches/delete`,
5323
- // SPEC-217 · path per-mesin (LocalBinding, tak disync) + clone dari gitRemote
5324
- binding: (id) => `${API}/projects/${id}/binding`,
5325
- clone: (id) => `${API}/projects/${id}/clone`,
5326
- specs: `${API}/specs`,
5327
- spec: (id) => `${API}/specs/${id}`,
5328
- specDocs: (id) => `${API}/specs/${id}/docs`,
5329
- specDocFile: (id, path) => `${API}/specs/${id}/docs/${path}`,
5330
- // SPEC-340 · ADR-0076 · rekomendasi tindak lanjut audit (turunan blok json dokumen audit).
5331
- specEscalation: (id) => `${API}/specs/${id}/escalation`,
5332
- specIntegrate: (id) => `${API}/specs/${id}/integrate`,
5333
- specReview: (id) => `${API}/specs/${id}/review`,
5334
- specReviewFile: (id, path) => `${API}/specs/${id}/review/${path}`,
5335
- settings: `${API}/settings`,
5336
- notifications: `${API}/notifications`,
5337
- limits: `${API}/limits`,
5338
- // SPEC-339 · versi codex CLI (peringatan lunak model GPT-5.6).
5339
- codexVersion: `${API}/codex/version`,
5340
- docs: (id) => `${API}/projects/${id}/docs`,
5341
- docFile: (id, path) => `${API}/projects/${id}/docs/${path}`,
5342
- // SPEC-210 · dokumen PRD project (freshest-wins: worktree sesi prd hidup > repoDir)
5343
- prds: (id) => `${API}/projects/${id}/prds`,
5344
- allPrds: `${API}/prds`,
5345
- // perbaikan SPEC-210 · daftar PRD lintas-project (filter "Semua project")
5346
- prdFile: (id, path) => `${API}/projects/${id}/prds/${path}`,
5347
- // SPEC-273 · manifest breakdown sebuah PRD (freshest-wins) + materialize batch.
5348
- breakdown: (id, prd) => `${API}/projects/${id}/breakdown?prd=${encodeURIComponent(prd)}`,
5349
- specsBatch: `${API}/specs/batch`,
5350
- // SPEC-182 · IDE Visual
5351
- ideTree: (id, ref = "") => `${API}/projects/${id}/tree${ref ? `?ref=${encodeURIComponent(ref)}` : ""}`,
5352
- ideFile: (id, path, ref = "") => `${API}/projects/${id}/file${path ? `?path=${encodeURIComponent(path)}${ref ? `&ref=${encodeURIComponent(ref)}` : ""}` : ""}`,
5353
- ideGraph: (id, limit = 200, opts) => {
5354
- const p = new URLSearchParams({ limit: String(limit) });
5355
- if (opts?.branches?.length) p.set("branches", opts.branches.join(","));
5356
- if (opts?.showRemote === false) p.set("showRemote", "false");
5357
- if (opts?.showTags === false) p.set("showTags", "false");
5358
- return `${API}/projects/${id}/graph?${p.toString()}`;
5359
- },
5360
- ideStatus: (id) => `${API}/projects/${id}/status`,
5361
- // SPEC-233 · status working tree
5362
- ideSearch: (id, q, by = "all") => `${API}/projects/${id}/graph/search?q=${encodeURIComponent(q)}&by=${by}`,
5363
- // SPEC-233
5364
- ideStashes: (id) => `${API}/projects/${id}/stashes`,
5365
- // SPEC-233 · daftar stash
5366
- // SPEC-233 · remote mgmt + pr-url + archive
5367
- ideRemotes: (id) => `${API}/projects/${id}/remotes`,
5368
- ideRemote: (id, name) => `${API}/projects/${id}/remotes/${encodeURIComponent(name)}`,
5369
- idePrUrl: (id, branch, base) => `${API}/projects/${id}/pr-url?branch=${encodeURIComponent(branch)}${base ? `&base=${encodeURIComponent(base)}` : ""}`,
5370
- ideArchive: (id, ref, format = "zip") => `${API}/projects/${id}/archive?ref=${encodeURIComponent(ref)}&format=${format}`,
5371
- ideCommit: (id, sha) => `${API}/projects/${id}/commit/${sha}`,
5372
- // SPEC-233 · diff satu file di commit (vs parent)
5373
- ideCommitFile: (id, sha, path) => `${API}/projects/${id}/commit/${sha}/file?path=${encodeURIComponent(path)}`,
5374
- // SPEC-233 · compare dua commit
5375
- ideCompare: (id, from, to) => `${API}/projects/${id}/compare?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`,
5376
- ideCompareFile: (id, from, to, path) => `${API}/projects/${id}/compare/file?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}&path=${encodeURIComponent(path)}`,
5377
- ideGit: (id) => `${API}/projects/${id}/git`,
5378
- ideGitMerge: (id) => `${API}/projects/${id}/git/merge`,
5379
- // SPEC-229 · merge git graph isolasi
5380
- // SPEC-234 · status working tree (staged/unstaged) + diff satu file working tree
5381
- // catat: /working-status dibedakan dari /status milik SPEC-233 (repoStatus graph) — beda bentuk respons.
5382
- ideWorkingStatus: (id) => `${API}/projects/${id}/working-status`,
5383
- ideFileDiff: (id, path, staged) => `${API}/projects/${id}/file-diff?path=${encodeURIComponent(path)}${staged ? "&staged=1" : ""}`,
5384
- ideGitRebase: (id) => `${API}/projects/${id}/git/rebase`,
5385
- // SPEC-233 · rebase isolasi
5386
- ideGitPull: (id) => `${API}/projects/${id}/git/pull`,
5387
- // SPEC-233 · pull isolasi
5388
- ideGitDrop: (id) => `${API}/projects/${id}/git/drop`,
5389
- // SPEC-233 · drop commit isolasi
5390
- fsBrowse: (path) => `${API}/fs/browse${path ? `?path=${encodeURIComponent(path)}` : ""}`,
5391
- terminalSessions: `${API}/terminal/sessions`,
5392
- terminalSession: (id) => `${API}/terminal/sessions/${id}`,
5393
- terminalPhases: (id) => `${API}/terminal/sessions/${id}/phases`,
5394
- // SPEC-230 · review + integrate ber-skop sesi (sesi project-level PRD, tanpa Spec).
5395
- sessionReview: (id) => `${API}/terminal/sessions/${id}/review`,
5396
- sessionReviewFile: (id, path) => `${API}/terminal/sessions/${id}/review/${path}`,
5397
- sessionIntegrate: (id) => `${API}/terminal/sessions/${id}/integrate`,
5398
- terminalWs: (id) => `${API}/terminal/sessions/${id}/ws`,
5399
- // SPEC-362 · ADR-0079 · riwayat sesi. Di bawah prefix /terminal supaya ikut capability
5400
- // `sessions` yang sudah ada (services/agent-capabilities.ts) tanpa menambah domain baru.
5401
- sessionHistory: (qs = "") => `${API}/terminal/history${qs}`,
5402
- sessionHistoryItem: (id) => `${API}/terminal/history/${encodeURIComponent(id)}`,
5403
- sessionTranscript: (id) => `${API}/terminal/history/${encodeURIComponent(id)}/transcript`,
5404
- eventsWs: `${API}/events/ws`,
5405
- // SPEC-199 · WebSocket siar dashboard (global, bukan per-sesi)
5406
- vps: `${API}/vps`,
5407
- vpsOne: (id) => `${API}/vps/${id}`,
5408
- vpsAudit: (id) => `${API}/vps/${id}/audit`,
5409
- vpsHarden: (id) => `${API}/vps/${id}/harden`,
5410
- vpsSession: (id) => `${API}/vps/${id}/session`,
5411
- vpsTest: (id) => `${API}/vps/${id}/test`,
5412
- vpsConsole: (id) => `${API}/vps/${id}/console`,
5413
- // SPEC-220 · kepatuhan checklist
5414
- vpsChecklist: (id) => `${API}/vps/${id}/checklist`,
5415
- vpsItemNa: (id, itemId) => `${API}/vps/${id}/items/${itemId}/na`,
5416
- vpsItemNaBulk: (id) => `${API}/vps/${id}/items/na-bulk`,
5417
- vpsItemAttest: (id, itemId) => `${API}/vps/${id}/items/${itemId}/attest`,
5418
- vpsRemediatePreview: (id) => `${API}/vps/${id}/remediate/preview`,
5419
- vpsRemediate: (id) => `${API}/vps/${id}/remediate`,
5420
- // SPEC-169 · auth
5421
- authStatus: `${API}/auth/status`,
5422
- authSetup: `${API}/auth/setup`,
5423
- authLogin: `${API}/auth/login`,
5424
- authLogout: `${API}/auth/logout`,
5425
- authUsers: `${API}/auth/users`,
5426
- authUser: (id) => `${API}/auth/users/${id}`,
5427
- authChangePassword: `${API}/auth/change-password`,
5428
- // SPEC-213 · device token + activity log
5429
- deviceTokens: `${API}/device-tokens`,
5430
- deviceToken: (id) => `${API}/device-tokens/${id}`,
5431
- sessionResults: (projectId) => `${API}/session-results${projectId ? `?projectId=${encodeURIComponent(projectId)}` : ""}`,
5432
- // SPEC-215 · config runtime
5433
- config: `${API}/config`,
5434
- configKey: (key) => `${API}/config/${encodeURIComponent(key)}`,
5435
- // SPEC-299 · panel scheduler (daun #6) — konsumen read-only fondasi SPEC-294/ADR-0072.
5436
- schedulerConfig: `${API}/scheduler/config`,
5437
- schedulerState: `${API}/scheduler/state`,
5438
- // SPEC-268 · ADR-0066 · pemicu sync manual (cookie-authed)
5439
- syncNow: `${API}/sync/now`,
5440
- // SPEC-270 · ADR-0067 · antrean konflik rekonsil (cookie-authed)
5441
- syncConflicts: `${API}/sync/conflicts`,
5442
- syncConflictResolve: (entity, recordId) => `${API}/sync/conflicts/${encodeURIComponent(entity)}/${encodeURIComponent(recordId)}/resolve`,
5443
- // SPEC-257 · ADR-0065 · agent token (kelola cookie-only) + katalog capability
5444
- agentTokens: `${API}/agent-tokens`,
5445
- agentToken: (id) => `${API}/agent-tokens/${id}`,
5446
- agentCapabilities: `${API}/agent-tokens/capabilities`,
5447
- // SPEC-249 · error monitoring. ingest publik ber-DSN (bypass gate cookie, ADR-0060).
5448
- ingest: (slug) => `${API}/ingest/${encodeURIComponent(slug)}`,
5449
- errors: `${API}/errors`,
5450
- errorsGuide: `${API}/errors/integration-guide`,
5451
- error: (id) => `${API}/errors/${id}`,
5452
- errorEscalate: (id) => `${API}/errors/${id}/escalate`,
5453
- errorUnlink: (id) => `${API}/errors/${id}/unlink`,
5454
- // SPEC-271 · lepas tautan backlog
5455
- projectIngestKey: (id) => `${API}/projects/${encodeURIComponent(id)}/ingest-key`,
5456
- // SPEC-253 · Help Center publik (bypass gate cookie; otorisasi helpEnabled + kunci opaque tiket).
5457
- help: (slug) => `${API}/help/${encodeURIComponent(slug)}`,
5458
- helpTickets: (slug) => `${API}/help/${encodeURIComponent(slug)}/tickets`,
5459
- helpStatus: (slug, key) => `${API}/help/${encodeURIComponent(slug)}/tickets/${encodeURIComponent(key)}`,
5460
- // SPEC-253 · triase (di belakang gate cookie)
5461
- projectHelpCenter: (id) => `${API}/projects/${encodeURIComponent(id)}/help-center`,
5462
- tickets: `${API}/tickets`,
5463
- ticket: (id) => `${API}/tickets/${id}`,
5464
- ticketAttachment: (id, attId) => `${API}/tickets/${id}/attachments/${attId}`,
5465
- ticketAccept: (id) => `${API}/tickets/${id}/accept`,
5466
- ticketUnlink: (id) => `${API}/tickets/${id}/unlink`,
5467
- // SPEC-271 · lepas tautan backlog
5468
- ticketReject: (id) => `${API}/tickets/${id}/reject`,
5469
- // SPEC-337 · ADR-0075 · relasi integrasi antar project (LOCAL-only) + log lintas project.
5470
- projectLinks: (id) => `${API}/projects/${encodeURIComponent(id)}/links`,
5471
- projectLink: (id, linkId) => `${API}/projects/${encodeURIComponent(id)}/links/${encodeURIComponent(linkId)}`,
5472
- // SPEC-361 · ADR-0078 · unduh dokumen: query ditempelkan ke URL endpoint dokumen yang sudah ada
5473
- // (tak ada endpoint ekspor terpisah). `base` bisa sudah membawa query, mis. ideFile(?path=…).
5474
- download: (base, fmt) => `${base}${base.includes("?") ? "&" : "?"}download=${fmt}`
5475
- };
5518
+ init_src2();
5519
+ init_router();
5520
+ PKG = "hanoman";
5521
+ INSTALL_ARGS = ["i", "-g", `${PKG}@latest`];
5522
+ DEFAULT_REGISTRY = "https://registry.npmjs.org";
5476
5523
  }
5477
5524
  });
5478
5525
 
5479
- // ../shared/src/coverage.ts
5480
- function coverageOf(docs) {
5481
- const byCat = /* @__PURE__ */ new Map();
5482
- for (const d of docs) byCat.set(d.category, (byCat.get(d.category) ?? true) && d.linked);
5483
- if (byCat.size === 0) return 0;
5484
- const linked = [...byCat.values()].filter(Boolean).length;
5485
- return Math.round(linked / byCat.size * 100);
5526
+ // src/commands/start.ts
5527
+ var start_exports = {};
5528
+ __export(start_exports, {
5529
+ MAX_UPDATE_RESTARTS: () => MAX_UPDATE_RESTARTS,
5530
+ applyMigrations: () => applyMigrations,
5531
+ default: () => start,
5532
+ distDir: () => distDir,
5533
+ ensurePrismaClient: () => ensurePrismaClient,
5534
+ ensureSpawnHelpersExecutable: () => ensureSpawnHelpersExecutable,
5535
+ installLatest: () => installLatest,
5536
+ migrateFailureHint: () => migrateFailureHint,
5537
+ parseStartArgs: () => parseStartArgs,
5538
+ planSupervisorStep: () => planSupervisorStep,
5539
+ prismaClientUsable: () => prismaClientUsable,
5540
+ repairSpawnHelper: () => repairSpawnHelper,
5541
+ serverEnv: () => serverEnv,
5542
+ spawnHelperPaths: () => spawnHelperPaths
5543
+ });
5544
+ import { spawn, execFileSync as execFileSync2 } from "node:child_process";
5545
+ import { createRequire } from "node:module";
5546
+ import { existsSync, mkdirSync, readdirSync, statSync, chmodSync } from "node:fs";
5547
+ import { dirname as dirname2, join as join3, resolve as resolvePath } from "node:path";
5548
+ import { fileURLToPath } from "node:url";
5549
+ function parseStartArgs(argv) {
5550
+ const out = { port: null, host: null, db: null, migrate: true };
5551
+ const value = (i, flag, inline) => {
5552
+ const v = inline ?? argv[i + 1];
5553
+ if (v === void 0 || v.startsWith("--")) throw new Error(`${flag} butuh nilai`);
5554
+ return v;
5555
+ };
5556
+ for (let i = 0; i < argv.length; i++) {
5557
+ const raw = argv[i];
5558
+ const eq = raw.indexOf("=");
5559
+ const flag = eq === -1 ? raw : raw.slice(0, eq);
5560
+ const inline = eq === -1 ? void 0 : raw.slice(eq + 1);
5561
+ if (flag === "--no-migrate") {
5562
+ out.migrate = false;
5563
+ continue;
5564
+ }
5565
+ if (flag === "--port") {
5566
+ const v = value(i, "--port", inline);
5567
+ const n = Number(v);
5568
+ if (!Number.isInteger(n) || n <= 0) throw new Error(`--port harus angka, dapat "${v}"`);
5569
+ out.port = n;
5570
+ if (inline === void 0) i++;
5571
+ continue;
5572
+ }
5573
+ if (flag === "--host") {
5574
+ out.host = value(i, "--host", inline);
5575
+ if (inline === void 0) i++;
5576
+ continue;
5577
+ }
5578
+ if (flag === "--db") {
5579
+ out.db = value(i, "--db", inline);
5580
+ if (inline === void 0) i++;
5581
+ continue;
5582
+ }
5583
+ throw new Error(`argumen tak dikenal untuk start: ${raw}`);
5584
+ }
5585
+ return out;
5486
5586
  }
5487
- function isExternalLink(target) {
5488
- return !target || /^(https?:|#|mailto:)/.test(target);
5587
+ function distDir() {
5588
+ return dirname2(fileURLToPath(import.meta.url));
5489
5589
  }
5490
- function resolveLink(fromRel, target) {
5491
- const clean = target.trim().split(/\s+/)[0].split("#")[0].split("\\").join("/");
5492
- if (!clean) return "";
5493
- if (clean.startsWith("/")) return clean.slice(1).split("/").filter((p) => p && p !== ".").join("/");
5494
- const dir = fromRel.includes("/") ? fromRel.slice(0, fromRel.lastIndexOf("/")) : "";
5495
- const parts = (dir ? dir.split("/") : []).concat(clean.replace(/^\.\//, "").split("/"));
5496
- const out = [];
5497
- for (const p of parts) {
5498
- if (p === "" || p === ".") continue;
5499
- if (p === "..") out.pop();
5500
- else out.push(p);
5590
+ function runPrisma(args, dbUrl) {
5591
+ const prismaCli = prismaCliPath(createRequire(import.meta.url).resolve);
5592
+ try {
5593
+ const out = execFileSync2(process.execPath, [prismaCli, ...args], {
5594
+ env: { ...process.env, DATABASE_URL: dbUrl },
5595
+ encoding: "utf8",
5596
+ stdio: ["ignore", "pipe", "pipe"]
5597
+ });
5598
+ process.stdout.write(out);
5599
+ return out;
5600
+ } catch (e) {
5601
+ const err = e;
5602
+ const output = `${err.stdout ?? ""}${err.stderr ?? ""}`;
5603
+ process.stderr.write(output);
5604
+ throw Object.assign(new Error("prisma gagal"), { output });
5501
5605
  }
5502
- return out.join("/");
5503
5606
  }
5504
- function linkedSetFrom(indexRel, docs, read) {
5505
- const inCorpus = new Set(docs);
5506
- const seen = /* @__PURE__ */ new Set();
5507
- const queue = [indexRel];
5508
- let i = 0;
5509
- while (i < queue.length) {
5510
- const cur = queue[i++];
5511
- if (seen.has(cur)) continue;
5512
- seen.add(cur);
5513
- const md = read(cur);
5514
- if (md === null) continue;
5515
- for (const m of md.matchAll(LINK_RE)) {
5516
- const target = m[1].trim();
5517
- if (isExternalLink(target)) continue;
5518
- const rel = resolveLink(cur, target);
5519
- if (rel && inCorpus.has(rel) && !seen.has(rel)) queue.push(rel);
5520
- }
5521
- }
5522
- return new Set([...seen].filter((p) => inCorpus.has(p)));
5607
+ function migrateFailureHint(output, dbFile) {
5608
+ if (!output.includes("P3005")) return null;
5609
+ return `hanoman: berkas DB ${dbFile} sudah berisi tabel, tapi tak punya riwayat migrasi hanoman.
5610
+ Biasanya ia bukan DB hanoman versi ini \u2014 mis. sisa prototipe lama atau berkas tool lain.
5611
+ Pilih salah satu:
5612
+ \u2022 Pindahkan berkas itu, lalu jalankan ulang: mv "${dbFile}" "${dbFile}.lama"
5613
+ \u2022 Pakai berkas lain: hanoman --db /path/baru.db (atau HANOMAN_DATABASE_URL=file:/path/baru.db)
5614
+ Isi berkas lama tidak diubah oleh hanoman \u2014 periksa dulu sebelum menghapusnya.`;
5523
5615
  }
5524
- var LINK_RE;
5525
- var init_coverage = __esm({
5526
- "../shared/src/coverage.ts"() {
5527
- "use strict";
5528
- LINK_RE = /\]\(([^)]+)\)/g;
5529
- }
5530
- });
5531
-
5532
- // ../shared/src/ticket-status.ts
5533
- var init_ticket_status = __esm({
5534
- "../shared/src/ticket-status.ts"() {
5535
- "use strict";
5536
- }
5537
- });
5538
-
5539
- // ../shared/src/session-kind.ts
5540
- var SESSION_KINDS, zSessionKind;
5541
- var init_session_kind = __esm({
5542
- "../shared/src/session-kind.ts"() {
5543
- "use strict";
5544
- init_zod();
5545
- SESSION_KINDS = [
5546
- "spec",
5547
- "reverse",
5548
- "prd",
5549
- "scaffold",
5550
- "breakdown",
5551
- "cross-audit",
5552
- "vps",
5553
- "shell",
5554
- "worktree",
5555
- "terminal"
5556
- ];
5557
- zSessionKind = external_exports.enum(SESSION_KINDS);
5616
+ function applyMigrations(schema, dbUrl) {
5617
+ runPrisma(["migrate", "deploy", "--schema", schema], dbUrl);
5618
+ }
5619
+ async function prismaClientUsable() {
5620
+ try {
5621
+ const { PrismaClient } = await import("@prisma/client");
5622
+ new PrismaClient();
5623
+ return true;
5624
+ } catch {
5625
+ return false;
5558
5626
  }
5559
- });
5560
-
5561
- // ../shared/src/config.ts
5562
- var zHanomanConfig;
5563
- var init_config = __esm({
5564
- "../shared/src/config.ts"() {
5565
- "use strict";
5566
- init_zod();
5567
- zHanomanConfig = external_exports.object({
5568
- docsDir: external_exports.string().default("internal/docs")
5569
- });
5627
+ }
5628
+ async function ensurePrismaClient(schema, dbUrl, ctx) {
5629
+ if (await prismaClientUsable()) return true;
5630
+ ctx.stdout("hanoman \xB7 menyiapkan Prisma client (sekali per instalasi)\n");
5631
+ try {
5632
+ runPrisma(["generate", "--schema", schema], dbUrl);
5633
+ return true;
5634
+ } catch {
5635
+ ctx.stderr("hanoman: `prisma generate` gagal \u2014 jalankan manual di direktori paket, atau pasang ulang tanpa --ignore-scripts\n");
5636
+ return false;
5570
5637
  }
5571
- });
5572
-
5573
- // ../shared/src/config-registry.ts
5574
- var CONFIG_REGISTRY, BY_KEY;
5575
- var init_config_registry = __esm({
5576
- "../shared/src/config-registry.ts"() {
5577
- "use strict";
5578
- CONFIG_REGISTRY = [
5579
- // sync
5580
- {
5581
- key: "SYNC_SERVER_URL",
5582
- group: "sync",
5583
- label: "URL hub",
5584
- kind: "url",
5585
- apply: "live",
5586
- category: "knob",
5587
- help: "Base URL hub tujuan sync (REST + WS). Kosong = instance ini murni HUB."
5588
- },
5589
- {
5590
- key: "SYNC_DEVICE_TOKEN",
5591
- group: "sync",
5592
- label: "Device token",
5593
- kind: "secret",
5594
- apply: "live",
5595
- category: "credential",
5596
- help: "Token yang diterbitkan hub (tab Perangkat di hub). Dikirim sebagai Bearer."
5597
- },
5598
- {
5599
- key: "SYNC_TICK_MS",
5600
- group: "sync",
5601
- label: "Interval sync (ms)",
5602
- kind: "int",
5603
- apply: "live",
5604
- category: "knob",
5605
- default: "15000",
5606
- min: 1e3
5607
- },
5608
- // claude
5609
- {
5610
- key: "CLAUDE_CODE_OAUTH_TOKEN",
5611
- group: "claude",
5612
- label: "Claude OAuth token",
5613
- kind: "secret",
5614
- apply: "new-session",
5615
- category: "credential",
5616
- inheritEnv: true,
5617
- help: "Token `claude setup-token`. Diwarisi proses claude yang di-spawn."
5618
- },
5619
- { key: "ANTHROPIC_API_KEY", group: "claude", label: "Anthropic API key", kind: "secret", apply: "new-session", category: "credential", inheritEnv: true },
5620
- { key: "HANOMAN_CLAUDE_BIN", group: "claude", label: "Biner claude", kind: "path", apply: "new-session", category: "knob", default: "claude" },
5621
- // codex (SPEC-338 · ADR-0074)
5622
- { key: "HANOMAN_CODEX_BIN", group: "claude", label: "Biner codex", kind: "path", apply: "new-session", category: "knob", default: "codex" },
5623
- {
5624
- key: "CLAUDE_CONFIG_DIR",
5625
- group: "claude",
5626
- label: "Dir config Claude",
5627
- kind: "path",
5628
- apply: "new-session",
5629
- category: "knob",
5630
- help: "Default ~/.claude. Sumber .credentials.json untuk panel usage/limit."
5631
- },
5632
- // vps
5633
- { key: "HANOMAN_SSH_KEY_DIR", group: "vps", label: "Dir key SSH", kind: "path", apply: "new-session", category: "knob", help: "Default ~/.hanoman." },
5634
- { key: "HANOMAN_SSH_BIN", group: "vps", label: "Biner ssh", kind: "path", apply: "new-session", category: "knob", default: "ssh" },
5635
- // runtime
5636
- { key: "HANOMAN_EVENTS_TICK_MS", group: "runtime", label: "Interval events (ms)", kind: "int", apply: "live", category: "knob", default: "1000", min: 100 },
5637
- { key: "HANOMAN_UPDATE_FETCH", group: "runtime", label: "Deteksi update saat boot", kind: "bool", apply: "live", category: "knob", default: "1" },
5638
- // SPEC-398 · ADR-0087 · deteksi update kini membandingkan semver dengan registry npm, bukan
5639
- // menghitung commit di repo git (HANOMAN_REPO_ROOT dicabut bersama jalur git itu).
5640
- {
5641
- key: "HANOMAN_NPM_REGISTRY",
5642
- group: "runtime",
5643
- label: "Registry npm",
5644
- kind: "string",
5645
- apply: "live",
5646
- category: "knob",
5647
- default: "https://registry.npmjs.org",
5648
- help: "Sumber versi terbaru paket `hanoman`."
5649
- },
5650
- {
5651
- key: "HANOMAN_TMUX_SOCKET",
5652
- group: "runtime",
5653
- label: "Socket tmux",
5654
- kind: "string",
5655
- apply: "restart",
5656
- category: "knob",
5657
- default: "hanoman",
5658
- help: "Mengubah ini TIDAK memindahkan sesi tmux yang sudah hidup \u2014 berlaku setelah restart."
5659
- },
5660
- // gitGraph (SPEC-233 · preferensi tampilan git graph; semua live, dikonsumsi client)
5661
- { key: "gitGraph.style", group: "gitGraph", label: "Gaya graph", kind: "string", apply: "live", category: "knob", default: "rounded", help: "rounded | angular" },
5662
- { key: "gitGraph.colours", group: "gitGraph", label: "Warna lane (CSV)", kind: "string", apply: "live", category: "knob", help: "Daftar warna hex dipisah koma; kosong = palet bawaan." },
5663
- { key: "gitGraph.dateType", group: "gitGraph", label: "Jenis tanggal", kind: "string", apply: "live", category: "knob", default: "author", help: "author | commit" },
5664
- { key: "gitGraph.commitsInitialLoad", group: "gitGraph", label: "Muat awal", kind: "int", apply: "live", category: "knob", default: "200", min: 1 },
5665
- { key: "gitGraph.commitsLoadMore", group: "gitGraph", label: "Muat lagi", kind: "int", apply: "live", category: "knob", default: "100", min: 1 },
5666
- { key: "gitGraph.showRemoteBranches", group: "gitGraph", label: "Tampilkan remote", kind: "bool", apply: "live", category: "knob", default: "1" },
5667
- { key: "gitGraph.showTags", group: "gitGraph", label: "Tampilkan tag", kind: "bool", apply: "live", category: "knob", default: "1" },
5668
- { key: "gitGraph.showStashes", group: "gitGraph", label: "Tampilkan stash", kind: "bool", apply: "live", category: "knob", default: "1" },
5669
- { key: "gitGraph.showUncommitted", group: "gitGraph", label: "Tampilkan uncommitted", kind: "bool", apply: "live", category: "knob", default: "1" },
5670
- { key: "gitGraph.muteMergeCommits", group: "gitGraph", label: "Redupkan merge commit", kind: "bool", apply: "live", category: "knob", default: "1" },
5671
- { key: "gitGraph.fetchAvatars", group: "gitGraph", label: "Ambil avatar (gravatar)", kind: "bool", apply: "live", category: "knob", default: "0", help: "Jaringan eksternal ke gravatar.com." },
5672
- { key: "gitGraph.combineLocalRemote", group: "gitGraph", label: "Gabung label local+remote", kind: "bool", apply: "live", category: "knob", default: "0" },
5673
- { key: "gitGraph.markdown", group: "gitGraph", label: "Render markdown pesan", kind: "bool", apply: "live", category: "knob", default: "1" },
5674
- { key: "gitGraph.emoji", group: "gitGraph", label: "Render emoji shortcode", kind: "bool", apply: "live", category: "knob", default: "1" },
5675
- { key: "gitGraph.issueLinkPattern", group: "gitGraph", label: "Pola link issue", kind: "string", apply: "live", category: "knob", help: "URL dengan $1 untuk nomor issue, mis. https://github.com/acme/app/issues/$1" },
5676
- // bootstrap (read-only)
5677
- { key: "DATABASE_URL", group: "bootstrap", label: "DATABASE_URL", kind: "secret", apply: "restart", category: "bootstrap" },
5678
- { key: "TEST_DATABASE_URL", group: "bootstrap", label: "TEST_DATABASE_URL", kind: "secret", apply: "restart", category: "bootstrap" },
5679
- { key: "PORT", group: "bootstrap", label: "PORT", kind: "int", apply: "restart", category: "bootstrap", default: "8787" },
5680
- { key: "HOST", group: "bootstrap", label: "HOST", kind: "string", apply: "restart", category: "bootstrap", default: "127.0.0.1" },
5681
- { key: "NODE_ENV", group: "bootstrap", label: "NODE_ENV", kind: "string", apply: "restart", category: "bootstrap" },
5682
- // SPEC-398 · ADR-0086/0087 · lokasi data & aset, dibaca sekali saat boot (CLI yang menyetelnya).
5683
- { key: "HANOMAN_HOME", group: "bootstrap", label: "HANOMAN_HOME", kind: "path", apply: "restart", category: "bootstrap" },
5684
- { key: "HANOMAN_WEB_DIR", group: "bootstrap", label: "HANOMAN_WEB_DIR", kind: "path", apply: "restart", category: "bootstrap" }
5685
- ];
5686
- BY_KEY = new Map(CONFIG_REGISTRY.map((e) => [e.key, e]));
5638
+ }
5639
+ function spawnHelperPaths(ptyDir, listDir, exists) {
5640
+ const dirs = [join3(ptyDir, "build", "Release")];
5641
+ for (const name of listDir(join3(ptyDir, "prebuilds"))) dirs.push(join3(ptyDir, "prebuilds", name));
5642
+ return dirs.map((d) => join3(d, "spawn-helper")).filter(exists);
5643
+ }
5644
+ function ensureSpawnHelpersExecutable(paths2, ops) {
5645
+ const fixed = [];
5646
+ for (const p of paths2) {
5647
+ try {
5648
+ const mode = ops.mode(p) & 4095;
5649
+ if ((mode & 73) === 73) continue;
5650
+ ops.chmod(p, mode | 73);
5651
+ fixed.push(p);
5652
+ } catch {
5653
+ }
5687
5654
  }
5688
- });
5689
-
5690
- // ../shared/src/semver.ts
5691
- function parse(v) {
5692
- const m = RE.exec(v.trim());
5693
- return m ? { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ?? null } : null;
5655
+ return fixed;
5694
5656
  }
5695
- function preKey(pre) {
5696
- return pre.split(".").map((s) => /^\d+$/.test(s) ? s.padStart(12, "0") : s).join(".");
5657
+ function repairSpawnHelper(ctx) {
5658
+ let ptyDir;
5659
+ try {
5660
+ ptyDir = dirname2(createRequire(import.meta.url).resolve("node-pty/package.json"));
5661
+ } catch {
5662
+ return;
5663
+ }
5664
+ const paths2 = spawnHelperPaths(ptyDir, (d) => {
5665
+ try {
5666
+ return readdirSync(d);
5667
+ } catch {
5668
+ return [];
5669
+ }
5670
+ }, existsSync);
5671
+ const fixed = ensureSpawnHelpersExecutable(paths2, {
5672
+ mode: (p) => statSync(p).mode,
5673
+ chmod: (p, m) => chmodSync(p, m)
5674
+ });
5675
+ if (fixed.length) ctx.stdout("hanoman \xB7 memperbaiki izin `spawn-helper` node-pty (sekali per instalasi)\n");
5697
5676
  }
5698
- function compareSemver(a, b) {
5699
- const pa = parse(a), pb = parse(b);
5700
- if (!pa || !pb) return 0;
5701
- for (let i = 0; i < 3; i++) {
5702
- const d = pa.nums[i] - pb.nums[i];
5703
- if (d !== 0) return d < 0 ? -1 : 1;
5677
+ function planSupervisorStep(code, restartsUsed) {
5678
+ if (code !== UPDATE_RESTART_EXIT) return { action: "exit", code };
5679
+ if (restartsUsed >= MAX_UPDATE_RESTARTS) return { action: "exit", code };
5680
+ return { action: "update" };
5681
+ }
5682
+ function serverEnv(o) {
5683
+ return {
5684
+ NODE_ENV: "production",
5685
+ DATABASE_URL: o.dbUrl,
5686
+ PORT: String(o.port),
5687
+ HOST: o.host,
5688
+ HANOMAN_HOME: o.home,
5689
+ HANOMAN_SUPERVISOR: "1",
5690
+ ...o.web ? { HANOMAN_WEB_DIR: o.web } : {}
5691
+ };
5692
+ }
5693
+ function installLatest() {
5694
+ try {
5695
+ execFileSync2("npm", [...INSTALL_ARGS], { stdio: "inherit" });
5696
+ return { ok: true };
5697
+ } catch (e) {
5698
+ return { ok: false, reason: e.message || "npm i -g gagal" };
5704
5699
  }
5705
- if (pa.pre === pb.pre) return 0;
5706
- if (pa.pre === null) return 1;
5707
- if (pb.pre === null) return -1;
5708
- const ka = preKey(pa.pre), kb = preKey(pb.pre);
5709
- return ka < kb ? -1 : ka > kb ? 1 : 0;
5710
5700
  }
5711
- var RE;
5712
- var init_semver = __esm({
5713
- "../shared/src/semver.ts"() {
5714
- "use strict";
5715
- RE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/;
5701
+ function runServer(serverJs, env) {
5702
+ const child = spawn(process.execPath, [serverJs], { stdio: "inherit", env: { ...process.env, ...env } });
5703
+ const handlers = ["SIGINT", "SIGTERM"].map((sig) => [sig, () => child.kill(sig)]);
5704
+ for (const [sig, h] of handlers) process.on(sig, h);
5705
+ return new Promise((res) => child.on("exit", (code) => {
5706
+ for (const [sig, h] of handlers) process.off(sig, h);
5707
+ res(code ?? 0);
5708
+ }));
5709
+ }
5710
+ async function start(argv, ctx) {
5711
+ let opts;
5712
+ try {
5713
+ opts = parseStartArgs(argv);
5714
+ } catch (e) {
5715
+ ctx.stderr(`${e.message}
5716
+ `);
5717
+ return 2;
5716
5718
  }
5717
- });
5718
-
5719
- // ../shared/src/index.ts
5720
- var init_src2 = __esm({
5721
- "../shared/src/index.ts"() {
5719
+ let layout;
5720
+ let dbUrl;
5721
+ try {
5722
+ layout = resolveLayout(distDir(), existsSync);
5723
+ dbUrl = opts.db ? `file:${resolvePath(opts.db)}` : resolveDbUrl(ctx.env, dirname2(layout.schema));
5724
+ } catch (e) {
5725
+ ctx.stderr(`${e.message}
5726
+ `);
5727
+ return 1;
5728
+ }
5729
+ const notice = dbUrlNotice(ctx.env);
5730
+ if (notice) ctx.stderr(`${notice}
5731
+ `);
5732
+ const home = resolveHome(ctx.env);
5733
+ mkdirSync(home, { recursive: true });
5734
+ mkdirSync(dirname2(dbFilePath(dbUrl)), { recursive: true });
5735
+ if (!existsSync(layout.server)) {
5736
+ ctx.stderr(`hanoman: bundle server tak ada di ${layout.server} \u2014 jalankan \`pnpm build\` dulu
5737
+ `);
5738
+ return 1;
5739
+ }
5740
+ if (!await ensurePrismaClient(layout.schema, dbUrl, ctx)) return 1;
5741
+ repairSpawnHelper(ctx);
5742
+ if (opts.migrate) {
5743
+ ctx.stdout(`hanoman \xB7 menerapkan migrasi ke ${dbFilePath(dbUrl)}
5744
+ `);
5745
+ try {
5746
+ applyMigrations(layout.schema, dbUrl);
5747
+ } catch (e) {
5748
+ const hint = migrateFailureHint(String(e.output ?? ""), dbFilePath(dbUrl));
5749
+ ctx.stderr(hint ? `
5750
+ ${hint}
5751
+ ` : "hanoman: `prisma migrate deploy` gagal \u2014 lihat keluaran di atas\n");
5752
+ return 1;
5753
+ }
5754
+ }
5755
+ const port = opts.port ?? Number(ctx.env.PORT ?? 8787);
5756
+ const host = opts.host ?? ctx.env.HOST ?? "127.0.0.1";
5757
+ ctx.stdout(`hanoman \xB7 http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}
5758
+ `);
5759
+ const env = serverEnv({ dbUrl, port, host, home, web: layout.web ?? null });
5760
+ let restartsUsed = 0;
5761
+ for (; ; ) {
5762
+ const code = await runServer(layout.server, env);
5763
+ const step = planSupervisorStep(code, restartsUsed);
5764
+ if (step.action === "exit") {
5765
+ if (code === UPDATE_RESTART_EXIT) {
5766
+ ctx.stderr(`hanoman: jatah update-restart (${MAX_UPDATE_RESTARTS}) habis \u2014 keluar tanpa memasang
5767
+ `);
5768
+ }
5769
+ return step.code;
5770
+ }
5771
+ restartsUsed++;
5772
+ ctx.stdout(`hanoman \xB7 memasang versi terbaru dari npm (${restartsUsed}/${MAX_UPDATE_RESTARTS})
5773
+ `);
5774
+ const res = installLatest();
5775
+ if (!res.ok) {
5776
+ ctx.stderr(`hanoman: update gagal \u2014 ${res.reason}
5777
+ `);
5778
+ ctx.stdout("hanoman \xB7 menjalankan ulang versi yang ada\n");
5779
+ continue;
5780
+ }
5781
+ try {
5782
+ runPrisma(["generate", "--schema", layout.schema], dbUrl);
5783
+ } catch {
5784
+ ctx.stderr("hanoman: `prisma generate` sesudah update gagal \u2014 lanjut; server anak yang akan mengeluh\n");
5785
+ }
5786
+ if (opts.migrate) {
5787
+ try {
5788
+ applyMigrations(layout.schema, dbUrl);
5789
+ } catch (e) {
5790
+ const hint = migrateFailureHint(String(e.output ?? ""), dbFilePath(dbUrl));
5791
+ ctx.stderr(hint ? `
5792
+ ${hint}
5793
+ ` : "hanoman: migrasi sesudah update gagal \u2014 lihat keluaran di atas\n");
5794
+ return 1;
5795
+ }
5796
+ }
5797
+ ctx.stdout("hanoman \xB7 terpasang; menjalankan ulang\n");
5798
+ }
5799
+ }
5800
+ var MAX_UPDATE_RESTARTS;
5801
+ var init_start = __esm({
5802
+ "src/commands/start.ts"() {
5722
5803
  "use strict";
5723
- init_enums();
5724
- init_entities();
5725
- init_agent();
5726
- init_dto();
5727
- init_api();
5728
- init_coverage();
5729
- init_ticket_status();
5730
- init_session_kind();
5731
- init_config();
5732
- init_config_registry();
5733
- init_semver();
5804
+ init_src();
5805
+ init_src2();
5806
+ init_layout();
5807
+ init_update();
5808
+ MAX_UPDATE_RESTARTS = 5;
5734
5809
  }
5735
5810
  });
5736
5811
 
5737
- // src/commands/update.ts
5738
- var update_exports = {};
5739
- __export(update_exports, {
5740
- INSTALL_ARGS: () => INSTALL_ARGS,
5741
- PKG: () => PKG,
5742
- default: () => update,
5743
- planUpdate: () => planUpdate
5812
+ // src/commands/doctor.ts
5813
+ var doctor_exports = {};
5814
+ __export(doctor_exports, {
5815
+ default: () => doctor,
5816
+ doctorReport: () => doctorReport
5744
5817
  });
5745
5818
  import { execFileSync as execFileSync3 } from "node:child_process";
5746
- function planUpdate(current, latest) {
5747
- if (!latest) return { action: "unknown", current, latest: null };
5748
- return compareSemver(latest, current) > 0 ? { action: "install", current, latest } : { action: "up-to-date", current, latest };
5819
+ import { accessSync, constants, existsSync as existsSync2 } from "node:fs";
5820
+ import { dirname as dirname3 } from "node:path";
5821
+ function doctorReport(p) {
5822
+ const major = Number(/^v?(\d+)/.exec(p.node)?.[1] ?? 0);
5823
+ const rows = [
5824
+ { mark: major >= 20 ? "\u2713" : "\u2717", text: `node ${p.node} (butuh \u2265 20)`, fatal: major < 20 },
5825
+ { mark: p.git ? "\u2713" : "\u2717", text: p.git ?? "git \u2014 TAK ADA (wajib: worktree per sesi)", fatal: !p.git },
5826
+ { mark: p.tmux ? "\u2713" : "\u2717", text: p.tmux ?? "tmux \u2014 TAK ADA (wajib: sesi agen hidup di tmux)", fatal: !p.tmux },
5827
+ { mark: p.claude ? "\u2713" : "\xB7", text: p.claude ? `claude ${p.claude}` : "claude \u2014 tak ada", fatal: false },
5828
+ { mark: p.codex ? "\u2713" : "\xB7", text: p.codex ? `codex ${p.codex}` : "codex \u2014 tak ada", fatal: false },
5829
+ { mark: p.homeWritable ? "\u2713" : "\u2717", text: `data dir ${p.homeWritable ? "bisa ditulis" : "TAK bisa ditulis"}`, fatal: !p.homeWritable },
5830
+ { mark: p.web ? "\u2713" : "!", text: p.web ? "aset dashboard ada" : "aset dashboard tak ada \u2014 API jalan, dashboard tidak", fatal: false },
5831
+ { mark: "\xB7", text: `db ${p.db}`, fatal: false }
5832
+ ];
5833
+ if (!p.claude && !p.codex) {
5834
+ rows.push({ mark: "\u2717", text: "tak ada CLI agen (claude ATAU codex wajib ada)", fatal: true });
5835
+ }
5836
+ return { lines: rows.map((r) => ` ${r.mark} ${r.text}`), ok: !rows.some((r) => r.fatal) };
5749
5837
  }
5750
- async function latestVersion(registry) {
5838
+ function version(bin, args) {
5751
5839
  try {
5752
- const res = await fetch(`${registry.replace(/\/+$/, "")}/${PKG}/latest`, { signal: AbortSignal.timeout(1e4) });
5753
- if (!res.ok) return null;
5754
- const body = await res.json();
5755
- return typeof body.version === "string" ? body.version : null;
5840
+ return execFileSync3(bin, args, { encoding: "utf8", timeout: 1e4, stdio: ["ignore", "pipe", "ignore"] }).trim().split("\n")[0] ?? null;
5756
5841
  } catch {
5757
5842
  return null;
5758
5843
  }
5759
5844
  }
5760
- async function update(argv, ctx) {
5761
- const check = argv.includes("--check");
5762
- const current = currentVersion();
5763
- const latest = await latestVersion(ctx.env.HANOMAN_NPM_REGISTRY ?? DEFAULT_REGISTRY);
5764
- const plan = planUpdate(current, latest);
5765
- if (plan.action === "unknown") {
5766
- ctx.stderr(`hanoman ${current} \xB7 registry npm tak terjangkau \u2014 coba lagi nanti
5845
+ async function doctor(_argv, ctx) {
5846
+ let layout;
5847
+ let db;
5848
+ try {
5849
+ layout = resolveLayout(distDir(), existsSync2);
5850
+ db = dbFilePath(resolveDbUrl(ctx.env, dirname3(layout.schema)));
5851
+ } catch (e) {
5852
+ ctx.stderr(`${e.message}
5767
5853
  `);
5768
5854
  return 1;
5769
5855
  }
5770
- if (plan.action === "up-to-date") {
5771
- ctx.stdout(`hanoman ${current} sudah terkini
5772
- `);
5773
- return 0;
5774
- }
5775
- ctx.stdout(`hanoman ${plan.current} \u2192 ${plan.latest}
5776
- `);
5777
- if (check) {
5778
- ctx.stdout(`jalankan: npm ${INSTALL_ARGS.join(" ")}
5779
- `);
5780
- return 0;
5781
- }
5856
+ const home = resolveHome(ctx.env);
5857
+ let homeWritable = false;
5782
5858
  try {
5783
- execFileSync3("npm", [...INSTALL_ARGS], { stdio: "inherit" });
5859
+ accessSync(existsSync2(home) ? home : dirname3(home), constants.W_OK);
5860
+ homeWritable = true;
5784
5861
  } catch {
5785
- ctx.stderr("npm i -g gagal \u2014 jalankan manual (mungkin butuh sudo)\n");
5786
- return 1;
5787
5862
  }
5788
- ctx.stdout(`terpasang hanoman ${plan.latest} \xB7 restart instance yang berjalan
5863
+ const r = doctorReport({
5864
+ node: process.version,
5865
+ git: version("git", ["--version"]),
5866
+ tmux: version("tmux", ["-V"]),
5867
+ claude: version(ctx.env.HANOMAN_CLAUDE_BIN ?? "claude", ["--version"]),
5868
+ codex: version(ctx.env.HANOMAN_CODEX_BIN ?? "codex", ["--version"]),
5869
+ homeWritable,
5870
+ web: layout.web !== null,
5871
+ db
5872
+ });
5873
+ ctx.stdout(`hanoman doctor
5874
+ ${r.lines.join("\n")}
5789
5875
  `);
5790
- return 0;
5876
+ const notice = dbUrlNotice(ctx.env);
5877
+ if (notice) ctx.stdout(`
5878
+ ${notice}
5879
+ `);
5880
+ if (!r.ok) ctx.stderr("\nada prasyarat yang belum terpenuhi \u2014 hanoman tak akan bisa menjalankan sesi\n");
5881
+ return r.ok ? 0 : 1;
5791
5882
  }
5792
- var PKG, INSTALL_ARGS, DEFAULT_REGISTRY;
5793
- var init_update = __esm({
5794
- "src/commands/update.ts"() {
5883
+ var init_doctor = __esm({
5884
+ "src/commands/doctor.ts"() {
5795
5885
  "use strict";
5796
- init_src2();
5797
- init_router();
5798
- PKG = "hanoman";
5799
- INSTALL_ARGS = ["i", "-g", `${PKG}@latest`];
5800
- DEFAULT_REGISTRY = "https://registry.npmjs.org";
5886
+ init_src();
5887
+ init_layout();
5888
+ init_start();
5801
5889
  }
5802
5890
  });
5803
5891
 
5804
5892
  // src/commands/migrate-pg.ts
5805
5893
  var migrate_pg_exports = {};
5806
5894
  __export(migrate_pg_exports, {
5895
+ INT8_OID: () => INT8_OID,
5807
5896
  PG_ORDER: () => PG_ORDER,
5808
5897
  chunk: () => chunk,
5898
+ coerceInt8: () => coerceInt8,
5809
5899
  default: () => migratePg,
5900
+ isUndefinedTable: () => isUndefinedTable,
5810
5901
  migrationSteps: () => migrationSteps,
5811
5902
  parseMigrateArgs: () => parseMigrateArgs
5812
5903
  });
5813
5904
  import { existsSync as existsSync3 } from "node:fs";
5814
5905
  import { dirname as dirname4, resolve as resolvePath2 } from "node:path";
5906
+ function coerceInt8(rows, fields, model) {
5907
+ const cols = fields.filter((f) => f.dataTypeID === INT8_OID).map((f) => f.name);
5908
+ if (!cols.length) return rows;
5909
+ return rows.map((row) => {
5910
+ const out = { ...row };
5911
+ for (const c of cols) {
5912
+ const v = out[c];
5913
+ if (v === null || v === void 0) continue;
5914
+ const n = Number(v);
5915
+ if (!Number.isSafeInteger(n)) {
5916
+ throw new Error(`${model}.${c} = ${String(v)} di luar jangkauan integer aman \u2014 migrasi dihentikan`);
5917
+ }
5918
+ out[c] = n;
5919
+ }
5920
+ return out;
5921
+ });
5922
+ }
5923
+ function isUndefinedTable(e) {
5924
+ return typeof e === "object" && e !== null && e.code === "42P01";
5925
+ }
5815
5926
  function chunk(xs, n) {
5816
5927
  const out = [];
5817
5928
  for (let i = 0; i < xs.length; i += n) out.push(xs.slice(i, i + n));
@@ -5897,7 +6008,16 @@ async function migratePg(argv, ctx) {
5897
6008
  }
5898
6009
  let total = 0;
5899
6010
  for (const model of PG_ORDER) {
5900
- const { rows } = await pg.query(`SELECT * FROM "${model}"`);
6011
+ let rows;
6012
+ try {
6013
+ const res = await pg.query(`SELECT * FROM "${model}"`);
6014
+ rows = coerceInt8(res.rows, res.fields, model);
6015
+ } catch (e) {
6016
+ if (!isUndefinedTable(e)) throw e;
6017
+ ctx.stdout(` ${"\u2014".padStart(6)} \xB7 ${model} (tak ada di sumber \u2014 dilewati)
6018
+ `);
6019
+ continue;
6020
+ }
5901
6021
  total += rows.length;
5902
6022
  if (rows.length && steps.write) {
5903
6023
  for (const part of chunk(rows, CHUNK)) await at(model).createMany({ data: part });
@@ -5918,7 +6038,7 @@ async function migratePg(argv, ctx) {
5918
6038
  await db?.$disconnect();
5919
6039
  }
5920
6040
  }
5921
- var PG_ORDER, CHUNK, delegateKey;
6041
+ var PG_ORDER, CHUNK, INT8_OID, delegateKey;
5922
6042
  var init_migrate_pg = __esm({
5923
6043
  "src/commands/migrate-pg.ts"() {
5924
6044
  "use strict";
@@ -5954,6 +6074,7 @@ var init_migrate_pg = __esm({
5954
6074
  "TicketAttachment"
5955
6075
  ];
5956
6076
  CHUNK = 200;
6077
+ INT8_OID = 20;
5957
6078
  delegateKey = (model) => model.charAt(0).toLowerCase() + model.slice(1);
5958
6079
  }
5959
6080
  });