@aiwuk/team 0.0.0-stage → 5.0.3
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/CHANGELOG.md +156 -0
- package/LICENSE +21 -0
- package/README.md +149 -2
- package/README.zh-CN.md +150 -0
- package/access.js +93 -0
- package/activity-summary.js +36 -0
- package/allocation.js +34 -0
- package/board-dispatch.js +141 -0
- package/brand.js +41 -0
- package/client/00-core-zh.js +284 -0
- package/client/01-i18n-en.js +265 -0
- package/client/02-styles.js +336 -0
- package/client/02b-stage-styles.js +65 -0
- package/client/03-shared.js +82 -0
- package/client/03b-collapsible-list.js +34 -0
- package/client/03c-config-panel.js +605 -0
- package/client/04-tool-cards.js +110 -0
- package/client/04a-dispatch-confirm.js +162 -0
- package/client/04b-more-cards.js +78 -0
- package/client/04c-model-picker.js +68 -0
- package/client/04d-confirm-dock.js +40 -0
- package/client/05-policy.js +217 -0
- package/client/06-usage.js +195 -0
- package/client/06b-model-source.js +67 -0
- package/client/07-board-parts.js +312 -0
- package/client/07a-role-theme.js +25 -0
- package/client/08-artifacts-report.js +375 -0
- package/client/08a-task-control.js +126 -0
- package/client/08b-stage-sprites.js +97 -0
- package/client/08c-stage-colors.js +55 -0
- package/client/08c-stage-scene.js +238 -0
- package/client/08d-stage-adapter.js +65 -0
- package/client/08e-stage-activity.js +83 -0
- package/client/09-team-board.js +181 -0
- package/client/09b-role-view.js +95 -0
- package/client/09c-model-tabs.js +20 -0
- package/client/10-overview.js +364 -0
- package/client/10b-onboarding.js +121 -0
- package/client/11-register.js +249 -0
- package/client.js +5053 -0
- package/config-projection.js +40 -0
- package/config.js +411 -0
- package/cordis.patch.yml +110 -0
- package/defaults.js +222 -0
- package/dispatch-confirm.js +293 -0
- package/dispatch-routes-store.js +31 -0
- package/failover.js +85 -0
- package/file-limits.js +119 -0
- package/free-worker.mjs +125 -0
- package/http-guard.js +14 -0
- package/i18n/roles.en.json +23 -0
- package/i18n/roles.zh.json +23 -0
- package/i18n/server.en.json +659 -0
- package/i18n/server.zh.json +659 -0
- package/i18n.js +34 -0
- package/icon.svg +7 -0
- package/index.js +111 -0
- package/integrations-config.js +301 -0
- package/integrations-messages.js +62 -0
- package/integrations.js +17 -0
- package/lead-route.js +30 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/long-context.js +30 -0
- package/managed-config-route.js +49 -0
- package/managed-ref.js +38 -0
- package/managed-resolve.js +47 -0
- package/member-task-control.js +242 -0
- package/memory-backends.js +89 -0
- package/memory-embed.js +70 -0
- package/memory-hub.js +150 -0
- package/memory-openviking.js +101 -0
- package/memory-redact.js +34 -0
- package/memory-store.js +219 -0
- package/memory-sync-queue.js +28 -0
- package/model-policy.js +85 -0
- package/model-prefs.js +104 -0
- package/observability-api.js +76 -0
- package/observability-projection.js +141 -0
- package/onboarding.js +47 -0
- package/opencode.js +74 -0
- package/package.json +153 -4
- package/plan-gate.js +92 -0
- package/preset-guard.js +47 -0
- package/request-evidence.js +41 -0
- package/roles.js +69 -0
- package/roster-defaults.js +70 -0
- package/route-health.js +39 -0
- package/runtime-observability.js +78 -0
- package/runtime-view.js +21 -0
- package/scripts/memory-cli.mjs +138 -0
- package/search-engines.js +119 -0
- package/search.js +164 -0
- package/session-policy.js +59 -0
- package/session-rotation.js +206 -0
- package/settings-schema.js +40 -0
- package/shared/managed-config.js +84 -0
- package/single-model.js +44 -0
- package/skills/project-role-theme/SKILL.md +46 -0
- package/task-bridge.js +32 -0
- package/task-control-api.js +36 -0
- package/task-control-audit.js +60 -0
- package/team.js +101 -0
- package/teammate-context.js +120 -0
- package/teammate-wait.js +18 -0
- package/template.js +46 -0
- package/theme-plugin.js +172 -0
- package/theme.js +115 -0
- package/token-discipline.js +116 -0
- package/token-metrics.js +37 -0
- package/tool-names.js +10 -0
- package/tool-schema.js +23 -0
- package/transcribe.js +104 -0
- package/ui.js +113 -0
- package/usage.js +92 -0
- package/workflow.js +246 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
const BaseComponent = React.Component || class DummyComponent { constructor(props) { this.props = props; } };
|
|
2
|
+
class ErrorBoundary extends BaseComponent {
|
|
3
|
+
constructor(props) {
|
|
4
|
+
super(props);
|
|
5
|
+
this.state = { hasError: false, error: null };
|
|
6
|
+
}
|
|
7
|
+
static getDerivedStateFromError(error) {
|
|
8
|
+
return { hasError: true, error };
|
|
9
|
+
}
|
|
10
|
+
componentDidCatch(error, errorInfo) {
|
|
11
|
+
if (typeof console !== 'undefined' && console.error) {
|
|
12
|
+
console.error('CapabilityTeam tab render error caught by ErrorBoundary:', error, errorInfo);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
render() {
|
|
16
|
+
if (this.state.hasError) {
|
|
17
|
+
const t = this.props.t ?? (k => k);
|
|
18
|
+
return h('div', { className: 'ctm-ov-callout', 'data-tone': 'error', style: { margin: '16px' } },
|
|
19
|
+
h('p', { className: 'ctm-error' }, t('error.tabCrashed')),
|
|
20
|
+
this.state.error ? h('pre', { className: 'ctm-pre ctm-error' }, String(this.state.error?.message ?? this.state.error)) : null,
|
|
21
|
+
h('button', { type: 'button', className: 'ctm-btn', style: { marginTop: '8px' }, onClick: () => this.setState({ hasError: false, error: null }) },
|
|
22
|
+
t('models.reset')));
|
|
23
|
+
}
|
|
24
|
+
return this.props.children;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The status command ships catalog rows as tuples to keep its (visible) log entry small. */
|
|
29
|
+
function expandStatus(data) {
|
|
30
|
+
const policy = data?.team?.modelPolicy;
|
|
31
|
+
if (policy && Array.isArray(policy.rows)) {
|
|
32
|
+
policy.rows = policy.rows.map(row => {
|
|
33
|
+
if (!Array.isArray(row)) return row;
|
|
34
|
+
const [key, tier, primaryFor = [], fallbackFor = []] = row;
|
|
35
|
+
const slash = key.indexOf('/');
|
|
36
|
+
return { key, provider: key.slice(0, slash), model: key.slice(slash + 1), tiers: tier ? [tier] : [], primaryFor, fallbackFor };
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
/** Last manual snapshot per session: memory first, browser storage across panel reloads; never required. */
|
|
42
|
+
const snapshotCache = (() => {
|
|
43
|
+
const memory = new Map();
|
|
44
|
+
const keyOf = id => `capability-team:snapshot:${id}`;
|
|
45
|
+
return {
|
|
46
|
+
get(id) {
|
|
47
|
+
if (memory.has(id)) return memory.get(id);
|
|
48
|
+
try { const raw = window.localStorage?.getItem(keyOf(id)); const value = raw ? JSON.parse(raw) : null; if (value) memory.set(id, value); return value; } catch { return null; }
|
|
49
|
+
},
|
|
50
|
+
put(id, value) {
|
|
51
|
+
memory.set(id, value);
|
|
52
|
+
try { window.localStorage?.setItem(keyOf(id), JSON.stringify(value)); } catch { /* storage full or blocked */ }
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
})();
|
|
56
|
+
/** Host-pushed agent status (no polling, nothing logged) plus the read-only direct-child catalog. */
|
|
57
|
+
function liveStore(ctx) {
|
|
58
|
+
const remote = ctx.remote;
|
|
59
|
+
const sessions = ctx.sessions;
|
|
60
|
+
const states = new Map();
|
|
61
|
+
const listeners = new Set();
|
|
62
|
+
const requested = new Set();
|
|
63
|
+
let roster = 0;
|
|
64
|
+
const notify = () => { for (const listener of listeners) listener(); };
|
|
65
|
+
// DSH's own projection frames (agentTeam, modelSelection, tokenUsage, sessionStats) reach the shared Session store without any command.
|
|
66
|
+
if (typeof sessions?.list?.subscribe === 'function') ctx.effect(() => sessions.list.subscribe(notify), 'capability-team: session store');
|
|
67
|
+
const snapshot = () => { try { return sessions?.list?.getSnapshot?.(); } catch { return undefined; } };
|
|
68
|
+
const on = (event, listener) => { if (typeof remote?.$on === 'function') remote.$on(event, listener); };
|
|
69
|
+
on('api-session/status', (id, running) => {
|
|
70
|
+
const previous = states.get(id) ?? {};
|
|
71
|
+
if (!previous.known) roster++;
|
|
72
|
+
states.set(id, { known: true, running: !!running, since: running ? previous.since ?? Date.now() : undefined, error: running ? undefined : previous.error });
|
|
73
|
+
notify();
|
|
74
|
+
});
|
|
75
|
+
on('api-session/error', (id, message) => { states.set(id, { ...(states.get(id) ?? {}), known: true, error: String(message) }); notify(); });
|
|
76
|
+
on('api-session/added', () => { roster++; notify(); });
|
|
77
|
+
on('api-session/removed', id => { states.delete(id); roster++; notify(); });
|
|
78
|
+
return {
|
|
79
|
+
startedAt: Date.now(),
|
|
80
|
+
/** Live projection values of one session; asks the host once for a session the store has not loaded yet. */
|
|
81
|
+
projections(id) {
|
|
82
|
+
const entry = snapshot()?.projectionsBySession?.[id];
|
|
83
|
+
if (!entry && id && !requested.has(id) && typeof sessions?.refreshProjections === 'function') {
|
|
84
|
+
requested.add(id);
|
|
85
|
+
sessions.refreshProjections(id).catch(() => { requested.delete(id); });
|
|
86
|
+
}
|
|
87
|
+
return entry?.values;
|
|
88
|
+
},
|
|
89
|
+
parentSessionId: id => {
|
|
90
|
+
const direct = snapshot()?.projectionsBySession?.[id]?.values?.agentTeam?.parentSessionId;
|
|
91
|
+
if (direct) return direct;
|
|
92
|
+
try {
|
|
93
|
+
return sessions?.binding?.(id)?.session?.getSnapshot?.()?.subagent?.address?.parentSessionId;
|
|
94
|
+
} catch { return undefined; }
|
|
95
|
+
},
|
|
96
|
+
// True when the session is a subagent (has a subagent address) but its parent could not be resolved;
|
|
97
|
+
// the overview must then show only the notice, never a team canvas rooted at the wrong session.
|
|
98
|
+
isOrphanSubagent: id => {
|
|
99
|
+
try {
|
|
100
|
+
const addr = sessions?.binding?.(id)?.session?.getSnapshot?.()?.subagent?.address;
|
|
101
|
+
const direct = snapshot()?.projectionsBySession?.[id]?.values?.agentTeam?.parentSessionId;
|
|
102
|
+
return !!addr && !addr.parentSessionId && !direct;
|
|
103
|
+
} catch { return false; }
|
|
104
|
+
},
|
|
105
|
+
running: id => snapshot()?.byId?.[id]?.running,
|
|
106
|
+
status: id => states.get(id),
|
|
107
|
+
rosterVersion: () => roster,
|
|
108
|
+
subscribe(listener) { listeners.add(listener); return () => { listeners.delete(listener); }; },
|
|
109
|
+
preset: id => {
|
|
110
|
+
const direct = snapshot()?.projectionsBySession?.[id]?.values?.agentPreset;
|
|
111
|
+
if (direct !== undefined) return direct;
|
|
112
|
+
try {
|
|
113
|
+
const b = sessions?.binding?.(id)?.session?.getSnapshot?.()?.agentPreset;
|
|
114
|
+
if (b !== undefined) return b;
|
|
115
|
+
} catch {}
|
|
116
|
+
try {
|
|
117
|
+
const s = snapshot()?.byId?.[id]?.preset;
|
|
118
|
+
if (s !== undefined) return s;
|
|
119
|
+
} catch {}
|
|
120
|
+
const parentId = snapshot()?.projectionsBySession?.[id]?.values?.agentTeam?.parentSessionId
|
|
121
|
+
|| sessions?.binding?.(id)?.session?.getSnapshot?.()?.subagent?.address?.parentSessionId;
|
|
122
|
+
if (parentId && parentId !== id) {
|
|
123
|
+
const p = snapshot()?.projectionsBySession?.[parentId]?.values?.agentPreset;
|
|
124
|
+
if (p !== undefined) return p;
|
|
125
|
+
try {
|
|
126
|
+
const pb = sessions?.binding?.(parentId)?.session?.getSnapshot?.()?.agentPreset;
|
|
127
|
+
if (pb !== undefined) return pb;
|
|
128
|
+
} catch {}
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
},
|
|
132
|
+
isCapabilityTeam: id => {
|
|
133
|
+
if (!id) return false;
|
|
134
|
+
const directPreset = snapshot()?.projectionsBySession?.[id]?.values?.agentPreset;
|
|
135
|
+
if (directPreset === 'capability-team') return true;
|
|
136
|
+
if (directPreset && directPreset !== 'capability-team') return false;
|
|
137
|
+
const vals = snapshot()?.projectionsBySession?.[id]?.values;
|
|
138
|
+
if (vals?.capabilityTeamConfig !== undefined || vals?.capabilityTeamActivity !== undefined || vals?.capabilityTeamUsage !== undefined) return true;
|
|
139
|
+
const parentId = vals?.agentTeam?.parentSessionId
|
|
140
|
+
|| sessions?.binding?.(id)?.session?.getSnapshot?.()?.subagent?.address?.parentSessionId;
|
|
141
|
+
if (parentId && parentId !== id) {
|
|
142
|
+
const parentP = snapshot()?.projectionsBySession?.[parentId]?.values?.agentPreset;
|
|
143
|
+
if (parentP === 'capability-team') return true;
|
|
144
|
+
if (parentP && parentP !== 'capability-team') return false;
|
|
145
|
+
const parentVals = snapshot()?.projectionsBySession?.[parentId]?.values;
|
|
146
|
+
if (parentVals?.capabilityTeamConfig !== undefined || parentVals?.capabilityTeamActivity !== undefined || parentVals?.capabilityTeamUsage !== undefined) return true;
|
|
147
|
+
}
|
|
148
|
+
const s = snapshot()?.byId?.[id]?.preset;
|
|
149
|
+
if (s === 'capability-team') return true;
|
|
150
|
+
if (s && s !== 'capability-team') return false;
|
|
151
|
+
return undefined;
|
|
152
|
+
},
|
|
153
|
+
async children(parentId) {
|
|
154
|
+
const reply = await remote?.subagents?.list?.(parentId);
|
|
155
|
+
if (!reply?.ok) throw new Error(reply?.error?.message ?? 'subagent catalog unavailable');
|
|
156
|
+
return reply.value?.entries ?? [];
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const VIEWS = {
|
|
162
|
+
capability_dispatch_plan: DispatchPlanView,
|
|
163
|
+
capability_free_task: FreeTaskView,
|
|
164
|
+
capability_team_read: teamView('read'),
|
|
165
|
+
capability_team_save: teamView('save'),
|
|
166
|
+
capability_team_import: teamView('save'),
|
|
167
|
+
capability_model_catalog: CatalogView,
|
|
168
|
+
capability_task_budget: BudgetView,
|
|
169
|
+
capability_member_override: OverrideView,
|
|
170
|
+
capability_team_export: ExportView,
|
|
171
|
+
omni_search: SearchView,
|
|
172
|
+
omni_fetch: FetchView,
|
|
173
|
+
capability_handoff: HandoffView,
|
|
174
|
+
capability_rotate_member: RotateView,
|
|
175
|
+
capability_memory_search: MemorySearchView,
|
|
176
|
+
capability_memory_write: MemoryWriteView,
|
|
177
|
+
capability_model_prefs: PrefsView,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Test-only seam: harnesses may define window.__ctmTestHook to reach components; browsers never do.
|
|
181
|
+
if (typeof window.__ctmTestHook === 'function') window.__ctmTestHook({ TaskControl, leaseFor, DispatchConfirmCard, DirectConfirmCard, ConfirmDock, dockedSessions, DispatchPlanView, ModelPicker, filterRoutes, CatalogView, BudgetView, SearchView, ExportView, contextMetrics, RoleView, ModelSubTabs, CollapsibleList });
|
|
182
|
+
const plugin = {
|
|
183
|
+
inject: ['slots', 'locale', 'remote', 'remote.commands', 'remote.credentials', 'configForms', 'sidebarRightTabs', 'sessions', 'uiWorkspace'],
|
|
184
|
+
apply(ctx) {
|
|
185
|
+
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'capability-team: dictionaries');
|
|
186
|
+
ctx.effect(() => {
|
|
187
|
+
const tag = document.createElement('style');
|
|
188
|
+
tag.dataset.plugin = '@aiwuk/team';
|
|
189
|
+
tag.textContent = CSS + STAGE_CSS;
|
|
190
|
+
document.head.appendChild(tag);
|
|
191
|
+
// Stage canvas colors re-resolve on the host theme/change event (the body-attribute observer is the fallback).
|
|
192
|
+
const offTheme = stageTheme.bind(ctx);
|
|
193
|
+
return () => { offTheme(); tag.remove(); };
|
|
194
|
+
}, 'capability-team: styles + stage theme');
|
|
195
|
+
const bound = ctx.locale.bind(NS);
|
|
196
|
+
const execute = async (sessionId, line) => {
|
|
197
|
+
const reply = await ctx.remote.commands.execute(sessionId, line, []);
|
|
198
|
+
if (!reply.ok) throw new Error(reply.error?.message ?? 'Remote command failed');
|
|
199
|
+
const result = reply.value?.result;
|
|
200
|
+
if (!result || result.kind === 'error') throw new Error(result?.text ?? 'capability-status is unavailable');
|
|
201
|
+
const data = parse(result.text);
|
|
202
|
+
if (!data) throw new Error('Invalid capability-status response');
|
|
203
|
+
return data;
|
|
204
|
+
};
|
|
205
|
+
const load = async sessionId => expandStatus(await execute(sessionId, '/capability-status'));
|
|
206
|
+
const live = liveStore(ctx);
|
|
207
|
+
const onboardingGate = registerOnboarding(ctx, bound);
|
|
208
|
+
const save = (sessionId, disabledRoutes, expectedRevision) => execute(sessionId,
|
|
209
|
+
'/capability-model-policy ' + JSON.stringify({ disabledRoutes, expectedRevision }));
|
|
210
|
+
ctx.effect(() => ctx.sidebarRightTabs.register({
|
|
211
|
+
id: 'capability-team-overview', kind: 'capability-team-overview',
|
|
212
|
+
title: () => bound('overview.title'),
|
|
213
|
+
guide: [{ order: 35, title: () => bound('overview.title'), description: () => bound('overview.hint') }],
|
|
214
|
+
}), 'capability-team: right sidebar tab');
|
|
215
|
+
ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({
|
|
216
|
+
name: 'sidebar.right.pane.tab', key: 'capability-team-overview', id: 'capability-team-overview', locale: NS,
|
|
217
|
+
}, props => {
|
|
218
|
+
const effectiveLive = props.live ?? live;
|
|
219
|
+
const targetSessionId = props.sessionId;
|
|
220
|
+
const isCtm = effectiveLive?.isCapabilityTeam?.(targetSessionId);
|
|
221
|
+
if (isCtm === false) {
|
|
222
|
+
return h('div', { className: 'ctm-ov-empty ctm-not-mounted', 'data-tone': 'warn', style: { padding: '24px' } },
|
|
223
|
+
onboardingGate(props), h('p', { className: 'ctm-sub' }, bound('overview.notMounted')));
|
|
224
|
+
}
|
|
225
|
+
return h(Overview, { ...props, onboarding: props.onboarding ?? onboardingGate,
|
|
226
|
+
// Overview follows the host locale service (`locale`) and re-renders on a language switch. `t` is only
|
|
227
|
+
// passed through when a caller (a test harness) injects one; `hostT` is the fallback for missing keys.
|
|
228
|
+
locale: props.locale ?? ctx.locale, hostT: bound, load: props.load ?? load, save: props.save ?? save, live: effectiveLive, cache: props.cache ?? snapshotCache,
|
|
229
|
+
// Same navigation as DSH's own Team panel: open normal session for Lead or continuable subagent address for teammate.
|
|
230
|
+
openMember: typeof ctx.uiWorkspace?.openSession === 'function'
|
|
231
|
+
? (parentSessionId, childSessionId) => {
|
|
232
|
+
if (!childSessionId || childSessionId === parentSessionId) {
|
|
233
|
+
ctx.uiWorkspace.openSession(parentSessionId);
|
|
234
|
+
} else {
|
|
235
|
+
ctx.uiWorkspace.openSession({ parentSessionId, childSessionId, mode: 'continuable' });
|
|
236
|
+
}
|
|
237
|
+
} : undefined });
|
|
238
|
+
}));
|
|
239
|
+
// Each view receives `t`; fall back to the bound translator when the slot does not inject one.
|
|
240
|
+
const withT = View => function CapabilityToolView(props) { return h(View, { ...props, t: props.t ?? bound }); };
|
|
241
|
+
// Pending dispatch / direct confirmations open right above the input box, where the user sees them.
|
|
242
|
+
ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({ name: 'conversation.input.dock', id: 'capability-team-confirm', order: 5,
|
|
243
|
+
locale: NS, inject: sessionId => ({ sessionId }) }, withT(ConfirmDock)));
|
|
244
|
+
for (const [key, View] of Object.entries(VIEWS)) {
|
|
245
|
+
// `inject` hands each view its session id, which the dispatch confirmation card needs.
|
|
246
|
+
ctx.slots.inject('tool.call.toolview', () => ctx.slots.register({ name: 'tool.call.toolview', key, locale: NS, inject: sessionId => ({ sessionId }) }, withT(View)));
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
};
|