biaws 0.2.2 → 0.3.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/README.md CHANGED
@@ -122,6 +122,7 @@ biaws workspace api PATCH /recurso/ID --body '{"status":"Ativo"}'
122
122
  ```bash
123
123
  biaws workspace agent configure codex
124
124
  biaws workspace agent configure claude
125
+ biaws workspace agent configure codex --no-interactive --env-file /caminho/instancia.env --workspace workspace-id
125
126
  biaws workspace agent doctor codex
126
127
  biaws workspace skills list
127
128
  biaws workspace skills install SKILL_ID
@@ -61,9 +61,8 @@ flags > variáveis de ambiente > configuração da pasta > perfil global > defau
61
61
  ```
62
62
 
63
63
  As variáveis canônicas são `BIAWS_API_URL`, `BIAWS_API_KEY` e
64
- `BIAWS_WORKSPACE_ID`. Os nomes `ISSUE_*` permanecem aceitos como variáveis de
65
- ambiente internas durante a transição do backend, mas não representam comandos
66
- antigos do CLI.
64
+ `BIAWS_WORKSPACE_ID`. Variáveis com o prefixo temporário anterior não são
65
+ aceitas como aliases.
67
66
 
68
67
  ## Convenções
69
68
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "biaws",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "CLI do Bondia Workspaces para administração, configuração e operação de workspaces",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -4,6 +4,7 @@ import { AuthenticatedApiCommand, ProjectCommand } from "./baseCommands.js";
4
4
  import {
5
5
  configureContextFlags,
6
6
  configureContextInput,
7
+ interactiveConfigureInput,
7
8
  legacyAgentContext,
8
9
  } from "./configure/command.js";
9
10
  import { runAgentCommand } from "./commands/agent.js";
