hanoman 0.9.27 → 0.9.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +5 -2
  2. package/dist/build-info.json +3 -3
  3. package/dist/cli.js +423 -90
  4. package/dist/server.js +3361 -1608
  5. package/docs/agent-integration.md +101 -6
  6. package/package.json +1 -1
  7. package/prisma/migrations/20261014130000_cron_report/migration.sql +19 -0
  8. package/prisma/schema.prisma +25 -0
  9. package/scripts/vps/provision.sh +26 -3
  10. package/web/assets/{DalangHanomanScreen-wJskhX1_.js → DalangHanomanScreen-BMrikKnt.js} +1 -1
  11. package/web/assets/{DocPreviewModal-ClHbRVmQ.js → DocPreviewModal-5j31WUwI.js} +1 -1
  12. package/web/assets/{DocsWorkspace-Db_g219X.js → DocsWorkspace-GkTrniF3.js} +1 -1
  13. package/web/assets/{IdeScreen-CfX1HEtj.js → IdeScreen-CAQfv1_e.js} +1 -1
  14. package/web/assets/LeadScreen-Da5-1FLe.js +1 -0
  15. package/web/assets/{ReviewScreen-DMGTLCki.js → ReviewScreen-B8KHzQpd.js} +1 -1
  16. package/web/assets/SchedulerScreen-CBd4O5kw.js +1 -0
  17. package/web/assets/SettingsScreen-BxQ3CH2D.js +62 -0
  18. package/web/assets/{TeamScreen-CS9osC8I.js → TeamScreen-P6vz88Pp.js} +1 -1
  19. package/web/assets/TerminalScreen-B_cagBZd.js +2 -0
  20. package/web/assets/TerminalScreen-BjFMJnq6.css +1 -0
  21. package/web/assets/{TriageScreen-Eh8BoPTm.js → TriageScreen-IYkxyhdm.js} +1 -1
  22. package/web/assets/{VpsScreen-CweCi934.js → VpsScreen-DFGT5S8Y.js} +2 -2
  23. package/web/assets/fields-CmVwp6QK.js +1 -0
  24. package/web/assets/{index-B8xChq6y.css → index-0T3s-I82.css} +1 -1
  25. package/web/assets/index-C-iSWHn3.js +1012 -0
  26. package/web/assets/{live-Bfx0Oehi.js → live-lSo-u7M6.js} +1 -1
  27. package/web/assets/{sched-lead-shared-DJn2D3VE.js → sched-lead-shared-BTz6aILx.js} +1 -1
  28. package/web/assets/{scheduler-CQt-VP9-.css → scheduler-D64RlGvZ.css} +1 -1
  29. package/web/assets/settings-rebase-CPawFVpp.js +1 -0
  30. package/web/index.html +2 -2
  31. package/web/assets/LeadScreen-BIpisTdG.js +0 -1
  32. package/web/assets/SchedulerScreen-CSaFiXc9.js +0 -1
  33. package/web/assets/SettingsScreen-C4chALvS.js +0 -62
  34. package/web/assets/TerminalScreen-C0fHHsUa.js +0 -2
  35. package/web/assets/TerminalScreen-D0NdFmR-.css +0 -1
  36. package/web/assets/index-Av-RfHXX.js +0 -1012
  37. package/web/assets/settings-rebase-Bbz53ceL.js +0 -1
package/dist/cli.js CHANGED
@@ -582,11 +582,11 @@ function datetimeRegex(args) {
582
582
  regex = `${regex}(${opts.join("|")})`;
583
583
  return new RegExp(`^${regex}$`);
584
584
  }
