@wowyuarm/dsh-agent-team 0.1.12 → 0.1.13

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 (85) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +2 -0
  3. package/cordis.patch.yml +7 -3
  4. package/package.json +14 -2
  5. package/packages/agent-team/README.md +2 -2
  6. package/packages/agent-team/README.zh.md +2 -2
  7. package/packages/agent-team/lib/index.js +151 -69
  8. package/packages/agent-team/lib/ledger.js +249 -31
  9. package/packages/agent-team/lib/member-context.js +18 -1
  10. package/packages/agent-team/lib/member-runtime.js +5 -4
  11. package/packages/agent-team/lib/mentions.js +48 -24
  12. package/packages/agent-team/lib/spec.js +19 -0
  13. package/packages/agent-team/lib/typert.host.js +187 -41
  14. package/packages/agent-team/lib/typert.remote-client.d.ts +7 -3
  15. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  16. package/packages/agent-team/lib/typert.remote-client.js +132 -27
  17. package/packages/agent-team/lib/types/index.d.ts +32 -7
  18. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  19. package/packages/agent-team/lib/types/ledger.d.ts +46 -2
  20. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  21. package/packages/agent-team/lib/types/member-context.d.ts +6 -0
  22. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  23. package/packages/agent-team/lib/types/mentions.d.ts +20 -7
  24. package/packages/agent-team/lib/types/mentions.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  26. package/packages/agent-team/lib/types/types/entities.d.ts +3 -2
  27. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  28. package/packages/agent-team/lib/types/types/operations.d.ts +37 -1
  29. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/types/requests-results.d.ts +50 -10
  31. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts +87 -0
  33. package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts.map +1 -0
  34. package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts +59 -0
  35. package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts.map +1 -0
  36. package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts +57 -0
  37. package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts.map +1 -0
  38. package/packages/agent-team/lib/vendor/storage-sqlite/index.js +139 -0
  39. package/packages/agent-team/lib/vendor/storage-sqlite/schema.js +120 -0
  40. package/packages/agent-team/lib/vendor/storage-sqlite/unit.js +132 -0
  41. package/packages/client-agent-team/README.md +1 -1
  42. package/packages/client-agent-team/README.zh.md +1 -1
  43. package/packages/client-agent-team/lib/client.js +603 -343
  44. package/packages/client-agent-team/lib/client.js.map +1 -1
  45. package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts +12 -0
  46. package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts.map +1 -0
  47. package/packages/client-agent-team/lib/types/client/TeamAgentImport.js +69 -0
  48. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -1
  49. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  50. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +29 -17
  51. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  52. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +19 -44
  53. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +2 -2
  54. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
  55. package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +15 -14
  56. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +1 -1
  57. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  58. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  59. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +15 -29
  60. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  61. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  62. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
  63. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  64. package/packages/client-agent-team/lib/types/client/index.js +8 -1
  65. package/packages/client-agent-team/lib/types/client/locales.d.ts +18 -0
  66. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  67. package/packages/client-agent-team/lib/types/client/locales.js +18 -0
  68. package/packages/client-agent-team/lib/types/client/slots.d.ts +3 -1
  69. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  70. package/packages/client-agent-team/lib/types/client/team-changes.d.ts +15 -31
  71. package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
  72. package/packages/client-agent-team/lib/types/client/team-changes.js +82 -111
  73. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +13 -11
  74. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  75. package/packages/client-agent-team/lib/types/client/team-formatters.js +29 -35
  76. package/packages/tool-agent-team/README.md +1 -1
  77. package/packages/tool-agent-team/README.zh.md +1 -1
  78. package/packages/tool-agent-team/lib/host-access.js +19 -0
  79. package/packages/tool-agent-team/lib/index.js +42 -33
  80. package/packages/tool-agent-team/lib/types/host-access.d.ts +10 -0
  81. package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -1
  82. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  83. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +0 -41
  84. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +0 -1
  85. package/packages/client-agent-team/lib/types/client/scope-coverage.js +0 -64
@@ -42,23 +42,21 @@ export interface MentionSegment {
42
42
  readonly name?: string;
43
43
  }
44
44
  /**
45
- * Locate one Message's structured mention names inside its literal body. A
46
- * name matches case-insensitively with an optional leading '@' on Unicode word
47
- * boundaries, and longer names win at the same position. Mention segments
48
- * render the canonical `@Handle`; names absent from the body come back
49
- * unmatched so the consumer can append them as a fallback chip row.
45
+ * Locate one Message's delivered mention names inside its literal body. Matching
46
+ * is the shared Host delivery scan — an authored `@`, case-insensitive on Unicode
47
+ * word boundaries, longest handle first, code quoted rather than called so a chip
48
+ * never lands where delivery would not reach. Mention segments render the canonical
49
+ * `@Handle`; names absent from the body come back unmatched so the consumer can
50
+ * append them as a fallback chip row.
50
51
  */
51
52
  export declare function splitMentionNames(text: string, names: readonly string[]): {
52
53
  segments: MentionSegment[];
53
54
  unmatched: readonly string[];
54
55
  };
55
56
  /**
56
- * Whether one draft spells a handle as an authored `@mention`: a literal `@`
57
- * before the handle, case-insensitively, on Unicode word boundaries. The Host
58
- * resolves delivery from the same text with its own scanner, so this is the
59
- * Client's single answer to "did the author call this name" — the composer
60
- * prunes picked recipients with it and previews the draft's notifications with
61
- * it.
57
+ * Whether one draft spells a handle as an authored `@mention`: the shared
58
+ * delivery scan, so the composer's recipient prune and will-notify preview agree
59
+ * with the Host on what the draft actually calls.
62
60
  */
63
61
  export declare function containsMention(body: string, handle: string): boolean;
64
62
  /** Whether one draft carries the `@all` marker the mention menu expands. */
