@awak-app/simy-cli 0.1.1 → 0.1.3
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/README.md +45 -4
- package/package.json +16 -3
- package/src/agent.js +717 -41
- package/src/backend-executable.js +44 -0
- package/src/browser.js +59 -0
- package/src/console/app.js +1042 -0
- package/src/console/commands.js +100 -0
- package/src/console/index.js +25 -0
- package/src/index.js +22 -1
- package/src/local-attachments.js +270 -0
- package/src/orchestrator/contract.js +1 -0
- package/src/orchestrator/independent-audit.js +25 -0
- package/src/orchestrator/index.js +1 -1
- package/src/orchestrator/instruction.js +27 -1
- package/src/orchestrator/loop.js +65 -25
- package/src/orchestrator/presentation.js +189 -0
- package/src/orchestrator/result.js +11 -0
- package/src/provider-stream.js +327 -0
- package/src/repository-inventory.js +216 -0
- package/src/run-registry.js +44 -0
- package/src/runner.js +565 -66
- package/src/web-api.js +66 -0
- package/src/workspace-context.js +37 -0
package/src/web-api.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export function webApiHeaders({ token } = {}, extraHeaders = {}) {
|
|
2
|
+
const headers = { ...extraHeaders };
|
|
3
|
+
if (typeof token === "string" && token) {
|
|
4
|
+
headers.Authorization = `Bearer ${token}`;
|
|
5
|
+
}
|
|
6
|
+
return headers;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const APP_DEV_ORIGIN = "https://app-dev.simy.one";
|
|
10
|
+
const APP_DEV_GATEWAY_BASE_URL = "https://app.simy.one/api/local-cli-gateway/";
|
|
11
|
+
|
|
12
|
+
export function resolveWebApiBaseUrl(webOrigin, requestedBaseUrl = null) {
|
|
13
|
+
const normalizedWebOrigin = new URL(webOrigin).origin;
|
|
14
|
+
if (!requestedBaseUrl) {
|
|
15
|
+
if (normalizedWebOrigin === APP_DEV_ORIGIN) {
|
|
16
|
+
throw new Error("SIMY Web did not provide the required dev CLI gateway.");
|
|
17
|
+
}
|
|
18
|
+
return new URL("/api/local-cli/", normalizedWebOrigin).href;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const requested = new URL(requestedBaseUrl);
|
|
22
|
+
requested.hash = "";
|
|
23
|
+
requested.search = "";
|
|
24
|
+
if (!requested.pathname.endsWith("/")) requested.pathname += "/";
|
|
25
|
+
|
|
26
|
+
const directBase = new URL("/api/local-cli/", normalizedWebOrigin).href;
|
|
27
|
+
if (requested.href === directBase) return directBase;
|
|
28
|
+
if (
|
|
29
|
+
normalizedWebOrigin === APP_DEV_ORIGIN &&
|
|
30
|
+
requested.href === APP_DEV_GATEWAY_BASE_URL
|
|
31
|
+
) {
|
|
32
|
+
return APP_DEV_GATEWAY_BASE_URL;
|
|
33
|
+
}
|
|
34
|
+
throw new Error("SIMY Web provided an untrusted CLI API endpoint.");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function webApiUrl(path, { webOrigin, apiBaseUrl = null }) {
|
|
38
|
+
const baseUrl = resolveWebApiBaseUrl(webOrigin, apiBaseUrl);
|
|
39
|
+
return new URL(String(path || "").replace(/^\/+/, ""), baseUrl);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function sessionRequiresWebAuthorization(session, webOrigin) {
|
|
43
|
+
try {
|
|
44
|
+
resolveWebApiBaseUrl(webOrigin, session?.api_base_url);
|
|
45
|
+
return false;
|
|
46
|
+
} catch {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function webApiErrorMessage(payload, status) {
|
|
52
|
+
const message = nestedErrorMessage(payload);
|
|
53
|
+
return message || `SIMY Web returned HTTP ${status}.`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function nestedErrorMessage(value, seen = new Set()) {
|
|
57
|
+
if (typeof value === "string") return value.trim();
|
|
58
|
+
if (!value || typeof value !== "object" || seen.has(value)) return "";
|
|
59
|
+
seen.add(value);
|
|
60
|
+
|
|
61
|
+
for (const key of ["message", "detail", "error", "hint", "description"]) {
|
|
62
|
+
const message = nestedErrorMessage(value[key], seen);
|
|
63
|
+
if (message) return message;
|
|
64
|
+
}
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
|
|
6
|
+
export async function discoverWorkspace(cwd = process.cwd()) {
|
|
7
|
+
try {
|
|
8
|
+
const [{ stdout: root }, { stdout: remote }, { stdout: branch }] = await Promise.all([
|
|
9
|
+
execFileAsync("git", ["rev-parse", "--show-toplevel"], { cwd }),
|
|
10
|
+
execFileAsync("git", ["remote", "get-url", "origin"], { cwd }),
|
|
11
|
+
execFileAsync("git", ["branch", "--show-current"], { cwd }),
|
|
12
|
+
]);
|
|
13
|
+
const repository = normalizeGitHubRemote(remote);
|
|
14
|
+
if (!repository) return emptyWorkspace(cwd);
|
|
15
|
+
return {
|
|
16
|
+
repository,
|
|
17
|
+
branch: String(branch || "").trim() || "dev",
|
|
18
|
+
localPath: String(root || "").trim(),
|
|
19
|
+
};
|
|
20
|
+
} catch {
|
|
21
|
+
return emptyWorkspace(cwd);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function normalizeGitHubRemote(value) {
|
|
26
|
+
const repository = String(value || "")
|
|
27
|
+
.trim()
|
|
28
|
+
.replace(/^git@github\.com:/, "")
|
|
29
|
+
.replace(/^ssh:\/\/git@github\.com\//, "")
|
|
30
|
+
.replace(/^https?:\/\/github\.com\//, "")
|
|
31
|
+
.replace(/\.git$/, "");
|
|
32
|
+
return repository.includes("/") ? repository : null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function emptyWorkspace(cwd) {
|
|
36
|
+
return { repository: null, branch: "dev", localPath: cwd };
|
|
37
|
+
}
|