trismegistus 1.0.1 → 1.0.2
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/README.md +8 -5
- package/dist/cli.js +63 -12
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ The daemon picks up tasks one at a time, runs each in a full Claude Code session
|
|
|
39
39
|
|
|
40
40
|
| Command | Description |
|
|
41
41
|
|---------|-------------|
|
|
42
|
-
| `tmg init` | Create `.trismegistus/` folder with config, tasks, and
|
|
42
|
+
| `tmg init` | Create `.trismegistus/` folder with config, tasks, notes, and README; adds transient files to `.gitignore` |
|
|
43
43
|
| `tmg add "task"` | Add a task to the queue |
|
|
44
44
|
| `tmg start` | Start the daemon — runs tasks continuously until the queue is empty |
|
|
45
45
|
| `tmg status` | Show counts of pending, in-progress, done, retrying, and gave-up tasks |
|
|
@@ -178,12 +178,15 @@ TASK_DELAY_SECONDS=5 # Pause between tasks
|
|
|
178
178
|
|
|
179
179
|
```
|
|
180
180
|
.trismegistus/
|
|
181
|
-
config # Daemon configuration
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
181
|
+
config # Daemon configuration (committed)
|
|
182
|
+
README.md # Explains the folder to collaborators (committed)
|
|
183
|
+
tasks.md # Your task queue (gitignored)
|
|
184
|
+
notes.md # Notes for Claude, cleared after each read (gitignored)
|
|
185
|
+
handoff # Context passed between retry attempts (gitignored, auto-managed)
|
|
185
186
|
```
|
|
186
187
|
|
|
188
|
+
`tmg init` automatically adds the transient files (`tasks.md`, `notes.md`, `handoff`) to your project's `.gitignore`. The `config` and `README.md` are committed so team members share daemon settings and understand the folder.
|
|
189
|
+
|
|
187
190
|
## License
|
|
188
191
|
|
|
189
192
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { hostname } from "os";
|
|
|
7
7
|
import qrcode from "qrcode-terminal";
|
|
8
8
|
|
|
9
9
|
// src/init.ts
|
|
10
|
-
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
11
11
|
import { join } from "path";
|
|
12
12
|
|
|
13
13
|
// src/types.ts
|
|
@@ -37,6 +37,44 @@ IDLE_POLL_SECONDS=10
|
|
|
37
37
|
TASK_DELAY_SECONDS=5
|
|
38
38
|
`;
|
|
39
39
|
var STATUS_PRIORITY = [" ", "!", "!!"];
|
|
40
|
+
var README_FILE = "README.md";
|
|
41
|
+
var README_TEMPLATE = `# .trismegistus
|
|
42
|
+
|
|
43
|
+
This project uses [Trismegistus](https://www.npmjs.com/package/trismegistus) \u2014 a local daemon that runs Claude Code sessions from a task queue.
|
|
44
|
+
|
|
45
|
+
## Getting started
|
|
46
|
+
|
|
47
|
+
\`\`\`bash
|
|
48
|
+
npm install -D trismegistus
|
|
49
|
+
npx tmg init # already done if you see this file
|
|
50
|
+
npx tmg add "your task here"
|
|
51
|
+
npx tmg start # runs tasks autonomously
|
|
52
|
+
\`\`\`
|
|
53
|
+
|
|
54
|
+
## Files in this directory
|
|
55
|
+
|
|
56
|
+
| File | Tracked | Purpose |
|
|
57
|
+
|------|---------|---------|
|
|
58
|
+
| \`config\` | Yes | Daemon settings (retries, timeouts) \u2014 shared with team |
|
|
59
|
+
| \`README.md\` | Yes | This file |
|
|
60
|
+
| \`tasks.md\` | No | Personal task queue (gitignored) |
|
|
61
|
+
| \`notes.md\` | No | Notes for Claude, cleared after each read (gitignored) |
|
|
62
|
+
| \`handoff\` | No | Retry context between failed attempts (gitignored) |
|
|
63
|
+
|
|
64
|
+
## Commands
|
|
65
|
+
|
|
66
|
+
- \`tmg add "task"\` \u2014 Add a task to the queue
|
|
67
|
+
- \`tmg start\` \u2014 Start the daemon
|
|
68
|
+
- \`tmg status\` \u2014 Show task counts
|
|
69
|
+
- \`tmg notes "text"\` \u2014 Leave notes for Claude's next run
|
|
70
|
+
- \`tmg reset\` \u2014 Reset gave-up tasks back to pending
|
|
71
|
+
- \`tmg remote\` \u2014 Start a VS Code tunnel for mobile access
|
|
72
|
+
`;
|
|
73
|
+
var GITIGNORE_ENTRIES = [
|
|
74
|
+
".trismegistus/tasks.md",
|
|
75
|
+
".trismegistus/notes.md",
|
|
76
|
+
".trismegistus/handoff"
|
|
77
|
+
];
|
|
40
78
|
var CLAUDE_COMMANDS = [
|
|
41
79
|
{
|
|
42
80
|
name: "tmg.md",
|
|
@@ -105,7 +143,8 @@ function initProject(projectDir) {
|
|
|
105
143
|
const files = [
|
|
106
144
|
{ name: CONFIG_FILE, content: CONFIG_TEMPLATE },
|
|
107
145
|
{ name: TASKS_FILE, content: TASKS_TEMPLATE },
|
|
108
|
-
{ name: NOTES_FILE, content: NOTES_TEMPLATE }
|
|
146
|
+
{ name: NOTES_FILE, content: NOTES_TEMPLATE },
|
|
147
|
+
{ name: README_FILE, content: README_TEMPLATE }
|
|
109
148
|
];
|
|
110
149
|
for (const file of files) {
|
|
111
150
|
const path = join(tmgDir, file.name);
|
|
@@ -125,11 +164,23 @@ function initProject(projectDir) {
|
|
|
125
164
|
result.created.push(`.claude/commands/${cmd.name}`);
|
|
126
165
|
}
|
|
127
166
|
}
|
|
167
|
+
const gitignorePath = join(projectDir, ".gitignore");
|
|
168
|
+
let gitignoreContent = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
|
|
169
|
+
const missing = GITIGNORE_ENTRIES.filter(
|
|
170
|
+
(entry) => !gitignoreContent.includes(entry)
|
|
171
|
+
);
|
|
172
|
+
if (missing.length > 0) {
|
|
173
|
+
const block = missing.join("\n") + "\n";
|
|
174
|
+
const needsNewline = gitignoreContent.length > 0 && !gitignoreContent.endsWith("\n");
|
|
175
|
+
gitignoreContent += (needsNewline ? "\n" : "") + block;
|
|
176
|
+
writeFileSync(gitignorePath, gitignoreContent);
|
|
177
|
+
result.created.push(".gitignore entries");
|
|
178
|
+
}
|
|
128
179
|
return result;
|
|
129
180
|
}
|
|
130
181
|
|
|
131
182
|
// src/tasks.ts
|
|
132
|
-
import { readFileSync, writeFileSync as writeFileSync2, existsSync as existsSync2, unlinkSync } from "fs";
|
|
183
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, unlinkSync } from "fs";
|
|
133
184
|
import { join as join2 } from "path";
|
|
134
185
|
var TASK_REGEX = /^- \[([^\]]*)\] (.+)$/;
|
|
135
186
|
function tasksPath(projectDir) {
|
|
@@ -156,7 +207,7 @@ function parseTasks(content) {
|
|
|
156
207
|
function readTasks(projectDir) {
|
|
157
208
|
const path = tasksPath(projectDir);
|
|
158
209
|
if (!existsSync2(path)) return [];
|
|
159
|
-
return parseTasks(
|
|
210
|
+
return parseTasks(readFileSync2(path, "utf-8"));
|
|
160
211
|
}
|
|
161
212
|
function getNextTask(projectDir) {
|
|
162
213
|
const tasks = readTasks(projectDir);
|
|
@@ -168,7 +219,7 @@ function getNextTask(projectDir) {
|
|
|
168
219
|
}
|
|
169
220
|
function setTaskStatus(projectDir, taskText, newStatus) {
|
|
170
221
|
const path = tasksPath(projectDir);
|
|
171
|
-
const content =
|
|
222
|
+
const content = readFileSync2(path, "utf-8");
|
|
172
223
|
const lines = content.split("\n");
|
|
173
224
|
let found = false;
|
|
174
225
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -198,7 +249,7 @@ function getTaskCounts(projectDir) {
|
|
|
198
249
|
function resetGaveUpTasks(projectDir) {
|
|
199
250
|
const path = tasksPath(projectDir);
|
|
200
251
|
if (!existsSync2(path)) return 0;
|
|
201
|
-
const content =
|
|
252
|
+
const content = readFileSync2(path, "utf-8");
|
|
202
253
|
const lines = content.split("\n");
|
|
203
254
|
let count = 0;
|
|
204
255
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -214,7 +265,7 @@ function resetGaveUpTasks(projectDir) {
|
|
|
214
265
|
function readAndClearNotes(projectDir) {
|
|
215
266
|
const path = notesPath(projectDir);
|
|
216
267
|
if (!existsSync2(path)) return "";
|
|
217
|
-
const content =
|
|
268
|
+
const content = readFileSync2(path, "utf-8");
|
|
218
269
|
const notes = content.split("\n").filter((l) => !l.startsWith("#") && l.trim() !== "").slice(0, 50).join("\n");
|
|
219
270
|
writeFileSync2(
|
|
220
271
|
path,
|
|
@@ -225,7 +276,7 @@ function readAndClearNotes(projectDir) {
|
|
|
225
276
|
function readHandoff(projectDir) {
|
|
226
277
|
const path = handoffPath(projectDir);
|
|
227
278
|
if (!existsSync2(path)) return "";
|
|
228
|
-
return
|
|
279
|
+
return readFileSync2(path, "utf-8");
|
|
229
280
|
}
|
|
230
281
|
function writeHandoff(projectDir, content) {
|
|
231
282
|
writeFileSync2(handoffPath(projectDir), content);
|
|
@@ -255,7 +306,7 @@ function appendNotes(projectDir, text) {
|
|
|
255
306
|
if (!existsSync2(path)) {
|
|
256
307
|
throw new Error("No notes file found. Run `tmg init` first.");
|
|
257
308
|
}
|
|
258
|
-
const content =
|
|
309
|
+
const content = readFileSync2(path, "utf-8");
|
|
259
310
|
const separator = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
|
|
260
311
|
writeFileSync2(path, content + separator + trimmed + "\n");
|
|
261
312
|
}
|
|
@@ -270,7 +321,7 @@ function addTask(projectDir, text) {
|
|
|
270
321
|
"No tasks file found. Run `tmg init` first."
|
|
271
322
|
);
|
|
272
323
|
}
|
|
273
|
-
const content =
|
|
324
|
+
const content = readFileSync2(path, "utf-8");
|
|
274
325
|
const line = `- [ ] ${trimmed}
|
|
275
326
|
`;
|
|
276
327
|
const separator = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
|
|
@@ -288,7 +339,7 @@ import { join as join4 } from "path";
|
|
|
288
339
|
import { execFileSync } from "child_process";
|
|
289
340
|
|
|
290
341
|
// src/config.ts
|
|
291
|
-
import { readFileSync as
|
|
342
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
|
|
292
343
|
import { join as join3 } from "path";
|
|
293
344
|
var KEY_MAP = {
|
|
294
345
|
MAX_RETRIES: "maxRetries",
|
|
@@ -319,7 +370,7 @@ function loadConfig(projectDir) {
|
|
|
319
370
|
if (!existsSync3(configPath)) {
|
|
320
371
|
return { ...DEFAULT_CONFIG };
|
|
321
372
|
}
|
|
322
|
-
const content =
|
|
373
|
+
const content = readFileSync3(configPath, "utf-8");
|
|
323
374
|
const overrides = parseConfigFile(content);
|
|
324
375
|
return { ...DEFAULT_CONFIG, ...overrides };
|
|
325
376
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trismegistus",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A local persistent daemon that runs AI sessions from a task queue, with mobile support.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/cli.js",
|
|
7
6
|
"bin": {
|
|
8
7
|
"tmg": "./dist/cli.js"
|
|
9
8
|
},
|
|
@@ -12,7 +11,7 @@
|
|
|
12
11
|
"dev": "tsx src/cli.ts",
|
|
13
12
|
"test": "vitest run",
|
|
14
13
|
"test:watch": "vitest",
|
|
15
|
-
"prepublishOnly": "npm run build"
|
|
14
|
+
"prepublishOnly": "npm run build && npm test"
|
|
16
15
|
},
|
|
17
16
|
"keywords": [
|
|
18
17
|
"claude",
|