@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.
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/bin/vp.js +12 -0
- package/dist/commands/bootstrap.d.ts +1 -0
- package/dist/commands/bootstrap.js +40 -0
- package/dist/commands/config.d.ts +1 -0
- package/dist/commands/config.js +96 -0
- package/dist/commands/context.d.ts +1 -0
- package/dist/commands/context.js +46 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +69 -0
- package/dist/commands/event.d.ts +1 -0
- package/dist/commands/event.js +65 -0
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.js +39 -0
- package/dist/commands/session.d.ts +1 -0
- package/dist/commands/session.js +110 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +46 -0
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +108 -0
- package/dist/commands/whoami.d.ts +1 -0
- package/dist/commands/whoami.js +32 -0
- package/dist/commands/workspace.d.ts +1 -0
- package/dist/commands/workspace.js +66 -0
- package/dist/core/api.d.ts +24 -0
- package/dist/core/api.js +190 -0
- package/dist/core/auth.d.ts +16 -0
- package/dist/core/auth.js +71 -0
- package/dist/core/cli.d.ts +9 -0
- package/dist/core/cli.js +66 -0
- package/dist/core/config.d.ts +31 -0
- package/dist/core/config.js +263 -0
- package/dist/core/constants.d.ts +22 -0
- package/dist/core/constants.js +78 -0
- package/dist/core/env.d.ts +2 -0
- package/dist/core/env.js +10 -0
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.js +37 -0
- package/dist/core/git.d.ts +2 -0
- package/dist/core/git.js +66 -0
- package/dist/core/logger.d.ts +8 -0
- package/dist/core/logger.js +52 -0
- package/dist/core/machine.d.ts +4 -0
- package/dist/core/machine.js +87 -0
- package/dist/core/queue.d.ts +14 -0
- package/dist/core/queue.js +62 -0
- package/dist/core/runtime.d.ts +13 -0
- package/dist/core/runtime.js +16 -0
- package/dist/core/serializer.d.ts +7 -0
- package/dist/core/serializer.js +31 -0
- package/dist/core/server.d.ts +10 -0
- package/dist/core/server.js +84 -0
- package/dist/core/session.d.ts +16 -0
- package/dist/core/session.js +35 -0
- package/dist/core/workspace-binding.d.ts +15 -0
- package/dist/core/workspace-binding.js +41 -0
- package/dist/core/workspace.d.ts +2 -0
- package/dist/core/workspace.js +121 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +97 -0
- package/dist/types/api.d.ts +61 -0
- package/dist/types/api.js +2 -0
- package/dist/types/auth.d.ts +36 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/config.d.ts +58 -0
- package/dist/types/config.js +2 -0
- package/dist/types/machine.d.ts +49 -0
- package/dist/types/machine.js +2 -0
- package/dist/types/snapshot.d.ts +15 -0
- package/dist/types/snapshot.js +2 -0
- package/dist/types/workspace.d.ts +44 -0
- package/dist/types/workspace.js +2 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 VectorPlane
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# VectorPlane Ctrl CLI
|
|
2
|
+
|
|
3
|
+
`vectorplane-ctrl-cli` é o CLI oficial do ecossistema **VectorPlane**, nome comercial do backend `conductor-edge-ia`.
|
|
4
|
+
|
|
5
|
+
O repositório analisado posiciona o produto como uma control plane de contexto para engenharia com IA: memória remota por workspace, snapshots consolidados, governança, sessões de agentes, jobs e operação edge. Este CLI segue exatamente essa lógica. Ele não é um utilitário genérico de sync; ele é a porta local para autenticação, coleta de contexto da máquina, análise de workspace e envio seguro de snapshots para o plano de controle.
|
|
6
|
+
|
|
7
|
+
## Relação com `conductor-edge-ia`
|
|
8
|
+
|
|
9
|
+
O backend atual define alguns conceitos centrais que este CLI preserva:
|
|
10
|
+
|
|
11
|
+
- `workspace` como unidade primária de contexto
|
|
12
|
+
- `snapshot` consolidado como envelope principal de estado
|
|
13
|
+
- `agent session` e `clientInstanceId` como base de observabilidade e coordenação
|
|
14
|
+
- `control plane` como camada acima de clientes locais, MCP e REST
|
|
15
|
+
- preocupação explícita com governança, rastreabilidade, serialização consistente e isolamento
|
|
16
|
+
|
|
17
|
+
O `vp` foi desenhado para se encaixar nesse vocabulário e servir como cliente local premium do VectorPlane.
|
|
18
|
+
|
|
19
|
+
## Evolução planejada
|
|
20
|
+
|
|
21
|
+
O roadmap do CLI foi documentado em [`docs/evolution-phases.md`](./docs/evolution-phases.md), alinhado às fases já visíveis no `conductor-edge-ia`:
|
|
22
|
+
|
|
23
|
+
- `Foundation`
|
|
24
|
+
- `Coordination`
|
|
25
|
+
- `Governed Sync`
|
|
26
|
+
- `Enterprise Control Surface`
|
|
27
|
+
|
|
28
|
+
## Instalação
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install
|
|
32
|
+
npm run build
|
|
33
|
+
npm install -g .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Instalação via npm público:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g @vectorplane/ctrl-cli
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Uso local
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
vp login
|
|
46
|
+
vp status
|
|
47
|
+
vp sync
|
|
48
|
+
vp whoami
|
|
49
|
+
vp doctor
|
|
50
|
+
vp workspace current
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Comandos
|
|
54
|
+
|
|
55
|
+
### `vp login`
|
|
56
|
+
|
|
57
|
+
- inicia callback local em `http://127.0.0.1:4217/callback`
|
|
58
|
+
- gera `state` seguro
|
|
59
|
+
- abre o navegador para autenticação
|
|
60
|
+
- troca `code` por tokens via API
|
|
61
|
+
- persiste a sessão em `~/.vectorplane/session.json`
|
|
62
|
+
|
|
63
|
+
### `vp sync`
|
|
64
|
+
|
|
65
|
+
- exige sessão ativa
|
|
66
|
+
- coleta contexto de máquina, runtime, workspace e git
|
|
67
|
+
- gera snapshot estruturado e hash estável
|
|
68
|
+
- faz deduplicação por hash
|
|
69
|
+
- persiste snapshot localmente
|
|
70
|
+
- envia para `POST https://api.vectorplane.io/sync`
|
|
71
|
+
- enfileira localmente quando a API falha
|
|
72
|
+
|
|
73
|
+
### `vp status`
|
|
74
|
+
|
|
75
|
+
- informa estado da sessão local
|
|
76
|
+
- mostra perfil ativo
|
|
77
|
+
- mostra workspace ativo e binding local
|
|
78
|
+
- mostra diretório atual
|
|
79
|
+
- mostra machine ID persistido
|
|
80
|
+
- mostra branch git, fila local, sessão de agente e última sincronização quando disponíveis
|
|
81
|
+
|
|
82
|
+
### Comandos adicionais já implementados
|
|
83
|
+
|
|
84
|
+
- `vp whoami`
|
|
85
|
+
- consulta a identidade atual via API
|
|
86
|
+
- `vp doctor`
|
|
87
|
+
- verifica diretório local, git, health, ready e autenticação
|
|
88
|
+
- `vp config`
|
|
89
|
+
- lista, cria e troca perfis
|
|
90
|
+
- lê e altera configurações principais
|
|
91
|
+
- `vp workspace`
|
|
92
|
+
- consulta o workspace atual
|
|
93
|
+
- faz binding manual
|
|
94
|
+
- tenta resolver por repositório remoto
|
|
95
|
+
- `vp session`
|
|
96
|
+
- faz check-in, heartbeat e check-out de sessão de agente
|
|
97
|
+
- `vp context`
|
|
98
|
+
- carrega `context`, `snapshot` ou `delivery-context`
|
|
99
|
+
- `vp bootstrap`
|
|
100
|
+
- lê `agent-setup` e guidance de bootstrap do workspace
|
|
101
|
+
- `vp event send`
|
|
102
|
+
- envia ou enfileira eventos operacionais
|
|
103
|
+
|
|
104
|
+
## Persistência local
|
|
105
|
+
|
|
106
|
+
Arquivos usados:
|
|
107
|
+
|
|
108
|
+
- `~/.vectorplane/config.json`
|
|
109
|
+
- `~/.vectorplane/session.json`
|
|
110
|
+
- `~/.vectorplane/device.json`
|
|
111
|
+
- `~/.vectorplane/state.json`
|
|
112
|
+
- `~/.vectorplane/queue.json`
|
|
113
|
+
- `~/.vectorplane/workspaces.json`
|
|
114
|
+
- `~/.vectorplane/snapshots/`
|
|
115
|
+
|
|
116
|
+
## Segurança
|
|
117
|
+
|
|
118
|
+
- tokens nunca são impressos no terminal
|
|
119
|
+
- tokens nunca são enviados por query string
|
|
120
|
+
- o callback aceita apenas `code` e `state`
|
|
121
|
+
- `state` é validado obrigatoriamente
|
|
122
|
+
- logs evitam payloads sensíveis e mascaram chaves delicadas
|
|
123
|
+
- remotes git são sanitizados antes de entrarem no snapshot
|
|
124
|
+
|
|
125
|
+
## Desenvolvimento
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npm run check
|
|
129
|
+
npm run build
|
|
130
|
+
npm start -- status
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Publicação npm
|
|
134
|
+
|
|
135
|
+
O pacote foi preparado para publicação pública como `@vectorplane/ctrl-cli`.
|
|
136
|
+
|
|
137
|
+
Checklist local:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm run release:check
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Publicação:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npm login
|
|
147
|
+
npm publish --access public
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Notas de empacotamento:
|
|
151
|
+
|
|
152
|
+
- o tarball publica apenas `bin/`, `dist/`, `README.md` e `LICENSE`
|
|
153
|
+
- `src/`, `docs/`, `.git/`, `node_modules/`, `package-lock.json` e arquivos locais não entram no pacote
|
|
154
|
+
- tokens, sessão local e dados de `~/.vectorplane/` não fazem parte do publish
|
|
155
|
+
|
|
156
|
+
## Integração aplicada
|
|
157
|
+
|
|
158
|
+
O fluxo web e backend do CLI foi alinhado ao ecossistema real:
|
|
159
|
+
|
|
160
|
+
- dashboard com rota `/cli/login`
|
|
161
|
+
- emissão autenticada de código por `POST /auth/cli/code`
|
|
162
|
+
- troca de token por `POST /cli/token/exchange`
|
|
163
|
+
- refresh por `POST /cli/token/refresh`
|
|
164
|
+
- resolução e leitura de workspace via rotas `cli/workspace/*`
|
|
165
|
+
- `POST /sync` e `POST /events` no mesmo envelope oficial do worker
|
|
166
|
+
|
|
167
|
+
O cliente agora faz unwrapping do envelope `{ success, data, requestId }` usado pelo `conductor-edge-ia`, em vez de assumir respostas cruas.
|
package/bin/vp.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import("../dist/index.js")
|
|
4
|
+
.then(({ runCli }) => runCli(process.argv.slice(2)))
|
|
5
|
+
.then((exitCode) => {
|
|
6
|
+
process.exitCode = typeof exitCode === "number" ? exitCode : 0;
|
|
7
|
+
})
|
|
8
|
+
.catch((error) => {
|
|
9
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10
|
+
console.error(`VectorPlane: ${message}`);
|
|
11
|
+
process.exitCode = 1;
|
|
12
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runBootstrapCommand(cliVersion: string, args: string[]): Promise<number>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { getStringOption, parseArgs } from "../core/cli.js";
|
|
2
|
+
import { ensureSessionAvailable, getProfileState } 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 { getBoundWorkspace, resolveWorkspaceRoot } from "../core/workspace-binding.js";
|
|
9
|
+
import { ValidationError } from "../core/errors.js";
|
|
10
|
+
export async function runBootstrapCommand(cliVersion, args) {
|
|
11
|
+
const parsed = parseArgs(args);
|
|
12
|
+
const runtime = await loadRuntimeStatus();
|
|
13
|
+
const session = await ensureSessionAvailable(runtime.profile.name);
|
|
14
|
+
const [git, machine, runtimeContext] = await Promise.all([
|
|
15
|
+
collectGitContext(process.cwd()),
|
|
16
|
+
collectMachineContext(runtime.device, runtime.config),
|
|
17
|
+
collectRuntimeContext(cliVersion, "bootstrap", process.argv.slice(2)),
|
|
18
|
+
]);
|
|
19
|
+
const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
|
|
20
|
+
const freshSession = await ensureFreshSession({
|
|
21
|
+
profileName: runtime.profile.name,
|
|
22
|
+
session,
|
|
23
|
+
machine,
|
|
24
|
+
runtime: runtimeContext,
|
|
25
|
+
device: runtime.device,
|
|
26
|
+
apiClient,
|
|
27
|
+
logger: runtime.logger,
|
|
28
|
+
});
|
|
29
|
+
const rootPath = resolveWorkspaceRoot(process.cwd(), git);
|
|
30
|
+
const boundWorkspace = await getBoundWorkspace(rootPath);
|
|
31
|
+
const profileState = getProfileState(runtime.state, runtime.profile.name);
|
|
32
|
+
const workspace = resolveWorkspaceSlug(runtime.profile, freshSession, getStringOption(parsed, "workspace"), boundWorkspace, profileState.lastWorkspace);
|
|
33
|
+
if (!workspace) {
|
|
34
|
+
throw new ValidationError("Nenhum workspace resolvido para bootstrap.");
|
|
35
|
+
}
|
|
36
|
+
const payload = await apiClient.getAgentSetup(freshSession.accessToken, workspace);
|
|
37
|
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runConfigCommand(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { getStringOption, parseArgs, requirePositional } from "../core/cli.js";
|
|
2
|
+
import { getActiveProfile, loadConfig, saveConfig, setActiveProfile, upsertProfile } from "../core/config.js";
|
|
3
|
+
import { ValidationError } from "../core/errors.js";
|
|
4
|
+
function setProfileField(profile, key, value) {
|
|
5
|
+
switch (key) {
|
|
6
|
+
case "apiBaseUrl":
|
|
7
|
+
return { ...profile, apiBaseUrl: value };
|
|
8
|
+
case "appBaseUrl":
|
|
9
|
+
return { ...profile, appBaseUrl: value };
|
|
10
|
+
case "workspace":
|
|
11
|
+
return { ...profile, workspace: value };
|
|
12
|
+
case "orgId":
|
|
13
|
+
return { ...profile, orgId: value };
|
|
14
|
+
case "environment":
|
|
15
|
+
return { ...profile, environment: value };
|
|
16
|
+
default:
|
|
17
|
+
throw new ValidationError(`Campo de perfil não suportado: ${key}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function runConfigCommand(args) {
|
|
21
|
+
const parsed = parseArgs(args);
|
|
22
|
+
const [subcommand, ...rest] = parsed.positionals;
|
|
23
|
+
const config = await loadConfig();
|
|
24
|
+
if (!subcommand) {
|
|
25
|
+
process.stdout.write(JSON.stringify(config, null, 2));
|
|
26
|
+
process.stdout.write("\n");
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
if (subcommand === "profile") {
|
|
30
|
+
const action = rest[0];
|
|
31
|
+
if (!action || action === "list") {
|
|
32
|
+
for (const profile of Object.values(config.profiles)) {
|
|
33
|
+
process.stdout.write(`${profile.name}${config.activeProfile === profile.name ? " *" : ""}\n`);
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
if (action === "create") {
|
|
38
|
+
const name = rest[1];
|
|
39
|
+
if (!name) {
|
|
40
|
+
throw new ValidationError("Informe o nome do perfil.");
|
|
41
|
+
}
|
|
42
|
+
await upsertProfile(name, { name });
|
|
43
|
+
process.stdout.write(`Perfil criado: ${name}\n`);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
if (action === "use") {
|
|
47
|
+
const name = rest[1];
|
|
48
|
+
if (!name) {
|
|
49
|
+
throw new ValidationError("Informe o nome do perfil.");
|
|
50
|
+
}
|
|
51
|
+
await setActiveProfile(name);
|
|
52
|
+
process.stdout.write(`Perfil ativo: ${name}\n`);
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (subcommand === "get") {
|
|
57
|
+
const key = requirePositional({ ...parsed, positionals: rest }, 0, "Informe a chave a ser lida.");
|
|
58
|
+
const active = getActiveProfile(config);
|
|
59
|
+
switch (key) {
|
|
60
|
+
case "debug":
|
|
61
|
+
process.stdout.write(String(config.debug));
|
|
62
|
+
break;
|
|
63
|
+
case "telemetryEnabled":
|
|
64
|
+
process.stdout.write(String(config.telemetryEnabled));
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
process.stdout.write(String(active[key] ?? ""));
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
process.stdout.write("\n");
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
if (subcommand === "set") {
|
|
74
|
+
const key = rest[0];
|
|
75
|
+
const value = rest[1];
|
|
76
|
+
if (!key || value === undefined) {
|
|
77
|
+
throw new ValidationError("Uso: vp config set <chave> <valor>");
|
|
78
|
+
}
|
|
79
|
+
if (key === "debug" || key === "telemetryEnabled") {
|
|
80
|
+
const next = { ...config, [key]: ["1", "true", "yes", "on"].includes(value.toLowerCase()) };
|
|
81
|
+
await saveConfig(next);
|
|
82
|
+
process.stdout.write(`Configuração atualizada: ${key}\n`);
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
const profileName = getStringOption(parsed, "profile") ?? config.activeProfile;
|
|
86
|
+
const current = config.profiles[profileName];
|
|
87
|
+
if (!current) {
|
|
88
|
+
throw new ValidationError(`Perfil ${profileName} não existe.`);
|
|
89
|
+
}
|
|
90
|
+
await upsertProfile(profileName, setProfileField(current, key, value));
|
|
91
|
+
process.stdout.write(`Perfil ${profileName} atualizado: ${key}\n`);
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
throw new ValidationError("Subcomando de config não suportado.");
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runContextCommand(cliVersion: string, args: string[]): Promise<number>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { getBooleanOption, getStringOption, parseArgs } from "../core/cli.js";
|
|
2
|
+
import { ensureSessionAvailable, getProfileState } 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 { getBoundWorkspace, resolveWorkspaceRoot } from "../core/workspace-binding.js";
|
|
9
|
+
import { ValidationError } from "../core/errors.js";
|
|
10
|
+
export async function runContextCommand(cliVersion, args) {
|
|
11
|
+
const parsed = parseArgs(args);
|
|
12
|
+
const delivery = getBooleanOption(parsed, "delivery");
|
|
13
|
+
const snapshot = getBooleanOption(parsed, "snapshot");
|
|
14
|
+
const runtime = await loadRuntimeStatus();
|
|
15
|
+
const session = await ensureSessionAvailable(runtime.profile.name);
|
|
16
|
+
const [git, machine, runtimeContext] = await Promise.all([
|
|
17
|
+
collectGitContext(process.cwd()),
|
|
18
|
+
collectMachineContext(runtime.device, runtime.config),
|
|
19
|
+
collectRuntimeContext(cliVersion, "context", process.argv.slice(2)),
|
|
20
|
+
]);
|
|
21
|
+
const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
|
|
22
|
+
const freshSession = await ensureFreshSession({
|
|
23
|
+
profileName: runtime.profile.name,
|
|
24
|
+
session,
|
|
25
|
+
machine,
|
|
26
|
+
runtime: runtimeContext,
|
|
27
|
+
device: runtime.device,
|
|
28
|
+
apiClient,
|
|
29
|
+
logger: runtime.logger,
|
|
30
|
+
});
|
|
31
|
+
const rootPath = resolveWorkspaceRoot(process.cwd(), git);
|
|
32
|
+
const boundWorkspace = await getBoundWorkspace(rootPath);
|
|
33
|
+
const profileState = getProfileState(runtime.state, runtime.profile.name);
|
|
34
|
+
const workspace = resolveWorkspaceSlug(runtime.profile, freshSession, getStringOption(parsed, "workspace"), boundWorkspace, profileState.lastWorkspace);
|
|
35
|
+
if (!workspace) {
|
|
36
|
+
throw new ValidationError("Nenhum workspace resolvido para carregar contexto.");
|
|
37
|
+
}
|
|
38
|
+
const payload = delivery
|
|
39
|
+
? await apiClient.getWorkspaceDeliveryContext(freshSession.accessToken, workspace)
|
|
40
|
+
: snapshot
|
|
41
|
+
? await apiClient.getWorkspaceSnapshot(freshSession.accessToken, workspace)
|
|
42
|
+
: await apiClient.getWorkspaceContext(freshSession.accessToken, workspace);
|
|
43
|
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runDoctorCommand(cliVersion: string): Promise<number>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { constants as fsConstants } from "node:fs";
|
|
3
|
+
import { configDirectoryExists, ensureSessionAvailable, getConfigDirectoryPath } from "../core/config.js";
|
|
4
|
+
import { collectGitContext } from "../core/git.js";
|
|
5
|
+
import { collectMachineContext, collectRuntimeContext } from "../core/machine.js";
|
|
6
|
+
import { loadRuntimeStatus } from "../core/runtime.js";
|
|
7
|
+
import { ensureFreshSession } from "../core/session.js";
|
|
8
|
+
import { VectorPlaneApiClient } from "../core/api.js";
|
|
9
|
+
async function writable(filePath) {
|
|
10
|
+
try {
|
|
11
|
+
await access(filePath, fsConstants.W_OK);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function printCheck(label, ok, details) {
|
|
19
|
+
process.stdout.write(`${ok ? "OK" : "FAIL"} ${label}: ${details}\n`);
|
|
20
|
+
}
|
|
21
|
+
export async function runDoctorCommand(cliVersion) {
|
|
22
|
+
const runtime = await loadRuntimeStatus();
|
|
23
|
+
const configDirectory = await getConfigDirectoryPath();
|
|
24
|
+
const [hasConfigDir, git, canWriteConfig] = await Promise.all([
|
|
25
|
+
configDirectoryExists(),
|
|
26
|
+
collectGitContext(process.cwd()),
|
|
27
|
+
writable(configDirectory),
|
|
28
|
+
]);
|
|
29
|
+
printCheck("config_dir", hasConfigDir, configDirectory);
|
|
30
|
+
printCheck("config_dir_writable", canWriteConfig, canWriteConfig ? "gravável" : "sem permissão de escrita");
|
|
31
|
+
printCheck("git", git.isRepository, git.isRepository ? (git.rootPath ?? process.cwd()) : "repositório não detectado");
|
|
32
|
+
printCheck("node", true, process.version);
|
|
33
|
+
const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
|
|
34
|
+
try {
|
|
35
|
+
const health = await apiClient.getHealth();
|
|
36
|
+
printCheck("api_health", true, JSON.stringify(health));
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
printCheck("api_health", false, error instanceof Error ? error.message : String(error));
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const ready = await apiClient.getReady();
|
|
43
|
+
printCheck("api_ready", true, JSON.stringify(ready));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
printCheck("api_ready", false, error instanceof Error ? error.message : String(error));
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const session = await ensureSessionAvailable(runtime.profile.name);
|
|
50
|
+
const machine = await collectMachineContext(runtime.device, runtime.config);
|
|
51
|
+
const runtimeContext = await collectRuntimeContext(cliVersion, "doctor", process.argv.slice(2));
|
|
52
|
+
const freshSession = await ensureFreshSession({
|
|
53
|
+
profileName: runtime.profile.name,
|
|
54
|
+
session,
|
|
55
|
+
machine,
|
|
56
|
+
runtime: runtimeContext,
|
|
57
|
+
device: runtime.device,
|
|
58
|
+
apiClient,
|
|
59
|
+
logger: runtime.logger,
|
|
60
|
+
});
|
|
61
|
+
const me = await apiClient.getCurrentUser(freshSession.accessToken);
|
|
62
|
+
printCheck("auth_me", true, `${me.type}:${me.id}`);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
printCheck("auth_me", false, error instanceof Error ? error.message : String(error));
|
|
66
|
+
}
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runEventCommand(cliVersion: string, args: string[]): Promise<number>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { getStringOption, parseArgs, parseJsonOption, requirePositional } from "../core/cli.js";
|
|
2
|
+
import { ensureSessionAvailable, getProfileState } 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 { queueEvent } from "../core/queue.js";
|
|
9
|
+
import { getBoundWorkspace, resolveWorkspaceRoot } from "../core/workspace-binding.js";
|
|
10
|
+
import { ValidationError } from "../core/errors.js";
|
|
11
|
+
export async function runEventCommand(cliVersion, args) {
|
|
12
|
+
const parsed = parseArgs(args);
|
|
13
|
+
const [subcommand] = parsed.positionals;
|
|
14
|
+
if (!subcommand || subcommand !== "send") {
|
|
15
|
+
throw new ValidationError("Uso: vp event send <nome> [--payload '{...}']");
|
|
16
|
+
}
|
|
17
|
+
const eventName = requirePositional(parsed, 1, "Informe o nome do evento.");
|
|
18
|
+
const payloadObject = parseJsonOption(getStringOption(parsed, "payload"));
|
|
19
|
+
const runtime = await loadRuntimeStatus();
|
|
20
|
+
const session = await ensureSessionAvailable(runtime.profile.name);
|
|
21
|
+
const [git, machine, runtimeContext] = await Promise.all([
|
|
22
|
+
collectGitContext(process.cwd()),
|
|
23
|
+
collectMachineContext(runtime.device, runtime.config),
|
|
24
|
+
collectRuntimeContext(cliVersion, "event", process.argv.slice(2)),
|
|
25
|
+
]);
|
|
26
|
+
const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
|
|
27
|
+
const freshSession = await ensureFreshSession({
|
|
28
|
+
profileName: runtime.profile.name,
|
|
29
|
+
session,
|
|
30
|
+
machine,
|
|
31
|
+
runtime: runtimeContext,
|
|
32
|
+
device: runtime.device,
|
|
33
|
+
apiClient,
|
|
34
|
+
logger: runtime.logger,
|
|
35
|
+
});
|
|
36
|
+
const rootPath = resolveWorkspaceRoot(process.cwd(), git);
|
|
37
|
+
const boundWorkspace = await getBoundWorkspace(rootPath);
|
|
38
|
+
const profileState = getProfileState(runtime.state, runtime.profile.name);
|
|
39
|
+
const workspace = resolveWorkspaceSlug(runtime.profile, freshSession, getStringOption(parsed, "workspace"), boundWorkspace, profileState.lastWorkspace);
|
|
40
|
+
if (!workspace) {
|
|
41
|
+
throw new ValidationError("Nenhum workspace resolvido para o evento.");
|
|
42
|
+
}
|
|
43
|
+
const eventPayload = {
|
|
44
|
+
workspace,
|
|
45
|
+
event: eventName,
|
|
46
|
+
payload: {
|
|
47
|
+
...payloadObject,
|
|
48
|
+
branch: git.branch,
|
|
49
|
+
commitHash: git.commitHash,
|
|
50
|
+
rootPath,
|
|
51
|
+
},
|
|
52
|
+
sent_at: new Date().toISOString(),
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
await apiClient.sendEvent(freshSession.accessToken, eventPayload);
|
|
56
|
+
runtime.logger.success("evento enviado.");
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
await queueEvent(runtime.profile.name, eventPayload, error);
|
|
61
|
+
runtime.logger.warn("API indisponível no momento. O evento foi enfileirado localmente.");
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runLoginCommand(cliVersion: string, args: string[]): Promise<number>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getStringOption, parseArgs } from "../core/cli.js";
|
|
2
|
+
import { runLoginFlow } from "../core/auth.js";
|
|
3
|
+
import { saveSession, setActiveProfile, updateProfileState, upsertProfile } from "../core/config.js";
|
|
4
|
+
import { collectMachineContext, collectRuntimeContext } from "../core/machine.js";
|
|
5
|
+
import { loadRuntimeStatus } from "../core/runtime.js";
|
|
6
|
+
import { VectorPlaneApiClient } from "../core/api.js";
|
|
7
|
+
export async function runLoginCommand(cliVersion, args) {
|
|
8
|
+
const parsed = parseArgs(args);
|
|
9
|
+
const requestedProfile = getStringOption(parsed, "profile");
|
|
10
|
+
if (requestedProfile) {
|
|
11
|
+
await upsertProfile(requestedProfile, { name: requestedProfile });
|
|
12
|
+
await setActiveProfile(requestedProfile);
|
|
13
|
+
}
|
|
14
|
+
const runtime = await loadRuntimeStatus();
|
|
15
|
+
const machine = await collectMachineContext(runtime.device, runtime.config);
|
|
16
|
+
const runtimeContext = await collectRuntimeContext(cliVersion, "login", process.argv.slice(2));
|
|
17
|
+
const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
|
|
18
|
+
const session = await runLoginFlow({
|
|
19
|
+
config: runtime.config,
|
|
20
|
+
profile: runtime.profile,
|
|
21
|
+
machine,
|
|
22
|
+
runtime: runtimeContext,
|
|
23
|
+
device: runtime.device,
|
|
24
|
+
apiClient,
|
|
25
|
+
logger: runtime.logger,
|
|
26
|
+
});
|
|
27
|
+
await saveSession(session, runtime.profile.name);
|
|
28
|
+
await upsertProfile(runtime.profile.name, { workspace: session.workspace });
|
|
29
|
+
await updateProfileState(runtime.profile.name, {
|
|
30
|
+
lastCommand: "login",
|
|
31
|
+
lastWorkspace: session.workspace,
|
|
32
|
+
lastError: null,
|
|
33
|
+
});
|
|
34
|
+
runtime.logger.success("login realizado com sucesso.");
|
|
35
|
+
process.stdout.write(`Perfil: ${runtime.profile.name}\n`);
|
|
36
|
+
process.stdout.write(`Workspace ativo: ${session.workspace}\n`);
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runSessionCommand(cliVersion: string, args: string[]): Promise<number>;
|