@chatpanel/events 0.101.0 → 0.102.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 +1 -1
- package/package.json +1 -1
- package/team-org.js +99 -5
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, soloTeam, teamsWithSolos, SOLO_BUDGET, 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, builtinOrg, isBuiltin, grantChoices, grantsFromChoices, skillChoices, GRANT_INFO, 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.
|
|
3
|
+
"version": "0.102.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/team-org.js
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
// Nothing here renders. A client maps `columns` to boxes and arrows, `hue` to a colour, and
|
|
14
14
|
// `kind` to a word; the SVG is its own.
|
|
15
15
|
|
|
16
|
-
import { normalizeTeam, validateTeam, starterTeams, TeamError } from './team.js';
|
|
17
|
-
import { normalizeAgent, engineOf, starterAgents, STARTER_AGENTS, ASSISTANT_ID } from './agent.js';
|
|
16
|
+
import { normalizeTeam, validateTeam, starterTeams, TeamError, GRANT_RE } from './team.js';
|
|
17
|
+
import { normalizeAgent, engineOf, starterAgents, assistantAgent, STARTER_AGENTS, ASSISTANT_ID } from './agent.js';
|
|
18
18
|
|
|
19
19
|
const isRecord = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
20
20
|
const poolList = (pool) => (Array.isArray(pool) ? pool : []).filter((a) => a && a.id);
|
|
@@ -320,7 +320,7 @@ export function upsertAgents(pool, cards) {
|
|
|
320
320
|
export const SOLO_BUDGET = Object.freeze({ tokens: 40000, ms: 300000 });
|
|
321
321
|
export function soloTeam(agent, { budget = SOLO_BUDGET } = {}) {
|
|
322
322
|
const a = agent && agent.id ? agent : null;
|
|
323
|
-
if (!a || a.
|
|
323
|
+
if (!a || a.enabled === false) return null;
|
|
324
324
|
return normalizeTeam({
|
|
325
325
|
name: String(a.id).toLowerCase(),
|
|
326
326
|
description: `Just ${a.name || a.id}${a.purpose ? ` — ${a.purpose}` : ''}`,
|
|
@@ -331,18 +331,112 @@ export function soloTeam(agent, { budget = SOLO_BUDGET } = {}) {
|
|
|
331
331
|
});
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
|
|
334
335
|
/**
|
|
335
336
|
* The teams a chat can run: the saved ones, then a solo team per enabled pool agent whose
|
|
336
337
|
* id no saved team already claims. What the slash menu, the `team` tool and "run …" all read.
|
|
337
338
|
*/
|
|
338
339
|
export function teamsWithSolos(teams = [], pool = [], opts = {}) {
|
|
339
|
-
const
|
|
340
|
+
const org = builtinOrg(teams, pool);
|
|
341
|
+
const saved = org.teams;
|
|
340
342
|
const taken = new Set(saved.map((t) => String(t.name).toLowerCase()));
|
|
341
343
|
const solos = [];
|
|
342
|
-
for (const a of
|
|
344
|
+
for (const a of org.pool) {
|
|
343
345
|
if (taken.has(String(a.id).toLowerCase()) || !(Array.isArray(a.appliesTo) ? a.appliesTo : ['jobs']).includes('jobs')) continue;
|
|
344
346
|
const t = soloTeam(a, opts);
|
|
345
347
|
if (t) { solos.push(t); taken.add(t.name); }
|
|
346
348
|
}
|
|
349
|
+
// The Assistant too: `/assistant <request>` runs the chat's own model as a one-role team —
|
|
350
|
+
// on the board, on a scorecard — where a plain turn is neither.
|
|
351
|
+
if (!taken.has(ASSISTANT_ID)) { const t = soloTeam(assistantAgent(), opts); if (t) solos.push({ ...t, builtin: true }); }
|
|
347
352
|
return [...saved, ...solos];
|
|
348
353
|
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* THE BUILT-IN ORG — the standing agents and the starter teams ship with the product, present
|
|
357
|
+
* and runnable without a click (the mock's "built-in" chips), and DERIVED, never stored: the
|
|
358
|
+
* `agents` and `teams` sections hold only what a person made, edited or switched off. A saved
|
|
359
|
+
* record with a built-in's id or name REPLACES it (an edit, or `enabled: false`), so the
|
|
360
|
+
* sections stay small and a product update reaches every unedited built-in.
|
|
361
|
+
*
|
|
362
|
+
* • every starter team a person has not saved is here, promoted (its roles as cards) and
|
|
363
|
+
* marked `builtin`, with the cards it stands on;
|
|
364
|
+
* • every starter agent not in the pool is here, marked `builtin`;
|
|
365
|
+
* • the Assistant stays the fixed card it is (agent.js assistantAgent).
|
|
366
|
+
* Returns `{ teams, pool }` — what every list, the slash menu and the runner read.
|
|
367
|
+
*/
|
|
368
|
+
export function builtinOrg(teams = [], pool = []) {
|
|
369
|
+
const savedTeams = (Array.isArray(teams) ? teams : []).filter((t) => t && t.name);
|
|
370
|
+
const savedNames = new Set(savedTeams.map((t) => String(t.name).toLowerCase()));
|
|
371
|
+
const outPool = [...poolList(pool)];
|
|
372
|
+
const have = () => new Set(outPool.map((a) => String(a.id)));
|
|
373
|
+
const outTeams = [...savedTeams];
|
|
374
|
+
for (const st of starterTeams()) {
|
|
375
|
+
if (savedNames.has(st.name)) continue;
|
|
376
|
+
const { team, agents } = starterTeam(st.name, outPool, { now: () => 0 });
|
|
377
|
+
outTeams.push({ ...team, builtin: true });
|
|
378
|
+
const ids = have();
|
|
379
|
+
for (const a of agents) if (!ids.has(a.id)) { const { createdAt, ...card } = a; outPool.push({ ...card, builtin: true }); }
|
|
380
|
+
}
|
|
381
|
+
const ids = have();
|
|
382
|
+
for (const a of starterAgents()) if (!ids.has(a.id)) outPool.push({ ...a, builtin: true });
|
|
383
|
+
return { teams: outTeams, pool: outPool };
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/** Is this record the product's, not a person's — drawn with the built-in chip, toggled rather than deleted. */
|
|
387
|
+
export const isBuiltin = (rec) => !!rec?.builtin;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* The GRANTS a person can give, as choices — not a free field of ids nobody has seen. Grouped
|
|
391
|
+
* the way they read: what the agent may reach, which connected servers, what work it may do
|
|
392
|
+
* (only an agent-tool engine can use those). `servers` are the connected MCP servers
|
|
393
|
+
* (`{ id, name? }`), each its own `mcp:<id>` choice under the umbrella `mcp`.
|
|
394
|
+
*/
|
|
395
|
+
export const GRANT_INFO = Object.freeze({
|
|
396
|
+
data: ['Your data', 'notes, meetings and past chats — search and read'],
|
|
397
|
+
web: ['Web', 'search the web and fetch pages'],
|
|
398
|
+
history: ['Chat history', 'search past chats only'],
|
|
399
|
+
mcp: ['Every connected server', 'all MCP servers you connected; pick servers below to narrow'],
|
|
400
|
+
shell: ['Run commands', 'a shell in its working directory'],
|
|
401
|
+
'fs:write': ['Write files', 'edit files in its working directory'],
|
|
402
|
+
'scm:read': ['Read the repository', 'the checkout and its hub'],
|
|
403
|
+
'scm:push': ['Push its branch', 'its own cp/<project>/<job> branch, never main'],
|
|
404
|
+
'scm:pr': ['Open a pull request', ''],
|
|
405
|
+
'scm:merge': ['Merge', 'only where the org\'s gate allows it'],
|
|
406
|
+
});
|
|
407
|
+
export function grantChoices({ servers = [] } = {}) {
|
|
408
|
+
const item = (id) => ({ id, label: GRANT_INFO[id]?.[0] || id, hint: GRANT_INFO[id]?.[1] || '' });
|
|
409
|
+
const groups = [
|
|
410
|
+
{ id: 'reach', label: 'May reach', items: ['data', 'web', 'history', 'mcp'].map(item) },
|
|
411
|
+
];
|
|
412
|
+
const srv = (Array.isArray(servers) ? servers : []).filter((s) => s && s.id);
|
|
413
|
+
if (srv.length) groups.push({ id: 'servers', label: 'Connected servers', items: srv.map((s) => ({ id: `mcp:${s.id}`, label: s.name || s.id, hint: 'this server only' })) });
|
|
414
|
+
groups.push({ id: 'work', label: 'May do (agent-tool engines only)', items: ['shell', 'fs:write', 'scm:read', 'scm:push', 'scm:pr', 'scm:merge'].map(item) });
|
|
415
|
+
return groups;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Grants from checked ids: nothing checked is `none`; `mcp` swallows the per-server picks. */
|
|
419
|
+
export function grantsFromChoices(checked = []) {
|
|
420
|
+
const set = new Set((Array.isArray(checked) ? checked : []).filter((g) => g && g !== 'none' && GRANT_RE.test(String(g))));
|
|
421
|
+
if (set.has('mcp')) for (const g of [...set]) if (g.startsWith('mcp:')) set.delete(g);
|
|
422
|
+
return set.size ? [...set] : ['none'];
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* The SKILLS a person can attach, from the skills they have: the shared `skills` section
|
|
427
|
+
* (written or installed, `{ command, name?, description?, enabled? }`) and any names an
|
|
428
|
+
* agent already carries that are not there (kept, marked `missing`, so a card never loses a
|
|
429
|
+
* skill the list forgot). A skill's id is its command — what `skill_open` and `fit` match on.
|
|
430
|
+
*/
|
|
431
|
+
export function skillChoices(skills = [], { current = [] } = {}) {
|
|
432
|
+
const out = [];
|
|
433
|
+
const seen = new Set();
|
|
434
|
+
for (const s of Array.isArray(skills) ? skills : []) {
|
|
435
|
+
const id = String(s?.command || s?.name || '').trim();
|
|
436
|
+
if (!id || seen.has(id) || s?.enabled === false) continue;
|
|
437
|
+
seen.add(id);
|
|
438
|
+
out.push({ id, label: s.name && s.name !== id ? `${s.name} (/${id})` : `/${id}`, hint: String(s.description || '').slice(0, 120) });
|
|
439
|
+
}
|
|
440
|
+
for (const id of Array.isArray(current) ? current : []) if (id && !seen.has(id)) { seen.add(id); out.push({ id, label: id, hint: 'not among your skills now', missing: true }); }
|
|
441
|
+
return out;
|
|
442
|
+
}
|