instar 0.6.14 → 0.7.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.
@@ -24,43 +24,68 @@ This wizard runs in a terminal that may be narrow (80-120 chars). Long text gets
24
24
  **Good** (fits in terminal):
25
25
  > Everything here is just a starting point. You can change any of it later — or just tell your agent to adjust itself.
26
26
 
27
- ## Phase 1: Welcome & Use Case Selection
27
+ ## Phase 1: Context Detection & Welcome
28
28
 
29
- Start with a brief welcome, then immediately ask HOW they want to use Instar.
29
+ **Do NOT ask "how do you want to use Instar?"** Instead, detect the context automatically and present an intelligent default.
30
+
31
+ ### Step 1a: Detect Environment
32
+
33
+ Run these checks BEFORE showing anything to the user:
34
+
35
+ ```bash
36
+ # Check if we're inside a git repository
37
+ git rev-parse --show-toplevel 2>/dev/null
38
+
39
+ # Get the repo name if it exists
40
+ basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null
41
+
42
+ # Check for common project indicators
43
+ ls package.json Cargo.toml pyproject.toml go.mod Gemfile pom.xml 2>/dev/null
44
+ ```
45
+
46
+ ### Step 1b: Present Context-Aware Welcome
47
+
48
+ **If inside a git repository:**
30
49
 
31
50
  ---
32
51
 
33
52
  **Welcome to Instar!**
34
53
 
35
- Instar turns Claude Code into a persistent agent you just talk to through Telegram, not the terminal. This setup gets you there. Two ways to use it:
54
+ I see you're in **[repo-name]**I'll set up a persistent agent for this project.
55
+
56
+ Your agent will monitor, build, and maintain this codebase. You'll talk to it through Telegram — no terminal needed after setup.
57
+
58
+ ---
59
+
60
+ Then proceed directly — no "project vs general" question needed. The context made it obvious.
61
+
62
+ If the user objects ("actually I want a personal agent, not a project agent"), accommodate immediately: "Got it — setting up a personal agent instead."
63
+
64
+ **If NOT inside a git repository:**
36
65
 
37
66
  ---
38
67
 
39
- Present a question with two clear options:
68
+ **Welcome to Instar!**
69
+
70
+ You're not inside a project, so I'll set up a personal agent — a persistent AI companion you talk to through Telegram.
71
+
72
+ It can research, schedule tasks, manage files, and grow over time.
73
+
74
+ ---
40
75
 
41
- 1. **Project Agent** Add an agent to an existing codebase. It monitors, builds, and maintains your project.
42
- 2. **General Agent** — A personal agent on your computer. Like having a persistent AI assistant you talk to through Telegram.
76
+ Then ask: "What should your agent be called?" (default: "my-agent")
43
77
 
44
- This choice determines the defaults, but the agent can always grow into more.
78
+ ### Key principle: Telegram is the interface, always
45
79
 
46
- ### If "Project Agent" selected:
47
- - Use the current working directory as the project
48
- - Default jobs focus on health checks, code monitoring, reflection
49
- - The agent's identity centers on the project
80
+ Regardless of project or personal agent, **Telegram is how you talk to your agent**. This should be clear from the very first message. Don't present it as an optional add-on — it's the destination of this entire setup.
50
81
 
51
- ### If "General Agent" selected:
52
- - Ask for a name for the agent (this becomes the directory name)
53
- - Create the directory in the current location or home dir
54
- - Default jobs focus on communication, scheduling, research
55
- - **Telegram is essential** — without it, a general agent has no natural interface
56
- - Frame the identity around being a personal assistant, not a code monitor
57
- - The AGENT.md should emphasize: "I'm your personal agent. Talk to me through Telegram."
82
+ The terminal session is the on-ramp. Telegram is where the agent experience lives.
58
83
 
59
84
  ## Phase 2: Identity Bootstrap — The Birth Conversation
60
85
 
61
86
  **This is the most important part.** Have a conversation to understand who the user is and who their agent will become. Keep it natural and concise.
62
87
 
