@vectorplane/ctrl-cli 0.1.12 → 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
@@ -21,11 +21,15 @@ vp sync
21
21
  vp task templates
22
22
  vp task run --title "Entrega X" --intention "Implementar fluxo Y"
23
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>
24
25
  vp task claim --capability qa.test
25
26
  vp task execute <task-id> --step <step-id>
26
27
  vp task daemon --capability qa.test
27
28
  vp context --search "decisões sobre autenticação"
28
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
29
33
  vp context --workspace <workspace> --delivery
30
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"
31
35
  vp draft create --type progress --title "Entrega concluída" --content "Resumo da mudança"
@@ -74,6 +78,7 @@ vp draft create --type progress --title "Entrega concluída" --content "Resumo d
74
78
  - lista templates disponíveis com `vp task templates`
75
79
  - aceita `--template <slug>` para herdar capabilities e paths padrão do backend
76
80
  - lista e inspeciona tasks existentes
81
+ - acompanha uma task em tempo real com `vp task watch <taskId>`
77
82
  - faz claim explícito de steps `pending_claim` atribuídos a agentes CLI
78
83
  - executa steps locais via `metadata.execution.command`
79
84
  - suporta loop controlado com `vp task daemon --capability ...`
@@ -111,12 +116,14 @@ vp draft create --type progress --title "Entrega concluída" --content "Resumo d
111
116
  - inclui `vp config privacy` e `vp config policy`
112
117
  - `vp workspace`
113
118
  - gerencia o workspace atual
119
+ - suporta `vp workspace webhook list|create|delete` para integrações externas por workspace
114
120
  - `vp session`
115
121
  - gerencia sessões de agente
116
122
  - `vp context`
117
123
  - carrega contexto remoto do workspace
118
124
  - suporta `--search "QUERY"` para busca semântica na memória
119
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
120
127
  - `vp bootstrap`
121
128
  - obtém instruções de setup do workspace
122
129
  - `vp event send`
@@ -12,6 +12,7 @@ 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");
15
16
  const search = getStringOption(parsed, "search")?.trim();
16
17
  const runtime = await loadRuntimeStatus();
17
18
  const session = await ensureSessionAvailable(runtime.profile.name);
@@ -38,6 +39,9 @@ export async function runContextCommand(cliVersion, args) {
38
39
  throw new ValidationError("Nenhum workspace resolvido para carregar contexto.");
39
40
  }
40
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
+ }
41
45
  const payload = search
42
46
  ? (delivery
43
47
  ? await apiClient.getWorkspaceDeliveryContextSemantic(freshSession.accessToken, workspace, {
@@ -52,11 +56,16 @@ export async function runContextCommand(cliVersion, args) {
52
56
  authority: getStringOption(parsed, "authority")?.trim(),
53
57
  limit: Number(getStringOption(parsed, "limit") ?? "0") || undefined,
54
58
  }))
55
- : delivery
56
- ? await apiClient.getWorkspaceDeliveryContext(freshSession.accessToken, workspace)
57
- : snapshot
58
- ? await apiClient.getWorkspaceSnapshot(freshSession.accessToken, workspace)
59
- : await apiClient.getWorkspaceContext(freshSession.accessToken, workspace);
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);
60
69
  process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
61
70
  return 0;
62
71
  }
@@ -157,6 +157,12 @@ function printObservability(payload) {
157
157
  process.stdout.write(`Delegadas: ${String(payload.delegatedTasks ?? 0)}\n`);
158
158
  process.stdout.write(`Success rate: ${String(payload.successRate ?? 0)}\n`);
159
159
  }
