@desplega.ai/agent-fs 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/__tests__/api-client.test.d.ts +2 -0
  2. package/dist/__tests__/api-client.test.d.ts.map +1 -0
  3. package/dist/__tests__/api-client.test.js +86 -0
  4. package/dist/__tests__/api-client.test.js.map +1 -0
  5. package/dist/__tests__/param-mapping.test.d.ts +2 -0
  6. package/dist/__tests__/param-mapping.test.d.ts.map +1 -0
  7. package/dist/__tests__/param-mapping.test.js +53 -0
  8. package/dist/__tests__/param-mapping.test.js.map +1 -0
  9. package/dist/api-client.d.ts +11 -0
  10. package/dist/api-client.d.ts.map +1 -0
  11. package/dist/api-client.js +56 -0
  12. package/dist/api-client.js.map +1 -0
  13. package/dist/cli.js +280 -0
  14. package/dist/commands/auth.d.ts +4 -0
  15. package/dist/commands/auth.d.ts.map +1 -0
  16. package/dist/commands/auth.js +81 -0
  17. package/dist/commands/auth.js.map +1 -0
  18. package/dist/commands/comment.d.ts +4 -0
  19. package/dist/commands/comment.d.ts.map +1 -0
  20. package/dist/commands/comment.js +161 -0
  21. package/dist/commands/comment.js.map +1 -0
  22. package/dist/commands/config-cmd.d.ts +3 -0
  23. package/dist/commands/config-cmd.d.ts.map +1 -0
  24. package/dist/commands/config-cmd.js +147 -0
  25. package/dist/commands/config-cmd.js.map +1 -0
  26. package/dist/commands/daemon.d.ts +3 -0
  27. package/dist/commands/daemon.d.ts.map +1 -0
  28. package/dist/commands/daemon.js +33 -0
  29. package/dist/commands/daemon.js.map +1 -0
  30. package/dist/commands/docs.d.ts +3 -0
  31. package/dist/commands/docs.d.ts.map +1 -0
  32. package/dist/commands/docs.js +13 -0
  33. package/dist/commands/docs.js.map +1 -0
  34. package/dist/commands/drive.d.ts +4 -0
  35. package/dist/commands/drive.d.ts.map +1 -0
  36. package/dist/commands/drive.js +86 -0
  37. package/dist/commands/drive.js.map +1 -0
  38. package/dist/commands/init.d.ts +3 -0
  39. package/dist/commands/init.d.ts.map +1 -0
  40. package/dist/commands/init.js +20 -0
  41. package/dist/commands/init.js.map +1 -0
  42. package/dist/commands/onboard.d.ts +3 -0
  43. package/dist/commands/onboard.d.ts.map +1 -0
  44. package/dist/commands/onboard.js +229 -0
  45. package/dist/commands/onboard.js.map +1 -0
  46. package/dist/commands/ops.d.ts +4 -0
  47. package/dist/commands/ops.d.ts.map +1 -0
  48. package/dist/commands/ops.js +99 -0
  49. package/dist/commands/ops.js.map +1 -0
  50. package/dist/embedded.d.ts +5 -0
  51. package/dist/embedded.d.ts.map +1 -0
  52. package/dist/embedded.js +59 -0
  53. package/dist/embedded.js.map +1 -0
  54. package/dist/formatters.d.ts +11 -0
  55. package/dist/formatters.d.ts.map +1 -0
  56. package/dist/formatters.js +257 -0
  57. package/dist/formatters.js.map +1 -0
  58. package/dist/index.d.ts +3 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +83 -0
  61. package/dist/index.js.map +1 -0
  62. package/package.json +42 -0
  63. package/src/index.ts +90 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/api-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,86 @@
