@detergent-software/conductor 0.0.0-stage → 1.0.0-dev.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 (69) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +131 -2
  3. package/build/claude.js +102 -0
  4. package/build/claude.js.map +1 -0
  5. package/build/cli.js +450 -0
  6. package/build/cli.js.map +1 -0
  7. package/build/client.js +64 -0
  8. package/build/client.js.map +1 -0
  9. package/build/conditions.js +198 -0
  10. package/build/conditions.js.map +1 -0
  11. package/build/config.js +74 -0
  12. package/build/config.js.map +1 -0
  13. package/build/daemon.js +127 -0
  14. package/build/daemon.js.map +1 -0
  15. package/build/errors.js +17 -0
  16. package/build/errors.js.map +1 -0
  17. package/build/jsonc.js +24 -0
  18. package/build/jsonc.js.map +1 -0
  19. package/build/lock.js +64 -0
  20. package/build/lock.js.map +1 -0
  21. package/build/log.js +43 -0
  22. package/build/log.js.map +1 -0
  23. package/build/manager.js +614 -0
  24. package/build/manager.js.map +1 -0
  25. package/build/paths.js +16 -0
  26. package/build/paths.js.map +1 -0
  27. package/build/profile.js +74 -0
  28. package/build/profile.js.map +1 -0
  29. package/build/registry.js +33 -0
  30. package/build/registry.js.map +1 -0
  31. package/build/resolve.js +28 -0
  32. package/build/resolve.js.map +1 -0
  33. package/build/run.js +52 -0
  34. package/build/run.js.map +1 -0
  35. package/build/server.js +227 -0
  36. package/build/server.js.map +1 -0
  37. package/build/spend.js +134 -0
  38. package/build/spend.js.map +1 -0
  39. package/build/startup.js +78 -0
  40. package/build/startup.js.map +1 -0
  41. package/build/store.js +528 -0
  42. package/build/store.js.map +1 -0
  43. package/build/tab.js +26 -0
  44. package/build/tab.js.map +1 -0
  45. package/build/token.js +58 -0
  46. package/build/token.js.map +1 -0
  47. package/build/upgrade.js +93 -0
  48. package/build/upgrade.js.map +1 -0
  49. package/build/wait.js +149 -0
  50. package/build/wait.js.map +1 -0
  51. package/build/watchers/ado.js +167 -0
  52. package/build/watchers/ado.js.map +1 -0
  53. package/build/watchers/github.js +82 -0
  54. package/build/watchers/github.js.map +1 -0
  55. package/build/watchers/health.js +42 -0
  56. package/build/watchers/health.js.map +1 -0
  57. package/build/watchers/index.js +226 -0
  58. package/build/watchers/index.js.map +1 -0
  59. package/build/watchers/linear-key.js +56 -0
  60. package/build/watchers/linear-key.js.map +1 -0
  61. package/build/watchers/linear.js +218 -0
  62. package/build/watchers/linear.js.map +1 -0
  63. package/build/watchers/npm.js +35 -0
  64. package/build/watchers/npm.js.map +1 -0
  65. package/build/watchers/source.js +94 -0
  66. package/build/watchers/source.js.map +1 -0
  67. package/build/worktrees.js +143 -0
  68. package/build/worktrees.js.map +1 -0
  69. package/package.json +56 -5
