@chatpanel/events 0.100.0 → 0.101.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.
package/index.js CHANGED
@@ -238,7 +238,7 @@ export { workLogFor, workLogText, workLogEvidence, describeCall, WORKLOG_KINDS }
238
238
  export { normalizeRequest, subtaskFromRequest, takeUp, takeUpLine, holdsGrants, jobFromSubtask, extendDependents, taskTree, threadRows, MAX_SUBTASKS, MAX_DEPTH, MIN_TAKEUP_FIT } from './team-subtask.js';
239
239
  export { teamLine, teamLanes } from './team-trail.js';
240
240
  // The org, derived (F8 §17): roles as cards, starters whole, a team's health and shape, the roster, one colour per agent.
241
- export { promoteRoles, starterTeam, missingStarters, teamHealth, teamShape, describeTeamShape, whereItWorks, rosterRows, agentKind, agentHue, agentColor, agentInitials, roleCardId, cardNumbers, upsertAgents, TEAM_SHAPES, ROSTER_KINDS } from './team-org.js';
241
+ export { promoteRoles, starterTeam, missingStarters, teamHealth, teamShape, describeTeamShape, whereItWorks, rosterRows, agentKind, agentHue, agentColor, agentInitials, roleCardId, cardNumbers, upsertAgents, soloTeam, teamsWithSolos, SOLO_BUDGET, TEAM_SHAPES, ROSTER_KINDS } from './team-org.js';
242
242
  export { observeInbox, observeStrip, runLanes, spendRows, engineStrip } from './team-observe.js';
243
243
  export { mcpDispatchProvider, MCP_TOOL_NAME } from './mcp-dispatch.js';
244
244
  export { createManifest, ManifestError, SOURCES } from './manifest.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/events",
3
- "version": "0.100.0",
3
+ "version": "0.101.0",
4
4
  "description": "The canonical ChatPanel event-log and capability contracts — typed durable facts, clock-free deterministic linearization, schema upcasting, and the invariants the replay harness asserts. Pure, dependency-free ESM shared by the ChatPanel extension, gateway and bridge.",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/slash-commands.js CHANGED
@@ -40,7 +40,9 @@ function recipeItem(recipe) {
40
40
  // A saved TEAM answers to a slash the same way: `/research <request>` is a request to run
41
41
  // it, and the `team` tool does the rest.
42
42
  function teamItem(team) {
43
- return { type: 'team', command: team.name || '', icon: '🧑‍🤝‍🧑', description: team.description || 'Agent team', team };
43
+ // A solo team (team-org.js soloTeam) IS an agent, invokable on its own: drawn as one.
44
+ const solo = !!team.origin?.agent;
45
+ return { type: 'team', command: team.name || '', icon: solo ? '🧑‍💻' : '🧑‍🤝‍🧑', description: team.description || (solo ? 'Agent' : 'Agent team'), team, ...(solo ? { agent: team.origin.agent } : {}) };
44
46
  }
45
47
 
46
48
  /** Skills that are switched on. Absence of the flag means enabled (older records have none). */
@@ -119,6 +121,7 @@ export function matchSlashTeam(text, teams = []) {
119
121
  /** What the model receives for a team command: a request to run it, never a prompt expansion. */
120
122
  export function teamInvocationText(team, args = '') {
121
123
  const a = String(args || '').trim();
124
+ if (team.origin?.agent) return `Run the agent "${team.name}" (a one-role team of that name)${a ? ` on this request: ${a}` : ''}. Use the team tool; if the request is unclear, ask first.`;
122
125
  return `Run the saved team "${team.name}"${a ? ` on this request: ${a}` : ''}. Use the team tool; if the request is unclear, ask first.`;
123
126
  }
124
127
 
package/team-org.js CHANGED
@@ -309,3 +309,40 @@ export function upsertAgents(pool, cards) {
309
309
  const add = (Array.isArray(cards) ? cards : []).filter((c) => c && c.id);
310
310
  return [...list.map((a) => add.find((c) => c.id === a.id) || a), ...add.filter((c) => !list.some((a) => a.id === c.id))];
311
311
  }
312
+
313
+ /**
314
+ * An agent, INVOKABLE on its own: a one-role team named after it (`/researcher`, "ask the
315
+ * researcher to…"), the role standing for the card, the answer the role's own (`merge:
316
+ * first`), under a default budget since a team without one does not run (O1). `origin.agent`
317
+ * marks it so a client can draw it as an agent, not a team. Never stored — derived from the
318
+ * pool every time, so a card edit lands at once and a deleted card takes its command with it.
319
+ */
320
+ export const SOLO_BUDGET = Object.freeze({ tokens: 40000, ms: 300000 });
321
+ export function soloTeam(agent, { budget = SOLO_BUDGET } = {}) {
322
+ const a = agent && agent.id ? agent : null;
323
+ if (!a || a.id === ASSISTANT_ID || a.enabled === false) return null;
324
+ return normalizeTeam({
325
+ name: String(a.id).toLowerCase(),
326
+ description: `Just ${a.name || a.id}${a.purpose ? ` — ${a.purpose}` : ''}`,
327
+ plan: 'fixed', merge: 'first',
328
+ roles: [{ id: String(a.id).toLowerCase().slice(0, 32), agent: a.id }],
329
+ budget: { ...budget },
330
+ origin: { agent: a.id },
331
+ });
332
+ }
333
+
334
+ /**
335
+ * The teams a chat can run: the saved ones, then a solo team per enabled pool agent whose
336
+ * id no saved team already claims. What the slash menu, the `team` tool and "run …" all read.
337
+ */
338
+ export function teamsWithSolos(teams = [], pool = [], opts = {}) {
339
+ const saved = (Array.isArray(teams) ? teams : []).filter((t) => t && t.name);
340
+ const taken = new Set(saved.map((t) => String(t.name).toLowerCase()));
341
+ const solos = [];
342
+ for (const a of poolList(pool)) {
343
+ if (taken.has(String(a.id).toLowerCase()) || !(Array.isArray(a.appliesTo) ? a.appliesTo : ['jobs']).includes('jobs')) continue;
344
+ const t = soloTeam(a, opts);
345
+ if (t) { solos.push(t); taken.add(t.name); }
346
+ }
347
+ return [...saved, ...solos];
348
+ }