instar 1.3.1660 → 1.3.1661
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/dashboard/desktop.css +2 -0
- package/dashboard/desktop.html +1 -0
- package/dashboard/desktop.js +39 -3
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +67 -34
- package/dist/commands/server.js.map +1 -1
- package/dist/core/DesktopAccessAudit.d.ts +5 -1
- package/dist/core/DesktopAccessAudit.d.ts.map +1 -1
- package/dist/core/DesktopAccessAudit.js +5 -0
- package/dist/core/DesktopAccessAudit.js.map +1 -1
- package/dist/core/DesktopLockedController.d.ts +21 -1
- package/dist/core/DesktopLockedController.d.ts.map +1 -1
- package/dist/core/DesktopLockedController.js +29 -7
- package/dist/core/DesktopLockedController.js.map +1 -1
- package/dist/core/DirectDesktopAccess.d.ts +26 -1
- package/dist/core/DirectDesktopAccess.d.ts.map +1 -1
- package/dist/core/DirectDesktopAccess.js +77 -8
- package/dist/core/DirectDesktopAccess.js.map +1 -1
- package/dist/core/MacDesktopHost.d.ts +1 -0
- package/dist/core/MacDesktopHost.d.ts.map +1 -1
- package/dist/core/MacDesktopHost.js +29 -3
- package/dist/core/MacDesktopHost.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +27 -6
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts +6 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +12 -1
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
- package/dist/core/WriteDomainRegistry.js +8 -0
- package/dist/core/WriteDomainRegistry.js.map +1 -1
- package/dist/core/channelRegistry.d.ts +6 -0
- package/dist/core/channelRegistry.d.ts.map +1 -1
- package/dist/core/channelRegistry.js +19 -0
- package/dist/core/channelRegistry.js.map +1 -1
- package/dist/core/dashboardPin.d.ts +22 -0
- package/dist/core/dashboardPin.d.ts.map +1 -1
- package/dist/core/dashboardPin.js +41 -0
- package/dist/core/dashboardPin.js.map +1 -1
- package/dist/core/instarChannels.d.ts +2 -0
- package/dist/core/instarChannels.d.ts.map +1 -1
- package/dist/core/instarChannels.js +13 -0
- package/dist/core/instarChannels.js.map +1 -1
- package/dist/core/memorySandboxProbe.d.ts +8 -0
- package/dist/core/memorySandboxProbe.d.ts.map +1 -1
- package/dist/core/memorySandboxProbe.js +25 -0
- package/dist/core/memorySandboxProbe.js.map +1 -1
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/dist/lifeline/TelegramLifeline.d.ts +10 -0
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +92 -16
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/lifeline/pollDecision.d.ts +27 -0
- package/dist/lifeline/pollDecision.d.ts.map +1 -1
- package/dist/lifeline/pollDecision.js +28 -0
- package/dist/lifeline/pollDecision.js.map +1 -1
- package/dist/messaging/TelegramAdapter.d.ts +3 -0
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +12 -0
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/messaging/telegram-origin/OriginDeliveryResolution.d.ts.map +1 -1
- package/dist/messaging/telegram-origin/OriginDeliveryResolution.js +2 -1
- package/dist/messaging/telegram-origin/OriginDeliveryResolution.js.map +1 -1
- package/dist/messaging/telegram-origin/OriginForwardToHolder.d.ts +9 -1
- package/dist/messaging/telegram-origin/OriginForwardToHolder.d.ts.map +1 -1
- package/dist/messaging/telegram-origin/OriginForwardToHolder.js +48 -5
- package/dist/messaging/telegram-origin/OriginForwardToHolder.js.map +1 -1
- package/dist/messaging/telegram-origin/OriginMesh.d.ts.map +1 -1
- package/dist/messaging/telegram-origin/OriginMesh.js +4 -2
- package/dist/messaging/telegram-origin/OriginMesh.js.map +1 -1
- package/dist/messaging/telegram-origin/OriginOperationOutcome.d.ts +1 -0
- package/dist/messaging/telegram-origin/OriginOperationOutcome.d.ts.map +1 -1
- package/dist/messaging/telegram-origin/OriginOperationOutcome.js +21 -15
- package/dist/messaging/telegram-origin/OriginOperationOutcome.js.map +1 -1
- package/dist/messaging/telegram-origin/OriginStoreBackend.d.ts.map +1 -1
- package/dist/messaging/telegram-origin/OriginStoreBackend.js +7 -1
- package/dist/messaging/telegram-origin/OriginStoreBackend.js.map +1 -1
- package/dist/messaging/telegram-origin/TelegramOriginRuntime.js +1 -1
- package/dist/messaging/telegram-origin/TelegramOriginRuntime.js.map +1 -1
- package/dist/native/InstarWedgeCanary.app/Contents/MacOS/InstarWedgeCanary +0 -0
- package/dist/native/instar-desktop-host +0 -0
- package/dist/native/instar-desktop-host.json +1 -1
- package/dist/recommended/recipes.d.ts.map +1 -1
- package/dist/recommended/recipes.js +3 -0
- package/dist/recommended/recipes.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +5 -4
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +25 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.js +4 -4
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +6 -0
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/recommendedServiceRoutes.d.ts.map +1 -1
- package/dist/server/recommendedServiceRoutes.js +2 -1
- package/dist/server/recommendedServiceRoutes.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +124 -11
- package/dist/server/routes.js.map +1 -1
- package/dist/threadline/ThreadlineEndpoints.d.ts +3 -0
- package/dist/threadline/ThreadlineEndpoints.d.ts.map +1 -1
- package/dist/threadline/ThreadlineEndpoints.js +16 -1
- package/dist/threadline/ThreadlineEndpoints.js.map +1 -1
- package/dist/threadline/ThreadlineMCPServer.d.ts +2 -0
- package/dist/threadline/ThreadlineMCPServer.d.ts.map +1 -1
- package/dist/threadline/ThreadlineMCPServer.js +20 -11
- package/dist/threadline/ThreadlineMCPServer.js.map +1 -1
- package/dist/threadline/ThreadlineMcpHttpService.d.ts.map +1 -1
- package/dist/threadline/ThreadlineMcpHttpService.js +8 -0
- package/dist/threadline/ThreadlineMcpHttpService.js.map +1 -1
- package/dist/threadline/agentRelayStatus.d.ts +28 -0
- package/dist/threadline/agentRelayStatus.d.ts.map +1 -0
- package/dist/threadline/agentRelayStatus.js +66 -0
- package/dist/threadline/agentRelayStatus.js.map +1 -0
- package/dist/threadline/mcp-http-client.d.ts.map +1 -1
- package/dist/threadline/mcp-http-client.js +16 -19
- package/dist/threadline/mcp-http-client.js.map +1 -1
- package/dist/threadline/mcp-stdio-entry.js +8 -0
- package/dist/threadline/mcp-stdio-entry.js.map +1 -1
- package/dist/threadline/relayForward.d.ts.map +1 -1
- package/dist/threadline/relayForward.js +3 -1
- package/dist/threadline/relayForward.js.map +1 -1
- package/dist/tunnel/TunnelManager.d.ts.map +1 -1
- package/dist/tunnel/TunnelManager.js +3 -0
- package/dist/tunnel/TunnelManager.js.map +1 -1
- package/dist/users/MemoryAudience.d.ts +2 -0
- package/dist/users/MemoryAudience.d.ts.map +1 -1
- package/dist/users/MemoryAudience.js +5 -0
- package/dist/users/MemoryAudience.js.map +1 -1
- package/dist/users/MemoryInboundTracker.d.ts +16 -0
- package/dist/users/MemoryInboundTracker.d.ts.map +1 -1
- package/dist/users/MemoryInboundTracker.js +36 -0
- package/dist/users/MemoryInboundTracker.js.map +1 -1
- package/dist/users/MemoryPrivacy.d.ts +7 -0
- package/dist/users/MemoryPrivacy.d.ts.map +1 -1
- package/dist/users/MemoryPrivacy.js +15 -0
- package/dist/users/MemoryPrivacy.js.map +1 -1
- package/dist/users/MemoryPrivacyRecovery.d.ts +65 -0
- package/dist/users/MemoryPrivacyRecovery.d.ts.map +1 -0
- package/dist/users/MemoryPrivacyRecovery.js +124 -0
- package/dist/users/MemoryPrivacyRecovery.js.map +1 -0
- package/dist/users/wireMemoryPrivacy.d.ts +6 -0
- package/dist/users/wireMemoryPrivacy.d.ts.map +1 -1
- package/dist/users/wireMemoryPrivacy.js +74 -22
- package/dist/users/wireMemoryPrivacy.js.map +1 -1
- package/package.json +1 -1
- package/scripts/lint-machine-local-justification.js +12 -0
- package/skills/instar-dev/templates/side-effects-artifact.md +6 -0
- package/src/data/builtin-manifest.json +66 -66
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/src/scaffold/templates.ts +5 -4
- package/upgrades/1.3.1661.md +77 -0
- package/upgrades/side-effects/desktop-locked-proof-fixes.md +110 -0
- package/upgrades/side-effects/lease-poll-boot-hold.md +48 -0
- package/upgrades/side-effects/memory-privacy-owner-recovery.md +86 -0
- package/upgrades/side-effects/recommended-services-proof-fixes.md +65 -0
- package/upgrades/side-effects/standby-telegram-replies.md +53 -0
- package/upgrades/side-effects/whole-agent-threadline-status.md +49 -0
package/dashboard/desktop.css
CHANGED
|
@@ -46,6 +46,8 @@ body.desktop-live #localCursor{display:block}
|
|
|
46
46
|
#lockedPassword[hidden],#leaveUnlockedButton[hidden]{display:none}
|
|
47
47
|
#lockedPassword input{width:100%;font-size:16px;padding:.55rem}
|
|
48
48
|
#lockedPassword p{margin:0;font-size:.8rem}
|
|
49
|
+
#lockedPasswordReason{position:absolute;z-index:8;left:max(.5rem,env(safe-area-inset-left));right:max(.5rem,env(safe-area-inset-right));top:max(.5rem,env(safe-area-inset-top));margin:0;padding:.6rem;background:#111827f2;border:1px solid #64748b;border-radius:10px;color:#f1f5f9;font-size:.85rem;pointer-events:none}
|
|
50
|
+
#lockedPasswordReason[hidden]{display:none}
|
|
49
51
|
#leaveUnlockedButton{position:absolute;z-index:8;right:max(.5rem,env(safe-area-inset-right));bottom:4rem;padding:.55rem .8rem}
|
|
50
52
|
#lockedCard{margin-top:.8rem}
|
|
51
53
|
#lockedCard[hidden]{display:none}
|
package/dashboard/desktop.html
CHANGED
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
<button type="submit">Unlock</button>
|
|
96
96
|
<p>The machine serving this page and the tunnel provider can read what you type here. The Instar app is safer.</p>
|
|
97
97
|
</form>
|
|
98
|
+
<p id="lockedPasswordReason" role="status" hidden></p>
|
|
98
99
|
<button id="leaveUnlockedButton" type="button" hidden>Leave unlocked</button>
|
|
99
100
|
<div id="keyboardBar" hidden>
|
|
100
101
|
<label class="type-label" for="typeText">Type on remote desktop</label>
|
package/dashboard/desktop.js
CHANGED
|
@@ -415,11 +415,19 @@ let controlSequence = 0n;
|
|
|
415
415
|
let lockedSealKey = '';
|
|
416
416
|
let lockedScreenState = '';
|
|
417
417
|
let lockedBoxAllowed = false;
|
|
418
|
+
let lockedBoxRefusal = '';
|
|
418
419
|
let secretSequence = 0;
|
|
419
420
|
function syncLockedPassword() {
|
|
420
|
-
const
|
|
421
|
+
const locked = lockedScreenState === 'locked-in-session';
|
|
422
|
+
const show = lockedBoxAllowed && !lockedBoxRefusal && locked && !!lockedSealKey;
|
|
421
423
|
$('lockedPassword').hidden = !show;
|
|
422
424
|
if (!show) $('lockedPasswordInput').value = '';
|
|
425
|
+
// A locked Mac whose box cannot work says why, rather than showing nothing.
|
|
426
|
+
const reason = $('lockedPasswordReason');
|
|
427
|
+
if (reason) {
|
|
428
|
+
reason.hidden = !(locked && lockedBoxRefusal);
|
|
429
|
+
reason.textContent = locked && lockedBoxRefusal ? lockedMessage(lockedBoxRefusal) : '';
|
|
430
|
+
}
|
|
423
431
|
}
|
|
424
432
|
function lockedMessage(reason) {
|
|
425
433
|
return { 'relock-pending': 'This Mac is finishing a relock. Try again in a couple of minutes.',
|
|
@@ -428,7 +436,30 @@ function lockedMessage(reason) {
|
|
|
428
436
|
aborted: 'Stopped before the password finished. Type it again.',
|
|
429
437
|
'field-dirty': 'Clearing the password field. Try again in a moment.',
|
|
430
438
|
'browser-box-off': 'Password entry from a browser is off for this Mac.',
|
|
431
|
-
'tunnel-not-first-tier': 'Password entry is off while the backup connection is in use.'
|
|
439
|
+
'tunnel-not-first-tier': 'Password entry is off while the backup connection is in use.',
|
|
440
|
+
'tunnel-not-active': 'Password entry from a browser is off until this Mac\'s secure tunnel is up. This page updates when it is.',
|
|
441
|
+
'retained-helper-required': 'Password entry needs Instar\'s kept desktop helper on this Mac, and this install does not have one.',
|
|
442
|
+
'own-input-grant-required': 'Password entry needs macOS Accessibility permission for Instar\'s own desktop helper on this Mac.',
|
|
443
|
+
'unsupported-macos': 'Password entry is not available on this Mac\'s macOS version.',
|
|
444
|
+
'helper-unprobed': 'This Mac\'s desktop helper has not answered yet, so password entry is not ready.',
|
|
445
|
+
'shield-not-confirmed': 'This Mac\'s lock screen is not ready for a password right now. Wake the screen and try again.',
|
|
446
|
+
'not-at-the-lock-screen': 'This Mac is not at its lock screen, so the password was not typed.',
|
|
447
|
+
'not-locked': 'This Mac is not locked, so there is nothing to unlock.',
|
|
448
|
+
'not-available': 'Password entry is not available in this session.',
|
|
449
|
+
'grant-ended': 'This remote session has ended. Start a new one to try again.',
|
|
450
|
+
'repeat': 'That password was already sent. Type it again to retry.',
|
|
451
|
+
'too-long': 'That password is too long to type here.',
|
|
452
|
+
'character-not-typable': 'That password has a character this Mac\'s keyboard layout cannot type from here.',
|
|
453
|
+
'state-unavailable': 'This Mac could not read its relock record. Try again in a moment.',
|
|
454
|
+
'relock-not-owed': 'This Mac is not ready for a password in this session. Start a new session.',
|
|
455
|
+
relocking: 'This Mac is relocking now. Try again in a couple of minutes.',
|
|
456
|
+
'relock-pending-unconfirmed': 'This Mac is finishing a relock. Try again in a couple of minutes.',
|
|
457
|
+
'relock-failed': 'This Mac could not confirm its last relock. Check it before trying again.',
|
|
458
|
+
'relock-failed-producer-alive': 'This Mac could not confirm its last relock. Check it before trying again.',
|
|
459
|
+
'guard-not-alive': 'This Mac\'s relock guard is not running, so password entry is paused. Try again shortly.',
|
|
460
|
+
disabled: 'Locked-screen access is turned off on this Mac.',
|
|
461
|
+
busy: 'This Mac is busy with another password. Try again in a moment.',
|
|
462
|
+
'state-unknown': 'This Mac\'s lock state is unclear right now. Try again in a moment.' }[reason]
|
|
432
463
|
?? 'This Mac did not accept that. Try again.';
|
|
433
464
|
}
|
|
434
465
|
async function receiveControl(record) {
|
|
@@ -440,7 +471,11 @@ async function receiveControl(record) {
|
|
|
440
471
|
controlSequence = sequence;
|
|
441
472
|
const value = JSON.parse(new TextDecoder().decode(plain));
|
|
442
473
|
if (value.type === 'seal') lockedSealKey = value.key;
|
|
443
|
-
if (value.type === 'state') {
|
|
474
|
+
if (value.type === 'state') {
|
|
475
|
+
lockedScreenState = value.state;
|
|
476
|
+
lockedBoxAllowed = value.box === true;
|
|
477
|
+
lockedBoxRefusal = typeof value.boxRefusal === 'string' ? value.boxRefusal : '';
|
|
478
|
+
}
|
|
444
479
|
if (value.type === 'secret-result' && value.refused) status(lockedMessage(value.refused));
|
|
445
480
|
if (value.type === 'secret-result' && value.sent) { $('leaveUnlockedButton').hidden = false; }
|
|
446
481
|
if (value.type === 'relock') status(value.phase === 'left-unlocked' ? 'This Mac will stay unlocked.' : 'Relocking has begun.');
|
|
@@ -934,6 +969,7 @@ async function openStream(result, resume = null) {
|
|
|
934
969
|
socket.binaryType = 'arraybuffer';
|
|
935
970
|
controlSequence = 0n;
|
|
936
971
|
lockedSealKey = '';
|
|
972
|
+
lockedBoxRefusal = '';
|
|
937
973
|
secretSequence = 0;
|
|
938
974
|
syncLockedPassword();
|
|
939
975
|
return new Promise((resolve, reject) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/server.js
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { configureClaudeChildAuth, sweepClaudeAuthEnvFiles } from '../core/claudeChildAuth.js';
|
|
7
7
|
import { SlackPrincipalResolver } from '../permissions/SlackPrincipalResolver.js';
|
|
8
|
-
import {
|
|
9
|
-
import { whatsappPersonKey } from '../users/MemoryAudience.js';
|
|
8
|
+
import { whatsappPersonKey, whatsappSpeakerJid } from '../users/MemoryAudience.js';
|
|
10
9
|
import { slackHistoryLabel } from '../messaging/slack/threadHistoryLabel.js';
|
|
11
10
|
import { readPairingOwnerName } from '../threadline/pairingOwnerName.js';
|
|
12
11
|
import { buildThrowawayJobGuard, checkThrowawayExpiry, describeExpiry, takeLastAutoStartRefusal, throwawayStartupDecision } from '../core/ThrowawayAgentGuard.js';
|
|
@@ -58,6 +57,7 @@ import { setAspClassifierRef, getAspClassifierRef } from '../core/aspClassifierR
|
|
|
58
57
|
import { resolveInboundTelegramMessageId, resolveSignedByAgent, operatorAutoBindPermitted } from '../messaging/shared/signedInbound.js';
|
|
59
58
|
import { verifiedEntityName } from '../messaging/shared/channelIdentity.js';
|
|
60
59
|
import { StandDownRegistry } from '../core/StandDownRegistry.js';
|
|
60
|
+
import { ensureDashboardPin, persistDashboardPin, pickDashboardPin } from '../core/dashboardPin.js';
|
|
61
61
|
import { getActiveOverloadShedPlanner, getMoveAftercare } from '../core/OverloadShedPlanner.js';
|
|
62
62
|
import { QuietTopicScanner } from '../core/quietTopicScanner.js';
|
|
63
63
|
import { RebalanceProofRunner, getActiveRebalanceProof, waitForSettledIdle, proofSpawnBrief, setActiveRebalanceProof, setActiveRebalanceProofStore } from '../core/rebalanceProof.js';
|
|
@@ -426,9 +426,11 @@ async function handleFixCommand(topicId, text, deps) {
|
|
|
426
426
|
return true;
|
|
427
427
|
}
|
|
428
428
|
if (cmd === 'fix dashboard') {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
429
|
+
// A vault-backed config holds {secret:true}; resolve it rather than print an object.
|
|
430
|
+
const stored = deps.liveConfig.get('dashboardPin', '');
|
|
431
|
+
if (stored) {
|
|
432
|
+
const existing = pickDashboardPin(stored, deps.config.stateDir);
|
|
433
|
+
await send(existing ? `Your dashboard already has a PIN: ${existing}` : 'Your dashboard already has a PIN, kept in its secret store.');
|
|
432
434
|
return true;
|
|
433
435
|
}
|
|
434
436
|
const pin = String(randomInt(100000, 1000000));
|
|
@@ -642,6 +644,8 @@ let _topicProfileCtxRef = null;
|
|
|
642
644
|
let _inboundQueue = null;
|
|
643
645
|
/** Memory privacy (docs/specs/memory-privacy.md): set in startServer, read at every inbound. */
|
|
644
646
|
let _memoryInbound = null;
|
|
647
|
+
/** The tunnel's address for a path, once a tunnel exists. The tunnel starts after memory privacy. */
|
|
648
|
+
let _memoryLinkFor = null;
|
|
645
649
|
function telegramConfiguredForMemory(config) {
|
|
646
650
|
return (config.messaging ?? []).some((m) => m.type === 'telegram');
|
|
647
651
|
}
|
|
@@ -2362,16 +2366,22 @@ getHubClassifierDeps) {
|
|
|
2362
2366
|
: null;
|
|
2363
2367
|
// Memory privacy: record who spoke and re-check the group's readers BEFORE routing.
|
|
2364
2368
|
if (_memoryInbound) {
|
|
2365
|
-
const
|
|
2369
|
+
const memoryFacts = {
|
|
2366
2370
|
placeKey: telegram.memoryPlaceKey,
|
|
2367
2371
|
placeKind: 'shared',
|
|
2368
2372
|
senderKey: resolvedUser ? `user:${resolvedUser.id}` : telegramUserId ? `telegram:${telegramUserId}` : null,
|
|
2369
2373
|
personId: resolvedUser?.id ?? null,
|
|
2370
2374
|
readerCount: () => telegram.groupReaderCount(),
|
|
2371
2375
|
liveSession: () => telegram.getSessionForTopic(topicId),
|
|
2372
|
-
}
|
|
2376
|
+
};
|
|
2377
|
+
const verdict = await _memoryInbound.onInbound(memoryFacts);
|
|
2373
2378
|
if (verdict === 'unavailable') {
|
|
2374
|
-
await telegram.sendToTopic(topicId,
|
|
2379
|
+
await telegram.sendToTopic(topicId, await _memoryInbound.refuse(memoryFacts, async (text) => {
|
|
2380
|
+
// This DM has one fixed recipient, so it goes only when that is who asked.
|
|
2381
|
+
if (!telegramUserId || telegram.getOwnerUserId() !== telegramUserId)
|
|
2382
|
+
return false;
|
|
2383
|
+
return (await telegram.sendToOwnerDM(text)) !== null;
|
|
2384
|
+
}));
|
|
2375
2385
|
return;
|
|
2376
2386
|
}
|
|
2377
2387
|
}
|
|
@@ -3268,17 +3278,23 @@ getHubClassifierDeps) {
|
|
|
3268
3278
|
async function whatsappMemoryCheck(whatsapp, jid, metadata) {
|
|
3269
3279
|
if (!_memoryInbound)
|
|
3270
3280
|
return true;
|
|
3271
|
-
const
|
|
3272
|
-
const
|
|
3281
|
+
const senderJid = whatsappSpeakerJid(metadata, jid);
|
|
3282
|
+
const profile = _memoryUserResolver?.channel('whatsapp', senderJid) ?? null;
|
|
3283
|
+
const memoryFacts = {
|
|
3273
3284
|
placeKey: `whatsapp:${jid}`,
|
|
3274
3285
|
placeKind: jid.endsWith('@g.us') ? 'shared' : 'private',
|
|
3275
|
-
senderKey: profile ? `user:${profile.id}` : whatsappPersonKey(
|
|
3286
|
+
senderKey: profile ? `user:${profile.id}` : whatsappPersonKey(senderJid),
|
|
3276
3287
|
personId: profile?.id ?? null,
|
|
3277
3288
|
liveSession: () => whatsapp.getSessionForChannel(jid),
|
|
3278
|
-
}
|
|
3289
|
+
};
|
|
3290
|
+
const verdict = await _memoryInbound.onInbound(memoryFacts);
|
|
3279
3291
|
if (verdict === 'deliver')
|
|
3280
3292
|
return true;
|
|
3281
|
-
await
|
|
3293
|
+
const content = await _memoryInbound.refuse(memoryFacts, async (text) => {
|
|
3294
|
+
await whatsapp.send({ userId: senderJid, content: text, channel: { type: 'whatsapp', identifier: senderJid } });
|
|
3295
|
+
return true;
|
|
3296
|
+
});
|
|
3297
|
+
await whatsapp.send({ userId: jid, content, channel: { type: 'whatsapp', identifier: jid } });
|
|
3282
3298
|
return false;
|
|
3283
3299
|
}
|
|
3284
3300
|
/**
|
|
@@ -3446,16 +3462,17 @@ function wireIMessageRouting(imessage, sessionManager) {
|
|
|
3446
3462
|
// with imsg, which the sandbox cannot give, so a scoped session is refused here.
|
|
3447
3463
|
if (_memoryInbound) {
|
|
3448
3464
|
const imProfile = _memoryUserResolver?.channel('imessage', sender) ?? null;
|
|
3449
|
-
const
|
|
3465
|
+
const memoryFacts = {
|
|
3450
3466
|
placeKey: `imessage:${senderNorm}`,
|
|
3451
3467
|
placeKind: 'private',
|
|
3452
3468
|
senderKey: imProfile ? `user:${imProfile.id}` : `imessage:${sender}`,
|
|
3453
3469
|
personId: imProfile?.id ?? null,
|
|
3454
3470
|
scopedUnsupported: true,
|
|
3455
3471
|
liveSession: () => imessage.getSessionForSender(sender),
|
|
3456
|
-
}
|
|
3472
|
+
};
|
|
3473
|
+
const verdict = await _memoryInbound.onInbound(memoryFacts);
|
|
3457
3474
|
if (verdict === 'unavailable') {
|
|
3458
|
-
await imessage.send({ userId: sender, content:
|
|
3475
|
+
await imessage.send({ userId: sender, content: await _memoryInbound.refuse(memoryFacts), channel: { type: 'imessage', identifier: sender } });
|
|
3459
3476
|
return;
|
|
3460
3477
|
}
|
|
3461
3478
|
}
|
|
@@ -6511,6 +6528,7 @@ export async function startServer(options) {
|
|
|
6511
6528
|
projectName: config.projectName,
|
|
6512
6529
|
framework: () => sessionManagerConfig.framework ?? 'claude-code',
|
|
6513
6530
|
claudePath: sessionManagerConfig.frameworkBinaryPaths?.['claude-code'] ?? sessionManagerConfig.claudePath,
|
|
6531
|
+
linkFor: (urlPath) => _memoryLinkFor?.(urlPath) ?? null,
|
|
6514
6532
|
memoryPrivacy: () => config.memoryPrivacy,
|
|
6515
6533
|
messaging: () => (config.messaging ?? []),
|
|
6516
6534
|
initialUsers: config.users,
|
|
@@ -9585,16 +9603,21 @@ export async function startServer(options) {
|
|
|
9585
9603
|
// a channel or thread is shared, and a thread's audience is its channel's.
|
|
9586
9604
|
if (_memoryInbound) {
|
|
9587
9605
|
const slackProfile = slackUserId ? _memoryUserResolver?.slack(slackUserId) ?? null : null;
|
|
9588
|
-
const
|
|
9606
|
+
const memoryFacts = {
|
|
9589
9607
|
placeKey: `slack:${channelId}`,
|
|
9590
9608
|
placeKind: channelId.startsWith('D') ? 'private' : 'shared',
|
|
9591
9609
|
senderKey: slackProfile ? `user:${slackProfile.id}` : slackUserId ? `slack:${slackUserId}` : null,
|
|
9592
9610
|
personId: slackProfile?.id ?? null,
|
|
9593
9611
|
readerCount: () => slackAdapter.channelReaderCount(channelId),
|
|
9594
9612
|
liveSession: () => slackAdapter.getSessionForChannel(routingKey),
|
|
9595
|
-
}
|
|
9613
|
+
};
|
|
9614
|
+
const verdict = await _memoryInbound.onInbound(memoryFacts);
|
|
9596
9615
|
if (verdict === 'unavailable') {
|
|
9597
|
-
|
|
9616
|
+
// Posting to a user id opens the app's direct message with them.
|
|
9617
|
+
const reply = await _memoryInbound.refuse(memoryFacts, slackUserId
|
|
9618
|
+
? async (text) => { await slackAdapter.sendToChannel(slackUserId, text); return true; }
|
|
9619
|
+
: undefined);
|
|
9620
|
+
await slackAdapter.sendToChannel(channelId, reply, replyThreadTs ? { thread_ts: replyThreadTs } : undefined);
|
|
9598
9621
|
return 'refused';
|
|
9599
9622
|
}
|
|
9600
9623
|
}
|
|
@@ -13132,6 +13155,7 @@ export async function startServer(options) {
|
|
|
13132
13155
|
if (!config.tunnel) {
|
|
13133
13156
|
liveConfig.set('tunnel', { enabled: true, type: 'quick' });
|
|
13134
13157
|
}
|
|
13158
|
+
_memoryLinkFor = (urlPath) => tunnel?.getExternalUrl(urlPath) ?? null;
|
|
13135
13159
|
tunnel = new TunnelManager({
|
|
13136
13160
|
enabled: true,
|
|
13137
13161
|
type: config.tunnel?.type || 'quick',
|
|
@@ -29035,8 +29059,8 @@ export async function startServer(options) {
|
|
|
29035
29059
|
const result = reply.result;
|
|
29036
29060
|
if (reply.ok && result?.ok && result.operationId === operationId) {
|
|
29037
29061
|
const state = String(result.state);
|
|
29038
|
-
if (state === 'accepted' && result.originReceiptConfirmed === true)
|
|
29039
|
-
return { state: 'accepted', receiptJson: JSON.stringify({ confirmedVia: 'receipt', deliveryMachineId: machineId, operationId }) };
|
|
29062
|
+
if (state === 'accepted' && result.originReceiptConfirmed === true && result.messageIds?.length === 1 && /^[1-9]\d*$/.test(result.messageIds[0]))
|
|
29063
|
+
return { state: 'accepted', receiptJson: JSON.stringify({ messageId: result.messageIds[0], confirmedVia: 'receipt', deliveryMachineId: machineId, operationId }) };
|
|
29040
29064
|
// Definite non-admission: never seen, evidence only, or terminal without delivery.
|
|
29041
29065
|
if (['no-record', 'not-admitted', 'known-failed', 'expired', 'suppressed', 'superseded'].includes(state))
|
|
29042
29066
|
return { state: 'not-accepted' };
|
|
@@ -29057,7 +29081,7 @@ export async function startServer(options) {
|
|
|
29057
29081
|
},
|
|
29058
29082
|
resolve: (operationId, deliveryMachineId, receiptJson) => runtime.store.recordForwardedAcceptance({ operationId, deliveryMachineId, receiptJson }),
|
|
29059
29083
|
settleUnknown: (operationId, deliveryMachineId) => runtime.store.recordForwardedOutcomeUnknown({ operationId, deliveryMachineId }),
|
|
29060
|
-
rehold: async (operationId, detail) =>
|
|
29084
|
+
rehold: async (operationId, detail) => runtime.store.recordOperationState({ operationId, state: 'held', holdReason: originForwardMod.HOLD_REASON_LEASE_NOT_HELD, holdDetail: detail }),
|
|
29061
29085
|
supersede: (operationId, next, detail) => runtime.store.supersedeWithAdmission({ operationId, admission: next.admission,
|
|
29062
29086
|
holdReason: originForwardMod.HOLD_REASON_LEASE_NOT_HELD, holdDetail: detail }),
|
|
29063
29087
|
sendLocal: async (detail) => {
|
|
@@ -29066,6 +29090,14 @@ export async function startServer(options) {
|
|
|
29066
29090
|
},
|
|
29067
29091
|
}, row, operation);
|
|
29068
29092
|
// §3.3 — a delivered/resolved forward may have emptied the topic's held set.
|
|
29093
|
+
if (outcome === 'sent' || outcome === 'resolved') {
|
|
29094
|
+
// The original adapter call returned HELD, so it never wrote its
|
|
29095
|
+
// outbound topic row. Only a durable receipt with a concrete
|
|
29096
|
+
// Telegram id may fill that gap; this never sends a second copy.
|
|
29097
|
+
const recovered = await originForwardMod.confirmedRecoveredForward(row, id => runtime.store.getOperation(id)).catch(() => null);
|
|
29098
|
+
if (recovered)
|
|
29099
|
+
telegram.recordRecoveredOutbound(recovered.topicId, recovered.text, recovered.messageId, row.producerKind === 'session' ? 'agent' : 'automation');
|
|
29100
|
+
}
|
|
29069
29101
|
if (outcome === 'sent' || outcome === 'resolved' || outcome === 'settled')
|
|
29070
29102
|
await clearHeldItemIfResolved(row.destination.topicId);
|
|
29071
29103
|
return outcome;
|
|
@@ -31684,6 +31716,16 @@ export async function startServer(options) {
|
|
|
31684
31716
|
advertiseSelfMeshUrl(coordinator.managers.identityManager, coordinator.identity.machineId, cfUrl, (m) => console.log(pc.dim(m)));
|
|
31685
31717
|
await advertiseSelfMeshEndpointsNow(coordinator.managers.identityManager, coordinator.identity.machineId, config, cfUrl);
|
|
31686
31718
|
}
|
|
31719
|
+
// Every agent gets a dashboard PIN, with or without Telegram: the PIN
|
|
31720
|
+
// gates every dashboard operator route, and an agent must work without
|
|
31721
|
+
// Telegram. An existing PIN (or an unresolved vault reference) is kept.
|
|
31722
|
+
// Runs before the Telegram dashboard broadcast below, which reads config.dashboardPin.
|
|
31723
|
+
const pinStore = { at: 'config' };
|
|
31724
|
+
if (ensureDashboardPin(config, pin => {
|
|
31725
|
+
pinStore.at = persistDashboardPin(config.stateDir, pin, value => liveConfig.set('dashboardPin', value));
|
|
31726
|
+
}).generated) {
|
|
31727
|
+
console.log(pc.green(` Auto-generated a dashboard PIN (stored in this agent's ${pinStore.at === 'vault' ? 'secret store' : 'config'})`));
|
|
31728
|
+
}
|
|
31687
31729
|
// ── Dashboard Topic: always-available link ──────────────────────────
|
|
31688
31730
|
// Retroactive: creates the topic on first run for existing agents.
|
|
31689
31731
|
// Posts tunnel URL + PIN and pins the message for instant access.
|
|
@@ -31692,16 +31734,6 @@ export async function startServer(options) {
|
|
|
31692
31734
|
const dashTopicId = await telegram.ensureDashboardTopic();
|
|
31693
31735
|
if (dashTopicId) {
|
|
31694
31736
|
console.log(pc.green(` Dashboard topic: ${dashTopicId}`));
|
|
31695
|
-
// Auto-generate dashboardPin if missing — do this on every startup,
|
|
31696
|
-
// not just during upgrades. The PIN should always exist.
|
|
31697
|
-
if (!config.dashboardPin) {
|
|
31698
|
-
const { randomInt } = await import('node:crypto');
|
|
31699
|
-
const pin = String(randomInt(100000, 1000000)); // 6-digit
|
|
31700
|
-
config.dashboardPin = pin;
|
|
31701
|
-
// Persist via LiveConfig so it survives restart
|
|
31702
|
-
liveConfig.set('dashboardPin', pin);
|
|
31703
|
-
console.log(pc.green(` Auto-generated dashboard PIN: ${pin}`));
|
|
31704
|
-
}
|
|
31705
31737
|
// Wire the tunnel's two-channel notifier to telegram now that
|
|
31706
31738
|
// both telegram + Dashboard topic exist. Per
|
|
31707
31739
|
// specs/dev-infrastructure/tunnel-failure-resilience.md Part 3:
|
|
@@ -31711,8 +31743,9 @@ export async function startServer(options) {
|
|
|
31711
31743
|
// at compose time so the notifier never holds stale credentials.
|
|
31712
31744
|
if (tunnel) {
|
|
31713
31745
|
tunnel.attachTelegram(telegram, () => {
|
|
31714
|
-
|
|
31715
|
-
return
|
|
31746
|
+
// A vault-backed config holds {secret:true}; resolve it to the real PIN.
|
|
31747
|
+
return pickDashboardPin(liveConfig.get('dashboardPin', ''), config.stateDir)
|
|
31748
|
+
?? pickDashboardPin(config.dashboardPin, config.stateDir) ?? '';
|
|
31716
31749
|
});
|
|
31717
31750
|
}
|
|
31718
31751
|
// Only broadcast if we have a tunnel URL — posting localhost to Telegram
|