monomind 2.1.0 → 2.1.4

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.
Files changed (57) hide show
  1. package/README.md +77 -94
  2. package/package.json +3 -3
  3. package/packages/@monomind/cli/.claude/commands/mastermind/createorg.md +8 -9
  4. package/packages/@monomind/cli/.claude/helpers/handlers/capture-handler.cjs +24 -10
  5. package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +2 -2
  6. package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +29 -0
  7. package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +35 -23
  8. package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +21 -0
  9. package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +73 -2
  10. package/packages/@monomind/cli/.claude/skills/mastermind-skills/createorg.md +91 -701
  11. package/packages/@monomind/cli/.claude/skills/mastermind-skills/org-settings.md +46 -47
  12. package/packages/@monomind/cli/.claude/skills/mastermind-skills/runorg.md +12 -1
  13. package/packages/@monomind/cli/README.md +77 -94
  14. package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +2 -2
  15. package/packages/@monomind/cli/dist/src/commands/browse.d.ts +1 -1
  16. package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +5 -0
  17. package/packages/@monomind/cli/dist/src/commands/org.js +46 -29
  18. package/packages/@monomind/cli/dist/src/commands/platforms.d.ts +1 -1
  19. package/packages/@monomind/cli/dist/src/init/executor.js +30 -6
  20. package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.d.ts +8 -8
  21. package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +31 -31
  22. package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +5 -1
  23. package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +28 -3
  24. package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +36 -36
  25. package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
  26. package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.d.ts +12 -0
  27. package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +12 -0
  28. package/packages/@monomind/cli/dist/src/orgrt/broker.d.ts +3 -1
  29. package/packages/@monomind/cli/dist/src/orgrt/broker.js +8 -3
  30. package/packages/@monomind/cli/dist/src/orgrt/bus.d.ts +5 -1
  31. package/packages/@monomind/cli/dist/src/orgrt/bus.js +5 -1
  32. package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +35 -1
  33. package/packages/@monomind/cli/dist/src/orgrt/daemon.js +190 -21
  34. package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +47 -10
  35. package/packages/@monomind/cli/dist/src/orgrt/inbox.d.ts +11 -0
  36. package/packages/@monomind/cli/dist/src/orgrt/inbox.js +56 -0
  37. package/packages/@monomind/cli/dist/src/orgrt/policy.d.ts +5 -1
  38. package/packages/@monomind/cli/dist/src/orgrt/policy.js +58 -5
  39. package/packages/@monomind/cli/dist/src/orgrt/server.d.ts +3 -2
  40. package/packages/@monomind/cli/dist/src/orgrt/server.js +31 -40
  41. package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +11 -1
  42. package/packages/@monomind/cli/dist/src/orgrt/session.js +32 -1
  43. package/packages/@monomind/cli/dist/src/orgrt/test-loop.js +8 -8
  44. package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +53 -53
  45. package/packages/@monomind/cli/dist/src/output.d.ts +29 -29
  46. package/packages/@monomind/cli/dist/src/output.js +10 -2
  47. package/packages/@monomind/cli/dist/src/pricing/model-pricing.d.ts +1 -1
  48. package/packages/@monomind/cli/dist/src/types.d.ts +2 -2
  49. package/packages/@monomind/cli/dist/src/ui/collector.mjs +20 -5
  50. package/packages/@monomind/cli/dist/src/ui/dashboard.html +465 -500
  51. package/packages/@monomind/cli/dist/src/ui/orgs-files.js +192 -0
  52. package/packages/@monomind/cli/dist/src/ui/orgs.html +21 -52
  53. package/packages/@monomind/cli/dist/src/ui/server.mjs +174 -164
  54. package/packages/@monomind/cli/package.json +12 -16
  55. package/packages/@monomind/cli/scripts/publish.sh +6 -0
  56. package/scripts/generate-agent-avatars.mjs +3 -3
  57. package/packages/@monomind/cli/dist/src/orgrt/live.html +0 -56
@@ -1,38 +1,12 @@
1
1
  // packages/@monomind/cli/src/orgrt/server.ts
2
+ // monolean: stripped to xdeliver-only — live UI, WS fanout, and redundant REST
3
+ // endpoints deleted; the control server at :4242 handles all of those.
2
4
  import http from 'node:http';
