@barryfan2045/dsh-matrix 0.1.0
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/LICENSE +21 -0
- package/README.md +286 -0
- package/THIRD_PARTY_NOTICES.md +53 -0
- package/assets/avatars/instance-01.png +0 -0
- package/assets/avatars/instance-02.png +0 -0
- package/assets/avatars/instance-03.png +0 -0
- package/assets/avatars/instance-04.png +0 -0
- package/assets/avatars/instance-05.png +0 -0
- package/assets/avatars/instance-06.png +0 -0
- package/assets/avatars/instance-07.png +0 -0
- package/assets/avatars/instance-08.png +0 -0
- package/assets/avatars/instance-09.png +0 -0
- package/assets/avatars/instance-10.png +0 -0
- package/assets/avatars/instance-11.png +0 -0
- package/assets/avatars/instance-12.png +0 -0
- package/assets/avatars/management.png +0 -0
- package/cordis.patch.yml +13 -0
- package/dist/auth/admin-commands.d.ts +47 -0
- package/dist/auth/admin-commands.d.ts.map +1 -0
- package/dist/auth/admin-commands.js +112 -0
- package/dist/auth/admin-commands.js.map +1 -0
- package/dist/auth/challenge.d.ts +93 -0
- package/dist/auth/challenge.d.ts.map +1 -0
- package/dist/auth/challenge.js +104 -0
- package/dist/auth/challenge.js.map +1 -0
- package/dist/auth/store.d.ts +55 -0
- package/dist/auth/store.d.ts.map +1 -0
- package/dist/auth/store.js +124 -0
- package/dist/auth/store.js.map +1 -0
- package/dist/bridge/agent-commands.d.ts +39 -0
- package/dist/bridge/agent-commands.d.ts.map +1 -0
- package/dist/bridge/agent-commands.js +243 -0
- package/dist/bridge/agent-commands.js.map +1 -0
- package/dist/bridge/attachments-ledger.d.ts +54 -0
- package/dist/bridge/attachments-ledger.d.ts.map +1 -0
- package/dist/bridge/attachments-ledger.js +68 -0
- package/dist/bridge/attachments-ledger.js.map +1 -0
- package/dist/bridge/commands.d.ts +28 -0
- package/dist/bridge/commands.d.ts.map +1 -0
- package/dist/bridge/commands.js +18 -0
- package/dist/bridge/commands.js.map +1 -0
- package/dist/bridge/crypto-health.d.ts +37 -0
- package/dist/bridge/crypto-health.d.ts.map +1 -0
- package/dist/bridge/crypto-health.js +38 -0
- package/dist/bridge/crypto-health.js.map +1 -0
- package/dist/bridge/group-gate.d.ts +38 -0
- package/dist/bridge/group-gate.d.ts.map +1 -0
- package/dist/bridge/group-gate.js +49 -0
- package/dist/bridge/group-gate.js.map +1 -0
- package/dist/bridge/instance-lock.d.ts +10 -0
- package/dist/bridge/instance-lock.d.ts.map +1 -0
- package/dist/bridge/instance-lock.js +82 -0
- package/dist/bridge/instance-lock.js.map +1 -0
- package/dist/bridge/interactions.d.ts +62 -0
- package/dist/bridge/interactions.d.ts.map +1 -0
- package/dist/bridge/interactions.js +237 -0
- package/dist/bridge/interactions.js.map +1 -0
- package/dist/bridge/management-room.d.ts +13 -0
- package/dist/bridge/management-room.d.ts.map +1 -0
- package/dist/bridge/management-room.js +27 -0
- package/dist/bridge/management-room.js.map +1 -0
- package/dist/bridge/multi-project.d.ts +34 -0
- package/dist/bridge/multi-project.d.ts.map +1 -0
- package/dist/bridge/multi-project.js +44 -0
- package/dist/bridge/multi-project.js.map +1 -0
- package/dist/bridge/pipeline.d.ts +151 -0
- package/dist/bridge/pipeline.d.ts.map +1 -0
- package/dist/bridge/pipeline.js +502 -0
- package/dist/bridge/pipeline.js.map +1 -0
- package/dist/bridge/pmctl.d.ts +50 -0
- package/dist/bridge/pmctl.d.ts.map +1 -0
- package/dist/bridge/pmctl.js +272 -0
- package/dist/bridge/pmctl.js.map +1 -0
- package/dist/bridge/power-levels.d.ts +57 -0
- package/dist/bridge/power-levels.d.ts.map +1 -0
- package/dist/bridge/power-levels.js +92 -0
- package/dist/bridge/power-levels.js.map +1 -0
- package/dist/bridge/power-sync.d.ts +64 -0
- package/dist/bridge/power-sync.d.ts.map +1 -0
- package/dist/bridge/power-sync.js +121 -0
- package/dist/bridge/power-sync.js.map +1 -0
- package/dist/bridge/projects.d.ts +97 -0
- package/dist/bridge/projects.d.ts.map +1 -0
- package/dist/bridge/projects.js +288 -0
- package/dist/bridge/projects.js.map +1 -0
- package/dist/bridge/quote-cache.d.ts +38 -0
- package/dist/bridge/quote-cache.d.ts.map +1 -0
- package/dist/bridge/quote-cache.js +56 -0
- package/dist/bridge/quote-cache.js.map +1 -0
- package/dist/bridge/reply.d.ts +31 -0
- package/dist/bridge/reply.d.ts.map +1 -0
- package/dist/bridge/reply.js +122 -0
- package/dist/bridge/reply.js.map +1 -0
- package/dist/bridge/space-identity.d.ts +43 -0
- package/dist/bridge/space-identity.d.ts.map +1 -0
- package/dist/bridge/space-identity.js +92 -0
- package/dist/bridge/space-identity.js.map +1 -0
- package/dist/bridge/space-sync.d.ts +94 -0
- package/dist/bridge/space-sync.d.ts.map +1 -0
- package/dist/bridge/space-sync.js +137 -0
- package/dist/bridge/space-sync.js.map +1 -0
- package/dist/bridge/turn-commands.d.ts +28 -0
- package/dist/bridge/turn-commands.d.ts.map +1 -0
- package/dist/bridge/turn-commands.js +97 -0
- package/dist/bridge/turn-commands.js.map +1 -0
- package/dist/cli/config-store.d.ts +32 -0
- package/dist/cli/config-store.d.ts.map +1 -0
- package/dist/cli/config-store.js +118 -0
- package/dist/cli/config-store.js.map +1 -0
- package/dist/cli/crypto-store.d.ts +42 -0
- package/dist/cli/crypto-store.d.ts.map +1 -0
- package/dist/cli/crypto-store.js +70 -0
- package/dist/cli/crypto-store.js.map +1 -0
- package/dist/cli/device-prune.d.ts +105 -0
- package/dist/cli/device-prune.d.ts.map +1 -0
- package/dist/cli/device-prune.js +163 -0
- package/dist/cli/device-prune.js.map +1 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +584 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/log-filter.d.ts +32 -0
- package/dist/cli/log-filter.d.ts.map +1 -0
- package/dist/cli/log-filter.js +40 -0
- package/dist/cli/log-filter.js.map +1 -0
- package/dist/cli/pnpm-builds.d.ts +32 -0
- package/dist/cli/pnpm-builds.d.ts.map +1 -0
- package/dist/cli/pnpm-builds.js +73 -0
- package/dist/cli/pnpm-builds.js.map +1 -0
- package/dist/cli/profile-patch.d.ts +26 -0
- package/dist/cli/profile-patch.d.ts.map +1 -0
- package/dist/cli/profile-patch.js +56 -0
- package/dist/cli/profile-patch.js.map +1 -0
- package/dist/cli/setup.d.ts +39 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +234 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli/systemd-hint.d.ts +11 -0
- package/dist/cli/systemd-hint.d.ts.map +1 -0
- package/dist/cli/systemd-hint.js +46 -0
- package/dist/cli/systemd-hint.js.map +1 -0
- package/dist/cli/systemd.d.ts +32 -0
- package/dist/cli/systemd.d.ts.map +1 -0
- package/dist/cli/systemd.js +58 -0
- package/dist/cli/systemd.js.map +1 -0
- package/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +107 -0
- package/dist/config.js.map +1 -0
- package/dist/dsh/backend.d.ts +110 -0
- package/dist/dsh/backend.d.ts.map +1 -0
- package/dist/dsh/backend.js +481 -0
- package/dist/dsh/backend.js.map +1 -0
- package/dist/dsh/interactions.d.ts +50 -0
- package/dist/dsh/interactions.d.ts.map +1 -0
- package/dist/dsh/interactions.js +141 -0
- package/dist/dsh/interactions.js.map +1 -0
- package/dist/dsh/stream.d.ts +32 -0
- package/dist/dsh/stream.d.ts.map +1 -0
- package/dist/dsh/stream.js +109 -0
- package/dist/dsh/stream.js.map +1 -0
- package/dist/formatting.d.ts +14 -0
- package/dist/formatting.d.ts.map +1 -0
- package/dist/formatting.js +63 -0
- package/dist/formatting.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +232 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +28 -0
- package/dist/logger.js.map +1 -0
- package/dist/matrix/matrix-events.d.ts +49 -0
- package/dist/matrix/matrix-events.d.ts.map +1 -0
- package/dist/matrix/matrix-events.js +89 -0
- package/dist/matrix/matrix-events.js.map +1 -0
- package/dist/matrix/transport.d.ts +192 -0
- package/dist/matrix/transport.d.ts.map +1 -0
- package/dist/matrix/transport.js +510 -0
- package/dist/matrix/transport.js.map +1 -0
- package/dist/ports/attachments.d.ts +51 -0
- package/dist/ports/attachments.d.ts.map +1 -0
- package/dist/ports/attachments.js +27 -0
- package/dist/ports/attachments.js.map +1 -0
- package/dist/ports/backend.d.ts +159 -0
- package/dist/ports/backend.d.ts.map +1 -0
- package/dist/ports/backend.js +25 -0
- package/dist/ports/backend.js.map +1 -0
- package/dist/ports/interactions.d.ts +65 -0
- package/dist/ports/interactions.d.ts.map +1 -0
- package/dist/ports/interactions.js +15 -0
- package/dist/ports/interactions.js.map +1 -0
- package/dist/ports/streaming.d.ts +45 -0
- package/dist/ports/streaming.d.ts.map +1 -0
- package/dist/ports/streaming.js +23 -0
- package/dist/ports/streaming.js.map +1 -0
- package/dist/ports/transport.d.ts +68 -0
- package/dist/ports/transport.d.ts.map +1 -0
- package/dist/ports/transport.js +2 -0
- package/dist/ports/transport.js.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/** 宽松归一化:字段以问题服务实际送来的为准,缺啥用啥,绝不崩在解析上。 */
|
|
2
|
+
function normalizeQuestions(raw) {
|
|
3
|
+
if (!Array.isArray(raw))
|
|
4
|
+
return [];
|
|
5
|
+
const out = [];
|
|
6
|
+
raw.forEach((entry, i) => {
|
|
7
|
+
if (typeof entry !== 'object' || entry === null)
|
|
8
|
+
return;
|
|
9
|
+
const q = entry;
|
|
10
|
+
const options = Array.isArray(q.options)
|
|
11
|
+
? q.options.flatMap((o) => {
|
|
12
|
+
if (typeof o !== 'object' || o === null)
|
|
13
|
+
return [];
|
|
14
|
+
const opt = o;
|
|
15
|
+
if (typeof opt.label !== 'string')
|
|
16
|
+
return [];
|
|
17
|
+
return [{ label: opt.label, ...(typeof opt.description === 'string' ? { description: opt.description } : {}) }];
|
|
18
|
+
})
|
|
19
|
+
: undefined;
|
|
20
|
+
out.push({
|
|
21
|
+
id: typeof q.id === 'string' ? q.id : `q${i}`,
|
|
22
|
+
question: typeof q.question === 'string' ? q.question : '',
|
|
23
|
+
...(typeof q.detail === 'string' ? { detail: q.detail } : {}),
|
|
24
|
+
...(typeof q.header === 'string' ? { header: q.header } : {}),
|
|
25
|
+
...(options && options.length > 0 ? { options } : {}),
|
|
26
|
+
...(q.multiSelect === true ? { multiSelect: true } : {}),
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
function bridgeSessionOf(agent, opts) {
|
|
32
|
+
const sessionId = agent?.session?.id;
|
|
33
|
+
if (typeof sessionId !== 'string')
|
|
34
|
+
return undefined;
|
|
35
|
+
return opts.roomForSession(sessionId) ? sessionId : undefined;
|
|
36
|
+
}
|
|
37
|
+
export function createDshInteractionSource(ctx, opts) {
|
|
38
|
+
const questionSubs = new Map();
|
|
39
|
+
const approvalSubs = new Map();
|
|
40
|
+
let subSeq = 0;
|
|
41
|
+
let questionDisposer;
|
|
42
|
+
let approvalDisposer;
|
|
43
|
+
function claimQuestion(request, sessionId) {
|
|
44
|
+
const questions = normalizeQuestions(request.questions);
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
let settled = false;
|
|
47
|
+
const skip = () => questions.map((q) => ({ id: q.id, selected: [] }));
|
|
48
|
+
const respond = (answers) => {
|
|
49
|
+
if (settled)
|
|
50
|
+
return;
|
|
51
|
+
settled = true;
|
|
52
|
+
resolve({ answers });
|
|
53
|
+
};
|
|
54
|
+
// 上游 abort:waterfall 调用方已经不等了,这里兑现跳过答案纯粹为了不悬挂 promise。
|
|
55
|
+
request.signal?.addEventListener('abort', () => {
|
|
56
|
+
if (!settled) {
|
|
57
|
+
settled = true;
|
|
58
|
+
resolve({ answers: skip() });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
for (const sub of questionSubs.values())
|
|
62
|
+
sub({ sessionId, questions, ...(request.signal ? { signal: request.signal } : {}) }, respond);
|
|
63
|
+
if (questionSubs.size === 0) {
|
|
64
|
+
settled = true;
|
|
65
|
+
resolve({ answers: skip() });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function claimApproval(request, sessionId) {
|
|
70
|
+
const toolName = typeof request.toolName === 'string' ? request.toolName : '(unknown tool)';
|
|
71
|
+
const event = {
|
|
72
|
+
sessionId,
|
|
73
|
+
toolName,
|
|
74
|
+
...(typeof request.reason === 'string' ? { reason: request.reason } : {}),
|
|
75
|
+
...(typeof request.callId === 'string' ? { callId: request.callId } : {}),
|
|
76
|
+
...(request.signal ? { signal: request.signal } : {}),
|
|
77
|
+
};
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
let settled = false;
|
|
80
|
+
const respond = (outcome) => {
|
|
81
|
+
if (settled)
|
|
82
|
+
return;
|
|
83
|
+
settled = true;
|
|
84
|
+
resolve(outcome);
|
|
85
|
+
};
|
|
86
|
+
request.signal?.addEventListener('abort', () => {
|
|
87
|
+
if (!settled) {
|
|
88
|
+
settled = true;
|
|
89
|
+
resolve('cancelled');
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
for (const sub of approvalSubs.values())
|
|
93
|
+
sub(event, respond);
|
|
94
|
+
if (approvalSubs.size === 0) {
|
|
95
|
+
settled = true;
|
|
96
|
+
resolve('cancelled');
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
onRequestQuestion(cb) {
|
|
102
|
+
if (questionSubs.size === 0) {
|
|
103
|
+
questionDisposer = ctx.on('user-questions/request', (request, next) => {
|
|
104
|
+
const sessionId = bridgeSessionOf(request.agent, opts);
|
|
105
|
+
if (!sessionId)
|
|
106
|
+
return next();
|
|
107
|
+
return claimQuestion(request, sessionId);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const id = subSeq++;
|
|
111
|
+
questionSubs.set(id, cb);
|
|
112
|
+
return () => {
|
|
113
|
+
questionSubs.delete(id);
|
|
114
|
+
if (questionSubs.size === 0) {
|
|
115
|
+
questionDisposer?.();
|
|
116
|
+
questionDisposer = undefined;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
onRequestApproval(cb) {
|
|
121
|
+
if (approvalSubs.size === 0) {
|
|
122
|
+
approvalDisposer = ctx.on('approval/request', (request, next) => {
|
|
123
|
+
const sessionId = bridgeSessionOf(request.agent, opts);
|
|
124
|
+
if (!sessionId)
|
|
125
|
+
return next();
|
|
126
|
+
return claimApproval(request, sessionId);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const id = subSeq++;
|
|
130
|
+
approvalSubs.set(id, cb);
|
|
131
|
+
return () => {
|
|
132
|
+
approvalSubs.delete(id);
|
|
133
|
+
if (approvalSubs.size === 0) {
|
|
134
|
+
approvalDisposer?.();
|
|
135
|
+
approvalDisposer = undefined;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=interactions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions.js","sourceRoot":"","sources":["../../src/dsh/interactions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T7 DSH adapter: implements TurnStreamSource on the root
|
|
3
|
+
* `agent/assistant-stream` event. The payload shape is verified against
|
|
4
|
+
* dsh-agent@0.1.5 `lib/types/runtime-types.d.ts`:
|
|
5
|
+
*
|
|
6
|
+
* payload = { agent, frame }
|
|
7
|
+
* frame = {type:'start', attemptId, revision, turn, step}
|
|
8
|
+
* | {type:'chunk', attemptId, revision, index /* dense from 0 *\/, time, chunk: StreamChunk}
|
|
9
|
+
* | {type:'end', attemptId, revision, index /* next position *\/,
|
|
10
|
+
* outcome: {kind:'committed', eventType, seq} | {kind:'abandoned'}}
|
|
11
|
+
*
|
|
12
|
+
* Only `chunk` frames whose `chunk` is a dsh-llm `text-delta`
|
|
13
|
+
* (`{type:'text-delta', index, text: string}`, types.d.ts) become
|
|
14
|
+
* onTextDelta - `reasoning-delta` also carries a `text` field, so the type
|
|
15
|
+
* check is what keeps private reasoning out of the room. An `end` frame
|
|
16
|
+
* settles ONE model attempt, never the turn (a turn is many attempts in a
|
|
17
|
+
* tool loop), so it maps to no onTurnEnd here; `abandoned` maps to
|
|
18
|
+
* onAttemptAbandoned so retry content can be rewound. Everything is
|
|
19
|
+
* defensive: this listener runs inside the harness process and must never
|
|
20
|
+
* throw (US42).
|
|
21
|
+
*
|
|
22
|
+
* The root listener lives only while someone is subscribed, mirroring the
|
|
23
|
+
* T5 interaction-source pattern; Cordis also unwinds it with the fiber.
|
|
24
|
+
*/
|
|
25
|
+
import type { TurnStreamSource } from '../ports/streaming.ts';
|
|
26
|
+
import type { Logger } from '../types.ts';
|
|
27
|
+
/** The minimal structural view of the root context this adapter consumes. */
|
|
28
|
+
export interface AssistantStreamEventsLike {
|
|
29
|
+
on(name: 'agent/assistant-stream', listener: (payload: unknown) => void): () => boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare function createDshTurnStream(ctx: AssistantStreamEventsLike, logger: Logger): TurnStreamSource;
|
|
32
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/dsh/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACjF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,6EAA6E;AAC7E,MAAM,WAAW,yBAAyB;IACxC,EAAE,CACA,IAAI,EAAE,wBAAwB,EAC9B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GACnC,MAAM,OAAO,CAAA;CACjB;AAkBD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,yBAAyB,EAC9B,MAAM,EAAE,MAAM,GACb,gBAAgB,CAoGlB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export function createDshTurnStream(ctx, logger) {
|
|
2
|
+
const subs = new Map();
|
|
3
|
+
const attempts = new Map();
|
|
4
|
+
let rootDisposer;
|
|
5
|
+
const route = (sessionId, fn) => {
|
|
6
|
+
for (const h of [...(subs.get(sessionId) ?? [])])
|
|
7
|
+
fn(h);
|
|
8
|
+
};
|
|
9
|
+
const openAttempt = (sessionId, attemptId) => {
|
|
10
|
+
const state = { attemptId, nextIndex: 0 };
|
|
11
|
+
attempts.set(sessionId, state);
|
|
12
|
+
route(sessionId, (h) => h.onAttemptStart?.());
|
|
13
|
+
return state;
|
|
14
|
+
};
|
|
15
|
+
function onFrame(payload) {
|
|
16
|
+
try {
|
|
17
|
+
const p = payload;
|
|
18
|
+
const sessionId = p?.agent?.session?.id;
|
|
19
|
+
if (typeof sessionId !== 'string')
|
|
20
|
+
return;
|
|
21
|
+
if (!subs.has(sessionId))
|
|
22
|
+
return; // not a bridge turn in flight: cheap exit
|
|
23
|
+
const frame = p?.frame;
|
|
24
|
+
if (!frame || typeof frame.type !== 'string')
|
|
25
|
+
return;
|
|
26
|
+
// Every real frame names its attempt (LlmAttemptId is a branded string);
|
|
27
|
+
// anything else is garbage and must not open attempt state.
|
|
28
|
+
if (typeof frame.attemptId !== 'string')
|
|
29
|
+
return;
|
|
30
|
+
switch (frame.type) {
|
|
31
|
+
case 'start':
|
|
32
|
+
openAttempt(sessionId, frame.attemptId);
|
|
33
|
+
break;
|
|
34
|
+
case 'chunk': {
|
|
35
|
+
let state = attempts.get(sessionId);
|
|
36
|
+
if (!state || state.attemptId !== frame.attemptId) {
|
|
37
|
+
// missed start frame (or a replacement attempt): open defensively
|
|
38
|
+
state = openAttempt(sessionId, frame.attemptId);
|
|
39
|
+
}
|
|
40
|
+
const index = typeof frame.index === 'number' ? frame.index : state.nextIndex;
|
|
41
|
+
if (index < state.nextIndex)
|
|
42
|
+
return; // stale/replay - the room already has it
|
|
43
|
+
state.nextIndex = index + 1;
|
|
44
|
+
const chunk = frame.chunk;
|
|
45
|
+
if (chunk
|
|
46
|
+
&& chunk.type === 'text-delta'
|
|
47
|
+
&& typeof chunk.text === 'string'
|
|
48
|
+
&& chunk.text.length > 0) {
|
|
49
|
+
const text = chunk.text;
|
|
50
|
+
route(sessionId, (h) => h.onTextDelta(text));
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case 'end': {
|
|
55
|
+
const state = attempts.get(sessionId);
|
|
56
|
+
if (state && frame.attemptId !== undefined && state.attemptId !== frame.attemptId)
|
|
57
|
+
break;
|
|
58
|
+
attempts.delete(sessionId);
|
|
59
|
+
if (frame.outcome?.kind === 'abandoned') {
|
|
60
|
+
route(sessionId, (h) => h.onAttemptAbandoned?.());
|
|
61
|
+
}
|
|
62
|
+
// committed: content stays streamed; the TURN still runs.
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
default:
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
logger.warn('assistant-stream frame failed:', error instanceof Error ? error.message : error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
subscribe(sessionId, handlers) {
|
|
75
|
+
const list = subs.get(sessionId) ?? [];
|
|
76
|
+
list.push(handlers);
|
|
77
|
+
subs.set(sessionId, list);
|
|
78
|
+
if (!rootDisposer)
|
|
79
|
+
rootDisposer = ctx.on('agent/assistant-stream', onFrame);
|
|
80
|
+
let released = false;
|
|
81
|
+
return () => {
|
|
82
|
+
if (released)
|
|
83
|
+
return;
|
|
84
|
+
released = true;
|
|
85
|
+
const live = subs.get(sessionId);
|
|
86
|
+
if (live) {
|
|
87
|
+
const i = live.indexOf(handlers);
|
|
88
|
+
if (i >= 0)
|
|
89
|
+
live.splice(i, 1);
|
|
90
|
+
if (live.length === 0) {
|
|
91
|
+
subs.delete(sessionId);
|
|
92
|
+
attempts.delete(sessionId);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (subs.size === 0 && rootDisposer) {
|
|
96
|
+
const dispose = rootDisposer;
|
|
97
|
+
rootDisposer = undefined;
|
|
98
|
+
try {
|
|
99
|
+
dispose();
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
logger.warn('assistant-stream dispose failed:', error instanceof Error ? error.message : error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/dsh/stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text extraction and message formatting helpers.
|
|
3
|
+
* Ported from pi-courier src/formatting.ts (MIT); AssistantMessage swapped
|
|
4
|
+
* for the structural content-part shape both pi and DSH produce.
|
|
5
|
+
*/
|
|
6
|
+
/** Join text-bearing parts of a message content array. */
|
|
7
|
+
export declare function extractTextFromParts(parts: readonly unknown[]): string;
|
|
8
|
+
/** Format tool-call summaries for the remote user (🔧 `name` (k=v, …)). */
|
|
9
|
+
export declare function formatToolCalls(parts: readonly unknown[]): string;
|
|
10
|
+
/** Truncate string to max length with ellipsis. */
|
|
11
|
+
export declare function truncate(str: string, maxLen: number): string;
|
|
12
|
+
/** Split long messages into chunks, breaking at newlines when possible. */
|
|
13
|
+
export declare function splitMessage(text: string, maxLen: number): string[];
|
|
14
|
+
//# sourceMappingURL=formatting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../src/formatting.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,0DAA0D;AAC1D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAKtE;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAgBjE;AAED,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI5D;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAyBnE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text extraction and message formatting helpers.
|
|
3
|
+
* Ported from pi-courier src/formatting.ts (MIT); AssistantMessage swapped
|
|
4
|
+
* for the structural content-part shape both pi and DSH produce.
|
|
5
|
+
*/
|
|
6
|
+
/** Join text-bearing parts of a message content array. */
|
|
7
|
+
export function extractTextFromParts(parts) {
|
|
8
|
+
return parts
|
|
9
|
+
.filter((p) => p?.type === 'text' && typeof p.text === 'string')
|
|
10
|
+
.map((p) => p.text)
|
|
11
|
+
.join('\n');
|
|
12
|
+
}
|
|
13
|
+
/** Format tool-call summaries for the remote user (🔧 `name` (k=v, …)). */
|
|
14
|
+
export function formatToolCalls(parts) {
|
|
15
|
+
const toolCalls = parts.filter((p) => p?.type === 'toolCall');
|
|
16
|
+
if (toolCalls.length === 0)
|
|
17
|
+
return '';
|
|
18
|
+
return toolCalls
|
|
19
|
+
.map((tc) => {
|
|
20
|
+
const name = tc.name || 'tool';
|
|
21
|
+
const args = (tc.arguments ?? tc.input ?? {});
|
|
22
|
+
const argPairs = Object.entries(args)
|
|
23
|
+
.map(([k, v]) => {
|
|
24
|
+
const valStr = typeof v === 'string' ? v : JSON.stringify(v);
|
|
25
|
+
return `${k}=${truncate(valStr, 50)}`;
|
|
26
|
+
})
|
|
27
|
+
.join(', ');
|
|
28
|
+
return argPairs ? `🔧 \`${name}\` (${argPairs})` : `🔧 \`${name}\``;
|
|
29
|
+
})
|
|
30
|
+
.join('\n');
|
|
31
|
+
}
|
|
32
|
+
/** Truncate string to max length with ellipsis. */
|
|
33
|
+
export function truncate(str, maxLen) {
|
|
34
|
+
if (!str)
|
|
35
|
+
return '';
|
|
36
|
+
if (str.length <= maxLen)
|
|
37
|
+
return str;
|
|
38
|
+
return str.substring(0, maxLen - 3) + '...';
|
|
39
|
+
}
|
|
40
|
+
/** Split long messages into chunks, breaking at newlines when possible. */
|
|
41
|
+
export function splitMessage(text, maxLen) {
|
|
42
|
+
if (text.length <= maxLen)
|
|
43
|
+
return [text];
|
|
44
|
+
const chunks = [];
|
|
45
|
+
let remaining = text;
|
|
46
|
+
while (remaining.length > 0) {
|
|
47
|
+
if (remaining.length <= maxLen) {
|
|
48
|
+
chunks.push(remaining);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
let breakAt = remaining.lastIndexOf('\n', maxLen);
|
|
52
|
+
if (breakAt < maxLen * 0.5) {
|
|
53
|
+
breakAt = remaining.lastIndexOf(' ', maxLen);
|
|
54
|
+
}
|
|
55
|
+
if (breakAt < maxLen * 0.3) {
|
|
56
|
+
breakAt = maxLen;
|
|
57
|
+
}
|
|
58
|
+
chunks.push(remaining.substring(0, breakAt));
|
|
59
|
+
remaining = remaining.substring(breakAt).trimStart();
|
|
60
|
+
}
|
|
61
|
+
return chunks;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=formatting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.js","sourceRoot":"","sources":["../src/formatting.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;;;;eAuB/B,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;;AAJ3E,wBA6NC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-matrix plugin entry: a Cordis host-plane plugin that boots the Matrix
|
|
3
|
+
* bridge inside a DSH profile (dsh-base + this bundle, spike-verified).
|
|
4
|
+
*
|
|
5
|
+
* Mount: `dsh plugin --profile matrix add dsh-matrix` then override the
|
|
6
|
+
* `matrix-bridge` row's config in the profile's own cordis.patch.yml
|
|
7
|
+
* (homeserver / credentials / trustedUsers / workdir). Password lives in the
|
|
8
|
+
* profile file (chmod 600), never in this package.
|
|
9
|
+
*/
|
|
10
|
+
import * as os from 'node:os';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { loadConfig } from "./config.js";
|
|
13
|
+
import { createLogger } from "./logger.js";
|
|
14
|
+
import { createBridge } from "./bridge/pipeline.js";
|
|
15
|
+
import { createCommandRouter } from "./bridge/agent-commands.js";
|
|
16
|
+
import { createInteractions } from "./bridge/interactions.js";
|
|
17
|
+
import { createDshInteractionSource } from "./dsh/interactions.js";
|
|
18
|
+
import { createDshTurnStream } from "./dsh/stream.js";
|
|
19
|
+
import { JsonFileStore } from "./auth/store.js";
|
|
20
|
+
import { ChallengeEngine } from "./auth/challenge.js";
|
|
21
|
+
import { MatrixTransport } from "./matrix/transport.js";
|
|
22
|
+
import { DshBackend } from "./dsh/backend.js";
|
|
23
|
+
import { ProjectMap } from "./bridge/projects.js";
|
|
24
|
+
import { createMultiProjectWiring } from "./bridge/multi-project.js";
|
|
25
|
+
import { demoteUserEverywhere, elevateTrustedInRoom, healPowerLevels } from "./bridge/power-sync.js";
|
|
26
|
+
import { healSpaceIdentity } from "./bridge/space-sync.js";
|
|
27
|
+
import { isSpaceMode } from "./bridge/space-identity.js";
|
|
28
|
+
import { acquireInstanceLock } from "./bridge/instance-lock.js";
|
|
29
|
+
export default {
|
|
30
|
+
name: 'dsh-matrix',
|
|
31
|
+
// Hard dependency: without live agents there is nothing to bridge to.
|
|
32
|
+
inject: ['agents'],
|
|
33
|
+
async apply(ctx, config) {
|
|
34
|
+
const cfg = loadConfig(config ?? {});
|
|
35
|
+
const logger = createLogger(cfg.logLevel);
|
|
36
|
+
const dataDir = cfg.dataDir ?? path.join(process.env.DSH_HOME ?? path.join(os.homedir(), '.dsh'), 'dsh-matrix');
|
|
37
|
+
// 规格实现决策 10(lock.ts):同一个 Matrix 账号只允许一个桥实例,
|
|
38
|
+
// 否则两个进程会双回帖、互相抢会话。抢不到直接抛错 —— 这是重复启动的
|
|
39
|
+
// 配置错误,不是网络抖动,不该被下面的退避重试掩盖。
|
|
40
|
+
const instanceLock = acquireInstanceLock(path.join(dataDir, 'bridge.lock'));
|
|
41
|
+
logger.info('🔒 已获取单实例锁: ' + instanceLock.path);
|
|
42
|
+
const transport = new MatrixTransport({
|
|
43
|
+
homeserver: cfg.homeserver,
|
|
44
|
+
...(cfg.username ? { username: cfg.username } : {}),
|
|
45
|
+
...(cfg.password ? { password: cfg.password } : {}),
|
|
46
|
+
...(cfg.accessToken ? { accessToken: cfg.accessToken } : {}),
|
|
47
|
+
...(typeof cfg.encryption === 'boolean' ? { encryption: cfg.encryption } : {}),
|
|
48
|
+
storePath: path.join(dataDir, 'matrix-store.json'),
|
|
49
|
+
cryptoPath: path.join(dataDir, 'matrix-crypto'),
|
|
50
|
+
});
|
|
51
|
+
const backend = new DshBackend(ctx, {
|
|
52
|
+
logger,
|
|
53
|
+
...(cfg.provider ? { provider: cfg.provider } : {}),
|
|
54
|
+
...(cfg.model ? { model: cfg.model } : {}),
|
|
55
|
+
// T6: 附件兜底落盘目录(ctx.attachments 服务不可用时才写这里)。
|
|
56
|
+
attachmentsDir: cfg.attachments.dir ?? path.join(dataDir, 'attachments'),
|
|
57
|
+
});
|
|
58
|
+
// Runtime auth: persisted trust list + challenge engine. The code itself
|
|
59
|
+
// is logged host-side only; replying with it grants trust (US 30).
|
|
60
|
+
const store = new JsonFileStore(path.join(dataDir, 'auth.json'), {
|
|
61
|
+
onError: (e) => logger.warn('auth store:', e),
|
|
62
|
+
});
|
|
63
|
+
await store.load();
|
|
64
|
+
const challenge = new ChallengeEngine(store, {
|
|
65
|
+
seedAdmin: cfg.trustedUsers[0],
|
|
66
|
+
onCode: (userId, code) => logger.info(`🔐 [challenge] ${userId} 的验证码: ${code}`),
|
|
67
|
+
notify: (message, level) => (level === 'warn' ? logger.warn(message) : logger.info(message)),
|
|
68
|
+
});
|
|
69
|
+
// T9 多项目:房间→项目映射持久层 + 管理房间收养 + /pmctl 挂点。
|
|
70
|
+
// 单项目模式下 wiring 只给 resolveCwd(恒=workdir),不装 multiProject,
|
|
71
|
+
// pipeline 现行为逐条不变。config.projects/managementRooms 作 boot 种子,
|
|
72
|
+
// 持久层已存在的项赢(重启不覆盖运行时改动)。
|
|
73
|
+
let projectMap;
|
|
74
|
+
if (cfg.multiProject) {
|
|
75
|
+
projectMap = new ProjectMap({
|
|
76
|
+
filePath: path.join(dataDir, 'projects.json'),
|
|
77
|
+
projectRoot: cfg.workdir,
|
|
78
|
+
onError: (e) => logger.warn('projects store:', e),
|
|
79
|
+
});
|
|
80
|
+
await projectMap.load();
|
|
81
|
+
projectMap.seedFromConfig(cfg.projects, cfg.managementRooms);
|
|
82
|
+
}
|
|
83
|
+
// T12(US37):"当前可信的人" = 配置快照 ∪ 运行时名单(challenge 认证加进来的人)。
|
|
84
|
+
const effectiveTrusted = () => [...new Set([...cfg.trustedUsers, ...store.get().trustedUsers])];
|
|
85
|
+
// T12(US38):space 的已认领状态(以持久层为准,config 只作 boot 种子)。
|
|
86
|
+
// 提前取出来,是因为"建房挂钩"也要用它 —— 新房间必须**立刻**进 space 带头像,
|
|
87
|
+
// 而不是等下次启动对账(票面 e2e 明确要求"建房 → 自动进 space 且带头像")。
|
|
88
|
+
const spaceState = projectMap?.spaceIdentity();
|
|
89
|
+
if (spaceState && !spaceState.roomId && cfg.space?.roomId)
|
|
90
|
+
spaceState.roomId = cfg.space.roomId;
|
|
91
|
+
if (spaceState && spaceState.avatarPoolVersion === undefined && cfg.space?.avatarPoolVersion !== undefined) {
|
|
92
|
+
spaceState.avatarPoolVersion = cfg.space.avatarPoolVersion;
|
|
93
|
+
}
|
|
94
|
+
const instanceName = cfg.instanceName ?? os.hostname();
|
|
95
|
+
const spaceMode = isSpaceMode(cfg.space);
|
|
96
|
+
// 建房后三件事:按账本提权(US37)、进 space、挂头像(US38)。
|
|
97
|
+
// 全部尽力而为:失败不拦建房(pmctl 会回一句提示),下次启动对账还会再补。
|
|
98
|
+
const onRoomCreated = projectMap
|
|
99
|
+
? async (roomId) => {
|
|
100
|
+
let changed = false;
|
|
101
|
+
const elevated = await elevateTrustedInRoom(roomId, effectiveTrusted(), projectMap.powerLedger(), transport, logger);
|
|
102
|
+
changed = elevated.elevated.length > 0;
|
|
103
|
+
if (spaceState && spaceMode) {
|
|
104
|
+
const projectName = projectMap.get(roomId)?.name ?? roomId;
|
|
105
|
+
const healed = await healSpaceIdentity({ instanceName, rooms: [{ roomId, target: { kind: 'pool', name: projectName } }] }, spaceState, transport, logger);
|
|
106
|
+
changed = changed || healed.spaceCreated || healed.avatarsSet.length > 0 || healed.childrenAdded.length > 0;
|
|
107
|
+
}
|
|
108
|
+
if (changed)
|
|
109
|
+
await projectMap.save();
|
|
110
|
+
}
|
|
111
|
+
: undefined;
|
|
112
|
+
const wiring = createMultiProjectWiring({
|
|
113
|
+
transport,
|
|
114
|
+
backend,
|
|
115
|
+
logger,
|
|
116
|
+
multiProject: cfg.multiProject,
|
|
117
|
+
instanceName: cfg.instanceName ?? os.hostname(),
|
|
118
|
+
defaultWorkdir: cfg.workdir,
|
|
119
|
+
...(projectMap ? { map: projectMap } : {}),
|
|
120
|
+
...(onRoomCreated ? { onRoomCreated } : {}),
|
|
121
|
+
});
|
|
122
|
+
// T4: bridge command surface (/model /help /sessions … + DSH passthrough).
|
|
123
|
+
const commandRouter = createCommandRouter({ backend, transport, logger });
|
|
124
|
+
// T5: questions & approvals into the room. Ownership = sessions the
|
|
125
|
+
// bridge itself opened (roomIdForSession); anything else is yielded
|
|
126
|
+
// (next()) so the Web answerer keeps working untouched.
|
|
127
|
+
const source = createDshInteractionSource(ctx, {
|
|
128
|
+
roomForSession: (sessionId) => backend.roomIdForSession(sessionId),
|
|
129
|
+
logger,
|
|
130
|
+
});
|
|
131
|
+
const interactions = createInteractions({
|
|
132
|
+
transport,
|
|
133
|
+
logger,
|
|
134
|
+
source,
|
|
135
|
+
roomForSession: (sessionId) => backend.roomIdForSession(sessionId),
|
|
136
|
+
});
|
|
137
|
+
// T7: streaming replies (US2). Only mounted when `streamReplies: true`;
|
|
138
|
+
// otherwise the pipeline keeps the T1 one-shot reply byte-for-byte.
|
|
139
|
+
const turnStream = cfg.streamReplies === true
|
|
140
|
+
? createDshTurnStream(ctx, logger)
|
|
141
|
+
: undefined;
|
|
142
|
+
// T12(US37):提权账本的三个动作都在这里落地(规则在 power-sync,本层只负责
|
|
143
|
+
// "改完存盘")。没有 ProjectMap(单项目模式)就没有账本 → 不注入,行为不变。
|
|
144
|
+
const power = projectMap
|
|
145
|
+
? {
|
|
146
|
+
revoke: async (userId) => {
|
|
147
|
+
const r = await demoteUserEverywhere(userId, projectMap.powerLedger(), transport, logger);
|
|
148
|
+
if (r.demoted.length + r.forgotten.length > 0)
|
|
149
|
+
await projectMap.save();
|
|
150
|
+
return { demoted: r.demoted.length, failures: r.failures.length };
|
|
151
|
+
},
|
|
152
|
+
heal: async () => {
|
|
153
|
+
const rooms = [...projectMap.getManagementRooms(), ...projectMap.list().map(([roomId]) => roomId)];
|
|
154
|
+
const r = await healPowerLevels(rooms, effectiveTrusted(), projectMap.powerLedger(), transport, logger);
|
|
155
|
+
if (r.elevated.length + r.demoted.length + r.forgotten.length > 0)
|
|
156
|
+
await projectMap.save();
|
|
157
|
+
return { elevated: r.elevated.length, demoted: r.demoted.length, failures: r.failures.length };
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
: undefined;
|
|
161
|
+
// T12(US38):space 归集 + 头像自愈。没开空间模式 / 没有 ProjectMap → 不注入,
|
|
162
|
+
// 行为与 T12 之前逐条一致。已认领状态以持久层为准,config 里的值只作 boot 种子。
|
|
163
|
+
const space = projectMap && spaceState && spaceMode
|
|
164
|
+
? {
|
|
165
|
+
heal: async () => {
|
|
166
|
+
const rooms = [
|
|
167
|
+
...projectMap.getManagementRooms().map((roomId) => ({ roomId, target: { kind: 'management' } })),
|
|
168
|
+
...projectMap.list().map(([roomId, entry]) => ({
|
|
169
|
+
roomId,
|
|
170
|
+
target: { kind: 'pool', name: entry.name ?? roomId },
|
|
171
|
+
})),
|
|
172
|
+
];
|
|
173
|
+
const r = await healSpaceIdentity({ instanceName, rooms }, spaceState, transport, logger);
|
|
174
|
+
if (r.spaceCreated || r.avatarsSet.length > 0 || r.childrenAdded.length > 0 || r.failures.length > 0) {
|
|
175
|
+
await projectMap.save();
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
spaceCreated: r.spaceCreated,
|
|
179
|
+
avatarsSet: r.avatarsSet.length,
|
|
180
|
+
childrenAdded: r.childrenAdded.length,
|
|
181
|
+
failures: r.failures.length,
|
|
182
|
+
};
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
: undefined;
|
|
186
|
+
const bridge = createBridge({
|
|
187
|
+
transport,
|
|
188
|
+
backend,
|
|
189
|
+
logger,
|
|
190
|
+
trustedUsers: cfg.trustedUsers,
|
|
191
|
+
workdir: cfg.workdir,
|
|
192
|
+
resolveCwd: wiring.resolveCwd,
|
|
193
|
+
...(power ? { power } : {}),
|
|
194
|
+
...(space ? { space } : {}),
|
|
195
|
+
...(wiring.multiProject ? { multiProject: wiring.multiProject } : {}),
|
|
196
|
+
maxChunk: cfg.maxChunkChars,
|
|
197
|
+
attachments: { maxMb: cfg.attachments.maxMb },
|
|
198
|
+
auth: { store, challenge },
|
|
199
|
+
commandRouter,
|
|
200
|
+
intercept: (msg) => interactions.intercept(msg),
|
|
201
|
+
...(turnStream ? { turnStream: () => turnStream } : {}),
|
|
202
|
+
});
|
|
203
|
+
// 桥的启动失败(网络抖动等)绝不能把宿主 profile 带崩:
|
|
204
|
+
// apply 立即返回,后台带退避重试直到连上或 fiber 销毁(US42)。
|
|
205
|
+
let stopped = false;
|
|
206
|
+
ctx.effect(() => () => {
|
|
207
|
+
stopped = true;
|
|
208
|
+
interactions.stop();
|
|
209
|
+
try {
|
|
210
|
+
return bridge.stop();
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
instanceLock.release();
|
|
214
|
+
}
|
|
215
|
+
}, 'dsh-matrix bridge');
|
|
216
|
+
const backoff = [1_000, 5_000, 15_000, 60_000];
|
|
217
|
+
void (async () => {
|
|
218
|
+
for (let attempt = 0; !stopped; attempt++) {
|
|
219
|
+
try {
|
|
220
|
+
await bridge.start();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
const wait = backoff[Math.min(attempt, backoff.length - 1)] ?? 60_000;
|
|
225
|
+
logger.error(`启动失败(第 ${attempt + 1} 次),${wait / 1000}s 后重试:`, error instanceof Error ? error.message : error);
|
|
226
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
})();
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
//# sourceMappingURL=index.js.map
|