hanoman 0.1.4 → 0.1.6
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/README.md +11 -3
- package/dist/build-info.json +3 -3
- package/dist/cli.js +1560 -1280
- package/dist/server.js +1542 -104
- package/package.json +1 -1
- package/prisma/migrations/20260731000000_spec_created_started_at/migration.sql +43 -0
- package/prisma/migrations/20260731120000_lead_decision/migration.sql +33 -0
- package/prisma/schema.prisma +41 -0
- package/web/assets/{index-a6SFYnK5.js → index-DB8a8_aD.js} +1549 -1549
- package/web/index.html +1 -1
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
|
-
//
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
-
//
|
|
253
|
-
var
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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
|
|
362
|
-
|
|
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
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
//
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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.
|
|
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
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
-
|
|
651
|
+
if (issueData.message !== void 0) {
|
|
652
|
+
return {
|
|
653
|
+
...issueData,
|
|
654
|
+
path: fullPath,
|
|
655
|
+
message: issueData.message
|
|
656
|
+
};
|
|
559
657
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
obj[item] = item;
|
|
569
|
-
}
|
|
570
|
-
return obj;
|
|
663
|
+
return {
|
|
664
|
+
...issueData,
|
|
665
|
+
path: fullPath,
|
|
666
|
+
message: errorMessage
|
|
571
667
|
};
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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
|
|
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
|
|
774
|
-
|
|
775
|
-
|
|
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
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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 {
|
|
800
|
-
}
|
|
801
|
-
get formErrors() {
|
|
802
|
-
return this.flatten();
|
|
721
|
+
return { status: status.value, value: finalObject };
|
|
803
722
|
}
|
|
804
723
|
};
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
};
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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, zLeadEngine, zLead, LEAD_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,11 +4413,16 @@ 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
|
-
baseSha: external_exports.string().nullable()
|
|
4420
|
+
baseSha: external_exports.string().nullable(),
|
|
4732
4421
|
// SPEC-186 · null = belum pernah ada sesi (belum dimulai)
|
|
4422
|
+
// SPEC-408 · ADR-0090 · stempel waktu backlog (ISO string di wire — kolom DateTime di DB).
|
|
4423
|
+
// `startedAt` null = belum pernah dikerjakan; ia tak pernah ditulis ulang saat sesi dilanjutkan.
|
|
4424
|
+
createdAt: external_exports.string(),
|
|
4425
|
+
startedAt: external_exports.string().nullable()
|
|
4733
4426
|
});
|
|
4734
4427
|
NOTIFY_SOUNDS = [
|
|
4735
4428
|
"off",
|
|
@@ -4782,6 +4475,31 @@ var init_entities = __esm({
|
|
|
4782
4475
|
effort: external_exports.string().default("xhigh")
|
|
4783
4476
|
});
|
|
4784
4477
|
CONFLICT_DEFAULTS = zConflict.parse({});
|
|
4478
|
+
zLeadEngine = external_exports.object({
|
|
4479
|
+
enabled: external_exports.boolean().default(false),
|
|
4480
|
+
agent: zAgent.default("claude"),
|
|
4481
|
+
model: external_exports.string().default("claude-opus-5"),
|
|
4482
|
+
effort: external_exports.string().default("xhigh")
|
|
4483
|
+
});
|
|
4484
|
+
zLead = external_exports.object({
|
|
4485
|
+
enabled: external_exports.boolean().default(false),
|
|
4486
|
+
// master switch (AC-30)
|
|
4487
|
+
paused: external_exports.boolean().default(false),
|
|
4488
|
+
// rem darurat global (AC-27)
|
|
4489
|
+
pausedProjects: external_exports.array(external_exports.string()).default([]),
|
|
4490
|
+
// rem per project (AC-15/US-4)
|
|
4491
|
+
everyMin: external_exports.number().int().min(1).max(1440).default(5),
|
|
4492
|
+
// denyut proaktif (OQ-2)
|
|
4493
|
+
timeoutSec: external_exports.number().int().min(10).max(900).default(120),
|
|
4494
|
+
// batas waktu satu putusan (AC-4/35)
|
|
4495
|
+
// AC-11 / OQ-10 · berapa jawaban otomatis berturut-turut untuk SATU sesi sebelum lead berhenti.
|
|
4496
|
+
maxAutoAnswers: external_exports.number().int().min(1).max(20).default(3),
|
|
4497
|
+
// OQ-3 · syarat objektif sebelum lead boleh mengintegrasikan ke branch utama. Default MENYALA:
|
|
4498
|
+
// risiko "kode masuk main tanpa mata manusia" diterima sadar, tapi syaratnya tetap terukur.
|
|
4499
|
+
requireGreenBeforeIntegrate: external_exports.boolean().default(true),
|
|
4500
|
+
engine: zLeadEngine.default({})
|
|
4501
|
+
});
|
|
4502
|
+
LEAD_DEFAULTS = zLead.parse({});
|
|
4785
4503
|
zSetting = external_exports.object({
|
|
4786
4504
|
model: external_exports.string().default("claude-opus-5"),
|
|
4787
4505
|
effort: external_exports.string().default("xhigh"),
|
|
@@ -4808,13 +4526,17 @@ var init_entities = __esm({
|
|
|
4808
4526
|
// SPEC-338 · ADR-0074 · model/effort codex
|
|
4809
4527
|
verifyScope: zVerifyScope.default("changed"),
|
|
4810
4528
|
// SPEC-376 · ADR-0080 · scope verifikasi sesi
|
|
4811
|
-
conflict: zConflict.default(CONFLICT_DEFAULTS)
|
|
4529
|
+
conflict: zConflict.default(CONFLICT_DEFAULTS),
|
|
4812
4530
|
// SPEC-383 · ADR-0081 · default sesi konflik rebase/merge
|
|
4531
|
+
lead: zLead.default(LEAD_DEFAULTS)
|
|
4532
|
+
// SPEC-409 · ADR-0091 · hanoman-lead (default mati)
|
|
4813
4533
|
});
|
|
4814
4534
|
zNotification = external_exports.object({
|
|
4815
4535
|
id: external_exports.string(),
|
|
4816
|
-
type: external_exports.enum(["done", "decision", "error", "ticket", "fail"]).default("done"),
|
|
4817
4536
|
// SPEC-249 · +error; SPEC-253 · +ticket; SPEC-298 · +fail (sesi scheduler gagal/limit)
|
|
4537
|
+
// SPEC-409 · +lead (ADR-0091): keputusan berbobot / ragu / tindakan terkunci ditolak. MEMBERI
|
|
4538
|
+
// TAHU, bukan meminta izin — tak ada pekerjaan yang menunggu notifikasi ini dibaca (AC-25).
|
|
4539
|
+
type: external_exports.enum(["done", "decision", "error", "ticket", "fail", "lead"]).default("done"),
|
|
4818
4540
|
specId: external_exports.string().nullable(),
|
|
4819
4541
|
sessionId: external_exports.string().nullable(),
|
|
4820
4542
|
title: external_exports.string(),
|
|
@@ -4864,7 +4586,13 @@ var init_agent = __esm({
|
|
|
4864
4586
|
"support:read",
|
|
4865
4587
|
"support:write",
|
|
4866
4588
|
"notifications:read",
|
|
4867
|
-
"notifications:write"
|
|
4589
|
+
"notifications:write",
|
|
4590
|
+
// SPEC-409 · ADR-0091 · minta putusan ke hanoman-lead + baca jejak keputusan. Domain TERSENDIRI,
|
|
4591
|
+
// bukan menumpang prefix baca yang sudah ada: meminta putusan adalah operasi TULIS (ia melahirkan
|
|
4592
|
+
// baris jejak & bisa menggerakkan sesi), dan SPEC-405 sudah membuktikan apa yang terjadi saat
|
|
4593
|
+
// endpoint tulis menumpang prefix status yang dipetakan tanpa melihat method (AC-5).
|
|
4594
|
+
"lead:read",
|
|
4595
|
+
"lead:write"
|
|
4868
4596
|
];
|
|
4869
4597
|
zCapability = external_exports.enum(CAPABILITY_IDS);
|
|
4870
4598
|
zCapabilityInfo = external_exports.object({
|
|
@@ -4898,13 +4626,77 @@ var init_agent = __esm({
|
|
|
4898
4626
|
}
|
|
4899
4627
|
});
|
|
4900
4628
|
|
|
4901
|
-
// ../shared/src/
|
|
4902
|
-
var
|
|
4903
|
-
var
|
|
4904
|
-
"../shared/src/
|
|
4629
|
+
// ../shared/src/lead.ts
|
|
4630
|
+
var zLeadGate, zLeadKind, zLeadConfidence, zLeadStatus, LEAD_ACTIONS, zLeadAction, zLeadVerdict, zLeadAsk, zLeadOverride;
|
|
4631
|
+
var init_lead = __esm({
|
|
4632
|
+
"../shared/src/lead.ts"() {
|
|
4633
|
+
"use strict";
|
|
4634
|
+
init_zod();
|
|
4635
|
+
zLeadGate = external_exports.enum(["contract", "detected", "pulse"]);
|
|
4636
|
+
zLeadKind = external_exports.enum(["answer", "order", "collision", "quality", "refusal"]);
|
|
4637
|
+
zLeadConfidence = external_exports.enum(["tinggi", "sedang", "ragu"]);
|
|
4638
|
+
zLeadStatus = external_exports.enum(["berlaku", "ditimpa", "dibatalkan", "gagal"]);
|
|
4639
|
+
LEAD_ACTIONS = [
|
|
4640
|
+
"none",
|
|
4641
|
+
// keputusan murni jawaban; tak ada tindakan menyusul
|
|
4642
|
+
"answer-session",
|
|
4643
|
+
// ketik jawaban ke pane sesi (pintu deteksi otomatis)
|
|
4644
|
+
"start-session",
|
|
4645
|
+
// mulai sesi untuk sebuah backlog (lewat antrean scheduler)
|
|
4646
|
+
"stop-session",
|
|
4647
|
+
// hentikan sesi — worktree DIBIARKAN utuh (AC-32a)
|
|
4648
|
+
"resume-session",
|
|
4649
|
+
// lanjutkan sesi terputus (jalur ADR-0084)
|
|
4650
|
+
"restart-session",
|
|
4651
|
+
// ulangi pekerjaan dari awal
|
|
4652
|
+
"order-queue",
|
|
4653
|
+
// tata urutan antrean yang sudah ada (ADR-0072) — bukan antrean kedua
|
|
4654
|
+
"hold-work",
|
|
4655
|
+
// tunda satu pekerjaan karena tabrakan area kerja
|
|
4656
|
+
"push-branch",
|
|
4657
|
+
// dorong perubahan ke branch
|
|
4658
|
+
"integrate-main",
|
|
4659
|
+
// integrasikan ke branch utama (risiko yang diterima sadar, PRD §Risiko)
|
|
4660
|
+
"run-migration"
|
|
4661
|
+
// jalankan migration pada basis data LOKAL operator
|
|
4662
|
+
];
|
|
4663
|
+
zLeadAction = external_exports.enum(LEAD_ACTIONS);
|
|
4664
|
+
zLeadVerdict = external_exports.object({
|
|
4665
|
+
decision: external_exports.string().min(1),
|
|
4666
|
+
reason: external_exports.string().min(1),
|
|
4667
|
+
refs: external_exports.array(external_exports.string()).default([]),
|
|
4668
|
+
confidence: zLeadConfidence.default("sedang"),
|
|
4669
|
+
// Sengaja `string`, BUKAN `zLeadAction`: tindakan di luar allowlist harus bisa MASUK supaya
|
|
4670
|
+
// server menolaknya secara sadar — mencatat penolakan & menotifikasi operator (AC-33). Kalau
|
|
4671
|
+
// enum yang menyaring di sini, permintaan "deploy ke produksi" hanya akan tampak sebagai
|
|
4672
|
+
// keluaran rusak, dan justru peristiwa paling layak dilaporkan itulah yang hilang dari jejak.
|
|
4673
|
+
action: external_exports.string().default("none"),
|
|
4674
|
+
/** Teks yang benar-benar diketik ke pane sesi (pintu deteksi otomatis). */
|
|
4675
|
+
reply: external_exports.string().default("")
|
|
4676
|
+
});
|
|
4677
|
+
zLeadAsk = external_exports.object({
|
|
4678
|
+
projectId: external_exports.string().min(1),
|
|
4679
|
+
specId: external_exports.string().nullish(),
|
|
4680
|
+
sessionId: external_exports.string().nullish(),
|
|
4681
|
+
question: external_exports.string().min(1).max(8e3),
|
|
4682
|
+
options: external_exports.array(external_exports.string().max(2e3)).max(20).default([]),
|
|
4683
|
+
context: external_exports.string().max(2e4).default("")
|
|
4684
|
+
});
|
|
4685
|
+
zLeadOverride = external_exports.object({
|
|
4686
|
+
answer: external_exports.string().min(1).max(8e3),
|
|
4687
|
+
reason: external_exports.string().max(8e3).default("")
|
|
4688
|
+
});
|
|
4689
|
+
}
|
|
4690
|
+
});
|
|
4691
|
+
|
|
4692
|
+
// ../shared/src/dto.ts
|
|
4693
|
+
var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zCreateLink, zUpdateProject, zCreateSpec, zPatchSpec, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerState, zLeadDecisionView, zLeadAnswer, zLeadProjectStatus, zLeadStatusView, 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;
|
|
4694
|
+
var init_dto = __esm({
|
|
4695
|
+
"../shared/src/dto.ts"() {
|
|
4905
4696
|
"use strict";
|
|
4906
4697
|
init_zod();
|
|
4907
4698
|
init_entities();
|
|
4699
|
+
init_lead();
|
|
4908
4700
|
init_enums();
|
|
4909
4701
|
zIssueDeviceToken = external_exports.object({ name: external_exports.string().min(1) });
|
|
4910
4702
|
zSessionResult = external_exports.object({
|
|
@@ -4960,19 +4752,22 @@ var init_dto = __esm({
|
|
|
4960
4752
|
// SPEC-213 · set git remote resmi project
|
|
4961
4753
|
repoDir: external_exports.string().nullable().optional(),
|
|
4962
4754
|
// SPEC-217 · path default/server editable (null = kosongkan)
|
|
4963
|
-
schedulerOptIn: external_exports.boolean().optional()
|
|
4755
|
+
schedulerOptIn: external_exports.boolean().optional(),
|
|
4964
4756
|
// SPEC-294 · opt-in scheduler otonom (lokal, tak disync)
|
|
4757
|
+
leadOptIn: external_exports.boolean().optional()
|
|
4758
|
+
// SPEC-409 · ADR-0091 · opt-in hanoman-lead (lokal, tak disync)
|
|
4965
4759
|
});
|
|
4966
4760
|
zCreateSpec = external_exports.object({
|
|
4967
4761
|
project: external_exports.string(),
|
|
4968
4762
|
source: zSpecSource,
|
|
4969
4763
|
title: external_exports.string().min(1),
|
|
4970
4764
|
priority: zPriority,
|
|
4971
|
-
payload: external_exports.union([zBriefPayload, zQaPayload]),
|
|
4765
|
+
payload: external_exports.union([zBriefPayload, zQaPayload, zGoalPayload]),
|
|
4972
4766
|
branchFrom: external_exports.string().min(1).optional()
|
|
4973
4767
|
}).superRefine((o, ctx) => {
|
|
4974
|
-
const
|
|
4975
|
-
|
|
4768
|
+
const shape = "severity" in o.payload ? "qa" : "goal" in o.payload ? "goal" : "brief";
|
|
4769
|
+
const want = o.source === "qa" ? "qa" : o.source === "goal" ? "goal" : "brief";
|
|
4770
|
+
if (shape !== want)
|
|
4976
4771
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["payload"], message: "bentuk payload tak cocok dengan source" });
|
|
4977
4772
|
});
|
|
4978
4773
|
zPatchSpec = external_exports.object({
|
|
@@ -4982,7 +4777,8 @@ var init_dto = __esm({
|
|
|
4982
4777
|
// SPEC-186 · edit konten selagi item belum dimulai. Ditolak server bila sudah mulai.
|
|
4983
4778
|
title: external_exports.string().min(1).optional(),
|
|
4984
4779
|
priority: zPriority.optional(),
|
|
4985
|
-
payload: external_exports.union([zBriefPayload, zQaPayload]).optional()
|
|
4780
|
+
payload: external_exports.union([zBriefPayload, zQaPayload, zGoalPayload]).optional()
|
|
4781
|
+
// SPEC-407 · +goal
|
|
4986
4782
|
});
|
|
4987
4783
|
zIntegrate = external_exports.object({
|
|
4988
4784
|
op: external_exports.enum(["merge", "rebase"]),
|
|
@@ -5007,7 +4803,9 @@ var init_dto = __esm({
|
|
|
5007
4803
|
// SPEC-249 · hint prefix DSN (bukan hash/rahasia)
|
|
5008
4804
|
helpEnabled: external_exports.boolean().default(false),
|
|
5009
4805
|
// SPEC-253 · Help Center publik aktif
|
|
5010
|
-
schedulerOptIn: external_exports.boolean().default(false)
|
|
4806
|
+
schedulerOptIn: external_exports.boolean().default(false),
|
|
4807
|
+
// SPEC-294 · opt-in scheduler otonom
|
|
4808
|
+
leadOptIn: external_exports.boolean().default(false)
|
|
5011
4809
|
});
|
|
5012
4810
|
zSchedulerQueueItem = external_exports.object({
|
|
5013
4811
|
id: external_exports.string(),
|
|
@@ -5047,7 +4845,51 @@ var init_dto = __esm({
|
|
|
5047
4845
|
queue: external_exports.array(zSchedulerQueueItem),
|
|
5048
4846
|
sessions: external_exports.array(zSchedulerSessionView)
|
|
5049
4847
|
});
|
|
5050
|
-
|
|
4848
|
+
zLeadDecisionView = external_exports.object({
|
|
4849
|
+
id: external_exports.string(),
|
|
4850
|
+
projectId: external_exports.string(),
|
|
4851
|
+
specId: external_exports.string().nullable(),
|
|
4852
|
+
sessionId: external_exports.string().nullable(),
|
|
4853
|
+
gate: zLeadGate,
|
|
4854
|
+
kind: zLeadKind,
|
|
4855
|
+
question: external_exports.string(),
|
|
4856
|
+
answer: external_exports.string(),
|
|
4857
|
+
reason: external_exports.string(),
|
|
4858
|
+
refs: external_exports.array(external_exports.string()),
|
|
4859
|
+
confidence: zLeadConfidence,
|
|
4860
|
+
action: zLeadAction,
|
|
4861
|
+
status: zLeadStatus,
|
|
4862
|
+
weighty: external_exports.boolean(),
|
|
4863
|
+
supersededById: external_exports.string().nullable(),
|
|
4864
|
+
createdAt: external_exports.string()
|
|
4865
|
+
});
|
|
4866
|
+
zLeadAnswer = external_exports.object({
|
|
4867
|
+
id: external_exports.string(),
|
|
4868
|
+
decision: external_exports.string(),
|
|
4869
|
+
reason: external_exports.string(),
|
|
4870
|
+
refs: external_exports.array(external_exports.string()),
|
|
4871
|
+
confidence: zLeadConfidence,
|
|
4872
|
+
action: zLeadAction
|
|
4873
|
+
});
|
|
4874
|
+
zLeadProjectStatus = external_exports.object({
|
|
4875
|
+
projectId: external_exports.string(),
|
|
4876
|
+
name: external_exports.string(),
|
|
4877
|
+
optIn: external_exports.boolean(),
|
|
4878
|
+
paused: external_exports.boolean(),
|
|
4879
|
+
decisions24h: external_exports.number(),
|
|
4880
|
+
openSessions: external_exports.number()
|
|
4881
|
+
});
|
|
4882
|
+
zLeadStatusView = external_exports.object({
|
|
4883
|
+
config: zLead,
|
|
4884
|
+
projects: external_exports.array(zLeadProjectStatus),
|
|
4885
|
+
queue: external_exports.array(zSchedulerQueueItem),
|
|
4886
|
+
deciding: external_exports.array(external_exports.string()),
|
|
4887
|
+
// id sesi yang sedang disusun keputusannya (AC-3)
|
|
4888
|
+
waiting: external_exports.array(external_exports.string()),
|
|
4889
|
+
// id sesi ber-marker keputusan terisi
|
|
4890
|
+
lastPulseAt: external_exports.string().nullable()
|
|
4891
|
+
});
|
|
4892
|
+
zFlow = external_exports.enum(["feature", "qa", "scaffold", "reverse", "prd", "audit", "breakdown", "cross-audit", "goal"]);
|
|
5051
4893
|
zPrdBrief = external_exports.object({
|
|
5052
4894
|
title: external_exports.string().min(1),
|
|
5053
4895
|
context: external_exports.string(),
|
|
@@ -5193,6 +5035,8 @@ var init_dto = __esm({
|
|
|
5193
5035
|
});
|
|
5194
5036
|
zAttest = external_exports.object({ note: external_exports.string().max(500).optional() });
|
|
5195
5037
|
zRemediate = external_exports.object({ items: external_exports.array(external_exports.string()).min(1).max(64) });
|
|
5038
|
+
UPDATE_RESTART_EXIT = 75;
|
|
5039
|
+
zUpdateApplyBody = external_exports.object({ confirm: external_exports.boolean().optional() });
|
|
5196
5040
|
zStackFrame = external_exports.object({
|
|
5197
5041
|
function: external_exports.string().max(500).optional(),
|
|
5198
5042
|
filename: external_exports.string().max(2e3).optional(),
|
|
@@ -5303,515 +5147,940 @@ var init_dto = __esm({
|
|
|
5303
5147
|
createdAt: external_exports.string()
|
|
5304
5148
|
});
|
|
5305
5149
|
}
|
|
5306
|
-
});
|
|
5307
|
-
|
|
5308
|
-
// ../shared/src/api.ts
|
|
5309
|
-
var API, paths;
|
|
5310
|
-
var init_api = __esm({
|
|
5311
|
-
"../shared/src/api.ts"() {
|
|
5150
|
+
});
|
|
5151
|
+
|
|
5152
|
+
// ../shared/src/api.ts
|
|
5153
|
+
var API, paths;
|
|
5154
|
+
var init_api = __esm({
|
|
5155
|
+
"../shared/src/api.ts"() {
|
|
5156
|
+
"use strict";
|
|
5157
|
+
API = "/api";
|
|
5158
|
+
paths = {
|
|
5159
|
+
projects: `${API}/projects`,
|
|
5160
|
+
project: (id) => `${API}/projects/${id}`,
|
|
5161
|
+
// SPEC-255 · ADR-0064 · rename slug project (efek: DSN, Help Center, sync).
|
|
5162
|
+
projectRename: (id) => `${API}/projects/${encodeURIComponent(id)}/rename`,
|
|
5163
|
+
branches: (id) => `${API}/projects/${id}/branches`,
|
|
5164
|
+
// SPEC-360 · ADR-0077 · branch ter-merge (nilai turunan git) + hapus batch local/origin.
|
|
5165
|
+
branchesUnused: (id, base) => `${API}/projects/${id}/branches/unused${base ? `?base=${encodeURIComponent(base)}` : ""}`,
|
|
5166
|
+
branchesDelete: (id) => `${API}/projects/${id}/branches/delete`,
|
|
5167
|
+
// SPEC-217 · path per-mesin (LocalBinding, tak disync) + clone dari gitRemote
|
|
5168
|
+
binding: (id) => `${API}/projects/${id}/binding`,
|
|
5169
|
+
clone: (id) => `${API}/projects/${id}/clone`,
|
|
5170
|
+
specs: `${API}/specs`,
|
|
5171
|
+
spec: (id) => `${API}/specs/${id}`,
|
|
5172
|
+
specDocs: (id) => `${API}/specs/${id}/docs`,
|
|
5173
|
+
specDocFile: (id, path) => `${API}/specs/${id}/docs/${path}`,
|
|
5174
|
+
// SPEC-340 · ADR-0076 · rekomendasi tindak lanjut audit (turunan blok json dokumen audit).
|
|
5175
|
+
specEscalation: (id) => `${API}/specs/${id}/escalation`,
|
|
5176
|
+
specIntegrate: (id) => `${API}/specs/${id}/integrate`,
|
|
5177
|
+
specReview: (id) => `${API}/specs/${id}/review`,
|
|
5178
|
+
specReviewFile: (id, path) => `${API}/specs/${id}/review/${path}`,
|
|
5179
|
+
settings: `${API}/settings`,
|
|
5180
|
+
notifications: `${API}/notifications`,
|
|
5181
|
+
limits: `${API}/limits`,
|
|
5182
|
+
// SPEC-339 · versi codex CLI (peringatan lunak model GPT-5.6).
|
|
5183
|
+
codexVersion: `${API}/codex/version`,
|
|
5184
|
+
docs: (id) => `${API}/projects/${id}/docs`,
|
|
5185
|
+
docFile: (id, path) => `${API}/projects/${id}/docs/${path}`,
|
|
5186
|
+
// SPEC-210 · dokumen PRD project (freshest-wins: worktree sesi prd hidup > repoDir)
|
|
5187
|
+
prds: (id) => `${API}/projects/${id}/prds`,
|
|
5188
|
+
allPrds: `${API}/prds`,
|
|
5189
|
+
// perbaikan SPEC-210 · daftar PRD lintas-project (filter "Semua project")
|
|
5190
|
+
prdFile: (id, path) => `${API}/projects/${id}/prds/${path}`,
|
|
5191
|
+
// SPEC-273 · manifest breakdown sebuah PRD (freshest-wins) + materialize batch.
|
|
5192
|
+
breakdown: (id, prd) => `${API}/projects/${id}/breakdown?prd=${encodeURIComponent(prd)}`,
|
|
5193
|
+
specsBatch: `${API}/specs/batch`,
|
|
5194
|
+
// SPEC-182 · IDE Visual
|
|
5195
|
+
ideTree: (id, ref = "") => `${API}/projects/${id}/tree${ref ? `?ref=${encodeURIComponent(ref)}` : ""}`,
|
|
5196
|
+
ideFile: (id, path, ref = "") => `${API}/projects/${id}/file${path ? `?path=${encodeURIComponent(path)}${ref ? `&ref=${encodeURIComponent(ref)}` : ""}` : ""}`,
|
|
5197
|
+
ideGraph: (id, limit = 200, opts) => {
|
|
5198
|
+
const p = new URLSearchParams({ limit: String(limit) });
|
|
5199
|
+
if (opts?.branches?.length) p.set("branches", opts.branches.join(","));
|
|
5200
|
+
if (opts?.showRemote === false) p.set("showRemote", "false");
|
|
5201
|
+
if (opts?.showTags === false) p.set("showTags", "false");
|
|
5202
|
+
return `${API}/projects/${id}/graph?${p.toString()}`;
|
|
5203
|
+
},
|
|
5204
|
+
ideStatus: (id) => `${API}/projects/${id}/status`,
|
|
5205
|
+
// SPEC-233 · status working tree
|
|
5206
|
+
ideSearch: (id, q, by = "all") => `${API}/projects/${id}/graph/search?q=${encodeURIComponent(q)}&by=${by}`,
|
|
5207
|
+
// SPEC-233
|
|
5208
|
+
ideStashes: (id) => `${API}/projects/${id}/stashes`,
|
|
5209
|
+
// SPEC-233 · daftar stash
|
|
5210
|
+
// SPEC-233 · remote mgmt + pr-url + archive
|
|
5211
|
+
ideRemotes: (id) => `${API}/projects/${id}/remotes`,
|
|
5212
|
+
ideRemote: (id, name) => `${API}/projects/${id}/remotes/${encodeURIComponent(name)}`,
|
|
5213
|
+
idePrUrl: (id, branch, base) => `${API}/projects/${id}/pr-url?branch=${encodeURIComponent(branch)}${base ? `&base=${encodeURIComponent(base)}` : ""}`,
|
|
5214
|
+
ideArchive: (id, ref, format = "zip") => `${API}/projects/${id}/archive?ref=${encodeURIComponent(ref)}&format=${format}`,
|
|
5215
|
+
ideCommit: (id, sha) => `${API}/projects/${id}/commit/${sha}`,
|
|
5216
|
+
// SPEC-233 · diff satu file di commit (vs parent)
|
|
5217
|
+
ideCommitFile: (id, sha, path) => `${API}/projects/${id}/commit/${sha}/file?path=${encodeURIComponent(path)}`,
|
|
5218
|
+
// SPEC-233 · compare dua commit
|
|
5219
|
+
ideCompare: (id, from, to) => `${API}/projects/${id}/compare?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`,
|
|
5220
|
+
ideCompareFile: (id, from, to, path) => `${API}/projects/${id}/compare/file?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}&path=${encodeURIComponent(path)}`,
|
|
5221
|
+
ideGit: (id) => `${API}/projects/${id}/git`,
|
|
5222
|
+
ideGitMerge: (id) => `${API}/projects/${id}/git/merge`,
|
|
5223
|
+
// SPEC-229 · merge git graph isolasi
|
|
5224
|
+
// SPEC-234 · status working tree (staged/unstaged) + diff satu file working tree
|
|
5225
|
+
// catat: /working-status dibedakan dari /status milik SPEC-233 (repoStatus graph) — beda bentuk respons.
|
|
5226
|
+
ideWorkingStatus: (id) => `${API}/projects/${id}/working-status`,
|
|
5227
|
+
ideFileDiff: (id, path, staged) => `${API}/projects/${id}/file-diff?path=${encodeURIComponent(path)}${staged ? "&staged=1" : ""}`,
|
|
5228
|
+
ideGitRebase: (id) => `${API}/projects/${id}/git/rebase`,
|
|
5229
|
+
// SPEC-233 · rebase isolasi
|
|
5230
|
+
ideGitPull: (id) => `${API}/projects/${id}/git/pull`,
|
|
5231
|
+
// SPEC-233 · pull isolasi
|
|
5232
|
+
ideGitDrop: (id) => `${API}/projects/${id}/git/drop`,
|
|
5233
|
+
// SPEC-233 · drop commit isolasi
|
|
5234
|
+
fsBrowse: (path) => `${API}/fs/browse${path ? `?path=${encodeURIComponent(path)}` : ""}`,
|
|
5235
|
+
terminalSessions: `${API}/terminal/sessions`,
|
|
5236
|
+
terminalSession: (id) => `${API}/terminal/sessions/${id}`,
|
|
5237
|
+
terminalPhases: (id) => `${API}/terminal/sessions/${id}/phases`,
|
|
5238
|
+
// SPEC-230 · review + integrate ber-skop sesi (sesi project-level PRD, tanpa Spec).
|
|
5239
|
+
sessionReview: (id) => `${API}/terminal/sessions/${id}/review`,
|
|
5240
|
+
sessionReviewFile: (id, path) => `${API}/terminal/sessions/${id}/review/${path}`,
|
|
5241
|
+
sessionIntegrate: (id) => `${API}/terminal/sessions/${id}/integrate`,
|
|
5242
|
+
terminalWs: (id) => `${API}/terminal/sessions/${id}/ws`,
|
|
5243
|
+
// SPEC-362 · ADR-0079 · riwayat sesi. Di bawah prefix /terminal supaya ikut capability
|
|
5244
|
+
// `sessions` yang sudah ada (services/agent-capabilities.ts) tanpa menambah domain baru.
|
|
5245
|
+
sessionHistory: (qs = "") => `${API}/terminal/history${qs}`,
|
|
5246
|
+
sessionHistoryItem: (id) => `${API}/terminal/history/${encodeURIComponent(id)}`,
|
|
5247
|
+
sessionTranscript: (id) => `${API}/terminal/history/${encodeURIComponent(id)}/transcript`,
|
|
5248
|
+
eventsWs: `${API}/events/ws`,
|
|
5249
|
+
// SPEC-199 · WebSocket siar dashboard (global, bukan per-sesi)
|
|
5250
|
+
vps: `${API}/vps`,
|
|
5251
|
+
vpsOne: (id) => `${API}/vps/${id}`,
|
|
5252
|
+
vpsAudit: (id) => `${API}/vps/${id}/audit`,
|
|
5253
|
+
vpsHarden: (id) => `${API}/vps/${id}/harden`,
|
|
5254
|
+
vpsSession: (id) => `${API}/vps/${id}/session`,
|
|
5255
|
+
vpsTest: (id) => `${API}/vps/${id}/test`,
|
|
5256
|
+
vpsConsole: (id) => `${API}/vps/${id}/console`,
|
|
5257
|
+
// SPEC-220 · kepatuhan checklist
|
|
5258
|
+
vpsChecklist: (id) => `${API}/vps/${id}/checklist`,
|
|
5259
|
+
vpsItemNa: (id, itemId) => `${API}/vps/${id}/items/${itemId}/na`,
|
|
5260
|
+
vpsItemNaBulk: (id) => `${API}/vps/${id}/items/na-bulk`,
|
|
5261
|
+
vpsItemAttest: (id, itemId) => `${API}/vps/${id}/items/${itemId}/attest`,
|
|
5262
|
+
vpsRemediatePreview: (id) => `${API}/vps/${id}/remediate/preview`,
|
|
5263
|
+
vpsRemediate: (id) => `${API}/vps/${id}/remediate`,
|
|
5264
|
+
// SPEC-169 · auth
|
|
5265
|
+
authStatus: `${API}/auth/status`,
|
|
5266
|
+
authSetup: `${API}/auth/setup`,
|
|
5267
|
+
authLogin: `${API}/auth/login`,
|
|
5268
|
+
authLogout: `${API}/auth/logout`,
|
|
5269
|
+
authUsers: `${API}/auth/users`,
|
|
5270
|
+
authUser: (id) => `${API}/auth/users/${id}`,
|
|
5271
|
+
authChangePassword: `${API}/auth/change-password`,
|
|
5272
|
+
// SPEC-213 · device token + activity log
|
|
5273
|
+
deviceTokens: `${API}/device-tokens`,
|
|
5274
|
+
deviceToken: (id) => `${API}/device-tokens/${id}`,
|
|
5275
|
+
sessionResults: (projectId) => `${API}/session-results${projectId ? `?projectId=${encodeURIComponent(projectId)}` : ""}`,
|
|
5276
|
+
// SPEC-215 · config runtime
|
|
5277
|
+
config: `${API}/config`,
|
|
5278
|
+
configKey: (key) => `${API}/config/${encodeURIComponent(key)}`,
|
|
5279
|
+
// SPEC-299 · panel scheduler (daun #6) — konsumen read-only fondasi SPEC-294/ADR-0072.
|
|
5280
|
+
schedulerConfig: `${API}/scheduler/config`,
|
|
5281
|
+
schedulerState: `${API}/scheduler/state`,
|
|
5282
|
+
// SPEC-409 · ADR-0091 · hanoman-lead. Semua HTTP (polling) — tak ada kanal WS baru (AC-26).
|
|
5283
|
+
leadConfig: `${API}/lead/config`,
|
|
5284
|
+
leadStatus: `${API}/lead/status`,
|
|
5285
|
+
leadDecisions: `${API}/lead/decisions`,
|
|
5286
|
+
leadDecisionOverride: (id) => `${API}/lead/decisions/${encodeURIComponent(id)}/override`,
|
|
5287
|
+
leadDecisionCancel: (id) => `${API}/lead/decisions/${encodeURIComponent(id)}/cancel`,
|
|
5288
|
+
// SPEC-268 · ADR-0066 · pemicu sync manual (cookie-authed)
|
|
5289
|
+
syncNow: `${API}/sync/now`,
|
|
5290
|
+
// SPEC-270 · ADR-0067 · antrean konflik rekonsil (cookie-authed)
|
|
5291
|
+
syncConflicts: `${API}/sync/conflicts`,
|
|
5292
|
+
syncConflictResolve: (entity, recordId) => `${API}/sync/conflicts/${encodeURIComponent(entity)}/${encodeURIComponent(recordId)}/resolve`,
|
|
5293
|
+
// SPEC-257 · ADR-0065 · agent token (kelola cookie-only) + katalog capability
|
|
5294
|
+
agentTokens: `${API}/agent-tokens`,
|
|
5295
|
+
agentToken: (id) => `${API}/agent-tokens/${id}`,
|
|
5296
|
+
agentCapabilities: `${API}/agent-tokens/capabilities`,
|
|
5297
|
+
// SPEC-249 · error monitoring. ingest publik ber-DSN (bypass gate cookie, ADR-0060).
|
|
5298
|
+
ingest: (slug) => `${API}/ingest/${encodeURIComponent(slug)}`,
|
|
5299
|
+
errors: `${API}/errors`,
|
|
5300
|
+
errorsGuide: `${API}/errors/integration-guide`,
|
|
5301
|
+
error: (id) => `${API}/errors/${id}`,
|
|
5302
|
+
errorEscalate: (id) => `${API}/errors/${id}/escalate`,
|
|
5303
|
+
errorUnlink: (id) => `${API}/errors/${id}/unlink`,
|
|
5304
|
+
// SPEC-271 · lepas tautan backlog
|
|
5305
|
+
projectIngestKey: (id) => `${API}/projects/${encodeURIComponent(id)}/ingest-key`,
|
|
5306
|
+
// SPEC-253 · Help Center publik (bypass gate cookie; otorisasi helpEnabled + kunci opaque tiket).
|
|
5307
|
+
help: (slug) => `${API}/help/${encodeURIComponent(slug)}`,
|
|
5308
|
+
helpTickets: (slug) => `${API}/help/${encodeURIComponent(slug)}/tickets`,
|
|
5309
|
+
helpStatus: (slug, key) => `${API}/help/${encodeURIComponent(slug)}/tickets/${encodeURIComponent(key)}`,
|
|
5310
|
+
// SPEC-253 · triase (di belakang gate cookie)
|
|
5311
|
+
projectHelpCenter: (id) => `${API}/projects/${encodeURIComponent(id)}/help-center`,
|
|
5312
|
+
tickets: `${API}/tickets`,
|
|
5313
|
+
ticket: (id) => `${API}/tickets/${id}`,
|
|
5314
|
+
ticketAttachment: (id, attId) => `${API}/tickets/${id}/attachments/${attId}`,
|
|
5315
|
+
ticketAccept: (id) => `${API}/tickets/${id}/accept`,
|
|
5316
|
+
ticketUnlink: (id) => `${API}/tickets/${id}/unlink`,
|
|
5317
|
+
// SPEC-271 · lepas tautan backlog
|
|
5318
|
+
ticketReject: (id) => `${API}/tickets/${id}/reject`,
|
|
5319
|
+
// SPEC-337 · ADR-0075 · relasi integrasi antar project (LOCAL-only) + log lintas project.
|
|
5320
|
+
projectLinks: (id) => `${API}/projects/${encodeURIComponent(id)}/links`,
|
|
5321
|
+
projectLink: (id, linkId) => `${API}/projects/${encodeURIComponent(id)}/links/${encodeURIComponent(linkId)}`,
|
|
5322
|
+
// SPEC-361 · ADR-0078 · unduh dokumen: query ditempelkan ke URL endpoint dokumen yang sudah ada
|
|
5323
|
+
// (tak ada endpoint ekspor terpisah). `base` bisa sudah membawa query, mis. ideFile(?path=…).
|
|
5324
|
+
download: (base, fmt) => `${base}${base.includes("?") ? "&" : "?"}download=${fmt}`
|
|
5325
|
+
};
|
|
5326
|
+
}
|
|
5327
|
+
});
|
|
5328
|
+
|
|
5329
|
+
// ../shared/src/coverage.ts
|
|
5330
|
+
function coverageOf(docs) {
|
|
5331
|
+
const byCat = /* @__PURE__ */ new Map();
|
|
5332
|
+
for (const d of docs) byCat.set(d.category, (byCat.get(d.category) ?? true) && d.linked);
|
|
5333
|
+
if (byCat.size === 0) return 0;
|
|
5334
|
+
const linked = [...byCat.values()].filter(Boolean).length;
|
|
5335
|
+
return Math.round(linked / byCat.size * 100);
|
|
5336
|
+
}
|
|
5337
|
+
function isExternalLink(target) {
|
|
5338
|
+
return !target || /^(https?:|#|mailto:)/.test(target);
|
|
5339
|
+
}
|
|
5340
|
+
function resolveLink(fromRel, target) {
|
|
5341
|
+
const clean = target.trim().split(/\s+/)[0].split("#")[0].split("\\").join("/");
|
|
5342
|
+
if (!clean) return "";
|
|
5343
|
+
if (clean.startsWith("/")) return clean.slice(1).split("/").filter((p) => p && p !== ".").join("/");
|
|
5344
|
+
const dir = fromRel.includes("/") ? fromRel.slice(0, fromRel.lastIndexOf("/")) : "";
|
|
5345
|
+
const parts = (dir ? dir.split("/") : []).concat(clean.replace(/^\.\//, "").split("/"));
|
|
5346
|
+
const out = [];
|
|
5347
|
+
for (const p of parts) {
|
|
5348
|
+
if (p === "" || p === ".") continue;
|
|
5349
|
+
if (p === "..") out.pop();
|
|
5350
|
+
else out.push(p);
|
|
5351
|
+
}
|
|
5352
|
+
return out.join("/");
|
|
5353
|
+
}
|
|
5354
|
+
function linkedSetFrom(indexRel, docs, read) {
|
|
5355
|
+
const inCorpus = new Set(docs);
|
|
5356
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5357
|
+
const queue = [indexRel];
|
|
5358
|
+
let i = 0;
|
|
5359
|
+
while (i < queue.length) {
|
|
5360
|
+
const cur = queue[i++];
|
|
5361
|
+
if (seen.has(cur)) continue;
|
|
5362
|
+
seen.add(cur);
|
|
5363
|
+
const md = read(cur);
|
|
5364
|
+
if (md === null) continue;
|
|
5365
|
+
for (const m of md.matchAll(LINK_RE)) {
|
|
5366
|
+
const target = m[1].trim();
|
|
5367
|
+
if (isExternalLink(target)) continue;
|
|
5368
|
+
const rel = resolveLink(cur, target);
|
|
5369
|
+
if (rel && inCorpus.has(rel) && !seen.has(rel)) queue.push(rel);
|
|
5370
|
+
}
|
|
5371
|
+
}
|
|
5372
|
+
return new Set([...seen].filter((p) => inCorpus.has(p)));
|
|
5373
|
+
}
|
|
5374
|
+
var LINK_RE;
|
|
5375
|
+
var init_coverage = __esm({
|
|
5376
|
+
"../shared/src/coverage.ts"() {
|
|
5377
|
+
"use strict";
|
|
5378
|
+
LINK_RE = /\]\(([^)]+)\)/g;
|
|
5379
|
+
}
|
|
5380
|
+
});
|
|
5381
|
+
|
|
5382
|
+
// ../shared/src/ticket-status.ts
|
|
5383
|
+
var init_ticket_status = __esm({
|
|
5384
|
+
"../shared/src/ticket-status.ts"() {
|
|
5385
|
+
"use strict";
|
|
5386
|
+
}
|
|
5387
|
+
});
|
|
5388
|
+
|
|
5389
|
+
// ../shared/src/session-kind.ts
|
|
5390
|
+
var SESSION_KINDS, zSessionKind;
|
|
5391
|
+
var init_session_kind = __esm({
|
|
5392
|
+
"../shared/src/session-kind.ts"() {
|
|
5393
|
+
"use strict";
|
|
5394
|
+
init_zod();
|
|
5395
|
+
SESSION_KINDS = [
|
|
5396
|
+
"spec",
|
|
5397
|
+
"reverse",
|
|
5398
|
+
"prd",
|
|
5399
|
+
"scaffold",
|
|
5400
|
+
"breakdown",
|
|
5401
|
+
"cross-audit",
|
|
5402
|
+
"vps",
|
|
5403
|
+
"shell",
|
|
5404
|
+
"worktree",
|
|
5405
|
+
"terminal"
|
|
5406
|
+
];
|
|
5407
|
+
zSessionKind = external_exports.enum(SESSION_KINDS);
|
|
5408
|
+
}
|
|
5409
|
+
});
|
|
5410
|
+
|
|
5411
|
+
// ../shared/src/config.ts
|
|
5412
|
+
var zHanomanConfig;
|
|
5413
|
+
var init_config = __esm({
|
|
5414
|
+
"../shared/src/config.ts"() {
|
|
5415
|
+
"use strict";
|
|
5416
|
+
init_zod();
|
|
5417
|
+
zHanomanConfig = external_exports.object({
|
|
5418
|
+
docsDir: external_exports.string().default("internal/docs")
|
|
5419
|
+
});
|
|
5420
|
+
}
|
|
5421
|
+
});
|
|
5422
|
+
|
|
5423
|
+
// ../shared/src/config-registry.ts
|
|
5424
|
+
var CONFIG_REGISTRY, BY_KEY;
|
|
5425
|
+
var init_config_registry = __esm({
|
|
5426
|
+
"../shared/src/config-registry.ts"() {
|
|
5427
|
+
"use strict";
|
|
5428
|
+
CONFIG_REGISTRY = [
|
|
5429
|
+
// sync
|
|
5430
|
+
{
|
|
5431
|
+
key: "SYNC_SERVER_URL",
|
|
5432
|
+
group: "sync",
|
|
5433
|
+
label: "URL hub",
|
|
5434
|
+
kind: "url",
|
|
5435
|
+
apply: "live",
|
|
5436
|
+
category: "knob",
|
|
5437
|
+
help: "Base URL hub tujuan sync (REST + WS). Kosong = instance ini murni HUB."
|
|
5438
|
+
},
|
|
5439
|
+
{
|
|
5440
|
+
key: "SYNC_DEVICE_TOKEN",
|
|
5441
|
+
group: "sync",
|
|
5442
|
+
label: "Device token",
|
|
5443
|
+
kind: "secret",
|
|
5444
|
+
apply: "live",
|
|
5445
|
+
category: "credential",
|
|
5446
|
+
help: "Token yang diterbitkan hub (tab Perangkat di hub). Dikirim sebagai Bearer."
|
|
5447
|
+
},
|
|
5448
|
+
{
|
|
5449
|
+
key: "SYNC_TICK_MS",
|
|
5450
|
+
group: "sync",
|
|
5451
|
+
label: "Interval sync (ms)",
|
|
5452
|
+
kind: "int",
|
|
5453
|
+
apply: "live",
|
|
5454
|
+
category: "knob",
|
|
5455
|
+
default: "15000",
|
|
5456
|
+
min: 1e3
|
|
5457
|
+
},
|
|
5458
|
+
// claude
|
|
5459
|
+
{
|
|
5460
|
+
key: "CLAUDE_CODE_OAUTH_TOKEN",
|
|
5461
|
+
group: "claude",
|
|
5462
|
+
label: "Claude OAuth token",
|
|
5463
|
+
kind: "secret",
|
|
5464
|
+
apply: "new-session",
|
|
5465
|
+
category: "credential",
|
|
5466
|
+
inheritEnv: true,
|
|
5467
|
+
help: "Token `claude setup-token`. Diwarisi proses claude yang di-spawn."
|
|
5468
|
+
},
|
|
5469
|
+
{ key: "ANTHROPIC_API_KEY", group: "claude", label: "Anthropic API key", kind: "secret", apply: "new-session", category: "credential", inheritEnv: true },
|
|
5470
|
+
{ key: "HANOMAN_CLAUDE_BIN", group: "claude", label: "Biner claude", kind: "path", apply: "new-session", category: "knob", default: "claude" },
|
|
5471
|
+
// codex (SPEC-338 · ADR-0074)
|
|
5472
|
+
{ key: "HANOMAN_CODEX_BIN", group: "claude", label: "Biner codex", kind: "path", apply: "new-session", category: "knob", default: "codex" },
|
|
5473
|
+
{
|
|
5474
|
+
key: "CLAUDE_CONFIG_DIR",
|
|
5475
|
+
group: "claude",
|
|
5476
|
+
label: "Dir config Claude",
|
|
5477
|
+
kind: "path",
|
|
5478
|
+
apply: "new-session",
|
|
5479
|
+
category: "knob",
|
|
5480
|
+
help: "Default ~/.claude. Sumber .credentials.json untuk panel usage/limit."
|
|
5481
|
+
},
|
|
5482
|
+
// vps
|
|
5483
|
+
{ key: "HANOMAN_SSH_KEY_DIR", group: "vps", label: "Dir key SSH", kind: "path", apply: "new-session", category: "knob", help: "Default ~/.hanoman." },
|
|
5484
|
+
{ key: "HANOMAN_SSH_BIN", group: "vps", label: "Biner ssh", kind: "path", apply: "new-session", category: "knob", default: "ssh" },
|
|
5485
|
+
// runtime
|
|
5486
|
+
{ key: "HANOMAN_EVENTS_TICK_MS", group: "runtime", label: "Interval events (ms)", kind: "int", apply: "live", category: "knob", default: "1000", min: 100 },
|
|
5487
|
+
{ key: "HANOMAN_UPDATE_FETCH", group: "runtime", label: "Deteksi update saat boot", kind: "bool", apply: "live", category: "knob", default: "1" },
|
|
5488
|
+
// SPEC-398 · ADR-0087 · deteksi update kini membandingkan semver dengan registry npm, bukan
|
|
5489
|
+
// menghitung commit di repo git (HANOMAN_REPO_ROOT dicabut bersama jalur git itu).
|
|
5490
|
+
{
|
|
5491
|
+
key: "HANOMAN_NPM_REGISTRY",
|
|
5492
|
+
group: "runtime",
|
|
5493
|
+
label: "Registry npm",
|
|
5494
|
+
kind: "string",
|
|
5495
|
+
apply: "live",
|
|
5496
|
+
category: "knob",
|
|
5497
|
+
default: "https://registry.npmjs.org",
|
|
5498
|
+
help: "Sumber versi terbaru paket `hanoman`."
|
|
5499
|
+
},
|
|
5500
|
+
{
|
|
5501
|
+
key: "HANOMAN_TMUX_SOCKET",
|
|
5502
|
+
group: "runtime",
|
|
5503
|
+
label: "Socket tmux",
|
|
5504
|
+
kind: "string",
|
|
5505
|
+
apply: "restart",
|
|
5506
|
+
category: "knob",
|
|
5507
|
+
default: "hanoman",
|
|
5508
|
+
help: "Mengubah ini TIDAK memindahkan sesi tmux yang sudah hidup \u2014 berlaku setelah restart."
|
|
5509
|
+
},
|
|
5510
|
+
// gitGraph (SPEC-233 · preferensi tampilan git graph; semua live, dikonsumsi client)
|
|
5511
|
+
{ key: "gitGraph.style", group: "gitGraph", label: "Gaya graph", kind: "string", apply: "live", category: "knob", default: "rounded", help: "rounded | angular" },
|
|
5512
|
+
{ key: "gitGraph.colours", group: "gitGraph", label: "Warna lane (CSV)", kind: "string", apply: "live", category: "knob", help: "Daftar warna hex dipisah koma; kosong = palet bawaan." },
|
|
5513
|
+
{ key: "gitGraph.dateType", group: "gitGraph", label: "Jenis tanggal", kind: "string", apply: "live", category: "knob", default: "author", help: "author | commit" },
|
|
5514
|
+
{ key: "gitGraph.commitsInitialLoad", group: "gitGraph", label: "Muat awal", kind: "int", apply: "live", category: "knob", default: "200", min: 1 },
|
|
5515
|
+
{ key: "gitGraph.commitsLoadMore", group: "gitGraph", label: "Muat lagi", kind: "int", apply: "live", category: "knob", default: "100", min: 1 },
|
|
5516
|
+
{ key: "gitGraph.showRemoteBranches", group: "gitGraph", label: "Tampilkan remote", kind: "bool", apply: "live", category: "knob", default: "1" },
|
|
5517
|
+
{ key: "gitGraph.showTags", group: "gitGraph", label: "Tampilkan tag", kind: "bool", apply: "live", category: "knob", default: "1" },
|
|
5518
|
+
{ key: "gitGraph.showStashes", group: "gitGraph", label: "Tampilkan stash", kind: "bool", apply: "live", category: "knob", default: "1" },
|
|
5519
|
+
{ key: "gitGraph.showUncommitted", group: "gitGraph", label: "Tampilkan uncommitted", kind: "bool", apply: "live", category: "knob", default: "1" },
|
|
5520
|
+
{ key: "gitGraph.muteMergeCommits", group: "gitGraph", label: "Redupkan merge commit", kind: "bool", apply: "live", category: "knob", default: "1" },
|
|
5521
|
+
{ key: "gitGraph.fetchAvatars", group: "gitGraph", label: "Ambil avatar (gravatar)", kind: "bool", apply: "live", category: "knob", default: "0", help: "Jaringan eksternal ke gravatar.com." },
|
|
5522
|
+
{ key: "gitGraph.combineLocalRemote", group: "gitGraph", label: "Gabung label local+remote", kind: "bool", apply: "live", category: "knob", default: "0" },
|
|
5523
|
+
{ key: "gitGraph.markdown", group: "gitGraph", label: "Render markdown pesan", kind: "bool", apply: "live", category: "knob", default: "1" },
|
|
5524
|
+
{ key: "gitGraph.emoji", group: "gitGraph", label: "Render emoji shortcode", kind: "bool", apply: "live", category: "knob", default: "1" },
|
|
5525
|
+
{ 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" },
|
|
5526
|
+
// bootstrap (read-only)
|
|
5527
|
+
{ key: "DATABASE_URL", group: "bootstrap", label: "DATABASE_URL", kind: "secret", apply: "restart", category: "bootstrap" },
|
|
5528
|
+
{ key: "TEST_DATABASE_URL", group: "bootstrap", label: "TEST_DATABASE_URL", kind: "secret", apply: "restart", category: "bootstrap" },
|
|
5529
|
+
{ key: "PORT", group: "bootstrap", label: "PORT", kind: "int", apply: "restart", category: "bootstrap", default: "8787" },
|
|
5530
|
+
{ key: "HOST", group: "bootstrap", label: "HOST", kind: "string", apply: "restart", category: "bootstrap", default: "127.0.0.1" },
|
|
5531
|
+
{ key: "NODE_ENV", group: "bootstrap", label: "NODE_ENV", kind: "string", apply: "restart", category: "bootstrap" },
|
|
5532
|
+
// SPEC-398 · ADR-0086/0087 · lokasi data & aset, dibaca sekali saat boot (CLI yang menyetelnya).
|
|
5533
|
+
{ key: "HANOMAN_HOME", group: "bootstrap", label: "HANOMAN_HOME", kind: "path", apply: "restart", category: "bootstrap" },
|
|
5534
|
+
{ key: "HANOMAN_WEB_DIR", group: "bootstrap", label: "HANOMAN_WEB_DIR", kind: "path", apply: "restart", category: "bootstrap" }
|
|
5535
|
+
];
|
|
5536
|
+
BY_KEY = new Map(CONFIG_REGISTRY.map((e) => [e.key, e]));
|
|
5537
|
+
}
|
|
5538
|
+
});
|
|
5539
|
+
|
|
5540
|
+
// ../shared/src/semver.ts
|
|
5541
|
+
function parse(v) {
|
|
5542
|
+
const m = RE.exec(v.trim());
|
|
5543
|
+
return m ? { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ?? null } : null;
|
|
5544
|
+
}
|
|
5545
|
+
function preKey(pre) {
|
|
5546
|
+
return pre.split(".").map((s) => /^\d+$/.test(s) ? s.padStart(12, "0") : s).join(".");
|
|
5547
|
+
}
|
|
5548
|
+
function compareSemver(a, b) {
|
|
5549
|
+
const pa = parse(a), pb = parse(b);
|
|
5550
|
+
if (!pa || !pb) return 0;
|
|
5551
|
+
for (let i = 0; i < 3; i++) {
|
|
5552
|
+
const d = pa.nums[i] - pb.nums[i];
|
|
5553
|
+
if (d !== 0) return d < 0 ? -1 : 1;
|
|
5554
|
+
}
|
|
5555
|
+
if (pa.pre === pb.pre) return 0;
|
|
5556
|
+
if (pa.pre === null) return 1;
|
|
5557
|
+
if (pb.pre === null) return -1;
|
|
5558
|
+
const ka = preKey(pa.pre), kb = preKey(pb.pre);
|
|
5559
|
+
return ka < kb ? -1 : ka > kb ? 1 : 0;
|
|
5560
|
+
}
|
|
5561
|
+
var RE;
|
|
5562
|
+
var init_semver = __esm({
|
|
5563
|
+
"../shared/src/semver.ts"() {
|
|
5564
|
+
"use strict";
|
|
5565
|
+
RE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/;
|
|
5566
|
+
}
|
|
5567
|
+
});
|
|
5568
|
+
|
|
5569
|
+
// ../shared/src/index.ts
|
|
5570
|
+
var init_src2 = __esm({
|
|
5571
|
+
"../shared/src/index.ts"() {
|
|
5572
|
+
"use strict";
|
|
5573
|
+
init_enums();
|
|
5574
|
+
init_entities();
|
|
5575
|
+
init_agent();
|
|
5576
|
+
init_lead();
|
|
5577
|
+
init_dto();
|
|
5578
|
+
init_api();
|
|
5579
|
+
init_coverage();
|
|
5580
|
+
init_ticket_status();
|
|
5581
|
+
init_session_kind();
|
|
5582
|
+
init_config();
|
|
5583
|
+
init_config_registry();
|
|
5584
|
+
init_semver();
|
|
5585
|
+
}
|
|
5586
|
+
});
|
|
5587
|
+
|
|
5588
|
+
// src/layout.ts
|
|
5589
|
+
import { join as join2, resolve as resolve2 } from "node:path";
|
|
5590
|
+
function resolveLayout(distDir2, exists) {
|
|
5591
|
+
const pkg = resolve2(distDir2, "..");
|
|
5592
|
+
if (exists(join2(pkg, "prisma", "schema.prisma"))) {
|
|
5593
|
+
return {
|
|
5594
|
+
root: pkg,
|
|
5595
|
+
schema: join2(pkg, "prisma", "schema.prisma"),
|
|
5596
|
+
server: join2(pkg, "dist", "server.js"),
|
|
5597
|
+
web: exists(join2(pkg, "web")) ? join2(pkg, "web") : null
|
|
5598
|
+
};
|
|
5599
|
+
}
|
|
5600
|
+
const repo = resolve2(distDir2, "../..");
|
|
5601
|
+
if (exists(join2(repo, "server", "prisma", "schema.prisma"))) {
|
|
5602
|
+
return {
|
|
5603
|
+
root: repo,
|
|
5604
|
+
schema: join2(repo, "server", "prisma", "schema.prisma"),
|
|
5605
|
+
server: join2(repo, "server", "dist", "server.js"),
|
|
5606
|
+
web: exists(join2(repo, "src", "dist")) ? join2(repo, "src", "dist") : null
|
|
5607
|
+
};
|
|
5608
|
+
}
|
|
5609
|
+
throw new Error(`hanoman: prisma/schema.prisma tak ditemukan dari ${distDir2} \u2014 instalasi rusak?`);
|
|
5610
|
+
}
|
|
5611
|
+
var init_layout = __esm({
|
|
5612
|
+
"src/layout.ts"() {
|
|
5613
|
+
"use strict";
|
|
5614
|
+
}
|
|
5615
|
+
});
|
|
5616
|
+
|
|
5617
|
+
// src/commands/update.ts
|
|
5618
|
+
var update_exports = {};
|
|
5619
|
+
__export(update_exports, {
|
|
5620
|
+
INSTALL_ARGS: () => INSTALL_ARGS,
|
|
5621
|
+
PKG: () => PKG,
|
|
5622
|
+
default: () => update,
|
|
5623
|
+
planUpdate: () => planUpdate
|
|
5624
|
+
});
|
|
5625
|
+
import { execFileSync } from "node:child_process";
|
|
5626
|
+
function planUpdate(current, latest) {
|
|
5627
|
+
if (!latest) return { action: "unknown", current, latest: null };
|
|
5628
|
+
return compareSemver(latest, current) > 0 ? { action: "install", current, latest } : { action: "up-to-date", current, latest };
|
|
5629
|
+
}
|
|
5630
|
+
async function latestVersion(registry) {
|
|
5631
|
+
try {
|
|
5632
|
+
const res = await fetch(`${registry.replace(/\/+$/, "")}/${PKG}/latest`, { signal: AbortSignal.timeout(1e4) });
|
|
5633
|
+
if (!res.ok) return null;
|
|
5634
|
+
const body = await res.json();
|
|
5635
|
+
return typeof body.version === "string" ? body.version : null;
|
|
5636
|
+
} catch {
|
|
5637
|
+
return null;
|
|
5638
|
+
}
|
|
5639
|
+
}
|
|
5640
|
+
async function update(argv, ctx) {
|
|
5641
|
+
const check = argv.includes("--check");
|
|
5642
|
+
const current = currentVersion();
|
|
5643
|
+
const latest = await latestVersion(ctx.env.HANOMAN_NPM_REGISTRY ?? DEFAULT_REGISTRY);
|
|
5644
|
+
const plan = planUpdate(current, latest);
|
|
5645
|
+
if (plan.action === "unknown") {
|
|
5646
|
+
ctx.stderr(`hanoman ${current} \xB7 registry npm tak terjangkau \u2014 coba lagi nanti
|
|
5647
|
+
`);
|
|
5648
|
+
return 1;
|
|
5649
|
+
}
|
|
5650
|
+
if (plan.action === "up-to-date") {
|
|
5651
|
+
ctx.stdout(`hanoman ${current} sudah terkini
|
|
5652
|
+
`);
|
|
5653
|
+
return 0;
|
|
5654
|
+
}
|
|
5655
|
+
ctx.stdout(`hanoman ${plan.current} \u2192 ${plan.latest}
|
|
5656
|
+
`);
|
|
5657
|
+
if (check) {
|
|
5658
|
+
ctx.stdout(`jalankan: npm ${INSTALL_ARGS.join(" ")}
|
|
5659
|
+
`);
|
|
5660
|
+
return 0;
|
|
5661
|
+
}
|
|
5662
|
+
try {
|
|
5663
|
+
execFileSync("npm", [...INSTALL_ARGS], { stdio: "inherit" });
|
|
5664
|
+
} catch {
|
|
5665
|
+
ctx.stderr("npm i -g gagal \u2014 jalankan manual (mungkin butuh sudo)\n");
|
|
5666
|
+
return 1;
|
|
5667
|
+
}
|
|
5668
|
+
ctx.stdout(`terpasang hanoman ${plan.latest} \xB7 restart instance yang berjalan
|
|
5669
|
+
`);
|
|
5670
|
+
return 0;
|
|
5671
|
+
}
|
|
5672
|
+
var PKG, INSTALL_ARGS, DEFAULT_REGISTRY;
|
|
5673
|
+
var init_update = __esm({
|
|
5674
|
+
"src/commands/update.ts"() {
|
|
5312
5675
|
"use strict";
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
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
|
-
};
|
|
5676
|
+
init_src2();
|
|
5677
|
+
init_router();
|
|
5678
|
+
PKG = "hanoman";
|
|
5679
|
+
INSTALL_ARGS = ["i", "-g", `${PKG}@latest`];
|
|
5680
|
+
DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
5476
5681
|
}
|
|
5477
5682
|
});
|
|
5478
5683
|
|
|
5479
|
-
//
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5684
|
+
// src/commands/start.ts
|
|
5685
|
+
var start_exports = {};
|
|
5686
|
+
__export(start_exports, {
|
|
5687
|
+
MAX_UPDATE_RESTARTS: () => MAX_UPDATE_RESTARTS,
|
|
5688
|
+
applyMigrations: () => applyMigrations,
|
|
5689
|
+
default: () => start,
|
|
5690
|
+
distDir: () => distDir,
|
|
5691
|
+
ensurePrismaClient: () => ensurePrismaClient,
|
|
5692
|
+
ensureSpawnHelpersExecutable: () => ensureSpawnHelpersExecutable,
|
|
5693
|
+
installLatest: () => installLatest,
|
|
5694
|
+
migrateFailureHint: () => migrateFailureHint,
|
|
5695
|
+
parseStartArgs: () => parseStartArgs,
|
|
5696
|
+
planSupervisorStep: () => planSupervisorStep,
|
|
5697
|
+
prismaClientUsable: () => prismaClientUsable,
|
|
5698
|
+
repairSpawnHelper: () => repairSpawnHelper,
|
|
5699
|
+
serverEnv: () => serverEnv,
|
|
5700
|
+
spawnHelperPaths: () => spawnHelperPaths
|
|
5701
|
+
});
|
|
5702
|
+
import { spawn, execFileSync as execFileSync2 } from "node:child_process";
|
|
5703
|
+
import { createRequire } from "node:module";
|
|
5704
|
+
import { existsSync, mkdirSync, readdirSync, statSync, chmodSync } from "node:fs";
|
|
5705
|
+
import { dirname as dirname2, join as join3, resolve as resolvePath } from "node:path";
|
|
5706
|
+
import { fileURLToPath } from "node:url";
|
|
5707
|
+
function parseStartArgs(argv) {
|
|
5708
|
+
const out = { port: null, host: null, db: null, migrate: true };
|
|
5709
|
+
const value = (i, flag, inline) => {
|
|
5710
|
+
const v = inline ?? argv[i + 1];
|
|
5711
|
+
if (v === void 0 || v.startsWith("--")) throw new Error(`${flag} butuh nilai`);
|
|
5712
|
+
return v;
|
|
5713
|
+
};
|
|
5714
|
+
for (let i = 0; i < argv.length; i++) {
|
|
5715
|
+
const raw = argv[i];
|
|
5716
|
+
const eq = raw.indexOf("=");
|
|
5717
|
+
const flag = eq === -1 ? raw : raw.slice(0, eq);
|
|
5718
|
+
const inline = eq === -1 ? void 0 : raw.slice(eq + 1);
|
|
5719
|
+
if (flag === "--no-migrate") {
|
|
5720
|
+
out.migrate = false;
|
|
5721
|
+
continue;
|
|
5722
|
+
}
|
|
5723
|
+
if (flag === "--port") {
|
|
5724
|
+
const v = value(i, "--port", inline);
|
|
5725
|
+
const n = Number(v);
|
|
5726
|
+
if (!Number.isInteger(n) || n <= 0) throw new Error(`--port harus angka, dapat "${v}"`);
|
|
5727
|
+
out.port = n;
|
|
5728
|
+
if (inline === void 0) i++;
|
|
5729
|
+
continue;
|
|
5730
|
+
}
|
|
5731
|
+
if (flag === "--host") {
|
|
5732
|
+
out.host = value(i, "--host", inline);
|
|
5733
|
+
if (inline === void 0) i++;
|
|
5734
|
+
continue;
|
|
5735
|
+
}
|
|
5736
|
+
if (flag === "--db") {
|
|
5737
|
+
out.db = value(i, "--db", inline);
|
|
5738
|
+
if (inline === void 0) i++;
|
|
5739
|
+
continue;
|
|
5740
|
+
}
|
|
5741
|
+
throw new Error(`argumen tak dikenal untuk start: ${raw}`);
|
|
5742
|
+
}
|
|
5743
|
+
return out;
|
|
5486
5744
|
}
|
|
5487
|
-
function
|
|
5488
|
-
return
|
|
5745
|
+
function distDir() {
|
|
5746
|
+
return dirname2(fileURLToPath(import.meta.url));
|
|
5489
5747
|
}
|
|
5490
|
-
function
|
|
5491
|
-
const
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5748
|
+
function runPrisma(args, dbUrl) {
|
|
5749
|
+
const prismaCli = prismaCliPath(createRequire(import.meta.url).resolve);
|
|
5750
|
+
try {
|
|
5751
|
+
const out = execFileSync2(process.execPath, [prismaCli, ...args], {
|
|
5752
|
+
env: { ...process.env, DATABASE_URL: dbUrl },
|
|
5753
|
+
encoding: "utf8",
|
|
5754
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
5755
|
+
});
|
|
5756
|
+
process.stdout.write(out);
|
|
5757
|
+
return out;
|
|
5758
|
+
} catch (e) {
|
|
5759
|
+
const err = e;
|
|
5760
|
+
const output = `${err.stdout ?? ""}${err.stderr ?? ""}`;
|
|
5761
|
+
process.stderr.write(output);
|
|
5762
|
+
throw Object.assign(new Error("prisma gagal"), { output });
|
|
5501
5763
|
}
|
|
5502
|
-
return out.join("/");
|
|
5503
5764
|
}
|
|
5504
|
-
function
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
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)));
|
|
5765
|
+
function migrateFailureHint(output, dbFile) {
|
|
5766
|
+
if (!output.includes("P3005")) return null;
|
|
5767
|
+
return `hanoman: berkas DB ${dbFile} sudah berisi tabel, tapi tak punya riwayat migrasi hanoman.
|
|
5768
|
+
Biasanya ia bukan DB hanoman versi ini \u2014 mis. sisa prototipe lama atau berkas tool lain.
|
|
5769
|
+
Pilih salah satu:
|
|
5770
|
+
\u2022 Pindahkan berkas itu, lalu jalankan ulang: mv "${dbFile}" "${dbFile}.lama"
|
|
5771
|
+
\u2022 Pakai berkas lain: hanoman --db /path/baru.db (atau HANOMAN_DATABASE_URL=file:/path/baru.db)
|
|
5772
|
+
Isi berkas lama tidak diubah oleh hanoman \u2014 periksa dulu sebelum menghapusnya.`;
|
|
5523
5773
|
}
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
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);
|
|
5774
|
+
function applyMigrations(schema, dbUrl) {
|
|
5775
|
+
runPrisma(["migrate", "deploy", "--schema", schema], dbUrl);
|
|
5776
|
+
}
|
|
5777
|
+
async function prismaClientUsable() {
|
|
5778
|
+
try {
|
|
5779
|
+
const { PrismaClient } = await import("@prisma/client");
|
|
5780
|
+
new PrismaClient();
|
|
5781
|
+
return true;
|
|
5782
|
+
} catch {
|
|
5783
|
+
return false;
|
|
5558
5784
|
}
|
|
5559
|
-
}
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
});
|
|
5785
|
+
}
|
|
5786
|
+
async function ensurePrismaClient(schema, dbUrl, ctx) {
|
|
5787
|
+
if (await prismaClientUsable()) return true;
|
|
5788
|
+
ctx.stdout("hanoman \xB7 menyiapkan Prisma client (sekali per instalasi)\n");
|
|
5789
|
+
try {
|
|
5790
|
+
runPrisma(["generate", "--schema", schema], dbUrl);
|
|
5791
|
+
return true;
|
|
5792
|
+
} catch {
|
|
5793
|
+
ctx.stderr("hanoman: `prisma generate` gagal \u2014 jalankan manual di direktori paket, atau pasang ulang tanpa --ignore-scripts\n");
|
|
5794
|
+
return false;
|
|
5570
5795
|
}
|
|
5571
|
-
}
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
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]));
|
|
5796
|
+
}
|
|
5797
|
+
function spawnHelperPaths(ptyDir, listDir, exists) {
|
|
5798
|
+
const dirs = [join3(ptyDir, "build", "Release")];
|
|
5799
|
+
for (const name of listDir(join3(ptyDir, "prebuilds"))) dirs.push(join3(ptyDir, "prebuilds", name));
|
|
5800
|
+
return dirs.map((d) => join3(d, "spawn-helper")).filter(exists);
|
|
5801
|
+
}
|
|
5802
|
+
function ensureSpawnHelpersExecutable(paths2, ops) {
|
|
5803
|
+
const fixed = [];
|
|
5804
|
+
for (const p of paths2) {
|
|
5805
|
+
try {
|
|
5806
|
+
const mode = ops.mode(p) & 4095;
|
|
5807
|
+
if ((mode & 73) === 73) continue;
|
|
5808
|
+
ops.chmod(p, mode | 73);
|
|
5809
|
+
fixed.push(p);
|
|
5810
|
+
} catch {
|
|
5811
|
+
}
|
|
5687
5812
|
}
|
|
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;
|
|
5813
|
+
return fixed;
|
|
5694
5814
|
}
|
|
5695
|
-
function
|
|
5696
|
-
|
|
5815
|
+
function repairSpawnHelper(ctx) {
|
|
5816
|
+
let ptyDir;
|
|
5817
|
+
try {
|
|
5818
|
+
ptyDir = dirname2(createRequire(import.meta.url).resolve("node-pty/package.json"));
|
|
5819
|
+
} catch {
|
|
5820
|
+
return;
|
|
5821
|
+
}
|
|
5822
|
+
const paths2 = spawnHelperPaths(ptyDir, (d) => {
|
|
5823
|
+
try {
|
|
5824
|
+
return readdirSync(d);
|
|
5825
|
+
} catch {
|
|
5826
|
+
return [];
|
|
5827
|
+
}
|
|
5828
|
+
}, existsSync);
|
|
5829
|
+
const fixed = ensureSpawnHelpersExecutable(paths2, {
|
|
5830
|
+
mode: (p) => statSync(p).mode,
|
|
5831
|
+
chmod: (p, m) => chmodSync(p, m)
|
|
5832
|
+
});
|
|
5833
|
+
if (fixed.length) ctx.stdout("hanoman \xB7 memperbaiki izin `spawn-helper` node-pty (sekali per instalasi)\n");
|
|
5697
5834
|
}
|
|
5698
|
-
function
|
|
5699
|
-
|
|
5700
|
-
if (
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5835
|
+
function planSupervisorStep(code, restartsUsed) {
|
|
5836
|
+
if (code !== UPDATE_RESTART_EXIT) return { action: "exit", code };
|
|
5837
|
+
if (restartsUsed >= MAX_UPDATE_RESTARTS) return { action: "exit", code };
|
|
5838
|
+
return { action: "update" };
|
|
5839
|
+
}
|
|
5840
|
+
function serverEnv(o) {
|
|
5841
|
+
return {
|
|
5842
|
+
NODE_ENV: "production",
|
|
5843
|
+
DATABASE_URL: o.dbUrl,
|
|
5844
|
+
PORT: String(o.port),
|
|
5845
|
+
HOST: o.host,
|
|
5846
|
+
HANOMAN_HOME: o.home,
|
|
5847
|
+
HANOMAN_SUPERVISOR: "1",
|
|
5848
|
+
...o.web ? { HANOMAN_WEB_DIR: o.web } : {}
|
|
5849
|
+
};
|
|
5850
|
+
}
|
|
5851
|
+
function installLatest() {
|
|
5852
|
+
try {
|
|
5853
|
+
execFileSync2("npm", [...INSTALL_ARGS], { stdio: "inherit" });
|
|
5854
|
+
return { ok: true };
|
|
5855
|
+
} catch (e) {
|
|
5856
|
+
return { ok: false, reason: e.message || "npm i -g gagal" };
|
|
5704
5857
|
}
|
|
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
5858
|
}
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
"
|
|
5714
|
-
|
|
5715
|
-
|
|
5859
|
+
function runServer(serverJs, env) {
|
|
5860
|
+
const child = spawn(process.execPath, [serverJs], { stdio: "inherit", env: { ...process.env, ...env } });
|
|
5861
|
+
const handlers = ["SIGINT", "SIGTERM"].map((sig) => [sig, () => child.kill(sig)]);
|
|
5862
|
+
for (const [sig, h] of handlers) process.on(sig, h);
|
|
5863
|
+
return new Promise((res) => child.on("exit", (code) => {
|
|
5864
|
+
for (const [sig, h] of handlers) process.off(sig, h);
|
|
5865
|
+
res(code ?? 0);
|
|
5866
|
+
}));
|
|
5867
|
+
}
|
|
5868
|
+
async function start(argv, ctx) {
|
|
5869
|
+
let opts;
|
|
5870
|
+
try {
|
|
5871
|
+
opts = parseStartArgs(argv);
|
|
5872
|
+
} catch (e) {
|
|
5873
|
+
ctx.stderr(`${e.message}
|
|
5874
|
+
`);
|
|
5875
|
+
return 2;
|
|
5716
5876
|
}
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5877
|
+
let layout;
|
|
5878
|
+
let dbUrl;
|
|
5879
|
+
try {
|
|
5880
|
+
layout = resolveLayout(distDir(), existsSync);
|
|
5881
|
+
dbUrl = opts.db ? `file:${resolvePath(opts.db)}` : resolveDbUrl(ctx.env, dirname2(layout.schema));
|
|
5882
|
+
} catch (e) {
|
|
5883
|
+
ctx.stderr(`${e.message}
|
|
5884
|
+
`);
|
|
5885
|
+
return 1;
|
|
5886
|
+
}
|
|
5887
|
+
const notice = dbUrlNotice(ctx.env);
|
|
5888
|
+
if (notice) ctx.stderr(`${notice}
|
|
5889
|
+
`);
|
|
5890
|
+
const home = resolveHome(ctx.env);
|
|
5891
|
+
mkdirSync(home, { recursive: true });
|
|
5892
|
+
mkdirSync(dirname2(dbFilePath(dbUrl)), { recursive: true });
|
|
5893
|
+
if (!existsSync(layout.server)) {
|
|
5894
|
+
ctx.stderr(`hanoman: bundle server tak ada di ${layout.server} \u2014 jalankan \`pnpm build\` dulu
|
|
5895
|
+
`);
|
|
5896
|
+
return 1;
|
|
5897
|
+
}
|
|
5898
|
+
if (!await ensurePrismaClient(layout.schema, dbUrl, ctx)) return 1;
|
|
5899
|
+
repairSpawnHelper(ctx);
|
|
5900
|
+
if (opts.migrate) {
|
|
5901
|
+
ctx.stdout(`hanoman \xB7 menerapkan migrasi ke ${dbFilePath(dbUrl)}
|
|
5902
|
+
`);
|
|
5903
|
+
try {
|
|
5904
|
+
applyMigrations(layout.schema, dbUrl);
|
|
5905
|
+
} catch (e) {
|
|
5906
|
+
const hint = migrateFailureHint(String(e.output ?? ""), dbFilePath(dbUrl));
|
|
5907
|
+
ctx.stderr(hint ? `
|
|
5908
|
+
${hint}
|
|
5909
|
+
` : "hanoman: `prisma migrate deploy` gagal \u2014 lihat keluaran di atas\n");
|
|
5910
|
+
return 1;
|
|
5911
|
+
}
|
|
5912
|
+
}
|
|
5913
|
+
const port = opts.port ?? Number(ctx.env.PORT ?? 8787);
|
|
5914
|
+
const host = opts.host ?? ctx.env.HOST ?? "127.0.0.1";
|
|
5915
|
+
ctx.stdout(`hanoman \xB7 http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}
|
|
5916
|
+
`);
|
|
5917
|
+
const env = serverEnv({ dbUrl, port, host, home, web: layout.web ?? null });
|
|
5918
|
+
let restartsUsed = 0;
|
|
5919
|
+
for (; ; ) {
|
|
5920
|
+
const code = await runServer(layout.server, env);
|
|
5921
|
+
const step = planSupervisorStep(code, restartsUsed);
|
|
5922
|
+
if (step.action === "exit") {
|
|
5923
|
+
if (code === UPDATE_RESTART_EXIT) {
|
|
5924
|
+
ctx.stderr(`hanoman: jatah update-restart (${MAX_UPDATE_RESTARTS}) habis \u2014 keluar tanpa memasang
|
|
5925
|
+
`);
|
|
5926
|
+
}
|
|
5927
|
+
return step.code;
|
|
5928
|
+
}
|
|
5929
|
+
restartsUsed++;
|
|
5930
|
+
ctx.stdout(`hanoman \xB7 memasang versi terbaru dari npm (${restartsUsed}/${MAX_UPDATE_RESTARTS})
|
|
5931
|
+
`);
|
|
5932
|
+
const res = installLatest();
|
|
5933
|
+
if (!res.ok) {
|
|
5934
|
+
ctx.stderr(`hanoman: update gagal \u2014 ${res.reason}
|
|
5935
|
+
`);
|
|
5936
|
+
ctx.stdout("hanoman \xB7 menjalankan ulang versi yang ada\n");
|
|
5937
|
+
continue;
|
|
5938
|
+
}
|
|
5939
|
+
try {
|
|
5940
|
+
runPrisma(["generate", "--schema", layout.schema], dbUrl);
|
|
5941
|
+
} catch {
|
|
5942
|
+
ctx.stderr("hanoman: `prisma generate` sesudah update gagal \u2014 lanjut; server anak yang akan mengeluh\n");
|
|
5943
|
+
}
|
|
5944
|
+
if (opts.migrate) {
|
|
5945
|
+
try {
|
|
5946
|
+
applyMigrations(layout.schema, dbUrl);
|
|
5947
|
+
} catch (e) {
|
|
5948
|
+
const hint = migrateFailureHint(String(e.output ?? ""), dbFilePath(dbUrl));
|
|
5949
|
+
ctx.stderr(hint ? `
|
|
5950
|
+
${hint}
|
|
5951
|
+
` : "hanoman: migrasi sesudah update gagal \u2014 lihat keluaran di atas\n");
|
|
5952
|
+
return 1;
|
|
5953
|
+
}
|
|
5954
|
+
}
|
|
5955
|
+
ctx.stdout("hanoman \xB7 terpasang; menjalankan ulang\n");
|
|
5956
|
+
}
|
|
5957
|
+
}
|
|
5958
|
+
var MAX_UPDATE_RESTARTS;
|
|
5959
|
+
var init_start = __esm({
|
|
5960
|
+
"src/commands/start.ts"() {
|
|
5722
5961
|
"use strict";
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
init_coverage();
|
|
5729
|
-
init_ticket_status();
|
|
5730
|
-
init_session_kind();
|
|
5731
|
-
init_config();
|
|
5732
|
-
init_config_registry();
|
|
5733
|
-
init_semver();
|
|
5962
|
+
init_src();
|
|
5963
|
+
init_src2();
|
|
5964
|
+
init_layout();
|
|
5965
|
+
init_update();
|
|
5966
|
+
MAX_UPDATE_RESTARTS = 5;
|
|
5734
5967
|
}
|
|
5735
5968
|
});
|
|
5736
5969
|
|
|
5737
|
-
// src/commands/
|
|
5738
|
-
var
|
|
5739
|
-
__export(
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
default: () => update,
|
|
5743
|
-
planUpdate: () => planUpdate
|
|
5970
|
+
// src/commands/doctor.ts
|
|
5971
|
+
var doctor_exports = {};
|
|
5972
|
+
__export(doctor_exports, {
|
|
5973
|
+
default: () => doctor,
|
|
5974
|
+
doctorReport: () => doctorReport
|
|
5744
5975
|
});
|
|
5745
5976
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5977
|
+
import { accessSync, constants, existsSync as existsSync2 } from "node:fs";
|
|
5978
|
+
import { dirname as dirname3 } from "node:path";
|
|
5979
|
+
function doctorReport(p) {
|
|
5980
|
+
const major = Number(/^v?(\d+)/.exec(p.node)?.[1] ?? 0);
|
|
5981
|
+
const rows = [
|
|
5982
|
+
{ mark: major >= 20 ? "\u2713" : "\u2717", text: `node ${p.node} (butuh \u2265 20)`, fatal: major < 20 },
|
|
5983
|
+
{ mark: p.git ? "\u2713" : "\u2717", text: p.git ?? "git \u2014 TAK ADA (wajib: worktree per sesi)", fatal: !p.git },
|
|
5984
|
+
{ mark: p.tmux ? "\u2713" : "\u2717", text: p.tmux ?? "tmux \u2014 TAK ADA (wajib: sesi agen hidup di tmux)", fatal: !p.tmux },
|
|
5985
|
+
{ mark: p.claude ? "\u2713" : "\xB7", text: p.claude ? `claude ${p.claude}` : "claude \u2014 tak ada", fatal: false },
|
|
5986
|
+
{ mark: p.codex ? "\u2713" : "\xB7", text: p.codex ? `codex ${p.codex}` : "codex \u2014 tak ada", fatal: false },
|
|
5987
|
+
{ mark: p.homeWritable ? "\u2713" : "\u2717", text: `data dir ${p.homeWritable ? "bisa ditulis" : "TAK bisa ditulis"}`, fatal: !p.homeWritable },
|
|
5988
|
+
{ mark: p.web ? "\u2713" : "!", text: p.web ? "aset dashboard ada" : "aset dashboard tak ada \u2014 API jalan, dashboard tidak", fatal: false },
|
|
5989
|
+
{ mark: "\xB7", text: `db ${p.db}`, fatal: false }
|
|
5990
|
+
];
|
|
5991
|
+
if (!p.claude && !p.codex) {
|
|
5992
|
+
rows.push({ mark: "\u2717", text: "tak ada CLI agen (claude ATAU codex wajib ada)", fatal: true });
|
|
5993
|
+
}
|
|
5994
|
+
return { lines: rows.map((r) => ` ${r.mark} ${r.text}`), ok: !rows.some((r) => r.fatal) };
|
|
5749
5995
|
}
|
|
5750
|
-
|
|
5996
|
+
function version(bin, args) {
|
|
5751
5997
|
try {
|
|
5752
|
-
|
|
5753
|
-
if (!res.ok) return null;
|
|
5754
|
-
const body = await res.json();
|
|
5755
|
-
return typeof body.version === "string" ? body.version : null;
|
|
5998
|
+
return execFileSync3(bin, args, { encoding: "utf8", timeout: 1e4, stdio: ["ignore", "pipe", "ignore"] }).trim().split("\n")[0] ?? null;
|
|
5756
5999
|
} catch {
|
|
5757
6000
|
return null;
|
|
5758
6001
|
}
|
|
5759
6002
|
}
|
|
5760
|
-
async function
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
6003
|
+
async function doctor(_argv, ctx) {
|
|
6004
|
+
let layout;
|
|
6005
|
+
let db;
|
|
6006
|
+
try {
|
|
6007
|
+
layout = resolveLayout(distDir(), existsSync2);
|
|
6008
|
+
db = dbFilePath(resolveDbUrl(ctx.env, dirname3(layout.schema)));
|
|
6009
|
+
} catch (e) {
|
|
6010
|
+
ctx.stderr(`${e.message}
|
|
5767
6011
|
`);
|
|
5768
6012
|
return 1;
|
|
5769
6013
|
}
|
|
5770
|
-
|
|
5771
|
-
|
|
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
|
-
}
|
|
6014
|
+
const home = resolveHome(ctx.env);
|
|
6015
|
+
let homeWritable = false;
|
|
5782
6016
|
try {
|
|
5783
|
-
|
|
6017
|
+
accessSync(existsSync2(home) ? home : dirname3(home), constants.W_OK);
|
|
6018
|
+
homeWritable = true;
|
|
5784
6019
|
} catch {
|
|
5785
|
-
ctx.stderr("npm i -g gagal \u2014 jalankan manual (mungkin butuh sudo)\n");
|
|
5786
|
-
return 1;
|
|
5787
6020
|
}
|
|
5788
|
-
|
|
6021
|
+
const r = doctorReport({
|
|
6022
|
+
node: process.version,
|
|
6023
|
+
git: version("git", ["--version"]),
|
|
6024
|
+
tmux: version("tmux", ["-V"]),
|
|
6025
|
+
claude: version(ctx.env.HANOMAN_CLAUDE_BIN ?? "claude", ["--version"]),
|
|
6026
|
+
codex: version(ctx.env.HANOMAN_CODEX_BIN ?? "codex", ["--version"]),
|
|
6027
|
+
homeWritable,
|
|
6028
|
+
web: layout.web !== null,
|
|
6029
|
+
db
|
|
6030
|
+
});
|
|
6031
|
+
ctx.stdout(`hanoman doctor
|
|
6032
|
+
${r.lines.join("\n")}
|
|
5789
6033
|
`);
|
|
5790
|
-
|
|
6034
|
+
const notice = dbUrlNotice(ctx.env);
|
|
6035
|
+
if (notice) ctx.stdout(`
|
|
6036
|
+
${notice}
|
|
6037
|
+
`);
|
|
6038
|
+
if (!r.ok) ctx.stderr("\nada prasyarat yang belum terpenuhi \u2014 hanoman tak akan bisa menjalankan sesi\n");
|
|
6039
|
+
return r.ok ? 0 : 1;
|
|
5791
6040
|
}
|
|
5792
|
-
var
|
|
5793
|
-
|
|
5794
|
-
"src/commands/update.ts"() {
|
|
6041
|
+
var init_doctor = __esm({
|
|
6042
|
+
"src/commands/doctor.ts"() {
|
|
5795
6043
|
"use strict";
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
INSTALL_ARGS = ["i", "-g", `${PKG}@latest`];
|
|
5800
|
-
DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
6044
|
+
init_src();
|
|
6045
|
+
init_layout();
|
|
6046
|
+
init_start();
|
|
5801
6047
|
}
|
|
5802
6048
|
});
|
|
5803
6049
|
|
|
5804
6050
|
// src/commands/migrate-pg.ts
|
|
5805
6051
|
var migrate_pg_exports = {};
|
|
5806
6052
|
__export(migrate_pg_exports, {
|
|
6053
|
+
INT8_OID: () => INT8_OID,
|
|
5807
6054
|
PG_ORDER: () => PG_ORDER,
|
|
5808
6055
|
chunk: () => chunk,
|
|
6056
|
+
coerceInt8: () => coerceInt8,
|
|
5809
6057
|
default: () => migratePg,
|
|
6058
|
+
isUndefinedTable: () => isUndefinedTable,
|
|
5810
6059
|
migrationSteps: () => migrationSteps,
|
|
5811
6060
|
parseMigrateArgs: () => parseMigrateArgs
|
|
5812
6061
|
});
|
|
5813
6062
|
import { existsSync as existsSync3 } from "node:fs";
|
|
5814
6063
|
import { dirname as dirname4, resolve as resolvePath2 } from "node:path";
|
|
6064
|
+
function coerceInt8(rows, fields, model) {
|
|
6065
|
+
const cols = fields.filter((f) => f.dataTypeID === INT8_OID).map((f) => f.name);
|
|
6066
|
+
if (!cols.length) return rows;
|
|
6067
|
+
return rows.map((row) => {
|
|
6068
|
+
const out = { ...row };
|
|
6069
|
+
for (const c of cols) {
|
|
6070
|
+
const v = out[c];
|
|
6071
|
+
if (v === null || v === void 0) continue;
|
|
6072
|
+
const n = Number(v);
|
|
6073
|
+
if (!Number.isSafeInteger(n)) {
|
|
6074
|
+
throw new Error(`${model}.${c} = ${String(v)} di luar jangkauan integer aman \u2014 migrasi dihentikan`);
|
|
6075
|
+
}
|
|
6076
|
+
out[c] = n;
|
|
6077
|
+
}
|
|
6078
|
+
return out;
|
|
6079
|
+
});
|
|
6080
|
+
}
|
|
6081
|
+
function isUndefinedTable(e) {
|
|
6082
|
+
return typeof e === "object" && e !== null && e.code === "42P01";
|
|
6083
|
+
}
|
|
5815
6084
|
function chunk(xs, n) {
|
|
5816
6085
|
const out = [];
|
|
5817
6086
|
for (let i = 0; i < xs.length; i += n) out.push(xs.slice(i, i + n));
|
|
@@ -5897,7 +6166,16 @@ async function migratePg(argv, ctx) {
|
|
|
5897
6166
|
}
|
|
5898
6167
|
let total = 0;
|
|
5899
6168
|
for (const model of PG_ORDER) {
|
|
5900
|
-
|
|
6169
|
+
let rows;
|
|
6170
|
+
try {
|
|
6171
|
+
const res = await pg.query(`SELECT * FROM "${model}"`);
|
|
6172
|
+
rows = coerceInt8(res.rows, res.fields, model);
|
|
6173
|
+
} catch (e) {
|
|
6174
|
+
if (!isUndefinedTable(e)) throw e;
|
|
6175
|
+
ctx.stdout(` ${"\u2014".padStart(6)} \xB7 ${model} (tak ada di sumber \u2014 dilewati)
|
|
6176
|
+
`);
|
|
6177
|
+
continue;
|
|
6178
|
+
}
|
|
5901
6179
|
total += rows.length;
|
|
5902
6180
|
if (rows.length && steps.write) {
|
|
5903
6181
|
for (const part of chunk(rows, CHUNK)) await at(model).createMany({ data: part });
|
|
@@ -5918,7 +6196,7 @@ async function migratePg(argv, ctx) {
|
|
|
5918
6196
|
await db?.$disconnect();
|
|
5919
6197
|
}
|
|
5920
6198
|
}
|
|
5921
|
-
var PG_ORDER, CHUNK, delegateKey;
|
|
6199
|
+
var PG_ORDER, CHUNK, INT8_OID, delegateKey;
|
|
5922
6200
|
var init_migrate_pg = __esm({
|
|
5923
6201
|
"src/commands/migrate-pg.ts"() {
|
|
5924
6202
|
"use strict";
|
|
@@ -5947,6 +6225,7 @@ var init_migrate_pg = __esm({
|
|
|
5947
6225
|
"SyncConflict",
|
|
5948
6226
|
"SchedulerQueueItem",
|
|
5949
6227
|
"RuntimeConfig",
|
|
6228
|
+
"LeadDecision",
|
|
5950
6229
|
"ErrorGroup",
|
|
5951
6230
|
"ErrorEvent",
|
|
5952
6231
|
"SourceMapArtifact",
|
|
@@ -5954,6 +6233,7 @@ var init_migrate_pg = __esm({
|
|
|
5954
6233
|
"TicketAttachment"
|
|
5955
6234
|
];
|
|
5956
6235
|
CHUNK = 200;
|
|
6236
|
+
INT8_OID = 20;
|
|
5957
6237
|
delegateKey = (model) => model.charAt(0).toLowerCase() + model.slice(1);
|
|
5958
6238
|
}
|
|
5959
6239
|
});
|