3
- import { readFileSync, existsSync } from 'node:fs';
4
- import { join, dirname } from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import { WebSocketServer, WebSocket } from 'ws';
7
- /** Daemon-owned live view: WS fanout of every bus event + tiny REST surface. */
8
- export async function startOrgServer(daemon, port) {
9
- const here = dirname(fileURLToPath(import.meta.url));
10
- const htmlPath = ['live.html', '../orgrt/live.html']
11
- .map(p => join(here, p)).find(existsSync) ?? join(here, 'live.html');
5
+ /** Minimal HTTP listener for cross-process org message delivery.
6
+ * Binds an ephemeral port (pass 0) so the daemon can register it with the broker. */
7
+ export async function startOrgServer(daemon, port = 0) {
12
8
  const server = http.createServer((req, res) => {
13
- const url = req.url ?? '/';
14
- if (req.method === 'GET' && url === '/') {
15
- res.writeHead(200, { 'Content-Type': 'text/html' });
16
- res.end(readFileSync(htmlPath, 'utf8'));
17
- }
18
- else if (req.method === 'GET' && url === '/api/orgs') {
19
- res.writeHead(200, { 'Content-Type': 'application/json' });
20
- res.end(JSON.stringify(daemon.listOrgs().map(o => ({
21
- name: o.def.name, run: o.run, goal: o.def.goal,
22
- agents: [...o.agents.entries()].map(([id, a]) => ({
23
- id, usage: a.policy.usage, closed: a.mailbox.isClosed,
24
- status: a.status, error: a.error,
25
- })),
26
- }))));
27
- }
28
- else if (req.method === 'GET' && url.startsWith('/api/history/')) {
29
- const name = decodeURIComponent(url.slice('/api/history/'.length));
30
- const org = daemon.getOrg(name);
31
- res.writeHead(200, { 'Content-Type': 'application/json' });
32
- res.end(JSON.stringify(org ? org.busEvents() : []));
33
- }
34
- else if (req.method === 'POST' && url === '/api/xdeliver') {
35
- // inbound cross-process delivery — see OrgDaemon.deliverRemote() on the sending side
9
+ if (req.method === 'POST' && req.url === '/api/xdeliver') {
36
10
  let body = '';
37
11
  req.on('data', c => { body += c; });
38
12
  req.on('end', () => {
@@ -53,20 +27,37 @@ export async function startOrgServer(daemon, port) {
53
27
  }
54
28
  });
55
29
  }
30
+ else if (req.method === 'POST' && req.url === '/api/answer-question') {
31
+ let body = '';
32
+ req.on('data', c => { body += c; });
33
+ req.on('end', () => {
34
+ (async () => {
35
+ try {
36
+ const payload = JSON.parse(body || '{}');
37
+ if (!payload.org || !payload.role || !payload.questionId || payload.answer === undefined) {
38
+ res.writeHead(400, { 'Content-Type': 'application/json' });
39
+ res.end(JSON.stringify({ ok: false, error: 'org, role, questionId, answer are required' }));
40
+ return;
41
+ }
42
+ const result = await daemon.answerQuestion(payload.org, payload.role, payload.questionId, payload.answer);
43
+ res.writeHead(result.ok ? 200 : 404, { 'Content-Type': 'application/json' });
44
+ res.end(JSON.stringify(result));
45
+ }
46
+ catch (err) {
47
+ res.writeHead(400, { 'Content-Type': 'application/json' });
48
+ res.end(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : 'bad request' }));
49
+ }
50
+ })();
51
+ });
52
+ return;
53
+ }
56
54
  else {
57
55
  res.writeHead(404);
58
56
  res.end('not found');
59
57
  }
60
58
  });
61
- const wss = new WebSocketServer({ server, path: '/ws' });
62
- const unsubscribe = daemon.subscribe(e => {
63
- const line = JSON.stringify(e);
64
- for (const c of wss.clients)
65
- if (c.readyState === WebSocket.OPEN)
66
- c.send(line);
67
- });
68
59
  await new Promise(r => server.listen(port, r));
69
60
  const actual = server.address().port;
70
- return { port: actual, close: () => { unsubscribe(); wss.close(); server.close(); } };
61
+ return { port: actual, close: () => { server.close(); } };
71
62
  }
72
63
  //# sourceMappingURL=server.js.map
@@ -12,12 +12,22 @@ export interface SessionOpts {
12
12
  mailbox: Mailbox;
13
13
  cwd: string;
14
14
  deliver: DeliverFn;
15
+ askHuman?: (role: string, question: string) => Promise<string>;
15
16
  def?: OrgDef;
16
17
  maxTurns?: number;
17
18
  queryFn?: typeof query;
18
19
  }
19
20
  /** Role briefing given to each agent session (SDK systemPrompt option). */
