@mcp-graph-workflow/agent-graph-flow 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +1274 -268
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
|
11
11
|
import os, { homedir } from 'os';
|
|
12
12
|
import { stat, readFile, access, constants } from 'fs/promises';
|
|
13
13
|
import { execFile, execSync, spawn } from 'child_process';
|
|
14
|
-
import { render, useApp, Box, Text } from 'ink';
|
|
14
|
+
import { render, useApp, useInput, Box, Text } from 'ink';
|
|
15
15
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
16
16
|
import { createElement, useState, useCallback, useEffect } from 'react';
|
|
17
17
|
import TextInput from 'ink-text-input';
|
|
@@ -2863,6 +2863,33 @@ var init_migrations = __esm({
|
|
|
2863
2863
|
FROM events e
|
|
2864
2864
|
WHERE e.kind = 'tool.completed'
|
|
2865
2865
|
AND e.subjectRef_kind = 'mcp.tool';
|
|
2866
|
+
`
|
|
2867
|
+
},
|
|
2868
|
+
{
|
|
2869
|
+
version: 96,
|
|
2870
|
+
// λ_flow (transient-hypofrontality) telemetry. Records, per context call, the
|
|
2871
|
+
// flow state (Φ, λ_flow) and how much topological decay pruned vs. pinned,
|
|
2872
|
+
// tagged flow_on/flow_off for A/B. Telemetry-only — never affects graph state.
|
|
2873
|
+
// Pairs with flow-metrics-store.ts / flow-report.ts.
|
|
2874
|
+
description: "flow_metrics \u2014 \u03BB_flow (hipofrontalidade) A/B telemetry",
|
|
2875
|
+
sql: `
|
|
2876
|
+
CREATE TABLE IF NOT EXISTS flow_metrics (
|
|
2877
|
+
id TEXT PRIMARY KEY,
|
|
2878
|
+
project_id TEXT NOT NULL,
|
|
2879
|
+
node_id TEXT NOT NULL,
|
|
2880
|
+
mode TEXT NOT NULL,
|
|
2881
|
+
phi REAL NOT NULL,
|
|
2882
|
+
lambda REAL NOT NULL,
|
|
2883
|
+
tokens_baseline INTEGER NOT NULL,
|
|
2884
|
+
tokens_actual INTEGER NOT NULL,
|
|
2885
|
+
pruned_count INTEGER NOT NULL,
|
|
2886
|
+
pinned_count INTEGER NOT NULL,
|
|
2887
|
+
created_at INTEGER NOT NULL
|
|
2888
|
+
);
|
|
2889
|
+
CREATE INDEX IF NOT EXISTS idx_flow_metrics_project_created
|
|
2890
|
+
ON flow_metrics(project_id, created_at DESC);
|
|
2891
|
+
CREATE INDEX IF NOT EXISTS idx_flow_metrics_mode
|
|
2892
|
+
ON flow_metrics(mode, created_at DESC);
|
|
2866
2893
|
`
|
|
2867
2894
|
}
|
|
2868
2895
|
];
|
|
@@ -5408,6 +5435,13 @@ function getNodeAcTexts(doc, nodeId) {
|
|
|
5408
5435
|
if (inline.length > 0) return inline;
|
|
5409
5436
|
return _acByParent.get(nodeId) ?? [];
|
|
5410
5437
|
}
|
|
5438
|
+
function getNodeAcFromStore(store2, nodeId) {
|
|
5439
|
+
const node = store2.getNodeById(nodeId);
|
|
5440
|
+
if (!node) return [];
|
|
5441
|
+
const inline = node.acceptanceCriteria ?? [];
|
|
5442
|
+
if (inline.length > 0) return inline;
|
|
5443
|
+
return store2.getChildNodes(nodeId).filter((n) => n.type === "acceptance_criteria").map((n) => n.title);
|
|
5444
|
+
}
|
|
5411
5445
|
function nodeHasAc(doc, nodeId) {
|
|
5412
5446
|
return getNodeAcTexts(doc, nodeId).length > 0;
|
|
5413
5447
|
}
|
|
@@ -6805,9 +6839,15 @@ var init_copilot_sdk_adapter = __esm({
|
|
|
6805
6839
|
init_logger();
|
|
6806
6840
|
log22 = createLogger({ layer: "core", source: "copilot-sdk-adapter.ts" });
|
|
6807
6841
|
ModelAdapterError = class extends McpGraphError {
|
|
6808
|
-
|
|
6842
|
+
/** HTTP status quando a falha veio de uma resposta do provider (p/ classifyLlmError). */
|
|
6843
|
+
status;
|
|
6844
|
+
/** Espera sugerida (ms), derivada de `retry-after` em respostas 429. */
|
|
6845
|
+
retryAfterMs;
|
|
6846
|
+
constructor(message, opts = {}) {
|
|
6809
6847
|
super(`Model adapter error: ${message}`);
|
|
6810
6848
|
this.name = "ModelAdapterError";
|
|
6849
|
+
this.status = opts.status;
|
|
6850
|
+
this.retryAfterMs = opts.retryAfterMs;
|
|
6811
6851
|
}
|
|
6812
6852
|
};
|
|
6813
6853
|
CopilotSdkAdapter = class {
|
|
@@ -6898,9 +6938,16 @@ var init_copilot_api_adapter = __esm({
|
|
|
6898
6938
|
}
|
|
6899
6939
|
if (!res.ok) {
|
|
6900
6940
|
if (res.status === 401 || res.status === 403) {
|
|
6901
|
-
throw new ModelAdapterError("token Copilot expirado/inv\xE1lido (401/403) \u2014 rode `agf login` novamente."
|
|
6941
|
+
throw new ModelAdapterError("token Copilot expirado/inv\xE1lido (401/403) \u2014 rode `agf login` novamente.", {
|
|
6942
|
+
status: res.status
|
|
6943
|
+
});
|
|
6902
6944
|
}
|
|
6903
|
-
|
|
6945
|
+
const retryAfterRaw = res.headers?.get?.("retry-after");
|
|
6946
|
+
const retryAfterMs = retryAfterRaw && Number.isFinite(Number(retryAfterRaw)) ? Math.round(Number(retryAfterRaw) * 1e3) : void 0;
|
|
6947
|
+
throw new ModelAdapterError(`API do Copilot retornou ${res.status}: ${(await res.text()).slice(0, 200)}`, {
|
|
6948
|
+
status: res.status,
|
|
6949
|
+
retryAfterMs
|
|
6950
|
+
});
|
|
6904
6951
|
}
|
|
6905
6952
|
const body = await res.json();
|
|
6906
6953
|
const text = body.choices?.[0]?.message?.content;
|
|
@@ -7044,8 +7091,8 @@ var init_implementation_executor = __esm({
|
|
|
7044
7091
|
};
|
|
7045
7092
|
defaultRunner = (command, cwd) => {
|
|
7046
7093
|
try {
|
|
7047
|
-
const
|
|
7048
|
-
return { exitCode: 0, output:
|
|
7094
|
+
const output16 = execSync(command, { cwd, encoding: "utf8", stdio: "pipe" });
|
|
7095
|
+
return { exitCode: 0, output: output16 };
|
|
7049
7096
|
} catch (err) {
|
|
7050
7097
|
const e = err;
|
|
7051
7098
|
return {
|
|
@@ -7125,11 +7172,89 @@ var init_plan_parser = __esm({
|
|
|
7125
7172
|
}
|
|
7126
7173
|
});
|
|
7127
7174
|
|
|
7175
|
+
// src/core/model-hub/llm-error.ts
|
|
7176
|
+
function readHeader(headers, name) {
|
|
7177
|
+
if (!headers || typeof headers !== "object") return null;
|
|
7178
|
+
const getter = headers.get;
|
|
7179
|
+
if (typeof getter === "function") {
|
|
7180
|
+
const v = getter.call(headers, name);
|
|
7181
|
+
return typeof v === "string" ? v : null;
|
|
7182
|
+
}
|
|
7183
|
+
const lower = name.toLowerCase();
|
|
7184
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
7185
|
+
if (k.toLowerCase() === lower && typeof v === "string") return v;
|
|
7186
|
+
}
|
|
7187
|
+
return null;
|
|
7188
|
+
}
|
|
7189
|
+
function extractStatus(err) {
|
|
7190
|
+
const candidates = [err.status, err.statusCode, err.response?.status];
|
|
7191
|
+
for (const c of candidates) {
|
|
7192
|
+
const n = typeof c === "number" ? c : typeof c === "string" ? Number(c) : NaN;
|
|
7193
|
+
if (Number.isFinite(n) && n >= 100 && n < 600) return n;
|
|
7194
|
+
}
|
|
7195
|
+
if (typeof err.message === "string") {
|
|
7196
|
+
const m = err.message.match(/\b(4\d\d|5\d\d)\b/);
|
|
7197
|
+
if (m) return Number(m[1]);
|
|
7198
|
+
}
|
|
7199
|
+
return void 0;
|
|
7200
|
+
}
|
|
7201
|
+
function resolveRetryAfterMs(err) {
|
|
7202
|
+
if (typeof err.retryAfterMs === "number" && err.retryAfterMs >= 0) return err.retryAfterMs;
|
|
7203
|
+
const headers = err.headers ?? err.response?.headers;
|
|
7204
|
+
const raw = readHeader(headers, "retry-after");
|
|
7205
|
+
if (raw !== null) {
|
|
7206
|
+
const seconds = Number(raw);
|
|
7207
|
+
if (Number.isFinite(seconds) && seconds >= 0) return Math.round(seconds * 1e3);
|
|
7208
|
+
}
|
|
7209
|
+
return DEFAULT_RATE_LIMIT_MS;
|
|
7210
|
+
}
|
|
7211
|
+
function classifyLlmError(err) {
|
|
7212
|
+
const e = err && typeof err === "object" ? err : {};
|
|
7213
|
+
const message = typeof e.message === "string" ? e.message : "";
|
|
7214
|
+
const status = extractStatus(e);
|
|
7215
|
+
if (status === 429) {
|
|
7216
|
+
return { kind: "rate_limit", retryable: true, retryAfterMs: resolveRetryAfterMs(e) };
|
|
7217
|
+
}
|
|
7218
|
+
if (status === 401 || status === 403) {
|
|
7219
|
+
return { kind: "auth", retryable: false };
|
|
7220
|
+
}
|
|
7221
|
+
if (status !== void 0 && status >= 400 && status < 500 && CONTENT_POLICY_RE.test(message)) {
|
|
7222
|
+
return { kind: "content_policy", retryable: false };
|
|
7223
|
+
}
|
|
7224
|
+
if (status !== void 0 && status >= 400 && status < 500) {
|
|
7225
|
+
return { kind: "invalid_request", retryable: false };
|
|
7226
|
+
}
|
|
7227
|
+
if (status !== void 0 && RETRYABLE_5XX.has(status)) {
|
|
7228
|
+
return { kind: "server", retryable: true };
|
|
7229
|
+
}
|
|
7230
|
+
const code = typeof e.code === "string" ? e.code : "";
|
|
7231
|
+
if (NETWORK_CODE.has(code) || status === void 0 && NETWORK_MSG_RE.test(message)) {
|
|
7232
|
+
return { kind: "network", retryable: true };
|
|
7233
|
+
}
|
|
7234
|
+
return { kind: "unknown", retryable: false };
|
|
7235
|
+
}
|
|
7236
|
+
var DEFAULT_RATE_LIMIT_MS, CONTENT_POLICY_RE, NETWORK_CODE, NETWORK_MSG_RE, RETRYABLE_5XX;
|
|
7237
|
+
var init_llm_error = __esm({
|
|
7238
|
+
"src/core/model-hub/llm-error.ts"() {
|
|
7239
|
+
init_esm_shims();
|
|
7240
|
+
DEFAULT_RATE_LIMIT_MS = 1e3;
|
|
7241
|
+
CONTENT_POLICY_RE = /content[_\s-]?filter|content[_\s-]?policy|policy violation|moderat/i;
|
|
7242
|
+
NETWORK_CODE = /* @__PURE__ */ new Set(["ECONNRESET", "ETIMEDOUT", "ECONNREFUSED", "EAI_AGAIN", "EPIPE", "ENOTFOUND"]);
|
|
7243
|
+
NETWORK_MSG_RE = /fetch failed|network|socket hang up|timed? out|timeout|aborted|abort/i;
|
|
7244
|
+
RETRYABLE_5XX = /* @__PURE__ */ new Set([500, 502, 503, 504, 529]);
|
|
7245
|
+
}
|
|
7246
|
+
});
|
|
7247
|
+
|
|
7128
7248
|
// src/core/autonomy/implement-attempt.ts
|
|
7249
|
+
function defaultSleep(ms) {
|
|
7250
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
7251
|
+
}
|
|
7129
7252
|
function buildInitialPrompt(node, opts = {}) {
|
|
7130
7253
|
const repoMapBlock = opts.repoMap && opts.repoMap.length > 0 ? [`Contexto do reposit\xF3rio (refer\xEAncia, n\xE3o reescreva o que j\xE1 existe):`, opts.repoMap, ""] : [];
|
|
7254
|
+
const flowBlock = opts.flowContext && opts.flowContext.length > 0 ? [opts.flowContext, ""] : [];
|
|
7131
7255
|
return [
|
|
7132
7256
|
...repoMapBlock,
|
|
7257
|
+
...flowBlock,
|
|
7133
7258
|
`Implemente a task "${node.title}" (id: ${node.id}) seguindo TDD.`,
|
|
7134
7259
|
"Responda APENAS com um bloco ```json. H\xE1 DOIS mecanismos:",
|
|
7135
7260
|
'- "edits" (PREFIRA \u2014 economia de token): [{ "path", "oldString", "newString", "replaceAll"? }].',
|
|
@@ -7155,16 +7280,40 @@ function buildRetryPrompt(node, failure, maxFeedbackChars) {
|
|
|
7155
7280
|
async function attemptImplementation(deps, options) {
|
|
7156
7281
|
const maxAttempts = Math.max(1, options.maxAttempts);
|
|
7157
7282
|
const maxFeedbackChars = options.maxFeedbackChars ?? DEFAULT_MAX_FEEDBACK_CHARS;
|
|
7283
|
+
const sleep2 = deps.sleep ?? defaultSleep;
|
|
7158
7284
|
let lastResult;
|
|
7159
7285
|
let lastError;
|
|
7160
7286
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
7161
|
-
const prompt = attempt === 1 || !lastResult ? buildInitialPrompt(options.node, { repoMap: options.repoMap }) : buildRetryPrompt(options.node, lastResult, maxFeedbackChars);
|
|
7287
|
+
const prompt = attempt === 1 || !lastResult ? buildInitialPrompt(options.node, { repoMap: options.repoMap, flowContext: options.flowContext }) : buildRetryPrompt(options.node, lastResult, maxFeedbackChars);
|
|
7288
|
+
let text;
|
|
7289
|
+
try {
|
|
7290
|
+
text = await deps.generate(prompt);
|
|
7291
|
+
} catch (err) {
|
|
7292
|
+
lastError = getErrorMessage(err);
|
|
7293
|
+
const cls = classifyLlmError(err);
|
|
7294
|
+
if (!cls.retryable) {
|
|
7295
|
+
log25.warn("Erro permanente do provider \u2014 escalando sem re-tentar", {
|
|
7296
|
+
attempt,
|
|
7297
|
+
node: options.node.id,
|
|
7298
|
+
kind: cls.kind,
|
|
7299
|
+
error: lastError
|
|
7300
|
+
});
|
|
7301
|
+
return { success: false, attempts: attempt, lastResult, error: lastError };
|
|
7302
|
+
}
|
|
7303
|
+
if (cls.retryAfterMs && cls.retryAfterMs > 0) await sleep2(cls.retryAfterMs);
|
|
7304
|
+
log25.warn("Erro transit\xF3rio do provider \u2014 re-tentando", {
|
|
7305
|
+
attempt,
|
|
7306
|
+
node: options.node.id,
|
|
7307
|
+
kind: cls.kind,
|
|
7308
|
+
retryAfterMs: cls.retryAfterMs
|
|
7309
|
+
});
|
|
7310
|
+
continue;
|
|
7311
|
+
}
|
|
7162
7312
|
let plan;
|
|
7163
7313
|
try {
|
|
7164
|
-
const text = await deps.generate(prompt);
|
|
7165
7314
|
plan = parseImplementationPlan(text);
|
|
7166
7315
|
} catch (err) {
|
|
7167
|
-
lastError =
|
|
7316
|
+
lastError = getErrorMessage(err);
|
|
7168
7317
|
log25.warn("Tentativa falhou no parse", { attempt, node: options.node.id, error: lastError });
|
|
7169
7318
|
continue;
|
|
7170
7319
|
}
|
|
@@ -7183,8 +7332,10 @@ var init_implement_attempt = __esm({
|
|
|
7183
7332
|
"src/core/autonomy/implement-attempt.ts"() {
|
|
7184
7333
|
init_esm_shims();
|
|
7185
7334
|
init_logger();
|
|
7335
|
+
init_errors();
|
|
7186
7336
|
init_truncate();
|
|
7187
7337
|
init_plan_parser();
|
|
7338
|
+
init_llm_error();
|
|
7188
7339
|
log25 = createLogger({ layer: "core", source: "implement-attempt.ts" });
|
|
7189
7340
|
DEFAULT_MAX_FEEDBACK_CHARS = 1200;
|
|
7190
7341
|
}
|
|
@@ -7573,6 +7724,854 @@ var init_repo_map = __esm({
|
|
|
7573
7724
|
FOCUS_BOOST = 3;
|
|
7574
7725
|
}
|
|
7575
7726
|
});
|
|
7727
|
+
var LspConfigOverrideSchema, LspDiagnosticSchema, LspDocumentSymbolSchema, LspTextEditSchema, LspWorkspaceEditSchema;
|
|
7728
|
+
var init_lsp_types = __esm({
|
|
7729
|
+
"src/core/lsp/lsp-types.ts"() {
|
|
7730
|
+
init_esm_shims();
|
|
7731
|
+
z.object({
|
|
7732
|
+
languageId: z.string(),
|
|
7733
|
+
extensions: z.array(z.string()),
|
|
7734
|
+
command: z.string(),
|
|
7735
|
+
args: z.array(z.string()),
|
|
7736
|
+
configFiles: z.array(z.string()),
|
|
7737
|
+
probeCommand: z.string().optional(),
|
|
7738
|
+
initializationOptions: z.record(z.string(), z.unknown()).optional(),
|
|
7739
|
+
settings: z.record(z.string(), z.unknown()).optional()
|
|
7740
|
+
});
|
|
7741
|
+
LspConfigOverrideSchema = z.object({
|
|
7742
|
+
languageId: z.string(),
|
|
7743
|
+
command: z.string(),
|
|
7744
|
+
args: z.array(z.string()).default([]),
|
|
7745
|
+
extensions: z.array(z.string()).optional(),
|
|
7746
|
+
initializationOptions: z.record(z.string(), z.unknown()).optional(),
|
|
7747
|
+
settings: z.record(z.string(), z.unknown()).optional()
|
|
7748
|
+
});
|
|
7749
|
+
z.object({
|
|
7750
|
+
file: z.string(),
|
|
7751
|
+
startLine: z.int().min(0),
|
|
7752
|
+
startCharacter: z.int().min(0),
|
|
7753
|
+
endLine: z.int().min(0),
|
|
7754
|
+
endCharacter: z.int().min(0)
|
|
7755
|
+
});
|
|
7756
|
+
z.object({
|
|
7757
|
+
signature: z.string(),
|
|
7758
|
+
documentation: z.string().optional(),
|
|
7759
|
+
language: z.string().optional()
|
|
7760
|
+
});
|
|
7761
|
+
LspDiagnosticSchema = z.object({
|
|
7762
|
+
file: z.string(),
|
|
7763
|
+
startLine: z.int().min(0),
|
|
7764
|
+
startCharacter: z.int().min(0),
|
|
7765
|
+
endLine: z.int().min(0),
|
|
7766
|
+
endCharacter: z.int().min(0),
|
|
7767
|
+
severity: z.number().int().min(1).max(4),
|
|
7768
|
+
message: z.string(),
|
|
7769
|
+
code: z.string().optional(),
|
|
7770
|
+
source: z.string().optional()
|
|
7771
|
+
});
|
|
7772
|
+
z.object({
|
|
7773
|
+
name: z.string(),
|
|
7774
|
+
kind: z.string(),
|
|
7775
|
+
file: z.string(),
|
|
7776
|
+
startLine: z.int().min(0),
|
|
7777
|
+
endLine: z.int().min(0)
|
|
7778
|
+
});
|
|
7779
|
+
LspDocumentSymbolSchema = z.object({
|
|
7780
|
+
name: z.string(),
|
|
7781
|
+
kind: z.string(),
|
|
7782
|
+
file: z.string(),
|
|
7783
|
+
startLine: z.int().min(0),
|
|
7784
|
+
endLine: z.int().min(0),
|
|
7785
|
+
children: z.lazy(() => z.array(LspDocumentSymbolSchema)).optional()
|
|
7786
|
+
});
|
|
7787
|
+
LspTextEditSchema = z.object({
|
|
7788
|
+
file: z.string(),
|
|
7789
|
+
startLine: z.int().min(0),
|
|
7790
|
+
startCharacter: z.int().min(0),
|
|
7791
|
+
endLine: z.int().min(0),
|
|
7792
|
+
endCharacter: z.int().min(0),
|
|
7793
|
+
newText: z.string()
|
|
7794
|
+
});
|
|
7795
|
+
LspWorkspaceEditSchema = z.object({
|
|
7796
|
+
changes: z.array(LspTextEditSchema)
|
|
7797
|
+
});
|
|
7798
|
+
z.object({
|
|
7799
|
+
languageId: z.string(),
|
|
7800
|
+
status: z.enum(["stopped", "starting", "ready", "error"]),
|
|
7801
|
+
pid: z.number().int().optional(),
|
|
7802
|
+
error: z.string().optional()
|
|
7803
|
+
});
|
|
7804
|
+
z.object({
|
|
7805
|
+
languageId: z.string(),
|
|
7806
|
+
confidence: z.number().min(0).max(1),
|
|
7807
|
+
detectedVia: z.enum(["file_extension", "config_file", "shebang"]),
|
|
7808
|
+
fileCount: z.int().min(0),
|
|
7809
|
+
configFile: z.string().optional()
|
|
7810
|
+
});
|
|
7811
|
+
z.object({
|
|
7812
|
+
title: z.string(),
|
|
7813
|
+
kind: z.string().optional(),
|
|
7814
|
+
isPreferred: z.boolean().optional(),
|
|
7815
|
+
edit: LspWorkspaceEditSchema.optional(),
|
|
7816
|
+
diagnostics: z.array(LspDiagnosticSchema).optional()
|
|
7817
|
+
});
|
|
7818
|
+
z.object({
|
|
7819
|
+
applied: z.boolean(),
|
|
7820
|
+
filesModified: z.array(z.string()),
|
|
7821
|
+
totalEdits: z.number().int(),
|
|
7822
|
+
errors: z.array(z.string()),
|
|
7823
|
+
backups: z.map(z.string(), z.string()).optional()
|
|
7824
|
+
});
|
|
7825
|
+
}
|
|
7826
|
+
});
|
|
7827
|
+
var BROWSER_PILOT_MODELS, ContextModeSchema, ProfileFilterConfigSchema, BrowserAutomationConfigSchema, FlowConfigSchema, ConfigSchema;
|
|
7828
|
+
var init_config_schema = __esm({
|
|
7829
|
+
"src/core/config/config-schema.ts"() {
|
|
7830
|
+
init_esm_shims();
|
|
7831
|
+
init_lsp_types();
|
|
7832
|
+
BROWSER_PILOT_MODELS = ["claude-3.5-sonnet", "gpt-4o", "gpt-4o-mini", "o1", "o1-mini"];
|
|
7833
|
+
ContextModeSchema = z.enum(["ultra-lean", "lean", "full"]);
|
|
7834
|
+
ProfileFilterConfigSchema = z.enum(["core", "pro", "expert", "all"]);
|
|
7835
|
+
BrowserAutomationConfigSchema = z.object({
|
|
7836
|
+
enabled: z.boolean().default(false),
|
|
7837
|
+
bridgeUrl: z.string().regex(/^https?:\/\//, "bridgeUrl must start with http:// or https://").default("http://127.0.0.1:9876/v1"),
|
|
7838
|
+
defaultModel: z.enum(BROWSER_PILOT_MODELS).default("claude-3.5-sonnet"),
|
|
7839
|
+
defaultCdpUrl: z.string().min(1).optional(),
|
|
7840
|
+
allowedDomains: z.array(z.string().min(1)).default([]),
|
|
7841
|
+
forbiddenCdpMethods: z.array(z.string().min(1)).default(["Browser.close"]),
|
|
7842
|
+
maxStepsDefault: z.number().int().min(1).max(100).default(25),
|
|
7843
|
+
tokenBudgetPerDay: z.number().int().nonnegative().optional()
|
|
7844
|
+
}).default({
|
|
7845
|
+
enabled: false,
|
|
7846
|
+
bridgeUrl: "http://127.0.0.1:9876/v1",
|
|
7847
|
+
defaultModel: "claude-3.5-sonnet",
|
|
7848
|
+
allowedDomains: [],
|
|
7849
|
+
forbiddenCdpMethods: ["Browser.close"],
|
|
7850
|
+
maxStepsDefault: 25
|
|
7851
|
+
});
|
|
7852
|
+
FlowConfigSchema = z.object({
|
|
7853
|
+
/** Master switch. OFF = byte-identical legacy context behaviour. */
|
|
7854
|
+
enabled: z.boolean().default(false),
|
|
7855
|
+
/** λ_base — minimum architectural forgetting rate. */
|
|
7856
|
+
lambdaBase: z.number().min(0).default(0.15),
|
|
7857
|
+
/** α — hypofrontality accelerator (weight of Φ on λ_flow). */
|
|
7858
|
+
alpha: z.number().min(0).default(1.5),
|
|
7859
|
+
/** BFS depth used to pull distant pinned invariants back into scope. */
|
|
7860
|
+
maxDepth: z.number().int().min(0).max(6).default(3),
|
|
7861
|
+
/** Peripheral neighbours below this decayed weight are pruned (unless pinned). */
|
|
7862
|
+
weightThreshold: z.number().min(0).max(1).default(0.1),
|
|
7863
|
+
/** EMA gain per consecutive success when computing Φ. */
|
|
7864
|
+
emaGain: z.number().min(0).max(1).default(0.34),
|
|
7865
|
+
/** Multiplier applied to Φ on a failure (0 = hard reset → re-hydrate memory). */
|
|
7866
|
+
resetFactor: z.number().min(0).max(1).default(0),
|
|
7867
|
+
/** Damping fraction of `emaGain` applied on a `partial` outcome. */
|
|
7868
|
+
partialFactor: z.number().min(0).max(1).default(0.5),
|
|
7869
|
+
/** rag budget is never scaled below this fraction of baseline (long-range safety). */
|
|
7870
|
+
budgetFloorRatio: z.number().min(0).max(1).default(0.25),
|
|
7871
|
+
/** How many recent task outcomes feed Φ. */
|
|
7872
|
+
historyWindow: z.number().int().min(1).max(200).default(12),
|
|
7873
|
+
/** Node types that are never diluted. */
|
|
7874
|
+
pinnedTypes: z.array(z.string()).default(["constraint", "risk", "decision", "acceptance_criteria", "constitution", "requirement"]),
|
|
7875
|
+
/** A/B experiment: alternate flow_on/flow_off deterministically per node to measure impact. */
|
|
7876
|
+
experiment: z.object({ abEnabled: z.boolean().default(false) }).default({ abEnabled: false })
|
|
7877
|
+
});
|
|
7878
|
+
ConfigSchema = z.object({
|
|
7879
|
+
port: z.number().int().min(1).max(65535).default(3e3),
|
|
7880
|
+
dbPath: z.string().default("workflow-graph"),
|
|
7881
|
+
basePath: z.string().optional(),
|
|
7882
|
+
contextMode: ContextModeSchema.default("lean"),
|
|
7883
|
+
profile: ProfileFilterConfigSchema.default("all"),
|
|
7884
|
+
dashboard: z.object({
|
|
7885
|
+
autoOpen: z.boolean().default(true)
|
|
7886
|
+
}).default({ autoOpen: true }),
|
|
7887
|
+
integrations: z.object({
|
|
7888
|
+
codeGraphAutoIndex: z.boolean().default(true),
|
|
7889
|
+
codeGraphReindexIntervalSec: z.number().int().min(0).default(0),
|
|
7890
|
+
lspServers: z.array(LspConfigOverrideSchema).default([]),
|
|
7891
|
+
browserAutomation: BrowserAutomationConfigSchema
|
|
7892
|
+
}).prefault({}),
|
|
7893
|
+
flow: FlowConfigSchema.prefault({})
|
|
7894
|
+
});
|
|
7895
|
+
}
|
|
7896
|
+
});
|
|
7897
|
+
|
|
7898
|
+
// src/core/context/flow-config.ts
|
|
7899
|
+
function resolveFlowConfig(source) {
|
|
7900
|
+
const raw = source.getProjectSetting(FLOW_CONFIG_SETTING_KEY);
|
|
7901
|
+
if (!raw) return FlowConfigSchema.parse({});
|
|
7902
|
+
try {
|
|
7903
|
+
return FlowConfigSchema.parse(JSON.parse(raw));
|
|
7904
|
+
} catch {
|
|
7905
|
+
return FlowConfigSchema.parse({});
|
|
7906
|
+
}
|
|
7907
|
+
}
|
|
7908
|
+
function flowAbArm(nodeId) {
|
|
7909
|
+
let sum = 0;
|
|
7910
|
+
for (let i = 0; i < nodeId.length; i += 1) sum += nodeId.charCodeAt(i);
|
|
7911
|
+
return sum % 2 === 0 ? "flow_on" : "flow_off";
|
|
7912
|
+
}
|
|
7913
|
+
var FLOW_CONFIG_SETTING_KEY;
|
|
7914
|
+
var init_flow_config = __esm({
|
|
7915
|
+
"src/core/context/flow-config.ts"() {
|
|
7916
|
+
init_esm_shims();
|
|
7917
|
+
init_config_schema();
|
|
7918
|
+
FLOW_CONFIG_SETTING_KEY = "flow_config";
|
|
7919
|
+
}
|
|
7920
|
+
});
|
|
7921
|
+
|
|
7922
|
+
// src/core/context/flow-index.ts
|
|
7923
|
+
function computeFlowIndex(outcomesNewestFirst, tuning = {}) {
|
|
7924
|
+
const { emaGain, resetFactor, partialFactor } = { ...DEFAULT_FLOW_TUNING, ...tuning };
|
|
7925
|
+
let streak = 0;
|
|
7926
|
+
for (const outcome of outcomesNewestFirst) {
|
|
7927
|
+
if (outcome === "success") streak += 1;
|
|
7928
|
+
else break;
|
|
7929
|
+
}
|
|
7930
|
+
let phi = 0;
|
|
7931
|
+
for (let i = outcomesNewestFirst.length - 1; i >= 0; i -= 1) {
|
|
7932
|
+
const outcome = outcomesNewestFirst[i];
|
|
7933
|
+
if (outcome === "success") {
|
|
7934
|
+
phi += emaGain * (1 - phi);
|
|
7935
|
+
} else if (outcome === "failure") {
|
|
7936
|
+
phi *= resetFactor;
|
|
7937
|
+
} else {
|
|
7938
|
+
phi *= 1 - emaGain * partialFactor;
|
|
7939
|
+
}
|
|
7940
|
+
}
|
|
7941
|
+
phi = Math.min(1, Math.max(0, phi));
|
|
7942
|
+
return { phi, streak, sampleCount: outcomesNewestFirst.length };
|
|
7943
|
+
}
|
|
7944
|
+
function computeLambdaFlow(phi, lambdaBase, alpha) {
|
|
7945
|
+
return lambdaBase + alpha * phi;
|
|
7946
|
+
}
|
|
7947
|
+
function decayWeight(lambda, distance) {
|
|
7948
|
+
return Math.exp(-lambda * distance);
|
|
7949
|
+
}
|
|
7950
|
+
var DEFAULT_FLOW_TUNING;
|
|
7951
|
+
var init_flow_index = __esm({
|
|
7952
|
+
"src/core/context/flow-index.ts"() {
|
|
7953
|
+
init_esm_shims();
|
|
7954
|
+
DEFAULT_FLOW_TUNING = {
|
|
7955
|
+
emaGain: 0.34,
|
|
7956
|
+
resetFactor: 0,
|
|
7957
|
+
partialFactor: 0.5
|
|
7958
|
+
};
|
|
7959
|
+
}
|
|
7960
|
+
});
|
|
7961
|
+
|
|
7962
|
+
// src/core/context/token-estimator.ts
|
|
7963
|
+
function isAsciiLetter(code) {
|
|
7964
|
+
return code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
7965
|
+
}
|
|
7966
|
+
function isAsciiDigit(code) {
|
|
7967
|
+
return code >= 48 && code <= 57;
|
|
7968
|
+
}
|
|
7969
|
+
function isWhitespace(code) {
|
|
7970
|
+
return code === 32 || code === 9 || code === 10 || code === 13 || code === 12 || code === 11;
|
|
7971
|
+
}
|
|
7972
|
+
function estimateTokens2(text) {
|
|
7973
|
+
if (!text) return 0;
|
|
7974
|
+
let tokens = 0;
|
|
7975
|
+
const len = text.length;
|
|
7976
|
+
let i = 0;
|
|
7977
|
+
while (i < len) {
|
|
7978
|
+
const code = text.charCodeAt(i);
|
|
7979
|
+
if (isWhitespace(code)) {
|
|
7980
|
+
i++;
|
|
7981
|
+
continue;
|
|
7982
|
+
}
|
|
7983
|
+
if (isAsciiLetter(code)) {
|
|
7984
|
+
const start = i;
|
|
7985
|
+
i++;
|
|
7986
|
+
let subWords = 1;
|
|
7987
|
+
while (i < len && isAsciiLetter(text.charCodeAt(i))) {
|
|
7988
|
+
if (i > start && text.charCodeAt(i) >= 65 && text.charCodeAt(i) <= 90 && text.charCodeAt(i - 1) >= 97 && text.charCodeAt(i - 1) <= 122) {
|
|
7989
|
+
subWords++;
|
|
7990
|
+
}
|
|
7991
|
+
i++;
|
|
7992
|
+
}
|
|
7993
|
+
const wordLen = i - start;
|
|
7994
|
+
if (subWords > 1) {
|
|
7995
|
+
tokens += subWords;
|
|
7996
|
+
} else {
|
|
7997
|
+
tokens += wordLen <= 6 ? 1 : wordLen > 20 ? Math.ceil(wordLen / 4) : Math.ceil(wordLen / 5);
|
|
7998
|
+
}
|
|
7999
|
+
continue;
|
|
8000
|
+
}
|
|
8001
|
+
if (isAsciiDigit(code)) {
|
|
8002
|
+
const start = i;
|
|
8003
|
+
i++;
|
|
8004
|
+
while (i < len && isAsciiDigit(text.charCodeAt(i))) i++;
|
|
8005
|
+
const digitsLen = i - start;
|
|
8006
|
+
tokens += Math.ceil(digitsLen / 3);
|
|
8007
|
+
continue;
|
|
8008
|
+
}
|
|
8009
|
+
tokens += 1;
|
|
8010
|
+
i++;
|
|
8011
|
+
}
|
|
8012
|
+
return tokens;
|
|
8013
|
+
}
|
|
8014
|
+
var init_token_estimator = __esm({
|
|
8015
|
+
"src/core/context/token-estimator.ts"() {
|
|
8016
|
+
init_esm_shims();
|
|
8017
|
+
}
|
|
8018
|
+
});
|
|
8019
|
+
|
|
8020
|
+
// src/core/context/compact-context.ts
|
|
8021
|
+
function toTaskSummary(node) {
|
|
8022
|
+
const summary = {
|
|
8023
|
+
id: node.id,
|
|
8024
|
+
type: node.type,
|
|
8025
|
+
title: node.title,
|
|
8026
|
+
status: node.status,
|
|
8027
|
+
priority: node.priority
|
|
8028
|
+
};
|
|
8029
|
+
if (node.description) summary.description = node.description;
|
|
8030
|
+
if (node.sprint) summary.sprint = node.sprint;
|
|
8031
|
+
if (node.xpSize) summary.xpSize = node.xpSize;
|
|
8032
|
+
if (node.tags?.length) summary.tags = node.tags;
|
|
8033
|
+
return summary;
|
|
8034
|
+
}
|
|
8035
|
+
function isInferred(edge) {
|
|
8036
|
+
return edge.metadata?.inferred === true;
|
|
8037
|
+
}
|
|
8038
|
+
function buildTaskContext(store2, nodeId, snapshot) {
|
|
8039
|
+
const resolveNode = (id) => {
|
|
8040
|
+
return store2.getNodeById(id);
|
|
8041
|
+
};
|
|
8042
|
+
const node = resolveNode(nodeId);
|
|
8043
|
+
if (!node) {
|
|
8044
|
+
log26.warn(`buildTaskContext: node ${nodeId} not found`);
|
|
8045
|
+
return null;
|
|
8046
|
+
}
|
|
8047
|
+
let parent = null;
|
|
8048
|
+
if (node.parentId) {
|
|
8049
|
+
const parentNode = resolveNode(node.parentId);
|
|
8050
|
+
if (parentNode) parent = toTaskSummary(parentNode);
|
|
8051
|
+
}
|
|
8052
|
+
let childNodes;
|
|
8053
|
+
{
|
|
8054
|
+
childNodes = store2.getChildNodes(nodeId);
|
|
8055
|
+
}
|
|
8056
|
+
const children = childNodes.map(toTaskSummary);
|
|
8057
|
+
let incomingEdges;
|
|
8058
|
+
let outgoingEdges;
|
|
8059
|
+
{
|
|
8060
|
+
incomingEdges = store2.getEdgesTo(nodeId);
|
|
8061
|
+
outgoingEdges = store2.getEdgesFrom(nodeId);
|
|
8062
|
+
}
|
|
8063
|
+
const blockers = [];
|
|
8064
|
+
const dependsOn = [];
|
|
8065
|
+
const relatedIds = /* @__PURE__ */ new Set();
|
|
8066
|
+
const relatedNodes = [];
|
|
8067
|
+
const implementsNodes = [];
|
|
8068
|
+
const derivedFromNodes = [];
|
|
8069
|
+
let edgeParent = null;
|
|
8070
|
+
const edgeChildren = [];
|
|
8071
|
+
const edgeChildrenIds = /* @__PURE__ */ new Set();
|
|
8072
|
+
for (const edge of incomingEdges) {
|
|
8073
|
+
if (edge.relationType === "blocks") {
|
|
8074
|
+
const blockerNode = resolveNode(edge.from);
|
|
8075
|
+
if (blockerNode) {
|
|
8076
|
+
blockers.push({
|
|
8077
|
+
id: blockerNode.id,
|
|
8078
|
+
title: blockerNode.title,
|
|
8079
|
+
status: blockerNode.status,
|
|
8080
|
+
relationType: edge.relationType,
|
|
8081
|
+
inferred: isInferred(edge)
|
|
8082
|
+
});
|
|
8083
|
+
}
|
|
8084
|
+
} else if (edge.relationType === "related_to") {
|
|
8085
|
+
const relNode = resolveNode(edge.from);
|
|
8086
|
+
if (relNode && !relatedIds.has(relNode.id)) {
|
|
8087
|
+
relatedIds.add(relNode.id);
|
|
8088
|
+
relatedNodes.push(toTaskSummary(relNode));
|
|
8089
|
+
}
|
|
8090
|
+
} else if (edge.relationType === "parent_of" && !edgeParent) {
|
|
8091
|
+
const parentNode = resolveNode(edge.from);
|
|
8092
|
+
if (parentNode) edgeParent = toTaskSummary(parentNode);
|
|
8093
|
+
}
|
|
8094
|
+
}
|
|
8095
|
+
for (const edge of outgoingEdges) {
|
|
8096
|
+
if (edge.relationType === "depends_on") {
|
|
8097
|
+
const depNode = resolveNode(edge.to);
|
|
8098
|
+
if (depNode) {
|
|
8099
|
+
dependsOn.push({
|
|
8100
|
+
id: depNode.id,
|
|
8101
|
+
title: depNode.title,
|
|
8102
|
+
status: depNode.status,
|
|
8103
|
+
resolved: depNode.status === "done",
|
|
8104
|
+
inferred: isInferred(edge)
|
|
8105
|
+
});
|
|
8106
|
+
}
|
|
8107
|
+
} else if (edge.relationType === "related_to") {
|
|
8108
|
+
const relNode = resolveNode(edge.to);
|
|
8109
|
+
if (relNode && !relatedIds.has(relNode.id)) {
|
|
8110
|
+
relatedIds.add(relNode.id);
|
|
8111
|
+
relatedNodes.push(toTaskSummary(relNode));
|
|
8112
|
+
}
|
|
8113
|
+
} else if (edge.relationType === "implements") {
|
|
8114
|
+
const implNode = resolveNode(edge.to);
|
|
8115
|
+
if (implNode) implementsNodes.push(toTaskSummary(implNode));
|
|
8116
|
+
} else if (edge.relationType === "derived_from") {
|
|
8117
|
+
const derivedNode = resolveNode(edge.to);
|
|
8118
|
+
if (derivedNode) derivedFromNodes.push(toTaskSummary(derivedNode));
|
|
8119
|
+
} else if (edge.relationType === "parent_of") {
|
|
8120
|
+
const childNode = resolveNode(edge.to);
|
|
8121
|
+
if (childNode && !edgeChildrenIds.has(childNode.id)) {
|
|
8122
|
+
edgeChildrenIds.add(childNode.id);
|
|
8123
|
+
edgeChildren.push(toTaskSummary(childNode));
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
}
|
|
8127
|
+
const acceptanceCriteria = getNodeAcFromStore(store2, node.id);
|
|
8128
|
+
const sourceRef = node.sourceRef ? { ...node.sourceRef } : null;
|
|
8129
|
+
const localNodes = [node, ...childNodes];
|
|
8130
|
+
const originalChars = localNodes.reduce(
|
|
8131
|
+
(sum, n) => sum + n.title.length + (n.description?.length ?? 0) + (n.acceptanceCriteria?.join("").length ?? 0),
|
|
8132
|
+
0
|
|
8133
|
+
) + [...incomingEdges, ...outgoingEdges].reduce((sum, e) => sum + (e.reason?.length ?? 0), 0);
|
|
8134
|
+
const summary = toTaskSummary(node);
|
|
8135
|
+
const corePayload = {
|
|
8136
|
+
task: summary,
|
|
8137
|
+
parent,
|
|
8138
|
+
children,
|
|
8139
|
+
blockers,
|
|
8140
|
+
dependsOn,
|
|
8141
|
+
relatedNodes: relatedNodes.length > 0 ? relatedNodes : void 0,
|
|
8142
|
+
implementsNodes: implementsNodes.length > 0 ? implementsNodes : void 0,
|
|
8143
|
+
derivedFromNodes: derivedFromNodes.length > 0 ? derivedFromNodes : void 0,
|
|
8144
|
+
edgeParent: edgeParent ?? void 0,
|
|
8145
|
+
edgeChildren: edgeChildren.length > 0 ? edgeChildren : void 0,
|
|
8146
|
+
acceptanceCriteria,
|
|
8147
|
+
sourceRef,
|
|
8148
|
+
metrics: { originalChars: 0, compactChars: 0, reductionPercent: 0, estimatedTokens: 0 }
|
|
8149
|
+
};
|
|
8150
|
+
const compactJson = JSON.stringify(corePayload);
|
|
8151
|
+
const compactChars = compactJson.length;
|
|
8152
|
+
const reductionPercent = originalChars > 0 ? Math.round((originalChars - compactChars) / originalChars * 100) : 0;
|
|
8153
|
+
const metrics = {
|
|
8154
|
+
originalChars,
|
|
8155
|
+
compactChars,
|
|
8156
|
+
reductionPercent,
|
|
8157
|
+
estimatedTokens: estimateTokens2(compactJson)
|
|
8158
|
+
};
|
|
8159
|
+
const contextPayload = {
|
|
8160
|
+
...corePayload,
|
|
8161
|
+
node: summary,
|
|
8162
|
+
metrics
|
|
8163
|
+
};
|
|
8164
|
+
log26.info(`Context for ${nodeId}: ${metrics.estimatedTokens} tokens, ${metrics.reductionPercent}% reduction`);
|
|
8165
|
+
return contextPayload;
|
|
8166
|
+
}
|
|
8167
|
+
var log26, KEY_MAP, KEY_LEGEND;
|
|
8168
|
+
var init_compact_context = __esm({
|
|
8169
|
+
"src/core/context/compact-context.ts"() {
|
|
8170
|
+
init_esm_shims();
|
|
8171
|
+
init_ac_helpers();
|
|
8172
|
+
init_token_estimator();
|
|
8173
|
+
init_logger();
|
|
8174
|
+
log26 = createLogger({ layer: "core", source: "compact-context.ts" });
|
|
8175
|
+
KEY_MAP = {
|
|
8176
|
+
// TaskContext top-level
|
|
8177
|
+
task: "tk",
|
|
8178
|
+
node: "n",
|
|
8179
|
+
parent: "par",
|
|
8180
|
+
children: "ch",
|
|
8181
|
+
blockers: "bl",
|
|
8182
|
+
dependsOn: "dep",
|
|
8183
|
+
acceptanceCriteria: "ac",
|
|
8184
|
+
sourceRef: "sr",
|
|
8185
|
+
relatedNodes: "rel",
|
|
8186
|
+
implementsNodes: "impl",
|
|
8187
|
+
derivedFromNodes: "drv",
|
|
8188
|
+
edgeParent: "ep",
|
|
8189
|
+
edgeChildren: "ech",
|
|
8190
|
+
metrics: "m",
|
|
8191
|
+
// TaskSummary / shared fields
|
|
8192
|
+
id: "i",
|
|
8193
|
+
type: "t",
|
|
8194
|
+
title: "n",
|
|
8195
|
+
status: "s",
|
|
8196
|
+
priority: "p",
|
|
8197
|
+
description: "d",
|
|
8198
|
+
sprint: "sp",
|
|
8199
|
+
xpSize: "xs",
|
|
8200
|
+
tags: "tg",
|
|
8201
|
+
// BlockerInfo / DependencyInfo
|
|
8202
|
+
relationType: "rt",
|
|
8203
|
+
inferred: "inf",
|
|
8204
|
+
resolved: "res",
|
|
8205
|
+
// SourceRefInfo
|
|
8206
|
+
file: "f",
|
|
8207
|
+
startLine: "sl",
|
|
8208
|
+
endLine: "el",
|
|
8209
|
+
confidence: "cf",
|
|
8210
|
+
// ContextMetrics
|
|
8211
|
+
originalChars: "oc",
|
|
8212
|
+
compactChars: "cc",
|
|
8213
|
+
reductionPercent: "rp",
|
|
8214
|
+
estimatedTokens: "et"
|
|
8215
|
+
};
|
|
8216
|
+
KEY_LEGEND = {};
|
|
8217
|
+
for (const [full, short] of Object.entries(KEY_MAP)) {
|
|
8218
|
+
KEY_LEGEND[short] = full;
|
|
8219
|
+
}
|
|
8220
|
+
}
|
|
8221
|
+
});
|
|
8222
|
+
|
|
8223
|
+
// src/core/context/topological-decay.ts
|
|
8224
|
+
function corePayloadTokens(ctx, pinned) {
|
|
8225
|
+
const { metrics: _m, node: _n, ...core } = ctx;
|
|
8226
|
+
return estimateTokens2(JSON.stringify(pinned.length > 0 ? { ...core, pinnedInvariants: pinned } : core));
|
|
8227
|
+
}
|
|
8228
|
+
function isPinnedType(type, pinnedTypes) {
|
|
8229
|
+
return pinnedTypes.has(type);
|
|
8230
|
+
}
|
|
8231
|
+
function collectDistantInvariants(store2, rootId, alreadyPresent, maxDepth, pinnedTypes) {
|
|
8232
|
+
if (maxDepth <= 0) return [];
|
|
8233
|
+
const visited = /* @__PURE__ */ new Set([rootId]);
|
|
8234
|
+
const found = /* @__PURE__ */ new Map();
|
|
8235
|
+
let frontier = [rootId];
|
|
8236
|
+
for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth += 1) {
|
|
8237
|
+
const next = [];
|
|
8238
|
+
for (const id of frontier) {
|
|
8239
|
+
const edges = [...store2.getEdgesFrom(id), ...store2.getEdgesTo(id)];
|
|
8240
|
+
for (const edge of edges) {
|
|
8241
|
+
const neighborId = edge.from === id ? edge.to : edge.from;
|
|
8242
|
+
if (visited.has(neighborId)) continue;
|
|
8243
|
+
visited.add(neighborId);
|
|
8244
|
+
next.push(neighborId);
|
|
8245
|
+
if (alreadyPresent.has(neighborId) || found.has(neighborId)) continue;
|
|
8246
|
+
const neighbor = store2.getNodeById(neighborId);
|
|
8247
|
+
if (neighbor && isPinnedType(neighbor.type, pinnedTypes)) {
|
|
8248
|
+
found.set(neighborId, {
|
|
8249
|
+
id: neighbor.id,
|
|
8250
|
+
type: neighbor.type,
|
|
8251
|
+
title: neighbor.title,
|
|
8252
|
+
status: neighbor.status,
|
|
8253
|
+
distance: depth
|
|
8254
|
+
});
|
|
8255
|
+
}
|
|
8256
|
+
}
|
|
8257
|
+
}
|
|
8258
|
+
frontier = next;
|
|
8259
|
+
}
|
|
8260
|
+
return [...found.values()];
|
|
8261
|
+
}
|
|
8262
|
+
function buildDecayedTaskContext(store2, nodeId, opts) {
|
|
8263
|
+
const base = buildTaskContext(store2, nodeId);
|
|
8264
|
+
if (!base) return null;
|
|
8265
|
+
const pinnedTypes = opts.pinnedTypes ?? new Set(DEFAULT_PINNED_TYPES);
|
|
8266
|
+
const tokensBaseline = corePayloadTokens(base, []);
|
|
8267
|
+
const peripheralWeight = decayWeight(opts.lambda, PERIPHERAL_DISTANCE);
|
|
8268
|
+
const peripheralSurvives = peripheralWeight >= opts.weightThreshold;
|
|
8269
|
+
const presentIds = /* @__PURE__ */ new Set([base.task.id]);
|
|
8270
|
+
if (base.parent) presentIds.add(base.parent.id);
|
|
8271
|
+
for (const c of base.children) presentIds.add(c.id);
|
|
8272
|
+
for (const b of base.blockers) presentIds.add(b.id);
|
|
8273
|
+
for (const d of base.dependsOn) presentIds.add(d.id);
|
|
8274
|
+
const ctx = structuredClone(base);
|
|
8275
|
+
let prunedCount = 0;
|
|
8276
|
+
const prunePeripheral = (list) => {
|
|
8277
|
+
if (!list) return list;
|
|
8278
|
+
const kept = list.filter((item) => {
|
|
8279
|
+
presentIds.add(item.id);
|
|
8280
|
+
if (isPinnedType(item.type, pinnedTypes)) return true;
|
|
8281
|
+
if (peripheralSurvives) return true;
|
|
8282
|
+
prunedCount += 1;
|
|
8283
|
+
return false;
|
|
8284
|
+
});
|
|
8285
|
+
return kept.length > 0 ? kept : void 0;
|
|
8286
|
+
};
|
|
8287
|
+
ctx.relatedNodes = prunePeripheral(ctx.relatedNodes);
|
|
8288
|
+
ctx.implementsNodes = prunePeripheral(ctx.implementsNodes);
|
|
8289
|
+
ctx.derivedFromNodes = prunePeripheral(ctx.derivedFromNodes);
|
|
8290
|
+
ctx.edgeChildren = prunePeripheral(ctx.edgeChildren);
|
|
8291
|
+
if (ctx.edgeParent) {
|
|
8292
|
+
presentIds.add(ctx.edgeParent.id);
|
|
8293
|
+
if (!isPinnedType(ctx.edgeParent.type, pinnedTypes) && !peripheralSurvives) {
|
|
8294
|
+
ctx.edgeParent = null;
|
|
8295
|
+
prunedCount += 1;
|
|
8296
|
+
}
|
|
8297
|
+
}
|
|
8298
|
+
const pinnedInvariants = collectDistantInvariants(
|
|
8299
|
+
store2,
|
|
8300
|
+
nodeId,
|
|
8301
|
+
presentIds,
|
|
8302
|
+
opts.maxDepth,
|
|
8303
|
+
pinnedTypes
|
|
8304
|
+
);
|
|
8305
|
+
const tokensActual = corePayloadTokens(ctx, pinnedInvariants);
|
|
8306
|
+
ctx.metrics = {
|
|
8307
|
+
...ctx.metrics,
|
|
8308
|
+
estimatedTokens: tokensActual
|
|
8309
|
+
};
|
|
8310
|
+
ctx.node = ctx.task;
|
|
8311
|
+
const retainedCount = (ctx.children?.length ?? 0) + (ctx.blockers?.length ?? 0) + (ctx.dependsOn?.length ?? 0) + (ctx.relatedNodes?.length ?? 0) + (ctx.implementsNodes?.length ?? 0) + (ctx.derivedFromNodes?.length ?? 0) + (ctx.edgeChildren?.length ?? 0);
|
|
8312
|
+
log27.debug("flow:decay", {
|
|
8313
|
+
nodeId,
|
|
8314
|
+
lambda: opts.lambda,
|
|
8315
|
+
prunedCount,
|
|
8316
|
+
pinnedCount: pinnedInvariants.length,
|
|
8317
|
+
tokensBaseline,
|
|
8318
|
+
tokensActual
|
|
8319
|
+
});
|
|
8320
|
+
return {
|
|
8321
|
+
context: ctx,
|
|
8322
|
+
meta: {
|
|
8323
|
+
lambda: opts.lambda,
|
|
8324
|
+
prunedCount,
|
|
8325
|
+
retainedCount,
|
|
8326
|
+
pinnedCount: pinnedInvariants.length,
|
|
8327
|
+
tokensBaseline,
|
|
8328
|
+
tokensActual,
|
|
8329
|
+
tokensSaved: tokensBaseline - tokensActual,
|
|
8330
|
+
pinnedInvariants
|
|
8331
|
+
}
|
|
8332
|
+
};
|
|
8333
|
+
}
|
|
8334
|
+
var log27, DEFAULT_PINNED_TYPES, PERIPHERAL_DISTANCE;
|
|
8335
|
+
var init_topological_decay = __esm({
|
|
8336
|
+
"src/core/context/topological-decay.ts"() {
|
|
8337
|
+
init_esm_shims();
|
|
8338
|
+
init_compact_context();
|
|
8339
|
+
init_flow_index();
|
|
8340
|
+
init_token_estimator();
|
|
8341
|
+
init_logger();
|
|
8342
|
+
log27 = createLogger({ layer: "core", source: "topological-decay.ts" });
|
|
8343
|
+
DEFAULT_PINNED_TYPES = [
|
|
8344
|
+
"constraint",
|
|
8345
|
+
"risk",
|
|
8346
|
+
"decision",
|
|
8347
|
+
"acceptance_criteria",
|
|
8348
|
+
"constitution",
|
|
8349
|
+
"requirement"
|
|
8350
|
+
];
|
|
8351
|
+
PERIPHERAL_DISTANCE = 2;
|
|
8352
|
+
}
|
|
8353
|
+
});
|
|
8354
|
+
|
|
8355
|
+
// src/core/store/episodic-outcomes-store.ts
|
|
8356
|
+
function buildApproachSummary(touchedFiles, acIds) {
|
|
8357
|
+
const files = [...touchedFiles].sort().join("+");
|
|
8358
|
+
const acs = [...acIds].sort().join(",");
|
|
8359
|
+
return `${files}:${acs}`;
|
|
8360
|
+
}
|
|
8361
|
+
function insertEpisodicOutcome(db, outcome) {
|
|
8362
|
+
db.prepare(
|
|
8363
|
+
`INSERT OR IGNORE INTO episodic_outcomes
|
|
8364
|
+
(id, node_id, task_type, tags, approach_summary, outcome, cycle_time_delta, reopen_count, created_at)
|
|
8365
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
8366
|
+
).run(
|
|
8367
|
+
outcome.id,
|
|
8368
|
+
outcome.nodeId,
|
|
8369
|
+
outcome.taskType,
|
|
8370
|
+
outcome.tags,
|
|
8371
|
+
outcome.approachSummary,
|
|
8372
|
+
outcome.outcome,
|
|
8373
|
+
outcome.cycleTimeDelta,
|
|
8374
|
+
outcome.reopenCount,
|
|
8375
|
+
outcome.createdAt
|
|
8376
|
+
);
|
|
8377
|
+
}
|
|
8378
|
+
function queryEpisodicOutcomes(db, opts = {}) {
|
|
8379
|
+
const conditions = [];
|
|
8380
|
+
const params = [];
|
|
8381
|
+
if (opts.taskType) {
|
|
8382
|
+
conditions.push("task_type = ?");
|
|
8383
|
+
params.push(opts.taskType);
|
|
8384
|
+
}
|
|
8385
|
+
if (opts.maxAgeDays) {
|
|
8386
|
+
const cutoff = Date.now() - opts.maxAgeDays * 24 * 3600 * 1e3;
|
|
8387
|
+
conditions.push("created_at >= ?");
|
|
8388
|
+
params.push(cutoff);
|
|
8389
|
+
}
|
|
8390
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
8391
|
+
const limit = Math.min(opts.limit ?? 100, 500);
|
|
8392
|
+
params.push(limit);
|
|
8393
|
+
const rows = db.prepare(
|
|
8394
|
+
`SELECT id, node_id, task_type, tags, approach_summary, outcome,
|
|
8395
|
+
cycle_time_delta, reopen_count, created_at
|
|
8396
|
+
FROM episodic_outcomes
|
|
8397
|
+
${where}
|
|
8398
|
+
ORDER BY created_at DESC
|
|
8399
|
+
LIMIT ?`
|
|
8400
|
+
).all(...params);
|
|
8401
|
+
return rows.map((r) => ({
|
|
8402
|
+
id: r.id,
|
|
8403
|
+
nodeId: r.node_id,
|
|
8404
|
+
taskType: r.task_type,
|
|
8405
|
+
tags: r.tags,
|
|
8406
|
+
approachSummary: r.approach_summary,
|
|
8407
|
+
outcome: r.outcome,
|
|
8408
|
+
cycleTimeDelta: r.cycle_time_delta,
|
|
8409
|
+
reopenCount: r.reopen_count,
|
|
8410
|
+
createdAt: r.created_at
|
|
8411
|
+
}));
|
|
8412
|
+
}
|
|
8413
|
+
var init_episodic_outcomes_store = __esm({
|
|
8414
|
+
"src/core/store/episodic-outcomes-store.ts"() {
|
|
8415
|
+
init_esm_shims();
|
|
8416
|
+
}
|
|
8417
|
+
});
|
|
8418
|
+
|
|
8419
|
+
// src/core/context/flow-metrics-store.ts
|
|
8420
|
+
function insertFlowMetric(db, metric) {
|
|
8421
|
+
db.prepare(
|
|
8422
|
+
`INSERT OR IGNORE INTO flow_metrics
|
|
8423
|
+
(id, project_id, node_id, mode, phi, lambda,
|
|
8424
|
+
tokens_baseline, tokens_actual, pruned_count, pinned_count, created_at)
|
|
8425
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
8426
|
+
).run(
|
|
8427
|
+
metric.id,
|
|
8428
|
+
metric.projectId,
|
|
8429
|
+
metric.nodeId,
|
|
8430
|
+
metric.mode,
|
|
8431
|
+
metric.phi,
|
|
8432
|
+
metric.lambda,
|
|
8433
|
+
metric.tokensBaseline,
|
|
8434
|
+
metric.tokensActual,
|
|
8435
|
+
metric.prunedCount,
|
|
8436
|
+
metric.pinnedCount,
|
|
8437
|
+
metric.createdAt
|
|
8438
|
+
);
|
|
8439
|
+
}
|
|
8440
|
+
var init_flow_metrics_store = __esm({
|
|
8441
|
+
"src/core/context/flow-metrics-store.ts"() {
|
|
8442
|
+
init_esm_shims();
|
|
8443
|
+
}
|
|
8444
|
+
});
|
|
8445
|
+
|
|
8446
|
+
// src/core/context/flow-compact.ts
|
|
8447
|
+
function formatFlowContext(result) {
|
|
8448
|
+
const { context: ctx, pinnedInvariants } = result;
|
|
8449
|
+
const lines = ["Contexto do grafo (dilu\xEDdo por flow \u2014 \u03A6 governando o esquecimento):"];
|
|
8450
|
+
lines.push(`- Task: ${ctx.task.title} (${ctx.task.id}) [${ctx.task.status}]`);
|
|
8451
|
+
if (ctx.task.description) lines.push(` ${ctx.task.description}`);
|
|
8452
|
+
if (ctx.acceptanceCriteria.length > 0) {
|
|
8453
|
+
lines.push("- Crit\xE9rios de aceita\xE7\xE3o:");
|
|
8454
|
+
for (const ac of ctx.acceptanceCriteria) lines.push(` \u2022 ${ac}`);
|
|
8455
|
+
}
|
|
8456
|
+
const openBlockers = ctx.blockers.filter((b) => b.status !== "done");
|
|
8457
|
+
if (openBlockers.length > 0) {
|
|
8458
|
+
lines.push(`- Bloqueadores: ${openBlockers.map((b) => `${b.title} (${b.status})`).join("; ")}`);
|
|
8459
|
+
}
|
|
8460
|
+
const openDeps = ctx.dependsOn.filter((d) => !d.resolved);
|
|
8461
|
+
if (openDeps.length > 0) {
|
|
8462
|
+
lines.push(`- Depende de: ${openDeps.map((d) => `${d.title} (${d.status})`).join("; ")}`);
|
|
8463
|
+
}
|
|
8464
|
+
if (pinnedInvariants.length > 0) {
|
|
8465
|
+
lines.push("- Invariantes pinados (nunca dilu\xEDdos):");
|
|
8466
|
+
for (const inv of pinnedInvariants) lines.push(` \u2022 [${inv.type}] ${inv.title}`);
|
|
8467
|
+
}
|
|
8468
|
+
return lines.join("\n");
|
|
8469
|
+
}
|
|
8470
|
+
function recordMetric(store2, row) {
|
|
8471
|
+
try {
|
|
8472
|
+
insertFlowMetric(store2.getDb(), {
|
|
8473
|
+
id: generateId("flowm"),
|
|
8474
|
+
createdAt: row.createdAt ?? Date.now(),
|
|
8475
|
+
...row
|
|
8476
|
+
});
|
|
8477
|
+
} catch (err) {
|
|
8478
|
+
log28.warn("flow:metric:record-failed", { error: err instanceof Error ? err.message : String(err) });
|
|
8479
|
+
}
|
|
8480
|
+
}
|
|
8481
|
+
function applyFlowToCompact(store2, nodeId) {
|
|
8482
|
+
const cfg = resolveFlowConfig(store2);
|
|
8483
|
+
if (!cfg.enabled) return null;
|
|
8484
|
+
const projectId = store2.getActiveProject()?.id ?? "unknown";
|
|
8485
|
+
const outcomes = queryEpisodicOutcomes(store2.getDb(), { limit: cfg.historyWindow }).map((o) => o.outcome);
|
|
8486
|
+
const state = computeFlowIndex(outcomes, {
|
|
8487
|
+
emaGain: cfg.emaGain,
|
|
8488
|
+
resetFactor: cfg.resetFactor,
|
|
8489
|
+
partialFactor: cfg.partialFactor
|
|
8490
|
+
});
|
|
8491
|
+
const lambda = computeLambdaFlow(state.phi, cfg.lambdaBase, cfg.alpha);
|
|
8492
|
+
const mode = cfg.experiment.abEnabled ? flowAbArm(nodeId) : "flow_on";
|
|
8493
|
+
if (mode === "flow_off") {
|
|
8494
|
+
const base = buildTaskContext(store2, nodeId);
|
|
8495
|
+
if (!base) return null;
|
|
8496
|
+
const baseline = base.metrics.estimatedTokens;
|
|
8497
|
+
recordMetric(store2, {
|
|
8498
|
+
projectId,
|
|
8499
|
+
nodeId,
|
|
8500
|
+
mode,
|
|
8501
|
+
phi: state.phi,
|
|
8502
|
+
lambda,
|
|
8503
|
+
tokensBaseline: baseline,
|
|
8504
|
+
tokensActual: baseline,
|
|
8505
|
+
prunedCount: 0,
|
|
8506
|
+
pinnedCount: 0
|
|
8507
|
+
});
|
|
8508
|
+
return {
|
|
8509
|
+
context: base,
|
|
8510
|
+
pinnedInvariants: [],
|
|
8511
|
+
flow: {
|
|
8512
|
+
enabled: true,
|
|
8513
|
+
mode,
|
|
8514
|
+
phi: state.phi,
|
|
8515
|
+
streak: state.streak,
|
|
8516
|
+
lambda,
|
|
8517
|
+
prunedCount: 0,
|
|
8518
|
+
pinnedCount: 0,
|
|
8519
|
+
tokensBaseline: baseline,
|
|
8520
|
+
tokensActual: baseline,
|
|
8521
|
+
tokensSaved: 0
|
|
8522
|
+
}
|
|
8523
|
+
};
|
|
8524
|
+
}
|
|
8525
|
+
const decayed = buildDecayedTaskContext(store2, nodeId, {
|
|
8526
|
+
lambda,
|
|
8527
|
+
maxDepth: cfg.maxDepth,
|
|
8528
|
+
weightThreshold: cfg.weightThreshold,
|
|
8529
|
+
pinnedTypes: new Set(cfg.pinnedTypes)
|
|
8530
|
+
});
|
|
8531
|
+
if (!decayed) return null;
|
|
8532
|
+
recordMetric(store2, {
|
|
8533
|
+
projectId,
|
|
8534
|
+
nodeId,
|
|
8535
|
+
mode,
|
|
8536
|
+
phi: state.phi,
|
|
8537
|
+
lambda,
|
|
8538
|
+
tokensBaseline: decayed.meta.tokensBaseline,
|
|
8539
|
+
tokensActual: decayed.meta.tokensActual,
|
|
8540
|
+
prunedCount: decayed.meta.prunedCount,
|
|
8541
|
+
pinnedCount: decayed.meta.pinnedCount
|
|
8542
|
+
});
|
|
8543
|
+
return {
|
|
8544
|
+
context: decayed.context,
|
|
8545
|
+
pinnedInvariants: decayed.meta.pinnedInvariants,
|
|
8546
|
+
flow: {
|
|
8547
|
+
enabled: true,
|
|
8548
|
+
mode,
|
|
8549
|
+
phi: state.phi,
|
|
8550
|
+
streak: state.streak,
|
|
8551
|
+
lambda,
|
|
8552
|
+
prunedCount: decayed.meta.prunedCount,
|
|
8553
|
+
pinnedCount: decayed.meta.pinnedCount,
|
|
8554
|
+
tokensBaseline: decayed.meta.tokensBaseline,
|
|
8555
|
+
tokensActual: decayed.meta.tokensActual,
|
|
8556
|
+
tokensSaved: decayed.meta.tokensSaved
|
|
8557
|
+
}
|
|
8558
|
+
};
|
|
8559
|
+
}
|
|
8560
|
+
var log28;
|
|
8561
|
+
var init_flow_compact = __esm({
|
|
8562
|
+
"src/core/context/flow-compact.ts"() {
|
|
8563
|
+
init_esm_shims();
|
|
8564
|
+
init_flow_config();
|
|
8565
|
+
init_flow_index();
|
|
8566
|
+
init_topological_decay();
|
|
8567
|
+
init_compact_context();
|
|
8568
|
+
init_episodic_outcomes_store();
|
|
8569
|
+
init_flow_metrics_store();
|
|
8570
|
+
init_id();
|
|
8571
|
+
init_logger();
|
|
8572
|
+
log28 = createLogger({ layer: "core", source: "flow-compact.ts" });
|
|
8573
|
+
}
|
|
8574
|
+
});
|
|
7576
8575
|
|
|
7577
8576
|
// src/cli/shared/live-implement.ts
|
|
7578
8577
|
function buildLiveImplement(options) {
|
|
@@ -7589,6 +8588,14 @@ function buildLiveImplement(options) {
|
|
|
7589
8588
|
const repoRelations = projectId ? codeStore.getAllRelations(projectId) : [];
|
|
7590
8589
|
const implement = async (node) => {
|
|
7591
8590
|
const repoMap = repoSymbols.length > 0 ? buildRepoMap({ symbols: repoSymbols, relations: repoRelations }, { tokenBudget: REPO_MAP_TOKEN_BUDGET, focus: node.title }).text : void 0;
|
|
8591
|
+
let flowContext;
|
|
8592
|
+
const flow = applyFlowToCompact(store2, node.id);
|
|
8593
|
+
if (flow) {
|
|
8594
|
+
flowContext = formatFlowContext(flow);
|
|
8595
|
+
onLog?.(
|
|
8596
|
+
` [flow] \u03A6=${flow.flow.phi.toFixed(2)} \u03BB=${flow.flow.lambda.toFixed(2)} podados=${flow.flow.prunedCount} pinados=${flow.flow.pinnedCount} \u2192 ${flow.flow.tokensSaved} tok economizados`
|
|
8597
|
+
);
|
|
8598
|
+
}
|
|
7592
8599
|
const outcome = await attemptImplementation(
|
|
7593
8600
|
{
|
|
7594
8601
|
generate: async (prompt) => {
|
|
@@ -7604,13 +8611,28 @@ function buildLiveImplement(options) {
|
|
|
7604
8611
|
},
|
|
7605
8612
|
execute: (plan) => executePlan(plan, { workspaceDir: dir, defaultTestCommand: testCmd })
|
|
7606
8613
|
},
|
|
7607
|
-
{ node, maxAttempts, repoMap }
|
|
8614
|
+
{ node, maxAttempts, repoMap, flowContext }
|
|
7608
8615
|
);
|
|
7609
8616
|
const files = outcome.lastResult?.applied.length ?? 0;
|
|
7610
8617
|
const task = ledger.byTask(node.id);
|
|
7611
8618
|
onLog?.(
|
|
7612
8619
|
` [live] ${client.modelFor("implement")}: ${outcome.attempts} tentativa(s), ${files} arquivo(s), ${task.total} tok \u2192 ${outcome.success ? "verde" : "escala"}`
|
|
7613
8620
|
);
|
|
8621
|
+
try {
|
|
8622
|
+
const applied = outcome.lastResult?.applied ?? [];
|
|
8623
|
+
insertEpisodicOutcome(store2.getDb(), {
|
|
8624
|
+
id: generateId("epi"),
|
|
8625
|
+
nodeId: node.id,
|
|
8626
|
+
taskType: "",
|
|
8627
|
+
tags: "",
|
|
8628
|
+
approachSummary: buildApproachSummary(applied, []),
|
|
8629
|
+
outcome: outcome.success ? "success" : "failure",
|
|
8630
|
+
cycleTimeDelta: 0,
|
|
8631
|
+
reopenCount: 0,
|
|
8632
|
+
createdAt: Date.now()
|
|
8633
|
+
});
|
|
8634
|
+
} catch {
|
|
8635
|
+
}
|
|
7614
8636
|
return outcome.success;
|
|
7615
8637
|
};
|
|
7616
8638
|
return { implement, repoSymbolCount: repoSymbols.length };
|
|
@@ -7625,6 +8647,9 @@ var init_live_implement = __esm({
|
|
|
7625
8647
|
init_implement_attempt();
|
|
7626
8648
|
init_code_store();
|
|
7627
8649
|
init_repo_map();
|
|
8650
|
+
init_flow_compact();
|
|
8651
|
+
init_episodic_outcomes_store();
|
|
8652
|
+
init_id();
|
|
7628
8653
|
REPO_MAP_TOKEN_BUDGET = 1e3;
|
|
7629
8654
|
}
|
|
7630
8655
|
});
|
|
@@ -7658,6 +8683,18 @@ var init_store_port = __esm({
|
|
|
7658
8683
|
init_definition_of_done();
|
|
7659
8684
|
}
|
|
7660
8685
|
});
|
|
8686
|
+
|
|
8687
|
+
// src/tui/status-line.ts
|
|
8688
|
+
function formatStatusLine(input) {
|
|
8689
|
+
const tokens = `${Math.max(0, Math.round(input.totalTokens))} tok`;
|
|
8690
|
+
const cost = `$${input.costUsd.toFixed(4)}`;
|
|
8691
|
+
return `\u26C1 ${tokens} \xB7 ${cost} \xB7 ${input.model}`;
|
|
8692
|
+
}
|
|
8693
|
+
var init_status_line = __esm({
|
|
8694
|
+
"src/tui/status-line.ts"() {
|
|
8695
|
+
init_esm_shims();
|
|
8696
|
+
}
|
|
8697
|
+
});
|
|
7661
8698
|
function TaskRow({ task }) {
|
|
7662
8699
|
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
7663
8700
|
" ",
|
|
@@ -7684,6 +8721,7 @@ function App({ model }) {
|
|
|
7684
8721
|
" ",
|
|
7685
8722
|
model.wip
|
|
7686
8723
|
] }) }),
|
|
8724
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: "green", children: formatStatusLine({ totalTokens: model.tokens.total, costUsd: model.tokens.costUsd, model: model.modelLabel }) }) }),
|
|
7687
8725
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
7688
8726
|
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
7689
8727
|
"Tasks ativas (",
|
|
@@ -7714,6 +8752,7 @@ var STATUS_ICON;
|
|
|
7714
8752
|
var init_app = __esm({
|
|
7715
8753
|
"src/tui/app.tsx"() {
|
|
7716
8754
|
init_esm_shims();
|
|
8755
|
+
init_status_line();
|
|
7717
8756
|
STATUS_ICON = {
|
|
7718
8757
|
in_progress: "\u25CF",
|
|
7719
8758
|
ready: "\u25CB",
|
|
@@ -7764,6 +8803,7 @@ var init_banner_screen = __esm({
|
|
|
7764
8803
|
function CommandBar({ value, onChange, onSubmit, suggestions }) {
|
|
7765
8804
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
7766
8805
|
suggestions.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: suggestions.map((c) => /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
8806
|
+
c.source === "skill" ? /* @__PURE__ */ jsx(Text, { color: "magenta", children: "[skill] " }) : null,
|
|
7767
8807
|
c.usage,
|
|
7768
8808
|
" \u2014 ",
|
|
7769
8809
|
c.desc
|
|
@@ -7780,6 +8820,28 @@ var init_command_bar = __esm({
|
|
|
7780
8820
|
}
|
|
7781
8821
|
});
|
|
7782
8822
|
|
|
8823
|
+
// src/tui/history.ts
|
|
8824
|
+
function valueAt(state, cursor) {
|
|
8825
|
+
if (cursor < 0) return state.draft;
|
|
8826
|
+
return state.history[state.history.length - 1 - cursor];
|
|
8827
|
+
}
|
|
8828
|
+
function navigateHistory(state, dir) {
|
|
8829
|
+
const last = state.history.length - 1;
|
|
8830
|
+
if (last < 0) return { value: state.draft, cursor: -1 };
|
|
8831
|
+
let cursor = state.cursor;
|
|
8832
|
+
if (dir === "up") {
|
|
8833
|
+
cursor = Math.min(cursor + 1, last);
|
|
8834
|
+
} else {
|
|
8835
|
+
cursor = Math.max(cursor - 1, -1);
|
|
8836
|
+
}
|
|
8837
|
+
return { value: valueAt(state, cursor), cursor };
|
|
8838
|
+
}
|
|
8839
|
+
var init_history = __esm({
|
|
8840
|
+
"src/tui/history.ts"() {
|
|
8841
|
+
init_esm_shims();
|
|
8842
|
+
}
|
|
8843
|
+
});
|
|
8844
|
+
|
|
7783
8845
|
// src/tui/dispatch.ts
|
|
7784
8846
|
function parseCommand(input) {
|
|
7785
8847
|
const trimmed = input.trim();
|
|
@@ -7789,11 +8851,38 @@ function parseCommand(input) {
|
|
|
7789
8851
|
if (sp === -1) return { cmd: body.toLowerCase(), args: "" };
|
|
7790
8852
|
return { cmd: body.slice(0, sp).toLowerCase(), args: body.slice(sp + 1).trim() };
|
|
7791
8853
|
}
|
|
8854
|
+
function fuzzyScore(query, text) {
|
|
8855
|
+
const q = query.toLowerCase();
|
|
8856
|
+
const t = text.toLowerCase();
|
|
8857
|
+
if (q === "") return 0;
|
|
8858
|
+
let qi = 0;
|
|
8859
|
+
let score = 0;
|
|
8860
|
+
let lastMatch = -1;
|
|
8861
|
+
for (let ti = 0; ti < t.length && qi < q.length; ti++) {
|
|
8862
|
+
if (t[ti] === q[qi]) {
|
|
8863
|
+
if (lastMatch === -1) score += ti;
|
|
8864
|
+
else score += ti - lastMatch - 1;
|
|
8865
|
+
lastMatch = ti;
|
|
8866
|
+
qi++;
|
|
8867
|
+
}
|
|
8868
|
+
}
|
|
8869
|
+
return qi === q.length ? score : null;
|
|
8870
|
+
}
|
|
8871
|
+
function fuzzyFilter(query, commands) {
|
|
8872
|
+
if (query.trim() === "") return [...commands];
|
|
8873
|
+
const scored = [];
|
|
8874
|
+
commands.forEach((cmd, idx) => {
|
|
8875
|
+
const score = fuzzyScore(query, cmd.name);
|
|
8876
|
+
if (score !== null) scored.push({ cmd, score, idx });
|
|
8877
|
+
});
|
|
8878
|
+
scored.sort((a, b) => a.score !== b.score ? a.score - b.score : a.idx - b.idx);
|
|
8879
|
+
return scored.map((s) => s.cmd);
|
|
8880
|
+
}
|
|
7792
8881
|
function filterCommands(input, extra = []) {
|
|
7793
8882
|
const trimmed = input.trim();
|
|
7794
8883
|
if (!trimmed.startsWith("/")) return [];
|
|
7795
|
-
const
|
|
7796
|
-
return [...COMMANDS, ...extra]
|
|
8884
|
+
const query = trimmed.slice(1).split(" ")[0];
|
|
8885
|
+
return fuzzyFilter(query, [...COMMANDS, ...extra]);
|
|
7797
8886
|
}
|
|
7798
8887
|
async function runAsyncCommand(port, parsed, _onLine) {
|
|
7799
8888
|
switch (parsed.cmd) {
|
|
@@ -7890,15 +8979,30 @@ function InteractiveApp({ dashboard, port, asyncPort, liveRunner, skillCommands
|
|
|
7890
8979
|
process.stdout.isTTY ? "banner" : "dashboard"
|
|
7891
8980
|
);
|
|
7892
8981
|
const [input, setInput] = useState("");
|
|
7893
|
-
const [
|
|
8982
|
+
const [log48, setLog] = useState([]);
|
|
7894
8983
|
const [running, setRunning] = useState(false);
|
|
7895
8984
|
const [showHelp, setShowHelp] = useState(false);
|
|
8985
|
+
const [history, setHistory] = useState([]);
|
|
8986
|
+
const [histCursor, setHistCursor] = useState(-1);
|
|
8987
|
+
const [draft, setDraft] = useState("");
|
|
7896
8988
|
const append = (line) => setLog((prev) => [...prev, line].slice(-MAX_LOG_LINES));
|
|
8989
|
+
useInput((_input, key) => {
|
|
8990
|
+
if (phase !== "dashboard" || running) return;
|
|
8991
|
+
if (!key.upArrow && !key.downArrow) return;
|
|
8992
|
+
const effectiveDraft = histCursor === -1 ? input : draft;
|
|
8993
|
+
if (histCursor === -1) setDraft(input);
|
|
8994
|
+
const result = navigateHistory({ history, cursor: histCursor, draft: effectiveDraft }, key.upArrow ? "up" : "down");
|
|
8995
|
+
setHistCursor(result.cursor);
|
|
8996
|
+
setInput(result.value);
|
|
8997
|
+
});
|
|
7897
8998
|
const submit = (raw) => {
|
|
7898
8999
|
const parsed = parseCommand(raw);
|
|
7899
9000
|
setInput("");
|
|
7900
9001
|
const text = raw.trim();
|
|
7901
9002
|
if (text === "" || running) return;
|
|
9003
|
+
setHistory((prev) => [...prev, text]);
|
|
9004
|
+
setHistCursor(-1);
|
|
9005
|
+
setDraft("");
|
|
7902
9006
|
if (parsed.cmd === "quit") {
|
|
7903
9007
|
exit();
|
|
7904
9008
|
return;
|
|
@@ -7939,7 +9043,7 @@ ${skill.body}` : `Skill n\xE3o encontrada: ${parsed.cmd}`);
|
|
|
7939
9043
|
}
|
|
7940
9044
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
7941
9045
|
/* @__PURE__ */ jsx(App, { model: dashboard }),
|
|
7942
|
-
|
|
9046
|
+
log48.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: "single", paddingX: 1, children: log48.map((line, i) => /* @__PURE__ */ jsx(Text, { children: line }, i)) }),
|
|
7943
9047
|
showHelp && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", paddingX: 1, children: [
|
|
7944
9048
|
/* @__PURE__ */ jsx(Text, { bold: true, children: "Comandos:" }),
|
|
7945
9049
|
COMMANDS.map((c) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
@@ -7962,6 +9066,7 @@ var init_interactive_app = __esm({
|
|
|
7962
9066
|
init_app();
|
|
7963
9067
|
init_banner_screen();
|
|
7964
9068
|
init_command_bar();
|
|
9069
|
+
init_history();
|
|
7965
9070
|
init_dispatch();
|
|
7966
9071
|
MAX_LOG_LINES = 12;
|
|
7967
9072
|
}
|
|
@@ -8166,22 +9271,25 @@ function parseSkillMarkdown(content) {
|
|
|
8166
9271
|
} catch (err) {
|
|
8167
9272
|
return { ok: false, error: `YAML parse error: ${err instanceof Error ? err.message : String(err)}` };
|
|
8168
9273
|
}
|
|
9274
|
+
const rawTriggers = frontmatter.triggers;
|
|
9275
|
+
const triggers = Array.isArray(rawTriggers) ? rawTriggers.map((t) => typeof t === "string" ? { event: t } : t) : rawTriggers;
|
|
9276
|
+
const phases = Array.isArray(frontmatter.phases) ? frontmatter.phases : [];
|
|
8169
9277
|
const raw = {
|
|
8170
9278
|
name: frontmatter.name,
|
|
8171
9279
|
description: frontmatter.description,
|
|
8172
9280
|
category: frontmatter.category ?? "know-me",
|
|
8173
|
-
phases
|
|
9281
|
+
phases,
|
|
8174
9282
|
// §extracta-sweep-1 — optional `platforms:` array; absent = all OSes.
|
|
8175
9283
|
platforms: frontmatter.platforms,
|
|
8176
9284
|
instructions: bodyText,
|
|
8177
9285
|
toolchain: frontmatter.toolchain,
|
|
8178
|
-
triggers
|
|
9286
|
+
triggers,
|
|
8179
9287
|
contextTemplate: frontmatter.contextTemplate
|
|
8180
9288
|
};
|
|
8181
9289
|
const parsed = CustomSkillInputSchema.safeParse(raw);
|
|
8182
9290
|
if (!parsed.success) {
|
|
8183
9291
|
const issues = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
8184
|
-
|
|
9292
|
+
log29.debug("skill-loader:validation_failed", { issues });
|
|
8185
9293
|
return { ok: false, error: `Validation failed: ${issues}` };
|
|
8186
9294
|
}
|
|
8187
9295
|
return { ok: true, skill: parsed.data };
|
|
@@ -8224,13 +9332,13 @@ function walk(dir, acc) {
|
|
|
8224
9332
|
else acc.errors.push({ file: full, error: parsed.error ?? "unknown parse error" });
|
|
8225
9333
|
}
|
|
8226
9334
|
}
|
|
8227
|
-
var
|
|
9335
|
+
var log29;
|
|
8228
9336
|
var init_skill_loader = __esm({
|
|
8229
9337
|
"src/core/skills/skill-loader.ts"() {
|
|
8230
9338
|
init_esm_shims();
|
|
8231
9339
|
init_skill_schema();
|
|
8232
9340
|
init_logger();
|
|
8233
|
-
|
|
9341
|
+
log29 = createLogger({ layer: "core", source: "skill-loader.ts" });
|
|
8234
9342
|
}
|
|
8235
9343
|
});
|
|
8236
9344
|
function summarize(skill) {
|
|
@@ -8323,7 +9431,7 @@ function mergeGraph(store2, incoming, options) {
|
|
|
8323
9431
|
}
|
|
8324
9432
|
const sourceProject = incoming.project.name;
|
|
8325
9433
|
const dryRun = options?.dryRun ?? false;
|
|
8326
|
-
|
|
9434
|
+
log30.info("merge-graph:start", {
|
|
8327
9435
|
sourceProject,
|
|
8328
9436
|
incomingNodes: incoming.nodes.length,
|
|
8329
9437
|
incomingEdges: incoming.edges.length,
|
|
@@ -8375,7 +9483,7 @@ function mergeGraph(store2, incoming, options) {
|
|
|
8375
9483
|
edgesInserted2++;
|
|
8376
9484
|
}
|
|
8377
9485
|
}
|
|
8378
|
-
|
|
9486
|
+
log30.info("merge-graph:dry-run", {
|
|
8379
9487
|
nodesInserted: nodesToInsert.length,
|
|
8380
9488
|
nodesSkipped,
|
|
8381
9489
|
edgesInserted: edgesInserted2,
|
|
@@ -8395,7 +9503,7 @@ function mergeGraph(store2, incoming, options) {
|
|
|
8395
9503
|
const { nodesInserted, edgesInserted } = store2.mergeInsert(nodesToInsert, validEdges);
|
|
8396
9504
|
const edgesSkipped = validEdges.length - edgesInserted;
|
|
8397
9505
|
store2.recordImport(`merge:${sourceProject}`, nodesInserted, edgesInserted);
|
|
8398
|
-
|
|
9506
|
+
log30.info("merge-graph:done", {
|
|
8399
9507
|
sourceProject,
|
|
8400
9508
|
nodesInserted,
|
|
8401
9509
|
nodesSkipped,
|
|
@@ -8412,14 +9520,14 @@ function mergeGraph(store2, incoming, options) {
|
|
|
8412
9520
|
sourceProject
|
|
8413
9521
|
};
|
|
8414
9522
|
}
|
|
8415
|
-
var
|
|
9523
|
+
var log30;
|
|
8416
9524
|
var init_import_graph = __esm({
|
|
8417
9525
|
"src/core/importer/import-graph.ts"() {
|
|
8418
9526
|
init_esm_shims();
|
|
8419
9527
|
init_graph_schema();
|
|
8420
9528
|
init_errors();
|
|
8421
9529
|
init_logger();
|
|
8422
|
-
|
|
9530
|
+
log30 = createLogger({ layer: "core", source: "import-graph.ts" });
|
|
8423
9531
|
}
|
|
8424
9532
|
});
|
|
8425
9533
|
|
|
@@ -8530,7 +9638,7 @@ function computeFileSha256(path22) {
|
|
|
8530
9638
|
return hash.digest("hex");
|
|
8531
9639
|
}
|
|
8532
9640
|
async function downloadFileWithVerify(url, destPath, expectedSha256) {
|
|
8533
|
-
|
|
9641
|
+
log31.info("model-downloader:start", { url, dest: destPath, hasExpectedHash: false });
|
|
8534
9642
|
const controller = new AbortController();
|
|
8535
9643
|
const timeoutId = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT_MS);
|
|
8536
9644
|
let response;
|
|
@@ -8552,15 +9660,15 @@ async function downloadFileWithVerify(url, destPath, expectedSha256) {
|
|
|
8552
9660
|
const actualSha = computeFileSha256(destPath);
|
|
8553
9661
|
const sizeBytes = statSync(destPath).size;
|
|
8554
9662
|
const verified = expectedSha256 != null && actualSha === expectedSha256;
|
|
8555
|
-
|
|
9663
|
+
log31.info("model-downloader:ok", { dest: destPath, sizeBytes, sha256: actualSha, verified });
|
|
8556
9664
|
return { sha256: actualSha, verified, sizeBytes };
|
|
8557
9665
|
}
|
|
8558
|
-
var
|
|
9666
|
+
var log31, DOWNLOAD_TIMEOUT_MS, ChecksumMismatchError, DownloadError;
|
|
8559
9667
|
var init_model_downloader = __esm({
|
|
8560
9668
|
"src/core/rag/model-downloader.ts"() {
|
|
8561
9669
|
init_esm_shims();
|
|
8562
9670
|
init_logger();
|
|
8563
|
-
|
|
9671
|
+
log31 = createLogger({ layer: "core", source: "model-downloader.ts" });
|
|
8564
9672
|
DOWNLOAD_TIMEOUT_MS = 9e4;
|
|
8565
9673
|
ChecksumMismatchError = class extends Error {
|
|
8566
9674
|
constructor(url, expected, actual) {
|
|
@@ -8629,15 +9737,15 @@ async function isOnnxAvailable() {
|
|
|
8629
9737
|
onnxAvailableCache = true;
|
|
8630
9738
|
} catch {
|
|
8631
9739
|
onnxAvailableCache = false;
|
|
8632
|
-
|
|
9740
|
+
log32.warn("onnx:unavailable", { reason: "onnxruntime-node not installed \u2014 RAG will use hash embeddings (degraded mode)" });
|
|
8633
9741
|
}
|
|
8634
9742
|
return onnxAvailableCache;
|
|
8635
9743
|
}
|
|
8636
9744
|
async function logEmbeddingModeOnBoot(isAvailable = isOnnxAvailable, logFn = (event, fields) => {
|
|
8637
9745
|
if (fields.mode === "neural") {
|
|
8638
|
-
|
|
9746
|
+
log32.info(event, fields);
|
|
8639
9747
|
} else {
|
|
8640
|
-
|
|
9748
|
+
log32.warn(event, fields);
|
|
8641
9749
|
}
|
|
8642
9750
|
}) {
|
|
8643
9751
|
try {
|
|
@@ -8660,7 +9768,7 @@ function ensureOnnxModelDir(modelsDir) {
|
|
|
8660
9768
|
async function downloadFile(url, destPath) {
|
|
8661
9769
|
try {
|
|
8662
9770
|
const resultValue = await downloadFileWithVerify(url, destPath);
|
|
8663
|
-
|
|
9771
|
+
log32.info("onnx:download:ok", {
|
|
8664
9772
|
dest: destPath,
|
|
8665
9773
|
sizeBytes: resultValue.sizeBytes,
|
|
8666
9774
|
sha256: resultValue.sha256,
|
|
@@ -8684,7 +9792,7 @@ async function ensureModelFiles(modelsDir) {
|
|
|
8684
9792
|
if (existsSync(modelPath)) {
|
|
8685
9793
|
const size = statSync(modelPath).size;
|
|
8686
9794
|
if (size < MIN_MODEL_SIZE) {
|
|
8687
|
-
|
|
9795
|
+
log32.warn("onnx:corrupted-model", { modelPath, sizeBytes: size, minRequired: MIN_MODEL_SIZE });
|
|
8688
9796
|
unlinkSync(modelPath);
|
|
8689
9797
|
}
|
|
8690
9798
|
}
|
|
@@ -8693,12 +9801,12 @@ async function ensureModelFiles(modelsDir) {
|
|
|
8693
9801
|
const raw = readFileSync(tokenizerPath, "utf-8");
|
|
8694
9802
|
JSON.parse(raw);
|
|
8695
9803
|
} catch {
|
|
8696
|
-
|
|
9804
|
+
log32.warn("onnx:corrupted-tokenizer", { tokenizerPath });
|
|
8697
9805
|
unlinkSync(tokenizerPath);
|
|
8698
9806
|
}
|
|
8699
9807
|
}
|
|
8700
9808
|
if (existsSync(modelPath) && existsSync(tokenizerPath)) {
|
|
8701
|
-
|
|
9809
|
+
log32.debug("onnx:cache-hit", { modelDir });
|
|
8702
9810
|
return { modelPath, tokenizerPath };
|
|
8703
9811
|
}
|
|
8704
9812
|
mkdirSync(modelDir, { recursive: true });
|
|
@@ -8715,7 +9823,7 @@ function loadTokenizer(tokenizerPath) {
|
|
|
8715
9823
|
const raw = readFileSync(tokenizerPath, "utf-8");
|
|
8716
9824
|
return JSON.parse(raw);
|
|
8717
9825
|
} catch (err) {
|
|
8718
|
-
|
|
9826
|
+
log32.warn("onnx:tokenizer-load-failed", { tokenizerPath, error: err instanceof Error ? err.message : String(err) });
|
|
8719
9827
|
return null;
|
|
8720
9828
|
}
|
|
8721
9829
|
}
|
|
@@ -8767,15 +9875,15 @@ function startOnnxBackgroundDownload(modelsDir, options = {}) {
|
|
|
8767
9875
|
modelPath = join(modelDir, MODEL_FILENAME);
|
|
8768
9876
|
tokenizerPath = join(modelDir, TOKENIZER_FILENAME);
|
|
8769
9877
|
const cacheEvent = "onnx:background-ready-from-cache";
|
|
8770
|
-
|
|
9878
|
+
log32.info(cacheEvent, { modelsDir });
|
|
8771
9879
|
onLog?.(cacheEvent);
|
|
8772
9880
|
} else {
|
|
8773
9881
|
const startEvent = "onnx:background-download-start";
|
|
8774
|
-
|
|
9882
|
+
log32.info(startEvent, { message: "Downloading MiniLM-L6-v2 (23MB)...", modelsDir });
|
|
8775
9883
|
onLog?.(startEvent);
|
|
8776
9884
|
({ modelPath, tokenizerPath } = await ensureFiles(modelsDir));
|
|
8777
9885
|
const doneEvent = "onnx:background-download-complete";
|
|
8778
|
-
|
|
9886
|
+
log32.info(doneEvent, { modelsDir });
|
|
8779
9887
|
onLog?.(doneEvent);
|
|
8780
9888
|
}
|
|
8781
9889
|
const provider = makeProvider(modelPath, tokenizerPath);
|
|
@@ -8783,7 +9891,7 @@ function startOnnxBackgroundDownload(modelsDir, options = {}) {
|
|
|
8783
9891
|
onReady?.(provider);
|
|
8784
9892
|
} catch (err) {
|
|
8785
9893
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8786
|
-
|
|
9894
|
+
log32.warn("onnx:background-download-failed", { error: msg, action: "fallback-remains-tfidf" });
|
|
8787
9895
|
onWarning?.(msg);
|
|
8788
9896
|
}
|
|
8789
9897
|
};
|
|
@@ -8797,7 +9905,7 @@ function _resetBackgroundDownloadState() {
|
|
|
8797
9905
|
async function getOnnxProvider(modelsDir) {
|
|
8798
9906
|
const available = await isOnnxAvailable();
|
|
8799
9907
|
if (!available) {
|
|
8800
|
-
|
|
9908
|
+
log32.warn("onnx:provider-degraded", { available: false, impact: "RAG operates with hash embeddings instead of neural \u2014 lower search quality" });
|
|
8801
9909
|
return null;
|
|
8802
9910
|
}
|
|
8803
9911
|
const existing = providerCache.get(modelsDir);
|
|
@@ -8817,8 +9925,8 @@ async function getOnnxProvider(modelsDir) {
|
|
|
8817
9925
|
return await creation;
|
|
8818
9926
|
} catch (err) {
|
|
8819
9927
|
providerCache.delete(modelsDir);
|
|
8820
|
-
|
|
8821
|
-
|
|
9928
|
+
log32.error("onnx:provider-init-failed", { error: err instanceof Error ? err.message : String(err) });
|
|
9929
|
+
log32.warn("onnx:fallback", {
|
|
8822
9930
|
reason: err instanceof Error ? err.message : String(err),
|
|
8823
9931
|
action: "return-null-provider",
|
|
8824
9932
|
modelsDir
|
|
@@ -8826,7 +9934,7 @@ async function getOnnxProvider(modelsDir) {
|
|
|
8826
9934
|
return null;
|
|
8827
9935
|
}
|
|
8828
9936
|
}
|
|
8829
|
-
var
|
|
9937
|
+
var log32, MODEL_NAME, MODEL_FILENAME, TOKENIZER_FILENAME, EMBEDDING_DIM, MAX_SEQUENCE_LENGTH, MODEL_BASE_URL, MODEL_URL, TOKENIZER_URL, DOWNLOAD_TIMEOUT_MS2, onnxAvailableCache, OnnxEmbeddingProvider, _backgroundProvider, _backgroundStarted, providerCache;
|
|
8830
9938
|
var init_onnx_embeddings = __esm({
|
|
8831
9939
|
"src/core/rag/onnx-embeddings.ts"() {
|
|
8832
9940
|
init_esm_shims();
|
|
@@ -8834,7 +9942,7 @@ var init_onnx_embeddings = __esm({
|
|
|
8834
9942
|
init_errors();
|
|
8835
9943
|
init_tensor_buffer_pool();
|
|
8836
9944
|
init_model_downloader();
|
|
8837
|
-
|
|
9945
|
+
log32 = createLogger({ layer: "rag", source: "onnx-embeddings.ts" });
|
|
8838
9946
|
MODEL_NAME = "all-MiniLM-L6-v2-quantized";
|
|
8839
9947
|
MODEL_FILENAME = "model.onnx";
|
|
8840
9948
|
TOKENIZER_FILENAME = "tokenizer.json";
|
|
@@ -8866,7 +9974,7 @@ var init_onnx_embeddings = __esm({
|
|
|
8866
9974
|
throw new OnnxModelNotFoundError(`Failed to load tokenizer: ${this.tokenizerPath}`);
|
|
8867
9975
|
}
|
|
8868
9976
|
this.vocab = config.model?.vocab ?? {};
|
|
8869
|
-
|
|
9977
|
+
log32.info("onnx:session-created", { model: this.modelPath });
|
|
8870
9978
|
return this.session;
|
|
8871
9979
|
}
|
|
8872
9980
|
async generateEmbedding(text) {
|
|
@@ -8995,7 +10103,7 @@ async function checkSqliteDatabase(basePath) {
|
|
|
8995
10103
|
};
|
|
8996
10104
|
}
|
|
8997
10105
|
} catch (err) {
|
|
8998
|
-
|
|
10106
|
+
log33.debug("intentional-swallow", { error: String(err), reason: "statSync race with deletion; fall through to open attempt" });
|
|
8999
10107
|
}
|
|
9000
10108
|
try {
|
|
9001
10109
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -9045,7 +10153,7 @@ async function checkDbIntegrity2(basePath) {
|
|
|
9045
10153
|
};
|
|
9046
10154
|
}
|
|
9047
10155
|
} catch (err) {
|
|
9048
|
-
|
|
10156
|
+
log33.debug("intentional-swallow", { error: String(err), reason: "fall through to open attempt" });
|
|
9049
10157
|
}
|
|
9050
10158
|
try {
|
|
9051
10159
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -9053,7 +10161,7 @@ async function checkDbIntegrity2(basePath) {
|
|
|
9053
10161
|
try {
|
|
9054
10162
|
schemaCount = db.prepare("SELECT count(*) as n FROM sqlite_master WHERE type IN ('table','view')").get().n;
|
|
9055
10163
|
} catch (err) {
|
|
9056
|
-
|
|
10164
|
+
log33.debug("intentional-swallow", { error: String(err), reason: "reading sqlite_master itself failed \u2014 DB is unreadable, fall through" });
|
|
9057
10165
|
}
|
|
9058
10166
|
if (schemaCount === 0) {
|
|
9059
10167
|
db.close();
|
|
@@ -9213,7 +10321,7 @@ async function checkIntegrations(basePath) {
|
|
|
9213
10321
|
});
|
|
9214
10322
|
return results;
|
|
9215
10323
|
} catch (err) {
|
|
9216
|
-
|
|
10324
|
+
log33.debug("doctor:integrations:fail", {
|
|
9217
10325
|
error: err instanceof Error ? err.message : String(err)
|
|
9218
10326
|
});
|
|
9219
10327
|
return [
|
|
@@ -9264,7 +10372,7 @@ async function checkOnnxStatus() {
|
|
|
9264
10372
|
const { isOnnxAvailable: isOnnxAvailable2 } = await Promise.resolve().then(() => (init_onnx_embeddings(), onnx_embeddings_exports));
|
|
9265
10373
|
return checkOnnxStatusWith(isOnnxAvailable2);
|
|
9266
10374
|
}
|
|
9267
|
-
var
|
|
10375
|
+
var log33, MIN_NODE_VERSION;
|
|
9268
10376
|
var init_doctor_checks = __esm({
|
|
9269
10377
|
"src/core/doctor/doctor-checks.ts"() {
|
|
9270
10378
|
init_esm_shims();
|
|
@@ -9272,7 +10380,7 @@ var init_doctor_checks = __esm({
|
|
|
9272
10380
|
init_fs();
|
|
9273
10381
|
init_tool_status();
|
|
9274
10382
|
init_logger();
|
|
9275
|
-
|
|
10383
|
+
log33 = createLogger({ layer: "core", source: "doctor-checks.ts" });
|
|
9276
10384
|
MIN_NODE_VERSION = 20;
|
|
9277
10385
|
}
|
|
9278
10386
|
});
|
|
@@ -9297,7 +10405,7 @@ async function runDoctor(basePath) {
|
|
|
9297
10405
|
if (!basePath) {
|
|
9298
10406
|
throw new McpGraphError("Doctor requires a valid base path");
|
|
9299
10407
|
}
|
|
9300
|
-
|
|
10408
|
+
log34.info("Running doctor checks", { basePath });
|
|
9301
10409
|
const checks = [];
|
|
9302
10410
|
checks.push(checkNodeVersion());
|
|
9303
10411
|
checks.push(checkConfigFile(basePath));
|
|
@@ -9335,7 +10443,7 @@ async function runDoctor(basePath) {
|
|
|
9335
10443
|
}
|
|
9336
10444
|
}
|
|
9337
10445
|
for (const result of checks) {
|
|
9338
|
-
|
|
10446
|
+
log34.event(
|
|
9339
10447
|
{ action: "health.check", category: "health", outcome: result.level === "ok" ? "success" : "failure" },
|
|
9340
10448
|
`health.check.${result.name}`,
|
|
9341
10449
|
{ check: result.name }
|
|
@@ -9348,7 +10456,7 @@ async function runDoctor(basePath) {
|
|
|
9348
10456
|
passed: summary.error === 0
|
|
9349
10457
|
};
|
|
9350
10458
|
}
|
|
9351
|
-
var
|
|
10459
|
+
var log34;
|
|
9352
10460
|
var init_doctor_runner = __esm({
|
|
9353
10461
|
"src/core/doctor/doctor-runner.ts"() {
|
|
9354
10462
|
init_esm_shims();
|
|
@@ -9357,7 +10465,7 @@ var init_doctor_runner = __esm({
|
|
|
9357
10465
|
init_errors();
|
|
9358
10466
|
init_logger();
|
|
9359
10467
|
init_doctor_checks();
|
|
9360
|
-
|
|
10468
|
+
log34 = createLogger({ layer: "core", source: "doctor-runner.ts" });
|
|
9361
10469
|
}
|
|
9362
10470
|
});
|
|
9363
10471
|
|
|
@@ -9490,7 +10598,8 @@ async function launchTui(store2) {
|
|
|
9490
10598
|
return skills.map((s) => ({
|
|
9491
10599
|
name: s.name,
|
|
9492
10600
|
usage: `/${s.name}`,
|
|
9493
|
-
desc: `[${s.category}] ${s.description}
|
|
10601
|
+
desc: `[${s.category}] ${s.description}`,
|
|
10602
|
+
source: "skill"
|
|
9494
10603
|
}));
|
|
9495
10604
|
});
|
|
9496
10605
|
const instance = render(
|
|
@@ -10104,16 +11213,36 @@ init_token_ledger();
|
|
|
10104
11213
|
init_llm_call_ledger();
|
|
10105
11214
|
init_live_implement();
|
|
10106
11215
|
init_store_port();
|
|
11216
|
+
|
|
11217
|
+
// src/cli/shared/enable-flow.ts
|
|
11218
|
+
init_esm_shims();
|
|
11219
|
+
init_flow_config();
|
|
11220
|
+
function enableFlowConfig(store2) {
|
|
11221
|
+
const raw = store2.getProjectSetting(FLOW_CONFIG_SETTING_KEY);
|
|
11222
|
+
let current = {};
|
|
11223
|
+
if (raw) {
|
|
11224
|
+
try {
|
|
11225
|
+
current = JSON.parse(raw);
|
|
11226
|
+
} catch {
|
|
11227
|
+
current = {};
|
|
11228
|
+
}
|
|
11229
|
+
}
|
|
11230
|
+
store2.setProjectSetting(FLOW_CONFIG_SETTING_KEY, JSON.stringify({ ...current, enabled: true }));
|
|
11231
|
+
}
|
|
10107
11232
|
function output7(msg) {
|
|
10108
11233
|
process.stdout.write(msg + "\n");
|
|
10109
11234
|
}
|
|
10110
11235
|
function autopilotCommand() {
|
|
10111
|
-
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").action(
|
|
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(
|
|
10112
11237
|
async (opts) => {
|
|
10113
11238
|
const store2 = openStoreOrFail(opts.dir, { requireExisting: true });
|
|
10114
11239
|
try {
|
|
10115
11240
|
const maxIterations = Math.max(1, parseInt(opts.max, 10) || 5);
|
|
10116
11241
|
const port = makeStorePort(store2);
|
|
11242
|
+
if (opts.flow) {
|
|
11243
|
+
enableFlowConfig(store2);
|
|
11244
|
+
output7("[FLOW] \u03BB_flow ativo: contexto do grafo dilu\xEDdo por \u03A6(t) (esquecimento din\xE2mico).\n");
|
|
11245
|
+
}
|
|
10117
11246
|
if (opts.simulate) output7("[SIMULA\xC7\xC3O] impl tratada como verde \u2014 DoD real decide prontid\xE3o.\n");
|
|
10118
11247
|
if (opts.live) output7("[LIVE] modelo via SDK do Copilot: gera plano \u2192 aplica no workspace \u2192 roda testes.\n");
|
|
10119
11248
|
let implement;
|
|
@@ -10413,7 +11542,7 @@ function whichCommand() {
|
|
|
10413
11542
|
}
|
|
10414
11543
|
|
|
10415
11544
|
// src/core/lsp/lsp-deps-installer.ts
|
|
10416
|
-
var
|
|
11545
|
+
var log36 = createLogger({ layer: "core", source: "lsp-deps-installer.ts" });
|
|
10417
11546
|
var execAsync = promisify(execFile);
|
|
10418
11547
|
var LSP_NPM_PACKAGES = {
|
|
10419
11548
|
typescript: "typescript-language-server",
|
|
@@ -10464,7 +11593,7 @@ var LSP_SYSTEM_PACKAGES = {
|
|
|
10464
11593
|
async function checkLspDep(languageId, command) {
|
|
10465
11594
|
try {
|
|
10466
11595
|
await execAsync(whichCommand(), [command]);
|
|
10467
|
-
|
|
11596
|
+
log36.info("LSP server available", { languageId, command });
|
|
10468
11597
|
return {
|
|
10469
11598
|
name: command,
|
|
10470
11599
|
languageId,
|
|
@@ -10510,7 +11639,7 @@ function getServerCommand(languageId) {
|
|
|
10510
11639
|
}
|
|
10511
11640
|
async function installLspDeps(detectedLanguages) {
|
|
10512
11641
|
if (detectedLanguages.length === 0) return [];
|
|
10513
|
-
|
|
11642
|
+
log36.info("Checking LSP server dependencies", {
|
|
10514
11643
|
languages: detectedLanguages.join(", ")
|
|
10515
11644
|
});
|
|
10516
11645
|
const results = [];
|
|
@@ -10522,7 +11651,7 @@ async function installLspDeps(detectedLanguages) {
|
|
|
10522
11651
|
}
|
|
10523
11652
|
const available = results.filter((r) => r.status === "already_available").length;
|
|
10524
11653
|
const missing = results.filter((r) => r.status === "not_found").length;
|
|
10525
|
-
|
|
11654
|
+
log36.info("LSP dependency check complete", {
|
|
10526
11655
|
total: String(results.length),
|
|
10527
11656
|
available: String(available),
|
|
10528
11657
|
missing: String(missing)
|
|
@@ -10533,7 +11662,7 @@ async function installLspDeps(detectedLanguages) {
|
|
|
10533
11662
|
// src/core/lsp/language-detector.ts
|
|
10534
11663
|
init_esm_shims();
|
|
10535
11664
|
init_logger();
|
|
10536
|
-
var
|
|
11665
|
+
var log37 = createLogger({ layer: "core", source: "language-detector.ts" });
|
|
10537
11666
|
var CONFIG_FILE_MAP = {
|
|
10538
11667
|
"tsconfig.json": "typescript",
|
|
10539
11668
|
"jsconfig.json": "typescript",
|
|
@@ -10573,7 +11702,7 @@ var IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
|
10573
11702
|
"__pycache__"
|
|
10574
11703
|
]);
|
|
10575
11704
|
function detectProjectLanguages(projectPath, registry) {
|
|
10576
|
-
|
|
11705
|
+
log37.debug("detecting project languages", { projectPath });
|
|
10577
11706
|
const configDetections = /* @__PURE__ */ new Map();
|
|
10578
11707
|
const fileCounts = /* @__PURE__ */ new Map();
|
|
10579
11708
|
detectConfigFiles(projectPath, configDetections);
|
|
@@ -10601,7 +11730,7 @@ function detectProjectLanguages(projectPath, registry) {
|
|
|
10601
11730
|
});
|
|
10602
11731
|
}
|
|
10603
11732
|
results.sort((a, b) => b.fileCount - a.fileCount);
|
|
10604
|
-
|
|
11733
|
+
log37.info("project languages detected", {
|
|
10605
11734
|
count: String(results.length),
|
|
10606
11735
|
languages: results.map((r) => r.languageId).join(",")
|
|
10607
11736
|
});
|
|
@@ -10612,7 +11741,7 @@ function detectConfigFiles(rootPath, configDetections) {
|
|
|
10612
11741
|
try {
|
|
10613
11742
|
entries = readdirSync(rootPath, { withFileTypes: true, encoding: "utf-8" });
|
|
10614
11743
|
} catch {
|
|
10615
|
-
|
|
11744
|
+
log37.debug("cannot read root directory for config detection", { rootPath });
|
|
10616
11745
|
return;
|
|
10617
11746
|
}
|
|
10618
11747
|
for (const entry of entries) {
|
|
@@ -10637,7 +11766,7 @@ function walkAndCountFiles(dirPath, registry, fileCounts) {
|
|
|
10637
11766
|
try {
|
|
10638
11767
|
entries = readdirSync(dirPath, { withFileTypes: true, encoding: "utf-8" });
|
|
10639
11768
|
} catch {
|
|
10640
|
-
|
|
11769
|
+
log37.debug("cannot read directory, skipping", { dirPath });
|
|
10641
11770
|
return;
|
|
10642
11771
|
}
|
|
10643
11772
|
for (const entry of entries) {
|
|
@@ -11722,176 +12851,10 @@ function applySection(existingContent, newSection) {
|
|
|
11722
12851
|
|
|
11723
12852
|
// src/core/config/config-loader.ts
|
|
11724
12853
|
init_esm_shims();
|
|
11725
|
-
|
|
11726
|
-
// src/core/config/config-schema.ts
|
|
11727
|
-
init_esm_shims();
|
|
11728
|
-
|
|
11729
|
-
// src/core/lsp/lsp-types.ts
|
|
11730
|
-
init_esm_shims();
|
|
11731
|
-
z.object({
|
|
11732
|
-
languageId: z.string(),
|
|
11733
|
-
extensions: z.array(z.string()),
|
|
11734
|
-
command: z.string(),
|
|
11735
|
-
args: z.array(z.string()),
|
|
11736
|
-
configFiles: z.array(z.string()),
|
|
11737
|
-
probeCommand: z.string().optional(),
|
|
11738
|
-
initializationOptions: z.record(z.string(), z.unknown()).optional(),
|
|
11739
|
-
settings: z.record(z.string(), z.unknown()).optional()
|
|
11740
|
-
});
|
|
11741
|
-
var LspConfigOverrideSchema = z.object({
|
|
11742
|
-
languageId: z.string(),
|
|
11743
|
-
command: z.string(),
|
|
11744
|
-
args: z.array(z.string()).default([]),
|
|
11745
|
-
extensions: z.array(z.string()).optional(),
|
|
11746
|
-
initializationOptions: z.record(z.string(), z.unknown()).optional(),
|
|
11747
|
-
settings: z.record(z.string(), z.unknown()).optional()
|
|
11748
|
-
});
|
|
11749
|
-
z.object({
|
|
11750
|
-
file: z.string(),
|
|
11751
|
-
startLine: z.int().min(0),
|
|
11752
|
-
startCharacter: z.int().min(0),
|
|
11753
|
-
endLine: z.int().min(0),
|
|
11754
|
-
endCharacter: z.int().min(0)
|
|
11755
|
-
});
|
|
11756
|
-
z.object({
|
|
11757
|
-
signature: z.string(),
|
|
11758
|
-
documentation: z.string().optional(),
|
|
11759
|
-
language: z.string().optional()
|
|
11760
|
-
});
|
|
11761
|
-
var LspDiagnosticSchema = z.object({
|
|
11762
|
-
file: z.string(),
|
|
11763
|
-
startLine: z.int().min(0),
|
|
11764
|
-
startCharacter: z.int().min(0),
|
|
11765
|
-
endLine: z.int().min(0),
|
|
11766
|
-
endCharacter: z.int().min(0),
|
|
11767
|
-
severity: z.number().int().min(1).max(4),
|
|
11768
|
-
message: z.string(),
|
|
11769
|
-
code: z.string().optional(),
|
|
11770
|
-
source: z.string().optional()
|
|
11771
|
-
});
|
|
11772
|
-
z.object({
|
|
11773
|
-
name: z.string(),
|
|
11774
|
-
kind: z.string(),
|
|
11775
|
-
file: z.string(),
|
|
11776
|
-
startLine: z.int().min(0),
|
|
11777
|
-
endLine: z.int().min(0)
|
|
11778
|
-
});
|
|
11779
|
-
var LspDocumentSymbolSchema = z.object({
|
|
11780
|
-
name: z.string(),
|
|
11781
|
-
kind: z.string(),
|
|
11782
|
-
file: z.string(),
|
|
11783
|
-
startLine: z.int().min(0),
|
|
11784
|
-
endLine: z.int().min(0),
|
|
11785
|
-
children: z.lazy(() => z.array(LspDocumentSymbolSchema)).optional()
|
|
11786
|
-
});
|
|
11787
|
-
var LspTextEditSchema = z.object({
|
|
11788
|
-
file: z.string(),
|
|
11789
|
-
startLine: z.int().min(0),
|
|
11790
|
-
startCharacter: z.int().min(0),
|
|
11791
|
-
endLine: z.int().min(0),
|
|
11792
|
-
endCharacter: z.int().min(0),
|
|
11793
|
-
newText: z.string()
|
|
11794
|
-
});
|
|
11795
|
-
var LspWorkspaceEditSchema = z.object({
|
|
11796
|
-
changes: z.array(LspTextEditSchema)
|
|
11797
|
-
});
|
|
11798
|
-
z.object({
|
|
11799
|
-
languageId: z.string(),
|
|
11800
|
-
status: z.enum(["stopped", "starting", "ready", "error"]),
|
|
11801
|
-
pid: z.number().int().optional(),
|
|
11802
|
-
error: z.string().optional()
|
|
11803
|
-
});
|
|
11804
|
-
z.object({
|
|
11805
|
-
languageId: z.string(),
|
|
11806
|
-
confidence: z.number().min(0).max(1),
|
|
11807
|
-
detectedVia: z.enum(["file_extension", "config_file", "shebang"]),
|
|
11808
|
-
fileCount: z.int().min(0),
|
|
11809
|
-
configFile: z.string().optional()
|
|
11810
|
-
});
|
|
11811
|
-
z.object({
|
|
11812
|
-
title: z.string(),
|
|
11813
|
-
kind: z.string().optional(),
|
|
11814
|
-
isPreferred: z.boolean().optional(),
|
|
11815
|
-
edit: LspWorkspaceEditSchema.optional(),
|
|
11816
|
-
diagnostics: z.array(LspDiagnosticSchema).optional()
|
|
11817
|
-
});
|
|
11818
|
-
z.object({
|
|
11819
|
-
applied: z.boolean(),
|
|
11820
|
-
filesModified: z.array(z.string()),
|
|
11821
|
-
totalEdits: z.number().int(),
|
|
11822
|
-
errors: z.array(z.string()),
|
|
11823
|
-
backups: z.map(z.string(), z.string()).optional()
|
|
11824
|
-
});
|
|
11825
|
-
|
|
11826
|
-
// src/core/config/config-schema.ts
|
|
11827
|
-
var BROWSER_PILOT_MODELS = ["claude-3.5-sonnet", "gpt-4o", "gpt-4o-mini", "o1", "o1-mini"];
|
|
11828
|
-
var ContextModeSchema = z.enum(["ultra-lean", "lean", "full"]);
|
|
11829
|
-
var ProfileFilterConfigSchema = z.enum(["core", "pro", "expert", "all"]);
|
|
11830
|
-
var BrowserAutomationConfigSchema = z.object({
|
|
11831
|
-
enabled: z.boolean().default(false),
|
|
11832
|
-
bridgeUrl: z.string().regex(/^https?:\/\//, "bridgeUrl must start with http:// or https://").default("http://127.0.0.1:9876/v1"),
|
|
11833
|
-
defaultModel: z.enum(BROWSER_PILOT_MODELS).default("claude-3.5-sonnet"),
|
|
11834
|
-
defaultCdpUrl: z.string().min(1).optional(),
|
|
11835
|
-
allowedDomains: z.array(z.string().min(1)).default([]),
|
|
11836
|
-
forbiddenCdpMethods: z.array(z.string().min(1)).default(["Browser.close"]),
|
|
11837
|
-
maxStepsDefault: z.number().int().min(1).max(100).default(25),
|
|
11838
|
-
tokenBudgetPerDay: z.number().int().nonnegative().optional()
|
|
11839
|
-
}).default({
|
|
11840
|
-
enabled: false,
|
|
11841
|
-
bridgeUrl: "http://127.0.0.1:9876/v1",
|
|
11842
|
-
defaultModel: "claude-3.5-sonnet",
|
|
11843
|
-
allowedDomains: [],
|
|
11844
|
-
forbiddenCdpMethods: ["Browser.close"],
|
|
11845
|
-
maxStepsDefault: 25
|
|
11846
|
-
});
|
|
11847
|
-
var FlowConfigSchema = z.object({
|
|
11848
|
-
/** Master switch. OFF = byte-identical legacy context behaviour. */
|
|
11849
|
-
enabled: z.boolean().default(false),
|
|
11850
|
-
/** λ_base — minimum architectural forgetting rate. */
|
|
11851
|
-
lambdaBase: z.number().min(0).default(0.15),
|
|
11852
|
-
/** α — hypofrontality accelerator (weight of Φ on λ_flow). */
|
|
11853
|
-
alpha: z.number().min(0).default(1.5),
|
|
11854
|
-
/** BFS depth used to pull distant pinned invariants back into scope. */
|
|
11855
|
-
maxDepth: z.number().int().min(0).max(6).default(3),
|
|
11856
|
-
/** Peripheral neighbours below this decayed weight are pruned (unless pinned). */
|
|
11857
|
-
weightThreshold: z.number().min(0).max(1).default(0.1),
|
|
11858
|
-
/** EMA gain per consecutive success when computing Φ. */
|
|
11859
|
-
emaGain: z.number().min(0).max(1).default(0.34),
|
|
11860
|
-
/** Multiplier applied to Φ on a failure (0 = hard reset → re-hydrate memory). */
|
|
11861
|
-
resetFactor: z.number().min(0).max(1).default(0),
|
|
11862
|
-
/** Damping fraction of `emaGain` applied on a `partial` outcome. */
|
|
11863
|
-
partialFactor: z.number().min(0).max(1).default(0.5),
|
|
11864
|
-
/** rag budget is never scaled below this fraction of baseline (long-range safety). */
|
|
11865
|
-
budgetFloorRatio: z.number().min(0).max(1).default(0.25),
|
|
11866
|
-
/** How many recent task outcomes feed Φ. */
|
|
11867
|
-
historyWindow: z.number().int().min(1).max(200).default(12),
|
|
11868
|
-
/** Node types that are never diluted. */
|
|
11869
|
-
pinnedTypes: z.array(z.string()).default(["constraint", "risk", "decision", "acceptance_criteria", "constitution", "requirement"]),
|
|
11870
|
-
/** A/B experiment: alternate flow_on/flow_off deterministically per node to measure impact. */
|
|
11871
|
-
experiment: z.object({ abEnabled: z.boolean().default(false) }).default({ abEnabled: false })
|
|
11872
|
-
});
|
|
11873
|
-
var ConfigSchema = z.object({
|
|
11874
|
-
port: z.number().int().min(1).max(65535).default(3e3),
|
|
11875
|
-
dbPath: z.string().default("workflow-graph"),
|
|
11876
|
-
basePath: z.string().optional(),
|
|
11877
|
-
contextMode: ContextModeSchema.default("lean"),
|
|
11878
|
-
profile: ProfileFilterConfigSchema.default("all"),
|
|
11879
|
-
dashboard: z.object({
|
|
11880
|
-
autoOpen: z.boolean().default(true)
|
|
11881
|
-
}).default({ autoOpen: true }),
|
|
11882
|
-
integrations: z.object({
|
|
11883
|
-
codeGraphAutoIndex: z.boolean().default(true),
|
|
11884
|
-
codeGraphReindexIntervalSec: z.number().int().min(0).default(0),
|
|
11885
|
-
lspServers: z.array(LspConfigOverrideSchema).default([]),
|
|
11886
|
-
browserAutomation: BrowserAutomationConfigSchema
|
|
11887
|
-
}).prefault({}),
|
|
11888
|
-
flow: FlowConfigSchema.prefault({})
|
|
11889
|
-
});
|
|
11890
|
-
|
|
11891
|
-
// src/core/config/config-loader.ts
|
|
12854
|
+
init_config_schema();
|
|
11892
12855
|
init_errors();
|
|
11893
12856
|
init_logger();
|
|
11894
|
-
var
|
|
12857
|
+
var log38 = createLogger({ layer: "core", source: "config-loader.ts" });
|
|
11895
12858
|
var CONFIG_FILENAME = "mcp-graph.config.json";
|
|
11896
12859
|
function loadConfig(basePath) {
|
|
11897
12860
|
const resolvedBase = basePath ?? process.cwd();
|
|
@@ -11901,13 +12864,13 @@ function loadConfig(basePath) {
|
|
|
11901
12864
|
try {
|
|
11902
12865
|
const raw = readFileSync(configPath, "utf-8").replace(/^\uFEFF/, "");
|
|
11903
12866
|
fileConfig = JSON.parse(raw);
|
|
11904
|
-
|
|
12867
|
+
log38.info(`Config loaded from ${configPath}`);
|
|
11905
12868
|
} catch (err) {
|
|
11906
12869
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11907
12870
|
throw new McpGraphError(`Invalid config at ${configPath}: ${msg}`);
|
|
11908
12871
|
}
|
|
11909
12872
|
} else {
|
|
11910
|
-
|
|
12873
|
+
log38.info("No config file found, using defaults");
|
|
11911
12874
|
}
|
|
11912
12875
|
if (process.env.MCP_PORT) {
|
|
11913
12876
|
const envPort = parseInt(process.env.MCP_PORT, 10);
|
|
@@ -11927,7 +12890,7 @@ function loadConfig(basePath) {
|
|
|
11927
12890
|
// src/core/config/ignore-templates.ts
|
|
11928
12891
|
init_esm_shims();
|
|
11929
12892
|
init_logger();
|
|
11930
|
-
var
|
|
12893
|
+
var log39 = createLogger({ layer: "core", source: "ignore-templates.ts" });
|
|
11931
12894
|
var IGNORE_TEMPLATE = `# ========================================
|
|
11932
12895
|
# LEAN CONTEXT (mcp-graph)
|
|
11933
12896
|
# Filosofia: zero auto-load, tudo on-demand via MCP
|
|
@@ -12078,21 +13041,21 @@ release-please-config.json
|
|
|
12078
13041
|
function ensureClaudeIgnore(projectDir) {
|
|
12079
13042
|
const filePath = path17__default.join(projectDir, ".claudeignore");
|
|
12080
13043
|
if (existsSync(filePath)) {
|
|
12081
|
-
|
|
13044
|
+
log39.debug(".claudeignore already exists, skipping");
|
|
12082
13045
|
return false;
|
|
12083
13046
|
}
|
|
12084
13047
|
writeFileSync(filePath, IGNORE_TEMPLATE, "utf-8");
|
|
12085
|
-
|
|
13048
|
+
log39.info(".claudeignore created with lean context template");
|
|
12086
13049
|
return true;
|
|
12087
13050
|
}
|
|
12088
13051
|
function ensureCopilotIgnore(projectDir) {
|
|
12089
13052
|
const filePath = path17__default.join(projectDir, ".copilotignore");
|
|
12090
13053
|
if (existsSync(filePath)) {
|
|
12091
|
-
|
|
13054
|
+
log39.debug(".copilotignore already exists, skipping");
|
|
12092
13055
|
return false;
|
|
12093
13056
|
}
|
|
12094
13057
|
writeFileSync(filePath, IGNORE_TEMPLATE, "utf-8");
|
|
12095
|
-
|
|
13058
|
+
log39.info(".copilotignore created with lean context template");
|
|
12096
13059
|
return true;
|
|
12097
13060
|
}
|
|
12098
13061
|
function updateIgnoreFile(filePath, label, dryRun) {
|
|
@@ -12100,7 +13063,7 @@ function updateIgnoreFile(filePath, label, dryRun) {
|
|
|
12100
13063
|
if (!exists) {
|
|
12101
13064
|
if (!dryRun) {
|
|
12102
13065
|
writeFileSync(filePath, IGNORE_TEMPLATE, "utf-8");
|
|
12103
|
-
|
|
13066
|
+
log39.info(`${label} created with lean context template`);
|
|
12104
13067
|
}
|
|
12105
13068
|
return { status: "created", message: `${label} created` };
|
|
12106
13069
|
}
|
|
@@ -12110,7 +13073,7 @@ function updateIgnoreFile(filePath, label, dryRun) {
|
|
|
12110
13073
|
}
|
|
12111
13074
|
if (!dryRun) {
|
|
12112
13075
|
writeFileSync(filePath, IGNORE_TEMPLATE, "utf-8");
|
|
12113
|
-
|
|
13076
|
+
log39.info(`${label} updated to latest template`);
|
|
12114
13077
|
}
|
|
12115
13078
|
return { status: "updated", message: `${label} updated` };
|
|
12116
13079
|
}
|
|
@@ -12787,7 +13750,7 @@ init_registry();
|
|
|
12787
13750
|
// src/core/atomic-files/writer-markdown.ts
|
|
12788
13751
|
init_esm_shims();
|
|
12789
13752
|
init_logger();
|
|
12790
|
-
var
|
|
13753
|
+
var log40 = createLogger({ layer: "core", source: "writer-markdown.ts" });
|
|
12791
13754
|
var markerStart2 = (id) => `<!-- MCP-GRAPH:MANAGED-START:${id} -->`;
|
|
12792
13755
|
var markerEnd2 = (id) => `<!-- MCP-GRAPH:MANAGED-END:${id} -->`;
|
|
12793
13756
|
function extractManagedBlock(content, fileId) {
|
|
@@ -12849,7 +13812,7 @@ async function write(file, mode) {
|
|
|
12849
13812
|
const existingBlock = extractManagedBlock(current, fileId);
|
|
12850
13813
|
const tampered = existingBlock !== null && detectTampering(filePath, fileId, existingBlock);
|
|
12851
13814
|
if (tampered) {
|
|
12852
|
-
|
|
13815
|
+
log40.warn("managed block tampered \u2014 system reconquering", { fileId, filePath });
|
|
12853
13816
|
fs.writeFileSync(filePath + ".user-modified.bak", current, "utf8");
|
|
12854
13817
|
}
|
|
12855
13818
|
if (!tampered && existingBlock === managedContent) {
|
|
@@ -12887,7 +13850,7 @@ async function atomicWrite(filePath, content) {
|
|
|
12887
13850
|
try {
|
|
12888
13851
|
fs.unlinkSync(tmp);
|
|
12889
13852
|
} catch (e) {
|
|
12890
|
-
|
|
13853
|
+
log40.debug("intentional swallow", { error: e, reason: "tmp file already gone, cleanup not needed" });
|
|
12891
13854
|
}
|
|
12892
13855
|
throw err;
|
|
12893
13856
|
}
|
|
@@ -12915,7 +13878,7 @@ async function runAtomicWrites(mode) {
|
|
|
12915
13878
|
}
|
|
12916
13879
|
|
|
12917
13880
|
// src/cli/commands/init-cmd.ts
|
|
12918
|
-
var
|
|
13881
|
+
var log41 = createLogger({ layer: "cli", source: "init.ts" });
|
|
12919
13882
|
var LEVEL_ICON = { ok: "\u2713", warning: "\u26A0", error: "\u2717" };
|
|
12920
13883
|
async function runInitOrchestration(opts, deps) {
|
|
12921
13884
|
const { dir, skipNeural, noServe, port } = opts;
|
|
@@ -13028,7 +13991,7 @@ function initCommand() {
|
|
|
13028
13991
|
const dir = path17__default.resolve(opts.dir);
|
|
13029
13992
|
const port = parseInt(opts.port, 10);
|
|
13030
13993
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
13031
|
-
|
|
13994
|
+
log41.error("Invalid port number", { port: opts.port });
|
|
13032
13995
|
process.exitCode = 1;
|
|
13033
13996
|
return;
|
|
13034
13997
|
}
|
|
@@ -13046,7 +14009,7 @@ function initCommand() {
|
|
|
13046
14009
|
out("\nPronto. Execute `mcp-graph serve` para iniciar o servidor.");
|
|
13047
14010
|
}
|
|
13048
14011
|
} catch (error) {
|
|
13049
|
-
|
|
14012
|
+
log41.error("Init failed", { error: getErrorMessage(error) });
|
|
13050
14013
|
process.exitCode = 1;
|
|
13051
14014
|
}
|
|
13052
14015
|
});
|
|
@@ -13111,7 +14074,7 @@ function readDaemonMeta(stateDir) {
|
|
|
13111
14074
|
|
|
13112
14075
|
// src/core/daemon/daemon-reaper.ts
|
|
13113
14076
|
init_logger();
|
|
13114
|
-
var
|
|
14077
|
+
var log43 = createLogger({ layer: "core", source: "daemon-reaper" });
|
|
13115
14078
|
function defaultDaemonRoot(home = os.homedir()) {
|
|
13116
14079
|
return path17__default.join(home, ".mcp-graph");
|
|
13117
14080
|
}
|
|
@@ -13150,7 +14113,7 @@ function reapDaemons(options = {}) {
|
|
|
13150
14113
|
try {
|
|
13151
14114
|
kill(lock.pid);
|
|
13152
14115
|
} catch (err) {
|
|
13153
|
-
|
|
14116
|
+
log43.debug("intentional-swallow", {
|
|
13154
14117
|
error: String(err),
|
|
13155
14118
|
reason: "process vanished between liveness probe and signal \u2014 treat as already reaped"
|
|
13156
14119
|
});
|
|
@@ -13180,7 +14143,7 @@ function reapDaemons(options = {}) {
|
|
|
13180
14143
|
try {
|
|
13181
14144
|
fs__default.rmSync(stateDir, { recursive: true, force: true });
|
|
13182
14145
|
} catch (err) {
|
|
13183
|
-
|
|
14146
|
+
log43.debug("intentional-swallow", {
|
|
13184
14147
|
error: String(err),
|
|
13185
14148
|
reason: "state dir removal hit a permission error or race \u2014 next reaper run retries"
|
|
13186
14149
|
});
|
|
@@ -13200,14 +14163,14 @@ function reapDaemons(options = {}) {
|
|
|
13200
14163
|
|
|
13201
14164
|
// src/cli/commands/daemon-cmd.ts
|
|
13202
14165
|
init_logger();
|
|
13203
|
-
var
|
|
14166
|
+
var log44 = createLogger({ layer: "cli", source: "daemon.ts" });
|
|
13204
14167
|
function output12(msg) {
|
|
13205
14168
|
process.stdout.write(msg + "\n");
|
|
13206
14169
|
}
|
|
13207
14170
|
function daemonCommand() {
|
|
13208
14171
|
const cmd = new Command("daemon").description("Inspect and clean up mcp-graph daemons");
|
|
13209
14172
|
cmd.command("prune").description("Kill orphaned daemons (workspace gone) and remove stale state dirs").option("--dry-run", "Show what would be reaped without killing or deleting", false).action((opts) => {
|
|
13210
|
-
|
|
14173
|
+
log44.info("cli:daemon:prune", { dryRun: opts.dryRun });
|
|
13211
14174
|
const report = reapDaemons({ dryRun: opts.dryRun });
|
|
13212
14175
|
const prefix = opts.dryRun ? "[dry-run] " : "";
|
|
13213
14176
|
for (const a of report.actions) {
|
|
@@ -13279,7 +14242,7 @@ function formatProviderReport(report) {
|
|
|
13279
14242
|
// src/cli/commands/doctor-cmd.ts
|
|
13280
14243
|
init_errors();
|
|
13281
14244
|
init_logger();
|
|
13282
|
-
var
|
|
14245
|
+
var log45 = createLogger({ layer: "cli", source: "doctor.ts" });
|
|
13283
14246
|
function output13(msg) {
|
|
13284
14247
|
process.stdout.write(msg + "\n");
|
|
13285
14248
|
}
|
|
@@ -13334,7 +14297,7 @@ function doctorCommand() {
|
|
|
13334
14297
|
process.exit(1);
|
|
13335
14298
|
}
|
|
13336
14299
|
} catch (err) {
|
|
13337
|
-
|
|
14300
|
+
log45.error(`Doctor failed: ${getErrorMessage(err)}`);
|
|
13338
14301
|
process.exit(1);
|
|
13339
14302
|
}
|
|
13340
14303
|
});
|
|
@@ -13346,7 +14309,7 @@ init_esm_shims();
|
|
|
13346
14309
|
// src/core/autonomy/shadow-branch.ts
|
|
13347
14310
|
init_esm_shims();
|
|
13348
14311
|
init_logger();
|
|
13349
|
-
var
|
|
14312
|
+
var log46 = createLogger({ layer: "core", source: "shadow-branch.ts" });
|
|
13350
14313
|
function parseShadowTimestamp(branchName) {
|
|
13351
14314
|
const match = /-(\d{10,})$/.exec(branchName);
|
|
13352
14315
|
if (!match) return null;
|
|
@@ -13388,7 +14351,7 @@ function pruneOrphanWorktrees(options) {
|
|
|
13388
14351
|
).toString();
|
|
13389
14352
|
branches = out2.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
13390
14353
|
} catch (err) {
|
|
13391
|
-
|
|
14354
|
+
log46.debug("shadow-branch:prune:list-failed", { error: String(err) });
|
|
13392
14355
|
}
|
|
13393
14356
|
const wtMap = branches.length > 0 ? listShadowWorktrees(execOpts) : /* @__PURE__ */ new Map();
|
|
13394
14357
|
for (const branch of branches) {
|
|
@@ -13400,34 +14363,34 @@ function pruneOrphanWorktrees(options) {
|
|
|
13400
14363
|
execSync(`git worktree remove --force --force ${wtPath}`, execOpts);
|
|
13401
14364
|
reapedWorktrees += 1;
|
|
13402
14365
|
} catch (err) {
|
|
13403
|
-
|
|
14366
|
+
log46.debug("shadow-branch:prune:wt-remove-failed", { branch, wtPath, error: String(err) });
|
|
13404
14367
|
}
|
|
13405
14368
|
}
|
|
13406
14369
|
try {
|
|
13407
14370
|
execSync(`git branch -D ${branch}`, execOpts);
|
|
13408
14371
|
reapedBranches += 1;
|
|
13409
14372
|
} catch (err) {
|
|
13410
|
-
|
|
14373
|
+
log46.debug("shadow-branch:prune:branch-delete-failed", { branch, error: String(err) });
|
|
13411
14374
|
}
|
|
13412
14375
|
}
|
|
13413
14376
|
try {
|
|
13414
|
-
const
|
|
14377
|
+
const output16 = execSync("git worktree prune --verbose", execOpts).toString();
|
|
13415
14378
|
if (reapedBranches > 0 || reapedWorktrees > 0) {
|
|
13416
|
-
|
|
14379
|
+
log46.info("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, ttlMs });
|
|
13417
14380
|
} else {
|
|
13418
|
-
|
|
14381
|
+
log46.debug("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, output: output16 });
|
|
13419
14382
|
}
|
|
13420
|
-
return { pruned: true, reapedBranches, reapedWorktrees, output:
|
|
14383
|
+
return { pruned: true, reapedBranches, reapedWorktrees, output: output16 };
|
|
13421
14384
|
} catch (err) {
|
|
13422
14385
|
const error = String(err);
|
|
13423
|
-
|
|
14386
|
+
log46.debug("shadow-branch:prune-failed", { error });
|
|
13424
14387
|
return { pruned: false, reapedBranches, reapedWorktrees, error };
|
|
13425
14388
|
}
|
|
13426
14389
|
}
|
|
13427
14390
|
|
|
13428
14391
|
// src/cli/commands/gc-cmd.ts
|
|
13429
14392
|
init_logger();
|
|
13430
|
-
var
|
|
14393
|
+
var log47 = createLogger({ layer: "cli", source: "gc.ts" });
|
|
13431
14394
|
function output14(msg) {
|
|
13432
14395
|
process.stdout.write(msg + "\n");
|
|
13433
14396
|
}
|
|
@@ -13435,7 +14398,7 @@ function gcCommand() {
|
|
|
13435
14398
|
return new Command("gc").description("Garbage-collect orphan ai-shadow/* worktrees and branches").option("-d, --dir <dir>", "Project directory (git root)", process.cwd()).option("--ttl <minutes>", "Only reap branches older than N minutes (0 = all)", "0").action((opts) => {
|
|
13436
14399
|
const ttlMinutes = parseInt(opts.ttl, 10);
|
|
13437
14400
|
const ttlMs = Number.isFinite(ttlMinutes) && ttlMinutes > 0 ? ttlMinutes * 60 * 1e3 : 0;
|
|
13438
|
-
|
|
14401
|
+
log47.info("cli:gc:start", { dir: opts.dir, ttlMs });
|
|
13439
14402
|
const result = pruneOrphanWorktrees({ cwd: opts.dir, ttlMs });
|
|
13440
14403
|
if (result.pruned) {
|
|
13441
14404
|
output14(`gc: reaped ${result.reapedBranches} branches, ${result.reapedWorktrees} worktrees`);
|
|
@@ -13446,6 +14409,48 @@ function gcCommand() {
|
|
|
13446
14409
|
});
|
|
13447
14410
|
}
|
|
13448
14411
|
|
|
14412
|
+
// src/cli/commands/skill-cmd.ts
|
|
14413
|
+
init_esm_shims();
|
|
14414
|
+
init_skill_registry();
|
|
14415
|
+
function output15(msg) {
|
|
14416
|
+
process.stdout.write(msg + "\n");
|
|
14417
|
+
}
|
|
14418
|
+
function skillCommand() {
|
|
14419
|
+
const cmd = new Command("skill").description("Lista e exibe skills (instru\xE7\xF5es para agentes)");
|
|
14420
|
+
cmd.command("list").description("Lista as skills dispon\xEDveis (src/skills, .agents/skills, .claude/skills)").option("-p, --phase <fase>", "Ordena/filtra pela fase do ciclo (ANALYZE, IMPLEMENT, \u2026)").option("-d, --dir <dir>", "Raiz do projeto", process.cwd()).action((opts) => {
|
|
14421
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14422
|
+
let count = 0;
|
|
14423
|
+
for (const root of defaultSkillRoots(opts.dir)) {
|
|
14424
|
+
const { skills } = listSkills(root, opts.phase);
|
|
14425
|
+
for (const s of skills) {
|
|
14426
|
+
if (seen.has(s.name)) continue;
|
|
14427
|
+
seen.add(s.name);
|
|
14428
|
+
count += 1;
|
|
14429
|
+
output15(`${s.name.padEnd(28)} [${s.category}] ${s.description}`);
|
|
14430
|
+
}
|
|
14431
|
+
}
|
|
14432
|
+
if (count === 0) output15("Nenhuma skill encontrada.");
|
|
14433
|
+
else output15(`
|
|
14434
|
+
${count} skill(s).`);
|
|
14435
|
+
});
|
|
14436
|
+
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
|
+
for (const root of defaultSkillRoots(opts.dir)) {
|
|
14438
|
+
const found = invokeSkill(root, nome);
|
|
14439
|
+
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);
|
|
14445
|
+
return;
|
|
14446
|
+
}
|
|
14447
|
+
}
|
|
14448
|
+
output15(`Skill n\xE3o encontrada: ${nome}. Tente 'skill list'.`);
|
|
14449
|
+
process.exitCode = 1;
|
|
14450
|
+
});
|
|
14451
|
+
return cmd;
|
|
14452
|
+
}
|
|
14453
|
+
|
|
13449
14454
|
// src/cli/index.ts
|
|
13450
14455
|
var program = new Command();
|
|
13451
14456
|
program.name("agent-graph-flow").description(PROMISE).version(VERSION, "-v, --version");
|
|
@@ -13466,6 +14471,7 @@ program.addCommand(initCommand());
|
|
|
13466
14471
|
program.addCommand(daemonCommand());
|
|
13467
14472
|
program.addCommand(doctorCommand());
|
|
13468
14473
|
program.addCommand(gcCommand());
|
|
14474
|
+
program.addCommand(skillCommand());
|
|
13469
14475
|
function shouldLaunchTui() {
|
|
13470
14476
|
const noArgs = process.argv.length <= 2;
|
|
13471
14477
|
const isTty = Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
|