@marktrue/dsh-mobile-remote 3.2.2-alpha.1 → 3.2.2-rc.1-app
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/DSH-Remote-v3.2.2.apk +4 -0
- package/README.md +6 -253
- package/manifest.json +21 -0
- package/package.json +12 -65
- package/CHANGELOG.md +0 -1223
- package/CONTRIBUTING.md +0 -59
- package/FAQ.md +0 -111
- package/cordis.patch.yml +0 -14
- package/docs/00-/345/274/200/345/217/221/346/200/273/347/272/262.md +0 -125
- package/docs/01-PRD.md +0 -148
- package/docs/02-architecture.md +0 -249
- package/docs/03-api.md +0 -930
- package/docs/04-security.md +0 -100
- package/docs/05-test-cases.md +0 -366
- package/docs/06-install-run.md +0 -372
- package/docs/07-user-manual.md +0 -66
- package/docs/08-/346/211/251/345/261/225/345/274/200/345/217/221/346/214/207/345/215/227.md +0 -86
- package/docs/09-compatibility.md +0 -223
- package/docs/10-release.md +0 -929
- package/docs/screenshots/01-home.png +0 -0
- package/docs/screenshots/02-notifications.png +0 -0
- package/docs/screenshots/03-sessions.png +0 -0
- package/docs/screenshots/04-chat.png +0 -0
- package/docs/screenshots/05-settings.png +0 -0
- package/docs/screenshots/06-new-session.png +0 -0
- package/docs/screenshots/pgy-appstore.jpg +0 -0
- package/docs/screenshots/pgy-mobile-app.jpg +0 -0
- package/docs/screenshots/pgy-pc-client.jpg +0 -0
- package/docs/spec-app-auto-update.md +0 -143
- package/lib/account-usage.js +0 -145
- package/lib/app-alignment.js +0 -112
- package/lib/app-carrier-store.js +0 -1972
- package/lib/app-carrier.js +0 -609
- package/lib/client.js +0 -1174
- package/lib/desktop-form.js +0 -738
- package/lib/endpoint-registry.js +0 -165
- package/lib/git-read-bundled-provider.js +0 -255
- package/lib/git-read-service.js +0 -322
- package/lib/index.js +0 -9467
- package/lib/npm-update-source.js +0 -226
- package/lib/plugin-content-digest.js +0 -80
- package/lib/plugin-self-update.js +0 -997
- package/lib/plugin-update-controller.js +0 -274
- package/lib/plugin-update-log.js +0 -164
- package/lib/plugin-update-transaction.js +0 -322
- package/lib/plugin-update.js +0 -309
- package/lib/runtime-dependency-snapshot.js +0 -345
- package/lib/session-title-cache.js +0 -123
- package/lib/session-title-refresh.js +0 -261
- package/lib/tool-process.js +0 -20
- package/lib/update-fetch.js +0 -24
- package/lib/update-lock-arbiter.js +0 -170
- package/lib/update-supervisor.js +0 -346
- package/node_modules/ansi-regex/index.d.ts +0 -37
- package/node_modules/ansi-regex/index.js +0 -10
- package/node_modules/ansi-regex/license +0 -9
- package/node_modules/ansi-regex/package.json +0 -55
- package/node_modules/ansi-regex/readme.md +0 -78
- package/node_modules/ansi-styles/index.d.ts +0 -345
- package/node_modules/ansi-styles/index.js +0 -163
- package/node_modules/ansi-styles/license +0 -9
- package/node_modules/ansi-styles/package.json +0 -56
- package/node_modules/ansi-styles/readme.md +0 -152
- package/node_modules/camelcase/index.d.ts +0 -63
- package/node_modules/camelcase/index.js +0 -76
- package/node_modules/camelcase/license +0 -9
- package/node_modules/camelcase/package.json +0 -43
- package/node_modules/camelcase/readme.md +0 -99
- package/node_modules/cliui/CHANGELOG.md +0 -76
- package/node_modules/cliui/LICENSE.txt +0 -14
- package/node_modules/cliui/README.md +0 -115
- package/node_modules/cliui/index.js +0 -354
- package/node_modules/cliui/package.json +0 -65
- package/node_modules/color-convert/CHANGELOG.md +0 -54
- package/node_modules/color-convert/LICENSE +0 -21
- package/node_modules/color-convert/README.md +0 -68
- package/node_modules/color-convert/conversions.js +0 -839
- package/node_modules/color-convert/index.js +0 -81
- package/node_modules/color-convert/package.json +0 -48
- package/node_modules/color-convert/route.js +0 -97
- package/node_modules/color-name/LICENSE +0 -8
- package/node_modules/color-name/README.md +0 -11
- package/node_modules/color-name/index.js +0 -152
- package/node_modules/color-name/package.json +0 -28
- package/node_modules/decamelize/index.js +0 -13
- package/node_modules/decamelize/license +0 -21
- package/node_modules/decamelize/package.json +0 -38
- package/node_modules/decamelize/readme.md +0 -48
- package/node_modules/dijkstrajs/.travis.yml +0 -4
- package/node_modules/dijkstrajs/CONTRIBUTING.md +0 -8
- package/node_modules/dijkstrajs/LICENSE.md +0 -19
- package/node_modules/dijkstrajs/README.md +0 -18
- package/node_modules/dijkstrajs/dijkstra.js +0 -165
- package/node_modules/dijkstrajs/package.json +0 -60
- package/node_modules/dijkstrajs/test/dijkstra.test.js +0 -96
- package/node_modules/emoji-regex/LICENSE-MIT.txt +0 -20
- package/node_modules/emoji-regex/README.md +0 -73
- package/node_modules/emoji-regex/es2015/index.js +0 -6
- package/node_modules/emoji-regex/es2015/text.js +0 -6
- package/node_modules/emoji-regex/index.d.ts +0 -23
- package/node_modules/emoji-regex/index.js +0 -6
- package/node_modules/emoji-regex/package.json +0 -50
- package/node_modules/emoji-regex/text.js +0 -6
- package/node_modules/find-up/index.d.ts +0 -137
- package/node_modules/find-up/index.js +0 -89
- package/node_modules/find-up/license +0 -9
- package/node_modules/find-up/package.json +0 -53
- package/node_modules/find-up/readme.md +0 -156
- package/node_modules/get-caller-file/LICENSE.md +0 -6
- package/node_modules/get-caller-file/README.md +0 -41
- package/node_modules/get-caller-file/index.d.ts +0 -2
- package/node_modules/get-caller-file/index.js +0 -22
- package/node_modules/get-caller-file/index.js.map +0 -1
- package/node_modules/get-caller-file/package.json +0 -42
- package/node_modules/is-fullwidth-code-point/index.d.ts +0 -17
- package/node_modules/is-fullwidth-code-point/index.js +0 -50
- package/node_modules/is-fullwidth-code-point/license +0 -9
- package/node_modules/is-fullwidth-code-point/package.json +0 -42
- package/node_modules/is-fullwidth-code-point/readme.md +0 -39
- package/node_modules/locate-path/index.d.ts +0 -83
- package/node_modules/locate-path/index.js +0 -65
- package/node_modules/locate-path/license +0 -9
- package/node_modules/locate-path/package.json +0 -45
- package/node_modules/locate-path/readme.md +0 -122
- package/node_modules/p-limit/index.d.ts +0 -38
- package/node_modules/p-limit/index.js +0 -57
- package/node_modules/p-limit/license +0 -9
- package/node_modules/p-limit/package.json +0 -52
- package/node_modules/p-limit/readme.md +0 -101
- package/node_modules/p-locate/index.d.ts +0 -64
- package/node_modules/p-locate/index.js +0 -52
- package/node_modules/p-locate/license +0 -9
- package/node_modules/p-locate/package.json +0 -53
- package/node_modules/p-locate/readme.md +0 -90
- package/node_modules/p-try/index.d.ts +0 -39
- package/node_modules/p-try/index.js +0 -9
- package/node_modules/p-try/license +0 -9
- package/node_modules/p-try/package.json +0 -42
- package/node_modules/p-try/readme.md +0 -58
- package/node_modules/path-exists/index.d.ts +0 -28
- package/node_modules/path-exists/index.js +0 -23
- package/node_modules/path-exists/license +0 -9
- package/node_modules/path-exists/package.json +0 -39
- package/node_modules/path-exists/readme.md +0 -52
- package/node_modules/pngjs/.eslintignore +0 -2
- package/node_modules/pngjs/.eslintrc.json +0 -19
- package/node_modules/pngjs/.prettierignore +0 -3
- package/node_modules/pngjs/LICENSE +0 -20
- package/node_modules/pngjs/README.md +0 -429
- package/node_modules/pngjs/browser.js +0 -16096
- package/node_modules/pngjs/coverage/lcov-report/base.css +0 -354
- package/node_modules/pngjs/coverage/lcov-report/bitmapper.js.html +0 -881
- package/node_modules/pngjs/coverage/lcov-report/bitpacker.js.html +0 -554
- package/node_modules/pngjs/coverage/lcov-report/block-navigation.js +0 -77
- package/node_modules/pngjs/coverage/lcov-report/chunkstream.js.html +0 -647
- package/node_modules/pngjs/coverage/lcov-report/constants.js.html +0 -176
- package/node_modules/pngjs/coverage/lcov-report/crc.js.html +0 -200
- package/node_modules/pngjs/coverage/lcov-report/favicon.png +0 -0
- package/node_modules/pngjs/coverage/lcov-report/filter-pack.js.html +0 -593
- package/node_modules/pngjs/coverage/lcov-report/filter-parse-async.js.html +0 -152
- package/node_modules/pngjs/coverage/lcov-report/filter-parse-sync.js.html +0 -143
- package/node_modules/pngjs/coverage/lcov-report/filter-parse.js.html +0 -611
- package/node_modules/pngjs/coverage/lcov-report/format-normaliser.js.html +0 -359
- package/node_modules/pngjs/coverage/lcov-report/index.html +0 -426
- package/node_modules/pngjs/coverage/lcov-report/interlace.js.html +0 -365
- package/node_modules/pngjs/coverage/lcov-report/packer-async.js.html +0 -230
- package/node_modules/pngjs/coverage/lcov-report/packer-sync.js.html +0 -248
- package/node_modules/pngjs/coverage/lcov-report/packer.js.html +0 -467
- package/node_modules/pngjs/coverage/lcov-report/paeth-predictor.js.html +0 -128
- package/node_modules/pngjs/coverage/lcov-report/parser-async.js.html +0 -575
- package/node_modules/pngjs/coverage/lcov-report/parser-sync.js.html +0 -404
- package/node_modules/pngjs/coverage/lcov-report/parser.js.html +0 -950
- package/node_modules/pngjs/coverage/lcov-report/png-sync.js.html +0 -116
- package/node_modules/pngjs/coverage/lcov-report/png.js.html +0 -662
- package/node_modules/pngjs/coverage/lcov-report/prettify.css +0 -101
- package/node_modules/pngjs/coverage/lcov-report/prettify.js +0 -1007
- package/node_modules/pngjs/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/node_modules/pngjs/coverage/lcov-report/sorter.js +0 -169
- package/node_modules/pngjs/coverage/lcov-report/sync-inflate.js.html +0 -584
- package/node_modules/pngjs/coverage/lcov-report/sync-reader.js.html +0 -215
- package/node_modules/pngjs/coverage/lcov.info +0 -2177
- package/node_modules/pngjs/lib/bitmapper.js +0 -267
- package/node_modules/pngjs/lib/bitpacker.js +0 -158
- package/node_modules/pngjs/lib/chunkstream.js +0 -189
- package/node_modules/pngjs/lib/constants.js +0 -32
- package/node_modules/pngjs/lib/crc.js +0 -40
- package/node_modules/pngjs/lib/filter-pack.js +0 -171
- package/node_modules/pngjs/lib/filter-parse-async.js +0 -24
- package/node_modules/pngjs/lib/filter-parse-sync.js +0 -21
- package/node_modules/pngjs/lib/filter-parse.js +0 -177
- package/node_modules/pngjs/lib/format-normaliser.js +0 -93
- package/node_modules/pngjs/lib/interlace.js +0 -95
- package/node_modules/pngjs/lib/packer-async.js +0 -50
- package/node_modules/pngjs/lib/packer-sync.js +0 -56
- package/node_modules/pngjs/lib/packer.js +0 -129
- package/node_modules/pngjs/lib/paeth-predictor.js +0 -16
- package/node_modules/pngjs/lib/parser-async.js +0 -165
- package/node_modules/pngjs/lib/parser-sync.js +0 -108
- package/node_modules/pngjs/lib/parser.js +0 -290
- package/node_modules/pngjs/lib/png-sync.js +0 -12
- package/node_modules/pngjs/lib/png.js +0 -194
- package/node_modules/pngjs/lib/sync-inflate.js +0 -168
- package/node_modules/pngjs/lib/sync-reader.js +0 -45
- package/node_modules/pngjs/package.json +0 -73
- package/node_modules/qrcode/README.md +0 -770
- package/node_modules/qrcode/bin/qrcode +0 -159
- package/node_modules/qrcode/helper/to-sjis-browser.js +0 -2
- package/node_modules/qrcode/helper/to-sjis.js +0 -105
- package/node_modules/qrcode/lib/browser.js +0 -76
- package/node_modules/qrcode/lib/can-promise.js +0 -7
- package/node_modules/qrcode/lib/core/alignment-pattern.js +0 -83
- package/node_modules/qrcode/lib/core/alphanumeric-data.js +0 -59
- package/node_modules/qrcode/lib/core/bit-buffer.js +0 -37
- package/node_modules/qrcode/lib/core/bit-matrix.js +0 -65
- package/node_modules/qrcode/lib/core/byte-data.js +0 -30
- package/node_modules/qrcode/lib/core/error-correction-code.js +0 -135
- package/node_modules/qrcode/lib/core/error-correction-level.js +0 -50
- package/node_modules/qrcode/lib/core/finder-pattern.js +0 -22
- package/node_modules/qrcode/lib/core/format-info.js +0 -29
- package/node_modules/qrcode/lib/core/galois-field.js +0 -69
- package/node_modules/qrcode/lib/core/kanji-data.js +0 -54
- package/node_modules/qrcode/lib/core/mask-pattern.js +0 -234
- package/node_modules/qrcode/lib/core/mode.js +0 -167
- package/node_modules/qrcode/lib/core/numeric-data.js +0 -43
- package/node_modules/qrcode/lib/core/polynomial.js +0 -62
- package/node_modules/qrcode/lib/core/qrcode.js +0 -495
- package/node_modules/qrcode/lib/core/reed-solomon-encoder.js +0 -56
- package/node_modules/qrcode/lib/core/regex.js +0 -31
- package/node_modules/qrcode/lib/core/segments.js +0 -330
- package/node_modules/qrcode/lib/core/utils.js +0 -63
- package/node_modules/qrcode/lib/core/version-check.js +0 -9
- package/node_modules/qrcode/lib/core/version.js +0 -163
- package/node_modules/qrcode/lib/index.js +0 -12
- package/node_modules/qrcode/lib/renderer/canvas.js +0 -63
- package/node_modules/qrcode/lib/renderer/png.js +0 -78
- package/node_modules/qrcode/lib/renderer/svg-tag.js +0 -81
- package/node_modules/qrcode/lib/renderer/svg.js +0 -19
- package/node_modules/qrcode/lib/renderer/terminal/terminal-small.js +0 -85
- package/node_modules/qrcode/lib/renderer/terminal/terminal.js +0 -49
- package/node_modules/qrcode/lib/renderer/terminal.js +0 -9
- package/node_modules/qrcode/lib/renderer/utf8.js +0 -71
- package/node_modules/qrcode/lib/renderer/utils.js +0 -99
- package/node_modules/qrcode/lib/server.js +0 -138
- package/node_modules/qrcode/license +0 -10
- package/node_modules/qrcode/package.json +0 -77
- package/node_modules/require-directory/.jshintrc +0 -67
- package/node_modules/require-directory/.npmignore +0 -1
- package/node_modules/require-directory/.travis.yml +0 -3
- package/node_modules/require-directory/LICENSE +0 -22
- package/node_modules/require-directory/README.markdown +0 -184
- package/node_modules/require-directory/index.js +0 -86
- package/node_modules/require-directory/package.json +0 -40
- package/node_modules/require-main-filename/CHANGELOG.md +0 -26
- package/node_modules/require-main-filename/LICENSE.txt +0 -14
- package/node_modules/require-main-filename/README.md +0 -26
- package/node_modules/require-main-filename/index.js +0 -18
- package/node_modules/require-main-filename/package.json +0 -35
- package/node_modules/set-blocking/CHANGELOG.md +0 -26
- package/node_modules/set-blocking/LICENSE.txt +0 -14
- package/node_modules/set-blocking/README.md +0 -31
- package/node_modules/set-blocking/index.js +0 -7
- package/node_modules/set-blocking/package.json +0 -42
- package/node_modules/string-width/index.d.ts +0 -29
- package/node_modules/string-width/index.js +0 -47
- package/node_modules/string-width/license +0 -9
- package/node_modules/string-width/package.json +0 -56
- package/node_modules/string-width/readme.md +0 -50
- package/node_modules/strip-ansi/index.d.ts +0 -17
- package/node_modules/strip-ansi/index.js +0 -4
- package/node_modules/strip-ansi/license +0 -9
- package/node_modules/strip-ansi/package.json +0 -54
- package/node_modules/strip-ansi/readme.md +0 -46
- package/node_modules/which-module/LICENSE +0 -13
- package/node_modules/which-module/README.md +0 -58
- package/node_modules/which-module/index.js +0 -9
- package/node_modules/which-module/package.json +0 -41
- package/node_modules/wrap-ansi/index.js +0 -186
- package/node_modules/wrap-ansi/license +0 -9
- package/node_modules/wrap-ansi/package.json +0 -61
- package/node_modules/wrap-ansi/readme.md +0 -97
- package/node_modules/y18n/CHANGELOG.md +0 -35
- package/node_modules/y18n/LICENSE +0 -13
- package/node_modules/y18n/README.md +0 -109
- package/node_modules/y18n/index.js +0 -188
- package/node_modules/y18n/package.json +0 -39
- package/node_modules/yargs/CHANGELOG.md +0 -420
- package/node_modules/yargs/LICENSE +0 -21
- package/node_modules/yargs/README.md +0 -140
- package/node_modules/yargs/build/lib/apply-extends.d.ts +0 -2
- package/node_modules/yargs/build/lib/apply-extends.js +0 -65
- package/node_modules/yargs/build/lib/argsert.d.ts +0 -2
- package/node_modules/yargs/build/lib/argsert.js +0 -65
- package/node_modules/yargs/build/lib/command.d.ts +0 -64
- package/node_modules/yargs/build/lib/command.js +0 -416
- package/node_modules/yargs/build/lib/common-types.d.ts +0 -36
- package/node_modules/yargs/build/lib/common-types.js +0 -25
- package/node_modules/yargs/build/lib/completion-templates.d.ts +0 -2
- package/node_modules/yargs/build/lib/completion-templates.js +0 -50
- package/node_modules/yargs/build/lib/completion.d.ts +0 -21
- package/node_modules/yargs/build/lib/completion.js +0 -135
- package/node_modules/yargs/build/lib/is-promise.d.ts +0 -1
- package/node_modules/yargs/build/lib/is-promise.js +0 -9
- package/node_modules/yargs/build/lib/levenshtein.d.ts +0 -1
- package/node_modules/yargs/build/lib/levenshtein.js +0 -58
- package/node_modules/yargs/build/lib/middleware.d.ts +0 -10
- package/node_modules/yargs/build/lib/middleware.js +0 -57
- package/node_modules/yargs/build/lib/obj-filter.d.ts +0 -1
- package/node_modules/yargs/build/lib/obj-filter.js +0 -14
- package/node_modules/yargs/build/lib/parse-command.d.ts +0 -11
- package/node_modules/yargs/build/lib/parse-command.js +0 -36
- package/node_modules/yargs/build/lib/process-argv.d.ts +0 -2
- package/node_modules/yargs/build/lib/process-argv.js +0 -31
- package/node_modules/yargs/build/lib/usage.d.ts +0 -49
- package/node_modules/yargs/build/lib/usage.js +0 -540
- package/node_modules/yargs/build/lib/validation.d.ts +0 -34
- package/node_modules/yargs/build/lib/validation.js +0 -330
- package/node_modules/yargs/build/lib/yargs.d.ts +0 -274
- package/node_modules/yargs/build/lib/yargs.js +0 -1190
- package/node_modules/yargs/build/lib/yerror.d.ts +0 -4
- package/node_modules/yargs/build/lib/yerror.js +0 -11
- package/node_modules/yargs/index.js +0 -40
- package/node_modules/yargs/locales/be.json +0 -46
- package/node_modules/yargs/locales/de.json +0 -46
- package/node_modules/yargs/locales/en.json +0 -51
- package/node_modules/yargs/locales/es.json +0 -46
- package/node_modules/yargs/locales/fi.json +0 -49
- package/node_modules/yargs/locales/fr.json +0 -53
- package/node_modules/yargs/locales/hi.json +0 -49
- package/node_modules/yargs/locales/hu.json +0 -46
- package/node_modules/yargs/locales/id.json +0 -50
- package/node_modules/yargs/locales/it.json +0 -46
- package/node_modules/yargs/locales/ja.json +0 -51
- package/node_modules/yargs/locales/ko.json +0 -49
- package/node_modules/yargs/locales/nb.json +0 -44
- package/node_modules/yargs/locales/nl.json +0 -49
- package/node_modules/yargs/locales/nn.json +0 -44
- package/node_modules/yargs/locales/pirate.json +0 -13
- package/node_modules/yargs/locales/pl.json +0 -49
- package/node_modules/yargs/locales/pt.json +0 -45
- package/node_modules/yargs/locales/pt_BR.json +0 -48
- package/node_modules/yargs/locales/ru.json +0 -46
- package/node_modules/yargs/locales/th.json +0 -46
- package/node_modules/yargs/locales/tr.json +0 -48
- package/node_modules/yargs/locales/zh_CN.json +0 -48
- package/node_modules/yargs/locales/zh_TW.json +0 -47
- package/node_modules/yargs/package.json +0 -92
- package/node_modules/yargs/yargs.js +0 -14
- package/node_modules/yargs-parser/CHANGELOG.md +0 -601
- package/node_modules/yargs-parser/LICENSE.txt +0 -14
- package/node_modules/yargs-parser/README.md +0 -449
- package/node_modules/yargs-parser/index.js +0 -1032
- package/node_modules/yargs-parser/lib/tokenize-arg-string.js +0 -40
- package/node_modules/yargs-parser/package.json +0 -46
package/docs/03-api.md
DELETED
|
@@ -1,930 +0,0 @@
|
|
|
1
|
-
# 03 API 接口设计文档 — dsh-mobile-remote
|
|
2
|
-
|
|
3
|
-
> 版本:v3.1.5 · 状态:已实现;Git API 小节为尚未实现的设计草案 · 配套:00-开发总纲.md、02-architecture.md、04-security.md、09-compatibility.md
|
|
4
|
-
> 前缀:`/m`(可配置项 `path`,默认 `/m`)。以下所有路径均以前缀开头。
|
|
5
|
-
> 服务端 API 同时服务 Flutter App(dsh-mobile-app)与桌面设置页客户端模块;不含网页版页面(v2.1 起移除)。
|
|
6
|
-
## 1. 通用约定
|
|
7
|
-
|
|
8
|
-
- **内容类型**:JSON API 一律 `application/json; charset=utf-8`;错误统一 `{ "error": string, "detail"?: string }`。
|
|
9
|
-
- **鉴权**:`authToken` 配置为空 → 无鉴权;非空 → 除 `GET /m/api/qr-config`(仅 loopback)外,所有端点要求凭证。
|
|
10
|
-
- **凭证形式**(二选一,任一通过即可):
|
|
11
|
-
- 请求头:`X-Mobile-Token: <token>`(App 使用)
|
|
12
|
-
- Cookie:`dsh_mobile_token=<token>`(兼容保留,无登录入口)
|
|
13
|
-
- **未认证响应**:`401 { "error": "auth-required", "detail": "访问口令未通过验证" }`。
|
|
14
|
-
- **路由匹配**:`/m/api/*` 按前缀注册;未知子路径 → `404 { "error": "not-found" }`;`/m` 之外的裸路径不拦截(fallback 仍归桌面 SPA)。
|
|
15
|
-
## 2. 端点总表
|
|
16
|
-
|
|
17
|
-
| 方法 | 路径 | 用途 | 鉴权 |
|
|
18
|
-
|---|---|---|---|
|
|
19
|
-
| GET | `/m/api/bootstrap` | 初始状态:地址、认证要求、agent 摘要、会话列表 | 是 |
|
|
20
|
-
| GET | `/m/api/update/manifest` | App 自动更新(主机源):`updateDir` 里的 `manifest.json`(仅含元数据,不含 APK 本体) | 是 |
|
|
21
|
-
| GET | `/m/api/update/apk` | 按 manifest 指定文件流式下发 APK(服务端先按 manifest 的 sha256 校验再下发) | 是 |
|
|
22
|
-
| POST | `/m/api/send` | 向指定/默认 agent 注入消息(v2.7.2 支持 `mode: "steer"` 插队) | 是 |
|
|
23
|
-
| GET | `/m/api/queue` | 排队消息列表(对齐 PC 端 Queue Dock;`placement: "queued"` 可插话、`"steering"` 不可,v2.7.2) | 是 |
|
|
24
|
-
| POST | `/m/api/messages` | 排队消息操作:`{ sessionId, itemId, action: { kind: "edit"|"remove"|"steer", content? } }`(转发内核 `session.updateQueue`;错误码如 `queue-item-not-found`/`steer-unavailable` 透传,v2.7.2) | 是 |
|
|
25
|
-
| GET | `/m/api/sessions` | 会话列表 | 是 |
|
|
26
|
-
| GET | `/m/api/history` | 指定会话的 Conversation timeline 历史(按 seq 分页) | 是 |
|
|
27
|
-
| GET | `/m/api/event-detail` | 单个 Visible event 无损详情(按 seq) | 是 |
|
|
28
|
-
| GET | `/m/api/turn-outline` | 会话轮次大纲(只读投影;轮次号 / 起始序号 / 提示词与回复预览,轮次导航) | 是 |
|
|
29
|
-
| GET | `/m/api/events` | SSE 事件流(session/event 摘要) | 是 |
|
|
30
|
-
| GET | `/m/api/catalog` | 模型/推理/权限/预设目录 | 是 |
|
|
31
|
-
| GET/POST | `/m/api/session-config` | 会话配置(读写) | 是 |
|
|
32
|
-
| POST | `/m/api/sessions` | 新建会话 | 是 |
|
|
33
|
-
| POST | `/m/api/sessions/touch` | 标记会话被打开(最近活跃排序) | 是 |
|
|
34
|
-
| POST | `/m/api/sessions/archive` | 归档会话 | 是 |
|
|
35
|
-
| POST | `/m/api/sessions/unarchive` | 恢复(取消归档) | 是 |
|
|
36
|
-
| POST | `/m/api/sessions/stop` | 停止(取消)会话当前运行 | 是 |
|
|
37
|
-
| POST | `/m/api/sessions/fork` | 在新对话中分支(映射内核 `session.fork`) | 是 |
|
|
38
|
-
| GET/POST | `/m/api/feedback` | 消息反馈 👍/👎(内核 `messageFeedback` 服务,与 PC 端同一份) | 是 |
|
|
39
|
-
| GET | `/m/api/notifications` | 通知列表 | 是 |
|
|
40
|
-
| POST | `/m/api/notifications/read` | 标记已读 | 是 |
|
|
41
|
-
| POST | `/m/api/notifications/delete` | 删除通知记录(单条/批量/全部) | 是 |
|
|
42
|
-
| POST | `/m/api/respond` | 回答内核问询/审批(与 PC 端 GUI 同一 respond 通道) | 是 |
|
|
43
|
-
| GET | `/m/api/actions` | 插件动作清单 | 是 |
|
|
44
|
-
| POST | `/m/api/actions/:id/invoke` | 执行插件动作 | 是 |
|
|
45
|
-
| GET | `/m/api/usage` | 会话 token 用量 | 是 |
|
|
46
|
-
| GET | `/m/api/workspaces` | 已注册工作区 | 是 |
|
|
47
|
-
| GET/POST | `/m/api/directories` | 目录浏览/新建文件夹 | 是 |
|
|
48
|
-
| GET | `/m/api/diagnostics` | 环境诊断(插件运行时、services、checks) | 是 |
|
|
49
|
-
| — | `/m/api/git/*`(规划中) | 设计草案;v3.1.5 未注册这些路由 | 不适用 |
|
|
50
|
-
| GET | `/m/api/balance` | DeepSeek 官方余额 | 是 |
|
|
51
|
-
| GET | `/m/api/account-usage` | 用量与额度(DeepSeek / Codex / OpenCode Go) | 是 |
|
|
52
|
-
| GET | `/m/api/qr-config` | 桌面二维码数据(loopback only) | 否(loopback) |
|
|
53
|
-
| POST | `/m/api/defaults` | 修改默认 Agent/权限预设 | 是 |
|
|
54
|
-
| GET/POST | `/m/api/llm-providers` | 模型提供商列表 / 保存配置(v2.6) | 是 |
|
|
55
|
-
| POST | `/m/api/llm-providers/probe` | 探测端点模型列表(v2.6) | 是 |
|
|
56
|
-
| GET | `/m/qr.png` | 二维码 PNG | 否 |
|
|
57
|
-
| GET | `/m/api/jobs` | 会话后台任务列表(v2.7,内核 jobs 同源) | 是 |
|
|
58
|
-
| POST | `/m/api/jobs/kill` | 取消任务(v2.7,映射 `jobs.kill`) | 是 |
|
|
59
|
-
| GET | `/m/api/subagents` | 子代理列表(v2.7,按父会话 `subagent.list`) | 是 |
|
|
60
|
-
| POST | `/m/api/subagents/interrupt` | 中断子代理(v2.7,`subagent.interrupt`) | 是 |
|
|
61
|
-
| GET/POST | `/m/api/goal` | 当前目标 / 创建·暂停·继续·完成(v2.7,goal RPC 同源) | 是 |
|
|
62
|
-
| GET/POST | `/m/api/commands` | 斜杠命令目录/执行(v2.8.0;v2.8.2 适配内核 0.1.1-rc.2 四参签名,服务缺失优雅降级) | 是 |
|
|
63
|
-
|
|
64
|
-
### 2.1 App 自动更新(主机源,v3.x)
|
|
65
|
-
|
|
66
|
-
**概念**:插件配置 `updateDir`(如 `~/.dsh/mobile-remote/update/`,见 docs/06 §8.5)里放发布脚本产出的 APK 与 `manifest.json`。**manifest 是唯一权威**——App 只读 manifest,不枚举目录。
|
|
67
|
-
|
|
68
|
-
**`manifest.json` 契约**(由 `tools/gen-manifest.js` 统一生成,双端发布脚本共用):
|
|
69
|
-
|
|
70
|
-
```json
|
|
71
|
-
{ "version": "3.0.0+8", "apk": "DSH-Remote-v3.0.0.apk", "sha256": "<小写hex>", "size": 72026882, "notes": "CHANGELOG 最新条目全文(可为空)" }
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
- `version`:`X.Y.Z` + 可选 `+build`(App 端精确到 build 判定更新/防降级)。
|
|
75
|
-
- `sha256`:APK 字节 SHA-256(小写 hex);`size`:APK 字节数;`notes`:更新说明(可选)。
|
|
76
|
-
|
|
77
|
-
**GET `/m/api/update/manifest`**:返回 `{ ok: true, manifest: {...} }`。错误码:
|
|
78
|
-
- `503 update-not-configured`:未配置 `updateDir`;
|
|
79
|
-
- `404 update-dir-missing` / `404 update-manifest-missing`:目录或 manifest 不存在;
|
|
80
|
-
- `404 update-manifest-invalid`:manifest 缺字段/非 JSON。
|
|
81
|
-
|
|
82
|
-
**GET `/m/api/update/apk`**:按 manifest `apk` 字段流式下发(`application/vnd.android.package-archive`,含 `content-length`)。**服务端先按 manifest 的 sha256 校验 APK 字节**再下发(防目录内文件被替换/损坏)。错误码:
|
|
83
|
-
- 继承 manifest 阶段各错误码;`404 update-apk-missing`:文件不存在(含路径越界防御);
|
|
84
|
-
- `500 update-apk-checksum-mismatch`:文件与 manifest sha256 不符(拒发);
|
|
85
|
-
- `500 update-apk-read-failed`:读取失败。
|
|
86
|
-
|
|
87
|
-
> GitHub 源不经过本插件(App 直连 `api.github.com/repos/201222-L/dsh-mobile-remote/releases/latest`,取首个 `DSH-Remote-*.apk` 资产,`browser_download_url` 直连下载)。
|
|
88
|
-
|
|
89
|
-
## 3. 端点详述(v1 既有端点)
|
|
90
|
-
### 3.1 GET /m/api/bootstrap
|
|
91
|
-
|
|
92
|
-
**响应 200**
|
|
93
|
-
|
|
94
|
-
```json
|
|
95
|
-
{
|
|
96
|
-
"ok": true,
|
|
97
|
-
"auth": { "enabled": false },
|
|
98
|
-
"server": {
|
|
99
|
-
"port": 3080,
|
|
100
|
-
"urls": ["http://192.168.1.5:3080", "http://100.101.102.103:3080", "http://127.0.0.1:3080"]
|
|
101
|
-
},
|
|
102
|
-
"capabilities": {
|
|
103
|
-
"eventTimeline": {
|
|
104
|
-
"version": 1,
|
|
105
|
-
"live": true,
|
|
106
|
-
"history": true,
|
|
107
|
-
"detail": true,
|
|
108
|
-
"unknownEvents": true,
|
|
109
|
-
"callCorrelation": true
|
|
110
|
-
},
|
|
111
|
-
"turnOutline": { "version": 1, "supported": true, "unloaded": true, "truncated": true }
|
|
112
|
-
},
|
|
113
|
-
"agents": [
|
|
114
|
-
{ "id": "session-abc", "status": "running", "hasPending": false }
|
|
115
|
-
],
|
|
116
|
-
"sessions": [
|
|
117
|
-
{ "id": "session-abc", "createdAt": 1750000000000, "cwd": "F:\\DSH-Outpost" }
|
|
118
|
-
]
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
- `urls`:按优先级排列——默认「局域网私有地址优先」(`10./192.168.x` → `172.16-31` → Tailscale CGNAT `100.64/10` → 其他),首个非 internal IPv4 在前,loopback 最后;**仅当机器上没有任何局域网私有地址时**,才把 Tailscale CGNAT 提到最前(issue #49,避免校园网/热点等场景选出不可达地址);`port` 来自 `ctx.webServer.port`。v3.0.0:`lanBridge` 监听成功时首选地址为桥地址(`http://<IP>:<lanBridge.port>`,端口默认 3080),回环 webserver 地址仅作本机自连兜底。
|
|
123
|
-
- `agents[].status`:`"running" | "idle"`(映射自 agent 状态与最近事件推断)。
|
|
124
|
-
- `capabilities.turnOutline`:轮次大纲能力位(轮次导航)。宿主**真的注册了** `turnOutline` 投影单元、且投影感知观察面(`sessionQuery.observeSession`)可用时,返回 `{ "version": 1, "supported": true, "unloaded": true, "truncated": true }`——`unloaded` 表示未加载轮次也可跳转、`truncated` 表示超过体积上限会显式截断;否则返回 `{ "version": 1, "supported": false }`。**不按宿主版本号推断**:旧宿主/裁剪宿主显式声明不支持,App 据此退回「只用已加载轮次」的降级行为。SSE hello 的同名字段与该处**同判据、同形状**(见 §3.6 与 §6.18)。
|
|
125
|
-
- 未认证:`401`(见通用约定)。
|
|
126
|
-
### 3.2 POST /m/api/send
|
|
127
|
-
**请求**
|
|
128
|
-
|
|
129
|
-
```json
|
|
130
|
-
{ "sessionId": "session-abc", "text": "帮我跑一下测试", "mode": "steer" }
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
- `requestId` 可选(**v3.0.0 热修 05**):客户端生成的 UUID(`^[A-Za-z0-9-]{8,64}$`,非法 → `400 invalid requestId`)。携带时服务端启用**幂等回执**:投递之前占位 in-progress,处理完成后记录结果快照;同一 `sessionId+requestId` 的重复请求**直接返回第一次结果、不再二次投递**(`Connection reset by peer` 后重试不会产生重复消息)。回执经 `GET /m/api/send-receipt` 查询;单进程内 + TTL 15 分钟幂等,持久化于 `~/.dsh/mobile-remote/send-receipts.json`(重启恢复;处理中状态不跨重启保留)。
|
|
134
|
-
|
|
135
|
-
图片发送(v3.0.0 图像链路,与 PC 端 wire 同形,原始字节不压缩):
|
|
136
|
-
|
|
137
|
-
```json
|
|
138
|
-
{ "sessionId": "session-abc", "text": "这是什么", "images": [{ "mediaType": "image/png", "data": "<base64>", "name": "photo.png" }] }
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
- `sessionId` 可选:指定会话(必须存在且其 agent 存活);缺省 → 第一个 root agent。
|
|
142
|
-
- `mode` 可选(v2.7.2):`"followup"`(默认,排队到下一轮)| `"steer"`(插队:消息插到 agent 下一步执行,适合 team 插件子会话向主会话插队)。agent 空闲时 `steer` 自动降级为 `followup`,响应 `note: "agent-idle-followup"`。
|
|
143
|
-
- `images` 可选(v3.0.0):`[{ mediaType(仅 png/jpeg/webp/gif), data(canonical base64 原始字节), name? }]`——经内核 `session.prompt` 图片通道(内核限额/降采样/附件落盘,与 PC 端完全同一通路;纯文本仍走 followup)。超限/非规范 → `attachment-error`(`IMAGE_TOO_LARGE`/`INVALID_IMAGE_BASE64` 等)。请求体上限 64MB;**移动端客户端总量上限 40MB(热修 05)**——64MB body 扣掉 base64 膨胀(×4/3)与 JSON 开销后的安全值,超限在客户端明确提示、不落到服务端 413;内核侧 200MB 能力不受影响(PC 端同源)。**mediaType 纠正(v3.0.0 热修 02)**:服务端按字节魔数(PNG/JPEG/GIF/WebP/HEIC)嗅探真实类型,声明与字节不符自动纠正(warn 记录);未识别类型原样交内核裁决。图片路径 200 响应带 `accepted: true`(与文本路径语义一致)。
|
|
144
|
-
- **v3.0.0(方案 A)**:`followup` 且 agent **运行中**时,消息**不进内核 next-turn**(内核会在当前轮结束瞬间自动认领执行,PC 端同款语义),而是**插件侧持存**——只出现在 Queue Dock/移动端 dock,**不渲染进对话窗口**(与 PC 端一致);agent 真正空闲(整个任务/目标结束)后按序自动释放为 `followup`。持存期间消息可经 `/messages` 删除/编辑/插队(全部插件侧执行,无认领竞态)。响应 `mode: "queued", note: "held-until-idle"`。持存文件 `~/.dsh/mobile-remote/held-queue.json`,插件重启不丢。图片持存同样支持(base64 随持存落盘,重启恢复;插队=立即 prompt steer)。
|
|
145
|
-
**响应**
|
|
146
|
-
|
|
147
|
-
- `200 { "ok": true, "agentId": "session-abc", "messageId": "m_<uuid>", "mode": "followup" | "steer" | "queued" }`(`mode: "queued"` 时附 `note`;图片路径 `note: "image-prompt"`)
|
|
148
|
-
- `400 { "error": "empty-text" }`:text 为空或非字符串
|
|
149
|
-
- `404 { "error": "session-not-found" }`:指定会话不存在
|
|
150
|
-
- `503 { "error": "no-live-agent" }`:无匹配的运行中 agent
|
|
151
|
-
- `503 { "error": "agents-unavailable" }`:agents 服务不可用(非 web 组合或启动中)
|
|
152
|
-
**语义**:服务端构造 `createUserMessage({ content: [{ type: 'text', text }], source: { kind: 'user' } })` 后调用 `agent.followup(message)`(排队/空闲释放)或 `agent.steer(message)`(插队);运行中 `followup` 走持存(见上);含 `images` 时经内核 `session.prompt` 图片通道。`followup` 会持久化消息并唤醒空闲驱动器;不等待执行结果(结果经 SSE 回流)。
|
|
153
|
-
|
|
154
|
-
### 3.2c GET /m/api/send-receipt(v3.0.0 热修 05,发送回执查询)
|
|
155
|
-
|
|
156
|
-
**查询参数**:`sessionId`(与发送时一致;缺省按 root agent 解析)、`requestId`(必填,非法 → `400 invalid requestId`)。
|
|
157
|
-
**响应**:`200 { "ok": true, "receipt": { "status": "done" | "error" | "in-progress", "result": {...} } }`(`result` 为发送响应快照,含 messageId/accepted/note/mode);未命中 → `404 receipt-not-found`。
|
|
158
|
-
**语义**:客户端在传输层错误(reset/超时)后用**同一个 requestId** 查询——`done` 即确认已送达(请勿重发);`in-progress` 稍后轮询;`404` 表示第一次请求未到达服务端(可重试,同 id 幂等)。此端点**不投递任何消息**。
|
|
159
|
-
|
|
160
|
-
### 3.2b GET /m/api/attachment(v3.0.0 图像链路,渲染取图)
|
|
161
|
-
|
|
162
|
-
**查询参数**:`sessionId`、`attachmentId`(均必填,来自 SSE/history 摘要的 `images[].attachmentId`)。
|
|
163
|
-
**响应**:`200` 原始字节(`Content-Type` 按 `mediaType`,`Cache-Control: private, max-age=3600`,`x-attachment-meta` 带 width/height/bytes/name);`400` 缺参;`404 attachment-not-found`;其他错误透传。鉴权与其他端点一致(`x-mobile-token`/cookie)。
|
|
164
|
-
### 3.3 GET /m/api/sessions
|
|
165
|
-
|
|
166
|
-
**规划中的扩展响应示例**(当前 v3.1.5 仅返回原有字段,仍按 `lastActivity ?? createdAt` 排序;以下新增字段与排序规则待实现)
|
|
167
|
-
|
|
168
|
-
```json
|
|
169
|
-
{
|
|
170
|
-
"ok": true,
|
|
171
|
-
"sessions": [
|
|
172
|
-
{
|
|
173
|
-
"id": "session-abc",
|
|
174
|
-
"createdAt": 1750000000000,
|
|
175
|
-
"cwd": "F:\\DSH-Outpost",
|
|
176
|
-
"live": true,
|
|
177
|
-
"title": "会话标题(活动会话)",
|
|
178
|
-
"archived": false,
|
|
179
|
-
"lastActivity": 1750000123456,
|
|
180
|
-
"lastMessageAt": 1750000111000,
|
|
181
|
-
"origin": "subagent",
|
|
182
|
-
"parentSession": "session-parent"
|
|
183
|
-
}
|
|
184
|
-
]
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
- 排序(规划中):优先按 `lastMessageAt` 倒序,缺失时回退 `lastActivity`,再回退 `createdAt`;等值时以 `id` 为次级键保证顺序稳定。数据源:优先 `sessionQuery.listSessions()`(含休眠会话),回退 `ctx.sessions.list()`(仅活动会话)。
|
|
189
|
-
- `archived`:是否已归档(见 3.4 归档接口)。
|
|
190
|
-
- `lastActivity`:最近活跃时间(ms)。任意会话事件(SSE)与移动端"打开会话"(3.4 touch)都会更新,持久化于 `~/.dsh/mobile-remote/session-activity.json`。保留给旧版 App,且在消息时间缺失时仍作为排序回退值;旧 App 调用 `touch` 或内部事件发生时,这类会话仍可能重排。
|
|
191
|
-
- `lastMessageAt`(规划中,可选):最近一条用户/助手可见对话消息的时间(ms);无记录时为 `null`。打开会话不更新,工具活动与生命周期事件也不更新。字段缺失或为 `null` 时,客户端回退 `lastActivity`、再回退 `createdAt`,不提示降级;这项兼容回退不保证打开/内部事件后顺序始终不变。
|
|
192
|
-
- `origin`(规划中,可选):会话来源,子代理会话为 `"subagent"`;其余会话不返回。客户端据此隐藏子代理会话;字段缺失即不过滤。
|
|
193
|
-
- `parentSession`(规划中,可选):派生来源会话 id,为将来"折叠到父会话"预留。**不得**用它判定子代理会话——用户主动 fork 的会话只有该字段而没有 `origin`。
|
|
194
|
-
|
|
195
|
-
### 3.4 归档 / 活跃时间接口
|
|
196
|
-
|
|
197
|
-
| 方法 | 路径 | 说明 |
|
|
198
|
-
|---|---|---|
|
|
199
|
-
| POST | `/m/api/sessions/touch` | 标记会话被打开(更新 lastActivity);新版 App 将不再调用,端点保留给旧版 App |
|
|
200
|
-
| POST | `/m/api/sessions/archive` | 归档会话(映射内核 `workspace.archiveSession`,与 PC 端同一份状态) |
|
|
201
|
-
| POST | `/m/api/sessions/unarchive` | 恢复(取消归档) |
|
|
202
|
-
| POST | `/m/api/sessions/stop` | 停止(取消)会话当前运行(映射核心 RPC `session.cancel`) |
|
|
203
|
-
|
|
204
|
-
请求体统一为 `{ "sessionId": "session-abc" }`。
|
|
205
|
-
|
|
206
|
-
- `touch` 响应:`200 { "ok": true, "lastActivity": 1750000123456 }`
|
|
207
|
-
- `archive` / `unarchive` 响应:`200 { "ok": true, "archived": true|false }`
|
|
208
|
-
- `stop` 响应:`200 { "ok": true, "accepted": true }`;失败时 `400 { "error": "cancel-failed" }`(v2.8.0 起统一 rpcError 映射:内核错误透传 status+code、传输层 502、超时 504;旧版固定 500)
|
|
209
|
-
- 归档状态即内核 `workspaceRegistry.archivedSessionIds`(与 PC 端同一份):PC 端归档的会话在移动端同样显示为已归档,反之亦然。归档会话仍出现在 3.3 列表中(`archived: true`),由客户端分栏展示。
|
|
210
|
-
|
|
211
|
-
### 3.5 GET /m/api/history
|
|
212
|
-
|
|
213
|
-
**查询参数**
|
|
214
|
-
|
|
215
|
-
- `sessionId`(必填):目标会话
|
|
216
|
-
- `after`(可选):**增量模式**——只返回 `seq > after` 的事件(SSE 重连补漏用)。
|
|
217
|
-
- `before`(可选):**上翻分页**——只返回 `seq < before` 的最近 `limit` 条事件(对话内滚动到顶部加载更早)。
|
|
218
|
-
- 三种模式优先级:`after` > `before` > 初始加载(缺省时返回最近 `limit` 条,即尾部)。
|
|
219
|
-
- `limit`(可选,默认 500,上限 1000):最多返回条数
|
|
220
|
-
**过滤规则**:返回可进入 Conversation timeline 的事件;`assistant/chunk` / `assistant/live-chunk` 只用于实时草稿,`agent/inbox/spliced` 由队列投影承载,`request/header`(含 system prompt/tool schema)、`request/context`、`session/end-seed`、`step/start`、`step/end`、`system/message`、`assistant/attempt`(重试/中断的原始 stream 记录)与 `compaction/start` / `compaction/summary` / `compaction/prune` / `compaction/end`(压缩生命周期;summary 正文即替换 shadowed 区间后的上下文快照)属于内部/重建/快照元数据,历史、实时与 3.5b 详情三处都不返回。`compaction/end` 作为不落卡片的实时控制帧通知 App 重新加载 durable snapshot。未知 type(即使带 `ignorable: true`)保留 `seq`/`type`,但不提供详情指针;由于详情端点采用 fail-closed allow-list,未知类型请求详情会返回 `404 event-not-found`。只有经审查并列入 allow-list 的可见类型可通过 3.5b 读取详情。
|
|
221
|
-
|
|
222
|
-
> 客户端呈现约定:`session/title`、`model/selection`、`sandbox/mode`、`agent-preset/selected`、`subagent/*`、`team/*`、`feedback/*`、`command/*`、`approval/policy`、`tool/ptc-dispatch*`、`goal/change` 属协议/运行时元数据;普通模式不渲染,调试模式按摘要可用字段展示。只有 `user/message`、`assistant/message`、`tool/call`、`tool/result`、`todo/write`、`turn/start`、`turn/end` 在服务端详情 allow-list 中,其他事件没有详情指针(见 3.5b)。`approval/asked` / `approval/decided` 是 durable 审批记录,普通模式以可读标题呈现(历史回放的权威源;问询只有瞬态帧,不保证回放)。
|
|
223
|
-
**响应 200**
|
|
224
|
-
|
|
225
|
-
```json
|
|
226
|
-
{
|
|
227
|
-
"ok": true,
|
|
228
|
-
"sessionId": "session-abc",
|
|
229
|
-
"after": 42,
|
|
230
|
-
"hasMore": false,
|
|
231
|
-
"events": [
|
|
232
|
-
{ "seq": 43, "type": "user/message", "detail": { "available": true, "seq": 43 }, "data": { "text": "帮我跑一下测试" } }
|
|
233
|
-
]
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
`events[]` 使用与 SSE 帧相同的摘要格式(见 3.6),保证客户端去重逻辑单一。数据源:`ctx.sessions.get(id).events`(追加式冻结快照,天然按 seq 有序)。
|
|
238
|
-
- `404 { "error": "session-not-found" }`
|
|
239
|
-
|
|
240
|
-
### 3.5b GET /m/api/event-detail
|
|
241
|
-
|
|
242
|
-
按会话和 durable `seq` 读取单个 Visible event 的无损详情。该端点需要认证;服务端优先使用 `sessionQuery.readEvent`,旧内核回退到活动会话快照或休眠会话读取。
|
|
243
|
-
|
|
244
|
-
查询参数:`sessionId`、`seq`。
|
|
245
|
-
|
|
246
|
-
```json
|
|
247
|
-
{
|
|
248
|
-
"ok": true,
|
|
249
|
-
"sessionId": "session-abc",
|
|
250
|
-
"event": {
|
|
251
|
-
"seq": 43,
|
|
252
|
-
"type": "tool/result",
|
|
253
|
-
"time": 1750000000000,
|
|
254
|
-
"surfaceOp": "append",
|
|
255
|
-
"sourceEventSeqs": [42],
|
|
256
|
-
"data": { "callId": "call-1", "isError": false, "text": "完整结果" }
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
当服务端只能从 seeded session 的当前 surface 读取时,成功响应额外包含 `"degraded": true, "detailMode": "current-surface"`;客户端必须保留该元数据并提示详情可能不完整。详情不存在或属于内部/敏感类型返回 `404 event-not-found`;单事件详情超过 8 MiB 返回 `413 event-detail-too-large`。
|
|
262
|
-
|
|
263
|
-
稳定错误矩阵:`session-not-found`(会话不存在)、`event-not-found`(seq 不存在/不可见)、`session-corrupt`(会话数据损坏)、`event-read-failed`(读取失败)和 `event-detail-too-large`(超过 8 MiB)。错误响应不得泄露主机路径或原始异常;旧服务端未保存详情时客户端显示安全错误并提供重试,不猜测重建。
|
|
264
|
-
|
|
265
|
-
**规范化正文(`text`)**:`assistant/message` 的详情响应额外附 `data.text`,由服务端用**与事件摘要同一个 `blocksToText`** 提取(只拼 `type == "text"` 的块,跳过 `reasoning` 与内部块),因此与摘要下发的 `text` 同源同规则。客户端必须直接采用该字段作为正文,**不得自行递归拼接 `message.content`**——那会把 `reasoning` 块并进正文,使思维链在折叠块之外重复出现(issue #1 需求变更记录)。`tool/result` 等其它类型的详情仍以原始事件载荷为准;原始 `message` 块原样保留。
|
|
266
|
-
|
|
267
|
-
### 3.6 GET /m/api/events(SSE)
|
|
268
|
-
`Content-Type: text/event-stream`。帧格式(`data:` 单行 JSON):
|
|
269
|
-
|
|
270
|
-
```json
|
|
271
|
-
{ "type": "session/event", "sessionId": "session-abc", "event": { "seq": 44, "type": "turn/end", "data": { "reason": { "kind": "complete" } }, "detail": { "available": true, "seq": 44 } } }
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
**事件摘要 `event` 字段**:实时和历史使用同一摘要 envelope;摘要可包含 `detail: { available: true, seq }`,长参数/结果通过 3.5b 按需读取,不在列表中静默截断。只有 `/event-detail` 真能取回的事件才带该指针(token delta 与内部/快照记录不带,避免客户端显示必然 404 的详情按钮)。
|
|
275
|
-
|
|
276
|
-
`assistant/message` 的指针额外带 **`textChars`**:与摘要同 `blocksToText` 口径的**未截断**正文长度。客户端据此**在加载前**判断「详情是否真有正文增量」(`textChars > 当前可见正文长度`),从而普通模式只在确有增量时显示加载入口;调试模式不受此限,始终提供「查看原始事件」。该字段为纯增量,旧客户端忽略即可。
|
|
277
|
-
|
|
278
|
-
| event.type | event.data 内容 |
|
|
279
|
-
|---|---|
|
|
280
|
-
| `user/message` | `{ text: string }`(text blocks 拼接,≤2000 字符);v3.0.0 起附图 `images: [{ attachmentId, mediaType, width?, height?, name? }]`;文件块可带 `files: [{ attachmentId?, path?, name?, mediaType?, size? }]`(**用户自己的附件,保留**;App 只显示文件名/类型/大小,不提供下载——issue #1 需求变更) |
|
|
281
|
-
| `assistant/message` | `{ text: string, reasoningChars: number, reasoning?: string }`(`reasoning` 为思维链正文,仅当非空时下发,供移动端折叠块;≤20000 字符);v3.0.0 起附图 `images: [...]`(同上);**v3.0.0 版本二**:`images` 含嵌套收集——`tool-result.content` 内的图片块(read_image 等工具结果)与顶层图一并带出(对齐 PC 端 contentParts 语义);**文件块不再下发 `files`**(issue #1 需求变更:时间线不提供产出文件的下载入口) |
|
|
282
|
-
| `assistant/chunk` / `assistant/live-chunk` | `{ text: string }` 文本/reasoning delta;工具参数 delta 的 canonical `chunk.id` 归一为摘要 `callId`(仅实时过程,历史过滤) |
|
|
283
|
-
| `tool/call` | `{ turn, step, callId, name, arguments }`;长参数可通过详情端点获取 |
|
|
284
|
-
| `tool/result` | `{ callId, name, isError, text, images? }`;长结果可通过详情端点获取;**不再下发 `files`**(issue #1 需求变更:工具产出文件不上时间线;图片仍带 `images`) |
|
|
285
|
-
| `turn/start` | `{ turn: number }` |
|
|
286
|
-
| `turn/end` | `{ turn: number, reason: object }` |
|
|
287
|
-
| 其他可见事件 | 保留 `type`、`seq`,未知类型使用通用卡保留顺序;不提供详情指针,也不允许通过 3.5b 读取原始载荷 |
|
|
288
|
-
|
|
289
|
-
**控制帧**:连接建立后立即 `data: {"type":"hello","serverTime":...,"capabilities":{"eventTimeline":{...},"turnOutline":{...}}}`;每 25s `: ping` 注释行。bootstrap 同样返回这两项能力;`turnOutline` 与 bootstrap 同判据、同形状(见 §6.18),客户端应按能力协商而不是按版本号猜测。
|
|
290
|
-
**错误语义**:鉴权失败在连接建立阶段以 `401` HTTP 状态返回(EventSource 会触发 error 事件,客户端转登录态)。
|
|
291
|
-
|
|
292
|
-
### 3.6b SSE 帧类型汇总(v2.3+ 扩展)
|
|
293
|
-
|
|
294
|
-
除 3.6 的 `session/event` 外,SSE 还会推送:
|
|
295
|
-
|
|
296
|
-
| type | 说明 |
|
|
297
|
-
|---|---|
|
|
298
|
-
| `session/context` | `{ sessionId, contextWindow }`——模型上下文窗口(`request/context` 事件,PC 端圆环同源) |
|
|
299
|
-
| `agent/status` | `{ agentId, sessionId, status, child }`——`status` 只有 `running` / `idle` 两值(内核 `AgentStatus` 即为二元联合);`sessionId` 为去 `session:` 前缀的会话 id,`child` 标记子代理会话(v2.7.2 起携带后两字段)。**不存在 `waiting`**:等待用户审批/作答时 agent 仍为 `running`,该事实由 `mobile/frame` 的挂起问询/审批承载 |
|
|
300
|
-
| `notifications/changed` | 通知记录增删(如移动端删除后),客户端刷新列表与角标 |
|
|
301
|
-
| `mobile/notify` | `{ notification: { id, kind, sessionId, title, detail, time } }`——插件"真结束"判定后推送的通知(completed / failed / needs-answer),悬浮球/App 与通知中心同源渲染(v2.7.2) |
|
|
302
|
-
| `mobile/frame` | 内核瞬态帧(问询/审批)。`frame` 字段为 `question/requested`(含 `rpcId`、`questions[]`)、`question/resolved`(`questionRpcId`)、`approval/requested`(`rpcId`、`approvalId`、`toolName`、`reason?`)、`approval/resolved`(`approvalId`)。**App 断线重连时服务端补发挂起的待答帧**(`pendingFrames` 回放) |
|
|
303
|
-
| `mobile/queue` | `{ sessionId, rows: [{ id, text, placement }] }`——内核队列快照(`agent/inbox/spliced` 即时镜像,v3.0.2):认领/删除/编辑实时反映,App 端 dock 以此为权威源(`placement`: `queued` / `steering` / `context`,与 GET /queue 同款形状);断线重连时 mux 回放当前队列 |
|
|
304
|
-
| `git/changed`(规划中) | 设计目标为 `{ repositoryId }`;当前版本未实现 Git provider,也不会推送此帧 |
|
|
305
|
-
|
|
306
|
-
客户端应按 `type` 分派;未知 type 使用通用事件卡保留顺序(前向兼容)。当前服务端故意不给未知 type 详情指针,按需详情端点对其返回 `404 event-not-found`,避免未经审查地暴露事件载荷。
|
|
307
|
-
### 3.7 GET /m/qr.png
|
|
308
|
-
|
|
309
|
-
**查询参数**:`text`(必填,二维码内容,URL 编码)。无 `text` → `400`。 **响应**:`200 image/png`(qrcode 包生成,尺寸 512,纠错级别 M)。
|
|
310
|
-
## 4. 错误码汇总
|
|
311
|
-
| HTTP | error 值 | 场景 |
|
|
312
|
-
|---|---|---|
|
|
313
|
-
| 400 | `bad-request` | JSON 解析失败 / 缺参 / 参数类型错误 |
|
|
314
|
-
| 400 | `empty-text` | send 的 text 为空 |
|
|
315
|
-
| 401 | `auth-required` | 未提供有效凭证 |
|
|
316
|
-
| 401 | `bad-token` | 登录口令错误 |
|
|
317
|
-
| 429 | `rate-limited` | 登录失败超限(v2.6,仅 authToken 启用时;响应带 `Retry-After` 头,默认 60s 后恢复) |
|
|
318
|
-
| 404 | `not-found` | 未知路径 |
|
|
319
|
-
| 404 | `session-not-found` | 会话不存在 |
|
|
320
|
-
| 404 | `event-not-found` | 事件不存在、属于内部/敏感类型,或不在移动端 Visible timeline |
|
|
321
|
-
| 413 | `event-detail-too-large` | 单个无损详情超过 8 MiB 上限 |
|
|
322
|
-
| 405 | `method-not-allowed` | 方法不支持(GET 端点收到 POST 等) |
|
|
323
|
-
| 503 | `no-live-agent` | 无运行中 agent |
|
|
324
|
-
| 503 | `agents-unavailable` | agents 服务不可用 |
|
|
325
|
-
| 503 | `git-provider-unavailable` | DSH subprocess/git provider 不可用 |
|
|
326
|
-
| 403 | `workspace-not-allowed` | 仓库不在已注册工作区边界内 |
|
|
327
|
-
| 404 | `not-git-repository` | 工作区不是 Git 仓库 |
|
|
328
|
-
| 400 | `git-command-failed` | Git 只读命令失败 |
|
|
329
|
-
|
|
330
|
-
## 5. 版本兼容策略
|
|
331
|
-
|
|
332
|
-
- 端点仅追加、不破坏性修改;`event` 摘要格式允许增加字段,禁止删除/重命名既有字段。
|
|
333
|
-
- 前端与后端同包发布(单文件页面由插件自身服务),无跨版本部署问题。
|
|
334
|
-
## 6. 移动端新增端点(Phase 1,v2.0)
|
|
335
|
-
> 全部要求鉴权(与既有端点一致);写操作遵循与 PC 端相同的确认语义(如 Full Access 风险确认由客户端先行,服务端在参数中携带确认标记)。
|
|
336
|
-
### 6.1 端点总表
|
|
337
|
-
|
|
338
|
-
| 方法 | 路径 | 用途 |
|
|
339
|
-
|---|---|---|
|
|
340
|
-
| GET | `/m/api/catalog` | 模型目录 + 推理强度 + 权限预设 + Agent 预设(全部枚举,一次拉取) |
|
|
341
|
-
| GET | `/m/api/session-config` | 当前会话配置(模型/推理强度/权限/预设) |
|
|
342
|
-
| POST | `/m/api/session-config` | 更新当前会话配置 |
|
|
343
|
-
| POST | `/m/api/sessions` | 新建会话(preset 参数) |
|
|
344
|
-
| GET | `/m/api/notifications` | 通知列表(未读/已读) |
|
|
345
|
-
| POST | `/m/api/notifications/read` | 标记已读(单条/全部) |
|
|
346
|
-
| POST | `/m/api/notifications/delete` | 删除通知记录(单条/批量/全部,v2.3) |
|
|
347
|
-
| GET | `/m/api/actions` | 插件动作清单(实时) |
|
|
348
|
-
| POST | `/m/api/actions/:id/invoke` | 执行插件动作 |
|
|
349
|
-
| GET | `/m/api/usage` | 会话 token 用量统计(v2.1) |
|
|
350
|
-
| GET | `/m/api/workspaces` | 已注册工作区(新建会话默认目录,v2.1) |
|
|
351
|
-
| GET | `/m/api/directories` | 目录浏览(盘符/子目录,v2.1;v3.1.1 根视图响应新增 `sep` 字段) |
|
|
352
|
-
| POST | `/m/api/directories` | 新建文件夹(v2.1) |
|
|
353
|
-
| GET | `/m/api/diagnostics` | 环境诊断(服务端端点实测,v2.1) |
|
|
354
|
-
| GET | `/m/api/balance` | DeepSeek 官方余额(服务端代查,v2.1) |
|
|
355
|
-
| GET | `/m/api/account-usage` | 用量与额度(服务端代查,v3.1.5) |
|
|
356
|
-
| GET | `/m/api/turn-outline` | 会话轮次大纲(只读;完整阶梯的轮次摘要,轮次导航) |
|
|
357
|
-
| GET | `/m/api/qr-config` | 桌面二维码数据(loopback only,v2.1) |
|
|
358
|
-
| POST | `/m/api/defaults` | 修改默认 Agent/权限预设(v2.1) |
|
|
359
|
-
|
|
360
|
-
> **路径风格约定(v3.1.1,issue #5)**:`GET /m/api/directories?path=`、`POST /m/api/directories {path}` 与
|
|
361
|
-
> `POST /m/api/sessions {cwd}` 的路径允许按客户端平台习惯传分隔符(Windows `\` / WSL·Linux·macOS `/`);
|
|
362
|
-
> 服务端会归一化为**当前平台**分隔符后读盘/建夹/建会话(旧版 App 在 WSL 上拼出的 `/\home` 也能命中真实目录)。
|
|
363
|
-
> 根视图响应(`path` 为空)携带 `sep`(服务端真实分隔符),新版 App 据此拼接子目录,不再按 Windows 习惯硬编码 `\`;
|
|
364
|
-
> 该字段为纯增量,旧版 App 忽略即可。
|
|
365
|
-
|
|
366
|
-
### 6.2 GET /m/api/catalog
|
|
367
|
-
|
|
368
|
-
返回 PC 端真实枚举(单一事实源,客户端不硬编码):
|
|
369
|
-
```json
|
|
370
|
-
{
|
|
371
|
-
"ok": true,
|
|
372
|
-
"models": [
|
|
373
|
-
{ "provider": "deepseek-official", "id": "deepseek-v4-flash", "name": "DeepSeek-V4-Flash",
|
|
374
|
-
"reasoning": { "efforts": [{ "id": "off", "name": "Off" }, { "id": "high", "name": "High" }], "defaultEffort": "high" } },
|
|
375
|
-
{ "provider": "openai-codex", "id": "gpt-6-luna", "name": "GPT-6-Luna",
|
|
376
|
-
"reasoning": { "efforts": [{ "id": "low", "name": "Low" }, { "id": "xhigh", "name": "Xhigh" }] } }
|
|
377
|
-
],
|
|
378
|
-
"reasoningEfforts": ["off", "high", "low", "xhigh"],
|
|
379
|
-
"permissionPresets": [
|
|
380
|
-
{ "id": "read-only", "name": "Read Only", "description": "只读 · 拒绝一切写入操作" },
|
|
381
|
-
{ "id": "workspace-write", "name": "Workspace Write", "description": "仅工作区内读写 · 危险操作前询问" },
|
|
382
|
-
{ "id": "danger-full-access", "name": "Danger Full Access", "description": "完全访问 · 可执行任何操作" }
|
|
383
|
-
],
|
|
384
|
-
"agentPresets": [
|
|
385
|
-
{ "id": "standard", "name": "标准模式", "description": "功能完整的编码 Agent:文件编辑、Shell、文件与网页检索、Skills、计划、目标、子代理和工作流" },
|
|
386
|
-
{ "id": "code", "name": "PTC 模式", "description": "—" },
|
|
387
|
-
{ "id": "minimal", "name": "极简模式", "description": "—" },
|
|
388
|
-
{ "id": "cordis", "name": "创造模式", "description": "—" }
|
|
389
|
-
],
|
|
390
|
-
"defaults": {
|
|
391
|
-
"provider": "deepseek-official",
|
|
392
|
-
"model": "deepseek-v4-flash",
|
|
393
|
-
"reasoningEffort": "max",
|
|
394
|
-
"permissionPreset": "workspace-write",
|
|
395
|
-
"agentPreset": "standard"
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
`models[].reasoning` 来自内核模型目录,只对该模型有效;没有该字段表示不支持显式强度。`reasoning.defaultEffort` 可以缺省,此时由提供商决定;`off` 是具体等级而不是“跟随默认”。顶层 `reasoningEfforts` 是历史上的跨模型并集,仅为兼容已发布接口保留;客户端必须按当前模型取能力,不能据此绘制或验证当前模型的按钮。`defaults.provider/model` 是部署默认模型,不是第一个活动会话上次使用的模型。目录通常缓存 15 秒;选择失败后的 `GET /m/api/catalog?refresh=1` 绕过缓存,以便重新展示该模型的最新能力。权限、Agent 预设来自对应宿主服务。
|
|
401
|
-
### 6.3 GET /m/api/session-config
|
|
402
|
-
|
|
403
|
-
```json
|
|
404
|
-
{
|
|
405
|
-
"ok": true,
|
|
406
|
-
"sessionId": "session-abc",
|
|
407
|
-
"config": {
|
|
408
|
-
"provider": "openai-codex",
|
|
409
|
-
"model": "gpt-6-luna",
|
|
410
|
-
"reasoningEffort": "low",
|
|
411
|
-
"permissionPreset": "workspace-write"
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
模型身份与强度读取自 `session/control` 的 `modelSelection.next`(待生效选择),不是可能滞后的 `lastUsed`。内核可能把省略的 effort 具体化为模型默认值,因此返回 `low` 不代表用户曾显式选择了 `low`。
|
|
417
|
-
|
|
418
|
-
### 6.4 POST /m/api/session-config
|
|
419
|
-
|
|
420
|
-
**切换模型**(provider、model 必须成对提供,省略强度即使用新模型默认值):
|
|
421
|
-
|
|
422
|
-
```json
|
|
423
|
-
{ "sessionId": "session-abc", "provider": "openai-codex", "model": "gpt-6-luna" }
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
**只改强度**:`{ "sessionId": "session-abc", "reasoningEffort": "high" }`;**回到模型默认**:`{ "sessionId": "session-abc", "resetReasoningEffort": true }`。两者不可同时提交。服务端使用同一次 `next` 的 provider/model;若 `next` 不可确认,返回 `409 model-selection-unavailable`,不拿 `lastUsed` 或 DeepSeek 兜底。**限定条件(2026-10-04 补充)**:该保证针对**已挂载**会话;对休眠会话,插件在按 `next` 取值后仍会执行 `Object.assign(config, foldFromEvents(events))`,而折叠函数恒返回全部字段(无匹配事件时为 `undefined`),会覆盖投影值——两者同源(都来自 `model/selection` 事件),但休眠会话可能因此报不出 effort。真正的修复方向是核心侧 `readSession` 走 restore 构造路径(见 issue #20)。不支持该模型的显式强度由内核拒绝,目录过期时客户端应刷新目录并显示错误,不静默降级。
|
|
427
|
-
|
|
428
|
-
- `permissionPreset` 为 `danger-full-access` 时 `confirmDanger` 必须为 `true`,否则 `400 { "error": "risk-confirmation-required" }`(与 PC 端 Full access 需显式确认风险一致)。
|
|
429
|
-
- 权限写入走 PC 端同一路径(`permission/preset` + sandbox/approval 旋钮事件)。
|
|
430
|
-
- 模型选择会产生内核 `model/selection` 事件;`404 session-not-found` 通常表示会话不存在——但**请求带 `permissionPreset` 时,休眠(未挂载)会话也会 404**:权限预设需要本地 Session 对象才能 `applyPermissionPreset`,无法像模型/强度那样经内核 `selectModel` 对持久化会话生效(2026-10-04 补充)。
|
|
431
|
-
### 6.5 POST /m/api/sessions(新建会话)
|
|
432
|
-
|
|
433
|
-
**请求**:
|
|
434
|
-
```json
|
|
435
|
-
{
|
|
436
|
-
"preset": "standard",
|
|
437
|
-
"provider": "openai-codex",
|
|
438
|
-
"model": "gpt-6-luna",
|
|
439
|
-
"reasoningEffort": "high",
|
|
440
|
-
"permissionPreset": "workspace-write"
|
|
441
|
-
}
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
- `preset` 未传时使用服务端 Agent 预设默认值;`provider` 和 `model` 必须一起指定,未指定时采用内核部署默认选择(包含部署默认强度),不沿用现有会话配置。主动指定新模型而省略 `reasoningEffort` 时采用该模型默认强度;具体等级由内核校验。
|
|
445
|
-
- 新建页模型草稿不修改已有会话。服务端先确定完整模型身份,再创建 agent 并选择模型;选择或附加配置失败时清理新建会话,返回错误而非假报成功。
|
|
446
|
-
**响应**:`200 { "ok": true, "sessionId": "session-xyz", "agentId": "session-xyz" }`——客户端随后即可 `POST /api/send` 或订阅 SSE 该会话。
|
|
447
|
-
### 6.6 GET /m/api/notifications
|
|
448
|
-
|
|
449
|
-
通知由服务端从会话事件流**聚合**(不新增存储):
|
|
450
|
-
|
|
451
|
-
```json
|
|
452
|
-
{
|
|
453
|
-
"ok": true,
|
|
454
|
-
"unread": 2,
|
|
455
|
-
"items": [
|
|
456
|
-
{ "id": "n-1", "kind": "needs-answer", "sessionId": "session-abc", "title": "需要你回答", "detail": "发现 214 个重复文件,是否删除以释放空间?", "time": 1750000000000, "unread": true },
|
|
457
|
-
{ "id": "n-2", "kind": "completed", "sessionId": "session-abc", "title": "任务完成", "detail": "备份配置到 E 盘(耗时 4 分钟)", "time": 1750000000000, "unread": true },
|
|
458
|
-
{ "id": "n-3", "kind": "failed", "sessionId": "session-def", "title": "任务失败", "detail": "日志分析任务执行失败,已自动重试", "time": 1750000000000, "unread": false }
|
|
459
|
-
]
|
|
460
|
-
}
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
- `kind`:`completed`(turn/end 正常)、`needs-answer`(等待人类决策——从审批/提问相关事件推导,Phase 1 实现时验证语义)、`failed`(turn/end 异常/aborted)。
|
|
464
|
-
- **未读状态持久化**:插件在 settings 域保存已读 id 集合(`ctx.settings`),服务重启不丢。
|
|
465
|
-
- 排序:时间倒序;上限 100 条。
|
|
466
|
-
### 6.7 POST /m/api/notifications/read
|
|
467
|
-
|
|
468
|
-
```json
|
|
469
|
-
{ "ids": ["n-1", "n-2"] }
|
|
470
|
-
```
|
|
471
|
-
或 `{ "all": true }`。响应 `200 { "ok": true }`。
|
|
472
|
-
### 6.7b POST /m/api/notifications/delete(v2.3)
|
|
473
|
-
|
|
474
|
-
```json
|
|
475
|
-
{ "ids": ["n-1", "n-2"] }
|
|
476
|
-
```
|
|
477
|
-
或 `{ "all": true }`。删除移动端通知镜像中的记录(不影响 PC 端自己的通知中心);不设墓碑——后续新事件仍会正常生成新通知。删除后经 SSE 广播 `notifications/changed` 帧,客户端刷新列表与未读角标。响应 `200 { "ok": true }`。
|
|
478
|
-
### 6.7c POST /m/api/respond(v2.3,问询/审批弹窗)
|
|
479
|
-
|
|
480
|
-
回答内核人类问询(`ask_user_question` 工具)或权限审批。插件经 `apiProxy.respond` 回写,**与 PC 端 GUI 完全同一 pending 通道与校验**(`matchesQuestions`、审批决策等由内核把关):
|
|
481
|
-
|
|
482
|
-
**问询**(`kind: "question"`,answers 顺序与提问一致、每问必答):
|
|
483
|
-
|
|
484
|
-
```json
|
|
485
|
-
{ "kind": "question", "rpcId": "<frame 携带的 rpcId>", "sessionId": "session-abc",
|
|
486
|
-
"answers": [ { "id": "q1", "selected": ["方案A"] }, { "id": "q2", "selected": [], "custom": "先跳过" } ] }
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
- 单选:`selected` 至多 1 项;给了 `custom` 则 `selected` 必须为空(二选一)。
|
|
490
|
-
- 多选:`selected` 多项;`custom` 可与之并存。
|
|
491
|
-
- `selected` 必须是提问声明的选项 label。
|
|
492
|
-
|
|
493
|
-
**审批**(`kind: "approval"`):
|
|
494
|
-
|
|
495
|
-
```json
|
|
496
|
-
{ "kind": "approval", "rpcId": "...", "sessionId": "session-abc", "approvalId": "a-1", "outcome": "allowed-once" }
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
- `outcome`:`allowed-once` | `rejected`。
|
|
500
|
-
|
|
501
|
-
**取消**(`kind: "cancel"`):必须携带对应 `sessionId`;问询以 `UserQuestionError`/`ASK_CANCELLED` rejection 结算,审批以 `cancelled` 结算。
|
|
502
|
-
|
|
503
|
-
响应:`200 { "ok": true, "accepted": true }`;`accepted: false` + `reason`(如 `not-pending`,PC 端已先回答)。
|
|
504
|
-
|
|
505
|
-
**SSE 帧**:`question/requested`(含 `questions[]`)、`question/resolved`、`approval/requested`(toolName/reason)、`approval/resolved`,经 `mobile/frame` 帧推送;App 断线重连时服务端补发挂起的待答帧。
|
|
506
|
-
### 6.8 GET /m/api/actions
|
|
507
|
-
|
|
508
|
-
**动作契约 v0.1**(可选能力,插件不注册则返回空数组,客户端隐藏动作区):
|
|
509
|
-
|
|
510
|
-
```json
|
|
511
|
-
{
|
|
512
|
-
"ok": true,
|
|
513
|
-
"actions": [
|
|
514
|
-
{ "id": "fs-cleanup", "title": "清理磁盘", "icon": "trash", "fields": [ { "key": "target", "label": "目标目录", "placeholder": "如 F:\\资料" } ] },
|
|
515
|
-
{ "id": "test-run", "title": "跑测试", "icon": "zap", "fields": [] }
|
|
516
|
-
]
|
|
517
|
-
}
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
- 服务端注册表:`ctx.mobileActions.register({ id, title, icon, fields?, handler })`——id 冲突抛错(Cordis 语义);插件卸载随 fiber dispose 自动移除。
|
|
521
|
-
- `icon` 限定为移动端内置图标库的 id(不允许插件自带 UI/图标)。
|
|
522
|
-
- `fields`:v0.1 仅支持 `text` 类型字段。
|
|
523
|
-
### 6.9 POST /m/api/actions/:id/invoke
|
|
524
|
-
|
|
525
|
-
**请求**:`{ "args": { "target": "F:\\资料" } }`
|
|
526
|
-
|
|
527
|
-
- 服务端校验注册表存在与参数类型,调用 `handler(args)`(跑在电脑端)。
|
|
528
|
-
- 执行结果**不直接返回**(可能长任务):`200 { "ok": true, "accepted": true }`;后续进展经 SSE 会话事件回流(动作应通过既有消息/工具通道呈现)。
|
|
529
|
-
### 6.10 GET /m/api/qr-config(桌面二维码数据,v2.1)
|
|
530
|
-
**仅电脑本机可访问**(TCP 层 socket 来源,仅 loopback 可访问;否则 403 `loopback-only`)—— 桌面 dsh 设置页客户端模块用它生成「连接移动端设备」二维码。
|
|
531
|
-
> v2.6.0:`/m/qr.png`(二维码图片渲染,供设置页 `<img>` 使用)同样收口——Host 校验 + loopback 来源,非本机 403。
|
|
532
|
-
**响应**:`{ "ok": true, "urls": ["http://192.168.1.100:3080/m", ...], "token": "<authToken>", "path": "/m" }`
|
|
533
|
-
|
|
534
|
-
> v3.0.0:`lanBridge.enabled` 且监听成功时,`urls` 首选为桥地址(`http://<电脑局域网IP>:<lanBridge.port>/m`,端口默认 3080);绑定失败自动回退 webserver 地址(不指向死端口)。
|
|
535
|
-
|
|
536
|
-
二维码内容格式:`DSHREMOTE|<地址>|<口令>`(地址取 `urls` 中首个非回环项,不含 /m 尾巴)。App 扫码解析后自动配置连接。
|
|
537
|
-
### 6.11 POST /m/api/defaults(修改默认配置,v2.1)
|
|
538
|
-
修改**默认 Agent 预设 / 默认权限预设**(作用于之后新建的会话),与 PC 端设置页同一写入通道(走 `/api` 调 `settings.update`,不在 HTTP 回调直接调 settings 服务)。
|
|
539
|
-
**请求**:`{ "agentPreset": "code", "permissionPreset": "workspace-write" }`(两者均可选)
|
|
540
|
-
|
|
541
|
-
**响应**:`200 { "ok": true }`;失败 `400 { "error": "update-failed", "detail": "<原因>" }`
|
|
542
|
-
|
|
543
|
-
### 6.11b GET /m/api/diagnostics(宿主能力自检字段)
|
|
544
|
-
|
|
545
|
-
环境诊断在 `checks` 下提供宿主兼容自检(ADR 0017,**纯增量字段,旧 App 忽略即可**):
|
|
546
|
-
|
|
547
|
-
- `checks.hostCapabilities`:逐项三态 `ok` / `drift` / `missing`。`drift` = 能力语义漂移(服务在、调用不报错、成员形状或实参语义已变)。包含 `jobs.callerShape`、`jobs.eventsApi`、`settings.read`、`gateway.wireStream`、`gateway.eventsPeer`(issue #34,0.2.1 的进程内 Peer 来源)、`permissionPresets.apply`、`permissionPresets.catalog`、`workspaceRegistry.stateWrite`。
|
|
548
|
-
- `checks.hostCapabilityReasons`:仅对 `drift` 项给出的允许清单原因码(如 `settings.read` 的 `settings-get-threw`;`gateway.eventsPeer` 的 `gateway-peer-source-missing`)。
|
|
549
|
-
- `checks.hostGeneration`:插件实际走到的代际路径——`jobsCaller`(`sessionId` / `agent`)、`settingsRead`(`describe` / `get`)、`wireStreamArgs`(`controlArg` / `legacyArg`)、`eventsPeer`(`createPeer` / `operatorPeer` / `legacy` / `none` / `unknown`)。
|
|
550
|
-
- `checks.remoteEvents` / `checks.approvalMode`:`$events` 双端审批通道是否就绪与实际生效的审批呈现策略。
|
|
551
|
-
|
|
552
|
-
详见 `docs/09-compatibility.md` §2.5/§2.6。
|
|
553
|
-
|
|
554
|
-
### 6.12 错误码补全
|
|
555
|
-
| HTTP | error 值 | 场景 |
|
|
556
|
-
|---|---|---|
|
|
557
|
-
| 400 | `risk-confirmation-required` | 选 danger-full-access 未带 confirmDanger |
|
|
558
|
-
| 400 | `invalid-preset` | preset 不在目录内 |
|
|
559
|
-
| 404 | `action-not-found` | 动作 id 未注册 |
|
|
560
|
-
| 503 | `action-busy` | 同一动作并发执行限制(v0.1 可先不做) |
|
|
561
|
-
|
|
562
|
-
### 6.13 模型提供商(v2.6,与 PC 端「设置 → 模型」同一配置通道)
|
|
563
|
-
> 全部端点需鉴权;密钥只写不读(响应不含密钥本身)。
|
|
564
|
-
|
|
565
|
-
**GET `/m/api/llm-providers`** — 提供商列表(live + dormant)
|
|
566
|
-
```json
|
|
567
|
-
{ "ok": true, "providers": [
|
|
568
|
-
{ "id": "deepseek-official", "name": "DeepSeek", "dormant": false,
|
|
569
|
-
"settingsNs": "llm-deepseek", "settingsPath": [],
|
|
570
|
-
"baseURL": "https://api.deepseek.com", "apiKeyRef": "DEEPSEEK_API_KEY",
|
|
571
|
-
"keyConfigured": true, "keyWritable": true, "catalogModels": [{"id":"deepseek-v4-pro","name":"DeepSeek-V4-Pro"}] },
|
|
572
|
-
{ "id": "anthropic", "name": "anthropic", "dormant": true, "settingsNs": "…", "baseURL": null, "keyConfigured": false }
|
|
573
|
-
]}
|
|
574
|
-
```
|
|
575
|
-
- dormant = 配置目录已声明但未激活(配好 baseURL/密钥即生效);37 个内置 dormant 提供商(anthropic/openai/google/groq 等)
|
|
576
|
-
- `apiKeyRef` 为凭据引用名(如 `DEEPSEEK_API_KEY`),**非密钥本身**;`keyConfigured` 指示是否已存
|
|
577
|
-
|
|
578
|
-
**POST `/m/api/llm-providers/probe`** — 探测端点模型列表
|
|
579
|
-
```json
|
|
580
|
-
请求: { "settingsNs": "llm-deepseek", "baseURL": "https://…", "apiKey": "可选", "protocol": "可选" }
|
|
581
|
-
响应: { "ok": true, "models": [{"id":"…","name":"…","contextWindow":…}], "fallback": true }
|
|
582
|
-
```
|
|
583
|
-
- 优先内核 `discoverModels`;内核未注册模型探测时回退 OpenAI 兼容 `GET {baseURL}/models`
|
|
584
|
-
- 凭据一次性使用,不存储;仅允许探测配置目录声明的命名空间
|
|
585
|
-
|
|
586
|
-
**POST `/m/api/llm-providers`** — 保存提供商配置
|
|
587
|
-
```json
|
|
588
|
-
请求: { "provider": "deepseek-official", "settingsNs": "llm-deepseek",
|
|
589
|
-
"baseURL": "https://…", "apiKey": "可选(留空不修改)", "removeKey": false }
|
|
590
|
-
响应: { "ok": true, "provider": "…", "apiKeyRef": "…", "keyConfigured": true }
|
|
591
|
-
```
|
|
592
|
-
- 经 `settings.mutate` 写配置 + `credentials.set` 存密钥(引用派生规则与 PC 端一致:`<PROVIDER>_API_KEY`)
|
|
593
|
-
- 仅允许写入配置目录声明的命名空间(`400 unknown-provider`);`removeKey: true` 清除已存密钥
|
|
594
|
-
|
|
595
|
-
### 6.14 会话工具(v2.7:任务 / 子代理 / 目标,PC 端 GUI 同源)
|
|
596
|
-
> 全部端点需鉴权;数据与 PC 端「任务 / 子代理 / 目标」同一内核服务,手机只读 + 简单操作。
|
|
597
|
-
|
|
598
|
-
**GET `/m/api/jobs?sessionId=可选`** — 会话后台任务列表(不传 sessionId 返回全部)
|
|
599
|
-
```json
|
|
600
|
-
{ "ok": true, "sessionId": "…", "jobs": [
|
|
601
|
-
{ "id": "…", "kind": "task", "label": "…", "status": "running",
|
|
602
|
-
"startedAt": 1786987923387, "finishedAt": 1786987923387 }
|
|
603
|
-
]}
|
|
604
|
-
```
|
|
605
|
-
- 状态:`running / stopping / completed / failed`;任务视图与 SSE `session/jobs` 帧同源
|
|
606
|
-
- 会话不存在 `404 session-not-found`;jobs 服务不可用 `503 jobs-unavailable`
|
|
607
|
-
|
|
608
|
-
**POST `/m/api/jobs/kill`** — 取消任务
|
|
609
|
-
```json
|
|
610
|
-
请求: { "sessionId": "可选", "jobId": "…" }
|
|
611
|
-
响应: { "ok": true }
|
|
612
|
-
```
|
|
613
|
-
- 映射内核 `jobs.kill(jobId, agent, reason)`;失败 `400 job-kill-failed`
|
|
614
|
-
|
|
615
|
-
**GET `/m/api/subagents?parentSessionId=…`** — 子代理列表(按父会话)
|
|
616
|
-
```json
|
|
617
|
-
{ "ok": true, "parentAvailable": true, "catalogDegraded": true, "subagents": [
|
|
618
|
-
{ "id": "…", "kind": "child", "status": "running", "title": "…", "createdAt": 1730000000000 }
|
|
619
|
-
]}
|
|
620
|
-
```
|
|
621
|
-
- 目录来源按优先级取:① 宿主持久目录 `ctx.subagents.listChildren(parentSessionId)` → ② 持久化枚举(父会话休眠/归档时入口不消失)→ ③ 会话注册表派生。
|
|
622
|
-
**不调用 `subagents/list` Remote 端点**——该端点在宿主 0.2.0 已被删除
|
|
623
|
-
- `kind`:`child`(普通子代理)或 `diagnostic`(目录 `mode: "unknown"` 的不受支持条目,此时 `status` 为原因 `unsupported`)
|
|
624
|
-
- `status`:活 agent 的 AgentStatus 映射(`running`/`inactive`)或 diagnostic reason
|
|
625
|
-
- `createdAt` 可选,用于排序;`catalogDegraded: true` 表示来源 ②/③ 不完整,客户端据此区分"确实没有子代理"与"目录读不到"
|
|
626
|
-
- 缺参数 `400 parentSessionId-required`;三条路径都取不到会话 `404 session-not-found`
|
|
627
|
-
|
|
628
|
-
**POST `/m/api/subagents/interrupt`** — 中断子代理
|
|
629
|
-
```json
|
|
630
|
-
请求: { "parentSessionId": "…", "childSessionId": "…" }
|
|
631
|
-
响应: { "ok": true }
|
|
632
|
-
```
|
|
633
|
-
- 映射内核 `subagent.interrupt`(payload `{ parentSessionId, childSessionId, mode: "continuable" }`)
|
|
634
|
-
|
|
635
|
-
**GET `/m/api/goal?sessionId=…`** — 当前目标(无目标返回 `{ "goal": null }`)
|
|
636
|
-
```json
|
|
637
|
-
{ "ok": true, "goal": { "id": "…", "revision": 1, "objective": "…",
|
|
638
|
-
"phase": "active", "maxGoalRounds": 256, "roundsStarted": 0,
|
|
639
|
-
"createdAt": 1786987923387, "updatedAt": 1786987923387, "activation": "armed" } }
|
|
640
|
-
```
|
|
641
|
-
- `phase`: active / paused / blocked / complete;blocked 时含 `blockedReason`(如轮次耗尽)
|
|
642
|
-
- 无会话 `503 goal-unavailable`
|
|
643
|
-
|
|
644
|
-
**POST `/m/api/goal`** — 创建 / 暂停 / 继续 / 完成
|
|
645
|
-
```json
|
|
646
|
-
请求: { "action": "create|pause|resume|complete", "sessionId": "…",
|
|
647
|
-
"objective": "create 必填", "maxGoalRounds": "create 可选" }
|
|
648
|
-
响应: { "ok": true }
|
|
649
|
-
```
|
|
650
|
-
- 映射内核 goal RPC(契约一致:create 需 `sessionId + objective`;pause/resume/complete 需 `sessionId + ref`,ref 由插件经 `goals.get(agent)` 自动取得)
|
|
651
|
-
- 缺参 `400 sessionId-required / objective-required`;无当前目标 `400 no-active-goal`;非法 action `400 bad-action`
|
|
652
|
-
|
|
653
|
-
### 6.15 斜杠命令(v2.8.0 引入 / v2.8.2 适配内核 0.1.1-rc.2)
|
|
654
|
-
|
|
655
|
-
**GET `/m/api/commands?sessionId=…`** — 命令目录(对齐内核 `ctx.commands`)
|
|
656
|
-
```json
|
|
657
|
-
{ "ok": true, "commands": [
|
|
658
|
-
{ "name": "goal", "description": "set or view the goal for a long-running task",
|
|
659
|
-
"input": { "hint": "[<objective>|clear|edit <objective>|pause|resume]", "attachments": true } }
|
|
660
|
-
] }
|
|
661
|
-
```
|
|
662
|
-
- 命令条目:`name` / `description` 必填;`input`(`hint` / `attachments`)可选,有则返回——**原样透传**内核 `commands.list()` 的描述符,插件不改写字段
|
|
663
|
-
- ⚠️ **字段名是 `attachments`,不是 `images`**(内核 `dsh-commands` 与 PC 端客户端均判定 `input.attachments === true`)。本文档 2026-10-04 修正,此前误写为 `images` —— 按旧文档实现会永远读不到该标志
|
|
664
|
-
- `commands` 服务未注册(无 dsh-commands host 服务)→ `200 { ok, commands: [], unavailable: true }`(App 端弹「无可用命令」,不硬 503)
|
|
665
|
-
- 会话不存在 → `404 session-not-found`;缺 `sessionId` → `400 bad-request`。**GET 要求会话已挂载**(`agents.get(sessionId)` 命中):休眠/未挂载会话返回 404 —— 这与 `/send`(会先自动 resume 再发)不同,客户端不能假设"能发消息就一定能列命令"
|
|
666
|
-
|
|
667
|
-
**POST `/m/api/commands`** — 执行斜杠命令
|
|
668
|
-
```json
|
|
669
|
-
请求: { "sessionId": "…", "line": "/goal" }
|
|
670
|
-
响应: { "ok": true, "result": { "commandId": "cmd-…", "result": { "kind": "success", "text": "…" } } }
|
|
671
|
-
```
|
|
672
|
-
- 映射内核 `commands.execute(agent, line, images, signal)`(0.1.1-rc.2 四参签名;本插件 `images` 恒为空数组,`signal` 为 15s 超时中止;2.8.1 的旧三参调用会把 AbortSignal 误传 images 槽,已改正)
|
|
673
|
-
- 缺 `sessionId` → `400 missing-sessionId`(注意与 GET 的 `bad-request` **不同码**);`line` 必须以 `/` 开头(否则 `400 bad-request`);未知/畸形命令 `404 command-not-found`;服务未注册 `503 commands-unavailable`(带 detail);服务在而会话不存在 `404 session-not-found`(与 GET 拆分语义一致)
|
|
674
|
-
- **会话必须已挂载**:`agents.get(sessionId)` 未命中即 404。休眠会话需先经 `/send` 唤醒,否则命令无法执行(与 `/send` 的自动 resume 语义不同)
|
|
675
|
-
- `commands.execute` 外层套 `AbortSignal.timeout(15000)`:15s 是**整个命令**的上限。`/compact` 之类会等一次完整的 LLM 摘要,长会话可能超时 → `504 commands-execute-failed`;客户端此时**不能断言失败**(结果未知)
|
|
676
|
-
- `result` 为内核 settle 对象(`commandId` + `result.{kind,text}`),与 PC 端一致
|
|
677
|
-
|
|
678
|
-
### Git API 设计草案(本版本未实现)
|
|
679
|
-
|
|
680
|
-
> 以下 Git endpoints 是设计目标,不属于 v3.1.5 已实现 API;当前 `lib/index.js` 未注册 `/m/api/git/*` 路由,客户端不得依赖这些端点。设计背景见 `docs/design/mobile-git.md` 与 `docs/adr/` 中相关 ADR。
|
|
681
|
-
|
|
682
|
-
Git 接口计划由项目自有 provider 提供,执行通过 DSH `subprocess`,仓库必须位于
|
|
683
|
-
`workspaceRegistry` 已注册工作区内。`repositoryId` 为 provider 分配的不透明仓库标识,客户端不得自行拼接
|
|
684
|
-
shell 命令。Slice A 是只读基础;B1/B2 提供受保护的 stage/commit 与本地分支写操作;B3 增加明确目标的 fetch/pull/push/sync 及冲突 abort,仍不提供删除分支、stash、tags、force push 或手机端冲突编辑。
|
|
685
|
-
|
|
686
|
-
`GET /m/api/git/capabilities` 始终返回 `{ok, git:{available,read,writes,reason,features}}`,不可用时
|
|
687
|
-
由 `available=false` 明确表达;实际仓库操作在 provider 不可用时返回 `503 git-provider-unavailable`。
|
|
688
|
-
`GET /m/api/git/context?sessionId=…` 返回不透明的稳定 `repositoryId`、仓库名称和能力,不返回主机路径。
|
|
689
|
-
其余接口均要求 `repositoryId`:`status` 返回分支与文件状态,`branches` 返回本地/远端分支。
|
|
690
|
-
客户端不得将主机路径当作 B1 写操作的 `repositoryId`;服务端仅接受由 `context` 返回、并在授权工作区内解析的仓库标识。
|
|
691
|
-
`graph` 支持 `limit/cursor` 和可选 JSON `refs`(最多 5 个 `{name,tipOid}` 引用对;本地与远程引用合计);首次请求返回
|
|
692
|
-
`snapshotId`、绑定的 `tips`、提交页和 `nextCursor`,后续请求必须使用同一快照的不透明游标。
|
|
693
|
-
引用移动、删除、tip 不匹配、仓库变化、游标上下文错误或快照过期返回 `409 graph-stale`,客户端不得
|
|
694
|
-
静默回退到全量图。`commit` 要求 `oid`,`diff` 支持 `kind=working|staged|commit`、`oid/path`。
|
|
695
|
-
越过工作区边界返回 `403 workspace-not-allowed`,非 Git 目录返回 `404 not-git-repository`。
|
|
696
|
-
|
|
697
|
-
#### Slice B0 操作任务
|
|
698
|
-
|
|
699
|
-
B0 在同一 Git 移动契约下提供持久化任务查询基础设施。`GET /m/api/git/operations` 支持
|
|
700
|
-
`repositoryId`、`status`、`limit`(1–100)和不透明 `cursor`;`GET
|
|
701
|
-
/m/api/git/operations/:operationId` 查询单项任务。查询响应包含 `operationId`、`requestId`、`repositoryId`、`kind`、`status`、`revision`、阶段、可取消性、结果/脱敏错误和恢复阻塞事实。
|
|
702
|
-
|
|
703
|
-
`POST /m/api/git/operations/:operationId/cancel` 的 JSON 请求体必须包含新的控制
|
|
704
|
-
`requestId` 和查询时的 `expectedRevision`。它只接受 `queued` 或 `running`;排队任务立即进入
|
|
705
|
-
`cancelled`,运行任务先持久化取消请求再尽力终止子进程,不能宣称已回滚。重复的相同控制
|
|
706
|
-
`requestId` 返回原结果,revision 不匹配返回 `409 state-changed`。
|
|
707
|
-
|
|
708
|
-
任务状态为 `queued`、`running` 或终态 `succeeded`、`failed`、`cancelled`、`conflicted`、
|
|
709
|
-
`unknown-result`。`POST /m/api/git/recovery/acknowledge` 必须携带新的控制
|
|
710
|
-
`requestId`、`operationId`、`repositoryId` 和 `expectedRevision`;它只解除用户已查看事实后的
|
|
711
|
-
恢复阻塞,不重放旧操作。SSE `/m/api/events` 增加 `git/operation` 帧,包含完整操作视图和单调
|
|
712
|
-
`revision`;B1 的 `git/changed` 帧仍至少包含 `repositoryId`,并可带 `changeKinds`(如 `index`、`head`)提示
|
|
713
|
-
客户端刷新对应事实。事件重复或丢失都不改变账本事实,客户端重连后必须重新查询 operationId。
|
|
714
|
-
B0 不定义具体 Git 写操作;B1/B2 写端点复用 B0 任务账本。所有返回 `202` 的执行端点统一返回 accepted DTO:
|
|
715
|
-
`{ok:true,accepted:true,operationId,requestId,status,deduplicated,queryUrl,queryLink,operation}`。
|
|
716
|
-
其中 `queryUrl`/`queryLink` 是可直接 GET 的相对链接 `/git/operations/:operationId`;客户端应按该链接查询,不能把 `operation` 快照当作最终结果。
|
|
717
|
-
`git.capabilities.operations` 用于声明任务账本、幂等、恢复和取消基础设施是否可用。
|
|
718
|
-
|
|
719
|
-
#### Slice B1 暂存与精确提交
|
|
720
|
-
|
|
721
|
-
`POST /m/api/git/change-sets` 请求 `{repositoryId,kind}`,其中 `kind` 为 `working|staged`;响应返回
|
|
722
|
-
短期 `changeSetId`、`stateVersion`、`preconditionToken` 和文件/可选 hunk 清单。客户端只提交
|
|
723
|
-
`fileId` 与 `hunkId`,不得提交 patch;未跟踪、二进制和重命名首版仅支持整文件操作。
|
|
724
|
-
|
|
725
|
-
`POST /m/api/git/stage` 与 `/m/api/git/unstage` 请求 `{repositoryId,requestId,changeSetId,
|
|
726
|
-
preconditionToken,selections}`,`selections` 为 `[{fileId,hunkIds?}]`,立即返回 `202` 的 Git 操作任务。
|
|
727
|
-
服务端在私有临时 index 中执行并通过 Git index lock 原子安装,change-set 事实变化返回
|
|
728
|
-
`409 state-changed` 或 `409 hunk-stale`,不会部分应用。
|
|
729
|
-
|
|
730
|
-
`POST /m/api/git/commit/preflight` 请求 `{repositoryId,message}`,响应返回 staged tree、当前 HEAD、
|
|
731
|
-
本地分支、提交身份和绑定这些事实的 `preconditionToken`。随后 `POST /m/api/git/commit` 请求
|
|
732
|
-
`{repositoryId,requestId,message,preconditionToken,confirm:true}`,立即返回 `202` 任务;提交任务使用
|
|
733
|
-
`commit-tree` 加 expected HEAD 的 `update-ref` CAS,不运行 hooks,HEAD/tree 变化返回
|
|
734
|
-
`409 state-changed`。任务成功结果包含新 commit OID、tree OID 和分支。
|
|
735
|
-
|
|
736
|
-
#### Slice B2 本地分支与受保护切换
|
|
737
|
-
|
|
738
|
-
`POST /m/api/git/branches/preflight` 的 `action` 只能为 `create|rename`(缺失或其他值均为
|
|
739
|
-
`400 invalid-argument`)。预检返回规范化的 `params`;执行请求必须携带**同一个** `params` 对象,另加
|
|
740
|
-
`{repositoryId,requestId,preconditionToken}`。创建参数为 `{name,startOid,remoteRef?}`(默认从当前 HEAD,
|
|
741
|
-
远端起点必须是已验证且仍存在的精确 `refs/remotes/<remote>/<branch>`);rename 参数为
|
|
742
|
-
`{oldName,name,oldOid}`。创建成功不会自动切换。
|
|
743
|
-
|
|
744
|
-
`POST /m/api/git/branch-rename` 使用 `{repositoryId,requestId,params:{oldName,name,oldOid},preconditionToken}`,
|
|
745
|
-
只重命名本地分支,不修改远端引用。非法/重复/不存在分支分别返回稳定的 `invalid-argument`、
|
|
746
|
-
`branch-exists` 或 `branch-not-found`。
|
|
747
|
-
|
|
748
|
-
`POST /m/api/git/branch-switch/preflight` 的 action 固定为 `switch`,使用 `targetBranch` 或已验证的
|
|
749
|
-
`targetRef`。远端引用必须是 provider 精确验证的 `refs/remotes/<remote>/<branch>`;远端切换必须明确
|
|
750
|
-
`localName`,该值同时成为规范 `params.targetBranch`,不会隐式猜测本地名称。返回目标 OID 与影响摘要。
|
|
751
|
-
干净工作区或 Git 可安全携带的改动返回 `safe:true` 和 token;存在覆盖风险时返回 `safe:false` 及
|
|
752
|
-
`allowedActions: ["commit","computer","cancel"]`,不签发强制切换 token。`POST /m/api/git/branch-switch`
|
|
753
|
-
必须提交预检返回的同一 `params`,只执行无 force 的安全切换;所有分支写操作均作为 B0 Git 操作任务返回
|
|
754
|
-
`202` accepted DTO。
|
|
755
|
-
|
|
756
|
-
#### Slice B3 远端同步
|
|
757
|
-
|
|
758
|
-
B3 的写请求必须携带 `X-DSH-Git-Contract: 2.x`(或等价的
|
|
759
|
-
`X-DSH-Git-Mobile-Contract`)版本声明;缺失或主版本不兼容返回
|
|
760
|
-
`409 client-incompatible`。所有执行端点只接受预检返回的规范 `params` 和短期
|
|
761
|
-
`preconditionToken`,不接受远端 URL、任意 refspec、OID 或命令选项。
|
|
762
|
-
|
|
763
|
-
- `GET /m/api/git/remotes?repositoryId=…` 返回已配置 remote、脱敏 URL、remote-tracking 分支和本地 upstream;远端凭据不进入 DTO、账本或错误。
|
|
764
|
-
- `POST /m/api/git/fetch/preflight` 请求 `{repositoryId,remote,branch}`,随后
|
|
765
|
-
`POST /m/api/git/fetch` 执行只更新对应 `refs/remotes/<remote>/<branch>` 的 fetch。
|
|
766
|
-
- `POST /m/api/git/pull/preflight` 请求 `{repositoryId,remote?,branch?,localBranch?,strategy?}`,随后
|
|
767
|
-
`POST /m/api/git/pull` 执行 fetch→固定 OID 的 merge/rebase 两阶段;默认策略为 merge。
|
|
768
|
-
- `POST /m/api/git/push/preflight` 请求 `{repositoryId,remote,branch,localBranch?,setUpstream?}`,随后
|
|
769
|
-
`POST /m/api/git/push` 执行明确的 `refs/heads/<local>:refs/heads/<branch>` 普通 push;目标不存在时允许创建该单一目标 ref。
|
|
770
|
-
force/force-with-lease 永不支持;只有远端确认成功后才写入 upstream 配置。
|
|
771
|
-
- `POST /m/api/git/sync/preflight` 与 `POST /m/api/git/sync` 执行非原子的
|
|
772
|
-
fetch→pull→push;新建的远端目标会跳过没有目标可取的 fetch/integrate 阶段,直接以普通 push 创建单一目标 ref。
|
|
773
|
-
操作查询中的 `stages[]` 保存每阶段状态、跳过原因、前后事实和副作用;任一阶段失败、冲突、取消或不确定都会停止后续阶段并保留部分成功结果。
|
|
774
|
-
- `POST /m/api/git/abort/preflight` 返回当前 merge/rebase 中间态的影响摘要;随后先经
|
|
775
|
-
`POST /m/api/git/confirmations` 签发一次性挑战,再由 `POST /m/api/git/abort` 创建独立 abort 任务;签发记录可跨服务重启幂等复用,挑战消费和任务创建在同一持久化账本事务中完成。
|
|
776
|
-
abort 不由普通 cancel 隐式执行。
|
|
777
|
-
- `POST /m/api/git/operations/:operationId/handoff` 的 `target` 为 `computer|model`,只记录冲突交接意图;移动端不自动 continue、commit 或 push。
|
|
778
|
-
|
|
779
|
-
所有 B3 执行端点返回 `202` accepted DTO。fetch/pull/push/sync/abort 使用不同协调域:
|
|
780
|
-
fetch/push 序列化 common domain,pull/sync/abort 同时序列化 common 与 worktree domain。
|
|
781
|
-
远端认证、网络、远端拒绝、非 fast-forward 分别映射为稳定错误;连接中断或结果无法
|
|
782
|
-
从读事实证明时进入 `unknown-result`,而不是自动重试。
|
|
783
|
-
|
|
784
|
-
### 6.16 GET /m/api/account-usage(用量与额度,v3.1.5)
|
|
785
|
-
|
|
786
|
-
服务端并发查询三个固定来源,凭据只在电脑端解析和使用;手机端只接收成功来源的脱敏投影。默认使用电脑进程内 60 秒快照;详情页顶部刷新使用 `?refresh=1` 绕过快照并发起一轮新的查询(2 秒内重复刷新受保护)。来源固定按 DeepSeek → Codex → OpenCode Go 排列,未配置/未登录来源不返回,已配置但本次查询失败的来源也不返回。
|
|
787
|
-
|
|
788
|
-
```json
|
|
789
|
-
{
|
|
790
|
-
"ok": true,
|
|
791
|
-
"fetchedAt": "2026-08-30T12:00:00.000Z",
|
|
792
|
-
"availableCount": 3,
|
|
793
|
-
"failedCount": 0,
|
|
794
|
-
"sources": [
|
|
795
|
-
{ "id": "deepseek", "title": "DeepSeek", "kind": "balance",
|
|
796
|
-
"amount": "12.50", "currency": "CNY", "available": true },
|
|
797
|
-
{ "id": "codex", "title": "Codex", "kind": "quota",
|
|
798
|
-
"account": { "displayName": "Personal", "maskedEmail": "p***@example.com" },
|
|
799
|
-
"windows": [
|
|
800
|
-
{ "window": "5h", "remainingPercent": 72, "resetAt": "2026-08-30T13:00:00.000Z" },
|
|
801
|
-
{ "window": "weekly", "remainingPercent": 64 }
|
|
802
|
-
],
|
|
803
|
-
"credits": { "unlimited": false, "balance": "8.00" },
|
|
804
|
-
"individualLimit": { "limit": "100", "used": "28", "remaining": "72", "remainingPercent": 72 }
|
|
805
|
-
},
|
|
806
|
-
{ "id": "opencode-go", "title": "OpenCode Go", "kind": "quota",
|
|
807
|
-
"windows": [
|
|
808
|
-
{ "window": "5h", "remainingPercent": 91 },
|
|
809
|
-
{ "window": "weekly", "remainingPercent": 83 },
|
|
810
|
-
{ "window": "monthly", "remainingPercent": 76 }
|
|
811
|
-
]
|
|
812
|
-
}
|
|
813
|
-
]
|
|
814
|
-
}
|
|
815
|
-
```
|
|
816
|
-
|
|
817
|
-
- Codex 通过 `dsh-codex-connect` 的 `OpenAICodexCredentialStore`、`openAICodexAuthStatus` 与 `readOpenAICodexRateLimits` 查询同一份当前活动账户快照;若 Codex 配置启用代理,额度请求复用其 `OpenAICodexProxyManager`,代理不可用时不直连;不读取/复制 OAuth 文件,不返回 token。
|
|
818
|
-
- OpenCode Go 优先读取 `llm-pi-ai` 的 `opencode-go.apiKeyEnv`,其次读取 `llm-pi-ai/opencode-go` API-key record,再回退 `OPENCODE_GO_API_KEY` / `OPENCODE_API_KEY`;请求固定发送到官方 `GET https://opencode.ai/zen/go/v1/usage`,不接受任意 baseURL。`percent` 转换为 `remainingPercent = 100 - percent`,`rate-limited` 窗口仍保留并标记 `limited: true`。
|
|
819
|
-
- `failedCount` 只统计“已配置但本次查询失败”的来源;未配置来源不算失败。`failedCount > 0` 时 App 显示汇总提示,不显示失败来源细节。
|
|
820
|
-
- 查询快照在电脑进程内缓存 60 秒并共享并发请求;手动 `refresh=1` 的连点在 2 秒内复用快照;不写手机或电脑持久化文件。配额窗口不相加,有限 Credits 和个人消费上限分别展示。
|
|
821
|
-
- HTTP 错误只返回通用 `502 account-usage-failed`(单来源失败不会使整体请求失败)。
|
|
822
|
-
|
|
823
|
-
**悬浮球面板消费语义(v3.1.5,ADR 0008)**:原生悬浮球面板把本端点当作「展开时按需读取」的快照——每次展开面板最多触发一次查询(客户端 2 分钟节流,不并入面板打开期间的 5 秒轮询,也不做后台周期轮询);成功快照在进程内保留,失败时沿用旧值并标注相对时间;投影不可用(旧插件 404 / 未配置 / 全部失败)时,面板整体降级为原有的单行 DeepSeek 余额。面板按「一个来源一行」渲染:金额来源保留文字(CNY 优先),配额来源只显示主 bucket 窗口的细条与颜色、不出百分比数字,每个进度条上方居中显示窗口短标签(5h / 每周 / 每月,与详情页窗口语义一致);附加 bucket(服务端命名的 `名称 · 5h`)与账户身份不出现 overlay 面板,详情页仍是完整信息入口(`displayName`/`maskedEmail`、Credits、个人消费上限、重置时间)。
|
|
824
|
-
|
|
825
|
-
### 6.17 文件传输(v3.1.2,B站 csborbbnc 反馈)
|
|
826
|
-
|
|
827
|
-
**GET `/m/api/files?path=…`** — 下载电脑文件
|
|
828
|
-
- 响应:`200` 文件流(`content-type` 按扩展名推断、`content-disposition: attachment` 带 UTF-8 文件名);路径不存在或非文件 → `404 file-not-found`;缺 `path` → `400 bad-request`
|
|
829
|
-
- 与目录选择器(§6.2)同信任模型:口令鉴权 + 现有限流,路径由手机显式指定;服务端先打开句柄、`fstat` 复核为普通文件,再按 descriptor 真实路径做工作区包含校验,符号链接/越界路径一律 `404`
|
|
830
|
-
- 平台范围:descriptor-relative 保护需 procfs/devfs,**仅 Linux/macOS 提供**;Windows 返回 `503 files-unavailable`(安全 fail-closed,见 docs/04 §6)
|
|
831
|
-
|
|
832
|
-
**POST `/m/api/files/upload`** — 上传文件到电脑(写会话工作目录)
|
|
833
|
-
```json
|
|
834
|
-
请求: { "sessionId": "…(可选)", "name": "README.md", "data": "<base64>" }
|
|
835
|
-
响应: { "ok": true, "path": "F:\\DSH-Outpost\\README.md", "bytes": 1234 }
|
|
836
|
-
```
|
|
837
|
-
- 目标目录:`sessionId` 对应 agent 的工作目录 → 缺省回退第一个注册工作区根;无法确定 → `404 workspace-not-found`(不再静默写入其它 workspace)
|
|
838
|
-
- 服务端先打开并校验目录句柄,再通过 descriptor-relative + `O_CREAT|O_EXCL|O_NOFOLLOW` 创建目标,目录替换/符号链接竞态不会越界;当前平台不具备 descriptor fs 时 fail-closed → `503 files-unavailable`
|
|
839
|
-
- `name` 不合法(含 `\ / : * ? " < > |`、`.`/`..`/超 255)→ `400 invalid-name`;同名已存在 → `409 file-exists`;body 上限 64MB → `413 payload-too-large`
|
|
840
|
-
|
|
841
|
-
### 6.18 GET /m/api/turn-outline(轮次大纲,轮次导航)
|
|
842
|
-
|
|
843
|
-
> 只读端点:把宿主 `turnOutline` 投影(电脑端刻度轨消费的同一份轮次摘要)**薄透出**为移动端契约。插件只做投影读取与形状稳定化,**不自己折叠会话日志**——轮次边界与预览文字只有宿主一个权威来源,避免桌面端与手机端在边界条件上出现两种答案。不改变会话内容/轮次边界,不写任何持久状态,不新增会话事件类型。
|
|
844
|
-
|
|
845
|
-
**查询参数**:`sessionId`(必填;缺 → `400 bad-request`)。
|
|
846
|
-
|
|
847
|
-
**响应 200(可用态)**
|
|
848
|
-
|
|
849
|
-
```json
|
|
850
|
-
{
|
|
851
|
-
"ok": true,
|
|
852
|
-
"sessionId": "session-abc",
|
|
853
|
-
"state": "available",
|
|
854
|
-
"asOfSeq": 12873,
|
|
855
|
-
"turns": [
|
|
856
|
-
{ "turn": 1, "seq": 2048, "prompt": "帮我跑一下测试", "response": "测试结果……" },
|
|
857
|
-
{ "turn": 2, "seq": 5121, "prompt": "", "response": "纯命令轮的回复" }
|
|
858
|
-
],
|
|
859
|
-
"truncated": false,
|
|
860
|
-
"dropped": 0
|
|
861
|
-
}
|
|
862
|
-
```
|
|
863
|
-
|
|
864
|
-
| 字段 | 类型 | 说明 |
|
|
865
|
-
|---|---|---|
|
|
866
|
-
| `state` | string | `available` / `empty` / `capability-missing` / `read-failed`(四态见下) |
|
|
867
|
-
| `asOfSeq` | number \| null | 该投影快照对应的 durable 事件序号;`null` 表示无法确定 |
|
|
868
|
-
| `turns` | array | 轮次摘要,按 `turn` 升序;元素字段见下 |
|
|
869
|
-
| `turns[].turn` | number | 轮次号(从 1 开始) |
|
|
870
|
-
| `turns[].seq` | number | 该轮起始事件(`turn/start`)的 durable 序号,作定位锚点 |
|
|
871
|
-
| `turns[].prompt` | string | 该轮提示词预览;可能为空(纯图片/纯命令轮) |
|
|
872
|
-
| `turns[].response` | string | 该轮回复摘要;可能为空(该轮尚无回复) |
|
|
873
|
-
| `truncated` | boolean | 是否因体积上限截断(仅 `available` 有意义) |
|
|
874
|
-
| `dropped` | number | 被截掉的轮次数;未截断为 `0` |
|
|
875
|
-
|
|
876
|
-
**四态必须显式区分,空数组不得表示「没有轮次」**(同一份投影在不同宿主/会话上的语义差别很大):
|
|
877
|
-
|
|
878
|
-
| `state` | 含义 | 客户端(刻度轨)行为 |
|
|
879
|
-
|---|---|---|
|
|
880
|
-
| `available` | 能力可用且该会话有大纲 | 与「已加载轮次」取并集画完整刻度;未加载轮次可点击(先跨页加载再定位) |
|
|
881
|
-
| `empty` | 能力可用,但该会话暂无大纲(新会话/投影尚未生成) | 退回「只用已加载轮次」的降级行为,不打扰用户 |
|
|
882
|
-
| `capability-missing` | 宿主未注册 `turnOutline` 投影单元,或没有投影感知观察面(**全局能力缺失**) | 同 `empty`;**不得**按宿主版本号自行推断 |
|
|
883
|
-
| `read-failed` | 读取失败;带稳定 `code` 与 `degraded: true` | 退回降级行为,在刻度轨可见时说明一次原因 |
|
|
884
|
-
|
|
885
|
-
`read-failed` 的稳定 `code`:
|
|
886
|
-
|
|
887
|
-
| `code` | 场景 |
|
|
888
|
-
|---|---|
|
|
889
|
-
| `turn-outline-timeout` | 有界等待超时(默认 5000 ms,见下「有界与截断」;从请求到达起算、**包含排队时间**) |
|
|
890
|
-
| `turn-outline-busy` | 冷折叠执行槽队列已满(并发 1、队列上限 8),立刻明确降级而不是无限排队 |
|
|
891
|
-
| `turn-outline-unavailable` | 宿主观察面无法回放完整日志(seeded 前缀校验缺陷等已知兼容问题) |
|
|
892
|
-
|
|
893
|
-
读取失败响应形状(HTTP 仍为 200;这是**明确的降级结果**,不是错误):
|
|
894
|
-
|
|
895
|
-
```json
|
|
896
|
-
{ "ok": true, "sessionId": "session-abc", "state": "read-failed", "code": "turn-outline-timeout", "degraded": true, "turns": [] }
|
|
897
|
-
```
|
|
898
|
-
|
|
899
|
-
> 旧宿主路径(无投影感知观察面)返回的 `capability-missing` 形状为 `{ "ok": true, "sessionId": …, "state": "capability-missing", "turns": [] }`,可能不含 `asOfSeq`/`truncated`/`dropped`;客户端应按 `state` 分支,不依赖字段恒在。
|
|
900
|
-
|
|
901
|
-
**HTTP 错误码**:
|
|
902
|
-
|
|
903
|
-
| HTTP | error 值 | 场景 |
|
|
904
|
-
|---|---|---|
|
|
905
|
-
| 400 | `bad-request` | 缺 `sessionId` |
|
|
906
|
-
| 401 | `auth-required` / `bad-token` | 未提供 / 口令错误(见 §1) |
|
|
907
|
-
| 403 | `host-not-allowed` | Host 不在白名单(见 docs/04) |
|
|
908
|
-
| 404 | `session-not-found` | 会话**明确不存在**(只有这一种情况才 404) |
|
|
909
|
-
| 405 | `method-not-allowed` | 非 GET(HEAD 与其它 GET 端点一致:路由放行、无响应体) |
|
|
910
|
-
| 500 | `session-corrupt` / `event-read-failed` | 会话数据损坏 / 其它读取异常;错误响应不泄露主机路径或原始异常。**明确的超时/繁忙/已知兼容降级不走 5xx**,而是上表的 200 + `read-failed` |
|
|
911
|
-
|
|
912
|
-
**有界与截断**:
|
|
913
|
-
|
|
914
|
-
- **有界等待**:配置项 `turnOutlineTimeoutMs`(schema 默认 **5000 ms**;冷折叠单会话最坏实测 1.8 s,约 3× 余量)。截止后立即向仍连接的客户端回 `read-failed`;底层未结束的观察**不强行打断**(同步折叠不可中断),继续占住执行槽直到结束,迟到的投影 lease 随即释放、**不会回写成功**。客户端断开同样取消请求且之后不再写响应。
|
|
915
|
-
- **冷折叠串行**:并发 1 + 队列上限 8(3 路并发实测 RSS 峰值 831 MB、耗时近似叠加,故不允许无界并发);队列满立刻回 `turn-outline-busy`。
|
|
916
|
-
- **按体积截断**:下发上限 **256 KB**(实测最大 77 KB / 288 轮、p99 29.5 KB)。从**最新**往回保留、至少保留 1 轮;超出部分丢弃并显式标 `truncated: true` / `dropped: N`——绝不静默截断,也不回空数组(回空数组会被读成「没有轮次」)。
|
|
917
|
-
- 实现使用宿主的投影感知观察面 `sessionQuery.observeSession(sessionId, { projectionMode: "all", signal })`;读到即释放 lease(不泄漏 prepared 会话 pin)。
|
|
918
|
-
|
|
919
|
-
**客户端消费约定(App 刻度轨)**:合并「已加载轮次」与 `turns`——按轮次号升序取并集,两边都有时保留已加载锚点、预览以已加载为准(仅本地为空时用大纲补齐,保证同一轮加载前后文字不跳变);未加载轮次以短淡刻度呈现,点击后按 **200 条/页**有界跨页加载直至覆盖该轮起始序号,再走既有的按序号跳转定位;`empty` / `capability-missing` 不提示用户,`read-failed` / `truncated` 在刻度轨可见时说明一次。
|
|
920
|
-
|
|
921
|
-
**能力位**:`GET /m/api/bootstrap` 与 SSE hello 的 `capabilities.turnOutline` 与本节同一判据(见 §3.1、§3.6):宿主真的注册了投影单元且观察面可用才 `supported: true`,否则 `supported: false`。客户端必须先读能力位再决定是否渲染未加载刻度。
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
### 6.18 GET /m/api/diagnostics
|
|
927
|
-
|
|
928
|
-
返回当前插件的运行诊断:`plugin` 标识插件名与版本;`runtime` 描述插件进程、WebServer 监听地址、鉴权、LAN 桥及运行指标;`services` 列出探测到的宿主服务;`checks` 提供功能检查结果;`notes` 提供可读提示。
|
|
929
|
-
|
|
930
|
-
`checks.approvalMode` 表示问询/审批策略,`checks.remoteEvents` 表示 `$events` 双端通道是否就绪。旧宿主的 `apiProxy` / `respondBridge` / `frameBridge` 项仅在相应服务被探测到时出现。当前响应不包含宿主版本、`host.capabilities` 或统一受支持范围;不能根据插件版本推断宿主能力。
|