1
+ import { describe, test, expect, beforeAll, afterAll } from "bun:test";
2
+ import { createTestDb, MockS3Client } from "../../../core/src/test-utils.js";
3
+ import { createApp } from "../../../server/src/app.js";
4
+ // We test ApiClient by pointing it at a real in-memory Hono server.
5
+ let server;
6
+ let port = 0;
7
+ let apiKey;
8
+ let orgId;
9
+ beforeAll(async () => {
10
+ const db = createTestDb();
11
+ const s3 = new MockS3Client();
12
+ const app = createApp(db, s3);
13
+ // Start on a random port
14
+ server = Bun.serve({
15
+ port: 0,
16
+ fetch: app.fetch,
17
+ });
18
+ port = server.port;
19
+ // Register a user to get an API key
20
+ const res = await fetch(`http://localhost:${port}/auth/register`, {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/json" },
23
+ body: JSON.stringify({ email: "cli-test@example.com" }),
24
+ });
25
+ const body = await res.json();
26
+ apiKey = body.apiKey;
27
+ orgId = body.orgId;
28
+ // Set env vars so ApiClient picks them up
29
+ process.env.AGENT_FS_API_URL = `http://localhost:${port}`;
30
+ process.env.AGENT_FS_API_KEY = apiKey;
31
+ });
32
+ afterAll(() => {
33
+ server?.stop();
34
+ delete process.env.AGENT_FS_API_URL;
35
+ delete process.env.AGENT_FS_API_KEY;
36
+ });
37
+ describe("ApiClient", () => {
38
+ // Dynamic import so env vars are set before constructor runs
39
+ async function makeClient() {
40
+ const { ApiClient } = await import("../api-client.js");
41
+ return new ApiClient();
42
+ }
43
+ test("get() fetches data", async () => {
44
+ const client = await makeClient();
45
+ const result = await client.get("/orgs");
46
+ expect(result.orgs).toBeDefined();
47
+ expect(result.orgs.length).toBeGreaterThan(0);
48
+ });
49
+ test("post() sends data", async () => {
50
+ const client = await makeClient();
51
+ const result = await client.post("/orgs", { name: "cli-test-org" });
52
+ expect(result.name).toBe("cli-test-org");
53
+ });
54
+ test("callOp() dispatches operation", async () => {
55
+ const client = await makeClient();
56
+ // Write a file
57
+ const writeResult = await client.callOp(orgId, "write", {
58
+ path: "/cli-test.txt",
59
+ content: "Hello from CLI",
60
+ });
61
+ expect(writeResult.version).toBe(1);
62
+ // Read it back
63
+ const catResult = await client.callOp(orgId, "cat", {
64
+ path: "/cli-test.txt",
65
+ });
66
+ expect(catResult.content).toBe("Hello from CLI");
67
+ });
68
+ test("setApiKey() changes auth", async () => {
69
+ const client = await makeClient();
70
+ client.setApiKey("af_invalid_key");
71
+ // Should fail with auth error
72
+ await expect(client.get("/orgs")).rejects.toThrow();
73
+ });
74
+ test("connection error gives helpful message", async () => {
75
+ process.env.AGENT_FS_API_URL = "http://localhost:1"; // Nothing running
76
+ const client = await makeClient();
77
+ await expect(client.get("/health")).rejects.toThrow(/Cannot connect/);
78
+ // Restore
79
+ process.env.AGENT_FS_API_URL = `http://localhost:${port}`;
80
+ });
81
+ test("server error includes message from response", async () => {
82
+ const client = await makeClient();
83
+ await expect(client.callOp(orgId, "cat", { path: "/nonexistent.txt" })).rejects.toThrow(/not found|NoSuchKey/i);
84
+ });
85
+ });
86
+ //# sourceMappingURL=api-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.test.js","sourceRoot":"","sources":["../../src/__tests__/api-client.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=param-mapping.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"param-mapping.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/param-mapping.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,53 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ /**
3
+ * Tests for CLI flag → Zod schema param mapping.
4
+ * The CLI uses --old/--new flags but the edit Zod schema expects old_string/new_string.
5
+ * The CLI uses --expected-version but the write Zod schema expects expectedVersion.
6
+ */
7
+ function applyParamMapping(params) {
8
+ const mapped = { ...params };
9
+ // These mappings mirror packages/cli/src/commands/ops.ts
10
+ if (mapped["expected-version"] !== undefined) {
11
+ mapped.expectedVersion = mapped["expected-version"];
12
+ delete mapped["expected-version"];
13
+ }
14
+ if (mapped["old"] !== undefined) {
15
+ mapped.old_string = mapped["old"];
16
+ delete mapped["old"];
17
+ }
18
+ if (mapped["new"] !== undefined) {
19
+ mapped.new_string = mapped["new"];
20
+ delete mapped["new"];
21
+ }
22
+ return mapped;
23
+ }
24
+ describe("CLI param mapping", () => {
25
+ test("maps --old to old_string and --new to new_string", () => {
26
+ const input = { path: "/test.md", old: "hello", new: "world" };
27
+ const result = applyParamMapping(input);
28
+ expect(result.old_string).toBe("hello");
29
+ expect(result.new_string).toBe("world");
30
+ expect(result.old).toBeUndefined();
31
+ expect(result.new).toBeUndefined();
32
+ expect(result.path).toBe("/test.md");
33
+ });
34
+ test("maps --expected-version to expectedVersion", () => {
35
+ const input = { path: "/test.md", "expected-version": "3" };
36
+ const result = applyParamMapping(input);
37
+ expect(result.expectedVersion).toBe("3");
38
+ expect(result["expected-version"]).toBeUndefined();
39
+ });
40
+ test("does not affect params without CLI flag names", () => {
41
+ const input = { path: "/test.md", content: "hello", message: "update" };
42
+ const result = applyParamMapping(input);
43
+ expect(result).toEqual(input);
44
+ });
45
+ test("handles missing optional params gracefully", () => {
46
+ const input = { path: "/test.md", old: "hello" };
47
+ const result = applyParamMapping(input);
48
+ expect(result.old_string).toBe("hello");
49
+ expect(result.new_string).toBeUndefined();
50
+ expect(result.old).toBeUndefined();
51
+ });
52
+ });
53
+ //# sourceMappingURL=param-mapping.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"param-mapping.test.js","sourceRoot":"","sources":["../../src/__tests__/param-mapping.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare class ApiClient {
2
+ private baseUrl;
3
+ private apiKey;
4
+ constructor();
5
+ private request;
6
+ get(path: string): Promise<any>;
7
+ post(path: string, body: any): Promise<any>;
8
+ callOp(orgId: string, op: string, params: Record<string, any>): Promise<any>;
9
+ setApiKey(key: string): void;
10
+ }
11
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAEA,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;;YAUT,OAAO;IA+Bf,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAI/B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAO3C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAIlF,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAG7B"}
@@ -0,0 +1,56 @@
1
+ import { getConfig } from "@/core";
2
+ export class ApiClient {
3
+ baseUrl;
4
+ apiKey;
5
+ constructor() {
6
+ const config = getConfig();
7
+ this.baseUrl =
8
+ process.env.AGENT_FS_API_URL ??
9
+ `http://${config.server.host}:${config.server.port}`;
10
+ this.apiKey = process.env.AGENT_FS_API_KEY ?? config.auth.apiKey;
11
+ }
12
+ async request(path, opts) {
13
+ const headers = new Headers(opts?.headers);
14
+ if (this.apiKey) {
15
+ headers.set("Authorization", `Bearer ${this.apiKey}`);
16
+ }
17
+ headers.set("Content-Type", "application/json");
18
+ let res;
19
+ try {
20
+ res = await fetch(`${this.baseUrl}${path}`, { ...opts, headers });
21
+ }
22
+ catch (err) {
23
+ throw new Error(`Cannot connect to agent-fs daemon at ${this.baseUrl}. Is it running? Start with: agent-fs daemon start`);
24
+ }
25
+ let body;
26
+ try {
27
+ body = await res.json();
28
+ }
29
+ catch {
30
+ const text = await res.text().catch(() => "");
31
+ throw new Error(`Unexpected response from daemon (${res.status}): ${text || "empty"}`);
32
+ }
33
+ if (!res.ok) {
34
+ const msg = body.message ?? body.error ?? "Request failed";
35
+ const suggestion = body.suggestion ? `\n Suggestion: ${body.suggestion}` : "";
36
+ throw new Error(`${msg}${suggestion}`);
37
+ }
38
+ return body;
39
+ }
40
+ async get(path) {
41
+ return this.request(path);
42
+ }
43
+ async post(path, body) {
44
+ return this.request(path, {
45
+ method: "POST",
46
+ body: JSON.stringify(body),
47
+ });
48
+ }
49
+ async callOp(orgId, op, params) {
50
+ return this.post(`/orgs/${orgId}/ops`, { op, ...params });
51
+ }
52
+ setApiKey(key) {
53
+ this.apiKey = key;
54
+ }
55
+ }
56
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnC,MAAM,OAAO,SAAS;IACZ,OAAO,CAAS;IAChB,MAAM,CAAS;IAEvB;QACE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO;YACV,OAAO,CAAC,GAAG,CAAC,gBAAgB;gBAC5B,UAAU,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACvD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IACnE,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,IAAkB;QACpD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAEhD,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,CAAC,OAAO,oDAAoD,CACzG,CAAC;QACJ,CAAC;QAED,IAAI,IAAS,CAAC;QACd,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,CAAC,MAAM,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,gBAAgB,CAAC;YAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/E,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,GAAG,UAAU,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,IAAS;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,EAAU,EAAE,MAA2B;QACjE,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,KAAK,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,SAAS,CAAC,GAAW;QACnB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;IACpB,CAAC;CACF"}
package/dist/cli.js ADDED
@@ -0,0 +1,280 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ var y=import.meta.require;import{Command as mt}from"commander";import{getConfig as gt,listUserOrgs as yt,getUserByApiKey as ft,VERSION as wt}from"@/core";import{getConfig as V}from"@/core";class N{baseUrl;apiKey;constructor(){let n=V();this.baseUrl=process.env.AGENT_FS_API_URL??`http://${n.server.host}:${n.server.port}`,this.apiKey=process.env.AGENT_FS_API_KEY??n.auth.apiKey}async request(n,t){let e=new Headers(t?.headers);if(this.apiKey)e.set("Authorization",`Bearer ${this.apiKey}`);e.set("Content-Type","application/json");let i;try{i=await fetch(`${this.baseUrl}${n}`,{...t,headers:e})}catch(a){throw Error(`Cannot connect to agent-fs daemon at ${this.baseUrl}. Is it running? Start with: agent-fs daemon start`)}let o;try{o=await i.json()}catch{let a=await i.text().catch(()=>"");throw Error(`Unexpected response from daemon (${i.status}): ${a||"empty"}`)}if(!i.ok){let a=o.message??o.error??"Request failed",c=o.suggestion?`
4
+ Suggestion: ${o.suggestion}`:"";throw Error(`${a}${c}`)}return o}async get(n){return this.request(n)}async post(n,t){return this.request(n,{method:"POST",body:JSON.stringify(t)})}async callOp(n,t,e){return this.post(`/orgs/${n}/ops`,{op:t,...e})}setApiKey(n){this.apiKey=n}}import{Command as On}from"commander";import{createDatabase as nn,getConfig as J,AgentS3Client as tn,getUserByApiKey as en,resolveContext as an,dispatchOp as on,ensureLocalUser as cn,createEmbeddingProviderFromEnv as rn}from"@/core";var l=null,k=null,I=null,E=null;async function sn(){let n=U();if(n.embeddingProvider===void 0){let t=J();if(!E)E=rn(t.embedding);n.embeddingProvider=await E}return n}function U(){if(I)return I;let n=J();l=nn(),k=new tn(n.s3);let{apiKey:t}=cn(l),e=en(l,t);if(!e)throw Error("Invalid API key in config");let i=an(l,{userId:e.id});return I={db:l,s3:k,orgId:i.orgId,driveId:i.driveId,userId:e.id},I}function S(){return U().orgId}async function $(n,t,e){let i=await sn();return on(i,t,e)}async function q(){try{let n=J(),t=`http://${n.server.host}:${n.server.port}/health`;return(await fetch(t,{signal:AbortSignal.timeout(1000)})).ok}catch{return!1}}import{getOpDefinition as Tn}from"@/core";function w(n){if(n<1024)return`${n} B`;if(n<1048576)return`${(n/1024).toFixed(1)} KB`;if(n<1073741824)return`${(n/1048576).toFixed(1)} MB`;return`${(n/1073741824).toFixed(1)} GB`}function v(n){if(!n)return"-";let t=typeof n==="string"?new Date(n):n;if(isNaN(t.getTime()))return String(n);return t.toISOString().replace("T"," ").replace(/\.\d{3}Z$/,"Z")}function p(n,t){return n.length>=t?n:n+" ".repeat(t-n.length)}function O(n,t){return n.length>=t?n:" ".repeat(t-n.length)+n}function dn(n){let t=n.entries??[];if(t.length===0)return"(empty directory)";let e=Math.max(4,...t.map((r)=>String(r.name).length)),i=Math.max(4,...t.map((r)=>String(r.type).length)),o=Math.max(4,...t.map((r)=>w(r.size??0).length)),a=p("NAME",e)+" "+p("TYPE",i)+" "+O("SIZE",o)+" MODIFIED",c=t.map((r)=>p(r.name,e)+" "+p(r.type,i)+" "+O(w(r.size??0),o)+" "+v(r.modifiedAt));return[a,...c].join(`
5
+ `)}function A(n){let e=(n.content??"").split(`
6
+ `);if(e.length>0&&e[e.length-1]==="")e.pop();let i=n.offset??1,o=String(i+e.length-1).length;return e.map((a,c)=>`${O(String(i+c),o)} ${a}`).join(`
7
+ `)}function hn(n){let t=[["Path",n.path??"-"],["Size",w(n.size??0)],["Content-Type",n.contentType??"-"],["Author",n.author??"-"],["Version",n.currentVersion!=null?String(n.currentVersion):"-"],["Created",v(n.createdAt)],["Modified",v(n.modifiedAt)],["Deleted",n.isDeleted?"yes":"no"]];if(n.embeddingStatus)t.push(["Embedding",n.embeddingStatus]);let e=Math.max(...t.map(([i])=>i.length));return t.map(([i,o])=>`${p(i+":",e+1)} ${o}`).join(`
8
+ `)}function mn(n){let t=n.versions??[];if(t.length===0)return"(no version history)";return t.map((e)=>{let i=[`v${e.version} ${v(e.createdAt)} ${e.author??"-"} [${e.operation}]`];if(e.message)i.push(` ${e.message}`);if(e.diffSummary)i.push(` ${e.diffSummary}`);return i.join(`
9
+ `)}).join(`
10
+
11
+ `)}function gn(n){return`\u2713 wrote ${n.path} (v${n.version}, ${w(n.size??0)})`}function yn(n){return`\u2713 edited ${n.path} (v${n.version}, ${n.changes} change${n.changes!==1?"s":""})`}function fn(n){return`\u2713 appended (v${n.version}, ${w(n.size??0)})`}function wn(n){return n.deleted?`\u2713 deleted ${n.path}`:`(not found: ${n.path})`}function vn(n){return`\u2713 moved ${n.from} -> ${n.to} (v${n.version})`}function ln(n){return`\u2713 copied ${n.from} -> ${n.to} (v${n.version})`}function pn(n){let t=n.tree??[];if(t.length===0)return"(empty)";let e=[];function i(o,a){for(let c=0;c<o.length;c++){let r=o[c],s=c===o.length-1,d=s?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",m=r.type==="directory"?"/":"";if(e.push(`${a}${d}${r.name}${m}`),r.children&&r.children.length>0){let F=a+(s?" ":"\u2502 ");i(r.children,F)}}}return i(t,""),e.join(`
12
+ `)}function In(n){let t=n.matches??[];if(t.length===0)return"(no matches)";return t.map((e)=>`${e.path}:${e.lineNumber}: ${e.content}`).join(`
13
+ `)}function Sn(n){let t=n.matches??[];if(t.length===0)return n.hint?`(no matches) ${n.hint}`:"(no matches)";let e=t.map((i)=>`${i.path} (rank: ${typeof i.rank==="number"?i.rank.toFixed(2):i.rank})
14
+ ${i.snippet}`);if(n.hint)e.push(`
15
+ hint: ${n.hint}`);return e.join(`
16
+
17
+ `)}function $n(n){let t=n.results??[];if(t.length===0)return"(no results)";return t.map((e)=>`${e.path} (score: ${typeof e.score==="number"?e.score.toFixed(3):e.score})`+(e.author?` by ${e.author}`:"")+`
18
+ ${e.snippet}`).join(`
19
+
20
+ `)}function qn(n){let t=n.matches??[];if(t.length===0)return"(no matches)";return t.map((e)=>`${e.path} ${w(e.size??0)} ${v(e.modifiedAt)}`).join(`
21
+ `)}function Rn(n){let t=n.changes??[];if(t.length===0)return"(no changes)";return t.map((e)=>{let i=e.type==="add"?"+":e.type==="remove"?"-":" ",o=e.lineNumber!=null?`${e.lineNumber}: `:"";return`${i} ${o}${e.content}`}).join(`
22
+ `)}function xn(n){return A(n)}function Dn(n){return`\u2713 reverted to v${n.revertedTo} (new version: v${n.version})`}function Fn(n){let t=n.entries??[];if(t.length===0)return"(no recent activity)";return t.map((e)=>`${e.path} v${e.version} ${v(e.createdAt)} ${e.author??"-"} [${e.operation}]`+(e.message?`
23
+ ${e.message}`:"")).join(`
24
+
25
+ `)}function Nn(n){let t=[];if(t.push(`reindexed: ${n.reindexed??0}`),n.failed)t.push(`failed: ${n.failed}`);if(n.skipped)t.push(`skipped: ${n.skipped}`);return t.join(", ")}var En={ls:dn,cat:A,stat:hn,log:mn,write:gn,edit:yn,append:fn,rm:wn,mv:vn,cp:ln,tree:pn,grep:In,fts:Sn,search:$n,glob:qn,diff:Rn,tail:xn,revert:Dn,recent:Fn,reindex:Nn};function Jn(n,t){let e=En[n];if(e)return e(t);return JSON.stringify(t,null,2)}function Q(n,t,e){if(e)console.log(JSON.stringify(t,null,2));else console.log(Jn(n,t))}var kn=[{name:"write",args:[{name:"path",required:!0}],options:[{flag:"--content <text>",description:"File content (reads stdin if omitted)"},{flag:"-m, --message <msg>",description:"Version message"},{flag:"--expected-version <n>",description:"Fail if file is not at this version (optimistic concurrency)"}]},{name:"cat",args:[{name:"path",required:!0}],options:[{flag:"--offset <n>",description:"Line offset"},{flag:"--limit <n>",description:"Max lines"}]},{name:"edit",args:[{name:"path",required:!0}],options:[{flag:"--old <string>",description:"Text to replace"},{flag:"--new <string>",description:"Replacement text"},{flag:"-m, --message <msg>",description:"Version message"}]},{name:"append",args:[{name:"path",required:!0}],options:[{flag:"--content <text>",description:"Content to append"},{flag:"-m, --message <msg>",description:"Version message"}]},{name:"ls",args:[{name:"path",required:!1}],options:[]},{name:"stat",args:[{name:"path",required:!0}],options:[]},{name:"rm",args:[{name:"path",required:!0}],options:[]},{name:"mv",args:[{name:"from",required:!0},{name:"to",required:!0}],options:[{flag:"-m, --message <msg>",description:"Version message"}]},{name:"cp",args:[{name:"from",required:!0},{name:"to",required:!0}],options:[]},{name:"tail",args:[{name:"path",required:!0}],options:[{flag:"-n, --lines <n>",description:"Number of lines (default: 20)"}]},{name:"log",args:[{name:"path",required:!0}],options:[{flag:"--limit <n>",description:"Max entries"}]},{name:"diff",args:[{name:"path",required:!0}],options:[{flag:"--v1 <n>",description:"First version"},{flag:"--v2 <n>",description:"Second version"}]},{name:"revert",args:[{name:"path",required:!0}],options:[{flag:"--version <n>",description:"Version to revert to"}]},{name:"recent",args:[{name:"path",required:!1}],options:[{flag:"--since <duration>",description:"Time filter (e.g., 1h, 24h)"},{flag:"--limit <n>",description:"Max entries"}]},{name:"grep",args:[{name:"pattern",required:!0},{name:"path",required:!0}],options:[]},{name:"fts",args:[{name:"pattern",required:!0}],options:[{flag:"--path <prefix>",description:"Path prefix filter"}]},{name:"search",args:[{name:"query",required:!0}],options:[{flag:"--limit <n>",description:"Max results"}]},{name:"reindex",args:[],options:[{flag:"--path <prefix>",description:"Path prefix filter"}]},{name:"tree",args:[{name:"path",required:!1}],options:[{flag:"--depth <n>",description:"Max recursion depth"}]},{name:"glob",args:[{name:"pattern",required:!0}],options:[{flag:"--path <prefix>",description:"Path prefix filter"}]}];function G(n,t,e){for(let i of kn){let o=Tn(i.name),a=new On(i.name).description(o?.description??i.name);for(let c of i.args)if(c.required)a.argument(`<${c.name}>`);else a.argument(`[${c.name}]`);for(let c of i.options)a.option(c.flag,c.description);a.action(async(...c)=>{let s={...c[c.length-2]};for(let d=0;d<i.args.length;d++)if(c[d]!==void 0)s[i.args[d].name]=c[d];if((i.name==="write"||i.name==="append")&&!s.content)if(!process.stdin.isTTY)s.content=await Bun.stdin.text();else console.error("Error: --content required (or pipe content via stdin)"),process.exit(1);if(s["expected-version"]!==void 0)s.expectedVersion=s["expected-version"],delete s["expected-version"];if(s.old!==void 0)s.old_string=s.old,delete s.old;if(s.new!==void 0)s.new_string=s.new,delete s.new;for(let d of["offset","limit","lines","v1","v2","version","expectedVersion","depth"])if(s[d]!==void 0)s[d]=parseInt(s[d]);try{let d;if(await q())d=await t.callOp(e(),i.name,s);else{let m=S();d=await $(m,i.name,s)}Q(i.name,d,n.opts().json)}catch(d){console.error(`Error: ${d.message}`),process.exit(1)}}),n.addCommand(a)}}import{Command as Un}from"commander";import{setConfigValue as An,createUser as Qn,createDatabase as Gn,listUserOrgs as Kn}from"@/core";function H(n){let t=new Un("auth").description("Authentication commands");return t.command("register").argument("<email>","Email address").description("Register a new user").action(async(e)=>{try{let i=await n.post("/auth/register",{email:e});K(i,n)}catch{try{let i=Gn(),o=Qn(i,{email:e}),a=Kn(i,o.user.id);K({apiKey:o.apiKey,userId:o.user.id,orgId:a[0]?.id},n)}catch(i){if(i.message?.includes("UNIQUE"))console.error("Error: User with this email already exists.");else console.error(`Error: ${i.message}`);process.exit(1)}}}),t.command("whoami").description("Show current user info").action(async()=>{try{let e=await n.get("/auth/me");console.log(JSON.stringify(e,null,2))}catch{try{let{getConfig:e,getUserByApiKey:i,createDatabase:o,listUserOrgs:a}=await import("@/core"),c=e();if(!c.auth.apiKey)console.error("Not logged in. Run: agent-fs auth register <email>"),process.exit(1);let r=o(),s=i(r,c.auth.apiKey);if(!s)console.error("Invalid API key in config."),process.exit(1);let d=a(r,s.id);console.log(JSON.stringify({...s,orgs:d},null,2))}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}}}),t}function K(n,t){console.log("Registered successfully!"),console.log(`API Key: ${n.apiKey}`),console.log(`User ID: ${n.userId}`),console.log(`Org ID: ${n.orgId}`),An("auth.apiKey",n.apiKey),t.setApiKey(n.apiKey),console.log(`
26
+ API key saved to config.`)}import{Command as Hn}from"commander";function L(){let n=new Hn("daemon").description("Daemon lifecycle management");return n.command("start").description("Start the agent-fs daemon").action(async()=>{let{startDaemon:t}=await import("@/server/daemon.js");t()}),n.command("stop").description("Stop the agent-fs daemon").action(async()=>{let{stopDaemon:t}=await import("@/server/daemon.js");t()}),n.command("status").description("Check daemon status").action(async()=>{let{daemonStatus:t}=await import("@/server/daemon.js"),e=t();if(e.running)console.log(`Daemon running (PID: ${e.pid})`);else console.log("Daemon is not running")}),n}import{Command as Ln}from"commander";import{existsSync as M}from"fs";import{getConfig as T,setConfigValue as Mn,getDbPath as X,getConfigPath as Z,AgentS3Client as Xn,createEmbeddingProviderFromEnv as Zn}from"@/core";function Y(){let n=new Ln("config").description("Configuration management");return n.command("get").argument("<key>","Config key (dot notation, e.g., s3.bucket)").description("Get a config value").action((t)=>{let e=T(),i=t.split("."),o=e;for(let a of i)o=o?.[a];if(o===void 0)console.error(`Key not found: ${t}`),process.exit(1);console.log(typeof o==="object"?JSON.stringify(o,null,2):String(o))}),n.command("set").argument("<key>","Config key").argument("<value>","Config value").description("Set a config value").action((t,e)=>{let i=e;try{i=JSON.parse(e)}catch{}Mn(t,i),console.log(`Set ${t} = ${JSON.stringify(i)}`)}),n.command("list").description("Show all config").action(()=>{console.log(JSON.stringify(T(),null,2))}),n.command("validate").description("Check that config, database, S3, and embeddings are healthy").action(async()=>{let t=[],e=T(),i=M(Z());t.push({name:"Config file",ok:i,message:i?Z():"Not found \u2014 run `agent-fs onboard`"});let a=["endpoint","bucket","accessKeyId","secretAccessKey"].filter((m)=>!e.s3[m]);if(t.push({name:"S3 config",ok:a.length===0,message:a.length===0?`${e.s3.provider} \u2192 ${e.s3.endpoint}/${e.s3.bucket}`:`Missing: ${a.join(", ")}`}),a.length===0)try{await new Xn(e.s3).listObjects(""),t.push({name:"S3 connectivity",ok:!0,message:"Connected"})}catch(m){t.push({name:"S3 connectivity",ok:!1,message:m.message||"Connection failed"})}let c=M(X());t.push({name:"Database",ok:c,message:c?X():"Not found \u2014 run `agent-fs onboard`"}),t.push({name:"Auth",ok:!!e.auth.apiKey,message:e.auth.apiKey?"API key configured":"No API key \u2014 run `agent-fs onboard`"});let r=e.embedding.provider,s=!!e.embedding.apiKey||!!process.env.OPENAI_API_KEY||!!process.env.GEMINI_API_KEY;if(r==="openai"||r==="gemini")if(s)try{let m=await Zn(e.embedding);t.push({name:"Embeddings",ok:!!m,message:m?`${r} ready`:`${r} configured but failed to init`})}catch(m){t.push({name:"Embeddings",ok:!1,message:m.message})}else t.push({name:"Embeddings",ok:!1,message:`${r} selected but no API key`});else t.push({name:"Embeddings",ok:!0,message:"local/disabled (semantic search may be unavailable)"});console.log(`
27
+ agent-fs health check
28
+ `);let d=!0;for(let m of t){let F=m.ok?"\u2713":"\u2717";if(console.log(` ${F} ${m.name}: ${m.message}`),!m.ok)d=!1}if(console.log(),d)console.log("All checks passed.");else console.log("Some checks failed. Fix the issues above and re-run."),process.exit(1)}),n}import{Command as Yn}from"commander";import{createDatabase as Wn,listDrives as W,createDrive as zn,listUserOrgs as Bn,getUserByApiKey as bn,getConfig as _n,inviteToOrg as Pn}from"@/core";function z(n){let t=new Yn("drive").description("Drive management");return t.command("list").description("List drives in current org").action(async()=>{try{let{db:e,orgId:i}=R(),o=W(e,i);console.log(JSON.stringify({drives:o},null,2))}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}}),t.command("create").argument("<name>","Drive name").description("Create a new drive").action(async(e)=>{try{let{db:i,orgId:o}=R(),a=zn(i,{orgId:o,name:e});console.log(JSON.stringify(a,null,2))}catch(i){console.error(`Error: ${i.message}`),process.exit(1)}}),t.command("current").description("Show current drive context").action(async()=>{try{let{db:e,orgId:i,userId:o}=R(),a=W(e,i),c=a.find((r)=>r.isDefault);console.log(JSON.stringify({orgId:i,drive:c??a[0]??null},null,2))}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}}),t.command("invite").argument("<email>","User email to invite").requiredOption("--role <role>","Role: viewer, editor, or admin").description("Invite a user to the current org").addHelpText("after",`
29
+ This invites the user to the organization that owns the current drive. The user will have access to all drives in the org based on their role.`).action(async(e,i)=>{try{let{db:o,orgId:a}=R();Pn(o,{orgId:a,email:e,role:i.role}),console.log(`Invited ${e} as ${i.role}`)}catch(o){console.error(`Error: ${o.message}`),process.exit(1)}}),t}function R(){let n=_n();if(!n.auth.apiKey)throw Error("Not logged in. Run: agent-fs auth register <email>");let t=Wn(),e=bn(t,n.auth.apiKey);if(!e)throw Error("Invalid API key in config.");let i=Bn(t,e.id);if(i.length===0)throw Error("No orgs found.");return{db:t,orgId:i[0].id,userId:e.id}}import{Command as rt}from"commander";import{Command as jn}from"commander";import{execSync as f}from"child_process";import{getConfig as b,setConfigValue as h,createDatabase as Cn,getUserByApiKey as un,listUserOrgs as B,ensureLocalUser as Vn,createUser as nt,getConfigPath as tt}from"@/core";import{existsSync as et}from"fs";function x(){return new jn("onboard").description("Set up agent-fs (storage, embeddings, database, first user)").option("--local","Use local MinIO Docker container for S3").option("--remote <url>","Connect to a remote agent-fs server").option("-y, --yes","Accept all defaults without prompts").option("--s3-endpoint <url>","S3 endpoint URL").option("--s3-bucket <name>","S3 bucket name").option("--s3-access-key <key>","S3 access key ID").option("--s3-secret-key <key>","S3 secret access key").option("--s3-region <region>","S3 region").option("--embeddings <provider>","Embedding provider: openai, gemini, local, none").option("--openai-key <key>","OpenAI API key for embeddings").option("--gemini-key <key>","Gemini API key for embeddings").option("--no-daemon","Skip starting the daemon").action(async(t)=>{if(t.remote)console.error(`Remote mode is not yet supported in the onboard wizard.
30
+ To connect to a remote server, configure manually:
31
+ agent-fs config set api.url "`+t.remote+`"
32
+ agent-fs config set api.key "<your-api-key>"`),process.exit(1);let e=tt();if(et(e)){if(b().auth.apiKey&&!t.yes)console.log("Existing configuration found at "+e),console.log(`Re-running onboard will update settings. Use -y to accept defaults.
33
+ `)}console.log(`Setting up agent-fs...
34
+ `);let o=!(t.s3Endpoint||t.s3Bucket||t.s3AccessKey||t.s3SecretKey);if(t.s3Endpoint){if(h("s3.endpoint",t.s3Endpoint),t.s3Bucket)h("s3.bucket",t.s3Bucket);if(t.s3AccessKey)h("s3.accessKeyId",t.s3AccessKey);if(t.s3SecretKey)h("s3.secretAccessKey",t.s3SecretKey);if(t.s3Region)h("s3.region",t.s3Region);h("s3.provider","s3"),console.log("S3 configured from flags.")}else if(o)await at(!!t.yes);else await ot();let a=t.embeddings??(t.yes?"none":void 0);if(a)it(a,t);else if(!t.yes)console.log(`
35
+ Embedding provider not specified. Skipping (semantic search disabled).`),console.log("Configure later: agent-fs config set embedding.provider openai");console.log(`
36
+ Initializing database...`);let c=Cn();if(console.log("Database ready."),o||t.yes){let{apiKey:r}=Vn(c),s=un(c,r),d=B(c,s.id);console.log(`
37
+ User registered: ${s.email}`),console.log(`API Key: ${r}`),console.log(`Org ID: ${d[0]?.id}`)}else{let r=await ct();try{let s=nt(c,{email:r}),d=B(c,s.user.id);h("auth.apiKey",s.apiKey),console.log(`
38
+ User registered: ${r}`),console.log(`API Key: ${s.apiKey}`),console.log(`Org ID: ${d[0]?.id}`)}catch(s){if(s.message?.includes("UNIQUE"))console.log(`User ${r} already exists.`);else throw s}}console.log("\nSetup complete! Run `agent-fs daemon start` to begin."),console.log("Or use MCP directly: agent-fs mcp")})}function it(n,t){switch(n){case"openai":if(h("embedding.provider","openai"),h("embedding.model","text-embedding-3-small"),t.openaiKey)h("embedding.apiKey",t.openaiKey);console.log("Embeddings: OpenAI (text-embedding-3-small)");break;case"gemini":if(h("embedding.provider","gemini"),h("embedding.model","text-embedding-004"),t.geminiKey)h("embedding.apiKey",t.geminiKey);console.log("Embeddings: Google Gemini (text-embedding-004)");break;case"local":h("embedding.provider","local"),console.log("Embeddings: local llama.cpp");break;case"none":h("embedding.provider","local"),h("embedding.model",""),h("embedding.apiKey",""),console.log("Embeddings: disabled (semantic search unavailable)");break;default:console.error(`Unknown embedding provider: ${n}`),console.error("Valid options: openai, gemini, local, none"),process.exit(1)}}async function at(n){try{f("which docker",{stdio:"ignore"}),f("docker info",{stdio:"ignore"})}catch{console.error(`Docker is required for local mode (MinIO).
39
+ Install Docker: https://docs.docker.com/get-docker/
40
+ Or use 'agent-fs onboard --s3-endpoint <url>' to configure your own S3 bucket.`),process.exit(1)}let t=f("docker ps -a --filter name=agent-fs-minio --format '{{.Names}}'",{encoding:"utf-8"}).trim();if(t==="agent-fs-minio")console.log("Found existing MinIO container (agent-fs-minio).");if(!n){let e=t==="agent-fs-minio"?"start the existing":"create a new";process.stdout.write(`This will ${e} MinIO Docker container. Continue? [Y/n] `);let i=Bun.stdin.stream().getReader(),{value:o}=await i.read();i.releaseLock();let a=new TextDecoder().decode(o).trim().toLowerCase();if(a==="n"||a==="no"){console.log("Skipped MinIO setup. Configure S3 manually:"),console.log(" agent-fs config set s3.endpoint <url>");return}}console.log("Setting up MinIO (local S3)...");try{if(t==="agent-fs-minio")f("docker start agent-fs-minio",{stdio:"inherit"}),console.log("MinIO container started.");else f('docker run -d --name agent-fs-minio -p 9000:9000 -p 9001:9001 -v agent-fs-minio-data:/data -e MINIO_ROOT_USER=minioadmin -e MINIO_ROOT_PASSWORD=minioadmin minio/minio server /data --console-address ":9001"',{stdio:"inherit"}),console.log("MinIO container created.");console.log("Waiting for MinIO to be ready..."),await new Promise((i)=>setTimeout(i,2000));try{f("docker exec agent-fs-minio mc alias set local http://localhost:9000 minioadmin minioadmin && docker exec agent-fs-minio mc mb --ignore-existing local/agentfs",{stdio:"inherit"})}catch{}let e=f("docker inspect --format='{{.Id}}' agent-fs-minio",{encoding:"utf-8"}).trim();h("minio.containerId",e),h("minio.managed",!0)}catch(e){console.error(`Failed to set up MinIO: ${e.message}`),process.exit(1)}h("s3.provider","minio"),h("s3.endpoint","http://localhost:9000"),h("s3.bucket","agentfs"),h("s3.region","us-east-1"),h("s3.accessKeyId","minioadmin"),h("s3.secretAccessKey","minioadmin"),console.log("MinIO configured.")}async function ot(){let n=b();console.log("Using S3 configuration from ~/.agent-fs/config.json"),console.log(` Provider: ${n.s3.provider}`),console.log(` Endpoint: ${n.s3.endpoint}`),console.log(` Bucket: ${n.s3.bucket}`),console.log(`
41
+ Edit with: agent-fs config set s3.endpoint <url>`)}async function ct(){process.stdout.write("Email for first user: ");let n=Bun.stdin.stream().getReader(),{value:t}=await n.read();return n.releaseLock(),new TextDecoder().decode(t).trim()||"local@agent-fs.local"}function _(){let n=x(),t=new rt("init").description("Set up agent-fs (alias for 'onboard')").allowUnknownOption(!0).action(async(e,i)=>{console.log(`Note: 'agent-fs init' is now 'agent-fs onboard'.
42
+ `),await n.parseAsync(i.args,{from:"user"})});for(let e of n.options)t.addOption(e);return t}import{Command as st}from"commander";function P(n,t){let e=new st("comment").description("Document comments");async function i(o,a){if(await q())return n.callOp(t(),o,a);else{let c=S();return $(c,o,a)}}return e.command("add").argument("<path>","File path to comment on").requiredOption("--body <text>","Comment body").option("--line <n>","Line number (sets both line-start and line-end)").option("--line-start <n>","Start line").option("--line-end <n>","End line").option("--quoted-content <text>","Quoted content from the file").description("Add a comment to a file").action(async(o,a)=>{try{let c={path:o,body:a.body};if(a.quotedContent)c.quotedContent=a.quotedContent;if(a.line)c.lineStart=parseInt(a.line),c.lineEnd=parseInt(a.line);if(a.lineStart)c.lineStart=parseInt(a.lineStart);if(a.lineEnd)c.lineEnd=parseInt(a.lineEnd);let r=await i("comment-add",c);console.log(JSON.stringify(r,null,2))}catch(c){console.error(`Error: ${c.message}`),process.exit(1)}}),e.command("reply").argument("<comment-id>","Parent comment ID to reply to").requiredOption("--body <text>","Reply body").description("Reply to a comment").action(async(o,a)=>{try{let c=await i("comment-add",{parentId:o,body:a.body});console.log(JSON.stringify(c,null,2))}catch(c){console.error(`Error: ${c.message}`),process.exit(1)}}),e.command("list").argument("[path]","File path to list comments for").option("--resolved","Show resolved comments").option("--limit <n>","Max results").option("--offset <n>","Skip N results").description("List comments").action(async(o,a)=>{try{let c={};if(o)c.path=o;if(a.resolved)c.resolved=!0;if(a.limit)c.limit=parseInt(a.limit);if(a.offset)c.offset=parseInt(a.offset);let r=await i("comment-list",c);console.log(JSON.stringify(r,null,2))}catch(c){console.error(`Error: ${c.message}`),process.exit(1)}}),e.command("get").argument("<id>","Comment ID").description("Get a comment with its replies").action(async(o)=>{try{let a=await i("comment-get",{id:o});console.log(JSON.stringify(a,null,2))}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}}),e.command("update").argument("<id>","Comment ID").requiredOption("--body <text>","New comment body").description("Update a comment").action(async(o,a)=>{try{let c=await i("comment-update",{id:o,body:a.body});console.log(JSON.stringify(c,null,2))}catch(c){console.error(`Error: ${c.message}`),process.exit(1)}}),e.command("delete").argument("<id>","Comment ID").description("Delete a comment (soft delete)").action(async(o)=>{try{let a=await i("comment-delete",{id:o});console.log(JSON.stringify(a,null,2))}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}}),e.command("resolve").argument("<id>","Comment ID").description("Resolve a comment").action(async(o)=>{try{let a=await i("comment-resolve",{id:o,resolved:!0});console.log(JSON.stringify(a,null,2))}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}}),e.command("reopen").argument("<id>","Comment ID").description("Reopen a resolved comment").action(async(o)=>{try{let a=await i("comment-resolve",{id:o,resolved:!1});console.log(JSON.stringify(a,null,2))}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}}),e}import{Command as ht}from"commander";var j=`---
43
+ name: agent-fs
44
+ description: >-
45
+ Use when the user wants to store, retrieve, search, or manage files in agent-fs \u2014
46
+ an agent-first filesystem backed by S3. Triggers on: "save this to agent-fs",
47
+ "find that file", "store this document", "search agent-fs", "list my files",
48
+ "show version history", "revert file", "set up agent-fs", file persistence for
49
+ agents, shared agent filesystem, or any mention of the agent-fs CLI. Also use
50
+ when the user needs to manage drives, check recent activity, or use semantic
51
+ search across stored files. If the user mentions agent-fs in any context, always
52
+ consult this skill.
53
+ ---
54
+
55
+ # agent-fs CLI
56
+
57
+ agent-fs is an agent-first filesystem backed by S3 with full versioning, full-text search (FTS5), and semantic search. It provides a CLI that outputs JSON, making it ideal for agent workflows. Files are organized in drives within orgs.
58
+
59
+ ## Quick Start
60
+
61
+ \`\`\`bash
62
+ # 1. Set up (local MinIO \u2014 requires Docker)
63
+ agent-fs onboard -y
64
+
65
+ # 2. Optionally start the daemon (CLI auto-detects and works without it)
66
+ agent-fs daemon start
67
+
68
+ # 3. Start using it
69
+ echo "hello world" | agent-fs write docs/readme.txt -m "initial version"
70
+ agent-fs cat docs/readme.txt
71
+ \`\`\`
72
+
73
+ For custom S3 (AWS, R2, etc.), use flags: \`agent-fs onboard --s3-endpoint <url> --s3-bucket <name> --s3-access-key <key> --s3-secret-key <key>\`.
74
+
75
+ ## Essential Patterns
76
+
77
+ 1. **All output is JSON** \u2014 always parse CLI output as JSON (except \`daemon status\` and \`auth register\` which print human-readable text).
78
+
79
+ 2. **Auto-detection** \u2014 the CLI automatically detects whether the daemon is running. If it is, commands go via HTTP; otherwise, they use embedded mode directly. No user action needed.
80
+
81
+ 3. **Stdin piping for content** \u2014 \`write\` and \`append\` accept content via stdin or \`--content\`:
82
+ \`\`\`bash
83
+ # Preferred for multi-line content
84
+ echo "content here" | agent-fs write path/to/file.txt
85
+
86
+ # Inline for short content
87
+ agent-fs write path/to/file.txt --content "short text"
88
+ \`\`\`
89
+
90
+ 4. **Paths** \u2014 forward-slash separated, no leading slash required. Example: \`docs/notes/meeting.md\`
91
+
92
+ 5. **Version messages** \u2014 optional but recommended for auditability:
93
+ \`\`\`bash
94
+ agent-fs write docs/spec.md --content "..." -m "added API section"
95
+ \`\`\`
96
+
97
+ 6. **Optimistic concurrency** \u2014 use \`--expected-version\` on \`write\` to prevent conflicts:
98
+ \`\`\`bash
99
+ agent-fs write config.json --content '{}' --expected-version 3
100
+ # Fails if file is not at version 3
101
+ \`\`\`
102
+
103
+ ## Command Quick Reference
104
+
105
+ ### File Operations
106
+
107
+ | Command | Usage | Description |
108
+ |---------|-------|-------------|
109
+ | \`write\` | \`agent-fs write <path> [--content <text>] [-m <msg>] [--expected-version <n>]\` | Write content (stdin or --content) |
110
+ | \`cat\` | \`agent-fs cat <path> [--offset <n>] [--limit <n>]\` | Read file content |
111
+ | \`edit\` | \`agent-fs edit <path> --old <text> --new <text> [-m <msg>]\` | Find-and-replace in file |
112
+ | \`append\` | \`agent-fs append <path> [--content <text>] [-m <msg>]\` | Append to file (stdin or --content) |
113
+ | \`tail\` | \`agent-fs tail <path> [--lines <n>]\` | Last N lines (default: 20) |
114
+ | \`ls\` | \`agent-fs ls [path]\` | List directory contents (defaults to /) |
115
+ | \`stat\` | \`agent-fs stat <path>\` | Show file metadata (size, version, timestamps) |
116
+ | \`tree\` | \`agent-fs tree [path] [--depth <n>]\` | Recursive directory listing |
117
+ | \`glob\` | \`agent-fs glob <pattern> [path]\` | Find files by pattern (\`*.md\`, \`**/*.md\`) |
118
+ | \`rm\` | \`agent-fs rm <path>\` | Delete a file |
119
+ | \`mv\` | \`agent-fs mv <from> <to> [-m <msg>]\` | Move or rename a file |
120
+ | \`cp\` | \`agent-fs cp <from> <to>\` | Copy a file |
121
+
122
+ ### Versioning
123
+
124
+ | Command | Usage | Description |
125
+ |---------|-------|-------------|
126
+ | \`log\` | \`agent-fs log <path> [--limit <n>]\` | Show version history |
127
+ | \`diff\` | \`agent-fs diff <path> --v1 <n> --v2 <n>\` | Diff between versions |
128
+ | \`revert\` | \`agent-fs revert <path> --version <n>\` | Revert to a previous version |
129
+
130
+ ### Search & Discovery
131
+
132
+ | Command | Usage | Description |
133
+ |---------|-------|-------------|
134
+ | \`grep\` | \`agent-fs grep <pattern> <path>\` | Regex search in file content |
135
+ | \`fts\` | \`agent-fs fts <pattern> [path]\` | Full-text search (FTS5) across all files |
136
+ | \`search\` | \`agent-fs search <query> [--limit <n>]\` | Semantic search using embeddings |
137
+ | \`recent\` | \`agent-fs recent [path] [--since <duration>] [--limit <n>]\` | Recent activity (e.g., \`--since 24h\`) |
138
+ | \`reindex\` | \`agent-fs reindex [path]\` | Re-index files with failed/missing embeddings |
139
+
140
+ **When to use which:**
141
+ - \`grep\` \u2014 you know the exact pattern and path (regex)
142
+ - \`fts\` \u2014 keyword search across all files (fast, FTS5-based)
143
+ - \`search\` \u2014 conceptual/semantic search ("find things about X")
144
+
145
+ ### Comments
146
+
147
+ | Command | Usage | Description |
148
+ |---------|-------|-------------|
149
+ | \`comment add\` | \`agent-fs comment add <path> --body <text> [--line-start <n>] [--line-end <n>]\` | Add a comment to a file |
150
+ | \`comment reply\` | \`agent-fs comment reply <comment-id> --body <text>\` | Reply to a comment |
151
+ | \`comment list\` | \`agent-fs comment list [path]\` | List comments (with inline replies) |
152
+ | \`comment get\` | \`agent-fs comment get <id>\` | Get a comment with its replies |
153
+ | \`comment update\` | \`agent-fs comment update <id> --body <text>\` | Update a comment (author only) |
154
+ | \`comment delete\` | \`agent-fs comment delete <id>\` | Soft-delete a comment (author only) |
155
+ | \`comment resolve\` | \`agent-fs comment resolve <id>\` | Resolve a comment |
156
+
157
+ ### Setup & Auth
158
+
159
+ | Command | Usage | Description |
160
+ |---------|-------|-------------|
161
+ | \`onboard\` | \`agent-fs onboard [--local] [-y] [--embeddings <provider>]\` | Set up agent-fs (S3 + database + user) |
162
+ | \`init\` | \`agent-fs init [--local] [-y]\` | Alias for \`onboard\` |
163
+ | \`auth register\` | \`agent-fs auth register <email>\` | Register a new user |
164
+ | \`auth whoami\` | \`agent-fs auth whoami\` | Show current user info |
165
+
166
+ ### Drive Management
167
+
168
+ | Command | Usage | Description |
169
+ |---------|-------|-------------|
170
+ | \`drive list\` | \`agent-fs drive list\` | List drives in current org |
171
+ | \`drive create\` | \`agent-fs drive create <name>\` | Create a new drive |
172
+ | \`drive current\` | \`agent-fs drive current\` | Show current drive context |
173
+ | \`drive invite\` | \`agent-fs drive invite <email> --role <role>\` | Invite user (viewer/editor/admin) |
174
+
175
+ ### Config & Daemon
176
+
177
+ | Command | Usage | Description |
178
+ |---------|-------|-------------|
179
+ | \`config get\` | \`agent-fs config get <key>\` | Get config value (dot notation: \`s3.bucket\`) |
180
+ | \`config set\` | \`agent-fs config set <key> <value>\` | Set config value |
181
+ | \`config list\` | \`agent-fs config list\` | Show all configuration |
182
+ | \`config validate\` | \`agent-fs config validate\` | Check S3, database, auth, embeddings health |
183
+ | \`daemon start\` | \`agent-fs daemon start\` | Start the background daemon |
184
+ | \`daemon stop\` | \`agent-fs daemon stop\` | Stop the daemon |
185
+ | \`daemon status\` | \`agent-fs daemon status\` | Check if daemon is running |
186
+
187
+ ## Common Workflows
188
+
189
+ ### Store and retrieve a document
190
+
191
+ \`\`\`bash
192
+ # Write a document (multi-line via stdin)
193
+ cat <<'EOF' | agent-fs write reports/q1-summary.md -m "Q1 summary draft"
194
+ # Q1 Summary
195
+ Revenue grew 15% quarter over quarter.
196
+ EOF
197
+
198
+ # Read it back
199
+ agent-fs cat reports/q1-summary.md
200
+
201
+ # Check metadata
202
+ agent-fs stat reports/q1-summary.md
203
+ \`\`\`
204
+
205
+ ### Search across files
206
+
207
+ \`\`\`bash
208
+ # Regex search within a specific path
209
+ agent-fs grep "revenue|growth" reports/
210
+
211
+ # Full-text search across all files (FTS5 \u2014 fast keyword matching)
212
+ agent-fs fts "quarterly revenue"
213
+
214
+ # Semantic search (finds conceptually related content)
215
+ agent-fs search "financial performance metrics" --limit 5
216
+ \`\`\`
217
+
218
+ ### Review and revert changes
219
+
220
+ \`\`\`bash
221
+ # View version history
222
+ agent-fs log docs/spec.md --limit 10
223
+
224
+ # Compare two versions
225
+ agent-fs diff docs/spec.md --v1 2 --v2 5
226
+
227
+ # Revert to version 2
228
+ agent-fs revert docs/spec.md --version 2
229
+ \`\`\`
230
+
231
+ ### Comments and collaboration
232
+
233
+ \`\`\`bash
234
+ # Add a comment to a file
235
+ agent-fs comment add docs/spec.md --body "Needs more detail on auth"
236
+
237
+ # Reply to a comment
238
+ agent-fs comment reply <comment-id> --body "Added in v3"
239
+
240
+ # List comments
241
+ agent-fs comment list docs/spec.md
242
+
243
+ # Resolve a comment
244
+ agent-fs comment resolve <comment-id>
245
+ \`\`\`
246
+
247
+ ### Set up a new drive and invite users
248
+
249
+ \`\`\`bash
250
+ # Create a shared drive
251
+ agent-fs drive create "team-docs"
252
+
253
+ # Invite a teammate
254
+ agent-fs drive invite alice@company.com --role editor
255
+
256
+ # Check current drive context
257
+ agent-fs drive current
258
+ \`\`\`
259
+
260
+ ### Check recent activity
261
+
262
+ \`\`\`bash
263
+ # What changed in the last hour?
264
+ agent-fs recent --since 1h
265
+
266
+ # Recent changes under a specific path
267
+ agent-fs recent docs/ --since 24h --limit 20
268
+ \`\`\`
269
+
270
+ ### Validate your setup
271
+
272
+ \`\`\`bash
273
+ agent-fs config validate
274
+ \`\`\`
275
+ `;function C(){return new ht("docs").description("Show agent-fs documentation and command reference").action(()=>{let n=j.replace(/^---[\s\S]*?---\n*/,"");console.log(n)})}var g=new mt;g.name("agent-fs").description("Agent-first filesystem backed by S3").version(wt).option("--org <orgId>","Override org context").option("--drive <driveId>","Override drive context").option("--json","Output raw JSON");var D=new N;function u(){let n=g.opts().org;if(n)return n;let t=gt();if(t.auth.apiKey)try{let{createDatabase:e}=y("@/core"),i=e(),o=ft(i,t.auth.apiKey);if(o){let a=yt(i,o.id);if(a.length>0)return a[0].id}}catch{}console.error("Error: No org context. Use --org or run 'agent-fs auth register'"),process.exit(1)}g.addCommand(C());G(g,D,u);g.addCommand(H(D));g.addCommand(L());g.addCommand(Y());g.addCommand(z(D));g.addCommand(_());g.addCommand(x());g.addCommand(P(D,u));g.command("mcp").description("Start MCP server (stdio)").action(async()=>{await import("@/mcp/index.js")});g.command("server").description("Run server in foreground (dev mode)").action(async()=>{await import("@/server/index.js")});var vt=`
276
+ Global Options:
277
+ --org <orgId> Override org context
278
+ --drive <driveId> Override drive context
279
+ --json Output raw JSON
280
+ `;for(let n of g.commands)n.addHelpText("after",vt);g.parse();
@@ -0,0 +1,4 @@
1
+ import { Command } from "commander";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function authCommands(client: ApiClient): Command;
4
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQlD,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,WAqE7C"}