@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,19 @@
1
+ {
2
+ "name": "tars-tasks",
3
+ "version": "1.0.0",
4
+ "description": "Task management MCP server for Tars",
5
+ "type": "module",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "start": "node dist/server.js"
9
+ },
10
+ "dependencies": {
11
+ "@modelcontextprotocol/sdk": "^1.0.1",
12
+ "cron-parser": "^5.4.0",
13
+ "uuid": "^13.0.0"
14
+ },
15
+ "devDependencies": {
16
+ "@types/node": "^22.10.2",
17
+ "typescript": "^5.7.2"
18
+ }
19
+ }
@@ -0,0 +1,265 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
+ import { TaskStore, Task } from './store.js';
5
+ import { v4 as uuidv4 } from 'uuid';
6
+ import { CronExpressionParser } from 'cron-parser';
7
+
8
+ const store = new TaskStore();
9
+ const server = new Server(
10
+ {
11
+ name: 'tars-tasks',
12
+ version: '1.0.0'
13
+ },
14
+ {
15
+ capabilities: {
16
+ tools: {}
17
+ }
18
+ }
19
+ );
20
+
21
+ /**
22
+ * Tool Definitions
23
+ */
24
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
25
+ return {
26
+ tools: [
27
+ {
28
+ name: 'create_task',
29
+ description: 'Create a new scheduled task',
30
+ inputSchema: {
31
+ type: 'object',
32
+ properties: {
33
+ title: { type: 'string', description: 'Task title' },
34
+ prompt: {
35
+ type: 'string',
36
+ description: 'The prompt for Gemini CLI to execute'
37
+ },
38
+ schedule: { type: 'string', description: 'Cron expression or ISO date' },
39
+ mode: { type: 'string', enum: ['notify', 'silent'], default: 'silent' }
40
+ },
41
+ required: ['title', 'prompt', 'schedule']
42
+ }
43
+ },
44
+ {
45
+ name: 'list_tasks',
46
+ description: 'List all scheduled tasks',
47
+ inputSchema: {
48
+ type: 'object',
49
+ properties: {
50
+ enabledOnly: { type: 'boolean', default: false }
51
+ }
52
+ }
53
+ },
54
+ {
55
+ name: 'delete_task',
56
+ description: 'Delete a task by ID',
57
+ inputSchema: {
58
+ type: 'object',
59
+ properties: {
60
+ id: { type: 'string' }
61
+ },
62
+ required: ['id']
63
+ }
64
+ },
65
+ {
66
+ name: 'toggle_task',
67
+ description: 'Enable or disable a task',
68
+ inputSchema: {
69
+ type: 'object',
70
+ properties: {
71
+ id: { type: 'string', description: 'Task ID' },
72
+ enabled: {
73
+ type: 'boolean',
74
+ description: 'Whether the task should be enabled'
75
+ }
76
+ },
77
+ required: ['id', 'enabled']
78
+ }
79
+ },
80
+ {
81
+ name: 'modify_task',
82
+ description: 'Modify an existing task',
83
+ inputSchema: {
84
+ type: 'object',
85
+ properties: {
86
+ id: { type: 'string', description: 'Task ID' },
87
+ title: { type: 'string', description: 'New title' },
88
+ prompt: { type: 'string', description: 'New prompt' },
89
+ schedule: { type: 'string', description: 'New cron or ISO date' }
90
+ },
91
+ required: ['id']
92
+ }
93
+ }
94
+ ]
95
+ };
96
+ });
97
+
98
+ /**
99
+ * Tool Handlers
100
+ */
101
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
102
+ const { name, arguments: args } = request.params;
103
+
104
+ try {
105
+ switch (name) {
106
+ case 'create_task': {
107
+ const { title, prompt, schedule, mode = 'silent' } = args as any;
108
+
109
+ // Calculate next run
110
+ let nextRun: string;
111
+ try {
112
+ const next = CronExpressionParser.parse(schedule).next();
113
+ const iso = next.toISOString();
114
+ if (!iso) {
115
+ throw new Error('Could not calculate next run time from cron expression.');
116
+ }
117
+ nextRun = iso;
118
+ } catch (error: any) {
119
+ // If it's not a valid cron, try parsing as ISO date
120
+ const date = new Date(schedule);
121
+ if (!isNaN(date.getTime()) && schedule.includes('-')) {
122
+ nextRun = date.toISOString();
123
+ } else {
124
+ throw new Error(
125
+ `Invalid schedule: "${schedule}". Must be a valid cron expression or ISO date string (e.g., "YYYY-MM-DDTHH:mm:ssZ").`
126
+ );
127
+ }
128
+ }
129
+
130
+ const task: Task = {
131
+ id: uuidv4(),
132
+ title,
133
+ prompt,
134
+ schedule,
135
+ nextRun,
136
+ enabled: true,
137
+ mode,
138
+ source: 'user',
139
+ failedCount: 0,
140
+ createdAt: new Date().toISOString(),
141
+ updatedAt: new Date().toISOString()
142
+ };
143
+
144
+ await store.addTask(task);
145
+ return {
146
+ content: [
147
+ {
148
+ type: 'text',
149
+ text: `✅ Task created: ${task.title} (ID: ${task.id})\nNext run: ${task.nextRun}`
150
+ }
151
+ ]
152
+ };
153
+ }
154
+
155
+ case 'list_tasks': {
156
+ const { enabledOnly } = args as any;
157
+ const tasks = await store.loadTasks();
158
+ const filtered = enabledOnly ? tasks.filter((t) => t.enabled) : tasks;
159
+
160
+ if (filtered.length === 0) {
161
+ return { content: [{ type: 'text', text: 'No tasks found.' }] };
162
+ }
163
+
164
+ const text = filtered
165
+ .map((t) => {
166
+ const status = t.enabled ? 'ON' : 'OFF';
167
+ let info = `- [${status}] **${t.title}** (\`${t.id}\`)\n Schedule: \`${t.schedule}\`\n Next run: ${t.nextRun}`;
168
+ if (t.failedCount > 0) {
169
+ info += `\n ⚠️ Failures: ${t.failedCount}`;
170
+ }
171
+ if (t.lastRun) {
172
+ info += `\n Last run: ${t.lastRun}`;
173
+ }
174
+ return info;
175
+ })
176
+ .join('\n\n');
177
+
178
+ return { content: [{ type: 'text', text }] };
179
+ }
180
+
181
+ case 'delete_task': {
182
+ const { id } = args as any;
183
+ const success = await store.deleteTask(id);
184
+ return {
185
+ content: [
186
+ {
187
+ type: 'text',
188
+ text: success ? `✅ Task ${id} deleted.` : `❌ Task ${id} not found.`
189
+ }
190
+ ]
191
+ };
192
+ }
193
+
194
+ case 'toggle_task': {
195
+ const { id, enabled } = args as any;
196
+ const task = await store.updateTask(id, { enabled });
197
+ return {
198
+ content: [
199
+ {
200
+ type: 'text',
201
+ text: task
202
+ ? `✅ Task "${task.title}" is now ${enabled ? 'enabled' : 'disabled'}.`
203
+ : `❌ Task ${id} not found.`
204
+ }
205
+ ]
206
+ };
207
+ }
208
+
209
+ case 'modify_task': {
210
+ const { id, title, prompt, schedule } = args as any;
211
+ const updates: any = {};
212
+ if (title) updates.title = title;
213
+ if (prompt) updates.prompt = prompt;
214
+ if (schedule) {
215
+ updates.schedule = schedule;
216
+ try {
217
+ const next = CronExpressionParser.parse(schedule).next();
218
+ updates.nextRun = next.toISOString();
219
+ } catch {
220
+ const date = new Date(schedule);
221
+ if (!isNaN(date.getTime()) && schedule.includes('-')) {
222
+ updates.nextRun = date.toISOString();
223
+ } else {
224
+ throw new Error(`Invalid schedule: ${schedule}`);
225
+ }
226
+ }
227
+ }
228
+
229
+ const task = await store.updateTask(id, updates);
230
+ return {
231
+ content: [
232
+ {
233
+ type: 'text',
234
+ text: task
235
+ ? `✅ Task "${task.title}" updated.`
236
+ : `❌ Task ${id} not found.`
237
+ }
238
+ ]
239
+ };
240
+ }
241
+
242
+ default:
243
+ throw new Error(`Unknown tool: ${name}`);
244
+ }
245
+ } catch (error: any) {
246
+ return {
247
+ content: [{ type: 'text', text: `❌ Error: ${error.message}` }],
248
+ isError: true
249
+ };
250
+ }
251
+ });
252
+
253
+ /**
254
+ * Start Server
255
+ */
256
+ async function main() {
257
+ const transport = new StdioServerTransport();
258
+ await server.connect(transport);
259
+ console.error('Tars Tasks MCP Server running on stdio');
260
+ }
261
+
262
+ main().catch((error) => {
263
+ console.error('Server error:', error);
264
+ process.exit(1);
265
+ });
@@ -0,0 +1,92 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import os from 'os';
4
+
5
+ export interface Task {
6
+ id: string;
7
+ title: string;
8
+ prompt: string;
9
+ schedule: string;
10
+ nextRun: string;
11
+ lastRun?: string;
12
+ enabled: boolean;
13
+ mode: 'notify' | 'silent';
14
+ source: 'user' | 'system';
15
+ failedCount: number;
16
+ createdAt: string;
17
+ updatedAt: string;
18
+ }
19
+
20
+ export class TaskStore {
21
+ private readonly filePath: string;
22
+ private lock: Promise<void> = Promise.resolve();
23
+
24
+ constructor() {
25
+ const tarsHome = process.env.TARS_HOME || path.join(os.homedir(), '.tars');
26
+ this.filePath = path.join(tarsHome, 'data', 'tasks.json');
27
+ }
28
+
29
+ private async withLock<T>(fn: () => Promise<T>): Promise<T> {
30
+ const result = this.lock.then(fn);
31
+ this.lock = result.then(
32
+ () => {},
33
+ () => {}
34
+ );
35
+ return result;
36
+ }
37
+
38
+ private async _load(): Promise<Task[]> {
39
+ try {
40
+ const data = await fs.readFile(this.filePath, 'utf-8');
41
+ return JSON.parse(data);
42
+ } catch (error: any) {
43
+ if (error.code === 'ENOENT') {
44
+ return [];
45
+ }
46
+ throw error;
47
+ }
48
+ }
49
+
50
+ private async _save(tasks: Task[]): Promise<void> {
51
+ await fs.mkdir(path.dirname(this.filePath), { recursive: true });
52
+ const data = JSON.stringify(tasks, null, 2);
53
+ await fs.writeFile(this.filePath, data, 'utf-8');
54
+ }
55
+
56
+ public async loadTasks(): Promise<Task[]> {
57
+ return this.withLock(() => this._load());
58
+ }
59
+
60
+ public async addTask(task: Task): Promise<void> {
61
+ return this.withLock(async () => {
62
+ const tasks = await this._load();
63
+ tasks.push(task);
64
+ await this._save(tasks);
65
+ });
66
+ }
67
+
68
+ public async updateTask(id: string, updates: Partial<Task>): Promise<Task | null> {
69
+ return this.withLock(async () => {
70
+ const tasks = await this._load();
71
+ const index = tasks.findIndex((t) => t.id === id);
72
+ if (index === -1) return null;
73
+
74
+ tasks[index] = { ...tasks[index], ...updates, updatedAt: new Date().toISOString() };
75
+ await this._save(tasks);
76
+ return tasks[index];
77
+ });
78
+ }
79
+
80
+ public async deleteTask(id: string): Promise<boolean> {
81
+ return this.withLock(async () => {
82
+ const tasks = await this._load();
83
+ const initialLength = tasks.length;
84
+ const filteredTasks = tasks.filter((t) => t.id !== id);
85
+
86
+ if (filteredTasks.length === initialLength) return false;
87
+
88
+ await this._save(filteredTasks);
89
+ return true;
90
+ });
91
+ }
92
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "declaration": true,
11
+ "sourceMap": true
12
+ },
13
+ "include": ["src/**/*"]
14
+ }
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@saccolabs/tars",
3
+ "version": "1.0.7",
4
+ "description": "Tars — Your personal AI assistant",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "type": "module",
9
+ "bin": {
10
+ "tars": "dist/cli/index.js"
11
+ },
12
+ "main": "./dist/supervisor/main.js",
13
+ "scripts": {
14
+ "build": "npm run build:src && npm run build:extensions",
15
+ "build:src": "tsc && chmod +x dist/cli/index.js",
16
+ "build:extensions": "true",
17
+ "dev": "tsx watch src/supervisor/main.ts",
18
+ "start": "node dist/supervisor/main.js",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "lint": "prettier --check .",
22
+ "format": "prettier --write ."
23
+ },
24
+ "files": [
25
+ "dist/",
26
+ "!dist/tests/",
27
+ "src/prompts/",
28
+ "extensions/",
29
+ "!extensions/**/node_modules/",
30
+ "context/",
31
+ "README.md"
32
+ ],
33
+ "dependencies": {
34
+ "chalk": "^5.0.0",
35
+ "commander": "^12.0.0",
36
+ "cron-parser": "^5.4.0",
37
+ "discord.js": "^14.16.3",
38
+ "dotenv": "^16.4.7",
39
+ "inquirer": "^9.0.0",
40
+ "ora": "^8.0.0",
41
+ "pm2": "^5.3.0",
42
+ "uuid": "^13.0.0",
43
+ "winston": "^3.19.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/inquirer": "^9.0.0",
47
+ "@types/node": "^22.10.2",
48
+ "@types/uuid": "^10.0.0",
49
+ "@vitest/coverage-v8": "^2.1.9",
50
+ "prettier": "^3.7.4",
51
+ "tsx": "^4.19.2",
52
+ "typescript": "^5.7.2",
53
+ "vitest": "^2.1.8"
54
+ }
55
+ }
@@ -0,0 +1,25 @@
1
+ # Tars - System Instructions
2
+
3
+ You are **Tars**, a personal AI assistant. You are autonomous, proactive, and capable of self-improvement. You serve one user as a trusted generalist across all domains.
4
+
5
+ ## Core Directives
6
+
7
+ 1. **Be Helpful & Efficient**: Save the user time. Provide accurate, useful info.
8
+ 2. **Be Adaptable**: Adjust your tone, style, and approach based on the user's current request and preferences stored in memory (`~/.tars/.gemini/GEMINI.md`).
9
+ 3. **Be Proactive**: Suggest follow-ups or improvements when relevant.
10
+ 4. **Be Secure**: Never expose secrets or sensitive info.
11
+
12
+ ## Operational Rules
13
+
14
+ - **Memory**: Your persistent long-term memory is at `~/.tars/.gemini/GEMINI.md`. Read/write to this path to store preferences and context. Use `tars memory search` to recall past decisions.
15
+ - **Safety**: Do **NOT** run `gemini` CLI commands or manage the `tars` supervisor process (start/stop) directly. Use internal tools or config files.
16
+ - **Tools**: Use absolute file paths. Maximize parallelism and tool usage. Use background processes (`&`) for long-running shell commands.
17
+
18
+ ## Capabilities
19
+
20
+ - **Self-Modification**: Create **Extensions** (MCP), **Skills** (`SKILL.md`), or **Commands** (`cmd.toml`) to extend your abilities.
21
+ - **Task Scheduling**: Use task tools to create reminders or recurring jobs (prefer cron syntax).
22
+ - **Coding**: When coding, prioritize understanding the existing codebase, planning before acting, and verifying your changes with tests/linting.
23
+
24
+ ${AgentSkills}
25
+ ${SubAgents}