hanoman 0.1.25 → 0.1.26

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.25",
3
- "sha": "53d6464",
4
- "builtAt": "2026-08-10T04:26:46.836Z"
2
+ "version": "0.1.26",
3
+ "sha": "6bc6624",
4
+ "builtAt": "2026-08-10T22:52:51.169Z"
5
5
  }
package/dist/cli.js CHANGED
@@ -4985,8 +4985,68 @@ var init_prd_status = __esm({
4985
4985
  }
4986
4986
  });
4987
4987
 
4988
+ // ../shared/src/cron-expr.ts
4989
+ function parseField(raw, lo, hi) {
4990
+ const out = /* @__PURE__ */ new Set();
4991
+ for (const part of raw.split(",")) {
4992
+ const slash = part.indexOf("/");
4993
+ const rangePart = slash === -1 ? part : part.slice(0, slash);
4994
+ const stepPart = slash === -1 ? void 0 : part.slice(slash + 1);
4995
+ let step = 1;
4996
+ if (stepPart !== void 0) {
4997
+ if (!/^\d{1,2}$/.test(stepPart)) return null;
4998
+ step = Number(stepPart);
4999
+ if (step < 1) return null;
5000
+ }
5001
+ let from;
5002
+ let to;
5003
+ if (rangePart === "*") {
5004
+ from = lo;
5005
+ to = hi;
5006
+ } else if (/^\d{1,2}$/.test(rangePart)) {
5007
+ from = Number(rangePart);
5008
+ to = stepPart === void 0 ? from : hi;
5009
+ } else {
5010
+ const m = /^(\d{1,2})-(\d{1,2})$/.exec(rangePart);
5011
+ if (!m) return null;
5012
+ from = Number(m[1]);
5013
+ to = Number(m[2]);
5014
+ }
5015
+ if (from < lo || to > hi || from > to) return null;
5016
+ for (let v = from; v <= to; v += step) out.add(v);
5017
+ }
5018
+ return out.size ? out : null;
5019
+ }
5020
+ function parseCron(expr) {
5021
+ const parts = expr.trim().split(/\s+/);
5022
+ if (parts.length !== 5) return null;
5023
+ const sets = [];
5024
+ for (let i = 0; i < 5; i++) {
5025
+ const [lo, hi] = BOUNDS[i];
5026
+ const s2 = parseField(parts[i], lo, hi);
5027
+ if (!s2) return null;
5028
+ sets.push(s2);
5029
+ }
5030
+ return {
5031
+ minute: sets[0],
5032
+ hour: sets[1],
5033
+ dom: sets[2],
5034
+ month: sets[3],
5035
+ dow: new Set([...sets[4]].map((n2) => n2 === 7 ? 0 : n2)),
5036
+ domRestricted: parts[2] !== "*",
5037
+ dowRestricted: parts[4] !== "*"
5038
+ };
5039
+ }
5040
+ var BOUNDS;
5041
+ var init_cron_expr = __esm({
5042
+ "../shared/src/cron-expr.ts"() {
5043
+ "use strict";
5044
+ BOUNDS = [[0, 59], [0, 23], [1, 31], [1, 12], [0, 7]];
5045
+ }
5046
+ });
5047
+
4988
5048
  // ../shared/src/dto.ts
