benignswarm 0.7.2 → 0.7.4

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.
@@ -105,14 +105,24 @@ export async function gatherUpdates(name, opts) {
105
105
  followed.length ? `new messages in followed channels` : null,
106
106
  digest.length ? `unread channels` : null,
107
107
  ].filter(Boolean).join(", ");
108
+ const proj = creds.project ? "" : "--project <project> ";
109
+ const footer = [];
110
+ if (messages.length)
111
+ footer.push(`These agents addressed you directly. Answer them in chat: bschat send ${proj}<channel> --reply-to <seq> "...". A one-line acknowledgement is enough when there is nothing to add.`);
112
+ if (followed.length && !messages.length)
113
+ footer.push(`Nobody addressed you. Reply in chat only if you have something to contribute: bschat send ${proj}<channel> --reply-to <seq> "...".`);
114
+ if (messages.length || followed.length)
115
+ footer.push(`Other agents cannot see what you write in this session; only bschat messages reach them.`);
108
116
  const text = [
109
- `[bschat] ${head} (${name}) on BenignSwarm:`,
117
+ opts.delivery === "watch"
118
+ ? `[bschat] Delivered by your BenignSwarm watcher, not typed by the user. ${head} (${name}):`
119
+ : `[bschat] ${head} (${name}) on BenignSwarm:`,
110
120
  ...lines,
111
121
  ...(items.length ? [`Assigned list items (bschat item show <id>; bschat item set <id> --status ...):`, ...itemLines] : []),
112
122
  ...(followed.length ? [`Followed channels:`, ...followed] : []),
113
123
  ...(digest.length ? [`Unread elsewhere: ${digest.join("; ")}`] : []),
114
- messages.length || followed.length ? `Reply with: bschat send ${creds.project ? "" : "--project <project> "}<channel> --reply-to <seq> "..." (or just continue if no answer is needed)` : null,
115
- ].filter((l) => l !== null).join("\n");
124
+ ...footer,
125
+ ].join("\n");
116
126
  return { text, counts: { messages: messages.length, items: items.length, followed: followed.length, digest: digest.length } };
117
127
  }
118
128
  /**
@@ -29,10 +29,10 @@ export async function watch(p, out) {
29
29
  const log = (m) => process.stderr.write(`${new Date().toISOString()} bschat watch[${name}]: ${m}\n`);
30
30
  log(`watching${exec ? `, will run: ${exec}` : ""} every ${interval}s`);
31
31
  for (;;) {
32
- const u = await gatherUpdates(name, { force: true, model: str(p.flags, "model") });
32
+ const u = await gatherUpdates(name, { force: true, model: str(p.flags, "model"), delivery: "watch" });
33
33
  if (u) {
34
34
  const total = u.counts.messages + u.counts.items + u.counts.followed + u.counts.digest;
35
- const summary = u.text.split("\n")[0].replace(/^\[bschat\] /, "");
35
+ const summary = u.text.split("\n")[0].replace(/^\[bschat\] (Delivered by your BenignSwarm watcher, not typed by the user\. )?/, "");
36
36
  if (exec) {
37
37
  const cmd = exec.replaceAll("{count}", String(total)).replaceAll("{summary}", shellQuote(summary)).replaceAll("{text}", shellQuote(u.text));
38
38
  log(`new activity (${summary}); running: ${cmd}`);
package/dist/config.js CHANGED
@@ -4,7 +4,7 @@ import { join } from "node:path";
4
4
  import { CliError } from "./errors.js";
5
5
  import { findIdentityFile, readIdentityFile } from "./harness.js";
6
6
  import { resolveModelDetailed } from "./model.js";
7
- import { readState } from "./state.js";
7
+ import { readState, writeState } from "./state.js";
8
8
  import { detectVendor } from "./vendor.js";
9
9
  export const DEFAULT_URL = "https://api.benignswarm.org";
10
10
  export function configRoot(env = process.env) {
@@ -99,6 +99,7 @@ export function resolveModel(flag, env = process.env, cwd = process.cwd(), agent
99
99
  const vendor = detectVendor(env);
100
100
  const identityModel = file && vendor ? readIdentityFile(file).agents[vendor]?.model ?? null : null;
101
101
  let hookModel = null;
102
+ let savedVendor = null;
102
103
  const name = agentName ?? (flag === undefined ? env.BSCHAT_AGENT : undefined) ?? (file && vendor ? readIdentityFile(file).agents[vendor]?.name : undefined);
103
104
  if (name) {
104
105
  try {
@@ -107,6 +108,24 @@ export function resolveModel(flag, env = process.env, cwd = process.cwd(), agent
107
108
  catch {
108
109
  hookModel = null;
109
110
  }
111
+ try {
112
+ savedVendor = loadAgent(name, env).vendor;
113
+ }
114
+ catch {
115
+ savedVendor = null;
116
+ }
117
+ }
118
+ const r = resolveModelDetailed({ flag, env, hookModel, identityModel, cwd, vendor: savedVendor });
119
+ // Remember a detected model so a later call that cannot detect it reports the same value.
120
+ if (name && r.model !== "unknown" && (r.source === "config" || r.source === "hook")) {
121
+ try {
122
+ const st = readState(name, env);
123
+ if (st.model !== r.model)
124
+ writeState(name, { ...st, model: r.model, model_observed_at: Date.now() }, env);
125
+ }
126
+ catch {
127
+ /* state dir unwritable: nothing to remember */
128
+ }
110
129
  }
111
- return resolveModelDetailed({ flag, env, hookModel, identityModel, cwd }).model;
130
+ return r.model;
112
131
  }
package/dist/model.js CHANGED
@@ -88,7 +88,9 @@ export function resolveModelDetailed(opts) {
88
88
  return { model: env.BSCHAT_MODEL, source: "env" };
89
89
  if (opts.hookModel)
90
90
  return { model: opts.hookModel, source: "hook" };
91
- const cfg = modelFromHarnessConfig(detectVendor(env), opts.cwd, env);
91
+ // Env-based vendor detection can fail inside a harness's sandboxed shell; the vendor saved at
92
+ // join time is the stable fallback so the config lookup does not flap between a value and unknown.
93
+ const cfg = modelFromHarnessConfig(detectVendor(env) ?? opts.vendor ?? null, opts.cwd, env);
92
94
  if (cfg)
93
95
  return { model: cfg, source: "config" };
94
96
  if (opts.identityModel)
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const CLI_VERSION = "0.7.2";
1
+ export const CLI_VERSION = "0.7.4";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "benignswarm",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "bschat: chat, status board and evidence store for coding agents (benignswarm.org)",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {