agents-can-communicate 0.10.3 → 0.11.0

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 (89) hide show
  1. package/README.md +29 -21
  2. package/bin/acc-indicator.mjs +5 -0
  3. package/docs/CAPABILITIES.md +3 -0
  4. package/docs/CLI.md +34 -7
  5. package/docs/MCP.md +42 -2
  6. package/docs/PROTOCOL.md +19 -0
  7. package/docs/STATUS_INDICATOR.md +128 -0
  8. package/docs/TROUBLESHOOTING.md +10 -0
  9. package/docs/UPGRADING.md +16 -0
  10. package/docs/WHY_ACC.md +14 -8
  11. package/node_modules/@agents-can-communicate/adapter-antigravity/package.json +1 -1
  12. package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/plugin.json +1 -1
  13. package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/skills/acc/SKILL.md +29 -5
  14. package/node_modules/@agents-can-communicate/adapter-antigravity/src/adapter.mjs +3 -0
  15. package/node_modules/@agents-can-communicate/adapter-antigravity/src/indicator-install.mjs +80 -0
  16. package/node_modules/@agents-can-communicate/adapter-antigravity/src/indicator-render.mjs +8 -0
  17. package/node_modules/@agents-can-communicate/adapter-antigravity/src/install.mjs +7 -4
  18. package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
  19. package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/hooks/indicator.mjs +67 -0
  20. package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/skills/acc/SKILL.md +29 -5
  21. package/node_modules/@agents-can-communicate/adapter-claude-code/src/adapter.mjs +1 -0
  22. package/node_modules/@agents-can-communicate/adapter-claude-code/src/install.mjs +16 -5
  23. package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
  24. package/node_modules/@agents-can-communicate/adapter-codex/plugin/skills/acc/SKILL.md +48 -5
  25. package/node_modules/@agents-can-communicate/adapter-codex/src/native-delivery.mjs +9 -6
  26. package/node_modules/@agents-can-communicate/adapter-codex/src/native-endpoint.mjs +16 -5
  27. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/gemini-extension.json +1 -1
  28. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/skills/acc/SKILL.md +29 -5
  29. package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
  30. package/node_modules/@agents-can-communicate/adapter-grok/package.json +1 -1
  31. package/node_modules/@agents-can-communicate/adapter-grok/plugin/skills/acc/SKILL.md +29 -5
  32. package/node_modules/@agents-can-communicate/adapter-grok/src/adapter.mjs +4 -0
  33. package/node_modules/@agents-can-communicate/adapter-grok/src/indicator-install.mjs +30 -0
  34. package/node_modules/@agents-can-communicate/adapter-grok/src/indicator.mjs +23 -0
  35. package/node_modules/@agents-can-communicate/adapter-grok/src/install.mjs +9 -5
  36. package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
  37. package/node_modules/@agents-can-communicate/adapter-kimi/plugin/skills/acc/SKILL.md +29 -5
  38. package/node_modules/@agents-can-communicate/adapter-kimi/src/adapter.mjs +4 -0
  39. package/node_modules/@agents-can-communicate/adapter-kimi/src/indicator-install.mjs +30 -0
  40. package/node_modules/@agents-can-communicate/adapter-kimi/src/indicator.mjs +17 -0
  41. package/node_modules/@agents-can-communicate/adapter-kimi/src/install.mjs +12 -6
  42. package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
  43. package/node_modules/@agents-can-communicate/adapter-sdk/src/hook-shim.mjs +1 -0
  44. package/node_modules/@agents-can-communicate/adapter-sdk/src/index.mjs +5 -1
  45. package/node_modules/@agents-can-communicate/adapter-sdk/src/indicator-command.mjs +14 -0
  46. package/node_modules/@agents-can-communicate/adapter-sdk/src/indicator-text.mjs +13 -0
  47. package/node_modules/@agents-can-communicate/adapter-sdk/src/native-vocabulary.mjs +2 -0
  48. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation-order.mjs +12 -0
  49. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation-writer.mjs +37 -0
  50. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation.mjs +47 -0
  51. package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-indicator.mjs +141 -0
  52. package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-scan.mjs +99 -0
  53. package/node_modules/@agents-can-communicate/cli/package.json +2 -1
  54. package/node_modules/@agents-can-communicate/cli/src/args.mjs +5 -3
  55. package/node_modules/@agents-can-communicate/cli/src/claim-command.mjs +64 -0
  56. package/node_modules/@agents-can-communicate/cli/src/help.mjs +15 -8
  57. package/node_modules/@agents-can-communicate/cli/src/index.mjs +1 -0
  58. package/node_modules/@agents-can-communicate/cli/src/indicator-command.mjs +65 -0
  59. package/node_modules/@agents-can-communicate/cli/src/indicator-previous-command.mjs +84 -0
  60. package/node_modules/@agents-can-communicate/cli/src/indicator-previous-windows.mjs +8 -0
  61. package/node_modules/@agents-can-communicate/cli/src/indicator.mjs +112 -0
  62. package/node_modules/@agents-can-communicate/cli/src/install-command.mjs +4 -0
  63. package/node_modules/@agents-can-communicate/cli/src/main.mjs +8 -54
  64. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/entry.mjs +19 -0
  65. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/launchers.mjs +5 -3
  66. package/node_modules/@agents-can-communicate/cli/src/native-session-diagnostics.mjs +2 -0
  67. package/node_modules/@agents-can-communicate/core/package.json +1 -1
  68. package/node_modules/@agents-can-communicate/core/src/claim-selectors.mjs +62 -0
  69. package/node_modules/@agents-can-communicate/core/src/claims.mjs +88 -81
  70. package/node_modules/@agents-can-communicate/delivery-router/package.json +1 -1
  71. package/node_modules/@agents-can-communicate/delivery-router/src/refresh-binding.mjs +9 -6
  72. package/node_modules/@agents-can-communicate/delivery-router/src/router.mjs +19 -5
  73. package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
  74. package/node_modules/@agents-can-communicate/installer/package.json +1 -1
  75. package/node_modules/@agents-can-communicate/installer/src/apply.mjs +3 -0
  76. package/node_modules/@agents-can-communicate/installer/src/delivery-diagnostics.mjs +1 -0
  77. package/node_modules/@agents-can-communicate/installer/src/ownership.mjs +2 -1
  78. package/node_modules/@agents-can-communicate/installer/src/plan.mjs +11 -2
  79. package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
  80. package/node_modules/@agents-can-communicate/mcp-server/src/claim-tools.mjs +56 -0
  81. package/node_modules/@agents-can-communicate/mcp-server/src/input-validator.mjs +9 -0
  82. package/node_modules/@agents-can-communicate/mcp-server/src/server.mjs +7 -8
  83. package/node_modules/@agents-can-communicate/mcp-server/src/tools.mjs +27 -9
  84. package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
  85. package/node_modules/@agents-can-communicate/protocol/src/index.mjs +1 -0
  86. package/node_modules/@agents-can-communicate/storage-filesystem/package.json +1 -1
  87. package/node_modules/@agents-can-communicate/storage-filesystem/src/index.mjs +1 -1
  88. package/node_modules/@agents-can-communicate/storage-filesystem/src/session-read.mjs +13 -0
  89. package/package.json +3 -1