package/build/spend.js ADDED
@@ -0,0 +1,134 @@
1
+ import { closeSync, existsSync, openSync, readdirSync, readSync, statSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { z } from 'zod';
5
+ // One assistant message writes a line per content block, each with the same `usage` (ATK-309's
6
+ // check: 33 ids, none differ), and tool results can fall between them, so a message counts once
7
+ // by its id. Ids are kept for the most recent messages only; an older one doesn't come back.
8
+ const RECENT_IDS = 200;
9
+ const READ_CHUNK = 4 * 1024 * 1024;
10
+ const usageLine = z.looseObject({
11
+ message: z.looseObject({
12
+ id: z.string(),
13
+ usage: z.looseObject({
14
+ cache_creation_input_tokens: z.number().nullish(),
15
+ cache_read_input_tokens: z.number().nullish(),
16
+ input_tokens: z.number().nullish(),
17
+ output_tokens: z.number().nullish(),
18
+ }),
19
+ }),
20
+ timestamp: z.string(),
21
+ });
22
+ export function claudeProjectsDir() {
23
+ return join(process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude'), 'projects');
24
+ }
25
+ export function emptyUsage() {
26
+ return { cacheRead: 0, cacheWrite: 0, input: 0, output: 0 };
27
+ }
28
+ // The session's transcript, under ~/.claude/projects/<slug of its cwd>/, wherever the cwd was.
29
+ export function findTranscript(projectsDir, sessionId) {
30
+ if (!existsSync(projectsDir))
31
+ return null;
32
+ for (const dir of readdirSync(projectsDir)) {
33
+ const file = join(projectsDir, dir, `${sessionId}.jsonl`);
34
+ if (existsSync(file))
35
+ return file;
36
+ }
37
+ return null;
38
+ }
39
+ // The local calendar day of a timestamp, YYYY-MM-DD: quiet hours and daily caps are local.
40
+ export function localDay(at) {
41
+ const pad = (n) => String(n).padStart(2, '0');
42
+ return `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`;
43
+ }
44
+ // The directory name Claude Code keeps a cwd's transcripts under: every character that isn't a
45
+ // letter or digit becomes `-` (C:\Users\x\repo → C--Users-x-repo).
46
+ export function projectSlug(cwd) {
47
+ return cwd.replace(/[^a-zA-Z0-9]/g, '-');
48
+ }
49
+ // The new usage in a transcript since `cursor`, by local day. Only whole lines are read: a line
50
+ // still being written is read on the next call.
51
+ export function readUsage(file, cursor) {
52
+ const byDay = new Map();
53
+ const size = existsSync(file) ? statSync(file).size : 0;
54
+ // A file that shrank was replaced: start again.
55
+ const start = size < cursor.bytes ? 0 : cursor.bytes;
56
+ if (size === start)
57
+ return { byDay, cursor: { ...cursor, bytes: start } };
58
+ // Cut at the last newline in the bytes, not in decoded text: a byte that isn't UTF-8 decodes to
59
+ // U+FFFD, three bytes long, and would move the cursor past the next line's start.
60
+ const bytes = readFrom(file, start, size);
61
+ const end = bytes.lastIndexOf(0x0a);
62
+ if (end < 0)
63
+ return { byDay, cursor: { ...cursor, bytes: start } };
64
+ const recent = new Set(cursor.recentIds);
65
+ const counted = [];
66
+ for (const line of bytes.subarray(0, end).toString('utf8').split('\n')) {
67
+ const entry = parseLine(line);
68
+ if (!entry || recent.has(entry.message.id))
69
+ continue;
70
+ recent.add(entry.message.id);
71
+ counted.push(entry.message.id);
72
+ const day = localDay(new Date(entry.timestamp));
73
+ const usage = byDay.get(day) ?? emptyUsage();
74
+ const u = entry.message.usage;
75
+ usage.input += u.input_tokens ?? 0;
76
+ usage.output += u.output_tokens ?? 0;
77
+ usage.cacheRead += u.cache_read_input_tokens ?? 0;
78
+ usage.cacheWrite += u.cache_creation_input_tokens ?? 0;
79
+ byDay.set(day, usage);
80
+ }
81
+ return {
82
+ byDay,
83
+ cursor: {
84
+ bytes: start + end + 1,
85
+ recentIds: [...cursor.recentIds, ...counted].slice(-RECENT_IDS),
86
+ },
87
+ };
88
+ }
89
+ export function totalTokens(usage) {
90
+ return usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
91
+ }
92
+ // A session's transcripts: its own, and one per subagent it ran (<session>/subagents/*.jsonl).
93
+ // Jason counts subagent spend too.
94
+ export function transcriptFiles(main) {
95
+ const subagents = join(main.replace(/\.jsonl$/, ''), 'subagents');
96
+ const children = existsSync(subagents)
97
+ ? readdirSync(subagents)
98
+ .filter((f) => f.endsWith('.jsonl'))
99
+ .sort()
100
+ .map((f) => join(subagents, f))
101
+ : [];
102
+ return [main, ...children];
103
+ }
104
+ function parseLine(line) {
105
+ if (!line.includes('"usage"'))
106
+ return null;
107
+ try {
108
+ const parsed = usageLine.safeParse(JSON.parse(line));
109
+ return parsed.success ? parsed.data : null;
110
+ }
111
+ catch {
112
+ return null; // not JSON: skip it, as Claude Code does
113
+ }
114
+ }
115
+ // Bytes [start, end) of a file.
116
+ function readFrom(file, start, end) {
117
+ const fd = openSync(file, 'r');
118
+ try {
119
+ const chunks = [];
120
+ for (let position = start; position < end;) {
121
+ const buffer = Buffer.alloc(Math.min(READ_CHUNK, end - position));
122
+ const read = readSync(fd, buffer, 0, buffer.length, position);
123
+ if (read === 0)
124
+ break;
125
+ chunks.push(buffer.subarray(0, read));
126
+ position += read;
127
+ }
128
+ return Buffer.concat(chunks);
129
+ }
130
+ finally {
131
+ closeSync(fd);
132
+ }
133
+ }
134
+ //# sourceMappingURL=spend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spend.js","sourceRoot":"","sources":["../src/spend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { execFileSync, spawnSync } from 'node:child_process';
2
+ import { ConductorError } from "./errors.js";
3
+ export const TASK_NAME = 'Conductor';
4
+ // Registers a per-user Task Scheduler task that runs `conduct serve` at logon. No elevation is
5
+ // needed for a task that runs as the current user. conhost --headless keeps a console window (or
6
+ // a Windows Terminal tab) from opening, and the zero time limit stops Task Scheduler from ending
7
+ // the daemon after its default 72 hours. A second start while one runs exits on the pid lock.
8
+ export function installStartup({ cliPath, nodePath }) {
9
+ requireWindows();
10
+ const script = [
11
+ "$ErrorActionPreference = 'Stop'",
12
+ '$user = "$env:USERDOMAIN\\$env:USERNAME"',
13
+ '$action = New-ScheduledTaskAction -Execute "$env:SystemRoot\\System32\\conhost.exe" -Argument $env:CONDUCTOR_TASK_ARGS',
14
+ '$trigger = New-ScheduledTaskTrigger -AtLogOn -User $user',
15
+ '$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -MultipleInstances IgnoreNew -ExecutionTimeLimit ([TimeSpan]::Zero)',
16
+ '$principal = New-ScheduledTaskPrincipal -UserId $user -LogonType Interactive -RunLevel Limited',
17
+ `Register-ScheduledTask -TaskName '${TASK_NAME}' -Description 'Starts the conductor daemon (conduct serve) at logon.' -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force | Out-Null`,
18
+ ].join('\n');
19
+ powershell(script, { CONDUCTOR_TASK_ARGS: `--headless "${nodePath}" "${cliPath}" serve` });
20
+ }
21
+ // True when a task was removed, false when there was none.
22
+ export function removeStartup() {
23
+ requireWindows();
24
+ if (!startupInstalled())
25
+ return false;
26
+ execFileSync('schtasks', ['/Delete', '/TN', TASK_NAME, '/F'], { stdio: 'ignore' });
27
+ return true;
28
+ }
29
+ export function runStartup() {
30
+ const result = spawnSync('schtasks', ['/Run', '/TN', TASK_NAME], { encoding: 'utf8' });
31
+ if (result.status !== 0) {
32
+ throw new ConductorError(`could not run the "${TASK_NAME}" logon task`, [
33
+ result.stderr?.trim() || result.error?.message || `exit ${result.status}`,
34
+ ]);
35
+ }
36
+ }
37
+ export function startupInstalled() {
38
+ return spawnSync('schtasks', ['/Query', '/TN', TASK_NAME], { stdio: 'ignore' }).status === 0;
39
+ }
40
+ // True when the logon task exists and its action runs this cli.js, so running it starts this
41
+ // build. A task registered from another build (a linked checkout) would start that one.
42
+ export function startupRunsCli(cliPath) {
43
+ if (process.platform !== 'win32')
44
+ return false;
45
+ const result = spawnSync('schtasks', ['/Query', '/TN', TASK_NAME, '/XML'], { encoding: 'utf8' });
46
+ return result.status === 0 && taskRunsCli(result.stdout, cliPath);
47
+ }
48
+ // The task's <Arguments> quote the cli.js path (installStartup); XML escapes it, and Windows paths
49
+ // compare without case.
50
+ export function taskRunsCli(xml, cliPath) {
51
+ const args = /<Arguments>([^<]*)<\/Arguments>/.exec(xml)?.[1];
52
+ if (args === undefined)
53
+ return false;
54
+ const unescaped = args
55
+ .replaceAll('&quot;', '"')
56
+ .replaceAll('&apos;', "'")
57
+ .replaceAll('&lt;', '<')
58
+ .replaceAll('&gt;', '>')
59
+ .replaceAll('&amp;', '&');
60
+ return unescaped.toLowerCase().includes(`"${cliPath.toLowerCase()}"`);
61
+ }
62
+ function powershell(script, env) {
63
+ const result = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script], {
64
+ encoding: 'utf8',
65
+ env: { ...process.env, ...env },
66
+ });
67
+ if (result.status !== 0) {
68
+ throw new ConductorError('could not register the logon task', [result.stderr.trim() || `exit ${result.status}`]);
69
+ }
70
+ }
71
+ function requireWindows() {
72
+ if (process.platform !== 'win32') {
73
+ throw new ConductorError('install-startup supports Windows only', [
74
+ 'start `conduct serve` from your own login items',
75
+ ]);
76
+ }
77
+ }
78
+ //# sourceMappingURL=startup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup.js","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":"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"}