dsh-jiuling-remote-mobile 1.0.3 → 1.0.5
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/lib/index.js +48 -13
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -413,8 +413,17 @@ export function apply(ctx) {
|
|
|
413
413
|
const controller = ctx.sessionController;
|
|
414
414
|
if (controller === undefined) return;
|
|
415
415
|
const originalPrompt = controller.prompt.bind(controller);
|
|
416
|
-
|
|
417
|
-
|
|
416
|
+
// ⚠️ **签名必须带上第二个参数 `signal`**(`(request, signal)`)。
|
|
417
|
+
//
|
|
418
|
+
// 官方 `dsh-api-session-controller/lib/index.js:3096` 是
|
|
419
|
+
// `prompt(request, signal) { signal.throwIfAborted(); ... }` —— 它**无条件**
|
|
420
|
+
// 对 `signal` 调 `throwIfAborted()`。我们的包装若只声明 `(request)`,
|
|
421
|
+
// 转发给 `originalPrompt(request)` 时 `signal` 就是 `undefined`,
|
|
422
|
+
// 于是发消息必报:
|
|
423
|
+
// `Cannot read properties of undefined (reading 'throwIfAborted')`
|
|
424
|
+
// 症状是**消息根本发不出去**,而报错文案完全看不出是参数漏传。
|
|
425
|
+
controller.prompt = async (request, signal) => {
|
|
426
|
+
if (!remoteSessions.has(request.sessionId)) return originalPrompt(request, signal);
|
|
418
427
|
const text = (request.content ?? [])
|
|
419
428
|
.filter((part) => part.type === 'text')
|
|
420
429
|
.map((part) => part.text)
|
|
@@ -549,7 +558,7 @@ export function apply(ctx) {
|
|
|
549
558
|
}
|
|
550
559
|
|
|
551
560
|
/**
|
|
552
|
-
*
|
|
561
|
+
* 挑一个**手机本地**的工作区给新建的远程会话用。
|
|
553
562
|
*
|
|
554
563
|
* ## ⚠️ 为什么不能直接用 `process.cwd()`
|
|
555
564
|
*
|
|
@@ -567,24 +576,25 @@ export function apply(ctx) {
|
|
|
567
576
|
* `files/workspace/deepseek-harness/default-workspace`(**更深一层**),
|
|
568
577
|
* 两者不相等,正好踩中这个坑。
|
|
569
578
|
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
572
|
-
*
|
|
579
|
+
* ⚠️ **光把 cwd 设对还不够**:`sessionPaths` 索引只在该注册表启动
|
|
580
|
+
* (`indexHeader`)时建一次,新建的会话**不在索引里** ⇒ `sessionPath(id)`
|
|
581
|
+
* 返回 `undefined` ≠ `record.path`,照样被 getter 过滤掉。
|
|
582
|
+
* 所以创建完必须再 `attachSession()` 一次(见 `createSession`),
|
|
583
|
+
* 它会 `rememberSessionPath()` 把这条补进索引。
|
|
573
584
|
*
|
|
574
585
|
* @param ctx - 宿主 Cordis 上下文。
|
|
575
|
-
* @returns
|
|
586
|
+
* @returns 工作区实体;没有可用工作区时 `undefined`。
|
|
576
587
|
*/
|
|
577
|
-
function
|
|
588
|
+
function localWorkspaceFor(ctx) {
|
|
578
589
|
try {
|
|
579
590
|
const registry = ctx.get?.('workspaceRegistry');
|
|
580
591
|
const all = registry?.list?.() ?? [];
|
|
581
|
-
if (all.length === 0) return
|
|
592
|
+
if (all.length === 0) return undefined;
|
|
582
593
|
const preferredId = registry?.state?.defaultWorkspaceId;
|
|
583
594
|
const chosen = all.find((entity) => entity.id === preferredId) ?? all[0];
|
|
584
|
-
|
|
585
|
-
return typeof path === 'string' && path !== '' ? path : process.cwd();
|
|
595
|
+
return typeof chosen?.path === 'string' && chosen.path !== '' ? chosen : undefined;
|
|
586
596
|
} catch {
|
|
587
|
-
return
|
|
597
|
+
return undefined;
|
|
588
598
|
}
|
|
589
599
|
}
|
|
590
600
|
|
|
@@ -623,7 +633,8 @@ async function handleBridge(ctx, config, io) {
|
|
|
623
633
|
// ⚠️ 手机端 cwd 必须是**手机本地**的绝对路径,绝不把电脑路径传进来
|
|
624
634
|
// (Android 是 posix 语义,`path.posix.isAbsolute('C:/...') === false`,
|
|
625
635
|
// 且官方 createOrAdopt 会 `mkdir(cwd, {recursive:true})` 真去建目录)。
|
|
626
|
-
const
|
|
636
|
+
const workspace = localWorkspaceFor(ctx);
|
|
637
|
+
const cwd = workspace?.path ?? process.cwd();
|
|
627
638
|
// ⚠️ **必须走 `sessionController.create`,不能走 `ctx.sessions.create`。**
|
|
628
639
|
//
|
|
629
640
|
// `ctx.sessions.create()` 只把会话塞进内存 store:持久化层既没
|
|
@@ -641,6 +652,30 @@ async function handleBridge(ctx, config, io) {
|
|
|
641
652
|
throw new Error('sessionController.create 不可用,无法在手机本地建会话');
|
|
642
653
|
}
|
|
643
654
|
await ctx.sessionController.create({ sessionId, cwd });
|
|
655
|
+
// ⚠️ 建完必须**挂到工作区**上,否则前端看不到这个会话。
|
|
656
|
+
//
|
|
657
|
+
// 归属判据是 `dsh-workspace` 的 `sessionIds` getter:
|
|
658
|
+
// `record.sessionIds.filter(id => host.sessionPath(id) === record.path)`。
|
|
659
|
+
// 而 `sessionPaths` 索引只在注册表启动时建一次(`indexHeader`),
|
|
660
|
+
// 新建的会话不在索引里 ⇒ `sessionPath(id)` 是 `undefined` ≠ `record.path`
|
|
661
|
+
// ⇒ 被 getter 过滤掉:侧边栏没有它、composer 判成「没选工作区」而禁用。
|
|
662
|
+
//
|
|
663
|
+
// `attachSession()` 会 `rememberSessionPath()` 把这条补进索引,并写进
|
|
664
|
+
// `record.sessionIds` —— 正是官方「添加工作区」那条路的落点。
|
|
665
|
+
// 它要求 `header.cwd` 的 realpath **等于**工作区 path,所以上面的 cwd
|
|
666
|
+
// 必须取自同一个工作区实体,不能是 `process.cwd()`。
|
|
667
|
+
//
|
|
668
|
+
// ⚠️ 失败不致命(最坏是回到「会话在盘上、界面看不见」的旧症状),
|
|
669
|
+
// 所以只记日志,不让整个创建失败。
|
|
670
|
+
if (workspace !== undefined && typeof workspace.attachSession === 'function') {
|
|
671
|
+
try {
|
|
672
|
+
await workspace.attachSession(sessionId);
|
|
673
|
+
} catch (error) {
|
|
674
|
+
ctx.logger?.warn?.(
|
|
675
|
+
`[dsh-remote-mobile] 会话 ${sessionId} 挂到工作区失败(界面可能看不到它): ${String(error?.message ?? error)}`,
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
644
679
|
try {
|
|
645
680
|
await callRemote(config, 'createSession', { sessionId, cwd: params.path });
|
|
646
681
|
} catch (error) {
|