instar 0.6.12 → 0.6.13

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.
@@ -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
@@ -21,7 +21,7 @@ import fs from 'node:fs';
21
21
  import path from 'node:path';
22
22
  import { Command } from 'commander';
23
23
  import { initProject } from './commands/init.js';
24
- import { runSetup } from './commands/setup.js';
24
+ // setup.ts is imported dynamically — it depends on @inquirer/prompts which requires Node 20.12+
25
25
  import { startServer, stopServer } from './commands/server.js';
26
26
  import { showStatus } from './commands/status.js';
27
27
  import { addUser, listUsers } from './commands/user.js';
@@ -257,13 +257,33 @@ program
257
257
  .description('Persistent autonomy infrastructure for AI agents')
258
258
  .version(getInstarVersion())
259
259
  .option('--classic', 'Use the classic inquirer-based setup wizard instead of Claude')
260
- .action((opts) => runSetup(opts)); // Default: run interactive setup when no subcommand given
260
+ .action(async (opts) => {
261
+ const [major, minor] = process.versions.node.split('.').map(Number);
262
+ if (major < 20 || (major === 20 && minor < 12)) {
263
+ console.error(`\n Instar setup requires Node.js 20.12 or later.`);
264
+ console.error(` You're running Node.js ${process.versions.node}.`);
265
+ console.error(`\n Upgrade: https://nodejs.org/en/download\n`);
266
+ process.exit(1);
267
+ }
268
+ const { runSetup } = await import('./commands/setup.js');
269
+ return runSetup(opts);
270
+ }); // Default: run interactive setup when no subcommand given
261
271
  // ── Setup (explicit alias) ────────────────────────────────────────
262
272
  program
263
273
  .command('setup')
264
274
  .description('Interactive setup wizard (same as running `instar` with no args)')
265
275
  .option('--classic', 'Use the classic inquirer-based setup wizard instead of Claude')
266
- .action((opts) => runSetup(opts));
276
+ .action(async (opts) => {
277
+ const [major, minor] = process.versions.node.split('.').map(Number);
278
+ if (major < 20 || (major === 20 && minor < 12)) {
279
+ console.error(`\n Instar setup requires Node.js 20.12 or later.`);
280
+ console.error(` You're running Node.js ${process.versions.node}.`);
281
+ console.error(`\n Upgrade: https://nodejs.org/en/download\n`);
282
+ process.exit(1);
283
+ }
284
+ const { runSetup } = await import('./commands/setup.js');
285
+ return runSetup(opts);
286
+ });
267
287
  // ── Init ─────────────────────────────────────────────────────────
268
288
  program
269
289
  .command('init [project-name]')
