iteration-cli 0.9.1 → 0.10.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 (41) hide show
  1. package/README.md +4 -0
  2. package/dist/cli.js +18207 -429
  3. package/dist/cursor-hook-entry.js +11667 -139
  4. package/dist/launcher.js +6731 -0
  5. package/package.json +4 -3
  6. package/dist/auto-connect.d.ts +0 -32
  7. package/dist/auto-connect.js +0 -235
  8. package/dist/background-service.d.ts +0 -7
  9. package/dist/background-service.js +0 -37
  10. package/dist/claude-transcript.d.ts +0 -6
  11. package/dist/claude-transcript.js +0 -256
  12. package/dist/clerk-device-auth.d.ts +0 -7
  13. package/dist/clerk-device-auth.js +0 -279
  14. package/dist/cli.d.ts +0 -2
  15. package/dist/collector-fetch.d.ts +0 -9
  16. package/dist/collector-fetch.js +0 -57
  17. package/dist/collector.d.ts +0 -17
  18. package/dist/collector.js +0 -268
  19. package/dist/cursor-hook-entry.d.ts +0 -1
  20. package/dist/cursor-hooks.d.ts +0 -7
  21. package/dist/cursor-hooks.js +0 -163
  22. package/dist/cursor-transcript.d.ts +0 -8
  23. package/dist/cursor-transcript.js +0 -294
  24. package/dist/history-import.d.ts +0 -17
  25. package/dist/history-import.js +0 -63
  26. package/dist/launch-agent.d.ts +0 -13
  27. package/dist/launch-agent.js +0 -183
  28. package/dist/redact-trace.d.ts +0 -2
  29. package/dist/redact-trace.js +0 -186
  30. package/dist/rollout.d.ts +0 -11
  31. package/dist/rollout.js +0 -259
  32. package/dist/service.d.ts +0 -5
  33. package/dist/service.js +0 -249
  34. package/dist/status-view.d.ts +0 -33
  35. package/dist/status-view.js +0 -257
  36. package/dist/storage.d.ts +0 -94
  37. package/dist/storage.js +0 -809
  38. package/dist/systemd-user.d.ts +0 -7
  39. package/dist/systemd-user.js +0 -137
  40. package/dist/turn-summary.d.ts +0 -23
  41. package/dist/turn-summary.js +0 -365