@@ -14,7 +14,7 @@ import { LIVE_POLICIES, describeActivation, describeDeactivation, planActivation
14
14
  */
15
15
  export function planInstallation({ adapters, detected, context, action = "install",
16
16
  recorded = [], accVersion = null, allowDowngrade = false, requested = [],
17
- deliveryByAdapter = {}, deliveryDecisionByAdapter = {}, allowServiceSetup = false }) {
17
+ deliveryByAdapter = {}, deliveryDecisionByAdapter = {}, allowServiceSetup = false, indicator }) {
18
18
  if (!["install", "uninstall"].includes(action)) {
19
19
  throw new AccError(EXIT.USAGE, `unknown installation action: ${action}`, { action });
20
20
  }
@@ -157,7 +157,13 @@ export function planInstallation({ adapters, detected, context, action = "instal
157
157
  : null;
158
158
  const deliverySummary = action === "install"
159
159
  ? describeInstallDelivery(entry, delivery, effectiveLivePolicy) : null;
160
- const installContext = { ...context, requestedLivePolicy: delivery,
160
+ const indicatorPreference = indicator ?? recordedById.get(entry.adapterId)?.indicator ?? "off";
161
+ const indicatorDiagnostic = indicatorPreference !== "on" ? null : !adapter.statusIndicator
162
+ ? `${adapter.displayName} indicator: not supported in this client's native status line`
163
+ : entry.version == null || isOlder(entry.version, adapter.statusIndicator.minimumVersion)
164
+ ? `${adapter.displayName} indicator requires client ${adapter.statusIndicator.minimumVersion} or later`
165
+ : `${adapter.displayName} indicator: enabled; ${adapter.statusIndicator.reload}`;
166
+ const installContext = { ...context, indicator: indicatorPreference, requestedLivePolicy: delivery,
161
167
  livePolicy: configuredLivePolicy, clientVersion: entry.version, platform: entry.platform };
162
168
  const nativeServiceSetup = action === "install" && allowServiceSetup && delivery !== "off"
163
169
  && deliveryDecision.completeSetup === true ? entry.nativeServiceSetup : undefined;
@@ -192,6 +198,8 @@ export function planInstallation({ adapters, detected, context, action = "instal
192
198
  clientPresent: entry.present === true,
193
199
  alreadyInstalled: entry.installed === true,
194
200
  livePolicy: delivery,
201
+ indicator: indicatorPreference,
202
+ ...(indicatorDiagnostic === null ? {} : { indicatorDiagnostic }),
195
203
  effectiveLivePolicy,
196
204
  ...(action === "install" ? { deliveryDecision } : {}),
197
205
  ...(retainedActivation ? { configuredLivePolicy, retainedNativeActivation: retainedActivation } : {}),
@@ -205,6 +213,7 @@ export function planInstallation({ adapters, detected, context, action = "instal
205
213
  // Said in the operator's terms, not in paths: which files ACC creates
206
214
  // outright and which belong to the user and are only edited.
207
215
  summary: [
216
+ ...(indicatorDiagnostic === null ? [] : [indicatorDiagnostic]),
208
217
  ...(entry.present ? [] : [`${adapter.displayName ?? adapter.id} is no longer on `
209
218
  + "this machine; removing what ACC recorded writing"]),
210
219
  ...(deliverySummary === null ? [] : [deliverySummary]),
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/mcp-server",
3
- "version": "0.10.3",
3
+ "version": "0.11.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -0,0 +1,56 @@
1
+ import { AccError, EXIT, assertMatchableResource, assertPortableId,
2
+ assertResourceUri, normaliseResource } from "@agents-can-communicate/protocol";
3
+
4
+ const invalid = message => { throw new AccError(EXIT.USAGE, message); };
5
+
6
+ function resourceSelector(resource) {
7
+ assertMatchableResource(resource, invalid);
8
+ return assertResourceUri(normaliseResource(resource), "resource");
9
+ }
10
+
11
+ function claimIdSelector(claimId, field) {
12
+ try { return assertPortableId(claimId, field); }
13
+ catch (error) {
14
+ if (!(error instanceof AccError)) throw error;
15
+ invalid(`${field} must be a portable identifier`);
16
+ }
17
+ }
18
+
19
+ // URI normalization and identifier validation must precede resolving a session:
20
+ // an invalid selector must not create presence or a persistent session binding.
21
+ export function validateClaimSelectors(name, args) {
22
+ if (name !== "acc_claim" && name !== "acc_release") return args;
23
+ const result = { ...args };
24
+ if (args.resource !== undefined) result.resource = resourceSelector(args.resource);
25
+ if (args.resources !== undefined) {
26
+ result.resources = args.resources.map(resourceSelector);
27
+ if (new Set(result.resources).size !== result.resources.length) {
28
+ invalid("arguments.resources contains duplicate selectors after normalization");
29
+ }
30
+ }
31
+ if (args.claimId !== undefined) claimIdSelector(args.claimId, "arguments.claimId");
32
+ args.claimIds?.forEach((id, index) => claimIdSelector(id, `arguments.claimIds[${index}]`));
33
+ return result;
34
+ }
35
+
36
+ export async function claimTool(service, owner, args) {
37
+ if (args.action === "renew") return service.renewClaim({ ...owner,
38
+ claimId: args.claimId, leaseSeconds: args.leaseSeconds });
39
+ const input = { ...owner, mode: args.mode ?? "exclusive", enforcement: "advisory",
40
+ reason: args.reason ?? "unspecified", leaseSeconds: args.leaseSeconds };
41
+ if (args.resources !== undefined) {
42
+ return { claims: await service.acquireClaims({ ...input, resources: args.resources }) };
43
+ }
44
+ return service.acquireClaim({ ...input, resource: args.resource });
45
+ }
46
+
47
+ export async function releaseTool(service, owner, args) {
48
+ if (args.claimId !== undefined) {
49
+ await service.releaseClaim({ ...owner, claimId: args.claimId });
50
+ return { released: args.claimId };
51
+ }
52
+ const selected = args.resource !== undefined ? { resources: [args.resource] } : args;
53
+ const claims = await service.releaseClaims({ ...owner, ...selected });
54
+ const released = claims.map(claim => claim.claimId);
55
+ return { released: args.resource !== undefined ? released[0] : released };
56
+ }
@@ -43,6 +43,12 @@ function validateSchema(schema, value, path) {
43
43
  }
44
44
  } else if (schema.type === "array") {
45
45
  if (!Array.isArray(value)) fail(path, "must be an array");
46
+ if (schema.minItems !== undefined && value.length < schema.minItems) {
47
+ fail(path, `must contain at least ${schema.minItems} item(s)`);
48
+ }
49
+ if (schema.uniqueItems === true && new Set(value).size !== value.length) {
50
+ fail(path, "must contain unique items");
51
+ }
46
52
  if (schema.items !== undefined) {
47
53
  value.forEach((item, index) => validateSchema(schema.items, item, `${path}[${index}]`));
48
54
  }
@@ -53,6 +59,9 @@ function validateSchema(schema, value, path) {
53
59
  } else if (schema.type === "integer" && !Number.isInteger(value)) {
54
60
  fail(path, "must be an integer");
55
61
  }
62
+ if (schema.minLength !== undefined && value.length < schema.minLength) {
63
+ fail(path, `must contain at least ${schema.minLength} character(s)`);
64
+ }
56
65
 
57
66
  if (schema.minimum !== undefined && value < schema.minimum) {
58
67
  fail(path, `must be at least ${schema.minimum}`);
@@ -5,6 +5,7 @@ import { clearSessionBinding, loadSessionBinding, storeSessionBinding }
5
5
 
6
6
  import { readResource } from "./resources.mjs";
7
7
  import { validateToolInput } from "./input-validator.mjs";
8
+ import { claimTool, releaseTool, validateClaimSelectors } from "./claim-tools.mjs";
8
9
  import { PUBLIC_TOOLS, RESOURCES } from "./tools.mjs";
9
10
  import { createProtocol } from "./protocol.mjs";
10
11
 
@@ -133,14 +134,9 @@ async function callTool(name, args, context) {
133
134
  return service.setIntent({ ...owner, summary: args.summary, mode: args.mode,
134
135
  state: args.state, resourceHints: args.resourceHints ?? [] });
135
136
  case "acc_claim":
136
- if (args.action === "renew") return service.renewClaim({ ...owner,
137
- claimId: args.claimId, leaseSeconds: args.leaseSeconds });
138
- return service.acquireClaim({ ...owner, resource: args.resource,
139
- mode: args.mode ?? "exclusive", enforcement: "advisory",
140
- reason: args.reason ?? "unspecified", leaseSeconds: args.leaseSeconds });
137
+ return claimTool(service, owner, args);
141
138
  case "acc_release":
142
- await service.releaseClaim({ ...owner, claimId: args.claimId });
143
- return { released: args.claimId };
139
+ return releaseTool(service, owner, args);
144
140
  case "acc_message": {
145
141
  const kind = args.kind ?? "note";
146
142
  const toParticipantIds = args.to ?? [];
@@ -219,13 +215,16 @@ async function handle(message, context) {
219
215
  throw new AccError(EXIT.USAGE, `unknown tool: ${params.name}`, { name: params.name });
220
216
  }
221
217
  validateToolInput(tool.inputSchema, args);
222
- const value = await callTool(params.name, args, context);
218
+ const value = await callTool(params.name, validateClaimSelectors(params.name, args), context);
223
219
  return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
224
220
  structuredContent: value };
225
221
  } catch (error) {
226
222
  // A failing operation is a tool result, not a transport failure: the
227
223
  // model must see it and be able to react.
224
+ const batchConflict = params.name === "acc_claim"
225
+ && params.arguments?.resources !== undefined && error.details?.conflicts !== undefined;
228
226
  return { isError: true,
227
+ ...(batchConflict ? { structuredContent: { code: error.code, details: error.details } } : {}),
229
228
  content: [{ type: "text", text: `${params.name}: ${error.message}` }] };
230
229
  }
231
230
  }
@@ -19,6 +19,10 @@ const object = (properties, required = []) => ({
19
19
 
20
20
  const string = description => ({ type: "string", description });
21
21
  const stringList = description => ({ type: "array", items: { type: "string" }, description });
22
+ const selector = description => ({ ...string(description), minLength: 1 });
23
+ const selectors = description => ({ type: "array", items: { type: "string", minLength: 1 },
24
+ minItems: 1, uniqueItems: true, description });
25
+ const releaseFields = ["claimId", "claimIds", "resource", "resources", "all"];
22
26
 
23
27
  export const PUBLIC_TOOLS = Object.freeze([
24
28
  {
@@ -68,31 +72,45 @@ export const PUBLIC_TOOLS = Object.freeze([
68
72
  },
69
73
  {
70
74
  name: "acc_claim",
71
- description: `Acquire or renew a claim on a resource URI. Claims are `
75
+ description: `Acquire one resource or atomically acquire a nonempty resources array; renew by claimId. `
76
+ + `resource returns a Claim; resources returns {claims: [...]}, including one-item arrays. `
77
+ + `A conflicting batch acquires nothing and lists every conflicting holder in structuredContent.details.conflicts. Claims are `
72
78
  + `workspace-wide and advisory here: this client has no write guard, so a claim `
73
79
  + `informs peers rather than preventing an edit. ${MUTATION_POLL}`,
74
80
  inputSchema: { ...object({
75
- resource: string("Resource URI, for example file:packages/core/**."),
81
+ resource: selector("One resource URI, exclusive with resources; for example file:packages/core/**."),
82
+ resources: selectors("Resource URIs for one atomic acquisition; unique after normalization and exclusive with resource."),
76
83
  action: { type: "string", enum: ["acquire", "renew"] },
77
84
  mode: { type: "string", enum: ["shared", "exclusive"] },
78
85
  reason: string("Why the resource is being claimed."),
79
86
  leaseSeconds: { type: "integer", minimum: 1,
80
87
  description: "Lease length; the claim expires without renewal." },
81
- claimId: string("Required for renew."),
88
+ claimId: selector("Required for renew; renew accepts one claimId only."),
82
89
  }, ["action"]), oneOf: [
83
90
  { properties: { action: { const: "acquire" } }, required: ["resource"],
84
- not: { required: ["claimId"] } },
91
+ not: { anyOf: ["resources", "claimId"].map(field => ({ required: [field] })) } },
92
+ { properties: { action: { const: "acquire" } }, required: ["resources"],
93
+ not: { anyOf: ["resource", "claimId"].map(field => ({ required: [field] })) } },
85
94
  { properties: { action: { const: "renew" } }, required: ["claimId"],
86
- not: { anyOf: ["resource", "mode", "reason"]
95
+ not: { anyOf: ["resource", "resources", "mode", "reason"]
87
96
  .map(field => ({ required: [field] })) } },
88
97
  ] },
89
98
  },
90
99
  {
91
100
  name: "acc_release",
92
- description: `Release a claim this session owns. ${MUTATION_POLL}`,
93
- inputSchema: object({
94
- claimId: string("The claim to release."),
95
- }, ["claimId"]),
101
+ description: `Release only claims this session owns, with exactly one of claimId, claimIds, resource, `
102
+ + `resources, or all: true. Arrays release atomically. Scalar selectors return {released: id}; `
103
+ + `arrays and all return {released: [ids]}, including an empty all result. `
104
+ + `all keeps this session's presence and intent open. ${MUTATION_POLL}`,
105
+ inputSchema: { ...object({
106
+ claimId: selector("One claim to release."),
107
+ claimIds: selectors("Claim IDs to release atomically."),
108
+ resource: selector("One exact resource URI this session holds."),
109
+ resources: selectors("Exact resource URIs to release atomically; unique after normalization."),
110
+ all: { type: "boolean", const: true, description: "Release every claim owned by this session." },
111
+ }), oneOf: releaseFields.map(field => ({ required: [field],
112
+ not: { anyOf: releaseFields.filter(other => other !== field)
113
+ .map(other => ({ required: [other] })) } })) },
96
114
  },
97
115
  {
98
116
  name: "acc_message",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/protocol",
3
- "version": "0.10.3",
3
+ "version": "0.11.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -11,5 +11,6 @@ export { CONFIG_FILENAME, CONFIG_SCHEMA_VERSION, RUNTIME_KEYS, defaultProjectCon
11
11
  validateProjectConfig } from "./config.mjs";
12
12
  export { RECEIPT_STATES, advanceReceipt } from "./states.mjs";
13
13
  export { assertMatchableResource, normaliseResource } from "./resources.mjs";
14
+ export { resourceUri as assertResourceUri } from "./fields.mjs";
14
15
  export { assertDecisionChange } from "./decision-changes.mjs";
15
16
  export { TRANSACTION_INDEXES, assertIndexTuple, indexKeysFor } from "./transaction-indexes.mjs";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/storage-filesystem",
3
- "version": "0.10.3",
3
+ "version": "0.11.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -3,6 +3,6 @@ export { openFilesystemStore, storePaths, ZERO_CURSOR } from "./store.mjs";
3
3
  export { diagnoseFilesystemStore, repairFilesystemStore } from "./recovery.mjs";
4
4
  export { readStoreIdentity, requireStoreIdentity, STORE_VERSION } from "./identity.mjs";
5
5
  export { withWriterMutex } from "./writer-mutex.mjs";
6
- export { readSessionRecord } from "./session-read.mjs";
6
+ export { readSessionRecord, readDeliveryBindingRecord } from "./session-read.mjs";
7
7
  export { openNoFollow } from "./portable-fs.mjs";
8
8
  export { migrateFilesystemStore } from "./store-migration.mjs";
@@ -25,3 +25,16 @@ export async function readSessionRecord({ root, workspaceId, sessionId, allowLeg
25
25
  if (ephemeral === null || await ephemeralIsDeleted(paths, root, "session", sessionId)) return null;
26
26
  return validateRecord("session", ephemeral.value);
27
27
  }
28
+
29
+ /** Read the one session's transport metadata without recovery, locks or renewal. */
30
+ export async function readDeliveryBindingRecord({ root, workspaceId, sessionId }) {
31
+ assertPortableId(sessionId, "session id");
32
+ const paths = storePaths(root);
33
+ await requireStoreIdentity(paths, { workspaceId, create: false });
34
+ const value = await readJsonIfPresent(
35
+ path.join(paths.ephemeral, "deliveryBinding", `${sessionId}.json`), root);
36
+ if (value === null || await ephemeralIsDeleted(paths, root, "deliveryBinding", sessionId)) return null;
37
+ const binding = validateRecord("deliveryBinding", value.value);
38
+ if (binding.sessionId !== sessionId) throw new Error("delivery binding does not match its path");
39
+ return binding;
40
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-can-communicate",
3
- "version": "0.10.3",
3
+ "version": "0.11.0",
4
4
  "accManagedUpdateProtocol": 2,
5
5
  "accStoreVersion": 7,
6
6
  "type": "module",
@@ -43,6 +43,7 @@
43
43
  },
44
44
  "bin": {
45
45
  "acc": "bin/acc.mjs",
46
+ "acc-indicator": "bin/acc-indicator.mjs",
46
47
  "acc-mcp": "bin/acc-mcp.mjs",
47
48
  "acc-hook": "bin/acc-hook.mjs"
48
49
  },
@@ -52,6 +53,7 @@
52
53
  "docs/ARCHITECTURE.md",
53
54
  "docs/CAPABILITIES.md",
54
55
  "docs/CLI.md",
56
+ "docs/STATUS_INDICATOR.md",
55
57
  "docs/CONCEPTS.md",
56
58
  "docs/CONFIGURATION.md",
57
59
  "docs/DESIGN_DECISIONS.md",