refactor: consolidate DB-fallback inline functions in auto-prompts (#1276)

* refactor: consolidate DB-fallback inline functions in auto-prompts

Extract shared inlineFromDbOrFile() helper that encapsulates the
repeated pattern of checking DB availability, dynamically importing
context-store, running a query, formatting results, and falling back
to the filesystem. The three public functions (inlineDecisionsFromDb,
inlineRequirementsFromDb, inlineProjectFromDb) become thin wrappers
that pass only the differing query/format logic as a callback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update source-level test to match refactored DB-fallback function name

The context-compression test greps auto-prompts.ts source for
`inlineGsdRootFile(base, "project.md"` which was replaced by
`inlineProjectFromDb(base)` in the consolidation refactor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
TÂCHES 2026-03-18 19:11:01 -06:00 committed by GitHub
parent 8f06a14fb6
commit 922826ba8a
2 changed files with 50 additions and 48 deletions

View file

@ -188,6 +188,38 @@ export async function inlineGsdRootFile(
// ─── DB-Aware Inline Helpers ──────────────────────────────────────────────
/**
* Shared DB-fallback pattern: attempt a DB query via the context-store, format
* the result, and fall back to the filesystem file when the DB is unavailable
* or the query yields no results.
*
* @param base Project root for filesystem fallback
* @param label Section heading (e.g. "Decisions")
* @param filename Filesystem fallback file (e.g. "decisions.md")
* @param queryDb Async callback receiving the dynamically-imported
* context-store module. Returns formatted markdown or null.
*/
async function inlineFromDbOrFile(
base: string,
label: string,
filename: string,
queryDb: (cs: typeof import("./context-store.js")) => string | null,
): Promise<string | null> {
try {
const { isDbAvailable } = await import("./gsd-db.js");
if (isDbAvailable()) {
const contextStore = await import("./context-store.js");
const content = queryDb(contextStore);
if (content) {
return `### ${label}\nSource: \`.gsd/${filename.toUpperCase().replace(/\.MD$/i, "")}.md\`\n\n${content}`;
}
}
} catch {
// DB not available — fall through to filesystem
}
return inlineGsdRootFile(base, filename, label);
}
/**
* Inline decisions with optional milestone scoping from the DB.
* Falls back to filesystem via inlineGsdRootFile when DB unavailable or empty.
@ -196,23 +228,13 @@ export async function inlineDecisionsFromDb(
base: string, milestoneId?: string, scope?: string, level?: InlineLevel,
): Promise<string | null> {
const inlineLevel = level ?? resolveInlineLevel();
try {
const { isDbAvailable } = await import("./gsd-db.js");
if (isDbAvailable()) {
const { queryDecisions, formatDecisionsForPrompt } = await import("./context-store.js");
const decisions = queryDecisions({ milestoneId, scope });
if (decisions.length > 0) {
// Use compact format for non-full levels to save ~35% tokens
const formatted = inlineLevel !== "full"
? formatDecisionsCompact(decisions)
: formatDecisionsForPrompt(decisions);
return `### Decisions\nSource: \`.gsd/DECISIONS.md\`\n\n${formatted}`;
}
}
} catch {
// DB not available — fall through to filesystem
}
return inlineGsdRootFile(base, "decisions.md", "Decisions");
return inlineFromDbOrFile(base, "Decisions", "decisions.md", (cs) => {
const decisions = cs.queryDecisions({ milestoneId, scope });
if (decisions.length === 0) return null;
return inlineLevel !== "full"
? formatDecisionsCompact(decisions)
: cs.formatDecisionsForPrompt(decisions);
});
}
/**
@ -223,23 +245,13 @@ export async function inlineRequirementsFromDb(
base: string, sliceId?: string, level?: InlineLevel,
): Promise<string | null> {
const inlineLevel = level ?? resolveInlineLevel();
try {
const { isDbAvailable } = await import("./gsd-db.js");
if (isDbAvailable()) {
const { queryRequirements, formatRequirementsForPrompt } = await import("./context-store.js");
const requirements = queryRequirements({ sliceId });
if (requirements.length > 0) {
// Use compact format for non-full levels to save ~40% tokens
const formatted = inlineLevel !== "full"
? formatRequirementsCompact(requirements)
: formatRequirementsForPrompt(requirements);
return `### Requirements\nSource: \`.gsd/REQUIREMENTS.md\`\n\n${formatted}`;
}
}
} catch {
// DB not available — fall through to filesystem
}
return inlineGsdRootFile(base, "requirements.md", "Requirements");
return inlineFromDbOrFile(base, "Requirements", "requirements.md", (cs) => {
const requirements = cs.queryRequirements({ sliceId });
if (requirements.length === 0) return null;
return inlineLevel !== "full"
? formatRequirementsCompact(requirements)
: cs.formatRequirementsForPrompt(requirements);
});
}
/**
@ -249,19 +261,9 @@ export async function inlineRequirementsFromDb(
export async function inlineProjectFromDb(
base: string,
): Promise<string | null> {
try {
const { isDbAvailable } = await import("./gsd-db.js");
if (isDbAvailable()) {
const { queryProject } = await import("./context-store.js");
const content = queryProject();
if (content) {
return `### Project\nSource: \`.gsd/PROJECT.md\`\n\n${content}`;
}
}
} catch {
// DB not available — fall through to filesystem
}
return inlineGsdRootFile(base, "project.md", "Project");
return inlineFromDbOrFile(base, "Project", "project.md", (cs) => {
return cs.queryProject();
});
}
// ─── Skill Discovery ──────────────────────────────────────────────────────

View file

@ -91,7 +91,7 @@ test("compression: buildPlanMilestonePrompt minimal drops project/requirements/d
// The plan-milestone builder should gate root file inlining on inlineLevel
assert.ok(
promptsSrc.includes('inlineLevel !== "minimal"') &&
promptsSrc.includes('inlineGsdRootFile(base, "project.md"'),
promptsSrc.includes("inlineProjectFromDb(base)"),
"plan-milestone should conditionally include project.md based on level",
);
});