@@ -1,163 +0,0 @@
1
- import { promises as fs } from "node:fs";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import * as z from "zod";
5
- import { ensurePrivateDirectory } from "./storage.js";
6
- export const CURSOR_HOOKS = [
7
- "sessionStart",
8
- "beforeSubmitPrompt",
9
- "preToolUse",
10
- "postToolUse",
11
- "postToolUseFailure",
12
- "afterAgentThought",
13
- "afterAgentResponse",
14
- "preCompact",
15
- "stop",
16
- "subagentStart",
17
- "subagentStop",
18
- "sessionEnd",
19
- ];
20
- export function cursorHookDirectory(dataDirectory) {
21
- return path.join(dataDirectory, "cursor-hooks");
22
- }
23
- export function cursorHookFailurePath(dataDirectory) {
24
- return path.join(dataDirectory, "cursor-hook-failure.json");
25
- }
26
- export async function cursorHookFailureAtMs(dataDirectory) {
27
- let contents;
28
- try {
29
- contents = await fs.readFile(cursorHookFailurePath(dataDirectory), "utf8");
30
- }
31
- catch (error) {
32
- if (error instanceof Error && "code" in error && error.code === "ENOENT")
33
- return null;
34
- throw error;
35
- }
36
- let decoded;
37
- try {
38
- decoded = JSON.parse(contents);
39
- }
40
- catch (error) {
41
- throw new Error("Cursor hook failure status is invalid.", { cause: error });
42
- }
43
- const parsed = z
44
- .object({ atMs: z.number().int().min(0) })
45
- .strict()
46
- .safeParse(decoded);
47
- if (!parsed.success)
48
- throw new Error("Cursor hook failure status is invalid.");
49
- return parsed.data.atMs;
50
- }
51
- function shellQuote(value) {
52
- return `'${value.replaceAll("'", `'\\''`)}'`;
53
- }
54
- function hookCommand(hook, dataDirectory) {
55
- const entry = fileURLToPath(new URL("./cursor-hook-entry.js", import.meta.url));
56
- return `${shellQuote(process.execPath)} ${shellQuote(entry)} ${shellQuote(hook)} ${shellQuote(dataDirectory)}`;
57
- }
58
- const hookEntrySchema = z.object({ command: z.string().optional() }).loose();
59
- const hookFileSchema = z
60
- .object({
61
- version: z.literal(1).optional(),
62
- hooks: z.record(z.string(), z.array(hookEntrySchema)).optional(),
63
- })
64
- .loose();
65
- async function readHooks(filename) {
66
- let contents;
67
- let mode = 0o600;
68
- try {
69
- contents = await fs.readFile(filename, "utf8");
70
- mode = (await fs.stat(filename)).mode & 0o777;
71
- }
72
- catch (error) {
73
- if (error instanceof Error && "code" in error && error.code === "ENOENT")
74
- return { file: {}, mode };
75
- throw new Error(`Could not read Cursor hooks at ${filename}.`, {
76
- cause: error,
77
- });
78
- }
79
- let parsed;
80
- try {
81
- parsed = JSON.parse(contents);
82
- }
83
- catch (error) {
84
- throw new Error(`Cursor hooks at ${filename} are not valid JSON.`, {
85
- cause: error,
86
- });
87
- }
88
- const checked = hookFileSchema.safeParse(parsed);
89
- if (!checked.success)
90
- throw new Error(`Cursor hooks at ${filename} have an unexpected shape.`);
91
- return { file: checked.data, mode };
92
- }
93
- async function writeHooks(filename, file, mode) {
94
- await ensurePrivateDirectory(path.dirname(filename));
95
- const target = await fs.realpath(filename).catch((error) => {
96
- if (error instanceof Error && "code" in error && error.code === "ENOENT")
97
- return filename;
98
- throw error;
99
- });
100
- const temporary = `${target}.iteration-${process.pid}.tmp`;
101
- const handle = await fs.open(temporary, "w", mode);
102
- try {
103
- await handle.writeFile(`${JSON.stringify(file, null, 2)}\n`, "utf8");
104
- await handle.sync();
105
- }
106
- finally {
107
- await handle.close();
108
- }
109
- await fs.rename(temporary, target);
110
- }
111
- function entries(value) {
112
- return value ?? [];
113
- }
114
- export async function installCursorHooks(cursorHome, dataDirectory) {
115
- await ensurePrivateDirectory(cursorHookDirectory(dataDirectory));
116
- const filename = path.join(cursorHome, "hooks.json");
117
- const { file, mode } = await readHooks(filename);
118
- const hooks = { ...file.hooks };
119
- for (const hook of CURSOR_HOOKS) {
120
- const command = hookCommand(hook, dataDirectory);
121
- const existing = entries(hooks[hook]);
122
- if (!existing.some((entry) => entry.command === command))
123
- hooks[hook] = [...existing, { command }];
124
- }
125
- await writeHooks(filename, { ...file, version: 1, hooks }, mode);
126
- }
127
- export async function uninstallCursorHooks(cursorHome, dataDirectory) {
128
- const filename = path.join(cursorHome, "hooks.json");
129
- const { file, mode } = await readHooks(filename);
130
- const hooks = { ...file.hooks };
131
- let changed = false;
132
- for (const hook of CURSOR_HOOKS) {
133
- const existing = entries(hooks[hook]);
134
- const remaining = existing.filter((entry) => entry.command !== hookCommand(hook, dataDirectory));
135
- if (remaining.length !== existing.length) {
136
- changed = true;
137
- if (remaining.length === 0)
138
- delete hooks[hook];
139
- else
140
- hooks[hook] = remaining;
141
- }
142
- }
143
- if (changed)
144
- await writeHooks(filename, { ...file, hooks }, mode);
145
- }
146
- export async function cursorHookFiles(dataDirectory) {
147
- const directory = cursorHookDirectory(dataDirectory);
148
- let names;
149
- try {
150
- names = await fs.readdir(directory);
151
- }
152
- catch (error) {
153
- if (error instanceof Error && "code" in error && error.code === "ENOENT")
154
- return [];
155
- throw error;
156
- }
157
- if (names.length > 10_000)
158
- throw new Error("Cursor hook queue exceeds the scan limit.");
159
- return names
160
- .filter((name) => /^[0-9a-f-]+\.jsonl$/i.test(name))
161
- .sort()
162
- .map((name) => path.join(directory, name));
163
- }
@@ -1,8 +0,0 @@
1
- import { type TraceEvent } from "iteration-trace-contracts";
2
- type ParseResult = Readonly<{
3
- events: readonly TraceEvent[];
4
- gaps: readonly string[];
5
- }>;
6
- export declare function parseCursorTranscriptLine(line: string, filename: string, byteOffset: number): ParseResult;
7
- export declare function parseCursorHookLine(line: string, filename: string): ParseResult;
8
- export {};
@@ -1,294 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import path from "node:path";
3
- import * as z from "zod";
4
- import { parseTraceEventBatch, } from "iteration-trace-contracts";
5
- const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
6
- function record(value) {
7
- const parsed = z.record(z.string(), z.json()).safeParse(value);
8
- return parsed.success ? parsed.data : null;
9
- }
10
- function string(value) {
11
- const parsed = z.string().safeParse(value);
12
- return parsed.success ? parsed.data : null;
13
- }
14
- function nonnegativeInteger(value) {
15
- const parsed = z
16
- .number()
17
- .int()
18
- .min(0)
19
- .max(Number.MAX_SAFE_INTEGER)
20
- .safeParse(value);
21
- return parsed.success ? parsed.data : null;
22
- }
23
- function event(conversationId, filename, byteOffset, index, eventType, payload, callId = null, occurredAt = null) {
24
- const hash = createHash("sha256")
25
- .update(`${filename}:${byteOffset}:${index}:${eventType}`)
26
- .digest("hex");
27
- return {
28
- eventId: `${String(index).padStart(4, "0")}:${hash}`,
29
- sessionId: `cursor:${conversationId}`,
30
- sequence: byteOffset * 1000 + index,
31
- callId,
32
- projectId: null,
33
- occurredAt,
34
- eventType,
35
- payload,
36
- };
37
- }
38
- export function parseCursorTranscriptLine(line, filename, byteOffset) {
39
- const conversationId = path.basename(filename, ".jsonl");
40
- if (!UUID.test(conversationId) ||
41
- path.basename(path.dirname(filename)) !== conversationId)
42
- return { events: [], gaps: ["invalid_cursor_transcript_path"] };
43
- let decoded;
44
- try {
45
- decoded = JSON.parse(line);
46
- }
47
- catch {
48
- return { events: [], gaps: ["malformed_jsonl_record"] };
49
- }
50
- const source = record(decoded);
51
- if (source === null)
52
- return { events: [], gaps: ["record_is_not_an_object"] };
53
- const events = [];
54
- const gaps = [];
55
- if (byteOffset === 0) {
56
- events.push({
57
- ...event(conversationId, filename, 0, 0, "session_meta", {
58
- id: conversationId,
59
- transcript_path: filename,
60
- }),
61
- run: {
62
- kind: "identity",
63
- id: conversationId,
64
- parentId: null,
65
- ownStart: true,
66
- startOrdinal: null,
67
- },
68
- });
69
- }
70
- const role = string(source.role);
71
- if (role === "user" || role === "assistant") {
72
- const message = record(source.message);
73
- if (message === null || !Array.isArray(message.content))
74
- gaps.push("cursor_message_without_content");
75
- else {
76
- for (const [index, value] of message.content.entries()) {
77
- const block = record(value);
78
- if (block === null) {
79
- gaps.push("invalid_cursor_content_block");
80
- continue;
81
- }
82
- const type = string(block.type);
83
- const eventType = type === "tool_use"
84
- ? "tool_call"
85
- : type === "thinking"
86
- ? "reasoning"
87
- : type === "text"
88
- ? role === "user"
89
- ? "user_message"
90
- : "assistant_message"
91
- : "source_record";
92
- events.push(event(conversationId, filename, byteOffset, index + 1, eventType, {
93
- text: string(block.text) ?? string(block.thinking),
94
- name: string(block.name),
95
- input: block.input ?? null,
96
- sourceType: type,
97
- record: source,
98
- }, string(block.id)));
99
- if (type !== "text" && type !== "tool_use" && type !== "thinking")
100
- gaps.push(`unsupported_cursor_content_block:${type ?? "unknown"}`);
101
- }
102
- }
103
- }
104
- else if (source.type === "turn_ended") {
105
- events.push(event(conversationId, filename, byteOffset, 1, source.status === "success" ? "turn_complete" : "turn_aborted", { record: source }));
106
- }
107
- else {
108
- gaps.push(`unsupported_cursor_record:${string(source.type) ?? "unknown"}`);
109
- events.push(event(conversationId, filename, byteOffset, 1, "source_record", {
110
- sourceType: string(source.type),
111
- record: source,
112
- }));
113
- }
114
- return validated(events, gaps);
115
- }
116
- export function parseCursorHookLine(line, filename) {
117
- let decoded;
118
- try {
119
- decoded = JSON.parse(line);
120
- }
121
- catch {
122
- return { events: [], gaps: ["malformed_cursor_hook_record"] };
123
- }
124
- const wrapper = record(decoded);
125
- const input = wrapper === null ? null : record(wrapper.input);
126
- const conversationId = input === null ? null : string(input.conversation_id);
127
- const hook = wrapper === null ? null : string(wrapper.hook);
128
- const capturedAt = wrapper === null ? null : string(wrapper.capturedAt);
129
- if (wrapper?.kind === "subagent_transcript_chunk") {
130
- const subagent = record(wrapper.subagent);
131
- const part = nonnegativeInteger(subagent?.part);
132
- const totalParts = nonnegativeInteger(subagent?.totalParts);
133
- if (conversationId === null ||
134
- !UUID.test(conversationId) ||
135
- capturedAt === null ||
136
- Number.isNaN(Date.parse(capturedAt)) ||
137
- subagent === null ||
138
- part === null ||
139
- totalParts === null ||
140
- part < 1 ||
141
- part > totalParts ||
142
- string(subagent.base64) === null)
143
- return { events: [], gaps: ["invalid_cursor_subagent_transcript_chunk"] };
144
- const transcriptBytes = nonnegativeInteger(wrapper.transcriptBytes) ?? 0;
145
- const candidate = event(conversationId, filename, transcriptBytes, part, "source_record", {
146
- sourceType: "cursor_subagent_transcript",
147
- text: string(subagent.text),
148
- base64: string(subagent.base64),
149
- path: string(subagent.path),
150
- part,
151
- totalParts,
152
- parent_conversation_id: string(input?.parent_conversation_id),
153
- subagent_id: string(input?.subagent_id),
154
- }, null, capturedAt);
155
- const hash = candidate.eventId.split(":").at(-1);
156
- return validated([
157
- {
158
- ...candidate,
159
- sequence: transcriptBytes * 1000 + 500,
160
- eventId: `${String(Date.parse(capturedAt)).padStart(13, "0")}:${String(2000 + part).padStart(4, "0")}:${hash}`,
161
- },
162
- ], []);
163
- }
164
- if (input === null ||
165
- conversationId === null ||
166
- !UUID.test(conversationId) ||
167
- hook === null ||
168
- capturedAt === null ||
169
- Number.isNaN(Date.parse(capturedAt)))
170
- return { events: [], gaps: ["invalid_cursor_hook_record"] };
171
- const transcriptBytes = wrapper?.transcriptBytes;
172
- const sequence = nonnegativeInteger(transcriptBytes) ?? 0;
173
- const events = [];
174
- if (hook === "beforeSubmitPrompt" || hook === "sessionStart") {
175
- const roots = Array.isArray(input.workspace_roots)
176
- ? input.workspace_roots
177
- : [];
178
- events.push({
179
- ...event(conversationId, filename, sequence, 0, "session_meta", {
180
- id: conversationId,
181
- cwd: string(roots[0]),
182
- version: string(input.cursor_version),
183
- model: string(input.model),
184
- transcript_path: string(input.transcript_path),
185
- }, null, capturedAt),
186
- run: {
187
- kind: "identity",
188
- id: conversationId,
189
- parentId: null,
190
- ownStart: true,
191
- startOrdinal: null,
192
- },
193
- });
194
- }
195
- const rawText = JSON.stringify(input);
196
- if (Buffer.byteLength(rawText, "utf8") <= 500_000) {
197
- events.push(event(conversationId, filename, sequence, 1, "source_record", {
198
- sourceType: `cursor_hook:${hook}`,
199
- record: input,
200
- }, null, capturedAt));
201
- }
202
- else {
203
- const chunks = splitText(rawText);
204
- for (const [index, text] of chunks.entries())
205
- events.push(event(conversationId, filename, sequence, index + 1, "source_record", {
206
- sourceType: `cursor_hook:${hook}`,
207
- text,
208
- part: index + 1,
209
- totalParts: chunks.length,
210
- }, null, capturedAt));
211
- }
212
- const next = events.length + 1;
213
- if (hook === "preToolUse") {
214
- events.push(event(conversationId, filename, sequence, next, "tool_call", {
215
- name: string(input.tool_name),
216
- input: input.tool_input ?? null,
217
- }, string(input.tool_use_id), capturedAt));
218
- }
219
- if (hook === "postToolUse" || hook === "postToolUseFailure") {
220
- const output = string(input.tool_output) ??
221
- string(input.error_message) ??
222
- string(input.error) ??
223
- (input.tool_output === undefined && input.error === undefined
224
- ? null
225
- : JSON.stringify(input.tool_output ?? input.error));
226
- const chunks = output === null ? [null] : splitText(output);
227
- for (const [index, text] of chunks.entries())
228
- events.push(event(conversationId, filename, sequence, next + index, "tool_result", {
229
- text,
230
- name: string(input.tool_name),
231
- part: index + 1,
232
- totalParts: chunks.length,
233
- }, string(input.tool_use_id), capturedAt));
234
- }
235
- else if (hook === "afterAgentThought") {
236
- events.push(event(conversationId, filename, sequence, next, "reasoning", {
237
- text: string(input.text) ?? string(input.thought),
238
- }, null, capturedAt));
239
- }
240
- else if (hook === "afterAgentResponse" &&
241
- (input.usage !== undefined ||
242
- input.input_tokens !== undefined ||
243
- input.output_tokens !== undefined)) {
244
- events.push(event(conversationId, filename, sequence, next, "token_usage_record", {
245
- model: string(input.model),
246
- usage: input.usage ?? {
247
- input_tokens: input.input_tokens ?? null,
248
- output_tokens: input.output_tokens ?? null,
249
- cache_read_tokens: input.cache_read_tokens ?? null,
250
- cache_write_tokens: input.cache_write_tokens ?? null,
251
- },
252
- }, null, capturedAt));
253
- }
254
- const capturedAtMs = Date.parse(capturedAt);
255
- const ordered = events.map((candidate, index) => {
256
- const digest = candidate.eventId.split(":").at(-1);
257
- const thought = candidate.eventType === "reasoning"
258
- ? createHash("sha256")
259
- .update(`${conversationId}:${string(input.generation_id)?.slice(0, 36) ?? ""}:${candidate.payload.text}`)
260
- .digest("hex")
261
- : null;
262
- return {
263
- ...candidate,
264
- sequence: sequence * 1000 + 500,
265
- eventId: thought === null
266
- ? `${String(capturedAtMs).padStart(13, "0")}:${String(index).padStart(4, "0")}:${digest}`
267
- : `thought:${thought}`,
268
- };
269
- });
270
- return validated(ordered, []);
271
- }
272
- function splitText(value) {
273
- if (value.length === 0)
274
- return [""];
275
- const chunks = [];
276
- for (let start = 0; start < value.length;) {
277
- let end = Math.min(start + 250_000, value.length);
278
- if (end < value.length && /[\uD800-\uDBFF]/u.test(value[end - 1]))
279
- end -= 1;
280
- chunks.push(value.slice(start, end));
281
- start = end;
282
- }
283
- return chunks;
284
- }
285
- function validated(events, gaps) {
286
- const valid = [];
287
- for (const candidate of events) {
288
- if (parseTraceEventBatch({ events: [candidate] }).success)
289
- valid.push(candidate);
290
- else
291
- gaps.push(`invalid_normalized_event:${candidate.eventType}`);
292
- }
293
- return { events: valid, gaps };
294
- }
@@ -1,17 +0,0 @@
1
- import { type CollectorConfig, type CollectorPaths } from "./storage.js";
2
- type HistoryImportSize = Readonly<{
3
- files: number;
4
- bytes: number;
5
- }>;
6
- export type HistoryImportControl = Readonly<{
7
- isRunning: () => Promise<boolean>;
8
- stop: () => Promise<void>;
9
- start: (directory: string) => Promise<unknown>;
10
- acquireLock: (paths: CollectorPaths) => Promise<() => Promise<void>>;
11
- }>;
12
- export declare function importSourceHistory(config: CollectorConfig, paths: CollectorPaths, confirmed: boolean, control?: HistoryImportControl): Promise<Readonly<{
13
- imported: boolean;
14
- size: HistoryImportSize;
15
- backgroundRunning: boolean | null;
16
- }>>;
17
- export {};
@@ -1,63 +0,0 @@
1
- import path from "node:path";
2
- import { backgroundServiceStatus, installBackgroundService, uninstallBackgroundService, } from "./background-service.js";
3
- import { waitForCollectorLock } from "./service.js";
4
- import { collectorSource, collectorSourceDirectory, historyImportSize, loadState, resetHistoryCursors, } from "./storage.js";
5
- function backgroundControl(source) {
6
- return {
7
- isRunning: () => backgroundServiceStatus(source),
8
- stop: () => uninstallBackgroundService(source),
9
- start: (directory) => installBackgroundService(directory, source),
10
- acquireLock: waitForCollectorLock,
11
- };
12
- }
13
- export async function importSourceHistory(config, paths, confirmed, control = backgroundControl(collectorSource(config))) {
14
- const source = collectorSource(config);
15
- const directory = collectorSourceDirectory(config);
16
- const state = await loadState(paths);
17
- if (!state.initialized || state.sourceDirectory !== path.resolve(directory)) {
18
- throw new Error(`Connect the ${source} source before importing its history.`);
19
- }
20
- const estimate = await historyImportSize(directory, source);
21
- if (!confirmed)
22
- return { imported: false, size: estimate, backgroundRunning: null };
23
- const wasRunning = await control.isRunning();
24
- let size = null;
25
- let stopAttempted = false;
26
- let rewound = false;
27
- let failure = null;
28
- try {
29
- if (wasRunning) {
30
- stopAttempted = true;
31
- await control.stop();
32
- }
33
- const releaseLock = await control.acquireLock(paths);
34
- try {
35
- size = await resetHistoryCursors(directory, paths, source);
36
- rewound = true;
37
- }
38
- finally {
39
- await releaseLock();
40
- }
41
- }
42
- catch (error) {
43
- failure = { error };
44
- }
45
- if (stopAttempted) {
46
- try {
47
- await control.start(config.dataDirectory);
48
- }
49
- catch (error) {
50
- throw new Error(rewound
51
- ? `History checkpoints were rewound, but the collector could not restart. Run iteration start ${source} to resume uploads.`
52
- : `The collector could not be restored after a failed history import. Run iteration start ${source} to resume uploads.`, {
53
- cause: failure ? new AggregateError([failure.error, error]) : error,
54
- });
55
- }
56
- }
57
- if (failure)
58
- throw failure.error;
59
- if (size === null) {
60
- throw new Error("History import did not update checkpoints.");
61
- }
62
- return { imported: true, size, backgroundRunning: wasRunning };
63
- }
@@ -1,13 +0,0 @@
1
- import type { CollectorSource } from "iteration-trace-contracts";
2
- export type LaunchAgentRestart = {
3
- isLoaded(timeoutMs: number): Promise<boolean>;
4
- bootstrap(timeoutMs: number): Promise<void>;
5
- wait(delayMs: number): Promise<void>;
6
- now(): number;
7
- };
8
- export declare function launchAgentPlist(cliPath?: string, nodePath?: string, logDirectory?: string, dataDirectory?: string, source?: CollectorSource): string;
9
- export declare function bootstrapAfterBootout(wasLoaded: boolean, control: LaunchAgentRestart): Promise<void>;
10
- export declare function installLaunchAgent(dataDirectory?: string, source?: CollectorSource): Promise<string>;
11
- export declare function uninstallLaunchAgent(source?: CollectorSource): Promise<void>;
12
- export declare function launchAgentStatus(source?: CollectorSource): Promise<boolean>;
13
- export declare function launchAgentRunning(output: string): boolean;