20
21
  export declare function buildRolePrompt(role: OrgRole, def: Pick<OrgDef, 'name' | 'goal'>, roster: string[]): string;
21
- /** Runs one persistent agent session; resolves when the mailbox closes and the SDK stream ends. */
22
+ /**
23
+ * Runs a role for the life of the org, transparently restarting the
24
+ * underlying SDK session whenever it ends on its own (`maxTurns` reached)
25
+ * while the mailbox is still open. `maxTurns` bounds a single SDK query()
26
+ * call's TOTAL turns, not "turns per incoming message" — since one query()
27
+ * call stays open across every mailbox message for as long as the mailbox
28
+ * itself stays open, without a restart the role would go permanently silent
29
+ * (no crash, no alert) once its lifetime turn count crossed the limit, while
30
+ * deliver() kept queuing new messages into a mailbox nobody was reading.
31
+ */
22
32
  export declare function runAgentSession(opts: SessionOpts): Promise<void>;
23
33
  //# sourceMappingURL=session.d.ts.map
@@ -12,12 +12,36 @@ export function buildRolePrompt(role, def, roster) {
12
12
  `## Communication protocol`,
13
13
  `The ONLY way to communicate with other agents is the org_send tool.`,
14
14
  `Roster: ${roster.join(', ')}. Address another org's agent as "<org-name>:<role-id>".`,
15
+ `If you need a human decision, call ask_human with your question, then end your turn — you'll receive the human's answer as a new message when it arrives. Do not call ask_human for anything you can resolve yourself.`,
15
16
  `When you receive a message, act on it, then org_send your result to the requester.`,
16
17
  `When your current work is complete and no reply is needed, end your turn without further tool calls.`,
17
18
  ].filter(Boolean).join('\n\n');
18
19
  }
19
- /** Runs one persistent agent session; resolves when the mailbox closes and the SDK stream ends. */
20
+ /**
21
+ * Runs a role for the life of the org, transparently restarting the
22
+ * underlying SDK session whenever it ends on its own (`maxTurns` reached)
23
+ * while the mailbox is still open. `maxTurns` bounds a single SDK query()
24
+ * call's TOTAL turns, not "turns per incoming message" — since one query()
25
+ * call stays open across every mailbox message for as long as the mailbox
26
+ * itself stays open, without a restart the role would go permanently silent
27
+ * (no crash, no alert) once its lifetime turn count crossed the limit, while
28
+ * deliver() kept queuing new messages into a mailbox nobody was reading.
29
+ */
20
30
  export async function runAgentSession(opts) {
31
+ const { mailbox } = opts;
32
+ // Always run at least once: a mailbox can be closed with queued items still
33
+ // pending (stream() drains the queue before honoring `closed`), which is a
34
+ // normal, valid starting state — checking isClosed before the first run
35
+ // would skip that drain entirely.
36
+ while (true) {
37
+ await runOneSession(opts);
38
+ if (mailbox.isClosed)
39
+ return;
40
+ opts.bus.emit({ type: 'status', from: opts.role.id, msg: 'session restarting (turn limit reached, mailbox still open)' });
41
+ }
42
+ }
43
+ /** One bounded SDK session for a role; resolves when the SDK stream ends (mailbox closed or maxTurns reached). */
44
+ async function runOneSession(opts) {
21
45
  const { org, role, bus, policy, mailbox, cwd, deliver } = opts;
22
46
  const queryFn = opts.queryFn ?? query;
23
47
  const orgServer = createSdkMcpServer({
@@ -28,6 +52,13 @@ export async function runAgentSession(opts) {
28
52
  const receipt = await deliver(role.id, args.to, args.subject, args.message);
29
53
  return { content: [{ type: 'text', text: receipt }] };
30
54
  }),
55
+ tool('ask_human', 'Ask a human a free-form question and pause for their answer. Use only when you genuinely need human judgment.', { question: z.string() }, async (args) => {
56
+ if (!opts.askHuman) {
57
+ return { content: [{ type: 'text', text: 'ask_human is not available in this session' }] };
58
+ }
59
+ const receipt = await opts.askHuman(role.id, args.question);
60
+ return { content: [{ type: 'text', text: receipt }] };
61
+ }),
31
62
  ],
32
63
  });
33
64
  bus.emit({ type: 'status', from: role.id, msg: 'session starting' });
@@ -1,10 +1,10 @@
1
1
  // packages/@monomind/cli/src/orgrt/test-loop.ts