160
+ function printWatchEvent(event) {
161
+ const scope = event.taskId ? `task=${event.taskId}` : `workspace=${event.workspaceId}`;
162
+ const step = event.stepId ? ` step=${event.stepId}` : "";
163
+ const summary = event.summary ? ` ${JSON.stringify(event.summary)}` : "";
164
+ process.stdout.write(`[${event.timestamp}] ${event.type} ${scope}${step}${summary}\n`);
165
+ }
160
166
  async function runTaskList(cliVersion, args) {
161
167
  const { parsed, apiClient, freshSession, workspace } = await resolveAuthenticatedWorkspace(cliVersion, args);
162
168
  const tasks = await apiClient.listTasks(freshSession.accessToken, workspace);
@@ -433,6 +439,40 @@ async function runTaskObservability(cliVersion, args) {
433
439
  }
434
440
  return 0;
435
441
  }
442
+ async function runTaskWatch(cliVersion, args) {
443
+ const { apiClient, freshSession, workspace } = await resolveAuthenticatedWorkspace(cliVersion, args);
444
+ const parsed = parseArgs(args);
445
+ const taskId = requirePositional(parsed, 0, "Uso: vp task watch <taskId> [--json]");
446
+ const task = await apiClient.getTask(freshSession.accessToken, workspace, taskId);
447
+ if (printJsonIfRequested(parsed, task)) {
448
+ return 0;
449
+ }
450
+ printTask(task);
451
+ const controller = new AbortController();
452
+ let exitCode = 0;
453
+ await apiClient.streamWorkspaceEvents(freshSession.accessToken, workspace, {
454
+ taskId,
455
+ signal: controller.signal,
456
+ onEvent: (event) => {
457
+ if (event.type === "ready" || event.type === "heartbeat") {
458
+ return;
459
+ }
460
+ printWatchEvent(event);
461
+ if (event.type === "task.failed" || event.type === "task.blocked") {
462
+ exitCode = 1;
463
+ }
464
+ if (event.type === "task.completed" || event.type === "task.failed" || event.type === "task.blocked") {
465
+ controller.abort();
466
+ }
467
+ },
468
+ }).catch((error) => {
469
+ if (controller.signal.aborted) {
470
+ return;
471
+ }
472
+ throw error;
473
+ });
474
+ return exitCode;
475
+ }
436
476
  async function runTaskHealth(cliVersion, args) {
437
477
  const { apiClient, freshSession, workspace } = await resolveAuthenticatedWorkspace(cliVersion, args);
438
478
  const parsed = parseArgs(args);
@@ -465,7 +505,7 @@ async function runTaskApproval(cliVersion, args, approved) {
465
505
  }
466
506
  export async function runTaskCommand(cliVersion, args) {
467
507
  const parsed = parseArgs(args);
468
- const subcommand = requirePositional(parsed, 0, "Uso: vp task <run|templates|list|inspect|claim|execute|daemon|approve|reject|delegate|step-update|handoff|observability|health> [...]");
508
+ const subcommand = requirePositional(parsed, 0, "Uso: vp task <run|templates|list|inspect|watch|claim|execute|daemon|approve|reject|delegate|step-update|handoff|observability|health> [...]");
469
509
  switch (subcommand) {
470
510
  case "run":
471
511
  return runTaskRun(cliVersion, args.slice(1));
@@ -475,6 +515,8 @@ export async function runTaskCommand(cliVersion, args) {
475
515
  return runTaskList(cliVersion, args.slice(1));
476
516
  case "inspect":
477
517
  return runTaskInspect(cliVersion, args.slice(1));
518
+ case "watch":
519
+ return runTaskWatch(cliVersion, args.slice(1));
478
520
  case "claim":
479
521
  return runTaskClaim(cliVersion, args.slice(1));
480
522
  case "execute":
@@ -496,7 +538,7 @@ export async function runTaskCommand(cliVersion, args) {
496
538
  case "health":
497
539
  return runTaskHealth(cliVersion, args.slice(1));
498
540
  default:
499
- throw new ValidationError("Uso: vp task <run|templates|list|inspect|claim|execute|daemon|approve|reject|delegate|step-update|handoff|observability|health> [...]");
541
+ throw new ValidationError("Uso: vp task <run|templates|list|inspect|watch|claim|execute|daemon|approve|reject|delegate|step-update|handoff|observability|health> [...]");
500
542
  }
501
543
  }
502
544
  //# sourceMappingURL=task.js.map
@@ -39,6 +39,20 @@ function printPolicyRule(rule) {
39
39
  process.stdout.write(`Required capabilities: ${rule.conditions.requiredCapabilities.join(", ")}\n`);
40
40
  }
41
41
  }
42
+ function printWebhook(hook) {
43
+ process.stdout.write(`Webhook: ${hook.id}\n`);
44
+ process.stdout.write(`Nome: ${hook.name}\n`);
45
+ process.stdout.write(`URL: ${hook.targetUrl}\n`);
46
+ process.stdout.write(`Enabled: ${hook.enabled ? "true" : "false"}\n`);
47
+ process.stdout.write(`Secret: ${hook.secretPreview}\n`);
48
+ process.stdout.write(`Eventos: ${hook.events.join(", ")}\n`);
49
+ if (hook.lastDeliveryStatus) {
50
+ process.stdout.write(`Última entrega: ${hook.lastDeliveryStatus}${hook.lastDeliveryAt ? ` em ${hook.lastDeliveryAt}` : ""}\n`);
51
+ }
52
+ if (hook.lastError) {
53
+ process.stdout.write(`Erro: ${hook.lastError}\n`);
54
+ }
55
+ }
42
56
  function resolvePolicyConditions(parsed) {
43
57
  const archetypes = getStringListOption(parsed, "archetypes");
44
58
  const requiredCapabilities = getStringListOption(parsed, "required-capabilities");
@@ -155,6 +169,54 @@ async function runWorkspacePolicyCommand(args) {
155
169
  }
156
170
  throw new ValidationError("Subcomando de workspace policy não suportado.");
157
171
  }
172
+ async function runWorkspaceWebhookCommand(args) {
173
+ const parsed = parseArgs(args);
174
+ const [subcommand] = parsed.positionals.slice(1);
175
+ const { session, apiClient, workspace } = await resolveWorkspaceApiContext();
176
+ if (!subcommand || subcommand === "list") {
177
+ const hooks = await apiClient.listWorkspaceWebhooks(session.accessToken, workspace);
178
+ if (printJsonIfRequested(parsed, hooks)) {
179
+ return 0;
180
+ }
181
+ if (hooks.length === 0) {
182
+ process.stdout.write("VectorPlane: nenhum webhook encontrado.\n");
183
+ return 0;
184
+ }
185
+ for (const hook of hooks) {
186
+ process.stdout.write(`${hook.id} | ${hook.enabled ? "enabled" : "disabled"} | ${hook.name} | ${hook.targetUrl}\n`);
187
+ }
188
+ return 0;
189
+ }
190
+ if (subcommand === "create") {
191
+ const name = getStringOption(parsed, "name")?.trim();
192
+ const targetUrl = getStringOption(parsed, "url")?.trim();
193
+ const secret = getStringOption(parsed, "secret")?.trim();
194
+ const events = getStringListOption(parsed, "events");
195
+ if (!name || !targetUrl || !secret || events.length === 0) {
196
+ throw new ValidationError("Informe `--name`, `--url`, `--secret` e `--events`.");
197
+ }
198
+ const hook = await apiClient.createWorkspaceWebhook(session.accessToken, workspace, {
199
+ name,
200
+ targetUrl,
201
+ secret,
202
+ events,
203
+ enabled: parsed.options.enabled === undefined ? true : getBooleanOption(parsed, "enabled"),
204
+ });
205
+ if (!printJsonIfRequested(parsed, hook)) {
206
+ printWebhook(hook);
207
+ }
208
+ return 0;
209
+ }
210
+ if (subcommand === "delete") {
211
+ const webhookId = requirePositional(parsed, 2, "Informe o identificador do webhook.");
212
+ const result = await apiClient.deleteWorkspaceWebhook(session.accessToken, workspace, webhookId);
213
+ if (!printJsonIfRequested(parsed, result)) {
214
+ process.stdout.write(`Webhook removido: ${result.webhookId}\n`);
215
+ }
216
+ return 0;
217
+ }
218
+ throw new ValidationError("Subcomando de workspace webhook não suportado.");
219
+ }
158
220
  export async function runWorkspaceCommand(args) {
159
221
  const parsed = parseArgs(args);
160
222
  const [subcommand] = parsed.positionals;
@@ -214,6 +276,9 @@ export async function runWorkspaceCommand(args) {
214
276
  if (subcommand === "policy") {
215
277
  return runWorkspacePolicyCommand(args);
216
278
  }
279
+ if (subcommand === "webhook") {
280
+ return runWorkspaceWebhookCommand(args);
281
+ }
217
282
  throw new ValidationError("Subcomando de workspace não suportado.");
218
283
  }
219
284
  //# sourceMappingURL=workspace.js.map
@@ -1,6 +1,6 @@
1
1
  import type { Logger } from "./logger.js";
2
2
  import type { CurrentUserResponse, AuthCodeExchangeRequest, AuthTokenExchangeResponse, CreateLoginAttemptRequest, CreateLoginAttemptResponse, LoginAttemptStatusResponse, RefreshTokenRequest } from "../types/auth.js";
3
- import type { AgentCheckoutRequest, AgentHeartbeatRequest, AgentSessionRequest, AgentSessionResponse, EventRequest, MemoryDraftCreateRequest, MemoryDraftRecord, MemoryDraftStatus, MemorySearchRecord, ClaimableTaskStepRecord, ClaimedTaskStepResponse, TaskCreateRequest, TaskHandoffRecord, TaskObservabilityRecord, TaskRecord, ResolveWorkspaceRequest, ResolveWorkspaceResponse, SyncRequest, SyncResponse, WorkspaceAgentSetup, WorkspacePolicyRuleRecord, AgentRegistryRecord, TaskTemplateRecord } from "../types/api.js";
3
+ import type { AgentCheckoutRequest, AgentHeartbeatRequest, AgentSessionRequest, AgentSessionResponse, EventRequest, MemoryDraftCreateRequest, MemoryDraftRecord, MemoryDraftStatus, MemorySearchRecord, ClaimableTaskStepRecord, ClaimedTaskStepResponse, TaskCreateRequest, TaskHandoffRecord, TaskObservabilityRecord, TaskRecord, ResolveWorkspaceRequest, ResolveWorkspaceResponse, SyncRequest, SyncResponse, WorkspaceAgentSetup, WorkspaceSnapshotDiffRecord, WorkspacePolicyRuleRecord, WorkspaceWebhookRecord, AgentRegistryRecord, TaskTemplateRecord, WorkspaceStreamEventRecord } from "../types/api.js";
4
4
  export declare class VectorPlaneApiClient {
5
5
  private readonly apiBaseUrl;
6
6
  private readonly timeoutMs;
@@ -20,6 +20,10 @@ export declare class VectorPlaneApiClient {
20
20
  resolveWorkspaceByRepo(accessToken: string, payload: ResolveWorkspaceRequest): Promise<ResolveWorkspaceResponse>;
21
21
  getWorkspaceContext(accessToken: string, workspaceId: string): Promise<Record<string, unknown>>;
22
22
  getWorkspaceSnapshot(accessToken: string, workspaceId: string): Promise<Record<string, unknown>>;
23
+ getWorkspaceSnapshotDiff(accessToken: string, workspaceId: string, params: {
24
+ from?: string;
25
+ to?: string;
26
+ }): Promise<WorkspaceSnapshotDiffRecord>;
23
27
  getWorkspaceDeliveryContext(accessToken: string, workspaceId: string): Promise<Record<string, unknown>>;
24
28
  getWorkspaceDeliveryContextSemantic(accessToken: string, workspaceId: string, params: {
25
29
  query: string;
@@ -49,6 +53,18 @@ export declare class VectorPlaneApiClient {
49
53
  approvalRole?: string | null;
50
54
  enabled?: boolean;
51
55
  }): Promise<WorkspacePolicyRuleRecord>;
56
+ listWorkspaceWebhooks(accessToken: string, workspaceRef: string): Promise<WorkspaceWebhookRecord[]>;
57
+ createWorkspaceWebhook(accessToken: string, workspaceRef: string, payload: {
58
+ name: string;
59
+ targetUrl: string;
60
+ secret: string;
61
+ events: WorkspaceWebhookRecord["events"];
62
+ enabled?: boolean;
63
+ }): Promise<WorkspaceWebhookRecord>;
64
+ deleteWorkspaceWebhook(accessToken: string, workspaceRef: string, webhookId: string): Promise<{
65
+ deleted: boolean;
66
+ webhookId: string;
67
+ }>;
52
68
  listMemoryDrafts(accessToken: string, workspaceRef: string, status?: MemoryDraftStatus): Promise<MemoryDraftRecord[]>;
53
69
  createMemoryDraft(accessToken: string, workspaceRef: string, payload: MemoryDraftCreateRequest): Promise<MemoryDraftRecord>;
54
70
  searchWorkspaceMemory(accessToken: string, workspaceRef: string, params: {
@@ -119,4 +135,10 @@ export declare class VectorPlaneApiClient {
119
135
  checkOutAgent(accessToken: string, payload: AgentCheckoutRequest): Promise<AgentSessionResponse>;
120
136
  getHealth(): Promise<Record<string, unknown>>;
121
137
  getReady(): Promise<Record<string, unknown>>;
138
+ streamWorkspaceEvents(accessToken: string, workspaceRef: string, params: {
139
+ taskId?: string;
140
+ types?: string[];
141
+ signal?: AbortSignal;
142
+ onEvent: (event: WorkspaceStreamEventRecord) => void;
143
+ }): Promise<void>;
122
144
  }
package/dist/core/api.js CHANGED
@@ -144,6 +144,21 @@ export class VectorPlaneApiClient {
144
144
  },
145
145
  }, this.timeoutMs, this.logger);
146
146
  }
147
+ async getWorkspaceSnapshotDiff(accessToken, workspaceId, params) {
148
+ const url = new URL(`${this.apiBaseUrl}/workspace/${workspaceId}/snapshot/diff`);
149
+ if (params.from) {
150
+ url.searchParams.set("from", params.from);
151
+ }
152
+ if (params.to) {
153
+ url.searchParams.set("to", params.to);
154
+ }
155
+ return requestJson(url.toString(), {
156
+ method: "GET",
157
+ headers: {
158
+ "Authorization": `Bearer ${accessToken}`,
159
+ },
160
+ }, this.timeoutMs, this.logger);
161
+ }
147
162
  async getWorkspaceDeliveryContext(accessToken, workspaceId) {
148
163
  return requestJson(`${this.apiBaseUrl}/cli/workspace/${workspaceId}/delivery-context`, {
149
164
  method: "GET",
@@ -202,6 +217,29 @@ export class VectorPlaneApiClient {
202
217
  body: JSON.stringify(payload),
203
218
  }, this.timeoutMs, this.logger);
204
219
  }
220
+ async listWorkspaceWebhooks(accessToken, workspaceRef) {
221
+ return requestJson(`${this.apiBaseUrl}/workspace/${workspaceRef}/webhooks`, {
222
+ method: "GET",
223
+ headers: {
224
+ "Authorization": `Bearer ${accessToken}`,
225
+ },
226
+ }, this.timeoutMs, this.logger);
227
+ }
228
+ async createWorkspaceWebhook(accessToken, workspaceRef, payload) {
229
+ return requestJson(`${this.apiBaseUrl}/workspace/${workspaceRef}/webhooks`, {
230
+ method: "POST",
231
+ headers: authHeaders(accessToken),
232
+ body: JSON.stringify(payload),
233
+ }, this.timeoutMs, this.logger);
234
+ }
235
+ async deleteWorkspaceWebhook(accessToken, workspaceRef, webhookId) {
236
+ return requestJson(`${this.apiBaseUrl}/workspace/${workspaceRef}/webhooks/${webhookId}`, {
237
+ method: "DELETE",
238
+ headers: {
239
+ "Authorization": `Bearer ${accessToken}`,
240
+ },
241
+ }, this.timeoutMs, this.logger);
242
+ }
205
243
  async listMemoryDrafts(accessToken, workspaceRef, status) {
206
244
  const url = new URL(`${this.apiBaseUrl}/cli/workspace/${workspaceRef}/memory-drafts`);
207
245
  if (status) {
@@ -421,5 +459,79 @@ export class VectorPlaneApiClient {
421
459
  method: "GET",
422
460
  }, this.timeoutMs, this.logger);
423
461
  }
462
+ async streamWorkspaceEvents(accessToken, workspaceRef, params) {
463
+ const url = new URL(`${this.apiBaseUrl}/workspace/${workspaceRef}/events/stream`);
464
+ if (params.taskId) {
465
+ url.searchParams.set("task_id", params.taskId);
466
+ }
467
+ if (params.types && params.types.length > 0) {
468
+ url.searchParams.set("types", params.types.join(","));
469
+ }
470
+ this.logger.debug("http_stream_open", { url: url.toString() });
471
+ const response = await fetch(url.toString(), {
472
+ method: "GET",
473
+ headers: {
474
+ "Authorization": `Bearer ${accessToken}`,
475
+ "Accept": "text/event-stream",
476
+ },
477
+ signal: params.signal,
478
+ });
479
+ if (!response.ok || !response.body) {
480
+ const body = await parseBody(response);
481
+ const message = typeof body === "string" ? body : `HTTP ${response.status}`;
482
+ throw new ApiError(message, response.status, body);
483
+ }
484
+ const reader = response.body.getReader();
485
+ const decoder = new TextDecoder();
486
+ let buffer = "";
487
+ const emitFrame = (frame) => {
488
+ const lines = frame.split("\n");
489
+ let eventName = "message";
490
+ const dataLines = [];
491
+ for (const line of lines) {
492
+ if (line.startsWith("event:")) {
493
+ eventName = line.slice(6).trim();
494
+ continue;
495
+ }
496
+ if (line.startsWith("data:")) {
497
+ dataLines.push(line.slice(5).trim());
498
+ }
499
+ }
500
+ if (dataLines.length === 0) {
501
+ return;
502
+ }
503
+ try {
504
+ const payload = JSON.parse(dataLines.join("\n"));
505
+ params.onEvent({
506
+ type: eventName,
507
+ workspaceId: payload.workspaceId,
508
+ taskId: payload.taskId ?? null,
509
+ stepId: payload.stepId ?? null,
510
+ timestamp: payload.timestamp,
511
+ summary: payload.summary ?? null,
512
+ });
513
+ }
514
+ catch (error) {
515
+ this.logger.debug("http_stream_frame_ignored", {
516
+ reason: error instanceof Error ? error.message : "invalid_json",
517
+ eventName,
518
+ });
519
+ }
520
+ };
521
+ while (true) {
522
+ const { done, value } = await reader.read();
523
+ if (done) {
524
+ break;
525
+ }
526
+ buffer += decoder.decode(value, { stream: true });
527
+ let separatorIndex = buffer.indexOf("\n\n");
528
+ while (separatorIndex >= 0) {
529
+ const frame = buffer.slice(0, separatorIndex);
530
+ buffer = buffer.slice(separatorIndex + 2);
531
+ emitFrame(frame);
532
+ separatorIndex = buffer.indexOf("\n\n");
533
+ }
534
+ }
535
+ }
424
536
  }
425
537
  //# sourceMappingURL=api.js.map
package/dist/index.js CHANGED
@@ -35,13 +35,13 @@ function printHelp() {
35
35
  process.stdout.write(" logout\n");
36
36
  process.stdout.write(" sync [--force]\n");
37
37
  process.stdout.write(" status\n");
38
- process.stdout.write(" task <run|templates|list|inspect|claim|execute|daemon|approve|reject|delegate|step-update|handoff|observability|health>\n");
38
+ process.stdout.write(" task <run|templates|list|inspect|watch|claim|execute|daemon|approve|reject|delegate|step-update|handoff|observability|health>\n");
39
39
  process.stdout.write(" registry <list|register|update|deactivate>\n");
40
40
  process.stdout.write(" whoami\n");
41
41
  process.stdout.write(" doctor\n");
42
42
  process.stdout.write(" draft <create|list>\n");
43
43
  process.stdout.write(" config <profile|get|set>\n");
44
- process.stdout.write(" workspace <current|use|resolve|clear>\n");
44
+ process.stdout.write(" workspace <current|use|resolve|clear|policy|webhook>\n");
45
45
  process.stdout.write(" session <check-in|heartbeat|check-out>\n");
46
46
  process.stdout.write(" context [--snapshot|--delivery]\n");
47
47
  process.stdout.write(" bootstrap\n");
@@ -88,6 +88,23 @@ export interface WorkspacePolicyRuleRecord {
88
88
  updatedAt: string;
89
89
  [key: string]: unknown;
90
90
  }
91
+ export type WorkspaceWebhookEventType = "task.created" | "task.blocked" | "task.completed" | "task.approval_required" | "health.degraded";
92
+ export interface WorkspaceWebhookRecord {
93
+ id: string;
94
+ orgId: string;
95
+ workspaceId: string;
96
+ name: string;
97
+ targetUrl: string;
98
+ secretPreview: string;
99
+ events: WorkspaceWebhookEventType[];
100
+ enabled: boolean;
101
+ lastDeliveryAt: string | null;
102
+ lastDeliveryStatus: "delivered" | "failed" | null;
103
+ lastError: string | null;
104
+ createdAt: string;
105
+ updatedAt: string;
106
+ [key: string]: unknown;
107
+ }
91
108
  export interface AgentRegistryRecord {
92
109
  id: string;
93
110
  orgId: string | null;
@@ -291,3 +308,32 @@ export interface TaskObservabilityRecord {
291
308
  timeline?: Array<Record<string, unknown>>;
292
309
  [key: string]: unknown;
293
310
  }
311
+ export interface WorkspaceStreamEventRecord {
312
+ type: string;
313
+ workspaceId: string;
314
+ taskId?: string | null;
315
+ stepId?: string | null;
316
+ timestamp: string;
317
+ summary?: Record<string, unknown> | null;
318
+ }
319
+ export interface WorkspaceSnapshotDiffRecord {
320
+ workspaceId: string;
321
+ from: {
322
+ reference: string;
323
+ version: number;
324
+ generatedAt: string;
325
+ };
326
+ to: {
327
+ reference: string;
328
+ version: number;
329
+ generatedAt: string;
330
+ };
331
+ summary: Record<string, {
332
+ added: number;
333
+ removed: number;
334
+ modified: number;
335
+ }>;
336
+ added: Record<string, Array<Record<string, unknown>>>;
337
+ removed: Record<string, Array<Record<string, unknown>>>;
338
+ modified: Record<string, Array<Record<string, unknown>>>;
339
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectorplane/ctrl-cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "Official VectorPlane CLI.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",