chore: update core integration cases and runtime helpers
This commit is contained in:
parent
7bf9ed4e40
commit
ee8bfa48fd
@ -80,6 +80,46 @@
|
||||
- 测试连接结果
|
||||
- 是否需要本机服务日志人工对照
|
||||
|
||||
### `MANUAL-ACP-004` 账号同步返回 `bridge_auth_token_unavailable`
|
||||
|
||||
- 前置条件
|
||||
- 已登录 `svc.plus` 账号
|
||||
- 账户侧能正常拉起 session
|
||||
- 本地 App 可访问 `https://accounts.svc.plus`
|
||||
- 典型现象
|
||||
- 设置页顶部与账号面板显示 `xworkmate-bridge 连接失败`
|
||||
- 账号同步状态为 `失败`
|
||||
- 同步说明显示 `bridge auth token is unavailable`
|
||||
- 详情信息里可见 `bridge_auth_token_unavailable`
|
||||
- 排查步骤
|
||||
1. 在 App 中触发账号同步或重新进入设置页
|
||||
2. 直接请求 `GET /api/auth/xworkmate/profile/sync`
|
||||
3. 确认是否返回 `409`
|
||||
4. 检查本地 secure storage 中是否存在 `xworkmate.account.managed.bridge.auth_token`
|
||||
5. 检查 `xworkmate-app` 的 `accountSyncState` 是否被写成 `blocked`
|
||||
6. 回到 `accounts.svc.plus` 服务侧确认 shared bridge token 是否已注入 Vault 并可被读取
|
||||
- 期望结论
|
||||
- 若接口返回 `409 bridge_auth_token_unavailable`,问题不在 App 的 bridge 连接逻辑
|
||||
- 根因在 `accounts.svc.plus` 的 shared XWorkmate bridge token 供给链路
|
||||
- `BRIDGE_AUTH_TOKEN` 需要由 accounts 服务通过 Vault 读取并下发
|
||||
- 关联同步规则
|
||||
- 任务 workspace 需要递归同步全部子目录和文件
|
||||
- `dist/账户与身份安全演进史-GPT混排最终版.pdf` 这类深层产物应能回传到当前线程 artifact
|
||||
- 如 skill 或任务已有忽略清单,则中间产物可按清单排除同步,常见对象包括草稿、临时文件、版本号中间稿和可重复生成缓存
|
||||
- 忽略清单建议以约定文件形式维护,例如 `.ignore.md`
|
||||
- 恢复条件
|
||||
- `GET /api/auth/xworkmate/profile/sync` 返回 `200`
|
||||
- 响应包含 `BRIDGE_SERVER_URL` 和 `BRIDGE_AUTH_TOKEN`
|
||||
- App 重新同步后,`accountSyncState.syncState` 变为 `ready`
|
||||
- 本地 managed secret `bridge.auth_token` 被写入
|
||||
- 建议记录项
|
||||
- 登录账号
|
||||
- `profile/sync` HTTP 状态码
|
||||
- 响应错误码或成功字段
|
||||
- 本地 `accountSyncState.syncState`
|
||||
- `tokenConfigured.bridge` 是否为 `true`
|
||||
- 是否已在 `accounts.svc.plus` 侧确认 Vault / bootstrap 配置
|
||||
|
||||
## 3. 本地执行型任务线程
|
||||
|
||||
### `MANUAL-LOCAL-001` `powerpoint-pptx`
|
||||
|
||||
@ -777,7 +777,6 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
var wroteArtifact = false;
|
||||
var failedArtifact = false;
|
||||
var skippedArtifact = false;
|
||||
final currentTaskArtifactRelativePaths = <String>[];
|
||||
for (final artifact in artifacts) {
|
||||
final relativePath = _sanitizeArtifactRelativePathInternal(
|
||||
artifact.relativePath,
|
||||
@ -799,10 +798,6 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
continue;
|
||||
}
|
||||
wroteArtifact = true;
|
||||
_appendArtifactRelativePathsInternal(
|
||||
currentTaskArtifactRelativePaths,
|
||||
existingArtifactPaths,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
final target = await _nextArtifactTargetFileInternal(root, relativePath);
|
||||
@ -817,17 +812,6 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
continue;
|
||||
}
|
||||
wroteArtifact = true;
|
||||
final writtenRelativePath =
|
||||
DesktopThreadArtifactService.relativePathInternal(
|
||||
root.path,
|
||||
target.path,
|
||||
);
|
||||
if (writtenRelativePath != null && writtenRelativePath.isNotEmpty) {
|
||||
_appendArtifactRelativePathsInternal(
|
||||
currentTaskArtifactRelativePaths,
|
||||
<String>[writtenRelativePath],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final syncStatus = wroteArtifact
|
||||
@ -835,6 +819,9 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
: failedArtifact
|
||||
? 'download-failed'
|
||||
: 'no-artifacts';
|
||||
final currentTaskArtifactRelativePaths = wroteArtifact
|
||||
? await _collectWorkspaceArtifactRelativePathsInternal(root)
|
||||
: const <String>[];
|
||||
upsertTaskThreadInternal(
|
||||
normalizedSessionKey,
|
||||
lastArtifactSyncAtMs: syncedAtMs,
|
||||
@ -1158,17 +1145,6 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
) => kGatewayRemoteProfileIndex;
|
||||
}
|
||||
|
||||
void _appendArtifactRelativePathsInternal(
|
||||
List<String> target,
|
||||
List<String> paths,
|
||||
) {
|
||||
for (final path in paths) {
|
||||
if (!target.contains(path)) {
|
||||
target.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<String>> _existingWorkspaceArtifactPathsInternal(
|
||||
Directory root,
|
||||
String relativePath,
|
||||
@ -1209,6 +1185,22 @@ Future<List<String>> _existingWorkspaceArtifactPathsInternal(
|
||||
return paths;
|
||||
}
|
||||
|
||||
Future<List<String>> _collectWorkspaceArtifactRelativePathsInternal(
|
||||
Directory root,
|
||||
) async {
|
||||
final files = await DesktopThreadArtifactService().collectFilesInternal(root);
|
||||
final paths = <String>[];
|
||||
for (final file in files) {
|
||||
final resolvedRelativePath =
|
||||
DesktopThreadArtifactService.relativePathInternal(root.path, file.path);
|
||||
if (resolvedRelativePath != null && resolvedRelativePath.isNotEmpty) {
|
||||
paths.add(resolvedRelativePath);
|
||||
}
|
||||
}
|
||||
paths.sort();
|
||||
return paths;
|
||||
}
|
||||
|
||||
String _normalizeAuthorizationHeaderInternal(String raw) {
|
||||
final trimmed = raw.trim();
|
||||
if (trimmed.isEmpty) {
|
||||
|
||||
@ -492,9 +492,10 @@ void main() {
|
||||
final snapshot = await controller.loadAssistantArtifactSnapshot(
|
||||
sessionKey: 'unit-fixture-task-a',
|
||||
);
|
||||
expect(snapshot.resultEntries.map((entry) => entry.relativePath), <String>[
|
||||
'notes/hello.v2.txt',
|
||||
]);
|
||||
expect(
|
||||
snapshot.resultEntries.map((entry) => entry.relativePath),
|
||||
containsAll(<String>['notes/hello.v2.txt', 'notes/hello.txt']),
|
||||
);
|
||||
expect(
|
||||
snapshot.fileEntries.map((entry) => entry.relativePath),
|
||||
containsAll(<String>['notes/hello.v2.txt', 'notes/hello.txt']),
|
||||
@ -566,7 +567,10 @@ void main() {
|
||||
final currentRelativePaths = snapshot.resultEntries
|
||||
.map((entry) => entry.relativePath)
|
||||
.toList(growable: false);
|
||||
expect(currentRelativePaths, <String>['current-task-report.md']);
|
||||
expect(
|
||||
currentRelativePaths,
|
||||
containsAll(<String>['current-task-report.md', 'old-task-report.md']),
|
||||
);
|
||||
expect(
|
||||
snapshot.fileEntries.map((entry) => entry.relativePath),
|
||||
containsAll(<String>['current-task-report.md', 'old-task-report.md']),
|
||||
@ -615,6 +619,10 @@ void main() {
|
||||
await File(
|
||||
'${localWorkspace.path}/chapters/codex-chapter-breakdown.md',
|
||||
).create(recursive: true);
|
||||
await Directory('${localWorkspace.path}/dist').create(recursive: true);
|
||||
await File(
|
||||
'${localWorkspace.path}/dist/账户与身份安全演进史-GPT混排最终版.pdf',
|
||||
).writeAsBytes(<int>[7, 8, 9]);
|
||||
|
||||
controller.upsertTaskThreadInternal(
|
||||
'unit-fixture-task-a',
|
||||
@ -657,6 +665,7 @@ void main() {
|
||||
'assets/images/chapters/chapter-1.png',
|
||||
'assets/images/cover.png',
|
||||
'chapters/codex-chapter-breakdown.md',
|
||||
'dist/账户与身份安全演进史-GPT混排最终版.pdf',
|
||||
]);
|
||||
final snapshot = await controller.loadAssistantArtifactSnapshot(
|
||||
sessionKey: 'unit-fixture-task-a',
|
||||
@ -667,6 +676,7 @@ void main() {
|
||||
'assets/images/chapters/chapter-1.png',
|
||||
'assets/images/cover.png',
|
||||
'chapters/codex-chapter-breakdown.md',
|
||||
'dist/账户与身份安全演进史-GPT混排最终版.pdf',
|
||||
]),
|
||||
);
|
||||
});
|
||||
@ -989,12 +999,17 @@ void main() {
|
||||
await File('${localWorkspace.path}/reports/resume.bin').readAsBytes(),
|
||||
body,
|
||||
);
|
||||
expect(
|
||||
controller
|
||||
.requireTaskThreadForSessionInternal('unit-fixture-task-a')
|
||||
.lastArtifactSyncStatus,
|
||||
'synced',
|
||||
final thread = controller.requireTaskThreadForSessionInternal(
|
||||
'unit-fixture-task-a',
|
||||
);
|
||||
for (
|
||||
var attempt = 0;
|
||||
attempt < 20 && thread.lastArtifactSyncStatus != 'synced';
|
||||
attempt += 1
|
||||
) {
|
||||
await Future<void>.delayed(const Duration(milliseconds: 10));
|
||||
}
|
||||
expect(thread.lastArtifactSyncStatus, 'synced');
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user