doer-agent 0.7.8 → 0.7.9

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.
@@ -4,18 +4,83 @@ import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/p
4
4
  import { formatPatch, structuredPatch } from "diff";
5
5
  const AGENT_NOTES_ROOT = ".doer-agent/notes";
6
6
  const PATCHES_ROOT = `${AGENT_NOTES_ROOT}/patches`;
7
+ function resolveSystemTimeZone() {
8
+ const configured = process.env.TZ?.trim();
9
+ if (configured) {
10
+ return configured;
11
+ }
12
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
13
+ }
14
+ function resolveTimeZoneOffsetString(date, timeZone) {
15
+ try {
16
+ const parts = new Intl.DateTimeFormat("en-US", {
17
+ timeZone,
18
+ timeZoneName: "shortOffset",
19
+ hour: "2-digit",
20
+ minute: "2-digit",
21
+ hour12: false,
22
+ }).formatToParts(date);
23
+ const token = parts.find((part) => part.type === "timeZoneName")?.value || "GMT+0";
24
+ const matched = token.match(/GMT([+-]\d{1,2})(?::?(\d{2}))?/i);
25
+ if (!matched) {
26
+ return "+00:00";
27
+ }
28
+ const hourRaw = matched[1] || "+0";
29
+ const minuteRaw = matched[2] || "00";
30
+ const sign = hourRaw.startsWith("-") ? "-" : "+";
31
+ const absHour = String(Math.abs(Number.parseInt(hourRaw, 10))).padStart(2, "0");
32
+ const absMinute = String(Math.abs(Number.parseInt(minuteRaw, 10))).padStart(2, "0");
33
+ return `${sign}${absHour}:${absMinute}`;
34
+ }
35
+ catch {
36
+ return "+00:00";
37
+ }
38
+ }
39
+ function systemTimeParts(date) {
40
+ const timeZone = resolveSystemTimeZone();
41
+ const parts = new Intl.DateTimeFormat("en-CA", {
42
+ timeZone,
43
+ year: "numeric",
44
+ month: "2-digit",
45
+ day: "2-digit",
46
+ hour: "2-digit",
47
+ minute: "2-digit",
48
+ second: "2-digit",
49
+ hour12: false,
50
+ hourCycle: "h23",
51
+ }).formatToParts(date);
52
+ const pick = (type) => {
53
+ return parts.find((part) => part.type === type)?.value || "00";
54
+ };
55
+ return {
56
+ year: pick("year"),
57
+ month: pick("month"),
58
+ day: pick("day"),
59
+ hours: pick("hour"),
60
+ minutes: pick("minute"),
61
+ seconds: pick("second"),
62
+ milliseconds: String(date.getMilliseconds()).padStart(3, "0"),
63
+ offset: resolveTimeZoneOffsetString(date, timeZone),
64
+ };
65
+ }
7
66
  function nowIso() {
8
- return new Date().toISOString();
67
+ const parts = systemTimeParts(new Date());
68
+ return `${parts.year}-${parts.month}-${parts.day}T${parts.hours}:${parts.minutes}:${parts.seconds}.${parts.milliseconds}${parts.offset}`;
9
69
  }
10
70
  function createTimeBasedPatchId(createdAt) {
11
- const stamp = createdAt.replace(/[-:.]/g, "").replace("T", "t").replace("Z", "z");
71
+ const stamp = createdAt
72
+ .replace("T", "t")
73
+ .replace(/([+-])(\d{2}):?(\d{2})$/, (_match, sign, hours, minutes) => {
74
+ return `${sign === "-" ? "m" : "p"}${hours}${minutes}`;
75
+ })
76
+ .replace(/[-:.]/g, "")
77
+ .replace("Z", "z");
12
78
  const random = Math.random().toString(36).slice(2, 8);
13
79
  return `${stamp}-${random}`;
14
80
  }
15
81
  function patchRelPath(id, createdAt) {
16
82
  const date = new Date(createdAt);
17
- const year = String(date.getUTCFullYear());
18
- const month = String(date.getUTCMonth() + 1).padStart(2, "0");
83
+ const { year, month } = systemTimeParts(Number.isNaN(date.getTime()) ? new Date() : date);
19
84
  return path.posix.join(PATCHES_ROOT, year, month, `${id}.patch`);
20
85
  }
21
86
  export function sanitizeNoteId(value) {
@@ -171,7 +171,10 @@ export function writeRpcStream(requestId, stream, chunk) {
171
171
  }
172
172
  function resolveLogTimeZone() {
173
173
  const configured = process.env.DOER_AGENT_LOG_TIMEZONE?.trim() || process.env.TZ?.trim();
174
- return configured && configured.length > 0 ? configured : "Asia/Seoul";
174
+ if (configured && configured.length > 0) {
175
+ return configured;
176
+ }
177
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
175
178
  }
176
179
  function resolveTimeZoneOffsetString(date, timeZone) {
177
180
  try {
@@ -210,6 +213,7 @@ export function formatLocalTimestamp(date = new Date()) {
210
213
  minute: "2-digit",
211
214
  second: "2-digit",
212
215
  hour12: false,
216
+ hourCycle: "h23",
213
217
  }).formatToParts(date);
214
218
  const pick = (type) => {
215
219
  return parts.find((part) => part.type === type)?.value || "00";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doer-agent",
3
- "version": "0.7.8",
3
+ "version": "0.7.9",
4
4
  "description": "Reverse-polling agent runtime for doer",
5
5
  "type": "module",
6
6
  "main": "dist/agent.js",