dsh-agy-acp 0.1.2 → 0.1.3

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/client.js CHANGED
@@ -101,6 +101,22 @@
101
101
  return value !== null && typeof value === 'object' && !Array.isArray(value);
102
102
  }
103
103
 
104
+ /**
105
+ * 解包真实宿主 @deepseek-ai/dsh-api-gateway 的一元 Remote 结果信封。
106
+ *
107
+ * 网关客户端 invoke() 的成功返回是 { ok: true, value: <payload> }(失败是
108
+ * { ok: false, error }),并不是裸 payload;离线的远程替身与旧宿主则直接返回
109
+ * payload。这里只剥一层、且只剥「成功信封」:
110
+ * - ok:false 的失败信封原样返回,交给调用方既有的错误分支处理;
111
+ * - 裸 payload 原样返回,绝不误剥业务字段里自带的 ok/value 组合。
112
+ */
113
+ function unwrapRemoteResult(response) {
114
+ if (isPlainObject(response) && response.ok === true && 'value' in response && response.value !== undefined) {
115
+ return response.value;
116
+ }
117
+ return response;
118
+ }
119
+
104
120
  function resolveService(ctx, name) {
105
121
  if (!ctx || typeof ctx !== 'object') return null;
106
122
  try {
@@ -960,7 +976,7 @@
960
976
  if (!api || typeof api.getAcpSnapshot !== 'function') {
961
977
  throw new Error('Host 端 dsh-agy-acp.getAcpSnapshot 服务未就绪');
962
978
  }
963
- const response = await api.getAcpSnapshot({ sessionId: focusSessionId || GLOBAL });
979
+ const response = unwrapRemoteResult(await api.getAcpSnapshot({ sessionId: focusSessionId || GLOBAL }));
964
980
  if (isPlainObject(response) && response.ok === false) {
965
981
  throw new Error(formatErrorMessage(response.error || response));
966
982
  }
@@ -974,7 +990,7 @@
974
990
  if (!api || typeof api.stopAcpRun !== 'function') {
975
991
  return { ok: false, stopped: false, runId, phase: '', reason: 'host-unavailable' };
976
992
  }
977
- const response = await api.stopAcpRun({ runId });
993
+ const response = unwrapRemoteResult(await api.stopAcpRun({ runId }));
978
994
  if (isPlainObject(response) && response.ok === false && response.error) {
979
995
  throw new Error(formatErrorMessage(response.error));
980
996
  }
@@ -1008,7 +1024,9 @@
1008
1024
  if (!remoteApi || typeof remoteApi.getAcpQuota !== 'function') {
1009
1025
  throw new Error('Host 端 dsh-agy-acp.getAcpQuota 服务未就绪');
1010
1026
  }
1011
- const response = await remoteApi.getAcpQuota(isPlainObject(options) ? options : { force: true });
1027
+ const response = unwrapRemoteResult(
1028
+ await remoteApi.getAcpQuota(isPlainObject(options) ? options : { force: true })
1029
+ );
1012
1030
  if (isPlainObject(response) && response.ok === false && response.error) {
1013
1031
  throw new Error(formatErrorMessage(response.error));
1014
1032
  }
@@ -1187,9 +1205,10 @@
1187
1205
  order: PATCH_ORDER,
1188
1206
  label: () => (locale && typeof locale.bind === 'function' ? locale.bind(SETTINGS_NS)('title') : 'Antigravity ACP'),
1189
1207
  locale: SETTINGS_NS,
1190
- // api 允许设置页在连接就绪后补拉一次 snapshot.models;
1191
- // 拿不到时组件自动降级到内置静态目录,绝不阻塞渲染。
1192
- inject: () => ({ form, api: getAcpApi() }),
1208
+ // api 是上面构造好的客户端封装(fetchSnapshot 已解包宿主网关信封),
1209
+ // 传入后设置页能真正拉到宿主实测 snapshot.models;拿不到时组件自动降级到
1210
+ // 内置静态目录,绝不阻塞渲染、也绝不让离线单测崩掉。
1211
+ inject: () => ({ form, api }),
1193
1212
  }, AcpSettingsView))
1194
1213
  ));
