@vectorplane/ctrl-cli 0.1.11 → 0.1.13

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 CHANGED
@@ -18,6 +18,18 @@ vp login
18
18
  vp logout
19
19
  vp status
20
20
  vp sync
21
+ vp task templates
22
+ vp task run --title "Entrega X" --intention "Implementar fluxo Y"
23
+ vp task run --template code-review --title "Review auth" --intention "Revisar risco e cobertura do fluxo de auth"
24
+ vp task watch <task-id>
25
+ vp task claim --capability qa.test
26
+ vp task execute <task-id> --step <step-id>
27
+ vp task daemon --capability qa.test
28
+ vp context --search "decisões sobre autenticação"
29
+ vp context --delivery --search "fluxo de login" --type decisions
30
+ vp context --diff --from latest-1 --to latest
31
+ vp workspace webhook list
32
+ vp workspace webhook create --name approvals --url https://example.com/hooks/vectorplane --secret supersecret123 --events task.approval_required,task.blocked
21
33
  vp context --workspace <workspace> --delivery
22
34
  vp session check-in --workspace <workspace> --agent codex --type codex --client openai-codex --feature feature-key --task task-key --owning-path "src/core,src/ui" --need "api-contract" --provide "implementation" --status "starting implementation"
23
35
  vp draft create --type progress --title "Entrega concluída" --content "Resumo da mudança"
@@ -42,6 +54,7 @@ vp draft create --type progress --title "Entrega concluída" --content "Resumo d
42
54
  - salva a sessão localmente
43
55
  - suporta `--no-browser` e `--manual`
44
56
  - em ambientes remotos ou isolados, o loopback local pode exigir um fluxo alternativo
57
+ - a URL web do login é emitida pelo control plane; o domínio do app não deve ser hardcoded em automações externas
45
58
 
46
59
  ### `vp logout`
47
60
 
@@ -59,6 +72,26 @@ vp draft create --type progress --title "Entrega concluída" --content "Resumo d
59
72
  - mostra o estado da sessão local
60
73
  - exibe workspace ativo, diretório atual e última sincronização
61
74
 
75
+ ### `vp task`
76
+
77
+ - cria tasks no orchestrator do workspace
78
+ - lista templates disponíveis com `vp task templates`
79
+ - aceita `--template <slug>` para herdar capabilities e paths padrão do backend
80
+ - lista e inspeciona tasks existentes
81
+ - acompanha uma task em tempo real com `vp task watch <taskId>`
82
+ - faz claim explícito de steps `pending_claim` atribuídos a agentes CLI
83
+ - executa steps locais via `metadata.execution.command`
84
+ - suporta loop controlado com `vp task daemon --capability ...`
85
+ - registra delegação de step
86
+ - envia callback de execução por step para concluir a pipeline
87
+ - lê handoff operacional por task
88
+ - consulta observabilidade por task ou workspace
89
+ - consulta health do workspace ligado às tasks
90
+ - para automação local real, o agente de registry deve ter `metadata.execution` com:
91
+ - `type: "command"`
92
+ - `command: "npm"` ou equivalente
93
+ - `args`, `cwd` e `env` opcionais
94
+
62
95
  ### `vp draft`
63
96
 
64
97
  - cria drafts editoriais ligados ao workspace atual
@@ -83,16 +116,22 @@ vp draft create --type progress --title "Entrega concluída" --content "Resumo d
83
116
  - inclui `vp config privacy` e `vp config policy`
84
117
  - `vp workspace`
85
118
  - gerencia o workspace atual
119
+ - suporta `vp workspace webhook list|create|delete` para integrações externas por workspace
86
120
  - `vp session`
87
121
  - gerencia sessões de agente
88
122
  - `vp context`
89
123
  - carrega contexto remoto do workspace
124
+ - suporta `--search "QUERY"` para busca semântica na memória
125
+ - com `--delivery --search`, retorna delivery context com fragmentos semânticos relevantes
126
+ - suporta `--diff --from latest-1 --to latest` para comparar snapshots do workspace
90
127
  - `vp bootstrap`
91
128
  - obtém instruções de setup do workspace
92
129
  - `vp event send`
93
130
  - envia eventos operacionais
94
131
  - `vp draft`
95
132
  - envia e consulta drafts editoriais do workspace
133
+ - `vp task`
134
+ - opera tasks do autonomous control plane
96
135
 
97
136
  ## Persistência local
98
137
 
@@ -7,11 +7,13 @@ import { ensureFreshSession, resolveWorkspaceSlug } from "../core/session.js";
7
7
  import { VectorPlaneApiClient } from "../core/api.js";
