@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.
- package/dist/cli/index.js +301 -96
- 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, 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
|
|
7095
|
-
return { exitCode: 0, output:
|
|
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
|
-
|
|
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
|
|
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
|
|
9019
|
-
|
|
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
|
|
9859
|
+
let norm2 = 0;
|
|
9721
9860
|
for (let dVar = 0; dVar < dim; dVar++) {
|
|
9722
9861
|
embedding[dVar] /= validTokens;
|
|
9723
|
-
|
|
9862
|
+
norm2 += embedding[dVar] * embedding[dVar];
|
|
9724
9863
|
}
|
|
9725
|
-
|
|
9726
|
-
if (
|
|
9864
|
+
norm2 = Math.sqrt(norm2);
|
|
9865
|
+
if (norm2 > 0) {
|
|
9727
9866
|
for (let dVar = 0; dVar < dim; dVar++) {
|
|
9728
|
-
embedding[dVar] /=
|
|
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
|
|
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
|
|
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
|
-
|
|
11448
|
+
output8("[FLOW] \u03BB_flow ativo: contexto do grafo dilu\xEDdo por \u03A6(t) (esquecimento din\xE2mico).\n");
|
|
11245
11449
|
}
|
|
11246
|
-
if (opts.simulate)
|
|
11247
|
-
if (opts.live)
|
|
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:
|
|
11462
|
+
onLog: output8
|
|
11259
11463
|
});
|
|
11260
|
-
if (live.repoSymbolCount > 0)
|
|
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
|
-
|
|
11474
|
+
output8(`${icon} ${s.nodeId} ${s.title} [${s.action}] ${s.detail}`);
|
|
11271
11475
|
}
|
|
11272
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11491
|
+
output8(` ${rows} chamada(s) persistida(s) (session ${sessionId})`);
|
|
11288
11492
|
}
|
|
11289
11493
|
}
|
|
11290
11494
|
if (!opts.simulate && !opts.live && result.stopped === "escalation") {
|
|
11291
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
11527
|
+
output9(`[${tier}]`);
|
|
11324
11528
|
for (const m of modelsForTier(tier)) {
|
|
11325
11529
|
const mark = m.id === DEFAULT_MODEL ? " (default)" : "";
|
|
11326
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
11380
|
-
|
|
11381
|
-
|
|
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
|
-
|
|
11587
|
+
output10(`
|
|
11384
11588
|
Tokens por task (top ${top}):`);
|
|
11385
11589
|
for (const t of summary.byTask.slice(0, top)) {
|
|
11386
|
-
|
|
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
|
-
|
|
11593
|
+
output10("\nTokens por sess\xE3o:");
|
|
11390
11594
|
for (const s of summary.bySession) {
|
|
11391
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11708
|
+
output12(`\u2713 Logout \u2014 ${path22} removido.`);
|
|
11505
11709
|
} else {
|
|
11506
|
-
|
|
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
|
|
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
|
-
|
|
14382
|
+
output13(`${prefix}${a.outcome}: ${a.stateDir}${a.pid ? ` (pid=${a.pid})` : ""} \u2014 ${a.reason}`);
|
|
14179
14383
|
}
|
|
14180
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14396
|
+
output13(`${would}: ${a.stateDir}${a.pid ? ` (pid=${a.pid})` : ""} \u2014 ${a.reason}`);
|
|
14193
14397
|
}
|
|
14194
|
-
|
|
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
|
|
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
|
-
|
|
14473
|
+
output14(JSON.stringify(providerReport, null, 2));
|
|
14270
14474
|
} else {
|
|
14271
|
-
|
|
14475
|
+
output14("mcp-graph doctor \u2014 LLM providers\n");
|
|
14272
14476
|
for (const line of formatProviderReport(providerReport)) {
|
|
14273
|
-
|
|
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
|
-
|
|
14484
|
+
output14(JSON.stringify(report, null, 2));
|
|
14281
14485
|
} else {
|
|
14282
|
-
|
|
14486
|
+
output14("mcp-graph doctor\n");
|
|
14283
14487
|
for (const check of report.checks) {
|
|
14284
|
-
|
|
14488
|
+
output14(formatCheck(check));
|
|
14285
14489
|
}
|
|
14286
|
-
|
|
14287
|
-
|
|
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
|
-
|
|
14495
|
+
output14("\nAll critical checks passed.");
|
|
14292
14496
|
} else {
|
|
14293
|
-
|
|
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
|
|
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:
|
|
14585
|
+
log46.debug("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, output: output17 });
|
|
14382
14586
|
}
|
|
14383
|
-
return { pruned: true, reapedBranches, reapedWorktrees, output:
|
|
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
|
|
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
|
-
|
|
14608
|
+
output15(`gc: reaped ${result.reapedBranches} branches, ${result.reapedWorktrees} worktrees`);
|
|
14405
14609
|
} else {
|
|
14406
|
-
|
|
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
|
|
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
|
-
|
|
14633
|
+
output16(`${s.name.padEnd(28)} [${s.category}] ${s.description}`);
|
|
14430
14634
|
}
|
|
14431
14635
|
}
|
|
14432
|
-
if (count === 0)
|
|
14433
|
-
else
|
|
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
|
-
|
|
14441
|
-
|
|
14442
|
-
if (found.phases.length > 0)
|
|
14443
|
-
|
|
14444
|
-
|
|
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
|
-
|
|
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
|
+
"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",
|