@kodrunhq/opencode-autopilot 1.6.0 → 1.7.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kodrunhq/opencode-autopilot",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Curated agents, skills, and commands for the OpenCode AI coding CLI — autonomous orchestrator, multi-agent code review, model fallback, and in-session asset creation tools.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"keywords": [
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
import { getObservationsByProject, getProjectByPath } from "../memory/repository";
|
|
1
3
|
import { summarizeConfidence } from "./confidence";
|
|
2
4
|
import type { ConfidenceEntry } from "./types";
|
|
3
5
|
|
|
@@ -39,3 +41,32 @@ export function shouldTriggerExplorer(
|
|
|
39
41
|
const thresholdOrder = LEVEL_ORDER[threshold];
|
|
40
42
|
return entries.some((entry) => LEVEL_ORDER[entry.level] < thresholdOrder);
|
|
41
43
|
}
|
|
44
|
+
|
|
45
|
+
/** Minimum error observations to trigger deeper review. */
|
|
46
|
+
const ERROR_DEPTH_THRESHOLD = 3;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Memory-tuned debate depth: adjusts arena depth based on project error history.
|
|
50
|
+
* Scans the 50 most-recent observations (recency window) — older errors are not counted.
|
|
51
|
+
* Projects with 3+ error observations in the window get deeper review (+1, capped at 3).
|
|
52
|
+
* Best-effort: memory errors never affect pipeline (falls back to standard depth).
|
|
53
|
+
*/
|
|
54
|
+
export function getMemoryTunedDepth(
|
|
55
|
+
entries: readonly ConfidenceEntry[],
|
|
56
|
+
projectPath: string,
|
|
57
|
+
db?: Database,
|
|
58
|
+
): number {
|
|
59
|
+
const baseDepth = getDebateDepth(entries);
|
|
60
|
+
try {
|
|
61
|
+
const project = getProjectByPath(projectPath, db);
|
|
62
|
+
if (!project) return baseDepth;
|
|
63
|
+
const observations = getObservationsByProject(project.id, 50, db);
|
|
64
|
+
const errorCount = observations.filter((o) => o.type === "error").length;
|
|
65
|
+
if (errorCount >= ERROR_DEPTH_THRESHOLD) {
|
|
66
|
+
return Math.min(baseDepth + 1, 3);
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.warn("[opencode-autopilot] memory-tuned depth failed, using base:", err);
|
|
70
|
+
}
|
|
71
|
+
return baseDepth;
|
|
72
|
+
}
|
|
@@ -2,7 +2,7 @@ import { readdir } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { sanitizeTemplateContent } from "../../review/sanitize";
|
|
4
4
|
import { fileExists } from "../../utils/fs-helpers";
|
|
5
|
-
import {
|
|
5
|
+
import { getMemoryTunedDepth } from "../arena";
|
|
6
6
|
import { ensurePhaseDir, getArtifactRef, getPhaseDir } from "../artifacts";
|
|
7
7
|
import { filterByPhase } from "../confidence";
|
|
8
8
|
import type { PipelineState } from "../types";
|
|
@@ -62,7 +62,7 @@ export async function handleArchitect(
|
|
|
62
62
|
// Step 1: Dispatch architect(s) based on confidence depth
|
|
63
63
|
await ensurePhaseDir(artifactDir, "ARCHITECT");
|
|
64
64
|
const reconEntries = filterByPhase(state.confidence, "RECON");
|
|
65
|
-
const depth =
|
|
65
|
+
const depth = getMemoryTunedDepth(reconEntries, join(artifactDir, ".."));
|
|
66
66
|
const reconRef = getArtifactRef("RECON", "report.md");
|
|
67
67
|
const challengeRef = getArtifactRef("CHALLENGE", "brief.md");
|
|
68
68
|
const safeIdea = sanitizeTemplateContent(state.idea).replace(/[\r\n]+/g, " ");
|
|
@@ -82,9 +82,9 @@ export async function loadAdaptiveSkillContext(
|
|
|
82
82
|
|
|
83
83
|
const matchingSkills = filterSkillsByStack(allSkills, projectTags);
|
|
84
84
|
return buildMultiSkillContext(matchingSkills, tokenBudget);
|
|
85
|
-
} catch
|
|
86
|
-
// Best-effort
|
|
87
|
-
|
|
85
|
+
} catch {
|
|
86
|
+
// Best-effort: all errors return empty string. Caller (injectSkillContext)
|
|
87
|
+
// logs the error — no need to re-throw since the call site is also best-effort.
|
|
88
88
|
return "";
|
|
89
89
|
}
|
|
90
90
|
}
|
package/src/tools/orchestrate.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { DispatchResult } from "../orchestrator/handlers/types";
|
|
|
5
5
|
import { buildLessonContext } from "../orchestrator/lesson-injection";
|
|
6
6
|
import { loadLessonMemory } from "../orchestrator/lesson-memory";
|
|
7
7
|
import { completePhase, getNextPhase } from "../orchestrator/phase";
|
|
8
|
-
import {
|
|
8
|
+
import { loadAdaptiveSkillContext } from "../orchestrator/skill-injection";
|
|
9
9
|
import { createInitialState, loadState, patchState, saveState } from "../orchestrator/state";
|
|
10
10
|
import type { Phase } from "../orchestrator/types";
|
|
11
11
|
import { isEnoentError } from "../utils/fs-helpers";
|
|
@@ -96,17 +96,16 @@ async function injectLessonContext(
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
* Attempt to inject
|
|
99
|
+
* Attempt to inject stack-filtered adaptive skill context into a dispatch prompt.
|
|
100
100
|
* Best-effort: failures are silently swallowed to avoid breaking dispatch.
|
|
101
101
|
*/
|
|
102
|
-
async function injectSkillContext(prompt: string): Promise<string> {
|
|
102
|
+
async function injectSkillContext(prompt: string, projectRoot?: string): Promise<string> {
|
|
103
103
|
try {
|
|
104
104
|
const baseDir = getGlobalConfigDir();
|
|
105
|
-
const
|
|
106
|
-
const ctx = buildSkillContext(content);
|
|
105
|
+
const ctx = await loadAdaptiveSkillContext(baseDir, projectRoot ?? process.cwd());
|
|
107
106
|
if (ctx) return prompt + ctx;
|
|
108
|
-
} catch {
|
|
109
|
-
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.warn("[opencode-autopilot] skill injection failed:", err);
|
|
110
109
|
}
|
|
111
110
|
return prompt;
|
|
112
111
|
}
|
|
@@ -146,7 +145,7 @@ async function processHandlerResult(
|
|
|
146
145
|
handlerResult.phase,
|
|
147
146
|
artifactDir,
|
|
148
147
|
);
|
|
149
|
-
const withSkills = await injectSkillContext(enrichedPrompt);
|
|
148
|
+
const withSkills = await injectSkillContext(enrichedPrompt, join(artifactDir, ".."));
|
|
150
149
|
if (withSkills !== handlerResult.prompt) {
|
|
151
150
|
return JSON.stringify({ ...handlerResult, prompt: withSkills });
|
|
152
151
|
}
|
|
@@ -163,7 +162,7 @@ async function processHandlerResult(
|
|
|
163
162
|
handlerResult.phase as string,
|
|
164
163
|
artifactDir,
|
|
165
164
|
);
|
|
166
|
-
const skillSuffix = await injectSkillContext("");
|
|
165
|
+
const skillSuffix = await injectSkillContext("", join(artifactDir, ".."));
|
|
167
166
|
const combinedSuffix = lessonSuffix + (skillSuffix || "");
|
|
168
167
|
if (combinedSuffix) {
|
|
169
168
|
const enrichedAgents = handlerResult.agents.map((entry) => ({
|