@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.
@@ -1,10 +1,222 @@
1
- import { getStringOption, parseArgs, requirePositional } from "../core/cli.js";
1
+ import { getBooleanOption, getStringListOption, getStringOption, parseArgs, requirePositional } from "../core/cli.js";
2
2
  import { ensureSessionAvailable, upsertProfile } from "../core/config.js";
3
3
  import { collectGitContext } from "../core/git.js";
4
4
  import { loadRuntimeStatus } from "../core/runtime.js";
5
5
  import { VectorPlaneApiClient } from "../core/api.js";
6
6
  import { bindWorkspaceToRoot, clearBoundWorkspace, getBindingStore, resolveWorkspaceRoot } from "../core/workspace-binding.js";
7
7
  import { ValidationError } from "../core/errors.js";
8
+ function printJsonIfRequested(parsed, payload) {
9
+ if (!getBooleanOption(parsed, "json")) {
10
+ return false;
11
+ }
12
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
13
+ return true;
14
+ }
15
+ function printPolicyRule(rule) {
16
+ process.stdout.write(`Rule: ${rule.id}\n`);
17
+ process.stdout.write(`Nome: ${rule.name}\n`);
18
+ process.stdout.write(`Effect: ${rule.effect}\n`);
19
+ process.stdout.write(`Enabled: ${rule.enabled ? "true" : "false"}\n`);
20
+ if (rule.pathPrefix) {
21
+ process.stdout.write(`Path: ${rule.pathPrefix}\n`);
22
+ }
23
+ if (rule.capability) {
24
+ process.stdout.write(`Capability: ${rule.capability}\n`);
25
+ }
26
+ if (rule.approvalRole) {
27
+ process.stdout.write(`Approval role: ${rule.approvalRole}\n`);
28
+ }
29
+ if (rule.rationale) {
30
+ process.stdout.write(`Rationale: ${rule.rationale}\n`);
31
+ }
32
+ if (rule.conditions?.archetypes?.length) {
33
+ process.stdout.write(`Archetypes: ${rule.conditions.archetypes.join(", ")}\n`);
34
+ }
35
+ if (typeof rule.conditions?.minTargetPathCount === "number") {
36
+ process.stdout.write(`Min target paths: ${rule.conditions.minTargetPathCount}\n`);
37
+ }
38
+ if (rule.conditions?.requiredCapabilities?.length) {
39
+ process.stdout.write(`Required capabilities: ${rule.conditions.requiredCapabilities.join(", ")}\n`);
40
+ }
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
+ }
56
+ function resolvePolicyConditions(parsed) {
57
+ const archetypes = getStringListOption(parsed, "archetypes");
58
+ const requiredCapabilities = getStringListOption(parsed, "required-capabilities");
59
+ const minTargetPathCountRaw = getStringOption(parsed, "min-target-path-count");
60
+ const minTargetPathCount = minTargetPathCountRaw ? Number(minTargetPathCountRaw) : undefined;
61
+ if (minTargetPathCountRaw && (!Number.isInteger(minTargetPathCount) || (minTargetPathCount ?? 0) < 1)) {
62
+ throw new ValidationError("`--min-target-path-count` deve ser um inteiro maior que zero.");
63
+ }
64
+ if (archetypes.length === 0 && requiredCapabilities.length === 0 && minTargetPathCount === undefined) {
65
+ return undefined;
66
+ }
67
+ return {
68
+ ...(archetypes.length > 0 ? { archetypes } : {}),
69
+ ...(requiredCapabilities.length > 0 ? { requiredCapabilities } : {}),
70
+ ...(minTargetPathCount !== undefined ? { minTargetPathCount } : {}),
71
+ };
72
+ }
73
+ async function resolveWorkspaceApiContext() {
74
+ const runtime = await loadRuntimeStatus();
75
+ const session = await ensureSessionAvailable(runtime.profile.name);
76
+ const git = await collectGitContext(process.cwd());
77
+ const rootPath = resolveWorkspaceRoot(process.cwd(), git);
78
+ const store = await getBindingStore();
79
+ const binding = store.bindings[rootPath];
80
+ const workspace = binding?.workspace ?? runtime.profile.workspace;
81
+ if (!workspace) {
82
+ throw new ValidationError("Nenhum workspace resolvido. Use `vp workspace use <workspace>` ou `vp workspace resolve`.");
83
+ }
84
+ const apiClient = new VectorPlaneApiClient(runtime.profile.apiBaseUrl, runtime.config.requestTimeoutMs, runtime.logger);
85
+ return { runtime, session, apiClient, workspace };
86
+ }
87
+ async function runWorkspacePolicyCommand(args) {
88
+ const parsed = parseArgs(args);
89
+ const [subcommand] = parsed.positionals.slice(1);
90
+ const { session, apiClient, workspace } = await resolveWorkspaceApiContext();
91
+ if (!subcommand || subcommand === "list") {
92
+ const rules = await apiClient.listWorkspacePolicyRules(session.accessToken, workspace);
93
+ if (printJsonIfRequested(parsed, rules)) {
94
+ return 0;
95
+ }
96
+ if (rules.length === 0) {
97
+ process.stdout.write("VectorPlane: nenhuma policy rule encontrada.\n");
98
+ return 0;
99
+ }
100
+ for (const rule of rules) {
101
+ process.stdout.write(`${rule.id} | ${rule.enabled ? "enabled" : "disabled"} | ${rule.effect} | ${rule.name}\n`);
102
+ }
103
+ return 0;
104
+ }
105
+ if (subcommand === "create") {
106
+ const name = getStringOption(parsed, "name")?.trim();
107
+ const pathPrefix = getStringOption(parsed, "path")?.trim();
108
+ const capability = getStringOption(parsed, "capability")?.trim();
109
+ const effect = getStringOption(parsed, "effect")?.trim();
110
+ if (!name || !effect || (!pathPrefix && !capability)) {
111
+ throw new ValidationError("Informe `--name`, `--effect` e pelo menos um entre `--path` ou `--capability`.");
112
+ }
113
+ const rule = await apiClient.createWorkspacePolicyRule(session.accessToken, workspace, {
114
+ name,
115
+ pathPrefix: pathPrefix || undefined,
116
+ capability: capability || undefined,
117
+ effect,
118
+ rationale: getStringOption(parsed, "rationale")?.trim() || undefined,
119
+ approvalRole: getStringOption(parsed, "approval-role")?.trim() || undefined,
120
+ enabled: parsed.options.enabled === undefined ? true : getBooleanOption(parsed, "enabled"),
121
+ conditions: resolvePolicyConditions(parsed),
122
+ });
123
+ if (!printJsonIfRequested(parsed, rule)) {
124
+ printPolicyRule(rule);
125
+ }
126
+ return 0;
127
+ }
128
+ if (subcommand === "update") {
129
+ const ruleId = requirePositional(parsed, 2, "Informe o identificador da policy rule.");
130
+ const updates = {};
131
+ if (parsed.options.name !== undefined) {
132
+ updates.name = getStringOption(parsed, "name")?.trim();
133
+ }
134
+ if (parsed.options.path !== undefined) {
135
+ updates.pathPrefix = getStringOption(parsed, "path")?.trim() || null;
136
+ }
137
+ if (parsed.options.capability !== undefined) {
138
+ updates.capability = getStringOption(parsed, "capability")?.trim() || null;
139
+ }
140
+ if (parsed.options.effect !== undefined) {
141
+ updates.effect = getStringOption(parsed, "effect")?.trim();
142
+ }
143
+ if (parsed.options.rationale !== undefined) {
144
+ updates.rationale = getStringOption(parsed, "rationale")?.trim() || null;
145
+ }
146
+ if (parsed.options["approval-role"] !== undefined) {
147
+ updates.approvalRole = getStringOption(parsed, "approval-role")?.trim() || null;
148
+ }
149
+ if (parsed.options.enabled !== undefined) {
150
+ updates.enabled = getBooleanOption(parsed, "enabled");
151
+ }
152
+ if (parsed.options["clear-conditions"]) {
153
+ updates.conditions = null;
154
+ }
155
+ else {
156
+ const conditions = resolvePolicyConditions(parsed);
157
+ if (conditions) {
158
+ updates.conditions = conditions;
159
+ }
160
+ }
161
+ if (Object.keys(updates).length === 0) {
162
+ throw new ValidationError("Informe ao menos um campo para atualização.");
163
+ }
164
+ const rule = await apiClient.updateWorkspacePolicyRule(session.accessToken, workspace, ruleId, updates);
165
+ if (!printJsonIfRequested(parsed, rule)) {
166
+ printPolicyRule(rule);
167
+ }
168
+ return 0;
169
+ }
170
+ throw new ValidationError("Subcomando de workspace policy não suportado.");
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
+ }
8
220
  export async function runWorkspaceCommand(args) {
9
221
  const parsed = parseArgs(args);
10
222
  const [subcommand] = parsed.positionals;
@@ -61,6 +273,12 @@ export async function runWorkspaceCommand(args) {
61
273
  process.stdout.write(`Workspace resolvido: ${workspace}\n`);
62
274
  return 0;
63
275
  }
276
+ if (subcommand === "policy") {
277
+ return runWorkspacePolicyCommand(args);
278
+ }
279
+ if (subcommand === "webhook") {
280
+ return runWorkspaceWebhookCommand(args);
281
+ }
64
282
  throw new ValidationError("Subcomando de workspace não suportado.");
65
283
  }