2
2
  import { mkdirSync, writeFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
- import WebSocket from 'ws';
5
4
  import { OrgDaemon } from './daemon.js';
6
5
  import { startOrgServer } from './server.js';
7
6
  import { OrgBus } from './bus.js';
7
+ import { queueMessage } from './inbox.js';
8
8
  import { ORG_DIR } from './types.js';
9
9
  /**
10
10
  * Scripted fake SDK used by the verification loop (no API cost, deterministic).
@@ -73,20 +73,20 @@ export async function runTestLoop(root, times) {
73
73
  return scriptedQuery(roleId)(args);
74
74
  };
75
75
  const daemon = new OrgDaemon(root, { queryFn: queryFn, forward: false });
76
+ // xdeliver server for cross-process delivery (tested via the xorg check)
76
77
  const srv = await startOrgServer(daemon, 0);
77
- const wsEvents = [];
78
- const ws = new WebSocket(`ws://127.0.0.1:${srv.port}/ws`);
79
- ws.on('message', d => wsEvents.push(JSON.parse(d.toString())));
80
- await new Promise(r => ws.on('open', r));
78
+ daemon.setInboxUrl(`http://127.0.0.1:${srv.port}`);
79
+ // Queue a message for partner:boss BEFORE starting it — verifies inbox drain on startup
80
+ queueMessage(root, 'partner', { fromQualified: 'external:system', toRole: 'boss', subject: 'pre-start', body: 'queued while offline', ts: Date.now() });
81
81
  const alpha = await daemon.startOrg('alpha');
82
- await daemon.startOrg('partner');
82
+ const partner = await daemon.startOrg('partner');
83
83
  await waitFor(() => alpha.busEvents().some(e => e.type === 'message' && e.from === 'coder' && e.to === 'boss'));
84
84
  await daemon.stopAll();
85
- ws.close();
86
85
  srv.close();
87
86
  const evs = alpha.busEvents();
88
87
  const has = (pred) => evs.some(pred);
89
88
  const persistedCount = OrgBus.readHistory(join(root, ORG_DIR, 'alpha', alpha.run)).length;
89
+ const partnerEvs = partner.busEvents();
90
90
  const checks = {
91
91
  chat: has(e => e.type === 'chat'),
92
92
  message: has(e => e.type === 'message' && e.from === 'boss' && e.to === 'coder'),
@@ -95,8 +95,8 @@ export async function runTestLoop(root, times) {
95
95
  asset: has(e => e.type === 'asset' && (e.path ?? '').endsWith('out/report.md')),
96
96
  xorg: has(e => e.type === 'xorg' && e.to === 'partner:boss'),
97
97
  usage: has(e => e.type === 'usage'),
98
- wsDelivery: wsEvents.length > 0 && wsEvents.some(e => e.type === 'chat'),
99
98
  persisted: persistedCount === evs.length,
99
+ inboxDrain: partnerEvs.some(e => e.type === 'xorg' && e.from === 'external:system' && e.subject === 'pre-start'),
100
100
  };
101
101
  iterations.push({ checks, events: evs.length });
102
102
  }
@@ -8,14 +8,14 @@ export declare const ProviderSchema: z.ZodObject<{
8
8
  /** env var NAME holding the auth token for base-url providers */
9
9
  authTokenEnv: z.ZodOptional<z.ZodString>;
10
10
  }, "strict", z.ZodTypeAny, {
11
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
12
- baseUrl?: string | undefined;
11
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
13
12
  apiKeyEnv?: string | undefined;
13
+ baseUrl?: string | undefined;
14
14
  authTokenEnv?: string | undefined;
15
15
  }, {
16
- baseUrl?: string | undefined;
17
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
16
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
18
17
  apiKeyEnv?: string | undefined;
18
+ baseUrl?: string | undefined;
19
19
  authTokenEnv?: string | undefined;
20
20
  }>;
