agents-can-communicate 0.1.10 → 0.1.11

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-claude-code",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-codex",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -68,8 +68,10 @@ export function createCodexAdapter() {
68
68
  "write guards cover apply_patch and the shell writes ACC can read; a model "
69
69
  + "without apply_patch edits through the shell, where a redirection or an "
70
70
  + "mv is matched and a runtime opening the file is not",
71
- "Codex requires hooks to be trusted before they run; an untrusted plugin is "
72
- + "installed but inert",
71
+ // Was a standing sentence here, true and useless: it said the same
72
+ // thing on a machine whose hooks were trusted, on one whose were not,
73
+ // and on one with nothing installed. Detection reads the client's own
74
+ // record now and speaks only when it has something to report.
73
75
  ],
74
76
  };
75
77
  },
@@ -238,33 +238,6 @@ async function removeEmptyDirs(directories) {
238
238
  }
239
239
  }
240
240
 
241
- /**
242
- * Drop the client's trust record for hooks that are about to stop existing.
243
- *
244
- * Scoped to tables whose key begins with ACC's own `plugin@marketplace:` - a
245
- * table belonging to any other plugin is the client's business and stays. The
246
- * file is rewritten only when something was found, so an install that never ran
247
- * here leaves the config byte for byte as it was.
248
- */
249
- export async function removeHookTrust(file, prefix) {
250
- const before = await readFile(file, "utf8").catch(() => null);
251
- if (before === null || !before.includes(`hooks.state."${prefix}`)) return false;
252
-
253
- const lines = before.split("\n");
254
- const kept = [];
255
- let dropping = false;
256
- for (const line of lines) {
257
- const header = /^\s*\[([^\]]*)\]\s*$/.exec(line);
258
- if (header !== null) dropping = header[1].startsWith(`hooks.state."${prefix}`);
259
- if (dropping) continue;
260
- kept.push(line);
261
- }
262
- // A table's trailing blank line goes with it rather than piling up.
263
- const text = kept.join("\n").replace(/\n{3,}/g, "\n\n");
264
- if (text === before) return false;
265
- await writeFile(file, text, "utf8");
266
- return true;
267
- }
268
241
 
