MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / dispatchAction

Function dispatchAction

src/cli/dashboard-control.ts:78–279  ·  view source on GitHub ↗
(name: string, params: any, cwd: string)

Source from the content-addressed store, hash-verified

76}
77
78/** Dispatch a dashboard action by name. Unknown actions are rejected. */
79export async function dispatchAction(name: string, params: any, cwd: string): Promise<ActionResult> {
80 try {
81 switch (name) {
82 case 'config.set': {
83 const v = validateConfigSet(String(params?.key ?? ''), params?.value);
84 if (!v.ok) return { ok: false, message: v.error };
85 await writeConfigKnob(String(params.key), v.coerced);
86 return { ok: true, message: `Set ${params.key} = ${v.coerced}. Takes effect on the next run.` };
87 }
88 case 'model.set': {
89 // role: main (default) | subagent | vision | all — "all" points every role at one model,
90 // which is all you need when that model has vision (no separate vision model required).
91 const model = String(params?.model ?? '').trim();
92 const role = String(params?.role ?? 'main').trim();
93 if (!model) return { ok: false, message: 'Pick a model.' };
94 if (!['main', 'subagent', 'vision', 'all'].includes(role)) return { ok: false, message: `Unknown role "${role}".` };
95 const { inferProvider } = await import('../llm/role-resolver.js');
96 const { looksVisionCapable } = await import('../setup/model-detector.js');
97 const provider = inferProvider(model);
98 const seesImages = looksVisionCapable(model);
99 if (role === 'main' || role === 'all') await writeConfigKnob('defaults.model', model);
100 if (role === 'subagent' || role === 'all') { await writeConfigKnob('roles.subagent.model', model); await writeConfigKnob('roles.subagent.provider', provider); }
101 if (role === 'vision' || role === 'all') { await writeConfigKnob('roles.vision.model', model); await writeConfigKnob('roles.vision.provider', provider); }
102 const visionNote = role === 'vision' && !seesImages
103 ? ' ⚠️ this model does not look vision-capable — screenshots may fail.'
104 : seesImages && role !== 'subagent' ? ' 👁 has vision — no separate vision model needed.' : '';
105 const label = role === 'all' ? 'ALL roles (main + subagent + vision)' : role === 'main' ? 'Default model' : `${role} model`;
106 return { ok: true, message: `${label} → ${model}.${visionNote} Takes effect on the next run.` };
107 }
108 case 'recall.query': {
109 const q = String(params?.query ?? '').trim();
110 if (!q) return { ok: false, message: 'Type what to recall.' };
111 const { rankApproaches } = await import('../context/approach-recall.js');
112 const { renderApproachDiffs } = await import('../context/approach-diff.js');
113 const { getSessionStore } = await import('../session/store.js');
114 const store = getSessionStore();
115 const worklog = (() => { try { return store.getWorklog(cwd, 100).map((w: any) => ({ kind: 'worklog' as const, text: w.entry, when: String(w.created_at ?? '').slice(0, 10), at: w.created_at, detail: w.kind })); } catch { return []; } })();
116 const episodes = await (async () => {
117 try { const { readEpisodes } = await import('../context/episodic-memory.js'); return (await readEpisodes(cwd)).map((e: any) => ({ kind: 'episode' as const, text: `${e.prompt} ${e.summary}`, when: String(e.ts ?? '').slice(0, 10), at: e.ts, files: e.filesChanged, detail: e.summary, verified: e.verified })); }
118 catch { return []; }
119 })();
120 const facts = (() => { try { return store.getFactsForCwd(cwd, 200).map((f: string) => ({ kind: 'fact' as const, text: f, when: '', detail: 'fact' })); } catch { return []; } })();
121 const receipts = await (async () => {
122 try {
123 const { getScheduleStore } = await import('../schedule/store.js');
124 const { parseMaintainScope } = await import('../schedule/recipes.js');
125 const sched = getScheduleStore();
126 const out: any[] = [];
127 for (const s of sched.list().filter((s: any) => s.recipe === 'maintain' && s.cwd === cwd)) {
128 const scope = parseMaintainScope(s.prompt).scope;
129 for (const r of sched.recentRuns(s.id, 50)) {
130 if (!r.receipt) continue;
131 try {
132 const rc = JSON.parse(r.receipt);
133 out.push({ kind: 'receipt' as const, at: r.started_at, when: String(r.started_at ?? '').slice(0, 10), text: `maintain ${scope}: ${rc.summary || rc.reason || rc.status}`, files: Array.isArray(rc.filesChanged) ? rc.filesChanged : [], detail: scope, verified: rc.status === 'opened' ? true : rc.status === 'blocked' || rc.status === 'failed' ? false : undefined });
134 } catch { /* skip */ }
135 }

Callers 3

handleRequestFunction · 0.85

Calls 15

validateConfigSetFunction · 0.85
writeConfigKnobFunction · 0.85
inferProviderFunction · 0.85
looksVisionCapableFunction · 0.85
getSessionStoreFunction · 0.85
readEpisodesFunction · 0.85
getScheduleStoreFunction · 0.85
parseMaintainScopeFunction · 0.85
rankApproachesFunction · 0.85
renderApproachDiffsFunction · 0.85
exportMemoryFunction · 0.85
promoteCandidateFunction · 0.85

Tested by

no test coverage detected