@temporal-cortex/truth-engine 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -57,6 +57,8 @@ export interface UnifiedAvailability {
57
57
  window_end: string;
58
58
  privacy: string;
59
59
  }
60
+ /** @internal — exposed for testing only. */
61
+ export declare function _resetHint(): void;
60
62
  /**
61
63
  * Merge N event streams into unified availability within a time window.
62
64
  *
@@ -81,3 +83,64 @@ export declare function mergeAvailability(streams: EventStream[], windowStart: s
81
83
  * @returns The first qualifying free slot, or null if none found
82
84
  */
83
85
  export declare function findFirstFreeAcross(streams: EventStream[], windowStart: string, windowEnd: string, minDurationMinutes: number): FreeSlot | null;
86
+ export interface ConvertedDatetime {
87
+ utc: string;
88
+ local: string;
89
+ timezone: string;
90
+ utc_offset: string;
91
+ dst_active: boolean;
92
+ }
93
+ export interface DurationInfo {
94
+ total_seconds: number;
95
+ days: number;
96
+ hours: number;
97
+ minutes: number;
98
+ seconds: number;
99
+ human_readable: string;
100
+ }
101
+ export interface AdjustedTimestamp {
102
+ original: string;
103
+ adjusted_utc: string;
104
+ adjusted_local: string;
105
+ adjustment_applied: string;
106
+ }
107
+ export interface ResolvedDatetime {
108
+ resolved_utc: string;
109
+ resolved_local: string;
110
+ timezone: string;
111
+ interpretation: string;
112
+ }
113
+ /**
114
+ * Convert a datetime to a different timezone representation.
115
+ *
116
+ * @param datetime - RFC 3339 datetime string (e.g., "2026-03-15T14:00:00Z")
117
+ * @param targetTimezone - IANA timezone name (e.g., "America/New_York")
118
+ * @returns Conversion result with UTC, local, offset, and DST info
119
+ */
120
+ export declare function convertTimezone(datetime: string, targetTimezone: string): ConvertedDatetime;
121
+ /**
122
+ * Compute the duration between two timestamps.
123
+ *
124
+ * @param start - RFC 3339 datetime string
125
+ * @param end - RFC 3339 datetime string
126
+ * @returns Duration decomposed into days, hours, minutes, seconds
127
+ */
128
+ export declare function computeDuration(start: string, end: string): DurationInfo;
129
+ /**
130
+ * Adjust a timestamp by adding or subtracting a duration.
131
+ *
132
+ * @param datetime - RFC 3339 datetime string
133
+ * @param adjustment - Duration string (e.g., "+2h", "-30m", "+1d2h30m")
134
+ * @param timezone - IANA timezone for day-level adjustments across DST
135
+ * @returns Adjusted timestamp in UTC and local time
136
+ */
137
+ export declare function adjustTimestamp(datetime: string, adjustment: string, timezone: string): AdjustedTimestamp;
138
+ /**
139
+ * Resolve a relative time expression to an absolute datetime.
140
+ *
141
+ * @param anchor - RFC 3339 datetime string (the "now" reference point)
142
+ * @param expression - Time expression (e.g., "next Tuesday at 2pm", "tomorrow", "+3h")
143
+ * @param timezone - IANA timezone for interpreting local-time expressions
144
+ * @returns Resolved datetime in UTC and local time with interpretation
145
+ */
146
+ export declare function resolveRelative(anchor: string, expression: string, timezone: string): ResolvedDatetime;
package/dist/index.js CHANGED
@@ -54,6 +54,26 @@ export function findFreeSlots(events, windowStart, windowEnd) {
54
54
  return JSON.parse(json);
55
55
  }
56
56
  // ---------------------------------------------------------------------------