63
- For **General Agents**: emphasize that this agent will be their persistent companion. It grows, learns, and communicates through Telegram. It's not a project tool — it's a presence.
88
+ For **Personal Agents**: emphasize that this agent will be their persistent companion. It grows, learns, and communicates through Telegram. It's not a project tool — it's a presence.
64
89
 
65
90
  For **Project Agents**: emphasize that this agent will own the project's health and development. It monitors, builds, and maintains.
66
91
 
@@ -225,30 +250,11 @@ This project uses instar for persistent agent capabilities.
225
250
  - **Research before escalating** — Check tools first. Build solutions. "Needs human" is last resort.
226
251
  ```
227
252
 
228
- ## Phase 3: Technical Configuration
229
-
230
- Now that identity is established, move to the technical setup. This feels more natural — the user already knows what they're building and why.
231
-
232
- ### 3a. Project Detection
233
-
234
- - The project directory is passed in the prompt (e.g., "The project to set up is at: /path/to/project")
235
- - All files should be written there, not in the instar package directory
236
- - Check if `.instar/config.json` already exists (offer to reconfigure or skip)
237
- - Verify prerequisites: check that `tmux` and `claude` CLI are available
238
-
239
- ```bash
240
- which tmux
241
- which claude
242
- ```
243
-
244
- ### 3b. Server Configuration
253
+ ## Phase 3: Telegram Setup — The Destination
245
254
 
246
- - **Port** (default: 4040) "The agent runs a small HTTP server for health checks and internal communication."
247
- - **Max sessions** (default: 3) — "This limits how many Claude sessions can run at once. 2-3 is usually right."
255
+ **Telegram comes BEFORE technical configuration.** It's the whole point everything else supports getting the user onto Telegram.
248
256
 
249
- ### 3c. Telegram Setup — The Destination
250
-
251
- **This terminal session is the on-ramp. Telegram is where the agent experience truly begins.** Frame it that way:
257
+ Frame it clearly:
252
258
 
253
259
  > Right now we're in a terminal. Telegram is where your agent comes alive:
254
260
  > - **Just talk** — no commands, no terminal, just conversation
@@ -256,9 +262,7 @@ which claude
256
262
  > - **Mobile access** — your agent is always reachable
257
263
  > - **Proactive** — your agent reaches out when something matters
258
264
 
259
- The goal of this setup is to get the user onto Telegram as fast as possible. Everything else (jobs, config, technical setup) supports that destination.
260
-
261
- For **General Agents**: Telegram is essential. Without it, there IS no natural interface. Be direct: "This is how you'll talk to your agent."
265
+ For **Personal Agents**: Telegram is essential. Without it, there IS no natural interface. Be direct: "This is how you'll talk to your agent."
262
266
 
263
267
  For **Project Agents**: Telegram is strongly recommended. Frame it as: "Your agent can message you about builds, issues, and progress — you just reply."
264
268
 
@@ -382,7 +386,32 @@ curl -s "https://api.telegram.org/bot${TOKEN}/getUpdates?timeout=5"
382
386
  - Look for `chat.id` where `chat.type` is "supergroup" or "group"
383
387
  - If auto-detection fails, guide manual entry
384
388
 
385
- ### 3d. Job Scheduler (Optional)
389
+ ## Phase 4: Technical Configuration
390
+
391
+ Now that identity and Telegram are established, handle the remaining technical setup. These should feel like sensible defaults, not interrogation.
392
+
393
+ ### 4a. Project Detection
394
+
395
+ - The project directory is passed in the prompt (e.g., "The project to set up is at: /path/to/project")
396
+ - All files should be written there, not in the instar package directory
397
+ - Check if `.instar/config.json` already exists (offer to reconfigure or skip)
398
+ - Verify prerequisites: check that `tmux` and `claude` CLI are available
399
+
400
+ ```bash
401
+ which tmux
402
+ which claude
403
+ ```
404
+
405
+ ### 4b. Server Configuration
406
+
407
+ Present sensible defaults — don't make the user think about these unless they want to:
408
+
409
+ - **Port** (default: 4040) — "The agent runs a small local server."
410
+ - **Max sessions** (default: 3) — "How many Claude sessions can run at once."
411
+
412
+ Ask as a single confirmation: "I'll use port 4040 with up to 3 sessions. Want to change these?" If yes, ask for specifics. If no, move on.
413
+
414
+ ### 4c. Job Scheduler (Optional)
386
415
 
387
416
  - Ask if they want scheduled jobs
388
417
  - If yes, walk through adding a first job:
@@ -393,7 +422,7 @@ curl -s "https://api.telegram.org/bot${TOKEN}/getUpdates?timeout=5"
393
422
  - **Execution type**: prompt (AI instruction), script (shell script), or skill (slash command)
394
423
  - Offer to add more jobs
395
424
 
396
- ### 3e. Write Configuration Files
425
+ ### 4d. Write Configuration Files
397
426
 
398
427
  Create the directory structure and write config files:
399
428
 
@@ -438,7 +467,7 @@ mkdir -p .instar/state/sessions .instar/state/jobs .instar/logs
438
467
 
439
468
  **`.instar/users.json`**: Array of user objects from the identity conversation.
440
469
 
441
- ### 3f. Update .gitignore
470
+ ### 4e. Update .gitignore
442
471
 
443
472
  Append if not present:
444
473
  ```
