@mcp-graph-workflow/agent-graph-flow 0.3.0 → 0.5.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.
Files changed (2) hide show
  1. package/dist/cli/index.js +301 -96
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -13,7 +13,7 @@ import { stat, readFile, access, constants } from 'fs/promises';
13
13
  import { execFile, execSync, spawn } from 'child_process';
14
14
  import { render, useApp, useInput, Box, Text } from 'ink';
15
15
  import { jsx, jsxs } from 'react/jsx-runtime';
16
- import { createElement, useState, useCallback, useEffect } from 'react';
16
+ import { createElement, useState, useEffect, useRef, useCallback } from 'react';
17
17
  import TextInput from 'ink-text-input';
18
18
  import Spinner from 'ink-spinner';
19
19
  import { Command } from 'commander';
@@ -6370,6 +6370,9 @@ async function runAutopilot(port, options) {
6370
6370
  options.onStep?.(step);
6371
6371
  };
6372
6372
  for (let i = 0; i < options.maxIterations; i++) {
6373
+ if (options.signal?.aborted === true) {
6374
+ return { steps, completed, escalated, stopped: "aborted" };
6375
+ }
6373
6376
  const next = port.nextTask();
6374
6377
  if (next === null) {
6375
6378
  return { steps, completed, escalated, stopped: "no_more_tasks" };
@@ -7091,8 +7094,8 @@ var init_implementation_executor = __esm({
7091
7094
  };
7092
7095
  defaultRunner = (command, cwd) => {
7093
7096
  try {
7094
- const output16 = execSync(command, { cwd, encoding: "utf8", stdio: "pipe" });
7095
- return { exitCode: 0, output: output16 };
7097
+ const output17 = execSync(command, { cwd, encoding: "utf8", stdio: "pipe" });
7098
+ return { exitCode: 0, output: output17 };
7096
7099
  } catch (err) {
7097
7100
  const e = err;
7098
7101
  return {
@@ -7320,7 +7323,12 @@ async function attemptImplementation(deps, options) {
7320
7323
  lastResult = await deps.execute(plan);
7321
7324
  if (lastResult.testPassed === true) {
7322
7325
  log25.info("Implementa\xE7\xE3o verde", { attempt, node: options.node.id });
7323
- return { success: true, attempts: attempt, lastResult };
7326
+ const appliedEdits = (plan.edits ?? []).map((e) => ({
7327
+ path: e.path,
7328
+ oldString: e.oldString,
7329
+ newString: e.newString
7330
+ }));
7331
+ return { success: true, attempts: attempt, lastResult, appliedEdits };
7324
7332
  }
7325
7333
  lastError = lastResult.testOutput;
7326
7334
  log25.warn("Testes vermelhos", { attempt, node: options.node.id });
@@ -7341,6 +7349,79 @@ var init_implement_attempt = __esm({
7341
7349
  }
7342
7350
  });
7343
7351
 
7352
+ // src/core/autonomy/exec-policy.ts
7353
+ function norm(cmd) {
7354
+ return cmd.trim().replace(/\s+/g, " ");
7355
+ }
7356
+ function evaluateExecPolicy(command, rules, defaultEffect = "ask") {
7357
+ const cmd = norm(command);
7358
+ let best;
7359
+ for (const rule of rules) {
7360
+ const m = norm(rule.match);
7361
+ if (cmd === m || cmd.startsWith(m + " ") || cmd.startsWith(m)) {
7362
+ if (!best || m.length > norm(best.match).length) best = rule;
7363
+ }
7364
+ }
7365
+ if (best) return { effect: best.effect, matchedRule: best };
7366
+ const low = cmd.toLowerCase();
7367
+ for (const danger of DEFAULT_DENY) {
7368
+ if (low.includes(danger)) return { effect: "deny", builtin: true };
7369
+ }
7370
+ return { effect: defaultEffect };
7371
+ }
7372
+ function guardExecRunner(base, opts = {}) {
7373
+ const rules = opts.rules ?? [];
7374
+ const defaultEffect = opts.defaultEffect ?? "ask";
7375
+ return (command, cwd) => {
7376
+ const decision = evaluateExecPolicy(command, rules, defaultEffect);
7377
+ const allowed = decision.effect === "allow" || decision.effect === "ask" && opts.cache?.isApproved(command) === true;
7378
+ if (allowed) return base(command, cwd);
7379
+ const reason = decision.effect === "deny" ? decision.builtin ? "deny (built-in perigoso)" : "deny (regra)" : "ask (n\xE3o aprovado nesta sess\xE3o)";
7380
+ return { exitCode: 126, output: `[exec-policy] comando bloqueado \u2014 ${reason}: ${command}` };
7381
+ };
7382
+ }
7383
+ var DEFAULT_DENY;
7384
+ var init_exec_policy = __esm({
7385
+ "src/core/autonomy/exec-policy.ts"() {
7386
+ init_esm_shims();
7387
+ DEFAULT_DENY = [
7388
+ "rm -rf",
7389
+ "sudo ",
7390
+ "git push --force",
7391
+ "git push -f",
7392
+ "chmod -R 777",
7393
+ "chmod 777",
7394
+ "dd if=",
7395
+ ":(){",
7396
+ "mkfs",
7397
+ "| sh",
7398
+ "|sh",
7399
+ "| bash",
7400
+ "> /dev/sd"
7401
+ ];
7402
+ }
7403
+ });
7404
+
7405
+ // src/tui/diff-render.ts
7406
+ function renderEditDiff(edit) {
7407
+ const lines = [`\u2500\u2500 ${edit.path} \u2500\u2500`];
7408
+ if (edit.oldString.length > 0) {
7409
+ for (const l of edit.oldString.split("\n")) lines.push(`- ${l}`);
7410
+ }
7411
+ if (edit.newString.length > 0) {
7412
+ for (const l of edit.newString.split("\n")) lines.push(`+ ${l}`);
7413
+ }
7414
+ return lines;
7415
+ }
7416
+ function renderPlanDiff(edits) {
7417
+ return edits.flatMap(renderEditDiff);
7418
+ }
7419
+ var init_diff_render = __esm({
7420
+ "src/tui/diff-render.ts"() {
7421
+ init_esm_shims();
7422
+ }
7423
+ });
7424
+
7344
7425
  // src/core/code/code-store.ts
7345
7426
  function rowToSymbol(row) {
7346
7427
  return {
@@ -8582,6 +8663,18 @@ function buildLiveImplement(options) {
8582
8663
  onLog?.(`[live] provider: ${resolved.kind === "api" ? "Copilot API (HTTP, logado)" : "Copilot CLI"}`);
8583
8664
  const client = new TieredModelClient(resolved.adapter, config);
8584
8665
  const maxAttempts = Math.max(1, retries);
8666
+ let execRules = [];
8667
+ let execDefault = "allow";
8668
+ const rawPolicy = store2.getProjectSetting("exec_policy");
8669
+ if (rawPolicy) {
8670
+ try {
8671
+ const parsed = JSON.parse(rawPolicy);
8672
+ if (parsed.default) execDefault = parsed.default;
8673
+ if (Array.isArray(parsed.rules)) execRules = parsed.rules;
8674
+ } catch {
8675
+ }
8676
+ }
8677
+ const guardedRunner = guardExecRunner(defaultRunner, { rules: execRules, defaultEffect: execDefault });
8585
8678
  const codeStore = new CodeStore(store2.getDb());
8586
8679
  const projectId = store2.getProject()?.id;
8587
8680
  const repoSymbols = projectId ? codeStore.getAllSymbols(projectId) : [];
@@ -8609,7 +8702,7 @@ function buildLiveImplement(options) {
8609
8702
  });
8610
8703
  return res.text;
8611
8704
  },
8612
- execute: (plan) => executePlan(plan, { workspaceDir: dir, defaultTestCommand: testCmd })
8705
+ execute: (plan) => executePlan(plan, { workspaceDir: dir, defaultTestCommand: testCmd, runCommand: guardedRunner })
8613
8706
  },
8614
8707
  { node, maxAttempts, repoMap, flowContext }
8615
8708
  );
@@ -8618,6 +8711,9 @@ function buildLiveImplement(options) {
8618
8711
  onLog?.(
8619
8712
  ` [live] ${client.modelFor("implement")}: ${outcome.attempts} tentativa(s), ${files} arquivo(s), ${task.total} tok \u2192 ${outcome.success ? "verde" : "escala"}`
8620
8713
  );
8714
+ if (outcome.success && outcome.appliedEdits && outcome.appliedEdits.length > 0) {
8715
+ for (const line of renderPlanDiff(outcome.appliedEdits)) onLog?.(line);
8716
+ }
8621
8717
  try {
8622
8718
  const applied = outcome.lastResult?.applied ?? [];
8623
8719
  insertEpisodicOutcome(store2.getDb(), {
@@ -8645,6 +8741,8 @@ var init_live_implement = __esm({
8645
8741
  init_resolve_adapter();
8646
8742
  init_implementation_executor();
8647
8743
  init_implement_attempt();
8744
+ init_exec_policy();
8745
+ init_diff_render();
8648
8746
  init_code_store();
8649
8747
  init_repo_map();
8650
8748
  init_flow_compact();
@@ -8842,6 +8940,22 @@ var init_history = __esm({
8842
8940
  }
8843
8941
  });
8844
8942
 
8943
+ // src/tui/elapsed.ts
8944
+ function formatElapsed(ms) {
8945
+ const totalSec = Math.max(0, Math.floor(ms / 1e3));
8946
+ const h = Math.floor(totalSec / 3600);
8947
+ const m = Math.floor(totalSec % 3600 / 60);
8948
+ const s = totalSec % 60;
8949
+ if (h > 0) return `${h}h ${String(m).padStart(2, "0")}m`;
8950
+ if (m > 0) return `${m}m ${String(s).padStart(2, "0")}s`;
8951
+ return `${s}s`;
8952
+ }
8953
+ var init_elapsed = __esm({
8954
+ "src/tui/elapsed.ts"() {
8955
+ init_esm_shims();
8956
+ }
8957
+ });
8958
+
8845
8959
  // src/tui/dispatch.ts
8846
8960
  function parseCommand(input) {
8847
8961
  const trimmed = input.trim();
@@ -8981,13 +9095,29 @@ function InteractiveApp({ dashboard, port, asyncPort, liveRunner, skillCommands
8981
9095
  const [input, setInput] = useState("");
8982
9096
  const [log48, setLog] = useState([]);
8983
9097
  const [running, setRunning] = useState(false);
9098
+ const [elapsedMs, setElapsedMs] = useState(0);
8984
9099
  const [showHelp, setShowHelp] = useState(false);
9100
+ useEffect(() => {
9101
+ if (!running) return;
9102
+ setElapsedMs(0);
9103
+ const startedAt = Date.now();
9104
+ const t = setInterval(() => setElapsedMs(Date.now() - startedAt), 1e3);
9105
+ return () => clearInterval(t);
9106
+ }, [running]);
8985
9107
  const [history, setHistory] = useState([]);
8986
9108
  const [histCursor, setHistCursor] = useState(-1);
8987
9109
  const [draft, setDraft] = useState("");
9110
+ const abortRef = useRef(null);
8988
9111
  const append = (line) => setLog((prev) => [...prev, line].slice(-MAX_LOG_LINES));
8989
9112
  useInput((_input, key) => {
8990
- if (phase !== "dashboard" || running) return;
9113
+ if (phase === "dashboard" && running) {
9114
+ if (key.escape && abortRef.current) {
9115
+ abortRef.current.abort();
9116
+ append("\u26D4 interrompendo\u2026 (para ap\xF3s o passo atual)");
9117
+ }
9118
+ return;
9119
+ }
9120
+ if (phase !== "dashboard") return;
8991
9121
  if (!key.upArrow && !key.downArrow) return;
8992
9122
  const effectiveDraft = histCursor === -1 ? input : draft;
8993
9123
  if (histCursor === -1) setDraft(input);
@@ -9015,8 +9145,13 @@ function InteractiveApp({ dashboard, port, asyncPort, liveRunner, skillCommands
9015
9145
  if ((parsed.cmd === "run" || parsed.cmd === "autopilot") && liveRunner) {
9016
9146
  append(`\u203A ${text}`);
9017
9147
  setRunning(true);
9018
- const task = parsed.cmd === "run" ? liveRunner.run(parsed.args, append) : liveRunner.autopilot(parseInt(parsed.args, 10) || 5, append);
9019
- task.then((summary) => append(summary)).catch((err) => append(`erro: ${err instanceof Error ? err.message : String(err)}`)).finally(() => setRunning(false));
9148
+ const controller = new AbortController();
9149
+ abortRef.current = controller;
9150
+ const task = parsed.cmd === "run" ? liveRunner.run(parsed.args, append) : liveRunner.autopilot(parseInt(parsed.args, 10) || 5, append, controller.signal);
9151
+ task.then((summary) => append(summary)).catch((err) => append(`erro: ${err instanceof Error ? err.message : String(err)}`)).finally(() => {
9152
+ abortRef.current = null;
9153
+ setRunning(false);
9154
+ });
9020
9155
  return;
9021
9156
  }
9022
9157
  if (ASYNC_CMDS.includes(parsed.cmd) && asyncPort) {
@@ -9054,7 +9189,10 @@ ${skill.body}` : `Skill n\xE3o encontrada: ${parsed.cmd}`);
9054
9189
  ] }),
9055
9190
  running && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
9056
9191
  /* @__PURE__ */ jsx(Spinner, { type: "dots" }),
9057
- " executando\u2026"
9192
+ " executando\u2026 ",
9193
+ formatElapsed(elapsedMs),
9194
+ " \xB7 ",
9195
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Esc para interromper" })
9058
9196
  ] }) }),
9059
9197
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(CommandBar, { value: input, onChange: setInput, onSubmit: submit, suggestions: filterCommands(input, skillCommands) }) })
9060
9198
  ] });
@@ -9067,6 +9205,7 @@ var init_interactive_app = __esm({
9067
9205
  init_banner_screen();
9068
9206
  init_command_bar();
9069
9207
  init_history();
9208
+ init_elapsed();
9070
9209
  init_dispatch();
9071
9210
  MAX_LOG_LINES = 12;
9072
9211
  }
@@ -9717,15 +9856,15 @@ function meanPoolAndNormalize(data, validTokens, dim) {
9717
9856
  embedding[dVar] += data[tVar * dim + dVar];
9718
9857
  }
9719
9858
  }
9720
- let norm = 0;
9859
+ let norm2 = 0;
9721
9860
  for (let dVar = 0; dVar < dim; dVar++) {
9722
9861
  embedding[dVar] /= validTokens;
9723
- norm += embedding[dVar] * embedding[dVar];
9862
+ norm2 += embedding[dVar] * embedding[dVar];
9724
9863
  }
9725
- norm = Math.sqrt(norm);
9726
- if (norm > 0) {
9864
+ norm2 = Math.sqrt(norm2);
9865
+ if (norm2 > 0) {
9727
9866
  for (let dVar = 0; dVar < dim; dVar++) {
9728
- embedding[dVar] /= norm;
9867
+ embedding[dVar] /= norm2;
9729
9868
  }
9730
9869
  }
9731
9870
  return embedding;
@@ -10479,13 +10618,14 @@ function ledgerCostUsd(ledger) {
10479
10618
  }
10480
10619
  function buildLiveRunner(store2) {
10481
10620
  return {
10482
- async autopilot(maxIterations, onLine) {
10621
+ async autopilot(maxIterations, onLine, signal) {
10483
10622
  const ledger = new TokenLedger();
10484
10623
  const live = buildLiveImplement({ store: store2, dir: process.cwd(), testCmd: "npm test", retries: 2, ledger, onLog: onLine });
10485
10624
  const port = makeStorePort(store2);
10486
10625
  const result = await runAutopilot(port, {
10487
10626
  maxIterations,
10488
10627
  implement: live.implement,
10628
+ signal,
10489
10629
  onStep: (s) => onLine(`${STEP_ICON[s.action] ?? "\xB7"} ${s.title} [${s.action}] ${s.detail}`)
10490
10630
  });
10491
10631
  const t = ledger.totals();
@@ -11217,7 +11357,7 @@ init_store_port();
11217
11357
  // src/cli/shared/enable-flow.ts
11218
11358
  init_esm_shims();
11219
11359
  init_flow_config();
11220
- function enableFlowConfig(store2) {
11360
+ function setFlowEnabled(store2, enabled) {
11221
11361
  const raw = store2.getProjectSetting(FLOW_CONFIG_SETTING_KEY);
11222
11362
  let current = {};
11223
11363
  if (raw) {
@@ -11227,24 +11367,88 @@ function enableFlowConfig(store2) {
11227
11367
  current = {};
11228
11368
  }
11229
11369
  }
11230
- store2.setProjectSetting(FLOW_CONFIG_SETTING_KEY, JSON.stringify({ ...current, enabled: true }));
11370
+ store2.setProjectSetting(FLOW_CONFIG_SETTING_KEY, JSON.stringify({ ...current, enabled }));
11371
+ }
11372
+ function enableFlowConfig(store2) {
11373
+ setFlowEnabled(store2, true);
11374
+ }
11375
+
11376
+ // src/cli/commands/profile-cmd.ts
11377
+ init_esm_shims();
11378
+
11379
+ // src/core/config/profiles.ts
11380
+ init_esm_shims();
11381
+ var BUILT_IN_PROFILES = {
11382
+ fast: { modelTier: "cheap", flow: false, retries: 1 },
11383
+ build: { modelTier: "build", flow: true, retries: 2 },
11384
+ frontier: { modelTier: "frontier", flow: true, retries: 3 }
11385
+ };
11386
+ function resolveProfile(name) {
11387
+ return BUILT_IN_PROFILES[name];
11388
+ }
11389
+ function listProfiles() {
11390
+ return Object.keys(BUILT_IN_PROFILES);
11231
11391
  }
11392
+
11393
+ // src/cli/commands/profile-cmd.ts
11394
+ init_tier_router();
11232
11395
  function output7(msg) {
11233
11396
  process.stdout.write(msg + "\n");
11234
11397
  }
11398
+ function applyProfile(store2, name) {
11399
+ const profile = resolveProfile(name);
11400
+ if (!profile) return void 0;
11401
+ store2.setProjectSetting("model", resolveTierModel(profile.modelTier));
11402
+ setFlowEnabled(store2, profile.flow);
11403
+ return profile;
11404
+ }
11405
+ function profileCommand() {
11406
+ const cmd = new Command("profile").description("Bundles de trabalho: tier de modelo + flow + retries");
11407
+ cmd.command("list").description("Lista os profiles dispon\xEDveis").action(() => {
11408
+ for (const name of listProfiles()) {
11409
+ const p = BUILT_IN_PROFILES[name];
11410
+ output7(`${name.padEnd(10)} tier=${p.modelTier} flow=${p.flow} retries=${p.retries}`);
11411
+ }
11412
+ });
11413
+ cmd.command("show <nome>").description("Detalha um profile").action((nome) => {
11414
+ const p = resolveProfile(nome);
11415
+ if (!p) {
11416
+ output7(`Profile desconhecido: ${nome}. Tente 'profile list'.`);
11417
+ process.exitCode = 1;
11418
+ return;
11419
+ }
11420
+ output7(`${nome}: tier=${p.modelTier} \xB7 flow=${p.flow} \xB7 retries=${p.retries} \xB7 modelo=${resolveTierModel(p.modelTier)}`);
11421
+ });
11422
+ return cmd;
11423
+ }
11424
+ function output8(msg) {
11425
+ process.stdout.write(msg + "\n");
11426
+ }
11235
11427
  function autopilotCommand() {
11236
- return new Command("autopilot").description("Loop aut\xF4nomo com guardrails: next \u2192 in_progress \u2192 DoD \u2192 done|escalate (WIP=1)").option("-d, --dir <dir>", "Diret\xF3rio do projeto", process.cwd()).option("-m, --max <n>", "Budget: m\xE1ximo de tasks por sess\xE3o (cost-runaway guard)", "5").option("--simulate", "Simula impl bem-sucedida (deixa o DoD real decidir) \u2014 n\xE3o escreve c\xF3digo", false).option("--live", "Invoca o modelo real via SDK do Copilot: gera plano \u2192 aplica \u2192 roda testes \u2192 done|escala", false).option("--test-cmd <cmd>", "Comando de teste rodado no modo --live quando o plano n\xE3o traz um", "npm test").option("--retries <n>", "Tentativas por task no --live (retry com feedback compacto do teste)", "2").option("--flow", "Ativa a dilui\xE7\xE3o de contexto por \u03BB_flow (hipofrontalidade) no --live", false).action(
11428
+ return new Command("autopilot").description("Loop aut\xF4nomo com guardrails: next \u2192 in_progress \u2192 DoD \u2192 done|escalate (WIP=1)").option("-d, --dir <dir>", "Diret\xF3rio do projeto", process.cwd()).option("-m, --max <n>", "Budget: m\xE1ximo de tasks por sess\xE3o (cost-runaway guard)", "5").option("--simulate", "Simula impl bem-sucedida (deixa o DoD real decidir) \u2014 n\xE3o escreve c\xF3digo", false).option("--live", "Invoca o modelo real via SDK do Copilot: gera plano \u2192 aplica \u2192 roda testes \u2192 done|escala", false).option("--test-cmd <cmd>", "Comando de teste rodado no modo --live quando o plano n\xE3o traz um", "npm test").option("--retries <n>", "Tentativas por task no --live (retry com feedback compacto do teste)", "2").option("--flow", "Ativa a dilui\xE7\xE3o de contexto por \u03BB_flow (hipofrontalidade) no --live", false).option("--profile <nome>", "Aplica um bundle de trabalho (fast|build|frontier): tier+flow+retries").action(
11237
11429
  async (opts) => {
11238
11430
  const store2 = openStoreOrFail(opts.dir, { requireExisting: true });
11239
11431
  try {
11240
11432
  const maxIterations = Math.max(1, parseInt(opts.max, 10) || 5);
11241
11433
  const port = makeStorePort(store2);
11434
+ let retriesOverride;
11435
+ if (opts.profile) {
11436
+ const applied = applyProfile(store2, opts.profile);
11437
+ if (!applied) {
11438
+ output8(`Profile desconhecido: ${opts.profile}. Tente 'profile list'.`);
11439
+ store2.close();
11440
+ return;
11441
+ }
11442
+ retriesOverride = applied.retries;
11443
+ output8(`[PROFILE] ${opts.profile}: tier=${applied.modelTier} flow=${applied.flow} retries=${applied.retries}
11444
+ `);
11445
+ }
11242
11446
  if (opts.flow) {
11243
11447
  enableFlowConfig(store2);
11244
- output7("[FLOW] \u03BB_flow ativo: contexto do grafo dilu\xEDdo por \u03A6(t) (esquecimento din\xE2mico).\n");
11448
+ output8("[FLOW] \u03BB_flow ativo: contexto do grafo dilu\xEDdo por \u03A6(t) (esquecimento din\xE2mico).\n");
11245
11449
  }
11246
- if (opts.simulate) output7("[SIMULA\xC7\xC3O] impl tratada como verde \u2014 DoD real decide prontid\xE3o.\n");
11247
- if (opts.live) output7("[LIVE] modelo via SDK do Copilot: gera plano \u2192 aplica no workspace \u2192 roda testes.\n");
11450
+ if (opts.simulate) output8("[SIMULA\xC7\xC3O] impl tratada como verde \u2014 DoD real decide prontid\xE3o.\n");
11451
+ if (opts.live) output8("[LIVE] modelo via SDK do Copilot: gera plano \u2192 aplica no workspace \u2192 roda testes.\n");
11248
11452
  let implement;
11249
11453
  let ledger;
11250
11454
  if (opts.live) {
@@ -11253,11 +11457,11 @@ function autopilotCommand() {
11253
11457
  store: store2,
11254
11458
  dir: opts.dir,
11255
11459
  testCmd: opts.testCmd,
11256
- retries: parseInt(opts.retries, 10) || 2,
11460
+ retries: retriesOverride ?? (parseInt(opts.retries, 10) || 2),
11257
11461
  ledger,
11258
- onLog: output7
11462
+ onLog: output8
11259
11463
  });
11260
- if (live.repoSymbolCount > 0) output7(`[LIVE] repo-map: ${live.repoSymbolCount} s\xEDmbolo(s) indexado(s).`);
11464
+ if (live.repoSymbolCount > 0) output8(`[LIVE] repo-map: ${live.repoSymbolCount} s\xEDmbolo(s) indexado(s).`);
11261
11465
  implement = live.implement;
11262
11466
  } else if (opts.simulate) {
11263
11467
  implement = () => true;
@@ -11267,28 +11471,28 @@ function autopilotCommand() {
11267
11471
  const result = await runAutopilot(port, { maxIterations, implement });
11268
11472
  for (const s of result.steps) {
11269
11473
  const icon = s.action === "done" ? "\u2713" : s.action === "escalated" ? "\u26A0" : "\u2192";
11270
- output7(`${icon} ${s.nodeId} ${s.title} [${s.action}] ${s.detail}`);
11474
+ output8(`${icon} ${s.nodeId} ${s.title} [${s.action}] ${s.detail}`);
11271
11475
  }
11272
- output7(`
11476
+ output8(`
11273
11477
  Resumo: ${result.completed} conclu\xEDda(s), ${result.escalated} escalada(s). Parou: ${result.stopped}`);
11274
11478
  if (ledger) {
11275
11479
  const totals = ledger.totals();
11276
- output7(`
11480
+ output8(`
11277
11481
  Tokens (sess\xE3o): ${totals.total} (in ${totals.tokensIn} / out ${totals.tokensOut}) em ${totals.calls} chamada(s)`);
11278
11482
  for (const t of ledger.tasks()) {
11279
- output7(` ${t.nodeId}: ${t.total} tok (in ${t.tokensIn} / out ${t.tokensOut}, ${t.calls} chamada(s))`);
11483
+ output8(` ${t.nodeId}: ${t.total} tok (in ${t.tokensIn} / out ${t.tokensOut}, ${t.calls} chamada(s))`);
11280
11484
  }
11281
11485
  if (result.completed > 0) {
11282
- output7(` m\xE9dia/task conclu\xEDda: ${Math.round(totals.total / result.completed)} tok`);
11486
+ output8(` m\xE9dia/task conclu\xEDda: ${Math.round(totals.total / result.completed)} tok`);
11283
11487
  }
11284
11488
  if (totals.calls > 0) {
11285
11489
  const sessionId = `autopilot_${randomUUID().replace(/-/g, "").slice(0, 12)}`;
11286
11490
  const rows = persistLedger(store2.getDb(), ledger, { sessionId, provider: "copilot" });
11287
- output7(` ${rows} chamada(s) persistida(s) (session ${sessionId})`);
11491
+ output8(` ${rows} chamada(s) persistida(s) (session ${sessionId})`);
11288
11492
  }
11289
11493
  }
11290
11494
  if (!opts.simulate && !opts.live && result.stopped === "escalation") {
11291
- output7("\nDica: --simulate exercita o loop + gate DoD; --live invoca o modelo real via SDK do Copilot.");
11495
+ output8("\nDica: --simulate exercita o loop + gate DoD; --live invoca o modelo real via SDK do Copilot.");
11292
11496
  }
11293
11497
  } finally {
11294
11498
  store2.close();
@@ -11301,7 +11505,7 @@ Tokens (sess\xE3o): ${totals.total} (in ${totals.tokensIn} / out ${totals.tokens
11301
11505
  init_esm_shims();
11302
11506
  init_tier_router();
11303
11507
  var SETTING_KEY = "model";
11304
- function output8(msg) {
11508
+ function output9(msg) {
11305
11509
  process.stdout.write(msg + "\n");
11306
11510
  }
11307
11511
  function readConfig(dir) {
@@ -11318,29 +11522,29 @@ function modelCommand() {
11318
11522
  "Seleciona/inspeciona o modelo do tier-router (pool do Copilot CLI; 'auto' roteia por tarefa)"
11319
11523
  );
11320
11524
  cmd.command("list").description("Lista o pool agrupado por tier").action(() => {
11321
- output8("auto \u2014 roteia por tarefa (cheap classifica \xB7 build implementa \xB7 frontier planeja)\n");
11525
+ output9("auto \u2014 roteia por tarefa (cheap classifica \xB7 build implementa \xB7 frontier planeja)\n");
11322
11526
  for (const tier of MODEL_TIERS) {
11323
- output8(`[${tier}]`);
11527
+ output9(`[${tier}]`);
11324
11528
  for (const m of modelsForTier(tier)) {
11325
11529
  const mark = m.id === DEFAULT_MODEL ? " (default)" : "";
11326
- output8(` ${m.id} \u2014 ${m.label}${mark}`);
11530
+ output9(` ${m.id} \u2014 ${m.label}${mark}`);
11327
11531
  }
11328
11532
  }
11329
11533
  });
11330
11534
  cmd.command("current").description("Mostra o modelo/modo selecionado").option("-d, --dir <dir>", "Diret\xF3rio do projeto", process.cwd()).action((opts) => {
11331
11535
  const config = readConfig(opts.dir);
11332
- output8(config.mode === "auto" ? "auto (roteamento por tarefa)" : `pinned: ${config.modelId}`);
11536
+ output9(config.mode === "auto" ? "auto (roteamento por tarefa)" : `pinned: ${config.modelId}`);
11333
11537
  });
11334
11538
  cmd.command("set").description("Fixa um modelo (id do pool) ou 'auto' para roteamento por tarefa").argument("<idOrAuto>", "ID do modelo ou 'auto'").option("-d, --dir <dir>", "Diret\xF3rio do projeto", process.cwd()).action((idOrAuto, opts) => {
11335
11539
  const value = idOrAuto.trim();
11336
11540
  if (value !== "auto" && !isKnownModel(value)) {
11337
- output8(`Modelo desconhecido: "${value}". Rode 'model list' para ver o pool.`);
11541
+ output9(`Modelo desconhecido: "${value}". Rode 'model list' para ver o pool.`);
11338
11542
  process.exit(1);
11339
11543
  }
11340
11544
  const store2 = openStoreOrFail(opts.dir, { requireExisting: true });
11341
11545
  try {
11342
11546
  store2.setProjectSetting(SETTING_KEY, value);
11343
- output8(value === "auto" ? "Modo: auto (roteamento por tarefa)." : `Modelo fixado: ${value}.`);
11547
+ output9(value === "auto" ? "Modo: auto (roteamento por tarefa)." : `Modelo fixado: ${value}.`);
11344
11548
  } finally {
11345
11549
  store2.close();
11346
11550
  }
@@ -11348,11 +11552,11 @@ function modelCommand() {
11348
11552
  cmd.command("route").description("Mostra qual modelo o router escolhe para um tipo de tarefa").argument("<kind>", `Tipo: ${TaskKindSchema.options.join("|")}`).option("-d, --dir <dir>", "Diret\xF3rio do projeto", process.cwd()).action((kind, opts) => {
11349
11553
  const parsed = TaskKindSchema.safeParse(kind);
11350
11554
  if (!parsed.success) {
11351
- output8(`Tipo inv\xE1lido: "${kind}". Esperado: ${TaskKindSchema.options.join(", ")}.`);
11555
+ output9(`Tipo inv\xE1lido: "${kind}". Esperado: ${TaskKindSchema.options.join(", ")}.`);
11352
11556
  process.exit(1);
11353
11557
  }
11354
11558
  const config = readConfig(opts.dir);
11355
- output8(`${kind} \u2192 ${routeModel(config, parsed.data)}`);
11559
+ output9(`${kind} \u2192 ${routeModel(config, parsed.data)}`);
11356
11560
  });
11357
11561
  return cmd;
11358
11562
  }
@@ -11360,7 +11564,7 @@ function modelCommand() {
11360
11564
  // src/cli/commands/metrics-cmd.ts
11361
11565
  init_esm_shims();
11362
11566
  init_llm_call_ledger();
11363
- function output9(msg) {
11567
+ function output10(msg) {
11364
11568
  process.stdout.write(msg + "\n");
11365
11569
  }
11366
11570
  function metricsCommand() {
@@ -11369,30 +11573,30 @@ function metricsCommand() {
11369
11573
  try {
11370
11574
  const summary = summarizeLedger(store2.getDb(), { sessionId: opts.session });
11371
11575
  if (summary.totals.calls === 0) {
11372
- output9("Sem chamadas de modelo registradas. Rode `autopilot --live` para gerar m\xE9tricas.");
11576
+ output10("Sem chamadas de modelo registradas. Rode `autopilot --live` para gerar m\xE9tricas.");
11373
11577
  return;
11374
11578
  }
11375
11579
  const usd = (n) => `$${n.toFixed(4)}`;
11376
11580
  const { totals } = summary;
11377
11581
  const taskCount = summary.byTask.length;
11378
11582
  const avgCost = taskCount > 0 ? totals.costUsd / taskCount : 0;
11379
- output9(`Tokens totais: ${totals.total} (in ${totals.tokensIn} / out ${totals.tokensOut}) em ${totals.calls} chamada(s)`);
11380
- output9(`Custo total: \u2248 ${usd(totals.costUsd)}`);
11381
- output9(`M\xE9dia por task: ${summary.avgTokensPerTask} tok \u2248 ${usd(avgCost)} | ${taskCount} task(s), ${summary.bySession.length} sess\xE3o(\xF5es)`);
11583
+ output10(`Tokens totais: ${totals.total} (in ${totals.tokensIn} / out ${totals.tokensOut}) em ${totals.calls} chamada(s)`);
11584
+ output10(`Custo total: \u2248 ${usd(totals.costUsd)}`);
11585
+ output10(`M\xE9dia por task: ${summary.avgTokensPerTask} tok \u2248 ${usd(avgCost)} | ${taskCount} task(s), ${summary.bySession.length} sess\xE3o(\xF5es)`);
11382
11586
  const top = Math.max(1, parseInt(opts.top, 10) || 10);
11383
- output9(`
11587
+ output10(`
11384
11588
  Tokens por task (top ${top}):`);
11385
11589
  for (const t of summary.byTask.slice(0, top)) {
11386
- output9(` ${t.nodeId}: ${t.total} tok \u2248 ${usd(t.costUsd)} (in ${t.tokensIn} / out ${t.tokensOut}, ${t.calls} chamada(s))`);
11590
+ output10(` ${t.nodeId}: ${t.total} tok \u2248 ${usd(t.costUsd)} (in ${t.tokensIn} / out ${t.tokensOut}, ${t.calls} chamada(s))`);
11387
11591
  }
11388
11592
  if (!opts.session) {
11389
- output9("\nTokens por sess\xE3o:");
11593
+ output10("\nTokens por sess\xE3o:");
11390
11594
  for (const s of summary.bySession) {
11391
- output9(` ${s.sessionId}: ${s.total} tok \u2248 ${usd(s.costUsd)} (${s.calls} chamada(s))`);
11595
+ output10(` ${s.sessionId}: ${s.total} tok \u2248 ${usd(s.costUsd)} (${s.calls} chamada(s))`);
11392
11596
  }
11393
11597
  }
11394
11598
  if (totals.costUsd === 0) {
11395
- output9("\nNota: custo $0 \u2014 modelos usados n\xE3o t\xEAm pre\xE7o cadastrado (ver cost-tracker MODEL_PRICING).");
11599
+ output10("\nNota: custo $0 \u2014 modelos usados n\xE3o t\xEAm pre\xE7o cadastrado (ver cost-tracker MODEL_PRICING).");
11396
11600
  }
11397
11601
  } finally {
11398
11602
  store2.close();
@@ -11407,7 +11611,7 @@ init_resolve_adapter();
11407
11611
  init_implementation_executor();
11408
11612
  init_implement_attempt();
11409
11613
  init_token_ledger();
11410
- function output10(msg) {
11614
+ function output11(msg) {
11411
11615
  process.stdout.write(msg + "\n");
11412
11616
  }
11413
11617
  function runCommand() {
@@ -11418,7 +11622,7 @@ function runCommand() {
11418
11622
  const maxAttempts = Math.max(1, parseInt(opts.retries, 10) || 2);
11419
11623
  const ledger = new TokenLedger();
11420
11624
  const node = { id: `run_${randomUUID().replace(/-/g, "").slice(0, 8)}`, title: prompt };
11421
- output10(`[run] ${client.modelFor("implement")} via ${resolved.kind === "api" ? "API HTTP" : "CLI"} \u2192 "${prompt}"`);
11625
+ output11(`[run] ${client.modelFor("implement")} via ${resolved.kind === "api" ? "API HTTP" : "CLI"} \u2192 "${prompt}"`);
11422
11626
  const outcome = await attemptImplementation(
11423
11627
  {
11424
11628
  generate: async (p) => {
@@ -11438,7 +11642,7 @@ function runCommand() {
11438
11642
  );
11439
11643
  const files = outcome.lastResult?.applied.length ?? 0;
11440
11644
  const totals = ledger.totals();
11441
- output10(
11645
+ output11(
11442
11646
  `${outcome.success ? "\u2713" : "\u26A0"} ${outcome.attempts} tentativa(s), ${files} arquivo(s), ${totals.total} tok (in ${totals.tokensIn} / out ${totals.tokensOut}) \u2192 ${outcome.success ? "verde" : "falhou (testes n\xE3o passaram)"}`
11443
11647
  );
11444
11648
  if (!outcome.success) process.exitCode = 1;
@@ -11462,7 +11666,7 @@ function tuiCommand() {
11462
11666
  // src/cli/commands/login-cmd.ts
11463
11667
  init_esm_shims();
11464
11668
  init_copilot_auth();
11465
- function output11(msg) {
11669
+ function output12(msg) {
11466
11670
  process.stdout.write(msg + "\n");
11467
11671
  }
11468
11672
  function loginCommand() {
@@ -11470,15 +11674,15 @@ function loginCommand() {
11470
11674
  const path22 = defaultAuthPath();
11471
11675
  if (opts.token) {
11472
11676
  saveAuth(path22, { githubToken: opts.token });
11473
- output11(`\u2713 Token salvo em ${path22}. Provider HTTP do Copilot habilitado.`);
11677
+ output12(`\u2713 Token salvo em ${path22}. Provider HTTP do Copilot habilitado.`);
11474
11678
  return;
11475
11679
  }
11476
11680
  const device = await requestDeviceCode(globalThis.fetch);
11477
- output11("\nPara autenticar, abra:");
11478
- output11(` ${device.verificationUri}`);
11479
- output11(`e informe o c\xF3digo: \x1B[1m${device.userCode}\x1B[0m
11681
+ output12("\nPara autenticar, abra:");
11682
+ output12(` ${device.verificationUri}`);
11683
+ output12(`e informe o c\xF3digo: \x1B[1m${device.userCode}\x1B[0m
11480
11684
  `);
11481
- output11("Aguardando autoriza\xE7\xE3o\u2026 (Ctrl+C para cancelar)");
11685
+ output12("Aguardando autoriza\xE7\xE3o\u2026 (Ctrl+C para cancelar)");
11482
11686
  const deadline = Date.now() + device.expiresIn * 1e3;
11483
11687
  let interval = Math.max(1, device.interval);
11484
11688
  while (Date.now() < deadline) {
@@ -11486,13 +11690,13 @@ function loginCommand() {
11486
11690
  const r = await pollForAccessToken(globalThis.fetch, device.deviceCode);
11487
11691
  if ("accessToken" in r) {
11488
11692
  saveAuth(path22, { githubToken: r.accessToken });
11489
- output11(`
11693
+ output12(`
11490
11694
  \u2713 Autenticado. Token salvo em ${path22}. Provider HTTP do Copilot habilitado.`);
11491
11695
  return;
11492
11696
  }
11493
11697
  if ("slowDown" in r) interval += 5;
11494
11698
  }
11495
- output11("\n\u26A0 Tempo esgotado sem autoriza\xE7\xE3o. Rode `agf login` de novo.");
11699
+ output12("\n\u26A0 Tempo esgotado sem autoriza\xE7\xE3o. Rode `agf login` de novo.");
11496
11700
  process.exitCode = 1;
11497
11701
  });
11498
11702
  }
@@ -11501,9 +11705,9 @@ function logoutCommand() {
11501
11705
  const path22 = defaultAuthPath();
11502
11706
  if (existsSync(path22) && loadAuth(path22)) {
11503
11707
  rmSync(path22, { force: true });
11504
- output11(`\u2713 Logout \u2014 ${path22} removido.`);
11708
+ output12(`\u2713 Logout \u2014 ${path22} removido.`);
11505
11709
  } else {
11506
- output11("Nenhum login salvo.");
11710
+ output12("Nenhum login salvo.");
11507
11711
  }
11508
11712
  });
11509
11713
  }
@@ -14164,7 +14368,7 @@ function reapDaemons(options = {}) {
14164
14368
  // src/cli/commands/daemon-cmd.ts
14165
14369
  init_logger();
14166
14370
  var log44 = createLogger({ layer: "cli", source: "daemon.ts" });
14167
- function output12(msg) {
14371
+ function output13(msg) {
14168
14372
  process.stdout.write(msg + "\n");
14169
14373
  }
14170
14374
  function daemonCommand() {
@@ -14175,23 +14379,23 @@ function daemonCommand() {
14175
14379
  const prefix = opts.dryRun ? "[dry-run] " : "";
14176
14380
  for (const a of report.actions) {
14177
14381
  if (a.outcome === "kept") continue;
14178
- output12(`${prefix}${a.outcome}: ${a.stateDir}${a.pid ? ` (pid=${a.pid})` : ""} \u2014 ${a.reason}`);
14382
+ output13(`${prefix}${a.outcome}: ${a.stateDir}${a.pid ? ` (pid=${a.pid})` : ""} \u2014 ${a.reason}`);
14179
14383
  }
14180
- output12(
14384
+ output13(
14181
14385
  `${prefix}daemon prune: scanned ${report.scanned}, killed ${report.killed}, removed ${report.removed}, kept ${report.kept}`
14182
14386
  );
14183
14387
  });
14184
14388
  cmd.command("list").description("List daemon state directories and their status (read-only)").action(() => {
14185
14389
  const report = reapDaemons({ dryRun: true });
14186
14390
  if (report.scanned === 0) {
14187
- output12("daemon list: no daemon state directories found");
14391
+ output13("daemon list: no daemon state directories found");
14188
14392
  return;
14189
14393
  }
14190
14394
  for (const a of report.actions) {
14191
14395
  const would = a.outcome === "kept" ? "alive" : `stale \u2192 would ${a.outcome}`;
14192
- output12(`${would}: ${a.stateDir}${a.pid ? ` (pid=${a.pid})` : ""} \u2014 ${a.reason}`);
14396
+ output13(`${would}: ${a.stateDir}${a.pid ? ` (pid=${a.pid})` : ""} \u2014 ${a.reason}`);
14193
14397
  }
14194
- output12(`daemon list: ${report.scanned} state dir(s), ${report.kept} alive`);
14398
+ output13(`daemon list: ${report.scanned} state dir(s), ${report.kept} alive`);
14195
14399
  });
14196
14400
  return cmd;
14197
14401
  }
@@ -14243,7 +14447,7 @@ function formatProviderReport(report) {
14243
14447
  init_errors();
14244
14448
  init_logger();
14245
14449
  var log45 = createLogger({ layer: "cli", source: "doctor.ts" });
14246
- function output13(msg) {
14450
+ function output14(msg) {
14247
14451
  process.stdout.write(msg + "\n");
14248
14452
  }
14249
14453
  var LEVEL_ICON2 = {
@@ -14266,31 +14470,31 @@ function doctorCommand() {
14266
14470
  if (opts.providers) {
14267
14471
  const providerReport = checkProviders();
14268
14472
  if (opts.json) {
14269
- output13(JSON.stringify(providerReport, null, 2));
14473
+ output14(JSON.stringify(providerReport, null, 2));
14270
14474
  } else {
14271
- output13("mcp-graph doctor \u2014 LLM providers\n");
14475
+ output14("mcp-graph doctor \u2014 LLM providers\n");
14272
14476
  for (const line of formatProviderReport(providerReport)) {
14273
- output13(line);
14477
+ output14(line);
14274
14478
  }
14275
14479
  }
14276
14480
  return;
14277
14481
  }
14278
14482
  const report = await runDoctor(opts.dir);
14279
14483
  if (opts.json) {
14280
- output13(JSON.stringify(report, null, 2));
14484
+ output14(JSON.stringify(report, null, 2));
14281
14485
  } else {
14282
- output13("mcp-graph doctor\n");
14486
+ output14("mcp-graph doctor\n");
14283
14487
  for (const check of report.checks) {
14284
- output13(formatCheck(check));
14488
+ output14(formatCheck(check));
14285
14489
  }
14286
- output13("");
14287
- output13(
14490
+ output14("");
14491
+ output14(
14288
14492
  `Summary: ${report.summary.ok} ok, ${report.summary.warning} warnings, ${report.summary.error} errors`
14289
14493
  );
14290
14494
  if (report.passed) {
14291
- output13("\nAll critical checks passed.");
14495
+ output14("\nAll critical checks passed.");
14292
14496
  } else {
14293
- output13("\nSome critical checks failed. Fix errors above.");
14497
+ output14("\nSome critical checks failed. Fix errors above.");
14294
14498
  }
14295
14499
  }
14296
14500
  if (!report.passed) {
@@ -14374,13 +14578,13 @@ function pruneOrphanWorktrees(options) {
14374
14578
  }
14375
14579
  }
14376
14580
  try {
14377
- const output16 = execSync("git worktree prune --verbose", execOpts).toString();
14581
+ const output17 = execSync("git worktree prune --verbose", execOpts).toString();
14378
14582
  if (reapedBranches > 0 || reapedWorktrees > 0) {
14379
14583
  log46.info("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, ttlMs });
14380
14584
  } else {
14381
- log46.debug("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, output: output16 });
14585
+ log46.debug("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, output: output17 });
14382
14586
  }
14383
- return { pruned: true, reapedBranches, reapedWorktrees, output: output16 };
14587
+ return { pruned: true, reapedBranches, reapedWorktrees, output: output17 };
14384
14588
  } catch (err) {
14385
14589
  const error = String(err);
14386
14590
  log46.debug("shadow-branch:prune-failed", { error });
@@ -14391,7 +14595,7 @@ function pruneOrphanWorktrees(options) {
14391
14595
  // src/cli/commands/gc-cmd.ts
14392
14596
  init_logger();
14393
14597
  var log47 = createLogger({ layer: "cli", source: "gc.ts" });
14394
- function output14(msg) {
14598
+ function output15(msg) {
14395
14599
  process.stdout.write(msg + "\n");
14396
14600
  }
14397
14601
  function gcCommand() {
@@ -14401,9 +14605,9 @@ function gcCommand() {
14401
14605
  log47.info("cli:gc:start", { dir: opts.dir, ttlMs });
14402
14606
  const result = pruneOrphanWorktrees({ cwd: opts.dir, ttlMs });
14403
14607
  if (result.pruned) {
14404
- output14(`gc: reaped ${result.reapedBranches} branches, ${result.reapedWorktrees} worktrees`);
14608
+ output15(`gc: reaped ${result.reapedBranches} branches, ${result.reapedWorktrees} worktrees`);
14405
14609
  } else {
14406
- output14(`gc: failed \u2014 ${result.error ?? "unknown error"}`);
14610
+ output15(`gc: failed \u2014 ${result.error ?? "unknown error"}`);
14407
14611
  process.exit(1);
14408
14612
  }
14409
14613
  });
@@ -14412,7 +14616,7 @@ function gcCommand() {
14412
14616
  // src/cli/commands/skill-cmd.ts
14413
14617
  init_esm_shims();
14414
14618
  init_skill_registry();
14415
- function output15(msg) {
14619
+ function output16(msg) {
14416
14620
  process.stdout.write(msg + "\n");
14417
14621
  }
14418
14622
  function skillCommand() {
@@ -14426,26 +14630,26 @@ function skillCommand() {
14426
14630
  if (seen.has(s.name)) continue;
14427
14631
  seen.add(s.name);
14428
14632
  count += 1;
14429
- output15(`${s.name.padEnd(28)} [${s.category}] ${s.description}`);
14633
+ output16(`${s.name.padEnd(28)} [${s.category}] ${s.description}`);
14430
14634
  }
14431
14635
  }
14432
- if (count === 0) output15("Nenhuma skill encontrada.");
14433
- else output15(`
14636
+ if (count === 0) output16("Nenhuma skill encontrada.");
14637
+ else output16(`
14434
14638
  ${count} skill(s).`);
14435
14639
  });
14436
14640
  cmd.command("show <nome>").description("Imprime as instru\xE7\xF5es completas de uma skill").option("-d, --dir <dir>", "Raiz do projeto", process.cwd()).action((nome, opts) => {
14437
14641
  for (const root of defaultSkillRoots(opts.dir)) {
14438
14642
  const found = invokeSkill(root, nome);
14439
14643
  if (found) {
14440
- output15(`=== ${found.name} ===`);
14441
- output15(`[${found.category}] ${found.description}`);
14442
- if (found.phases.length > 0) output15(`fases: ${found.phases.join(", ")}`);
14443
- output15("");
14444
- output15(found.body);
14644
+ output16(`=== ${found.name} ===`);
14645
+ output16(`[${found.category}] ${found.description}`);
14646
+ if (found.phases.length > 0) output16(`fases: ${found.phases.join(", ")}`);
14647
+ output16("");
14648
+ output16(found.body);
14445
14649
  return;
14446
14650
  }
14447
14651
  }
14448
- output15(`Skill n\xE3o encontrada: ${nome}. Tente 'skill list'.`);
14652
+ output16(`Skill n\xE3o encontrada: ${nome}. Tente 'skill list'.`);
14449
14653
  process.exitCode = 1;
14450
14654
  });
14451
14655
  return cmd;
@@ -14472,6 +14676,7 @@ program.addCommand(daemonCommand());
14472
14676
  program.addCommand(doctorCommand());
14473
14677
  program.addCommand(gcCommand());
14474
14678
  program.addCommand(skillCommand());
14679
+ program.addCommand(profileCommand());
14475
14680
  function shouldLaunchTui() {
14476
14681
  const noArgs = process.argv.length <= 2;
14477
14682
  const isTty = Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-graph-workflow/agent-graph-flow",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Agente SWE autônomo, local-first e token-frugal: PRD → grafo de execução persistente, TDD obrigatório, custo de token brutalmente baixo. AGPL v3.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",