atris 3.15.54 → 3.15.55

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.
@@ -5,7 +5,9 @@
5
5
  * atris gmail inbox - List recent emails
6
6
  * atris gmail read <id> - Read specific email
7
7
  * atris calendar today - Show today's events
8
+ * atris calendar yesterday - Show yesterday's events
8
9
  * atris calendar week - Show this week's events
10
+ * atris calendar date YYYY-MM-DD - Show events on a date
9
11
  * atris twitter post - Post a tweet (interactive)
10
12
  * atris slack channels - List Slack channels
11
13
  */
@@ -137,12 +139,63 @@ async function gmailCommand(subcommand, ...args) {
137
139
  // CALENDAR
138
140
  // ============================================================================
139
141
 
140
- async function calendarToday() {
142
+ function localDayBounds(offsetDays = 0) {
143
+ const start = new Date();
144
+ start.setHours(0, 0, 0, 0);
145
+ start.setDate(start.getDate() + offsetDays);
146
+ const end = new Date(start);
147
+ end.setDate(end.getDate() + 1);
148
+ return { start, end };
149
+ }
150
+
151
+ function localDateBounds(dateText) {
152
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(String(dateText || ''))) {
153
+ console.error('Usage: atris calendar date YYYY-MM-DD');
154
+ process.exit(1);
155
+ }
156
+ const start = new Date(`${dateText}T00:00:00`);
157
+ if (Number.isNaN(start.getTime())) {
158
+ console.error('Invalid date. Use YYYY-MM-DD.');
159
+ process.exit(1);
160
+ }
161
+ const end = new Date(start);
162
+ end.setDate(end.getDate() + 1);
163
+ return { start, end };
164
+ }
165
+
166
+ function formatCalendarEvents(label, events) {
167
+ if (events.length === 0) {
168
+ console.log(`No events ${label}. 🎉`);
169
+ return;
170
+ }
171
+
172
+ console.log('─'.repeat(50));
173
+
174
+ for (const event of events) {
175
+ const start = event.start?.dateTime || event.start?.date || '';
176
+ const time = start ? new Date(start).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }) : 'All day';
177
+ const title = event.summary || '(no title)';
178
+
179
+ console.log(`${time} ${title}`);
180
+ if (event.location) {
181
+ console.log(` 📍 ${event.location}`);
182
+ }
183
+ }
184
+
185
+ console.log('─'.repeat(50));
186
+ }
187
+
188
+ async function calendarRange(label, { timeMin, timeMax, days } = {}) {
141
189
  const { token, email } = await getAuth();
142
190
 
143
- console.log('📅 Today\'s events:\n');
191
+ console.log(`📅 ${label}:\n`);
144
192
 
145
- const result = await apiRequestJson('/integrations/google-calendar/events/today', {
193
+ const params = new URLSearchParams();
194
+ if (timeMin) params.set('time_min', timeMin);
195
+ if (timeMax) params.set('time_max', timeMax);
196
+ if (days) params.set('days', String(days));
197
+ const suffix = params.toString() ? `?${params.toString()}` : '';
198
+ const result = await apiRequestJson(`/integrations/google-calendar/events${suffix}`, {
146
199
  method: 'GET',
147
200
  token,
148
201
  });
@@ -159,26 +212,25 @@ async function calendarToday() {
159
212
  }
160
213
 
161
214
  const events = result.data?.events || result.data || [];
215
+ formatCalendarEvents(label.toLowerCase(), events);
216
+ }
162
217
 
163
- if (events.length === 0) {
164
- console.log('No events today. 🎉');
165
- return;
166
- }
167
-
168
- console.log('─'.repeat(50));
218
+ async function calendarToday() {
219
+ await calendarRange("Today's events", { days: 1 });
220
+ }
169
221
 
170
- for (const event of events) {
171
- const start = event.start?.dateTime || event.start?.date || '';
172
- const time = start ? new Date(start).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }) : 'All day';
173
- const title = event.summary || '(no title)';
222
+ async function calendarYesterday() {
223
+ const { start, end } = localDayBounds(-1);
224
+ await calendarRange("Yesterday's events", { timeMin: start.toISOString(), timeMax: end.toISOString() });
225
+ }
174
226
 
175
- console.log(`${time} ${title}`);
176
- if (event.location) {
177
- console.log(` 📍 ${event.location}`);
178
- }
179
- }
227
+ async function calendarWeek() {
228
+ await calendarRange("This week's events", { days: 7 });
229
+ }
180
230
 
181
- console.log('─'.repeat(50));
231
+ async function calendarDate(dateText) {
232
+ const { start, end } = localDateBounds(dateText);
233
+ await calendarRange(`Events on ${dateText}`, { timeMin: start.toISOString(), timeMax: end.toISOString() });
182
234
  }
