@vectorplane/ctrl-cli 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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +167 -0
  3. package/bin/vp.js +12 -0
  4. package/dist/commands/bootstrap.d.ts +1 -0
  5. package/dist/commands/bootstrap.js +40 -0
  6. package/dist/commands/config.d.ts +1 -0
  7. package/dist/commands/config.js +96 -0
  8. package/dist/commands/context.d.ts +1 -0
  9. package/dist/commands/context.js +46 -0
  10. package/dist/commands/doctor.d.ts +1 -0
  11. package/dist/commands/doctor.js +69 -0
  12. package/dist/commands/event.d.ts +1 -0
  13. package/dist/commands/event.js +65 -0
  14. package/dist/commands/login.d.ts +1 -0
  15. package/dist/commands/login.js +39 -0
  16. package/dist/commands/session.d.ts +1 -0
  17. package/dist/commands/session.js +110 -0
  18. package/dist/commands/status.d.ts +1 -0
  19. package/dist/commands/status.js +46 -0
  20. package/dist/commands/sync.d.ts +1 -0
  21. package/dist/commands/sync.js +108 -0
  22. package/dist/commands/whoami.d.ts +1 -0
  23. package/dist/commands/whoami.js +32 -0
  24. package/dist/commands/workspace.d.ts +1 -0
  25. package/dist/commands/workspace.js +66 -0
  26. package/dist/core/api.d.ts +24 -0
  27. package/dist/core/api.js +190 -0
  28. package/dist/core/auth.d.ts +16 -0
  29. package/dist/core/auth.js +71 -0
  30. package/dist/core/cli.d.ts +9 -0
  31. package/dist/core/cli.js +66 -0
  32. package/dist/core/config.d.ts +31 -0
  33. package/dist/core/config.js +263 -0
  34. package/dist/core/constants.d.ts +22 -0
  35. package/dist/core/constants.js +78 -0
  36. package/dist/core/env.d.ts +2 -0
  37. package/dist/core/env.js +10 -0
  38. package/dist/core/errors.d.ts +18 -0
  39. package/dist/core/errors.js +37 -0
  40. package/dist/core/git.d.ts +2 -0
  41. package/dist/core/git.js +66 -0
  42. package/dist/core/logger.d.ts +8 -0
  43. package/dist/core/logger.js +52 -0
  44. package/dist/core/machine.d.ts +4 -0
  45. package/dist/core/machine.js +87 -0
  46. package/dist/core/queue.d.ts +14 -0
  47. package/dist/core/queue.js +62 -0
  48. package/dist/core/runtime.d.ts +13 -0
  49. package/dist/core/runtime.js +16 -0
  50. package/dist/core/serializer.d.ts +7 -0
  51. package/dist/core/serializer.js +31 -0
  52. package/dist/core/server.d.ts +10 -0
  53. package/dist/core/server.js +84 -0
  54. package/dist/core/session.d.ts +16 -0
  55. package/dist/core/session.js +35 -0
  56. package/dist/core/workspace-binding.d.ts +15 -0
  57. package/dist/core/workspace-binding.js +41 -0
  58. package/dist/core/workspace.d.ts +2 -0
  59. package/dist/core/workspace.js +121 -0
  60. package/dist/index.d.ts +1 -0
  61. package/dist/index.js +97 -0
  62. package/dist/types/api.d.ts +61 -0
  63. package/dist/types/api.js +2 -0
  64. package/dist/types/auth.d.ts +36 -0
  65. package/dist/types/auth.js +2 -0
  66. package/dist/types/config.d.ts +58 -0
  67. package/dist/types/config.js +2 -0
  68. package/dist/types/machine.d.ts +49 -0
  69. package/dist/types/machine.js +2 -0
  70. package/dist/types/snapshot.d.ts +15 -0
  71. package/dist/types/snapshot.js +2 -0
  72. package/dist/types/workspace.d.ts +44 -0
  73. package/dist/types/workspace.js +2 -0
  74. package/package.json +61 -0