269
242
  export async function uninstallCodexPlugin({ home, agentsHome = home,
270
243
  codexHome = path.join(home, ".codex"), keep = [] }) {
@@ -277,15 +250,18 @@ export async function uninstallCodexPlugin({ home, agentsHome = home,
277
250
  await writeMarketplace(file, { ...existing, plugins: kept });
278
251
  }
279
252
  if (await removeTomlBlock(configPath(codexHome))) changes.push(configPath(codexHome));
280
- // This client keeps its own record of which hook files it has trusted, one
281
- // table per hook, keyed by the plugin that declared them. ACC never writes
282
- // those - they are the client's bookkeeping about ACC - but once the plugin is
283
- // gone they name a thing that does not exist, five of them per install, and
284
- // nothing else will ever clear them. Verified inert first: a hook whose hash
285
- // no longer matches still runs, so this is tidiness rather than repair.
286
- if (await removeHookTrust(configPath(codexHome), `${PLUGIN_NAME}@${MARKETPLACE}:`)) {
287
- if (!changes.includes(configPath(codexHome))) changes.push(configPath(codexHome));
288
- }
253
+ // The client's `[hooks.state."<plugin>:…"]` tables stay. 0.1.9 removed them as
254
+ // litter naming a plugin that was gone; that was wrong, and wrong in a way
255
+ // worth writing down. The check behind it perturbed the record - a hook whose
256
+ // recorded hash no longer *matched* was seen still running - and concluded the
257
+ // record was inert. Absence was never tested, and absence is what matters:
258
+ // with the tables gone this client runs no hook at all, prints
259
+ // `hook: SessionStart Completed` while executing nothing, and ACC's write
260
+ // guard is silently off while `acc doctor` reports the adapter installed.
261
+ //
262
+ // The record is granted once, by a person, and survives ACC upgrades - hashes
263
+ // captured under 0.1.6 still admitted 0.1.10's hooks. Nothing ACC writes can
264
+ // put it back. So it is not ACC's to remove.
289
265
  // The marketplace directory is ACC's too, so it goes rather than being left
290
266
  // behind empty.
291
267
  // A blank TOML config and an absent one are the same to this client, and a
@@ -328,6 +304,13 @@ export async function detectCodex({ home, agentsHome = home,
328
304
  const enabled = config.includes(`[plugins."${QUALIFIED}"]`);
329
305
  const cached = await stat(cachePath(codexHome))
330
306
  .then(() => true).catch(() => false);
307
+ // The condition that decides whether ACC runs here at all, and the only one
308
+ // this client will not tell you about: with no trust record it runs no hook,
309
+ // prints `hook: SessionStart Completed`, and executes nothing. Everything else
310
+ // - published, registered, enabled, cached - can be true while the write guard
311
+ // is off. Only asked when something is wired: a warning about hooks that do
312
+ // not exist is how a real one gets ignored.
313
+ const untrusted = cached && !config.includes(`hooks.state."${QUALIFIED}:`);
331
314
  return { ok: true, changes: [], diagnostics: [
332
315
  published ? "acc plugin published in the marketplace" : "acc plugin not registered",
333
316
  registered && enabled
@@ -339,7 +322,25 @@ export async function detectCodex({ home, agentsHome = home,
339
322
  cached
340
323
  ? "plugin installed in the client's cache"
341
324
  : `plugin not installed yet; run: codex plugin add ${QUALIFIED}`,
342
- ] };
325
+ // The condition that decides whether ACC runs here at all, and the only one
326
+ // this client will not tell you about: with no trust record it runs no hook,
327
+ // prints `hook: SessionStart Completed`, and executes nothing. Everything
328
+ // else - published, registered, enabled, cached - can be true while the
329
+ // write guard is off. Said only when there is something to trust, because a
330
+ // warning on a machine with nothing wired is how a real one gets ignored.
331
+ ...(untrusted
332
+ ? ["hooks are not trusted, so this client reports them completed and runs "
333
+ + "nothing"]
334
+ : []),
335
+ ],
336
+ // Said as an action rather than an observation, because a person has to do it
337
+ // and no acc command can: the client grants this once, from its own prompt.
338
+ // A diagnostic alone would have stayed in `--json`, which is where the first
339
+ // version of this fix put it and where nobody would have read it.
340
+ needsAction: untrusted
341
+ ? ["start codex once and accept the hook trust prompt "
342
+ + "# its hooks run nothing until then"]
343
+ : [] };
343
344
  }
344
345
 
345
346
  /**
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-gemini-cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-kimi",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-sdk",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -130,6 +130,9 @@ async function diagnoseAdapters({ options, runtime }) {
130
130
  if (owned.missing.length > 0) {
131
131
  remediation.push(`acc install --adapter ${entry.adapterId} # files are missing`);
132
132
  }
133
+ // An adapter can name something only a person can do - the client's own
134
+ // trust prompt, most of all. It goes where a person reads, not into --json.
135
+ remediation.push(...(entry.needsAction ?? []));
133
136
  const installed = record.installs.find(one => one.adapterId === entry.adapterId);
134
137
  const stale = staleInstall({ recorded: installed?.accVersion ?? null, running });
135
138
  if (stale !== null) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/core",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/hook-runner",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/installer",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": { ".": "./src/index.mjs" },
@@ -44,7 +44,8 @@ export async function detectInstallation({ adapters, context, probe = spawnProbe
44
44
  .map(async adapter => {
45
45
  const entry = { adapterId: adapter.id, displayName: adapter.displayName,
46
46
  present: false, version: null, versionOutput: null, installed: false,
47
- diagnostics: [], capabilities: adapter.capabilities ?? {}, error: null };
47
+ diagnostics: [], needsAction: [], capabilities: adapter.capabilities ?? {},
48
+ error: null };
48
49
 
49
50
  try {
50
51
  const output = await withTimeout(
@@ -65,6 +66,9 @@ export async function detectInstallation({ adapters, context, probe = spawnProbe
65
66
  try {
66
67
  const detected = await adapter.detect(context);
67
68
  entry.diagnostics = detected.diagnostics ?? [];
69
+ // What a person has to do, as opposed to what is true. Adapters that
70
+ // have nothing to ask for say nothing.
71
+ entry.needsAction = detected.needsAction ?? [];
68
72
  // "Installed" is the adapter's own answer, phrased in its own terms.
69
73
  // The installer does not second-guess it by looking at files it does
70
74
  // not understand.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/mcp-server",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/protocol",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/storage-filesystem",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-can-communicate",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "type": "module",
5
5
  "description": "Local-first coordination for independently opened AI agent sessions.",
6
6
  "keywords": [