57
+ // One-time hint for multi-calendar users
58
+ // ---------------------------------------------------------------------------
59
+ let _hintShown = false;
60
+ function _maybeShowHint(streamCount) {
61
+ if (_hintShown)
62
+ return;
63
+ if (typeof process !== "undefined" && process.env?.TEMPORAL_CORTEX_QUIET)
64
+ return;
65
+ if (streamCount < 3)
66
+ return;
67
+ _hintShown = true;
68
+ console.info("[temporal-cortex] Merging 3+ calendars? Temporal Cortex Platform adds " +
69
+ "live connectors, booking safety & policy rules. " +
70
+ "https://tally.so/r/aQ66W2");
71
+ }
72
+ /** @internal — exposed for testing only. */
73
+ export function _resetHint() {
74
+ _hintShown = false;
75
+ }
76
+ // ---------------------------------------------------------------------------
57
77
  // Multi-stream availability API
58
78
  // ---------------------------------------------------------------------------
59
79
  /**
@@ -69,6 +89,7 @@ export function findFreeSlots(events, windowStart, windowEnd) {
69
89
  * @returns Unified availability with busy blocks and free slots
70
90
  */
71
91
  export function mergeAvailability(streams, windowStart, windowEnd, opaque = true) {
92
+ _maybeShowHint(streams.length);
72
93
  const json = wasm.mergeAvailability(JSON.stringify(streams), windowStart, windowEnd, opaque);
73
94
  return JSON.parse(json);
74
95
  }
@@ -86,3 +107,52 @@ export function findFirstFreeAcross(streams, windowStart, windowEnd, minDuration
86
107
  const json = wasm.findFirstFreeAcross(JSON.stringify(streams), windowStart, windowEnd, minDurationMinutes);
87
108
  return JSON.parse(json);
88
109
  }
110
+ // ---------------------------------------------------------------------------
111
+ // Temporal computation API
112
+ // ---------------------------------------------------------------------------
113
+ /**
114
+ * Convert a datetime to a different timezone representation.
115
+ *
116
+ * @param datetime - RFC 3339 datetime string (e.g., "2026-03-15T14:00:00Z")
117
+ * @param targetTimezone - IANA timezone name (e.g., "America/New_York")
118
+ * @returns Conversion result with UTC, local, offset, and DST info
119
+ */
120
+ export function convertTimezone(datetime, targetTimezone) {
121
+ const json = wasm.convertTimezone(datetime, targetTimezone);
122
+ return JSON.parse(json);
123
+ }
124
+ /**
125
+ * Compute the duration between two timestamps.
126
+ *
127
+ * @param start - RFC 3339 datetime string
128
+ * @param end - RFC 3339 datetime string
129
+ * @returns Duration decomposed into days, hours, minutes, seconds
130
+ */
131
+ export function computeDuration(start, end) {
132
+ const json = wasm.computeDuration(start, end);
133
+ return JSON.parse(json);
134
+ }
135
+ /**
136
+ * Adjust a timestamp by adding or subtracting a duration.
137
+ *
138
+ * @param datetime - RFC 3339 datetime string
139
+ * @param adjustment - Duration string (e.g., "+2h", "-30m", "+1d2h30m")
140
+ * @param timezone - IANA timezone for day-level adjustments across DST
141
+ * @returns Adjusted timestamp in UTC and local time
142
+ */
143
+ export function adjustTimestamp(datetime, adjustment, timezone) {
144
+ const json = wasm.adjustTimestamp(datetime, adjustment, timezone);
145
+ return JSON.parse(json);
146
+ }
147
+ /**
148
+ * Resolve a relative time expression to an absolute datetime.
149
+ *
150
+ * @param anchor - RFC 3339 datetime string (the "now" reference point)
151
+ * @param expression - Time expression (e.g., "next Tuesday at 2pm", "tomorrow", "+3h")
152
+ * @param timezone - IANA timezone for interpreting local-time expressions
153
+ * @returns Resolved datetime in UTC and local time with interpretation
154
+ */
155
+ export function resolveRelative(anchor, expression, timezone) {
156
+ const json = wasm.resolveRelative(anchor, expression, timezone);
157
+ return JSON.parse(json);
158
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@temporal-cortex/truth-engine",
3
- "version": "0.1.0",
4
- "description": "Truth Engine — deterministic RRULE expansion, conflict detection, free/busy for AI calendar agents",
3
+ "version": "0.2.0",
4
+ "description": "Truth Engine — deterministic temporal resolution, timezone conversion, RRULE expansion, conflict detection, and availability merging for AI calendar agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -14,6 +14,8 @@
14
14
  "calendar",
15
15
  "icalendar",
16
16
  "recurrence",
17
+ "timezone",
18
+ "datetime",
17
19
  "wasm"
18
20
  ],
