climemo 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 (76) hide show
  1. package/dist/commands/ask.d.ts +2 -0
  2. package/dist/commands/ask.js +37 -0
  3. package/dist/commands/ask.js.map +1 -0
  4. package/dist/commands/compare.d.ts +2 -0
  5. package/dist/commands/compare.js +57 -0
  6. package/dist/commands/compare.js.map +1 -0
  7. package/dist/commands/config.d.ts +2 -0
  8. package/dist/commands/config.js +37 -0
  9. package/dist/commands/config.js.map +1 -0
  10. package/dist/commands/daemon.d.ts +2 -0
  11. package/dist/commands/daemon.js +69 -0
  12. package/dist/commands/daemon.js.map +1 -0
  13. package/dist/commands/invite.d.ts +2 -0
  14. package/dist/commands/invite.js +49 -0
  15. package/dist/commands/invite.js.map +1 -0
  16. package/dist/commands/login.d.ts +2 -0
  17. package/dist/commands/login.js +94 -0
  18. package/dist/commands/login.js.map +1 -0
  19. package/dist/commands/logout.d.ts +2 -0
  20. package/dist/commands/logout.js +9 -0
  21. package/dist/commands/logout.js.map +1 -0
  22. package/dist/commands/members.d.ts +2 -0
  23. package/dist/commands/members.js +98 -0
  24. package/dist/commands/members.js.map +1 -0
  25. package/dist/commands/merge.d.ts +2 -0
  26. package/dist/commands/merge.js +120 -0
  27. package/dist/commands/merge.js.map +1 -0
  28. package/dist/commands/search.d.ts +2 -0
  29. package/dist/commands/search.js +32 -0
  30. package/dist/commands/search.js.map +1 -0
  31. package/dist/commands/sync.d.ts +2 -0
  32. package/dist/commands/sync.js +200 -0
  33. package/dist/commands/sync.js.map +1 -0
  34. package/dist/commands/token.d.ts +2 -0
  35. package/dist/commands/token.js +60 -0
  36. package/dist/commands/token.js.map +1 -0
  37. package/dist/commands/whoami.d.ts +2 -0
  38. package/dist/commands/whoami.js +20 -0
  39. package/dist/commands/whoami.js.map +1 -0
  40. package/dist/daemon/index.d.ts +2 -0
  41. package/dist/daemon/index.js +27 -0
  42. package/dist/daemon/index.js.map +1 -0
  43. package/dist/daemon/install.d.ts +13 -0
  44. package/dist/daemon/install.js +143 -0
  45. package/dist/daemon/install.js.map +1 -0
  46. package/dist/daemon/logger.d.ts +8 -0
  47. package/dist/daemon/logger.js +41 -0
  48. package/dist/daemon/logger.js.map +1 -0
  49. package/dist/daemon/token-refresher.d.ts +14 -0
  50. package/dist/daemon/token-refresher.js +88 -0
  51. package/dist/daemon/token-refresher.js.map +1 -0
  52. package/dist/index.d.ts +2 -0
  53. package/dist/index.js +40 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/lib/api.d.ts +13 -0
  56. package/dist/lib/api.js +18 -0
  57. package/dist/lib/api.js.map +1 -0
  58. package/dist/lib/auth.d.ts +24 -0
  59. package/dist/lib/auth.js +72 -0
  60. package/dist/lib/auth.js.map +1 -0
  61. package/dist/lib/config.d.ts +9 -0
  62. package/dist/lib/config.js +36 -0
  63. package/dist/lib/config.js.map +1 -0
  64. package/dist/lib/git.d.ts +24 -0
  65. package/dist/lib/git.js +63 -0
  66. package/dist/lib/git.js.map +1 -0
  67. package/dist/lib/keychain.d.ts +4 -0
  68. package/dist/lib/keychain.js +39 -0
  69. package/dist/lib/keychain.js.map +1 -0
  70. package/dist/lib/project.d.ts +13 -0
  71. package/dist/lib/project.js +133 -0
  72. package/dist/lib/project.js.map +1 -0
  73. package/dist/lib/server.d.ts +9 -0
  74. package/dist/lib/server.js +80 -0
  75. package/dist/lib/server.js.map +1 -0
  76. package/package.json +48 -0
