@saccolabs/tars 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +93 -0
  2. package/context/GEMINI.md +13 -0
  3. package/context/config/settings.json-template +36 -0
  4. package/context/skills/create-extension/SKILL.md +90 -0
  5. package/context/skills/create-skill/SKILL.md +33 -0
  6. package/context/skills/manage-extensions/SKILL.md +69 -0
  7. package/context/skills/tars-ops/SKILL.md +89 -0
  8. package/dist/cli/commands/discord.d.ts +4 -0
  9. package/dist/cli/commands/discord.js +48 -0
  10. package/dist/cli/commands/discord.js.map +1 -0
  11. package/dist/cli/commands/export.d.ts +3 -0
  12. package/dist/cli/commands/export.js +39 -0
  13. package/dist/cli/commands/export.js.map +1 -0
  14. package/dist/cli/commands/import.d.ts +1 -0
  15. package/dist/cli/commands/import.js +45 -0
  16. package/dist/cli/commands/import.js.map +1 -0
  17. package/dist/cli/commands/logs.d.ts +4 -0
  18. package/dist/cli/commands/logs.js +23 -0
  19. package/dist/cli/commands/logs.js.map +1 -0
  20. package/dist/cli/commands/memory.d.ts +1 -0
  21. package/dist/cli/commands/memory.js +35 -0
  22. package/dist/cli/commands/memory.js.map +1 -0
  23. package/dist/cli/commands/secret.d.ts +6 -0
  24. package/dist/cli/commands/secret.js +46 -0
  25. package/dist/cli/commands/secret.js.map +1 -0
  26. package/dist/cli/commands/setup.d.ts +4 -0
  27. package/dist/cli/commands/setup.js +329 -0
  28. package/dist/cli/commands/setup.js.map +1 -0
  29. package/dist/cli/commands/start.d.ts +1 -0
  30. package/dist/cli/commands/start.js +42 -0
  31. package/dist/cli/commands/start.js.map +1 -0
  32. package/dist/cli/commands/status.d.ts +1 -0
  33. package/dist/cli/commands/status.js +56 -0
  34. package/dist/cli/commands/status.js.map +1 -0
  35. package/dist/cli/commands/stop.d.ts +1 -0
  36. package/dist/cli/commands/stop.js +38 -0
  37. package/dist/cli/commands/stop.js.map +1 -0
  38. package/dist/cli/commands/uninstall.d.ts +1 -0
  39. package/dist/cli/commands/uninstall.js +91 -0
  40. package/dist/cli/commands/uninstall.js.map +1 -0
  41. package/dist/cli/index.d.ts +2 -0
  42. package/dist/cli/index.js +54 -0
  43. package/dist/cli/index.js.map +1 -0
  44. package/dist/config/config.d.ts +14 -0
  45. package/dist/config/config.js +69 -0
  46. package/dist/config/config.js.map +1 -0
  47. package/dist/discord/discord-bot.d.ts +32 -0
  48. package/dist/discord/discord-bot.js +151 -0
  49. package/dist/discord/discord-bot.js.map +1 -0
  50. package/dist/discord/message-formatter.d.ts +95 -0
  51. package/dist/discord/message-formatter.js +448 -0
  52. package/dist/discord/message-formatter.js.map +1 -0
  53. package/dist/memory/knowledge-store.d.ts +24 -0
  54. package/dist/memory/knowledge-store.js +126 -0
  55. package/dist/memory/knowledge-store.js.map +1 -0
  56. package/dist/memory/memory-manager.d.ts +24 -0
  57. package/dist/memory/memory-manager.js +101 -0
  58. package/dist/memory/memory-manager.js.map +1 -0
  59. package/dist/scripts/debug-cli.d.ts +1 -0
  60. package/dist/scripts/debug-cli.js +52 -0
  61. package/dist/scripts/debug-cli.js.map +1 -0
  62. package/dist/supervisor/gemini-cli.d.ts +28 -0
  63. package/dist/supervisor/gemini-cli.js +315 -0
  64. package/dist/supervisor/gemini-cli.js.map +1 -0
  65. package/dist/supervisor/heartbeat-service.d.ts +21 -0
  66. package/dist/supervisor/heartbeat-service.js +143 -0
  67. package/dist/supervisor/heartbeat-service.js.map +1 -0
  68. package/dist/supervisor/main.d.ts +1 -0
  69. package/dist/supervisor/main.js +242 -0
  70. package/dist/supervisor/main.js.map +1 -0
  71. package/dist/supervisor/session-manager.d.ts +47 -0
  72. package/dist/supervisor/session-manager.js +118 -0
  73. package/dist/supervisor/session-manager.js.map +1 -0
  74. package/dist/supervisor/supervisor.d.ts +32 -0
  75. package/dist/supervisor/supervisor.js +98 -0
  76. package/dist/supervisor/supervisor.js.map +1 -0
  77. package/dist/types/index.d.ts +42 -0
  78. package/dist/types/index.js +5 -0
  79. package/dist/types/index.js.map +1 -0
  80. package/dist/utils/attachment-processor.d.ts +22 -0
  81. package/dist/utils/attachment-processor.js +79 -0
  82. package/dist/utils/attachment-processor.js.map +1 -0
  83. package/dist/utils/logger.d.ts +6 -0
  84. package/dist/utils/logger.js +15 -0
  85. package/dist/utils/logger.js.map +1 -0
  86. package/dist/utils/secrets-manager.d.ts +27 -0
  87. package/dist/utils/secrets-manager.js +79 -0
  88. package/dist/utils/secrets-manager.js.map +1 -0
  89. package/dist/utils/version.d.ts +3 -0
  90. package/dist/utils/version.js +23 -0
  91. package/dist/utils/version.js.map +1 -0
  92. package/extensions/tasks/gemini-extension.json +14 -0
  93. package/extensions/tasks/package-lock.json +1209 -0
  94. package/extensions/tasks/package.json +19 -0
  95. package/extensions/tasks/src/server.ts +265 -0
  96. package/extensions/tasks/src/store.ts +92 -0
  97. package/extensions/tasks/tsconfig.json +14 -0
  98. package/package.json +55 -0
  99. package/src/prompts/system.md +25 -0