66
284
  //# sourceMappingURL=workspace.js.map
@@ -0,0 +1,13 @@
1
+ export type SupportedAgent = "claude" | "cursor" | "windsurf" | "copilot" | "codex" | "generic";
2
+ export type DetectionConfidence = "high" | "medium" | "low";
3
+ export interface AgentDetectionResult {
4
+ selected: SupportedAgent | null;
5
+ confidence: DetectionConfidence;
6
+ reasons: string[];
7
+ candidates: SupportedAgent[];
8
+ }
9
+ export declare function detectAgentRuntime(rootPath: string): Promise<AgentDetectionResult>;
10
+ export declare function resolveAgentSelection(rootPath: string, explicitAgent?: SupportedAgent): Promise<{
11
+ agent: SupportedAgent;
12
+ detection: AgentDetectionResult;
13
+ }>;
@@ -0,0 +1,117 @@
1
+ import { access } from "node:fs/promises";
2
+ import { constants as fsConstants } from "node:fs";
3
+ import path from "node:path";
4
+ import readline from "node:readline/promises";
5
+ import { ValidationError } from "./errors.js";
6
+ async function pathExists(filePath) {
7
+ try {
8
+ await access(filePath, fsConstants.F_OK);
9
+ return true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ function uniqueAgents(values) {
16
+ return [...new Set(values)];
17
+ }
18
+ export async function detectAgentRuntime(rootPath) {
19
+ const scores = new Map();
20
+ const reasons = new Map();
21
+ const addScore = (agent, amount, reason) => {
22
+ scores.set(agent, (scores.get(agent) ?? 0) + amount);
23
+ reasons.set(agent, [...(reasons.get(agent) ?? []), reason]);
24
+ };
25
+ const fileCandidates = [
26
+ { agent: "claude", file: path.join(rootPath, "CLAUDE.md") },
27
+ { agent: "cursor", file: path.join(rootPath, ".cursor") },
28
+ { agent: "windsurf", file: path.join(rootPath, ".windsurfrules") },
29
+ { agent: "copilot", file: path.join(rootPath, ".github", "copilot-instructions.md") },
30
+ { agent: "codex", file: path.join(rootPath, "AGENTS.md") },
31
+ ];
32
+ for (const candidate of fileCandidates) {
33
+ if (await pathExists(candidate.file)) {
34
+ addScore(candidate.agent, 25, `file:${path.relative(rootPath, candidate.file) || candidate.file}`);
35
+ }
36
+ }
37
+ const envSignals = [
38
+ { agent: "cursor", value: process.env.CURSOR_TRACE_ID, reason: "env:CURSOR_TRACE_ID" },
39
+ { agent: "windsurf", value: process.env.WINDSURF_SESSION_ID, reason: "env:WINDSURF_SESSION_ID" },
40
+ { agent: "codex", value: process.env.CODEX_ENV, reason: "env:CODEX_ENV" },
41
+ { agent: "claude", value: process.env.CLAUDECODE, reason: "env:CLAUDECODE" },
42
+ { agent: "copilot", value: process.env.GITHUB_COPILOT, reason: "env:GITHUB_COPILOT" },
43
+ ];
44
+ for (const signal of envSignals) {
45
+ if (signal.value) {
46
+ addScore(signal.agent, 100, signal.reason);
47
+ }
48
+ }
49
+ const ranked = [...scores.entries()].sort((left, right) => right[1] - left[1]);
50
+ if (ranked.length === 0) {
51
+ return { selected: null, confidence: "low", reasons: [], candidates: [] };
52
+ }
53
+ const topScore = ranked[0][1];
54
+ const candidates = uniqueAgents(ranked.filter((entry) => entry[1] === topScore).map(([agent]) => agent));
55
+ const selected = candidates.length === 1 ? candidates[0] : null;
56
+ return {
57
+ selected,
58
+ confidence: topScore >= 100 ? "high" : candidates.length === 1 ? "medium" : "low",
59
+ reasons: selected ? (reasons.get(selected) ?? []) : candidates.flatMap((agent) => reasons.get(agent) ?? []),
60
+ candidates,
61
+ };
62
+ }
63
+ async function promptForAgent(detection) {
64
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
65
+ throw new ValidationError("Não foi possível detectar o agente local com segurança. Use --agent claude|cursor|windsurf|copilot|codex|generic.");
66
+ }
67
+ const ordered = uniqueAgents([
68
+ ...detection.candidates,
69
+ "claude",
70
+ "cursor",
71
+ "windsurf",
72
+ "copilot",
73
+ "codex",
74
+ "generic",
75
+ ]);
76
+ process.stdout.write("VectorPlane: não foi possível identificar o agente local com segurança.\n");
77
+ ordered.forEach((agent, index) => {
78
+ process.stdout.write(` ${index + 1}. ${agent}\n`);
79
+ });
80
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
81
+ try {
82
+ const answer = (await rl.question("Selecione o agente local: ")).trim();
83
+ const index = Number(answer);
84
+ if (Number.isInteger(index) && index >= 1 && index <= ordered.length) {
85
+ return ordered[index - 1];
86
+ }
87
+ if (ordered.includes(answer)) {
88
+ return answer;
89
+ }
90
+ }
91
+ finally {
92
+ rl.close();
93
+ }
94
+ throw new ValidationError("Seleção de agente inválida.");
95
+ }
96
+ export async function resolveAgentSelection(rootPath, explicitAgent) {
97
+ if (explicitAgent) {
98
+ return {
99
+ agent: explicitAgent,
100
+ detection: {
101
+ selected: explicitAgent,
102
+ confidence: "high",
103
+ reasons: ["explicit-flag"],
104
+ candidates: [explicitAgent],
105
+ },
106
+ };
107
+ }
108
+ const detection = await detectAgentRuntime(rootPath);
109
+ if (detection.selected && detection.confidence !== "low") {
110
+ return { agent: detection.selected, detection };
111
+ }
112
+ return {
113
+ agent: await promptForAgent(detection),
114
+ detection,
115
+ };
116
+ }
117
+ //# sourceMappingURL=agent-runtime-detection.js.map
@@ -1,18 +1,6 @@
1
1
  import type { VectorPlaneApiClient } from "./api.js";
2
2
  import type { Logger } from "./logger.js";
3
- export type SupportedAgent = "claude" | "cursor" | "windsurf" | "copilot" | "codex" | "generic";
4
- export type DetectionConfidence = "high" | "medium" | "low";
5
- export interface AgentDetectionResult {
6
- selected: SupportedAgent | null;
7
- confidence: DetectionConfidence;
8
- reasons: string[];
9
- candidates: SupportedAgent[];
10
- }
11
- export declare function detectAgentRuntime(rootPath: string): Promise<AgentDetectionResult>;
12
- export declare function resolveAgentSelection(rootPath: string, explicitAgent?: SupportedAgent): Promise<{
13
- agent: SupportedAgent;
14
- detection: AgentDetectionResult;
15
- }>;
3
+ import { type DetectionConfidence, type SupportedAgent } from "./agent-runtime-detection.js";
16
4
  export declare function ensureAgentSetupCurrent(params: {
17
5
  rootPath: string;
18
6
  workspace: string;
@@ -1,9 +1,9 @@
1
1
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { constants as fsConstants } from "node:fs";
3
3
  import path from "node:path";
4
- import readline from "node:readline/promises";
5
4
  import { ValidationError } from "./errors.js";
6
5
  import { bindWorkspaceToRoot, getWorkspaceBinding } from "./workspace-binding.js";
6
+ import { detectAgentRuntime, resolveAgentSelection, } from "./agent-runtime-detection.js";
7
7
  const AGENT_TEMPLATE_PATHS = {
8
8
  claude: "CLAUDE.md",
9
9
  cursor: ".cursor/rules/traceplane.mdc",
@@ -21,92 +21,6 @@ async function pathExists(filePath) {
21
21
  return false;
22
22
  }
23
23
  }
24
- function uniqueAgents(values) {
25
- return [...new Set(values)];
26
- }
27
- export async function detectAgentRuntime(rootPath) {
28
- const scores = new Map();
29
- const reasons = new Map();
30
- const addScore = (agent, amount, reason) => {
31
- scores.set(agent, (scores.get(agent) ?? 0) + amount);
32
- reasons.set(agent, [...(reasons.get(agent) ?? []), reason]);
33
- };
34
- const fileCandidates = [
35
- { agent: "claude", file: path.join(rootPath, "CLAUDE.md") },
36
- { agent: "cursor", file: path.join(rootPath, ".cursor") },
37
- { agent: "windsurf", file: path.join(rootPath, ".windsurfrules") },
38
- { agent: "copilot", file: path.join(rootPath, ".github", "copilot-instructions.md") },
39
- { agent: "codex", file: path.join(rootPath, "AGENTS.md") },
40
- ];
41
- for (const candidate of fileCandidates) {
42
- if (await pathExists(candidate.file)) {
43
- addScore(candidate.agent, 25, `file:${path.relative(rootPath, candidate.file) || candidate.file}`);
44
- }
45
- }
46
- const envSignals = [
47
- { agent: "cursor", value: process.env.CURSOR_TRACE_ID, reason: "env:CURSOR_TRACE_ID" },
48
- { agent: "windsurf", value: process.env.WINDSURF_SESSION_ID, reason: "env:WINDSURF_SESSION_ID" },
49
- { agent: "codex", value: process.env.CODEX_ENV, reason: "env:CODEX_ENV" },
50
- { agent: "claude", value: process.env.CLAUDECODE, reason: "env:CLAUDECODE" },
51
- { agent: "copilot", value: process.env.GITHUB_COPILOT, reason: "env:GITHUB_COPILOT" },
52
- ];
53
- for (const signal of envSignals) {
54
- if (signal.value) {
55
- addScore(signal.agent, 100, signal.reason);
56
- }
57
- }
58
- const ranked = [...scores.entries()].sort((left, right) => right[1] - left[1]);
59
- if (ranked.length === 0) {
60
- return {
61
- selected: null,
62
- confidence: "low",
63
- reasons: [],
64
- candidates: [],
65
- };
66
- }
67
- const topScore = ranked[0][1];
68
- const candidates = uniqueAgents(ranked.filter((entry) => entry[1] === topScore).map(([agent]) => agent));
69
- const selected = candidates.length === 1 ? candidates[0] : null;
70
- return {
71
- selected,
72
- confidence: topScore >= 100 ? "high" : candidates.length === 1 ? "medium" : "low",
73
- reasons: selected ? (reasons.get(selected) ?? []) : candidates.flatMap((agent) => reasons.get(agent) ?? []),
74
- candidates,
75
- };
76
- }
77
- async function promptForAgent(detection) {
78
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
79
- throw new ValidationError("Não foi possível detectar o agente local com segurança. Use --agent claude|cursor|windsurf|copilot|codex|generic.");
80
- }
81
- const ordered = uniqueAgents([
82
- ...detection.candidates,
83
- "claude",
84
- "cursor",
85
- "windsurf",
86
- "copilot",
87
- "codex",
88
- "generic",
89
- ]);
90
- process.stdout.write("VectorPlane: não foi possível identificar o agente local com segurança.\n");
91
- ordered.forEach((agent, index) => {
92
- process.stdout.write(` ${index + 1}. ${agent}\n`);
93
- });
94
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
95
- try {
96
- const answer = (await rl.question("Selecione o agente local: ")).trim();
97
- const index = Number(answer);
98
- if (Number.isInteger(index) && index >= 1 && index <= ordered.length) {
99
- return ordered[index - 1];
100
- }
101
- if (ordered.includes(answer)) {
102
- return answer;
103
- }
104
- }
105
- finally {
106
- rl.close();
107
- }
108
- throw new ValidationError("Seleção de agente inválida.");
109
- }
110
24
  async function appendGitIgnoreEntry(rootPath, relativeTarget) {
111
25
  const gitIgnorePath = path.join(rootPath, ".gitignore");
112
26
  const normalizedEntry = relativeTarget.replace(/\\/g, "/");
@@ -143,27 +57,6 @@ function getAgentTemplate(setup, agent) {
143
57
  }
144
58
  return template;
145
59
  }
146
- export async function resolveAgentSelection(rootPath, explicitAgent) {
147
- if (explicitAgent) {
148
- return {
149
- agent: explicitAgent,
150
- detection: {
151
- selected: explicitAgent,
152
- confidence: "high",
153
- reasons: ["explicit-flag"],
154
- candidates: [explicitAgent],
155
- },
156
- };
157
- }
158
- const detection = await detectAgentRuntime(rootPath);
159
- if (detection.selected && detection.confidence !== "low") {
160
- return { agent: detection.selected, detection };
161
- }
162
- return {
163
- agent: await promptForAgent(detection),
164
- detection,
165
- };
166
- }
167
60
  export async function ensureAgentSetupCurrent(params) {
168
61
  const binding = await getWorkspaceBinding(params.rootPath);
169
62
  let selection;
@@ -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, ResolveWorkspaceRequest, ResolveWorkspaceResponse, SyncRequest, SyncResponse, WorkspaceAgentSetup } 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,13 +20,125 @@ 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>>;
28
+ getWorkspaceDeliveryContextSemantic(accessToken: string, workspaceId: string, params: {
29
+ query: string;
30
+ type?: string;
31
+ authority?: string;
32
+ limit?: number;
33
+ }): Promise<Record<string, unknown>>;
24
34
  getAgentSetup(accessToken: string, workspaceId: string): Promise<WorkspaceAgentSetup>;
35
+ listWorkspacePolicyRules(accessToken: string, workspaceRef: string): Promise<WorkspacePolicyRuleRecord[]>;
36
+ createWorkspacePolicyRule(accessToken: string, workspaceRef: string, payload: {
37
+ name: string;
38
+ pathPrefix?: string;
39
+ capability?: string;
40
+ effect: WorkspacePolicyRuleRecord["effect"];
41
+ rationale?: string;
42
+ conditions?: WorkspacePolicyRuleRecord["conditions"];
43
+ approvalRole?: string;
44
+ enabled?: boolean;
45
+ }): Promise<WorkspacePolicyRuleRecord>;
46
+ updateWorkspacePolicyRule(accessToken: string, workspaceRef: string, ruleId: string, payload: {
47
+ name?: string;
48
+ pathPrefix?: string | null;
49
+ capability?: string | null;
50
+ effect?: WorkspacePolicyRuleRecord["effect"];
51
+ rationale?: string | null;
52
+ conditions?: WorkspacePolicyRuleRecord["conditions"] | null;
53
+ approvalRole?: string | null;
54
+ enabled?: boolean;
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
+ }>;
25
68
  listMemoryDrafts(accessToken: string, workspaceRef: string, status?: MemoryDraftStatus): Promise<MemoryDraftRecord[]>;
26
69
  createMemoryDraft(accessToken: string, workspaceRef: string, payload: MemoryDraftCreateRequest): Promise<MemoryDraftRecord>;
70
+ searchWorkspaceMemory(accessToken: string, workspaceRef: string, params: {
71
+ query: string;
72
+ type?: string;
73
+ authority?: string;
74
+ limit?: number;
75
+ }): Promise<MemorySearchRecord[]>;
76
+ listTasks(accessToken: string, workspaceRef: string): Promise<TaskRecord[]>;
77
+ createTask(accessToken: string, workspaceRef: string, payload: TaskCreateRequest): Promise<TaskRecord>;
78
+ listTaskTemplates(accessToken: string): Promise<TaskTemplateRecord[]>;
79
+ getTask(accessToken: string, workspaceRef: string, taskId: string): Promise<TaskRecord>;
80
+ listClaimableTaskSteps(accessToken: string, workspaceRef: string, filters?: {
81
+ capability?: string;
82
+ agentName?: string;
83
+ }): Promise<ClaimableTaskStepRecord[]>;
84
+ claimTaskStep(accessToken: string, workspaceRef: string, taskId: string, stepId: string, payload?: {
85
+ sessionId?: string;
86
+ clientInstanceId?: string;
87
+ agentName?: string;
88
+ }): Promise<ClaimedTaskStepResponse>;
89
+ delegateTask(accessToken: string, workspaceRef: string, taskId: string, stepId: string, toAgentId: string, reason: string): Promise<TaskRecord>;
90
+ callbackTaskStep(accessToken: string, workspaceRef: string, taskId: string, stepId: string, payload: {
91
+ status: "running" | "completed" | "failed" | "blocked";
92
+ agentId?: string;
93
+ output?: Record<string, unknown>;
94
+ error?: string;
95
+ }): Promise<TaskRecord>;
96
+ getTaskHandoff(accessToken: string, workspaceRef: string, taskId: string): Promise<TaskHandoffRecord>;
97
+ getTaskObservability(accessToken: string, workspaceRef: string, taskId: string): Promise<TaskObservabilityRecord>;
98
+ getWorkspaceTaskObservability(accessToken: string, workspaceRef: string): Promise<TaskObservabilityRecord>;
99
+ approveTask(accessToken: string, workspaceRef: string, taskId: string, payload: {
100
+ approved: boolean;
101
+ approvedBy?: string;
102
+ rationale?: string;
103
+ }): Promise<TaskRecord>;
104
+ listAgentRegistry(accessToken: string): Promise<AgentRegistryRecord[]>;
105
+ createRegistryAgent(accessToken: string, payload: {
106
+ orgId?: string;
107
+ name: string;
108
+ runtimeType: string;
109
+ provider: string;
110
+ model: string;
111
+ capabilities: string[];
112
+ costProfile: string;
113
+ latencyProfile: string;
114
+ reliabilityScore: number;
115
+ status?: string;
116
+ metadata?: Record<string, unknown>;
117
+ }): Promise<AgentRegistryRecord>;
118
+ updateRegistryAgent(accessToken: string, agentId: string, payload: {
119
+ name?: string;
120
+ provider?: string;
121
+ model?: string;
122
+ capabilities?: string[];
123
+ costProfile?: string;
124
+ latencyProfile?: string;
125
+ reliabilityScore?: number;
126
+ status?: string;
127
+ metadata?: Record<string, unknown>;
128
+ }): Promise<AgentRegistryRecord>;
129
+ deactivateRegistryAgent(accessToken: string, agentId: string): Promise<{
130
+ deactivated: boolean;
131
+ }>;
132
+ getWorkspaceHealth(accessToken: string, workspaceRef: string): Promise<Record<string, unknown>>;
27
133
  checkInAgent(accessToken: string, payload: AgentSessionRequest): Promise<AgentSessionResponse>;
28
134
  heartbeatAgent(accessToken: string, payload: AgentHeartbeatRequest): Promise<AgentSessionResponse>;
29
135
  checkOutAgent(accessToken: string, payload: AgentCheckoutRequest): Promise<AgentSessionResponse>;
30
136
  getHealth(): Promise<Record<string, unknown>>;
31
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>;
32
144
  }