@jungjaehoon/mama-os 0.35.0 → 0.36.1

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.
Files changed (144) hide show
  1. package/dist/agent/agent-loop.d.ts +2 -1
  2. package/dist/agent/agent-loop.d.ts.map +1 -1
  3. package/dist/agent/agent-loop.js.map +1 -1
  4. package/dist/agent/backend-model-policy.d.ts +28 -0
  5. package/dist/agent/backend-model-policy.d.ts.map +1 -1
  6. package/dist/agent/backend-model-policy.js +87 -2
  7. package/dist/agent/backend-model-policy.js.map +1 -1
  8. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  9. package/dist/agent/code-act/host-bridge.js +65 -2
  10. package/dist/agent/code-act/host-bridge.js.map +1 -1
  11. package/dist/agent/code-act/type-definition-generator.d.ts.map +1 -1
  12. package/dist/agent/code-act/type-definition-generator.js +3 -1
  13. package/dist/agent/code-act/type-definition-generator.js.map +1 -1
  14. package/dist/agent/context-compile-service.d.ts +2 -0
  15. package/dist/agent/context-compile-service.d.ts.map +1 -1
  16. package/dist/agent/context-compile-service.js +1 -1
  17. package/dist/agent/context-compile-service.js.map +1 -1
  18. package/dist/agent/gateway-tool-executor.d.ts +8 -5
  19. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  20. package/dist/agent/gateway-tool-executor.js +183 -20
  21. package/dist/agent/gateway-tool-executor.js.map +1 -1
  22. package/dist/agent/gateway-tools.md +5 -0
  23. package/dist/agent/managed-agent-runtime-sync.d.ts.map +1 -1
  24. package/dist/agent/managed-agent-runtime-sync.js +37 -8
  25. package/dist/agent/managed-agent-runtime-sync.js.map +1 -1
  26. package/dist/agent/role-manager.d.ts.map +1 -1
  27. package/dist/agent/role-manager.js +4 -5
  28. package/dist/agent/role-manager.js.map +1 -1
  29. package/dist/agent/tool-registry.d.ts.map +1 -1
  30. package/dist/agent/tool-registry.js +50 -0
  31. package/dist/agent/tool-registry.js.map +1 -1
  32. package/dist/agent/types.d.ts +40 -2
  33. package/dist/agent/types.d.ts.map +1 -1
  34. package/dist/agent/types.js.map +1 -1
  35. package/dist/api/graph-api.d.ts.map +1 -1
  36. package/dist/api/graph-api.js +68 -4
  37. package/dist/api/graph-api.js.map +1 -1
  38. package/dist/api/report-handler.d.ts +9 -5
  39. package/dist/api/report-handler.d.ts.map +1 -1
  40. package/dist/api/report-handler.js +26 -13
  41. package/dist/api/report-handler.js.map +1 -1
  42. package/dist/api/report-persistence.d.ts.map +1 -1
  43. package/dist/api/report-persistence.js +6 -3
  44. package/dist/api/report-persistence.js.map +1 -1
  45. package/dist/api/runtime-status-handler.d.ts +1 -0
  46. package/dist/api/runtime-status-handler.d.ts.map +1 -1
  47. package/dist/api/runtime-status-handler.js +1 -0
  48. package/dist/api/runtime-status-handler.js.map +1 -1
  49. package/dist/cli/commands/init.d.ts.map +1 -1
  50. package/dist/cli/commands/init.js +10 -9
  51. package/dist/cli/commands/init.js.map +1 -1
  52. package/dist/cli/commands/start.d.ts +20 -2
  53. package/dist/cli/commands/start.d.ts.map +1 -1
  54. package/dist/cli/commands/start.js +94 -49
  55. package/dist/cli/commands/start.js.map +1 -1
  56. package/dist/cli/commands/status.d.ts +6 -0
  57. package/dist/cli/commands/status.d.ts.map +1 -1
  58. package/dist/cli/commands/status.js +89 -0
  59. package/dist/cli/commands/status.js.map +1 -1
  60. package/dist/cli/config/config-manager.d.ts.map +1 -1
  61. package/dist/cli/config/config-manager.js +34 -14
  62. package/dist/cli/config/config-manager.js.map +1 -1
  63. package/dist/cli/config/types.d.ts.map +1 -1
  64. package/dist/cli/config/types.js +5 -0
  65. package/dist/cli/config/types.js.map +1 -1
  66. package/dist/cli/index.js +2 -15
  67. package/dist/cli/index.js.map +1 -1
  68. package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
  69. package/dist/cli/runtime/agent-loop-init.js +0 -8
  70. package/dist/cli/runtime/agent-loop-init.js.map +1 -1
  71. package/dist/cli/runtime/api-routes-init.d.ts +7 -1
  72. package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
  73. package/dist/cli/runtime/api-routes-init.js +104 -29
  74. package/dist/cli/runtime/api-routes-init.js.map +1 -1
  75. package/dist/cli/runtime/api-server-init.d.ts.map +1 -1
  76. package/dist/cli/runtime/api-server-init.js +3 -0
  77. package/dist/cli/runtime/api-server-init.js.map +1 -1
  78. package/dist/cli/runtime/gateway-init.d.ts +6 -1
  79. package/dist/cli/runtime/gateway-init.d.ts.map +1 -1
  80. package/dist/cli/runtime/gateway-init.js +4 -1
  81. package/dist/cli/runtime/gateway-init.js.map +1 -1
  82. package/dist/cli/runtime/owner-backfill.d.ts +24 -0
  83. package/dist/cli/runtime/owner-backfill.d.ts.map +1 -0
  84. package/dist/cli/runtime/owner-backfill.js +24 -0
  85. package/dist/cli/runtime/owner-backfill.js.map +1 -0
  86. package/dist/envelope/reactive-config.js +1 -1
  87. package/dist/envelope/reactive-config.js.map +1 -1
  88. package/dist/gateways/discord.d.ts +8 -0
  89. package/dist/gateways/discord.d.ts.map +1 -1
  90. package/dist/gateways/discord.js +8 -2
  91. package/dist/gateways/discord.js.map +1 -1
  92. package/dist/gateways/member-candidate-store.d.ts +26 -0
  93. package/dist/gateways/member-candidate-store.d.ts.map +1 -0
  94. package/dist/gateways/member-candidate-store.js +90 -0
  95. package/dist/gateways/member-candidate-store.js.map +1 -0
  96. package/dist/gateways/message-router.d.ts.map +1 -1
  97. package/dist/gateways/message-router.js +4 -1
  98. package/dist/gateways/message-router.js.map +1 -1
  99. package/dist/gateways/principal.d.ts +11 -1
  100. package/dist/gateways/principal.d.ts.map +1 -1
  101. package/dist/gateways/principal.js +22 -3
  102. package/dist/gateways/principal.js.map +1 -1
  103. package/dist/gateways/slack.d.ts +8 -0
  104. package/dist/gateways/slack.d.ts.map +1 -1
  105. package/dist/gateways/slack.js +6 -1
  106. package/dist/gateways/slack.js.map +1 -1
  107. package/dist/gateways/telegram.d.ts +7 -0
  108. package/dist/gateways/telegram.d.ts.map +1 -1
  109. package/dist/gateways/telegram.js +20 -1
  110. package/dist/gateways/telegram.js.map +1 -1
  111. package/dist/observability/code-audit.d.ts.map +1 -1
  112. package/dist/observability/code-audit.js +11 -3
  113. package/dist/observability/code-audit.js.map +1 -1
  114. package/dist/operator/action-verifier.d.ts +2 -0
  115. package/dist/operator/action-verifier.d.ts.map +1 -1
  116. package/dist/operator/action-verifier.js +3 -2
  117. package/dist/operator/action-verifier.js.map +1 -1
  118. package/dist/operator/board-reconcile.d.ts +2 -2
  119. package/dist/operator/board-reconcile.d.ts.map +1 -1
  120. package/dist/operator/board-reconcile.js +10 -2
  121. package/dist/operator/board-reconcile.js.map +1 -1
  122. package/dist/operator/board-refresh-gate.d.ts +34 -0
  123. package/dist/operator/board-refresh-gate.d.ts.map +1 -0
  124. package/dist/operator/board-refresh-gate.js +82 -0
  125. package/dist/operator/board-refresh-gate.js.map +1 -0
  126. package/dist/operator/briefs.d.ts.map +1 -1
  127. package/dist/operator/briefs.js +92 -4
  128. package/dist/operator/briefs.js.map +1 -1
  129. package/dist/operator/workorder-hooks.d.ts +14 -0
  130. package/dist/operator/workorder-hooks.d.ts.map +1 -1
  131. package/dist/operator/workorder-hooks.js +64 -0
  132. package/dist/operator/workorder-hooks.js.map +1 -1
  133. package/dist/operator/workorder-publishers.d.ts +10 -0
  134. package/dist/operator/workorder-publishers.d.ts.map +1 -1
  135. package/dist/operator/workorder-publishers.js +39 -8
  136. package/dist/operator/workorder-publishers.js.map +1 -1
  137. package/dist/package-version.d.ts +3 -0
  138. package/dist/package-version.d.ts.map +1 -0
  139. package/dist/package-version.js +18 -0
  140. package/dist/package-version.js.map +1 -0
  141. package/package.json +2 -2
  142. package/public/viewer/js/modules/system.js +1 -0
  143. package/public/viewer/src/modules/system.ts +2 -0
  144. package/public/viewer/sw.js +2 -2
