drafted 1.14.0 → 1.14.1

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/cli/drafted.mjs CHANGED
@@ -1911,89 +1911,89 @@ skillCmd
1911
1911
  else console.log(`ok\t${id}\t${data.hash}\tpushed ${data.count}${data.stripped ? `, stripped ${data.stripped}` : ''}${gitignored ? ', gitignored .skillinstall/' : ''}`);
1912
1912
  });
1913
1913
 
1914
- // ── Collectors: management seam (parity with the MCP `collector` tool) ──
1915
- // Collectors are checklist-driven intake surfaces. Management is behind the
1916
- // agent allowlist (same gate as Minion) and scoped to the session's active org.
1917
- function emitCollectorResult(format, obj) {
1914
+ // ── Minions: management seam (parity with the MCP `minion` tool) ──
1915
+ // Minions are checklist-driven intake surfaces. Management is behind the
1916
+ // agent allowlist and scoped to the session's active org.
1917
+ function emitMinionResult(format, obj) {
1918
1918
  if (format === 'json') { console.log(JSON.stringify(obj)); return; }
1919
1919
  console.log([obj.status, obj.id || '', obj.slug || '', obj.name || '', obj.error || ''].join('\t'));
1920
1920
  }
1921
1921
 
1922
- async function collectorSetEnabled(id, enabled, format) {
1922
+ async function minionSetEnabled(id, enabled, format) {
1923
1923
  requireLogin();
1924
1924
  const server = getServerUrl().replace(/\/$/, '');
1925
- const res = await authFetch(`${server}/api/collectors/${encodeURIComponent(id)}`, {
1925
+ const res = await authFetch(`${server}/api/minions/${encodeURIComponent(id)}`, {
1926
1926
  method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled }),
1927
1927
  });
1928
1928
  const data = await res.json().catch(() => ({}));
1929
- if (!res.ok) { emitCollectorResult(format, { status: res.status === 404 ? 'not-found' : 'error', error: data.error || `HTTP ${res.status}` }); process.exit(1); }
1930
- const c = data.collector || {};
1931
- emitCollectorResult(format, { status: 'ok', id: c.id, slug: c.slug, name: c.name });
1929
+ if (!res.ok) { emitMinionResult(format, { status: res.status === 404 ? 'not-found' : 'error', error: data.error || `HTTP ${res.status}` }); process.exit(1); }
1930
+ const c = data.minion || {};
1931
+ emitMinionResult(format, { status: 'ok', id: c.id, slug: c.slug, name: c.name });
1932
1932
  }
1933
1933
 
1934
- const collectorCmd = program.command('collector').description('Collector management (checklist-driven intake surfaces). Requires the agent allowlist.');
1934
+ const minionCmd = program.command('minion').description('Minion management (checklist-driven intake surfaces). Requires the agent allowlist.');
1935
1935
 
1936
- collectorCmd
1936
+ minionCmd
1937
1937
  .command('list')
1938
- .description('List collectors (scoped to --project or your active project; all org collectors if neither)')
1938
+ .description('List Minions (scoped to --project or your active project; all org Minions if neither)')
1939
1939
  .option('--project <id>', 'project to scope to (defaults to your active project)')
1940
1940
  .option('--format <fmt>', 'output format: json or text', 'text')
1941
1941
  .action(async (opts) => {
1942
1942
  const pid = opts.project || getActiveProject()?.id;
1943
- const data = await readApiGet('collector:list', withQuery('/api/collectors', { projectId: pid }));
1944
- const rows = data.collectors || [];
1943
+ const data = await readApiGet('minion:list', withQuery('/api/minions', { projectId: pid }));
1944
+ const rows = data.minions || [];
1945
1945
  if (opts.format === 'json') { console.log(JSON.stringify(rows)); return; }
1946
1946
  for (const c of rows) console.log(`${c.id}\t${c.slug}\t${c.enabled ? 'enabled' : 'disabled'}\t${c.name}`);
1947
1947
  });
1948
1948
 
1949
- collectorCmd
1949
+ minionCmd
1950
1950
  .command('get <id>')
1951
- .description('Get a collector by id')
1951
+ .description('Get a Minion by id')
1952
1952
  .option('--format <fmt>', 'output format: json or text', 'text')
1953
1953
  .action(async (id, opts) => {
1954
- const data = await readApiGet('collector:get', `/api/collectors/${encodeURIComponent(id)}`);
1955
- if (opts.format === 'json') { console.log(JSON.stringify(data.collector || data)); return; }
1956
- const c = data.collector || {};
1954
+ const data = await readApiGet('minion:get', `/api/minions/${encodeURIComponent(id)}`);
1955
+ if (opts.format === 'json') { console.log(JSON.stringify(data.minion || data)); return; }
1956
+ const c = data.minion || {};
1957
1957
  console.log(`${c.id}\t${c.slug}\t${c.enabled ? 'enabled' : 'disabled'}\t${c.name}`);
1958
1958
  });
1959
1959
 
1960
- collectorCmd
1960
+ minionCmd
1961
1961
  .command('meta')
1962
- .description('Project layers/lanes/frames for building a collector target/output')
1962
+ .description('Project layers/lanes/frames for building a Minion target/output')
1963
1963
  .option('--project <id>', 'project (defaults to your active project)')
1964
1964
  .option('--format <fmt>', 'output format: json or text', 'text')
1965
1965
  .action(async (opts) => {
1966
1966
  const pid = opts.project || getActiveProject()?.id;
1967
1967
  if (!pid) { console.error('No active project. Pass --project <id> or run `drafted use <project>`.'); process.exit(1); }
1968
- const data = await readApiGet('collector:meta', withQuery('/api/collectors/meta', { projectId: pid }));
1968
+ const data = await readApiGet('minion:meta', withQuery('/api/minions/meta', { projectId: pid }));
1969
1969
  console.log(JSON.stringify(data));
1970
1970
  });
1971
1971
 
1972
- collectorCmd
1972
+ minionCmd
1973
1973
  .command('create')
1974
- .description('Create a collector from stdin JSON {name,description?,target,checklist,output,enabled?}')
1974
+ .description('Create a Minion from stdin JSON {name,description?,target,checklist,output,enabled?}')
1975
1975
  .option('--project <id>', 'project to bind to (defaults to your active project)')
1976
1976
  .option('--format <fmt>', 'output format: json or text', 'text')
1977
1977
  .action(async (opts) => {
1978
1978
  requireLogin();
1979
1979
  const pid = opts.project || getActiveProject()?.id;
1980
- if (!pid) { emitCollectorResult(opts.format, { status: 'error', error: 'no project — pass --project <id> or run `drafted use <project>`' }); process.exit(1); }
1980
+ if (!pid) { emitMinionResult(opts.format, { status: 'error', error: 'no project — pass --project <id> or run `drafted use <project>`' }); process.exit(1); }
1981
1981
  let p;
1982
1982
  try { p = readStdinJSON(); } catch { console.error('invalid JSON on stdin'); process.exit(1); }
1983
1983
  const server = getServerUrl().replace(/\/$/, '');
1984
- const res = await authFetch(`${server}/api/collectors`, {
1984
+ const res = await authFetch(`${server}/api/minions`, {
1985
1985
  method: 'POST', headers: { 'Content-Type': 'application/json' },
1986
1986
  body: JSON.stringify({ projectId: pid, name: p.name, description: p.description, target: p.target, checklist: p.checklist, output: p.output, enabled: p.enabled }),
1987
1987
  });
1988
1988
  const data = await res.json().catch(() => ({}));
1989
- if (!res.ok) { emitCollectorResult(opts.format, { status: res.status === 403 ? 'forbidden' : 'error', error: data.error || `HTTP ${res.status}` }); process.exit(1); }
1990
- const c = data.collector || {};
1991
- emitCollectorResult(opts.format, { status: 'ok', id: c.id, slug: c.slug, name: c.name });
1989
+ if (!res.ok) { emitMinionResult(opts.format, { status: res.status === 403 ? 'forbidden' : 'error', error: data.error || `HTTP ${res.status}` }); process.exit(1); }
1990
+ const c = data.minion || {};
1991
+ emitMinionResult(opts.format, { status: 'ok', id: c.id, slug: c.slug, name: c.name });
1992
1992
  });
1993
1993
 
1994
- collectorCmd
1994
+ minionCmd
1995
1995
  .command('update <id>')
1996
- .description('Update a collector from stdin JSON {name?,description?,target?,checklist?,output?,enabled?}')
1996
+ .description('Update a Minion from stdin JSON {name?,description?,target?,checklist?,output?,enabled?}')
1997
1997
  .option('--format <fmt>', 'output format: json or text', 'text')
1998
1998
  .action(async (id, opts) => {
1999
1999
  requireLogin();
@@ -2003,33 +2003,33 @@ collectorCmd
2003
2003
  for (const k of ['name', 'description', 'target', 'checklist', 'output', 'enabled']) {
2004
2004
  if (p[k] !== undefined) body[k] = p[k];
2005
2005
  }
2006
- if (Object.keys(body).length === 0) { emitCollectorResult(opts.format, { status: 'error', error: 'no fields to update' }); process.exit(1); }
2006
+ if (Object.keys(body).length === 0) { emitMinionResult(opts.format, { status: 'error', error: 'no fields to update' }); process.exit(1); }
2007
2007
  const server = getServerUrl().replace(/\/$/, '');
2008
- const res = await authFetch(`${server}/api/collectors/${encodeURIComponent(id)}`, {
2008
+ const res = await authFetch(`${server}/api/minions/${encodeURIComponent(id)}`, {
2009
2009
  method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body),
2010
2010
  });
2011
2011
  const data = await res.json().catch(() => ({}));
2012
- if (!res.ok) { emitCollectorResult(opts.format, { status: res.status === 404 ? 'not-found' : 'error', error: data.error || `HTTP ${res.status}` }); process.exit(1); }
2013
- const c = data.collector || {};
2014
- emitCollectorResult(opts.format, { status: 'ok', id: c.id, slug: c.slug, name: c.name });
2012
+ if (!res.ok) { emitMinionResult(opts.format, { status: res.status === 404 ? 'not-found' : 'error', error: data.error || `HTTP ${res.status}` }); process.exit(1); }
2013
+ const c = data.minion || {};
2014
+ emitMinionResult(opts.format, { status: 'ok', id: c.id, slug: c.slug, name: c.name });
2015
2015
  });
2016
2016
 
2017
- collectorCmd
2017
+ minionCmd
2018
2018
  .command('enable <id>')
2019
- .description('Make a collector live')
2019
+ .description('Make a Minion live')
2020
2020
  .option('--format <fmt>', 'output format: json or text', 'text')
2021
- .action((id, opts) => collectorSetEnabled(id, true, opts.format));
2021
+ .action((id, opts) => minionSetEnabled(id, true, opts.format));
2022
2022
 
2023
- collectorCmd
2023
+ minionCmd
2024
2024
  .command('disable <id>')
2025
- .description('Take a collector offline')
2025
+ .description('Take a Minion offline')
2026
2026
  .option('--format <fmt>', 'output format: json or text', 'text')
2027
- .action((id, opts) => collectorSetEnabled(id, false, opts.format));
2027
+ .action((id, opts) => minionSetEnabled(id, false, opts.format));
2028
2028
 
2029
- async function collectorTestPost(id, path, body, format) {
2029
+ async function minionTestPost(id, path, body, format) {
2030
2030
  requireLogin();
2031
2031
  const server = getServerUrl().replace(/\/$/, '');
2032
- const res = await authFetch(`${server}/api/collectors/${encodeURIComponent(id)}/${path}`, {
2032
+ const res = await authFetch(`${server}/api/minions/${encodeURIComponent(id)}/${path}`, {
2033
2033
  method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body || {}),
2034
2034
  });
2035
2035
  const data = await res.json().catch(() => ({}));
@@ -2041,39 +2041,39 @@ async function collectorTestPost(id, path, body, format) {
2041
2041
  console.log(JSON.stringify(data));
2042
2042
  }
2043
2043
 
2044
- collectorCmd
2044
+ minionCmd
2045
2045
  .command('test-start <id>')
2046
- .description('QA: start (or resume) a test run of a collector you own — works even when disabled. --fresh for a new run.')
2046
+ .description('QA: start (or resume) a test run of a Minion you own — works even when disabled. --fresh for a new run.')
2047
2047
  .option('--fresh', 'start a brand-new run instead of resuming', false)
2048
2048
  .option('--format <fmt>', 'output format: json (default)', 'json')
2049
- .action((id, opts) => collectorTestPost(id, 'test-start', { fresh: !!opts.fresh }, opts.format));
2049
+ .action((id, opts) => minionTestPost(id, 'test-start', { fresh: !!opts.fresh }, opts.format));
2050
2050
 
2051
- collectorCmd
2051
+ minionCmd
2052
2052
  .command('test-say <id>')
2053
2053
  .description('QA: send a text answer to your test run; returns the agent reply, checklist state, pending actions.')
2054
2054
  .requiredOption('--text <text>', 'the consumer message to send')
2055
2055
  .option('--format <fmt>', 'output format: json (default)', 'json')
2056
- .action((id, opts) => collectorTestPost(id, 'test-message', { content: opts.text }, opts.format));
2056
+ .action((id, opts) => minionTestPost(id, 'test-message', { content: opts.text }, opts.format));
2057
2057
 
2058
- collectorCmd
2058
+ minionCmd
2059
2059
  .command('test-resolve <id>')
2060
2060
  .description('QA: approve or reject a pending destructive action in your test run.')
2061
2061
  .requiredOption('--action <actionId>', 'the pending action id')
2062
2062
  .option('--reject', 'reject instead of approve', false)
2063
2063
  .option('--format <fmt>', 'output format: json (default)', 'json')
2064
- .action((id, opts) => collectorTestPost(id, 'test-resolve', { actionId: opts.action, approve: !opts.reject }, opts.format));
2064
+ .action((id, opts) => minionTestPost(id, 'test-resolve', { actionId: opts.action, approve: !opts.reject }, opts.format));
2065
2065
 
2066
- collectorCmd
2066
+ minionCmd
2067
2067
  .command('delete <id>')
2068
- .description('Delete a collector (past submissions are kept as history)')
2068
+ .description('Delete a Minion (past submissions are kept as history)')
2069
2069
  .option('--format <fmt>', 'output format: json or text', 'text')
2070
2070
  .action(async (id, opts) => {
2071
2071
  requireLogin();
2072
2072
  const server = getServerUrl().replace(/\/$/, '');
2073
- const res = await authFetch(`${server}/api/collectors/${encodeURIComponent(id)}`, { method: 'DELETE' });
2073
+ const res = await authFetch(`${server}/api/minions/${encodeURIComponent(id)}`, { method: 'DELETE' });
2074
2074
  const data = await res.json().catch(() => ({}));
2075
- if (!res.ok) { emitCollectorResult(opts.format, { status: res.status === 404 ? 'not-found' : 'error', error: data.error || `HTTP ${res.status}` }); process.exit(1); }
2076
- emitCollectorResult(opts.format, { status: 'ok', id: data.id || id });
2075
+ if (!res.ok) { emitMinionResult(opts.format, { status: res.status === 404 ? 'not-found' : 'error', error: data.error || `HTTP ${res.status}` }); process.exit(1); }
2076
+ emitMinionResult(opts.format, { status: 'ok', id: data.id || id });
2077
2077
  });
2078
2078
 
2079
2079
  program.parse();
package/mcp/server.mjs CHANGED
@@ -144,7 +144,7 @@ const REMOTE_JSON_STRING_PARAMS = {
144
144
  wiki: ['frontmatter', 'pages'],
145
145
  project: ['layers'],
146
146
  template: ['layers'],
147
- collector: ['target', 'checklist', 'output'],
147
+ minion: ['target', 'checklist', 'output'],
148
148
  };
149
149
 
150
150
  // Remove sentences that reference local-file params from a tool description,
@@ -258,8 +258,8 @@ const TOOL_ANNOTATIONS = {
258
258
  skill: { title: 'Skills', readOnlyHint: false, destructiveHint: true, openWorldHint: false, description: 'Manage the Drafted skill library: search, load, add, update, remove, attach/detach from projects, favorite, and edit skill files.' },
259
259
  wiki: { title: 'Wiki', readOnlyHint: false, destructiveHint: true, openWorldHint: false, description: 'Per-org wiki. Markdown pages with paths as hierarchy. Dispatch by `action`.' },
260
260
 
261
- // Collectors — checklist-driven, Minion-run intake surfaces bound to a project
262
- collector: { title: 'Collectors', readOnlyHint: false, destructiveHint: true, openWorldHint: false, description: 'Manage Collectors: checklist-driven intake surfaces that guide a consumer through a checklist (via a shareable /c/<slug> link) and then write a producible into the project. Dispatch by `action`: meta (discover layers/lanes/frames), list, get, create, update, enable, disable, delete. QA your own collectors with test_start/test_say/test_resolve — drive the checklist conversation yourself (works even when disabled) and verify it produces the right Doc/Sheet output. Requires the agent allowlist (same gate as Minion).' },
261
+ // Minions — checklist-driven intake surfaces bound to a project
262
+ minion: { title: 'Minions', readOnlyHint: false, destructiveHint: true, openWorldHint: false, description: 'Manage Minions: checklist-driven intake surfaces that guide a consumer through a checklist (via a shareable /c/<slug> link) and then write a producible into the project. Dispatch by `action`: meta (discover layers/lanes/frames), list, get, create, update, enable, disable, delete. QA your own Minions with test_start/test_say/test_resolve — drive the checklist conversation yourself (works even when disabled) and verify it produces the right Doc/Sheet output. Requires the agent allowlist.' },
263
263
  };
264
264
 
265
265
  function isMutatingToolCall(name, args = {}) {
@@ -285,7 +285,7 @@ function isMutatingToolCall(name, args = {}) {
285
285
  return ['add', 'update', 'remove', 'attach', 'detach', 'favorite', 'unfavorite', 'update_file'].includes(action);
286
286
  case 'wiki':
287
287
  return ['log', 'write', 'edit', 'mv', 'rm', 'source-register', 'bulk-write'].includes(action);
288
- case 'collector':
288
+ case 'minion':
289
289
  return ['create', 'update', 'enable', 'disable', 'delete', 'test_start', 'test_say', 'test_resolve'].includes(action);
290
290
  case 'rm':
291
291
  case 'shape':
@@ -4171,51 +4171,51 @@ tool('wiki', 'Per-org wiki. Markdown pages with paths as hierarchy. You and othe
4171
4171
  } catch (error) { return err(error); }
4172
4172
  });
4173
4173
 
4174
- // ── Collectors ────────────────────────────────────────────────────
4174
+ // ── Minions ───────────────────────────────────────────────────────
4175
4175
 
4176
- function compactCollectorEntry(c) {
4176
+ function compactMinionEntry(c) {
4177
4177
  if (!c || typeof c !== 'object') return c;
4178
4178
  return { id: c.id, slug: c.slug, name: c.name, enabled: c.enabled, projectId: c.projectId };
4179
4179
  }
4180
4180
 
4181
- // Shape a {collectors:[...]} list with limit/offset pagination + optional compact
4181
+ // Shape a {minions:[...]} list with limit/offset pagination + optional compact
4182
4182
  // mode, mirroring shapeSkillCatalog so large lists stay within token budget.
4183
- function shapeCollectorList(result, { limit, offset = 0, compact = false } = {}) {
4184
- if (!Array.isArray(result?.collectors)) return result;
4185
- const total = result.collectors.length;
4183
+ function shapeMinionList(result, { limit, offset = 0, compact = false } = {}) {
4184
+ if (!Array.isArray(result?.minions)) return result;
4185
+ const total = result.minions.length;
4186
4186
  const start = Math.max(0, Math.floor(Number(offset) || 0));
4187
4187
  const cap = Math.min(Math.max(1, Math.floor(Number(limit) || 25)), 100);
4188
- const page = result.collectors.slice(start, start + cap);
4188
+ const page = result.minions.slice(start, start + cap);
4189
4189
  result.totalAvailable = total;
4190
4190
  result.offset = start;
4191
4191
  result.returned = page.length;
4192
4192
  result.truncated = start + page.length < total;
4193
- result.collectors = compact ? page.map(compactCollectorEntry) : page;
4193
+ result.minions = compact ? page.map(compactMinionEntry) : page;
4194
4194
  result.note = compact
4195
- ? 'Compact list: {id,slug,name,enabled,projectId} only. Use collector(action="get", id="<id>") for full config; limit/offset to page.'
4196
- : 'Collectors are scoped to the active project (all org collectors when no project is open). Use limit/offset to page; compact=true for a leaner list.';
4195
+ ? 'Compact list: {id,slug,name,enabled,projectId} only. Use minion(action="get", id="<id>") for full config; limit/offset to page.'
4196
+ : 'Minions are scoped to the active project (all org Minions when no project is open). Use limit/offset to page; compact=true for a leaner list.';
4197
4197
  return result;
4198
4198
  }
4199
4199
 
4200
4200
  // Friendlier message when the agent allowlist gate (requireAgentAccess) rejects.
4201
- function collectorGateError(e) {
4201
+ function minionGateError(e) {
4202
4202
  if (e?.status === 403 || e?.code === 'agent_disabled') {
4203
- return new Error('Collector management is not enabled for this org/account (agent allowlist). Ask an admin to add your org or email to DRAFTED_AGENT_ALLOWED_ORGS / DRAFTED_AGENT_ALLOWED_EMAILS.');
4203
+ return new Error('Minion management is not enabled for this org/account (agent allowlist). Ask an admin to add your org or email to DRAFTED_AGENT_ALLOWED_ORGS / DRAFTED_AGENT_ALLOWED_EMAILS.');
4204
4204
  }
4205
4205
  return e;
4206
4206
  }
4207
4207
 
4208
- tool('collector', {
4209
- action: z.enum(['meta', 'list', 'get', 'create', 'update', 'enable', 'disable', 'delete', 'test_start', 'test_say', 'test_resolve']).describe('Operation to perform. test_* drive a QA conversation against a collector you own (even disabled) to verify it end-to-end.'),
4210
- id: z.string().optional().describe('[get|update|enable|disable|delete|test_*] collector ID (UUID)'),
4208
+ tool('minion', {
4209
+ action: z.enum(['meta', 'list', 'get', 'create', 'update', 'enable', 'disable', 'delete', 'test_start', 'test_say', 'test_resolve']).describe('Operation to perform. test_* drive a QA conversation against a Minion you own (even disabled) to verify it end-to-end.'),
4210
+ id: z.string().optional().describe('[get|update|enable|disable|delete|test_*] Minion ID (UUID)'),
4211
4211
  text: z.string().optional().describe('[test_say] the consumer message to send to your test run'),
4212
4212
  fresh: z.boolean().optional().describe('[test_start] start a brand-new run instead of resuming your latest'),
4213
4213
  actionId: z.string().optional().describe('[test_resolve] id of the pending action to resolve'),
4214
4214
  approve: z.boolean().optional().describe('[test_resolve] approve (default true) or reject the pending action'),
4215
4215
  projectId: z.string().optional().describe('[create|meta] project to bind/scope to (defaults to the active project). The org derives from this project — open the target project first via project(action="open") if none is active.'),
4216
- name: z.string().optional().describe('[create|update] collector name'),
4216
+ name: z.string().optional().describe('[create|update] Minion name'),
4217
4217
  description: z.string().optional().describe('[create|update] one-line description shown to the consumer'),
4218
- enabled: z.boolean().optional().describe('[create|update] whether the collector is live; a disabled collector 404s on its /c/<slug> link. enable/disable set this directly.'),
4218
+ enabled: z.boolean().optional().describe('[create|update] whether the Minion is live; a disabled Minion 404s on its /c/<slug> link. enable/disable set this directly.'),
4219
4219
  target: z.object({
4220
4220
  type: z.enum(['new-record', 'layer', 'frame']).describe('what the run writes against'),
4221
4221
  layer: z.string().optional(),
@@ -4244,7 +4244,7 @@ tool('collector', {
4244
4244
  }).optional().describe('[create|update] where/how the producible lands'),
4245
4245
  limit: z.number().optional().describe('[list] max results per page (default 25, max 100)'),
4246
4246
  offset: z.number().optional().describe('[list] skip N results for pagination (default 0)'),
4247
- compact: z.boolean().optional().describe('[list] return only {id,slug,name,enabled,projectId} per collector'),
4247
+ compact: z.boolean().optional().describe('[list] return only {id,slug,name,enabled,projectId} per Minion'),
4248
4248
  }, async (args) => {
4249
4249
  try {
4250
4250
  const { action } = args;
@@ -4254,18 +4254,18 @@ tool('collector', {
4254
4254
  const pid = active || args.projectId;
4255
4255
  if (!pid) throw new Error('No active project. Call project(action="open") first, or pass projectId.');
4256
4256
  // api() auto-appends the active project; add projectId explicitly only when none is active.
4257
- const path = active ? '/api/collectors/meta' : `/api/collectors/meta?projectId=${encodeURIComponent(pid)}`;
4257
+ const path = active ? '/api/minions/meta' : `/api/minions/meta?projectId=${encodeURIComponent(pid)}`;
4258
4258
  return ok(await api('GET', path));
4259
4259
  }
4260
4260
  case 'list': {
4261
4261
  // api() auto-appends the active project as ?projectId — so this lists the
4262
- // active project's collectors, or all org collectors when none is open.
4263
- const result = await api('GET', '/api/collectors');
4264
- return ok(shapeCollectorList(result, { limit: args.limit, offset: args.offset, compact: args.compact }));
4262
+ // active project's Minions, or all org Minions when none is open.
4263
+ const result = await api('GET', '/api/minions');
4264
+ return ok(shapeMinionList(result, { limit: args.limit, offset: args.offset, compact: args.compact }));
4265
4265
  }
4266
4266
  case 'get': {
4267
4267
  if (!args.id) throw new Error('id is required for action=get');
4268
- return ok(await api('GET', `/api/collectors/${args.id}`));
4268
+ return ok(await api('GET', `/api/minions/${args.id}`));
4269
4269
  }
4270
4270
  case 'create': {
4271
4271
  // projectId lives in the BODY (the POST route reads body, ignores the query).
@@ -4278,7 +4278,7 @@ tool('collector', {
4278
4278
  const body = { projectId, name, target, checklist, output };
4279
4279
  if (description !== undefined) body.description = description;
4280
4280
  if (enabled !== undefined) body.enabled = enabled;
4281
- return ok(await api('POST', '/api/collectors', body));
4281
+ return ok(await api('POST', '/api/minions', body));
4282
4282
  }
4283
4283
  case 'update': {
4284
4284
  if (!args.id) throw new Error('id is required for action=update');
@@ -4287,35 +4287,35 @@ tool('collector', {
4287
4287
  if (args[k] !== undefined) body[k] = args[k];
4288
4288
  }
4289
4289
  if (Object.keys(body).length === 0) throw new Error('At least one field is required for action=update');
4290
- return ok(await api('PATCH', `/api/collectors/${args.id}`, body));
4290
+ return ok(await api('PATCH', `/api/minions/${args.id}`, body));
4291
4291
  }
4292
4292
  case 'enable':
4293
4293
  case 'disable': {
4294
4294
  if (!args.id) throw new Error(`id is required for action=${action}`);
4295
- return ok(await api('PATCH', `/api/collectors/${args.id}`, { enabled: action === 'enable' }));
4295
+ return ok(await api('PATCH', `/api/minions/${args.id}`, { enabled: action === 'enable' }));
4296
4296
  }
4297
4297
  case 'delete': {
4298
4298
  if (!args.id) throw new Error('id is required for action=delete');
4299
- return ok(await api('DELETE', `/api/collectors/${args.id}`));
4299
+ return ok(await api('DELETE', `/api/minions/${args.id}`));
4300
4300
  }
4301
4301
  case 'test_start': {
4302
4302
  if (!args.id) throw new Error('id is required for action=test_start');
4303
- return ok(await api('POST', `/api/collectors/${args.id}/test-start`, { fresh: !!args.fresh }));
4303
+ return ok(await api('POST', `/api/minions/${args.id}/test-start`, { fresh: !!args.fresh }));
4304
4304
  }
4305
4305
  case 'test_say': {
4306
4306
  if (!args.id) throw new Error('id is required for action=test_say');
4307
4307
  if (!args.text) throw new Error('text is required for action=test_say');
4308
- return ok(await api('POST', `/api/collectors/${args.id}/test-message`, { content: args.text }));
4308
+ return ok(await api('POST', `/api/minions/${args.id}/test-message`, { content: args.text }));
4309
4309
  }
4310
4310
  case 'test_resolve': {
4311
4311
  if (!args.id) throw new Error('id is required for action=test_resolve');
4312
4312
  if (!args.actionId) throw new Error('actionId is required for action=test_resolve');
4313
- return ok(await api('POST', `/api/collectors/${args.id}/test-resolve`, { actionId: args.actionId, approve: args.approve !== false }));
4313
+ return ok(await api('POST', `/api/minions/${args.id}/test-resolve`, { actionId: args.actionId, approve: args.approve !== false }));
4314
4314
  }
4315
4315
  default:
4316
- throw new Error(`Unknown collector action: ${action}`);
4316
+ throw new Error(`Unknown minion action: ${action}`);
4317
4317
  }
4318
- } catch (error) { return err(collectorGateError(error)); }
4318
+ } catch (error) { return err(minionGateError(error)); }
4319
4319
  });
4320
4320
 
4321
4321
  // ── Resource: canvas info ─────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drafted",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
4
4
  "description": "Drafted — visual thinking surface for humans and AI agents. Renders HTML, markdown, images, and code as frames on a zoomable canvas, with MCP tools for AI agents and real-time sync for humans.",
5
5
  "type": "module",
6
6
  "files": [