@khorsheed/dsh-local-agent 0.1.0-rc.6

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.
Files changed (99) hide show
  1. package/README.en.md +181 -0
  2. package/README.i18n.yaml +2 -0
  3. package/README.md +181 -0
  4. package/cordis.patch.yml +21 -0
  5. package/lib/client.js +8832 -0
  6. package/lib/index.js +5281 -0
  7. package/lib/invariant.js +85 -0
  8. package/lib/member-bridge.js +298 -0
  9. package/lib/typert.host.d.ts +3 -0
  10. package/lib/typert.host.js +3137 -0
  11. package/lib/typert.remote-client.d.ts +67 -0
  12. package/lib/typert.remote-client.js +1971 -0
  13. package/lib/types/cli-version.d.ts +82 -0
  14. package/lib/types/cli-version.js +165 -0
  15. package/lib/types/client/AuthStatusDot.d.ts +17 -0
  16. package/lib/types/client/AuthStatusDot.js +9 -0
  17. package/lib/types/client/HarnessModelPicker.d.ts +17 -0
  18. package/lib/types/client/HarnessModelPicker.js +48 -0
  19. package/lib/types/client/LocalAgentRecordsAction.d.ts +41 -0
  20. package/lib/types/client/LocalAgentRecordsAction.js +74 -0
  21. package/lib/types/client/MemberComposer.d.ts +79 -0
  22. package/lib/types/client/MemberComposer.js +308 -0
  23. package/lib/types/client/MemberConfiguration.d.ts +9 -0
  24. package/lib/types/client/MemberConfiguration.js +46 -0
  25. package/lib/types/client/MemberInboxView.d.ts +12 -0
  26. package/lib/types/client/MemberInboxView.js +38 -0
  27. package/lib/types/client/MemberLiveNode.d.ts +14 -0
  28. package/lib/types/client/MemberLiveNode.js +74 -0
  29. package/lib/types/client/MemberPaintDiagnostics.d.ts +7 -0
  30. package/lib/types/client/MemberPaintDiagnostics.js +20 -0
  31. package/lib/types/client/ModelConfigurationFields.d.ts +15 -0
  32. package/lib/types/client/ModelConfigurationFields.js +23 -0
  33. package/lib/types/client/ProviderAuthBlock.d.ts +59 -0
  34. package/lib/types/client/ProviderAuthBlock.js +164 -0
  35. package/lib/types/client/auth-status.d.ts +28 -0
  36. package/lib/types/client/auth-status.js +56 -0
  37. package/lib/types/client/icons.d.ts +22 -0
  38. package/lib/types/client/icons.js +6 -0
  39. package/lib/types/client/index.d.ts +62 -0
  40. package/lib/types/client/index.js +135 -0
  41. package/lib/types/client/live-node.d.ts +14 -0
  42. package/lib/types/client/live-node.js +34 -0
  43. package/lib/types/client/live-output.d.ts +34 -0
  44. package/lib/types/client/live-output.js +94 -0
  45. package/lib/types/client/live-paint.d.ts +40 -0
  46. package/lib/types/client/live-paint.js +74 -0
  47. package/lib/types/client/locales.d.ts +120 -0
  48. package/lib/types/client/locales.js +227 -0
  49. package/lib/types/client/member-configuration.d.ts +41 -0
  50. package/lib/types/client/member-configuration.js +114 -0
  51. package/lib/types/client/member-dock.d.ts +94 -0
  52. package/lib/types/client/member-dock.js +102 -0
  53. package/lib/types/client/member-feed.d.ts +24 -0
  54. package/lib/types/client/member-feed.js +134 -0
  55. package/lib/types/client/request-id.d.ts +3 -0
  56. package/lib/types/client/request-id.js +6 -0
  57. package/lib/types/client/settings-scope.d.ts +74 -0
  58. package/lib/types/client/settings-scope.js +98 -0
  59. package/lib/types/client/use-configuration-menu.d.ts +10 -0
  60. package/lib/types/client/use-configuration-menu.js +61 -0
  61. package/lib/types/container.d.ts +69 -0
  62. package/lib/types/container.js +129 -0
  63. package/lib/types/env.d.ts +17 -0
  64. package/lib/types/env.js +89 -0
  65. package/lib/types/gateway.d.ts +162 -0
  66. package/lib/types/gateway.js +470 -0
  67. package/lib/types/index.d.ts +1463 -0
  68. package/lib/types/index.js +2704 -0
  69. package/lib/types/invariant.d.ts +16 -0
  70. package/lib/types/invariant.js +105 -0
  71. package/lib/types/live-flush.d.ts +21 -0
  72. package/lib/types/live-flush.js +59 -0
  73. package/lib/types/live-stream.d.ts +41 -0
  74. package/lib/types/live-stream.js +178 -0
  75. package/lib/types/member-bridge.d.ts +50 -0
  76. package/lib/types/member-bridge.js +216 -0
  77. package/lib/types/member-channel.d.ts +86 -0
  78. package/lib/types/member-channel.js +232 -0
  79. package/lib/types/member-control-storage.d.ts +10 -0
  80. package/lib/types/member-control-storage.js +100 -0
  81. package/lib/types/member-control.d.ts +62 -0
  82. package/lib/types/member-control.js +359 -0
  83. package/lib/types/member-controls.d.ts +23 -0
  84. package/lib/types/member-controls.js +143 -0
  85. package/lib/types/member-feed.d.ts +4 -0
  86. package/lib/types/member-feed.js +45 -0
  87. package/lib/types/member-inbox.d.ts +30 -0
  88. package/lib/types/member-inbox.js +225 -0
  89. package/lib/types/model-directory.d.ts +43 -0
  90. package/lib/types/model-directory.js +192 -0
  91. package/lib/types/prepared-members.d.ts +15 -0
  92. package/lib/types/prepared-members.js +61 -0
  93. package/lib/types/settings-face.d.ts +61 -0
  94. package/lib/types/settings-face.js +61 -0
  95. package/lib/types/types.d.ts +959 -0
  96. package/lib/types/types.js +24 -0
  97. package/locale/en.json +6 -0
  98. package/locale/zh.json +6 -0
  99. package/package.json +112 -0