8
8
  import { getBoundWorkspace, resolveWorkspaceRoot } from "../core/workspace-binding.js";
9
9
  import { ValidationError } from "../core/errors.js";
10
- import { ensureAgentSetupCurrent } from "../core/agent-setup.js";
10
+ import { ensureRuntimeAgentSetup } from "../core/runtime-agent-setup.js";
11
11
  export async function runContextCommand(cliVersion, args) {
12
12
  const parsed = parseArgs(args);
13
13
  const delivery = getBooleanOption(parsed, "delivery");
14
14
  const snapshot = getBooleanOption(parsed, "snapshot");
15
+ const diff = getBooleanOption(parsed, "diff");
16
+ const search = getStringOption(parsed, "search")?.trim();
15
17
  const runtime = await loadRuntimeStatus();
16
18
  const session = await ensureSessionAvailable(runtime.profile.name);
17
19
  const [git, machine, runtimeContext] = await Promise.all([
@@ -36,20 +38,34 @@ export async function runContextCommand(cliVersion, args) {
36
38
  if (!workspace) {
37
39
  throw new ValidationError("Nenhum workspace resolvido para carregar contexto.");
38
40
  }
39
- await ensureAgentSetupCurrent({
40
- rootPath,
41
- workspace,
42
- repoUrl: git.remoteOrigin,
43
- source: git.remoteOrigin ? "api-resolve" : "manual",
44
- accessToken: freshSession.accessToken,
45
- apiClient,
46
- logger: runtime.logger,
47
- });
48
- const payload = delivery
49
- ? await apiClient.getWorkspaceDeliveryContext(freshSession.accessToken, workspace)
50
- : snapshot
51
- ? await apiClient.getWorkspaceSnapshot(freshSession.accessToken, workspace)
52
- : await apiClient.getWorkspaceContext(freshSession.accessToken, workspace);
41
+ await ensureRuntimeAgentSetup({ rootPath, workspace, git, session: freshSession, apiClient, logger: runtime.logger });
42
+ if (diff && (delivery || snapshot || search)) {
43
+ throw new ValidationError("`--diff` não pode ser combinado com `--delivery`, `--snapshot` ou `--search`.");
44
+ }
45
+ const payload = search
46
+ ? (delivery
47
+ ? await apiClient.getWorkspaceDeliveryContextSemantic(freshSession.accessToken, workspace, {
48
+ query: search,
49
+ type: getStringOption(parsed, "type")?.trim(),
50
+ authority: getStringOption(parsed, "authority")?.trim(),
51
+ limit: Number(getStringOption(parsed, "limit") ?? "0") || undefined,
52
+ })
53
+ : await apiClient.searchWorkspaceMemory(freshSession.accessToken, workspace, {
54
+ query: search,
55
+ type: getStringOption(parsed, "type")?.trim(),
56
+ authority: getStringOption(parsed, "authority")?.trim(),
57
+ limit: Number(getStringOption(parsed, "limit") ?? "0") || undefined,
58
+ }))
59
+ : diff
60
+ ? await apiClient.getWorkspaceSnapshotDiff(freshSession.accessToken, workspace, {
61
+ from: getStringOption(parsed, "from")?.trim() || "latest-1",
62
+ to: getStringOption(parsed, "to")?.trim() || "latest",
63
+ })
64
+ : delivery
65
+ ? await apiClient.getWorkspaceDeliveryContext(freshSession.accessToken, workspace)
66
+ : snapshot
67
+ ? await apiClient.getWorkspaceSnapshot(freshSession.accessToken, workspace)
68
+ : await apiClient.getWorkspaceContext(freshSession.accessToken, workspace);
53
69
  process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
54
70
  return 0;
55
71
  }
@@ -1,76 +1,32 @@
1
1
  import { getBooleanOption, getStringOption, parseArgs } from "../core/cli.js";
2
- import { ensureSessionAvailable, loadSession, upsertProfile } from "../core/config.js";
3
- import { collectGitContext } from "../core/git.js";
4
2
  import { runLoginCommand } from "./login.js";
5
- import { collectMachineContext, collectRuntimeContext } from "../core/machine.js";
6
3
  import { loadRuntimeStatus } from "../core/runtime.js";
7
- import { ensureFreshSession } from "../core/session.js";
8
- import { VectorPlaneApiClient } from "../core/api.js";
9
- import { ensureAgentSetupCurrent } from "../core/agent-setup.js";
10
- import { resolveWorkspaceRoot } from "../core/workspace-binding.js";
11
- import { resolveAuthorizedWorkspace } from "../core/workspace-resolution.js";
4
+ import { buildInitLoginArgs, runInitWorkspaceUseCase } from "../core/init-workspace.js";
12
5
  export async function runInitCommand(cliVersion, args) {
13
6
  const parsed = parseArgs(args);
14
7
  const force = getBooleanOption(parsed, "force");
15
8
  const requestedAgent = getStringOption(parsed, "agent");
16
9
  const explicitWorkspace = getStringOption(parsed, "workspace");
17
- const loginArgs = [];
18
- if (getBooleanOption(parsed, "manual")) {
19
- loginArgs.push("--manual");
20
- }
21
- if (getBooleanOption(parsed, "no-browser")) {
22
- loginArgs.push("--no-browser");
23
- }
24
10
  const requestedProfile = getStringOption(parsed, "profile");
25
- if (requestedProfile) {
26
- loginArgs.push("--profile", requestedProfile);
27
- }
28
- let runtime = await loadRuntimeStatus();
29
- let session = await loadSession(runtime.profile.name);
30
- if (!session) {
31
- runtime.logger.info("sessão local ausente, iniciando login...");
32
- await runLoginCommand(cliVersion, loginArgs);
33
- runtime = await loadRuntimeStatus();
34
- session = await ensureSessionAvailable(runtime.profile.name);
35
- }
36
- const [git, machine, runtimeContext] = await Promise.all([
37
- collectGitContext(process.cwd()),
38
- collectMachineContext(runtime.device, runtime.config),
39
- collectRuntimeContext(cliVersion, "init", process.argv.slice(2)),
40
- ]);
41
- const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
42
- const freshSession = await ensureFreshSession({
43
- profileName: runtime.profile.name,
44
- session,
45
- machine,
46
- runtime: runtimeContext,
47
- device: runtime.device,
48
- apiClient,
49
- logger: runtime.logger,
11
+ const loginArgs = await buildInitLoginArgs({
12
+ manual: getBooleanOption(parsed, "manual"),
13
+ noBrowser: getBooleanOption(parsed, "no-browser"),
14
+ profile: requestedProfile ?? undefined,
50
15
  });
51
- const rootPath = resolveWorkspaceRoot(process.cwd(), git);
52
- const workspace = await resolveAuthorizedWorkspace({
53
- apiClient,
54
- accessToken: freshSession.accessToken,
55
- git,
56
- explicitWorkspace: explicitWorkspace ?? undefined,
57
- profile: runtime.profile,
58
- session: freshSession,
59
- });
60
- const result = await ensureAgentSetupCurrent({
61
- rootPath,
62
- workspace,
63
- repoUrl: git.remoteOrigin,
64
- source: git.remoteOrigin ? "api-resolve" : "manual",
65
- accessToken: freshSession.accessToken,
66
- apiClient,
67
- logger: runtime.logger,
68
- explicitAgent: requestedAgent,
16
+ const runtime = await loadRuntimeStatus();
17
+ const result = await runInitWorkspaceUseCase({
18
+ cliVersion,
19
+ commandArgs: process.argv.slice(2),
20
+ runtime,
69
21
  force,
22
+ explicitWorkspace: explicitWorkspace ?? undefined,
23
+ requestedAgent,
24
+ ensureLoggedIn: async () => {
25
+ await runLoginCommand(cliVersion, loginArgs);
26
+ },
70
27
  });
71
- await upsertProfile(runtime.profile.name, { workspace });
72
28
  runtime.logger.success("workspace inicializado.");
73
- process.stdout.write(`Workspace: ${workspace}\n`);
29
+ process.stdout.write(`Workspace: ${result.workspace}\n`);
74
30
  process.stdout.write(`Agente configurado: ${result.agent}\n`);
75
31
  process.stdout.write(`Confiança da detecção: ${result.confidence}\n`);
76
32
  process.stdout.write(`Template: ${result.templatePath} (${result.fileStatus})\n`);
@@ -0,0 +1 @@
1
+ export declare function runRegistryCommand(args: string[]): Promise<number>;
@@ -0,0 +1,116 @@
1
+ import { getBooleanOption, getStringListOption, getStringOption, parseArgs, parseJsonOption, requirePositional } from "../core/cli.js";
2
+ import { ensureSessionAvailable } from "../core/config.js";
3
+ import { loadRuntimeStatus } from "../core/runtime.js";
4
+ import { VectorPlaneApiClient } from "../core/api.js";
5
+ import { ValidationError } from "../core/errors.js";
6
+ function printJsonIfRequested(parsed, payload) {
7
+ if (!getBooleanOption(parsed, "json")) {
8
+ return false;
9
+ }
10
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
11
+ return true;
12
+ }
13
+ function printAgent(agent) {
14
+ process.stdout.write(`Agent: ${agent.id}\n`);
15
+ process.stdout.write(`Nome: ${agent.name}\n`);
16
+ process.stdout.write(`Runtime: ${agent.runtimeType}\n`);
17
+ process.stdout.write(`Provider: ${agent.provider}\n`);
18
+ process.stdout.write(`Model: ${agent.model}\n`);
19
+ process.stdout.write(`Status: ${agent.status}\n`);
20
+ process.stdout.write(`Reliability: ${String(agent.reliabilityScore)}\n`);
21
+ process.stdout.write(`Capabilities: ${agent.capabilities.join(", ")}\n`);
22
+ if (agent.metadata && Object.keys(agent.metadata).length > 0) {
23
+ process.stdout.write(`Metadata: ${JSON.stringify(agent.metadata)}\n`);
24
+ }
25
+ }
26
+ async function resolveRegistryContext() {
27
+ const runtime = await loadRuntimeStatus();
28
+ const session = await ensureSessionAvailable(runtime.profile.name);
29
+ const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
30
+ return { runtime, session, apiClient };
31
+ }
32
+ export async function runRegistryCommand(args) {
33
+ const parsed = parseArgs(args);
34
+ const subcommand = requirePositional(parsed, 0, "Uso: vp registry <list|register|update|deactivate> [...]");
35
+ const { runtime, session, apiClient } = await resolveRegistryContext();
36
+ if (subcommand === "list") {
37
+ const agents = await apiClient.listAgentRegistry(session.accessToken);
38
+ if (printJsonIfRequested(parsed, agents))
39
+ return 0;
40
+ if (agents.length === 0) {
41
+ process.stdout.write("VectorPlane: nenhum agente registrado.\n");
42
+ return 0;
43
+ }
44
+ for (const agent of agents) {
45
+ process.stdout.write(`${agent.id} | ${agent.status} | ${agent.runtimeType} | ${agent.provider}/${agent.model} | ${agent.name}\n`);
46
+ }
47
+ return 0;
48
+ }
49
+ if (subcommand === "register") {
50
+ const name = getStringOption(parsed, "name")?.trim();
51
+ const runtimeType = getStringOption(parsed, "runtime")?.trim();
52
+ const provider = getStringOption(parsed, "provider")?.trim();
53
+ const model = getStringOption(parsed, "model")?.trim();
54
+ if (!name || !runtimeType || !provider || !model) {
55
+ throw new ValidationError("Informe `--name`, `--runtime`, `--provider` e `--model`.");
56
+ }
57
+ const agent = await apiClient.createRegistryAgent(session.accessToken, {
58
+ orgId: getStringOption(parsed, "org-id")?.trim() || undefined,
59
+ name,
60
+ runtimeType,
61
+ provider,
62
+ model,
63
+ capabilities: getStringListOption(parsed, "capabilities"),
64
+ costProfile: getStringOption(parsed, "cost")?.trim() || "standard",
65
+ latencyProfile: getStringOption(parsed, "latency")?.trim() || "standard",
66
+ reliabilityScore: Number(getStringOption(parsed, "reliability") ?? "0.9"),
67
+ status: getStringOption(parsed, "status")?.trim() || "active",
68
+ metadata: parseJsonOption(getStringOption(parsed, "metadata")),
69
+ });
70
+ runtime.logger.success("agente registrado.");
71
+ if (!printJsonIfRequested(parsed, agent)) {
72
+ printAgent(agent);
73
+ }
74
+ return 0;
75
+ }
76
+ if (subcommand === "update") {
77
+ const agentId = requirePositional(parsed, 1, "Informe o identificador do agente.");
78
+ const payload = {};
79
+ if (parsed.options.name !== undefined)
80
+ payload.name = getStringOption(parsed, "name")?.trim();
81
+ if (parsed.options.provider !== undefined)
82
+ payload.provider = getStringOption(parsed, "provider")?.trim();
83
+ if (parsed.options.model !== undefined)
84
+ payload.model = getStringOption(parsed, "model")?.trim();
85
+ if (parsed.options.capabilities !== undefined)
86
+ payload.capabilities = getStringListOption(parsed, "capabilities");
87
+ if (parsed.options.cost !== undefined)
88
+ payload.costProfile = getStringOption(parsed, "cost")?.trim();
89
+ if (parsed.options.latency !== undefined)
90
+ payload.latencyProfile = getStringOption(parsed, "latency")?.trim();
91
+ if (parsed.options.reliability !== undefined)
92
+ payload.reliabilityScore = Number(getStringOption(parsed, "reliability"));
93
+ if (parsed.options.status !== undefined)
94
+ payload.status = getStringOption(parsed, "status")?.trim();
95
+ if (parsed.options.metadata !== undefined)
96
+ payload.metadata = parseJsonOption(getStringOption(parsed, "metadata"));
97
+ if (Object.keys(payload).length === 0) {
98
+ throw new ValidationError("Informe ao menos um campo para atualização.");
99
+ }
100
+ const agent = await apiClient.updateRegistryAgent(session.accessToken, agentId, payload);
101
+ runtime.logger.success("agente atualizado.");
102
+ if (!printJsonIfRequested(parsed, agent)) {
103
+ printAgent(agent);
104
+ }
105
+ return 0;
106
+ }
107
+ if (subcommand === "deactivate") {
108
+ const agentId = requirePositional(parsed, 1, "Informe o identificador do agente.");
109
+ await apiClient.deactivateRegistryAgent(session.accessToken, agentId);
110
+ runtime.logger.success("agente desativado.");
111
+ process.stdout.write(`Agent deactivated: ${agentId}\n`);
112
+ return 0;
113
+ }
114
+ throw new ValidationError("Subcomando de registry não suportado.");
115
+ }
116
+ //# sourceMappingURL=registry.js.map
@@ -7,7 +7,7 @@ import { ensureFreshSession, resolveWorkspaceSlug } from "../core/session.js";
7
7
  import { VectorPlaneApiClient } from "../core/api.js";
8
8
  import { deriveClientInstanceId, getBoundWorkspace, resolveWorkspaceRoot } from "../core/workspace-binding.js";
9
9
  import { ValidationError } from "../core/errors.js";
10
- import { ensureAgentSetupCurrent } from "../core/agent-setup.js";
10
+ import { ensureRuntimeAgentSetup } from "../core/runtime-agent-setup.js";
11
11
  function readCollaborationMetadata(parsed, rootPath) {
12
12
  const owningPaths = getStringListOption(parsed, "owning-path");
13
13
  const needs = getStringListOption(parsed, "need");
@@ -57,15 +57,7 @@ export async function runSessionCommand(cliVersion, args) {
57
57
  if (!workspace) {
58
58
  throw new ValidationError("Nenhum workspace resolvido para a sessão.");
59
59
  }
60
- await ensureAgentSetupCurrent({
61
- rootPath,
62
- workspace,
63
- repoUrl: git.remoteOrigin,
64
- source: git.remoteOrigin ? "api-resolve" : "manual",
65
- accessToken: freshSession.accessToken,
66
- apiClient,
67
- logger: runtime.logger,
68
- });
60
+ await ensureRuntimeAgentSetup({ rootPath, workspace, git, session: freshSession, apiClient, logger: runtime.logger });
69
61
  const clientInstanceId = getStringOption(parsed, "client-instance-id") ?? deriveClientInstanceId(runtime.device.machineId, rootPath, git);
70
62
  const metadata = readCollaborationMetadata(parsed, rootPath);
71
63
  if (subcommand === "check-in") {
@@ -10,7 +10,7 @@ import { VectorPlaneApiClient } from "../core/api.js";
10
10
  import { collectWorkspaceContext } from "../core/workspace.js";
11
11
  import { getBoundWorkspace } from "../core/workspace-binding.js";
12
12
  import { ValidationError } from "../core/errors.js";
13
- import { ensureAgentSetupCurrent } from "../core/agent-setup.js";
13
+ import { ensureRuntimeAgentSetup } from "../core/runtime-agent-setup.js";
14
14
  export async function runSyncCommand(cliVersion, args) {
15
15
  const parsed = parseArgs(args);
16
16
  const force = getBooleanOption(parsed, "force");
@@ -40,12 +40,11 @@ export async function runSyncCommand(cliVersion, args) {
40
40
  if (!workspaceSlug) {
41
41
  throw new ValidationError("Nenhum workspace ativo foi resolvido. Use `vp workspace use <workspace>` ou `vp login`.");
42
42
  }
43
- await ensureAgentSetupCurrent({
43
+ await ensureRuntimeAgentSetup({
44
44
  rootPath: workspaceRoot,
45
45
  workspace: workspaceSlug,
46
- repoUrl: git.remoteOrigin,
47
- source: git.remoteOrigin ? "api-resolve" : "manual",
48
- accessToken: freshSession.accessToken,
46
+ git,
47
+ session: freshSession,
49
48
  apiClient,
50
49
  logger: runtime.logger,
51
50
  });
@@ -0,0 +1 @@
1
+ export declare function runTaskCommand(cliVersion: string, args: string[]): Promise<number>;