@ouro.bot/cli 0.1.0-alpha.535 → 0.1.0-alpha.537

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.
@@ -81,6 +81,152 @@ function renderTripSummary(trip) {
81
81
  lines.push(` notes: ${trip.notes}`);
82
82
  return lines.join("\n");
83
83
  }
84
+ function compact(parts) {
85
+ return parts
86
+ .map((part) => part?.trim())
87
+ .filter((part) => !!part)
88
+ .join(" ");
89
+ }
90
+ function routeLabel(origin, destination) {
91
+ if (origin && destination)
92
+ return `${origin} -> ${destination}`;
93
+ return origin ?? destination;
94
+ }
95
+ function tripLegCalendarEntry(trip, leg) {
96
+ switch (leg.kind) {
97
+ case "lodging":
98
+ return {
99
+ tripId: trip.tripId,
100
+ tripName: trip.name,
101
+ legId: leg.legId,
102
+ kind: leg.kind,
103
+ status: leg.status,
104
+ start: leg.checkInDate,
105
+ end: leg.checkOutDate,
106
+ title: leg.vendor ?? "lodging",
107
+ where: leg.city,
108
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
109
+ };
110
+ case "flight": {
111
+ const route = routeLabel(leg.origin, leg.destination);
112
+ return {
113
+ tripId: trip.tripId,
114
+ tripName: trip.name,
115
+ legId: leg.legId,
116
+ kind: leg.kind,
117
+ status: leg.status,
118
+ start: leg.departureAt,
119
+ end: leg.arrivalAt,
120
+ title: compact([leg.vendor ?? "flight", leg.flightNumber, route]),
121
+ where: route,
122
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
123
+ };
124
+ }
125
+ case "train": {
126
+ const route = routeLabel(leg.originStation, leg.destinationStation);
127
+ return {
128
+ tripId: trip.tripId,
129
+ tripName: trip.name,
130
+ legId: leg.legId,
131
+ kind: leg.kind,
132
+ status: leg.status,
133
+ start: leg.departureAt,
134
+ end: leg.arrivalAt,
135
+ title: compact([leg.vendor ?? "train", leg.trainNumber, route]),
136
+ where: route,
137
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
138
+ };
139
+ }
140
+ case "ground-transport": {
141
+ const route = routeLabel(leg.origin, leg.destination);
142
+ return {
143
+ tripId: trip.tripId,
144
+ tripName: trip.name,
145
+ legId: leg.legId,
146
+ kind: leg.kind,
147
+ status: leg.status,
148
+ start: leg.departureAt,
149
+ end: leg.arrivalAt,
150
+ title: compact([leg.operator ?? leg.vendor ?? "ground transport", route]),
151
+ where: route,
152
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
153
+ };
154
+ }
155
+ case "rental-car": {
156
+ const route = routeLabel(leg.pickupLocation, leg.dropoffLocation);
157
+ return {
158
+ tripId: trip.tripId,
159
+ tripName: trip.name,
160
+ legId: leg.legId,
161
+ kind: leg.kind,
162
+ status: leg.status,
163
+ start: leg.pickupAt,
164
+ end: leg.dropoffAt,
165
+ title: compact([leg.rentalVendor ?? leg.vendor ?? "rental car", route]),
166
+ where: route,
167
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
168
+ };
169
+ }
170
+ case "ferry": {
171
+ const route = routeLabel(leg.originPort, leg.destinationPort);
172
+ return {
173
+ tripId: trip.tripId,
174
+ tripName: trip.name,
175
+ legId: leg.legId,
176
+ kind: leg.kind,
177
+ status: leg.status,
178
+ start: leg.departureAt,
179
+ end: leg.arrivalAt,
180
+ title: compact([leg.operator ?? leg.vendor ?? "ferry", route]),
181
+ where: route,
182
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
183
+ };
184
+ }
185
+ case "event": {
186
+ const where = [leg.venue, leg.city].filter(Boolean).join(", ") || undefined;
187
+ return {
188
+ tripId: trip.tripId,
189
+ tripName: trip.name,
190
+ legId: leg.legId,
191
+ kind: leg.kind,
192
+ status: leg.status,
193
+ start: leg.startsAt,
194
+ end: leg.endsAt,
195
+ title: leg.vendor ?? "event",
196
+ where,
197
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
198
+ };
199
+ }
200
+ }
201
+ }
202
+ function calendarEntryRange(entry) {
203
+ if (entry.start && entry.end && entry.start !== entry.end)
204
+ return `${entry.start} -> ${entry.end}`;
205
+ return entry.start ?? entry.end ?? "(undated)";
206
+ }
207
+ function renderTripCalendar(trips, includeUndated) {
208
+ const entries = trips
209
+ .flatMap((trip) => trip.legs.map((leg) => tripLegCalendarEntry(trip, leg)))
210
+ .filter((entry) => includeUndated || entry.start || entry.end)
211
+ .sort((left, right) => {
212
+ const leftKey = left.start ?? left.end ?? "9999-99-99T99:99:99.999Z";
213
+ const rightKey = right.start ?? right.end ?? "9999-99-99T99:99:99.999Z";
214
+ return leftKey.localeCompare(rightKey) || left.tripName.localeCompare(right.tripName) || left.legId.localeCompare(right.legId);
215
+ });
216
+ if (entries.length === 0)
217
+ return includeUndated ? "no calendar entries on the trip ledger yet." : "no dated calendar entries on the trip ledger yet.";
218
+ const noun = entries.length === 1 ? "entry" : "entries";
219
+ const lines = [`${entries.length} trip calendar ${noun}:`];
220
+ for (const entry of entries) {
221
+ lines.push(`- ${calendarEntryRange(entry)} | ${entry.kind} | ${entry.status} | ${entry.title}`);
222
+ lines.push(` trip: ${entry.tripName} (${entry.tripId}); leg: ${entry.legId}`);
223
+ if (entry.where)
224
+ lines.push(` where: ${entry.where}`);
225
+ if (entry.evidenceIds.length > 0)
226
+ lines.push(` evidence: ${entry.evidenceIds.join(", ")}`);
227
+ }
228
+ return lines.join("\n");
229
+ }
84
230
  exports.tripToolDefinitions = [
85
231
  {
86
232
  tool: {
@@ -390,6 +536,42 @@ exports.tripToolDefinitions = [
390
536
  },
391
537
  summaryKeys: ["tripId", "legId", "reason"],
392
538
  },
539
+ {
540
+ tool: {
541
+ type: "function",
542
+ function: {
543
+ name: "trip_calendar",
544
+ description: "Render a chronological calendar/agenda projection from the trip ledger. Use this before answering current itinerary, travel gap, or what-changed questions; friend notes and old handoffs may be stale. Also use this after extracting mail-backed trip facts so the agent can track dates across lodging, travel, events, and local transport.",
545
+ parameters: {
546
+ type: "object",
547
+ properties: {
548
+ tripId: { type: "string", description: "Optional canonical trip id. Omit to render all trips on the ledger." },
549
+ includeUndated: { type: "string", enum: ["true", "false"], description: "Set true to include legs that have no start/end dates yet. Defaults to false." },
550
+ },
551
+ },
552
+ },
553
+ },
554
+ handler: async (args, ctx) => {
555
+ if (!trustAllowsTripAccess(ctx))
556
+ return "trip ledger is private; this tool is only available in trusted contexts.";
557
+ const includeUndated = args.includeUndated === "true";
558
+ const tripId = typeof args.tripId === "string" ? args.tripId.trim() : "";
559
+ try {
560
+ const trips = tripId
561
+ ? [(0, store_1.readTripRecord)((0, identity_1.getAgentName)(), tripId)]
562
+ : (0, store_1.listTripIds)((0, identity_1.getAgentName)()).map((id) => (0, store_1.readTripRecord)((0, identity_1.getAgentName)(), id));
563
+ if (trips.length === 0)
564
+ return "no trips on the ledger yet.";
565
+ return renderTripCalendar(trips, includeUndated);
566
+ }
567
+ catch (error) {
568
+ if (error instanceof store_1.TripNotFoundError)
569
+ return error.message;
570
+ throw error;
571
+ }
572
+ },
573
+ summaryKeys: ["tripId"],
574
+ },
393
575
  {
394
576
  tool: {
395
577
  type: "function",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.535",
3
+ "version": "0.1.0-alpha.537",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",