21
21
  export declare const RolePolicySchema: z.ZodObject<{
@@ -65,14 +65,14 @@ export declare const RoleSchema: z.ZodObject<{
65
65
  /** env var NAME holding the auth token for base-url providers */
66
66
  authTokenEnv: z.ZodOptional<z.ZodString>;
67
67
  }, "strict", z.ZodTypeAny, {
68
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
69
- baseUrl?: string | undefined;
68
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
70
69
  apiKeyEnv?: string | undefined;
70
+ baseUrl?: string | undefined;
71
71
  authTokenEnv?: string | undefined;
72
72
  }, {
73
- baseUrl?: string | undefined;
74
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
73
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
75
74
  apiKeyEnv?: string | undefined;
75
+ baseUrl?: string | undefined;
76
76
  authTokenEnv?: string | undefined;
77
77
  }>>;
78
78
  policy: z.ZodOptional<z.ZodObject<{
@@ -122,14 +122,14 @@ export declare const RoleSchema: z.ZodObject<{
122
122
  /** env var NAME holding the auth token for base-url providers */
123
123
  authTokenEnv: z.ZodOptional<z.ZodString>;
124
124
  }, "strict", z.ZodTypeAny, {
125
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
126
- baseUrl?: string | undefined;
125
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
127
126
  apiKeyEnv?: string | undefined;
127
+ baseUrl?: string | undefined;
128
128
  authTokenEnv?: string | undefined;
129
129
  }, {
130
- baseUrl?: string | undefined;
131
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
130
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
132
131
  apiKeyEnv?: string | undefined;
132
+ baseUrl?: string | undefined;
133
133
  authTokenEnv?: string | undefined;
134
134
  }>>;
135
135
  policy: z.ZodOptional<z.ZodObject<{
@@ -179,14 +179,14 @@ export declare const RoleSchema: z.ZodObject<{
179
179
  /** env var NAME holding the auth token for base-url providers */
180
180
  authTokenEnv: z.ZodOptional<z.ZodString>;
181
181
  }, "strict", z.ZodTypeAny, {
182
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
183
- baseUrl?: string | undefined;
182
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
184
183
  apiKeyEnv?: string | undefined;
184
+ baseUrl?: string | undefined;
185
185
  authTokenEnv?: string | undefined;
186
186
  }, {
187
- baseUrl?: string | undefined;
188
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
187
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
189
188
  apiKeyEnv?: string | undefined;
189
+ baseUrl?: string | undefined;
190
190
  authTokenEnv?: string | undefined;
191
191
  }>>;
192
192
  policy: z.ZodOptional<z.ZodObject<{
@@ -268,14 +268,14 @@ export declare const OrgDefSchema: z.ZodObject<{
268
268
  /** env var NAME holding the auth token for base-url providers */
269
269
  authTokenEnv: z.ZodOptional<z.ZodString>;
270
270
  }, "strict", z.ZodTypeAny, {
271
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
272
- baseUrl?: string | undefined;
271
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
273
272
  apiKeyEnv?: string | undefined;
273
+ baseUrl?: string | undefined;
274
274
  authTokenEnv?: string | undefined;
275
275
  }, {
276
- baseUrl?: string | undefined;
277
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
276
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
278
277
  apiKeyEnv?: string | undefined;
278
+ baseUrl?: string | undefined;
279
279
  authTokenEnv?: string | undefined;
280
280
  }>>;
281
281
  policy: z.ZodOptional<z.ZodObject<{
@@ -325,14 +325,14 @@ export declare const OrgDefSchema: z.ZodObject<{
325
325
  /** env var NAME holding the auth token for base-url providers */
326
326
  authTokenEnv: z.ZodOptional<z.ZodString>;
327
327
  }, "strict", z.ZodTypeAny, {
328
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
329
- baseUrl?: string | undefined;
328
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
330
329
  apiKeyEnv?: string | undefined;
330
+ baseUrl?: string | undefined;
331
331
  authTokenEnv?: string | undefined;
332
332
  }, {
333
- baseUrl?: string | undefined;
334
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
333
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
335
334
  apiKeyEnv?: string | undefined;
335
+ baseUrl?: string | undefined;
336
336
  authTokenEnv?: string | undefined;
337
337
  }>>;
338
338
  policy: z.ZodOptional<z.ZodObject<{
@@ -382,14 +382,14 @@ export declare const OrgDefSchema: z.ZodObject<{
382
382
  /** env var NAME holding the auth token for base-url providers */
383
383
  authTokenEnv: z.ZodOptional<z.ZodString>;
384
384
  }, "strict", z.ZodTypeAny, {
385
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
386
- baseUrl?: string | undefined;
385
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
387
386
  apiKeyEnv?: string | undefined;
387
+ baseUrl?: string | undefined;
388
388
  authTokenEnv?: string | undefined;
389
389
  }, {
390
- baseUrl?: string | undefined;
391
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
390
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
392
391
  apiKeyEnv?: string | undefined;
392
+ baseUrl?: string | undefined;
393
393
  authTokenEnv?: string | undefined;
394
394
  }>>;
395
395
  policy: z.ZodOptional<z.ZodObject<{
@@ -471,14 +471,14 @@ export declare const OrgDefSchema: z.ZodObject<{
471
471
  /** env var NAME holding the auth token for base-url providers */
472
472
  authTokenEnv: z.ZodOptional<z.ZodString>;
473
473
  }, "strict", z.ZodTypeAny, {
474
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
475
- baseUrl?: string | undefined;
474
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
476
475
  apiKeyEnv?: string | undefined;
476
+ baseUrl?: string | undefined;
477
477
  authTokenEnv?: string | undefined;
478
478
  }, {
479
- baseUrl?: string | undefined;
480
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
479
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
481
480
  apiKeyEnv?: string | undefined;
481
+ baseUrl?: string | undefined;
482
482
  authTokenEnv?: string | undefined;
483
483
  }>>;
484
484
  policy: z.ZodOptional<z.ZodObject<{
@@ -528,14 +528,14 @@ export declare const OrgDefSchema: z.ZodObject<{
528
528
  /** env var NAME holding the auth token for base-url providers */
529
529
  authTokenEnv: z.ZodOptional<z.ZodString>;
530
530
  }, "strict", z.ZodTypeAny, {
531
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
532
- baseUrl?: string | undefined;
531
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
533
532
  apiKeyEnv?: string | undefined;
533
+ baseUrl?: string | undefined;
534
534
  authTokenEnv?: string | undefined;
535
535
  }, {
536
- baseUrl?: string | undefined;
537
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
536
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
538
537
  apiKeyEnv?: string | undefined;
538
+ baseUrl?: string | undefined;
539
539
  authTokenEnv?: string | undefined;
540
540
  }>>;
541
541
  policy: z.ZodOptional<z.ZodObject<{
@@ -585,14 +585,14 @@ export declare const OrgDefSchema: z.ZodObject<{
585
585
  /** env var NAME holding the auth token for base-url providers */
586
586
  authTokenEnv: z.ZodOptional<z.ZodString>;
587
587
  }, "strict", z.ZodTypeAny, {
588
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
589
- baseUrl?: string | undefined;
588
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
590
589
  apiKeyEnv?: string | undefined;
590
+ baseUrl?: string | undefined;
591
591
  authTokenEnv?: string | undefined;
592
592
  }, {
593
- baseUrl?: string | undefined;
594
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
593
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
595
594
  apiKeyEnv?: string | undefined;
595
+ baseUrl?: string | undefined;
596
596
  authTokenEnv?: string | undefined;
597
597
  }>>;
598
598
  policy: z.ZodOptional<z.ZodObject<{
@@ -674,14 +674,14 @@ export declare const OrgDefSchema: z.ZodObject<{
674
674
  /** env var NAME holding the auth token for base-url providers */
675
675
  authTokenEnv: z.ZodOptional<z.ZodString>;
676
676
  }, "strict", z.ZodTypeAny, {
677
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
678
- baseUrl?: string | undefined;
677
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
679
678
  apiKeyEnv?: string | undefined;
679
+ baseUrl?: string | undefined;
680
680
  authTokenEnv?: string | undefined;
681
681
  }, {
682
- baseUrl?: string | undefined;
683
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
682
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
684
683
  apiKeyEnv?: string | undefined;
684
+ baseUrl?: string | undefined;
685
685
  authTokenEnv?: string | undefined;
686
686
  }>>;
687
687
  policy: z.ZodOptional<z.ZodObject<{
@@ -731,14 +731,14 @@ export declare const OrgDefSchema: z.ZodObject<{
731
731
  /** env var NAME holding the auth token for base-url providers */
732
732
  authTokenEnv: z.ZodOptional<z.ZodString>;
733
733
  }, "strict", z.ZodTypeAny, {
734
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
735
- baseUrl?: string | undefined;
734
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
736
735
  apiKeyEnv?: string | undefined;
736
+ baseUrl?: string | undefined;
737
737
  authTokenEnv?: string | undefined;
738
738
  }, {
739
- baseUrl?: string | undefined;
740
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
739
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
741
740
  apiKeyEnv?: string | undefined;
741
+ baseUrl?: string | undefined;
742
742
  authTokenEnv?: string | undefined;
743
743
  }>>;
744
744
  policy: z.ZodOptional<z.ZodObject<{
@@ -788,14 +788,14 @@ export declare const OrgDefSchema: z.ZodObject<{
788
788
  /** env var NAME holding the auth token for base-url providers */
789
789
  authTokenEnv: z.ZodOptional<z.ZodString>;
790
790
  }, "strict", z.ZodTypeAny, {
791
- kind: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex";
792
- baseUrl?: string | undefined;
791
+ kind: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex";
793
792
  apiKeyEnv?: string | undefined;
793
+ baseUrl?: string | undefined;
794
794
  authTokenEnv?: string | undefined;
795
795
  }, {
796
- baseUrl?: string | undefined;
797
- kind?: "api-key" | "subscription" | "base-url" | "bedrock" | "vertex" | undefined;
796
+ kind?: "api-key" | "base-url" | "bedrock" | "subscription" | "vertex" | undefined;
798
797
  apiKeyEnv?: string | undefined;
798
+ baseUrl?: string | undefined;
799
799
  authTokenEnv?: string | undefined;
800
800
  }>>;
801
801
  policy: z.ZodOptional<z.ZodObject<{
@@ -832,7 +832,7 @@ export interface BusEvent {
832
832
  ts: number;
833
833
  org: string;
834
834
  run: string;
835
- type: 'message' | 'xorg' | 'tool' | 'asset' | 'chat' | 'status' | 'audit' | 'usage';
835
+ type: 'message' | 'xorg' | 'tool' | 'asset' | 'chat' | 'status' | 'audit' | 'usage' | 'question';
836
836
  from?: string;
837
837
  to?: string;
838
838
  subject?: string;
@@ -4,35 +4,35 @@
4
4
  */
5
5
  import type { TableOptions, ProgressOptions, SpinnerOptions } from './types.js';
6
6
  declare const COLORS: {
7
- readonly reset: "\u001B[0m";
8
- readonly bold: "\u001B[1m";
9
- readonly dim: "\u001B[2m";
10
- readonly italic: "\u001B[3m";
11
- readonly underline: "\u001B[4m";
12
- readonly black: "\u001B[30m";
13
- readonly red: "\u001B[31m";
14
- readonly green: "\u001B[32m";
15
- readonly yellow: "\u001B[33m";
16
- readonly blue: "\u001B[34m";
17
- readonly magenta: "\u001B[35m";
18
- readonly cyan: "\u001B[36m";
19
- readonly white: "\u001B[37m";
20
- readonly gray: "\u001B[90m";
21
- readonly brightRed: "\u001B[91m";
22
- readonly brightGreen: "\u001B[92m";
23
- readonly brightYellow: "\u001B[93m";
24
- readonly brightBlue: "\u001B[94m";
25
- readonly brightMagenta: "\u001B[95m";
26
- readonly brightCyan: "\u001B[96m";
27
- readonly brightWhite: "\u001B[97m";
28
- readonly bgBlack: "\u001B[40m";
29
- readonly bgRed: "\u001B[41m";
30
- readonly bgGreen: "\u001B[42m";
31
- readonly bgYellow: "\u001B[43m";
32
- readonly bgBlue: "\u001B[44m";
33
- readonly bgMagenta: "\u001B[45m";
34
- readonly bgCyan: "\u001B[46m";
35
- readonly bgWhite: "\u001B[47m";
7
+ readonly reset: '\u001B[0m';
8
+ readonly bold: '\u001B[1m';
9
+ readonly dim: '\u001B[2m';
10
+ readonly italic: '\u001B[3m';
11
+ readonly underline: '\u001B[4m';
12
+ readonly black: '\u001B[30m';
13
+ readonly red: '\u001B[31m';
14
+ readonly green: '\u001B[32m';
15
+ readonly yellow: '\u001B[33m';
16
+ readonly blue: '\u001B[34m';
17
+ readonly magenta: '\u001B[35m';
18
+ readonly cyan: '\u001B[36m';
19
+ readonly white: '\u001B[37m';
20
+ readonly gray: '\u001B[90m';
21
+ readonly brightRed: '\u001B[91m';
22
+ readonly brightGreen: '\u001B[92m';
23
+ readonly brightYellow: '\u001B[93m';
24
+ readonly brightBlue: '\u001B[94m';
25
+ readonly brightMagenta: '\u001B[95m';
26
+ readonly brightCyan: '\u001B[96m';
27
+ readonly brightWhite: '\u001B[97m';
28
+ readonly bgBlack: '\u001B[40m';
29
+ readonly bgRed: '\u001B[41m';
30
+ readonly bgGreen: '\u001B[42m';
31
+ readonly bgYellow: '\u001B[43m';
32
+ readonly bgBlue: '\u001B[44m';
33
+ readonly bgMagenta: '\u001B[45m';
34
+ readonly bgCyan: '\u001B[46m';
35
+ readonly bgWhite: '\u001B[47m';
36
36
  };
37
37
  type ColorName = keyof typeof COLORS;
38
38
  export type VerbosityLevel = 'quiet' | 'normal' | 'verbose' | 'debug';
@@ -484,6 +484,14 @@ export class Spinner {
484
484
  start() {
485
485
  if (this.interval)
486
486
  return;
487
+ // `\r`-based in-place redraw only works on a real TTY. Without one
488
+ // (piped output, CI logs, non-interactive terminals) each animation
489
+ // frame prints as its own line instead of overwriting the last —
490
+ // so print the text once and skip the animation entirely.
491
+ if (!process.stdout.isTTY) {
492
+ process.stdout.write(`${this.text}\n`);
493
+ return;
494
+ }
487
495
  this.interval = setInterval(() => {
488
496
  this.render();
489
497
  this.frameIndex = (this.frameIndex + 1) % this.frames.length;
@@ -495,9 +503,9 @@ export class Spinner {
495
503
  if (this.interval) {
496
504
  clearInterval(this.interval);
497
505
  this.interval = null;
506
+ // Clear the line (only meaningful when the animation actually ran on a TTY)
507
+ process.stdout.write('\r' + ' '.repeat(this.text.length + 10) + '\r');
498
508
  }
499
- // Clear the line
500
- process.stdout.write('\r' + ' '.repeat(this.text.length + 10) + '\r');
501
509
  if (message) {
502
510
  this.formatter.writeln(message);
503
511
  }
@@ -7,7 +7,7 @@
7
7
  * cw — cache-write tokens
8
8
  * cr — cache-read tokens
9
9
  *
10
- * Consumers: dist/src/ui/collector.mjs and dist/src/ui/server.mjs both
10
+ * Consumers: src/ui/collector.mjs and src/ui/server.mjs both
11
11
  * derive their inline pricing tables from this canonical list.
12
12
  */
13
13
  export interface ModelPrice {
@@ -184,7 +184,7 @@ export interface MultiSelectPromptOptions<T = string> {
184
184
  export declare class CLIError extends Error {
185
185
  code: string;
186
186
  exitCode: number;
187
- details?: unknown | undefined;
188
- constructor(message: string, code: string, exitCode?: number, details?: unknown | undefined);
187
+ details?: unknown;
188
+ constructor(message: string, code: string, exitCode?: number, details?: unknown);
189
189
  }
190
190
  //# sourceMappingURL=types.d.ts.map
@@ -640,15 +640,30 @@ function slugToPath(slug) {
640
640
  }
641
641
 
642
642
  // Reconstruct the real filesystem path from a Claude project slug.
643
- // Slugs encode the path with every '/' replaced by '-', which is lossy when
644
- // directory names contain literal hyphens (e.g. /Desktop/agent-f/accounting).
645
- // Strategy: naive replace first; if not found, greedy DFS through the filesystem
646
- // trying longest-possible segment (with embedded hyphens) at each level.
643
+ // Slugs encode the path with every '/' AND '.' replaced by '-' (so a hidden
644
+ // directory like '.claude' shows up as a bare '--claude', i.e. an empty split
645
+ // token immediately before 'claude' e.g. the real path
646
+ // '/monomind/.claude/worktrees/foo' slugs to '-monomind--claude-worktrees-foo').
647
+ // Also lossy when directory names contain literal hyphens (e.g.
648
+ // /Desktop/agent-f/accounting). Strategy: naive replace first; if not found,
649
+ // greedy DFS through the filesystem trying longest-possible segment (with
650
+ // embedded hyphens) at each level.
647
651
  function resolveSlugPath(slug) {
648
652
  const naive = '/' + slug.replace(/^-/, '').replace(/-/g, '/');
649
653
  try { if (fs.existsSync(naive)) return naive; } catch {}
650
654
 
651
- const tokens = slug.replace(/^-/, '').split('-').filter(Boolean);
655
+ // An empty token between two hyphens marks a collapsed '.' — reattach it to
656
+ // the following token instead of dropping it, so hidden directories survive
657
+ // reconstruction (dropping it silently turns '.claude' into 'claude', which
658
+ // never exists on disk, sending the walk down the wrong path entirely).
659
+ const rawTokens = slug.replace(/^-/, '').split('-');
660
+ const tokens = [];
661
+ let pendingDot = false;
662
+ for (const part of rawTokens) {
663
+ if (part === '') { pendingDot = true; continue; }
664
+ tokens.push(pendingDot ? '.' + part : part);
665
+ pendingDot = false;
666
+ }
652
667
 
653
668
  function walk(idx, dir) {
654
669
  if (idx === tokens.length) return dir;