@mcp-graph-workflow/agent-graph-flow 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli/index.js +1069 -259
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -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
  }
@@ -7044,8 +7078,8 @@ var init_implementation_executor = __esm({
7044
7078
  };
7045
7079
  defaultRunner = (command, cwd) => {
7046
7080
  try {
7047
- const output15 = execSync(command, { cwd, encoding: "utf8", stdio: "pipe" });
7048
- return { exitCode: 0, output: output15 };
7081
+ const output16 = execSync(command, { cwd, encoding: "utf8", stdio: "pipe" });
7082
+ return { exitCode: 0, output: output16 };
7049
7083
  } catch (err) {
7050
7084
  const e = err;
7051
7085
  return {
@@ -7128,8 +7162,10 @@ var init_plan_parser = __esm({
7128
7162
  // src/core/autonomy/implement-attempt.ts
7129
7163
  function buildInitialPrompt(node, opts = {}) {
7130
7164
  const repoMapBlock = opts.repoMap && opts.repoMap.length > 0 ? [`Contexto do reposit\xF3rio (refer\xEAncia, n\xE3o reescreva o que j\xE1 existe):`, opts.repoMap, ""] : [];
7165
+ const flowBlock = opts.flowContext && opts.flowContext.length > 0 ? [opts.flowContext, ""] : [];
7131
7166
  return [
7132
7167
  ...repoMapBlock,
7168
+ ...flowBlock,
7133
7169
  `Implemente a task "${node.title}" (id: ${node.id}) seguindo TDD.`,
7134
7170
  "Responda APENAS com um bloco ```json. H\xE1 DOIS mecanismos:",
7135
7171
  '- "edits" (PREFIRA \u2014 economia de token): [{ "path", "oldString", "newString", "replaceAll"? }].',
@@ -7158,7 +7194,7 @@ async function attemptImplementation(deps, options) {
7158
7194
  let lastResult;
7159
7195
  let lastError;
7160
7196
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
7161
- const prompt = attempt === 1 || !lastResult ? buildInitialPrompt(options.node, { repoMap: options.repoMap }) : buildRetryPrompt(options.node, lastResult, maxFeedbackChars);
7197
+ const prompt = attempt === 1 || !lastResult ? buildInitialPrompt(options.node, { repoMap: options.repoMap, flowContext: options.flowContext }) : buildRetryPrompt(options.node, lastResult, maxFeedbackChars);
7162
7198
  let plan;
7163
7199
  try {
7164
7200
  const text = await deps.generate(prompt);
@@ -7573,6 +7609,854 @@ var init_repo_map = __esm({
7573
7609
  FOCUS_BOOST = 3;
7574
7610
  }
7575
7611
  });
7612
+ var LspConfigOverrideSchema, LspDiagnosticSchema, LspDocumentSymbolSchema, LspTextEditSchema, LspWorkspaceEditSchema;
7613
+ var init_lsp_types = __esm({
7614
+ "src/core/lsp/lsp-types.ts"() {
7615
+ init_esm_shims();
7616
+ z.object({
7617
+ languageId: z.string(),
7618
+ extensions: z.array(z.string()),
7619
+ command: z.string(),
7620
+ args: z.array(z.string()),
7621
+ configFiles: z.array(z.string()),
7622
+ probeCommand: z.string().optional(),
7623
+ initializationOptions: z.record(z.string(), z.unknown()).optional(),
7624
+ settings: z.record(z.string(), z.unknown()).optional()
7625
+ });
7626
+ LspConfigOverrideSchema = z.object({
7627
+ languageId: z.string(),
7628
+ command: z.string(),
7629
+ args: z.array(z.string()).default([]),
7630
+ extensions: z.array(z.string()).optional(),
7631
+ initializationOptions: z.record(z.string(), z.unknown()).optional(),
7632
+ settings: z.record(z.string(), z.unknown()).optional()
7633
+ });
7634
+ z.object({
7635
+ file: z.string(),
7636
+ startLine: z.int().min(0),
7637
+ startCharacter: z.int().min(0),
7638
+ endLine: z.int().min(0),
7639
+ endCharacter: z.int().min(0)
7640
+ });
7641
+ z.object({
7642
+ signature: z.string(),
7643
+ documentation: z.string().optional(),
7644
+ language: z.string().optional()
7645
+ });
7646
+ LspDiagnosticSchema = z.object({
7647
+ file: z.string(),
7648
+ startLine: z.int().min(0),
7649
+ startCharacter: z.int().min(0),
7650
+ endLine: z.int().min(0),
7651
+ endCharacter: z.int().min(0),
7652
+ severity: z.number().int().min(1).max(4),
7653
+ message: z.string(),
7654
+ code: z.string().optional(),
7655
+ source: z.string().optional()
7656
+ });
7657
+ z.object({
7658
+ name: z.string(),
7659
+ kind: z.string(),
7660
+ file: z.string(),
7661
+ startLine: z.int().min(0),
7662
+ endLine: z.int().min(0)
7663
+ });
7664
+ LspDocumentSymbolSchema = z.object({
7665
+ name: z.string(),
7666
+ kind: z.string(),
7667
+ file: z.string(),
7668
+ startLine: z.int().min(0),
7669
+ endLine: z.int().min(0),
7670
+ children: z.lazy(() => z.array(LspDocumentSymbolSchema)).optional()
7671
+ });
7672
+ LspTextEditSchema = z.object({
7673
+ file: z.string(),
7674
+ startLine: z.int().min(0),
7675
+ startCharacter: z.int().min(0),
7676
+ endLine: z.int().min(0),
7677
+ endCharacter: z.int().min(0),
7678
+ newText: z.string()
7679
+ });
7680
+ LspWorkspaceEditSchema = z.object({
7681
+ changes: z.array(LspTextEditSchema)
7682
+ });
7683
+ z.object({
7684
+ languageId: z.string(),
7685
+ status: z.enum(["stopped", "starting", "ready", "error"]),
7686
+ pid: z.number().int().optional(),
7687
+ error: z.string().optional()
7688
+ });
7689
+ z.object({
7690
+ languageId: z.string(),
7691
+ confidence: z.number().min(0).max(1),
7692
+ detectedVia: z.enum(["file_extension", "config_file", "shebang"]),
7693
+ fileCount: z.int().min(0),
7694
+ configFile: z.string().optional()
7695
+ });
7696
+ z.object({
7697
+ title: z.string(),
7698
+ kind: z.string().optional(),
7699
+ isPreferred: z.boolean().optional(),
7700
+ edit: LspWorkspaceEditSchema.optional(),
7701
+ diagnostics: z.array(LspDiagnosticSchema).optional()
7702
+ });
7703
+ z.object({
7704
+ applied: z.boolean(),
7705
+ filesModified: z.array(z.string()),
7706
+ totalEdits: z.number().int(),
7707
+ errors: z.array(z.string()),
7708
+ backups: z.map(z.string(), z.string()).optional()
7709
+ });
7710
+ }
7711
+ });
7712
+ var BROWSER_PILOT_MODELS, ContextModeSchema, ProfileFilterConfigSchema, BrowserAutomationConfigSchema, FlowConfigSchema, ConfigSchema;
7713
+ var init_config_schema = __esm({
7714
+ "src/core/config/config-schema.ts"() {
7715
+ init_esm_shims();
7716
+ init_lsp_types();
7717
+ BROWSER_PILOT_MODELS = ["claude-3.5-sonnet", "gpt-4o", "gpt-4o-mini", "o1", "o1-mini"];
7718
+ ContextModeSchema = z.enum(["ultra-lean", "lean", "full"]);
7719
+ ProfileFilterConfigSchema = z.enum(["core", "pro", "expert", "all"]);
7720
+ BrowserAutomationConfigSchema = z.object({
7721
+ enabled: z.boolean().default(false),
7722
+ bridgeUrl: z.string().regex(/^https?:\/\//, "bridgeUrl must start with http:// or https://").default("http://127.0.0.1:9876/v1"),
7723
+ defaultModel: z.enum(BROWSER_PILOT_MODELS).default("claude-3.5-sonnet"),
7724
+ defaultCdpUrl: z.string().min(1).optional(),
7725
+ allowedDomains: z.array(z.string().min(1)).default([]),
7726
+ forbiddenCdpMethods: z.array(z.string().min(1)).default(["Browser.close"]),
7727
+ maxStepsDefault: z.number().int().min(1).max(100).default(25),
7728
+ tokenBudgetPerDay: z.number().int().nonnegative().optional()
7729
+ }).default({
7730
+ enabled: false,
7731
+ bridgeUrl: "http://127.0.0.1:9876/v1",
7732
+ defaultModel: "claude-3.5-sonnet",
7733
+ allowedDomains: [],
7734
+ forbiddenCdpMethods: ["Browser.close"],
7735
+ maxStepsDefault: 25
7736
+ });
7737
+ FlowConfigSchema = z.object({
7738
+ /** Master switch. OFF = byte-identical legacy context behaviour. */
7739
+ enabled: z.boolean().default(false),
7740
+ /** λ_base — minimum architectural forgetting rate. */
7741
+ lambdaBase: z.number().min(0).default(0.15),
7742
+ /** α — hypofrontality accelerator (weight of Φ on λ_flow). */
7743
+ alpha: z.number().min(0).default(1.5),
7744
+ /** BFS depth used to pull distant pinned invariants back into scope. */
7745
+ maxDepth: z.number().int().min(0).max(6).default(3),
7746
+ /** Peripheral neighbours below this decayed weight are pruned (unless pinned). */
7747
+ weightThreshold: z.number().min(0).max(1).default(0.1),
7748
+ /** EMA gain per consecutive success when computing Φ. */
7749
+ emaGain: z.number().min(0).max(1).default(0.34),
7750
+ /** Multiplier applied to Φ on a failure (0 = hard reset → re-hydrate memory). */
7751
+ resetFactor: z.number().min(0).max(1).default(0),
7752
+ /** Damping fraction of `emaGain` applied on a `partial` outcome. */
7753
+ partialFactor: z.number().min(0).max(1).default(0.5),
7754
+ /** rag budget is never scaled below this fraction of baseline (long-range safety). */
7755
+ budgetFloorRatio: z.number().min(0).max(1).default(0.25),
7756
+ /** How many recent task outcomes feed Φ. */
7757
+ historyWindow: z.number().int().min(1).max(200).default(12),
7758
+ /** Node types that are never diluted. */
7759
+ pinnedTypes: z.array(z.string()).default(["constraint", "risk", "decision", "acceptance_criteria", "constitution", "requirement"]),
7760
+ /** A/B experiment: alternate flow_on/flow_off deterministically per node to measure impact. */
7761
+ experiment: z.object({ abEnabled: z.boolean().default(false) }).default({ abEnabled: false })
7762
+ });
7763
+ ConfigSchema = z.object({
7764
+ port: z.number().int().min(1).max(65535).default(3e3),
7765
+ dbPath: z.string().default("workflow-graph"),
7766
+ basePath: z.string().optional(),
7767
+ contextMode: ContextModeSchema.default("lean"),
7768
+ profile: ProfileFilterConfigSchema.default("all"),
7769
+ dashboard: z.object({
7770
+ autoOpen: z.boolean().default(true)
7771
+ }).default({ autoOpen: true }),
7772
+ integrations: z.object({
7773
+ codeGraphAutoIndex: z.boolean().default(true),
7774
+ codeGraphReindexIntervalSec: z.number().int().min(0).default(0),
7775
+ lspServers: z.array(LspConfigOverrideSchema).default([]),
7776
+ browserAutomation: BrowserAutomationConfigSchema
7777
+ }).prefault({}),
7778
+ flow: FlowConfigSchema.prefault({})
7779
+ });
7780
+ }
7781
+ });
7782
+
7783
+ // src/core/context/flow-config.ts
7784
+ function resolveFlowConfig(source) {
7785
+ const raw = source.getProjectSetting(FLOW_CONFIG_SETTING_KEY);
7786
+ if (!raw) return FlowConfigSchema.parse({});
7787
+ try {
7788
+ return FlowConfigSchema.parse(JSON.parse(raw));
7789
+ } catch {
7790
+ return FlowConfigSchema.parse({});
7791
+ }
7792
+ }
7793
+ function flowAbArm(nodeId) {
7794
+ let sum = 0;
7795
+ for (let i = 0; i < nodeId.length; i += 1) sum += nodeId.charCodeAt(i);
7796
+ return sum % 2 === 0 ? "flow_on" : "flow_off";
7797
+ }
7798
+ var FLOW_CONFIG_SETTING_KEY;
7799
+ var init_flow_config = __esm({
7800
+ "src/core/context/flow-config.ts"() {
7801
+ init_esm_shims();
7802
+ init_config_schema();
7803
+ FLOW_CONFIG_SETTING_KEY = "flow_config";
7804
+ }
7805
+ });
7806
+
7807
+ // src/core/context/flow-index.ts
7808
+ function computeFlowIndex(outcomesNewestFirst, tuning = {}) {
7809
+ const { emaGain, resetFactor, partialFactor } = { ...DEFAULT_FLOW_TUNING, ...tuning };
7810
+ let streak = 0;
7811
+ for (const outcome of outcomesNewestFirst) {
7812
+ if (outcome === "success") streak += 1;
7813
+ else break;
7814
+ }
7815
+ let phi = 0;
7816
+ for (let i = outcomesNewestFirst.length - 1; i >= 0; i -= 1) {
7817
+ const outcome = outcomesNewestFirst[i];
7818
+ if (outcome === "success") {
7819
+ phi += emaGain * (1 - phi);
7820
+ } else if (outcome === "failure") {
7821
+ phi *= resetFactor;
7822
+ } else {
7823
+ phi *= 1 - emaGain * partialFactor;
7824
+ }
7825
+ }
7826
+ phi = Math.min(1, Math.max(0, phi));
7827
+ return { phi, streak, sampleCount: outcomesNewestFirst.length };
7828
+ }
7829
+ function computeLambdaFlow(phi, lambdaBase, alpha) {
7830
+ return lambdaBase + alpha * phi;
7831
+ }
7832
+ function decayWeight(lambda, distance) {
7833
+ return Math.exp(-lambda * distance);
7834
+ }
7835
+ var DEFAULT_FLOW_TUNING;
7836
+ var init_flow_index = __esm({
7837
+ "src/core/context/flow-index.ts"() {
7838
+ init_esm_shims();
7839
+ DEFAULT_FLOW_TUNING = {
7840
+ emaGain: 0.34,
7841
+ resetFactor: 0,
7842
+ partialFactor: 0.5
7843
+ };
7844
+ }
7845
+ });
7846
+
7847
+ // src/core/context/token-estimator.ts
7848
+ function isAsciiLetter(code) {
7849
+ return code >= 65 && code <= 90 || code >= 97 && code <= 122;
7850
+ }
7851
+ function isAsciiDigit(code) {
7852
+ return code >= 48 && code <= 57;
7853
+ }
7854
+ function isWhitespace(code) {
7855
+ return code === 32 || code === 9 || code === 10 || code === 13 || code === 12 || code === 11;
7856
+ }
7857
+ function estimateTokens2(text) {
7858
+ if (!text) return 0;
7859
+ let tokens = 0;
7860
+ const len = text.length;
7861
+ let i = 0;
7862
+ while (i < len) {
7863
+ const code = text.charCodeAt(i);
7864
+ if (isWhitespace(code)) {
7865
+ i++;
7866
+ continue;
7867
+ }
7868
+ if (isAsciiLetter(code)) {
7869
+ const start = i;
7870
+ i++;
7871
+ let subWords = 1;
7872
+ while (i < len && isAsciiLetter(text.charCodeAt(i))) {
7873
+ if (i > start && text.charCodeAt(i) >= 65 && text.charCodeAt(i) <= 90 && text.charCodeAt(i - 1) >= 97 && text.charCodeAt(i - 1) <= 122) {
7874
+ subWords++;
7875
+ }
7876
+ i++;
7877
+ }
7878
+ const wordLen = i - start;
7879
+ if (subWords > 1) {
7880
+ tokens += subWords;
7881
+ } else {
7882
+ tokens += wordLen <= 6 ? 1 : wordLen > 20 ? Math.ceil(wordLen / 4) : Math.ceil(wordLen / 5);
7883
+ }
7884
+ continue;
7885
+ }
7886
+ if (isAsciiDigit(code)) {
7887
+ const start = i;
7888
+ i++;
7889
+ while (i < len && isAsciiDigit(text.charCodeAt(i))) i++;
7890
+ const digitsLen = i - start;
7891
+ tokens += Math.ceil(digitsLen / 3);
7892
+ continue;
7893
+ }
7894
+ tokens += 1;
7895
+ i++;
7896
+ }
7897
+ return tokens;
7898
+ }
7899
+ var init_token_estimator = __esm({
7900
+ "src/core/context/token-estimator.ts"() {
7901
+ init_esm_shims();
7902
+ }
7903
+ });
7904
+
7905
+ // src/core/context/compact-context.ts
7906
+ function toTaskSummary(node) {
7907
+ const summary = {
7908
+ id: node.id,
7909
+ type: node.type,
7910
+ title: node.title,
7911
+ status: node.status,
7912
+ priority: node.priority
7913
+ };
7914
+ if (node.description) summary.description = node.description;
7915
+ if (node.sprint) summary.sprint = node.sprint;
7916
+ if (node.xpSize) summary.xpSize = node.xpSize;
7917
+ if (node.tags?.length) summary.tags = node.tags;
7918
+ return summary;
7919
+ }
7920
+ function isInferred(edge) {
7921
+ return edge.metadata?.inferred === true;
7922
+ }
7923
+ function buildTaskContext(store2, nodeId, snapshot) {
7924
+ const resolveNode = (id) => {
7925
+ return store2.getNodeById(id);
7926
+ };
7927
+ const node = resolveNode(nodeId);
7928
+ if (!node) {
7929
+ log26.warn(`buildTaskContext: node ${nodeId} not found`);
7930
+ return null;
7931
+ }
7932
+ let parent = null;
7933
+ if (node.parentId) {
7934
+ const parentNode = resolveNode(node.parentId);
7935
+ if (parentNode) parent = toTaskSummary(parentNode);
7936
+ }
7937
+ let childNodes;
7938
+ {
7939
+ childNodes = store2.getChildNodes(nodeId);
7940
+ }
7941
+ const children = childNodes.map(toTaskSummary);
7942
+ let incomingEdges;
7943
+ let outgoingEdges;
7944
+ {
7945
+ incomingEdges = store2.getEdgesTo(nodeId);
7946
+ outgoingEdges = store2.getEdgesFrom(nodeId);
7947
+ }
7948
+ const blockers = [];
7949
+ const dependsOn = [];
7950
+ const relatedIds = /* @__PURE__ */ new Set();
7951
+ const relatedNodes = [];
7952
+ const implementsNodes = [];
7953
+ const derivedFromNodes = [];
7954
+ let edgeParent = null;
7955
+ const edgeChildren = [];
7956
+ const edgeChildrenIds = /* @__PURE__ */ new Set();
7957
+ for (const edge of incomingEdges) {
7958
+ if (edge.relationType === "blocks") {
7959
+ const blockerNode = resolveNode(edge.from);
7960
+ if (blockerNode) {
7961
+ blockers.push({
7962
+ id: blockerNode.id,
7963
+ title: blockerNode.title,
7964
+ status: blockerNode.status,
7965
+ relationType: edge.relationType,
7966
+ inferred: isInferred(edge)
7967
+ });
7968
+ }
7969
+ } else if (edge.relationType === "related_to") {
7970
+ const relNode = resolveNode(edge.from);
7971
+ if (relNode && !relatedIds.has(relNode.id)) {
7972
+ relatedIds.add(relNode.id);
7973
+ relatedNodes.push(toTaskSummary(relNode));
7974
+ }
7975
+ } else if (edge.relationType === "parent_of" && !edgeParent) {
7976
+ const parentNode = resolveNode(edge.from);
7977
+ if (parentNode) edgeParent = toTaskSummary(parentNode);
7978
+ }
7979
+ }
7980
+ for (const edge of outgoingEdges) {
7981
+ if (edge.relationType === "depends_on") {
7982
+ const depNode = resolveNode(edge.to);
7983
+ if (depNode) {
7984
+ dependsOn.push({
7985
+ id: depNode.id,
7986
+ title: depNode.title,
7987
+ status: depNode.status,
7988
+ resolved: depNode.status === "done",
7989
+ inferred: isInferred(edge)
7990
+ });
7991
+ }
7992
+ } else if (edge.relationType === "related_to") {
7993
+ const relNode = resolveNode(edge.to);
7994
+ if (relNode && !relatedIds.has(relNode.id)) {
7995
+ relatedIds.add(relNode.id);
7996
+ relatedNodes.push(toTaskSummary(relNode));
7997
+ }
7998
+ } else if (edge.relationType === "implements") {
7999
+ const implNode = resolveNode(edge.to);
8000
+ if (implNode) implementsNodes.push(toTaskSummary(implNode));
8001
+ } else if (edge.relationType === "derived_from") {
8002
+ const derivedNode = resolveNode(edge.to);
8003
+ if (derivedNode) derivedFromNodes.push(toTaskSummary(derivedNode));
8004
+ } else if (edge.relationType === "parent_of") {
8005
+ const childNode = resolveNode(edge.to);
8006
+ if (childNode && !edgeChildrenIds.has(childNode.id)) {
8007
+ edgeChildrenIds.add(childNode.id);
8008
+ edgeChildren.push(toTaskSummary(childNode));
8009
+ }
8010
+ }
8011
+ }
8012
+ const acceptanceCriteria = getNodeAcFromStore(store2, node.id);
8013
+ const sourceRef = node.sourceRef ? { ...node.sourceRef } : null;
8014
+ const localNodes = [node, ...childNodes];
8015
+ const originalChars = localNodes.reduce(
8016
+ (sum, n) => sum + n.title.length + (n.description?.length ?? 0) + (n.acceptanceCriteria?.join("").length ?? 0),
8017
+ 0
8018
+ ) + [...incomingEdges, ...outgoingEdges].reduce((sum, e) => sum + (e.reason?.length ?? 0), 0);
8019
+ const summary = toTaskSummary(node);
8020
+ const corePayload = {
8021
+ task: summary,
8022
+ parent,
8023
+ children,
8024
+ blockers,
8025
+ dependsOn,
8026
+ relatedNodes: relatedNodes.length > 0 ? relatedNodes : void 0,
8027
+ implementsNodes: implementsNodes.length > 0 ? implementsNodes : void 0,
8028
+ derivedFromNodes: derivedFromNodes.length > 0 ? derivedFromNodes : void 0,
8029
+ edgeParent: edgeParent ?? void 0,
8030
+ edgeChildren: edgeChildren.length > 0 ? edgeChildren : void 0,
8031
+ acceptanceCriteria,
8032
+ sourceRef,
8033
+ metrics: { originalChars: 0, compactChars: 0, reductionPercent: 0, estimatedTokens: 0 }
8034
+ };
8035
+ const compactJson = JSON.stringify(corePayload);
8036
+ const compactChars = compactJson.length;
8037
+ const reductionPercent = originalChars > 0 ? Math.round((originalChars - compactChars) / originalChars * 100) : 0;
8038
+ const metrics = {
8039
+ originalChars,
8040
+ compactChars,
8041
+ reductionPercent,
8042
+ estimatedTokens: estimateTokens2(compactJson)
8043
+ };
8044
+ const contextPayload = {
8045
+ ...corePayload,
8046
+ node: summary,
8047
+ metrics
8048
+ };
8049
+ log26.info(`Context for ${nodeId}: ${metrics.estimatedTokens} tokens, ${metrics.reductionPercent}% reduction`);
8050
+ return contextPayload;
8051
+ }
8052
+ var log26, KEY_MAP, KEY_LEGEND;
8053
+ var init_compact_context = __esm({
8054
+ "src/core/context/compact-context.ts"() {
8055
+ init_esm_shims();
8056
+ init_ac_helpers();
8057
+ init_token_estimator();
8058
+ init_logger();
8059
+ log26 = createLogger({ layer: "core", source: "compact-context.ts" });
8060
+ KEY_MAP = {
8061
+ // TaskContext top-level
8062
+ task: "tk",
8063
+ node: "n",
8064
+ parent: "par",
8065
+ children: "ch",
8066
+ blockers: "bl",
8067
+ dependsOn: "dep",
8068
+ acceptanceCriteria: "ac",
8069
+ sourceRef: "sr",
8070
+ relatedNodes: "rel",
8071
+ implementsNodes: "impl",
8072
+ derivedFromNodes: "drv",
8073
+ edgeParent: "ep",
8074
+ edgeChildren: "ech",
8075
+ metrics: "m",
8076
+ // TaskSummary / shared fields
8077
+ id: "i",
8078
+ type: "t",
8079
+ title: "n",
8080
+ status: "s",
8081
+ priority: "p",
8082
+ description: "d",
8083
+ sprint: "sp",
8084
+ xpSize: "xs",
8085
+ tags: "tg",
8086
+ // BlockerInfo / DependencyInfo
8087
+ relationType: "rt",
8088
+ inferred: "inf",
8089
+ resolved: "res",
8090
+ // SourceRefInfo
8091
+ file: "f",
8092
+ startLine: "sl",
8093
+ endLine: "el",
8094
+ confidence: "cf",
8095
+ // ContextMetrics
8096
+ originalChars: "oc",
8097
+ compactChars: "cc",
8098
+ reductionPercent: "rp",
8099
+ estimatedTokens: "et"
8100
+ };
8101
+ KEY_LEGEND = {};
8102
+ for (const [full, short] of Object.entries(KEY_MAP)) {
8103
+ KEY_LEGEND[short] = full;
8104
+ }
8105
+ }
8106
+ });
8107
+
8108
+ // src/core/context/topological-decay.ts
8109
+ function corePayloadTokens(ctx, pinned) {
8110
+ const { metrics: _m, node: _n, ...core } = ctx;
8111
+ return estimateTokens2(JSON.stringify(pinned.length > 0 ? { ...core, pinnedInvariants: pinned } : core));
8112
+ }
8113
+ function isPinnedType(type, pinnedTypes) {
8114
+ return pinnedTypes.has(type);
8115
+ }
8116
+ function collectDistantInvariants(store2, rootId, alreadyPresent, maxDepth, pinnedTypes) {
8117
+ if (maxDepth <= 0) return [];
8118
+ const visited = /* @__PURE__ */ new Set([rootId]);
8119
+ const found = /* @__PURE__ */ new Map();
8120
+ let frontier = [rootId];
8121
+ for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth += 1) {
8122
+ const next = [];
8123
+ for (const id of frontier) {
8124
+ const edges = [...store2.getEdgesFrom(id), ...store2.getEdgesTo(id)];
8125
+ for (const edge of edges) {
8126
+ const neighborId = edge.from === id ? edge.to : edge.from;
8127
+ if (visited.has(neighborId)) continue;
8128
+ visited.add(neighborId);
8129
+ next.push(neighborId);
8130
+ if (alreadyPresent.has(neighborId) || found.has(neighborId)) continue;
8131
+ const neighbor = store2.getNodeById(neighborId);
8132
+ if (neighbor && isPinnedType(neighbor.type, pinnedTypes)) {
8133
+ found.set(neighborId, {
8134
+ id: neighbor.id,
8135
+ type: neighbor.type,
8136
+ title: neighbor.title,
8137
+ status: neighbor.status,
8138
+ distance: depth
8139
+ });
8140
+ }
8141
+ }
8142
+ }
8143
+ frontier = next;
8144
+ }
8145
+ return [...found.values()];
8146
+ }
8147
+ function buildDecayedTaskContext(store2, nodeId, opts) {
8148
+ const base = buildTaskContext(store2, nodeId);
8149
+ if (!base) return null;
8150
+ const pinnedTypes = opts.pinnedTypes ?? new Set(DEFAULT_PINNED_TYPES);
8151
+ const tokensBaseline = corePayloadTokens(base, []);
8152
+ const peripheralWeight = decayWeight(opts.lambda, PERIPHERAL_DISTANCE);
8153
+ const peripheralSurvives = peripheralWeight >= opts.weightThreshold;
8154
+ const presentIds = /* @__PURE__ */ new Set([base.task.id]);
8155
+ if (base.parent) presentIds.add(base.parent.id);
8156
+ for (const c of base.children) presentIds.add(c.id);
8157
+ for (const b of base.blockers) presentIds.add(b.id);
8158
+ for (const d of base.dependsOn) presentIds.add(d.id);
8159
+ const ctx = structuredClone(base);
8160
+ let prunedCount = 0;
8161
+ const prunePeripheral = (list) => {
8162
+ if (!list) return list;
8163
+ const kept = list.filter((item) => {
8164
+ presentIds.add(item.id);
8165
+ if (isPinnedType(item.type, pinnedTypes)) return true;
8166
+ if (peripheralSurvives) return true;
8167
+ prunedCount += 1;
8168
+ return false;
8169
+ });
8170
+ return kept.length > 0 ? kept : void 0;
8171
+ };
8172
+ ctx.relatedNodes = prunePeripheral(ctx.relatedNodes);
8173
+ ctx.implementsNodes = prunePeripheral(ctx.implementsNodes);
8174
+ ctx.derivedFromNodes = prunePeripheral(ctx.derivedFromNodes);
8175
+ ctx.edgeChildren = prunePeripheral(ctx.edgeChildren);
8176
+ if (ctx.edgeParent) {
8177
+ presentIds.add(ctx.edgeParent.id);
8178
+ if (!isPinnedType(ctx.edgeParent.type, pinnedTypes) && !peripheralSurvives) {
8179
+ ctx.edgeParent = null;
8180
+ prunedCount += 1;
8181
+ }
8182
+ }
8183
+ const pinnedInvariants = collectDistantInvariants(
8184
+ store2,
8185
+ nodeId,
8186
+ presentIds,
8187
+ opts.maxDepth,
8188
+ pinnedTypes
8189
+ );
8190
+ const tokensActual = corePayloadTokens(ctx, pinnedInvariants);
8191
+ ctx.metrics = {
8192
+ ...ctx.metrics,
8193
+ estimatedTokens: tokensActual
8194
+ };
8195
+ ctx.node = ctx.task;
8196
+ 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);
8197
+ log27.debug("flow:decay", {
8198
+ nodeId,
8199
+ lambda: opts.lambda,
8200
+ prunedCount,
8201
+ pinnedCount: pinnedInvariants.length,
8202
+ tokensBaseline,
8203
+ tokensActual
8204
+ });
8205
+ return {
8206
+ context: ctx,
8207
+ meta: {
8208
+ lambda: opts.lambda,
8209
+ prunedCount,
8210
+ retainedCount,
8211
+ pinnedCount: pinnedInvariants.length,
8212
+ tokensBaseline,
8213
+ tokensActual,
8214
+ tokensSaved: tokensBaseline - tokensActual,
8215
+ pinnedInvariants
8216
+ }
8217
+ };
8218
+ }
8219
+ var log27, DEFAULT_PINNED_TYPES, PERIPHERAL_DISTANCE;
8220
+ var init_topological_decay = __esm({
8221
+ "src/core/context/topological-decay.ts"() {
8222
+ init_esm_shims();
8223
+ init_compact_context();
8224
+ init_flow_index();
8225
+ init_token_estimator();
8226
+ init_logger();
8227
+ log27 = createLogger({ layer: "core", source: "topological-decay.ts" });
8228
+ DEFAULT_PINNED_TYPES = [
8229
+ "constraint",
8230
+ "risk",
8231
+ "decision",
8232
+ "acceptance_criteria",
8233
+ "constitution",
8234
+ "requirement"
8235
+ ];
8236
+ PERIPHERAL_DISTANCE = 2;
8237
+ }
8238
+ });
8239
+
8240
+ // src/core/store/episodic-outcomes-store.ts
8241
+ function buildApproachSummary(touchedFiles, acIds) {
8242
+ const files = [...touchedFiles].sort().join("+");
8243
+ const acs = [...acIds].sort().join(",");
8244
+ return `${files}:${acs}`;
8245
+ }
8246
+ function insertEpisodicOutcome(db, outcome) {
8247
+ db.prepare(
8248
+ `INSERT OR IGNORE INTO episodic_outcomes
8249
+ (id, node_id, task_type, tags, approach_summary, outcome, cycle_time_delta, reopen_count, created_at)
8250
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
8251
+ ).run(
8252
+ outcome.id,
8253
+ outcome.nodeId,
8254
+ outcome.taskType,
8255
+ outcome.tags,
8256
+ outcome.approachSummary,
8257
+ outcome.outcome,
8258
+ outcome.cycleTimeDelta,
8259
+ outcome.reopenCount,
8260
+ outcome.createdAt
8261
+ );
8262
+ }
8263
+ function queryEpisodicOutcomes(db, opts = {}) {
8264
+ const conditions = [];
8265
+ const params = [];
8266
+ if (opts.taskType) {
8267
+ conditions.push("task_type = ?");
8268
+ params.push(opts.taskType);
8269
+ }
8270
+ if (opts.maxAgeDays) {
8271
+ const cutoff = Date.now() - opts.maxAgeDays * 24 * 3600 * 1e3;
8272
+ conditions.push("created_at >= ?");
8273
+ params.push(cutoff);
8274
+ }
8275
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
8276
+ const limit = Math.min(opts.limit ?? 100, 500);
8277
+ params.push(limit);
8278
+ const rows = db.prepare(
8279
+ `SELECT id, node_id, task_type, tags, approach_summary, outcome,
8280
+ cycle_time_delta, reopen_count, created_at
8281
+ FROM episodic_outcomes
8282
+ ${where}
8283
+ ORDER BY created_at DESC
8284
+ LIMIT ?`
8285
+ ).all(...params);
8286
+ return rows.map((r) => ({
8287
+ id: r.id,
8288
+ nodeId: r.node_id,
8289
+ taskType: r.task_type,
8290
+ tags: r.tags,
8291
+ approachSummary: r.approach_summary,
8292
+ outcome: r.outcome,
8293
+ cycleTimeDelta: r.cycle_time_delta,
8294
+ reopenCount: r.reopen_count,
8295
+ createdAt: r.created_at
8296
+ }));
8297
+ }
8298
+ var init_episodic_outcomes_store = __esm({
8299
+ "src/core/store/episodic-outcomes-store.ts"() {
8300
+ init_esm_shims();
8301
+ }
8302
+ });
8303
+
8304
+ // src/core/context/flow-metrics-store.ts
8305
+ function insertFlowMetric(db, metric) {
8306
+ db.prepare(
8307
+ `INSERT OR IGNORE INTO flow_metrics
8308
+ (id, project_id, node_id, mode, phi, lambda,
8309
+ tokens_baseline, tokens_actual, pruned_count, pinned_count, created_at)
8310
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
8311
+ ).run(
8312
+ metric.id,
8313
+ metric.projectId,
8314
+ metric.nodeId,
8315
+ metric.mode,
8316
+ metric.phi,
8317
+ metric.lambda,
8318
+ metric.tokensBaseline,
8319
+ metric.tokensActual,
8320
+ metric.prunedCount,
8321
+ metric.pinnedCount,
8322
+ metric.createdAt
8323
+ );
8324
+ }
8325
+ var init_flow_metrics_store = __esm({
8326
+ "src/core/context/flow-metrics-store.ts"() {
8327
+ init_esm_shims();
8328
+ }
8329
+ });
8330
+
8331
+ // src/core/context/flow-compact.ts
8332
+ function formatFlowContext(result) {
8333
+ const { context: ctx, pinnedInvariants } = result;
8334
+ const lines = ["Contexto do grafo (dilu\xEDdo por flow \u2014 \u03A6 governando o esquecimento):"];
8335
+ lines.push(`- Task: ${ctx.task.title} (${ctx.task.id}) [${ctx.task.status}]`);
8336
+ if (ctx.task.description) lines.push(` ${ctx.task.description}`);
8337
+ if (ctx.acceptanceCriteria.length > 0) {
8338
+ lines.push("- Crit\xE9rios de aceita\xE7\xE3o:");
8339
+ for (const ac of ctx.acceptanceCriteria) lines.push(` \u2022 ${ac}`);
8340
+ }
8341
+ const openBlockers = ctx.blockers.filter((b) => b.status !== "done");
8342
+ if (openBlockers.length > 0) {
8343
+ lines.push(`- Bloqueadores: ${openBlockers.map((b) => `${b.title} (${b.status})`).join("; ")}`);
8344
+ }
8345
+ const openDeps = ctx.dependsOn.filter((d) => !d.resolved);
8346
+ if (openDeps.length > 0) {
8347
+ lines.push(`- Depende de: ${openDeps.map((d) => `${d.title} (${d.status})`).join("; ")}`);
8348
+ }
8349
+ if (pinnedInvariants.length > 0) {
8350
+ lines.push("- Invariantes pinados (nunca dilu\xEDdos):");
8351
+ for (const inv of pinnedInvariants) lines.push(` \u2022 [${inv.type}] ${inv.title}`);
8352
+ }
8353
+ return lines.join("\n");
8354
+ }
8355
+ function recordMetric(store2, row) {
8356
+ try {
8357
+ insertFlowMetric(store2.getDb(), {
8358
+ id: generateId("flowm"),
8359
+ createdAt: row.createdAt ?? Date.now(),
8360
+ ...row
8361
+ });
8362
+ } catch (err) {
8363
+ log28.warn("flow:metric:record-failed", { error: err instanceof Error ? err.message : String(err) });
8364
+ }
8365
+ }
8366
+ function applyFlowToCompact(store2, nodeId) {
8367
+ const cfg = resolveFlowConfig(store2);
8368
+ if (!cfg.enabled) return null;
8369
+ const projectId = store2.getActiveProject()?.id ?? "unknown";
8370
+ const outcomes = queryEpisodicOutcomes(store2.getDb(), { limit: cfg.historyWindow }).map((o) => o.outcome);
8371
+ const state = computeFlowIndex(outcomes, {
8372
+ emaGain: cfg.emaGain,
8373
+ resetFactor: cfg.resetFactor,
8374
+ partialFactor: cfg.partialFactor
8375
+ });
8376
+ const lambda = computeLambdaFlow(state.phi, cfg.lambdaBase, cfg.alpha);
8377
+ const mode = cfg.experiment.abEnabled ? flowAbArm(nodeId) : "flow_on";
8378
+ if (mode === "flow_off") {
8379
+ const base = buildTaskContext(store2, nodeId);
8380
+ if (!base) return null;
8381
+ const baseline = base.metrics.estimatedTokens;
8382
+ recordMetric(store2, {
8383
+ projectId,
8384
+ nodeId,
8385
+ mode,
8386
+ phi: state.phi,
8387
+ lambda,
8388
+ tokensBaseline: baseline,
8389
+ tokensActual: baseline,
8390
+ prunedCount: 0,
8391
+ pinnedCount: 0
8392
+ });
8393
+ return {
8394
+ context: base,
8395
+ pinnedInvariants: [],
8396
+ flow: {
8397
+ enabled: true,
8398
+ mode,
8399
+ phi: state.phi,
8400
+ streak: state.streak,
8401
+ lambda,
8402
+ prunedCount: 0,
8403
+ pinnedCount: 0,
8404
+ tokensBaseline: baseline,
8405
+ tokensActual: baseline,
8406
+ tokensSaved: 0
8407
+ }
8408
+ };
8409
+ }
8410
+ const decayed = buildDecayedTaskContext(store2, nodeId, {
8411
+ lambda,
8412
+ maxDepth: cfg.maxDepth,
8413
+ weightThreshold: cfg.weightThreshold,
8414
+ pinnedTypes: new Set(cfg.pinnedTypes)
8415
+ });
8416
+ if (!decayed) return null;
8417
+ recordMetric(store2, {
8418
+ projectId,
8419
+ nodeId,
8420
+ mode,
8421
+ phi: state.phi,
8422
+ lambda,
8423
+ tokensBaseline: decayed.meta.tokensBaseline,
8424
+ tokensActual: decayed.meta.tokensActual,
8425
+ prunedCount: decayed.meta.prunedCount,
8426
+ pinnedCount: decayed.meta.pinnedCount
8427
+ });
8428
+ return {
8429
+ context: decayed.context,
8430
+ pinnedInvariants: decayed.meta.pinnedInvariants,
8431
+ flow: {
8432
+ enabled: true,
8433
+ mode,
8434
+ phi: state.phi,
8435
+ streak: state.streak,
8436
+ lambda,
8437
+ prunedCount: decayed.meta.prunedCount,
8438
+ pinnedCount: decayed.meta.pinnedCount,
8439
+ tokensBaseline: decayed.meta.tokensBaseline,
8440
+ tokensActual: decayed.meta.tokensActual,
8441
+ tokensSaved: decayed.meta.tokensSaved
8442
+ }
8443
+ };
8444
+ }
8445
+ var log28;
8446
+ var init_flow_compact = __esm({
8447
+ "src/core/context/flow-compact.ts"() {
8448
+ init_esm_shims();
8449
+ init_flow_config();
8450
+ init_flow_index();
8451
+ init_topological_decay();
8452
+ init_compact_context();
8453
+ init_episodic_outcomes_store();
8454
+ init_flow_metrics_store();
8455
+ init_id();
8456
+ init_logger();
8457
+ log28 = createLogger({ layer: "core", source: "flow-compact.ts" });
8458
+ }
8459
+ });
7576
8460
 
7577
8461
  // src/cli/shared/live-implement.ts
7578
8462
  function buildLiveImplement(options) {
@@ -7589,6 +8473,14 @@ function buildLiveImplement(options) {
7589
8473
  const repoRelations = projectId ? codeStore.getAllRelations(projectId) : [];
7590
8474
  const implement = async (node) => {
7591
8475
  const repoMap = repoSymbols.length > 0 ? buildRepoMap({ symbols: repoSymbols, relations: repoRelations }, { tokenBudget: REPO_MAP_TOKEN_BUDGET, focus: node.title }).text : void 0;
8476
+ let flowContext;
8477
+ const flow = applyFlowToCompact(store2, node.id);
8478
+ if (flow) {
8479
+ flowContext = formatFlowContext(flow);
8480
+ onLog?.(
8481
+ ` [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`
8482
+ );
8483
+ }
7592
8484
  const outcome = await attemptImplementation(
7593
8485
  {
7594
8486
  generate: async (prompt) => {
@@ -7604,13 +8496,28 @@ function buildLiveImplement(options) {
7604
8496
  },
7605
8497
  execute: (plan) => executePlan(plan, { workspaceDir: dir, defaultTestCommand: testCmd })
7606
8498
  },
7607
- { node, maxAttempts, repoMap }
8499
+ { node, maxAttempts, repoMap, flowContext }
7608
8500
  );
7609
8501
  const files = outcome.lastResult?.applied.length ?? 0;
7610
8502
  const task = ledger.byTask(node.id);
7611
8503
  onLog?.(
7612
8504
  ` [live] ${client.modelFor("implement")}: ${outcome.attempts} tentativa(s), ${files} arquivo(s), ${task.total} tok \u2192 ${outcome.success ? "verde" : "escala"}`
7613
8505
  );
8506
+ try {
8507
+ const applied = outcome.lastResult?.applied ?? [];
8508
+ insertEpisodicOutcome(store2.getDb(), {
8509
+ id: generateId("epi"),
8510
+ nodeId: node.id,
8511
+ taskType: "",
8512
+ tags: "",
8513
+ approachSummary: buildApproachSummary(applied, []),
8514
+ outcome: outcome.success ? "success" : "failure",
8515
+ cycleTimeDelta: 0,
8516
+ reopenCount: 0,
8517
+ createdAt: Date.now()
8518
+ });
8519
+ } catch {
8520
+ }
7614
8521
  return outcome.success;
7615
8522
  };
7616
8523
  return { implement, repoSymbolCount: repoSymbols.length };
@@ -7625,6 +8532,9 @@ var init_live_implement = __esm({
7625
8532
  init_implement_attempt();
7626
8533
  init_code_store();
7627
8534
  init_repo_map();
8535
+ init_flow_compact();
8536
+ init_episodic_outcomes_store();
8537
+ init_id();
7628
8538
  REPO_MAP_TOKEN_BUDGET = 1e3;
7629
8539
  }
7630
8540
  });
@@ -7890,7 +8800,7 @@ function InteractiveApp({ dashboard, port, asyncPort, liveRunner, skillCommands
7890
8800
  process.stdout.isTTY ? "banner" : "dashboard"
7891
8801
  );
7892
8802
  const [input, setInput] = useState("");
7893
- const [log45, setLog] = useState([]);
8803
+ const [log48, setLog] = useState([]);
7894
8804
  const [running, setRunning] = useState(false);
7895
8805
  const [showHelp, setShowHelp] = useState(false);
7896
8806
  const append = (line) => setLog((prev) => [...prev, line].slice(-MAX_LOG_LINES));
@@ -7939,7 +8849,7 @@ ${skill.body}` : `Skill n\xE3o encontrada: ${parsed.cmd}`);
7939
8849
  }
7940
8850
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
7941
8851
  /* @__PURE__ */ jsx(App, { model: dashboard }),
7942
- log45.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: "single", paddingX: 1, children: log45.map((line, i) => /* @__PURE__ */ jsx(Text, { children: line }, i)) }),
8852
+ 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
8853
  showHelp && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", paddingX: 1, children: [
7944
8854
  /* @__PURE__ */ jsx(Text, { bold: true, children: "Comandos:" }),
7945
8855
  COMMANDS.map((c) => /* @__PURE__ */ jsxs(Text, { children: [
@@ -8166,22 +9076,25 @@ function parseSkillMarkdown(content) {
8166
9076
  } catch (err) {
8167
9077
  return { ok: false, error: `YAML parse error: ${err instanceof Error ? err.message : String(err)}` };
8168
9078
  }
9079
+ const rawTriggers = frontmatter.triggers;
9080
+ const triggers = Array.isArray(rawTriggers) ? rawTriggers.map((t) => typeof t === "string" ? { event: t } : t) : rawTriggers;
9081
+ const phases = Array.isArray(frontmatter.phases) ? frontmatter.phases : [];
8169
9082
  const raw = {
8170
9083
  name: frontmatter.name,
8171
9084
  description: frontmatter.description,
8172
9085
  category: frontmatter.category ?? "know-me",
8173
- phases: frontmatter.phases,
9086
+ phases,
8174
9087
  // §extracta-sweep-1 — optional `platforms:` array; absent = all OSes.
8175
9088
  platforms: frontmatter.platforms,
8176
9089
  instructions: bodyText,
8177
9090
  toolchain: frontmatter.toolchain,
8178
- triggers: frontmatter.triggers,
9091
+ triggers,
8179
9092
  contextTemplate: frontmatter.contextTemplate
8180
9093
  };
8181
9094
  const parsed = CustomSkillInputSchema.safeParse(raw);
8182
9095
  if (!parsed.success) {
8183
9096
  const issues = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
8184
- log26.warn("skill-loader:validation_failed", { issues });
9097
+ log29.debug("skill-loader:validation_failed", { issues });
8185
9098
  return { ok: false, error: `Validation failed: ${issues}` };
8186
9099
  }
8187
9100
  return { ok: true, skill: parsed.data };
@@ -8224,13 +9137,13 @@ function walk(dir, acc) {
8224
9137
  else acc.errors.push({ file: full, error: parsed.error ?? "unknown parse error" });
8225
9138
  }
8226
9139
  }
8227
- var log26;
9140
+ var log29;
8228
9141
  var init_skill_loader = __esm({
8229
9142
  "src/core/skills/skill-loader.ts"() {
8230
9143
  init_esm_shims();
8231
9144
  init_skill_schema();
8232
9145
  init_logger();
8233
- log26 = createLogger({ layer: "core", source: "skill-loader.ts" });
9146
+ log29 = createLogger({ layer: "core", source: "skill-loader.ts" });
8234
9147
  }
8235
9148
  });
8236
9149
  function summarize(skill) {
@@ -8323,7 +9236,7 @@ function mergeGraph(store2, incoming, options) {
8323
9236
  }
8324
9237
  const sourceProject = incoming.project.name;
8325
9238
  const dryRun = options?.dryRun ?? false;
8326
- log27.info("merge-graph:start", {
9239
+ log30.info("merge-graph:start", {
8327
9240
  sourceProject,
8328
9241
  incomingNodes: incoming.nodes.length,
8329
9242
  incomingEdges: incoming.edges.length,
@@ -8375,7 +9288,7 @@ function mergeGraph(store2, incoming, options) {
8375
9288
  edgesInserted2++;
8376
9289
  }
8377
9290
  }
8378
- log27.info("merge-graph:dry-run", {
9291
+ log30.info("merge-graph:dry-run", {
8379
9292
  nodesInserted: nodesToInsert.length,
8380
9293
  nodesSkipped,
8381
9294
  edgesInserted: edgesInserted2,
@@ -8395,7 +9308,7 @@ function mergeGraph(store2, incoming, options) {
8395
9308
  const { nodesInserted, edgesInserted } = store2.mergeInsert(nodesToInsert, validEdges);
8396
9309
  const edgesSkipped = validEdges.length - edgesInserted;
8397
9310
  store2.recordImport(`merge:${sourceProject}`, nodesInserted, edgesInserted);
8398
- log27.info("merge-graph:done", {
9311
+ log30.info("merge-graph:done", {
8399
9312
  sourceProject,
8400
9313
  nodesInserted,
8401
9314
  nodesSkipped,
@@ -8412,14 +9325,14 @@ function mergeGraph(store2, incoming, options) {
8412
9325
  sourceProject
8413
9326
  };
8414
9327
  }
8415
- var log27;
9328
+ var log30;
8416
9329
  var init_import_graph = __esm({
8417
9330
  "src/core/importer/import-graph.ts"() {
8418
9331
  init_esm_shims();
8419
9332
  init_graph_schema();
8420
9333
  init_errors();
8421
9334
  init_logger();
8422
- log27 = createLogger({ layer: "core", source: "import-graph.ts" });
9335
+ log30 = createLogger({ layer: "core", source: "import-graph.ts" });
8423
9336
  }
8424
9337
  });
8425
9338
 
@@ -8530,7 +9443,7 @@ function computeFileSha256(path22) {
8530
9443
  return hash.digest("hex");
8531
9444
  }
8532
9445
  async function downloadFileWithVerify(url, destPath, expectedSha256) {
8533
- log28.info("model-downloader:start", { url, dest: destPath, hasExpectedHash: false });
9446
+ log31.info("model-downloader:start", { url, dest: destPath, hasExpectedHash: false });
8534
9447
  const controller = new AbortController();
8535
9448
  const timeoutId = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT_MS);
8536
9449
  let response;
@@ -8552,15 +9465,15 @@ async function downloadFileWithVerify(url, destPath, expectedSha256) {
8552
9465
  const actualSha = computeFileSha256(destPath);
8553
9466
  const sizeBytes = statSync(destPath).size;
8554
9467
  const verified = expectedSha256 != null && actualSha === expectedSha256;
8555
- log28.info("model-downloader:ok", { dest: destPath, sizeBytes, sha256: actualSha, verified });
9468
+ log31.info("model-downloader:ok", { dest: destPath, sizeBytes, sha256: actualSha, verified });
8556
9469
  return { sha256: actualSha, verified, sizeBytes };
8557
9470
  }
8558
- var log28, DOWNLOAD_TIMEOUT_MS, ChecksumMismatchError, DownloadError;
9471
+ var log31, DOWNLOAD_TIMEOUT_MS, ChecksumMismatchError, DownloadError;
8559
9472
  var init_model_downloader = __esm({
8560
9473
  "src/core/rag/model-downloader.ts"() {
8561
9474
  init_esm_shims();
8562
9475
  init_logger();
8563
- log28 = createLogger({ layer: "core", source: "model-downloader.ts" });
9476
+ log31 = createLogger({ layer: "core", source: "model-downloader.ts" });
8564
9477
  DOWNLOAD_TIMEOUT_MS = 9e4;
8565
9478
  ChecksumMismatchError = class extends Error {
8566
9479
  constructor(url, expected, actual) {
@@ -8629,15 +9542,15 @@ async function isOnnxAvailable() {
8629
9542
  onnxAvailableCache = true;
8630
9543
  } catch {
8631
9544
  onnxAvailableCache = false;
8632
- log29.warn("onnx:unavailable", { reason: "onnxruntime-node not installed \u2014 RAG will use hash embeddings (degraded mode)" });
9545
+ log32.warn("onnx:unavailable", { reason: "onnxruntime-node not installed \u2014 RAG will use hash embeddings (degraded mode)" });
8633
9546
  }
8634
9547
  return onnxAvailableCache;
8635
9548
  }
8636
9549
  async function logEmbeddingModeOnBoot(isAvailable = isOnnxAvailable, logFn = (event, fields) => {
8637
9550
  if (fields.mode === "neural") {
8638
- log29.info(event, fields);
9551
+ log32.info(event, fields);
8639
9552
  } else {
8640
- log29.warn(event, fields);
9553
+ log32.warn(event, fields);
8641
9554
  }
8642
9555
  }) {
8643
9556
  try {
@@ -8660,7 +9573,7 @@ function ensureOnnxModelDir(modelsDir) {
8660
9573
  async function downloadFile(url, destPath) {
8661
9574
  try {
8662
9575
  const resultValue = await downloadFileWithVerify(url, destPath);
8663
- log29.info("onnx:download:ok", {
9576
+ log32.info("onnx:download:ok", {
8664
9577
  dest: destPath,
8665
9578
  sizeBytes: resultValue.sizeBytes,
8666
9579
  sha256: resultValue.sha256,
@@ -8684,7 +9597,7 @@ async function ensureModelFiles(modelsDir) {
8684
9597
  if (existsSync(modelPath)) {
8685
9598
  const size = statSync(modelPath).size;
8686
9599
  if (size < MIN_MODEL_SIZE) {
8687
- log29.warn("onnx:corrupted-model", { modelPath, sizeBytes: size, minRequired: MIN_MODEL_SIZE });
9600
+ log32.warn("onnx:corrupted-model", { modelPath, sizeBytes: size, minRequired: MIN_MODEL_SIZE });
8688
9601
  unlinkSync(modelPath);
8689
9602
  }
8690
9603
  }
@@ -8693,12 +9606,12 @@ async function ensureModelFiles(modelsDir) {
8693
9606
  const raw = readFileSync(tokenizerPath, "utf-8");
8694
9607
  JSON.parse(raw);
8695
9608
  } catch {
8696
- log29.warn("onnx:corrupted-tokenizer", { tokenizerPath });
9609
+ log32.warn("onnx:corrupted-tokenizer", { tokenizerPath });
8697
9610
  unlinkSync(tokenizerPath);
8698
9611
  }
8699
9612
  }
8700
9613
  if (existsSync(modelPath) && existsSync(tokenizerPath)) {
8701
- log29.debug("onnx:cache-hit", { modelDir });
9614
+ log32.debug("onnx:cache-hit", { modelDir });
8702
9615
  return { modelPath, tokenizerPath };
8703
9616
  }
8704
9617
  mkdirSync(modelDir, { recursive: true });
@@ -8715,7 +9628,7 @@ function loadTokenizer(tokenizerPath) {
8715
9628
  const raw = readFileSync(tokenizerPath, "utf-8");
8716
9629
  return JSON.parse(raw);
8717
9630
  } catch (err) {
8718
- log29.warn("onnx:tokenizer-load-failed", { tokenizerPath, error: err instanceof Error ? err.message : String(err) });
9631
+ log32.warn("onnx:tokenizer-load-failed", { tokenizerPath, error: err instanceof Error ? err.message : String(err) });
8719
9632
  return null;
8720
9633
  }
8721
9634
  }
@@ -8767,15 +9680,15 @@ function startOnnxBackgroundDownload(modelsDir, options = {}) {
8767
9680
  modelPath = join(modelDir, MODEL_FILENAME);
8768
9681
  tokenizerPath = join(modelDir, TOKENIZER_FILENAME);
8769
9682
  const cacheEvent = "onnx:background-ready-from-cache";
8770
- log29.info(cacheEvent, { modelsDir });
9683
+ log32.info(cacheEvent, { modelsDir });
8771
9684
  onLog?.(cacheEvent);
8772
9685
  } else {
8773
9686
  const startEvent = "onnx:background-download-start";
8774
- log29.info(startEvent, { message: "Downloading MiniLM-L6-v2 (23MB)...", modelsDir });
9687
+ log32.info(startEvent, { message: "Downloading MiniLM-L6-v2 (23MB)...", modelsDir });
8775
9688
  onLog?.(startEvent);
8776
9689
  ({ modelPath, tokenizerPath } = await ensureFiles(modelsDir));
8777
9690
  const doneEvent = "onnx:background-download-complete";
8778
- log29.info(doneEvent, { modelsDir });
9691
+ log32.info(doneEvent, { modelsDir });
8779
9692
  onLog?.(doneEvent);
8780
9693
  }
8781
9694
  const provider = makeProvider(modelPath, tokenizerPath);
@@ -8783,7 +9696,7 @@ function startOnnxBackgroundDownload(modelsDir, options = {}) {
8783
9696
  onReady?.(provider);
8784
9697
  } catch (err) {
8785
9698
  const msg = err instanceof Error ? err.message : String(err);
8786
- log29.warn("onnx:background-download-failed", { error: msg, action: "fallback-remains-tfidf" });
9699
+ log32.warn("onnx:background-download-failed", { error: msg, action: "fallback-remains-tfidf" });
8787
9700
  onWarning?.(msg);
8788
9701
  }
8789
9702
  };
@@ -8797,7 +9710,7 @@ function _resetBackgroundDownloadState() {
8797
9710
  async function getOnnxProvider(modelsDir) {
8798
9711
  const available = await isOnnxAvailable();
8799
9712
  if (!available) {
8800
- log29.warn("onnx:provider-degraded", { available: false, impact: "RAG operates with hash embeddings instead of neural \u2014 lower search quality" });
9713
+ log32.warn("onnx:provider-degraded", { available: false, impact: "RAG operates with hash embeddings instead of neural \u2014 lower search quality" });
8801
9714
  return null;
8802
9715
  }
8803
9716
  const existing = providerCache.get(modelsDir);
@@ -8817,8 +9730,8 @@ async function getOnnxProvider(modelsDir) {
8817
9730
  return await creation;
8818
9731
  } catch (err) {
8819
9732
  providerCache.delete(modelsDir);
8820
- log29.error("onnx:provider-init-failed", { error: err instanceof Error ? err.message : String(err) });
8821
- log29.warn("onnx:fallback", {
9733
+ log32.error("onnx:provider-init-failed", { error: err instanceof Error ? err.message : String(err) });
9734
+ log32.warn("onnx:fallback", {
8822
9735
  reason: err instanceof Error ? err.message : String(err),
8823
9736
  action: "return-null-provider",
8824
9737
  modelsDir
@@ -8826,7 +9739,7 @@ async function getOnnxProvider(modelsDir) {
8826
9739
  return null;
8827
9740
  }
8828
9741
  }
8829
- var log29, 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;
9742
+ 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
9743
  var init_onnx_embeddings = __esm({
8831
9744
  "src/core/rag/onnx-embeddings.ts"() {
8832
9745
  init_esm_shims();
@@ -8834,7 +9747,7 @@ var init_onnx_embeddings = __esm({
8834
9747
  init_errors();
8835
9748
  init_tensor_buffer_pool();
8836
9749
  init_model_downloader();
8837
- log29 = createLogger({ layer: "rag", source: "onnx-embeddings.ts" });
9750
+ log32 = createLogger({ layer: "rag", source: "onnx-embeddings.ts" });
8838
9751
  MODEL_NAME = "all-MiniLM-L6-v2-quantized";
8839
9752
  MODEL_FILENAME = "model.onnx";
8840
9753
  TOKENIZER_FILENAME = "tokenizer.json";
@@ -8866,7 +9779,7 @@ var init_onnx_embeddings = __esm({
8866
9779
  throw new OnnxModelNotFoundError(`Failed to load tokenizer: ${this.tokenizerPath}`);
8867
9780
  }
8868
9781
  this.vocab = config.model?.vocab ?? {};
8869
- log29.info("onnx:session-created", { model: this.modelPath });
9782
+ log32.info("onnx:session-created", { model: this.modelPath });
8870
9783
  return this.session;
8871
9784
  }
8872
9785
  async generateEmbedding(text) {
@@ -8995,7 +9908,7 @@ async function checkSqliteDatabase(basePath) {
8995
9908
  };
8996
9909
  }
8997
9910
  } catch (err) {
8998
- log30.debug("intentional-swallow", { error: String(err), reason: "statSync race with deletion; fall through to open attempt" });
9911
+ log33.debug("intentional-swallow", { error: String(err), reason: "statSync race with deletion; fall through to open attempt" });
8999
9912
  }
9000
9913
  try {
9001
9914
  const db = new Database2(dbPath, { readonly: true });
@@ -9045,7 +9958,7 @@ async function checkDbIntegrity2(basePath) {
9045
9958
  };
9046
9959
  }
9047
9960
  } catch (err) {
9048
- log30.debug("intentional-swallow", { error: String(err), reason: "fall through to open attempt" });
9961
+ log33.debug("intentional-swallow", { error: String(err), reason: "fall through to open attempt" });
9049
9962
  }
9050
9963
  try {
9051
9964
  const db = new Database2(dbPath, { readonly: true });
@@ -9053,7 +9966,7 @@ async function checkDbIntegrity2(basePath) {
9053
9966
  try {
9054
9967
  schemaCount = db.prepare("SELECT count(*) as n FROM sqlite_master WHERE type IN ('table','view')").get().n;
9055
9968
  } catch (err) {
9056
- log30.debug("intentional-swallow", { error: String(err), reason: "reading sqlite_master itself failed \u2014 DB is unreadable, fall through" });
9969
+ log33.debug("intentional-swallow", { error: String(err), reason: "reading sqlite_master itself failed \u2014 DB is unreadable, fall through" });
9057
9970
  }
9058
9971
  if (schemaCount === 0) {
9059
9972
  db.close();
@@ -9213,7 +10126,7 @@ async function checkIntegrations(basePath) {
9213
10126
  });
9214
10127
  return results;
9215
10128
  } catch (err) {
9216
- log30.debug("doctor:integrations:fail", {
10129
+ log33.debug("doctor:integrations:fail", {
9217
10130
  error: err instanceof Error ? err.message : String(err)
9218
10131
  });
9219
10132
  return [
@@ -9264,7 +10177,7 @@ async function checkOnnxStatus() {
9264
10177
  const { isOnnxAvailable: isOnnxAvailable2 } = await Promise.resolve().then(() => (init_onnx_embeddings(), onnx_embeddings_exports));
9265
10178
  return checkOnnxStatusWith(isOnnxAvailable2);
9266
10179
  }
9267
- var log30, MIN_NODE_VERSION;
10180
+ var log33, MIN_NODE_VERSION;
9268
10181
  var init_doctor_checks = __esm({
9269
10182
  "src/core/doctor/doctor-checks.ts"() {
9270
10183
  init_esm_shims();
@@ -9272,7 +10185,7 @@ var init_doctor_checks = __esm({
9272
10185
  init_fs();
9273
10186
  init_tool_status();
9274
10187
  init_logger();
9275
- log30 = createLogger({ layer: "core", source: "doctor-checks.ts" });
10188
+ log33 = createLogger({ layer: "core", source: "doctor-checks.ts" });
9276
10189
  MIN_NODE_VERSION = 20;
9277
10190
  }
9278
10191
  });
@@ -9297,7 +10210,7 @@ async function runDoctor(basePath) {
9297
10210
  if (!basePath) {
9298
10211
  throw new McpGraphError("Doctor requires a valid base path");
9299
10212
  }
9300
- log31.info("Running doctor checks", { basePath });
10213
+ log34.info("Running doctor checks", { basePath });
9301
10214
  const checks = [];
9302
10215
  checks.push(checkNodeVersion());
9303
10216
  checks.push(checkConfigFile(basePath));
@@ -9335,7 +10248,7 @@ async function runDoctor(basePath) {
9335
10248
  }
9336
10249
  }
9337
10250
  for (const result of checks) {
9338
- log31.event(
10251
+ log34.event(
9339
10252
  { action: "health.check", category: "health", outcome: result.level === "ok" ? "success" : "failure" },
9340
10253
  `health.check.${result.name}`,
9341
10254
  { check: result.name }
@@ -9348,7 +10261,7 @@ async function runDoctor(basePath) {
9348
10261
  passed: summary.error === 0
9349
10262
  };
9350
10263
  }
9351
- var log31;
10264
+ var log34;
9352
10265
  var init_doctor_runner = __esm({
9353
10266
  "src/core/doctor/doctor-runner.ts"() {
9354
10267
  init_esm_shims();
@@ -9357,7 +10270,7 @@ var init_doctor_runner = __esm({
9357
10270
  init_errors();
9358
10271
  init_logger();
9359
10272
  init_doctor_checks();
9360
- log31 = createLogger({ layer: "core", source: "doctor-runner.ts" });
10273
+ log34 = createLogger({ layer: "core", source: "doctor-runner.ts" });
9361
10274
  }
9362
10275
  });
9363
10276
 
@@ -10104,16 +11017,36 @@ init_token_ledger();
10104
11017
  init_llm_call_ledger();
10105
11018
  init_live_implement();
10106
11019
  init_store_port();
11020
+
11021
+ // src/cli/shared/enable-flow.ts
11022
+ init_esm_shims();
11023
+ init_flow_config();
11024
+ function enableFlowConfig(store2) {
11025
+ const raw = store2.getProjectSetting(FLOW_CONFIG_SETTING_KEY);
11026
+ let current = {};
11027
+ if (raw) {
11028
+ try {
11029
+ current = JSON.parse(raw);
11030
+ } catch {
11031
+ current = {};
11032
+ }
11033
+ }
11034
+ store2.setProjectSetting(FLOW_CONFIG_SETTING_KEY, JSON.stringify({ ...current, enabled: true }));
11035
+ }
10107
11036
  function output7(msg) {
10108
11037
  process.stdout.write(msg + "\n");
10109
11038
  }
10110
11039
  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(
11040
+ 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
11041
  async (opts) => {
10113
11042
  const store2 = openStoreOrFail(opts.dir, { requireExisting: true });
10114
11043
  try {
10115
11044
  const maxIterations = Math.max(1, parseInt(opts.max, 10) || 5);
10116
11045
  const port = makeStorePort(store2);
11046
+ if (opts.flow) {
11047
+ enableFlowConfig(store2);
11048
+ output7("[FLOW] \u03BB_flow ativo: contexto do grafo dilu\xEDdo por \u03A6(t) (esquecimento din\xE2mico).\n");
11049
+ }
10117
11050
  if (opts.simulate) output7("[SIMULA\xC7\xC3O] impl tratada como verde \u2014 DoD real decide prontid\xE3o.\n");
10118
11051
  if (opts.live) output7("[LIVE] modelo via SDK do Copilot: gera plano \u2192 aplica no workspace \u2192 roda testes.\n");
10119
11052
  let implement;
@@ -10413,7 +11346,7 @@ function whichCommand() {
10413
11346
  }
10414
11347
 
10415
11348
  // src/core/lsp/lsp-deps-installer.ts
10416
- var log33 = createLogger({ layer: "core", source: "lsp-deps-installer.ts" });
11349
+ var log36 = createLogger({ layer: "core", source: "lsp-deps-installer.ts" });
10417
11350
  var execAsync = promisify(execFile);
10418
11351
  var LSP_NPM_PACKAGES = {
10419
11352
  typescript: "typescript-language-server",
@@ -10464,7 +11397,7 @@ var LSP_SYSTEM_PACKAGES = {
10464
11397
  async function checkLspDep(languageId, command) {
10465
11398
  try {
10466
11399
  await execAsync(whichCommand(), [command]);
10467
- log33.info("LSP server available", { languageId, command });
11400
+ log36.info("LSP server available", { languageId, command });
10468
11401
  return {
10469
11402
  name: command,
10470
11403
  languageId,
@@ -10510,7 +11443,7 @@ function getServerCommand(languageId) {
10510
11443
  }
10511
11444
  async function installLspDeps(detectedLanguages) {
10512
11445
  if (detectedLanguages.length === 0) return [];
10513
- log33.info("Checking LSP server dependencies", {
11446
+ log36.info("Checking LSP server dependencies", {
10514
11447
  languages: detectedLanguages.join(", ")
10515
11448
  });
10516
11449
  const results = [];
@@ -10522,7 +11455,7 @@ async function installLspDeps(detectedLanguages) {
10522
11455
  }
10523
11456
  const available = results.filter((r) => r.status === "already_available").length;
10524
11457
  const missing = results.filter((r) => r.status === "not_found").length;
10525
- log33.info("LSP dependency check complete", {
11458
+ log36.info("LSP dependency check complete", {
10526
11459
  total: String(results.length),
10527
11460
  available: String(available),
10528
11461
  missing: String(missing)
@@ -10533,7 +11466,7 @@ async function installLspDeps(detectedLanguages) {
10533
11466
  // src/core/lsp/language-detector.ts
10534
11467
  init_esm_shims();
10535
11468
  init_logger();
10536
- var log34 = createLogger({ layer: "core", source: "language-detector.ts" });
11469
+ var log37 = createLogger({ layer: "core", source: "language-detector.ts" });
10537
11470
  var CONFIG_FILE_MAP = {
10538
11471
  "tsconfig.json": "typescript",
10539
11472
  "jsconfig.json": "typescript",
@@ -10573,7 +11506,7 @@ var IGNORED_DIRS = /* @__PURE__ */ new Set([
10573
11506
  "__pycache__"
10574
11507
  ]);
10575
11508
  function detectProjectLanguages(projectPath, registry) {
10576
- log34.debug("detecting project languages", { projectPath });
11509
+ log37.debug("detecting project languages", { projectPath });
10577
11510
  const configDetections = /* @__PURE__ */ new Map();
10578
11511
  const fileCounts = /* @__PURE__ */ new Map();
10579
11512
  detectConfigFiles(projectPath, configDetections);
@@ -10601,7 +11534,7 @@ function detectProjectLanguages(projectPath, registry) {
10601
11534
  });
10602
11535
  }
10603
11536
  results.sort((a, b) => b.fileCount - a.fileCount);
10604
- log34.info("project languages detected", {
11537
+ log37.info("project languages detected", {
10605
11538
  count: String(results.length),
10606
11539
  languages: results.map((r) => r.languageId).join(",")
10607
11540
  });
@@ -10612,7 +11545,7 @@ function detectConfigFiles(rootPath, configDetections) {
10612
11545
  try {
10613
11546
  entries = readdirSync(rootPath, { withFileTypes: true, encoding: "utf-8" });
10614
11547
  } catch {
10615
- log34.debug("cannot read root directory for config detection", { rootPath });
11548
+ log37.debug("cannot read root directory for config detection", { rootPath });
10616
11549
  return;
10617
11550
  }
10618
11551
  for (const entry of entries) {
@@ -10637,7 +11570,7 @@ function walkAndCountFiles(dirPath, registry, fileCounts) {
10637
11570
  try {
10638
11571
  entries = readdirSync(dirPath, { withFileTypes: true, encoding: "utf-8" });
10639
11572
  } catch {
10640
- log34.debug("cannot read directory, skipping", { dirPath });
11573
+ log37.debug("cannot read directory, skipping", { dirPath });
10641
11574
  return;
10642
11575
  }
10643
11576
  for (const entry of entries) {
@@ -11722,176 +12655,10 @@ function applySection(existingContent, newSection) {
11722
12655
 
11723
12656
  // src/core/config/config-loader.ts
11724
12657
  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
12658
+ init_config_schema();
11892
12659
  init_errors();
11893
12660
  init_logger();
11894
- var log35 = createLogger({ layer: "core", source: "config-loader.ts" });
12661
+ var log38 = createLogger({ layer: "core", source: "config-loader.ts" });
11895
12662
  var CONFIG_FILENAME = "mcp-graph.config.json";
11896
12663
  function loadConfig(basePath) {
11897
12664
  const resolvedBase = basePath ?? process.cwd();
@@ -11901,13 +12668,13 @@ function loadConfig(basePath) {
11901
12668
  try {
11902
12669
  const raw = readFileSync(configPath, "utf-8").replace(/^\uFEFF/, "");
11903
12670
  fileConfig = JSON.parse(raw);
11904
- log35.info(`Config loaded from ${configPath}`);
12671
+ log38.info(`Config loaded from ${configPath}`);
11905
12672
  } catch (err) {
11906
12673
  const msg = err instanceof Error ? err.message : String(err);
11907
12674
  throw new McpGraphError(`Invalid config at ${configPath}: ${msg}`);
11908
12675
  }
11909
12676
  } else {
11910
- log35.info("No config file found, using defaults");
12677
+ log38.info("No config file found, using defaults");
11911
12678
  }
11912
12679
  if (process.env.MCP_PORT) {
11913
12680
  const envPort = parseInt(process.env.MCP_PORT, 10);
@@ -11927,7 +12694,7 @@ function loadConfig(basePath) {
11927
12694
  // src/core/config/ignore-templates.ts
11928
12695
  init_esm_shims();
11929
12696
  init_logger();
11930
- var log36 = createLogger({ layer: "core", source: "ignore-templates.ts" });
12697
+ var log39 = createLogger({ layer: "core", source: "ignore-templates.ts" });
11931
12698
  var IGNORE_TEMPLATE = `# ========================================
11932
12699
  # LEAN CONTEXT (mcp-graph)
11933
12700
  # Filosofia: zero auto-load, tudo on-demand via MCP
@@ -12078,21 +12845,21 @@ release-please-config.json
12078
12845
  function ensureClaudeIgnore(projectDir) {
12079
12846
  const filePath = path17__default.join(projectDir, ".claudeignore");
12080
12847
  if (existsSync(filePath)) {
12081
- log36.debug(".claudeignore already exists, skipping");
12848
+ log39.debug(".claudeignore already exists, skipping");
12082
12849
  return false;
12083
12850
  }
12084
12851
  writeFileSync(filePath, IGNORE_TEMPLATE, "utf-8");
12085
- log36.info(".claudeignore created with lean context template");
12852
+ log39.info(".claudeignore created with lean context template");
12086
12853
  return true;
12087
12854
  }
12088
12855
  function ensureCopilotIgnore(projectDir) {
12089
12856
  const filePath = path17__default.join(projectDir, ".copilotignore");
12090
12857
  if (existsSync(filePath)) {
12091
- log36.debug(".copilotignore already exists, skipping");
12858
+ log39.debug(".copilotignore already exists, skipping");
12092
12859
  return false;
12093
12860
  }
12094
12861
  writeFileSync(filePath, IGNORE_TEMPLATE, "utf-8");
12095
- log36.info(".copilotignore created with lean context template");
12862
+ log39.info(".copilotignore created with lean context template");
12096
12863
  return true;
12097
12864
  }
12098
12865
  function updateIgnoreFile(filePath, label, dryRun) {
@@ -12100,7 +12867,7 @@ function updateIgnoreFile(filePath, label, dryRun) {
12100
12867
  if (!exists) {
12101
12868
  if (!dryRun) {
12102
12869
  writeFileSync(filePath, IGNORE_TEMPLATE, "utf-8");
12103
- log36.info(`${label} created with lean context template`);
12870
+ log39.info(`${label} created with lean context template`);
12104
12871
  }
12105
12872
  return { status: "created", message: `${label} created` };
12106
12873
  }
@@ -12110,7 +12877,7 @@ function updateIgnoreFile(filePath, label, dryRun) {
12110
12877
  }
12111
12878
  if (!dryRun) {
12112
12879
  writeFileSync(filePath, IGNORE_TEMPLATE, "utf-8");
12113
- log36.info(`${label} updated to latest template`);
12880
+ log39.info(`${label} updated to latest template`);
12114
12881
  }
12115
12882
  return { status: "updated", message: `${label} updated` };
12116
12883
  }
@@ -12787,7 +13554,7 @@ init_registry();
12787
13554
  // src/core/atomic-files/writer-markdown.ts
12788
13555
  init_esm_shims();
12789
13556
  init_logger();
12790
- var log37 = createLogger({ layer: "core", source: "writer-markdown.ts" });
13557
+ var log40 = createLogger({ layer: "core", source: "writer-markdown.ts" });
12791
13558
  var markerStart2 = (id) => `<!-- MCP-GRAPH:MANAGED-START:${id} -->`;
12792
13559
  var markerEnd2 = (id) => `<!-- MCP-GRAPH:MANAGED-END:${id} -->`;
12793
13560
  function extractManagedBlock(content, fileId) {
@@ -12849,7 +13616,7 @@ async function write(file, mode) {
12849
13616
  const existingBlock = extractManagedBlock(current, fileId);
12850
13617
  const tampered = existingBlock !== null && detectTampering(filePath, fileId, existingBlock);
12851
13618
  if (tampered) {
12852
- log37.warn("managed block tampered \u2014 system reconquering", { fileId, filePath });
13619
+ log40.warn("managed block tampered \u2014 system reconquering", { fileId, filePath });
12853
13620
  fs.writeFileSync(filePath + ".user-modified.bak", current, "utf8");
12854
13621
  }
12855
13622
  if (!tampered && existingBlock === managedContent) {
@@ -12887,7 +13654,7 @@ async function atomicWrite(filePath, content) {
12887
13654
  try {
12888
13655
  fs.unlinkSync(tmp);
12889
13656
  } catch (e) {
12890
- log37.debug("intentional swallow", { error: e, reason: "tmp file already gone, cleanup not needed" });
13657
+ log40.debug("intentional swallow", { error: e, reason: "tmp file already gone, cleanup not needed" });
12891
13658
  }
12892
13659
  throw err;
12893
13660
  }
@@ -12915,7 +13682,7 @@ async function runAtomicWrites(mode) {
12915
13682
  }
12916
13683
 
12917
13684
  // src/cli/commands/init-cmd.ts
12918
- var log38 = createLogger({ layer: "cli", source: "init.ts" });
13685
+ var log41 = createLogger({ layer: "cli", source: "init.ts" });
12919
13686
  var LEVEL_ICON = { ok: "\u2713", warning: "\u26A0", error: "\u2717" };
12920
13687
  async function runInitOrchestration(opts, deps) {
12921
13688
  const { dir, skipNeural, noServe, port } = opts;
@@ -13028,7 +13795,7 @@ function initCommand() {
13028
13795
  const dir = path17__default.resolve(opts.dir);
13029
13796
  const port = parseInt(opts.port, 10);
13030
13797
  if (isNaN(port) || port < 1 || port > 65535) {
13031
- log38.error("Invalid port number", { port: opts.port });
13798
+ log41.error("Invalid port number", { port: opts.port });
13032
13799
  process.exitCode = 1;
13033
13800
  return;
13034
13801
  }
@@ -13046,7 +13813,7 @@ function initCommand() {
13046
13813
  out("\nPronto. Execute `mcp-graph serve` para iniciar o servidor.");
13047
13814
  }
13048
13815
  } catch (error) {
13049
- log38.error("Init failed", { error: getErrorMessage(error) });
13816
+ log41.error("Init failed", { error: getErrorMessage(error) });
13050
13817
  process.exitCode = 1;
13051
13818
  }
13052
13819
  });
@@ -13111,7 +13878,7 @@ function readDaemonMeta(stateDir) {
13111
13878
 
13112
13879
  // src/core/daemon/daemon-reaper.ts
13113
13880
  init_logger();
13114
- var log40 = createLogger({ layer: "core", source: "daemon-reaper" });
13881
+ var log43 = createLogger({ layer: "core", source: "daemon-reaper" });
13115
13882
  function defaultDaemonRoot(home = os.homedir()) {
13116
13883
  return path17__default.join(home, ".mcp-graph");
13117
13884
  }
@@ -13150,7 +13917,7 @@ function reapDaemons(options = {}) {
13150
13917
  try {
13151
13918
  kill(lock.pid);
13152
13919
  } catch (err) {
13153
- log40.debug("intentional-swallow", {
13920
+ log43.debug("intentional-swallow", {
13154
13921
  error: String(err),
13155
13922
  reason: "process vanished between liveness probe and signal \u2014 treat as already reaped"
13156
13923
  });
@@ -13180,7 +13947,7 @@ function reapDaemons(options = {}) {
13180
13947
  try {
13181
13948
  fs__default.rmSync(stateDir, { recursive: true, force: true });
13182
13949
  } catch (err) {
13183
- log40.debug("intentional-swallow", {
13950
+ log43.debug("intentional-swallow", {
13184
13951
  error: String(err),
13185
13952
  reason: "state dir removal hit a permission error or race \u2014 next reaper run retries"
13186
13953
  });
@@ -13200,14 +13967,14 @@ function reapDaemons(options = {}) {
13200
13967
 
13201
13968
  // src/cli/commands/daemon-cmd.ts
13202
13969
  init_logger();
13203
- var log41 = createLogger({ layer: "cli", source: "daemon.ts" });
13970
+ var log44 = createLogger({ layer: "cli", source: "daemon.ts" });
13204
13971
  function output12(msg) {
13205
13972
  process.stdout.write(msg + "\n");
13206
13973
  }
13207
13974
  function daemonCommand() {
13208
13975
  const cmd = new Command("daemon").description("Inspect and clean up mcp-graph daemons");
13209
13976
  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
- log41.info("cli:daemon:prune", { dryRun: opts.dryRun });
13977
+ log44.info("cli:daemon:prune", { dryRun: opts.dryRun });
13211
13978
  const report = reapDaemons({ dryRun: opts.dryRun });
13212
13979
  const prefix = opts.dryRun ? "[dry-run] " : "";
13213
13980
  for (const a of report.actions) {
@@ -13279,7 +14046,7 @@ function formatProviderReport(report) {
13279
14046
  // src/cli/commands/doctor-cmd.ts
13280
14047
  init_errors();
13281
14048
  init_logger();
13282
- var log42 = createLogger({ layer: "cli", source: "doctor.ts" });
14049
+ var log45 = createLogger({ layer: "cli", source: "doctor.ts" });
13283
14050
  function output13(msg) {
13284
14051
  process.stdout.write(msg + "\n");
13285
14052
  }
@@ -13334,7 +14101,7 @@ function doctorCommand() {
13334
14101
  process.exit(1);
13335
14102
  }
13336
14103
  } catch (err) {
13337
- log42.error(`Doctor failed: ${getErrorMessage(err)}`);
14104
+ log45.error(`Doctor failed: ${getErrorMessage(err)}`);
13338
14105
  process.exit(1);
13339
14106
  }
13340
14107
  });
@@ -13346,7 +14113,7 @@ init_esm_shims();
13346
14113
  // src/core/autonomy/shadow-branch.ts
13347
14114
  init_esm_shims();
13348
14115
  init_logger();
13349
- var log43 = createLogger({ layer: "core", source: "shadow-branch.ts" });
14116
+ var log46 = createLogger({ layer: "core", source: "shadow-branch.ts" });
13350
14117
  function parseShadowTimestamp(branchName) {
13351
14118
  const match = /-(\d{10,})$/.exec(branchName);
13352
14119
  if (!match) return null;
@@ -13388,7 +14155,7 @@ function pruneOrphanWorktrees(options) {
13388
14155
  ).toString();
13389
14156
  branches = out2.split("\n").map((s) => s.trim()).filter(Boolean);
13390
14157
  } catch (err) {
13391
- log43.debug("shadow-branch:prune:list-failed", { error: String(err) });
14158
+ log46.debug("shadow-branch:prune:list-failed", { error: String(err) });
13392
14159
  }
13393
14160
  const wtMap = branches.length > 0 ? listShadowWorktrees(execOpts) : /* @__PURE__ */ new Map();
13394
14161
  for (const branch of branches) {
@@ -13400,34 +14167,34 @@ function pruneOrphanWorktrees(options) {
13400
14167
  execSync(`git worktree remove --force --force ${wtPath}`, execOpts);
13401
14168
  reapedWorktrees += 1;
13402
14169
  } catch (err) {
13403
- log43.debug("shadow-branch:prune:wt-remove-failed", { branch, wtPath, error: String(err) });
14170
+ log46.debug("shadow-branch:prune:wt-remove-failed", { branch, wtPath, error: String(err) });
13404
14171
  }
13405
14172
  }
13406
14173
  try {
13407
14174
  execSync(`git branch -D ${branch}`, execOpts);
13408
14175
  reapedBranches += 1;
13409
14176
  } catch (err) {
13410
- log43.debug("shadow-branch:prune:branch-delete-failed", { branch, error: String(err) });
14177
+ log46.debug("shadow-branch:prune:branch-delete-failed", { branch, error: String(err) });
13411
14178
  }
13412
14179
  }
13413
14180
  try {
13414
- const output15 = execSync("git worktree prune --verbose", execOpts).toString();
14181
+ const output16 = execSync("git worktree prune --verbose", execOpts).toString();
13415
14182
  if (reapedBranches > 0 || reapedWorktrees > 0) {
13416
- log43.info("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, ttlMs });
14183
+ log46.info("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, ttlMs });
13417
14184
  } else {
13418
- log43.debug("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, output: output15 });
14185
+ log46.debug("shadow-branch:prune-ok", { reapedBranches, reapedWorktrees, output: output16 });
13419
14186
  }
13420
- return { pruned: true, reapedBranches, reapedWorktrees, output: output15 };
14187
+ return { pruned: true, reapedBranches, reapedWorktrees, output: output16 };
13421
14188
  } catch (err) {
13422
14189
  const error = String(err);
13423
- log43.debug("shadow-branch:prune-failed", { error });
14190
+ log46.debug("shadow-branch:prune-failed", { error });
13424
14191
  return { pruned: false, reapedBranches, reapedWorktrees, error };
13425
14192
  }
13426
14193
  }
13427
14194
 
13428
14195
  // src/cli/commands/gc-cmd.ts
13429
14196
  init_logger();
13430
- var log44 = createLogger({ layer: "cli", source: "gc.ts" });
14197
+ var log47 = createLogger({ layer: "cli", source: "gc.ts" });
13431
14198
  function output14(msg) {
13432
14199
  process.stdout.write(msg + "\n");
13433
14200
  }
@@ -13435,7 +14202,7 @@ function gcCommand() {
13435
14202
  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
14203
  const ttlMinutes = parseInt(opts.ttl, 10);
13437
14204
  const ttlMs = Number.isFinite(ttlMinutes) && ttlMinutes > 0 ? ttlMinutes * 60 * 1e3 : 0;
13438
- log44.info("cli:gc:start", { dir: opts.dir, ttlMs });
14205
+ log47.info("cli:gc:start", { dir: opts.dir, ttlMs });
13439
14206
  const result = pruneOrphanWorktrees({ cwd: opts.dir, ttlMs });
13440
14207
  if (result.pruned) {
13441
14208
  output14(`gc: reaped ${result.reapedBranches} branches, ${result.reapedWorktrees} worktrees`);
@@ -13446,6 +14213,48 @@ function gcCommand() {
13446
14213
  });
13447
14214
  }
13448
14215
 
14216
+ // src/cli/commands/skill-cmd.ts
14217
+ init_esm_shims();
14218
+ init_skill_registry();
14219
+ function output15(msg) {
14220
+ process.stdout.write(msg + "\n");
14221
+ }
14222
+ function skillCommand() {
14223
+ const cmd = new Command("skill").description("Lista e exibe skills (instru\xE7\xF5es para agentes)");
14224
+ 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) => {
14225
+ const seen = /* @__PURE__ */ new Set();
14226
+ let count = 0;
14227
+ for (const root of defaultSkillRoots(opts.dir)) {
14228
+ const { skills } = listSkills(root, opts.phase);
14229
+ for (const s of skills) {
14230
+ if (seen.has(s.name)) continue;
14231
+ seen.add(s.name);
14232
+ count += 1;
14233
+ output15(`${s.name.padEnd(28)} [${s.category}] ${s.description}`);
14234
+ }
14235
+ }
14236
+ if (count === 0) output15("Nenhuma skill encontrada.");
14237
+ else output15(`
14238
+ ${count} skill(s).`);
14239
+ });
14240
+ 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) => {
14241
+ for (const root of defaultSkillRoots(opts.dir)) {
14242
+ const found = invokeSkill(root, nome);
14243
+ if (found) {
14244
+ output15(`=== ${found.name} ===`);
14245
+ output15(`[${found.category}] ${found.description}`);
14246
+ if (found.phases.length > 0) output15(`fases: ${found.phases.join(", ")}`);
14247
+ output15("");
14248
+ output15(found.body);
14249
+ return;
14250
+ }
14251
+ }
14252
+ output15(`Skill n\xE3o encontrada: ${nome}. Tente 'skill list'.`);
14253
+ process.exitCode = 1;
14254
+ });
14255
+ return cmd;
14256
+ }
14257
+
13449
14258
  // src/cli/index.ts
13450
14259
  var program = new Command();
13451
14260
  program.name("agent-graph-flow").description(PROMISE).version(VERSION, "-v, --version");
@@ -13466,6 +14275,7 @@ program.addCommand(initCommand());
13466
14275
  program.addCommand(daemonCommand());
13467
14276
  program.addCommand(doctorCommand());
13468
14277
  program.addCommand(gcCommand());
14278
+ program.addCommand(skillCommand());
13469
14279
  function shouldLaunchTui() {
13470
14280
  const noArgs = process.argv.length <= 2;
13471
14281
  const isTty = Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);