atris 3.15.54 → 3.15.56

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,9 +5,13 @@
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
13
+ * atris slack messages <channel> [--limit 20] - Read recent messages
14
+ * atris slack search <query> [--limit 20] - Search Slack messages
11
15
  */
12
16
 
13
17
  const { loadCredentials, ensureValidCredentials } = require('../utils/auth');
@@ -137,12 +141,85 @@ async function gmailCommand(subcommand, ...args) {
137
141
  // CALENDAR
138
142
  // ============================================================================
139
143
 
140
- async function calendarToday() {
144
+ function localDayBounds(offsetDays = 0) {
145
+ const start = new Date();
146
+ start.setHours(0, 0, 0, 0);
147
+ start.setDate(start.getDate() + offsetDays);
148
+ const end = new Date(start);
149
+ end.setDate(end.getDate() + 1);
150
+ return { start, end };
151
+ }
152
+
153
+ function localDateBounds(dateText) {
154
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(String(dateText || ''))) {
155
+ console.error('Usage: atris calendar date YYYY-MM-DD');
156
+ process.exit(1);
157
+ }
158
+ const start = new Date(`${dateText}T00:00:00`);
159
+ if (Number.isNaN(start.getTime())) {
160
+ console.error('Invalid date. Use YYYY-MM-DD.');
161
+ process.exit(1);
162
+ }
163
+ const end = new Date(start);
164
+ end.setDate(end.getDate() + 1);
165
+ return { start, end };
166
+ }
167
+
168
+ function calendarEventTimeValue(value) {
169
+ if (!value) return '';
170
+ if (typeof value === 'string') return value;
171
+ return value.dateTime || value.date || '';
172
+ }
173
+
174
+ function isDateOnly(value) {
175
+ return /^\d{4}-\d{2}-\d{2}$/.test(String(value || ''));
176
+ }
177
+
178
+ function formatCalendarTimeRange(event) {
179
+ const start = calendarEventTimeValue(event.start || event.start_time || event.startTime);
180
+ const end = calendarEventTimeValue(event.end || event.end_time || event.endTime);
181
+ if (!start || isDateOnly(start)) return 'All day';
182
+ const startDate = new Date(start);
183
+ if (Number.isNaN(startDate.getTime())) return 'Time unavailable';
184
+ const startText = startDate.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
185
+ if (!end || isDateOnly(end)) return startText;
186
+ const endDate = new Date(end);
187
+ if (Number.isNaN(endDate.getTime())) return startText;
188
+ return `${startText}-${endDate.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })}`;
189
+ }
190
+
191
+ function formatCalendarEvents(label, events) {
192
+ if (events.length === 0) {
193
+ console.log(`No events ${label}. 🎉`);
194
+ return;
195
+ }
196
+
197
+ console.log('─'.repeat(50));
198
+
199
+ for (const event of events) {
200
+ const time = formatCalendarTimeRange(event);
201
+ const title = event.summary || '(no title)';
202
+
203
+ console.log(`${time} ${title}`);
204
+ if (event.location) {
205
+ console.log(` 📍 ${event.location}`);
206
+ }
207
+ }
208
+
209
+ console.log('─'.repeat(50));
210
+ }
211
+
212
+ async function calendarRange(label, { timeMin, timeMax, days } = {}) {
141
213
  const { token, email } = await getAuth();
142
214
 
143
- console.log('📅 Today\'s events:\n');
215
+ console.log(`📅 ${label}:\n`);
144
216
 
145
- const result = await apiRequestJson('/integrations/google-calendar/events/today', {
217
+ const params = new URLSearchParams();
218
+ if (timeMin) params.set('time_min', timeMin);
219
+ if (timeMax) params.set('time_max', timeMax);
220
+ if (days) params.set('days', String(days));
221
+ const suffix = params.toString() ? `?${params.toString()}` : '';
222
+ const result = await apiRequestJson(`/integrations/google-calendar/events${suffix}`, {
146
223
  method: 'GET',
147
224
  token,
148
225
  });
@@ -159,26 +236,25 @@ async function calendarToday() {
159
236
  }
160
237
 
161
238
  const events = result.data?.events || result.data || [];
239
+ formatCalendarEvents(label.toLowerCase(), events);
240
+ }
162
241
 
163
- if (events.length === 0) {
164
- console.log('No events today. 🎉');
165
- return;
166
- }
167
-
168
- console.log('─'.repeat(50));
242
+ async function calendarToday() {
243
+ await calendarRange("Today's events", { days: 1 });
244
+ }
169
245
 
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)';
246
+ async function calendarYesterday() {
247
+ const { start, end } = localDayBounds(-1);
248
+ await calendarRange("Yesterday's events", { timeMin: start.toISOString(), timeMax: end.toISOString() });
249
+ }
174
250
 
175
- console.log(`${time} ${title}`);
176
- if (event.location) {
177
- console.log(` 📍 ${event.location}`);
178
- }
179
- }
251
+ async function calendarWeek() {
252
+ await calendarRange("This week's events", { days: 7 });
253
+ }
180
254
 
181
- console.log('─'.repeat(50));
255
+ async function calendarDate(dateText) {
256
+ const { start, end } = localDateBounds(dateText);
257
+ await calendarRange(`Events on ${dateText}`, { timeMin: start.toISOString(), timeMax: end.toISOString() });
182
258
  }
183
259
 
184
260
  async function calendarCommand(subcommand, ...args) {
@@ -186,13 +262,22 @@ async function calendarCommand(subcommand, ...args) {
186
262
  case 'today':
187
263
  await calendarToday();
188
264
  break;
265
+ case 'yesterday':
266
+ case 'yday':
267
+ await calendarYesterday();
268
+ break;
189
269
  case 'week':
190
- console.log('Week view coming soon...');
270
+ await calendarWeek();
271
+ break;
272
+ case 'date':
273
+ await calendarDate(args[0]);
191
274
  break;
192
275
  default:
193
276
  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');
277
+ console.log(' atris calendar today - Show today\'s events');
278
+ console.log(' atris calendar yesterday - Show yesterday\'s events');
279
+ console.log(' atris calendar week - Show this week\'s events');
280
+ console.log(' atris calendar date YYYY-MM-DD - Show events on a date');
196
281
  }
197
282
  }
198
283
 
@@ -270,7 +355,7 @@ async function slackChannels() {
270
355
 
271
356
  console.log('💬 Fetching Slack channels...\n');
272
357
 
273
- const result = await apiRequestJson('/integrations/slack/channels', {
358
+ const result = await apiRequestJson('/integrations/slack/me/channels', {
274
359
  method: 'GET',
275
360
  token,
276
361
  });
@@ -298,8 +383,137 @@ async function slackChannels() {
298
383
  for (const ch of channels) {
299
384
  const name = ch.name || ch.id;
300
385
  const priv = ch.is_private ? '🔒' : '#';
301
- console.log(` ${priv} ${name}`);
386
+ console.log(` ${priv} ${name} ${ch.id || ''}`.trimEnd());
387
+ }
388
+ }
389
+
390
+ async function slackDms() {
391
+ const token = await getAuthToken();
392
+
393
+ console.log('💬 Fetching Slack DMs...\n');
394
+
395
+ const result = await apiRequestJson('/integrations/slack/me/dms', {
396
+ method: 'GET',
397
+ token,
398
+ });
399
+
400
+ if (!result.ok) {
401
+ console.error(`Error: ${result.error || 'Failed to fetch DMs'}`);
402
+ process.exit(1);
403
+ }
404
+
405
+ const dms = result.data?.dms || result.data?.channels || result.data || [];
406
+ if (!dms.length) {
407
+ console.log('No DMs found.');
408
+ return;
409
+ }
410
+ for (const dm of dms) {
411
+ const name = dm.name || dm.user_name || dm.user || dm.id;
412
+ console.log(` ${name} ${dm.id || ''}`.trimEnd());
413
+ }
414
+ }
415
+
416
+ function parseLimit(args, fallback = 20) {
417
+ const idx = args.findIndex((arg) => arg === '--limit' || arg === '-n');
418
+ const raw = idx >= 0 ? args[idx + 1] : '';
419
+ const parsed = Number.parseInt(raw, 10);
420
+ return Number.isFinite(parsed) && parsed > 0 ? Math.min(parsed, 100) : fallback;
421
+ }
422
+
423
+ function argsWithoutLimit(args = []) {
424
+ const out = [];
425
+ for (let i = 0; i < args.length; i += 1) {
426
+ if (args[i] === '--limit' || args[i] === '-n') {
427
+ i += 1;
428
+ continue;
429
+ }
430
+ out.push(args[i]);
431
+ }
432
+ return out;
433
+ }
434
+
435
+ async function slackPersonalChannels(token) {
436
+ const result = await apiRequestJson('/integrations/slack/me/channels', {
437
+ method: 'GET',
438
+ token,
439
+ });
440
+ if (!result.ok) return [];
441
+ return result.data?.channels || result.data || [];
442
+ }
443
+
444
+ async function resolveSlackChannel(token, channel) {
445
+ const text = String(channel || '').trim();
446
+ if (!text) return '';
447
+ if (/^[A-Z][A-Z0-9]{5,}$/.test(text)) return text;
448
+ const wanted = text.replace(/^#/, '').toLowerCase();
449
+ const channels = await slackPersonalChannels(token);
450
+ const match = channels.find((ch) => String(ch.name || '').toLowerCase() === wanted || String(ch.id || '').toLowerCase() === wanted);
451
+ return match?.id || text;
452
+ }
453
+
454
+ function formatSlackMessages(messages) {
455
+ if (!messages.length) {
456
+ console.log('No Slack messages found.');
457
+ return;
458
+ }
459
+ console.log('─'.repeat(60));
460
+ for (const message of messages) {
461
+ const author = message.user_name || message.username || message.user || message.sender || 'unknown';
462
+ const ts = message.datetime || message.time || message.ts || message.created_at || '';
463
+ const text = String(message.text || message.content || message.message || '').replace(/\s+/g, ' ').trim();
464
+ console.log(`${ts} ${author}: ${text || '(no text)'}`);
302
465
  }
466
+ console.log('─'.repeat(60));
467
+ }
468
+
469
+ async function slackMessages(channel, args = []) {
470
+ if (!channel) {
471
+ console.error('Usage: atris slack messages <channel-or-id> [--limit 20]');
472
+ process.exit(1);
473
+ }
474
+ const token = await getAuthToken();
475
+ const limit = parseLimit(args);
476
+ const channelId = await resolveSlackChannel(token, channel);
477
+
478
+ console.log(`💬 Reading Slack messages from ${channel}...\n`);
479
+
480
+ const result = await apiRequestJson(`/integrations/slack/me/messages/${encodeURIComponent(channelId)}?limit=${limit}`, {
481
+ method: 'GET',
482
+ token,
483
+ });
484
+
485
+ if (!result.ok) {
486
+ console.error(`Error: ${result.error || 'Failed to fetch Slack messages'}`);
487
+ process.exit(1);
488
+ }
489
+
490
+ const messages = result.data?.messages || result.data || [];
491
+ formatSlackMessages(messages);
492
+ }
493
+
494
+ async function slackSearch(query, args = []) {
495
+ if (!query) {
496
+ console.error('Usage: atris slack search <query> [--limit 20]');
497
+ process.exit(1);
498
+ }
499
+ const token = await getAuthToken();
500
+ const limit = parseLimit(args);
501
+ const q = encodeURIComponent(query);
502
+
503
+ console.log(`💬 Searching Slack for "${query}"...\n`);
504
+
505
+ const result = await apiRequestJson(`/integrations/slack/me/search?q=${q}&count=${limit}`, {
506
+ method: 'GET',
507
+ token,
508
+ });
509
+
510
+ if (!result.ok) {
511
+ console.error(`Error: ${result.error || 'Failed to search Slack messages'}`);
512
+ process.exit(1);
513
+ }
514
+
515
+ const messages = result.data?.messages || result.data?.results || result.data || [];
516
+ formatSlackMessages(messages);
303
517
  }
304
518
 
305
519
  async function slackCommand(subcommand, ...args) {
@@ -308,9 +522,22 @@ async function slackCommand(subcommand, ...args) {
308
522
  case 'list':
309
523
  await slackChannels();
310
524
  break;
525
+ case 'dms':
526
+ await slackDms();
527
+ break;
528
+ case 'messages':
529
+ case 'read':
530
+ await slackMessages(args[0], args.slice(1));
531
+ break;
532
+ case 'search':
533
+ await slackSearch(argsWithoutLimit(args).join(' '), args);
534
+ break;
311
535
  default:
312
536
  console.log('Slack commands:');
313
- console.log(' atris slack channels - List Slack channels');
537
+ console.log(' atris slack channels - List Slack channels');
538
+ console.log(' atris slack dms - List Slack DMs');
539
+ console.log(' atris slack messages <channel> - Read recent messages');
540
+ console.log(' atris slack search <query> - Search Slack messages');
314
541
  }
315
542
  }
316
543
 
package/commands/xp.js CHANGED
@@ -1123,6 +1123,36 @@ function workspaceName(workspace) {
1123
1123
  return path.basename(workspace) || workspace;
1124
1124
  }
1125
1125
 
1126
+ function booleanSetting(value) {
1127
+ if (value === true || value === false) return value;
1128
+ const text = String(value || '').trim().toLowerCase();
1129
+ if (['1', 'true', 'yes', 'public', 'global'].includes(text)) return true;
1130
+ if (['0', 'false', 'no', 'private', 'internal', 'org'].includes(text)) return false;
1131
+ return null;
1132
+ }
1133
+
1134
+ function agentXpPublicBinding(binding = {}) {
1135
+ const nested = binding.agentxp && typeof binding.agentxp === 'object' ? binding.agentxp : {};
1136
+ const explicit = booleanSetting(
1137
+ binding.agentxp_public
1138
+ ?? binding.public_agentxp
1139
+ ?? binding.agentxp_public_leaderboard
1140
+ ?? nested.public
1141
+ ?? nested.public_agentxp
1142
+ );
1143
+ if (explicit !== null) return explicit;
1144
+
1145
+ const visibility = slugify(binding.agentxp_visibility || nested.visibility);
1146
+ if (visibility === 'public') return true;
1147
+ if (['internal', 'private'].includes(visibility)) return false;
1148
+
1149
+ const scope = slugify(binding.agentxp_scope || nested.scope);
1150
+ if (scope === 'global') return true;
1151
+ if (['org', 'internal', 'private'].includes(scope)) return false;
1152
+
1153
+ return null;
1154
+ }
1155
+
1126
1156
  function publicWorkspaceBinding(workspace) {
1127
1157
  const binding = readJsonFile(path.join(workspace, BUSINESS_BINDING_FILE), null);
1128
1158
  if (!binding || typeof binding !== 'object') return null;
@@ -1130,6 +1160,7 @@ function publicWorkspaceBinding(workspace) {
1130
1160
  const workspaceId = String(binding.workspace_id || '').trim();
1131
1161
  const businessSlug = slugify(binding.slug || binding.business_slug || binding.name);
1132
1162
  const workspaceTemplate = slugify(binding.workspace_template || binding.organization_type || binding.computer_type);
1163
+ const agentxpPublic = agentXpPublicBinding(binding);
1133
1164
  if (!businessId && !workspaceId && !businessSlug) return null;
1134
1165
  return {
1135
1166
  business_id: businessId || null,
@@ -1138,6 +1169,7 @@ function publicWorkspaceBinding(workspace) {
1138
1169
  workspace_template: workspaceTemplate || null,
1139
1170
  computer: businessSlug || workspaceName(workspace),
1140
1171
  computer_slug: businessSlug || slugify(workspaceName(workspace)),
1172
+ ...(agentxpPublic === null ? {} : { agentxp_public: agentxpPublic }),
1141
1173
  };
1142
1174
  }
1143
1175
 
@@ -1727,10 +1759,34 @@ function loadLocalPayload(args) {
1727
1759
  return normalizeLocalScore(JSON.parse(result.stdout), workspace);
1728
1760
  }
1729
1761
 
1730
- function publicAgentXp(value) {
1762
+ function earnedAgentXp(value) {
1763
+ return Math.max(0, asNumber(value));
1764
+ }
1765
+
1766
+ function currentFormScore(value) {
1731
1767
  return Math.max(0, Math.min(99, asNumber(value)));
1732
1768
  }
1733
1769
 
1770
+ function agentXpLevelProgress(totalXp) {
1771
+ const levelXp = Math.max(0, asNumber(totalXp));
1772
+ const level = levelFromXp(levelXp);
1773
+ const currentLevelFloor = (level - 1) * LEVEL_XP;
1774
+ const nextLevelXp = level * LEVEL_XP;
1775
+ const xpIntoLevel = levelXp - currentLevelFloor;
1776
+ return {
1777
+ schema: 'atris.agentxp_level_progress.v1',
1778
+ level,
1779
+ stage: `Level ${level}`,
1780
+ level_xp: levelXp,
1781
+ current_level_floor: currentLevelFloor,
1782
+ next_level_xp: nextLevelXp,
1783
+ xp_into_level: xpIntoLevel,
1784
+ xp_to_next: Math.max(0, nextLevelXp - levelXp),
1785
+ progress_pct: Math.max(0, Math.min(99, Math.round((xpIntoLevel / LEVEL_XP) * 100))),
1786
+ uncapped: true,
1787
+ };
1788
+ }
1789
+
1734
1790
  function verifiedProjection(projection) {
1735
1791
  return projection?.integrity_status === 'verified'
1736
1792
  && projection?.integrity?.status === 'verified';
@@ -1768,19 +1824,22 @@ function uniqueTruthy(values) {
1768
1824
  return Array.from(new Set(values.map(value => String(value || '').trim()).filter(Boolean))).sort();
1769
1825
  }
1770
1826
 
1771
- function syncAttribution(workspaces) {
1827
+ function syncAttribution(workspaces, options = {}) {
1772
1828
  const included = workspaces.filter(workspace => workspace.included !== false);
1773
1829
  const scoped = included.length ? included : workspaces;
1774
1830
  const businessIds = uniqueTruthy(scoped.map(workspace => workspace.business_id));
1775
1831
  const workspaceIds = uniqueTruthy(scoped.map(workspace => workspace.workspace_id));
1776
1832
  const businessSlugs = uniqueTruthy(scoped.map(workspace => workspace.business_slug || workspace.computer_slug));
1777
1833
  const templates = uniqueTruthy(scoped.map(workspace => workspace.workspace_template));
1834
+ const explicitPublic = typeof options.publicAgentXp === 'boolean' ? options.publicAgentXp : null;
1835
+ const workspacePublic = scoped.length === 1 && scoped[0]?.agentxp_public === true;
1836
+ const agentxpPublic = explicitPublic === null ? (workspacePublic ? true : null) : explicitPublic;
1778
1837
 
1779
1838
  if (businessIds.length > 1) {
1780
- return { attribution_scope: 'multi_business', computer: 'multiple-workspaces' };
1839
+ return { attribution_scope: 'multi_business', computer: 'multiple-workspaces', agentxp_public: explicitPublic === true };
1781
1840
  }
1782
1841
  if (businessIds.length === 0 && scoped.length > 1 && businessSlugs.length > 1) {
1783
- return { attribution_scope: 'multi_workspace', computer: 'multiple-workspaces' };
1842
+ return { attribution_scope: 'multi_workspace', computer: 'multiple-workspaces', agentxp_public: explicitPublic === true };
1784
1843
  }
1785
1844
 
1786
1845
  const businessId = businessIds[0] || null;
@@ -1794,9 +1853,32 @@ function syncAttribution(workspaces) {
1794
1853
  business_slug: businessSlug,
1795
1854
  workspace_template: workspaceTemplate,
1796
1855
  computer: businessSlug || scoped[0]?.computer || scoped[0]?.name || 'local',
1856
+ agentxp_public: agentxpPublic,
1857
+ };
1858
+ }
1859
+
1860
+ function syncScopeFields(attribution = {}) {
1861
+ const attributionScope = slugify(attribution.attribution_scope);
1862
+ const orgId = String(attribution.business_id || attribution.business_slug || '').trim() || null;
1863
+ const businessBound = Boolean(orgId) || attributionScope === 'business-bound' || attributionScope === 'multi-business';
1864
+ const publicAgentXp = typeof attribution.agentxp_public === 'boolean'
1865
+ ? attribution.agentxp_public
1866
+ : !businessBound;
1867
+ return {
1868
+ scope: publicAgentXp ? 'global' : (businessBound ? 'org' : 'global'),
1869
+ org_id: orgId,
1870
+ computer_id: String(attribution.workspace_id || attribution.computer || 'local').trim() || 'local',
1871
+ visibility: publicAgentXp ? 'public' : 'internal',
1872
+ public_agentxp: publicAgentXp,
1797
1873
  };
1798
1874
  }
1799
1875
 
1876
+ function publicAgentXpOverride(args = []) {
1877
+ if (hasFlag(args, '--public')) return true;
1878
+ if (hasFlag(args, '--private') || hasFlag(args, '--internal')) return false;
1879
+ return null;
1880
+ }
1881
+
1800
1882
  function credentialHandle(credentials) {
1801
1883
  return slugify(
1802
1884
  credentials?.username
@@ -1849,26 +1931,30 @@ function syncPlayer(args, projection) {
1849
1931
 
1850
1932
  function buildAgentXpSyncPacket(args = []) {
1851
1933
  const localMode = hasFlag(args, '--local') || hasFlag(args, '--workspace') || hasFlag(args, '--operator');
1852
- const projectionArgs = args.filter(arg => !['--dry-run', '--no-post', '--packet'].includes(arg));
1934
+ const projectionArgs = args.filter(arg => !['--dry-run', '--no-post', '--packet', '--public', '--private', '--internal'].includes(arg));
1853
1935
  const projection = hasFlag(args, '--all') || !localMode
1854
1936
  ? collectAllLocalXpProjection(projectionArgs)
1855
1937
  : collectLocalXpProjection(projectionArgs);
1856
1938
  const player = syncPlayer(args, projection);
1857
1939
  const workspaces = projectionWorkspaceSummaries(projection);
1858
- const attribution = syncAttribution(workspaces);
1940
+ const attribution = syncAttribution(workspaces, { publicAgentXp: publicAgentXpOverride(args) });
1941
+ const scopeFields = syncScopeFields(attribution);
1859
1942
  const totalXp = asNumber(projection.total_agent_xp ?? projection.agent_xp ?? projection.total_xp ?? projection.career_xp);
1860
1943
  const receiptsCount = asNumber(projection.receipts_count);
1861
1944
  const eligible = verifiedProjection(projection) && receiptsCount > 0 && totalXp > 0;
1862
- const publicXp = publicAgentXp(totalXp);
1945
+ const publicXp = earnedAgentXp(totalXp);
1946
+ const currentForm = currentFormScore(totalXp);
1947
+ const levelProgress = agentXpLevelProgress(publicXp);
1863
1948
  const workspaceRootHash = sha256(workspaces.map(item => item.workspace_root_hash || item.name).sort().join(':'));
1864
1949
  const entry = {
1865
1950
  user_id: player,
1866
1951
  username: player,
1867
1952
  agent_xp: publicXp,
1868
1953
  career_xp: publicXp,
1869
- current_form: publicXp,
1870
- ovr: publicXp,
1871
- level: Math.max(1, asNumber(projection.level, 1)),
1954
+ current_form: currentForm,
1955
+ ovr: currentForm,
1956
+ level: levelProgress.level,
1957
+ level_progress: levelProgress,
1872
1958
  verified_receipts: receiptsCount,
1873
1959
  reviewed_tasks: receiptsCount,
1874
1960
  recent_verified_receipts: receiptsCount,
@@ -1883,12 +1969,17 @@ function buildAgentXpSyncPacket(args = []) {
1883
1969
  schema: 'atris.agentxp_sync_packet.v1',
1884
1970
  generated_at: new Date().toISOString(),
1885
1971
  workspace_root_hash: workspaceRootHash,
1972
+ scope: scopeFields.scope,
1973
+ org_id: scopeFields.org_id,
1886
1974
  attribution_scope: attribution.attribution_scope,
1887
1975
  business_id: attribution.business_id || null,
1888
1976
  workspace_id: attribution.workspace_id || null,
1889
1977
  business_slug: attribution.business_slug || null,
1890
1978
  workspace_template: attribution.workspace_template || null,
1979
+ computer_id: scopeFields.computer_id,
1891
1980
  computer: attribution.computer || projection.workspace_name || workspaces[0]?.name || 'local',
1981
+ visibility: scopeFields.visibility,
1982
+ public_agentxp: scopeFields.public_agentxp,
1892
1983
  operator: player,
1893
1984
  privacy: {
1894
1985
  raw_proofs_included: false,
@@ -1903,12 +1994,17 @@ function buildAgentXpSyncPacket(args = []) {
1903
1994
  local_evidence: {
1904
1995
  schema: 'atris.agentxp_local_evidence.v1',
1905
1996
  workspace_root_hash: workspaceRootHash,
1997
+ scope: scopeFields.scope,
1998
+ org_id: scopeFields.org_id,
1906
1999
  attribution_scope: attribution.attribution_scope,
1907
2000
  business_id: attribution.business_id || null,
1908
2001
  workspace_id: attribution.workspace_id || null,
1909
2002
  business_slug: attribution.business_slug || null,
1910
2003
  workspace_template: attribution.workspace_template || null,
2004
+ computer_id: scopeFields.computer_id,
1911
2005
  computer: attribution.computer || null,
2006
+ visibility: scopeFields.visibility,
2007
+ public_agentxp: scopeFields.public_agentxp,
1912
2008
  workspaces,
1913
2009
  verified_workspace_count: asNumber(projection.verified_workspace_count, verifiedProjection(projection) ? 1 : 0),
1914
2010
  receipts_count: receiptsCount,
@@ -1933,12 +2029,17 @@ function buildAgentXpSyncPacket(args = []) {
1933
2029
  gm_projection: {
1934
2030
  schema: 'atris.gm_xp_projection.v1',
1935
2031
  workspace_root_hash: workspaceRootHash,
2032
+ scope: scopeFields.scope,
2033
+ org_id: scopeFields.org_id,
1936
2034
  attribution_scope: attribution.attribution_scope,
1937
2035
  business_id: attribution.business_id || null,
1938
2036
  workspace_id: attribution.workspace_id || null,
1939
2037
  business_slug: attribution.business_slug || null,
1940
2038
  workspace_template: attribution.workspace_template || null,
2039
+ computer_id: scopeFields.computer_id,
1941
2040
  computer: attribution.computer || null,
2041
+ visibility: scopeFields.visibility,
2042
+ public_agentxp: scopeFields.public_agentxp,
1942
2043
  operator: player,
1943
2044
  player_score: {
1944
2045
  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.56",
4
4
  "main": "bin/atris.js",
5
5
  "bin": {
6
6
  "atris": "bin/atris.js",