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.
- package/.claude/skills/setup-wizard/skill.md +78 -49
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/dist/cli.js +0 -0
- package/dist/commands/init.js +9 -0
- package/dist/commands/server.js +53 -4
- package/dist/commands/setup.js +95 -21
- package/dist/core/AnthropicIntelligenceProvider.d.ts +24 -0
- package/dist/core/AnthropicIntelligenceProvider.js +68 -0
- package/dist/core/ClaudeCliIntelligenceProvider.d.ts +21 -0
- package/dist/core/ClaudeCliIntelligenceProvider.js +59 -0
- package/dist/core/EvolutionManager.d.ts +157 -0
- package/dist/core/EvolutionManager.js +432 -0
- package/dist/core/Prerequisites.js +2 -1
- package/dist/core/RelationshipManager.d.ts +67 -0
- package/dist/core/RelationshipManager.js +358 -4
- package/dist/core/SessionManager.d.ts +3 -1
- package/dist/core/SessionManager.js +14 -6
- package/dist/core/types.d.ts +224 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +4 -0
- package/dist/monitoring/QuotaExhaustionDetector.d.ts +21 -0
- package/dist/monitoring/QuotaExhaustionDetector.js +136 -0
- package/dist/monitoring/QuotaTracker.d.ts +41 -5
- package/dist/monitoring/QuotaTracker.js +103 -14
- package/dist/scaffold/bootstrap.js +2 -1
- package/dist/scheduler/JobScheduler.d.ts +9 -0
- package/dist/scheduler/JobScheduler.js +33 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/routes.d.ts +2 -0
- package/dist/server/routes.js +218 -0
- package/package.json +1 -1
|
@@ -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:
|
|
27
|
+
## Phase 1: Context Detection & Welcome
|
|
28
28
|
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
+
### Key principle: Telegram is the interface, always
|
|
45
79
|
|
|
46
|
-
|
|
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
|
-
|
|
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 **
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
|
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
|
|
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
|
package/dist/commands/init.js
CHANGED
|
@@ -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 ""
|
package/dist/commands/server.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|
package/dist/commands/setup.js
CHANGED
|
@@ -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('
|
|
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:
|
|
176
|
+
// ── Step 1: Detect context and determine mode ─────────────────
|
|
147
177
|
const detectedDir = process.cwd();
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
|
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:
|
|
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
|