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,80 @@
1
+ import { Octokit } from "@octokit/rest";
2
+ export class GitHubClient {
3
+ octokit;
4
+ constructor(token) {
5
+ this.octokit = new Octokit({ auth: token });
6
+ }
7
+ parseRepo(repo) {
8
+ const [owner, name] = repo.split("/");
9
+ return { owner, repo: name };
10
+ }
11
+ async createIssue(repo, title, body) {
12
+ const { owner, repo: name } = this.parseRepo(repo);
13
+ const { data } = await this.octokit.issues.create({
14
+ owner,
15
+ repo: name,
16
+ title,
17
+ body,
18
+ });
19
+ return {
20
+ number: data.number,
21
+ title: data.title,
22
+ body: data.body ?? null,
23
+ state: data.state,
24
+ html_url: data.html_url,
25
+ created_at: data.created_at,
26
+ user: data.user?.login ?? "unknown",
27
+ };
28
+ }
29
+ async listIssues(repo, state = "open") {
30
+ const { owner, repo: name } = this.parseRepo(repo);
31
+ const { data } = await this.octokit.issues.listForRepo({
32
+ owner,
33
+ repo: name,
34
+ state,
35
+ per_page: 30,
36
+ });
37
+ return data.map((d) => ({
38
+ number: d.number,
39
+ title: d.title,
40
+ body: d.body ?? null,
41
+ state: d.state,
42
+ html_url: d.html_url,
43
+ created_at: d.created_at,
44
+ user: d.user?.login ?? "unknown",
45
+ }));
46
+ }
47
+ async commitFile(repo, path, content, message, branch) {
48
+ const { owner, repo: name } = this.parseRepo(repo);
49
+ // Check if file exists to get its SHA
50
+ let existingSha;
51
+ try {
52
+ const { data } = await this.octokit.repos.getContent({
53
+ owner,
54
+ repo: name,
55
+ path,
56
+ ...(branch ? { ref: branch } : {}),
57
+ });
58
+ if (!Array.isArray(data) && data.type === "file") {
59
+ existingSha = data.sha;
60
+ }
61
+ }
62
+ catch {
63
+ // File doesn't exist yet
64
+ }
65
+ const { data } = await this.octokit.repos.createOrUpdateFileContents({
66
+ owner,
67
+ repo: name,
68
+ path,
69
+ message,
70
+ content: Buffer.from(content).toString("base64"),
71
+ sha: existingSha,
72
+ ...(branch ? { branch } : {}),
73
+ });
74
+ return {
75
+ sha: data.commit.sha ?? "",
76
+ html_url: data.content?.html_url ?? "",
77
+ };
78
+ }
79
+ }
80
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../src/modules/github/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { FreeTurtleModule, ToolDefinition } from "../types.js";
2
+ import type { PolicyConfig } from "../../policy.js";
3
+ export declare class GitHubModule implements FreeTurtleModule {
4
+ name: string;
5
+ description: string;
6
+ private client;
7
+ private policy?;
8
+ initialize(_config: Record<string, unknown>, env: Record<string, string>, options?: {
9
+ policy?: PolicyConfig;
10
+ }): Promise<void>;
11
+ getTools(): ToolDefinition[];
12
+ executeTool(name: string, input: Record<string, unknown>): Promise<string>;
13
+ }
@@ -0,0 +1,45 @@
1
+ import { assertGithubRepoAllowed, assertGithubPathAllowed, } from "../../policy.js";
2
+ import { withRetry } from "../../reliability.js";
3
+ import { GitHubClient } from "./client.js";
4
+ import { githubTools } from "./tools.js";
5
+ export class GitHubModule {
6
+ name = "github";
7
+ description = "Create issues, list issues, and commit files to GitHub.";
8
+ client;
9
+ policy;
10
+ async initialize(_config, env, options) {
11
+ const token = env.GITHUB_TOKEN;
12
+ if (!token)
13
+ throw new Error("GitHub module requires GITHUB_TOKEN");
14
+ this.client = new GitHubClient(token);
15
+ this.policy = options?.policy;
16
+ }
17
+ getTools() {
18
+ return githubTools;
19
+ }
20
+ async executeTool(name, input) {
21
+ // Enforce repo allowlist on all GitHub operations
22
+ if (input.repo) {
23
+ assertGithubRepoAllowed(this.policy, input.repo);
24
+ }
25
+ switch (name) {
26
+ case "create_issue": {
27
+ const issue = await withRetry(() => this.client.createIssue(input.repo, input.title, input.body));
28
+ return JSON.stringify(issue);
29
+ }
30
+ case "list_issues": {
31
+ const issues = await withRetry(() => this.client.listIssues(input.repo, input.state ?? "open"));
32
+ return JSON.stringify(issues);
33
+ }
34
+ case "commit_file": {
35
+ // Enforce path allowlist for commits
36
+ assertGithubPathAllowed(this.policy, input.path);
37
+ const result = await withRetry(() => this.client.commitFile(input.repo, input.path, input.content, input.message, input.branch));
38
+ return JSON.stringify(result);
39
+ }
40
+ default:
41
+ throw new Error(`Unknown github tool: ${name}`);
42
+ }
43
+ }
44
+ }
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/github/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,OAAO,YAAY;IACvB,IAAI,GAAG,QAAQ,CAAC;IAChB,WAAW,GAAG,yDAAyD,CAAC;IAEhE,MAAM,CAAgB;IACtB,MAAM,CAAgB;IAE9B,KAAK,CAAC,UAAU,CACd,OAAgC,EAChC,GAA2B,EAC3B,OAAmC;QAEnC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC;QAC/B,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACnE,IAAI,CAAC,MAAM,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC;IAChC,CAAC;IAED,QAAQ;QACN,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,WAAW,CACf,IAAY,EACZ,KAA8B;QAE9B,kDAAkD;QAClD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,uBAAuB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAc,CAAC,CAAC;QAC7D,CAAC;QAED,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,cAAc,CAAC,CAAC,CAAC;gBACpB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CACjC,IAAI,CAAC,MAAM,CAAC,WAAW,CACrB,KAAK,CAAC,IAAc,EACpB,KAAK,CAAC,KAAe,EACrB,KAAK,CAAC,IAAc,CACrB,CACF,CAAC;gBACF,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CAClC,IAAI,CAAC,MAAM,CAAC,UAAU,CACpB,KAAK,CAAC,IAAc,EACnB,KAAK,CAAC,KAAmC,IAAI,MAAM,CACrD,CACF,CAAC;gBACF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,qCAAqC;gBACrC,uBAAuB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAc,CAAC,CAAC;gBAE3D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CAClC,IAAI,CAAC,MAAM,CAAC,UAAU,CACpB,KAAK,CAAC,IAAc,EACpB,KAAK,CAAC,IAAc,EACpB,KAAK,CAAC,OAAiB,EACvB,KAAK,CAAC,OAAiB,EACvB,KAAK,CAAC,MAA4B,CACnC,CACF,CAAC;gBACF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;YACD;gBACE,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ import type { ToolDefinition } from "../types.js";
2
+ export declare const githubTools: ToolDefinition[];
@@ -0,0 +1,74 @@
1
+ export const githubTools = [
2
+ {
3
+ name: "create_issue",
4
+ description: "Create a new issue on a GitHub repository.",
5
+ input_schema: {
6
+ type: "object",
7
+ properties: {
8
+ repo: {
9
+ type: "string",
10
+ description: "Repository in owner/name format (e.g. 'tortoise-club/FreeTurtle')",
11
+ },
12
+ title: {
13
+ type: "string",
14
+ description: "Issue title",
15
+ },
16
+ body: {
17
+ type: "string",
18
+ description: "Issue body (markdown supported)",
19
+ },
20
+ },
21
+ required: ["repo", "title", "body"],
22
+ },
23
+ },
24
+ {
25
+ name: "list_issues",
26
+ description: "List issues for a GitHub repository.",
27
+ input_schema: {
28
+ type: "object",
29
+ properties: {
30
+ repo: {
31
+ type: "string",
32
+ description: "Repository in owner/name format",
33
+ },
34
+ state: {
35
+ type: "string",
36
+ enum: ["open", "closed", "all"],
37
+ description: "Filter by state (default: open)",
38
+ },
39
+ },
40
+ required: ["repo"],
41
+ },
42
+ },
43
+ {
44
+ name: "commit_file",
45
+ description: "Create or update a file in a GitHub repository via a commit. Writes to non-main branches are allowed if in scope. Writes to main require founder approval.",
46
+ input_schema: {
47
+ type: "object",
48
+ properties: {
49
+ repo: {
50
+ type: "string",
51
+ description: "Repository in owner/name format",
52
+ },
53
+ path: {
54
+ type: "string",
55
+ description: "File path in the repo (e.g. 'strategy/2026-03-02.md')",
56
+ },
57
+ content: {
58
+ type: "string",
59
+ description: "The file content to write",
60
+ },
61
+ message: {
62
+ type: "string",
63
+ description: "Commit message",
64
+ },
65
+ branch: {
66
+ type: "string",
67
+ description: "Target branch (default: main). Non-main branches do not require approval.",
68
+ },
69
+ },
70
+ required: ["repo", "path", "content", "message"],
71
+ },
72
+ },
73
+ ];
74
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../../src/modules/github/tools.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAqB;IAC3C;QACE,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,4CAA4C;QACzD,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,mEAAmE;iBACjF;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,aAAa;iBAC3B;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,iCAAiC;iBAC/C;aACF;YACD,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;SACpC;KACF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,sCAAsC;QACnD,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,iCAAiC;iBAC/C;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;oBAC/B,WAAW,EAAE,iCAAiC;iBAC/C;aACF;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;SACnB;KACF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,4JAA4J;QAC9J,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,iCAAiC;iBAC/C;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,uDAAuD;iBACrE;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,2BAA2B;iBACzC;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,gBAAgB;iBAC9B;gBACD,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,2EAA2E;iBACzF;aACF;YACD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC;SACjD;KACF;CACF,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { FreeTurtleConfig } from "../config.js";
2
+ import type { PolicyConfig } from "../policy.js";
3
+ import type { FreeTurtleModule } from "./types.js";
4
+ import type { Logger } from "../logger.js";
5
+ export declare function loadModules(config: FreeTurtleConfig, env: Record<string, string>, logger?: Logger, policy?: PolicyConfig): Promise<FreeTurtleModule[]>;
@@ -0,0 +1,35 @@
1
+ import { FarcasterModule } from "./farcaster/index.js";
2
+ import { DatabaseModule } from "./database/index.js";
3
+ import { GitHubModule } from "./github/index.js";
4
+ import { OnchainModule } from "./onchain/index.js";
5
+ import { XmtpModule } from "./xmtp/index.js";
6
+ const MODULE_MAP = {
7
+ farcaster: FarcasterModule,
8
+ database: DatabaseModule,
9
+ github: GitHubModule,
10
+ onchain: OnchainModule,
11
+ xmtp: XmtpModule,
12
+ };
13
+ export async function loadModules(config, env, logger, policy) {
14
+ const modules = [];
15
+ for (const [name, moduleConfig] of Object.entries(config.modules)) {
16
+ if (!moduleConfig.enabled)
17
+ continue;
18
+ const ModuleClass = MODULE_MAP[name];
19
+ if (!ModuleClass) {
20
+ logger?.warn(`Unknown module: ${name} — skipping`);
21
+ continue;
22
+ }
23
+ try {
24
+ const mod = new ModuleClass();
25
+ await mod.initialize(moduleConfig, env, { policy });
26
+ modules.push(mod);
27
+ }
28
+ catch (err) {
29
+ const msg = err instanceof Error ? err.message : "Unknown error";
30
+ logger?.error(`Module "${name}" failed to initialize: ${msg} — skipping`);
31
+ }
32
+ }
33
+ return modules;
34
+ }
35
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/modules/loader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,UAAU,GAA+C;IAC7D,SAAS,EAAE,eAAe;IAC1B,QAAQ,EAAE,cAAc;IACxB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,aAAa;IACtB,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAwB,EACxB,GAA2B,EAC3B,MAAe,EACf,MAAqB;IAErB,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,KAAK,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAClE,IAAI,CAAC,YAAY,CAAC,OAAO;YAAE,SAAS;QAEpC,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,EAAE,IAAI,CAAC,mBAAmB,IAAI,aAAa,CAAC,CAAC;YACnD,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,MAAM,GAAG,CAAC,UAAU,CAClB,YAAkD,EAClD,GAAG,EACH,EAAE,MAAM,EAAE,CACX,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACjE,MAAM,EAAE,KAAK,CAAC,WAAW,IAAI,2BAA2B,GAAG,aAAa,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare class OnchainClient {
2
+ private client;
3
+ private basescanKey?;
4
+ constructor(rpcUrl: string, basescanKey?: string);
5
+ readContract(address: string, abi: unknown[], functionName: string, args?: unknown[]): Promise<unknown>;
6
+ getBalance(address: string): Promise<string>;
7
+ getTransactions(address: string, limit?: number): Promise<Record<string, unknown>[]>;
8
+ }
@@ -0,0 +1,46 @@
1
+ import { createPublicClient, http, formatEther } from "viem";
2
+ import { base } from "viem/chains";
3
+ export class OnchainClient {
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ client;
6
+ basescanKey;
7
+ constructor(rpcUrl, basescanKey) {
8
+ this.client = createPublicClient({
9
+ chain: base,
10
+ transport: http(rpcUrl),
11
+ });
12
+ this.basescanKey = basescanKey;
13
+ }
14
+ async readContract(address, abi, functionName, args) {
15
+ const result = await this.client.readContract({
16
+ address: address,
17
+ abi,
18
+ functionName,
19
+ args: args ?? [],
20
+ });
21
+ return result;
22
+ }
23
+ async getBalance(address) {
24
+ const balance = await this.client.getBalance({
25
+ address: address,
26
+ });
27
+ return formatEther(balance);
28
+ }
29
+ async getTransactions(address, limit = 10) {
30
+ if (!this.basescanKey) {
31
+ return [{ error: "BASESCAN_API_KEY not set, cannot fetch transactions" }];
32
+ }
33
+ const url = `https://api.basescan.org/api?module=account&action=txlist&address=${address}&startblock=0&endblock=99999999&page=1&offset=${limit}&sort=desc&apikey=${this.basescanKey}`;
34
+ const res = await fetch(url);
35
+ const data = (await res.json());
36
+ return (data.result ?? []).map((tx) => ({
37
+ hash: tx.hash,
38
+ from: tx.from,
39
+ to: tx.to,
40
+ value: tx.value,
41
+ timestamp: tx.timeStamp,
42
+ functionName: tx.functionName,
43
+ }));
44
+ }
45
+ }
46
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../src/modules/onchain/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,MAAM,OAAO,aAAa;IACxB,8DAA8D;IACtD,MAAM,CAAM;IACZ,WAAW,CAAU;IAE7B,YAAY,MAAc,EAAE,WAAoB;QAC9C,IAAI,CAAC,MAAM,GAAG,kBAAkB,CAAC;YAC/B,KAAK,EAAE,IAAI;YACX,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;SACxB,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,OAAe,EACf,GAAc,EACd,YAAoB,EACpB,IAAgB;QAEhB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;YAC5C,OAAO,EAAE,OAAwB;YACjC,GAAG;YACH,YAAY;YACZ,IAAI,EAAE,IAAI,IAAI,EAAE;SACjB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAe;QAC9B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;YAC3C,OAAO,EAAE,OAAwB;SAClC,CAAC,CAAC;QACH,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,OAAe,EACf,KAAK,GAAG,EAAE;QAEV,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO,CAAC,EAAE,KAAK,EAAE,qDAAqD,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,GAAG,GAAG,qEAAqE,OAAO,iDAAiD,KAAK,qBAAqB,IAAI,CAAC,WAAW,EAAE,CAAC;QACtL,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAE7B,CAAC;QAEF,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACtC,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,EAAE,EAAE,EAAE,CAAC,EAAE;YACT,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,SAAS,EAAE,EAAE,CAAC,SAAS;YACvB,YAAY,EAAE,EAAE,CAAC,YAAY;SAC9B,CAAC,CAAC,CAAC;IACN,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { FreeTurtleModule, ToolDefinition } from "../types.js";
2
+ import type { PolicyConfig } from "../../policy.js";
3
+ export declare class OnchainModule implements FreeTurtleModule {
4
+ name: string;
5
+ description: string;
6
+ private client;
7
+ private policy?;
8
+ initialize(_config: Record<string, unknown>, env: Record<string, string>, options?: {
9
+ policy?: PolicyConfig;
10
+ }): Promise<void>;
11
+ getTools(): ToolDefinition[];
12
+ executeTool(name: string, input: Record<string, unknown>): Promise<string>;
13
+ }
@@ -0,0 +1,40 @@
1
+ import { assertOnchainScopeAllowed } from "../../policy.js";
2
+ import { withRetry } from "../../reliability.js";
3
+ import { OnchainClient } from "./client.js";
4
+ import { onchainTools } from "./tools.js";
5
+ export class OnchainModule {
6
+ name = "onchain";
7
+ description = "Read smart contracts, balances, and transactions on Base.";
8
+ client;
9
+ policy;
10
+ async initialize(_config, env, options) {
11
+ const rpcUrl = env.RPC_URL;
12
+ if (!rpcUrl)
13
+ throw new Error("Onchain module requires RPC_URL");
14
+ this.client = new OnchainClient(rpcUrl, env.BASESCAN_API_KEY);
15
+ this.policy = options?.policy;
16
+ }
17
+ getTools() {
18
+ return onchainTools;
19
+ }
20
+ async executeTool(name, input) {
21
+ switch (name) {
22
+ case "read_contract": {
23
+ assertOnchainScopeAllowed(this.policy, input.address, input.function_name);
24
+ const result = await withRetry(() => this.client.readContract(input.address, input.abi, input.function_name, input.args));
25
+ return JSON.stringify(result);
26
+ }
27
+ case "get_balance": {
28
+ const balance = await withRetry(() => this.client.getBalance(input.address));
29
+ return `${balance} ETH`;
30
+ }
31
+ case "get_transactions": {
32
+ const txs = await withRetry(() => this.client.getTransactions(input.address, input.limit ?? 10));
33
+ return JSON.stringify(txs);
34
+ }
35
+ default:
36
+ throw new Error(`Unknown onchain tool: ${name}`);
37
+ }
38
+ }
39
+ }
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/onchain/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,OAAO,aAAa;IACxB,IAAI,GAAG,SAAS,CAAC;IACjB,WAAW,GAAG,2DAA2D,CAAC;IAElE,MAAM,CAAiB;IACvB,MAAM,CAAgB;IAE9B,KAAK,CAAC,UAAU,CACd,OAAgC,EAChC,GAA2B,EAC3B,OAAmC;QAEnC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC;IAChC,CAAC;IAED,QAAQ;QACN,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,WAAW,CACf,IAAY,EACZ,KAA8B;QAE9B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,eAAe,CAAC,CAAC,CAAC;gBACrB,yBAAyB,CACvB,IAAI,CAAC,MAAM,EACX,KAAK,CAAC,OAAiB,EACvB,KAAK,CAAC,aAAuB,CAC9B,CAAC;gBACF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CAClC,IAAI,CAAC,MAAM,CAAC,YAAY,CACtB,KAAK,CAAC,OAAiB,EACvB,KAAK,CAAC,GAAgB,EACtB,KAAK,CAAC,aAAuB,EAC7B,KAAK,CAAC,IAA6B,CACpC,CACF,CAAC;gBACF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CACnC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,OAAiB,CAAC,CAChD,CAAC;gBACF,OAAO,GAAG,OAAO,MAAM,CAAC;YAC1B,CAAC;YACD,KAAK,kBAAkB,CAAC,CAAC,CAAC;gBACxB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CAC/B,IAAI,CAAC,MAAM,CAAC,eAAe,CACzB,KAAK,CAAC,OAAiB,EACtB,KAAK,CAAC,KAAgB,IAAI,EAAE,CAC9B,CACF,CAAC;gBACF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC7B,CAAC;YACD;gBACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ import type { ToolDefinition } from "../types.js";
2
+ export declare const onchainTools: ToolDefinition[];
@@ -0,0 +1,61 @@
1
+ export const onchainTools = [
2
+ {
3
+ name: "read_contract",
4
+ description: "Read data from a smart contract on Base. Requires the contract ABI for the function being called.",
5
+ input_schema: {
6
+ type: "object",
7
+ properties: {
8
+ address: {
9
+ type: "string",
10
+ description: "Contract address (0x...)",
11
+ },
12
+ abi: {
13
+ type: "array",
14
+ description: "ABI array containing at least the function definition",
15
+ },
16
+ function_name: {
17
+ type: "string",
18
+ description: "Name of the function to call",
19
+ },
20
+ args: {
21
+ type: "array",
22
+ description: "Function arguments (optional)",
23
+ },
24
+ },
25
+ required: ["address", "abi", "function_name"],
26
+ },
27
+ },
28
+ {
29
+ name: "get_balance",
30
+ description: "Get the ETH balance of an address on Base.",
31
+ input_schema: {
32
+ type: "object",
33
+ properties: {
34
+ address: {
35
+ type: "string",
36
+ description: "Wallet address (0x...)",
37
+ },
38
+ },
39
+ required: ["address"],
40
+ },
41
+ },
42
+ {
43
+ name: "get_transactions",
44
+ description: "Get recent transactions for an address on Base (requires BASESCAN_API_KEY).",
45
+ input_schema: {
46
+ type: "object",
47
+ properties: {
48
+ address: {
49
+ type: "string",
50
+ description: "Wallet address (0x...)",
51
+ },
52
+ limit: {
53
+ type: "number",
54
+ description: "Number of transactions to return (default 10)",
55
+ },
56
+ },
57
+ required: ["address"],
58
+ },
59
+ },
60
+ ];
61
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../../src/modules/onchain/tools.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAqB;IAC5C;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,mGAAmG;QACrG,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,0BAA0B;iBACxC;gBACD,GAAG,EAAE;oBACH,IAAI,EAAE,OAAO;oBACb,WAAW,EAAE,uDAAuD;iBACrE;gBACD,aAAa,EAAE;oBACb,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,8BAA8B;iBAC5C;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,OAAO;oBACb,WAAW,EAAE,+BAA+B;iBAC7C;aACF;YACD,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,eAAe,CAAC;SAC9C;KACF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,4CAA4C;QACzD,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,wBAAwB;iBACtC;aACF;YACD,QAAQ,EAAE,CAAC,SAAS,CAAC;SACtB;KACF;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,6EAA6E;QAC/E,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,wBAAwB;iBACtC;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,+CAA+C;iBAC7D;aACF;YACD,QAAQ,EAAE,CAAC,SAAS,CAAC;SACtB;KACF;CACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface ToolDefinition {
2
+ name: string;
3
+ description: string;
4
+ input_schema: Record<string, unknown>;
5
+ }
6
+ export interface ToolCall {
7
+ id: string;
8
+ name: string;
9
+ input: Record<string, unknown>;
10
+ }
11
+ export interface ToolResult {
12
+ tool_use_id: string;
13
+ content: string;
14
+ }
15
+ export type ToolExecutor = (call: ToolCall) => Promise<string>;
16
+ export interface FreeTurtleModule {
17
+ name: string;
18
+ description: string;
19
+ initialize(config: Record<string, unknown>, env: Record<string, string>, options?: {
20
+ policy?: import("../policy.js").PolicyConfig;
21
+ }): Promise<void>;
22
+ getTools(): ToolDefinition[];
23
+ executeTool(name: string, input: Record<string, unknown>): Promise<string>;
24
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ import type { FreeTurtleModule, ToolDefinition } from "../types.js";
2
+ export declare class XmtpModule implements FreeTurtleModule {
3
+ name: string;
4
+ description: string;
5
+ initialize(): Promise<void>;
6
+ getTools(): ToolDefinition[];
7
+ executeTool(name: string): Promise<string>;
8
+ }
@@ -0,0 +1,14 @@
1
+ export class XmtpModule {
2
+ name = "xmtp";
3
+ description = "XMTP messaging (not yet implemented).";
4
+ async initialize() {
5
+ console.log("XMTP module not yet implemented");
6
+ }
7
+ getTools() {
8
+ return [];
9
+ }
10
+ async executeTool(name) {
11
+ throw new Error(`XMTP tool "${name}" not implemented`);
12
+ }
13
+ }
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/xmtp/index.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,UAAU;IACrB,IAAI,GAAG,MAAM,CAAC;IACd,WAAW,GAAG,uCAAuC,CAAC;IAEtD,KAAK,CAAC,UAAU;QACd,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IACjD,CAAC;IAED,QAAQ;QACN,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAAY;QAC5B,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,mBAAmB,CAAC,CAAC;IACzD,CAAC;CACF"}
@@ -0,0 +1,45 @@
1
+ export interface PolicyConfig {
2
+ github: {
3
+ allowed_repos: string[];
4
+ allowed_paths: string[];
5
+ approval_required_branches: string[];
6
+ };
7
+ farcaster: {
8
+ allowed_channels: string[];
9
+ };
10
+ database: {
11
+ allowed_schemas: string[];
12
+ allowed_tables: string[];
13
+ };
14
+ onchain: {
15
+ allowed_contracts: string[];
16
+ allowed_read_functions: string[];
17
+ };
18
+ approvals: {
19
+ timeout_seconds: number;
20
+ fail_mode: "deny" | "allow";
21
+ };
22
+ }
23
+ export declare class PolicyDeniedError extends Error {
24
+ code: string;
25
+ constructor(code: string, message: string);
26
+ }
27
+ export declare function assertGithubRepoAllowed(policy: PolicyConfig | undefined, repo: string): void;
28
+ export declare function assertGithubPathAllowed(policy: PolicyConfig | undefined, path: string): void;
29
+ export declare function assertGithubBranchAllowed(policy: PolicyConfig | undefined, branch: string): void;
30
+ export declare function assertFarcasterChannelAllowed(policy: PolicyConfig | undefined, channel: string): void;
31
+ export declare function assertDatabaseScopeAllowed(policy: PolicyConfig | undefined, schema: string, table: string): void;
32
+ export declare function assertOnchainScopeAllowed(policy: PolicyConfig | undefined, contract: string, fn?: string): void;
33
+ /**
34
+ * Determines whether a tool call requires human approval before execution.
35
+ * - delete_cast => always true
36
+ * - commit_file => true if branch is in approval_required_branches (default ["main"])
37
+ * - everything else => false
38
+ */
39
+ export declare function requiresApproval(policy: PolicyConfig | undefined, toolName: string, input: Record<string, unknown>): boolean;
40
+ export declare function getDefaultPolicy(): PolicyConfig;
41
+ /**
42
+ * Parse a raw config object (from the ## Policy section) into a PolicyConfig.
43
+ * Expects subsections like github.allowed_repos as comma-separated strings.
44
+ */
45
+ export declare function parsePolicy(raw: Record<string, Record<string, string | boolean>>): PolicyConfig;