@@ -85,12 +86,21 @@ export function createAgentCommand(action) {
85
86
 
86
87
  async run() {
87
88
  const { args, flags } = await this.parse(this.constructor);
88
- const context = await this.projectContext(configureContextInput(flags));
89
+ const input =
90
+ action === "configure"
91
+ ? await interactiveConfigureInput(this, flags)
92
+ : configureContextInput(flags);
93
+ const context = await this.projectContext(input);
89
94
  await runAgentCommand(
90
95
  context.api,
91
96
  action,
92
97
  [args.client],
93
- { ...flags, project: context.projectDirectory },
98
+ {
99
+ ...flags,
100
+ interactive: input.interactive,
101
+ project: context.projectDirectory,
102
+ prompts: this.adapters.prompts,
103
+ },
94
104
  legacyAgentContext(context),
95
105
  );
96
106
  }
@@ -4,13 +4,14 @@ import path from "node:path";
4
4
 
5
5
  import { BaseCommand, TOOL_DIRECTORY } from "../baseCommands.js";
6
6
  import { showTopic } from "../commandFactories.js";
7
+ import { CliError } from "../core/errors.js";
7
8
  import { readLock } from "../localSkills.js";
8
9
  import { runSkillsCommand } from "./skills.js";
9
10
 
10
11
  const CODEX_BEGIN = "# BEGIN BIAWS MANAGED MCP";
11
12
  const CODEX_END = "# END BIAWS MANAGED MCP";
12
13
  export const MCP_PACKAGE_NAME = "biaws-mcp";
13
- export const MCP_PACKAGE_VERSION = "0.1.0";
14
+ export const MCP_PACKAGE_VERSION = "0.2.0";
14
15
  export const MCP_PACKAGE_SPEC = `${MCP_PACKAGE_NAME}@${MCP_PACKAGE_VERSION}`;
15
16
  const MCP_COMMAND = "npx";
16
17
  const MCP_ARGS = ["--yes", MCP_PACKAGE_SPEC];
@@ -75,7 +76,7 @@ async function writeCodexConfiguration(
75
76
  [mcp_servers.biaws]
76
77
  command = ${JSON.stringify(MCP_COMMAND)}
77
78
  args = ${JSON.stringify(MCP_ARGS)}
78
- env = {${envFile ? ` BIAWS_ENV_FILE = ${JSON.stringify(envFile)},` : ""} ISSUE_WORKSPACE_ID = ${JSON.stringify(workspaceId)} }
79
+ env = {${envFile ? ` BIAWS_ENV_FILE = ${JSON.stringify(envFile)},` : ""} BIAWS_WORKSPACE_ID = ${JSON.stringify(workspaceId)} }
79
80
  ${CODEX_END}
80
81
  `;
81
82
  const output = current ? `${current}\n\n${managed}` : managed;
@@ -113,14 +114,19 @@ async function writeClaudeConfiguration(
113
114
  args: MCP_ARGS,
114
115
  env: {
115
116
  ...(envFile ? { BIAWS_ENV_FILE: envFile } : {}),
116
- ISSUE_WORKSPACE_ID: workspaceId,
117
+ BIAWS_WORKSPACE_ID: workspaceId,
117
118
  },
118
119
  };
119
120
  await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
120
121
  return configPath;
121
122
  }
122
123
 
123
- async function resolveWorkspaceId(api, requestedWorkspaceId = "") {
124
+ async function resolveWorkspaceId(
125
+ api,
126
+ requestedWorkspaceId = "",
127
+ interactive = false,
128
+ prompts,
129
+ ) {
124
130
  let identity;
125
131
  try {
126
132
  identity = await api.identity();
@@ -132,7 +138,22 @@ async function resolveWorkspaceId(api, requestedWorkspaceId = "") {
132
138
  }
133
139
  throw error;
134
140
  }
135
- const workspaceId = requestedWorkspaceId || identity?.actor?.workspaceId;
141
+ const workspaces = identity?.actor?.workspaces || [];
142
+ let workspaceId = requestedWorkspaceId || identity?.actor?.workspaceId;
143
+ if (interactive && workspaces.length > 0) {
144
+ workspaceId = await prompts.ask({
145
+ name: "workspaceId",
146
+ type: "select",
147
+ message: "Workspace do projeto",
148
+ choices: workspaces.map((workspace) => ({
149
+ name: workspace.name
150
+ ? `${workspace.name} (${workspace.id})`
151
+ : workspace.id,
152
+ value: workspace.id,
153
+ })),
154
+ ...(workspaceId ? { default: workspaceId } : {}),
155
+ });
156
+ }
136
157
  if (!workspaceId) {
137
158
  if ((identity?.actor?.workspaces?.length || 0) > 1) {
138
159
  throw new Error(
@@ -153,7 +174,29 @@ async function configure(api, client, options, context) {
153
174
  );
154
175
  }
155
176
  const projectDirectory = path.resolve(options.project || process.cwd());
156
- const { workspaceId } = await resolveWorkspaceId(api, context.workspaceId);
177
+ const { workspaceId } = await resolveWorkspaceId(
178
+ api,
179
+ context.workspaceId,
180
+ options.interactive,
181
+ options.prompts,
182
+ );
183
+ if (options.interactive) {
184
+ const confirmed = await options.prompts.ask({
185
+ name: "confirmConfiguration",
186
+ type: "confirm",
187
+ message: `Configurar ${client} em ${projectDirectory} para o workspace ${workspaceId}?`,
188
+ default: true,
189
+ });
190
+ if (!confirmed) {
191
+ throw new CliError(
192
+ "Configuração cancelada antes de qualquer alteração.",
193
+ {
194
+ code: "PROMPT_CANCELLED",
195
+ exitCode: 130,
196
+ },
197
+ );
198
+ }
199
+ }
157
200
  const target = skillTarget(client, projectDirectory);
158
201
  const configPath =
159
202
  client === "codex"
@@ -213,7 +256,7 @@ async function mcpStatus(envFile, workspaceId) {
213
256
  env: {
214
257
  ...process.env,
215
258
  ...(envFile ? { BIAWS_ENV_FILE: envFile } : {}),
216
- ISSUE_WORKSPACE_ID: workspaceId,
259
+ BIAWS_WORKSPACE_ID: workspaceId,
217
260
  },
218
261
  });
219
262
  let output = "";
@@ -302,7 +345,7 @@ function configurationStatus(client, contents, envFile, workspaceId) {
302
345
  contents.includes(`command = ${JSON.stringify(MCP_COMMAND)}`) &&
303
346
  contents.includes(`args = ${JSON.stringify(MCP_ARGS)}`) &&
304
347
  (!envFile || contents.includes(JSON.stringify(envFile))) &&
305
- contents.includes(`ISSUE_WORKSPACE_ID = ${JSON.stringify(workspaceId)}`);
348
+ contents.includes(`BIAWS_WORKSPACE_ID = ${JSON.stringify(workspaceId)}`);
306
349
  return {
307
350
  ok,
308
351
  detail: ok
@@ -316,7 +359,7 @@ function configurationStatus(client, contents, envFile, workspaceId) {
316
359
  server?.command === MCP_COMMAND &&
317
360
  JSON.stringify(server.args || []) === JSON.stringify(MCP_ARGS) &&
318
361
  (!envFile || server.env?.BIAWS_ENV_FILE === envFile) &&
319
- server.env?.ISSUE_WORKSPACE_ID === workspaceId;
362
+ server.env?.BIAWS_WORKSPACE_ID === workspaceId;
320
363
  return {
321
364
  ok,
322
365
  detail: ok
@@ -1,7 +1,7 @@
1
1
  import { ProjectCommand } from "../../baseCommands.js";
2
2
  import {
3
3
  configureContextFlags,
4
- configureContextInput,
4
+ interactiveConfigureInput,
5
5
  legacyAgentContext,
6
6
  } from "../../configure/command.js";
7
7
  import { runAgentCommand } from "../agent.js";
@@ -13,12 +13,18 @@ export default class ConfigureClaude extends ProjectCommand {
13
13
 
14
14
  async run() {
15
15
  const { flags } = await this.parse(ConfigureClaude);
16
- const context = await this.projectContext(configureContextInput(flags));
16
+ const input = await interactiveConfigureInput(this, flags);
17
+ const context = await this.projectContext(input);
17
18
  await runAgentCommand(
18
19
  context.api,
19
20
  "configure",
20
21
  ["claude"],
21
- { ...flags, project: context.projectDirectory },
22
+ {
23
+ ...flags,
24
+ interactive: input.interactive,
25
+ project: context.projectDirectory,
26
+ prompts: this.adapters.prompts,
27
+ },
22
28
  legacyAgentContext(context),
23
29
  );
24
30
  }
@@ -1,7 +1,7 @@
1
1
  import { ProjectCommand } from "../../baseCommands.js";
2
2
  import {
3
3
  configureContextFlags,
4
- configureContextInput,
4
+ interactiveConfigureInput,
5
5
  legacyAgentContext,
6
6
  } from "../../configure/command.js";
7
7
  import { runAgentCommand } from "../agent.js";
@@ -13,12 +13,18 @@ export default class ConfigureCodex extends ProjectCommand {
13
13
 
14
14
  async run() {
15
15
  const { flags } = await this.parse(ConfigureCodex);
16
- const context = await this.projectContext(configureContextInput(flags));
16
+ const input = await interactiveConfigureInput(this, flags);
17
+ const context = await this.projectContext(input);
17
18
  await runAgentCommand(
18
19
  context.api,
19
20
  "configure",
20
21
  ["codex"],
21
- { ...flags, project: context.projectDirectory },
22
+ {
23
+ ...flags,
24
+ interactive: input.interactive,
25
+ project: context.projectDirectory,
26
+ prompts: this.adapters.prompts,
27
+ },
22
28
  legacyAgentContext(context),
23
29
  );
24
30
  }
@@ -52,7 +52,7 @@ function credentialsWithKey(configuration, name, apiKey) {
52
52
  async function requiredApiKey(command) {
53
53
  const fromEnvironment = String(
54
54
  command.adapters.environment.BIAWS_API_KEY ||
55
- command.adapters.environment.ISSUE_API_KEY ||
55
+ command.adapters.environment.BIAWS_API_KEY ||
56
56
  "",
57
57
  ).trim();
58
58
  if (fromEnvironment) return fromEnvironment;
@@ -2,6 +2,8 @@ import path from "node:path";
2
2
 
3
3
  import { Args, Flags } from "@oclif/core";
4
4
 
5
+ import { CliError } from "../core/errors.js";
6
+
5
7
  export const configureContextFlags = Object.freeze({
6
8
  project: Flags.string({
7
9
  char: "p",
@@ -16,6 +18,12 @@ export const configureContextFlags = Object.freeze({
16
18
  "env-file": Flags.string({
17
19
  description: "arquivo privado com URL e chave de API",
18
20
  }),
21
+ interactive: Flags.boolean({
22
+ char: "i",
23
+ allowNo: true,
24
+ description:
25
+ "usa o modo assistente (padrão em terminais; use --no-interactive para desativar)",
26
+ }),
19
27
  force: Flags.boolean({
20
28
  char: "f",
21
29
  description: "substitui somente a configuração BIAWS conflitante",
@@ -23,6 +31,46 @@ export const configureContextFlags = Object.freeze({
23
31
  json: Flags.boolean({ description: "emite somente JSON em stdout" }),
24
32
  });
25
33
 
34
+ export async function interactiveConfigureInput(command, flags) {
35
+ const interactive =
36
+ flags.interactive === true ||
37
+ (flags.interactive !== false && command.adapters.terminal.isInteractive);
38
+ if (!interactive) {
39
+ return { ...configureContextInput(flags), interactive: false };
40
+ }
41
+ if (!command.adapters.prompts.isInteractive) {
42
+ throw new CliError("O modo assistente exige um terminal interativo.", {
43
+ code: "INTERACTIVE_INPUT_UNAVAILABLE",
44
+ exitCode: 2,
45
+ });
46
+ }
47
+ const project = String(
48
+ await command.adapters.prompts.ask({
49
+ name: "project",
50
+ message: "Diretório do projeto",
51
+ default: flags.project || command.adapters.cwd(),
52
+ }),
53
+ ).trim();
54
+ const envFile = String(
55
+ await command.adapters.prompts.ask({
56
+ name: "envFile",
57
+ message: "Arquivo privado da instância (BIAWS_ENV_FILE)",
58
+ default:
59
+ flags["env-file"] || command.adapters.environment.BIAWS_ENV_FILE || "",
60
+ }),
61
+ ).trim();
62
+ if (!envFile) {
63
+ throw new CliError("Informe o arquivo privado da instância.", {
64
+ code: "ENV_FILE_REQUIRED",
65
+ exitCode: 2,
66
+ });
67
+ }
68
+ return {
69
+ ...configureContextInput({ ...flags, project, "env-file": envFile }),
70
+ interactive: true,
71
+ };
72
+ }
73
+
26
74
  export const clientArgument = Args.string({
27
75
  description: "cliente a diagnosticar",
28
76
  options: ["codex", "claude"],
@@ -126,32 +126,31 @@ export async function resolveCommandContext(options) {
126
126
  const configuredApiUrl =
127
127
  input.apiUrl ||
128
128
  explicitFileEnv.BIAWS_API_URL ||
129
- explicitFileEnv.ISSUE_API_URL ||
129
+ explicitFileEnv.BIAWS_API_URL ||
130
+ environment.BIAWS_API_URL ||
130
131
  environment.BIAWS_API_URL ||
131
- environment.ISSUE_API_URL ||
132
- environment.ISSUE_API_BASE_URL ||
132
+ environment.BIAWS_API_BASE_URL ||
133
133
  workspaceConfiguration.apiUrl ||
134
134
  profile.config.apiUrl ||
135
- effectiveEnv.ISSUE_API_URL ||
136
- effectiveEnv.ISSUE_API_BASE_URL ||
135
+ effectiveEnv.BIAWS_API_URL ||
136
+ effectiveEnv.BIAWS_API_BASE_URL ||
137
137
  DEFAULT_API_URL;
138
138
  const configuredApiKey = String(
139
139
  input.apiKey ||
140
140
  explicitFileEnv.BIAWS_API_KEY ||
141
- explicitFileEnv.ISSUE_API_KEY ||
141
+ explicitFileEnv.BIAWS_API_KEY ||
142
+ environment.BIAWS_API_KEY ||
142
143
  environment.BIAWS_API_KEY ||
143
- environment.ISSUE_API_KEY ||
144
144
  profile.credentials.apiKey ||
145
- effectiveEnv.ISSUE_API_KEY ||
145
+ effectiveEnv.BIAWS_API_KEY ||
146
146
  "",
147
147
  );
148
148
  const configuredWorkspaceId = String(
149
149
  input.workspaceId ||
150
150
  input.workspace ||
151
151
  environment.BIAWS_WORKSPACE_ID ||
152
- environment.ISSUE_WORKSPACE_ID ||
153
152
  workspaceConfiguration.workspaceId ||
154
- effectiveEnv.ISSUE_WORKSPACE_ID ||
153
+ effectiveEnv.BIAWS_WORKSPACE_ID ||
155
154
  "",
156
155
  ).trim();
157
156
 
@@ -6,8 +6,8 @@ import { parseEnv } from "../core/context.js";
6
6
 
7
7
  const PORT_FIELDS = Object.freeze({
8
8
  mongoPort: "MONGO_PORT",
9
- apiPort: "ISSUE_API_PORT",
10
- uiPort: "ISSUE_UI_PORT",
9
+ apiPort: "BIAWS_API_PORT",
10
+ uiPort: "BIAWS_UI_PORT",
11
11
  });
12
12
 
13
13
  const STORAGE_FIELDS = Object.freeze({
@@ -143,11 +143,11 @@ export async function listInstances(context, filesystem) {
143
143
  directory,
144
144
  envFile: path.join(directory, ".env"),
145
145
  mongoPort: Number(env.MONGO_PORT || 27_017),
146
- apiPort: Number(env.ISSUE_API_PORT || 3_100),
147
- uiPort: Number(env.ISSUE_UI_PORT || 4_400),
146
+ apiPort: Number(env.BIAWS_API_PORT || 3_100),
147
+ uiPort: Number(env.BIAWS_UI_PORT || 4_400),
148
148
  publicUrl:
149
149
  env.BIAWS_PUBLIC_URL ||
150
- `http://localhost:${env.ISSUE_UI_PORT || 4_400}`,
150
+ `http://localhost:${env.BIAWS_UI_PORT || 4_400}`,
151
151
  storage: Object.values(STORAGE_FIELDS).some((key) => env[key])
152
152
  ? "directories"
153
153
  : "volumes",