@@ -0,0 +1,94 @@
1
+ import { LivePaintDiagnostics } from './live-paint.js';
2
+ export class MemberLiveOutput {
3
+ id;
4
+ follow;
5
+ onIdle;
6
+ diagnostics;
7
+ listeners = new Set();
8
+ snapshot = { items: new Map(), connected: false };
9
+ controller;
10
+ constructor(id, follow, onIdle, diagnostics) {
11
+ this.id = id;
12
+ this.follow = follow;
13
+ this.onIdle = onIdle;
14
+ this.diagnostics = diagnostics;
15
+ }
16
+ getSnapshot = () => this.snapshot;
17
+ subscribe = (listener) => {
18
+ this.listeners.add(listener);
19
+ if (this.controller === undefined) {
20
+ const controller = new AbortController();
21
+ this.controller = controller;
22
+ void this.run(controller.signal);
23
+ }
24
+ return () => {
25
+ this.listeners.delete(listener);
26
+ if (this.listeners.size === 0) {
27
+ this.controller?.abort();
28
+ this.controller = undefined;
29
+ this.snapshot = { items: new Map(), connected: false };
30
+ this.onIdle();
31
+ }
32
+ };
33
+ };
34
+ publish(snapshot) {
35
+ this.snapshot = snapshot;
36
+ for (const listener of this.listeners)
37
+ listener();
38
+ }
39
+ async run(signal) {
40
+ let delay = 250;
41
+ while (!signal.aborted) {
42
+ try {
43
+ for await (const frame of this.follow(this.id, signal)) {
44
+ if (signal.aborted)
45
+ return;
46
+ const items = frame.baseline ? new Map() : new Map(this.snapshot.items);
47
+ for (const update of frame.updates) {
48
+ const old = items.get(update.id);
49
+ if (update.append && old === undefined)
50
+ throw new Error('live output suffix without baseline');
51
+ if (old !== undefined && update.revision <= old.revision)
52
+ continue;
53
+ this.diagnostics.receive(this.id, update, frame.baseline);
54
+ items.set(update.id, { ...update, text: update.append ? old.text + update.text : update.text, baseline: frame.baseline });
55
+ }
56
+ // Retain the final live text until the durable native message removes
57
+ // its node; the two transports may arrive in either order.
58
+ this.publish({ items, connected: true });
59
+ delay = 250;
60
+ }
61
+ }
62
+ catch {
63
+ // A reconnect obtains a fresh baseline, never replays stale suffixes.
64
+ }
65
+ if (signal.aborted)
66
+ return;
67
+ this.publish({ ...this.snapshot, connected: false });
68
+ await new Promise(resolve => {
69
+ const done = () => { clearTimeout(timer); signal.removeEventListener('abort', done); resolve(); };
70
+ const timer = setTimeout(done, delay);
71
+ signal.addEventListener('abort', done, { once: true });
72
+ });
73
+ delay = Math.min(delay * 2, 5_000);
74
+ }
75
+ }
76
+ }
77
+ /** Cached only while rendered: historical sessions do not retain text or connections. */
78
+ export class MemberLiveOutputs {
79
+ follow;
80
+ diagnostics = new LivePaintDiagnostics();
81
+ stores = new Map();
82
+ constructor(follow) {
83
+ this.follow = follow;
84
+ }
85
+ get(id) {
86
+ let store = this.stores.get(id);
87
+ if (store === undefined)
88
+ this.stores.set(id, store = new MemberLiveOutput(id, this.follow, () => {
89
+ if (this.stores.get(id) === store)
90
+ this.stores.delete(id);
91
+ }, this.diagnostics));
92
+ return store;
93
+ }
94
+ }
@@ -0,0 +1,40 @@
1
+ /** Bounded, text-free diagnostics. Receipt times require a shared host/browser clock. */
2
+ import type { LocalAgentStreamItem } from '../types.ts';
3
+ export type PaintSurface = 'room' | 'member';
4
+ export type PaintOutcome = 'pending' | 'painted' | 'hidden' | 'unmounted' | 'clock-mismatch';
5
+ export declare class LivePaintDiagnostics {
6
+ private readonly maxRounds;
7
+ private readonly maxReceipts;
8
+ private readonly rounds;
9
+ private readonly listeners;
10
+ private evictedRounds;
11
+ constructor(maxRounds?: number, maxReceipts?: number);
12
+ readonly subscribe: (listener: () => void) => (() => void);
13
+ private changed;
14
+ receive(sessionId: string, item: LocalAgentStreamItem, baseline: boolean): void;
15
+ begin(sessionId: string, turn: number, revision: number, surface: PaintSurface): ((outcome: Exclude<PaintOutcome, 'pending'>, now: number) => void) | undefined;
16
+ /** Survives stream-node unmount; never includes prompts, answers or credentials. */
17
+ report(sessionId: string): {
18
+ clock: string;
19
+ evictedRounds: number;
20
+ rounds: {
21
+ turn: number;
22
+ dropped: number;
23
+ baselineUpdates: number;
24
+ liveUpdates: number;
25
+ surfaces: {
26
+ [k: string]: {
27
+ samples: number[];
28
+ p95: number | null | undefined;
29
+ painted: number;
30
+ pending: number;
31
+ hidden: number;
32
+ unmounted: number;
33
+ clockMismatch: number;
34
+ unrendered: number;
35
+ };
36
+ };
37
+ }[];
38
+ };
39
+ }
40
+ //# sourceMappingURL=live-paint.d.ts.map
@@ -0,0 +1,74 @@
1
+ export class LivePaintDiagnostics {
2
+ maxRounds;
3
+ maxReceipts;
4
+ rounds = new Map();
5
+ listeners = new Set();
6
+ evictedRounds = 0;
7
+ constructor(maxRounds = 32, maxReceipts = 4_096) {
8
+ this.maxRounds = maxRounds;
9
+ this.maxReceipts = maxReceipts;
10
+ }
11
+ subscribe = (listener) => {
12
+ this.listeners.add(listener);
13
+ return () => { this.listeners.delete(listener); };
14
+ };
15
+ changed() { for (const listener of this.listeners)
16
+ listener(); }
17
+ receive(sessionId, item, baseline) {
18
+ const key = JSON.stringify([sessionId, item.turn]);
19
+ let round = this.rounds.get(key);
20
+ if (!round) {
21
+ round = { sessionId, turn: item.turn, receipts: new Map(), dropped: 0 };
22
+ this.rounds.set(key, round);
23
+ if (this.rounds.size > this.maxRounds) {
24
+ this.rounds.delete(this.rounds.keys().next().value);
25
+ this.evictedRounds++;
26
+ }
27
+ }
28
+ // Reconnect baselines must not reclassify an already observed live update.
29
+ if (round.receipts.has(item.revision))
30
+ return;
31
+ round.receipts.set(item.revision, { id: item.id, revision: item.revision, receivedAt: item.receivedAt, baseline, paints: {} });
32
+ if (round.receipts.size > this.maxReceipts) {
33
+ round.receipts.delete(round.receipts.keys().next().value);
34
+ round.dropped++;
35
+ }
36
+ this.changed();
37
+ }
38
+ begin(sessionId, turn, revision, surface) {
39
+ const receipt = this.rounds.get(JSON.stringify([sessionId, turn]))?.receipts.get(revision);
40
+ if (!receipt || receipt.baseline || receipt.paints[surface])
41
+ return undefined;
42
+ const paint = { outcome: 'pending' };
43
+ receipt.paints[surface] = paint;
44
+ this.changed();
45
+ return (outcome, now) => {
46
+ if (paint.outcome !== 'pending')
47
+ return;
48
+ const elapsed = now - receipt.receivedAt;
49
+ paint.outcome = outcome === 'painted' && elapsed < 0 ? 'clock-mismatch' : outcome;
50
+ if (paint.outcome === 'painted')
51
+ paint.elapsed = elapsed;
52
+ this.changed();
53
+ };
54
+ }
55
+ /** Survives stream-node unmount; never includes prompts, answers or credentials. */
56
+ report(sessionId) {
57
+ return { clock: 'shared-wall-clock-required', evictedRounds: this.evictedRounds, rounds: [...this.rounds.values()]
58
+ .filter(round => round.sessionId === sessionId).map(round => {
59
+ const receipts = [...round.receipts.values()];
60
+ const live = receipts.filter(receipt => !receipt.baseline);
61
+ return { turn: round.turn, dropped: round.dropped, baselineUpdates: receipts.length - live.length, liveUpdates: live.length,
62
+ surfaces: Object.fromEntries(['room', 'member'].map(surface => {
63
+ const paints = live.map(receipt => receipt.paints[surface]);
64
+ const samples = paints.flatMap(paint => paint?.elapsed === undefined ? [] : [paint.elapsed]);
65
+ const sorted = [...samples].sort((a, b) => a - b);
66
+ const count = (outcome) => paints.filter(paint => paint?.outcome === outcome).length;
67
+ return [surface, { samples, p95: sorted.length ? sorted[Math.ceil(sorted.length * 0.95) - 1] : null,
68
+ painted: count('painted'), pending: count('pending'), hidden: count('hidden'), unmounted: count('unmounted'),
69
+ clockMismatch: count('clock-mismatch'), unrendered: paints.filter(paint => paint === undefined).length }];
70
+ })),
71
+ };
72
+ }) };
73
+ }
74
+ }
@@ -0,0 +1,120 @@
1
+ /** `local-agent` namespace dictionaries. */
2
+ /** Dictionary namespace owned by this plugin. */
3
+ export declare const NS = "local-agent";
4
+ /** Simplified Chinese dictionary (the key-set source of truth). */
5
+ export declare const zh: {
6
+ readonly 'inbox.title': '待处理消息';
7
+ readonly 'inbox.pause': '暂停队列';
8
+ readonly 'inbox.resume': '继续队列';
9
+ readonly 'inbox.paused': '队列已暂停;重启后请先核对未完成消息。';
10
+ readonly 'inbox.cancel': '取消这条';
11
+ readonly 'inbox.evidence': '填写核对结果或证据';
12
+ readonly 'inbox.confirmDone': '确认已完成';
13
+ readonly 'inbox.confirmCancelled': '确认已取消';
14
+ readonly 'inbox.status.queued': '已排队';
15
+ readonly 'inbox.status.running': '执行中';
16
+ readonly 'inbox.status.uncertain': '结果待核对';
17
+ readonly 'inbox.status.failed': '失败';
18
+ readonly 'inbox.status.done': '已完成';
19
+ readonly 'inbox.status.cancelled': '已取消';
20
+ readonly "configuration.title": "模型与推理配置";
21
+ readonly "configuration.choose": "选择模型";
22
+ readonly "configuration.unavailable": "暂不可用";
23
+ readonly "configuration.back": "返回";
24
+ readonly "configuration.details": "模型目录详情";
25
+ readonly "configuration.model": "模型";
26
+ readonly "configuration.effort": "推理强度";
27
+ readonly "configuration.inherit": "继承成员创建配置";
28
+ readonly "configuration.default": "跟随 harness 默认值";
29
+ readonly "configuration.search": "搜索模型名称或 ID";
30
+ readonly "configuration.custom": "自定义模型 ID";
31
+ readonly "configuration.source.native": "原生目录";
32
+ readonly "configuration.source.configuration": "配置项";
33
+ readonly "configuration.source.history": "历史观测";
34
+ readonly "configuration.hidden": "扩展候选";
35
+ readonly "configuration.empty": "暂无匹配的候选模型";
36
+ readonly "configuration.unverified": "尚未验证此模型的支持情况";
37
+ readonly "configuration.effortUnknown": "暂未取得此模型的强度选项,当前强度保持不变。";
38
+ readonly "configuration.directory.loading": "正在读取目录";
39
+ readonly "configuration.directory.ready": "目录已更新";
40
+ readonly "configuration.directory.stale": "目录更新失败,展示上次结果";
41
+ readonly "configuration.directory.error": "目录读取失败";
42
+ readonly "configuration.directory.unsupported": "此来源未提供完整目录";
43
+ readonly "configuration.incomplete": "候选列表可能不完整";
44
+ readonly "configuration.round": "本轮配置";
45
+ readonly "configuration.ready": "下轮已准备的配置";
46
+ readonly "configuration.pending": "下轮待生效";
47
+ readonly "configuration.applying": "正在准备配置";
48
+ readonly "configuration.boundary": "现在可以选择;当前轮次及工具续跑保持原配置,新选择从下一轮生效。";
49
+ readonly "configuration.reconnecting": "正在重新连接配置状态…";
50
+ readonly "configuration.apply": "应用选择";
51
+ readonly "configuration.cancel": "撤销待生效配置";
52
+ readonly "configuration.retry": "对账并重试";
53
+ readonly "configuration.refresh": "刷新模型目录";
54
+ readonly "configuration.accepted": "选择已接收,请以下方实时状态为准。";
55
+ readonly "configuration.cancelled": "已接收撤销请求,正在恢复配置。";
56
+ readonly "configuration.failed": "配置操作失败,请检查原因后重试。";
57
+ readonly 'stream.thinking': '思考中';
58
+ readonly 'stream.writing': '正在生成';
59
+ readonly 'stream.recovering': '部分记录,等待实时连接';
60
+ readonly 'stream.copy': '复制';
61
+ readonly 'stream.copied': '已复制';
62
+ readonly 'stream.footnotes': '脚注';
63
+ readonly 'list.aria': '{harness} 会话记录';
64
+ readonly 'list.title': '{harness} 会话记录';
65
+ readonly empty: '作用域内还没有 {harness} 会话';
66
+ readonly 'login.hint': '运行 /{command} login 授权后开始委派';
67
+ readonly loading: '加载中…';
68
+ readonly error: '无法读取 {harness} 会话记录';
69
+ readonly 'unknown.command': '/{command} sessions 不可用({harness} 插件未安装?)';
70
+ readonly 'row.aria': '{harness} 会话 {sessionId}';
71
+ readonly workdir: '工作目录';
72
+ readonly 'settings.nav': '本地 Agent';
73
+ readonly 'settings.intro': '管理本机安装的编码 agent CLI:查看授权状态,通过网页登录授权。';
74
+ readonly 'settings.noSession': '先打开一个会话,再管理本地 agent';
75
+ readonly 'settings.authenticated': '已登录';
76
+ readonly 'settings.notAuthenticated': '未登录';
77
+ readonly 'settings.login': '网页登录';
78
+ readonly 'settings.reauthorize': '重新授权';
79
+ readonly 'settings.logout': '退出登录';
80
+ readonly 'settings.loggedOut': '已退出登录';
81
+ readonly 'settings.openPage': '打开授权页面';
82
+ readonly 'settings.homeDir': '作用域目录';
83
+ readonly 'settings.pending': '等待授权…';
84
+ readonly 'settings.loginSuccess': '{harness} 登录成功,快去试试吧!';
85
+ readonly 'settings.pasteCode': '粘贴授权页面给出的 code';
86
+ readonly 'settings.submitCode': '提交 code';
87
+ readonly 'settings.unsupported': '待支持';
88
+ readonly 'settings.rosterFailed': '无法读取本地 Agent 列表,请重试';
89
+ readonly 'settings.retry': '重试';
90
+ readonly 'member.checking': '正在确认成员身份…';
91
+ readonly 'member.readonly.title': '一次性子代理记录';
92
+ readonly 'member.readonly.body': '一次性任务不支持后续消息,可在这里查看完整执行记录。';
93
+ readonly 'member.title': '{harness} 成员';
94
+ readonly 'member.placeholder': '给成员发消息,继续同一会话…';
95
+ readonly 'member.send': '发送';
96
+ readonly 'member.stop': '停止';
97
+ readonly 'member.running': '成员运行中…';
98
+ readonly 'member.sendFailed': '发送失败,请重试';
99
+ readonly 'member.stats.cacheHit': '缓存命中 {percent}%';
100
+ readonly 'member.stats.tokens': '输入 {input} tok · 输出 {output} tok';
101
+ readonly 'member.tasks.summary': '任务 {done}/{total}';
102
+ readonly 'member.tasks.active': ' · 进行中:{title}';
103
+ readonly 'member.model.picker': '成员模型';
104
+ readonly 'member.model.default': '默认';
105
+ readonly 'member.model.defaultLastObserved': '默认(最近 {model})';
106
+ readonly 'member.model.title': '模型:{model}({source})';
107
+ readonly 'member.model.source.override': '会话级覆盖';
108
+ readonly 'member.model.source.delegation': '委派时指定';
109
+ readonly 'member.model.source.settings': '插件设置';
110
+ readonly 'member.model.source.cli-config': 'CLI 配置文件';
111
+ readonly 'member.model.source.cli-builtin': 'CLI 内置默认:没有任何层级指定模型,运行 CLI 自己的默认;已知时显示最近实际运行的模型';
112
+ readonly 'member.model.followSettings': '跟随设置';
113
+ readonly 'member.model.empty': '暂无候选模型';
114
+ readonly 'member.model.failed': '切换模型失败,请重试';
115
+ };
116
+ /** English dictionary, key-identical to the Chinese source of truth. */
117
+ export declare const en: Record<LocalAgentKey, string>;
118
+ /** Key domain of the `local-agent` namespace (zh is the source of truth). */
119
+ export type LocalAgentKey = keyof typeof zh;
120
+ //# sourceMappingURL=locales.d.ts.map
@@ -0,0 +1,227 @@
1
+ /** `local-agent` namespace dictionaries. */
2
+ /** Dictionary namespace owned by this plugin. */
3
+ export const NS = 'local-agent';
4
+ /** Simplified Chinese dictionary (the key-set source of truth). */
5
+ export const zh = {
6
+ 'inbox.title': '待处理消息',
7
+ 'inbox.pause': '暂停队列',
8
+ 'inbox.resume': '继续队列',
9
+ 'inbox.paused': '队列已暂停;重启后请先核对未完成消息。',
10
+ 'inbox.cancel': '取消这条',
11
+ 'inbox.evidence': '填写核对结果或证据',
12
+ 'inbox.confirmDone': '确认已完成',
13
+ 'inbox.confirmCancelled': '确认已取消',
14
+ 'inbox.status.queued': '已排队',
15
+ 'inbox.status.running': '执行中',
16
+ 'inbox.status.uncertain': '结果待核对',
17
+ 'inbox.status.failed': '失败',
18
+ 'inbox.status.done': '已完成',
19
+ 'inbox.status.cancelled': '已取消',
20
+ "configuration.title": "模型与推理配置",
21
+ "configuration.choose": "选择模型",
22
+ "configuration.unavailable": "暂不可用",
23
+ "configuration.back": "返回",
24
+ "configuration.details": "模型目录详情",
25
+ "configuration.model": "模型",
26
+ "configuration.effort": "推理强度",
27
+ "configuration.inherit": "继承成员创建配置",
28
+ "configuration.default": "跟随 harness 默认值",
29
+ "configuration.search": "搜索模型名称或 ID",
30
+ "configuration.custom": "自定义模型 ID",
31
+ "configuration.source.native": "原生目录",
32
+ "configuration.source.configuration": "配置项",
33
+ "configuration.source.history": "历史观测",
34
+ "configuration.hidden": "扩展候选",
35
+ "configuration.empty": "暂无匹配的候选模型",
36
+ "configuration.unverified": "尚未验证此模型的支持情况",
37
+ "configuration.effortUnknown": "暂未取得此模型的强度选项,当前强度保持不变。",
38
+ "configuration.directory.loading": "正在读取目录",
39
+ "configuration.directory.ready": "目录已更新",
40
+ "configuration.directory.stale": "目录更新失败,展示上次结果",
41
+ "configuration.directory.error": "目录读取失败",
42
+ "configuration.directory.unsupported": "此来源未提供完整目录",
43
+ "configuration.incomplete": "候选列表可能不完整",
44
+ "configuration.round": "本轮配置",
45
+ "configuration.ready": "下轮已准备的配置",
46
+ "configuration.pending": "下轮待生效",
47
+ "configuration.applying": "正在准备配置",
48
+ "configuration.boundary": "现在可以选择;当前轮次及工具续跑保持原配置,新选择从下一轮生效。",
49
+ "configuration.reconnecting": "正在重新连接配置状态…",
50
+ "configuration.apply": "应用选择",
51
+ "configuration.cancel": "撤销待生效配置",
52
+ "configuration.retry": "对账并重试",
53
+ "configuration.refresh": "刷新模型目录",
54
+ "configuration.accepted": "选择已接收,请以下方实时状态为准。",
55
+ "configuration.cancelled": "已接收撤销请求,正在恢复配置。",
56
+ "configuration.failed": "配置操作失败,请检查原因后重试。",
57
+ 'stream.thinking': '思考中',
58
+ 'stream.writing': '正在生成',
59
+ 'stream.recovering': '部分记录,等待实时连接',
60
+ 'stream.copy': '复制',
61
+ 'stream.copied': '已复制',
62
+ 'stream.footnotes': '脚注',
63
+ 'list.aria': '{harness} 会话记录',
64
+ 'list.title': '{harness} 会话记录',
65
+ 'empty': '作用域内还没有 {harness} 会话',
66
+ 'login.hint': '运行 /{command} login 授权后开始委派',
67
+ 'loading': '加载中…',
68
+ 'error': '无法读取 {harness} 会话记录',
69
+ 'unknown.command': '/{command} sessions 不可用({harness} 插件未安装?)',
70
+ 'row.aria': '{harness} 会话 {sessionId}',
71
+ 'workdir': '工作目录',
72
+ 'settings.nav': '本地 Agent',
73
+ 'settings.intro': '管理本机安装的编码 agent CLI:查看授权状态,通过网页登录授权。',
74
+ 'settings.noSession': '先打开一个会话,再管理本地 agent',
75
+ 'settings.authenticated': '已登录',
76
+ 'settings.notAuthenticated': '未登录',
77
+ 'settings.login': '网页登录',
78
+ 'settings.reauthorize': '重新授权',
79
+ 'settings.logout': '退出登录',
80
+ 'settings.loggedOut': '已退出登录',
81
+ 'settings.openPage': '打开授权页面',
82
+ 'settings.homeDir': '作用域目录',
83
+ 'settings.pending': '等待授权…',
84
+ 'settings.loginSuccess': '{harness} 登录成功,快去试试吧!',
85
+ 'settings.pasteCode': '粘贴授权页面给出的 code',
86
+ 'settings.submitCode': '提交 code',
87
+ 'settings.unsupported': '待支持',
88
+ 'settings.rosterFailed': '无法读取本地 Agent 列表,请重试',
89
+ 'settings.retry': '重试',
90
+ 'member.checking': '正在确认成员身份…',
91
+ 'member.readonly.title': '一次性子代理记录',
92
+ 'member.readonly.body': '一次性任务不支持后续消息,可在这里查看完整执行记录。',
93
+ 'member.title': '{harness} 成员',
94
+ 'member.placeholder': '给成员发消息,继续同一会话…',
95
+ 'member.send': '发送',
96
+ 'member.stop': '停止',
97
+ 'member.running': '成员运行中…',
98
+ 'member.sendFailed': '发送失败,请重试',
99
+ 'member.stats.cacheHit': '缓存命中 {percent}%',
100
+ 'member.stats.tokens': '输入 {input} tok · 输出 {output} tok',
101
+ 'member.tasks.summary': '任务 {done}/{total}',
102
+ 'member.tasks.active': ' · 进行中:{title}',
103
+ 'member.model.picker': '成员模型',
104
+ 'member.model.default': '默认',
105
+ 'member.model.defaultLastObserved': '默认(最近 {model})',
106
+ 'member.model.title': '模型:{model}({source})',
107
+ 'member.model.source.override': '会话级覆盖',
108
+ 'member.model.source.delegation': '委派时指定',
109
+ 'member.model.source.settings': '插件设置',
110
+ 'member.model.source.cli-config': 'CLI 配置文件',
111
+ 'member.model.source.cli-builtin': 'CLI 内置默认:没有任何层级指定模型,运行 CLI 自己的默认;已知时显示最近实际运行的模型',
112
+ 'member.model.followSettings': '跟随设置',
113
+ 'member.model.empty': '暂无候选模型',
114
+ 'member.model.failed': '切换模型失败,请重试',
115
+ };
116
+ /** English dictionary, key-identical to the Chinese source of truth. */
117
+ export const en = {
118
+ 'inbox.title': 'Pending messages',
119
+ 'inbox.pause': 'Pause queue',
120
+ 'inbox.resume': 'Resume queue',
121
+ 'inbox.paused': 'Queue paused; check unfinished inputs after a restart.',
122
+ 'inbox.cancel': 'Cancel input',
123
+ 'inbox.evidence': 'Reconciliation evidence',
124
+ 'inbox.confirmDone': 'Confirm completed',
125
+ 'inbox.confirmCancelled': 'Confirm cancelled',
126
+ 'inbox.status.queued': 'Queued',
127
+ 'inbox.status.running': 'Running',
128
+ 'inbox.status.uncertain': 'Outcome uncertain',
129
+ 'inbox.status.failed': 'Failed',
130
+ 'inbox.status.done': 'Done',
131
+ 'inbox.status.cancelled': 'Cancelled',
132
+ "configuration.title": "Model and reasoning configuration",
133
+ "configuration.choose": "Choose model",
134
+ "configuration.unavailable": "Unavailable",
135
+ "configuration.back": "Back",
136
+ "configuration.details": "Model directory details",
137
+ "configuration.model": "Model",
138
+ "configuration.effort": "Reasoning effort",
139
+ "configuration.inherit": "Inherit member configuration",
140
+ "configuration.default": "Follow harness defaults",
141
+ "configuration.search": "Search model names or IDs",
142
+ "configuration.custom": "Custom model ID",
143
+ "configuration.source.native": "Native directory",
144
+ "configuration.source.configuration": "Configuration",
145
+ "configuration.source.history": "Previously observed",
146
+ "configuration.hidden": "Additional candidate",
147
+ "configuration.empty": "No matching model candidates",
148
+ "configuration.unverified": "Not verified for this model",
149
+ "configuration.effortUnknown": "Reasoning choices are not available yet. The current effort is unchanged.",
150
+ "configuration.directory.loading": "Loading directory",
151
+ "configuration.directory.ready": "Directory updated",
152
+ "configuration.directory.stale": "Refresh failed; showing previous directory",
153
+ "configuration.directory.error": "Directory unavailable",
154
+ "configuration.directory.unsupported": "This source does not expose a full directory",
155
+ "configuration.incomplete": "Candidate list may be incomplete",
156
+ "configuration.round": "This round",
157
+ "configuration.ready": "Prepared for the next round",
158
+ "configuration.pending": "Pending for the next round",
159
+ "configuration.applying": "Preparing configuration",
160
+ "configuration.boundary": "You can choose now. The current round, including tool continuations, keeps its configuration; changes apply next round.",
161
+ "configuration.reconnecting": "Reconnecting configuration state…",
162
+ "configuration.apply": "Apply selection",
163
+ "configuration.cancel": "Cancel pending change",
164
+ "configuration.retry": "Reconcile and retry",
165
+ "configuration.refresh": "Refresh model directory",
166
+ "configuration.accepted": "Selection accepted. The live state shows when it is ready.",
167
+ "configuration.cancelled": "Cancellation accepted; restoring configuration.",
168
+ "configuration.failed": "Configuration failed; check the reason before retrying.",
169
+ 'stream.thinking': 'Thinking',
170
+ 'stream.writing': 'Writing',
171
+ 'stream.recovering': 'Partial record, awaiting live connection',
172
+ 'stream.copy': 'Copy',
173
+ 'stream.copied': 'Copied',
174
+ 'stream.footnotes': 'Footnotes',
175
+ 'list.aria': '{harness} sessions',
176
+ 'list.title': '{harness} sessions',
177
+ 'empty': 'No {harness} sessions in the scoped home yet',
178
+ 'login.hint': 'Run /{command} login to authorize, then delegate',
179
+ 'loading': 'Loading…',
180
+ 'error': 'Could not read {harness} sessions',
181
+ 'unknown.command': '/{command} sessions unavailable (is the {harness} bundle installed?)',
182
+ 'row.aria': '{harness} session {sessionId}',
183
+ 'workdir': 'workDir',
184
+ 'settings.nav': 'Local Agents',
185
+ 'settings.intro': 'Manage locally-installed coding-agent CLIs: check auth status and authorize through the web login.',
186
+ 'settings.noSession': 'Open a session first, then manage local agents',
187
+ 'settings.authenticated': 'Authenticated',
188
+ 'settings.notAuthenticated': 'Not authenticated',
189
+ 'settings.login': 'Web login',
190
+ 'settings.reauthorize': 'Re-authorize',
191
+ 'settings.logout': 'Sign out',
192
+ 'settings.loggedOut': 'Signed out',
193
+ 'settings.openPage': 'Open authorization page',
194
+ 'settings.homeDir': 'Home',
195
+ 'settings.pending': 'Waiting for authorization…',
196
+ 'settings.loginSuccess': '{harness} login succeeded — go try it out!',
197
+ 'settings.pasteCode': 'Paste the code from the authorization page',
198
+ 'settings.submitCode': 'Submit code',
199
+ 'settings.unsupported': 'Coming soon',
200
+ 'settings.rosterFailed': 'Could not read the local-agent roster; retry',
201
+ 'settings.retry': 'Retry',
202
+ 'member.checking': 'Checking membership…',
203
+ 'member.readonly.title': 'One-shot subagent record',
204
+ 'member.readonly.body': 'One-shot tasks do not accept follow-up messages; the full run record is available here.',
205
+ 'member.title': '{harness} member',
206
+ 'member.placeholder': 'Message the member to continue the same session…',
207
+ 'member.send': 'Send',
208
+ 'member.stop': 'Stop',
209
+ 'member.running': 'Member running…',
210
+ 'member.sendFailed': 'Send failed; try again',
211
+ 'member.stats.cacheHit': 'Cache hit {percent}%',
212
+ 'member.stats.tokens': 'Input {input} tok · Output {output} tok',
213
+ 'member.tasks.summary': 'Tasks {done}/{total}',
214
+ 'member.tasks.active': ' · Active: {title}',
215
+ 'member.model.picker': 'Member model',
216
+ 'member.model.default': 'Default',
217
+ 'member.model.defaultLastObserved': 'Default (last: {model})',
218
+ 'member.model.title': 'Model: {model} ({source})',
219
+ 'member.model.source.override': 'session override',
220
+ 'member.model.source.delegation': 'set at delegation',
221
+ 'member.model.source.settings': 'plugin settings',
222
+ 'member.model.source.cli-config': 'CLI config file',
223
+ 'member.model.source.cli-builtin': "CLI built-in default: no layer names a model, so the CLI's own default runs; the last observed model is shown when known",
224
+ 'member.model.followSettings': 'Follow settings',
225
+ 'member.model.empty': 'No models to pick',
226
+ 'member.model.failed': 'Could not switch the model; try again',
227
+ };
@@ -0,0 +1,41 @@
1
+ import type { LocalAgentControlReceipt, LocalAgentMemberConfiguration, LocalAgentMemberControlState, LocalAgentModelDirectory } from '../types.ts';
2
+ export interface MemberConfigurationFace {
3
+ read(id: string): Promise<LocalAgentMemberControlState>;
4
+ follow(id: string, signal: AbortSignal): AsyncIterable<LocalAgentMemberControlState>;
5
+ directory(id: string, refresh: boolean): Promise<LocalAgentModelDirectory | null>;
6
+ followDirectory(id: string, signal: AbortSignal): AsyncIterable<LocalAgentModelDirectory>;
7
+ select(id: string, request: string, revision: number, selection: LocalAgentMemberConfiguration): Promise<LocalAgentControlReceipt>;
8
+ cancel(id: string, request: string, revision: number): Promise<LocalAgentControlReceipt>;
9
+ retry(id: string, revision: number): Promise<void>;
10
+ }
11
+ export interface MemberConfigurationSnapshot {
12
+ state?: LocalAgentMemberControlState;
13
+ directory?: LocalAgentModelDirectory;
14
+ connected: boolean;
15
+ error?: string | undefined;
16
+ }
17
+ /** One shared source for every visible entry to the same member. */
18
+ export declare class MemberConfigurationStore {
19
+ readonly id: string;
20
+ readonly face: MemberConfigurationFace;
21
+ private readonly onIdle;
22
+ private snapshot;
23
+ private readonly listeners;
24
+ private controller;
25
+ constructor(id: string, face: MemberConfigurationFace, onIdle?: () => void);
26
+ readonly getSnapshot: () => MemberConfigurationSnapshot;
27
+ readonly subscribe: (listener: () => void) => (() => void);
28
+ private publish;
29
+ private accept;
30
+ private follow;
31
+ private followDirectory;
32
+ refreshDirectory(): Promise<void>;
33
+ refresh(): Promise<void>;
34
+ }
35
+ export declare class MemberConfigurationStores {
36
+ private readonly face;
37
+ private readonly stores;
38
+ constructor(face: MemberConfigurationFace);
39
+ get(id: string): MemberConfigurationStore;
40
+ }
41
+ //# sourceMappingURL=member-configuration.d.ts.map