@kingcrab/pi-imessage 0.0.1

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 (75) hide show
  1. package/README.md +120 -0
  2. package/dist/agent.d.ts +22 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +341 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/cli.d.ts +15 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +179 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/imessage.d.ts +32 -0
  11. package/dist/imessage.d.ts.map +1 -0
  12. package/dist/imessage.js +65 -0
  13. package/dist/imessage.js.map +1 -0
  14. package/dist/logger.d.ts +33 -0
  15. package/dist/logger.d.ts.map +1 -0
  16. package/dist/logger.js +103 -0
  17. package/dist/logger.js.map +1 -0
  18. package/dist/main.d.ts +5 -0
  19. package/dist/main.d.ts.map +1 -0
  20. package/dist/main.js +66 -0
  21. package/dist/main.js.map +1 -0
  22. package/dist/pipeline.d.ts +26 -0
  23. package/dist/pipeline.d.ts.map +1 -0
  24. package/dist/pipeline.js +48 -0
  25. package/dist/pipeline.js.map +1 -0
  26. package/dist/queue.d.ts +16 -0
  27. package/dist/queue.d.ts.map +1 -0
  28. package/dist/queue.js +47 -0
  29. package/dist/queue.js.map +1 -0
  30. package/dist/self-echo.d.ts +19 -0
  31. package/dist/self-echo.d.ts.map +1 -0
  32. package/dist/self-echo.js +54 -0
  33. package/dist/self-echo.js.map +1 -0
  34. package/dist/send.d.ts +17 -0
  35. package/dist/send.d.ts.map +1 -0
  36. package/dist/send.js +107 -0
  37. package/dist/send.js.map +1 -0
  38. package/dist/settings.d.ts +39 -0
  39. package/dist/settings.d.ts.map +1 -0
  40. package/dist/settings.js +74 -0
  41. package/dist/settings.js.map +1 -0
  42. package/dist/store.d.ts +41 -0
  43. package/dist/store.d.ts.map +1 -0
  44. package/dist/store.js +72 -0
  45. package/dist/store.js.map +1 -0
  46. package/dist/tasks.d.ts +88 -0
  47. package/dist/tasks.d.ts.map +1 -0
  48. package/dist/tasks.js +260 -0
  49. package/dist/tasks.js.map +1 -0
  50. package/dist/types.d.ts +77 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +24 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/watch.d.ts +21 -0
  55. package/dist/watch.d.ts.map +1 -0
  56. package/dist/watch.js +137 -0
  57. package/dist/watch.js.map +1 -0
  58. package/dist/web/data.d.ts +11 -0
  59. package/dist/web/data.d.ts.map +1 -0
  60. package/dist/web/data.js +56 -0
  61. package/dist/web/data.js.map +1 -0
  62. package/dist/web/html.d.ts +5 -0
  63. package/dist/web/html.d.ts.map +1 -0
  64. package/dist/web/html.js +16 -0
  65. package/dist/web/html.js.map +1 -0
  66. package/dist/web/index.d.ts +15 -0
  67. package/dist/web/index.d.ts.map +1 -0
  68. package/dist/web/index.js +116 -0
  69. package/dist/web/index.js.map +1 -0
  70. package/dist/web/render.d.ts +5 -0
  71. package/dist/web/render.d.ts.map +1 -0
  72. package/dist/web/render.js +50 -0
  73. package/dist/web/render.js.map +1 -0
  74. package/dist/web/templates/page.eta +85 -0
  75. package/package.json +42 -0
