@nex-ai/nex 0.1.28 → 0.1.30

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 (69) hide show
  1. package/README.md +25 -8
  2. package/dist/agent/message-router.d.ts +26 -0
  3. package/dist/agent/message-router.js +114 -0
  4. package/dist/agent/message-router.js.map +1 -0
  5. package/dist/agent/orchestrate.d.ts +26 -0
  6. package/dist/agent/orchestrate.js +87 -0
  7. package/dist/agent/orchestrate.js.map +1 -0
  8. package/dist/agent/providers/types.d.ts +5 -0
  9. package/dist/agent/providers/types.js +2 -0
  10. package/dist/agent/providers/types.js.map +1 -0
  11. package/dist/agent/queues.d.ts +1 -0
  12. package/dist/agent/queues.js +3 -0
  13. package/dist/agent/queues.js.map +1 -1
  14. package/dist/agent/templates.js +10 -3
  15. package/dist/agent/templates.js.map +1 -1
  16. package/dist/agent/tick-manager.d.ts +20 -0
  17. package/dist/agent/tick-manager.js +50 -0
  18. package/dist/agent/tick-manager.js.map +1 -0
  19. package/dist/commands/dispatch.d.ts +5 -0
  20. package/dist/commands/dispatch.js +120 -0
  21. package/dist/commands/dispatch.js.map +1 -1
  22. package/dist/commands/init.d.ts +1 -1
  23. package/dist/commands/init.js +11 -19
  24. package/dist/commands/init.js.map +1 -1
  25. package/dist/commands/setup.js +9 -11
  26. package/dist/commands/setup.js.map +1 -1
  27. package/dist/index.js +90 -22
  28. package/dist/index.js.map +1 -1
  29. package/dist/lib/claude-code-installer.d.ts +8 -0
  30. package/dist/lib/claude-code-installer.js +76 -0
  31. package/dist/lib/claude-code-installer.js.map +1 -0
  32. package/dist/lib/errors.js +1 -1
  33. package/dist/lib/errors.js.map +1 -1
  34. package/dist/lib/installers.d.ts +4 -0
  35. package/dist/lib/installers.js +8 -4
  36. package/dist/lib/installers.js.map +1 -1
  37. package/dist/lib/nex-mcp-config.d.ts +11 -4
  38. package/dist/lib/nex-mcp-config.js +15 -8
  39. package/dist/lib/nex-mcp-config.js.map +1 -1
  40. package/dist/plugin/auto-capture.js +1 -0
  41. package/dist/plugin/auto-capture.js.map +1 -1
  42. package/dist/plugin/auto-register.d.ts +1 -1
  43. package/dist/plugin/auto-register.js +13 -8
  44. package/dist/plugin/auto-register.js.map +1 -1
  45. package/dist/plugin/config.d.ts +7 -16
  46. package/dist/plugin/config.js +16 -36
  47. package/dist/plugin/config.js.map +1 -1
  48. package/dist/plugin/nex-client.js +1 -1
  49. package/dist/plugin/nex-client.js.map +1 -1
  50. package/dist/plugin/shared.d.ts +1 -0
  51. package/dist/plugin/shared.js +134 -4
  52. package/dist/plugin/shared.js.map +1 -1
  53. package/dist/tui/app.js +10 -105
  54. package/dist/tui/app.js.map +1 -1
  55. package/dist/tui/components/agent-roster.d.ts +7 -0
  56. package/dist/tui/components/agent-roster.js +66 -0
  57. package/dist/tui/components/agent-roster.js.map +1 -0
  58. package/dist/tui/register-views.js +7 -1
  59. package/dist/tui/register-views.js.map +1 -1
  60. package/dist/tui/services/agent-service.d.ts +2 -0
  61. package/dist/tui/services/agent-service.js +5 -0
  62. package/dist/tui/services/agent-service.js.map +1 -1
  63. package/dist/tui/slash-commands.d.ts +2 -0
  64. package/dist/tui/slash-commands.js +151 -8
  65. package/dist/tui/slash-commands.js.map +1 -1
  66. package/dist/tui/views/stream.d.ts +19 -0
  67. package/dist/tui/views/stream.js +343 -0
  68. package/dist/tui/views/stream.js.map +1 -0
  69. package/package.json +2 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![GitHub](https://img.shields.io/badge/github-nex--crm%2Fnex--as--a--skill-blue)](https://github.com/nex-crm/nex-as-a-skill)
5
5
  [![Discord](https://img.shields.io/badge/Discord-Join%20Community-5865F2?logo=discord&logoColor=white)](https://discord.gg/gjSySC3PzV)
6
6
 
7
- Turn all your AI agent conversations into a unified knowledge graph. Supports Claude Code, Codex, OpenClaw, Cursor, OpenCode, etc. Adds additional context from Email, Meetings, Slack, HubSpot, Salesforce.
7
+ Turn all your AI agent conversations into a unified knowledge graph with proactive context surfacing. Supports Claude Code, Codex, OpenClaw, Cursor, OpenCode, etc. Adds additional context from Email, Meetings, Slack, HubSpot, Salesforce.
8
8
 
9
9
  <a href="https://discord.gg/gjSySC3PzV"><img src="https://img.shields.io/badge/Join%20our%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Join our Discord" /></a>
10
10
 
@@ -16,7 +16,7 @@ Talk to the team, share feedback, and connect with other developers building AI
16
16
 
17
17
  ```bash
18
18
  # Install globally
19
- bun install -g @nex-ai/nex
19
+ npm install -g @nex-ai/nex
20
20
 
21
21
  # Or run directly (no install)
22
22
  npx @nex-ai/nex ask "who is Maria?"
@@ -102,9 +102,9 @@ nex graph # Open the workspace graph in your browser
102
102
  - Installs the full 6-layer hierarchy for each detected platform: hooks → plugins → agents → workflows → rules → MCP
103
103
  - Scans current directory and ingests new/changed files into Nex
104
104
  - Creates `.nex.toml` project config with commented defaults
105
- - Syncs API key to `~/.nex-mcp.json` (shared config)
105
+ - Stores config in `~/.nex/config.json`
106
106
 
107
- **Single install**: `bun install -g @nex-ai/nex` bundles everything — hooks, adapters, platform plugins, slash commands, rules, and MCP server. No separate packages needed.
107
+ **Single install**: `npm install -g @nex-ai/nex` bundles everything — hooks, adapters, platform plugins, slash commands, rules, and MCP server. No separate packages needed.
108
108
 
109
109
  **Integration hierarchy** (per platform): Hooks > Custom plugins > Custom agents/modes > Workflows > Rules > MCP. Each platform gets every layer it supports.
110
110
 
@@ -120,8 +120,8 @@ Per-project settings file created by `nex setup`. All fields are optional.
120
120
  # enabled = true # Master kill switch for all hooks
121
121
 
122
122
  [hooks.recall]
123
- # enabled = true # Auto-recall context on each prompt
124
- # debounce_ms = 30000
123
+ # enabled = true # Proactive context on every prompt
124
+ # debounce_ms = 10000
125
125
 
126
126
  [hooks.capture]
127
127
  # enabled = true # Auto-capture on conversation stop
@@ -135,7 +135,7 @@ Per-project settings file created by `nex setup`. All fields are optional.
135
135
  # enabled = true
136
136
  # extensions = [".md", ".txt", ".csv", ".json", ".yaml", ".yml"]
137
137
  # ignore_dirs = ["node_modules", ".git", "dist", "build", "__pycache__"]
138
- # max_files = 5
138
+ # max_files = 1000
139
139
  # max_file_size = 100000
140
140
  # depth = 2
141
141
 
@@ -208,7 +208,14 @@ nex list-job create "enterprise contacts in EMEA"
208
208
 
209
209
  ### File Scanning
210
210
 
211
- On session start, Nex automatically scans project files and ingests changed content.
211
+ On session start, Nex automatically scans project files and ingests changed content using concurrent workers (5 parallel requests). After ingestion, compounding intelligence jobs are triggered automatically to generate patterns and playbook rules.
212
+
213
+ ```bash
214
+ nex scan # Scan current directory (up to 1000 files)
215
+ nex scan --max-files 500 # Limit files per scan
216
+ nex scan --force # Re-scan all files (ignore manifest)
217
+ nex scan --dry-run # Preview what would be scanned
218
+ ```
212
219
 
213
220
  **Default text-based extensions:** `.md`, `.txt`, `.csv`, `.json`, `.yaml`, `.yml`
214
221
 
@@ -216,6 +223,16 @@ On session start, Nex automatically scans project files and ingests changed cont
216
223
 
217
224
  Configure via `.nex.toml` `[scan]` section or environment variables (`NEX_SCAN_ENABLED`, `NEX_SCAN_EXTENSIONS`, etc.).
218
225
 
226
+ ### Proactive Context
227
+
228
+ Nex surfaces relevant knowledge graph context on every prompt — not just questions. When you say "fix the migration script" or "deploy to staging", the system automatically injects entity insights, knowledge insights, and playbook patterns from your knowledge graph.
229
+
230
+ Context is injected as `<nex-context>` blocks that AI agents use naturally without explicitly referencing the source. Only trivial inputs (yes/ok/lgtm) are skipped.
231
+
232
+ ### Transcript Capture
233
+
234
+ At session end, the full conversation transcript is automatically ingested into the knowledge graph. This captures complete decision trails, code discussions, and debugging sessions — not just the last message.
235
+
219
236
  ### Config & Sessions
220
237
 
221
238
  ```bash
@@ -0,0 +1,26 @@
1
+ /**
2
+ * MessageRouter: routes incoming messages to the best-fit agent
3
+ * using TaskRouter for skill scoring and thread-detection heuristics
4
+ * for follow-up messages.
5
+ */
6
+ export interface RoutingResult {
7
+ primary: string;
8
+ collaborators: string[];
9
+ isFollowUp: boolean;
10
+ teamLeadAware: boolean;
11
+ }
12
+ export declare class MessageRouter {
13
+ private router;
14
+ private recentThreads;
15
+ private FOLLOWUP_WINDOW_MS;
16
+ registerAgent(slug: string, expertise: string[]): void;
17
+ unregisterAgent(slug: string): void;
18
+ recordAgentActivity(agentSlug: string): void;
19
+ route(message: string, availableAgents: Array<{
20
+ slug: string;
21
+ expertise: string[];
22
+ }>): RoutingResult;
23
+ private detectFollowUp;
24
+ /** Extract skill keywords from a message using pattern matching. */
25
+ extractSkills(message: string): string[];
26
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * MessageRouter: routes incoming messages to the best-fit agent
3
+ * using TaskRouter for skill scoring and thread-detection heuristics
4
+ * for follow-up messages.
5
+ */
6
+ import { TaskRouter } from '../orchestration/router.js';
7
+ export class MessageRouter {
8
+ router = new TaskRouter();
9
+ recentThreads = new Map();
10
+ FOLLOWUP_WINDOW_MS = 30_000;
11
+ registerAgent(slug, expertise) {
12
+ this.router.registerAgent(slug, expertise.map((e) => ({ name: e, description: e, proficiency: 0.8 })));
13
+ }
14
+ unregisterAgent(slug) {
15
+ this.router.unregisterAgent(slug);
16
+ }
17
+ recordAgentActivity(agentSlug) {
18
+ this.recentThreads.set(agentSlug, { agentSlug, lastActivity: Date.now() });
19
+ }
20
+ route(message, availableAgents) {
21
+ // Step 1: Thread detection
22
+ const followUp = this.detectFollowUp(message);
23
+ if (followUp) {
24
+ return { primary: followUp, collaborators: [], isFollowUp: true, teamLeadAware: false };
25
+ }
26
+ // Step 2: Extract skills from message using keyword patterns
27
+ const requiredSkills = this.extractSkills(message);
28
+ // No recognized skills → route to team-lead for triage
29
+ if (requiredSkills.length === 0) {
30
+ return { primary: 'team-lead', collaborators: [], isFollowUp: false, teamLeadAware: false };
31
+ }
32
+ // Step 3: Register agents (ensure current state) and score
33
+ for (const agent of availableAgents) {
34
+ this.registerAgent(agent.slug, agent.expertise);
35
+ }
36
+ const task = {
37
+ id: `route-${Date.now()}`,
38
+ title: message,
39
+ description: message,
40
+ requiredSkills,
41
+ priority: 'medium',
42
+ status: 'pending',
43
+ createdAt: Date.now(),
44
+ };
45
+ const capable = this.router.findCapableAgents(task);
46
+ if (capable.length === 0) {
47
+ return { primary: 'team-lead', collaborators: [], isFollowUp: false, teamLeadAware: false };
48
+ }
49
+ const primary = capable[0].agentSlug;
50
+ const collaborators = capable
51
+ .slice(1)
52
+ .filter((c) => c.score > 0.5)
53
+ .map((c) => c.agentSlug);
54
+ return {
55
+ primary,
56
+ collaborators,
57
+ isFollowUp: false,
58
+ teamLeadAware: primary !== 'team-lead',
59
+ };
60
+ }
61
+ detectFollowUp(message) {
62
+ const now = Date.now();
63
+ const followUpPatterns = /^(also|and |too |that |it |the results|those |these |this |what about|how about|can you also)/i;
64
+ if (!followUpPatterns.test(message.trim()))
65
+ return null;
66
+ // Find most recent active thread within window
67
+ let mostRecent = null;
68
+ for (const [, ctx] of this.recentThreads) {
69
+ if (now - ctx.lastActivity <= this.FOLLOWUP_WINDOW_MS) {
70
+ if (!mostRecent || ctx.lastActivity > mostRecent.lastActivity) {
71
+ mostRecent = ctx;
72
+ }
73
+ }
74
+ }
75
+ return mostRecent?.agentSlug ?? null;
76
+ }
77
+ /** Extract skill keywords from a message using pattern matching. */
78
+ extractSkills(message) {
79
+ const skillPatterns = [
80
+ {
81
+ pattern: /\b(research|investigate|analyze|analysis|competitor)\b/i,
82
+ skills: ['market-research', 'competitive-analysis'],
83
+ },
84
+ {
85
+ pattern: /\b(leads?|prospect|outreach|prospecting|pipeline)\b/i,
86
+ skills: ['prospecting', 'outreach'],
87
+ },
88
+ {
89
+ pattern: /\b(enrich|validate|data quality|fill in|complete)\b/i,
90
+ skills: ['data-enrichment', 'validation'],
91
+ },
92
+ {
93
+ pattern: /\b(seo|keyword|search visibility|ranking|content)\b/i,
94
+ skills: ['seo', 'content-analysis'],
95
+ },
96
+ {
97
+ pattern: /\b(customer|success|health|renewal|churn|retention)\b/i,
98
+ skills: ['relationship-management', 'health-scoring'],
99
+ },
100
+ {
101
+ pattern: /\b(code|bug|fix|implement|build|deploy|test)\b/i,
102
+ skills: ['general', 'planning'],
103
+ },
104
+ ];
105
+ const skills = [];
106
+ for (const { pattern, skills: matchedSkills } of skillPatterns) {
107
+ if (pattern.test(message)) {
108
+ skills.push(...matchedSkills);
109
+ }
110
+ }
111
+ return [...new Set(skills)];
112
+ }
113
+ }
114
+ //# sourceMappingURL=message-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-router.js","sourceRoot":"","sources":["../../src/agent/message-router.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAexD,MAAM,OAAO,aAAa;IAChB,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;IAC1B,aAAa,GAAG,IAAI,GAAG,EAAyB,CAAC;IACjD,kBAAkB,GAAG,MAAM,CAAC;IAEpC,aAAa,CAAC,IAAY,EAAE,SAAmB;QAC7C,IAAI,CAAC,MAAM,CAAC,aAAa,CACvB,IAAI,EACJ,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,CACtE,CAAC;IACJ,CAAC;IAED,eAAe,CAAC,IAAY;QAC1B,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,mBAAmB,CAAC,SAAiB;QACnC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,KAAK,CACH,OAAe,EACf,eAA6D;QAE7D,2BAA2B;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QAC1F,CAAC;QAED,6DAA6D;QAC7D,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAEnD,uDAAuD;QACvD,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QAC9F,CAAC;QAED,2DAA2D;QAC3D,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;YACpC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,IAAI,GAAmB;YAC3B,EAAE,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,EAAE;YACzB,KAAK,EAAE,OAAO;YACd,WAAW,EAAE,OAAO;YACpB,cAAc;YACd,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAEpD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QAC9F,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrC,MAAM,aAAa,GAAG,OAAO;aAC1B,KAAK,CAAC,CAAC,CAAC;aACR,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC;aAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAE3B,OAAO;YACL,OAAO;YACP,aAAa;YACb,UAAU,EAAE,KAAK;YACjB,aAAa,EAAE,OAAO,KAAK,WAAW;SACvC,CAAC;IACJ,CAAC;IAEO,cAAc,CAAC,OAAe;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,gBAAgB,GACpB,gGAAgG,CAAC;QAEnG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QAExD,+CAA+C;QAC/C,IAAI,UAAU,GAAyB,IAAI,CAAC;QAC5C,KAAK,MAAM,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACzC,IAAI,GAAG,GAAG,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACtD,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,YAAY,GAAG,UAAU,CAAC,YAAY,EAAE,CAAC;oBAC9D,UAAU,GAAG,GAAG,CAAC;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,UAAU,EAAE,SAAS,IAAI,IAAI,CAAC;IACvC,CAAC;IAED,oEAAoE;IACpE,aAAa,CAAC,OAAe;QAC3B,MAAM,aAAa,GAAiD;YAClE;gBACE,OAAO,EAAE,yDAAyD;gBAClE,MAAM,EAAE,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;aACpD;YACD;gBACE,OAAO,EAAE,sDAAsD;gBAC/D,MAAM,EAAE,CAAC,aAAa,EAAE,UAAU,CAAC;aACpC;YACD;gBACE,OAAO,EAAE,sDAAsD;gBAC/D,MAAM,EAAE,CAAC,iBAAiB,EAAE,YAAY,CAAC;aAC1C;YACD;gBACE,OAAO,EAAE,sDAAsD;gBAC/D,MAAM,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC;aACpC;YACD;gBACE,OAAO,EAAE,wDAAwD;gBACjE,MAAM,EAAE,CAAC,yBAAyB,EAAE,gBAAgB,CAAC;aACtD;YACD;gBACE,OAAO,EAAE,iDAAiD;gBAC1D,MAAM,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;aAChC;SACF,CAAC;QAEF,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,aAAa,EAAE,CAAC;YAC/D,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1B,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Objective-first delegation: Team-Lead decomposes objectives
3
+ * and routes sub-tasks to specialist agents via steer messages.
4
+ *
5
+ * Uses the orchestration TaskRouter for skill matching and
6
+ * MessageQueues for non-blocking delegation.
7
+ */
8
+ import type { AgentConfig } from './types.js';
9
+ import type { MessageQueues } from './queues.js';
10
+ /** Extract actionable sub-tasks from the Team-Lead's response text. */
11
+ export declare function extractSubTasks(response: string): Array<{
12
+ action: string;
13
+ skills: string[];
14
+ }>;
15
+ export interface Specialist {
16
+ config: AgentConfig;
17
+ }
18
+ /**
19
+ * Delegate sub-tasks to specialist agents.
20
+ * Non-blocking: sends steer messages to matching specialists
21
+ * so they pick up work on their next tick.
22
+ */
23
+ export declare function delegateToSpecialists(response: string, specialists: Specialist[], queues: MessageQueues): Array<{
24
+ agentSlug: string;
25
+ task: string;
26
+ }>;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Objective-first delegation: Team-Lead decomposes objectives
3
+ * and routes sub-tasks to specialist agents via steer messages.
4
+ *
5
+ * Uses the orchestration TaskRouter for skill matching and
6
+ * MessageQueues for non-blocking delegation.
7
+ */
8
+ import { TaskRouter } from '../orchestration/router.js';
9
+ import { getAgentService } from '../tui/services/agent-service.js';
10
+ /** Map agent expertise strings to SkillDeclarations for the router. */
11
+ function expertiseToSkills(expertise) {
12
+ return expertise.map(e => ({
13
+ name: e,
14
+ description: e,
15
+ proficiency: 0.8,
16
+ }));
17
+ }
18
+ /** Extract actionable sub-tasks from the Team-Lead's response text. */
19
+ export function extractSubTasks(response) {
20
+ const subTasks = [];
21
+ // Skill keyword mapping — matches action words to required expertise
22
+ const skillPatterns = [
23
+ { pattern: /\b(research|investigate|analyze|analysis)\b/i, skills: ['research', 'market-research', 'competitive-analysis'] },
24
+ { pattern: /\b(find leads|generate leads|prospect|outreach|prospecting)\b/i, skills: ['prospecting', 'enrichment', 'outreach'] },
25
+ { pattern: /\b(enrich|validate|fill in|complete data|data quality)\b/i, skills: ['data-enrichment', 'research', 'validation'] },
26
+ { pattern: /\b(seo|keyword|search visibility|content.?analysis|ranking)\b/i, skills: ['seo', 'content-analysis', 'keyword-research'] },
27
+ { pattern: /\b(customer success|health score|renewal|churn|retention)\b/i, skills: ['relationship-management', 'health-scoring', 'renewal-tracking'] },
28
+ ];
29
+ // Split response into sentences and look for action-oriented ones
30
+ const sentences = response.split(/[.!?\n]+/).map(s => s.trim()).filter(Boolean);
31
+ for (const sentence of sentences) {
32
+ for (const { pattern, skills } of skillPatterns) {
33
+ if (pattern.test(sentence)) {
34
+ // Avoid duplicates
35
+ if (!subTasks.some(t => t.action === sentence)) {
36
+ subTasks.push({ action: sentence, skills });
37
+ }
38
+ }
39
+ }
40
+ }
41
+ return subTasks;
42
+ }
43
+ /**
44
+ * Delegate sub-tasks to specialist agents.
45
+ * Non-blocking: sends steer messages to matching specialists
46
+ * so they pick up work on their next tick.
47
+ */
48
+ export function delegateToSpecialists(response, specialists, queues) {
49
+ if (specialists.length === 0)
50
+ return [];
51
+ const subTasks = extractSubTasks(response);
52
+ if (subTasks.length === 0)
53
+ return [];
54
+ // Build a router with registered specialists
55
+ const router = new TaskRouter();
56
+ for (const spec of specialists) {
57
+ router.registerAgent(spec.config.slug, expertiseToSkills(spec.config.expertise));
58
+ }
59
+ const delegated = [];
60
+ for (const subTask of subTasks) {
61
+ const taskDef = {
62
+ id: `delegate-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
63
+ title: subTask.action,
64
+ description: subTask.action,
65
+ requiredSkills: subTask.skills,
66
+ priority: 'medium',
67
+ status: 'pending',
68
+ createdAt: Date.now(),
69
+ };
70
+ const best = router.findBestAgent(taskDef);
71
+ if (best && best.score > 0.1) {
72
+ // Steer the specialist with the sub-task
73
+ queues.steer(best.agentSlug, `[TEAM-LEAD DELEGATION] ${subTask.action}`);
74
+ delegated.push({ agentSlug: best.agentSlug, task: subTask.action });
75
+ // Ensure specialist agent tick loop is running
76
+ try {
77
+ const agentService = getAgentService();
78
+ agentService.ensureRunning(best.agentSlug);
79
+ }
80
+ catch {
81
+ // AgentService may not be initialized yet — delegation still succeeds via queue
82
+ }
83
+ }
84
+ }
85
+ return delegated;
86
+ }
87
+ //# sourceMappingURL=orchestrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrate.js","sourceRoot":"","sources":["../../src/agent/orchestrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export type LLMProvider = 'gemini' | 'claude-code';
2
+ export interface ProviderConfig {
3
+ provider: LLMProvider;
4
+ geminiApiKey?: string;
5
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/agent/providers/types.ts"],"names":[],"mappings":""}
@@ -13,4 +13,5 @@ export declare class MessageQueues {
13
13
  drainFollowUp(agentSlug: string): string | undefined;
14
14
  hasSteer(agentSlug: string): boolean;
15
15
  hasFollowUp(agentSlug: string): boolean;
16
+ hasMessages(agentSlug: string): boolean;
16
17
  }
@@ -40,5 +40,8 @@ export class MessageQueues {
40
40
  const q = this.followUpQueues.get(agentSlug);
41
41
  return q !== undefined && q.length > 0;
42
42
  }
43
+ hasMessages(agentSlug) {
44
+ return this.hasSteer(agentSlug) || this.hasFollowUp(agentSlug);
45
+ }
43
46
  }
44
47
  //# sourceMappingURL=queues.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"queues.js","sourceRoot":"","sources":["../../src/agent/queues.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,OAAO,aAAa;IAChB,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,cAAc,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE7C,QAAQ,CAAC,GAA0B,EAAE,SAAiB;QAC5D,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3B,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,CAAC;YACP,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,KAAK,CAAC,SAAiB,EAAE,OAAe;QACtC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED,QAAQ,CAAC,SAAiB,EAAE,OAAe;QACzC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9D,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3C,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,aAAa,CAAC,SAAiB;QAC7B,MAAM,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3C,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,QAAQ,CAAC,SAAiB;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1C,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,CAAC;CACF"}
1
+ {"version":3,"file":"queues.js","sourceRoot":"","sources":["../../src/agent/queues.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,OAAO,aAAa;IAChB,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,cAAc,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE7C,QAAQ,CAAC,GAA0B,EAAE,SAAiB;QAC5D,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3B,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,CAAC;YACP,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,KAAK,CAAC,SAAiB,EAAE,OAAe;QACtC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED,QAAQ,CAAC,SAAiB,EAAE,OAAe;QACzC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9D,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3C,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,aAAa,CAAC,SAAiB;QAC7B,MAAM,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3C,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,QAAQ,CAAC,SAAiB;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1C,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IACjE,CAAC;CACF"}
@@ -37,10 +37,17 @@ export const templates = {
37
37
  heartbeatCron: '0 */8 * * *',
38
38
  tools: ['nex_search', 'nex_ask', 'nex_record_list', 'nex_record_get', 'nex_remember'],
39
39
  },
40
+ 'team-lead': {
41
+ name: 'Team Lead',
42
+ expertise: ['general', 'research', 'analysis', 'communication', 'planning', 'orchestration'],
43
+ personality: 'You are the Team Lead — the primary interface between the human and the specialist agents. You understand objectives, break them into tasks, delegate to the right specialists, and synthesize results. When the user says what they want, you figure out the path to get there using the context graph and available agents. You always respond first, then coordinate behind the scenes.',
44
+ heartbeatCron: 'manual',
45
+ tools: ['nex_search', 'nex_ask', 'nex_remember', 'nex_record_list', 'nex_record_get', 'nex_record_create', 'nex_record_update'],
46
+ },
40
47
  'founding-agent': {
41
- name: 'Founding Agent',
42
- expertise: ['general', 'research', 'analysis', 'communication', 'planning'],
43
- personality: 'Versatile and proactive. Your first AI team member — handles everything from research to outreach until specialized agents are added.',
48
+ name: 'Team Lead',
49
+ expertise: ['general', 'research', 'analysis', 'communication', 'planning', 'orchestration'],
50
+ personality: 'Versatile and proactive. Your first AI team member — handles everything from research to outreach until specialized agents are added. Delegates to specialists when they exist.',
44
51
  heartbeatCron: 'daily',
45
52
  tools: ['nex_search', 'nex_ask', 'nex_remember', 'nex_record_list', 'nex_record_get', 'nex_record_create', 'nex_record_update'],
46
53
  },
@@ -1 +1 @@
1
- {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/agent/templates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,CAAC,MAAM,SAAS,GAA8C;IAClE,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,SAAS,EAAE,CAAC,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,CAAC;QAC1D,WAAW,EAAE,2DAA2D;QACxE,aAAa,EAAE,OAAO;QACtB,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,CAAC;KACpE;IACD,UAAU,EAAE;QACV,IAAI,EAAE,gBAAgB;QACtB,SAAS,EAAE,CAAC,aAAa,EAAE,YAAY,EAAE,UAAU,CAAC;QACpD,WAAW,EAAE,mDAAmD;QAChE,aAAa,EAAE,aAAa;QAC5B,KAAK,EAAE,CAAC,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,cAAc,CAAC;KAC9E;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,eAAe;QACrB,SAAS,EAAE,CAAC,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC;QACxD,WAAW,EAAE,6CAA6C;QAC1D,aAAa,EAAE,aAAa;QAC5B,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,CAAC;KACxF;IACD,UAAU,EAAE;QACV,IAAI,EAAE,kBAAkB;QACxB,SAAS,EAAE,CAAC,iBAAiB,EAAE,sBAAsB,EAAE,gBAAgB,CAAC;QACxE,WAAW,EAAE,oDAAoD;QACjE,aAAa,EAAE,OAAO;QACtB,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,cAAc,CAAC;KACjD;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,kBAAkB;QACxB,SAAS,EAAE,CAAC,yBAAyB,EAAE,gBAAgB,EAAE,kBAAkB,CAAC;QAC5E,WAAW,EAAE,uDAAuD;QACpE,aAAa,EAAE,aAAa;QAC5B,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,cAAc,CAAC;KACtF;IACD,gBAAgB,EAAE;QAChB,IAAI,EAAE,gBAAgB;QACtB,SAAS,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,CAAC;QAC3E,WAAW,EAAE,uIAAuI;QACpJ,aAAa,EAAE,OAAO;QACtB,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,mBAAmB,CAAC;KAChI;CACF,CAAC"}
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/agent/templates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,CAAC,MAAM,SAAS,GAA8C;IAClE,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,SAAS,EAAE,CAAC,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,CAAC;QAC1D,WAAW,EAAE,2DAA2D;QACxE,aAAa,EAAE,OAAO;QACtB,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,CAAC;KACpE;IACD,UAAU,EAAE;QACV,IAAI,EAAE,gBAAgB;QACtB,SAAS,EAAE,CAAC,aAAa,EAAE,YAAY,EAAE,UAAU,CAAC;QACpD,WAAW,EAAE,mDAAmD;QAChE,aAAa,EAAE,aAAa;QAC5B,KAAK,EAAE,CAAC,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,cAAc,CAAC;KAC9E;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,eAAe;QACrB,SAAS,EAAE,CAAC,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC;QACxD,WAAW,EAAE,6CAA6C;QAC1D,aAAa,EAAE,aAAa;QAC5B,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,CAAC;KACxF;IACD,UAAU,EAAE;QACV,IAAI,EAAE,kBAAkB;QACxB,SAAS,EAAE,CAAC,iBAAiB,EAAE,sBAAsB,EAAE,gBAAgB,CAAC;QACxE,WAAW,EAAE,oDAAoD;QACjE,aAAa,EAAE,OAAO;QACtB,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,cAAc,CAAC;KACjD;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,kBAAkB;QACxB,SAAS,EAAE,CAAC,yBAAyB,EAAE,gBAAgB,EAAE,kBAAkB,CAAC;QAC5E,WAAW,EAAE,uDAAuD;QACpE,aAAa,EAAE,aAAa;QAC5B,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,cAAc,CAAC;KACtF;IACD,WAAW,EAAE;QACX,IAAI,EAAE,WAAW;QACjB,SAAS,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,CAAC;QAC5F,WAAW,EAAE,4XAA4X;QACzY,aAAa,EAAE,QAAQ;QACvB,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,mBAAmB,CAAC;KAChI;IACD,gBAAgB,EAAE;QAChB,IAAI,EAAE,WAAW;QACjB,SAAS,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,CAAC;QAC5F,WAAW,EAAE,iLAAiL;QAC9L,aAAa,EAAE,OAAO;QACtB,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,mBAAmB,CAAC;KAChI;CACF,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * TickManager: drives agent loops on a fixed interval.
3
+ * Each agent gets its own setInterval; ticks are skipped
4
+ * when the agent is idle with no queued work.
5
+ */
6
+ export declare class TickManager {
7
+ private intervals;
8
+ private tickRateMs;
9
+ constructor(tickRateMs?: number);
10
+ startLoop(slug: string, loop: {
11
+ getState(): {
12
+ phase: string;
13
+ };
14
+ start(): void;
15
+ tick(): Promise<void>;
16
+ }, hasWork: () => boolean): void;
17
+ stopLoop(slug: string): void;
18
+ isRunning(slug: string): boolean;
19
+ stopAll(): void;
20
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * TickManager: drives agent loops on a fixed interval.
3
+ * Each agent gets its own setInterval; ticks are skipped
4
+ * when the agent is idle with no queued work.
5
+ */
6
+ export class TickManager {
7
+ intervals = new Map();
8
+ tickRateMs;
9
+ constructor(tickRateMs = 500) {
10
+ this.tickRateMs = tickRateMs;
11
+ }
12
+ startLoop(slug, loop, hasWork) {
13
+ if (this.intervals.has(slug))
14
+ return; // idempotent
15
+ const interval = setInterval(async () => {
16
+ const state = loop.getState();
17
+ // Only tick if there's pending work
18
+ if ((state.phase === 'done' || state.phase === 'error' || state.phase === 'idle') &&
19
+ !hasWork()) {
20
+ return; // idle skip
21
+ }
22
+ if (state.phase === 'done' || state.phase === 'error') {
23
+ loop.start(); // reset to idle
24
+ }
25
+ try {
26
+ await loop.tick();
27
+ }
28
+ catch {
29
+ /* swallow tick errors */
30
+ }
31
+ }, this.tickRateMs);
32
+ this.intervals.set(slug, interval);
33
+ }
34
+ stopLoop(slug) {
35
+ const interval = this.intervals.get(slug);
36
+ if (interval) {
37
+ clearInterval(interval);
38
+ this.intervals.delete(slug);
39
+ }
40
+ }
41
+ isRunning(slug) {
42
+ return this.intervals.has(slug);
43
+ }
44
+ stopAll() {
45
+ for (const [slug] of this.intervals) {
46
+ this.stopLoop(slug);
47
+ }
48
+ }
49
+ }
50
+ //# sourceMappingURL=tick-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tick-manager.js","sourceRoot":"","sources":["../../src/agent/tick-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,OAAO,WAAW;IACd,SAAS,GAAG,IAAI,GAAG,EAA0C,CAAC;IAC9D,UAAU,CAAS;IAE3B,YAAY,UAAU,GAAG,GAAG;QAC1B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,SAAS,CACP,IAAY,EACZ,IAA6E,EAC7E,OAAsB;QAEtB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,aAAa;QAEnD,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YACtC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,oCAAoC;YACpC,IACE,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC;gBAC7E,CAAC,OAAO,EAAE,EACV,CAAC;gBACD,OAAO,CAAC,YAAY;YACtB,CAAC;YACD,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;gBACtD,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,gBAAgB;YAChC,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YACpB,CAAC;YAAC,MAAM,CAAC;gBACP,yBAAyB;YAC3B,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAEpB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,QAAQ,CAAC,IAAY;QACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE,CAAC;YACb,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,OAAO;QACL,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;CACF"}
@@ -28,6 +28,11 @@ export interface CommandContext {
28
28
  * The TUI and CLI can both call this to execute commands without stdout side effects.
29
29
  */
30
30
  export declare function dispatch(input: string, ctx?: CommandContext): Promise<CommandResult>;
31
+ /**
32
+ * Dispatch from pre-tokenized args (e.g. process.argv).
33
+ * Use this when the shell has already handled quoting/splitting.
34
+ */
35
+ export declare function dispatchTokens(tokens: string[], ctx?: CommandContext): Promise<CommandResult>;
31
36
  /** All registered command names, for autocomplete. */
32
37
  export declare const commandNames: string[];
33
38
  /** Help entries for each command, with category and description. */