codebase-cli 2.0.0-pre.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.
- package/LICENSE +21 -0
- package/README.md +266 -0
- package/bin/codebase +2 -0
- package/dist/agent/agent.js +198 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/config.js +117 -0
- package/dist/agent/config.js.map +1 -0
- package/dist/agent/events.js +153 -0
- package/dist/agent/events.js.map +1 -0
- package/dist/agent/router.js +35 -0
- package/dist/agent/router.js.map +1 -0
- package/dist/agent/system-prompt.js +21 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/auth/cli.js +138 -0
- package/dist/auth/cli.js.map +1 -0
- package/dist/auth/credentials.js +105 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/auth/flow.js +222 -0
- package/dist/auth/flow.js.map +1 -0
- package/dist/auth/pkce.js +46 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +1 -0
- package/dist/clipboard/copy.js +106 -0
- package/dist/clipboard/copy.js.map +1 -0
- package/dist/commands/builtins.js +203 -0
- package/dist/commands/builtins.js.map +1 -0
- package/dist/commands/registry.js +65 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/compaction/engine.js +209 -0
- package/dist/compaction/engine.js.map +1 -0
- package/dist/compaction/tokens.js +79 -0
- package/dist/compaction/tokens.js.map +1 -0
- package/dist/compaction/types.js +2 -0
- package/dist/compaction/types.js.map +1 -0
- package/dist/diagnostics/checkers.js +211 -0
- package/dist/diagnostics/checkers.js.map +1 -0
- package/dist/diagnostics/engine.js +71 -0
- package/dist/diagnostics/engine.js.map +1 -0
- package/dist/diagnostics/types.js +2 -0
- package/dist/diagnostics/types.js.map +1 -0
- package/dist/dotenv/loader.js +115 -0
- package/dist/dotenv/loader.js.map +1 -0
- package/dist/glue/client.js +47 -0
- package/dist/glue/client.js.map +1 -0
- package/dist/glue/intent.js +78 -0
- package/dist/glue/intent.js.map +1 -0
- package/dist/glue/narration.js +55 -0
- package/dist/glue/narration.js.map +1 -0
- package/dist/headless/run.js +89 -0
- package/dist/headless/run.js.map +1 -0
- package/dist/hooks/manager.js +158 -0
- package/dist/hooks/manager.js.map +1 -0
- package/dist/hooks/runner.js +70 -0
- package/dist/hooks/runner.js.map +1 -0
- package/dist/hooks/types.js +2 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/memory/inject.js +12 -0
- package/dist/memory/inject.js.map +1 -0
- package/dist/memory/store.js +178 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/types.js +10 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/permissions/store.js +172 -0
- package/dist/permissions/store.js.map +1 -0
- package/dist/plan/flow.js +214 -0
- package/dist/plan/flow.js.map +1 -0
- package/dist/plan/prompts.js +69 -0
- package/dist/plan/prompts.js.map +1 -0
- package/dist/plan/store.js +37 -0
- package/dist/plan/store.js.map +1 -0
- package/dist/plan/types.js +3 -0
- package/dist/plan/types.js.map +1 -0
- package/dist/sessions/store.js +105 -0
- package/dist/sessions/store.js.map +1 -0
- package/dist/skills/loader.js +41 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/platform-loader.js +63 -0
- package/dist/skills/platform-loader.js.map +1 -0
- package/dist/skills/types.js +21 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/ask-user.js +61 -0
- package/dist/tools/ask-user.js.map +1 -0
- package/dist/tools/dispatch-agent.js +178 -0
- package/dist/tools/dispatch-agent.js.map +1 -0
- package/dist/tools/edit-file.js +80 -0
- package/dist/tools/edit-file.js.map +1 -0
- package/dist/tools/errors.js +89 -0
- package/dist/tools/errors.js.map +1 -0
- package/dist/tools/file-ops.js +136 -0
- package/dist/tools/file-ops.js.map +1 -0
- package/dist/tools/file-state-cache.js +92 -0
- package/dist/tools/file-state-cache.js.map +1 -0
- package/dist/tools/git/branch.js +84 -0
- package/dist/tools/git/branch.js.map +1 -0
- package/dist/tools/git/commit.js +83 -0
- package/dist/tools/git/commit.js.map +1 -0
- package/dist/tools/git/diff.js +72 -0
- package/dist/tools/git/diff.js.map +1 -0
- package/dist/tools/git/git-helpers.js +58 -0
- package/dist/tools/git/git-helpers.js.map +1 -0
- package/dist/tools/git/log.js +70 -0
- package/dist/tools/git/log.js.map +1 -0
- package/dist/tools/git/status.js +97 -0
- package/dist/tools/git/status.js.map +1 -0
- package/dist/tools/git/worktree.js +132 -0
- package/dist/tools/git/worktree.js.map +1 -0
- package/dist/tools/glob.js +128 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.js +199 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/list-files.js +120 -0
- package/dist/tools/list-files.js.map +1 -0
- package/dist/tools/memory-tools.js +127 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/multi-edit.js +87 -0
- package/dist/tools/multi-edit.js.map +1 -0
- package/dist/tools/notebook-edit.js +147 -0
- package/dist/tools/notebook-edit.js.map +1 -0
- package/dist/tools/permission.js +168 -0
- package/dist/tools/permission.js.map +1 -0
- package/dist/tools/plan-mode.js +76 -0
- package/dist/tools/plan-mode.js.map +1 -0
- package/dist/tools/read-file.js +135 -0
- package/dist/tools/read-file.js.map +1 -0
- package/dist/tools/registry.js +52 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/shell.js +216 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/tools/task-store.js +70 -0
- package/dist/tools/task-store.js.map +1 -0
- package/dist/tools/tasks.js +131 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/web-fetch.js +152 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.js +169 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/tools/write-file.js +70 -0
- package/dist/tools/write-file.js.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/App.js +216 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/Input.js +90 -0
- package/dist/ui/Input.js.map +1 -0
- package/dist/ui/Message.js +89 -0
- package/dist/ui/Message.js.map +1 -0
- package/dist/ui/MessageList.js +35 -0
- package/dist/ui/MessageList.js.map +1 -0
- package/dist/ui/Permission.js +39 -0
- package/dist/ui/Permission.js.map +1 -0
- package/dist/ui/Status.js +34 -0
- package/dist/ui/Status.js.map +1 -0
- package/dist/ui/TaskPanel.js +43 -0
- package/dist/ui/TaskPanel.js.map +1 -0
- package/dist/ui/Throbber.js +20 -0
- package/dist/ui/Throbber.js.map +1 -0
- package/dist/ui/ToolPanel.js +83 -0
- package/dist/ui/ToolPanel.js.map +1 -0
- package/dist/ui/UserQuery.js +38 -0
- package/dist/ui/UserQuery.js.map +1 -0
- package/dist/ui/input-state.js +210 -0
- package/dist/ui/input-state.js.map +1 -0
- package/dist/ui/wrap.js +30 -0
- package/dist/ui/wrap.js.map +1 -0
- package/dist/user-queries/store.js +60 -0
- package/dist/user-queries/store.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { constantTimeEquals, generateCodeChallenge, generateCodeVerifier, generateState } from "./pkce.js";
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes for the user to complete the browser flow
|
|
5
|
+
/**
|
|
6
|
+
* Build the URL we open in the user's browser. Every parameter is
|
|
7
|
+
* URL-encoded — a space in the scope used to break the redirect in
|
|
8
|
+
* the Go v1 (commit ac1dd56), and we don't want that bug to come
|
|
9
|
+
* back unnoticed.
|
|
10
|
+
*/
|
|
11
|
+
export function buildAuthorizationUrl(config, params) {
|
|
12
|
+
const url = new URL(config.authorizationUrl);
|
|
13
|
+
url.searchParams.set("response_type", "code");
|
|
14
|
+
url.searchParams.set("client_id", config.clientId);
|
|
15
|
+
url.searchParams.set("redirect_uri", params.redirectUri);
|
|
16
|
+
url.searchParams.set("scope", config.scopes.join(" "));
|
|
17
|
+
url.searchParams.set("state", params.state);
|
|
18
|
+
url.searchParams.set("code_challenge", params.codeChallenge);
|
|
19
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
20
|
+
return url.toString();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Spin a localhost HTTP server, listen for one /callback hit, return
|
|
24
|
+
* the code+state. Validates the returned state against the supplied
|
|
25
|
+
* value to defend against CSRF; treats anything else as an error.
|
|
26
|
+
*
|
|
27
|
+
* Resolves with { code, state } on success. Rejects on timeout, state
|
|
28
|
+
* mismatch, or upstream error param.
|
|
29
|
+
*/
|
|
30
|
+
export function awaitCallback(server, expectedState, timeoutMs) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
let settled = false;
|
|
33
|
+
const safeResolve = (value) => {
|
|
34
|
+
if (settled)
|
|
35
|
+
return;
|
|
36
|
+
settled = true;
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
resolve(value);
|
|
39
|
+
};
|
|
40
|
+
const safeReject = (err) => {
|
|
41
|
+
if (settled)
|
|
42
|
+
return;
|
|
43
|
+
settled = true;
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
reject(err);
|
|
46
|
+
};
|
|
47
|
+
const timer = setTimeout(() => {
|
|
48
|
+
server.close();
|
|
49
|
+
safeReject(new Error(`OAuth callback timed out after ${Math.round(timeoutMs / 1000)}s`));
|
|
50
|
+
}, timeoutMs);
|
|
51
|
+
server.on("request", (req, res) => {
|
|
52
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
53
|
+
if (url.pathname !== "/callback") {
|
|
54
|
+
res.statusCode = 404;
|
|
55
|
+
res.end("Not Found. The codebase OAuth callback expects /callback.");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const error = url.searchParams.get("error");
|
|
59
|
+
if (error) {
|
|
60
|
+
const desc = url.searchParams.get("error_description") ?? "";
|
|
61
|
+
renderResponse(res, false, `Sign-in failed: ${error}${desc ? ` — ${desc}` : ""}`);
|
|
62
|
+
server.close();
|
|
63
|
+
safeReject(new Error(`OAuth provider returned error: ${error}${desc ? ` — ${desc}` : ""}`));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const code = url.searchParams.get("code") ?? "";
|
|
67
|
+
const state = url.searchParams.get("state") ?? "";
|
|
68
|
+
if (!code) {
|
|
69
|
+
renderResponse(res, false, "Sign-in failed: provider did not return a code.");
|
|
70
|
+
server.close();
|
|
71
|
+
safeReject(new Error("OAuth callback missing code parameter"));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!constantTimeEquals(state, expectedState)) {
|
|
75
|
+
renderResponse(res, false, "Sign-in failed: state mismatch (possible CSRF).");
|
|
76
|
+
server.close();
|
|
77
|
+
safeReject(new Error("OAuth callback state mismatch"));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
renderResponse(res, true, "Signed in. You can close this tab.");
|
|
81
|
+
server.close();
|
|
82
|
+
safeResolve({ code, state });
|
|
83
|
+
});
|
|
84
|
+
server.on("error", (err) => {
|
|
85
|
+
safeReject(err);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function renderResponse(res, ok, message) {
|
|
90
|
+
const html = `<!doctype html>
|
|
91
|
+
<html><head><meta charset="utf-8"><title>codebase</title></head>
|
|
92
|
+
<body style="font-family:system-ui;padding:40px;max-width:560px;margin:auto;">
|
|
93
|
+
<h1>${ok ? "✓" : "✗"} codebase</h1>
|
|
94
|
+
<p>${message}</p>
|
|
95
|
+
</body></html>`;
|
|
96
|
+
res.statusCode = ok ? 200 : 400;
|
|
97
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
98
|
+
res.end(html);
|
|
99
|
+
}
|
|
100
|
+
export async function exchangeCode(config, params) {
|
|
101
|
+
const body = new URLSearchParams({
|
|
102
|
+
grant_type: "authorization_code",
|
|
103
|
+
client_id: config.clientId,
|
|
104
|
+
code: params.code,
|
|
105
|
+
code_verifier: params.codeVerifier,
|
|
106
|
+
redirect_uri: params.redirectUri,
|
|
107
|
+
});
|
|
108
|
+
const res = await fetch(config.tokenUrl, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" },
|
|
111
|
+
body,
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
const text = await res.text();
|
|
115
|
+
throw new Error(`token exchange failed: ${res.status} ${res.statusText}${text ? ` — ${text.slice(0, 200)}` : ""}`);
|
|
116
|
+
}
|
|
117
|
+
const json = (await res.json());
|
|
118
|
+
return tokenToCredentials(json, config);
|
|
119
|
+
}
|
|
120
|
+
export async function refreshAccessToken(config, refreshToken) {
|
|
121
|
+
const body = new URLSearchParams({
|
|
122
|
+
grant_type: "refresh_token",
|
|
123
|
+
client_id: config.clientId,
|
|
124
|
+
refresh_token: refreshToken,
|
|
125
|
+
});
|
|
126
|
+
const res = await fetch(config.refreshUrl, {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" },
|
|
129
|
+
body,
|
|
130
|
+
});
|
|
131
|
+
if (!res.ok) {
|
|
132
|
+
const text = await res.text();
|
|
133
|
+
throw new Error(`token refresh failed: ${res.status} ${res.statusText}${text ? ` — ${text.slice(0, 200)}` : ""}`);
|
|
134
|
+
}
|
|
135
|
+
const json = (await res.json());
|
|
136
|
+
return tokenToCredentials(json, config);
|
|
137
|
+
}
|
|
138
|
+
export async function revokeToken(config, accessToken) {
|
|
139
|
+
if (!config.revokeUrl)
|
|
140
|
+
return;
|
|
141
|
+
const body = new URLSearchParams({ token: accessToken, client_id: config.clientId });
|
|
142
|
+
try {
|
|
143
|
+
await fetch(config.revokeUrl, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
146
|
+
body,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Best-effort logout — local credentials clear regardless.
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function tokenToCredentials(token, config) {
|
|
154
|
+
if (!token.access_token)
|
|
155
|
+
throw new Error("token response missing access_token");
|
|
156
|
+
const scopes = token.scope ? token.scope.split(/\s+/).filter(Boolean) : config.scopes.slice();
|
|
157
|
+
return {
|
|
158
|
+
version: 1,
|
|
159
|
+
accessToken: token.access_token,
|
|
160
|
+
refreshToken: token.refresh_token,
|
|
161
|
+
expiresAt: token.expires_in ? Date.now() + token.expires_in * 1000 : undefined,
|
|
162
|
+
scopes,
|
|
163
|
+
userId: token.user?.id,
|
|
164
|
+
email: token.user?.email,
|
|
165
|
+
source: "codebase",
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Run the full browser OAuth flow:
|
|
170
|
+
* 1. PKCE: generate verifier + challenge + state
|
|
171
|
+
* 2. Bind a localhost HTTP server on a random port
|
|
172
|
+
* 3. Open the authorization URL in the user's browser
|
|
173
|
+
* 4. Wait for /callback, validate state
|
|
174
|
+
* 5. Exchange the code for tokens
|
|
175
|
+
*
|
|
176
|
+
* Returns ready-to-save Credentials.
|
|
177
|
+
*/
|
|
178
|
+
export async function runOAuthLogin(config, openBrowserFn = openBrowser) {
|
|
179
|
+
const verifier = generateCodeVerifier();
|
|
180
|
+
const challenge = generateCodeChallenge(verifier);
|
|
181
|
+
const state = generateState();
|
|
182
|
+
const server = createServer();
|
|
183
|
+
await new Promise((resolve, reject) => {
|
|
184
|
+
server.once("error", reject);
|
|
185
|
+
server.listen(0, "127.0.0.1", () => resolve());
|
|
186
|
+
});
|
|
187
|
+
const port = server.address().port;
|
|
188
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
189
|
+
const authUrl = buildAuthorizationUrl(config, { codeChallenge: challenge, state, redirectUri });
|
|
190
|
+
const callbackPromise = awaitCallback(server, state, config.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
191
|
+
try {
|
|
192
|
+
await openBrowserFn(authUrl);
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
server.close();
|
|
196
|
+
throw new Error(`couldn't open browser automatically: ${err instanceof Error ? err.message : String(err)}. ` +
|
|
197
|
+
`Open this URL manually:\n${authUrl}`);
|
|
198
|
+
}
|
|
199
|
+
const { code } = await callbackPromise;
|
|
200
|
+
return exchangeCode(config, { code, codeVerifier: verifier, redirectUri });
|
|
201
|
+
}
|
|
202
|
+
/** Best-effort browser open. Falls back to printing the URL on platforms we can't detect. */
|
|
203
|
+
export async function openBrowser(url) {
|
|
204
|
+
const command = browserOpenCommand(url);
|
|
205
|
+
if (!command) {
|
|
206
|
+
throw new Error(`unsupported platform ${process.platform}`);
|
|
207
|
+
}
|
|
208
|
+
await new Promise((resolve, reject) => {
|
|
209
|
+
exec(command, (err) => (err ? reject(err) : resolve()));
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function browserOpenCommand(url) {
|
|
213
|
+
const escaped = url.replace(/"/g, '\\"');
|
|
214
|
+
if (process.platform === "darwin")
|
|
215
|
+
return `open "${escaped}"`;
|
|
216
|
+
if (process.platform === "win32")
|
|
217
|
+
return `start "" "${escaped}"`;
|
|
218
|
+
if (process.platform === "linux")
|
|
219
|
+
return `xdg-open "${escaped}"`;
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../../src/auth/flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* PKCE helpers for RFC 7636. Used by the OAuth flow to bind the
|
|
4
|
+
* /callback redirect to this specific login attempt — without these
|
|
5
|
+
* the auth code on the redirect URL would be replayable.
|
|
6
|
+
*/
|
|
7
|
+
const VERIFIER_BYTE_LENGTH = 64;
|
|
8
|
+
const STATE_BYTE_LENGTH = 24;
|
|
9
|
+
/**
|
|
10
|
+
* Base64url encoding without padding (RFC 7636 §4.2). Node's
|
|
11
|
+
* `Buffer.toString("base64url")` lands in the right shape; this
|
|
12
|
+
* wrapper exists so call sites can swap to a different encoder
|
|
13
|
+
* without rippling through.
|
|
14
|
+
*/
|
|
15
|
+
export function base64url(buf) {
|
|
16
|
+
return buf.toString("base64url");
|
|
17
|
+
}
|
|
18
|
+
/** Generate the code_verifier — 64 random bytes, base64url-encoded. */
|
|
19
|
+
export function generateCodeVerifier() {
|
|
20
|
+
return base64url(randomBytes(VERIFIER_BYTE_LENGTH));
|
|
21
|
+
}
|
|
22
|
+
/** Derive the code_challenge from a code_verifier using SHA-256 (RFC 7636 §4.2). */
|
|
23
|
+
export function generateCodeChallenge(verifier) {
|
|
24
|
+
if (typeof verifier !== "string" || verifier.length === 0) {
|
|
25
|
+
throw new Error("code verifier must be a non-empty string");
|
|
26
|
+
}
|
|
27
|
+
return base64url(createHash("sha256").update(verifier).digest());
|
|
28
|
+
}
|
|
29
|
+
/** Generate an anti-CSRF state token, base64url-encoded random bytes. */
|
|
30
|
+
export function generateState() {
|
|
31
|
+
return base64url(randomBytes(STATE_BYTE_LENGTH));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Constant-time comparison for state validation to avoid timing leaks
|
|
35
|
+
* in the (unlikely) event an attacker probes the callback handler.
|
|
36
|
+
*/
|
|
37
|
+
export function constantTimeEquals(a, b) {
|
|
38
|
+
if (a.length !== b.length)
|
|
39
|
+
return false;
|
|
40
|
+
let diff = 0;
|
|
41
|
+
for (let i = 0; i < a.length; i++) {
|
|
42
|
+
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
43
|
+
}
|
|
44
|
+
return diff === 0;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=pkce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/auth/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;GAIG;AAEH,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAChC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACpC,OAAO,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAClC,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,oBAAoB;IACnC,OAAO,SAAS,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACrD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa;IAC5B,OAAO,SAAS,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAS,EAAE,CAAS;IACtD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,CAAC;AACnB,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { render } from "ink";
|
|
5
|
+
import { runAuthSubcommand } from "./auth/cli.js";
|
|
6
|
+
import { loadDotEnv } from "./dotenv/loader.js";
|
|
7
|
+
import { runHeadless } from "./headless/run.js";
|
|
8
|
+
import { App } from "./ui/App.js";
|
|
9
|
+
// Auto-load .env files before any subsystem reads process.env.
|
|
10
|
+
loadDotEnv();
|
|
11
|
+
const argv = process.argv.slice(2);
|
|
12
|
+
if (argv[0] === "--version" || argv[0] === "-v") {
|
|
13
|
+
process.stdout.write(`${readPackageVersion()}\n`);
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
else if (argv[0] === "--help" || argv[0] === "-h") {
|
|
17
|
+
printHelp();
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
else if (argv[0] === "auth") {
|
|
21
|
+
runAuthSubcommand(argv).then((code) => process.exit(code));
|
|
22
|
+
}
|
|
23
|
+
else if (argv[0] === "run") {
|
|
24
|
+
const prompt = argv.slice(1).join(" ").trim();
|
|
25
|
+
if (!prompt) {
|
|
26
|
+
process.stderr.write("usage: codebase run <prompt>\n");
|
|
27
|
+
process.exit(2);
|
|
28
|
+
}
|
|
29
|
+
runHeadless({ prompt }).then((code) => process.exit(code));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const instance = render(_jsx(App, {}));
|
|
33
|
+
instance.waitUntilExit().catch(() => {
|
|
34
|
+
process.exit(1);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function readPackageVersion() {
|
|
38
|
+
// dist/cli.js → ../package.json. Works for tsc-emitted output; if
|
|
39
|
+
// we ever ship a bundled binary this needs to switch to a build-time
|
|
40
|
+
// version constant.
|
|
41
|
+
try {
|
|
42
|
+
const url = new URL("../package.json", import.meta.url);
|
|
43
|
+
const pkg = JSON.parse(readFileSync(url, "utf8"));
|
|
44
|
+
return pkg.version ?? "unknown";
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return "unknown";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function printHelp() {
|
|
51
|
+
process.stdout.write([
|
|
52
|
+
"codebase — AI coding agent in your terminal",
|
|
53
|
+
"",
|
|
54
|
+
"Usage:",
|
|
55
|
+
" codebase run the interactive TUI in the current directory",
|
|
56
|
+
" codebase run <prompt> one-shot headless run, prints to stdout",
|
|
57
|
+
" codebase auth login sign in via codebase.foundation OAuth",
|
|
58
|
+
" codebase auth logout revoke the current session",
|
|
59
|
+
" codebase auth status show current sign-in",
|
|
60
|
+
" codebase auth refresh force-refresh the access token",
|
|
61
|
+
" codebase auth <cbk_xxx> save a manual API key (for SSH / headless)",
|
|
62
|
+
" codebase --version print version and exit",
|
|
63
|
+
" codebase --help show this message",
|
|
64
|
+
"",
|
|
65
|
+
"More: https://github.com/codebase-foundation/codebase-cli",
|
|
66
|
+
"",
|
|
67
|
+
].join("\n"));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";;AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,+DAA+D;AAC/D,UAAU,EAAE,CAAC;AAEb,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;IACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,kBAAkB,EAAE,IAAI,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;KAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;IACrD,SAAS,EAAE,CAAC;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;KAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;IAC/B,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5D,CAAC;KAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5D,CAAC;KAAM,CAAC;IACP,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAC,GAAG,KAAG,CAAC,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB;IAC1B,kEAAkE;IAClE,qEAAqE;IACrE,oBAAoB;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAyB,CAAC;QAC1E,OAAO,GAAG,CAAC,OAAO,IAAI,SAAS,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,SAAS,SAAS;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CACnB;QACC,6CAA6C;QAC7C,EAAE;QACF,QAAQ;QACR,iFAAiF;QACjF,wEAAwE;QACxE,sEAAsE;QACtE,2DAA2D;QAC3D,qDAAqD;QACrD,+DAA+D;QAC/D,2EAA2E;QAC3E,uDAAuD;QACvD,kDAAkD;QAClD,EAAE;QACF,2DAA2D;QAC3D,EAAE;KACF,CAAC,IAAI,CAAC,IAAI,CAAC,CACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const DEFAULT_MAX_BYTES = 75_000;
|
|
3
|
+
/**
|
|
4
|
+
* Push text to the system clipboard via the most reliable available
|
|
5
|
+
* channel. Strategy:
|
|
6
|
+
* 1. SSH session → OSC 52 (only path that crosses the network)
|
|
7
|
+
* 2. macOS → pbcopy (rock solid)
|
|
8
|
+
* 3. WSL → clip.exe (writes to Windows clipboard from WSL)
|
|
9
|
+
* 4. Linux Wayland with wl-copy installed → wl-copy
|
|
10
|
+
* 5. Linux X11 with xclip installed → xclip
|
|
11
|
+
* 6. fallback → OSC 52 (works in most modern terminals)
|
|
12
|
+
*
|
|
13
|
+
* Caller can override via `options.method` for tests or to force a
|
|
14
|
+
* specific path. Always returns the actual method used and the byte
|
|
15
|
+
* count written; throws if the method's underlying transport fails.
|
|
16
|
+
*/
|
|
17
|
+
export async function copyToClipboard(text, options = {}) {
|
|
18
|
+
const max = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
19
|
+
const truncated = Buffer.byteLength(text, "utf8") > max;
|
|
20
|
+
const payload = truncated ? text.slice(0, max) : text;
|
|
21
|
+
const method = options.method ?? (await detectClipboardMethod());
|
|
22
|
+
switch (method) {
|
|
23
|
+
case "osc52":
|
|
24
|
+
writeOsc52(payload, options.stdout ?? process.stdout, options.insideTmux ?? !!process.env.TMUX);
|
|
25
|
+
break;
|
|
26
|
+
case "pbcopy":
|
|
27
|
+
await spawnCopy("pbcopy", [], payload);
|
|
28
|
+
break;
|
|
29
|
+
case "clip.exe":
|
|
30
|
+
await spawnCopy("clip.exe", [], payload);
|
|
31
|
+
break;
|
|
32
|
+
case "wl-copy":
|
|
33
|
+
await spawnCopy("wl-copy", [], payload);
|
|
34
|
+
break;
|
|
35
|
+
case "xclip":
|
|
36
|
+
await spawnCopy("xclip", ["-selection", "clipboard"], payload);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
return { method, bytes: Buffer.byteLength(payload, "utf8"), truncated };
|
|
40
|
+
}
|
|
41
|
+
export async function detectClipboardMethod(env = process.env) {
|
|
42
|
+
if (env.SSH_CONNECTION || env.SSH_CLIENT)
|
|
43
|
+
return "osc52";
|
|
44
|
+
if (process.platform === "darwin")
|
|
45
|
+
return "pbcopy";
|
|
46
|
+
if (await commandExists("clip.exe"))
|
|
47
|
+
return "clip.exe";
|
|
48
|
+
if (env.WAYLAND_DISPLAY && (await commandExists("wl-copy")))
|
|
49
|
+
return "wl-copy";
|
|
50
|
+
if (await commandExists("xclip"))
|
|
51
|
+
return "xclip";
|
|
52
|
+
return "osc52";
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Emit an OSC 52 escape sequence carrying the base64-encoded payload.
|
|
56
|
+
* Inside tmux we wrap it in tmux's DCS pass-through so the embedding
|
|
57
|
+
* terminal still sees the escape.
|
|
58
|
+
*/
|
|
59
|
+
export function writeOsc52(text, stdout, insideTmux) {
|
|
60
|
+
const b64 = Buffer.from(text, "utf8").toString("base64");
|
|
61
|
+
if (insideTmux) {
|
|
62
|
+
stdout.write(`\x1bPtmux;\x1b\x1b]52;c;${b64}\x07\x1b\\`);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
stdout.write(`\x1b]52;c;${b64}\x07`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function spawnCopy(cmd, args, text) {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
const child = spawn(cmd, args, { stdio: ["pipe", "ignore", "ignore"] });
|
|
71
|
+
child.on("error", reject);
|
|
72
|
+
child.on("close", (code) => {
|
|
73
|
+
if (code !== 0)
|
|
74
|
+
reject(new Error(`${cmd} exited ${code}`));
|
|
75
|
+
else
|
|
76
|
+
resolve();
|
|
77
|
+
});
|
|
78
|
+
child.stdin?.end(text, "utf8");
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function commandExists(cmd) {
|
|
82
|
+
return new Promise((resolve) => {
|
|
83
|
+
const which = process.platform === "win32" ? "where" : "which";
|
|
84
|
+
const child = spawn(which, [cmd], { stdio: "ignore" });
|
|
85
|
+
child.on("error", () => resolve(false));
|
|
86
|
+
child.on("close", (code) => resolve(code === 0));
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Pull the most-recent code block out of a markdown body. Recognizes
|
|
91
|
+
* triple-backtick fences with or without a language tag. Returns null
|
|
92
|
+
* if no fenced block is found.
|
|
93
|
+
*/
|
|
94
|
+
export function extractLastCodeBlock(markdown) {
|
|
95
|
+
const fenceRe = /```[^\n]*\n([\s\S]*?)```/g;
|
|
96
|
+
let match;
|
|
97
|
+
let last = null;
|
|
98
|
+
while (true) {
|
|
99
|
+
match = fenceRe.exec(markdown);
|
|
100
|
+
if (!match)
|
|
101
|
+
break;
|
|
102
|
+
last = match[1];
|
|
103
|
+
}
|
|
104
|
+
return last !== null ? last.replace(/\n$/, "") : null;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=copy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../../src/clipboard/copy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAqB3C,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEjC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,UAAuB,EAAE;IAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IAClD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC;IACxD,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,qBAAqB,EAAE,CAAC,CAAC;IAEjE,QAAQ,MAAM,EAAE,CAAC;QAChB,KAAK,OAAO;YACX,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChG,MAAM;QACP,KAAK,QAAQ;YACZ,MAAM,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YACvC,MAAM;QACP,KAAK,UAAU;YACd,MAAM,SAAS,CAAC,UAAU,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YACzC,MAAM;QACP,KAAK,SAAS;YACb,MAAM,SAAS,CAAC,SAAS,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YACxC,MAAM;QACP,KAAK,OAAO;YACX,MAAM,SAAS,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAC;YAC/D,MAAM;IACR,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC/E,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,UAAU;QAAE,OAAO,OAAO,CAAC;IACzD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACnD,IAAI,MAAM,aAAa,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IACvD,IAAI,GAAG,CAAC,eAAe,IAAI,CAAC,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9E,IAAI,MAAM,aAAa,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACjD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAA6B,EAAE,UAAmB;IAC1F,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzD,IAAI,UAAU,EAAE,CAAC;QAChB,MAAM,CAAC,KAAK,CAAC,2BAA2B,GAAG,YAAY,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC,CAAC;IACtC,CAAC;AACF,CAAC;AAED,SAAS,SAAS,CAAC,GAAW,EAAE,IAAc,EAAE,IAAY;IAC3D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1B,IAAI,IAAI,KAAK,CAAC;gBAAE,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,GAAG,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC;;gBACtD,OAAO,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IACjC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACpD,MAAM,OAAO,GAAG,2BAA2B,CAAC;IAC5C,IAAI,KAA6B,CAAC;IAClC,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,OAAO,IAAI,EAAE,CAAC;QACb,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK;YAAE,MAAM;QAClB,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvD,CAAC"}
|