agents-can-communicate 0.10.4 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -21
- package/bin/acc-indicator.mjs +5 -0
- package/bin/entrypoints/acc-antigravity-relay.mjs +2 -2
- package/bin/entrypoints/acc-hook.mjs +4 -24
- package/bin/entrypoints/acc-mcp.mjs +8 -6
- package/bin/entrypoints/acc.mjs +22 -11
- package/bin/entrypoints/antigravity-relay-binding.mjs +1 -1
- package/docs/CAPABILITIES.md +3 -0
- package/docs/CLI.md +34 -7
- package/docs/MCP.md +42 -2
- package/docs/PROTOCOL.md +19 -0
- package/docs/STATUS_INDICATOR.md +133 -0
- package/docs/TROUBLESHOOTING.md +2 -2
- package/docs/WHY_ACC.md +14 -8
- package/node_modules/@agents-can-communicate/adapter-antigravity/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/plugin.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/skills/acc/SKILL.md +29 -5
- package/node_modules/@agents-can-communicate/adapter-antigravity/src/adapter.mjs +3 -0
- package/node_modules/@agents-can-communicate/adapter-antigravity/src/indicator-install.mjs +80 -0
- package/node_modules/@agents-can-communicate/adapter-antigravity/src/indicator-render.mjs +8 -0
- package/node_modules/@agents-can-communicate/adapter-antigravity/src/install.mjs +7 -4
- package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/hooks/indicator.mjs +83 -0
- package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/skills/acc/SKILL.md +29 -5
- package/node_modules/@agents-can-communicate/adapter-claude-code/src/adapter.mjs +1 -0
- package/node_modules/@agents-can-communicate/adapter-claude-code/src/install.mjs +16 -5
- package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-codex/plugin/skills/acc/SKILL.md +29 -5
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/gemini-extension.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/skills/acc/SKILL.md +29 -5
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-grok/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-grok/plugin/skills/acc/SKILL.md +29 -5
- package/node_modules/@agents-can-communicate/adapter-grok/src/adapter.mjs +4 -0
- package/node_modules/@agents-can-communicate/adapter-grok/src/indicator-install.mjs +30 -0
- package/node_modules/@agents-can-communicate/adapter-grok/src/indicator.mjs +23 -0
- package/node_modules/@agents-can-communicate/adapter-grok/src/install.mjs +9 -5
- package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-kimi/plugin/skills/acc/SKILL.md +29 -5
- package/node_modules/@agents-can-communicate/adapter-kimi/src/adapter.mjs +4 -0
- package/node_modules/@agents-can-communicate/adapter-kimi/src/indicator-install.mjs +30 -0
- package/node_modules/@agents-can-communicate/adapter-kimi/src/indicator.mjs +17 -0
- package/node_modules/@agents-can-communicate/adapter-kimi/src/install.mjs +12 -6
- package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-sdk/src/hook-shim.mjs +1 -0
- package/node_modules/@agents-can-communicate/adapter-sdk/src/index.mjs +5 -1
- package/node_modules/@agents-can-communicate/adapter-sdk/src/indicator-command.mjs +14 -0
- package/node_modules/@agents-can-communicate/adapter-sdk/src/indicator-text.mjs +13 -0
- package/node_modules/@agents-can-communicate/adapter-sdk/src/native-attempt-writer.mjs +1 -1
- package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation-order.mjs +12 -0
- package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation-writer.mjs +37 -0
- package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation.mjs +47 -0
- package/node_modules/@agents-can-communicate/adapter-sdk/src/process-table.mjs +40 -27
- package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-indicator.mjs +141 -0
- package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-scan.mjs +99 -0
- package/node_modules/@agents-can-communicate/cli/package.json +8 -1
- package/node_modules/@agents-can-communicate/cli/src/adapter-catalog.mjs +33 -0
- package/node_modules/@agents-can-communicate/cli/src/args.mjs +5 -3
- package/node_modules/@agents-can-communicate/cli/src/claim-command.mjs +64 -0
- package/node_modules/@agents-can-communicate/cli/src/help.mjs +17 -11
- package/node_modules/@agents-can-communicate/cli/src/index.mjs +1 -0
- package/node_modules/@agents-can-communicate/cli/src/indicator-command.mjs +65 -0
- package/node_modules/@agents-can-communicate/cli/src/indicator-previous-command.mjs +84 -0
- package/node_modules/@agents-can-communicate/cli/src/indicator-previous-windows.mjs +8 -0
- package/node_modules/@agents-can-communicate/cli/src/indicator.mjs +112 -0
- package/node_modules/@agents-can-communicate/cli/src/install-command.mjs +4 -0
- package/node_modules/@agents-can-communicate/cli/src/main.mjs +38 -110
- package/node_modules/@agents-can-communicate/cli/src/managed-runtime/entry.mjs +19 -0
- package/node_modules/@agents-can-communicate/cli/src/managed-runtime/launchers.mjs +5 -3
- package/node_modules/@agents-can-communicate/cli/src/native-session-diagnostics.mjs +1 -1
- package/node_modules/@agents-can-communicate/cli/src/recorded-text.mjs +32 -0
- package/node_modules/@agents-can-communicate/core/package.json +1 -1
- package/node_modules/@agents-can-communicate/core/src/claim-selectors.mjs +62 -0
- package/node_modules/@agents-can-communicate/core/src/claims.mjs +88 -81
- package/node_modules/@agents-can-communicate/core/src/next-turn-delivery.mjs +2 -1
- package/node_modules/@agents-can-communicate/core/src/sessions.mjs +5 -2
- package/node_modules/@agents-can-communicate/core/src/sync.mjs +2 -1
- package/node_modules/@agents-can-communicate/delivery-router/package.json +1 -1
- package/node_modules/@agents-can-communicate/delivery-router/src/router.mjs +19 -7
- package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
- package/node_modules/@agents-can-communicate/hook-runner/src/client-pid.mjs +23 -11
- package/node_modules/@agents-can-communicate/hook-runner/src/runner.mjs +66 -26
- package/node_modules/@agents-can-communicate/installer/package.json +3 -2
- package/node_modules/@agents-can-communicate/installer/src/apply.mjs +3 -0
- package/node_modules/@agents-can-communicate/installer/src/ownership.mjs +2 -1
- package/node_modules/@agents-can-communicate/installer/src/plan.mjs +11 -2
- package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
- package/node_modules/@agents-can-communicate/mcp-server/src/claim-tools.mjs +56 -0
- package/node_modules/@agents-can-communicate/mcp-server/src/input-validator.mjs +9 -0
- package/node_modules/@agents-can-communicate/mcp-server/src/server.mjs +7 -8
- package/node_modules/@agents-can-communicate/mcp-server/src/tools.mjs +27 -9
- package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
- package/node_modules/@agents-can-communicate/protocol/src/index.mjs +1 -0
- package/node_modules/@agents-can-communicate/storage-filesystem/package.json +3 -2
- package/node_modules/@agents-can-communicate/storage-filesystem/src/index.mjs +1 -1
- package/node_modules/@agents-can-communicate/storage-filesystem/src/session-read.mjs +13 -0
- package/node_modules/@agents-can-communicate/storage-filesystem/src/state-reads.mjs +24 -7
- package/package.json +3 -1
|
@@ -121,7 +121,7 @@ async function saveOwnership({ dataHome, record }) {
|
|
|
121
121
|
*/
|
|
122
122
|
export async function recordInstall({ dataHome, adapterId, version, accVersion = null,
|
|
123
123
|
artifacts, createdDirectories = [], deliveryPolicy, deliveryDecision,
|
|
124
|
-
nativeActivation = null }) {
|
|
124
|
+
nativeActivation = null, indicator }) {
|
|
125
125
|
const stamped = await Promise.all(artifacts.map(async artifact => ({
|
|
126
126
|
path: artifact.path,
|
|
127
127
|
kind: artifact.kind ?? "file",
|
|
@@ -141,6 +141,7 @@ export async function recordInstall({ dataHome, adapterId, version, accVersion =
|
|
|
141
141
|
{ adapterId, version, accVersion, artifacts: stamped,
|
|
142
142
|
...(directories.length === 0 ? {} : { createdDirectories: directories }),
|
|
143
143
|
...(deliveryPolicy === undefined ? {} : { deliveryPolicy }),
|
|
144
|
+
...(indicator === undefined ? {} : { indicator }),
|
|
144
145
|
...(retainedDeliveryDecision === undefined ? {} : {
|
|
145
146
|
deliveryDecision: retainedDeliveryDecision,
|
|
146
147
|
}),
|
|
@@ -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
|
|
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]),
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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: {
|
|
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
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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",
|
|
@@ -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,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agents-can-communicate/storage-filesystem",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
|
-
".": "./src/index.mjs"
|
|
7
|
+
".": "./src/index.mjs",
|
|
8
|
+
"./writer-mutex": "./src/writer-mutex.mjs"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"src/"
|
|
@@ -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
|
+
}
|
|
@@ -19,14 +19,31 @@ export async function readStateEnvelope(paths, { root, workspaceId }, kind, id)
|
|
|
19
19
|
return envelope;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// How many records of one kind are read at once. One at a time, a turn spent
|
|
23
|
+
// 0.4 s reading a workspace of a few thousand records; sixteen read it in 0.15 s
|
|
24
|
+
// on the same Mac (#298). The order of the listing is kept.
|
|
25
|
+
const LIST_READS = 16;
|
|
26
|
+
|
|
22
27
|
export async function listState(paths, root, kind, deadlineAt) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const files = await listJsonFiles(path.join(paths.state, kind), { root });
|
|
29
|
+
const envelopes = new Array(files.length).fill(null);
|
|
30
|
+
let next = 0;
|
|
31
|
+
let failed = false;
|
|
32
|
+
const reader = async () => {
|
|
33
|
+
while (!failed && next < files.length) {
|
|
34
|
+
const index = next++;
|
|
35
|
+
try {
|
|
36
|
+
assertPublicationDeadline(deadlineAt);
|
|
37
|
+
envelopes[index] = await readStateEnvelope(paths, { root }, kind,
|
|
38
|
+
path.basename(files[index], ".json"));
|
|
39
|
+
} catch (error) {
|
|
40
|
+
failed = true;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
await Promise.all(Array.from({ length: Math.min(LIST_READS, files.length) }, reader));
|
|
46
|
+
return envelopes.filter(envelope => envelope !== null);
|
|
30
47
|
}
|
|
31
48
|
|
|
32
49
|
export async function loadStateEnvelopes(paths, { root, deadlineAt }, wanted = null) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents-can-communicate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
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",
|