@@ -0,0 +1,143 @@
1
+ import fs from 'fs/promises';
2
+ import logger from '../utils/logger.js';
3
+ import { CronExpressionParser } from 'cron-parser';
4
+ import { AttachmentProcessor } from '../utils/attachment-processor.js';
5
+ /**
6
+ * HeartbeatService - Manages background task execution via file polling
7
+ */
8
+ export class HeartbeatService {
9
+ supervisor;
10
+ config;
11
+ interval = null;
12
+ isExecuting = false;
13
+ processor;
14
+ constructor(supervisor, config) {
15
+ this.supervisor = supervisor;
16
+ this.config = config;
17
+ this.processor = new AttachmentProcessor(config);
18
+ }
19
+ async start() {
20
+ const intervalMs = this.config.heartbeatIntervalMs;
21
+ logger.info(`💓 Heartbeat service started (Interval: ${intervalMs / 1000}s)`);
22
+ // Initial run
23
+ this.tick();
24
+ this.interval = setInterval(() => this.tick(), intervalMs);
25
+ }
26
+ stop() {
27
+ if (this.interval) {
28
+ clearInterval(this.interval);
29
+ this.interval = null;
30
+ }
31
+ logger.info('💓 Heartbeat service stopped');
32
+ }
33
+ async tick() {
34
+ if (this.isExecuting)
35
+ return;
36
+ this.isExecuting = true;
37
+ try {
38
+ // 1. Maintenance & Sync
39
+ this.processor.cleanup();
40
+ await this.supervisor.memory.fullSync();
41
+ // 2. Load Tasks
42
+ const tasks = await this.loadTasks();
43
+ const now = new Date();
44
+ const dueTasks = tasks.filter((t) => t.enabled && new Date(t.nextRun) <= now);
45
+ // 3. Autonomous Check (The OpenClaw style)
46
+ // If no hard-scheduled tasks, we do a semantic "health check"
47
+ if (dueTasks.length === 0) {
48
+ await this.autonomousCheck();
49
+ }
50
+ else {
51
+ logger.info(`💓 Found ${dueTasks.length} due tasks`);
52
+ for (const task of dueTasks) {
53
+ await this.runTask(task);
54
+ }
55
+ await this.saveTasks(tasks);
56
+ }
57
+ }
58
+ catch (error) {
59
+ logger.error(`❌ Heartbeat tick error: ${error.message}`);
60
+ }
61
+ finally {
62
+ this.isExecuting = false;
63
+ }
64
+ }
65
+ async autonomousCheck() {
66
+ // This is a "quiet" heartbeat. We ask the AI if anything needs attention
67
+ // based on the context it has in memory.
68
+ const prompt = `Self-Correction and Autonomous Heartbeat:\nReview your current objectives in GEMINI.md and any pending tasks.\nIf everything is on track and no immediate action is required, reply exactly with 'SILENT_ACK'.\nIf you detect an issue, a missed deadline, or a high-priority task that needs starting, provide a short internal reasoning and then describe the action you are taking.`;
69
+ try {
70
+ const response = await this.supervisor.executeTask(prompt);
71
+ if (response.includes('SILENT_ACK')) {
72
+ // Heartbeat OK, prune to prevent context bloat
73
+ await this.supervisor.pruneLastTurn();
74
+ return;
75
+ }
76
+ // If the AI didn't say SILENT_ACK, it wants to do something!
77
+ logger.info(`🤖 Tars Heartbeat initiated action: ${response.substring(0, 100)}...`);
78
+ // Here we could route this to Discord or a Log.
79
+ }
80
+ catch (error) {
81
+ logger.error(`❌ Autonomous check failed: ${error.message}`);
82
+ }
83
+ }
84
+ async runTask(task) {
85
+ logger.info(`🚀 Running task: ${task.title} (${task.id})`);
86
+ try {
87
+ const result = await this.supervisor.executeTask(task.prompt);
88
+ logger.info(`✅ Task ${task.id} completed. Result length: ${result.length}`);
89
+ task.lastRun = new Date().toISOString();
90
+ task.failedCount = 0;
91
+ }
92
+ catch (error) {
93
+ logger.error(`❌ Task ${task.id} failed: ${error.message}`);
94
+ task.failedCount++;
95
+ }
96
+ finally {
97
+ // Calculate next run
98
+ task.nextRun = this.calculateNextRun(task.schedule);
99
+ task.updatedAt = new Date().toISOString();
100
+ }
101
+ }
102
+ calculateNextRun(schedule) {
103
+ try {
104
+ // 1. Try parsing as a cron expression (using the new 5.x API)
105
+ const interval = CronExpressionParser.parse(schedule);
106
+ const next = interval.next();
107
+ const iso = next.toISOString();
108
+ if (!iso) {
109
+ throw new Error('Could not calculate next run from cron.');
110
+ }
111
+ return iso;
112
+ }
113
+ catch (err) {
114
+ // 2. If not cron, try parsing as a specific ISO date
115
+ const date = new Date(schedule);
116
+ if (!isNaN(date.getTime()) && schedule.includes('-')) {
117
+ // We check for '-' to ensure it's likely a date string and not a weird numeric cron fallback
118
+ return date.toISOString();
119
+ }
120
+ // 3. Absolute Fallback: Run in 24 hours if the schedule is totally unparseable
121
+ // This prevents the task from "looping" or getting stuck in the past
122
+ logger.warn(`⚠️ Unrecognized schedule format: "${schedule}". Falling back to 24h.`);
123
+ return new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
124
+ }
125
+ }
126
+ async loadTasks() {
127
+ try {
128
+ const data = await fs.readFile(this.config.taskFilePath, 'utf-8');
129
+ return JSON.parse(data);
130
+ }
131
+ catch (error) {
132
+ if (error.code === 'ENOENT') {
133
+ return [];
134
+ }
135
+ throw error;
136
+ }
137
+ }
138
+ async saveTasks(tasks) {
139
+ const data = JSON.stringify(tasks, null, 2);
140
+ await fs.writeFile(this.config.taskFilePath, data, 'utf-8');
141
+ }
142
+ }
143
+ //# sourceMappingURL=heartbeat-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-service.js","sourceRoot":"","sources":["../../src/supervisor/heartbeat-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,242 @@
1
+ import { Config } from '../config/config.js';
2
+ import { GeminiCli } from './gemini-cli.js';
3
+ import { SessionManager } from './session-manager.js';
4
+ import { Supervisor } from './supervisor.js';
5
+ import { HeartbeatService } from './heartbeat-service.js';
6
+ import { DiscordBot } from '../discord/discord-bot.js';
7
+ import logger from '../utils/logger.js';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+ /**
14
+ * Install the fixed system prompt into the Tars home directory.
15
+ * This ensures Gemini CLI uses Tars' custom persona instead of the default coding-centric prompt.
16
+ */
17
+ function installSystemPrompt(config) {
18
+ // Walk up from dist/supervisor/ or src/supervisor/ to find prompts/system.md
19
+ let searchDir = __dirname;
20
+ let srcPrompt = '';
21
+ // Try to find the prompt relative to the package root
22
+ for (let i = 0; i < 5; i++) {
23
+ const candidate = path.join(searchDir, 'prompts', 'system.md');
24
+ const srcCandidate = path.join(searchDir, 'src', 'prompts', 'system.md');
25
+ if (fs.existsSync(candidate)) {
26
+ srcPrompt = candidate;
27
+ break;
28
+ }
29
+ else if (fs.existsSync(srcCandidate)) {
30
+ srcPrompt = srcCandidate;
31
+ break;
32
+ }
33
+ searchDir = path.dirname(searchDir);
34
+ }
35
+ if (!srcPrompt) {
36
+ logger.warn('⚠️ Could not locate system.md prompt file');
37
+ return;
38
+ }
39
+ // Ensure target directory exists
40
+ const targetDir = path.dirname(config.systemPromptPath);
41
+ fs.mkdirSync(targetDir, { recursive: true });
42
+ // Always overwrite to ensure latest prompt is deployed
43
+ fs.copyFileSync(srcPrompt, config.systemPromptPath);
44
+ logger.info(`📝 System prompt installed: ${config.systemPromptPath}`);
45
+ }
46
+ /**
47
+ * Install built-in skills into the Tars runtime directory.
48
+ */
49
+ /**
50
+ * Install and sync built-in skills into the Tars runtime directory.
51
+ * Safely updates built-in skills while preserving user-created ones.
52
+ */
53
+ function installSkills(config) {
54
+ // 1. Locate context/skills/ in the repo
55
+ let searchDir = __dirname;
56
+ let skillsSrc = '';
57
+ for (let i = 0; i < 5; i++) {
58
+ const candidate = path.join(searchDir, 'context', 'skills');
59
+ const srcCandidate = path.join(searchDir, '..', 'context', 'skills'); // If in dist/supervisor/
60
+ if (fs.existsSync(candidate)) {
61
+ skillsSrc = candidate;
62
+ break;
63
+ }
64
+ else if (fs.existsSync(srcCandidate)) {
65
+ skillsSrc = srcCandidate;
66
+ break;
67
+ }
68
+ // Try finding context in root if running from src
69
+ const rootCandidate = path.join(searchDir, '..', '..', 'context', 'skills');
70
+ if (fs.existsSync(rootCandidate)) {
71
+ skillsSrc = rootCandidate;
72
+ break;
73
+ }
74
+ searchDir = path.dirname(searchDir);
75
+ }
76
+ if (!skillsSrc) {
77
+ logger.warn('⚠️ Could not locate built-in skills directory');
78
+ return;
79
+ }
80
+ // 2. Define target directory (~/.tars/.gemini/skills)
81
+ const skillsDest = path.join(config.homeDir, '.gemini', 'skills');
82
+ try {
83
+ if (!fs.existsSync(skillsDest)) {
84
+ fs.mkdirSync(skillsDest, { recursive: true });
85
+ }
86
+ // 3. Selective Sync: Copy each built-in skill individually
87
+ const builtInSkills = fs.readdirSync(skillsSrc);
88
+ for (const skillName of builtInSkills) {
89
+ const srcSkillPath = path.join(skillsSrc, skillName);
90
+ const destSkillPath = path.join(skillsDest, skillName);
91
+ // Only copy directories
92
+ if (!fs.statSync(srcSkillPath).isDirectory())
93
+ continue;
94
+ // Remove existing destination (to ensure clean update - e.g. deleting old files)
95
+ // This assumes built-in skills are managed entirely by the repo
96
+ if (fs.existsSync(destSkillPath)) {
97
+ fs.rmSync(destSkillPath, { recursive: true, force: true });
98
+ }
99
+ // Copy fresh from repo
100
+ fs.cpSync(srcSkillPath, destSkillPath, { recursive: true });
101
+ logger.info(`📚 Skill synced: ${skillName}`);
102
+ }
103
+ }
104
+ catch (error) {
105
+ logger.error(`❌ Failed to sync skills: ${error}`);
106
+ }
107
+ }
108
+ /**
109
+ * Automatically install/link extensions and enable them.
110
+ * Verifies symlinks are valid and re-links if broken.
111
+ */
112
+ function installExtensions(config) {
113
+ const repoExtensionsDir = path.join(__dirname, '..', '..', 'extensions');
114
+ const targetExtensionsDir = path.join(config.homeDir, '.gemini', 'extensions');
115
+ const enablementFile = path.join(targetExtensionsDir, 'extension-enablement.json');
116
+ if (!fs.existsSync(repoExtensionsDir)) {
117
+ logger.warn('⚠️ Could not locate extensions directory');
118
+ return;
119
+ }
120
+ if (!fs.existsSync(targetExtensionsDir)) {
121
+ fs.mkdirSync(targetExtensionsDir, { recursive: true });
122
+ }
123
+ // Load Enablement
124
+ let enablement = {};
125
+ if (fs.existsSync(enablementFile)) {
126
+ try {
127
+ enablement = JSON.parse(fs.readFileSync(enablementFile, 'utf-8'));
128
+ }
129
+ catch (e) {
130
+ logger.warn('⚠️ Could not parse extension-enablement.json, starting fresh');
131
+ }
132
+ }
133
+ const builtInExtensions = fs.readdirSync(repoExtensionsDir);
134
+ for (const extName of builtInExtensions) {
135
+ const srcPath = path.resolve(repoExtensionsDir, extName);
136
+ if (!fs.statSync(srcPath).isDirectory())
137
+ continue;
138
+ const finalExtName = extName === 'tasks' ? 'tars-tasks' : extName;
139
+ const finalDestPath = path.join(targetExtensionsDir, finalExtName);
140
+ // Check if symlink exists and is valid
141
+ let needsLink = true;
142
+ try {
143
+ if (fs.existsSync(finalDestPath)) {
144
+ const stats = fs.lstatSync(finalDestPath);
145
+ if (stats.isSymbolicLink()) {
146
+ const realPath = fs.realpathSync(finalDestPath);
147
+ if (realPath === srcPath) {
148
+ needsLink = false; // Already linked correctly
149
+ }
150
+ }
151
+ }
152
+ }
153
+ catch (e) {
154
+ // Broken link or other error, proceed to re-link
155
+ }
156
+ if (needsLink) {
157
+ try {
158
+ // Remove existing file/link if present to prevent EEXIST
159
+ if (fs.existsSync(finalDestPath) || fs.lstatSync(finalDestPath).isSymbolicLink()) {
160
+ fs.rmSync(finalDestPath, { recursive: true, force: true });
161
+ }
162
+ fs.symlinkSync(srcPath, finalDestPath, 'dir');
163
+ logger.info(`🔌 Linked extension: ${finalExtName} -> ${srcPath}`);
164
+ }
165
+ catch (error) {
166
+ logger.error(`❌ Failed to link extension ${finalExtName}: ${error}`);
167
+ }
168
+ }
169
+ // Ensure enabled
170
+ if (!enablement[finalExtName]) {
171
+ enablement[finalExtName] = {
172
+ overrides: [path.join(config.homeDir, '*')]
173
+ };
174
+ }
175
+ }
176
+ fs.writeFileSync(enablementFile, JSON.stringify(enablement, null, 2));
177
+ }
178
+ /**
179
+ * Install default settings if none exist.
180
+ */
181
+ function installDefaultSettings(config) {
182
+ const settingsTemplate = path.join(__dirname, '..', '..', 'context', 'config', 'settings.json-template');
183
+ const targetSettings = path.join(config.homeDir, '.gemini', 'settings.json');
184
+ if (fs.existsSync(targetSettings))
185
+ return;
186
+ if (fs.existsSync(settingsTemplate)) {
187
+ fs.mkdirSync(path.dirname(targetSettings), { recursive: true });
188
+ fs.copyFileSync(settingsTemplate, targetSettings);
189
+ logger.info(`⚙️ Default settings installed: ${targetSettings}`);
190
+ }
191
+ else {
192
+ logger.warn('⚠️ Could not locate settings.json-template');
193
+ }
194
+ }
195
+ /**
196
+ * Tars Main Entry Point
197
+ */
198
+ async function main() {
199
+ try {
200
+ logger.info('🚀 Tars Starting...');
201
+ // 1. Load Configuration
202
+ const config = Config.getInstance();
203
+ // 2. Install system prompt, skills, extensions and settings
204
+ installSystemPrompt(config);
205
+ installSkills(config);
206
+ installExtensions(config);
207
+ installDefaultSettings(config);
208
+ // 3. Initialize Core Services
209
+ const gemini = new GeminiCli(config);
210
+ const sessionManager = new SessionManager(config.sessionFilePath);
211
+ const supervisor = new Supervisor(gemini, sessionManager);
212
+ // 4. Initialize Heartbeat (Background Tasks)
213
+ const heartbeat = new HeartbeatService(supervisor, config);
214
+ // 5. Initialize Interface (Discord)
215
+ const discordBot = new DiscordBot(supervisor, config);
216
+ // Start Services
217
+ await discordBot.start();
218
+ await heartbeat.start();
219
+ logger.info('✨ Tars successfully initialized and running.');
220
+ // Graceful shutdown
221
+ process.on('SIGINT', async () => {
222
+ logger.info('🛑 Shutting down...');
223
+ heartbeat.stop();
224
+ process.exit(0);
225
+ });
226
+ }
227
+ catch (error) {
228
+ logger.error(`💥 Fatal error during startup: ${error.message}`);
229
+ process.exit(1);
230
+ }
231
+ }
232
+ // 6. Run Main
233
+ // Strict Safety Check: The supervisor must be explicitly activated via environment variable.
234
+ // This prevents accidental execution via "node dist/supervisor/main.js" which can spawn zombie processes.
235
+ if (process.env.TARS_SUPERVISOR_MODE !== 'true') {
236
+ logger.error('❌ TARS_SUPERVISOR_MODE=true is required to start the supervisor.');
237
+ logger.error(' This safety check prevents accidental multiple instances.');
238
+ logger.error('👉 Use "tars start" or "npm run dev" instead.');
239
+ process.exit(1);
240
+ }
241
+ main();
242
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/supervisor/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { UsageStats } from '../types/index.js';
2
+ /**
3
+ * Session data stored to disk
4
+ */
5
+ export interface SessionData {
6
+ sessionId: string;
7
+ createdAt: string;
8
+ totalInputTokens: number;
9
+ totalOutputTokens: number;
10
+ totalCachedTokens: number;
11
+ interactionCount: number;
12
+ lastInteractionAt: string;
13
+ lastInputTokens: number;
14
+ totalNetTokens: number;
15
+ }
16
+ /**
17
+ * Manages Gemini CLI session persistence with token tracking
18
+ */
19
+ export declare class SessionManager {
20
+ private readonly sessionFilePath;
21
+ private sessionData;
22
+ constructor(sessionFilePath: string);
23
+ /**
24
+ * Load session data from storage
25
+ */
26
+ load(): string | null;
27
+ /**
28
+ * Save or initialize session
29
+ */
30
+ save(sessionId: string): void;
31
+ /**
32
+ * Update session with usage stats from latest interaction
33
+ */
34
+ updateUsage(usage: UsageStats): void;
35
+ /**
36
+ * Get current session statistics
37
+ */
38
+ getStats(): SessionData | null;
39
+ /**
40
+ * Clear the stored session
41
+ */
42
+ clear(): void;
43
+ /**
44
+ * Check if a session exists
45
+ */
46
+ exists(): boolean;
47
+ }
@@ -0,0 +1,118 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import logger from '../utils/logger.js';
4
+ /**
5
+ * Manages Gemini CLI session persistence with token tracking
6
+ */
7
+ export class SessionManager {
8
+ sessionFilePath;
9
+ sessionData = null;
10
+ constructor(sessionFilePath) {
11
+ this.sessionFilePath = sessionFilePath;
12
+ }
13
+ /**
14
+ * Load session data from storage
15
+ */
16
+ load() {
17
+ if (!fs.existsSync(this.sessionFilePath)) {
18
+ return null;
19
+ }
20
+ try {
21
+ const raw = fs.readFileSync(this.sessionFilePath, 'utf-8');
22
+ const parsed = JSON.parse(raw);
23
+ // Check if sessionId exists
24
+ if (!parsed.sessionId) {
25
+ return null;
26
+ }
27
+ this.sessionData = parsed;
28
+ if (this.sessionData.totalNetTokens === undefined) {
29
+ this.sessionData.totalNetTokens = this.sessionData.totalInputTokens || 0;
30
+ }
31
+ return this.sessionData.sessionId;
32
+ }
33
+ catch (e) {
34
+ logger.warn(`[SessionManager] Failed to load session: ${e}`);
35
+ return null;
36
+ }
37
+ }
38
+ /**
39
+ * Save or initialize session
40
+ */
41
+ save(sessionId) {
42
+ try {
43
+ // Initialize new session data if not exists
44
+ if (!this.sessionData || this.sessionData.sessionId !== sessionId) {
45
+ this.sessionData = {
46
+ sessionId,
47
+ createdAt: new Date().toISOString(),
48
+ totalInputTokens: 0,
49
+ totalOutputTokens: 0,
50
+ totalCachedTokens: 0,
51
+ interactionCount: 0,
52
+ lastInteractionAt: new Date().toISOString(),
53
+ lastInputTokens: 0,
54
+ totalNetTokens: 0
55
+ };
56
+ }
57
+ const dir = path.dirname(this.sessionFilePath);
58
+ fs.mkdirSync(dir, { recursive: true });
59
+ fs.writeFileSync(this.sessionFilePath, JSON.stringify(this.sessionData, null, 2));
60
+ logger.info(`[SessionManager] Session saved: ${sessionId}`);
61
+ }
62
+ catch (e) {
63
+ logger.error(`[SessionManager] Failed to save session: ${e}`);
64
+ }
65
+ }
66
+ /**
67
+ * Update session with usage stats from latest interaction
68
+ */
69
+ updateUsage(usage) {
70
+ if (!this.sessionData) {
71
+ logger.warn('[SessionManager] Cannot update usage - no active session');
72
+ return;
73
+ }
74
+ const netInput = Math.max(0, usage.inputTokens - (usage.cachedTokens || 0));
75
+ this.sessionData.totalNetTokens += netInput;
76
+ this.sessionData.totalInputTokens = usage.inputTokens; // Current context size
77
+ this.sessionData.totalOutputTokens += usage.outputTokens;
78
+ this.sessionData.totalCachedTokens = usage.cachedTokens || 0; // Current cached state
79
+ this.sessionData.interactionCount++;
80
+ this.sessionData.lastInteractionAt = new Date().toISOString();
81
+ this.sessionData.lastInputTokens = usage.inputTokens;
82
+ // Persist to disk
83
+ try {
84
+ fs.writeFileSync(this.sessionFilePath, JSON.stringify(this.sessionData, null, 2));
85
+ }
86
+ catch (e) {
87
+ logger.error(`[SessionManager] Failed to update usage: ${e}`);
88
+ }
89
+ }
90
+ /**
91
+ * Get current session statistics
92
+ */
93
+ getStats() {
94
+ return this.sessionData ? { ...this.sessionData } : null;
95
+ }
96
+ /**
97
+ * Clear the stored session
98
+ */
99
+ clear() {
100
+ if (fs.existsSync(this.sessionFilePath)) {
101
+ try {
102
+ fs.unlinkSync(this.sessionFilePath);
103
+ this.sessionData = null;
104
+ logger.info('[SessionManager] Session cleared');
105
+ }
106
+ catch (e) {
107
+ logger.error(`[SessionManager] Failed to clear session: ${e}`);
108
+ }
109
+ }
110
+ }
111
+ /**
112
+ * Check if a session exists
113
+ */
114
+ exists() {
115
+ return fs.existsSync(this.sessionFilePath);
116
+ }
117
+ }
118
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/supervisor/session-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { GeminiCli } from './gemini-cli.js';
2
+ import { SessionManager } from './session-manager.js';
3
+ import { GeminiOutputHandler } from '../types/index.js';
4
+ import { MemoryManager } from '../memory/memory-manager.js';
5
+ /**
6
+ * Tars Supervisor - Core Orchestrator
7
+ * Simplified to handle session management and Gemini CLI execution.
8
+ */
9
+ export declare class Supervisor {
10
+ private readonly gemini;
11
+ private readonly sessionManager;
12
+ private readonly config;
13
+ readonly memory: MemoryManager;
14
+ private isProcessing;
15
+ constructor(gemini: GeminiCli, sessionManager: SessionManager);
16
+ /**
17
+ * Executes a user prompt through the Gemini CLI
18
+ */
19
+ run(content: string, onEvent: GeminiOutputHandler, sessionId?: string): Promise<void>;
20
+ /**
21
+ * Specialized execution for background tasks
22
+ */
23
+ executeTask(prompt: string): Promise<string>;
24
+ /**
25
+ * Prunes the last turn from the current session.
26
+ */
27
+ pruneLastTurn(): Promise<void>;
28
+ /**
29
+ * Checks if the supervisor is currently processing a request
30
+ */
31
+ isBusy(): boolean;
32
+ }