@@ -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,7 @@ 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';
28
31
  /**
29
32
  * Respawn a session for a topic, including thread history in the bootstrap.
30
33
  * This prevents "thread drift" where respawned sessions lose context.
@@ -218,9 +221,9 @@ function wireTelegramRouting(telegram, sessionManager) {
218
221
  const ctxPath = path.join(tmpDir, `ctx-${topicId}-${Date.now()}.txt`);
219
222
  fs.writeFileSync(ctxPath, contextLines.join('\n'));
220
223
  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) => {
224
+ sessionManager.spawnInteractiveSession(bootstrapMessage, storedName, { telegramTopicId: topicId }).then((newSessionName) => {
222
225
  telegram.registerTopicSession(topicId, newSessionName);
223
- telegram.sendToTopic(topicId, `Session created.`).catch(() => { });
226
+ telegram.sendToTopic(topicId, `Session starting up — reading your message now. One moment.`).catch(() => { });
224
227
  console.log(`[telegram→session] Auto-spawned "${newSessionName}" for topic ${topicId}`);
225
228
  }).catch((err) => {
226
229
  console.error(`[telegram→session] Auto-spawn failed:`, err);
@@ -351,8 +354,32 @@ export async function startServer(options) {
351
354
  const sessionManager = new SessionManager(config.sessions, state);
352
355
  let relationships;
353
356
  if (config.relationships) {
357
+ // Wire LLM intelligence for identity resolution.
358
+ // Priority: Claude CLI (subscription, zero extra cost) > Anthropic API (explicit opt-in only)
359
+ const claudePath = config.sessions.claudePath;
360
+ let intelligenceMode = 'heuristic-only';
361
+ // Check if user explicitly opted into API-based intelligence
362
+ // (intelligenceProvider is a config-file-only field, not in the TypeScript type)
363
+ const explicitProvider = config.relationships.intelligenceProvider;
364
+ if (explicitProvider === 'anthropic-api') {
365
+ // User explicitly chose API — respect their decision
366
+ const apiProvider = AnthropicIntelligenceProvider.fromEnv();
367
+ if (apiProvider) {
368
+ config.relationships.intelligence = apiProvider;
369
+ intelligenceMode = 'LLM-supervised (Anthropic API — user choice)';
370
+ }
371
+ else {
372
+ console.log(pc.yellow(' intelligenceProvider: "anthropic-api" set but ANTHROPIC_API_KEY not found'));
373
+ }
374
+ }
375
+ else if (claudePath) {
376
+ // Default: use Claude CLI via subscription (zero extra cost)
377
+ config.relationships.intelligence = new ClaudeCliIntelligenceProvider(claudePath);
378
+ intelligenceMode = 'LLM-supervised (Claude CLI subscription)';
379
+ }
354
380
  relationships = new RelationshipManager(config.relationships);
355
- console.log(pc.green(` Relationships loaded: ${relationships.getAll().length} tracked`));
381
+ const count = relationships.getAll().length;
382
+ console.log(pc.green(` Relationships loaded: ${count} tracked (${intelligenceMode})`));
356
383
  }
357
384
  let scheduler;
358
385
  if (config.scheduler.enabled) {
@@ -454,7 +481,13 @@ export async function startServer(options) {
454
481
  stateDir: config.stateDir,
455
482
  });
456
483
  }
457
- const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, dispatches, updateChecker, publisher, viewer, tunnel });
484
+ // Set up evolution system (always enabled the feedback loop infrastructure)
485
+ const evolution = new EvolutionManager({
486
+ stateDir: config.stateDir,
487
+ ...(config.evolution || {}),
488
+ });
489
+ console.log(pc.green(' Evolution system enabled'));
490
+ const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, dispatches, updateChecker, publisher, viewer, tunnel, evolution });
458
491
  await server.start();
459
492
  // Start tunnel AFTER server is listening
460
493
  if (tunnel) {
@@ -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
@@ -0,0 +1,59 @@
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 { execFile } from 'node:child_process';
16
+ /** Model mapping: abstract tiers → Claude CLI model flags */
17
+ const MODEL_MAP = {
18
+ fast: 'haiku',
19
+ balanced: 'sonnet',
20
+ capable: 'opus',
21
+ };
22
+ const DEFAULT_MODEL = 'fast';
23
+ const DEFAULT_TIMEOUT_MS = 30_000;
24
+ export class ClaudeCliIntelligenceProvider {
25
+ claudePath;
26
+ constructor(claudePath) {
27
+ this.claudePath = claudePath;
28
+ }
29
+ async evaluate(prompt, options) {
30
+ const model = MODEL_MAP[options?.model ?? DEFAULT_MODEL] ?? MODEL_MAP[DEFAULT_MODEL];
31
+ const maxTokens = options?.maxTokens ?? 100;
32
+ return new Promise((resolve, reject) => {
33
+ const args = [
34
+ '-p', prompt,
35
+ '--model', model,
36
+ '--max-turns', '1',
37
+ '--output-format', 'text',
38
+ ];
39
+ if (maxTokens) {
40
+ args.push('--max-tokens', String(maxTokens));
41
+ }
42
+ const child = execFile(this.claudePath, args, {
43
+ timeout: DEFAULT_TIMEOUT_MS,
44
+ maxBuffer: 1024 * 1024, // 1MB
45
+ env: { ...process.env },
46
+ }, (error, stdout, stderr) => {
47
+ if (error) {
48
+ // Timeout or other error — return empty so caller can fall back
49
+ reject(new Error(`Claude CLI error: ${error.message}${stderr ? ` — ${stderr.slice(0, 200)}` : ''}`));
50
+ return;
51
+ }
52
+ resolve(stdout.trim());
53
+ });
54
+ // Write prompt via stdin for very long prompts (belt and suspenders)
55
+ child.stdin?.end();
56
+ });
57
+ }
58
+ }
59
+ //# sourceMappingURL=ClaudeCliIntelligenceProvider.js.map
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Evolution Manager — the feedback loop that turns running into evolving.
3
+ *
4
+ * Four subsystems, one principle: every interaction is an opportunity
5
+ * to improve. Not during batch reflection hours later, but at the
6
+ * moment the insight is freshest.
7
+ *
8
+ * Subsystems:
9
+ * 1. Evolution Queue — staged self-improvement proposals
10
+ * 2. Learning Registry — structured, searchable insights
11
+ * 3. Capability Gap Tracker — "what am I missing?"
12
+ * 4. Action Queue — commitment tracking with stale detection
13
+ *
14
+ * Born from Portal's engagement pipeline (Steps 8-11) and proven
15
+ * across 100+ evolution proposals and 10 platform engagement skills.
16
+ */
17
+ import type { EvolutionProposal, EvolutionType, EvolutionStatus, LearningEntry, LearningSource, CapabilityGap, GapCategory, ActionItem, EvolutionManagerConfig } from './types.js';
18
+ interface EvolutionState {
19
+ proposals: EvolutionProposal[];
20
+ stats: {
21
+ totalProposals: number;
22
+ byStatus: Record<string, number>;
23
+ byType: Record<string, number>;
24
+ lastUpdated: string;
25
+ };
26
+ }
27
+ interface LearningState {
28
+ learnings: LearningEntry[];
29
+ stats: {
30
+ totalLearnings: number;
31
+ applied: number;
32
+ pending: number;
33
+ byCategory: Record<string, number>;
34
+ lastUpdated: string;
35
+ };
36
+ }
37
+ interface GapState {
38
+ gaps: CapabilityGap[];
39
+ stats: {
40
+ totalGaps: number;
41
+ bySeverity: Record<string, number>;
42
+ byCategory: Record<string, number>;
43
+ addressed: number;
44
+ lastUpdated: string;
45
+ };
46
+ }
47
+ interface ActionState {
48
+ actions: ActionItem[];
49
+ stats: {
50
+ totalActions: number;
51
+ pending: number;
52
+ completed: number;
53
+ overdue: number;
54
+ lastUpdated: string;
55
+ };
56
+ }
57
+ export declare class EvolutionManager {
58
+ private stateDir;
59
+ private config;
60
+ constructor(config: EvolutionManagerConfig);
61
+ private filePath;
62
+ private readFile;
63
+ private writeFile;
64
+ private now;
65
+ private loadEvolution;
66
+ private saveEvolution;
67
+ private nextProposalId;
68
+ addProposal(opts: {
69
+ title: string;
70
+ source: string;
71
+ description: string;
72
+ type: EvolutionType;
73
+ impact?: 'high' | 'medium' | 'low';
74
+ effort?: 'high' | 'medium' | 'low';
75
+ proposedBy?: string;
76
+ tags?: string[];
77
+ }): EvolutionProposal;
78
+ updateProposalStatus(id: string, status: EvolutionStatus, resolution?: string): boolean;
79
+ listProposals(filter?: {
80
+ status?: EvolutionStatus;
81
+ type?: EvolutionType;
82
+ }): EvolutionProposal[];
83
+ getEvolutionStats(): EvolutionState['stats'];
84
+ private loadLearnings;
85
+ private saveLearnings;
86
+ private nextLearningId;
87
+ addLearning(opts: {
88
+ title: string;
89
+ category: string;
90
+ description: string;
91
+ source: LearningSource;
92
+ tags?: string[];
93
+ evolutionRelevance?: string;
94
+ }): LearningEntry;
95
+ markLearningApplied(id: string, appliedTo: string): boolean;
96
+ listLearnings(filter?: {
97
+ category?: string;
98
+ applied?: boolean;
99
+ }): LearningEntry[];
100
+ getLearningStats(): LearningState['stats'];
101
+ private loadGaps;
102
+ private saveGaps;
103
+ private nextGapId;
104
+ addGap(opts: {
105
+ title: string;
106
+ category: GapCategory;
107
+ severity: 'critical' | 'high' | 'medium' | 'low';
108
+ description: string;
109
+ context: string;
110
+ platform?: string;
111
+ session?: string;
112
+ currentState?: string;
113
+ proposedSolution?: string;
114
+ }): CapabilityGap;
115
+ addressGap(id: string, resolution: string): boolean;
116
+ listGaps(filter?: {
117
+ severity?: string;
118
+ category?: GapCategory;
119
+ status?: string;
120
+ }): CapabilityGap[];
121
+ getGapStats(): GapState['stats'];
122
+ private loadActions;
123
+ private saveActions;
124
+ private nextActionId;
125
+ addAction(opts: {
126
+ title: string;
127
+ description: string;
128
+ priority?: 'critical' | 'high' | 'medium' | 'low';
129
+ commitTo?: string;
130
+ dueBy?: string;
131
+ source?: ActionItem['source'];
132
+ tags?: string[];
133
+ }): ActionItem;
134
+ updateAction(id: string, updates: {
135
+ status?: ActionItem['status'];
136
+ resolution?: string;
137
+ }): boolean;
138
+ listActions(filter?: {
139
+ status?: ActionItem['status'];
140
+ priority?: string;
141
+ }): ActionItem[];
142
+ getOverdueActions(): ActionItem[];
143
+ getActionStats(): ActionState['stats'];
144
+ /**
145
+ * Get a full dashboard of evolution health.
146
+ * Useful for session-start orientation and status reporting.
147
+ */
148
+ getDashboard(): {
149
+ evolution: EvolutionState['stats'];
150
+ learnings: LearningState['stats'];
151
+ gaps: GapState['stats'];
152
+ actions: ActionState['stats'];
153
+ highlights: string[];
154
+ };
155
+ }
156
+ export {};
157
+ //# sourceMappingURL=EvolutionManager.d.ts.map