instar 1.3.731 → 1.3.733
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +208 -2
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +26 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/ConversationRegistry.d.ts +355 -0
- package/dist/core/ConversationRegistry.d.ts.map +1 -0
- package/dist/core/ConversationRegistry.js +1438 -0
- package/dist/core/ConversationRegistry.js.map +1 -0
- package/dist/core/PostUpdateMigrator.d.ts +12 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +80 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts +15 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +28 -0
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/conversationBindToken.d.ts +36 -0
- package/dist/core/conversationBindToken.d.ts.map +1 -0
- package/dist/core/conversationBindToken.js +144 -0
- package/dist/core/conversationBindToken.js.map +1 -0
- package/dist/core/conversationIdentity.d.ts +126 -0
- package/dist/core/conversationIdentity.d.ts.map +1 -0
- package/dist/core/conversationIdentity.js +160 -0
- package/dist/core/conversationIdentity.js.map +1 -0
- package/dist/core/deliverToConversation.d.ts +105 -0
- package/dist/core/deliverToConversation.d.ts.map +1 -0
- package/dist/core/deliverToConversation.js +374 -0
- package/dist/core/deliverToConversation.js.map +1 -0
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/slackRefreshBinding.d.ts +8 -10
- package/dist/core/slackRefreshBinding.d.ts.map +1 -1
- package/dist/core/slackRefreshBinding.js +8 -16
- package/dist/core/slackRefreshBinding.js.map +1 -1
- package/dist/core/types.d.ts +46 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/CommitmentTracker.d.ts +64 -0
- package/dist/monitoring/CommitmentTracker.d.ts.map +1 -1
- package/dist/monitoring/CommitmentTracker.js +58 -0
- package/dist/monitoring/CommitmentTracker.js.map +1 -1
- package/dist/monitoring/PromiseBeacon.d.ts +70 -0
- package/dist/monitoring/PromiseBeacon.d.ts.map +1 -1
- package/dist/monitoring/PromiseBeacon.js +221 -24
- package/dist/monitoring/PromiseBeacon.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +10 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +12 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +20 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +14 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +17 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +206 -10
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +65 -65
- package/src/scaffold/templates.ts +10 -0
- package/upgrades/1.3.732.md +107 -0
- package/upgrades/1.3.733.md +108 -0
- package/upgrades/side-effects/durable-conversation-identity-increment1.md +89 -0
- package/upgrades/side-effects/durable-conversation-identity-increment2.md +88 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiDH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAyBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA6H7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAu/CD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GACpD,IAAI,CAijBN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAu/kBtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -29,6 +29,7 @@ import { resolveDevAgentGate, resolveStateSyncStores } from '../core/devAgentGat
|
|
|
29
29
|
import { resolveAntiThrashKnobs, readingValidity } from '../core/SwapAntiThrash.js';
|
|
30
30
|
import { shouldReleaseOnComplete, planClaimOnSpawn, ownershipNonce } from '../core/ownershipFollowsLiveWork.js';
|
|
31
31
|
import { PrHandLease } from '../core/PrHandLease.js';
|
|
32
|
+
import { ConversationRegistry } from '../core/ConversationRegistry.js';
|
|
32
33
|
import { claimSuspensionExcludesPin } from '../core/TopicClaimAnnotationStore.js';
|
|
33
34
|
import { parseProfileTrigger, platformMessageIdFrom } from '../core/topicProfileIngress.js';
|
|
34
35
|
import { slugifyChannelName } from '../messaging/slack/sanitize.js';
|
|
@@ -4959,8 +4960,21 @@ export async function startServer(options) {
|
|
|
4959
4960
|
// knows whether to reroute a `claude -p` one-shot onto the interactive
|
|
4960
4961
|
// (subscription) lane. Absent/'off' ⇒ today's behavior, byte-for-byte.
|
|
4961
4962
|
const subscriptionPathCfg = config.intelligence?.subscriptionPath;
|
|
4963
|
+
// ── durable-conversation-identity §7 bind-time authority (increment 2) ──
|
|
4964
|
+
// Constructed HERE (before SessionManager) so the spawn env can carry the
|
|
4965
|
+
// per-session bind token. One shared secret backs both the spawn-side mint
|
|
4966
|
+
// and the POST /commitments verify (below). Deploy stamp is written once,
|
|
4967
|
+
// first-boot, to anchor the R7-minor-2 straggler grace clock.
|
|
4968
|
+
const { createConversationBindAuth: _createConversationBindAuth, ensureBindDeployStamp: _ensureBindDeployStamp } = await import('../core/conversationBindToken.js');
|
|
4969
|
+
const conversationBindAuth = _createConversationBindAuth(config.stateDir);
|
|
4970
|
+
try {
|
|
4971
|
+
_ensureBindDeployStamp(config.stateDir, startupVersion);
|
|
4972
|
+
}
|
|
4973
|
+
catch { /* @silent-fallback-ok — the stamp only arms the fail-open straggler backstop */ }
|
|
4962
4974
|
const sessionManagerConfig = {
|
|
4963
4975
|
...config.sessions,
|
|
4976
|
+
// §7: mint the per-session bind token into INSTAR_BIND_TOKEN at spawn.
|
|
4977
|
+
mintBindToken: (sessionName, bootstrapConversationIds) => conversationBindAuth.mint(sessionName, bootstrapConversationIds),
|
|
4964
4978
|
...(codexThreadlineMcp ? { codexThreadlineMcp } : {}),
|
|
4965
4979
|
respawnBuildContext: {
|
|
4966
4980
|
...(config.sessions.respawnBuildContext ?? {}),
|
|
@@ -6659,6 +6673,112 @@ export async function startServer(options) {
|
|
|
6659
6673
|
}
|
|
6660
6674
|
// ── Slack adapter initialization ─────────────────────────────────
|
|
6661
6675
|
let slackAdapter;
|
|
6676
|
+
// ── Durable conversation identity (durable-conversation-identity §3/§6.3) ──
|
|
6677
|
+
// ALWAYS constructed (the foundation is always-on once shipped — only
|
|
6678
|
+
// DELIVERY is dev-gated), so GET /conversations/health answers 200 even on a
|
|
6679
|
+
// Telegram-only agent (an empty, healthy registry). getLocalWorkspaceId is
|
|
6680
|
+
// late-bound over the adapter declared above; the D1 kill-switch + fsync
|
|
6681
|
+
// escape hatch are read LIVE at the chokepoint (no restart to apply).
|
|
6682
|
+
const conversationRegistry = new ConversationRegistry({
|
|
6683
|
+
stateDir: config.stateDir,
|
|
6684
|
+
machineId: () => _meshSelfId ?? os.hostname(),
|
|
6685
|
+
isRecordingEnabled: () => config.conversationIdentity?.recording?.enabled !== false,
|
|
6686
|
+
isJournalFsyncDisabled: () => config.conversationIdentity?.recording?.disableJournalFsync === true,
|
|
6687
|
+
getLocalWorkspaceId: () => slackAdapter?.getWorkspaceId(),
|
|
6688
|
+
getConfigWorkspacePin: () => config.conversationIdentity?.workspacePin,
|
|
6689
|
+
breaker: config.conversationIdentity?.mintBreaker,
|
|
6690
|
+
onAttention: (dedupeKey, title, body) => {
|
|
6691
|
+
try {
|
|
6692
|
+
_meshAttentionRaise?.({ id: dedupeKey, title, body, priority: 'medium', sourceContext: 'conversation-identity' });
|
|
6693
|
+
}
|
|
6694
|
+
catch { /* @silent-fallback-ok — attention is observability; a failed raise never gates identity or delivery */ }
|
|
6695
|
+
},
|
|
6696
|
+
log: (line) => console.log(pc.dim(` ${line}`)),
|
|
6697
|
+
});
|
|
6698
|
+
try {
|
|
6699
|
+
conversationRegistry.load();
|
|
6700
|
+
}
|
|
6701
|
+
catch (err) {
|
|
6702
|
+
// @silent-fallback-ok — fail toward delivery (§3.6): a broken registry boot
|
|
6703
|
+
// must never take the server down; mints degrade to in-memory candidates
|
|
6704
|
+
// (behavior-identical to legacy hashing) until healed, and the failure is
|
|
6705
|
+
// logged loudly here.
|
|
6706
|
+
console.warn(` [conversation-registry] boot load failed (degraded to in-memory candidates): ${err instanceof Error ? err.message : String(err)}`);
|
|
6707
|
+
}
|
|
6708
|
+
// ── durable-conversation-identity §5 funnel + §6.1 step-2 wiring (increment 2) ──
|
|
6709
|
+
// followThrough gate: dark-on-fleet / live-on-dev via the developmentAgent
|
|
6710
|
+
// gate (config OMITS `enabled` → resolveDevAgentGate resolves it), dryRun
|
|
6711
|
+
// TRUE first (delivery is externally visible — spec §9). The Telegram lane
|
|
6712
|
+
// (`id>0`) is byte-identical regardless.
|
|
6713
|
+
const conversationFollowThrough = () => {
|
|
6714
|
+
const ft = config
|
|
6715
|
+
.conversationIdentity?.followThrough;
|
|
6716
|
+
return {
|
|
6717
|
+
enabled: resolveDevAgentGate(ft?.enabled, config),
|
|
6718
|
+
dryRun: ft?.dryRun !== false,
|
|
6719
|
+
};
|
|
6720
|
+
};
|
|
6721
|
+
const { createConversationDelivery: _createConversationDelivery } = await import('../core/deliverToConversation.js');
|
|
6722
|
+
const deliverToConversation = _createConversationDelivery({
|
|
6723
|
+
registry: conversationRegistry,
|
|
6724
|
+
followThrough: conversationFollowThrough,
|
|
6725
|
+
// id>0 → today's Telegram path via the existing /telegram/reply route
|
|
6726
|
+
// (queue/dedup/tone-gate untouched).
|
|
6727
|
+
sendTelegram: async (topicId, text, opts) => {
|
|
6728
|
+
const url = `http://localhost:${config.port}/telegram/reply/${topicId}`;
|
|
6729
|
+
const response = await fetch(url, {
|
|
6730
|
+
method: 'POST',
|
|
6731
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.authToken}` },
|
|
6732
|
+
body: JSON.stringify({
|
|
6733
|
+
text,
|
|
6734
|
+
metadata: { source: opts?.source ?? 'conversation-funnel', isProxy: opts?.isProxy, tier: opts?.tier, allowDuplicate: opts?.allowDuplicate },
|
|
6735
|
+
}),
|
|
6736
|
+
});
|
|
6737
|
+
return response.ok;
|
|
6738
|
+
},
|
|
6739
|
+
// id<0 → the local Slack adapter (channel + thread_ts). Late-bound over
|
|
6740
|
+
// _slackAdapter (declared below); undefined here means no local Slack
|
|
6741
|
+
// adapter → the funnel returns a typed non-delivery (§5.0 ownership).
|
|
6742
|
+
sendSlack: async (channelId, text, threadTs) => {
|
|
6743
|
+
if (!_slackAdapter)
|
|
6744
|
+
throw new Error('no local Slack adapter');
|
|
6745
|
+
await _slackAdapter.sendToChannel(channelId, text, threadTs ? { thread_ts: threadTs } : undefined);
|
|
6746
|
+
},
|
|
6747
|
+
isSystemChannel: (channelId) => _slackAdapter?.isSystemChannel(channelId) ?? false,
|
|
6748
|
+
auditWouldDeliver: (line) => console.log(pc.dim(` ${line}`)),
|
|
6749
|
+
onAttention: (dedupeKey, title, body) => {
|
|
6750
|
+
try {
|
|
6751
|
+
_meshAttentionRaise?.({ id: dedupeKey, title, body, priority: 'medium', sourceContext: 'conversation-identity' });
|
|
6752
|
+
}
|
|
6753
|
+
catch { /* @silent-fallback-ok — attention is observability; never gates delivery */ }
|
|
6754
|
+
},
|
|
6755
|
+
log: (line) => console.log(pc.dim(` ${line}`)),
|
|
6756
|
+
});
|
|
6757
|
+
// §6.1 step 2 — the ConversationBinder the CommitmentTracker uses for a
|
|
6758
|
+
// durable bind on a MINTED id: durable-binding-forced registration (WAL
|
|
6759
|
+
// fsynced) + the §3.5.2 bind-pin, handing back the bind-time tuple.
|
|
6760
|
+
const conversationBinder = {
|
|
6761
|
+
bind: (conversationId) => {
|
|
6762
|
+
const resolved = conversationRegistry.resolve(conversationId);
|
|
6763
|
+
if (!resolved || resolved.platform !== 'slack') {
|
|
6764
|
+
return { ok: false, error: 'conversation-bind-unresolvable' };
|
|
6765
|
+
}
|
|
6766
|
+
const routingKey = resolved.threadTs ? `${resolved.channelId}:${resolved.threadTs}` : resolved.channelId;
|
|
6767
|
+
const mint = conversationRegistry.mintForDurableBinding(routingKey);
|
|
6768
|
+
if (!mint.ok)
|
|
6769
|
+
return { ok: false, error: mint.error };
|
|
6770
|
+
const tuple = conversationRegistry.bindPin(mint.id);
|
|
6771
|
+
if (!tuple)
|
|
6772
|
+
return { ok: false, error: 'conversation-bind-unresolvable' };
|
|
6773
|
+
return { ok: true, boundTuple: { platform: 'slack', channelId: tuple.channelId, threadTs: tuple.threadTs } };
|
|
6774
|
+
},
|
|
6775
|
+
release: (conversationId) => {
|
|
6776
|
+
try {
|
|
6777
|
+
conversationRegistry.bindRelease(conversationId);
|
|
6778
|
+
}
|
|
6779
|
+
catch { /* @silent-fallback-ok — a failed release leaks one refcount (harmless R6-low-4 orphan) */ }
|
|
6780
|
+
},
|
|
6781
|
+
};
|
|
6662
6782
|
const slackConfig = config.messaging?.find(m => m.type === 'slack' && m.enabled);
|
|
6663
6783
|
if (slackConfig) {
|
|
6664
6784
|
try {
|
|
@@ -6886,6 +7006,21 @@ export async function startServer(options) {
|
|
|
6886
7006
|
const isThreadSession = slackAdapter.isThreadRoutingKey(routingKey);
|
|
6887
7007
|
// The thread_ts to thread replies under (only when this is a thread session).
|
|
6888
7008
|
const replyThreadTs = isThreadSession ? threadTs : undefined;
|
|
7009
|
+
// ── §6.3 eager mint (durable-conversation-identity) ────────────────
|
|
7010
|
+
// Get-or-create the durable conversation id for the RESOLVED routing
|
|
7011
|
+
// key on EVERY inbound (one cached registry read after the first).
|
|
7012
|
+
// Carried under the PINNED field key `conversationId` in message
|
|
7013
|
+
// metadata + the session bootstrap context so the session can attach
|
|
7014
|
+
// durable state to it. Fail toward delivery (§3.6): a mint
|
|
7015
|
+
// degradation ("no durable id") never blocks the message.
|
|
7016
|
+
let conversationId = null;
|
|
7017
|
+
try {
|
|
7018
|
+
conversationId = conversationRegistry.mintForInbound(routingKey).id;
|
|
7019
|
+
if (conversationId !== null && message.metadata) {
|
|
7020
|
+
message.metadata.conversationId = conversationId;
|
|
7021
|
+
}
|
|
7022
|
+
}
|
|
7023
|
+
catch { /* @silent-fallback-ok — identity never costs a message (§3.6 fail-toward-delivery): the inbound proceeds without a durable id and re-mints later */ }
|
|
6889
7024
|
// Build injection tag with sender info (matches Telegram's buildInjectionTag pattern)
|
|
6890
7025
|
const slackUserId = message.metadata?.slackUserId;
|
|
6891
7026
|
// Sanitize sender name at injection boundary (prevents injection attacks)
|
|
@@ -6946,6 +7081,13 @@ export async function startServer(options) {
|
|
|
6946
7081
|
contextLines.push('');
|
|
6947
7082
|
contextLines.push('Strip the [slack:] prefix before interpreting the message.');
|
|
6948
7083
|
contextLines.push('Only relay conversational text — not tool output, file contents, or internal reasoning.');
|
|
7084
|
+
if (conversationId !== null) {
|
|
7085
|
+
// §6.3: the durable conversation id rides the session bootstrap
|
|
7086
|
+
// context (pinned metadata key `conversationId`; the prompt phrasing
|
|
7087
|
+
// below is build-time cheap-to-change).
|
|
7088
|
+
contextLines.push('');
|
|
7089
|
+
contextLines.push(`Conversation id: ${conversationId} — the durable identity of THIS Slack conversation. Use it as the topicId when opening durable state (e.g. POST /commitments) for this conversation.`);
|
|
7090
|
+
}
|
|
6949
7091
|
const contextData = contextLines.join('\n');
|
|
6950
7092
|
// Also write to file as backup reference
|
|
6951
7093
|
const ctxPath = path.join(tmpDir, `ctx-${channelId}-${Date.now()}.txt`);
|
|
@@ -7029,7 +7171,14 @@ export async function startServer(options) {
|
|
|
7029
7171
|
// isolated work session (DMs don't carry thread_ts anyway).
|
|
7030
7172
|
const targetSession = (isDM && !isThreadSession) ? 'lifeline' : undefined;
|
|
7031
7173
|
try {
|
|
7032
|
-
const newSessionName = await sessionManager.spawnInteractiveSession(bootstrapMessage, targetSession, {
|
|
7174
|
+
const newSessionName = await sessionManager.spawnInteractiveSession(bootstrapMessage, targetSession, {
|
|
7175
|
+
resumeSessionId,
|
|
7176
|
+
slackChannelId: channelId,
|
|
7177
|
+
slackThreadTs: replyThreadTs,
|
|
7178
|
+
// durable-conversation-identity §7: scope this session's bind
|
|
7179
|
+
// token to the minted conversation it may open durable state on.
|
|
7180
|
+
...(conversationId !== null ? { bootstrapConversationIds: [conversationId] } : {}),
|
|
7181
|
+
});
|
|
7033
7182
|
if (newSessionName) {
|
|
7034
7183
|
// Register on the routing key (channelId for a channel session,
|
|
7035
7184
|
// `<channelId>:<thread_ts>` for a thread session). channelName carries
|
|
@@ -7046,6 +7195,32 @@ export async function startServer(options) {
|
|
|
7046
7195
|
// Expose to the owner-side mesh bridge (a forwarded Slack message replays
|
|
7047
7196
|
// through the same dispatch on the machine that owns the conversation).
|
|
7048
7197
|
_slackInboundDispatch = slackInboundDispatch;
|
|
7198
|
+
// ── §6.2 adoption pass (durable-conversation-identity) ─────────────
|
|
7199
|
+
// Idempotent boot-time ensure: pre-register channel-LEVEL conversations
|
|
7200
|
+
// from slack-channel-registry.json with their legacy-hash ids, inside
|
|
7201
|
+
// ONE batched-save window. Gated to channels with authorized-sender
|
|
7202
|
+
// traffic on record (security-B8): a channel enters the session
|
|
7203
|
+
// registry ONLY via the authorized-sender dispatch above, so presence
|
|
7204
|
+
// there IS the authorized-traffic evidence — an auto-joined channel
|
|
7205
|
+
// with no authorized activity never appears and mints lazily on its
|
|
7206
|
+
// first authorized inbound instead. A pre-population convenience, not a
|
|
7207
|
+
// recovery requirement (§6.2).
|
|
7208
|
+
try {
|
|
7209
|
+
const channelRegistry = slackAdapter.getChannelRegistry();
|
|
7210
|
+
const channelIds = new Map();
|
|
7211
|
+
for (const [routingKey, entry] of Object.entries(channelRegistry)) {
|
|
7212
|
+
const chId = routingKey.includes(':') ? routingKey.slice(0, routingKey.indexOf(':')) : routingKey;
|
|
7213
|
+
if (!channelIds.has(chId))
|
|
7214
|
+
channelIds.set(chId, entry.channelName);
|
|
7215
|
+
}
|
|
7216
|
+
conversationRegistry.runAdoptionPass([...channelIds].map(([channelId, name]) => ({ channelId, ...(name ? { name } : {}) })), () => true);
|
|
7217
|
+
}
|
|
7218
|
+
catch (err) {
|
|
7219
|
+
// @silent-fallback-ok — the adoption pass is a pre-population CONVENIENCE,
|
|
7220
|
+
// not a recovery requirement (§6.2): every channel mints lazily on its
|
|
7221
|
+
// next authorized inbound; the failure is logged loudly here.
|
|
7222
|
+
console.warn(` [conversation-registry] adoption pass failed (channels mint lazily on next inbound): ${err instanceof Error ? err.message : String(err)}`);
|
|
7223
|
+
}
|
|
7049
7224
|
slackAdapter.onMessage(async (message) => {
|
|
7050
7225
|
const channelId = message.channel.identifier;
|
|
7051
7226
|
const messageTs = message.metadata?.ts;
|
|
@@ -10959,6 +11134,11 @@ export async function startServer(options) {
|
|
|
10959
11134
|
notify('IMMEDIATE', 'commitment', `The change you asked for ("${commitment.userRequest}") keeps reverting — this looks like a bug I need to fix. ${detail}`);
|
|
10960
11135
|
},
|
|
10961
11136
|
});
|
|
11137
|
+
// durable-conversation-identity §6.1 step 2: the ConversationBinder is
|
|
11138
|
+
// late-bound (the registry constructs before the tracker). A durable bind
|
|
11139
|
+
// on a minted (negative) conversation id now registers durably + records
|
|
11140
|
+
// the §3.5.2 bind-pin and denormalizes boundTuple onto the commitment.
|
|
11141
|
+
commitmentTracker.setConversationBinder(conversationBinder);
|
|
10962
11142
|
commitmentTracker.start();
|
|
10963
11143
|
console.log(pc.green(' Commitment tracker enabled'));
|
|
10964
11144
|
// SubscriptionPool — multi-account subscription registry (P1.1 of the
|
|
@@ -12243,6 +12423,32 @@ export async function startServer(options) {
|
|
|
12243
12423
|
if (!response.ok)
|
|
12244
12424
|
throw new Error(`Beacon reply failed: ${response.status}`);
|
|
12245
12425
|
},
|
|
12426
|
+
// ── durable-conversation-identity §6.1 step 2: the funnel swap ──
|
|
12427
|
+
// EVERY beacon send routes through deliverToConversation: the id>0
|
|
12428
|
+
// arm is today's Telegram path unchanged; the id<0 arm delivers
|
|
12429
|
+
// into the exact Slack thread with the E1 guard + §5.1 typed
|
|
12430
|
+
// outcomes. The `metadata` shape maps to the funnel opts contract.
|
|
12431
|
+
deliverMessage: (topicId, text, opts) => deliverToConversation(topicId, text, {
|
|
12432
|
+
source: opts.source,
|
|
12433
|
+
isProxy: opts.isProxy,
|
|
12434
|
+
tier: typeof opts.tier === 'number' ? String(opts.tier) : opts.tier,
|
|
12435
|
+
logicalSendId: opts.logicalSendId,
|
|
12436
|
+
...(opts.boundTuple ? { boundTuple: opts.boundTuple } : {}),
|
|
12437
|
+
}),
|
|
12438
|
+
// §5.0(a): journal send-retire after the sendSeq persist (R5-M3 order).
|
|
12439
|
+
retireSend: (conversationId, logicalSendId) => {
|
|
12440
|
+
try {
|
|
12441
|
+
conversationRegistry.retireSend(conversationId, logicalSendId);
|
|
12442
|
+
}
|
|
12443
|
+
catch { /* guard bookkeeping */ }
|
|
12444
|
+
},
|
|
12445
|
+
// §5.0 ownership predicate (drives the R3-M16 stand-down recheck).
|
|
12446
|
+
ownsConversation: (conversationId) => {
|
|
12447
|
+
if (conversationId > 0)
|
|
12448
|
+
return true; // Telegram is always locally owned
|
|
12449
|
+
const resolved = conversationRegistry.resolve(conversationId);
|
|
12450
|
+
return !!resolved && resolved.platform === 'slack' && resolved.origin !== 'replicated' && !!_slackAdapter;
|
|
12451
|
+
},
|
|
12246
12452
|
prefix: promiseBeaconCfg.prefix ?? '⏳',
|
|
12247
12453
|
maxDailyLlmSpendCents: promiseBeaconCfg.maxDailyLlmSpendCents ?? 100,
|
|
12248
12454
|
sentinelAutoEnable: promiseBeaconCfg.sentinelAutoEnable ?? false,
|
|
@@ -20229,7 +20435,7 @@ export async function startServer(options) {
|
|
|
20229
20435
|
const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, cartographer: cartographer ?? undefined, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, subscriptionPool, accountFollowMePeerViews: async () => { const nickById = new Map((_listPoolMachines?.() ?? []).map((m) => [m.machineId, m.nickname ?? m.machineId])); let peers = (_resolvePeerUrls?.() ?? []).map((p) => ({ machineId: p.machineId, nickname: nickById.get(p.machineId) ?? p.machineId, url: p.url })); if (peers.length === 0) {
|
|
20230
20436
|
peers = (_listPoolMachines?.() ?? []).filter((m) => m.machineId !== _meshSelfId && !!m.lastKnownUrl).map((m) => ({ machineId: m.machineId, nickname: m.nickname ?? m.machineId, url: m.lastKnownUrl }));
|
|
20231
20437
|
} if (peers.length === 0)
|
|
20232
|
-
return []; const { fetchPeerSubscriptionViews } = await import('../core/fetchPeerSubscriptionViews.js'); return fetchPeerSubscriptionViews({ peers: () => peers, fetchImpl: fetch, authToken: config.authToken ?? '' }); }, quotaPoller, quotaAwareScheduler: _quotaAwareScheduler ?? undefined, proactiveSwapMonitor: _proactiveSwapMonitor ?? undefined, inUseAccountResolver, enrollmentWizard, accountFollowMeRevocation, credentialRepointing, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, greenPrAutoMerger: greenPrAutoMerger ?? undefined, guardLatchStore: guardLatchStore ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, topicProfile: _topicProfileCtx ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, meshBindActive: coordinator.managers.identityManager.hasIdentity() && config.multiMachine?.meshTransport?.enabled !== false, localSigningKeyPem, leaseTransport, peerEndpointRecorder, getSelfMeshEndpoints, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, threadLog, threadMessageRecorder, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, a2aDeliveryTracker: a2aDeliveryTracker ?? undefined, responseReviewGate, reviewCanaryBattery, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, ropeHealthMonitor, writeAdmission: writeAdmission ?? undefined, getInboundQueue: () => _inboundQueue, meshRpcDispatcher, workingSetPullCoordinator, commitmentReplicaStore, preferenceReplicaStore, replicatedRecordEmitter, conflictStore, rollbackUnmerge, droppedOriginRegistry, preferencesUnionReader, forwardCommitmentMutate, sessionOwnershipRegistry, topicPinStore: _topicPinStore ?? undefined, topicPinSkewQuarantine: _topicPinSkewQuarantine ?? undefined, topicPinFoldView: _topicPinFoldView ?? undefined, ownershipReconciler: _ownershipReconciler ?? undefined, staleOwnerEngine: _staleOwnerEngine ?? undefined, leaseHandback: _leaseHandbackCtx ?? undefined, streamTicketStore: _streamTicketStore ?? undefined, poolStreamAllowRemoteInput: config.dashboard?.poolStream?.allowRemoteInput ?? false, poolStreamConnector: _poolStreamConnector ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, guardRegistry, listPoolMachines: _listPoolMachines ?? undefined, deliverMandateToMachine: _deliverMandateToMachine ?? undefined, poolLink: _poolLink ?? undefined, poolPollCache: _poolPollCache ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, orphanedWorkSentinel, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, resumeQueue, resumeDrainer, autonomousLivenessReconciler, enforcedTerminationStatus: () => enforcedTerminationWatchdog?.guardStatus() ?? null, prHandLease: prHandLease ?? undefined, operatorStopRecorder: recordOperatorStop, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier, liveTestGate, liveTestGateMode, liveTestRunnerCtx }); // Resolve the late-bound topic-operator getter (increment 2e): routing was
|
|
20438
|
+
return []; const { fetchPeerSubscriptionViews } = await import('../core/fetchPeerSubscriptionViews.js'); return fetchPeerSubscriptionViews({ peers: () => peers, fetchImpl: fetch, authToken: config.authToken ?? '' }); }, quotaPoller, quotaAwareScheduler: _quotaAwareScheduler ?? undefined, proactiveSwapMonitor: _proactiveSwapMonitor ?? undefined, inUseAccountResolver, enrollmentWizard, accountFollowMeRevocation, credentialRepointing, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, greenPrAutoMerger: greenPrAutoMerger ?? undefined, guardLatchStore: guardLatchStore ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, topicProfile: _topicProfileCtx ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, meshBindActive: coordinator.managers.identityManager.hasIdentity() && config.multiMachine?.meshTransport?.enabled !== false, localSigningKeyPem, leaseTransport, peerEndpointRecorder, getSelfMeshEndpoints, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, conversationRegistry, conversationBindAuth, conversationFollowThrough, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, threadLog, threadMessageRecorder, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, a2aDeliveryTracker: a2aDeliveryTracker ?? undefined, responseReviewGate, reviewCanaryBattery, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, ropeHealthMonitor, writeAdmission: writeAdmission ?? undefined, getInboundQueue: () => _inboundQueue, meshRpcDispatcher, workingSetPullCoordinator, commitmentReplicaStore, preferenceReplicaStore, replicatedRecordEmitter, conflictStore, rollbackUnmerge, droppedOriginRegistry, preferencesUnionReader, forwardCommitmentMutate, sessionOwnershipRegistry, topicPinStore: _topicPinStore ?? undefined, topicPinSkewQuarantine: _topicPinSkewQuarantine ?? undefined, topicPinFoldView: _topicPinFoldView ?? undefined, ownershipReconciler: _ownershipReconciler ?? undefined, staleOwnerEngine: _staleOwnerEngine ?? undefined, leaseHandback: _leaseHandbackCtx ?? undefined, streamTicketStore: _streamTicketStore ?? undefined, poolStreamAllowRemoteInput: config.dashboard?.poolStream?.allowRemoteInput ?? false, poolStreamConnector: _poolStreamConnector ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, guardRegistry, listPoolMachines: _listPoolMachines ?? undefined, deliverMandateToMachine: _deliverMandateToMachine ?? undefined, poolLink: _poolLink ?? undefined, poolPollCache: _poolPollCache ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, orphanedWorkSentinel, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, resumeQueue, resumeDrainer, autonomousLivenessReconciler, enforcedTerminationStatus: () => enforcedTerminationWatchdog?.guardStatus() ?? null, prHandLease: prHandLease ?? undefined, operatorStopRecorder: recordOperatorStop, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier, liveTestGate, liveTestGateMode, liveTestRunnerCtx }); // Resolve the late-bound topic-operator getter (increment 2e): routing was
|
|
20233
20439
|
// wired before the server existed; from here on inbound binds use the
|
|
20234
20440
|
// server's own store instance.
|
|
20235
20441
|
_agentServerRef = server;
|