@@ -0,0 +1,120 @@
1
+ import { Command } from "commander";
2
+ import { apiRequest } from "../lib/api.js";
3
+ import { resolveProject } from "../lib/project.js";
4
+ export const mergeCommand = new Command("merge")
5
+ .description("Merge a source project into the current repo's project")
6
+ .argument("<sourceProjectId>", "ID of the source project to merge from")
7
+ .option("--force", "Overwrite conflicting docs with the source version")
8
+ .action(async (sourceProjectId, options, cmd) => {
9
+ const globalOpts = cmd.optsWithGlobals();
10
+ try {
11
+ // Auto-detect target project from the current git repo
12
+ const targetProjectId = await resolveProject(globalOpts.token);
13
+ if (sourceProjectId === targetProjectId) {
14
+ console.error(JSON.stringify({ error: "Source and target projects are the same" }));
15
+ process.exit(1);
16
+ }
17
+ // Fetch docs from both projects in parallel
18
+ const [sourceRes, targetRes] = await Promise.all([
19
+ apiRequest(`/api/projects/${sourceProjectId}/documents`, {
20
+ token: globalOpts.token,
21
+ }),
22
+ apiRequest(`/api/projects/${targetProjectId}/documents`, {
23
+ token: globalOpts.token,
24
+ }),
25
+ ]);
26
+ if (!sourceRes.ok || !sourceRes.data) {
27
+ console.error(JSON.stringify({
28
+ error: "Failed to fetch source project documents",
29
+ details: sourceRes.data,
30
+ }));
31
+ process.exit(1);
32
+ }
33
+ if (!targetRes.ok || !targetRes.data) {
34
+ console.error(JSON.stringify({
35
+ error: "Failed to fetch target project documents",
36
+ details: targetRes.data,
37
+ }));
38
+ process.exit(1);
39
+ }
40
+ const sourceDocs = sourceRes.data.data || [];
41
+ const targetDocs = targetRes.data.data || [];
42
+ const targetPaths = new Set(targetDocs.map((d) => d.path));
43
+ let moved = 0;
44
+ let overwritten = 0;
45
+ let skipped = 0;
46
+ const conflicts = [];
47
+ for (const doc of sourceDocs) {
48
+ const hasConflict = targetPaths.has(doc.path);
49
+ if (hasConflict && !options.force) {
50
+ conflicts.push(doc.path);
51
+ skipped++;
52
+ continue;
53
+ }
54
+ if (hasConflict && options.force) {
55
+ // Find the target doc to update
56
+ const targetDoc = targetDocs.find((d) => d.path === doc.path);
57
+ if (targetDoc) {
58
+ const { ok } = await apiRequest(`/api/projects/${targetProjectId}/documents/${targetDoc.id}`, {
59
+ method: "PATCH",
60
+ body: {
61
+ content: doc.content,
62
+ title: doc.title,
63
+ change_summary: "Overwritten during merge",
64
+ },
65
+ token: globalOpts.token,
66
+ });
67
+ if (ok)
68
+ overwritten++;
69
+ }
70
+ // Delete from source
71
+ await apiRequest(`/api/projects/${sourceProjectId}/documents/${doc.id}`, { method: "DELETE", token: globalOpts.token });
72
+ }
73
+ else {
74
+ // No conflict — create in target
75
+ const { ok } = await apiRequest(`/api/projects/${targetProjectId}/documents`, {
76
+ method: "POST",
77
+ body: {
78
+ title: doc.title,
79
+ path: doc.path,
80
+ content: doc.content,
81
+ updated_via: "cli-merge",
82
+ },
83
+ token: globalOpts.token,
84
+ });
85
+ if (ok)
86
+ moved++;
87
+ // Delete from source
88
+ await apiRequest(`/api/projects/${sourceProjectId}/documents/${doc.id}`, { method: "DELETE", token: globalOpts.token });
89
+ }
90
+ }
91
+ // Check if source project is now empty, and delete it if so
92
+ let sourceDeleted = false;
93
+ const remainRes = await apiRequest(`/api/projects/${sourceProjectId}/documents`, { token: globalOpts.token });
94
+ const remaining = remainRes.ok && remainRes.data
95
+ ? remainRes.data.data || []
96
+ : [];
97
+ if (remaining.length === 0) {
98
+ const delRes = await apiRequest(`/api/projects/${sourceProjectId}`, { method: "DELETE", token: globalOpts.token });
99
+ sourceDeleted = delRes.ok;
100
+ }
101
+ if (conflicts.length > 0) {
102
+ console.error(JSON.stringify({
103
+ warning: "Conflicting docs skipped (use --force to overwrite)",
104
+ conflicts,
105
+ }));
106
+ }
107
+ console.log(JSON.stringify({
108
+ target_project: targetProjectId,
109
+ source_project: sourceProjectId,
110
+ merged: { moved, overwritten, skipped },
111
+ source_deleted: sourceDeleted,
112
+ }, null, 2));
113
+ }
114
+ catch (err) {
115
+ const message = err instanceof Error ? err.message : String(err);
116
+ console.error(JSON.stringify({ error: message }));
117
+ process.exit(1);
118
+ }
119
+ });
120
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/commands/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const searchCommand: Command;
@@ -0,0 +1,32 @@
1
+ import { Command } from "commander";
2
+ import { apiRequest } from "../lib/api.js";
3
+ import { resolveProject } from "../lib/project.js";
4
+ export const searchCommand = new Command("search")
5
+ .description("Cross-project document search")
6
+ .argument("<query>", "Search query")
7
+ .option("--project <projectId>", "Project ID (auto-detected from git repo if omitted)")
8
+ .option("--all", "Search across all projects, not just current repo")
9
+ .action(async (query, options, cmd) => {
10
+ const globalOpts = cmd.optsWithGlobals();
11
+ try {
12
+ const params = new URLSearchParams({ q: query });
13
+ if (!options.all) {
14
+ const projectId = options.project || await resolveProject(globalOpts.token);
15
+ params.set("project_id", projectId);
16
+ }
17
+ const { ok, data } = await apiRequest(`/api/search?${params}`, {
18
+ token: globalOpts.token,
19
+ });
20
+ if (!ok) {
21
+ console.error(JSON.stringify({ error: "Search failed", details: data }));
22
+ process.exit(1);
23
+ }
24
+ console.log(JSON.stringify(data, null, 2));
25
+ }
26
+ catch (err) {
27
+ const message = err instanceof Error ? err.message : String(err);
28
+ console.error(JSON.stringify({ error: message }));
29
+ process.exit(1);
30
+ }
31
+ });
32
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,+BAA+B,CAAC;KAC5C,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;KACnC,MAAM,CAAC,uBAAuB,EAAE,qDAAqD,CAAC;KACtF,MAAM,CAAC,OAAO,EAAE,mDAAmD,CAAC;KACpE,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE;IAC5C,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;IAEzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAEjD,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,cAAc,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAC5E,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,UAAU,CAAC,eAAe,MAAM,EAAE,EAAE;YAC7D,KAAK,EAAE,UAAU,CAAC,KAAK;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const syncCommand: Command;
@@ -0,0 +1,200 @@
1
+ import { Command } from "commander";
2
+ import { readFileSync, existsSync } from "fs";
3
+ import { resolve, relative, basename } from "path";
4
+ import { execSync } from "child_process";
5
+ import { apiRequest } from "../lib/api.js";
6
+ import { resolveProject } from "../lib/project.js";
7
+ import { getGitInfo, parseGitHubRemote } from "../lib/git.js";
8
+ /**
9
+ * Find markdown/text files that are likely project documentation.
10
+ */
11
+ function findDocFiles(rootPath) {
12
+ try {
13
+ // Use git ls-files to respect .gitignore
14
+ const output = execSync('git ls-files --cached --others --exclude-standard -- "*.md" "*.mdx" "CLAUDE.md" "TASKS.md" "docs/**"', { cwd: rootPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
15
+ return output
16
+ .trim()
17
+ .split("\n")
18
+ .filter((f) => f.length > 0)
19
+ .map((f) => resolve(rootPath, f));
20
+ }
21
+ catch {
22
+ return [];
23
+ }
24
+ }
25
+ export const syncCommand = new Command("sync")
26
+ .description("Sync local docs to your climemo project (auto-detects git repo)")
27
+ .option("--project <projectId>", "Project ID (auto-detected from git repo if omitted)")
28
+ .option("--dry-run", "Show what would be synced without making changes")
29
+ .option("--no-team", "Skip auto-inviting GitHub repo collaborators")
30
+ .option("--pattern <glob>", "Additional file pattern to include (e.g. '**/*.txt')")
31
+ .action(async (options, cmd) => {
32
+ const globalOpts = cmd.optsWithGlobals();
33
+ try {
34
+ const git = getGitInfo();
35
+ if (!git) {
36
+ console.error(JSON.stringify({ error: "Not inside a git repository." }));
37
+ process.exit(1);
38
+ }
39
+ const projectId = options.project || await resolveProject(globalOpts.token);
40
+ // Find doc files
41
+ let files = findDocFiles(git.rootPath);
42
+ // Add extra pattern if specified
43
+ if (options.pattern) {
44
+ try {
45
+ const extra = execSync(`git ls-files --cached --others --exclude-standard -- "${options.pattern}"`, { cwd: git.rootPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
46
+ const extraFiles = extra.trim().split("\n").filter((f) => f.length > 0).map((f) => resolve(git.rootPath, f));
47
+ files = [...new Set([...files, ...extraFiles])];
48
+ }
49
+ catch {
50
+ // ignore
51
+ }
52
+ }
53
+ if (files.length === 0) {
54
+ console.log(JSON.stringify({ message: "No documentation files found.", hint: "Add .md files or use --pattern" }));
55
+ return;
56
+ }
57
+ if (options.dryRun) {
58
+ const list = files.map((f) => "/" + relative(git.rootPath, f));
59
+ console.log(JSON.stringify({ dry_run: true, files: list }, null, 2));
60
+ return;
61
+ }
62
+ // Get existing documents in the project
63
+ const { ok: listOk, data: listData } = await apiRequest(`/api/projects/${projectId}/documents`, { token: globalOpts.token });
64
+ const existingDocs = listOk && listData ? listData.data || [] : [];
65
+ const existingByPath = new Map(existingDocs.map((d) => [d.path, d]));
66
+ let created = 0;
67
+ let updated = 0;
68
+ let skipped = 0;
69
+ let conflicts = 0;
70
+ const conflictDetails = [];
71
+ for (const filePath of files) {
72
+ if (!existsSync(filePath))
73
+ continue;
74
+ const content = readFileSync(filePath, "utf-8");
75
+ const docPath = "/" + relative(git.rootPath, filePath);
76
+ const title = basename(filePath);
77
+ const existing = existingByPath.get(docPath);
78
+ if (existing) {
79
+ // Skip if content unchanged
80
+ if (existing.content === content) {
81
+ skipped++;
82
+ continue;
83
+ }
84
+ // Update with optimistic locking
85
+ const { ok, status, data } = await apiRequest(`/api/projects/${projectId}/documents/${existing.id}`, {
86
+ method: "PATCH",
87
+ body: {
88
+ content,
89
+ title,
90
+ change_summary: "Synced from CLI",
91
+ expected_version: existing.current_version,
92
+ },
93
+ token: globalOpts.token,
94
+ });
95
+ if (ok) {
96
+ updated++;
97
+ }
98
+ else if (status === 409) {
99
+ conflicts++;
100
+ const conflictData = data;
101
+ conflictDetails.push({
102
+ path: docPath,
103
+ reason: conflictData?.message || "Document was modified by another user",
104
+ });
105
+ }
106
+ }
107
+ else {
108
+ // Create
109
+ const { ok, status } = await apiRequest(`/api/projects/${projectId}/documents`, {
110
+ method: "POST",
111
+ body: { title, path: docPath, content, updated_via: "cli" },
112
+ token: globalOpts.token,
113
+ });
114
+ if (ok) {
115
+ created++;
116
+ }
117
+ else if (status === 409 || status === 422 || status === 500) {
118
+ // Constraint violation (UNIQUE(project_id, path)) — another user
119
+ // created the same doc concurrently. Retry as an update.
120
+ const { ok: retryListOk, data: retryListData } = await apiRequest(`/api/projects/${projectId}/documents`, { token: globalOpts.token });
121
+ if (retryListOk && retryListData) {
122
+ const retryDocs = retryListData.data || [];
123
+ const retryDoc = retryDocs.find((d) => d.path === docPath);
124
+ if (retryDoc) {
125
+ const { ok: updateOk, status: updateStatus, data: updateData } = await apiRequest(`/api/projects/${projectId}/documents/${retryDoc.id}`, {
126
+ method: "PATCH",
127
+ body: {
128
+ content,
129
+ title,
130
+ change_summary: "Synced from CLI",
131
+ expected_version: retryDoc.current_version,
132
+ },
133
+ token: globalOpts.token,
134
+ });
135
+ if (updateOk) {
136
+ updated++;
137
+ }
138
+ else if (updateStatus === 409) {
139
+ conflicts++;
140
+ const conflictData = updateData;
141
+ conflictDetails.push({
142
+ path: docPath,
143
+ reason: conflictData?.message || "Document was modified by another user during sync",
144
+ });
145
+ }
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ const result = {
152
+ project_id: projectId,
153
+ synced: { created, updated, skipped, conflicts, total: files.length },
154
+ };
155
+ if (conflictDetails.length > 0) {
156
+ result.conflict_details = conflictDetails;
157
+ }
158
+ // Auto-invite GitHub collaborators (default: on, skip with --no-team)
159
+ if (options.team !== false) {
160
+ const ghRepo = parseGitHubRemote(git.remoteUrl);
161
+ if (!ghRepo) {
162
+ result.team = { error: "Not a GitHub repository. --team requires a GitHub remote." };
163
+ }
164
+ else {
165
+ // Get the project's organization_id
166
+ const { ok: projOk, data: projData } = await apiRequest(`/api/projects/${projectId}`, { token: globalOpts.token });
167
+ const orgId = projOk && projData
168
+ ? projData.data?.organization_id
169
+ : null;
170
+ if (!orgId) {
171
+ result.team = { error: "Could not determine workspace for auto-invite." };
172
+ }
173
+ else {
174
+ const { ok: invOk, data: invData } = await apiRequest("/api/organizations/auto-invite", {
175
+ method: "POST",
176
+ body: {
177
+ github_owner: ghRepo.owner,
178
+ github_repo: ghRepo.repo,
179
+ organization_id: orgId,
180
+ },
181
+ token: globalOpts.token,
182
+ });
183
+ if (invOk && invData) {
184
+ result.team = invData.data;
185
+ }
186
+ else {
187
+ result.team = { error: "Auto-invite failed", details: invData };
188
+ }
189
+ }
190
+ }
191
+ }
192
+ console.log(JSON.stringify(result, null, 2));
193
+ }
194
+ catch (err) {
195
+ const message = err instanceof Error ? err.message : String(err);
196
+ console.error(JSON.stringify({ error: message }));
197
+ process.exit(1);
198
+ }
199
+ });
200
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE9D;;GAEG;AACH,SAAS,YAAY,CAAC,QAAgB;IACpC,IAAI,CAAC;QACH,yCAAyC;QACzC,MAAM,MAAM,GAAG,QAAQ,CACrB,sGAAsG,EACtG,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACtE,CAAC;QACF,OAAO,MAAM;aACV,IAAI,EAAE;aACN,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;aAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,iEAAiE,CAAC;KAC9E,MAAM,CAAC,uBAAuB,EAAE,qDAAqD,CAAC;KACtF,MAAM,CAAC,WAAW,EAAE,kDAAkD,CAAC;KACvE,MAAM,CAAC,WAAW,EAAE,8CAA8C,CAAC;KACnE,MAAM,CAAC,kBAAkB,EAAE,sDAAsD,CAAC;KAClF,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE;IAC7B,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;IAEzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;QACzB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,cAAc,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAE5E,iBAAiB;QACjB,IAAI,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEvC,iCAAiC;QACjC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,QAAQ,CACpB,yDAAyD,OAAO,CAAC,OAAO,GAAG,EAC3E,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAC1E,CAAC;gBACF,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7G,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,+BAA+B,EAAE,IAAI,EAAE,gCAAgC,EAAE,CAAC,CAAC,CAAC;YAClH,OAAO;QACT,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/D,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,wCAAwC;QACxC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,UAAU,CACrD,iBAAiB,SAAS,YAAY,EACtC,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAC5B,CAAC;QAEF,MAAM,YAAY,GAChB,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAE,QAA+F,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAExI,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAErE,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,MAAM,eAAe,GAAuC,EAAE,CAAC;QAE/D,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAEpC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAChD,MAAM,OAAO,GAAG,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAEjC,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAE7C,IAAI,QAAQ,EAAE,CAAC;gBACb,4BAA4B;gBAC5B,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;oBACjC,OAAO,EAAE,CAAC;oBACV,SAAS;gBACX,CAAC;gBAED,iCAAiC;gBACjC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,UAAU,CAC3C,iBAAiB,SAAS,cAAc,QAAQ,CAAC,EAAE,EAAE,EACrD;oBACE,MAAM,EAAE,OAAO;oBACf,IAAI,EAAE;wBACJ,OAAO;wBACP,KAAK;wBACL,cAAc,EAAE,iBAAiB;wBACjC,gBAAgB,EAAE,QAAQ,CAAC,eAAe;qBAC3C;oBACD,KAAK,EAAE,UAAU,CAAC,KAAK;iBACxB,CACF,CAAC;gBAEF,IAAI,EAAE,EAAE,CAAC;oBACP,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC1B,SAAS,EAAE,CAAC;oBACZ,MAAM,YAAY,GAAG,IAA6D,CAAC;oBACnF,eAAe,CAAC,IAAI,CAAC;wBACnB,IAAI,EAAE,OAAO;wBACb,MAAM,EAAE,YAAY,EAAE,OAAO,IAAI,uCAAuC;qBACzE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,SAAS;gBACT,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU,CACrC,iBAAiB,SAAS,YAAY,EACtC;oBACE,MAAM,EAAE,MAAM;oBACd,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE;oBAC3D,KAAK,EAAE,UAAU,CAAC,KAAK;iBACxB,CACF,CAAC;gBAEF,IAAI,EAAE,EAAE,CAAC;oBACP,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC9D,iEAAiE;oBACjE,yDAAyD;oBACzD,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,MAAM,UAAU,CAC/D,iBAAiB,SAAS,YAAY,EACtC,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAC5B,CAAC;oBAEF,IAAI,WAAW,IAAI,aAAa,EAAE,CAAC;wBACjC,MAAM,SAAS,GAAI,aAAmF,CAAC,IAAI,IAAI,EAAE,CAAC;wBAClH,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;wBAC3D,IAAI,QAAQ,EAAE,CAAC;4BACb,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,UAAU,CAC/E,iBAAiB,SAAS,cAAc,QAAQ,CAAC,EAAE,EAAE,EACrD;gCACE,MAAM,EAAE,OAAO;gCACf,IAAI,EAAE;oCACJ,OAAO;oCACP,KAAK;oCACL,cAAc,EAAE,iBAAiB;oCACjC,gBAAgB,EAAE,QAAQ,CAAC,eAAe;iCAC3C;gCACD,KAAK,EAAE,UAAU,CAAC,KAAK;6BACxB,CACF,CAAC;4BAEF,IAAI,QAAQ,EAAE,CAAC;gCACb,OAAO,EAAE,CAAC;4BACZ,CAAC;iCAAM,IAAI,YAAY,KAAK,GAAG,EAAE,CAAC;gCAChC,SAAS,EAAE,CAAC;gCACZ,MAAM,YAAY,GAAG,UAAyC,CAAC;gCAC/D,eAAe,CAAC,IAAI,CAAC;oCACnB,IAAI,EAAE,OAAO;oCACb,MAAM,EAAE,YAAY,EAAE,OAAO,IAAI,mDAAmD;iCACrF,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAA4B;YACtC,UAAU,EAAE,SAAS;YACrB,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE;SACtE,CAAC;QACF,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,gBAAgB,GAAG,eAAe,CAAC;QAC5C,CAAC;QAED,sEAAsE;QACtE,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAChD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,2DAA2D,EAAE,CAAC;YACvF,CAAC;iBAAM,CAAC;gBACN,oCAAoC;gBACpC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,UAAU,CACrD,iBAAiB,SAAS,EAAE,EAC5B,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAC5B,CAAC;gBACF,MAAM,KAAK,GAAG,MAAM,IAAI,QAAQ;oBAC9B,CAAC,CAAE,QAAkD,CAAC,IAAI,EAAE,eAAe;oBAC3E,CAAC,CAAC,IAAI,CAAC;gBAET,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,MAAM,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,gDAAgD,EAAE,CAAC;gBAC5E,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CACnD,gCAAgC,EAChC;wBACE,MAAM,EAAE,MAAM;wBACd,IAAI,EAAE;4BACJ,YAAY,EAAE,MAAM,CAAC,KAAK;4BAC1B,WAAW,EAAE,MAAM,CAAC,IAAI;4BACxB,eAAe,EAAE,KAAK;yBACvB;wBACD,KAAK,EAAE,UAAU,CAAC,KAAK;qBACxB,CACF,CAAC;oBAEF,IAAI,KAAK,IAAI,OAAO,EAAE,CAAC;wBACrB,MAAM,CAAC,IAAI,GAAI,OAA6B,CAAC,IAAI,CAAC;oBACpD,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;oBAClE,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const tokenCommand: Command;
@@ -0,0 +1,60 @@
1
+ import { Command } from "commander";
2
+ import { getAccessToken, getRefreshToken } from "../lib/keychain.js";
3
+ import { refreshAccessToken, getAuthHeaders } from "../lib/auth.js";
4
+ import { getConfig } from "../lib/config.js";
5
+ export const tokenCommand = new Command("token")
6
+ .description("Token management");
7
+ tokenCommand
8
+ .command("create")
9
+ .description("Create a new API token (for CI/CD)")
10
+ .option("--name <name>", "Token name", "ci-token")
11
+ .option("--expires <duration>", "Expiry duration", "24h")
12
+ .action(async (options, cmd) => {
13
+ const globalOpts = cmd.optsWithGlobals();
14
+ const config = getConfig();
15
+ try {
16
+ const headers = await getAuthHeaders(globalOpts.token);
17
+ const res = await fetch(`${config.apiUrl}/api/cli/token/create`, {
18
+ method: "POST",
19
+ headers,
20
+ body: JSON.stringify({ name: options.name, expires: options.expires }),
21
+ });
22
+ if (!res.ok) {
23
+ console.error("Failed to create token:", await res.text());
24
+ process.exit(1);
25
+ }
26
+ const data = await res.json();
27
+ console.log(JSON.stringify(data, null, 2));
28
+ }
29
+ catch (err) {
30
+ const message = err instanceof Error ? err.message : String(err);
31
+ console.error("Error:", message);
32
+ process.exit(1);
33
+ }
34
+ });
35
+ tokenCommand
36
+ .command("refresh")
37
+ .description("Manually refresh the access token")
38
+ .action(async () => {
39
+ const success = await refreshAccessToken();
40
+ if (success) {
41
+ console.log("Token refreshed and stored in Keychain.");
42
+ }
43
+ else {
44
+ console.log("Failed to refresh token. Run `climemo login` to re-authenticate.");
45
+ process.exit(1);
46
+ }
47
+ });
48
+ tokenCommand
49
+ .command("status")
50
+ .description("Check token status")
51
+ .action(async () => {
52
+ const accessToken = await getAccessToken();
53
+ const refreshToken = await getRefreshToken();
54
+ console.log(JSON.stringify({
55
+ access_token: accessToken ? "stored" : "none",
56
+ refresh_token: refreshToken ? "stored" : "none",
57
+ storage: "os_keychain",
58
+ }, null, 2));
59
+ });
60
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/commands/token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const whoamiCommand: Command;
@@ -0,0 +1,20 @@
1
+ import { Command } from "commander";
2
+ import { resolveToken, validateToken } from "../lib/auth.js";
3
+ export const whoamiCommand = new Command("whoami")
4
+ .description("Show current authenticated user")
5
+ .action(async (_, cmd) => {
6
+ const globalOpts = cmd.optsWithGlobals();
7
+ const token = await resolveToken(globalOpts.token);
8
+ if (!token) {
9
+ console.log("Not logged in. Run `climemo login` to authenticate.");
10
+ process.exit(1);
11
+ }
12
+ const { valid, email, expires_at } = await validateToken(token);
13
+ if (!valid) {
14
+ console.log("Token is invalid or expired. Run `climemo login` to re-authenticate.");
15
+ process.exit(1);
16
+ }
17
+ // JSON output (default for CLI, agent-friendly)
18
+ console.log(JSON.stringify({ email, expires_at, source: globalOpts.token ? "flag" : process.env.CLIMEMO_TOKEN ? "env" : "keychain" }, null, 2));
19
+ });
20
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE7D,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,iCAAiC,CAAC;KAC9C,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE;IACvB,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAEnD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;IAEhE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;QACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,gDAAgD;IAChD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAClJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { TokenRefresher } from "./token-refresher.js";
3
+ import { DaemonLogger } from "./logger.js";
4
+ const logger = new DaemonLogger();
5
+ async function main() {
6
+ logger.info("Climemo daemon starting...");
7
+ const tokenRefresher = new TokenRefresher(logger);
8
+ // Start token refresh loop (check every 30 minutes)
9
+ tokenRefresher.start(30 * 60 * 1000);
10
+ // Handle graceful shutdown
11
+ process.on("SIGINT", () => {
12
+ logger.info("Daemon shutting down...");
13
+ tokenRefresher.stop();
14
+ process.exit(0);
15
+ });
16
+ process.on("SIGTERM", () => {
17
+ logger.info("Daemon shutting down...");
18
+ tokenRefresher.stop();
19
+ process.exit(0);
20
+ });
21
+ logger.info("Daemon started. Token auto-refresh active.");
22
+ }
23
+ main().catch((err) => {
24
+ logger.error("Daemon failed to start:", err);
25
+ process.exit(1);
26
+ });
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;AAElC,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAE1C,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAElD,oDAAoD;IACpD,cAAc,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAErC,2BAA2B;IAC3B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACvC,cAAc,CAAC,IAAI,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACvC,cAAc,CAAC,IAAI,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { DaemonLogger } from "./logger.js";
2
+ /**
3
+ * Install the daemon as a launchd service (macOS)
4
+ */
5
+ export declare function installDaemon(logger?: DaemonLogger): void;
6
+ /**
7
+ * Uninstall the daemon
8
+ */
9
+ export declare function uninstallDaemon(logger?: DaemonLogger): void;
10
+ /**
11
+ * Check if daemon is running
12
+ */
13
+ export declare function isDaemonRunning(): boolean;