@adhdev/daemon-core 0.9.82-rc.369 → 0.9.82-rc.370
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/daemon/dev-server.d.ts +0 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +102 -547
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +100 -547
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events-coordinator.d.ts +4 -91
- package/package.json +2 -2
- package/src/commands/handler.ts +2 -2
- package/src/daemon/dev-server.ts +0 -541
- package/src/index.ts +5 -3
- package/src/mesh/mesh-events-coordinator.ts +162 -109
- package/src/providers/cli-provider-instance.ts +2 -5
- package/src/providers/provider-loader.ts +2 -4
|
@@ -1754,98 +1754,35 @@ export function shouldForceInjectMeshEvent(eventName: unknown): boolean {
|
|
|
1754
1754
|
return typeof eventName === 'string' && MESH_FORCE_INJECT_EVENTS.has(eventName);
|
|
1755
1755
|
}
|
|
1756
1756
|
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
// (a remote worker's completion arrives via handleMeshForwardEvent with no local
|
|
1787
|
-
// sourceSession, so the stamp can only ride in the relayed metadata). Empty on legacy /
|
|
1788
|
-
// version-skewed dispatches → the event stays daemon-broadcast (no regression).
|
|
1789
|
-
const workerCoordinatorSessionId = readNonEmptyString(
|
|
1790
|
-
(sourceSession?.getState()?.settings as Record<string, unknown>)?.meshCoordinatorSessionId,
|
|
1791
|
-
) || readNonEmptyString(args.metadataEvent.meshCoordinatorSessionId);
|
|
1792
|
-
|
|
1793
|
-
// T2: a summary-less completion (and any non-completion status-sync event) carries no
|
|
1794
|
-
// assistant text on the event, so resolveMeshSurfacedSessionPreview had nothing to surface
|
|
1795
|
-
// and the coordinator's inbox mirror stayed stuck on the first dispatched user task. When
|
|
1796
|
-
// THIS daemon hosts the live worker instance (sourceSession present), derive the worker's
|
|
1797
|
-
// latest display message straight from its transcript and attach it to the event as
|
|
1798
|
-
// lastMessagePreview/lastMessageRole/lastMessageAt. resolveMeshSurfacedSessionPreview reads
|
|
1799
|
-
// these as an assistant-only fallback; they also ride the pending-queue + P2P relay
|
|
1800
|
-
// (handleMeshForwardEvent whitelist) so a remote coordinator can surface them. A remote
|
|
1801
|
-
// coordinator has no local instance and keeps relying on the relayed fields — unchanged.
|
|
1802
|
-
const enrichedMetadataEvent = ((): Record<string, unknown> => {
|
|
1803
|
-
const last = sourceSession ? getLastDisplayMessage(sourceSession.getState()) : null;
|
|
1804
|
-
if (!last || !last.preview) return args.metadataEvent;
|
|
1805
|
-
return {
|
|
1806
|
-
...args.metadataEvent,
|
|
1807
|
-
lastMessagePreview: last.preview,
|
|
1808
|
-
lastMessageRole: last.role,
|
|
1809
|
-
...(last.receivedAt > 0 ? { lastMessageAt: last.receivedAt } : {}),
|
|
1810
|
-
};
|
|
1811
|
-
})();
|
|
1812
|
-
|
|
1813
|
-
// R2: cloud P2P dashboard metadata sync. The cloud daemon used to do this from its own
|
|
1814
|
-
// relay listener; now the single core forwarder invokes the injected hook (no-op on
|
|
1815
|
-
// standalone) so the event path stays single-listener and the local code path is identical
|
|
1816
|
-
// across standalone and cloud.
|
|
1817
|
-
if (components.onMeshCoordinatorEventForwarded) {
|
|
1818
|
-
try {
|
|
1819
|
-
// T: the coordinator surfaces a remote worker's session but holds no local
|
|
1820
|
-
// instance for it, so the status snapshot can't derive a preview and the
|
|
1821
|
-
// mirror would stay stuck on the first dispatched user task. Resolve the
|
|
1822
|
-
// worker's latest assistant reply (carried on the completion event's
|
|
1823
|
-
// finalSummary / workerResult) into a preview the mirror can stamp, so the
|
|
1824
|
-
// mobile inbox reflects the assistant response. Completion events carry assistant
|
|
1825
|
-
// text as finalSummary; a summary-less completion / status sync falls back to the
|
|
1826
|
-
// worker's latest assistant display message (enrichedMetadataEvent.lastMessage*).
|
|
1827
|
-
// For a mid-turn user-only event this is undefined and the prior surfaced preview
|
|
1828
|
-
// is preserved downstream (no clobber).
|
|
1829
|
-
const surfacedPreview = resolveMeshSurfacedSessionPreview(enrichedMetadataEvent);
|
|
1830
|
-
components.onMeshCoordinatorEventForwarded({
|
|
1831
|
-
event: args.event,
|
|
1832
|
-
meshId: args.meshId,
|
|
1833
|
-
nodeId: eventNodeId || undefined,
|
|
1834
|
-
...enrichedMetadataEvent,
|
|
1835
|
-
// Ensure a `workspace` field reaches updateMeshOwnedSession even when the
|
|
1836
|
-
// worker provider event only carried `workspaceName`. The merge spread of
|
|
1837
|
-
// metadataEvent above wins when it already has a non-empty `workspace`.
|
|
1838
|
-
workspace: readNonEmptyString(args.metadataEvent.workspace)
|
|
1839
|
-
|| readNonEmptyString(args.metadataEvent.workspaceName)
|
|
1840
|
-
|| undefined,
|
|
1841
|
-
...(surfacedPreview ? {
|
|
1842
|
-
meshSessionLastMessagePreview: surfacedPreview.preview,
|
|
1843
|
-
meshSessionLastMessageRole: surfacedPreview.role,
|
|
1844
|
-
meshSessionLastMessageAt: surfacedPreview.receivedAt || undefined,
|
|
1845
|
-
} : {}),
|
|
1846
|
-
});
|
|
1847
|
-
} catch { /* dashboard metadata sync is best-effort */ }
|
|
1848
|
-
}
|
|
1757
|
+
// Coordinator-side suppression/reconcile gate for an incoming mesh event. Each clause is a
|
|
1758
|
+
// closed dedup/suppression concern that only inspects the event + already-resolved context and
|
|
1759
|
+
// either (a) returns a `suppress` result the caller forwards verbatim, (b) returns a `reconcile`
|
|
1760
|
+
// signal carrying the rewritten metadataEvent for the caller to re-inject as
|
|
1761
|
+
// agent:generating_completed, or (c) returns null to let the event fall through to the
|
|
1762
|
+
// terminal/ledger machinery. Extracted verbatim from injectMeshSystemMessage — no behavior
|
|
1763
|
+
// change; the only side effects (best-effort remote-idle cleanup, LOG, trace) fire on the same
|
|
1764
|
+
// paths as before.
|
|
1765
|
+
function evaluateMeshEventSuppression(
|
|
1766
|
+
args: {
|
|
1767
|
+
meshId: string;
|
|
1768
|
+
sourceInstanceId?: string;
|
|
1769
|
+
nodeId?: string;
|
|
1770
|
+
nodeLabel: string;
|
|
1771
|
+
event: string;
|
|
1772
|
+
metadataEvent: Record<string, unknown>;
|
|
1773
|
+
},
|
|
1774
|
+
ctx: {
|
|
1775
|
+
traceCtx: Parameters<typeof traceMeshEventDrop>[1];
|
|
1776
|
+
eventSessionId: string;
|
|
1777
|
+
eventNodeId: string;
|
|
1778
|
+
eventTimestamp: number | null;
|
|
1779
|
+
workerCoordinatorDaemonId: string | undefined;
|
|
1780
|
+
},
|
|
1781
|
+
):
|
|
1782
|
+
| { kind: 'suppress'; result: { success: true; forwarded: 0; suppressed: true; [extra: string]: unknown } }
|
|
1783
|
+
| { kind: 'reconcile'; metadataEvent: Record<string, unknown> }
|
|
1784
|
+
| null {
|
|
1785
|
+
const { traceCtx, eventSessionId, eventNodeId, eventTimestamp, workerCoordinatorDaemonId } = ctx;
|
|
1849
1786
|
|
|
1850
1787
|
const intentionalCleanupStop = shouldSuppressIntentionalCleanupStop({
|
|
1851
1788
|
event: args.event,
|
|
@@ -1862,7 +1799,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
1862
1799
|
}
|
|
1863
1800
|
LOG.info('MeshEvents', `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || '(unknown session)'}`);
|
|
1864
1801
|
traceMeshEventDrop('intentional_cleanup_stop', traceCtx);
|
|
1865
|
-
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
1802
|
+
return { kind: 'suppress', result: { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true } };
|
|
1866
1803
|
}
|
|
1867
1804
|
|
|
1868
1805
|
if (args.event === 'monitor:no_progress') {
|
|
@@ -1875,21 +1812,20 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
1875
1812
|
});
|
|
1876
1813
|
if (reconciledCompletion?.source === 'no_progress_reconciliation') {
|
|
1877
1814
|
LOG.info('MeshEvents', `Reconciled no-progress monitor to completion for session ${eventSessionId || '(unknown session)'}`);
|
|
1878
|
-
return
|
|
1879
|
-
...args,
|
|
1880
|
-
event: 'agent:generating_completed',
|
|
1881
|
-
metadataEvent: reconciledCompletion,
|
|
1882
|
-
});
|
|
1815
|
+
return { kind: 'reconcile', metadataEvent: reconciledCompletion };
|
|
1883
1816
|
}
|
|
1884
1817
|
if (reconciledCompletion?.source === 'no_progress_terminal_ledger_suppression') {
|
|
1885
1818
|
LOG.info('MeshEvents', `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || '(unknown session)'}`);
|
|
1886
1819
|
traceMeshEventDrop('no_progress_terminal_ledger_suppression', traceCtx, `terminalKind=${reconciledCompletion.terminalLedgerKind}`);
|
|
1887
1820
|
return {
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1821
|
+
kind: 'suppress',
|
|
1822
|
+
result: {
|
|
1823
|
+
success: true,
|
|
1824
|
+
forwarded: 0,
|
|
1825
|
+
suppressed: true,
|
|
1826
|
+
terminalLedgerEvidence: true,
|
|
1827
|
+
terminalLedgerKind: reconciledCompletion.terminalLedgerKind,
|
|
1828
|
+
},
|
|
1893
1829
|
};
|
|
1894
1830
|
}
|
|
1895
1831
|
}
|
|
@@ -1897,10 +1833,9 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
1897
1833
|
if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
|
|
1898
1834
|
LOG.info('MeshEvents', `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
|
|
1899
1835
|
traceMeshEventDrop('duplicate_refine_terminal', traceCtx);
|
|
1900
|
-
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
1836
|
+
return { kind: 'suppress', result: { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true } };
|
|
1901
1837
|
}
|
|
1902
1838
|
|
|
1903
|
-
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
1904
1839
|
if (args.event === 'agent:waiting_approval' && eventSessionId) {
|
|
1905
1840
|
const duplicateApproval = isDuplicateMeshApprovalEvent({
|
|
1906
1841
|
meshId: args.meshId,
|
|
@@ -1913,7 +1848,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
1913
1848
|
if (duplicateApproval) {
|
|
1914
1849
|
LOG.info('MeshEvents', `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
1915
1850
|
traceMeshEventDrop('duplicate_approval', traceCtx);
|
|
1916
|
-
return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
|
|
1851
|
+
return { kind: 'suppress', result: { success: true, forwarded: 0, suppressed: true, duplicateApproval: true } };
|
|
1917
1852
|
}
|
|
1918
1853
|
}
|
|
1919
1854
|
if (args.event === 'agent:generating_completed' && eventSessionId) {
|
|
@@ -1965,7 +1900,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
1965
1900
|
) {
|
|
1966
1901
|
LOG.info('MeshEvents', `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
1967
1902
|
traceMeshEventDrop('duplicate_completion_terminal_ledger', traceCtx);
|
|
1968
|
-
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
1903
|
+
return { kind: 'suppress', result: { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true } };
|
|
1969
1904
|
}
|
|
1970
1905
|
}
|
|
1971
1906
|
}
|
|
@@ -1984,7 +1919,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
1984
1919
|
if (duplicateCompletion) {
|
|
1985
1920
|
LOG.info('MeshEvents', `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
1986
1921
|
traceMeshEventDrop('duplicate_completion', traceCtx);
|
|
1987
|
-
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
1922
|
+
return { kind: 'suppress', result: { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true } };
|
|
1988
1923
|
}
|
|
1989
1924
|
}
|
|
1990
1925
|
if (args.event === 'agent:stopped' && eventSessionId) {
|
|
@@ -2003,8 +1938,126 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
2003
1938
|
if (duplicateStopped) {
|
|
2004
1939
|
LOG.info('MeshEvents', `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
2005
1940
|
traceMeshEventDrop('duplicate_stopped', traceCtx);
|
|
2006
|
-
return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
|
|
1941
|
+
return { kind: 'suppress', result: { success: true, forwarded: 0, suppressed: true, duplicateStopped: true } };
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
return null;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
1949
|
+
meshId: string;
|
|
1950
|
+
sourceInstanceId?: string;
|
|
1951
|
+
nodeId?: string;
|
|
1952
|
+
nodeLabel: string;
|
|
1953
|
+
event: string;
|
|
1954
|
+
metadataEvent: Record<string, unknown>;
|
|
1955
|
+
}) {
|
|
1956
|
+
const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
1957
|
+
const eventNodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
|
|
1958
|
+
|
|
1959
|
+
// EVTTRACE correlation context for this event's coordinator-side lifecycle (queue /
|
|
1960
|
+
// dedup / suppress). Observation only — never read by any decision below.
|
|
1961
|
+
const traceCtx = {
|
|
1962
|
+
taskId: args.metadataEvent.taskId,
|
|
1963
|
+
sessionId: eventSessionId,
|
|
1964
|
+
nodeId: eventNodeId,
|
|
1965
|
+
meshId: args.meshId,
|
|
1966
|
+
event: args.event,
|
|
1967
|
+
};
|
|
1968
|
+
|
|
1969
|
+
const sourceSession = args.sourceInstanceId
|
|
1970
|
+
? components.instanceManager.getInstance(args.sourceInstanceId)
|
|
1971
|
+
: undefined;
|
|
1972
|
+
const workerCoordinatorDaemonId = readNonEmptyString(
|
|
1973
|
+
(sourceSession?.getState()?.settings as Record<string, unknown>)?.meshCoordinatorDaemonId,
|
|
1974
|
+
);
|
|
1975
|
+
// Session-level routing anchor (multi-coordinator). Prefer the LIVE worker session's
|
|
1976
|
+
// stamp; fall back to a relayed value carried in metadataEvent.meshCoordinatorSessionId
|
|
1977
|
+
// (a remote worker's completion arrives via handleMeshForwardEvent with no local
|
|
1978
|
+
// sourceSession, so the stamp can only ride in the relayed metadata). Empty on legacy /
|
|
1979
|
+
// version-skewed dispatches → the event stays daemon-broadcast (no regression).
|
|
1980
|
+
const workerCoordinatorSessionId = readNonEmptyString(
|
|
1981
|
+
(sourceSession?.getState()?.settings as Record<string, unknown>)?.meshCoordinatorSessionId,
|
|
1982
|
+
) || readNonEmptyString(args.metadataEvent.meshCoordinatorSessionId);
|
|
1983
|
+
|
|
1984
|
+
// T2: a summary-less completion (and any non-completion status-sync event) carries no
|
|
1985
|
+
// assistant text on the event, so resolveMeshSurfacedSessionPreview had nothing to surface
|
|
1986
|
+
// and the coordinator's inbox mirror stayed stuck on the first dispatched user task. When
|
|
1987
|
+
// THIS daemon hosts the live worker instance (sourceSession present), derive the worker's
|
|
1988
|
+
// latest display message straight from its transcript and attach it to the event as
|
|
1989
|
+
// lastMessagePreview/lastMessageRole/lastMessageAt. resolveMeshSurfacedSessionPreview reads
|
|
1990
|
+
// these as an assistant-only fallback; they also ride the pending-queue + P2P relay
|
|
1991
|
+
// (handleMeshForwardEvent whitelist) so a remote coordinator can surface them. A remote
|
|
1992
|
+
// coordinator has no local instance and keeps relying on the relayed fields — unchanged.
|
|
1993
|
+
const enrichedMetadataEvent = ((): Record<string, unknown> => {
|
|
1994
|
+
const last = sourceSession ? getLastDisplayMessage(sourceSession.getState()) : null;
|
|
1995
|
+
if (!last || !last.preview) return args.metadataEvent;
|
|
1996
|
+
return {
|
|
1997
|
+
...args.metadataEvent,
|
|
1998
|
+
lastMessagePreview: last.preview,
|
|
1999
|
+
lastMessageRole: last.role,
|
|
2000
|
+
...(last.receivedAt > 0 ? { lastMessageAt: last.receivedAt } : {}),
|
|
2001
|
+
};
|
|
2002
|
+
})();
|
|
2003
|
+
|
|
2004
|
+
// R2: cloud P2P dashboard metadata sync. The cloud daemon used to do this from its own
|
|
2005
|
+
// relay listener; now the single core forwarder invokes the injected hook (no-op on
|
|
2006
|
+
// standalone) so the event path stays single-listener and the local code path is identical
|
|
2007
|
+
// across standalone and cloud.
|
|
2008
|
+
if (components.onMeshCoordinatorEventForwarded) {
|
|
2009
|
+
try {
|
|
2010
|
+
// T: the coordinator surfaces a remote worker's session but holds no local
|
|
2011
|
+
// instance for it, so the status snapshot can't derive a preview and the
|
|
2012
|
+
// mirror would stay stuck on the first dispatched user task. Resolve the
|
|
2013
|
+
// worker's latest assistant reply (carried on the completion event's
|
|
2014
|
+
// finalSummary / workerResult) into a preview the mirror can stamp, so the
|
|
2015
|
+
// mobile inbox reflects the assistant response. Completion events carry assistant
|
|
2016
|
+
// text as finalSummary; a summary-less completion / status sync falls back to the
|
|
2017
|
+
// worker's latest assistant display message (enrichedMetadataEvent.lastMessage*).
|
|
2018
|
+
// For a mid-turn user-only event this is undefined and the prior surfaced preview
|
|
2019
|
+
// is preserved downstream (no clobber).
|
|
2020
|
+
const surfacedPreview = resolveMeshSurfacedSessionPreview(enrichedMetadataEvent);
|
|
2021
|
+
components.onMeshCoordinatorEventForwarded({
|
|
2022
|
+
event: args.event,
|
|
2023
|
+
meshId: args.meshId,
|
|
2024
|
+
nodeId: eventNodeId || undefined,
|
|
2025
|
+
...enrichedMetadataEvent,
|
|
2026
|
+
// Ensure a `workspace` field reaches updateMeshOwnedSession even when the
|
|
2027
|
+
// worker provider event only carried `workspaceName`. The merge spread of
|
|
2028
|
+
// metadataEvent above wins when it already has a non-empty `workspace`.
|
|
2029
|
+
workspace: readNonEmptyString(args.metadataEvent.workspace)
|
|
2030
|
+
|| readNonEmptyString(args.metadataEvent.workspaceName)
|
|
2031
|
+
|| undefined,
|
|
2032
|
+
...(surfacedPreview ? {
|
|
2033
|
+
meshSessionLastMessagePreview: surfacedPreview.preview,
|
|
2034
|
+
meshSessionLastMessageRole: surfacedPreview.role,
|
|
2035
|
+
meshSessionLastMessageAt: surfacedPreview.receivedAt || undefined,
|
|
2036
|
+
} : {}),
|
|
2037
|
+
});
|
|
2038
|
+
} catch { /* dashboard metadata sync is best-effort */ }
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
2042
|
+
// Coordinator-side dedup/suppression gate (extracted, behavior-preserving). A non-null
|
|
2043
|
+
// outcome either short-circuits with a forwarded result or signals a no-progress→completion
|
|
2044
|
+
// reconciliation that we re-inject; null lets the event fall through to the ledger machinery.
|
|
2045
|
+
const suppression = evaluateMeshEventSuppression(args, {
|
|
2046
|
+
traceCtx,
|
|
2047
|
+
eventSessionId,
|
|
2048
|
+
eventNodeId,
|
|
2049
|
+
eventTimestamp,
|
|
2050
|
+
workerCoordinatorDaemonId,
|
|
2051
|
+
});
|
|
2052
|
+
if (suppression) {
|
|
2053
|
+
if (suppression.kind === 'reconcile') {
|
|
2054
|
+
return injectMeshSystemMessage(components, {
|
|
2055
|
+
...args,
|
|
2056
|
+
event: 'agent:generating_completed',
|
|
2057
|
+
metadataEvent: suppression.metadataEvent,
|
|
2058
|
+
});
|
|
2007
2059
|
}
|
|
2060
|
+
return suppression.result;
|
|
2008
2061
|
}
|
|
2009
2062
|
|
|
2010
2063
|
function markSessionTerminal(sessionId: string, outcome: 'completed' | 'failed', occurredAtMs?: number | null, opts?: { tentativeIfDirect?: boolean }): { id?: string } | null {
|
|
@@ -15,6 +15,7 @@ import { assertProviderSupportsDeclaredInput, getEffectiveMessageInputSupport }
|
|
|
15
15
|
import type { ProviderInstance, ProviderState, ProviderEvent, InstanceContext, ProviderErrorReason, HotChatSessionState, SessionModalState } from './provider-instance.js';
|
|
16
16
|
import { normalizeInteractivePrompt, normalizeInteractivePromptResponse, type InteractivePrompt } from './types/interactive-prompt.js';
|
|
17
17
|
import { ProviderCliAdapter } from '../cli-adapters/provider-cli-adapter.js';
|
|
18
|
+
import { shortHash } from '../system/hash.js';
|
|
18
19
|
import type { CliProviderModule } from '../cli-adapters/provider-cli-adapter.js';
|
|
19
20
|
import { createCliAdapter } from './spec/route.js';
|
|
20
21
|
import type { PtyRuntimeMetadata, PtyTransportFactory } from '../cli-adapters/pty-transport.js';
|
|
@@ -1056,11 +1057,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1056
1057
|
|
|
1057
1058
|
const receivedAt = Date.now();
|
|
1058
1059
|
this.lastAcknowledgedUserInputAt = receivedAt;
|
|
1059
|
-
const dedupKey = `user_input_ack:${
|
|
1060
|
-
.createHash('sha256')
|
|
1061
|
-
.update(`${this.instanceId}:${content}:${receivedAt}`)
|
|
1062
|
-
.digest('hex')
|
|
1063
|
-
.slice(0, 24)}`;
|
|
1060
|
+
const dedupKey = `user_input_ack:${shortHash(`${this.instanceId}:${content}:${receivedAt}`, 24)}`;
|
|
1064
1061
|
this.appendRuntimeMessage(buildChatMessage({
|
|
1065
1062
|
role: 'user',
|
|
1066
1063
|
senderName: 'User',
|
|
@@ -18,6 +18,7 @@ import * as path from 'path';
|
|
|
18
18
|
import * as os from 'os';
|
|
19
19
|
import * as chokidar from 'chokidar';
|
|
20
20
|
import { registerIDEDefinition } from '../detection/ide-detector.js';
|
|
21
|
+
import { sha256Hex } from '../system/hash.js';
|
|
21
22
|
import { LOG } from '../logging/logger.js';
|
|
22
23
|
import { VersionArchive } from './version-archive.js';
|
|
23
24
|
import type {
|
|
@@ -1604,10 +1605,7 @@ export class ProviderLoader {
|
|
|
1604
1605
|
});
|
|
1605
1606
|
|
|
1606
1607
|
// Verify checksum
|
|
1607
|
-
const actualChecksum =
|
|
1608
|
-
const crypto = require('crypto') as typeof import('crypto');
|
|
1609
|
-
resolve(crypto.createHash('sha256').update(manifestBody, 'utf-8').digest('hex'));
|
|
1610
|
-
});
|
|
1608
|
+
const actualChecksum = sha256Hex(manifestBody);
|
|
1611
1609
|
if (actualChecksum !== checksum) {
|
|
1612
1610
|
this.log(`⚠ Registry checksum mismatch for ${type}@${version} — skipping`);
|
|
1613
1611
|
continue;
|