@@ -0,0 +1,110 @@
1
+ import { getStringOption, parseArgs } from "../core/cli.js";
2
+ import { ensureSessionAvailable, getProfileState, updateProfileState } from "../core/config.js";
3
+ import { collectGitContext } from "../core/git.js";
4
+ import { collectMachineContext, collectRuntimeContext } from "../core/machine.js";
5
+ import { loadRuntimeStatus } from "../core/runtime.js";
6
+ import { ensureFreshSession, resolveWorkspaceSlug } from "../core/session.js";
7
+ import { VectorPlaneApiClient } from "../core/api.js";
8
+ import { deriveClientInstanceId, getBoundWorkspace, resolveWorkspaceRoot } from "../core/workspace-binding.js";
9
+ import { ValidationError } from "../core/errors.js";
10
+ export async function runSessionCommand(cliVersion, args) {
11
+ const parsed = parseArgs(args);
12
+ const [subcommand] = parsed.positionals;
13
+ if (!subcommand) {
14
+ throw new ValidationError("Uso: vp session <check-in|heartbeat|check-out>");
15
+ }
16
+ const runtime = await loadRuntimeStatus();
17
+ const session = await ensureSessionAvailable(runtime.profile.name);
18
+ const [git, machine, runtimeContext] = await Promise.all([
19
+ collectGitContext(process.cwd()),
20
+ collectMachineContext(runtime.device, runtime.config),
21
+ collectRuntimeContext(cliVersion, `session:${subcommand}`, process.argv.slice(2)),
22
+ ]);
23
+ const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
24
+ const freshSession = await ensureFreshSession({
25
+ profileName: runtime.profile.name,
26
+ session,
27
+ machine,
28
+ runtime: runtimeContext,
29
+ device: runtime.device,
30
+ apiClient,
31
+ logger: runtime.logger,
32
+ });
33
+ const rootPath = resolveWorkspaceRoot(process.cwd(), git);
34
+ const boundWorkspace = await getBoundWorkspace(rootPath);
35
+ const profileState = getProfileState(runtime.state, runtime.profile.name);
36
+ const workspace = resolveWorkspaceSlug(runtime.profile, freshSession, getStringOption(parsed, "workspace"), boundWorkspace, profileState.lastWorkspace);
37
+ if (!workspace) {
38
+ throw new ValidationError("Nenhum workspace resolvido para a sessão.");
39
+ }
40
+ const clientInstanceId = getStringOption(parsed, "client-instance-id") ?? deriveClientInstanceId(runtime.device.machineId, rootPath, git);
41
+ if (subcommand === "check-in") {
42
+ const response = await apiClient.checkInAgent(freshSession.accessToken, {
43
+ workspaceId: workspace,
44
+ agentName: getStringOption(parsed, "agent-name") ?? "vp-cli",
45
+ agentType: getStringOption(parsed, "agent-type") ?? "vp-cli",
46
+ clientName: getStringOption(parsed, "client-name") ?? "vectorplane-ctrl-cli",
47
+ clientInstanceId,
48
+ repoUrl: git.remoteOrigin ?? undefined,
49
+ branch: git.branch,
50
+ commitSha: git.commitHash,
51
+ metadata: {
52
+ source: "vp-cli",
53
+ rootPath,
54
+ },
55
+ });
56
+ const sessionId = String(response.id ?? response.sessionId ?? "");
57
+ await updateProfileState(runtime.profile.name, {
58
+ lastSessionId: sessionId || profileState.lastSessionId,
59
+ lastCommand: "session:check-in",
60
+ lastWorkspace: workspace,
61
+ lastError: null,
62
+ });
63
+ process.stdout.write(`Session ID: ${sessionId || "não retornado"}\n`);
64
+ process.stdout.write(`Client Instance ID: ${clientInstanceId}\n`);
65
+ return 0;
66
+ }
67
+ if (subcommand === "heartbeat") {
68
+ const sessionId = getStringOption(parsed, "session-id") ?? profileState.lastSessionId;
69
+ if (!sessionId) {
70
+ throw new ValidationError("Nenhuma sessão conhecida para heartbeat.");
71
+ }
72
+ await apiClient.heartbeatAgent(freshSession.accessToken, {
73
+ sessionId,
74
+ clientInstanceId,
75
+ branch: git.branch,
76
+ commitSha: git.commitHash,
77
+ metadata: {
78
+ source: "vp-cli",
79
+ rootPath,
80
+ },
81
+ });
82
+ await updateProfileState(runtime.profile.name, {
83
+ lastCommand: "session:heartbeat",
84
+ lastError: null,
85
+ });
86
+ process.stdout.write(`Heartbeat enviado para ${sessionId}\n`);
87
+ return 0;
88
+ }
89
+ if (subcommand === "check-out") {
90
+ const sessionId = getStringOption(parsed, "session-id") ?? profileState.lastSessionId;
91
+ if (!sessionId) {
92
+ throw new ValidationError("Nenhuma sessão conhecida para check-out.");
93
+ }
94
+ await apiClient.checkOutAgent(freshSession.accessToken, {
95
+ sessionId,
96
+ metadata: {
97
+ source: "vp-cli",
98
+ },
99
+ });
100
+ await updateProfileState(runtime.profile.name, {
101
+ lastSessionId: null,
102
+ lastCommand: "session:check-out",
103
+ lastError: null,
104
+ });
105
+ process.stdout.write(`Sessão encerrada: ${sessionId}\n`);
106
+ return 0;
107
+ }
108
+ throw new ValidationError("Subcomando de sessão não suportado.");
109
+ }
110
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ export declare function runStatusCommand(): Promise<number>;
@@ -0,0 +1,46 @@
1
+ import { configDirectoryExists, getConfigDirectoryPath, getProfileState, loadQueue, loadSession } from "../core/config.js";
2
+ import { collectGitContext } from "../core/git.js";
3
+ import { getBoundWorkspace } from "../core/workspace-binding.js";
4
+ import { loadRuntimeStatus } from "../core/runtime.js";
5
+ export async function runStatusCommand() {
6
+ const runtime = await loadRuntimeStatus();
7
+ const [hasConfigDir, session, git, configDirectory, queue] = await Promise.all([
8
+ configDirectoryExists(),
9
+ loadSession(runtime.profile.name),
10
+ collectGitContext(process.cwd()),
11
+ getConfigDirectoryPath(),
12
+ loadQueue(),
13
+ ]);
14
+ const rootPath = git.rootPath ?? process.cwd();
15
+ const boundWorkspace = await getBoundWorkspace(rootPath);
16
+ const profileState = getProfileState(runtime.state, runtime.profile.name);
17
+ const queuedItems = queue.items.filter((item) => item.profile === runtime.profile.name).length;
18
+ process.stdout.write(`Perfil: ${runtime.profile.name}\n`);
19
+ process.stdout.write(`Diretório: ${process.cwd()}\n`);
20
+ process.stdout.write(`Persistência local: ${configDirectory}\n`);
21
+ process.stdout.write(`Machine ID: ${runtime.device.machineId}\n`);
22
+ process.stdout.write(`Fila pendente: ${queuedItems}\n`);
23
+ if (!hasConfigDir || !session) {
24
+ runtime.logger.warn("sessão não encontrada.");
25
+ process.stdout.write(`Workspace vinculado: ${boundWorkspace ?? runtime.profile.workspace ?? "nenhum"}\n`);
26
+ return 0;
27
+ }
28
+ runtime.logger.success("sessão ativa.");
29
+ process.stdout.write(`Workspace: ${session.workspace}\n`);
30
+ process.stdout.write(`Workspace vinculado: ${boundWorkspace ?? runtime.profile.workspace ?? "nenhum"}\n`);
31
+ process.stdout.write(`Sessão de agente: ${profileState.lastSessionId ?? "nenhuma"}\n`);
32
+ process.stdout.write(`Expira em: ${session.expiresAt}\n`);
33
+ if (git.branch) {
34
+ process.stdout.write(`Branch: ${git.branch}\n`);
35
+ }
36
+ process.stdout.write(`Última sincronização: ${profileState.lastSyncAt ?? "nunca"}\n`);
37
+ process.stdout.write(`Status do último sync: ${profileState.lastSyncStatus ?? "desconhecido"}\n`);
38
+ if (profileState.lastSnapshotPath) {
39
+ process.stdout.write(`Último snapshot local: ${profileState.lastSnapshotPath}\n`);
40
+ }
41
+ if (profileState.lastError) {
42
+ process.stdout.write(`Último erro: ${profileState.lastError}\n`);
43
+ }
44
+ return 0;
45
+ }
46
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ export declare function runSyncCommand(cliVersion: string, args: string[]): Promise<number>;
@@ -0,0 +1,108 @@
1
+ import { getBooleanOption, getStringOption, parseArgs } from "../core/cli.js";
2
+ import { ensureSessionAvailable, getProfileState, persistSnapshot, updateProfileState } from "../core/config.js";
3
+ import { collectGitContext } from "../core/git.js";
4
+ import { collectMachineContext, collectRuntimeContext } from "../core/machine.js";
5
+ import { flushQueue, queueSync } from "../core/queue.js";
6
+ import { loadRuntimeStatus } from "../core/runtime.js";
7
+ import { buildSnapshotEnvelope } from "../core/serializer.js";
8
+ import { ensureFreshSession, resolveWorkspaceSlug } from "../core/session.js";
9
+ import { VectorPlaneApiClient } from "../core/api.js";
10
+ import { collectWorkspaceContext } from "../core/workspace.js";
11
+ import { getBoundWorkspace } from "../core/workspace-binding.js";
12
+ import { ValidationError } from "../core/errors.js";
13
+ export async function runSyncCommand(cliVersion, args) {
14
+ const parsed = parseArgs(args);
15
+ const force = getBooleanOption(parsed, "force");
16
+ const explicitWorkspace = getStringOption(parsed, "workspace");
17
+ const runtime = await loadRuntimeStatus();
18
+ const session = await ensureSessionAvailable(runtime.profile.name);
19
+ const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
20
+ runtime.logger.info("analisando workspace...");
21
+ const [machine, runtimeContext, git] = await Promise.all([
22
+ collectMachineContext(runtime.device, runtime.config),
23
+ collectRuntimeContext(cliVersion, "sync", process.argv.slice(2)),
24
+ collectGitContext(process.cwd()),
25
+ ]);
26
+ const freshSession = await ensureFreshSession({
27
+ profileName: runtime.profile.name,
28
+ session,
29
+ machine,
30
+ runtime: runtimeContext,
31
+ device: runtime.device,
32
+ apiClient,
33
+ logger: runtime.logger,
34
+ });
35
+ const workspaceRoot = git.rootPath ?? process.cwd();
36
+ const boundWorkspace = await getBoundWorkspace(workspaceRoot);
37
+ const profileState = getProfileState(runtime.state, runtime.profile.name);
38
+ const workspaceSlug = resolveWorkspaceSlug(runtime.profile, freshSession, explicitWorkspace, boundWorkspace, profileState.lastWorkspace);
39
+ if (!workspaceSlug) {
40
+ throw new ValidationError("Nenhum workspace ativo foi resolvido. Use `vp workspace use <workspace>` ou `vp login`.");
41
+ }
42
+ const workspace = await collectWorkspaceContext(process.cwd(), git);
43
+ runtime.logger.info("consolidando contexto...");
44
+ const timestamp = new Date().toISOString();
45
+ const snapshot = {
46
+ machine,
47
+ runtime: runtimeContext,
48
+ workspace,
49
+ git,
50
+ command: {
51
+ name: "sync",
52
+ startedAt: timestamp,
53
+ cwd: process.cwd(),
54
+ },
55
+ timestamp,
56
+ };
57
+ const { hash } = buildSnapshotEnvelope(snapshot);
58
+ if (!force && profileState.lastSyncHash === hash) {
59
+ runtime.logger.info("nenhuma mudança material detectada desde o último sync.");
60
+ return 0;
61
+ }
62
+ const snapshotPath = await persistSnapshot(runtime.profile.name, hash, snapshot);
63
+ const syncPayload = {
64
+ workspace: workspaceSlug,
65
+ command: "sync",
66
+ snapshot,
67
+ hash,
68
+ sent_at: timestamp,
69
+ };
70
+ const flushResult = await flushQueue({
71
+ profile: runtime.profile.name,
72
+ accessToken: freshSession.accessToken,
73
+ apiClient,
74
+ logger: runtime.logger,
75
+ queueMaxRetries: runtime.config.queueMaxRetries,
76
+ });
77
+ if (flushResult.delivered > 0 || flushResult.kept > 0) {
78
+ runtime.logger.info(`fila local processada: ${flushResult.delivered} entregues, ${flushResult.kept} mantidos.`);
79
+ }
80
+ try {
81
+ await apiClient.sync(freshSession.accessToken, syncPayload);
82
+ await updateProfileState(runtime.profile.name, {
83
+ lastCommand: "sync",
84
+ lastSyncAt: timestamp,
85
+ lastWorkspace: workspaceSlug,
86
+ lastSyncHash: hash,
87
+ lastSyncStatus: "success",
88
+ lastError: null,
89
+ lastSnapshotPath: snapshotPath,
90
+ });
91
+ runtime.logger.success("sincronização concluída.");
92
+ return 0;
93
+ }
94
+ catch (error) {
95
+ await queueSync(runtime.profile.name, syncPayload, error);
96
+ await updateProfileState(runtime.profile.name, {
97
+ lastCommand: "sync",
98
+ lastWorkspace: workspaceSlug,
99
+ lastSyncHash: hash,
100
+ lastSyncStatus: "queued",
101
+ lastError: error instanceof Error ? error.message : String(error),
102
+ lastSnapshotPath: snapshotPath,
103
+ });
104
+ runtime.logger.warn("API indisponível no momento. O sync foi enfileirado localmente.");
105
+ return 0;
106
+ }
107
+ }
108
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ export declare function runWhoAmICommand(cliVersion: string): Promise<number>;
@@ -0,0 +1,32 @@
1
+ import { ensureSessionAvailable } from "../core/config.js";
2
+ import { collectMachineContext, collectRuntimeContext } from "../core/machine.js";
3
+ import { loadRuntimeStatus } from "../core/runtime.js";
4
+ import { ensureFreshSession } from "../core/session.js";
5
+ import { VectorPlaneApiClient } from "../core/api.js";
6
+ export async function runWhoAmICommand(cliVersion) {
7
+ const runtime = await loadRuntimeStatus();
8
+ const session = await ensureSessionAvailable(runtime.profile.name);
9
+ const machine = await collectMachineContext(runtime.device, runtime.config);
10
+ const runtimeContext = await collectRuntimeContext(cliVersion, "whoami", process.argv.slice(2));
11
+ const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
12
+ const freshSession = await ensureFreshSession({
13
+ profileName: runtime.profile.name,
14
+ session,
15
+ machine,
16
+ runtime: runtimeContext,
17
+ device: runtime.device,
18
+ apiClient,
19
+ logger: runtime.logger,
20
+ });
21
+ const me = await apiClient.getCurrentUser(freshSession.accessToken);
22
+ process.stdout.write(`Perfil: ${runtime.profile.name}\n`);
23
+ process.stdout.write(`ID: ${me.id}\n`);
24
+ process.stdout.write(`Tipo: ${me.type}\n`);
25
+ process.stdout.write(`Nome: ${me.name ?? "n/a"}\n`);
26
+ process.stdout.write(`Email: ${me.email ?? "n/a"}\n`);
27
+ process.stdout.write(`Workspace: ${freshSession.workspace}\n`);
28
+ process.stdout.write(`Orgs: ${me.orgIds.join(", ") || "nenhuma"}\n`);
29
+ process.stdout.write(`Capabilities: ${me.capabilities.join(", ") || "nenhuma"}\n`);
30
+ return 0;
31
+ }
32
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ export declare function runWorkspaceCommand(args: string[]): Promise<number>;
@@ -0,0 +1,66 @@
1
+ import { getStringOption, parseArgs, requirePositional } from "../core/cli.js";
2
+ import { ensureSessionAvailable, upsertProfile } from "../core/config.js";
3
+ import { collectGitContext } from "../core/git.js";
4
+ import { loadRuntimeStatus } from "../core/runtime.js";
5
+ import { VectorPlaneApiClient } from "../core/api.js";
6
+ import { bindWorkspaceToRoot, clearBoundWorkspace, getBindingStore, resolveWorkspaceRoot } from "../core/workspace-binding.js";
7
+ import { ValidationError } from "../core/errors.js";
8
+ export async function runWorkspaceCommand(args) {
9
+ const parsed = parseArgs(args);
10
+ const [subcommand] = parsed.positionals;
11
+ const runtime = await loadRuntimeStatus();
12
+ const git = await collectGitContext(process.cwd());
13
+ const rootPath = resolveWorkspaceRoot(process.cwd(), git);
14
+ if (!subcommand || subcommand === "current") {
15
+ const store = await getBindingStore();
16
+ const binding = store.bindings[rootPath];
17
+ process.stdout.write(`Root: ${rootPath}\n`);
18
+ process.stdout.write(`Workspace: ${binding?.workspace ?? runtime.profile.workspace ?? "nenhum"}\n`);
19
+ process.stdout.write(`Source: ${binding?.source ?? "perfil"}\n`);
20
+ return 0;
21
+ }
22
+ if (subcommand === "use") {
23
+ const workspace = requirePositional(parsed, 1, "Informe o workspace.");
24
+ await bindWorkspaceToRoot({
25
+ rootPath,
26
+ workspace,
27
+ repoUrl: git.remoteOrigin,
28
+ source: "manual",
29
+ });
30
+ await upsertProfile(runtime.profile.name, { workspace });
31
+ process.stdout.write(`Workspace associado a ${rootPath}: ${workspace}\n`);
32
+ return 0;
33
+ }
34
+ if (subcommand === "clear") {
35
+ await clearBoundWorkspace(rootPath);
36
+ process.stdout.write(`Binding removido de ${rootPath}\n`);
37
+ return 0;
38
+ }
39
+ if (subcommand === "resolve") {
40
+ const session = await ensureSessionAvailable(runtime.profile.name);
41
+ const repoUrl = getStringOption(parsed, "repo") ?? git.remoteOrigin;
42
+ if (!repoUrl) {
43
+ throw new ValidationError("Nenhum remote git disponível para resolver o workspace.");
44
+ }
45
+ const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
46
+ const response = await apiClient.resolveWorkspaceByRepo(session.accessToken, {
47
+ repoUrl,
48
+ orgId: runtime.profile.orgId ?? undefined,
49
+ });
50
+ const workspace = String(response.workspaceId ?? response.id ?? response.slug ?? "");
51
+ if (!workspace) {
52
+ throw new ValidationError("A resolução de workspace não retornou um identificador utilizável.");
53
+ }
54
+ await bindWorkspaceToRoot({
55
+ rootPath,
56
+ workspace,
57
+ repoUrl,
58
+ source: "api-resolve",
59
+ });
60
+ await upsertProfile(runtime.profile.name, { workspace });
61
+ process.stdout.write(`Workspace resolvido: ${workspace}\n`);
62
+ return 0;
63
+ }
64
+ throw new ValidationError("Subcomando de workspace não suportado.");
65
+ }
66
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1,24 @@
1
+ import type { Logger } from "./logger.js";
2
+ import type { CurrentUserResponse, AuthCodeExchangeRequest, AuthTokenExchangeResponse, RefreshTokenRequest } from "../types/auth.js";
3
+ import type { AgentCheckoutRequest, AgentHeartbeatRequest, AgentSessionRequest, AgentSessionResponse, EventRequest, ResolveWorkspaceRequest, ResolveWorkspaceResponse, SyncRequest, SyncResponse } from "../types/api.js";
4
+ export declare class VectorPlaneApiClient {
5
+ private readonly apiBaseUrl;
6
+ private readonly timeoutMs;
7
+ private readonly logger;
8
+ constructor(apiBaseUrl: string, timeoutMs: number, logger: Logger);
9
+ exchangeToken(payload: AuthCodeExchangeRequest): Promise<AuthTokenExchangeResponse>;
10
+ refreshToken(payload: RefreshTokenRequest): Promise<AuthTokenExchangeResponse>;
11
+ getCurrentUser(accessToken: string): Promise<CurrentUserResponse>;
12
+ sync(accessToken: string, payload: SyncRequest): Promise<SyncResponse>;
13
+ sendEvent(accessToken: string, payload: EventRequest): Promise<Record<string, unknown>>;
14
+ resolveWorkspaceByRepo(accessToken: string, payload: ResolveWorkspaceRequest): Promise<ResolveWorkspaceResponse>;
15
+ getWorkspaceContext(accessToken: string, workspaceId: string): Promise<Record<string, unknown>>;
16
+ getWorkspaceSnapshot(accessToken: string, workspaceId: string): Promise<Record<string, unknown>>;
17
+ getWorkspaceDeliveryContext(accessToken: string, workspaceId: string): Promise<Record<string, unknown>>;
18
+ getAgentSetup(accessToken: string, workspaceId: string): Promise<Record<string, unknown>>;
19
+ checkInAgent(accessToken: string, payload: AgentSessionRequest): Promise<AgentSessionResponse>;
20
+ heartbeatAgent(accessToken: string, payload: AgentHeartbeatRequest): Promise<AgentSessionResponse>;
21
+ checkOutAgent(accessToken: string, payload: AgentCheckoutRequest): Promise<AgentSessionResponse>;
22
+ getHealth(): Promise<Record<string, unknown>>;
23
+ getReady(): Promise<Record<string, unknown>>;
24
+ }
@@ -0,0 +1,190 @@
1
+ import { ApiError } from "./errors.js";
2
+ async function parseBody(response) {
3
+ const contentType = response.headers.get("content-type") ?? "";
4
+ if (contentType.includes("application/json")) {
5
+ return response.json();
6
+ }
7
+ return response.text();
8
+ }
9
+ function unwrapEnvelope(body) {
10
+ if (body && typeof body === "object" && "success" in body) {
11
+ const envelope = body;
12
+ if (envelope.success) {
13
+ return envelope.data;
14
+ }
15
+ const message = typeof envelope.error?.message === "string" ? envelope.error.message : "Falha na API do VectorPlane.";
16
+ throw new ApiError(message, undefined, body);
17
+ }
18
+ return body;
19
+ }
20
+ async function requestJson(url, init, timeoutMs, logger) {
21
+ const controller = new AbortController();
22
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
23
+ try {
24
+ logger.debug("http_request", { method: init.method ?? "GET", url });
25
+ const response = await fetch(url, { ...init, signal: controller.signal });
26
+ const body = await parseBody(response);
27
+ if (!response.ok) {
28
+ const message = typeof body === "string"
29
+ ? body
30
+ : typeof body === "object" && body && "error" in body
31
+ ? String((body.error?.message) ?? `HTTP ${response.status}`)
32
+ : typeof body === "object" && body && "message" in body
33
+ ? String(body.message)
34
+ : `HTTP ${response.status}`;
35
+ throw new ApiError(message, response.status, body);
36
+ }
37
+ return unwrapEnvelope(body);
38
+ }
39
+ catch (error) {
40
+ if (error instanceof ApiError) {
41
+ throw error;
42
+ }
43
+ if (error.name === "AbortError") {
44
+ throw new ApiError("A requisição para a API expirou.");
45
+ }
46
+ throw new ApiError("Falha na comunicação com a API do VectorPlane.", undefined, error);
47
+ }
48
+ finally {
49
+ clearTimeout(timer);
50
+ }
51
+ }
52
+ function authHeaders(accessToken) {
53
+ return {
54
+ "Authorization": `Bearer ${accessToken}`,
55
+ "Content-Type": "application/json",
56
+ };
57
+ }
58
+ export class VectorPlaneApiClient {
59
+ apiBaseUrl;
60
+ timeoutMs;
61
+ logger;
62
+ constructor(apiBaseUrl, timeoutMs, logger) {
63
+ this.apiBaseUrl = apiBaseUrl;
64
+ this.timeoutMs = timeoutMs;
65
+ this.logger = logger;
66
+ }
67
+ async exchangeToken(payload) {
68
+ return requestJson(`${this.apiBaseUrl}/cli/token/exchange`, {
69
+ method: "POST",
70
+ headers: { "Content-Type": "application/json" },
71
+ body: JSON.stringify(payload),
72
+ }, this.timeoutMs, this.logger);
73
+ }
74
+ async refreshToken(payload) {
75
+ return requestJson(`${this.apiBaseUrl}/cli/token/refresh`, {
76
+ method: "POST",
77
+ headers: { "Content-Type": "application/json" },
78
+ body: JSON.stringify(payload),
79
+ }, this.timeoutMs, this.logger);
80
+ }
81
+ async getCurrentUser(accessToken) {
82
+ return requestJson(`${this.apiBaseUrl}/auth/me`, {
83
+ method: "GET",
84
+ headers: {
85
+ "Authorization": `Bearer ${accessToken}`,
86
+ },
87
+ }, this.timeoutMs, this.logger);
88
+ }
89
+ async sync(accessToken, payload) {
90
+ return requestJson(`${this.apiBaseUrl}/sync`, {
91
+ method: "POST",
92
+ headers: authHeaders(accessToken),
93
+ body: JSON.stringify(payload),
94
+ }, this.timeoutMs, this.logger);
95
+ }
96
+ async sendEvent(accessToken, payload) {
97
+ return requestJson(`${this.apiBaseUrl}/events`, {
98
+ method: "POST",
99
+ headers: authHeaders(accessToken),
100
+ body: JSON.stringify(payload),
101
+ }, this.timeoutMs, this.logger);
102
+ }
103
+ async resolveWorkspaceByRepo(accessToken, payload) {
104
+ return requestJson(`${this.apiBaseUrl}/cli/workspace/resolve`, {
105
+ method: "POST",
106
+ headers: authHeaders(accessToken),
107
+ body: JSON.stringify(payload),
108
+ }, this.timeoutMs, this.logger);
109
+ }
110
+ async getWorkspaceContext(accessToken, workspaceId) {
111
+ return requestJson(`${this.apiBaseUrl}/cli/workspace/${workspaceId}/context`, {
112
+ method: "GET",
113
+ headers: {
114
+ "Authorization": `Bearer ${accessToken}`,
115
+ },
116
+ }, this.timeoutMs, this.logger);
117
+ }
118
+ async getWorkspaceSnapshot(accessToken, workspaceId) {
119
+ return requestJson(`${this.apiBaseUrl}/cli/workspace/${workspaceId}/snapshot`, {
120
+ method: "GET",
121
+ headers: {
122
+ "Authorization": `Bearer ${accessToken}`,
123
+ },
124
+ }, this.timeoutMs, this.logger);
125
+ }
126
+ async getWorkspaceDeliveryContext(accessToken, workspaceId) {
127
+ return requestJson(`${this.apiBaseUrl}/cli/workspace/${workspaceId}/delivery-context`, {
128
+ method: "GET",
129
+ headers: {
130
+ "Authorization": `Bearer ${accessToken}`,
131
+ },
132
+ }, this.timeoutMs, this.logger);
133
+ }
134
+ async getAgentSetup(accessToken, workspaceId) {
135
+ return requestJson(`${this.apiBaseUrl}/cli/workspace/${workspaceId}/agent-setup`, {
136
+ method: "GET",
137
+ headers: {
138
+ "Authorization": `Bearer ${accessToken}`,
139
+ },
140
+ }, this.timeoutMs, this.logger);
141
+ }
142
+ async checkInAgent(accessToken, payload) {
143
+ return requestJson(`${this.apiBaseUrl}/cli/workspace/${payload.workspaceId}/agents/check-in`, {
144
+ method: "POST",
145
+ headers: authHeaders(accessToken),
146
+ body: JSON.stringify({
147
+ agentName: payload.agentName,
148
+ agentType: payload.agentType,
149
+ clientName: payload.clientName,
150
+ clientInstanceId: payload.clientInstanceId,
151
+ repoUrl: payload.repoUrl,
152
+ branch: payload.branch,
153
+ commitSha: payload.commitSha,
154
+ metadata: payload.metadata,
155
+ }),
156
+ }, this.timeoutMs, this.logger);
157
+ }
158
+ async heartbeatAgent(accessToken, payload) {
159
+ return requestJson(`${this.apiBaseUrl}/agent-sessions/${payload.sessionId}/heartbeat`, {
160
+ method: "POST",
161
+ headers: authHeaders(accessToken),
162
+ body: JSON.stringify({
163
+ clientInstanceId: payload.clientInstanceId,
164
+ branch: payload.branch,
165
+ commitSha: payload.commitSha,
166
+ metadata: payload.metadata,
167
+ }),
168
+ }, this.timeoutMs, this.logger);
169
+ }
170
+ async checkOutAgent(accessToken, payload) {
171
+ return requestJson(`${this.apiBaseUrl}/agent-sessions/${payload.sessionId}/check-out`, {
172
+ method: "POST",
173
+ headers: authHeaders(accessToken),
174
+ body: JSON.stringify({
175
+ metadata: payload.metadata,
176
+ }),
177
+ }, this.timeoutMs, this.logger);
178
+ }
179
+ async getHealth() {
180
+ return requestJson(`${this.apiBaseUrl}/health`, {
181
+ method: "GET",
182
+ }, this.timeoutMs, this.logger);
183
+ }
184
+ async getReady() {
185
+ return requestJson(`${this.apiBaseUrl}/ready`, {
186
+ method: "GET",
187
+ }, this.timeoutMs, this.logger);
188
+ }
189
+ }
190
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1,16 @@
1
+ import type { CliConfig, CliProfileConfig } from "../types/config.js";
2
+ import type { AuthSession } from "../types/auth.js";
3
+ import type { DeviceIdentity, MachineContext, RuntimeContext } from "../types/machine.js";
4
+ import { VectorPlaneApiClient } from "./api.js";
5
+ import type { Logger } from "./logger.js";
6
+ export declare function generateLoginState(): string;
7
+ export declare function openBrowser(url: string): Promise<boolean>;
8
+ export declare function runLoginFlow(params: {
9
+ config: CliConfig;
10
+ profile: CliProfileConfig;
11
+ machine: MachineContext;
12
+ runtime: RuntimeContext;
13
+ device: DeviceIdentity;
14
+ apiClient: VectorPlaneApiClient;
15
+ logger: Logger;
16
+ }): Promise<AuthSession>;