183
235
 
184
236
  async function calendarCommand(subcommand, ...args) {
@@ -186,13 +238,22 @@ async function calendarCommand(subcommand, ...args) {
186
238
  case 'today':
187
239
  await calendarToday();
188
240
  break;
241
+ case 'yesterday':
242
+ case 'yday':
243
+ await calendarYesterday();
244
+ break;
189
245
  case 'week':
190
- console.log('Week view coming soon...');
246
+ await calendarWeek();
247
+ break;
248
+ case 'date':
249
+ await calendarDate(args[0]);
191
250
  break;
192
251
  default:
193
252
  console.log('Calendar commands:');
194
- console.log(' atris calendar today - Show today\'s events');
195
- console.log(' atris calendar week - Show this week\'s events');
253
+ console.log(' atris calendar today - Show today\'s events');
254
+ console.log(' atris calendar yesterday - Show yesterday\'s events');
255
+ console.log(' atris calendar week - Show this week\'s events');
256
+ console.log(' atris calendar date YYYY-MM-DD - Show events on a date');
196
257
  }
197
258
  }
198
259
 
package/commands/xp.js CHANGED
@@ -1727,10 +1727,34 @@ function loadLocalPayload(args) {
1727
1727
  return normalizeLocalScore(JSON.parse(result.stdout), workspace);
1728
1728
  }
1729
1729
 