@@ -79,11 +79,15 @@ const wiki_publish_adapter_js_1 = require("../wiki-artifacts/wiki-publish-adapte
79
79
  const changes_projection_js_1 = require("../operator/changes-projection.js");
80
80
  const read_js_1 = require("../evidence/read.js");
81
81
  const private_connector_policy_js_1 = require("../connectors/private-connector-policy.js");
82
+ const member_candidate_store_js_1 = require("../gateways/member-candidate-store.js");
82
83
  const DEFAULT_PRIVATE_CONNECTOR_POLICY = (0, private_connector_policy_js_1.resolvePrivateConnectorPolicy)({
83
84
  ok: true,
84
85
  config: {},
85
86
  enabledNames: [],
86
87
  });
88
+ function isReportPublishResult(value) {
89
+ return value !== undefined && !Array.isArray(value);
90
+ }
87
91
  function serializeTaskToolRecord(task) {
88
92
  return {
89
93
  ...task,
@@ -202,6 +206,13 @@ const ENVELOPE_REQUIRED_SURFACES = new Set([
202
206
  'reactive_internal',
203
207
  'code_act',
204
208
  ]);
209
+ const OWNER_CONSOLE_MEMBER_TOOLS = new Set([
210
+ 'member_candidates',
211
+ 'member_register',
212
+ 'member_suspend',
213
+ 'member_offboard',
214
+ 'member_list',
215
+ ]);
205
216
  class ContextPacketProvenanceError extends Error {
206
217
  }
207
218
  function asRecord(value) {
@@ -373,6 +384,7 @@ class GatewayToolExecutor {
373
384
  channelGrantProvider;
374
385
  envelopeIssuanceMode;
375
386
  metricsStore;
387
+ principalRepository;
376
388
  contextCompileService;
377
389
  temporalContextPacketLookup;
378
390
  currentContext = null;
@@ -489,6 +501,8 @@ class GatewayToolExecutor {
489
501
  signal: active.signal,
490
502
  parentToolName: active.parentToolName ?? fallback.parentToolName,
491
503
  backgroundTasks: active.backgroundTasks ?? fallback.backgroundTasks,
504
+ // Never merged from fallback - one snapshot belongs to one gateway call only.
505
+ channelGrantSnapshot: active.channelGrantSnapshot,
492
506
  // Never merged from fallback - blocks are strictly per-call.
493
507
  disallowedGatewayTools: active.disallowedGatewayTools,
494
508
  };
@@ -566,6 +580,9 @@ class GatewayToolExecutor {
566
580
  setWikiPublishAdapter(adapter) {
567
581
  this.wikiPublishAdapter = adapter;
568
582
  }
583
+ setPrincipalRepository(repository) {
584
+ this.principalRepository = repository;
585
+ }
569
586
  /** Check if a memory agent is available for routing memory writes. */
570
587
  hasMemoryAgent() {
571
588
  return this.memoryAgentProcessManager !== null;
@@ -582,6 +599,7 @@ class GatewayToolExecutor {
582
599
  this.sessionStore = options.sessionStore;
583
600
  this.envelopeIssuanceMode = options.envelopeIssuanceMode ?? 'enabled';
584
601
  this.metricsStore = options.metricsStore ?? null;
602
+ this.principalRepository = options.principalRepository ?? null;
585
603
  this.contextCompileService = options.contextCompileService;
586
604
  this.temporalContextPacketLookup =
587
605
  options.temporalContextPacketLookup ??
@@ -838,7 +856,7 @@ class GatewayToolExecutor {
838
856
  }
839
857
  try {
840
858
  this.envelopeEnforcer.check(ctx.envelope, toolName, enforcementInput, {
841
- readScopeMirror: this.readScopeMirrorFor(toolName, ctx.envelope),
859
+ readScopeMirror: this.readScopeMirrorFor(toolName, ctx.envelope, ctx.channelGrantSnapshot),
842
860
  });
843
861
  return undefined;
844
862
  }
@@ -938,7 +956,10 @@ class GatewayToolExecutor {
938
956
  const baseCtx = this.mergeWithFallbackExecutionContext(this.executionContextStorage.getStore());
939
957
  baseCtx.signal?.throwIfAborted();
940
958
  const gatewayCallId = baseCtx.gatewayCallId ?? `gw_${(0, crypto_1.randomUUID)().replace(/-/g, '')}`;
941
- const ctx = { ...baseCtx, gatewayCallId };
959
+ const channelGrantSnapshot = baseCtx.envelope && index_js_1.MIRROR_READABLE_TOOLS.has(toolName)
960
+ ? snapshotChannelGrant(this.channelGrantProvider)
961
+ : undefined;
962
+ const ctx = { ...baseCtx, gatewayCallId, channelGrantSnapshot };
942
963
  const effectiveInput = this.applyEnvelopeScopedReadDefaults(toolName, input, ctx);
943
964
  const computedScopeAudit = this.computeScopeAuditFields(toolName, effectiveInput, ctx);
944
965
  const scopeAudit = ctx.temporalWorkContext
@@ -995,7 +1016,7 @@ class GatewayToolExecutor {
995
1016
  await this.failDirectModelRunIfNeeded(traceState, toolName, auditError).catch((finalizationError) => {
996
1017
  securityLogger.warn('[model-run] failed to finalize failed direct model run', finalizationError);
997
1018
  });
998
- this.logGatewayToolCall(activeCtx, toolName, undefined, Date.now() - startedAt, scopeAudit, gatewayCallId, auditError);
1019
+ this.logGatewayToolCall(activeCtx, toolName, undefined, Date.now() - startedAt, scopeAudit, gatewayCallId, this.gatewayTraceDetails(toolName, undefined), auditError);
999
1020
  if (scopeAudit.mismatch) {
1000
1021
  this.alarmScopeMismatch(activeCtx, toolName);
1001
1022
  }
@@ -1010,13 +1031,13 @@ class GatewayToolExecutor {
1010
1031
  }
1011
1032
  }
1012
1033
  catch (postRunError) {
1013
- this.logGatewayToolCall(activeCtx, toolName, auditResult, Date.now() - startedAt, scopeAudit, gatewayCallId, postRunError);
1034
+ this.logGatewayToolCall(activeCtx, toolName, auditResult, Date.now() - startedAt, scopeAudit, gatewayCallId, this.gatewayTraceDetails(toolName, auditResult), postRunError);
1014
1035
  if (scopeAudit.mismatch) {
1015
1036
  this.alarmScopeMismatch(activeCtx, toolName);
1016
1037
  }
1017
1038
  throw postRunError;
1018
1039
  }
1019
- this.logGatewayToolCall(activeCtx, toolName, auditResult, Date.now() - startedAt, scopeAudit, gatewayCallId);
1040
+ this.logGatewayToolCall(activeCtx, toolName, auditResult, Date.now() - startedAt, scopeAudit, gatewayCallId, this.gatewayTraceDetails(toolName, auditResult));
1020
1041
  if (scopeAudit.mismatch) {
1021
1042
  this.alarmScopeMismatch(activeCtx, toolName);
1022
1043
  }
@@ -1174,7 +1195,9 @@ class GatewayToolExecutor {
1174
1195
  return { requestedScopes, envelopeScopesSnapshot, mismatch: 0 };
1175
1196
  }
1176
1197
  if (!requestedScopes || requestedScopes.length === 0) {
1177
- if (toolName === 'context_compile' && Array.isArray(input.scopes)) {
1198
+ const requestedScopeValue = input.scopes;
1199
+ if (toolName === 'context_compile' &&
1200
+ (requestedScopeValue === undefined || Array.isArray(requestedScopeValue))) {
1178
1201
  return { requestedScopes, envelopeScopesSnapshot, mismatch: 0 };
1179
1202
  }
1180
1203
  return {
@@ -1183,7 +1206,11 @@ class GatewayToolExecutor {
1183
1206
  mismatch: envelopeScopesSnapshot.length > 0 ? 1 : 0,
1184
1207
  };
1185
1208
  }
1186
- const envelopeScopeKeys = new Set(envelopeScopesSnapshot.map(memoryScopeKey));
1209
+ const effectiveAuditAllowance = [
1210
+ ...envelopeScopesSnapshot,
1211
+ ...(this.readScopeMirrorFor(toolName, ctx.envelope, ctx.channelGrantSnapshot) ?? []),
1212
+ ];
1213
+ const envelopeScopeKeys = new Set(effectiveAuditAllowance.map(memoryScopeKey));
1187
1214
  const hasOutOfEnvelopeScope = requestedScopes.some((scope) => !envelopeScopeKeys.has(memoryScopeKey(scope)));
1188
1215
  return {
1189
1216
  requestedScopes,
@@ -1230,7 +1257,7 @@ class GatewayToolExecutor {
1230
1257
  const envelopeScopes = ctx.envelope
1231
1258
  ? [
1232
1259
  ...ctx.envelope.scope.memory_scopes,
1233
- ...(0, read_js_1.mirrorReadScopes)(ctx.envelope, this.channelGrantProvider()),
1260
+ ...(this.readScopeMirrorFor(toolName, ctx.envelope, ctx.channelGrantSnapshot) ?? []),
1234
1261
  ]
1235
1262
  : null;
1236
1263
  const allowedScopes = envelopeScopes ?? this.deriveMemoryScopesFromActiveContext(ctx) ?? [];
@@ -1277,15 +1304,14 @@ class GatewayToolExecutor {
1277
1304
  }
1278
1305
  /**
1279
1306
  * The grant-mirror READ allowance for memory tools (see mirrorReadScopes):
1280
- * computed lazily - only memory-scoped tools pay the connector-config read -
1281
- * and against the LIVE grant, so a channel the owner removes stops being
1282
- * readable on the next call, mid-envelope included.
1307
+ * computed from the gateway-call snapshot, so every authority check agrees
1308
+ * within one call while the next call observes a fresh live grant.
1283
1309
  */
1284
- readScopeMirrorFor(toolName, envelope) {
1285
- if (!index_js_1.MIRROR_READABLE_TOOLS.has(toolName)) {
1310
+ readScopeMirrorFor(toolName, envelope, channelGrantSnapshot) {
1311
+ if (!index_js_1.MIRROR_READABLE_TOOLS.has(toolName) || !channelGrantSnapshot) {
1286
1312
  return undefined;
1287
1313
  }
1288
- return (0, read_js_1.mirrorReadScopes)(envelope, this.channelGrantProvider());
1314
+ return (0, read_js_1.mirrorReadScopes)(envelope, channelGrantSnapshot);
1289
1315
  }
1290
1316
  applyEnvelopeScopedReadDefaults(toolName, input, ctx) {
1291
1317
  // Memory read tools must inherit envelope scopes consistently when the
@@ -1327,7 +1353,7 @@ class GatewayToolExecutor {
1327
1353
  // READ defaulting: identity scopes plus the grant mirror, so an omitted
1328
1354
  // scopes arg recalls everything this run is ALLOWED to read instead of
1329
1355
  // silently less than the enforcer would accept.
1330
- const mirror = (0, read_js_1.mirrorReadScopes)(ctx.envelope, this.channelGrantProvider());
1356
+ const mirror = this.readScopeMirrorFor(toolName, ctx.envelope, ctx.channelGrantSnapshot) ?? [];
1331
1357
  const seen = new Set(ctx.envelope.scope.memory_scopes.map((scope) => `${scope.kind}:${scope.id}`));
1332
1358
  return {
1333
1359
  ...scopedInput,
@@ -1420,7 +1446,7 @@ class GatewayToolExecutor {
1420
1446
  typeof candidate.reasoning === 'string' &&
1421
1447
  candidate.reasoning.length > 0);
1422
1448
  }
1423
- logGatewayToolCall(ctx, toolName, result, durationMs, scopeAudit, gatewayCallId, error) {
1449
+ logGatewayToolCall(ctx, toolName, result, durationMs, scopeAudit, gatewayCallId, toolDetails, error) {
1424
1450
  try {
1425
1451
  if (!this.sessionsDb) {
1426
1452
  return;
@@ -1454,6 +1480,7 @@ class GatewayToolExecutor {
1454
1480
  ...(ctx?.workorderAttemptId !== undefined
1455
1481
  ? { workorder_attempt_id: ctx.workorderAttemptId }
1456
1482
  : {}),
1483
+ ...toolDetails,
1457
1484
  },
1458
1485
  });
1459
1486
  }
@@ -1461,6 +1488,16 @@ class GatewayToolExecutor {
1461
1488
  securityLogger.warn('[envelope] gateway audit log failed (non-fatal)', logErr);
1462
1489
  }
1463
1490
  }
1491
+ gatewayTraceDetails(toolName, result) {
1492
+ if (toolName !== 'report_publish')
1493
+ return {};
1494
+ const slotIds = result?.acceptedSlotIds;
1495
+ if (!Array.isArray(slotIds) || slotIds.some((slotId) => typeof slotId !== 'string'))
1496
+ return {};
1497
+ // Audit only the structural slot identity. Board HTML/content must never
1498
+ // enter gateway trace details.
1499
+ return { report_slot_ids: [...slotIds].sort() };
1500
+ }
1464
1501
  alarmScopeMismatch(ctx, toolName) {
1465
1502
  try {
1466
1503
  this.metricsStore?.record({
@@ -1494,6 +1531,13 @@ class GatewayToolExecutor {
1494
1531
  if (!VALID_TOOLS.includes(toolName)) {
1495
1532
  throw new types_js_1.AgentError(`Unknown tool: ${toolName}`, 'UNKNOWN_TOOL', undefined, false);
1496
1533
  }
1534
+ if (OWNER_CONSOLE_MEMBER_TOOLS.has(toolName) &&
1535
+ this.getExecutionState().agentContext?.roleName !== 'owner_console') {
1536
+ return {
1537
+ success: false,
1538
+ error: `Permission denied: ${toolName} is restricted to owner_console.`,
1539
+ };
1540
+ }
1497
1541
  if (toolName.startsWith('drive_') &&
1498
1542
  this.getExecutionState().agentContext?.roleName !== 'owner_console') {
1499
1543
  return {
@@ -1751,11 +1795,28 @@ class GatewayToolExecutor {
1751
1795
  }
1752
1796
  }
1753
1797
  if (this.reportPublisher) {
1754
- this.reportPublisher(slotsInput);
1755
- const slotNames = Object.keys(slotsInput);
1798
+ const publication = this.reportPublisher(slotsInput);
1799
+ // Backward compatibility: older injected publishers return void
1800
+ // or the exact changed slot array. Production distinguishes slots
1801
+ // accepted as present from slots whose HTML actually changed.
1802
+ const acceptedSlotIds = Array.isArray(publication)
1803
+ ? [...new Set(publication)].sort()
1804
+ : isReportPublishResult(publication)
1805
+ ? [...new Set(publication.acceptedSlotIds)].sort()
1806
+ : Object.keys(slotsInput).sort();
1807
+ const changedSlotIds = Array.isArray(publication)
1808
+ ? [...acceptedSlotIds]
1809
+ : isReportPublishResult(publication)
1810
+ ? [...new Set(publication.changedSlotIds)].sort()
1811
+ : [...acceptedSlotIds];
1812
+ if (acceptedSlotIds.length === 0) {
1813
+ throw new types_js_1.AgentError('Report publisher accepted no slots', 'TOOL_ERROR', undefined, false);
1814
+ }
1756
1815
  return {
1757
1816
  success: true,
1758
- message: `Dashboard updated: ${slotNames.join(', ')} (${slotNames.length} slots)`,
1817
+ acceptedSlotIds,
1818
+ changedSlotIds,
1819
+ message: `Dashboard report accepted: ${acceptedSlotIds.join(', ')} (${acceptedSlotIds.length} accepted, ${changedSlotIds.length} changed)`,
1759
1820
  };
1760
1821
  }
1761
1822
  throw new types_js_1.AgentError('Report publisher not configured', 'TOOL_ERROR', undefined, false);
@@ -1862,6 +1923,103 @@ class GatewayToolExecutor {
1862
1923
  message: 'Lesson appended to your operating brief; it applies from the next session re-anchor.',
1863
1924
  };
1864
1925
  }
1926
+ case 'member_candidates': {
1927
+ const candidates = (0, member_candidate_store_js_1.getMemberCandidateStore)()
1928
+ .list(Date.now())
1929
+ .map((candidate) => ({
1930
+ candidateId: candidate.candidateId,
1931
+ ...(candidate.displayName === undefined
1932
+ ? {}
1933
+ : {
1934
+ displayName: (0, untrusted_content_js_1.wrapUntrustedContent)('member-candidate-display-name', candidate.displayName),
1935
+ }),
1936
+ firstSeen: candidate.firstSeen,
1937
+ }));
1938
+ return { success: true, candidates };
1939
+ }
1940
+ case 'member_register': {
1941
+ const fields = Object.keys(input);
1942
+ const candidateId = input.candidate_id;
1943
+ if (fields.length !== 1 ||
1944
+ fields[0] !== 'candidate_id' ||
1945
+ typeof candidateId !== 'string' ||
1946
+ candidateId.trim().length === 0) {
1947
+ return {
1948
+ success: false,
1949
+ code: 'member_candidate_required',
1950
+ error: 'member_register accepts exactly one candidate_id from member_candidates.',
1951
+ };
1952
+ }
1953
+ if (!this.principalRepository) {
1954
+ return {
1955
+ success: false,
1956
+ code: 'principal_repository_unavailable',
1957
+ error: 'Principal repository is not wired on this deployment.',
1958
+ };
1959
+ }
1960
+ const now = Date.now();
1961
+ const candidateStore = (0, member_candidate_store_js_1.getMemberCandidateStore)();
1962
+ const candidate = candidateStore.get(candidateId, now);
1963
+ if (!candidate) {
1964
+ return {
1965
+ success: false,
1966
+ code: 'member_candidate_missing',
1967
+ error: 'Member candidate is missing or expired.',
1968
+ };
1969
+ }
1970
+ const principalId = this.principalRepository.registerMember({
1971
+ connector: candidate.connector,
1972
+ namespace: candidate.namespace,
1973
+ externalId: candidate.externalId,
1974
+ ...(candidate.displayName === undefined ? {} : { displayName: candidate.displayName }),
1975
+ now,
1976
+ });
1977
+ candidateStore.delete(candidate.candidateId);
1978
+ return { success: true, principalId };
1979
+ }
1980
+ case 'member_suspend':
1981
+ case 'member_offboard': {
1982
+ const principalId = input.principal_id;
1983
+ if (typeof principalId !== 'string' || principalId.trim().length === 0) {
1984
+ return {
1985
+ success: false,
1986
+ code: 'principal_id_required',
1987
+ error: `${toolName} requires principal_id.`,
1988
+ };
1989
+ }
1990
+ if (!this.principalRepository) {
1991
+ return {
1992
+ success: false,
1993
+ code: 'principal_repository_unavailable',
1994
+ error: 'Principal repository is not wired on this deployment.',
1995
+ };
1996
+ }
1997
+ const now = Date.now();
1998
+ if (toolName === 'member_suspend') {
1999
+ this.principalRepository.suspend(principalId, now);
2000
+ return { success: true, principalId, status: 'suspended' };
2001
+ }
2002
+ this.principalRepository.offboard(principalId, now);
2003
+ return { success: true, principalId, status: 'offboarded' };
2004
+ }
2005
+ case 'member_list': {
2006
+ if (!this.principalRepository) {
2007
+ return {
2008
+ success: false,
2009
+ code: 'principal_repository_unavailable',
2010
+ error: 'Principal repository is not wired on this deployment.',
2011
+ };
2012
+ }
2013
+ const members = this.principalRepository.listMembers().map((member) => ({
2014
+ ...member,
2015
+ ...(member.displayName === undefined
2016
+ ? {}
2017
+ : {
2018
+ displayName: (0, untrusted_content_js_1.wrapUntrustedContent)('member-list-display-name', member.displayName),
2019
+ }),
2020
+ }));
2021
+ return { success: true, members };
2022
+ }
1865
2023
  case 'board_read': {
1866
2024
  if (!this.reportReader) {
1867
2025
  return {
@@ -3162,7 +3320,7 @@ class GatewayToolExecutor {
3162
3320
  // back excerpts from every other channel of the connector. Citation would then be
3163
3321
  // strictly wider than reading, which is the one thing this path must never be.
3164
3322
  const citationChannels = ctx.envelope
3165
- ? (0, read_js_1.narrowGrantToEnvelope)((0, read_js_1.liveBoundaryChannels)(), {
3323
+ ? (0, read_js_1.narrowGrantToEnvelope)(ctx.channelGrantSnapshot ?? {}, {
3166
3324
  connectors,
3167
3325
  scopes: ctx.envelope.scope.memory_scopes ?? [],
3168
3326
  })
@@ -3307,6 +3465,7 @@ class GatewayToolExecutor {
3307
3465
  caller: 'gateway',
3308
3466
  envelope: ctx.envelope,
3309
3467
  modelRunId: ctx.modelRunId ?? null,
3468
+ channelGrantSnapshot: ctx.channelGrantSnapshot,
3310
3469
  input: effectiveInput,
3311
3470
  signal: ctx.signal,
3312
3471
  beforePersist: temporalContext
@@ -3428,6 +3587,10 @@ function getContextPacketIdForTrustedProvenance(input) {
3428
3587
  function dedupeSourceRefs(refs) {
3429
3588
  return [...new Set(refs)];
3430
3589
  }
3590
+ function snapshotChannelGrant(provider) {
3591
+ const liveGrant = provider();
3592
+ return Object.fromEntries(Object.entries(liveGrant).map(([connector, channels]) => [connector, [...channels]]));
3593
+ }
3431
3594
  function normalizeMemoryScopes(value) {
3432
3595
  if (!Array.isArray(value) || value.length === 0) {
3433
3596
  return null;