@@ -84,6 +82,10 @@ export declare function allMentionMembers(members: readonly AgentTeamClientMembe
84
82
  export declare function mentionedMemberIds(body: string, members: readonly AgentTeamClientMemberStatus[]): readonly AgentTeamMemberId[];
85
83
  /** Canonical chip handles for one Message's structured mention refs. */
86
84
  export declare function mentionNamesOf(mentions: readonly AgentTeamMemberId[], handles: ReadonlyMap<AgentTeamMemberId, string>): string[];
85
+ /** Accessible label for one "who is on this work" stack: its owners' handles, comma-separated. */
86
+ export declare function claimersLabel(owners: ReadonlyArray<{
87
+ readonly name: string;
88
+ }>, t: TeamConversationProps['t']): string;
87
89
  /**
88
90
  * Whether an Agent body survives literal rendering unchanged: no fences,
89
91
  * inline code, emphasis markers, links, images, tables, or block constructs.
@@ -1 +1 @@
1
- {"version":3,"file":"team-formatters.d.ts","sourceRoot":"","sources":["../../../src/client/team-formatters.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"team-formatters.d.ts","sourceRoot":"","sources":["../../../src/client/team-formatters.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { hasAllMarker, resolveBodyMentions, scanBodyHandles } from '@wowyuarm/dsh-agent-team/mentions';
1
2
  export function formatTaskStatus(status, t) {
2
3
  return t({
3
4
  todo: 'taskStatusTodo',
@@ -81,56 +82,42 @@ export function isSingleBrandedRef(text) {
81
82
  const matches = [...trimmed.matchAll(BRANDED_REF_PATTERN)];
82
83
  return matches.length === 1 && matches[0][0] === trimmed;
83
84
  }
84
- function escapeRegExp(value) {
85
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
86
- }
87
85
  /**
88
- * Locate one Message's structured mention names inside its literal body. A
89
- * name matches case-insensitively with an optional leading '@' on Unicode word
90
- * boundaries, and longer names win at the same position. Mention segments
91
- * render the canonical `@Handle`; names absent from the body come back
92
- * unmatched so the consumer can append them as a fallback chip row.
86
+ * Locate one Message's delivered mention names inside its literal body. Matching
87
+ * is the shared Host delivery scan — an authored `@`, case-insensitive on Unicode
88
+ * word boundaries, longest handle first, code quoted rather than called so a chip
89
+ * never lands where delivery would not reach. Mention segments render the canonical
90
+ * `@Handle`; names absent from the body come back unmatched so the consumer can
91
+ * append them as a fallback chip row.
93
92
  */
94
93
  export function splitMentionNames(text, names) {
95
94
  if (names.length === 0)
96
95
  return { segments: [{ text, mention: false }], unmatched: [] };
97
- const ordered = [...names].sort((left, right) => right.length - left.length);
98
- // The lookbehind keeps the optional '@' from consuming the separator of an
99
- // email-like occurrence: the character before the name (or before its '@')
100
- // must not be a letter, digit, underscore, or another '@'.
101
- const pattern = new RegExp(`(?<![\\p{L}\\p{N}_@])@?(?:${ordered.map(name => `(${escapeRegExp(name)})`).join('|')})(?=$|[^\\p{L}\\p{N}_])`, 'giu');
102
96
  const segments = [];
103
97
  const matched = new Set();
104
98
  let cursor = 0;
105
- for (const match of text.matchAll(pattern)) {
106
- const groupIndex = match.findIndex((group, index) => index >= 1 && group !== undefined);
107
- if (groupIndex < 1)
108
- continue;
109
- if (match.index > cursor)
110
- segments.push({ text: text.slice(cursor, match.index), mention: false });
111
- const name = ordered[groupIndex - 1];
112
- segments.push({ text: `@${name}`, mention: true, name });
113
- matched.add(name.toLowerCase());
114
- cursor = match.index + match[0].length;
99
+ for (const match of scanBodyHandles(text, names)) {
100
+ if (match.start > cursor)
101
+ segments.push({ text: text.slice(cursor, match.start), mention: false });
102
+ segments.push({ text: `@${match.handle}`, mention: true, name: match.handle });
103
+ matched.add(match.handle.toLowerCase());
104
+ cursor = match.end;
115
105
  }
116
106
  if (cursor < text.length)
117
107
  segments.push({ text: text.slice(cursor), mention: false });
118
108
  return { segments, unmatched: names.filter(name => !matched.has(name.toLowerCase())) };
119
109
  }
120
110
  /**
121
- * Whether one draft spells a handle as an authored `@mention`: a literal `@`
122
- * before the handle, case-insensitively, on Unicode word boundaries. The Host
123
- * resolves delivery from the same text with its own scanner, so this is the
124
- * Client's single answer to "did the author call this name" — the composer
125
- * prunes picked recipients with it and previews the draft's notifications with
126
- * it.
111
+ * Whether one draft spells a handle as an authored `@mention`: the shared
112
+ * delivery scan, so the composer's recipient prune and will-notify preview agree
113
+ * with the Host on what the draft actually calls.
127
114
  */
128
115
  export function containsMention(body, handle) {
129
- return new RegExp(`(?:^|[^\\p{L}\\p{N}_])@${escapeRegExp(handle)}(?=$|[^\\p{L}\\p{N}_])`, 'iu').test(body);
116
+ return scanBodyHandles(body, [handle]).length > 0;
130
117
  }
131
118
  /** Whether one draft carries the `@all` marker the mention menu expands. */
132
119
  export function containsAllMention(body) {
133
- return /(?<![\p{L}\p{N}_@])@all(?=$|[^\p{L}\p{N}_])/u.test(body);
120
+ return hasAllMarker(body);
134
121
  }
135
122
  /**
136
123
  * Every Member the mention menu's `@all` row stands for: the roster this
@@ -153,12 +140,15 @@ export function allMentionMembers(members) {
153
140
  * rather than the prose the Host reads.
154
141
  */
155
142
  export function mentionedMemberIds(body, members) {
156
- if (containsAllMention(body))
143
+ if (hasAllMarker(body))
157
144
  return allMentionMembers(members).map(status => status.member.memberId);
158
- return members
145
+ const candidates = members
159
146
  .filter(status => status.member.state !== 'inactive' && status.member.state !== 'archived')
160
- .filter(status => containsMention(body, status.member.handle))
161
- .map(status => status.member.memberId);
147
+ .map(status => ({ memberId: status.member.memberId, handle: status.member.handle }));
148
+ // The draft's author is the Human reader, and a Message never mentions its
149
+ // own author: resolving with that sender drops a self-call exactly where
150
+ // delivery would.
151
+ return resolveBodyMentions(body, candidates, 'member:human').memberIds;
162
152
  }
163
153
  /** Canonical chip handles for one Message's structured mention refs. */
164
154
  export function mentionNamesOf(mentions, handles) {
@@ -168,6 +158,10 @@ export function mentionNamesOf(mentions, handles) {
168
158
  .map(memberId => memberId === 'member:human' ? 'human' : handles.get(memberId))
169
159
  .filter((name) => name !== undefined);
170
160
  }
161
+ /** Accessible label for one "who is on this work" stack: its owners' handles, comma-separated. */
162
+ export function claimersLabel(owners, t) {
163
+ return t('claimers', { names: owners.map(owner => `@${owner.name}`).join(', ') });
164
+ }
171
165
  const MARKDOWN_BLOCK_CONSTRUCT = /(^|\n)[ \t]{0,3}(?:#{1,6}[ \t]|>[ \t]|[-*+][ \t]|\d+[.)][ \t])|^[ \t]*\|.+\|/m;
172
166
  const MARKDOWN_INLINE_CONSTRUCT = /[`*_[\]!]|~~~|```/;
173
167
  /**
@@ -19,7 +19,7 @@ Mentions are authored in the Message body, as `@Handle` (the `@` is required, ma
19
19
 
20
20
  Every agent-facing render carries absolute event instants in the fixed Team coordination zone UTC+8 with an explicit offset (`2026-09-08T17:00:00+08:00`): `team_thread` fact lines and anchors stamp each fact with its committing operation's instant, `team_inbox` rows carry `newestOccurredAt`, `team_view` Thread rows carry `lastActivityAt`, notifications state `Occurred at:`, and committed mutations render `Committed at:` from the receipt. The same stored instant renders byte-identically on every reread path; only absolute timestamps are rendered, never relative text, and sequence and revision — not wall-clock time — remain the ordering authority.
21
21
 
22
- Canonical results expose stable refs, optional Task status, Thread revision, Claim history, Attention, and unread facts as structured fields. The model-visible renders follow the action decision surface: the write token appears only on a fully drained `team_thread read` and a committed public mutation; browsing results (`team_view`, `team_inbox`, status/follow/unfollow, `history`, `team_claim list`) and all typed rejections render no revision and no token. Typed `unread_required` and `stale_revision` results keep the structured fields needed to reread and retry deliberately. Tool execution resolves the exact live `exec.agent`; arguments cannot select or impersonate the actor or Workspace. Write request identity derives from sessionId plus tool callId. `context_rollover` and `context_checkpoint` conclude the Agent turn (a rollover must not be followed by old-generation work, and a checkpoint resolves at its containing turn's end); every other Team tool returns to the model loop.
22
+ Canonical results expose stable refs, optional Task status, Thread revision, Claim history, Attention, and unread facts as structured fields. The model-visible renders follow the action decision surface: the write token appears only on a fully drained `team_thread read` and a committed public mutation; browsing results (`team_view`, `team_inbox`, status/follow/unfollow, `history`, `team_claim list`) and all typed rejections render no revision and no token. Typed `unread_required` and `stale_revision` results keep the structured fields needed to reread and retry deliberately. Tool execution resolves the exact live `exec.agent`; arguments cannot select or impersonate the actor, and the optional `workspace` selector can only pick among that actor's participated Workspaces. Write request identity derives from sessionId plus tool callId. `context_rollover` and `context_checkpoint` conclude the Agent turn (a rollover must not be followed by old-generation work, and a checkpoint resolves at its containing turn's end); every other Team tool returns to the model loop.
23
23
 
24
24
  The complete implemented protocol is documented in [`../../docs/team-collaboration.md`](../../docs/team-collaboration.md).
25
25
 
@@ -19,7 +19,7 @@ mention 在 Message 正文里撰写,形如 `@Handle`(`@` 必需、大小写
19
19
 
20
20
  所有 agent-facing 渲染都在固定的 Team 协调时区 UTC+8 下携带带显式偏移的绝对事件时刻(`2026-09-08T17:00:00+08:00`):`team_thread` 的 fact 行与 anchor 为每条 fact 标注其提交 operation 的时刻,`team_inbox` 行携带 `newestOccurredAt`,`team_view` 的 Thread 行携带 `lastActivityAt`,通知给出 `Occurred at:`,已提交变更从 receipt 渲染 `Committed at:`。同一存储时刻在任何重读路径中渲染完全一致;只渲染绝对 timestamp,绝不出现相对时间文案,且 sequence 与 revision——而非 wall-clock 时间——仍是顺序 authority。
21
21
 
22
- Canonical result 以结构化字段暴露稳定 refs、可选 Task status、Thread revision、Claim history、Attention 和未读 facts。模型可见的渲染遵循 action decision surface:写令牌只出现在未读清零的 `team_thread read` 与一次已提交的 public mutation 上;浏览类结果(`team_view`、`team_inbox`、status/follow/unfollow、`history`、`team_claim list`)与所有类型化拒绝都不渲染 revision 与令牌。类型化的 `unread_required` 与 `stale_revision` 结果保留重新读取和审慎重试所需的结构化字段。工具执行通过准确的 live `exec.agent` 解析 actor;参数不能选择或冒充 actor Workspace。写操作的 request identity 由 sessionId 与 tool callId 派生。`context_rollover` 与 `context_checkpoint` 结束 Agent turn;其余 Team tools 将结果返回模型循环,不主动结束 turn。
22
+ Canonical result 以结构化字段暴露稳定 refs、可选 Task status、Thread revision、Claim history、Attention 和未读 facts。模型可见的渲染遵循 action decision surface:写令牌只出现在未读清零的 `team_thread read` 与一次已提交的 public mutation 上;浏览类结果(`team_view`、`team_inbox`、status/follow/unfollow、`history`、`team_claim list`)与所有类型化拒绝都不渲染 revision 与令牌。类型化的 `unread_required` 与 `stale_revision` 结果保留重新读取和审慎重试所需的结构化字段。工具执行通过准确的 live `exec.agent` 解析 actor;参数不能选择或冒充 actor,可选的 `workspace` 选择器只能在该 actor 已参与的 Workspace 中选择。写操作的 request identity 由 sessionId 与 tool callId 派生。`context_rollover` 与 `context_checkpoint` 结束 Agent turn;其余 Team tools 将结果返回模型循环,不主动结束 turn。
23
23
 
24
24
  完整的已实现协议见 [`../../docs/team-collaboration.md`](../../docs/team-collaboration.md)。
25
25
 
@@ -18,3 +18,22 @@ export function member(agent) {
18
18
  throw new Error('team tool requires an active Team Member');
19
19
  return current;
20
20
  }
21
+ /** A collaboration address, never a cwd or Session switch. */
22
+ export const workspaceParam = {
23
+ type: 'string',
24
+ description: 'Target Workspace id exactly as listed in your participation context or team_view. Required when you participate in more than one Workspace; only a sole participation can be inferred. This does not change your Session cwd.',
25
+ };
26
+ /** Reject ambiguous routing before a tool reads facts or attempts a mutation. */
27
+ export function workspaceOf(args, agent) {
28
+ const workspaces = service(agent).workspacesForAgent(agent);
29
+ const choices = workspaces.map(workspace => workspace.workspaceId).join(', ');
30
+ if (args.workspace === undefined) {
31
+ if (workspaces.length !== 1)
32
+ throw new Error(`workspace is required when participating in multiple Workspaces. Choose: ${choices}`);
33
+ return workspaces[0].workspaceId;
34
+ }
35
+ const selected = workspaces.find(workspace => workspace.workspaceId === args.workspace);
36
+ if (selected === undefined)
37
+ throw new Error(`Not participating in Workspace '${args.workspace}'. Choose: ${choices}`);
38
+ return selected.workspaceId;
39
+ }
@@ -1,7 +1,7 @@
1
1
  import { AGENT_TEAM_HUMAN_HANDLE, AgentTeamDmDeliveryError, markAgentTeamPreset } from '@wowyuarm/dsh-agent-team/host';
2
2
  import { formatTeamTimestamp } from '@wowyuarm/dsh-agent-team/time-format';
3
3
  import { registerContextTools } from "./context-tools.js";
4
- import { member, service } from "./host-access.js";
4
+ import { service, workspaceOf, workspaceParam } from "./host-access.js";
5
5
  import { defineTool } from '@deepseek-ai/dsh-tools';
6
6
  export const name = 'wowyuarm-agent-team-tools';
7
7
  export const inject = ['tools'];
@@ -114,13 +114,13 @@ function rejectionLines(noun, value) {
114
114
  }
115
115
  const teamInbox = defineTool({
116
116
  name: 'team_inbox',
117
- description: 'List your bounded Team Inbox for triage: unread Thread summaries with counts, without message bodies and without marking anything read. Read a selected Thread with team_thread read; the inbox itself authorizes no mutation.',
118
- parameters: { limit: { type: 'number' } },
117
+ description: 'List your bounded Team Inbox across all joined Workspaces for triage: unread Thread summaries with counts, without message bodies and without marking anything read. Read a selected Thread with team_thread read; the inbox itself authorizes no mutation.',
118
+ parameters: { limit: { type: 'number' }, workspace: { type: 'string', description: 'Optional Workspace id filter. Omit to triage all your participations together.' } },
119
119
  output: {
120
120
  schema: { type: 'object', additionalProperties: false, properties: {
121
121
  totalUnreadCount: { type: 'number', required: true }, totalDirectCount: { type: 'number', required: true },
122
122
  items: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: {
123
- threadRef: { type: 'string', required: true }, channelRef: { type: 'string', required: true },
123
+ workspaceId: { type: 'string', required: true }, threadRef: { type: 'string', required: true }, channelRef: { type: 'string', required: true },
124
124
  taskRef: { type: 'string' }, status: { type: 'string' }, revision: { type: 'number', required: true }, unreadCount: { type: 'number', required: true }, directCount: { type: 'number', required: true },
125
125
  taskNumber: { type: 'number' }, newestOccurredAt: { type: 'string' },
126
126
  } } },
@@ -139,7 +139,7 @@ const teamInbox = defineTool({
139
139
  const shown = value.items.reduce((sum, item) => sum + item.unreadCount, 0);
140
140
  return [{ type: 'text', text: [
141
141
  `Inbox — ${value.totalUnreadCount} unread update(s) total, ${value.totalDirectCount} direct, across ${value.items.length} Thread(s) shown${value.totalUnreadCount > shown ? `; ${value.totalUnreadCount - shown} more on Threads beyond this bounded list — call again with a larger limit.` : '.'}`,
142
- ...value.items.map(item => `${item.threadRef}${item.channelRef === undefined ? '' : ` · ${item.channelRef}`}${item.taskRef === undefined ? '' : ` · ${taskStanding(item)}`} · ${item.unreadCount} unread, ${item.directCount} direct${item.newestOccurredAt === undefined ? '' : ` · newest ${formatTeamTimestamp(item.newestOccurredAt)}`}`),
142
+ ...value.items.map(item => `${item.workspaceId} · ${item.threadRef}${item.channelRef === undefined ? '' : ` · ${item.channelRef}`}${item.taskRef === undefined ? '' : ` · ${taskStanding(item)}`} · ${item.unreadCount} unread, ${item.directCount} direct${item.newestOccurredAt === undefined ? '' : ` · newest ${formatTeamTimestamp(item.newestOccurredAt)}`}`),
143
143
  'Read a selected Thread with team_thread read. Listing changes no read state and supplies no write token.',
144
144
  ].join('\n') }];
145
145
  },
@@ -148,16 +148,13 @@ const teamInbox = defineTool({
148
148
  const agent = exec.agent;
149
149
  if (agent === undefined)
150
150
  throw new Error('team_inbox requires an Agent session');
151
- const current = member(agent);
152
151
  const host = service(agent);
153
- const inbox = host.inboxForAgent(agent, { workspaceId: current.workspaceId, ...(args.limit === undefined ? {} : { limit: args.limit }) });
154
- const taskNumbers = new Map(host.viewForAgent(agent, { workspaceId: current.workspaceId, topLevelOnly: true, includeActivities: false, direction: 'before' })
155
- .taskNumbers.map(entry => [entry.taskRef, entry.taskNumber]));
152
+ const inbox = host.inboxForAgent(agent, { ...(args.workspace === undefined ? {} : { workspaceId: workspaceOf(args, agent) }), ...(args.limit === undefined ? {} : { limit: args.limit }) });
156
153
  return {
157
154
  totalUnreadCount: inbox.totalUnreadCount, totalDirectCount: inbox.totalDirectCount,
158
155
  items: inbox.items.map(item => {
159
- const taskNumber = item.task === undefined ? undefined : taskNumbers.get(item.task.taskRef);
160
- return { threadRef: item.thread.threadRef, channelRef: item.channelRef,
156
+ const taskNumber = item.taskNumber;
157
+ return { workspaceId: item.workspaceId, threadRef: item.thread.threadRef, channelRef: item.channelRef,
161
158
  ...(item.task === undefined ? {} : { taskRef: item.task.taskRef, status: item.task.status }),
162
159
  revision: item.thread.revision, unreadCount: item.unreadCount, directCount: item.directCount, newestOccurredAt: item.newestOccurredAt,
163
160
  ...(taskNumber === undefined ? {} : { taskNumber }) };
@@ -172,10 +169,11 @@ const teamThread = defineTool({
172
169
  action: { type: 'string', required: true, enum: ['status', 'follow', 'unfollow', 'read', 'history'] },
173
170
  threadRef: { type: 'string', description: "Full branded Thread ref exactly as returned by Team tools, including the 'thread:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
174
171
  taskRef: { type: 'string', description: "Optional Task ref alias for released clients. Prefer threadRef; if both are given they must identify the same Thread." },
175
- beforeSequence: { type: 'number' }, limit: { type: 'number' },
172
+ beforeSequence: { type: 'number' }, limit: { type: 'number' }, workspace: workspaceParam,
176
173
  },
177
174
  output: {
178
175
  schema: { type: 'object', additionalProperties: false, properties: {
176
+ workspaceId: { type: 'string', required: true }, channelRef: { type: 'string', required: true },
179
177
  kind: { type: 'string', required: true }, threadRef: { type: 'string', required: true }, taskRef: { type: 'string' },
180
178
  revision: { type: 'number', required: true }, status: { type: 'string' }, resolution: { type: 'string' }, taskNumber: { type: 'number' },
181
179
  following: { type: 'boolean', required: true }, readThroughSequence: { type: 'number' }, remainingUnreadCount: { type: 'number' }, earlierFactCount: { type: 'number' }, cursor: { type: 'number' }, hasMore: { type: 'boolean' },
@@ -201,15 +199,16 @@ const teamThread = defineTool({
201
199
  // current collision surface or any write token.
202
200
  render: (args, value) => {
203
201
  const standing = taskStanding(value);
202
+ const source = `Workspace: ${value.workspaceId} · Channel: ${value.channelRef}`;
204
203
  if (value.kind === 'status') {
205
- return [{ type: 'text', text: `Attention status — ${value.following ? 'following' : 'not following'} ${value.threadRef}${standing === '' ? '' : ` · ${standing}`}.` }];
204
+ return [{ type: 'text', text: `${source}\nAttention status — ${value.following ? 'following' : 'not following'} ${value.threadRef}${standing === '' ? '' : ` · ${standing}`}.` }];
206
205
  }
207
206
  if (value.kind === 'follow' || value.kind === 'unfollow') {
208
- return [{ type: 'text', text: `Attention changed — ${value.following ? 'now following' : 'no longer following'} ${value.threadRef}${standing === '' ? '' : ` · ${standing}`}.` }];
207
+ return [{ type: 'text', text: `${source}\nAttention changed — ${value.following ? 'now following' : 'no longer following'} ${value.threadRef}${standing === '' ? '' : ` · ${standing}`}.` }];
209
208
  }
210
209
  if (value.kind === 'history') {
211
210
  const facts = value.facts;
212
- const lines = [`History for ${value.threadRef}${standing === '' ? '' : ` · ${standing}`}`];
211
+ const lines = [source, `History for ${value.threadRef}${standing === '' ? '' : ` · ${standing}`}`];
213
212
  // First page (no beforeSequence supplied) orients on the full
214
213
  // anchor; a continuation orients on the shared bounded subject. An
215
214
  // anchor already selected as a fact never repeats.
@@ -235,6 +234,7 @@ const teamThread = defineTool({
235
234
  // A read with nothing unread writes no durable operation, so the opening
236
235
  // line claims a commit only when unread facts were actually acknowledged.
237
236
  const lines = [
237
+ source,
238
238
  acknowledged === 0
239
239
  ? `Read — no unread updates on ${value.threadRef}; nothing remains.`
240
240
  : `Read committed — acknowledged ${acknowledged} unread update(s) on ${value.threadRef}; ${remaining} remain.`,
@@ -281,15 +281,14 @@ const teamThread = defineTool({
281
281
  const agent = exec.agent;
282
282
  if (agent === undefined)
283
283
  throw new Error('team_thread requires an Agent session');
284
- const current = member(agent);
285
284
  const host = service(agent);
286
285
  if (args.threadRef === undefined && args.taskRef === undefined)
287
286
  throw new Error('team_thread requires threadRef');
288
- const base = { workspaceId: current.workspaceId, ...(args.threadRef === undefined ? {} : { threadRef: args.threadRef }), ...(args.taskRef === undefined ? {} : { taskRef: args.taskRef }) };
287
+ const base = { workspaceId: workspaceOf(args, agent), ...(args.threadRef === undefined ? {} : { threadRef: args.threadRef }), ...(args.taskRef === undefined ? {} : { taskRef: args.taskRef }) };
289
288
  const taskNumberOf = (task) => {
290
289
  if (task === undefined)
291
290
  return {};
292
- const resolved = host.resolveTaskRefs({ workspaceId: current.workspaceId, taskRefs: [task.taskRef] }).resolved[0];
291
+ const resolved = host.resolveTaskRefs({ workspaceId: base.workspaceId, taskRefs: [task.taskRef] }).resolved[0];
293
292
  return resolved === undefined ? {} : { taskNumber: resolved.taskNumber };
294
293
  };
295
294
  if (args.action === 'status') {
@@ -297,26 +296,26 @@ const teamThread = defineTool({
297
296
  throw new Error('status does not accept history arguments');
298
297
  const status = host.attentionStatusForAgent(agent, base);
299
298
  const snapshot = host.threadHistoryForAgent(agent, { ...base, beforeSequence: 1, limit: 1 });
300
- return threadResult('status', snapshot, status.attention, [], taskNumberOf(snapshot.task));
299
+ return threadResult('status', base.workspaceId, snapshot, status.attention, [], taskNumberOf(snapshot.task));
301
300
  }
302
301
  if (args.action === 'follow' || args.action === 'unfollow') {
303
302
  if (args.beforeSequence !== undefined || args.limit !== undefined)
304
303
  throw new Error(`${args.action} does not accept history arguments`);
305
304
  const result = await host.changeAttentionForAgent(agent, { requestId: requestId(agent.id, exec.callId), ...base, action: args.action });
306
305
  const snapshot = host.threadHistoryForAgent(agent, { ...base, beforeSequence: 1, limit: 1 });
307
- return threadResult(args.action, snapshot, result.attention, [], taskNumberOf(snapshot.task));
306
+ return threadResult(args.action, base.workspaceId, snapshot, result.attention, [], taskNumberOf(snapshot.task));
308
307
  }
309
308
  if (args.action === 'history') {
310
309
  const history = host.threadHistoryForAgent(agent, { ...base, ...(args.beforeSequence === undefined ? {} : { beforeSequence: args.beforeSequence }), ...(args.limit === undefined ? {} : { limit: args.limit }) });
311
310
  const status = host.attentionStatusForAgent(agent, base);
312
- return threadResult('history', history, status.attention, history.facts.map(fact => fact.kind === 'message'
311
+ return threadResult('history', base.workspaceId, history, status.attention, history.facts.map(fact => fact.kind === 'message'
313
312
  ? { sequence: fact.sequence, kind: 'message', body: fact.message.body, sender: fact.message.sender, mentions: [...fact.mentions], occurredAt: fact.occurredAt }
314
313
  : activityFactView(fact.sequence, fact.activity, undefined, fact.occurredAt)), { cursor: history.cursor, hasMore: history.hasMore, ...taskNumberOf(history.task) });
315
314
  }
316
315
  if (args.beforeSequence !== undefined || args.limit !== undefined)
317
316
  throw new Error('read does not accept history arguments');
318
317
  const read = await host.readThreadForAgent(agent, { requestId: requestId(agent.id, exec.callId), ...base });
319
- return threadResult('read', read, read.attention, read.facts.map(entry => entry.fact.kind === 'message'
318
+ return threadResult('read', base.workspaceId, read, read.attention, read.facts.map(entry => entry.fact.kind === 'message'
320
319
  ? { sequence: entry.fact.sequence, kind: 'message', body: entry.fact.message.body, sender: entry.fact.message.sender, mentions: [...entry.fact.mentions], unread: entry.unread, direct: entry.direct, occurredAt: entry.fact.occurredAt }
321
320
  : activityFactView(entry.fact.sequence, entry.fact.activity, { unread: entry.unread, direct: entry.direct }, entry.fact.occurredAt)), { readThroughSequence: read.readThroughSequence, remainingUnreadCount: read.remainingUnreadCount, ...(read.earlierFactCount === undefined ? {} : { earlierFactCount: read.earlierFactCount }), ...(read.contextAdvice === undefined ? {} : { contextAdvice: adviceView(read.contextAdvice) }), ...taskNumberOf(read.task) });
322
321
  },
@@ -332,8 +331,9 @@ function factLine(fact) {
332
331
  function claimLine(claim) {
333
332
  return `${claim.claimRef} — ${claim.owner}: ${claim.direction}`;
334
333
  }
335
- function threadResult(kind, snapshot, attention, facts, extra = {}) {
334
+ function threadResult(kind, workspaceId, snapshot, attention, facts, extra = {}) {
336
335
  return {
336
+ workspaceId, channelRef: snapshot.anchor.channelRef,
337
337
  kind, threadRef: snapshot.thread.threadRef, revision: snapshot.thread.revision,
338
338
  ...(snapshot.task === undefined ? {} : { taskRef: snapshot.task.taskRef, status: snapshot.task.status, resolution: snapshot.task.resolution }),
339
339
  ...(extra.taskNumber === undefined ? {} : { taskNumber: extra.taskNumber }),
@@ -365,6 +365,7 @@ const teamMessage = markAgentTeamPreset(defineTool({
365
365
  asTask: { type: 'boolean', description: 'When true, start creates a Task with the Thread. Default false creates a taskless Thread.' },
366
366
  body: { type: 'string', required: true, description: "Markdown body. Lead with the conclusion or state. Mention the Human only when they must know or decide; when a decision is owed, say plainly what needs deciding and what happens by default if nobody answers — no fixed template. Keep it the shortest useful message for the recipients; mechanical detail follows below. Cite Team refs exactly as returned, as bare text with one colon (e.g. task:0f0a…) — never a double colon, never inside backticks or quotes. Unambiguous UUID abbreviations (first 6+ hex chars) also resolve. Mention a Member by writing `@Handle` (`@` required, case-insensitive) in the prose: that is what delivers the Message to them and renders the mention chip, and `@all` reaches the whole Channel." }, baseRevision: { type: 'number', description: "The next-write token from your latest fully drained team_thread read (or your own last committed mutation) on this Thread. Copy the explicitly rendered value verbatim; never increment, derive, compare, or cite it — it is an opaque concurrency token, not a fact about the Thread." },
367
367
  attachments: { type: 'array', items: { type: 'string' }, description: 'Absolute file paths to share, e.g. screenshots or generated artifacts; images render as thumbnails for recipients. The Host validates each path and copies the file into the attachment cache, and members also receive one cached path per attachment; if any path fails validation the whole send is rejected.' },
368
+ workspace: workspaceParam,
368
369
  },
369
370
  output: {
370
371
  schema: { type: 'object', additionalProperties: false, properties: {
@@ -408,7 +409,6 @@ const teamMessage = markAgentTeamPreset(defineTool({
408
409
  const agent = exec.agent;
409
410
  if (agent === undefined)
410
411
  throw new Error('team_message requires an Agent session');
411
- const current = member(agent);
412
412
  const host = service(agent);
413
413
  const rawPaths = args.attachments;
414
414
  const attachmentPaths = Array.isArray(rawPaths) ? rawPaths.filter((entry) => typeof entry === 'string' && entry.trim() !== '') : undefined;
@@ -416,7 +416,7 @@ const teamMessage = markAgentTeamPreset(defineTool({
416
416
  if (args.action === 'start') {
417
417
  if (args.channelRef === undefined || args.taskRef !== undefined || args.threadRef !== undefined || args.baseRevision !== undefined)
418
418
  throw new Error('start requires channelRef and does not accept threadRef, taskRef, or baseRevision');
419
- const result = await host.sendMessageForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
419
+ const result = await host.sendMessageForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: workspaceOf(args, agent),
420
420
  channelRef: args.channelRef, body: args.body, asTask: args.asTask === true, ...paths });
421
421
  return messageOutcome(result, 'start');
422
422
  }
@@ -426,7 +426,7 @@ const teamMessage = markAgentTeamPreset(defineTool({
426
426
  throw new Error('dm requires memberRef and body only; it does not accept channelRef, threadRef, taskRef, baseRevision, asTask, or attachments');
427
427
  }
428
428
  try {
429
- const result = await host.dmForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
429
+ const result = await host.dmForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: workspaceOf(args, agent),
430
430
  recipientMemberId: args.memberRef, body: args.body });
431
431
  return { kind: 'dm-sent', recipientMemberId: result.recipient.memberId, recipientHandle: result.recipient.handle, delivered: true, occurredAt: result.receipt.occurredAt };
432
432
  }
@@ -441,7 +441,7 @@ const teamMessage = markAgentTeamPreset(defineTool({
441
441
  if ((args.threadRef === undefined && args.taskRef === undefined) || args.channelRef !== undefined || args.asTask !== undefined || typeof baseRevision !== 'number' || !Number.isSafeInteger(baseRevision) || baseRevision < 1) {
442
442
  throw new Error('reply requires threadRef and a positive baseRevision; drain the Thread with team_thread read and copy the token it renders, or reuse the one your own last committed mutation rendered');
443
443
  }
444
- const result = await host.replyForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
444
+ const result = await host.replyForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: workspaceOf(args, agent),
445
445
  ...(args.threadRef === undefined ? {} : { threadRef: args.threadRef }),
446
446
  ...(args.taskRef === undefined ? {} : { taskRef: args.taskRef }),
447
447
  body: args.body, baseRevision, ...paths });
@@ -477,6 +477,7 @@ const teamClaim = defineTool({
477
477
  taskRef: { type: 'string', required: true, description: "Full branded Task ref exactly as returned by Team tools, including the 'task:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
478
478
  baseRevision: { type: 'number', description: "The next-write token from your latest fully drained team_thread read (or your own last committed mutation) on this Task's Thread. Copy the explicitly rendered value verbatim; never increment, derive, compare, or cite it — it is an opaque concurrency token, not a fact about the Task." }, direction: { type: 'string' },
479
479
  claimRef: { type: 'string', description: "Full branded Claim ref exactly as returned by team_claim, including the 'claim:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
480
+ workspace: workspaceParam,
480
481
  },
481
482
  output: {
482
483
  schema: { type: 'object', additionalProperties: false, properties: {
@@ -518,9 +519,8 @@ const teamClaim = defineTool({
518
519
  const agent = exec.agent;
519
520
  if (agent === undefined)
520
521
  throw new Error('team_claim requires an Agent session');
521
- const current = member(agent);
522
522
  const host = service(agent);
523
- const base = { workspaceId: current.workspaceId, taskRef: args.taskRef };
523
+ const base = { workspaceId: workspaceOf(args, agent), taskRef: args.taskRef };
524
524
  if (args.action === 'list') {
525
525
  if (args.baseRevision !== undefined || args.direction !== undefined || args.claimRef !== undefined)
526
526
  throw new Error('list accepts only taskRef');
@@ -557,11 +557,13 @@ const teamView = defineTool({
557
557
  description: 'Discover your authorized Team addresses: current Channels, a newest-first page of top-level Threads (each with its bounded anchor subject; Task standing inline on taskful rows), and current Members. This is an address book, not a work queue — unread work lives in team_inbox, and a Thread is read with team_thread read. The cursor pages Thread rows only.',
558
558
  parameters: {
559
559
  channelRef: { type: 'string', description: "Full branded Channel ref exactly as returned by Team tools, including the 'channel:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
560
- limit: { type: 'number' }, cursor: { type: 'number' },
560
+ limit: { type: 'number' }, cursor: { type: 'number' }, workspace: workspaceParam,
561
561
  },
562
562
  output: {
563
563
  schema: { type: 'object', additionalProperties: false, properties: {
564
564
  channels: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: { channelRef: { type: 'string', required: true }, name: { type: 'string', required: true } } } },
565
+ workspaceId: { type: 'string', required: true },
566
+ workspaces: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: { workspaceId: { type: 'string', required: true }, title: { type: 'string' }, default: { type: 'boolean', required: true } } } },
565
567
  members: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: {
566
568
  memberId: { type: 'string', required: true }, kind: { type: 'string', required: true }, handle: { type: 'string', required: true }, description: { type: 'string', required: true }, presence: { type: 'string', required: true },
567
569
  } } },
@@ -581,7 +583,7 @@ const teamView = defineTool({
581
583
  // which is reading, never writing from a directory snapshot.
582
584
  render: (_args, value) => {
583
585
  const continuation = value.page === 'threads';
584
- const lines = [];
586
+ const lines = [`Workspace: ${value.workspaceId}`];
585
587
  if (!continuation) {
586
588
  lines.push('Team directory', '', 'Channels — current');
587
589
  if (value.channels.length === 0)
@@ -596,6 +598,10 @@ const teamView = defineTool({
596
598
  else
597
599
  lines.push(...value.threads.map(thread => `${thread.threadRef} · ${thread.channelRef}${thread.taskRef === undefined ? ' · taskless' : ` · ${taskStanding(thread)}`} — ${thread.subject}${thread.lastActivityAt === undefined ? '' : ` · last activity ${formatTeamTimestamp(thread.lastActivityAt)}`}`));
598
600
  lines.push(`Thread cursor ${value.cursor}; hasMore=${value.hasMore ? 'true' : 'false'}${value.hasMore ? ' — older Thread anchors exist; page again with this cursor.' : ' — no older Threads remain.'}`);
601
+ if (!continuation && value.workspaces.length > 1) {
602
+ lines.push('', 'Workspaces — you participate in');
603
+ lines.push(...value.workspaces.map(workspace => `${workspace.workspaceId}${workspace.title === undefined ? '' : ` · ${workspace.title}`}${workspace.default ? ' · default — your Session and cwd live here' : ' — address it with the workspace argument; file work needs absolute paths'}`));
604
+ }
599
605
  if (!continuation) {
600
606
  lines.push('', 'Members — current');
601
607
  if (value.members.length === 0)
@@ -610,11 +616,14 @@ const teamView = defineTool({
610
616
  const agent = exec.agent;
611
617
  if (agent === undefined)
612
618
  throw new Error('team_view requires an Agent session');
613
- const current = member(agent);
614
619
  const host = service(agent);
615
- const view = host.viewForAgent(agent, { workspaceId: current.workspaceId, ...(args.channelRef === undefined ? {} : { channelRef: args.channelRef }), ...(args.limit === undefined ? {} : { limit: args.limit }), ...(args.cursor === undefined ? {} : { cursor: args.cursor }), topLevelOnly: true, includeActivities: false, direction: 'before' });
620
+ const workspaceId = workspaceOf(args, agent);
621
+ const view = host.viewForAgent(agent, { workspaceId, ...(args.channelRef === undefined ? {} : { channelRef: args.channelRef }), ...(args.limit === undefined ? {} : { limit: args.limit }), ...(args.cursor === undefined ? {} : { cursor: args.cursor }), topLevelOnly: true, includeActivities: false, direction: 'before' });
616
622
  const visibleMemberIds = new Set(view.members.map(membership => membership.memberId));
617
623
  return {
624
+ workspaceId,
625
+ workspaces: view.workspaces.map(participation => ({ workspaceId: participation.workspaceId,
626
+ ...(participation.title === undefined ? {} : { title: participation.title }), default: participation.default })),
618
627
  channels: view.channels.map(channel => ({ channelRef: channel.channelRef, name: channel.name })),
619
628
  members: [
620
629
  { memberId: view.humanMemberId, kind: 'human', handle: AGENT_TEAM_HUMAN_HANDLE, description: 'Human Team Member', presence: 'available' },
@@ -5,10 +5,20 @@
5
5
  * rejection rather than a silent no-op. Both messages are user-facing text.
6
6
  */
7
7
  import AgentTeam from '@wowyuarm/dsh-agent-team/host';
8
+ import type { WorkspaceId } from '@deepseek-ai/dsh-api-workspace-controller/client';
8
9
  /** The Agent shape every Team tool receives. */
9
10
  export type TeamToolAgent = NonNullable<Parameters<AgentTeam['memberForAgent']>[0]>;
10
11
  /** Resolve the Team Host service, or reject the tool call. */
11
12
  export declare function service(agent: TeamToolAgent): AgentTeam;
12
13
  /** Resolve the calling Team Member, or reject the tool call. */
13
14
  export declare function member(agent: TeamToolAgent): import("@wowyuarm/dsh-agent-team/types").AgentTeamAgentMember;
15
+ /** A collaboration address, never a cwd or Session switch. */
16
+ export declare const workspaceParam: {
17
+ type: "string";
18
+ description: string;
19
+ };
20
+ /** Reject ambiguous routing before a tool reads facts or attempts a mutation. */
21
+ export declare function workspaceOf(args: {
22
+ workspace?: string | undefined;
23
+ }, agent: TeamToolAgent): WorkspaceId;
14
24
  //# sourceMappingURL=host-access.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"host-access.d.ts","sourceRoot":"","sources":["../../src/host-access.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,SAAS,MAAM,+BAA+B,CAAA;AAErD,gDAAgD;AAChD,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAEnF,8DAA8D;AAC9D,wBAAgB,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAIvD;AAED,gEAAgE;AAChE,wBAAgB,MAAM,CAAC,KAAK,EAAE,aAAa,iEAI1C"}
1
+ {"version":3,"file":"host-access.d.ts","sourceRoot":"","sources":["../../src/host-access.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,SAAS,MAAM,+BAA+B,CAAA;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,gDAAgD;AAChD,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAEnF,8DAA8D;AAC9D,wBAAgB,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAIvD;AAED,gEAAgE;AAChE,wBAAgB,MAAM,CAAC,KAAK,EAAE,aAAa,iEAI1C;AAED,8DAA8D;AAC9D,eAAO,MAAM,cAAc;;;CAG1B,CAAA;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,EAAE,KAAK,EAAE,aAAa,GAAG,WAAW,CAUvG"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAelD,eAAO,MAAM,IAAI,8BAA8B,CAAA;AAC/C,eAAO,MAAM,MAAM,UAAY,CAAA;AAoqB/B,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAOxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAelD,eAAO,MAAM,IAAI,8BAA8B,CAAA;AAC/C,eAAO,MAAM,MAAM,UAAY,CAAA;AA8qB/B,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAOxC"}
@@ -1,41 +0,0 @@
1
- /** The change scopes whose wakes one surface answers with a shared refresh round. */
2
- export type SupplementalScope = 'workspace' | 'presence';
3
- /** One change wake, carrying a version from the scope that issued it. */
4
- export interface ScopeWake {
5
- readonly scope: SupplementalScope;
6
- readonly version: number;
7
- }
8
- /**
9
- * Per-scope coverage of the change versions one surface has already answered.
10
- *
11
- * A version is only comparable inside the scope that issued it: the Host
12
- * answers a workspace scope from the durable ledger position and a presence
13
- * scope from its process-local wake epoch, which starts low and climbs on every
14
- * Agent transition. One high-water mark shared by both would therefore let a
15
- * presence epoch swallow a later, smaller ledger sequence and park the surface
16
- * on stale data, so coverage and pending versions are kept per scope.
17
- *
18
- * One round answers one version per scope. The Host delivers one event to every
19
- * matching scope, so the first version a round sees in a scope it has not
20
- * answered yet is that event reaching a second scope, and joins the round
21
- * already fetching instead of earning a second identical read. A newer version
22
- * in a scope the round has answered arrived after the round issued its fetch,
23
- * so it owes one trailing round.
24
- */
25
- export declare class ScopeCoverage {
26
- private readonly covered;
27
- private readonly pending;
28
- /** The scopes the open round has an answer for. */
29
- private readonly answered;
30
- private fetching;
31
- /** Folds one wake in and answers whether it opens a round. */
32
- wake(scope: SupplementalScope, version: number): boolean;
33
- /** Opens a round's fetch window; versions observed from here on are pending. */
34
- beginRound(): void;
35
- /** Closes a round's fetch window and answers whether a trailing round is owed. */
36
- finishRound(): boolean;
37
- /** Drops every observation: a new owner starts with nothing covered. */
38
- reset(): void;
39
- private coveredOf;
40
- }
41
- //# sourceMappingURL=scope-coverage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scope-coverage.d.ts","sourceRoot":"","sources":["../../../src/client/scope-coverage.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,UAAU,CAAA;AAExD,yEAAyE;AACzE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,mDAAmD;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAQ;IAExB,8DAA8D;IAC9D,IAAI,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAWxD,gFAAgF;IAChF,UAAU,IAAI,IAAI;IAKlB,kFAAkF;IAClF,WAAW,IAAI,OAAO;IAYtB,wEAAwE;IACxE,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,SAAS;CAGlB"}