1195
1214
  return () => {
@@ -1309,6 +1328,7 @@
1309
1328
  DEFAULT_SETTINGS,
1310
1329
  DEFAULT_MODEL_OPTIONS,
1311
1330
  MODEL_ACCESS_VALUES,
1331
+ unwrapRemoteResult,
1312
1332
  normalizeModelCatalog,
1313
1333
  normalizeStringList,
1314
1334
  mergeModelCatalog,
@@ -1406,14 +1426,20 @@
1406
1426
 
1407
1427
  // 连接就绪后再补一次真实模型目录;任何异常(远程未挂载 / 未注入 api)都静默
1408
1428
  // 降级到内置静态目录,绝不阻塞渲染、也绝不让离线单测崩掉。
1409
- const snapshotApi =
1410
- props && props.api && typeof props.api.getAcpSnapshot === 'function' ? props.api : null;
1429
+ // 两种注入形态都支持:本插件客户端封装 api.fetchSnapshot(已解包宿主网关
1430
+ // { ok: true, value } 信封),以及宿主远程命名空间 api.getAcpSnapshot(这里再解一次)。
1431
+ const snapshotApi = props && props.api ? props.api : null;
1432
+ const useApiFetch = Boolean(snapshotApi && typeof snapshotApi.fetchSnapshot === 'function');
1433
+ const canPullSnapshot =
1434
+ useApiFetch || Boolean(snapshotApi && typeof snapshotApi.getAcpSnapshot === 'function');
1411
1435
  React.useEffect(() => {
1412
- if (!snapshotApi) return undefined;
1436
+ if (!canPullSnapshot || !snapshotApi) return undefined;
1413
1437
  let cancelled = false;
1414
1438
  const pull = async () => {
1415
1439
  try {
1416
- const snap = await snapshotApi.getAcpSnapshot({ sessionId: GLOBAL });
1440
+ const snap = useApiFetch
1441
+ ? await snapshotApi.fetchSnapshot(GLOBAL)
1442
+ : unwrapRemoteResult(await snapshotApi.getAcpSnapshot({ sessionId: GLOBAL }));
1417
1443
  if (cancelled) return;
1418
1444
  const models = normalizeModelCatalog(snap && snap.models);
1419
1445
  if (models.length > 0) setCatalogModels(models);
@@ -1425,7 +1451,7 @@
1425
1451
  return () => {
1426
1452
  cancelled = true;
1427
1453
  };
1428
- }, [snapshotApi]);
1454
+ }, [canPullSnapshot, snapshotApi, useApiFetch]);
1429
1455
 
1430
1456
  const val = (state && state.value) || {};
1431
1457
  const isReady = state && state.status === 'ready';
package/docs/changelog.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  [返回主页](../README.md) · [配置参考](configuration.md) · [接口参考](reference.md) · [开发与发布](development.md)
4
4
 
5
+ ## [0.1.3] - 2026-11-15
6
+
7
+ ### 修复
8
+ - 修复真实宿主 `@deepseek-ai/dsh-api-gateway` 的一元 Remote 结果信封 `{ ok: true, value: <payload> }` 未解包的问题:`client.js` 新增 `unwrapRemoteResult()`(只剥成功信封;`ok: false` 失败信封与离线替身/旧宿主的裸 payload 一律原样返回),并接入 `fetchSnapshotOnce` / `stopRun` / `fetchQuotaOnce` 三处。
9
+ - 症状:面板快照恒为空、停止运行恒报 `stopped: false`、额度卡片读不到 `groups`,设置页也拿不到宿主实测模型列表。
10
+ - 设置页 `settings.section` 槽位的 `inject` 改为传入已构造好的客户端封装 `api`(原为远程命名空间),并把 `AcpSettingsView` 的快照拉取改走 `api.fetchSnapshot`(仍兼容 `api.getAcpSnapshot` 形态并同样解包信封),真实桌面打开设置页即可把宿主实测模型合并进权限矩阵;离线测试只传 `{ form }` 时仍安全降级、绝不报错。
11
+
12
+ ### 测试
13
+ - `test/acp-panel.test.mjs`:新增 `unwrapRemoteResult` 边界用例(成功信封 / 失败信封 / 裸 payload / `value: undefined`)、三处远程调用解包回归(`models`、`stopped: true`、`quota.groups`)、以及挂载后设置页注入 `api` 解包拉取 `models` 并合并进权限矩阵的回归。
14
+ - `test/acp-quota.test.mjs`:新增 `api.fetchQuota` 解包网关信封后额度卡片读到 `groups`(0 余额精确保留)与失败信封继续抛错的回归。
15
+
5
16
  ## [0.1.2] - 2026-11-15
6
17
 
7
18
  ### 新增
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-agy-acp",
3
3
  "displayName": "Antigravity ACP Worker",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "description": "Antigravity CLI (agy) ACP bridge for DeepSeek Harness: resumable worker turns, background job wakeup, semaphore queuing, four-tier permission gating, zero-sidecar SQLite token ledger, and on-demand quota inspection.",
6
6
  "license": "MIT",
7
7
  "author": "higekibaka",
package/src/acp-client.js CHANGED
@@ -22,7 +22,7 @@ const executableMod = require('./executable.js');
22
22
  const imagesMod = require('./images.js');
23
23
 
24
24
  const PLUGIN_NAME = 'dsh-agy-acp';
25
- const PLUGIN_VERSION = '0.1.2';
25
+ const PLUGIN_VERSION = '0.1.3';
26
26
  const PROTOCOL_VERSION = 1;
27
27
  const MAX_LINE_BYTES = 8 * 1024 * 1024;
28
28