@mcp-graph-workflow/agent-graph-flow 0.3.0 → 0.4.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/dist/cli/index.js +280 -92
- 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,
|
|
16
|
+
import { createElement, useState, useEffect, useCallback } from 'react';
|
|
17
17
|
import TextInput from 'ink-text-input';
|
|
18
18
|
import Spinner from 'ink-spinner';
|
|
19
19
|
import { Command } from 'commander';
|
|
@@ -7091,8 +7091,8 @@ var init_implementation_executor = __esm({
|
|
|
7091
7091
|
};
|
|
7092
7092
|
defaultRunner = (command, cwd) => {
|
|
7093
7093
|
try {
|
|
7094
|
-
const
|
|
7095
|
-
return { exitCode: 0, output:
|
|
7094
|
+
const output17 = execSync(command, { cwd, encoding: "utf8", stdio: "pipe" });
|
|
7095
|
+
return { exitCode: 0, output: output17 };
|
|
7096
7096
|
} catch (err) {
|
|
7097
7097
|
const e = err;
|
|
7098
7098
|
return {
|
|
@@ -7320,7 +7320,12 @@ async function attemptImplementation(deps, options) {
|
|
|
7320
7320
|
lastResult = await deps.execute(plan);
|
|
7321
7321
|
if (lastResult.testPassed === true) {
|
|
7322
7322
|
log25.info("Implementa\xE7\xE3o verde", { attempt, node: options.node.id });
|
|
7323
|
-
|
|
7323
|
+
const appliedEdits = (plan.edits ?? []).map((e) => ({
|
|
7324
|
+
path: e.path,
|
|
7325
|
+
oldString: e.oldString,
|
|
7326
|
+
newString: e.newString
|
|
7327
|
+
}));
|
|
7328
|
+
return { success: true, attempts: attempt, lastResult, appliedEdits };
|
|
7324
7329
|
}
|
|
7325
7330
|
lastError = lastResult.testOutput;
|
|
7326
7331
|
log25.warn("Testes vermelhos", { attempt, node: options.node.id });
|
|
@@ -7341,6 +7346,79 @@ var init_implement_attempt = __esm({
|
|
|
7341
7346
|
}
|
|
7342
7347
|
});
|
|
7343
7348
|
|
|
7349
|
+
// src/core/autonomy/exec-policy.ts
|
|
7350
|
+
function norm(cmd) {
|
|
7351
|
+
return cmd.trim().replace(/\s+/g, " ");
|
|
7352
|
+
}
|
|
7353
|
+
function evaluateExecPolicy(command, rules, defaultEffect = "ask") {
|
|
7354
|
+
const cmd = norm(command);
|
|
7355
|
+
let best;
|
|
7356
|
+
for (const rule of rules) {
|
|
7357
|
+
const m = norm(rule.match);
|
|
7358
|
+
if (cmd === m || cmd.startsWith(m + " ") || cmd.startsWith(m)) {
|
|
7359
|
+
if (!best || m.length > norm(best.match).length) best = rule;
|
|
7360
|
+
}
|
|
7361
|
+
}
|
|
7362
|
+
if (best) return { effect: best.effect, matchedRule: best };
|
|
7363
|
+
const low = cmd.toLowerCase();
|
|
7364
|
+
for (const danger of DEFAULT_DENY) {
|
|
7365
|
+
if (low.includes(danger)) return { effect: "deny", builtin: true };
|
|
7366
|
+
}
|
|
7367
|
+
return { effect: defaultEffect };
|
|
7368
|
+
}
|
|
7369
|
+
function guardExecRunner(base, opts = {}) {
|
|
7370
|
+
const rules = opts.rules ?? [];
|
|
7371
|
+
const defaultEffect = opts.defaultEffect ?? "ask";
|
|
7372
|
+
return (command, cwd) => {
|
|
7373
|
+
const decision = evaluateExecPolicy(command, rules, defaultEffect);
|
|
7374
|
+
const allowed = decision.effect === "allow" || decision.effect === "ask" && opts.cache?.isApproved(command) === true;
|
|
7375
|
+
if (allowed) return base(command, cwd);
|
|
7376
|
+
const reason = decision.effect === "deny" ? decision.builtin ? "deny (built-in perigoso)" : "deny (regra)" : "ask (n\xE3o aprovado nesta sess\xE3o)";
|
|
7377
|
+
return { exitCode: 126, output: `[exec-policy] comando bloqueado \u2014 ${reason}: ${command}` };
|
|
7378
|
+
};
|
|
7379
|
+
}
|
|
7380
|
+
var DEFAULT_DENY;
|
|
7381
|
+
var init_exec_policy = __esm({
|
|
7382
|
+
"src/core/autonomy/exec-policy.ts"() {
|
|
7383
|
+
init_esm_shims();
|
|
7384
|
+
DEFAULT_DENY = [
|
|
7385
|
+
"rm -rf",
|
|
7386
|
+
"sudo ",
|
|
7387
|
+
"git push --force",
|
|
7388
|
+
"git push -f",
|
|
7389
|
+
"chmod -R 777",
|
|
7390
|
+
"chmod 777",
|
|
7391
|
+
"dd if=",
|
|
7392
|
+
":(){",
|
|
7393
|
+
"mkfs",
|
|
7394
|
+
"| sh",
|
|
7395
|
+
"|sh",
|
|
7396
|
+
"| bash",
|
|
7397
|
+
"> /dev/sd"
|
|
7398
|
+
];
|
|
7399
|
+
}
|
|
7400
|
+
});
|
|
7401
|
+
|
|
7402
|
+
// src/tui/diff-render.ts
|
|
7403
|
+
function renderEditDiff(edit) {
|
|
7404
|
+
const lines = [`\u2500\u2500 ${edit.path} \u2500\u2500`];
|
|
7405
|
+
if (edit.oldString.length > 0) {
|
|
7406
|
+
for (const l of edit.oldString.split("\n")) lines.push(`- ${l}`);
|
|
7407
|
+
}
|
|
7408
|
+
if (edit.newString.length > 0) {
|
|
7409
|
+
for (const l of edit.newString.split("\n")) lines.push(`+ ${l}`);
|
|
7410
|
+
}
|
|
7411
|
+
return lines;
|
|
7412
|
+
}
|
|
7413
|
+
function renderPlanDiff(edits) {
|
|
7414
|
+
return edits.flatMap(renderEditDiff);
|
|
7415
|
+
}
|
|
7416
|
+
var init_diff_render = __esm({
|
|
7417
|
+
"src/tui/diff-render.ts"() {
|
|
7418
|
+
init_esm_shims();
|
|
7419
|
+
}
|
|
7420
|
+
});
|
|
7421
|
+
|
|
7344
7422
|
// src/core/code/code-store.ts
|
|
7345
7423
|
function rowToSymbol(row) {
|
|
7346
7424
|
return {
|
|
@@ -8582,6 +8660,18 @@ function buildLiveImplement(options) {
|
|
|
8582
8660
|
onLog?.(`[live] provider: ${resolved.kind === "api" ? "Copilot API (HTTP, logado)" : "Copilot CLI"}`);
|
|
8583
8661
|
const client = new TieredModelClient(resolved.adapter, config);
|
|
8584
8662
|
const maxAttempts = Math.max(1, retries);
|
|
8663
|
+
let execRules = [];
|
|
8664
|
+
let execDefault = "allow";
|
|
8665
|
+
const rawPolicy = store2.getProjectSetting("exec_policy");
|
|
8666
|
+
if (rawPolicy) {
|
|
8667
|
+
try {
|
|
8668
|
+
const parsed = JSON.parse(rawPolicy);
|
|
8669
|
+
if (parsed.default) execDefault = parsed.default;
|
|
8670
|
+
if (Array.isArray(parsed.rules)) execRules = parsed.rules;
|
|
8671
|
+
} catch {
|
|
8672
|
+
}
|
|
8673
|
+
}
|
|
8674
|
+
const guardedRunner = guardExecRunner(defaultRunner, { rules: execRules, defaultEffect: execDefault });
|
|
8585
8675
|
const codeStore = new CodeStore(store2.getDb());
|
|
8586
8676
|
const projectId = store2.getProject()?.id;
|
|
8587
8677
|
const repoSymbols = projectId ? codeStore.getAllSymbols(projectId) : [];
|
|
@@ -8609,7 +8699,7 @@ function buildLiveImplement(options) {
|
|
|
8609
8699
|
});
|
|
8610
8700
|
return res.text;
|
|
8611
8701
|
},
|
|
8612
|
-
execute: (plan) => executePlan(plan, { workspaceDir: dir, defaultTestCommand: testCmd })
|
|
8702
|
+
execute: (plan) => executePlan(plan, { workspaceDir: dir, defaultTestCommand: testCmd, runCommand: guardedRunner })
|
|
8613
8703
|
},
|
|
8614
8704
|
{ node, maxAttempts, repoMap, flowContext }
|
|
8615
8705
|
);
|
|
@@ -8618,6 +8708,9 @@ function buildLiveImplement(options) {
|
|
|
8618
8708
|
onLog?.(
|
|
8619
8709
|
` [live] ${client.modelFor("implement")}: ${outcome.attempts} tentativa(s), ${files} arquivo(s), ${task.total} tok \u2192 ${outcome.success ? "verde" : "escala"}`
|
|
8620
8710
|
);
|
|
8711
|
+
if (outcome.success && outcome.appliedEdits && outcome.appliedEdits.length > 0) {
|
|
8712
|
+
for (const line of renderPlanDiff(outcome.appliedEdits)) onLog?.(line);
|
|
8713
|
+
}
|
|
8621
8714
|
try {
|
|
8622
8715
|
const applied = outcome.lastResult?.applied ?? [];
|
|
8623
8716
|
insertEpisodicOutcome(store2.getDb(), {
|
|
@@ -8645,6 +8738,8 @@ var init_live_implement = __esm({
|
|
|
8645
8738
|
init_resolve_adapter();
|
|
8646
8739
|
init_implementation_executor();
|
|
8647
8740
|
init_implement_attempt();
|
|
8741
|
+
init_exec_policy();
|
|
8742
|
+
init_diff_render();
|
|
8648
8743
|
init_code_store();
|
|
8649
8744
|
init_repo_map();
|
|
8650
8745
|
init_flow_compact();
|
|
@@ -8842,6 +8937,22 @@ var init_history = __esm({
|
|
|
8842
8937
|
}
|
|
8843
8938
|
});
|
|
8844
8939
|
|
|
8940
|
+
// src/tui/elapsed.ts
|
|
8941
|
+
function formatElapsed(ms) {
|
|
8942
|
+
const totalSec = Math.max(0, Math.floor(ms / 1e3));
|
|
8943
|
+
const h = Math.floor(totalSec / 3600);
|
|
8944
|
+
const m = Math.floor(totalSec % 3600 / 60);
|
|
8945
|
+
const s = totalSec % 60;
|
|
8946
|
+
if (h > 0) return `${h}h ${String(m).padStart(2, "0")}m`;
|
|
8947
|
+
if (m > 0) return `${m}m ${String(s).padStart(2, "0")}s`;
|
|
8948
|
+
return `${s}s`;
|
|
8949
|
+
}
|
|
8950
|
+
var init_elapsed = __esm({
|
|
8951
|
+
"src/tui/elapsed.ts"() {
|
|
8952
|
+
init_esm_shims();
|
|
8953
|
+
}
|
|
8954
|
+
});
|
|
8955
|
+
|
|
8845
8956
|
// src/tui/dispatch.ts
|
|
8846
8957
|
function parseCommand(input) {
|
|
8847
8958
|
const trimmed = input.trim();
|
|
@@ -8981,7 +9092,15 @@ function InteractiveApp({ dashboard, port, asyncPort, liveRunner, skillCommands
|
|
|
8981
9092
|
const [input, setInput] = useState("");
|
|
8982
9093
|
const [log48, setLog] = useState([]);
|
|
8983
9094
|
const [running, setRunning] = useState(false);
|
|
9095
|
+
const [elapsedMs, setElapsedMs] = useState(0);
|
|
8984
9096
|
const [showHelp, setShowHelp] = useState(false);
|
|
9097
|
+
useEffect(() => {
|
|
9098
|
+
if (!running) return;
|
|
9099
|
+
setElapsedMs(0);
|
|
9100
|
+
const startedAt = Date.now();
|
|
9101
|
+
const t = setInterval(() => setElapsedMs(Date.now() - startedAt), 1e3);
|
|
9102
|
+
return () => clearInterval(t);
|
|
9103
|
+
}, [running]);
|
|
8985
9104
|
const [history, setHistory] = useState([]);
|
|
8986
9105
|
const [histCursor, setHistCursor] = useState(-1);
|
|
8987
9106
|
const [draft, setDraft] = useState("");
|
|
@@ -9054,7 +9173,10 @@ ${skill.body}` : `Skill n\xE3o encontrada: ${parsed.cmd}`);
|
|
|
9054
9173
|
] }),
|
|
9055
9174
|
running && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
9056
9175
|
/* @__PURE__ */ jsx(Spinner, { type: "dots" }),
|
|
9057
|
-
" executando\u2026"
|
|
9176
|
+
" executando\u2026 ",
|
|
9177
|
+
formatElapsed(elapsedMs),
|
|
9178
|
+
" \xB7 ",
|
|
9179
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Esc para interromper" })
|
|
9058
9180
|
] }) }),
|
|
9059
9181
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(CommandBar, { value: input, onChange: setInput, onSubmit: submit, suggestions: filterCommands(input, skillCommands) }) })
|
|
9060
9182
|
] });
|
|
@@ -9067,6 +9189,7 @@ var init_interactive_app = __esm({
|
|
|
9067
9189
|
init_banner_screen();
|
|
9068
9190
|
init_command_bar();
|
|
9069
9191
|
init_history();
|
|
9192
|
+
init_elapsed();
|
|
9070
9193
|
init_dispatch();
|
|
9071
9194
|
MAX_LOG_LINES = 12;
|
|
9072
9195
|
}
|
|
@@ -9717,15 +9840,15 @@ function meanPoolAndNormalize(data, validTokens, dim) {
|
|
|
9717
9840
|
embedding[dVar] += data[tVar * dim + dVar];
|
|
9718
9841
|
}
|
|
9719
9842
|
}
|
|
9720
|
-
let
|
|
9843
|
+
let norm2 = 0;
|
|
9721
9844
|
for (let dVar = 0; dVar < dim; dVar++) {
|
|
9722
9845
|
embedding[dVar] /= validTokens;
|
|
9723
|
-
|
|
9846
|
+
norm2 += embedding[dVar] * embedding[dVar];
|
|
9724
9847
|
}
|
|
9725
|
-
|
|
9726
|
-
if (
|
|
9848
|
+
norm2 = Math.sqrt(norm2);
|
|
9849
|
+
if (norm2 > 0) {
|
|
9727
9850
|
for (let dVar = 0; dVar < dim; dVar++) {
|
|
9728
|
-
embedding[dVar] /=
|
|
9851
|
+
embedding[dVar] /= norm2;
|
|
9729
9852
|
}
|
|
9730
9853
|
}
|
|
9731
9854
|
return embedding;
|
|
@@ -11217,7 +11340,7 @@ init_store_port();
|
|
|
11217
11340
|
// src/cli/shared/enable-flow.ts
|
|
11218
11341
|
init_esm_shims();
|
|
11219
11342
|
init_flow_config();
|
|
11220
|
-
function
|
|
11343
|
+
function setFlowEnabled(store2, enabled) {
|
|
11221
11344
|
const raw = store2.getProjectSetting(FLOW_CONFIG_SETTING_KEY);
|
|
11222
11345
|
let current = {};
|
|
11223
11346
|
if (raw) {
|
|
@@ -11227,24 +11350,88 @@ function enableFlowConfig(store2) {
|
|
|
11227
11350
|
current = {};
|
|
11228
11351
|
}
|
|
11229
11352
|
}
|
|
11230
|
-
store2.setProjectSetting(FLOW_CONFIG_SETTING_KEY, JSON.stringify({ ...current, enabled
|
|
11353
|
+
store2.setProjectSetting(FLOW_CONFIG_SETTING_KEY, JSON.stringify({ ...current, enabled }));
|
|
11354
|
+
}
|
|
11355
|
+
function enableFlowConfig(store2) {
|
|
11356
|
+
setFlowEnabled(store2, true);
|
|
11231
11357
|
}
|
|
11358
|
+
|
|
11359
|
+
// src/cli/commands/profile-cmd.ts
|
|
11360
|
+
init_esm_shims();
|
|
11361
|
+
|
|
11362
|
+
// src/core/config/profiles.ts
|
|
11363
|
+
init_esm_shims();
|
|
11364
|
+
var BUILT_IN_PROFILES = {
|
|
11365
|
+
fast: { modelTier: "cheap", flow: false, retries: 1 },
|
|
11366
|
+
build: { modelTier: "build", flow: true, retries: 2 },
|
|
11367
|
+
frontier: { modelTier: "frontier", flow: true, retries: 3 }
|
|
11368
|
+
};
|
|
11369
|
+
function resolveProfile(name) {
|
|
11370
|
+
return BUILT_IN_PROFILES[name];
|
|
11371
|
+
}
|
|
11372
|
+
function listProfiles() {
|
|
11373
|
+
return Object.keys(BUILT_IN_PROFILES);
|
|
11374
|
+
}
|
|
11375
|
+
|
|
11376
|
+
// src/cli/commands/profile-cmd.ts
|
|
11377
|
+
init_tier_router();
|
|
11232
11378
|
function output7(msg) {
|
|
11233
11379
|
process.stdout.write(msg + "\n");
|
|
11234
11380
|
}
|
|
11381
|
+
function applyProfile(store2, name) {
|
|
11382
|
+
const profile = resolveProfile(name);
|
|
11383
|
+
if (!profile) return void 0;
|
|
11384
|
+
store2.setProjectSetting("model", resolveTierModel(profile.modelTier));
|
|
11385
|
+
setFlowEnabled(store2, profile.flow);
|
|
11386
|
+
return profile;
|
|
11387
|
+
}
|
|
11388
|
+
function profileCommand() {
|
|
11389
|
+
const cmd = new Command("profile").description("Bundles de trabalho: tier de modelo + flow + retries");
|
|
11390
|
+
cmd.command("list").description("Lista os profiles dispon\xEDveis").action(() => {
|
|
11391
|
+
for (const name of listProfiles()) {
|
|
11392
|
+
const p = BUILT_IN_PROFILES[name];
|
|
11393
|
+
output7(`${name.padEnd(10)} tier=${p.modelTier} flow=${p.flow} retries=${p.retries}`);
|
|
11394
|
+
}
|
|
11395
|
+
});
|
|
11396
|
+
cmd.command("show <nome>").description("Detalha um profile").action((nome) => {
|
|
11397
|
+
const p = resolveProfile(nome);
|
|
11398
|
+
if (!p) {
|
|
11399
|
+
output7(`Profile desconhecido: ${nome}. Tente 'profile list'.`);
|
|
11400
|
+
process.exitCode = 1;
|
|
11401
|
+
return;
|
|
11402
|
+
}
|
|
11403
|
+
output7(`${nome}: tier=${p.modelTier} \xB7 flow=${p.flow} \xB7 retries=${p.retries} \xB7 modelo=${resolveTierModel(p.modelTier)}`);
|
|
11404
|
+
});
|
|
11405
|
+
return cmd;
|
|
11406
|
+
}
|
|
11407
|
+
function output8(msg) {
|
|
11408
|
+
process.stdout.write(msg + "\n");
|
|
11409
|
+
}
|
|
11235
11410
|
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(
|
|
11411
|
+
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
11412
|
async (opts) => {
|
|
11238
11413
|
const store2 = openStoreOrFail(opts.dir, { requireExisting: true });
|
|
11239
11414
|
try {
|
|
11240
11415
|
const maxIterations = Math.max(1, parseInt(opts.max, 10) || 5);
|
|
11241
11416
|
const port = makeStorePort(store2);
|
|
11417
|
+
let retriesOverride;
|
|
11418
|
+
if (opts.profile) {
|
|
11419
|
+
const applied = applyProfile(store2, opts.profile);
|
|
11420
|
+
if (!applied) {
|
|
11421
|
+
output8(`Profile desconhecido: ${opts.profile}. Tente 'profile list'.`);
|
|
11422
|
+
store2.close();
|
|
11423
|
+
return;
|
|
11424
|
+
}
|
|
11425
|
+
retriesOverride = applied.retries;
|
|
11426
|
+
output8(`[PROFILE] ${opts.profile}: tier=${applied.modelTier} flow=${applied.flow} retries=${applied.retries}
|
|
11427
|
+
`);
|
|
11428
|
+
}
|
|
11242
11429
|
if (opts.flow) {
|
|
11243
11430
|
enableFlowConfig(store2);
|
|
11244
|
-
|
|
11431
|
+
output8("[FLOW] \u03BB_flow ativo: contexto do grafo dilu\xEDdo por \u03A6(t) (esquecimento din\xE2mico).\n");
|
|
11245
11432
|
}
|
|
11246
|
-
if (opts.simulate)
|
|
11247
|
-
if (opts.live)
|
|
11433
|
+
if (opts.simulate) output8("[SIMULA\xC7\xC3O] impl tratada como verde \u2014 DoD real decide prontid\xE3o.\n");
|
|
11434
|
+
if (opts.live) output8("[LIVE] modelo via SDK do Copilot: gera plano \u2192 aplica no workspace \u2192 roda testes.\n");
|
|
11248
11435
|
let implement;
|
|
11249
11436
|
let ledger;
|
|
11250
11437
|
if (opts.live) {
|
|
@@ -11253,11 +11440,11 @@ function autopilotCommand() {
|
|
|
11253
11440
|
store: store2,
|
|
11254
11441
|
dir: opts.dir,
|
|
11255
11442
|
testCmd: opts.testCmd,
|
|
11256
|
-
retries: parseInt(opts.retries, 10) || 2,
|
|
11443
|
+
retries: retriesOverride ?? (parseInt(opts.retries, 10) || 2),
|
|
11257
11444
|
ledger,
|
|
11258
|
-
onLog:
|
|
11445
|
+
onLog: output8
|
|
11259
11446
|
});
|
|
11260
|
-
if (live.repoSymbolCount > 0)
|
|
11447
|
+
if (live.repoSymbolCount > 0) output8(`[LIVE] repo-map: ${live.repoSymbolCount} s\xEDmbolo(s) indexado(s).`);
|
|
11261
11448
|
implement = live.implement;
|
|
11262
11449
|
} else if (opts.simulate) {
|
|
11263
11450
|
implement = () => true;
|
|
@@ -11267,28 +11454,28 @@ function autopilotCommand() {
|
|
|
11267
11454
|
const result = await runAutopilot(port, { maxIterations, implement });
|
|
11268
11455
|
for (const s of result.steps) {
|
|
11269
11456
|
const icon = s.action === "done" ? "\u2713" : s.action === "escalated" ? "\u26A0" : "\u2192";
|
|
11270
|
-
|
|
11457
|
+
output8(`${icon} ${s.nodeId} ${s.title} [${s.action}] ${s.detail}`);
|
|
11271
11458
|
}
|
|
11272
|
-
|
|
11459
|
+
output8(`
|
|
11273
11460
|
Resumo: ${result.completed} conclu\xEDda(s), ${result.escalated} escalada(s). Parou: ${result.stopped}`);
|
|
11274
11461
|
if (ledger) {
|
|
11275
11462
|
const totals = ledger.totals();
|
|
11276
|
-
|
|
11463
|
+
output8(`
|
|
11277
11464
|
Tokens (sess\xE3o): ${totals.total} (in ${totals.tokensIn} / out ${totals.tokensOut}) em ${totals.calls} chamada(s)`);
|
|
11278
11465
|
for (const t of ledger.tasks()) {
|
|
11279
|
-
|
|
11466
|
+
output8(` ${t.nodeId}: ${t.total} tok (in ${t.tokensIn} / out ${t.tokensOut}, ${t.calls} chamada(s))`);
|
|
11280
11467
|
}
|
|
11281
11468
|
if (result.completed > 0) {
|
|
11282
|
-
|
|
11469
|
+
output8(` m\xE9dia/task conclu\xEDda: ${Math.round(totals.total / result.completed)} tok`);
|
|
11283
11470
|
}
|
|
11284
11471
|
if (totals.calls > 0) {
|
|
11285
11472
|
const sessionId = `autopilot_${randomUUID().replace(/-/g, "").slice(0, 12)}`;
|
|
11286
11473
|
const rows = persistLedger(store2.getDb(), ledger, { sessionId, provider: "copilot" });
|
|
11287
|
-
|
|
11474
|
+
output8(` ${rows} chamada(s) persistida(s) (session ${sessionId})`);
|
|
11288
11475
|
}
|
|
11289
11476
|
}
|
|
11290
11477
|
if (!opts.simulate && !opts.live && result.stopped === "escalation") {
|
|
11291
|
-
|
|
11478
|
+
output8("\nDica: --simulate exercita o loop + gate DoD; --live invoca o modelo real via SDK do Copilot.");
|
|
11292
11479
|
}
|
|
11293
11480
|
} finally {
|
|
11294
11481
|
store2.close();
|
|
@@ -11301,7 +11488,7 @@ Tokens (sess\xE3o): ${totals.total} (in ${totals.tokensIn} / out ${totals.tokens
|
|
|
11301
11488
|
init_esm_shims();
|
|
11302
11489
|
init_tier_router();
|
|
11303
11490
|
var SETTING_KEY = "model";
|
|
11304
|
-
function
|
|
11491
|
+
function output9(msg) {
|
|
11305
11492
|
process.stdout.write(msg + "\n");
|
|
11306
11493
|
}
|
|
11307
11494
|
function readConfig(dir) {
|
|
@@ -11318,29 +11505,29 @@ function modelCommand() {
|
|
|
11318
11505
|
"Seleciona/inspeciona o modelo do tier-router (pool do Copilot CLI; 'auto' roteia por tarefa)"
|
|
11319
11506
|
);
|
|
11320
11507
|
cmd.command("list").description("Lista o pool agrupado por tier").action(() => {
|
|
11321
|
-
|
|
11508
|
+
output9("auto \u2014 roteia por tarefa (cheap classifica \xB7 build implementa \xB7 frontier planeja)\n");
|
|
11322
11509
|
for (const tier of MODEL_TIERS) {
|
|
11323
|
-
|
|
11510
|
+
output9(`[${tier}]`);
|
|
11324
11511
|
for (const m of modelsForTier(tier)) {
|
|
11325
11512
|
const mark = m.id === DEFAULT_MODEL ? " (default)" : "";
|
|
11326
|
-
|
|
11513
|
+
output9(` ${m.id} \u2014 ${m.label}${mark}`);
|
|
11327
11514
|
}
|
|
11328
11515
|
}
|
|
11329
11516
|
});
|
|
11330
11517
|
cmd.command("current").description("Mostra o modelo/modo selecionado").option("-d, --dir <dir>", "Diret\xF3rio do projeto", process.cwd()).action((opts) => {
|
|
11331
11518
|
const config = readConfig(opts.dir);
|
|
11332
|
-
|
|
11519
|
+
output9(config.mode === "auto" ? "auto (roteamento por tarefa)" : `pinned: ${config.modelId}`);
|
|
11333
11520
|
});
|
|
11334
11521
|
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
11522
|
const value = idOrAuto.trim();
|
|
11336
11523
|
if (value !== "auto" && !isKnownModel(value)) {
|
|
11337
|
-
|
|
11524
|
+
output9(`Modelo desconhecido: "${value}". Rode 'model list' para ver o pool.`);
|
|
11338
11525
|
process.exit(1);
|
|
11339
11526
|
}
|
|
11340
11527
|
const store2 = openStoreOrFail(opts.dir, { requireExisting: true });
|
|
11341
11528
|
try {
|
|
11342
11529
|
store2.setProjectSetting(SETTING_KEY, value);
|
|
11343
|
-
|
|
11530
|
+
output9(value === "auto" ? "Modo: auto (roteamento por tarefa)." : `Modelo fixado: ${value}.`);
|
|
11344
11531
|
} finally {
|
|
11345
11532
|
store2.close();
|
|
11346
11533
|
}
|
|
@@ -11348,11 +11535,11 @@ function modelCommand() {
|
|
|
11348
11535
|
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
11536
|
const parsed = TaskKindSchema.safeParse(kind);
|
|
11350
11537
|
if (!parsed.success) {
|
|
11351
|
-
|
|
11538
|
+
output9(`Tipo inv\xE1lido: "${kind}". Esperado: ${TaskKindSchema.options.join(", ")}.`);
|
|
11352
11539
|
process.exit(1);
|
|
11353
11540
|
}
|
|
11354
11541
|
const config = readConfig(opts.dir);
|
|
11355
|
-
|
|
11542
|
+
output9(`${kind} \u2192 ${routeModel(config, parsed.data)}`);
|
|
11356
11543
|
});
|
|
11357
11544
|
return cmd;
|
|
11358
11545
|
}
|
|
@@ -11360,7 +11547,7 @@ function modelCommand() {
|
|
|
11360
11547
|
// src/cli/commands/metrics-cmd.ts
|
|
11361
11548
|
init_esm_shims();
|
|
11362
11549
|
init_llm_call_ledger();
|
|
11363
|
-
function
|
|
11550
|
+
function output10(msg) {
|
|
11364
11551
|
process.stdout.write(msg + "\n");
|
|
11365
11552
|
}
|
|
11366
11553
|
function metricsCommand() {
|
|
@@ -11369,30 +11556,30 @@ function metricsCommand() {
|
|
|
11369
11556
|
try {
|
|
11370
11557
|
const summary = summarizeLedger(store2.getDb(), { sessionId: opts.session });
|
|
11371
11558
|
if (summary.totals.calls === 0) {
|
|
11372
|
-
|
|
11559
|
+
output10("Sem chamadas de modelo registradas. Rode `autopilot --live` para gerar m\xE9tricas.");
|
|
11373
11560
|
return;
|
|
11374
11561
|
}
|
|
11375
11562
|
const usd = (n) => `$${n.toFixed(4)}`;
|
|
11376
11563
|
const { totals } = summary;
|
|
11377
11564
|
const taskCount = summary.byTask.length;
|
|
11378
11565
|
const avgCost = taskCount > 0 ? totals.costUsd / taskCount : 0;
|
|
11379
|
-
|
|
11380
|
-
|
|
11381
|
-
|
|
11566
|
+
output10(`Tokens totais: ${totals.total} (in ${totals.tokensIn} / out ${totals.tokensOut}) em ${totals.calls} chamada(s)`);
|
|
11567
|
+
output10(`Custo total: \u2248 ${usd(totals.costUsd)}`);
|
|
11568
|
+
output10(`M\xE9dia por task: ${summary.avgTokensPerTask} tok \u2248 ${usd(avgCost)} | ${taskCount} task(s), ${summary.bySession.length} sess\xE3o(\xF5es)`);
|
|
11382
11569
|
const top = Math.max(1, parseInt(opts.top, 10) || 10);
|
|
11383
|
-
|
|
11570
|
+
output10(`
|
|
11384
11571
|
Tokens por task (top ${top}):`);
|
|
11385
11572
|
for (const t of summary.byTask.slice(0, top)) {
|
|
11386
|
-
|
|
11573
|
+
output10(` ${t.nodeId}: ${t.total} tok \u2248 ${usd(t.costUsd)} (in ${t.tokensIn} / out ${t.tokensOut}, ${t.calls} chamada(s))`);
|
|
11387
11574
|
}
|
|
11388
11575
|
if (!opts.session) {
|
|
11389
|
-
|
|
11576
|
+
output10("\nTokens por sess\xE3o:");
|
|
11390
11577
|
for (const s of summary.bySession) {
|
|
11391
|
-
|
|
11578
|
+
output10(` ${s.sessionId}: ${s.total} tok \u2248 ${usd(s.costUsd)} (${s.calls} chamada(s))`);
|
|
11392
11579
|
}
|
|
11393
11580
|
}
|
|
11394
11581
|
if (totals.costUsd === 0) {
|
|
11395
|
-
|
|
11582
|
+
output10("\nNota: custo $0 \u2014 modelos usados n\xE3o t\xEAm pre\xE7o cadastrado (ver cost-tracker MODEL_PRICING).");
|
|
11396
11583
|
}
|
|
11397
11584
|
} finally {
|
|
11398
11585
|
store2.close();
|
|
@@ -11407,7 +11594,7 @@ init_resolve_adapter();
|
|
|
11407
11594
|
init_implementation_executor();
|
|
11408
11595
|
init_implement_attempt();
|
|
11409
11596
|
init_token_ledger();
|
|
11410
|
-
function
|
|
11597
|
+
function output11(msg) {
|
|
11411
11598
|
process.stdout.write(msg + "\n");
|
|
11412
11599
|
}
|
|
11413
11600
|
function runCommand() {
|
|
@@ -11418,7 +11605,7 @@ function runCommand() {
|
|
|
11418
11605
|
const maxAttempts = Math.max(1, parseInt(opts.retries, 10) || 2);
|
|
11419
11606
|
const ledger = new TokenLedger();
|
|
11420
11607
|
const node = { id: `run_${randomUUID().replace(/-/g, "").slice(0, 8)}`, title: prompt };
|
|
11421
|
-
|
|
11608
|
+
output11(`[run] ${client.modelFor("implement")} via ${resolved.kind === "api" ? "API HTTP" : "CLI"} \u2192 "${prompt}"`);
|
|
11422
11609
|
const outcome = await attemptImplementation(
|
|
11423
11610
|
{
|
|
11424
11611
|
generate: async (p) => {
|
|
@@ -11438,7 +11625,7 @@ function runCommand() {
|
|
|
11438
11625
|
);
|
|
11439
11626
|
const files = outcome.lastResult?.applied.length ?? 0;
|
|
11440
11627
|
const totals = ledger.totals();
|
|
11441
|
-
|
|
11628
|
+
output11(
|
|
11442
11629
|
`${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
11630
|
);
|
|
11444
11631
|
if (!outcome.success) process.exitCode = 1;
|
|
@@ -11462,7 +11649,7 @@ function tuiCommand() {
|
|
|
11462
11649
|
// src/cli/commands/login-cmd.ts
|
|
11463
11650
|
init_esm_shims();
|
|
11464
11651
|
init_copilot_auth();
|
|
11465
|
-
function
|
|
11652
|
+
function output12(msg) {
|
|
11466
11653
|
process.stdout.write(msg + "\n");
|
|
11467
11654
|
}
|
|
11468
11655
|
function loginCommand() {
|
|
@@ -11470,15 +11657,15 @@ function loginCommand() {
|
|
|
11470
11657
|
const path22 = defaultAuthPath();
|
|
11471
11658
|
if (opts.token) {
|
|
11472
11659
|
saveAuth(path22, { githubToken: opts.token });
|
|
11473
|
-
|
|
11660
|
+
output12(`\u2713 Token salvo em ${path22}. Provider HTTP do Copilot habilitado.`);
|
|
11474
11661
|
return;
|
|
11475
11662
|
}
|
|
11476
11663
|
const device = await requestDeviceCode(globalThis.fetch);
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11664
|
+
output12("\nPara autenticar, abra:");
|
|
11665
|
+
output12(` ${device.verificationUri}`);
|
|
11666
|
+
output12(`e informe o c\xF3digo: \x1B[1m${device.userCode}\x1B[0m
|
|
11480
11667
|
`);
|
|
11481
|
-
|
|
11668
|
+
output12("Aguardando autoriza\xE7\xE3o\u2026 (Ctrl+C para cancelar)");
|
|
11482
11669
|
const deadline = Date.now() + device.expiresIn * 1e3;
|
|
11483
11670
|
let interval = Math.max(1, device.interval);
|
|
11484
11671
|
while (Date.now() < deadline) {
|
|
@@ -11486,13 +11673,13 @@ function loginCommand() {
|
|
|
11486
11673
|
const r = await pollForAccessToken(globalThis.fetch, device.deviceCode);
|
|
11487
11674
|
if ("accessToken" in r) {
|
|
11488
11675
|
saveAuth(path22, { githubToken: r.accessToken });
|
|
11489
|
-
|
|
11676
|
+
output12(`
|
|
11490
11677
|
\u2713 Autenticado. Token salvo em ${path22}. Provider HTTP do Copilot habilitado.`);
|
|
11491
11678
|
return;
|
|
11492
11679
|
}
|
|
11493
11680
|
if ("slowDown" in r) interval += 5;
|
|
11494
11681
|
}
|
|
11495
|
-
|
|
11682
|
+
output12("\n\u26A0 Tempo esgotado sem autoriza\xE7\xE3o. Rode `agf login` de novo.");
|
|
11496
11683
|
process.exitCode = 1;
|
|
11497
11684
|
});
|
|
11498
11685
|
}
|
|
@@ -11501,9 +11688,9 @@ function logoutCommand() {
|
|
|
11501
11688
|
const path22 = defaultAuthPath();
|
|
11502
11689
|
if (existsSync(path22) && loadAuth(path22)) {
|
|
11503
11690
|
rmSync(path22, { force: true });
|
|
11504
|
-
|
|
11691
|
+
output12(`\u2713 Logout \u2014 ${path22} removido.`);
|
|
11505
11692
|
} else {
|
|
11506
|
-
|
|
11693
|
+
output12("Nenhum login salvo.");
|
|
11507
11694
|
}
|
|
11508
11695
|
});
|
|
11509
11696
|
}
|
|
@@ -14164,7 +14351,7 @@ function reapDaemons(options = {}) {
|
|
|
14164
14351
|
// src/cli/commands/daemon-cmd.ts
|
|
14165
14352
|
init_logger();
|
|
14166
14353
|
var log44 = createLogger({ layer: "cli", source: "daemon.ts" });
|
|
14167
|
-
function
|
|
14354
|
+
function output13(msg) {
|
|
14168
14355
|
process.stdout.write(msg + "\n");
|
|
14169
14356
|
}
|
|
14170
14357
|
function daemonCommand() {
|
|
@@ -14175,23 +14362,23 @@ function daemonCommand() {
|
|
|
14175
14362
|
const prefix = opts.dryRun ? "[dry-run] " : "";
|
|
14176
14363
|
for (const a of report.actions) {
|
|
14177
14364
|
if (a.outcome === "kept") continue;
|
|
14178
|
-
|
|
14365
|
+
output13(`${prefix}${a.outcome}: ${a.stateDir}${a.pid ? ` (pid=${a.pid})` : ""} \u2014 ${a.reason}`);
|
|
14179
14366
|
}
|
|
14180
|
-
|
|
14367
|
+
output13(
|
|
14181
14368
|
`${prefix}daemon prune: scanned ${report.scanned}, killed ${report.killed}, removed ${report.removed}, kept ${report.kept}`
|
|
14182
14369
|
);
|
|
14183
14370
|
});
|
|
14184
14371
|
cmd.command("list").description("List daemon state directories and their status (read-only)").action(() => {
|
|
14185
14372
|
const report = reapDaemons({ dryRun: true });
|
|
14186
14373
|
if (report.scanned === 0) {
|
|
14187
|
-
|
|
14374
|
+
output13("daemon list: no daemon state directories found");
|
|
14188
14375
|
return;
|
|
14189
14376
|
}
|
|
14190
14377
|
for (const a of report.actions) {
|
|
14191
14378
|
const would = a.outcome === "kept" ? "alive" : `stale \u2192 would ${a.outcome}`;
|
|
14192
|
-
|
|
14379
|
+
output13(`${would}: ${a.stateDir}${a.pid ? ` (pid=${a.pid})` : ""} \u2014 ${a.reason}`);
|
|
14193
14380
|
}
|
|
14194
|
-
|
|
14381
|
+
output13(`daemon list: ${report.scanned} state dir(s), ${report.kept} alive`);
|
|
14195
14382
|
});
|
|
14196
14383
|
return cmd;
|
|
14197
14384
|
}
|
|
@@ -14243,7 +14430,7 @@ function formatProviderReport(report) {
|
|
|
14243
14430
|
init_errors();
|
|
14244
14431
|
init_logger();
|
|
14245
14432
|
var log45 = createLogger({ layer: "cli", source: "doctor.ts" });
|
|
14246
|
-
function
|
|
14433
|
+
function output14(msg) {
|
|
14247
14434
|
process.stdout.write(msg + "\n");
|
|
14248
14435
|
}
|
|
14249
14436
|
var LEVEL_ICON2 = {
|
|
@@ -14266,31 +14453,31 @@ function doctorCommand() {
|
|
|
14266
14453
|
if (opts.providers) {
|
|
14267
14454
|
const providerReport = checkProviders();
|
|
14268
14455
|
if (opts.json) {
|
|
14269
|
-
|
|
14456
|
+
output14(JSON.stringify(providerReport, null, 2));
|
|
14270
14457
|
} else {
|
|
14271
|
-
|
|
14458
|
+
output14("mcp-graph doctor \u2014 LLM providers\n");
|
|
14272
14459
|
for (const line of formatProviderReport(providerReport)) {
|
|
14273
|
-
|
|
14460
|
+
output14(line);
|
|
14274
14461
|
}
|
|
14275
14462
|
}
|
|
14276
14463
|
return;
|
|
14277
14464
|
}
|
|
14278
14465
|
const report = await runDoctor(opts.dir);
|
|
14279
14466
|
if (opts.json) {
|
|
14280
|
-
|
|
14467
|
+
output14(JSON.stringify(report, null, 2));
|
|
14281
14468
|
} else {
|
|
14282
|
-
|
|
14469
|
+
output14("mcp-graph doctor\n");
|
|
14283
14470
|
for (const check of report.checks) {
|
|
14284
|
-
|
|
14471
|
+
output14(formatCheck(check));
|
|
14285
14472
|
}
|
|
14286
|
-
|
|
14287
|
-
|
|
14473
|
+
output14("");
|
|
14474
|
+
output14(
|
|
14288
14475
|
`Summary: ${report.summary.ok} ok, ${report.summary.warning} warnings, ${report.summary.error} errors`
|
|
14289
14476
|
);
|
|
14290
14477
|
if (report.passed) {
|
|
14291
|
-
|
|
14478
|
+
output14("\nAll critical checks passed.");
|
|
14292
14479
|
} else {
|
|
14293
|
-
|
|
14480
|
+
output14("\nSome critical checks failed. Fix errors above.");
|
|
14294
14481
|
}
|
|
14295
14482
|
}
|
|
14296
14483
|
if (!report.passed) {
|
|
@@ -14374,13 +14561,13 @@ function pruneOrphanWorktrees(options) {
|
|
|
14374
14561
|
}
|
|
14375
14562
|
}
|
|
14376
14563
|
try {
|
|
14377
|
-
const
|
|
14564
|
+
const output17 = execSync("git worktree prune --verbose", execOpts).toString();
|
|
14378
14565
|
if (reapedBranches > 0 || reapedWorktrees > 0) {
|
|
14379
14566
|
log46.info("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, ttlMs });
|
|
14380
14567
|
} else {
|
|
14381
|
-
log46.debug("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, output:
|
|
14568
|
+
log46.debug("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, output: output17 });
|
|
14382
14569
|
}
|
|
14383
|
-
return { pruned: true, reapedBranches, reapedWorktrees, output:
|
|
14570
|
+
return { pruned: true, reapedBranches, reapedWorktrees, output: output17 };
|
|
14384
14571
|
} catch (err) {
|
|
14385
14572
|
const error = String(err);
|
|
14386
14573
|
log46.debug("shadow-branch:prune-failed", { error });
|
|
@@ -14391,7 +14578,7 @@ function pruneOrphanWorktrees(options) {
|
|
|
14391
14578
|
// src/cli/commands/gc-cmd.ts
|
|
14392
14579
|
init_logger();
|
|
14393
14580
|
var log47 = createLogger({ layer: "cli", source: "gc.ts" });
|
|
14394
|
-
function
|
|
14581
|
+
function output15(msg) {
|
|
14395
14582
|
process.stdout.write(msg + "\n");
|
|
14396
14583
|
}
|
|
14397
14584
|
function gcCommand() {
|
|
@@ -14401,9 +14588,9 @@ function gcCommand() {
|
|
|
14401
14588
|
log47.info("cli:gc:start", { dir: opts.dir, ttlMs });
|
|
14402
14589
|
const result = pruneOrphanWorktrees({ cwd: opts.dir, ttlMs });
|
|
14403
14590
|
if (result.pruned) {
|
|
14404
|
-
|
|
14591
|
+
output15(`gc: reaped ${result.reapedBranches} branches, ${result.reapedWorktrees} worktrees`);
|
|
14405
14592
|
} else {
|
|
14406
|
-
|
|
14593
|
+
output15(`gc: failed \u2014 ${result.error ?? "unknown error"}`);
|
|
14407
14594
|
process.exit(1);
|
|
14408
14595
|
}
|
|
14409
14596
|
});
|
|
@@ -14412,7 +14599,7 @@ function gcCommand() {
|
|
|
14412
14599
|
// src/cli/commands/skill-cmd.ts
|
|
14413
14600
|
init_esm_shims();
|
|
14414
14601
|
init_skill_registry();
|
|
14415
|
-
function
|
|
14602
|
+
function output16(msg) {
|
|
14416
14603
|
process.stdout.write(msg + "\n");
|
|
14417
14604
|
}
|
|
14418
14605
|
function skillCommand() {
|
|
@@ -14426,26 +14613,26 @@ function skillCommand() {
|
|
|
14426
14613
|
if (seen.has(s.name)) continue;
|
|
14427
14614
|
seen.add(s.name);
|
|
14428
14615
|
count += 1;
|
|
14429
|
-
|
|
14616
|
+
output16(`${s.name.padEnd(28)} [${s.category}] ${s.description}`);
|
|
14430
14617
|
}
|
|
14431
14618
|
}
|
|
14432
|
-
if (count === 0)
|
|
14433
|
-
else
|
|
14619
|
+
if (count === 0) output16("Nenhuma skill encontrada.");
|
|
14620
|
+
else output16(`
|
|
14434
14621
|
${count} skill(s).`);
|
|
14435
14622
|
});
|
|
14436
14623
|
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
14624
|
for (const root of defaultSkillRoots(opts.dir)) {
|
|
14438
14625
|
const found = invokeSkill(root, nome);
|
|
14439
14626
|
if (found) {
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
if (found.phases.length > 0)
|
|
14443
|
-
|
|
14444
|
-
|
|
14627
|
+
output16(`=== ${found.name} ===`);
|
|
14628
|
+
output16(`[${found.category}] ${found.description}`);
|
|
14629
|
+
if (found.phases.length > 0) output16(`fases: ${found.phases.join(", ")}`);
|
|
14630
|
+
output16("");
|
|
14631
|
+
output16(found.body);
|
|
14445
14632
|
return;
|
|
14446
14633
|
}
|
|
14447
14634
|
}
|
|
14448
|
-
|
|
14635
|
+
output16(`Skill n\xE3o encontrada: ${nome}. Tente 'skill list'.`);
|
|
14449
14636
|
process.exitCode = 1;
|
|
14450
14637
|
});
|
|
14451
14638
|
return cmd;
|
|
@@ -14472,6 +14659,7 @@ program.addCommand(daemonCommand());
|
|
|
14472
14659
|
program.addCommand(doctorCommand());
|
|
14473
14660
|
program.addCommand(gcCommand());
|
|
14474
14661
|
program.addCommand(skillCommand());
|
|
14662
|
+
program.addCommand(profileCommand());
|
|
14475
14663
|
function shouldLaunchTui() {
|
|
14476
14664
|
const noArgs = process.argv.length <= 2;
|
|
14477
14665
|
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
|
+
"version": "0.4.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",
|