freeturtle 0.1.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 (135) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +392 -0
  3. package/dist/bin/freeturtle.d.ts +2 -0
  4. package/dist/bin/freeturtle.js +119 -0
  5. package/dist/bin/freeturtle.js.map +1 -0
  6. package/dist/src/approval.d.ts +38 -0
  7. package/dist/src/approval.js +140 -0
  8. package/dist/src/approval.js.map +1 -0
  9. package/dist/src/audit.d.ts +33 -0
  10. package/dist/src/audit.js +36 -0
  11. package/dist/src/audit.js.map +1 -0
  12. package/dist/src/channels/telegram.d.ts +10 -0
  13. package/dist/src/channels/telegram.js +41 -0
  14. package/dist/src/channels/telegram.js.map +1 -0
  15. package/dist/src/channels/terminal.d.ts +9 -0
  16. package/dist/src/channels/terminal.js +52 -0
  17. package/dist/src/channels/terminal.js.map +1 -0
  18. package/dist/src/channels/types.d.ts +6 -0
  19. package/dist/src/channels/types.js +2 -0
  20. package/dist/src/channels/types.js.map +1 -0
  21. package/dist/src/cli/approvals.d.ts +3 -0
  22. package/dist/src/cli/approvals.js +33 -0
  23. package/dist/src/cli/approvals.js.map +1 -0
  24. package/dist/src/cli/connect-farcaster.d.ts +5 -0
  25. package/dist/src/cli/connect-farcaster.js +265 -0
  26. package/dist/src/cli/connect-farcaster.js.map +1 -0
  27. package/dist/src/cli/connection-tests.d.ts +16 -0
  28. package/dist/src/cli/connection-tests.js +65 -0
  29. package/dist/src/cli/connection-tests.js.map +1 -0
  30. package/dist/src/cli/init.d.ts +1 -0
  31. package/dist/src/cli/init.js +729 -0
  32. package/dist/src/cli/init.js.map +1 -0
  33. package/dist/src/cli/install-service.d.ts +1 -0
  34. package/dist/src/cli/install-service.js +57 -0
  35. package/dist/src/cli/install-service.js.map +1 -0
  36. package/dist/src/cli/intake.d.ts +23 -0
  37. package/dist/src/cli/intake.js +68 -0
  38. package/dist/src/cli/intake.js.map +1 -0
  39. package/dist/src/cli/send.d.ts +1 -0
  40. package/dist/src/cli/send.js +16 -0
  41. package/dist/src/cli/send.js.map +1 -0
  42. package/dist/src/cli/start.d.ts +3 -0
  43. package/dist/src/cli/start.js +25 -0
  44. package/dist/src/cli/start.js.map +1 -0
  45. package/dist/src/cli/status.d.ts +2 -0
  46. package/dist/src/cli/status.js +54 -0
  47. package/dist/src/cli/status.js.map +1 -0
  48. package/dist/src/cli/update.d.ts +1 -0
  49. package/dist/src/cli/update.js +39 -0
  50. package/dist/src/cli/update.js.map +1 -0
  51. package/dist/src/config.d.ts +31 -0
  52. package/dist/src/config.js +93 -0
  53. package/dist/src/config.js.map +1 -0
  54. package/dist/src/daemon.d.ts +18 -0
  55. package/dist/src/daemon.js +272 -0
  56. package/dist/src/daemon.js.map +1 -0
  57. package/dist/src/heartbeat.d.ts +17 -0
  58. package/dist/src/heartbeat.js +60 -0
  59. package/dist/src/heartbeat.js.map +1 -0
  60. package/dist/src/llm.d.ts +29 -0
  61. package/dist/src/llm.js +225 -0
  62. package/dist/src/llm.js.map +1 -0
  63. package/dist/src/logger.d.ts +8 -0
  64. package/dist/src/logger.js +45 -0
  65. package/dist/src/logger.js.map +1 -0
  66. package/dist/src/memory.d.ts +3 -0
  67. package/dist/src/memory.js +36 -0
  68. package/dist/src/memory.js.map +1 -0
  69. package/dist/src/modules/database/client.d.ts +18 -0
  70. package/dist/src/modules/database/client.js +50 -0
  71. package/dist/src/modules/database/client.js.map +1 -0
  72. package/dist/src/modules/database/index.d.ts +9 -0
  73. package/dist/src/modules/database/index.js +32 -0
  74. package/dist/src/modules/database/index.js.map +1 -0
  75. package/dist/src/modules/database/tools.d.ts +2 -0
  76. package/dist/src/modules/database/tools.js +26 -0
  77. package/dist/src/modules/database/tools.js.map +1 -0
  78. package/dist/src/modules/farcaster/client.d.ts +43 -0
  79. package/dist/src/modules/farcaster/client.js +87 -0
  80. package/dist/src/modules/farcaster/client.js.map +1 -0
  81. package/dist/src/modules/farcaster/index.d.ts +14 -0
  82. package/dist/src/modules/farcaster/index.js +71 -0
  83. package/dist/src/modules/farcaster/index.js.map +1 -0
  84. package/dist/src/modules/farcaster/tools.d.ts +2 -0
  85. package/dist/src/modules/farcaster/tools.js +90 -0
  86. package/dist/src/modules/farcaster/tools.js.map +1 -0
  87. package/dist/src/modules/github/client.d.ts +21 -0
  88. package/dist/src/modules/github/client.js +80 -0
  89. package/dist/src/modules/github/client.js.map +1 -0
  90. package/dist/src/modules/github/index.d.ts +13 -0
  91. package/dist/src/modules/github/index.js +45 -0
  92. package/dist/src/modules/github/index.js.map +1 -0
  93. package/dist/src/modules/github/tools.d.ts +2 -0
  94. package/dist/src/modules/github/tools.js +74 -0
  95. package/dist/src/modules/github/tools.js.map +1 -0
  96. package/dist/src/modules/loader.d.ts +5 -0
  97. package/dist/src/modules/loader.js +35 -0
  98. package/dist/src/modules/loader.js.map +1 -0
  99. package/dist/src/modules/onchain/client.d.ts +8 -0
  100. package/dist/src/modules/onchain/client.js +46 -0
  101. package/dist/src/modules/onchain/client.js.map +1 -0
  102. package/dist/src/modules/onchain/index.d.ts +13 -0
  103. package/dist/src/modules/onchain/index.js +40 -0
  104. package/dist/src/modules/onchain/index.js.map +1 -0
  105. package/dist/src/modules/onchain/tools.d.ts +2 -0
  106. package/dist/src/modules/onchain/tools.js +61 -0
  107. package/dist/src/modules/onchain/tools.js.map +1 -0
  108. package/dist/src/modules/types.d.ts +24 -0
  109. package/dist/src/modules/types.js +2 -0
  110. package/dist/src/modules/types.js.map +1 -0
  111. package/dist/src/modules/xmtp/index.d.ts +8 -0
  112. package/dist/src/modules/xmtp/index.js +14 -0
  113. package/dist/src/modules/xmtp/index.js.map +1 -0
  114. package/dist/src/policy.d.ts +45 -0
  115. package/dist/src/policy.js +164 -0
  116. package/dist/src/policy.js.map +1 -0
  117. package/dist/src/redaction.d.ts +13 -0
  118. package/dist/src/redaction.js +75 -0
  119. package/dist/src/redaction.js.map +1 -0
  120. package/dist/src/reliability.d.ts +16 -0
  121. package/dist/src/reliability.js +124 -0
  122. package/dist/src/reliability.js.map +1 -0
  123. package/dist/src/runner.d.ts +37 -0
  124. package/dist/src/runner.js +257 -0
  125. package/dist/src/runner.js.map +1 -0
  126. package/dist/src/scheduler.d.ts +22 -0
  127. package/dist/src/scheduler.js +61 -0
  128. package/dist/src/scheduler.js.map +1 -0
  129. package/dist/src/setup.d.ts +8 -0
  130. package/dist/src/setup.js +179 -0
  131. package/dist/src/setup.js.map +1 -0
  132. package/dist/src/soul.d.ts +1 -0
  133. package/dist/src/soul.js +15 -0
  134. package/dist/src/soul.js.map +1 -0
  135. package/package.json +56 -0
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { Command } from "commander";
5
+ import { runInit } from "../src/cli/init.js";
6
+ import { runStart } from "../src/cli/start.js";
7
+ import { runStatus } from "../src/cli/status.js";
8
+ import { runSend } from "../src/cli/send.js";
9
+ import { runSetup } from "../src/setup.js";
10
+ import { connectFarcaster } from "../src/cli/connect-farcaster.js";
11
+ import { runInstallService } from "../src/cli/install-service.js";
12
+ import { runUpdate } from "../src/cli/update.js";
13
+ import { runApprove, runReject, runListApprovals, } from "../src/cli/approvals.js";
14
+ const DEFAULT_DIR = join(homedir(), ".freeturtle");
15
+ const program = new Command();
16
+ program
17
+ .name("freeturtle")
18
+ .description("An open-source framework for deploying autonomous AI CEOs that run onchain businesses.")
19
+ .version("0.1.0");
20
+ program
21
+ .command("hello")
22
+ .description("Verify the CLI is working")
23
+ .action(() => {
24
+ console.log(" \x1b[38;2;94;255;164m _____ ____\x1b[0m");
25
+ console.log(" \x1b[38;2;94;255;164m/ \\ | o |\x1b[0m");
26
+ console.log(" \x1b[38;2;94;255;164m| |/ ___\\|\x1b[0m FreeTurtle v0.1");
27
+ console.log(" \x1b[38;2;94;255;164m|_________/\x1b[0m");
28
+ console.log(" \x1b[38;2;94;255;164m|_|_| |_|_|\x1b[0m");
29
+ });
30
+ program
31
+ .command("init")
32
+ .description("Set up a new AI CEO")
33
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
34
+ .action(async (opts) => {
35
+ await runInit(opts.dir);
36
+ });
37
+ program
38
+ .command("setup")
39
+ .description("Configure your LLM provider and API key")
40
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
41
+ .action(async (opts) => {
42
+ await runSetup(opts.dir);
43
+ });
44
+ program
45
+ .command("start")
46
+ .description("Start the FreeTurtle daemon")
47
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
48
+ .option("--chat", "Open interactive terminal chat", false)
49
+ .action(async (opts) => {
50
+ await runStart(opts.dir, { chat: opts.chat });
51
+ });
52
+ program
53
+ .command("status")
54
+ .description("Show daemon status")
55
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
56
+ .action(async (opts) => {
57
+ try {
58
+ await runStatus(opts.dir);
59
+ }
60
+ catch (err) {
61
+ if (err instanceof Error)
62
+ console.error(err.message);
63
+ process.exit(1);
64
+ }
65
+ });
66
+ program
67
+ .command("send <message>")
68
+ .description("Send a message to the running CEO")
69
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
70
+ .action(async (message, opts) => {
71
+ await runSend(opts.dir, message);
72
+ });
73
+ program
74
+ .command("update")
75
+ .description("Update FreeTurtle to the latest version")
76
+ .action(async () => {
77
+ await runUpdate();
78
+ });
79
+ program
80
+ .command("install-service")
81
+ .description("Install FreeTurtle as a systemd user service (Linux)")
82
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
83
+ .action(async (opts) => {
84
+ await runInstallService(opts.dir);
85
+ });
86
+ program
87
+ .command("approve <id>")
88
+ .description("Approve a pending action")
89
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
90
+ .action(async (id, opts) => {
91
+ await runApprove(opts.dir, id);
92
+ });
93
+ program
94
+ .command("reject <id>")
95
+ .description("Reject a pending action")
96
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
97
+ .option("--reason <reason>", "Rejection reason")
98
+ .action(async (id, opts) => {
99
+ await runReject(opts.dir, id, opts.reason);
100
+ });
101
+ program
102
+ .command("approvals")
103
+ .description("List pending approval requests")
104
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
105
+ .action(async (opts) => {
106
+ await runListApprovals(opts.dir);
107
+ });
108
+ const connect = program
109
+ .command("connect")
110
+ .description("Connect external services");
111
+ connect
112
+ .command("farcaster")
113
+ .description("Set up Farcaster signer with QR code approval")
114
+ .option("--dir <path>", "Workspace directory", DEFAULT_DIR)
115
+ .action(async (opts) => {
116
+ await connectFarcaster(opts.dir);
117
+ });
118
+ program.parse();
119
+ //# sourceMappingURL=freeturtle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freeturtle.js","sourceRoot":"","sources":["../../bin/freeturtle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export type ApprovalStatus = "pending" | "approved" | "rejected" | "expired";
2
+ export interface ApprovalRequest {
3
+ id: string;
4
+ runId: string;
5
+ toolName: string;
6
+ reason: string;
7
+ input: Record<string, unknown>;
8
+ status: ApprovalStatus;
9
+ createdAt: string;
10
+ decidedAt?: string;
11
+ decidedBy?: string;
12
+ rejectReason?: string;
13
+ expiresAt: string;
14
+ }
15
+ export declare class ApprovalManager {
16
+ private dir;
17
+ constructor(dir: string);
18
+ createRequest(opts: {
19
+ runId: string;
20
+ toolName: string;
21
+ reason: string;
22
+ input: Record<string, unknown>;
23
+ timeoutSeconds: number;
24
+ }): Promise<ApprovalRequest>;
25
+ /**
26
+ * Polls the approval file until the status changes from "pending" or the
27
+ * timeout elapses. Returns the final state of the approval request.
28
+ */
29
+ waitForDecision(id: string, timeoutMs: number): Promise<ApprovalRequest>;
30
+ approve(id: string, decidedBy?: string): Promise<ApprovalRequest>;
31
+ reject(id: string, reason?: string, decidedBy?: string): Promise<ApprovalRequest>;
32
+ expire(id: string): Promise<ApprovalRequest>;
33
+ list(status?: ApprovalStatus): Promise<ApprovalRequest[]>;
34
+ get(id: string): Promise<ApprovalRequest | null>;
35
+ private save;
36
+ private load;
37
+ private approvalPath;
38
+ }
@@ -0,0 +1,140 @@
1
+ import { mkdir, readFile, writeFile, readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ const POLL_INTERVAL_MS = 2000;
5
+ export class ApprovalManager {
6
+ dir; // workspace/approvals/
7
+ constructor(dir) {
8
+ this.dir = join(dir, "workspace", "approvals");
9
+ }
10
+ async createRequest(opts) {
11
+ const now = new Date();
12
+ const expiresAt = new Date(now.getTime() + opts.timeoutSeconds * 1000);
13
+ const req = {
14
+ id: randomUUID(),
15
+ runId: opts.runId,
16
+ toolName: opts.toolName,
17
+ reason: opts.reason,
18
+ input: opts.input,
19
+ status: "pending",
20
+ createdAt: now.toISOString(),
21
+ expiresAt: expiresAt.toISOString(),
22
+ };
23
+ await this.save(req);
24
+ return req;
25
+ }
26
+ /**
27
+ * Polls the approval file until the status changes from "pending" or the
28
+ * timeout elapses. Returns the final state of the approval request.
29
+ */
30
+ async waitForDecision(id, timeoutMs) {
31
+ const deadline = Date.now() + timeoutMs;
32
+ while (Date.now() < deadline) {
33
+ const req = await this.load(id);
34
+ if (!req) {
35
+ throw new Error(`Approval request ${id} not found`);
36
+ }
37
+ // Check if expired by time
38
+ if (new Date(req.expiresAt).getTime() <= Date.now() && req.status === "pending") {
39
+ return this.expire(id);
40
+ }
41
+ if (req.status !== "pending") {
42
+ return req;
43
+ }
44
+ // Wait before next poll
45
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
46
+ }
47
+ // Timed out waiting — expire the request
48
+ return this.expire(id);
49
+ }
50
+ async approve(id, decidedBy) {
51
+ const req = await this.load(id);
52
+ if (!req)
53
+ throw new Error(`Approval request ${id} not found`);
54
+ if (req.status !== "pending") {
55
+ throw new Error(`Approval request ${id} is already ${req.status}`);
56
+ }
57
+ req.status = "approved";
58
+ req.decidedAt = new Date().toISOString();
59
+ if (decidedBy)
60
+ req.decidedBy = decidedBy;
61
+ await this.save(req);
62
+ return req;
63
+ }
64
+ async reject(id, reason, decidedBy) {
65
+ const req = await this.load(id);
66
+ if (!req)
67
+ throw new Error(`Approval request ${id} not found`);
68
+ if (req.status !== "pending") {
69
+ throw new Error(`Approval request ${id} is already ${req.status}`);
70
+ }
71
+ req.status = "rejected";
72
+ req.decidedAt = new Date().toISOString();
73
+ if (reason)
74
+ req.rejectReason = reason;
75
+ if (decidedBy)
76
+ req.decidedBy = decidedBy;
77
+ await this.save(req);
78
+ return req;
79
+ }
80
+ async expire(id) {
81
+ const req = await this.load(id);
82
+ if (!req)
83
+ throw new Error(`Approval request ${id} not found`);
84
+ if (req.status !== "pending") {
85
+ // Already decided, just return as-is
86
+ return req;
87
+ }
88
+ req.status = "expired";
89
+ req.decidedAt = new Date().toISOString();
90
+ await this.save(req);
91
+ return req;
92
+ }
93
+ async list(status) {
94
+ await mkdir(this.dir, { recursive: true });
95
+ let files;
96
+ try {
97
+ files = await readdir(this.dir);
98
+ }
99
+ catch {
100
+ return [];
101
+ }
102
+ const results = [];
103
+ for (const file of files) {
104
+ if (!file.endsWith(".json"))
105
+ continue;
106
+ const id = file.replace(".json", "");
107
+ const req = await this.load(id);
108
+ if (!req)
109
+ continue;
110
+ if (status && req.status !== status)
111
+ continue;
112
+ results.push(req);
113
+ }
114
+ // Sort by creation time descending
115
+ results.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
116
+ return results;
117
+ }
118
+ async get(id) {
119
+ return this.load(id);
120
+ }
121
+ async save(req) {
122
+ await mkdir(this.dir, { recursive: true });
123
+ const filePath = this.approvalPath(req.id);
124
+ await writeFile(filePath, JSON.stringify(req, null, 2), "utf-8");
125
+ }
126
+ async load(id) {
127
+ const filePath = this.approvalPath(id);
128
+ try {
129
+ const data = await readFile(filePath, "utf-8");
130
+ return JSON.parse(data);
131
+ }
132
+ catch {
133
+ return null;
134
+ }
135
+ }
136
+ approvalPath(id) {
137
+ return join(this.dir, `${id}.json`);
138
+ }
139
+ }
140
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../../src/approval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export interface AuditToolCall {
2
+ name: string;
3
+ input: Record<string, unknown>;
4
+ output?: string;
5
+ error?: string;
6
+ durationMs: number;
7
+ retries: number;
8
+ approvalId?: string;
9
+ approvalStatus?: string;
10
+ }
11
+ export interface AuditRecord {
12
+ runId: string;
13
+ taskName: string;
14
+ startedAt: string;
15
+ completedAt: string;
16
+ status: "success" | "error";
17
+ promptPreview: string;
18
+ toolCalls: AuditToolCall[];
19
+ totalDurationMs: number;
20
+ error?: string;
21
+ }
22
+ export declare class AuditLogger {
23
+ private dir;
24
+ constructor(dir: string);
25
+ /**
26
+ * Writes an audit record to workspace/audit/YYYY-MM-DD/{runId}.json
27
+ */
28
+ writeRecord(record: AuditRecord): Promise<void>;
29
+ /**
30
+ * Extracts YYYY-MM-DD from an ISO date string.
31
+ */
32
+ private extractDate;
33
+ }
@@ -0,0 +1,36 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ export class AuditLogger {
4
+ dir;
5
+ constructor(dir) {
6
+ this.dir = dir;
7
+ }
8
+ /**
9
+ * Writes an audit record to workspace/audit/YYYY-MM-DD/{runId}.json
10
+ */
11
+ async writeRecord(record) {
12
+ // Derive the date folder from completedAt (or startedAt as fallback)
13
+ const dateStr = this.extractDate(record.completedAt || record.startedAt);
14
+ const dayDir = join(this.dir, "workspace", "audit", dateStr);
15
+ await mkdir(dayDir, { recursive: true });
16
+ const filePath = join(dayDir, `${record.runId}.json`);
17
+ await writeFile(filePath, JSON.stringify(record, null, 2), "utf-8");
18
+ }
19
+ /**
20
+ * Extracts YYYY-MM-DD from an ISO date string.
21
+ */
22
+ extractDate(isoString) {
23
+ try {
24
+ const date = new Date(isoString);
25
+ const year = date.getFullYear();
26
+ const month = String(date.getMonth() + 1).padStart(2, "0");
27
+ const day = String(date.getDate()).padStart(2, "0");
28
+ return `${year}-${month}-${day}`;
29
+ }
30
+ catch {
31
+ // Fallback: try to parse the first 10 chars directly
32
+ return isoString.slice(0, 10);
33
+ }
34
+ }
35
+ }
36
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAyBjC,MAAM,OAAO,WAAW;IACd,GAAG,CAAS;IAEpB,YAAY,GAAW;QACrB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,MAAmB;QACnC,qEAAqE;QACrE,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC;QACzE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAE7D,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,OAAO,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,SAAiB;QACnC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACpD,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;YACrD,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { Channel } from "./types.js";
2
+ export declare class TelegramChannel implements Channel {
3
+ name: string;
4
+ private bot;
5
+ private ownerId;
6
+ constructor(token: string, ownerId: number);
7
+ start(onMessage: (text: string) => Promise<string>): Promise<void>;
8
+ send(text: string): Promise<void>;
9
+ stop(): Promise<void>;
10
+ }
@@ -0,0 +1,41 @@
1
+ import { Bot } from "grammy";
2
+ export class TelegramChannel {
3
+ name = "telegram";
4
+ bot;
5
+ ownerId;
6
+ constructor(token, ownerId) {
7
+ this.bot = new Bot(token);
8
+ this.ownerId = ownerId;
9
+ }
10
+ async start(onMessage) {
11
+ this.bot.on("message:text", async (ctx) => {
12
+ const senderId = ctx.from?.id;
13
+ if (senderId !== this.ownerId) {
14
+ await ctx.reply("Sorry, I only talk to my founder.");
15
+ return;
16
+ }
17
+ const text = ctx.message.text;
18
+ try {
19
+ const response = await onMessage(text);
20
+ await ctx.reply(response);
21
+ }
22
+ catch (err) {
23
+ const msg = err instanceof Error ? err.message : "Unknown error";
24
+ await ctx.reply(`Error: ${msg}`);
25
+ }
26
+ });
27
+ this.bot.catch((err) => {
28
+ console.error(`[telegram] ${err.message}`);
29
+ });
30
+ this.bot.start().catch((err) => {
31
+ console.error(`[telegram] Failed to start: ${err.message}`);
32
+ });
33
+ }
34
+ async send(text) {
35
+ await this.bot.api.sendMessage(this.ownerId, text);
36
+ }
37
+ async stop() {
38
+ await this.bot.stop();
39
+ }
40
+ }
41
+ //# sourceMappingURL=telegram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../../src/channels/telegram.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAG7B,MAAM,OAAO,eAAe;IAC1B,IAAI,GAAG,UAAU,CAAC;IACV,GAAG,CAAM;IACT,OAAO,CAAS;IAExB,YAAY,KAAa,EAAE,OAAe;QACxC,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,SAA4C;QACtD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACxC,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;YAC9B,IAAI,QAAQ,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC9B,MAAM,GAAG,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBACrD,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;gBACvC,MAAM,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;gBACjE,MAAM,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC;YACnC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACrB,OAAO,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YAC7B,OAAO,CAAC,KAAK,CAAC,+BAA+B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY;QACrB,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { Channel } from "./types.js";
2
+ export declare class TerminalChannel implements Channel {
3
+ name: string;
4
+ private rl;
5
+ private processing;
6
+ start(onMessage: (text: string) => Promise<string>): Promise<void>;
7
+ send(text: string): Promise<void>;
8
+ stop(): Promise<void>;
9
+ }
@@ -0,0 +1,52 @@
1
+ import * as readline from "node:readline";
2
+ import { stdin, stdout } from "node:process";
3
+ export class TerminalChannel {
4
+ name = "terminal";
5
+ rl = null;
6
+ processing = false;
7
+ async start(onMessage) {
8
+ this.rl = readline.createInterface({ input: stdin, output: stdout });
9
+ console.log("\n Terminal channel active. Type a message or Ctrl+C to exit.\n");
10
+ const prompt = () => {
11
+ if (!this.rl)
12
+ return;
13
+ this.rl.question("you> ", async (input) => {
14
+ const text = input.trim();
15
+ if (!text) {
16
+ prompt();
17
+ return;
18
+ }
19
+ this.processing = true;
20
+ try {
21
+ const response = await onMessage(text);
22
+ console.log(`\nceo> ${response}\n`);
23
+ }
24
+ catch (err) {
25
+ const msg = err instanceof Error ? err.message : "Unknown error";
26
+ console.log(`\n[error] ${msg}\n`);
27
+ }
28
+ finally {
29
+ this.processing = false;
30
+ prompt();
31
+ }
32
+ });
33
+ };
34
+ this.rl.on("close", () => {
35
+ if (!this.processing) {
36
+ console.log("\nGoodbye!");
37
+ process.exit(0);
38
+ }
39
+ });
40
+ prompt();
41
+ }
42
+ async send(text) {
43
+ console.log(`\nceo> ${text}\n`);
44
+ }
45
+ async stop() {
46
+ if (this.rl) {
47
+ this.rl.close();
48
+ this.rl = null;
49
+ }
50
+ }
51
+ }
52
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../../src/channels/terminal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,OAAO,eAAe;IAC1B,IAAI,GAAG,UAAU,CAAC;IACV,EAAE,GAA8B,IAAI,CAAC;IACrC,UAAU,GAAG,KAAK,CAAC;IAE3B,KAAK,CAAC,KAAK,CAAC,SAA4C;QACtD,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAErE,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;QAEhF,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,CAAC,IAAI,CAAC,EAAE;gBAAE,OAAO;YACrB,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACxC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC1B,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,MAAM,EAAE,CAAC;oBACT,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;gBACvB,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;oBACvC,OAAO,CAAC,GAAG,CAAC,UAAU,QAAQ,IAAI,CAAC,CAAC;gBACtC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;oBACjE,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;gBACpC,CAAC;wBAAS,CAAC;oBACT,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;oBACxB,MAAM,EAAE,CAAC;gBACX,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACvB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBAC1B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,EAAE,CAAC;IACX,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY;QACrB,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ export interface Channel {
2
+ name: string;
3
+ start(onMessage: (text: string) => Promise<string>): Promise<void>;
4
+ send(text: string): Promise<void>;
5
+ stop(): Promise<void>;
6
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/channels/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export declare function runApprove(dir: string, id: string): Promise<void>;
2
+ export declare function runReject(dir: string, id: string, reason?: string): Promise<void>;
3
+ export declare function runListApprovals(dir: string): Promise<void>;
@@ -0,0 +1,33 @@
1
+ import net from "node:net";
2
+ import { join } from "node:path";
3
+ async function sendIpc(dir, command) {
4
+ const sockPath = join(dir, "daemon.sock");
5
+ return new Promise((resolve, reject) => {
6
+ const client = net.createConnection(sockPath, () => {
7
+ client.write(command);
8
+ client.end();
9
+ });
10
+ let data = "";
11
+ client.on("data", (chunk) => {
12
+ data += chunk.toString();
13
+ });
14
+ client.on("end", () => resolve(data));
15
+ client.on("error", (err) => {
16
+ reject(new Error(`Cannot connect to daemon. Is FreeTurtle running?\n${err.message}`));
17
+ });
18
+ });
19
+ }
20
+ export async function runApprove(dir, id) {
21
+ const response = await sendIpc(dir, `approve ${id}`);
22
+ console.log(response);
23
+ }
24
+ export async function runReject(dir, id, reason) {
25
+ const cmd = reason ? `reject ${id} ${reason}` : `reject ${id}`;
26
+ const response = await sendIpc(dir, cmd);
27
+ console.log(response);
28
+ }
29
+ export async function runListApprovals(dir) {
30
+ const response = await sendIpc(dir, "approvals");
31
+ console.log(response);
32
+ }
33
+ //# sourceMappingURL=approvals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approvals.js","sourceRoot":"","sources":["../../../src/cli/approvals.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,OAAe;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAE1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;YACjD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,MAAM,CACJ,IAAI,KAAK,CACP,qDAAqD,GAAG,CAAC,OAAO,EAAE,CACnE,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,EAAU;IACtD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAW,EACX,EAAU,EACV,MAAe;IAEf,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC;IAC/D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW;IAChD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function connectFarcaster(dir: string): Promise<{
2
+ neynarKey: string;
3
+ signerUuid: string;
4
+ fid: string;
5
+ } | null>;