@chatpanel/events 0.75.0 โ†’ 0.76.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
@@ -213,7 +213,7 @@ export { SOURCE_TRUST, SkillSourceError, defineSkillSource, createSkillSourceReg
213
213
  export { SKILL_MANIFEST_VERSION, SKILL_CONTEXTS, SKILL_HISTORY_SCOPES, SKILL_MCP_MODES, SKILL_TRUST, SKILL_FILE_KINDS, SKILL_UPCASTERS, SkillManifestError, isSafeSkillPath, originOf, trustOf, skillFiles, needsBridge, declaredAccess, originLabel, sameSkillOrigin, skillIsStale, validateSkill, upcastSkill, upcastSkills, normalizeSkill } from './skill-manifest.js';
214
214
  export { SKILL_VARS, SKILL_VAR_NAMES, skillVar, skillVarPattern, parseSkillVars, lintSkillPrompt, suggestSkillVar, substituteSkillVars, expandSkillPrompt, skillVarGuidance, SkillVarError } from './skill-vars.js';
215
215
  export { lineAt, writerAffordance, INSTRUCTION_RE, instructionOnLine, GOAL_MIN_NEW, goalDraftAllowed, createSpendMeter, writerTail, draftSeparator, groundingBlock, writerRequest, AUTOCOMPLETE_SYSTEM, AUTOCOMPLETE_MAX_TOKENS, AUTOCOMPLETE_TEMPERATURE, clipCompletion, GEARS, WRITER_PREFS, WRITER_PREF_DEFAULTS, normalizeWriterPrefs, normalizeIntent } from './cowriter-writer.js';
216
- export { SLASH_TYPING_RE, enabledSkills, slashCommandItems, matchSlashSkill, matchSlashRecipe, recipeInvocationText, slashCommandInsert, skillInvocationOf, skillInvocationLabel } from './slash-commands.js';
216
+ export { SLASH_TYPING_RE, enabledSkills, slashCommandItems, matchSlashSkill, matchSlashRecipe, recipeInvocationText, matchSlashTeam, teamInvocationText, slashCommandInsert, skillInvocationOf, skillInvocationLabel } from './slash-commands.js';
217
217
  export { outlineOf, parseListItem, continueList, indentSelection, toggleWrap, toggleLinePrefix, toggleTask, toggleLink, docStats, selectionStats } from './markdown-authoring.js';
218
218
  export {
219
219
  MAX_TAG_LENGTH, MAX_TAGS, normalizeTag, normalizeTags, hasTag, addTag, removeTag, toggleTag,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/events",
3
- "version": "0.75.0",
3
+ "version": "0.76.0",
4
4
  "description": "The canonical ChatPanel event-log and capability contracts \u2014 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
@@ -37,6 +37,12 @@ function recipeItem(recipe) {
37
37
  return { type: 'recipe', command: recipe.name || '', icon: '๐Ÿงฉ', description: recipe.description || 'Saved recipe', recipe };
38
38
  }
39
39
 
40
+ // A saved TEAM answers to a slash the same way: `/research <request>` is a request to run
41
+ // it, and the `team` tool does the rest.
42
+ function teamItem(team) {
43
+ return { type: 'team', command: team.name || '', icon: '๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘', description: team.description || 'Agent team', team };
44
+ }
45
+
40
46
  /** Skills that are switched on. Absence of the flag means enabled (older records have none). */
41
47
  export function enabledSkills(skills) {
42
48
  return (Array.isArray(skills) ? skills : []).filter((s) => !!s && s.enabled !== false);
@@ -58,6 +64,7 @@ export function slashCommandItems({
58
64
  builtins = [],
59
65
  skills = [],
60
66
  recipes = [],
67
+ teams = [],
61
68
  prefix = '',
62
69
  skillsAllowed = false,
63
70
  features = {},
@@ -70,7 +77,8 @@ export function slashCommandItems({
70
77
  }));
71
78
  const skillItems = skillsAllowed ? enabledSkills(skills).map(skillItem) : [];
72
79
  const recipeItems = (recipes || []).filter((r) => r && r.enabled !== false && r.name).map(recipeItem);
73
- return [...own, ...skillItems, ...recipeItems]
80
+ const teamItems = (teams || []).filter((t) => t && t.enabled !== false && t.name).map(teamItem);
81
+ return [...own, ...skillItems, ...recipeItems, ...teamItems]
74
82
  .filter((item) => item.command && item.command.toLowerCase().startsWith(normalized))
75
83
  .slice(0, 12);
76
84
  }
@@ -100,6 +108,20 @@ export function recipeInvocationText(recipe, args = '') {
100
108
  return `Run the saved recipe "${recipe.name}"${a ? ` with this input: ${a}` : ''}. Use the recipe tool; if a parameter is missing, ask for it.`;
101
109
  }
102
110
 
111
+ /** "/research compare A and B" โ†’ the team, and the rest of the line as its request. */
112
+ export function matchSlashTeam(text, teams = []) {
113
+ const m = /^\/([a-z0-9_-]+)\s*([\s\S]*)$/i.exec(String(text || ''));
114
+ if (!m) return null;
115
+ const team = (teams || []).find((t) => t && t.enabled !== false && String(t.name || '').toLowerCase() === m[1].toLowerCase());
116
+ return team ? { team, args: m[2].trim() } : null;
117
+ }
118
+
119
+ /** What the model receives for a team command: a request to run it, never a prompt expansion. */
120
+ export function teamInvocationText(team, args = '') {
121
+ const a = String(args || '').trim();
122
+ return `Run the saved team "${team.name}"${a ? ` on this request: ${a}` : ''}. Use the team tool; if the request is unclear, ask first.`;
123
+ }
124
+
103
125
  export function slashCommandInsert(item) {
104
126
  return item?.command ? `/${item.command} ` : '/';
105
127
  }
package/team-run.js CHANGED
@@ -48,7 +48,9 @@ export function dryRunTeam(team, request, { appoint = null } = {}) {
48
48
  const t = normalizeTeam(team);
49
49
  const roles = t.roles.map((r) => {
50
50
  const a = appoint ? appoint(r) : null;
51
- return { id: r.id, name: r.name, mode: r.mode, prefer: r.prefer, model: a?.model || r.model || null, appointed: !!(a?.model || r.model), grants: r.grants, ...(r.recipe ? { recipe: r.recipe } : {}) };
51
+ // `model` is what callModel will be handed (a target id in a client that resolves ids);
52
+ // `label` is what a person should read โ€” the appointer says which, when it knows.
53
+ return { id: r.id, name: r.name, mode: r.mode, prefer: r.prefer, model: a?.model || r.model || null, label: a?.label || a?.model || r.model || null, appointed: !!(a?.model || r.model), grants: r.grants, ...(r.recipe ? { recipe: r.recipe } : {}) };
52
54
  });
53
55
  const missing = roles.filter((r) => r.mode !== 'recipe' && !r.appointed).map((r) => r.id);
54
56
  return {
@@ -137,9 +139,11 @@ export async function runTeam({
137
139
  if (!budget.canAfford({ tokens: 0 })) { overBudget = true; throw new Error('over budget'); }
138
140
  const prior = boardText(board.all(), { taskIds: task.dependsOn?.length ? task.dependsOn : null });
139
141
  const prompt = [task.prompt, prior, findingsInstruction()].filter(Boolean).join('\n\n');
142
+ // A host may build a toolset asynchronously (connecting MCP servers takes time).
143
+ const tools = await toolsFor(role);
140
144
  const res = await callModel({
141
145
  runId: id, taskId: task.id, role: role.id, model: m.model, mode: m.mode || role.mode,
142
- system: role.prompt, prompt, tools: toolsFor(role), signal,
146
+ system: role.prompt, prompt, tools, signal,
143
147
  onDelta: (delta, full) => say('task.delta', { taskId: task.id, role: role.id, delta, text: full }),
144
148
  });
145
149
  usage = res?.usage || null;
package/team-tool.js CHANGED
@@ -49,7 +49,7 @@ export function teamToolSpec(teams) {
49
49
  /** The card a person approves a new team on. */
50
50
  export function describeTeamForApproval(team, dry) {
51
51
  const lines = [`${team.name}${team.description ? ` โ€” ${team.description}` : ''}`, `Plan: ${team.plan || 'fixed'} ยท merge: ${team.merge || 'concat'}${team.judge ? ` (judge: ${team.judge})` : ''}`];
52
- for (const r of dry?.roles || team.roles || []) lines.push(`โ€ข ${describeRole({ ...r, model: r.model || undefined })}${r.appointed === false ? ' โ€” NO MODEL AVAILABLE' : ''}`);
52
+ for (const r of dry?.roles || team.roles || []) lines.push(`โ€ข ${describeRole({ ...r, model: r.label || r.model || undefined })}${r.appointed === false ? ' โ€” NO MODEL AVAILABLE' : ''}`);
53
53
  const b = team.budget || {};
54
54
  lines.push(`Budget: ${Object.entries(b).map(([k, v]) => `${k} ${v}`).join(' ยท ')}`);
55
55
  lines.push('Runs go through your own models and tools; a team may not act on a page. Nothing a team produces lands without you.');