package/dist/cli.js ADDED
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI entry point — handles launchd service management and foreground run.
4
+ *
5
+ * Usage:
6
+ * pi-imessage Run in foreground
7
+ * pi-imessage install Install + start launchd service (auto-starts on boot)
8
+ * pi-imessage uninstall Stop + remove launchd service
9
+ * pi-imessage start Start the service
10
+ * pi-imessage stop Stop the service
11
+ * pi-imessage restart Restart the service
12
+ * pi-imessage logs Tail service logs
13
+ */
14
+ import { execSync, fork } from "node:child_process";
15
+ import { existsSync, mkdirSync, unlinkSync, writeFileSync } from "node:fs";
16
+ import { homedir } from "node:os";
17
+ import { join } from "node:path";
18
+ const LABEL = "com.kingcrab.pi-imessage";
19
+ const PLIST_PATH = join(homedir(), "Library", "LaunchAgents", `${LABEL}.plist`);
20
+ const WORKING_DIR = process.env.WORKING_DIR || join(homedir(), ".pi", "imessage");
21
+ const LOG_DIR = join(WORKING_DIR, "logs");
22
+ const MAIN_JS = join(import.meta.dirname, "main.js");
23
+ function getNodePath() {
24
+ try {
25
+ return execSync("which node", { encoding: "utf-8" }).trim();
26
+ }
27
+ catch {
28
+ return "/usr/local/bin/node";
29
+ }
30
+ }
31
+ function buildPlist() {
32
+ const nodePath = getNodePath();
33
+ const stdoutLog = join(LOG_DIR, "stdout.log");
34
+ const stderrLog = join(LOG_DIR, "stderr.log");
35
+ return `<?xml version="1.0" encoding="UTF-8"?>
36
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
37
+ <plist version="1.0">
38
+ <dict>
39
+ <key>Label</key>
40
+ <string>${LABEL}</string>
41
+ <key>ProgramArguments</key>
42
+ <array>
43
+ <string>${nodePath}</string>
44
+ <string>${MAIN_JS}</string>
45
+ </array>
46
+ <key>RunAtLoad</key>
47
+ <true/>
48
+ <key>KeepAlive</key>
49
+ <true/>
50
+ <key>StandardOutPath</key>
51
+ <string>${stdoutLog}</string>
52
+ <key>StandardErrorPath</key>
53
+ <string>${stderrLog}</string>
54
+ <key>EnvironmentVariables</key>
55
+ <dict>
56
+ <key>PATH</key>
57
+ <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
58
+ <key>WORKING_DIR</key>
59
+ <string>${WORKING_DIR}</string>
60
+ </dict>
61
+ </dict>
62
+ </plist>`;
63
+ }
64
+ function isLoaded() {
65
+ try {
66
+ execSync(`launchctl list ${LABEL}`, { stdio: "pipe" });
67
+ return true;
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }
73
+ function install() {
74
+ mkdirSync(LOG_DIR, { recursive: true });
75
+ writeFileSync(PLIST_PATH, buildPlist(), "utf-8");
76
+ console.log(`[pi-imessage] Wrote ${PLIST_PATH}`);
77
+ if (isLoaded()) {
78
+ execSync(`launchctl unload ${PLIST_PATH}`, { stdio: "inherit" });
79
+ }
80
+ execSync(`launchctl load ${PLIST_PATH}`, { stdio: "inherit" });
81
+ console.log("[pi-imessage] Service installed and started (auto-starts on boot)");
82
+ }
83
+ function uninstall() {
84
+ if (isLoaded()) {
85
+ execSync(`launchctl unload ${PLIST_PATH}`, { stdio: "inherit" });
86
+ console.log("[pi-imessage] Service stopped");
87
+ }
88
+ if (existsSync(PLIST_PATH)) {
89
+ unlinkSync(PLIST_PATH);
90
+ console.log(`[pi-imessage] Removed ${PLIST_PATH}`);
91
+ }
92
+ console.log("[pi-imessage] Service uninstalled");
93
+ }
94
+ function start() {
95
+ if (!existsSync(PLIST_PATH)) {
96
+ console.error("[pi-imessage] Service not installed. Run 'pi-imessage install' first.");
97
+ process.exit(1);
98
+ }
99
+ if (!isLoaded()) {
100
+ execSync(`launchctl load ${PLIST_PATH}`, { stdio: "inherit" });
101
+ }
102
+ execSync(`launchctl start ${LABEL}`, { stdio: "inherit" });
103
+ console.log("[pi-imessage] Service started");
104
+ }
105
+ function stop() {
106
+ if (!isLoaded()) {
107
+ console.log("[pi-imessage] Service is not running");
108
+ return;
109
+ }
110
+ execSync(`launchctl stop ${LABEL}`, { stdio: "inherit" });
111
+ console.log("[pi-imessage] Service stopped");
112
+ }
113
+ function restart() {
114
+ stop();
115
+ start();
116
+ }
117
+ function logs() {
118
+ const stdoutLog = join(LOG_DIR, "stdout.log");
119
+ const stderrLog = join(LOG_DIR, "stderr.log");
120
+ if (!existsSync(stdoutLog) && !existsSync(stderrLog)) {
121
+ console.error("[pi-imessage] No logs found. Is the service installed?");
122
+ process.exit(1);
123
+ }
124
+ console.log("[pi-imessage] Tailing logs (Ctrl+C to stop)…\n");
125
+ const files = [stdoutLog, stderrLog].filter((f) => existsSync(f));
126
+ execSync(`tail -f ${files.join(" ")}`, { stdio: "inherit" });
127
+ }
128
+ function runForeground() {
129
+ // Fork main.js as a child so cli.ts doesn't need to import the full bot.
130
+ const child = fork(MAIN_JS, { stdio: "inherit" });
131
+ child.on("exit", (code) => process.exit(code ?? 0));
132
+ }
133
+ function help() {
134
+ console.log(`Usage: pi-imessage [command]
135
+
136
+ Commands:
137
+ (none) Run in foreground
138
+ install Install + start launchd service (auto-starts on boot)
139
+ uninstall Stop + remove launchd service
140
+ start Start the service
141
+ stop Stop the service
142
+ restart Restart the service
143
+ logs Tail service logs
144
+ help Show this help message`);
145
+ }
146
+ const command = process.argv[2];
147
+ switch (command) {
148
+ case "install":
149
+ install();
150
+ break;
151
+ case "uninstall":
152
+ uninstall();
153
+ break;
154
+ case "start":
155
+ start();
156
+ break;
157
+ case "stop":
158
+ stop();
159
+ break;
160
+ case "restart":
161
+ restart();
162
+ break;
163
+ case "logs":
164
+ logs();
165
+ break;
166
+ case "help":
167
+ case "--help":
168
+ case "-h":
169
+ help();
170
+ break;
171
+ case undefined:
172
+ runForeground();
173
+ break;
174
+ default:
175
+ console.error(`Unknown command: ${command}\n`);
176
+ help();
177
+ process.exit(1);
178
+ }
179
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * iMessage bot — pulls IncomingMessage objects from a queue (fed by the
3
+ * watcher) and runs them through the pipeline (before → start → end).
4
+ *
5
+ * watcher → queue → pipeline.process()
6
+ *
7
+ * Message ordering: every pulled message is immediately dispatched to the
8
+ * pipeline (fire-and-forget). Different chats run concurrently. For the
9
+ * same chat, the agent's steering mode (streamingBehavior: "steer") handles
10
+ * rapid messages: if the agent is mid-run, a new message interrupts it as
11
+ * a steering prompt rather than queuing behind the previous run.
12
+ */
13
+ import type { AgentManager } from "./agent.js";
14
+ import type { DigestLogger } from "./logger.js";
15
+ import type { AsyncQueue } from "./queue.js";
16
+ import type { MessageSender } from "./send.js";
17
+ import type { Settings } from "./settings.js";
18
+ import type { ChatStore } from "./store.js";
19
+ import type { IncomingMessage } from "./types.js";
20
+ export interface IMessageBotConfig {
21
+ queue: AsyncQueue<IncomingMessage>;
22
+ agent: AgentManager;
23
+ sender: MessageSender;
24
+ store: ChatStore;
25
+ getSettings: () => Settings;
26
+ digestLogger: DigestLogger;
27
+ }
28
+ export declare function createIMessageBot(config: IMessageBotConfig): {
29
+ start(): void;
30
+ stop(): void;
31
+ };
32
+ //# sourceMappingURL=imessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imessage.d.ts","sourceRoot":"","sources":["../src/imessage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAc5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC;IACnC,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,MAAM,QAAQ,CAAC;IAC5B,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB;;;EAqD1D"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * iMessage bot — pulls IncomingMessage objects from a queue (fed by the
3
+ * watcher) and runs them through the pipeline (before → start → end).
4
+ *
5
+ * watcher → queue → pipeline.process()
6
+ *
7
+ * Message ordering: every pulled message is immediately dispatched to the
8
+ * pipeline (fire-and-forget). Different chats run concurrently. For the
9
+ * same chat, the agent's steering mode (streamingBehavior: "steer") handles
10
+ * rapid messages: if the agent is mid-run, a new message interrupts it as
11
+ * a steering prompt rather than queuing behind the previous run.
12
+ */
13
+ import { createMessagePipeline } from "./pipeline.js";
14
+ import { QueueClosedError } from "./queue.js";
15
+ import { createSelfEchoFilter } from "./self-echo.js";
16
+ import { createCallAgentTask, createCheckReplyEnabledTask, createCommandHandlerTask, createDownloadImagesTask, createDropSelfEchoTask, createLogIncomingTask, createLogOutgoingTask, createResizeImagesTask, createSendReplyTask, createStoreIncomingTask, createStoreOutgoingTask, } from "./tasks.js";
17
+ export function createIMessageBot(config) {
18
+ const { queue, agent, sender, store, getSettings, digestLogger } = config;
19
+ const echoFilter = createSelfEchoFilter();
20
+ const pipeline = createMessagePipeline();
21
+ // ── Pipeline tasks ─────────────────────────────────────────────────────────
22
+ //
23
+ // before -> start ──┬── yield reply -> end
24
+ // ├── yield reply -> end
25
+ // └── ...done
26
+ // before
27
+ pipeline.before(createLogIncomingTask(digestLogger));
28
+ pipeline.before(createDropSelfEchoTask(echoFilter));
29
+ pipeline.before(createStoreIncomingTask(store));
30
+ pipeline.before(createCheckReplyEnabledTask(getSettings));
31
+ pipeline.before(createDownloadImagesTask());
32
+ pipeline.before(createResizeImagesTask());
33
+ // start
34
+ pipeline.start(createCommandHandlerTask(agent));
35
+ pipeline.start(createCallAgentTask(agent));
36
+ // end
37
+ pipeline.end(createSendReplyTask(echoFilter, sender));
38
+ pipeline.end(createLogOutgoingTask(digestLogger));
39
+ pipeline.end(createStoreOutgoingTask(store));
40
+ return {
41
+ start() {
42
+ async function loop() {
43
+ while (true) {
44
+ const msg = await queue.pull();
45
+ // Fire-and-forget — steering handles same-guid concurrency
46
+ pipeline.process(msg).catch((error) => {
47
+ console.error(`[sid] failed to process message from ${msg.sender}:`, error);
48
+ });
49
+ }
50
+ }
51
+ loop().catch((error) => {
52
+ if (error instanceof QueueClosedError) {
53
+ console.log("[sid] Queue closed, consumer stopped");
54
+ }
55
+ else {
56
+ console.error("[sid] Consumer crashed:", error);
57
+ }
58
+ });
59
+ },
60
+ stop() {
61
+ queue.close();
62
+ },
63
+ };
64
+ }
65
+ //# sourceMappingURL=imessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imessage.js","sourceRoot":"","sources":["../src/imessage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAItD,OAAO,EACN,mBAAmB,EACnB,2BAA2B,EAC3B,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,YAAY,CAAC;AAcpB,MAAM,UAAU,iBAAiB,CAAC,MAAyB;IAC1D,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IAC1E,MAAM,UAAU,GAAG,oBAAoB,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;IAEzC,8EAA8E;IAC9E,EAAE;IACF,6CAA6C;IAC7C,6CAA6C;IAC7C,kCAAkC;IAElC,SAAS;IACT,QAAQ,CAAC,MAAM,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,MAAM,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,MAAM,CAAC,2BAA2B,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC;IAC5C,QAAQ,CAAC,MAAM,CAAC,sBAAsB,EAAE,CAAC,CAAC;IAE1C,QAAQ;IACR,QAAQ,CAAC,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;IAE3C,MAAM;IACN,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,GAAG,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC;IAE7C,OAAO;QACN,KAAK;YACJ,KAAK,UAAU,IAAI;gBAClB,OAAO,IAAI,EAAE,CAAC;oBACb,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;oBAE/B,2DAA2D;oBAC3D,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;wBAC9C,OAAO,CAAC,KAAK,CAAC,wCAAwC,GAAG,CAAC,MAAM,GAAG,EAAE,KAAK,CAAC,CAAC;oBAC7E,CAAC,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC/B,IAAI,KAAK,YAAY,gBAAgB,EAAE,CAAC;oBACvC,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;gBACrD,CAAC;qBAAM,CAAC;oBACP,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;gBACjD,CAAC;YACF,CAAC,CAAC,CAAC;QACJ,CAAC;QACD,IAAI;YACH,KAAK,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * File-based logger with size-based rotation.
3
+ *
4
+ * Two log destinations:
5
+ * app.log — receives ALL console output (log / warn / error / info)
6
+ * diget.log — receives only incoming/outgoing digest lines
7
+ *
8
+ * Rotation strategy:
9
+ * - Rotate when the active file reaches MAX_BYTES (default 10 MB)
10
+ * - Keep up to MAX_FILES rotated copies (default 5)
11
+ * - On rotation: .5 is deleted, .4→.5, …, .1→.2, active→.1, new active created
12
+ */
13
+ export interface AppLogger {
14
+ /** Restore original console methods and close the file stream. */
15
+ close(): void;
16
+ }
17
+ export declare function createAppLogger(workingDir: string, options?: {
18
+ maxBytes?: number;
19
+ maxFiles?: number;
20
+ }): AppLogger;
21
+ export interface DigestLogger {
22
+ /**
23
+ * Write a digest line to diget.log and forward to console.log
24
+ * (which in turn lands in app.log via the app logger patch).
25
+ */
26
+ log(msg: string): void;
27
+ close(): void;
28
+ }
29
+ export declare function createDigestLogger(workingDir: string, options?: {
30
+ maxBytes?: number;
31
+ maxFiles?: number;
32
+ }): DigestLogger;
33
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmEH,MAAM,WAAW,SAAS;IACzB,kEAAkE;IAClE,KAAK,IAAI,IAAI,CAAC;CACd;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,SAAS,CA+BrH;AAID,MAAM,WAAW,YAAY;IAC5B;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,IAAI,IAAI,CAAC;CACd;AAED,wBAAgB,kBAAkB,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GACpD,YAAY,CAkBd"}
package/dist/logger.js ADDED
@@ -0,0 +1,103 @@
1
+ /**
2
+ * File-based logger with size-based rotation.
3
+ *
4
+ * Two log destinations:
5
+ * app.log — receives ALL console output (log / warn / error / info)
6
+ * diget.log — receives only incoming/outgoing digest lines
7
+ *
8
+ * Rotation strategy:
9
+ * - Rotate when the active file reaches MAX_BYTES (default 10 MB)
10
+ * - Keep up to MAX_FILES rotated copies (default 5)
11
+ * - On rotation: .5 is deleted, .4→.5, …, .1→.2, active→.1, new active created
12
+ */
13
+ import { createWriteStream, existsSync, renameSync, statSync } from "node:fs";
14
+ import { join } from "node:path";
15
+ const DEFAULT_MAX_BYTES = 10 * 1024 * 1024; // 10 MB
16
+ const DEFAULT_MAX_FILES = 5;
17
+ // ── Rotating file writer ──────────────────────────────────────────────────────
18
+ class RotatingFileWriter {
19
+ filePath;
20
+ maxBytes;
21
+ maxFiles;
22
+ stream;
23
+ currentSize;
24
+ constructor(filePath, maxBytes, maxFiles) {
25
+ this.filePath = filePath;
26
+ this.maxBytes = maxBytes;
27
+ this.maxFiles = maxFiles;
28
+ this.currentSize = existsSync(filePath) ? statSync(filePath).size : 0;
29
+ this.stream = createWriteStream(filePath, { flags: "a" });
30
+ }
31
+ write(line) {
32
+ const byteLength = Buffer.byteLength(line, "utf8");
33
+ if (this.currentSize + byteLength > this.maxBytes) {
34
+ this.rotate();
35
+ }
36
+ this.stream.write(line);
37
+ this.currentSize += byteLength;
38
+ }
39
+ rotate() {
40
+ this.stream.end();
41
+ // Shift rotated files: .maxFiles deleted, …, .1 → .2, active → .1
42
+ for (let index = this.maxFiles - 1; index >= 1; index--) {
43
+ const from = `${this.filePath}.${index}`;
44
+ const to = `${this.filePath}.${index + 1}`;
45
+ if (existsSync(from))
46
+ renameSync(from, to);
47
+ }
48
+ if (existsSync(this.filePath)) {
49
+ renameSync(this.filePath, `${this.filePath}.1`);
50
+ }
51
+ this.stream = createWriteStream(this.filePath, { flags: "a" });
52
+ this.currentSize = 0;
53
+ }
54
+ close() {
55
+ this.stream.end();
56
+ }
57
+ }
58
+ // ── Timestamp helper ──────────────────────────────────────────────────────────
59
+ function timestamp() {
60
+ return new Date().toISOString();
61
+ }
62
+ function formatLine(args) {
63
+ return `[${timestamp()}] ${args.map(String).join(" ")}\n`;
64
+ }
65
+ export function createAppLogger(workingDir, options = {}) {
66
+ const writer = new RotatingFileWriter(join(workingDir, "app.log"), options.maxBytes ?? DEFAULT_MAX_BYTES, options.maxFiles ?? DEFAULT_MAX_FILES);
67
+ const originalLog = console.log.bind(console);
68
+ const originalWarn = console.warn.bind(console);
69
+ const originalError = console.error.bind(console);
70
+ const originalInfo = console.info.bind(console);
71
+ function writeAndForward(original, args) {
72
+ writer.write(formatLine(args));
73
+ original(...args);
74
+ }
75
+ console.log = (...args) => writeAndForward(originalLog, args);
76
+ console.warn = (...args) => writeAndForward(originalWarn, args);
77
+ console.error = (...args) => writeAndForward(originalError, args);
78
+ console.info = (...args) => writeAndForward(originalInfo, args);
79
+ return {
80
+ close() {
81
+ console.log = originalLog;
82
+ console.warn = originalWarn;
83
+ console.error = originalError;
84
+ console.info = originalInfo;
85
+ writer.close();
86
+ },
87
+ };
88
+ }
89
+ export function createDigestLogger(workingDir, options = {}) {
90
+ const writer = new RotatingFileWriter(join(workingDir, "diget.log"), options.maxBytes ?? DEFAULT_MAX_BYTES, options.maxFiles ?? DEFAULT_MAX_FILES);
91
+ return {
92
+ log(msg) {
93
+ writer.write(formatLine([msg]));
94
+ // Forward to console.log so the line also appears in app.log
95
+ // (and on stdout for live monitoring).
96
+ console.log(msg);
97
+ },
98
+ close() {
99
+ writer.close();
100
+ },
101
+ };
102
+ }
103
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Sid — iMessage friend entry point.
3
+ */
4
+ import "dotenv/config";
5
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,eAAe,CAAC"}
package/dist/main.js ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Sid — iMessage friend entry point.
3
+ */
4
+ import "dotenv/config";
5
+ import { homedir } from "node:os";
6
+ import { join } from "node:path";
7
+ import { createAgentManager } from "./agent.js";
8
+ import { createIMessageBot } from "./imessage.js";
9
+ import { createAppLogger, createDigestLogger } from "./logger.js";
10
+ import { createAsyncQueue } from "./queue.js";
11
+ import { checkEnvironment, createMessageSender } from "./send.js";
12
+ import { readSettings, writeSettings } from "./settings.js";
13
+ import { createChatStore } from "./store.js";
14
+ import { createWatcher } from "./watch.js";
15
+ import { createWebServer } from "./web/index.js";
16
+ async function main() {
17
+ const webHost = process.env.WEB_HOST || "localhost";
18
+ const webPort = Number.parseInt(process.env.WEB_PORT || "7750", 10);
19
+ const workingDir = process.env.WORKING_DIR || join(homedir(), ".pi", "imessage");
20
+ // Loggers must be created before anything else so all console output is captured.
21
+ const appLogger = createAppLogger(workingDir);
22
+ const digestLogger = createDigestLogger(workingDir);
23
+ // Pre-flight: ensure Messages.app is running and iMessage is active.
24
+ await checkEnvironment();
25
+ const sender = createMessageSender();
26
+ let settings = readSettings(workingDir);
27
+ const getSettings = () => {
28
+ settings = readSettings(workingDir);
29
+ return settings;
30
+ };
31
+ const agent = await createAgentManager({ workingDir });
32
+ const store = createChatStore({ workingDir });
33
+ const queue = createAsyncQueue();
34
+ const watcher = createWatcher({ queue });
35
+ const setSettings = (updated) => {
36
+ settings = updated;
37
+ writeSettings(workingDir, updated);
38
+ };
39
+ const bot = createIMessageBot({ queue, agent, sender, store, getSettings, digestLogger });
40
+ const web = createWebServer({ workingDir, host: webHost, port: webPort, getSettings, setSettings });
41
+ console.log(`[sid] workspace: ${workingDir}`);
42
+ watcher.start();
43
+ bot.start();
44
+ web.start();
45
+ let shuttingDown = false;
46
+ async function shutdown() {
47
+ if (shuttingDown)
48
+ return;
49
+ shuttingDown = true;
50
+ console.log("[sid] Shutting down…");
51
+ watcher.stop();
52
+ bot.stop();
53
+ await web.stop();
54
+ digestLogger.close();
55
+ appLogger.close();
56
+ console.log("[sid] Shutdown complete");
57
+ process.exit(0);
58
+ }
59
+ process.on("SIGINT", () => shutdown());
60
+ process.on("SIGTERM", () => shutdown());
61
+ }
62
+ main().catch((error) => {
63
+ console.error("[sid] Fatal:", error);
64
+ process.exit(1);
65
+ });
66
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Message pipeline — lifecycle-based processing for incoming messages.
3
+ *
4
+ * before (× 1) ──► start ──┬── dispatch reply ──► end (× 1)
5
+ * ├── dispatch reply ──► end (× 1)
6
+ * └── ...done
7
+ *
8
+ * before : Filter & prepare. Runs once. Sets shouldContinue=false to drop.
9
+ * start : Calls agent. Invokes dispatch() for each reply produced.
10
+ * Sets shouldContinue=false on outgoing to skip remaining start tasks.
11
+ * end : Runs once per dispatched reply (send, log, store).
12
+ */
13
+ import type { IncomingMessage, OutgoingMessage } from "./types.js";
14
+ export type BeforeTask = (incoming: IncomingMessage, outgoing: OutgoingMessage) => Promise<OutgoingMessage> | OutgoingMessage;
15
+ /** dispatch() runs the full end phase for one reply. */
16
+ export type DispatchFn = (outgoing: OutgoingMessage) => Promise<void>;
17
+ export type StartTask = (incoming: IncomingMessage, outgoing: OutgoingMessage, dispatch: DispatchFn) => Promise<void>;
18
+ export type EndTask = (incoming: IncomingMessage, outgoing: OutgoingMessage) => Promise<OutgoingMessage> | OutgoingMessage;
19
+ export interface MessagePipeline {
20
+ before(task: BeforeTask): void;
21
+ start(task: StartTask): void;
22
+ end(task: EndTask): void;
23
+ process(incoming: IncomingMessage): Promise<OutgoingMessage>;
24
+ }
25
+ export declare function createMessagePipeline(): MessagePipeline;
26
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGnE,MAAM,MAAM,UAAU,GAAG,CACxB,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,eAAe,KACrB,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;AAEhD,wDAAwD;AACxD,MAAM,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AACtE,MAAM,MAAM,SAAS,GAAG,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEtH,MAAM,MAAM,OAAO,GAAG,CACrB,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,eAAe,KACrB,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC/B,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC7D;AAED,wBAAgB,qBAAqB,IAAI,eAAe,CAoCvD"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Message pipeline — lifecycle-based processing for incoming messages.
3
+ *
4
+ * before (× 1) ──► start ──┬── dispatch reply ──► end (× 1)
5
+ * ├── dispatch reply ──► end (× 1)
6
+ * └── ...done
7
+ *
8
+ * before : Filter & prepare. Runs once. Sets shouldContinue=false to drop.
9
+ * start : Calls agent. Invokes dispatch() for each reply produced.
10
+ * Sets shouldContinue=false on outgoing to skip remaining start tasks.
11
+ * end : Runs once per dispatched reply (send, log, store).
12
+ */
13
+ import { createOutgoingMessage } from "./types.js";
14
+ export function createMessagePipeline() {
15
+ const beforeTasks = [];
16
+ const startTasks = [];
17
+ const endTasks = [];
18
+ async function runEndTasks(incoming, outgoing) {
19
+ let result = outgoing;
20
+ for (const task of endTasks) {
21
+ result = await task(incoming, result);
22
+ if (!result.shouldContinue)
23
+ return;
24
+ }
25
+ }
26
+ async function process(incoming) {
27
+ let outgoing = createOutgoingMessage();
28
+ for (const task of beforeTasks) {
29
+ outgoing = await task(incoming, outgoing);
30
+ if (!outgoing.shouldContinue)
31
+ return outgoing;
32
+ }
33
+ const dispatch = (out) => runEndTasks(incoming, out);
34
+ for (const task of startTasks) {
35
+ await task(incoming, outgoing, dispatch);
36
+ if (!outgoing.shouldContinue)
37
+ break;
38
+ }
39
+ return outgoing;
40
+ }
41
+ return {
42
+ before: (task) => beforeTasks.push(task),
43
+ start: (task) => startTasks.push(task),
44
+ end: (task) => endTasks.push(task),
45
+ process,
46
+ };
47
+ }
48
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAuBnD,MAAM,UAAU,qBAAqB;IACpC,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,MAAM,UAAU,GAAgB,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,KAAK,UAAU,WAAW,CAAC,QAAyB,EAAE,QAAyB;QAC9E,IAAI,MAAM,GAAG,QAAQ,CAAC;QACtB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,cAAc;gBAAE,OAAO;QACpC,CAAC;IACF,CAAC;IAED,KAAK,UAAU,OAAO,CAAC,QAAyB;QAC/C,IAAI,QAAQ,GAAG,qBAAqB,EAAE,CAAC;QAEvC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAChC,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC1C,IAAI,CAAC,QAAQ,CAAC,cAAc;gBAAE,OAAO,QAAQ,CAAC;QAC/C,CAAC;QAED,MAAM,QAAQ,GAAe,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACjE,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC/B,MAAM,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACzC,IAAI,CAAC,QAAQ,CAAC,cAAc;gBAAE,MAAM;QACrC,CAAC;QAED,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,OAAO;QACN,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QACxC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QACtC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAClC,OAAO;KACP,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generic unbounded async queue.
3
+ *
4
+ * push() never blocks; pull() returns a promise that resolves when an item
5
+ * is available. close() rejects all pending waiters and future pull() calls.
6
+ */
7
+ export declare class QueueClosedError extends Error {
8
+ constructor();
9
+ }
10
+ export interface AsyncQueue<T> {
11
+ push(item: T): void;
12
+ pull(): Promise<T>;
13
+ close(): void;
14
+ }
15
+ export declare function createAsyncQueue<T>(): AsyncQueue<T>;
16
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAa,gBAAiB,SAAQ,KAAK;;CAK1C;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IACnB,KAAK,IAAI,IAAI,CAAC;CACd;AAED,wBAAgB,gBAAgB,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAgCnD"}