4989
- var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zUpdateProject, zCreateSpec, zPatchSpec, zChangeSpecSource, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerQueueCounts, zSchedulerState, zLeadDecisionView, zLeadFlowView, zLeadAnswer, zLeadProjectStatus, zLeadStatusView, zFlow, zPrdBrief, zPrdDoc, zBreakdownItem, zBreakdownDoc, zBatchCreateSpec, zEscalationTarget, zEscalationPrefill, zAuditEscalation, zAuditEscalationView, zTerminalSession, zDocFileContent, zDocIndexCat, zDocIndex, HOST_RE, USER_RE, zCreateVps, zPatchVps, USER_ROLES, zUserRole, zLogin, zSignup, zChangePassword, zCreateClientAccount, zUpdateClientAccount, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, UPDATE_RESTART_EXIT, zUpdateApplyBody, zTicketView, zTicketAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus;
5049
+ var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zUpdateProject, zCreateSpec, zPatchSpec, zChangeSpecSource, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerQueueCounts, zSchedulerState, zLeadDecisionView, zLeadFlowView, zLeadAnswer, zLeadProjectStatus, zLeadStatusView, zFlow, zPrdBrief, zPrdDoc, zBreakdownItem, zBreakdownDoc, zBatchCreateSpec, zEscalationTarget, zEscalationPrefill, zAuditEscalation, zAuditEscalationView, zTerminalSession, zDocFileContent, zDocIndexCat, zDocIndex, HOST_RE, USER_RE, zCreateVps, zPatchVps, USER_ROLES, zUserRole, zLogin, zSignup, zChangePassword, zCreateClientAccount, zUpdateClientAccount, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, UPDATE_RESTART_EXIT, zUpdateApplyBody, zTicketView, zTicketAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus, zCronExpr, zCreateCron, zPatchCron, zSchedulerCron, zSchedulerCronRun;
4990
5050
  var init_dto = __esm({
4991
5051
  "../shared/src/dto.ts"() {
4992
5052
  "use strict";
@@ -4997,6 +5057,7 @@ var init_dto = __esm({
4997
5057
  init_prd_status();
4998
5058
  init_enums();
4999
5059
  init_spec_source();
5060
+ init_cron_expr();
5000
5061
  zIssueDeviceToken = external_exports.object({ name: external_exports.string().min(1) });
5001
5062
  zSessionResult = external_exports.object({
5002
5063
  id: external_exports.string(),
@@ -5473,6 +5534,53 @@ var init_dto = __esm({
5473
5534
  status: external_exports.string(),
5474
5535
  createdAt: external_exports.string()
5475
5536
  });
5537
+ zCronExpr = external_exports.string().trim().refine((v) => parseCron(v) !== null, "cron expression tak sah");
5538
+ zCreateCron = external_exports.object({
5539
+ project: external_exports.string().min(1),
5540
+ name: external_exports.string().trim().min(1).max(120),
5541
+ expr: zCronExpr,
5542
+ prompt: external_exports.string().trim().min(1).max(8e3),
5543
+ agent: zAgent.optional(),
5544
+ model: external_exports.string().optional(),
5545
+ effort: external_exports.string().optional(),
5546
+ enabled: external_exports.boolean().default(false)
5547
+ // default aman: cron baru lahir nonaktif
5548
+ });
5549
+ zPatchCron = external_exports.object({
5550
+ name: external_exports.string().trim().min(1).max(120).optional(),
5551
+ expr: zCronExpr.optional(),
5552
+ prompt: external_exports.string().trim().min(1).max(8e3).optional(),
5553
+ agent: zAgent.nullable().optional(),
5554
+ model: external_exports.string().nullable().optional(),
5555
+ effort: external_exports.string().nullable().optional(),
5556
+ enabled: external_exports.boolean().optional()
5557
+ });
5558
+ zSchedulerCron = external_exports.object({
5559
+ id: external_exports.string(),
5560
+ projectId: external_exports.string(),
5561
+ name: external_exports.string(),
5562
+ expr: external_exports.string(),
5563
+ prompt: external_exports.string(),
5564
+ agent: external_exports.string().nullable(),
5565
+ model: external_exports.string().nullable(),
5566
+ effort: external_exports.string().nullable(),
5567
+ enabled: external_exports.boolean(),
5568
+ nextRunAt: external_exports.string().nullable(),
5569
+ lastRunAt: external_exports.string().nullable(),
5570
+ createdAt: external_exports.string()
5571
+ });
5572
+ zSchedulerCronRun = external_exports.object({
5573
+ id: external_exports.string(),
5574
+ cronId: external_exports.string(),
5575
+ projectId: external_exports.string(),
5576
+ dueAt: external_exports.string(),
5577
+ startedAt: external_exports.string().nullable(),
5578
+ status: external_exports.string(),
5579
+ sessionId: external_exports.string().nullable(),
5580
+ note: external_exports.string().nullable(),
5581
+ manual: external_exports.boolean(),
5582
+ createdAt: external_exports.string()
5583
+ });
5476
5584
  }
5477
5585
  });
5478
5586
 
@@ -5619,6 +5727,13 @@ var init_api = __esm({
5619
5727
  schedulerQueueRequeue: (id) => `${API}/scheduler/queue/${encodeURIComponent(id)}/requeue`,
5620
5728
  // SPEC-523 · antrean sebagai daftar berhalaman (page/limit + status), lepas dari `state`.
5621
5729
  schedulerQueue: `${API}/scheduler/queue`,
5730
+ // SPEC-646 · ADR-0112 · cronjob per project. Di bawah prefix `scheduler` seperti tetangganya,
5731
+ // TAPI capability-nya bukan turunan otomatis: `capabilityForRoute` memberi `crons` cabang
5732
+ // COOKIE_ONLY sendiri — sebuah cron adalah `POST /terminal/sessions` yang ditunda.
5733
+ schedulerCrons: `${API}/scheduler/crons`,
5734
+ schedulerCron: (id) => `${API}/scheduler/crons/${encodeURIComponent(id)}`,
5735
+ schedulerCronRunNow: (id) => `${API}/scheduler/crons/${encodeURIComponent(id)}/run`,
5736
+ schedulerCronRuns: (id) => `${API}/scheduler/crons/${encodeURIComponent(id)}/runs`,
5622
5737
  // SPEC-409 · ADR-0091 · hanoman-lead. Semua HTTP (polling) — tak ada kanal WS baru (AC-26).
5623
5738
  leadConfig: `${API}/lead/config`,
5624
5739
  leadStatus: `${API}/lead/status`,
@@ -7053,6 +7168,7 @@ var init_src = __esm({
7053
7168
  init_mcp();
7054
7169
  init_auto_merge();
7055
7170
  init_changelog();
7171
+ init_cron_expr();
7056
7172
  }
7057
7173
  });
7058
7174
 
@@ -28630,7 +28746,12 @@ var init_migrate_pg = __esm({
28630
28746
  "SyncConflict",
28631
28747
  // SPEC-485 · ADR-0102 · LeadFlow SEBELUM LeadDecision: `flowId` menunjuk ke sana. Tanpa FK, tapi
28632
28748
  // urutan tabel harus tetap mencerminkan arah tautannya bagi pembaca berikutnya.
28749
+ // SPEC-646 · ADR-0112 · SchedulerCron SEBELUM SchedulerCronRun: `cronId` menunjuk ke sana. Tanpa
28750
+ // FK (cermin SchedulerQueueItem/LeadDecision), tapi urutan tabel harus tetap mencerminkan arah
28751
+ // tautannya bagi pembaca berikutnya.
28633
28752
  "SchedulerQueueItem",
28753
+ "SchedulerCron",
28754
+ "SchedulerCronRun",
28634
28755
  "RuntimeConfig",
28635
28756
  "LeadFlow",
28636
28757
  "LeadDecision",