585
- function isValidIP(ip, version3) {
586
- if ((version3 === "v4" || !version3) && ipv4Regex.test(ip)) {
585
+ function isValidIP(ip, version2) {
586
+ if ((version2 === "v4" || !version2) && ipv4Regex.test(ip)) {
587
587
  return true;
588
588
  }
589
- if ((version3 === "v6" || !version3) && ipv6Regex.test(ip)) {
589
+ if ((version2 === "v6" || !version2) && ipv6Regex.test(ip)) {
590
590
  return true;
591
591
  }
592
592
  return false;
@@ -613,11 +613,11 @@ function isValidJWT(jwt, alg) {
613
613
  return false;
614
614
  }
615
615
  }
616
- function isValidCidr(ip, version3) {
617
- if ((version3 === "v4" || !version3) && ipv4CidrRegex.test(ip)) {
616
+ function isValidCidr(ip, version2) {
617
+ if ((version2 === "v4" || !version2) && ipv4CidrRegex.test(ip)) {
618
618
  return true;
619
619
  }
620
- if ((version3 === "v6" || !version3) && ipv6CidrRegex.test(ip)) {
620
+ if ((version2 === "v6" || !version2) && ipv6CidrRegex.test(ip)) {
621
621
  return true;
622
622
  }
623
623
  return false;
@@ -4133,7 +4133,7 @@ var init_enums = __esm({
4133
4133
  zDocStatus = external_exports.enum(["ok", "drift", "broken"]);
4134
4134
  zPriority = external_exports.enum(["tinggi", "sedang", "rendah"]);
4135
4135
  zProjectKind = external_exports.enum(["from-scratch", "existing"]);
4136
- zAgent = external_exports.enum(["claude", "codex"]);
4136
+ zAgent = external_exports.enum(["claude", "codex", "antigravity"]);
4137
4137
  zSeverity = external_exports.enum(["critical", "major", "minor"]);
4138
4138
  zTicketCategory = external_exports.enum(["bug", "fitur", "pertanyaan", "lainnya"]);
4139
4139
  zTicketStatus = external_exports.enum(["new", "accepted", "rejected"]);
@@ -4210,6 +4210,7 @@ var init_method_catalog = __esm({
4210
4210
  exitSkills: [VERIFICATION_GATE],
4211
4211
  requires: ["superpowers"],
4212
4212
  install: {
4213
+ antigravity: [],
4213
4214
  claude: [
4214
4215
  "claude plugin marketplace add obra/superpowers-marketplace",
4215
4216
  "claude plugin install superpowers@superpowers-marketplace"
@@ -4244,6 +4245,7 @@ var init_method_catalog = __esm({
4244
4245
  // dari sana (INVARIAN 2). codex belum punya plugin native mattpocock — jalur resminya
4245
4246
  // `npx skills`, dan ia INTERAKTIF; itu justru alasan pemasangan hidup di pane yang ditonton.
4246
4247
  install: {
4248
+ antigravity: [],
4247
4249
  claude: [
4248
4250
  "claude plugin install mattpocock-skills",
4249
4251
  "claude plugin marketplace add obra/superpowers-marketplace",
@@ -4280,6 +4282,7 @@ var init_method_catalog = __esm({
4280
4282
  requires: ["agent-skills", "superpowers"],
4281
4283
  // Manifest upstream: marketplace Claude = addy-agent-skills, Codex = agent-skills.
4282
4284
  install: {
4285
+ antigravity: [],
4283
4286
  claude: [
4284
4287
  "claude plugin marketplace add addyosmani/agent-skills",
4285
4288
  "claude plugin install agent-skills@addy-agent-skills",
@@ -4314,15 +4317,18 @@ function methodStatus(m, agent, installed) {
4314
4317
  method: m.id,
4315
4318
  label: m.label,
4316
4319
  agent,
4317
- ready: missingPackages.length === 0 && missingSkills.length === 0,
4320
+ ...agent === "antigravity" ? { available: false, availabilityReason: ANTIGRAVITY_METHOD_UNAVAILABLE_REASON } : {},
4321
+ ready: agent !== "antigravity" && missingPackages.length === 0 && missingSkills.length === 0,
4318
4322
  missingPackages,
4319
4323
  missingSkills,
4320
4324
  install: [...m.install[agent]]
4321
4325
  };
4322
4326
  }
4327
+ var ANTIGRAVITY_METHOD_UNAVAILABLE_REASON;
4323
4328
  var init_method_status = __esm({
4324
4329
  "../shared/src/method-status.ts"() {
4325
4330
  "use strict";
4331
+ ANTIGRAVITY_METHOD_UNAVAILABLE_REASON = "Installer metode Antigravity belum terverifikasi dari upstream";
4326
4332
  }
4327
4333
  });
4328
4334
 
@@ -4342,8 +4348,29 @@ var init_agent_engine = __esm({
4342
4348
  }
4343
4349
  });
4344
4350
 
4351
+ // ../shared/src/antigravity.ts
4352
+ function isAntigravityChildTier(value) {
4353
+ return ANTIGRAVITY_CHILD_TIERS.some((tier) => tier === value);
4354
+ }
4355
+ var ANTIGRAVITY_CHILD_TIERS, BUILTIN_ANTIGRAVITY_RUNTIME_DEFAULTS, ANTIGRAVITY_MODELS;
4356
+ var init_antigravity = __esm({
4357
+ "../shared/src/antigravity.ts"() {
4358
+ "use strict";
4359
+ ANTIGRAVITY_CHILD_TIERS = ["inherit", "flash", "pro"];
4360
+ BUILTIN_ANTIGRAVITY_RUNTIME_DEFAULTS = {
4361
+ model: "gemini-3.8-flash-high",
4362
+ effort: "high"
4363
+ };
4364
+ ANTIGRAVITY_MODELS = [{
4365
+ id: BUILTIN_ANTIGRAVITY_RUNTIME_DEFAULTS.model,
4366
+ label: "Gemini 3.8 Flash High",
4367
+ efforts: [BUILTIN_ANTIGRAVITY_RUNTIME_DEFAULTS.effort]
4368
+ }];
4369
+ }
4370
+ });
4371
+
4345
4372
  // ../shared/src/telegram.ts
4346
- var zTelegramSettings, TELEGRAM_DEFAULTS, zTelegramReadiness, zTelegramGatewayStatus, zTelegramMemoryRecord, zTelegramChatContext, TELEGRAM_REPLY_KINDS, zTelegramReplyKind, zTelegramConfirmationRequest, zTelegramReplyInput, zTelegramAuditRecord, zTerminalSteerInput;
4373
+ var zTelegramSettings, TELEGRAM_DEFAULTS, zTelegramReadiness, zTelegramGatewayStatus, zTelegramMemoryRecord, zTelegramChatContext, TELEGRAM_REPLY_KINDS, zTelegramReplyKind, zTelegramConfirmationRequest, zTelegramReplyInput, zTelegramAuditRecord, zTerminalSteerInput, SESSION_NAME_MAX, zTerminalRenameInput;
4347
4374
  var init_telegram = __esm({
4348
4375
  "../shared/src/telegram.ts"() {
4349
4376
  "use strict";
@@ -4440,6 +4467,8 @@ var init_telegram = __esm({
4440
4467
  zTerminalSteerInput = external_exports.object({
4441
4468
  text: external_exports.string().trim().min(1).max(16e3)
4442
4469
  });
4470
+ SESSION_NAME_MAX = 80;
4471
+ zTerminalRenameInput = external_exports.object({ name: external_exports.string().max(SESSION_NAME_MAX * 4) });
4443
4472
  }
4444
4473
  });
4445
4474
 
@@ -4702,10 +4731,20 @@ var init_runtime_defaults = __esm({
4702
4731
  model: zRuntimeDefaultState.default("seeded"),
4703
4732
  effort: zRuntimeDefaultState.default("seeded")
4704
4733
  }).default({}),
4734
+ antigravity: external_exports.object({
4735
+ model: zRuntimeDefaultState.default("seeded"),
4736
+ effort: zRuntimeDefaultState.default("seeded")
4737
+ }).default({}),
4705
4738
  orchestration: external_exports.record(external_exports.string(), zRuntimeDefaultState).default({})
4706
4739
  });
4707
4740
  cell = (model, effort) => ({ model, effort });
4708
- flow = (claude, codex, enabled = true) => ({ enabled, executeMode: "inline", claude, codex });
4741
+ flow = (claude, codex, enabled = true) => ({
4742
+ enabled,
4743
+ executeMode: "inline",
4744
+ claude,
4745
+ codex,
4746
+ antigravity: Object.fromEntries(Object.keys(claude).map((phase) => [phase, { model: "inherit", effort: null }]))
4747
+ });
4709
4748
  BUILTIN_ORCHESTRATION_DEFAULTS = {
4710
4749
  feature: flow(
4711
4750
  {
@@ -4813,7 +4852,7 @@ var init_runtime_defaults = __esm({
4813
4852
  };
4814
4853
  seededFlows = Object.fromEntries(ORCHESTRATION_FLOWS.flatMap((flow2) => [
4815
4854
  [`${flow2}.enabled`, "seeded"],
4816
- ...["claude", "codex"].flatMap((runtime) => FLOW_PHASES[flow2].flatMap((phase) => [
4855
+ ...["claude", "codex", "antigravity"].flatMap((runtime) => FLOW_PHASES[flow2].flatMap((phase) => [
4817
4856
  [`${flow2}.${runtime}.${phase}.model`, "seeded"],
4818
4857
  [`${flow2}.${runtime}.${phase}.effort`, "seeded"]
4819
4858
  ]))
@@ -4822,6 +4861,7 @@ var init_runtime_defaults = __esm({
4822
4861
  version: RUNTIME_DEFAULTS_VERSION,
4823
4862
  claude: { model: "seeded", effort: "seeded" },
4824
4863
  codex: { model: "seeded", effort: "seeded" },
4864
+ antigravity: { model: "seeded", effort: "seeded" },
4825
4865
  orchestration: seededFlows
4826
4866
  };
4827
4867
  }
@@ -4837,11 +4877,12 @@ function cmpVersion(a, b) {
4837
4877
  }
4838
4878
  return 0;
4839
4879
  }
4840
- var zProject, zBriefPayload, zQaPayload, zGoalPayload, zSpecBlocker, zSourceChange, zManualDone, zSpec, zSpecListItem, zSpecSlim, NOTIFY_SOUNDS, zCodex, CODEX_DEFAULTS, zSourceCommon, zScheduler, SCHEDULER_DEFAULTS, zGoal, GOAL_DEFAULTS, zConflict, CONFLICT_DEFAULTS, zLeadEngine, zLead, LEAD_DEFAULTS, zPortalChat, PORTAL_CHAT_DEFAULTS, zPhaseCell, PHASE_OVERRIDE_LIMITS, zPhaseOverride, zPhaseOverrides, zFlowOrchestration, zOrchestration, ORCHESTRATION_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
4880
+ var zProject, zBriefPayload, zQaPayload, zGoalPayload, zSpecBlocker, zSourceChange, zManualDone, zSpec, zSpecListItem, zSpecSlim, NOTIFY_SOUNDS, zCodex, CODEX_DEFAULTS, zAntigravity, ANTIGRAVITY_DEFAULTS, zSourceCommon, zScheduler, SCHEDULER_DEFAULTS, zGoal, GOAL_DEFAULTS, zConflict, CONFLICT_DEFAULTS, zLeadEngine, zLead, LEAD_DEFAULTS, zPortalChat, PORTAL_CHAT_DEFAULTS, zPhaseCell, zAntigravityPhaseCell, PHASE_OVERRIDE_LIMITS, zPhaseOverride, zPhaseOverrides, zFlowOrchestration, zOrchestration, ORCHESTRATION_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
4841
4881
  var init_entities = __esm({
4842
4882
  "../shared/src/entities.ts"() {
4843
4883
  "use strict";
4844
4884
  init_zod();
4885
+ init_antigravity();
4845
4886
  init_enums();
4846
4887
  init_telegram();
4847
4888
  init_agent_engine();
@@ -4972,6 +5013,11 @@ var init_entities = __esm({
4972
5013
  effort: external_exports.string().default("medium")
4973
5014
  });
4974
5015
  CODEX_DEFAULTS = zCodex.parse({});
5016
+ zAntigravity = external_exports.object({
5017
+ model: external_exports.string().default(BUILTIN_ANTIGRAVITY_RUNTIME_DEFAULTS.model),
5018
+ effort: external_exports.string().default(BUILTIN_ANTIGRAVITY_RUNTIME_DEFAULTS.effort)
5019
+ });
5020
+ ANTIGRAVITY_DEFAULTS = zAntigravity.parse({});
4975
5021
  zSourceCommon = { enabled: external_exports.boolean().default(false) };
4976
5022
  zScheduler = external_exports.object({
4977
5023
  enabled: external_exports.boolean().default(false),
@@ -5062,10 +5108,14 @@ var init_entities = __esm({
5062
5108
  model: external_exports.string().nullable().default(null),
5063
5109
  effort: external_exports.string().nullable().default(null)
5064
5110
  });
5111
+ zAntigravityPhaseCell = external_exports.object({
5112
+ model: external_exports.enum(ANTIGRAVITY_CHILD_TIERS).nullable().default(null),
5113
+ effort: external_exports.null().default(null)
5114
+ });
5065
5115
  PHASE_OVERRIDE_LIMITS = { model: 200, effort: 64, phase: 64, phases: 32 };
5066
5116
  zPhaseOverride = external_exports.object({
5067
- model: external_exports.string().min(1).max(PHASE_OVERRIDE_LIMITS.model).optional(),
5068
- effort: external_exports.string().min(1).max(PHASE_OVERRIDE_LIMITS.effort).optional()
5117
+ model: external_exports.string().min(1).max(PHASE_OVERRIDE_LIMITS.model).nullable().optional(),
5118
+ effort: external_exports.string().min(1).max(PHASE_OVERRIDE_LIMITS.effort).nullable().optional()
5069
5119
  });
5070
5120
  zPhaseOverrides = external_exports.record(external_exports.string().min(1).max(PHASE_OVERRIDE_LIMITS.phase), zPhaseOverride).refine(
5071
5121
  (o) => Object.keys(o).length <= PHASE_OVERRIDE_LIMITS.phases,
@@ -5076,7 +5126,8 @@ var init_entities = __esm({
5076
5126
  // Amandemen ADR-0170 P2 · lenient: nilai asing jatuh ke `inline`, bukan Setting gagal parse.
5077
5127
  executeMode: external_exports.enum(["inline", "subagent"]).catch("inline").default("inline"),
5078
5128
  claude: external_exports.record(external_exports.string(), zPhaseCell).default({}),
5079
- codex: external_exports.record(external_exports.string(), zPhaseCell).default({})
5129
+ codex: external_exports.record(external_exports.string(), zPhaseCell).default({}),
5130
+ antigravity: external_exports.record(external_exports.string(), zPhaseCell).default({})
5080
5131
  });
5081
5132
  zOrchestration = external_exports.object({
5082
5133
  feature: zFlowOrchestration.default({}),
@@ -5114,6 +5165,7 @@ var init_entities = __esm({
5114
5165
  // SPEC-338 · ADR-0074 · mesin sesi default
5115
5166
  codex: zCodex.default(CODEX_DEFAULTS),
5116
5167
  // SPEC-338 · ADR-0074 · model/effort codex
5168
+ antigravity: zAntigravity.default(ANTIGRAVITY_DEFAULTS),
5117
5169
  verifyScope: zVerifyScope.default("changed"),
5118
5170
  // SPEC-376 · ADR-0080 · scope verifikasi sesi
5119
5171
  // SPEC-734 · ADR-0113 · metode workflow default. LENIENT (`z.string()`, bukan `z.enum`):
@@ -5189,14 +5241,15 @@ var init_entities = __esm({
5189
5241
  });
5190
5242
 
5191
5243
  // ../shared/src/orchestration-plan.ts
5192
- function codexNativeAgentsSupported(version3) {
5193
- const parsed = version3 ? /(\d+)\.(\d+)\.(\d+)/.exec(version3)?.[0] : null;
5244
+ function codexNativeAgentsSupported(version2) {
5245
+ const parsed = version2 ? /(\d+)\.(\d+)\.(\d+)/.exec(version2)?.[0] : null;
5194
5246
  return parsed ? cmpVersion(parsed, CODEX_NATIVE_AGENTS_MIN_CLIENT) >= 0 : false;
5195
5247
  }
5196
5248
  var CODEX_NATIVE_AGENTS_MIN_CLIENT;
5197
5249
  var init_orchestration_plan = __esm({
5198
5250
  "../shared/src/orchestration-plan.ts"() {
5199
5251
  "use strict";
5252
+ init_antigravity();
5200
5253
  init_entities();
5201
5254
  init_orchestration();
5202
5255
  CODEX_NATIVE_AGENTS_MIN_CLIENT = "0.151.0";
@@ -5358,6 +5411,7 @@ var init_agent = __esm({
5358
5411
 
5359
5412
  // ../shared/src/custom-agent.ts
5360
5413
  function validateCreateWorkspacePolicy(value, ctx) {
5414
+ validateAntigravityChild(value, ctx);
5361
5415
  if (value.workspacePolicy === "isolated-worktree" && value.runtime !== "claude") {
5362
5416
  ctx.addIssue({
5363
5417
  code: external_exports.ZodIssueCode.custom,
@@ -5366,13 +5420,23 @@ function validateCreateWorkspacePolicy(value, ctx) {
5366
5420
  });
5367
5421
  }
5368
5422
  }
5423
+ function validateAntigravityChild(value, ctx) {
5424
+ if (value.runtime !== "antigravity") return;
5425
+ if (value.model != null && !isAntigravityChildTier(value.model)) {
5426
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["model"], message: "Antigravity child memakai tier inherit, flash, atau pro" });
5427
+ }
5428
+ if (value.effort != null) {
5429
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["effort"], message: "Antigravity child tidak mendukung effort independen" });
5430
+ }
5431
+ }
5369
5432
  var AGENT_RUNTIMES, zAgentRuntime, AGENT_ACTIVATIONS, zAgentActivation, zAgentEffort, AGENT_WORKSPACE_POLICIES, zAgentWorkspacePolicy, AGENT_NAME_RE, DEFAULT_AGENT_TOOLS, zCustomAgent, zCreateCustomAgentFields, zCreateCustomAgent, zUpdateCustomAgent;
5370
5433
  var init_custom_agent = __esm({
5371
5434
  "../shared/src/custom-agent.ts"() {
5372
5435
  "use strict";
5373
5436
  init_zod();
5437
+ init_antigravity();
5374
5438
  init_orchestration();
5375
- AGENT_RUNTIMES = ["claude", "codex"];
5439
+ AGENT_RUNTIMES = ["claude", "codex", "antigravity"];
5376
5440
  zAgentRuntime = external_exports.enum(AGENT_RUNTIMES);
5377
5441
  AGENT_ACTIVATIONS = ["always", "smart"];
5378
5442
  zAgentActivation = external_exports.enum(AGENT_ACTIVATIONS);
@@ -5430,6 +5494,7 @@ var init_custom_agent = __esm({
5430
5494
  });
5431
5495
  zCreateCustomAgent = zCreateCustomAgentFields.superRefine(validateCreateWorkspacePolicy);
5432
5496
  zUpdateCustomAgent = zCreateCustomAgentFields.omit({ name: true, projectId: true }).partial().superRefine((value, ctx) => {
5497
+ validateAntigravityChild(value, ctx);
5433
5498
  if (value.workspacePolicy === "isolated-worktree" && value.runtime !== void 0 && value.runtime !== "claude") {
5434
5499
  ctx.addIssue({
5435
5500
  code: external_exports.ZodIssueCode.custom,
@@ -6448,6 +6513,7 @@ var BUILTIN_AGENT_TOOLS;
6448
6513
  var init_agent_catalog = __esm({
6449
6514
  "../shared/src/agent-catalog.ts"() {
6450
6515
  "use strict";
6516
+ init_antigravity();
6451
6517
  init_custom_agent();
6452
6518
  init_entities();
6453
6519
  BUILTIN_AGENT_TOOLS = DEFAULT_AGENT_TOOLS.map((id) => ({
@@ -7236,6 +7302,7 @@ var init_dto = __esm({
7236
7302
  "agent-image",
7237
7303
  "claude",
7238
7304
  "codex",
7305
+ "antigravity",
7239
7306
  "gh"
7240
7307
  ];
7241
7308
  zProvision = external_exports.object({
@@ -7484,6 +7551,7 @@ var init_api = __esm({
7484
7551
  limits: `${API}/limits`,
7485
7552
  // SPEC-339 · versi codex CLI (peringatan lunak model GPT-5.6).
7486
7553
  codexVersion: `${API}/codex/version`,
7554
+ antigravityVersion: `${API}/antigravity/version`,
7487
7555
  // SPEC-739 · ADR-0114 · kesiapan skill metode per agen. LOCAL-only, diturunkan live dari disk.
7488
7556
  methodStatus: `${API}/methods/status`,
7489
7557
  // SPEC-489 · panduan AI agent — markdown MENTAH & PUBLIC (tanpa auth). Satu definisi URL untuk
@@ -7584,6 +7652,8 @@ var init_api = __esm({
7584
7652
  // SPEC-199 · WebSocket siar dashboard (global, bukan per-sesi)
7585
7653
  // SPEC-919 · ADR-0147 · muat awal + fallback halaman Klien. Selama WS sehat tak ada yang men-poll-nya.
7586
7654
  presence: `${API}/presence`,
7655
+ // ADR-0220 · muat awal agen/MCP untuk agregat Overview; dashboard menerimanya lewat grup siar `overview`.
7656
+ overview: `${API}/overview`,
7587
7657
  wsTickets: `${API}/ws-tickets`,
7588
7658
  vps: `${API}/vps`,
7589
7659
  vpsOne: (id) => `${API}/vps/${id}`,
@@ -7649,6 +7719,9 @@ var init_api = __esm({
7649
7719
  schedulerCron: (id) => `${API}/scheduler/crons/${encodeURIComponent(id)}`,
7650
7720
  schedulerCronRunNow: (id) => `${API}/scheduler/crons/${encodeURIComponent(id)}/run`,
7651
7721
  schedulerCronRuns: (id) => `${API}/scheduler/crons/${encodeURIComponent(id)}/runs`,
7722
+ // ADR-0222 · laporan run cron (baca-saja).
7723
+ schedulerReports: `${API}/scheduler/reports`,
7724
+ schedulerReport: (id) => `${API}/scheduler/reports/${encodeURIComponent(id)}`,
7652
7725
  // SPEC-409 · ADR-0091 · hanoman-lead. Semua HTTP (polling) — tak ada kanal WS baru (AC-26).
7653
7726
  leadConfig: `${API}/lead/config`,
7654
7727
  leadStatus: `${API}/lead/status`,
@@ -7867,6 +7940,77 @@ var init_session_end = __esm({
7867
7940
  }
7868
7941
  });
7869
7942
 
7943
+ // ../shared/src/overview.ts
7944
+ var zHeadlinePart, zOverviewDay, zOverviewRiver, zOverviewTokens, zOverviewWait, BENSIN_VERDICTS, zOverviewBensin, zOverviewHeatmap, zOverviewRecords, zOverview;
7945
+ var init_overview = __esm({
7946
+ "../shared/src/overview.ts"() {
7947
+ "use strict";
7948
+ init_zod();
7949
+ zHeadlinePart = external_exports.object({ text: external_exports.string(), tone: external_exports.enum(["bad", "good"]).optional() });
7950
+ zOverviewDay = external_exports.object({ landed: external_exports.number().int(), failed: external_exports.number().int() });
7951
+ zOverviewRiver = external_exports.object({
7952
+ created: external_exports.number().int(),
7953
+ started: external_exports.number().int(),
7954
+ landed: external_exports.number().int(),
7955
+ // Median 7 hari terakhir atas spec yang selesai; null bila tak ada.
7956
+ leadTimeMedMs: external_exports.number().nullable(),
7957
+ cycleTimeMedMs: external_exports.number().nullable()
7958
+ });
7959
+ zOverviewTokens = external_exports.object({
7960
+ input: external_exports.number(),
7961
+ output: external_exports.number(),
7962
+ cached: external_exports.number(),
7963
+ total: external_exports.number(),
7964
+ cacheHitPct: external_exports.number().nullable(),
7965
+ perLanded: external_exports.number().nullable(),
7966
+ topAgent: external_exports.object({ name: external_exports.string(), total: external_exports.number() }).nullable(),
7967
+ yesterdayTotal: external_exports.number()
7968
+ });
7969
+ zOverviewWait = external_exports.object({
7970
+ todayMin: external_exports.number(),
7971
+ yesterdayMin: external_exports.number(),
7972
+ pctOfLive: external_exports.number().nullable()
7973
+ });
7974
+ BENSIN_VERDICTS = ["habis", "aman", "stabil", "kurang-data"];
7975
+ zOverviewBensin = external_exports.object({
7976
+ source: external_exports.enum(["claude", "codex"]),
7977
+ key: external_exports.string(),
7978
+ label: external_exports.string(),
7979
+ usedPct: external_exports.number(),
7980
+ resetsAt: external_exports.string().nullable(),
7981
+ exhaustAt: external_exports.string().nullable(),
7982
+ verdict: external_exports.enum(BENSIN_VERDICTS),
7983
+ samples: external_exports.array(external_exports.object({ at: external_exports.string(), pct: external_exports.number() }))
7984
+ });
7985
+ zOverviewHeatmap = external_exports.object({
7986
+ days: external_exports.array(external_exports.string()),
7987
+ // YYYY-MM-DD lokal, terlama dulu
7988
+ minutes: external_exports.array(external_exports.array(external_exports.number()))
7989
+ // [hari][jam 0..23] = menit sesi agen hidup
7990
+ });
7991
+ zOverviewRecords = external_exports.object({
7992
+ streakDays: external_exports.number().int(),
7993
+ bestStreak: external_exports.number().int(),
7994
+ bestLandedDay: external_exports.object({ date: external_exports.string(), count: external_exports.number().int() }).nullable(),
7995
+ landedRecordToday: external_exports.boolean()
7996
+ });
7997
+ zOverview = external_exports.object({
7998
+ generatedAt: external_exports.string(),
7999
+ recordingSince: external_exports.string(),
8000
+ // awal perekam di memori (menunggu & bensin); restart mengulangnya
8001
+ today: zOverviewDay.nullable(),
8002
+ yesterday: zOverviewDay.nullable(),
8003
+ river: zOverviewRiver.nullable(),
8004
+ tokens: zOverviewTokens.nullable(),
8005
+ wait: zOverviewWait.nullable(),
8006
+ bensin: external_exports.array(zOverviewBensin).nullable(),
8007
+ heatmap: zOverviewHeatmap.nullable(),
8008
+ records: zOverviewRecords.nullable(),
8009
+ headline: external_exports.object({ text: external_exports.string(), parts: external_exports.array(zHeadlinePart) })
8010
+ });
8011
+ }
8012
+ });
8013
+
7870
8014
  // ../shared/src/config.ts
7871
8015
  var zHanomanConfig;
7872
8016
  var init_config = __esm({
@@ -7933,6 +8077,17 @@ var init_config_registry = __esm({
7933
8077
  { key: "HANOMAN_CLAUDE_BIN", group: "claude", label: "Biner claude", kind: "path", apply: "new-session", category: "knob", example: "/opt/homebrew/bin/claude", default: "claude" },
7934
8078
  // codex (SPEC-338 · ADR-0074)
7935
8079
  { key: "HANOMAN_CODEX_BIN", group: "claude", label: "Biner codex", kind: "path", apply: "new-session", category: "knob", example: "/opt/homebrew/bin/codex", default: "codex" },
8080
+ {
8081
+ key: "HANOMAN_ANTIGRAVITY_BIN",
8082
+ group: "claude",
8083
+ label: "Biner Antigravity",
8084
+ kind: "path",
8085
+ apply: "new-session",
8086
+ category: "knob",
8087
+ example: "/opt/homebrew/bin/agy",
8088
+ default: "agy",
8089
+ help: "Executable Antigravity CLI, bukan shell command atau daftar flag."
8090
+ },
7936
8091
  {
7937
8092
  key: "CLAUDE_CONFIG_DIR",
7938
8093
  group: "claude",
@@ -10305,7 +10460,7 @@ var init_settings = __esm({
10305
10460
  {
10306
10461
  name: "hanoman_settings_get",
10307
10462
  title: "Baca setelan instance",
10308
- description: "Seluruh setelan instance: agen & model default, effort, notifikasi, mode goal, verifikasi, dan blok Telegram. Panggil ini sebelum hanoman_settings_set \u2014 setelan disimpan sebagai satu blok.",
10463
+ description: "Seluruh setelan instance: runtime Claude/Codex/Antigravity, model parent, effort, tier child native Antigravity, notifikasi, mode goal, verifikasi, dan blok Telegram. Panggil ini sebelum hanoman_settings_set \u2014 setelan disimpan sebagai satu blok.",
10309
10464
  inputSchema: obj({ properties: {} }),
10310
10465
  mode: "read",
10311
10466
  capability: "settings:read",
@@ -10317,7 +10472,7 @@ var init_settings = __esm({
10317
10472
  {
10318
10473
  name: "hanoman_settings_set",
10319
10474
  title: "Simpan setelan instance",
10320
- description: "Menyimpan setelan instance. MENGGANTI blok penuh \u2014 kirim hasil hanoman_settings_get yang sudah diubah, bukan potongan. Panggil hanoman_settings_get TEPAT sebelum tool ini (jangan memakai hasil lama) dan ubah HANYA field yang dimaksud: setiap model/effort/sel orkestrasi yang berbeda dari nilai tersimpan ditandai milik operator dan tak lagi diperbarui default bawaan saat update. Setelan ini berlaku untuk SETIAP sesi baru di seluruh workspace. Menyentuh blok Telegram akan memuat ulang gateway.",
10475
+ description: "Menyimpan setelan instance. MENGGANTI blok penuh \u2014 kirim hasil hanoman_settings_get yang sudah diubah, bukan potongan. Panggil hanoman_settings_get TEPAT sebelum tool ini (jangan memakai hasil lama) dan ubah HANYA field yang dimaksud: setiap model/effort/sel orkestrasi yang berbeda dari nilai tersimpan ditandai milik operator dan tak lagi diperbarui default bawaan saat update. Parent Antigravity memakai blok antigravity.model/effort; sel orchestration.<flow>.antigravity hanya menerima tier inherit|flash|pro atau model null dan effort null, bukan slug parent. Phase override per sesi menerima model/effort null; model null mewarisi tier native, effort tetap unknown, bukan effort parent. Blok runtime Antigravity yang hilang dari klien lama dipertahankan. Setelan ini berlaku untuk SETIAP sesi baru di seluruh workspace. Menyentuh blok Telegram akan memuat ulang gateway.",
10321
10476
  inputSchema: obj({ properties: { settings: WHOLE_BLOCK("setelan") }, required: ["settings"] }),
10322
10477
  mode: "write",
10323
10478
  capability: "settings:write",
@@ -10470,6 +10625,7 @@ var init_agents = __esm({
10470
10625
  "../shared/src/mcp-catalog/agents.ts"() {
10471
10626
  "use strict";
10472
10627
  init_mcp_schema();
10628
+ init_custom_agent();
10473
10629
  init_helpers();
10474
10630
  AGENTS_TOOLS = [
10475
10631
  {
@@ -10491,13 +10647,16 @@ var init_agents = __esm({
10491
10647
  title: "Daftar custom agent",
10492
10648
  description: "Persona custom yang aktif. Tanpa `project` hanya yang global; dengan `project` ia menggabung global + milik project, dan nama yang ditimpa project muncul SEKALI dengan versi project yang menang.",
10493
10649
  inputSchema: obj({
10494
- properties: { project: str("Id project. Kosongkan untuk hanya persona global.") }
10650
+ properties: {
10651
+ project: str("Id project. Kosongkan untuk hanya persona global."),
10652
+ runtime: enumStr(AGENT_RUNTIMES, "Runtime parent untuk availability dan alasan ketidaktersediaan persona.")
10653
+ }
10495
10654
  }),
10496
10655
  mode: "read",
10497
10656
  capability: "agents:read",
10498
10657
  samplePath: "/custom-agents",
10499
10658
  sampleMethod: "GET",
10500
- build: (a) => ({ method: "GET", path: "/custom-agents", query: query({ projectId: s(a.project) }) }),
10659
+ build: (a) => ({ method: "GET", path: "/custom-agents", query: query({ projectId: s(a.project), runtime: s(a.runtime) }) }),
10501
10660
  shape: (raw) => raw
10502
10661
  },
10503
10662
  {
@@ -10511,9 +10670,9 @@ var init_agents = __esm({
10511
10670
  instructions: str("Instruksi persona (1\u201320.000 karakter). Inilah yang dibaca agen."),
10512
10671
  project: str("Id project. Kosongkan untuk persona GLOBAL yang berlaku di semua project."),
10513
10672
  tools: strArray("Tool yang boleh dipakai persona ini. Harus ada di hanoman_agents_catalog. Kosongkan untuk mewarisi."),
10514
- model: str("Model. Harus sah untuk `runtime` yang dipilih."),
10673
+ model: str("Model child. Antigravity hanya tier inherit|flash|pro; effort independen unavailable. Harus sah untuk `runtime` yang dipilih."),
10515
10674
  mentions: strArray("Nama persona lain yang boleh dipanggil."),
10516
- runtime: enumStr(["claude", "codex"], "Penyaring mesin sesi. Kosongkan untuk mengikuti sesi induk."),
10675
+ runtime: enumStr(AGENT_RUNTIMES, "Penyaring mesin sesi. Kosongkan untuk mengikuti sesi induk."),
10517
10676
  enabled: bool("Aktif atau tidak. Default aktif.")
10518
10677
  },
10519
10678
  required: ["name", "description", "instructions"]
@@ -10546,9 +10705,9 @@ var init_agents = __esm({
10546
10705
  description: str("Deskripsi baru."),
10547
10706
  instructions: str("Instruksi baru."),
10548
10707
  tools: strArray("Daftar tool baru."),
10549
- model: str("Model baru."),
10708
+ model: str("Model child baru. Antigravity hanya tier inherit|flash|pro; effort independen unavailable."),
10550
10709
  mentions: strArray("Daftar mention baru."),
10551
- runtime: enumStr(["claude", "codex"], "Penyaring mesin sesi."),
10710
+ runtime: enumStr(AGENT_RUNTIMES, "Penyaring mesin sesi."),
10552
10711
  enabled: bool("Aktif atau tidak.")
10553
10712
  },
10554
10713
  required: ["agent"]
@@ -10593,7 +10752,7 @@ var init_skills = __esm({
10593
10752
  {
10594
10753
  name: "hanoman_skills_list",
10595
10754
  title: "Daftar skill",
10596
- description: "Skill dari semua sumber: global hanoman ($HANOMAN_HOME/skills, disuntik ke setiap sesi), user (~/.claude|~/.codex|~/.agents), plugin (baca-saja), dan per project (.claude/.agents/.codex/skills + folder lain berisi SKILL.md). Tanpa `project`: global + satu grup per project. Dengan `project`: global (bertanda shadowedBy bila ditimpa) + skill project itu.",
10755
+ description: "Skill dari semua sumber: global hanoman ($HANOMAN_HOME/skills, disuntik ke setiap sesi), user (~/.claude|~/.codex|~/.agents|~/.gemini/antigravity-cli), plugin (baca-saja), dan per project (.claude/.agents/.codex/skills + folder lain berisi SKILL.md). Tanpa `project`: global + satu grup per project. Dengan `project`: global (bertanda shadowedBy bila ditimpa) + skill project itu.",
10597
10756
  inputSchema: obj({ properties: { project: str("Id project. Kosongkan untuk semua grup.") } }),
10598
10757
  mode: "read",
10599
10758
  capability: "skills:read",
@@ -10651,7 +10810,7 @@ var init_skills = __esm({
10651
10810
  layer: enumStr(["hanoman", "user", "project"], "Lapis tujuan."),
10652
10811
  name: str("Nama skill (kebab-case)."),
10653
10812
  description: str('Deskripsi \u2014 diawali kapan skill dipakai, mis. "Use when \u2026".'),
10654
- source: enumStr([".claude", ".agents", ".codex"], "Sumber untuk lapis user/project. Default .claude."),
10813
+ source: enumStr([".claude", ".agents", ".codex", ".gemini/antigravity-cli"], "Sumber untuk lapis user/project. .gemini/antigravity-cli hanya user. Default .claude."),
10655
10814
  project: str("Id project (wajib untuk layer project).")
10656
10815
  },
10657
10816
  required: ["layer", "name", "description"]
@@ -10670,13 +10829,13 @@ var init_skills = __esm({
10670
10829
  {
10671
10830
  name: "hanoman_skill_fork",
10672
10831
  title: "Fork skill",
10673
- description: "Menyalin skill mana pun (termasuk plugin yang baca-saja) ke global hanoman atau ke project, supaya bisa disunting. `name` default = nama asal.",
10832
+ description: "Menyalin skill mana pun (termasuk plugin yang baca-saja) ke global hanoman, user, atau project, supaya bisa disunting. `name` default = nama asal.",
10674
10833
  inputSchema: obj({
10675
10834
  properties: {
10676
10835
  key: str("Key skill sumber."),
10677
- layer: enumStr(["hanoman", "project"], "Tujuan. Default hanoman."),
10836
+ layer: enumStr(["hanoman", "user", "project"], "Tujuan. Default hanoman."),
10678
10837
  project: str("Id project (wajib untuk layer project)."),
10679
- source: enumStr([".claude", ".agents", ".codex"], "Sumber tujuan untuk layer project."),
10838
+ source: enumStr([".claude", ".agents", ".codex", ".gemini/antigravity-cli"], "Sumber tujuan user/project; .gemini/antigravity-cli hanya user."),
10680
10839
  name: str("Nama baru (opsional).")
10681
10840
  },
10682
10841
  required: ["key"]
@@ -11236,6 +11395,7 @@ var CORE3, MORE2, SESSIONS_TOOLS;
11236
11395
  var init_sessions = __esm({
11237
11396
  "../shared/src/mcp-catalog/sessions.ts"() {
11238
11397
  "use strict";
11398
+ init_entities();
11239
11399
  init_mcp_schema();
11240
11400
  init_mcp_shape();
11241
11401
  init_helpers();
@@ -11257,7 +11417,7 @@ var init_sessions = __esm({
11257
11417
  {
11258
11418
  name: "hanoman_session_phases",
11259
11419
  title: "Fase sesi",
11260
- description: "Pipeline fase sebuah sesi beserta posisinya sekarang. Menjawab 404 bila sesi itu bukan sesi ber-flow (terminal biasa tak punya fase).",
11420
+ description: "Pipeline fase sebuah sesi beserta posisinya sekarang. Antigravity menggunakan tier child native inherit|flash|pro, effort unknown dan protocol wait asynchronous; reviewer fase read-only instruksional, bukan enforcement runtime. Marker Execute menunggu review independen lulus. Menjawab 404 bila sesi itu bukan sesi ber-flow (terminal biasa tak punya fase).",
11261
11421
  inputSchema: obj({ properties: { session: str("Id sesi, dari hanoman_sessions_list.") }, required: ["session"] }),
11262
11422
  mode: "read",
11263
11423
  capability: "sessions:read",
@@ -11383,10 +11543,25 @@ var init_sessions = __esm({
11383
11543
  build: (a) => ({ method: "POST", path: `/terminal/sessions/${enc(String(a.session))}/interrupt` }),
11384
11544
  shape: (raw) => raw
11385
11545
  },
11546
+ {
11547
+ name: "hanoman_session_rename",
11548
+ title: "Ganti nama sesi",
11549
+ description: "Memberi nama kustom pada sesi terminal (hidup atau yang panenya masih ada) supaya mudah dikenali di Terminal. Nama maksimal 80 karakter, satu baris. Nama kosong menghapus nama kustom dan UI kembali memakai label turunan (backlog/flow/project).",
11550
+ inputSchema: obj({
11551
+ properties: { session: str("Id sesi."), name: str("Nama baru. Kosong = hapus nama kustom.") },
11552
+ required: ["session", "name"]
11553
+ }),
11554
+ mode: "write",
11555
+ capability: "sessions:write",
11556
+ samplePath: "/terminal/sessions/s1",
11557
+ sampleMethod: "PATCH",
11558
+ build: (a) => ({ method: "PATCH", path: `/terminal/sessions/${enc(String(a.session))}`, body: { name: String(a.name) } }),
11559
+ shape: (raw) => raw
11560
+ },
11386
11561
  {
11387
11562
  name: "hanoman_session_create",
11388
11563
  title: "Buka sesi agen baru (BERBAHAYA)",
11389
- description: "BERBAHAYA \u2014 membuka sesi agen BARU: hanoman menjalankan claude/codex dengan IZIN PENUH di worktree project, dan sesi itu bisa menulis berkas, menjalankan perintah, serta membuat commit tanpa manusia di pane. Menuntut capability `sessions:spawn`; `sessions:write` \u2014 yang cukup untuk mengendalikan sesi yang SUDAH ada \u2014 tidak cukup di sini. Panggil hanoman_sessions_list lebih dulu: sesi yang sudah berjalan untuk backlog yang sama akan DILANJUTKAN, bukan digandakan. Hanya muncul saat tingkat `--danger` menyala.",
11564
+ description: "BERBAHAYA \u2014 membuka sesi agen BARU: hanoman menjalankan claude/codex/antigravity dengan IZIN PENUH di worktree project, dan sesi itu bisa menulis berkas, menjalankan perintah, serta membuat commit tanpa manusia di pane. Menuntut capability `sessions:spawn`; `sessions:write` \u2014 yang cukup untuk mengendalikan sesi yang SUDAH ada \u2014 tidak cukup di sini. Panggil hanoman_sessions_list lebih dulu: sesi yang sudah berjalan untuk backlog yang sama akan DILANJUTKAN, bukan digandakan. Hanya muncul saat tingkat `--danger` menyala.",
11390
11565
  inputSchema: obj({
11391
11566
  properties: {
11392
11567
  spec: str("Id backlog, mis. `SPEC-482`. Mengisinya membuka sesi BACKLOG dan mewajibkan `flow`."),
@@ -11396,13 +11571,23 @@ var init_sessions = __esm({
11396
11571
  "Alur sesi. Wajib bila `spec` diisi. `reverse`/`prd`/`breakdown`/`scaffold` adalah sesi tingkat-project dan dipasangkan dengan `project`."
11397
11572
  ),
11398
11573
  shell: bool("true = terminal shell biasa di repo project, tanpa agen. Hanya dengan `project`."),
11399
- agent: enumStr(["claude", "codex"], "Mesin sesi. Kosong = default global."),
11574
+ agent: enumStr(["claude", "codex", "antigravity"], "Mesin sesi. Kosong = default global."),
11400
11575
  model: str("Model. Kosong = default global."),
11401
11576
  effort: str("Effort. Kosong = default global."),
11402
11577
  goal: bool("Mode goal per-sesi. Kosong = ikut setelan global."),
11403
11578
  goalCondition: str("Kondisi selesai mode goal (maks 4000 karakter)."),
11404
11579
  verifyScope: enumStr(["changed", "full"], "Scope verifikasi. Kosong = ikut setelan global."),
11405
11580
  method: str("Metode workflow. Id tak dikenal jatuh ke default, bukan ditolak."),
11581
+ phaseOverrides: {
11582
+ type: "object",
11583
+ maxProperties: PHASE_OVERRIDE_LIMITS.phases,
11584
+ propertyNames: { type: "string", minLength: 1, maxLength: PHASE_OVERRIDE_LIMITS.phase },
11585
+ description: "Override fase backlog. Antigravity memakai tier inherit|flash|pro, effort null; validasi mengikuti runtime efektif.",
11586
+ additionalProperties: obj({ properties: {
11587
+ model: { oneOf: [{ type: "string", minLength: 1, maxLength: PHASE_OVERRIDE_LIMITS.model }, { type: "null" }] },
11588
+ effort: { oneOf: [{ type: "string", minLength: 1, maxLength: PHASE_OVERRIDE_LIMITS.effort }, { type: "null" }] }
11589
+ } })
11590
+ },
11406
11591
  prdPath: str("flow `breakdown`: jalur PRD yang dipecah. WAJIB untuk alur itu."),
11407
11592
  force: bool("Lewati gerbang dependency. Pakai HANYA sesudah melihat daftar pemblokirnya.")
11408
11593
  },
@@ -11423,6 +11608,7 @@ var init_sessions = __esm({
11423
11608
  const body2 = { spec: String(a.spec), flow: String(a.flow) };
11424
11609
  for (const k of ["model", "effort", "goalCondition", "agent", "verifyScope", "method"])
11425
11610
  if (s(a[k]) !== void 0) body2[k] = s(a[k]);
11611
+ if (a.phaseOverrides && typeof a.phaseOverrides === "object" && !Array.isArray(a.phaseOverrides)) body2.phaseOverrides = a.phaseOverrides;
11426
11612
  for (const k of ["goal", "force"]) if (typeof a[k] === "boolean") body2[k] = a[k];
11427
11613
  return { method: "POST", path: "/terminal/sessions", body: body2 };
11428
11614
  }
@@ -12509,6 +12695,18 @@ var init_system = __esm({
12509
12695
  build: () => ({ method: "GET", path: "/limits/codex" }),
12510
12696
  shape: (raw) => raw
12511
12697
  },
12698
+ {
12699
+ name: "hanoman_overview_get",
12700
+ title: "Ringkasan kinerja hari ini (Overview)",
12701
+ description: 'Agregat kinerja workspace hari ini vs kemarin, persis yang tampil di layar Overview "Koran Pagi": spec mendarat, sesi agen tumbang, menit agen menunggu jawaban manusia, token agen tercatat (hanya subagen/agen fase), prakiraan kapan limit habis dibanding reset, peta panas jam kerja agen 7\xD724, streak/rekor, dan headline-nya. Menit menunggu & prakiraan limit direkam di memori server dan hilang saat restart (`recordingSince`). Panel `null` = sumbernya gagal dibaca. Tak menuntut capability apa pun.',
12702
+ inputSchema: obj({ properties: {} }),
12703
+ mode: "read",
12704
+ capability: null,
12705
+ samplePath: "/overview",
12706
+ sampleMethod: "GET",
12707
+ build: () => ({ method: "GET", path: "/overview" }),
12708
+ shape: (raw) => raw
12709
+ },
12512
12710
  {
12513
12711
  name: "hanoman_update_status",
12514
12712
  title: "Status versi & pembaruan",
@@ -12596,10 +12794,10 @@ var init_observability = __esm({
12596
12794
  {
12597
12795
  name: "hanoman_models",
12598
12796
  title: "Katalog model agen",
12599
- description: 'Katalog model claude & codex yang tersedia di MESIN ini: id, label, effort yang diterima, serta status probe per penyedia (`providers`: sumber `cli`/`cache`/`bundled`, kapan terakhir dicek, galatnya). Katalog dibaca dari CLI yang terpasang dan di-refresh server tiap 5 menit, jadi ini jawaban yang benar untuk "model/effort apa yang sah dipakai hanoman_session_create atau hanoman_agent_create" \u2014 jangan menebak id model. Hanya menampilkan data yang sudah disaring parser (detail akun CLI tak pernah tersimpan). Tak menuntut capability apa pun.',
12797
+ description: 'Katalog model claude, codex & antigravity yang tersedia di MESIN ini: id, label, effort yang diterima, serta status probe per penyedia (`providers`: sumber `cli`/`cache`/`bundled`, kapan terakhir dicek, galatnya). Katalog dibaca dari CLI yang terpasang dan di-refresh server tiap 5 menit, jadi ini jawaban yang benar untuk "model/effort apa yang sah dipakai hanoman_session_create atau hanoman_agent_create" \u2014 jangan menebak id model. Hanya menampilkan data yang sudah disaring parser (detail akun CLI tak pernah tersimpan). Tak menuntut capability apa pun.',
12600
12798
  inputSchema: obj({
12601
12799
  properties: {
12602
- agent: enumStr(["claude", "codex"], "Batasi ke satu mesin. Kosong = keduanya.")
12800
+ agent: enumStr(["claude", "codex", "antigravity"], "Batasi ke satu mesin. Kosong = semua runtime.")
12603
12801
  }
12604
12802
  }),
12605
12803
  mode: "read",
@@ -12610,7 +12808,7 @@ var init_observability = __esm({
12610
12808
  shape: (raw, a) => {
12611
12809
  const agent = s(a.agent);
12612
12810
  const r = raw ?? {};
12613
- if (agent !== "claude" && agent !== "codex") return raw;
12811
+ if (agent !== "claude" && agent !== "codex" && agent !== "antigravity") return raw;
12614
12812
  const providers = r.providers ?? {};
12615
12813
  return { [agent]: r[agent], providers: { [agent]: providers[agent] } };
12616
12814
  }
@@ -12627,10 +12825,22 @@ var init_observability = __esm({
12627
12825
  build: () => ({ method: "GET", path: "/codex/version" }),
12628
12826
  shape: (raw) => raw
12629
12827
  },
12828
+ {
12829
+ name: "hanoman_antigravity_version",
12830
+ title: "Versi Antigravity CLI",
12831
+ description: "Versi Antigravity CLI pada boundary sesi saat ini: `{version,error}`. Versi semver atau null beserta alasan aman bila biner hilang, timeout, keluaran tidak dikenal, atau sandbox belum didukung. Tidak memuat keluaran CLI mentah atau kredensial; kegagalan observasi tidak memblokir sesi host. Cache 5 menit, invalidasi saat biner/boundary berubah. Tak menuntut capability apa pun.",
12832
+ inputSchema: obj({ properties: {} }),
12833
+ mode: "read",
12834
+ capability: null,
12835
+ samplePath: "/antigravity/version",
12836
+ sampleMethod: "GET",
12837
+ build: () => ({ method: "GET", path: "/antigravity/version" }),
12838
+ shape: (raw) => raw
12839
+ },
12630
12840
  {
12631
12841
  name: "hanoman_methods_status",
12632
12842
  title: "Kesiapan metode workflow",
12633
- description: "Metode workflow mana yang benar-benar siap dipakai di MESIN ini, per agen (claude/codex): skill/paket apa yang sudah terpasang dan apa yang masih kurang. Diturunkan dari disk tiap dipanggil (tanpa cache), jadi hasilnya segar sesudah operator memasang skill. Baca-saja dan tak pernah memblokir kelahiran sesi \u2014 metode yang belum siap hanya ditandai; memasangnya tetap tindakan manusia di dashboard. Berisi path home/roots skill di mesin. Tak menuntut capability apa pun.",
12843
+ description: "Metode workflow mana yang benar-benar siap dipakai di MESIN ini, per agen (claude/codex/antigravity; installer Antigravity unavailable sampai upstream terverifikasi): skill/paket apa yang sudah terpasang dan apa yang masih kurang. Diturunkan dari disk tiap dipanggil (tanpa cache), jadi hasilnya segar sesudah operator memasang skill. Baca-saja dan tak pernah memblokir kelahiran sesi \u2014 metode yang belum siap hanya ditandai; memasangnya tetap tindakan manusia di dashboard. Berisi path home/roots skill di mesin. Tak menuntut capability apa pun.",
12634
12844
  inputSchema: obj({ properties: {} }),
12635
12845
  mode: "read",
12636
12846
  capability: null,
@@ -13298,7 +13508,7 @@ var init_gates = __esm({
13298
13508
  name: str("Nama cron (1\u2013120 karakter)."),
13299
13509
  expr: str("Cron expression 5 kolom (menit jam tanggal bulan hari-minggu), mis. `0 7 * * *`. Ekspresi tak sah ditolak 400."),
13300
13510
  prompt: str("Prompt awal yang dikirim ke sesi agen setiap kali cron jatuh tempo (maks 8000 karakter).", { maxLength: 8e3 }),
13301
- agent: enumStr(["claude", "codex"], "Mesin sesi. Kosong = default global."),
13511
+ agent: enumStr(["claude", "codex", "antigravity"], "Mesin sesi. Kosong = default global."),
13302
13512
  model: str("Model. Kosong = default global."),
13303
13513
  effort: str("Effort. Kosong = default global.")
13304
13514
  };
@@ -13335,6 +13545,45 @@ var init_gates = __esm({
13335
13545
  }),
13336
13546
  shape: (raw) => raw
13337
13547
  },
13548
+ {
13549
+ name: "hanoman_scheduler_reports",
13550
+ title: "Daftar laporan run cron",
13551
+ description: "Laporan hasil run cron (ADR-0222): pesan akhir agen yang disimpan sebagai dokumen markdown, satu per run, tersync antar mesin. Amplop berhalaman `{items,total,page,pageSize}`, terbaru dulu, TANPA isi (`id`, `cronId`, `cronName`, `runDate`, `dueAt`, `bytes`, `filename`). Isi dibaca lewat hanoman_scheduler_report_get. Saring menurut `cron` / `project`; cron dari mesin lain tetap terdaftar (cron tak harus ada di instance ini).",
13552
+ inputSchema: obj({ properties: {
13553
+ cron: str("Saring menurut id cron."),
13554
+ project: str("Saring menurut id project."),
13555
+ ...PAGE_PARAMS
13556
+ } }),
13557
+ mode: "read",
13558
+ capability: "scheduler:read",
13559
+ samplePath: "/scheduler/reports",
13560
+ sampleMethod: "GET",
13561
+ build: (a) => ({
13562
+ method: "GET",
13563
+ path: "/scheduler/reports",
13564
+ query: query({ cronId: s(a.cron), projectId: s(a.project), page: n(a.page)?.toString(), limit: n(a.limit)?.toString() })
13565
+ }),
13566
+ shape: (raw) => raw
13567
+ },
13568
+ {
13569
+ name: "hanoman_scheduler_report_get",
13570
+ title: "Baca laporan run cron",
13571
+ description: 'Baca SATU laporan run cron berikut isi markdown-nya (`body`) dan `filename` turunan. `report` = id laporan (sama dengan id run), atau `latest` (default) untuk laporan terbaru \u2014 saring dengan `cron` / `project`. 404 bila belum ada laporan. Contoh laporan terakhir sebuah cron: `{cron:"<id cron>"}`.',
13572
+ inputSchema: obj({ properties: {
13573
+ report: str("Id laporan, atau `latest` (default)."),
13574
+ cron: str("Untuk `latest`: batasi ke id cron ini."),
13575
+ project: str("Untuk `latest`: batasi ke id project ini.")
13576
+ } }),
13577
+ mode: "read",
13578
+ capability: "scheduler:read",
13579
+ samplePath: "/scheduler/reports/latest",
13580
+ sampleMethod: "GET",
13581
+ build: (a) => {
13582
+ const id = s(a.report);
13583
+ return id && id !== "latest" ? { method: "GET", path: `/scheduler/reports/${enc(id)}` } : { method: "GET", path: "/scheduler/reports/latest", query: query({ cronId: s(a.cron), projectId: s(a.project) }) };
13584
+ },
13585
+ shape: (raw) => raw
13586
+ },
13338
13587
  {
13339
13588
  name: "hanoman_scheduler_cron_create",
13340
13589
  title: "Buat cronjob (BERBAHAYA)",
@@ -14616,6 +14865,16 @@ var init_mcp = __esm({
14616
14865
  }
14617
14866
  });
14618
14867
 
14868
+ // ../shared/src/cron-report.ts
14869
+ var CRON_REPORT_MAX_BYTES, enc2;
14870
+ var init_cron_report = __esm({
14871
+ "../shared/src/cron-report.ts"() {
14872
+ "use strict";
14873
+ CRON_REPORT_MAX_BYTES = 64 * 1024;
14874
+ enc2 = new TextEncoder();
14875
+ }
14876
+ });
14877
+
14619
14878
  // ../shared/src/terminal-workspace.ts
14620
14879
  var zSessionId, zTrackSizes, zTerminalGroup, zTerminalWorkspaceV1, zTerminalWorkspaceWrite, zTerminalWorkspaceSnapshot;
14621
14880
  var init_terminal_workspace = __esm({
@@ -14782,6 +15041,7 @@ var PRESENCE_PROTOCOL, MAX_PRESENCE_SESSIONS, PRESENCE_MAX_FRAME_BYTES, zPresenc
14782
15041
  var init_presence = __esm({
14783
15042
  "../shared/src/presence.ts"() {
14784
15043
  "use strict";
15044
+ init_enums();
14785
15045
  init_zod();
14786
15046
  init_session_admission();
14787
15047
  PRESENCE_PROTOCOL = 1;
@@ -14794,7 +15054,7 @@ var init_presence = __esm({
14794
15054
  flow: external_exports.string().max(40).optional(),
14795
15055
  /** Fase `active` dari `readPhases()`. Absen = sesi tanpa berkas fase (mis. konsol VPS). */
14796
15056
  phase: external_exports.string().max(80).optional(),
14797
- agent: external_exports.enum(["claude", "codex"]),
15057
+ agent: zAgent,
14798
15058
  status: external_exports.enum(["working", "waiting", "exited"]),
14799
15059
  startedAt: external_exports.string().max(40)
14800
15060
  }).strict();
@@ -14829,6 +15089,7 @@ var init_pending = __esm({
14829
15089
  var init_model_catalog = __esm({
14830
15090
  "../shared/src/model-catalog.ts"() {
14831
15091
  "use strict";
15092
+ init_antigravity();
14832
15093
  init_entities();
14833
15094
  }
14834
15095
  });
@@ -14870,6 +15131,7 @@ var init_src = __esm({
14870
15131
  init_session_kind();
14871
15132
  init_session_admission();
14872
15133
  init_session_end();
15134
+ init_overview();
14873
15135
  init_config();
14874
15136
  init_config_registry();
14875
15137
  init_semver();
@@ -14882,6 +15144,7 @@ var init_src = __esm({
14882
15144
  init_auto_merge();
14883
15145
  init_handled_by();
14884
15146
  init_cron_expr();
15147
+ init_cron_report();
14885
15148
  init_terminal_workspace();
14886
15149
  init_terminal_io();
14887
15150
  init_session_dialog();
@@ -14895,6 +15158,7 @@ var init_src = __esm({
14895
15158
  init_model_catalog();
14896
15159
  init_runtime_defaults();
14897
15160
  init_skills2();
15161
+ init_antigravity();
14898
15162
  }
14899
15163
  });
14900
15164
 
@@ -15297,6 +15561,7 @@ import { homedir as homedir2 } from "node:os";
15297
15561
  import { basename, dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
15298
15562
  import { existsSync, readdirSync, readFileSync } from "node:fs";
15299
15563
  function agentSkillHome(agent, env = process.env, osHome = homedir2()) {
15564
+ if (agent === "antigravity") return join2(osHome, ".gemini", "antigravity-cli");
15300
15565
  const own = (agent === "codex" ? env.HANOMAN_CODEX_HOME : env.HANOMAN_CLAUDE_HOME)?.trim();
15301
15566
  if (own) return own;
15302
15567
  if (agent === "codex") {
@@ -15391,12 +15656,13 @@ function cacheRoots(home) {
15391
15656
  const out = [];
15392
15657
  for (const marketplace of dirsIn(cache))
15393
15658
  for (const pkg of dirsIn(join2(cache, marketplace)))
15394
- for (const version3 of dirsIn(join2(cache, marketplace, pkg)))
15395
- out.push({ pkg, marketplace, dir: join2(cache, marketplace, pkg, version3) });
15659
+ for (const version2 of dirsIn(join2(cache, marketplace, pkg)))
15660
+ out.push({ pkg, marketplace, dir: join2(cache, marketplace, pkg, version2) });
15396
15661
  return out;
15397
15662
  }
15398
15663
  function disabledPlugins(agent, home) {
15399
15664
  const out = /* @__PURE__ */ new Set();
15665
+ if (agent === "antigravity") return out;
15400
15666
  if (agent === "claude") {
15401
15667
  const en = readJson(join2(home, "settings.json"))?.enabledPlugins;
15402
15668
  if (en && typeof en === "object") {
@@ -15444,7 +15710,7 @@ function scanAgentSkills(agent, env = process.env, osHome = homedir2()) {
15444
15710
  };
15445
15711
  const userDir = join2(home, "skills");
15446
15712
  add(userDir, skillsUnder(userDir, null));
15447
- for (const r of [...manifestRoots(home), ...cacheRoots(home)]) {
15713
+ for (const r of agent === "antigravity" ? [] : [...manifestRoots(home), ...cacheRoots(home)]) {
15448
15714
  if (disabled.has(`${r.pkg}@${r.marketplace}`)) continue;
15449
15715
  const found = pluginSkills(r.dir, r.pkg);
15450
15716
  if (!found.length) continue;
@@ -15559,6 +15825,25 @@ var init_config_env = __esm({
15559
15825
  }
15560
15826
  });
15561
15827
 
15828
+ // ../runner/src/agent-env.ts
15829
+ function agentEnvironment(agent, env) {
15830
+ const result = { ...env };
15831
+ if (agent === "antigravity") {
15832
+ delete result.CLAUDE_CODE_OAUTH_TOKEN;
15833
+ delete result.ANTHROPIC_API_KEY;
15834
+ } else {
15835
+ for (const key of ANTIGRAVITY_ENV_KEYS) delete result[key];
15836
+ }
15837
+ return result;
15838
+ }
15839
+ var ANTIGRAVITY_ENV_KEYS;
15840
+ var init_agent_env = __esm({
15841
+ "../runner/src/agent-env.ts"() {
15842
+ "use strict";
15843
+ ANTIGRAVITY_ENV_KEYS = ["GEMINI_API_KEY", "GOOGLE_GEMINI_BASE_URL"];
15844
+ }
15845
+ });
15846
+
15562
15847
  // ../runner/src/sandbox-probe.ts
15563
15848
  import { execFileSync } from "node:child_process";
15564
15849
  import { accessSync, constants } from "node:fs";
@@ -15623,15 +15908,15 @@ function prerequisites(env, facts) {
15623
15908
  function allReady(rows) {
15624
15909
  return rows.every((r) => r.ok);
15625
15910
  }
15626
- function run(file, args) {
15911
+ function run(file, args, env) {
15627
15912
  try {
15628
- return execFileSync(file, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
15913
+ return execFileSync(file, args, { encoding: "utf8", env: agentEnvironment(null, env), stdio: ["ignore", "pipe", "ignore"] }).trim();
15629
15914
  } catch {
15630
15915
  return null;
15631
15916
  }
15632
15917
  }
15633
15918
  function collectProbeFacts(env) {
15634
- const podman = run("podman", ["--version"]);
15919
+ const podman = run("podman", ["--version"], env);
15635
15920
  const network = env.HANOMAN_SESSION_NETWORK ?? "hanoman-egress";
15636
15921
  const dir = env.HANOMAN_AGENT_CREDENTIAL_DIR;
15637
15922
  let credentialDirReadable = false;
@@ -15644,8 +15929,8 @@ function collectProbeFacts(env) {
15644
15929
  }
15645
15930
  return {
15646
15931
  podman,
15647
- rootless: podman ? run("podman", ["info", "--format", "{{.Host.Security.Rootless}}"]) === "true" : false,
15648
- networkExists: podman ? run("podman", ["network", "exists", network]) !== null : false,
15932
+ rootless: podman ? run("podman", ["info", "--format", "{{.Host.Security.Rootless}}"], env) === "true" : false,
15933
+ networkExists: podman ? run("podman", ["network", "exists", network], env) !== null : false,
15649
15934
  credentialDirReadable
15650
15935
  };
15651
15936
  }
@@ -15653,6 +15938,7 @@ var filled2;
15653
15938
  var init_sandbox_probe = __esm({
15654
15939
  "../runner/src/sandbox-probe.ts"() {
15655
15940
  "use strict";
15941
+ init_agent_env();
15656
15942
  filled2 = (v) => !!v && v.trim() !== "";
15657
15943
  }
15658
15944
  });
@@ -15709,6 +15995,16 @@ var init_skill_files = __esm({
15709
15995
  }
15710
15996
  });
15711
15997
 
15998
+ // ../runner/src/antigravity-agent-config.ts
15999
+ var init_antigravity_agent_config = __esm({
16000
+ "../runner/src/antigravity-agent-config.ts"() {
16001
+ "use strict";
16002
+ init_src();
16003
+ init_agent_env();
16004
+ init_custom_agents();
16005
+ }
16006
+ });
16007
+
15712
16008
  // ../runner/src/index.ts
15713
16009
  var init_src2 = __esm({
15714
16010
  "../runner/src/index.ts"() {
@@ -15740,6 +16036,8 @@ var init_src2 = __esm({
15740
16036
  init_subagent_statusline();
15741
16037
  init_skill_library();
15742
16038
  init_skill_files();
16039
+ init_agent_env();
16040
+ init_antigravity_agent_config();
15743
16041
  }
15744
16042
  });
15745
16043
 
@@ -16125,6 +16423,8 @@ var doctor_exports = {};
16125
16423
  __export(doctor_exports, {
16126
16424
  default: () => doctor,
16127
16425
  doctorReport: () => doctorReport,
16426
+ probeDoctorVersion: () => probeDoctorVersion,
16427
+ resolveDoctorAntigravityBin: () => resolveDoctorAntigravityBin,
16128
16428
  resolveDoctorCodexBin: () => resolveDoctorCodexBin
16129
16429
  });
16130
16430
  import { execFileSync as execFileSync4 } from "node:child_process";
@@ -16142,6 +16442,11 @@ function doctorReport(p3) {
16142
16442
  text: p3.codex ? `codex ${p3.codex} \u2014 custom agent native ${codexNativeAgentsSupported(p3.codex) ? "siap" : `butuh >= ${CODEX_NATIVE_AGENTS_MIN_CLIENT}; sesi parent tetap bisa berjalan`}` : "codex \u2014 tak ada",
16143
16443
  fatal: false
16144
16444
  },
16445
+ {
16446
+ mark: p3.antigravity ? p3.sandboxRequired ? "!" : "\u2713" : "\xB7",
16447
+ text: p3.antigravity ? `Antigravity CLI ${p3.antigravity} \u2014 auth manual; ${p3.sandboxRequired ? "sandbox belum didukung" : "host/lab; jalankan agy untuk login; autentikasi belum diverifikasi"}` : p3.sandboxRequired ? "Antigravity CLI \u2014 host/lab saja; sandbox belum didukung; probe/login tidak dijalankan" : "Antigravity CLI \u2014 tak ada (opsional; install/login manual)",
16448
+ fatal: false
16449
+ },
16145
16450
  // SPEC-471 · ADR-0095 · `gh` opsional: tanpa dia tarik issue jatuh ke HTTPS + GITHUB_TOKEN.
16146
16451
  {
16147
16452
  mark: p3.gh ? "\u2713" : "\xB7",
@@ -16171,16 +16476,16 @@ function doctorReport(p3) {
16171
16476
  }
16172
16477
  ];
16173
16478
  for (const m of p3.methods) {
16174
- const agent = m.agent === "codex" ? "Codex CLI" : "Claude Code";
16479
+ const agent = m.agent === "antigravity" ? "Antigravity CLI" : m.agent === "codex" ? "Codex CLI" : "Claude Code";
16175
16480
  rows.push({
16176
16481
  mark: m.ready ? "\u2713" : "!",
16177
- text: m.ready ? `metode ${m.method} \xB7 ${agent} \u2014 siap` : `metode ${m.method} \xB7 ${agent} \u2014 belum siap: ` + [...m.missingPackages, ...m.missingSkills].join(", ") + m.install.map((c) => `
16482
+ text: m.available === false ? `metode ${m.method} \xB7 ${agent} \u2014 tidak tersedia: ${m.availabilityReason}` : m.ready ? `metode ${m.method} \xB7 ${agent} \u2014 siap` : `metode ${m.method} \xB7 ${agent} \u2014 belum siap: ` + [...m.missingPackages, ...m.missingSkills].join(", ") + m.install.map((c) => `
16178
16483
  ${c}`).join(""),
16179
16484
  fatal: false
16180
16485
  });
16181
16486
  }
16182
- if (!p3.claude && !p3.codex) {
16183
- rows.push({ mark: "\u2717", text: "tak ada CLI agen (claude ATAU codex wajib ada)", fatal: true });
16487
+ if (!p3.claude && !p3.codex && (!p3.antigravity || p3.sandboxRequired)) {
16488
+ rows.push({ mark: "\u2717", text: "tak ada CLI agen (claude, codex ATAU Antigravity host/lab wajib ada)", fatal: true });
16184
16489
  }
16185
16490
  return { lines: rows.map((r) => ` ${r.mark} ${r.text}`), ok: !rows.some((r) => r.fatal) };
16186
16491
  }
@@ -16199,9 +16504,23 @@ function writable(path) {
16199
16504
  p3 = up;
16200
16505
  }
16201
16506
  }
16202
- function version(bin, args) {
16507
+ function probeDoctorVersion(bin, args, env, agent = null) {
16508
+ if (agent === "antigravity" && (resolveHardening(env) || (env.HANOMAN_SESSION_SANDBOX ?? "off") !== "off")) return null;
16203
16509
  try {
16204
- return execFileSync4(bin, args, { encoding: "utf8", timeout: 1e4, stdio: ["ignore", "pipe", "ignore"] }).trim().split("\n")[0] ?? null;
16510
+ const output = execFileSync4(bin, args, {
16511
+ encoding: "utf8",
16512
+ env: agentEnvironment(agent, env),
16513
+ timeout: 1e4,
16514
+ ...agent === "antigravity" ? { maxBuffer: 16 * 1024, killSignal: "SIGKILL" } : {},
16515
+ stdio: ["ignore", "pipe", "ignore"]
16516
+ }).trim();
16517
+ if (agent === "antigravity") {
16518
+ const numeric = "(?:0|[1-9]\\d*)";
16519
+ const identifier = "(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)";
16520
+ const semver = new RegExp(`^${numeric}\\.${numeric}\\.${numeric}(?:-${identifier}(?:\\.${identifier})*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$`);
16521
+ return semver.test(output) ? output : null;
16522
+ }
16523
+ return output.split("\n")[0] || null;
16205
16524
  } catch {
16206
16525
  return null;
16207
16526
  }
@@ -16214,6 +16533,14 @@ async function resolveDoctorCodexBin(env, dbUrl, read = readRuntimeConfig) {
16214
16533
  }
16215
16534
  return env.HANOMAN_CODEX_BIN?.trim() || "codex";
16216
16535
  }
16536
+ async function resolveDoctorAntigravityBin(env, dbUrl, read = readRuntimeConfig) {
16537
+ try {
16538
+ const configured = (await read(dbUrl, "HANOMAN_ANTIGRAVITY_BIN"))?.trim();
16539
+ if (configured) return configured;
16540
+ } catch {
16541
+ }
16542
+ return env.HANOMAN_ANTIGRAVITY_BIN?.trim() || "agy";
16543
+ }
16217
16544
  async function doctor(_argv, ctx) {
16218
16545
  let layout;
16219
16546
  let db;
@@ -16234,11 +16561,13 @@ async function doctor(_argv, ctx) {
16234
16561
  { label: "upload", path: d.uploads, writable: writable(d.uploads), fatal: false },
16235
16562
  { label: "key SSH", path: d.sshKeys, writable: writable(d.sshKeys), fatal: false }
16236
16563
  ];
16237
- const claude = version(ctx.env.HANOMAN_CLAUDE_BIN ?? "claude", ["--version"]);
16564
+ const version2 = (bin, args) => probeDoctorVersion(bin, args, ctx.env);
16565
+ const claude = version2(ctx.env.HANOMAN_CLAUDE_BIN ?? "claude", ["--version"]);
16566
+ const antigravity = probeDoctorVersion(await resolveDoctorAntigravityBin(ctx.env, dbUrl), ["--version"], ctx.env, "antigravity");
16238
16567
  const codexProbe = codexNativeVersionProbe(ctx.env, await resolveDoctorCodexBin(ctx.env, dbUrl));
16239
- const codex = version(codexProbe.bin, codexProbe.args);
16568
+ const codex = version2(codexProbe.bin, codexProbe.args);
16240
16569
  const method = METHODS[DEFAULT_METHOD];
16241
- const methods = zAgent.options.filter((a) => (a === "codex" ? codex : claude) !== null).map((a) => {
16570
+ const methods = zAgent.options.filter((a) => ({ claude, codex, antigravity })[a] !== null).map((a) => {
16242
16571
  const s2 = scanAgentSkills(a, ctx.env);
16243
16572
  return methodStatus(method, a, { skills: s2.skills.map((k) => k.id), packages: s2.packages });
16244
16573
  });
@@ -16248,12 +16577,13 @@ async function doctor(_argv, ctx) {
16248
16577
  const sandboxReady = allReady(prerequisites(ctx.env, podmanFacts));
16249
16578
  const r = doctorReport({
16250
16579
  node: process.version,
16251
- git: version("git", ["--version"]),
16252
- tmux: version("tmux", ["-V"]),
16580
+ git: version2("git", ["--version"]),
16581
+ tmux: version2("tmux", ["-V"]),
16253
16582
  claude,
16254
16583
  codex,
16255
- gh: version(ctx.env.HANOMAN_GH_BIN ?? "gh", ["--version"]),
16256
- curl: version("curl", ["--version"]),
16584
+ antigravity,
16585
+ gh: version2(ctx.env.HANOMAN_GH_BIN ?? "gh", ["--version"]),
16586
+ curl: version2("curl", ["--version"]),
16257
16587
  dirs,
16258
16588
  web: layout.web !== null,
16259
16589
  db,
@@ -17337,10 +17667,10 @@ var init_regexes = __esm({
17337
17667
  nanoid = /^[a-zA-Z0-9_-]{21}$/;
17338
17668
  duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
17339
17669
  guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
17340
- uuid = (version3) => {
17341
- if (!version3)
17670
+ uuid = (version2) => {
17671
+ if (!version2)
17342
17672
  return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
17343
- return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version3}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
17673
+ return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
17344
17674
  };
17345
17675
  email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
17346
17676
  _emoji = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`;
@@ -17808,10 +18138,10 @@ var init_doc = __esm({
17808
18138
  });
17809
18139
 
17810
18140
  // ../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js
17811
- var version2;
18141
+ var version;
17812
18142
  var init_versions = __esm({
17813
18143
  "../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js"() {
17814
- version2 = {
18144
+ version = {
17815
18145
  major: 4,
17816
18146
  minor: 4,
17817
18147
  patch: 3
@@ -18117,7 +18447,7 @@ var init_schemas = __esm({
18117
18447
  inst ?? (inst = {});
18118
18448
  inst._zod.def = def;
18119
18449
  inst._zod.bag = inst._zod.bag || {};
18120
- inst._zod.version = version2;
18450
+ inst._zod.version = version;
18121
18451
  const checks = [...inst._zod.def.checks ?? []];
18122
18452
  if (inst._zod.traits.has("$ZodCheck")) {
18123
18453
  checks.unshift(inst);
@@ -23202,14 +23532,14 @@ function missingClientCapabilities(required2, declared) {
23202
23532
  }
23203
23533
  return Object.keys(missing).length > 0 ? missing : void 0;
23204
23534
  }
23205
- function isModernProtocolVersion(version3) {
23206
- return version3 >= FIRST_MODERN_PROTOCOL_VERSION;
23535
+ function isModernProtocolVersion(version2) {
23536
+ return version2 >= FIRST_MODERN_PROTOCOL_VERSION;
23207
23537
  }
23208
23538
  function legacyProtocolVersions(versions) {
23209
- return versions.filter((version3) => !isModernProtocolVersion(version3));
23539
+ return versions.filter((version2) => !isModernProtocolVersion(version2));
23210
23540
  }
23211
23541
  function modernProtocolVersions(versions) {
23212
- return versions.filter((version3) => isModernProtocolVersion(version3));
23542
+ return versions.filter((version2) => isModernProtocolVersion(version2));
23213
23543
  }
23214
23544
  function appendTextFallbackForNonObject(result) {
23215
23545
  const sc = result.structuredContent;
@@ -25323,8 +25653,8 @@ function getWireResultSchemas() {
25323
25653
  };
25324
25654
  return wireResultSchemasMemo;
25325
25655
  }
25326
- function codecForVersion(version3) {
25327
- return version3 !== void 0 && isModernProtocolVersion(version3) ? rev2026Codec : rev2025Codec;
25656
+ function codecForVersion(version2) {
25657
+ return version2 !== void 0 && isModernProtocolVersion(version2) ? rev2026Codec : rev2025Codec;
25328
25658
  }
25329
25659
  function classifiedWireEra(classification) {
25330
25660
  if (classification.revision !== void 0) return codecForVersion(classification.revision).era;
@@ -25761,8 +26091,8 @@ function withRequestStateValue(ctx, value) {
25761
26091
  }
25762
26092
  };
25763
26093
  }
25764
- function setNegotiatedProtocolVersion(instance, version3) {
25765
- writeNegotiatedProtocolVersion(instance, version3);
26094
+ function setNegotiatedProtocolVersion(instance, version2) {
26095
+ writeNegotiatedProtocolVersion(instance, version2);
25766
26096
  }
25767
26097
  function isPlainObject$1(value) {
25768
26098
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -26992,8 +27322,8 @@ var init_src_CX2iR2pK = __esm({
26992
27322
  */
26993
27323
  _negotiatedProtocolVersion;
26994
27324
  static {
26995
- writeNegotiatedProtocolVersion = (instance, version3) => {
26996
- instance._negotiatedProtocolVersion = version3;
27325
+ writeNegotiatedProtocolVersion = (instance, version2) => {
27326
+ instance._negotiatedProtocolVersion = version2;
26997
27327
  };
26998
27328
  }
26999
27329
  _supportedProtocolVersions;
@@ -35208,7 +35538,7 @@ var init_mcp_DXXb3Vv3 = __esm({
35208
35538
  if (identity.clientInfo !== void 0) server._clientVersion = identity.clientInfo;
35209
35539
  };
35210
35540
  installDiscoverHandler = (server, servedModernVersions) => {
35211
- const missing = servedModernVersions.filter((version3) => !server._supportedProtocolVersions.includes(version3));
35541
+ const missing = servedModernVersions.filter((version2) => !server._supportedProtocolVersions.includes(version2));
35212
35542
  if (missing.length > 0) server._supportedProtocolVersions = [...server._supportedProtocolVersions, ...missing];
35213
35543
  server.setRequestHandler("server/discover", () => server._ondiscover());
35214
35544
  };
@@ -36766,8 +37096,8 @@ var init_stdio = __esm({
36766
37096
  if (this._outboundIntercept?.(message) === "handled") return;
36767
37097
  return this._wire.send(message, options);
36768
37098
  }
36769
- setProtocolVersion = (version3) => {
36770
- this._wire.setProtocolVersion?.(version3);
37099
+ setProtocolVersion = (version2) => {
37100
+ this._wire.setProtocolVersion?.(version2);
36771
37101
  };
36772
37102
  /** Forwards one inbound message to the connected instance. */
36773
37103
  deliver(message, extra) {
@@ -37556,7 +37886,7 @@ function localScriptPath(cwd = process.cwd()) {
37556
37886
  }
37557
37887
  function runScript(env, ctx) {
37558
37888
  return new Promise((resolve6) => {
37559
- const p3 = spawn2("bash", [localScriptPath(ctx.cwd)], { env: { ...process.env, ...env } });
37889
+ const p3 = spawn2("bash", [localScriptPath(ctx.cwd)], { env: { ...agentEnvironment(null, ctx.env), ...env } });
37560
37890
  p3.stdout.on("data", (d) => ctx.stdout(String(d)));
37561
37891
  p3.stderr.on("data", (d) => ctx.stderr(String(d)));
37562
37892
  p3.on("close", (code) => resolve6(code ?? 1));
@@ -37591,6 +37921,7 @@ var PROFILES, flag;
37591
37921
  var init_provision = __esm({
37592
37922
  "src/commands/provision.ts"() {
37593
37923
  "use strict";
37924
+ init_src2();
37594
37925
  PROFILES = ["lab", "production"];
37595
37926
  flag = (args, name) => args.find((a) => a.startsWith(`--${name}=`))?.split("=").slice(1).join("=");
37596
37927
  }
@@ -37834,7 +38165,9 @@ var init_migrate_pg = __esm({
37834
38165
  "QaReport",
37835
38166
  "QaCase",
37836
38167
  "QaFinding",
37837
- "QaAttachment"
38168
+ "QaAttachment",
38169
+ // ADR-0222 · CronReport sesudah Project (FK projectId, cascade); tak ada di sumber Postgres lama.
38170
+ "CronReport"
37838
38171
  ];
37839
38172
  CHUNK = 200;
37840
38173
  INT8_OID = 20;
@@ -38078,10 +38411,10 @@ var init_docs_link = __esm({
38078
38411
 
38079
38412
  // src/release/pack.ts
38080
38413
  import { join as join15 } from "node:path";
38081
- function packageJsonFor(version3, deps) {
38414
+ function packageJsonFor(version2, deps) {
38082
38415
  return {
38083
38416
  name: PKG_NAME,
38084
- version: version3,
38417
+ version: version2,
38085
38418
  description: "Orchestrator + dashboard workflow docs-driven untuk sesi Claude Code / Codex",
38086
38419
  type: "module",
38087
38420
  repository: { type: "git", url: REPO_URL },
@@ -38211,8 +38544,8 @@ async function pack(argv, ctx) {
38211
38544
  }
38212
38545
  const outIdx = argv.indexOf("--out");
38213
38546
  const out = outIdx === -1 ? join16(repo, "dist-npm") : join16(repo, argv[outIdx + 1] ?? "dist-npm");
38214
- const version3 = JSON.parse(readFileSync9(join16(repo, "package.json"), "utf8")).version;
38215
- if (!version3) {
38547
+ const version2 = JSON.parse(readFileSync9(join16(repo, "package.json"), "utf8")).version;
38548
+ if (!version2) {
38216
38549
  ctx.stderr("pack: root package.json tanpa field version\n");
38217
38550
  return 1;
38218
38551
  }
@@ -38237,14 +38570,14 @@ async function pack(argv, ctx) {
38237
38570
  cpSync(item.from, dest, item.dir ? { recursive: true } : {});
38238
38571
  }
38239
38572
  writeFileSync3(join16(out, "bin/hanoman.mjs"), BIN_SHIM);
38240
- writeFileSync3(join16(out, "package.json"), JSON.stringify(packageJsonFor(version3, deps), null, 2) + "\n");
38573
+ writeFileSync3(join16(out, "package.json"), JSON.stringify(packageJsonFor(version2, deps), null, 2) + "\n");
38241
38574
  const missing = REQUIRED_ARTIFACTS.filter((a) => !existsSync10(join16(out, a)));
38242
38575
  if (missing.length) {
38243
38576
  ctx.stderr(`pack: artefak wajib hilang: ${missing.join(", ")}
38244
38577
  `);
38245
38578
  return 1;
38246
38579
  }
38247
- ctx.stdout(`pack \xB7 ${out} \xB7 hanoman@${version3} \xB7 ${REQUIRED_ARTIFACTS.length} artefak wajib ada
38580
+ ctx.stdout(`pack \xB7 ${out} \xB7 hanoman@${version2} \xB7 ${REQUIRED_ARTIFACTS.length} artefak wajib ada
38248
38581
  `);
38249
38582
  ctx.stdout("terbitkan MANUAL: cd dist-npm && npm publish --otp <kode>\n");
38250
38583
  return 0;
@@ -38353,10 +38686,10 @@ var init_router = __esm({
38353
38686
  doctor periksa prasyarat: node, git, tmux, CLI agen, data dir
38354
38687
  update [--check] bandingkan versi dengan registry npm; pasang yang terbaru
38355
38688
  provision [--with=a,b] [--probe] pasang komponen di MESIN INI (hanoman, caddy, claude,
38356
- [--profile=lab|production] codex, gh, \u2026). --probe hanya melaporkan apa yang ada.
38689
+ [--profile=lab|production] codex, antigravity (host/lab), gh, \u2026). --probe hanya melaporkan apa yang ada.
38357
38690
  [--domain=<d>] [--dry-run] [--yes]
38358
38691
  mcp [--read-only] [--host <url>] MCP server stdio untuk klien AI (Claude Code/Desktop,
38359
- [--max-bytes <n>] Codex, Cursor, Copilot). Token dari HANOMAN_AGENT_TOKEN.
38692
+ [--max-bytes <n>] Codex, Antigravity, Cursor, Copilot). Token dari HANOMAN_AGENT_TOKEN.
38360
38693
  [--transfer-dir <d>] direktori tambahan untuk unggah/unduh berkas (ADR-0183)
38361
38694
  migrate-from-postgres --from <url> pindahkan data Postgres lama ke SQLite
38362
38695
  [--to <file>] [--dry-run] [--force]