@getforgeai/cli 0.1.0-beta.1
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 +201 -0
- package/README.md +80 -0
- package/dist/bin/forgeai.d.ts +3 -0
- package/dist/bin/forgeai.js +8 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +180 -0
- package/dist/commands/auth-login.d.ts +4 -0
- package/dist/commands/auth-login.js +202 -0
- package/dist/commands/auth-logout.d.ts +2 -0
- package/dist/commands/auth-logout.js +41 -0
- package/dist/commands/auth-status.d.ts +4 -0
- package/dist/commands/auth-status.js +81 -0
- package/dist/commands/cli-list.d.ts +4 -0
- package/dist/commands/cli-list.js +40 -0
- package/dist/commands/cli-unlink.d.ts +4 -0
- package/dist/commands/cli-unlink.js +45 -0
- package/dist/commands/config-set.d.ts +5 -0
- package/dist/commands/config-set.js +63 -0
- package/dist/commands/connect.d.ts +9 -0
- package/dist/commands/connect.js +165 -0
- package/dist/commands/disconnect.d.ts +5 -0
- package/dist/commands/disconnect.js +126 -0
- package/dist/commands/journal-clear.d.ts +2 -0
- package/dist/commands/journal-clear.js +16 -0
- package/dist/commands/journal-list.d.ts +2 -0
- package/dist/commands/journal-list.js +20 -0
- package/dist/commands/journal-status.d.ts +2 -0
- package/dist/commands/journal-status.js +18 -0
- package/dist/commands/mcp-serve.d.ts +13 -0
- package/dist/commands/mcp-serve.js +74 -0
- package/dist/commands/org-list.d.ts +4 -0
- package/dist/commands/org-list.js +56 -0
- package/dist/commands/org-unlink.d.ts +4 -0
- package/dist/commands/org-unlink.js +63 -0
- package/dist/commands/reconnect.d.ts +4 -0
- package/dist/commands/reconnect.js +46 -0
- package/dist/commands/release-open.d.ts +2 -0
- package/dist/commands/release-open.js +43 -0
- package/dist/commands/session-respond.d.ts +2 -0
- package/dist/commands/session-respond.js +29 -0
- package/dist/commands/task-open.d.ts +2 -0
- package/dist/commands/task-open.js +42 -0
- package/dist/commands/vm.d.ts +21 -0
- package/dist/commands/vm.js +122 -0
- package/dist/commands/workflow-open.d.ts +2 -0
- package/dist/commands/workflow-open.js +43 -0
- package/dist/config/config-manager.d.ts +31 -0
- package/dist/config/config-manager.js +70 -0
- package/dist/config/token-manager.d.ts +11 -0
- package/dist/config/token-manager.js +87 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +22 -0
- package/dist/lib/auth-client.d.ts +1670 -0
- package/dist/lib/auth-client.js +10 -0
- package/dist/lib/branch-manager.d.ts +79 -0
- package/dist/lib/branch-manager.js +620 -0
- package/dist/lib/clone-and-checkout.d.ts +6 -0
- package/dist/lib/clone-and-checkout.js +41 -0
- package/dist/lib/connection-manager.d.ts +58 -0
- package/dist/lib/connection-manager.js +436 -0
- package/dist/lib/daemon-entry.d.ts +2 -0
- package/dist/lib/daemon-entry.js +210 -0
- package/dist/lib/daemon.d.ts +38 -0
- package/dist/lib/daemon.js +148 -0
- package/dist/lib/event-journal.d.ts +24 -0
- package/dist/lib/event-journal.js +76 -0
- package/dist/lib/ipc-client.d.ts +10 -0
- package/dist/lib/ipc-client.js +70 -0
- package/dist/lib/ipc-server.d.ts +36 -0
- package/dist/lib/ipc-server.js +70 -0
- package/dist/lib/node-version-guard.d.ts +8 -0
- package/dist/lib/node-version-guard.js +60 -0
- package/dist/lib/open-directory.d.ts +7 -0
- package/dist/lib/open-directory.js +41 -0
- package/dist/lib/repo-manager.d.ts +29 -0
- package/dist/lib/repo-manager.js +103 -0
- package/dist/lib/resilient-emitter.d.ts +53 -0
- package/dist/lib/resilient-emitter.js +160 -0
- package/dist/lib/rest-client.d.ts +164 -0
- package/dist/lib/rest-client.js +139 -0
- package/dist/lib/skill-manager.d.ts +23 -0
- package/dist/lib/skill-manager.js +167 -0
- package/dist/lib/socket-client.d.ts +68 -0
- package/dist/lib/socket-client.js +160 -0
- package/dist/mcp/mcp-probe.d.ts +11 -0
- package/dist/mcp/mcp-probe.js +106 -0
- package/dist/mcp/mcp-response.d.ts +29 -0
- package/dist/mcp/mcp-response.js +67 -0
- package/dist/mcp/mcp-server.d.ts +19 -0
- package/dist/mcp/mcp-server.js +76 -0
- package/dist/mcp/resources/project-conventions.d.ts +4 -0
- package/dist/mcp/resources/project-conventions.js +50 -0
- package/dist/mcp/resources/task-current.d.ts +4 -0
- package/dist/mcp/resources/task-current.js +51 -0
- package/dist/mcp/tools/forge-add-group-dependency.d.ts +4 -0
- package/dist/mcp/tools/forge-add-group-dependency.js +20 -0
- package/dist/mcp/tools/forge-add-task-dependency.d.ts +4 -0
- package/dist/mcp/tools/forge-add-task-dependency.js +20 -0
- package/dist/mcp/tools/forge-ask-human.d.ts +4 -0
- package/dist/mcp/tools/forge-ask-human.js +80 -0
- package/dist/mcp/tools/forge-column-done.d.ts +4 -0
- package/dist/mcp/tools/forge-column-done.js +46 -0
- package/dist/mcp/tools/forge-complete-step.d.ts +4 -0
- package/dist/mcp/tools/forge-complete-step.js +139 -0
- package/dist/mcp/tools/forge-create-task-group.d.ts +4 -0
- package/dist/mcp/tools/forge-create-task-group.js +22 -0
- package/dist/mcp/tools/forge-create-task.d.ts +4 -0
- package/dist/mcp/tools/forge-create-task.js +28 -0
- package/dist/mcp/tools/forge-delete-task-group.d.ts +4 -0
- package/dist/mcp/tools/forge-delete-task-group.js +17 -0
- package/dist/mcp/tools/forge-delete-task.d.ts +4 -0
- package/dist/mcp/tools/forge-delete-task.js +17 -0
- package/dist/mcp/tools/forge-get-task.d.ts +4 -0
- package/dist/mcp/tools/forge-get-task.js +17 -0
- package/dist/mcp/tools/forge-merge-back.d.ts +4 -0
- package/dist/mcp/tools/forge-merge-back.js +179 -0
- package/dist/mcp/tools/forge-release-merge.d.ts +4 -0
- package/dist/mcp/tools/forge-release-merge.js +159 -0
- package/dist/mcp/tools/forge-release-notes.d.ts +4 -0
- package/dist/mcp/tools/forge-release-notes.js +51 -0
- package/dist/mcp/tools/forge-release-tag.d.ts +4 -0
- package/dist/mcp/tools/forge-release-tag.js +125 -0
- package/dist/mcp/tools/forge-remove-group-dependency.d.ts +4 -0
- package/dist/mcp/tools/forge-remove-group-dependency.js +19 -0
- package/dist/mcp/tools/forge-remove-task-dependency.d.ts +4 -0
- package/dist/mcp/tools/forge-remove-task-dependency.js +19 -0
- package/dist/mcp/tools/forge-requeue.d.ts +4 -0
- package/dist/mcp/tools/forge-requeue.js +39 -0
- package/dist/mcp/tools/forge-submit-pr.d.ts +4 -0
- package/dist/mcp/tools/forge-submit-pr.js +68 -0
- package/dist/mcp/tools/forge-update-status.d.ts +4 -0
- package/dist/mcp/tools/forge-update-status.js +77 -0
- package/dist/mcp/tools/forge-update-task-group.d.ts +4 -0
- package/dist/mcp/tools/forge-update-task-group.js +21 -0
- package/dist/mcp/tools/forge-update-task.d.ts +4 -0
- package/dist/mcp/tools/forge-update-task.js +25 -0
- package/dist/mcp/tools/forge-validate-merge.d.ts +4 -0
- package/dist/mcp/tools/forge-validate-merge.js +194 -0
- package/dist/mcp/types.d.ts +39 -0
- package/dist/mcp/types.js +8 -0
- package/dist/methodology/artifact-manager.d.ts +14 -0
- package/dist/methodology/artifact-manager.js +55 -0
- package/dist/orchestrator/agent-registry.d.ts +53 -0
- package/dist/orchestrator/agent-registry.js +96 -0
- package/dist/orchestrator/agent-spawner.d.ts +112 -0
- package/dist/orchestrator/agent-spawner.js +1518 -0
- package/dist/orchestrator/connectors/claude-code-connector.d.ts +3 -0
- package/dist/orchestrator/connectors/claude-code-connector.js +60 -0
- package/dist/orchestrator/connectors/connector.d.ts +95 -0
- package/dist/orchestrator/connectors/connector.js +25 -0
- package/dist/orchestrator/connectors/docker-connector.d.ts +14 -0
- package/dist/orchestrator/connectors/docker-connector.js +337 -0
- package/dist/orchestrator/connectors/native-vm-connector.d.ts +11 -0
- package/dist/orchestrator/connectors/native-vm-connector.js +162 -0
- package/dist/orchestrator/connectors/opencode-connector.d.ts +3 -0
- package/dist/orchestrator/connectors/opencode-connector.js +39 -0
- package/dist/orchestrator/connectors/vm-connector.d.ts +3 -0
- package/dist/orchestrator/connectors/vm-connector.js +139 -0
- package/dist/orchestrator/dispatch-queue.d.ts +43 -0
- package/dist/orchestrator/dispatch-queue.js +93 -0
- package/dist/orchestrator/resume-handler.d.ts +34 -0
- package/dist/orchestrator/resume-handler.js +159 -0
- package/dist/orchestrator/stream-batcher.d.ts +16 -0
- package/dist/orchestrator/stream-batcher.js +50 -0
- package/dist/orchestrator/stream-json-extractor.d.ts +97 -0
- package/dist/orchestrator/stream-json-extractor.js +579 -0
- package/dist/vm/claude-token-manager.d.ts +36 -0
- package/dist/vm/claude-token-manager.js +223 -0
- package/dist/vm/docker-executor.d.ts +131 -0
- package/dist/vm/docker-executor.js +360 -0
- package/dist/vm/docker-process-proxy.d.ts +31 -0
- package/dist/vm/docker-process-proxy.js +105 -0
- package/dist/vm/forge-vm-agent.d.ts +11 -0
- package/dist/vm/forge-vm-agent.js +159 -0
- package/dist/vm/git-credentials.d.ts +43 -0
- package/dist/vm/git-credentials.js +53 -0
- package/dist/vm/image-manager.d.ts +7 -0
- package/dist/vm/image-manager.js +61 -0
- package/dist/vm/log.d.ts +9 -0
- package/dist/vm/log.js +18 -0
- package/dist/vm/mcp-bridge.d.ts +63 -0
- package/dist/vm/mcp-bridge.js +243 -0
- package/dist/vm/mcp-stub.d.ts +15 -0
- package/dist/vm/mcp-stub.js +67 -0
- package/dist/vm/native-addon.d.ts +69 -0
- package/dist/vm/native-addon.js +68 -0
- package/dist/vm/provider-resolver.d.ts +7 -0
- package/dist/vm/provider-resolver.js +27 -0
- package/dist/vm/providers/lima.d.ts +17 -0
- package/dist/vm/providers/lima.js +191 -0
- package/dist/vm/providers/qemu.d.ts +28 -0
- package/dist/vm/providers/qemu.js +260 -0
- package/dist/vm/providers/vfkit.d.ts +40 -0
- package/dist/vm/providers/vfkit.js +371 -0
- package/dist/vm/providers/wsl2.d.ts +27 -0
- package/dist/vm/providers/wsl2.js +226 -0
- package/dist/vm/session-manager.d.ts +130 -0
- package/dist/vm/session-manager.js +494 -0
- package/dist/vm/session-snapshot.d.ts +31 -0
- package/dist/vm/session-snapshot.js +180 -0
- package/dist/vm/types.d.ts +73 -0
- package/dist/vm/types.js +2 -0
- package/dist/vm/vm-helper-client.d.ts +81 -0
- package/dist/vm/vm-helper-client.js +335 -0
- package/dist/vm/vm-helper.d.ts +11 -0
- package/dist/vm/vm-helper.js +156 -0
- package/dist/vm/vm-ipc-protocol.d.ts +84 -0
- package/dist/vm/vm-ipc-protocol.js +9 -0
- package/dist/vm/vm-manager-facade.d.ts +23 -0
- package/dist/vm/vm-manager-facade.js +43 -0
- package/dist/vm/vm-manager.d.ts +74 -0
- package/dist/vm/vm-manager.js +515 -0
- package/dist/vm/vm-process-proxy.d.ts +34 -0
- package/dist/vm/vm-process-proxy.js +64 -0
- package/dist/vm/vsock-bridge.d.ts +44 -0
- package/dist/vm/vsock-bridge.js +140 -0
- package/dist/vm/vsock-protocol.d.ts +98 -0
- package/dist/vm/vsock-protocol.js +57 -0
- package/package.json +65 -0
- package/rootfs/Dockerfile +50 -0
- package/rootfs/forge-mcp-relay.mjs +158 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import { initVmManager, getVmManager, } from "../vm/vm-manager-facade.js";
|
|
4
|
+
import { ensureImage } from "../vm/image-manager.js";
|
|
5
|
+
import { isDockerAvailable } from "../vm/docker-executor.js";
|
|
6
|
+
/**
|
|
7
|
+
* forge vm init — Check Docker availability and pull/build agent image.
|
|
8
|
+
*/
|
|
9
|
+
export async function vmInitAction() {
|
|
10
|
+
const spinner = ora("Checking Docker availability...").start();
|
|
11
|
+
try {
|
|
12
|
+
const available = await isDockerAvailable();
|
|
13
|
+
if (!available) {
|
|
14
|
+
spinner.fail("Docker not available");
|
|
15
|
+
console.log(chalk.yellow("\nDocker Desktop is required. Install it from https://docker.com/products/docker-desktop"));
|
|
16
|
+
console.log(chalk.yellow("Ensure the Docker daemon is running."));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
spinner.text = "Docker available. Checking agent image...";
|
|
20
|
+
const image = await ensureImage();
|
|
21
|
+
spinner.succeed(`Agent environment ready — image: ${image}`);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
spinner.fail(`Init failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* forge vm status — List active Docker container sessions.
|
|
30
|
+
*/
|
|
31
|
+
export async function vmStatusAction() {
|
|
32
|
+
try {
|
|
33
|
+
let sm;
|
|
34
|
+
try {
|
|
35
|
+
sm = getVmManager();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
sm = await initVmManager();
|
|
39
|
+
}
|
|
40
|
+
const sessions = sm.getAllSessions();
|
|
41
|
+
if (sessions.length === 0) {
|
|
42
|
+
console.log(chalk.dim("No active sessions"));
|
|
43
|
+
console.log(chalk.dim(`Docker ready: ${sm.isVmRunning() ? "yes" : "no"}`));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
console.log(chalk.bold(`\nActive sessions (${sessions.length}):\n`));
|
|
47
|
+
for (const session of sessions) {
|
|
48
|
+
const color = session.status === "RUNNING"
|
|
49
|
+
? chalk.green
|
|
50
|
+
: session.status === "SPAWNING"
|
|
51
|
+
? chalk.yellow
|
|
52
|
+
: chalk.dim;
|
|
53
|
+
console.log(` ${color("●")} ${session.id} task: ${session.taskId} status: ${color(session.status)} container: ${session.containerId?.slice(0, 12) ?? "N/A"}`);
|
|
54
|
+
}
|
|
55
|
+
console.log();
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
console.error(chalk.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* forge vm cleanup — Remove stopped session containers.
|
|
63
|
+
*/
|
|
64
|
+
export async function vmCleanupAction() {
|
|
65
|
+
const spinner = ora("Cleaning up...").start();
|
|
66
|
+
try {
|
|
67
|
+
let sm;
|
|
68
|
+
try {
|
|
69
|
+
sm = getVmManager();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
sm = await initVmManager();
|
|
73
|
+
}
|
|
74
|
+
const sessions = sm.getAllSessions();
|
|
75
|
+
let cleaned = 0;
|
|
76
|
+
for (const session of sessions) {
|
|
77
|
+
if (session.status === "STOPPED") {
|
|
78
|
+
await sm.destroySession(session.taskId);
|
|
79
|
+
cleaned++;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
spinner.succeed(`Cleaned up ${cleaned} session(s)`);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
spinner.fail(`Cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* forge vm stop-all — Stop all containers and shut down.
|
|
90
|
+
*/
|
|
91
|
+
export async function vmStopAllAction() {
|
|
92
|
+
const spinner = ora("Stopping all containers...").start();
|
|
93
|
+
try {
|
|
94
|
+
let sm;
|
|
95
|
+
try {
|
|
96
|
+
sm = getVmManager();
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
sm = await initVmManager();
|
|
100
|
+
}
|
|
101
|
+
await sm.shutdown();
|
|
102
|
+
spinner.succeed("All containers stopped");
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
spinner.fail(`Shutdown failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* forge auth setup-claude — Obtain a long-lived Claude Code OAuth token.
|
|
110
|
+
*/
|
|
111
|
+
export async function setupClaudeTokenAction() {
|
|
112
|
+
try {
|
|
113
|
+
const { runClaudeSetupToken } = await import("../vm/claude-token-manager.js");
|
|
114
|
+
await runClaudeSetupToken();
|
|
115
|
+
console.log(chalk.green("\nClaude OAuth token stored. Agents can now authenticate."));
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
console.error(chalk.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=vm.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { getConfig, getServerUrl } from "../config/config-manager.js";
|
|
5
|
+
import { loadToken } from "../config/token-manager.js";
|
|
6
|
+
import { createRestClient } from "../lib/rest-client.js";
|
|
7
|
+
import { cloneAndCheckout } from "../lib/clone-and-checkout.js";
|
|
8
|
+
import { openDirectory } from "../lib/open-directory.js";
|
|
9
|
+
export async function workflowOpenAction(workflowId) {
|
|
10
|
+
const token = loadToken();
|
|
11
|
+
if (!token) {
|
|
12
|
+
console.error(chalk.red('Not authenticated. Run "forge auth login" first.'));
|
|
13
|
+
process.exitCode = 1;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const config = getConfig();
|
|
17
|
+
const orgId = config.defaultOrgId;
|
|
18
|
+
if (!orgId) {
|
|
19
|
+
console.error(chalk.red('No organization selected. Run "forge connect" first.'));
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const serverUrl = getServerUrl();
|
|
24
|
+
const client = createRestClient(serverUrl, token, orgId);
|
|
25
|
+
const workflow = await client.getWorkflow(workflowId);
|
|
26
|
+
const branch = workflow.baseBranch ?? workflow.sourceBranch;
|
|
27
|
+
if (!branch) {
|
|
28
|
+
console.error(chalk.red("Workflow has no branch assigned yet."));
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (!workflow.project.repoUrl) {
|
|
33
|
+
console.error(chalk.red("Project has no repository URL configured."));
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const branchSlug = branch.replaceAll("/", "--");
|
|
38
|
+
const targetDir = join(homedir(), ".forgeai", "open", workflow.project.slug, branchSlug);
|
|
39
|
+
await cloneAndCheckout(workflow.project.repoUrl, branch, targetDir);
|
|
40
|
+
openDirectory(targetDir, config.opener ?? "terminal");
|
|
41
|
+
console.log(chalk.green(`Opened workflow "${workflow.name}" at ${targetDir}`));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=workflow-open.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type Opener = "terminal" | "vscode" | "finder";
|
|
2
|
+
export type CliConfig = {
|
|
3
|
+
serverUrl: string;
|
|
4
|
+
defaultOrg?: string;
|
|
5
|
+
defaultOrgId?: string;
|
|
6
|
+
linkedOrgs?: Array<{
|
|
7
|
+
orgId: string;
|
|
8
|
+
orgSlug: string;
|
|
9
|
+
orgName?: string;
|
|
10
|
+
}>;
|
|
11
|
+
cliId?: string;
|
|
12
|
+
cliName?: string;
|
|
13
|
+
agentType?: string;
|
|
14
|
+
agentSlots?: number;
|
|
15
|
+
opener?: Opener;
|
|
16
|
+
lastSyncCursor?: string;
|
|
17
|
+
lastSyncTimestamp?: string;
|
|
18
|
+
vmCpus?: number;
|
|
19
|
+
vmMemoryMB?: number;
|
|
20
|
+
};
|
|
21
|
+
export declare function getConfig(): CliConfig;
|
|
22
|
+
export declare function setConfig(config: Partial<CliConfig>): void;
|
|
23
|
+
export declare function removeLinkedOrg(orgSlug: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Clear all session-specific config fields (orgs, CLI identity, sync state).
|
|
26
|
+
* Preserves machine-level settings (serverUrl, agentSlots, VM config).
|
|
27
|
+
* Called on logout to ensure a clean slate for the next login.
|
|
28
|
+
*/
|
|
29
|
+
export declare function clearSessionConfig(): void;
|
|
30
|
+
export declare function getServerUrl(): string;
|
|
31
|
+
//# sourceMappingURL=config-manager.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const FORGEAI_DIR = join(homedir(), ".forgeai");
|
|
5
|
+
const CONFIG_FILE = join(FORGEAI_DIR, "config.json");
|
|
6
|
+
const DEFAULT_SERVER_URL = "http://localhost:3000";
|
|
7
|
+
function ensureDir() {
|
|
8
|
+
if (!existsSync(FORGEAI_DIR)) {
|
|
9
|
+
mkdirSync(FORGEAI_DIR, { recursive: true, mode: 0o700 });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function getConfig() {
|
|
13
|
+
ensureDir();
|
|
14
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
15
|
+
return { serverUrl: DEFAULT_SERVER_URL };
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
19
|
+
return JSON.parse(raw);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return { serverUrl: DEFAULT_SERVER_URL };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function setConfig(config) {
|
|
26
|
+
ensureDir();
|
|
27
|
+
const current = getConfig();
|
|
28
|
+
const merged = { ...current, ...config };
|
|
29
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2), {
|
|
30
|
+
encoding: "utf-8",
|
|
31
|
+
mode: 0o600,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export function removeLinkedOrg(orgSlug) {
|
|
35
|
+
const config = getConfig();
|
|
36
|
+
if (!config.linkedOrgs)
|
|
37
|
+
return;
|
|
38
|
+
const filtered = config.linkedOrgs.filter((o) => o.orgSlug !== orgSlug);
|
|
39
|
+
setConfig({ linkedOrgs: filtered });
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Clear all session-specific config fields (orgs, CLI identity, sync state).
|
|
43
|
+
* Preserves machine-level settings (serverUrl, agentSlots, VM config).
|
|
44
|
+
* Called on logout to ensure a clean slate for the next login.
|
|
45
|
+
*/
|
|
46
|
+
export function clearSessionConfig() {
|
|
47
|
+
ensureDir();
|
|
48
|
+
const config = getConfig();
|
|
49
|
+
const cleaned = { serverUrl: config.serverUrl };
|
|
50
|
+
if (config.agentType !== undefined) {
|
|
51
|
+
cleaned.agentType = config.agentType;
|
|
52
|
+
}
|
|
53
|
+
if (config.agentSlots !== undefined) {
|
|
54
|
+
cleaned.agentSlots = config.agentSlots;
|
|
55
|
+
}
|
|
56
|
+
if (config.vmCpus !== undefined) {
|
|
57
|
+
cleaned.vmCpus = config.vmCpus;
|
|
58
|
+
}
|
|
59
|
+
if (config.vmMemoryMB !== undefined) {
|
|
60
|
+
cleaned.vmMemoryMB = config.vmMemoryMB;
|
|
61
|
+
}
|
|
62
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(cleaned, null, 2), {
|
|
63
|
+
encoding: "utf-8",
|
|
64
|
+
mode: 0o600,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function getServerUrl() {
|
|
68
|
+
return getConfig().serverUrl;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get a stable machine hostname that doesn't change with network state.
|
|
3
|
+
* On macOS, `hostname()` returns the DNS hostname (e.g. "mac.home") which
|
|
4
|
+
* can change via DHCP. `scutil --get LocalHostName` returns the Bonjour
|
|
5
|
+
* hostname (e.g. "MacBook-Pro-de-Jeremy") which is stable.
|
|
6
|
+
*/
|
|
7
|
+
export declare function stableHostname(): string;
|
|
8
|
+
export declare function saveToken(token: string): void;
|
|
9
|
+
export declare function loadToken(): string | null;
|
|
10
|
+
export declare function deleteToken(): void;
|
|
11
|
+
//# sourceMappingURL=token-manager.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { createCipheriv, createDecipheriv, randomBytes, scryptSync, } from "node:crypto";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
4
|
+
import { homedir, hostname, userInfo } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
const AUTH_DIR = join(homedir(), ".forgeai", "auth");
|
|
7
|
+
const CREDENTIALS_FILE = join(AUTH_DIR, "credentials.json");
|
|
8
|
+
const ALGORITHM = "aes-256-gcm";
|
|
9
|
+
const KEY_LENGTH = 32;
|
|
10
|
+
const IV_LENGTH = 16;
|
|
11
|
+
const SALT_LENGTH = 16;
|
|
12
|
+
/**
|
|
13
|
+
* Get a stable machine hostname that doesn't change with network state.
|
|
14
|
+
* On macOS, `hostname()` returns the DNS hostname (e.g. "mac.home") which
|
|
15
|
+
* can change via DHCP. `scutil --get LocalHostName` returns the Bonjour
|
|
16
|
+
* hostname (e.g. "MacBook-Pro-de-Jeremy") which is stable.
|
|
17
|
+
*/
|
|
18
|
+
export function stableHostname() {
|
|
19
|
+
if (process.platform === "darwin") {
|
|
20
|
+
try {
|
|
21
|
+
return execSync("scutil --get LocalHostName", {
|
|
22
|
+
encoding: "utf-8",
|
|
23
|
+
timeout: 2000,
|
|
24
|
+
}).trim();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Fallback if scutil is unavailable
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return hostname().replace(/\.(home|local)$/i, "");
|
|
31
|
+
}
|
|
32
|
+
function deriveKey(salt) {
|
|
33
|
+
const machineId = `${stableHostname()}:${userInfo().username}`;
|
|
34
|
+
return scryptSync(machineId, salt, KEY_LENGTH);
|
|
35
|
+
}
|
|
36
|
+
function ensureAuthDir() {
|
|
37
|
+
if (!existsSync(AUTH_DIR)) {
|
|
38
|
+
mkdirSync(AUTH_DIR, { recursive: true, mode: 0o700 });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function saveToken(token) {
|
|
42
|
+
ensureAuthDir();
|
|
43
|
+
const salt = randomBytes(SALT_LENGTH);
|
|
44
|
+
const key = deriveKey(salt);
|
|
45
|
+
const iv = randomBytes(IV_LENGTH);
|
|
46
|
+
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
47
|
+
let encrypted = cipher.update(token, "utf-8", "hex");
|
|
48
|
+
encrypted += cipher.final("hex");
|
|
49
|
+
const tag = cipher.getAuthTag();
|
|
50
|
+
const credentials = {
|
|
51
|
+
iv: iv.toString("hex"),
|
|
52
|
+
data: encrypted,
|
|
53
|
+
tag: tag.toString("hex"),
|
|
54
|
+
salt: salt.toString("hex"),
|
|
55
|
+
};
|
|
56
|
+
writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), {
|
|
57
|
+
encoding: "utf-8",
|
|
58
|
+
mode: 0o600,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export function loadToken() {
|
|
62
|
+
if (!existsSync(CREDENTIALS_FILE)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const raw = readFileSync(CREDENTIALS_FILE, "utf-8");
|
|
67
|
+
const credentials = JSON.parse(raw);
|
|
68
|
+
const salt = Buffer.from(credentials.salt, "hex");
|
|
69
|
+
const key = deriveKey(salt);
|
|
70
|
+
const iv = Buffer.from(credentials.iv, "hex");
|
|
71
|
+
const tag = Buffer.from(credentials.tag, "hex");
|
|
72
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
73
|
+
decipher.setAuthTag(tag);
|
|
74
|
+
let decrypted = decipher.update(credentials.data, "hex", "utf-8");
|
|
75
|
+
decrypted += decipher.final("utf-8");
|
|
76
|
+
return decrypted;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function deleteToken() {
|
|
83
|
+
if (existsSync(CREDENTIALS_FILE)) {
|
|
84
|
+
unlinkSync(CREDENTIALS_FILE);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=token-manager.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI version, read from package.json so `forge --version` can never drift
|
|
3
|
+
* from the published version (it used to be hardcoded here and silently
|
|
4
|
+
* reported a stale number). Falls back to "0.0.0-unknown" if package.json is
|
|
5
|
+
* unreadable, so version reporting never crashes the CLI.
|
|
6
|
+
*/
|
|
7
|
+
export declare const VERSION: string;
|
|
8
|
+
export { createCliAuthClient } from "./lib/auth-client.js";
|
|
9
|
+
export { getConfig, setConfig, getServerUrl } from "./config/config-manager.js";
|
|
10
|
+
export { saveToken, loadToken, deleteToken } from "./config/token-manager.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
/**
|
|
3
|
+
* The CLI version, read from package.json so `forge --version` can never drift
|
|
4
|
+
* from the published version (it used to be hardcoded here and silently
|
|
5
|
+
* reported a stale number). Falls back to "0.0.0-unknown" if package.json is
|
|
6
|
+
* unreadable, so version reporting never crashes the CLI.
|
|
7
|
+
*/
|
|
8
|
+
export const VERSION = (() => {
|
|
9
|
+
try {
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
// From dist/index.js (or src/index.ts), ../package.json is the CLI manifest.
|
|
12
|
+
const pkg = require("../package.json");
|
|
13
|
+
return pkg.version ?? "0.0.0-unknown";
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return "0.0.0-unknown";
|
|
17
|
+
}
|
|
18
|
+
})();
|
|
19
|
+
export { createCliAuthClient } from "./lib/auth-client.js";
|
|
20
|
+
export { getConfig, setConfig, getServerUrl } from "./config/config-manager.js";
|
|
21
|
+
export { saveToken, loadToken, deleteToken } from "./config/token-manager.js";
|
|
22
|
+
//# sourceMappingURL=index.js.map
|