@viraatdas/rudder 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.
@@ -0,0 +1,246 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { spawn } from "node:child_process";
3
+ import { loadAuthStore, saveRunRecord } from "./state.js";
4
+ import { commandExists, lineSplitBuffer, nowIso, parseJsonLine } from "./util.js";
5
+ export function getBackend(id) {
6
+ if (id === "claude") {
7
+ return claudeBackend();
8
+ }
9
+ if (id === "codex") {
10
+ return codexBackend();
11
+ }
12
+ return acpxBackend();
13
+ }
14
+ function claudeBackend() {
15
+ return {
16
+ id: "claude",
17
+ async verify() {
18
+ return commandExists("claude")
19
+ ? { ok: true, message: "claude found" }
20
+ : { ok: false, message: "claude is not on PATH" };
21
+ },
22
+ async run(request, emit) {
23
+ const sessionId = request.run.session?.nativeSessionId ?? randomUUID();
24
+ request.run.session = {
25
+ ...(request.run.session ?? {}),
26
+ nativeSessionId: sessionId,
27
+ };
28
+ await saveRunRecord(request.run);
29
+ const env = await backendEnv("anthropic");
30
+ const args = [
31
+ "-p",
32
+ request.prompt,
33
+ "--model",
34
+ request.run.model || "opus",
35
+ "--effort",
36
+ "xhigh",
37
+ "--permission-mode",
38
+ "bypassPermissions",
39
+ "--dangerously-skip-permissions",
40
+ "--output-format",
41
+ "stream-json",
42
+ "--include-partial-messages",
43
+ "--append-system-prompt",
44
+ request.contract,
45
+ "--session-id",
46
+ sessionId,
47
+ ];
48
+ return await spawnAndStream({
49
+ command: "claude",
50
+ args,
51
+ cwd: request.run.worktree.path,
52
+ env,
53
+ request,
54
+ emit,
55
+ });
56
+ },
57
+ };
58
+ }
59
+ function codexBackend() {
60
+ return {
61
+ id: "codex",
62
+ async verify() {
63
+ return commandExists("codex")
64
+ ? { ok: true, message: "codex found" }
65
+ : { ok: false, message: "codex is not on PATH" };
66
+ },
67
+ async run(request, emit) {
68
+ const env = await backendEnv("openai");
69
+ const args = [
70
+ "exec",
71
+ "--json",
72
+ "--color",
73
+ "never",
74
+ "--model",
75
+ request.run.model || "gpt-5.4-codex",
76
+ "--ask-for-approval",
77
+ "never",
78
+ "--sandbox",
79
+ "danger-full-access",
80
+ "--dangerously-bypass-approvals-and-sandbox",
81
+ "-c",
82
+ 'model_reasoning_effort="xhigh"',
83
+ "-c",
84
+ 'model_reasoning_summary="detailed"',
85
+ "-c",
86
+ "model_supports_reasoning_summaries=true",
87
+ `${request.contract}\n\nUSER TASK:\n${request.prompt}`,
88
+ ];
89
+ return await spawnAndStream({
90
+ command: "codex",
91
+ args,
92
+ cwd: request.run.worktree.path,
93
+ env,
94
+ request,
95
+ emit,
96
+ });
97
+ },
98
+ };
99
+ }
100
+ function acpxBackend() {
101
+ return {
102
+ id: "acpx",
103
+ async verify() {
104
+ return commandExists("acpx")
105
+ ? { ok: true, message: "acpx found" }
106
+ : { ok: false, message: "acpx is not on PATH" };
107
+ },
108
+ async run(request, emit) {
109
+ const sessionName = request.run.session?.sessionName ?? request.run.id;
110
+ request.run.session = {
111
+ ...(request.run.session ?? {}),
112
+ sessionName,
113
+ };
114
+ await saveRunRecord(request.run);
115
+ const args = [
116
+ "--approve-all",
117
+ "--format",
118
+ "json",
119
+ "--cwd",
120
+ request.run.worktree.path,
121
+ "codex",
122
+ "-s",
123
+ sessionName,
124
+ `${request.contract}\n\nUSER TASK:\n${request.prompt}`,
125
+ ];
126
+ return await spawnAndStream({
127
+ command: "acpx",
128
+ args,
129
+ cwd: request.run.worktree.path,
130
+ env: process.env,
131
+ request,
132
+ emit,
133
+ });
134
+ },
135
+ };
136
+ }
137
+ async function backendEnv(provider) {
138
+ const store = await loadAuthStore();
139
+ const env = { ...process.env };
140
+ if (provider === "anthropic") {
141
+ const profile = firstProfile(store, ["anthropic:env", "anthropic:default"]);
142
+ if (profile?.type === "api_key" && profile.key) {
143
+ env.ANTHROPIC_API_KEY = profile.key;
144
+ }
145
+ if (profile?.type === "token" && profile.token) {
146
+ env.ANTHROPIC_OAUTH_TOKEN = profile.token;
147
+ }
148
+ }
149
+ if (provider === "openai") {
150
+ const profile = firstProfile(store, ["openai:env", "openai:default"]);
151
+ if (profile?.type === "api_key" && profile.key) {
152
+ env.OPENAI_API_KEY = profile.key;
153
+ }
154
+ }
155
+ return env;
156
+ }
157
+ function firstProfile(store, ids) {
158
+ for (const id of ids) {
159
+ const profile = store.profiles[id];
160
+ if (profile) {
161
+ return profile;
162
+ }
163
+ }
164
+ return undefined;
165
+ }
166
+ async function spawnAndStream(params) {
167
+ await params.emit({
168
+ ts: nowIso(),
169
+ runId: params.request.run.id,
170
+ type: "run.started",
171
+ message: `${params.command} started`,
172
+ data: { command: params.command, args: params.args },
173
+ });
174
+ const child = spawn(params.command, params.args, {
175
+ cwd: params.cwd,
176
+ env: params.env,
177
+ stdio: ["ignore", "pipe", "pipe"],
178
+ });
179
+ params.request.run.process = {
180
+ ...(params.request.run.process ?? {}),
181
+ pid: child.pid,
182
+ startedAt: nowIso(),
183
+ };
184
+ params.request.run.status = "running";
185
+ await saveRunRecord(params.request.run);
186
+ let outRest = "";
187
+ let errRest = "";
188
+ child.stdout.setEncoding("utf8");
189
+ child.stderr.setEncoding("utf8");
190
+ child.stdout.on("data", (chunk) => {
191
+ const split = lineSplitBuffer(outRest, chunk);
192
+ outRest = split.rest;
193
+ for (const line of split.lines) {
194
+ void emitBackendLine(params.request.run.id, line, params.emit, false);
195
+ }
196
+ });
197
+ child.stderr.on("data", (chunk) => {
198
+ const split = lineSplitBuffer(errRest, chunk);
199
+ errRest = split.rest;
200
+ for (const line of split.lines) {
201
+ void emitBackendLine(params.request.run.id, line, params.emit, true);
202
+ }
203
+ });
204
+ return await new Promise((resolve) => {
205
+ child.on("error", (error) => {
206
+ void params.emit({
207
+ ts: nowIso(),
208
+ runId: params.request.run.id,
209
+ type: "backend.error",
210
+ message: error.message,
211
+ });
212
+ resolve(1);
213
+ });
214
+ child.on("close", (code, signal) => {
215
+ if (outRest) {
216
+ void emitBackendLine(params.request.run.id, outRest, params.emit, false);
217
+ }
218
+ if (errRest) {
219
+ void emitBackendLine(params.request.run.id, errRest, params.emit, true);
220
+ }
221
+ void params.emit({
222
+ ts: nowIso(),
223
+ runId: params.request.run.id,
224
+ type: "backend.exit",
225
+ message: `${params.command} exited with ${code ?? signal ?? "unknown"}`,
226
+ data: { code: code ?? null, signal: signal ?? null },
227
+ });
228
+ resolve(code ?? (signal ? 130 : 1));
229
+ });
230
+ });
231
+ }
232
+ async function emitBackendLine(runId, line, emit, stderr) {
233
+ const trimmed = line.trimEnd();
234
+ if (!trimmed) {
235
+ return;
236
+ }
237
+ const parsed = parseJsonLine(trimmed);
238
+ await emit({
239
+ ts: nowIso(),
240
+ runId,
241
+ type: stderr ? "backend.error" : "backend.output",
242
+ message: typeof parsed === "object" && parsed ? undefined : trimmed,
243
+ data: parsed ?? trimmed,
244
+ });
245
+ }
246
+ //# sourceMappingURL=backends.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backends.js","sourceRoot":"","sources":["../src/backends.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { RunRecord, SpecContract, VerificationResult } from "./types.js";
2
+ export declare function createSpec(run: RunRecord): Promise<SpecContract>;
3
+ export declare function renderContract(spec: SpecContract): string;
4
+ export declare function verifyRun(run: RunRecord): Promise<VerificationResult>;
package/dist/brain.js ADDED
@@ -0,0 +1,131 @@
1
+ import fsp from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { currentBranch, currentCommit, gitDiff, gitStatus, hasChanges } from "./git.js";
4
+ import { pathExists, readJson, runCommand, writeJson } from "./util.js";
5
+ import { specPath, verifierPath } from "./state.js";
6
+ const INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md", "README.md"];
7
+ export async function createSpec(run) {
8
+ const workspace = run.worktree.path;
9
+ const instructionsFiles = [];
10
+ for (const name of INSTRUCTION_FILES) {
11
+ const filePath = path.join(workspace, name);
12
+ if (!(await pathExists(filePath))) {
13
+ continue;
14
+ }
15
+ const content = await fsp.readFile(filePath, "utf8");
16
+ instructionsFiles.push({
17
+ path: name,
18
+ content: content.slice(0, 12_000),
19
+ });
20
+ }
21
+ const spec = {
22
+ runId: run.id,
23
+ task: run.task,
24
+ createdAt: new Date().toISOString(),
25
+ repo: {
26
+ root: workspace,
27
+ branch: await currentBranch(workspace),
28
+ baseCommit: (await currentCommit(workspace)) || run.baseCommit,
29
+ status: await gitStatus(workspace),
30
+ },
31
+ instructionsFiles,
32
+ acceptanceCriteria: buildAcceptanceCriteria(run.task),
33
+ suggestedTests: await suggestTests(workspace),
34
+ };
35
+ await writeJson(specPath(run.repoRoot, run.id), spec);
36
+ return spec;
37
+ }
38
+ export function renderContract(spec) {
39
+ const instructions = spec.instructionsFiles
40
+ .map((file) => `### ${file.path}\n${file.content}`)
41
+ .join("\n\n");
42
+ return [
43
+ "RUDDER CONTRACT",
44
+ "",
45
+ `Task: ${spec.task}`,
46
+ "",
47
+ "Acceptance criteria:",
48
+ ...spec.acceptanceCriteria.map((item) => `- ${item}`),
49
+ "",
50
+ spec.suggestedTests.length > 0
51
+ ? ["Suggested verification:", ...spec.suggestedTests.map((item) => `- ${item}`)].join("\n")
52
+ : "Suggested verification: choose the smallest relevant checks for this repo.",
53
+ "",
54
+ "Working rules:",
55
+ "- Keep changes focused on the task.",
56
+ "- Preserve unrelated user changes.",
57
+ "- Run relevant checks when practical and report any checks that could not be run.",
58
+ "- Do not mark the task complete unless the acceptance criteria are handled.",
59
+ "",
60
+ instructions ? `Repository instructions:\n\n${instructions}` : "",
61
+ "END RUDDER CONTRACT",
62
+ ]
63
+ .filter(Boolean)
64
+ .join("\n");
65
+ }
66
+ export async function verifyRun(run) {
67
+ const diff = await gitDiff(run.worktree.path);
68
+ const changed = await hasChanges(run.worktree.path);
69
+ const outputPath = path.join(run.repoRoot, ".rudder", "runs", run.id, "output.txt");
70
+ const transcript = await fsp.readFile(outputPath, "utf8").catch(() => "");
71
+ const spec = await readJson(specPath(run.repoRoot, run.id));
72
+ const missing = [];
73
+ const satisfied = [];
74
+ if (!changed) {
75
+ missing.push("No file changes were detected.");
76
+ }
77
+ else {
78
+ satisfied.push(diff.trim() ? "The run produced a git diff." : "The run produced git status changes.");
79
+ }
80
+ if (/test|spec|check|lint|typecheck|verify/i.test(transcript)) {
81
+ satisfied.push("The transcript mentions verification or tests.");
82
+ }
83
+ else if (spec?.suggestedTests.length) {
84
+ missing.push("No explicit verification/test run was detected in the transcript.");
85
+ }
86
+ const result = {
87
+ satisfied,
88
+ missing,
89
+ notes: changed
90
+ ? "Local verifier checked for produced changes and evidence of verification."
91
+ : "Local verifier found no changes. The worker may have only analyzed the task.",
92
+ shouldContinue: missing.some((item) => item.startsWith("No file changes")),
93
+ };
94
+ await writeJson(verifierPath(run.repoRoot, run.id), result);
95
+ return result;
96
+ }
97
+ function buildAcceptanceCriteria(task) {
98
+ const criteria = ["Address the user's requested task directly.", "Keep the change scoped and reviewable."];
99
+ if (/test|fail|bug|fix/i.test(task)) {
100
+ criteria.push("Run or explain the relevant failing test/check.");
101
+ }
102
+ if (/refactor/i.test(task)) {
103
+ criteria.push("Preserve existing behavior while improving structure.");
104
+ }
105
+ return criteria;
106
+ }
107
+ async function suggestTests(workspace) {
108
+ const suggestions = [];
109
+ const packageJson = await readJson(path.join(workspace, "package.json"));
110
+ if (packageJson?.scripts) {
111
+ for (const script of ["test", "check", "typecheck", "lint"]) {
112
+ if (packageJson.scripts[script]) {
113
+ suggestions.push(`npm run ${script}`);
114
+ }
115
+ }
116
+ }
117
+ if (await pathExists(path.join(workspace, "Cargo.toml"))) {
118
+ suggestions.push("cargo test");
119
+ }
120
+ if (await pathExists(path.join(workspace, "pyproject.toml"))) {
121
+ suggestions.push("pytest");
122
+ }
123
+ if (suggestions.length === 0) {
124
+ const result = await runCommand("git", ["ls-files"], { cwd: workspace, allowFailure: true });
125
+ if (result.stdout.includes("Makefile")) {
126
+ suggestions.push("make test");
127
+ }
128
+ }
129
+ return suggestions;
130
+ }
131
+ //# sourceMappingURL=brain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brain.js","sourceRoot":"","sources":["../src/brain.ts"],"names":[],"mappings":"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"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { RunRecord } from "./types.js";
2
+ export declare function findRepoRoot(cwd?: string): string;
3
+ export declare function isGitRepo(cwd: string): boolean;
4
+ export declare function currentBranch(repoRoot: string): Promise<string>;
5
+ export declare function currentCommit(repoRoot: string): Promise<string>;
6
+ export declare function gitStatus(repoRoot: string): Promise<string[]>;
7
+ export declare function gitDiff(repoRoot: string): Promise<string>;
8
+ export declare function hasChanges(repoRoot: string): Promise<boolean>;
9
+ export declare function processAlive(pid: number | undefined): boolean;
10
+ export declare function activeRunsForCheckout(repoRoot: string, checkoutPath: string): Promise<RunRecord[]>;
11
+ export declare function createRunWorktree(params: {
12
+ repoRoot: string;
13
+ runId: string;
14
+ task: string;
15
+ baseCommit: string;
16
+ }): Promise<{
17
+ branch: string;
18
+ path: string;
19
+ }>;
20
+ export declare function removeWorktree(repoRoot: string, targetPath: string, force?: boolean): Promise<void>;
21
+ export declare function mergeRunIntoCurrentBranch(run: RunRecord, allowDirty?: boolean): Promise<RunRecord>;
22
+ export declare function conflictedFiles(repoRoot: string): Promise<string[]>;
23
+ export declare function worktreeList(repoRoot: string): Promise<string>;
package/dist/git.js ADDED
@@ -0,0 +1,184 @@
1
+ import fsp from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { runCommand, runCommandSync, slugify } from "./util.js";
4
+ import { listRuns, saveRunRecord, worktreePath } from "./state.js";
5
+ export function findRepoRoot(cwd = process.cwd()) {
6
+ const result = runCommandSync("git", ["rev-parse", "--show-toplevel"], {
7
+ cwd,
8
+ allowFailure: true,
9
+ });
10
+ return result.code === 0 ? result.stdout.trim() : path.resolve(cwd);
11
+ }
12
+ export function isGitRepo(cwd) {
13
+ return (runCommandSync("git", ["rev-parse", "--is-inside-work-tree"], {
14
+ cwd,
15
+ allowFailure: true,
16
+ }).stdout.trim() === "true");
17
+ }
18
+ export async function currentBranch(repoRoot) {
19
+ const result = await runCommand("git", ["branch", "--show-current"], {
20
+ cwd: repoRoot,
21
+ allowFailure: true,
22
+ });
23
+ return result.stdout.trim() || "HEAD";
24
+ }
25
+ export async function currentCommit(repoRoot) {
26
+ const result = await runCommand("git", ["rev-parse", "HEAD"], {
27
+ cwd: repoRoot,
28
+ allowFailure: true,
29
+ });
30
+ return result.stdout.trim() || "";
31
+ }
32
+ export async function gitStatus(repoRoot) {
33
+ const result = await runCommand("git", ["status", "--short"], {
34
+ cwd: repoRoot,
35
+ allowFailure: true,
36
+ });
37
+ return result.stdout
38
+ .split(/\r?\n/)
39
+ .map((line) => line.trimEnd())
40
+ .filter(Boolean)
41
+ .filter((line) => {
42
+ const file = line.slice(3).trim();
43
+ return file !== ".rudder" && !file.startsWith(".rudder/");
44
+ });
45
+ }
46
+ export async function gitDiff(repoRoot) {
47
+ const status = await gitStatus(repoRoot);
48
+ const result = await runCommand("git", ["diff", "--stat", "--", "."], {
49
+ cwd: repoRoot,
50
+ allowFailure: true,
51
+ });
52
+ const patch = await runCommand("git", ["diff", "--", "."], {
53
+ cwd: repoRoot,
54
+ allowFailure: true,
55
+ });
56
+ return [
57
+ status.length ? `status:\n${status.join("\n")}` : "",
58
+ result.stdout.trim(),
59
+ patch.stdout.trim(),
60
+ ]
61
+ .filter(Boolean)
62
+ .join("\n\n");
63
+ }
64
+ export async function hasChanges(repoRoot) {
65
+ return (await gitStatus(repoRoot)).length > 0;
66
+ }
67
+ export function processAlive(pid) {
68
+ if (!pid) {
69
+ return false;
70
+ }
71
+ try {
72
+ process.kill(pid, 0);
73
+ return true;
74
+ }
75
+ catch {
76
+ return false;
77
+ }
78
+ }
79
+ export async function activeRunsForCheckout(repoRoot, checkoutPath) {
80
+ const runs = await listRuns(repoRoot);
81
+ return runs.filter((run) => {
82
+ if (!["created", "running", "verifying"].includes(run.status)) {
83
+ return false;
84
+ }
85
+ if (path.resolve(run.worktree.path) !== path.resolve(checkoutPath)) {
86
+ return false;
87
+ }
88
+ return processAlive(run.process?.pid);
89
+ });
90
+ }
91
+ export async function createRunWorktree(params) {
92
+ const branch = `rudder/${params.runId.slice(0, 14)}-${slugify(params.task, "task").slice(0, 32)}`;
93
+ const targetPath = worktreePath(params.repoRoot, params.runId);
94
+ await fsp.mkdir(path.dirname(targetPath), { recursive: true });
95
+ await runCommand("git", ["branch", branch, params.baseCommit], {
96
+ cwd: params.repoRoot,
97
+ allowFailure: true,
98
+ });
99
+ await runCommand("git", ["worktree", "add", targetPath, branch], {
100
+ cwd: params.repoRoot,
101
+ });
102
+ return { branch, path: targetPath };
103
+ }
104
+ export async function removeWorktree(repoRoot, targetPath, force = false) {
105
+ await runCommand("git", ["worktree", "remove", ...(force ? ["--force"] : []), targetPath], {
106
+ cwd: repoRoot,
107
+ allowFailure: force,
108
+ });
109
+ }
110
+ export async function mergeRunIntoCurrentBranch(run, allowDirty = false) {
111
+ if (!run.worktree.branch) {
112
+ throw new Error("Run has no worktree branch to merge.");
113
+ }
114
+ if (!allowDirty && (await hasChanges(run.repoRoot))) {
115
+ throw new Error("Target branch is dirty. Commit/stash changes or pass --allow-dirty.");
116
+ }
117
+ run.merge = {
118
+ status: "not-started",
119
+ attemptedAt: new Date().toISOString(),
120
+ targetBranch: await currentBranch(run.repoRoot),
121
+ };
122
+ await saveRunRecord(run);
123
+ await commitWorktreeChanges(run);
124
+ const merge = await runCommand("git", ["merge", "--no-ff", run.worktree.branch], {
125
+ cwd: run.repoRoot,
126
+ allowFailure: true,
127
+ });
128
+ if (merge.code === 0) {
129
+ run.status = "merged";
130
+ run.merge = {
131
+ ...run.merge,
132
+ status: "merged",
133
+ };
134
+ await saveRunRecord(run);
135
+ return run;
136
+ }
137
+ const conflicted = await conflictedFiles(run.repoRoot);
138
+ run.status = "merge-conflict";
139
+ run.merge = {
140
+ ...run.merge,
141
+ status: "conflict",
142
+ conflictedFiles: conflicted,
143
+ error: merge.stderr.trim() || merge.stdout.trim(),
144
+ };
145
+ await saveRunRecord(run);
146
+ return run;
147
+ }
148
+ async function commitWorktreeChanges(run) {
149
+ if (!(await hasChanges(run.worktree.path))) {
150
+ return;
151
+ }
152
+ await runCommand("git", ["add", "-A"], {
153
+ cwd: run.worktree.path,
154
+ });
155
+ const message = `rudder: ${run.task.slice(0, 72)}`;
156
+ const commit = await runCommand("git", ["commit", "-m", message], {
157
+ cwd: run.worktree.path,
158
+ allowFailure: true,
159
+ });
160
+ if (commit.code !== 0) {
161
+ const stillChanged = await hasChanges(run.worktree.path);
162
+ if (stillChanged) {
163
+ throw new Error(commit.stderr.trim() || commit.stdout.trim() || "Failed to commit worktree changes.");
164
+ }
165
+ }
166
+ }
167
+ export async function conflictedFiles(repoRoot) {
168
+ const result = await runCommand("git", ["diff", "--name-only", "--diff-filter=U"], {
169
+ cwd: repoRoot,
170
+ allowFailure: true,
171
+ });
172
+ return result.stdout
173
+ .split(/\r?\n/)
174
+ .map((line) => line.trim())
175
+ .filter(Boolean);
176
+ }
177
+ export async function worktreeList(repoRoot) {
178
+ const result = await runCommand("git", ["worktree", "list"], {
179
+ cwd: repoRoot,
180
+ allowFailure: true,
181
+ });
182
+ return result.stdout.trim();
183
+ }
184
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "./main.js";
3
+ main().catch((error) => {
4
+ const message = error instanceof Error ? error.message : String(error);
5
+ console.error(`rudder: ${message}`);
6
+ process.exit(1);
7
+ });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/main.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function main(): Promise<void>;