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.
Files changed (3) hide show
  1. package/README.md +8 -5
  2. package/dist/cli.js +63 -12
  3. 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 notes files |
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
- tasks.md # Your task queue
183
- notes.md # Notes for Claude (cleared after each read)
184
- handoff # Context passed between retry attempts (auto-managed)
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(readFileSync(path, "utf-8"));
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 = readFileSync(path, "utf-8");
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 = readFileSync(path, "utf-8");
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 = readFileSync(path, "utf-8");
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 readFileSync(path, "utf-8");
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 = readFileSync(path, "utf-8");
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 = readFileSync(path, "utf-8");
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 readFileSync2, existsSync as existsSync3 } from "fs";
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 = readFileSync2(configPath, "utf-8");
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.1",
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",