@operor/cli 0.1.0
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/README.md +76 -0
- package/dist/config-Bn2pbORi.js +34 -0
- package/dist/config-Bn2pbORi.js.map +1 -0
- package/dist/converse-C_PB7-JH.js +142 -0
- package/dist/converse-C_PB7-JH.js.map +1 -0
- package/dist/doctor-98gPl743.js +122 -0
- package/dist/doctor-98gPl743.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2268 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-override-BIQl0V6H.js +445 -0
- package/dist/llm-override-BIQl0V6H.js.map +1 -0
- package/dist/reset-DT8SBgFS.js +87 -0
- package/dist/reset-DT8SBgFS.js.map +1 -0
- package/dist/simulate-BKv62GJc.js +144 -0
- package/dist/simulate-BKv62GJc.js.map +1 -0
- package/dist/status-D6LIZvQa.js +82 -0
- package/dist/status-D6LIZvQa.js.map +1 -0
- package/dist/test-DYjkxbtK.js +177 -0
- package/dist/test-DYjkxbtK.js.map +1 -0
- package/dist/test-suite-D8H_5uKs.js +209 -0
- package/dist/test-suite-D8H_5uKs.js.map +1 -0
- package/dist/utils-BuV4q7f6.js +11 -0
- package/dist/utils-BuV4q7f6.js.map +1 -0
- package/dist/vibe-Bl_js3Jo.js +395 -0
- package/dist/vibe-Bl_js3Jo.js.map +1 -0
- package/package.json +43 -0
- package/src/commands/analytics.ts +408 -0
- package/src/commands/chat.ts +310 -0
- package/src/commands/config.ts +34 -0
- package/src/commands/converse.ts +182 -0
- package/src/commands/doctor.ts +154 -0
- package/src/commands/history.ts +60 -0
- package/src/commands/init.ts +163 -0
- package/src/commands/kb.ts +429 -0
- package/src/commands/llm-override.ts +480 -0
- package/src/commands/reset.ts +72 -0
- package/src/commands/simulate.ts +187 -0
- package/src/commands/status.ts +112 -0
- package/src/commands/test-suite.ts +247 -0
- package/src/commands/test.ts +177 -0
- package/src/commands/vibe.ts +478 -0
- package/src/config.ts +127 -0
- package/src/index.ts +190 -0
- package/src/log-timestamps.ts +26 -0
- package/src/setup.ts +712 -0
- package/src/start.ts +573 -0
- package/src/utils.ts +6 -0
- package/templates/agents/_defaults/SOUL.md +20 -0
- package/templates/agents/_defaults/USER.md +16 -0
- package/templates/agents/customer-support/IDENTITY.md +6 -0
- package/templates/agents/customer-support/INSTRUCTIONS.md +79 -0
- package/templates/agents/customer-support/SOUL.md +26 -0
- package/templates/agents/faq-bot/IDENTITY.md +6 -0
- package/templates/agents/faq-bot/INSTRUCTIONS.md +53 -0
- package/templates/agents/faq-bot/SOUL.md +19 -0
- package/templates/agents/sales/IDENTITY.md +6 -0
- package/templates/agents/sales/INSTRUCTIONS.md +67 -0
- package/templates/agents/sales/SOUL.md +20 -0
- package/tsconfig.json +9 -0
- package/tsdown.config.ts +13 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-suite-D8H_5uKs.js","names":[],"sources":["../src/commands/test-suite.ts"],"sourcesContent":["import { formatTimestamp } from '../utils.js';\nimport { readConfig } from '../config.js';\n\nexport async function runTestSuite(file: string, options: {\n strategy?: 'exact' | 'contains' | 'similarity' | 'semantic';\n timeout?: number;\n parallel?: boolean;\n verbose?: boolean;\n json?: boolean;\n real?: boolean;\n allowWrites?: boolean;\n dryRun?: boolean;\n llm?: boolean;\n}): Promise<void> {\n const { Operor } = await import('@operor/core');\n const { MockProvider } = await import('@operor/provider-mock');\n const { CSVLoader, TestSuiteRunner, SkillTestHarness } = await import('@operor/testing');\n\n // Load test cases from file\n let testCases;\n try {\n testCases = await CSVLoader.fromFile(file);\n } catch (err) {\n const isNotFound = err instanceof Error && 'code' in err && (err as any).code === 'ENOENT';\n if (isNotFound) {\n console.error(`\\n Test file not found: ${file}\\n`);\n console.error(` To get started, create a CSV file with this format:\\n`);\n console.error(` id,question,expected_answer,expected_tools,persona,tags`);\n console.error(` greeting-1,Hello,Hi! How can I help you?,,friendly,greeting`);\n console.error(` order-1,Where is my order?,Let me check.,get_order,helpful,order_tracking\\n`);\n console.error(` Required columns: id, question`);\n console.error(` Optional columns: expected_answer, expected_tools, persona, tags\\n`);\n console.error(` A sample file is included at tests.csv in the project root.`);\n console.error(` You can also use JSON format — see docs for details.\\n`);\n } else {\n console.error(`Failed to load test cases from ${file}: ${err instanceof Error ? err.message : err}`);\n }\n process.exit(1);\n }\n\n if (testCases.length === 0) {\n console.error('No test cases found in file.');\n process.exit(1);\n }\n\n // Set up Operor\n const os = new Operor({ debug: false, batchWindowMs: 0 });\n const provider = new MockProvider();\n await os.addProvider(provider);\n\n let harness: InstanceType<typeof SkillTestHarness> | null = null;\n let agent: any;\n let allTools: any[] = [];\n\n if (options.real || options.dryRun) {\n // Real integration testing now uses MCP skills via mcp.json\n console.error('--real/--dry-run mode has been removed. Configure MCP skills in mcp.json instead.');\n console.error('Use the mock-based test suite (default) or Docker E2E tests for integration testing.');\n process.exit(1);\n } else {\n // Default: use mocks\n const { MockShopifySkill } = await import('@operor/testing');\n const shopify = new MockShopifySkill();\n await os.addSkill(shopify);\n\n allTools = [shopify.tools.get_order, shopify.tools.create_discount, shopify.tools.search_products];\n\n agent = os.createAgent({\n name: 'Test Agent',\n purpose: 'Handle customer support queries',\n personality: 'helpful and solution-focused',\n triggers: ['order_tracking', 'general'],\n tools: allTools,\n rules: [{\n name: 'Auto-compensation',\n condition: async (_ctx: any, toolResults: any[]) => {\n const order = toolResults.find((t) => t.name === 'get_order');\n return order?.success && order.result?.isDelayed && order.result?.delayDays >= 2;\n },\n action: async () => {\n const discount = await shopify.tools.create_discount.execute({ percent: 10, validDays: 30 });\n return { type: 'discount_created', code: discount.code, percent: 10, validDays: 30 };\n },\n }],\n });\n }\n\n // Set up LLM-based agent processing if --llm flag is set\n let llm: any;\n if (options.llm) {\n const config = readConfig();\n\n if (!config.LLM_PROVIDER || !config.LLM_API_KEY) {\n console.error('--llm requires LLM_PROVIDER and LLM_API_KEY in .env. Run \"operor setup\" or \"operor config set\" to configure.');\n process.exit(1);\n }\n\n const { AIProvider } = await import('@operor/llm');\n llm = new AIProvider({\n provider: config.LLM_PROVIDER as any,\n apiKey: config.LLM_API_KEY,\n model: config.LLM_MODEL,\n });\n\n if (!options.json) {\n console.log(`\\n LLM mode: ${llm.getProviderName()} (${llm.getModelName()})`);\n }\n\n // Override agent.process with LLM-based implementation\n agent.process = async (context: any) => {\n const startTime = Date.now();\n const systemMessage = `You are a ${agent.config.personality} customer support agent. ${agent.config.purpose}.`;\n const messages = [\n { role: 'system' as const, content: systemMessage },\n ...context.history.map((m: any) => ({\n role: m.role as 'user' | 'assistant',\n content: m.content,\n })),\n { role: 'user' as const, content: context.currentMessage.text },\n ];\n\n const toolCalls: any[] = [];\n let finalText = '';\n let iterations = 0;\n const maxIterations = 5;\n\n while (iterations < maxIterations) {\n iterations++;\n\n const response = await llm.complete(messages, {\n tools: allTools.map((t) => ({\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n })),\n });\n\n if (response.toolCalls && response.toolCalls.length > 0) {\n const executedTools: Array<{ name: string; result: any; success: boolean; error?: string }> = [];\n\n for (const tc of response.toolCalls) {\n const tool = allTools.find((t) => t.name === tc.name);\n if (!tool) continue;\n\n try {\n const result = await tool.execute(tc.arguments);\n toolCalls.push({ id: tc.id, name: tc.name, params: tc.arguments, result, success: true });\n executedTools.push({ name: tc.name, result, success: true });\n } catch (err: any) {\n toolCalls.push({ id: tc.id, name: tc.name, params: tc.arguments, result: null, success: false, error: err.message });\n executedTools.push({ name: tc.name, result: null, success: false, error: err.message });\n }\n }\n\n const toolResultSummary = executedTools.map(tc =>\n `[Tool ${tc.name}]: ${JSON.stringify(tc.success ? tc.result : { error: tc.error })}`\n ).join('\\n');\n\n messages.push(\n { role: 'assistant', content: `I'll call ${executedTools.map(tc => tc.name).join(', ')} to help with that.` },\n { role: 'user', content: `Tool results:\\n${toolResultSummary}\\n\\nPlease use these results to respond to the customer.` }\n );\n } else {\n finalText = response.text;\n break;\n }\n }\n\n return {\n text: finalText,\n toolCalls,\n duration: Date.now() - startTime,\n };\n };\n }\n\n await os.start();\n\n if (!options.json) {\n console.log(`\\n Running ${testCases.length} test case(s) from ${file}...\\n`);\n }\n\n const runner = new TestSuiteRunner({\n agentOS: os,\n llm,\n timeout: options.timeout ?? 10000,\n strategy: options.strategy,\n });\n\n const result = await runner.runSuite(testCases);\n await os.stop();\n\n // Output results\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n // Per-test results\n for (const r of result.results) {\n const status = r.evaluation.passed ? 'PASS' : 'FAIL';\n const score = r.evaluation.score.toFixed(2);\n const line = ` [${formatTimestamp()}] [${status}] ${r.testCase.id}: ${r.testCase.question} (score: ${score}, ${r.duration}ms)`;\n console.log(line);\n\n if (options.verbose && !r.evaluation.passed) {\n console.log(` Reason: ${r.evaluation.reasoning}`);\n console.log(` Response: ${r.agentResponse.slice(0, 120)}`);\n }\n }\n\n // Tag breakdown\n const tags = Object.entries(result.byTag);\n if (tags.length > 0) {\n console.log('\\n --- By Tag ---');\n for (const [tag, stats] of tags) {\n console.log(` ${tag}: ${stats.passed}/${stats.total} passed (avg score: ${stats.avgScore.toFixed(2)})`);\n }\n }\n\n // Audit log summary (when using SkillTestHarness)\n if (harness) {\n const log = harness.getAuditLog();\n if (log.length > 0) {\n console.log('\\n --- Skill Call Log ---');\n const reads = log.filter((e) => e.classification === 'read');\n const writes = log.filter((e) => e.classification === 'write');\n const destructive = log.filter((e) => e.classification === 'destructive');\n const dryRuns = log.filter((e) => (e.result as any)?.dryRun);\n\n console.log(` Total calls: ${log.length} (${reads.length} read, ${writes.length} write, ${destructive.length} destructive)`);\n if (dryRuns.length > 0) {\n console.log(` Dry-run calls: ${dryRuns.length} (not executed)`);\n }\n for (const entry of log) {\n const dryTag = (entry.result as any)?.dryRun ? ' [DRY-RUN]' : '';\n console.log(` ${entry.classification.toUpperCase()} ${entry.name}${dryTag} (${entry.duration}ms)`);\n }\n }\n }\n\n // Summary\n console.log(`\\n Summary: ${result.passed}/${result.total} passed, avg score: ${result.averageScore.toFixed(2)}`);\n console.log(` Duration: ${(result.totalDuration / 1000).toFixed(1)}s, Cost: $${result.totalCost.toFixed(4)}`);\n console.log(` Result: ${result.failed === 0 ? 'PASSED' : 'FAILED'}\\n`);\n }\n\n process.exit(result.failed === 0 ? 0 : 1);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Format current time as HH:MM:SS timestamp
|
|
4
|
+
*/
|
|
5
|
+
function formatTimestamp() {
|
|
6
|
+
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { formatTimestamp as t };
|
|
11
|
+
//# sourceMappingURL=utils-BuV4q7f6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-BuV4q7f6.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["/**\n * Format current time as HH:MM:SS timestamp\n */\nexport function formatTimestamp(): string {\n return new Date().toLocaleTimeString('en-US', { hour12: false });\n}\n"],"mappings":";;;;AAGA,SAAgB,kBAA0B;AACxC,yBAAO,IAAI,MAAM,EAAC,mBAAmB,SAAS,EAAE,QAAQ,OAAO,CAAC"}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import { n as readConfig } from "./index.js";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import * as readline from "node:readline";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/vibe.ts
|
|
7
|
+
const WELCOME = `
|
|
8
|
+
Welcome to Operor Vibe -- your agent copilot!
|
|
9
|
+
|
|
10
|
+
I can help you with:
|
|
11
|
+
|
|
12
|
+
1. Create Create a new agent from a description
|
|
13
|
+
2. Customize Update an agent's instructions and behavior
|
|
14
|
+
3. Connect Add skills, knowledge sources, and tools
|
|
15
|
+
4. Improve Refine responses based on feedback
|
|
16
|
+
|
|
17
|
+
What would you like to do?
|
|
18
|
+
`;
|
|
19
|
+
const AGENTS_DIR = path.resolve(process.cwd(), "agents");
|
|
20
|
+
const META_PROMPT = `You are Operor Vibe, an AI copilot that helps users create and customize AI agents.
|
|
21
|
+
|
|
22
|
+
You generate file-based agent definitions for the Operor framework. Each agent lives in an agents/<name>/ directory with these files:
|
|
23
|
+
|
|
24
|
+
## INSTRUCTIONS.md Format
|
|
25
|
+
|
|
26
|
+
YAML frontmatter followed by markdown body:
|
|
27
|
+
|
|
28
|
+
\`\`\`
|
|
29
|
+
---
|
|
30
|
+
name: <agent-slug>
|
|
31
|
+
purpose: <one-line description>
|
|
32
|
+
triggers:
|
|
33
|
+
- <intent keywords that route to this agent>
|
|
34
|
+
channels: # optional — omit to handle all channels
|
|
35
|
+
- whatsapp
|
|
36
|
+
- telegram
|
|
37
|
+
- wati
|
|
38
|
+
skills: # optional — configured via mcp.json
|
|
39
|
+
- shopify
|
|
40
|
+
- stripe
|
|
41
|
+
- github
|
|
42
|
+
knowledgeBase: false # set true to enable KB retrieval
|
|
43
|
+
guardrails: # optional
|
|
44
|
+
maxResponseLength: 1500
|
|
45
|
+
blockedTopics: []
|
|
46
|
+
escalationTriggers: []
|
|
47
|
+
systemRules: []
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Role
|
|
51
|
+
<What this agent does and who it serves>
|
|
52
|
+
|
|
53
|
+
## Scope
|
|
54
|
+
<Bullet list of what the agent CAN do>
|
|
55
|
+
|
|
56
|
+
## Out of Scope
|
|
57
|
+
<Bullet list of what the agent should NOT do>
|
|
58
|
+
|
|
59
|
+
## Style
|
|
60
|
+
<Communication style guidelines>
|
|
61
|
+
|
|
62
|
+
## Escalation
|
|
63
|
+
<When and how to hand off to humans>
|
|
64
|
+
|
|
65
|
+
## Examples
|
|
66
|
+
<2-3 example user/agent exchanges>
|
|
67
|
+
\`\`\`
|
|
68
|
+
|
|
69
|
+
## IDENTITY.md Format
|
|
70
|
+
Short personality card:
|
|
71
|
+
- Name, Emoji, Nature, Vibe
|
|
72
|
+
|
|
73
|
+
## SOUL.md Format
|
|
74
|
+
Deeper behavioral guide:
|
|
75
|
+
- Core Principles, Boundaries, Tone, When Things Go Wrong
|
|
76
|
+
|
|
77
|
+
## Available skills
|
|
78
|
+
configured via mcp.json (e.g. shopify, stripe, github)
|
|
79
|
+
|
|
80
|
+
## Available channels
|
|
81
|
+
whatsapp, telegram, wati
|
|
82
|
+
|
|
83
|
+
## Your behavior
|
|
84
|
+
- Be conversational and friendly
|
|
85
|
+
- When the user describes what they want, ask 2-3 clarifying questions naturally before generating
|
|
86
|
+
- Questions should cover: target audience, tone/personality, key capabilities, skills needed
|
|
87
|
+
- When you have enough info, generate all three files
|
|
88
|
+
- Output each file clearly marked with these exact delimiters:
|
|
89
|
+
--- FILE: INSTRUCTIONS.md ---
|
|
90
|
+
(file content)
|
|
91
|
+
--- FILE: IDENTITY.md ---
|
|
92
|
+
(file content)
|
|
93
|
+
--- FILE: SOUL.md ---
|
|
94
|
+
(file content)
|
|
95
|
+
- After generating, summarize what you created`;
|
|
96
|
+
const CUSTOMIZE_PROMPT = `You are Operor Vibe, helping the user customize an existing agent.
|
|
97
|
+
|
|
98
|
+
The user will provide feedback about their agent. You have access to the current INSTRUCTIONS.md content.
|
|
99
|
+
|
|
100
|
+
- Ask clarifying questions if the feedback is vague
|
|
101
|
+
- When ready to apply changes, output the updated file with:
|
|
102
|
+
--- FILE: INSTRUCTIONS.md ---
|
|
103
|
+
(full updated content)
|
|
104
|
+
- Explain what you changed`;
|
|
105
|
+
const CONNECT_PROMPT = `You are Operor Vibe, helping the user connect skills and knowledge sources to an agent.
|
|
106
|
+
|
|
107
|
+
Available skills: configured via mcp.json (e.g. shopify, stripe, github)
|
|
108
|
+
Available channels: whatsapp, telegram, wati
|
|
109
|
+
|
|
110
|
+
The user will tell you what to add. You have access to the current INSTRUCTIONS.md content.
|
|
111
|
+
|
|
112
|
+
- Update the YAML frontmatter to add the requested skills/channels
|
|
113
|
+
- Output the updated file with:
|
|
114
|
+
--- FILE: INSTRUCTIONS.md ---
|
|
115
|
+
(full updated content)
|
|
116
|
+
- Explain what you connected`;
|
|
117
|
+
const IMPROVE_PROMPT = `You are Operor Vibe, helping the user improve an agent's responses.
|
|
118
|
+
|
|
119
|
+
The user will provide examples of bad responses and what they'd prefer instead.
|
|
120
|
+
You have access to the current INSTRUCTIONS.md content.
|
|
121
|
+
|
|
122
|
+
- Analyze the gap between actual and desired behavior
|
|
123
|
+
- Update the Examples section and/or Style section to address the issue
|
|
124
|
+
- Output the updated file with:
|
|
125
|
+
--- FILE: INSTRUCTIONS.md ---
|
|
126
|
+
(full updated content)
|
|
127
|
+
- Explain what you improved`;
|
|
128
|
+
function createLLM(config) {
|
|
129
|
+
return import("@operor/llm").then(({ AIProvider }) => {
|
|
130
|
+
const maxTokens = config.VIBE_MAX_TOKENS ? Number(config.VIBE_MAX_TOKENS) : 4e3;
|
|
131
|
+
return new AIProvider({
|
|
132
|
+
provider: config.LLM_PROVIDER,
|
|
133
|
+
apiKey: config.LLM_API_KEY,
|
|
134
|
+
model: config.LLM_MODEL,
|
|
135
|
+
maxTokens
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function listAgents() {
|
|
140
|
+
if (!fs.existsSync(AGENTS_DIR)) return [];
|
|
141
|
+
return fs.readdirSync(AGENTS_DIR, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("_")).map((e) => e.name);
|
|
142
|
+
}
|
|
143
|
+
function readAgentFile(agentName, fileName) {
|
|
144
|
+
const filePath = path.join(AGENTS_DIR, agentName, fileName);
|
|
145
|
+
if (!fs.existsSync(filePath)) return null;
|
|
146
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
147
|
+
}
|
|
148
|
+
function writeAgentFile(agentName, fileName, content) {
|
|
149
|
+
const dir = path.join(AGENTS_DIR, agentName);
|
|
150
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
151
|
+
fs.writeFileSync(path.join(dir, fileName), content, "utf-8");
|
|
152
|
+
}
|
|
153
|
+
function parseGeneratedFiles(text) {
|
|
154
|
+
const files = {};
|
|
155
|
+
const pattern = /---\s*FILE:\s*(\S+)\s*---\n([\s\S]*?)(?=---\s*FILE:|$)/g;
|
|
156
|
+
let match;
|
|
157
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
158
|
+
const name = match[1].trim();
|
|
159
|
+
const content = match[2].trim();
|
|
160
|
+
if (name && content) files[name] = content;
|
|
161
|
+
}
|
|
162
|
+
return files;
|
|
163
|
+
}
|
|
164
|
+
function extractAgentName(files) {
|
|
165
|
+
const nameMatch = (files["INSTRUCTIONS.md"] || "").match(/^name:\s*(.+)$/m);
|
|
166
|
+
if (nameMatch) return nameMatch[1].trim();
|
|
167
|
+
return "new-agent";
|
|
168
|
+
}
|
|
169
|
+
function prompt(rl, question) {
|
|
170
|
+
return new Promise((resolve) => {
|
|
171
|
+
rl.question(question, (answer) => resolve(answer.trim()));
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
async function conversationLoop(rl, llm, systemPrompt, initialUserMessage, maxTokens = 4e3) {
|
|
175
|
+
const history = [{
|
|
176
|
+
role: "system",
|
|
177
|
+
content: systemPrompt
|
|
178
|
+
}];
|
|
179
|
+
if (initialUserMessage) {
|
|
180
|
+
history.push({
|
|
181
|
+
role: "user",
|
|
182
|
+
content: initialUserMessage
|
|
183
|
+
});
|
|
184
|
+
process.stdout.write("\n Thinking...");
|
|
185
|
+
const response = await llm.complete(history, { maxTokens });
|
|
186
|
+
process.stdout.write("\r" + " ".repeat(20) + "\r");
|
|
187
|
+
history.push({
|
|
188
|
+
role: "assistant",
|
|
189
|
+
content: response.text
|
|
190
|
+
});
|
|
191
|
+
console.log(`\n Vibe: ${response.text}\n`);
|
|
192
|
+
const files = parseGeneratedFiles(response.text);
|
|
193
|
+
if (Object.keys(files).length > 0) return {
|
|
194
|
+
history,
|
|
195
|
+
lastResponse: response.text
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
while (true) {
|
|
199
|
+
const input = await prompt(rl, " You: ");
|
|
200
|
+
if (!input || input === "exit" || input === "quit" || input === "done") return {
|
|
201
|
+
history,
|
|
202
|
+
lastResponse: history[history.length - 1]?.content || ""
|
|
203
|
+
};
|
|
204
|
+
history.push({
|
|
205
|
+
role: "user",
|
|
206
|
+
content: input
|
|
207
|
+
});
|
|
208
|
+
process.stdout.write(" Thinking...");
|
|
209
|
+
const response = await llm.complete(history, { maxTokens });
|
|
210
|
+
process.stdout.write("\r" + " ".repeat(20) + "\r");
|
|
211
|
+
history.push({
|
|
212
|
+
role: "assistant",
|
|
213
|
+
content: response.text
|
|
214
|
+
});
|
|
215
|
+
console.log(`\n Vibe: ${response.text}\n`);
|
|
216
|
+
const files = parseGeneratedFiles(response.text);
|
|
217
|
+
if (Object.keys(files).length > 0) return {
|
|
218
|
+
history,
|
|
219
|
+
lastResponse: response.text
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async function handleCreate(rl, llm, maxTokens) {
|
|
224
|
+
console.log("\n Describe the agent you want to create:\n");
|
|
225
|
+
const description = await prompt(rl, " You: ");
|
|
226
|
+
if (!description) return;
|
|
227
|
+
const { lastResponse } = await conversationLoop(rl, llm, META_PROMPT, description, maxTokens);
|
|
228
|
+
const files = parseGeneratedFiles(lastResponse);
|
|
229
|
+
if (Object.keys(files).length === 0) {
|
|
230
|
+
console.log("\n No agent files were generated. Try again with more detail.\n");
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const agentName = extractAgentName(files);
|
|
234
|
+
console.log(`\n Writing agent files to agents/${agentName}/\n`);
|
|
235
|
+
for (const [fileName, content] of Object.entries(files)) {
|
|
236
|
+
writeAgentFile(agentName, fileName, content);
|
|
237
|
+
console.log(` + agents/${agentName}/${fileName}`);
|
|
238
|
+
}
|
|
239
|
+
console.log(`\n Agent "${agentName}" created! Run "operor start" to use it.\n`);
|
|
240
|
+
}
|
|
241
|
+
async function handleCustomize(rl, llm, maxTokens, targetAgent) {
|
|
242
|
+
const agents = listAgents();
|
|
243
|
+
if (agents.length === 0) {
|
|
244
|
+
console.log("\n No agents found. Create one first with \"operor vibe create\".\n");
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
let agentName = targetAgent;
|
|
248
|
+
if (!agentName) {
|
|
249
|
+
console.log("\n Available agents:\n");
|
|
250
|
+
agents.forEach((a, i) => console.log(` ${i + 1}. ${a}`));
|
|
251
|
+
const choice = await prompt(rl, "\n Select an agent (name or number): ");
|
|
252
|
+
const idx = parseInt(choice, 10);
|
|
253
|
+
agentName = idx > 0 && idx <= agents.length ? agents[idx - 1] : choice;
|
|
254
|
+
}
|
|
255
|
+
const instructions = readAgentFile(agentName, "INSTRUCTIONS.md");
|
|
256
|
+
if (!instructions) {
|
|
257
|
+
console.log(`\n Agent "${agentName}" not found or has no INSTRUCTIONS.md.\n`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
console.log(`\n Customizing agent "${agentName}". What would you like to change?\n`);
|
|
261
|
+
const feedback = await prompt(rl, " You: ");
|
|
262
|
+
if (!feedback) return;
|
|
263
|
+
const { lastResponse } = await conversationLoop(rl, llm, CUSTOMIZE_PROMPT, `Current INSTRUCTIONS.md for agent "${agentName}":\n\n${instructions}\n\nUser feedback: ${feedback}`, maxTokens);
|
|
264
|
+
const files = parseGeneratedFiles(lastResponse);
|
|
265
|
+
if (files["INSTRUCTIONS.md"]) {
|
|
266
|
+
writeAgentFile(agentName, "INSTRUCTIONS.md", files["INSTRUCTIONS.md"]);
|
|
267
|
+
console.log(`\n Updated agents/${agentName}/INSTRUCTIONS.md\n`);
|
|
268
|
+
} else console.log("\n No changes generated.\n");
|
|
269
|
+
}
|
|
270
|
+
async function handleConnect(rl, llm, maxTokens, targetAgent) {
|
|
271
|
+
const agents = listAgents();
|
|
272
|
+
if (agents.length === 0) {
|
|
273
|
+
console.log("\n No agents found. Create one first with \"operor vibe create\".\n");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
let agentName = targetAgent;
|
|
277
|
+
if (!agentName) {
|
|
278
|
+
console.log("\n Available agents:\n");
|
|
279
|
+
agents.forEach((a, i) => console.log(` ${i + 1}. ${a}`));
|
|
280
|
+
const choice = await prompt(rl, "\n Select an agent (name or number): ");
|
|
281
|
+
const idx = parseInt(choice, 10);
|
|
282
|
+
agentName = idx > 0 && idx <= agents.length ? agents[idx - 1] : choice;
|
|
283
|
+
}
|
|
284
|
+
const instructions = readAgentFile(agentName, "INSTRUCTIONS.md");
|
|
285
|
+
if (!instructions) {
|
|
286
|
+
console.log(`\n Agent "${agentName}" not found or has no INSTRUCTIONS.md.\n`);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
console.log(`\n What would you like to connect to "${agentName}"?`);
|
|
290
|
+
console.log(" (skills: configured via mcp.json, e.g. shopify, stripe, github)");
|
|
291
|
+
console.log(" (channels: whatsapp, telegram, wati)\n");
|
|
292
|
+
const request = await prompt(rl, " You: ");
|
|
293
|
+
if (!request) return;
|
|
294
|
+
const { lastResponse } = await conversationLoop(rl, llm, CONNECT_PROMPT, `Current INSTRUCTIONS.md for agent "${agentName}":\n\n${instructions}\n\nUser request: ${request}`, maxTokens);
|
|
295
|
+
const files = parseGeneratedFiles(lastResponse);
|
|
296
|
+
if (files["INSTRUCTIONS.md"]) {
|
|
297
|
+
writeAgentFile(agentName, "INSTRUCTIONS.md", files["INSTRUCTIONS.md"]);
|
|
298
|
+
console.log(`\n Updated agents/${agentName}/INSTRUCTIONS.md\n`);
|
|
299
|
+
} else console.log("\n No changes generated.\n");
|
|
300
|
+
}
|
|
301
|
+
async function handleImprove(rl, llm, maxTokens, targetAgent) {
|
|
302
|
+
const agents = listAgents();
|
|
303
|
+
if (agents.length === 0) {
|
|
304
|
+
console.log("\n No agents found. Create one first with \"operor vibe create\".\n");
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
let agentName = targetAgent;
|
|
308
|
+
if (!agentName) {
|
|
309
|
+
console.log("\n Available agents:\n");
|
|
310
|
+
agents.forEach((a, i) => console.log(` ${i + 1}. ${a}`));
|
|
311
|
+
const choice = await prompt(rl, "\n Select an agent (name or number): ");
|
|
312
|
+
const idx = parseInt(choice, 10);
|
|
313
|
+
agentName = idx > 0 && idx <= agents.length ? agents[idx - 1] : choice;
|
|
314
|
+
}
|
|
315
|
+
const instructions = readAgentFile(agentName, "INSTRUCTIONS.md");
|
|
316
|
+
if (!instructions) {
|
|
317
|
+
console.log(`\n Agent "${agentName}" not found or has no INSTRUCTIONS.md.\n`);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
console.log(`\n Improving agent "${agentName}".`);
|
|
321
|
+
console.log(" Share an example of a bad response and what you'd prefer:\n");
|
|
322
|
+
const feedback = await prompt(rl, " You: ");
|
|
323
|
+
if (!feedback) return;
|
|
324
|
+
const { lastResponse } = await conversationLoop(rl, llm, IMPROVE_PROMPT, `Current INSTRUCTIONS.md for agent "${agentName}":\n\n${instructions}\n\nUser feedback on response quality: ${feedback}`, maxTokens);
|
|
325
|
+
const files = parseGeneratedFiles(lastResponse);
|
|
326
|
+
if (files["INSTRUCTIONS.md"]) {
|
|
327
|
+
writeAgentFile(agentName, "INSTRUCTIONS.md", files["INSTRUCTIONS.md"]);
|
|
328
|
+
console.log(`\n Updated agents/${agentName}/INSTRUCTIONS.md\n`);
|
|
329
|
+
} else console.log("\n No changes generated.\n");
|
|
330
|
+
}
|
|
331
|
+
function resolveAction(input) {
|
|
332
|
+
const normalized = input.toLowerCase().trim();
|
|
333
|
+
if (["1", "create"].includes(normalized)) return "create";
|
|
334
|
+
if (["2", "customize"].includes(normalized)) return "customize";
|
|
335
|
+
if (["3", "connect"].includes(normalized)) return "connect";
|
|
336
|
+
if (["4", "improve"].includes(normalized)) return "improve";
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
async function runVibe(opts) {
|
|
340
|
+
const config = readConfig();
|
|
341
|
+
if (!config.LLM_PROVIDER || !config.LLM_API_KEY) {
|
|
342
|
+
console.error("\n LLM not configured. Run \"operor setup\" first to configure your LLM provider.\n");
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
let llm;
|
|
346
|
+
try {
|
|
347
|
+
llm = await createLLM(config);
|
|
348
|
+
} catch (err) {
|
|
349
|
+
console.error(`\n Failed to initialize LLM: ${err.message}\n`);
|
|
350
|
+
process.exit(1);
|
|
351
|
+
}
|
|
352
|
+
const maxTokens = config.VIBE_MAX_TOKENS ? Number(config.VIBE_MAX_TOKENS) : 4e3;
|
|
353
|
+
const rl = readline.createInterface({
|
|
354
|
+
input: process.stdin,
|
|
355
|
+
output: process.stdout
|
|
356
|
+
});
|
|
357
|
+
rl.on("close", () => {
|
|
358
|
+
console.log("\n Goodbye!\n");
|
|
359
|
+
process.exit(0);
|
|
360
|
+
});
|
|
361
|
+
let action = opts.action ? resolveAction(opts.action) : null;
|
|
362
|
+
if (!action) {
|
|
363
|
+
console.log(WELCOME);
|
|
364
|
+
action = resolveAction(await prompt(rl, " > "));
|
|
365
|
+
if (!action) {
|
|
366
|
+
console.log("\n Invalid choice. Use: create, customize, connect, or improve.\n");
|
|
367
|
+
rl.close();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
switch (action) {
|
|
373
|
+
case "create":
|
|
374
|
+
await handleCreate(rl, llm, maxTokens);
|
|
375
|
+
break;
|
|
376
|
+
case "customize":
|
|
377
|
+
await handleCustomize(rl, llm, maxTokens, opts.agent);
|
|
378
|
+
break;
|
|
379
|
+
case "connect":
|
|
380
|
+
await handleConnect(rl, llm, maxTokens, opts.agent);
|
|
381
|
+
break;
|
|
382
|
+
case "improve":
|
|
383
|
+
await handleImprove(rl, llm, maxTokens, opts.agent);
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
} catch (err) {
|
|
387
|
+
if (err.code === "ERR_USE_AFTER_CLOSE") return;
|
|
388
|
+
console.error(`\n Error: ${err.message}\n`);
|
|
389
|
+
}
|
|
390
|
+
rl.close();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
//#endregion
|
|
394
|
+
export { runVibe };
|
|
395
|
+
//# sourceMappingURL=vibe-Bl_js3Jo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vibe-Bl_js3Jo.js","names":[],"sources":["../src/commands/vibe.ts"],"sourcesContent":["import * as readline from 'node:readline';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { readConfig } from '../config.js';\n\ninterface VibeOptions {\n action?: string;\n agent?: string;\n}\n\ninterface LLMMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nconst WELCOME = `\n Welcome to Operor Vibe -- your agent copilot!\n\n I can help you with:\n\n 1. Create Create a new agent from a description\n 2. Customize Update an agent's instructions and behavior\n 3. Connect Add skills, knowledge sources, and tools\n 4. Improve Refine responses based on feedback\n\n What would you like to do?\n`;\n\nconst AGENTS_DIR = path.resolve(process.cwd(), 'agents');\n\nconst META_PROMPT = `You are Operor Vibe, an AI copilot that helps users create and customize AI agents.\n\nYou generate file-based agent definitions for the Operor framework. Each agent lives in an agents/<name>/ directory with these files:\n\n## INSTRUCTIONS.md Format\n\nYAML frontmatter followed by markdown body:\n\n\\`\\`\\`\n---\nname: <agent-slug>\npurpose: <one-line description>\ntriggers:\n - <intent keywords that route to this agent>\nchannels: # optional — omit to handle all channels\n - whatsapp\n - telegram\n - wati\nskills: # optional — configured via mcp.json\n - shopify\n - stripe\n - github\nknowledgeBase: false # set true to enable KB retrieval\nguardrails: # optional\n maxResponseLength: 1500\n blockedTopics: []\n escalationTriggers: []\n systemRules: []\n---\n\n## Role\n<What this agent does and who it serves>\n\n## Scope\n<Bullet list of what the agent CAN do>\n\n## Out of Scope\n<Bullet list of what the agent should NOT do>\n\n## Style\n<Communication style guidelines>\n\n## Escalation\n<When and how to hand off to humans>\n\n## Examples\n<2-3 example user/agent exchanges>\n\\`\\`\\`\n\n## IDENTITY.md Format\nShort personality card:\n- Name, Emoji, Nature, Vibe\n\n## SOUL.md Format\nDeeper behavioral guide:\n- Core Principles, Boundaries, Tone, When Things Go Wrong\n\n## Available skills\nconfigured via mcp.json (e.g. shopify, stripe, github)\n\n## Available channels\nwhatsapp, telegram, wati\n\n## Your behavior\n- Be conversational and friendly\n- When the user describes what they want, ask 2-3 clarifying questions naturally before generating\n- Questions should cover: target audience, tone/personality, key capabilities, skills needed\n- When you have enough info, generate all three files\n- Output each file clearly marked with these exact delimiters:\n --- FILE: INSTRUCTIONS.md ---\n (file content)\n --- FILE: IDENTITY.md ---\n (file content)\n --- FILE: SOUL.md ---\n (file content)\n- After generating, summarize what you created`;\n\nconst CUSTOMIZE_PROMPT = `You are Operor Vibe, helping the user customize an existing agent.\n\nThe user will provide feedback about their agent. You have access to the current INSTRUCTIONS.md content.\n\n- Ask clarifying questions if the feedback is vague\n- When ready to apply changes, output the updated file with:\n --- FILE: INSTRUCTIONS.md ---\n (full updated content)\n- Explain what you changed`;\n\nconst CONNECT_PROMPT = `You are Operor Vibe, helping the user connect skills and knowledge sources to an agent.\n\nAvailable skills: configured via mcp.json (e.g. shopify, stripe, github)\nAvailable channels: whatsapp, telegram, wati\n\nThe user will tell you what to add. You have access to the current INSTRUCTIONS.md content.\n\n- Update the YAML frontmatter to add the requested skills/channels\n- Output the updated file with:\n --- FILE: INSTRUCTIONS.md ---\n (full updated content)\n- Explain what you connected`;\n\nconst IMPROVE_PROMPT = `You are Operor Vibe, helping the user improve an agent's responses.\n\nThe user will provide examples of bad responses and what they'd prefer instead.\nYou have access to the current INSTRUCTIONS.md content.\n\n- Analyze the gap between actual and desired behavior\n- Update the Examples section and/or Style section to address the issue\n- Output the updated file with:\n --- FILE: INSTRUCTIONS.md ---\n (full updated content)\n- Explain what you improved`;\n\nfunction createLLM(config: ReturnType<typeof readConfig>) {\n // Lazy import to avoid loading AI SDK at CLI startup\n return import('@operor/llm').then(({ AIProvider }) => {\n const maxTokens = config.VIBE_MAX_TOKENS ? Number(config.VIBE_MAX_TOKENS) : 4000;\n return new AIProvider({\n provider: config.LLM_PROVIDER as 'openai' | 'anthropic' | 'google' | 'groq' | 'ollama',\n apiKey: config.LLM_API_KEY,\n model: config.LLM_MODEL,\n maxTokens,\n });\n });\n}\n\nfunction listAgents(): string[] {\n if (!fs.existsSync(AGENTS_DIR)) return [];\n return fs.readdirSync(AGENTS_DIR, { withFileTypes: true })\n .filter(e => e.isDirectory() && !e.name.startsWith('_'))\n .map(e => e.name);\n}\n\nfunction readAgentFile(agentName: string, fileName: string): string | null {\n const filePath = path.join(AGENTS_DIR, agentName, fileName);\n if (!fs.existsSync(filePath)) return null;\n return fs.readFileSync(filePath, 'utf-8');\n}\n\nfunction writeAgentFile(agentName: string, fileName: string, content: string): void {\n const dir = path.join(AGENTS_DIR, agentName);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(path.join(dir, fileName), content, 'utf-8');\n}\n\nexport function parseGeneratedFiles(text: string): Record<string, string> {\n const files: Record<string, string> = {};\n const pattern = /---\\s*FILE:\\s*(\\S+)\\s*---\\n([\\s\\S]*?)(?=---\\s*FILE:|$)/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(text)) !== null) {\n const name = match[1].trim();\n const content = match[2].trim();\n if (name && content) files[name] = content;\n }\n return files;\n}\n\nexport function extractAgentName(files: Record<string, string>): string {\n const instructions = files['INSTRUCTIONS.md'] || '';\n const nameMatch = instructions.match(/^name:\\s*(.+)$/m);\n if (nameMatch) return nameMatch[1].trim();\n return 'new-agent';\n}\n\nfunction prompt(rl: readline.Interface, question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n}\n\nasync function conversationLoop(\n rl: readline.Interface,\n llm: { complete: (msgs: LLMMessage[], opts?: any) => Promise<{ text: string }> },\n systemPrompt: string,\n initialUserMessage?: string,\n maxTokens = 4000,\n): Promise<{ history: LLMMessage[]; lastResponse: string }> {\n const history: LLMMessage[] = [{ role: 'system', content: systemPrompt }];\n\n if (initialUserMessage) {\n history.push({ role: 'user', content: initialUserMessage });\n process.stdout.write('\\n Thinking...');\n const response = await llm.complete(history, { maxTokens });\n process.stdout.write('\\r' + ' '.repeat(20) + '\\r');\n history.push({ role: 'assistant', content: response.text });\n console.log(`\\n Vibe: ${response.text}\\n`);\n\n // Check if files were generated\n const files = parseGeneratedFiles(response.text);\n if (Object.keys(files).length > 0) {\n return { history, lastResponse: response.text };\n }\n }\n\n // Continue conversation\n while (true) {\n const input = await prompt(rl, ' You: ');\n if (!input || input === 'exit' || input === 'quit' || input === 'done') {\n return { history, lastResponse: history[history.length - 1]?.content || '' };\n }\n\n history.push({ role: 'user', content: input });\n process.stdout.write(' Thinking...');\n const response = await llm.complete(history, { maxTokens });\n process.stdout.write('\\r' + ' '.repeat(20) + '\\r');\n history.push({ role: 'assistant', content: response.text });\n console.log(`\\n Vibe: ${response.text}\\n`);\n\n // Check if files were generated in this turn\n const files = parseGeneratedFiles(response.text);\n if (Object.keys(files).length > 0) {\n return { history, lastResponse: response.text };\n }\n }\n}\n\nasync function handleCreate(\n rl: readline.Interface,\n llm: { complete: (msgs: LLMMessage[], opts?: any) => Promise<{ text: string }> },\n maxTokens: number,\n): Promise<void> {\n console.log('\\n Describe the agent you want to create:\\n');\n const description = await prompt(rl, ' You: ');\n if (!description) return;\n\n const { lastResponse } = await conversationLoop(rl, llm, META_PROMPT, description, maxTokens);\n const files = parseGeneratedFiles(lastResponse);\n\n if (Object.keys(files).length === 0) {\n console.log('\\n No agent files were generated. Try again with more detail.\\n');\n return;\n }\n\n const agentName = extractAgentName(files);\n console.log(`\\n Writing agent files to agents/${agentName}/\\n`);\n\n for (const [fileName, content] of Object.entries(files)) {\n writeAgentFile(agentName, fileName, content);\n console.log(` + agents/${agentName}/${fileName}`);\n }\n\n console.log(`\\n Agent \"${agentName}\" created! Run \"operor start\" to use it.\\n`);\n}\n\nasync function handleCustomize(\n rl: readline.Interface,\n llm: { complete: (msgs: LLMMessage[], opts?: any) => Promise<{ text: string }> },\n maxTokens: number,\n targetAgent?: string,\n): Promise<void> {\n const agents = listAgents();\n if (agents.length === 0) {\n console.log('\\n No agents found. Create one first with \"operor vibe create\".\\n');\n return;\n }\n\n let agentName = targetAgent;\n if (!agentName) {\n console.log('\\n Available agents:\\n');\n agents.forEach((a, i) => console.log(` ${i + 1}. ${a}`));\n const choice = await prompt(rl, '\\n Select an agent (name or number): ');\n const idx = parseInt(choice, 10);\n agentName = idx > 0 && idx <= agents.length ? agents[idx - 1] : choice;\n }\n\n const instructions = readAgentFile(agentName, 'INSTRUCTIONS.md');\n if (!instructions) {\n console.log(`\\n Agent \"${agentName}\" not found or has no INSTRUCTIONS.md.\\n`);\n return;\n }\n\n console.log(`\\n Customizing agent \"${agentName}\". What would you like to change?\\n`);\n const feedback = await prompt(rl, ' You: ');\n if (!feedback) return;\n\n const contextMessage = `Current INSTRUCTIONS.md for agent \"${agentName}\":\\n\\n${instructions}\\n\\nUser feedback: ${feedback}`;\n const { lastResponse } = await conversationLoop(rl, llm, CUSTOMIZE_PROMPT, contextMessage, maxTokens);\n const files = parseGeneratedFiles(lastResponse);\n\n if (files['INSTRUCTIONS.md']) {\n writeAgentFile(agentName, 'INSTRUCTIONS.md', files['INSTRUCTIONS.md']);\n console.log(`\\n Updated agents/${agentName}/INSTRUCTIONS.md\\n`);\n } else {\n console.log('\\n No changes generated.\\n');\n }\n}\n\nasync function handleConnect(\n rl: readline.Interface,\n llm: { complete: (msgs: LLMMessage[], opts?: any) => Promise<{ text: string }> },\n maxTokens: number,\n targetAgent?: string,\n): Promise<void> {\n const agents = listAgents();\n if (agents.length === 0) {\n console.log('\\n No agents found. Create one first with \"operor vibe create\".\\n');\n return;\n }\n\n let agentName = targetAgent;\n if (!agentName) {\n console.log('\\n Available agents:\\n');\n agents.forEach((a, i) => console.log(` ${i + 1}. ${a}`));\n const choice = await prompt(rl, '\\n Select an agent (name or number): ');\n const idx = parseInt(choice, 10);\n agentName = idx > 0 && idx <= agents.length ? agents[idx - 1] : choice;\n }\n\n const instructions = readAgentFile(agentName, 'INSTRUCTIONS.md');\n if (!instructions) {\n console.log(`\\n Agent \"${agentName}\" not found or has no INSTRUCTIONS.md.\\n`);\n return;\n }\n\n console.log(`\\n What would you like to connect to \"${agentName}\"?`);\n console.log(' (skills: configured via mcp.json, e.g. shopify, stripe, github)');\n console.log(' (channels: whatsapp, telegram, wati)\\n');\n const request = await prompt(rl, ' You: ');\n if (!request) return;\n\n const contextMessage = `Current INSTRUCTIONS.md for agent \"${agentName}\":\\n\\n${instructions}\\n\\nUser request: ${request}`;\n const { lastResponse } = await conversationLoop(rl, llm, CONNECT_PROMPT, contextMessage, maxTokens);\n const files = parseGeneratedFiles(lastResponse);\n\n if (files['INSTRUCTIONS.md']) {\n writeAgentFile(agentName, 'INSTRUCTIONS.md', files['INSTRUCTIONS.md']);\n console.log(`\\n Updated agents/${agentName}/INSTRUCTIONS.md\\n`);\n } else {\n console.log('\\n No changes generated.\\n');\n }\n}\n\nasync function handleImprove(\n rl: readline.Interface,\n llm: { complete: (msgs: LLMMessage[], opts?: any) => Promise<{ text: string }> },\n maxTokens: number,\n targetAgent?: string,\n): Promise<void> {\n const agents = listAgents();\n if (agents.length === 0) {\n console.log('\\n No agents found. Create one first with \"operor vibe create\".\\n');\n return;\n }\n\n let agentName = targetAgent;\n if (!agentName) {\n console.log('\\n Available agents:\\n');\n agents.forEach((a, i) => console.log(` ${i + 1}. ${a}`));\n const choice = await prompt(rl, '\\n Select an agent (name or number): ');\n const idx = parseInt(choice, 10);\n agentName = idx > 0 && idx <= agents.length ? agents[idx - 1] : choice;\n }\n\n const instructions = readAgentFile(agentName, 'INSTRUCTIONS.md');\n if (!instructions) {\n console.log(`\\n Agent \"${agentName}\" not found or has no INSTRUCTIONS.md.\\n`);\n return;\n }\n\n console.log(`\\n Improving agent \"${agentName}\".`);\n console.log(' Share an example of a bad response and what you\\'d prefer:\\n');\n const feedback = await prompt(rl, ' You: ');\n if (!feedback) return;\n\n const contextMessage = `Current INSTRUCTIONS.md for agent \"${agentName}\":\\n\\n${instructions}\\n\\nUser feedback on response quality: ${feedback}`;\n const { lastResponse } = await conversationLoop(rl, llm, IMPROVE_PROMPT, contextMessage, maxTokens);\n const files = parseGeneratedFiles(lastResponse);\n\n if (files['INSTRUCTIONS.md']) {\n writeAgentFile(agentName, 'INSTRUCTIONS.md', files['INSTRUCTIONS.md']);\n console.log(`\\n Updated agents/${agentName}/INSTRUCTIONS.md\\n`);\n } else {\n console.log('\\n No changes generated.\\n');\n }\n}\n\nfunction resolveAction(input: string): string | null {\n const normalized = input.toLowerCase().trim();\n if (['1', 'create'].includes(normalized)) return 'create';\n if (['2', 'customize'].includes(normalized)) return 'customize';\n if (['3', 'connect'].includes(normalized)) return 'connect';\n if (['4', 'improve'].includes(normalized)) return 'improve';\n return null;\n}\n\nexport async function runVibe(opts: VibeOptions): Promise<void> {\n const config = readConfig();\n\n if (!config.LLM_PROVIDER || !config.LLM_API_KEY) {\n console.error('\\n LLM not configured. Run \"operor setup\" first to configure your LLM provider.\\n');\n process.exit(1);\n }\n\n let llm: Awaited<ReturnType<typeof createLLM>>;\n try {\n llm = await createLLM(config);\n } catch (err: any) {\n console.error(`\\n Failed to initialize LLM: ${err.message}\\n`);\n process.exit(1);\n }\n\n const maxTokens = config.VIBE_MAX_TOKENS ? Number(config.VIBE_MAX_TOKENS) : 4000;\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n // Graceful Ctrl+C\n rl.on('close', () => {\n console.log('\\n Goodbye!\\n');\n process.exit(0);\n });\n\n let action = opts.action ? resolveAction(opts.action) : null;\n\n if (!action) {\n console.log(WELCOME);\n const choice = await prompt(rl, ' > ');\n action = resolveAction(choice);\n if (!action) {\n console.log('\\n Invalid choice. Use: create, customize, connect, or improve.\\n');\n rl.close();\n return;\n }\n }\n\n try {\n switch (action) {\n case 'create':\n await handleCreate(rl, llm, maxTokens);\n break;\n case 'customize':\n await handleCustomize(rl, llm, maxTokens, opts.agent);\n break;\n case 'connect':\n await handleConnect(rl, llm, maxTokens, opts.agent);\n break;\n case 'improve':\n await handleImprove(rl, llm, maxTokens, opts.agent);\n break;\n }\n } catch (err: any) {\n if (err.code === 'ERR_USE_AFTER_CLOSE') return; // readline closed via Ctrl+C\n console.error(`\\n Error: ${err.message}\\n`);\n }\n\n rl.close();\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@operor/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI setup wizard and launcher for Operor",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"operor": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@clack/prompts": "^1.0.0",
|
|
19
|
+
"commander": "^14.0.0",
|
|
20
|
+
"dotenv": "^17.0.0",
|
|
21
|
+
"gray-matter": "^4.0.3",
|
|
22
|
+
"@operor/llm": "0.1.0",
|
|
23
|
+
"@operor/core": "0.1.0",
|
|
24
|
+
"@operor/memory": "0.1.0",
|
|
25
|
+
"@operor/provider-mock": "0.1.0",
|
|
26
|
+
"@operor/provider-baileys": "0.1.0",
|
|
27
|
+
"@operor/testing": "0.1.0",
|
|
28
|
+
"@operor/provider-telegram": "0.1.0",
|
|
29
|
+
"@operor/knowledge": "0.1.0",
|
|
30
|
+
"@operor/provider-wati": "0.1.0",
|
|
31
|
+
"@operor/copilot": "0.1.0",
|
|
32
|
+
"@operor/analytics": "0.1.0",
|
|
33
|
+
"@operor/skills": "0.1.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"tsx": "^4.7.0"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsdown",
|
|
40
|
+
"dev": "node --import tsx src/index.ts",
|
|
41
|
+
"test": "vitest run"
|
|
42
|
+
}
|
|
43
|
+
}
|