1730
- function publicAgentXp(value) {
1730
+ function earnedAgentXp(value) {
1731
+ return Math.max(0, asNumber(value));
1732
+ }
1733
+
1734
+ function currentFormScore(value) {
1731
1735
  return Math.max(0, Math.min(99, asNumber(value)));
1732
1736
  }
1733
1737
 
1738
+ function agentXpLevelProgress(totalXp) {
1739
+ const levelXp = Math.max(0, asNumber(totalXp));
1740
+ const level = levelFromXp(levelXp);
1741
+ const currentLevelFloor = (level - 1) * LEVEL_XP;
1742
+ const nextLevelXp = level * LEVEL_XP;
1743
+ const xpIntoLevel = levelXp - currentLevelFloor;
1744
+ return {
1745
+ schema: 'atris.agentxp_level_progress.v1',
1746
+ level,
1747
+ stage: `Level ${level}`,
1748
+ level_xp: levelXp,
1749
+ current_level_floor: currentLevelFloor,
1750
+ next_level_xp: nextLevelXp,
1751
+ xp_into_level: xpIntoLevel,
1752
+ xp_to_next: Math.max(0, nextLevelXp - levelXp),
1753
+ progress_pct: Math.max(0, Math.min(99, Math.round((xpIntoLevel / LEVEL_XP) * 100))),
1754
+ uncapped: true,
1755
+ };
1756
+ }
1757
+
1734
1758
  function verifiedProjection(projection) {
1735
1759
  return projection?.integrity_status === 'verified'
1736
1760
  && projection?.integrity?.status === 'verified';
@@ -1797,6 +1821,19 @@ function syncAttribution(workspaces) {
1797
1821
  };
1798
1822
  }
1799
1823
 
1824
+ function syncScopeFields(attribution = {}) {
1825
+ const attributionScope = slugify(attribution.attribution_scope);
1826
+ const orgId = String(attribution.business_id || attribution.business_slug || '').trim() || null;
1827
+ const businessBound = Boolean(orgId) || attributionScope === 'business-bound' || attributionScope === 'multi-business';
1828
+ return {
1829
+ scope: businessBound ? 'org' : 'global',
1830
+ org_id: orgId,
1831
+ computer_id: String(attribution.workspace_id || attribution.computer || 'local').trim() || 'local',
1832
+ visibility: businessBound ? 'internal' : 'public',
1833
+ public_agentxp: !businessBound,
1834
+ };
1835
+ }
1836
+
1800
1837
  function credentialHandle(credentials) {
1801
1838
  return slugify(
1802
1839
  credentials?.username
@@ -1856,19 +1893,23 @@ function buildAgentXpSyncPacket(args = []) {
1856
1893
  const player = syncPlayer(args, projection);
1857
1894
  const workspaces = projectionWorkspaceSummaries(projection);
1858
1895
  const attribution = syncAttribution(workspaces);
1896
+ const scopeFields = syncScopeFields(attribution);
1859
1897
  const totalXp = asNumber(projection.total_agent_xp ?? projection.agent_xp ?? projection.total_xp ?? projection.career_xp);
1860
1898
  const receiptsCount = asNumber(projection.receipts_count);
1861
1899
  const eligible = verifiedProjection(projection) && receiptsCount > 0 && totalXp > 0;
1862
- const publicXp = publicAgentXp(totalXp);
1900
+ const publicXp = earnedAgentXp(totalXp);
1901
+ const currentForm = currentFormScore(totalXp);
1902
+ const levelProgress = agentXpLevelProgress(publicXp);
1863
1903
  const workspaceRootHash = sha256(workspaces.map(item => item.workspace_root_hash || item.name).sort().join(':'));
1864
1904
  const entry = {
1865
1905
  user_id: player,
1866
1906
  username: player,
1867
1907
  agent_xp: publicXp,
1868
1908
  career_xp: publicXp,
1869
- current_form: publicXp,
1870
- ovr: publicXp,
1871
- level: Math.max(1, asNumber(projection.level, 1)),
1909
+ current_form: currentForm,
1910
+ ovr: currentForm,
1911
+ level: levelProgress.level,
1912
+ level_progress: levelProgress,
1872
1913
  verified_receipts: receiptsCount,
1873
1914
  reviewed_tasks: receiptsCount,
1874
1915
  recent_verified_receipts: receiptsCount,
@@ -1883,12 +1924,17 @@ function buildAgentXpSyncPacket(args = []) {
1883
1924
  schema: 'atris.agentxp_sync_packet.v1',
1884
1925
  generated_at: new Date().toISOString(),
1885
1926
  workspace_root_hash: workspaceRootHash,
1927
+ scope: scopeFields.scope,
1928
+ org_id: scopeFields.org_id,
1886
1929
  attribution_scope: attribution.attribution_scope,
1887
1930
  business_id: attribution.business_id || null,
1888
1931
  workspace_id: attribution.workspace_id || null,
1889
1932
  business_slug: attribution.business_slug || null,
1890
1933
  workspace_template: attribution.workspace_template || null,
1934
+ computer_id: scopeFields.computer_id,
1891
1935
  computer: attribution.computer || projection.workspace_name || workspaces[0]?.name || 'local',
1936
+ visibility: scopeFields.visibility,
1937
+ public_agentxp: scopeFields.public_agentxp,
1892
1938
  operator: player,
1893
1939
  privacy: {
1894
1940
  raw_proofs_included: false,
@@ -1903,12 +1949,17 @@ function buildAgentXpSyncPacket(args = []) {
1903
1949
  local_evidence: {
1904
1950
  schema: 'atris.agentxp_local_evidence.v1',
1905
1951
  workspace_root_hash: workspaceRootHash,
1952
+ scope: scopeFields.scope,
1953
+ org_id: scopeFields.org_id,
1906
1954
  attribution_scope: attribution.attribution_scope,
1907
1955
  business_id: attribution.business_id || null,
1908
1956
  workspace_id: attribution.workspace_id || null,
1909
1957
  business_slug: attribution.business_slug || null,
1910
1958
  workspace_template: attribution.workspace_template || null,
1959
+ computer_id: scopeFields.computer_id,
1911
1960
  computer: attribution.computer || null,
1961
+ visibility: scopeFields.visibility,
1962
+ public_agentxp: scopeFields.public_agentxp,
1912
1963
  workspaces,
1913
1964
  verified_workspace_count: asNumber(projection.verified_workspace_count, verifiedProjection(projection) ? 1 : 0),
1914
1965
  receipts_count: receiptsCount,
@@ -1933,12 +1984,17 @@ function buildAgentXpSyncPacket(args = []) {
1933
1984
  gm_projection: {
1934
1985
  schema: 'atris.gm_xp_projection.v1',
1935
1986
  workspace_root_hash: workspaceRootHash,
1987
+ scope: scopeFields.scope,
1988
+ org_id: scopeFields.org_id,
1936
1989
  attribution_scope: attribution.attribution_scope,
1937
1990
  business_id: attribution.business_id || null,
1938
1991
  workspace_id: attribution.workspace_id || null,
1939
1992
  business_slug: attribution.business_slug || null,
1940
1993
  workspace_template: attribution.workspace_template || null,
1994
+ computer_id: scopeFields.computer_id,
1941
1995
  computer: attribution.computer || null,
1996
+ visibility: scopeFields.visibility,
1997
+ public_agentxp: scopeFields.public_agentxp,
1942
1998
  operator: player,
1943
1999
  player_score: {
1944
2000
  agent_xp: totalXp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atris",
3
- "version": "3.15.54",
3
+ "version": "3.15.55",
4
4
  "main": "bin/atris.js",
5
5
  "bin": {
6
6
  "atris": "bin/atris.js",