19
21
  "license": "MIT OR Apache-2.0",
@@ -28,9 +30,9 @@
28
30
  "url": "https://github.com/billylui/temporal-cortex-core/issues"
29
31
  },
30
32
  "devDependencies": {
31
- "@types/node": "^20",
33
+ "@types/node": "^25",
32
34
  "typescript": "^5",
33
- "vitest": "^3"
35
+ "vitest": "^4.0.18"
34
36
  },
35
37
  "scripts": {
36
38
  "build": "tsc",
@@ -1,5 +1,125 @@
1
1
  /* @ts-self-types="./truth_engine_wasm.d.ts" */
2
2
 
3
+ /**
4
+ * Adjust a timestamp by a duration string.
5
+ *
6
+ * `adjustment` format: `+2h`, `-30m`, `+1d2h30m`, `+1w`, etc.
7
+ * `timezone` is an IANA timezone for day-level adjustments across DST.
8
+ *
9
+ * Returns a JSON string with `{original, adjusted_utc, adjusted_local, adjustment_applied}`.
10
+ * @param {string} datetime
11
+ * @param {string} adjustment
12
+ * @param {string} timezone
13
+ * @returns {string}
14
+ */
15
+ function adjustTimestamp(datetime, adjustment, timezone) {
16
+ let deferred5_0;
17
+ let deferred5_1;
18
+ try {
19
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
20
+ const ptr0 = passStringToWasm0(datetime, wasm.__wbindgen_export, wasm.__wbindgen_export2);
21
+ const len0 = WASM_VECTOR_LEN;
22
+ const ptr1 = passStringToWasm0(adjustment, wasm.__wbindgen_export, wasm.__wbindgen_export2);
23
+ const len1 = WASM_VECTOR_LEN;
24
+ const ptr2 = passStringToWasm0(timezone, wasm.__wbindgen_export, wasm.__wbindgen_export2);
25
+ const len2 = WASM_VECTOR_LEN;
26
+ wasm.adjustTimestamp(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
27
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
28
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
29
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
30
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
31
+ var ptr4 = r0;
32
+ var len4 = r1;
33
+ if (r3) {
34
+ ptr4 = 0; len4 = 0;
35
+ throw takeObject(r2);
36
+ }
37
+ deferred5_0 = ptr4;
38
+ deferred5_1 = len4;
39
+ return getStringFromWasm0(ptr4, len4);
40
+ } finally {
41
+ wasm.__wbindgen_add_to_stack_pointer(16);
42
+ wasm.__wbindgen_export3(deferred5_0, deferred5_1, 1);
43
+ }
44
+ }
45
+ exports.adjustTimestamp = adjustTimestamp;
46
+
47
+ /**
48
+ * Compute the duration between two timestamps.
49
+ *
50
+ * Returns a JSON string with `{total_seconds, days, hours, minutes, seconds, human_readable}`.
51
+ * @param {string} start
52
+ * @param {string} end
53
+ * @returns {string}
54
+ */
55
+ function computeDuration(start, end) {
56
+ let deferred4_0;
57
+ let deferred4_1;
58
+ try {
59
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
60
+ const ptr0 = passStringToWasm0(start, wasm.__wbindgen_export, wasm.__wbindgen_export2);
61
+ const len0 = WASM_VECTOR_LEN;
62
+ const ptr1 = passStringToWasm0(end, wasm.__wbindgen_export, wasm.__wbindgen_export2);
63
+ const len1 = WASM_VECTOR_LEN;
64
+ wasm.computeDuration(retptr, ptr0, len0, ptr1, len1);
65
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
66
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
67
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
68
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
69
+ var ptr3 = r0;
70
+ var len3 = r1;
71
+ if (r3) {
72
+ ptr3 = 0; len3 = 0;
73
+ throw takeObject(r2);
74
+ }
75
+ deferred4_0 = ptr3;
76
+ deferred4_1 = len3;
77
+ return getStringFromWasm0(ptr3, len3);
78
+ } finally {
79
+ wasm.__wbindgen_add_to_stack_pointer(16);
80
+ wasm.__wbindgen_export3(deferred4_0, deferred4_1, 1);
81
+ }
82
+ }
83
+ exports.computeDuration = computeDuration;
84
+
85
+ /**
86
+ * Convert a datetime to a different timezone.
87
+ *
88
+ * Returns a JSON string with `{utc, local, timezone, utc_offset, dst_active}`.
89
+ * @param {string} datetime
90
+ * @param {string} target_timezone
91
+ * @returns {string}
92
+ */
93
+ function convertTimezone(datetime, target_timezone) {
94
+ let deferred4_0;
95
+ let deferred4_1;
96
+ try {
97
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
98
+ const ptr0 = passStringToWasm0(datetime, wasm.__wbindgen_export, wasm.__wbindgen_export2);
99
+ const len0 = WASM_VECTOR_LEN;
100
+ const ptr1 = passStringToWasm0(target_timezone, wasm.__wbindgen_export, wasm.__wbindgen_export2);
101
+ const len1 = WASM_VECTOR_LEN;
102
+ wasm.convertTimezone(retptr, ptr0, len0, ptr1, len1);
103
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
104
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
105
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
106
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
107
+ var ptr3 = r0;
108
+ var len3 = r1;
109
+ if (r3) {
110
+ ptr3 = 0; len3 = 0;
111
+ throw takeObject(r2);
112
+ }
113
+ deferred4_0 = ptr3;
114
+ deferred4_1 = len3;
115
+ return getStringFromWasm0(ptr3, len3);
116
+ } finally {
117
+ wasm.__wbindgen_add_to_stack_pointer(16);
118
+ wasm.__wbindgen_export3(deferred4_0, deferred4_1, 1);
119
+ }
120
+ }
121
+ exports.convertTimezone = convertTimezone;
122
+
3
123
  /**
4
124
  * Expand an RRULE string into concrete datetime instances.
5
125
  *
@@ -228,6 +348,51 @@ function mergeAvailability(streams_json, window_start, window_end, opaque) {
228
348
  }
229
349
  exports.mergeAvailability = mergeAvailability;
230
350
 
351
+ /**
352
+ * Resolve a relative time expression to an absolute datetime.
353
+ *
354
+ * `anchor` is an RFC 3339 datetime (the "now" reference point).
355
+ * `expression` is a time expression (e.g., "next Tuesday at 2pm", "tomorrow", "+3h").
356
+ * `timezone` is an IANA timezone for interpreting local-time expressions.
357
+ *
358
+ * Returns a JSON string with `{resolved_utc, resolved_local, timezone, interpretation}`.
359
+ * @param {string} anchor
360
+ * @param {string} expression
361
+ * @param {string} timezone
362
+ * @returns {string}
363
+ */
364
+ function resolveRelative(anchor, expression, timezone) {
365
+ let deferred5_0;
366
+ let deferred5_1;
367
+ try {
368
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
369
+ const ptr0 = passStringToWasm0(anchor, wasm.__wbindgen_export, wasm.__wbindgen_export2);
370
+ const len0 = WASM_VECTOR_LEN;
371
+ const ptr1 = passStringToWasm0(expression, wasm.__wbindgen_export, wasm.__wbindgen_export2);
372
+ const len1 = WASM_VECTOR_LEN;
373
+ const ptr2 = passStringToWasm0(timezone, wasm.__wbindgen_export, wasm.__wbindgen_export2);
374
+ const len2 = WASM_VECTOR_LEN;
375
+ wasm.resolveRelative(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
376
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
377
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
378
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
379
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
380
+ var ptr4 = r0;
381
+ var len4 = r1;
382
+ if (r3) {
383
+ ptr4 = 0; len4 = 0;
384
+ throw takeObject(r2);
385
+ }
386
+ deferred5_0 = ptr4;
387
+ deferred5_1 = len4;
388
+ return getStringFromWasm0(ptr4, len4);
389
+ } finally {
390
+ wasm.__wbindgen_add_to_stack_pointer(16);
391
+ wasm.__wbindgen_export3(deferred5_0, deferred5_1, 1);
392
+ }
393
+ }
394
+ exports.resolveRelative = resolveRelative;
395
+
231
396
  function __wbg_get_imports() {
232
397
  const import0 = {
233
398
  __proto__: null,
@@ -1,6 +1,30 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
3
 
4
+ /**
5
+ * Adjust a timestamp by a duration string.
6
+ *
7
+ * `adjustment` format: `+2h`, `-30m`, `+1d2h30m`, `+1w`, etc.
8
+ * `timezone` is an IANA timezone for day-level adjustments across DST.
9
+ *
10
+ * Returns a JSON string with `{original, adjusted_utc, adjusted_local, adjustment_applied}`.
11
+ */
12
+ export function adjustTimestamp(datetime: string, adjustment: string, timezone: string): string;
13
+
14
+ /**
15
+ * Compute the duration between two timestamps.
16
+ *
17
+ * Returns a JSON string with `{total_seconds, days, hours, minutes, seconds, human_readable}`.
18
+ */
19
+ export function computeDuration(start: string, end: string): string;
20
+
21
+ /**
22
+ * Convert a datetime to a different timezone.
23
+ *
24
+ * Returns a JSON string with `{utc, local, timezone, utc_offset, dst_active}`.
25
+ */
26
+ export function convertTimezone(datetime: string, target_timezone: string): string;
27
+
4
28
  /**
5
29
  * Expand an RRULE string into concrete datetime instances.
6
30
  *
@@ -54,3 +78,14 @@ export function findFreeSlots(events_json: string, window_start: string, window_
54
78
  * Returns a JSON string with `{busy, free, window_start, window_end, privacy}`.
55
79
  */
56
80
  export function mergeAvailability(streams_json: string, window_start: string, window_end: string, opaque: boolean): string;
81
+
82
+ /**
83
+ * Resolve a relative time expression to an absolute datetime.
84
+ *
85
+ * `anchor` is an RFC 3339 datetime (the "now" reference point).
86
+ * `expression` is a time expression (e.g., "next Tuesday at 2pm", "tomorrow", "+3h").
87
+ * `timezone` is an IANA timezone for interpreting local-time expressions.
88
+ *
89
+ * Returns a JSON string with `{resolved_utc, resolved_local, timezone, interpretation}`.
90
+ */
91
+ export function resolveRelative(anchor: string, expression: string, timezone: string): string;
Binary file
@@ -1,11 +1,15 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
3
  export const memory: WebAssembly.Memory;
4
+ export const adjustTimestamp: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
5
+ export const computeDuration: (a: number, b: number, c: number, d: number, e: number) => void;
6
+ export const convertTimezone: (a: number, b: number, c: number, d: number, e: number) => void;
4
7
  export const expandRRule: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => void;
5
8
  export const findConflicts: (a: number, b: number, c: number, d: number, e: number) => void;
6
9
  export const findFirstFreeAcross: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: bigint) => void;
7
10
  export const findFreeSlots: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
8
11
  export const mergeAvailability: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
12
+ export const resolveRelative: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
9
13
  export const __wbindgen_add_to_stack_pointer: (a: number) => number;
10
14
  export const __wbindgen_export: (a: number, b: number) => number;
11
15
  export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;