@@ -447,7 +476,7 @@ Append if not present:
447
476
  .instar/logs/
448
477
  ```
449
478
 
450
- ## Phase 4: Summary & Launch
479
+ ## Phase 5: Summary & Launch
451
480
 
452
481
  Show what was created briefly, then get the user to their agent.
453
482
 
@@ -485,4 +514,4 @@ Offer to start the server.
485
514
 
486
515
  ## Starting
487
516
 
488
- Begin by reading the project directory, checking for existing config, and then launching into the welcome explanation followed by the identity conversation. Let the conversation flow naturally.
517
+ Begin by detecting the environment (git repo check, project file check), then present the context-aware welcome. Let the conversation flow naturally from there.
@@ -0,0 +1,11 @@
1
+ > Why do I have a folder named ".vercel" in my project?
2
+ The ".vercel" folder is created when you link a directory to a Vercel project.
3
+
4
+ > What does the "project.json" file contain?
5
+ The "project.json" file contains:
6
+ - The ID of the Vercel project that you linked ("projectId")
7
+ - The ID of the user or team your Vercel project is owned by ("orgId")
8
+
9
+ > Should I commit the ".vercel" folder?
10
+ No, you should not share the ".vercel" folder with anyone.
11
+ Upon creation, it will be automatically added to your ".gitignore" file.
@@ -0,0 +1 @@
1
+ {"projectId":"prj_evM5LcItYL3IAmw8zNvEPGrHeaya","orgId":"team_dHctwIDcV3X9ydapQlCPHFGI","projectName":"claude-agent-kit"}
package/dist/cli.js CHANGED
File without changes
@@ -1336,6 +1336,15 @@ fi
1336
1336
  # For startup/resume/clear — output a compact orientation
1337
1337
  echo "=== SESSION START ==="
1338
1338
 
1339
+ # Telegram-spawned session awareness
1340
+ # When auto-created for a Telegram topic, prime the agent to respond immediately
1341
+ if [ -n "\$INSTAR_TELEGRAM_TOPIC" ]; then
1342
+ echo ""
1343
+ echo "This session was auto-spawned for Telegram topic \$INSTAR_TELEGRAM_TOPIC."
1344
+ echo "A message from your user triggered this session and will arrive momentarily."
1345
+ echo "IMMEDIATELY acknowledge it via your Telegram relay — they are waiting."
1346
+ fi
1347
+
1339
1348
  # Identity summary (first 20 lines of AGENT.md — enough for name + role)
1340
1349
  if [ -f "$INSTAR_DIR/AGENT.md" ]; then
1341
1350
  echo ""
@@ -18,6 +18,8 @@ import { JobScheduler } from '../scheduler/JobScheduler.js';
18
18
  import { AgentServer } from '../server/AgentServer.js';
19
19
  import { TelegramAdapter } from '../messaging/TelegramAdapter.js';
20
20
  import { RelationshipManager } from '../core/RelationshipManager.js';
21
+ import { ClaudeCliIntelligenceProvider } from '../core/ClaudeCliIntelligenceProvider.js';
22
+ import { AnthropicIntelligenceProvider } from '../core/AnthropicIntelligenceProvider.js';
21
23
  import { FeedbackManager } from '../core/FeedbackManager.js';
22
24
  import { DispatchManager } from '../core/DispatchManager.js';
23
25
  import { UpdateChecker } from '../core/UpdateChecker.js';
@@ -25,6 +27,8 @@ import { registerPort, unregisterPort, startHeartbeat } from '../core/PortRegist
25
27
  import { TelegraphService } from '../publishing/TelegraphService.js';
26
28
  import { PrivateViewer } from '../publishing/PrivateViewer.js';
27
29
  import { TunnelManager } from '../tunnel/TunnelManager.js';
30
+ import { EvolutionManager } from '../core/EvolutionManager.js';
31
+ import { QuotaTracker } from '../monitoring/QuotaTracker.js';
28
32
  /**
29
33
  * Respawn a session for a topic, including thread history in the bootstrap.
30
34
  * This prevents "thread drift" where respawned sessions lose context.
@@ -218,9 +222,9 @@ function wireTelegramRouting(telegram, sessionManager) {
218
222
  const ctxPath = path.join(tmpDir, `ctx-${topicId}-${Date.now()}.txt`);
219
223
  fs.writeFileSync(ctxPath, contextLines.join('\n'));
220
224
  const bootstrapMessage = `[telegram:${topicId}] ${text} (IMPORTANT: Read ${ctxPath} for Telegram relay instructions — you MUST relay your response back.)`;
221
- sessionManager.spawnInteractiveSession(bootstrapMessage, storedName).then((newSessionName) => {
225
+ sessionManager.spawnInteractiveSession(bootstrapMessage, storedName, { telegramTopicId: topicId }).then((newSessionName) => {
222
226
  telegram.registerTopicSession(topicId, newSessionName);
223
- telegram.sendToTopic(topicId, `Session created.`).catch(() => { });
227
+ telegram.sendToTopic(topicId, `Session starting up — reading your message now. One moment.`).catch(() => { });
224
228
  console.log(`[telegram→session] Auto-spawned "${newSessionName}" for topic ${topicId}`);
225
229
  }).catch((err) => {
226
230
  console.error(`[telegram→session] Auto-spawn failed:`, err);
@@ -351,12 +355,51 @@ export async function startServer(options) {
351
355
  const sessionManager = new SessionManager(config.sessions, state);
352
356
  let relationships;
353
357
  if (config.relationships) {
358
+ // Wire LLM intelligence for identity resolution.
359
+ // Priority: Claude CLI (subscription, zero extra cost) > Anthropic API (explicit opt-in only)
360
+ const claudePath = config.sessions.claudePath;
361
+ let intelligenceMode = 'heuristic-only';
362
+ // Check if user explicitly opted into API-based intelligence
363
+ // (intelligenceProvider is a config-file-only field, not in the TypeScript type)
364
+ const explicitProvider = config.relationships.intelligenceProvider;
365
+ if (explicitProvider === 'anthropic-api') {
366
+ // User explicitly chose API — respect their decision
367
+ const apiProvider = AnthropicIntelligenceProvider.fromEnv();
368
+ if (apiProvider) {
369
+ config.relationships.intelligence = apiProvider;
370
+ intelligenceMode = 'LLM-supervised (Anthropic API — user choice)';
371
+ }
372
+ else {
373
+ console.log(pc.yellow(' intelligenceProvider: "anthropic-api" set but ANTHROPIC_API_KEY not found'));
374
+ }
375
+ }
376
+ else if (claudePath) {
377
+ // Default: use Claude CLI via subscription (zero extra cost)
378
+ config.relationships.intelligence = new ClaudeCliIntelligenceProvider(claudePath);
379
+ intelligenceMode = 'LLM-supervised (Claude CLI subscription)';
380
+ }
354
381
  relationships = new RelationshipManager(config.relationships);
355
- console.log(pc.green(` Relationships loaded: ${relationships.getAll().length} tracked`));
382
+ const count = relationships.getAll().length;
383
+ console.log(pc.green(` Relationships loaded: ${count} tracked (${intelligenceMode})`));
384
+ }
385
+ // Set up quota tracking if enabled
386
+ let quotaTracker;
387
+ if (config.monitoring?.quotaTracking) {
388
+ const quotaFile = config.monitoring.quotaStateFile
389
+ || path.join(config.stateDir, 'quota-state.json');
390
+ quotaTracker = new QuotaTracker({
391
+ quotaFile,
392
+ thresholds: config.scheduler?.quotaThresholds ?? { normal: 50, elevated: 60, critical: 80, shutdown: 95 },
393
+ });
394
+ console.log(pc.green(` Quota tracking enabled (${quotaFile})`));
356
395
  }
357
396
  let scheduler;
358
397
  if (config.scheduler.enabled) {
359
398
  scheduler = new JobScheduler(config.scheduler, sessionManager, state, config.stateDir);
399
+ if (quotaTracker) {
400
+ scheduler.canRunJob = quotaTracker.canRunJob.bind(quotaTracker);
401
+ scheduler.setQuotaTracker(quotaTracker);
402
+ }
360
403
  scheduler.start();
361
404
  console.log(pc.green(' Scheduler started'));
362
405
  }
@@ -454,7 +497,13 @@ export async function startServer(options) {
454
497
  stateDir: config.stateDir,
455
498
  });
456
499
  }
457
- const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, dispatches, updateChecker, publisher, viewer, tunnel });
500
+ // Set up evolution system (always enabled the feedback loop infrastructure)
501
+ const evolution = new EvolutionManager({
502
+ stateDir: config.stateDir,
503
+ ...(config.evolution || {}),
504
+ });
505
+ console.log(pc.green(' Evolution system enabled'));
506
+ const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, dispatches, updateChecker, quotaTracker, publisher, viewer, tunnel, evolution });
458
507
  await server.start();
459
508
  // Start tunnel AFTER server is listening
460
509
  if (tunnel) {
@@ -69,8 +69,23 @@ export async function runSetup(opts) {
69
69
  console.log(pc.dim(' Security is enforced through behavioral hooks, identity grounding, and'));
70
70
  console.log(pc.dim(' scoped access — not permission dialogs. See: README.md > Security Model'));
71
71
  console.log();
72
+ // Detect git context to pass to the conversational wizard
73
+ const projectDir = process.cwd();
74
+ let gitContext = '';
75
+ try {
76
+ const gitRoot = execFileSync('git', ['rev-parse', '--show-toplevel'], {
77
+ cwd: projectDir,
78
+ encoding: 'utf-8',
79
+ stdio: ['pipe', 'pipe', 'pipe'],
80
+ }).trim();
81
+ const repoName = path.basename(gitRoot);
82
+ gitContext = ` This directory is inside a git repository "${repoName}" at ${gitRoot}.`;
83
+ }
84
+ catch {
85
+ gitContext = ' This directory is NOT inside a git repository.';
86
+ }
72
87
  // Launch Claude Code from the instar package root (where .claude/skills/ lives)
73
- // and pass the target project directory in the prompt.
88
+ // and pass the target project directory + git context in the prompt.
74
89
  //
75
90
  // --dangerously-skip-permissions is required here because the setup wizard
76
91
  // runs in instar's OWN package directory (instarRoot), not the user's
@@ -78,10 +93,9 @@ export async function runSetup(opts) {
78
93
  // user's project directory, which breaks the interactive flow. The wizard
79
94
  // only writes to well-defined locations (.instar/, .claude/, CLAUDE.md).
80
95
  const instarRoot = findInstarRoot();
81
- const projectDir = process.cwd();
82
96
  const child = spawn(claudePath, [
83
97
  '--dangerously-skip-permissions',
84
- `/setup-wizard The project to set up is at: ${projectDir}`,
98
+ `/setup-wizard The project to set up is at: ${projectDir}.${gitContext}`,
85
99
  ], {
86
100
  cwd: instarRoot,
87
101
  stdio: 'inherit',
@@ -126,6 +140,22 @@ function findInstarRoot() {
126
140
  // Fallback: assume we're in dist/commands/ — go up to root
127
141
  return path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..');
128
142
  }
143
+ /**
144
+ * Detect whether the current directory is inside a git repository.
145
+ */
146
+ function detectGitRepo(dir) {
147
+ try {
148
+ const root = execFileSync('git', ['rev-parse', '--show-toplevel'], {
149
+ cwd: dir,
150
+ encoding: 'utf-8',
151
+ stdio: ['pipe', 'pipe', 'pipe'],
152
+ }).trim();
153
+ return { isRepo: true, repoRoot: root, repoName: path.basename(root) };
154
+ }
155
+ catch {
156
+ return { isRepo: false };
157
+ }
158
+ }
129
159
  /**
130
160
  * Classic inquirer-based setup wizard.
131
161
  * The original interactive setup experience.
@@ -133,7 +163,7 @@ function findInstarRoot() {
133
163
  async function runClassicSetup() {
134
164
  console.log();
135
165
  console.log(pc.bold(' Welcome to Instar'));
136
- console.log(pc.dim(' Persistent agent infrastructure for any Claude Code project'));
166
+ console.log(pc.dim(' Turn Claude Code into a persistent agent you talk to through Telegram.'));
137
167
  console.log();
138
168
  // ── Step 0: Check and install prerequisites ─────────────────────
139
169
  const prereqs = await ensurePrerequisites();
@@ -143,19 +173,59 @@ async function runClassicSetup() {
143
173
  const tmuxPath = prereqs.results.find(r => r.name === 'tmux').path;
144
174
  // Use a scoped name to avoid shadowing the outer runSetup's claudePath
145
175
  const claudePath = prereqs.results.find(r => r.name === 'Claude CLI').path;
146
- // ── Step 1: Project ──────────────────────────────────────────────
176
+ // ── Step 1: Detect context and determine mode ─────────────────
147
177
  const detectedDir = process.cwd();
148
- const detectedName = path.basename(detectedDir);
149
- const projectDir = detectedDir; // Always use cwd
150
- const projectName = await input({
151
- message: 'Project name',
152
- default: detectedName,
153
- });
178
+ const gitInfo = detectGitRepo(detectedDir);
179
+ let projectDir;
180
+ let projectName;
181
+ let isProjectAgent;
182
+ if (gitInfo.isRepo) {
183
+ // Inside a git repository — suggest project agent
184
+ console.log(` ${pc.green('✓')} Detected git repository: ${pc.cyan(gitInfo.repoName)}`);
185
+ console.log(pc.dim(` ${gitInfo.repoRoot}`));
186
+ console.log();
187
+ console.log(pc.dim(' Your agent will live alongside this project — monitoring, building,'));
188
+ console.log(pc.dim(' and maintaining it. You talk to it through Telegram.'));
189
+ console.log();
190
+ const useThisRepo = await confirm({
191
+ message: `Set up an agent for ${gitInfo.repoName}?`,
192
+ default: true,
193
+ });
194
+ if (useThisRepo) {
195
+ projectDir = gitInfo.repoRoot;
196
+ projectName = await input({
197
+ message: 'Agent name',
198
+ default: gitInfo.repoName,
199
+ });
200
+ isProjectAgent = true;
201
+ }
202
+ else {
203
+ // They want a general agent instead
204
+ projectName = await input({
205
+ message: 'What should your agent be called?',
206
+ default: 'my-agent',
207
+ });
208
+ projectDir = detectedDir;
209
+ isProjectAgent = false;
210
+ }
211
+ }
212
+ else {
213
+ // Not in a git repo — this is a general/personal agent
214
+ console.log(pc.dim(' No git repository detected — setting up a personal agent.'));
215
+ console.log(pc.dim(' A personal agent lives on your machine and you talk to it through Telegram.'));
216
+ console.log();
217
+ projectName = await input({
218
+ message: 'What should your agent be called?',
219
+ default: 'my-agent',
220
+ });
221
+ projectDir = detectedDir;
222
+ isProjectAgent = false;
223
+ }
154
224
  // Check if already initialized
155
225
  const stateDir = path.join(projectDir, '.instar');
156
226
  if (fs.existsSync(path.join(stateDir, 'config.json'))) {
157
227
  const overwrite = await confirm({
158
- message: 'Agent kit already initialized here. Reconfigure?',
228
+ message: 'Agent already initialized here. Reconfigure?',
159
229
  default: false,
160
230
  });
161
231
  if (!overwrite) {
@@ -163,7 +233,19 @@ async function runClassicSetup() {
163
233
  return;
164
234
  }
165
235
  }
166
- // ── Step 2: Server port + sessions ─────────────────────────────
236
+ // ── Step 2: Telegram the primary interface ───────────────────
237
+ console.log();
238
+ console.log(pc.bold(' Telegram — How You Talk to Your Agent'));
239
+ console.log();
240
+ console.log(pc.dim(' Once connected, you just talk — no commands, no terminal.'));
241
+ console.log(pc.dim(' Topic threads, message history, mobile access, proactive notifications.'));
242
+ if (!isProjectAgent) {
243
+ console.log();
244
+ console.log(pc.dim(' For a personal agent, Telegram IS the interface.'));
245
+ }
246
+ console.log();
247
+ const telegramConfig = await promptForTelegram();
248
+ // ── Step 3: Server config (sensible defaults) ──────────────────
167
249
  const port = await number({
168
250
  message: 'Server port',
169
251
  default: 4040,
@@ -182,14 +264,6 @@ async function runClassicSetup() {
182
264
  return true;
183
265
  },
184
266
  }) ?? 3;
185
- // ── Step 3: Telegram (BEFORE users, so we know context) ────────
186
- console.log();
187
- console.log(pc.bold(' Telegram — Where Your Agent Lives'));
188
- console.log(pc.dim(' Telegram is where the real experience begins.'));
189
- console.log(pc.dim(' Once connected, you just talk — no commands, no terminal.'));
190
- console.log(pc.dim(' Topic threads, message history, mobile access, proactive notifications.'));
191
- console.log();
192
- const telegramConfig = await promptForTelegram();
193
267
  // ── Step 4: User setup ─────────────────────────────────────────
194
268
  console.log();
195
269
  const addUser = await confirm({
@@ -0,0 +1,24 @@
1
+ /**
2
+ * AnthropicIntelligenceProvider — OPTIONAL IntelligenceProvider using the Anthropic Messages API.
3
+ *
4
+ * ⚠️ This provider uses API tokens (extra cost). For most Instar agents, the
5
+ * ClaudeCliIntelligenceProvider (which uses the Claude subscription) is the
6
+ * correct default. Only use this provider when:
7
+ * - The user explicitly sets intelligenceProvider: "anthropic-api" in config
8
+ * - The Claude CLI is not available
9
+ * - The user has a specific reason to prefer direct API access
10
+ *
11
+ * No SDK dependency — direct fetch calls, following the TelegramAdapter pattern.
12
+ */
13
+ import type { IntelligenceProvider, IntelligenceOptions } from './types.js';
14
+ export declare class AnthropicIntelligenceProvider implements IntelligenceProvider {
15
+ private apiKey;
16
+ constructor(apiKey: string);
17
+ /**
18
+ * Create a provider from environment variables, or null if no key available.
19
+ * Follows the same graceful degradation pattern as TelegramAdapter's voice providers.
20
+ */
21
+ static fromEnv(): AnthropicIntelligenceProvider | null;
22
+ evaluate(prompt: string, options?: IntelligenceOptions): Promise<string>;
23
+ }
24
+ //# sourceMappingURL=AnthropicIntelligenceProvider.d.ts.map
@@ -0,0 +1,68 @@
1
+ /**
2
+ * AnthropicIntelligenceProvider — OPTIONAL IntelligenceProvider using the Anthropic Messages API.
3
+ *
4
+ * ⚠️ This provider uses API tokens (extra cost). For most Instar agents, the
5
+ * ClaudeCliIntelligenceProvider (which uses the Claude subscription) is the
6
+ * correct default. Only use this provider when:
7
+ * - The user explicitly sets intelligenceProvider: "anthropic-api" in config
8
+ * - The Claude CLI is not available
9
+ * - The user has a specific reason to prefer direct API access
10
+ *
11
+ * No SDK dependency — direct fetch calls, following the TelegramAdapter pattern.
12
+ */
13
+ const ANTHROPIC_API_URL = 'https://api.anthropic.com/v1/messages';
14
+ const ANTHROPIC_API_VERSION = '2023-06-01';
15
+ /** Model mapping: abstract tiers → concrete Anthropic model IDs */
16
+ const MODEL_MAP = {
17
+ fast: 'claude-haiku-4-5-20251001',
18
+ balanced: 'claude-sonnet-4-5-20250514',
19
+ capable: 'claude-opus-4-0-20250514',
20
+ };
21
+ const DEFAULT_MODEL = 'fast';
22
+ export class AnthropicIntelligenceProvider {
23
+ apiKey;
24
+ constructor(apiKey) {
25
+ this.apiKey = apiKey;
26
+ }
27
+ /**
28
+ * Create a provider from environment variables, or null if no key available.
29
+ * Follows the same graceful degradation pattern as TelegramAdapter's voice providers.
30
+ */
31
+ static fromEnv() {
32
+ const apiKey = process.env['ANTHROPIC_API_KEY'];
33
+ if (!apiKey) {
34
+ return null;
35
+ }
36
+ return new AnthropicIntelligenceProvider(apiKey);
37
+ }
38
+ async evaluate(prompt, options) {
39
+ const model = MODEL_MAP[options?.model ?? DEFAULT_MODEL] ?? MODEL_MAP[DEFAULT_MODEL];
40
+ const maxTokens = options?.maxTokens ?? 100;
41
+ const temperature = options?.temperature ?? 0;
42
+ const response = await fetch(ANTHROPIC_API_URL, {
43
+ method: 'POST',
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ 'x-api-key': this.apiKey,
47
+ 'anthropic-version': ANTHROPIC_API_VERSION,
48
+ },
49
+ body: JSON.stringify({
50
+ model,
51
+ max_tokens: maxTokens,
52
+ temperature,
53
+ messages: [
54
+ { role: 'user', content: prompt },
55
+ ],
56
+ }),
57
+ });
58
+ if (!response.ok) {
59
+ const errorText = await response.text().catch(() => 'unknown error');
60
+ throw new Error(`Anthropic API error ${response.status}: ${errorText}`);
61
+ }
62
+ const data = await response.json();
63
+ // Extract text from the response
64
+ const textBlock = data.content?.find((block) => block.type === 'text');
65
+ return textBlock?.text ?? '';
66
+ }
67
+ }
68
+ //# sourceMappingURL=AnthropicIntelligenceProvider.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ClaudeCliIntelligenceProvider — Default IntelligenceProvider using the Claude CLI.
3
+ *
4
+ * Uses `claude -p` (print mode) to make judgment calls via the user's existing
5
+ * Claude subscription. Zero extra cost — the subscription is already paid for.
6
+ *
7
+ * This is the DEFAULT provider for Instar agents. The Anthropic API provider
8
+ * (AnthropicIntelligenceProvider) is an explicit opt-in alternative for users
9
+ * who intentionally choose direct API access.
10
+ *
11
+ * Preference hierarchy:
12
+ * 1. Claude CLI (subscription) — default, always available
13
+ * 2. Anthropic API — explicit user choice only
14
+ */
15
+ import type { IntelligenceProvider, IntelligenceOptions } from './types.js';
16
+ export declare class ClaudeCliIntelligenceProvider implements IntelligenceProvider {
17
+ private claudePath;
18
+ constructor(claudePath: string);
19
+ evaluate(prompt: string, options?: IntelligenceOptions): Promise<string>;
20
+ }
21
+ //# sourceMappingURL=ClaudeCliIntelligenceProvider.d.ts.map