@gurugokul/doomscroller 0.0.0-stage → 0.2.0

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 (61) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/LICENSE +21 -0
  3. package/README.md +323 -2
  4. package/dist/adapters/claude-code-hooks.js +27 -0
  5. package/dist/adapters/claude-code-hooks.js.map +1 -0
  6. package/dist/adapters/cli-wrapper.js +230 -0
  7. package/dist/adapters/cli-wrapper.js.map +1 -0
  8. package/dist/adapters/command-code-hooks.js +32 -0
  9. package/dist/adapters/command-code-hooks.js.map +1 -0
  10. package/dist/adapters/file-activity.js +78 -0
  11. package/dist/adapters/file-activity.js.map +1 -0
  12. package/dist/adapters/hook-settings.js +164 -0
  13. package/dist/adapters/hook-settings.js.map +1 -0
  14. package/dist/adapters/hook.js +17 -0
  15. package/dist/adapters/hook.js.map +1 -0
  16. package/dist/adapters/hotkey.js +50 -0
  17. package/dist/adapters/hotkey.js.map +1 -0
  18. package/dist/adapters/ide-activity.js +245 -0
  19. package/dist/adapters/ide-activity.js.map +1 -0
  20. package/dist/adapters/ports.js +3 -0
  21. package/dist/adapters/ports.js.map +1 -0
  22. package/dist/adapters/wrapper-tracker.js +77 -0
  23. package/dist/adapters/wrapper-tracker.js.map +1 -0
  24. package/dist/cli.js +343 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/core/config.js +192 -0
  27. package/dist/core/config.js.map +1 -0
  28. package/dist/core/daemon.js +156 -0
  29. package/dist/core/daemon.js.map +1 -0
  30. package/dist/core/ipc.js +215 -0
  31. package/dist/core/ipc.js.map +1 -0
  32. package/dist/core/logger.js +53 -0
  33. package/dist/core/logger.js.map +1 -0
  34. package/dist/core/sound.js +38 -0
  35. package/dist/core/sound.js.map +1 -0
  36. package/dist/core/state-machine.js +272 -0
  37. package/dist/core/state-machine.js.map +1 -0
  38. package/dist/core/stats.js +109 -0
  39. package/dist/core/stats.js.map +1 -0
  40. package/dist/core/targets.js +27 -0
  41. package/dist/core/targets.js.map +1 -0
  42. package/dist/core/types.js +6 -0
  43. package/dist/core/types.js.map +1 -0
  44. package/dist/index.js +15 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/util/errors.js +16 -0
  47. package/dist/util/errors.js.map +1 -0
  48. package/dist/util/paths.js +77 -0
  49. package/dist/util/paths.js.map +1 -0
  50. package/dist/windows/cpu-probe.js +108 -0
  51. package/dist/windows/cpu-probe.js.map +1 -0
  52. package/dist/windows/key-listener.js +198 -0
  53. package/dist/windows/key-listener.js.map +1 -0
  54. package/dist/windows/win32.js +158 -0
  55. package/dist/windows/win32.js.map +1 -0
  56. package/dist/windows/window-controller.js +3 -0
  57. package/dist/windows/window-controller.js.map +1 -0
  58. package/package.json +57 -4
  59. package/scripts/cpu-sampler.ps1 +83 -0
  60. package/scripts/key-watcher.ps1 +132 -0
  61. package/scripts/win32-window.ps1 +344 -0
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DoomscrollerStateMachine = exports.systemScheduler = void 0;
4
+ const logger_1 = require("./logger");
5
+ const types_1 = require("./types");
6
+ const errors_1 = require("../util/errors");
7
+ exports.systemScheduler = {
8
+ setTimer: (callback, delayMs) => setTimeout(callback, delayMs),
9
+ clearTimer: (timer) => clearTimeout(timer),
10
+ };
11
+ class DoomscrollerStateMachine {
12
+ deps;
13
+ currentState = 'idle';
14
+ startedAtMs = 0;
15
+ doomStartedAtMs = null;
16
+ target = null;
17
+ agentWindow = null;
18
+ browserWindow = null;
19
+ delayTimer = null;
20
+ capTimer = null;
21
+ tail = Promise.resolve();
22
+ disposed = false;
23
+ now;
24
+ scheduler;
25
+ constructor(deps) {
26
+ this.deps = deps;
27
+ this.now = deps.now ?? Date.now;
28
+ this.scheduler = deps.scheduler ?? exports.systemScheduler;
29
+ }
30
+ get state() {
31
+ return this.currentState;
32
+ }
33
+ get isWorking() {
34
+ return this.currentState === 'working';
35
+ }
36
+ get currentTarget() {
37
+ return this.target;
38
+ }
39
+ /** Refreshes the config used by the next session (delay, cap, ...). */
40
+ updateConfig(config) {
41
+ this.deps.config = config;
42
+ }
43
+ /** Serializes events so overlapping hook callbacks can't interleave window operations. */
44
+ handle(event) {
45
+ if (event === types_1.AGENT_STARTED) {
46
+ return this.enqueue(() => this.onStarted());
47
+ }
48
+ if (event === types_1.AGENT_FINISHED) {
49
+ return this.enqueue(() => this.onFinished());
50
+ }
51
+ return Promise.resolve();
52
+ }
53
+ /** Global hotkey / max-cap escape hatch. Ends the current session and restores focus. */
54
+ forceReturn(reason = 'hotkey') {
55
+ return this.enqueue(async () => {
56
+ if (this.currentState !== 'working') {
57
+ this.deps.logger.debug(`force return ignored while ${this.currentState}`);
58
+ return;
59
+ }
60
+ this.deps.logger.info(`force return requested (${reason})`);
61
+ await this.endSession(reason);
62
+ });
63
+ }
64
+ whenIdle() {
65
+ return this.tail;
66
+ }
67
+ dispose() {
68
+ this.disposed = true;
69
+ this.clearTimers();
70
+ }
71
+ enqueue(operation) {
72
+ const next = this.tail
73
+ .then(operation)
74
+ .catch((error) => {
75
+ (0, logger_1.logCaught)(this.deps.logger, 'state machine error', error);
76
+ });
77
+ this.tail = next;
78
+ return next;
79
+ }
80
+ onStarted() {
81
+ if (this.disposed)
82
+ return Promise.resolve();
83
+ if (this.currentState === 'working') {
84
+ this.deps.logger.debug('duplicate agent:started ignored');
85
+ return Promise.resolve();
86
+ }
87
+ this.clearTimers();
88
+ this.currentState = 'working';
89
+ this.startedAtMs = this.now();
90
+ this.doomStartedAtMs = null;
91
+ this.target = null;
92
+ this.agentWindow = null;
93
+ this.browserWindow = null;
94
+ this.notify();
95
+ const delayMs = Math.max(0, this.deps.config.delaySeconds) * 1000;
96
+ this.deps.logger.info(`agent:started -> WORKING (doomscroll in ${this.deps.config.delaySeconds}s)`);
97
+ if (delayMs === 0)
98
+ return this.beginDoomscroll();
99
+ this.delayTimer = this.scheduler.setTimer(() => {
100
+ this.delayTimer = null;
101
+ void this.enqueue(() => this.beginDoomscroll());
102
+ }, delayMs);
103
+ return Promise.resolve();
104
+ }
105
+ onFinished() {
106
+ if (this.disposed)
107
+ return Promise.resolve();
108
+ if (this.currentState !== 'working') {
109
+ this.deps.logger.debug(`agent:finished ignored while ${this.currentState}`);
110
+ return Promise.resolve();
111
+ }
112
+ return this.endSession('finished');
113
+ }
114
+ async beginDoomscroll() {
115
+ if (this.disposed || this.currentState !== 'working' || this.doomStartedAtMs !== null)
116
+ return;
117
+ let agentWindow = null;
118
+ try {
119
+ agentWindow = await this.deps.windows.getForegroundWindow();
120
+ }
121
+ catch (error) {
122
+ (0, logger_1.logCaught)(this.deps.logger, 'could not read foreground window', error);
123
+ }
124
+ if (agentWindow) {
125
+ this.agentWindow = agentWindow;
126
+ try {
127
+ await this.deps.windows.minimizeWindow(agentWindow);
128
+ this.deps.logger.info(`minimized agent window: "${agentWindow.title}" (${agentWindow.processName})`);
129
+ }
130
+ catch (error) {
131
+ (0, logger_1.logCaught)(this.deps.logger, 'could not minimize agent window', error);
132
+ }
133
+ }
134
+ else {
135
+ this.deps.logger.warn('no foreground window to save; continuing without a restore target');
136
+ }
137
+ let target = null;
138
+ try {
139
+ target = this.deps.targets.next();
140
+ }
141
+ catch (error) {
142
+ (0, logger_1.logCaught)(this.deps.logger, 'could not pick a target', error);
143
+ }
144
+ if (!target) {
145
+ this.deps.logger.warn('no doomscroll targets configured; restoring agent window');
146
+ await this.restoreAgentWindow();
147
+ return;
148
+ }
149
+ let browserWindow = null;
150
+ try {
151
+ browserWindow = await this.deps.windows.openInNewBrowserWindow(target);
152
+ }
153
+ catch (error) {
154
+ (0, logger_1.logCaught)(this.deps.logger, 'could not open doomscroll target', error);
155
+ }
156
+ if (!browserWindow) {
157
+ this.deps.logger.warn('browser window was not found; restoring agent window');
158
+ await this.restoreAgentWindow();
159
+ return;
160
+ }
161
+ this.browserWindow = browserWindow;
162
+ this.target = target;
163
+ this.doomStartedAtMs = this.now();
164
+ this.notify();
165
+ this.deps.logger.info(`doomscroll started: ${target} (browser ${browserWindow.processName} ${browserWindow.id})`);
166
+ const capSeconds = Math.max(0, this.deps.config.maxDoomscrollSeconds);
167
+ if (capSeconds > 0) {
168
+ this.capTimer = this.scheduler.setTimer(() => {
169
+ this.capTimer = null;
170
+ this.deps.logger.warn(`max doomscroll time reached (${capSeconds}s)`);
171
+ void this.forceReturn('cap');
172
+ }, capSeconds * 1000);
173
+ }
174
+ }
175
+ async endSession(reason) {
176
+ const finishedAtMs = this.now();
177
+ this.clearTimers();
178
+ const wasDoomscrolling = this.doomStartedAtMs !== null;
179
+ const durationMs = Math.max(0, finishedAtMs - this.startedAtMs);
180
+ const doomscrollMs = wasDoomscrolling
181
+ ? Math.max(0, finishedAtMs - this.doomStartedAtMs)
182
+ : 0;
183
+ const agentWindow = this.agentWindow;
184
+ const browserWindow = this.browserWindow;
185
+ const target = this.target;
186
+ this.currentState = 'done';
187
+ this.notify();
188
+ if (wasDoomscrolling) {
189
+ if (browserWindow) {
190
+ try {
191
+ await this.deps.windows.minimizeWindow(browserWindow);
192
+ this.deps.logger.info('minimized doomscroll browser window');
193
+ }
194
+ catch (error) {
195
+ (0, logger_1.logCaught)(this.deps.logger, 'could not minimize browser window', error);
196
+ }
197
+ }
198
+ if (agentWindow) {
199
+ try {
200
+ const focused = await this.deps.windows.restoreAndFocusWindow(agentWindow);
201
+ if (focused) {
202
+ this.deps.logger.info(`restored agent window: "${agentWindow.title}"`);
203
+ }
204
+ else {
205
+ this.deps.logger.warn('window restore ran but focus was not confirmed');
206
+ }
207
+ }
208
+ catch (error) {
209
+ (0, logger_1.logCaught)(this.deps.logger, 'could not restore agent window', error);
210
+ }
211
+ }
212
+ try {
213
+ this.deps.sound.play();
214
+ }
215
+ catch (error) {
216
+ (0, logger_1.logCaught)(this.deps.logger, 'could not play notification sound', error);
217
+ }
218
+ }
219
+ try {
220
+ this.deps.stats.record({
221
+ type: 'session',
222
+ startedAt: new Date(this.startedAtMs).toISOString(),
223
+ finishedAt: new Date(finishedAtMs).toISOString(),
224
+ durationMs,
225
+ doomscrollMs,
226
+ target,
227
+ end: reason,
228
+ });
229
+ }
230
+ catch (error) {
231
+ (0, logger_1.logCaught)(this.deps.logger, 'could not record session stats', error);
232
+ }
233
+ this.deps.logger.info(`session ended (${reason}) duration=${(durationMs / 1000).toFixed(1)}s doomscroll=${(doomscrollMs / 1000).toFixed(1)}s -> DONE`);
234
+ this.doomStartedAtMs = null;
235
+ this.agentWindow = null;
236
+ this.browserWindow = null;
237
+ this.target = null;
238
+ }
239
+ async restoreAgentWindow() {
240
+ if (!this.agentWindow)
241
+ return;
242
+ try {
243
+ await this.deps.windows.restoreAndFocusWindow(this.agentWindow);
244
+ }
245
+ catch (error) {
246
+ (0, logger_1.logCaught)(this.deps.logger, 'could not restore agent window', error);
247
+ }
248
+ }
249
+ clearTimers() {
250
+ if (this.delayTimer !== null) {
251
+ this.scheduler.clearTimer(this.delayTimer);
252
+ this.delayTimer = null;
253
+ }
254
+ if (this.capTimer !== null) {
255
+ this.scheduler.clearTimer(this.capTimer);
256
+ this.capTimer = null;
257
+ }
258
+ }
259
+ notify() {
260
+ try {
261
+ this.deps.onStateChange?.(this.currentState, {
262
+ target: this.target,
263
+ doomscrolling: this.doomStartedAtMs !== null,
264
+ });
265
+ }
266
+ catch (error) {
267
+ this.deps.logger.debug(`state change callback failed: ${(0, errors_1.errorMessage)(error)}`);
268
+ }
269
+ }
270
+ }
271
+ exports.DoomscrollerStateMachine = DoomscrollerStateMachine;
272
+ //# sourceMappingURL=state-machine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-machine.js","sourceRoot":"","sources":["../../src/core/state-machine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SessionLogger = void 0;
7
+ exports.readSessions = readSessions;
8
+ exports.aggregateByDay = aggregateByDay;
9
+ exports.formatDuration = formatDuration;
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ class SessionLogger {
13
+ filePath;
14
+ constructor(filePath) {
15
+ this.filePath = filePath;
16
+ }
17
+ record(record) {
18
+ try {
19
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(this.filePath), { recursive: true });
20
+ node_fs_1.default.appendFileSync(this.filePath, `${JSON.stringify(record)}\n`, 'utf8');
21
+ }
22
+ catch {
23
+ // Never let session logging interfere with the agent.
24
+ }
25
+ }
26
+ }
27
+ exports.SessionLogger = SessionLogger;
28
+ function readSessions(filePath) {
29
+ let text;
30
+ try {
31
+ text = node_fs_1.default.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '');
32
+ }
33
+ catch {
34
+ return [];
35
+ }
36
+ const records = [];
37
+ for (const line of text.split(/\r?\n/)) {
38
+ const trimmed = line.trim();
39
+ if (!trimmed)
40
+ continue;
41
+ try {
42
+ const parsed = JSON.parse(trimmed);
43
+ if (parsed &&
44
+ parsed.type === 'session' &&
45
+ typeof parsed.startedAt === 'string' &&
46
+ typeof parsed.finishedAt === 'string' &&
47
+ typeof parsed.durationMs === 'number' &&
48
+ typeof parsed.doomscrollMs === 'number' &&
49
+ (parsed.end === 'finished' || parsed.end === 'hotkey' || parsed.end === 'cap')) {
50
+ records.push({
51
+ type: 'session',
52
+ startedAt: parsed.startedAt,
53
+ finishedAt: parsed.finishedAt,
54
+ durationMs: parsed.durationMs,
55
+ doomscrollMs: parsed.doomscrollMs,
56
+ target: typeof parsed.target === 'string' ? parsed.target : null,
57
+ end: parsed.end,
58
+ });
59
+ }
60
+ }
61
+ catch {
62
+ // Ignore corrupt lines.
63
+ }
64
+ }
65
+ return records;
66
+ }
67
+ function localDateKey(date) {
68
+ const year = date.getFullYear();
69
+ const month = `${date.getMonth() + 1}`.padStart(2, '0');
70
+ const day = `${date.getDate()}`.padStart(2, '0');
71
+ return `${year}-${month}-${day}`;
72
+ }
73
+ function aggregateByDay(records, options = {}) {
74
+ const now = options.now ?? new Date();
75
+ const days = options.days === undefined ? 14 : options.days;
76
+ let cutoff = null;
77
+ if (days !== null) {
78
+ const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());
79
+ start.setDate(start.getDate() - Math.max(0, days - 1));
80
+ cutoff = start.getTime();
81
+ }
82
+ const map = new Map();
83
+ for (const record of records) {
84
+ const finished = new Date(record.finishedAt);
85
+ if (Number.isNaN(finished.getTime()))
86
+ continue;
87
+ if (cutoff !== null && finished.getTime() < cutoff)
88
+ continue;
89
+ const key = localDateKey(finished);
90
+ const current = map.get(key) ?? { date: key, sessions: 0, doomscrollMs: 0, durationMs: 0 };
91
+ current.sessions += 1;
92
+ current.doomscrollMs += Math.max(0, record.doomscrollMs);
93
+ current.durationMs += Math.max(0, record.durationMs);
94
+ map.set(key, current);
95
+ }
96
+ return [...map.values()].sort((a, b) => a.date.localeCompare(b.date));
97
+ }
98
+ function formatDuration(ms) {
99
+ const totalSeconds = Math.max(0, Math.round(ms / 1000));
100
+ const hours = Math.floor(totalSeconds / 3600);
101
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
102
+ const seconds = totalSeconds % 60;
103
+ if (hours > 0)
104
+ return `${hours}h ${minutes}m ${seconds}s`;
105
+ if (minutes > 0)
106
+ return `${minutes}m ${seconds}s`;
107
+ return `${seconds}s`;
108
+ }
109
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/core/stats.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TargetRotator = void 0;
4
+ /** Cycles through the configured targets, one per doomscroll session. */
5
+ class TargetRotator {
6
+ targets;
7
+ index = 0;
8
+ constructor(targets) {
9
+ this.targets = targets;
10
+ }
11
+ setTargets(targets) {
12
+ this.targets = targets;
13
+ this.index = 0;
14
+ }
15
+ next() {
16
+ if (this.targets.length === 0)
17
+ return null;
18
+ const target = this.targets[this.index % this.targets.length];
19
+ this.index = (this.index + 1) % this.targets.length;
20
+ return target;
21
+ }
22
+ get position() {
23
+ return this.index;
24
+ }
25
+ }
26
+ exports.TargetRotator = TargetRotator;
27
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../../src/core/targets.ts"],"names":[],"mappings":";;;AAEA,yEAAyE;AACzE,MAAa,aAAa;IAGJ;IAFZ,KAAK,GAAG,CAAC,CAAC;IAElB,YAAoB,OAA0B;QAA1B,YAAO,GAAP,OAAO,CAAmB;IAAG,CAAC;IAElD,UAAU,CAAC,OAA0B;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QACpD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AApBD,sCAoBC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AGENT_FINISHED = exports.AGENT_STARTED = void 0;
4
+ exports.AGENT_STARTED = 'agent:started';
5
+ exports.AGENT_FINISHED = 'agent:finished';
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":";;;AAAa,QAAA,aAAa,GAAG,eAAwB,CAAC;AACzC,QAAA,cAAc,GAAG,gBAAyB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const cli_1 = require("./cli");
5
+ (0, cli_1.main)(process.argv.slice(2))
6
+ .then((code) => {
7
+ // A null code means the daemon is running and should stay alive.
8
+ if (code !== null)
9
+ process.exit(code);
10
+ })
11
+ .catch(() => {
12
+ // Never break an agent hook because of a CLI failure.
13
+ process.exit(0);
14
+ });
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,+BAA6B;AAE7B,IAAA,UAAI,EAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACxB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;IACb,iEAAiE;IACjE,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC,CAAC;KACD,KAAK,CAAC,GAAG,EAAE;IACV,sDAAsD;IACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.errorMessage = errorMessage;
4
+ function errorMessage(error) {
5
+ if (error instanceof Error)
6
+ return error.message;
7
+ if (typeof error === 'string')
8
+ return error;
9
+ try {
10
+ return JSON.stringify(error);
11
+ }
12
+ catch {
13
+ return String(error);
14
+ }
15
+ }
16
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/util/errors.ts"],"names":[],"mappings":";;AAAA,oCAQC;AARD,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.expandHome = expandHome;
7
+ exports.doomscrollerHome = doomscrollerHome;
8
+ exports.configFilePath = configFilePath;
9
+ exports.stateDirectory = stateDirectory;
10
+ exports.defaultLogPath = defaultLogPath;
11
+ exports.defaultSessionLogPath = defaultSessionLogPath;
12
+ exports.claudeSettingsPath = claudeSettingsPath;
13
+ exports.commandCodeSettingsPath = commandCodeSettingsPath;
14
+ exports.packageRoot = packageRoot;
15
+ exports.scriptsDirectory = scriptsDirectory;
16
+ exports.scriptPath = scriptPath;
17
+ exports.cliEntryPath = cliEntryPath;
18
+ const node_os_1 = __importDefault(require("node:os"));
19
+ const node_path_1 = __importDefault(require("node:path"));
20
+ function expandHome(input) {
21
+ if (input === '~')
22
+ return node_os_1.default.homedir();
23
+ if (input.startsWith('~/') || input.startsWith('~\\')) {
24
+ return node_path_1.default.join(node_os_1.default.homedir(), input.slice(2));
25
+ }
26
+ return input;
27
+ }
28
+ function doomscrollerHome() {
29
+ const override = process.env.DOOMSCROLLER_HOME;
30
+ if (override)
31
+ return node_path_1.default.resolve(expandHome(override));
32
+ return node_os_1.default.homedir();
33
+ }
34
+ function configFilePath() {
35
+ const override = process.env.DOOMSCROLLER_CONFIG;
36
+ if (override)
37
+ return node_path_1.default.resolve(expandHome(override));
38
+ return node_path_1.default.join(doomscrollerHome(), '.doomscroller.json');
39
+ }
40
+ function stateDirectory() {
41
+ return node_path_1.default.join(doomscrollerHome(), '.doomscroller');
42
+ }
43
+ function defaultLogPath() {
44
+ return node_path_1.default.join(stateDirectory(), 'doomscroller.log');
45
+ }
46
+ function defaultSessionLogPath() {
47
+ return node_path_1.default.join(stateDirectory(), 'sessions.jsonl');
48
+ }
49
+ function claudeSettingsPath() {
50
+ const base = process.env.CLAUDE_CONFIG_DIR
51
+ ? node_path_1.default.resolve(expandHome(process.env.CLAUDE_CONFIG_DIR))
52
+ : node_path_1.default.join(node_os_1.default.homedir(), '.claude');
53
+ return node_path_1.default.join(base, 'settings.json');
54
+ }
55
+ function commandCodeSettingsPath() {
56
+ const base = process.env.COMMANDCODE_CONFIG_DIR
57
+ ? node_path_1.default.resolve(expandHome(process.env.COMMANDCODE_CONFIG_DIR))
58
+ : node_path_1.default.join(node_os_1.default.homedir(), '.commandcode');
59
+ return node_path_1.default.join(base, 'settings.json');
60
+ }
61
+ function packageRoot() {
62
+ // dist/util -> package root, or src/util -> package root.
63
+ return node_path_1.default.resolve(__dirname, '..', '..');
64
+ }
65
+ function scriptsDirectory() {
66
+ return node_path_1.default.join(packageRoot(), 'scripts');
67
+ }
68
+ function scriptPath(name) {
69
+ return node_path_1.default.join(scriptsDirectory(), name);
70
+ }
71
+ function cliEntryPath() {
72
+ const arg = process.argv[1];
73
+ if (arg && /\.(?:[cm]?js|ts)$/i.test(arg))
74
+ return node_path_1.default.resolve(arg);
75
+ return node_path_1.default.join(packageRoot(), 'dist', 'index.js');
76
+ }
77
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/util/paths.ts"],"names":[],"mappings":"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"}