paqad-ai
Version:
Spec-driven development framework — AI agents that think before they type
43,247 lines • 1.53 MB
JavaScript
import { createRequire as __paqadCreateRequire } from 'module'; const require = __paqadCreateRequire(import.meta.url);
import {
AcTestMappingGate,
FIX_PROOF_STATE_LABEL,
GATE_CATALOG,
GATE_STATE_LABEL,
HEURISTIC_BAND_FLOOR,
LANE_RECORD_GAP,
VERIFICATION_EVIDENCE_RELATIVE_PATH,
VERIFICATION_GATES,
buildAndWriteChangeTraceabilityMap,
buildBundleCompletenessConfig,
buildVerificationEvidence,
checkBooleanGate,
checkJudgedGate,
createDidNotRun,
createFail,
createInconclusive,
createNotRequired,
createPass,
extractImportSpecifiers,
foldFixProofState,
formatStageIsolationLine,
gateOwner,
gradeGateResult,
hasStageAgentEvidence,
hasStageAgentEvidenceSince,
isBackstopVerificationOrigin,
readChecksReport,
readFeatureChecks,
readFeatureTechDebtIndex,
readFixProofRows,
readRuleOverrides,
readTraceabilityMap,
recordGapText,
resolveDuplicationConfig,
resolveDuplicationMode,
resolveEnterprisePolicy,
scanImports,
summarizeStageIsolation,
unrecordedStagesGap,
verdictKindFor,
verdictParts,
writeChecksReport,
writeFeatureChecks,
writeFeatureTechDebtIndex,
writeVerificationEvidence,
writesLedger
} from "./chunk-E5BR2SQP.js";
import {
DSSE_PAYLOAD_TYPE,
ZERO_DIGEST,
computeChangeSubjectDigest,
computeFileDigests,
decodeReceiptStatement,
latestFeatureReceipt,
pae,
projectFeatureReceipt,
splitReceiptEvidenceRows
} from "./chunk-4GDYY56G.js";
import {
StackIntrospector,
createDefaultEcosystemParserRegistry,
detectEnvironmentTraits,
prefixRepositoryPath
} from "./chunk-URTQMBPY.js";
import {
estimateTokens
} from "./chunk-F657QMM6.js";
import {
MANAGED_HEADER
} from "./chunk-XVGJKRBZ.js";
import {
bundleLedgerEra,
stageLedgerEra
} from "./chunk-WKGFBXSZ.js";
import {
missingTeamConfigFiles,
missingTeamFileLine,
unknownSettingLine,
unknownTeamConfigSettings
} from "./chunk-XKSEMNPB.js";
import {
getOrLoad
} from "./chunk-XEROU3PT.js";
import {
deriveHealthTier,
queryPatterns,
readAllModuleHealth,
recordFindings,
syncModuleHealth,
syncModuleHealthFromVerification,
writeModuleHealthProfile
} from "./chunk-T7QKKKPS.js";
import {
AstChunker,
ChunkIndexManager,
EmbeddingProviderError,
FileVectorIndex,
RagService,
appendRagAudit,
createEmbeddingProvider,
createReranker
} from "./chunk-YAYHLNWR.js";
import {
liveChecksRunningMarker
} from "./chunk-FVFH4UAE.js";
import {
PAQAD_STATUS_GLYPH,
PAQAD_STATUS_LABEL,
PAQAD_TERM_TRANSLATIONS,
PAQAD_VERDICT,
paqadFrameLead,
paqadGlyphLegend
} from "./chunk-VZJTQQG2.js";
import {
describeOptionalEngine,
engineInstallNetworkHint,
maybeStartOptionalEngineInstall
} from "./chunk-GVVZTJJR.js";
import {
compileRuleScripts,
dropRuleScriptMapSources,
isRuleScriptMapCurrent,
isRuleScriptMapStale,
readDrift
} from "./chunk-YME53X5M.js";
import {
AGENT_RECORD_WRITER,
COMPLIANCE_SCHEMA_VERSION,
DEFAULT_OBLIGATION_INDEX_PATH,
PACK_REGISTRY_FAULT_REMEDIATION,
SKILL_RECORD_WRITER,
SPEC_PIPELINE_STAGING_DIR,
SPEC_REVIEW_SCHEMA_VERSION,
agentOrchestratorEnabled,
agentRecordFilename,
appendSpecCorrectionRow,
appendSpecStepRow,
applyResolvedDecisions,
armDecisionFromDuplicationFinding,
authoringConfigProblems,
buildFeatureSpec,
changeIsFeatureDev,
changePastSpecification,
classifyCompletionEnforcement,
compileFailureReason,
coverageGaps,
designSignOffApplies,
ensureCompiledRulesCurrent,
findVisualEvidenceWaiver,
frontendTriggerOrFault,
isFrameworkDisabledForRoot,
isFrameworkEnabled,
isFrameworkEnabledForRoot,
loadDesignSignOff,
packRegistryFaultDetail,
planExpertSlices,
readAgentRecord,
readAuthoringConfig,
readCanonicalSiteMap,
readCodeKnowledgeIndex,
readFeaturePlan,
readFeatureReview,
readFeatureSpecification,
readRulesLoaded,
readSkillRecord,
readStagedText,
resolveRuleApplicabilityForChange,
resolveRuleComplianceMode,
resolveStagesMode,
reuseCounts,
skillOrchestratorEnabled,
skillRecordFilename,
specReviewPath,
validateCodeKnowledgeIndex,
visualEvidenceReadiness,
visualEvidenceWaiverHint,
writeCodeKnowledgeIndex,
writeExpertNotes,
writeExpertRoster,
writeExpertSynthesis,
writeLabel,
writeQuestions,
writeRequest,
writeRuleContext,
writeStagedText
} from "./chunk-3AKVAXRJ.js";
import {
AdapterFactory,
ClaudeCodeAdapter,
OPEN_STANDARD_SKILLS_ROOT,
PLUGIN_MARKETPLACE_KEY,
PLUGIN_MARKETPLACE_REPO,
RECIPE_NAMES,
SKILL_FILE,
TemplateEngine,
agentNameOf,
agentRoots,
buildFrameworkFallbackClause,
deriveRecordedProviders,
enabledAdapters,
hashAgentFile,
hashAgentText,
hashFolder,
isGeneratedProjectStageAgent,
isGeneratedRecipeFolder,
isMissingPathError,
isPaqadRepository,
listFolderFiles,
pluginSettingsKeys,
readRegularFile,
readSkillPathContext,
readTextIfPresent,
recipeHasScript,
recipeRepairAdvice,
recipeRoot,
resolveAiAttributionMode,
resolveFlooredMode,
runningVersionHealth,
skillFolderOf,
skillRoots,
writeStageAgents
} from "./chunk-KXN6TRQP.js";
import {
digestFile,
subtractUnchangedBaselineFiles
} from "./chunk-Z4GLUCC5.js";
import {
RECEIPT_NOT_POSTED_LINE,
RECEIPT_NOT_WRITTEN_LINE,
RECEIPT_OFF_LINE,
RECEIPT_POSTED_LINE,
prSignedOffLine,
prSkippedLine,
readHld,
receiptSignedOffLine,
receiptSkippedLine
} from "./chunk-LGAFOBYN.js";
import {
StackSnapshotCache
} from "./chunk-WRHJCBRI.js";
import {
readExistingOnboardingManifest,
readFrameworkVersion,
resolveFrameworkInstallPath,
sanitizeStackSnapshotRepository,
writeDetectionReport,
writeFrameworkMetadata,
writeFrameworkVersionPreservingTimestamp,
writeOnboardingManifest,
writeProjectProfile
} from "./chunk-73AIVIC6.js";
import {
DEFAULT_CONTEXT_BUDGET,
DEFAULT_STANDING_EXPERTS,
EXPERT_ROLES,
ROLE_TOKEN_BUDGETS,
isExpertRole,
resolveContextBudgetForModelTier
} from "./chunk-IKAOR4NY.js";
import {
ADAPTER_TYPES
} from "./chunk-BKNKG26S.js";
import {
compileRules,
isCompiledRulesStale,
readCompiledRules,
writeCompiledRules
} from "./chunk-7Q65STES.js";
import {
StackPackLoader,
emitSkillAuditEvent,
getPackTestRunners,
getPacksForFrameworks,
getSharedSkillAuditBuffer,
parseCommandChain,
recordSkillMetadataDeprecation,
resolvePackManagerRoots,
runCommandChain
} from "./chunk-K4E6ACLH.js";
import {
DECISION_REUSE_DOC_TYPE,
DecisionStore,
createPendingDecision,
jaccard,
mintDecisionId,
readContractDecisions,
shingles,
tokenizeCode
} from "./chunk-4ZAWKFXT.js";
import {
appendHooksLog
} from "./chunk-4S3XFJAH.js";
import {
buildDetectedStackProfile,
compareStackProfiles,
getLegacyCapabilities,
getPrimaryStack,
summarizeStack
} from "./chunk-HNYZUZ7D.js";
import {
CAPABILITIES,
DOMAINS,
DOMAIN_STACK_MAP,
STACKS,
STACK_CAPABILITIES_MAP,
getProfileDomain,
readProjectProfile
} from "./chunk-AK3HYELM.js";
import {
DECISION_CATEGORY_DEFAULTS,
isStrictDecisionId
} from "./chunk-6XDDIYNJ.js";
import {
DISCOVERY_CLASH_MESSAGE,
PLUGIN_ID,
classifyFrameworkCopy,
describeFrameworkLink,
discoveryPluginClash,
isPluginInstalled,
pluginLoadState,
pluginOptedOutLocally,
projectTurnsPluginOn,
readPackageVersion,
readRuntimeCopyVersion
} from "./chunk-THDANA7U.js";
import {
readReport,
ruleRunFindings
} from "./chunk-SS625UO5.js";
import {
DEFAULT_IGNORE_GLOBS,
scanWorkingTree
} from "./chunk-LBNBI3D6.js";
import {
appendChangeMetrics,
appendDuplicationRun,
appendFeatureEvidenceRows,
appendRuleRun,
readChangeMetrics,
readDuplication,
readRuleRun
} from "./chunk-5ETIY5I3.js";
import {
buildEvidenceRow,
readEvidenceRowsAt
} from "./chunk-UUBQQJVE.js";
import {
activeChangeFiles,
detectStaleDocTargets,
isCodeFile,
isDocumentationFile,
isTestFile,
loadChangeEvidence,
readGitStatusFiles
} from "./chunk-EQYAXXZO.js";
import {
execa,
onExit
} from "./chunk-MDXUST3Z.js";
import {
STAGE_NARRATION
} from "./chunk-22I2D24D.js";
import {
BUNDLE_MANIFEST,
FAST_LANE_REFREEZE_HINT,
extractAssistantText,
isBundleFileRequired,
isSpecFrozenOnFastLane,
routeIsAffirmativelyNonFeature,
specPipelineStrictApplies,
strayBundleFiles,
validateBundleFileContent,
validateSpecificationAdoption
} from "./chunk-OAEANL22.js";
import {
endStage,
openStageEvidence,
resolveEffectiveLane,
stageIsOpen,
stagesWithKind
} from "./chunk-7D5MLTG3.js";
import {
appendModuleMapEvent,
appendRunCancelledEvent,
emitContextTruncated,
matchesAnyGlob,
readRawModuleMap
} from "./chunk-Y3O45QYV.js";
import {
require_out
} from "./chunk-P4RPU2KB.js";
import {
toPosixPath
} from "./chunk-LYNDVGNE.js";
import {
PINNED_DIFF_ARGS,
appendFeatureStageRow,
closeActiveFeature,
currentFeature,
documentSessionId,
foldFeature,
isPaqadArtifactPath,
peekActiveChangeKey,
readChangeStartPoint,
readFeatureDelivery,
readFeatureIndexEntries,
readFeatureStageUnit,
reconcileDeliveryFromGit,
recordedLaneOrFull,
resolveFeatureRef,
writeFeatureIndexDocument
} from "./chunk-5M55PDWL.js";
import {
AGENT_ATTACHED_JOURNEY,
BACKSTOP_WRITER,
RECIPE_INJECTED_KIND,
RECORD_REPAIR_KIND,
SKILL_USED_KIND,
SPEC_CORRECTION_KIND,
SPEC_STEP_OUTCOMES,
STAGE_AGENT_KIND,
STAGE_EVIDENCE_STAGES,
agentForWriter,
featureRecordIsUntitled,
isBundleMaterialized,
isFeatureFinished,
isKnownStage,
isMandatoryStage,
listFeatureDirs,
listInFlightFeatures,
liveStageAgents,
readChangeConstants,
readFeatureRecord,
seedFeatureRecord,
sessionClosedAnyFeature,
startedAfterLastEnd,
validateVisualEvidenceRecord
} from "./chunk-7TBVBCDH.js";
import {
buildTextHeader,
documentHashMatches,
renderFrontMatter,
renderHeaderScript,
rowHashMatches,
rowRecordedAt,
sha256Hex,
splitFrontMatter,
textHashMatches
} from "./chunk-RJMJYPHL.js";
import {
CLASSIFICATION_WORKFLOWS,
CLAUDE_CODE_AGENT_FIELDS,
DESCRIPTION_MAX_CHARS,
MANDATORY_STAGE_AGENTS,
STAGE_AGENT_STAGES,
SkillFrontmatterParser,
allowedSkillFields,
defaultFeatureDevelopmentPolicy,
descriptionLength,
detectAnalyticsProvider,
extractCallSites,
findProvider,
isClaudeModel,
isObjectRoleName,
skillDeclaresRequestRouting,
splitSkillFrontmatter,
toLoadedSkill
} from "./chunk-NCYDV2N5.js";
import {
CancelledError,
FrameworkError,
SCHEMA_VERSION_UPDATE_HINT,
SchemaVersionError,
SkillRegistrationError,
ValidationError,
engineLog,
getSecretPermissionWarning,
isCancelledError,
redactSecrets,
setEngineLogger
} from "./chunk-D6VEUSB6.js";
import {
readGitState
} from "./chunk-BOEVU2BD.js";
import {
CONFIG_GROUP_FILES,
DEFAULT_BENCHMARK_GATES,
DEFAULT_FRAMEWORK_CONFIG,
FRAMEWORK_CONFIG_SPECS,
GIT_WORKFLOW_COMMITS_FILE,
GIT_WORKFLOW_FILES,
LEGACY_SCHEMA_LINE_PREFIX,
MIGRATED_STUB_MARKER,
RETIRED_SAFETY_FILE,
STAGE_SETTING_STAGES,
SchemaValidator,
TEAM_CONFIG_FILES,
WORKFLOW_POLICY_STAGES,
changedOutside,
checkYamlValue,
checkoutIsNewer,
defaultIntelligenceConfig,
detectFlippedFrameworkValues,
embedRuleMarker,
envConfigValue,
getDefaultEmbeddingModel,
gitWorkflowDir,
gitWorkflowFilePath,
insertKey,
isMigratedStub,
isMissingFileError,
isRetiredSettingKey,
isShippedWorkflowEntry,
lastAppliedPath,
layeredConfigMap,
legacyFilesWithSettings,
legacyShouldMoveLine,
loadGitWorkflow,
normalizeIntelligenceConfig,
parseDotConfig,
parseRuleMarker,
parseTeamConfigText,
readConfigsDir,
readDotConfig,
readLastApplied,
readTeamConfig,
readTextIfExistsSync,
reconcileConfigOverrides,
refreshLastAppliedHashes,
releasedAfterLegacyWindow,
renderTeamConfigFile,
require_dist,
resolveFrameworkConfig,
resolveNumericConfig,
resolvePluginMigrationConfig,
resolveSpecPipelineSwitches,
resolveTeamBootstrapEnabled,
retiredSettingLine,
setConfigValue,
setTeamConfigValue,
setValue,
sha256,
shippedRuleLineStart,
stampLastApplied,
stripRuleMarker,
syncTeamConfigFiles,
teamConfigPath,
toYamlValue,
versionAtLeast,
writeConfigExample,
writeConfigsReadme,
writeFrameworkOverridesToConfig,
yamlDefault
} from "./chunk-ACJQW7SB.js";
import {
DEFAULT_BASE_BRANCH,
DEFAULT_TRACKER_PATTERNS,
TEAM_FILE_SCHEMA_VERSION,
isHigherStamp,
isNewerTeamFile,
newerTeamFileLine,
removeAiAttributionComment,
renderDefaultGitWorkflowFile,
renderWriteBlock,
swapTeamFileStamp
} from "./chunk-YA6SCYMC.js";
import {
renameWithRetrySync
} from "./chunk-Z3NGWHFX.js";
import {
getPackageRoot,
getRuntimeRoot,
getRuntimeTemplatesRoot
} from "./chunk-YWAORJG6.js";
import {
currentOrdinal,
openSessionDoc,
readSessionDoc,
readUnitFile
} from "./chunk-Q353EDKY.js";
import {
resolveSessionId
} from "./chunk-SG6LXLDH.js";
import {
readSessionControl
} from "./chunk-FMQ5YRSP.js";
import {
DECISIONS_DOC_TYPE,
FEATURE_BUNDLE_FILES,
FEATURE_DOC_SCHEMA_VERSION,
SPEC_SOURCE_DOC_TYPE,
basename,
chatRagPath,
dirname,
extname,
featureChangeKey,
featureDir,
featureFilePath,
featureLegacySpecMarkdownPath,
featureReportPath,
isFeatureDirName,
join,
parseFeatureDirName,
relative,
slugifyAscii,
trimChar,
trimTrailingChar
} from "./chunk-AZLA53A6.js";
import {
PATHS,
REGISTRIES
} from "./chunk-IHMBVS6H.js";
import {
__commonJS,
__require,
__toESM,
init_esm_shims
} from "./chunk-IDFRWBMN.js";
// node_modules/.pnpm/cli-width@4.1.0/node_modules/cli-width/index.js
var require_cli_width = __commonJS({
"node_modules/.pnpm/cli-width@4.1.0/node_modules/cli-width/index.js"(exports, module) {
"use strict";
init_esm_shims();
module.exports = cliWidth2;
function normalizeOpts(options) {
const defaultOpts = {
defaultWidth: 0,
output: process.stdout,
tty: __require("tty")
};
if (!options) {
return defaultOpts;
}
Object.keys(defaultOpts).forEach(function(key) {
if (!options[key]) {
options[key] = defaultOpts[key];
}
});
return options;
}
function cliWidth2(options) {
const opts = normalizeOpts(options);
if (opts.output.getWindowSize) {
return opts.output.getWindowSize()[0] || opts.defaultWidth;
}
if (opts.tty.getWindowSize) {
return opts.tty.getWindowSize()[1] || opts.defaultWidth;
}
if (opts.output.columns) {
return opts.output.columns;
}
if (process.env.CLI_WIDTH) {
const width = parseInt(process.env.CLI_WIDTH, 10);
if (!isNaN(width) && width !== 0) {
return width;
}
}
return opts.defaultWidth;
}
}
});
// node_modules/.pnpm/mute-stream@3.0.0/node_modules/mute-stream/lib/index.js
var require_lib = __commonJS({
"node_modules/.pnpm/mute-stream@3.0.0/node_modules/mute-stream/lib/index.js"(exports, module) {
"use strict";
init_esm_shims();
var Stream = __require("stream");
var MuteStream2 = class extends Stream {
#isTTY = null;
constructor(opts = {}) {
super(opts);
this.writable = this.readable = true;
this.muted = false;
this.on("pipe", this._onpipe);
this.replace = opts.replace;
this._prompt = opts.prompt || null;
this._hadControl = false;
}
#destSrc(key, def) {
if (this._dest) {
return this._dest[key];
}
if (this._src) {
return this._src[key];
}
return def;
}
#proxy(method, ...args) {
if (typeof this._dest?.[method] === "function") {
this._dest[method](...args);
}
if (typeof this._src?.[method] === "function") {
this._src[method](...args);
}
}
get isTTY() {
if (this.#isTTY !== null) {
return this.#isTTY;
}
return this.#destSrc("isTTY", false);
}
// basically just get replace the getter/setter with a regular value
set isTTY(val) {
this.#isTTY = val;
}
get rows() {
return this.#destSrc("rows");
}
get columns() {
return this.#destSrc("columns");
}
mute() {
this.muted = true;
}
unmute() {
this.muted = false;
}
_onpipe(src) {
this._src = src;
}
pipe(dest, options) {
this._dest = dest;
return super.pipe(dest, options);
}
pause() {
if (this._src) {
return this._src.pause();
}
}
resume() {
if (this._src) {
return this._src.resume();
}
}
write(c) {
if (this.muted) {
if (!this.replace) {
return true;
}
if (c.match(/^\u001b/)) {
if (c.indexOf(this._prompt) === 0) {
c = c.slice(this._prompt.length);
c = c.replace(/./g, this.replace);
c = this._prompt + c;
}
this._hadControl = true;
return this.emit("data", c);
} else {
if (this._prompt && this._hadControl && c.indexOf(this._prompt) === 0) {
this._hadControl = false;
this.emit("data", this._prompt);
c = c.slice(this._prompt.length);
}
c = c.toString().replace(/./g, this.replace);
}
}
this.emit("data", c);
}
end(c) {
if (this.muted) {
if (c && this.replace) {
c = c.toString().replace(/./g, this.replace);
} else {
c = null;
}
}
if (c) {
this.emit("data", c);
}
this.emit("end");
}
destroy(...args) {
return this.#proxy("destroy", ...args);
}
destroySoon(...args) {
return this.#proxy("destroySoon", ...args);
}
close(...args) {
return this.#proxy("close", ...args);
}
};
module.exports = MuteStream2;
}
});
// src/index.ts
init_esm_shims();
// src/adapters/index.ts
init_esm_shims();
// src/adapters/adapter.interface.ts
init_esm_shims();
// src/analytics/index.ts
init_esm_shims();
// src/analytics/conflicts.ts
init_esm_shims();
var ANALYTICS_CONFLICTS = {
provider_version_mismatch: {
category: "analytics.provider_version_mismatch",
title: "I'm not sure which analytics tool (or version) this project uses \u2014 which is right?"
},
taxonomy_violation: {
category: "analytics.taxonomy_violation",
title: "This event name breaks your existing naming convention \u2014 keep mine or rename?"
},
pii_consent: {
category: "analytics.pii_consent",
title: "This property looks like personal data \u2014 I won't auto-track it. Track it anyway?"
},
no_provider_flag: {
category: "analytics.no_provider_flag",
title: "Analytics is on but no provider is wired up \u2014 want me to set one up, or stay dormant?"
},
architecture_conflict: {
category: "analytics.architecture_conflict",
title: "Your module docs say tracking belongs elsewhere than this change \u2014 where should it go?"
}
};
function conflictCategory(kind) {
return ANALYTICS_CONFLICTS[kind].category;
}
// src/analytics/doc-tree.ts
init_esm_shims();
import { mkdir, readFile, writeFile } from "fs/promises";
import { dirname as dirname2, join as join2, posix } from "path";
function analyticsFeatureDir(module, feature) {
return posix.join("docs", "modules", module, "analytics", feature);
}
function analyticsIndexPath(module) {
return posix.join("docs", "modules", module, "analytics", "index.md");
}
function normalizeEventSlug(eventName) {
return eventName.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-/, "").replace(/-$/, "");
}
function analyticsEventDocPath(module, feature, eventName) {
return posix.join(analyticsFeatureDir(module, feature), `${normalizeEventSlug(eventName)}.md`);
}
function groupBySlug(callSites) {
const bySlug = /* @__PURE__ */ new Map();
for (const site of callSites) {
const slug = normalizeEventSlug(site.eventName);
if (slug === "") continue;
const entry = bySlug.get(slug) ?? { variants: /* @__PURE__ */ new Set(), providers: /* @__PURE__ */ new Set() };
entry.variants.add(site.eventName);
entry.providers.add(site.provider);
bySlug.set(slug, entry);
}
return [...bySlug.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([slug, entry]) => ({
slug,
variants: [...entry.variants].sort(),
providers: [...entry.providers].sort()
}));
}
function providerDisplay(id) {
return findProvider(id)?.displayName ?? id;
}
function buildEventDoc(input) {
const { module, feature, group } = input;
const canonical = group.variants[0];
const conflictNote = group.variants.length > 1 ? `
> \u26A0\uFE0F Casing conflict \u2014 these spellings collapse to one event and must be reconciled to a single string: ${group.variants.map((v) => `\`${v}\``).join(", ")}.
` : "";
const providerSections = group.providers.map(
(id) => `### ${providerDisplay(id)}
Fired via ${providerDisplay(id)} (\`${id}\`). Event string: \`${canonical}\`.
`
).join("\n");
return `# Event: \`${canonical}\`
${conflictNote}
- Module: \`${module}\`
- Feature: \`${feature}\`
- Slug: \`${group.slug}\`
## What it means
_Describe when this event fires and why it exists (the business question it answers)._
## Providers
${providerSections}
## Properties
_Document the event's properties and their types._
## PII / consent
_Does this event or any property carry personal data? If so, it must pass an
\`analytics.pii_consent\` decision. This is review-time governance, not redaction at capture._
`;
}
function buildAnalyticsIndex(input) {
const { module, entries } = input;
const rows = entries.length === 0 ? "_No analytics events documented for this module yet._" : entries.slice().sort(
(a, b) => a.feature.localeCompare(b.feature) || a.group.slug.localeCompare(b.group.slug)
).map(({ feature, group }) => {
const rel = `${feature}/${group.slug}.md`;
return `| \`${group.variants[0]}\` | \`${feature}\` | ${group.providers.map((p) => providerDisplay(p)).join(", ")} | [doc](${rel}) |`;
}).join("\n");
return `# Analytics events \u2014 \`${module}\`
The tracking plan for this module. Each row is one event with its own reviewed, versioned doc.
Read this before adding a new event so you reuse an existing one rather than coining a duplicate.
| Event | Feature | Providers | Doc |
| --- | --- | --- | --- |
${rows}
`;
}
async function syncAnalyticsDocs(projectRoot, entries) {
const result2 = { written: [], skipped: [], conflicts: [] };
const indexByModule = /* @__PURE__ */ new Map();
for (const entry of entries) {
for (const group of groupBySlug(entry.callSites)) {
const rel = posix.join(analyticsFeatureDir(entry.module, entry.feature), `${group.slug}.md`);
await writeIfChanged(projectRoot, rel, buildEventDoc({ ...entry, group }), result2);
if (group.variants.length > 1) {
result2.conflicts.push({ path: rel, variants: group.variants });
}
const bucket = indexByModule.get(entry.module) ?? [];
bucket.push({ feature: entry.feature, group });
indexByModule.set(entry.module, bucket);
}
}
for (const [module, indexEntries] of indexByModule) {
const rel = analyticsIndexPath(module);
await writeIfChanged(
projectRoot,
rel,
buildAnalyticsIndex({ module, entries: indexEntries }),
result2
);
}
return result2;
}
async function writeIfChanged(projectRoot, relPath, content, result2) {
const abs = join2(projectRoot, relPath);
let existing;
try {
existing = await readFile(abs, "utf8");
} catch {
existing = null;
}
if (existing === content) {
result2.skipped.push(relPath);
return;
}
await mkdir(dirname2(abs), { recursive: true });
await writeFile(abs, content, "utf8");
result2.written.push(relPath);
}
// src/analytics/enforcement.ts
init_esm_shims();
import { existsSync } from "fs";
import { join as join3 } from "path";
var ANALYTICS_STRICTNESS_MODES = ["off", "warn", "strict"];
var DEFAULT_ANALYTICS_STRICTNESS = "warn";
function resolveAnalyticsStrictness(projectRoot, env2 = process.env) {
return resolveFlooredMode(
{
team: readConfigsDir(projectRoot).merged.get("analytics_strictness"),
local: readDotConfig(projectRoot).get("analytics_strictness"),
env: envConfigValue(env2, "analytics_strictness")
},
ANALYTICS_STRICTNESS_MODES,
DEFAULT_ANALYTICS_STRICTNESS
);
}
function evaluateAnalyticsCompleteness(input) {
const { mode, events, docExists } = input;
if (mode === "off") {
return { mode, verdict: "ok", missingDocs: [] };
}
const missing = /* @__PURE__ */ new Set();
for (const event of events) {
const rel = analyticsEventDocPath(event.module, event.feature, event.eventName);
if (!docExists(rel)) {
missing.add(rel);
}
}
const missingDocs = [...missing].sort();
if (missingDocs.length === 0) {
return { mode, verdict: "ok", missingDocs };
}
return { mode, verdict: mode === "strict" ? "block" : "warn", missingDocs };
}
function evaluateAnalyticsCompletenessForProject(projectRoot, events, env2 = process.env) {
return evaluateAnalyticsCompleteness({
mode: resolveAnalyticsStrictness(projectRoot, env2),
events,
docExists: (rel) => existsSync(join3(projectRoot, rel))
});
}
// src/cache/index.ts
init_esm_shims();
// src/cache/types.ts
init_esm_shims();
// src/cache/transition-log.ts
init_esm_shims();
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
import { join as join4, dirname as dirname3 } from "path";
var TransitionLogManager = class {
constructor(projectRoot, maxPerKey = 500) {
this.projectRoot = projectRoot;
this.maxPerKey = maxPerKey;
}
projectRoot;
maxPerKey;
get logPath() {
return join4(this.projectRoot, ".paqad", "cache", "transition-log.json");
}
async append(entry) {
const log = await this.load();
const key = entry.stack_key;
if (!log.entries[key]) {
log.entries[key] = [];
}
log.entries[key].push(entry);
if (log.entries[key].length > log.max_entries_per_key) {
log.entries[key] = log.entries[key].slice(-log.max_entries_per_key);
}
await this.save(log);
}
async load() {
try {
const raw = await readFile2(this.logPath, "utf8");
return JSON.parse(raw);
} catch {
return {
version: 1,
entries: {},
max_entries_per_key: this.maxPerKey
};
}
}
async computeProbabilities(stackKey, fromSkill) {
const log = await this.load();
const entries = (log.entries[stackKey] ?? []).filter((e) => e.from_skill === fromSkill);
if (entries.length === 0) return [];
const counts = {};
for (const entry of entries) {
counts[entry.to_skill] = (counts[entry.to_skill] ?? 0) + 1;
}
const total = entries.length;
return Object.entries(counts).map(([to_skill, count2]) => ({
to_skill,
probability: count2 / total
})).sort((a, b) => b.probability - a.probability);
}
async save(log) {
await mkdir2(dirname3(this.logPath), { recursive: true });
await writeFile2(this.logPath, JSON.stringify(log, null, 2), "utf8");
}
};
// src/cache/metrics.ts
init_esm_shims();
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
import { join as join5, dirname as dirname4 } from "path";
var EVENT_TO_FIELD = {
cache_hit: "cache_hits",
cache_miss: "cache_misses",
prewarm_hit: "prewarm_hits",
prewarm_miss: "prewarm_misses",
prewarm_skipped: "prewarm_skipped"
};
var CacheMetricsTracker = class {
constructor(projectRoot) {
this.projectRoot = projectRoot;
}
projectRoot;
metricsPath(sessionId) {
return join5(this.projectRoot, ".paqad", "cache", `metrics-${sessionId}.json`);
}
async record(sessionId, event, tokenSavings = 0) {
const metrics = await this.read(sessionId);
const field = EVENT_TO_FIELD[event];
metrics[field]++;
metrics.total_token_savings_estimate += tokenSavings;
await this.write(sessionId, metrics);
}
async read(sessionId) {
try {
const raw = await readFile3(this.metricsPath(sessionId), "utf8");
return JSON.parse(raw);
} catch {
return {
session_id: sessionId,
cache_hits: 0,
cache_misses: 0,
prewarm_hits: 0,
prewarm_misses: 0,
prewarm_skipped: 0,
total_token_savings_estimate: 0
};
}
}
async write(sessionId, metrics) {
const path10 = this.metricsPath(sessionId);
await mkdir3(dirname4(path10), { recursive: true });
await writeFile3(path10, JSON.stringify(metrics, null, 2), "utf8");
}
};
// src/cache/cache-warmer.ts
init_esm_shims();
var CacheWarmer = class {
constructor(cacheManager) {
this.cacheManager = cacheManager;
}
cacheManager;
async prewarm(skillName, predictedInputFiles) {
try {
const existing = await this.cacheManager.checkCache(skillName, predictedInputFiles);
if (existing.hit) return false;
const inputHash = await this.cacheManager.computeInputHash(predictedInputFiles);
await this.cacheManager.writeCache(
skillName,
inputHash,
"[prewarm-pending]",
predictedInputFiles
);
return true;
} catch {
return false;
}
}
};
// src/cache/predictive-cache.ts
init_esm_shims();
import { createHash } from "crypto";
var DEFAULT_PREDICTIVE_CACHE_OPTIONS = {
enabled: true,
confidence_threshold: 0.7,
max_candidates: 3
};
var PredictiveCache = class {
constructor(transitionLog, warmer, metrics, options = DEFAULT_PREDICTIVE_CACHE_OPTIONS) {
this.transitionLog = transitionLog;
this.warmer = warmer;
this.metrics = metrics;
this.options = options;
}
transitionLog;
warmer;
metrics;
options;
async onSkillComplete(sessionId, stackKey, workflow, completedSkill, outputHash, nextSkill) {
if (nextSkill) {
await this.transitionLog.append({
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
workflow,
stack_key: stackKey,
from_skill: completedSkill,
to_skill: nextSkill,
from_outputs_hash: outputHash
});
}
if (!this.options.enabled) return;
const candidates = await this.transitionLog.computeProbabilities(stackKey, completedSkill);
const aboveThreshold = candidates.filter((c) => c.probability >= this.options.confidence_threshold).slice(0, this.options.max_candidates);
for (const candidate of aboveThreshold) {
try {
const warmed = await this.warmer.prewarm(candidate.to_skill, [outputHash]);
if (warmed) {
await this.metrics.record(sessionId, "prewarm_hit");
} else {
await this.metrics.record(sessionId, "prewarm_skipped");
}
} catch {
await this.metrics.record(sessionId, "prewarm_miss");
}
}
}
static computeOutputHash(output) {
return createHash("sha256").update(output).digest("hex");
}
};
// src/context/index.ts
init_esm_shims();
// src/context/budget-enforcer.ts
init_esm_shims();
// src/skills/model-selector.ts
init_esm_shims();
function selectModelForTier(profile, tier) {
if (tier === "fast") {
return profile.model_routing.fast_model;
}
if (tier === "reasoning") {
return profile.model_routing.reasoning_model;
}
return profile.model_routing.default_model;
}
// src/context/budget-enforcer.ts
var COMPRESSION_BAND_THRESHOLDS = {
standard: [60, 80, 95],
aggressive: [50, 70, 85],
conservative: [70, 85, 97]
};
function classifyBand(usagePct, policy) {
const [tightening, compressed, forceSummary] = COMPRESSION_BAND_THRESHOLDS[policy];
const pct = usagePct * 100;
if (pct < tightening) {
return "comfortable";
}
if (pct < compressed) {
return "tightening";
}
if (pct < forceSummary) {
return "compressed";
}
return "force-summary";
}
var ContextBudgetEnforcer = class _ContextBudgetEnforcer {
budget;
constructor(config) {
this.budget = { ...DEFAULT_CONTEXT_BUDGET, ...config };
}
static fromProfile(profile, tier = "medium", overrides) {
const models = {
fast: profile.model_routing.fast_model,
reasoning: profile.model_routing.reasoning_model,
medium: selectModelForTier(profile, "medium")
};
return new _ContextBudgetEnforcer({
...resolveContextBudgetForModelTier(models, tier),
...overrides
});
}
checkBudget(estimatedTokens) {
const budget = this.budget.main_agent_max;
const pct = budget === 0 ? 0 : estimatedTokens / budget;
if (pct <= 0.8) {
return {
verdict: "ok",
usage_pct: pct,
budget,
actual: estimatedTokens,
message: "Within budget"
};
}
if (pct <= 1) {
return {
verdict: "warning",
usage_pct: pct,
budget,
actual: estimatedTokens,
message: `Context at ${Math.round(pct * 100)}% of budget \u2014 consider reducing loaded files`
};
}
if (pct <= 1.2) {
return {
verdict: "requires-justification",
usage_pct: pct,
budget,
actual: estimatedTokens,
message: `Context at ${Math.round(pct * 100)}% of budget \u2014 must justify or reduce`
};
}
return {
verdict: "blocked",
usage_pct: pct,
budget,
actual: estimatedTokens,
message: `Context at ${Math.round(pct * 100)}% of budget \u2014 blocked. Select fewer files.`
};
}
shouldCompact(currentTokens) {
return this.budget.main_agent_max > 0 && currentTokens / this.budget.main_agent_max >= this.budget.compaction_trigger_pct;
}
evaluate(tokensUsed) {
const result2 = this.checkBudget(tokensUsed);
return {
decision: toLegacyDecision(result2.verdict),
usage_ratio: result2.usage_pct
};
}
static async computeBudget(input) {
const { model } = input;
if (typeof model.context_window_tokens !== "number" || Number.isNaN(model.context_window_tokens)) {
return {
ok: false,
error: "Model catalog entry is missing context_window_tokens",
missing_field: "context_window_tokens"
};
}
const window = model.context_window_tokens;
const reserved = typeof model.max_output_tokens === "number" ? Math.min(input.reserved_output_tokens, model.max_output_tokens) : input.reserved_output_tokens;
const tokenizer = await getOrLoad(model.tokenizer_version);
const count2 = (text2) => tokenizer.countTokens(text2);
const systemTokens = count2(input.system_prompt);
const projectKnowledgeTokens = count2(input.project_knowledge);
const rollingSummaryTokens = input.rolling_summary === null ? 0 : count2(input.rolling_summary);
const recentTurnsTokens = count2(input.recent_turns);
const newUserMessageTokens = count2(input.new_user_message);
const nonChunkContent = systemTokens + projectKnowledgeTokens + rollingSummaryTokens + recentTurnsTokens + newUserMessageTokens;
let remaining = window - nonChunkContent - reserved;
let retrievedChunksTokens = 0;
let droppedChunkCount = 0;
for (const chunk of input.retrieved_chunks) {
const chunkTokens = count2(chunk);
if (chunkTokens > remaining) {
droppedChunkCount += 1;
continue;
}
retrievedChunksTokens += chunkTokens;
remaining -= chunkTokens;
}
const totalUsed = nonChunkContent + retrievedChunksTokens + reserved;
const usagePct = window === 0 ? 0 : totalUsed / window;
const result2 = {
ok: true,
system_prompt_tokens: systemTokens,
project_knowledge_tokens: projectKnowledgeTokens,
retrieved_chunks_tokens: retrievedChunksTokens,
rolling_summary_tokens: input.rolling_summary === null ? "\u2014" : rollingSummaryTokens,
recent_turns_tokens: recentTurnsTokens,
new_user_message_tokens: newUserMessageTokens,
reserved_output_tokens: reserved,
total_used: totalUsed,
usage_pct: usagePct,
band: classifyBand(usagePct, input.compression_policy),
tokenizer_version: tokenizer.tokenizer_version,
dropped_chunk_count: droppedChunkCount
};
if (droppedChunkCount > 0) {
result2.compression_audit = {
event: "context.compression_applied",
reason: "chunk_exceeds_budget",
dropped_chunk_count: droppedChunkCount
};
}
return result2;
}
};
function toLegacyDecision(verdict2) {
switch (verdict2) {
case "ok":
return "allow";
case "warning":
return "warn";
case "requires-justification":
return "require-justification";
case "blocked":
return "block";
}
}
// src/context/budget-optimizer.ts
init_esm_shims();
import { writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
import { join as join6, dirname as dirname5 } from "path";
// src/context/turn-summarizer.ts
init_esm_shims();
var SUMMARY_TOKEN_CAP = 2e3;
var DEFAULT_TIMEOUT_MS = 3e4;
var BASE_SYSTEM_PROMPT = [
"You compress an older slice of a conversation into a faithful rolling summary.",
'Attribute every collapsed turn explicitly: prefix each user turn with "user said"',
'and each assistant turn with "assistant replied". Preserve decisions, blockers,',
"and next steps. Redact any PII (names, emails, phone numbers, secrets) \u2014 never",
`echo it back. Keep the summary under ${SUMMARY_TOKEN_CAP} tokens.`
].join(" ");
var STRICT_SYSTEM_PROMPT = [
BASE_SYSTEM_PROMPT,
"CRITICAL: your previous attempt was too long. Be much terser \u2014 collapse",
"aggressively and stay well under the token cap while keeping the attribution tags."
].join(" ");
var ALT_SYSTEM_PROMPT = [
"Summarise the conversation slice below as a bulleted recap.",
'Tag each collapsed turn with "user said" or "assistant replied".',
"Drop all PII. Be concise."
].join(" ");
var TurnSummarizer = class {
summarize(turnText, turnIndex, timestamp) {
const summarized = {
turn_index: turnIndex,
timestamp,
decisions: this.extractDecisions(turnText).slice(0, 3),
files_touched: this.extractFilesTouched(turnText),
blockers: this.extractBlockers(turnText).slice(0, 2),
next_steps: this.extractNextSteps(turnText).slice(0, 2),
original_tokens: this.estimateTokens(turnText),
summary_tokens: 0
};
summarized.summary_tokens = this.estimateTokens(JSON.stringify(summarized));
return summarized;
}
extractDecisions(text2) {
const decisions = [];
const patterns = [
/(?:decided to|chose|going with|will use|using)\s+([^.\n]{10,80})/gi,
/(?:going to|selected|picked)\s+([^.\n]{10,80})/gi
];
for (const pattern of patterns) {
let match;
while ((match = pattern.exec(text2)) !== null) {
decisions.push(match[1].trim());
}
}
return [...new Set(decisions)];
}
extractFilesTouched(text2) {
return [...new Set(findTouchedFilePaths(text2))];
}
extractBlockers(text2) {
const blockers = [];
const pattern = /(?:blocked by|waiting on|can't proceed|cannot proceed|error:)\s+([^.\n]{5,100})/gi;
let match;
while ((match = pattern.exec(text2)) !== null) {
blockers.push(match[1].trim());
}
return blockers;
}
extractNextSteps(text2) {
const steps = [];
const pattern = /(?:next step|next:|remaining:|TODO:|- \[ \])\s*([^.\n]{5,100})/gi;
let match;
while ((match = pattern.exec(text2)) !== null) {
steps.push(match[1].trim());
}
return steps;
}
estimateTokens(text2) {
return Math.ceil(text2.length / 4);
}
async summarise(messages, targetTokenCount, opts = {}) {
const provider = opts.inferenceProvider;
if (!provider) {
return { ok: false, error: "inference-failed" };
}
if (opts.signal?.aborted) {
return { ok: false, error: "cancelled" };
}
const preserved_turn_ids = [];
const collapsible = [];
for (const message of messages) {
if (message.decision_packet || message.approval_turn) {
preserved_turn_ids.push(message.turn_id);
} else {
collapsible.push(message);
}
}
const valid_through_turn_id = collapsible.at(-1)?.turn_id ?? opts.priorSummary?.valid_through_turn_id ?? "";
const segments = [];
if (opts.priorSummary) {
segments.push(`Prior summary:
${opts.priorSummary.text}`);
}
for (const message of collapsible) {
segments.push(`${message.role}: ${message.content}`);
}
const inputText = segments.join("\n");
const input_token_count = this.estimateTokens(inputText);
const targetInstruction = `Aim for roughly ${Math.max(0, targetTokenCount)} tokens.`;
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
const first = await this.invoke(
provider,
`${BASE_SYSTEM_PROMPT} ${targetInstruction}`,
inputText,
timeoutMs,
opts.signal
);
if (!first.ok) {
return first;
}
let summaryText = first.text;
if (!isUsable(summaryText)) {
const retry = await this.invoke(
provider,
`${ALT_SYSTEM_PROMPT} ${targetInstruction}`,
inputText,
timeoutMs,
opts.signal
);
if (!retry.ok) {
return retry;
}
if (!isUsable(retry.text)) {
return { ok: false, error: "inference-failed" };
}
summaryText = retry.text;
}
let truncated = false;
summaryText = summaryText.trim();
if (this.estimateTokens(summaryText) > SUMMARY_TOKEN_CAP) {
const stricter = await this.invoke(
provider,
`${STRICT_SYSTEM_PROMPT} ${targetInstruction}`,
inputText,
timeoutMs,
opts.signal
);
if (!stricter.ok) {
return stricter;
}
if (isUsable(stricter.text)) {
summaryText = stricter.text.trim();
}
if (this.estimateTokens(summaryText) > SUMMARY_TOKEN_CAP) {
summaryText = this.truncateToTokenCap(summaryText);
truncated = true;
}
}
return {
ok: true,
summary_text: summaryText,
valid_through_turn_id,
input_token_count,
summary_token_count: this.estimateTokens(summaryText),
truncated,
preserved_turn_ids
};
}
truncateToTokenCap(text2) {
return text2.slice(0, SUMMARY_TOKEN_CAP * 4);
}
async invoke(provider, systemPrompt, inputText, timeoutMs, callerSignal) {
const timeoutSignal = AbortSignal.timeout(timeoutMs);
const signal5 = callerSignal ? AbortSignal.any([callerSignal, timeoutSignal]) : timeoutSignal;
const inferenceMessages = [
{ role: "system", content: systemPrompt },
{ role: "user", content: inputText }
];
try {
const text2 = await raceAbort(
provider.complete(inferenceMessages, { timeoutMs, signal: signal5 }),
signal5
);
return { ok: true, text: text2 };
} catch {
if (signal5.aborted) {
const reason2 = signal5.reason;
return { ok: false, error: reason2?.name === "TimeoutError" ? "timeout" : "cancelled" };
}
return { ok: false, error: "inference-failed" };
}
}
};
function isUsable(text2) {
return typeof text2 === "string" && text2.trim().length > 0;
}
function raceAbort(promise, signal5) {
return new Promise((resolve5, reject2) => {
if (signal5.aborted) {
reject2(signal5.reason);
return;
}
const onAbort = () => reject2(signal5.reason);
signal5.addEventListener("abort", onAbort, { once: true });
promise.then(
(value) => {
signal5.removeEventListener("abort", onAbort);
resolve5(value);
},
(error) => {
signal5.removeEventListener("abort", onAbort);
reject2(error);
}
);
});
}
var TOUCHED_PATH_START = /(?:src|app|lib|tests?|routes?|config|docs?)\/[\w/.-]+/g;
var WORD_CHAR = /\w/;
function findTouchedFilePaths(text2) {
const files = [];
TOUCHED_PATH_START.lastIndex = 0;
let match;
while ((match = TOUCHED_PATH_START.exec(text2)) !== null) {
const run2 = match[0];
const bodyStart = run2.indexOf("/") + 1;
const end = touchedPathEnd(run2, bodyStart);
if (end === -1) continue;
files.push(run2.slice(0, end));
TOUCHED_PATH_START.lastIndex = match.index + end;
}
return files;
}
function touchedPathEnd(run2, bodyStart) {
for (let dot = run2.length - 2; dot > bodyStart; dot -= 1) {
if (run2[dot] !== "." || !WORD_CHAR.test(run2[dot + 1])) continue;
let end = dot + 1;
while (end < run2.length && end - dot <= 6 && WORD_CHAR.test(run2[end])) end += 1;
return end;
}
return -1;
}
// src/context/priority-classifier.ts
init_esm_shims();
var InferredTurnClassifierModel = class {
score() {
return "normal";
}
};
var PriorityClassifier = class {
turnModel;
constructor(turnModel = new InferredTurnClassifierModel()) {
this.turnModel = turnModel;
}
tag(turns, policy) {
if (turns.length === 0) {
return { tagged: [], warnings: [] };
}
const tagged = [];
const warnings = [];
for (const turn of turns) {
const protectedTurn = turn.decision_packet === true || turn.approval_turn === true;
if (protectedTurn && turn.priority === "high") {
tagged.push({ ...turn, priority: "high" });
continue;
}
const scored = this.turnModel.score(turn);
let resolved = policy?.all_normal && !protectedTurn ? "normal" : scored;
if (protectedTurn && resolved !== "high") {
warnings.push({
type: "context.context_health_warning",
reason: "priority_invariant_breach",
turn_id: turn.turn_id,
classifier_returned: resolved,
corrected_to: "high"
});
resolved = "high";
}
tagged.push({ ...turn, priority: resolved });
}
return { tagged, warnings };
}
classify(artifactSource, artifactType) {
const src = artifactSource.toLowerCase();
const type = artifactType.toLowerCase();
if (src.includes("rules/") || src.includes("constitution") || src.includes(".paqad/session/spec") || type === "rule" || type === "constitution") {
return "critical";
}
if (type === "conversation-turn" || type === "current-file" || src.includes("recent-decision")) {
return "high";
}
if (src.includes("stack-docs") || src.includes("docs/") || type === "stack-doc" || type === "handoff" || type === "summarized-turn") {
return "medium";
}
return "low";
}
classifyByContent(_content, phase) {
if (phase === "router" || phase === "constitution") return "critical";
if (phase === "implementation" || phase === "spec") return "high";
if (phase === "docs" || phase === "stack") return "medium";
return "low";
}
};
// src/context/context-evictor.ts
init_esm_shims();
var ContextEvictor = class {
evict(segments, tier) {
const toEvict = [];
if (tier === "yellow") {
toEvict.push(...segments.filter((s) => s.tier === "low"));
} else if (tier === "amber") {
toEvict.push(...segments.filter((s) => s.tier === "low" || s.tier === "medium"));
} else if (tier === "red") {
toEvict.push(...segments.filter((s) => s.tier === "low" || s.tier === "medium"));
}
const remaining_segments = segments.filter((segment) => !toEvict.includes(segment));
const evicted_count = toEvict.length;
const tokens_reclaimed = toEvict.reduce((sum, s) => sum + s.token_estimate, 0);
const evicted_sources = toEvict.map((s) => s.content_type);
return {
evicted_count,
tokens_reclaimed,
evicted_sources,
evicted_segments: toEvict,
remaining_segments
};
}
};
// src/context/budget-optimizer.ts
var TIER_THRESHOLDS = {
aggressive: { yellow: 0.5, amber: 0.7, red: 0.85 },
balanced: { yellow: 0.6, amber: 0.8, red: 0.9 },
conservative: { yellow: 0.7, amber: 0.85, red: 0.95 }
};
var ContextBudgetOptimizer = class _ContextBudgetOptimizer {
constructor(summarizer, classifier, evictor, projectRoot, config = {
strategy: "balanced",
summarize_after_turns: 15
}) {
this.summarizer = summarizer;
this.evictor = evictor;
this.projectRoot = projectRoot;
this.config = config;
this.classifier = classifier;
}
summarizer;
evictor;
projectRoot;
config;
classifier;
static fromProfile(projectRoot, profile, summarizer = new TurnSummarizer(), classifier = new PriorityClassifier(), evictor = new ContextEvictor()) {
return new _ContextBudgetOptimizer(summarizer, classifier, evictor, projectRoot, {
strategy: profile.efficiency.context_budget_strategy ?? "balanced",
summarize_after_turns: profile.efficiency.auto_summarize_interval ?? 15
});
}
async evaluate(tokensUsed, maxTokens, metrics = {}) {
const ratio = tokensUsed / maxTokens;
const baseTier = this.classifyTier(ratio);
const hitRateBelowTarget = metrics.current_hit_rate !== void 0 && metrics.target_hit_rate !== void 0 && metrics.current_hit_rate < metrics.target_hit_rate;
const tier = hitRateBelowTarget ? "red" : baseTier;
let action;
if (tier === "red") {
action = "compact";
} else if (tier === "amber") {
action = "warn";
} else {
action = "continue";
}
await this.saveState({
tier,
tokens_used: tokensUsed,
max_tokens: maxTokens,
last_evaluated_at: (/* @__PURE__ */ new Date()).toISOString(),
summarized_turn_count: metrics.summarized_turn_count ?? 0,
evicted_segment_count: metrics.evicted_segment_count ?? 0,
recommended_action: action,
enforcement_reason: hitRateBelowTarget ? "context-hit-rate-below-target" : action === "compact" ? "token-budget-tight" : "healthy"
});
return { action, tier };
}
async summarizeTurns(turns, olderThanIndex) {
return turns.slice(0, olderThanIndex).map((t, i) => this.summarizer.summarize(t.text, i, t.timestamp));
}
evictSegments(segments, tier) {
return this.evictor.evict(segments, tier);
}
summarizeBeforeIndex(turnCount) {
return Math.max(0, turnCount - this.config.summarize_after_turns);
}
resolveMaxTokens(profile) {
const models = {
fast: profile.model_routing.fast_model,
reasoning: profile.model_routing.reasoning_model,
medium: selectModelForTier(profile, "medium")
};
return resolveContextBudgetForModelTier(models, "medium").main_agent_max;
}
async saveState(state) {
try {
const statePath = join6(this.projectRoot, ".paqad", "session", "context-budget.json");
await mkdir4(dirname5(statePath), { recursive: true });
await writeFile4(statePath, JSON.stringify(state, null, 2), "utf8");
} catch {
}
}
classifyTier(ratio) {
const thresholds = TIER_THRESHOLDS[this.config.strategy];
if (ratio > thresholds.red) return "red";
if (ratio > thresholds.amber) return "amber";
if (ratio > thresholds.yellow) return "yellow";
return "green";
}
};
// src/context/differential-refresh.ts
init_esm_shims();
// src/context/file-registry-mapper.ts
init_esm_shims();
var FILE_REGISTRY_RULES = [
{
patterns: [/^app\/Models\//, /^lib\/models\//],
registries: ["model-registry.md", "table-registry.md"]
},
{
patterns: [/^routes\//, /^lib\/router\//, /^app\/Http\/Controllers\//],
registries: ["api-registry.md"]
},
{ patterns: [/^database\/migrations\//], registries: ["table-registry.md", "query-registry.md"] },
{ patterns: [/^src\/components\//, /^lib\/widgets\//], registries: ["component-registry.md"] },
{ patterns: [/^resources\/views\//, /^lib\/screens\//], registries: ["screen-registry.md"] },
{
patterns: [/^app\/Events\//, /^app\/Listeners\//, /^app\/Jobs\//],
registries: ["job-event-registry.md", "integration-registry.md"]
},
{ patterns: [/^app\/Exceptions\//], registries: ["error-code-registry.md"] },
{ patterns: [/^tests\//], registries: ["test-registry.md"] }
];
var FileRegistryMapper = class {
getAffectedRegistries(file) {
const affected = /* @__PURE__ */ new Set();
for (const rule of FILE_REGISTRY_RULES) {
if (rule.patterns.some((pattern) => pattern.test(file))) {
rule.registries.forEach((registry) => affected.add(registry));
}
}
if (isModuleDirectory(file)) {
affected.add("module-registry.md");
affected.add("feature-registry.md");
}
return REGISTRIES.filter((registry) => affected.has(registry));
}
};
function isModuleDirectory(file) {
return /(^|\/)modules\/[^/]+/.test(file) || /^docs\/modules\/[^/]+/.test(file);
}
// src/context/differential-refresh.ts
var DifferentialRefresh = class {
constructor(mapper = new FileRegistryMapper()) {
this.mapper = mapper;
}
mapper;
async refresh(changedFiles) {
const affectedRegistries = /* @__PURE__ */ new Set();
for (const file of changedFiles) {
const registries = this.mapper.getAffectedRegistries(file);
registries.forEach((registry) => affectedRegistries.add(registry));
}
return {
total_registries: REGISTRIES.length,
refreshed: affectedRegistries.size,
skipped: REGISTRIES.length - affectedRegistries.size,
registries: [...affectedRegistries].sort()
};
}
};
// src/context/hit-tracker.ts
init_esm_shims();
var ContextHitTracker = class {
loaded = /* @__PURE__ */ new Set();
referenced = /* @__PURE__ */ new Set();
input;
constructor(sessionIdOrInput, phase, story) {
this.input = typeof sessionIdOrInput === "string" ? { session_id: sessionIdOrInput, phase: phase ?? "unknown", story } : sessionIdOrInput;
}
recordLoaded(files) {
files.forEach((file) => this.loaded.add(file));
}
recordReferenced(file) {
this.referenced.add(file);
}
computeHitRate() {
const filesLoaded = this.loaded.size;
const filesReferenced = this.referenced.size;
const hitRate = filesLoaded === 0 ? 0 : filesReferenced / filesLoaded;
const unreferencedFiles = [...this.loaded].filter((file) => !this.referenced.has(file)).sort();
return {
session_id: this.input.session_id,
phase: this.input.phase,
story: this.input.story,
files_loaded: filesLoaded,
files_referenced: filesReferenced,
hit_rate: Math.round(hitRate * 100) / 100,
unreferenced_files: unreferencedFiles,
timestamp: (/* @__PURE__ */ new Date()).toISOString()
};
}
reset() {
this.loaded.clear();
this.referenced.clear();
}
};
// src/context/inference-provider.ts
init_esm_shims();
// src/context/conversation-lineage.ts
init_esm_shims();
function isActive(message) {
return message.stopped !== true && !message.discardedAt;
}
function chronologically(a, b) {
if (a.createdAt !== b.createdAt) {
return a.createdAt < b.createdAt ? -1 : 1;
}
return a.id < b.id ? -1 : 1;
}
function latest(messages) {
return messages.reduce(
(newest, candidate) => chronologically(candidate, newest) > 0 ? candidate : newest
);
}
function hasParentPointer(message) {
return message.parentMessageId != null;
}
function resolveActiveLineage(messages) {
const live = messages.filter(isActive);
if (live.length === 0) {
return [];
}
const leaf = latest(live);
if (!messages.some(hasParentPointer)) {
const branch = leaf.branchId ?? null;
return live.filter((m) => (m.branchId ?? null) === branch).sort(chronologically);
}
const byId = new Map(messages.map((m) => [m.id, m]));
const chain = [];
const seen = /* @__PURE__ */ new Set();
let cursor = leaf;
while (cursor && !seen.has(cursor.id)) {
seen.add(cursor.id);
if (isActive(cursor)) {
chain.push(cursor);
}
cursor = hasParentPointer(cursor) ? byId.get(cursor.parentMessageId) : void 0;
}
return chain.sort(chronologically);
}
// src/context/conversation-rebuild.ts
init_esm_shims();
// src/core/types/conversation.ts
init_esm_shims();
var RebuildFailedError = class extends Error {
kind = "rebuild_failed";
reason;
constructor(reason2) {
super(`Conversation rebuild failed: ${reason2}`);
this.name = "RebuildFailedError";
this.reason = reason2;
}
};
// src/context/context-hash.ts
init_esm_shims();
import { createHash as createHash2 } from "crypto";
var CONTEXT_HASH_ALGO_VERSION = 1;
function sha256Hex2(value) {
return createHash2("sha256").update(value, "utf8").digest("hex");
}
function canonicalize(value) {
if (value === null || typeof value !== "object") {
return JSON.stringify(value) ?? "null";
}
if (Array.isArray(value)) {
return `[${value.map(canonicalize).join(",")}]`;
}
const entries = Object.keys(value).sort().map(
(key) => `${JSON.stringify(key)}:${canonicalize(value[key])}`
);
return `{${entries.join(",")}}`;
}
function buildContextHashPreimage(input) {
return {
algo_version: CONTEXT_HASH_ALGO_VERSION,
lineage: input.lineage.map((message) => ({
id: message.id,
role: message.role,
content: message.content,
created_at: message.createdAt
})),
classifier: {
retrieval_needed: input.classifierOutput.retrieval_needed === true,
context_budget_hint: input.classifierOutput.context_budget_hint ?? null
},
retrieved_chunks: input.retrievedChunks.map((chunk) => ({
chunk_id: chunk.chunkId,
content_sha256: sha256Hex2(chunk.content)
})),
budget_tokens: input.budgetTokens,
summarizer_mode: input.summarizerMode,
truncated: input.truncated,
truncated_turn_count: input.truncatedTurnCount
};
}
function computeContextHash(input) {
return sha256Hex2(canonicalize(buildContextHashPreimage(input)));
}
// src/context/conversation-rebuild.ts
var KEEP_RECENT_TURNS = 2;
async function rebuildApiConversation(input) {
const { budgetTokens } = input;
if (!Number.isFinite(budgetTokens) || budgetTokens <= 0) {
throw new RebuildFailedError(`invalid budgetTokens: ${String(budgetTokens)}`);
}
const cache = input.cache;
const cacheKey = cache ? cache.computeKey(input.displayMessages, {
classifierOutput: input.classifierOutput,
retrievedChunks: input.retrievedChunks ?? null,
budgetTokens
}) : void 0;
if (cache) {
const cached2 = cache.get(cacheKey);
if (cached2) {
return cached2;
}
}
const summarizer = input.summarizer ?? new TurnSummarizer();
const lineage = resolveActiveLineage(input.displayMessages);
const retrievalNeeded = input.classifierOutput.retrieval_needed === true;
const chunks = retrievalNeeded ? input.retrievedChunks ?? [] : [];
const retrievalTokens = chunks.reduce(
(sum, chunk) => sum + summarizer.estimateTokens(chunk.content),
0
);
const historyBudget = budgetTokens - retrievalTokens;
const overBudget = (msgs) => estimateMessagesTokens(summarizer, msgs) > historyBudget;
let working = lineage.slice();
if (overBudget(working) && input.optimizer && working.length > KEEP_RECENT_TURNS) {
working = await summariseOlderTurns(input.optimizer, working);
}
let truncated = false;
let truncatedTurnCount = 0;
let tokensReclaimed = 0;
while (overBudget(working) && working.length > 1) {
const [dropped, ...rest] = working;
tokensReclaimed += summarizer.estimateTokens(dropped.content);
working = rest;
truncated = true;
truncatedTurnCount += 1;
}
const messages = working.map(toApiMessage);
const retrievedChunkIds = [];
if (chunks.length > 0) {
const refs = insertRetrieval(messages, chunks);
for (const ref of refs) {
retrievedChunkIds.push(ref.chunkId);
}
}
const contextHash = computeContextHash({
lineage,
classifierOutput: input.classifierOutput,
retrievedChunks: chunks,
budgetTokens,
summarizerMode: input.optimizer ? "optimizer" : "deterministic-regex",
truncated,
truncatedTurnCount
});
const result2 = {
messages,
retrievedChunkIds,
truncated,
truncatedTurnCount,
contextHash
};
if (truncated && input.audit) {
emitContextTruncated(input.audit.projectRoot, {
sessionId: input.audit.sessionId,
turnsDropped: truncatedTurnCount,
tokensReclaimed
});
}
if (cache) {
cache.set(cacheKey, result2);
}
return result2;
}
async function summariseOlderTurns(optimizer, working) {
const olderCount = working.length - KEEP_RECENT_TURNS;
const older = working.slice(0, olderCount);
let summaries;
try {
summaries = await optimizer.summarizeTurns(
older.map((m) => ({ text: m.content, timestamp: m.createdAt })),
olderCount
);
} catch (error) {
throw new RebuildFailedError(
`summarisation failed: ${error instanceof Error ? error.message : String(error)}`
);
}
return [buildSummaryMessage(summaries, older), ...working.slice(olderCount)];
}
function estimateMessagesTokens(summarizer, msgs) {
return msgs.reduce((sum, m) => sum + summarizer.estimateTokens(m.content), 0);
}
function toApiMessage(message) {
return { role: message.role, content: message.content };
}
function buildSummaryMessage(summaries, originals) {
const lines = summaries.map((summary, index) => {
const parts = [];
if (summary.decisions.length > 0) parts.push(`decisions: ${summary.decisions.join("; ")}`);
if (summary.files_touched.length > 0) parts.push(`files: ${summary.files_touched.join(", ")}`);
if (summary.blockers.length > 0) parts.push(`blockers: ${summary.blockers.join("; ")}`);
if (summary.next_steps.length > 0) parts.push(`next: ${summary.next_steps.join("; ")}`);
return `Turn ${index + 1}: ${parts.length > 0 ? parts.join(" | ") : "(no salient content)"}`;
});
const earliest = originals[0];
return {
id: `summary:${earliest.id}`,
role: "system",
content: `Summary of ${summaries.length} earlier turns:
${lines.join("\n")}`,
createdAt: earliest.createdAt
};
}
function insertRetrieval(messages, chunks) {
const firstNonSystem = messages.findIndex((m) => m.role !== "system");
const position = firstNonSystem === -1 ? messages.length : firstNonSystem;
const content = `Retrieved context:
${chunks.map((chunk) => chunk.content).join("\n\n")}`;
messages.splice(position, 0, { role: "system", content });
return chunks.map((chunk) => ({ chunkId: chunk.chunkId, position }));
}
// src/context/rebuild-cache.ts
init_esm_shims();
import { createHash as createHash3 } from "crypto";
var DEFAULT_REBUILD_CACHE_MAX_SIZE = 50;
var RebuildCache = class {
constructor(maxSize = DEFAULT_REBUILD_CACHE_MAX_SIZE) {
this.maxSize = maxSize;
}
maxSize;
entries = /* @__PURE__ */ new Map();
computeKey(displayMessages, classifierOutput) {
return createHash3("sha256").update(JSON.stringify([displayMessages, classifierOutput])).digest("hex");
}
get(key) {
const hit = this.entries.get(key);
if (hit === void 0) {
return void 0;
}
this.entries.delete(key);
this.entries.set(key, hit);
return hit;
}
set(key, result2) {
this.entries.delete(key);
this.entries.set(key, result2);
if (this.entries.size > this.maxSize) {
const oldest = this.entries.keys().next().value;
this.entries.delete(oldest);
}
}
get size() {
return this.entries.size;
}
};
// src/context/types.ts
init_esm_shims();
// src/context/relevance-scorer.ts
init_esm_shims();
import { basename as basename2, dirname as dirname6 } from "path";
// src/context/metadata-filter.ts
init_esm_shims();
var DEFAULT_MIN_FILTERED_SIZE = 3;
function applyMetadataFilters(chunks, filters, options = {}) {
const minFilteredSize = options.minFilteredSize ?? DEFAULT_MIN_FILTERED_SIZE;
const filterTypesApplied = [];
if (chunks.length === 0) {
return {
chunks,
fallback: true,
fallback_reason: "empty-corpus",
filter_types_applied: []
};
}
if (filters.length === 0) {
return { chunks, fallback: false, filter_types_applied: [] };
}
let filtered = chunks;
for (const filter of filters) {
filtered = applyFilter(filtered, filter);
filterTypesApplied.push(filter.type);
}
if (filtered.length < minFilteredSize) {
return {
chunks,
fallback: true,
fallback_reason: "below-min-threshold",
filter_types_applied: []
};
}
return { chunks: filtered, fallback: false, filter_types_applied: filterTypesApplied };
}
var FRAMEWORK_EXT_PATTERNS = {
react: [".tsx", ".jsx"],
"react-native": [".tsx", ".jsx"],
next: [".tsx", ".jsx"],
"next.js": [".tsx", ".jsx"],
vue: [".vue"],
angular: [".component.ts", ".module.ts", ".directive.ts"],
laravel: [".php"],
flutter: [".dart"],
django: [".py"],
fastapi: [".py"]
};
function applyFilter(chunks, filter) {
switch (filter.type) {
case "file_extension": {
const ext = String(filter.value);
return chunks.filter((c) => c.source_file.endsWith(ext));
}
case "module_path_prefix": {
const prefix = trimTrailingChar(
String(filter.value).replace(/\\/g, "/").replace(/^\.?\//, ""),
"/"
);
return chunks.filter((c) => {
const filePath = c.source_file.replace(/\\/g, "/");
return filePath === prefix || filePath.startsWith(`${prefix}/`) || filePath.endsWith(`/${prefix}`) || filePath.includes(`/${prefix}/`);
});
}
case "framework": {
const fw = String(filter.value).toLowerCase();
const extensions = FRAMEWORK_EXT_PATTERNS[fw] ?? [];
return chunks.filter((c) => {
const fileLower = c.source_file.toLowerCase();
return fileLower.includes(fw) || extensions.some((ext) => fileLower.endsWith(ext));
});
}
case "recency_cutoff_ms": {
const cutoff = Date.now() - Number(filter.value);
return chunks.filter((c) => {
const ts2 = c.modified_at_ms;
if (ts2 === void 0) return true;
return ts2 >= cutoff;
});
}
default:
return chunks;
}
}
// src/context/relevance-scorer.ts
var RelevanceScorer = class {
constructor(threshold = 0.15) {
this.threshold = threshold;
}
threshold;
score(chunk, context) {
const vector = this.vectorSimilarityScore(chunk, context.vectorScores);
const kw = this.keywordOverlapScore(chunk, context.keywords);
const sym = this.symbolReferenceScore(chunk, context.symbolReferences ?? []);
const path10 = this.filePathProximityScore(chunk, context.targetFilePath ?? "");
const depth = this.astDepthPenalty(chunk);
return vector * 0.55 + kw * 0.25 + sym * 0.1 + path10 * 0.1 - depth * 0.05;
}
filterAndRank(chunks, context, filters = []) {
const filterResult = applyMetadataFilters(chunks, filters);
const corpus = filterResult.chunks;
const ranked = corpus.map((c) => ({ chunk: c, score: this.score(c, context) })).filter(({ score }) => score >= this.threshold).sort((a, b) => b.score - a.score).map(({ chunk }) => chunk);
const fusion_strategy = {
signals: ["vector:0.55", "keyword:0.25", "symbol:0.10", "path:0.10"],
filters_applied: filterResult.filter_types_applied,
filter_fallback: filterResult.fallback || void 0,
filter_fallback_reason: filterResult.fallback_reason
};
return { chunks: ranked, fusion_strategy };
}
vectorSimilarityScore(chunk, vectorScores) {
if (!vectorScores) return 0;
return vectorScores.get(chunk.id) ?? 0;
}
keywordOverlapScore(chunk, keywords) {
if (keywords.length === 0) return 0;
const content = chunk.content.toLowerCase();
const matched = keywords.filter((kw) => content.includes(kw.toLowerCase())).length;
return matched / keywords.length;
}
symbolReferenceScore(chunk, symbols) {
if (symbols.length === 0) return 0;
const content = chunk.content;
const matched = symbols.filter((sym) => content.includes(sym)).length;
return matched / symbols.length;
}
filePathProximityScore(chunk, targetPath) {
if (!targetPath) return 0;
const chunkDir = dirname6(chunk.source_file);
const targetDir = dirname6(targetPath);
if (chunkDir === targetDir) return 1;
if (dirname6(chunkDir) === dirname6(targetDir)) return 0.5;
if (basename2(chunkDir) === basename2(targetDir)) return 0.3;
return 0;
}
astDepthPenalty(chunk) {
const depth = (chunk.ast_node_path.match(/>/g) ?? []).length;
return Math.min(depth * 0.2, 1);
}
};
// src/context/budget-allocator.ts
init_esm_shims();
var RATIO_PRESETS = [
{
test: ({ complexity, scope }) => complexity === "trivial" || scope === "single-file",
critical: 0.55,
task_relevant: 0.4,
supporting: 0.05
},
{
test: ({ complexity, scope }) => complexity === "low" || scope === "single-module",
critical: 0.5,
task_relevant: 0.42,
supporting: 0.08
},
{
test: ({ complexity, scope }) => complexity === "very-high" || scope === "system-wide",
critical: 0.35,
task_relevant: 0.4,
supporting: 0.25
},
{
test: ({ complexity, scope }) => complexity === "high" || scope === "multi-module",
critical: 0.38,
task_relevant: 0.42,
supporting: 0.2
}
];
var DEFAULT_RATIOS = { critical: 0.4, task_relevant: 0.45, supporting: 0.15 };
var BudgetAllocator = class {
allocate(totalBudget, hints) {
const ratios = hints !== void 0 ? RATIO_PRESETS.find((preset) => preset.test(hints)) ?? DEFAULT_RATIOS : DEFAULT_RATIOS;
return {
critical_budget: Math.floor(totalBudget * ratios.critical),
task_relevant_budget: Math.floor(totalBudget * ratios.task_relevant),
supporting_budget: Math.floor(totalBudget * ratios.supporting)
};
}
packChunks(chunks, budgetTokens, estimateTokens2 = (t) => Math.ceil(t.length / 4)) {
const packed = [];
const seen = /* @__PURE__ */ new Set();
let remaining = budgetTokens;
for (const chunk of chunks) {
const signature = chunk.content_hash || normalizeChunkContent(chunk.content);
if (seen.has(signature)) {
continue;
}
const tokens = estimateTokens2(chunk.content);
if (tokens <= remaining) {
packed.push(chunk);
seen.add(signature);
remaining -= tokens;
}
if (remaining <= 0) break;
}
return packed;
}
};
function normalizeChunkContent(content) {
return content.replace(/\s+/g, " ").trim();
}
// src/context/semantic-loader.ts
init_esm_shims();
import { writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
import { join as join9, dirname as dirname7, extname as extname2 } from "path";
// src/context/retrieval-depth-router.ts
init_esm_shims();
function selectRetrievalDepth(input) {
const { complexity, risk, scope, workflow } = input;
if (workflow === "investigation" && (complexity === "trivial" || complexity === "low")) {
return "none";
}
if (complexity === "trivial" && scope === "single-file") {
return "none";
}
if (complexity === "high" || complexity === "very-high" || scope === "system-wide" || risk === "high") {
return "deep";
}
return "standard";
}
function escalateDepth(depth) {
if (depth === "none") return "standard";
if (depth === "standard") return "deep";
return "deep";
}
function topNForDepth(depth, baseTopN) {
if (depth === "none") return 0;
if (depth === "deep") return baseTopN * 3;
return baseTopN;
}
function gateRetrieval(input) {
const depth = selectRetrievalDepth(input);
const topN = topNForDepth(depth, input.baseTopN);
return { depth, topN, skip: topN === 0 };
}
// src/context/action-router.ts
init_esm_shims();
var ActionRouter = class {
suggestActions(chunks, classification, workflowIds) {
if (chunks.length === 0 || workflowIds.length === 0) {
return [];
}
const recommendations = [];
for (const workflowId of workflowIds) {
const triggerKeywords = this.extractTriggerKeywords(workflowId, classification);
if (triggerKeywords.length === 0) continue;
const matchingChunks = chunks.filter(
(chunk) => this.chunkMatchesTrigger(chunk, triggerKeywords)
);
if (matchingChunks.length === 0) continue;
const confidence = Math.min(matchingChunks.length / chunks.length, 1);
recommendations.push({
action_type: "workflow",
confidence: Math.round(confidence * 100) / 100,
evidence_chunk_ids: matchingChunks.map((c) => c.id),
workflow_id: workflowId,
explanation: `Chunks matching [${triggerKeywords.join(", ")}] suggest workflow "${workflowId}" may be applicable.`,
requires_user_approval: true
});
}
return recommendations.sort((a, b) => b.confidence - a.confidence);
}
extractTriggerKeywords(workflowId, classification) {
const nameKeywords = workflowId.split(/[-_]/).map((k) => k.toLowerCase()).filter((k) => k.length > 2);
const classKeywords = [];
if (classification?.risk === "high" && workflowId.includes("pentest")) {
classKeywords.push("security", "vulnerability");
}
return [.../* @__PURE__ */ new Set([...nameKeywords, ...classKeywords])];
}
chunkMatchesTrigger(chunk, triggerKeywords) {
const symbolText = chunk.exported_symbols.join(" ").toLowerCase();
const contentLower = chunk.content.toLowerCase();
return triggerKeywords.some((kw) => symbolText.includes(kw) || contentLower.includes(kw));
}
};
// src/workflows/template-loader.ts
init_esm_shims();
var import_yaml = __toESM(require_dist(), 1);
import { readFile as readFile4, readdir } from "fs/promises";
import { join as join8 } from "path";
// src/pipeline/feature-development-view.ts
init_esm_shims();
import { join as join7 } from "path";
var FEATURE_DEVELOPMENT_VIEW_FILE = "feature-development.yaml";
var FEATURE_DEVELOPMENT_VIEW_RELATIVE = `${PATHS.WORKFLOWS_DIR}/${FEATURE_DEVELOPMENT_VIEW_FILE}`;
var GENERATED_VIEW_FIRST_LINE = "# Generated by paqad. Do not edit: changes here are overwritten.";
function isFeatureDevelopmentViewFile(fileName) {
return fileName === FEATURE_DEVELOPMENT_VIEW_FILE;
}
function featureDevelopmentViewPath(projectRoot) {
return join7(projectRoot, FEATURE_DEVELOPMENT_VIEW_RELATIVE);
}
function isGeneratedView(text2) {
return text2.startsWith(GENERATED_VIEW_FIRST_LINE);
}
// src/workflows/template-loader.ts
var WorkflowTemplateLoader = class {
constructor(projectRoot) {
this.projectRoot = projectRoot;
}
projectRoot;
get workflowsDir() {
return join8(this.projectRoot, "docs", "instructions", "workflows");
}
async load(workflowName) {
const filePath = join8(this.workflowsDir, `${workflowName}.yaml`);
const raw = await readFile4(filePath, "utf8");
return import_yaml.default.parse(raw);
}
async list() {
try {
const files = await readdir(this.workflowsDir);
return files.filter(
(f) => (f.endsWith(".yaml") || f.endsWith(".yml")) && !isFeatureDevelopmentViewFile(f)
).map((f) => f.replace(/\.(yaml|yml)$/, ""));
} catch {
return [];
}
}
};
// src/context/semantic-loader.ts
var SemanticLoader = class {
constructor(options) {
this.options = options;
this.chunker = new AstChunker();
this.indexManager = new ChunkIndexManager(options.projectRoot);
this.scorer = new RelevanceScorer();
this.allocator = new BudgetAllocator();
this.rag = new RagService(options.projectRoot);
this.supportedExtensions = loadSupportedExtensions(options.projectRoot);
this.priorityClassifier = new PriorityClassifier();
}
options;
chunker;
indexManager;
scorer;
allocator;
rag;
supportedExtensions;
priorityClassifier;
reranker;
async load(artifacts, loadOptions) {
const sourcePaths = artifacts.map((a) => a.path).filter((p) => this.isSupportedFile(p));
let tokensBefore = 0;
for (const artifact of artifacts) {
if (artifact.content) {
tokensBefore += Math.ceil(artifact.content.length / 4);
}
}
if (loadOptions.fullContextOverride) {
const overrideChunks = artifacts.map((a) => this.artifactToChunk(a));
const tokensAfter2 = overrideChunks.reduce(
(sum, c) => sum + Math.ceil(c.content.length / 4),
0
);
const stats2 = {
session_id: this.options.sessionId,
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
tokens_before: tokensBefore,
tokens_after: tokensAfter2,
reduction_pct: tokensBefore > 0 ? Math.round((tokensBefore - tokensAfter2) / tokensBefore * 100) : 0,
chunks_loaded: overrideChunks.length
};
await this.persistStats(stats2);
return {
chunks: overrideChunks,
stats: stats2,
action_recommendations: void 0
};
}
const sync = await this.indexManager.sync(sourcePaths, this.chunker);
const index = sync.index;
const allChunks = index.entries.flatMap((entry) => {
const modifiedAtMs = Date.parse(entry.modified_at);
return entry.chunks.map((chunk) => ({
...chunk,
modified_at_ms: Number.isFinite(modifiedAtMs) ? modifiedAtMs : void 0
}));
});
const profile = readProjectProfile(this.options.projectRoot);
const intelligence = normalizeIntelligenceConfig(profile?.intelligence);
if (!this.reranker) {
this.reranker = createReranker(intelligence.reranking);
}
const adaptiveConfig = intelligence.adaptive_retrieval;
const adaptiveEnabled = adaptiveConfig.enabled;
const minUsefulChunks = adaptiveConfig.thresholds.min_useful_chunks;
const depthInput = {
complexity: loadOptions.classification?.complexity,
risk: loadOptions.classification?.risk,
scope: loadOptions.classification?.scope,
workflow: loadOptions.classification?.workflow ?? null
};
let depth = adaptiveEnabled ? selectRetrievalDepth(depthInput) : "standard";
const retrievalInput = {
taskDescription: loadOptions.taskDescription,
keywords: loadOptions.taskKeywords,
targetFilePath: loadOptions.taskTargetFile,
symbolReferences: loadOptions.symbolReferences
};
const metadataFiltersEnabled = intelligence.metadata_filters.enabled;
const metadataFilters = [];
if (metadataFiltersEnabled) {
const classification = loadOptions.classification;
const targetExt = classification?.file_extension ?? extname2(loadOptions.taskTargetFile ?? "");
if (targetExt) {
metadataFilters.push({ type: "file_extension", value: targetExt });
}
for (const mod of classification?.affected_modules ?? []) {
metadataFilters.push({ type: "module_path_prefix", value: mod });
}
for (const framework of classification?.frameworks ?? profile?.stack_profile?.frameworks ?? []) {
metadataFilters.push({ type: "framework", value: framework });
}
if (classification?.recency_cutoff_ms !== void 0) {
metadataFilters.push({
type: "recency_cutoff_ms",
value: classification.recency_cutoff_ms
});
}
}
let ragResult = await this.rag.retrieve(
sync,
retrievalInput,
topNForDepth(depth, intelligence.rag_top_n)
);
let scoringCtx = {
keywords: loadOptions.taskKeywords,
targetFilePath: loadOptions.taskTargetFile,
symbolReferences: loadOptions.symbolReferences,
sessionStartMs: Date.now(),
vectorScores: ragResult.vector_scores
};
const ragBoundedCorpus = new Set(ragResult.retrieved_chunk_ids);
const corpus = intelligence.rag_enabled && ragBoundedCorpus.size > 0 ? allChunks.filter((chunk) => ragBoundedCorpus.has(chunk.id)) : allChunks;
let scorerResult = this.scorer.filterAndRank(corpus, scoringCtx, metadataFilters);
let ranked = scorerResult.chunks;
let escalated = false;
if (adaptiveEnabled && intelligence.rag_enabled && ranked.length < minUsefulChunks && depth !== "deep") {
depth = escalateDepth(depth);
ragResult = await this.rag.retrieve(
sync,
retrievalInput,
topNForDepth(depth, intelligence.rag_top_n)
);
scoringCtx = { ...scoringCtx, vectorScores: ragResult.vector_scores };
const escalatedIds = new Set(ragResult.retrieved_chunk_ids);
const escalatedCorpus = intelligence.rag_enabled && escalatedIds.size > 0 ? allChunks.filter((chunk) => escalatedIds.has(chunk.id)) : allChunks;
scorerResult = this.scorer.filterAndRank(escalatedCorpus, scoringCtx, metadataFilters);
ranked = scorerResult.chunks;
escalated = true;
}
const rerankingCfg = intelligence.reranking;
const candidatePoolSize = rerankingCfg.candidate_pool_size;
const rerankResult = await this.reranker.rerank(
loadOptions.taskDescription ?? loadOptions.taskKeywords.join(" "),
ranked,
candidatePoolSize
);
const reranked = rerankResult.chunks;
const allocation = this.allocator.allocate(loadOptions.tokenBudget, {
complexity: loadOptions.classification?.complexity,
scope: loadOptions.classification?.scope
});
const packed = this.packChunksByPriority(reranked, allocation, loadOptions.taskTargetFile);
const tokensAfter = packed.reduce((sum, c) => sum + Math.ceil(c.content.length / 4), 0);
const stats = {
session_id: this.options.sessionId,
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
tokens_before: tokensBefore,
tokens_after: tokensAfter,
reduction_pct: tokensBefore > 0 ? Math.round((tokensBefore - tokensAfter) / tokensBefore * 100) : 0,
chunks_loaded: packed.length,
rag_chunks_retrieved: ragResult.chunks_retrieved,
rag_fallback_reason: ragResult.fallback_reason,
retrieval_depth: depth,
retrieval_escalated: escalated || void 0,
reranking: rerankingCfg.enabled ? {
enabled: true,
backend: this.reranker.backend,
model: this.reranker.model,
candidate_pool_size: candidatePoolSize,
pre_rerank_chunk_ids: rerankResult.pre_rerank_ids,
post_rerank_chunk_ids: rerankResult.post_rerank_ids,
latency_ms: rerankResult.latency_ms
} : void 0,
fusion_strategy: scorerResult.fusion_strategy
};
await this.persistStats(stats);
let action_recommendations;
if (intelligence.action_routing?.enabled) {
const workflowLoader = new WorkflowTemplateLoader(this.options.projectRoot);
const workflowIds = await workflowLoader.list();
const router = new ActionRouter();
const suggestions = router.suggestActions(packed, loadOptions.classification, workflowIds);
action_recommendations = suggestions.length > 0 ? suggestions : void 0;
}
return { chunks: packed, stats, action_recommendations };
}
isSupportedFile(path10) {
return Array.from(this.supportedExtensions).some((extension) => path10.endsWith(extension));
}
artifactToChunk(artifact) {
const content = artifact.content ?? "";
return {
id: artifact.path,
source_file: artifact.path,
ast_node_type: "fallback",
ast_node_path: artifact.path,
exported_symbols: [],
content,
char_count: content.replace(/\s/g, "").length,
content_hash: ""
};
}
async persistStats(stats) {
try {
const statsPath = join9(this.options.projectRoot, ".paqad", "context", "load-stats.json");
await mkdir5(dirname7(statsPath), { recursive: true });
await writeFile5(statsPath, JSON.stringify(stats, null, 2), "utf8");
} catch {
}
}
packChunksByPriority(chunks, allocation, taskTargetFile) {
const critical = [];
const taskRelevant = [];
const supporting = [];
for (const chunk of chunks) {
const tier = this.classifyChunkPriority(chunk, taskTargetFile);
if (tier === "critical") {
critical.push(chunk);
} else if (tier === "high" || tier === "medium") {
taskRelevant.push(chunk);
} else {
supporting.push(chunk);
}
}
const packed = [];
const consume = (candidates, budget) => {
const next = this.allocator.packChunks(candidates, budget);
packed.push(...next);
const used = next.reduce((sum, chunk) => sum + Math.ceil(chunk.content.length / 4), 0);
return { used };
};
const criticalResult = consume(critical, allocation.critical_budget);
const taskBudget = allocation.task_relevant_budget + (allocation.critical_budget - criticalResult.used);
const taskResult = consume(taskRelevant, taskBudget);
const supportingBudget = allocation.supporting_budget + (taskBudget - taskResult.used);
consume(supporting, supportingBudget);
return packed;
}
classifyChunkPriority(chunk, taskTargetFile) {
if (taskTargetFile && chunk.source_file === taskTargetFile) {
return this.priorityClassifier.classify(chunk.source_file, "current-file");
}
return this.priorityClassifier.classify(chunk.source_file, "chunk");
}
};
function loadSupportedExtensions(projectRoot) {
const defaults = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".php", ".dart"]);
const profile = readProjectProfile(projectRoot);
const frameworks = profile?.stack_profile?.frameworks ?? [];
for (const pack of getPacksForFrameworks(frameworks, projectRoot)) {
for (const extension of pack.manifest.ast?.file_extensions ?? []) {
defaults.add(extension);
}
}
return defaults;
}
// src/compliance/index.ts
init_esm_shims();
// src/compliance/types.ts
init_esm_shims();
// src/compliance/index-store.ts
init_esm_shims();
import { readFile as readFile5, mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
import path from "path";
async function loadObligationIndex(options) {
const indexPath = resolveIndexPath(options.project_root, options.index_path);
try {
const raw = await readFile5(indexPath, "utf8");
return JSON.parse(raw);
} catch (error) {
if (isEnoentError(error)) {
return null;
}
throw error;
}
}
async function saveObligationIndex(options) {
const indexPath = resolveIndexPath(options.project_root, options.index_path);
await mkdir6(path.dirname(indexPath), { recursive: true });
await writeFile6(indexPath, JSON.stringify(options.index, null, 2) + "\n", "utf8");
return toPosixPath(indexPath);
}
function resolveIndexPath(projectRoot, indexPath) {
return path.resolve(projectRoot, indexPath ?? DEFAULT_OBLIGATION_INDEX_PATH);
}
function isEnoentError(error) {
if (!error || typeof error !== "object") return false;
return "code" in error && error.code === "ENOENT";
}
// src/compliance/compliance-checker.ts
init_esm_shims();
var import_fast_glob = __toESM(require_out(), 1);
import { mkdir as mkdir7, readFile as readFile6, writeFile as writeFile7 } from "fs/promises";
import path2 from "path";
var DEFAULT_TEST_GLOBS = ["tests/**/*.{test,spec}.{ts,tsx,js,jsx}", "tests/**/*.test.ts"];
var OBLIGATION_ANNOTATION_PATTERN = /@obligation\s+([A-Z][A-Z0-9._-]*)\b/g;
var TEST_CALL_PATTERN = /(?:it|test|describe)\s*\(\s*['"`]([^'"`\n]*)/g;
async function checkSpecCompliance(options) {
if (options.signal?.aborted) {
throw new CancelledError("Compliance check cancelled by consumer");
}
const testGlobs = options.test_globs && options.test_globs.length > 0 ? options.test_globs : DEFAULT_TEST_GLOBS;
const { sortedFiles, testFilesHash } = await computeTestFilesHash(
options.project_root,
testGlobs
);
if (options.report_path) {
const cached2 = await loadCachedReport(options.project_root, options.report_path);
if (cached2 && cached2.metadata.spec_hash === options.index.metadata.spec_hash && cached2.metadata.test_files_hash === testFilesHash) {
return { ...cached2, metadata: { ...cached2.metadata, cache_hit: true } };
}
}
const evidence = await scanEvidence(sortedFiles);
const obligations = options.index.obligations.map((obligation) => {
const annotationEvidence = evidence.byObligationId.get(obligation.obligation_id) ?? [];
const testNameEvidence = getTestNameEvidence(
obligation.obligation_id,
evidence.testNamesByFile
);
const state = computeState(
obligation.obligation_id,
annotationEvidence,
testNameEvidence,
evidence
);
const allEvidence = [.../* @__PURE__ */ new Set([...annotationEvidence, ...testNameEvidence])].sort(
(a, b) => a.localeCompare(b)
);
return {
...obligation,
state,
evidence: allEvidence
};
});
const summary = summarize(obligations);
const uncovered_obligations = obligations.filter((o) => o.state === "uncovered").map((o) => o.obligation_id);
const report = {
metadata: {
spec_file: options.index.metadata.spec_file,
spec_hash: options.index.metadata.spec_hash,
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
schema_version: COMPLIANCE_SCHEMA_VERSION,
test_files_hash: testFilesHash,
cache_hit: false
},
summary,
spec_review: summarizeSpecReview(options.spec_review),
obligations,
uncovered_obligations
};
if (options.signal?.aborted) {
throw new CancelledError("Compliance check cancelled by consumer");
}
if (options.report_path) {
await persistReport(options.project_root, options.report_path, report);
}
return report;
}
function summarizeSpecReview(review) {
if (!review) return null;
const activeDefects = review.defects.filter((defect) => defect.status !== "resolved");
const criticalCount = activeDefects.filter((defect) => defect.severity === "critical").length;
return {
defect_count: activeDefects.length,
critical_count: criticalCount,
warning: criticalCount > 0 ? `${criticalCount} critical spec defects remain unresolved \u2014 compliance results may be unreliable.` : null
};
}
function assertComplianceSummaryInvariants(summary) {
enforceSummaryInvariants(summary);
}
var FILE_SEPARATOR = String.fromCharCode(1);
async function computeTestFilesHash(projectRoot, globs) {
const matches = await (0, import_fast_glob.default)(globs, { cwd: projectRoot, absolute: true, onlyFiles: true });
const sortedFiles = [...new Set(matches)].sort((a, b) => a.localeCompare(b));
if (sortedFiles.length === 0) {
return { sortedFiles, testFilesHash: sha256Hex("") };
}
const contents = await Promise.all(sortedFiles.map((f) => readFile6(f, "utf8")));
const hashInput = sortedFiles.map((f, i) => `${f}\0${contents[i]}`).join(FILE_SEPARATOR);
return { sortedFiles, testFilesHash: sha256Hex(hashInput) };
}
async function loadCachedReport(projectRoot, reportPath2) {
try {
const fullPath = path2.resolve(projectRoot, reportPath2);
const raw = await readFile6(fullPath, "utf8");
return JSON.parse(raw);
} catch {
return null;
}
}
async function persistReport(projectRoot, reportPath2, report) {
const fullPath = path2.resolve(projectRoot, reportPath2);
await mkdir7(path2.dirname(fullPath), { recursive: true });
await writeFile7(fullPath, JSON.stringify(report, null, 2) + "\n", "utf8");
}
function extractTestCallNames(body) {
const names = [];
for (const m of body.matchAll(TEST_CALL_PATTERN)) {
names.push(m[1]);
}
return names;
}
function getTestNameEvidence(obligationId, testNamesByFile) {
const hits = [];
for (const [filePath, names] of testNamesByFile) {
if (names.some((name) => name.includes(obligationId))) {
hits.push(filePath);
}
}
return hits.sort((a, b) => a.localeCompare(b));
}
async function scanEvidence(sortedFiles) {
const contents = await Promise.all(
sortedFiles.map(async (filePath) => [filePath, await readFile6(filePath, "utf8")])
);
const fileContents = new Map(contents);
const byObligationId = /* @__PURE__ */ new Map();
const testNamesByFile = /* @__PURE__ */ new Map();
for (const [filePath, body] of contents) {
const annotationMatches = [...body.matchAll(OBLIGATION_ANNOTATION_PATTERN)];
for (const match of annotationMatches) {
const id = match[1];
const list = byObligationId.get(id) ?? [];
if (!list.includes(filePath)) {
list.push(filePath);
}
byObligationId.set(id, list);
}
testNamesByFile.set(filePath, extractTestCallNames(body));
}
return { byObligationId, testNamesByFile, fileContents };
}
function computeState(obligationId, annotationEvidence, testNameEvidence, scan) {
if (annotationEvidence.length > 0 || testNameEvidence.length > 0) {
return "covered";
}
const referencedAnywhere = [...scan.fileContents.values()].some(
(body) => body.includes(obligationId)
);
if (referencedAnywhere) {
return "partial";
}
if (obligationId.startsWith("GEN-")) {
return "indeterminate";
}
return "uncovered";
}
function summarize(obligations) {
const summary = {
total: obligations.length,
covered: 0,
partial: 0,
uncovered: 0,
indeterminate: 0,
compliance_ratio: 0
};
for (const obligation of obligations) {
summary[obligation.state] += 1;
}
const denominator = summary.total - summary.indeterminate;
summary.compliance_ratio = denominator === 0 ? 1 : summary.covered / denominator;
enforceSummaryInvariants(summary);
return summary;
}
function enforceSummaryInvariants(summary) {
const sum = summary.covered + summary.partial + summary.uncovered + summary.indeterminate;
if (sum !== summary.total) {
throw new Error(
`Compliance invariant violated: state sum ${sum} does not equal total ${summary.total}`
);
}
if (summary.uncovered > 0 && summary.compliance_ratio >= 1) {
throw new Error(
"Compliance invariant violated: uncovered obligations imply compliance_ratio < 1.0"
);
}
}
// src/compliance/doctor.ts
init_esm_shims();
// src/compliance/boundary/types.ts
init_esm_shims();
var BOUNDARY_SCHEMA_VERSION = 1;
// src/compliance/doctor.ts
function doctorObligationIndex(index) {
const issues = [];
if (!index) {
issues.push({ level: "warning", message: "No obligation index found." });
return { ok: true, issues };
}
if (index.metadata.schema_version !== COMPLIANCE_SCHEMA_VERSION) {
issues.push({
level: "error",
message: `Unsupported compliance schema_version ${index.metadata.schema_version}. Expected ${COMPLIANCE_SCHEMA_VERSION}.`
});
}
const seen = /* @__PURE__ */ new Set();
for (const obligation of index.obligations) {
if (seen.has(obligation.obligation_id)) {
issues.push({
level: "error",
message: `Duplicate obligation_id "${obligation.obligation_id}".`
});
}
seen.add(obligation.obligation_id);
}
return { ok: issues.every((issue) => issue.level !== "error"), issues };
}
function doctorBoundaryReport(report) {
const issues = [];
if (!report) {
issues.push({
level: "warning",
message: "No boundary report found. Run `compliance boundary` to generate one."
});
return { ok: true, issues };
}
if (report.metadata.schema_version !== BOUNDARY_SCHEMA_VERSION) {
issues.push({
level: "error",
message: `Unsupported boundary schema_version ${report.metadata.schema_version}. Expected ${BOUNDARY_SCHEMA_VERSION}.`
});
}
if (report.unhandled_count > 0) {
issues.push({
level: "warning",
message: `${report.unhandled_count} unhandled boundary variant${report.unhandled_count === 1 ? "" : "s"} detected. Run \`compliance boundary --generate\` to create test stubs.`
});
}
return { ok: issues.every((issue) => issue.level !== "error"), issues };
}
function doctorSpecReview(review, options) {
const issues = [];
if (!review) {
issues.push({ level: "warning", message: "No spec review report found." });
return { ok: true, issues };
}
if (review.metadata.schema_version !== SPEC_REVIEW_SCHEMA_VERSION) {
issues.push({
level: "error",
message: `Unsupported spec review schema_version ${review.metadata.schema_version}. Expected ${SPEC_REVIEW_SCHEMA_VERSION}.`
});
}
if (options?.spec_is_newer) {
issues.push({
level: "warning",
message: "Spec review is stale because the spec was modified after the last review."
});
}
return { ok: issues.every((issue) => issue.level !== "error"), issues };
}
// src/compliance/spec-review-store.ts
init_esm_shims();
import { mkdir as mkdir8, readFile as readFile7, writeFile as writeFile8 } from "fs/promises";
import path3 from "path";
async function loadSpecReviewReport(options) {
const reviewPath = resolveReviewPath(
options.project_root,
options.review_path,
options.spec_file
);
try {
const raw = await readFile7(reviewPath, "utf8");
return JSON.parse(raw);
} catch (error) {
if (isEnoentError(error)) {
return null;
}
throw error;
}
}
async function saveSpecReviewReport(options) {
const reviewPath = resolveReviewPath(
options.project_root,
options.review_path,
options.spec_file
);
await mkdir8(path3.dirname(reviewPath), { recursive: true });
await writeFile8(reviewPath, JSON.stringify(options.report, null, 2) + "\n", "utf8");
return reviewPath;
}
function resolveReviewPath(projectRoot, reviewPath, specFile) {
const relativePath = reviewPath ?? (specFile ? specReviewPath(specFile) : void 0);
if (!relativePath) {
throw new Error("spec_file or review_path is required to resolve the spec review path");
}
return path3.resolve(projectRoot, relativePath);
}
// src/compliance/skeletons/vitest.ts
init_esm_shims();
import { access, mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
import path4 from "path";
async function generateVitestSkeletons(options) {
const outDir = path4.resolve(options.project_root, options.output_dir);
await mkdir9(outDir, { recursive: true });
const written = [];
for (const obligation of options.obligations) {
const fileName = `${sanitize(obligation.obligation_id)}.test.ts`;
const filePath = path4.join(outDir, fileName);
const exists2 = await fileExists(filePath);
if (!exists2) {
const contents = renderVitestSkeleton(obligation);
await writeFile9(filePath, contents, "utf8");
}
written.push(filePath);
}
written.sort((left, right) => left.localeCompare(right));
return written;
}
function renderVitestSkeleton(obligation) {
const desc = obligation.description.trim().length > 0 ? obligation.description.trim() : `Obligation ${obligation.obligation_id}`;
const passCriteria = obligation.pass_criteria?.trim() ?? "N/A";
const sourceLocation = obligation.source_line !== null ? `${obligation.source_section} (line ${obligation.source_line})` : obligation.source_section;
const testName = `${obligation.obligation_id}: ${desc}`;
return `import { describe, it, expect } from 'vitest';
describe('Spec compliance obligation', () => {
/**
* @obligation ${obligation.obligation_id}
* Description: ${desc}
* Pass criteria: ${passCriteria}
* Source: ${sourceLocation}
*/
it(${JSON.stringify(testName)}, () => {
// @obligation ${obligation.obligation_id}
expect(false, 'TODO: implement test for this obligation').toBe(true);
});
});
`;
}
async function fileExists(filePath) {
try {
await access(filePath);
return true;
} catch {
return false;
}
}
function sanitize(obligationId) {
return obligationId.replace(/[^a-zA-Z0-9._-]+/g, "-");
}
// src/compliance/boundary/index.ts
init_esm_shims();
// src/compliance/boundary/detector.ts
init_esm_shims();
var ANNOTATION_PATTERN = /\/\/\s*@boundary\s+([A-Za-z_]\w*)(?:\s+producer:([^\s]+))?(?:\s+consumer:([^\s]+))?(?:\s+states:([^\s]+))?/;
var ENUM_OPEN_PATTERN = /\benum\s+([A-Za-z_]\w*)\s*\{/;
var UNION_TYPE_PATTERN = /\btype\s+([A-Za-z_]\w*)\s*=([^;]+);/;
function detectBoundariesInSource(filePath, source) {
const lines = source.split("\n");
const boundaries = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const annotationMatch = ANNOTATION_PATTERN.exec(line);
if (!annotationMatch) continue;
const typeName = annotationMatch[1];
const producerSpec = annotationMatch[2] ?? null;
const consumerSpecs = annotationMatch[3] ? annotationMatch[3].split(",") : [];
const explicitStates = annotationMatch[4] ? annotationMatch[4].split(",") : null;
const nextLine = findNextNonBlank(lines, i + 1);
const states = explicitStates ?? extractStatesFromDefinition(lines, nextLine);
const relationship = classifyRelationship(producerSpec, consumerSpecs, states);
boundaries.push({
type_name: typeName,
file: filePath,
producer_spec: producerSpec,
consumer_specs: consumerSpecs,
output_states: states,
relationship
});
}
return boundaries;
}
function findNextNonBlank(lines, from) {
for (let i = from; i < lines.length; i++) {
if (lines[i].trim()) return i;
}
return from;
}
function extractStatesFromDefinition(lines, lineIndex) {
const line = lines[lineIndex] ?? "";
const enumMatch = ENUM_OPEN_PATTERN.exec(line);
if (enumMatch) {
return extractEnumMembers(lines, lineIndex);
}
const unionMatch = UNION_TYPE_PATTERN.exec(line);
const unionBody = unionMatch?.[2]?.trim();
if (unionBody) {
return extractUnionMembers(unionBody);
}
return [];
}
function extractEnumMembers(lines, openLineIndex) {
const members = [];
let body = "";
let depth = 0;
for (let i = openLineIndex; i < lines.length; i++) {
const text2 = lines[i];
for (const ch of text2) {
if (ch === "{") depth++;
else if (ch === "}") depth--;
}
body += text2 + "\n";
if (depth === 0 && i > openLineIndex) break;
}
const memberPattern = /\b([A-Za-z_]\w*)\s*(?:=|,|\n|})/g;
for (const match of body.matchAll(memberPattern)) {
const name = match[1];
if (name === "enum" || name === "const" || name === "export") continue;
members.push(name);
}
return [...new Set(members)];
}
function extractUnionMembers(rhs) {
const members = [];
for (const rawPart of rhs.split("|")) {
const part = rawPart.trim();
if (!part) continue;
const quoted = part.match(/^(['"`])(.+)\1$/);
if (quoted) {
members.push(quoted[2].trim());
continue;
}
const identifier = part.match(/^([A-Za-z_]\w*)$/);
if (identifier) {
members.push(identifier[1]);
}
}
return [...new Set(members)];
}
function classifyRelationship(producer, consumers, states) {
if (states.length === 0) return "unanalyzable";
if (!producer && consumers.length === 0) return "shared_utility";
if (producer && consumers.length > 0) return "producer_consumer";
return "shared_utility";
}
// src/compliance/boundary/extractor.ts
init_esm_shims();
function extractUnhandledVariants(boundary, specTexts) {
const unhandledByConsumer = /* @__PURE__ */ new Map();
for (const consumerSpec of boundary.consumer_specs) {
const specText = specTexts.get(consumerSpec) ?? "";
const specLower = specText.toLowerCase();
const unhandled = boundary.output_states.filter((state) => !specLower.includes(state.toLowerCase())).map((state) => ({
type_name: boundary.type_name,
state,
producer_spec: boundary.producer_spec,
consumer_spec: consumerSpec
}));
unhandledByConsumer.set(consumerSpec, unhandled);
}
return { boundary, unhandled_by_consumer: unhandledByConsumer };
}
// src/compliance/boundary/generator.ts
init_esm_shims();
import { mkdir as mkdir10, readFile as readFile8, writeFile as writeFile10 } from "fs/promises";
import path5 from "path";
async function generateBoundaryTests(options) {
const outputDir = path5.resolve(
options.project_root,
options.output_dir ?? ".paqad/compliance/boundary-tests"
);
await mkdir10(outputDir, { recursive: true });
const results = [];
for (const consumer of options.boundary.consumer_specs) {
const fileName = buildFileName(options.boundary, consumer);
const filePath = path5.join(outputDir, fileName);
const content = renderTestFile(options.boundary, consumer, options.unhandled);
const written = await writeIfChanged2(filePath, content);
results.push({ file_path: filePath, written });
}
return results;
}
function buildFileName(boundary, consumerSpec) {
const producer = boundary.producer_spec ?? "unknown";
const slugify4 = (s) => trimChar(s.replace(/[^a-z0-9]+/gi, "-"), "-");
return `${slugify4(producer)}__${slugify4(consumerSpec)}__${boundary.type_name}.test.ts`;
}
function renderTestFile(boundary, consumerSpec, allUnhandled) {
const unhandledStates = new Set(
allUnhandled.filter((u) => u.consumer_spec === consumerSpec).map((u) => u.state)
);
const testBlocks = boundary.output_states.map((state) => {
const isUnhandled = unhandledStates.has(state);
const unhandledComment = isUnhandled ? ` // NOTE: this state is produced by ${boundary.producer_spec ?? "unknown"} but not explicitly handled by ${consumerSpec}.
` : "";
return [
` it('handles ${boundary.type_name} state: ${state}', () => {`,
unhandledComment,
` // TODO: construct a ${boundary.type_name} fixture in state "${state}" and pass it`,
` // to the consumer entry point. Assert no crash or unhandled-case error.`,
` expect(true).toBe(true); // replace with real assertion`,
` });`
].filter(Boolean).join("\n");
});
return [
`/**`,
` * Boundary test: ${boundary.type_name}`,
` * Producer: ${boundary.producer_spec ?? "unknown"}`,
` * Consumer: ${consumerSpec}`,
` *`,
` * Auto-generated by compliance boundary. Do not edit header.`,
` * Add assertions to each stub; header will be preserved on regeneration.`,
` */`,
`import { describe, expect, it } from 'vitest';`,
``,
`describe('boundary: ${boundary.type_name} \u2192 ${consumerSpec}', () => {`,
...testBlocks,
`});`,
``
].join("\n");
}
async function writeIfChanged2(filePath, content) {
try {
const existing = await readFile8(filePath, "utf8");
if (existing === content) return false;
} catch {
}
await writeFile10(filePath, content, "utf8");
return true;
}
// src/compliance/boundary/report.ts
init_esm_shims();
import { mkdir as mkdir11, readFile as readFile9, writeFile as writeFile11 } from "fs/promises";
import path6 from "path";
var DEFAULT_BOUNDARY_REPORT_PATH = ".paqad/compliance/boundary-report.json";
function buildBoundaryReport(results) {
if (results.length === 0) {
return {
metadata: { generated_at: (/* @__PURE__ */ new Date()).toISOString(), schema_version: BOUNDARY_SCHEMA_VERSION },
total_interfaces: 0,
total_states: 0,
handled_count: 0,
unhandled_count: 0,
gate_result: "skip",
interfaces: []
};
}
let totalStates = 0;
let unhandledCount = 0;
const interfaces = results.map((result2) => {
const allUnhandled = [...result2.unhandled_by_consumer.values()].flat();
totalStates += result2.boundary.output_states.length * result2.boundary.consumer_specs.length;
unhandledCount += allUnhandled.length;
return {
type_name: result2.boundary.type_name,
file: result2.boundary.file,
producer_spec: result2.boundary.producer_spec,
consumer_specs: result2.boundary.consumer_specs,
total_states: result2.boundary.output_states.length,
unhandled_variants: allUnhandled
};
});
const handledCount = totalStates - unhandledCount;
const gateResult = unhandledCount > 0 ? "warn" : "pass";
return {
metadata: { generated_at: (/* @__PURE__ */ new Date()).toISOString(), schema_version: BOUNDARY_SCHEMA_VERSION },
total_interfaces: results.length,
total_states: totalStates,
handled_count: handledCount,
unhandled_count: unhandledCount,
gate_result: gateResult,
interfaces
};
}
async function saveBoundaryReport(report, projectRoot, reportPath2 = DEFAULT_BOUNDARY_REPORT_PATH) {
const fullPath = path6.resolve(projectRoot, reportPath2);
await mkdir11(path6.dirname(fullPath), { recursive: true });
await writeFile11(fullPath, JSON.stringify(report, null, 2) + "\n", "utf8");
return fullPath;
}
async function loadBoundaryReport(projectRoot, reportPath2 = DEFAULT_BOUNDARY_REPORT_PATH) {
try {
const fullPath = path6.resolve(projectRoot, reportPath2);
const raw = await readFile9(fullPath, "utf8");
return JSON.parse(raw);
} catch {
return null;
}
}
// src/compliance/boundary/scanner.ts
init_esm_shims();
var import_fast_glob2 = __toESM(require_out(), 1);
import { readFile as readFile10 } from "fs/promises";
import path7 from "path";
async function scanBoundaries(options) {
const globs = options.source_globs ?? ["src/**/*.ts"];
const files = await (0, import_fast_glob2.default)(globs, {
cwd: options.project_root,
absolute: true,
onlyFiles: true
});
const allBoundaries = (await Promise.all(
files.map(async (file) => {
const source = await readFile10(file, "utf8");
const relativePath = path7.relative(options.project_root, file);
return detectBoundariesInSource(relativePath, source);
})
)).flat();
const specTexts = await loadSpecTexts(options.spec_paths ?? /* @__PURE__ */ new Map(), options.project_root);
return allBoundaries.map((boundary) => extractUnhandledVariants(boundary, specTexts));
}
async function loadSpecTexts(specPaths, projectRoot) {
const texts = /* @__PURE__ */ new Map();
for (const [slug, specPath] of specPaths) {
try {
const fullPath = path7.isAbsolute(specPath) ? specPath : path7.resolve(projectRoot, specPath);
texts.set(slug, await readFile10(fullPath, "utf8"));
} catch {
texts.set(slug, "");
}
}
return texts;
}
// src/compliance/defect-patterns/index.ts
init_esm_shims();
// src/compliance/defect-patterns/classifier.ts
init_esm_shims();
var CLASSIFICATION_RULES = [
{
pattern: /threshold|magic.?number|hard.?coded.?value|numeric.?literal/i,
subcategory: "D3.threshold-heuristic"
},
{
pattern: /type.?coer|instanceof|typeof.*check|type.?guard/i,
subcategory: "D3.type-coercion-heuristic"
},
{
pattern: /\b(?:cli|command.?line)\b.*(flag|command|option|subcommand|expose|surface)/i,
subcategory: "D5.missing-cli-surface"
},
{
pattern: /(command|flag|option|subcommand).*(?:cli|command.?line)/i,
subcategory: "D5.missing-cli-surface"
},
{
pattern: /\bsubcommand\b.*\b(surface|surfaced|expose|exposed|missing)\b/i,
subcategory: "D5.missing-cli-surface"
},
{
pattern: /boundary|exactly\s+\d|at\s+the\s+limit|off.?by.?one|fence.?post/i,
subcategory: "D5.missing-boundary"
},
{
pattern: /error.*(handling|path|case|state)|failure.*(case|path|mode)|exception/i,
subcategory: "D5.missing-error-handling"
},
{
pattern: /empty.*(case|input|collection|list|array)|no\s+items|zero\s+items/i,
subcategory: "D5.missing-empty-case"
},
{ pattern: /self.?clos|xml|html.*tag|closing.*tag/i, subcategory: "D5.missing-format-variant" },
{
pattern: /format.?(variant|version|flavou?r|dialect)|alternative.?format/i,
subcategory: "D5.missing-format-variant"
},
{
pattern: /enum|state\s+machine|all\s+(possible\s+)?states|\bvariant\b/i,
subcategory: "D5.missing-enum-variant"
},
{
pattern: /file.*(path|location|directory)|wrong.?path|incorrect.?path/i,
subcategory: "D5.wrong-file-path"
},
{
pattern: /negative.*(case|path|test)|when\s+not|otherwise/i,
subcategory: "D5.missing-negative-case"
},
{
pattern: /tautolog|trivial.*test|test.*trivial|assert.*itself/i,
subcategory: "D8.tautological-test"
},
{
pattern: /mock.?only|stub.?only|no.?real.*assert|hollow.*test/i,
subcategory: "D8.mock-only-test"
},
{
pattern: /not\s+in\s+(the\s+)?spec|invented|unspecified\s+logic|undocumented\s+behavior/i,
subcategory: "D1.unspecified-logic"
},
{
pattern: /wrong\s+obligation|mismatched\s+id|incorrect\s+obligation/i,
subcategory: "D2.wrong-obligation-mapping"
}
];
function classifyDefect(description, sourceCategory) {
const normalized = description.toLowerCase();
for (const rule of CLASSIFICATION_RULES) {
if (rule.pattern.test(normalized)) {
return rule.subcategory;
}
}
return `${sourceCategory}.unclassified`;
}
// src/compliance/defect-patterns/recorder.ts
init_esm_shims();
async function recordFromComplianceReport(options) {
const { report } = options;
const stackContext = options.stack_context ?? { frameworks: [], traits: [] };
const now = (/* @__PURE__ */ new Date()).toISOString();
const findings = report.obligations.filter((o) => o.state === "uncovered").map((obligation) => {
const subcategory = classifyDefect(obligation.description, "D5");
return {
defect_id: `${report.metadata.spec_file}:${obligation.obligation_id}`,
source: "compliance",
category: "D5",
subcategory,
spec_file: report.metadata.spec_file,
obligation_id: obligation.obligation_id,
stack_context: stackContext,
description: obligation.description,
file_path: null,
recorded_at: now,
resolved: false,
recurrence_count: 1
};
});
if (findings.length > 0) {
await recordFindings(findings, options.storeRoot);
}
return findings.length;
}
// src/compliance/defect-patterns/advisor.ts
init_esm_shims();
async function buildPatternAdvisories(options) {
const patterns = await queryPatterns(
{
stack_context: options.stack_context,
min_frequency: options.min_frequency,
max_age_days: options.max_age_days
},
options.storeRoot
);
return patterns.map((pattern) => ({
advisory_id: `PA-${pattern.pattern_id}`,
title: `Recurring pattern: ${pattern.subcategory}`,
description: `Based on ${pattern.frequency} prior defect${pattern.frequency === 1 ? "" : "s"}, implementations in this area commonly miss: ${pattern.description}`
}));
}
async function formatAgentContextWarnings(options) {
const patterns = await queryPatterns(
{
stack_context: options.stack_context,
min_frequency: options.min_frequency,
max_age_days: options.max_age_days,
limit: 5
},
options.storeRoot
);
if (patterns.length === 0) return "";
const lines = [
"Common defect patterns for this type of implementation:",
...patterns.map((p) => `- [${p.subcategory}, seen ${p.frequency}x] ${p.description}`),
"Pay specific attention to these areas."
];
return lines.join("\n");
}
// src/core/index.ts
init_esm_shims();
// src/core/constants/index.ts
init_esm_shims();
// src/core/constants/domains.ts
init_esm_shims();
var SUPPORTED_DOMAINS = DOMAINS;
var SUPPORTED_STACKS = STACKS;
var SUPPORTED_CAPABILITIES = CAPABILITIES;
// src/core/constants/exit-codes.ts
init_esm_shims();
var HOOK_EXIT_CODES = {
ALLOW: 0,
ERROR: 1,
BLOCK: 2
};
// src/core/constants/schema.ts
init_esm_shims();
var PAQAD_SCHEMA_VERSION = "1.1.0";
// src/core/logging/index.ts
init_esm_shims();
// src/core/logging/logger.ts
init_esm_shims();
// src/core/logging/redaction.ts
init_esm_shims();
var REDACTION_PLACEHOLDER = "[REDACTED]";
var DEFAULT_REDACTION_ALLOWLIST = Object.freeze([
"credential",
"prompt",
"user_content"
]);
function isPlainObject(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function redactFields(fields, allowlist) {
const blocked = new Set(allowlist);
const redacted = {};
let count2 = 0;
for (const [key, value] of Object.entries(fields)) {
if (blocked.has(key)) {
redacted[key] = REDACTION_PLACEHOLDER;
count2 += 1;
continue;
}
if (isPlainObject(value)) {
const inner = {};
for (const [innerKey, innerValue] of Object.entries(value)) {
if (blocked.has(innerKey)) {
inner[innerKey] = REDACTION_PLACEHOLDER;
count2 += 1;
} else {
inner[innerKey] = innerValue;
}
}
redacted[key] = inner;
continue;
}
redacted[key] = value;
}
return { redacted, count: count2 };
}
// src/core/logging/logger.ts
var LEVEL_ORDER = { debug: 0, info: 1, warn: 2, error: 3 };
function makeLogger(state, correlationId) {
function emit(level, event, fields) {
if (LEVEL_ORDER[level] < LEVEL_ORDER[state.level]) {
return;
}
const { redacted, count: count2 } = redactFields(fields ?? {}, state.allowlist);
state.redactionCount += count2;
const record2 = {
...redacted,
level,
timestamp: state.now(),
runtime: state.runtime,
event,
...correlationId !== void 0 ? { correlation_id: correlationId } : {}
};
state.writeLine(`${JSON.stringify(record2)}
`);
}
return {
debug: (event, fields) => emit("debug", event, fields),
info: (event, fields) => emit("info", event, fields),
warn: (event, fields) => emit("warn", event, fields),
error: (event, fields) => emit("error", event, fields),
log: (level, event, fields) => emit(level, event, fields),
getRedactionCount: () => state.redactionCount,
resetRedactionCount: () => {
state.redactionCount = 0;
},
setLevel: (level) => {
state.level = level;
},
setAllowlist: (list) => {
state.allowlist = list;
},
withCorrelation: (id) => makeLogger(state, id)
};
}
function createLogger(options) {
const state = {
runtime: options.runtime,
level: options.level ?? "info",
allowlist: options.allowlist ?? DEFAULT_REDACTION_ALLOWLIST,
redactionCount: 0,
writeLine: options.writeLine ?? ((line) => void process.stdout.write(line)),
now: options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString())
};
return makeLogger(state, options.correlationId);
}
// src/core/logging/config.ts
init_esm_shims();
var VALID_LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
function isLogLevel(value) {
return value !== void 0 && VALID_LEVELS.has(value);
}
function loadLoggingConfig(overrides) {
const envLevel = process.env.PAQAD_LOG_LEVEL;
return {
level: isLogLevel(envLevel) ? envLevel : "info",
allowlist: DEFAULT_REDACTION_ALLOWLIST,
runtime: "engine",
...overrides
};
}
function reloadLoggingConfig(logger, config) {
logger.setLevel(config.level);
logger.setAllowlist(config.allowlist);
}
var engineLogger;
function getEngineLogger() {
if (engineLogger === void 0) {
const config = loadLoggingConfig();
engineLogger = createLogger({
runtime: config.runtime,
level: config.level,
allowlist: config.allowlist
});
}
return engineLogger;
}
// src/core/schema-version.ts
init_esm_shims();
import {
closeSync,
existsSync as existsSync2,
mkdirSync,
openSync,
readFileSync as readFileSync2,
renameSync as renameSync2,
writeFileSync as writeFileSync2
} from "fs";
import { appendFile, mkdir as mkdir12, readFile as readFile11, rename, unlink, writeFile as writeFile12 } from "fs/promises";
import { dirname as dirname8, join as join10 } from "path";
// src/core/schema-migrators.ts
init_esm_shims();
// src/feature-evidence/migrate.ts
init_esm_shims();
import {
readdirSync,
readFileSync,
renameSync,
rmdirSync,
rmSync,
statSync,
writeFileSync
} from "fs";
// src/spec-pipeline/experts/brief.ts
init_esm_shims();
var CHARS_PER_TOKEN = 4;
function lensPathForRole(role) {
return `runtime/base/skills/expert-notes/references/lenses/${role}.md`;
}
function buildExpertBriefs(input) {
const plan = planExpertSlices(
input.needs.map((need) => need.role),
input.ceiling
);
const grantedByRole = new Map(plan.slices.map((slice) => [slice.role, slice]));
const briefs = input.needs.map((need) => {
const slice = grantedByRole.get(need.role);
const rendered = renderExpertBrief({
...input,
need,
granted: slice.granted,
...input.projectVoice === void 0 ? {} : { projectVoice: input.projectVoice }
});
return { role: need.role, granted: slice.granted, clamped: slice.clamped, ...rendered };
});
return { briefs, warnings: plan.warnings };
}
function rosterEntryFor(need, brief) {
return {
role: need.role,
reason: need.reason,
lens: lensPathForRole(need.role),
budget_tokens: brief.granted,
grounding_truncated: brief.truncated,
brief_hash: brief.hash,
tokens_used: null,
...need.origin === void 0 ? {} : { origin: need.origin }
};
}
function renderExpertBrief(input) {
const pointers = fitGroundingToBudget(input.grounding, input.granted);
const content = renderBrief(input, pointers);
return { truncated: pointers.truncated, content, hash: sha256Hex(content) };
}
function fitGroundingToBudget(grounding, granted) {
const items = grounding.references.map((ref, index) => ({
text: `${ref.kind}: ${ref.ref}`,
index
}));
const budgetChars = granted * CHARS_PER_TOKEN;
const total = items.reduce((sum, item) => sum + item.text.length, 0);
const dropped = /* @__PURE__ */ new Set();
if (total > budgetChars) {
let running = total;
const byLength = [...items].sort((a, b) => b.text.length - a.text.length || a.index - b.index);
for (const item of byLength) {
if (running <= budgetChars) break;
dropped.add(item.index);
running -= item.text.length;
}
}
return {
references: items.filter((item) => !dropped.has(item.index)).map((item) => item.text),
truncated: dropped.size > 0
};
}
function renderBrief(input, pointers) {
const { need } = input;
const lines = [];
lines.push(`# Expert brief \u2014 ${need.role}`, "");
lines.push(`- Lens: \`${lensPathForRole(need.role)}\``);
lines.push(`- Why you were brought in: ${need.reason}`);
lines.push(`- Granted budget: ${input.granted} tokens`);
lines.push(`- Grounding truncated: ${pointers.truncated ? "yes" : "no"}`, "");
lines.push("## Request", "", input.request.trim(), "");
if (input.ticketAcceptanceCriteria && input.ticketAcceptanceCriteria.length > 0) {
lines.push("## Ticket acceptance criteria", "");
for (const criterion of input.ticketAcceptanceCriteria) {
lines.push(`- ${criterion}`);
}
lines.push("");
}
lines.push("## Grounding (pointers, not bodies)", "");
lines.push("References:");
if (pointers.references.length > 0) {
for (const ref of pointers.references) lines.push(`- ${ref}`);
} else {
lines.push("- (none)");
}
lines.push("");
lines.push("## Clarity", "", `- Label: ${input.label.label}`);
if (input.label.signals.length > 0) {
lines.push("- Signals:");
for (const signal5 of input.label.signals) {
lines.push(` - ${signal5.kind}: "${signal5.span}"`);
}
}
lines.push("");
if (input.projectVoice !== void 0 && input.projectVoice.length > 0) {
lines.push(input.projectVoice, "");
}
return `${lines.join("\n")}
`;
}
// src/feature-evidence/migrate.ts
var LEGACY_SPECS_DIR = ".paqad/_specs";
var LEGACY_SPECS_IGNORE_LINE = "_specs/";
var PIPELINE_DIR = "pipeline";
var UNKNOWN = "unknown";
var STAGED_SOURCES = [
["task", "task.json"],
["trace", "trace.json"],
["grounding", "grounding.json"],
["finish", "finish.json"],
["craft", "spec.md"]
];
var MERGED_SOURCES = [
"log.jsonl",
"request.md",
"label.json",
"questions.json",
"experts.json",
"expert-notes.json",
"expert-synthesis.json",
"corrections.jsonl"
];
var RETIRED_SOURCES = ["expert-merge.json"];
var RETIRED_REDO = /\.redo-\d+$/;
var RETIRED_BRIEFS_DIR = "briefs";
var HELD_SESSION_STALE_MS = 24 * 60 * 60 * 1e3;
function readText(abs) {
try {
return readFileSync(abs, "utf8");
} catch {
return null;
}
}
function readJson(abs) {
const raw = readText(abs);
if (raw === null) return void 0;
try {
return JSON.parse(raw);
} catch {
return void 0;
}
}
function atomicWrite(abs, text2) {
const tmp = `${abs}.tmp-${process.pid}`;
writeFileSync(tmp, text2, "utf8");
renameSync(tmp, abs);
}
function isRecord(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function listEntries(abs) {
try {
return readdirSync(abs, { withFileTypes: true }).map((entry) => ({
name: entry.name,
dir: entry.isDirectory()
}));
} catch {
return [];
}
}
function listFilesUnder(abs, prefix = "") {
return listEntries(abs).flatMap((entry) => {
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
return entry.dir ? listFilesUnder(join(abs, entry.name), rel) : [rel];
}).sort();
}
function pipelinePath(projectRoot, run2, file) {
return join(projectRoot, LEGACY_SPECS_DIR, run2, PIPELINE_DIR, file);
}
function readLog(projectRoot, run2, file = "log.jsonl") {
const raw = readText(pipelinePath(projectRoot, run2, file)) ?? "";
return raw.split("\n").flatMap((line) => {
try {
const row = JSON.parse(line);
return isRecord(row) ? [row] : [];
} catch {
return [];
}
});
}
function readRun(projectRoot, name) {
return { name, ulid: featureChangeKey(name), log: readLog(projectRoot, name) };
}
function completedSteps(run2) {
return new Set(
run2.log.filter((row) => row.outcome === "complete" && typeof row.step === "string").map((row) => row.step)
);
}
function isChangePlaceholder(name) {
const parts = parseFeatureDirName(name);
return parts !== null && parts.issue === null && parts.slug === "change";
}
function pickRun(runs) {
const renamed = runs.filter((run2) => !isChangePlaceholder(run2.name));
const finished = renamed.find((run2) => completedSteps(run2).has("finish"));
if (finished) return finished;
return [...runs].sort(
(a, b) => completedSteps(b).size - completedSteps(a).size || Number(isChangePlaceholder(a.name)) - Number(isChangePlaceholder(b.name)) || a.name.localeCompare(b.name)
)[0];
}
function bundleClosed(projectRoot, bundle) {
return readUnitFile(projectRoot, featureFilePath(bundle, "stageEvidence")).some(
(row) => row.kind === "close"
);
}
function lastSeenMs(updatedAt, rows, sessionId) {
const times = [
Date.parse(updatedAt),
...rows.filter((row) => row.session_id === sessionId).map((row) => Date.parse(rowRecordedAt(row)))
].filter((time) => !Number.isNaN(time));
return times.length === 0 ? Number.NEGATIVE_INFINITY : Math.max(...times);
}
function heldByAnotherSession(projectRoot, bundle, hold) {
if (bundleClosed(projectRoot, bundle)) return false;
let rows = null;
for (const entry of listEntries(join(projectRoot, PATHS.FEATURE_EVIDENCE_SESSION_DIR))) {
if (entry.dir || !entry.name.endsWith(".json")) continue;
const sessionId = entry.name.slice(0, -".json".length);
if (sessionId === hold.self) continue;
const control = readSessionControl(projectRoot, sessionId);
if (control.active !== bundle && !control.paused.includes(bundle)) continue;
rows ??= readUnitFile(projectRoot, featureFilePath(bundle, "stageEvidence"));
if (hold.nowMs - lastSeenMs(control.updated_at, rows, sessionId) <= hold.staleAfterMs) {
return true;
}
}
return false;
}
function bundleHas(projectRoot, bundle, file) {
return readText(join(projectRoot, featureFilePath(bundle, file))) !== null;
}
function stepRowsFrom(run2) {
return run2.log.flatMap((row) => {
const outcome = row.outcome;
if (typeof row.step !== "string" || row.step.length === 0) return [];
if (!SPEC_STEP_OUTCOMES.includes(outcome)) return [];
const hash = typeof row.hash === "string" ? row.hash : row.artifact_hash;
const tokens = row.tokens;
return [
{
step: row.step,
outcome,
hash: typeof hash === "string" ? hash : "",
...typeof tokens === "number" && Number.isInteger(tokens) && tokens >= 0 ? { tokens } : {},
at: typeof row.ts === "string" && !Number.isNaN(Date.parse(row.ts)) ? row.ts : null
}
];
});
}
function correctionsFrom(projectRoot, run2) {
return readLog(projectRoot, run2.name, "corrections.jsonl").flatMap((row) => {
if (typeof row.spec_id !== "string" || row.spec_id.length === 0) return [];
const sections2 = Array.isArray(row.changed_sections) ? row.changed_sections : [];
return [
{
spec_id: row.spec_id,
changed_sections: sections2.filter((item) => typeof item === "string"),
at: typeof row.at === "string" && !Number.isNaN(Date.parse(row.at)) ? row.at : null
}
];
});
}
function missingCorrections(corrections, existing) {
const rows = existing.filter((row) => row.kind === SPEC_CORRECTION_KIND);
const used = /* @__PURE__ */ new Set();
return corrections.filter((correction) => {
const index = rows.findIndex(
(row, i) => !used.has(i) && row.spec_id === correction.spec_id && (correction.at === null ? JSON.stringify(row.changed_sections) === JSON.stringify(correction.changed_sections) : Date.parse(rowRecordedAt(row)) === Date.parse(correction.at))
);
if (index === -1) return true;
used.add(index);
return false;
});
}
function frozenSpecHash(projectRoot, bundle) {
const spec = readJson(join(projectRoot, featureFilePath(bundle, "specification")));
if (!isRecord(spec)) return void 0;
return typeof spec.spec_hash === "string" ? spec.spec_hash : null;
}
function stepKey(step, hash) {
return `${String(step)}\0${typeof hash === "string" ? hash : ""}`;
}
function missingSteps(steps, existing) {
const have = /* @__PURE__ */ new Map();
for (const row of existing) {
if (row.kind !== "spec-step") continue;
const key = stepKey(row.step, row.artifact_hash);
have.set(key, (have.get(key) ?? 0) + 1);
}
return steps.filter((step) => {
const key = stepKey(step.step, step.hash);
const count2 = have.get(key) ?? 0;
if (count2 === 0) return true;
have.set(key, count2 - 1);
return false;
});
}
function planMerge(projectRoot, run2, bundle, created) {
const read = (file) => readText(pipelinePath(projectRoot, run2.name, file));
const json = (file) => readJson(pipelinePath(projectRoot, run2.name, file));
const has = (file) => !created && bundleHas(projectRoot, bundle, file);
const request = read("request.md");
const label = json("label.json");
const questions = json("questions.json");
const clarificationFree = !has("clarification");
const specHash = created ? void 0 : frozenSpecHash(projectRoot, bundle);
const specSource = read("spec.md");
const existingRows = created ? [] : readUnitFile(projectRoot, featureFilePath(bundle, "stageEvidence"));
const staged = specHash === void 0 ? STAGED_SOURCES.filter(
([file, source]) => read(source) !== null && readStagedText(projectRoot, bundle, file) === null
).map(([file]) => file) : [];
const accounted = (rel) => {
const [top, name, ...rest] = rel.split("/");
if (top !== PIPELINE_DIR || name === void 0) return false;
if (name === RETIRED_BRIEFS_DIR) return rest.length === 1 && rest[0].endsWith(".md");
if (rest.length > 0) return false;
if (MERGED_SOURCES.includes(name) || RETIRED_SOURCES.includes(name)) return true;
if (RETIRED_REDO.test(name)) return true;
const stagedFile = STAGED_SOURCES.find(([, source]) => source === name)?.[0];
if (stagedFile === void 0) return false;
if (specHash !== void 0) {
if (stagedFile !== "craft") return true;
return typeof specHash === "string" && sha256Hex(read(name)) === specHash;
}
return staged.includes(stagedFile) || readStagedText(projectRoot, bundle, stagedFile) === read(name);
};
const files = listFilesUnder(join(projectRoot, LEGACY_SPECS_DIR, run2.name));
return {
run: run2,
bundle,
created,
request: request !== null && !has("request") ? splitFrontMatter(request).body : null,
label: isRecord(label) && clarificationFree ? label : null,
questions: isRecord(questions) && Array.isArray(questions.questions) && clarificationFree ? questions : null,
experts: isRecord(json("experts.json")) && !has("experts"),
specMd: typeof specHash === "string" && specSource !== null && !has("specMd") && sha256Hex(specSource) === specHash ? specSource : null,
steps: missingSteps(stepRowsFrom(run2), existingRows),
corrections: missingCorrections(correctionsFrom(projectRoot, run2), existingRows),
staged,
removable: files.filter(accounted),
leftovers: files.filter((rel) => !accounted(rel))
};
}
function describeAdds(plan) {
const added = [];
if (plan.created) added.push("feature.json");
if (plan.request !== null) added.push("request.md");
if (plan.label || plan.questions) added.push("clarification.json");
if (plan.experts) added.push("experts.json");
if (plan.specMd !== null) added.push("spec.md");
const rows = plan.steps.length + plan.corrections.length + (plan.created ? 1 : 0);
if (rows > 0) {
added.push(`stage-evidence.jsonl (+${rows} row${rows === 1 ? "" : "s"})`);
}
return added;
}
function briefFacts(text2) {
if (text2 === null) return { budget: 0, truncated: false, hash: "" };
const budget = /^- Granted budget: (\d+) tokens$/m.exec(text2);
return {
budget: budget ? Number(budget[1]) : 0,
truncated: /^- Grounding truncated: yes$/m.test(text2),
hash: sha256Hex(text2)
};
}
function writeExperts(projectRoot, plan) {
const json = (file) => readJson(pipelinePath(projectRoot, plan.run.name, file));
const need = json("experts.json");
const notes = json("expert-notes.json");
const roster = (need.experts ?? []).map(({ role, reason: reason2 }) => {
const brief = briefFacts(
readText(pipelinePath(projectRoot, plan.run.name, join("briefs", `${role}.md`)))
);
return {
role,
reason: reason2,
lens: lensPathForRole(role),
budget_tokens: brief.budget,
grounding_truncated: brief.truncated,
brief_hash: brief.hash,
tokens_used: null
};
});
writeExpertRoster(projectRoot, plan.bundle, roster);
if (isRecord(notes) && Array.isArray(notes.notes)) {
const artifact = {
notes: notes.notes.map(({ role, findings }) => ({
role,
findings
})),
tokens: isRecord(notes.tokens) ? notes.tokens : {}
};
writeExpertNotes(projectRoot, plan.bundle, artifact);
}
const synthesis = json("expert-synthesis.json");
if (isRecord(synthesis)) {
writeExpertSynthesis(projectRoot, plan.bundle, synthesis);
}
}
function applyMerge(projectRoot, plan) {
const { bundle } = plan;
if (plan.created) {
seedFeatureRecord(projectRoot, bundle, {
adapter: UNKNOWN,
sessionId: UNKNOWN,
status: "spec-only"
});
}
if (plan.request !== null) writeRequest(projectRoot, bundle, plan.request);
if (plan.label) writeLabel(projectRoot, bundle, plan.label);
if (plan.questions) writeQuestions(projectRoot, bundle, plan.questions);
if (plan.experts) writeExperts(projectRoot, plan);
if (plan.specMd !== null) {
const header = buildTextHeader({
docType: SPEC_SOURCE_DOC_TYPE,
change: featureChangeKey(bundle),
sessionId: documentSessionId(projectRoot, bundle),
schemaVersion: FEATURE_DOC_SCHEMA_VERSION,
body: plan.specMd
});
atomicWrite(
join(projectRoot, featureFilePath(bundle, "specMd")),
renderFrontMatter(header, plan.specMd)
);
}
for (const step of plan.steps) {
appendSpecStepRow(
projectRoot,
bundle,
{
step: step.step,
outcome: step.outcome,
artifactHash: step.hash,
...step.tokens !== void 0 ? { tokens: step.tokens } : {}
},
step.at === null ? {} : { now: () => new Date(step.at) }
);
}
for (const correction of plan.corrections) {
appendSpecCorrectionRow(
projectRoot,
bundle,
{ spec_id: correction.spec_id, changed_sections: correction.changed_sections },
correction.at === null ? {} : { now: () => new Date(correction.at) }
);
}
for (const file of plan.staged) {
const source = STAGED_SOURCES.find(([staged]) => staged === file)[1];
writeStagedText(
projectRoot,
bundle,
file,
readText(pipelinePath(projectRoot, plan.run.name, source))
);
}
if (plan.created) {
appendFeatureStageRow(projectRoot, UNKNOWN, bundle, {
kind: "close",
event_status: "completed",
note: "spec-only: the spec ran but the change never opened (evidence migration)"
});
}
}
function strayTmpFiles(projectRoot, runs, bundles) {
const tmpRoot = join(projectRoot, ".paqad", "tmp");
const stagingName = SPEC_PIPELINE_STAGING_DIR.split("/").pop();
const prefixes = /* @__PURE__ */ new Set();
const ulids = /* @__PURE__ */ new Set();
const contents = /* @__PURE__ */ new Set();
for (const name of [...runs.map((run2) => run2.name), ...bundles]) {
const parts = parseFeatureDirName(name);
ulids.add(parts.ulid);
if (parts.slug !== "change") {
prefixes.add(parts.slug);
if (parts.issue) prefixes.add(`${parts.issue}-${parts.slug}`);
}
}
for (const run2 of runs) {
for (const entry of listEntries(join(projectRoot, LEGACY_SPECS_DIR, run2.name, PIPELINE_DIR))) {
const text2 = entry.dir ? null : readText(pipelinePath(projectRoot, run2.name, entry.name));
if (text2 !== null) contents.add(sha256Hex(text2));
}
}
return listEntries(tmpRoot).filter((entry) => !entry.dir && entry.name !== stagingName).filter((entry) => {
const named = [...ulids].some((ulid) => entry.name.includes(ulid)) || [...prefixes].some(
(prefix) => entry.name.startsWith(`${prefix}-`) || entry.name.startsWith(`${prefix}.`)
);
if (named) return true;
const text2 = readText(join(tmpRoot, entry.name));
return text2 !== null && contents.has(sha256Hex(text2));
}).map((entry) => `.paqad/tmp/${entry.name}`).sort();
}
function gitignoreWithoutSpecsLine(projectRoot) {
const path10 = join(projectRoot, ".paqad", ".gitignore");
const text2 = readText(path10);
if (text2 === null) return null;
const lines = text2.split("\n");
const kept = lines.filter((line) => line.trim() !== LEGACY_SPECS_IGNORE_LINE);
return kept.length === lines.length ? null : { path: path10, next: kept.join("\n") };
}
function specsDirExists(projectRoot) {
try {
return statSync(join(projectRoot, LEGACY_SPECS_DIR)).isDirectory();
} catch {
return false;
}
}
function migrateFeatureEvidence(projectRoot, options = {}) {
const dryRun = options.dryRun === true;
const hold = {
self: options.sessionId?.trim() || null,
staleAfterMs: options.staleAfterMs ?? HELD_SESSION_STALE_MS,
nowMs: (options.now ?? (() => /* @__PURE__ */ new Date()))().getTime()
};
const actions = [];
const leftBehind = [];
const specsRel = (rel) => `${LEGACY_SPECS_DIR}/${rel}`;
const byUlid = /* @__PURE__ */ new Map();
for (const entry of listEntries(join(projectRoot, LEGACY_SPECS_DIR))) {
if (!entry.dir || !isFeatureDirName(entry.name)) {
actions.push({ kind: "skip-unrecognized", source: entry.name });
leftBehind.push(specsRel(entry.name));
continue;
}
const run2 = readRun(projectRoot, entry.name);
byUlid.set(run2.ulid, [...byUlid.get(run2.ulid) ?? [], run2]);
}
const bundles = listFeatureDirs(projectRoot);
const merged = [];
const dropped = [];
for (const [ulid, runs] of [...byUlid.entries()].sort(([a], [b]) => a.localeCompare(b))) {
const kept = pickRun(runs);
const existing = bundles.find((name) => featureChangeKey(name) === ulid);
if (existing && heldByAnotherSession(projectRoot, existing, hold)) {
for (const run2 of runs) {
actions.push({ kind: "skip-held", source: run2.name, bundle: existing });
leftBehind.push(specsRel(run2.name));
}
continue;
}
const bundle = existing ?? kept.name;
try {
const plan = planMerge(projectRoot, kept, bundle, existing === void 0);
if (!dryRun) applyMerge(projectRoot, plan);
actions.push({
kind: "merge",
source: kept.name,
bundle,
created: plan.created,
added: describeAdds(plan),
staged: [...plan.staged]
});
if (plan.leftovers.length > 0) {
actions.push({ kind: "leave-files", source: kept.name, files: [...plan.leftovers] });
leftBehind.push(...plan.leftovers.map((rel) => specsRel(`${kept.name}/${rel}`)));
}
for (const run2 of runs) {
if (run2 === kept) continue;
actions.push({ kind: "drop-duplicate", source: run2.name, kept: kept.name });
dropped.push(run2);
}
merged.push(plan);
} catch (error) {
actions.push({
kind: "failed",
source: kept.name,
error: error.message
});
leftBehind.push(specsRel(kept.name));
}
}
const remove = (rel, recursive) => {
try {
rmSync(join(projectRoot, rel), { recursive, force: true });
} catch (error) {
actions.push({ kind: "delete-failed", path: rel, error: error.message });
if (rel.startsWith(`${LEGACY_SPECS_DIR}/`)) leftBehind.push(rel);
}
};
const stray = strayTmpFiles(
projectRoot,
[...merged.map((plan) => plan.run), ...dropped],
merged.map((plan) => plan.bundle)
);
for (const path10 of stray) actions.push({ kind: "delete-tmp", path: path10 });
if (!dryRun) {
for (const path10 of stray) remove(path10, false);
for (const run2 of dropped) remove(specsRel(run2.name), true);
for (const plan of merged) {
const runRel = specsRel(plan.run.name);
if (plan.leftovers.length === 0) {
remove(runRel, true);
continue;
}
for (const rel of plan.removable) remove(`${runRel}/${rel}`, false);
pruneEmptyDirs(join(projectRoot, runRel));
}
}
const specsDir = specsDirExists(projectRoot);
if (specsDir && leftBehind.length === 0) {
actions.push({ kind: "remove-specs-dir" });
if (!dryRun) remove(LEGACY_SPECS_DIR, true);
}
if (!specsDir || leftBehind.length === 0) {
const gitignore = gitignoreWithoutSpecsLine(projectRoot);
if (gitignore) {
actions.push({ kind: "remove-gitignore-line" });
if (!dryRun) atomicWrite(gitignore.path, gitignore.next);
}
}
return { dryRun, actions, leftBehind: [...new Set(leftBehind)].sort() };
}
function pruneEmptyDirs(abs) {
for (const entry of listEntries(abs)) {
if (entry.dir) pruneEmptyDirs(join(abs, entry.name));
}
try {
rmdirSync(abs);
} catch {
}
}
function migrationSessionId(env2 = process.env) {
return env2.SE_SESSION ?? env2.CLAUDE_SESSION_ID ?? null;
}
function legacyEvidenceIgnoreEntries(projectRoot) {
return specsDirExists(projectRoot) ? [LEGACY_SPECS_IGNORE_LINE] : [];
}
function evidenceMigrationPending(projectRoot) {
return specsDirExists(projectRoot);
}
function runPendingEvidenceMigration(projectRoot, warn2 = (message) => process.stderr.write(`${message}
`), env2 = process.env) {
if (!evidenceMigrationPending(projectRoot)) return null;
try {
return migrateFeatureEvidence(projectRoot, { sessionId: migrationSessionId(env2) });
} catch (error) {
warn2(
`paqad: the evidence migration did not finish (${error.message}); it runs again on the next update, or run \`paqad-ai evidence migrate\`.`
);
return null;
}
}
function formatEvidenceMigration(result2) {
if (result2.actions.length === 0) return "Nothing to migrate: the evidence layout is current.";
const verb = result2.dryRun ? "would" : "did";
const lines = result2.actions.map((action) => {
switch (action.kind) {
case "merge": {
const into = action.created ? `a new spec-only bundle ${action.bundle}` : action.bundle;
const added = action.added.length > 0 ? action.added.join(", ") : "nothing new";
const staged = action.staged.length > 0 ? `; staged ${action.staged.join(", ")} for a later freeze` : "";
return `merge ${action.source} into ${into}: add ${added}${staged}`;
}
case "drop-duplicate":
return `delete ${action.source} (a half run; kept ${action.kept})`;
case "skip-held":
return `skip ${action.source}: ${action.bundle} is open in another session (migrated once it closes)`;
case "skip-unrecognized":
return `leave ${action.source}: not a change folder`;
case "failed":
return `leave ${action.source}: migration failed (${action.error})`;
case "leave-files":
return `leave ${action.files.join(", ")} in ${LEGACY_SPECS_DIR}/${action.source}/: not merged, so kept for you to check`;
case "delete-failed":
return `could not delete ${action.path} (${action.error}); it stays for a later run`;
case "delete-tmp":
return `delete ${action.path}`;
case "remove-specs-dir":
return `delete ${LEGACY_SPECS_DIR}/`;
case "remove-gitignore-line":
return `remove the ${LEGACY_SPECS_IGNORE_LINE} line from .paqad/.gitignore`;
}
});
return [`Evidence migration (${verb}):`, ...lines.map((line) => `- ${line}`)].join("\n");
}
// src/core/schema-migrators.ts
var FEATURE_EVIDENCE_MIGRATOR = {
id: "feature-evidence",
appliesTo: (fromVersion) => /^(0|1\.0)\./.test(fromVersion.trim()),
migrate: async ({ projectRoot }) => {
try {
const result2 = migrateFeatureEvidence(projectRoot, { sessionId: migrationSessionId() });
return result2.actions.length === 0 ? void 0 : formatEvidenceMigration(result2);
} catch (error) {
return `the evidence migration did not finish (${error.message}); it runs again on the next update, or run \`paqad-ai evidence migrate\`.`;
}
}
};
var SCHEMA_MIGRATORS = Object.freeze([
FEATURE_EVIDENCE_MIGRATOR
]);
async function runSchemaMigrators(context, migrators = SCHEMA_MIGRATORS) {
const notes = [];
for (const migrator of migrators) {
if (!migrator.appliesTo(context.fromVersion, context.toVersion)) {
continue;
}
const note = await migrator.migrate(context);
notes.push(note ? `${migrator.id}: ${note}` : migrator.id);
}
return notes;
}
// src/core/schema-version.ts
var STALE_LOCK_TIMEOUT_MS = 2e3;
var LOCK_POLL_MS = 20;
function schemaMarkerPath(projectRoot) {
return join10(projectRoot, PATHS.SCHEMA_MARKER);
}
function schemaMigrationLogPath(projectRoot) {
return join10(projectRoot, PATHS.SCHEMA_MIGRATION_LOG);
}
async function writeSchemaMarker(projectRoot, engineVersion) {
const marker = {
paqad_schema_version: PAQAD_SCHEMA_VERSION,
written_at: (/* @__PURE__ */ new Date()).toISOString(),
written_by_engine_version: engineVersion
};
const target = schemaMarkerPath(projectRoot);
await mkdir12(dirname8(target), { recursive: true });
const tmp = `${target}.tmp-${process.pid}`;
await writeFile12(tmp, JSON.stringify(marker, null, 2) + "\n", "utf8");
await rename(tmp, target);
return marker;
}
function writeSchemaMarkerSync(projectRoot, engineVersion) {
const marker = {
paqad_schema_version: PAQAD_SCHEMA_VERSION,
written_at: (/* @__PURE__ */ new Date()).toISOString(),
written_by_engine_version: engineVersion
};
const target = schemaMarkerPath(projectRoot);
mkdirSync(dirname8(target), { recursive: true });
const tmp = `${target}.tmp-${process.pid}`;
writeFileSync2(tmp, JSON.stringify(marker, null, 2) + "\n", "utf8");
renameSync2(tmp, target);
return marker;
}
async function readSchemaMarker(projectRoot) {
const target = schemaMarkerPath(projectRoot);
if (!existsSync2(target)) return null;
try {
const parsed = JSON.parse(await readFile11(target, "utf8"));
if (!isValidMarker(parsed)) return null;
return parsed;
} catch {
return null;
}
}
function readSchemaMarkerSync(projectRoot) {
const target = schemaMarkerPath(projectRoot);
if (!existsSync2(target)) return null;
try {
const parsed = JSON.parse(readFileSync2(target, "utf8"));
if (!isValidMarker(parsed)) return null;
return parsed;
} catch {
return null;
}
}
function ensureSchemaMarkerSync(projectRoot, engineVersion) {
const existing = readSchemaMarkerSync(projectRoot);
if (existing) return existing;
return writeSchemaMarkerSync(projectRoot, engineVersion);
}
function isValidMarker(value) {
if (typeof value !== "object" || value === null) return false;
const marker = value;
return typeof marker.paqad_schema_version === "string" && isSemver(marker.paqad_schema_version) && typeof marker.written_at === "string" && typeof marker.written_by_engine_version === "string";
}
function checkSchemaCompatibility(marker) {
const comparison = compareSemver(marker.paqad_schema_version, PAQAD_SCHEMA_VERSION);
if (comparison === 0) return "compatible";
if (comparison < 0) return "needs-migration";
return "future";
}
async function appendMigrationRecord(projectRoot, record2) {
const target = schemaMigrationLogPath(projectRoot);
await mkdir12(dirname8(target), { recursive: true });
await appendFile(target, JSON.stringify(record2) + "\n", "utf8");
}
async function withSchemaMigrationLock(projectRoot, fn) {
const lockPath = join10(projectRoot, PATHS.SCHEMA_MIGRATION_LOCK);
await acquireLock(lockPath);
try {
return await fn();
} finally {
await releaseLock(lockPath);
}
}
async function acquireLock(lockPath) {
await mkdir12(dirname8(lockPath), { recursive: true });
const deadline = Date.now() + STALE_LOCK_TIMEOUT_MS;
while (Date.now() < deadline) {
try {
const fd = openSync(lockPath, "wx");
closeSync(fd);
return;
} catch {
await delay(LOCK_POLL_MS);
}
}
writeFileSync2(lockPath, String(process.pid));
}
async function releaseLock(lockPath) {
try {
await unlink(lockPath);
} catch {
}
}
function delay(ms) {
return new Promise((resolve5) => setTimeout(resolve5, ms));
}
async function checkAndMigrateSchema(projectRoot, engineVersion, options = {}) {
const markerFile = schemaMarkerPath(projectRoot);
if (!existsSync2(markerFile)) {
return writeSchemaMarker(projectRoot, engineVersion);
}
const marker = await readSchemaMarker(projectRoot);
if (marker === null) {
return withSchemaMigrationLock(projectRoot, async () => {
const written = await writeSchemaMarker(projectRoot, engineVersion);
await appendMigrationRecord(projectRoot, {
from_version: null,
to_version: PAQAD_SCHEMA_VERSION,
migrated_at: (/* @__PURE__ */ new Date()).toISOString(),
engine_version: engineVersion,
file: PATHS.SCHEMA_MARKER
});
return written;
});
}
const compatibility = checkSchemaCompatibility(marker);
if (compatibility === "future") {
throw new SchemaVersionError(
`This project's .paqad/ layout was written with schema version ${marker.paqad_schema_version}, which is newer than this engine understands (${PAQAD_SCHEMA_VERSION}). Upgrade paqad-ai to operate on this project.`,
{
code: "SCHEMA_VERSION_FUTURE",
details: {
found_version: marker.paqad_schema_version,
known_version: PAQAD_SCHEMA_VERSION
}
}
);
}
if (compatibility === "compatible") {
return marker;
}
return withSchemaMigrationLock(projectRoot, async () => {
const current = await readSchemaMarker(projectRoot);
if (current !== null && checkSchemaCompatibility(current) !== "needs-migration") {
return current;
}
const fromVersion = current?.paqad_schema_version ?? marker.paqad_schema_version;
const notes = await runSchemaMigrators(
{
projectRoot,
fromVersion,
toVersion: PAQAD_SCHEMA_VERSION,
engineVersion
},
options.migrators
);
const written = await writeSchemaMarker(projectRoot, engineVersion);
await appendMigrationRecord(projectRoot, {
from_version: fromVersion,
to_version: PAQAD_SCHEMA_VERSION,
migrated_at: (/* @__PURE__ */ new Date()).toISOString(),
engine_version: engineVersion,
file: PATHS.SCHEMA_MARKER,
...notes.length > 0 ? { notes } : {}
});
return written;
});
}
function isSemver(value) {
return /^\d+\.\d+\.\d+$/.test(value.trim());
}
function compareSemver(a, b) {
const pa = parseSemver(a);
const pb = parseSemver(b);
for (let i = 0; i < 3; i += 1) {
if (pa[i] !== pb[i]) return pa[i] < pb[i] ? -1 : 1;
}
return 0;
}
function parseSemver(value) {
const parts = value.trim().split(".").map(Number);
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
}
// src/core/types/index.ts
init_esm_shims();
// src/core/types/context.ts
init_esm_shims();
var CONTEXT_LEVELS = [0, 1, 2, 3, 4];
// src/core/capabilities.ts
init_esm_shims();
var ACTIVE_CAPABILITY_ORDER = ["content", "coding", "security"];
var MANAGEABLE_ACTIVE_CAPABILITIES = ["content", "coding"];
function listAvailableActiveCapabilities() {
return [...MANAGEABLE_ACTIVE_CAPABILITIES];
}
function isActiveCapability(value) {
return ACTIVE_CAPABILITY_ORDER.includes(value);
}
function isManageableActiveCapability(value) {
return MANAGEABLE_ACTIVE_CAPABILITIES.includes(value);
}
function assertActiveCapability(value) {
if (!isActiveCapability(value)) {
throw new Error(
`Unknown capability "${value}". Expected one of: ${MANAGEABLE_ACTIVE_CAPABILITIES.join(", ")}`
);
}
if (!isManageableActiveCapability(value)) {
throw new Error(
`Capability "${value}" is dependency-managed and cannot be changed directly. Manage "coding" instead.`
);
}
return value;
}
function normalizeActiveCapabilities(capabilities) {
const values = /* @__PURE__ */ new Set(["content"]);
for (const capability of capabilities) {
if (ACTIVE_CAPABILITY_ORDER.includes(capability)) {
values.add(capability);
}
}
if (values.has("coding")) {
values.add("security");
} else {
values.delete("security");
}
return ACTIVE_CAPABILITY_ORDER.filter((capability) => values.has(capability));
}
function addActiveCapability(profile, capability) {
return {
...profile,
active_capabilities: normalizeActiveCapabilities([...profile.active_capabilities, capability])
};
}
function removeActiveCapability(profile, capability) {
if (capability === "content") {
throw new Error("content capability cannot be removed");
}
const next = profile.active_capabilities.filter((value) => value !== capability);
const normalized = normalizeActiveCapabilities(next);
return {
...profile,
active_capabilities: normalized,
stack_profile: normalized.includes("coding") ? profile.stack_profile : void 0
};
}
// src/core/types/design-tokens.ts
init_esm_shims();
// src/core/types/documentation.ts
init_esm_shims();
var DOC_TYPES = [
"stories",
"spec",
"user-flow",
"schema",
"query",
"index",
"registry",
"ui",
"api",
"integration",
"error-catalog",
"glossary",
"decision-record",
"review-report",
"sequence-plan"
];
// src/core/types/document-generation.ts
init_esm_shims();
// src/core/types/health.ts
init_esm_shims();
var HEALTH_CHECK_STATUSES = ["pass", "fail", "warning", "info"];
// src/core/types/hook.ts
init_esm_shims();
var HOOK_TRIGGERS = [
"user-prompt-submit",
"pre-tool-use",
"post-tool-use",
"stop",
"subagent-stop",
"pre-compact"
];
// src/core/types/introspection.ts
init_esm_shims();
var STACK_ECOSYSTEMS = [
"node",
"php",
"python",
"ruby",
"jvm",
"go",
"rust",
"dart",
"dotnet"
];
// src/core/types/logger.ts
init_esm_shims();
// src/core/types/logging.ts
init_esm_shims();
// src/core/types/onboarding.ts
init_esm_shims();
// src/core/types/pack.ts
init_esm_shims();
var STRUCTURED_TEST_FORMATS = [
"jest-json",
"junit-xml",
"pytest-json",
"go-json",
"rspec-json",
"tap",
"none"
];
var TEST_RUNNER_OUTPUT_SOURCES = ["stdout", "file"];
var TEST_RUNNER_PARALLEL_MODES = ["native", "flag", "unavailable"];
var SINGLE_TEST_SELECTORS = ["test_id", "file"];
var COMPLIANCE_RELATIONS = [
"equivalent-to",
"equal-to",
"subset-of",
"superset-of",
"intersects-with",
"no-relationship"
];
var COMPLIANCE_EVIDENCE_STRENGTHS = ["partial", "substantial"];
// src/core/types/pipeline.ts
init_esm_shims();
var PIPELINE_PHASES = [
"request-classification",
"docs-first-load",
"analysis",
"question-answering",
"root-cause-analysis",
"pentest",
"pentest-retest",
"sequence-planning",
"specification",
"user-flow",
"spec-review",
"implementation",
"implementation-review",
"verification-gates",
"documentation-update",
"module-documentation"
];
// src/core/types/pentest.ts
init_esm_shims();
var PENTEST_WORKFLOWS = ["pentest", "pentest-retest"];
var PENTEST_SEVERITIES = ["high", "medium", "low"];
var PENTEST_EFFORTS = ["low", "medium", "high"];
var PENTEST_RETEST_STATUSES = [
"fixed",
"still-open",
"needs-manual-verification"
];
var PENTEST_FINDING_STATUSES = [
"open",
"coverage-gap",
"fixed",
"still-open",
"needs-manual-verification",
"potentially-fixed"
];
var PENTEST_SOURCE_TYPES = ["docs", "tests", "code", "runtime", "advisory"];
var PENTEST_RUN_STEP_STATUSES = [
"not_started",
"running",
"completed",
"blocked",
"failed"
];
var PENTEST_RUN_STATUSES = ["running", "completed", "blocked", "failed"];
// src/core/types/planning.ts
init_esm_shims();
var REQUIREMENT_PRIORITIES = ["must", "should", "could"];
var REQUIREMENT_RISKS = ["low", "medium", "high"];
// src/core/types/post-classification.ts
init_esm_shims();
// src/core/types/pre-classification.ts
init_esm_shims();
// src/core/types/project-profile.ts
init_esm_shims();
var ESCALATION_MODES = ["block", "require_approval", "warn"];
var TICKET_PROVIDER_KINDS = [
"jira",
"linear",
"servicenow",
"github-issues",
"generic"
];
var EMBEDDING_PROVIDER_NAMES = ["local", "openai"];
var DECISION_ASK_THRESHOLDS = ["strict", "balanced", "permissive"];
// src/core/types/resolution.ts
init_esm_shims();
var RESOLUTION_LAYERS = [0, 1, 2, 3, 4, 5, 6];
// src/core/types/review.ts
init_esm_shims();
var REVIEW_TIERS = ["full", "standard", "spot-check"];
var REVIEW_MODES = ["fresh", "diff"];
var REVIEW_DIMENSIONS = [
"completeness",
"assumption-safety",
"security",
"data-integrity",
"performance",
"failure-modes",
"reuse-architecture",
"database-quality",
"ux-ui-quality",
"test-quality",
"observability",
"rollback-safety"
];
var TIER_DIMENSIONS = {
full: REVIEW_DIMENSIONS,
standard: [
"completeness",
"security",
"data-integrity",
"performance",
"test-quality",
"rollback-safety"
],
"spot-check": ["security", "test-quality", "rollback-safety"]
};
var FINDING_SEVERITIES = ["critical", "high", "medium", "low"];
// src/core/types/schema-version.ts
init_esm_shims();
// src/core/types/skill.ts
init_esm_shims();
var SKILL_MODEL_TIERS = ["fast", "medium", "reasoning"];
var SKILL_OUTPUT_FORMATS = ["markdown", "yaml", "json"];
// src/core/types/stability.ts
init_esm_shims();
var STABILITY_LEVELS = ["stable", "beta", "alpha", "internal"];
// src/core/types/template.ts
init_esm_shims();
// src/core/types/test-output.ts
init_esm_shims();
var TEST_OUTPUT_SCHEMA_VERSION = "1.0.0";
var UNKNOWN_TEST_OUTPUT_TIMESTAMP = "1970-01-01T00:00:00.000Z";
var TEST_ISSUE_CATEGORIES = ["assertion", "error", "timeout", "unknown"];
var TEST_PARSE_STRATEGIES = ["structured", "plain-text-fallback", "degraded"];
// src/core/types/token-efficiency.ts
init_esm_shims();
var TOKEN_ARTIFACT_CLASSES = [
"test-output",
"coverage-output",
"json-report",
"xml-report",
"log-output",
"grep-results",
"route-dump",
"inventory-scan-output"
];
var ESCALATION_REASONS = [
"structured-parse-failed-or-degraded",
"summary-confidence-low",
"compact-signals-contradict",
"diagnosis-unresolved-after-compact-pass"
];
var DISCLOSURE_LEVELS = ["summary", "compact", "excerpt", "raw"];
var DISCLOSURE_ESCALATION_REASONS = [
"ambiguity-unresolved",
"previous-layer-insufficient",
"high-risk-or-cross-cutting"
];
var TASK_COMPLEXITIES = [
"trivial",
"single-file",
"single-module",
"cross-cutting"
];
var RETRIEVAL_PATHS = ["direct", "lexical", "rag-shallow", "rag-deep"];
var RETRIEVAL_ESCALATION_SIGNALS = [
"insufficient-chunks",
"conflicting-evidence",
"unresolved-target-file-ambiguity"
];
var ROUTING_MECHANISMS = [
"deterministic-rule",
"metadata-lookup",
"cheap-model",
"reasoning-model"
];
// src/decisions/index.ts
init_esm_shims();
// src/detection/index.ts
init_esm_shims();
// src/detection/ai-detector.ts
init_esm_shims();
import { readFileSync as readFileSync3 } from "fs";
import { join as join11 } from "path";
// src/detection/report.ts
init_esm_shims();
// src/detection/language-map.ts
init_esm_shims();
var ECOSYSTEM_LANGUAGE = {
node: "JavaScript/TypeScript",
php: "PHP",
python: "Python",
ruby: "Ruby",
jvm: "Java/Kotlin",
go: "Go",
rust: "Rust",
dart: "Dart",
dotnet: "C#"
};
function ecosystemToLanguage(ecosystem) {
if (ecosystem === null || ecosystem === void 0) {
return null;
}
return ECOSYSTEM_LANGUAGE[ecosystem] ?? null;
}
// src/detection/report.ts
var CONFIDENCE_SCORE = {
high: 0.9,
medium: 0.7,
low: 0.4
};
function buildDetectionReport(input) {
return {
detected_domain: input.domain,
detected_stack: input.stack,
detected_capabilities: input.capabilities ?? [],
matched_packs: input.matchedPacks ?? [],
detected_traits: input.detectedTraits ?? [],
recommended_capabilities: input.recommendedCapabilities ?? ["content"],
detection_phase: input.detectionPhase,
confidence: input.confidence,
confidence_score: input.confidenceScore ?? CONFIDENCE_SCORE[input.confidence],
primary_language: ecosystemToLanguage(input.ecosystem ?? null),
source: input.source ?? "static",
signals: input.signals,
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
repository: input.repository
};
}
// src/detection/ai-detector.ts
var MANIFEST_FILES = [
"package.json",
"pubspec.yaml",
"requirements.txt",
"Cargo.toml",
"go.mod",
"pom.xml",
"Gemfile",
"composer.json"
];
var MAX_FILE_BYTES = 4096;
var DEFAULT_TIMEOUT_MS2 = 1e4;
var MIN_CONFIDENCE = 0.6;
var AIDetector = class {
provider;
timeoutMs;
minConfidence;
constructor(options = {}) {
this.provider = options.provider ?? null;
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
this.minConfidence = options.minConfidence ?? MIN_CONFIDENCE;
}
async detect(projectRoot) {
const provider = this.provider;
if (provider === null) {
return null;
}
const manifests = readManifestSamples(projectRoot);
if (manifests.length === 0) {
return null;
}
let raw;
try {
raw = await this.completeWithTimeout(provider, buildPrompt(manifests));
} catch {
return null;
}
const parsed = parseResponse(raw);
if (parsed === null || parsed.confidence_score < this.minConfidence) {
return null;
}
return buildDetectionReport({
domain: parsed.domain,
stack: parsed.stack,
ecosystem: parsed.ecosystem,
confidence: scoreToCategorical(parsed.confidence_score),
confidenceScore: parsed.confidence_score,
source: "ai",
detectionPhase: parsed.stack === null ? "none" : "framework",
recommendedCapabilities: parsed.domain === "coding" ? ["content", "coding", "security"] : ["content"],
signals: []
});
}
completeWithTimeout(provider, messages) {
const controller = new AbortController();
return new Promise((resolve5, reject2) => {
const timer = setTimeout(() => {
controller.abort();
reject2(new Error("ai-detection-timeout"));
}, this.timeoutMs);
provider.complete(messages, { timeoutMs: this.timeoutMs, signal: controller.signal }).then(
(value) => {
clearTimeout(timer);
resolve5(value);
},
(error) => {
clearTimeout(timer);
reject2(error instanceof Error ? error : new Error(String(error)));
}
);
});
}
};
function readManifestSamples(projectRoot) {
const samples = [];
for (const file of MANIFEST_FILES) {
const path10 = join11(projectRoot, file);
try {
const content = readFileSync3(path10, "utf8").slice(0, MAX_FILE_BYTES);
samples.push({ file, content });
} catch {
}
}
return samples;
}
function buildPrompt(manifests) {
const manifestBlock = manifests.map((manifest) => `### ${manifest.file}
${manifest.content}`).join("\n\n");
return [
{
role: "system",
content: `You classify a software project's stack from its manifest files. Respond with a single JSON object and nothing else, using exactly these keys: "domain" (one of "coding", "content", or null), "stack" (one of the known stack slugs or null), "ecosystem" (one of "node", "php", "python", "ruby", "jvm", "go", "rust", "dart", or null), "confidence_score" (a number between 0 and 1). Known stack slugs: ${STACKS.join(", ")}.`
},
{
role: "user",
content: `Classify this project from its manifests:
${manifestBlock}`
}
];
}
function parseResponse(raw) {
const json = extractJsonObject(raw);
if (json === null) {
return null;
}
const confidenceRaw = json.confidence_score;
if (typeof confidenceRaw !== "number" || !Number.isFinite(confidenceRaw)) {
return null;
}
const confidence_score = Math.min(1, Math.max(0, confidenceRaw));
return {
domain: isDomain(json.domain) ? json.domain : null,
stack: isStack(json.stack) ? json.stack : null,
ecosystem: isEcosystem(json.ecosystem) ? json.ecosystem : null,
confidence_score
};
}
function extractJsonObject(raw) {
const start = raw.indexOf("{");
const end = raw.lastIndexOf("}");
if (start === -1 || end === -1 || end < start) {
return null;
}
try {
const parsed = JSON.parse(raw.slice(start, end + 1));
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
return null;
}
return parsed;
} catch {
return null;
}
}
function isDomain(value) {
return typeof value === "string" && DOMAINS.includes(value);
}
function isStack(value) {
return typeof value === "string" && STACKS.includes(value);
}
function isEcosystem(value) {
return typeof value === "string" && STACK_ECOSYSTEMS.includes(value);
}
function scoreToCategorical(score) {
if (score >= 0.85) {
return "high";
}
if (score >= 0.6) {
return "medium";
}
return "low";
}
// src/detection/detector.ts
init_esm_shims();
var import_fast_glob3 = __toESM(require_out(), 1);
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
import { join as join13 } from "path";
// src/detection/signals/short-video.ts
init_esm_shims();
var import_yaml2 = __toESM(require_dist(), 1);
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
import { join as join12 } from "path";
function detectShortVideoSignals(projectRoot) {
const profilePath = join12(projectRoot, ".paqad", "project-profile.yaml");
const markerPath = join12(projectRoot, ".short-video-project");
const signals = [];
if (existsSync3(profilePath)) {
const profile = (0, import_yaml2.parse)(readFileSync4(profilePath, "utf8"));
if (profile.routing?.domain === "content" && (profile.stack_profile?.frameworks?.includes("short-video") || profile.routing.stack === "short-video")) {
signals.push({
signal: "project profile declares content/short-video",
file: ".paqad/project-profile.yaml",
implies: "short-video",
confidence: "high"
});
}
}
if (existsSync3(markerPath)) {
signals.push({
signal: "short-video marker file exists",
file: ".short-video-project",
implies: "short-video",
confidence: "medium"
});
}
return signals;
}
// src/detection/detector.ts
var Detector = class {
introspector = new StackIntrospector();
packLoader = new StackPackLoader();
aiDetector;
inflight = /* @__PURE__ */ new Map();
constructor(options = {}) {
this.aiDetector = options.aiDetector ?? null;
}
async detect(projectRoot, options = {}) {
const persist = options.persist ?? true;
const key = `${projectRoot}\0${persist}`;
const existing = this.inflight.get(key);
if (existing !== void 0) {
return existing;
}
const promise = this.runDetect(projectRoot, options).finally(() => {
this.inflight.delete(key);
});
this.inflight.set(key, promise);
return promise;
}
async runDetect(projectRoot, options) {
if (this.aiDetector !== null) {
const aiReport = await this.aiDetector.detect(projectRoot);
if (aiReport !== null) {
return aiReport;
}
}
const snapshot = await this.introspector.snapshot(projectRoot, {
persist: options.persist ?? true
});
const repository = snapshot.repository ?? emptyRepositoryContext(projectRoot);
const primaryEcosystem = snapshot.toolchains?.[0]?.ecosystem ?? null;
const roots = resolvePackManagerRoots(projectRoot);
const registry = this.packLoader.load({
runtimeRoot: roots.runtimeRoot,
globalPacksRoot: roots.globalPacksRoot,
projectRoot
});
const allPacks = Array.from(registry.packs.values());
const frameworkPacks = allPacks.filter((p) => (p.manifest.tier ?? "framework") === "framework");
const archetypePacks = allPacks.filter((p) => p.manifest.tier === "archetype");
const applications = repository.applications.length > 0 ? repository.applications : [{ root: ".", component_roots: [] }];
const applicationResults = applications.map(
(application) => detectApplication(
projectRoot,
application,
snapshot.packages,
frameworkPacks,
archetypePacks
)
).sort(compareApplicationResults);
const primaryResult = applicationResults[0];
const matchedPacks = primaryResult?.matches ?? [];
const detectionPhase = primaryResult?.detectionPhase ?? "none";
const repositoryEnvironment = mergeEnvironmentTraits(
projectRoot,
repository.projects.map((project) => project.root),
snapshot.packages
);
if (matchedPacks.length === 0) {
const shortVideoSignals = detectShortVideoSignals(projectRoot);
if (shortVideoSignals.length > 0) {
return buildDetectionReport({
domain: "content",
stack: "short-video",
matchedPacks: [],
detectedTraits: [],
recommendedCapabilities: ["content"],
detectionPhase: "none",
signals: [...shortVideoSignals, ...repositoryEnvironment.signals],
capabilities: repositoryEnvironment.traits,
confidence: "low",
ecosystem: null,
confidenceScore: 0,
source: "static",
repository
});
}
return buildDetectionReport({
domain: null,
stack: null,
matchedPacks: [],
detectedTraits: repositoryEnvironment.traits,
recommendedCapabilities: ["content"],
detectionPhase: "none",
capabilities: repositoryEnvironment.traits,
signals: repositoryEnvironment.signals,
confidence: "low",
ecosystem: null,
confidenceScore: 0,
source: "static",
repository
});
}
const topScore = matchedPacks[0].score;
const topMatches = matchedPacks.filter((match) => match.score === topScore);
const ambiguous = topMatches.length > 1;
const detectedTraits = Array.from(
/* @__PURE__ */ new Set([
...applicationResults.flatMap((result2) => result2.matches.flatMap((match) => match.traits)),
...repositoryEnvironment.traits
])
).sort();
const repositoryMatchedPacks = Array.from(
new Set(applicationResults.flatMap((result2) => result2.matches.map((match) => match.name)))
).sort();
const confidence = ambiguous ? "low" : applicationResults.length > 1 ? "medium" : scoreToConfidence(topScore);
return buildDetectionReport({
domain: ambiguous ? null : "coding",
stack: ambiguous ? null : matchedPacks[0].name,
matchedPacks: repositoryMatchedPacks,
detectedTraits,
recommendedCapabilities: ["content", "coding", "security"],
detectionPhase,
capabilities: detectedTraits.filter(isCapability),
signals: [
...applicationResults.flatMap((result2) => result2.matches.flatMap((match) => match.signals)),
...repositoryEnvironment.signals
],
confidence,
ecosystem: primaryEcosystem,
source: "static",
repository
});
}
};
function detectApplication(projectRoot, application, packages, frameworkPacks, archetypePacks) {
const roots = [application.root, ...application.component_roots];
const packageNames = new Set(
packages.filter((pkg) => roots.includes(pkg.root ?? ".")).map((pkg) => pkg.name)
);
const environment = mergeEnvironmentTraits(projectRoot, roots, packages);
const frameworkMatches = frameworkPacks.map((pack) => evaluatePack(projectRoot, roots, pack, packageNames)).filter((match) => match !== null).filter((match, _, matches) => !isExcludedMatch(match, matches)).sort(compareMatchedPacks);
if (frameworkMatches.length > 0) {
return {
application,
matches: frameworkMatches,
detectionPhase: "framework",
environment
};
}
const archetypeMatches = archetypePacks.map((pack) => evaluatePack(projectRoot, roots, pack, packageNames)).filter((match) => match !== null).filter((match, _, matches) => !isExcludedMatch(match, matches)).sort(compareMatchedPacks);
return {
application,
matches: archetypeMatches,
detectionPhase: archetypeMatches.length > 0 ? "archetype" : "none",
environment
};
}
function evaluatePack(projectRoot, roots, pack, packageNames) {
const signals = [
...evaluateRules(
projectRoot,
roots,
pack.manifest.name,
pack.manifest.detection.manifests,
packageNames
),
...evaluateRules(
projectRoot,
roots,
pack.manifest.name,
pack.manifest.detection.lockfiles,
packageNames
),
...evaluateRules(
projectRoot,
roots,
pack.manifest.name,
pack.manifest.detection.heuristics,
packageNames
)
];
if (signals.length === 0) {
return null;
}
const traitMatches = detectTraits(projectRoot, roots, pack.manifest.traits ?? [], packageNames);
const allSignals = [...signals, ...traitMatches.signals];
return {
name: pack.manifest.name,
score: allSignals.length,
priority: pack.manifest.detection.priority ?? 0,
excludes: pack.manifest.detection.excludes ?? [],
signals: allSignals,
traits: traitMatches.names
};
}
function evaluateRules(projectRoot, roots, implies, rules, packageNames) {
return (rules ?? []).map((rule) => evaluateRule(projectRoot, roots, implies, rule, packageNames)).filter((signal5) => signal5 !== null);
}
function evaluateRule(projectRoot, roots, implies, rule, packageNames) {
const packagesMatched = rule.packages === void 0 || rule.packages.every((pkg) => packageNames.has(pkg));
const matchedRoot = roots.find(
(root) => matchesRuleAtRoot(projectRoot, root, rule, packageNames)
);
if (!packagesMatched || matchedRoot === void 0) {
return null;
}
return {
signal: buildRuleSignal(rule, implies),
file: prefixRepositoryPath(
matchedRoot,
rule.file ?? rule.directory ?? rule.patterns?.[0] ?? "package metadata"
),
implies,
confidence: rule.file && rule.packages ? "high" : rule.file || rule.directory ? "medium" : "low"
};
}
function matchesRuleAtRoot(projectRoot, root, rule, packageNames) {
const absoluteRoot = root === "." ? projectRoot : join13(projectRoot, root);
const fileMatched = rule.file ? existsSync4(join13(absoluteRoot, rule.file)) : true;
const directoryMatched = rule.directory ? existsSync4(join13(absoluteRoot, rule.directory)) : true;
const patternsMatched = rule.patterns === void 0 || rule.patterns.every((pattern) => import_fast_glob3.default.sync(pattern, { cwd: absoluteRoot }).length > 0);
const contentMatched = rule.content_match === void 0 || rule.file !== void 0 && existsSync4(join13(absoluteRoot, rule.file)) && readFileSync5(join13(absoluteRoot, rule.file), "utf8").includes(rule.content_match);
const fieldsMatched = evaluateFieldRules(absoluteRoot, rule);
const fieldAbsentMatched = evaluateFieldAbsentRules(absoluteRoot, rule);
const packagesMatched = rule.packages === void 0 || rule.packages.every((pkg) => packageNames.has(pkg));
return fileMatched && directoryMatched && patternsMatched && contentMatched && fieldsMatched && fieldAbsentMatched && packagesMatched;
}
function evaluateFieldRules(projectRoot, rule) {
if (!rule.fields?.length) return true;
if (!rule.file) return false;
const parsed = parseManifestFile(projectRoot, rule.file);
if (parsed === null) return false;
return rule.fields.every((fieldRule) => checkFieldRule(parsed, fieldRule));
}
function evaluateFieldAbsentRules(projectRoot, rule) {
if (!rule.field_absent?.length) return true;
if (!rule.file) return false;
const parsed = parseManifestFile(projectRoot, rule.file);
if (parsed === null) return false;
return rule.field_absent.every((fieldName) => !hasNestedField(parsed, fieldName));
}
function checkFieldRule(manifest, fieldRule) {
const exists2 = hasNestedField(manifest, fieldRule.name);
if (fieldRule.presence === "absent") return !exists2;
if (fieldRule.presence === "required") return exists2;
if ("value" in fieldRule && fieldRule.value !== void 0) {
return exists2 && getNestedField(manifest, fieldRule.name) === fieldRule.value;
}
return exists2;
}
function hasNestedField(obj, dotPath) {
const parts = dotPath.split(".");
let current = obj;
for (const part of parts) {
if (current === null || typeof current !== "object") return false;
if (!(part in current)) return false;
current = current[part];
}
return true;
}
function getNestedField(obj, dotPath) {
const parts = dotPath.split(".");
let current = obj;
for (const part of parts) {
if (current === null || typeof current !== "object") return void 0;
current = current[part];
}
return current;
}
function parseManifestFile(projectRoot, file) {
const filePath = join13(projectRoot, file);
if (!existsSync4(filePath)) return null;
try {
const content = readFileSync5(filePath, "utf8");
return JSON.parse(content);
} catch {
return null;
}
}
function detectTraits(projectRoot, roots, traits, packageNames) {
const names = [];
const signals = [];
for (const trait of traits) {
if (trait.detect_package && packageNames.has(trait.detect_package)) {
names.push(trait.name);
signals.push({
signal: `${trait.name} detected from package metadata`,
file: "package metadata",
implies: trait.name,
confidence: "medium"
});
continue;
}
const fileRoot = trait.detect_file ? roots.find(
(root) => existsSync4(
join13(root === "." ? projectRoot : join13(projectRoot, root), trait.detect_file)
)
) : void 0;
if (trait.detect_file && fileRoot) {
names.push(trait.name);
signals.push({
signal: `${trait.name} detected from ${trait.detect_file}`,
file: prefixRepositoryPath(fileRoot, trait.detect_file),
implies: trait.name,
confidence: "medium"
});
continue;
}
const directoryRoot = trait.detect_directory ? roots.find(
(root) => existsSync4(
join13(root === "." ? projectRoot : join13(projectRoot, root), trait.detect_directory)
)
) : void 0;
if (trait.detect_directory && directoryRoot) {
names.push(trait.name);
signals.push({
signal: `${trait.name} detected from ${trait.detect_directory}`,
file: prefixRepositoryPath(directoryRoot, trait.detect_directory),
implies: trait.name,
confidence: "medium"
});
}
}
return { names: names.sort(), signals };
}
function buildRuleSignal(rule, implies) {
if (rule.file && rule.packages?.length) {
return `${implies} detected from ${rule.file} package metadata`;
}
if (rule.file && rule.fields?.length) {
return `${implies} detected from ${rule.file} manifest fields`;
}
if (rule.file) {
return `${implies} detected from ${rule.file}`;
}
if (rule.directory) {
return `${implies} detected from ${rule.directory}`;
}
if (rule.patterns?.length) {
return `${implies} detected from ${rule.patterns[0]}`;
}
return `${implies} detected from pack heuristics`;
}
function compareMatchedPacks(left, right) {
return right.priority - left.priority || right.score - left.score || left.name.localeCompare(right.name);
}
function isExcludedMatch(candidate, matches) {
return matches.some(
(match) => match.name !== candidate.name && match.excludes.includes(candidate.name)
);
}
function compareApplicationResults(left, right) {
const leftScore = left.matches[0]?.score ?? -1;
const rightScore = right.matches[0]?.score ?? -1;
return rightScore - leftScore || left.application.root.localeCompare(right.application.root);
}
function scoreToConfidence(score) {
if (score >= 2) {
return "high";
}
return "low";
}
function mergeEnvironmentTraits(projectRoot, roots, packages) {
const traits = /* @__PURE__ */ new Set();
const signals = [];
const sources = [];
for (const root of roots.length > 0 ? roots : ["."]) {
const packageNames = packages.filter((pkg) => (pkg.root ?? ".") === root).map((pkg) => pkg.name);
const absoluteRoot = root === "." ? projectRoot : join13(projectRoot, root);
const environment = detectEnvironmentTraits(absoluteRoot, { packageNames });
for (const trait of environment.traits) {
traits.add(trait);
}
sources.push(
...environment.sources.map((source) => ({
...source,
file: prefixRepositoryPath(root, source.file)
}))
);
signals.push(
...environment.signals.map((signal5) => ({
...signal5,
file: prefixRepositoryPath(root, signal5.file)
}))
);
}
return {
traits: Array.from(traits).sort(),
sources,
signals: dedupeSignals(signals)
};
}
function dedupeSignals(signals) {
const seen = /* @__PURE__ */ new Set();
return signals.filter((signal5) => {
const key = `${signal5.signal}:${signal5.file}:${signal5.implies}:${signal5.confidence}`;
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
function emptyRepositoryContext(projectRoot) {
return {
selected_root: projectRoot,
scan_max_depth: 0,
ignored_paths: [],
projects: [],
applications: [],
primary_project_root: null
};
}
function isCapability(value) {
return [
"inertia",
"vue",
"react",
"tailwind",
"boost",
"pest",
"phpunit",
"docker",
"compose",
"sail",
"next",
"remix",
"vite-spa",
"gatsby",
"nuxt",
"quasar",
"blazor",
"ef-core",
"minimal-api",
"mvc",
"razor-pages",
"signalr",
"azure",
"identity",
"app-router",
"pages-router",
"prisma",
"trpc",
"next-auth",
"sqlalchemy",
"celery",
"blueprints",
"flask-login",
"flask-restx",
"gunicorn",
"typeorm",
"graphql",
"microservices",
"swagger",
"passport",
"fastify",
"jetpack-compose",
"room",
"hilt",
"retrofit",
"coroutines",
"navigation",
"datastore"
].includes(value);
}
// src/detection/types.ts
init_esm_shims();
import { createHash as createHash4 } from "crypto";
var ID_SEED_SEPARATOR = "::";
function toStackDetectionResource(report, options = {}) {
const timestamp = report.timestamp;
const id = createHash4("sha256").update(`${options.projectRoot ?? ""}${ID_SEED_SEPARATOR}${timestamp}`).digest("hex");
const human = toHumanTimestamp(timestamp);
return {
id,
type: "stack_detection",
created_at: timestamp,
updated_at: timestamp,
created_at_human: human,
updated_at_human: human,
permissions: {
can_view: options.permissions?.can_view ?? true,
can_edit: options.permissions?.can_edit ?? false,
can_delete: options.permissions?.can_delete ?? false
},
report
};
}
function toHumanTimestamp(timestamp) {
const parsed = new Date(timestamp);
if (Number.isNaN(parsed.getTime())) {
return timestamp;
}
const iso = parsed.toISOString();
const [date, time] = iso.split("T");
return `${date} ${time.slice(0, 5)} UTC`;
}
// src/detection/signals/analytics-provider.ts
init_esm_shims();
function detectAnalyticsSignals(projectRoot) {
const detection = detectAnalyticsProvider(projectRoot);
return detection?.signals ?? [];
}
// src/detection/signals/flutter.ts
init_esm_shims();
var import_yaml3 = __toESM(require_dist(), 1);
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
import { join as join14 } from "path";
function detectFlutterSignals(projectRoot) {
const pubspecPath = join14(projectRoot, "pubspec.yaml");
if (!existsSync5(pubspecPath)) {
return [];
}
const pubspec = (0, import_yaml3.parse)(readFileSync6(pubspecPath, "utf8"));
if (pubspec.dependencies?.flutter === void 0) {
return [];
}
return [
{
signal: "pubspec.yaml declares flutter dependency",
file: "pubspec.yaml",
implies: "flutter",
confidence: "high"
}
];
}
// src/detection/signals/laravel.ts
init_esm_shims();
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
import { join as join15 } from "path";
function detectLaravelSignals(projectRoot) {
const signals = [];
const capabilities = /* @__PURE__ */ new Set();
const composerPath = join15(projectRoot, "composer.json");
const packageJsonPath = join15(projectRoot, "package.json");
if (existsSync6(join15(projectRoot, "artisan"))) {
signals.push(signal("artisan file exists", "artisan", "laravel", "high"));
}
if (existsSync6(composerPath)) {
const composer = readJsonFile(composerPath);
const dependencies = {
...composer.dependencies,
...composer.require
};
if (dependencies["laravel/framework"] !== void 0) {
signals.push(
signal("composer dependency laravel/framework", "composer.json", "laravel", "high")
);
}
if (dependencies["inertiajs/inertia-laravel"] !== void 0) {
capabilities.add("inertia");
signals.push(
signal("composer dependency inertiajs/inertia-laravel", "composer.json", "inertia", "high")
);
}
if (dependencies["laravel/boost"] !== void 0) {
capabilities.add("boost");
signals.push(signal("composer dependency laravel/boost", "composer.json", "boost", "high"));
}
if (dependencies["laravel/sail"] !== void 0) {
capabilities.add("sail");
signals.push(signal("composer dependency laravel/sail", "composer.json", "sail", "high"));
}
}
if (existsSync6(join15(projectRoot, "app"))) {
signals.push(signal("app directory exists", "app", "laravel", "medium"));
}
if (existsSync6(join15(projectRoot, "routes"))) {
signals.push(signal("routes directory exists", "routes", "laravel", "medium"));
}
if (existsSync6(packageJsonPath)) {
const packageJson = readJsonFile(packageJsonPath);
const dependencies = {
...packageJson.dependencies,
...packageJson.devDependencies
};
if (dependencies.react !== void 0) {
capabilities.add("react");
signals.push(signal("package dependency react", "package.json", "react", "high"));
}
if (dependencies.vue !== void 0) {
capabilities.add("vue");
signals.push(signal("package dependency vue", "package.json", "vue", "high"));
}
}
if (existsSync6(join15(projectRoot, "resources", "js", "App.tsx"))) {
capabilities.add("react");
signals.push(signal("React entrypoint found", "resources/js/App.tsx", "react", "high"));
}
if (existsSync6(join15(projectRoot, "config", "boost.php"))) {
capabilities.add("boost");
signals.push(signal("boost config exists", "config/boost.php", "boost", "high"));
}
return {
signals,
capabilities: Array.from(capabilities)
};
}
function readJsonFile(path10) {
return JSON.parse(readFileSync7(path10, "utf8"));
}
function signal(description, file, implies, confidence) {
return {
signal: description,
file,
implies,
confidence
};
}
// src/detection/signals/react.ts
init_esm_shims();
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
import { join as join16 } from "path";
function detectReactSignals(projectRoot) {
const signals = [];
const capabilities = /* @__PURE__ */ new Set();
const packageJsonPath = join16(projectRoot, "package.json");
const packageJson = existsSync7(packageJsonPath) ? readJsonFile2(packageJsonPath) : null;
const dependencies = {
...packageJson?.dependencies,
...packageJson?.devDependencies
};
if (dependencies.react !== void 0) {
signals.push(signal2("package dependency react", "package.json", "react", "high"));
}
if (dependencies["react-dom"] !== void 0) {
signals.push(signal2("package dependency react-dom", "package.json", "react", "high"));
}
if (dependencies.next !== void 0) {
capabilities.add("next");
signals.push(signal2("package dependency next", "package.json", "react", "high"));
}
if (dependencies.remix !== void 0 || dependencies["@remix-run/react"] !== void 0) {
capabilities.add("remix");
signals.push(signal2("Remix dependency detected", "package.json", "react", "high"));
}
if (dependencies.gatsby !== void 0) {
capabilities.add("gatsby");
signals.push(signal2("package dependency gatsby", "package.json", "react", "high"));
}
if (dependencies.tailwindcss !== void 0) {
capabilities.add("tailwind");
}
if (dependencies["@vitejs/plugin-react"] !== void 0) {
capabilities.add("vite-spa");
signals.push(
signal2("package dependency @vitejs/plugin-react", "package.json", "react", "medium")
);
}
if (fileIncludes(projectRoot, "vite.config.ts", "@vitejs/plugin-react")) {
capabilities.add("vite-spa");
signals.push(
signal2("vite config uses @vitejs/plugin-react", "vite.config.ts", "react", "medium")
);
}
if (existsSync7(join16(projectRoot, "src", "App.tsx")) || existsSync7(join16(projectRoot, "src", "App.jsx"))) {
signals.push(signal2("React App entrypoint found", "src/App.tsx", "react", "medium"));
}
if (existsSync7(join16(projectRoot, "src", "main.tsx")) || existsSync7(join16(projectRoot, "src", "index.tsx")) || existsSync7(join16(projectRoot, "src", "main.jsx")) || existsSync7(join16(projectRoot, "src", "index.jsx"))) {
signals.push(signal2("React main entrypoint found", "src/main.tsx", "react", "low"));
}
if (fileIncludes(projectRoot, "tsconfig.json", '"jsx"') && fileIncludes(projectRoot, "tsconfig.json", "react-jsx")) {
signals.push(
signal2("tsconfig jsx runtime set to react-jsx", "tsconfig.json", "react", "medium")
);
}
if (hasAnyExistingFile(projectRoot, [
".eslintrc",
".eslintrc.js",
".eslintrc.cjs",
".eslintrc.json"
])) {
const eslintFile = [".eslintrc", ".eslintrc.js", ".eslintrc.cjs", ".eslintrc.json"].find(
(file) => existsSync7(join16(projectRoot, file))
);
if (eslintFile && fileIncludes(projectRoot, eslintFile, "react")) {
signals.push(signal2("ESLint React plugin configuration found", eslintFile, "react", "low"));
}
}
if (capabilities.size === 0 && (fileIncludes(projectRoot, "vite.config.ts", "vite") || dependencies.vite !== void 0 || dependencies["@vitejs/plugin-react"] !== void 0)) {
capabilities.add("vite-spa");
}
return {
signals,
capabilities: Array.from(capabilities)
};
}
function readJsonFile2(path10) {
return JSON.parse(readFileSync8(path10, "utf8"));
}
function fileIncludes(projectRoot, relativePath, pattern) {
const path10 = join16(projectRoot, relativePath);
return existsSync7(path10) && readFileSync8(path10, "utf8").includes(pattern);
}
function hasAnyExistingFile(projectRoot, candidates) {
return candidates.some((candidate) => existsSync7(join16(projectRoot, candidate)));
}
function signal2(description, file, implies, confidence) {
return {
signal: description,
file,
implies,
confidence
};
}
// src/detection/signals/svelte.ts
init_esm_shims();
import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
import { join as join17 } from "path";
function detectSvelteSignals(projectRoot) {
const signals = [];
const capabilities = /* @__PURE__ */ new Set();
const packageJsonPath = join17(projectRoot, "package.json");
const packageJson = existsSync8(packageJsonPath) ? readJsonFile3(packageJsonPath) : null;
const dependencies = {
...packageJson?.dependencies,
...packageJson?.devDependencies
};
if (dependencies.svelte !== void 0) {
signals.push(signal3("package dependency svelte", "package.json", "svelte", "high"));
}
if (dependencies["@sveltejs/kit"] !== void 0) {
signals.push(signal3("package dependency @sveltejs/kit", "package.json", "svelte", "high"));
}
if (dependencies["@sveltejs/vite-plugin-svelte"] !== void 0) {
signals.push(
signal3("package dependency @sveltejs/vite-plugin-svelte", "package.json", "svelte", "high")
);
}
if (dependencies.tailwindcss !== void 0) {
capabilities.add("tailwind");
}
if (existsSync8(join17(projectRoot, "svelte.config.js")) || existsSync8(join17(projectRoot, "svelte.config.ts"))) {
signals.push(signal3("Svelte config found", "svelte.config.js", "svelte", "high"));
}
if (existsSync8(join17(projectRoot, "src", "routes"))) {
signals.push(signal3("SvelteKit routes directory found", "src/routes", "svelte", "medium"));
}
if (existsSync8(join17(projectRoot, "src", "app.html"))) {
signals.push(signal3("SvelteKit app.html found", "src/app.html", "svelte", "medium"));
}
if (fileIncludes2(projectRoot, "vite.config.ts", "@sveltejs/vite-plugin-svelte") || fileIncludes2(projectRoot, "vite.config.js", "@sveltejs/vite-plugin-svelte")) {
signals.push(signal3("vite config uses Svelte plugin", "vite.config.ts", "svelte", "medium"));
}
return {
signals,
capabilities: Array.from(capabilities)
};
}
function readJsonFile3(path10) {
return JSON.parse(readFileSync9(path10, "utf8"));
}
function fileIncludes2(projectRoot, relativePath, pattern) {
const path10 = join17(projectRoot, relativePath);
return existsSync8(path10) && readFileSync9(path10, "utf8").includes(pattern);
}
function signal3(description, file, implies, confidence) {
return {
signal: description,
file,
implies,
confidence
};
}
// src/detection/signals/vue.ts
init_esm_shims();
import { existsSync as existsSync9, readFileSync as readFileSync10 } from "fs";
import { join as join18 } from "path";
function detectVueSignals(projectRoot) {
const signals = [];
const capabilities = /* @__PURE__ */ new Set();
const packageJsonPath = join18(projectRoot, "package.json");
const packageJson = existsSync9(packageJsonPath) ? readJsonFile4(packageJsonPath) : null;
const dependencies = {
...packageJson?.dependencies,
...packageJson?.devDependencies
};
if (dependencies.vue !== void 0) {
signals.push(signal4("package dependency vue", "package.json", "vue", "high"));
}
if (dependencies.nuxt !== void 0) {
capabilities.add("nuxt");
signals.push(signal4("package dependency nuxt", "package.json", "vue", "high"));
}
if (dependencies.quasar !== void 0 || dependencies["@quasar/app-vite"] !== void 0) {
capabilities.add("quasar");
signals.push(signal4("Quasar dependency detected", "package.json", "vue", "high"));
}
if (dependencies["@vitejs/plugin-vue"] !== void 0) {
capabilities.add("vite-spa");
signals.push(signal4("package dependency @vitejs/plugin-vue", "package.json", "vue", "high"));
}
if (dependencies["vue-router"] !== void 0) {
signals.push(signal4("package dependency vue-router", "package.json", "vue", "medium"));
}
if (dependencies.pinia !== void 0 || dependencies.vuex !== void 0) {
signals.push(signal4("Vue state library detected", "package.json", "vue", "medium"));
}
if (dependencies.tailwindcss !== void 0) {
capabilities.add("tailwind");
}
if (existsSync9(join18(projectRoot, "src", "App.vue"))) {
signals.push(signal4("Vue App entrypoint found", "src/App.vue", "vue", "high"));
}
if (existsSync9(join18(projectRoot, "nuxt.config.ts")) || existsSync9(join18(projectRoot, "nuxt.config.js"))) {
capabilities.add("nuxt");
signals.push(signal4("Nuxt config found", "nuxt.config.ts", "vue", "high"));
}
if (fileIncludes3(projectRoot, "vite.config.ts", "pluginVue") || fileIncludes3(projectRoot, "vite.config.ts", "@vitejs/plugin-vue")) {
capabilities.add("vite-spa");
signals.push(signal4("vite config uses Vue plugin", "vite.config.ts", "vue", "medium"));
}
if (capabilities.size === 0 && (fileIncludes3(projectRoot, "vite.config.ts", "vite") || dependencies.vite !== void 0 || dependencies["@vitejs/plugin-vue"] !== void 0)) {
capabilities.add("vite-spa");
}
return {
signals,
capabilities: Array.from(capabilities)
};
}
function readJsonFile4(path10) {
return JSON.parse(readFileSync10(path10, "utf8"));
}
function fileIncludes3(projectRoot, relativePath, pattern) {
const path10 = join18(projectRoot, relativePath);
return existsSync9(path10) && readFileSync10(path10, "utf8").includes(pattern);
}
function signal4(description, file, implies, confidence) {
return {
signal: description,
file,
implies,
confidence
};
}
// src/event-bus/index.ts
init_esm_shims();
// src/event-bus/types.ts
init_esm_shims();
// src/event-bus/engine-event-bus.ts
init_esm_shims();
import { randomUUID } from "crypto";
var DEFAULT_BUFFER_SIZE = 512;
var DEFAULT_MAX_PAYLOAD_BYTES = 65536;
var DEFAULT_NEVER_DROP = [
"decision-paused",
"decision-resolved",
"decision-packet-corrupt",
"decision-cap-exceeded",
"decision-discarded"
];
var EngineEventBus = class {
subscribers = /* @__PURE__ */ new Map();
bufferSize;
neverDrop;
maxPayloadBytes;
drainScheduled = false;
constructor(options = {}) {
this.bufferSize = options.bufferSize && options.bufferSize > 0 ? options.bufferSize : DEFAULT_BUFFER_SIZE;
this.maxPayloadBytes = options.maxPayloadBytes && options.maxPayloadBytes > 0 ? options.maxPayloadBytes : DEFAULT_MAX_PAYLOAD_BYTES;
this.neverDrop = /* @__PURE__ */ new Set([...options.neverDrop ?? DEFAULT_NEVER_DROP, "events-coalesced"]);
}
subscribe(callback, filter) {
const id = randomUUID();
const subscribers = this.subscribers;
const handle = {
id,
get state() {
return subscribers.get(id)?.state ?? "cancelled";
},
unsubscribe: () => this.unsubscribe(id)
};
const record2 = {
id,
callback,
kinds: filter ? new Set(filter.kinds) : null,
capacity: this.bufferSize,
ring: [],
droppedSinceMarker: 0,
state: "active",
handle
};
this.subscribers.set(id, record2);
return handle;
}
emit(event) {
const delivered = this.truncateIfOversized(event);
for (const record2 of this.subscribers.values()) {
if (record2.state !== "active") continue;
if (record2.kinds && !record2.kinds.has(delivered.kind)) continue;
this.enqueue(record2, delivered);
}
this.scheduleDrain();
}
unsubscribe(id) {
const record2 = this.subscribers.get(id);
if (!record2) return;
record2.state = "cancelled";
record2.ring = [];
record2.droppedSinceMarker = 0;
this.subscribers.delete(id);
}
subscriberCount() {
return this.subscribers.size;
}
activeSubscriberCount() {
let count2 = 0;
for (const record2 of this.subscribers.values()) {
if (record2.state === "active") count2 += 1;
}
return count2;
}
enqueue(record2, event) {
if (record2.ring.length >= record2.capacity) {
const dropIndex = record2.ring.findIndex((e) => !this.neverDrop.has(e.kind));
if (dropIndex === -1) {
record2.droppedSinceMarker += 1;
return;
}
record2.ring.splice(dropIndex, 1);
record2.droppedSinceMarker += 1;
}
record2.ring.push(event);
}
scheduleDrain() {
if (this.drainScheduled) return;
this.drainScheduled = true;
queueMicrotask(() => this.drain());
}
drain() {
this.drainScheduled = false;
for (const record2 of [...this.subscribers.values()]) {
this.deliver(record2);
}
}
deliver(record2) {
while (record2.state === "active" && (record2.ring.length > 0 || record2.droppedSinceMarker > 0)) {
let next;
if (record2.droppedSinceMarker > 0) {
next = {
kind: "events-coalesced",
at: (/* @__PURE__ */ new Date()).toISOString(),
droppedCount: record2.droppedSinceMarker
};
record2.droppedSinceMarker = 0;
} else {
next = record2.ring.shift();
}
try {
record2.callback(next);
} catch {
record2.state = "faulted";
record2.ring = [];
record2.droppedSinceMarker = 0;
return;
}
}
}
truncateIfOversized(event) {
if (JSON.stringify(event).length <= this.maxPayloadBytes) {
return event;
}
const clone = { ...event };
for (const [key, value] of Object.entries(clone)) {
if (key === "kind" || key === "at") continue;
if (typeof value === "string" && value.length > 64) {
clone[key] = `${value.slice(0, 64)}\u2026[truncated]`;
}
}
clone.truncated = true;
return clone;
}
};
// src/design-tokens/index.ts
init_esm_shims();
// src/design-tokens/defaults.ts
init_esm_shims();
var PLACEHOLDER_DESIGN_TOKENS = {
color: {
primary: {
$value: "#000000",
$type: "color",
$description: "PLACEHOLDER \u2014 replace with your primary brand color."
},
secondary: {
$value: "#000000",
$type: "color",
$description: "PLACEHOLDER \u2014 replace with your secondary brand color."
},
surface: {
$value: "#FFFFFF",
$type: "color",
$description: "PLACEHOLDER \u2014 replace with your default surface color."
},
text: {
default: {
$value: "#000000",
$type: "color",
$description: "PLACEHOLDER \u2014 replace with your default text color."
}
}
},
typography: {
fontFamily: {
body: {
$value: "system-ui, sans-serif",
$type: "fontFamily",
$description: "PLACEHOLDER \u2014 replace with your body font stack."
},
display: {
$value: "system-ui, sans-serif",
$type: "fontFamily",
$description: "PLACEHOLDER \u2014 replace with your display font stack."
}
}
},
spacing: {
sm: { $value: "0.5rem", $type: "dimension", $description: "PLACEHOLDER spacing step." },
md: { $value: "1rem", $type: "dimension", $description: "PLACEHOLDER spacing step." },
lg: { $value: "1.5rem", $type: "dimension", $description: "PLACEHOLDER spacing step." }
},
radius: {
md: { $value: "0.5rem", $type: "dimension", $description: "PLACEHOLDER corner radius." }
}
};
// src/design-tokens/service.ts
init_esm_shims();
import { mkdir as mkdir13, readFile as readFile12, writeFile as writeFile13 } from "fs/promises";
import { dirname as dirname9, join as join19 } from "path";
var GENERATED_DOC_BANNER = `<!-- GENERATED by paqad-ai from ${PATHS.DESIGN_TOKENS_FILE} \u2014 do not edit. Edit that file instead; these docs are regenerated by the documentation workflow. -->`;
function withGeneratedBanner(content) {
return `${GENERATED_DOC_BANNER}
${content}`;
}
var DESIGN_TOKENS_PLACEHOLDER_NOTE = `PLACEHOLDER design tokens seeded by paqad-ai. Replace these values with your project's real design tokens, then delete this "$comment". Until then, design-system docs (tokens.md, components.md, \u2026) are intentionally not generated, because they would describe a design system that does not exist.`;
var DesignTokensMissingError = class extends Error {
constructor(path10) {
super(
`Design tokens file not found at ${path10}. Run the documentation workflow ("create documentation") to seed a placeholder tokens file, or create the file manually.`
);
this.path = path10;
this.name = "DesignTokensMissingError";
}
path;
};
var DesignTokensPlaceholderError = class extends Error {
constructor(path10) {
super(
`Design tokens at ${path10} are still the placeholder scaffold. Fill in your project's real tokens (and delete the placeholder "$comment"), then re-run the documentation workflow to generate design-system docs.`
);
this.path = path10;
this.name = "DesignTokensPlaceholderError";
}
path;
};
function isPlaceholder(tokens) {
return tokens.$comment === DESIGN_TOKENS_PLACEHOLDER_NOTE;
}
var DesignTokenService = class {
constructor(validator = new SchemaValidator()) {
this.validator = validator;
}
validator;
async seed(projectRoot) {
const target = join19(projectRoot, PATHS.DESIGN_TOKENS_FILE);
const seeded = {
$comment: DESIGN_TOKENS_PLACEHOLDER_NOTE,
...PLACEHOLDER_DESIGN_TOKENS
};
await mkdir13(dirname9(target), { recursive: true });
await writeFile13(target, `${JSON.stringify(seeded, null, 2)}
`, {
flag: "wx"
}).catch((error) => {
if (error.code !== "EEXIST") {
throw error;
}
});
}
async load(projectRoot) {
const target = join19(projectRoot, PATHS.DESIGN_TOKENS_FILE);
let raw;
try {
raw = await readFile12(target, "utf8");
} catch (error) {
if (error.code === "ENOENT") {
throw new DesignTokensMissingError(target);
}
throw error;
}
const parsed = JSON.parse(raw);
const validation = this.validator.validate("design-tokens", parsed);
if (!validation.valid) {
throw new Error(
`Invalid design token file: ${validation.errors.map((error) => error.message).join("; ")}`
);
}
return parsed;
}
async generateDocs(projectRoot) {
const tokens = await this.load(projectRoot);
if (isPlaceholder(tokens)) {
throw new DesignTokensPlaceholderError(join19(projectRoot, PATHS.DESIGN_TOKENS_FILE));
}
const flattened = flattenTokens(tokens);
const sections2 = groupTokens(flattened);
return [
{
path: join19(PATHS.DESIGN_SYSTEM_DIR, "tokens.md"),
content: withGeneratedBanner(buildTokensMarkdown(flattened))
},
{
path: join19(PATHS.DESIGN_SYSTEM_DIR, "components.md"),
content: withGeneratedBanner(
buildSectionMarkdown("Component Defaults", sections2.components)
)
},
{
path: join19(PATHS.DESIGN_SYSTEM_DIR, "motion.md"),
content: withGeneratedBanner(buildSectionMarkdown("Motion", sections2.motion))
},
{
path: join19(PATHS.DESIGN_SYSTEM_DIR, "accessibility.md"),
content: withGeneratedBanner(buildSectionMarkdown("Accessibility", sections2.accessibility))
},
{
path: join19(PATHS.DESIGN_SYSTEM_DIR, "responsive.md"),
content: withGeneratedBanner(buildResponsiveMarkdown(sections2.spacing))
},
{
path: join19(PATHS.DESIGN_SYSTEM_DIR, "patterns.md"),
content: withGeneratedBanner(buildPatternsMarkdown(flattened))
}
];
}
async writeDocs(projectRoot) {
const docs = await this.generateDocs(projectRoot);
await Promise.all(
docs.map(async (artifact) => {
const target = join19(projectRoot, artifact.path);
await mkdir13(dirname9(target), { recursive: true });
await writeFile13(target, artifact.content);
})
);
return docs.map((artifact) => artifact.path);
}
async exportTheme(projectRoot, stack) {
const tokens = await this.load(projectRoot);
if (isPlaceholder(tokens)) {
throw new DesignTokensPlaceholderError(join19(projectRoot, PATHS.DESIGN_TOKENS_FILE));
}
const flattened = flattenTokens(tokens);
const cssVariables = flattened.map((token) => ` --${token.key.replace(/\./g, "-")}: ${stringifyValue(token.value)};`).join("\n");
const tailwindEntries = flattened.filter((token) => token.type === "color").map((token) => ` '${token.key.replace(/\./g, "-")}' : '${stringifyValue(token.value)}',`).join("\n");
const flutterEntries = flattened.filter((token) => token.type === "color").map(
(token) => ` static const String ${toIdentifier(token.key)} = '${stringifyValue(token.value)}';`
).join("\n");
const artifacts = [
{
path: ".paqad/theme/theme.css",
content: `:root {
${cssVariables}
}
`
},
{
path: ".paqad/theme/tailwind.theme.cjs",
content: `module.exports = {
theme: {
extend: {
colors: {
${tailwindEntries}
},
},
},
};
`
}
];
if (stack === "flutter") {
artifacts.push({
path: ".paqad/theme/theme_tokens.dart",
content: `class ThemeTokens {
${flutterEntries}
}
`
});
}
return artifacts;
}
async writeThemeExports(projectRoot, stack) {
const artifacts = await this.exportTheme(projectRoot, stack);
await Promise.all(
artifacts.map(async (artifact) => {
const target = join19(projectRoot, artifact.path);
await mkdir13(dirname9(target), { recursive: true });
await writeFile13(target, artifact.content);
})
);
return artifacts.map((artifact) => artifact.path);
}
};
function flattenTokens(node, pathSegments = [], tokens = []) {
for (const [key, value] of Object.entries(node)) {
if (key.startsWith("$")) {
continue;
}
const nextPath = [...pathSegments, key];
if (isTokenLeaf(value)) {
tokens.push({
key: nextPath.join("."),
type: value.$type,
value: value.$value,
description: value.$description
});
continue;
}
flattenTokens(value, nextPath, tokens);
}
return tokens.sort((left, right) => left.key.localeCompare(right.key));
}
function isTokenLeaf(value) {
return typeof value === "object" && value !== null && "$value" in value && "$type" in value && typeof value.$type === "string";
}
function groupTokens(tokens) {
return {
components: tokens.filter((token) => token.key.startsWith("components.")),
motion: tokens.filter((token) => token.key.startsWith("motion.")),
accessibility: tokens.filter((token) => token.key.startsWith("accessibility.")),
spacing: tokens.filter((token) => token.key.startsWith("spacing."))
};
}
function buildTokensMarkdown(tokens) {
const lines = ["# Design Tokens", "", "| Token | Type | Value |", "| --- | --- | --- |"];
for (const token of tokens) {
lines.push(`| \`${token.key}\` | \`${token.type}\` | \`${stringifyValue(token.value)}\` |`);
}
return `${lines.join("\n")}
`;
}
function buildSectionMarkdown(title, tokens) {
const lines = [`# ${title}`, ""];
if (tokens.length === 0) {
lines.push("No tokens defined yet.", "");
return lines.join("\n");
}
for (const token of tokens) {
lines.push(`- \`${token.key}\`: \`${stringifyValue(token.value)}\``);
}
lines.push("");
return lines.join("\n");
}
function buildResponsiveMarkdown(tokens) {
const lines = ["# Responsive Design", "", "## Spacing Scale", ""];
for (const token of tokens) {
lines.push(`- \`${token.key}\`: \`${stringifyValue(token.value)}\``);
}
lines.push("", "Use the spacing scale as the basis for layout density and breakpoints.", "");
return lines.join("\n");
}
function buildPatternsMarkdown(tokens) {
const highlighted = tokens.filter(
(token) => ["color.primary", "color.secondary", "typography.heading.h1", "components.button.radius"].some(
(prefix) => token.key.startsWith(prefix)
)
);
const lines = ["# Design Patterns", "", "## Framework Guidance", ""];
for (const token of highlighted) {
lines.push(`- Base pattern from \`${token.key}\`: \`${stringifyValue(token.value)}\``);
}
lines.push(
"",
"Keep generated UI aligned with these tokens before introducing new variants.",
""
);
return lines.join("\n");
}
function stringifyValue(value) {
return typeof value === "string" ? value : JSON.stringify(value);
}
function toIdentifier(value) {
return value.replace(/[^a-zA-Z0-9]+(.)/g, (_, character) => character.toUpperCase());
}
// src/health/index.ts
init_esm_shims();
// src/health/checker.ts
init_esm_shims();
import { execFileSync as execFileSync5 } from "child_process";
import { existsSync as existsSync18, readdirSync as readdirSync3, readFileSync as readFileSync17, statSync as statSync4 } from "fs";
import { join as join31, relative as relative7 } from "path";
// src/install/plugin-migration.ts
init_esm_shims();
import { execFileSync, spawnSync } from "child_process";
import {
existsSync as existsSync10,
mkdirSync as mkdirSync2,
readFileSync as readFileSync11,
readdirSync as readdirSync2,
readlinkSync,
renameSync as renameSync3,
rmSync as rmSync2,
statSync as statSync2,
writeFileSync as writeFileSync3
} from "fs";
import { homedir } from "os";
import { dirname as dirname10, join as join20 } from "path";
var MARKETPLACE_ADD_TIMEOUT_MS = 12e4;
var INSTALL_TIMEOUT_MS = 18e4;
var UNINSTALL_TIMEOUT_MS = 12e4;
var MIN_CLAUDE_VERSION = "2.1.295";
var RETRY_WINDOW_MS = 24 * 60 * 60 * 1e3;
var MANAGED_POLICY_RECHECK_MS = 7 * 24 * 60 * 60 * 1e3;
var MAX_ATTEMPTS = 5;
var ROLLBACK_AFTER_NPM_SESSIONS = 3;
var INSTALL_WAIT_MS = 7 * 24 * 60 * 60 * 1e3;
var MAX_COUNTED_SESSIONS = 10;
function paqadHome(home) {
return join20(home, ".paqad-ai");
}
function migrationStatePath(home) {
return join20(paqadHome(home), "plugin-migration.json");
}
function migrationLockDir(home) {
return join20(paqadHome(home), "locks", "plugin-migration.lock");
}
function pluginSeenPath(home) {
return join20(paqadHome(home), "plugin-seen.json");
}
function migrationLogPath(home) {
return join20(paqadHome(home), "logs", "plugin-migration.log");
}
function userClaudeSettingsPath(home) {
return join20(home, ".claude", "settings.json");
}
function readMigrationState(home) {
try {
return JSON.parse(readFileSync11(migrationStatePath(home), "utf8"));
} catch {
return null;
}
}
function writeMigrationState(home, record2) {
const path10 = migrationStatePath(home);
try {
mkdirSync2(dirname10(path10), { recursive: true });
const tmp = `${path10}.${process.pid}.tmp`;
writeFileSync3(tmp, `${JSON.stringify(record2, null, 2)}
`);
renameSync3(tmp, path10);
} catch {
}
}
function readPluginSeen(home) {
try {
return JSON.parse(readFileSync11(pluginSeenPath(home), "utf8"));
} catch {
return null;
}
}
function clearPluginSeen(home) {
try {
rmSync2(pluginSeenPath(home), { force: true });
} catch {
}
}
function isSyncedRoot(root) {
if (typeof root !== "string") return false;
const path10 = root.replaceAll("\\", "/");
if (path10.includes("/plugins/synced/")) return true;
const sessions = path10.indexOf("/Claude/local-agent-mode-sessions/");
return sessions !== -1 && path10.indexOf("/rpm/plugin_", sessions) !== -1;
}
function isPluginPresent(home) {
return isPluginInstalledRecord(home) || readPluginSeen(home) !== null;
}
function isPluginInstalledRecord(home) {
const installed = join20(home, ".claude", "plugins", "installed_plugins.json");
try {
return JSON.stringify(JSON.parse(readFileSync11(installed, "utf8"))).includes(PLUGIN_ID);
} catch {
return false;
}
}
function userDisabledPlugin(home) {
try {
const settings = JSON.parse(readFileSync11(userClaudeSettingsPath(home), "utf8"));
return settings.enabledPlugins?.[PLUGIN_ID] === false;
} catch {
return false;
}
}
function doneButDisabled(record2, home) {
return record2?.state === "done" && userDisabledPlugin(home);
}
var USER_DISABLED_REASON = "user-disabled";
function isCiOrHeadless(env2) {
return typeof env2.CI === "string" && env2.CI !== "" || typeof env2.PAQAD_HEADLESS === "string" && env2.PAQAD_HEADLESS !== "" || env2.CLAUDE_CODE_ENTRYPOINT === "sdk-cli";
}
function projectTargetsClaudeCode(projectRoot) {
try {
const manifest = JSON.parse(
readFileSync11(join20(projectRoot, PATHS.ONBOARDING_MANIFEST), "utf8")
);
if (manifest.adapter === "claude-code") return true;
return (manifest.generated_artifacts ?? []).some(
(artifact) => artifact.path.replaceAll("\\", "/") === "CLAUDE.md"
);
} catch {
return false;
}
}
function defaultManagedSettingsPaths(platform = process.platform) {
const base = platform === "darwin" ? "/Library/Application Support/ClaudeCode" : platform === "win32" ? "C:\\Program Files\\ClaudeCode" : "/etc/claude-code";
const dir = join20(base, "managed-settings.d");
const files = [join20(base, "managed-settings.json")];
try {
for (const name of readdirSync2(dir)) {
if (name.endsWith(".json")) files.push(join20(dir, name));
}
} catch {
}
return files;
}
function classifyManagedPolicy(paths) {
let found = null;
for (const path10 of paths) {
const policy = readPolicyFile(path10);
if (!policy) continue;
if (policy.allowManagedHooksOnly === true || policy.disableAllHooks === true) {
return "hooks-blocked";
}
if (policyBlocksPlugin(policy)) found = "plugin-blocked";
}
return found;
}
function readPolicyFile(path10) {
try {
const parsed = JSON.parse(readFileSync11(path10, "utf8"));
return isRecord2(parsed) ? parsed : null;
} catch {
return null;
}
}
function policyBlocksPlugin(policy) {
const enabled = policy.enabledPlugins;
if (isRecord2(enabled) && enabled[PLUGIN_ID] === false) return true;
const strict = policy.strictKnownMarketplaces;
if (Array.isArray(strict) && !marketplaceReferenced(strict)) return true;
const blocked = policy.blockedMarketplaces;
return Array.isArray(blocked) && marketplaceReferenced(blocked);
}
function managedPolicyBlockReason(paths) {
return classifyManagedPolicy(paths) === null ? null : "managed-policy";
}
function marketplaceReferenced(list) {
return list.some((entry) => JSON.stringify(entry).includes(PLUGIN_MARKETPLACE_REPO));
}
var PROJECT_TURNS_PLUGIN_ON_REASON = "project-turns-plugin-on";
var CONFIG_SKIP_REASONS = /* @__PURE__ */ new Set([
"migration-off",
"install-mode-settings",
"no-claude-code-provider",
"ci-or-headless",
PROJECT_TURNS_PLUGIN_ON_REASON
]);
var AUTO_ROLLBACK_REASON = "plugin-never-loaded";
var NEVER_INSTALLED_REASON = "plugin-never-installed";
var AUTO_ROLLBACK_REASONS = /* @__PURE__ */ new Set([AUTO_ROLLBACK_REASON, NEVER_INSTALLED_REASON]);
function isSettled(record2) {
if (record2.state === "rolled-back") return !AUTO_ROLLBACK_REASONS.has(record2.reason ?? "");
return record2.state === "done" || record2.state === "declined";
}
function retryAllowed(record2, now) {
if (!record2) return true;
if (isSettled(record2)) return false;
if (record2.attempts >= MAX_ATTEMPTS) return false;
const configSkip = isConfigSkip(record2.state, record2.reason);
const at2 = configSkip ? record2.last_real_attempt_at : record2.last_real_attempt_at ?? record2.last_attempt_at;
if (!at2) return true;
const reason2 = configSkip ? record2.last_real_reason : record2.reason;
const since = now.getTime() - new Date(at2).getTime();
const window = reason2 === "managed-policy" ? MANAGED_POLICY_RECHECK_MS : RETRY_WINDOW_MS;
return since >= window;
}
function isConfigSkip(state, reason2) {
return state === "skipped" && CONFIG_SKIP_REASONS.has(reason2 ?? "");
}
function installViaSettings(home) {
const path10 = userClaudeSettingsPath(home);
let settings = {};
if (existsSync10(path10)) {
try {
settings = JSON.parse(readFileSync11(path10, "utf8"));
} catch {
return { state: "failed", reason: "user-settings-unreadable" };
}
}
const existingEnabled = settings.enabledPlugins;
if (existingEnabled && existingEnabled[PLUGIN_ID] === false) {
return { state: "declined", reason: "user-opted-out" };
}
const keys = pluginSettingsKeys();
const next = {
...settings,
extraKnownMarketplaces: {
...settings.extraKnownMarketplaces ?? {},
...keys.extraKnownMarketplaces
},
enabledPlugins: {
...settings.enabledPlugins ?? {},
...keys.enabledPlugins
}
};
try {
mkdirSync2(dirname10(path10), { recursive: true });
const tmp = `${path10}.${process.pid}.tmp`;
writeFileSync3(tmp, `${JSON.stringify(next, null, 2)}
`);
renameSync3(tmp, path10);
} catch {
return { state: "failed", reason: "user-settings-write-failed" };
}
return { state: "installed" };
}
function undoViaSettings(home) {
const path10 = userClaudeSettingsPath(home);
let settings;
try {
settings = JSON.parse(readFileSync11(path10, "utf8"));
} catch {
return;
}
const marketplaces = settings.extraKnownMarketplaces;
if (marketplaces) delete marketplaces[PLUGIN_MARKETPLACE_KEY];
const enabled = settings.enabledPlugins;
if (enabled) delete enabled[PLUGIN_ID];
try {
const tmp = `${path10}.${process.pid}.tmp`;
writeFileSync3(tmp, `${JSON.stringify(settings, null, 2)}
`);
renameSync3(tmp, path10);
} catch {
}
}
function resolveDeps(deps) {
const home = deps.home ?? homedir();
return {
env: deps.env ?? process.env,
home,
now: deps.now ?? (() => /* @__PURE__ */ new Date()),
version: deps.version ?? VERSION,
claudeVersion: deps.claudeVersion ?? defaultClaudeVersion,
runClaudeInstall: deps.runClaudeInstall ?? defaultRunClaudeInstall,
bundledClaude: deps.bundledClaude ?? (() => findBundledClaude(home)),
runClaudeUninstall: deps.runClaudeUninstall ?? (() => {
}),
managedSettingsPaths: deps.managedSettingsPaths ?? defaultManagedSettingsPaths(),
log: deps.log ?? ((message) => appendMigrationLog(home, message))
};
}
function appendMigrationLog(home, message) {
try {
const path10 = migrationLogPath(home);
mkdirSync2(dirname10(path10), { recursive: true });
writeFileSync3(path10, `${(/* @__PURE__ */ new Date()).toISOString()} ${message}
`, { flag: "a" });
} catch {
}
}
function defaultClaudeVersion() {
try {
const out = execFileSync("claude", ["--version"], {
encoding: "utf8",
timeout: 12e4,
stdio: ["ignore", "pipe", "ignore"],
windowsHide: true,
shell: process.platform === "win32"
});
const match = out.match(/(\d+\.\d+\.\d+)/);
return match ? match[1] : null;
} catch {
return null;
}
}
function defaultRunClaudeInstall() {
return { ok: false, reason: "claude-cli-unavailable" };
}
function record(deps, prior, patch) {
const nowIso = deps.now().toISOString();
const next = {
attempts: prior?.attempts ?? 0,
npm_sessions_since_install: prior?.npm_sessions_since_install,
...prior,
...patch,
version: deps.version,
last_attempt_at: nowIso
};
if ((patch.state === "installed" || patch.state === "done") && !("reason" in patch)) {
delete next.reason;
}
if (patch.state === "installed" && prior?.state !== "installed") {
next.installed_at = nowIso;
next.counted_sessions = [];
}
if (!isConfigSkip(next.state, next.reason)) {
next.last_real_attempt_at = nowIso;
next.last_real_reason = next.reason;
} else if (prior && !prior.last_real_attempt_at && !isConfigSkip(prior.state, prior.reason)) {
next.last_real_attempt_at = prior.last_attempt_at;
next.last_real_reason = prior.reason;
}
writeMigrationState(deps.home, next);
return { state: next.state, path: next.path, reason: next.reason };
}
function maybeMigrateToPlugin(projectRoot, deps = {}) {
try {
return runMigration(projectRoot, resolveDeps(deps));
} catch (error) {
return { state: "skipped", reason: `error:${error.message}` };
}
}
function runMigration(projectRoot, deps) {
const prior = readMigrationState(deps.home);
if (doneButDisabled(prior, deps.home)) {
return record(deps, prior, { state: "declined", reason: USER_DISABLED_REASON });
}
if (prior && isSettled(prior)) {
return { state: prior.state, path: prior.path, reason: prior.reason };
}
if (prior && prior.state === "installed") {
const installed = withInstalledAt(deps.home, prior);
if (isPluginSeenFresh(installed, readPluginSeen(deps.home))) {
return confirmDone(deps, installed);
}
return { state: installed.state, path: installed.path, reason: installed.reason };
}
const cfg = resolvePluginMigrationConfig(projectRoot, deps.env);
if (cfg.install_mode === "settings") {
return record(deps, prior, { state: "skipped", reason: "install-mode-settings" });
}
if (cfg.migration !== "on" && cfg.install_mode !== "plugin") {
return record(deps, prior, { state: "skipped", reason: "migration-off" });
}
if (!projectTargetsClaudeCode(projectRoot)) {
return record(deps, prior, { state: "skipped", reason: "no-claude-code-provider" });
}
if (projectTurnsPluginOn(projectRoot)) {
if (prior?.reason !== PROJECT_TURNS_PLUGIN_ON_REASON) {
deps.log(
"this project turns the plugin on in .claude/settings.json; user-scope move not needed"
);
}
return record(deps, prior, { state: "skipped", reason: PROJECT_TURNS_PLUGIN_ON_REASON });
}
if (isCiOrHeadless(deps.env)) {
return record(deps, prior, { state: "skipped", reason: "ci-or-headless" });
}
if (!retryAllowed(prior, deps.now())) {
return { state: prior?.state ?? "skipped", reason: "retry-not-due" };
}
const policyReason = managedPolicyBlockReason(deps.managedSettingsPaths);
if (policyReason) {
return record(deps, prior, {
state: "skipped",
reason: policyReason,
attempts: (prior?.attempts ?? 0) + 1
});
}
if (isPluginPresent(deps.home)) {
return recordPresentPlugin(deps, prior);
}
if (!acquireLock2(deps.home)) {
return { state: prior?.state ?? "skipped", reason: "locked" };
}
try {
return performInstall(deps, prior);
} finally {
releaseLock2(deps.home);
}
}
function recordPresentPlugin(deps, prior) {
if (isSyncedRoot(readPluginSeen(deps.home)?.root)) {
deps.log("plugin synced from claude.ai; nothing to install");
return record(deps, prior, { state: "done", path: "synced" });
}
const attempts = (prior?.attempts ?? 0) + 1;
const settings = installViaSettings(deps.home);
if (settings.state !== "installed") {
deps.log(
`plugin already present; not turned on (${settings.state}: ${settings.reason ?? "unknown"})`
);
return record(deps, prior, { state: settings.state, reason: settings.reason, attempts });
}
deps.log("plugin already present; turned it on in the user settings");
return record(deps, prior, {
state: "installed",
path: "settings",
attempts,
npm_sessions_since_install: 0
});
}
function performInstall(deps, prior) {
if (userDisabledPlugin(deps.home)) {
deps.log("user turned the plugin off; not installing");
return record(deps, prior, { state: "declined", reason: "user-opted-out" });
}
const attempts = (prior?.attempts ?? 0) + 1;
const version = deps.claudeVersion();
if (version !== null && versionAtLeast(version, MIN_CLAUDE_VERSION)) {
const run3 = deps.runClaudeInstall(deps.home, deps.env);
if (run3.ok) return recordCliInstall(deps, prior, attempts, "cli", `claude ${version}`);
const reason3 = `path-a-failed:${run3.reason ?? "unknown"}`;
deps.log(`path A failed (${run3.reason ?? "unknown"})`);
return record(deps, prior, { state: "failed", reason: reason3, attempts });
}
const bundled = deps.bundledClaude();
if (bundled === null && version !== null) {
deps.log(`claude ${version} is older than ${MIN_CLAUDE_VERSION} and no bundled claude found`);
return record(deps, prior, { state: "skipped", reason: `claude-too-old:${version}`, attempts });
}
if (bundled === null) {
deps.log("no claude on PATH and no bundled claude from the Desktop app");
return record(deps, prior, { state: "skipped", reason: "no-claude-cli", attempts });
}
const run2 = deps.runClaudeInstall(deps.home, deps.env, bundled);
if (run2.ok) return recordCliInstall(deps, prior, attempts, "bundled-cli", bundled);
const reason2 = `bundled-cli-failed:${run2.reason ?? "unknown"}`;
deps.log(`bundled claude install failed (${run2.reason ?? "unknown"})`);
return record(deps, prior, { state: "skipped", reason: reason2, attempts });
}
function recordCliInstall(deps, prior, attempts, path10, via) {
const settings = installViaSettings(deps.home);
if (settings.state !== "installed") {
deps.log(
`user settings not written after the ${path10} install (${settings.state}: ${settings.reason ?? "unknown"})`
);
}
deps.log(`installed via ${path10} (${via})`);
return record(deps, prior, {
state: "installed",
path: path10,
attempts,
npm_sessions_since_install: 0
});
}
var BUNDLED_CLAUDE_SEARCH_DEPTH = 4;
function findBundledClaude(home, platform = process.platform, env2 = process.env) {
const root = bundledClaudeRoot(home, platform, env2);
if (root === null) return null;
for (const version of versionFolders(root)) {
const found = findExecutable(join20(root, version), platform, BUNDLED_CLAUDE_SEARCH_DEPTH);
if (found !== null) return found;
}
return null;
}
function bundledClaudeRoot(home, platform, env2) {
if (platform === "darwin") {
return join20(home, "Library", "Application Support", "Claude", "claude-code");
}
if (platform === "win32") {
const appData = env2.APPDATA?.trim() ? env2.APPDATA : join20(home, "AppData", "Roaming");
return join20(appData, "Claude", "claude-code");
}
return null;
}
function versionFolders(root) {
let names;
try {
names = readdirSync2(root);
} catch {
return [];
}
return names.filter((name) => /^\d+\.\d+\.\d+$/.test(name) && isDirectory(join20(root, name))).sort((a, b) => a === b ? 0 : versionAtLeast(a, b) ? -1 : 1);
}
function findExecutable(dir, platform, depth) {
const binary = platform === "win32" ? "claude.exe" : "claude";
const direct = platform === "win32" ? join20(dir, binary) : join20(dir, "claude.app", "Contents", "MacOS", binary);
if (isExecutableFile(direct, platform)) return direct;
if (depth <= 0) return null;
let names;
try {
names = readdirSync2(dir).sort();
} catch {
return null;
}
for (const name of names) {
const child = join20(dir, name);
if (name === "claude.app" || !isDirectory(child)) continue;
const found = findExecutable(child, platform, depth - 1);
if (found !== null) return found;
}
return null;
}
function isDirectory(path10) {
try {
return statSync2(path10).isDirectory();
} catch {
return false;
}
}
function isExecutableFile(path10, platform) {
try {
const stat4 = statSync2(path10);
if (!stat4.isFile()) return false;
return platform === "win32" || process.platform === "win32" || (stat4.mode & 73) !== 0;
} catch {
return false;
}
}
function withInstalledAt(home, record2) {
if (record2.installed_at) return { ...record2, installed_at: record2.installed_at };
const seeded = {
...record2,
installed_at: record2.last_attempt_at ?? (/* @__PURE__ */ new Date(0)).toISOString()
};
writeMigrationState(home, seeded);
return seeded;
}
function isPluginSeenFresh(prior, seen) {
if (!seen?.at) return false;
return new Date(seen.at).getTime() >= new Date(prior.installed_at).getTime();
}
function confirmDone(deps, prior) {
const seen = readPluginSeen(deps.home);
return record(deps, prior, {
state: "done",
path: isSyncedRoot(seen?.root) ? "synced" : prior.path
});
}
var DEFAULT_SETTLE_MS = 2e3;
async function recordMigrationSession(input, deps = {}) {
try {
const resolved = resolveDeps(deps);
const initial = readMigrationState(resolved.home);
if (!initial || initial.state !== "installed" && !doneButDisabled(initial, resolved.home)) {
return noTick(initial);
}
if (input.source === "npm") {
const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
await sleep(deps.settleMs ?? DEFAULT_SETTLE_MS);
}
if (!acquireLock2(resolved.home)) return { state: initial.state, reason: "locked" };
try {
return tickInstalled(resolved, input);
} finally {
releaseLock2(resolved.home);
}
} catch (error) {
return { state: "skipped", reason: `error:${error.message}` };
}
}
function noTick(prior) {
return { state: prior?.state ?? "pending", path: prior?.path, reason: "nothing-to-record" };
}
function tickInstalled(deps, input) {
const current = readMigrationState(deps.home);
if (doneButDisabled(current, deps.home)) {
return record(deps, current, { state: "declined", reason: USER_DISABLED_REASON });
}
if (current?.state !== "installed") return noTick(current);
const prior = withInstalledAt(deps.home, current);
if (input.source === "plugin" || isPluginSeenFresh(prior, readPluginSeen(deps.home))) {
return confirmDone(deps, prior);
}
if (!isPluginInstalledRecord(deps.home)) {
const waited = deps.now().getTime() - new Date(prior.installed_at).getTime();
if (waited >= INSTALL_WAIT_MS) {
return autoRollback(deps, prior, NEVER_INSTALLED_REASON);
}
return { state: prior.state, path: prior.path, reason: "waiting-for-plugin-install" };
}
const counted = prior.counted_sessions ?? [];
if (input.sessionId && counted.includes(input.sessionId)) {
return { state: prior.state, path: prior.path, reason: "session-already-counted" };
}
const sessions = (prior.npm_sessions_since_install ?? 0) + 1;
if (sessions >= ROLLBACK_AFTER_NPM_SESSIONS) {
return autoRollback(deps, prior, AUTO_ROLLBACK_REASON, sessions);
}
return record(deps, prior, {
state: "installed",
npm_sessions_since_install: sessions,
counted_sessions: input.sessionId ? [...counted, input.sessionId].slice(-MAX_COUNTED_SESSIONS) : counted
});
}
function autoRollback(deps, prior, reason2, sessions = prior.npm_sessions_since_install ?? 0) {
if (isPluginInstalledRecord(deps.home)) deps.runClaudeUninstall(deps.home);
undoViaSettings(deps.home);
clearPluginSeen(deps.home);
deps.log(
reason2 === NEVER_INSTALLED_REASON ? "rolled back: Claude Code never installed the plugin" : `rolled back after ${sessions} npm sessions with no plugin`
);
return record(deps, prior, {
state: "rolled-back",
reason: reason2,
npm_sessions_since_install: sessions
});
}
var STALE_MIGRATION_LOCK_MS = 15 * 60 * 1e3;
function acquireLock2(home, now = Date.now) {
const dir = migrationLockDir(home);
try {
mkdirSync2(dirname10(dir), { recursive: true });
mkdirSync2(dir);
return true;
} catch {
return reapStaleLock(dir, now);
}
}
function reapStaleLock(dir, now) {
try {
if (now() - statSync2(dir).mtimeMs <= STALE_MIGRATION_LOCK_MS) return false;
const aside = `${dir}.stale-${process.pid}-${now()}`;
renameSync3(dir, aside);
rmSync2(aside, { recursive: true, force: true });
mkdirSync2(dir);
return true;
} catch {
return false;
}
}
function releaseLock2(home) {
try {
rmSync2(migrationLockDir(home), { recursive: true, force: true });
} catch {
}
}
var ROLLBACK_MESSAGE = "paqad now runs from the npm package in Claude Code again. The plugin was removed.";
var ROLLBACK_NO_CLAUDE_MESSAGE = "The plugin is turned off. Run `claude plugin uninstall paqad@eliyce` to remove it.";
var ROLLBACK_NOT_TURNED_OFF_MESSAGE = "paqad could not turn the plugin off. Run `claude plugin uninstall paqad@eliyce` to remove it.";
var ROLLBACK_PROJECT_MESSAGE = "paqad now runs from the npm package in Claude Code again. This repo turns the plugin on for everyone, so I turned it off for you only in .claude/settings.local.json (not committed).";
var ROLLBACK_PROJECT_NOT_TURNED_OFF_MESSAGE = 'This repo turns the plugin on for everyone, and paqad could not turn it off for you. Set "paqad@eliyce": false under enabledPlugins in .claude/settings.local.json.';
function rollbackPlugin(projectRoot, deps = {}) {
const home = deps.home ?? homedir();
const prior = readMigrationState(home);
const listed = installedPluginEntries(join20(home, ".claude")).some(isUserScopeEntry);
const outcome = listed && deps.runClaudeUninstall ? deps.runClaudeUninstall(home) : void 0;
undoViaSettings(home);
const stillInstalled = listed && outcome !== void 0 && outcome !== "ok";
const turnedOff = stillInstalled && disableViaSettings(userClaudeSettingsPath(home));
const projectOn = projectTurnsPluginOn(projectRoot);
const optedOut = projectOn && disableViaSettings(join20(projectRoot, ".claude", "settings.local.json"));
clearPluginSeen(home);
writeMigrationState(home, {
attempts: prior?.attempts ?? 0,
...prior,
state: "rolled-back",
reason: "manual",
version: deps.version ?? VERSION,
last_attempt_at: (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
});
(deps.writeInstallModeSettings ?? ((root) => setConfigValue(root, "claude_install_mode", "settings")))(projectRoot);
if (projectOn) {
return optedOut ? ROLLBACK_PROJECT_MESSAGE : ROLLBACK_PROJECT_NOT_TURNED_OFF_MESSAGE;
}
if (!stillInstalled) return ROLLBACK_MESSAGE;
return turnedOff ? ROLLBACK_NO_CLAUDE_MESSAGE : ROLLBACK_NOT_TURNED_OFF_MESSAGE;
}
function isUserScopeEntry(entry) {
return entry.scope === void 0 || entry.scope === "user";
}
function disableViaSettings(path10) {
let settings = {};
if (existsSync10(path10)) {
try {
const parsed = JSON.parse(readFileSync11(path10, "utf8"));
if (!isRecord2(parsed)) return false;
settings = parsed;
} catch {
return false;
}
}
const enabled = isRecord2(settings.enabledPlugins) ? settings.enabledPlugins : {};
const next = { ...settings, enabledPlugins: { ...enabled, [PLUGIN_ID]: false } };
try {
mkdirSync2(dirname10(path10), { recursive: true });
const tmp = `${path10}.${process.pid}.tmp`;
writeFileSync3(tmp, `${JSON.stringify(next, null, 2)}
`);
renameSync3(tmp, path10);
} catch {
return false;
}
return true;
}
var HOOKS_BLOCKED_DETAIL = "A managed policy blocks paqad's hooks, so paqad's checks don't run here.";
var HOOKS_BLOCKED_FIX = "Ask IT to deploy the paqad plugin as a managed plugin, or allow its hooks.";
var PLUGIN_BLOCKED_DETAIL = "plugin blocked by policy; paqad stays on npm";
var WAITING_FOR_LOAD_DETAIL = "npm (moving to the plugin: waiting for the plugin to load in a new session)";
var VERSION_MISMATCH_FIX = "The plugin and paqad-ai are on different versions. Start a new Claude Code session so the plugin updates, or run `claude plugin update paqad@eliyce`.";
var PROJECT_PLUGIN_DETAIL = "plugin (turned on by this project)";
var PROJECT_PLUGIN_WAITING_DETAIL = "npm (this project turns the plugin on; waiting for Claude Code to install it)";
var LOCAL_OPT_OUT_DETAIL = "npm (plugin turned off for you in .claude/settings.local.json)";
var USER_SWITCH_OVERRIDDEN_FIX = "This repo turns the plugin on, which wins over your user setting. To turn it off for you only, run `paqad-ai plugin rollback`.";
function describeClaudeInstall(home = homedir(), projectRoot, env2 = process.env, options = {}) {
const policy = classifyManagedPolicy(
options.managedSettingsPaths ?? defaultManagedSettingsPaths()
);
if (policy === "hooks-blocked") {
return { detail: HOOKS_BLOCKED_DETAIL, level: "warning", remediation: HOOKS_BLOCKED_FIX };
}
if (policy === "plugin-blocked") return { detail: PLUGIN_BLOCKED_DETAIL, level: "pass" };
if (projectRoot !== void 0 && projectTurnsPluginOn(projectRoot) && !isSyncedRoot(readPluginSeen(home)?.root)) {
return describeProjectPlugin(home, projectRoot, env2, options);
}
const record2 = readMigrationState(home);
if (doneButDisabled(record2, home)) {
return { detail: `npm (migration declined: ${USER_DISABLED_REASON})`, level: "pass" };
}
const suffix = () => projectRoot !== void 0 ? npmHooksSuffix(home, projectRoot, env2) : "";
const installedRecord = isPluginInstalledRecord(home);
if (installedRecord && !userDisabledPlugin(home) && !hasNpmCopy(home, env2, options)) {
return withPluginVersion("plugin", home, env2, options);
}
if (isSyncedRoot(readPluginSeen(home)?.root) || record2?.state === "done" && record2.path === "synced") {
return { detail: `plugin (synced from claude.ai)${suffix()}`, level: "pass" };
}
if (!record2 || record2.state === "pending") return { detail: "npm", level: "pass" };
if (record2.state === "done") {
const date = record2.last_attempt_at ? record2.last_attempt_at.slice(0, 10) : "unknown";
const detail = `plugin (migrated ${date}, via ${record2.path ?? "settings"})${suffix()}`;
return installedRecord ? withPluginVersion(detail, home, env2, options) : { detail, level: "pass" };
}
if (record2.state === "installed") {
if (!installedRecord) {
return {
detail: "npm (migration installed: waiting for Claude Code to install the plugin)",
level: "pass"
};
}
const fresh = isPluginSeenFresh(withSeededInstalledAt(record2), readPluginSeen(home));
return { detail: fresh ? "npm (migration installed)" : WAITING_FOR_LOAD_DETAIL, level: "pass" };
}
const reason2 = record2.reason ? `: ${record2.reason}` : "";
return { detail: `npm (migration ${record2.state}${reason2})`, level: "pass" };
}
function describeProjectPlugin(home, projectRoot, env2, options) {
if (pluginOptedOutLocally(projectRoot)) return { detail: LOCAL_OPT_OUT_DETAIL, level: "pass" };
if (pluginLoadState(projectRoot, { env: env2, home }) !== "live") {
return { detail: PROJECT_PLUGIN_WAITING_DETAIL, level: "pass" };
}
const line = withPluginVersion(PROJECT_PLUGIN_DETAIL, home, env2, options);
if (line.level === "warning" || !userDisabledPlugin(home)) return line;
return { ...line, level: "warning", remediation: USER_SWITCH_OVERRIDDEN_FIX };
}
function withSeededInstalledAt(record2) {
return {
...record2,
installed_at: record2.installed_at ?? record2.last_attempt_at ?? (/* @__PURE__ */ new Date(0)).toISOString()
};
}
function hasNpmCopy(home, env2, options) {
const entry = options.cliEntry ?? process.argv[1] ?? "";
if (entry.includes("node_modules")) return true;
const link = env2.PAQAD_FRAMEWORK_HOME ?? join20(home, ".paqad-ai", "current");
try {
return classifyFrameworkCopy(readlinkSync(link)) === "npm";
} catch {
return false;
}
}
function withPluginVersion(detail, home, env2, options) {
const plugin = readInstalledPluginVersion(home, env2);
if (plugin === null) return { detail, level: "pass" };
const own = options.version ?? VERSION;
const line = `${detail}; plugin v${plugin}, paqad-ai v${own}`;
return plugin === own ? { detail: line, level: "pass" } : { detail: line, level: "warning", remediation: VERSION_MISMATCH_FIX };
}
function readInstalledPluginVersion(home, env2 = process.env) {
const configDir = claudeConfigDir(home, env2);
for (const entry of installedPluginEntries(configDir)) {
const installPath = typeof entry.installPath === "string" ? entry.installPath : null;
const fromRoot = installPath === null ? null : readPackageVersion(installPath);
if (fromRoot !== null) return fromRoot;
if (typeof entry.version === "string" && entry.version !== "") return entry.version;
}
const data = env2.CLAUDE_PLUGIN_DATA?.trim() ? env2.CLAUDE_PLUGIN_DATA : join20(configDir, "plugins", "data", "paqad-eliyce");
return readRuntimeCopyVersion(join20(data, "runtime"));
}
function claudeConfigDir(home, env2) {
const configDir = env2.CLAUDE_CONFIG_DIR?.trim();
return configDir ? configDir : join20(home, ".claude");
}
function installedPluginEntries(configDir) {
let parsed;
try {
parsed = JSON.parse(readFileSync11(join20(configDir, "plugins", "installed_plugins.json"), "utf8"));
} catch {
return [];
}
if (!isRecord2(parsed)) return [];
const value = isRecord2(parsed.plugins) ? parsed.plugins[PLUGIN_ID] : parsed[PLUGIN_ID];
const list = Array.isArray(value) ? value : [value];
return list.filter(isRecord2);
}
var PROJECT_NPM_HOOKS_SUFFIX = "; this project still runs the npm hooks (project .claude/settings.json)";
function hookUserSettingsPath(home, env2) {
return join20(claudeConfigDir(home, env2), "settings.json");
}
function userSettingsLabel(home, env2) {
return env2.CLAUDE_CONFIG_DIR?.trim() ? hookUserSettingsPath(home, env2) : "~/.claude/settings.json";
}
function npmHooksSuffix(home, projectRoot, env2) {
const user = settingsWireLivePaqadHook(hookUserSettingsPath(home, env2));
const project = projectWiresLiveNpmHooks(projectRoot);
if (!user) return project ? PROJECT_NPM_HOOKS_SUFFIX : "";
const files = project ? `${userSettingsLabel(home, env2)} and project .claude/settings.json` : userSettingsLabel(home, env2);
return `; this project still runs the npm hooks (${files})`;
}
function projectWiresLiveNpmHooks(projectRoot) {
return ["settings.json", "settings.local.json"].some(
(name) => settingsWireLivePaqadHook(join20(projectRoot, ".claude", name))
);
}
function settingsWireLivePaqadHook(settingsPath) {
let settings;
try {
settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
} catch {
return false;
}
const hooks = isRecord2(settings) ? settings.hooks : void 0;
if (!isRecord2(hooks)) return false;
return Object.values(hooks).some(
(entries) => Array.isArray(entries) && entries.some(
(entry) => isRecord2(entry) && Array.isArray(entry.hooks) && entry.hooks.some((hook) => {
const script = paqadHookScript(isRecord2(hook) ? hook.command : void 0);
return script !== null && existsSync10(script);
})
)
);
}
function paqadHookScript(command) {
if (typeof command !== "string" || !command.includes("paqad")) return null;
const match = /"([^"]+\.mjs)"|(\S+\.mjs)/.exec(command);
const path10 = match ? match[1] ?? match[2] : void 0;
return path10 !== void 0 && path10.includes("paqad") ? path10 : null;
}
function isRecord2(value) {
return typeof value === "object" && value !== null;
}
function claudeExecFor(bin) {
return (args, options) => defaultClaudeExec(args, options, bin);
}
function runClaudeInstallWith(home, env2, bin) {
return runClaudePluginInstall(
home,
env2,
bin === void 0 ? defaultClaudeExec : claudeExecFor(bin)
);
}
function defaultClaudeExec(args, options, bin = "claude") {
const result2 = spawnSync(bin, [...args], {
env: options.env,
timeout: options.timeoutMs,
stdio: "ignore",
windowsHide: true,
shell: process.platform === "win32" && bin === "claude"
});
if (result2.error) {
return result2.error.code === "ETIMEDOUT" ? "timeout" : "error";
}
return result2.status === 0 ? "ok" : "exit";
}
function runClaudePluginInstall(home, env2, exec2 = defaultClaudeExec, log = (message) => appendMigrationLog(home, message)) {
const added = exec2(["plugin", "marketplace", "add", PLUGIN_MARKETPLACE_REPO], {
timeoutMs: MARKETPLACE_ADD_TIMEOUT_MS,
env: env2
});
if (added !== "ok") {
log(`marketplace add ${PLUGIN_MARKETPLACE_REPO} did not succeed (${added}); continuing`);
}
const installed = exec2(["plugin", "install", PLUGIN_ID, "--scope", "user"], {
timeoutMs: INSTALL_TIMEOUT_MS,
env: env2
});
if (installed !== "ok") return { ok: false, reason: `cli-install-failed:${installed}` };
if (!isPluginInstalledRecord(home)) return { ok: false, reason: "cli-install-unconfirmed" };
return { ok: true };
}
function runClaudePluginUninstall(home, deps = {}) {
const log = deps.log ?? ((message) => appendMigrationLog(home, message));
try {
let exec2 = null;
let via = "cli";
if ((deps.claudeVersion ?? defaultClaudeVersion)() !== null) {
exec2 = deps.exec ?? defaultClaudeExec;
} else {
const bundled = (deps.bundledClaude ?? (() => findBundledClaude(home)))();
if (bundled !== null) {
exec2 = deps.exec ?? claudeExecFor(bundled);
via = "bundled-cli";
}
}
if (exec2 === null) {
log("uninstall skipped: no claude on PATH and no bundled claude");
return "no-claude";
}
const outcome = exec2(["plugin", "uninstall", PLUGIN_ID, "--scope", "user"], {
timeoutMs: UNINSTALL_TIMEOUT_MS,
env: deps.env ?? process.env
});
log(`uninstall via ${via}: ${outcome}`);
return outcome;
} catch (error) {
log(`uninstall via cli: error (${error.message})`);
return "error";
}
}
// src/mcp/server-registry.ts
init_esm_shims();
var MCP_SERVER_CATALOG = {
"laravel-boost": {
name: "laravel-boost",
provides: ["routes", "models", "services", "middleware", "config"],
replaces: ["route-scanning", "model-scanning", "service-scanning"]
},
"dart-mcp": {
name: "dart-mcp",
provides: ["widgets", "dependencies", "assets", "platforms"],
replaces: ["widget-scanning", "pubspec-parsing"]
},
"database-inspector": {
name: "database-inspector",
provides: ["schema", "indexes", "foreign-keys", "query-plans"],
replaces: ["migration-scanning"]
},
figma: {
name: "figma",
provides: ["design-specs", "components", "layouts"],
replaces: ["web-search-design-research"]
},
"vite-inspector": {
name: "vite-inspector",
provides: ["build-graph", "asset-manifest", "hmr-config"],
replaces: ["vite-config-scanning", "asset-manifest-scanning"]
},
"react-router-mcp": {
name: "react-router-mcp",
provides: ["route-tree", "lazy-chunks", "navigation-boundaries"],
replaces: ["manual-route-documentation"]
},
"vue-router-mcp": {
name: "vue-router-mcp",
provides: ["route-tree", "navigation-guards", "layout-routes"],
replaces: ["manual-route-documentation"]
},
"tailwind-mcp": {
name: "tailwind-mcp",
provides: ["design-tokens", "utility-classes", "theme-config"],
replaces: ["css-web-search", "manual-tailwind-scanning"]
}
};
var MCP_SERVERS = [
{ ...MCP_SERVER_CATALOG["laravel-boost"], stacks: ["laravel"], capabilities: ["boost"] },
{ ...MCP_SERVER_CATALOG["dart-mcp"], stacks: ["flutter"], capabilities: [] },
{
...MCP_SERVER_CATALOG["database-inspector"],
stacks: ["laravel", "flutter", "dotnet", "nestjs", "kotlin-android"],
capabilities: []
},
{
...MCP_SERVER_CATALOG.figma,
stacks: [
"laravel",
"flutter",
"react",
"vue",
"nextjs",
"dotnet",
"flask",
"nestjs",
"kotlin-android"
],
capabilities: []
},
{ ...MCP_SERVER_CATALOG["vite-inspector"], stacks: ["react", "vue"], capabilities: [] },
{ ...MCP_SERVER_CATALOG["react-router-mcp"], stacks: ["react"], capabilities: [] },
{ ...MCP_SERVER_CATALOG["vue-router-mcp"], stacks: ["vue"], capabilities: [] },
{
...MCP_SERVER_CATALOG["tailwind-mcp"],
stacks: ["laravel", "react", "vue"],
capabilities: ["tailwind"]
}
];
function getServersForStack(stack, capabilities) {
const frameworks = stack === "short-video" ? [] : [stack];
return resolveMcpDefaults(frameworks, capabilities);
}
var McpServerRegistry = class {
list() {
return [...MCP_SERVERS];
}
forProfile(profile) {
const stack = getPrimaryStack(profile);
if (stack === "short-video") {
return [];
}
const capabilities = getLegacyCapabilities(profile);
const frameworks = profile.stack_profile?.frameworks ?? [stack];
const enabledNames = profile.mcp.servers.filter((server) => server.enabled).map((server) => server.name);
const disabledNames = new Set(
profile.mcp.servers.filter((server) => !server.enabled).map((server) => server.name)
);
const byName = new Map(
resolveMcpDefaults(frameworks, capabilities).map((server) => [server.name, server])
);
for (const name of enabledNames) {
const explicitServer = buildExplicitServerDefinition(name, frameworks, capabilities);
if (!explicitServer) {
continue;
}
byName.set(explicitServer.name, explicitServer);
}
return Array.from(byName.values()).filter((server) => !disabledNames.has(server.name));
}
};
function resolveMcpDefaults(frameworks, capabilities) {
const byName = /* @__PURE__ */ new Map();
for (const framework of frameworks) {
if (framework === "laravel" || framework === "flutter") {
addServer(byName, "database-inspector", framework, []);
}
addServer(byName, "figma", framework, []);
}
for (const pack of getPacksForFrameworks(frameworks)) {
for (const item of pack.manifest.mcp_defaults ?? []) {
if (item.when === "when_trait" && (!item.trait || !capabilities.includes(item.trait))) {
continue;
}
addServer(
byName,
item.name,
pack.manifest.name,
item.when === "when_trait" && item.trait ? [item.trait] : []
);
}
}
return Array.from(byName.values());
}
function addServer(byName, name, stack, capabilities) {
const metadata = MCP_SERVER_CATALOG[name];
if (!metadata) {
return;
}
const existing = byName.get(name);
if (existing) {
existing.stacks = Array.from(/* @__PURE__ */ new Set([...existing.stacks, stack]));
existing.capabilities = Array.from(/* @__PURE__ */ new Set([...existing.capabilities, ...capabilities]));
return;
}
byName.set(name, {
...metadata,
stacks: [stack],
capabilities
});
}
function buildExplicitServerDefinition(name, frameworks, capabilities) {
if (!(name in MCP_SERVER_CATALOG)) {
return null;
}
const typedName = name;
const defaults = resolveMcpDefaults(frameworks, capabilities);
const existing = defaults.find((server) => server.name === typedName);
if (existing) {
return existing;
}
const metadata = MCP_SERVER_CATALOG[typedName];
return {
...metadata,
stacks: frameworks,
capabilities: []
};
}
// src/skills/cache-manager.ts
init_esm_shims();
var import_fast_glob4 = __toESM(require_out(), 1);
import { createHash as createHash5 } from "crypto";
import { mkdir as mkdir14, readFile as readFile13, readdir as readdir2, rm, stat, writeFile as writeFile14 } from "fs/promises";
import { dirname as dirname11, join as join21 } from "path";
var STATS_FILE = ".stats.json";
var SkillCacheManager = class {
constructor(cacheDir) {
this.cacheDir = cacheDir;
}
cacheDir;
parser = new SkillFrontmatterParser();
cacheability = /* @__PURE__ */ new Map();
cacheabilityLoaded = false;
async checkCache(skillName, inputFiles) {
await mkdir14(this.cacheDir, { recursive: true });
const inputHash = await this.computeInputHash(inputFiles);
if (!await this.isCacheable(skillName)) {
await this.updateMetrics("misses");
return { hit: false, input_hash: inputHash };
}
const cachePath = join21(this.cacheDir, `${skillName}-${inputHash}.json`);
try {
const cached2 = JSON.parse(await readFile13(cachePath, "utf8"));
await this.updateMetrics("hits");
return { hit: true, result: cached2.result, input_hash: inputHash };
} catch {
await this.updateMetrics("misses");
return { hit: false, input_hash: inputHash };
}
}
async writeCache(skillName, inputHash, result2, filesHashed) {
if (!await this.isCacheable(skillName)) {
return;
}
await mkdir14(this.cacheDir, { recursive: true });
const entry = {
skill_name: skillName,
input_hash: inputHash,
result: result2,
created_at: (/* @__PURE__ */ new Date()).toISOString(),
files_hashed: [...filesHashed].sort()
};
await writeFile14(
join21(this.cacheDir, `${skillName}-${inputHash}.json`),
JSON.stringify(entry, null, 2)
);
}
async invalidateModule(moduleName) {
await mkdir14(this.cacheDir, { recursive: true });
const files = await readdir2(this.cacheDir);
let removed = 0;
for (const file of files) {
if (file === STATS_FILE || !file.endsWith(".json")) {
continue;
}
const path10 = join21(this.cacheDir, file);
const entry = JSON.parse(await readFile13(path10, "utf8"));
if (entry.files_hashed.some((hashedFile) => hashedFile.includes(moduleName))) {
await rm(path10);
removed += 1;
}
}
return removed;
}
async getStats() {
await mkdir14(this.cacheDir, { recursive: true });
const files = await readdir2(this.cacheDir);
let totalEntries = 0;
let totalSize = 0;
for (const file of files) {
if (file === STATS_FILE || !file.endsWith(".json")) {
continue;
}
const fileStat = await stat(join21(this.cacheDir, file));
totalEntries += 1;
totalSize += fileStat.size;
}
const metrics = await this.readMetrics();
const totalChecks = metrics.hits + metrics.misses;
return {
total_entries: totalEntries,
total_size_bytes: totalSize,
hit_rate: totalChecks === 0 ? 0 : metrics.hits / totalChecks
};
}
async computeInputHash(files) {
const hash = createHash5("sha256");
for (const file of [...files].sort()) {
hash.update(file);
hash.update("\0");
hash.update(await readFile13(file));
hash.update("\0");
}
return hash.digest("hex");
}
async isCacheable(skillName) {
if (!this.cacheabilityLoaded) {
await this.loadCacheability();
}
return this.cacheability.get(skillName) ?? true;
}
async updateMetrics(kind) {
const metrics = await this.readMetrics();
metrics[kind] += 1;
await writeFile14(join21(this.cacheDir, STATS_FILE), JSON.stringify(metrics, null, 2));
}
async readMetrics() {
try {
return JSON.parse(await readFile13(join21(this.cacheDir, STATS_FILE), "utf8"));
} catch {
return { hits: 0, misses: 0 };
}
}
async loadCacheability() {
const files = await (0, import_fast_glob4.default)(
[
"base/skills/**/SKILL.md",
"capabilities/coding/skills/**/SKILL.md",
"capabilities/security/skills/**/SKILL.md"
],
{
cwd: getRuntimeRoot(),
absolute: true,
onlyFiles: true
}
);
for (const file of files) {
const parsed = this.parser.parse(await readFile13(file, "utf8"), dirname11(file));
this.cacheability.set(parsed.frontmatter.name, parsed.frontmatter.cacheable);
}
this.cacheabilityLoaded = true;
}
};
// src/test-output/index.ts
init_esm_shims();
// src/test-output/service.ts
init_esm_shims();
var import_fast_glob5 = __toESM(require_out(), 1);
import { readFile as readFile14 } from "fs/promises";
// src/token-efficiency/index.ts
init_esm_shims();
// src/token-efficiency/service.ts
init_esm_shims();
import { readFileSync as readFileSync12 } from "fs";
var DEFAULT_EXCERPTS = 3;
var DEFAULT_MIN_CHUNK_THRESHOLD = 3;
var DETERMINISTIC_TASK_TYPES = ["lint", "format", "typecheck", "build", "test-run", "ci"];
var DEFAULT_ACTIONS = {
"test-output": ["Fix failing tests and re-run the targeted suite."],
"coverage-output": ["Increase tests for files below the target threshold."],
"json-report": ["Inspect highest-severity report entries first."],
"xml-report": ["Inspect failure and error nodes first."],
"log-output": ["Investigate recurring ERROR/FATAL signatures first."],
"grep-results": ["Narrow search scope to reduce broad match noise."],
"route-dump": ["Review unexpected route additions and auth exposure."],
"inventory-scan-output": ["Patch critical/high findings before broader cleanup."]
};
function buildCompactArtifact(input) {
const normalizedRaw = normalizeLineEndings(input.raw_content);
const raw = normalizedRaw.trim();
const originalSize = Buffer.byteLength(normalizedRaw, "utf8");
const artifactSummary = summarizeByClass(
input.artifact_class,
raw,
input.max_excerpts ?? DEFAULT_EXCERPTS
);
const minimized = minimizeCompactRepresentation(
artifactSummary,
input.artifact_class,
originalSize,
input.max_excerpts ?? DEFAULT_EXCERPTS
);
const compactJson = JSON.stringify({
summary: minimized.summary,
excerpts: minimized.excerpts,
confidence: minimized.confidence
});
const compactSize = Buffer.byteLength(compactJson, "utf8");
const metadata = {
original_size: originalSize,
compact_size: compactSize,
reduction_ratio: calculateReductionRatio(originalSize, compactSize),
delta_mode_used: false,
escalation_occurred: false
};
return {
artifact_class: input.artifact_class,
summary: minimized.summary,
targeted_excerpts: minimized.excerpts,
confidence: minimized.confidence,
raw_artifact_path: input.raw_artifact_path ?? null,
metadata
};
}
function evaluateEscalation(input) {
const confidenceThreshold = input.confidence_threshold ?? 0.6;
const reason2 = resolveEscalationReason(input, confidenceThreshold);
if (reason2 === null) {
return {
should_escalate: false,
reason: null,
raw_slice: null,
metadata: {
...input.compact.metadata,
escalation_occurred: false
}
};
}
const rawSlice = extractRawSlice(
input.compact,
input.max_raw_slice_chars ?? 1200,
input.slice_hint ?? input.compact.summary.top_failures_or_errors[0] ?? ""
);
return {
should_escalate: true,
reason: reason2,
raw_slice: rawSlice,
metadata: {
...input.compact.metadata,
escalation_occurred: true
}
};
}
function buildReasoningInputPayload(compact, escalation) {
return {
compact_summary: compact.summary,
targeted_excerpts: compact.targeted_excerpts,
raw_slice: escalation.should_escalate ? escalation.raw_slice : null,
escalation_reason: escalation.reason,
metadata: escalation.metadata
};
}
function applyDisclosurePolicy(input) {
const level = resolveDisclosureLevel(input);
const payload = buildDisclosurePayload(level, input.compact, input.escalation);
const escalationReason = input.escalation_reason ?? null;
const skippedIntermediate = input.requested_level === "raw" && input.escalation?.raw_slice == null && !input.escalation_reason;
const audit = {
selected_level: level,
escalation_occurred: escalationReason !== null,
escalation_reason: escalationReason,
skipped_intermediate: skippedIntermediate
};
return {
level,
payload,
escalation_reason: escalationReason,
skipped_intermediate: skippedIntermediate,
audit
};
}
function evaluateRetrievalGate(input) {
const result2 = resolveRetrievalPath(
input.task_complexity,
input.ambiguity_detected ?? false,
input.chunk_count ?? 0,
input.min_chunk_threshold ?? DEFAULT_MIN_CHUNK_THRESHOLD,
input.conflicting_evidence ?? false
);
const audit = {
retrieval_depth: result2.path,
rag_skipped: result2.rag_skipped,
escalation_signal: result2.escalation_signal
};
return {
preferred_path: result2.path,
rag_skipped: result2.rag_skipped,
escalation_signal: result2.escalation_signal,
audit
};
}
function runRoutingDecision(input) {
const resolved = resolveRoutingMechanism(input.task_type, input.metadata);
const audit = {
routing_mechanism: resolved.mechanism,
resolved_before_reasoning: resolved.resolved
};
return {
needs_reasoning: !resolved.resolved,
mechanism_used: resolved.mechanism,
resolved_task_type: resolved.resolved_task_type,
audit
};
}
function buildControlLayerAudit(disclosure, retrieval, routing) {
return {
disclosure,
retrieval,
routing
};
}
function createTestDelta(baseline, current, options = {}) {
const baselineMap = new Map(baseline.map((item) => [item.test_id, item]));
const currentMap = new Map(current.map((item) => [item.test_id, item]));
const newlyFailing = [];
const newlyPassing = [];
const newlyErrored = [];
const changedMessages = [];
for (const [testId, now] of currentMap) {
const before = baselineMap.get(testId);
if (before === void 0) {
if (now.status === "failed") newlyFailing.push(testId);
if (now.status === "errored") newlyErrored.push(testId);
continue;
}
if (before.status !== "failed" && now.status === "failed") {
newlyFailing.push(testId);
}
if (before.status !== "passed" && now.status === "passed") {
newlyPassing.push(testId);
}
if (before.status !== "errored" && now.status === "errored") {
newlyErrored.push(testId);
}
const beforeMessage = normalizedIssueMessage(before);
const afterMessage = normalizedIssueMessage(now);
if (before.status === "failed" && now.status === "failed" && beforeMessage !== afterMessage) {
changedMessages.push({ test_id: testId, before: beforeMessage, after: afterMessage });
}
}
if (options.treat_missing_as_passing === true) {
for (const [testId, before] of baselineMap) {
if (currentMap.has(testId)) continue;
if (before.status !== "passed") {
newlyPassing.push(testId);
}
}
}
const delta = {
newly_failing_tests: sortUnique(newlyFailing),
newly_passing_tests: sortUnique(newlyPassing),
newly_errored_tests: sortUnique(newlyErrored),
changed_failure_messages: changedMessages.sort((a, b) => a.test_id.localeCompare(b.test_id))
};
return {
delta,
metadata: createDeltaMetadata(current, delta)
};
}
function createVerificationDelta(baseline, current) {
const baselineMap = new Map(baseline.map((item) => [item.gate, item]));
const currentMap = new Map(current.map((item) => [item.gate, item]));
const changedGateOutcomes = [];
const changedEvidence = [];
const changedActions = [];
for (const [gate, now] of currentMap) {
const before = baselineMap.get(gate);
if (before === void 0) {
changedGateOutcomes.push({ gate, before_passed: !now.passed, after_passed: now.passed });
changedEvidence.push({ gate, before_detail: "", after_detail: now.detail });
if ((now.remediation ?? "").trim().length > 0) {
changedActions.push({ gate, before: "", after: now.remediation.trim() });
}
continue;
}
if (before.passed !== now.passed) {
changedGateOutcomes.push({ gate, before_passed: before.passed, after_passed: now.passed });
}
if (before.detail !== now.detail) {
changedEvidence.push({ gate, before_detail: before.detail, after_detail: now.detail });
}
const beforeRemediation = (before.remediation ?? "").trim();
const afterRemediation = (now.remediation ?? "").trim();
if (beforeRemediation !== afterRemediation) {
changedActions.push({ gate, before: beforeRemediation, after: afterRemediation });
}
}
const delta = {
changed_gate_outcomes: changedGateOutcomes.sort((a, b) => a.gate.localeCompare(b.gate)),
changed_evidence: changedEvidence.sort((a, b) => a.gate.localeCompare(b.gate)),
changed_recommended_actions: changedActions.sort((a, b) => a.gate.localeCompare(b.gate))
};
return {
delta,
metadata: createDeltaMetadata(current, delta)
};
}
function createDriftDelta(baseline, current) {
const baselineMap = new Map(baseline.map((item) => [item.file, item]));
const currentMap = new Map(current.map((item) => [item.file, item]));
const changedFiles = /* @__PURE__ */ new Set();
const changedStatuses = [];
const changedConclusions = [];
for (const [file, now] of currentMap) {
const before = baselineMap.get(file);
if (before === void 0) {
changedFiles.add(file);
changedStatuses.push({ file, before: "", after: now.status });
changedConclusions.push({ file, before: "", after: now.conclusion });
continue;
}
if (before.status !== now.status) {
changedFiles.add(file);
changedStatuses.push({ file, before: before.status, after: now.status });
}
if (before.conclusion !== now.conclusion) {
changedFiles.add(file);
changedConclusions.push({ file, before: before.conclusion, after: now.conclusion });
}
}
for (const [file, before] of baselineMap) {
if (!currentMap.has(file)) {
changedFiles.add(file);
changedStatuses.push({ file, before: before.status, after: "" });
changedConclusions.push({ file, before: before.conclusion, after: "" });
}
}
const delta = {
changed_files: [...changedFiles].sort((a, b) => a.localeCompare(b)),
changed_statuses: changedStatuses.sort((a, b) => a.file.localeCompare(b.file)),
changed_conclusions: changedConclusions.sort((a, b) => a.file.localeCompare(b.file))
};
return {
delta,
metadata: createDeltaMetadata(current, delta)
};
}
function buildTestDeltaReasoningPayload(baseline, current, options = {}, escalationInput = {}) {
const result2 = createTestDelta(baseline, current, options);
return buildDeltaReasoningPayload(result2.delta, result2.metadata, escalationInput);
}
function buildVerificationDeltaReasoningPayload(baseline, current, escalationInput = {}) {
const result2 = createVerificationDelta(baseline, current);
return buildDeltaReasoningPayload(result2.delta, result2.metadata, escalationInput);
}
function buildDriftDeltaReasoningPayload(baseline, current, escalationInput = {}) {
const result2 = createDriftDelta(baseline, current);
return buildDeltaReasoningPayload(result2.delta, result2.metadata, escalationInput);
}
function resolveEscalationReason(input, confidenceThreshold) {
if (input.reason) return input.reason;
if (input.unresolved_after_compact === true) return "diagnosis-unresolved-after-compact-pass";
if (input.contradiction_detected === true) return "compact-signals-contradict";
if (input.compact.confidence < confidenceThreshold) return "summary-confidence-low";
return null;
}
function extractRawSlice(compact, maxChars, hint) {
const normalizedHint = hint.trim().toLowerCase();
const excerpt = compact.targeted_excerpts.find(
(line) => line.toLowerCase().includes(normalizedHint)
);
if (excerpt) return excerpt.slice(0, maxChars);
if (compact.raw_artifact_path === null) {
return compact.targeted_excerpts[0]?.slice(0, maxChars) ?? null;
}
try {
const raw = normalizeLineEndings(readFileSync12(compact.raw_artifact_path, "utf8"));
const lines = raw.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
if (lines.length === 0) return null;
if (normalizedHint.length > 0) {
const hit = lines.findIndex((line) => line.toLowerCase().includes(normalizedHint));
if (hit >= 0) {
const start = Math.max(hit - 1, 0);
const end = Math.min(hit + 2, lines.length);
return lines.slice(start, end).join("\n").slice(0, maxChars);
}
}
return lines[0].slice(0, maxChars);
} catch {
return compact.targeted_excerpts[0]?.slice(0, maxChars) ?? null;
}
}
function summarizeByClass(artifactClass, raw, maxExcerpts) {
switch (artifactClass) {
case "test-output":
return summarizeTestOutput(raw, maxExcerpts);
case "coverage-output":
return summarizeCoverageOutput(raw, maxExcerpts);
case "json-report":
return summarizeJsonReport(raw, maxExcerpts);
case "xml-report":
return summarizeXmlReport(raw, maxExcerpts);
case "log-output":
return summarizeLogOutput(raw, maxExcerpts);
case "grep-results":
return summarizeGrepResults(raw, maxExcerpts);
case "route-dump":
return summarizeRouteDump(raw, maxExcerpts);
case "inventory-scan-output":
return summarizeInventoryScan(raw, maxExcerpts);
}
}
function summarizeTestOutput(raw, maxExcerpts) {
const lines = tokenizeLines(raw);
const failures = lines.filter((line) => /(^|\s)(fail|failed|not ok|error)\b/i.test(line));
const passed = lines.filter((line) => /(^|\s)(pass|passed|ok)\b/i.test(line));
const files = extractFileLikeSegments(lines);
return {
summary: {
summary_counts: {
lines: lines.length,
failing_signals: failures.length,
passing_signals: passed.length
},
top_failures_or_errors: failures.slice(0, 5),
affected_files: files,
severity_or_status: failures.length > 0 ? "failing" : "passing",
next_recommended_actions: DEFAULT_ACTIONS["test-output"]
},
excerpts: failures.slice(0, maxExcerpts),
confidence: lines.length > 0 ? 0.9 : 0.4
};
}
function summarizeCoverageOutput(raw, maxExcerpts) {
const lines = tokenizeLines(raw);
const percentages = lines.map((line) => /([0-9]{1,3}(?:\.[0-9]+)?)%/.exec(line)?.[1]).filter((value) => value !== void 0).map((value) => Number(value));
const below80 = lines.filter((line) => {
const hit = /([0-9]{1,3}(?:\.[0-9]+)?)%/.exec(line);
return hit ? Number(hit[1]) < 80 : false;
});
return {
summary: {
summary_counts: {
lines: lines.length,
percentage_markers: percentages.length,
below_target_entries: below80.length
},
top_failures_or_errors: below80.slice(0, 5),
affected_files: extractFileLikeSegments(below80),
severity_or_status: below80.length > 0 ? "below-target" : "meets-target",
next_recommended_actions: DEFAULT_ACTIONS["coverage-output"]
},
excerpts: below80.slice(0, maxExcerpts),
confidence: percentages.length > 0 ? 0.88 : 0.55
};
}
function summarizeJsonReport(raw, maxExcerpts) {
try {
const parsed = JSON.parse(raw);
const flattened = flattenJson(parsed);
const errorLike = flattened.filter((line) => /(error|fail|critical|high|warn)/i.test(line));
const files = extractFileLikeSegments(flattened);
return {
summary: {
summary_counts: {
flattened_fields: flattened.length,
error_like_entries: errorLike.length
},
top_failures_or_errors: errorLike.slice(0, 5),
affected_files: files,
severity_or_status: errorLike.length > 0 ? "attention-needed" : "clean",
next_recommended_actions: DEFAULT_ACTIONS["json-report"]
},
excerpts: errorLike.slice(0, maxExcerpts),
confidence: 0.95
};
} catch {
return degradedSummary("json-report", raw, maxExcerpts, 0.35);
}
}
function summarizeXmlReport(raw, maxExcerpts) {
const nodes = raw.match(/<([a-zA-Z0-9:_-]+)\b[^>]*>/g) ?? [];
const failures = raw.match(/<(failure|error)\b[^>]*>([\s\S]*?)<\/\1>/gi) ?? [];
const files = extractFileLikeSegments(tokenizeLines(raw));
return {
summary: {
summary_counts: {
tags: nodes.length,
failure_or_error_nodes: failures.length
},
top_failures_or_errors: failures.map((value) => collapseWhitespace(value)).slice(0, 5),
affected_files: files,
severity_or_status: failures.length > 0 ? "failing" : "passing",
next_recommended_actions: DEFAULT_ACTIONS["xml-report"]
},
excerpts: failures.map((value) => collapseWhitespace(value)).slice(0, maxExcerpts),
confidence: nodes.length > 0 ? 0.85 : 0.5
};
}
function summarizeLogOutput(raw, maxExcerpts) {
const lines = tokenizeLines(raw);
const errors = lines.filter((line) => /(error|fatal|panic|exception)/i.test(line));
const warnings = lines.filter((line) => /\bwarn(?:ing)?\b/i.test(line));
return {
summary: {
summary_counts: {
lines: lines.length,
errors: errors.length,
warnings: warnings.length
},
top_failures_or_errors: errors.slice(0, 5),
affected_files: extractFileLikeSegments(errors.length > 0 ? errors : warnings),
severity_or_status: errors.length > 0 ? "error" : warnings.length > 0 ? "warning" : "ok",
next_recommended_actions: DEFAULT_ACTIONS["log-output"]
},
excerpts: (errors.length > 0 ? errors : warnings).slice(0, maxExcerpts),
confidence: lines.length > 0 ? 0.8 : 0.45
};
}
function summarizeGrepResults(raw, maxExcerpts) {
const lines = tokenizeLines(raw);
const matches = lines.filter((line) => /:\d+[:-]/.test(line) || line.includes(":"));
const files = extractFileLikeSegments(lines);
return {
summary: {
summary_counts: {
lines: lines.length,
matches: matches.length,
files: files.length
},
top_failures_or_errors: matches.slice(0, 5),
affected_files: files,
severity_or_status: matches.length > 0 ? "matches-found" : "no-matches",
next_recommended_actions: DEFAULT_ACTIONS["grep-results"]
},
excerpts: matches.slice(0, maxExcerpts),
confidence: lines.length > 0 ? 0.9 : 0.6
};
}
function summarizeRouteDump(raw, maxExcerpts) {
const lines = tokenizeLines(raw);
const routeLines = lines.filter(
(line) => /\b(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b/.test(line)
);
const authSensitive = routeLines.filter((line) => /(admin|auth|login|token|session)/i.test(line));
return {
summary: {
summary_counts: {
lines: lines.length,
routes: routeLines.length,
auth_sensitive_routes: authSensitive.length
},
top_failures_or_errors: authSensitive.slice(0, 5),
affected_files: extractFileLikeSegments(routeLines),
severity_or_status: authSensitive.length > 0 ? "review-required" : "normal",
next_recommended_actions: DEFAULT_ACTIONS["route-dump"]
},
excerpts: (authSensitive.length > 0 ? authSensitive : routeLines).slice(0, maxExcerpts),
confidence: routeLines.length > 0 ? 0.9 : 0.5
};
}
function summarizeInventoryScan(raw, maxExcerpts) {
const lines = tokenizeLines(raw);
const critical = lines.filter((line) => /\bcritical\b/i.test(line));
const high = lines.filter((line) => /\bhigh\b/i.test(line));
const medium = lines.filter((line) => /\bmedium\b/i.test(line));
const low = lines.filter((line) => /\blow\b/i.test(line));
const issues = [...critical, ...high, ...medium, ...low];
const severity = critical.length > 0 ? "critical" : high.length > 0 ? "high" : medium.length > 0 ? "medium" : low.length > 0 ? "low" : "none";
return {
summary: {
summary_counts: {
lines: lines.length,
critical: critical.length,
high: high.length,
medium: medium.length,
low: low.length
},
top_failures_or_errors: issues.slice(0, 5),
affected_files: extractFileLikeSegments(issues),
severity_or_status: severity,
next_recommended_actions: DEFAULT_ACTIONS["inventory-scan-output"]
},
excerpts: issues.slice(0, maxExcerpts),
confidence: lines.length > 0 ? 0.85 : 0.5
};
}
function degradedSummary(artifactClass, raw, maxExcerpts, confidence) {
const lines = tokenizeLines(raw);
return {
summary: {
summary_counts: { lines: lines.length },
top_failures_or_errors: lines.slice(0, 5),
affected_files: extractFileLikeSegments(lines),
severity_or_status: lines.length > 0 ? "unknown" : "empty",
next_recommended_actions: DEFAULT_ACTIONS[artifactClass]
},
excerpts: lines.slice(0, maxExcerpts),
confidence
};
}
function minimizeCompactRepresentation(summaryResult, artifactClass, originalSize, maxExcerpts) {
if (originalSize <= 0) {
return summaryResult;
}
const fullSize = measureCompactRepresentation(
summaryResult.summary,
summaryResult.excerpts,
summaryResult.confidence
);
if (fullSize < originalSize) {
return summaryResult;
}
const shrunkSummary = {
summary_counts: summaryResult.summary.summary_counts,
top_failures_or_errors: summaryResult.summary.top_failures_or_errors.slice(0, 1),
affected_files: summaryResult.summary.affected_files.slice(0, 3),
severity_or_status: summaryResult.summary.severity_or_status,
next_recommended_actions: summaryResult.summary.next_recommended_actions.slice(0, 1)
};
const shrunkExcerpts = summaryResult.excerpts.slice(0, 1).map((line) => line.slice(0, 240));
const shrunkSize = measureCompactRepresentation(
shrunkSummary,
shrunkExcerpts,
summaryResult.confidence
);
if (shrunkSize < originalSize) {
return {
summary: shrunkSummary,
excerpts: shrunkExcerpts,
confidence: summaryResult.confidence
};
}
if (originalSize < 256) {
return summaryResult;
}
const fallback = degradedSummary(
artifactClass,
"",
Math.min(maxExcerpts, 1),
summaryResult.confidence
);
return fallback;
}
function measureCompactRepresentation(summary, excerpts, confidence) {
return Buffer.byteLength(
JSON.stringify({
summary,
excerpts,
confidence
}),
"utf8"
);
}
function createDeltaMetadata(fullState, delta) {
const fullStateRaw = JSON.stringify(fullState) ?? "";
const deltaRaw = JSON.stringify(delta) ?? "";
const originalSize = Buffer.byteLength(fullStateRaw, "utf8");
const compactSize = Buffer.byteLength(deltaRaw, "utf8");
return {
original_size: originalSize,
compact_size: compactSize,
reduction_ratio: calculateReductionRatio(originalSize, compactSize),
delta_mode_used: true,
escalation_occurred: false
};
}
function buildDeltaReasoningPayload(delta, deltaMetadata, escalationInput) {
const compact = buildCompactArtifact({
artifact_class: "json-report",
raw_content: JSON.stringify(delta)
});
const escalation = evaluateEscalation({
...escalationInput,
compact: {
...compact,
metadata: {
...deltaMetadata,
escalation_occurred: false
}
}
});
return {
delta,
payload: buildReasoningInputPayload(compact, escalation)
};
}
function resolveDisclosureLevel(input) {
const requestedLevel = input.requested_level ?? "summary";
if (input.escalation_reason === "high-risk-or-cross-cutting") {
return "excerpt";
}
if (input.escalation_reason) {
if (requestedLevel === "summary") {
return "compact";
}
return requestedLevel;
}
if (requestedLevel === "raw" && input.escalation?.raw_slice == null) {
return "excerpt";
}
return DISCLOSURE_LEVELS.includes(requestedLevel) ? requestedLevel : "summary";
}
function buildDisclosurePayload(level, compact, escalation) {
switch (level) {
case "summary":
return `${compact.summary.severity_or_status}: ${compact.summary.top_failures_or_errors[0] ?? "none"}`;
case "compact":
return JSON.stringify(compact.summary);
case "excerpt":
return compact.targeted_excerpts.join("\n");
case "raw":
return escalation?.raw_slice ?? compact.targeted_excerpts.join("\n");
}
}
function resolveRetrievalPath(taskComplexity, ambiguityDetected, chunkCount, threshold, conflictingEvidence) {
let path10;
let ragSkipped;
let escalationSignal = null;
if (taskComplexity === "cross-cutting") {
path10 = "rag-deep";
ragSkipped = false;
} else if (taskComplexity === "single-module") {
if (ambiguityDetected) {
path10 = "rag-shallow";
ragSkipped = false;
escalationSignal = "unresolved-target-file-ambiguity";
} else if (chunkCount < threshold) {
path10 = "rag-shallow";
ragSkipped = false;
escalationSignal = "insufficient-chunks";
} else {
path10 = "lexical";
ragSkipped = true;
}
} else if (taskComplexity === "trivial" || taskComplexity === "single-file") {
if (ambiguityDetected) {
path10 = "lexical";
ragSkipped = false;
escalationSignal = "unresolved-target-file-ambiguity";
} else {
path10 = "direct";
ragSkipped = true;
}
} else {
path10 = "rag-deep";
ragSkipped = false;
}
if (conflictingEvidence) {
escalationSignal = "conflicting-evidence";
}
return {
path: path10,
rag_skipped: ragSkipped,
escalation_signal: escalationSignal
};
}
function resolveRoutingMechanism(taskType, metadata) {
if (DETERMINISTIC_TASK_TYPES.some(
(candidate) => taskType === candidate || taskType.startsWith(`${candidate}:`)
)) {
return {
mechanism: ROUTING_MECHANISMS[0],
resolved: true,
resolved_task_type: taskType
};
}
const workflowId = metadata?.workflow_id;
if (typeof workflowId === "string" && workflowId.trim().length > 0) {
return {
mechanism: ROUTING_MECHANISMS[1],
resolved: true,
resolved_task_type: workflowId
};
}
return {
mechanism: ROUTING_MECHANISMS[3],
resolved: false,
resolved_task_type: null
};
}
function calculateReductionRatio(originalSize, compactSize) {
if (originalSize <= 0) return 0;
return Math.max(0, Math.min(1, 1 - compactSize / originalSize));
}
function extractFileLikeSegments(lines) {
const matches = [];
for (const line of lines) {
for (const run2 of line.match(PATH_CHAR_RUN) ?? []) {
matches.push(...findPathSegmentsInRun(run2));
}
}
return sortUnique(matches).slice(0, 10);
}
var PATH_CHAR_RUN = /[\w@./-]+/g;
function isPathTailChar(char) {
return char !== void 0 && char !== "/" && char !== "@";
}
function nextSegmentEnd(run2, from) {
let nameStart = from;
if (run2[from] === "/") {
nameStart = from + 1;
if (nameStart >= run2.length || run2[nameStart] === "/") return -1;
}
const slash = run2.indexOf("/", nameStart);
return slash === -1 ? -1 : slash + 1;
}
function findPathSegmentsInRun(run2) {
const hits = [];
let start = 0;
while (start < run2.length) {
let tailStart = -1;
let position = start;
for (let next = nextSegmentEnd(run2, position); next !== -1; next = nextSegmentEnd(run2, position)) {
position = next;
if (isPathTailChar(run2[position])) tailStart = position;
}
if (tailStart === -1) {
if (position !== start) start = position + 1;
else if (run2[start] === "/") start += 1;
else break;
continue;
}
let end = tailStart;
while (isPathTailChar(run2[end])) end += 1;
hits.push(run2.slice(start, end));
start = end;
}
return hits;
}
function flattenJson(value, prefix = "") {
if (value === null || typeof value !== "object") {
return [`${prefix}${String(value)}`];
}
if (Array.isArray(value)) {
return value.flatMap((entry, index) => flattenJson(entry, `${prefix}[${index}].`));
}
return Object.entries(value).flatMap(
([key, nested]) => flattenJson(nested, `${prefix}${key}.`)
);
}
function normalizedIssueMessage(item) {
return collapseWhitespace(item.message.trim());
}
function tokenizeLines(raw) {
return raw.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
}
function normalizeLineEndings(raw) {
return raw.replace(/\r/g, "");
}
function collapseWhitespace(input) {
return input.replace(/\s+/g, " ").trim();
}
function sortUnique(values) {
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
}
var __tokenEfficiencyInternals = {
summarizeByClass,
summarizeTestOutput,
summarizeCoverageOutput,
summarizeJsonReport,
summarizeXmlReport,
summarizeLogOutput,
summarizeGrepResults,
summarizeRouteDump,
summarizeInventoryScan,
degradedSummary,
minimizeCompactRepresentation,
measureCompactRepresentation,
resolveEscalationReason,
extractRawSlice,
createDeltaMetadata,
buildDeltaReasoningPayload,
resolveDisclosureLevel,
buildDisclosurePayload,
resolveRetrievalPath,
resolveRoutingMechanism,
extractFileLikeSegments,
flattenJson,
normalizedIssueMessage,
tokenizeLines,
normalizeLineEndings,
collapseWhitespace,
sortUnique,
calculateReductionRatio
};
// src/test-output/service.ts
async function parseTestOutput(options) {
const rawSources = await collectRawSources(options);
const parseWarnings = [];
if (rawSources.length === 0) {
parseWarnings.push(`No test output found for runner "${options.runner.runner_id}"`);
const compact2 = buildCompactArtifact({
artifact_class: "test-output",
raw_content: "",
max_excerpts: 0
});
const tokenPayload2 = buildReasoningInputPayload(
compact2,
evaluateEscalation({
compact: compact2,
reason: "structured-parse-failed-or-degraded"
})
);
return finalizeParsedResult(createEmptyParsedResult(options.runner.runner_id), {
raw_byte_size: 0,
structured_byte_size: 0,
compression_ratio: 0,
original_size: tokenPayload2.metadata.original_size,
compact_size: tokenPayload2.metadata.compact_size,
reduction_ratio: tokenPayload2.metadata.reduction_ratio,
delta_mode_used: options.baseline_result !== void 0,
escalation_occurred: tokenPayload2.metadata.escalation_occurred,
escalation_reason: tokenPayload2.escalation_reason,
delta_summary: options.baseline_result ? summarizeTestDelta(
options.baseline_result,
createEmptyParsedResult(options.runner.runner_id)
) : null,
parse_strategy: "degraded",
parse_warnings: parseWarnings
});
}
const parsedResults = [];
let parseStrategy = options.runner.structured_format === "none" ? "plain-text-fallback" : "structured";
let rawByteSize = 0;
for (const source of rawSources) {
rawByteSize += Buffer.byteLength(source, "utf8");
const parsed = parseSingleSource(source, options.runner, parseWarnings);
parsedResults.push(parsed.result);
parseStrategy = selectDominantStrategy(parseStrategy, parsed.strategy);
}
const compact = buildCompactArtifact({
artifact_class: "test-output",
raw_content: rawSources.join("\n")
});
const shouldEscalateForParseHealth = parseStrategy === "degraded" || parseWarnings.some((warning2) => warning2.startsWith("Structured parser"));
const tokenPayload = buildReasoningInputPayload(
compact,
evaluateEscalation(
shouldEscalateForParseHealth ? {
compact,
reason: "structured-parse-failed-or-degraded"
} : { compact }
)
);
const merged = mergeParsedResults(parsedResults, options.runner.runner_id);
const projected = options.baseline_result && options.include_full_issues_with_baseline !== true ? projectDeltaIssues(options.baseline_result, merged) : merged;
return finalizeParsedResult(projected, {
raw_byte_size: rawByteSize,
structured_byte_size: 0,
compression_ratio: 0,
original_size: tokenPayload.metadata.original_size,
compact_size: tokenPayload.metadata.compact_size,
reduction_ratio: tokenPayload.metadata.reduction_ratio,
delta_mode_used: options.baseline_result !== void 0,
escalation_occurred: tokenPayload.metadata.escalation_occurred,
escalation_reason: tokenPayload.escalation_reason,
delta_summary: options.baseline_result ? summarizeTestDelta(options.baseline_result, merged) : null,
parse_strategy: parseStrategy,
parse_warnings: dedupeStrings(parseWarnings)
});
}
function parseSingleSource(rawSource, runner, parseWarnings) {
const normalized = normalizeRawOutput(rawSource);
if (runner.structured_format !== "none") {
try {
return {
result: parseStructuredByFormat(normalized, runner, parseWarnings),
strategy: "structured"
};
} catch (error) {
parseWarnings.push(
`Structured parser for "${runner.runner_id}" failed: ${formatErrorMessage(error)}`
);
}
}
try {
return {
result: parsePlainTextFallback(normalized, runner.runner_id),
strategy: "plain-text-fallback"
};
} catch (error) {
parseWarnings.push(
`Plain-text fallback for "${runner.runner_id}" failed: ${formatErrorMessage(error)}`
);
return {
result: createEmptyParsedResult(runner.runner_id),
strategy: "degraded"
};
}
}
async function collectRawSources(options) {
if ((options.runner.output_source ?? "stdout") === "file") {
if (!options.runner.output_path_pattern) {
return [];
}
const matches = await (0, import_fast_glob5.default)(options.runner.output_path_pattern, {
cwd: options.cwd,
absolute: true,
onlyFiles: true
});
const sortedMatches = [...matches].sort((left, right) => left.localeCompare(right));
return Promise.all(sortedMatches.map((path10) => readFile14(path10, "utf8")));
}
const stdout = toUtf8String(options.stdout);
const stderr = toUtf8String(options.stderr);
const combined = [stdout, stderr].filter((value) => value.trim().length > 0).join("\n");
return combined.trim().length > 0 ? [combined] : [];
}
function parseStructuredByFormat(rawOutput, runner, parseWarnings = []) {
switch (runner.structured_format) {
case "jest-json":
return parseJestJson(rawOutput, runner.runner_id);
case "junit-xml":
return parseJunitXml(rawOutput, runner.runner_id);
case "pytest-json":
return parsePytestJson(rawOutput, runner.runner_id);
case "go-json":
return parseGoJson(rawOutput, runner.runner_id, parseWarnings);
case "rspec-json":
return parseRspecJson(rawOutput, runner.runner_id);
case "tap":
return parseTap(rawOutput, runner.runner_id);
}
throw new Error(`Unsupported structured format "${runner.structured_format}"`);
}
function parseJestJson(rawOutput, runnerId) {
const parsed = JSON.parse(rawOutput);
const failures = [];
const errors = [];
let skippedFromLoop = 0;
for (const suite of parsed.testResults ?? []) {
for (const assertion of suite.assertionResults ?? []) {
const testId = assertion.fullName || [...assertion.ancestorTitles ?? [], assertion.title].filter(Boolean).join(" ") || suite.name || "unknown-test";
const issue = createIssue({
testId,
suite: assertion.ancestorTitles?.join(" > ") || null,
message: assertion.failureMessages?.join("\n\n") || `Test ${assertion.status ?? "unknown"}`,
stackTrace: assertion.failureMessages?.join("\n\n") || null,
filePath: suite.name ?? null,
lineNumber: assertion.location?.line ?? null,
category: classifyIssue(assertion.failureMessages?.join("\n") ?? "", "assertion"),
durationMs: assertion.duration ?? null
});
if (assertion.status === "failed") {
failures.push(issue);
} else if (assertion.status === "pending" || assertion.status === "skipped") {
skippedFromLoop += 1;
}
}
}
const failed = parsed.numFailedTests ?? failures.length;
const skipped5 = parsed.numPendingTests ?? skippedFromLoop;
return {
summary: {
total: parsed.numTotalTests ?? (parsed.numPassedTests ?? 0) + failed + skipped5 + errors.length,
passed: parsed.numPassedTests ?? 0,
failed,
skipped: skipped5,
errored: errors.length,
duration_ms: 0,
timestamp: toIsoTimestamp(parsed.startTime),
runner_id: runnerId
},
failures,
warnings: [],
errors
};
}
function parsePytestJson(rawOutput, runnerId) {
const parsed = JSON.parse(rawOutput);
const failures = [];
const errors = [];
for (const test of parsed.tests ?? []) {
const detail = test.call?.longrepr ?? test.call?.crash?.message ?? test.outcome ?? "unknown";
const issue = createIssue({
testId: test.nodeid ?? "unknown-test",
suite: test.nodeid?.split("::").slice(0, -1).join("::") || null,
message: detail,
stackTrace: test.call?.longrepr ?? null,
filePath: test.call?.crash?.path ?? test.nodeid?.split("::")[0] ?? null,
lineNumber: test.call?.crash?.lineno ?? test.lineno ?? null,
category: classifyIssue(detail, test.outcome === "error" ? "error" : "assertion"),
durationMs: toMilliseconds(test.call?.duration)
});
if (test.outcome === "failed") failures.push(issue);
if (test.outcome === "error") errors.push(issue);
}
return {
summary: {
total: parsed.summary?.total ?? parsed.tests?.length ?? 0,
passed: parsed.summary?.passed ?? 0,
failed: parsed.summary?.failed ?? failures.length,
skipped: parsed.summary?.skipped ?? 0,
errored: parsed.summary?.error ?? errors.length,
duration_ms: toMilliseconds(parsed.duration) ?? 0,
timestamp: normalizeTimestamp(parsed.created),
runner_id: runnerId
},
failures,
warnings: [],
errors
};
}
function parseRspecJson(rawOutput, runnerId) {
const parsed = JSON.parse(rawOutput);
const failures = [];
const errors = [];
for (const example of parsed.examples ?? []) {
if (example.status !== "failed") continue;
const message = example.exception?.message ?? "RSpec example failed";
failures.push(
createIssue({
testId: example.full_description ?? example.id ?? "unknown-test",
suite: null,
message,
stackTrace: example.exception?.backtrace?.join("\n") ?? null,
filePath: example.file_path ?? null,
lineNumber: example.line_number ?? null,
category: classifyIssue(message, "assertion"),
durationMs: toMilliseconds(example.run_time)
})
);
}
return {
summary: {
total: parsed.summary?.example_count ?? parsed.examples?.length ?? 0,
passed: (parsed.summary?.example_count ?? 0) - (parsed.summary?.failure_count ?? failures.length) - (parsed.summary?.pending_count ?? 0),
failed: parsed.summary?.failure_count ?? failures.length,
skipped: parsed.summary?.pending_count ?? 0,
errored: errors.length,
duration_ms: toMilliseconds(parsed.summary?.duration) ?? 0,
timestamp: UNKNOWN_TEST_OUTPUT_TIMESTAMP,
runner_id: runnerId
},
failures,
warnings: [],
errors
};
}
function parseGoJson(rawOutput, runnerId, parseWarnings = []) {
const lines = rawOutput.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
const events = [];
for (const line of lines) {
try {
events.push(JSON.parse(line));
} catch {
parseWarnings.push(`Go JSON: skipped malformed line: ${line.slice(0, 100)}`);
}
}
const outputs = /* @__PURE__ */ new Map();
const failures = [];
const errors = [];
let passed = 0;
let failed = 0;
let skipped5 = 0;
let total = 0;
let durationMs = 0;
for (const event of events) {
const testId = typeof event.Test === "string" ? event.Test : null;
const action = typeof event.Action === "string" ? event.Action : null;
const output = typeof event.Output === "string" ? event.Output : null;
if (testId && output) {
outputs.set(testId, [...outputs.get(testId) ?? [], output.trimEnd()]);
}
if (!testId || !action) continue;
if (action === "pass" || action === "fail" || action === "skip") {
total += 1;
durationMs += toMilliseconds(event.Elapsed) ?? 0;
if (action === "pass") passed += 1;
if (action === "skip") skipped5 += 1;
if (action === "fail") {
failed += 1;
const message = (outputs.get(testId) ?? []).join("\n").trim() || `${testId} failed`;
failures.push(
createIssue({
testId,
suite: typeof event.Package === "string" ? event.Package : null,
message,
stackTrace: message,
filePath: null,
lineNumber: null,
category: classifyIssue(message, "assertion"),
durationMs: toMilliseconds(event.Elapsed)
})
);
}
}
}
return {
summary: {
total,
passed,
failed,
skipped: skipped5,
errored: errors.length,
duration_ms: durationMs,
timestamp: UNKNOWN_TEST_OUTPUT_TIMESTAMP,
runner_id: runnerId
},
failures,
warnings: [],
errors
};
}
function splitTapEntry(raw) {
const text2 = (raw ?? "").replace(/\s*\{$/, "");
let name = "";
for (let i = 0; i < text2.length; i += 1) {
const ch = text2[i];
const next = text2[i + 1];
if (ch === "\\" && (next === "#" || next === "\\")) {
name += next;
i += 1;
continue;
}
if (ch === "#") return { name: name.trim(), directive: text2.slice(i + 1).trim() };
name += ch;
}
return { name: name.trim(), directive: "" };
}
function parseTap(rawOutput, runnerId) {
const failures = [];
const warnings = [];
let total = 0;
let passed = 0;
let failed = 0;
let skipped5 = 0;
let currentFailure = null;
let previousIndent = 0;
let inYaml = false;
const blocks = [];
const closeBlocksAt = (indent2) => {
const firstClosed = blocks.findIndex((block) => block.indent >= indent2);
if (firstClosed !== -1) blocks.length = firstClosed;
};
for (const line of rawOutput.split("\n")) {
const trimmed = line.trimEnd();
const content = trimmed.trimStart();
const indent2 = trimmed.length - content.length;
if (inYaml) {
if (content === "...") inYaml = false;
continue;
}
if (content === "---") {
inYaml = true;
continue;
}
if (content === "}") {
previousIndent = indent2;
closeBlocksAt(indent2);
continue;
}
const okMatch = /^(not )?ok\b(?:\s+\d+)?(?:\s+-\s+)?(.+)?$/i.exec(content);
if (okMatch) {
const opensBlock = content.endsWith("{");
const closesSubtests = indent2 < previousIndent;
previousIndent = indent2;
closeBlocksAt(indent2);
const entry = splitTapEntry(okMatch[2]);
if (opensBlock || closesSubtests) {
if (opensBlock) blocks.push({ indent: indent2, name: entry.name });
currentFailure = null;
continue;
}
total += 1;
const isFailure = okMatch[1] === "not ";
const description = entry.name || `test-${total}`;
const isSkipped = /^skip/i.test(entry.directive);
if (isSkipped) {
skipped5 += 1;
currentFailure = null;
continue;
}
if (isFailure) {
failed += 1;
const suite = blocks.map((block) => block.name).join(" > ");
currentFailure = createIssue({
testId: suite ? `${suite} > ${description}` : description,
suite: suite || null,
message: description,
stackTrace: null,
filePath: null,
lineNumber: null,
category: "unknown",
durationMs: null
});
failures.push(currentFailure);
} else {
passed += 1;
currentFailure = null;
}
continue;
}
if (trimmed.startsWith("#") && currentFailure !== null) {
currentFailure.message = `${currentFailure.message}
${trimmed.slice(1).trim()}`.trim();
currentFailure.stack_trace = currentFailure.message;
currentFailure.category = classifyIssue(currentFailure.message, "assertion");
continue;
}
if (trimmed.startsWith("#") && currentFailure === null) {
warnings.push({
type: "tap-note",
message: trimmed.slice(1).trim(),
source_test_id: null
});
}
}
return {
summary: {
total,
passed,
failed,
skipped: skipped5,
errored: 0,
duration_ms: 0,
timestamp: UNKNOWN_TEST_OUTPUT_TIMESTAMP,
runner_id: runnerId
},
failures,
warnings,
errors: []
};
}
function parseJunitXml(rawOutput, runnerId) {
if (!rawOutput.includes("<testsuite") && !rawOutput.includes("<testcase")) {
throw new Error("Not valid JUnit XML");
}
const failures = [];
const errors = [];
const warnings = [];
const cases = rawOutput.match(/<testcase\b(?:[^>]*\/>|[\s\S]*?<\/testcase>)/g) ?? [];
let total = 0;
let failed = 0;
let skipped5 = 0;
let errored = 0;
let durationMs = 0;
for (const testCase of cases) {
total += 1;
const attrs = parseXmlAttributes(testCase);
durationMs += toMilliseconds(attrs.time) ?? 0;
const failureTag = extractTag(testCase, "failure");
const errorTag = extractTag(testCase, "error");
const skippedTag = extractTag(testCase, "skipped");
const systemErr = extractTag(testCase, "system-err");
const testId = [attrs.classname, attrs.name].filter(Boolean).join("::") || "unknown-test";
if (skippedTag) {
skipped5 += 1;
continue;
}
if (failureTag) {
failed += 1;
failures.push(
createIssue({
testId,
suite: attrs.classname ?? null,
message: (failureTag.message ?? failureTag.content) || "Test failed",
stackTrace: failureTag.content || null,
filePath: attrs.file ?? null,
lineNumber: toInteger(attrs.line),
category: classifyIssue(failureTag.message ?? failureTag.content, "assertion"),
durationMs: toMilliseconds(attrs.time)
})
);
continue;
}
if (errorTag) {
errored += 1;
errors.push(
createIssue({
testId,
suite: attrs.classname ?? null,
message: (errorTag.message ?? errorTag.content) || "Test errored",
stackTrace: errorTag.content || null,
filePath: attrs.file ?? null,
lineNumber: toInteger(attrs.line),
category: classifyIssue(errorTag.message ?? errorTag.content, "error"),
durationMs: toMilliseconds(attrs.time)
})
);
continue;
}
if (systemErr) {
warnings.push({
type: "runner-stderr",
message: systemErr.content,
source_test_id: testId
});
}
}
return {
summary: {
total,
passed: total - failed - skipped5 - errored,
failed,
skipped: skipped5,
errored,
duration_ms: durationMs,
timestamp: UNKNOWN_TEST_OUTPUT_TIMESTAMP,
runner_id: runnerId
},
failures,
warnings,
errors
};
}
function parsePlainTextFallback(rawOutput, runnerId) {
const lines = rawOutput.split("\n").map((line) => line.replace(/\r/g, "")).filter((line) => !isRunnerEnvelope(line));
const failures = [];
const errors = [];
const warnings = [];
let currentIssue = null;
for (const line of lines) {
const trimmed = line.trim();
if (/warning|deprecated|deprecation/i.test(trimmed)) {
warnings.push({ type: "warning", message: trimmed, source_test_id: null });
}
const failureMatch = /^(?:FAIL(?:ED)?|not ok|✕|x)\s*[:-]?\s*(.+)$/i.exec(trimmed) ?? /^\s*\d+\)\s+(.+)$/.exec(trimmed);
if (failureMatch) {
currentIssue = createIssue({
testId: failureMatch[1].trim(),
suite: null,
message: failureMatch[1].trim(),
stackTrace: null,
filePath: null,
lineNumber: null,
category: "unknown",
durationMs: null
});
failures.push(currentIssue);
continue;
}
const errorMatch = /^ERROR\s*[:-]?\s*(.+)$/i.exec(trimmed);
if (errorMatch) {
currentIssue = createIssue({
testId: errorMatch[1].trim(),
suite: null,
message: errorMatch[1].trim(),
stackTrace: null,
filePath: null,
lineNumber: null,
category: "error",
durationMs: null
});
errors.push(currentIssue);
continue;
}
if (currentIssue !== null && (line.startsWith(" ") || /^\s*at\s+/.test(line))) {
currentIssue.stack_trace = `${currentIssue.stack_trace ?? currentIssue.message}
${trimmed}`;
currentIssue.category = classifyIssue(currentIssue.stack_trace, currentIssue.category);
continue;
}
}
const failed = failures.length;
const errored = errors.length;
const passed = extractSummaryCount(lines, "passed");
const skipped5 = extractSummaryCount(lines, "skipped");
const total = extractSummaryCount(lines, "total") || extractSummaryCount(lines, "tests") || passed + failed + errored + skipped5;
return {
summary: {
total,
passed,
failed,
skipped: skipped5,
errored,
duration_ms: extractDurationMs(lines) ?? 0,
timestamp: UNKNOWN_TEST_OUTPUT_TIMESTAMP,
runner_id: runnerId
},
failures,
warnings: dedupeWarnings(warnings),
errors
};
}
function mergeParsedResults(results, runnerId) {
const summary = {
total: 0,
passed: 0,
failed: 0,
skipped: 0,
errored: 0,
duration_ms: 0,
timestamp: UNKNOWN_TEST_OUTPUT_TIMESTAMP,
runner_id: runnerId
};
const failures = [];
const warnings = [];
const errors = [];
for (const result2 of results) {
summary.total += result2.summary.total;
summary.passed += result2.summary.passed;
summary.failed += result2.summary.failed;
summary.skipped += result2.summary.skipped;
summary.errored += result2.summary.errored;
summary.duration_ms += result2.summary.duration_ms;
summary.timestamp = summary.timestamp === UNKNOWN_TEST_OUTPUT_TIMESTAMP ? result2.summary.timestamp : summary.timestamp;
failures.push(...result2.failures);
warnings.push(...result2.warnings);
errors.push(...result2.errors);
}
return {
summary,
failures,
warnings: dedupeWarnings(warnings),
errors
};
}
function finalizeParsedResult(result2, parseMetadata) {
const structured = {
schema_version: TEST_OUTPUT_SCHEMA_VERSION,
summary: {
...result2.summary,
total: result2.summary.total || result2.summary.passed + result2.summary.failed + result2.summary.skipped + result2.summary.errored
},
failures: result2.failures,
warnings: result2.warnings,
parse_metadata: parseMetadata,
errors: result2.errors
};
const structuredByteSize = Buffer.byteLength(JSON.stringify(structured), "utf8");
const rawByteSize = parseMetadata.raw_byte_size;
structured.parse_metadata.structured_byte_size = structuredByteSize;
structured.parse_metadata.compression_ratio = rawByteSize > 0 ? Math.max(0, 1 - structuredByteSize / rawByteSize) : 0;
return structured;
}
function createEmptyParsedResult(runnerId) {
return {
summary: {
total: 0,
passed: 0,
failed: 0,
skipped: 0,
errored: 0,
duration_ms: 0,
timestamp: UNKNOWN_TEST_OUTPUT_TIMESTAMP,
runner_id: runnerId
},
failures: [],
warnings: [],
errors: []
};
}
function summarizeTestDelta(baseline, current) {
const baselineIssues = toIssueSnapshots(baseline.failures, baseline.errors);
const currentIssues = toIssueSnapshots(current.failures, current.errors);
const { delta } = createTestDelta(baselineIssues, currentIssues, {
treat_missing_as_passing: true
});
return {
newly_failing_tests: delta.newly_failing_tests.length,
newly_passing_tests: delta.newly_passing_tests.length,
newly_errored_tests: delta.newly_errored_tests.length,
changed_failure_messages: delta.changed_failure_messages.length
};
}
function projectDeltaIssues(baseline, current) {
const baselineIssues = toIssueSnapshots(baseline.failures, baseline.errors);
const currentIssues = toIssueSnapshots(current.failures, current.errors);
const { delta } = createTestDelta(baselineIssues, currentIssues, {
treat_missing_as_passing: true
});
const includeIds = /* @__PURE__ */ new Set([
...delta.newly_failing_tests,
...delta.newly_errored_tests,
...delta.changed_failure_messages.map((entry) => entry.test_id)
]);
return {
summary: current.summary,
failures: current.failures.filter((issue) => includeIds.has(issue.test_id)),
warnings: current.warnings.filter(
(warning2) => warning2.source_test_id !== null && includeIds.has(warning2.source_test_id)
),
errors: current.errors.filter((issue) => includeIds.has(issue.test_id))
};
}
function toIssueSnapshots(failures, errors) {
return [
...failures.map((issue) => ({
test_id: issue.test_id,
message: issue.message,
status: "failed"
})),
...errors.map((issue) => ({
test_id: issue.test_id,
message: issue.message,
status: "errored"
}))
];
}
function createIssue(input) {
return {
test_id: input.testId,
suite: input.suite,
message: input.message.trim() || "Unknown test issue",
stack_trace: input.stackTrace?.trim() || null,
file_path: input.filePath,
line_number: input.lineNumber,
category: input.category,
duration_ms: input.durationMs
};
}
function classifyIssue(message, fallback) {
if (/timeout|timed out/i.test(message)) return "timeout";
if (/error|exception|panic|segmentation fault/i.test(message)) return "error";
if (/expected|assert|failure|mismatch/i.test(message)) return "assertion";
return fallback;
}
function normalizeRawOutput(rawOutput) {
const ansiPattern = new RegExp(
String.raw`\u001b(?:\[[0-?]*[ -/]*[@-~]|\][^\u0007\u001b]*(?:\u0007|\u001b\\)|[@-Z\\-_])`,
"g"
);
return rawOutput.replace(ansiPattern, "").replace(/\r/g, "").trim();
}
function extractSummaryCount(lines, label) {
const patterns = [
new RegExp(`\\b${label}\\b[^\\d]*(\\d+)`, "i"),
new RegExp(`(\\d+)[^\\n]*\\b${label}\\b`, "i")
];
for (const line of [...lines].reverse()) {
for (const pattern of patterns) {
const match = pattern.exec(line);
if (match) {
return Number(match[1]);
}
}
}
return 0;
}
function extractDurationMs(lines) {
const candidates = [...lines].reverse();
for (const line of candidates) {
const seconds = /(\d+(?:\.\d+)?)s\b/.exec(line);
if (seconds) return Number(seconds[1]) * 1e3;
const milliseconds = /(\d+(?:\.\d+)?)ms\b/.exec(line);
if (milliseconds) return Number(milliseconds[1]);
}
return null;
}
function isRunnerEnvelope(line) {
const trimmed = line.trim();
return trimmed.length === 0 || /^[-=.]{3,}$/.test(trimmed) || /^Ran \d+ tests? in /i.test(trimmed) || /^={2,}\s*coverage/i.test(trimmed) || /^%?\s*Statements\s*:/.test(trimmed) || /^\.+$/.test(trimmed);
}
function parseXmlAttributes(xmlFragment) {
const attrMatch = /<testcase\b([^>]*)>/i.exec(xmlFragment);
const rawAttrs = attrMatch?.[1] ?? "";
const attrs = {};
for (const match of rawAttrs.matchAll(/([a-zA-Z_:][\w:.-]*)="([^"]*)"/g)) {
attrs[match[1]] = decodeXmlEntities(match[2]);
}
return attrs;
}
function extractTag(xmlFragment, tagName) {
const pairedMatch = new RegExp(`<${tagName}\\b([^>]*)>([\\s\\S]*?)<\\/${tagName}>`, "i").exec(
xmlFragment
);
const selfClosingMatch = new RegExp(`<${tagName}\\b([^>]*)\\/\\s*>`, "i").exec(xmlFragment);
const match = pairedMatch ?? selfClosingMatch;
if (!match) return null;
const attrs = {};
for (const attr of match[1].matchAll(/([a-zA-Z_:][\w:.-]*)="([^"]*)"/g)) {
attrs[attr[1]] = decodeXmlEntities(attr[2]);
}
return {
message: attrs.message ?? null,
content: decodeXmlEntities((pairedMatch?.[2] ?? "").trim())
};
}
function decodeXmlEntities(value) {
return value.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
}
function toUtf8String(value) {
if (value === void 0) return "";
return typeof value === "string" ? value : value.toString("utf8");
}
function toMilliseconds(value) {
if (typeof value === "string") {
const n = Number(value);
return Number.isNaN(n) ? null : n * 1e3;
}
if (typeof value !== "number" || Number.isNaN(value)) return null;
return value * 1e3;
}
function toInteger(value) {
if (typeof value === "number" && Number.isInteger(value)) return value;
if (typeof value === "string" && /^\d+$/.test(value)) return Number(value);
return null;
}
function toIsoTimestamp(epochMs) {
return typeof epochMs === "number" && Number.isFinite(epochMs) ? new Date(epochMs).toISOString() : UNKNOWN_TEST_OUTPUT_TIMESTAMP;
}
function normalizeTimestamp(value) {
if (!value) return UNKNOWN_TEST_OUTPUT_TIMESTAMP;
const parsed = new Date(value);
return Number.isNaN(parsed.getTime()) ? UNKNOWN_TEST_OUTPUT_TIMESTAMP : parsed.toISOString();
}
function dedupeWarnings(warnings) {
const seen = /* @__PURE__ */ new Set();
const deduped = [];
for (const warning2 of warnings) {
const key = `${warning2.type}:${warning2.message}:${warning2.source_test_id ?? ""}`;
if (seen.has(key)) continue;
seen.add(key);
deduped.push(warning2);
}
return deduped;
}
function dedupeStrings(values) {
return [...new Set(values)];
}
function formatErrorMessage(error) {
return error instanceof Error ? error.message : String(error);
}
function selectDominantStrategy(current, next) {
const rank = {
structured: 0,
"plain-text-fallback": 1,
degraded: 2
};
return rank[next] > rank[current] ? next : current;
}
var __testOutputInternals = {
selectDominantStrategy,
parseSingleSource,
collectRawSources,
parseStructuredByFormat,
parseJestJson,
parsePytestJson,
parseRspecJson,
parseGoJson,
parseTap,
parseJunitXml,
parsePlainTextFallback,
mergeParsedResults,
finalizeParsedResult,
createEmptyParsedResult,
summarizeTestDelta,
projectDeltaIssues,
createIssue,
classifyIssue,
normalizeRawOutput,
extractSummaryCount,
extractDurationMs,
isRunnerEnvelope,
parseXmlAttributes,
extractTag,
decodeXmlEntities,
toUtf8String,
toMilliseconds,
toInteger,
toIsoTimestamp,
normalizeTimestamp,
dedupeWarnings,
dedupeStrings,
formatErrorMessage
};
// src/test-output/fixtures.ts
init_esm_shims();
var TEST_OUTPUT_SMOKE_FIXTURES = {
"jest-json": JSON.stringify({
startTime: 17125e8,
numTotalTests: 1,
numPassedTests: 1,
numFailedTests: 0,
numPendingTests: 0,
testResults: [
{
name: "src/math.test.ts",
assertionResults: [
{
ancestorTitles: ["math"],
title: "adds",
fullName: "math adds",
status: "passed",
failureMessages: [],
duration: 5
}
]
}
]
}),
"junit-xml": `<testsuite tests="1" failures="0" errors="0" skipped="0" time="0.01">
<testcase classname="MathTest" name="adds" time="0.01" file="tests/MathTest.php" line="10"></testcase>
</testsuite>`,
"pytest-json": JSON.stringify({
created: "2024-04-01T10:00:00Z",
duration: 0.1,
summary: { total: 1, passed: 1, failed: 0, skipped: 0, error: 0 },
tests: [
{ nodeid: "tests/test_math.py::test_adds", outcome: "passed", call: { duration: 0.1 } }
]
}),
"go-json": `{"Time":"2024-04-01T10:00:00Z","Action":"run","Package":"pkg/math","Test":"TestAdds"}
{"Time":"2024-04-01T10:00:00Z","Action":"pass","Package":"pkg/math","Test":"TestAdds","Elapsed":0.01}`,
"rspec-json": JSON.stringify({
summary: { example_count: 1, failure_count: 0, pending_count: 0, duration: 0.1 },
examples: [{ id: "./spec/math_spec.rb[1:1]", full_description: "math adds", status: "passed" }]
}),
tap: `TAP version 13
1..1
ok 1 - math adds`,
none: `PASS src/math.test.ts
Tests: 1 passed
Time: 0.01s`
};
// src/spec-pipeline/config.ts
init_esm_shims();
var GATE_MODES = ["off", "warn", "strict"];
var DEFAULT_TOKEN_CEILING = 4e4;
var DEFAULT_GROUNDING_BUDGET_MS = 15e3;
function asGateMode(raw, fallback) {
if (raw === void 0) return fallback;
const v = raw.trim().toLowerCase();
return GATE_MODES.includes(v) ? v : fallback;
}
function parseStandingExperts(raw) {
if (raw === void 0) {
return { standing_experts: [...DEFAULT_STANDING_EXPERTS], standing_experts_dropped: [] };
}
const parts = raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
const standing_experts = [];
const standing_experts_dropped = [];
for (const part of parts) {
if (!isExpertRole(part)) {
if (!standing_experts_dropped.includes(part)) standing_experts_dropped.push(part);
continue;
}
if (!standing_experts.includes(part)) standing_experts.push(part);
}
return { standing_experts, standing_experts_dropped };
}
function readPipelineConfig(projectRoot, env2 = process.env) {
const map = layeredConfigMap(projectRoot, env2);
const switches = resolveSpecPipelineSwitches(map);
const standing = parseStandingExperts(map.get("spec_pipeline_standing_experts"));
return {
enabled: switches.enabled,
clarification: asGateMode(map.get("spec_pipeline_clarification"), "warn"),
final_review: asGateMode(map.get("spec_pipeline_final_review"), "off"),
token_ceiling: resolveNumericConfig(
projectRoot,
env2,
"spec_pipeline_token_ceiling",
DEFAULT_TOKEN_CEILING,
(n) => n > 0
),
grounding_budget_ms: resolveNumericConfig(
projectRoot,
env2,
"spec_grounding_budget_ms",
DEFAULT_GROUNDING_BUDGET_MS,
(n) => n > 0
),
experts_enabled: switches.experts_enabled,
adoption: switches.adoption,
standing_experts: standing.standing_experts,
standing_experts_dropped: standing.standing_experts_dropped,
experts_lanes: switches.experts_lanes
};
}
function expertsActive(config) {
return config.enabled && config.experts_enabled;
}
function standingBudgetSum(config) {
return config.standing_experts.reduce((sum, role) => sum + (ROLE_TOKEN_BUDGETS[role] ?? 0), 0);
}
// src/cli/commands/config.ts
init_esm_shims();
import { join as join24, relative as relative4 } from "path";
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/index.js
init_esm_shims();
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/argument.js
init_esm_shims();
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
init_esm_shims();
var CommanderError = class extends Error {
/**
* Constructs the CommanderError class
* @param {number} exitCode suggested exit code which could be used with process.exit
* @param {string} code an id string representing the error
* @param {string} message human-readable description of the error
*/
constructor(exitCode, code, message) {
super(message);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.code = code;
this.exitCode = exitCode;
this.nestedError = void 0;
}
};
var InvalidArgumentError = class extends CommanderError {
/**
* Constructs the InvalidArgumentError class
* @param {string} [message] explanation of why argument is invalid
*/
constructor(message) {
super(1, "commander.invalidArgument", message);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
}
};
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/argument.js
var Argument = class {
/**
* Initialize a new command argument with the given name and description.
* The default is that the argument is required, and you can explicitly
* indicate this with <> around the name. Put [] around the name for an optional argument.
*
* @param {string} name
* @param {string} [description]
*/
constructor(name, description) {
this.description = description || "";
this.variadic = false;
this.parseArg = void 0;
this.defaultValue = void 0;
this.defaultValueDescription = void 0;
this.argChoices = void 0;
switch (name[0]) {
case "<":
this.required = true;
this._name = name.slice(1, -1);
break;
case "[":
this.required = false;
this._name = name.slice(1, -1);
break;
default:
this.required = true;
this._name = name;
break;
}
if (this._name.endsWith("...")) {
this.variadic = true;
this._name = this._name.slice(0, -3);
}
}
/**
* Return argument name.
*
* @return {string}
*/
name() {
return this._name;
}
/**
* @package
*/
_collectValue(value, previous) {
if (previous === this.defaultValue || !Array.isArray(previous)) {
return [value];
}
previous.push(value);
return previous;
}
/**
* Set the default value, and optionally supply the description to be displayed in the help.
*
* @param {*} value
* @param {string} [description]
* @return {Argument}
*/
default(value, description) {
this.defaultValue = value;
this.defaultValueDescription = description;
return this;
}
/**
* Set the custom handler for processing CLI command arguments into argument values.
*
* @param {Function} [fn]
* @return {Argument}
*/
argParser(fn) {
this.parseArg = fn;
return this;
}
/**
* Only allow argument value to be one of choices.
*
* @param {string[]} values
* @return {Argument}
*/
choices(values) {
this.argChoices = values.slice();
this.parseArg = (arg, previous) => {
if (!this.argChoices.includes(arg)) {
throw new InvalidArgumentError(
`Allowed choices are ${this.argChoices.join(", ")}.`
);
}
if (this.variadic) {
return this._collectValue(arg, previous);
}
return arg;
};
return this;
}
/**
* Make argument required.
*
* @returns {Argument}
*/
argRequired() {
this.required = true;
return this;
}
/**
* Make argument optional.
*
* @returns {Argument}
*/
argOptional() {
this.required = false;
return this;
}
};
function humanReadableArgName(arg) {
const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
}
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/command.js
init_esm_shims();
import { EventEmitter } from "events";
import childProcess from "child_process";
import path8 from "path";
import fs from "fs";
import process2 from "process";
import { stripVTControlCharacters as stripVTControlCharacters2 } from "util";
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/help.js
init_esm_shims();
import { stripVTControlCharacters } from "util";
var Help = class {
constructor() {
this.helpWidth = void 0;
this.minWidthToWrap = 40;
this.sortSubcommands = false;
this.sortOptions = false;
this.showGlobalOptions = false;
}
/**
* prepareContext is called by Commander after applying overrides from `Command.configureHelp()`
* and just before calling `formatHelp()`.
*
* Commander just uses the helpWidth and the rest is provided for optional use by more complex subclasses.
*
* @param {{ error?: boolean, helpWidth?: number, outputHasColors?: boolean }} contextOptions
*/
prepareContext(contextOptions) {
this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
}
/**
* Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
*
* @param {Command} cmd
* @returns {Command[]}
*/
visibleCommands(cmd) {
const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
const helpCommand = cmd._getHelpCommand();
if (helpCommand && !helpCommand._hidden) {
visibleCommands.push(helpCommand);
}
if (this.sortSubcommands) {
visibleCommands.sort((a, b) => {
return a.name().localeCompare(b.name());
});
}
return visibleCommands;
}
/**
* Compare options for sort.
*
* @param {Option} a
* @param {Option} b
* @returns {number}
*/
compareOptions(a, b) {
const getSortKey = (option2) => {
return option2.short ? option2.short.replace(/^-/, "") : option2.long.replace(/^--/, "");
};
return getSortKey(a).localeCompare(getSortKey(b));
}
/**
* Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
*
* @param {Command} cmd
* @returns {Option[]}
*/
visibleOptions(cmd) {
const visibleOptions = cmd.options.filter((option2) => !option2.hidden);
const helpOption = cmd._getHelpOption();
if (helpOption && !helpOption.hidden) {
const removeShort = helpOption.short && cmd._findOption(helpOption.short);
const removeLong = helpOption.long && cmd._findOption(helpOption.long);
if (!removeShort && !removeLong) {
visibleOptions.push(helpOption);
} else if (helpOption.long && !removeLong) {
visibleOptions.push(
cmd.createOption(helpOption.long, helpOption.description)
);
} else if (helpOption.short && !removeShort) {
visibleOptions.push(
cmd.createOption(helpOption.short, helpOption.description)
);
}
}
if (this.sortOptions) {
visibleOptions.sort(this.compareOptions);
}
return visibleOptions;
}
/**
* Get an array of the visible global options. (Not including help.)
*
* @param {Command} cmd
* @returns {Option[]}
*/
visibleGlobalOptions(cmd) {
if (!this.showGlobalOptions) return [];
const globalOptions = [];
for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
const visibleOptions = ancestorCmd.options.filter(
(option2) => !option2.hidden
);
globalOptions.push(...visibleOptions);
}
if (this.sortOptions) {
globalOptions.sort(this.compareOptions);
}
return globalOptions;
}
/**
* Get an array of the arguments if any have a description.
*
* @param {Command} cmd
* @returns {Argument[]}
*/
visibleArguments(cmd) {
if (cmd._argsDescription) {
cmd.registeredArguments.forEach((argument) => {
argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
});
}
if (cmd.registeredArguments.find((argument) => argument.description)) {
return cmd.registeredArguments;
}
return [];
}
/**
* Get the command term to show in the list of subcommands.
*
* @param {Command} cmd
* @returns {string}
*/
subcommandTerm(cmd) {
const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + // simplistic check for non-help option
(args ? " " + args : "");
}
/**
* Get the option term to show in the list of options.
*
* @param {Option} option
* @returns {string}
*/
optionTerm(option2) {
return option2.flags;
}
/**
* Get the argument term to show in the list of arguments.
*
* @param {Argument} argument
* @returns {string}
*/
argumentTerm(argument) {
return argument.name();
}
/**
* Get the longest command term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestSubcommandTermLength(cmd, helper) {
return helper.visibleCommands(cmd).reduce((max, command) => {
return Math.max(
max,
this.displayWidth(
helper.styleSubcommandTerm(helper.subcommandTerm(command))
)
);
}, 0);
}
/**
* Get the longest option term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestOptionTermLength(cmd, helper) {
return helper.visibleOptions(cmd).reduce((max, option2) => {
return Math.max(
max,
this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option2)))
);
}, 0);
}
/**
* Get the longest global option term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestGlobalOptionTermLength(cmd, helper) {
return helper.visibleGlobalOptions(cmd).reduce((max, option2) => {
return Math.max(
max,
this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option2)))
);
}, 0);
}
/**
* Get the longest argument term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestArgumentTermLength(cmd, helper) {
return helper.visibleArguments(cmd).reduce((max, argument) => {
return Math.max(
max,
this.displayWidth(
helper.styleArgumentTerm(helper.argumentTerm(argument))
)
);
}, 0);
}
/**
* Get the command usage to be displayed at the top of the built-in help.
*
* @param {Command} cmd
* @returns {string}
*/
commandUsage(cmd) {
let cmdName = cmd._name;
if (cmd._aliases[0]) {
cmdName = cmdName + "|" + cmd._aliases[0];
}
let ancestorCmdNames = "";
for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
}
return ancestorCmdNames + cmdName + " " + cmd.usage();
}
/**
* Get the description for the command.
*
* @param {Command} cmd
* @returns {string}
*/
commandDescription(cmd) {
return cmd.description();
}
/**
* Get the subcommand summary to show in the list of subcommands.
* (Fallback to description for backwards compatibility.)
*
* @param {Command} cmd
* @returns {string}
*/
subcommandDescription(cmd) {
return cmd.summary() || cmd.description();
}
/**
* Get the option description to show in the list of options.
*
* @param {Option} option
* @return {string}
*/
optionDescription(option2) {
const extraInfo = [];
if (option2.argChoices) {
extraInfo.push(
// use stringify to match the display of the default value
`choices: ${option2.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`
);
}
if (option2.defaultValue !== void 0) {
const showDefault = option2.required || option2.optional || option2.isBoolean() && typeof option2.defaultValue === "boolean";
if (showDefault) {
extraInfo.push(
`default: ${option2.defaultValueDescription || JSON.stringify(option2.defaultValue)}`
);
}
}
if (option2.presetArg !== void 0 && option2.optional) {
extraInfo.push(`preset: ${JSON.stringify(option2.presetArg)}`);
}
if (option2.envVar !== void 0) {
extraInfo.push(`env: ${option2.envVar}`);
}
if (extraInfo.length > 0) {
const extraDescription = `(${extraInfo.join(", ")})`;
if (option2.description) {
return `${option2.description} ${extraDescription}`;
}
return extraDescription;
}
return option2.description;
}
/**
* Get the argument description to show in the list of arguments.
*
* @param {Argument} argument
* @return {string}
*/
argumentDescription(argument) {
const extraInfo = [];
if (argument.argChoices) {
extraInfo.push(
// use stringify to match the display of the default value
`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`
);
}
if (argument.defaultValue !== void 0) {
extraInfo.push(
`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`
);
}
if (extraInfo.length > 0) {
const extraDescription = `(${extraInfo.join(", ")})`;
if (argument.description) {
return `${argument.description} ${extraDescription}`;
}
return extraDescription;
}
return argument.description;
}
/**
* Format a list of items, given a heading and an array of formatted items.
*
* @param {string} heading
* @param {string[]} items
* @param {Help} helper
* @returns string[]
*/
formatItemList(heading, items, helper) {
if (items.length === 0) return [];
return [helper.styleTitle(heading), ...items, ""];
}
/**
* Group items by their help group heading.
*
* @param {Command[] | Option[]} unsortedItems
* @param {Command[] | Option[]} visibleItems
* @param {Function} getGroup
* @returns {Map<string, Command[] | Option[]>}
*/
groupItems(unsortedItems, visibleItems, getGroup) {
const result2 = /* @__PURE__ */ new Map();
unsortedItems.forEach((item) => {
const group = getGroup(item);
if (!result2.has(group)) result2.set(group, []);
});
visibleItems.forEach((item) => {
const group = getGroup(item);
if (!result2.has(group)) {
result2.set(group, []);
}
result2.get(group).push(item);
});
return result2;
}
/**
* Generate the built-in help text.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {string}
*/
formatHelp(cmd, helper) {
const termWidth = helper.padWidth(cmd, helper);
const helpWidth = helper.helpWidth ?? 80;
function callFormatItem(term, description) {
return helper.formatItem(term, termWidth, description, helper);
}
let output = [
`${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,
""
];
const commandDescription = helper.commandDescription(cmd);
if (commandDescription.length > 0) {
output = output.concat([
helper.boxWrap(
helper.styleCommandDescription(commandDescription),
helpWidth
),
""
]);
}
const argumentList = helper.visibleArguments(cmd).map((argument) => {
return callFormatItem(
helper.styleArgumentTerm(helper.argumentTerm(argument)),
helper.styleArgumentDescription(helper.argumentDescription(argument))
);
});
output = output.concat(
this.formatItemList("Arguments:", argumentList, helper)
);
const optionGroups = this.groupItems(
cmd.options,
helper.visibleOptions(cmd),
(option2) => option2.helpGroupHeading ?? "Options:"
);
optionGroups.forEach((options, group) => {
const optionList = options.map((option2) => {
return callFormatItem(
helper.styleOptionTerm(helper.optionTerm(option2)),
helper.styleOptionDescription(helper.optionDescription(option2))
);
});
output = output.concat(this.formatItemList(group, optionList, helper));
});
if (helper.showGlobalOptions) {
const globalOptionList = helper.visibleGlobalOptions(cmd).map((option2) => {
return callFormatItem(
helper.styleOptionTerm(helper.optionTerm(option2)),
helper.styleOptionDescription(helper.optionDescription(option2))
);
});
output = output.concat(
this.formatItemList("Global Options:", globalOptionList, helper)
);
}
const commandGroups = this.groupItems(
cmd.commands,
helper.visibleCommands(cmd),
(sub) => sub.helpGroup() || "Commands:"
);
commandGroups.forEach((commands, group) => {
const commandList = commands.map((sub) => {
return callFormatItem(
helper.styleSubcommandTerm(helper.subcommandTerm(sub)),
helper.styleSubcommandDescription(helper.subcommandDescription(sub))
);
});
output = output.concat(this.formatItemList(group, commandList, helper));
});
return output.join("\n");
}
/**
* Return display width of string, ignoring ANSI escape sequences. Used in padding and wrapping calculations.
*
* @param {string} str
* @returns {number}
*/
displayWidth(str) {
return stripVTControlCharacters(str).length;
}
/**
* Style the title for displaying in the help. Called with 'Usage:', 'Options:', etc.
*
* @param {string} str
* @returns {string}
*/
styleTitle(str) {
return str;
}
styleUsage(str) {
return str.split(" ").map((word) => {
if (word === "[options]") return this.styleOptionText(word);
if (word === "[command]") return this.styleSubcommandText(word);
if (word[0] === "[" || word[0] === "<")
return this.styleArgumentText(word);
return this.styleCommandText(word);
}).join(" ");
}
styleCommandDescription(str) {
return this.styleDescriptionText(str);
}
styleOptionDescription(str) {
return this.styleDescriptionText(str);
}
styleSubcommandDescription(str) {
return this.styleDescriptionText(str);
}
styleArgumentDescription(str) {
return this.styleDescriptionText(str);
}
styleDescriptionText(str) {
return str;
}
styleOptionTerm(str) {
return this.styleOptionText(str);
}
styleSubcommandTerm(str) {
return str.split(" ").map((word) => {
if (word === "[options]") return this.styleOptionText(word);
if (word[0] === "[" || word[0] === "<")
return this.styleArgumentText(word);
return this.styleSubcommandText(word);
}).join(" ");
}
styleArgumentTerm(str) {
return this.styleArgumentText(str);
}
styleOptionText(str) {
return str;
}
styleArgumentText(str) {
return str;
}
styleSubcommandText(str) {
return str;
}
styleCommandText(str) {
return str;
}
/**
* Calculate the pad width from the maximum term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
padWidth(cmd, helper) {
return Math.max(
helper.longestOptionTermLength(cmd, helper),
helper.longestGlobalOptionTermLength(cmd, helper),
helper.longestSubcommandTermLength(cmd, helper),
helper.longestArgumentTermLength(cmd, helper)
);
}
/**
* Detect manually wrapped and indented strings by checking for line break followed by whitespace.
*
* @param {string} str
* @returns {boolean}
*/
preformatted(str) {
return /\n[^\S\r\n]/.test(str);
}
/**
* Format the "item", which consists of a term and description. Pad the term and wrap the description, indenting the following lines.
*
* So "TTT", 5, "DDD DDDD DD DDD" might be formatted for this.helpWidth=17 like so:
* TTT DDD DDDD
* DD DDD
*
* @param {string} term
* @param {number} termWidth
* @param {string} description
* @param {Help} helper
* @returns {string}
*/
formatItem(term, termWidth, description, helper) {
const itemIndent = 2;
const itemIndentStr = " ".repeat(itemIndent);
if (!description) return itemIndentStr + term;
const paddedTerm = term.padEnd(
termWidth + term.length - helper.displayWidth(term)
);
const spacerWidth = 2;
const helpWidth = this.helpWidth ?? 80;
const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent;
let formattedDescription;
if (remainingWidth < this.minWidthToWrap || helper.preformatted(description)) {
formattedDescription = description;
} else {
const wrappedDescription = helper.boxWrap(description, remainingWidth);
formattedDescription = wrappedDescription.replace(
/\n/g,
"\n" + " ".repeat(termWidth + spacerWidth)
);
}
return itemIndentStr + paddedTerm + " ".repeat(spacerWidth) + formattedDescription.replace(/\n/g, `
${itemIndentStr}`);
}
/**
* Wrap a string at whitespace, preserving existing line breaks.
* Wrapping is skipped if the width is less than `minWidthToWrap`.
*
* @param {string} str
* @param {number} width
* @returns {string}
*/
boxWrap(str, width) {
if (width < this.minWidthToWrap) return str;
const rawLines2 = str.split(/\r\n|\n/);
const chunkPattern = /[\s]*[^\s]+/g;
const wrappedLines = [];
rawLines2.forEach((line) => {
const chunks = line.match(chunkPattern);
if (chunks === null) {
wrappedLines.push("");
return;
}
let sumChunks = [chunks.shift()];
let sumWidth = this.displayWidth(sumChunks[0]);
chunks.forEach((chunk) => {
const visibleWidth = this.displayWidth(chunk);
if (sumWidth + visibleWidth <= width) {
sumChunks.push(chunk);
sumWidth += visibleWidth;
return;
}
wrappedLines.push(sumChunks.join(""));
const nextChunk = chunk.trimStart();
sumChunks = [nextChunk];
sumWidth = this.displayWidth(nextChunk);
});
wrappedLines.push(sumChunks.join(""));
});
return wrappedLines.join("\n");
}
};
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/option.js
init_esm_shims();
var Option = class {
/**
* Initialize a new `Option` with the given `flags` and `description`.
*
* @param {string} flags
* @param {string} [description]
*/
constructor(flags, description) {
this.flags = flags;
this.description = description || "";
this.required = flags.includes("<");
this.optional = flags.includes("[");
this.variadic = /\w\.\.\.[>\]]$/.test(flags);
this.mandatory = false;
const optionFlags = splitOptionFlags(flags);
this.short = optionFlags.shortFlag;
this.long = optionFlags.longFlag;
this.negate = false;
if (this.long) {
this.negate = this.long.startsWith("--no-");
}
this.defaultValue = void 0;
this.defaultValueDescription = void 0;
this.presetArg = void 0;
this.envVar = void 0;
this.parseArg = void 0;
this.hidden = false;
this.argChoices = void 0;
this.conflictsWith = [];
this.implied = void 0;
this.helpGroupHeading = void 0;
}
/**
* Set the default value, and optionally supply the description to be displayed in the help.
*
* @param {*} value
* @param {string} [description]
* @return {Option}
*/
default(value, description) {
this.defaultValue = value;
this.defaultValueDescription = description;
return this;
}
/**
* Preset to use when option used without option-argument, especially optional but also boolean and negated.
* The custom processing (parseArg) is called.
*
* @example
* new Option('--color').default('GREYSCALE').preset('RGB');
* new Option('--donate [amount]').preset('20').argParser(parseFloat);
*
* @param {*} arg
* @return {Option}
*/
preset(arg) {
this.presetArg = arg;
return this;
}
/**
* Add option name(s) that conflict with this option.
* An error will be displayed if conflicting options are found during parsing.
*
* @example
* new Option('--rgb').conflicts('cmyk');
* new Option('--js').conflicts(['ts', 'jsx']);
*
* @param {(string | string[])} names
* @return {Option}
*/
conflicts(names) {
this.conflictsWith = this.conflictsWith.concat(names);
return this;
}
/**
* Specify implied option values for when this option is set and the implied options are not.
*
* The custom processing (parseArg) is not called on the implied values.
*
* @example
* program
* .addOption(new Option('--log', 'write logging information to file'))
* .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
*
* @param {object} impliedOptionValues
* @return {Option}
*/
implies(impliedOptionValues) {
let newImplied = impliedOptionValues;
if (typeof impliedOptionValues === "string") {
newImplied = { [impliedOptionValues]: true };
}
this.implied = Object.assign(this.implied || {}, newImplied);
return this;
}
/**
* Set environment variable to check for option value.
*
* An environment variable is only used if when processed the current option value is
* undefined, or the source of the current value is 'default' or 'config' or 'env'.
*
* @param {string} name
* @return {Option}
*/
env(name) {
this.envVar = name;
return this;
}
/**
* Set the custom handler for processing CLI option arguments into option values.
*
* @param {Function} [fn]
* @return {Option}
*/
argParser(fn) {
this.parseArg = fn;
return this;
}
/**
* Whether the option is mandatory and must have a value after parsing.
*
* @param {boolean} [mandatory=true]
* @return {Option}
*/
makeOptionMandatory(mandatory = true) {
this.mandatory = !!mandatory;
return this;
}
/**
* Hide option in help.
*
* @param {boolean} [hide=true]
* @return {Option}
*/
hideHelp(hide = true) {
this.hidden = !!hide;
return this;
}
/**
* @package
*/
_collectValue(value, previous) {
if (previous === this.defaultValue || !Array.isArray(previous)) {
return [value];
}
previous.push(value);
return previous;
}
/**
* Only allow option value to be one of choices.
*
* @param {string[]} values
* @return {Option}
*/
choices(values) {
this.argChoices = values.slice();
this.parseArg = (arg, previous) => {
if (!this.argChoices.includes(arg)) {
throw new InvalidArgumentError(
`Allowed choices are ${this.argChoices.join(", ")}.`
);
}
if (this.variadic) {
return this._collectValue(arg, previous);
}
return arg;
};
return this;
}
/**
* Return option name.
*
* @return {string}
*/
name() {
if (this.long) {
return this.long.replace(/^--/, "");
}
return this.short.replace(/^-/, "");
}
/**
* Return option name, in a camelcase format that can be used
* as an object attribute key.
*
* @return {string}
*/
attributeName() {
if (this.negate) {
return camelcase(this.name().replace(/^no-/, ""));
}
return camelcase(this.name());
}
/**
* Set the help group heading.
*
* @param {string} heading
* @return {Option}
*/
helpGroup(heading) {
this.helpGroupHeading = heading;
return this;
}
/**
* Check if `arg` matches the short or long flag.
*
* @param {string} arg
* @return {boolean}
* @package
*/
is(arg) {
return this.short === arg || this.long === arg;
}
/**
* Return whether a boolean option.
*
* Options are one of boolean, negated, required argument, or optional argument.
*
* @return {boolean}
* @package
*/
isBoolean() {
return !this.required && !this.optional && !this.negate;
}
};
var DualOptions = class {
/**
* @param {Option[]} options
*/
constructor(options) {
this.positiveOptions = /* @__PURE__ */ new Map();
this.negativeOptions = /* @__PURE__ */ new Map();
this.dualOptions = /* @__PURE__ */ new Set();
options.forEach((option2) => {
if (option2.negate) {
this.negativeOptions.set(option2.attributeName(), option2);
} else {
this.positiveOptions.set(option2.attributeName(), option2);
}
});
this.negativeOptions.forEach((value, key) => {
if (this.positiveOptions.has(key)) {
this.dualOptions.add(key);
}
});
}
/**
* Did the value come from the option, and not from possible matching dual option?
*
* @param {*} value
* @param {Option} option
* @returns {boolean}
*/
valueFromOption(value, option2) {
const optionKey = option2.attributeName();
if (!this.dualOptions.has(optionKey)) return true;
const preset = this.negativeOptions.get(optionKey).presetArg;
const negativeValue = preset !== void 0 ? preset : false;
return option2.negate === (negativeValue === value);
}
};
function camelcase(str) {
return str.split("-").reduce((str2, word) => {
return str2 + word[0].toUpperCase() + word.slice(1);
});
}
function splitOptionFlags(flags) {
let shortFlag;
let longFlag;
const shortFlagExp = /^-[^-]$/;
const longFlagExp = /^--[^-]/;
const flagParts = flags.split(/[ |,]+/).concat("guard");
if (shortFlagExp.test(flagParts[0])) shortFlag = flagParts.shift();
if (longFlagExp.test(flagParts[0])) longFlag = flagParts.shift();
if (!shortFlag && shortFlagExp.test(flagParts[0]))
shortFlag = flagParts.shift();
if (!shortFlag && longFlagExp.test(flagParts[0])) {
shortFlag = longFlag;
longFlag = flagParts.shift();
}
if (flagParts[0].startsWith("-")) {
const unsupportedFlag = flagParts[0];
const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;
if (/^-[^-][^-]/.test(unsupportedFlag))
throw new Error(
`${baseError}
- a short flag is a single dash and a single character
- either use a single dash and a single character (for a short flag)
- or use a double dash for a long option (and can have two, like '--ws, --workspace')`
);
if (shortFlagExp.test(unsupportedFlag))
throw new Error(`${baseError}
- too many short flags`);
if (longFlagExp.test(unsupportedFlag))
throw new Error(`${baseError}
- too many long flags`);
throw new Error(`${baseError}
- unrecognised flag format`);
}
if (shortFlag === void 0 && longFlag === void 0)
throw new Error(
`option creation failed due to no flags found in '${flags}'.`
);
return { shortFlag, longFlag };
}
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/suggestSimilar.js
init_esm_shims();
var maxDistance = 3;
function editDistance(a, b) {
if (Math.abs(a.length - b.length) > maxDistance)
return Math.max(a.length, b.length);
const d = [];
for (let i = 0; i <= a.length; i++) {
d[i] = [i];
}
for (let j = 0; j <= b.length; j++) {
d[0][j] = j;
}
for (let j = 1; j <= b.length; j++) {
for (let i = 1; i <= a.length; i++) {
let cost;
if (a[i - 1] === b[j - 1]) {
cost = 0;
} else {
cost = 1;
}
d[i][j] = Math.min(
d[i - 1][j] + 1,
// deletion
d[i][j - 1] + 1,
// insertion
d[i - 1][j - 1] + cost
// substitution
);
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
}
}
}
return d[a.length][b.length];
}
function suggestSimilar(word, candidates) {
if (!candidates || candidates.length === 0) return "";
candidates = Array.from(new Set(candidates));
const searchingOptions = word.startsWith("--");
if (searchingOptions) {
word = word.slice(2);
candidates = candidates.map((candidate) => candidate.slice(2));
}
let similar = [];
let bestDistance = maxDistance;
const minSimilarity = 0.4;
candidates.forEach((candidate) => {
if (candidate.length <= 1) return;
const distance = editDistance(word, candidate);
const length = Math.max(word.length, candidate.length);
const similarity = (length - distance) / length;
if (similarity > minSimilarity) {
if (distance < bestDistance) {
bestDistance = distance;
similar = [candidate];
} else if (distance === bestDistance) {
similar.push(candidate);
}
}
});
similar.sort((a, b) => a.localeCompare(b));
if (searchingOptions) {
similar = similar.map((candidate) => `--${candidate}`);
}
if (similar.length > 1) {
return `
(Did you mean one of ${similar.join(", ")}?)`;
}
if (similar.length === 1) {
return `
(Did you mean ${similar[0]}?)`;
}
return "";
}
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/command.js
var Command = class _Command extends EventEmitter {
/**
* Initialize a new `Command`.
*
* @param {string} [name]
*/
constructor(name) {
super();
this.commands = [];
this.options = [];
this.parent = null;
this._allowUnknownOption = false;
this._allowExcessArguments = false;
this.registeredArguments = [];
this._args = this.registeredArguments;
this.args = [];
this.rawArgs = [];
this.processedArgs = [];
this._scriptPath = null;
this._name = name || "";
this._optionValues = {};
this._optionValueSources = {};
this._storeOptionsAsProperties = false;
this._actionHandler = null;
this._executableHandler = false;
this._executableFile = null;
this._executableDir = null;
this._defaultCommandName = null;
this._exitCallback = null;
this._aliases = [];
this._combineFlagAndOptionalValue = true;
this._description = "";
this._summary = "";
this._argsDescription = void 0;
this._enablePositionalOptions = false;
this._passThroughOptions = false;
this._lifeCycleHooks = {};
this._showHelpAfterError = false;
this._showSuggestionAfterError = true;
this._savedState = null;
this._outputConfiguration = {
writeOut: (str) => process2.stdout.write(str),
writeErr: (str) => process2.stderr.write(str),
outputError: (str, write) => write(str),
getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : void 0,
getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : void 0,
getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
stripColor: (str) => stripVTControlCharacters2(str)
};
this._hidden = false;
this._helpOption = void 0;
this._addImplicitHelpCommand = void 0;
this._helpCommand = void 0;
this._helpConfiguration = {};
this._helpGroupHeading = void 0;
this._defaultCommandGroup = void 0;
this._defaultOptionGroup = void 0;
}
/**
* Copy settings that are useful to have in common across root command and subcommands.
*
* (Used internally when adding a command using `.command()` so subcommands inherit parent settings.)
*
* @param {Command} sourceCommand
* @return {Command} `this` command for chaining
*/
copyInheritedSettings(sourceCommand) {
this._outputConfiguration = sourceCommand._outputConfiguration;
this._helpOption = sourceCommand._helpOption;
this._helpCommand = sourceCommand._helpCommand;
this._helpConfiguration = sourceCommand._helpConfiguration;
this._exitCallback = sourceCommand._exitCallback;
this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
this._allowExcessArguments = sourceCommand._allowExcessArguments;
this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
this._showHelpAfterError = sourceCommand._showHelpAfterError;
this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
return this;
}
/**
* @returns {Command[]}
* @private
*/
_getCommandAndAncestors() {
const result2 = [];
for (let command = this; command; command = command.parent) {
result2.push(command);
}
return result2;
}
/**
* Define a command.
*
* There are two styles of command: pay attention to where to put the description.
*
* @example
* // Command implemented using action handler (description is supplied separately to `.command`)
* program
* .command('clone <source> [destination]')
* .description('clone a repository into a newly created directory')
* .action((source, destination) => {
* console.log('clone command called');
* });
*
* // Command implemented using separate executable file (description is second parameter to `.command`)
* program
* .command('start <service>', 'start named service')
* .command('stop [service]', 'stop named service, or all if no name supplied');
*
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
* @param {(object | string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
* @param {object} [execOpts] - configuration options (for executable)
* @return {Command} returns new command for action handler, or `this` for executable command
*/
command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
let desc = actionOptsOrExecDesc;
let opts = execOpts;
if (typeof desc === "object" && desc !== null) {
opts = desc;
desc = null;
}
opts = opts || {};
const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);
const cmd = this.createCommand(name);
if (desc) {
cmd.description(desc);
cmd._executableHandler = true;
}
if (opts.isDefault) this._defaultCommandName = cmd._name;
cmd._hidden = !!(opts.noHelp || opts.hidden);
cmd._executableFile = opts.executableFile || null;
if (args) cmd.arguments(args);
this._registerCommand(cmd);
cmd.parent = this;
cmd.copyInheritedSettings(this);
if (desc) return this;
return cmd;
}
/**
* Factory routine to create a new unattached command.
*
* See .command() for creating an attached subcommand, which uses this routine to
* create the command. You can override createCommand to customise subcommands.
*
* @param {string} [name]
* @return {Command} new command
*/
createCommand(name) {
return new _Command(name);
}
/**
* You can customise the help with a subclass of Help by overriding createHelp,
* or by overriding Help properties using configureHelp().
*
* @return {Help}
*/
createHelp() {
return Object.assign(new Help(), this.configureHelp());
}
/**
* You can customise the help by overriding Help properties using configureHelp(),
* or with a subclass of Help by overriding createHelp().
*
* @param {object} [configuration] - configuration options
* @return {(Command | object)} `this` command for chaining, or stored configuration
*/
configureHelp(configuration) {
if (configuration === void 0) return this._helpConfiguration;
this._helpConfiguration = configuration;
return this;
}
/**
* The default output goes to stdout and stderr. You can customise this for special
* applications. You can also customise the display of errors by overriding outputError.
*
* The configuration properties are all functions:
*
* // change how output being written, defaults to stdout and stderr
* writeOut(str)
* writeErr(str)
* // change how output being written for errors, defaults to writeErr
* outputError(str, write) // used for displaying errors and not used for displaying help
* // specify width for wrapping help
* getOutHelpWidth()
* getErrHelpWidth()
* // color support, currently only used with Help
* getOutHasColors()
* getErrHasColors()
* stripColor() // used to remove ANSI escape codes if output does not have colors
*
* @param {object} [configuration] - configuration options
* @return {(Command | object)} `this` command for chaining, or stored configuration
*/
configureOutput(configuration) {
if (configuration === void 0) return this._outputConfiguration;
this._outputConfiguration = {
...this._outputConfiguration,
...configuration
};
return this;
}
/**
* Display the help or a custom message after an error occurs.
*
* @param {(boolean|string)} [displayHelp]
* @return {Command} `this` command for chaining
*/
showHelpAfterError(displayHelp = true) {
if (typeof displayHelp !== "string") displayHelp = !!displayHelp;
this._showHelpAfterError = displayHelp;
return this;
}
/**
* Display suggestion of similar commands for unknown commands, or options for unknown options.
*
* @param {boolean} [displaySuggestion]
* @return {Command} `this` command for chaining
*/
showSuggestionAfterError(displaySuggestion = true) {
this._showSuggestionAfterError = !!displaySuggestion;
return this;
}
/**
* Add a prepared subcommand.
*
* See .command() for creating an attached subcommand which inherits settings from its parent.
*
* @param {Command} cmd - new subcommand
* @param {object} [opts] - configuration options
* @return {Command} `this` command for chaining
*/
addCommand(cmd, opts) {
if (!cmd._name) {
throw new Error(`Command passed to .addCommand() must have a name
- specify the name in Command constructor or using .name()`);
}
opts = opts || {};
if (opts.isDefault) this._defaultCommandName = cmd._name;
if (opts.noHelp || opts.hidden) cmd._hidden = true;
this._registerCommand(cmd);
cmd.parent = this;
cmd._checkForBrokenPassThrough();
return this;
}
/**
* Factory routine to create a new unattached argument.
*
* See .argument() for creating an attached argument, which uses this routine to
* create the argument. You can override createArgument to return a custom argument.
*
* @param {string} name
* @param {string} [description]
* @return {Argument} new argument
*/
createArgument(name, description) {
return new Argument(name, description);
}
/**
* Define argument syntax for command.
*
* The default is that the argument is required, and you can explicitly
* indicate this with <> around the name. Put [] around the name for an optional argument.
*
* @example
* program.argument('<input-file>');
* program.argument('[output-file]');
*
* @param {string} name
* @param {string} [description]
* @param {(Function|*)} [parseArg] - custom argument processing function or default value
* @param {*} [defaultValue]
* @return {Command} `this` command for chaining
*/
argument(name, description, parseArg, defaultValue) {
const argument = this.createArgument(name, description);
if (typeof parseArg === "function") {
argument.default(defaultValue).argParser(parseArg);
} else {
argument.default(parseArg);
}
this.addArgument(argument);
return this;
}
/**
* Define argument syntax for command, adding multiple at once (without descriptions).
*
* See also .argument().
*
* @example
* program.arguments('<cmd> [env]');
*
* @param {string} names
* @return {Command} `this` command for chaining
*/
arguments(names) {
names.trim().split(/ +/).forEach((detail) => {
this.argument(detail);
});
return this;
}
/**
* Define argument syntax for command, adding a prepared argument.
*
* @param {Argument} argument
* @return {Command} `this` command for chaining
*/
addArgument(argument) {
const previousArgument = this.registeredArguments.slice(-1)[0];
if (previousArgument?.variadic) {
throw new Error(
`only the last argument can be variadic '${previousArgument.name()}'`
);
}
if (argument.required && argument.defaultValue !== void 0 && argument.parseArg === void 0) {
throw new Error(
`a default value for a required argument is never used: '${argument.name()}'`
);
}
this.registeredArguments.push(argument);
return this;
}
/**
* Customise or override default help command. By default a help command is automatically added if your command has subcommands.
*
* @example
* program.helpCommand('help [cmd]');
* program.helpCommand('help [cmd]', 'show help');
* program.helpCommand(false); // suppress default help command
* program.helpCommand(true); // add help command even if no subcommands
*
* @param {string|boolean} enableOrNameAndArgs - enable with custom name and/or arguments, or boolean to override whether added
* @param {string} [description] - custom description
* @return {Command} `this` command for chaining
*/
helpCommand(enableOrNameAndArgs, description) {
if (typeof enableOrNameAndArgs === "boolean") {
this._addImplicitHelpCommand = enableOrNameAndArgs;
if (enableOrNameAndArgs && this._defaultCommandGroup) {
this._initCommandGroup(this._getHelpCommand());
}
return this;
}
const nameAndArgs = enableOrNameAndArgs ?? "help [command]";
const [, helpName, helpArgs] = nameAndArgs.match(/([^ ]+) *(.*)/);
const helpDescription = description ?? "display help for command";
const helpCommand = this.createCommand(helpName);
helpCommand.helpOption(false);
if (helpArgs) helpCommand.arguments(helpArgs);
if (helpDescription) helpCommand.description(helpDescription);
this._addImplicitHelpCommand = true;
this._helpCommand = helpCommand;
if (enableOrNameAndArgs || description) this._initCommandGroup(helpCommand);
return this;
}
/**
* Add prepared custom help command.
*
* @param {(Command|string|boolean)} helpCommand - custom help command, or deprecated enableOrNameAndArgs as for `.helpCommand()`
* @param {string} [deprecatedDescription] - deprecated custom description used with custom name only
* @return {Command} `this` command for chaining
*/
addHelpCommand(helpCommand, deprecatedDescription) {
if (typeof helpCommand !== "object") {
this.helpCommand(helpCommand, deprecatedDescription);
return this;
}
this._addImplicitHelpCommand = true;
this._helpCommand = helpCommand;
this._initCommandGroup(helpCommand);
return this;
}
/**
* Lazy create help command.
*
* @return {(Command|null)}
* @package
*/
_getHelpCommand() {
const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand("help"));
if (hasImplicitHelpCommand) {
if (this._helpCommand === void 0) {
this.helpCommand(void 0, void 0);
}
return this._helpCommand;
}
return null;
}
/**
* Add hook for life cycle event.
*
* @param {string} event
* @param {Function} listener
* @return {Command} `this` command for chaining
*/
hook(event, listener) {
const allowedValues = ["preSubcommand", "preAction", "postAction"];
if (!allowedValues.includes(event)) {
throw new Error(`Unexpected value for event passed to hook : '${event}'.
Expecting one of '${allowedValues.join("', '")}'`);
}
if (this._lifeCycleHooks[event]) {
this._lifeCycleHooks[event].push(listener);
} else {
this._lifeCycleHooks[event] = [listener];
}
return this;
}
/**
* Register callback to use as replacement for calling process.exit.
*
* @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing
* @return {Command} `this` command for chaining
*/
exitOverride(fn) {
if (fn) {
this._exitCallback = fn;
} else {
this._exitCallback = (err) => {
if (err.code !== "commander.executeSubCommandAsync") {
throw err;
} else {
}
};
}
return this;
}
/**
* Call process.exit, and _exitCallback if defined.
*
* @param {number} exitCode exit code for using with process.exit
* @param {string} code an id string representing the error
* @param {string} message human-readable description of the error
* @return never
* @private
*/
_exit(exitCode, code, message) {
if (this._exitCallback) {
this._exitCallback(new CommanderError(exitCode, code, message));
}
process2.exit(exitCode);
}
/**
* Register callback `fn` for the command.
*
* @example
* program
* .command('serve')
* .description('start service')
* .action(function() {
* // do work here
* });
*
* @param {Function} fn
* @return {Command} `this` command for chaining
*/
action(fn) {
const listener = (args) => {
const expectedArgsCount = this.registeredArguments.length;
const actionArgs = args.slice(0, expectedArgsCount);
if (this._storeOptionsAsProperties) {
actionArgs[expectedArgsCount] = this;
} else {
actionArgs[expectedArgsCount] = this.opts();
}
actionArgs.push(this);
return fn.apply(this, actionArgs);
};
this._actionHandler = listener;
return this;
}
/**
* Factory routine to create a new unattached option.
*
* See .option() for creating an attached option, which uses this routine to
* create the option. You can override createOption to return a custom option.
*
* @param {string} flags
* @param {string} [description]
* @return {Option} new option
*/
createOption(flags, description) {
return new Option(flags, description);
}
/**
* Wrap parseArgs to catch 'commander.invalidArgument'.
*
* @param {(Option | Argument)} target
* @param {string} value
* @param {*} previous
* @param {string} invalidArgumentMessage
* @private
*/
_callParseArg(target, value, previous, invalidArgumentMessage) {
try {
return target.parseArg(value, previous);
} catch (err) {
if (err.code === "commander.invalidArgument") {
const message = `${invalidArgumentMessage} ${err.message}`;
this.error(message, { exitCode: err.exitCode, code: err.code });
}
throw err;
}
}
/**
* Check for option flag conflicts.
* Register option if no conflicts found, or throw on conflict.
*
* @param {Option} option
* @private
*/
_registerOption(option2) {
const matchingOption = option2.short && this._findOption(option2.short) || option2.long && this._findOption(option2.long);
if (matchingOption) {
const matchingFlag = option2.long && this._findOption(option2.long) ? option2.long : option2.short;
throw new Error(`Cannot add option '${option2.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
- already used by option '${matchingOption.flags}'`);
}
this._initOptionGroup(option2);
this.options.push(option2);
}
/**
* Check for command name and alias conflicts with existing commands.
* Register command if no conflicts found, or throw on conflict.
*
* @param {Command} command
* @private
*/
_registerCommand(command) {
const knownBy = (cmd) => {
return [cmd.name()].concat(cmd.aliases());
};
const alreadyUsed = knownBy(command).find(
(name) => this._findCommand(name)
);
if (alreadyUsed) {
const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
const newCmd = knownBy(command).join("|");
throw new Error(
`cannot add command '${newCmd}' as already have command '${existingCmd}'`
);
}
this._initCommandGroup(command);
this.commands.push(command);
}
/**
* Add an option.
*
* @param {Option} option
* @return {Command} `this` command for chaining
*/
addOption(option2) {
this._registerOption(option2);
const oname = option2.name();
const name = option2.attributeName();
if (option2.defaultValue !== void 0) {
this.setOptionValueWithSource(name, option2.defaultValue, "default");
}
const handleOptionValue = (val, invalidValueMessage, valueSource) => {
if (val == null && option2.presetArg !== void 0) {
val = option2.presetArg;
}
const oldValue = this.getOptionValue(name);
if (val !== null && option2.parseArg) {
val = this._callParseArg(option2, val, oldValue, invalidValueMessage);
} else if (val !== null && option2.variadic) {
val = option2._collectValue(val, oldValue);
}
if (val == null) {
if (option2.negate) {
val = false;
} else if (option2.isBoolean() || option2.optional) {
val = true;
} else {
val = "";
}
}
this.setOptionValueWithSource(name, val, valueSource);
};
this.on("option:" + oname, (val) => {
const invalidValueMessage = `error: option '${option2.flags}' argument '${val}' is invalid.`;
handleOptionValue(val, invalidValueMessage, "cli");
});
if (option2.envVar) {
this.on("optionEnv:" + oname, (val) => {
const invalidValueMessage = `error: option '${option2.flags}' value '${val}' from env '${option2.envVar}' is invalid.`;
handleOptionValue(val, invalidValueMessage, "env");
});
}
return this;
}
/**
* Internal implementation shared by .option() and .requiredOption()
*
* @return {Command} `this` command for chaining
* @private
*/
_optionEx(config, flags, description, fn, defaultValue) {
if (typeof flags === "object" && flags instanceof Option) {
throw new Error(
"To add an Option object use addOption() instead of option() or requiredOption()"
);
}
const option2 = this.createOption(flags, description);
option2.makeOptionMandatory(!!config.mandatory);
if (typeof fn === "function") {
option2.default(defaultValue).argParser(fn);
} else if (fn instanceof RegExp) {
const regex = fn;
fn = (val, def) => {
const m = regex.exec(val);
return m ? m[0] : def;
};
option2.default(defaultValue).argParser(fn);
} else {
option2.default(fn);
}
return this.addOption(option2);
}
/**
* Define option with `flags`, `description`, and optional argument parsing function or `defaultValue` or both.
*
* The `flags` string contains the short and/or long flags, separated by comma, a pipe or space. A required
* option-argument is indicated by `<>` and an optional option-argument by `[]`.
*
* See the README for more details, and see also addOption() and requiredOption().
*
* @example
* program
* .option('-p, --pepper', 'add pepper')
* .option('--pt, --pizza-type <TYPE>', 'type of pizza') // required option-argument
* .option('-c, --cheese [CHEESE]', 'add extra cheese', 'mozzarella') // optional option-argument with default
* .option('-t, --tip <VALUE>', 'add tip to purchase cost', parseFloat) // custom parse function
*
* @param {string} flags
* @param {string} [description]
* @param {(Function|*)} [parseArg] - custom option processing function or default value
* @param {*} [defaultValue]
* @return {Command} `this` command for chaining
*/
option(flags, description, parseArg, defaultValue) {
return this._optionEx({}, flags, description, parseArg, defaultValue);
}
/**
* Add a required option which must have a value after parsing. This usually means
* the option must be specified on the command line. (Otherwise the same as .option().)
*
* The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
*
* @param {string} flags
* @param {string} [description]
* @param {(Function|*)} [parseArg] - custom option processing function or default value
* @param {*} [defaultValue]
* @return {Command} `this` command for chaining
*/
requiredOption(flags, description, parseArg, defaultValue) {
return this._optionEx(
{ mandatory: true },
flags,
description,
parseArg,
defaultValue
);
}
/**
* Alter parsing of short flags with optional values.
*
* @example
* // for `.option('-f,--flag [value]'):
* program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour
* program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
*
* @param {boolean} [combine] - if `true` or omitted, an optional value can be specified directly after the flag.
* @return {Command} `this` command for chaining
*/
combineFlagAndOptionalValue(combine = true) {
this._combineFlagAndOptionalValue = !!combine;
return this;
}
/**
* Allow unknown options on the command line.
*
* @param {boolean} [allowUnknown] - if `true` or omitted, no error will be thrown for unknown options.
* @return {Command} `this` command for chaining
*/
allowUnknownOption(allowUnknown = true) {
this._allowUnknownOption = !!allowUnknown;
return this;
}
/**
* Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
*
* @param {boolean} [allowExcess] - if `true` or omitted, no error will be thrown for excess arguments.
* @return {Command} `this` command for chaining
*/
allowExcessArguments(allowExcess = true) {
this._allowExcessArguments = !!allowExcess;
return this;
}
/**
* Enable positional options. Positional means global options are specified before subcommands which lets
* subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
* The default behaviour is non-positional and global options may appear anywhere on the command line.
*
* @param {boolean} [positional]
* @return {Command} `this` command for chaining
*/
enablePositionalOptions(positional = true) {
this._enablePositionalOptions = !!positional;
return this;
}
/**
* Pass through options that come after command-arguments rather than treat them as command-options,
* so actual command-options come before command-arguments. Turning this on for a subcommand requires
* positional options to have been enabled on the program (parent commands).
* The default behaviour is non-positional and options may appear before or after command-arguments.
*
* @param {boolean} [passThrough] for unknown options.
* @return {Command} `this` command for chaining
*/
passThroughOptions(passThrough = true) {
this._passThroughOptions = !!passThrough;
this._checkForBrokenPassThrough();
return this;
}
/**
* @private
*/
_checkForBrokenPassThrough() {
if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
throw new Error(
`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`
);
}
}
/**
* Whether to store option values as properties on command object,
* or store separately (specify false). In both cases the option values can be accessed using .opts().
*
* @param {boolean} [storeAsProperties=true]
* @return {Command} `this` command for chaining
*/
storeOptionsAsProperties(storeAsProperties = true) {
if (this.options.length) {
throw new Error("call .storeOptionsAsProperties() before adding options");
}
if (Object.keys(this._optionValues).length) {
throw new Error(
"call .storeOptionsAsProperties() before setting option values"
);
}
this._storeOptionsAsProperties = !!storeAsProperties;
return this;
}
/**
* Retrieve option value.
*
* @param {string} key
* @return {object} value
*/
getOptionValue(key) {
if (this._storeOptionsAsProperties) {
return this[key];
}
return this._optionValues[key];
}
/**
* Store option value.
*
* @param {string} key
* @param {object} value
* @return {Command} `this` command for chaining
*/
setOptionValue(key, value) {
return this.setOptionValueWithSource(key, value, void 0);
}
/**
* Store option value and where the value came from.
*
* @param {string} key
* @param {object} value
* @param {string} source - expected values are default/config/env/cli/implied
* @return {Command} `this` command for chaining
*/
setOptionValueWithSource(key, value, source) {
if (this._storeOptionsAsProperties) {
this[key] = value;
} else {
this._optionValues[key] = value;
}
this._optionValueSources[key] = source;
return this;
}
/**
* Get source of option value.
* Expected values are default | config | env | cli | implied
*
* @param {string} key
* @return {string}
*/
getOptionValueSource(key) {
return this._optionValueSources[key];
}
/**
* Get source of option value. See also .optsWithGlobals().
* Expected values are default | config | env | cli | implied
*
* @param {string} key
* @return {string}
*/
getOptionValueSourceWithGlobals(key) {
let source;
this._getCommandAndAncestors().forEach((cmd) => {
if (cmd.getOptionValueSource(key) !== void 0) {
source = cmd.getOptionValueSource(key);
}
});
return source;
}
/**
* Get user arguments from implied or explicit arguments.
* Side-effects: set _scriptPath if args included script. Used for default program name, and subcommand searches.
*
* @private
*/
_prepareUserArgs(argv, parseOptions) {
if (argv !== void 0 && !Array.isArray(argv)) {
throw new Error("first parameter to parse must be array or undefined");
}
parseOptions = parseOptions || {};
if (argv === void 0 && parseOptions.from === void 0) {
if (process2.versions?.electron) {
parseOptions.from = "electron";
}
const execArgv = process2.execArgv ?? [];
if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
parseOptions.from = "eval";
}
}
if (argv === void 0) {
argv = process2.argv;
}
this.rawArgs = argv.slice();
let userArgs;
switch (parseOptions.from) {
case void 0:
case "node":
this._scriptPath = argv[1];
userArgs = argv.slice(2);
break;
case "electron":
if (process2.defaultApp) {
this._scriptPath = argv[1];
userArgs = argv.slice(2);
} else {
userArgs = argv.slice(1);
}
break;
case "user":
userArgs = argv.slice(0);
break;
case "eval":
userArgs = argv.slice(1);
break;
default:
throw new Error(
`unexpected parse option { from: '${parseOptions.from}' }`
);
}
if (!this._name && this._scriptPath)
this.nameFromFilename(this._scriptPath);
this._name = this._name || "program";
return userArgs;
}
/**
* Parse `argv`, setting options and invoking commands when defined.
*
* Use parseAsync instead of parse if any of your action handlers are async.
*
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
*
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
* - `'user'`: just user arguments
*
* @example
* program.parse(); // parse process.argv and auto-detect electron and special node flags
* program.parse(process.argv); // assume argv[0] is app and argv[1] is script
* program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
*
* @param {string[]} [argv] - optional, defaults to process.argv
* @param {object} [parseOptions] - optionally specify style of options with from: node/user/electron
* @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
* @return {Command} `this` command for chaining
*/
parse(argv, parseOptions) {
this._prepareForParse();
const userArgs = this._prepareUserArgs(argv, parseOptions);
this._parseCommand([], userArgs);
return this;
}
/**
* Parse `argv`, setting options and invoking commands when defined.
*
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
*
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
* - `'user'`: just user arguments
*
* @example
* await program.parseAsync(); // parse process.argv and auto-detect electron and special node flags
* await program.parseAsync(process.argv); // assume argv[0] is app and argv[1] is script
* await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
*
* @param {string[]} [argv]
* @param {object} [parseOptions]
* @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
* @return {Promise}
*/
async parseAsync(argv, parseOptions) {
this._prepareForParse();
const userArgs = this._prepareUserArgs(argv, parseOptions);
await this._parseCommand([], userArgs);
return this;
}
_prepareForParse() {
if (this._savedState === null) {
this.options.filter(
(option2) => option2.negate && option2.defaultValue === void 0 && this.getOptionValue(option2.attributeName()) === void 0
).forEach((option2) => {
const positiveLongFlag = option2.long.replace(/^--no-/, "--");
if (!this._findOption(positiveLongFlag)) {
this.setOptionValueWithSource(
option2.attributeName(),
true,
"default"
);
}
});
this.saveStateBeforeParse();
} else {
this.restoreStateBeforeParse();
}
}
/**
* Called the first time parse is called to save state and allow a restore before subsequent calls to parse.
* Not usually called directly, but available for subclasses to save their custom state.
*
* This is called in a lazy way. Only commands used in parsing chain will have state saved.
*/
saveStateBeforeParse() {
this._savedState = {
// name is stable if supplied by author, but may be unspecified for root command and deduced during parsing
_name: this._name,
// option values before parse have default values (including false for negated options)
// shallow clones
_optionValues: { ...this._optionValues },
_optionValueSources: { ...this._optionValueSources }
};
}
/**
* Restore state before parse for calls after the first.
* Not usually called directly, but available for subclasses to save their custom state.
*
* This is called in a lazy way. Only commands used in parsing chain will have state restored.
*/
restoreStateBeforeParse() {
if (this._storeOptionsAsProperties)
throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
- either make a new Command for each call to parse, or stop storing options as properties`);
this._name = this._savedState._name;
this._scriptPath = null;
this.rawArgs = [];
this._optionValues = { ...this._savedState._optionValues };
this._optionValueSources = { ...this._savedState._optionValueSources };
this.args = [];
this.processedArgs = [];
}
/**
* Throw if expected executable is missing. Add lots of help for author.
*
* @param {string} executableFile
* @param {string} executableDir
* @param {string} subcommandName
*/
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
if (fs.existsSync(executableFile)) return;
const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
const executableMissing = `'${executableFile}' does not exist
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
- ${executableDirMessage}`;
throw new Error(executableMissing);
}
/**
* Execute a sub-command executable.
*
* @private
*/
_executeSubCommand(subcommand, args) {
args = args.slice();
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
function findFile(baseDir, baseName) {
const localBin = path8.resolve(baseDir, baseName);
if (fs.existsSync(localBin)) return localBin;
if (sourceExt.includes(path8.extname(baseName))) return void 0;
const foundExt = sourceExt.find(
(ext) => fs.existsSync(`${localBin}${ext}`)
);
if (foundExt) return `${localBin}${foundExt}`;
return void 0;
}
this._checkForMissingMandatoryOptions();
this._checkForConflictingOptions();
let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
let executableDir = this._executableDir || "";
if (this._scriptPath) {
let resolvedScriptPath;
try {
resolvedScriptPath = fs.realpathSync(this._scriptPath);
} catch {
resolvedScriptPath = this._scriptPath;
}
executableDir = path8.resolve(
path8.dirname(resolvedScriptPath),
executableDir
);
}
if (executableDir) {
let localFile = findFile(executableDir, executableFile);
if (!localFile && !subcommand._executableFile && this._scriptPath) {
const legacyName = path8.basename(
this._scriptPath,
path8.extname(this._scriptPath)
);
if (legacyName !== this._name) {
localFile = findFile(
executableDir,
`${legacyName}-${subcommand._name}`
);
}
}
executableFile = localFile || executableFile;
}
const launchWithNode = sourceExt.includes(path8.extname(executableFile));
let proc;
if (process2.platform !== "win32") {
if (launchWithNode) {
args.unshift(executableFile);
args = incrementNodeInspectorPort(process2.execArgv).concat(args);
proc = childProcess.spawn(process2.argv[0], args, { stdio: "inherit" });
} else {
proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
}
} else {
this._checkForMissingExecutable(
executableFile,
executableDir,
subcommand._name
);
args.unshift(executableFile);
args = incrementNodeInspectorPort(process2.execArgv).concat(args);
proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
}
if (!proc.killed) {
const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
signals.forEach((signal5) => {
process2.on(signal5, () => {
if (proc.killed === false && proc.exitCode === null) {
proc.kill(signal5);
}
});
});
}
const exitCallback = this._exitCallback;
proc.on("close", (code) => {
code = code ?? 1;
if (!exitCallback) {
process2.exit(code);
} else {
exitCallback(
new CommanderError(
code,
"commander.executeSubCommandAsync",
"(close)"
)
);
}
});
proc.on("error", (err) => {
if (err.code === "ENOENT") {
this._checkForMissingExecutable(
executableFile,
executableDir,
subcommand._name
);
} else if (err.code === "EACCES") {
throw new Error(`'${executableFile}' not executable`);
}
if (!exitCallback) {
process2.exit(1);
} else {
const wrappedError = new CommanderError(
1,
"commander.executeSubCommandAsync",
"(error)"
);
wrappedError.nestedError = err;
exitCallback(wrappedError);
}
});
this.runningCommand = proc;
}
/**
* @private
*/
_dispatchSubcommand(commandName, operands, unknown) {
const subCommand = this._findCommand(commandName);
if (!subCommand) this.help({ error: true });
subCommand._prepareForParse();
let promiseChain;
promiseChain = this._chainOrCallSubCommandHook(
promiseChain,
subCommand,
"preSubcommand"
);
promiseChain = this._chainOrCall(promiseChain, () => {
if (subCommand._executableHandler) {
this._executeSubCommand(subCommand, operands.concat(unknown));
} else {
return subCommand._parseCommand(operands, unknown);
}
});
return promiseChain;
}
/**
* Invoke help directly if possible, or dispatch if necessary.
* e.g. help foo
*
* @private
*/
_dispatchHelpCommand(subcommandName) {
if (!subcommandName) {
this.help();
}
const subCommand = this._findCommand(subcommandName);
if (subCommand && !subCommand._executableHandler) {
subCommand.help();
}
return this._dispatchSubcommand(
subcommandName,
[],
[this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? "--help"]
);
}
/**
* Check this.args against expected this.registeredArguments.
*
* @private
*/
_checkNumberOfArguments() {
this.registeredArguments.forEach((arg, i) => {
if (arg.required && this.args[i] == null) {
this.missingArgument(arg.name());
}
});
if (this.registeredArguments.length > 0 && this.registeredArguments[this.registeredArguments.length - 1].variadic) {
return;
}
if (this.args.length > this.registeredArguments.length) {
this._excessArguments(this.args);
}
}
/**
* Process this.args using this.registeredArguments and save as this.processedArgs!
*
* @private
*/
_processArguments() {
const myParseArg = (argument, value, previous) => {
let parsedValue = value;
if (value !== null && argument.parseArg) {
const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
parsedValue = this._callParseArg(
argument,
value,
previous,
invalidValueMessage
);
}
return parsedValue;
};
this._checkNumberOfArguments();
const processedArgs = [];
this.registeredArguments.forEach((declaredArg, index) => {
let value = declaredArg.defaultValue;
if (declaredArg.variadic) {
if (index < this.args.length) {
value = this.args.slice(index);
if (declaredArg.parseArg) {
value = value.reduce((processed, v) => {
return myParseArg(declaredArg, v, processed);
}, declaredArg.defaultValue);
}
} else if (value === void 0) {
value = [];
}
} else if (index < this.args.length) {
value = this.args[index];
if (declaredArg.parseArg) {
value = myParseArg(declaredArg, value, declaredArg.defaultValue);
}
}
processedArgs[index] = value;
});
this.processedArgs = processedArgs;
}
/**
* Once we have a promise we chain, but call synchronously until then.
*
* @param {(Promise|undefined)} promise
* @param {Function} fn
* @return {(Promise|undefined)}
* @private
*/
_chainOrCall(promise, fn) {
if (promise?.then && typeof promise.then === "function") {
return promise.then(() => fn());
}
return fn();
}
/**
*
* @param {(Promise|undefined)} promise
* @param {string} event
* @return {(Promise|undefined)}
* @private
*/
_chainOrCallHooks(promise, event) {
let result2 = promise;
const hooks = [];
this._getCommandAndAncestors().reverse().filter((cmd) => cmd._lifeCycleHooks[event] !== void 0).forEach((hookedCommand) => {
hookedCommand._lifeCycleHooks[event].forEach((callback) => {
hooks.push({ hookedCommand, callback });
});
});
if (event === "postAction") {
hooks.reverse();
}
hooks.forEach((hookDetail) => {
result2 = this._chainOrCall(result2, () => {
return hookDetail.callback(hookDetail.hookedCommand, this);
});
});
return result2;
}
/**
*
* @param {(Promise|undefined)} promise
* @param {Command} subCommand
* @param {string} event
* @return {(Promise|undefined)}
* @private
*/
_chainOrCallSubCommandHook(promise, subCommand, event) {
let result2 = promise;
if (this._lifeCycleHooks[event] !== void 0) {
this._lifeCycleHooks[event].forEach((hook) => {
result2 = this._chainOrCall(result2, () => {
return hook(this, subCommand);
});
});
}
return result2;
}
/**
* Process arguments in context of this command.
* Returns action result, in case it is a promise.
*
* @private
*/
_parseCommand(operands, unknown) {
const parsed = this.parseOptions(unknown);
this._parseOptionsEnv();
this._parseOptionsImplied();
operands = operands.concat(parsed.operands);
unknown = parsed.unknown;
this.args = operands.concat(unknown);
if (operands && this._findCommand(operands[0])) {
return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
}
if (this._getHelpCommand() && operands[0] === this._getHelpCommand().name()) {
return this._dispatchHelpCommand(operands[1]);
}
if (this._defaultCommandName) {
this._outputHelpIfRequested(unknown);
return this._dispatchSubcommand(
this._defaultCommandName,
operands,
unknown
);
}
if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
this.help({ error: true });
}
this._outputHelpIfRequested(parsed.unknown);
this._checkForMissingMandatoryOptions();
this._checkForConflictingOptions();
const checkForUnknownOptions = () => {
if (parsed.unknown.length > 0) {
this.unknownOption(parsed.unknown[0]);
}
};
const commandEvent = `command:${this.name()}`;
if (this._actionHandler) {
checkForUnknownOptions();
this._processArguments();
let promiseChain;
promiseChain = this._chainOrCallHooks(promiseChain, "preAction");
promiseChain = this._chainOrCall(
promiseChain,
() => this._actionHandler(this.processedArgs)
);
if (this.parent) {
promiseChain = this._chainOrCall(promiseChain, () => {
this.parent.emit(commandEvent, operands, unknown);
});
}
promiseChain = this._chainOrCallHooks(promiseChain, "postAction");
return promiseChain;
}
if (this.parent?.listenerCount(commandEvent)) {
checkForUnknownOptions();
this._processArguments();
this.parent.emit(commandEvent, operands, unknown);
} else if (operands.length) {
if (this._findCommand("*")) {
return this._dispatchSubcommand("*", operands, unknown);
}
if (this.listenerCount("command:*")) {
this.emit("command:*", operands, unknown);
} else if (this.commands.length) {
this.unknownCommand();
} else {
checkForUnknownOptions();
this._processArguments();
}
} else if (this.commands.length) {
checkForUnknownOptions();
this.help({ error: true });
} else {
checkForUnknownOptions();
this._processArguments();
}
}
/**
* Find matching command.
*
* @private
* @return {Command | undefined}
*/
_findCommand(name) {
if (!name) return void 0;
return this.commands.find(
(cmd) => cmd._name === name || cmd._aliases.includes(name)
);
}
/**
* Return an option matching `arg` if any.
*
* @param {string} arg
* @return {Option}
* @package
*/
_findOption(arg) {
return this.options.find((option2) => option2.is(arg));
}
/**
* Display an error message if a mandatory option does not have a value.
* Called after checking for help flags in leaf subcommand.
*
* @private
*/
_checkForMissingMandatoryOptions() {
this._getCommandAndAncestors().forEach((cmd) => {
cmd.options.forEach((anOption) => {
if (anOption.mandatory && cmd.getOptionValue(anOption.attributeName()) === void 0) {
cmd.missingMandatoryOptionValue(anOption);
}
});
});
}
/**
* Display an error message if conflicting options are used together in this.
*
* @private
*/
_checkForConflictingLocalOptions() {
const definedNonDefaultOptions = this.options.filter((option2) => {
const optionKey = option2.attributeName();
if (this.getOptionValue(optionKey) === void 0) {
return false;
}
return this.getOptionValueSource(optionKey) !== "default";
});
const optionsWithConflicting = definedNonDefaultOptions.filter(
(option2) => option2.conflictsWith.length > 0
);
optionsWithConflicting.forEach((option2) => {
const conflictingAndDefined = definedNonDefaultOptions.find(
(defined) => option2.conflictsWith.includes(defined.attributeName())
);
if (conflictingAndDefined) {
this._conflictingOption(option2, conflictingAndDefined);
}
});
}
/**
* Display an error message if conflicting options are used together.
* Called after checking for help flags in leaf subcommand.
*
* @private
*/
_checkForConflictingOptions() {
this._getCommandAndAncestors().forEach((cmd) => {
cmd._checkForConflictingLocalOptions();
});
}
/**
* Parse options from `argv` removing known options,
* and return argv split into operands and unknown arguments.
*
* Side effects: modifies command by storing options. Does not reset state if called again.
*
* Examples:
*
* argv => operands, unknown
* --known kkk op => [op], []
* op --known kkk => [op], []
* sub --unknown uuu op => [sub], [--unknown uuu op]
* sub -- --unknown uuu op => [sub --unknown uuu op], []
*
* @param {string[]} args
* @return {{operands: string[], unknown: string[]}}
*/
parseOptions(args) {
const operands = [];
const unknown = [];
let dest = operands;
function maybeOption(arg) {
return arg.length > 1 && arg[0] === "-";
}
const negativeNumberArg = (arg) => {
if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg)) return false;
return !this._getCommandAndAncestors().some(
(cmd) => cmd.options.map((opt) => opt.short).some((short) => /^-\d$/.test(short))
);
};
let activeVariadicOption = null;
let activeGroup = null;
let i = 0;
while (i < args.length || activeGroup) {
const arg = activeGroup ?? args[i++];
activeGroup = null;
if (arg === "--") {
if (dest === unknown) dest.push(arg);
dest.push(...args.slice(i));
break;
}
if (activeVariadicOption && (!maybeOption(arg) || negativeNumberArg(arg))) {
this.emit(`option:${activeVariadicOption.name()}`, arg);
continue;
}
activeVariadicOption = null;
if (maybeOption(arg)) {
const option2 = this._findOption(arg);
if (option2) {
if (option2.required) {
const value = args[i++];
if (value === void 0) this.optionMissingArgument(option2);
this.emit(`option:${option2.name()}`, value);
} else if (option2.optional) {
let value = null;
if (i < args.length && (!maybeOption(args[i]) || negativeNumberArg(args[i]))) {
value = args[i++];
}
this.emit(`option:${option2.name()}`, value);
} else {
this.emit(`option:${option2.name()}`);
}
activeVariadicOption = option2.variadic ? option2 : null;
continue;
}
}
if (arg.length > 2 && arg[0] === "-" && arg[1] !== "-") {
const option2 = this._findOption(`-${arg[1]}`);
if (option2) {
if (option2.required || option2.optional && this._combineFlagAndOptionalValue) {
this.emit(`option:${option2.name()}`, arg.slice(2));
} else {
this.emit(`option:${option2.name()}`);
activeGroup = `-${arg.slice(2)}`;
}
continue;
}
}
if (/^--[^=]+=/.test(arg)) {
const index = arg.indexOf("=");
const option2 = this._findOption(arg.slice(0, index));
if (option2 && (option2.required || option2.optional)) {
this.emit(`option:${option2.name()}`, arg.slice(index + 1));
continue;
}
}
if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
dest = unknown;
}
if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
if (this._findCommand(arg)) {
operands.push(arg);
unknown.push(...args.slice(i));
break;
} else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
operands.push(arg, ...args.slice(i));
break;
} else if (this._defaultCommandName) {
unknown.push(arg, ...args.slice(i));
break;
}
}
if (this._passThroughOptions) {
dest.push(arg, ...args.slice(i));
break;
}
dest.push(arg);
}
return { operands, unknown };
}
/**
* Return an object containing local option values as key-value pairs.
*
* @return {object}
*/
opts() {
if (this._storeOptionsAsProperties) {
const result2 = {};
const len = this.options.length;
for (let i = 0; i < len; i++) {
const key = this.options[i].attributeName();
result2[key] = key === this._versionOptionName ? this._version : this[key];
}
return result2;
}
return this._optionValues;
}
/**
* Return an object containing merged local and global option values as key-value pairs.
*
* @return {object}
*/
optsWithGlobals() {
return this._getCommandAndAncestors().reduce(
(combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()),
{}
);
}
/**
* Display error message and exit (or call exitOverride).
*
* @param {string} message
* @param {object} [errorOptions]
* @param {string} [errorOptions.code] - an id string representing the error
* @param {number} [errorOptions.exitCode] - used with process.exit
*/
error(message, errorOptions) {
this._outputConfiguration.outputError(
`${message}
`,
this._outputConfiguration.writeErr
);
if (typeof this._showHelpAfterError === "string") {
this._outputConfiguration.writeErr(`${this._showHelpAfterError}
`);
} else if (this._showHelpAfterError) {
this._outputConfiguration.writeErr("\n");
this.outputHelp({ error: true });
}
const config = errorOptions || {};
const exitCode = config.exitCode || 1;
const code = config.code || "commander.error";
this._exit(exitCode, code, message);
}
/**
* Apply any option related environment variables, if option does
* not have a value from cli or client code.
*
* @private
*/
_parseOptionsEnv() {
this.options.forEach((option2) => {
if (option2.envVar && option2.envVar in process2.env) {
const optionKey = option2.attributeName();
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
this.getOptionValueSource(optionKey)
)) {
if (option2.required || option2.optional) {
this.emit(`optionEnv:${option2.name()}`, process2.env[option2.envVar]);
} else {
this.emit(`optionEnv:${option2.name()}`);
}
}
}
});
}
/**
* Apply any implied option values, if option is undefined or default value.
*
* @private
*/
_parseOptionsImplied() {
const dualHelper = new DualOptions(this.options);
const hasCustomOptionValue = (optionKey) => {
return this.getOptionValue(optionKey) !== void 0 && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
};
this.options.filter(
(option2) => option2.implied !== void 0 && hasCustomOptionValue(option2.attributeName()) && dualHelper.valueFromOption(
this.getOptionValue(option2.attributeName()),
option2
)
).forEach((option2) => {
Object.keys(option2.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
this.setOptionValueWithSource(
impliedKey,
option2.implied[impliedKey],
"implied"
);
});
});
}
/**
* Argument `name` is missing.
*
* @param {string} name
* @private
*/
missingArgument(name) {
const message = `error: missing required argument '${name}'`;
this.error(message, { code: "commander.missingArgument" });
}
/**
* `Option` is missing an argument.
*
* @param {Option} option
* @private
*/
optionMissingArgument(option2) {
const message = `error: option '${option2.flags}' argument missing`;
this.error(message, { code: "commander.optionMissingArgument" });
}
/**
* `Option` does not have a value, and is a mandatory option.
*
* @param {Option} option
* @private
*/
missingMandatoryOptionValue(option2) {
const message = `error: required option '${option2.flags}' not specified`;
this.error(message, { code: "commander.missingMandatoryOptionValue" });
}
/**
* `Option` conflicts with another option.
*
* @param {Option} option
* @param {Option} conflictingOption
* @private
*/
_conflictingOption(option2, conflictingOption) {
const findBestOptionFromValue = (option3) => {
const optionKey = option3.attributeName();
const optionValue = this.getOptionValue(optionKey);
const negativeOption = this.options.find(
(target) => target.negate && optionKey === target.attributeName()
);
const positiveOption = this.options.find(
(target) => !target.negate && optionKey === target.attributeName()
);
if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
return negativeOption;
}
return positiveOption || option3;
};
const getErrorMessage = (option3) => {
const bestOption = findBestOptionFromValue(option3);
const optionKey = bestOption.attributeName();
const source = this.getOptionValueSource(optionKey);
if (source === "env") {
return `environment variable '${bestOption.envVar}'`;
}
return `option '${bestOption.flags}'`;
};
const message = `error: ${getErrorMessage(option2)} cannot be used with ${getErrorMessage(conflictingOption)}`;
this.error(message, { code: "commander.conflictingOption" });
}
/**
* Unknown option `flag`.
*
* @param {string} flag
* @private
*/
unknownOption(flag) {
if (this._allowUnknownOption) return;
let suggestion = "";
if (flag.startsWith("--") && this._showSuggestionAfterError) {
let candidateFlags = [];
let command = this;
do {
const moreFlags = command.createHelp().visibleOptions(command).filter((option2) => option2.long).map((option2) => option2.long);
candidateFlags = candidateFlags.concat(moreFlags);
command = command.parent;
} while (command && !command._enablePositionalOptions);
suggestion = suggestSimilar(flag, candidateFlags);
}
const message = `error: unknown option '${flag}'${suggestion}`;
this.error(message, { code: "commander.unknownOption" });
}
/**
* Excess arguments, more than expected.
*
* @param {string[]} receivedArgs
* @private
*/
_excessArguments(receivedArgs) {
if (this._allowExcessArguments) return;
const expected = this.registeredArguments.length;
const s = expected === 1 ? "" : "s";
const received = receivedArgs.length;
const forSubcommand = this.parent ? ` for '${this.name()}'` : "";
const details = receivedArgs.join(", ");
const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${received}: ${details}.`;
this.error(message, { code: "commander.excessArguments" });
}
/**
* Unknown command.
*
* @private
*/
unknownCommand() {
const unknownName = this.args[0];
let suggestion = "";
if (this._showSuggestionAfterError) {
const candidateNames = [];
this.createHelp().visibleCommands(this).forEach((command) => {
candidateNames.push(command.name());
if (command.alias()) candidateNames.push(command.alias());
});
suggestion = suggestSimilar(unknownName, candidateNames);
}
const message = `error: unknown command '${unknownName}'${suggestion}`;
this.error(message, { code: "commander.unknownCommand" });
}
/**
* Get or set the program version.
*
* This method auto-registers the "-V, --version" option which will print the version number.
*
* You can optionally supply the flags and description to override the defaults.
*
* @param {string} [str]
* @param {string} [flags]
* @param {string} [description]
* @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments
*/
version(str, flags, description) {
if (str === void 0) return this._version;
this._version = str;
flags = flags || "-V, --version";
description = description || "output the version number";
const versionOption = this.createOption(flags, description);
this._versionOptionName = versionOption.attributeName();
this._registerOption(versionOption);
this.on("option:" + versionOption.name(), () => {
this._outputConfiguration.writeOut(`${str}
`);
this._exit(0, "commander.version", str);
});
return this;
}
/**
* Set the description.
*
* @param {string} [str]
* @param {object} [argsDescription]
* @return {(string|Command)}
*/
description(str, argsDescription) {
if (str === void 0 && argsDescription === void 0)
return this._description;
this._description = str;
if (argsDescription) {
this._argsDescription = argsDescription;
}
return this;
}
/**
* Set the summary. Used when listed as subcommand of parent.
*
* @param {string} [str]
* @return {(string|Command)}
*/
summary(str) {
if (str === void 0) return this._summary;
this._summary = str;
return this;
}
/**
* Set an alias for the command.
*
* You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
*
* @param {string} [alias]
* @return {(string|Command)}
*/
alias(alias) {
if (alias === void 0) return this._aliases[0];
let command = this;
if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
command = this.commands[this.commands.length - 1];
}
if (alias === command._name)
throw new Error("Command alias can't be the same as its name");
const matchingCommand = this.parent?._findCommand(alias);
if (matchingCommand) {
const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
throw new Error(
`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`
);
}
command._aliases.push(alias);
return this;
}
/**
* Set aliases for the command.
*
* Only the first alias is shown in the auto-generated help.
*
* @param {string[]} [aliases]
* @return {(string[]|Command)}
*/
aliases(aliases) {
if (aliases === void 0) return this._aliases;
aliases.forEach((alias) => this.alias(alias));
return this;
}
/**
* Set / get the command usage `str`.
*
* @param {string} [str]
* @return {(string|Command)}
*/
usage(str) {
if (str === void 0) {
if (this._usage) return this._usage;
const args = this.registeredArguments.map((arg) => {
return humanReadableArgName(arg);
});
return [].concat(
this.options.length || this._helpOption !== null ? "[options]" : [],
this.commands.length ? "[command]" : [],
this.registeredArguments.length ? args : []
).join(" ");
}
this._usage = str;
return this;
}
/**
* Get or set the name of the command.
*
* @param {string} [str]
* @return {(string|Command)}
*/
name(str) {
if (str === void 0) return this._name;
this._name = str;
return this;
}
/**
* Set/get the help group heading for this subcommand in parent command's help.
*
* @param {string} [heading]
* @return {Command | string}
*/
helpGroup(heading) {
if (heading === void 0) return this._helpGroupHeading ?? "";
this._helpGroupHeading = heading;
return this;
}
/**
* Set/get the default help group heading for subcommands added to this command.
* (This does not override a group set directly on the subcommand using .helpGroup().)
*
* @example
* program.commandsGroup('Development Commands:);
* program.command('watch')...
* program.command('lint')...
* ...
*
* @param {string} [heading]
* @returns {Command | string}
*/
commandsGroup(heading) {
if (heading === void 0) return this._defaultCommandGroup ?? "";
this._defaultCommandGroup = heading;
return this;
}
/**
* Set/get the default help group heading for options added to this command.
* (This does not override a group set directly on the option using .helpGroup().)
*
* @example
* program
* .optionsGroup('Development Options:')
* .option('-d, --debug', 'output extra debugging')
* .option('-p, --profile', 'output profiling information')
*
* @param {string} [heading]
* @returns {Command | string}
*/
optionsGroup(heading) {
if (heading === void 0) return this._defaultOptionGroup ?? "";
this._defaultOptionGroup = heading;
return this;
}
/**
* @param {Option} option
* @private
*/
_initOptionGroup(option2) {
if (this._defaultOptionGroup && !option2.helpGroupHeading)
option2.helpGroup(this._defaultOptionGroup);
}
/**
* @param {Command} cmd
* @private
*/
_initCommandGroup(cmd) {
if (this._defaultCommandGroup && !cmd.helpGroup())
cmd.helpGroup(this._defaultCommandGroup);
}
/**
* Set the name of the command from script filename, such as process.argv[1],
* or import.meta.filename.
*
* (Used internally and public although not documented in README.)
*
* @example
* program.nameFromFilename(import.meta.filename);
*
* @param {string} filename
* @return {Command}
*/
nameFromFilename(filename) {
this._name = path8.basename(filename, path8.extname(filename));
return this;
}
/**
* Get or set the directory for searching for executable subcommands of this command.
*
* @example
* program.executableDir(import.meta.dirname);
* // or
* program.executableDir('subcommands');
*
* @param {string} [path]
* @return {(string|null|Command)}
*/
executableDir(path10) {
if (path10 === void 0) return this._executableDir;
this._executableDir = path10;
return this;
}
/**
* Return program help documentation.
*
* @param {{ error: boolean }} [contextOptions] - pass {error:true} to wrap for stderr instead of stdout
* @return {string}
*/
helpInformation(contextOptions) {
const helper = this.createHelp();
const context = this._getOutputContext(contextOptions);
helper.prepareContext({
error: context.error,
helpWidth: context.helpWidth,
outputHasColors: context.hasColors
});
const text2 = helper.formatHelp(this, helper);
if (context.hasColors) return text2;
return this._outputConfiguration.stripColor(text2);
}
/**
* @typedef HelpContext
* @type {object}
* @property {boolean} error
* @property {number} helpWidth
* @property {boolean} hasColors
* @property {function} write - includes stripColor if needed
*
* @returns {HelpContext}
* @private
*/
_getOutputContext(contextOptions) {
contextOptions = contextOptions || {};
const error = !!contextOptions.error;
let baseWrite;
let hasColors;
let helpWidth;
if (error) {
baseWrite = (str) => this._outputConfiguration.writeErr(str);
hasColors = this._outputConfiguration.getErrHasColors();
helpWidth = this._outputConfiguration.getErrHelpWidth();
} else {
baseWrite = (str) => this._outputConfiguration.writeOut(str);
hasColors = this._outputConfiguration.getOutHasColors();
helpWidth = this._outputConfiguration.getOutHelpWidth();
}
const write = (str) => {
if (!hasColors) str = this._outputConfiguration.stripColor(str);
return baseWrite(str);
};
return { error, write, hasColors, helpWidth };
}
/**
* Output help information for this command.
*
* Outputs built-in help, and custom text added using `.addHelpText()`.
*
* @param {{ error: boolean } | Function} [contextOptions] - pass {error:true} to write to stderr instead of stdout
*/
outputHelp(contextOptions) {
let deprecatedCallback;
if (typeof contextOptions === "function") {
deprecatedCallback = contextOptions;
contextOptions = void 0;
}
const outputContext = this._getOutputContext(contextOptions);
const eventContext = {
error: outputContext.error,
write: outputContext.write,
command: this
};
this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
this.emit("beforeHelp", eventContext);
let helpInformation = this.helpInformation({ error: outputContext.error });
if (deprecatedCallback) {
helpInformation = deprecatedCallback(helpInformation);
if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
throw new Error("outputHelp callback must return a string or a Buffer");
}
}
outputContext.write(helpInformation);
if (this._getHelpOption()?.long) {
this.emit(this._getHelpOption().long);
}
this.emit("afterHelp", eventContext);
this._getCommandAndAncestors().forEach(
(command) => command.emit("afterAllHelp", eventContext)
);
}
/**
* You can pass in flags and a description to customise the built-in help option.
* Pass in false to disable the built-in help option.
*
* @example
* program.helpOption('-?, --help' 'show help'); // customise
* program.helpOption(false); // disable
*
* @param {(string | boolean)} flags
* @param {string} [description]
* @return {Command} `this` command for chaining
*/
helpOption(flags, description) {
if (typeof flags === "boolean") {
if (flags) {
if (this._helpOption === null) this._helpOption = void 0;
if (this._defaultOptionGroup) {
this._initOptionGroup(this._getHelpOption());
}
} else {
this._helpOption = null;
}
return this;
}
this._helpOption = this.createOption(
flags ?? "-h, --help",
description ?? "display help for command"
);
if (flags || description) this._initOptionGroup(this._helpOption);
return this;
}
/**
* Lazy create help option.
* Returns null if has been disabled with .helpOption(false).
*
* @returns {(Option | null)} the help option
* @package
*/
_getHelpOption() {
if (this._helpOption === void 0) {
this.helpOption(void 0, void 0);
}
return this._helpOption;
}
/**
* Supply your own option to use for the built-in help option.
* This is an alternative to using helpOption() to customise the flags and description etc.
*
* @param {Option} option
* @return {Command} `this` command for chaining
*/
addHelpOption(option2) {
this._helpOption = option2;
this._initOptionGroup(option2);
return this;
}
/**
* Output help information and exit.
*
* Outputs built-in help, and custom text added using `.addHelpText()`.
*
* @param {{ error: boolean }} [contextOptions] - pass {error:true} to write to stderr instead of stdout
*/
help(contextOptions) {
this.outputHelp(contextOptions);
let exitCode = Number(process2.exitCode ?? 0);
if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
exitCode = 1;
}
this._exit(exitCode, "commander.help", "(outputHelp)");
}
/**
* // Do a little typing to coordinate emit and listener for the help text events.
* @typedef HelpTextEventContext
* @type {object}
* @property {boolean} error
* @property {Command} command
* @property {function} write
*/
/**
* Add additional text to be displayed with the built-in help.
*
* Position is 'before' or 'after' to affect just this command,
* and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
*
* @param {string} position - before or after built-in help
* @param {(string | Function)} text - string to add, or a function returning a string
* @return {Command} `this` command for chaining
*/
addHelpText(position, text2) {
const allowedValues = ["beforeAll", "before", "after", "afterAll"];
if (!allowedValues.includes(position)) {
throw new Error(`Unexpected value for position to addHelpText.
Expecting one of '${allowedValues.join("', '")}'`);
}
const helpEvent = `${position}Help`;
this.on(helpEvent, (context) => {
let helpStr;
if (typeof text2 === "function") {
helpStr = text2({ error: context.error, command: context.command });
} else {
helpStr = text2;
}
if (helpStr) {
context.write(`${helpStr}
`);
}
});
return this;
}
/**
* Output help information if help flags specified
*
* @param {Array} args - array of options to search for help flags
* @private
*/
_outputHelpIfRequested(args) {
const helpOption = this._getHelpOption();
const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
if (helpRequested) {
this.outputHelp();
this._exit(0, "commander.helpDisplayed", "(outputHelp)");
}
}
};
function incrementNodeInspectorPort(args) {
return args.map((arg) => {
if (!arg.startsWith("--inspect")) {
return arg;
}
let debugOption;
let debugHost = "127.0.0.1";
let debugPort = "9229";
let match;
if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
debugOption = match[1];
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
debugOption = match[1];
if (/^\d+$/.test(match[3])) {
debugPort = match[3];
} else {
debugHost = match[3];
}
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
debugOption = match[1];
debugHost = match[3];
debugPort = match[4];
}
if (debugOption && debugPort !== "0") {
return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
}
return arg;
});
}
function useColor() {
if (process2.env.NO_COLOR || process2.env.FORCE_COLOR === "0" || process2.env.FORCE_COLOR === "false")
return false;
if (process2.env.FORCE_COLOR || process2.env.CLICOLOR_FORCE !== void 0)
return true;
return void 0;
}
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/index.js
var program = new Command();
// src/core/team-config-migrate.ts
init_esm_shims();
var import_yaml4 = __toESM(require_dist(), 1);
import { execFileSync as execFileSync2 } from "child_process";
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync13, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
import { dirname as dirname12, join as join22, relative as relative2 } from "path";
var MIGRATION_DONE_LINE = "Moved your team settings to YAML files in .paqad/configs/. Review the changes and commit them together. Personal settings in .paqad/.config are unchanged.";
var MIGRATE_ONCE_LINE = "Migrate once, on the main branch, and merge it there: teammates then pull the YAML files instead of migrating again.";
var DRY_RUN_LINE = "This was a dry run, so nothing was written. Run paqad-ai config migrate to apply it.";
var NEWER_CHECKOUT_LINE = "This project was last updated by a newer paqad, so its team settings weren't moved. Update paqad-ai, then run paqad-ai config migrate.";
var NOTHING_TO_MOVE_LINE = "Nothing to move: your team settings are already in the YAML files in .paqad/configs/.";
var WORKFLOW_FILE = "feature-development/workflow.yaml";
var CHECKS_FILE = "feature-development/checks.yaml";
var LEGACY_ORDER = Object.values(CONFIG_GROUP_FILES).sort();
var GENERATED_COMMENT = /\(env: [A-Z0-9_]+\)\s*$/u;
var SECTION_HEADER = /^#\s*──/u;
var COMMENTED_KEY = /^#\s*(?:export\s+)?[a-z][a-z0-9_]*\s*=/u;
function render(value) {
return typeof value === "string" ? value : JSON.stringify(value);
}
function isRecord3(value) {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function strings(value) {
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim() !== "") : [];
}
function at(data, path10) {
let node = data;
for (const segment of path10) {
if (!isRecord3(node)) return void 0;
node = node[segment];
}
return node;
}
function sameValue(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
}
function readSetLines(text2) {
const out = [];
let pending = [];
for (const raw of text2.split(/\r?\n/u)) {
const line = raw.trim();
if (line === "") {
pending = [];
continue;
}
if (line.startsWith("#")) {
if (GENERATED_COMMENT.test(line) || SECTION_HEADER.test(line) || COMMENTED_KEY.test(line)) {
continue;
}
pending.push(line.replace(/^#\s?/u, ""));
continue;
}
const parsed = [...parseDotConfig(line)];
if (parsed.length === 1) {
const [key, value] = parsed[0];
out.push({ key, value, comments: pending });
}
pending = [];
}
return out;
}
function legacyPath(projectRoot, name) {
return join22(projectRoot, PATHS.PROJECT_CONFIGS_DIR, name);
}
function readText2(path10) {
try {
return readFileSync13(path10, "utf8");
} catch {
return null;
}
}
function teamConfigMigrationNeeded(projectRoot) {
for (const name of LEGACY_ORDER) {
const text2 = readText2(legacyPath(projectRoot, name));
if (text2 !== null && !isMigratedStub(text2) && readSetLines(text2).length > 0) return true;
}
const view = readText2(featureDevelopmentViewPath(projectRoot));
return view !== null && !isGeneratedView(view);
}
var HANDLED_WORKFLOW_PATHS = /* @__PURE__ */ new Set([
"schema_version",
"merge_mode",
"stages.checks.checks",
"stages.checks.rule_compliance.mode",
"stages.planning.escalation.attribution_pending",
"stages.documentation_sync.strictness.require_canonical_sync",
"stages.documentation_sync.escalation.stale_docs",
"stages.checks.strictness.block_on_failure"
]);
function unusedWorkflowPaths(edited, defaults, prefix = []) {
const dotted = prefix.join(".");
if (HANDLED_WORKFLOW_PATHS.has(dotted)) return [];
if (prefix.length === 3 && prefix[0] === "stages" && (prefix[2] === "read" || prefix[2] === "instructions")) {
return [];
}
if (isRecord3(edited)) {
return Object.entries(edited).flatMap(
([key, value]) => unusedWorkflowPaths(value, isRecord3(defaults) ? defaults[key] : void 0, [...prefix, key])
);
}
return sameValue(edited, defaults) ? [] : [dotted];
}
function planWorkflowCarry(edited, oldFile) {
const defaults = defaultFeatureDevelopmentPolicy();
const result2 = { carries: [], lines: [] };
const carry = (oldKey, file, path10, value) => {
result2.carries.push({ oldKey, file, path: path10, value, comments: [], oldFile });
};
const stages = isRecord3(edited) && isRecord3(edited.stages) ? edited.stages : {};
for (const stage of WORKFLOW_POLICY_STAGES) {
const raw = isRecord3(stages[stage]) ? stages[stage] : {};
const own = defaults.stages[stage];
const read = strings(raw.read).filter(
(entry) => !own.read.includes(entry) && !isShippedWorkflowEntry(stage, "read", entry)
);
if (read.length > 0) {
carry(`stages.${stage}.read`, WORKFLOW_FILE, ["stages", stage, "read"], read);
}
const instructions = strings(raw.instructions).filter(
(entry) => !own.instructions.includes(entry) && !isShippedWorkflowEntry(stage, "instructions", entry)
);
if (instructions.length > 0) {
carry(
`stages.${stage}.instructions`,
WORKFLOW_FILE,
["stages", stage, "instructions"],
instructions
);
for (const instruction of instructions) {
result2.lines.push(
`Carried this ${stage} instruction from the old workflow file; delete it from ${WORKFLOW_FILE} if it is a stale copy of paqad's own: ${instruction}`
);
}
}
}
const planning = isRecord3(stages.planning) ? stages.planning : {};
const attribution = at(planning, ["escalation", "attribution_pending"]);
if ((attribution === "defer" || attribution === "stop") && attribution !== defaults.stages.planning.escalation.attribution_pending) {
carry(
"stages.planning.escalation.attribution_pending",
WORKFLOW_FILE,
["stages", "planning", "module_attribution"],
attribution
);
}
const docs = isRecord3(stages.documentation_sync) ? stages.documentation_sync : {};
const staleEscalation = at(docs, ["escalation", "stale_docs"]);
const requireSync = at(docs, ["strictness", "require_canonical_sync"]);
if (requireSync === false || staleEscalation === "warn") {
result2.lines.push(retiredSettingLine(oldFile, "stages.documentation_sync.stale_docs"));
}
const checksStage = isRecord3(stages.checks) ? stages.checks : {};
const checks = isRecord3(checksStage.checks) ? checksStage.checks : {};
const base = defaults.stages.checks.checks;
if (checks.use_project_profile_commands !== void 0 || checks.commands !== void 0) {
const names = checks.use_project_profile_commands === false ? [] : [.../* @__PURE__ */ new Set([...base.commands, ...strings(checks.commands)])];
if (names.join(",") !== base.commands.join(",")) {
carry(
checks.use_project_profile_commands === false ? "stages.checks.checks.use_project_profile_commands" : "stages.checks.checks.commands",
CHECKS_FILE,
["commands", "from_project_profile"],
names
);
}
}
strings(checks.shell_commands).forEach((command, index) => {
carry(
"stages.checks.checks.shell_commands",
CHECKS_FILE,
["commands", "extra", `command-${index + 1}`],
command
);
});
const blockOnFailure = typeof checks.block_on_failure === "boolean" ? checks.block_on_failure : at(checksStage, ["strictness", "block_on_failure"]);
if (typeof blockOnFailure === "boolean" && blockOnFailure !== base.block_on_failure) {
carry(
typeof checks.block_on_failure === "boolean" ? "stages.checks.checks.block_on_failure" : "stages.checks.strictness.block_on_failure",
CHECKS_FILE,
["on_failure"],
blockOnFailure ? "block" : "warn"
);
}
const mode = at(checksStage, ["rule_compliance", "mode"]);
if (typeof mode === "string" && ["off", "warn", "strict"].includes(mode)) {
result2.ruleCompliance = mode;
}
for (const path10 of unusedWorkflowPaths(edited, defaults)) {
result2.lines.push(
`${path10} was set in the old workflow file but paqad never used it, so it wasn't carried over.`
);
}
return result2;
}
function pairFor(document, path10) {
const parent = path10.length === 1 ? document.contents : document.getIn(path10.slice(0, -1), true);
if (!import_yaml4.default.isMap(parent)) return void 0;
const last = path10[path10.length - 1];
return parent.items.find((pair) => {
const key = import_yaml4.default.isScalar(pair.key) ? pair.key.value : pair.key;
return key === last;
});
}
function setWithComments(document, path10, value, comments) {
document.setIn([...path10], value);
if (comments.length === 0) return;
const pair = pairFor(document, path10);
if (pair === void 0) return;
if (!import_yaml4.default.isScalar(pair.key)) pair.key = document.createNode(pair.key);
pair.key.commentBefore = comments.map((line) => ` ${line}`).join("\n");
}
function stubText(version, teamMinimum, unknown) {
const minimum = teamMinimum !== void 0 && /^\d+\.\d+\.\d+/u.test(teamMinimum) && !versionAtLeast(version, teamMinimum) ? teamMinimum : version;
return [
MIGRATED_STUB_MARKER,
"# This project's paqad settings moved to the YAML files in this folder.",
"# The lines below are for an older paqad, which can't read the YAML files: it turns itself off",
"# instead of running on its defaults. A current paqad ignores this file.",
"paqad_enable=false",
`minimum_version=${minimum}`,
...unknown.length === 0 ? [] : ["# Not carried over (not paqad settings):"],
...unknown.map((line) => `# ${line.key}=${line.value}`),
""
].join("\n");
}
function commitsText(document) {
const text2 = document.toString({ lineWidth: 0 });
return document.has("ai_attribution") ? removeAiAttributionComment(text2) : text2;
}
function commitsStampIsTrusted(projectRoot) {
return readLastApplied(projectRoot) !== null && !changedOutside(projectRoot).includes("commits.yaml");
}
function isTracked(projectRoot, relativePath) {
try {
execFileSync2("git", ["ls-files", "--error-unmatch", relativePath], {
cwd: projectRoot,
stdio: "ignore"
});
return true;
} catch {
return false;
}
}
function untrack(projectRoot, relativePath) {
try {
execFileSync2("git", ["rm", "--cached", "-q", "-f", "--", relativePath], {
cwd: projectRoot,
stdio: "ignore"
});
} catch {
}
}
function migrateTeamConfig(projectRoot, options = {}) {
const dryRun = options.dryRun === true;
const version = options.version ?? "1.128.1";
const result2 = {
ran: false,
dryRun,
lines: [],
created: [],
replaced: [],
deleted: []
};
if (!teamConfigMigrationNeeded(projectRoot)) {
result2.lines.push(NOTHING_TO_MOVE_LINE);
return result2;
}
if (checkoutIsNewer(projectRoot, version)) {
result2.lines.push(NEWER_CHECKOUT_LINE);
return result2;
}
result2.ran = true;
const rel = (path10) => relative2(projectRoot, path10).split("\\").join("/");
const legacy = [];
for (const name of LEGACY_ORDER) {
const path10 = legacyPath(projectRoot, name);
const text2 = readText2(path10);
if (text2 === null || isMigratedStub(text2)) continue;
legacy.push({ name, path: path10, lines: readSetLines(text2) });
}
const winners = /* @__PURE__ */ new Map();
const seenIn = /* @__PURE__ */ new Map();
for (const file of legacy) {
for (const line of file.lines) {
winners.set(line.key, { line, file: file.name });
seenIn.set(line.key, [...seenIn.get(line.key) ?? [], file.name]);
}
}
for (const [key, files] of seenIn) {
const unique = [...new Set(files)];
if (unique.length < 2) continue;
const kept = winners.get(key);
result2.lines.push(
`${key} was set in ${unique[unique.length - 2]} and ${unique[unique.length - 1]}; kept ${kept.line.value} from ${unique[unique.length - 1]}.`
);
}
const carries = [];
const unknown = [];
for (const [key, { line, file }] of winners) {
const spec = FRAMEWORK_CONFIG_SPECS.find((row) => row.key === key);
if (isRetiredSettingKey(key)) {
result2.lines.push(retiredSettingLine(`${PATHS.PROJECT_CONFIGS_DIR}/${file}`, key));
continue;
}
if (spec === void 0) {
unknown.push(line);
result2.lines.push(
`${key}=${line.value} in ${file} isn't a paqad setting, so it wasn't carried over.`
);
continue;
}
carries.push({
oldKey: key,
file: spec.file,
path: spec.path,
value: toYamlValue(spec, line.value),
comments: line.comments,
oldFile: file
});
}
const viewPath = featureDevelopmentViewPath(projectRoot);
const viewText = readText2(viewPath);
const legacyWorkflow = viewText !== null && !isGeneratedView(viewText) ? viewText : null;
let workflowReadable = true;
if (legacyWorkflow !== null) {
let edited;
try {
edited = import_yaml4.default.parse(legacyWorkflow);
} catch (error) {
workflowReadable = false;
result2.lines.push(
`Couldn't read ${FEATURE_DEVELOPMENT_VIEW_RELATIVE}, so it was kept and none of its settings were carried over: ${error instanceof Error ? error.message.split("\n")[0] : String(error)}`
);
}
if (workflowReadable) {
const workflow = planWorkflowCarry(edited, FEATURE_DEVELOPMENT_VIEW_RELATIVE);
result2.lines.push(...workflow.lines);
for (const carry of workflow.carries) {
const same = carries.findIndex(
(entry) => entry.file === carry.file && entry.path.join(".") === carry.path.join(".")
);
if (same === -1) carries.push(carry);
}
if (workflow.ruleCompliance !== void 0) {
const spec = FRAMEWORK_CONFIG_SPECS.find((row) => row.key === "rule_compliance");
const existing = carries.findIndex((entry) => entry.oldKey === "rule_compliance");
if (existing !== -1) {
result2.lines.push(
`rule_compliance was also set in the workflow file; kept ${workflow.ruleCompliance} from there.`
);
carries.splice(existing, 1);
}
carries.push({
oldKey: "stages.checks.rule_compliance.mode",
file: spec.file,
path: spec.path,
value: toYamlValue(spec, workflow.ruleCompliance),
comments: [],
oldFile: FEATURE_DEVELOPMENT_VIEW_RELATIVE
});
}
}
}
const documents = /* @__PURE__ */ new Map();
const documentFor = (file) => {
const known = documents.get(file);
if (known !== void 0) return known.document;
const existing = readText2(teamConfigPath(projectRoot, file));
const parsed = existing === null ? {
document: import_yaml4.default.parseDocument(`schema_version: ${TEAM_FILE_SCHEMA_VERSION}
`),
error: void 0
} : parseTeamConfigText(file, existing);
const document = parsed.document;
if (document === null || parsed.error !== void 0) {
throw new Error(
`${file} isn't valid YAML, so the settings for it weren't moved: ${parsed.error}`
);
}
if (document.contents !== null && !import_yaml4.default.isMap(document.contents)) {
throw new Error(
`${file} holds a list or a single value instead of settings, so the settings for it weren't moved.`
);
}
documents.set(file, { document, existed: existing !== null });
return document;
};
const summary = [];
try {
for (const carry of carries) {
const document = documentFor(carry.file);
const current = document.getIn([...carry.path]);
const plain = import_yaml4.default.isNode(current) ? current.toJSON() : current;
if (plain !== void 0 && plain !== null) {
if (!sameValue(plain, carry.value)) {
result2.lines.push(
`${carry.oldKey} is set in both ${carry.oldFile} and ${carry.file}; kept the YAML value ${render(plain)}.`
);
}
continue;
}
setWithComments(document, carry.path, carry.value, carry.comments);
summary.push(
`${carry.oldKey} \u2192 ${carry.file}: ${carry.path.join(".")} = ${render(carry.value)}`
);
}
} catch (error) {
result2.error = error instanceof Error ? error.message : String(error);
result2.lines.push(result2.error);
return result2;
}
result2.lines.push(...summary);
const active = options.activeChange === void 0 ? peekActiveChangeKey(projectRoot) : options.activeChange;
if (active !== null) {
result2.lines.push(
`The change ${active} is part-way through its stages. Its settings moved now, so its remaining stages read the YAML files.`
);
}
const blockedLines = [...documents.keys()].flatMap((file) => {
const text2 = readText2(teamConfigPath(projectRoot, file)) ?? "";
const shown = `${PATHS.PROJECT_CONFIGS_DIR}/${file}`;
if (file === GIT_WORKFLOW_COMMITS_FILE) {
return isNewerTeamFile(text2) ? [newerTeamFileLine(shown)] : [];
}
const blocked = renderWriteBlock(text2, shown);
return blocked === null ? [] : [blocked];
});
if (blockedLines.length > 0) {
const lines = blockedLines;
result2.lines = lines;
result2.error = lines.join(" ");
return result2;
}
const teamMinimum = winners.get("minimum_version")?.line.value;
const stub = stubText(version, teamMinimum, unknown);
const stubPath = legacyPath(projectRoot, CONFIG_GROUP_FILES.app);
const writes = [];
for (const [file, { document, existed }] of documents) {
writes.push({
path: teamConfigPath(projectRoot, file),
text: file === GIT_WORKFLOW_COMMITS_FILE ? commitsText(document) : renderTeamConfigFile(file, document),
existed
});
}
for (const file of TEAM_CONFIG_FILES) {
const path10 = teamConfigPath(projectRoot, file);
if (documents.has(file) || existsSync11(path10)) continue;
writes.push({ path: path10, text: renderTeamConfigFile(file, null), existed: false });
}
const stubWrite = { path: stubPath, text: stub, existed: existsSync11(stubPath) };
for (const write of [...writes, stubWrite]) {
(write.existed ? result2.replaced : result2.created).push(rel(write.path));
}
const deleteView = legacyWorkflow !== null && workflowReadable;
const toDelete = legacy.filter((file) => file.name !== CONFIG_GROUP_FILES.app).map((file) => file.path);
result2.deleted.push(...toDelete.map(rel));
if (deleteView) result2.deleted.push(FEATURE_DEVELOPMENT_VIEW_RELATIVE);
if (!dryRun) {
const stampCommits = documents.has(GIT_WORKFLOW_COMMITS_FILE) && commitsStampIsTrusted(projectRoot);
try {
for (const write of writes) {
mkdirSync3(dirname12(write.path), { recursive: true });
writeFileSync4(write.path, write.text, "utf8");
}
if (deleteView) {
const tracked = isTracked(projectRoot, FEATURE_DEVELOPMENT_VIEW_RELATIVE);
rmSync3(viewPath, { force: true });
if (tracked) untrack(projectRoot, FEATURE_DEVELOPMENT_VIEW_RELATIVE);
}
writeFileSync4(stubWrite.path, stubWrite.text, "utf8");
} catch (error) {
result2.error = `Couldn't write the new settings files, so the old ones were kept: ${error instanceof Error ? error.message : String(error)}`;
result2.lines.push(result2.error);
return result2;
}
for (const path10 of toDelete) rmSync3(path10, { force: true });
if (stampCommits) stampLastApplied(projectRoot, ["commits.yaml"], { version });
}
for (const path10 of result2.created) result2.lines.push(`Created ${path10}`);
for (const path10 of result2.replaced) result2.lines.push(`Replaced ${path10}`);
for (const path10 of result2.deleted) result2.lines.push(`Deleted ${path10}`);
result2.lines.push(MIGRATE_ONCE_LINE);
result2.lines.push(dryRun ? DRY_RUN_LINE : MIGRATION_DONE_LINE);
return result2;
}
// src/cli/commands/config-show.ts
init_esm_shims();
import { isDeepStrictEqual } from "util";
import { join as join23, relative as relative3 } from "path";
// src/verification/repository/bundle-completeness-mode.ts
init_esm_shims();
var BUNDLE_COMPLETENESS_MODES = ["off", "warn", "strict"];
var DEFAULT_BUNDLE_COMPLETENESS_MODE = "strict";
function resolveBundleCompletenessMode(projectRoot, env2 = process.env) {
return resolveFlooredMode(
{
team: readConfigsDir(projectRoot).merged.get("bundle_completeness"),
local: readDotConfig(projectRoot).get("bundle_completeness"),
env: envConfigValue(env2, "bundle_completeness")
},
BUNDLE_COMPLETENESS_MODES,
DEFAULT_BUNDLE_COMPLETENESS_MODE
);
}
// src/verification/repository/visual-evidence-mode.ts
init_esm_shims();
var VISUAL_EVIDENCE_MODES = ["warn", "strict"];
var DEFAULT_VISUAL_EVIDENCE_MODE = "warn";
function resolveVisualEvidenceMode(projectRoot, env2 = process.env) {
return resolveFlooredMode(
{
team: readConfigsDir(projectRoot).merged.get("visual_evidence_mode"),
local: readDotConfig(projectRoot).get("visual_evidence_mode"),
env: envConfigValue(env2, "visual_evidence_mode")
},
VISUAL_EVIDENCE_MODES,
DEFAULT_VISUAL_EVIDENCE_MODE
);
}
// src/checks/flaky-mode.ts
init_esm_shims();
var CHECKS_FLAKY_MODES = ["pass", "warn", "fail"];
var DEFAULT_CHECKS_FLAKY_MODE = "warn";
function resolveChecksFlakyMode(projectRoot, env2 = process.env) {
return resolveFlooredMode(
{
team: readConfigsDir(projectRoot).merged.get("checks_flaky_under_parallel"),
local: readDotConfig(projectRoot).get("checks_flaky_under_parallel"),
env: envConfigValue(env2, "checks_flaky_under_parallel")
},
CHECKS_FLAKY_MODES,
DEFAULT_CHECKS_FLAKY_MODE
);
}
// src/mutation/mode.ts
init_esm_shims();
var MUTATION_MODES = ["off", "warn", "strict"];
var DEFAULT_MUTATION_MODE = "off";
function resolveMutationMode(projectRoot, env2 = process.env) {
return resolveFlooredMode(
{
team: readConfigsDir(projectRoot).merged.get("mutation_mode"),
local: readDotConfig(projectRoot).get("mutation_mode"),
env: envConfigValue(env2, "mutation_mode")
},
MUTATION_MODES,
DEFAULT_MUTATION_MODE
);
}
// src/cli/commands/config-show.ts
var FLOORED = {
rule_compliance: resolveRuleComplianceMode,
stages_mode: resolveStagesMode,
bundle_completeness: resolveBundleCompletenessMode,
visual_evidence_mode: resolveVisualEvidenceMode,
checks_flaky_under_parallel: resolveChecksFlakyMode,
mutation_mode: resolveMutationMode,
ai_attribution: resolveAiAttributionMode
};
function personalIssue(spec, where, raw) {
const reason2 = checkYamlValue(spec, toYamlValue(spec, raw));
if (reason2 === null) return null;
const def = spec.default === void 0 ? "(unset)" : String(spec.default);
return `${where}: ${spec.key} has an invalid value ${raw}, so paqad uses the default ${def}. ${reason2}`;
}
function buildConfigShow(projectRoot, env2 = process.env) {
const team = readTeamConfig(projectRoot);
const personal = readDotConfig(projectRoot);
const layered = layeredConfigMap(projectRoot, env2);
const configsDir = join23(projectRoot, PATHS.PROJECT_CONFIGS_DIR);
const invalid2 = team.issues.map((issue) => issue.message);
const settings = FRAMEWORK_CONFIG_SPECS.map((spec) => {
const envRaw = envConfigValue(env2, spec.key);
let source = "default";
if (envRaw !== void 0 && envRaw.trim() !== "") {
source = `env: ${spec.env}`;
const issue = personalIssue(spec, `env ${spec.env}`, envRaw);
if (issue !== null) invalid2.push(issue);
} else if (personal.has(spec.key)) {
source = `personal: ${PATHS.PROJECT_CONFIG} (${spec.key})`;
const issue = personalIssue(spec, PATHS.PROJECT_CONFIG, personal.get(spec.key));
if (issue !== null) invalid2.push(issue);
} else if (team.merged.has(spec.key)) {
source = `team: ${toPosixPath(relative3(configsDir, team.sources.get(spec.key)))}`;
}
const floored = FLOORED[spec.key];
const legacy = floored !== void 0 ? floored(projectRoot, env2) : layered.get(spec.key) ?? (spec.default === void 0 ? void 0 : String(spec.default));
const value = legacy === void 0 ? null : toYamlValue(spec, legacy);
const def = yamlDefault(spec) ?? null;
return {
file: spec.file,
path: spec.path.join("."),
key: spec.key,
value,
source,
same_as_default: isDeepStrictEqual(value, def)
};
});
return { settings, invalid: invalid2 };
}
function renderValue(value) {
if (value === null) return "(unset)";
if (Array.isArray(value)) return `[${value.join(", ")}]`;
return String(value);
}
function renderConfigShow(result2, changedOnly = false) {
const rows = result2.settings.filter((row) => !changedOnly || !row.same_as_default);
const where = rows.map((row) => `${row.file}: ${row.path}`);
const width = Math.max(0, ...where.map((text2) => text2.length));
const lines = rows.map((row, index) => {
const note = row.same_as_default ? ", same as default" : "";
return `${where[index].padEnd(width)} ${renderValue(row.value)} (${row.source}${note})`;
});
if (result2.invalid.length > 0) {
lines.push("", "Invalid values:", ...result2.invalid.map((message) => `- ${message}`));
}
return lines.join("\n");
}
// src/cli/commands/config.ts
var NOTHING = "NOTHING";
var KNOB_CONSUMERS = {
paqad_enable: "enablement gate (bootstrap + every hook)",
auto_update: "silent background update",
minimum_version: "silent update (version floor)",
version_check_interval_hours: "background version check",
enterprise: "enterprise policy (ledger/receipt master switch)",
enterprise_evidence_ledger: "evidence ledger writer",
enterprise_ai_bom: "AI-BOM projector",
enterprise_compliance_citations: "compliance-citation resolver",
spec_only_mode: "onboarding orchestrator (planning)",
market_research: "market-research agent (planning)",
design_research: "design-research agent (planning)",
team_agents: "full-lane team routing",
analytics_instrumentation: "analytics gate + classifier",
site_map: "site-map engine + workflow",
rules_discovery_private_packages: "rules discovery (packages never researched on the web)",
visual_evidence: "visual-evidence capture (frontend trigger + gate + CLI)",
visual_evidence_mode: "visual-evidence gate (end-of-change enforcement)",
lean_rules: "context seam (rule injection)",
rag_enabled: "context seam / retrieval",
rag_embedding_provider: "RAG embedding provider",
rag_embedding_model: "RAG embedding model",
rag_similarity_threshold: "RAG hybrid scoring",
rag_top_n: "RAG retrieval depth",
rag_max_file_size: "RAG index build",
rag_base_branch: "branch-aware RAG index",
existing_surface_tokens: "existing-surface planning digest",
model_default: "model selection (skills/model-selector)",
model_reasoning: "model routing (budget optimizer)",
model_fast: "model routing (budget optimizer)",
decisions_ask_threshold: "askThresholdForProject (decision resolver)",
stages_mode: "stages capability gate (pre-code block)",
rule_compliance: "rule-scripts capability gate",
rule_gate_pre_edit: "rule-scripts capability gate (scripts run before an edit)",
rule_gate_concurrency: "rule-scripts capability gate (scripts run at once)",
rule_gate_budget_ms: "rule-scripts capability gate (pre-edit time budget)",
analytics_strictness: "analytics AC-track gate",
mutation_mode: "mutation-testing gate (ci-backstop and git-backstop only)",
bundle_completeness: "bundle-completeness gate (end-of-change)",
evidence_existence_gate: "evidence-existence gate (deprecated; runs only when bundle_completeness=off)",
spec_pipeline_enabled: "spec pipeline (spec pipeline command)",
spec_pipeline_clarification: "spec pipeline (question-round gate)",
spec_pipeline_final_review: "spec pipeline (finish gate)",
spec_pipeline_token_ceiling: "spec pipeline (per-run token ceiling)",
spec_pipeline_experts_enabled: "spec pipeline (expert roster, the High Table)",
spec_pipeline_adoption: "spec freeze (strict adoption) + bundle-completeness gate",
spec_pipeline_standing_experts: "spec pipeline (standing experts at every spec)",
spec_pipeline_experts_lanes: "spec pipeline (lanes where the standing experts sit)",
stage_isolation_lanes: "stage isolation (bundle-completeness gate + HUD isolation flag)",
checks_parallel: "checks stage (scheduler + parallel test plan)",
checks_max_processes: "checks stage (parallel process cap)",
checks_flaky_under_parallel: "checks isolated-re-run verdict (pass-alone policy)",
skill_orchestrator_enabled: "skill orchestrator (High Table seat, lane raise, skill pipeline, completion check)",
authoring_trigger_threshold: "skill pipeline S6 trigger gate (validation pass rate)",
authoring_trigger_min_runs: "skill pipeline S6 trigger gate (fires per query)",
skill_eval_min_gain_points: "skill pipeline S5 eval gate (gain over baseline)",
skill_eval_max_token_multiple: "skill pipeline S5 eval gate (token budget)",
authoring_runs_per_arm: "skill pipeline S5 eval plan (runs per arm)",
authoring_max_iterations: "skill pipeline S5 revision loop (iteration cap)",
authoring_fact_max_age_days: "skill drift + skill release (fact freshness)",
authoring_collision_jaccard: "skill overlap check (collision threshold)",
authoring_description_budget_chars: "skill overlap check (catalog description budget)",
skill_body_max_tokens: "skill lint SK-008 (body token limit)",
authoring_tool_result_max_tokens: "skill pipeline S5 analyst (oversize tool results)",
authoring_cache_hit_min: "skill pipeline S5 analyst (cache-hit defect)",
authoring_regression_tolerance: "skill pipeline S5 improve-mode gate + S8 regression gate",
authoring_dark_window_days: "skill catalog (dark skills) + activation log bound",
authoring_batch_mode: "skill pipeline S6 trigger plan (batch sweep)",
authoring_run_max_cost_usd: "skill pipeline S5/S6 plans (--max-cost-usd spend cap)",
authoring_otel_endpoint: "skill pipeline usage reader (OpenTelemetry source)",
agent_orchestrator_enabled: "agent orchestrator (High Table seat, lane raise, agent pipeline, completion check)",
agent_pass_k_threshold: "agent pipeline S5 eval gate (pass^3 threshold)",
agent_stage_pass_k_threshold: "agent pipeline S5 eval gate (pass^3 threshold for stage agents)",
agent_delegation_threshold: "agent pipeline S6 delegation gate (validation pass rate)",
agent_description_max_tokens: "agent lint AG-003 (description token limit)",
agent_report_max_tokens: "agent pipeline S5 grader (report length limit)",
agent_prompt_max_tokens: "agent lint AG-014 (body token limit)",
agent_max_tools: "agent lint AG-018 (tool count limit)",
agent_max_cost_multiple: "agent pipeline S5 eval gate (cost budget)",
agent_catalog_description_max_tokens: "agent lint AG-004 (catalog description budget)",
agent_memory_max_lines: "agent lint AG-010 + agent memory-consolidate (memory size)",
team_bootstrap_enabled: "resolveTeamBootstrapEnabled (team setup) + team launcher",
feature_report: "featureReportEnabled (feature report)",
metrics_enabled: "runRepositoryVerification (change metrics)",
hud_view: "isHudViewOff (plugin HUD band)",
hud_chime: "isChimeOn (plugin HUD chime)",
plugin_migration: "resolvePluginMigrationConfig (background move to the plugin)",
claude_install_mode: "resolvePluginMigrationConfig (how Claude Code installs paqad)",
rag_relief_floor: "RagService (RAG relief floor)",
...Object.fromEntries(
STAGE_SETTING_STAGES.flatMap((stage) => [
[`stage_effort_${stage}`, "resolveStageAgentSettings (stage agent effort)"],
[`stage_model_${stage}`, "resolveStageAgentSettings (stage agent model)"]
])
),
duplication_mode: "resolveDuplicationMode (duplication gate)",
duplication_similarity_threshold: "resolveDuplicationConfig (duplication gate)",
duplication_min_lines: "resolveDuplicationConfig (duplication gate)",
decision_arm_mode: "resolveDecisionArmMode (create-vs-reuse pause)",
decision_arm_plan_threshold: "resolveDecisionArmConfig (create-vs-reuse pause)",
decision_arm_max_per_change: "resolveDecisionArmConfig (create-vs-reuse pause)",
ai_attribution: "resolveAiAttributionMode (delivery attribution)",
spec_grounding_budget_ms: "readPipelineConfig (spec pipeline grounding budget)"
};
function resolveEffectiveConfig(projectRoot, env2 = process.env) {
const localMap = readDotConfig(projectRoot);
const team = readConfigsDir(projectRoot);
const teamMap = team.merged;
return FRAMEWORK_CONFIG_SPECS.map((spec) => {
const envVal = env2[spec.env];
let value;
let surface2;
if (envVal !== void 0 && envVal.trim() !== "") {
value = envVal;
surface2 = `env:${spec.env}`;
} else if (localMap.has(spec.key)) {
value = localMap.get(spec.key) ?? "";
surface2 = "local .paqad/.config";
} else if (teamMap.has(spec.key)) {
value = teamMap.get(spec.key) ?? "";
surface2 = `team configs/${relative4(join24(projectRoot, PATHS.PROJECT_CONFIGS_DIR), team.sources.get(spec.key))}`;
} else {
value = spec.default === void 0 ? "(unset)" : String(spec.default);
surface2 = "default";
}
if (spec.key === "rule_compliance") {
value = resolveRuleComplianceMode(projectRoot, env2);
surface2 = `${surface2} \u2192 floored`;
} else if (spec.key === "stages_mode") {
value = resolveStagesMode(projectRoot, env2);
surface2 = `${surface2} \u2192 floored`;
} else if (spec.key === "bundle_completeness") {
value = resolveBundleCompletenessMode(projectRoot, env2);
surface2 = `${surface2} \u2192 floored`;
} else if (spec.key === "visual_evidence_mode") {
value = resolveVisualEvidenceMode(projectRoot, env2);
surface2 = `${surface2} \u2192 floored`;
} else if (spec.key === "checks_flaky_under_parallel") {
value = resolveChecksFlakyMode(projectRoot, env2);
surface2 = `${surface2} \u2192 floored`;
} else if (spec.key === "mutation_mode") {
value = resolveMutationMode(projectRoot, env2);
surface2 = `${surface2} \u2192 floored`;
}
return { key: spec.key, value, surface: surface2, consumed_by: KNOB_CONSUMERS[spec.key] ?? NOTHING };
});
}
function createConfigCommand() {
const command = new Command("config").description("Inspect the framework configuration");
command.command("effective").description(
"Print, per knob, the value that actually binds, its source surface, and the gate that consumes it (consumed by: NOTHING flags a placebo). Read-only."
).option("--project-root <path>", "Project root", process.cwd()).option("--json", "emit machine-readable JSON").action((options) => {
const knobs = resolveEffectiveConfig(options.projectRoot);
if (options.json) {
console.log(JSON.stringify({ knobs }, null, 2));
return;
}
const keyWidth = Math.max(...knobs.map((knob) => knob.key.length));
const valWidth = Math.max(...knobs.map((knob) => knob.value.length), 5);
for (const knob of knobs) {
console.log(
`${knob.key.padEnd(keyWidth)} ${knob.value.padEnd(valWidth)} [${knob.surface}] consumed by: ${knob.consumed_by}`
);
}
const placebos = knobs.filter((knob) => knob.consumed_by === NOTHING).length;
console.log(
`
${knobs.length} knobs \xB7 ${placebos} with no consumer (placebo \u2014 no running code reads them).`
);
});
command.command("show").description(
"Print every setting: its YAML file and path, the value that applies, where it comes from, and whether it is the default. Read-only."
).option("--project-root <path>", "Project root", process.cwd()).option("--json", "emit machine-readable JSON").option("--changed", "hide settings that equal the default").action((options) => {
const result2 = buildConfigShow(options.projectRoot);
if (options.json) {
const settings = options.changed ? result2.settings.filter((row) => !row.same_as_default) : result2.settings;
console.log(JSON.stringify({ settings, invalid: result2.invalid }, null, 2));
return;
}
console.log(renderConfigShow(result2, options.changed === true));
});
command.command("migrate").description(
"Move the team settings from the old .paqad/configs/.config.* files and the old feature-development workflow file into the YAML files in .paqad/configs/."
).option("--project-root <path>", "Project root", process.cwd()).option("--dry-run", "print what would move without writing anything").action((options) => {
const migration = migrateTeamConfig(options.projectRoot, { dryRun: options.dryRun === true });
for (const line of migration.lines) console.log(line);
if (migration.error !== void 0) process.exitCode = 1;
});
return command;
}
// src/spec-pipeline/parser-parity.ts
init_esm_shims();
var RECOGNIZED_HEADINGS = [
"summary",
"functional requirements",
"non-functional requirements",
"acceptance criteria",
"edge cases",
"invariants",
"non-goals",
"open questions"
];
function normalizeHeading(text2) {
return text2.trim().toLowerCase().replace(/\s+/g, " ");
}
function checkSpecShape(markdown) {
const problems = [];
for (const line of markdown.split(/\r?\n/)) {
const heading = /^(#{2,6})\s+(.*\S)\s*$/.exec(line);
if (!heading) continue;
const text2 = normalizeHeading(heading[2]);
if (!RECOGNIZED_HEADINGS.includes(text2)) {
problems.push(
`unrecognized heading "${heading[2].trim()}" \u2014 recognized: ${RECOGNIZED_HEADINGS.join(", ")}`
);
}
}
if (/(^|\s)AC-\d+\.\d+/m.test(markdown)) {
problems.push("dotted AC-N.N criterion id \u2014 the freeze parser reads flat AC-N only");
}
const spec = buildFeatureSpec({
spec_id: "S-shape-check",
spec_file: "spec.md",
spec_markdown: markdown
});
if (spec.behaviour.length === 0) {
problems.push("no behaviour \u2014 needs a ## Functional requirements section (FR-n / NFR-n)");
}
if (spec.acceptance_criteria.length === 0) {
problems.push("no acceptance criteria \u2014 needs a ## Acceptance criteria section (AC-n)");
}
for (const criterion of spec.acceptance_criteria) {
if (!criterion.proof_type) {
problems.push(`criterion ${criterion.criterion_id} has no proof type (add "(proof: \u2026)")`);
}
if (criterion.then.trim().length === 0) {
problems.push(`criterion ${criterion.criterion_id} has no observable "then" clause`);
}
}
return { ok: problems.length === 0, problems };
}
var PARITY_CORPUS = [
{
name: "minimal flat spec",
markdown: [
"## Functional requirements",
"FR-1: the export excludes hidden columns.",
"## Acceptance criteria",
"- AC-1: Given an admin, when they export, then hidden columns are omitted (proof: automated).",
"## Invariants",
"- INV-1: an export never includes a hidden column."
].join("\n")
},
{
name: "multi-criterion with non-goals and NFR",
markdown: [
"## Summary",
"Cleaner report export.",
"## Functional requirements",
"FR-1: the export excludes hidden columns.",
"## Non-functional requirements",
"NFR-1: an export of 10k rows completes within 5 seconds.",
"## Acceptance criteria",
"- AC-1: Given an admin, when they export, then hidden columns are omitted (proof: automated).",
"- AC-2: Given a large report, when they export, then it completes under 5s (proof: manual).",
"## Non-goals",
"- does not change the import path",
"## Invariants",
"- INV-1: an export never includes a hidden column."
].join("\n")
},
{
name: "negative-path AC with edge-case-detection non-goals",
markdown: [
"## Summary",
"Bulk archive of selected records.",
"## Functional requirements",
"FR-1: an editor can archive the records they selected.",
"## Acceptance criteria",
"- AC-1: Given selected records, when an editor archives them, then each is marked archived (proof: automated).",
"- AC-2: Given an empty selection, when the editor triggers archive, then the action is rejected with a validation message and nothing is archived (proof: automated).",
"- AC-3: Given a viewer without archive permission, when they trigger archive, then the request is denied and no record changes (proof: automated).",
"## Non-goals",
"- does not archive records the editor did not select",
"- does not add an undo path for an archive",
"## Invariants",
"- INV-1: an archive never touches a record outside the current selection."
].join("\n")
}
];
// src/health/git-workflow-check.ts
init_esm_shims();
import { existsSync as existsSync14 } from "fs";
import { join as join27 } from "path";
// src/feature-evidence/git-hooks.ts
init_esm_shims();
import {
chmodSync,
existsSync as existsSync12,
mkdirSync as mkdirSync4,
readFileSync as readFileSync14,
rmSync as rmSync4,
statSync as statSync3,
writeFileSync as writeFileSync5
} from "fs";
import { execFileSync as execFileSync3 } from "child_process";
import { basename as basename3, dirname as dirname13, isAbsolute, join as join25, relative as relative5, resolve, sep } from "path";
var GIT_HOOK_MARKER = "# paqad-ai delivery-link";
var GIT_WORKFLOW_HOOK_MARKER = "# paqad-ai git-workflow";
var WORKFLOW_HOOKS = [
{
name: "commit-msg",
line: 'if command -v paqad-ai >/dev/null 2>&1; then paqad-ai git-workflow check-commit "$1" || exit 1; fi',
runs: /paqad-ai git-workflow check-commit\s+"?\$1"?/u
},
{
name: "pre-push",
line: "if command -v paqad-ai >/dev/null 2>&1; then paqad-ai git-workflow check-push || exit 1; fi",
runs: /paqad-ai git-workflow check-push/u
}
];
var HUSKY_RUNNER_DIR = "_";
var HUSKY_RUNNER_FILE = "h";
var PATH_LIMIT_LINE = "The check is skipped in a terminal where paqad-ai is not on the PATH.";
var WORKFLOW_HOOK_NAMES = WORKFLOW_HOOKS.map((hook) => hook.name);
function workflowHookBlock(name) {
const hook = WORKFLOW_HOOKS.find((entry) => entry.name === name);
return `${GIT_WORKFLOW_HOOK_MARKER}
${hook?.line ?? ""}`;
}
function distCliPath() {
return toPosixPath(join25(getPackageRoot(), "dist", "cli", "index.js"));
}
var HOOKS = [
{ name: "post-commit", verb: "commit" },
{ name: "post-merge", verb: "merge" }
];
function hooksDirIsTracked(projectRoot, dir) {
const gitDir = git(projectRoot, ["rev-parse", "--absolute-git-dir"]);
if (gitDir) {
const resolvedGitDir = resolve(gitDir);
const resolvedDir = resolve(dir);
if (resolvedDir === resolvedGitDir || resolvedDir.startsWith(resolvedGitDir + sep)) {
return false;
}
}
const rel = relative5(projectRoot, dir).replace(/\\/g, "/");
if (rel === "" || rel.startsWith("..")) {
return false;
}
const listed = git(projectRoot, ["ls-files", "--", rel]);
return listed !== void 0 && listed.length > 0;
}
function git(projectRoot, args) {
try {
return execFileSync3("git", args, {
cwd: projectRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"]
}).trim();
} catch {
return void 0;
}
}
function resolveHooksDir(projectRoot) {
const rel = git(projectRoot, ["rev-parse", "--git-path", "hooks"]);
if (!rel) return null;
return isAbsolute(rel) ? rel : join25(projectRoot, rel);
}
function hookBlock(verb, cliPath = distCliPath()) {
return `${GIT_HOOK_MARKER}
if command -v paqad-ai >/dev/null 2>&1; then paqad-ai delivery-link ${verb} >/dev/null 2>&1 || true; elif command -v node >/dev/null 2>&1 && [ -f "${cliPath}" ]; then node "${cliPath}" delivery-link ${verb} >/dev/null 2>&1 || true; fi`;
}
function readHook(path10) {
try {
return readFileSync14(path10, "utf8");
} catch {
return "";
}
}
function makeExecutable(path10, context) {
try {
context.chmod(path10, 493);
} catch (error) {
const shown = toPosixPath(relative5(context.projectRoot, path10));
const reason2 = error instanceof Error ? error.message : "unknown error";
context.problems.push(
`Couldn't make ${shown} executable: ${reason2}. Run chmod +x ${shown}, or git won't run it.`
);
}
}
function appendBlock(path10, existing, block, context) {
if (existing.trim() === "") {
writeFileSync5(path10, `#!/bin/sh
${block}
`, "utf8");
} else {
const prefix = existing.endsWith("\n") ? existing : `${existing}
`;
writeFileSync5(path10, `${prefix}${block}
`, "utf8");
}
makeExecutable(path10, context);
}
function stripWorkflowBlock(text2) {
const lines = text2.split("\n");
const kept = [];
for (let i = 0; i < lines.length; i += 1) {
if (lines[i] === GIT_WORKFLOW_HOOK_MARKER) {
i += 1;
continue;
}
kept.push(lines[i]);
}
return kept.join("\n");
}
function peopleSetting(projectRoot) {
try {
const { config } = loadGitWorkflow(projectRoot);
return config.enforcement.enabled ? config.enforcement.people : "off";
} catch {
return "off";
}
}
function syncWorkflowHooks(dir, people, result2, context) {
for (const hook of WORKFLOW_HOOKS) {
const { name } = hook;
const path10 = join25(dir, name);
const existing = readHook(path10);
const present = existing.includes(GIT_WORKFLOW_HOOK_MARKER);
if (people === "off") {
if (!present) continue;
const stripped = stripWorkflowBlock(existing);
if (stripped.replace(/^#!.*\n?/, "").trim() === "") rmSync4(path10, { force: true });
else writeFileSync5(path10, stripped, "utf8");
result2.removed.push(name);
continue;
}
if (hookRunsCheck(existing, hook)) {
if (!isExecutable(path10)) makeExecutable(path10, context);
result2.skipped.push(name);
continue;
}
appendBlock(path10, existing, workflowHookBlock(name), context);
result2.installed.push(name);
}
}
function hookRunsCheck(text2, hook) {
return text2.split(/\r?\n/u).some((line) => {
const trimmed = line.trim();
return !trimmed.startsWith("#") && hook.runs.test(trimmed);
});
}
function isExecutable(path10) {
try {
return (statSync3(path10).mode & 73) !== 0;
} catch {
return false;
}
}
function isHuskyRunnerDir(dir) {
return basename3(dir) === HUSKY_RUNNER_DIR && existsSync12(join25(dir, HUSKY_RUNNER_FILE));
}
function isHandEditedHooksDir(projectRoot, dir) {
return isHuskyRunnerDir(dir) || hooksDirIsTracked(projectRoot, dir);
}
function hookFilesFor(dir) {
return isHuskyRunnerDir(dir) ? { dir: dirname13(dir), huskyRuns: true } : { dir, huskyRuns: false };
}
function needsExecutableBit(files, platform) {
return !files.huskyRuns && platform !== "win32";
}
function workflowHooksInstalled(projectRoot, platform = process.platform) {
const dir = resolveHooksDir(projectRoot);
if (!dir) return false;
const files = hookFilesFor(dir);
return WORKFLOW_HOOKS.every((hook) => {
const path10 = join25(files.dir, hook.name);
return hookRunsCheck(readHook(path10), hook) && (!needsExecutableBit(files, platform) || isExecutable(path10));
});
}
function executableStep(shown) {
return `chmod +x ${shown}, or git update-index --chmod=+x ${shown} from Windows`;
}
function hookAdvice(projectRoot, files, hook, platform) {
const path10 = join25(files.dir, hook.name);
const shown = toPosixPath(relative5(projectRoot, path10));
const block = workflowHookBlock(hook.name);
if (files.huskyRuns && !hookRunsCheck(readHook(path10), hook)) return [`${shown}:`, block];
if (!existsSync12(path10)) {
return [
`${shown} doesn't exist yet. Create it with these lines, then run ${executableStep(shown)}:`,
"#!/bin/sh",
block
];
}
if (!hookRunsCheck(readHook(path10), hook)) return [`${shown}:`, block];
if (needsExecutableBit(files, platform) && !isExecutable(path10)) {
return [`${shown} has the line but git can't run it. Run ${executableStep(shown)}.`];
}
return [];
}
function trackedWorkflowHookAdvice(projectRoot, platform = process.platform) {
const dir = resolveHooksDir(projectRoot);
if (!dir || !isHandEditedHooksDir(projectRoot, dir) || peopleSetting(projectRoot) === "off") {
return null;
}
const files = hookFilesFor(dir);
const missing = WORKFLOW_HOOKS.flatMap((hook) => hookAdvice(projectRoot, files, hook, platform));
if (missing.length === 0) return null;
const reason2 = files.huskyRuns ? "which husky runs" : "which your repo tracks";
return [
`Your git hooks are in ${toPosixPath(relative5(projectRoot, files.dir))}, ${reason2}, so paqad didn't change them.`,
"Add these lines to commit-msg and pre-push so people get the workflow check:",
...missing,
PATH_LIMIT_LINE
].join("\n");
}
function deliveryLinkSnippet() {
return HOOKS.flatMap(({ name, verb }) => [`${name}:`, hookBlock(verb)]);
}
function installGitHooks(projectRoot, io = {}) {
const context = { projectRoot, chmod: io.chmod ?? chmodSync, problems: [] };
const dir = resolveHooksDir(projectRoot);
if (!dir) {
return { installed: [], skipped: [], notAGitRepo: true };
}
if (isHandEditedHooksDir(projectRoot, dir)) {
const advice = trackedWorkflowHookAdvice(projectRoot);
return {
installed: [],
skipped: [],
notAGitRepo: false,
trackedHooksDir: true,
huskyRuns: isHuskyRunnerDir(dir),
snippet: [
...advice === null ? [] : [advice],
isHuskyRunnerDir(dir) ? `Add these lines to post-commit and post-merge in ${toPosixPath(relative5(projectRoot, dirname13(dir)))}:` : "Add these lines to post-commit and post-merge in your tracked hooks dir:",
...deliveryLinkSnippet()
].join("\n")
};
}
mkdirSync4(dir, { recursive: true });
const installed = [];
const skipped5 = [];
const removed = [];
for (const { name, verb } of HOOKS) {
const path10 = join25(dir, name);
let existing = "";
try {
existing = readFileSync14(path10, "utf8");
} catch {
}
if (existing.includes(GIT_HOOK_MARKER)) {
skipped5.push(name);
continue;
}
appendBlock(path10, existing, hookBlock(verb), context);
installed.push(name);
}
syncWorkflowHooks(dir, peopleSetting(projectRoot), { installed, skipped: skipped5, removed }, context);
return { installed, skipped: skipped5, removed, notAGitRepo: false, problems: context.problems };
}
// src/git-workflow/migrate.ts
init_esm_shims();
var import_yaml5 = __toESM(require_dist(), 1);
import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync15, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
import { join as join26 } from "path";
// src/git-workflow/onboard.ts
init_esm_shims();
import { execFileSync as execFileSync4 } from "child_process";
var DEFAULT_PR_BODY = `## Summary
{summary}
## Ticket
{ticket}
## Test plan
- [ ] Unit / integration tests pass locally
- [ ] Manual verification on the affected surface
- [ ] Docs and registries updated
\u{1F916} Generated with paqad-ai delivery
`;
function remoteDefaultBranch(projectRoot) {
try {
const ref = execFileSync4("git", ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"], {
cwd: projectRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"]
}).trim();
const branch = ref.replace(/^origin\//, "");
return branch === "" ? DEFAULT_BASE_BRANCH : branch;
} catch {
return DEFAULT_BASE_BRANCH;
}
}
function generateGitWorkflowFiles(domain, projectRoot) {
if (domain !== "coding") {
return [];
}
const baseBranch = remoteDefaultBranch(projectRoot);
return [
...GIT_WORKFLOW_FILES.map((file) => ({
path: `${PATHS.GIT_WORKFLOW_DIR}/${file}`,
content: renderDefaultGitWorkflowFile(file, { baseBranch }),
autoUpdate: false
})),
{
path: PATHS.DELIVERY_PR_BODY_TEMPLATE,
content: DEFAULT_PR_BODY,
autoUpdate: false
}
];
}
// src/git-workflow/migrate.ts
var OLD_DELIVERY_POLICY = `${PATHS.WORKFLOWS_DIR}/delivery-policy.yaml`;
var MOVED_MESSAGE = "Moved your delivery rules to .paqad/configs/git-workflow/. Check the result and commit it with the old file's removal.";
var UNREADABLE_MESSAGE = `Couldn't read ${OLD_DELIVERY_POLICY}, so .paqad/configs/git-workflow/ starts from defaults. Copy your settings across by hand, then delete the old file.`;
var COMMENT_DECISIONS_LINE = "comment_decisions is no longer used. The design sign-off replaces it.";
var OLD_DEFAULTS = {
enabled: true,
ticket: {
provider: "jira",
server: "",
require_ticket: false,
write_back_refined: "ask"
},
host: { provider: "github", server: "" },
branch: {
template: "{type}/{ticket}-{title_slug}",
type_map: { Story: "feat", Bug: "fix", Task: "chore", default: "feat" },
slug_max_length: 50,
base: "main"
},
commit: {
template: "{type}({scope}): {summary}\n\nRefs: {ticket}",
sign_off: false,
ask_when_unspecified: true
},
pr: {
title_template: "{type}({scope}): {summary} [{ticket}]",
body_template_path: ".paqad/templates/pr-body.md",
base: "main",
draft: false,
reviewers: [],
labels: [],
link_ticket: true,
transition_on_open: "In Review"
},
ci: { gate: "wait_for_green", timeout_minutes: 30, on_red: "stop", transition_on_green: "Done" },
intake_decisions: {
auto_resolve_from_priors: true,
auto_resolve_from_rules: true,
confirm_auto_resolutions: "batched",
max_options_per_packet: 4,
fingerprint_scope: ["ticket_type", "module", "category"]
}
};
function isPlain(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function section(raw, name) {
const process5 = isPlain(raw.process) ? raw.process : {};
return isPlain(process5[name]) ? process5[name] : {};
}
function pick(raw, key, fallback) {
return raw[key] === void 0 ? fallback : raw[key];
}
function oldFileReadable(raw) {
if (!isPlain(raw)) return false;
if (raw.enabled !== void 0 && typeof raw.enabled !== "boolean") return false;
if (raw.process !== void 0 && !isPlain(raw.process)) return false;
const process5 = isPlain(raw.process) ? raw.process : {};
return Object.values(process5).every((value) => value === void 0 || isPlain(value));
}
function convertDeliveryPolicy(raw, options) {
const lines = [];
const ticket = section(raw, "ticket");
const host = section(raw, "host");
const branch = section(raw, "branch");
const commit = section(raw, "commit");
const pr = section(raw, "pr");
const ci = section(raw, "ci");
const intake = section(raw, "intake_decisions");
const d = OLD_DEFAULTS;
const render2 = (file) => renderDefaultGitWorkflowFile(file, {
baseBranch: options.baseBranch
});
let tickets = render2("tickets.yaml");
const provider = pick(ticket, "provider", d.ticket.provider);
const source = { tracker: provider };
const defaultPattern = DEFAULT_TRACKER_PATTERNS[provider];
if (defaultPattern === null || defaultPattern === void 0) {
source.pattern = ".+";
lines.push(
`tickets.yaml sources.${provider} has pattern ".+", which matches anything. Set a real pattern for your ticket keys.`
);
} else {
source.pattern = defaultPattern;
}
const server = pick(ticket, "server", d.ticket.server);
if (server) source.server = server;
const transitions = {};
const onOpen = pick(pr, "transition_on_open", d.pr.transition_on_open);
const onGreen = pick(ci, "transition_on_green", d.ci.transition_on_green);
if (onOpen) transitions.on_pr_open = onOpen;
if (onGreen) transitions.on_ci_green = onGreen;
if (Object.keys(transitions).length > 0) source.transitions = transitions;
tickets = setValue(tickets, ["sources"], { [provider]: source });
tickets = setValue(
tickets,
["require_ticket"],
pick(ticket, "require_ticket", d.ticket.require_ticket)
);
tickets = setValue(
tickets,
["write_back_refined"],
pick(ticket, "write_back_refined", d.ticket.write_back_refined)
);
for (const [key, fallback] of Object.entries(d.intake_decisions)) {
tickets = setValue(tickets, ["intake_decisions", key], pick(intake, key, fallback));
}
if (ticket.comment_decisions !== void 0) lines.push(COMMENT_DECISIONS_LINE);
let branches = render2("branches.yaml");
const branchBase = pick(branch, "base", d.branch.base);
const prBase = pick(pr, "base", d.pr.base);
if (branch.base !== void 0 && pr.base !== void 0 && branchBase !== prBase) {
lines.push(`branch.base and pr.base differed; kept pr.base (${prBase}).`);
}
branches = setValue(branches, ["base_branch"], pr.base !== void 0 ? prBase : branchBase);
const template = String(pick(branch, "template", d.branch.template)).replaceAll(
"{type}",
"{prefix}"
);
branches = setValue(branches, ["template"], template);
branches = setValue(
branches,
["slug_max_length"],
pick(branch, "slug_max_length", d.branch.slug_max_length)
);
const typeMap = {
...d.branch.type_map,
...isPlain(branch.type_map) ? branch.type_map : {}
};
const types = {};
for (const [ticketType, value] of Object.entries(typeMap)) {
const entry = types[value] ??= { prefix: value, commit_type: value, ticket_types: [] };
if (ticketType !== "default") entry.ticket_types.push(ticketType);
}
const defaultType = typeMap.default ?? "feat";
types[defaultType] ??= { prefix: defaultType, commit_type: defaultType, ticket_types: [] };
for (const entry of Object.values(types)) {
if (entry.ticket_types.length === 0) delete entry.ticket_types;
}
branches = setValue(branches, ["types"], types);
branches = setValue(branches, ["default_type"], defaultType);
let commits = render2("commits.yaml");
commits = setValue(commits, ["template"], pick(commit, "template", d.commit.template));
commits = setValue(commits, ["sign_off"], pick(commit, "sign_off", d.commit.sign_off));
commits = setValue(
commits,
["ask_when_unspecified"],
pick(commit, "ask_when_unspecified", d.commit.ask_when_unspecified)
);
let pulls = render2("pull-requests.yaml");
pulls = setValue(pulls, ["host"], pick(host, "provider", d.host.provider));
pulls = setValue(pulls, ["host_server"], pick(host, "server", d.host.server));
for (const key of ["title_template", "draft", "reviewers", "labels", "link_ticket"]) {
pulls = setValue(pulls, [key], pick(pr, key, d.pr[key]));
}
pulls = setValue(
pulls,
["body_template"],
pick(pr, "body_template_path", d.pr.body_template_path)
);
for (const key of ["gate", "timeout_minutes", "on_red"]) {
pulls = setValue(pulls, ["ci", key], pick(ci, key, d.ci[key]));
}
let enforcement = render2("enforcement.yaml");
enforcement = setValue(enforcement, ["enabled"], pick(raw, "enabled", d.enabled));
return {
files: {
"tickets.yaml": tickets,
"branches.yaml": branches,
"commits.yaml": commits,
"pull-requests.yaml": pulls,
"enforcement.yaml": enforcement,
"design-sign-off.yaml": render2("design-sign-off.yaml")
},
lines
};
}
var NOT_GIT_WORKFLOW_KEYS = /* @__PURE__ */ new Set(["paqad_version", "schema_version", "ai_attribution"]);
var NOT_MOVED_FILES = ["design-sign-off.yaml"];
var MOVED_FILES = GIT_WORKFLOW_FILES.filter((file) => !NOT_MOVED_FILES.includes(file));
function readSettings(path10) {
if (!existsSync13(path10)) return null;
try {
const parsed = import_yaml5.default.parse(readFileSync15(path10, "utf8"));
return isPlain(parsed) ? parsed : {};
} catch {
return { unreadable: true };
}
}
function gitWorkflowFilesAbsent(projectRoot) {
return MOVED_FILES.every((file) => {
const settings = readSettings(gitWorkflowFilePath(projectRoot, file));
return settings === null || Object.keys(settings).every((key) => NOT_GIT_WORKFLOW_KEYS.has(key));
});
}
function keepAiAttribution(projectRoot, files) {
const kept = readSettings(gitWorkflowFilePath(projectRoot, "commits.yaml"))?.ai_attribution;
if (kept !== void 0) {
files["commits.yaml"] = insertKey(
removeAiAttributionComment(files["commits.yaml"]),
[],
"ai_attribution",
kept
);
}
}
function deliveryMovePending(projectRoot) {
return existsSync13(join26(projectRoot, OLD_DELIVERY_POLICY)) && gitWorkflowFilesAbsent(projectRoot);
}
function deliveryMoveBlocks(projectRoot) {
return MOVED_FILES.flatMap((file) => {
const line = renderWriteBlock(
readTextIfExistsSync(gitWorkflowFilePath(projectRoot, file)) ?? "",
`${PATHS.GIT_WORKFLOW_DIR}/${file}`
);
return line === null ? [] : [line];
});
}
function pendingMoveRefusal(projectRoot) {
if (!deliveryMovePending(projectRoot)) return [];
return [
...deliveryMoveBlocks(projectRoot),
`${OLD_DELIVERY_POLICY} hasn't moved yet, so this wasn't changed. Run paqad-ai update first.`
];
}
function migrateDeliveryPolicy(projectRoot, options = {}) {
const oldPath = join26(projectRoot, OLD_DELIVERY_POLICY);
if (!deliveryMovePending(projectRoot)) {
return { ran: false, lines: [], written: [], deleted: false };
}
const blocked = deliveryMoveBlocks(projectRoot);
if (blocked.length > 0) {
return { ran: false, blocked: true, lines: blocked, written: [], deleted: false };
}
const version = options.version ?? "1.128.1";
const baseBranch = options.baseBranch ?? remoteDefaultBranch(projectRoot);
let raw;
try {
raw = import_yaml5.default.parse(readFileSync15(oldPath, "utf8")) ?? {};
} catch {
raw = null;
}
mkdirSync5(gitWorkflowDir(projectRoot), { recursive: true });
const written = [];
const targets = GIT_WORKFLOW_FILES.filter(
(file) => !NOT_MOVED_FILES.includes(file) || !existsSync13(gitWorkflowFilePath(projectRoot, file))
);
if (!oldFileReadable(raw)) {
for (const file of targets) {
const path10 = gitWorkflowFilePath(projectRoot, file);
writeFileSync6(path10, renderDefaultGitWorkflowFile(file, { baseBranch }), "utf8");
written.push(path10);
}
stampLastApplied(projectRoot, targets, { version, now: options.now });
return { ran: true, lines: [UNREADABLE_MESSAGE], written, deleted: false };
}
const converted = convertDeliveryPolicy(raw, { baseBranch });
keepAiAttribution(projectRoot, converted.files);
const lines = [];
for (const file of targets) {
const path10 = gitWorkflowFilePath(projectRoot, file);
writeFileSync6(path10, converted.files[file], "utf8");
written.push(path10);
if (!NOT_MOVED_FILES.includes(file)) {
lines.push(`Moved delivery rules into ${PATHS.GIT_WORKFLOW_DIR}/${file}.`);
}
}
stampLastApplied(projectRoot, targets, { version, now: options.now });
rmSync5(oldPath);
return {
ran: true,
lines: [...lines, ...converted.lines, MOVED_MESSAGE],
written,
deleted: true
};
}
// src/health/git-workflow-check.ts
var GIT_WORKFLOW_CHECK = "git-workflow";
var SKILL_REVIEW = "Ask your agent to review it with the git-workflow skill.";
function warning(detail, remediation) {
return { name: GIT_WORKFLOW_CHECK, status: "warning", detail, remediation };
}
function oldPolicyWarning(projectRoot) {
const blocks = deliveryMoveBlocks(projectRoot);
if (!deliveryMovePending(projectRoot)) {
const remedy = `Delete ${OLD_DELIVERY_POLICY}.`;
return warning(
[`${OLD_DELIVERY_POLICY} is no longer read. Delete it.`, ...blocks].join(" "),
[remedy, ...blocks].join(" ")
);
}
if (blocks.length === 0) {
return warning(
`${OLD_DELIVERY_POLICY} hasn't moved yet, so keep it. It holds your only copy of these rules. Run paqad-ai update to move them.`,
"Run paqad-ai update."
);
}
return warning(
`${OLD_DELIVERY_POLICY} hasn't moved yet, so keep it. ${blocks.join(" ")} The move runs on the next paqad-ai update.`,
blocks.join(" ")
);
}
function gitWorkflowHealth(projectRoot, hooksInstalled = workflowHooksInstalled) {
if (!existsSync14(gitWorkflowDir(projectRoot))) {
return [
warning(
`${PATHS.GIT_WORKFLOW_DIR}/ is missing. Run paqad-ai update to create it.`,
"Run paqad-ai update."
)
];
}
const results = [];
const loaded = loadGitWorkflow(projectRoot);
for (const error of loaded.errors) {
results.push(warning(`git-workflow: ${error.message}`, SKILL_REVIEW));
}
for (const unknown of loaded.warnings) {
results.push(warning(unknown.message, SKILL_REVIEW));
}
if (existsSync14(join27(projectRoot, OLD_DELIVERY_POLICY))) {
results.push(oldPolicyWarning(projectRoot));
}
const { tickets, enforcement } = loaded.config;
if (tickets.write_back_refined !== "ask") {
results.push(
warning(
"git-workflow: write_back_refined is set but not applied yet.",
"Leave write_back_refined at ask until paqad applies it."
)
);
}
if (enforcement.enabled && enforcement.people !== "off" && resolveHooksDir(projectRoot) !== null && !hooksInstalled(projectRoot)) {
const advice = trackedWorkflowHookAdvice(projectRoot);
results.push(
advice === null ? warning(
`git-workflow: people is set to ${enforcement.people} but the commit-msg and pre-push hooks aren't installed. Run paqad-ai update.`,
"Run paqad-ai update."
) : warning(advice, "Add the lines above by hand, then run paqad-ai doctor again.")
);
}
for (const file of changedOutside(projectRoot)) {
results.push(
warning(
`git-workflow: ${file} was changed outside the git-workflow skill. ${SKILL_REVIEW}`,
SKILL_REVIEW
)
);
}
if (results.length > 0) return results;
return [
{
name: GIT_WORKFLOW_CHECK,
status: "pass",
detail: `${PATHS.GIT_WORKFLOW_DIR}/ is valid and every file was applied through the git-workflow skill.`
}
];
}
// src/health/home-project-check.ts
init_esm_shims();
import { existsSync as existsSync15 } from "fs";
import { homedir as homedir2 } from "os";
import { join as join28 } from "path";
var HOME_PROJECT_CHECK = "Home folder project";
var HOME_PROJECT_WARNING = "Your home folder is set up as a paqad project. This makes the HUD pick the wrong folder. Remove ~/.paqad/framework-path.txt unless you really work in your home folder.";
function homeProjectHealth(homeDir = homedir2()) {
if (existsSync15(join28(homeDir, ".paqad", "framework-path.txt"))) {
return [
{
name: HOME_PROJECT_CHECK,
status: "warning",
detail: HOME_PROJECT_WARNING,
remediation: "Remove ~/.paqad/framework-path.txt by hand; paqad never deletes it."
}
];
}
return [
{
name: HOME_PROJECT_CHECK,
status: "pass",
detail: "Your home folder is not set up as a paqad project."
}
];
}
// src/health/team-config-check.ts
init_esm_shims();
import { existsSync as existsSync16 } from "fs";
import { join as join29 } from "path";
var TEAM_CONFIG_CHECK = "team-config";
var MIGRATE = "Run paqad-ai config migrate.";
function result(status, detail, remediation) {
return { name: TEAM_CONFIG_CHECK, status, detail, remediation };
}
function teamConfigHealth(projectRoot) {
if (!existsSync16(join29(projectRoot, PATHS.PROJECT_CONFIGS_DIR))) return [];
const results = [];
for (const file of missingTeamConfigFiles(projectRoot)) {
results.push(result("warning", missingTeamFileLine(file), "Run paqad-ai update."));
}
for (const issue of readTeamConfig(projectRoot).issues) {
if (issue.kind === "legacy") continue;
results.push(
result(
"warning",
issue.message,
`Fix .paqad/configs/${issue.file} or run paqad-ai config show.`
)
);
}
for (const { file, path: path10 } of unknownTeamConfigSettings(projectRoot)) {
results.push(
result("warning", unknownSettingLine(file, path10), `Check ${path10} in .paqad/configs/${file}.`)
);
}
const legacyStatus = releasedAfterLegacyWindow() ? "fail" : "warning";
for (const file of legacyFilesWithSettings(projectRoot)) {
results.push(result(legacyStatus, legacyShouldMoveLine(file), MIGRATE));
}
if (results.length > 0) return results;
return [
{
name: TEAM_CONFIG_CHECK,
status: "pass",
detail: "The team settings in .paqad/configs/ are valid."
}
];
}
// src/health/provider-entry-contract.ts
init_esm_shims();
import { existsSync as existsSync17, readFileSync as readFileSync16 } from "fs";
import { join as join30, relative as relative6 } from "path";
var REMEDIATION = "Re-run `paqad refresh --providers` to regenerate the lean entry stubs.";
var STALE_FAT_MARKERS = [
"## Decision Pause Contract",
"# Decision Pause Contract",
"## paqad in your chat",
"# paqad narration contract"
];
function entryFileProviders(projectRoot) {
try {
const manifest = readExistingOnboardingManifest(projectRoot);
if (manifest === null) return ADAPTER_TYPES;
const recorded = deriveRecordedProviders(manifest).filter(
(type) => ADAPTER_TYPES.includes(type)
);
return recorded.length > 0 ? recorded : ADAPTER_TYPES;
} catch {
return ADAPTER_TYPES;
}
}
function presentEntryFiles(projectRoot) {
return entryFileProviders(projectRoot).map((type) => join30(projectRoot, AdapterFactory.create(type).getConfigPath())).filter((path10) => existsSync17(path10)).map((path10) => ({
relativePath: relative6(projectRoot, path10),
content: readFileSync16(path10, "utf8")
}));
}
function noEntryFiles(kind) {
return {
status: "warning",
detail: "No adapter config files were found to check",
remediation: `Generate at least one adapter config before checking the ${kind}.`
};
}
function inspectProviderEntryBootstrapPointer(projectRoot) {
const entries = presentEntryFiles(projectRoot);
if (entries.length === 0) {
return noEntryFiles("bootstrap pointer");
}
const missingPointer = entries.filter((entry) => !entry.content.includes(PATHS.FRAMEWORK_PATH)).map((entry) => entry.relativePath);
if (missingPointer.length > 0) {
return {
status: "fail",
detail: `Bootstrap pointer (${PATHS.FRAMEWORK_PATH}) missing from: ${missingPointer.join(", ")}`,
remediation: REMEDIATION
};
}
const stillFat = entries.filter((entry) => STALE_FAT_MARKERS.some((marker) => entry.content.includes(marker))).map((entry) => entry.relativePath);
if (stillFat.length > 0) {
return {
status: "warning",
detail: `Stale (older full-contract) entry file still inlines a contract section in: ${stillFat.join(", ")}`,
remediation: REMEDIATION
};
}
return {
status: "pass",
detail: "Every generated entry file is a lean stub pointing to the framework bootstrap.",
remediation: "No action needed."
};
}
function inspectProviderEntryFallbackClause(projectRoot) {
const entries = presentEntryFiles(projectRoot);
if (entries.length === 0) {
return noEntryFiles("fallback clause");
}
const clause = buildFrameworkFallbackClause();
const missing = entries.filter((entry) => !entry.content.includes(clause)).map((entry) => entry.relativePath);
if (missing.length > 0) {
return {
status: "fail",
detail: `Graceful-degradation fallback clause missing from: ${missing.join(", ")}`,
remediation: REMEDIATION
};
}
return {
status: "pass",
detail: "Every generated entry file carries the graceful-degradation fallback clause.",
remediation: "No action needed."
};
}
// src/health/checker.ts
var STALENESS_WINDOW_MS = 1e3 * 60 * 60 * 24 * 7;
var SENTINEL_DIR = ".paqad/.agent-entry-loaded.d";
var HealthChecker = class {
constructor(options = {}) {
this.options = options;
}
options;
validator = new SchemaValidator();
async run(projectRoot) {
const profile = this.readProfile(projectRoot);
const modules = this.detectModules(projectRoot);
const checks = [
this.checkFrameworkArtifacts(projectRoot),
this.checkProfile(profile),
this.checkDetectionReport(projectRoot),
this.checkOnboardingManifest(projectRoot),
this.checkDecisionWorkspace(projectRoot),
this.checkStackSnapshot(projectRoot),
this.checkStackDrift(projectRoot),
this.checkModuleHealthLedger(projectRoot),
this.checkInstructionCopies(projectRoot, profile),
this.checkIndexesCurrent(projectRoot),
this.checkAdapterConfig(projectRoot),
this.checkCodexHooks(projectRoot),
this.checkGateFailClosed(projectRoot),
this.checkProviderEntryBootstrapPointer(projectRoot),
this.checkProviderEntryFallbackClause(projectRoot),
this.checkStackCommands(profile),
this.checkTestRunnerParallel(profile),
...await this.checkStructuredTestOutput(projectRoot, profile),
this.checkStableFrameworkPaths(projectRoot),
this.checkTrackedSentinels(projectRoot),
this.checkFrameworkInstall(),
this.checkClaudeInstall(projectRoot),
...this.checkDiscoveryClash(),
this.checkSchemaVersion(projectRoot),
this.checkBrokenScaffold(projectRoot),
this.checkUiDocs(projectRoot, modules),
this.checkApiDocs(projectRoot, modules),
this.checkIntegrationDocs(projectRoot, modules),
this.checkErrorCatalog(projectRoot, modules),
this.checkMcp(projectRoot, profile),
this.checkSkillCache(projectRoot),
this.checkContextHitRate(projectRoot, profile),
this.checkLeanRuleFootprint(projectRoot),
await this.checkCompiledRulesCurrent(projectRoot),
this.checkClassificationOverrideRate(projectRoot),
...await this.checkRag(projectRoot, profile),
this.checkSpecPipeline(projectRoot),
this.checkSpecPipelineSettings(projectRoot),
...this.checkExpertRoster(projectRoot),
...this.checkVisualEvidence(projectRoot),
...this.checkAuthoringConfig(projectRoot),
...gitWorkflowHealth(projectRoot),
...runningVersionHealth(projectRoot),
...teamConfigHealth(projectRoot),
...homeProjectHealth(this.options.homeDir)
];
const overallStatus = deriveOverallStatus(checks);
return {
overall_status: overallStatus,
checks,
efficiency: await this.buildEfficiencySummary(projectRoot)
};
}
readProfile(projectRoot) {
return readProjectProfile(projectRoot);
}
detectModules(projectRoot) {
const modulesRoot = join31(projectRoot, "docs/modules");
if (!existsSync18(modulesRoot)) {
return [];
}
return readdirSync3(modulesRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
}
checkFrameworkArtifacts(projectRoot) {
const required = [PATHS.PROJECT_PROFILE, PATHS.FRAMEWORK_PATH];
const missing = required.filter((relative21) => !existsSync18(join31(projectRoot, relative21)));
return missing.length === 0 ? pass("Framework artifacts exist", "Framework artifacts are present") : fail(
"Framework artifacts exist",
`Missing framework artifacts: ${missing.join(", ")}`,
"Re-run onboarding to regenerate the missing framework artifacts."
);
}
isPathIgnored(projectRoot, relPath, directory = false) {
const target = relPath.replace(/\/$/, "");
const probe = directory ? `${target}/` : target;
try {
execFileSync5("git", ["check-ignore", "-q", "--", probe], {
cwd: projectRoot,
stdio: "ignore"
});
return true;
} catch (error) {
if (error.status === 1) {
return false;
}
}
const probes = [
[join31(projectRoot, ".gitignore"), target],
[join31(projectRoot, ".paqad", ".gitignore"), target.replace(/^\.paqad\//, "")]
];
for (const [file, needle] of probes) {
if (existsSync18(file) && readFileSync17(file, "utf8").includes(needle)) {
return true;
}
}
return false;
}
checkProfile(profile) {
if (profile === null) {
return fail(
"Profile is valid",
"Project profile is missing or unreadable",
"Regenerate the project profile."
);
}
const validation = this.validator.validate("project-profile", profile);
return validation.valid ? pass("Profile is valid", "Project profile schema is valid") : fail(
"Profile is valid",
validation.errors.map((error) => error.message).join("; "),
"Fix the invalid project profile fields."
);
}
checkDetectionReport(projectRoot) {
return this.checkJsonArtifact({
projectRoot,
relativePath: PATHS.DETECTION_REPORT,
name: "Detection report is valid",
schemaId: "detection-report",
missingRemediation: "Run `paqad-ai join` to regenerate the detection report (a per-machine artifact).",
invalidRemediation: "Fix or regenerate the detection report JSON."
});
}
checkOnboardingManifest(projectRoot) {
return this.checkJsonArtifact({
projectRoot,
relativePath: PATHS.ONBOARDING_MANIFEST,
name: "Onboarding manifest is valid",
schemaId: "onboarding-manifest",
missingRemediation: "Re-run onboarding to regenerate the onboarding manifest.",
invalidRemediation: "Fix or regenerate the onboarding manifest JSON."
});
}
checkStackSnapshot(projectRoot) {
const path10 = join31(projectRoot, PATHS.STACK_SNAPSHOT);
if (!existsSync18(path10)) {
return fail(
"Stack snapshot present",
"Stack snapshot is missing",
"Run `paqad-ai join` (or onboarding/refresh) to regenerate the stack snapshot."
);
}
try {
const parsed = JSON.parse(readFileSync17(path10, "utf8"));
const valid = Array.isArray(parsed.toolchains) && Array.isArray(parsed.packages) && Array.isArray(parsed.profile?.frameworks);
return valid ? pass("Stack snapshot present", "Stack snapshot is present and readable") : fail(
"Stack snapshot present",
"Stack snapshot JSON is missing required sections",
"Run refresh to regenerate the stack snapshot."
);
} catch {
return fail(
"Stack snapshot present",
"Stack snapshot JSON is unreadable",
"Run refresh to regenerate the stack snapshot."
);
}
}
checkStackDrift(projectRoot) {
const path10 = join31(projectRoot, PATHS.STACK_DRIFT);
if (!existsSync18(path10)) {
return fail(
"Stack drift report present",
"Stack drift report is missing",
"Run `paqad-ai join` (or onboarding/refresh) to regenerate the stack drift report."
);
}
try {
const parsed = JSON.parse(readFileSync17(path10, "utf8"));
const valid = typeof parsed.status === "string" && typeof parsed.generated_at === "string";
return valid ? pass("Stack drift report present", "Stack drift report is present and readable") : fail(
"Stack drift report present",
"Stack drift report JSON is missing required fields",
"Run refresh to regenerate the stack drift report."
);
} catch {
return fail(
"Stack drift report present",
"Stack drift report JSON is unreadable",
"Run refresh to regenerate the stack drift report."
);
}
}
checkDecisionWorkspace(projectRoot) {
const required = [
PATHS.DECISIONS_PENDING_DIR,
PATHS.DECISIONS_RESOLVED_DIR,
PATHS.DECISIONS_EXPIRED_DIR,
PATHS.DECISIONS_INDEX
];
const missing = required.filter((relativePath) => !existsSync18(join31(projectRoot, relativePath)));
return missing.length === 0 ? pass("Decision workspace ready", "Decision storage directories and index are present") : warn(
"Decision workspace ready",
`Missing decision artifacts: ${missing.join(", ")}`,
"Run onboarding or refresh to regenerate the decision workspace."
);
}
checkModuleHealthLedger(projectRoot) {
const root = join31(projectRoot, PATHS.PLANNING_MODULE_HEALTH_DIR);
if (!existsSync18(root)) {
return pass(
"Module health ledger valid",
"No module health profiles yet \u2014 created on demand as modules accrue evidence"
);
}
const files = walk(root).filter((file) => file.endsWith(".json"));
const issues = [];
for (const file of files) {
try {
const parsed = JSON.parse(readFileSync17(file, "utf8"));
if (typeof parsed.module !== "string" || typeof parsed.tier !== "string" || typeof parsed.metrics !== "object" || parsed.metrics === null || typeof parsed.updated_at !== "string") {
issues.push(`${relativeTo(projectRoot, file)} missing required fields`);
continue;
}
const expectedTier = deriveHealthTier(parsed.metrics);
if (parsed.tier !== expectedTier) {
issues.push(
`${relativeTo(projectRoot, file)} tier is ${parsed.tier}; expected ${expectedTier}`
);
}
} catch {
issues.push(`${relativeTo(projectRoot, file)} is unreadable JSON`);
}
}
return issues.length === 0 ? pass("Module health ledger valid", "Module health profiles are valid and tier-consistent") : fail(
"Module health ledger valid",
issues.join("; "),
"Repair module health profiles or run module-health sync with current evidence."
);
}
checkInstructionCopies(projectRoot, profile) {
const rulesRoot = join31(projectRoot, PATHS.RULES_DIR);
const stack = profile === null ? null : getPrimaryStack(profile);
const toolsRoot = stack === null || profile === null || getProfileDomain(profile) !== "coding" ? null : join31(projectRoot, PATHS.TOOLS_DIR, stack);
const missing = [];
if (!existsSync18(rulesRoot)) {
missing.push(PATHS.RULES_DIR);
}
if (toolsRoot !== null && !existsSync18(toolsRoot)) {
missing.push(join31(PATHS.TOOLS_DIR, stack ?? "unknown"));
}
return missing.length === 0 ? pass("Instruction copies exist", "Copied rules and tools are present") : fail(
"Instruction copies exist",
`Missing copied instruction artifacts: ${missing.join(", ")}`,
"Re-run onboarding to restore the copied instruction bundles."
);
}
checkIndexesCurrent(projectRoot) {
const missing = REGISTRIES.filter(
(registry) => !existsSync18(join31(projectRoot, PATHS.REGISTRIES_DIR, registry))
);
const statusPath = join31(projectRoot, ".paqad/indexes/registry-status.json");
if (missing.length > 0 || !existsSync18(statusPath)) {
return warn(
"Indexes are current",
"Registry scaffold has not been generated yet",
"Run the documentation workflow to generate registries."
);
}
const stale = isStale(statSync4(statusPath).mtimeMs);
return stale ? warn("Indexes are current", "Registries are stale", "Run the documentation workflow again.") : pass("Indexes are current", "Registries are present and current");
}
checkAdapterConfig(projectRoot) {
const configs = ADAPTER_TYPES.map((type) => AdapterFactory.create(type).getConfigPath());
const existing = configs.filter((config) => existsSync18(join31(projectRoot, config)));
return existing.length > 0 ? pass("Adapter config is present", "Adapter config files are present") : fail(
"Adapter config is present",
"No adapter config files were found",
"Regenerate the adapter configuration."
);
}
checkCodexHooks(projectRoot) {
const name = "Codex hooks wired";
if (!existsSync18(join31(projectRoot, ".codex"))) {
return pass(name, "No .codex/ directory \u2014 not a Codex project, nothing to check.");
}
const trustStep = "Re-run onboarding with the codex-cli adapter, then open Codex in the project, run /hooks, and approve paqad\u2019s hooks.";
const hooksPath = join31(projectRoot, ".codex", "hooks.json");
if (!existsSync18(hooksPath)) {
return warn(
name,
"A .codex/ project has no .codex/hooks.json \u2014 paqad hooks are not wired.",
trustStep
);
}
let hooks;
try {
const parsed = JSON.parse(readFileSync17(hooksPath, "utf8"));
hooks = parsed.hooks && typeof parsed.hooks === "object" && !Array.isArray(parsed.hooks) ? parsed.hooks : {};
} catch {
return warn(
name,
".codex/hooks.json is unreadable JSON.",
"Re-run onboarding to regenerate .codex/hooks.json."
);
}
const required = [
["PreToolUse", "agent-entry-gate.mjs"],
["UserPromptSubmit", "agent-entry-prompt-gate.mjs"],
["SessionStart", "agent-entry-session-start.mjs"],
["Stop", "verification-completion.mjs"]
];
const missing = required.filter(([event, script]) => !JSON.stringify(hooks[event] ?? []).includes(script)).map(([event]) => event);
if (missing.length > 0) {
return warn(
name,
`.codex/hooks.json is missing paqad hooks for: ${missing.join(", ")}.`,
trustStep
);
}
return pass(
name,
"All four Codex events carry paqad hooks. If a gate never fires, run /hooks in Codex and approve them (project hooks load only when the .codex/ layer is trusted)."
);
}
checkGateFailClosed(projectRoot) {
const name = "Edit gates fail closed";
const settingsPath = join31(projectRoot, ".claude", "settings.json");
if (!existsSync18(settingsPath)) {
return pass(name, "No .claude/settings.json \u2014 not a Claude Code project, nothing to check.");
}
let preTool;
try {
const parsed = JSON.parse(readFileSync17(settingsPath, "utf8"));
preTool = Array.isArray(parsed.hooks?.PreToolUse) ? parsed.hooks.PreToolUse : [];
} catch {
return warn(
name,
".claude/settings.json is unreadable JSON.",
"Re-run onboarding to regenerate .claude/settings.json."
);
}
const gates = [
["agent-entry-gate", (cmd) => cmd.includes("agent-entry-gate.mjs")],
["decision-pause-gate", (cmd) => cmd.includes("decision-pause-gate.mjs")],
[
"capability-gate (pre-mutation)",
(cmd) => cmd.includes("capability-gate.mjs") && cmd.includes("pre-mutation")
]
];
const missing = [];
for (const [label, matches] of gates) {
let found = false;
let hasOnFailure = false;
for (const group of preTool) {
for (const hook of group.hooks ?? []) {
if (typeof hook.command === "string" && matches(hook.command)) {
found = true;
if (hook.onFailure !== void 0) {
hasOnFailure = true;
}
}
}
}
if (found && !hasOnFailure) {
missing.push(label);
}
}
if (missing.length > 0) {
return warn(
name,
`These Claude edit gates are missing onFailure (an install onboarded before the edit gates failed closed): ${missing.join(", ")}.`,
"Re-run onboarding to regenerate .claude/settings.json with fail-closed edit gates."
);
}
return pass(name, 'The Claude edit gates render onFailure: "block" with a timeout.');
}
checkProviderEntryBootstrapPointer(projectRoot) {
const result2 = inspectProviderEntryBootstrapPointer(projectRoot);
const label = "Entry files point to the framework bootstrap";
if (result2.status === "pass") {
return pass(label, result2.detail);
}
if (result2.status === "warning") {
return warn(label, result2.detail, result2.remediation);
}
return fail(label, result2.detail, result2.remediation);
}
checkProviderEntryFallbackClause(projectRoot) {
const result2 = inspectProviderEntryFallbackClause(projectRoot);
const label = "Entry files carry the graceful-degradation fallback clause";
if (result2.status === "pass") {
return pass(label, result2.detail);
}
if (result2.status === "warning") {
return warn(label, result2.detail, result2.remediation);
}
return fail(label, result2.detail, result2.remediation);
}
checkStackCommands(profile) {
if (profile === null) {
return fail(
"Stack commands configured",
"Project profile is missing",
"Restore a valid project profile."
);
}
if (!profile.commands || typeof profile.commands !== "object") {
return fail(
"Stack commands configured",
"Project commands are missing from the profile",
"Restore the commands block in the project profile."
);
}
const missing = Object.entries(profile.commands).filter(([, value]) => typeof value !== "string" || value.trim() === "").map(([key]) => key);
return missing.length === 0 ? pass("Stack commands configured", "Required stack commands are populated") : fail(
"Stack commands configured",
`Missing command definitions: ${missing.join(", ")}`,
"Populate the missing command entries in the project profile."
);
}
checkTestRunnerParallel(profile) {
const name = "Test runner parallel mode";
const testing = profile?.testing;
if (!testing) {
return pass(
name,
"No parallel-test decision recorded yet; it is derived on the next `paqad-ai checks run`."
);
}
if (testing.parallel === "native" || testing.parallel === "available") {
return pass(
name,
`The suite runs in parallel (${testing.parallel}) via ${testing.runner_id}.`
);
}
const reason2 = testing.reason ?? testing.parallel;
let suggestion = `Recorded ${testing.parallel} for ${testing.runner_id}: ${reason2}.`;
if (testing.parallel === "unavailable" && reason2.endsWith("-missing")) {
const pkg = reason2.replace(/-missing$/, "");
suggestion += ` Add ${pkg} as a dev dependency to run the suite in parallel.`;
}
return warn(name, `The suite runs sequentially (${testing.parallel}).`, suggestion);
}
async checkStructuredTestOutput(projectRoot, profile) {
const frameworks = profile?.stack_profile?.frameworks ?? [];
if (frameworks.length === 0) {
return [
pass(
"Structured test output ready",
"No coding stack profile is active, so structured test-output checks are not required"
)
];
}
const runners = getPackTestRunners(frameworks, projectRoot);
if (runners.length === 0) {
return [
warn(
"Structured test output ready",
`No test runners are declared for the active frameworks: ${frameworks.join(", ")}`,
"Add test_runners metadata for the active stack packs."
)
];
}
for (const runner of runners) {
const fixture = TEST_OUTPUT_SMOKE_FIXTURES[runner.structured_format];
if (!fixture) {
return [
fail(
"Structured test output ready",
`No smoke fixture is available for runner "${runner.runner_id}" (${runner.structured_format})`,
"Add a parser smoke fixture for the runner format."
)
];
}
try {
await parseTestOutput({
runner,
cwd: projectRoot,
stdout: fixture
});
} catch (error) {
return [
fail(
"Structured test output ready",
`Runner "${runner.runner_id}" failed parser smoke validation: ${error instanceof Error ? error.message : String(error)}`,
"Fix the parser, fixture, or runner declaration before relying on structured test output."
)
];
}
}
return [
pass(
"Structured test output ready",
`Structured test parsing is ready for ${runners.map((runner) => runner.runner_id).join(", ")}`
)
];
}
checkTrackedSentinels(projectRoot) {
const name = "Session sentinels untracked";
let tracked;
try {
tracked = execFileSync5("git", ["ls-files", "--", SENTINEL_DIR], {
cwd: projectRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"]
});
} catch {
return pass(name, "Not a git repository, nothing to check");
}
const count2 = tracked.split("\n").filter((line) => line.trim().length > 0).length;
return count2 === 0 ? pass(name, `git tracks nothing under ${SENTINEL_DIR}`) : warn(
name,
`git tracks ${count2} per-session file(s) under ${SENTINEL_DIR}, so every session dirties the tree`,
`Run \`git rm -r --cached ${SENTINEL_DIR}\` and commit the change.`
);
}
checkStableFrameworkPaths(projectRoot) {
if (isFrameworkDisabledForRoot(projectRoot)) {
return pass(
"Stable framework paths only",
"paqad is disabled (vanilla mode) \u2014 gates, hooks, and the verification backstop are a no-op. Re-enable with `paqad-ai enable`."
);
}
const frameworkPath = join31(projectRoot, PATHS.FRAMEWORK_PATH);
if (!existsSync18(frameworkPath)) {
return fail(
"Stable framework paths only",
"Framework path file is missing",
"Re-run onboarding to write the framework path."
);
}
const value = readFileSync17(frameworkPath, "utf8").trim();
const unstable = value.includes("npx") || value.includes("npm-global") || value.includes(".npm/_npx");
return unstable ? fail(
"Stable framework paths only",
"Framework path points to an ephemeral install location",
"Reinstall the framework to a stable user-level path and re-run onboarding."
) : pass("Stable framework paths only", "Framework path is stable");
}
checkClaudeInstall(projectRoot) {
const line = describeClaudeInstall(void 0, projectRoot, process.env, {
managedSettingsPaths: this.options.managedSettingsPaths
});
return line.level === "warning" ? warn("Claude Code install", line.detail, line.remediation ?? "") : pass("Claude Code install", line.detail);
}
checkDiscoveryClash() {
const home = this.options.homeDir;
return discoveryPluginClash(home === void 0 ? {} : { home }) ? [
fail(
"Claude plugins",
DISCOVERY_CLASH_MESSAGE,
"Remove paqad discovery in Claude: Customize, Plugins."
)
] : [];
}
checkFrameworkInstall() {
const name = "Framework install";
const info2 = describeFrameworkLink();
if (info2.copy === "directory") {
return pass(name, `Framework home is a directory at ${info2.home}.`);
}
if (info2.linkTarget === null) {
return warn(
name,
`Framework link ${info2.home} is missing.`,
'Restore it with `ln -sfn "$(npm root -g)/paqad-ai/runtime" ~/.paqad-ai/current` (npm copy), or start a Claude Code session with the paqad plugin installed, to re-point it.'
);
}
if (!info2.targetExists) {
return warn(
name,
`Framework link ${info2.home} points at a missing target (${info2.linkTarget}).`,
'Restore it with `ln -sfn "$(npm root -g)/paqad-ai/runtime" ~/.paqad-ai/current` (npm copy), or start a Claude Code session with the paqad plugin installed, to re-point the link.'
);
}
const copyLabel = info2.copy === "unknown" ? "framework" : info2.copy;
const version = info2.version === null ? "" : ` (v${info2.version})`;
return pass(
name,
`Framework link points at the ${copyLabel} copy${version} at ${info2.linkTarget}.`
);
}
checkSchemaVersion(projectRoot) {
const name = "Schema version";
const marker = readSchemaMarkerSync(projectRoot);
if (!marker || checkSchemaCompatibility(marker) !== "future") {
return pass(name, "The .paqad/ layout matches this paqad version.");
}
return warn(
name,
`The .paqad/ layout was written by a newer paqad (schema ${marker.paqad_schema_version}).`,
SCHEMA_VERSION_UPDATE_HINT
);
}
checkBrokenScaffold(projectRoot) {
const broken = walk(projectRoot).filter(
(path10) => path10.endsWith(".partial") || path10.endsWith(".tmp")
);
return broken.length === 0 ? pass("No broken scaffold state", "No partial scaffold artifacts detected") : fail(
"No broken scaffold state",
`Partial scaffold artifacts detected: ${broken.join(", ")}`,
"Remove the partial files and re-run onboarding or update."
);
}
checkUiDocs(projectRoot, modules) {
if (!this.documentationHasRun(projectRoot) || modules.length === 0) {
return pass("UI docs present", "UI docs are checked after documentation generation");
}
const missing = modules.filter(
(moduleName) => !existsSync18(join31(projectRoot, "docs/modules", moduleName, "ui/screens.md")) || !existsSync18(join31(projectRoot, "docs/modules", moduleName, "ui/components.md")) || !existsSync18(join31(projectRoot, "docs/modules", moduleName, "ui/states.md"))
);
return missing.length === 0 ? pass("UI docs present", "UI docs are present for all modules with UI docs") : fail(
"UI docs present",
`Missing UI docs for: ${missing.join(", ")}`,
"Add the missing UI documentation files."
);
}
checkApiDocs(projectRoot, modules) {
if (!this.documentationHasRun(projectRoot) || modules.length === 0) {
return pass("API docs present", "API docs are checked after documentation generation");
}
const missing = modules.filter(
(moduleName) => !existsSync18(join31(projectRoot, "docs/modules", moduleName, "api/endpoints.md")) || !existsSync18(join31(projectRoot, "docs/modules", moduleName, "api/schemas.md")) || !existsSync18(join31(projectRoot, "docs/modules", moduleName, "api/error-codes.md"))
);
return missing.length === 0 ? pass("API docs present", "API docs are present for all modules with APIs") : fail(
"API docs present",
`Missing API docs for: ${missing.join(", ")}`,
"Add the missing API documentation files."
);
}
checkIntegrationDocs(projectRoot, modules) {
if (!this.documentationHasRun(projectRoot) || modules.length === 0) {
return pass(
"Integration docs present",
"Integration docs are checked after documentation generation"
);
}
const missing = modules.filter(
(moduleName) => !existsSync18(join31(projectRoot, "docs/modules", moduleName, "integration/events.md")) || !existsSync18(join31(projectRoot, "docs/modules", moduleName, "integration/contracts.md"))
);
return missing.length === 0 ? pass("Integration docs present", "Integration docs are present for all modules") : fail(
"Integration docs present",
`Missing integration docs for: ${missing.join(", ")}`,
"Add the missing integration documentation files."
);
}
checkErrorCatalog(projectRoot, modules) {
if (!this.documentationHasRun(projectRoot) || modules.length === 0) {
return pass(
"Error catalog present",
"Error catalogs are checked after documentation generation"
);
}
const missing = modules.filter(
(moduleName) => !existsSync18(join31(projectRoot, "docs/modules", moduleName, "error-catalog.md"))
);
return missing.length === 0 ? pass("Error catalog present", "Error catalogs are present for all modules") : fail(
"Error catalog present",
`Missing error catalogs for: ${missing.join(", ")}`,
"Add the missing module error catalogs."
);
}
checkMcp(projectRoot, profile) {
if (profile === null) {
return info(
MCP_CHECK_NAME,
"Project profile is unavailable, so no MCP servers can be recommended for this stack."
);
}
const recommended = getServersForStack(getPrimaryStack(profile), getLegacyCapabilities(profile)).filter((server) => server.name !== "figma").map((server) => server.name);
const found = readMcpServerNames(
join31(projectRoot, AdapterFactory.create("claude-code").getMcpPath())
);
return info(
MCP_CHECK_NAME,
`Recommended for this stack: ${listOrNone(recommended)}.` + (found === null ? "" : ` Found in .mcp.json: ${listOrNone(found)}.`)
);
}
checkSkillCache(projectRoot) {
const cacheDir = join31(projectRoot, PATHS.SKILL_CACHE_DIR);
if (!existsSync18(cacheDir)) {
return warn(
"Skill cache healthy",
"Skill cache directory is missing",
"Run skill-cache-manager.sh --clear-all to reset cache"
);
}
const corrupt = readdirSync3(cacheDir).filter((entry) => entry.endsWith(".json")).filter((entry) => {
try {
JSON.parse(readFileSync17(join31(cacheDir, entry), "utf8"));
return false;
} catch {
return true;
}
});
return corrupt.length === 0 ? pass("Skill cache healthy", "Skill cache directory is healthy") : warn(
"Skill cache healthy",
`Corrupt cache files detected: ${corrupt.join(", ")}`,
"Run skill-cache-manager.sh --clear-all to reset cache"
);
}
checkContextHitRate(projectRoot, profile) {
const path10 = join31(projectRoot, PATHS.CONTEXT_HIT_LOG);
if (!existsSync18(path10) || profile === null) {
return pass("Context hit rate acceptable", "No recent context logs yet");
}
try {
const entry = JSON.parse(readFileSync17(path10, "utf8"));
const hitRate = entry.hit_rate ?? 0;
const target = profile.efficiency.context_hit_rate_target ?? 0.7;
return hitRate >= target ? pass("Context hit rate acceptable", "Context hit rate meets the configured target") : warn(
"Context hit rate acceptable",
"Context hit rate is below the configured target",
"Reduce unnecessary context loading or improve context selection."
);
} catch {
return warn(
"Context hit rate acceptable",
"Context hit log is unreadable",
"Regenerate the context hit log with the tracking hook."
);
}
}
async buildEfficiencySummary(projectRoot) {
const path10 = join31(projectRoot, PATHS.CONTEXT_HIT_LOG);
let contextHitRate = 0;
let skillCacheHitRate;
if (existsSync18(path10)) {
try {
const entry = JSON.parse(readFileSync17(path10, "utf8"));
contextHitRate = entry.hit_rate ?? 0;
} catch {
contextHitRate = 0;
}
}
try {
skillCacheHitRate = (await new SkillCacheManager(join31(projectRoot, PATHS.SKILL_CACHE_DIR)).getStats()).hit_rate;
} catch {
skillCacheHitRate = 0;
}
return {
context_hit_rate: contextHitRate,
skill_cache_hit_rate: skillCacheHitRate,
mcp_usage_rate: 0
};
}
checkLeanRuleFootprint(projectRoot) {
const name = "Lean rule footprint acceptable";
const rulesRoot = join31(projectRoot, PATHS.RULES_DIR);
if (!existsSync18(rulesRoot)) {
return pass(name, "No rules directory to load \u2014 nothing to slim");
}
const fullRulesBytes = walk(rulesRoot).filter((file) => file.endsWith(".md")).reduce((sum, file) => sum + statSync4(file).size, 0);
const artifactPath = join31(projectRoot, PATHS.CONTEXT_SESSION_ARTIFACT);
if (!existsSync18(artifactPath)) {
return pass(
name,
"Lean rule artifact not generated yet \u2014 full rule load is the fallback until the next refresh"
);
}
const residentBytes = statSync4(artifactPath).size;
const pct = fullRulesBytes > 0 ? Math.round(residentBytes / fullRulesBytes * 100) : 0;
const detail = `Resident rule context is ${residentBytes} bytes vs ${fullRulesBytes} bytes for the full rule set (${pct}% of full)`;
return residentBytes < fullRulesBytes || fullRulesBytes === 0 ? pass(name, detail) : warn(
name,
`${detail} \u2014 lean loading is not reducing the resident footprint`,
"Ensure lean_rules is on and re-run `paqad-ai rag refresh-context` to recompose the lean artifact."
);
}
async checkCompiledRulesCurrent(projectRoot) {
const name = "Compiled rules are current";
return await isCompiledRulesStale(projectRoot) ? fail(
name,
"The compiled rule store is out of date with docs/instructions/rules/, so the session context can serve rules that have drifted from the authored rules.",
"Run `paqad-ai rag refresh-context` to recompile the rule store from docs/instructions/rules/."
) : pass(name, "Compiled rule store matches the authored rules");
}
checkSpecPipeline(projectRoot) {
const name = "Spec pipeline is healthy";
for (const fixture of PARITY_CORPUS) {
if (!checkSpecShape(fixture.markdown).ok) {
return fail(
name,
`Parser-parity fixture "${fixture.name}" no longer passes the S4 shape check.`,
"A freeze-parser change broke S4 parity \u2014 update the shared corpus and the S4 check together."
);
}
const spec = buildFeatureSpec({
spec_id: "S-doctor",
spec_file: "spec.md",
spec_markdown: fixture.markdown
});
if (spec.acceptance_criteria.length === 0 || spec.behaviour.length === 0) {
return fail(
name,
`Parser-parity fixture "${fixture.name}" is no longer ingested by the freeze parser.`,
"The freeze parser and the S4 shape check have drifted \u2014 reconcile them (FR-10.2)."
);
}
}
const config = readPipelineConfig(projectRoot);
if (config.final_review === "strict" && !config.enabled) {
return warn(
name,
"spec_pipeline_final_review is required but spec_pipeline_enabled is off \u2014 a required gate on a disabled pipeline never runs.",
"Enable the pipeline (spec_pipeline_enabled=true) or relax spec_pipeline_final_review."
);
}
return pass(name, "Parser-parity corpus holds and the enforcement config is coherent.");
}
checkSpecPipelineSettings(projectRoot) {
const config = readPipelineConfig(projectRoot);
const from = specPipelineSources(projectRoot);
const onOff = (on) => on ? "on" : "off";
const values = `spec pipeline ${onOff(config.enabled)} (${from.spec_pipeline_enabled}), experts ${onOff(config.experts_enabled)} (${from.spec_pipeline_experts_enabled}), adoption ${config.adoption} (${from.spec_pipeline_adoption}).`;
if (!config.enabled) {
return pass(
"Spec pipeline settings",
`${values} The pipeline is off, so specs are written by hand and no experts run.`
);
}
const kTokens = (n) => `${Math.round(n / 1e3)}k`;
const cost = expertsActive(config) ? ` The ${config.standing_experts.length} standing experts carry about ${kTokens(standingBudgetSum(config))} tokens of budget per spec (ceiling ${kTokens(config.token_ceiling)}).` : "";
return pass(
"Spec pipeline settings",
`${values} It runs on the graduated and full lanes; the fast lane never runs it.${cost} To switch off for the team, set pipeline.enabled: false, experts.enabled: false or hand_written_specs: warn in .paqad/configs/feature-development/specification.yaml; just for you, set spec_pipeline_enabled=false, spec_pipeline_experts_enabled=false or spec_pipeline_adoption=warn in .paqad/.config.`
);
}
checkVisualEvidence(projectRoot) {
const name = "Visual evidence is ready";
const config = resolveFrameworkConfig(projectRoot);
if (!config.features.visual_evidence) {
return [pass(name, "Visual evidence is off (default); nothing to check.")];
}
const results = visualEvidenceReadiness(projectRoot).map(
(problem) => warn(name, problem.detail, problem.remediation)
);
if (results.length === 0) {
results.push(pass(name, "Visual evidence is on and every prerequisite is in place."));
}
return results;
}
checkAuthoringConfig(projectRoot) {
const name = "Skill authoring settings are in range";
const problems = authoringConfigProblems(projectRoot);
if (problems.length === 0) {
return [pass(name, "Every skill authoring setting is in its allowed range.")];
}
return problems.map(
(problem) => warn(
name,
`${problem.key}=${problem.value} is out of range (allowed: ${problem.allowed}); paqad uses the default instead`,
`Set ${problem.key} to ${problem.allowed}, or remove it to use the default.`
)
);
}
checkExpertRoster(projectRoot) {
const name = "Expert roster config is coherent";
const config = readPipelineConfig(projectRoot);
const results = [];
const from = specPipelineSources(projectRoot);
if (config.experts_enabled && !config.enabled && from.spec_pipeline_experts_enabled !== "default") {
results.push(
warn(
name,
"spec_pipeline_experts_enabled is on but spec_pipeline_enabled is off \u2014 the expert roster never runs while the pipeline itself is off.",
"Enable the pipeline (spec_pipeline_enabled=true), or turn the experts flag off."
)
);
} else if (expertsActive(config) && config.clarification === "off") {
results.push(
warn(
name,
"spec_pipeline_experts_enabled is on but spec_pipeline_clarification is off \u2014 experts can surface questions, but the question round is disabled so they are dropped.",
"Set spec_pipeline_clarification to warn or strict, or turn the experts flag off."
)
);
} else {
results.push(
pass(
name,
expertsActive(config) ? "Expert roster is enabled and its config is coherent." : "Expert roster is off; nothing to enforce."
)
);
}
if (config.adoption === "strict" && !config.enabled && from.spec_pipeline_adoption !== "default") {
results.push(
warn(
"Spec pipeline adoption is coherent",
"adoption is strict but the pipeline is off; the setting does nothing",
"Enable spec_pipeline_enabled=true, or set spec_pipeline_adoption=warn."
)
);
}
for (const role of config.standing_experts_dropped) {
results.push(
warn(
"Standing experts are all expert roles",
`spec_pipeline_standing_experts names "${role}", which is not an expert; it is ignored`,
"Remove it from spec_pipeline_standing_experts, or name a role in the expert roster."
)
);
}
if (config.experts_enabled) {
const lensDir = join31(
getRuntimeRoot(),
"base",
"skills",
"expert-notes",
"references",
"lenses"
);
const missing = EXPERT_ROLES.filter((role) => !existsSync18(join31(lensDir, `${role}.md`)));
if (missing.length > 0) {
results.push(
fail(
"Expert lens files are shipped",
`the expert roster is on but these roles ship no lens: ${missing.join(", ")}`,
"Add the missing lens file(s) under runtime/base/skills/expert-notes/references/lenses/."
)
);
}
const standingSum = standingBudgetSum(config);
if (config.token_ceiling < standingSum + 6e3) {
results.push(
warn(
"Spec pipeline token ceiling fits the experts",
`expert slices will be clamped on most runs (the standing experts need ${standingSum} and one on-call expert about 6000); raise spec_pipeline_token_ceiling to at least ${standingSum + 6e3} or accept clamped briefs`,
`Raise spec_pipeline_token_ceiling to at least ${standingSum + 6e3}.`
)
);
}
}
return results;
}
checkClassificationOverrideRate(projectRoot) {
const path10 = join31(projectRoot, PATHS.AGENCY_CACHE_DIR, "classification-history.json");
if (!existsSync18(path10)) {
return pass(
"Classification override rate acceptable",
"No classification history recorded yet"
);
}
try {
const entries = JSON.parse(readFileSync17(path10, "utf8"));
const sample = entries.slice(-50);
const ratio = sample.length === 0 ? 0 : sample.filter((entry) => entry.high_override_rate).length / sample.length;
return ratio > 0.3 ? warn(
"Classification override rate acceptable",
`High override rate detected across recent classifications (${Math.round(ratio * 100)}%)`,
"Review pre-classification signals and reduce deterministic/LLM disagreement."
) : pass(
"Classification override rate acceptable",
"Classification override rate is within acceptable bounds"
);
} catch {
return warn(
"Classification override rate acceptable",
"Classification history is unreadable",
"Regenerate classification history by re-running recent classification flows."
);
}
}
documentationHasRun(projectRoot) {
return existsSync18(join31(projectRoot, PATHS.DOC_PROGRESS));
}
async checkRag(projectRoot, profile) {
if (profile === null) {
return [];
}
const intelligence = profile.intelligence;
const results = [];
if (!intelligence.rag_enabled) {
results.push(pass("RAG index present", "RAG is disabled"));
results.push(pass("RAG provider matches profile", "RAG is disabled"));
results.push(pass("RAG chunk index present", "RAG is disabled"));
results.push(pass("RAG chunk index current", "RAG is disabled"));
results.push(pass("RAG vector payload consistent", "RAG is disabled"));
results.push(pass("RAG retrieval ready", "RAG is disabled"));
results.push(pass("RAG model cache present", "RAG is disabled"));
results.push(pass("RAG vector gitignore present", "RAG is disabled"));
results.push(pass("RAG secrets gitignore present", "RAG is disabled"));
results.push(pass("RAG secret permissions acceptable", "RAG is disabled"));
return results;
}
const service = new RagService(projectRoot);
const status = await service.getStatus();
results.push(
status.index_present ? pass("RAG index present", "Vector index files are present") : warn("RAG index present", "Vector index files are missing", "Run `paqad-ai rag init`.")
);
results.push(
status.valid ? pass("RAG provider matches profile", "Stored RAG provider and model match the profile") : warn(
"RAG provider matches profile",
status.reason ?? "Stored RAG metadata does not match the profile",
"Run `paqad-ai rag rebuild` after changing provider or model."
)
);
const chunkIndexManager = new ChunkIndexManager(projectRoot);
const chunkIndex = await chunkIndexManager.load();
results.push(
chunkIndex ? pass("RAG chunk index present", "Chunk index is present") : warn(
"RAG chunk index present",
"Chunk index is missing",
"Run `paqad-ai rag rebuild` to regenerate the chunk index and vectors."
)
);
if (!chunkIndex) {
results.push(
warn(
"RAG chunk index current",
"Chunk index freshness could not be verified because the chunk index is missing",
"Run `paqad-ai rag rebuild` to regenerate the chunk index."
)
);
} else {
const stale = await chunkIndexManager.isStale(chunkIndex);
results.push(
stale.stale ? warn(
"RAG chunk index current",
`Chunk index is stale for ${stale.changedFiles.length} file(s)`,
"Run `paqad-ai rag rebuild` to resync the chunk index and vectors."
) : pass("RAG chunk index current", "Chunk index matches indexed source files")
);
}
const vectorConsistency = await this.checkRagVectorPayloadConsistency(projectRoot);
results.push(vectorConsistency.payload);
results.push(vectorConsistency.retrievalReady);
results.push(
intelligence.embedding_provider === "local" ? service.localModelCached(
intelligence.embedding_model ?? getDefaultEmbeddingModel("local")
) ? pass("RAG model cache present", "Local embedding model cache is present") : warn(
"RAG model cache present",
"Local embedding model cache is missing",
"Run `paqad-ai rag rebuild` to download and cache the local model."
) : pass("RAG model cache present", "Local model cache is not required for this provider")
);
results.push(
this.isPathIgnored(projectRoot, PATHS.VECTORS_DIR, true) ? pass("RAG vector gitignore present", "Vector index path is gitignored") : warn(
"RAG vector gitignore present",
`Vector index path is not gitignored: ${PATHS.VECTORS_DIR}`,
"Re-run `paqad-ai onboard` to refresh the managed `.paqad/.gitignore`."
)
);
results.push(
this.isPathIgnored(projectRoot, PATHS.SECRETS_ENV) ? pass("RAG secrets gitignore present", "Secrets file path is gitignored") : warn(
"RAG secrets gitignore present",
`Secrets file path is not gitignored: ${PATHS.SECRETS_ENV}`,
"Re-run `paqad-ai onboard` to refresh the managed `.paqad/.gitignore`."
)
);
const permissionWarning = getSecretPermissionWarning(projectRoot);
results.push(
permissionWarning === null ? pass("RAG secret permissions acceptable", "Secrets file permissions are acceptable") : warn(
"RAG secret permissions acceptable",
permissionWarning,
"Restrict `.paqad/secrets.env` to owner-only access."
)
);
const engine = describeOptionalEngine();
if (engine.state === "ready") {
results.push(pass("RAG engine installed", "The embedding engine is installed"));
} else if (engine.state === "installing") {
results.push(
warn(
"RAG engine installed",
"not ready: installing in the background; retrieval uses text search until it is ready",
"Re-run `paqad-ai doctor` shortly to confirm it finished."
)
);
} else if (engine.state === "install failed") {
results.push(
warn(
"RAG engine installed",
`The embedding engine install failed: ${engine.detail ?? "unknown error"}`,
engine.hint ?? engineInstallNetworkHint()
)
);
} else {
results.push(
warn(
"RAG engine installed",
"The embedding engine is not installed; retrieval uses text search",
"It installs automatically on first use inside Claude Code; otherwise run `paqad-ai rag rebuild`."
)
);
}
return results;
}
async checkRagVectorPayloadConsistency(projectRoot) {
const vectorIndex = new FileVectorIndex();
const payload = await vectorIndex.load(projectRoot);
const meta = await vectorIndex.loadMeta(projectRoot);
if (!payload || !meta) {
return {
payload: warn(
"RAG vector payload consistent",
"Vector payload or metadata is missing",
"Run `paqad-ai rag rebuild` to regenerate the vector index."
),
retrievalReady: warn(
"RAG retrieval ready",
"Retrieval is not ready because the vector index is incomplete",
"Run `paqad-ai rag rebuild` to regenerate the vector index."
)
};
}
const vectorLengths = new Set(payload.items.map((item) => item.vector.length));
const dimensionsMatch = vectorLengths.size <= 1 && vectorLengths.has(payload.dimensions);
const chunkCountMatches = payload.items.length === meta.chunk_count;
const payloadCheck = payload.items.length === 0 ? warn(
"RAG vector payload consistent",
"Vector index is empty",
"Run `paqad-ai rag rebuild` after confirming eligible source files are present."
) : dimensionsMatch && chunkCountMatches ? pass(
"RAG vector payload consistent",
"Vector payload dimensions and chunk counts are internally consistent"
) : warn(
"RAG vector payload consistent",
"Vector payload dimensions or chunk counts do not match metadata",
"Run `paqad-ai rag rebuild` to regenerate the vector index."
);
const retrievalReady = payload.items.length > 0 && dimensionsMatch && chunkCountMatches && meta.embedding_dimensions > 0 ? pass("RAG retrieval ready", "Vector index is populated and structurally queryable") : warn(
"RAG retrieval ready",
"Vector index is present but not structurally ready for reliable retrieval",
"Run `paqad-ai rag rebuild` to regenerate the vector index."
);
return { payload: payloadCheck, retrievalReady };
}
checkJsonArtifact(input) {
const path10 = join31(input.projectRoot, input.relativePath);
if (!existsSync18(path10)) {
return fail(input.name, `${input.relativePath} is missing`, input.missingRemediation);
}
try {
const parsed = JSON.parse(readFileSync17(path10, "utf8"));
const validation = this.validator.validate(input.schemaId, parsed);
return validation.valid ? pass(input.name, `${input.relativePath} is present and valid`) : fail(
input.name,
schemaFailureDetail(validation.errors, parsed) || `${input.relativePath} doesn't match its schema`,
input.invalidRemediation
);
} catch {
return fail(input.name, `${input.relativePath} is unreadable`, input.invalidRemediation);
}
}
};
function pointerSegments(pointer) {
return pointer.split("/").filter((segment) => segment !== "").map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~"));
}
function valueAtPointer(data, segments) {
let node = data;
for (const segment of segments) {
if (node === null || typeof node !== "object") return void 0;
node = node[segment];
}
return node;
}
function schemaIssueLine(issue, parsed) {
const segments = pointerSegments(issue.path);
const field = segments.join(".");
if (issue.keyword === "enum" && field !== "") {
const value = valueAtPointer(parsed, segments);
const shown = typeof value === "string" ? value : JSON.stringify(value);
return `${field}: ${shown} isn't an allowed value`;
}
return field === "" ? issue.message : `${field}: ${issue.message}`;
}
function schemaFailureDetail(issues, parsed) {
const named = issues.filter(
(issue) => issue.keyword !== "anyOf" && issue.message !== "must be null"
);
const shown = named.length > 0 ? named : issues;
return [...new Set(shown.map((issue) => schemaIssueLine(issue, parsed)))].join("; ");
}
function specPipelineSources(projectRoot) {
const knobs = resolveEffectiveConfig(projectRoot);
const sourceOf = (key) => {
const surface2 = knobs.find((knob) => knob.key === key).surface;
if (surface2.startsWith("env:")) return surface2.slice("env:".length);
if (surface2.startsWith("local ")) return surface2.slice("local ".length);
if (surface2.startsWith("team ")) return `.paqad/${surface2.slice("team ".length)}`;
return surface2;
};
return {
spec_pipeline_enabled: sourceOf("spec_pipeline_enabled"),
spec_pipeline_experts_enabled: sourceOf("spec_pipeline_experts_enabled"),
spec_pipeline_adoption: sourceOf("spec_pipeline_adoption")
};
}
var MCP_CHECK_NAME = "MCP servers (recommended)";
function readMcpServerNames(path10) {
if (!existsSync18(path10)) {
return null;
}
try {
const parsed = JSON.parse(readFileSync17(path10, "utf8"));
const servers = isPlainObject2(parsed) ? parsed.mcpServers : void 0;
return isPlainObject2(servers) ? Object.keys(servers) : [];
} catch {
return null;
}
}
function isPlainObject2(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function listOrNone(names) {
return names.length === 0 ? "none" : names.join(", ");
}
function pass(name, detail) {
return { name, status: "pass", detail };
}
function fail(name, detail, remediation) {
return { name, status: "fail", detail, remediation };
}
function info(name, detail) {
return { name, status: "info", detail };
}
function warn(name, detail, remediation) {
return { name, status: "warning", detail, remediation };
}
function deriveOverallStatus(checks) {
if (checks.some((check2) => check2.status === "fail")) {
return "fail";
}
if (checks.some((check2) => check2.status === "warning")) {
return "warning";
}
return "pass";
}
function isStale(timestampMs) {
return Date.now() - timestampMs > STALENESS_WINDOW_MS;
}
function walk(root) {
const results = [];
for (const entry of readdirSync3(root, { withFileTypes: true })) {
const path10 = join31(root, entry.name);
if (entry.isDirectory()) {
results.push(...walk(path10));
continue;
}
results.push(path10);
}
return results;
}
function relativeTo(root, path10) {
return relative7(root, path10).replace(/\\/g, "/");
}
// src/hud/index.ts
init_esm_shims();
// src/install/index.ts
init_esm_shims();
// src/install/bootstrap.ts
init_esm_shims();
import {
cpSync,
existsSync as existsSync19,
lstatSync,
mkdirSync as mkdirSync6,
readFileSync as readFileSync18,
readlinkSync as readlinkSync2,
rmSync as rmSync6,
symlinkSync,
writeFileSync as writeFileSync7
} from "fs";
import { dirname as dirname14, join as join32 } from "path";
function bootstrapFrameworkHome() {
const frameworkHome = resolveFrameworkInstallPath();
const runtimeRoot = getRuntimeRoot();
ensureFrameworkSymlink(runtimeRoot, frameworkHome);
try {
writeStageAgents({ pluginInstalled: pluginLoadState(null) === "live" });
} catch {
}
return { framework_home: frameworkHome };
}
function bootstrapFramework(projectRoot, options) {
if (options?.logger !== void 0) {
setEngineLogger(options.logger);
}
const { framework_home: frameworkHome } = bootstrapFrameworkHome();
writeFrameworkMetadata(projectRoot, VERSION);
ensureSchemaMarkerSync(projectRoot, VERSION);
return {
framework_home: frameworkHome,
project_root: projectRoot,
version: VERSION,
...discoveryPluginClash() ? { warnings: [DISCOVERY_CLASH_MESSAGE] } : {}
};
}
function ensureFrameworkSymlink(runtimeRoot, frameworkHome, env2 = process.env) {
mkdirSync6(dirname14(frameworkHome), { recursive: true });
if (isPluginRuntime(env2)) {
repointFrameworkLinkPluginAware(runtimeRoot, frameworkHome, env2);
return;
}
if (isExpectedRuntimeSymlink(runtimeRoot, frameworkHome)) {
return;
}
removeConflictingFrameworkPath(frameworkHome);
try {
symlinkSync(runtimeRoot, frameworkHome, frameworkSymlinkType());
} catch (error) {
if (error instanceof Error && "code" in error && error.code === "EEXIST" && isExpectedRuntimeSymlink(runtimeRoot, frameworkHome)) {
return;
}
throw error;
}
}
function isPluginRuntime(env2) {
const pluginRoot = env2.CLAUDE_PLUGIN_ROOT;
return typeof pluginRoot === "string" && pluginRoot.length > 0;
}
function isNpmRuntime(target) {
return target.includes("node_modules");
}
function isPluginCacheRuntime(target) {
return target.includes("/plugins/") || target.includes("\\plugins\\");
}
function stableRuntimeHome(env2) {
const data = env2.CLAUDE_PLUGIN_DATA;
return typeof data === "string" && data.length > 0 ? join32(data, "runtime") : null;
}
function linkTarget(path10) {
try {
return readlinkSync2(path10);
} catch {
return null;
}
}
var RUNTIME_COPY_PARTS = ["package.json", "dist", "runtime"];
function readPluginVersion(pluginRoot) {
try {
const parsed = JSON.parse(readFileSync18(join32(pluginRoot, "package.json"), "utf8"));
return typeof parsed.version === "string" && parsed.version.length > 0 ? parsed.version : null;
} catch {
return null;
}
}
function runtimeCopyVersion(copyRoot) {
const st = lstatSafe(copyRoot);
if (!st || st.isSymbolicLink() || !st.isDirectory()) {
return null;
}
try {
return readFileSync18(join32(copyRoot, "version"), "utf8").trim();
} catch {
return null;
}
}
function removeTree(path10) {
rmSync6(path10, { recursive: true, force: true });
}
function removeTreeQuietly(path10) {
try {
removeTree(path10);
} catch {
return;
}
}
function replaceRuntimeCopy(staging, copyRoot) {
const st = lstatSafe(copyRoot);
let retired = null;
if (st && st.isSymbolicLink()) {
rmSync6(copyRoot, { force: true, recursive: false });
} else if (st) {
retired = `${copyRoot}.old-${process.pid}`;
removeTree(retired);
renameWithRetrySync(copyRoot, retired, { remove: () => void 0 });
}
renameWithRetrySync(staging, copyRoot, { remove: removeTreeQuietly });
if (retired) {
removeTreeQuietly(retired);
}
}
function ensureStablePluginRuntime(pluginRuntime, env2) {
const copyRoot = stableRuntimeHome(env2);
if (!copyRoot) {
return pluginRuntime;
}
const pluginRoot = dirname14(pluginRuntime);
const linked = join32(copyRoot, "runtime");
const staging = `${copyRoot}.tmp-${process.pid}`;
try {
const version = readPluginVersion(pluginRoot);
if (!version) {
return pluginRuntime;
}
if (runtimeCopyVersion(copyRoot) === version && existsSync19(linked)) {
return linked;
}
removeTree(staging);
mkdirSync6(staging, { recursive: true });
for (const part of RUNTIME_COPY_PARTS) {
const from = join32(pluginRoot, part);
if (existsSync19(from)) {
cpSync(from, join32(staging, part), { recursive: true });
}
}
writeFileSync7(join32(staging, "version"), `${version}
`, "utf8");
replaceRuntimeCopy(staging, copyRoot);
return linked;
} catch {
removeTreeQuietly(staging);
return pluginRuntime;
}
}
function repointFrameworkLinkPluginAware(pluginRuntime, frameworkHome, env2) {
const stat4 = lstatSafe(frameworkHome);
if (stat4 && stat4.isDirectory() && !stat4.isSymbolicLink()) {
return;
}
const stable = ensureStablePluginRuntime(pluginRuntime, env2);
if (stat4 && stat4.isSymbolicLink()) {
const target = linkTarget(frameworkHome);
if (target) {
if (target === stable) {
return;
}
const targetStat = lstatSafe(target);
if (targetStat && target !== stableRuntimeHome(env2)) {
if (isNpmRuntime(target)) {
return;
}
if (!isPluginCacheRuntime(target) && target !== pluginRuntime) {
return;
}
}
}
}
try {
mkdirSync6(dirname14(frameworkHome), { recursive: true });
rmSync6(frameworkHome, { force: true, recursive: false });
symlinkSync(stable, frameworkHome, frameworkSymlinkType());
} catch {
}
}
function frameworkSymlinkType() {
return process.platform === "win32" ? "junction" : void 0;
}
function removeConflictingFrameworkPath(frameworkHome) {
const stat4 = lstatSafe(frameworkHome);
if (stat4 === void 0) {
return;
}
if (stat4.isDirectory() && !stat4.isSymbolicLink()) {
throw new Error(
`Refusing to replace existing framework home directory at ${frameworkHome}. Remove it manually or point PAQAD_FRAMEWORK_HOME at an empty path.`
);
}
rmSync6(frameworkHome, { force: true, recursive: false });
}
function isExpectedRuntimeSymlink(runtimeRoot, frameworkHome) {
const stat4 = lstatSafe(frameworkHome);
if (stat4 === void 0 || !stat4.isSymbolicLink()) {
return false;
}
try {
return readlinkSync2(frameworkHome) === runtimeRoot;
} catch {
return false;
}
}
function lstatSafe(path10) {
try {
return lstatSync(path10);
} catch {
return void 0;
}
}
var __test = {
ensureFrameworkSymlink,
isPluginRuntime,
repointFrameworkLinkPluginAware,
ensureStablePluginRuntime,
stableRuntimeHome,
isNpmRuntime,
isPluginCacheRuntime
};
// src/install/version-report.ts
init_esm_shims();
var VERSION_UNKNOWN = "version unknown";
var MIN_CONSUMER_VERSION = "1.0.0";
var DEPRECATED_AS_OF = void 0;
function normalizeEngineVersion(raw) {
if (typeof raw !== "string") {
return VERSION_UNKNOWN;
}
const trimmed = raw.trim();
if (trimmed === "" || trimmed === "__PKG_VERSION__") {
return VERSION_UNKNOWN;
}
return trimmed;
}
var memoizedReport;
function getEngineVersionReport() {
if (memoizedReport === void 0) {
memoizedReport = Object.freeze({
engineVersion: normalizeEngineVersion("1.128.1"),
minConsumerVersion: MIN_CONSUMER_VERSION,
deprecatedAsOf: DEPRECATED_AS_OF
});
}
return memoizedReport;
}
// src/install/consumer-compatibility.ts
init_esm_shims();
function parseMajor(version) {
const match = /^\s*v?(\d+)/u.exec(version);
return match ? Number.parseInt(match[1], 10) : Number.NaN;
}
function compareConsumerCompatibility(consumerVersion, report) {
if (report.engineVersion === VERSION_UNKNOWN) {
return "engine-version-unknown";
}
const consumerMajor = parseMajor(consumerVersion);
if (Number.isNaN(consumerMajor)) {
return "engine-too-new";
}
const minConsumerMajor = parseMajor(report.minConsumerVersion);
if (!Number.isNaN(minConsumerMajor) && consumerMajor < minConsumerMajor) {
return "engine-too-new";
}
const engineMajor = parseMajor(report.engineVersion);
if (!Number.isNaN(engineMajor) && consumerMajor > engineMajor) {
return "engine-too-old";
}
return "ok";
}
// src/introspection/index.ts
init_esm_shims();
// src/introspection/ecosystems/types.ts
init_esm_shims();
// src/mcp/index.ts
init_esm_shims();
// src/mcp/cleanup.ts
init_esm_shims();
import { appendFileSync, existsSync as existsSync20, mkdirSync as mkdirSync7, readFileSync as readFileSync19, rmSync as rmSync7 } from "fs";
import { dirname as dirname15, join as join33 } from "path";
// src/mcp/config-manager.ts
init_esm_shims();
var LEGACY_MCP_OUTPUT_PATHS = {
"claude-code": ".claude/settings.mcp.json",
"codex-cli": ".codex/mcp.json",
antigravity: ".antigravity/mcp.json",
"gemini-cli": ".gemini/mcp.json",
junie: ".junie/mcp/mcp.json",
cursor: ".cursor/mcp.json",
"github-copilot": ".vscode/mcp.json",
windsurf: ".windsurf/mcp.json",
continue: ".continue/mcp.json",
aider: "aider.mcp.json",
aiassistant: ".aiassistant/mcp.json"
};
var McpConfigManager = class {
registry = new McpServerRegistry();
generate(profile) {
const why = `${getPrimaryStack(profile)} project`;
const recommendations = {
servers: this.registry.forProfile(profile).map((server) => ({
name: server.name,
provides: server.provides,
replaces: server.replaces,
why
}))
};
return {
path: PATHS.MCP_RECOMMENDATIONS,
content: JSON.stringify(recommendations, null, 2)
};
}
};
// src/mcp/cleanup.ts
var PAQAD_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["mcpServers", "resolved_artifacts"]);
var REAL_SERVER_KEYS = /* @__PURE__ */ new Set([
"command",
"url",
"type",
"serverUrl",
"args",
"env",
"headers",
"transport"
]);
function cleanupLegacyMcpFiles(projectRoot, options = {}) {
const result2 = { deleted: [], kept: [] };
for (const path10 of new Set(Object.values(LEGACY_MCP_OUTPUT_PATHS))) {
const absolute = join33(projectRoot, path10);
if (!existsSync20(absolute)) {
continue;
}
const verdict2 = inspect(absolute);
if (verdict2 === UNMARKED) {
result2.kept.push(path10);
continue;
}
const reason2 = verdict2 ?? deleteRefusal(path10, options);
if (reason2) {
result2.kept.push(path10);
logKept(projectRoot, path10, reason2);
continue;
}
try {
rmSync7(absolute);
result2.deleted.push(path10);
} catch (error) {
result2.kept.push(path10);
logKept(projectRoot, path10, `delete failed: ${errorMessage(error)}`);
}
}
return result2;
}
var UNMARKED = /* @__PURE__ */ Symbol("unmarked");
function inspect(absolute) {
let parsed;
try {
parsed = JSON.parse(readFileSync19(absolute, "utf8"));
} catch {
return UNMARKED;
}
if (!isRecord4(parsed) || !("resolved_artifacts" in parsed)) {
return UNMARKED;
}
if (!Array.isArray(parsed.resolved_artifacts)) {
return "resolved_artifacts is not a list";
}
const foreignTopLevel = Object.keys(parsed).filter((key) => !PAQAD_TOP_LEVEL_KEYS.has(key));
if (foreignTopLevel.length > 0) {
return `holds keys paqad never wrote: ${foreignTopLevel.join(", ")}`;
}
const servers = parsed.mcpServers ?? {};
if (!isRecord4(servers)) {
return "mcpServers is not an object";
}
const configured = Object.entries(servers).filter(
([, server]) => !isRecord4(server) || Object.keys(server).some((key) => REAL_SERVER_KEYS.has(key))
).map(([name]) => name);
if (configured.length > 0) {
return `holds configured server(s): ${configured.join(", ")}`;
}
return null;
}
function deleteRefusal(path10, options) {
if (!options.canDelete) {
return null;
}
try {
return options.canDelete(path10) ? null : "this command may not delete it (a tracked file); left for onboard or update";
} catch (error) {
return `delete check failed: ${errorMessage(error)}`;
}
}
function logKept(projectRoot, path10, reason2) {
const logPath = join33(projectRoot, PATHS.MCP_CLEANUP_LOG);
try {
mkdirSync7(dirname15(logPath), { recursive: true });
appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} kept ${path10}: ${reason2}
`);
} catch (error) {
process.stderr.write(
`paqad: could not record MCP cleanup for ${path10}: ${errorMessage(error)}
`
);
}
}
function isRecord4(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function errorMessage(error) {
return error instanceof Error ? error.message : String(error);
}
// src/mcp/decision-matrix.ts
init_esm_shims();
var MCP_MAPPING = {
routes: "laravel-boost",
models: "laravel-boost",
services: "laravel-boost",
schema: "database-inspector",
indexes: "database-inspector",
"foreign-keys": "database-inspector",
"query-plans": "database-inspector",
widgets: "dart-mcp",
dependencies: "dart-mcp",
"design-specs": "figma"
};
var SCRIPT_MAPPING = {
routes: "extract-routes.sh",
models: "extract-models.sh",
events: "extract-events.sh",
"error-codes": "extract-error-codes.sh"
};
var DataRetrievalDecider = class {
constructor(availableMcp = [], availableScripts = []) {
this.availableMcp = availableMcp;
this.availableScripts = availableScripts;
}
availableMcp;
availableScripts;
decide(dataNeeded) {
const mcpProvider = this.findMcpProvider(dataNeeded);
if (mcpProvider) {
return {
type: "mcp",
server: mcpProvider,
estimated_token_savings: 1200
};
}
const script = this.findScript(dataNeeded);
if (script) {
return {
type: "script",
script,
estimated_token_savings: 400
};
}
return {
type: "llm-read",
reason: `No MCP or script available for: ${dataNeeded}`,
estimated_token_savings: 0
};
}
findMcpProvider(dataNeeded) {
const server = MCP_MAPPING[dataNeeded];
return server && this.availableMcp.includes(server) ? server : void 0;
}
findScript(dataNeeded) {
const script = SCRIPT_MAPPING[dataNeeded];
return script && this.availableScripts.includes(script) ? script : void 0;
}
};
// src/document/index.ts
init_esm_shims();
// src/document/pipeline.ts
init_esm_shims();
// src/document/workflow.ts
init_esm_shims();
import { mkdir as mkdir17, readFile as readFile19, readdir as readdir4, writeFile as writeFile18 } from "fs/promises";
import { dirname as dirname17, join as join38, relative as relative9 } from "path";
// src/onboarding/registry-generator.ts
init_esm_shims();
import { readFile as readFile15, readdir as readdir3, writeFile as writeFile15 } from "fs/promises";
import { basename as basename4, join as join34, relative as relative8 } from "path";
var import_yaml6 = __toESM(require_dist(), 1);
var TECHNICAL_LAYER_NAMES = /* @__PURE__ */ new Set([
"adapters",
"api",
"cache",
"cli",
"components",
"controllers",
"core",
"database",
"hooks",
"http",
"https",
"grpc",
"rest",
"graphql",
"lib",
"middleware",
"models",
"pipeline",
"providers",
"queries",
"repository",
"resolver",
"routes",
"schemas",
"services",
"src",
"types",
"utils",
"validators"
]);
var TECHNICAL_SIGNAL_NAMES = /* @__PURE__ */ new Set([
"auth",
"authorization",
"authentication",
"base",
"abstract",
"exception",
"exceptions",
"error",
"errors",
"event",
"events",
"listener",
"listeners",
"job",
"jobs",
"queue",
"queues",
"notification",
"notifications",
"command",
"commands",
"console",
"helper",
"helpers",
"support",
"trait",
"traits",
"interface",
"interfaces",
"contract",
"contracts",
"migration",
"migrations",
"seeder",
"seeders",
"seed",
"test",
"tests",
"spec",
"specs",
"testing",
"config",
"configuration",
"setting",
"settings",
"lang",
"translation",
"translations",
"locale",
"provider",
"request",
"requests",
"resource",
"resources",
"policy",
"policies",
"gate",
"observer",
"observers",
"rule",
"rules",
"action",
"actions",
"handler",
"handlers",
"index",
"main",
"app",
"application"
]);
function toSlug(name) {
return name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
}
function titleCase(name) {
return name.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}
function isBusinessName(name) {
return !TECHNICAL_LAYER_NAMES.has(name.toLowerCase());
}
async function listTopLevelDirs(root) {
try {
const entries = await readdir3(root, { withFileTypes: true });
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
} catch {
return [];
}
}
async function listFilesWithExtension(dir, ext) {
const results = [];
try {
const entries = await readdir3(dir, { withFileTypes: true });
for (const entry of entries) {
const name = entry.name.toString();
if (entry.isDirectory() && !name.startsWith(".")) {
const sub = await listFilesWithExtension(join34(dir, name), ext);
results.push(...sub.map((f) => join34(name, f)));
} else if (entry.isFile() && name.endsWith(ext)) {
results.push(name);
}
}
} catch {
}
return results;
}
function isBusinessSignalName(name) {
const lower = name.toLowerCase();
return name.length >= 3 && isBusinessName(name) && !TECHNICAL_SIGNAL_NAMES.has(lower);
}
async function extractModulesFromSignals(projectRoot) {
const nameMap = /* @__PURE__ */ new Map();
function add(rawName, sourcePath) {
if (!isBusinessSignalName(rawName)) return;
const slug = toSlug(rawName);
if (!slug) return;
if (!nameMap.has(slug)) nameMap.set(slug, []);
nameMap.get(slug).push(toPosixPath(sourcePath));
}
for (const relDir of [
"app/Http/Controllers",
"app/Controllers",
"src/Controller",
"src/Controllers"
]) {
const files = await listFilesWithExtension(join34(projectRoot, relDir), ".php");
for (const file of files) {
const stem = basename4(file, ".php").replace(/Controller$/, "");
add(stem, `${relDir}/${file}`);
}
}
for (const relDir of ["app/Models", "app/Entities"]) {
const files = await listFilesWithExtension(join34(projectRoot, relDir), ".php");
for (const file of files) {
add(basename4(file, ".php"), `${relDir}/${file}`);
}
}
const phpServiceFiles = await listFilesWithExtension(join34(projectRoot, "app/Services"), ".php");
for (const file of phpServiceFiles) {
const stem = basename4(file, ".php").replace(/Service$/, "") || basename4(file, ".php");
add(stem, `app/Services/${file}`);
}
for (const relDir of ["src/services", "src/modules"]) {
for (const ext of [".ts", ".js"]) {
const files = await listFilesWithExtension(join34(projectRoot, relDir), ext);
for (const file of files) {
const stem = basename4(file, ext).replace(/Service$/, "") || basename4(file, ext);
add(stem, `${relDir}/${file}`);
}
}
}
for (const relDir of ["src/models", "src/entities"]) {
for (const ext of [".ts", ".js"]) {
const files = await listFilesWithExtension(join34(projectRoot, relDir), ext);
for (const file of files) {
add(basename4(file, ext), `${relDir}/${file}`);
}
}
}
for (const relDir of ["pages", "src/pages", "app/pages", "src/views", "resources/views"]) {
const dirs = await listTopLevelDirs(join34(projectRoot, relDir));
for (const name of dirs) {
if (isBusinessSignalName(name)) {
add(name, `${relDir}/${name}`);
}
}
}
return Array.from(nameMap.entries()).map(([slug, paths]) => ({
name: titleCase(slug.replace(/-/g, " ")),
slug,
paths
}));
}
async function generateInitialRegistries(projectRoot) {
const modules = await discoverModules(projectRoot);
return [
{
path: ".paqad/indexes/registry-status.json",
content: JSON.stringify(
{
generated: true,
modules,
generated_at: (/* @__PURE__ */ new Date()).toISOString()
},
null,
2
),
autoUpdate: true
},
{
path: PATHS.GLOSSARY,
content: "# Glossary\n\n",
autoUpdate: false
},
...REGISTRIES.map((registry) => ({
path: join34(PATHS.REGISTRIES_DIR, registry),
content: registry === "module-registry.md" ? buildModuleRegistry(modules) : `# ${registry}
`,
autoUpdate: false
}))
];
}
async function discoverModules(projectRoot) {
const map = await loadModuleMap(projectRoot);
if (map !== null && map.modules.length > 0) {
return map.modules.map((m) => m.slug);
}
const candidates = [
join34(projectRoot, "docs/modules"),
join34(projectRoot, "app"),
join34(projectRoot, "lib"),
join34(projectRoot, "src")
];
const modules = /* @__PURE__ */ new Set(["core"]);
for (const root of candidates) {
try {
const entries = await readdir3(root, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory()) {
continue;
}
const name = entry.name;
if (name !== "" && !name.startsWith(".")) {
modules.add(name);
}
}
} catch {
continue;
}
}
return Array.from(modules).sort();
}
async function discoverBusinessModules(projectRoot, hintModuleNames = []) {
const existing = await loadModuleMap(projectRoot);
const lockedModules = /* @__PURE__ */ new Map();
const lockedFeatures = /* @__PURE__ */ new Map();
if (existing !== null) {
for (const mod of existing.modules) {
if (!mod.auto_update_module_name) {
lockedModules.set(mod.slug, mod);
}
const featureMap = /* @__PURE__ */ new Map();
for (const feat of mod.features) {
if (!feat.auto_update_feature_name) {
featureMap.set(feat.slug, feat);
}
}
if (featureMap.size > 0) {
lockedFeatures.set(mod.slug, featureMap);
}
}
}
const entries = [];
for (const hint of hintModuleNames) {
const slug = toSlug(hint);
if (!slug || entries.some((e) => e.slug === slug)) continue;
if (lockedModules.has(slug)) {
entries.push(lockedModules.get(slug));
} else {
entries.push(buildEntry(hint, slug, "inferred", "high", [], lockedFeatures.get(slug)));
}
}
const nativeModuleDirs = [
join34(projectRoot, "app", "Modules"),
join34(projectRoot, "app", "Domain"),
join34(projectRoot, "src", "modules"),
join34(projectRoot, "src", "domain")
];
for (const dir of nativeModuleDirs) {
const names = await listTopLevelDirs(dir);
for (const name of names) {
if (!isBusinessName(name)) continue;
const slug = toSlug(name);
if (lockedModules.has(slug)) {
entries.push(lockedModules.get(slug));
continue;
}
const sourcePath = toPosixPath(join34(relative8(projectRoot, dir), name));
entries.push(
buildEntry(name, slug, "codebase_native", "high", [sourcePath], lockedFeatures.get(slug))
);
}
}
const packageDirs = [
join34(projectRoot, "packages"),
join34(projectRoot, "apps"),
join34(projectRoot, "services")
];
for (const dir of packageDirs) {
const names = await listTopLevelDirs(dir);
for (const name of names) {
if (!isBusinessName(name)) continue;
const slug = toSlug(name);
if (entries.some((e) => e.slug === slug)) continue;
if (lockedModules.has(slug)) {
entries.push(lockedModules.get(slug));
continue;
}
const sourcePath = toPosixPath(join34(relative8(projectRoot, dir), name));
entries.push(
buildEntry(name, slug, "codebase_native", "medium", [sourcePath], lockedFeatures.get(slug))
);
}
}
const inferCandidates = [
join34(projectRoot, "app"),
join34(projectRoot, "src"),
join34(projectRoot, "lib")
];
for (const dir of inferCandidates) {
const names = await listTopLevelDirs(dir);
for (const name of names) {
if (!isBusinessName(name)) continue;
const slug = toSlug(name);
if (entries.some((e) => e.slug === slug)) continue;
if (lockedModules.has(slug)) {
entries.push(lockedModules.get(slug));
continue;
}
const sourcePath = toPosixPath(join34(relative8(projectRoot, dir), name));
entries.push(
buildEntry(name, slug, "inferred", "medium", [sourcePath], lockedFeatures.get(slug))
);
}
}
if (entries.length === 0) {
const signalResults = await extractModulesFromSignals(projectRoot);
for (const { name, slug, paths } of signalResults) {
if (lockedModules.has(slug)) {
entries.push(lockedModules.get(slug));
} else {
entries.push(buildEntry(name, slug, "inferred", "low", paths, lockedFeatures.get(slug)));
}
}
}
for (const [slug, lockedMod] of lockedModules) {
if (!entries.some((e) => e.slug === slug)) {
entries.push(lockedMod);
}
}
if (entries.length === 0) {
entries.push(buildEntry("Core", "core", "inferred", "low", [], void 0));
}
return entries;
}
function buildEntry(rawName, slug, derivation, confidence, sourcePaths, lockedFeaturesMap) {
const name = titleCase(rawName);
const lockedFeaturesList = lockedFeaturesMap ? Array.from(lockedFeaturesMap.values()) : [];
return {
name,
slug,
auto_update_module_name: true,
derivation,
confidence,
source_paths: sourcePaths,
evidence: {},
features: lockedFeaturesList
};
}
async function generateModuleMapYaml(projectRoot, hintModuleNames = []) {
let existingRaw;
try {
existingRaw = await readFile15(join34(projectRoot, PATHS.MODULE_MAP), "utf8");
} catch {
existingRaw = null;
}
const modules = await discoverBusinessModules(projectRoot, hintModuleNames);
if (existingRaw !== null) {
const doc = import_yaml6.default.parseDocument(existingRaw);
doc.set("last_updated_at", (/* @__PURE__ */ new Date()).toISOString());
const existingSeq = doc.get("modules", true);
const existingNodesBySlug = /* @__PURE__ */ new Map();
if (import_yaml6.default.isSeq(existingSeq)) {
for (const item of existingSeq.items) {
if (import_yaml6.default.isMap(item)) {
const slug = item.get("slug");
if (typeof slug === "string") {
existingNodesBySlug.set(slug, item);
}
}
}
}
const newSeq = new import_yaml6.default.YAMLSeq();
for (const mod of modules) {
const existingNode = existingNodesBySlug.get(mod.slug);
if (existingNode !== void 0) {
if (mod.auto_update_module_name) {
existingNode.set("name", mod.name);
existingNode.set("derivation", mod.derivation);
existingNode.set("confidence", mod.confidence);
existingNode.set("source_paths", mod.source_paths);
}
existingNode.set("features", mod.features);
newSeq.add(existingNode);
} else {
newSeq.add(doc.createNode(mod));
}
}
doc.set("modules", newSeq);
return doc.toString();
}
const map = {
version: 1,
last_updated_at: (/* @__PURE__ */ new Date()).toISOString(),
domain_glossary: {
preferred_terms: [],
synonyms: {},
notes: ""
},
modules
};
return serializeModuleMap(map);
}
function serializeModuleMap(map) {
return import_yaml6.default.stringify(map, { indent: 2, lineWidth: 0 });
}
async function loadModuleMap(projectRoot) {
try {
const raw = await readFile15(join34(projectRoot, PATHS.MODULE_MAP), "utf8");
return parseModuleMapYaml(raw);
} catch {
return null;
}
}
async function writeModuleMap(projectRoot, yaml) {
await writeFile15(join34(projectRoot, PATHS.MODULE_MAP), yaml, "utf8");
}
function parseModuleMapYaml(raw) {
const parsed = import_yaml6.default.parse(raw);
if (typeof parsed !== "object" || parsed === null) {
throw new Error("Invalid module map YAML: expected a mapping at the document root");
}
const glossaryRaw = typeof parsed["domain_glossary"] === "object" && parsed["domain_glossary"] !== null ? parsed["domain_glossary"] : {};
const modules = (Array.isArray(parsed["modules"]) ? parsed["modules"] : []).map(
(m) => {
const mod = typeof m === "object" && m !== null ? m : {};
const evidenceRaw = typeof mod["evidence"] === "object" && mod["evidence"] !== null ? mod["evidence"] : {};
const features = (Array.isArray(mod["features"]) ? mod["features"] : []).map((f) => {
const feat = typeof f === "object" && f !== null ? f : {};
return {
name: String(feat["name"] ?? ""),
slug: String(feat["slug"] ?? ""),
auto_update_feature_name: feat["auto_update_feature_name"] !== false,
derivation: feat["derivation"] ?? "inferred",
confidence: feat["confidence"] ?? "medium",
source_paths: Array.isArray(feat["source_paths"]) ? feat["source_paths"].map(String) : []
};
});
return {
name: String(mod["name"] ?? ""),
slug: String(mod["slug"] ?? ""),
auto_update_module_name: mod["auto_update_module_name"] !== false,
derivation: mod["derivation"] ?? "inferred",
confidence: mod["confidence"] ?? "medium",
source_paths: Array.isArray(mod["source_paths"]) ? mod["source_paths"].map(String) : [],
evidence: {
routes: Array.isArray(evidenceRaw["routes"]) ? evidenceRaw["routes"].map(String) : void 0,
tables: Array.isArray(evidenceRaw["tables"]) ? evidenceRaw["tables"].map(String) : void 0,
symbols: Array.isArray(evidenceRaw["symbols"]) ? evidenceRaw["symbols"].map(String) : void 0
},
features
};
}
);
return {
version: typeof parsed["version"] === "number" ? parsed["version"] : 1,
last_updated_at: typeof parsed["last_updated_at"] === "string" ? parsed["last_updated_at"] : (/* @__PURE__ */ new Date()).toISOString(),
domain_glossary: {
preferred_terms: Array.isArray(glossaryRaw["preferred_terms"]) ? glossaryRaw["preferred_terms"].map(String) : [],
synonyms: typeof glossaryRaw["synonyms"] === "object" && glossaryRaw["synonyms"] !== null ? glossaryRaw["synonyms"] : {},
notes: typeof glossaryRaw["notes"] === "string" ? glossaryRaw["notes"] : ""
},
modules
};
}
function buildModuleRegistry(modules) {
return ["# module-registry.md", "", ...modules.map((module) => `- ${module}`), ""].join("\n");
}
// src/stack-docs/generator.ts
init_esm_shims();
import { mkdir as mkdir15, readFile as readFile16, rm as rm2, writeFile as writeFile16 } from "fs/promises";
import { join as join35 } from "path";
// src/rules-discovery/text.ts
init_esm_shims();
import { createHash as createHash6 } from "crypto";
var HTML_COMMENT_RE = /<!--[\s\S]*?(?:--!?>|$)/g;
var STRAY_MARKER_RE = /@rule\s+RL-[0-9a-f]+(?:\s+discovered:\S+)?/gi;
var SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
function cleanDiscoveredText(input) {
return input.replace(HTML_COMMENT_RE, " ").replace(/--!?>/g, " ").replace(STRAY_MARKER_RE, " ").replace(/\s+/g, " ").trim().replace(/^[-*]\s+/, "");
}
function capLine(text2, max) {
if (text2.length <= max) return text2;
return `${text2.slice(0, max - 1).trimEnd()}\u2026`;
}
function normalizeForMatch(text2) {
return cleanDiscoveredText(text2).toLowerCase().replace(/[`*_"'.,;:!?()]/g, "").replace(/\s+/g, " ").trim();
}
function isSlug(value) {
return SLUG_RE.test(value) && value.length <= 64;
}
function sha256Text(text2) {
return createHash6("sha256").update(text2).digest("hex");
}
// src/stack-docs/managed-block.ts
init_esm_shims();
// src/core/text/marker-block.ts
init_esm_shims();
function replaceMarkerBlock(existing, begin, end, block) {
const beginIdx = existing.indexOf(begin);
const endIdx = existing.indexOf(end);
if (beginIdx === -1 || endIdx <= beginIdx) {
return null;
}
return `${existing.slice(0, beginIdx)}${block}${existing.slice(endIdx + end.length)}`;
}
// src/stack-docs/managed-block.ts
function managedBlockMarkers(name) {
return {
begin: `<!-- paqad:stack:${name}:start -->`,
end: `<!-- paqad:stack:${name}:end -->`
};
}
function upsertManagedBlock(existing, name, body) {
const eol = existing.includes("\r\n") ? "\r\n" : "\n";
const { begin, end } = managedBlockMarkers(name);
const block = [begin, ...body.split("\n"), end].join(eol);
const replaced = replaceMarkerBlock(existing, begin, end, block);
if (replaced !== null) {
return replaced;
}
if (existing.length === 0) {
return `${block}${eol}`;
}
const separator = existing.endsWith("\n") ? eol : `${eol}${eol}`;
return `${existing}${separator}${block}${eol}`;
}
function escapeDocText(value) {
return value.replace(/\s+/g, " ").trim().replace(/\\/g, "\\\\").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\|/g, "\\|");
}
// src/stack-docs/generator.ts
async function writeStackArtifacts(projectRoot, snapshot, previousSnapshot, options = {}) {
const existingDrift = await readExistingDrift(projectRoot);
const computedDrift = compareStackProfiles(previousSnapshot?.profile ?? null, snapshot.profile, {
previous: previousSnapshot?.packages,
current: snapshot.packages
});
const drift = computedDrift.status === "no-drift" && existingDrift !== null ? existingDrift : computedDrift;
const sanitizedSnapshot = sanitizeStackSnapshotRepository(projectRoot, snapshot);
await writeFile16(
join35(projectRoot, PATHS.STACK_SNAPSHOT),
`${JSON.stringify(sanitizedSnapshot, null, 2)}
`
);
await writeFile16(join35(projectRoot, PATHS.STACK_DRIFT), `${JSON.stringify(drift, null, 2)}
`);
if (!options.writeHumanDocs) {
return drift;
}
await mkdir15(join35(projectRoot, PATHS.FRAMEWORK_STACK_DIR), { recursive: true });
const stackDir = join35(projectRoot, PATHS.FRAMEWORK_STACK_DIR);
await writeFile16(join35(stackDir, "overview.md"), await buildOverview(projectRoot, snapshot, drift));
await writeFile16(join35(stackDir, "frameworks.md"), await buildFrameworks(projectRoot, snapshot));
await writeFile16(join35(stackDir, "dependencies.md"), buildDependencies(snapshot));
await writeFile16(join35(stackDir, "tooling.md"), buildTooling(snapshot));
await writeFile16(join35(stackDir, "version-rules.md"), buildVersionRules(snapshot, drift));
await writeFile16(join35(stackDir, "sources.md"), buildSources(snapshot));
await writeFile16(join35(stackDir, "drift-report.md"), buildDriftReport(drift));
await writeAnalyticsDoc(projectRoot, stackDir);
return drift;
}
async function writeAnalyticsDoc(projectRoot, stackDir) {
const docPath = join35(stackDir, "analytics.md");
let flagEnabled;
try {
flagEnabled = resolveFrameworkConfig(projectRoot).features.analytics_instrumentation;
} catch {
flagEnabled = false;
}
if (!flagEnabled) {
try {
await rm2(docPath, { force: true });
} catch {
}
return;
}
await writeFile16(docPath, buildAnalytics(projectRoot));
}
function buildAnalytics(projectRoot) {
const detection = detectAnalyticsProvider(projectRoot);
const detectionLines = detection ? [
`- Provider: **${detection.providerDisplay}** (\`${detection.provider}\`)`,
`- Confidence: \`${detection.confidence}\``,
`- Observed naming convention: ${detection.convention ? `\`${detection.convention}\`` : "_none observed yet_"}`
].join("\n") : "- No analytics provider detected yet. Add one and re-run onboarding to populate this.";
return `# Analytics
Analytics instrumentation is **enabled** for this project (\`analytics_instrumentation\`).
paqad treats analytics as a **tracking plan as code**: every feature instruments its events,
each event is documented as a reviewed, versioned per-event doc, and every new event is
governed through a Decision Pause packet \u2014 so the team keeps a shared, attributed record of
what is tracked and why, reviewed in the normal PR.
## Detected provider
${detectionLines}
## How events are governed
Every tracked event carries a governance triple:
1. **Decision packet** (who / why) \u2014 every new event opens a Decision Pause packet capturing
the proposed name + normalized slug, provider(s), feature, and rationale, resolved and
committed with the PR.
2. **Per-event doc** (what it means) \u2014 \`docs/modules/{module}/analytics/{feature}/{event}.md\`,
one doc per event with a section per provider. The filename is a normalized slug; the exact
event string is recorded inside, so casing-variant duplicates collapse to one doc.
3. **AC + traceability** (proof) \u2014 one \`AC-TRACK\` per event, proven against the delivering
code and its doc; an unproven event surfaces as \`TR-UNTESTED-PROMISE\`.
## Convention
Pick one naming convention and be 100% consistent (object-action and past tense are common
defaults, not rigid rules). No variable data in event names \u2014 dynamic values are properties.
## Honest limits
This is PR/review-time governance via doc + AC existence. It is **not** type-safe codegen, not
ingestion-time or real-time blocking, and not PII redaction at capture \u2014 those live at your CDP.
`;
}
async function readExistingDrift(projectRoot) {
try {
return JSON.parse(
await readFile16(join35(projectRoot, PATHS.STACK_DRIFT), "utf8")
);
} catch {
return null;
}
}
async function buildOverview(projectRoot, snapshot, drift) {
const manifests = new Map(
getPacksForFrameworks(snapshot.profile.frameworks, projectRoot).map((pack) => [
pack.manifest.name,
pack.manifest
])
);
const frameworkSummary = snapshot.profile.frameworks.map((framework) => manifests.get(framework)?.display_name ?? framework).join(", ");
return `# Stack Overview
- Generated at: \`${snapshot.generated_at}\`
- Profile: ${summarizeStack(snapshot.profile)}
- Drift status: \`${drift.status}\`
- Frameworks: ${frameworkSummary ? frameworkSummary.split(", ").map((value) => `\`${value}\``).join(", ") : "none"}
- Traits: ${snapshot.profile.traits.map((value) => `\`${value}\``).join(", ") || "none"}
`;
}
async function buildFrameworks(projectRoot, snapshot) {
const packs = new Map(
getPacksForFrameworks(snapshot.profile.frameworks, projectRoot).map((pack) => [
pack.manifest.name,
pack
])
);
const lines = ["# Frameworks", ""];
for (const framework of snapshot.profile.frameworks) {
const pack = packs.get(framework);
const manifest = pack?.manifest;
const bands = snapshot.profile.version_bands.filter(
(band) => band.name.startsWith(`${mapFrameworkPackage(framework)}:`)
);
lines.push(`## ${manifest?.display_name ?? framework}`);
if (manifest?.description) {
lines.push("", manifest.description, "");
}
if (bands.length === 0) {
lines.push("- No version band detected.");
} else {
for (const band of bands) {
lines.push(
`- \`${band.package_name}\`: \`${band.locked_version}\` -> active rule band \`${band.range}\``
);
}
}
const conventions = await readTemplate(pack?.root, manifest?.docs?.conventions_template);
if (conventions) {
lines.push("", "### Pack Conventions", "", conventions.trim(), "");
}
lines.push("");
}
return `${lines.join("\n")}
`;
}
function buildDependencies(snapshot) {
const lines = ["# Dependencies", ""];
const runtime = snapshot.packages.filter((pkg) => !pkg.is_dev);
const dev = snapshot.packages.filter((pkg) => pkg.is_dev);
lines.push("## Runtime");
lines.push(...runtime.length === 0 ? ["- None"] : runtime.map(formatPackage));
lines.push("", "## Dev");
lines.push(...dev.length === 0 ? ["- None"] : dev.map(formatPackage));
return `${lines.join("\n")}
`;
}
function buildTooling(snapshot) {
const environmentTraits = snapshot.profile.traits.filter(
(trait) => ["docker", "compose", "sail"].includes(trait)
);
return `# Tooling
## Toolchains
${snapshot.profile.toolchains.map(
(toolchain) => `- \`${toolchain.package_manager}\` for \`${toolchain.ecosystem}\` with lockfile \`${toolchain.lockfile}\``
).join("\n")}
## Environment Traits
${environmentTraits.map((trait) => `- \`${trait}\``).join("\n") || "- None"}
`;
}
function buildVersionRules(snapshot, drift) {
return `# Version Rules
## Active Rule Bands
${snapshot.profile.version_bands.map((band) => `- \`${band.name}\``).join("\n") || "- None"}
## Drift Notes
${drift.material_changes.map((change) => `- \`${change.type}\` on \`${change.key}\`${change.after ? ` -> \`${change.after}\`` : ""}${change.before ? ` (from \`${change.before}\`)` : ""}`).join("\n") || "- No material stack drift detected."}
`;
}
function buildSources(snapshot) {
return `# Sources
${snapshot.profile.sources.map((source) => `- \`${source.file}\` via \`${source.kind}\`: ${source.detail}`).join("\n") || "- No sources recorded."}
`;
}
function buildDriftReport(drift) {
return `# Stack Drift Report
- Status: \`${drift.status}\`
- Previous: ${drift.previous_profile ? summarizeStack(drift.previous_profile) : "none"}
- Current: ${summarizeStack(drift.current_profile)}
## Material Changes
${drift.material_changes.map((change) => `- \`${change.type}\`: \`${change.key}\`${change.before ? ` from \`${change.before}\`` : ""}${change.after ? ` to \`${change.after}\`` : ""}`).join("\n") || "- None"}
## Review Targets
${drift.review_targets.map((target) => `- \`${target}\``).join("\n") || "- None"}
`;
}
function formatPackage(pkg) {
return `- \`${pkg.name}\` @ \`${pkg.locked_version}\`${pkg.is_dev ? " (dev)" : ""}`;
}
function mapFrameworkPackage(framework) {
switch (framework) {
case "laravel":
return "laravel/framework";
case "react":
return "react";
case "nextjs":
return "next";
case "vue":
return "vue";
case "flutter":
return "flutter";
case "dotnet":
return "Microsoft.AspNetCore.App";
case "django":
return "django";
case "fastapi":
return "fastapi";
case "flask":
return "flask";
case "rails":
return "rails";
case "spring-boot":
return "org.springframework.boot:spring-boot-starter-web";
case "express":
return "express";
case "nestjs":
return "@nestjs/core";
case "angular":
return "@angular/core";
case "svelte":
return "svelte";
case "astro":
return "astro";
case "go-web":
return "github.com/gin-gonic/gin";
case "rust-web":
return "axum";
case "kotlin-android":
return "com.android.application";
default:
return framework;
}
}
async function readTemplate(packRoot, templatePath) {
if (!packRoot || !templatePath) {
return null;
}
try {
return await readFile16(join35(packRoot, templatePath), "utf8");
} catch {
return null;
}
}
var PURPOSE_MAX = 120;
function packagePurpose(pkg, note) {
const raw = note ?? pkg.description ?? "";
return escapeDocText(capLine(cleanDiscoveredText(raw), PURPOSE_MAX));
}
function packageVersion(pkg) {
return pkg.installed ?? pkg.declared ?? "unknown";
}
function inventoryLine(pkg, notes) {
const purpose = packagePurpose(
pkg,
notes.get(`${pkg.ecosystem}:${pkg.name}`) ?? notes.get(pkg.name)
);
const head = `- \`${escapeDocText(pkg.name)}\` ${escapeDocText(packageVersion(pkg))}${pkg.dev ? " (dev)" : ""}`;
return purpose === "" ? head : `${head}: ${purpose}`;
}
function livePackages(packages) {
return packages.filter((pkg) => pkg.status !== "removed").sort((left, right) => left.name.localeCompare(right.name));
}
function versionsTable(packages) {
const rows = packages.map(
(pkg) => `| ${escapeDocText(pkg.name)} | ${pkg.ecosystem} | ${escapeDocText(pkg.declared ?? "")} | ${escapeDocText(pkg.installed ?? "")} | ${pkg.dev ? "yes" : "no"} |`
);
return [
"| Package | Ecosystem | Declared | Installed | Dev |",
"| --- | --- | --- | --- | --- |",
...rows
].join("\n");
}
async function refreshStackDocsFromInventory(projectRoot, input) {
const stackDir = join35(projectRoot, PATHS.FRAMEWORK_STACK_DIR);
await mkdir15(stackDir, { recursive: true });
const notes = input.notes ?? /* @__PURE__ */ new Map();
const live = livePackages(input.packages);
const lines = live.map((pkg) => inventoryLine(pkg, notes));
const list = lines.length === 0 ? "- None" : lines.join("\n");
const runtime = live.filter((pkg) => !pkg.dev).map((pkg) => inventoryLine(pkg, notes));
const dev = live.filter((pkg) => pkg.dev).map((pkg) => inventoryLine(pkg, notes));
const pages = [
{
file: "overview.md",
title: "# Stack Overview",
block: "packages",
body: `## Packages
${list}`
},
{
file: "dependencies.md",
title: "# Dependencies",
block: "dependencies",
body: `## Runtime
${runtime.length === 0 ? "- None" : runtime.join("\n")}
## Dev
${dev.length === 0 ? "- None" : dev.join("\n")}`
},
{ file: "versions.md", title: "# Versions", block: "versions", body: versionsTable(live) }
];
const updated = [];
for (const page of pages) {
const path10 = join35(stackDir, page.file);
let existing;
try {
existing = await readFile16(path10, "utf8");
} catch {
existing = `${page.title}
`;
}
const next = upsertManagedBlock(existing, page.block, page.body);
if (next !== existing) {
await writeFile16(path10, next);
updated.push(`${PATHS.FRAMEWORK_STACK_DIR}/${page.file}`);
}
}
return { updated };
}
// src/document/progress-tracker.ts
init_esm_shims();
import { mkdir as mkdir16, readFile as readFile17, rm as rm3, writeFile as writeFile17 } from "fs/promises";
import { dirname as dirname16, join as join36 } from "path";
var DocumentProgressTracker = class {
constructor(validator = new SchemaValidator()) {
this.validator = validator;
}
validator;
async load(projectRoot) {
const target = join36(projectRoot, PATHS.DOC_PROGRESS);
let raw;
try {
raw = await readFile17(target, "utf8");
} catch (error) {
if (hasErrorCode(error, "ENOENT")) {
return this.createEmpty();
}
throw new Error(`Failed to read document progress at ${PATHS.DOC_PROGRESS}`, {
cause: error
});
}
let parsed;
try {
parsed = JSON.parse(raw);
} catch (error) {
throw new Error(`Invalid JSON in ${PATHS.DOC_PROGRESS}`, { cause: error });
}
const validation = this.validator.validate("doc-progress", parsed);
if (!validation.valid) {
throw new Error(
`Invalid document progress schema in ${PATHS.DOC_PROGRESS}: ${validation.errors.map((issue) => issue.message).join("; ")}`
);
}
return parsed;
}
async save(projectRoot, progress) {
const target = join36(projectRoot, PATHS.DOC_PROGRESS);
await mkdir16(dirname16(target), { recursive: true });
await writeFile17(target, `${JSON.stringify(progress, null, 2)}
`);
}
async resetGeneratingEntries(projectRoot, progress) {
await Promise.all(
resetGeneratingEntries(progress).map(
(entry) => rm3(join36(projectRoot, entry.output_path), { force: true })
)
);
}
createEntry(output_path, source_files) {
return {
output_path,
state: "not_started",
started_at: null,
completed_at: null,
source_files,
source_hash: null,
tokens_used: null,
error: null
};
}
createEmpty() {
return {
schema_version: "1",
generated_by: "paqad-ai",
framework_version: VERSION,
modules: {},
global: {}
};
}
};
function resetGeneratingEntries(progress) {
const reset = [];
for (const entry of collectEntries(progress)) {
if (entry.state !== "generating") {
continue;
}
entry.state = "not_started";
entry.started_at = null;
entry.completed_at = null;
entry.error = null;
reset.push(entry);
}
return reset;
}
function collectEntries(progress) {
return [
...Object.values(progress.modules).flatMap((group) => Object.values(group)),
...Object.values(progress.global).flatMap((group) => Object.values(group))
];
}
function hasErrorCode(error, code) {
return typeof error === "object" && error !== null && "code" in error && error.code === code;
}
// src/document/staleness.ts
init_esm_shims();
import { createHash as createHash7 } from "crypto";
import { readFile as readFile18 } from "fs/promises";
import { join as join37 } from "path";
async function hashSourceFiles(projectRoot, sourceFiles) {
const hash = createHash7("sha1");
for (const relativePath of [...new Set(sourceFiles)].sort()) {
hash.update(`path:${relativePath}\0`);
try {
hash.update(await readFile18(join37(projectRoot, relativePath), "utf8"));
} catch {
hash.update(`missing\0`);
}
}
return `sha1:${hash.digest("hex").slice(0, 7)}`;
}
// src/document/workflow.ts
var MODULE_DOCS = [
{ key: "summary", outputPath: "index/summary.md", build: buildModuleSummary },
{ key: "schema", outputPath: "database/schema.md", build: buildDatabaseSchemaDoc },
{ key: "indexes", outputPath: "database/indexes.md", build: buildDatabaseIndexesDoc },
{ key: "queries", outputPath: "database/queries.md", build: buildDatabaseQueriesDoc },
{ key: "dataVolumes", outputPath: "database/data-volumes.md", build: buildDatabaseVolumesDoc },
{ key: "apiEndpoints", outputPath: "api/endpoints.md", build: buildApiEndpointsDoc },
{ key: "apiSchemas", outputPath: "api/schemas.md", build: buildApiSchemasDoc },
{ key: "apiErrorCodes", outputPath: "api/error-codes.md", build: buildApiErrorCodesDoc },
{
key: "integrationEvents",
outputPath: "integration/events.md",
build: buildIntegrationEventsDoc
},
{
key: "integrationContracts",
outputPath: "integration/contracts.md",
build: buildIntegrationContractsDoc
},
{ key: "errorCatalog", outputPath: "error-catalog.md", build: buildErrorCatalogDoc },
{ key: "screens", outputPath: "ui/screens.md", build: buildScreensDoc },
{ key: "components", outputPath: "ui/components.md", build: buildComponentsDoc },
{ key: "states", outputPath: "ui/states.md", build: buildStatesDoc }
];
var FEATURE_DOCS = [
{ key: "business", outputPath: "business.md", build: buildBusinessDoc },
{ key: "technical", outputPath: "technical.md", build: buildTechnicalDoc }
];
var DocumentationWorkflow = class {
tracker = new DocumentProgressTracker();
detector = new Detector();
introspector = new StackIntrospector();
async run(options) {
const mode = options.mode ?? "foundation";
if (mode === "module-docs") {
return this.runModuleDocs(options);
}
return this.runFoundation(options);
}
async runModuleDocs(options) {
const moduleMap = await loadModuleMap(options.projectRoot);
if (moduleMap === null) {
throw new Error(
"I cannot find docs/instructions/rules/module-map.yml. Prompt me with create documentation first, review the generated module map, then prompt me with create module documentation."
);
}
const profile = loadProjectProfile(options.projectRoot);
if (profile === null) {
throw new Error("Documentation workflow requires onboarding to complete first");
}
const progress = await this.tracker.load(options.projectRoot);
await this.tracker.resetGeneratingEntries(options.projectRoot, progress);
const detection = await this.detector.detect(options.projectRoot);
const stackSnapshot = await this.introspector.snapshot(options.projectRoot);
const routing = resolveEffectiveRouting(profile, detection, stackSnapshot, options.request);
await syncOnboardingState(options.projectRoot, profile, detection, routing, stackSnapshot);
const sourceFiles = await gatherSourceFiles(
options.projectRoot,
routing.stack,
stackSnapshot.repository
);
const generated = [];
const skipped5 = [];
const steps = [];
const orphanedModuleDirs = await findOrphanedModuleDirs(
options.projectRoot,
moduleMap.modules.map((m) => m.slug)
);
const analyticsEnabled = resolveAnalyticsInstrumentation(options.projectRoot);
for (const mod of moduleMap.modules) {
const moduleName = mod.slug;
const moduleFiles = mod.source_paths.length > 0 ? resolveSourcePaths(mod.source_paths, sourceFiles) : selectModuleFiles(moduleName, sourceFiles);
const title = mod.name;
progress.modules[moduleName] ??= {};
const moduleGenerated = [];
const moduleSkipped = [];
const features = mod.features.length > 0 ? mod.features.map((f) => ({
name: f.slug,
files: f.source_paths.length > 0 ? resolveSourcePaths(f.source_paths, sourceFiles) : selectModuleFiles(f.slug, moduleFiles)
})) : [];
for (const feature of features) {
for (const definition of FEATURE_DOCS) {
const path10 = join38(
PATHS.MODULES_DIR,
moduleName,
PATHS.MODULE_FEATURES_DIR,
feature.name,
definition.outputPath
);
const progressKey = `feature:${feature.name}:${definition.key}`;
progress.modules[moduleName][progressKey] ??= this.tracker.createEntry(
path10,
feature.files
);
await processEntry({
projectRoot: options.projectRoot,
entry: progress.modules[moduleName][progressKey],
content: definition.build({
moduleName,
title,
stack: routing.stack,
effectiveRouting: routing,
sourceFiles,
moduleFiles,
stackSnapshot,
featureName: feature.name,
featureTitle: titleize(feature.name),
featureFiles: feature.files
}),
generated: moduleGenerated,
skipped: moduleSkipped
});
}
}
if (analyticsEnabled) {
const analyticsEntries = await collectAnalyticsEntries(
options.projectRoot,
moduleName,
features
);
const sync = await syncAnalyticsDocs(options.projectRoot, analyticsEntries);
moduleGenerated.push(...sync.written);
moduleSkipped.push(...sync.skipped);
}
for (const definition of MODULE_DOCS) {
const path10 = join38(PATHS.MODULES_DIR, moduleName, definition.outputPath);
progress.modules[moduleName][definition.key] ??= this.tracker.createEntry(
path10,
moduleFiles
);
await processEntry({
projectRoot: options.projectRoot,
entry: progress.modules[moduleName][definition.key],
content: definition.build({
moduleName,
title,
stack: routing.stack,
effectiveRouting: routing,
sourceFiles,
moduleFiles,
stackSnapshot
}),
generated: moduleGenerated,
skipped: moduleSkipped
});
}
generated.push(...moduleGenerated);
skipped5.push(...moduleSkipped);
steps.push({
id: `module-${moduleName}`,
summary: `Updated canonical documentation for ${mod.name}`,
generated: moduleGenerated,
skipped: moduleSkipped
});
}
const moduleSlugs = moduleMap.modules.map((m) => m.slug);
const registryGenerated = [];
const registrySkipped = [];
progress.global.registries ??= {};
for (const registry of REGISTRIES) {
const path10 = join38(PATHS.REGISTRIES_DIR, registry);
progress.global.registries[registry] ??= this.tracker.createEntry(path10, sourceFiles);
progress.global.registries[registry].state = "not_started";
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.registries[registry],
content: buildRegistryDoc(registry, moduleSlugs, routing, stackSnapshot),
generated: registryGenerated,
skipped: registrySkipped
});
}
generated.push(...registryGenerated);
skipped5.push(...registrySkipped);
steps.push({
id: "registries",
summary: "Refreshed canonical registries from reviewed module map",
generated: registryGenerated,
skipped: registrySkipped
});
progress.global.handover ??= {};
progress.global.handover.summary ??= this.tracker.createEntry(
join38(".paqad/handover", "product-summary.md"),
sourceFiles
);
progress.global.handover.summary.state = "not_started";
const handoverGenerated = [];
const handoverSkipped = [];
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.handover.summary,
content: buildHandoverSummary(moduleSlugs, generated, routing, stackSnapshot),
generated: handoverGenerated,
skipped: handoverSkipped
});
generated.push(...handoverGenerated);
skipped5.push(...handoverSkipped);
steps.push({
id: "handover",
summary: "Wrote product summary handover output",
generated: handoverGenerated,
skipped: handoverSkipped
});
progress.moduleDocStage = "complete";
await this.tracker.save(options.projectRoot, progress);
return {
generated: generated.map(toPosixPath),
skipped: skipped5.map(toPosixPath),
progress_path: PATHS.DOC_PROGRESS,
handover_path: toPosixPath(join38(".paqad/handover", "product-summary.md")),
module_map_path: PATHS.MODULE_MAP,
module_docs_pending_map_review: false,
module_map_low_confidence_modules: [],
orphaned_module_dirs: orphanedModuleDirs,
stack_snapshot: stackSnapshot,
effective_routing: routing,
profile_updated: false,
steps
};
}
async runFoundation(options) {
const profile = loadProjectProfile(options.projectRoot);
if (profile === null) {
throw new Error("Documentation workflow requires onboarding to complete first");
}
const progress = await this.tracker.load(options.projectRoot);
await this.tracker.resetGeneratingEntries(options.projectRoot, progress);
const previousStackSnapshot = await new StackSnapshotCache().read(options.projectRoot);
const detection = await this.detector.detect(options.projectRoot);
const stackSnapshot = await this.introspector.snapshot(options.projectRoot);
const routing = resolveEffectiveRouting(profile, detection, stackSnapshot, options.request);
const profileUpdated = await syncOnboardingState(
options.projectRoot,
profile,
detection,
routing,
stackSnapshot
);
const sourceFiles = await gatherSourceFiles(
options.projectRoot,
routing.stack,
stackSnapshot.repository
);
const hintModuleNames = extractModuleNamesFromRequest(options.request?.request_text);
const moduleMapYaml = await generateModuleMapYaml(options.projectRoot, hintModuleNames);
await mkdir17(join38(options.projectRoot, PATHS.RULES_DIR), { recursive: true });
await writeModuleMap(options.projectRoot, moduleMapYaml);
const modules = await discoverModules(options.projectRoot);
const generated = [];
const skipped5 = [];
const steps = [];
steps.push({
id: "validate-stack",
summary: `Validated application stack as ${routing.stack} from project manifests`,
generated: [],
skipped: []
});
const stackDrift = await writeStackArtifacts(
options.projectRoot,
stackSnapshot,
previousStackSnapshot,
{ writeHumanDocs: true }
);
const stackDocs = [
join38(PATHS.FRAMEWORK_STACK_DIR, "overview.md"),
join38(PATHS.FRAMEWORK_STACK_DIR, "frameworks.md"),
join38(PATHS.FRAMEWORK_STACK_DIR, "dependencies.md"),
join38(PATHS.FRAMEWORK_STACK_DIR, "tooling.md"),
join38(PATHS.FRAMEWORK_STACK_DIR, "version-rules.md"),
join38(PATHS.FRAMEWORK_STACK_DIR, "sources.md"),
join38(PATHS.FRAMEWORK_STACK_DIR, "drift-report.md")
];
generated.push(...stackDocs);
steps.push({
id: "stack-context",
summary: `Wrote stack context and drift review targets (${stackDrift.review_targets.length})`,
generated: stackDocs,
skipped: []
});
if (routing.domain === "content" && options.request?.request_text) {
const contentOutputPath = options.request.output_path ?? defaultContentOutputPath(options.request.request_text);
const contentBody = await buildContentDeliverable({
projectRoot: options.projectRoot,
requestText: options.request.request_text,
outputPath: contentOutputPath,
routing,
stackSnapshot,
profile
});
await mkdir17(dirname17(join38(options.projectRoot, contentOutputPath)), { recursive: true });
await writeFile18(join38(options.projectRoot, contentOutputPath), contentBody);
generated.push(contentOutputPath);
steps.push({
id: "content-deliverable",
summary: `Wrote content deliverable to ${contentOutputPath}`,
generated: [contentOutputPath],
skipped: []
});
}
const designTokenService = new DesignTokenService();
await designTokenService.seed(options.projectRoot);
let designDocs = [];
let themeArtifacts = [];
let designSystemPlaceholderNote;
try {
designDocs = await designTokenService.generateDocs(options.projectRoot);
themeArtifacts = await designTokenService.exportTheme(options.projectRoot, routing.stack);
} catch (error) {
if (error instanceof DesignTokensPlaceholderError) {
designSystemPlaceholderNote = error.message;
} else {
throw error;
}
}
progress.global.designSystem ??= {};
const designSystemGenerated = [];
const designSystemSkipped = [];
progress.global.designSystem.designTokens ??= this.tracker.createEntry(
PATHS.DESIGN_TOKENS_FILE,
sourceFiles
);
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.designSystem.designTokens,
content: await readFile19(join38(options.projectRoot, PATHS.DESIGN_TOKENS_FILE), "utf8"),
generated: designSystemGenerated,
skipped: designSystemSkipped
});
for (const doc of designDocs) {
const key = basenameWithoutExtension(doc.path);
progress.global.designSystem[key] ??= this.tracker.createEntry(doc.path, [
PATHS.DESIGN_TOKENS_FILE
]);
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.designSystem[key],
content: doc.content,
generated: designSystemGenerated,
skipped: designSystemSkipped
});
}
await Promise.all(
themeArtifacts.map(async (artifact) => {
await mkdir17(dirname17(join38(options.projectRoot, artifact.path)), { recursive: true });
await writeFile18(join38(options.projectRoot, artifact.path), artifact.content);
designSystemGenerated.push(artifact.path);
})
);
generated.push(...designSystemGenerated);
skipped5.push(...designSystemSkipped);
steps.push({
id: "design-system",
summary: designSystemPlaceholderNote ? `Seeded placeholder design tokens; skipped design-system docs \u2014 ${designSystemPlaceholderNote}` : "Synced design-system documentation",
generated: designSystemGenerated,
skipped: designSystemSkipped
});
progress.global.architecture ??= {};
progress.global.architecture.overview ??= this.tracker.createEntry(
join38(PATHS.ARCHITECTURE_DIR, "overview.md"),
sourceFiles
);
progress.global.architecture.decisions ??= this.tracker.createEntry(
join38(PATHS.ARCHITECTURE_DIR, "decisions.md"),
sourceFiles
);
progress.global.architecture.patterns ??= this.tracker.createEntry(
join38(PATHS.ARCHITECTURE_DIR, "patterns.md"),
sourceFiles
);
const architectureGenerated = [];
const architectureSkipped = [];
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.architecture.overview,
content: buildArchitectureOverview(modules, routing, stackSnapshot),
generated: architectureGenerated,
skipped: architectureSkipped
});
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.architecture.decisions,
content: buildArchitectureDecisions(routing, stackSnapshot),
generated: architectureGenerated,
skipped: architectureSkipped
});
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.architecture.patterns,
content: buildArchitecturePatterns(routing, sourceFiles),
generated: architectureGenerated,
skipped: architectureSkipped
});
generated.push(...architectureGenerated);
skipped5.push(...architectureSkipped);
steps.push({
id: "architecture",
summary: "Updated global architecture documents",
generated: architectureGenerated,
skipped: architectureSkipped
});
const registryGenerated = [];
const registrySkipped = [];
progress.global.registries ??= {};
for (const registry of REGISTRIES) {
const path10 = join38(PATHS.REGISTRIES_DIR, registry);
progress.global.registries[registry] ??= this.tracker.createEntry(path10, sourceFiles);
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.registries[registry],
content: buildRegistryDoc(registry, modules, routing, stackSnapshot),
generated: registryGenerated,
skipped: registrySkipped
});
}
generated.push(...registryGenerated);
skipped5.push(...registrySkipped);
steps.push({
id: "registries",
summary: "Refreshed canonical registries from current modules and stack context",
generated: registryGenerated,
skipped: registrySkipped
});
progress.global.benchmarks ??= {};
progress.global.benchmarks.index ??= this.tracker.createEntry(
join38(PATHS.BENCHMARKS_DIR, "index.md"),
sourceFiles
);
progress.global.techDebt ??= {};
progress.global.techDebt.index ??= this.tracker.createEntry(
join38(PATHS.TECH_DEBT_DIR, "index.md"),
sourceFiles
);
const maintenanceGenerated = [];
const maintenanceSkipped = [];
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.benchmarks.index,
content: buildBenchmarksDoc(routing, stackSnapshot),
generated: maintenanceGenerated,
skipped: maintenanceSkipped
});
await processEntry({
projectRoot: options.projectRoot,
entry: progress.global.techDebt.index,
content: buildTechDebtDoc(modules, routing),
generated: maintenanceGenerated,
skipped: maintenanceSkipped
});
generated.push(...maintenanceGenerated);
skipped5.push(...maintenanceSkipped);
steps.push({
id: "maintenance-docs",
summary: "Updated benchmarks and technical debt indexes",
generated: maintenanceGenerated,
skipped: maintenanceSkipped
});
generated.push(PATHS.MODULE_MAP);
const writtenMap = await loadModuleMap(options.projectRoot);
const lowConfidenceModules = writtenMap.modules.filter((m) => m.confidence === "low").map((m) => m.name);
steps.push({
id: "module-map",
summary: `Wrote module map to ${PATHS.MODULE_MAP} \u2014 review before running create module documentation`,
generated: [PATHS.MODULE_MAP],
skipped: []
});
progress.moduleDocStage = "pending_map_review";
await this.tracker.save(options.projectRoot, progress);
return {
generated: generated.map(toPosixPath),
skipped: skipped5.map(toPosixPath),
progress_path: PATHS.DOC_PROGRESS,
handover_path: toPosixPath(join38(".paqad/handover", "product-summary.md")),
module_map_path: PATHS.MODULE_MAP,
module_docs_pending_map_review: true,
module_map_low_confidence_modules: lowConfidenceModules,
orphaned_module_dirs: [],
stack_snapshot: stackSnapshot,
effective_routing: routing,
profile_updated: profileUpdated,
steps
};
}
};
async function syncOnboardingState(projectRoot, profile, detection, routing, stackSnapshot) {
const routingChanged = getProfileDomain(profile) !== routing.domain || JSON.stringify(profile.stack_profile?.frameworks ?? []) !== JSON.stringify(stackSnapshot.profile.frameworks) || JSON.stringify(profile.stack_profile?.traits ?? []) !== JSON.stringify(stackSnapshot.profile.traits);
if (!routingChanged) {
writeDetectionReport(projectRoot, detection);
return false;
}
const updatedProfile = {
...profile,
active_capabilities: routing.domain === "coding" ? ["content", "coding", "security"] : ["content"],
stack_profile: routing.domain === "coding" ? stackSnapshot.profile : void 0
};
writeProjectProfile(projectRoot, updatedProfile);
writeDetectionReport(projectRoot, {
...detection,
detected_domain: routing.domain,
detected_stack: routing.stack,
detected_capabilities: routing.capabilities,
timestamp: stackSnapshot.generated_at
});
const manifest = await readOnboardingManifest(projectRoot);
if (manifest !== null) {
writeOnboardingManifest(projectRoot, {
...manifest,
profile: updatedProfile,
repository: detection.repository ?? stackSnapshot.repository
});
}
return true;
}
function resolveEffectiveRouting(profile, detection, stackSnapshot, request) {
const ecosystems = new Set(stackSnapshot.toolchains.map((toolchain) => toolchain.ecosystem));
const packageNames = new Set(stackSnapshot.packages.map((pkg) => pkg.name));
const stack = detection.detected_stack ?? (packageNames.has("laravel/framework") || ecosystems.has("php") ? "laravel" : ecosystems.has("dart") ? "flutter" : request?.stack ?? stackSnapshot.profile.frameworks[0] ?? "laravel");
const domain = request?.domain ?? detection.detected_domain ?? (stack === "short-video" ? "content" : getProfileDomain(profile));
const capabilities = detection.detected_capabilities.length > 0 ? detection.detected_capabilities : stackSnapshot.profile.traits.filter(
(trait) => [
"react",
"vue",
"inertia",
"tailwind",
"boost",
"next",
"remix",
"vite-spa",
"gatsby",
"nuxt",
"quasar"
].includes(trait)
);
return {
domain,
stack,
capabilities
};
}
function resolveAnalyticsInstrumentation(projectRoot) {
try {
return resolveFrameworkConfig(projectRoot).features.analytics_instrumentation;
} catch {
return false;
}
}
async function collectAnalyticsEntries(projectRoot, moduleName, features) {
const entries = [];
for (const feature of features) {
const callSites = [];
const seen = /* @__PURE__ */ new Set();
for (const file of feature.files) {
let text2;
try {
text2 = await readFile19(join38(projectRoot, file), "utf8");
} catch {
continue;
}
for (const site of extractCallSites(text2)) {
const key = `${site.provider}:${site.eventName}`;
if (seen.has(key)) continue;
seen.add(key);
callSites.push(site);
}
}
if (callSites.length > 0) {
entries.push({ module: moduleName, feature: feature.name, callSites });
}
}
return entries;
}
async function findOrphanedModuleDirs(projectRoot, reviewedSlugs) {
try {
const modulesRoot = join38(projectRoot, PATHS.MODULES_DIR);
const entries = await readdir4(modulesRoot, { withFileTypes: true });
const slugSet = new Set(reviewedSlugs);
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && !slugSet.has(e.name)).map((e) => toPosixPath(join38(PATHS.MODULES_DIR, e.name)));
} catch {
return [];
}
}
async function processEntry(input) {
const currentHash = await hashSourceFiles(input.projectRoot, input.entry.source_files);
if (input.entry.state === "done" && input.entry.source_hash === currentHash) {
const existingContent = await readFile19(
join38(input.projectRoot, input.entry.output_path),
"utf8"
).catch(() => null);
if (existingContent === input.content) {
input.skipped.push(input.entry.output_path);
return { generated: [], skipped: [input.entry.output_path] };
}
}
input.entry.state = "generating";
input.entry.started_at = (/* @__PURE__ */ new Date()).toISOString();
input.entry.error = null;
await mkdir17(dirname17(join38(input.projectRoot, input.entry.output_path)), { recursive: true });
await writeFile18(join38(input.projectRoot, input.entry.output_path), input.content);
input.generated.push(input.entry.output_path);
input.entry.state = "done";
input.entry.completed_at = (/* @__PURE__ */ new Date()).toISOString();
input.entry.source_hash = currentHash;
input.entry.tokens_used = Math.max(32, Math.round(input.content.length / 4));
if (input.entry.output_path.endsWith("tokens.md")) {
const placeholders = findBracePlaceholders(input.content);
input.entry.design_tokens = {
extraction_state: "done",
total_tokens_found: (input.content.match(/`/g) ?? []).length / 2,
placeholder_count: placeholders.length,
populated_count: Math.max(0, input.content.split("\n").length - 4),
placeholder_keys: Array.from(new Set(placeholders.map((item) => item.slice(1, -1)))).slice(
0,
10
)
};
}
return { generated: [input.entry.output_path], skipped: [] };
}
async function gatherSourceFiles(projectRoot, stack, repository) {
const roots = repository?.projects.length ? repository.projects.map((project) => project.root) : stack === "flutter" ? ["lib", "test", "web", "assets", "pubspec.yaml"] : stack === "short-video" ? ["src", "content", "scripts", "package.json"] : [
"app",
"routes",
"config",
"resources",
"database",
"tests",
"src",
"server",
"controllers",
"services",
"internal",
"cmd",
"lib",
"api",
"package.json",
"composer.json",
"requirements.txt",
"pyproject.toml",
"Gemfile",
"pom.xml",
"build.gradle",
"build.gradle.kts",
"go.mod",
"Cargo.toml"
];
const results = /* @__PURE__ */ new Set();
for (const root of roots) {
try {
for (const file of await walk2(join38(projectRoot, root))) {
results.add(relative9(projectRoot, file));
}
} catch {
if (!root.includes(".")) {
continue;
}
results.add(root);
}
}
if (results.size === 0) {
results.add("package.json");
}
return Array.from(results).sort();
}
async function buildContentDeliverable(input) {
const styleGuide = await readOptionalFile(
join38(input.projectRoot, "docs/instructions/rules/writing-style.md")
);
const codingContext = input.profile.active_capabilities.includes("coding") && input.stackSnapshot.profile.frameworks.length > 0 ? [
"## Technical Context",
"",
`- Coding stacks: ${input.stackSnapshot.profile.frameworks.map((framework) => `\`${framework}\``).join(", ")}`,
`- Active traits: ${input.stackSnapshot.profile.traits.map((trait) => `\`${trait}\``).join(", ") || "none"}`,
"",
"Embed only the minimum code or API detail needed to support the writing task.",
""
].join("\n") : "";
return [
`# ${input.requestText.trim()}`,
"",
"## Content Brief",
"",
"- Goal: Deliver a clear, publication-ready draft aligned with the project context.",
`- Output path: \`${input.outputPath}\``,
"- Required quality bar: precise structure, attributable claims, and concise code references.",
"",
codingContext,
"## Writing Rules",
"",
"- Lead with the user outcome, then support it with specifics.",
"- Prefer short sections and Markdown headings that scan well.",
"- Attribute externally-derived claims and avoid unsupported assertions.",
"- When code context is relevant, keep snippets brief and explain why they matter.",
"",
styleGuide ? ["## Project Writing Style", "", styleGuide.trim(), ""].join("\n") : "",
"## Draft",
"",
"> Replace this draft with the final content deliverable.",
"",
"- Audience:",
"- Key message:",
"- Supporting points:",
"- Call to action:",
""
].filter((section3) => section3 !== "").join("\n");
}
async function readOptionalFile(path10) {
try {
return await readFile19(path10, "utf8");
} catch {
return null;
}
}
function defaultContentOutputPath(requestText) {
return join38("content", `${slugify(requestText)}.md`);
}
function slugify(requestText) {
const slug = slugifyAscii(requestText).slice(0, 80);
return slug.length > 0 ? slug : "content-draft";
}
async function walk2(root) {
const entries = await readdir4(root, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const target = join38(root, entry.name);
if (entry.isDirectory()) {
if ([
".dart_tool",
".git",
".gradle",
".next",
".nuxt",
".turbo",
"build",
"coverage",
"dist",
"node_modules",
"out",
"target",
"vendor"
].includes(entry.name)) {
continue;
}
files.push(...await walk2(target));
continue;
}
files.push(target);
}
return files;
}
function selectModuleFiles(moduleName, sourceFiles) {
const normalized = moduleName.toLowerCase();
const matches = sourceFiles.filter((file) => file.toLowerCase().includes(normalized));
return (matches.length > 0 ? matches : sourceFiles).slice(0, 12);
}
function loadProjectProfile(projectRoot) {
return readProjectProfile(projectRoot);
}
async function readOnboardingManifest(projectRoot) {
try {
return JSON.parse(
await readFile19(join38(projectRoot, PATHS.ONBOARDING_MANIFEST), "utf8")
);
} catch {
return null;
}
}
function buildModuleSummary(input) {
return [
`# ${input.title} Summary`,
"",
`Stack: \`${input.stack}\``,
"",
"## What This Module Owns",
"",
`- Canonical ownership for ${input.moduleName} based on the current onboarded project.`,
...input.moduleFiles.slice(0, 5).map((file) => `- Evidence from \`${file}\``),
"",
"## Key Risks",
"",
"- Keep contracts, state changes, and external dependencies aligned with canonical docs.",
""
].join("\n");
}
function buildBusinessDoc(input) {
return [
`# ${input.featureTitle} Business`,
"",
"## Overview",
"",
`${input.featureTitle} is documented from the current ${input.stack} application state after onboarding.`,
"",
"## User Roles",
"",
"- Primary operators are inferred from the current product structure and routes/screens.",
"",
"## User Flows",
"",
...input.featureFiles.slice(0, 5).map((file, index) => `${index + 1}. Workflow signal from \`${file}\`.`),
"",
"## Business Rules",
"",
"- Preserve observed business invariants when implementation changes.",
"- Update this document whenever ownership or user-visible behavior shifts.",
"",
"## Triggers and Side Effects",
"",
"- Review events, notifications, queues, or state transitions tied to this module.",
"",
"## Error States",
"",
"- Record user-visible failures and documented recovery expectations.",
"",
"## Glossary",
"",
`- Add ${input.featureTitle}-specific domain language here as it stabilizes.`,
""
].join("\n");
}
function buildTechnicalDoc(input) {
return [
`# ${input.featureTitle} Technical`,
"",
"## Module Boundaries",
"",
...input.featureFiles.slice(0, 8).map((file) => `- \`${file}\``),
"",
"## Database Schema",
"",
input.stack === "laravel" ? "- Review owned migrations, models, and table contracts from the Laravel application." : "- Record local persistence or remote schema dependencies relevant to this module.",
"",
"## API Endpoints",
"",
"- Keep API docs, request schemas, and auth expectations aligned with implementation.",
"",
"## Models and Relationships",
"",
...input.stackSnapshot.packages.slice(0, 5).map((pkg) => `- \`${pkg.name}\` @ \`${pkg.locked_version}\``),
"",
"## State Management",
"",
stackStateHint(input.stack),
"",
"## Error Codes",
"",
"- Update structured error references in `error-catalog.md` and `api/error-codes.md` together.",
"",
"## Dependencies",
"",
...buildPackageList(input.stackSnapshot),
"",
"## Configuration",
"",
"- Capture environment/config dependencies discovered in manifest and source files.",
"",
"## Testing Entry Points",
"",
"- Keep unit, integration, and end-to-end coverage references current.",
""
].join("\n");
}
function buildDatabaseSchemaDoc(input) {
return [
`# ${input.moduleName} \u2014 Database Schema`,
"",
"## Owned Data Structures",
"",
input.stack === "laravel" ? "- Review tables, columns, and relationships from migrations and Eloquent models." : "- Record local or remote data shapes relevant to this module.",
"",
"## Source Signals",
"",
...input.moduleFiles.slice(0, 6).map((file) => `- \`${file}\``),
""
].join("\n");
}
function buildDatabaseIndexesDoc(input) {
return [
`# ${input.moduleName} \u2014 Database Indexes`,
"",
"## Index Coverage",
"",
"- Document lookup, uniqueness, and sorting indexes that materially affect behavior.",
"",
"## Query Hotspots",
"",
...input.moduleFiles.slice(0, 4).map((file) => `- Review query patterns in \`${file}\`.`),
""
].join("\n");
}
function buildDatabaseQueriesDoc(input) {
return [
`# ${input.moduleName} \u2014 Queries`,
"",
"## Query Inventory",
"",
"- Record high-value reads, writes, aggregates, and reporting paths.",
"",
"## Optimization Notes",
"",
`- Prefer optimizations that match the ${input.stack} stack conventions.`,
""
].join("\n");
}
function buildDatabaseVolumesDoc(input) {
return [
`# ${input.moduleName} \u2014 Data Volumes`,
"",
"## Expected Scale",
"",
"- Capture rough row counts, churn, and retention expectations when known.",
"",
"## Growth Drivers",
"",
"- Note batch jobs, user growth, or event throughput that could affect this module.",
""
].join("\n");
}
function buildApiEndpointsDoc(input) {
return [
`# ${input.moduleName} \u2014 API Endpoints`,
"",
"> Canonical reference for routes, auth rules, payloads, and response contracts.",
"",
"## Current Signals",
"",
...input.sourceFiles.filter((file) => file.includes("routes/") || file.includes("api/")).slice(0, 6).map((file) => `- Route or API signal from \`${file}\``),
"",
"## Documentation Rules",
"",
"- Add each endpoint with method, route, auth, schema, and error-code references.",
""
].join("\n");
}
function buildApiSchemasDoc(input) {
return [
`# ${input.moduleName} \u2014 API Schemas`,
"",
"## Request and Response Contracts",
"",
"- Keep request, response, and validation payloads aligned with the live application.",
"",
"## Related Sources",
"",
...input.moduleFiles.slice(0, 5).map((file) => `- \`${file}\``),
""
].join("\n");
}
function buildApiErrorCodesDoc(input) {
return [
`# ${input.moduleName} \u2014 API Error Codes`,
"",
"## Canonical Error References",
"",
"- Keep structured API errors aligned with the module error catalog.",
"",
`- Prefix recommendation: \`${input.moduleName.toUpperCase()}-\``,
""
].join("\n");
}
function buildIntegrationEventsDoc(input) {
return [
`# ${input.moduleName} \u2014 Events`,
"",
"## Published Events",
"",
"- Record events emitted by this module and their downstream subscribers.",
"",
"## Consumed Events",
"",
"- Record events consumed from external modules or services.",
"",
"## Source Signals",
"",
...input.moduleFiles.slice(0, 4).map((file) => `- \`${file}\``),
""
].join("\n");
}
function buildIntegrationContractsDoc(input) {
return [
`# ${input.moduleName} \u2014 Integration Contracts`,
"",
"## Internal Contracts",
"",
"- Document jobs, events, service contracts, and cross-module dependencies.",
"",
"## External Contracts",
"",
"- Record APIs, SDKs, and external service dependencies.",
""
].join("\n");
}
function buildErrorCatalogDoc(input) {
return [
`# ${input.moduleName} \u2014 Error Catalog`,
"",
"## Error Code Format",
"",
`${input.moduleName.toUpperCase()}-NNN`,
"",
"## Catalog Rules",
"",
"- Update user-facing message, internal message, recovery path, and alerting state together.",
""
].join("\n");
}
function buildScreensDoc(input) {
return [
`# ${input.moduleName} \u2014 Screens`,
"",
"## Screen Inventory",
"",
...uiSignals(input).map((line) => `- ${line}`),
""
].join("\n");
}
function buildComponentsDoc(input) {
return [
`# ${input.moduleName} \u2014 Components`,
"",
"## UI Components",
"",
...uiSignals(input).map((line) => `- ${line}`),
""
].join("\n");
}
function buildStatesDoc(input) {
return [
`# ${input.moduleName} \u2014 States`,
"",
"## State and Transition Notes",
"",
stackStateHint(input.stack),
"",
...input.moduleFiles.slice(0, 4).map((file) => `- Validate state transitions in \`${file}\``),
""
].join("\n");
}
function buildArchitectureOverview(modules, routing, stackSnapshot) {
return [
"# Architecture Overview",
"",
`Canonical documentation workflow resolved the project as \`${routing.domain}/${routing.stack}\`.`,
"",
"## Modules",
"",
...modules.map((moduleName) => `- ${moduleName}`),
"",
"## Toolchains",
"",
...stackSnapshot.toolchains.map(
(toolchain) => `- ${toolchain.ecosystem}: ${toolchain.package_manager} (${toolchain.lockfile})`
),
""
].join("\n");
}
function buildArchitectureDecisions(routing, stackSnapshot) {
return [
"# Architecture Decisions",
"",
`- Canonical stack confirmed as \`${routing.stack}\` before documentation generation.`,
`- Toolchains observed: ${stackSnapshot.toolchains.map((toolchain) => toolchain.package_manager).join(", ") || "none"}.`,
"- Update this file when architectural conventions or stack assumptions change.",
""
].join("\n");
}
function buildArchitecturePatterns(routing, sourceFiles) {
return [
"# Architecture Patterns",
"",
`- Documentation strategy selected for the \`${routing.stack}\` stack.`,
...sourceFiles.slice(0, 6).map((file) => `- Pattern evidence from \`${file}\``),
""
].join("\n");
}
function buildRegistryDoc(registry, modules, routing, stackSnapshot) {
return [
`# ${registry}`,
"",
`Generated from the current ${routing.stack} project state.`,
"",
...modules.map((moduleName) => `- ${moduleName}`),
"",
`Observed packages: ${stackSnapshot.packages.length}`,
""
].join("\n");
}
function buildBenchmarksDoc(routing, stackSnapshot) {
return [
"# Benchmarks",
"",
`Track performance-sensitive benchmarks for the ${routing.stack} stack.`,
"",
`Current package inventory: ${stackSnapshot.packages.length} package entries.`,
""
].join("\n");
}
function buildTechDebtDoc(modules, routing) {
return [
"# Technical Debt",
"",
`Review debt across ${modules.length} module(s) for the ${routing.stack} stack.`,
"",
...modules.map(
(moduleName) => `- ${moduleName}: capture follow-up items when docs drift from implementation.`
),
""
].join("\n");
}
function buildHandoverSummary(modules, generated, routing, stackSnapshot) {
return [
"# Product Summary",
"",
`Documentation workflow completed for the \`${routing.stack}\` application.`,
"",
`Modules documented: ${modules.length}.`,
`Artifacts written or refreshed: ${generated.length}.`,
`Package snapshot entries: ${stackSnapshot.packages.length}.`,
""
].join("\n");
}
function buildPackageList(stackSnapshot) {
const packages = stackSnapshot.packages.slice(0, 6);
if (packages.length === 0) {
return ["- No stack snapshot packages available."];
}
return packages.map((pkg) => `- \`${pkg.name}\` @ \`${pkg.locked_version}\``);
}
function uiSignals(input) {
const candidates = input.sourceFiles.filter(
(file) => file.includes("resources/") || file.includes("lib/") || file.includes("ui/") || file.includes("components/") || file.includes("screens/")
);
return (candidates.length > 0 ? candidates : input.moduleFiles).slice(0, 5);
}
function stackStateHint(stack) {
switch (stack) {
case "flutter":
return "- Document widget state, navigation state, and asynchronous view-model transitions.";
case "short-video":
return "- Document editorial states, publishing stages, and content workflow transitions.";
default:
return "- Document request lifecycle, domain state changes, and queued/background processing.";
}
}
function titleize(value) {
return value.replace(/[-_]/g, " ").replace(/\b\w/g, (character) => character.toUpperCase());
}
function basenameWithoutExtension(path10) {
return path10.split("/").at(-1)?.replace(/\.[^.]+$/, "") ?? path10;
}
function resolveSourcePaths(mappedPaths, sourceFiles) {
const result2 = [];
const posixSources = sourceFiles.map(toPosixPath);
for (const raw of mappedPaths) {
const p = toPosixPath(raw);
if (posixSources.includes(p)) {
result2.push(p);
} else {
const prefix = p.endsWith("/") ? p : `${p}/`;
result2.push(...posixSources.filter((f) => f.startsWith(prefix)));
}
}
return result2;
}
function findBracePlaceholders(content) {
const found = [];
let open = content.indexOf("{");
while (open !== -1) {
const close = content.indexOf("}", open + 1);
if (close === -1) break;
if (close > open + 1) {
found.push(content.slice(open, close + 1));
open = content.indexOf("{", close + 1);
} else {
open = content.indexOf("{", open + 1);
}
}
return found;
}
function extractModuleNamesFromRequest(requestText) {
if (!requestText) return [];
const match = /\bmodules?\s*(?:are|is|:)\s*([\w][\w\s,]*)/i.exec(requestText);
if (!match?.[1]) return [];
return match[1].split(",").flatMap((part) => splitOnAndWord(part)).map((s) => s.trim()).filter((s) => s.length >= 2);
}
function splitOnAndWord(text2) {
const tokens = text2.split(/(\s+)/);
const parts = [];
let current = "";
let index = 0;
while (index < tokens.length) {
const isSeparator = index % 2 === 1 && index + 2 < tokens.length && tokens[index + 1].toLowerCase() === "and";
if (isSeparator) {
parts.push(current);
current = "";
index += 3;
continue;
}
current += tokens[index];
index += 1;
}
parts.push(current);
return parts;
}
// src/document/pipeline.ts
var DocumentPipeline = class {
workflow = new DocumentationWorkflow();
async run(options) {
return this.workflow.run(options);
}
};
// src/onboarding/index.ts
init_esm_shims();
// src/onboarding/file-writer.ts
init_esm_shims();
import {
chmodSync as chmodSync2,
closeSync as closeSync2,
existsSync as existsSync21,
fstatSync,
mkdirSync as mkdirSync8,
openSync as openSync2,
readFileSync as readFileSync20,
writeFileSync as writeFileSync8
} from "fs";
import { dirname as dirname18, join as join39 } from "path";
function writeGeneratedFiles(projectRoot, files, options = {}) {
const written = [];
const skipped5 = [];
for (const file of files) {
const reportedPath = toPosixPath(file.path);
const target = join39(projectRoot, file.path);
if (!options.forceOverwrite && !file.autoUpdate && existsSync21(target)) {
skipped5.push(reportedPath);
continue;
}
mkdirSync8(dirname18(target), { recursive: true });
writeFileSync8(target, file.content);
if (file.executable === true) {
chmodSync2(target, 493);
}
written.push(reportedPath);
}
return { written, skipped: skipped5 };
}
function planGeneratedFiles(projectRoot, files) {
const entries = [];
for (const file of files) {
const reportedPath = toPosixPath(file.path);
const target = join39(projectRoot, file.path);
let fd;
try {
fd = openSync2(target, "r");
} catch (error) {
if (error.code === "ENOENT") {
entries.push({ path: reportedPath, action: "create" });
} else {
entries.push({
path: reportedPath,
action: "skip",
templateError: error instanceof Error ? error.message : "unreadable target path"
});
}
continue;
}
try {
const mtimeMs = fstatSync(fd).mtimeMs;
if (!file.autoUpdate) {
entries.push({ path: reportedPath, action: "skip", mtimeMs });
continue;
}
const existing = readFileSync20(fd);
const action = existing.equals(Buffer.from(file.content)) ? "skip" : "overwrite";
entries.push({ path: reportedPath, action, mtimeMs });
} catch (error) {
entries.push({
path: reportedPath,
action: "skip",
templateError: error instanceof Error ? error.message : "unreadable target path"
});
} finally {
closeSync2(fd);
}
}
return entries;
}
// src/onboarding/orchestrator.ts
init_esm_shims();
import { accessSync, constants as fsConstants, existsSync as existsSync26, readFileSync as readFileSync33, statSync as statSync5 } from "fs";
import { dirname as dirname24, join as join64 } from "path";
// src/planning/audit.ts
init_esm_shims();
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
import { dirname as dirname19, join as join40 } from "path";
function sanitize2(value) {
return String(value).replace(/[\r\n"]/g, (match) => {
if (match === '"') return "'";
return " ";
});
}
function appendPlanningAudit(projectRoot, level, event, fields = {}) {
const target = join40(projectRoot, PATHS.AUDIT_LOG);
mkdirSync9(dirname19(target), { recursive: true });
const suffix = Object.entries(fields).map(([key, value]) => `${key}="${sanitize2(value)}"`).join(" ");
appendFileSync2(
target,
`[${(/* @__PURE__ */ new Date()).toISOString()}] ${level} ${event}${suffix ? ` ${suffix}` : ""}
`,
"utf8"
);
}
// src/checks/prerequisites.ts
init_esm_shims();
import { existsSync as existsSync22, readdirSync as readdirSync4, readFileSync as readFileSync21 } from "fs";
import { join as join41 } from "path";
var ECOSYSTEM_FILES = {
composer: ["composer.lock"],
python: ["poetry.lock", "uv.lock", "Pipfile.lock", "pyproject.toml"],
node: ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"],
ruby: ["Gemfile.lock"]
};
var PYTHON_REQUIREMENTS = /^requirements.*\.txt$/i;
function normalize(name) {
return name.toLowerCase().replace(/_/g, "-");
}
function readIfPresent(path10) {
try {
return existsSync22(path10) ? readFileSync21(path10, "utf8") : null;
} catch {
return null;
}
}
function composerHas(content, name) {
let parsed;
try {
parsed = JSON.parse(content);
} catch {
return false;
}
const target = normalize(name);
const buckets = ["packages", "packages-dev"];
for (const bucket of buckets) {
const list = parsed?.[bucket];
if (!Array.isArray(list)) continue;
for (const entry of list) {
const entryName = entry?.name;
if (typeof entryName === "string" && normalize(entryName) === target) return true;
}
}
return false;
}
function hasPackage(projectRoot, ecosystem, name) {
const candidates = ECOSYSTEM_FILES[ecosystem].map((file) => join41(projectRoot, file));
if (ecosystem === "python") {
try {
for (const entry of readdirSync4(projectRoot)) {
if (PYTHON_REQUIREMENTS.test(entry)) candidates.push(join41(projectRoot, entry));
}
} catch {
}
}
const present = candidates.map((path10) => ({ path: path10, content: readIfPresent(path10) }));
const found = present.filter((entry) => entry.content !== null);
if (found.length === 0) return null;
const target = normalize(name);
for (const entry of found) {
if (ecosystem === "composer") {
if (composerHas(entry.content, name)) return true;
} else if (normalize(entry.content).includes(target)) {
return true;
}
}
return false;
}
var NODE_LOCKFILE_MANAGERS = [
["pnpm-lock.yaml", "pnpm"],
["yarn.lock", "yarn"],
["package-lock.json", "npm"]
];
function nodePackageManager(projectRoot) {
const found = NODE_LOCKFILE_MANAGERS.find(
([lockfile]) => existsSync22(join41(projectRoot, lockfile))
);
return found?.[1] ?? "npm";
}
// src/checks/test-runner.ts
init_esm_shims();
function selectTestRunner(stackProfile, command, projectRoot) {
const runners = getPackTestRunners(stackProfile.frameworks, projectRoot).filter(
(runner) => runner.structured_format !== "none"
);
if (runners.length === 0) return null;
const traits = stackProfile.traits ?? [];
const byTrait = runners.find(
(runner) => traits.some((trait) => trait.toLowerCase() === runner.runner_id.toLowerCase())
);
if (byTrait) return byTrait;
const normalized = command.toLowerCase();
const byCommand = runners.find((runner) => normalized.includes(runner.runner_id.toLowerCase()));
return byCommand ?? runners[0];
}
// src/checks/testing-record.ts
init_esm_shims();
import { createHash as createHash8 } from "crypto";
import { readdirSync as readdirSync5, writeFileSync as writeFileSync9 } from "fs";
import { join as join42 } from "path";
var PACKAGE_ECOSYSTEMS = {
composer: "composer",
php: "composer",
python: "python",
node: "node",
javascript: "node",
typescript: "node",
ruby: "ruby"
};
function resolvePackageEcosystem(frameworks, projectRoot) {
for (const pack of getPacksForFrameworks(frameworks, projectRoot)) {
const mapped = PACKAGE_ECOSYSTEMS[pack.manifest.ecosystem];
if (mapped) return mapped;
}
return null;
}
var ECOSYSTEM_LOCKFILES = {
composer: ["composer.lock"],
python: ["poetry.lock", "uv.lock", "Pipfile.lock", "pyproject.toml"],
node: ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"],
ruby: ["Gemfile.lock"]
};
function lockfileHash(projectRoot, ecosystem) {
if (!ecosystem) return void 0;
const files = [...ECOSYSTEM_LOCKFILES[ecosystem]];
if (ecosystem === "python") {
try {
for (const entry of readdirSync5(projectRoot)) {
if (/^requirements.*\.txt$/i.test(entry)) files.push(entry);
}
} catch {
}
}
const parts = [];
for (const file of files.sort()) {
try {
const text2 = readTextIfExistsSync(join42(projectRoot, file));
if (text2 !== null) parts.push(`${file}
${text2}`);
} catch {
}
}
if (parts.length === 0) return void 0;
return `sha256:${createHash8("sha256").update(parts.join("\0")).digest("hex")}`;
}
function insertParallelFlag(command, flag, structuredFlags) {
const sf = structuredFlags?.trim();
if (sf && command.includes(sf)) {
return command.replace(sf, `${flag} ${sf}`);
}
return `${command} ${flag}`;
}
function deriveTestingRecord(input) {
const { runner, sequentialTest, projectRoot, ecosystem, now } = input;
const detected_by = input.detectedBy ?? "script";
const hash = lockfileHash(projectRoot, ecosystem);
const base = {
runner_id: runner.runner_id,
detected_by,
recorded_at: now,
...hash ? { lockfile_hash: hash } : {}
};
const parallel = runner.parallel;
if (!parallel || parallel.mode === "unavailable") {
return {
testing: {
...base,
parallel: "unavailable",
reason: parallel?.reason ?? "unknown"
}
};
}
if (parallel.mode === "native") {
return { testing: { ...base, parallel: "native" } };
}
const pkg = parallel.requires_package;
const present = pkg && ecosystem ? hasPackage(projectRoot, ecosystem, pkg) : null;
if (present === true && parallel.flag) {
return {
test_parallel: insertParallelFlag(sequentialTest, parallel.flag, runner.structured_flags),
testing: { ...base, parallel: "available" }
};
}
if (present === false) {
return { testing: { ...base, parallel: "unavailable", reason: `${pkg}-missing` } };
}
return { testing: { ...base, parallel: "unknown", reason: "unknown" } };
}
function deriveTestingForProfile(input) {
const { stackProfile, commands, projectRoot, now } = input;
const runner = selectTestRunner(stackProfile, commands.test, projectRoot);
if (!runner || !projectRoot) return { commands };
const ecosystem = resolvePackageEcosystem(stackProfile.frameworks, projectRoot);
const derived = deriveTestingRecord({
runner,
sequentialTest: commands.test,
projectRoot,
ecosystem,
now,
detectedBy: input.detectedBy
});
const nextCommands = derived.test_parallel ? { ...commands, test_parallel: derived.test_parallel } : commands;
if (derived.test_parallel && input.mirrorDoc !== false) {
upsertStackDocCommandRow(projectRoot, "Test (parallel)", derived.test_parallel);
}
return { commands: nextCommands, testing: derived.testing };
}
var STACK_DOC_REL = "docs/instructions/stack/overview.md";
var STACK_DOC_HEADER = /^\|\s*action\s*\|\s*command\s*\|$/i;
function upsertStackDocCommandRow(projectRoot, action, command) {
const docPath = join42(projectRoot, STACK_DOC_REL);
const row = `| ${action} | ${command} |`;
const rowRe = new RegExp(`^\\|\\s*${escapeRegExp(action)}\\s*\\|.*\\|\\s*$`, "i");
let content = readTextIfExistsSync(docPath) ?? "";
const lines = content.split("\n");
const headerIdx = lines.findIndex((line) => STACK_DOC_HEADER.test(line.trim()));
if (headerIdx === -1) {
const section3 = [
"",
"## Test runner (recorded by paqad)",
"",
"| Action | Command |",
"|--------|---------|",
row,
""
].join("\n");
content = content.length > 0 ? `${trimTrailingChar(content, "\n")}
${section3}` : section3;
writeStackDoc(docPath, `${trimTrailingChar(content, "\n")}
`);
return;
}
const existingIdx = lines.findIndex(
(line, idx) => idx > headerIdx + 1 && rowRe.test(line.trim())
);
if (existingIdx !== -1) {
lines[existingIdx] = row;
} else {
let end = headerIdx + 1;
while (end + 1 < lines.length && lines[end + 1].trim().startsWith("|")) end += 1;
lines.splice(end + 1, 0, row);
}
writeStackDoc(docPath, lines.join("\n"));
}
function writeStackDoc(docPath, content) {
try {
writeFileSync9(docPath, content);
} catch (error) {
if (!isMissingFileError(error)) throw error;
}
}
function escapeRegExp(text2) {
return text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// src/resolver/resolver.ts
init_esm_shims();
var import_fast_glob6 = __toESM(require_out(), 1);
// src/resolver/artifact-types.ts
init_esm_shims();
var ARTIFACT_TYPES = [
"rules",
"skills",
"agents",
"hooks",
"templates",
"patterns",
"anti-patterns",
"checklists",
"mcp-configs"
];
var COLLISION_MAP = {
rules: "most-specific-wins",
skills: "most-specific-wins",
agents: "most-specific-wins",
hooks: "most-specific-wins",
templates: "most-specific-wins",
patterns: "additive-merge",
"anti-patterns": "additive-merge",
checklists: "additive-merge",
"mcp-configs": "additive-merge"
};
var ARTIFACT_OUTPUT_KEYS = {
rules: "rules",
skills: "skills",
agents: "agents",
hooks: "hooks",
templates: "templates",
patterns: "patterns",
"anti-patterns": "antiPatterns",
checklists: "checklists",
"mcp-configs": "mcpConfigs"
};
// src/resolver/inheritance.ts
init_esm_shims();
// src/resolver/capability-resolver.ts
init_esm_shims();
function resolveCapabilityDirectories(runtimeRoot, stack, capabilities, artifactType) {
const directoryName = resolveCapabilityArtifactDirectory(artifactType);
return capabilities.map(
(capability) => join(
runtimeRoot,
"capabilities",
"coding",
"stacks",
stack,
"capabilities",
capability,
directoryName
)
);
}
function resolveCapabilityArtifactDirectory(artifactType) {
switch (artifactType) {
case "mcp-configs":
return "mcp";
case "patterns":
return join("benchmarks", "patterns");
case "anti-patterns":
return join("benchmarks", "anti-patterns");
default:
return artifactType;
}
}
// src/resolver/inheritance.ts
function getInheritanceDirectories(runtimeRoot, routing, artifactType) {
if (artifactType === "hooks") {
return [
{
path: join(runtimeRoot, "hooks"),
level: 0,
source: relative(runtimeRoot, join(runtimeRoot, "hooks"))
}
];
}
if (artifactType === "templates") {
return [
{
path: join(runtimeRoot, "templates"),
level: 0,
source: relative(runtimeRoot, join(runtimeRoot, "templates"))
}
];
}
const directoryName = resolveArtifactDirectoryName(artifactType);
const activeCapabilities = deriveActiveCapabilities(routing);
const matchedPacks = deriveMatchedPacks(routing);
const traits = deriveTraits(routing);
const directories = [
{
path: join(runtimeRoot, "base", directoryName),
level: 0,
source: relative(runtimeRoot, join(runtimeRoot, "base", directoryName))
},
{
path: join(runtimeRoot, "capabilities", "content", directoryName),
level: 1,
source: relative(runtimeRoot, join(runtimeRoot, "capabilities", "content", directoryName))
}
];
if (activeCapabilities.includes("coding")) {
directories.push(
{
path: join(runtimeRoot, "capabilities", "coding", directoryName),
level: 2,
source: relative(runtimeRoot, join(runtimeRoot, "capabilities", "coding", directoryName))
},
{
path: join(runtimeRoot, "capabilities", "coding", "stacks", "_shared", directoryName),
level: 3,
source: relative(
runtimeRoot,
join(runtimeRoot, "capabilities", "coding", "stacks", "_shared", directoryName)
)
},
...matchedPacks.map((pack, index) => ({
path: join(runtimeRoot, "capabilities", "coding", "stacks", pack, directoryName),
level: 4 + Math.min(index, 1),
source: relative(
runtimeRoot,
join(runtimeRoot, "capabilities", "coding", "stacks", pack, directoryName)
)
})),
...matchedPacks.flatMap(
(pack) => resolveCapabilityDirectories(runtimeRoot, pack, traits, artifactType).map((path10) => ({
path: path10,
level: 5,
source: relative(runtimeRoot, path10)
}))
)
);
}
if (activeCapabilities.includes("security")) {
directories.push({
path: join(runtimeRoot, "capabilities", "security", directoryName),
level: 6,
source: relative(runtimeRoot, join(runtimeRoot, "capabilities", "security", directoryName))
});
}
return directories;
}
function deriveActiveCapabilities(routing) {
if (Array.isArray(routing.active_capabilities) && routing.active_capabilities.length > 0) {
return routing.active_capabilities;
}
if (routing.domain === "coding") {
return ["content", "coding", "security"];
}
return ["content"];
}
function deriveMatchedPacks(routing) {
if (Array.isArray(routing.matched_packs) && routing.matched_packs.length > 0) {
return routing.matched_packs;
}
if (Array.isArray(routing.stack_profile?.frameworks) && routing.stack_profile.frameworks.length > 0) {
return routing.stack_profile.frameworks;
}
if (typeof routing.stack === "string") {
return [routing.stack];
}
return [getPrimaryStack(routing)];
}
function deriveTraits(routing) {
if (Array.isArray(routing.capabilities)) {
return routing.capabilities;
}
return routing.stack_profile?.traits ?? [];
}
function resolveArtifactDirectoryName(artifactType) {
switch (artifactType) {
case "mcp-configs":
return "mcp";
case "patterns":
return join("benchmarks", "patterns");
case "anti-patterns":
return join("benchmarks", "anti-patterns");
default:
return artifactType;
}
}
// src/resolver/resolver.ts
var RULE_SEED_PRIORITY = [
"constitution",
"security",
"pentest",
"design-system",
"content-rules",
"testing",
"documentation",
"performance",
"pipeline",
"canonical-docs",
"architecture",
"code-quality",
"git",
"api-design",
"environment",
"foundation",
"conventions",
"inertia",
"react",
"vue",
"tailwind",
"boost"
];
var Resolver = class {
runtimeRoot;
constructor(options) {
this.runtimeRoot = options.runtimeRoot;
}
async resolve(routing, deduplicator) {
const result2 = {
rules: [],
skills: [],
agents: [],
hooks: [],
templates: [],
patterns: [],
antiPatterns: [],
checklists: [],
mcpConfigs: []
};
for (const artifactType of ARTIFACT_TYPES) {
const outputKey = ARTIFACT_OUTPUT_KEYS[artifactType];
const resolved = await this.resolveArtifactType(routing, artifactType);
if (deduplicator) {
const dedupArtifacts = resolved.map((a) => ({
path: a.path,
type: artifactType
}));
const { artifacts: deduplicated } = await deduplicator.deduplicate(
this.runtimeRoot,
dedupArtifacts
);
const resolvedByPath = new Map(resolved.map((a) => [a.path, a]));
result2[outputKey] = deduplicated.map((a) => resolvedByPath.get(a.path)).filter((a) => a !== void 0);
} else {
result2[outputKey] = resolved;
}
}
return result2;
}
async resolveArtifactType(routing, artifactType) {
const directories = getInheritanceDirectories(this.runtimeRoot, routing, artifactType);
const entries = [];
const overrides = /* @__PURE__ */ new Map();
for (const directory of directories) {
const files = await (0, import_fast_glob6.default)("**/*", {
cwd: directory.path,
onlyFiles: true,
absolute: true,
dot: false
});
for (const file of files.sort()) {
const artifact = {
path: file,
level: directory.level,
source: relative(this.runtimeRoot, file)
};
if (COLLISION_MAP[artifactType] === "additive-merge") {
entries.push(artifact);
continue;
}
overrides.set(relative(directory.path, file), artifact);
}
}
const resolved = COLLISION_MAP[artifactType] === "additive-merge" ? entries : Array.from(overrides.values());
if (artifactType === "rules") {
return resolved.sort(compareRuleSeedOrder);
}
return resolved;
}
};
function compareRuleSeedOrder(left, right) {
const leftPriority = getRulePriority(left.path);
const rightPriority = getRulePriority(right.path);
if (leftPriority !== rightPriority) {
return leftPriority - rightPriority;
}
return left.source.localeCompare(right.source);
}
function getRulePriority(filePath) {
const name = basename(filePath, extname(filePath));
const index = RULE_SEED_PRIORITY.indexOf(name);
return index === -1 ? RULE_SEED_PRIORITY.length : index;
}
// src/planning/index.ts
init_esm_shims();
// src/planning/contract-boundary.ts
init_esm_shims();
var import_fast_glob7 = __toESM(require_out(), 1);
import { readFile as readFile20 } from "fs/promises";
import { basename as basename5, extname as extname3, join as join43, relative as relative10 } from "path";
async function detectContractBoundaries(root, touchedFiles) {
const tsFiles = await (0, import_fast_glob7.default)("src/**/*.ts", { cwd: root, onlyFiles: true });
const untouchedFiles = tsFiles.filter((file) => !touchedFiles.includes(file));
const boundaries = [];
for (const touchedFile of touchedFiles.filter((file) => file.endsWith(".ts"))) {
const raw = await readFile20(join43(root, touchedFile), "utf8").catch(() => "");
const exportedSymbols = Array.from(
raw.matchAll(
/export\s+(?:async\s+)?(?:function|const|class|type|interface)\s+([A-Za-z_]\w*)/g
),
(match) => match[1]
);
if (exportedSymbols.length === 0) {
continue;
}
const stem = basename5(touchedFile, extname3(touchedFile));
const importers = [];
for (const candidate of untouchedFiles) {
const source = await readFile20(join43(root, candidate), "utf8").catch(() => "");
if (source.includes(stem) || source.includes(
relative10(join43(root, candidate, ".."), join43(root, touchedFile)).replace(/\\/g, "/")
)) {
importers.push(candidate);
}
}
for (const symbol of exportedSymbols) {
if (importers.length > 0) {
boundaries.push({ file: touchedFile, symbol, importers });
}
}
}
return boundaries;
}
function injectContractBoundaryCriteria(manifest, boundaries) {
if (boundaries.length === 0) {
return manifest;
}
let nextId = nextCriterionId(manifest.verification_matrix);
const injected = boundaries.map((boundary) => ({
criterion_id: `AC-${nextId++}`,
given: `${boundary.symbol} is imported outside the current execution scope.`,
when: `${boundary.file} changes.`,
then: `Existing importers remain compatible: ${boundary.importers.join(", ")}`,
proof_type: "manual",
status: "uncovered",
source: "contract-boundary",
linked_requirement_ids: manifest.requirement_graph.filter((requirement) => requirement.scope.includes(boundary.file)).map((requirement) => requirement.id)
}));
return {
...manifest,
verification_matrix: [...manifest.verification_matrix, ...injected]
};
}
function nextCriterionId(criteria) {
return criteria.reduce((max, criterion) => {
const match = criterion.criterion_id.match(/^AC-(\d+)$/);
return Math.max(max, match ? Number(match[1]) : 0);
}, 0) + 1;
}
// src/planning/decision-resolver.ts
init_esm_shims();
import { existsSync as existsSync23, readFileSync as readFileSync22, readdirSync as readdirSync6 } from "fs";
import { join as join44 } from "path";
async function resolveDecisionPacket(projectRoot, packet) {
const profile = readProjectProfile(projectRoot);
const ruleMatch = await resolveByCompiledRule(projectRoot, packet);
if (ruleMatch) {
return ruleMatch;
}
const designSystemMatch = resolveByDesignSystem(projectRoot, packet);
if (designSystemMatch) {
return designSystemMatch;
}
const profileMatch = resolveByProfile(packet, profile);
if (profileMatch) {
return profileMatch;
}
const confidentMatch = resolveByConfidence(projectRoot, packet);
if (confidentMatch) {
return confidentMatch;
}
return { source: "ask" };
}
function askThresholdForProject(projectRoot) {
const askThreshold = readProjectProfile(projectRoot)?.custom?.decisions?.ask_threshold ?? "strict";
switch (askThreshold) {
case "strict":
return 0.95;
case "permissive":
return 0.75;
default:
return 0.85;
}
}
async function resolveByCompiledRule(projectRoot, packet) {
const rules = await readCompiledRules(projectRoot);
if (!rules) {
return null;
}
const touchedFiles = watchedFilesForPacket(packet);
const matchingRule = rules.rules.find(
(rule) => rule.trigger_patterns.some(
(pattern) => touchedFiles.some((file) => matchesGlobish(file, pattern))
)
);
if (!matchingRule) {
return null;
}
const matchingOption = packet.options.find((option2) => option2.evidence.rule_match === matchingRule.rule_id) ?? /* v8 ignore start */
packet.options.find(
(option2) => option2.evidence.file ? matchingRule.trigger_patterns.some(
(pattern) => matchesGlobish(option2.evidence.file, pattern)
) : false
/* v8 ignore stop */
);
if (!matchingOption && !packet.recommendation) {
return null;
}
return {
source: "rule",
/* v8 ignore start -- fallback chain for missing option or recommendation; always resolved in tests */
option_key: matchingOption?.option_key ?? packet.recommendation ?? void 0,
/* v8 ignore stop */
reason: `Matched compiled rule ${matchingRule.rule_id}.`
};
}
function resolveByDesignSystem(projectRoot, packet) {
if (!supportsDesignSystemResolution(packet.category)) {
return null;
}
const designSystemDir = join44(projectRoot, PATHS.DESIGN_SYSTEM_DIR);
if (!existsSync23(designSystemDir)) {
return null;
}
const files = safeListMarkdownFiles(designSystemDir);
if (files.length === 0) {
return null;
}
const signal5 = files.some((file) => {
const content = safeReadFile(join44(designSystemDir, file));
return /\breuse\b|\bexisting\b|\bone\b.{0,20}\bcomponent\b/i.test(content);
});
if (!signal5) {
return null;
}
return {
source: "design-system",
option_key: packet.options.find((option2) => /^reuse|^keep|^use current|^stay/i.test(option2.option_key))?.option_key ?? packet.recommendation ?? void 0,
reason: "Design system docs prefer the existing pattern."
};
}
function resolveByProfile(packet, profile) {
const preferredOptionKey = profile?.custom?.decisions?.preferred_option_keys?.[packet.category];
if (!preferredOptionKey || !packet.options.some((option2) => option2.option_key === preferredOptionKey)) {
return null;
}
return {
source: "profile",
option_key: preferredOptionKey,
reason: `Project profile prefers ${preferredOptionKey}.`
};
}
function resolveByConfidence(projectRoot, packet) {
const floor = 0.55;
const ranked = [...packet.options].map((option2) => ({
option_key: option2.option_key,
similarity: option2.evidence.similarity ?? 0
})).filter((option2) => option2.similarity >= floor).sort((left, right) => right.similarity - left.similarity);
const best = ranked[0];
const second = ranked[1];
if (!best) {
if (packet.recommendation && packet.confidence >= askThresholdForProject(projectRoot)) {
return {
source: "rag-confident",
option_key: packet.recommendation,
reason: `Confidence ${packet.confidence.toFixed(2)} met the project ask threshold.`
};
}
return null;
}
const threshold = askThresholdForProject(projectRoot);
const secondScore = second?.similarity ?? 0;
if (best.similarity < threshold || secondScore > threshold - 0.2) {
return null;
}
return {
source: "rag-confident",
option_key: best.option_key,
reason: `Confidence ${best.similarity.toFixed(2)} met the project ask threshold.`
};
}
function watchedFilesForPacket(packet) {
return [
.../* @__PURE__ */ new Set([
...packet.invalidation_watch,
...packet.options.map((option2) => option2.evidence.file).filter(Boolean)
])
];
}
function supportsDesignSystemResolution(category) {
return category === "component-reuse" || category === "create-vs-reuse" || category === "ux-pattern";
}
function safeListMarkdownFiles(dir) {
try {
return readdirSync6(dir).filter((file) => file.endsWith(".md"));
} catch {
return [];
}
}
function safeReadFile(path10) {
try {
return readFileSync22(path10, "utf8");
} catch {
return "";
}
}
function matchesGlobish(value, pattern) {
const normalizedValue = value.replace(/\\/g, "/");
const normalizedPattern = pattern.replace(/\\/g, "/");
if (normalizedPattern === "**") {
return true;
}
const escaped = normalizedPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
const regex = new RegExp(
`^${escaped.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".")}$`
);
return regex.test(normalizedValue) || normalizedValue.includes(normalizedPattern.replace(/\*/g, ""));
}
// src/planning/cost-predictor.ts
init_esm_shims();
import { mkdir as mkdir18, readFile as readFile21, writeFile as writeFile19 } from "fs/promises";
import { join as join45 } from "path";
var DEFAULT_CEILINGS = {
fast: 600,
graduated: 1800,
full: 3500
};
var MIN_FLOORS = {
fast: 400,
graduated: 800,
full: 1500
};
async function predictTokenCeiling(root, options) {
const log = await readCostLog(root);
const matches = log.entries.filter(
(entry) => entry.classification.lane === options.lane && entry.classification.complexity === options.complexity && (entry.classification.scope ?? "unknown") === (options.scope ?? "unknown")
).map((entry) => entry.actual_tokens).sort((left, right) => left - right);
if (matches.length < 3) {
return DEFAULT_CEILINGS[options.lane];
}
const percentileIndex = Math.ceil(matches.length * 0.75) - 1;
const p75 = matches[Math.max(percentileIndex, 0)] ?? DEFAULT_CEILINGS[options.lane];
return Math.max(MIN_FLOORS[options.lane], Math.ceil(p75 * 1.2));
}
async function appendCostEntry(root, entry) {
const log = await readCostLog(root);
log.entries.push(entry);
await mkdir18(join45(root, PATHS.AGENCY_CACHE_DIR), { recursive: true });
await writeFile19(join45(root, PATHS.PLANNING_COSTS), JSON.stringify(log, null, 2) + "\n", "utf8");
}
async function readCostLog(root) {
try {
const raw = await readFile21(join45(root, PATHS.PLANNING_COSTS), "utf8");
return JSON.parse(raw);
} catch {
return { entries: [] };
}
}
// src/planning/coverage-overlay.ts
init_esm_shims();
var import_fast_glob8 = __toESM(require_out(), 1);
import { readFile as readFile22 } from "fs/promises";
import { join as join46 } from "path";
async function buildCoverageOverlay(root, modules) {
const testFiles2 = await (0, import_fast_glob8.default)(["tests/**/*.ts", "src/**/*.test.ts"], {
cwd: root,
onlyFiles: true
});
const relevantModules = new Set(modules.filter(Boolean));
const entries = /* @__PURE__ */ new Map();
for (const file of testFiles2) {
if (relevantModules.size > 0 && !matchesModule(file, relevantModules)) {
continue;
}
const raw = await readFile22(join46(root, file), "utf8");
const matches = Array.from(raw.matchAll(/@obligation\s+([A-Z]+-\d+)/g), (match) => match[1]);
if (matches.length === 0) {
const fallbackId = file.split("/").pop()?.replace(/\.test\.ts$/, "")?.replace(/[^A-Za-z0-9-]+/g, "-")?.toUpperCase();
if (fallbackId) {
entries.set(fallbackId, {
criterion_id: fallbackId,
status: "partial",
evidence_files: [file]
});
}
continue;
}
for (const criterionId of matches) {
const current = entries.get(criterionId);
entries.set(criterionId, {
criterion_id: criterionId,
status: "covered",
evidence_files: [.../* @__PURE__ */ new Set([...current?.evidence_files ?? [], file])]
});
}
}
return [...entries.values()].sort(
(left, right) => left.criterion_id.localeCompare(right.criterion_id)
);
}
function markCriteriaFromOverlay(criteria, overlay) {
return criteria.map((criterion) => {
const exact = overlay.find((entry) => entry.criterion_id === criterion.criterion_id);
if (exact) {
return { ...criterion, status: exact.status };
}
const proofTargetName = criterion.proof_target?.split("/").pop()?.replace(/\.[^.]+$/, "");
const fuzzy = overlay.find((entry) => {
const entryName = entry.evidence_files[0]?.split("/").pop()?.replace(/\.[^.]+$/, "");
return proofTargetName !== void 0 && entryName === proofTargetName || normalizeToken(criterion.criterion_id) === normalizeToken(entry.criterion_id) || /* c8 ignore next */
normalizeToken(criterion.criterion_id) === normalizeToken(entryName ?? "");
});
if (fuzzy) {
return { ...criterion, status: "partial" };
}
return { ...criterion, status: criterion.status ?? "uncovered" };
});
}
function matchesModule(file, modules) {
if (file.startsWith("tests/")) {
return true;
}
return [...modules].some(
(moduleName) => file.includes(`/${moduleName}/`) || file.startsWith(`${moduleName}/`)
);
}
function normalizeToken(value) {
return value.toLowerCase().replace(/[^a-z0-9]+/g, "");
}
// src/planning/defect-advisory.ts
init_esm_shims();
async function queryMatchingDefectPatterns(options) {
return queryPatterns({
stack_context: {
frameworks: [options.stack],
traits: options.affectedModules
},
limit: 5,
min_frequency: 3
});
}
function injectDefectAdvisoryCriteria(manifest, patterns) {
if (patterns.length === 0) {
return manifest;
}
let nextId = nextCriterionId2(manifest.verification_matrix);
const allRequirementIds = manifest.requirement_graph.map((requirement) => requirement.id);
const linkedRequirementIds = allRequirementIds.length > 0 ? allRequirementIds.slice(0, 3) : allRequirementIds;
const injected = patterns.slice(0, 5).map((pattern) => {
const strength = pattern.frequency > 10 ? "must" : "should";
return {
criterion_id: `AC-${nextId++}`,
given: `A historical defect pattern (${pattern.subcategory}) exists for this stack.`,
when: `The affected modules ${manifest.classification.affected_modules.join(", ") || "in scope"} change.`,
then: `The implementation ${strength} avoid the recurring defect: ${pattern.description}`,
proof_type: "manual",
status: "uncovered",
source: "defect-pattern",
linked_requirement_ids: linkedRequirementIds,
pattern_id: pattern.pattern_id
};
});
return {
...manifest,
verification_matrix: [...manifest.verification_matrix, ...injected]
};
}
function nextCriterionId2(criteria) {
return criteria.reduce((max, criterion) => {
const match = criterion.criterion_id.match(/^AC-(\d+)$/);
return Math.max(max, match ? Number(match[1]) : 0);
}, 0) + 1;
}
// src/planning/delta-merger.ts
init_esm_shims();
function mergeDeltaManifest(base, delta) {
return {
...base,
...delta,
requirement_graph: mergeById(
base.requirement_graph,
delta.requirement_graph,
(item) => item.id
),
execution_slices: mergeById(
base.execution_slices,
delta.execution_slices,
(item) => item.slice_id
),
verification_matrix: mergeById(
base.verification_matrix,
delta.verification_matrix,
(item) => item.criterion_id
),
decision_log: mergeById(base.decision_log, delta.decision_log, (item) => item.decision_id),
doc_targets: delta.doc_targets.length > 0 ? delta.doc_targets : base.doc_targets,
regression_watch: delta.regression_watch.length > 0 ? delta.regression_watch : base.regression_watch
};
}
function computeDelta(base, updated) {
return {
requirement_graph: diffById(
base.requirement_graph,
updated.requirement_graph,
(item) => item.id
),
execution_slices: diffById(
base.execution_slices,
updated.execution_slices,
(item) => item.slice_id
),
verification_matrix: diffById(
base.verification_matrix,
updated.verification_matrix,
(item) => item.criterion_id
),
decision_log: {
added: updated.decision_log.filter(
(item) => !base.decision_log.some((current) => current.decision_id === item.decision_id)
)
}
};
}
function mergeById(base, updated, idOf) {
const merged = new Map(base.map((item) => [idOf(item), item]));
for (const item of updated) {
merged.set(idOf(item), item);
}
return [...merged.values()];
}
function diffById(base, updated, idOf) {
const baseMap = new Map(base.map((item) => [idOf(item), item]));
const updatedMap = new Map(updated.map((item) => [idOf(item), item]));
const added = updated.filter((item) => !baseMap.has(idOf(item)));
const removed = base.filter((item) => !updatedMap.has(idOf(item)));
const changed = updated.flatMap((item) => {
const id = idOf(item);
const previous = baseMap.get(id);
if (!previous) {
return [];
}
return Object.entries(item).flatMap(([field, value]) => {
const oldValue = previous[field];
return JSON.stringify(oldValue) === JSON.stringify(value) ? [] : [{ id, field, old_value: oldValue, new_value: value }];
});
});
return { added, changed, removed };
}
// src/planning/doc-target-resolver.ts
init_esm_shims();
import { access as access2 } from "fs/promises";
import { posix as posix2 } from "path";
var { join: join47 } = posix2;
async function resolveDocTargets(root, executionSlices, apiImpact, uiImpact) {
const targets = [];
let nextId = 1;
for (const slice of executionSlices) {
for (const touched of slice.touches) {
const moduleName = deriveModuleName(touched);
if (!moduleName) {
continue;
}
const technicalDoc = join47("docs/modules", moduleName, "technical.md");
if (await exists(join47(root, technicalDoc))) {
targets.push({
target_id: `DOC-${nextId++}`,
file: technicalDoc,
section: "Technical Notes",
reason: `${slice.slice_id} touches ${touched}`,
slice_id: slice.slice_id,
status: "pending"
});
}
if (apiImpact && (touched.includes("/api/") || touched.includes("api"))) {
targets.push({
target_id: `DOC-${nextId++}`,
file: join47("docs/modules", moduleName, "api", "endpoints.md"),
section: "API Changes",
reason: `${slice.slice_id} changes API behavior`,
slice_id: slice.slice_id,
status: "pending"
});
}
if (uiImpact && (touched.includes("/ui/") || touched.includes("/components/") || touched.includes("/pages/"))) {
targets.push({
target_id: `DOC-${nextId++}`,
file: join47("docs/modules", moduleName, "ui", "components.md"),
section: "UI Changes",
reason: `${slice.slice_id} changes UI behavior`,
slice_id: slice.slice_id,
status: "pending"
});
}
}
}
return dedupeTargets(targets);
}
function deriveModuleName(touched) {
const segments = touched.split("/").filter(Boolean);
if (segments[0] === "src" && segments[1]) {
return segments[1];
}
if (segments[0] === "app" && segments[1]) {
return segments[1];
}
return null;
}
async function exists(path10) {
try {
await access2(path10);
return true;
} catch {
return false;
}
}
function dedupeTargets(targets) {
const seen = /* @__PURE__ */ new Set();
return targets.filter((target) => {
const key = `${target.file}:${target.section}:${target.slice_id}`;
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
// src/planning/full-suite-runner.ts
init_esm_shims();
var SLOW_SUITE_THRESHOLD_MS = 6e4;
async function verifyFullSuite(runFullSuite, baselineFailingTests = []) {
const result2 = await runFullSuite();
const baseline = new Set(baselineFailingTests);
const newFailures = result2.failing_tests.filter((test) => !baseline.has(test));
const preExistingFailures = result2.failing_tests.filter((test) => baseline.has(test));
return {
total_tests: result2.total_tests,
passing: result2.passing,
failing: result2.failing,
new_failures: newFailures,
pre_existing_failures: preExistingFailures,
duration_ms: result2.duration_ms,
slow_suite_warning: result2.duration_ms > SLOW_SUITE_THRESHOLD_MS
};
}
// src/planning/intelligence-assembler.ts
init_esm_shims();
var import_fast_glob9 = __toESM(require_out(), 1);
import { readFile as readFile23 } from "fs/promises";
import { join as join48 } from "path";
async function assembleIntelligence(root, classification) {
await syncModuleHealth({
projectRoot: root,
source: "preflight",
preflight: true,
silent: true
});
const [groupA, groupB, predictedTokens] = await Promise.all([
Promise.all([
readAllModuleHealth(root),
readCompiledRules(root),
readInheritedConstraints(root, classification.affected_modules)
]),
Promise.all([
buildCoverageOverlay(root, classification.affected_modules),
queryMatchingDefectPatterns({
stack: classification.stack,
affectedModules: classification.affected_modules
}),
loadSelectiveDocs(root, classification.affected_modules),
findExistingImplementations(root, classification.affected_modules)
]),
predictTokenCeiling(root, {
lane: classification.lane,
complexity: classification.complexity,
scope: classification.scope
})
]);
const [moduleHealth, compiledRules, inheritedConstraints] = groupA;
const [coverageOverlay, defectPatterns, selectiveDocs, existingImplementations] = groupB;
return {
module_health: moduleHealth,
compiled_rules: compiledRules,
inherited_constraints: inheritedConstraints,
coverage_overlay: coverageOverlay,
defect_patterns: defectPatterns.map((pattern) => ({
pattern_id: pattern.pattern_id,
subcategory: pattern.subcategory,
description: pattern.description,
frequency: pattern.frequency
})),
selective_docs: selectiveDocs,
existing_implementations: existingImplementations,
predicted_tokens: predictedTokens
};
}
async function readInheritedConstraints(root, modules) {
const files = await (0, import_fast_glob9.default)(`${PATHS.PLANNING_MANIFESTS_DIR}/*.yaml`, { cwd: root, onlyFiles: true });
return files.filter((file) => modules.some((moduleName) => file.includes(moduleName)));
}
async function loadSelectiveDocs(root, modules) {
const modulePatterns = modules.length > 0 ? modules.map((moduleName) => `docs/modules/${moduleName}/**/*.md`) : ["docs/instructions/**/*.md"];
const files = await (0, import_fast_glob9.default)(modulePatterns, { cwd: root, onlyFiles: true });
const selected = files.slice(0, 5);
return Promise.all(
selected.map(async (file) => ({
path: file,
content: await readFile23(join48(root, file), "utf8")
}))
);
}
async function findExistingImplementations(root, modules) {
const patterns = modules.length > 0 ? modules.map((moduleName) => `src/${moduleName}/**/*.ts`) : ["src/**/*.ts"];
const files = await (0, import_fast_glob9.default)(patterns, { cwd: root, onlyFiles: true });
return files.slice(0, 5).map((file, index) => ({
file_path: file,
/* c8 ignore next */
function_name: file.split("/").pop()?.replace(/\.ts$/, "") ?? `impl-${index + 1}`,
description: `Existing implementation candidate in ${file}`,
relevance_score: Number((1 - index * 0.1).toFixed(2))
}));
}
// src/planning/manifest-types.ts
init_esm_shims();
// src/planning/plan-vs-actual.ts
init_esm_shims();
import { mkdir as mkdir19, writeFile as writeFile20 } from "fs/promises";
import { join as join49 } from "path";
function computePlanVsActual(manifest, actual) {
const plannedFiles = [...new Set(manifest.execution_slices.flatMap((slice) => slice.touches))];
const changedFiles = [...new Set(actual.changed_files)];
const usedFiles = [...new Set(actual.used_files ?? changedFiles)];
const coveredCriteria = new Set(actual.covered_criteria ?? []);
const matchedFiles = plannedFiles.filter((file) => changedFiles.includes(file));
const coveredCount = manifest.verification_matrix.filter(
(criterion) => coveredCriteria.has(criterion.criterion_id)
).length;
return {
scope_accuracy_pct: plannedFiles.length === 0 ? 100 : round(matchedFiles.length / plannedFiles.length * 100),
criteria_pass_rate_pct: manifest.verification_matrix.length === 0 ? 100 : round(coveredCount / manifest.verification_matrix.length * 100),
unplanned_files: changedFiles.filter((file) => !plannedFiles.includes(file)),
planned_but_unused_files: plannedFiles.filter((file) => !usedFiles.includes(file)),
uncovered_criteria: manifest.verification_matrix.map((criterion) => criterion.criterion_id).filter((criterionId) => !coveredCriteria.has(criterionId))
};
}
async function writePlanVsActual(root, slug, diff) {
const dir = join49(root, PATHS.PLANNING_MANIFESTS_DIR);
await mkdir19(dir, { recursive: true });
const filePath = join49(dir, `${slug}.plan-vs-actual.json`);
await writeFile20(filePath, JSON.stringify(diff, null, 2) + "\n", "utf8");
return toPosixPath(filePath);
}
function round(value) {
return Math.round(value * 100) / 100;
}
// src/planning/reconnect-check.ts
init_esm_shims();
function computeReconnect(input) {
const review = input.lane === "full" ? "agent-re-read" : "structural";
const frozenCriterionIds = input.spec.acceptance_criteria.map(
(criterion) => criterion.criterion_id
);
if (input.spec.frozen === null) {
return {
coherent: false,
anchored: false,
review,
frozen_criteria_total: frozenCriterionIds.length,
uncovered_criteria: [...frozenCriterionIds],
unproven_criteria: [],
unwired_seams: [],
contradictions: []
};
}
const frozenSet = new Set(frozenCriterionIds);
const provenSet = new Set(input.snapshot.covered_criteria ?? []);
const sliceIds = new Set(input.slices.map((slice) => slice.slice_id));
const owners = ownersByCriterion(input.slices);
const uncovered = [];
const unproven = [];
for (const criterionId of frozenCriterionIds) {
const ownerSlices = owners.get(criterionId) ?? [];
if (ownerSlices.length === 0) {
uncovered.push(criterionId);
continue;
}
if (!provenSet.has(criterionId)) {
unproven.push(criterionId);
}
}
const contradictions = collectContradictions(owners, frozenSet);
const unwiredSeams = collectSeams(input.slices, sliceIds, owners, frozenSet, provenSet);
const coherent = uncovered.length === 0 && unproven.length === 0 && unwiredSeams.length === 0 && contradictions.length === 0;
return {
coherent,
anchored: true,
review,
frozen_criteria_total: frozenCriterionIds.length,
uncovered_criteria: uncovered,
unproven_criteria: unproven,
unwired_seams: unwiredSeams,
contradictions
};
}
function renderReconnectReport(report) {
const mark = (ok) => ok ? "\u2713" : "\u2717";
const proven = report.frozen_criteria_total - report.uncovered_criteria.length;
const lines = [
"# Reconnect to the whole",
"",
`- [${mark(report.anchored)}] Anchored on the frozen feature spec`,
`- [${mark(report.uncovered_criteria.length === 0)}] Every frozen criterion is owned by a slice (${proven}/${report.frozen_criteria_total})`,
`- [${mark(report.unproven_criteria.length === 0)}] Every covered criterion is proven`,
`- [${mark(report.unwired_seams.length === 0)}] No cross-slice seam left unwired`,
`- [${mark(report.contradictions.length === 0)}] No slice contradicts another`,
"",
`Review: ${report.review}`,
`Result: ${report.coherent ? "COHERENT" : "INCOHERENT"}`
];
if (!report.anchored) {
lines.push(
"Blocked: the feature spec is not frozen; there is no written anchor to reconnect to."
);
}
if (report.uncovered_criteria.length > 0) {
lines.push(`Uncovered criteria: ${report.uncovered_criteria.join(", ")}.`);
}
if (report.unproven_criteria.length > 0) {
lines.push(`Unproven criteria: ${report.unproven_criteria.join(", ")}.`);
}
for (const seam of report.unwired_seams) {
lines.push(`Unwired seam: ${seam.detail}`);
}
for (const contradiction of report.contradictions) {
lines.push(`Contradiction: ${contradiction.detail}`);
}
return `${lines.join("\n")}
`;
}
function ownersByCriterion(slices) {
const owners = /* @__PURE__ */ new Map();
for (const slice of slices) {
for (const cover of slice.covers) {
if (!/^AC-\d+$/.test(cover)) {
continue;
}
const bucket = owners.get(cover) ?? [];
bucket.push(slice.slice_id);
owners.set(cover, bucket);
}
}
return owners;
}
function collectContradictions(owners, frozenSet) {
const contradictions = [];
for (const [criterionId, ownerSlices] of owners) {
if (!frozenSet.has(criterionId)) {
contradictions.push({
kind: "off-spec",
criterion_id: criterionId,
slice_ids: [...ownerSlices].sort(compareIds),
detail: `${criterionId} is covered by ${ownerSlices.join(", ")} but is not in the frozen spec.`
});
continue;
}
if (ownerSlices.length > 1) {
contradictions.push({
kind: "double-owned",
criterion_id: criterionId,
slice_ids: [...ownerSlices].sort(compareIds),
detail: `${criterionId} is owned by more than one slice (${ownerSlices.join(", ")}); ownership is ambiguous.`
});
}
}
return contradictions.sort((left, right) => compareIds(left.criterion_id, right.criterion_id));
}
function collectSeams(slices, sliceIds, owners, frozenSet, provenSet) {
const frozenCoveredBySlice = /* @__PURE__ */ new Map();
for (const [criterionId, ownerSlices] of owners) {
if (!frozenSet.has(criterionId)) {
continue;
}
for (const sliceId of ownerSlices) {
const bucket = frozenCoveredBySlice.get(sliceId) ?? [];
bucket.push(criterionId);
frozenCoveredBySlice.set(sliceId, bucket);
}
}
const seams = [];
for (const slice of slices) {
for (const dependency of slice.depends_on) {
if (!sliceIds.has(dependency)) {
seams.push({
slice_id: slice.slice_id,
depends_on: dependency,
kind: "dangling",
detail: `${slice.slice_id} depends on ${dependency}, which is absent from the assembly.`
});
continue;
}
const upstreamCriteria = frozenCoveredBySlice.get(dependency) ?? [];
const unprovenUpstream = upstreamCriteria.filter(
(criterionId) => !provenSet.has(criterionId)
);
if (unprovenUpstream.length > 0) {
seams.push({
slice_id: slice.slice_id,
depends_on: dependency,
kind: "upstream-unproven",
detail: `${slice.slice_id} is wired onto ${dependency}, whose criteria are not all proven (${unprovenUpstream.join(", ")}).`
});
}
}
}
return seams;
}
function compareIds(left, right) {
return left.localeCompare(right, void 0, { numeric: true });
}
// src/planning/regression-detector.ts
init_esm_shims();
var import_fast_glob10 = __toESM(require_out(), 1);
import { readFile as readFile24 } from "fs/promises";
import { basename as basename6, extname as extname4, join as join50 } from "path";
async function buildRegressionWatchList(root, executionSlices) {
const testFiles2 = await (0, import_fast_glob10.default)("tests/**/*.ts", { cwd: root, onlyFiles: true });
const entries = [];
let index = 1;
for (const slice of executionSlices) {
for (const touchedFile of slice.touches) {
const stem = basename6(touchedFile, extname4(touchedFile));
for (const testFile of testFiles2) {
const raw = await readFile24(join50(root, testFile), "utf8").catch(() => "");
if (!raw.includes(stem) && !raw.includes(touchedFile)) {
continue;
}
const testName = raw.match(/(?:it|test)\((['"`])(.+?)\1/)?.[2];
entries.push({
entry_id: `REG-${index++}`,
test_file: testFile,
test_name: testName,
touched_file: touchedFile,
slice_id: slice.slice_id,
status: "pending"
});
}
}
}
return entries;
}
// src/planning/rule-injection.ts
init_esm_shims();
function injectRuleCriteria(manifest, compiledRules) {
if (!compiledRules || compiledRules.rules.length === 0) {
return manifest;
}
let nextCriterionNumber = nextCriterionId3(manifest.verification_matrix);
const injected = [];
for (const rule of compiledRules.rules) {
const matchingSlices = manifest.execution_slices.filter(
(slice) => slice.touches.some(
(touch) => rule.trigger_patterns.some((pattern) => pattern === "**" || touch.includes(pattern))
)
);
if (matchingSlices.length === 0) {
continue;
}
const linkedRequirementIds = [
...new Set(
matchingSlices.flatMap(
(slice) => slice.covers.filter((id) => /^((FR|NFR|EC|CONSTRAINT)-\d+)$/.test(id))
)
)
];
if (linkedRequirementIds.length === 0) {
continue;
}
const duplicate = manifest.verification_matrix.some(
(criterion) => criterion.rule_id === rule.rule_id
);
if (duplicate) {
continue;
}
injected.push({
criterion_id: `AC-${nextCriterionNumber++}`,
given: `The change touches files matched by rule ${rule.rule_id}.`,
when: `Implementation for ${linkedRequirementIds.join(", ")} is completed.`,
then: rule.summary,
proof_type: "manual",
status: "uncovered",
source: "compiled-rule",
linked_requirement_ids: linkedRequirementIds,
rule_id: rule.rule_id
});
}
return {
...manifest,
verification_matrix: [...manifest.verification_matrix, ...injected]
};
}
function nextCriterionId3(criteria) {
return criteria.reduce((max, criterion) => {
const match = criterion.criterion_id.match(/^AC-(\d+)$/);
return Math.max(max, match ? Number(match[1]) : 0);
}, 0) + 1;
}
// src/planning/skeleton-emitter.ts
init_esm_shims();
import { mkdir as mkdir20, writeFile as writeFile21 } from "fs/promises";
import { dirname as dirname20, join as join51 } from "path";
async function emitTestSkeletons(root, criteria, stack) {
const automated = criteria.filter(
(criterion) => criterion.proof_type === "automated" && criterion.status === "uncovered" && criterion.proof_target !== void 0
);
const grouped = /* @__PURE__ */ new Map();
for (const criterion of automated) {
const proofTarget = criterion.proof_target;
const current = grouped.get(proofTarget) ?? [];
current.push(criterion);
grouped.set(proofTarget, current);
}
const written = [];
for (const [proofTarget, group] of grouped) {
const absolutePath = join51(root, proofTarget);
await mkdir20(dirname20(absolutePath), { recursive: true });
await writeFile21(absolutePath, renderSkeletonFile(group, stack), "utf8");
written.push(proofTarget);
}
return written.sort();
}
function renderSkeletonFile(criteria, stack) {
const cases = criteria.map((criterion) => renderCriterionBlock(criterion)).join("\n\n");
return `import { describe, it } from 'vitest';
// Generated planning skeleton for ${stack}
describe('Planning manifest obligations', () => {
${indent(cases, 2)}
});
`;
}
function renderCriterionBlock(criterion) {
const blocks = [
renderTestCase(
criterion.criterion_id,
`${criterion.given} / ${criterion.when} / ${criterion.then}`
),
...renderVerificationCases(criterion.criterion_id, "negative", criterion.negative_cases),
...renderVerificationCases(criterion.criterion_id, "edge", criterion.edge_cases),
...renderVerificationCases(criterion.criterion_id, "adversarial", criterion.adversarial_cases)
];
return blocks.join("\n\n");
}
function renderVerificationCases(criterionId, label, cases) {
return (cases ?? []).map(
(entry, index) => renderTestCase(
criterionId,
`${label} case ${index + 1}: ${entry.input} => ${entry.expected_behavior}`
)
);
}
function renderTestCase(criterionId, title) {
return `it(${JSON.stringify(title)}, () => {
// @obligation ${criterionId}
throw new Error('Not implemented');
});`;
}
function indent(value, spaces) {
return value.split("\n").map((line) => `${" ".repeat(spaces)}${line}`).join("\n");
}
// src/code-knowledge/builder.ts
init_esm_shims();
import { readFile as readFile25 } from "fs/promises";
import { join as join54 } from "path";
// src/code-knowledge/dependency-usage.ts
init_esm_shims();
var TS_JS_EXTENSION_RE = /\.(?:[cm]?[jt]sx?)$/;
function packageNameFromSpecifier(specifier) {
if (specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("node:")) {
return null;
}
if (specifier.startsWith("@/")) {
return null;
}
const parts = specifier.split("/");
if (specifier.startsWith("@")) {
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null;
}
return parts[0] || null;
}
async function computeDependencyUsage(projectRoot, files, contentByFile) {
const importedPackages = /* @__PURE__ */ new Set();
for (const file of files) {
if (!TS_JS_EXTENSION_RE.test(file)) continue;
const content = contentByFile.get(file);
if (content === void 0) continue;
for (const specifier of extractImportSpecifiers(content)) {
const name = packageNameFromSpecifier(specifier);
if (name !== null) {
importedPackages.add(name);
}
}
}
const parsed = await createDefaultEcosystemParserRegistry().parseProject(projectRoot);
const dependencies = [];
const seen = /* @__PURE__ */ new Set();
for (const result2 of parsed) {
for (const pkg of result2.packages) {
if (pkg.ecosystem !== "node" || seen.has(pkg.name)) continue;
seen.add(pkg.name);
dependencies.push({
name: pkg.name,
ecosystem: pkg.ecosystem,
imported: importedPackages.has(pkg.name)
});
}
}
return dependencies.sort((a, b) => a.name.localeCompare(b.name));
}
// src/code-knowledge/entry-points.ts
init_esm_shims();
var import_fast_glob11 = __toESM(require_out(), 1);
import { readFileSync as readFileSync23 } from "fs";
import { join as join52 } from "path";
var STATIC_ENTRY_GLOBS = [
"src/cli/**",
"runtime/hooks/**",
"runtime/scripts/**",
"scripts/**",
"tests/**",
"**/*.test.{ts,tsx,js,jsx,mjs,cjs}",
"**/*.spec.{ts,tsx,js,jsx,mjs,cjs}",
"**/__tests__/**"
];
function isTestFile2(relPath) {
return /(?:^|\/)__tests__\//.test(relPath) || /(?:^|\/)tests\//.test(relPath) || /\.(?:test|spec)\.[cm]?[jt]sx?$/.test(relPath);
}
function packageEntryGlobs(projectRoot) {
const pkgPath = join52(projectRoot, "package.json");
let pkg;
try {
pkg = JSON.parse(readFileSync23(pkgPath, "utf8"));
} catch {
return [];
}
const globs = /* @__PURE__ */ new Set();
collectStringLeaves(pkg.main, globs);
collectStringLeaves(pkg.bin, globs);
collectStringLeaves(pkg.exports, globs);
return [...globs];
}
function collectStringLeaves(value, out) {
if (typeof value === "string") {
const normalized = value.replace(/^\.\//, "");
if (normalized.length > 0 && !normalized.startsWith("#")) {
out.add(normalized);
}
return;
}
if (value && typeof value === "object") {
for (const nested of Object.values(value)) {
collectStringLeaves(nested, out);
}
}
}
function resolveEntryPoints(projectRoot) {
const globs = [...STATIC_ENTRY_GLOBS, ...packageEntryGlobs(projectRoot)];
const files = new Set(
import_fast_glob11.default.sync(globs, { cwd: projectRoot, ignore: DEFAULT_IGNORE_GLOBS, onlyFiles: true })
);
return { globs, files };
}
// src/code-knowledge/import-edges.ts
init_esm_shims();
var DEFAULT_ALIASES = { "@/": "src/" };
var NAMED_BLOCK_RE = /\b(?:import|export)\s+(?:type\s+)?(?:[\w$*]+\s*,\s*)?\{([^}]*)\}\s+from\s+["'][^"']+["']/g;
function parseImportedNames(content) {
const names = /* @__PURE__ */ new Set();
NAMED_BLOCK_RE.lastIndex = 0;
let match;
while ((match = NAMED_BLOCK_RE.exec(content)) !== null) {
for (const raw of match[1].split(",")) {
const token = raw.trim().replace(/^type\s+/, "");
if (token.length === 0) continue;
const exported = token.split(/\s+as\s+/)[0].trim();
if (/^[A-Za-z_$][\w$]*$/.test(exported)) {
names.add(exported);
}
}
}
return names;
}
async function buildEdges(projectRoot, files, contentByFile, exportsByFile) {
const importEdges = await scanImports({ projectRoot, files, aliases: DEFAULT_ALIASES });
const referenceEdges = [];
const importedNamesByFile = /* @__PURE__ */ new Map();
for (const edge of importEdges) {
let imported = importedNamesByFile.get(edge.from);
if (!imported) {
imported = parseImportedNames(contentByFile.get(edge.from) ?? "");
importedNamesByFile.set(edge.from, imported);
}
const exportsOfTarget = exportsByFile.get(edge.to);
if (!exportsOfTarget) continue;
for (const name of imported) {
if (exportsOfTarget.has(name)) {
referenceEdges.push({ from: edge.from, to: edge.to, symbol: name });
}
}
}
return { importEdges, referenceEdges };
}
// src/code-knowledge/module-slugs.ts
init_esm_shims();
var import_yaml7 = __toESM(require_dist(), 1);
import { readFileSync as readFileSync24 } from "fs";
import { join as join53 } from "path";
function asStringArray(value) {
if (!Array.isArray(value)) return [];
return value.filter((entry) => typeof entry === "string");
}
function claimsForModule(module) {
const own = [...asStringArray(module.sources), ...asStringArray(module.source_paths)];
const featureSources = Array.isArray(module.features) ? module.features.flatMap(
(feature) => asStringArray(feature.sources).concat(asStringArray(feature.source_paths))
) : [];
return [...own, ...featureSources];
}
function loadModuleSlugResolver(projectRoot) {
const claims = [];
const slugOrder = [];
const mapPath = join53(projectRoot, PATHS.MODULE_MAP);
try {
const doc = (0, import_yaml7.parse)(readFileSync24(mapPath, "utf8"));
const modules = Array.isArray(doc?.modules) ? doc.modules : [];
for (const module of modules) {
if (typeof module.slug !== "string") continue;
const slug = module.slug;
let claimed = false;
for (const source of claimsForModule(module)) {
const prefix = source.replace(/\/+$/, "");
if (prefix.length > 0) {
claims.push({ slug, prefix });
claimed = true;
}
}
if (claimed) slugOrder.push(slug);
}
} catch {
}
return {
slugForFile(relPath) {
let best = null;
for (const claim of claims) {
if (relPath === claim.prefix || relPath.startsWith(`${claim.prefix}/`)) {
if (best === null || claim.prefix.length > best.prefix.length) {
best = claim;
}
}
}
return best?.slug ?? null;
},
slugs() {
return [...slugOrder];
}
};
}
// src/code-knowledge/reachability.ts
init_esm_shims();
function symbolKey(file, name) {
return `${file}\0${name}`;
}
function countCallers(edges, keyOf) {
const callers = /* @__PURE__ */ new Map();
for (const edge of edges) {
if (isTestFile2(edge.from)) continue;
const key = keyOf(edge);
let set = callers.get(key);
if (!set) {
set = /* @__PURE__ */ new Set();
callers.set(key, set);
}
set.add(edge.from);
}
return callers;
}
function computeReachability(input) {
const fileCallers = countCallers(input.importEdges, (edge) => edge.to);
const files = input.files.map((path10) => {
const callerCount = fileCallers.get(path10)?.size ?? 0;
const entryPoint = input.entryFiles.has(path10);
return {
path: path10,
caller_count: callerCount,
orphan: callerCount === 0 && !entryPoint,
entry_point: entryPoint
};
});
const symbolCallers = countCallers(
input.referenceEdges,
(edge) => symbolKey(edge.to, edge.symbol)
);
const symbolCallerCount = /* @__PURE__ */ new Map();
for (const [key, set] of symbolCallers) {
symbolCallerCount.set(key, set.size);
}
return { files, symbolCallerCount };
}
// src/code-knowledge/symbol-extractor.ts
init_esm_shims();
var TS_JS_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
function extractSymbols(relPath, content) {
const ext = extensionOf(relPath);
if (TS_JS_EXTENSIONS.has(ext)) {
return extractTsJs(content, ext === ".tsx" || ext === ".jsx");
}
if (ext === ".php") {
return extractPhp(content);
}
if (ext === ".dart") {
return extractDart(content);
}
return [];
}
function extensionOf(relPath) {
const base = relPath.slice(relPath.lastIndexOf("/") + 1);
const dot = base.lastIndexOf(".");
return dot <= 0 ? "" : base.slice(dot).toLowerCase();
}
var FN_RE = /^export\s+(?:default\s+)?(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/;
var CLASS_RE = /^export\s+(?:default\s+)?(?:abstract\s+)?class\s+([A-Za-z_$][\w$]*)/;
var TYPE_RE = /^export\s+(?:declare\s+)?(interface|type|enum)\s+([A-Za-z_$][\w$]*)/;
var VAR_RE = /^export\s+(?:declare\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)/;
var FN_VALUE_RE = /=\s*(?:async\s+)?(?:function\b|(?:<[^>]*>\s*)?\([^)]*\)\s*(?::[^=]+?)?=>|[A-Za-z_$][\w$]*\s*=>)/;
function extractTsJs(content, jsx) {
const lines = content.split(/\r?\n/);
const out = [];
for (let i = 0; i < lines.length; i += 1) {
const line = lines[i].trimStart();
const fn = FN_RE.exec(line);
if (fn) {
out.push(makeSymbol(fn[1], "function", i, signatureHead(lines, i, fn[1])));
continue;
}
const cls = CLASS_RE.exec(line);
if (cls) {
out.push(makeSymbol(cls[1], "class", i, signatureHead(lines, i, cls[1])));
continue;
}
const typ = TYPE_RE.exec(line);
if (typ) {
out.push(makeSymbol(typ[2], "type", i, `${typ[1]} ${typ[2]}`));
continue;
}
const varMatch = VAR_RE.exec(line);
if (varMatch) {
const name = varMatch[1];
const isComponent = jsx && /^[A-Z]/.test(name) && FN_VALUE_RE.test(line);
out.push(
makeSymbol(name, isComponent ? "component" : "const", i, signatureHead(lines, i, name))
);
continue;
}
}
return out;
}
function makeSymbol(name, kind, lineIndex, signature) {
return {
name,
kind,
line: lineIndex + 1,
signature,
exported: true,
extraction_tier: "regex"
};
}
function signatureHead(lines, startIndex, name) {
const joined = lines.slice(startIndex, startIndex + 6).join(" ").replace(/\s+/g, " ").trim();
const fromExport = joined.replace(/^export\s+(?:default\s+)?(?:declare\s+)?(?:abstract\s+)?/, "");
const nameAt = fromExport.indexOf(name);
const fromName = nameAt >= 0 ? fromExport.slice(nameAt) : fromExport;
let cut = fromName;
const brace = cut.indexOf("{");
if (brace >= 0) cut = cut.slice(0, brace);
const arrow = cut.indexOf("=>");
if (arrow >= 0) cut = cut.slice(0, arrow + 2);
else {
const eq = cut.indexOf("=");
if (eq >= 0) cut = cut.slice(0, eq).trim();
}
cut = cut.replace(/[;,]\s*$/, "").trim();
if (cut.length === 0) return name;
return cut.length > 200 ? name : cut;
}
var PHP_CLASS_RE = /^\s*(?:abstract\s+|final\s+)*(?:class|interface|trait)\s+([A-Za-z_]\w*)/;
var PHP_FN_RE = /^\s*(?:public\s+|private\s+|protected\s+|static\s+)*function\s+([A-Za-z_]\w*)\s*\(/;
function extractPhp(content) {
return extractByLine(content, (line, index) => {
const cls = PHP_CLASS_RE.exec(line);
if (cls) return makeFileLevel(cls[1], "class", index, `class ${cls[1]}`);
const fn = PHP_FN_RE.exec(line);
if (fn) return makeFileLevel(fn[1], "function", index, fn[1]);
return null;
});
}
var DART_CLASS_RE = /^\s*(?:abstract\s+)?class\s+([A-Za-z_]\w*)/;
var DART_FN_RE = /^\s*(?:[A-Za-z_][\w<>,.\s?]*\s+)?([A-Za-z_]\w*)\s*\([^)]*\)\s*(?:async\s*)?\{/;
var DART_CONTROL_KEYWORDS = /* @__PURE__ */ new Set(["if", "for", "while", "switch", "catch", "do"]);
function extractDart(content) {
return extractByLine(content, (line, index) => {
const cls = DART_CLASS_RE.exec(line);
if (cls) return makeFileLevel(cls[1], "class", index, `class ${cls[1]}`);
const fn = DART_FN_RE.exec(line);
if (fn && !DART_CONTROL_KEYWORDS.has(fn[1])) {
return makeFileLevel(fn[1], "function", index, fn[1]);
}
return null;
});
}
function extractByLine(content, match) {
const lines = content.split(/\r?\n/);
const out = [];
const seen = /* @__PURE__ */ new Set();
for (let i = 0; i < lines.length; i += 1) {
const symbol = match(lines[i], i);
if (symbol && !seen.has(symbol.name)) {
seen.add(symbol.name);
out.push(symbol);
}
}
return out;
}
function makeFileLevel(name, kind, lineIndex, signature) {
return { name, kind, line: lineIndex + 1, signature, exported: true, extraction_tier: "regex" };
}
// src/code-knowledge/types.ts
init_esm_shims();
var CODE_KNOWLEDGE_SCHEMA_VERSION = 1;
// src/code-knowledge/builder.ts
var SOURCE_GLOBS = ["**/*.{ts,tsx,js,jsx,mjs,cjs,php,dart}"];
async function readSourceFiles(projectRoot, files) {
const contentByFile = /* @__PURE__ */ new Map();
for (const rel of files) {
try {
contentByFile.set(rel, await readFile25(join54(projectRoot, rel), "utf8"));
} catch {
}
}
return contentByFile;
}
function extractAll(files, contentByFile) {
const rawSymbols = [];
const exportsByFile = /* @__PURE__ */ new Map();
for (const file of files) {
const content = contentByFile.get(file);
if (content === void 0) continue;
const symbols = extractSymbols(file, content);
if (symbols.length === 0) continue;
const names = /* @__PURE__ */ new Set();
for (const symbol of symbols) {
rawSymbols.push({ file, symbol });
names.add(symbol.name);
}
exportsByFile.set(file, names);
}
return { rawSymbols, exportsByFile };
}
async function buildCodeKnowledgeIndex(projectRoot, options = {}) {
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
const files = scanWorkingTree(projectRoot, SOURCE_GLOBS);
const contentByFile = await readSourceFiles(projectRoot, files);
const resolver = loadModuleSlugResolver(projectRoot);
const entryPoints = resolveEntryPoints(projectRoot);
const { rawSymbols, exportsByFile } = extractAll(files, contentByFile);
const { importEdges, referenceEdges } = await buildEdges(
projectRoot,
files,
contentByFile,
exportsByFile
);
const reach = computeReachability({
files,
importEdges,
referenceEdges,
entryFiles: entryPoints.files
});
const dependencies = await computeDependencyUsage(projectRoot, files, contentByFile);
const symbols = rawSymbols.map(({ file, symbol }) => {
const callerCount = reach.symbolCallerCount.get(symbolKey(file, symbol.name)) ?? 0;
return {
name: symbol.name,
kind: symbol.kind,
file,
line: symbol.line,
signature: symbol.signature,
exported: symbol.exported,
module_slug: resolver.slugForFile(file),
extraction_tier: symbol.extraction_tier,
caller_count: callerCount,
orphan: callerCount === 0 && !entryPoints.files.has(file)
};
});
const git2 = options.gitState ?? readGitState(projectRoot);
return {
schema_version: CODE_KNOWLEDGE_SCHEMA_VERSION,
header: {
generated_at: now(),
branch: git2.branch ?? null,
head_commit: git2.head_commit ?? null,
schema_version: CODE_KNOWLEDGE_SCHEMA_VERSION,
entry_point_globs: entryPoints.globs
},
symbols,
files: reach.files,
import_edges: importEdges,
reference_edges: referenceEdges,
dependencies
};
}
// src/onboarding/checkpoint.ts
init_esm_shims();
import { existsSync as existsSync24, mkdirSync as mkdirSync10, readFileSync as readFileSync25, renameSync as renameSync4, rmSync as rmSync8, writeFileSync as writeFileSync10 } from "fs";
import { dirname as dirname21, join as join55 } from "path";
function writeOnboardingCheckpoint(projectRoot, writtenPaths) {
const target = join55(projectRoot, PATHS.ONBOARDING_CHECKPOINT);
mkdirSync10(dirname21(target), { recursive: true });
const payload = {
schema_version: 1,
written: dedupePreservingOrder(writtenPaths.map(toPosixPath))
};
const tmp = `${target}.tmp`;
writeFileSync10(tmp, `${JSON.stringify(payload, null, 2)}
`, "utf8");
renameSync4(tmp, target);
}
function readOnboardingCheckpoint(projectRoot) {
const target = join55(projectRoot, PATHS.ONBOARDING_CHECKPOINT);
if (!existsSync24(target)) {
return null;
}
try {
const parsed = JSON.parse(readFileSync25(target, "utf8"));
if (!Array.isArray(parsed.written)) {
return null;
}
return parsed.written.filter((entry) => typeof entry === "string");
} catch {
return null;
}
}
function deleteOnboardingCheckpoint(projectRoot) {
rmSync8(join55(projectRoot, PATHS.ONBOARDING_CHECKPOINT), { force: true });
}
function dedupePreservingOrder(paths) {
const seen = /* @__PURE__ */ new Set();
const result2 = [];
for (const path10 of paths) {
if (!seen.has(path10)) {
seen.add(path10);
result2.push(path10);
}
}
return result2;
}
// src/onboarding/entry-stub-writer.ts
init_esm_shims();
import { mkdirSync as mkdirSync11, readFileSync as readFileSync26, writeFileSync as writeFileSync11 } from "fs";
import { dirname as dirname22, join as join56 } from "path";
var MANAGED_BEGIN = "<!-- >>> paqad-ai managed entry stub (do not edit between markers) >>> -->";
var MANAGED_END = "<!-- <<< paqad-ai managed entry stub <<< -->";
function wireEntryStubs(projectRoot, stubs) {
const wired = [];
for (const stub of stubs) {
const target = join56(projectRoot, stub.path);
const existing = readTextOrEmpty(target);
if (existing === "" || !existing.includes(MANAGED_BEGIN) && existing.includes(PATHS.FRAMEWORK_PATH)) {
continue;
}
const next = reconcileManagedBlock(existing, stub.content);
if (next !== existing) {
mkdirSync11(dirname22(target), { recursive: true });
writeFileSync11(target, next);
}
wired.push(toPosixPath(stub.path));
}
if (wired.length > 0) {
appendPlanningAudit(projectRoot, "INFO", "onboarding.entry-stub-wired", {
paths: wired.join(","),
count: wired.length
});
}
return { wired };
}
function reconcileManagedBlock(existing, stubBody) {
const block = `${MANAGED_BEGIN}
${stubBody.replace(/\n+$/, "")}
${MANAGED_END}`;
const replaced = replaceMarkerBlock(existing, MANAGED_BEGIN, MANAGED_END, block);
if (replaced !== null) {
return ensureTrailingNewline(replaced);
}
const trimmed = existing.replace(/\s+$/, "");
const prefix = trimmed.length > 0 ? `${trimmed}
` : "";
return `${prefix}${block}
`;
}
function ensureTrailingNewline(value) {
return value.endsWith("\n") ? value : `${value}
`;
}
function readTextOrEmpty(path10) {
try {
return readFileSync26(path10, "utf8");
} catch (error) {
if (error.code === "ENOENT") {
return "";
}
throw error;
}
}
// src/onboarding/obsolete-cleanup.ts
init_esm_shims();
import { readdirSync as readdirSync7, readFileSync as readFileSync27, rmSync as rmSync9, writeFileSync as writeFileSync12 } from "fs";
import { join as join57 } from "path";
var OBSOLETE_MANAGED_DOCS = [
PATHS.DECISION_PAUSE_CONTRACT,
PATHS.NARRATION_CONTRACT
];
var OBSOLETE_WORKFLOW_RULES = [
{
path: "security/pentest.md",
skill: "pentest",
job: "pentests",
shippedHashes: ["759462f321c63e9c4794b05d6b06a6075c5b10b7ff0aec56d1fca33f57fa19d5"]
},
{
path: "coding/site-map.md",
skill: "site-map",
job: "site maps",
shippedHashes: [
"0173ed5a2557273021a8979160bea306e2f85207fabf703f3e2c0b5e5c2d5e6a",
"3493199c3e1c50daf2f1e7cde8325fc5ce41ece20d2ea6912747c8c3d66ea2cf",
"5013379c70fe6adb2f29f3bf42c2dfc422884a1ceeaef4920587b619725c915a",
"b5897cf9d1553889b1c449039033df110ad33b8f9469ad1bec299efdd15307a3",
"e0a2e6aa8242959ea28a6507a4483dc9f81642b04059854d2ecb3ff954910d83"
]
},
{
path: "coding/site-map-retest.md",
skill: "site-map",
job: "site map retests",
shippedHashes: [
"ae0c8186b66f077fc3fa4535dacc44b32fd82c31275b402ec6a5f206280c0f0c",
"e1c0f0205f598b58a44b48dc88a76d36ce10358e59d77808ced00e282c9c061e"
]
},
{
path: "coding/design-test.md",
skill: "design-test",
job: "design tests",
shippedHashes: [
"8eb387c8cdbc1e6524ed9d66d485f2b069914ee18bed39c662f73ee2109e9921",
"edc8a1f43a04da6aa7f22abf61b021d97a9edd0e7acdcad11b6ed46c66d5f809"
]
},
{
path: "coding/design-retest.md",
skill: "design-test",
job: "design retests",
shippedHashes: ["622161f0a9ab7f398b469797c4f26b9ed348b1fdd4e1f62c329de3a6f60f9529"]
},
{
path: "coding/codebase-health.md",
skill: "codebase-health",
job: "codebase health checks",
shippedHashes: ["6bf818da926f07c4de1f967792dce6faa1523305d2080a68b88b04af3adb201d"]
},
{
path: "coding/health-retest.md",
skill: "codebase-health",
job: "health retests",
shippedHashes: ["b73e6d84df7bbb488433ba5011938925b83ba4d63c5a74688d81f98644c7527f"]
}
];
function normalizedRuleHash(content) {
const lines = content.replace(/\r\n/g, "\n").split("\n");
return sha256(lines.map((line) => stripRuleMarker(line).text).join("\n"));
}
function removeObsoleteContractDocs(projectRoot) {
const removed = [];
for (const relativePath of OBSOLETE_MANAGED_DOCS) {
const path10 = join57(projectRoot, relativePath);
let content;
try {
content = readFileSync27(path10, "utf8");
} catch {
continue;
}
if (!content.startsWith(MANAGED_HEADER)) {
continue;
}
rmSync9(path10, { force: true });
removed.push(relativePath);
}
return removed;
}
function cleanObsoleteWorkflowRule(projectRoot, rule) {
const shown = `${PATHS.RULES_DIR}/${rule.path}`;
const path10 = join57(projectRoot, PATHS.RULES_DIR, rule.path);
try {
if (!rule.shippedHashes.includes(normalizedRuleHash(readFileSync27(path10, "utf8")))) {
return {
line: `Kept ${shown} because it was edited. paqad now runs ${rule.job} from its own skill, so you can delete this file.`,
removed: null
};
}
rmSync9(path10);
} catch (error) {
const code = error.code;
if (code === "ENOENT") return { line: null, removed: null };
return {
line: `Couldn't remove ${shown} (${code ?? "unknown error"}); the next update tries again. paqad now runs ${rule.job} from its own skill.`,
removed: null
};
}
return {
line: `Removed ${shown}; paqad now runs ${rule.job} from its own ${rule.skill} skill.`,
removed: shown
};
}
function cleanObsoleteWorkflowRules(projectRoot) {
const outcomes = OBSOLETE_WORKFLOW_RULES.map(
(rule) => cleanObsoleteWorkflowRule(projectRoot, rule)
);
return {
lines: outcomes.flatMap((outcome) => outcome.line === null ? [] : [outcome.line]),
removed: outcomes.flatMap((outcome) => outcome.removed === null ? [] : [outcome.removed])
};
}
function removeObsoleteWorkflowRules(projectRoot) {
return cleanObsoleteWorkflowRules(projectRoot).lines;
}
var KEPT_RULE_WITH_SHIPPED_LINES = `${PATHS.RULES_DIR}/coding/feature-development.md`;
var FENCE = /^\s*(```|~~~)/u;
var BULLET = /^\s*[-*]\s+/u;
var LINE_END = /(\r?\n|\r)$/u;
var BOM_BYTES = "\xEF\xBB\xBF";
function rawLines(raw) {
return raw.split(/(?<=\n)/u);
}
function decode(rawText) {
return Buffer.from(rawText, "latin1").toString("utf8");
}
function encode(text2) {
return Buffer.from(text2, "utf8").toString("latin1");
}
function splitRawLine(rawLine) {
const bom = rawLine.startsWith(BOM_BYTES) ? BOM_BYTES : "";
const rest = rawLine.slice(bom.length);
const end = LINE_END.exec(rest)?.[0] ?? "";
return { bom, body: rest.slice(0, rest.length - end.length), end };
}
function currentShippedLine(shippedContent, start) {
if (shippedContent === null) return null;
const matches = shippedContent.split(/\r?\n/u).map((line) => stripRuleMarker(line).text).filter((line) => line.startsWith(start));
return matches.length === 1 ? matches[0] : null;
}
function bodyOfRule(text2) {
return text2.replace(BULLET, "");
}
function repairKeptRuleFile(projectRoot, shippedContent) {
const path10 = join57(projectRoot, KEPT_RULE_WITH_SHIPPED_LINES);
let bytes;
try {
bytes = readFileSync27(path10);
} catch {
return { repaired: false, texts: [], problem: null };
}
const texts = [];
let inFence = false;
let repaired = false;
const output = rawLines(bytes.toString("latin1")).map((rawLine) => {
const { bom, body, end } = splitRawLine(rawLine);
const line = decode(body);
if (FENCE.test(line)) {
inFence = !inFence;
return rawLine;
}
if (inFence) return rawLine;
const start = shippedRuleLineStart(line);
if (start === null) return rawLine;
const next = currentShippedLine(shippedContent, start);
if (next === null) return rawLine;
const id = parseRuleMarker(line);
repaired = true;
if (id !== null) texts.push({ id, text: bodyOfRule(next) });
return `${bom}${encode(id === null ? next : embedRuleMarker(next, id))}${end}`;
});
if (!repaired) return { repaired: false, texts: [], problem: null };
try {
writeFileSync12(path10, Buffer.from(output.join(""), "latin1"));
} catch (error) {
const reason2 = error instanceof Error ? error.message : "unknown error";
return {
repaired: false,
texts: [],
problem: `Couldn't repair ${KEPT_RULE_WITH_SHIPPED_LINES}: ${reason2}. The next update tries again.`
};
}
return { repaired: true, texts, problem: null };
}
function filesInRulesFolder(projectRoot, relativeDir) {
let entries;
try {
entries = readdirSync7(join57(projectRoot, relativeDir), { withFileTypes: true });
} catch {
return [];
}
return entries.flatMap((entry) => {
const path10 = `${relativeDir}/${entry.name}`;
return entry.isDirectory() ? filesInRulesFolder(projectRoot, path10) : [path10];
}).filter((path10) => path10 !== PATHS.RULE_SCRIPT_MAP).sort();
}
function stillMentionsLines(projectRoot, deletedPaths) {
return filesInRulesFolder(projectRoot, PATHS.RULES_DIR).flatMap((file) => {
let content;
try {
content = readFileSync27(join57(projectRoot, file), "utf8");
} catch {
return [];
}
return deletedPaths.filter((deleted) => content.includes(deleted)).map(
(deleted) => `${file} still mentions ${deleted}, which paqad removed. Update that line by hand.`
);
});
}
function repairKeptRuleLines(projectRoot, shippedContent, deletedPaths) {
const repair = repairKeptRuleFile(projectRoot, shippedContent);
return {
lines: [
...repair.problem === null ? [] : [repair.problem],
...stillMentionsLines(projectRoot, deletedPaths)
],
repaired: repair.repaired ? [KEPT_RULE_WITH_SHIPPED_LINES] : [],
texts: repair.texts
};
}
// src/stage-isolation/recipe-install.ts
init_esm_shims();
import { cpSync as cpSync2, mkdirSync as mkdirSync12, readFileSync as readFileSync28, renameSync as renameSync5, rmSync as rmSync10, writeFileSync as writeFileSync13 } from "fs";
import { join as join58 } from "path";
var CODEX_ADAPTER = "codex-cli";
var IGNORE_BEGIN = "# paqad recipes: generated on each machine, kept out of git";
var IGNORE_END = "# end paqad recipes";
function recipeIgnoreBlock() {
return [IGNORE_BEGIN, ...RECIPE_NAMES.map((name) => `/${name}/`), IGNORE_END, ""].join("\n");
}
function readIgnoreFile(path10) {
try {
return readFileSync28(path10, "utf8");
} catch (error) {
if (error.code === "ENOENT") return "";
throw error;
}
}
function writeRecipeIgnore(skillsRoot) {
const path10 = join58(skillsRoot, ".gitignore");
const current = readIgnoreFile(path10);
const start = current.indexOf(IGNORE_BEGIN);
const end = current.indexOf(IGNORE_END);
const kept = start === -1 || end === -1 ? current : `${current.slice(0, start)}${current.slice(end + IGNORE_END.length + 1)}`;
writeFileSync13(
path10,
`${kept}${kept === "" || kept.endsWith("\n") ? "" : "\n"}${recipeIgnoreBlock()}`
);
}
function stagedCopy(source, staged) {
rmSync10(staged, { recursive: true, force: true });
try {
cpSync2(source, staged, { recursive: true });
return true;
} catch (error) {
if (error.code === "ENOENT") return false;
throw error;
}
}
function replaceRecipe(source, skillsRoot, name) {
const target = join58(skillsRoot, name);
const staged = join58(skillsRoot, `.${name}.staged`);
try {
if (!stagedCopy(source, staged)) return false;
rmSync10(target, { recursive: true, force: true });
renameSync5(staged, target);
return true;
} finally {
rmSync10(staged, { recursive: true, force: true });
}
}
function writeCodexRecipes(projectRoot, source = recipeRoot()) {
if (!enabledAdapters(projectRoot).includes(CODEX_ADAPTER)) return [];
if (source === null) return [];
const skillsRoot = join58(projectRoot, OPEN_STANDARD_SKILLS_ROOT);
mkdirSync12(skillsRoot, { recursive: true });
const written = [];
for (const name of RECIPE_NAMES) {
if (!replaceRecipe(join58(source, name), skillsRoot, name)) continue;
written.push(`${OPEN_STANDARD_SKILLS_ROOT}/${name}`);
}
writeRecipeIgnore(skillsRoot);
return written;
}
// src/onboarding/gitignore-writer.ts
init_esm_shims();
import { execFileSync as execFileSync6 } from "child_process";
import { mkdirSync as mkdirSync13, readFileSync as readFileSync29, unlinkSync, writeFileSync as writeFileSync14 } from "fs";
import { dirname as dirname23, isAbsolute as isAbsolute2, join as join59 } from "path";
var MANAGED_BEGIN2 = "# >>> paqad-ai managed (do not edit between markers) >>>";
var MANAGED_END2 = "# <<< paqad-ai managed <<<";
var GITATTRIBUTES_BEGIN = "# >>> paqad-ai managed >>>";
var GITATTRIBUTES_END = "# <<< paqad-ai managed <<<";
var LEGACY_MARKER = "# paqad-ai";
var MANAGED_BLOCK_VERSION = 2;
var MANAGED_BLOCK_VERSION_LINE = /^# managed_block_version:[ \t]*(\S+)[ \t]*\r?$/mu;
var MANAGED_GITIGNORE_ENTRIES = [
`# managed_block_version: ${MANAGED_BLOCK_VERSION}`,
".agent-entry-loaded",
".agent-entry-loaded.d/",
"framework-version.txt",
"cache/",
"session/",
"locks/",
"context/",
"vectors/",
"secrets.env",
"workflows/",
"indexes/",
"pentest/",
"theme/",
"scripts/rules/.cache/",
"scripts/rules/.history/",
"onboarding-checkpoint.json",
".config",
"# per-machine runtime state (regenerated locally)",
"logs/",
"state/last-update.json",
"state/last-update.seen.json",
"audit.log",
"decisions/audit.jsonl",
"decisions/events.jsonl",
"detection-report.json",
"stack-snapshot.json",
"stack-drift.json",
"rules-discovery-nudge.json",
"doc-progress.json",
"quality-baseline.json",
"compiled-rules.json",
"module-health/",
"module-health-evidence/",
"module-health-consumed-events.json",
"patterns/",
"crs/",
"attachments/",
"attachment-events.jsonl",
"traceability/",
"module-map/drift.json",
"module-map/events.jsonl",
"schema-migrations.jsonl",
"# .paqad/skills/ only: .paqad/authoring/skills/ and .paqad/authoring/agents/ hold tracked skill and agent evidence",
"/skills/",
"delivery-detection.json",
"checks/",
"# compliance ledger (share via dashboard/SIEM, not git)",
"ledger/",
"compliance/",
"tmp/"
];
var MANAGED_GITATTRIBUTES_ENTRIES = ["decisions/index.json merge=union"];
var DEPRECATED_ARTIFACTS = [
".paqad/version",
".paqad/classifier-config.json",
".paqad/next-steps.md",
".paqad/hooks/silent-update.sh"
];
function ignoredPathsFromRoot(entries = MANAGED_GITIGNORE_ENTRIES) {
return entries.filter((entry) => !entry.startsWith("#")).map((entry) => `.paqad/${entry.replace(/^\//u, "")}`);
}
function managedBlockIsNewer(projectRoot) {
const found = MANAGED_BLOCK_VERSION_LINE.exec(
readTextOrEmpty2(join59(projectRoot, ".paqad", ".gitignore"))
)?.[1];
return isHigherStamp(found, MANAGED_BLOCK_VERSION);
}
function managedGitignoreEntries(projectRoot) {
return [...MANAGED_GITIGNORE_ENTRIES, ...legacyEvidenceIgnoreEntries(projectRoot)];
}
function writeManagedGitignoreBlock(projectRoot, entries = managedGitignoreEntries(projectRoot)) {
reconcileFile(join59(projectRoot, ".paqad", ".gitignore"), MANAGED_BEGIN2, MANAGED_END2, entries);
reconcileFile(
join59(projectRoot, ".paqad", ".gitattributes"),
GITATTRIBUTES_BEGIN,
GITATTRIBUTES_END,
MANAGED_GITATTRIBUTES_ENTRIES
);
}
function writeGitignore(projectRoot) {
const entries = managedGitignoreEntries(projectRoot);
writeManagedGitignoreBlock(projectRoot, entries);
scrubRootFile(join59(projectRoot, ".gitignore"), MANAGED_BEGIN2, MANAGED_END2, true);
scrubRootFile(join59(projectRoot, ".gitattributes"), GITATTRIBUTES_BEGIN, GITATTRIBUTES_END, false);
untrackNowIgnoredPaths(projectRoot, ignoredPathsFromRoot(entries));
removeDeprecatedArtifacts(projectRoot, DEPRECATED_ARTIFACTS);
}
function removeDeprecatedArtifacts(projectRoot, paths) {
if (isGitRepository(projectRoot)) {
const tracked = listTrackedPaths(projectRoot, paths);
if (tracked.length > 0) {
try {
execFileSync6("git", ["rm", "-r", "--cached", "--ignore-unmatch", ...tracked], {
cwd: projectRoot,
stdio: "ignore"
});
} catch {
}
}
}
const removed = paths.filter((path10) => unlinkIfPresent(join59(projectRoot, path10)));
if (removed.length > 0) {
appendPlanningAudit(projectRoot, "INFO", "gitignore.removed-deprecated-artifacts", {
paths: removed.join(","),
count: removed.length
});
}
}
function unlinkIfPresent(path10) {
try {
unlinkSync(path10);
return true;
} catch {
return false;
}
}
function reconcileFile(path10, begin, end, entries) {
const existing = readTextOrEmpty2(path10);
const next = reconcileManagedBlock2(existing, begin, end, entries);
if (next !== existing) {
mkdirSync13(dirname23(path10), { recursive: true });
writeFileSync14(path10, next);
}
}
function reconcileManagedBlock2(existing, begin, end, entries) {
const block = [begin, ...entries, end].join("\n");
const replaced = replaceMarkerBlock(existing, begin, end, block);
if (replaced !== null) {
return ensureTrailingNewline2(replaced);
}
const trimmed = existing.replace(/\s+$/, "");
const prefix = trimmed.length > 0 ? `${trimmed}
` : "";
return `${prefix}${block}
`;
}
function scrubRootFile(path10, begin, end, scrubLegacy) {
const existing = readTextOrEmpty2(path10);
if (existing === "") {
return;
}
let next = removeManagedBlock(existing, begin, end);
if (scrubLegacy && next.includes(LEGACY_MARKER)) {
next = stripLegacyBlock(next);
}
if (next !== existing) {
writeFileSync14(path10, next);
}
}
function removeManagedBlock(existing, begin, end) {
const beginIdx = existing.indexOf(begin);
const endIdx = existing.indexOf(end);
if (beginIdx === -1 || endIdx <= beginIdx) {
return existing;
}
const before = existing.slice(0, beginIdx).replace(/\n+$/, "");
const after = existing.slice(endIdx + end.length).replace(/^\n+/, "");
if (before === "" && after === "") {
return "";
}
if (before === "") {
return ensureTrailingNewline2(after);
}
if (after === "") {
return ensureTrailingNewline2(before);
}
return ensureTrailingNewline2(`${before}
${after}`);
}
function stripLegacyBlock(existing) {
const managedPaths = /* @__PURE__ */ new Set([...ignoredPathsFromRoot(), ".paqad/framework-path.txt"]);
return existing.split("\n").filter((line) => {
const trimmed = line.trim();
return trimmed !== LEGACY_MARKER && !managedPaths.has(trimmed);
}).join("\n");
}
function ensureTrailingNewline2(value) {
return value.endsWith("\n") ? value : `${value}
`;
}
function readTextOrEmpty2(path10) {
try {
return readFileSync29(path10, "utf8");
} catch (error) {
if (error.code === "ENOENT") {
return "";
}
throw error;
}
}
function untrackNowIgnoredPaths(projectRoot, paths) {
if (!isGitRepository(projectRoot)) {
return;
}
const tracked = listTrackedPaths(projectRoot, paths);
if (tracked.length === 0) {
return;
}
try {
execFileSync6("git", ["rm", "-r", "--cached", "--ignore-unmatch", ...tracked], {
cwd: projectRoot,
stdio: "ignore"
});
} catch {
return;
}
appendPlanningAudit(projectRoot, "INFO", "gitignore.untracked-now-ignored", {
paths: tracked.join(","),
count: tracked.length
});
}
function isGitRepository(projectRoot) {
try {
const out = execFileSync6("git", ["rev-parse", "--is-inside-work-tree"], {
cwd: projectRoot,
stdio: ["ignore", "pipe", "ignore"]
});
return out.toString().trim() === "true";
} catch {
return false;
}
}
function listTrackedPaths(projectRoot, paths) {
if (paths.length === 0) {
return [];
}
const normalized = paths.map((path10) => path10.replace(/\/$/, ""));
let listed;
try {
const out = execFileSync6("git", ["ls-files", "-z", "--", ...normalized], {
cwd: projectRoot,
stdio: ["ignore", "pipe", "ignore"]
});
listed = new Set(out.toString("utf8").split("\0").filter(Boolean));
} catch {
return [];
}
if (listed.size === 0) {
return [];
}
const trackedEntries = [...listed];
return normalized.filter(
(path10) => trackedEntries.some((entry) => entry === path10 || entry.startsWith(`${path10}/`))
);
}
var LOCAL_EXCLUDE_MARKER = "# paqad-ai: generated on each machine";
function localExcludePath(projectRoot) {
let excludePath;
try {
excludePath = execFileSync6("git", ["rev-parse", "--git-path", "info/exclude"], {
cwd: projectRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"]
}).trim();
} catch {
return null;
}
return isAbsolute2(excludePath) ? excludePath : join59(projectRoot, excludePath);
}
function excludeLine(relativePath) {
return `/${relativePath.replace(/^\//u, "")}`;
}
function unexcludeLocally(projectRoot, relativePath) {
const path10 = localExcludePath(projectRoot);
if (path10 === null) return false;
const text2 = readTextIfExistsSync(path10);
if (text2 === null) return false;
const line = excludeLine(relativePath);
const lines = text2.split("\n");
const kept = [];
let removed = false;
for (const entry of lines) {
if (entry.replace(/\r$/u, "") !== line) {
kept.push(entry);
continue;
}
removed = true;
if (kept.at(-1)?.replace(/\r$/u, "") === LOCAL_EXCLUDE_MARKER) kept.pop();
}
if (!removed) return false;
writeFileSync14(path10, kept.join("\n"), "utf8");
return true;
}
// src/onboarding/worktree-include-writer.ts
init_esm_shims();
import { readFileSync as readFileSync30, writeFileSync as writeFileSync15 } from "fs";
import { join as join60 } from "path";
var WORKTREE_INCLUDE_FILE = ".worktreeinclude";
var WORKTREE_INCLUDE_LINE = ".paqad/.config";
function mergeWorktreeInclude(existing, line) {
const present = existing.split(/\r?\n/).some((entry) => entry.trim() === line);
if (present) {
return existing;
}
const trimmed = existing.replace(/\s+$/, "");
const prefix = trimmed.length > 0 ? `${trimmed}
` : "";
return `${prefix}${line}
`;
}
function writeWorktreeInclude(projectRoot) {
const path10 = join60(projectRoot, WORKTREE_INCLUDE_FILE);
let existing;
try {
existing = readFileSync30(path10, "utf8");
} catch (error) {
if (error.code === "ENOENT") {
existing = "";
} else {
throw error;
}
}
const next = mergeWorktreeInclude(existing, WORKTREE_INCLUDE_LINE);
if (next !== existing) {
writeFileSync15(path10, next);
}
}
// src/onboarding/decision-id-migration.ts
init_esm_shims();
import { readFileSync as readFileSync31, readdirSync as readdirSync8, unlinkSync as unlinkSync2, writeFileSync as writeFileSync16 } from "fs";
import { join as join61 } from "path";
var LEGACY_PACKET_FILE = /^D-\d+\.json$/u;
function migrateLegacyDecisionIds(projectRoot, mint = mintDecisionId) {
const migrations = [];
const idRemap = /* @__PURE__ */ new Map();
for (const relativeDir of [PATHS.DECISIONS_PENDING_DIR, PATHS.DECISIONS_RESOLVED_DIR]) {
const absoluteDir = join61(projectRoot, relativeDir);
let files;
try {
files = readdirSync8(absoluteDir);
} catch {
continue;
}
for (const file of files.filter((name) => LEGACY_PACKET_FILE.test(name))) {
const oldId = file.replace(/\.json$/u, "");
if (isStrictDecisionId(oldId)) {
continue;
}
const newId = mint();
const oldPath = join61(absoluteDir, file);
const newPath = join61(absoluteDir, `${newId}.json`);
try {
const rewritten = rewritePacketId(readFileSync31(oldPath, "utf8"), oldId, newId);
writeFileSync16(newPath, rewritten);
unlinkSync2(oldPath);
idRemap.set(oldId, newId);
migrations.push({ from: oldId, to: newId, dir: relativeDir });
} catch {
}
}
}
if (idRemap.size > 0) {
remapIndex(projectRoot, idRemap);
}
return migrations;
}
function rewritePacketId(raw, oldId, newId) {
const packet = JSON.parse(raw);
if (packet.id === oldId) {
packet.id = newId;
}
if (packet.decision_id === oldId) {
packet.decision_id = newId;
}
return `${JSON.stringify(packet, null, 2)}
`;
}
function remapIndex(projectRoot, idRemap) {
const indexPath = join61(projectRoot, PATHS.DECISIONS_INDEX);
try {
const index = JSON.parse(readFileSync31(indexPath, "utf8"));
let changed = false;
if (index.fingerprints) {
for (const [fingerprint, decisionId] of Object.entries(index.fingerprints)) {
const remapped = idRemap.get(decisionId);
if (remapped) {
index.fingerprints[fingerprint] = remapped;
changed = true;
}
}
}
if (index.decisions) {
for (const [oldId, value] of Object.entries(index.decisions)) {
const remapped = idRemap.get(oldId);
if (remapped) {
delete index.decisions[oldId];
index.decisions[remapped] = value;
changed = true;
}
}
}
if (changed) {
writeFileSync16(indexPath, `${JSON.stringify(index, null, 2)}
`);
}
} catch {
}
}
// src/git-workflow/sync.ts
init_esm_shims();
var import_yaml8 = __toESM(require_dist(), 1);
import { mkdirSync as mkdirSync14, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
function syncGitWorkflowFile(text2) {
const doc = import_yaml8.default.parseDocument(text2);
if (doc.errors.length > 0 || !import_yaml8.default.isMap(doc.contents)) return text2;
return swapTeamFileStamp(text2);
}
function createFile(path10, text2) {
try {
writeFileSync17(path10, text2, { encoding: "utf8", flag: "wx" });
return true;
} catch (error) {
if (error.code === "EEXIST") return false;
throw error;
}
}
function syncGitWorkflow(projectRoot, options = {}) {
const version = options.version ?? "1.128.1";
const created = [];
const swapped = [];
const outside = changedOutside(projectRoot);
let baseBranch = options.baseBranch;
mkdirSync14(gitWorkflowDir(projectRoot), { recursive: true });
for (const file of GIT_WORKFLOW_FILES) {
const path10 = gitWorkflowFilePath(projectRoot, file);
let text2 = readTextIfExistsSync(path10);
const mayCreate = options.createMissing !== false || options.alwaysCreate?.includes(file);
if (text2 === null && !mayCreate) continue;
if (text2 === null) {
baseBranch ??= remoteDefaultBranch(projectRoot);
if (createFile(path10, renderDefaultGitWorkflowFile(file, { baseBranch }))) {
created.push(file);
continue;
}
text2 = readFileSync32(path10, "utf8");
}
if (isNewerTeamFile(text2)) {
options.notes?.push(newerTeamFileLine(`${PATHS.GIT_WORKFLOW_DIR}/${file}`));
continue;
}
const next = syncGitWorkflowFile(text2);
if (next === text2) continue;
try {
writeFileSync17(path10, next, "utf8");
swapped.push(file);
} catch (error) {
options.notes?.push(
`Couldn't write ${PATHS.GIT_WORKFLOW_DIR}/${file}: ${error instanceof Error ? error.message : "unknown error"}. The next update tries again.`
);
}
}
if (created.length > 0) stampLastApplied(projectRoot, created, { version, now: options.now });
refreshLastAppliedHashes(
projectRoot,
swapped.filter((file) => !outside.includes(file))
);
return [...created, ...swapped].map((file) => gitWorkflowFilePath(projectRoot, file));
}
// src/onboarding/prompts.ts
init_esm_shims();
// node_modules/.pnpm/@inquirer+prompts@8.7.5_@types+node@26.6.6/node_modules/@inquirer/prompts/dist/index.js
init_esm_shims();
// node_modules/.pnpm/@inquirer+checkbox@5.2.8_@types+node@26.6.6/node_modules/@inquirer/checkbox/dist/index.js
init_esm_shims();
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/index.js
init_esm_shims();
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/key.js
init_esm_shims();
var keybindings = ["emacs", "vim"];
var keybindingLookup = new Set(keybindings);
function isKeybinding(value) {
return keybindingLookup.has(value);
}
function getDefaultKeybindings() {
const env2 = process.env["INQUIRER_KEYBINDINGS"];
if (!env2)
return [];
return Array.from(new Set(env2.toLowerCase().split(/[\s,]+/).filter(isKeybinding)));
}
var isUpKey = (key, keybindings2 = []) => (
// The up key
key.name === "up" || // Vim keybinding: hjkl keys map to left/down/up/right
keybindings2.includes("vim") && key.name === "k" || // Emacs keybinding: Ctrl+P means "previous" in Emacs navigation conventions
keybindings2.includes("emacs") && key.ctrl && key.name === "p"
);
var isDownKey = (key, keybindings2 = []) => (
// The down key
key.name === "down" || // Vim keybinding: hjkl keys map to left/down/up/right
keybindings2.includes("vim") && key.name === "j" || // Emacs keybinding: Ctrl+N means "next" in Emacs navigation conventions
keybindings2.includes("emacs") && key.ctrl && key.name === "n"
);
var isSpaceKey = (key) => key.name === "space";
var isBackspaceKey = (key) => key.name === "backspace";
var isTabKey = (key) => key.name === "tab";
var isNumberKey = (key) => "1234567890".includes(key.name);
var isEnterKey = (key) => key.name === "enter" || key.name === "return";
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/errors.js
init_esm_shims();
var AbortPromptError = class extends Error {
name = "AbortPromptError";
message = "Prompt was aborted";
constructor(options) {
super();
this.cause = options?.cause;
}
};
var CancelPromptError = class extends Error {
name = "CancelPromptError";
message = "Prompt was canceled";
};
var ExitPromptError = class extends Error {
name = "ExitPromptError";
};
var HookError = class extends Error {
name = "HookError";
};
var ValidationError2 = class extends Error {
name = "ValidationError";
};
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/use-prefix.js
init_esm_shims();
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/use-state.js
init_esm_shims();
import { AsyncResource as AsyncResource2 } from "async_hooks";
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/hook-engine.js
init_esm_shims();
import { AsyncLocalStorage, AsyncResource } from "async_hooks";
var hookStorage = new AsyncLocalStorage();
function createStore(rl) {
const store = {
rl,
hooks: [],
hooksCleanup: [],
hooksEffect: [],
index: 0,
handleChange() {
}
};
return store;
}
function withHooks(rl, cb) {
const store = createStore(rl);
function cycle(render2) {
store.handleChange = () => {
store.index = 0;
render2();
};
store.handleChange();
}
return hookStorage.run(store, () => cb(cycle));
}
function getStore() {
const store = hookStorage.getStore();
if (!store) {
throw new HookError("[Inquirer] Hook functions can only be called from within a prompt");
}
return store;
}
function readline() {
return getStore().rl;
}
function withUpdates(fn) {
const wrapped = (...args) => {
const store = getStore();
let shouldUpdate = false;
const oldHandleChange = store.handleChange;
store.handleChange = () => {
shouldUpdate = true;
};
const returnValue = fn(...args);
if (shouldUpdate) {
oldHandleChange();
}
store.handleChange = oldHandleChange;
return returnValue;
};
return AsyncResource.bind(wrapped);
}
function withPointer(cb) {
const store = getStore();
const { index } = store;
const pointer = {
get() {
return store.hooks[index];
},
set(value) {
store.hooks[index] = value;
},
initialized: index in store.hooks
};
const returnValue = cb(pointer);
store.index++;
return returnValue;
}
function handleChange() {
getStore().handleChange();
}
var effectScheduler = {
queue(cb) {
const store = getStore();
const { index } = store;
store.hooksEffect.push(() => {
store.hooksCleanup[index]?.();
const cleanFn = cb(readline());
if (cleanFn != null && typeof cleanFn !== "function") {
throw new ValidationError2("useEffect return value must be a cleanup function or nothing.");
}
store.hooksCleanup[index] = cleanFn;
});
},
run() {
const store = getStore();
withUpdates(() => {
store.hooksEffect.forEach((effect) => {
effect();
});
store.hooksEffect.length = 0;
})();
},
clearAll() {
const store = getStore();
store.hooksCleanup.forEach((cleanFn) => {
cleanFn?.();
});
store.hooksEffect.length = 0;
store.hooksCleanup.length = 0;
}
};
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/use-state.js
function isFactory(value) {
return typeof value === "function";
}
function isReducer(value) {
return typeof value === "function";
}
function useState(defaultValue) {
return withPointer((pointer) => {
const setState = AsyncResource2.bind(function setState2(newValue) {
const currentValue = pointer.get();
const nextValue = isReducer(newValue) ? newValue(currentValue) : newValue;
if (!Object.is(currentValue, nextValue)) {
pointer.set(nextValue);
handleChange();
}
});
if (pointer.initialized) {
return [pointer.get(), setState];
}
const value = isFactory(defaultValue) ? defaultValue() : defaultValue;
pointer.set(value);
return [value, setState];
});
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/use-effect.js
init_esm_shims();
function useEffect(cb, depArray) {
withPointer((pointer) => {
const oldDeps = pointer.get();
const hasChanged = !Array.isArray(oldDeps) || depArray.some((dep, i) => !Object.is(dep, oldDeps[i]));
if (hasChanged) {
effectScheduler.queue(cb);
}
pointer.set(depArray);
});
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/make-theme.js
init_esm_shims();
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/theme.js
init_esm_shims();
import { styleText } from "util";
// node_modules/.pnpm/@inquirer+figures@2.0.10/node_modules/@inquirer/figures/dist/index.js
init_esm_shims();
import process3 from "process";
function isUnicodeSupported() {
if (!process3.platform.startsWith("win")) {
return process3.env["TERM"] !== "linux";
}
return Boolean(process3.env["CI"]) || // CI environments generally support unicode
Boolean(process3.env["WT_SESSION"]) || // Windows Terminal
Boolean(process3.env["TERMINUS_SUBLIME"]) || // Terminus (<0.2.27)
process3.env["ConEmuTask"] === "{cmd::Cmder}" || // ConEmu and cmder
process3.env["TERM_PROGRAM"] === "Terminus-Sublime" || process3.env["TERM_PROGRAM"] === "vscode" || process3.env["TERM"] === "xterm-256color" || process3.env["TERM"] === "alacritty" || process3.env["TERMINAL_EMULATOR"] === "JetBrains-JediTerm";
}
var common = {
circleQuestionMark: "(?)",
questionMarkPrefix: "(?)",
square: "\u2588",
squareDarkShade: "\u2593",
squareMediumShade: "\u2592",
squareLightShade: "\u2591",
squareTop: "\u2580",
squareBottom: "\u2584",
squareLeft: "\u258C",
squareRight: "\u2590",
squareCenter: "\u25A0",
bullet: "\u25CF",
dot: "\u2024",
ellipsis: "\u2026",
pointerSmall: "\u203A",
triangleUp: "\u25B2",
triangleUpSmall: "\u25B4",
triangleDown: "\u25BC",
triangleDownSmall: "\u25BE",
triangleLeftSmall: "\u25C2",
triangleRightSmall: "\u25B8",
home: "\u2302",
heart: "\u2665",
musicNote: "\u266A",
musicNoteBeamed: "\u266B",
arrowUp: "\u2191",
arrowDown: "\u2193",
arrowLeft: "\u2190",
arrowRight: "\u2192",
arrowLeftRight: "\u2194",
arrowUpDown: "\u2195",
almostEqual: "\u2248",
notEqual: "\u2260",
lessOrEqual: "\u2264",
greaterOrEqual: "\u2265",
identical: "\u2261",
infinity: "\u221E",
subscriptZero: "\u2080",
subscriptOne: "\u2081",
subscriptTwo: "\u2082",
subscriptThree: "\u2083",
subscriptFour: "\u2084",
subscriptFive: "\u2085",
subscriptSix: "\u2086",
subscriptSeven: "\u2087",
subscriptEight: "\u2088",
subscriptNine: "\u2089",
oneHalf: "\xBD",
oneThird: "\u2153",
oneQuarter: "\xBC",
oneFifth: "\u2155",
oneSixth: "\u2159",
oneEighth: "\u215B",
twoThirds: "\u2154",
twoFifths: "\u2156",
threeQuarters: "\xBE",
threeFifths: "\u2157",
threeEighths: "\u215C",
fourFifths: "\u2158",
fiveSixths: "\u215A",
fiveEighths: "\u215D",
sevenEighths: "\u215E",
line: "\u2500",
lineBold: "\u2501",
lineDouble: "\u2550",
lineDashed0: "\u2504",
lineDashed1: "\u2505",
lineDashed2: "\u2508",
lineDashed3: "\u2509",
lineDashed4: "\u254C",
lineDashed5: "\u254D",
lineDashed6: "\u2574",
lineDashed7: "\u2576",
lineDashed8: "\u2578",
lineDashed9: "\u257A",
lineDashed10: "\u257C",
lineDashed11: "\u257E",
lineDashed12: "\u2212",
lineDashed13: "\u2013",
lineDashed14: "\u2010",
lineDashed15: "\u2043",
lineVertical: "\u2502",
lineVerticalBold: "\u2503",
lineVerticalDouble: "\u2551",
lineVerticalDashed0: "\u2506",
lineVerticalDashed1: "\u2507",
lineVerticalDashed2: "\u250A",
lineVerticalDashed3: "\u250B",
lineVerticalDashed4: "\u254E",
lineVerticalDashed5: "\u254F",
lineVerticalDashed6: "\u2575",
lineVerticalDashed7: "\u2577",
lineVerticalDashed8: "\u2579",
lineVerticalDashed9: "\u257B",
lineVerticalDashed10: "\u257D",
lineVerticalDashed11: "\u257F",
lineDownLeft: "\u2510",
lineDownLeftArc: "\u256E",
lineDownBoldLeftBold: "\u2513",
lineDownBoldLeft: "\u2512",
lineDownLeftBold: "\u2511",
lineDownDoubleLeftDouble: "\u2557",
lineDownDoubleLeft: "\u2556",
lineDownLeftDouble: "\u2555",
lineDownRight: "\u250C",
lineDownRightArc: "\u256D",
lineDownBoldRightBold: "\u250F",
lineDownBoldRight: "\u250E",
lineDownRightBold: "\u250D",
lineDownDoubleRightDouble: "\u2554",
lineDownDoubleRight: "\u2553",
lineDownRightDouble: "\u2552",
lineUpLeft: "\u2518",
lineUpLeftArc: "\u256F",
lineUpBoldLeftBold: "\u251B",
lineUpBoldLeft: "\u251A",
lineUpLeftBold: "\u2519",
lineUpDoubleLeftDouble: "\u255D",
lineUpDoubleLeft: "\u255C",
lineUpLeftDouble: "\u255B",
lineUpRight: "\u2514",
lineUpRightArc: "\u2570",
lineUpBoldRightBold: "\u2517",
lineUpBoldRight: "\u2516",
lineUpRightBold: "\u2515",
lineUpDoubleRightDouble: "\u255A",
lineUpDoubleRight: "\u2559",
lineUpRightDouble: "\u2558",
lineUpDownLeft: "\u2524",
lineUpBoldDownBoldLeftBold: "\u252B",
lineUpBoldDownBoldLeft: "\u2528",
lineUpDownLeftBold: "\u2525",
lineUpBoldDownLeftBold: "\u2529",
lineUpDownBoldLeftBold: "\u252A",
lineUpDownBoldLeft: "\u2527",
lineUpBoldDownLeft: "\u2526",
lineUpDoubleDownDoubleLeftDouble: "\u2563",
lineUpDoubleDownDoubleLeft: "\u2562",
lineUpDownLeftDouble: "\u2561",
lineUpDownRight: "\u251C",
lineUpBoldDownBoldRightBold: "\u2523",
lineUpBoldDownBoldRight: "\u2520",
lineUpDownRightBold: "\u251D",
lineUpBoldDownRightBold: "\u2521",
lineUpDownBoldRightBold: "\u2522",
lineUpDownBoldRight: "\u251F",
lineUpBoldDownRight: "\u251E",
lineUpDoubleDownDoubleRightDouble: "\u2560",
lineUpDoubleDownDoubleRight: "\u255F",
lineUpDownRightDouble: "\u255E",
lineDownLeftRight: "\u252C",
lineDownBoldLeftBoldRightBold: "\u2533",
lineDownLeftBoldRightBold: "\u252F",
lineDownBoldLeftRight: "\u2530",
lineDownBoldLeftBoldRight: "\u2531",
lineDownBoldLeftRightBold: "\u2532",
lineDownLeftRightBold: "\u252E",
lineDownLeftBoldRight: "\u252D",
lineDownDoubleLeftDoubleRightDouble: "\u2566",
lineDownDoubleLeftRight: "\u2565",
lineDownLeftDoubleRightDouble: "\u2564",
lineUpLeftRight: "\u2534",
lineUpBoldLeftBoldRightBold: "\u253B",
lineUpLeftBoldRightBold: "\u2537",
lineUpBoldLeftRight: "\u2538",
lineUpBoldLeftBoldRight: "\u2539",
lineUpBoldLeftRightBold: "\u253A",
lineUpLeftRightBold: "\u2536",
lineUpLeftBoldRight: "\u2535",
lineUpDoubleLeftDoubleRightDouble: "\u2569",
lineUpDoubleLeftRight: "\u2568",
lineUpLeftDoubleRightDouble: "\u2567",
lineUpDownLeftRight: "\u253C",
lineUpBoldDownBoldLeftBoldRightBold: "\u254B",
lineUpDownBoldLeftBoldRightBold: "\u2548",
lineUpBoldDownLeftBoldRightBold: "\u2547",
lineUpBoldDownBoldLeftRightBold: "\u254A",
lineUpBoldDownBoldLeftBoldRight: "\u2549",
lineUpBoldDownLeftRight: "\u2540",
lineUpDownBoldLeftRight: "\u2541",
lineUpDownLeftBoldRight: "\u253D",
lineUpDownLeftRightBold: "\u253E",
lineUpBoldDownBoldLeftRight: "\u2542",
lineUpDownLeftBoldRightBold: "\u253F",
lineUpBoldDownLeftBoldRight: "\u2543",
lineUpBoldDownLeftRightBold: "\u2544",
lineUpDownBoldLeftBoldRight: "\u2545",
lineUpDownBoldLeftRightBold: "\u2546",
lineUpDoubleDownDoubleLeftDoubleRightDouble: "\u256C",
lineUpDoubleDownDoubleLeftRight: "\u256B",
lineUpDownLeftDoubleRightDouble: "\u256A",
lineCross: "\u2573",
lineBackslash: "\u2572",
lineSlash: "\u2571"
};
var specialMainSymbols = {
tick: "\u2714",
info: "\u2139",
warning: "\u26A0",
cross: "\u2718",
squareSmall: "\u25FB",
squareSmallFilled: "\u25FC",
circle: "\u25EF",
circleFilled: "\u25C9",
circleDotted: "\u25CC",
circleDouble: "\u25CE",
circleCircle: "\u24DE",
circleCross: "\u24E7",
circlePipe: "\u24BE",
radioOn: "\u25C9",
radioOff: "\u25EF",
checkboxOn: "\u2612",
checkboxOff: "\u2610",
checkboxCircleOn: "\u24E7",
checkboxCircleOff: "\u24BE",
pointer: "\u276F",
triangleUpOutline: "\u25B3",
triangleLeft: "\u25C0",
triangleRight: "\u25B6",
lozenge: "\u25C6",
lozengeOutline: "\u25C7",
hamburger: "\u2630",
smiley: "\u32E1",
mustache: "\u0DF4",
star: "\u2605",
play: "\u25B6",
nodejs: "\u2B22",
oneSeventh: "\u2150",
oneNinth: "\u2151",
oneTenth: "\u2152"
};
var specialFallbackSymbols = {
tick: "\u221A",
info: "i",
warning: "\u203C",
cross: "\xD7",
squareSmall: "\u25A1",
squareSmallFilled: "\u25A0",
circle: "( )",
circleFilled: "(*)",
circleDotted: "( )",
circleDouble: "( )",
circleCircle: "(\u25CB)",
circleCross: "(\xD7)",
circlePipe: "(\u2502)",
radioOn: "(*)",
radioOff: "( )",
checkboxOn: "[\xD7]",
checkboxOff: "[ ]",
checkboxCircleOn: "(\xD7)",
checkboxCircleOff: "( )",
pointer: ">",
triangleUpOutline: "\u2206",
triangleLeft: "\u25C4",
triangleRight: "\u25BA",
lozenge: "\u2666",
lozengeOutline: "\u25CA",
hamburger: "\u2261",
smiley: "\u263A",
mustache: "\u250C\u2500\u2510",
star: "\u2736",
play: "\u25BA",
nodejs: "\u2666",
oneSeventh: "1/7",
oneNinth: "1/9",
oneTenth: "1/10"
};
var mainSymbols = {
...common,
...specialMainSymbols
};
var fallbackSymbols = {
...common,
...specialFallbackSymbols
};
var shouldUseMain = isUnicodeSupported();
var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
var dist_default = figures;
var replacements = Object.entries(specialMainSymbols);
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/theme.js
var defaultTheme = {
prefix: {
idle: styleText("blue", "?"),
done: styleText("green", dist_default.tick)
},
spinner: {
interval: 80,
frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"].map((frame) => styleText("yellow", frame))
},
keybindings: [],
style: {
answer: (text2) => styleText("cyan", text2),
message: (text2) => styleText("bold", text2),
error: (text2) => styleText("red", `> ${text2}`),
defaultAnswer: (text2) => styleText("dim", `(${text2})`),
help: (text2) => styleText("dim", text2),
highlight: (text2) => styleText("cyan", text2),
key: (text2) => styleText("cyan", styleText("bold", `<${text2}>`))
}
};
function getDefaultTheme() {
return {
...defaultTheme,
keybindings: getDefaultKeybindings()
};
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/make-theme.js
function isPlainObject3(value) {
if (typeof value !== "object" || value === null)
return false;
let proto2 = value;
while (Object.getPrototypeOf(proto2) !== null) {
proto2 = Object.getPrototypeOf(proto2);
}
return Object.getPrototypeOf(value) === proto2;
}
function deepMerge(...objects) {
const output = {};
for (const obj of objects) {
for (const [key, value] of Object.entries(obj)) {
const prevValue = output[key];
output[key] = isPlainObject3(prevValue) && isPlainObject3(value) ? deepMerge(prevValue, value) : value;
}
}
return output;
}
function makeTheme(...themes) {
const themesToMerge = [
getDefaultTheme(),
...themes.filter((theme) => theme != null)
];
return deepMerge(...themesToMerge);
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/use-prefix.js
function usePrefix({ status = "idle", theme }) {
const [showLoader, setShowLoader] = useState(false);
const [tick, setTick] = useState(0);
const { prefix, spinner } = makeTheme(theme);
useEffect(() => {
if (status === "loading") {
let tickInterval;
let inc = -1;
const delayTimeout = setTimeout(() => {
setShowLoader(true);
tickInterval = setInterval(() => {
inc = inc + 1;
setTick(inc % spinner.frames.length);
}, spinner.interval);
}, 300);
return () => {
clearTimeout(delayTimeout);
clearInterval(tickInterval);
};
} else {
setShowLoader(false);
}
}, [status]);
if (showLoader) {
return spinner.frames[tick];
}
const iconName = status === "loading" ? "idle" : status;
return typeof prefix === "string" ? prefix : prefix[iconName] ?? prefix["idle"];
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/use-memo.js
init_esm_shims();
function useMemo(fn, dependencies) {
return withPointer((pointer) => {
const prev = pointer.get();
if (!pointer.initialized || prev.dependencies.length !== dependencies.length || prev.dependencies.some((dep, i) => dep !== dependencies[i])) {
const value = fn();
pointer.set({ value, dependencies });
return value;
}
return prev.value;
});
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/use-ref.js
init_esm_shims();
function useRef(val) {
return useState({ current: val })[0];
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/use-keypress.js
init_esm_shims();
function useKeypress(userHandler) {
const signal5 = useRef(userHandler);
signal5.current = userHandler;
useEffect((rl) => {
let ignore = false;
const handler = withUpdates((_input, event) => {
if (ignore)
return;
void signal5.current(event, rl);
});
rl.input.on("keypress", handler);
return () => {
ignore = true;
rl.input.removeListener("keypress", handler);
};
}, []);
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js
init_esm_shims();
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/utils.js
init_esm_shims();
var import_cli_width = __toESM(require_cli_width(), 1);
// node_modules/.pnpm/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
init_esm_shims();
// node_modules/.pnpm/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
init_esm_shims();
// node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
init_esm_shims();
// node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
init_esm_shims();
var getCodePointsLength = /* @__PURE__ */ (() => {
const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
return (input) => {
let surrogatePairsNr = 0;
SURROGATE_PAIR_RE.lastIndex = 0;
while (SURROGATE_PAIR_RE.test(input)) {
surrogatePairsNr += 1;
}
return input.length - surrogatePairsNr;
};
})();
var isFullWidth = (x) => {
return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
};
var isWideNotCJKTNotEmoji = (x) => {
return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
};
// node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
var TAB_RE = /\t{1,1000}/y;
var EMOJI_RE = new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*", "yu");
var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
var MODIFIER_RE = new RegExp("\\p{M}+", "gu");
var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
const LIMIT = truncationOptions.limit ?? Infinity;
const ELLIPSIS = truncationOptions.ellipsis ?? "";
const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
const ANSI_WIDTH = 0;
const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
const TAB_WIDTH = widthOptions.tabWidth ?? 8;
const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
const FULL_WIDTH_WIDTH = 2;
const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
const PARSE_BLOCKS = [
[LATIN_RE, REGULAR_WIDTH],
[ANSI_RE, ANSI_WIDTH],
[CONTROL_RE, CONTROL_WIDTH],
[TAB_RE, TAB_WIDTH],
[EMOJI_RE, EMOJI_WIDTH],
[CJKT_WIDE_RE, WIDE_WIDTH]
];
let indexPrev = 0;
let index = 0;
let length = input.length;
let lengthExtra = 0;
let truncationEnabled = false;
let truncationIndex = length;
let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
let unmatchedStart = 0;
let unmatchedEnd = 0;
let width = 0;
let widthExtra = 0;
outer: while (true) {
if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
lengthExtra = 0;
for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
const codePoint = char.codePointAt(0) || 0;
if (isFullWidth(codePoint)) {
widthExtra = FULL_WIDTH_WIDTH;
} else if (isWideNotCJKTNotEmoji(codePoint)) {
widthExtra = WIDE_WIDTH;
} else {
widthExtra = REGULAR_WIDTH;
}
if (width + widthExtra > truncationLimit) {
truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
}
if (width + widthExtra > LIMIT) {
truncationEnabled = true;
break outer;
}
lengthExtra += char.length;
width += widthExtra;
}
unmatchedStart = unmatchedEnd = 0;
}
if (index >= length) {
break outer;
}
for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
BLOCK_RE.lastIndex = index;
if (BLOCK_RE.test(input)) {
lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
widthExtra = lengthExtra * BLOCK_WIDTH;
if (width + widthExtra > truncationLimit) {
truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
}
if (width + widthExtra > LIMIT) {
truncationEnabled = true;
break outer;
}
width += widthExtra;
unmatchedStart = indexPrev;
unmatchedEnd = index;
index = indexPrev = BLOCK_RE.lastIndex;
continue outer;
}
}
index += 1;
}
return {
width: truncationEnabled ? truncationLimit : width,
index: truncationEnabled ? truncationIndex : length,
truncated: truncationEnabled,
ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
};
};
var dist_default2 = getStringTruncatedWidth;
// node_modules/.pnpm/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
var NO_TRUNCATION2 = {
limit: Infinity,
ellipsis: "",
ellipsisWidth: 0
};
var fastStringWidth = (input, options = {}) => {
return dist_default2(input, NO_TRUNCATION2, options).width;
};
var dist_default3 = fastStringWidth;
// node_modules/.pnpm/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
var ESC = "\x1B";
var CSI = "\x9B";
var END_CODE = 39;
var ANSI_ESCAPE_BELL = "\x07";
var ANSI_CSI = "[";
var ANSI_OSC = "]";
var ANSI_SGR_TERMINATOR = "m";
var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
var getClosingCode = (openingCode) => {
if (openingCode >= 30 && openingCode <= 37)
return 39;
if (openingCode >= 90 && openingCode <= 97)
return 39;
if (openingCode >= 40 && openingCode <= 47)
return 49;
if (openingCode >= 100 && openingCode <= 107)
return 49;
if (openingCode === 1 || openingCode === 2)
return 22;
if (openingCode === 3)
return 23;
if (openingCode === 4)
return 24;
if (openingCode === 7)
return 27;
if (openingCode === 8)
return 28;
if (openingCode === 9)
return 29;
if (openingCode === 0)
return 0;
return void 0;
};
var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
var wrapWord = (rows, word, columns) => {
const characters = word[Symbol.iterator]();
let isInsideEscape = false;
let isInsideLinkEscape = false;
let lastRow = rows.at(-1);
let visible = lastRow === void 0 ? 0 : dist_default3(lastRow);
let currentCharacter = characters.next();
let nextCharacter = characters.next();
let rawCharacterIndex = 0;
while (!currentCharacter.done) {
const character = currentCharacter.value;
const characterLength = dist_default3(character);
if (visible + characterLength <= columns) {
rows[rows.length - 1] += character;
} else {
rows.push(character);
visible = 0;
}
if (character === ESC || character === CSI) {
isInsideEscape = true;
isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
}
if (isInsideEscape) {
if (isInsideLinkEscape) {
if (character === ANSI_ESCAPE_BELL) {
isInsideEscape = false;
isInsideLinkEscape = false;
}
} else if (character === ANSI_SGR_TERMINATOR) {
isInsideEscape = false;
}
} else {
visible += characterLength;
if (visible === columns && !nextCharacter.done) {
rows.push("");
visible = 0;
}
}
currentCharacter = nextCharacter;
nextCharacter = characters.next();
rawCharacterIndex += character.length;
}
lastRow = rows.at(-1);
if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) {
rows[rows.length - 2] += rows.pop();
}
};
var stringVisibleTrimSpacesRight = (string) => {
const words = string.split(" ");
let last = words.length;
while (last) {
if (dist_default3(words[last - 1])) {
break;
}
last--;
}
if (last === words.length) {
return string;
}
return words.slice(0, last).join(" ") + words.slice(last).join("");
};
var exec = (string, columns, options = {}) => {
if (options.trim !== false && string.trim() === "") {
return "";
}
let returnValue = "";
let escapeCode;
let escapeUrl;
const words = string.split(" ");
let rows = [""];
let rowLength = 0;
for (let index = 0; index < words.length; index++) {
const word = words[index];
if (options.trim !== false) {
const row = rows.at(-1) ?? "";
const trimmed = row.trimStart();
if (row.length !== trimmed.length) {
rows[rows.length - 1] = trimmed;
rowLength = dist_default3(trimmed);
}
}
if (index !== 0) {
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
rows.push("");
rowLength = 0;
}
if (rowLength || options.trim === false) {
rows[rows.length - 1] += " ";
rowLength++;
}
}
const wordLength = dist_default3(word);
if (options.hard && wordLength > columns) {
const remainingColumns = columns - rowLength;
const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
if (breaksStartingNextLine < breaksStartingThisLine) {
rows.push("");
}
wrapWord(rows, word, columns);
rowLength = dist_default3(rows.at(-1) ?? "");
continue;
}
if (rowLength + wordLength > columns && rowLength && wordLength) {
if (options.wordWrap === false && rowLength < columns) {
wrapWord(rows, word, columns);
rowLength = dist_default3(rows.at(-1) ?? "");
continue;
}
rows.push("");
rowLength = 0;
}
if (rowLength + wordLength > columns && options.wordWrap === false) {
wrapWord(rows, word, columns);
rowLength = dist_default3(rows.at(-1) ?? "");
continue;
}
rows[rows.length - 1] += word;
rowLength += wordLength;
}
if (options.trim !== false) {
rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
}
const preString = rows.join("\n");
let inSurrogate = false;
for (let i = 0; i < preString.length; i++) {
const character = preString[i];
returnValue += character;
if (!inSurrogate) {
inSurrogate = character >= "\uD800" && character <= "\uDBFF";
if (inSurrogate) {
continue;
}
} else {
inSurrogate = false;
}
if (character === ESC || character === CSI) {
GROUP_REGEX.lastIndex = i + 1;
const groupsResult = GROUP_REGEX.exec(preString);
const groups = groupsResult?.groups;
if (groups?.code !== void 0) {
const code = Number.parseFloat(groups.code);
escapeCode = code === END_CODE ? void 0 : code;
} else if (groups?.uri !== void 0) {
escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
}
}
if (preString[i + 1] === "\n") {
if (escapeUrl) {
returnValue += wrapAnsiHyperlink("");
}
const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
if (escapeCode && closingCode) {
returnValue += wrapAnsiCode(closingCode);
}
} else if (character === "\n") {
if (escapeCode && getClosingCode(escapeCode)) {
returnValue += wrapAnsiCode(escapeCode);
}
if (escapeUrl) {
returnValue += wrapAnsiHyperlink(escapeUrl);
}
}
}
return returnValue;
};
var CRLF_OR_LF = /\r?\n/;
function wrapAnsi(string, columns, options) {
return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/utils.js
function breakLines(content, width) {
return content.split("\n").flatMap((line) => wrapAnsi(line, width, { trim: false, wordWrap: false }).split("\n").map((str) => str.trimEnd())).join("\n");
}
function readlineWidth() {
return (0, import_cli_width.default)({ defaultWidth: 80, output: readline().output });
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js
function usePointerPosition({ active, renderedItems, pageSize, loop }) {
const state = useRef({
lastPointer: active,
lastActive: void 0
});
const { lastPointer, lastActive } = state.current;
const middle = Math.floor(pageSize / 2);
const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
const defaultPointerPosition = renderedItems.slice(0, active).reduce((acc, item) => acc + item.length, 0);
let pointer = defaultPointerPosition;
if (renderedLength > pageSize) {
if (loop) {
pointer = lastPointer;
if (
// First render, skip this logic.
lastActive != null && // Only move the pointer down when the user moves down.
lastActive < active && // Check user didn't move up across page boundary.
active - lastActive < pageSize
) {
pointer = Math.min(
// Furthest allowed position for the pointer is the middle of the list
middle,
Math.abs(active - lastActive) === 1 ? Math.min(
// Move the pointer at most the height of the last active item.
lastPointer + (renderedItems[lastActive]?.length ?? 0),
// If the user moved by one item, move the pointer to the natural position of the active item as
// long as it doesn't move the cursor up.
Math.max(defaultPointerPosition, lastPointer)
) : (
// Otherwise, move the pointer down by the difference between the active and last active item.
lastPointer + active - lastActive
)
);
}
} else {
const spaceUnderActive = renderedItems.slice(active).reduce((acc, item) => acc + item.length, 0);
pointer = spaceUnderActive < pageSize - middle ? (
// If the active item is near the end of the list, progressively move the cursor towards the end.
pageSize - spaceUnderActive
) : (
// Otherwise, progressively move the pointer to the middle of the list.
Math.min(defaultPointerPosition, middle)
);
}
}
state.current.lastPointer = pointer;
state.current.lastActive = active;
return pointer;
}
function usePagination({ items, active, renderItem, pageSize, loop = true }) {
const width = readlineWidth();
const bound = (num) => (num % items.length + items.length) % items.length;
const renderedItems = items.map((item, index) => {
if (item == null)
return [];
return breakLines(renderItem({ item, index, isActive: index === active }), width).split("\n");
});
const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
const renderItemAtIndex = (index) => renderedItems[index] ?? [];
const pointer = usePointerPosition({ active, renderedItems, pageSize, loop });
const activeItem = renderItemAtIndex(active).slice(0, pageSize);
const activeItemPosition = pointer + activeItem.length <= pageSize ? pointer : pageSize - activeItem.length;
const pageBuffer = Array.from({ length: pageSize });
pageBuffer.splice(activeItemPosition, activeItem.length, ...activeItem);
const itemVisited = /* @__PURE__ */ new Set([active]);
let bufferPointer = activeItemPosition + activeItem.length;
let itemPointer = bound(active + 1);
while (bufferPointer < pageSize && !itemVisited.has(itemPointer) && (loop && renderedLength > pageSize ? itemPointer !== active : itemPointer > active)) {
const lines = renderItemAtIndex(itemPointer);
const linesToAdd = lines.slice(0, pageSize - bufferPointer);
pageBuffer.splice(bufferPointer, linesToAdd.length, ...linesToAdd);
itemVisited.add(itemPointer);
bufferPointer += linesToAdd.length;
itemPointer = bound(itemPointer + 1);
}
bufferPointer = activeItemPosition - 1;
itemPointer = bound(active - 1);
while (bufferPointer >= 0 && !itemVisited.has(itemPointer) && (loop && renderedLength > pageSize ? itemPointer !== active : itemPointer < active)) {
const lines = renderItemAtIndex(itemPointer);
const linesToAdd = lines.slice(Math.max(0, lines.length - bufferPointer - 1));
pageBuffer.splice(bufferPointer - linesToAdd.length + 1, linesToAdd.length, ...linesToAdd);
itemVisited.add(itemPointer);
bufferPointer -= linesToAdd.length;
itemPointer = bound(itemPointer - 1);
}
return pageBuffer.filter((line) => typeof line === "string").join("\n");
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/create-prompt.js
init_esm_shims();
import * as readline2 from "readline";
import { AsyncResource as AsyncResource3 } from "async_hooks";
// node_modules/.pnpm/@inquirer+type@4.2.1_@types+node@26.6.6/node_modules/@inquirer/type/dist/utils.js
init_esm_shims();
function withResolver() {
let resolve5;
let reject2;
const promise = new Promise((res, rej) => {
resolve5 = res;
reject2 = rej;
});
return { promise, resolve: resolve5, reject: reject2 };
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/create-prompt.js
var import_mute_stream = __toESM(require_lib(), 1);
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/screen-manager.js
init_esm_shims();
import { stripVTControlCharacters as stripVTControlCharacters3 } from "util";
// node_modules/.pnpm/@inquirer+ansi@2.0.10/node_modules/@inquirer/ansi/dist/index.js
init_esm_shims();
var ESC2 = "\x1B[";
var cursorLeft = ESC2 + "G";
var cursorHide = ESC2 + "?25l";
var cursorShow = ESC2 + "?25h";
var cursorUp = (rows = 1) => rows > 0 ? `${ESC2}${rows}A` : "";
var cursorDown = (rows = 1) => rows > 0 ? `${ESC2}${rows}B` : "";
var cursorTo = (x, y) => {
if (typeof y === "number" && !Number.isNaN(y)) {
return `${ESC2}${y + 1};${x + 1}H`;
}
return `${ESC2}${x + 1}G`;
};
var eraseLine = ESC2 + "2K";
var eraseLines = (lines) => lines > 0 ? (eraseLine + cursorUp(1)).repeat(lines - 1) + eraseLine + cursorLeft : "";
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/screen-manager.js
var height = (content) => content.split("\n").length;
var lastLine = (content) => content.split("\n").pop() ?? "";
var ScreenManager = class {
// These variables are keeping information to allow correct prompt re-rendering
height = 0;
extraLinesUnderPrompt = 0;
cursorPos;
rl;
constructor(rl) {
this.rl = rl;
this.cursorPos = rl.getCursorPos();
}
write(content) {
this.rl.output.unmute();
this.rl.output.write(content);
this.rl.output.mute();
}
render(content, bottomContent = "") {
const promptLine = lastLine(content);
const rawPromptLine = stripVTControlCharacters3(promptLine);
let prompt = rawPromptLine;
if (this.rl.line.length > 0) {
prompt = prompt.slice(0, -this.rl.line.length);
}
this.rl.setPrompt(prompt);
this.cursorPos = this.rl.getCursorPos();
const width = readlineWidth();
content = breakLines(content, width);
bottomContent = breakLines(bottomContent, width);
if (rawPromptLine.length % width === 0) {
content += "\n";
}
let output = content + (bottomContent ? "\n" + bottomContent : "");
const promptLineUpDiff = Math.floor(rawPromptLine.length / width) - this.cursorPos.rows;
const bottomContentHeight = promptLineUpDiff + (bottomContent ? height(bottomContent) : 0);
if (bottomContentHeight > 0)
output += cursorUp(bottomContentHeight);
output += cursorTo(this.cursorPos.cols);
this.write(cursorDown(this.extraLinesUnderPrompt) + eraseLines(this.height) + output);
this.extraLinesUnderPrompt = bottomContentHeight;
this.height = height(output);
}
checkCursorPos() {
const cursorPos = this.rl.getCursorPos();
if (cursorPos.cols !== this.cursorPos.cols) {
this.write(cursorTo(cursorPos.cols));
this.cursorPos = cursorPos;
}
}
done({ clearContent }) {
this.rl.setPrompt("");
let output = cursorDown(this.extraLinesUnderPrompt);
output += clearContent ? eraseLines(this.height) : "\n";
output += cursorLeft;
output += cursorShow;
this.write(output);
this.rl.close();
}
};
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/create-prompt.js
import path9 from "path";
var nativeSetImmediate = globalThis.setImmediate;
var nativeClearImmediate = globalThis.clearImmediate;
function listenTo(target, event, listener) {
if ("on" in target) {
target.on(event, listener);
return () => target.removeListener(event, listener);
}
target.addEventListener(event, listener);
return () => target.removeEventListener(event, listener);
}
function getCallSites() {
const savedPrepareStackTrace = Error.prepareStackTrace;
let result2 = [];
try {
Error.prepareStackTrace = (_, callSites) => {
const callSitesWithoutCurrent = callSites.slice(1);
result2 = callSitesWithoutCurrent;
return callSitesWithoutCurrent;
};
new Error().stack;
} catch {
return result2;
}
Error.prepareStackTrace = savedPrepareStackTrace;
return result2;
}
function createPrompt(view) {
const callSites = getCallSites();
const prompt = (config, context = {}) => {
const { input = process.stdin, signal: signal5 } = context;
const cleanups = /* @__PURE__ */ new Set();
const output = new import_mute_stream.default();
output.pipe(context.output ?? process.stdout);
const rl = readline2.createInterface({
terminal: true,
input,
output
});
output.mute();
const screen = new ScreenManager(rl);
const { promise, resolve: resolve5, reject: reject2 } = withResolver();
return withHooks(rl, (cycle) => {
const clearEffects = AsyncResource3.bind(() => effectScheduler.clearAll());
const settlePrompt = (settle) => {
try {
clearEffects();
settle();
} catch (error) {
reject2(error);
}
};
const resolvePrompt = (value) => settlePrompt(() => resolve5(value));
const rejectPrompt = (error) => settlePrompt(() => reject2(error));
const promptPromise = Object.assign(promise.finally(() => {
cleanups.forEach((cleanup) => cleanup());
screen.done({ clearContent: Boolean(context.clearPromptOnDone) });
output.end();
}).then(() => promise), { cancel: () => rejectPrompt(new CancelPromptError()) });
if (signal5) {
const abort = () => rejectPrompt(new AbortPromptError({ cause: signal5.reason }));
if (signal5.aborted) {
abort();
return promptPromise;
}
cleanups.add(listenTo(signal5, "abort", abort));
}
cleanups.add(onExit((code, signal6) => {
rejectPrompt(new ExitPromptError(`User force closed the prompt with ${code} ${signal6}`));
}));
cleanups.add(listenTo(rl, "SIGINT", () => rejectPrompt(new ExitPromptError(`User force closed the prompt with SIGINT`))));
cleanups.add(listenTo(rl, "close", clearEffects));
const startCycle = () => {
cleanups.add(listenTo(rl.input, "keypress", () => screen.checkCursorPos()));
let pendingDone = null;
cycle(() => {
let effectsSettled = false;
try {
const nextView = view(config, (value) => {
if (effectsSettled) {
resolvePrompt(value);
} else {
pendingDone = { value };
}
});
if (nextView === void 0) {
let callerFilename = callSites[1]?.getFileName();
if (callerFilename && !callerFilename.startsWith("file://")) {
callerFilename = path9.resolve(callerFilename);
}
throw new Error(`Prompt functions must return a string.
at ${callerFilename}`);
}
const [content, bottomContent] = typeof nextView === "string" ? [nextView] : nextView;
screen.render(content, bottomContent);
effectScheduler.run();
} catch (error) {
rejectPrompt(error);
}
effectsSettled = true;
if (pendingDone !== null) {
const { value } = pendingDone;
pendingDone = null;
resolvePrompt(value);
}
});
};
if ("readableFlowing" in input && input.isTTY) {
const immediate = nativeSetImmediate(startCycle);
cleanups.add(() => nativeClearImmediate(immediate));
} else {
startCycle();
}
return promptPromise;
});
};
return prompt;
}
// node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.6/node_modules/@inquirer/core/dist/lib/Separator.js
init_esm_shims();
import { styleText as styleText2 } from "util";
var Separator = class {
separator = styleText2("dim", Array.from({ length: 15 }).join(dist_default.line));
type = "separator";
constructor(separator) {
if (separator) {
this.separator = separator;
}
}
static isSeparator(choice) {
return Boolean(choice && typeof choice === "object" && "type" in choice && choice.type === "separator");
}
};
// node_modules/.pnpm/@inquirer+checkbox@5.2.8_@types+node@26.6.6/node_modules/@inquirer/checkbox/dist/index.js
import { styleText as styleText3 } from "util";
var checkboxTheme = {
icon: {
checked: styleText3("green", dist_default.circleFilled),
unchecked: dist_default.circle,
cursor: dist_default.pointer,
disabledChecked: styleText3("green", dist_default.circleDouble),
disabledUnchecked: "-"
},
style: {
disabled: (text2) => styleText3("dim", text2),
renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
description: (text2) => styleText3("cyan", text2),
keysHelpTip: (keys) => keys.map(([key, action]) => `${styleText3("bold", key)} ${styleText3("dim", action)}`).join(styleText3("dim", " \u2022 "))
},
i18n: { disabledError: "This option is disabled and cannot be toggled." }
};
function isSelectable(item) {
return !Separator.isSeparator(item) && !item.disabled;
}
function isNavigable(item) {
return !Separator.isSeparator(item);
}
function isChecked(item) {
return !Separator.isSeparator(item) && item.checked;
}
function toggle(item) {
return isSelectable(item) ? { ...item, checked: !item.checked } : item;
}
function check(checked) {
return function(item) {
return isSelectable(item) ? { ...item, checked } : item;
};
}
function normalizeChoices(choices) {
return choices.map((choice) => {
if (Separator.isSeparator(choice))
return choice;
if (typeof choice !== "object" || choice === null || !("value" in choice)) {
const name2 = String(choice);
return {
value: choice,
name: name2,
short: name2,
checkedName: name2,
disabled: false,
checked: false
};
}
const name = choice.name ?? String(choice.value);
const normalizedChoice = {
value: choice.value,
name,
short: choice.short ?? name,
checkedName: choice.checkedName ?? name,
disabled: choice.disabled ?? false,
checked: choice.checked ?? false
};
if (choice.description) {
normalizedChoice.description = choice.description;
}
return normalizedChoice;
});
}
var dist_default4 = createPrompt((config, done) => {
const { pageSize = 7, loop = true, required, validate = () => true } = config;
const shortcuts = { all: "a", invert: "i", ...config.shortcuts };
const theme = makeTheme(checkboxTheme, config.theme);
const { keybindings: keybindings2 } = theme;
const [status, setStatus] = useState("idle");
const prefix = usePrefix({ status, theme });
const [items, setItems] = useState(normalizeChoices(config.choices));
const bounds = useMemo(() => {
const first = items.findIndex(isNavigable);
const last = items.findLastIndex(isNavigable);
if (first === -1) {
throw new ValidationError2("[checkbox prompt] No selectable choices. All choices are disabled.");
}
return { first, last };
}, [items]);
const [active, setActive] = useState(bounds.first);
const [errorMsg, setError] = useState();
useKeypress(async (key) => {
if (status !== "idle")
return;
if (isEnterKey(key)) {
setStatus("loading");
const selection = items.filter(isChecked);
const isValid = await validate([...selection]);
setStatus("idle");
if (required && !selection.length) {
setError("At least one choice must be selected");
} else if (isValid === true) {
setStatus("done");
done(selection.map((choice) => choice.value));
} else {
setError(isValid || "You must select a valid value");
}
} else if (isUpKey(key, keybindings2) || isDownKey(key, keybindings2)) {
if (errorMsg) {
setError(void 0);
}
if (loop || isUpKey(key, keybindings2) && active !== bounds.first || isDownKey(key, keybindings2) && active !== bounds.last) {
const offset = isUpKey(key, keybindings2) ? -1 : 1;
let next = active;
do {
next = (next + offset + items.length) % items.length;
} while (!isNavigable(items[next]));
setActive(next);
}
} else if (isSpaceKey(key)) {
const activeItem = items[active];
if (activeItem && !Separator.isSeparator(activeItem)) {
if (activeItem.disabled) {
setError(theme.i18n.disabledError);
} else {
setError(void 0);
setItems(items.map((choice, i) => i === active ? toggle(choice) : choice));
}
}
} else if (key.name === shortcuts.all) {
const selectAll = items.some((choice) => isSelectable(choice) && !choice.checked);
setItems(items.map(check(selectAll)));
} else if (key.name === shortcuts.invert) {
setItems(items.map(toggle));
} else if (isNumberKey(key)) {
const selectedIndex = Number(key.name) - 1;
let selectableIndex = -1;
const position = items.findIndex((item) => {
if (Separator.isSeparator(item))
return false;
selectableIndex++;
return selectableIndex === selectedIndex;
});
const selectedItem = items[position];
if (selectedItem && isSelectable(selectedItem)) {
setActive(position);
setItems(items.map((choice, i) => i === position ? toggle(choice) : choice));
}
}
});
const message = theme.style.message(config.message, status);
let description;
const page = usePagination({
items,
active,
renderItem({ item, isActive: isActive2 }) {
if (Separator.isSeparator(item)) {
return ` ${item.separator}`;
}
const cursor = isActive2 ? theme.icon.cursor : " ";
if (item.disabled) {
const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
return theme.style.disabled(`${cursor}${checkbox2} ${item.name} ${disabledLabel}`);
}
if (isActive2) {
description = item.description;
}
const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
const name = item.checked ? item.checkedName : item.name;
const color = isActive2 ? theme.style.highlight : (x) => x;
return color(`${cursor}${checkbox} ${name}`);
},
pageSize,
loop
});
if (status === "done") {
const selection = items.filter(isChecked);
const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
return [prefix, message, answer].filter(Boolean).join(" ");
}
const keys = [
["\u2191\u2193", "navigate"],
["space", "select"]
];
if (shortcuts.all)
keys.push([shortcuts.all, "all"]);
if (shortcuts.invert)
keys.push([shortcuts.invert, "invert"]);
keys.push(["\u23CE", "submit"]);
const helpLine = theme.style.keysHelpTip(keys);
const lines = [
[prefix, message].filter(Boolean).join(" "),
page,
" ",
description ? theme.style.description(description) : "",
errorMsg ? theme.style.error(errorMsg) : "",
helpLine
].filter(Boolean).join("\n").trimEnd();
return `${lines}${cursorHide}`;
});
// node_modules/.pnpm/@inquirer+confirm@6.3.5_@types+node@26.6.6/node_modules/@inquirer/confirm/dist/index.js
init_esm_shims();
import { styleText as styleText4 } from "util";
var confirmTheme = {
keywords: {
yes: "Yes",
no: "No",
error: ({ yes, no }) => `You must answer with "${yes}" or "${no}"`
},
style: {
confirmDefault: (text2) => {
const first = text2[0] ?? "";
if (first.toLowerCase() === first.toUpperCase()) {
return styleText4("cyan", text2);
}
return first.toUpperCase() + text2.slice(1);
}
}
};
var dist_default5 = createPrompt((config, done) => {
const [status, setStatus] = useState("idle");
const [value, setValue2] = useState("");
const [errorMsg, setError] = useState();
const theme = makeTheme(confirmTheme, config.theme);
const prefix = usePrefix({ status, theme });
const { yes, no } = theme.keywords;
const yesHint = (yes[0] ?? "").toLowerCase();
const noHint = (no[0] ?? "").toLowerCase();
const hint = config.default === false ? `${yesHint}/${theme.style.confirmDefault(noHint)}` : `${theme.style.confirmDefault(yesHint)}/${noHint}`;
function boolToString(value2) {
return value2 ? yes : no;
}
const { transformer = boolToString } = config;
function getBooleanValue(value2) {
const v = value2.trim().toLowerCase();
if (v === "")
return config.default !== false;
if (yes.toLowerCase().startsWith(v))
return true;
if (no.toLowerCase().startsWith(v))
return false;
if ("yes".startsWith(v))
return true;
if ("no".startsWith(v))
return false;
return void 0;
}
useKeypress((key, rl) => {
if (status !== "idle")
return;
if (isEnterKey(key)) {
const answer = getBooleanValue(value);
if (answer === void 0) {
rl.write(value);
setError(theme.keywords.error({ yes, no }));
return;
}
setValue2(transformer(answer));
setStatus("done");
done(answer);
} else if (isTabKey(key)) {
const answer = boolToString(!(getBooleanValue(value) ?? config.default !== false));
rl.clearLine(0);
rl.write(answer);
setValue2(answer);
} else {
setValue2(rl.line);
setError(void 0);
}
});
let formattedValue = value;
let defaultValue = "";
if (status === "done") {
formattedValue = theme.style.answer(value);
} else {
defaultValue = ` ${theme.style.defaultAnswer(hint)}`;
}
const message = theme.style.message(config.message, status);
let error = "";
if (errorMsg) {
error = theme.style.error(errorMsg);
}
return [`${prefix} ${message}${defaultValue} ${formattedValue}`, error];
});
// node_modules/.pnpm/@inquirer+input@5.1.9_@types+node@26.6.6/node_modules/@inquirer/input/dist/index.js
init_esm_shims();
var inputTheme = {
validationFailureMode: "keep"
};
var dist_default6 = createPrompt((config, done) => {
const { prefill = "tab" } = config;
const theme = makeTheme(inputTheme, config.theme);
const [status, setStatus] = useState("idle");
const [defaultValue, setDefaultValue] = useState(String(config.default ?? ""));
const [errorMsg, setError] = useState();
const [value, setValue2] = useState("");
const prefix = usePrefix({ status, theme });
async function validate(value2) {
const { required, pattern, patternError = "Invalid input" } = config;
if (required && !value2) {
return "You must provide a value";
}
if (pattern && !pattern.test(value2)) {
return patternError;
}
if (typeof config.validate === "function") {
return await config.validate(value2) || "You must provide a valid value";
}
return true;
}
useKeypress(async (key, rl) => {
if (status !== "idle") {
return;
}
if (isEnterKey(key)) {
const answer = value || defaultValue;
setStatus("loading");
const isValid = await validate(answer);
if (isValid === true) {
setValue2(answer);
setStatus("done");
done(answer);
} else {
if (theme.validationFailureMode === "clear") {
setValue2("");
} else {
rl.write(value);
}
setError(isValid);
setStatus("idle");
}
} else if (isBackspaceKey(key) && !value) {
setDefaultValue("");
} else if (isTabKey(key) && !value) {
setDefaultValue("");
rl.clearLine(0);
rl.write(defaultValue);
setValue2(defaultValue);
} else {
setValue2(rl.line);
setError(void 0);
}
});
useEffect((rl) => {
if (prefill === "editable" && defaultValue) {
rl.write(defaultValue);
setValue2(defaultValue);
}
}, []);
const message = theme.style.message(config.message, status);
let formattedValue = value;
if (typeof config.transformer === "function") {
formattedValue = config.transformer(value, { isFinal: status === "done" });
} else if (status === "done") {
formattedValue = theme.style.answer(value);
}
let defaultStr;
if (defaultValue && status !== "done" && !value) {
defaultStr = theme.style.defaultAnswer(defaultValue);
}
let error = "";
if (errorMsg) {
error = theme.style.error(errorMsg);
}
return [
[prefix, message, defaultStr, formattedValue].filter((v) => v !== void 0).join(" "),
error
];
});
// node_modules/.pnpm/@inquirer+select@5.2.8_@types+node@26.6.6/node_modules/@inquirer/select/dist/index.js
init_esm_shims();
import { styleText as styleText5 } from "util";
var selectTheme = {
icon: { cursor: dist_default.pointer },
style: {
disabled: (text2) => styleText5("dim", text2),
description: (text2) => styleText5("cyan", text2),
keysHelpTip: (keys) => keys.map(([key, action]) => `${styleText5("bold", key)} ${styleText5("dim", action)}`).join(styleText5("dim", " \u2022 "))
},
i18n: { disabledError: "This option is disabled and cannot be selected." },
indexMode: "hidden"
};
function isSelectable2(item) {
return !Separator.isSeparator(item) && !item.disabled;
}
function isNavigable2(item) {
return !Separator.isSeparator(item);
}
function normalizeChoices2(choices) {
return choices.map((choice) => {
if (Separator.isSeparator(choice))
return choice;
if (typeof choice !== "object" || choice === null || !("value" in choice)) {
const name2 = String(choice);
return {
value: choice,
name: name2,
short: name2,
disabled: false
};
}
const name = choice.name ?? String(choice.value);
const normalizedChoice = {
value: choice.value,
name,
short: choice.short ?? name,
disabled: choice.disabled ?? false
};
if (choice.description) {
normalizedChoice.description = choice.description;
}
return normalizedChoice;
});
}
var dist_default7 = createPrompt((config, done) => {
const { loop = true, pageSize = 7 } = config;
const theme = makeTheme(selectTheme, config.theme);
const { keybindings: keybindings2 } = theme;
const [status, setStatus] = useState("idle");
const prefix = usePrefix({ status, theme });
const searchTimeoutRef = useRef();
const searchEnabled = !keybindings2.includes("vim");
const items = useMemo(() => normalizeChoices2(config.choices), [config.choices]);
const bounds = useMemo(() => {
const first = items.findIndex(isNavigable2);
const last = items.findLastIndex(isNavigable2);
if (first === -1) {
throw new ValidationError2("[select prompt] No selectable choices. All choices are disabled.");
}
return { first, last };
}, [items]);
const defaultItemIndex = useMemo(() => {
if (!("default" in config))
return -1;
return items.findIndex((item) => isSelectable2(item) && item.value === config.default);
}, [config.default, items]);
const [active, setActive] = useState(defaultItemIndex === -1 ? bounds.first : defaultItemIndex);
const selectedChoice = items[active];
if (selectedChoice == null || Separator.isSeparator(selectedChoice)) {
throw new Error("Active index does not point to a choice");
}
const [errorMsg, setError] = useState();
useKeypress((key, rl) => {
clearTimeout(searchTimeoutRef.current);
if (errorMsg) {
setError(void 0);
}
if (isEnterKey(key)) {
if (selectedChoice.disabled) {
setError(theme.i18n.disabledError);
} else {
setStatus("done");
done(selectedChoice.value);
}
} else if (isUpKey(key, keybindings2) || isDownKey(key, keybindings2)) {
rl.clearLine(0);
if (loop || isUpKey(key, keybindings2) && active !== bounds.first || isDownKey(key, keybindings2) && active !== bounds.last) {
const offset = isUpKey(key, keybindings2) ? -1 : 1;
let next = active;
do {
next = (next + offset + items.length) % items.length;
} while (!isNavigable2(items[next]));
setActive(next);
}
} else if (isNumberKey(key) && !Number.isNaN(Number(rl.line))) {
const selectedIndex = Number(rl.line) - 1;
let selectableIndex = -1;
const position = items.findIndex((item2) => {
if (Separator.isSeparator(item2))
return false;
selectableIndex++;
return selectableIndex === selectedIndex;
});
const item = items[position];
if (item != null && isSelectable2(item)) {
setActive(position);
}
searchTimeoutRef.current = setTimeout(() => {
rl.clearLine(0);
}, 700);
} else if (isBackspaceKey(key)) {
rl.clearLine(0);
} else if (searchEnabled) {
const searchTerm = rl.line.toLowerCase();
const matchIndex = items.findIndex((item) => {
if (Separator.isSeparator(item) || !isSelectable2(item))
return false;
return item.name.toLowerCase().startsWith(searchTerm);
});
if (matchIndex !== -1) {
setActive(matchIndex);
}
searchTimeoutRef.current = setTimeout(() => {
rl.clearLine(0);
}, 700);
}
});
useEffect(() => () => {
clearTimeout(searchTimeoutRef.current);
}, []);
const message = theme.style.message(config.message, status);
const helpLine = theme.style.keysHelpTip([
["\u2191\u2193", "navigate"],
["\u23CE", "select"]
]);
let separatorCount = 0;
const page = usePagination({
items,
active,
renderItem({ item, isActive: isActive2, index }) {
if (Separator.isSeparator(item)) {
separatorCount++;
return ` ${item.separator}`;
}
const cursor = isActive2 ? theme.icon.cursor : " ";
const indexLabel = theme.indexMode === "number" ? `${index + 1 - separatorCount}. ` : "";
if (item.disabled) {
const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
const disabledCursor = isActive2 ? theme.icon.cursor : "-";
return theme.style.disabled(`${disabledCursor} ${indexLabel}${item.name} ${disabledLabel}`);
}
const color = isActive2 ? theme.style.highlight : (x) => x;
return color(`${cursor} ${indexLabel}${item.name}`);
},
pageSize,
loop
});
if (status === "done") {
return [prefix, message, theme.style.answer(selectedChoice.short)].filter(Boolean).join(" ");
}
const { description } = selectedChoice;
const lines = [
[prefix, message].filter(Boolean).join(" "),
page,
" ",
description ? theme.style.description(description) : "",
errorMsg ? theme.style.error(errorMsg) : "",
helpLine
].filter(Boolean).join("\n").trimEnd();
return `${lines}${cursorHide}`;
});
// src/core/npm-available.ts
init_esm_shims();
import { execFileSync as execFileSync7 } from "child_process";
var cached;
function isNpmAvailable() {
if (cached === void 0) {
try {
execFileSync7("npm --version", { stdio: "ignore", shell: true });
cached = true;
} catch {
cached = false;
}
}
return cached;
}
// src/onboarding/prompts.ts
function isInteractive() {
return Boolean(process.stdout.isTTY && process.stdin.isTTY);
}
async function resolveSelections(detection, snapshotOrOverrides, maybeOverrides, options = {}) {
const snapshot = isSnapshotContext(snapshotOrOverrides) ? snapshotOrOverrides : void 0;
const overrides = isSnapshotContext(snapshotOrOverrides) ? maybeOverrides : snapshotOrOverrides;
if (options.interactive !== false && isInteractive() && !hasFullOverrides(overrides)) {
return runInteractivePrompts(detection, snapshot, overrides);
}
return buildFromOverridesAndDetection(detection, snapshot, overrides);
}
function isSnapshotContext(value) {
return Boolean(value && "toolchains" in value && "packages" in value && "profile" in value);
}
function hasFullOverrides(overrides) {
return Boolean(
overrides && overrides.providers !== void 0 && (overrides.stack_profile !== void 0 || overrides.stack !== void 0 && overrides.capabilities !== void 0)
);
}
function buildFromOverridesAndDetection(detection, snapshot, overrides) {
const domain = inferSelectionDomain(detection, overrides, snapshot);
if (overrides?.stack_profile === void 0 && overrides?.stack === void 0 && domain === "coding" && snapshot?.profile.frameworks.length === 0 && snapshot?.profile.traits.some((trait) => ["docker", "compose"].includes(trait))) {
throw new Error(
"Detected container environment signals without a framework. Re-run onboarding interactively to choose a stack, or pass --stack <stack> together with --capability docker and/or --capability compose."
);
}
const stackProfile = overrides?.stack_profile ?? (overrides?.stack !== void 0 ? buildFallbackStackProfile(domain, overrides.stack, overrides.capabilities ?? [], snapshot) : shouldUseDetectedFallbackProfile(domain, snapshot?.profile) ? buildFallbackStackProfile(
domain,
resolveDetectedFallbackStack(domain, detection),
detection.detected_capabilities,
snapshot
) : snapshot.profile);
const stack = overrides?.stack ?? getPrimaryStack({
active_capabilities: domain === "coding" ? ["content", "coding", "security"] : ["content"],
stack_profile: stackProfile
});
return {
providers: overrides?.providers ?? ["claude-code"],
domain,
stack_profile: stackProfile,
stack,
capabilities: overrides?.capabilities ?? detection.detected_capabilities
};
}
function shouldUseDetectedFallbackProfile(domain, snapshotProfile) {
if (!snapshotProfile) {
return true;
}
if (domain === "content") {
return false;
}
return snapshotProfile.frameworks.length === 0;
}
function resolveDetectedFallbackStack(domain, detection) {
if (detection.detected_stack !== null) {
return detection.detected_stack;
}
if (domain === "content") {
return "short-video";
}
throw new Error(
"Detected coding signals without a resolved stack. Re-run onboarding interactively to choose a stack, or pass --stack <stack> together with any needed --capability values."
);
}
async function runInteractivePrompts(detection, snapshot, overrides) {
let defaults = overrides;
while (true) {
const providers = await promptProviders(defaults?.providers);
const selections = await promptInteractiveSelections({
providers,
domain: inferSelectionDomain(detection, defaults, snapshot),
detection,
snapshot,
overrides: defaults
});
const action = await promptStackConfirmation(detection, snapshot, selections);
if (action === "continue") {
return selections;
}
if (action === "abort") {
throw new Error("Onboarding cancelled before confirmation.");
}
defaults = selections;
}
}
async function promptInteractiveSelections(input) {
if (input.domain === "content" && input.overrides?.stack === void 0 && input.overrides?.stack_profile === void 0 && !input.detection.recommended_capabilities?.includes("coding")) {
return {
providers: input.providers,
domain: "content",
stack_profile: buildFallbackStackProfile("content", "short-video", [], input.snapshot),
stack: "short-video",
capabilities: []
};
}
if (input.domain === "coding" && input.snapshot?.profile && input.detection.detected_stack !== null && input.detection.confidence !== "low" && input.overrides?.stack === void 0 && input.overrides?.stack_profile === void 0) {
const stackProfile = shouldUseDetectedFallbackProfile(input.domain, input.snapshot.profile) ? buildFallbackStackProfile(
input.domain,
resolveDetectedFallbackStack(input.domain, input.detection),
input.detection.detected_capabilities,
input.snapshot
) : input.snapshot.profile;
const stack2 = getPrimaryStack({
active_capabilities: input.domain === "coding" ? ["content", "coding", "security"] : ["content"],
stack_profile: stackProfile
});
return {
providers: input.providers,
domain: input.domain,
stack_profile: stackProfile,
stack: stack2,
capabilities: [...stackProfile.traits]
};
}
const stack = await promptStack(
input.domain,
input.overrides?.stack ?? input.detection.detected_stack ?? void 0
);
const capabilities = await promptCapabilitiesForStack(stack);
return {
providers: input.providers,
domain: input.domain,
stack_profile: buildFallbackStackProfile(input.domain, stack, capabilities, input.snapshot),
stack,
capabilities
};
}
async function promptProviders(defaultProviders) {
if (!isNpmAvailable()) {
return ["claude-code"];
}
const selected = await dist_default4({
message: "Which AI provider(s) do you want to use?",
choices: [
{
name: "Codex (OpenAI)",
value: "codex-cli",
checked: defaultProviders?.includes("codex-cli") ?? true
},
{
name: "Antigravity (Google)",
value: "antigravity",
checked: defaultProviders?.includes("antigravity") ?? false
},
{
name: "Claude Code (Anthropic)",
value: "claude-code",
checked: defaultProviders?.includes("claude-code") ?? true
},
{
name: "Gemini (Google)",
value: "gemini-cli",
checked: defaultProviders?.includes("gemini-cli") ?? true
},
{
name: "Junie (JetBrains)",
value: "junie",
checked: defaultProviders?.includes("junie") ?? true
},
{
name: "Cursor (Anysphere)",
value: "cursor",
checked: defaultProviders?.includes("cursor") ?? false
},
{
name: "GitHub Copilot (GitHub / VS Code Agent)",
value: "github-copilot",
checked: defaultProviders?.includes("github-copilot") ?? false
},
{
name: "Windsurf (Codeium)",
value: "windsurf",
checked: defaultProviders?.includes("windsurf") ?? false
},
{
name: "Continue (Continue.dev)",
value: "continue",
checked: defaultProviders?.includes("continue") ?? false
},
{
name: "Aider (paul-gauthier)",
value: "aider",
checked: defaultProviders?.includes("aider") ?? false
},
{
name: "AI Assistant (JetBrains)",
value: "aiassistant",
checked: defaultProviders?.includes("aiassistant") ?? false
}
],
validate(choices) {
if (choices.length === 0) return "Select at least one provider.";
return true;
}
});
return selected;
}
async function promptStack(domain, detectedStack) {
return dist_default7({
message: "Which stack is this project using?",
choices: getStackPromptChoices(domain),
default: domain === "content" ? "short-video" : detectedStack ?? "laravel"
});
}
async function promptCapabilitiesForStack(stack) {
if (stack === "laravel") {
return promptLaravelDetails();
}
if (stack === "react") {
return promptReactDetails();
}
if (stack === "vue") {
return promptVueDetails();
}
if (stack === "short-video") {
return [];
}
return promptContainerDetails(stack);
}
function formatStackName(stack) {
if (stack === "short-video") {
return "Short Video";
}
return stack.split("-").map((segment) => segment.slice(0, 1).toUpperCase() + segment.slice(1)).join(" ");
}
function getStackPromptChoices(domain) {
if (domain === "content") {
return [{ name: "Short Video", value: "short-video" }];
}
return DOMAIN_STACK_MAP.coding.map((stack) => ({
name: formatStackName(stack),
value: stack
}));
}
async function promptLaravelDetails() {
const capabilities = [];
const inertia = await dist_default7({
message: "Are you using Inertia.js?",
choices: [
{ name: "No", value: false },
{ name: "Yes", value: true }
],
default: false
});
if (inertia) capabilities.push("inertia");
const frontend = await dist_default7({
message: "Which frontend framework are you using?",
choices: [
{ name: "None", value: "none" },
{ name: "React.js", value: "react" },
{ name: "Vue.js", value: "vue" }
],
default: "none"
});
if (frontend === "react") capabilities.push("react");
if (frontend === "vue") capabilities.push("vue");
const tailwind = await dist_default7({
message: "Are you using Tailwind CSS?",
choices: [
{ name: "No", value: false },
{ name: "Yes", value: true }
],
default: false
});
if (tailwind) capabilities.push("tailwind");
const boost = await dist_default7({
message: "Are you using Laravel Boost?",
choices: [
{ name: "No", value: false },
{ name: "Yes", value: true }
],
default: false
});
if (boost) capabilities.push("boost");
const testing = await dist_default7({
message: "Which testing framework are you using?",
choices: [
{ name: "PHPUnit (default)", value: "phpunit" },
{ name: "Pest", value: "pest" },
{ name: "Neither (configure later)", value: "none" }
],
default: "phpunit"
});
if (testing === "pest") capabilities.push("pest");
if (testing === "phpunit") capabilities.push("phpunit");
const sail = await dist_default7({
message: "Are you using Laravel Sail?",
choices: [
{ name: "No", value: false },
{ name: "Yes", value: true }
],
default: false
});
if (sail) {
capabilities.push("sail");
} else {
capabilities.push(...await promptContainerDetails("laravel"));
}
return capabilities;
}
async function promptReactDetails() {
const capabilities = [];
const appType = await dist_default7({
message: "Which React application type are you using?",
choices: [
{ name: "Next.js", value: "next" },
{ name: "Remix", value: "remix" },
{ name: "Vite SPA", value: "vite-spa" },
{ name: "Gatsby", value: "gatsby" }
],
default: "next"
});
capabilities.push(appType);
const tailwind = await dist_default7({
message: "Are you using Tailwind CSS?",
choices: [
{ name: "No", value: false },
{ name: "Yes", value: true }
],
default: false
});
if (tailwind) capabilities.push("tailwind");
capabilities.push(...await promptContainerDetails("react"));
return capabilities;
}
async function promptVueDetails() {
const capabilities = [];
const appType = await dist_default7({
message: "Which Vue application type are you using?",
choices: [
{ name: "Nuxt", value: "nuxt" },
{ name: "Vite SPA", value: "vite-spa" },
{ name: "Quasar", value: "quasar" }
],
default: "nuxt"
});
capabilities.push(appType);
const tailwind = await dist_default7({
message: "Are you using Tailwind CSS?",
choices: [
{ name: "No", value: false },
{ name: "Yes", value: true }
],
default: false
});
if (tailwind) capabilities.push("tailwind");
capabilities.push(...await promptContainerDetails("vue"));
return capabilities;
}
async function promptContainerDetails(stack) {
const supported = new Set(STACK_CAPABILITIES_MAP[stack]);
if (!supported.has("docker") && !supported.has("compose")) {
return [];
}
const capabilities = [];
const docker = await dist_default7({
message: `Does this ${formatStackName(stack)} project use Docker?`,
choices: [
{ name: "No", value: false },
{ name: "Yes", value: true }
],
default: false
});
if (!docker) {
return capabilities;
}
if (supported.has("docker")) {
capabilities.push("docker");
}
if (!supported.has("compose")) {
return capabilities;
}
const compose = await dist_default7({
message: `Does this ${formatStackName(stack)} project use Docker Compose?`,
choices: [
{ name: "No", value: false },
{ name: "Yes", value: true }
],
default: false
});
if (compose) {
capabilities.push("compose");
}
return capabilities;
}
function buildFallbackStackProfile(_domain, stack, capabilities, snapshot) {
const fallbackSource = {
file: "interactive-onboarding",
kind: "fallback",
detail: "User-selected fallback stack profile"
};
return buildDetectedStackProfile({
toolchains: snapshot?.toolchains ?? [],
packages: snapshot?.packages ?? [],
sources: deduplicateSources([...snapshot?.profile?.sources ?? [], fallbackSource]),
detectedTraits: snapshot?.profile?.traits ?? [],
fallbackStack: stack,
fallbackCapabilities: capabilities
});
}
function deduplicateSources(sources) {
const seen = /* @__PURE__ */ new Set();
return sources.filter((source) => {
const key = `${source.file}::${source.kind}::${source.detail}`;
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
async function promptStackConfirmation(detection, snapshot, selections) {
if (!shouldConfirmSelections(selections)) {
return "continue";
}
process.stdout.write(`
${renderStackConfirmationSummary(detection, snapshot, selections)}
`);
return dist_default7({
message: "Continue with this detected stack profile?",
choices: [
{ name: "Continue", value: "continue" },
{ name: "Revise selections", value: "revise" },
{ name: "Abort onboarding", value: "abort" }
],
default: "continue"
});
}
function shouldConfirmSelections(selections) {
return !(selections.domain === "content" && selections.stack === "short-video");
}
function renderStackConfirmationSummary(detection, snapshot, selections) {
const effectiveStack = selections.stack ?? getPrimaryStack({
active_capabilities: selections.domain === "coding" ? ["content", "coding", "security"] : ["content"],
stack_profile: selections.stack_profile
});
const lines = [
"Detected stack summary",
`- Domain: ${selections.domain}`,
`- Primary stack: ${effectiveStack}`,
`- Effective profile: ${summarizeStack(selections.stack_profile)}`,
`- Confidence: ${detection.confidence}`,
`- Frameworks: ${formatList(selections.stack_profile.frameworks)}`,
`- Traits/capabilities: ${formatList(selections.stack_profile.traits)}`,
`- Toolchains: ${formatToolchains(snapshot?.toolchains ?? [])}`,
`- Version bands: ${formatVersionBands(selections.stack_profile.version_bands)}`,
`- Packages sampled: ${formatPackages(snapshot?.packages ?? [])}`,
`- Source signals: ${formatSources(selections.stack_profile.sources)}`
];
const detectedSummary = detection.detected_stack === null ? "none" : `${detection.detected_domain ?? "unknown"} / ${detection.detected_stack}`;
const finalSummary = `${selections.domain} / ${effectiveStack}`;
if (detectedSummary !== finalSummary) {
lines.push(`- Detected choice: ${detectedSummary}`);
lines.push(`- Final effective choice: ${finalSummary}`);
}
return lines.join("\n");
}
function formatList(values) {
return values.length === 0 ? "none" : values.join(", ");
}
function formatToolchains(toolchains) {
return toolchains.length === 0 ? "none" : toolchains.map(
(toolchain) => `${toolchain.ecosystem}:${toolchain.package_manager} (${toolchain.lockfile})`
).join(", ");
}
function formatVersionBands(bands) {
return bands.length === 0 ? "none" : bands.slice(0, 5).map((band) => `${band.package_name}@${band.locked_version} -> ${band.range}`).join(", ");
}
function formatPackages(packages) {
return packages.length === 0 ? "none" : packages.slice(0, 5).map((pkg) => `${pkg.name}@${pkg.locked_version}`).join(", ");
}
function formatSources(sources) {
return sources.length === 0 ? "none" : sources.slice(0, 5).map((source) => `${source.file} (${source.kind})`).join(", ");
}
function inferSelectionDomain(detection, overrides, snapshot) {
if (overrides?.domain) {
return overrides.domain;
}
if (overrides?.stack === "short-video") {
return "content";
}
if (overrides?.stack) {
return "coding";
}
if (detection.recommended_capabilities?.includes("coding")) {
return "coding";
}
if ((snapshot?.profile.frameworks.length ?? 0) > 0 || (snapshot?.profile.traits.length ?? 0) > 0) {
return "coding";
}
if (detection.detected_domain) {
return detection.detected_domain;
}
return "content";
}
// src/onboarding/rag-onboarding.ts
init_esm_shims();
// src/cli/ui/rag-progress.ts
init_esm_shims();
// node_modules/.pnpm/chalk@6.0.1/node_modules/chalk/source/index.js
init_esm_shims();
// node_modules/.pnpm/chalk@6.0.1/node_modules/chalk/source/utilities.js
init_esm_shims();
function stringReplaceAll(string, substring, postfix) {
let index = string.indexOf(substring);
if (index === -1) {
return string;
}
const substringLength = substring.length;
let endIndex = 0;
let returnValue = "";
do {
returnValue += string.slice(endIndex, index) + substring + postfix;
endIndex = index + substringLength;
index = string.indexOf(substring, endIndex);
} while (index !== -1);
returnValue += string.slice(endIndex);
return returnValue;
}
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
let endIndex = 0;
let returnValue = "";
do {
const isGotCR = string[index - 1] === "\r";
returnValue += string.slice(endIndex, isGotCR ? index - 1 : index) + prefix + (isGotCR ? "\r\n" : "\n") + postfix;
endIndex = index + 1;
index = string.indexOf("\n", endIndex);
} while (index !== -1);
returnValue += string.slice(endIndex);
return returnValue;
}
// node_modules/.pnpm/chalk@6.0.1/node_modules/chalk/source/vendor/ansi-styles/index.js
init_esm_shims();
var ANSI_BACKGROUND_OFFSET = 10;
var ANSI_UNDERLINE_OFFSET = 20;
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
var wrapUnderlineAnsi = (code) => `\x1B[58;5;${code < 90 ? code - 30 : code - 90 + 8}m`;
var styles = {
modifier: {
reset: [0, 0],
// 21 isn't widely supported and 22 does the same thing
bold: [1, 22],
dim: [2, 22],
italic: [3, 23],
underline: [4, 24],
// Extended underline styles (`SGR 4:x` sub-parameters). Not in upstream `ansi-styles`.
underlineDouble: ["4:2", 24],
underlineCurly: ["4:3", 24],
underlineDotted: ["4:4", 24],
underlineDashed: ["4:5", 24],
overline: [53, 55],
inverse: [7, 27],
hidden: [8, 28],
strikethrough: [9, 29]
},
color: {
black: [30, 39],
red: [31, 39],
green: [32, 39],
yellow: [33, 39],
blue: [34, 39],
magenta: [35, 39],
cyan: [36, 39],
white: [37, 39],
// Bright color
blackBright: [90, 39],
gray: [90, 39],
// Alias of `blackBright`
grey: [90, 39],
// Alias of `blackBright`
redBright: [91, 39],
greenBright: [92, 39],
yellowBright: [93, 39],
blueBright: [94, 39],
magentaBright: [95, 39],
cyanBright: [96, 39],
whiteBright: [97, 39]
},
bgColor: {
bgBlack: [40, 49],
bgRed: [41, 49],
bgGreen: [42, 49],
bgYellow: [43, 49],
bgBlue: [44, 49],
bgMagenta: [45, 49],
bgCyan: [46, 49],
bgWhite: [47, 49],
// Bright color
bgBlackBright: [100, 49],
bgGray: [100, 49],
// Alias of `bgBlackBright`
bgGrey: [100, 49],
// Alias of `bgBlackBright`
bgRedBright: [101, 49],
bgGreenBright: [102, 49],
bgYellowBright: [103, 49],
bgBlueBright: [104, 49],
bgMagentaBright: [105, 49],
bgCyanBright: [106, 49],
bgWhiteBright: [107, 49]
},
// Underline color (`SGR 58`/`59`). Not in upstream `ansi-styles`.
underlineColor: {
underlineBlack: ["58;5;0", 59],
underlineRed: ["58;5;1", 59],
underlineGreen: ["58;5;2", 59],
underlineYellow: ["58;5;3", 59],
underlineBlue: ["58;5;4", 59],
underlineMagenta: ["58;5;5", 59],
underlineCyan: ["58;5;6", 59],
underlineWhite: ["58;5;7", 59],
// Bright color
underlineBlackBright: ["58;5;8", 59],
underlineGray: ["58;5;8", 59],
// Alias of `underlineBlackBright`
underlineGrey: ["58;5;8", 59],
// Alias of `underlineBlackBright`
underlineRedBright: ["58;5;9", 59],
underlineGreenBright: ["58;5;10", 59],
underlineYellowBright: ["58;5;11", 59],
underlineBlueBright: ["58;5;12", 59],
underlineMagentaBright: ["58;5;13", 59],
underlineCyanBright: ["58;5;14", 59],
underlineWhiteBright: ["58;5;15", 59]
}
};
var modifierNames = Object.keys(styles.modifier);
var foregroundColorNames = Object.keys(styles.color);
var backgroundColorNames = Object.keys(styles.bgColor);
var underlineColorNames = Object.keys(styles.underlineColor);
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
function assembleStyles() {
const codes = /* @__PURE__ */ new Map();
for (const [groupName, group] of Object.entries(styles)) {
for (const [styleName, style] of Object.entries(group)) {
styles[styleName] = {
open: `\x1B[${style[0]}m`,
close: `\x1B[${style[1]}m`
};
group[styleName] = styles[styleName];
codes.set(Number.parseInt(style[0], 10), style[1]);
}
Object.defineProperty(styles, groupName, {
value: group,
enumerable: false
});
}
Object.defineProperty(styles, "codes", {
value: codes,
enumerable: false
});
styles.color.close = "\x1B[39m";
styles.bgColor.close = "\x1B[49m";
styles.underlineColor.close = "\x1B[59m";
styles.color.ansi = wrapAnsi16();
styles.color.ansi256 = wrapAnsi256();
styles.color.ansi16m = wrapAnsi16m();
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
styles.underlineColor.ansi = wrapUnderlineAnsi;
styles.underlineColor.ansi256 = wrapAnsi256(ANSI_UNDERLINE_OFFSET);
styles.underlineColor.ansi16m = wrapAnsi16m(ANSI_UNDERLINE_OFFSET);
Object.defineProperties(styles, {
rgbToAnsi256: {
value(red, green, blue) {
if (red === green && green === blue) {
if (red < 8) {
return 16;
}
if (red > 248) {
return 231;
}
return Math.round((red - 8) / 247 * 24) + 232;
}
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
},
enumerable: false
},
hexToRgb: {
value(hex) {
const matches = /[\da-f]{6}|[\da-f]{3}/i.exec(hex.toString(16));
if (!matches) {
return [0, 0, 0];
}
let [colorString] = matches;
if (colorString.length === 3) {
colorString = [...colorString].map((character) => character + character).join("");
}
const integer = Number.parseInt(colorString, 16);
return [
/* eslint-disable no-bitwise -- We need the speed */
integer >> 16 & 255,
integer >> 8 & 255,
integer & 255
/* eslint-enable no-bitwise */
];
},
enumerable: false
},
hexToAnsi256: {
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
enumerable: false
},
ansi256ToAnsi: {
value(code) {
if (code < 8) {
return 30 + code;
}
if (code < 16) {
return 90 + (code - 8);
}
let red;
let green;
let blue;
if (code >= 232) {
red = ((code - 232) * 10 + 8) / 255;
green = red;
blue = red;
} else {
code -= 16;
const remainder = code % 36;
red = Math.floor(code / 36) / 5;
green = Math.floor(remainder / 6) / 5;
blue = remainder % 6 / 5;
}
const value = Math.max(red, green, blue) * 2;
if (value === 0) {
return 30;
}
let result2 = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
if (value === 2) {
result2 += 60;
}
return result2;
},
enumerable: false
},
rgbToAnsi: {
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
enumerable: false
},
hexToAnsi: {
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
enumerable: false
}
});
return styles;
}
var ansiStyles = assembleStyles();
var ansi_styles_default = ansiStyles;
// node_modules/.pnpm/chalk@6.0.1/node_modules/chalk/source/vendor/supports-color/index.js
init_esm_shims();
import process4 from "process";
import os from "os";
import tty from "tty";
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process4.argv) {
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
const position = argv.indexOf(prefix + flag);
const terminatorPosition = argv.indexOf("--");
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
}
var { env } = process4;
var flagForceColor;
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
flagForceColor = 0;
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
flagForceColor = 1;
}
function hasNumericForceColor() {
return /^\d+$/.test(env.FORCE_COLOR);
}
function envForceColor() {
if (!("FORCE_COLOR" in env)) {
return;
}
if (env.FORCE_COLOR === "false") {
return 0;
}
if (env.FORCE_COLOR === "true" || env.FORCE_COLOR.length === 0) {
return 1;
}
if (!hasNumericForceColor()) {
return;
}
return Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
}
function translateLevel(level) {
if (level === 0) {
return false;
}
return {
level,
hasBasic: true,
has256: level >= 2,
has16m: level >= 3
};
}
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
const noFlagForceColor = envForceColor();
if (noFlagForceColor !== void 0) {
flagForceColor = noFlagForceColor;
}
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
if (forceColor === 0) {
return 0;
}
if (sniffFlags) {
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
return 3;
}
if (hasFlag("color=256")) {
return 2;
}
}
if (forceColor !== void 0 && hasNumericForceColor()) {
return forceColor;
}
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
return 1;
}
if (haveStream && !streamIsTTY && forceColor === void 0) {
return 0;
}
const min = forceColor || 0;
if (env.TERM === "dumb") {
return min;
}
if (process4.platform === "win32") {
const osRelease = os.release().split(".");
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
return Number(osRelease[2]) >= 14931 ? 3 : 2;
}
return 1;
}
if ("CI" in env) {
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
return 3;
}
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
return 1;
}
return min;
}
if ("TEAMCITY_VERSION" in env) {
return /^(?:9\.0*[1-9]\d*\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
}
if (env.COLORTERM === "truecolor") {
return 3;
}
if (env.TERM === "xterm-kitty") {
return 3;
}
if (env.TERM === "xterm-ghostty") {
return 3;
}
if (env.TERM === "wezterm") {
return 3;
}
if ("TERM_PROGRAM" in env) {
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".", 1)[0], 10);
switch (env.TERM_PROGRAM) {
case "iTerm.app": {
return version >= 3 ? 3 : 2;
}
case "Apple_Terminal": {
return 2;
}
}
}
if (/-256(?:color)?$/i.test(env.TERM)) {
return 2;
}
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
return 1;
}
if ("COLORTERM" in env) {
return 1;
}
return min;
}
function createSupportsColor(stream, options = {}) {
const level = _supportsColor(stream, {
streamIsTTY: stream && stream.isTTY,
...options
});
return translateLevel(level);
}
var supportsColor = {
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
};
var supports_color_default = supportsColor;
// node_modules/.pnpm/chalk@6.0.1/node_modules/chalk/source/index.js
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
var STYLER = /* @__PURE__ */ Symbol("STYLER");
var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
var LEVEL = /* @__PURE__ */ Symbol("LEVEL");
var styles2 = /* @__PURE__ */ Object.create(null);
var assertValidLevel = (level) => {
if (!Number.isSafeInteger(level) || level < 0 || level > 3) {
throw new Error("The `level` should be an integer from 0 to 3");
}
};
var levelDescriptor = {
enumerable: true,
get() {
return this[LEVEL];
},
set(level) {
assertValidLevel(level);
this[LEVEL] = level;
}
};
var applyOptions = (object, options = {}) => {
if (options.level !== void 0) {
assertValidLevel(options.level);
}
const colorLevel = stdoutColor ? stdoutColor.level : 0;
object[LEVEL] = options.level === void 0 ? colorLevel : options.level;
};
var chalkFactory = (options) => {
const chalk2 = (...strings2) => strings2.join(" ");
applyOptions(chalk2, options);
Object.setPrototypeOf(chalk2, createChalk.prototype);
return chalk2;
};
function createChalk(options) {
return chalkFactory(options);
}
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
styles2[styleName] = {
get() {
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
Object.defineProperty(this, styleName, { value: builder });
return builder;
}
};
}
styles2.visible = {
get() {
const builder = createBuilder(this, this[STYLER], true);
Object.defineProperty(this, "visible", { value: builder });
return builder;
}
};
var createModelConverters = (model, type) => {
const style = ansi_styles_default[type];
if (model === "rgb") {
const ansi2 = (red, green, blue) => style.ansi(ansi_styles_default.rgbToAnsi(red, green, blue));
const ansi256 = (red, green, blue) => style.ansi256(ansi_styles_default.rgbToAnsi256(red, green, blue));
return [ansi2, ansi2, ansi256, style.ansi16m];
}
if (model === "hex") {
const ansi2 = (hex) => style.ansi(ansi_styles_default.hexToAnsi(hex));
const ansi256 = (hex) => style.ansi256(ansi_styles_default.hexToAnsi256(hex));
return [ansi2, ansi2, ansi256, (hex) => style.ansi16m(...ansi_styles_default.hexToRgb(hex))];
}
const ansi = (code) => style.ansi(ansi_styles_default.ansi256ToAnsi(code));
return [ansi, ansi, style.ansi256, style.ansi256];
};
var usedModels = ["rgb", "hex", "ansi256"];
for (const model of usedModels) {
const capitalizedModel = model[0].toUpperCase() + model.slice(1);
for (const [styleName, type] of [
[model, "color"],
["bg" + capitalizedModel, "bgColor"],
["underline" + capitalizedModel, "underlineColor"]
]) {
const { close } = ansi_styles_default[type];
const converters = createModelConverters(model, type);
styles2[styleName] = {
get() {
const styleFunction = function(first, second, third) {
const open = converters[this.level](first, second, third);
return createBuilder(this, createStyler(open, close, this[STYLER]), this[IS_EMPTY]);
};
Object.defineProperty(this, styleName, { value: styleFunction });
return styleFunction;
}
};
}
}
var proto = Object.defineProperties(
() => {
},
{
...styles2,
level: {
enumerable: true,
get() {
return this[GENERATOR].level;
},
set(level) {
this[GENERATOR].level = level;
}
}
}
);
var createStyler = (open, close, parent) => {
let openAll;
let closeAll;
if (parent === void 0) {
openAll = open;
closeAll = close;
} else {
openAll = parent.openAll + open;
closeAll = close + parent.closeAll;
}
return {
open,
close,
openAll,
closeAll,
parent
};
};
var createBuilder = (self, _styler, _isEmpty) => {
const builder = (...arguments_) => {
if (arguments_.length === 1) {
return applyStyle(builder, "" + arguments_[0]);
}
if (arguments_.length === 2) {
return applyStyle(builder, `${arguments_[0] ?? ""} ${arguments_[1] ?? ""}`);
}
return applyStyle(builder, arguments_.join(" "));
};
Object.setPrototypeOf(builder, proto);
builder[GENERATOR] = self[GENERATOR] ?? self;
builder[STYLER] = _styler;
builder[IS_EMPTY] = _isEmpty;
return builder;
};
var applyStyle = (self, string) => {
if (self[GENERATOR][LEVEL] <= 0 || !string) {
return self[IS_EMPTY] ? "" : string;
}
let styler = self[STYLER];
if (styler === void 0) {
return string;
}
const { openAll, closeAll } = styler;
if (string.includes("\x1B")) {
while (styler !== void 0) {
string = stringReplaceAll(string, styler.close, styler.open);
styler = styler.parent;
}
}
const lfIndex = string.indexOf("\n");
if (lfIndex !== -1) {
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
}
return openAll + string + closeAll;
};
Object.defineProperties(createChalk.prototype, { ...styles2, level: levelDescriptor });
var chalk = createChalk();
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
var source_default = chalk;
// src/cli/ui/rag-progress.ts
var PANEL_WIDTH = 74;
function border(left, fill, right) {
return `${left}${fill.repeat(PANEL_WIDTH)}${right}`;
}
function pad(text2 = "") {
return ` ${text2}`.padEnd(PANEL_WIDTH, " ");
}
function surface(text2) {
return source_default.hex("#FFF7ED")(text2);
}
function accent(text2) {
return source_default.hex("#C2410C").bold(text2);
}
function muted(text2) {
return source_default.hex("#9A6B55")(text2);
}
function highlight(text2) {
return source_default.hex("#7C2D12").bold(text2);
}
function progressText(update) {
if (update.percent === void 0) {
return update.message;
}
return `${update.percent.toString().padStart(3, " ")}% ${update.message}`;
}
function detectStep(update) {
const message = update.message.toLowerCase();
if (update.phase === "download" || update.phase === "load") {
return { id: "prepare", number: 1, title: "Preparing embedding runtime" };
}
if (message.includes("discovering repository files") || message.includes("filtering ") || message.includes("filtered ") || message.includes("eligib") || message.includes("chunking") || message.includes("chunked")) {
return { id: "scan", number: 2, title: "Discovering, filtering, and chunking the codebase" };
}
if (message.includes("embedded")) {
return { id: "embed", number: 3, title: "Generating embeddings and vector data" };
}
return { id: "finalize", number: 4, title: "Finalizing RAG indexes and metadata" };
}
function renderRagIntroPanel() {
const lines = [
accent(border("\u2554", "\u2550", "\u2557")),
accent("\u2551") + surface(pad(" OPTIONAL PROJECT INTELLIGENCE")) + accent("\u2551"),
accent(border("\u2560", "\u2550", "\u2563")),
accent("\u2551") + surface(pad(" Build a semantic RAG layer over this codebase.")) + accent("\u2551"),
accent("\u2551") + muted(pad(" paqad-ai keeps AI suggestions relevant as files, docs, and patterns grow.")) + accent("\u2551"),
accent("\u2551") + surface(pad()) + accent("\u2551"),
accent("\u2551") + highlight(pad(" Retrieval-Augmented Generation (RAG) for your repo")) + accent("\u2551"),
accent("\u2551") + surface(pad()) + accent("\u2551"),
accent("\u2551") + muted(pad(" \u2022 Pulls the most relevant code and docs into each task")) + accent("\u2551"),
accent("\u2551") + muted(pad(" \u2022 Cuts irrelevant context so prompts stay tighter and cheaper")) + accent("\u2551"),
accent("\u2551") + muted(pad(" \u2022 Keeps completions grounded in your actual project structure")) + accent("\u2551"),
accent(border("\u255A", "\u2550", "\u255D")),
""
];
return lines.join("\n");
}
function createRagProgressReporter(write) {
let lastStepId;
return (update) => {
const step = detectStep(update);
if (step.id !== lastStepId) {
write(source_default.hex("#C2410C").bold(`[${step.number}/4] ${step.title}`));
lastStepId = step.id;
}
write(`${source_default.hex("#EA580C")(" >")} ${progressText(update)}`);
};
}
// src/onboarding/rag-onboarding.ts
var RAG_ENGINE_INSTALLING_LINE = "search index is installing in the background; text search until it is ready";
function ragEngineInstallingInBackground(projectRoot, ragSelection, env2 = process.env) {
if (ragSelection.provider !== "local") {
return false;
}
if (describeOptionalEngine(env2).state === "ready") {
return false;
}
const outcome = maybeStartOptionalEngineInstall(env2, {}, { projectRoot });
return outcome === "started" || outcome === "in-progress";
}
function isInteractive2() {
return Boolean(process.stdout.isTTY && process.stdin.isTTY);
}
function printRagProgress(message) {
process.stderr.write(`${message}
`);
}
async function resolveRagSelection(domain, preset, options = {}) {
if (preset) {
return preset.enabled ? {
enabled: true,
provider: preset.provider ?? "local",
model: preset.model ?? getDefaultEmbeddingModel(preset.provider ?? "local")
} : { enabled: false };
}
if (domain !== "coding" || options.interactive === false || !isInteractive2()) {
return void 0;
}
process.stdout.write(renderRagIntroPanel());
const enabled = await dist_default7({
message: "Want to enable this?",
choices: [
{
value: true,
name: "Yes, set it up for me",
description: "Recommended for coding projects"
},
{ value: false, name: "No, skip for now" }
],
default: true
});
if (!enabled) {
return { enabled: false };
}
const provider = await dist_default7({
message: "How should paqad-ai build your RAG index?",
default: "local",
choices: [
{
value: "local",
name: "On my machine (FREE \u2014 no account needed)",
description: "Runs a local embedding model (~80MB), private and shared under ~/.paqad/models"
},
{
value: "openai",
name: "Using my OpenAI key",
description: "Uses text-embedding-3-small for remote embeddings"
}
]
});
return {
enabled: true,
provider,
model: getDefaultEmbeddingModel(provider)
};
}
function applyRagSelection(intelligence, ragSelection) {
if (!ragSelection) {
return normalizeIntelligenceConfig(intelligence);
}
if (!ragSelection.enabled || !ragSelection.provider) {
return normalizeIntelligenceConfig({
...intelligence,
rag_enabled: false,
embedding_provider: void 0,
embedding_model: void 0
});
}
return normalizeIntelligenceConfig({
...intelligence,
rag_enabled: true,
embedding_provider: ragSelection.provider,
embedding_model: ragSelection.model ?? getDefaultEmbeddingModel(ragSelection.provider)
});
}
async function enableRagDuringOnboarding(projectRoot, ragSelection) {
if (!ragSelection.provider) {
return;
}
const service = new RagService(projectRoot);
if (ragSelection.provider !== "local" && !service.hasApiKey(ragSelection.provider)) {
if (!isInteractive2()) {
throw new Error("Missing OPENAI_API_KEY");
}
const key = await dist_default6({
message: "Enter your OpenAI API key",
validate: (value) => value.trim().length > 0 ? true : "API key is required"
});
service.storeApiKey(ragSelection.provider, key.trim());
}
const reportProgress = createRagProgressReporter(printRagProgress);
await service.configureAndBuild(
{
rag_enabled: true,
embedding_provider: ragSelection.provider,
embedding_model: ragSelection.model ?? getDefaultEmbeddingModel(ragSelection.provider)
},
reportProgress
);
}
// src/onboarding/reference-generator.ts
init_esm_shims();
var import_fast_glob12 = __toESM(require_out(), 1);
import { existsSync as existsSync25 } from "fs";
import { readFile as readFile26 } from "fs/promises";
import { join as join62, relative as relative11 } from "path";
async function generateReferenceGuides(runtimeRoot, context) {
if (context.domain !== "coding") {
return [];
}
const stack = getPrimaryStack({
active_capabilities: ["content", "coding", "security"],
routing: { domain: context.domain },
stack_profile: context.stack_profile
});
const referencesRoot = join62(runtimeRoot, "capabilities", "coding", "stacks", stack, "references");
if (!existsSync25(referencesRoot)) {
return [buildFallbackReferenceGuide(stack)];
}
const entries = await (0, import_fast_glob12.default)(["tools/*.md", "tools-catalog.md"], {
cwd: referencesRoot,
onlyFiles: true,
absolute: true
});
if (entries.length === 0) {
return [buildFallbackReferenceGuide(stack)];
}
return Promise.all(
entries.sort().map(async (entry) => ({
path: toProjectReferencePath(stack, relative11(referencesRoot, entry)),
content: await readFile26(entry, "utf8"),
autoUpdate: false
}))
);
}
function toProjectReferencePath(stack, relativePath) {
const normalized = relativePath.replaceAll("\\", "/");
if (normalized === "tools-catalog.md") {
return toPosixPath(join62(PATHS.TOOLS_DIR, stack, "README.md"));
}
return toPosixPath(join62(PATHS.TOOLS_DIR, stack, normalized.replace(/^tools\//, "")));
}
function buildFallbackReferenceGuide(stack) {
const title = stack.split("-").map((segment) => segment.slice(0, 1).toUpperCase() + segment.slice(1)).join(" ");
return {
path: toPosixPath(join62(PATHS.TOOLS_DIR, stack, "README.md")),
autoUpdate: false,
content: [
`# ${title} Tool References`,
"",
"This stack ships the minimum viable runtime tool contract.",
"",
"- Use `.paqad/project-profile.yaml` as the source of truth for project-specific commands.",
"- Use `docs/instructions/stack/*.md` for detected frameworks, traits, toolchains, and drift.",
"- Use `docs/instructions/rules/**` plus the stack pack rules for implementation conventions.",
"",
"Add stack-specific tool guides here when the runtime grows beyond the baseline contract."
].join("\n")
};
}
// src/onboarding/rule-generator.ts
init_esm_shims();
import { readFile as readFile27 } from "fs/promises";
import { join as join63 } from "path";
async function generateProjectRules(rules) {
return Promise.all(
rules.map(async (rule) => ({
path: toProjectRulePath(rule.source),
content: await readFile27(rule.path, "utf8"),
autoUpdate: false
}))
);
}
function toProjectRulePath(source) {
const normalized = source.replaceAll("\\", "/");
if (normalized.startsWith("base/rules/")) {
return join63(PATHS.RULES_DIR, "_shared", normalized.replace(/^base\/rules\//, ""));
}
if (normalized.startsWith("capabilities/")) {
const capabilityNormalized = normalized.replace(/^capabilities\//, "");
const [prefix2, suffix2] = capabilityNormalized.split("/rules/");
if (prefix2 !== void 0 && suffix2 !== void 0) {
const target2 = suffix2.endsWith("/guide.md") ? suffix2.replace("/guide.md", ".md") : suffix2;
return join63(PATHS.RULES_DIR, prefix2, target2);
}
}
const [prefix, suffix] = normalized.split("/rules/");
if (prefix === void 0 || suffix === void 0) {
return join63(PATHS.RULES_DIR, normalized);
}
const target = suffix.endsWith("/guide.md") ? suffix.replace("/guide.md", ".md") : suffix;
return join63(PATHS.RULES_DIR, prefix, target);
}
// src/onboarding/orchestrator.ts
var OnboardingOrchestrator = class {
async run(options) {
if (options.workspacePolicy?.project_creation_disabled === true) {
throw new FrameworkError(
"Project creation is disabled by workspace policy; onboarding will not run.",
{ code: "PROJECT_CREATION_DISABLED" }
);
}
const firstOnboarding = readExistingOnboardingManifest(options.projectRoot) === null;
await checkAndMigrateSchema(options.projectRoot, VERSION);
runPendingEvidenceMigration(options.projectRoot);
const detector = new Detector();
const detection = await detector.detect(options.projectRoot);
const introspector = new StackIntrospector();
const previousSnapshot = await new StackSnapshotCache().read(options.projectRoot);
const liveSnapshot = await introspector.snapshot(options.projectRoot);
const selections = await resolveSelections(detection, liveSnapshot, options.selections, {
interactive: options.interactive
});
const runtimeRoot = options.runtimeRoot ?? getRuntimeRoot();
const resolver = new Resolver({ runtimeRoot });
const resolved = await resolver.resolve(selections);
const adapters = options.adapters ?? selections.providers ?? ["claude-code"];
const existingProfile = readProjectProfile(options.projectRoot);
const profile = buildProjectProfile(
selections,
liveSnapshot,
mergeProfileOverrides(existingProfile, options.profileOverrides),
options.projectRoot
);
profile.intelligence = applyRagSelection(profile.intelligence, void 0);
const validator = new SchemaValidator();
const validation = validator.validate("project-profile", profile);
const modules = await discoverModules(options.projectRoot);
if (!validation.valid) {
throw new Error(validation.errors.map((error) => error.message).join("; "));
}
const generatedFiles = [];
const entryFilePaths = /* @__PURE__ */ new Set();
const entryStubs = [];
let recommendMcp = false;
for (const adapterType of adapters) {
const adapter = AdapterFactory.create(adapterType);
const configPath = adapter.getConfigPath();
entryFilePaths.add(configPath);
const configFiles = await adapter.generateConfig({
frameworkPath: PATHS.FRAMEWORK_PATH,
rulesPath: PATHS.RULES_DIR,
projectRoot: options.projectRoot
});
const entryFile = configFiles.find((file) => file.path === configPath);
if (entryFile) {
entryStubs.push({ path: configPath, content: entryFile.content });
}
generatedFiles.push(...configFiles);
if (adapter.capabilities.hooks) {
generatedFiles.push(...await adapter.installHooks(resolved.hooks));
}
recommendMcp ||= adapter.capabilities.mcp;
if (adapter.capabilities.caching) {
generatedFiles.push(...await adapter.configureCaching(profile));
}
if (adapter.capabilities.memory) {
generatedFiles.push(...await adapter.configureMemory(profile));
}
}
if (recommendMcp) {
generatedFiles.push({ ...new McpConfigManager().generate(profile), autoUpdate: true });
}
generatedFiles.push(...await generateProjectRules(resolved.rules));
generatedFiles.push(...generateGitWorkflowFiles(selections.domain, options.projectRoot));
generatedFiles.push(
...await generateReferenceGuides(runtimeRoot, {
domain: selections.domain,
stack_profile: selections.stack_profile
})
);
const completed = new Set(readOnboardingCheckpoint(options.projectRoot) ?? []);
const filesToWrite = generatedFiles.map(
(file) => !options.forceOverwrite && entryFilePaths.has(file.path) ? { ...file, autoUpdate: false } : file
).filter((file) => !completed.has(toPosixPath(file.path)));
const onboardingWarnings = [];
const unmapped = unmappedCommands(profile.commands);
if (unmapped.length > 0) {
onboardingWarnings.push(
`Commands left unmapped in .paqad/project-profile.yaml (no matching script found): ${unmapped.join(", ")}. Add them there if the project has them.`
);
}
let deliveryMoveBlocked = false;
if (selections.domain === "coding") {
const deliveryMove = migrateDeliveryPolicy(options.projectRoot);
onboardingWarnings.push(...deliveryMove.lines);
deliveryMoveBlocked = deliveryMove.blocked === true;
}
const teamConfigMigration = migrateTeamConfig(options.projectRoot);
if (teamConfigMigration.ran) onboardingWarnings.push(...teamConfigMigration.lines);
let revertedFrameworkValues;
let writeResult;
let drift;
try {
const gitWorkflowPrefix = `${PATHS.GIT_WORKFLOW_DIR}/`;
writeResult = writeGeneratedFiles(
options.projectRoot,
deliveryMoveBlocked ? filesToWrite.filter((file) => !toPosixPath(file.path).startsWith(gitWorkflowPrefix)) : filesToWrite,
{ forceOverwrite: options.forceOverwrite }
);
if (!options.forceOverwrite && isFrameworkEnabled(profile)) {
writeResult.written.push(...wireEntryStubs(options.projectRoot, entryStubs).wired);
}
writeOnboardingCheckpoint(options.projectRoot, [...completed, ...writeResult.written]);
if (selections.domain === "coding") {
settleGitWorkflow(options.projectRoot, writeResult.written, !deliveryMoveBlocked);
}
drift = await writeStackArtifacts(
options.projectRoot,
{ ...liveSnapshot, profile: profile.stack_profile ?? liveSnapshot.profile },
previousSnapshot,
{ writeHumanDocs: false }
);
revertedFrameworkValues = detectFlippedFrameworkValues(options.projectRoot);
writeProjectProfile(options.projectRoot, profile);
syncTeamConfigFiles(options.projectRoot, onboardingWarnings);
writeConfigsReadme(options.projectRoot);
writeConfigExample(options.projectRoot);
if (options.profileOverrides) {
writeFrameworkOverridesToConfig(options.projectRoot, options.profileOverrides);
}
for (const file of reconcileConfigOverrides(options.projectRoot)) {
onboardingWarnings.push(
`Pruned obsolete config key(s) from ${file.path}: ${file.removed.join(", ")}.`
);
}
for (const collision of readConfigsDir(options.projectRoot).collisions) {
onboardingWarnings.push(
`Config key "${collision.key}" is set in multiple .paqad/configs/ files; the last filename wins \u2014 keep it in one file.`
);
}
if (adapters.includes("claude-code")) {
onboardingWarnings.push(
...new ClaudeCodeAdapter().syncTeamSetup(options.projectRoot).notes
);
}
writeGitignore(options.projectRoot);
writeCodexRecipes(options.projectRoot);
writeWorktreeInclude(options.projectRoot);
onboardingWarnings.push(...installGitHooks(options.projectRoot).problems ?? []);
writeDetectionReport(options.projectRoot, detection);
writeFrameworkMetadata(options.projectRoot, VERSION);
} catch (error) {
throw translateDiskFullError(error);
}
cleanupLegacyMcpFiles(options.projectRoot);
onboardingWarnings.push(...bootstrapFramework(options.projectRoot).warnings ?? []);
try {
const codeIndex = await buildCodeKnowledgeIndex(options.projectRoot);
if (validateCodeKnowledgeIndex(codeIndex).valid) {
writeCodeKnowledgeIndex(options.projectRoot, codeIndex);
}
} catch {
}
new DecisionStore(options.projectRoot).initialize();
for (const migration of migrateLegacyDecisionIds(options.projectRoot)) {
onboardingWarnings.push(
`Migrated legacy decision id ${migration.from} \u2192 ${migration.to} in ${migration.dir}.`
);
}
removeObsoleteContractDocs(options.projectRoot);
onboardingWarnings.push(...removeObsoleteWorkflowRules(options.projectRoot));
try {
if (isRuleScriptMapStale(options.projectRoot)) {
compileRuleScripts(options.projectRoot);
}
} catch (error) {
onboardingWarnings.push(
`Rule-script map compilation failed during onboarding: ${error instanceof Error ? error.message : "unknown error"}.`
);
}
let compiledRulesPath = join64(options.projectRoot, PATHS.COMPILED_RULES);
try {
if (await isCompiledRulesStale(options.projectRoot)) {
const compiledRules = await compileRules(options.projectRoot);
compiledRulesPath = await writeCompiledRules(options.projectRoot, compiledRules);
}
} catch (error) {
onboardingWarnings.push(
`Planning rule compilation failed during onboarding: ${error instanceof Error ? error.message : "unknown error"}.`
);
}
try {
await writeRuleContext(options.projectRoot);
} catch (error) {
onboardingWarnings.push(
`Rule context generation failed during onboarding: ${error instanceof Error ? error.message : "unknown error"}.`
);
}
const manifestPath = writeOnboardingManifest(options.projectRoot, {
adapter: adapters[0],
providers: adapters,
project_root: toPosixPath(options.projectRoot),
profile,
detected: detection,
repository: detection.repository,
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
generated_artifacts: generatedFiles.map((file) => ({
path: toPosixPath(file.path),
auto_update: file.autoUpdate,
executable: file.executable
})),
planning_artifacts: {
compiled_rules_path: toPosixPath(compiledRulesPath),
module_health_initialized: []
}
});
deleteOnboardingCheckpoint(options.projectRoot);
if (firstOnboarding) {
appendPlanningAudit(options.projectRoot, "INFO", "project.onboarded", {
project_id: profile.project.id,
wizard_version: VERSION,
steps_completed: writeResult.written.length
});
}
const phase1Output = {
adapter: adapters[0],
decision_pause_supported_adapters: adapters,
generated_files: writeResult.written.map(toPosixPath),
detected_modules: modules,
runtime_root: toPosixPath(runtimeRoot),
manifest_path: toPosixPath(manifestPath),
warnings: [...onboardingWarnings],
kept_files: writeResult.skipped,
drift_review_targets: drift.review_targets,
reverted_framework_values: revertedFrameworkValues
};
options.onPhase1Complete?.(phase1Output);
const ragSelection = await resolveRagSelection(selections.domain, options.selections?.rag, {
interactive: options.interactive
});
if (ragSelection) {
profile.intelligence = applyRagSelection(profile.intelligence, ragSelection);
writeProjectProfile(options.projectRoot, profile);
persistRagConfig(options.projectRoot, profile.intelligence);
}
if (ragSelection?.enabled && ragSelection.provider) {
if (ragEngineInstallingInBackground(options.projectRoot, ragSelection)) {
onboardingWarnings.push(RAG_ENGINE_INSTALLING_LINE);
} else {
try {
await enableRagDuringOnboarding(options.projectRoot, ragSelection);
} catch (error) {
profile.intelligence = applyRagSelection(profile.intelligence, { enabled: false });
writeProjectProfile(options.projectRoot, profile);
setTeamConfigValue(options.projectRoot, "rag_enabled", "false");
onboardingWarnings.push(
`RAG was turned off: ${error instanceof Error ? error.message : "unknown error"}`
);
}
}
}
return {
...phase1Output,
warnings: [...onboardingWarnings]
};
}
async preview(options) {
this.assertReadableDirectory(options.projectRoot);
const { files, warnings } = await this.collectGeneratedFiles(options);
const entries = planGeneratedFiles(options.projectRoot, files);
return { entries, warnings };
}
assertReadableDirectory(projectRoot) {
let isDirectory2;
try {
accessSync(projectRoot, fsConstants.R_OK);
isDirectory2 = statSync5(projectRoot).isDirectory();
} catch (error) {
throw new ValidationError(`Onboarding preview cannot read project path: ${projectRoot}`, {
projectRoot,
reason: error instanceof Error ? error.message : "unreadable path"
});
}
if (!isDirectory2) {
throw new ValidationError(
`Onboarding preview requires a directory, but path is not one: ${projectRoot}`,
{ projectRoot }
);
}
}
async collectGeneratedFiles(options) {
const warnings = [];
const detector = new Detector();
const detection = await detector.detect(options.projectRoot, { persist: false });
const introspector = new StackIntrospector();
const liveSnapshot = await introspector.snapshot(options.projectRoot, { persist: false });
const selections = await resolveSelections(detection, liveSnapshot, options.selections, {
interactive: options.interactive
});
const runtimeRoot = options.runtimeRoot ?? getRuntimeRoot();
const resolver = new Resolver({ runtimeRoot });
const resolved = await resolver.resolve(selections);
const adapters = options.adapters ?? selections.providers ?? ["claude-code"];
const profile = buildProjectProfile(
selections,
liveSnapshot,
options.profileOverrides,
options.projectRoot
);
profile.intelligence = applyRagSelection(profile.intelligence, void 0);
const validator = new SchemaValidator();
const validation = validator.validate("project-profile", profile);
if (!validation.valid) {
throw new ValidationError(validation.errors.map((error) => error.message).join("; "), {
projectRoot: options.projectRoot
});
}
const files = [];
let recommendMcp = false;
for (const adapterType of adapters) {
const adapter = AdapterFactory.create(adapterType);
files.push(
...await adapter.generateConfig({
frameworkPath: PATHS.FRAMEWORK_PATH,
rulesPath: PATHS.RULES_DIR,
projectRoot: options.projectRoot
})
);
if (adapter.capabilities.hooks) {
files.push(...await adapter.installHooks(resolved.hooks));
}
recommendMcp ||= adapter.capabilities.mcp;
if (adapter.capabilities.caching) {
files.push(...await adapter.configureCaching(profile));
}
if (adapter.capabilities.memory) {
files.push(...await adapter.configureMemory(profile));
}
}
if (recommendMcp) {
files.push({ ...new McpConfigManager().generate(profile), autoUpdate: true });
}
files.push(...await generateProjectRules(resolved.rules));
files.push(
...await generateReferenceGuides(runtimeRoot, {
domain: selections.domain,
stack_profile: selections.stack_profile
})
);
return { files, warnings };
}
};
function translateDiskFullError(error) {
if (error?.code === "ENOSPC") {
return new FrameworkError("Not enough disk space \u2014 free up space and retry.", {
code: "DISK_FULL",
cause: error,
retryable: true
});
}
return error;
}
function mergeProfileOverrides(existing, explicit) {
if (!existing && !explicit) {
return void 0;
}
return { ...existing ?? {}, ...explicit ?? {} };
}
function persistRagConfig(projectRoot, intelligence) {
setTeamConfigValue(projectRoot, "rag_enabled", String(intelligence.rag_enabled));
if (intelligence.embedding_provider) {
setTeamConfigValue(projectRoot, "rag_embedding_provider", intelligence.embedding_provider);
}
if (intelligence.embedding_model) {
setTeamConfigValue(projectRoot, "rag_embedding_model", intelligence.embedding_model);
}
}
function buildProjectProfile(selections, snapshot, overrides, projectRoot) {
const stackProfile = selections.stack_profile ?? snapshot.profile;
const defaultCommands = buildDefaultCommands(stackProfile, projectRoot);
const derivedTesting = selections.domain === "coding" ? deriveTestingForProfile({
stackProfile,
commands: defaultCommands,
projectRoot,
now: (/* @__PURE__ */ new Date()).toISOString()
}) : { commands: defaultCommands, testing: void 0 };
return {
project: {
name: overrides?.project?.name ?? "paqad project",
id: overrides?.project?.id ?? "paqad-project",
description: overrides?.project?.description ?? "Generated by paqad-ai"
},
active_capabilities: deriveActiveCapabilities2(selections.domain, stackProfile),
stack_profile: selections.domain === "coding" ? stackProfile : void 0,
commands: overrides?.commands ?? derivedTesting.commands,
...overrides?.testing ? { testing: overrides.testing } : derivedTesting.testing && !overrides?.commands ? { testing: derivedTesting.testing } : {},
compliance_packs: overrides?.compliance_packs ?? [],
features: overrides?.features ?? {
spec_only_mode: false,
market_research: false,
design_research: false,
team_agents: true,
analytics_instrumentation: false,
site_map: false,
lean_rules: true,
feature_report: true,
metrics_enabled: true,
visual_evidence: false,
checks_parallel: true,
checks_max_processes: 0
},
enterprise: overrides?.enterprise ?? {
enabled: false,
evidence_ledger: false,
ai_bom: false,
compliance_citations: false
},
paqad: overrides?.paqad ?? { enabled: true },
mcp: overrides?.mcp ?? { servers: [] },
model_routing: overrides?.model_routing ?? {
default_model: "gpt-5",
reasoning_model: "gpt-5",
fast_model: "gpt-5-mini"
},
intelligence: overrides?.intelligence ?? defaultIntelligenceConfig(),
efficiency: overrides?.efficiency ?? DEFAULT_FRAMEWORK_CONFIG.efficiency,
custom: overrides?.custom ?? {
classification_dimensions: [],
verification_plugins: [],
escalation_rules: [],
decisions: {
ask_threshold: "strict"
}
}
};
}
function buildDefaultCommands(stackProfile, projectRoot) {
const stack = getPrimaryStack({
active_capabilities: ["content", "coding", "security"],
stack_profile: stackProfile
});
const usingCompose = stackProfile.traits.includes("compose");
if (stack === "laravel") {
const testTool = resolveLaravelTestTool(stackProfile.traits);
const usingSail = stackProfile.traits.includes("sail");
return applyStructuredTestCommandPreference(
{
install: usingSail ? "vendor/bin/sail composer install" : usingCompose ? "docker compose exec <php-service> composer install" : "composer install",
dev: usingSail ? "vendor/bin/sail up -d" : usingCompose ? "docker compose up -d" : "php artisan serve",
test: testTool.command,
test_single: testTool.single,
lint: usingSail ? "vendor/bin/sail php ./vendor/bin/pint" : usingCompose ? "docker compose exec <php-service> ./vendor/bin/pint" : "./vendor/bin/pint",
format: usingSail ? "vendor/bin/sail php ./vendor/bin/pint" : usingCompose ? "docker compose exec <php-service> ./vendor/bin/pint" : "./vendor/bin/pint",
migrate: usingSail ? "vendor/bin/sail artisan migrate" : usingCompose ? "docker compose exec <php-service> php artisan migrate" : "php artisan migrate",
build: usingSail ? "vendor/bin/sail npm run build" : usingCompose ? "docker compose exec <node-service> pnpm build" : "pnpm build"
},
stackProfile,
projectRoot
);
}
if (stack === "flutter") {
return applyStructuredTestCommandPreference(
{
install: usingCompose ? "docker compose exec <flutter-service> flutter pub get" : "flutter pub get",
dev: usingCompose ? "docker compose up -d" : "flutter run",
test: usingCompose ? "docker compose exec <flutter-service> flutter test" : "flutter test",
test_single: usingCompose ? "docker compose exec <flutter-service> flutter test test/<path_or_file>.dart" : "flutter test test/<path_or_file>.dart",
lint: usingCompose ? "docker compose exec <flutter-service> flutter analyze" : "flutter analyze",
format: usingCompose ? "docker compose exec <flutter-service> dart format --set-exit-if-changed ." : "dart format --set-exit-if-changed .",
migrate: 'echo "configure migrate command"',
build: usingCompose ? "docker compose exec <flutter-service> flutter build <target>" : "flutter build <target>"
},
stackProfile,
projectRoot
);
}
if (stack === "react" || stack === "vue" || stack === "express" || stack === "node-cli" || stack === "node-library" || stack === "node-service" || stack === "angular" || stack === "svelte" || stack === "astro") {
return applyStructuredTestCommandPreference(
buildNodeCommands(usingCompose, projectRoot),
stackProfile,
projectRoot
);
}
if (stack === "django") {
return applyStructuredTestCommandPreference(
buildPythonCommands(usingCompose, {
dev: "python manage.py runserver",
migrate: "python manage.py migrate"
}),
stackProfile,
projectRoot
);
}
if (stack === "fastapi") {
return applyStructuredTestCommandPreference(
buildPythonCommands(usingCompose, {
dev: "uvicorn app.main:app --reload",
migrate: 'echo "configure migrate command"'
}),
stackProfile,
projectRoot
);
}
if (stack === "rails") {
return applyStructuredTestCommandPreference(
buildRubyCommands(usingCompose),
stackProfile,
projectRoot
);
}
if (stack === "spring-boot") {
return applyStructuredTestCommandPreference(
buildJvmCommands(stackProfile, usingCompose),
stackProfile,
projectRoot
);
}
if (stack === "go-web") {
return applyStructuredTestCommandPreference(
buildGoCommands(usingCompose),
stackProfile,
projectRoot
);
}
if (stack === "rust-web") {
return applyStructuredTestCommandPreference(
buildRustCommands(usingCompose),
stackProfile,
projectRoot
);
}
return applyStructuredTestCommandPreference(
buildNodeCommands(false, projectRoot),
stackProfile,
projectRoot
);
}
function buildNodeCommands(usingCompose, projectRoot) {
const manager = nodePackageManager(projectRoot);
const scripts = packageScripts(projectRoot);
const exec2 = (command) => usingCompose ? `docker compose exec <node-service> ${command}` : command;
const run2 = (name) => manager === "npm" && name !== "test" ? `npm run ${name}` : `${manager} ${name}`;
const has = (name) => scripts === null ? name !== "migrate" : scripts.has(name);
const mapped = (name) => has(name) ? exec2(run2(name)) : "";
const single = manager === "yarn" ? "yarn test <pattern>" : `${manager} test -- <pattern>`;
return {
install: exec2(`${manager} install`),
dev: usingCompose ? "docker compose up -d" : mapped("dev"),
test: mapped("test"),
test_single: has("test") ? exec2(single) : "",
lint: mapped("lint"),
format: mapped("format"),
migrate: mapped("migrate"),
build: mapped("build")
};
}
function packageScripts(projectRoot) {
const manifestPath = join64(projectRoot, "package.json");
if (!existsSync26(manifestPath)) return null;
try {
const manifest = JSON.parse(readFileSync33(manifestPath, "utf8"));
const scripts = manifest.scripts;
return typeof scripts === "object" && scripts !== null && !Array.isArray(scripts) ? new Set(Object.keys(scripts)) : /* @__PURE__ */ new Set();
} catch {
return null;
}
}
function unmappedCommands(commands) {
return Object.entries(commands).filter(([, command]) => command.trim().length === 0).map(([name]) => name);
}
function applyStructuredTestCommandPreference(commands, stackProfile, projectRoot) {
if (commands.test.trim().length === 0) {
return commands;
}
const runner = selectPreferredStructuredRunner(stackProfile, commands.test, projectRoot);
if (!runner) {
return commands;
}
return {
...commands,
test: buildStructuredTestCommand(commands.test, runner),
test_single: buildStructuredTestCommand(commands.test_single, runner)
};
}
function selectPreferredStructuredRunner(stackProfile, testCommand, projectRoot) {
return selectTestRunner(stackProfile, testCommand, projectRoot);
}
function buildStructuredTestCommand(baseCommand, runner) {
const structuredFlags = runner.structured_flags?.trim();
let command = structuredFlags ? appendRunnerFlags(baseCommand, structuredFlags) : baseCommand;
const outputDir = runner.output_source === "file" && runner.output_path_pattern ? resolveStructuredOutputDirectory(runner.output_path_pattern) : null;
if (outputDir && outputDir !== "." && outputDir !== "") {
command = `mkdir -p ${outputDir} && ${command}`;
}
return command;
}
function resolveStructuredOutputDirectory(outputPathPattern) {
if (/[*?[{\]]/u.test(outputPathPattern)) {
return null;
}
const outputDir = dirname24(outputPathPattern);
return outputDir === "." || outputDir === "" ? null : outputDir;
}
function appendRunnerFlags(baseCommand, structuredFlags) {
const pnpmSeparator = /(\bpnpm\s+test)\s+--(?=\s|$)/u;
if (pnpmSeparator.test(baseCommand)) {
return `${baseCommand.replace(pnpmSeparator, "$1")} ${structuredFlags}`;
}
const separator = /\b(?:npm|yarn)\s+test$/u.test(baseCommand) ? " --" : "";
return `${baseCommand}${separator} ${structuredFlags}`;
}
function deriveActiveCapabilities2(domain, stackProfile) {
const codingFrameworks = stackProfile?.frameworks.filter((framework) => framework !== "short-video") ?? [];
if (domain === "coding" || codingFrameworks.length > 0) {
return ["content", "coding", "security"];
}
return ["content"];
}
function resolveLaravelTestTool(traits) {
if (traits.includes("sail")) {
return {
command: "vendor/bin/sail test",
single: 'vendor/bin/sail test --filter="<pattern>"'
};
}
if (traits.includes("compose")) {
return {
command: "docker compose exec <php-service> php artisan test",
single: 'docker compose exec <php-service> php artisan test --filter="<pattern>"'
};
}
return {
command: "php artisan test",
single: 'php artisan test --filter="<pattern>"'
};
}
function buildPythonCommands(usingCompose, input) {
const exec2 = (command) => usingCompose ? `docker compose exec <python-service> ${command}` : command;
return {
install: exec2("pip install -r requirements.txt"),
dev: usingCompose ? "docker compose up -d" : input.dev,
test: exec2("pytest"),
test_single: exec2('pytest -k "<pattern>"'),
lint: exec2("ruff check ."),
format: exec2("ruff format ."),
migrate: exec2(input.migrate),
build: exec2("python -m compileall .")
};
}
function buildRubyCommands(usingCompose) {
const exec2 = (command) => usingCompose ? `docker compose exec <ruby-service> ${command}` : command;
return {
install: exec2("bundle install"),
dev: usingCompose ? "docker compose up -d" : "bin/dev",
test: exec2("bundle exec rspec"),
test_single: exec2("bundle exec rspec <path_or_file>"),
lint: exec2("bundle exec rubocop"),
format: exec2("bundle exec rubocop -A"),
migrate: exec2("bin/rails db:migrate"),
build: exec2("bin/rails assets:precompile")
};
}
function buildJvmCommands(stackProfile, usingCompose) {
const packageManager = stackProfile.toolchains.find((toolchain) => toolchain.ecosystem === "jvm")?.package_manager ?? "gradle";
const exec2 = (command) => usingCompose ? `docker compose exec <jvm-service> ${command}` : command;
if (packageManager === "maven") {
return {
install: exec2("./mvnw dependency:resolve"),
dev: usingCompose ? "docker compose up -d" : "./mvnw spring-boot:run",
test: exec2("./mvnw test"),
test_single: exec2("./mvnw -Dtest=<pattern> test"),
lint: exec2("./mvnw verify"),
format: exec2("./mvnw spotless:apply"),
migrate: 'echo "configure migrate command"',
build: exec2("./mvnw package")
};
}
return {
install: exec2("./gradlew dependencies"),
dev: usingCompose ? "docker compose up -d" : "./gradlew bootRun",
test: exec2("./gradlew test"),
test_single: exec2('./gradlew test --tests "*<pattern>*"'),
lint: exec2("./gradlew check"),
format: exec2("./gradlew spotlessApply"),
migrate: 'echo "configure migrate command"',
build: exec2("./gradlew build")
};
}
function buildGoCommands(usingCompose) {
const exec2 = (command) => usingCompose ? `docker compose exec <go-service> ${command}` : command;
return {
install: exec2("go mod download"),
dev: usingCompose ? "docker compose up -d" : "go run ./...",
test: exec2("go test ./..."),
test_single: exec2('go test ./... -run "<pattern>"'),
lint: exec2("go vet ./..."),
format: exec2("gofmt -w ."),
migrate: 'echo "configure migrate command"',
build: exec2("go build ./...")
};
}
function buildRustCommands(usingCompose) {
const exec2 = (command) => usingCompose ? `docker compose exec <rust-service> ${command}` : command;
return {
install: exec2("cargo fetch"),
dev: usingCompose ? "docker compose up -d" : "cargo run",
test: exec2("cargo test"),
test_single: exec2('cargo test "<pattern>"'),
lint: exec2("cargo clippy --all-targets --all-features -- -D warnings"),
format: exec2("cargo fmt --check"),
migrate: 'echo "configure migrate command"',
build: exec2("cargo build")
};
}
function settleGitWorkflow(projectRoot, written, createMissing) {
syncGitWorkflow(projectRoot, { createMissing });
const fresh = GIT_WORKFLOW_FILES.filter(
(file) => written.some((path10) => toPosixPath(path10) === `${PATHS.GIT_WORKFLOW_DIR}/${file}`)
);
if (fresh.length > 0) stampLastApplied(projectRoot, fresh);
}
// src/onboarding/scaffold-generator.ts
init_esm_shims();
import { join as join65 } from "path";
// src/templates/index.ts
init_esm_shims();
// src/templates/context-builders/agent-config.ts
init_esm_shims();
function buildAgentConfigContext(input) {
return input;
}
// src/templates/context-builders/api-doc.ts
init_esm_shims();
function buildApiDocContext(moduleName) {
return { moduleName };
}
// src/templates/context-builders/design-system.ts
init_esm_shims();
function buildDesignSystemContext(projectName) {
return { projectName };
}
// src/templates/context-builders/error-catalog.ts
init_esm_shims();
function buildErrorCatalogContext(moduleName) {
return { moduleName };
}
// src/templates/context-builders/integration-doc.ts
init_esm_shims();
function buildIntegrationDocContext(moduleName) {
return { moduleName };
}
// src/templates/context-builders/module-scaffold.ts
init_esm_shims();
function buildModuleScaffoldContext(moduleName) {
return {
moduleName,
title: moduleName.replace(/-/g, " ")
};
}
// src/templates/context-builders/registry-files.ts
init_esm_shims();
function buildRegistryContext(name) {
return { name };
}
// src/templates/context-builders/runner-scripts.ts
init_esm_shims();
function buildRunnerScriptContext(input) {
const stack = input.stack ?? input.routing?.stack ?? "unknown";
return {
...input,
routing: {
stack
}
};
}
// src/templates/registry.ts
init_esm_shims();
var import_fast_glob13 = __toESM(require_out(), 1);
var TemplateRegistry = class {
constructor(templatesRoot) {
this.templatesRoot = templatesRoot;
}
templatesRoot;
async discover() {
const files = await (0, import_fast_glob13.default)("**/*.hbs", {
cwd: this.templatesRoot,
absolute: true,
onlyFiles: true
});
return files.sort().map((path10) => ({
name: basename(path10),
path: path10,
relativePath: relative(this.templatesRoot, path10)
}));
}
};
// src/onboarding/scaffold-generator.ts
var FEATURE_TEMPLATE_TARGETS = [
["business.md.hbs", toPosixPath(join65(PATHS.MODULE_FEATURES_DIR, "core", "business.md"))],
["technical.md.hbs", toPosixPath(join65(PATHS.MODULE_FEATURES_DIR, "core", "technical.md"))]
];
var MODULE_TEMPLATE_TARGETS = [
["summary.md.hbs", "index/summary.md"],
["schema.md.hbs", "database/schema.md"],
["indexes.md.hbs", "database/indexes.md"],
["queries.md.hbs", "database/queries.md"],
["data-volumes.md.hbs", "database/data-volumes.md"],
["api-endpoints.md.hbs", "api/endpoints.md"],
["api-schemas.md.hbs", "api/schemas.md"],
["api-error-codes.md.hbs", "api/error-codes.md"],
["integration-events.md.hbs", "integration/events.md"],
["integration-contracts.md.hbs", "integration/contracts.md"],
["error-catalog.md.hbs", "error-catalog.md"],
["screens.md.hbs", "ui/screens.md"],
["components.md.hbs", "ui/components.md"],
["states.md.hbs", "ui/states.md"]
];
async function generateDocumentationScaffold(moduleNames = ["core"]) {
const files = [];
for (const moduleName of Array.from(new Set(moduleNames)).sort()) {
files.push(...await generateModuleScaffold(moduleName));
}
return files;
}
async function generateModuleScaffold(moduleName) {
const engine = new TemplateEngine();
const context = buildModuleScaffoldContext(moduleName);
const files = [];
for (const [templateName, relativeTarget] of FEATURE_TEMPLATE_TARGETS) {
files.push({
path: toPosixPath(join65(PATHS.MODULES_DIR, moduleName, relativeTarget)),
content: await engine.render(
join65(getRuntimeTemplatesRoot(), "module-scaffold", templateName),
context
),
autoUpdate: false
});
}
for (const [templateName, relativeTarget] of MODULE_TEMPLATE_TARGETS) {
files.push({
path: toPosixPath(join65(PATHS.MODULES_DIR, moduleName, relativeTarget)),
content: await engine.render(
join65(getRuntimeTemplatesRoot(), "module-scaffold", templateName),
context
),
autoUpdate: false
});
}
return files;
}
// src/packs/index.ts
init_esm_shims();
// src/pentest/index.ts
init_esm_shims();
// src/pentest/osv.ts
init_esm_shims();
function toOsvEcosystem(ecosystem) {
if (ecosystem === "node") {
return "npm";
}
if (ecosystem === "php") {
return "Packagist";
}
if (ecosystem === "dart") {
return "Pub";
}
return null;
}
async function queryOsv(packages) {
const queries = packages.map((pkg) => ({
pkg,
ecosystem: toOsvEcosystem(pkg.ecosystem)
})).filter(
(entry) => entry.ecosystem !== null
).map((entry) => ({
package: {
name: entry.pkg.name,
ecosystem: entry.ecosystem
},
version: entry.pkg.locked_version
}));
if (queries.length === 0) {
return [];
}
try {
const response = await fetch("https://api.osv.dev/v1/querybatch", {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify({ queries }),
signal: AbortSignal.timeout(5e3)
});
if (!response.ok) {
return [];
}
const payload = await response.json();
return (payload.results ?? []).flatMap(
(result2, index) => (result2.vulns ?? []).map((vuln) => ({
package_name: queries[index]?.package.name ?? "unknown",
ecosystem: queries[index]?.package.ecosystem ?? "unknown",
version: queries[index]?.version ?? "unknown",
advisory_id: vuln.id ?? "unknown",
summary: vuln.summary ?? "OSV advisory",
details: vuln.details ?? ""
}))
);
} catch {
return [];
}
}
// src/pentest/progress-tracker.ts
init_esm_shims();
import { existsSync as existsSync28 } from "fs";
import { mkdir as mkdir22, readdir as readdir6, readFile as readFile29, writeFile as writeFile23 } from "fs/promises";
import { dirname as dirname26, join as join67 } from "path";
// src/pentest/shared.ts
init_esm_shims();
import { createHash as createHash9 } from "crypto";
import { existsSync as existsSync27 } from "fs";
import { mkdir as mkdir21, readFile as readFile28, readdir as readdir5, writeFile as writeFile22 } from "fs/promises";
import { basename as basename7, dirname as dirname25, join as join66, relative as relative12 } from "path";
var import_fast_glob14 = __toESM(require_out(), 1);
function toLocalTimestamp(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`;
}
function slugify2(value) {
return slugifyAscii(value);
}
async function writeJson(target, data) {
await mkdir21(dirname25(target), { recursive: true });
await writeFile22(target, `${JSON.stringify(data, null, 2)}
`);
}
async function readJsonIfExists(target) {
if (!existsSync27(target)) {
return null;
}
return JSON.parse(await readFile28(target, "utf8"));
}
async function hashRelevantInputs(projectRoot, workflow, extra = {}) {
const files = (await (0, import_fast_glob14.default)(
[
"docs/modules/**/*.md",
"tests/**/*",
"src/**/*",
"app/**/*",
"routes/**/*",
"package.json",
"pnpm-lock.yaml",
"package-lock.json",
"composer.json",
"composer.lock",
"pubspec.yaml",
"pubspec.lock",
".env",
".env.local",
".env.example"
],
{
cwd: projectRoot,
onlyFiles: true,
absolute: true,
dot: true
}
)).sort();
const hash = createHash9("sha256");
hash.update(workflow);
for (const file of files) {
hash.update(relative12(projectRoot, file));
hash.update(await readFile28(file));
}
hash.update(JSON.stringify(extra));
return hash.digest("hex");
}
async function discoverTargetUrl(projectRoot, stack, explicit) {
if (explicit) {
return explicit;
}
const envFiles = [".env", ".env.local", ".env.example"];
for (const envFile of envFiles) {
const path10 = join66(projectRoot, envFile);
if (!existsSync27(path10)) {
continue;
}
const content = await readFile28(path10, "utf8");
const match = content.match(/(?:^|\n)\s*APP_URL\s*=\s*["']?([^\n"']+)["']?/i) ?? content.match(/(?:^|\n)\s*VITE_APP_URL\s*=\s*["']?([^\n"']+)["']?/i) ?? content.match(/(?:^|\n)\s*VITE_BASE_URL\s*=\s*["']?([^\n"']+)["']?/i);
if (match?.[1]) {
return match[1].trim();
}
}
if (stack === "laravel") {
return "http://127.0.0.1:8000";
}
if (stack === "react" || stack === "vue") {
return "http://127.0.0.1:3000";
}
if (stack === "flutter") {
return "http://127.0.0.1:8080";
}
return null;
}
async function runProjectScript(projectRoot, scriptName, env2, logDir) {
const scriptPath = join66(projectRoot, PATHS.SCRIPTS_DIR, scriptName);
const stdoutPath = join66(logDir, `${scriptName}.stdout.log`);
const stderrPath = join66(logDir, `${scriptName}.stderr.log`);
await mkdir21(logDir, { recursive: true });
if (!existsSync27(scriptPath)) {
await writeFile22(stdoutPath, "");
await writeFile22(
stderrPath,
`Missing script: ${toPosixPath(relative12(projectRoot, scriptPath))}
`
);
return {
script: scriptName,
status: "blocked",
artifact_paths: [
toPosixPath(relative12(projectRoot, stdoutPath)),
toPosixPath(relative12(projectRoot, stderrPath))
],
exit_code: null,
summary: `Missing project script ${scriptName}`
};
}
const result2 = await execa(scriptPath, {
cwd: projectRoot,
env: env2,
reject: false
});
await writeFile22(stdoutPath, result2.stdout);
await writeFile22(stderrPath, result2.stderr);
return {
script: scriptName,
status: result2.exitCode === 0 ? "completed" : "failed",
artifact_paths: [
toPosixPath(relative12(projectRoot, stdoutPath)),
toPosixPath(relative12(projectRoot, stderrPath))
],
exit_code: result2.exitCode ?? null,
summary: result2.exitCode === 0 ? `${scriptName} completed` : `${scriptName} failed with exit code ${result2.exitCode}`
};
}
async function loadModuleDocs(projectRoot, focusModules = []) {
const moduleRoot = join66(projectRoot, PATHS.MODULES_DIR);
if (!existsSync27(moduleRoot)) {
return [];
}
const dirs = (await readdir5(moduleRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((moduleName) => focusModules.length === 0 || focusModules.includes(moduleName)).sort();
return Promise.all(
dirs.map(async (moduleName) => {
const paths = (await (0, import_fast_glob14.default)(
[
`${moduleName}/business.md`,
`${moduleName}/technical.md`,
`${moduleName}/features/*/business.md`,
`${moduleName}/features/*/technical.md`,
`${moduleName}/api/endpoints.md`,
`${moduleName}/api/schemas.md`,
`${moduleName}/integration/contracts.md`,
`${moduleName}/error-catalog.md`,
`${moduleName}/ui/states.md`
],
{
cwd: moduleRoot,
onlyFiles: true,
absolute: true
}
)).sort();
const content = (await Promise.all(paths.map((path10) => readFile28(path10, "utf8").catch(() => "")))).join("\n");
return {
module: moduleName,
paths: paths.map((path10) => toPosixPath(relative12(projectRoot, path10))),
content
};
})
);
}
async function loadTests(projectRoot, focusModules = []) {
const files = (await (0, import_fast_glob14.default)(["tests/**/*.{ts,tsx,js,jsx,php,dart}", "src/**/*.{test,spec}.{ts,tsx,js,jsx}"], {
cwd: projectRoot,
onlyFiles: true,
absolute: true
})).sort();
const loweredFocus = focusModules.map((moduleName) => moduleName.toLowerCase());
const filtered = focusModules.length ? files.filter(
(file) => loweredFocus.some((moduleName) => file.toLowerCase().includes(moduleName))
) : files;
return Promise.all(
filtered.map(async (path10) => ({
path: toPosixPath(relative12(projectRoot, path10)),
content: await readFile28(path10, "utf8").catch(() => "")
}))
);
}
function parseSuspiciousRoutes(runtimeChecks) {
return runtimeChecks.filter((entry) => entry.status > 0 && entry.status < 500).map((entry) => ({
path: entry.path,
status: entry.status,
kind: entry.path.includes("telescope") || entry.path.includes("debug") || entry.path.includes("clockwork") ? "debug-surface" : entry.path.includes(".env") ? "sensitive-file" : "public-admin-surface"
}));
}
function summarizeCommandAvailability(scriptResults) {
return scriptResults.filter((result2) => result2.status !== "completed").map((result2) => result2.summary);
}
function inferSourceArtifacts(baseDir, scriptResults) {
const artifacts = [];
for (const result2 of scriptResults) {
artifacts.push(...result2.artifact_paths);
}
return [
...new Set(
artifacts.map(
(artifact) => artifact.startsWith(".") ? artifact : toPosixPath(relative12(dirname25(baseDir), join66(dirname25(baseDir), artifact)))
)
)
];
}
var BASE_SKILLS = /* @__PURE__ */ new Set(["finding-normalizer"]);
function skillPath(name) {
const root = BASE_SKILLS.has(name) ? "runtime/base/skills" : "runtime/capabilities/security/skills";
return `${root}/${name}/SKILL.md`;
}
function toolReferencePath(stack) {
return `docs/instructions/tools/${stack}/security-review-checklist.md`;
}
function toReportId(prefix, date) {
return `${prefix}-${toLocalTimestamp(date)}`;
}
function extractRelevantTestPaths(tests, moduleName, keywords) {
const loweredModule = moduleName.toLowerCase();
return tests.filter((test) => {
const haystack = `${test.path}
${test.content}`.toLowerCase();
return haystack.includes(loweredModule) && keywords.some((keyword) => haystack.includes(keyword));
}).map((test) => test.path).slice(0, 5);
}
function parseSecretMatches(content) {
return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).slice(0, 20);
}
function safeBaseName(path10) {
return basename7(path10).replace(/[^a-zA-Z0-9._-]+/g, "-");
}
// src/pentest/progress-tracker.ts
var PentestProgressTracker = class {
constructor(validator = new SchemaValidator()) {
this.validator = validator;
}
validator;
async ensureRun(options) {
const existing = await this.findIncompleteRun(
options.projectRoot,
options.workflow,
options.sourceReportPath ?? null
);
if (existing !== null) {
const reset = this.resetRunningSteps(existing);
if (reset) {
await this.save(options.projectRoot, existing);
}
return existing;
}
const now = (/* @__PURE__ */ new Date()).toISOString();
return {
schema_version: "1",
generated_by: "paqad-ai",
framework_version: VERSION,
run_id: toLocalTimestamp(/* @__PURE__ */ new Date()),
workflow: options.workflow,
status: "running",
started_at: now,
updated_at: now,
report_path: null,
sidecar_path: null,
target_url: options.targetUrl ?? null,
source_report_path: options.sourceReportPath ?? null,
steps: options.steps.map((step) => ({
...step,
status: "not_started",
input_hash: null,
artifact_paths: [],
skill_names: [],
error: null,
started_at: null,
completed_at: null
})),
skill_invocations: [],
script_artifacts: [],
current_finding_ids: []
};
}
async load(projectRoot, runId) {
const target = join67(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "progress.json");
if (!existsSync28(target)) {
return null;
}
const parsed = JSON.parse(await readFile29(target, "utf8"));
const validation = this.validator.validate("pentest-progress", parsed);
if (!validation.valid) {
throw new Error(validation.errors.map((error) => error.message).join("; "));
}
return parsed;
}
async save(projectRoot, progress) {
const target = join67(projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "progress.json");
progress.updated_at = (/* @__PURE__ */ new Date()).toISOString();
await mkdir22(dirname26(target), { recursive: true });
await writeFile23(target, `${JSON.stringify(progress, null, 2)}
`);
}
markStepRunning(progress, stepId, inputHash) {
const step = this.findStep(progress, stepId);
step.status = "running";
step.input_hash = inputHash;
step.error = null;
step.started_at = (/* @__PURE__ */ new Date()).toISOString();
step.completed_at = null;
progress.status = "running";
}
markStepCompleted(progress, stepId, artifactPaths, skillNames) {
const step = this.findStep(progress, stepId);
step.status = "completed";
step.artifact_paths = [.../* @__PURE__ */ new Set([...step.artifact_paths, ...artifactPaths])];
step.skill_names = [.../* @__PURE__ */ new Set([...step.skill_names, ...skillNames])];
step.error = null;
step.completed_at = (/* @__PURE__ */ new Date()).toISOString();
progress.skill_invocations = [.../* @__PURE__ */ new Set([...progress.skill_invocations, ...skillNames])];
progress.script_artifacts = [.../* @__PURE__ */ new Set([...progress.script_artifacts, ...artifactPaths])];
}
markStepBlocked(progress, stepId, error, artifactPaths, skillNames) {
const step = this.findStep(progress, stepId);
step.status = "blocked";
step.error = error;
step.artifact_paths = [.../* @__PURE__ */ new Set([...step.artifact_paths, ...artifactPaths])];
step.skill_names = [.../* @__PURE__ */ new Set([...step.skill_names, ...skillNames])];
step.completed_at = (/* @__PURE__ */ new Date()).toISOString();
progress.status = "blocked";
progress.skill_invocations = [.../* @__PURE__ */ new Set([...progress.skill_invocations, ...skillNames])];
progress.script_artifacts = [.../* @__PURE__ */ new Set([...progress.script_artifacts, ...artifactPaths])];
}
markStepFailed(progress, stepId, error, artifactPaths, skillNames) {
const step = this.findStep(progress, stepId);
step.status = "failed";
step.error = error;
step.artifact_paths = [.../* @__PURE__ */ new Set([...step.artifact_paths, ...artifactPaths])];
step.skill_names = [.../* @__PURE__ */ new Set([...step.skill_names, ...skillNames])];
step.completed_at = (/* @__PURE__ */ new Date()).toISOString();
progress.status = "failed";
progress.skill_invocations = [.../* @__PURE__ */ new Set([...progress.skill_invocations, ...skillNames])];
progress.script_artifacts = [.../* @__PURE__ */ new Set([...progress.script_artifacts, ...artifactPaths])];
}
markRunCompleted(progress, reportPath2, sidecarPath, findingIds) {
progress.status = "completed";
progress.report_path = reportPath2;
progress.sidecar_path = sidecarPath;
progress.current_finding_ids = [...findingIds];
progress.updated_at = (/* @__PURE__ */ new Date()).toISOString();
}
shouldSkipStep(progress, stepId, inputHash) {
const step = this.findStep(progress, stepId);
return step.status === "completed" && step.input_hash === inputHash;
}
async findIncompleteRun(projectRoot, workflow, sourceReportPath) {
const runsDir = join67(projectRoot, PATHS.PENTEST_RUNS_DIR);
if (!existsSync28(runsDir)) {
return null;
}
const entries = (await readdir6(runsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
for (const runId of entries) {
const progress = await this.load(projectRoot, runId);
if (progress === null) {
continue;
}
const sameSource = progress.source_report_path === sourceReportPath || progress.source_report_path === null && sourceReportPath === null;
if (progress.workflow === workflow && progress.status !== "completed" && sameSource) {
return progress;
}
}
return null;
}
resetRunningSteps(progress) {
let changed = false;
for (const step of progress.steps) {
if (step.status !== "running") {
continue;
}
step.status = "not_started";
step.started_at = null;
step.completed_at = null;
step.error = null;
changed = true;
}
if (changed && progress.status === "running") {
progress.status = "blocked";
}
return changed;
}
findStep(progress, stepId) {
const step = progress.steps.find((candidate) => candidate.id === stepId);
if (!step) {
throw new Error(`Unknown pentest step: ${stepId}`);
}
return step;
}
};
function runArtifactsDir(projectRoot, runId) {
return join67(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "artifacts");
}
function runLogsDir(projectRoot, runId) {
return join67(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "logs");
}
function runStatusForSteps(steps) {
if (steps.some((step) => step.status === "failed")) {
return "failed";
}
if (steps.some((step) => step.status === "blocked")) {
return "blocked";
}
if (steps.every((step) => step.status === "completed")) {
return "completed";
}
return "running";
}
// src/pipeline/index.ts
init_esm_shims();
// src/pipeline/workflow-router.ts
init_esm_shims();
var import_fast_glob15 = __toESM(require_out(), 1);
import { readFile as readFile30 } from "fs/promises";
import { existsSync as existsSync29 } from "fs";
import { dirname as dirname27, join as join68, relative as relative13 } from "path";
var PROJECT_SKILL_ROOTS = [".codex/skills", ".claude/skills", ".gemini/skills", ".junie/skills"];
var WorkflowRouterService = class {
projectRoot;
runtimeRoot;
runtimeRegistry;
parser = new SkillFrontmatterParser();
constructor(options = {}) {
this.projectRoot = options.projectRoot ?? process.cwd();
this.runtimeRoot = options.runtimeRoot ?? getRuntimeRoot();
this.runtimeRegistry = options.runtimeRegistry;
}
async resolve(requestText, profile) {
const effectiveProfile = profile ?? readProjectProfile(this.projectRoot);
const runtimeSnapshot = this.runtimeRegistry?.snapshot() ?? [];
const [skills, customWorkflowNames] = await Promise.all([
this.loadRoutingSkills(effectiveProfile, runtimeSnapshot),
new WorkflowTemplateLoader(this.projectRoot).list()
]);
const normalizedRequest = normalizeText(requestText);
const requestTokens = tokenize(normalizedRequest);
const candidates = [];
for (const [precedence, skill] of skills.entries()) {
for (const rule of skill.request_routing ?? []) {
for (const pattern of rule.patterns) {
if (!matchesPattern(pattern, normalizedRequest, requestTokens)) {
continue;
}
candidates.push({
skill,
rule,
pattern,
specificity: normalizeText(pattern).length,
precedence
});
}
}
}
if (candidates.length === 0) {
return {
workflow: null,
custom_workflow_name: null,
workflow_source: "none",
workflow_reason: "No workflow routing rule matched the incoming request.",
matched_rule: null
};
}
candidates.sort((left, right) => {
if (left.rule.priority !== right.rule.priority) {
return right.rule.priority - left.rule.priority;
}
if (left.specificity !== right.specificity) {
return right.specificity - left.specificity;
}
return right.precedence - left.precedence;
});
const winner = candidates[0];
const target = winner.rule.target_workflow.trim();
const customWorkflowName = target.startsWith("custom:") ? target.slice("custom:".length) : null;
if (!customWorkflowName && !CLASSIFICATION_WORKFLOWS.includes(target)) {
throw new Error(`Workflow routing matched invalid workflow target "${target}"`);
}
if (customWorkflowName && !customWorkflowNames.includes(customWorkflowName)) {
throw new Error(
`Workflow routing matched custom template "${customWorkflowName}" but it does not exist`
);
}
return {
workflow: customWorkflowName ? "custom" : target,
custom_workflow_name: customWorkflowName,
workflow_source: "routing-skill",
workflow_reason: `Matched workflow-router rule "${winner.pattern}" from ${winner.skill.name}`,
matched_rule: winner.pattern
};
}
async loadRoutingSkills(profile, runtimeSnapshot = []) {
const routing = buildRoutingConfig(profile);
const resolver = new Resolver({ runtimeRoot: this.runtimeRoot });
const resolved = await resolver.resolve(routing);
const artifacts = [...resolved.skills, ...await this.projectSkillArtifacts()];
const skills = [];
for (const artifact of artifacts) {
const content = await readFile30(artifact.path, "utf8");
const folder = dirname27(artifact.path);
if (!skillDeclaresRequestRouting(content, folder)) {
continue;
}
const parsed = this.parser.parse(content, folder);
if (parsed.deprecation !== null) {
recordSkillMetadataDeprecation(
{
ts: (/* @__PURE__ */ new Date()).toISOString(),
type: "skill.metadata_deprecated",
path: artifact.path,
skill: parsed.frontmatter.name,
message: parsed.deprecation
},
this.projectRoot
);
}
if (!parsed.frontmatter.request_routing?.length) {
continue;
}
skills.push(toLoadedSkill(artifact.path, parsed, profile?.stack_profile?.frameworks ?? []));
}
for (const entry of runtimeSnapshot) {
if (entry.request_routing?.length) {
skills.push(entry);
}
}
return skills;
}
async projectSkillArtifacts() {
const artifacts = [];
for (const root of PROJECT_SKILL_ROOTS) {
const absoluteRoot = join68(this.projectRoot, root);
if (!existsSync29(absoluteRoot)) {
continue;
}
const files = await (0, import_fast_glob15.default)("**/SKILL.md", {
cwd: absoluteRoot,
absolute: true
});
for (const file of files.sort()) {
artifacts.push({
path: file,
level: 6,
source: relative13(this.projectRoot, file)
});
}
}
return artifacts;
}
};
function buildRoutingConfig(profile) {
if (!profile) {
return {
domain: "content",
active_capabilities: ["content"],
stack: "short-video"
};
}
return {
domain: profile.active_capabilities?.includes("coding") ? "coding" : "content",
active_capabilities: profile.active_capabilities,
stack_profile: profile.stack_profile,
stack: getPrimaryStack(profile),
capabilities: profile.stack_profile?.traits ?? []
};
}
function normalizeText(value) {
return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim().replace(/\s+/g, " ");
}
function tokenize(value) {
return value === "" ? [] : value.split(" ");
}
function matchesPattern(pattern, normalizedRequest, requestTokens) {
const normalizedPattern = normalizeText(pattern);
if (normalizedPattern === "") {
return false;
}
if (normalizedRequest.includes(normalizedPattern)) {
return true;
}
const patternTokens = tokenize(normalizedPattern);
if (patternTokens.length === 0 || requestTokens.length < patternTokens.length) {
return false;
}
for (let start = 0; start <= requestTokens.length - patternTokens.length; start += 1) {
let allMatch = true;
for (let offset = 0; offset < patternTokens.length; offset += 1) {
if (!tokensMatch(patternTokens[offset], requestTokens[start + offset])) {
allMatch = false;
break;
}
}
if (allMatch) {
return true;
}
}
return false;
}
function tokensMatch(patternToken, requestToken) {
if (patternToken === requestToken) {
return true;
}
if (patternToken.length < 6 || requestToken.length < 6) {
return false;
}
return editDistance2(patternToken, requestToken) <= 2;
}
function editDistance2(left, right) {
const matrix = Array.from(
{ length: left.length + 1 },
() => Array.from({ length: right.length + 1 }).fill(0)
);
for (let i = 0; i <= left.length; i += 1) {
matrix[i][0] = i;
}
for (let j = 0; j <= right.length; j += 1) {
matrix[0][j] = j;
}
for (let i = 1; i <= left.length; i += 1) {
for (let j = 1; j <= right.length; j += 1) {
const cost = left[i - 1] === right[j - 1] ? 0 : 1;
matrix[i][j] = Math.min(
matrix[i - 1][j] + 1,
matrix[i][j - 1] + 1,
matrix[i - 1][j - 1] + cost
);
}
}
return matrix[left.length][right.length];
}
// src/pipeline/stream-truncator.ts
init_esm_shims();
import { appendFile as appendFile2, mkdir as mkdir23 } from "fs/promises";
import { join as join69, dirname as dirname28 } from "path";
var TIER_TOKEN_LIMITS = {
fast: 2e3,
medium: 5e3,
reasoning: 15e3
};
var StreamTruncator = class {
constructor(projectRoot) {
this.projectRoot = projectRoot;
}
projectRoot;
truncate(output, tier, maxOutputTokensOverride) {
const limit = maxOutputTokensOverride ?? TIER_TOKEN_LIMITS[tier];
const originalTokens = this.estimateTokens(output);
if (originalTokens <= limit) {
return {
output,
truncated: false,
original_token_estimate: originalTokens,
final_token_estimate: originalTokens
};
}
const truncated = this.truncateAtSentenceBoundary(output, limit);
const finalTokens = this.estimateTokens(truncated);
return {
output: truncated + "\n\n[truncated]",
truncated: true,
original_token_estimate: originalTokens,
final_token_estimate: finalTokens
};
}
async logTruncation(skillName, result2) {
if (!result2.truncated) return;
try {
const auditPath2 = join69(this.projectRoot, ".paqad", "audit.log");
await mkdir23(dirname28(auditPath2), { recursive: true });
const entry = `[${(/* @__PURE__ */ new Date()).toISOString()}] WARN truncation skill=${skillName} original=${result2.original_token_estimate}t final=${result2.final_token_estimate}t
`;
await appendFile2(auditPath2, entry, "utf8");
} catch {
}
}
estimateTokens(text2) {
return Math.ceil(text2.length / 4);
}
truncateAtSentenceBoundary(text2, maxTokens) {
const maxChars = maxTokens * 4;
if (text2.length <= maxChars) return text2;
const candidate = text2.slice(0, maxChars);
const sentenceEnd = Math.max(
candidate.lastIndexOf(". "),
candidate.lastIndexOf(".\n"),
candidate.lastIndexOf("! "),
candidate.lastIndexOf("? ")
);
if (sentenceEnd > maxChars * 0.5) {
return text2.slice(0, sentenceEnd + 1);
}
const lastNewline = candidate.lastIndexOf("\n");
if (lastNewline > maxChars * 0.5) {
return text2.slice(0, lastNewline);
}
return candidate;
}
};
// src/resolver/index.ts
init_esm_shims();
// src/resolver/deduplicator.ts
init_esm_shims();
import { createHash as createHash10 } from "crypto";
import { readFile as readFile31, writeFile as writeFile24, mkdir as mkdir24 } from "fs/promises";
import { join as join70, dirname as dirname29 } from "path";
var ContextDeduplicator = class {
contentHashMap = /* @__PURE__ */ new Map();
async deduplicate(projectRoot, artifacts) {
const references = /* @__PURE__ */ new Map();
const result2 = [];
let deduplicated = 0;
let tokensSaved = 0;
for (const artifact of artifacts) {
const content = artifact.content ?? await this.readContent(artifact.path);
const hash = this.computeHash(content);
if (this.contentHashMap.has(hash)) {
const originalPath = this.contentHashMap.get(hash);
references.set(artifact.path, originalPath);
const saved = Math.ceil(content.length / 4);
tokensSaved += saved;
deduplicated++;
result2.push({
...artifact,
content: `[See: ${originalPath} already loaded above]`
});
} else {
this.contentHashMap.set(hash, artifact.path);
result2.push({ ...artifact, content });
}
}
const stats = {
total_artifacts: artifacts.length,
deduplicated,
tokens_saved_estimate: tokensSaved
};
await this.persistStats(projectRoot, stats);
return { artifacts: result2, references, stats };
}
reset() {
this.contentHashMap.clear();
}
async readContent(filePath) {
try {
return await readFile31(filePath, "utf8");
} catch {
return "";
}
}
computeHash(content) {
return createHash10("sha256").update(content).digest("hex");
}
async persistStats(projectRoot, stats) {
try {
const statsPath = join70(projectRoot, ".paqad", "session", "dedup-stats.json");
await mkdir24(dirname29(statsPath), { recursive: true });
await writeFile24(statsPath, JSON.stringify(stats, null, 2), "utf8");
} catch {
}
}
};
// src/rag/index.ts
init_esm_shims();
// src/rag/benchmark-gates.ts
init_esm_shims();
function compareConfigurations(baseline, candidate, mode, gates) {
return {
mode,
evaluation: evaluateBenchmarkGates(baseline, candidate, gates)
};
}
function relativeChangePct(baseline, candidate) {
if (baseline === 0) {
if (candidate === 0) {
return 0;
}
return Number.POSITIVE_INFINITY;
}
return (candidate - baseline) / baseline * 100;
}
function reductionPct(baseline, candidate) {
if (baseline === 0) {
return candidate === 0 ? 0 : -100;
}
return (baseline - candidate) / baseline * 100;
}
function formatDelta(delta) {
if (!Number.isFinite(delta)) {
return "+inf%";
}
const rounded = Math.round(delta * 10) / 10;
return `${rounded >= 0 ? "+" : ""}${rounded}%`;
}
function evaluateBenchmarkGates(baseline, candidate, gates = DEFAULT_BENCHMARK_GATES) {
const hitDelta = relativeChangePct(baseline.hit_at_5, candidate.hit_at_5);
const successDelta = relativeChangePct(baseline.task_success_rate, candidate.task_success_rate);
const correctionDelta = reductionPct(baseline.correction_turns, candidate.correction_turns);
const promptDelta = relativeChangePct(baseline.prompt_tokens_sent, candidate.prompt_tokens_sent);
const promptBaselineZero = baseline.prompt_tokens_sent === 0 && candidate.prompt_tokens_sent > 0;
const hitPass = hitDelta >= gates.hit_at_5_improvement_pct;
const successPass = successDelta >= gates.task_success_rate_improvement_pct;
const correctionPass = correctionDelta >= gates.correction_turn_reduction_pct;
const promptOverridePass = successDelta >= gates.prompt_token_override_success_improvement_pct;
const promptPass = promptDelta <= gates.prompt_token_increase_limit_pct || promptOverridePass;
return {
passed: hitPass && successPass && correctionPass && promptPass,
baseline,
candidate,
gates,
metrics: {
hit_at_5: {
passed: hitPass,
delta_pct: hitDelta,
threshold_pct: gates.hit_at_5_improvement_pct,
summary: `${hitPass ? "PASS" : "FAIL"} hit@5 ${formatDelta(hitDelta)} vs required +${gates.hit_at_5_improvement_pct}%`
},
task_success_rate: {
passed: successPass,
delta_pct: successDelta,
threshold_pct: gates.task_success_rate_improvement_pct,
summary: `${successPass ? "PASS" : "FAIL"} task success ${formatDelta(successDelta)} vs required +${gates.task_success_rate_improvement_pct}%`
},
correction_turns: {
passed: correctionPass,
delta_pct: correctionDelta,
threshold_pct: gates.correction_turn_reduction_pct,
summary: `${correctionPass ? "PASS" : "FAIL"} correction turns ${formatDelta(correctionDelta)} vs required +${gates.correction_turn_reduction_pct}% reduction`
},
prompt_tokens_sent: {
passed: promptPass,
delta_pct: promptDelta,
threshold_pct: gates.prompt_token_increase_limit_pct,
baseline_zero: promptBaselineZero,
override_passed: promptOverridePass,
success_delta_pct: successDelta,
summary: promptBaselineZero ? promptPass ? `PASS prompt tokens baseline=0 candidate=${candidate.prompt_tokens_sent} via success override` : `FAIL prompt tokens baseline=0 candidate=${candidate.prompt_tokens_sent} cannot satisfy +${gates.prompt_token_increase_limit_pct}% limit without success override` : promptPass ? promptOverridePass && promptDelta > gates.prompt_token_increase_limit_pct ? `PASS prompt tokens ${formatDelta(promptDelta)} exceeded +${gates.prompt_token_increase_limit_pct}% but success override passed (${formatDelta(successDelta)})` : `PASS prompt tokens ${formatDelta(promptDelta)} with limit +${gates.prompt_token_increase_limit_pct}%` : `FAIL prompt tokens ${formatDelta(promptDelta)} exceeded +${gates.prompt_token_increase_limit_pct}% without success override`
}
}
};
}
// src/rag/attachment-types.ts
init_esm_shims();
function toEphemeralCollectionId(sessionId) {
return sessionId;
}
function isAttachmentIndexingDegraded(outcome) {
return outcome.kind === "attachment_indexing_degraded";
}
// src/rag/attachment-registry.ts
init_esm_shims();
import { existsSync as existsSync30 } from "fs";
import { mkdir as mkdir25, readFile as readFile32, rename as rename2, writeFile as writeFile25 } from "fs/promises";
import { dirname as dirname30, join as join71, resolve as resolve2, sep as sep2 } from "path";
var AttachmentPathError = class extends Error {
constructor(sessionId, message) {
super(message);
this.sessionId = sessionId;
this.name = "AttachmentPathError";
}
sessionId;
};
function attachmentCollectionsRoot(projectRoot) {
return resolve2(projectRoot, PATHS.SESSION_ATTACHMENT_COLLECTIONS_DIR);
}
function resolveCollectionDir(projectRoot, sessionId) {
if (sessionId.trim().length === 0) {
throw new AttachmentPathError(sessionId, "Attachment session id must not be empty");
}
const root = attachmentCollectionsRoot(projectRoot);
const dir = resolve2(root, sessionId);
if (dir !== root && !dir.startsWith(root + sep2)) {
throw new AttachmentPathError(
sessionId,
`Attachment session id resolves outside the attachments root: ${sessionId}`
);
}
if (dir === root) {
throw new AttachmentPathError(
sessionId,
`Attachment session id is not a valid segment: ${sessionId}`
);
}
return dir;
}
function collectionVectorPaths(projectRoot, sessionId) {
resolveCollectionDir(projectRoot, sessionId);
const base = `${PATHS.SESSION_ATTACHMENT_COLLECTIONS_DIR}/${sessionId}`;
return { indexPath: `${base}/index.json`, metaPath: `${base}/meta.json` };
}
function registryPath(projectRoot) {
return join71(projectRoot, PATHS.SESSION_ATTACHMENT_REGISTRY);
}
async function readRegistry(projectRoot) {
const path10 = registryPath(projectRoot);
if (!existsSync30(path10)) {
return { version: 1, collections: [] };
}
try {
const raw = await readFile32(path10, "utf8");
const parsed = JSON.parse(raw);
return { version: 1, collections: parsed.collections ?? [] };
} catch {
return { version: 1, collections: [] };
}
}
async function writeRegistry(projectRoot, file) {
const path10 = registryPath(projectRoot);
await mkdir25(dirname30(path10), { recursive: true });
const tmp = `${path10}.tmp`;
await writeFile25(tmp, JSON.stringify(file, null, 2), "utf8");
await rename2(tmp, path10);
}
async function registerCollection(projectRoot, sessionId, collectionId, filePaths = [], status = "indexed") {
const file = await readRegistry(projectRoot);
const collections = file.collections.filter((record2) => record2.sessionId !== sessionId);
collections.push({ sessionId, collectionId, filePaths, status });
await writeRegistry(projectRoot, { version: 1, collections });
}
async function deregisterCollection(projectRoot, sessionId) {
const file = await readRegistry(projectRoot);
const collections = file.collections.filter((record2) => record2.sessionId !== sessionId);
if (collections.length === file.collections.length) {
return;
}
await writeRegistry(projectRoot, { version: 1, collections });
}
async function listCollections(projectRoot) {
const file = await readRegistry(projectRoot);
return file.collections.map((record2) => ({
sessionId: record2.sessionId,
collectionId: toEphemeralCollectionId(record2.collectionId)
}));
}
async function getCollectionId(projectRoot, sessionId) {
const file = await readRegistry(projectRoot);
const record2 = file.collections.find((entry) => entry.sessionId === sessionId);
return record2 ? toEphemeralCollectionId(record2.collectionId) : null;
}
// src/rag/attachment-indexer.ts
init_esm_shims();
import { createHash as createHash11 } from "crypto";
import { existsSync as existsSync32 } from "fs";
import { readFile as readFile34, rm as rm4 } from "fs/promises";
import { basename as basename8 } from "path";
// src/rag/attachment-events.ts
init_esm_shims();
import { appendFileSync as appendFileSync3, existsSync as existsSync31, mkdirSync as mkdirSync15, readFileSync as readFileSync34 } from "fs";
import { dirname as dirname31, join as join72 } from "path";
function appendAttachmentEvent(projectRoot, event) {
const record2 = { ...event, at: event.at ?? (/* @__PURE__ */ new Date()).toISOString() };
const path10 = join72(projectRoot, PATHS.ATTACHMENT_EVENTS_LOG);
mkdirSync15(dirname31(path10), { recursive: true });
appendFileSync3(path10, `${JSON.stringify(record2)}
`, "utf8");
return record2;
}
function readAttachmentEvents(projectRoot) {
const path10 = join72(projectRoot, PATHS.ATTACHMENT_EVENTS_LOG);
if (!existsSync31(path10)) {
return [];
}
const events = [];
for (const line of readFileSync34(path10, "utf8").split("\n")) {
if (line.trim().length === 0) {
continue;
}
try {
events.push(JSON.parse(line));
} catch {
}
}
return events;
}
// src/rag/attachment-parser.ts
init_esm_shims();
import { readFile as readFile33 } from "fs/promises";
var PDF_PAGE_CAP = 2e3;
var ZIP_DECOMPRESSED_LIMIT_BYTES = 500 * 1024 * 1024;
var BINARY_SNIFF_BYTES = 512;
var PDF_MAGIC = Buffer.from("%PDF");
var ZIP_MAGIC = Buffer.from([80, 75, 3, 4]);
function reject(outcome, reason2, message) {
return { ok: false, outcome, reason: reason2, message };
}
function errorMessage2(error) {
return error instanceof Error ? error.message : String(error);
}
function looksEncrypted(error) {
return /encrypt|password|protected/i.test(errorMessage2(error));
}
function sniffKind(bytes) {
if (bytes.subarray(0, PDF_MAGIC.length).equals(PDF_MAGIC)) {
return "pdf";
}
if (bytes.subarray(0, ZIP_MAGIC.length).equals(ZIP_MAGIC)) {
return "zip";
}
return "text";
}
function hasNullByte(bytes) {
return bytes.subarray(0, BINARY_SNIFF_BYTES).includes(0);
}
function isValidUtf8(bytes) {
return Buffer.from(bytes.toString("utf8"), "utf8").equals(bytes);
}
async function parsePdf(bytes, options) {
if (!options.pdfExtractor) {
return reject(
"format_rejected",
"unsupported-format",
"PDF attachments require a consumer-supplied pdfExtractor"
);
}
let extraction;
try {
extraction = await options.pdfExtractor(bytes);
} catch (error) {
if (looksEncrypted(error)) {
return reject("index_failed", "encrypted-pdf", `Encrypted PDF: ${errorMessage2(error)}`);
}
return reject("index_failed", "parse-error", `Could not parse PDF: ${errorMessage2(error)}`);
}
if (extraction.encrypted) {
return reject("index_failed", "encrypted-pdf", "Encrypted PDF could not be read");
}
const cap = options.pageCap ?? PDF_PAGE_CAP;
if (extraction.pageCount > cap) {
return reject(
"format_rejected",
"page-cap",
`PDF has ${extraction.pageCount} pages; the cap is ${cap}`
);
}
return {
ok: true,
content: extraction.text,
detectedKind: "pdf",
pageCount: extraction.pageCount
};
}
async function parseArchive(bytes, options) {
const limit = options.zipDecompressedLimitBytes ?? ZIP_DECOMPRESSED_LIMIT_BYTES;
if (!options.archiveInspector) {
return reject(
"format_rejected",
"unsupported-format",
"Archive attachments require a consumer-supplied archiveInspector"
);
}
let inspection;
try {
inspection = await options.archiveInspector(bytes);
} catch (error) {
return reject(
"index_failed",
"parse-error",
`Could not inspect archive: ${errorMessage2(error)}`
);
}
if (inspection.decompressedBytes > limit) {
return reject(
"format_rejected",
"zip-bomb",
`Archive decompresses to ${inspection.decompressedBytes} bytes; the limit is ${limit}`
);
}
return reject(
"format_rejected",
"unsupported-format",
"Archive contents are not indexable as text"
);
}
async function parseAttachment(filePath, options = {}) {
let bytes;
try {
bytes = options.bytes ?? await readFile33(filePath);
} catch (error) {
return reject(
"index_failed",
"parse-error",
`Could not read attachment: ${errorMessage2(error)}`
);
}
if (bytes.length === 0) {
return reject("index_failed", "empty-file", "Attachment is empty");
}
const kind = sniffKind(bytes);
if (kind === "pdf") {
return parsePdf(bytes, options);
}
if (kind === "zip") {
return parseArchive(bytes, options);
}
if (hasNullByte(bytes) || !isValidUtf8(bytes)) {
return reject(
"index_failed",
"mime-unrecognised",
"Attachment is not valid UTF-8 text and no extractor handles its format"
);
}
return { ok: true, content: bytes.toString("utf8"), detectedKind: "text" };
}
// src/rag/attachment-indexer.ts
var DEFAULT_RETRY_DELAYS_MS = [1e3, 2e3];
var EMBED_BATCH_SIZE = 32;
var SessionAttachmentIndexer = class {
constructor(providerFactory = createEmbeddingProvider, retryDelaysMs = DEFAULT_RETRY_DELAYS_MS) {
this.providerFactory = providerFactory;
this.retryDelaysMs = retryDelaysMs;
}
providerFactory;
retryDelaysMs;
chunker = new AstChunker();
running = /* @__PURE__ */ new Map();
async index(projectRoot, sessionId, filePaths, intelligence, onProgress, signal5) {
resolveCollectionDir(projectRoot, sessionId);
const collectionId = toEphemeralCollectionId(sessionId);
const { indexPath, metaPath } = collectionVectorPaths(projectRoot, sessionId);
const controller = new AbortController();
if (signal5?.aborted) {
controller.abort();
} else {
signal5?.addEventListener("abort", () => controller.abort(), { once: true });
}
this.running.set(sessionId, controller);
const start = Date.now();
try {
this.throwIfAborted(controller.signal);
const chunks = await this.chunkFiles(filePaths, controller.signal);
const provider = await this.providerFactory(projectRoot, intelligence, onProgress);
let items;
try {
items = await this.embedWithRetry(provider, chunks, controller.signal, onProgress);
} catch (error) {
if (isCancelledError(error)) {
throw error;
}
await this.purgeCollection(projectRoot, sessionId);
const reason2 = error instanceof Error ? error.message : "embedding provider unreachable";
appendRagAudit(projectRoot, "WARN", "rag-attachment-index-degraded", {
session_id: sessionId,
reason: reason2,
retries_exhausted: true
});
return {
kind: "attachment_indexing_degraded",
sessionId,
reason: reason2,
retriesExhausted: true
};
}
this.throwIfAborted(controller.signal);
const index = new FileVectorIndex(indexPath, metaPath);
await index.replaceAll(projectRoot, items, {
provider: provider.name,
model: provider.model
});
await registerCollection(projectRoot, sessionId, collectionId, filePaths, "indexed");
appendRagAudit(projectRoot, "INFO", "rag-attachment-index-completed", {
session_id: sessionId,
collection_id: collectionId,
chunks: items.length,
duration_ms: Date.now() - start
});
const result2 = {
collectionId,
chunkCount: items.length,
durationMs: Date.now() - start
};
return result2;
} catch (error) {
if (isCancelledError(error)) {
await this.purgeCollection(projectRoot, sessionId);
appendRagAudit(projectRoot, "WARN", "rag-attachment-index-cancelled", {
session_id: sessionId
});
}
throw error;
} finally {
this.running.delete(sessionId);
}
}
async cancel(projectRoot, sessionId) {
this.running.get(sessionId)?.abort();
await this.purgeCollection(projectRoot, sessionId);
}
async chunkFiles(filePaths, signal5) {
const chunks = [];
for (const filePath of filePaths) {
this.throwIfAborted(signal5);
if (!existsSync32(filePath)) {
continue;
}
let content;
try {
content = await readFile34(filePath, "utf8");
} catch {
continue;
}
chunks.push(...this.chunker.chunk(filePath, content));
}
return chunks;
}
async embedWithRetry(provider, chunks, signal5, onProgress) {
if (chunks.length === 0) {
return [];
}
const results = [];
for (let offset = 0; offset < chunks.length; offset += EMBED_BATCH_SIZE) {
this.throwIfAborted(signal5);
const batch = chunks.slice(offset, offset + EMBED_BATCH_SIZE);
const vectors = await this.embedBatchWithRetry(
provider,
batch.map((chunk) => chunk.content),
signal5,
onProgress
);
for (let index = 0; index < batch.length; index++) {
results.push({ ...batch[index], vector: vectors[index] });
}
}
return results;
}
async embedBatchWithRetry(provider, texts, signal5, onProgress) {
let lastError;
for (let attempt = 0; attempt <= this.retryDelaysMs.length; attempt++) {
this.throwIfAborted(signal5);
try {
return await provider.embed(texts);
} catch (error) {
lastError = error;
if (attempt === this.retryDelaysMs.length) {
break;
}
const delayMs = this.retryDelaysMs[attempt];
onProgress?.({
phase: "build",
message: `Attachment embedding failed; retrying in ${delayMs}ms`
});
await this.sleep(delayMs, signal5);
}
}
throw lastError ?? new Error("attachment embedding failed");
}
async purgeCollection(projectRoot, sessionId) {
let dir;
try {
dir = resolveCollectionDir(projectRoot, sessionId);
} catch {
return;
}
await rm4(dir, { recursive: true, force: true });
}
throwIfAborted(signal5) {
if (signal5.aborted) {
throw new CancelledError("Attachment indexing cancelled by consumer");
}
}
sleep(ms, signal5) {
return new Promise((resolve5, reject2) => {
if (signal5.aborted) {
reject2(new CancelledError("Attachment indexing cancelled by consumer"));
return;
}
const timer = setTimeout(() => {
signal5.removeEventListener("abort", onAbort);
resolve5();
}, ms);
const onAbort = () => {
clearTimeout(timer);
reject2(new CancelledError("Attachment indexing cancelled by consumer"));
};
signal5.addEventListener("abort", onAbort, { once: true });
});
}
};
var ATTACHMENT_RETRY_BUDGET_MS = 3e4;
var ATTACHMENT_RETRY_DELAY_MS = 1e3;
function isIndexAttachmentFailure(outcome) {
return outcome.ok === false;
}
function sha2562(content) {
return createHash11("sha256").update(content).digest("hex");
}
function scopeOf(kind) {
return kind === "project" ? "project" : "session";
}
function resolveTargetIndex(projectRoot, params) {
if (params.sessionKind === "project") {
return new FileVectorIndex();
}
const { indexPath, metaPath } = collectionVectorPaths(projectRoot, params.sessionId);
return new FileVectorIndex(indexPath, metaPath);
}
function isRateLimited(error) {
return error instanceof EmbeddingProviderError && error.code === "rate_limited";
}
function sleepFor(ms, signal5) {
return new Promise((resolve5, reject2) => {
if (signal5?.aborted) {
reject2(new CancelledError("Attachment indexing cancelled by consumer"));
return;
}
const timer = setTimeout(() => {
signal5?.removeEventListener("abort", onAbort);
resolve5();
}, ms);
const onAbort = () => {
clearTimeout(timer);
reject2(new CancelledError("Attachment indexing cancelled by consumer"));
};
signal5?.addEventListener("abort", onAbort, { once: true });
});
}
async function embedWithinDeadline(provider, texts, deadline, delayMs, signal5, onProgress) {
let lastError;
for (; ; ) {
if (signal5?.aborted) {
throw new CancelledError("Attachment indexing cancelled by consumer");
}
try {
return await provider.embed(texts);
} catch (error) {
lastError = error;
if (!isRateLimited(error)) {
throw error;
}
const remaining = deadline - Date.now();
if (remaining <= 0) {
break;
}
onProgress?.({
phase: "build",
message: `Attachment embedding rate-limited; retrying within the ${Math.max(0, Math.round(remaining))}ms budget`
});
await sleepFor(Math.min(delayMs, remaining), signal5);
}
}
throw lastError ?? new Error("attachment embedding rate-limited beyond retry budget");
}
async function indexAttachment(projectRoot, params) {
const fileName = basename8(params.filePath);
const scope = scopeOf(params.sessionKind);
const sessionField = params.sessionKind === "ephemeral" ? params.sessionId : void 0;
const emit = (event) => {
const record2 = appendAttachmentEvent(projectRoot, {
...event,
file_name: fileName,
collection_scope: scope,
session_id: sessionField
});
params.onEvent?.(record2);
return record2;
};
const index = resolveTargetIndex(projectRoot, params);
const parsed = await parseAttachment(params.filePath, params.parse);
if (!parsed.ok) {
emit({
kind: parsed.outcome === "format_rejected" ? "attachment.format_rejected" : "attachment.index_failed",
reason: parsed.reason
});
return { ok: false, outcome: parsed.outcome, reason: parsed.reason };
}
const fileHash = sha2562(parsed.content);
const existing = await index.load(projectRoot);
const existingItems = existing?.items ?? [];
const alreadyIndexed = existingItems.some(
(item) => item.source_file === params.filePath && item.file_content_hash === fileHash
);
if (alreadyIndexed) {
const meta = await index.loadMeta(projectRoot);
const chunkCount = existingItems.filter((item) => item.source_file === params.filePath).length;
return {
ok: true,
chunkCount,
provider: meta?.provider ?? params.intelligence.embedding_provider ?? "local",
collectionScope: scope,
deduped: true
};
}
const chunks = new AstChunker().chunk(params.filePath, parsed.content);
const factory = params.providerFactory ?? createEmbeddingProvider;
const provider = await factory(projectRoot, params.intelligence, params.onProgress);
const deadline = Date.now() + (params.retryBudgetMs ?? ATTACHMENT_RETRY_BUDGET_MS);
const delayMs = params.retryDelayMs ?? ATTACHMENT_RETRY_DELAY_MS;
const fresh = [];
try {
for (let offset = 0; offset < chunks.length; offset += EMBED_BATCH_SIZE) {
if (params.signal?.aborted) {
throw new CancelledError("Attachment indexing cancelled by consumer");
}
const batch = chunks.slice(offset, offset + EMBED_BATCH_SIZE);
const vectors = await embedWithinDeadline(
provider,
batch.map((chunk) => chunk.content),
deadline,
delayMs,
params.signal,
params.onProgress
);
for (let i = 0; i < batch.length; i++) {
fresh.push({ ...batch[i], vector: vectors[i], file_content_hash: fileHash });
}
}
} catch (error) {
if (isCancelledError(error)) {
throw error;
}
const reason2 = error instanceof Error ? error.message : "embedding failed";
appendRagAudit(projectRoot, "WARN", "rag-attachment-index-failed", {
session_id: params.sessionId,
file: fileName,
reason: reason2
});
emit({ kind: "attachment.index_failed", reason: reason2 });
return { ok: false, outcome: "index_failed", reason: reason2 };
}
const merged = [
...existingItems.filter((item) => item.source_file !== params.filePath),
...fresh
];
await index.replaceAll(projectRoot, merged, { provider: provider.name, model: provider.model });
if (params.sessionKind === "ephemeral") {
await registerCollection(
projectRoot,
params.sessionId,
toEphemeralCollectionId(params.sessionId),
[params.filePath],
"indexed"
);
}
emit({ kind: "attachment.indexed", chunk_count: fresh.length, provider: provider.name });
return {
ok: true,
chunkCount: fresh.length,
provider: provider.name,
collectionScope: scope,
deduped: false
};
}
async function clearEphemeralCollection(projectRoot, sessionId) {
let dir;
try {
dir = resolveCollectionDir(projectRoot, sessionId);
} catch {
return;
}
await rm4(dir, { recursive: true, force: true });
await deregisterCollection(projectRoot, sessionId);
}
// src/rag/orphan-sweep.ts
init_esm_shims();
import { rm as rm5 } from "fs/promises";
async function runOrphanSweep(projectRoot, liveSessionIds) {
const live = new Set(liveSessionIds);
const collections = await listCollections(projectRoot);
const purgedAt = (/* @__PURE__ */ new Date()).toISOString();
const purged = [];
for (const { sessionId, collectionId } of collections) {
if (live.has(sessionId)) {
continue;
}
let dir;
try {
dir = resolveCollectionDir(projectRoot, sessionId);
} catch (error) {
if (!(error instanceof AttachmentPathError)) {
throw error;
}
await deregisterCollection(projectRoot, sessionId);
continue;
}
await rm5(dir, { recursive: true, force: true });
await deregisterCollection(projectRoot, sessionId);
appendRagAudit(projectRoot, "INFO", "rag.orphan_collection_purged", {
collection_id: collectionId
});
purged.push({ collectionId, purgedAt });
}
return purged;
}
// src/rag/attachment-retriever.ts
init_esm_shims();
function emptyResult(fallbackReason) {
return {
vector_scores: /* @__PURE__ */ new Map(),
chunks_retrieved: 0,
retrieved_chunk_ids: [],
retrieved_source_files: [],
retrieved_chunks: [],
fallback_reason: fallbackReason
};
}
async function retrieveFromAttachments(projectRoot, sessionId, query, topN, providerFactory = createEmbeddingProvider) {
const collectionId = await getCollectionId(projectRoot, sessionId);
if (!collectionId) {
return emptyResult("no-attachment-collection");
}
const { indexPath, metaPath } = collectionVectorPaths(projectRoot, sessionId);
const index = new FileVectorIndex(indexPath, metaPath);
const meta = await index.loadMeta(projectRoot);
if (!meta) {
return emptyResult("attachment-index-unavailable");
}
const intelligence = normalizeIntelligenceConfig({
rag_enabled: true,
embedding_provider: meta.provider,
embedding_model: meta.model
});
const limit = topN ?? intelligence.rag_top_n;
const provider = await providerFactory(projectRoot, intelligence);
const [queryVector] = await provider.embed(query);
const results = await index.query(projectRoot, queryVector, limit);
return {
vector_scores: new Map(results.map((result2) => [result2.item.id, result2.score])),
chunks_retrieved: results.length,
retrieved_chunk_ids: results.map((result2) => result2.item.id),
retrieved_source_files: results.map((result2) => result2.item.source_file),
retrieved_chunks: results.map((result2) => ({
id: result2.item.id,
source_file: result2.item.source_file,
content: result2.item.content
}))
};
}
// src/scripts/index.ts
init_esm_shims();
// src/scripts/generator.ts
init_esm_shims();
import { chmodSync as chmodSync3 } from "fs";
import { mkdir as mkdir26, writeFile as writeFile26 } from "fs/promises";
import { dirname as dirname32, join as join73 } from "path";
var RunnerScriptGenerator = class {
engine = new TemplateEngine();
async generate(profile) {
const registry = new TemplateRegistry(join73(getRuntimeTemplatesRoot(), "runner-scripts"));
const templates = await registry.discover();
return Promise.all(
templates.map(async (template) => ({
path: join73("scripts", template.relativePath.replace(/\.hbs$/, "")),
content: await this.engine.render(template.path, buildScriptContext(profile)),
autoUpdate: true,
executable: true
}))
);
}
async write(projectRoot, profile) {
const generated = await this.generate(profile);
const written = [];
for (const file of generated) {
const target = join73(projectRoot, file.path);
await mkdir26(dirname32(target), { recursive: true });
await writeFile26(target, file.content);
chmodSync3(target, 493);
written.push(file.path);
}
return written;
}
};
function buildScriptContext(profile) {
return buildRunnerScriptContext({
projectName: profile.project.name,
commands: {
test: profile.commands.test,
lint: profile.commands.lint,
format: profile.commands.format
},
stack: getPrimaryStack(profile)
});
}
// src/skills/index.ts
init_esm_shims();
// src/skills/index-generator.ts
init_esm_shims();
var import_fast_glob16 = __toESM(require_out(), 1);
import { mkdir as mkdir27, readFile as readFile35, writeFile as writeFile27 } from "fs/promises";
import { dirname as dirname33, join as join74, relative as relative14 } from "path";
async function buildSkillIndex(profile, files, relativeTo2 = process.cwd()) {
const parser = new SkillFrontmatterParser();
const entries = await Promise.all(
files.map(async (file) => {
const parsed = parser.parse(await readFile35(file, "utf8"), dirname33(file));
return {
name: parsed.frontmatter.name,
description: parsed.frontmatter.description,
triggers: parsed.frontmatter.triggers,
request_routing: parsed.frontmatter.request_routing,
model_tier: parsed.frontmatter.model_tier,
resolved_model: selectModelForTier(profile, parsed.frontmatter.model_tier),
output_format: parsed.frontmatter.output_format,
cacheable: parsed.frontmatter.cacheable,
on_complete: parsed.frontmatter.on_complete,
file: relative14(relativeTo2, file)
};
})
);
return entries.sort((left, right) => left.name.localeCompare(right.name));
}
async function generateSkillIndex(profile, skillRoots2, relativeTo2 = process.cwd()) {
const files = (await Promise.all(
skillRoots2.map(
(root) => (0, import_fast_glob16.default)("**/SKILL.md", {
cwd: root,
absolute: true
})
)
)).flat().sort();
return buildSkillIndex(profile, files, relativeTo2);
}
async function writeSkillIndexFromArtifacts(projectRoot, profile, artifacts) {
const skillFiles = artifacts.map((artifact) => artifact.path).filter((path10) => path10.endsWith("SKILL.md")).sort();
return writeSkillIndex(projectRoot, await buildSkillIndex(profile, skillFiles, projectRoot));
}
async function writeSkillIndex(projectRoot, index) {
const target = join74(projectRoot, PATHS.SKILL_INDEX);
await mkdir27(dirname33(target), { recursive: true });
await writeFile27(target, `${JSON.stringify(index, null, 2)}
`);
return PATHS.SKILL_INDEX;
}
// src/skills/loader.ts
init_esm_shims();
import { createHash as createHash12 } from "crypto";
import { readFile as readFile36 } from "fs/promises";
var SkillLoader = class {
constructor(auditBuffer = getSharedSkillAuditBuffer(), warn2) {
this.auditBuffer = auditBuffer;
this.warn = warn2;
}
auditBuffer;
warn;
parser = new SkillFrontmatterParser();
async load(artifacts, projectRoot) {
const skillArtifacts = artifacts.filter(
(artifact) => basename(artifact.path).endsWith("SKILL.md")
);
const loaded = await Promise.all(
skillArtifacts.map(async (artifact) => {
const content = await readFile36(artifact.path, "utf8");
try {
const parsed = this.parser.parse(content, dirname(artifact.path));
if (parsed.deprecation !== null) {
recordSkillMetadataDeprecation(
{
ts: (/* @__PURE__ */ new Date()).toISOString(),
type: "skill.metadata_deprecated",
path: artifact.path,
skill: parsed.frontmatter.name,
message: parsed.deprecation
},
projectRoot,
this.warn
);
}
return toLoadedSkill(artifact.path, parsed);
} catch (error) {
if (error instanceof ValidationError) {
emitSkillAuditEvent(
{
ts: (/* @__PURE__ */ new Date()).toISOString(),
type: "skill.load_failed",
path: artifact.path,
validation_error_code: error.subCode ?? error.code,
message: error.message,
skill_id: null,
content_hash: createHash12("sha256").update(content).digest("hex")
},
projectRoot,
this.auditBuffer
);
return null;
}
throw error;
}
})
);
return loaded.filter((skill) => skill !== null).sort(
(left, right) => left.name.localeCompare(right.name) || left.file.localeCompare(right.file)
);
}
};
// src/skills/runtime-registry.ts
init_esm_shims();
var RUNTIME_PREFIX = "runtime:";
function runtimeIdFor(name) {
return `${RUNTIME_PREFIX}${name}`;
}
var RuntimeSkillRegistry = class {
builtIns;
builtInNames;
runtime = /* @__PURE__ */ new Map();
parser = new SkillFrontmatterParser();
constructor(builtIns) {
this.builtIns = [...builtIns];
this.builtInNames = new Set(this.builtIns.map((skill) => skill.name));
}
register(content, sourceLabel, folder) {
let skill;
try {
const parsed = this.parser.parse(content, folder);
skill = toLoadedSkill(`${RUNTIME_PREFIX}${sourceLabel ?? parsed.frontmatter.name}`, parsed);
} catch (cause) {
throw new SkillRegistrationError(
`Skill registration refused: ${cause instanceof Error ? cause.message : "malformed content"}`,
{ kind: "malformed", cause }
);
}
const name = skill.name;
const runtimeId = runtimeIdFor(name);
if (this.builtInNames.has(name)) {
throw new SkillRegistrationError(
`Skill "${name}" collides with a built-in skill; the built-in remains the default match.`,
{ kind: "duplicate", builtInId: name, runtimeId }
);
}
if (this.runtime.has(runtimeId)) {
throw new SkillRegistrationError(`A runtime skill "${name}" is already registered.`, {
kind: "duplicate",
runtimeId
});
}
this.runtime.set(runtimeId, skill);
return skill;
}
remove(runtimeId) {
if (this.runtime.delete(runtimeId)) {
return;
}
if (this.builtInNames.has(runtimeId)) {
throw new SkillRegistrationError(`Cannot remove built-in skill "${runtimeId}".`, {
kind: "built-in-protected",
builtInId: runtimeId
});
}
throw new SkillRegistrationError(`No runtime skill registered under "${runtimeId}".`, {
kind: "not-found",
runtimeId
});
}
snapshot() {
const builtIns = [...this.builtIns].sort((a, b) => a.name.localeCompare(b.name)).map((skill) => ({ ...skill, id: skill.name, source: "built-in" }));
const runtime = [...this.runtime.entries()].sort(([, a], [, b]) => a.name.localeCompare(b.name)).map(([id, skill]) => ({ ...skill, id, source: "runtime" }));
return Object.freeze([...builtIns, ...runtime]);
}
};
// src/skills/trigger-evaluator.ts
init_esm_shims();
var SkillTriggerEvaluator = class {
shouldLoad(skill, classification) {
return skill.triggers.some((trigger) => matchesTrigger(trigger, classification));
}
};
function matchesTrigger(trigger, classification) {
return Object.entries(trigger).every(([dimension, allowedValues]) => {
const currentValue = classification[dimension];
if (Array.isArray(currentValue)) {
return currentValue.some((value) => allowedValues.includes(String(value)));
}
return allowedValues.includes(String(currentValue));
});
}
// src/update/index.ts
init_esm_shims();
// src/update/audit.ts
init_esm_shims();
import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync16 } from "fs";
import { dirname as dirname34, join as join75 } from "path";
function auditPath(projectRoot) {
return join75(projectRoot, PATHS.AUDIT_LOG);
}
function ts() {
return (/* @__PURE__ */ new Date()).toISOString();
}
function appendAuditLog(projectRoot, previous, updated) {
const path10 = auditPath(projectRoot);
mkdirSync16(dirname34(path10), { recursive: true });
const line = `[${ts()}] INFO silent-update previous=${previous ?? "unknown"} updated=${updated}
`;
appendFileSync4(path10, line);
}
function appendAuditLogFailure(projectRoot, previous, target, error) {
const path10 = auditPath(projectRoot);
mkdirSync16(dirname34(path10), { recursive: true });
const sanitized = error.replace(/"/g, "'");
const line = `[${ts()}] WARN silent-update-failed previous=${previous ?? "unknown"} target=${target} error="${sanitized}"
`;
appendFileSync4(path10, line);
}
// src/update/updater.ts
init_esm_shims();
import {
chmodSync as chmodSync4,
existsSync as existsSync34,
mkdirSync as mkdirSync17,
readdirSync as readdirSync10,
readFileSync as readFileSync35,
writeFileSync as writeFileSync19
} from "fs";
import { mkdtemp, readdir as readdir7, readFile as readFile37, rm as rm6 } from "fs/promises";
import { tmpdir } from "os";
import { dirname as dirname35, join as join77, relative as relative15 } from "path";
// src/update/generated-files-cleanup.ts
init_esm_shims();
import { existsSync as existsSync33, readdirSync as readdirSync9, rmdirSync as rmdirSync2, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
import { join as join76 } from "path";
var LEGACY_VIEW_HASH = ".paqad/state/feature-development-view.sha256";
var LEGACY_SCHEMAS_DIR = `${PATHS.PROJECT_CONFIGS_DIR}/schemas`;
var INSTRUCTIONS_DIR = "docs/instructions";
function errorMessage3(error) {
return error instanceof Error ? error.message : String(error);
}
function stayedLine(item, error) {
return `Couldn't remove ${item}, so it stayed: ${errorMessage3(error)}. paqad tries again on the next update or join.`;
}
function removeGeneratedCopy(projectRoot) {
return () => {
const path10 = featureDevelopmentViewPath(projectRoot);
const text2 = readTextIfExistsSync(path10);
if (text2 === null || !isGeneratedView(text2)) return null;
rmSync11(path10);
return `Removed the generated workflow copy ${FEATURE_DEVELOPMENT_VIEW_RELATIVE}; paqad reads .paqad/configs/ directly.`;
};
}
function removeViewHash(projectRoot) {
return () => {
const path10 = join76(projectRoot, LEGACY_VIEW_HASH);
if (!existsSync33(path10)) return null;
rmSync11(path10);
return `Removed ${LEGACY_VIEW_HASH}, which paqad used to check the workflow copy.`;
};
}
function removeExcludeLine(projectRoot) {
return () => unexcludeLocally(projectRoot, FEATURE_DEVELOPMENT_VIEW_RELATIVE) ? `Removed the line for ${FEATURE_DEVELOPMENT_VIEW_RELATIVE} from .git/info/exclude.` : null;
}
function removeEmptyFolder(projectRoot, relative21) {
return () => {
const path10 = join76(projectRoot, relative21);
if (!existsSync33(path10) || readdirSync9(path10).length > 0) return null;
rmdirSync2(path10);
return `Removed the empty ${relative21}/ folder.`;
};
}
function removeSchemas(projectRoot) {
return () => {
const path10 = join76(projectRoot, LEGACY_SCHEMAS_DIR);
if (!existsSync33(path10)) return null;
rmSync11(path10, { recursive: true });
return `Removed ${LEGACY_SCHEMAS_DIR}/; paqad no longer writes editor schemas.`;
};
}
function removeSchemaLine(projectRoot, file) {
return () => {
const path10 = teamConfigPath(projectRoot, file);
const raw = readTextIfExistsSync(path10);
if (raw === null) return null;
const text2 = raw.startsWith("\uFEFF") ? raw.slice(1) : raw;
if (!text2.startsWith(LEGACY_SCHEMA_LINE_PREFIX)) return null;
const end = text2.indexOf("\n");
writeFileSync18(path10, end === -1 ? "" : text2.slice(end + 1), "utf8");
return `Removed the schema line at the top of ${PATHS.PROJECT_CONFIGS_DIR}/${file}.`;
};
}
function run(item, step, lines) {
try {
const line = step();
if (line !== null) lines.push(line);
} catch (error) {
lines.push(stayedLine(item, error));
}
}
function removeGeneratedFiles(projectRoot) {
const lines = [];
run(FEATURE_DEVELOPMENT_VIEW_RELATIVE, removeGeneratedCopy(projectRoot), lines);
run(LEGACY_VIEW_HASH, removeViewHash(projectRoot), lines);
run(
`the ${FEATURE_DEVELOPMENT_VIEW_RELATIVE} line in .git/info/exclude`,
removeExcludeLine(projectRoot),
lines
);
run(`${PATHS.WORKFLOWS_DIR}/`, removeEmptyFolder(projectRoot, PATHS.WORKFLOWS_DIR), lines);
run(`${INSTRUCTIONS_DIR}/`, removeEmptyFolder(projectRoot, INSTRUCTIONS_DIR), lines);
run(`${LEGACY_SCHEMAS_DIR}/`, removeSchemas(projectRoot), lines);
for (const file of TEAM_CONFIG_FILES) {
run(
`the schema line at the top of ${PATHS.PROJECT_CONFIGS_DIR}/${file}`,
removeSchemaLine(projectRoot, file),
lines
);
}
return lines;
}
// src/update/updater.ts
var CLAUDE_HOOK_ARTIFACTS = /* @__PURE__ */ new Set([
".claude/settings.json",
".claude/settings.hooks.json",
".claude/settings.local.json"
]);
var CLAUDE_TEAM_HOOK_ARTIFACTS = /* @__PURE__ */ new Set([".claude/settings.hooks.json"]);
var CLAUDE_HOST_FILES = /* @__PURE__ */ new Set([
".claude/.gitignore",
".claude/settings.json",
".claude/settings.local.json"
]);
var RETIRED_FILES = [
...OBSOLETE_WORKFLOW_RULES.map((rule) => `${PATHS.RULES_DIR}/${rule.path}`),
OLD_DELIVERY_POLICY,
FEATURE_DEVELOPMENT_VIEW_RELATIVE
];
function withoutRemovedRetiredFiles(artifacts, fileExists2) {
return artifacts.filter(
(artifact) => !RETIRED_FILES.includes(toPosixPath(artifact.path)) || fileExists2(artifact.path)
);
}
var REMOVED_WORKFLOW_FILES = [
OLD_DELIVERY_POLICY,
FEATURE_DEVELOPMENT_VIEW_RELATIVE
];
var TRACKED_UPDATE_FILES = [
PATHS.ONBOARDING_MANIFEST,
PATHS.PROJECT_CONFIG_EXAMPLE,
".paqad/.gitignore",
".paqad/.gitattributes",
".worktreeinclude",
PATHS.RULE_SCRIPT_MAP,
PATHS.CAPABILITY_LOCK,
PATHS.SCHEMA_MARKER,
LEGACY_VIEW_HASH,
...new Set(Object.values(LEGACY_MCP_OUTPUT_PATHS)),
...RETIRED_FILES
];
function snapshotText(path10) {
try {
return readFileSync35(path10, "utf8");
} catch {
return null;
}
}
function filesUnder(projectRoot, relativeDir) {
let entries;
try {
entries = readdirSync10(join77(projectRoot, relativeDir), { withFileTypes: true });
} catch {
return [];
}
return entries.flatMap((entry) => {
const path10 = `${relativeDir}/${entry.name}`;
return entry.isDirectory() ? filesUnder(projectRoot, path10) : [path10];
});
}
function trackedUpdatePaths(projectRoot) {
return [...TRACKED_UPDATE_FILES, ...filesUnder(projectRoot, PATHS.PROJECT_CONFIGS_DIR)];
}
function snapshotFiles(projectRoot) {
return new Map(
trackedUpdatePaths(projectRoot).map((path10) => [path10, snapshotText(join77(projectRoot, path10))])
);
}
function filesChangedSince(projectRoot, before) {
const paths = /* @__PURE__ */ new Set([...before.keys(), ...trackedUpdatePaths(projectRoot)]);
return [...paths].filter((path10) => (before.get(path10) ?? null) !== snapshotText(join77(projectRoot, path10))).sort();
}
function readExistingText(path10) {
try {
return readFileSync35(path10, "utf8");
} catch (error) {
if (error.code === "ENOENT") {
return null;
}
throw error;
}
}
var FrameworkUpdater = class {
constructor(options = {}) {
this.options = options;
}
options;
async run(projectRoot) {
const filesBefore = snapshotFiles(projectRoot);
await checkAndMigrateSchema(projectRoot, VERSION);
runPendingEvidenceMigration(projectRoot);
const previousVersion = readText3(join77(projectRoot, PATHS.FRAMEWORK_VERSION));
const manifest = readManifest(projectRoot);
const artifactPolicy = new Map(
manifest?.generated_artifacts.map((artifact) => [artifact.path, artifact.auto_update]) ?? []
);
const providers = manifest ? deriveRecordedProviders(manifest) : ["claude-code"];
const gitWorkflowDir2 = `${PATHS.GIT_WORKFLOW_DIR}/`;
const generated = (await this.getCandidates(projectRoot, providers)).filter(
(candidate) => !toPosixPath(candidate.path).startsWith(gitWorkflowDir2)
);
const usesClaude = generated.some((candidate) => toPosixPath(candidate.path) === "CLAUDE.md");
const claude = new ClaudeCodeAdapter();
const candidates = usesClaude ? [
...generated.filter((candidate) => !CLAUDE_HOST_FILES.has(toPosixPath(candidate.path))),
...claude.hostSettingsFiles(projectRoot)
] : generated;
const regenerated = [];
const skipped5 = [];
const newScripts = [];
const pluginInstalled = isPluginInstalled();
const pluginOwnsClaudeHooks = pluginInstalled && !projectWiresLiveNpmHooks(projectRoot);
const pluginSkips = resolveTeamBootstrapEnabled(projectRoot) ? CLAUDE_TEAM_HOOK_ARTIFACTS : CLAUDE_HOOK_ARTIFACTS;
for (const candidate of candidates) {
const reportedPath = toPosixPath(candidate.path);
const target = join77(projectRoot, candidate.path);
if (pluginOwnsClaudeHooks && pluginSkips.has(reportedPath)) {
continue;
}
const existing = readExistingText(target);
const existed = existing !== null;
const autoUpdate = artifactPolicy.get(candidate.path) ?? candidate.autoUpdate;
if (existing === candidate.content) {
if (candidate.executable === true && autoUpdate !== false) {
chmodSync4(target, 493);
}
continue;
}
if (existing !== null && autoUpdate === false) {
skipped5.push({
path: reportedPath,
before: existing,
after: candidate.content
});
continue;
}
mkdirSync17(dirname35(target), { recursive: true });
writeFileSync19(target, candidate.content);
if (candidate.executable === true) {
chmodSync4(target, 493);
}
regenerated.push(reportedPath);
if (!existed && reportedPath.startsWith("scripts/")) {
newScripts.push(reportedPath);
}
}
if (manifest) {
writeOnboardingManifest(projectRoot, { ...manifest, providers });
}
cleanupLegacyMcpFiles(projectRoot);
writeConfigsReadme(projectRoot);
writeConfigExample(projectRoot);
const gitWorkflowNotes = updateGitWorkflow(projectRoot);
const teamConfigMigration = migrateTeamConfig(projectRoot);
if (teamConfigMigration.ran) gitWorkflowNotes.push(...teamConfigMigration.lines);
gitWorkflowNotes.push(...removeGeneratedFiles(projectRoot));
const mapWasCurrent = isRuleScriptMapCurrent(projectRoot);
const ruleCleanup = cleanObsoleteWorkflowRules(projectRoot);
gitWorkflowNotes.push(...ruleCleanup.lines);
const ruleRepair = repairKeptRuleLines(
projectRoot,
candidates.find((candidate) => toPosixPath(candidate.path) === KEPT_RULE_WITH_SHIPPED_LINES)?.content ?? null,
REMOVED_WORKFLOW_FILES.filter((path10) => !existsSync34(join77(projectRoot, path10)))
);
gitWorkflowNotes.push(...ruleRepair.lines);
refreshSkippedEntries(projectRoot, skipped5, ruleRepair.repaired);
if (ruleCleanup.removed.length > 0 || ruleRepair.repaired.length > 0) {
try {
dropRuleScriptMapSources(projectRoot, ruleCleanup.removed, mapWasCurrent, ruleRepair.texts);
} catch (error) {
gitWorkflowNotes.push(
`Couldn't drop the removed rule files from the rule-script map: ${error instanceof Error ? error.message : "unknown error"}.`
);
}
}
if (manifest) {
const artifacts = withoutRemovedRetiredFiles(
manifest.generated_artifacts,
(path10) => existsSync34(join77(projectRoot, path10))
);
if (artifacts.length !== manifest.generated_artifacts.length) {
writeOnboardingManifest(projectRoot, {
...manifest,
providers,
generated_artifacts: artifacts
});
}
}
const teamConfigProblems = [];
syncTeamConfigFiles(projectRoot, teamConfigProblems);
gitWorkflowNotes.push(...teamConfigProblems);
const changedTeam = changedTeamFiles(projectRoot, filesBefore);
if (changedTeam.length > 0) gitWorkflowNotes.push(commitLine(projectRoot, changedTeam));
const configKeysPruned = reconcileConfigOverrides(projectRoot).flatMap((file) => file.removed);
try {
writeStageAgents({ pluginInstalled: pluginLoadState(null) === "live" });
} catch {
}
try {
writeCodexRecipes(projectRoot);
} catch {
}
const teamSetup = usesClaude ? claude.syncTeamSetup(projectRoot) : null;
mkdirSync17(dirname35(join77(projectRoot, PATHS.FRAMEWORK_VERSION)), { recursive: true });
const versionPath = join77(projectRoot, PATHS.FRAMEWORK_VERSION);
const recorded = readFrameworkVersion(versionPath);
if (recorded === null || versionAtLeast(VERSION, recorded)) {
writeFrameworkVersionPreservingTimestamp(versionPath, VERSION, (/* @__PURE__ */ new Date()).toISOString());
}
if (!managedBlockIsNewer(projectRoot)) {
writeManagedGitignoreBlock(projectRoot);
}
writeWorktreeInclude(projectRoot);
const compileFailure = await ensureCompiledRulesCurrent(projectRoot);
if (compileFailure !== null) {
gitWorkflowNotes.push(
`Couldn't refresh ${PATHS.COMPILED_RULES}: ${compileFailureReason(compileFailure)}. Doctor will flag it. Run paqad-ai rag refresh-context to try again.`
);
}
return {
previous_version: previousVersion,
target_version: VERSION,
regenerated,
changed_files: [
.../* @__PURE__ */ new Set([
...filesChangedSince(projectRoot, filesBefore),
...ruleRepair.repaired,
...teamSetup?.report.written ?? [],
...teamSetup?.report.removed ?? []
])
],
skipped: skipped5,
deprecated: [],
new_mcp_servers: [],
new_scripts: newScripts.sort(),
config_keys_pruned: configKeysPruned,
team_setup_notes: teamSetup?.notes ?? [],
git_workflow_notes: gitWorkflowNotes,
...discoveryPluginClash() ? { plugin_notes: [DISCOVERY_CLASH_MESSAGE] } : {}
};
}
async getCandidates(projectRoot, providers) {
if (this.options.generateCandidates) {
return this.options.generateCandidates(projectRoot);
}
const profile = readProfile(projectRoot);
if (profile === null) {
throw new Error("Cannot update framework-managed artifacts without a project profile");
}
const tempRoot = await mkdtemp(join77(tmpdir(), "paqad-ai-update-"));
try {
const result2 = await new OnboardingOrchestrator().run({
projectRoot: tempRoot,
interactive: false,
selections: {
providers,
domain: getProfileDomain(profile),
stack_profile: profile.stack_profile,
stack: getPrimaryStack(profile),
capabilities: getLegacyCapabilities(profile)
},
profileOverrides: profile
});
const tempManifest = readManifest(tempRoot);
const files = await collectFiles(tempRoot, result2.generated_files, tempManifest);
return files;
} finally {
await rm6(tempRoot, { recursive: true, force: true });
}
}
};
function refreshSkippedEntries(projectRoot, skipped5, repaired) {
for (const path10 of repaired) {
const index = skipped5.findIndex((entry2) => entry2.path === path10);
if (index < 0) continue;
const entry = skipped5[index];
const before = readFileSync35(join77(projectRoot, path10), "utf8");
if (before === entry.after) skipped5.splice(index, 1);
else skipped5[index] = { ...entry, before };
}
}
function changedTeamFiles(projectRoot, before) {
const teamFiles = [
...TEAM_CONFIG_FILES.map(
(file) => toTeamRelative(projectRoot, teamConfigPath(projectRoot, file))
),
`${PATHS.PROJECT_CONFIGS_DIR}/${RETIRED_SAFETY_FILE}`,
...GIT_WORKFLOW_FILES.map(
(file) => toTeamRelative(projectRoot, gitWorkflowFilePath(projectRoot, file))
)
];
return teamFiles.filter(
(path10) => (before.get(path10) ?? null) !== snapshotText(join77(projectRoot, path10))
);
}
function toTeamRelative(projectRoot, path10) {
return toPosixPath(relative15(projectRoot, path10));
}
function commitLine(projectRoot, files) {
const record2 = lastAppliedPath(projectRoot);
const named = existsSync34(record2) ? [...files, toTeamRelative(projectRoot, record2)] : files;
return `Commit ${named.join(", ")} together so your teammates don't repeat this change. This happens once. Everyone needs this version or newer, including the plugin inside sessions.`;
}
function updateGitWorkflow(projectRoot) {
const profile = readProfile(projectRoot);
if (profile === null || getProfileDomain(profile) !== "coding") return [];
const migration = migrateDeliveryPolicy(projectRoot);
const syncNotes = [];
const held = migration.blocked === true;
const missing = NOT_MOVED_FILES.map((file) => gitWorkflowFilePath(projectRoot, file)).filter(
(path10) => !existsSync34(path10)
);
syncGitWorkflow(projectRoot, {
notes: syncNotes,
createMissing: !held,
alwaysCreate: held ? NOT_MOVED_FILES : []
});
if (held) {
for (const path10 of missing.filter((path11) => existsSync34(path11))) {
syncNotes.push(`Added ${toTeamRelative(projectRoot, path10)} with its defaults.`);
}
}
migration.lines.push(...syncNotes.filter((note) => !migration.lines.includes(note)));
try {
migration.lines.push(...installGitHooks(projectRoot).problems ?? []);
const advice = trackedWorkflowHookAdvice(projectRoot);
if (advice !== null) migration.lines.push(advice);
} catch (error) {
migration.lines.push(
`Couldn't check the git hooks: ${error instanceof Error ? error.message : "unknown error"}.`
);
}
return migration.lines;
}
function readManifest(projectRoot) {
const path10 = join77(projectRoot, PATHS.ONBOARDING_MANIFEST);
if (!existsSync34(path10)) {
return null;
}
return JSON.parse(readFileSync35(path10, "utf8"));
}
function readProfile(projectRoot) {
return readProjectProfile(projectRoot);
}
function readText3(path10) {
if (!existsSync34(path10)) {
return null;
}
const raw = readFileSync35(path10, "utf8");
const match = raw.match(/^version=(.+)$/m);
return match ? match[1].trim() : raw.trim();
}
async function collectFiles(root, generated, manifest) {
const paths = generated.length > 0 ? generated : await walk3(root);
const artifactPolicy = new Map(
manifest?.generated_artifacts.map((artifact) => [artifact.path, artifact]) ?? []
);
return Promise.all(
paths.map(async (file) => ({
path: file,
content: await readFile37(join77(root, file), "utf8"),
autoUpdate: artifactPolicy.get(file)?.auto_update ?? true,
executable: artifactPolicy.get(file)?.executable ?? file.startsWith("scripts/")
}))
);
}
async function walk3(root, current = root) {
const entries = await readdir7(current, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const absolute = join77(current, entry.name);
if (entry.isDirectory()) {
files.push(...await walk3(root, absolute));
continue;
}
files.push(relative15(root, absolute));
}
return files.sort();
}
// src/verification/index.ts
init_esm_shims();
// src/verification/delta.ts
init_esm_shims();
function toVerificationSnapshots(results) {
return results.map((result2) => ({
gate: result2.gate,
passed: result2.passed,
detail: result2.detail,
remediation: result2.remediation
}));
}
function buildVerificationGateDeltaPayload(baselineResults, currentResults, escalationInput = {}) {
return buildVerificationDeltaReasoningPayload(
toVerificationSnapshots(baselineResults),
toVerificationSnapshots(currentResults),
escalationInput
);
}
function buildDocumentationDriftDeltaPayload(baseline, current, escalationInput = {}) {
return buildDriftDeltaReasoningPayload(baseline, current, escalationInput);
}
// src/verification/gate-runner.ts
init_esm_shims();
// src/verification/gates/architecture-compliance.ts
init_esm_shims();
var ArchitectureComplianceGate = class {
gate = "architecture-compliance";
async check(context) {
return checkJudgedGate(
this.gate,
context.architecture_compliant,
"Architecture compliance checks passed",
"Architecture compliance checks failed",
"Align the implementation with the architectural constraints.",
"No architecture check was recorded, so this gate did not run."
);
}
};
// src/verification/gates/behavioral-correctness.ts
init_esm_shims();
// src/verification/test-evidence.ts
init_esm_shims();
function assessTestEvidence(input) {
const changedPreview = previewChangedFiles(input.changed_files);
const structuredResults = input.structured_test_results ?? [];
const matchedResults = structuredResults.filter((result2) => matchesAffectedScope(result2, input));
if (matchedResults.length > 0) {
return {
strength: "strong",
detail: `Strong test evidence recorded for changed code (${changedPreview}) via ${listRunnerIds(matchedResults)}.`,
matched_runner_ids: matchedResults.map((result2) => result2.summary.runner_id)
};
}
if (structuredResults.length > 0) {
return {
strength: "weak",
detail: `Only weak test evidence recorded for changed code (${changedPreview}). Structured test results exist, but they are not mapped to the affected files or modules.`,
matched_runner_ids: []
};
}
if (input.test_files_changed) {
return {
strength: "weak",
detail: `Only weak test evidence recorded for changed code (${changedPreview}). Test files changed, but no structured verification evidence was recorded for the affected scope.`,
matched_runner_ids: []
};
}
return {
strength: "none",
detail: `No test evidence recorded for changed code (${changedPreview})`,
matched_runner_ids: []
};
}
function matchesAffectedScope(result2, input) {
const relatedPaths = result2.evidence_scope?.related_paths?.map(normalizePath) ?? [];
const relatedModules = result2.evidence_scope?.related_modules?.map(normalizeModule) ?? [];
if (relatedPaths.length === 0 && relatedModules.length === 0) {
return false;
}
const changedFiles = new Set(input.changed_files.map(normalizePath));
if (relatedPaths.some((path10) => changedFiles.has(path10))) {
return true;
}
const modules = new Set(input.modules.map(normalizeModule));
return relatedModules.some((moduleId) => modules.has(moduleId));
}
function normalizePath(value) {
return value.replaceAll("\\", "/").toLowerCase();
}
function normalizeModule(value) {
return value.trim().toLowerCase();
}
function previewChangedFiles(changedFiles) {
return changedFiles.slice(0, 5).join(", ") || "unknown files";
}
function listRunnerIds(results) {
return [...new Set(results.map((result2) => result2.summary.runner_id))].join(", ");
}
// src/verification/gates/behavioral-correctness.ts
var BehavioralCorrectnessGate = class {
gate = "behavioral-correctness";
async check(context) {
const evidence = assessTestEvidence({
changed_files: context.changed_files,
modules: context.modules,
test_files_changed: context.test_files_changed,
structured_test_results: context.structured_test_results
});
const degradedResult = context.structured_test_results?.find(
(result2) => result2.parse_metadata.parse_strategy === "degraded"
);
if (degradedResult) {
return createInconclusive(
this.gate,
`Test results for "${degradedResult.summary.runner_id}" could not be fully parsed`,
"Check the test runner output and re-run."
);
}
const structuredFailure = context.structured_test_results?.find(
(result2) => result2.summary.failed > 0 || result2.summary.errored > 0
);
if (structuredFailure) {
return createFail(
this.gate,
`Behavioral tests failed under ${structuredFailure.summary.runner_id}`,
"Validate the implementation against the specified behavior."
);
}
if (context.code_changed && evidence.strength !== "strong") {
return createInconclusive(
this.gate,
evidence.detail,
"Re-run behavior verification with structured test evidence mapped to the affected scope."
);
}
if (context.structured_test_results && context.structured_test_results.length > 0) {
return createPass(this.gate, "Structured behavioral test results report no failures");
}
return checkJudgedGate(
this.gate,
context.behavioral_correctness_passed,
"Behavioral correctness checks passed",
"Behavioral correctness checks failed",
"Validate the implementation against the specified behavior.",
"No behaviour check was recorded, so this gate did not run."
);
}
};
// src/verification/gates/change-completeness.ts
init_esm_shims();
// src/verification/repository/scope-drift.ts
init_esm_shims();
function normalizePath2(value) {
const slashed = value.replace(/\\/g, "/").trim();
let start = 0;
if (slashed.startsWith("./")) {
start = 2;
} else if (slashed.startsWith("/")) {
start = 1;
}
let end = slashed.length;
while (end > start && slashed[end - 1] === "/") {
end -= 1;
}
return slashed.slice(start, end);
}
function isWithinBoundary(file, boundary) {
return boundary.some((entry) => file === entry || file.startsWith(`${entry}/`));
}
function collectScopeDriftPaths(changedFiles, specBoundary) {
const boundary = specBoundary.map(normalizePath2).filter((entry) => entry.length > 0);
if (boundary.length === 0) {
return [];
}
const drift = changedFiles.map((file) => normalizePath2(file)).filter((file) => file.length > 0 && !isWithinBoundary(file, boundary));
return [...new Set(drift)].sort();
}
// src/verification/gates/documentation-checks.ts
init_esm_shims();
import { existsSync as existsSync35 } from "fs";
import { readFile as readFile38 } from "fs/promises";
import { join as join78 } from "path";
// src/validators/index.ts
init_esm_shims();
// src/validators/markdown-validators/api-doc.ts
init_esm_shims();
// src/validators/markdown-validators/shared.ts
init_esm_shims();
function validateRequiredHeadings(markdown, headings) {
const errors = headings.filter((heading) => !markdown.includes(heading)).map((heading) => `Missing required heading: ${heading}`);
return {
valid: errors.length === 0,
errors
};
}
function validateAcStatements(markdown) {
const hasGwt = containsInOrder(markdown, ["Given", "When", "Then"]);
const hasShall = /\bshall\b/i.test(markdown);
if (hasGwt || hasShall) {
return { valid: true, errors: [] };
}
return {
valid: false,
errors: ["Acceptance criteria must use Given/When/Then or shall statements"]
};
}
function containsInOrder(text2, words) {
let from = 0;
for (const word of words) {
const at2 = text2.indexOf(word, from);
if (at2 === -1) return false;
from = at2 + word.length;
}
return true;
}
// src/validators/markdown-validators/api-doc.ts
var ENDPOINT_HEADING = /^###\s+(GET|POST|PUT|PATCH|DELETE)\s+\/\S+/m;
var REQUIRED_FIELDS = [
"**Method**",
"**Route**",
"**Auth**",
"**Description**",
"**Request Schema**",
"**Response Schema**"
];
function validateApiDoc(markdown) {
const required = validateRequiredHeadings(markdown, ["## Endpoints"]);
const errors = [...required.errors];
if (!ENDPOINT_HEADING.test(markdown)) {
errors.push("Missing endpoint heading in the format: ### {METHOD} {Route}");
}
for (const field of REQUIRED_FIELDS) {
if (!markdown.includes(field)) {
errors.push(`Missing required API doc field: ${field}`);
}
}
return {
valid: errors.length === 0,
errors
};
}
// src/validators/markdown-validators/error-catalog-md.ts
init_esm_shims();
var ERROR_HEADING = /^###\s+[A-Z]{2,5}-[0-9]{3}:\s+\S/m;
var REQUIRED_FIELDS2 = [
"**Code**",
"**User-Facing Message**",
"**Trigger**",
"**Recovery Path**"
];
function validateErrorCatalogMarkdown(markdown) {
const required = validateRequiredHeadings(markdown, ["## Error Code Format", "## Errors"]);
const errors = [...required.errors];
if (!ERROR_HEADING.test(markdown)) {
errors.push("Missing error heading in the format: ### {CODE}: {Description}");
}
for (const field of REQUIRED_FIELDS2) {
if (!markdown.includes(field)) {
errors.push(`Missing required error catalog field: ${field}`);
}
}
return {
valid: errors.length === 0,
errors
};
}
// src/validators/markdown-validators/spec-document.ts
init_esm_shims();
function validateSpecDocument(markdown) {
const required = validateRequiredHeadings(markdown, [
"## User Story",
"## Acceptance Criteria",
"## Test Plan"
]);
const ac = validateAcStatements(markdown);
return {
valid: required.valid && ac.valid,
errors: [...required.errors, ...ac.errors]
};
}
// src/validators/markdown-validators/user-flow.ts
init_esm_shims();
function validateUserFlow(markdown) {
return validateRequiredHeadings(markdown, ["## Actors", "## Preconditions", "## Main Flow"]);
}
// src/verification/gates/documentation-checks.ts
var STALENESS_WINDOW_MS2 = 1e3 * 60 * 60 * 24 * 7;
async function collectUnresolvedDocTargets(projectRoot, changedFiles, staleDocTargets) {
const unresolvedTargets = await Promise.all(
staleDocTargets.map(async (target) => {
if (!changedFiles.includes(target.target_path)) {
if (!existsSync35(join78(projectRoot, target.target_path))) {
return null;
}
return target;
}
const validationFailure = await validateCanonicalDocTarget(projectRoot, target.target_path);
if (validationFailure === null) {
return null;
}
return {
...target,
reason: `${target.reason} Direct edit still unresolved: ${validationFailure}`
};
})
);
return unresolvedTargets.filter((target) => target !== null);
}
function formatCanonicalDocTarget(target) {
const ownership = target.ownership_kind === "direct-doc-edit" ? "direct doc edit" : "implementation drift";
const owners = target.owners.length > 0 ? `owners: ${target.owners.join(", ")}` : "owners: none";
return `${target.target_path} [${ownership}; ${owners}; reason: ${target.reason}]`;
}
async function collectCanonicalDocumentationFailures(projectRoot, expectedUiModules, expectedApiModules, expectedIntegrationModules, expectedErrorCatalogModules) {
return [
...collectMissingDocs(projectRoot, expectedUiModules, ["ui", "screens.md"]),
...await collectApiDocFailures(projectRoot, expectedApiModules),
...await collectIntegrationDocFailures(projectRoot, expectedIntegrationModules),
...await collectErrorCatalogFailures(projectRoot, expectedErrorCatalogModules)
];
}
function areRegistriesStale(registryRefreshedAt) {
if (!registryRefreshedAt) {
return true;
}
const parsed = Date.parse(registryRefreshedAt);
return Number.isNaN(parsed) || Date.now() - parsed > STALENESS_WINDOW_MS2;
}
async function collectApiDocFailures(projectRoot, modules) {
const failures = [];
for (const moduleName of modules) {
const modulePath = join78(projectRoot, "docs", "modules", moduleName);
const result2 = await checkApiDocs(modulePath);
if (!result2.passed) {
failures.push(result2.detail);
}
}
return failures;
}
async function collectIntegrationDocFailures(projectRoot, modules) {
const failures = [];
for (const moduleName of modules) {
const modulePath = join78(projectRoot, "docs", "modules", moduleName);
const result2 = await checkIntegrationDocs(modulePath);
if (!result2.passed) {
failures.push(result2.detail);
}
}
return failures;
}
async function collectErrorCatalogFailures(projectRoot, modules) {
const failures = [];
for (const moduleName of modules) {
const modulePath = join78(projectRoot, "docs", "modules", moduleName);
const result2 = await checkErrorCatalog(modulePath);
if (!result2.passed) {
failures.push(result2.detail);
}
}
return failures;
}
async function checkApiDocs(modulePath) {
const endpointsPath = join78(modulePath, "api", "endpoints.md");
const endpointsExists = existsSync35(endpointsPath);
const schemasExists = existsSync35(join78(modulePath, "api", "schemas.md"));
const errorCodesExists = existsSync35(join78(modulePath, "api", "error-codes.md"));
if (!endpointsExists || !schemasExists || !errorCodesExists) {
return {
passed: false,
detail: `Missing API docs in ${modulePath}: ${[
!endpointsExists && "endpoints.md",
!schemasExists && "schemas.md",
!errorCodesExists && "error-codes.md"
].filter(Boolean).join(", ")}`
};
}
const endpointsValidation = validateApiDoc(await readFile38(endpointsPath, "utf8"));
if (!endpointsValidation.valid) {
return {
passed: false,
detail: `Invalid API docs in ${modulePath}: ${endpointsValidation.errors.join("; ")}`
};
}
return { passed: true, detail: "API docs present" };
}
async function checkIntegrationDocs(modulePath) {
const eventsExists = existsSync35(join78(modulePath, "integration", "events.md"));
const contractsExists = existsSync35(join78(modulePath, "integration", "contracts.md"));
if (!eventsExists || !contractsExists) {
return {
passed: false,
detail: `Missing integration docs in ${modulePath}: ${[
!eventsExists && "events.md",
!contractsExists && "contracts.md"
].filter(Boolean).join(", ")}`
};
}
return { passed: true, detail: "Integration docs present" };
}
async function checkErrorCatalog(modulePath) {
const catalogPath = join78(modulePath, "error-catalog.md");
const catalogExists = existsSync35(catalogPath);
if (!catalogExists) {
return {
passed: false,
detail: `Missing error-catalog.md in ${modulePath}`
};
}
const validation = validateErrorCatalogMarkdown(await readFile38(catalogPath, "utf8"));
if (!validation.valid) {
return {
passed: false,
detail: `Invalid error catalog in ${modulePath}: ${validation.errors.join("; ")}`
};
}
return { passed: true, detail: "Error catalog present" };
}
function collectMissingDocs(projectRoot, modules, segments) {
return modules.map((moduleName) => ({
moduleName,
path: join78(projectRoot, "docs", "modules", moduleName, ...segments)
})).filter((entry) => !existsSync35(entry.path)).map((entry) => `${entry.moduleName}:${segments.join("/")}`);
}
async function validateCanonicalDocTarget(projectRoot, targetPath) {
const absolutePath = join78(projectRoot, targetPath);
if (!existsSync35(absolutePath)) {
return "file does not exist";
}
if (!targetPath.endsWith(".md")) {
return null;
}
const markdown = await readFile38(absolutePath, "utf8");
if (markdown.trim().length === 0) {
return "markdown file is empty";
}
if (targetPath.endsWith("/api/endpoints.md")) {
const validation = validateApiDoc(markdown);
return validation.valid ? null : validation.errors.join("; ");
}
if (targetPath.endsWith("/error-catalog.md")) {
const validation = validateErrorCatalogMarkdown(markdown);
return validation.valid ? null : validation.errors.join("; ");
}
if (!/^#{1,6}\s+\S+/m.test(markdown)) {
return "markdown file is missing a heading";
}
return null;
}
// src/verification/gates/change-completeness.ts
var ChangeCompletenessGate = class {
gate = "change-completeness";
async check(context) {
const blockerReasons = await collectBlockerReasons(context);
if (!context.code_changed && blockerReasons.length === 0) {
return createNotRequired(
this.gate,
"Not required: no code changed, so no implementation work was left to complete."
);
}
const incompleteReasons = await collectIncompleteReasons(context);
if (blockerReasons.length === 0 && incompleteReasons.length === 0) {
return createPass(
this.gate,
"Change completeness: complete. Code changed, test evidence exists, canonical docs are current, and no blockers remain."
);
}
return createFail(
this.gate,
buildFailureDetail(blockerReasons, incompleteReasons),
blockerReasons.length > 0 ? "Resolve the blocking verification issues and finish the remaining change work before closing the task." : "Finish the remaining implementation, test, and documentation work before closing the task."
);
}
};
async function collectIncompleteReasons(context) {
const reasons = [];
const testEvidence = assessTestEvidence({
changed_files: context.changed_files,
modules: context.modules,
test_files_changed: context.test_files_changed,
structured_test_results: context.structured_test_results
});
const backstopCannotProve = isBackstopVerificationOrigin(context.verification_origin) && (context.structured_test_results?.length ?? 0) === 0;
if (context.code_changed && testEvidence.strength !== "strong" && !backstopCannotProve) {
reasons.push(testEvidence.detail);
}
const unresolvedDocTargets = await collectUnresolvedDocTargets(
context.project_root,
context.changed_files,
context.stale_doc_targets
);
if (context.code_changed && unresolvedDocTargets.length > 0) {
reasons.push(
`Canonical docs not updated for changed code: ${unresolvedDocTargets.map(formatCanonicalDocTarget).join("; ")}`
);
}
return reasons;
}
async function collectBlockerReasons(context) {
const reasons = [];
if (context.requirements_complete === false) {
reasons.push("Requirements are incomplete");
}
if (context.story_quality_passed === false) {
reasons.push("Story quality checks failed");
}
if (!context.ac_test_mapping_passed) {
reasons.push("Acceptance criteria are not mapped to tests");
}
if (!context.spec_review_passed) {
reasons.push("Spec review failed");
}
if (context.architecture_compliant === false) {
reasons.push("Architecture compliance failed");
}
if (context.spec_boundary && context.spec_boundary.length > 0) {
const driftPaths = collectScopeDriftPaths(context.changed_files, context.spec_boundary);
if (driftPaths.length > 0) {
reasons.push(`Out-of-scope changes outside the spec boundary: ${driftPaths.join(", ")}`);
}
}
const structuredTestIssue = getStructuredTestIssue(context.structured_test_results);
if (structuredTestIssue) {
reasons.push(structuredTestIssue);
} else if (context.code_tests_lint_passed === false) {
reasons.push("Code, tests, or lint checks failed");
}
if (!context.implementation_review_passed) {
reasons.push("Implementation review failed");
}
if (!structuredTestIssue && context.behavioral_correctness_passed === false) {
reasons.push("Behavioral correctness checks failed");
}
if (context.database_quality_passed === false) {
reasons.push("Database quality checks failed");
}
const documentationFailures = await collectCanonicalDocumentationFailures(
context.project_root,
context.expected_ui_modules,
context.expected_api_modules,
context.expected_integration_modules,
context.expected_error_catalog_modules
);
if (documentationFailures.length > 0) {
reasons.push(
`Canonical documentation is missing or invalid: ${documentationFailures.join(", ")}`
);
}
if (areRegistriesStale(context.registry_refreshed_at)) {
reasons.push("Registries are stale");
}
if (!context.glossary_updated) {
reasons.push("Glossary is out of date");
}
return reasons;
}
function getStructuredTestIssue(structuredTestResults) {
const degradedResult = structuredTestResults?.find(
(result2) => result2.parse_metadata.parse_strategy === "degraded"
);
if (degradedResult) {
return `Test results for "${degradedResult.summary.runner_id}" could not be fully parsed`;
}
const failingResult = structuredTestResults?.find(
(result2) => result2.summary.failed > 0 || result2.summary.errored > 0
);
if (failingResult) {
return `Structured test results report failures for ${failingResult.summary.runner_id}`;
}
return null;
}
function buildFailureDetail(blockerReasons, incompleteReasons) {
if (blockerReasons.length > 0 && incompleteReasons.length > 0) {
return `Change completeness: blocked. Blockers: ${blockerReasons.join("; ")}. Remaining work: ${incompleteReasons.join("; ")}.`;
}
if (blockerReasons.length > 0) {
return `Change completeness: blocked. Blockers: ${blockerReasons.join("; ")}.`;
}
return `Change completeness: incomplete. Remaining work: ${incompleteReasons.join("; ")}.`;
}
// src/verification/gates/code-tests-lint.ts
init_esm_shims();
var CodeTestsLintGate = class {
gate = "code-tests-lint";
async check(context) {
const evidence = assessTestEvidence({
changed_files: context.changed_files,
modules: context.modules,
test_files_changed: context.test_files_changed,
structured_test_results: context.structured_test_results
});
if (context.code_changed && evidence.strength === "none") {
return createFail(
this.gate,
evidence.detail,
"Add verification evidence that explicitly covers the changed code before closing the work."
);
}
if (context.code_changed && evidence.strength === "weak") {
return createFail(
this.gate,
evidence.detail,
"Record structured verification evidence mapped to the affected files or modules."
);
}
const degradedResult = context.structured_test_results?.find(
(result2) => result2.parse_metadata.parse_strategy === "degraded"
);
if (degradedResult) {
return createInconclusive(
this.gate,
`Test results for "${degradedResult.summary.runner_id}" could not be fully parsed`,
"Check the test runner output and re-run."
);
}
const structuredFailure = context.structured_test_results?.find(
(result2) => result2.summary.failed > 0 || result2.summary.errored > 0
);
if (structuredFailure) {
return createFail(
this.gate,
`Structured test results report failures for ${structuredFailure.summary.runner_id}`,
"Fix the failing build, test, or lint signal."
);
}
if (context.structured_test_results && context.structured_test_results.length > 0) {
const totals = context.structured_test_results.reduce(
(aggregate, result2) => {
aggregate.total += result2.summary.total;
aggregate.passed += result2.summary.passed;
return aggregate;
},
{ total: 0, passed: 0 }
);
return createPass(
this.gate,
`Structured test results show ${totals.passed}/${totals.total} passing checks`
);
}
return checkJudgedGate(
this.gate,
context.code_tests_lint_passed,
"Code, tests, and lint checks passed",
"Code, tests, or lint checks failed",
"Fix the failing build, test, or lint signal.",
"No checks report is on record, so this gate did not run."
);
}
};
// src/verification/gates/database-quality.ts
init_esm_shims();
var DatabaseQualityGate = class {
gate = "database-quality";
async check(context) {
return checkJudgedGate(
this.gate,
context.database_quality_passed,
"Database quality checks passed",
"Database quality checks failed",
"Address schema, migration, or query quality issues.",
"No database check was recorded, so this gate did not run."
);
}
};
// src/verification/gates/documentation-freshness.ts
init_esm_shims();
var DocumentationFreshnessGate = class {
gate = "documentation-freshness";
async check(context) {
const unresolvedDocTargets = await collectUnresolvedDocTargets(
context.project_root,
context.changed_files,
context.stale_doc_targets
);
if (context.code_changed && unresolvedDocTargets.length > 0) {
return createFail(
this.gate,
`Canonical docs not updated for changed code: ${unresolvedDocTargets.map(formatCanonicalDocTarget).join("; ")}`,
"Update the stale canonical docs before treating the implementation as complete."
);
}
const unchecked = context.unchecked_documentation_inputs ?? [];
if (unchecked.length > 0) {
return {
gate: this.gate,
passed: true,
inconclusive: true,
detail: `No changed code left its canonical docs stale, but paqad did not check ${unchecked.join(", ")}.`
};
}
const missingDocs = await collectCanonicalDocumentationFailures(
context.project_root,
context.expected_ui_modules,
context.expected_api_modules,
context.expected_integration_modules,
context.expected_error_catalog_modules
);
if (missingDocs.length > 0) {
return createFail(
this.gate,
`Missing canonical docs: ${missingDocs.join(", ")}`,
"Create or update the missing canonical documentation files."
);
}
if (areRegistriesStale(context.registry_refreshed_at)) {
return createFail(
this.gate,
"Registries are stale",
"Run the registry refresh and update the registry refresh timestamp."
);
}
if (!context.glossary_updated) {
return createFail(
this.gate,
"Glossary is out of date",
"Update the glossary with new terms introduced by the change."
);
}
return createPass(this.gate, "Canonical documentation is current");
}
};
// src/verification/gates/extension-surface.ts
init_esm_shims();
import { existsSync as existsSync36 } from "fs";
import { join as join79 } from "path";
var SURFACE_DOC_PATH = "docs/extension-surface.md";
var PUBLIC_BARRELS = ["src/index.ts", "src/cli/index.ts", "src/rule-scripts/index.ts"];
var REMEDIATION2 = `Amend ${SURFACE_DOC_PATH} in the same change when adding, removing, or renaming a public export.`;
var ExtensionSurfaceGate = class {
gate = "extension-surface";
async check(context) {
const docAbsolutePath = join79(context.project_root, ...SURFACE_DOC_PATH.split("/"));
if (!existsSync36(docAbsolutePath)) {
return createNotRequired(
this.gate,
`Not required: this project has no extension surface document (${SURFACE_DOC_PATH}).`
);
}
const changedFiles = context.changed_files.map(normalizePath3);
const changedBarrel = changedFiles.find(
(filePath) => PUBLIC_BARRELS.includes(filePath)
);
if (!changedBarrel) {
return createNotRequired(this.gate, "Not required: no public export barrel changed.");
}
const documentAmended = changedFiles.includes(SURFACE_DOC_PATH);
if (!documentAmended) {
return createFail(
this.gate,
`Public export barrel ${changedBarrel} changed without amending ${SURFACE_DOC_PATH}`,
REMEDIATION2
);
}
return createPass(
this.gate,
`Public export barrel ${changedBarrel} changed and ${SURFACE_DOC_PATH} amended in the same change.`
);
}
};
function normalizePath3(filePath) {
return filePath.replaceAll("\\", "/").replace(/^\.?\//, "");
}
// src/verification/gates/implementation-review.ts
init_esm_shims();
// src/review-digest/index.ts
init_esm_shims();
// src/review-digest/digest.ts
init_esm_shims();
// src/review-digest/sources.ts
init_esm_shims();
import { isAbsolute as isAbsolute3, normalize as normalize2, relative as relative16 } from "path";
// src/checks/report-target.ts
init_esm_shims();
function activeFeatureDirOrNull(projectRoot) {
try {
return currentFeature(projectRoot, checksSessionId(projectRoot));
} catch {
return null;
}
}
function checksSessionId(projectRoot) {
return resolveSessionId(projectRoot, explicitSessionHint());
}
function explicitSessionHint() {
for (const candidate of [process.env.SE_SESSION, process.env.CLAUDE_SESSION_ID]) {
const cleaned = candidate?.trim();
if (cleaned) return cleaned;
}
return null;
}
function sessionChecksTarget(projectRoot, sessionId, dirName) {
if (!dirName) return null;
try {
if (!isBundleMaterialized(projectRoot, dirName)) {
return readSessionControl(projectRoot, sessionId).active === dirName ? dirName : null;
}
return readFeatureStageUnit(projectRoot, dirName).some((row) => row.session_id === sessionId) ? dirName : null;
} catch {
return null;
}
}
function readChecksReportForFeature(projectRoot, dirName) {
if (dirName) {
const fromBundle = readFeatureChecks(projectRoot, dirName);
if (fromBundle) return fromBundle;
}
return readChecksReport(projectRoot);
}
function writeChecksReportForFeature(projectRoot, dirName, report) {
return dirName ? writeFeatureChecks(projectRoot, dirName, report, checksSessionId(projectRoot)) : writeChecksReport(projectRoot, report);
}
// src/duplication/report.ts
init_esm_shims();
import { existsSync as existsSync37, mkdirSync as mkdirSync18, readFileSync as readFileSync36, writeFileSync as writeFileSync20 } from "fs";
import { dirname as dirname36, join as join80 } from "path";
var DUPLICATION_REPORT_SCHEMA_VERSION = 1;
function summarizeFindings(findings, mode) {
const deterministic = findings.filter((f) => f.kind === "deterministic").length;
const heuristic = findings.filter((f) => f.kind === "heuristic").length;
return {
counts: { deterministic, heuristic },
blocking: mode === "strict" && deterministic > 0
};
}
function buildDuplicationReport(input) {
const { counts, blocking } = summarizeFindings(input.findings, input.config.mode);
return {
schema_version: DUPLICATION_REPORT_SCHEMA_VERSION,
generated_at: input.now,
mode: input.config.mode,
similarity_threshold: input.config.similarityThreshold,
min_lines: input.config.minLines,
elapsed_ms: input.elapsedMs,
findings: input.findings,
counts,
blocking,
...input.resolvedDecisions && input.resolvedDecisions.length > 0 ? { resolved_decisions: input.resolvedDecisions } : {}
};
}
function reportPath(projectRoot) {
return join80(projectRoot, PATHS.DUPLICATION_REPORT);
}
function writeDuplicationReport(projectRoot, report) {
const path10 = reportPath(projectRoot);
mkdirSync18(dirname36(path10), { recursive: true });
writeFileSync20(path10, `${JSON.stringify(report, null, 2)}
`, "utf8");
}
function readDuplicationReport(projectRoot) {
const path10 = reportPath(projectRoot);
if (!existsSync37(path10)) {
return null;
}
try {
return JSON.parse(readFileSync36(path10, "utf8"));
} catch {
return null;
}
}
// src/duplication/types.ts
init_esm_shims();
function formatRange(range) {
return range.start === range.end ? `${range.start}` : `${range.start}-${range.end}`;
}
function duplicationMessage(input) {
const percent = Math.round(input.similarity * 100);
const matchedName = input.matchedSymbol ?? input.matchedFile;
return `New code in ${input.file}:${formatRange(input.lineRange)} is ${percent}% similar to existing ${matchedName} (${input.matchedFile}:${formatRange(input.matchedLineRange)}), already used by ${input.matchedCallers} call sites. Prefer reusing or extending it \u2014 or record why a new copy is needed.`;
}
// src/verification/evidence-markdown.ts
init_esm_shims();
import { existsSync as existsSync39, readFileSync as readFileSync38 } from "fs";
import { join as join82 } from "path";
// src/evidence/receipt/project.ts
init_esm_shims();
import { appendFileSync as appendFileSync5, existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync37 } from "fs";
import { mkdir as mkdir28, rename as rename3, writeFile as writeFile28 } from "fs/promises";
import { dirname as dirname37, join as join81 } from "path";
function latestReceiptAuthorship(projectRoot) {
const latest2 = latestFeatureReceipt(projectRoot);
if (latest2 === null) return null;
const statement = decodeReceiptStatement(latest2);
return statement?.predicate.change_authorship ?? null;
}
function latestReceiptTrustExtras(projectRoot) {
const latest2 = latestFeatureReceipt(projectRoot);
if (latest2 === null) return { compliance: [], reproducibility: null };
const statement = decodeReceiptStatement(latest2);
return {
compliance: statement?.predicate.compliance_citations ?? [],
reproducibility: statement?.predicate.reproducibility ?? null
};
}
// src/verification/evidence-markdown.ts
var GATE_GLYPHS = {
pass: PAQAD_STATUS_GLYPH.good,
fail: PAQAD_STATUS_GLYPH.failed,
inconclusive: PAQAD_STATUS_GLYPH.needsLook,
skipped: PAQAD_STATUS_GLYPH.skipped
};
var VERDICT_GLYPHS = {
pass: PAQAD_STATUS_GLYPH.good,
fail: PAQAD_STATUS_GLYPH.failed,
inconclusive: PAQAD_STATUS_GLYPH.needsLook
};
function commentVerdict(evidence) {
if (evidence.overall_status === "error") return "inconclusive";
return verdictKindFor(evidence.gates, evidence.unrecorded_mandatory_stages ?? []);
}
var GATE_LABELS = {
"code-tests-lint": "Tests",
"mutation-testing": "Mutation",
"quality-ratchet": "Quality ratchet",
"ac-test-mapping": "Traceability",
"behavioral-correctness": "Behavioural correctness",
"architecture-compliance": "Architecture"
};
var TRUST_GATES = ["code-tests-lint", "mutation-testing", "quality-ratchet"];
function gateLabel(name) {
return GATE_LABELS[name] ?? name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
}
function readVerificationEvidence(projectRoot) {
const path10 = join82(projectRoot, VERIFICATION_EVIDENCE_RELATIVE_PATH);
if (!existsSync39(path10)) return null;
try {
const evidence = JSON.parse(readFileSync38(path10, "utf8"));
if (!Array.isArray(evidence.gates)) return null;
return evidence;
} catch {
return null;
}
}
function buildEvidenceComment(projectRoot, sha) {
const evidence = readVerificationEvidence(projectRoot);
if (evidence === null) return null;
const authorship = latestReceiptAuthorship(projectRoot) ?? void 0;
const extras = latestReceiptTrustExtras(projectRoot);
return renderEvidenceMarkdown(evidence, {
...sha ? { sha } : {},
...authorship ? { authorship } : {},
...extras.compliance.length > 0 ? { compliance: extras.compliance } : {},
...extras.reproducibility ? { reproducibility: extras.reproducibility } : {}
});
}
function shortSha(sha) {
if (!sha) return null;
const trimmed = sha.trim();
if (trimmed.length === 0) return null;
return /^[0-9a-f]{8,40}$/i.test(trimmed) ? trimmed.slice(0, 7) : trimmed;
}
function renderFailure(failure) {
const location = failure.file !== null && failure.line !== null ? `${failure.file}:${failure.line}` : failure.file ?? failure.test_id ?? failure.suite ?? null;
return location ? ` - ${location} \u2014 ${failure.message}` : ` - ${failure.message}`;
}
function isDidNotRun(gate) {
return gate.status === "skipped" && gate.skip_kind === "did-not-run";
}
function didNotRunLine(gate) {
const label = gateLabel(gate.name);
return gate.skip_reason !== void 0 ? `- ${GATE_GLYPHS.skipped} ${label} did not run: ${gate.skip_reason}` : `- ${GATE_GLYPHS.skipped} ${label}: ${gate.detail}`;
}
function gateSummaryLine(gate) {
const confidence = gate.name === "mutation-testing" && gate.confidence === "lower" ? " _(confidence: lower \u2014 do not over-trust)_" : "";
return `- ${GATE_GLYPHS[gate.status]} ${gateLabel(gate.name)} \u2014 ${gate.detail}${confidence}`;
}
function renderComplianceLines(citations) {
if (citations.length === 0) return null;
const byClause = /* @__PURE__ */ new Map();
for (const citation of citations) {
byClause.set(`${citation.framework_id}|${citation.clause_id}`, citation);
}
const clauses = [...byClause.values()].map(
(c) => `${c.framework_title} ${c.clause_id} (${c.evidence_strength})`
);
const disclaimer = citations[0]?.disclaimer.trim().replace(/\s+/g, " ") ?? "";
const lines = [`> Compliance evidence toward: ${clauses.join(", ")}.`];
if (disclaimer.length > 0) lines.push(`> _${disclaimer}_`);
return lines;
}
function renderReproducibilityLine(stamp) {
return `> Replayable from frozen context: \`${stamp.context_hash.slice(0, 12)}\` (${stamp.determinism}, algo v${stamp.algo_version}).`;
}
function renderAuthorshipLine(authorship) {
const parts = [];
if (authorship.agent !== void 0) parts.push(`written by \`${authorship.agent}\``);
const modelLabel = authorship.model_id ?? authorship.model;
if (modelLabel !== void 0) {
const qualifier = authorship.provenance === "declared" ? " (declared)" : "";
parts.push(`model \`${modelLabel}\`${qualifier}`);
}
if (authorship.accepting_human?.name !== void 0) {
parts.push(`accepted by ${authorship.accepting_human.name}`);
}
if (parts.length === 0) return null;
return `> Authorship: ${parts.join(" \xB7 ")}. paqad attests this on its gates, so the proof holds whichever tool wrote it.`;
}
function renderEvidenceMarkdown(evidence, options = {}) {
const lines = [];
const sha = shortSha(options.sha);
const verdict2 = commentVerdict(evidence);
const headerSuffix = sha ? ` \u2014 ${sha}` : "";
lines.push(
`## paqad evidence${headerSuffix} ${VERDICT_GLYPHS[verdict2]} ${PAQAD_VERDICT[verdict2]}`
);
lines.push("");
const counts = { pass: 0, fail: 0, inconclusive: 0, notRequired: 0, didNotRun: 0 };
for (const gate of evidence.gates) {
if (gate.status !== "skipped") counts[gate.status] += 1;
else if (isDidNotRun(gate)) counts.didNotRun += 1;
else counts.notRequired += 1;
}
lines.push(
`Gates: ${counts.pass} passed, ${counts.fail} failed, ${counts.inconclusive} inconclusive, ${counts.notRequired} not required, ${counts.didNotRun} did not run.`
);
lines.push("");
const byName = new Map(evidence.gates.map((gate) => [gate.name, gate]));
const trustLines = TRUST_GATES.map((name) => byName.get(name)).filter(
(gate) => gate !== void 0 && (gate.status !== "skipped" || isDidNotRun(gate))
).map((gate) => gate.status === "skipped" ? didNotRunLine(gate) : gateSummaryLine(gate));
if (trustLines.length > 0) {
lines.push(...trustLines);
lines.push("");
}
const blocking = evidence.gates.filter(
(gate) => gate.status === "fail" || gate.status === "inconclusive"
);
if (blocking.length > 0) {
lines.push("### Blocking");
lines.push("");
for (const gate of blocking) {
lines.push(gateSummaryLine(gate));
for (const failure of gate.failures) {
lines.push(renderFailure(failure));
}
if (gate.remediation) {
lines.push(` - _Fix:_ ${gate.remediation}`);
}
}
lines.push("");
}
lines.push(
verdict2 === "pass" ? "> Attests paqad\u2019s gates passed for this run \u2014 not that the change is correct." : "> paqad\u2019s gates did not all pass. Resolve the blocking items above before merge."
);
const authorshipLine = options.authorship ? renderAuthorshipLine(options.authorship) : null;
if (authorshipLine !== null) {
lines.push("");
lines.push(authorshipLine);
}
const complianceLines = options.compliance ? renderComplianceLines(options.compliance) : null;
if (complianceLines !== null) {
lines.push("");
lines.push(...complianceLines);
}
if (options.reproducibility) {
lines.push("");
lines.push(renderReproducibilityLine(options.reproducibility));
}
return lines.join("\n");
}
// src/review-digest/sources.ts
var HIGH_BAND = ["critical", "blocker", "high"];
function oneLine(message, max = 200) {
const collapsed = message.replace(/\s+/g, " ").trim();
return collapsed.length > max ? `${collapsed.slice(0, max - 1)}\u2026` : collapsed;
}
function findingAnchor(finding) {
if (finding.file === null) return null;
return finding.line === null ? finding.file : `${finding.file}:${finding.line}`;
}
function ruleScriptRows(projectRoot) {
const report = readReport(projectRoot);
if (!report) return [];
const rows = [];
for (const result2 of report.results) {
for (const finding of result2.findings) {
rows.push({
source: `rule:${result2.rule_id}`,
severity: finding.severity,
tier: result2.kind,
file: finding.file,
line: finding.line === void 0 ? null : String(finding.line),
message: oneLine(finding.message)
});
}
}
return rows;
}
function duplicationRows(projectRoot) {
const report = readDuplicationReport(projectRoot);
if (!report) return [];
return report.findings.map((finding) => ({
source: "duplication",
severity: finding.kind === "deterministic" ? "high" : "medium",
tier: finding.kind,
file: finding.file,
line: formatRange(finding.line_range),
message: oneLine(finding.message)
}));
}
function checksRows(projectRoot) {
const report = readChecksReportForFeature(projectRoot, activeFeatureDirOrNull(projectRoot));
if (!report) return [];
const rows = [];
for (const result2 of report.results) {
const runner = result2.summary.runner_id;
const failed = result2.summary.failed + result2.summary.errored;
rows.push({
source: "checks",
severity: failed > 0 ? "high" : "info",
tier: "deterministic",
file: null,
line: null,
message: oneLine(
failed > 0 ? `${runner}: ${failed} failing of ${result2.summary.total}` : `${runner}: ${result2.summary.passed} passing of ${result2.summary.total}`
)
});
for (const failure of result2.failures) {
rows.push({
source: `checks:${runner}`,
severity: "high",
tier: "deterministic",
file: failure.file_path,
line: failure.line_number === null ? null : String(failure.line_number),
message: oneLine(`${failure.test_id}: ${failure.message}`)
});
}
}
return rows;
}
function gateRows(projectRoot) {
const evidence = readVerificationEvidence(projectRoot);
if (!evidence) return [];
const rows = [];
for (const gate of evidence.gates) {
if (gate.status !== "fail" && gate.status !== "inconclusive") continue;
const severity = gate.status === "fail" ? "high" : "medium";
if (gate.failures.length === 0) {
rows.push({
source: `gate:${gate.name}`,
severity,
tier: "deterministic",
file: null,
line: null,
message: oneLine(gate.detail)
});
continue;
}
for (const failure of gate.failures) {
rows.push({
source: `gate:${gate.name}`,
severity,
tier: "deterministic",
file: failure.file,
line: failure.line === null ? null : String(failure.line),
message: oneLine(failure.ac_id ? `${failure.ac_id}: ${failure.message}` : failure.message)
});
}
}
return rows;
}
function collectMachineFindings(projectRoot) {
return [
...ruleScriptRows(projectRoot),
...duplicationRows(projectRoot),
...checksRows(projectRoot),
...gateRows(projectRoot)
];
}
function isFileScopedRow(finding) {
return finding.source.startsWith("rule:") || finding.source === "duplication";
}
function pathUnderRoot(file, projectRoot) {
const slashed = file.replace(/\\/g, "/");
const under2 = isAbsolute3(slashed) ? relative16(projectRoot, slashed) : normalize2(slashed);
const clean = under2.replace(/\\/g, "/");
return clean === ".." || clean.startsWith("../") || isAbsolute3(clean) ? null : clean;
}
function scopeFindingsToChange(findings, files, projectRoot) {
if (files === null || files === void 0) return findings;
const own = new Set(files);
return findings.filter((finding) => {
if (!isFileScopedRow(finding) || !finding.file) return true;
const path10 = pathUnderRoot(finding.file, projectRoot);
return path10 === null || own.has(path10);
});
}
function anchoringFindings(findings) {
return findings.filter(
(finding) => finding.tier === "deterministic" && HIGH_BAND.includes(finding.severity) && findingAnchor(finding) !== null
);
}
function unanchoredMachineFindings(findings, reviewText2) {
return anchoringFindings(findings).filter((finding) => {
const anchor = findingAnchor(finding);
return anchor !== null && !reviewText2.includes(anchor);
});
}
// src/review-digest/digest.ts
var DIGEST_LINE_CAP = 150;
var CHANGED_FILE_LIMIT = 12;
var BLIND_SPOTS = [
"Semantic duplication \u2014 logic re-implemented in different words. The detector matches tokens, not meaning.",
"Architectural fit \u2014 whether this belongs in this module at all.",
"Naming and API shape \u2014 nothing grades whether a name will read well in six months.",
"Whether the tests assert the RIGHT behaviour; coverage proves they ran, not that they are correct.",
"Rollback and data-migration risk, and anything only reproducible against real data."
];
function section2(title, rows, emptyLine) {
return [`## ${title}`, "", ...rows.length > 0 ? rows : [emptyLine], ""];
}
function criterionLine(criterion) {
const gwt = [
criterion.given ? `given ${criterion.given}` : "",
criterion.when ? `when ${criterion.when}` : "",
criterion.then ? `then ${criterion.then}` : ""
].filter(Boolean).join(", ");
const proof = criterion.proof_type ? ` [${criterion.proof_type}]` : "";
return `- ${criterion.criterion_id}${proof} \u2014 ${gwt || "no given/when/then recorded"}`;
}
function findingLine(finding) {
const anchor = findingAnchor(finding) ?? "-";
return `${finding.source} | ${finding.severity} | ${finding.tier} | ${anchor} | ${finding.message}`;
}
function capLines(lines) {
if (lines.length <= DIGEST_LINE_CAP) return lines;
const kept = lines.slice(0, DIGEST_LINE_CAP - 1);
return [
...kept,
`> \u2026truncated: ${lines.length - kept.length} more lines (cap ${DIGEST_LINE_CAP}).`
];
}
function buildReviewDigest(input) {
const lines = [
"# Review digest",
"",
`> Machine-built ${input.generated_at} from cached evidence \u2014 no model wrote a word of it.`,
"> Confirm or contest every deterministic row below. An unaddressed deterministic finding is itself a review finding.",
"",
"## Change",
"",
`- Feature: ${input.feature ?? "none active"}`
];
if (input.changed_files.length === 0) {
lines.push("- Changed files: none recorded");
} else {
const shown = input.changed_files.slice(0, CHANGED_FILE_LIMIT);
lines.push(`- Changed files (${input.changed_files.length}):`);
lines.push(...shown.map((file) => ` - ${file}`));
if (input.changed_files.length > shown.length) {
lines.push(` - \u2026and ${input.changed_files.length - shown.length} more`);
}
}
lines.push(
input.stages.length === 0 ? "- Stages: none recorded" : `- Stages: ${input.stages.map((stage) => `${stage.stage}=${stage.state}`).join(" \xB7 ")}`
);
lines.push("");
lines.push(
...section2(
"Spec",
input.criteria.map(criterionLine),
"No frozen acceptance criteria on record (`paqad-ai spec freeze` writes them)."
)
);
const findingRows = input.findings.length === 0 ? [] : [
"source | severity | tier | file:line | message",
"--- | --- | --- | --- | ---",
...input.findings.map(findingLine)
];
lines.push(
...section2(
"Machine findings",
findingRows,
'No machine findings recorded. Nothing ran, or everything it ran came back clean \u2014 check the stage states above before reading this as "clean".'
)
);
lines.push(
...section2(
"Blind spots",
BLIND_SPOTS.map((spot) => `- ${spot}`),
"none recorded"
)
);
return `${capLines(lines).join("\n").trimEnd()}
`;
}
// src/review-digest/write.ts
init_esm_shims();
import { mkdirSync as mkdirSync20, writeFileSync as writeFileSync21 } from "fs";
import { dirname as dirname38, join as join83 } from "path";
function readStages(projectRoot, sessionId, feature) {
if (feature === null) return [];
try {
return foldFeature(projectRoot, sessionId, feature).stages.map((stage) => ({
stage: stage.stage,
state: stage.state
}));
} catch {
return [];
}
}
function readCriteria(projectRoot, feature) {
if (feature === null) return [];
const spec = readFeatureSpecification(projectRoot, feature);
if (!spec || !Array.isArray(spec.acceptance_criteria)) return [];
return spec.acceptance_criteria.map((criterion) => ({
criterion_id: criterion.criterion_id,
given: criterion.given,
when: criterion.when,
then: criterion.then,
proof_type: criterion.proof_type
}));
}
async function writeReviewDigest(projectRoot, sessionId, now = () => /* @__PURE__ */ new Date()) {
let feature;
try {
feature = currentFeature(projectRoot, sessionId);
} catch {
feature = null;
}
const ownFiles = activeChangeFiles(projectRoot, sessionId);
const findings = scopeFindingsToChange(
collectMachineFindings(projectRoot),
ownFiles,
projectRoot
);
const changedFiles = ownFiles ?? (await loadChangeEvidence(projectRoot)).files;
const markdown = buildReviewDigest({
feature,
generated_at: now().toISOString(),
changed_files: changedFiles,
stages: readStages(projectRoot, sessionId, feature),
criteria: readCriteria(projectRoot, feature),
findings
});
const target = join83(projectRoot, PATHS.REVIEW_DIGEST);
mkdirSync20(dirname38(target), { recursive: true });
writeFileSync21(target, markdown, "utf8");
return { path: PATHS.REVIEW_DIGEST, feature, findings: findings.length, markdown };
}
// src/verification/gates/implementation-review.ts
function activeReview(projectRoot) {
try {
const sessionId = resolveSessionId(projectRoot, process.env.CLAUDE_SESSION_ID ?? null);
const dirName = currentFeature(projectRoot, sessionId);
return dirName ? readFeatureReview(projectRoot, dirName) : null;
} catch {
return null;
}
}
function reviewText(review) {
if (!review) return "";
return [
review.summary,
review.rollback,
...review.checked ?? [],
...(review.findings ?? []).flatMap((finding) => [finding.description, finding.file ?? ""])
].join("\n");
}
var ImplementationReviewGate = class {
gate = "implementation-review";
async check(context) {
const findings = context.implementation_review_findings ?? [];
const blocking = findings.filter((finding) => finding.severity === "error");
if (blocking.length > 0) {
return createFail(
this.gate,
`Implementation review found blocking defects: ${blocking.map((finding) => finding.detail).join("; ")}`,
"Resolve implementation review findings before continuing."
);
}
if (context.change_own_files?.length === 0 && !context.change_past_specification) {
return createNotRequired(this.gate, "no files changed in this change yet");
}
const review = activeReview(context.project_root);
const unaddressed = unanchoredMachineFindings(
scopeFindingsToChange(
collectMachineFindings(context.project_root),
context.change_own_files,
context.project_root
),
reviewText(review)
);
if (unaddressed.length > 0) {
return createFail(
this.gate,
`Review does not address ${unaddressed.length} deterministic machine finding(s): ${unaddressed.map((finding) => `${findingAnchor(finding)} (${finding.source})`).join("; ")}`,
"Run `paqad-ai review digest`, then confirm or contest each finding in the review (cite its file:line)."
);
}
const warnings = findings.filter((finding) => finding.severity === "warning");
if (warnings.length > 0) {
return createPass(
this.gate,
`Implementation review passed with warnings: ${warnings.map((finding) => finding.detail).join("; ")}`
);
}
if (context.implementation_review_passed && !review) {
return context.lane === "fast" ? createNotRequired(this.gate, "This lane has no review stage.") : createDidNotRun(
this.gate,
"No review is on record for this change, so nothing was reviewed."
);
}
return checkBooleanGate(
this.gate,
context.implementation_review_passed,
"Implementation review passed",
"Implementation review failed",
"Resolve implementation review findings before continuing."
);
}
};
// src/verification/gates/instructions-docs-structure.ts
init_esm_shims();
var import_yaml9 = __toESM(require_dist(), 1);
import { existsSync as existsSync40 } from "fs";
import { readFile as readFile39 } from "fs/promises";
import { extname as extname5, join as join84 } from "path";
// src/workflows/template-validator.ts
init_esm_shims();
var WorkflowTemplateValidator = class {
validate(template, availableSkills) {
const errors = [];
if (!template.name) errors.push("Template must have a name");
if (!template.steps || template.steps.length === 0)
errors.push("Template must have at least one step");
for (let i = 0; i < (template.steps ?? []).length; i++) {
const step = template.steps[i];
if (this.isParallelGroup(step)) {
for (const subStep of step.parallel) {
if (!availableSkills.has(subStep.skill)) {
errors.push(`Step ${i}: unknown skill "${subStep.skill}" in parallel group`);
}
if (subStep.on_failure && !["skip", "abort", "retry"].includes(subStep.on_failure)) {
errors.push(`Step ${i}: invalid on_failure value "${subStep.on_failure}"`);
}
}
} else {
if (!availableSkills.has(step.skill)) {
errors.push(`Step ${i}: unknown skill "${step.skill}"`);
}
if (step.on_failure && !["skip", "abort", "retry"].includes(step.on_failure)) {
errors.push(`Step ${i}: invalid on_failure value "${step.on_failure}"`);
}
}
}
return { valid: errors.length === 0, errors };
}
isParallelGroup(step) {
return "parallel" in step;
}
};
// src/verification/gates/instructions-docs-structure.ts
var REMEDIATION3 = "Move instruction documentation under an approved docs/instructions/{rules,stack,architecture,design-system,registries,workflows,tools,benchmarks,tech-debt,site-map}/ path.";
var NON_CANONICAL_ROOTS = [
"docs/instruction/",
"docs/instruction-docs/",
"docs/instructions-docs/"
];
var ALLOWED_TOP_LEVEL_AREAS = /* @__PURE__ */ new Set([
"rules",
"stack",
"architecture",
"design-system",
"registries",
"workflows",
"tools",
"benchmarks",
"tech-debt"
]);
var InstructionsDocsStructureGate = class {
gate = "instructions-docs-structure";
async check(context) {
const changedFiles = context.changed_files.map(normalizePath4);
if (!isProviderCompletionCheck(context)) {
const touched = changedFiles.some(
(filePath) => ["docs/instructions/", ...NON_CANONICAL_ROOTS].some((root) => isUnderPath(filePath, root))
);
return touched ? createDidNotRun(
this.gate,
"Did not run: instruction doc structure is checked only at the in-session completion check."
) : createNotRequired(this.gate, "Not required: no instruction doc changed.");
}
const nonCanonicalPath = changedFiles.find(
(filePath) => NON_CANONICAL_ROOTS.some((root) => isUnderPath(filePath, root))
);
if (nonCanonicalPath) {
return createFail(
this.gate,
`Invalid instruction documentation path ${nonCanonicalPath}`,
REMEDIATION3
);
}
const instructionPaths = changedFiles.filter(
(filePath) => isUnderPath(filePath, "docs/instructions/")
);
if (instructionPaths.length === 0) {
return createNotRequired(this.gate, "Not required: no instruction doc changed.");
}
for (const filePath of instructionPaths) {
const structuralError = validateInstructionPath(filePath);
if (structuralError) {
return createFail(this.gate, structuralError, REMEDIATION3);
}
const absolutePath = join84(context.project_root, ...filePath.split("/"));
if (!existsSync40(absolutePath)) {
return createFail(
this.gate,
`Instruction documentation file ${filePath} does not exist`,
"Restore the touched instruction documentation file before completing the provider request."
);
}
const contentError = await validateFileContent(absolutePath, filePath);
if (contentError) {
return createFail(this.gate, contentError.detail, contentError.remediation);
}
}
return createPass(this.gate, "Instruction documentation structure is valid");
}
};
function validateInstructionPath(filePath) {
if (hasHiddenOrSystemSegment(filePath)) {
return `Invalid instruction documentation path ${filePath}`;
}
const segments = filePath.split("/");
if (segments.length < 4 || segments[0] !== "docs" || segments[1] !== "instructions") {
return `Invalid instruction documentation path ${filePath}`;
}
const area = segments[2];
if (!ALLOWED_TOP_LEVEL_AREAS.has(area)) {
return `Invalid instruction documentation path ${filePath}`;
}
switch (area) {
case "rules":
return validateRulesPath(filePath, segments);
case "stack":
return validateFlatExtensionPath(filePath, segments, [".md"]);
case "architecture":
return validateFlatExtensionPath(filePath, segments, [".md", ".json"]);
case "design-system":
return validateFlatExtensionPath(filePath, segments, [".md", ".json", ".css"]);
case "registries":
return validateFlatExtensionPath(filePath, segments, [".md"]);
case "workflows":
return validateFlatExtensionPath(filePath, segments, [".yaml", ".yml"]);
case "tools":
return validateToolsPath(filePath, segments);
case "benchmarks":
case "tech-debt":
return validateFlatExtensionPath(filePath, segments, [".md"]);
/* v8 ignore start -- ALLOWED_TOP_LEVEL_AREAS is exhaustive with the switch cases above */
default:
return `Invalid instruction documentation path ${filePath}`;
}
}
function validateRulesPath(filePath, segments) {
if (segments.length === 4) {
const filename = segments[3];
if (filename === "writing-style.md" || filename === "module-map.yml" || filename === "module-map.yaml") {
return null;
}
return `Invalid instruction documentation path ${filePath}`;
}
if (segments.length === 5 && extname5(filePath) === ".md" && segments[3].length > 0) {
return null;
}
return `Invalid instruction documentation path ${filePath}`;
}
function validateToolsPath(filePath, segments) {
if (segments.length === 5 && segments[3].length > 0 && extname5(filePath) === ".md") {
return null;
}
return `Invalid instruction documentation path ${filePath}`;
}
function validateFlatExtensionPath(filePath, segments, allowedExtensions) {
if (segments.length !== 4 || !allowedExtensions.includes(extname5(filePath))) {
return `Invalid instruction documentation path ${filePath}`;
}
return null;
}
async function validateFileContent(absolutePath, relativePath) {
const content = await readFile39(absolutePath, "utf8");
const extension = extname5(relativePath);
if (extension === ".md") {
if (content.trim().length === 0) {
return {
detail: `Instruction markdown file ${relativePath} is empty`,
remediation: "Add non-empty markdown content before completing the provider request."
};
}
if (!hasMarkdownHeading(content)) {
return {
detail: `Instruction markdown file ${relativePath} does not contain a heading`,
remediation: "Add at least one markdown heading before completing the provider request."
};
}
return null;
}
if (extension === ".yaml" || extension === ".yml") {
let parsed;
try {
parsed = (0, import_yaml9.parse)(content);
} catch {
return {
detail: `Instruction YAML file ${relativePath} does not parse`,
remediation: "Fix the YAML syntax before completing the provider request."
};
}
if (isModuleMap(relativePath) && !hasTopLevelModulesArray(parsed)) {
return {
detail: `Instruction module map ${relativePath} must contain a top-level modules array`,
remediation: "Add a top-level modules array to the instruction rule module map before completing the provider request."
};
}
if (isModuleMap(relativePath)) {
return validateModuleMap(parsed, relativePath);
}
return validateWorkflowYaml(parsed, relativePath);
}
if (extension === ".json") {
try {
JSON.parse(content);
return null;
} catch {
return {
detail: `Instruction JSON file ${relativePath} does not parse`,
remediation: "Fix the JSON syntax before completing the provider request."
};
}
}
if (content.trim().length === 0) {
return {
detail: `Instruction CSS file ${relativePath} is empty`,
remediation: "Add non-empty CSS content before completing the provider request."
};
}
return null;
}
function normalizePath4(filePath) {
return filePath.replaceAll("\\", "/").replace(/^\.?\//, "");
}
function isUnderPath(filePath, prefix) {
return filePath === prefix.slice(0, -1) || filePath.startsWith(prefix);
}
function isProviderCompletionCheck(context) {
return context.verification_origin === "provider-workflow" && context.verification_stage === "provider-completion";
}
function hasHiddenOrSystemSegment(filePath) {
return filePath.split("/").some((segment) => segment.startsWith("."));
}
function hasMarkdownHeading(markdown) {
return markdown.split(/\r?\n/u).some((line) => /^#{1,6}\s+\S/u.test(line.trim()));
}
function isModuleMap(relativePath) {
return relativePath === "docs/instructions/rules/module-map.yml" || relativePath === "docs/instructions/rules/module-map.yaml";
}
function hasTopLevelModulesArray(value) {
return typeof value === "object" && value !== null && "modules" in value && Array.isArray(value.modules);
}
function validateModuleMap(value, relativePath) {
if (!isPlainObject4(value)) {
return moduleMapError(relativePath, "must be a YAML mapping");
}
const requiredRootFields = ["version", "last_updated_at", "domain_glossary", "modules"];
for (const field of requiredRootFields) {
if (!(field in value)) {
return moduleMapError(relativePath, `is missing required field ${field}`);
}
}
if (typeof value["version"] !== "number") {
return moduleMapError(relativePath, "field version must be a number");
}
if (typeof value["last_updated_at"] !== "string" || value["last_updated_at"].trim() === "") {
return moduleMapError(relativePath, "field last_updated_at must be a non-empty string");
}
if (!isDomainGlossary(value["domain_glossary"])) {
return moduleMapError(
relativePath,
"field domain_glossary must include preferred_terms, synonyms, and notes"
);
}
if (!Array.isArray(value["modules"])) {
return moduleMapError(relativePath, "field modules must be an array");
}
for (const [index, moduleEntry] of value["modules"].entries()) {
const error = validateModuleMapEntry(moduleEntry, `modules[${index}]`);
if (error) {
return moduleMapError(relativePath, error);
}
}
return null;
}
function validateModuleMapEntry(value, path10) {
if (!isPlainObject4(value)) {
return `${path10} must be a mapping`;
}
const requiredFields = [
"name",
"slug",
"auto_update_module_name",
"derivation",
"confidence",
"source_paths",
"evidence",
"features"
];
for (const field of requiredFields) {
if (!(field in value)) {
return `${path10} is missing required field ${field}`;
}
}
const scalarError = validateSharedMapFields(value, path10, "auto_update_module_name");
if (scalarError) {
return scalarError;
}
if (!isEvidenceMap(value["evidence"])) {
return `${path10}.evidence must be a mapping with routes, tables, and/or symbols arrays`;
}
if (!Array.isArray(value["features"])) {
return `${path10}.features must be an array`;
}
for (const [index, feature] of value["features"].entries()) {
const featureError = validateModuleFeatureEntry(feature, `${path10}.features[${index}]`);
if (featureError) {
return featureError;
}
}
return null;
}
function validateModuleFeatureEntry(value, path10) {
if (!isPlainObject4(value)) {
return `${path10} must be a mapping`;
}
const requiredFields = [
"name",
"slug",
"auto_update_feature_name",
"derivation",
"confidence",
"source_paths"
];
for (const field of requiredFields) {
if (!(field in value)) {
return `${path10} is missing required field ${field}`;
}
}
return validateSharedMapFields(value, path10, "auto_update_feature_name");
}
function validateSharedMapFields(value, path10, autoUpdateField) {
if (typeof value["name"] !== "string" || value["name"].trim() === "") {
return `${path10}.name must be a non-empty string`;
}
if (typeof value["slug"] !== "string" || value["slug"].trim() === "") {
return `${path10}.slug must be a non-empty string`;
}
if (typeof value[autoUpdateField] !== "boolean") {
return `${path10}.${autoUpdateField} must be a boolean`;
}
if (!["user", "locked_manifest", "codebase_native", "inferred", "llm"].includes(
String(value["derivation"])
)) {
return `${path10}.derivation must be a valid derivation value`;
}
if (!["high", "medium", "low"].includes(String(value["confidence"]))) {
return `${path10}.confidence must be high, medium, or low`;
}
if (!isStringArray(value["source_paths"])) {
return `${path10}.source_paths must be an array of strings`;
}
return null;
}
function validateWorkflowYaml(value, relativePath) {
const filename = relativePath.split("/").at(-1) ?? relativePath;
if (isFeatureDevelopmentViewFile(filename)) {
const validation2 = new SchemaValidator().validate("feature-development-policy", value);
if (!validation2.valid) {
return {
detail: `Instruction workflow policy ${relativePath} is invalid`,
remediation: "Fix the feature-development policy schema before completing the provider request."
};
}
return null;
}
const template = value;
const availableSkills = collectReferencedTemplateSkills(template);
let validation;
try {
validation = new WorkflowTemplateValidator().validate(template, availableSkills);
} catch {
validation = { valid: false, errors: ["Template structure is invalid"] };
}
if (!validation.valid) {
return {
detail: `Instruction workflow template ${relativePath} is invalid`,
remediation: "Fix the custom workflow template name, steps, skills, and failure directives before completing the provider request."
};
}
return null;
}
function collectReferencedTemplateSkills(template) {
const skills = /* @__PURE__ */ new Set();
const steps = Array.isArray(template?.steps) ? template.steps : [];
for (const step of steps) {
if (isPlainObject4(step) && Array.isArray(step["parallel"])) {
for (const parallelStep of step["parallel"]) {
if (isPlainObject4(parallelStep) && typeof parallelStep["skill"] === "string") {
skills.add(parallelStep["skill"]);
}
}
} else if (isWorkflowStep(step) && typeof step.skill === "string") {
skills.add(step.skill);
}
}
return skills;
}
function isWorkflowStep(value) {
return isPlainObject4(value) && "skill" in value;
}
function moduleMapError(relativePath, reason2) {
return {
detail: `Instruction module map ${relativePath} ${reason2}`,
remediation: "Fix the instruction rule module map contract before completing the provider request."
};
}
function isDomainGlossary(value) {
return isPlainObject4(value) && isStringArray(value["preferred_terms"]) && isPlainObject4(value["synonyms"]) && Object.values(value["synonyms"]).every((entry) => typeof entry === "string") && typeof value["notes"] === "string";
}
function isEvidenceMap(value) {
if (!isPlainObject4(value)) {
return false;
}
return ["routes", "tables", "symbols"].every(
(field) => value[field] === void 0 || isStringArray(value[field])
);
}
function isStringArray(value) {
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
}
function isPlainObject4(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
// src/verification/gates/module-docs-structure.ts
init_esm_shims();
import { existsSync as existsSync41, readdirSync as readdirSync11 } from "fs";
import { readFile as readFile40 } from "fs/promises";
import { join as join85 } from "path";
var REQUIRED_FEATURE_DOCS = ["business.md", "technical.md", "api.md"];
var ModuleDocsStructureGate = class {
gate = "module-docs-structure";
async check(context) {
const changedFiles = context.changed_files.map(normalizePath5);
const legacyPath2 = changedFiles.find((filePath) => isUnderPath2(filePath, "docs/module/"));
if (legacyPath2) {
return createFail(
this.gate,
`Invalid module documentation path ${legacyPath2}; use docs/modules/`,
"Move feature documentation under docs/modules/{module}/features/{feature}/ before completing the provider request."
);
}
const moduleDocPaths = changedFiles.filter(
(filePath) => isUnderPath2(filePath, "docs/modules/")
);
if (moduleDocPaths.length === 0) {
return createNotRequired(this.gate, "Not required: no module doc changed.");
}
const scopedPaths = hasPreexistingFlatFeatureDocs(context.project_root, new Set(changedFiles)) ? moduleDocPaths.filter((filePath) => !isFlatFeatureDoc(filePath)) : moduleDocPaths;
const invalidFeatureDoc = scopedPaths.find((filePath) => isInvalidFeatureDocPath(filePath));
if (invalidFeatureDoc) {
return createFail(
this.gate,
`Feature documentation path ${invalidFeatureDoc} is outside docs/modules/{module}/features/{feature}/`,
"Place feature documentation under docs/modules/{module}/features/{feature}/ with business.md, technical.md, and api.md."
);
}
const scopes = collectTouchedFeatureScopes(scopedPaths);
if (scopes.length === 0) {
return createNotRequired(
this.gate,
"Not required: no module feature doc changed (only other module docs)."
);
}
for (const scope of scopes) {
for (const filename of REQUIRED_FEATURE_DOCS) {
const relativePath = `docs/modules/${scope.module}/features/${scope.feature}/${filename}`;
const absolutePath = join85(context.project_root, ...relativePath.split("/"));
if (!existsSync41(absolutePath)) {
return createFail(
this.gate,
`Missing ${relativePath}`,
`Create the missing feature-level ${formatDocKind(filename)} documentation file before completing the provider request.`
);
}
const markdown = await readFile40(absolutePath, "utf8");
if (markdown.trim().length === 0) {
return createFail(
this.gate,
`Required documentation file ${relativePath} is empty`,
"Add non-empty markdown content before completing the provider request."
);
}
if (!hasMarkdownHeading2(markdown)) {
return createFail(
this.gate,
`Required documentation file ${relativePath} does not contain a heading`,
"Add at least one markdown heading before completing the provider request."
);
}
}
}
return createPass(this.gate, "Module feature documentation structure is valid");
}
};
function normalizePath5(filePath) {
return filePath.replaceAll("\\", "/").replace(/^\.?\//, "");
}
function isUnderPath2(filePath, prefix) {
return filePath === prefix.slice(0, -1) || filePath.startsWith(prefix);
}
function isFlatFeatureDoc(filePath) {
const segments = filePath.split("/");
return segments.length === 5 && segments[0] === "docs" && segments[1] === "modules" && segments[2].length > 0 && segments[3] === "features" && segments[4].length > ".md".length && segments[4].endsWith(".md");
}
function hasPreexistingFlatFeatureDocs(projectRoot, changedSet) {
const modulesRoot = join85(projectRoot, "docs", "modules");
if (!existsSync41(modulesRoot)) {
return false;
}
let moduleEntries;
try {
moduleEntries = readdirSync11(modulesRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
} catch {
return false;
}
for (const moduleName of moduleEntries) {
const featuresDir = join85(modulesRoot, moduleName, "features");
let featureEntries;
try {
featureEntries = readdirSync11(featuresDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => entry.name);
} catch {
continue;
}
for (const filename of featureEntries) {
const relativePath = `docs/modules/${moduleName}/features/${filename}`;
if (!changedSet.has(relativePath)) {
return true;
}
}
}
return false;
}
function isInvalidFeatureDocPath(filePath) {
if (!filePath.endsWith(".md")) {
return false;
}
const segments = filePath.split("/");
const featuresIndex = segments.indexOf("features");
if (featuresIndex === -1) {
return false;
}
return segments.length !== 6 || segments[0] !== "docs" || segments[1] !== "modules" || segments[3] !== "features" || segments[2].length === 0 || segments[4].length === 0 || !REQUIRED_FEATURE_DOCS.includes(segments[5]);
}
function collectTouchedFeatureScopes(filePaths) {
const scopeKeys = /* @__PURE__ */ new Set();
const scopes = [];
for (const filePath of filePaths) {
const segments = filePath.split("/");
if (segments.length === 6 && segments[0] === "docs" && segments[1] === "modules" && segments[3] === "features" && REQUIRED_FEATURE_DOCS.includes(segments[5])) {
const scope = { module: segments[2], feature: segments[4] };
const key = `${scope.module}/${scope.feature}`;
if (!scopeKeys.has(key)) {
scopeKeys.add(key);
scopes.push(scope);
}
}
}
return scopes;
}
function hasMarkdownHeading2(markdown) {
return markdown.split(/\r?\n/u).some((line) => /^#{1,6}\s+\S/u.test(line.trim()));
}
function formatDocKind(filename) {
return filename.replace(".md", "");
}
// src/verification/gates/mutation-testing.ts
init_esm_shims();
var MUTATION_OFF_DETAIL = "Mutation testing is off (mutation_mode is off).";
var SKIP_READING = {
"fast-lane": {
kind: "not-required",
words: "Mutation testing is not required on the fast lane."
},
"no-changed-code": {
kind: "not-required",
words: "Mutation testing is not required: no code changed."
},
"tests-not-green": {
kind: "did-not-run",
words: "Mutation testing did not run: the test command was not green to begin with.",
remediation: "Make the test command pass, then run verification again."
},
"no-test-command": {
kind: "did-not-run",
words: "Mutation testing did not run: no test command is configured, so nothing proved the suite green first.",
remediation: "Set commands.test in .paqad/project-profile.yaml to the project test command, or set mutation_mode=off."
},
"tool-not-configured": {
kind: "did-not-run",
words: "Mutation testing did not run: no mutation tool is configured for this stack.",
remediation: "Install the mutation tool for this stack in the project, or set mutation_mode=off."
},
"run-failed": {
kind: "did-not-run",
words: "Mutation testing did not run: the mutation tool failed before it produced a result.",
remediation: "Check the mutation tool output, fix what stopped it, and run verification again."
}
};
function summarizeSurvivors(result2) {
const shown = result2.surviving_mutants.slice(0, 5).map((mutant) => `${mutant.file}:${mutant.line} (${mutant.operator})`).join(", ");
const extra = result2.surviving_mutants.length > 5 ? `, +${result2.surviving_mutants.length - 5} more` : "";
return `${shown}${extra}`;
}
var MutationTestingGate = class {
gate = "mutation-testing";
async check(context) {
const result2 = context.mutation_result;
if (!result2) {
return createNotRequired(this.gate, context.mutation_note ?? MUTATION_OFF_DETAIL);
}
if (result2.status === "skipped") {
const reading = result2.skipped_reason ? SKIP_READING[result2.skipped_reason] : void 0;
if (!reading) {
return createDidNotRun(
this.gate,
`Mutation testing did not run (${result2.skipped_reason ?? "no reason recorded"}).`
);
}
return reading.kind === "not-required" ? createNotRequired(this.gate, reading.words) : createDidNotRun(this.gate, reading.words, reading.remediation);
}
if (result2.status === "unsafe-tree") {
return createFail(
this.gate,
`Working tree was not clean after the mutation run (${result2.tool ?? "mutation tool"}); a mutant may have been left behind.`,
"Restore the tree to a clean state and re-run; mutation must always be fully reverted."
);
}
const killRate = result2.kill_rate === null ? "n/a" : `${result2.kill_rate}%`;
const counts = `killed ${result2.killed}, survived ${result2.survived}, set-aside ${result2.equivalent_set_aside}`;
if (result2.status === "lower-confidence") {
return createInconclusive(
this.gate,
`Mutation result is lower-confidence (${result2.tool ?? result2.language ?? "best-available tool"}); kill rate ${killRate} (${counts}).`,
"Treat this score as indicative only; a mature mutation tool is not available for this language."
);
}
if (result2.status === "survivors") {
const detail = `${result2.survived} behaviour-changing mutant(s) survived (kill rate ${killRate}): ${summarizeSurvivors(result2)}.`;
const remediation = "Strengthen the tests so each surviving mutant is caught, or confirm any genuinely equivalent.";
return context.mutation_strict ? createFail(this.gate, detail, remediation) : createInconclusive(this.gate, detail, remediation);
}
return createPass(
this.gate,
`Every behaviour-changing mutant was killed (kill rate ${killRate}; ${counts}).`
);
}
};
// src/verification/gates/quality-ratchet.ts
init_esm_shims();
function summarizeRegressions(result2) {
const shown = result2.blocking_regressions.slice(0, 5).map((r) => `${r.measure}@${r.module} ${r.baseline_value ?? "n/a"}\u2192${r.current_value ?? "n/a"}`).join(", ");
const extra = result2.blocking_regressions.length > 5 ? `, +${result2.blocking_regressions.length - 5} more` : "";
return `${shown}${extra}`;
}
function measureWords(measure) {
return measure.replace(/_/g, " ");
}
function ratchetMeasureScope(result2) {
const taken = /* @__PURE__ */ new Set();
const blocked = /* @__PURE__ */ new Set();
for (const verdict2 of result2.verdicts) {
const words = measureWords(verdict2.measure);
if (verdict2.outcome === "blocked" || verdict2.current_value === null) blocked.add(words);
else taken.add(words);
}
return { taken: [...taken], blocked: [...blocked] };
}
function scopeNote(result2, scope) {
const blocked = scope.blocked.length > 0 ? `; blocked: ${scope.blocked.join(", ")}` : "";
if (result2.lane === "fast") return ` (fast lane, strictness only${blocked})`;
return ` (measured: ${scope.taken.join(", ")}${blocked})`;
}
function comparedCount(result2) {
const compared = result2.verdicts.filter(
(verdict2) => verdict2.outcome !== "blocked" && verdict2.current_value !== null
).length;
return `${compared} ${compared === 1 ? "measure" : "measures"} compared`;
}
var QualityRatchetGate = class {
gate = "quality-ratchet";
async check(context) {
const result2 = context.quality_ratchet_result;
if (!result2) {
return createDidNotRun(
this.gate,
"Quality ratchet did not run, so no quality measure was compared."
);
}
if (result2.status === "skipped") {
return createDidNotRun(
this.gate,
`Quality ratchet did not run (${result2.skipped_reason ?? "no measures to evaluate"}).`
);
}
if (result2.status === "regressed") {
const excepted2 = result2.excepted_regressions.length > 0 ? ` (${result2.excepted_regressions.length} approved exception(s) allowed)` : "";
return createFail(
this.gate,
`${result2.blocking_regressions.length} quality measure(s) worsened against the baseline${excepted2}: ${summarizeRegressions(result2)}.`,
"Bring each measure back to at least its recorded level, or open a quality.ratchet_exception pause to approve a legitimate regression."
);
}
const scope = ratchetMeasureScope(result2);
if (scope.taken.length === 0) {
const blocked = scope.blocked.length > 0 ? ` (blocked: ${scope.blocked.join(", ")})` : "";
return createDidNotRun(
this.gate,
`Quality ratchet did not run: no quality measure could be taken${blocked}.`,
"Wire the tool each blocked measure reads (for example a tsconfig for strictness) so the ratchet can compare it."
);
}
if (result2.status === "captured") {
return createDidNotRun(
this.gate,
`Quality baseline captured at today's level${scopeNote(result2, scope)}; nothing to compare yet.`
);
}
const tightened = result2.tightened.length > 0 ? `; ${result2.tightened.length} measure(s) tightened` : "";
const excepted = result2.excepted_regressions.length > 0 ? `; ${result2.excepted_regressions.length} approved exception(s)` : "";
return createPass(
this.gate,
`Every quality measure held equal or better${scopeNote(result2, scope)}, ${comparedCount(result2)}${tightened}${excepted}.`
);
}
};
// src/verification/gates/requirement-completeness.ts
init_esm_shims();
var RequirementCompletenessGate = class {
gate = "requirement-completeness";
async check(context) {
return checkJudgedGate(
this.gate,
context.requirements_complete,
"Requirements are complete",
"Requirements are incomplete",
"Complete the missing requirements before proceeding.",
"No requirement check was recorded, so this gate did not run."
);
}
};
// src/verification/gates/site-map-freshness.ts
init_esm_shims();
// src/site-map/freshness.ts
init_esm_shims();
// src/site-map/verification.ts
init_esm_shims();
var NAVIGATIONAL_KINDS = /* @__PURE__ */ new Set([
"page",
"screen",
"modal",
"router",
"prompt-entry",
"llm-workflow",
"step",
"subflow"
]);
function normalizeEvidence(ref) {
if (ref === void 0) return [];
return Array.isArray(ref) ? ref : [ref];
}
function buildStatusOf(resolutions) {
const status = /* @__PURE__ */ new Map();
for (const resolution of resolutions) {
status.set(evidenceKey({ file: resolution.file, line: resolution.line }), resolution.status);
}
return (pointer) => status.get(evidenceKey(pointer)) ?? "resolved";
}
function asList(ref) {
if (ref === void 0) return [];
return Array.isArray(ref) ? ref : [ref];
}
function evidenceKey(pointer) {
return `${pointer.file}\0${pointer.line ?? ""}`;
}
function locate(pointer) {
return pointer.line === void 0 ? pointer.file : `${pointer.file}:${pointer.line}`;
}
function collectMapEvidence(map) {
if (map === null) return [];
const byKey = /* @__PURE__ */ new Map();
const add = (ref) => {
for (const pointer of normalizeEvidence(ref)) {
const key = evidenceKey(pointer);
if (!byKey.has(key)) byKey.set(key, pointer);
}
};
for (const surface2 of map.surfaces) {
add(surface2.evidence);
for (const transition of surface2.transitions ?? []) add(transition.evidence);
}
for (const guard of map.guards ?? []) add(guard.evidence);
return [...byKey.values()];
}
function isBackstage(surface2, areaById) {
if (surface2.visibility !== void 0) return surface2.visibility === "backstage";
const area = surface2.area === void 0 ? void 0 : areaById.get(surface2.area);
return area?.visibility === "backstage";
}
function isGuarded(surface2, areaById) {
if (asList(surface2.guard).length > 0) return true;
const area = surface2.area === void 0 ? void 0 : areaById.get(surface2.area);
return asList(area?.guard).length > 0;
}
function hasTerminalMarker(surface2) {
const ends = surface2.ends;
if (ends === void 0) return false;
return Boolean(ends.success) || Boolean(ends.failure) || Boolean(ends.abandoned);
}
function detectEvidenceFindings(map, resolutions) {
const statusOf = buildStatusOf(resolutions);
const candidates = [];
for (const surface2 of map.surfaces) {
const pointers = normalizeEvidence(surface2.evidence);
if (pointers.length === 0) continue;
const broken = pointers.filter((pointer) => statusOf(pointer) !== "resolved");
if (broken.length === 0) continue;
const files = [...new Set(broken.map((pointer) => pointer.file))].sort();
if (broken.length === pointers.length && broken.every((p) => statusOf(p) === "file-missing")) {
candidates.push({
title: `Removed surface: ${surface2.label}`,
description: `The ${surface2.kind} "${surface2.label}" is on the map, but every file it cites is gone from the tree, so the map describes code that no longer exists.`,
category: "SM-REMOVE",
severity: "high",
tier: "deterministic",
confidence: 1,
evidence: broken.map(
(pointer) => `app-map.yaml surface "${surface2.id}" cites ${pointer.file} \u2014 file not found`
),
resolution: `Remove surface "${surface2.id}" from ${PATHS.SITE_MAP_CANONICAL_APP_MAP}, or point its evidence at the code that replaced it.`,
affected_surfaces: [surface2.id],
affected_files: files,
baseline_status: "unknown",
status: "open"
});
continue;
}
candidates.push(
evidenceDefect(
`surface "${surface2.id}"`,
`surface "${surface2.label}"`,
surface2.id,
broken,
(pointer) => `app-map.yaml surface "${surface2.id}" cites ${locate(pointer)} \u2014 ${reason(statusOf(pointer))}`
)
);
}
for (const guard of map.guards ?? []) {
const broken = normalizeEvidence(guard.evidence).filter((p) => statusOf(p) !== "resolved");
if (broken.length === 0) continue;
candidates.push(
evidenceDefect(
`guard "${guard.id}"`,
`guard "${guard.label}"`,
void 0,
broken,
(pointer) => `app-map.yaml guard "${guard.id}" cites ${locate(pointer)} \u2014 ${reason(statusOf(pointer))}`
)
);
}
for (const surface2 of map.surfaces) {
for (const transition of surface2.transitions ?? []) {
const broken = normalizeEvidence(transition.evidence).filter(
(p) => statusOf(p) !== "resolved"
);
if (broken.length === 0) continue;
candidates.push(
evidenceDefect(
`transition ${surface2.id} \u2192 ${transition.to}`,
`the transition from "${surface2.id}" to "${transition.to}"`,
surface2.id,
broken,
(pointer) => `app-map.yaml transition ${surface2.id} \u2192 ${transition.to} cites ${locate(pointer)} \u2014 ${reason(statusOf(pointer))}`
)
);
}
}
return candidates;
}
function reason(status) {
return status === "file-missing" ? "file not found" : "line out of range";
}
function evidenceDefect(ownerId, ownerPhrase, affectedSurface, broken, proof) {
const files = [...new Set(broken.map((pointer) => pointer.file))].sort();
return {
title: `Stale evidence on ${ownerId}`,
description: `The evidence for ${ownerPhrase} no longer resolves in the tree, so the map cites code that has moved or been deleted and can no longer be trusted as proof.`,
category: "SM-EVIDENCE",
severity: "medium",
tier: "deterministic",
confidence: 1,
evidence: broken.map(proof),
resolution: `Re-anchor the evidence for ${ownerPhrase} to its current file:line, or remove the stale pointer, in ${PATHS.SITE_MAP_CANONICAL_APP_MAP}.`,
affected_surfaces: affectedSurface === void 0 ? [] : [affectedSurface],
affected_files: files,
baseline_status: "unknown",
status: "open"
};
}
function detectDanglingReferences(map) {
const surfaceIds = new Set(map.surfaces.map((surface2) => surface2.id));
const guardIds = new Set((map.guards ?? []).map((guard) => guard.id));
const candidates = [];
const guardRef = (refs, ownerId, ownerPhrase, affectedSurface) => {
for (const id of refs.flatMap(asList)) {
if (guardIds.has(id)) continue;
candidates.push({
title: `Undefined guard "${id}" referenced by ${ownerId}`,
description: `${ownerPhrase} requires guard "${id}", but no guard with that id is defined, so the map claims a protection that does not exist.`,
category: "SM-XREF",
severity: "high",
tier: "deterministic",
confidence: 1,
evidence: [`app-map.yaml \u2014 ${ownerId} references guard "${id}" (not in guards)`],
resolution: `Define a guard with id "${id}" in ${PATHS.SITE_MAP_CANONICAL_APP_MAP}, or correct the reference on ${ownerId}.`,
affected_surfaces: affectedSurface === void 0 ? [] : [affectedSurface],
affected_files: [],
baseline_status: "unknown",
status: "open"
});
}
};
for (const surface2 of map.surfaces) {
guardRef(
[surface2.guard, surface2.guard_not],
`surface "${surface2.id}"`,
`Surface "${surface2.label}"`,
surface2.id
);
for (const transition of surface2.transitions ?? []) {
if (!surfaceIds.has(transition.to)) {
candidates.push({
title: `Dangling transition: ${surface2.id} \u2192 ${transition.to}`,
description: `Surface "${surface2.id}" has a "${transition.trigger}" transition to "${transition.to}", but no surface with that id exists, so the path leads nowhere.`,
category: "SM-XREF",
severity: "high",
tier: "deterministic",
confidence: 1,
evidence: [
`app-map.yaml \u2014 transition ${surface2.id} \u2192 ${transition.to} (no such surface)`
],
resolution: `Add a surface with id "${transition.to}" to ${PATHS.SITE_MAP_CANONICAL_APP_MAP}, or repoint the "${transition.trigger}" transition on "${surface2.id}" at an existing surface.`,
affected_surfaces: [surface2.id],
affected_files: [],
baseline_status: "unknown",
status: "open"
});
}
guardRef(
[transition.guard, transition.guard_not],
`transition ${surface2.id} \u2192 ${transition.to}`,
`The transition from "${surface2.id}" to "${transition.to}"`,
surface2.id
);
}
}
for (const area of map.areas ?? []) {
guardRef([area.guard], `area "${area.id}"`, `Area "${area.label}"`, void 0);
}
for (const actor of map.actors ?? []) {
guardRef([actor.satisfies], `actor "${actor.id}"`, `Actor "${actor.label}"`, void 0);
}
return candidates;
}
function reachableFrom(roots, surfaces) {
const surfaceIds = new Set(surfaces.map((surface2) => surface2.id));
const outgoing = /* @__PURE__ */ new Map();
for (const surface2 of surfaces) {
outgoing.set(
surface2.id,
(surface2.transitions ?? []).map((transition) => transition.to).filter((to) => surfaceIds.has(to))
);
}
const reached = /* @__PURE__ */ new Set();
const queue = [...roots];
while (queue.length > 0) {
const id = queue.shift();
if (reached.has(id)) continue;
reached.add(id);
for (const next of outgoing.get(id)) queue.push(next);
}
return reached;
}
function detectGraphInvariants(map) {
const candidates = [];
const blocked = [];
const areaById = new Map((map.areas ?? []).map((area) => [area.id, area]));
const hasGraph = map.surfaces.some((surface2) => (surface2.transitions?.length ?? 0) > 0);
if (hasGraph) {
const roots = map.surfaces.filter((surface2) => surface2.entry !== void 0).map((s) => s.id);
if (roots.length === 0) {
blocked.push({
check: "reachability",
reason: "the map models transitions but marks no entry surface, so the graph has no root",
install_hint: `Mark at least one surface with an \`entry:\` block in ${PATHS.SITE_MAP_CANONICAL_APP_MAP} so reachability can be computed.`
});
} else {
const reached = reachableFrom(roots, map.surfaces);
for (const surface2 of map.surfaces) {
if (reached.has(surface2.id)) continue;
candidates.push({
title: `Orphan surface: ${surface2.label}`,
description: `The ${surface2.kind} "${surface2.label}" cannot be reached from any entry surface, so no user path leads to it \u2014 it is either dead code or an unmapped transition.`,
category: "SM-ORPHAN",
severity: "medium",
tier: "deterministic",
confidence: 1,
evidence: [`app-map.yaml \u2014 surface "${surface2.id}" is unreachable from every entry`],
resolution: `Add a transition that reaches "${surface2.id}", give it its own \`entry:\`, or remove it from ${PATHS.SITE_MAP_CANONICAL_APP_MAP}.`,
affected_surfaces: [surface2.id],
affected_files: [],
baseline_status: "unknown",
status: "open"
});
}
}
for (const surface2 of map.surfaces) {
if (!NAVIGATIONAL_KINDS.has(surface2.kind)) continue;
if (hasTerminalMarker(surface2)) continue;
if ((surface2.transitions?.length ?? 0) > 0) continue;
candidates.push({
title: `Dead-end surface: ${surface2.label}`,
description: `The ${surface2.kind} "${surface2.label}" has no outgoing transition and is not marked terminal, so a user who reaches it has no modelled way to leave.`,
category: "SM-DEADEND",
severity: "low",
tier: "deterministic",
confidence: 1,
evidence: [
`app-map.yaml \u2014 surface "${surface2.id}" has no outgoing transition and no \`ends\``
],
resolution: `Add an outgoing transition to "${surface2.id}", or mark it terminal with an \`ends:\` block, in ${PATHS.SITE_MAP_CANONICAL_APP_MAP}.`,
affected_surfaces: [surface2.id],
affected_files: [],
baseline_status: "unknown",
status: "open"
});
}
} else {
blocked.push({
check: "reachability",
reason: "the map records no navigation between screens, so reachability and dead ends cannot be checked",
install_hint: `Record transitions between surfaces in ${PATHS.SITE_MAP_CANONICAL_APP_MAP} so reachability and dead ends can be checked.`
});
}
for (const surface2 of map.surfaces) {
if (!isBackstage(surface2, areaById)) continue;
if (isGuarded(surface2, areaById)) continue;
candidates.push({
title: `Unguarded sensitive surface: ${surface2.label}`,
description: `The backstage ${surface2.kind} "${surface2.label}" carries no guard, so the map shows a sensitive surface with nothing gating access to it.`,
category: "SM-GUARDLESS",
severity: "high",
tier: "deterministic",
confidence: 1,
evidence: [`app-map.yaml \u2014 backstage surface "${surface2.id}" has no guard`],
resolution: `Add a \`guard:\` to surface "${surface2.id}" (or to its area) in ${PATHS.SITE_MAP_CANONICAL_APP_MAP}, or reclassify it as frontstage if it is not sensitive.`,
affected_surfaces: [surface2.id],
affected_files: [],
baseline_status: "unknown",
status: "open"
});
}
return { candidates, blocked };
}
function collectVerificationFindings(map, resolutions) {
if (map === null) {
return {
candidates: [],
blockedChecks: [
{
check: "map-present",
reason: `no site map has been authored at ${PATHS.SITE_MAP_CANONICAL_APP_MAP} yet, so there is nothing to check the code against`,
install_hint: `Author the site map at ${PATHS.SITE_MAP_CANONICAL_APP_MAP} (one surface entry per page, screen, or command), then run the site-map workflow to verify it.`
}
]
};
}
const graph = detectGraphInvariants(map);
return {
candidates: [
...detectEvidenceFindings(map, resolutions),
...detectDanglingReferences(map),
...graph.candidates
],
blockedChecks: graph.blocked
};
}
// src/site-map/freshness.ts
function deriveMapFreshness(map, resolutions) {
const anchors = collectMapEvidence(map);
const statusOf = buildStatusOf(resolutions);
const anchors_total = anchors.length;
const anchors_broken = anchors.filter((anchor) => statusOf(anchor) !== "resolved").length;
return {
anchors_total,
anchors_resolved: anchors_total - anchors_broken,
anchors_broken
};
}
function sameFreshness(a, b) {
return a !== void 0 && a.anchors_total === b.anchors_total && a.anchors_resolved === b.anchors_resolved && a.anchors_broken === b.anchors_broken;
}
function stampMapFreshness(map, freshness) {
if (sameFreshness(map.app.freshness, freshness)) return { map, changed: false };
return { map: { ...map, app: { ...map.app, freshness } }, changed: true };
}
function isStale2(freshness) {
return freshness.anchors_broken > 0;
}
// src/verification/gates/site-map-freshness.ts
var REFRESH_REMEDIATION = "Hit Run on the Site map area of `paqad-ai dashboard` to refresh the map before treating the change as complete.";
var SiteMapFreshnessGate = class {
gate = "site-map-freshness";
async check(context) {
if (!resolveFrameworkConfig(context.project_root).features.site_map) {
return createPass(this.gate, "Site map capability is off");
}
if (!context.code_changed) {
return createPass(this.gate, "No code change to drift the site map");
}
const storedMap = readCanonicalSiteMap(context.project_root);
const freshness = storedMap?.app.freshness;
if (freshness !== void 0 && isStale2(freshness)) {
return createFail(
this.gate,
`Site map has drifted from code: ${freshness.anchors_broken} of ${freshness.anchors_total} cited anchors no longer resolve`,
REFRESH_REMEDIATION
);
}
return createPass(this.gate, "Site map is current");
}
};
// src/verification/gates/spec-review.ts
init_esm_shims();
var SpecReviewGate = class {
gate = "spec-review";
async check(context) {
if (context.lane === "fast" && !context.spec_review_on_record && context.spec_review_passed) {
return createNotRequired(this.gate, "This lane has no specification stage to review.");
}
if (context.spec_review_passed && context.spec_review_inconclusive) {
return {
gate: this.gate,
passed: true,
inconclusive: true,
detail: context.spec_review_detail ?? "Nothing on record proves the spec was reviewed."
};
}
return checkBooleanGate(
this.gate,
context.spec_review_passed,
"Spec review passed",
"Spec review failed",
"Resolve outstanding specification review findings."
);
}
};
// src/verification/gates/story-quality.ts
init_esm_shims();
var StoryQualityGate = class {
gate = "story-quality";
async check(context) {
return checkJudgedGate(
this.gate,
context.story_quality_passed,
"Stories meet quality requirements",
"Story quality checks failed",
"Refine the story breakdown and acceptance criteria.",
"No story check was recorded, so this gate did not run."
);
}
};
// src/verification/gate-runner.ts
var DEFAULT_GATE_CODES = VERIFICATION_GATES.filter(
(gate) => GATE_CATALOG[gate].default_runner
);
var VerificationGateRunner = class {
constructor(gates = defaultGates()) {
this.gates = gates;
}
gates;
async run(context) {
const results = [];
let firstFailure = null;
for (const gate of this.gates) {
if (firstFailure && !shouldRunAfterFailure(gate, context)) {
results.push({
...createDidNotRun(gate.gate, skippedAfter(firstFailure)),
skip_reason: `${firstFailure.gate} ${failedWord(firstFailure)} first`
});
continue;
}
const result2 = await gate.check(context);
results.push(result2);
if (!result2.passed && firstFailure === null) {
firstFailure = result2;
}
}
return results;
}
async runWithDelta(context, baselineResults, escalationInput = {}) {
const results = await this.run(context);
return {
results,
delta_payload: buildVerificationGateDeltaPayload(
baselineResults.filter(ranInRun),
results.filter(ranInRun),
escalationInput
)
};
}
};
function shouldRunAfterFailure(gate, context) {
if (gate.gate === "module-docs-structure") {
return context.changed_files.some((filePath) => {
const normalized = normalizePath6(filePath);
return normalized.startsWith("docs/modules/") || normalized.startsWith("docs/module/");
});
}
if (gate.gate === "instructions-docs-structure") {
return context.changed_files.some((filePath) => {
const normalized = normalizePath6(filePath);
return normalized.startsWith("docs/instructions/") || normalized.startsWith("docs/instruction/") || normalized.startsWith("docs/instruction-docs/") || normalized.startsWith("docs/instructions-docs/");
});
}
if (gate.gate === "site-map-freshness") {
return context.changed_files.some(
(filePath) => normalizePath6(filePath).startsWith("docs/site-map/")
);
}
return false;
}
function ranInRun(result2) {
return !(result2.outcome === "did-not-run" && result2.skip_reason !== void 0);
}
function failedWord(failure) {
return failure.inconclusive ? "could not reach a result" : "failed";
}
function skippedAfter(failure) {
return `Did not run because ${failure.gate} ${failedWord(failure)} first.`;
}
function normalizePath6(filePath) {
return filePath.replaceAll("\\", "/").replace(/^\.?\//, "");
}
function defaultGates() {
return [
new ChangeCompletenessGate(),
new RequirementCompletenessGate(),
new StoryQualityGate(),
new AcTestMappingGate(),
new SpecReviewGate(),
new ArchitectureComplianceGate(),
new CodeTestsLintGate(),
new ImplementationReviewGate(),
new BehavioralCorrectnessGate(),
new MutationTestingGate(),
new QualityRatchetGate(),
new DatabaseQualityGate(),
new ModuleDocsStructureGate(),
new InstructionsDocsStructureGate(),
new DocumentationFreshnessGate(),
new SiteMapFreshnessGate(),
new ExtensionSurfaceGate()
];
}
// src/verification/repository/index.ts
init_esm_shims();
// src/verification/repository/repository-context.ts
init_esm_shims();
var import_fast_glob17 = __toESM(require_out(), 1);
import { readFile as readFile43, stat as stat2 } from "fs/promises";
import { join as join91 } from "path";
// src/checks/tree-identity.ts
init_esm_shims();
import { execFileSync as execFileSync8 } from "child_process";
import { copyFileSync, existsSync as existsSync42, mkdtempSync, rmSync as rmSync12, statSync as statSync6, utimesSync } from "fs";
import { tmpdir as tmpdir2 } from "os";
import { join as join86, resolve as resolve3 } from "path";
var TREE_IDENTITY_EXCLUDED_DIRS = [
PATHS.EVIDENCE_LEDGER_DIR,
PATHS.CHECKS_DIR,
PATHS.TRACEABILITY_DIR,
PATHS.DECISIONS_DIR
];
var TREE_IDENTITY_TIMEOUT_MS = 6e4;
var GITLINK_MODE = "160000";
var TreeIdentityError = class extends Error {
};
var GitCommandError = class extends Error {
};
function computeTreeIdentity(projectRoot, options = {}) {
return computeTreeIdentityResult(projectRoot, options).identity;
}
function computeTreeIdentityResult(projectRoot, options = {}) {
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
const nowMs = options.nowMs ?? (() => Date.now());
const deadline = nowMs() + (options.timeoutMs ?? TREE_IDENTITY_TIMEOUT_MS);
const git2 = (args, env2) => runGit(options.gitBinary ?? "git", args, projectRoot, deadline - nowMs(), env2);
let workDir = null;
try {
const head = resolveHead(git2);
const realIndex = resolve3(projectRoot, git2(["rev-parse", "--git-path", "index"]).trim());
if (!existsSync42(realIndex)) return { identity: null, reason: "the git index does not exist" };
workDir = mkdtempSync(join86(options.tempRoot ?? tmpdir2(), "paqad-tree-"));
const tempIndex = join86(workDir, "index");
copyFileSync(realIndex, tempIndex);
keepIndexTimestamp(realIndex, tempIndex);
const env2 = { ...process.env, GIT_INDEX_FILE: tempIndex };
git2(["add", "-A"], env2);
git2(
["rm", "-r", "--cached", "--ignore-unmatch", "--quiet", "--", ...TREE_IDENTITY_EXCLUDED_DIRS],
env2
);
const hidden = hiddenEditEntry(git2(["ls-files", "-s", "-v", "-z"], env2));
if (hidden) return { identity: null, reason: hidden };
const digest = git2(["write-tree"], env2).trim();
return { identity: { digest, head_commit: head, computed_at: now() }, reason: null };
} catch (error) {
return { identity: null, reason: error.message };
} finally {
if (workDir) rmSync12(workDir, { recursive: true, force: true });
}
}
function hiddenEditEntry(listing) {
for (const entry of listing.split("\0")) {
const match = /^(\S) (\d+) \S+ \d+\t(.+)$/s.exec(entry);
if (!match) continue;
const [, tag, mode, path10] = match;
if (mode === GITLINK_MODE) {
return `${path10} is a submodule or nested repository, so edits inside it cannot be seen`;
}
if (tag === "S" || tag !== tag.toUpperCase()) {
return `${path10} is marked assume-unchanged or skip-worktree, so its edits cannot be seen`;
}
}
return null;
}
function keepIndexTimestamp(realIndex, tempIndex) {
const stamp = (Math.floor(statSync6(realIndex).mtimeMs) - 1) / 1e3;
utimesSync(tempIndex, stamp, stamp);
}
function resolveHead(git2) {
try {
git2(["rev-parse", "--git-dir"]);
} catch (error) {
if (error instanceof GitCommandError) throw new TreeIdentityError("not a git repository");
throw error;
}
try {
return git2(["rev-parse", "--verify", "--quiet", "HEAD"]).trim();
} catch (error) {
if (error instanceof TreeIdentityError) throw error;
if (git2(["rev-list", "-n", "1", "--all"]).trim().length === 0) {
throw new TreeIdentityError("the repository has no commits");
}
return null;
}
}
function runGit(binary, args, cwd, remainingMs, env2) {
if (remainingMs <= 0) throw new TreeIdentityError("the tree identity ran past its time limit");
try {
return execFileSync8(binary, args, {
cwd,
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
timeout: remainingMs,
maxBuffer: 16 * 1024 * 1024,
...env2 ? { env: env2 } : {}
});
} catch (error) {
const failure = error;
if (failure.code === "ENOENT") throw new TreeIdentityError("git is not installed");
if (failure.code === "ETIMEDOUT" || failure.signal === "SIGTERM") {
throw new TreeIdentityError("the tree identity ran past its time limit");
}
const detail = String(failure.stderr ?? "").split("\n")[0]?.trim();
throw new GitCommandError(`git ${args[0]} failed${detail ? `: ${detail}` : ""}`);
}
}
// src/traceability/index.ts
init_esm_shims();
// src/quality-ratchet/index.ts
init_esm_shims();
// src/quality-ratchet/baseline.ts
init_esm_shims();
import { existsSync as existsSync43 } from "fs";
import { mkdir as mkdir29, readFile as readFile41, rename as rename4, writeFile as writeFile29 } from "fs/promises";
import { dirname as dirname39, join as join87 } from "path";
// src/core/types/quality-ratchet.ts
init_esm_shims();
var PROJECT_SCOPE = "(project)";
var QUALITY_BASELINE_SCHEMA_VERSION = "1.0.0";
// src/quality-ratchet/baseline.ts
function qualityBaselinePath(projectRoot) {
return join87(projectRoot, PATHS.QUALITY_BASELINE);
}
function sampleKey(measure, module) {
return `${measure}::${module}`;
}
function createBaseline(samples, now) {
return {
schema_version: QUALITY_BASELINE_SCHEMA_VERSION,
captured_at: now,
updated_at: now,
samples: sortSamples(samples)
};
}
function tightenBaseline(baseline, current, now) {
const byKey = /* @__PURE__ */ new Map();
for (const sample of baseline.samples) {
byKey.set(sampleKey(sample.measure, sample.module), sample);
}
let changed = false;
for (const sample of current) {
const key = sampleKey(sample.measure, sample.module);
const existing = byKey.get(key);
if (!existing) {
byKey.set(key, sample);
changed = true;
continue;
}
if (sample.value === null) continue;
if (existing.value === null || sample.value < existing.value) {
byKey.set(key, { ...sample, value: sample.value });
changed = true;
}
}
return {
...baseline,
samples: sortSamples([...byKey.values()]),
updated_at: changed ? now : baseline.updated_at
};
}
function applyApprovedRegressions(baseline, approved, now) {
if (approved.length === 0) return baseline;
const byKey = /* @__PURE__ */ new Map();
for (const sample of baseline.samples) {
byKey.set(sampleKey(sample.measure, sample.module), sample);
}
for (const sample of approved) {
if (sample.value === null) continue;
byKey.set(sampleKey(sample.measure, sample.module), { ...sample });
}
return {
...baseline,
samples: sortSamples([...byKey.values()]),
updated_at: now
};
}
function sortSamples(samples) {
return [...samples].sort(
(a, b) => sampleKey(a.measure, a.module).localeCompare(sampleKey(b.measure, b.module))
);
}
async function writeQualityBaseline(projectRoot, baseline) {
const target = qualityBaselinePath(projectRoot);
await mkdir29(dirname39(target), { recursive: true });
const tmp = `${target}.tmp-${process.pid}`;
await writeFile29(tmp, JSON.stringify(baseline, null, 2) + "\n", "utf8");
await rename4(tmp, target);
return target;
}
async function readQualityBaseline(projectRoot) {
const target = qualityBaselinePath(projectRoot);
if (!existsSync43(target)) return null;
try {
const parsed = JSON.parse(await readFile41(target, "utf8"));
if (parsed?.schema_version !== QUALITY_BASELINE_SCHEMA_VERSION || !Array.isArray(parsed.samples)) {
return null;
}
return parsed;
} catch {
return null;
}
}
// src/quality-ratchet/collector.ts
init_esm_shims();
// src/module-health/rollup.ts
init_esm_shims();
import { existsSync as existsSync44, readFileSync as readFileSync39 } from "fs";
import { execFileSync as execFileSync9 } from "child_process";
import { join as join88 } from "path";
// src/module-health/parsers/index.ts
init_esm_shims();
// src/module-health/parsers/cobertura.ts
init_esm_shims();
var CLASS_BLOCK = /<class\b([^>]*)>([\s\S]*?)<\/class>/g;
var FILENAME_ATTR = /\bfilename="([^"]+)"/;
var LINE_TAG = /<line\b[^>]*\bhits="(\d+)"/g;
function parseReport(content) {
const coverage = [];
for (const match of content.matchAll(CLASS_BLOCK)) {
const attrs = match[1] ?? "";
const body = match[2] ?? "";
const filenameMatch = FILENAME_ATTR.exec(attrs);
if (filenameMatch === null) continue;
const filename = (filenameMatch[1] ?? "").replace(/\\/g, "/");
let total = 0;
let covered = 0;
for (const lineMatch of body.matchAll(LINE_TAG)) {
total += 1;
if (Number.parseInt(lineMatch[1] ?? "0", 10) > 0) covered += 1;
}
coverage.push({ file: filename, lines_total: total, lines_covered: covered });
}
return { coverage };
}
// src/module-health/parsers/coverage-py-xml.ts
init_esm_shims();
function parseReport2(content) {
return parseReport(content);
}
// src/module-health/parsers/gocover.ts
init_esm_shims();
function parseReport3(content) {
const byFile = /* @__PURE__ */ new Map();
for (const rawLine of content.split(/\r?\n/)) {
const line = rawLine.trim();
if (line.length === 0 || line.startsWith("mode:")) continue;
const match = /^(.+?):\d+\.\d+,\d+\.\d+\s+(\d+)\s+(\d+)$/.exec(line);
if (match === null) continue;
const file = (match[1] ?? "").replace(/\\/g, "/");
const stmts = Number.parseInt(match[2] ?? "0", 10);
const count2 = Number.parseInt(match[3] ?? "0", 10);
const acc = byFile.get(file) ?? { total: 0, covered: 0 };
acc.total += stmts;
if (count2 > 0) acc.covered += stmts;
byFile.set(file, acc);
}
const coverage = [];
for (const [file, { total, covered }] of byFile) {
coverage.push({ file, lines_total: total, lines_covered: covered });
}
coverage.sort((a, b) => a.file.localeCompare(b.file));
return { coverage };
}
// src/module-health/parsers/go-json.ts
init_esm_shims();
function parseReport4(content) {
const byPackage = /* @__PURE__ */ new Map();
for (const rawLine of content.split(/\r?\n/)) {
const line = rawLine.trim();
if (line.length === 0 || line[0] !== "{") continue;
let event;
try {
event = JSON.parse(line);
} catch {
continue;
}
if (!event.Test || !event.Package) continue;
const pkg = event.Package;
const acc = byPackage.get(pkg) ?? { passing: 0, failing: 0 };
if (event.Action === "pass") acc.passing += 1;
else if (event.Action === "fail") acc.failing += 1;
else continue;
byPackage.set(pkg, acc);
}
const tests = [];
for (const [pkg, { passing, failing }] of byPackage) {
tests.push({ file: pkg, passing, failing, total: passing + failing });
}
tests.sort((a, b) => a.file.localeCompare(b.file));
return { tests };
}
// src/module-health/parsers/jacoco.ts
init_esm_shims();
var PACKAGE_BLOCK = /<package\b([^>]*)>([\s\S]*?)<\/package>/g;
var SOURCEFILE_BLOCK = /<sourcefile\b([^>]*)>([\s\S]*?)<\/sourcefile>/g;
var NAME_ATTR = /\bname="([^"]+)"/;
var LINE_COUNTER_TAG = /<counter\b[^>]*\btype="LINE"[^>]*\/?>/;
var MISSED_ATTR = /\bmissed="(\d+)"/;
var COVERED_ATTR = /\bcovered="(\d+)"/;
function parseReport5(content) {
const coverage = [];
for (const pkgMatch of content.matchAll(PACKAGE_BLOCK)) {
const pkgName = (NAME_ATTR.exec(pkgMatch[1] ?? "")?.[1] ?? "").replace(/\\/g, "/");
for (const fileMatch of (pkgMatch[2] ?? "").matchAll(SOURCEFILE_BLOCK)) {
const fileName = NAME_ATTR.exec(fileMatch[1] ?? "")?.[1] ?? "";
const body = fileMatch[2] ?? "";
const counterTag = LINE_COUNTER_TAG.exec(body)?.[0] ?? "";
const missed = Number.parseInt(MISSED_ATTR.exec(counterTag)?.[1] ?? "0", 10);
const covered = Number.parseInt(COVERED_ATTR.exec(counterTag)?.[1] ?? "0", 10);
coverage.push({
file: joinPath(pkgName, fileName),
lines_total: missed + covered,
lines_covered: covered
});
}
}
return { coverage };
}
function joinPath(pkg, file) {
if (pkg.length === 0) return file;
if (file.length === 0) return pkg;
return `${pkg.replace(/\.+$/, "")}/${file}`;
}
// src/module-health/parsers/junit-xml.ts
init_esm_shims();
var TESTCASE_TAG = /<testcase\b([^>]*?)\s*(?:\/>|>([\s\S]*?)<\/testcase>)/g;
var FILE_ATTR = /\bfile="([^"]+)"/;
var CLASSNAME_ATTR = /\bclassname="([^"]+)"/;
var FAILURE_OR_ERROR = /<(failure|error)\b/;
function parseReport6(content) {
const tests = [];
for (const match of content.matchAll(TESTCASE_TAG)) {
const attrs = match[1] ?? "";
const body = match[2] ?? "";
const fileMatch = FILE_ATTR.exec(attrs);
const classMatch = CLASSNAME_ATTR.exec(attrs);
const file = (fileMatch?.[1] ?? classMatch?.[1] ?? "").replace(/\\/g, "/");
const failed = FAILURE_OR_ERROR.test(body);
tests.push({
file,
passing: failed ? 0 : 1,
failing: failed ? 1 : 0,
total: 1
});
}
return { tests };
}
// src/module-health/parsers/lcov.ts
init_esm_shims();
function parseReport7(content) {
const coverage = [];
let currentFile = null;
let linesFound = 0;
let linesHit = 0;
for (const rawLine of content.split(/\r?\n/)) {
const line = rawLine.trim();
if (line.length === 0) continue;
if (line.startsWith("SF:")) {
currentFile = line.slice(3).trim().replace(/\\/g, "/");
linesFound = 0;
linesHit = 0;
continue;
}
if (line.startsWith("LF:")) {
linesFound = Number.parseInt(line.slice(3), 10);
if (!Number.isFinite(linesFound)) linesFound = 0;
continue;
}
if (line.startsWith("LH:")) {
linesHit = Number.parseInt(line.slice(3), 10);
if (!Number.isFinite(linesHit)) linesHit = 0;
continue;
}
if (line === "end_of_record") {
if (currentFile !== null) {
coverage.push({
file: currentFile,
lines_total: linesFound,
lines_covered: linesHit
});
}
currentFile = null;
linesFound = 0;
linesHit = 0;
}
}
return { coverage };
}
// src/module-health/parsers/opencover.ts
init_esm_shims();
var MODULE_BLOCK = /<Module\b[^>]*>([\s\S]*?)<\/Module>/g;
var FILE_TAG = /<File\b[^>]*\/?>/g;
var SEQUENCE_POINT_TAG = /<SequencePoint\b[^>]*\/?>/g;
var UID_ATTR = /\buid="(\d+)"/;
var FULLPATH_ATTR = /\bfullPath="([^"]+)"/;
var FILEID_ATTR = /\bfileid="(\d+)"/;
var VC_ATTR = /\bvc="(\d+)"/;
function parseReport8(content) {
const coverage = [];
for (const moduleMatch of content.matchAll(MODULE_BLOCK)) {
const body = moduleMatch[1] ?? "";
const filesById = /* @__PURE__ */ new Map();
for (const fileMatch of body.matchAll(FILE_TAG)) {
const tag = fileMatch[0];
const uid = UID_ATTR.exec(tag)?.[1];
const path10 = FULLPATH_ATTR.exec(tag)?.[1];
if (uid && path10) filesById.set(uid, path10.replace(/\\/g, "/"));
}
const stats = /* @__PURE__ */ new Map();
for (const id of filesById.keys()) {
stats.set(id, { total: 0, covered: 0 });
}
for (const spMatch of body.matchAll(SEQUENCE_POINT_TAG)) {
const tag = spMatch[0];
const fileId = FILEID_ATTR.exec(tag)?.[1];
if (!fileId) continue;
const acc = stats.get(fileId);
if (!acc) continue;
const vc = Number.parseInt(VC_ATTR.exec(tag)?.[1] ?? "0", 10);
acc.total += 1;
if (vc > 0) acc.covered += 1;
}
for (const [id, { total, covered }] of stats) {
const file = filesById.get(id);
if (!file) continue;
coverage.push({ file, lines_total: total, lines_covered: covered });
}
}
coverage.sort((a, b) => a.file.localeCompare(b.file));
return { coverage };
}
// src/module-health/parsers/vitest-json.ts
init_esm_shims();
function parseReport9(content) {
let parsed;
try {
parsed = JSON.parse(content);
} catch {
return { tests: [] };
}
const tests = [];
for (const result2 of parsed.testResults ?? []) {
const file = (result2.name ?? "").replace(/\\/g, "/");
let passing = 0;
let failing = 0;
if (Array.isArray(result2.assertionResults) && result2.assertionResults.length > 0) {
for (const assertion of result2.assertionResults) {
if (assertion.status === "passed") passing += 1;
else if (assertion.status === "failed") failing += 1;
}
} else {
passing = result2.numPassingTests ?? 0;
failing = result2.numFailingTests ?? 0;
}
tests.push({ file, passing, failing, total: passing + failing });
}
return { tests };
}
// src/module-health/parsers/index.ts
var REGISTRY = {
lcov: parseReport7,
cobertura: parseReport,
"coverage-py-xml": parseReport2,
gocover: parseReport3,
"junit-xml": parseReport6,
"go-json": parseReport4,
jacoco: parseReport5,
opencover: parseReport8,
"vitest-json": parseReport9
};
function getParser(format) {
return REGISTRY[format] ?? null;
}
// src/module-health/rollup.ts
var DEFAULT_GIT_WINDOW_DAYS = 14;
function readReport2(projectRoot, reportPath2, format) {
const abs = reportPath2.startsWith("/") ? reportPath2 : join88(projectRoot, reportPath2);
if (!existsSync44(abs)) {
return { error: `report_missing:${reportPath2}` };
}
const parser = getParser(format);
if (parser === null) {
return { error: `parser_missing:${format}` };
}
const content = readFileSync39(abs, "utf8");
return { parsed: parser(content), format };
}
function assignToModule(filePath, modules) {
const normalised = toPosixPath(filePath);
for (const mod of modules) {
if (matchesAnyGlob(normalised, mod.sources)) return mod.slug;
}
return null;
}
function rollupCoverage(rows, slug) {
let total = 0;
let covered = 0;
let touched = false;
for (const row of rows) {
if (row.lines_total <= 0) continue;
if (row.slug !== slug) continue;
total += row.lines_total;
covered += row.lines_covered;
touched = true;
}
if (!touched || total === 0) {
return { pct: null, lines_total: 0, lines_covered: 0 };
}
return {
pct: Math.round(covered / total * 100 * 100) / 100,
lines_total: total,
lines_covered: covered
};
}
function rollupTests(rows, slug) {
let passing = 0;
let failing = 0;
let total = 0;
let touched = false;
for (const row of rows) {
if (row.slug !== slug) continue;
passing += row.passing;
failing += row.failing;
total += row.total;
touched = true;
}
return touched ? { passing, failing, total } : { passing: null, failing: null, total: null };
}
function changeVelocity(projectRoot, sources, windowDays) {
if (sources.length === 0) return null;
try {
const since = `--since=${windowDays}.days.ago`;
const args = ["log", "--pretty=oneline", since, "--", ...sources];
const out = execFileSync9("git", args, {
cwd: projectRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"]
});
return out.split(/\r?\n/).filter((line) => line.trim().length > 0).length;
} catch {
return null;
}
}
async function rollupModuleHealth(opts) {
const now = (opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()))();
if (opts.moduleHealth === null) {
return {
generated_at: now,
blocked: "module_health_unknown",
modules: [],
unattributed_files: [],
source: "rollup",
formats: { coverage_format: null, test_report_format: null }
};
}
const mh = opts.moduleHealth;
const windowDays = mh.git_window_days ?? DEFAULT_GIT_WINDOW_DAYS;
const source = opts.coverageReportPath || opts.testReportPath ? "from-report" : "rollup";
const coveragePath = opts.coverageReportPath ?? mh.coverage_path;
const coverageFormat = mh.coverage_format ?? null;
const testReportPath = opts.testReportPath ?? mh.test_report_path;
const testReportFormat = mh.test_report_format ?? null;
const blockedGlobal = [];
let coverage = [];
if (coveragePath && coverageFormat) {
const result2 = readReport2(opts.projectRoot, coveragePath, coverageFormat);
if ("error" in result2) {
blockedGlobal.push(`coverage:${result2.error}`);
} else if (result2.parsed.coverage) {
coverage = result2.parsed.coverage;
}
} else {
blockedGlobal.push("coverage:not_configured");
}
let tests = [];
if (testReportPath && testReportFormat) {
const result2 = readReport2(opts.projectRoot, testReportPath, testReportFormat);
if ("error" in result2) {
blockedGlobal.push(`tests:${result2.error}`);
} else if (result2.parsed.tests) {
tests = result2.parsed.tests;
}
} else {
blockedGlobal.push("tests:not_configured");
}
const rawMap = readRawModuleMap(opts.projectRoot);
const modules = rawMap?.modules ?? [];
const attributedCoverage = coverage.map((row) => ({
...row,
slug: assignToModule(row.file, modules)
}));
const attributedTests = tests.map((row) => ({
...row,
slug: row.file ? assignToModule(row.file, modules) : null
}));
const unattributed = /* @__PURE__ */ new Set();
for (const row of attributedCoverage) {
if (row.slug === null) unattributed.add(row.file);
}
for (const row of attributedTests) {
if (row.slug === null && row.file) unattributed.add(row.file);
}
const rollups = [];
for (const mod of modules) {
const blocked = [];
const cov = rollupCoverage(attributedCoverage, mod.slug);
if (cov.pct === null) {
blocked.push(
coveragePath && coverageFormat ? "coverage_pct:no_matching_files" : "coverage_pct:not_configured"
);
}
const t = rollupTests(attributedTests, mod.slug);
if (t.total === null) {
blocked.push(
testReportPath && testReportFormat ? "tests:no_matching_files" : "tests:not_configured"
);
}
const velocity = changeVelocity(opts.projectRoot, mod.sources, windowDays);
if (velocity === null) {
blocked.push("change_velocity:unavailable");
}
const stability = null;
if (!mh.public_api_extractor) {
blocked.push("contract_stability:no_public_api_extractor");
}
blocked.push("mutation_score:not_configured");
const metrics = {
coverage_pct: cov.pct,
tests_passing: t.passing,
tests_failing: t.failing,
tests_total: t.total,
change_velocity: velocity,
contract_stability: stability,
defect_frequency: null,
mutation_score: null
};
const profile = {
schema_version: 2,
module: mod.slug,
tier: deriveHealthTier(metrics),
metrics,
blocked_metrics: [.../* @__PURE__ */ new Set([...blockedGlobal, ...blocked])].sort(),
evidence: {
rollup: {
...coverageFormat ? { coverage_format: coverageFormat } : {},
...coveragePath ? { coverage_path: coveragePath } : {},
...testReportFormat ? { test_report_format: testReportFormat } : {},
...testReportPath ? { test_report_path: testReportPath } : {},
git_window_days: windowDays,
ran_at: now,
source
}
},
updated_at: now
};
rollups.push({ slug: mod.slug, profile });
}
if (opts.writeProfiles !== false) {
for (const r of rollups) {
await writeModuleHealthProfile(opts.projectRoot, r.profile);
}
appendModuleMapEvent(opts.projectRoot, {
ts: now,
type: "module.health.rolled-up",
via: source,
payload: {
modules: rollups.map((r) => r.slug),
unattributed_count: unattributed.size
}
});
}
return {
generated_at: now,
blocked: null,
modules: rollups,
unattributed_files: [...unattributed].sort(),
source,
formats: {
coverage_format: coverageFormat,
test_report_format: testReportFormat
}
};
}
// src/quality-ratchet/strictness.ts
init_esm_shims();
import { existsSync as existsSync45, readFileSync as readFileSync40 } from "fs";
import { join as join89 } from "path";
var STRICT_FAMILY = [
"noImplicitAny",
"strictNullChecks",
"strictFunctionTypes",
"strictBindCallApply",
"strictPropertyInitialization",
"noImplicitThis",
"alwaysStrict",
"useUnknownInCatchVariables"
];
var EXTRA_STRICT_FLAGS = [
"noUnusedLocals",
"noUnusedParameters",
"noImplicitReturns",
"noFallthroughCasesInSwitch",
"noUncheckedIndexedAccess",
"exactOptionalPropertyTypes",
"noImplicitOverride"
];
function parseTsconfig(raw) {
try {
return JSON.parse(raw);
} catch {
const stripped = raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:"'])\/\/.*$/gm, "$1").replace(/,(\s*[}\]])/g, "$1");
try {
return JSON.parse(stripped);
} catch {
return null;
}
}
}
function measureStrictnessFromOptions(options) {
const strictUmbrella = options.strict === true;
let looseness = 0;
for (const flag of STRICT_FAMILY) {
const explicit = options[flag];
const enabled = explicit === void 0 ? strictUmbrella : explicit === true;
if (!enabled) looseness += 1;
}
for (const flag of EXTRA_STRICT_FLAGS) {
if (options[flag] !== true) looseness += 1;
}
return { looseness, considered: STRICT_FAMILY.length + EXTRA_STRICT_FLAGS.length };
}
function measureStrictness(projectRoot) {
const path10 = join89(projectRoot, "tsconfig.json");
if (!existsSync45(path10)) return null;
let raw;
try {
raw = readFileSync40(path10, "utf8");
} catch {
return null;
}
const parsed = parseTsconfig(raw);
if (parsed === null) return null;
return measureStrictnessFromOptions(parsed.compilerOptions ?? {});
}
// src/quality-ratchet/collector.ts
function readModules(projectRoot) {
const raw = readRawModuleMap(projectRoot);
return (raw?.modules ?? []).map((mod) => ({ slug: mod.slug, sources: mod.sources }));
}
function rollupFileDeficiencies(measure, files, modules, tool, confidence) {
let projectTotal = 0;
const perModule = /* @__PURE__ */ new Map();
for (const { file, count: count2 } of files) {
projectTotal += count2;
const slug = assignToModule(file, modules);
if (slug !== null) {
perModule.set(slug, (perModule.get(slug) ?? 0) + count2);
}
}
const samples = [
{ measure, module: PROJECT_SCOPE, value: projectTotal, confidence, tool, blocked_reason: null }
];
for (const [slug, value] of perModule) {
samples.push({ measure, module: slug, value, confidence, tool, blocked_reason: null });
}
return samples;
}
function blockedSample(measure, reason2) {
return {
measure,
module: PROJECT_SCOPE,
value: null,
confidence: "lower",
tool: null,
blocked_reason: reason2
};
}
async function collectQualityMeasures(options) {
const modules = readModules(options.projectRoot);
const runOptions = {
projectRoot: options.projectRoot,
changedFiles: options.changedFiles,
lane: options.lane,
stackProfile: options.stackProfile
};
const samples = [];
const strictness = measureStrictness(options.projectRoot);
samples.push(
strictness === null ? blockedSample("strictness", "no-tsconfig-or-unparseable") : {
measure: "strictness",
module: PROJECT_SCOPE,
value: strictness.looseness,
confidence: "mature",
tool: "tsconfig",
blocked_reason: null
}
);
if (options.lane === "fast") {
return samples;
}
if (options.deadCodeFiles === null) {
samples.push(blockedSample("dead_code", "traceability-map-unavailable"));
} else {
samples.push(
...rollupFileDeficiencies(
"dead_code",
options.deadCodeFiles.map((file) => ({ file, count: 1 })),
modules,
"traceability-reachability",
"mature"
)
);
}
const tangledness = await safeRun(options.deps?.collectTangledness, runOptions);
samples.push(...resultToSamples("tangledness", tangledness, modules));
const risky = await safeRun(options.deps?.collectRiskyPatterns, runOptions);
samples.push(...resultToSamples("risky_patterns", risky, modules));
return samples;
}
async function safeRun(runner, opts) {
if (!runner) return null;
try {
return await runner(opts);
} catch {
return null;
}
}
function resultToSamples(measure, result2, modules) {
if (result2 === null) {
return [blockedSample(measure, "tool-not-wired")];
}
return rollupFileDeficiencies(measure, result2.files, modules, result2.tool, result2.confidence);
}
// src/quality-ratchet/ratchet.ts
init_esm_shims();
function exceptionKind(measure) {
return `quality.${measure}`;
}
function evaluateRatchet(options) {
const { current, lane } = options;
const approved = options.approvedExceptionKinds ?? /* @__PURE__ */ new Set();
if (options.baseline === null) {
const verdicts2 = current.map((sample) => verdict(sample, null, "new"));
return {
status: "captured",
lane,
verdicts: verdicts2,
blocking_regressions: [],
excepted_regressions: [],
tightened: [],
captured_baseline: true,
skipped_reason: null
};
}
const baselineByKey = /* @__PURE__ */ new Map();
for (const sample of options.baseline.samples) {
baselineByKey.set(sampleKey(sample.measure, sample.module), sample);
}
const verdicts = [];
const blocking = [];
const excepted = [];
const tightened = [];
let capturedNew = false;
for (const sample of current) {
const base = baselineByKey.get(sampleKey(sample.measure, sample.module)) ?? null;
const baseValue = base?.value ?? null;
if (sample.value === null) {
verdicts.push(verdict(sample, baseValue, "blocked"));
continue;
}
if (base === void 0 || baseValue === null) {
verdicts.push(verdict(sample, baseValue, "new"));
capturedNew = true;
continue;
}
if (sample.value < baseValue) {
const v = verdict(sample, baseValue, "tightened");
verdicts.push(v);
tightened.push(v);
} else if (sample.value === baseValue) {
verdicts.push(verdict(sample, baseValue, "unchanged"));
} else {
const v = verdict(sample, baseValue, "regressed");
verdicts.push(v);
if (approved.has(v.kind)) {
excepted.push(v);
} else {
blocking.push(v);
}
}
}
const status = blocking.length > 0 ? "regressed" : "pass";
return {
status,
lane,
verdicts,
blocking_regressions: blocking,
excepted_regressions: excepted,
tightened,
captured_baseline: capturedNew,
skipped_reason: null
};
}
function verdict(sample, baselineValue, outcome) {
return {
measure: sample.measure,
module: sample.module,
baseline_value: baselineValue,
current_value: sample.value,
outcome,
confidence: sample.confidence,
kind: exceptionKind(sample.measure),
detail: detailFor(sample, baselineValue, outcome)
};
}
function detailFor(sample, baselineValue, outcome) {
const where = `${sample.measure} @ ${sample.module}`;
switch (outcome) {
case "new":
return `${where}: captured at ${fmt(sample.value)} (no prior baseline).`;
case "blocked":
return `${where}: not measured this run (${sample.blocked_reason ?? "unavailable"}).`;
case "tightened":
return `${where}: improved ${fmt(baselineValue)} \u2192 ${fmt(sample.value)}; recorded level tightens.`;
case "unchanged":
return `${where}: held at ${fmt(sample.value)}.`;
case "regressed":
return `${where}: worsened ${fmt(baselineValue)} \u2192 ${fmt(sample.value)} (lower is better).`;
}
}
function fmt(value) {
return value === null ? "n/a" : String(value);
}
// src/quality-ratchet/exception-decision.ts
init_esm_shims();
var CATEGORY = "quality.ratchet_exception";
var DEFAULT_REQUESTED_BY = "quality-ratchet";
var RATCHET_EXCEPTION_APPROVE = "approve-exception";
var RATCHET_EXCEPTION_REFUSE = "hold-the-line";
function buildRatchetExceptionPacket(input) {
const ttlDays = DECISION_CATEGORY_DEFAULTS[CATEGORY].ttl_days;
const ttlUntil = new Date(
new Date(input.created_at).getTime() + ttlDays * 24 * 60 * 60 * 1e3
).toISOString();
const fingerprint = `sha256:${sha256Hex(`${CATEGORY}:${input.kind}`)}`;
const from = input.baseline_value === null ? "n/a" : String(input.baseline_value);
const to = input.current_value === null ? "n/a" : String(input.current_value);
return {
decision_id: input.decision_id,
fingerprint,
category: CATEGORY,
question: `Allow ${input.measure} to worsen (${from} \u2192 ${to}) at ${input.module}?`,
context: `The quality ratchet refuses any change that worsens a measure. ${input.measure} at ${input.module} rose from ${from} to ${to} (lower is better). Approve only if this is a genuine, legitimate need \u2014 the approval is reused for the same kind.`,
options: [
{
option_key: RATCHET_EXCEPTION_APPROVE,
label: "Make an exception",
one_line_preview: "If you pick this, the worse level is recorded as the new baseline and reused for the same kind.",
trade_off: "You give up: holding the previous, stricter level for this measure.",
evidence: {}
},
{
option_key: RATCHET_EXCEPTION_REFUSE,
label: "Keep the current level",
one_line_preview: "If you pick this, the change must bring the measure back to at least its recorded level.",
trade_off: "You give up: shipping the change until the measure is no longer worse.",
evidence: {}
}
],
recommendation: RATCHET_EXCEPTION_REFUSE,
recommendation_reason: "The ratchet defaults to holding the line; worsening a measure should be a deliberate, recorded exception.",
confidence: 0.5,
requested_by: input.requested_by ?? DEFAULT_REQUESTED_BY,
task_session_id: input.task_session_id,
linked_requirements: [],
created_at: input.created_at,
status: "pending",
ttl_until: ttlUntil,
invalidation_watch: []
};
}
function resolveReusableExceptionKinds(store, kinds, buildPacket) {
const approved = /* @__PURE__ */ new Set();
for (const kind of new Set(kinds)) {
const packet = buildPacket(kind);
const reusableId = store.findReusableDecision({
fingerprint: packet.fingerprint,
category: packet.category,
options: packet.options
});
if (!reusableId) continue;
const resolved = store.readResolved(reusableId);
if (resolved?.human_response?.chosen_option_key === RATCHET_EXCEPTION_APPROVE) {
approved.add(kind);
}
}
return approved;
}
// src/quality-ratchet/runner.ts
init_esm_shims();
async function runQualityRatchetGate(options) {
const now = (options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()))();
const baseline = await readQualityBaseline(options.projectRoot);
const current = await collectQualityMeasures({
projectRoot: options.projectRoot,
changedFiles: options.changedFiles,
lane: options.lane,
stackProfile: options.stackProfile,
deadCodeFiles: options.deadCodeFiles,
deps: options.deps
});
if (baseline === null) {
const result3 = evaluateRatchet({ baseline: null, current, lane: options.lane });
if (options.writeBaseline !== false) {
await writeQualityBaseline(options.projectRoot, createBaseline(current, now));
}
return result3;
}
let result2 = evaluateRatchet({ baseline, current, lane: options.lane });
if (result2.blocking_regressions.length > 0 && options.decisionStore) {
const store = options.decisionStore;
const lookupTask = options.taskSessionId ?? "quality-ratchet-lookup";
const candidateKinds = result2.blocking_regressions.map((r) => r.kind);
const approved = resolveReusableExceptionKinds(
store,
candidateKinds,
(kind) => buildRatchetExceptionPacket(
exceptionInput("D-0", kind, result2.blocking_regressions, lookupTask, now)
)
);
if (approved.size > 0) {
result2 = evaluateRatchet({
baseline,
current,
lane: options.lane,
approvedExceptionKinds: approved
});
}
if (options.taskSessionId) {
raisePendingExceptions(store, result2.blocking_regressions, options.taskSessionId, now);
}
}
if (options.writeBaseline !== false && result2.status !== "regressed") {
let next = tightenBaseline(baseline, current, now);
if (result2.excepted_regressions.length > 0) {
const approvedSamples = result2.excepted_regressions.map((r) => ({
measure: r.measure,
module: r.module,
value: r.current_value,
confidence: r.confidence,
tool: null,
blocked_reason: null
}));
next = applyApprovedRegressions(next, approvedSamples, now);
}
await writeQualityBaseline(options.projectRoot, next);
}
return result2;
}
function exceptionInput(decisionId, kind, regressions, taskSessionId, now) {
const sample = regressions.find((r) => r.kind === kind) ?? regressions[0];
return {
decision_id: decisionId,
kind,
measure: sample.measure,
module: sample.module,
baseline_value: sample.baseline_value,
current_value: sample.current_value,
task_session_id: taskSessionId,
created_at: now
};
}
function raisePendingExceptions(store, blocking, taskSessionId, now) {
const kinds = new Set(blocking.map((r) => r.kind));
for (const kind of kinds) {
try {
const decisionId = store.nextDecisionId();
const packet = buildRatchetExceptionPacket(
exceptionInput(decisionId, kind, blocking, taskSessionId, now)
);
store.writePending(packet);
} catch {
}
}
}
// src/mutation/backstop.ts
init_esm_shims();
// src/delivery/shell.ts
init_esm_shims();
function createDeliveryShell(cwd, options = {}) {
const envOptions = options.env ? { env: options.env, extendEnv: false } : {};
return {
async run(command, args) {
try {
const result2 = await execa(command, args, { cwd, reject: false, ...envOptions });
return {
/* v8 ignore start -- execa always returns string stdout/stderr; the ?? '' guards a never-null path */
stdout: result2.stdout ?? "",
stderr: result2.stderr ?? "",
/* v8 ignore stop */
/* v8 ignore next -- execa always yields a numeric exitCode with reject:false */
exitCode: typeof result2.exitCode === "number" ? result2.exitCode : 1
};
} catch (error) {
return {
stdout: "",
stderr: error instanceof Error ? error.message : String(error),
exitCode: 1
};
}
}
};
}
// src/mutation/runner.ts
init_esm_shims();
import { existsSync as existsSync46 } from "fs";
import { readFile as readFile42 } from "fs/promises";
import { join as join90 } from "path";
// src/mutation/adapter.ts
init_esm_shims();
var MATURE_TOOLS = [
{
descriptor: {
tool: "stryker",
languages: ["typescript", "javascript"],
confidence: "mature",
run_command: "npx stryker run",
config_markers: [
"stryker.conf.json",
"stryker.conf.js",
"stryker.conf.mjs",
"stryker.conf.cjs",
".stryker.conf.json"
]
},
match: [
"typescript",
"javascript",
"ts",
"js",
"node",
"node-cli",
"react",
"next",
"nextjs",
"vue",
"svelte",
"angular",
"vite",
"vite-spa"
]
},
{
descriptor: {
tool: "stryker-net",
languages: ["csharp"],
confidence: "mature",
run_command: "dotnet stryker",
config_markers: ["stryker-config.json", "stryker-config.yaml"]
},
match: ["csharp", "dotnet", ".net", "c#"]
},
{
descriptor: {
tool: "pit",
languages: ["java"],
confidence: "mature",
run_command: "mvn org.pitest:pitest-maven:mutationCoverage",
config_markers: ["pitest.xml"]
},
match: ["java", "jvm", "maven", "gradle", "spring"]
},
{
descriptor: {
tool: "mutmut",
languages: ["python"],
confidence: "mature",
run_command: "mutmut run",
config_markers: ["setup.cfg", "mutmut_config.py", "pyproject.toml"]
},
match: ["python", "py", "django", "flask", "fastapi"]
},
{
descriptor: {
tool: "infection",
languages: ["php"],
confidence: "mature",
run_command: "vendor/bin/infection",
config_markers: ["infection.json", "infection.json5", "infection.json.dist"]
},
match: ["php", "laravel", "symfony"]
},
{
descriptor: {
tool: "mutant",
languages: ["ruby"],
confidence: "mature",
run_command: "bundle exec mutant run",
config_markers: [".mutant.yml", "config/mutant.yml"]
},
match: ["ruby", "rails"]
},
{
descriptor: {
tool: "cargo-mutants",
languages: ["rust"],
confidence: "mature",
run_command: "cargo mutants",
config_markers: [".cargo/mutants.toml", "mutants.toml"]
},
match: ["rust", "cargo"]
}
];
var FALLBACK_TOOL = {
tool: "generic",
languages: [],
confidence: "lower",
run_command: "",
config_markers: []
};
function normalizeTokens(stack) {
if (stack === null) {
return [];
}
const tokens = [...stack.frameworks, ...stack.traits].map((token) => token.trim().toLowerCase());
return [...new Set(tokens.filter((token) => token.length > 0))];
}
function selectMutationTool(stack) {
const tokens = normalizeTokens(stack);
if (tokens.length === 0) {
return { ...FALLBACK_TOOL };
}
for (const tool of MATURE_TOOLS) {
if (tool.match.some((token) => tokens.includes(token))) {
return { ...tool.descriptor };
}
}
return { ...FALLBACK_TOOL, languages: [tokens[0]] };
}
// src/mutation/outcome.ts
init_esm_shims();
var KILLED_STATUSES = /* @__PURE__ */ new Set(["killed", "timeout"]);
var SURVIVOR_STATUSES = /* @__PURE__ */ new Set(["survived", "no-coverage"]);
var SET_ASIDE_STATUSES = /* @__PURE__ */ new Set(["equivalent", "error"]);
function toSurvivor(mutant) {
return {
file: mutant.file,
line: mutant.line,
operator: mutant.operator,
...mutant.description ? { description: mutant.description } : {}
};
}
function deriveStatus(input) {
if (!input.treeClean) {
return "unsafe-tree";
}
if (input.survivors > 0) {
return "survivors";
}
if (input.confidence === "lower") {
return "lower-confidence";
}
return "killed-all";
}
function computeMutationOutcome(input) {
let killed = 0;
let survived = 0;
let setAside = 0;
const survivingMutants = [];
for (const mutant of input.mutants) {
if (KILLED_STATUSES.has(mutant.status)) {
killed += 1;
} else if (SURVIVOR_STATUSES.has(mutant.status)) {
survived += 1;
survivingMutants.push(toSurvivor(mutant));
} else if (SET_ASIDE_STATUSES.has(mutant.status)) {
setAside += 1;
}
}
const eligible = killed + survived;
const killRate = eligible === 0 ? null : Math.round(killed / eligible * 100 * 100) / 100;
const status = deriveStatus({
treeClean: input.tree_clean,
confidence: input.confidence,
survivors: survived
});
return {
tool: input.tool,
language: input.language,
confidence: input.confidence,
scoped_files: [...input.scoped_files].sort(),
total_mutants: input.mutants.length,
killed,
survived,
equivalent_set_aside: setAside,
kill_rate: killRate,
surviving_mutants: survivingMutants.sort(
(a, b) => a.file.localeCompare(b.file) || a.line - b.line
),
tree_clean: input.tree_clean,
status,
skipped_reason: null
};
}
// src/mutation/scope.ts
init_esm_shims();
var MUTABLE_EXTENSIONS = [
".ts",
".tsx",
".js",
".jsx",
".mjs",
".cjs",
".cs",
".java",
".kt",
".py",
".php",
".rb",
".rs",
".go"
];
var EXCLUDED_BASENAMES = ["package.json", "tsconfig.json"];
function hasMutableExtension(filePath) {
return MUTABLE_EXTENSIONS.some((extension) => filePath.endsWith(extension));
}
function scopeMutationTargets(changedFiles) {
const scoped = /* @__PURE__ */ new Set();
for (const raw of changedFiles) {
const filePath = raw.replace(/\\/g, "/").trim();
if (filePath.length === 0) {
continue;
}
if (isTestFile(filePath) || isDocumentationFile(filePath)) {
continue;
}
if (EXCLUDED_BASENAMES.includes(filePath.split("/").at(-1) ?? "")) {
continue;
}
if (!hasMutableExtension(filePath)) {
continue;
}
scoped.add(filePath);
}
return [...scoped].sort();
}
// src/mutation/runner.ts
function skipped(descriptor, scopedFiles, reason2, confidence = descriptor.confidence) {
return {
tool: descriptor.tool === "generic" ? null : descriptor.tool,
language: descriptor.languages[0] ?? null,
confidence,
scoped_files: scopedFiles,
total_mutants: 0,
killed: 0,
survived: 0,
equivalent_set_aside: 0,
kill_rate: null,
surviving_mutants: [],
tree_clean: true,
status: "skipped",
skipped_reason: reason2
};
}
function skippedMutationResult(stackProfile, reason2) {
return skipped(selectMutationTool(stackProfile), [], reason2);
}
async function runMutationGate(options) {
const descriptor = selectMutationTool(options.stackProfile);
const deps = options.deps ?? {};
const detectTool = deps.detectTool ?? defaultDetectTool;
const execute = deps.execute ?? defaultExecute;
const parse3 = deps.parse ?? defaultParse;
const isTreeClean = deps.isTreeClean ?? defaultIsTreeClean;
if (options.lane === "fast") {
return skipped(descriptor, [], "fast-lane");
}
if (!options.testsGreen) {
return skipped(descriptor, [], "tests-not-green");
}
const scopedFiles = scopeMutationTargets(options.changedFiles);
if (scopedFiles.length === 0) {
return skipped(descriptor, [], "no-changed-code");
}
const available = await detectTool(descriptor, options.projectRoot);
if (!available) {
return skipped(descriptor, scopedFiles, "tool-not-configured");
}
let run2;
let mutants;
try {
run2 = await execute(buildCommand(descriptor, scopedFiles), {
cwd: options.projectRoot
});
mutants = await parse3(descriptor, options.projectRoot, run2);
} catch {
return skipped(descriptor, scopedFiles, "run-failed");
}
if (mutants === null) {
return skipped(descriptor, scopedFiles, "run-failed");
}
const treeClean = await isTreeClean(options.projectRoot);
return computeMutationOutcome({
mutants,
confidence: descriptor.confidence,
tree_clean: treeClean,
scoped_files: scopedFiles,
tool: descriptor.tool,
language: descriptor.languages[0] ?? null
});
}
function buildCommand(descriptor, scopedFiles) {
if (descriptor.tool === "stryker") {
const globs = scopedFiles.join(",");
return `${descriptor.run_command} --mutate "${globs}"`;
}
return `${descriptor.run_command} ${scopedFiles.join(" ")}`.trim();
}
async function defaultDetectTool(descriptor, projectRoot) {
if (descriptor.config_markers.some((marker) => existsSync46(join90(projectRoot, marker)))) {
return true;
}
if (descriptor.tool === "stryker") {
try {
const manifest = JSON.parse(await readFile42(join90(projectRoot, "package.json"), "utf8"));
const deps = { ...manifest.dependencies, ...manifest.devDependencies };
return Object.keys(deps).some((name) => name.includes("stryker"));
} catch {
return false;
}
}
return false;
}
async function defaultExecute(command, options) {
const result2 = await execa(command, {
cwd: options.cwd,
reject: false,
shell: true
});
return {
/* v8 ignore next -- execa always yields a numeric exitCode for a process the shell ran */
exitCode: result2.exitCode ?? 1,
stdout: result2.stdout,
stderr: result2.stderr
};
}
var STRYKER_REPORT_PATHS = [
"reports/mutation/mutation.json",
"reports/mutation/mutation-report.json"
];
function mapStrykerStatus(status) {
switch (status) {
case "Killed":
return "killed";
case "Timeout":
return "timeout";
case "Survived":
return "survived";
case "NoCoverage":
return "no-coverage";
case "Ignored":
return "equivalent";
/* v8 ignore start -- defensive: RuntimeError/CompileError map to set-aside */
default:
return "error";
}
}
async function defaultParse(descriptor, projectRoot) {
if (descriptor.tool !== "stryker") {
return null;
}
const reportPath2 = STRYKER_REPORT_PATHS.map((relative21) => join90(projectRoot, relative21)).find(
(candidate) => existsSync46(candidate)
);
if (reportPath2 === void 0) {
return null;
}
const report = JSON.parse(await readFile42(reportPath2, "utf8"));
const mutants = [];
for (const [file, entry] of Object.entries(report.files ?? {})) {
for (const mutant of entry.mutants ?? []) {
mutants.push({
file,
line: mutant.location?.start?.line ?? 0,
operator: mutant.mutatorName ?? "unknown",
status: mapStrykerStatus(mutant.status ?? ""),
...mutant.replacement ? { description: mutant.replacement } : {}
});
}
}
return mutants;
}
async function defaultIsTreeClean(projectRoot) {
try {
const result2 = await execa("git", ["status", "--porcelain"], {
cwd: projectRoot,
reject: false
});
return result2.exitCode === 0 && result2.stdout.trim() === "";
} catch {
return false;
}
}
// src/mutation/backstop.ts
var MUTATION_ORIGINS = /* @__PURE__ */ new Set([
"ci-backstop",
"git-backstop"
]);
var MUTATION_OFF_NOTE = "Mutation testing is off (mutation_mode is off).";
function mutationSeamNote(mode) {
return `Mutation testing runs only on CI and pre-push (mutation_mode is ${mode}).`;
}
async function runBackstopMutation(options) {
const { projectRoot, origin, changedFiles, lane } = options;
const deps = options.deps ?? {};
const mode = (deps.resolveMode ?? resolveMutationMode)(projectRoot);
if (mode === "off") {
return { mutation_note: MUTATION_OFF_NOTE };
}
if (!MUTATION_ORIGINS.has(origin)) {
return { mutation_note: mutationSeamNote(mode) };
}
const strict = mode === "strict";
let stackProfile = null;
try {
const profile = (deps.readProfile ?? defaultReadProfile)(projectRoot);
stackProfile = profile?.stack_profile ?? await (deps.detectStackProfile ?? defaultDetectStackProfile)(projectRoot);
if (lane === "fast") {
return planted(skippedMutationResult(stackProfile, "fast-lane"), strict);
}
if (scopeMutationTargets(changedFiles).length === 0) {
return planted(skippedMutationResult(stackProfile, "no-changed-code"), strict);
}
const testCommand = profile?.commands?.test?.trim() ?? "";
if (testCommand.length === 0) {
return planted(skippedMutationResult(stackProfile, "no-test-command"), strict);
}
const testRun = await (deps.runTestCommand ?? defaultRunTestCommand)(testCommand, projectRoot);
if (testRun.exitCode !== 0) {
engineLog(
"warn",
`paqad: mutation testing did not run, the test command exited ${testRun.exitCode}`
);
return planted(skippedMutationResult(stackProfile, "tests-not-green"), strict);
}
const snapshotTree = deps.snapshotTree ?? defaultSnapshotTree;
const before = await snapshotTree(projectRoot);
const runnerDeps = {
isTreeClean: async (root) => await snapshotTree(root) === before,
...deps.runner
};
const result2 = await (deps.runMutation ?? runMutationGate)({
projectRoot,
changedFiles,
lane,
stackProfile,
testsGreen: true,
deps: runnerDeps
});
return planted(result2, strict);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: mutation testing did not run (${message})`);
return planted(skippedMutationResult(stackProfile, "run-failed"), strict);
}
}
function planted(result2, strict) {
return { mutation_result: result2, mutation_strict: strict };
}
function defaultReadProfile(projectRoot) {
return readProjectProfile(projectRoot, { persistMigration: false });
}
async function defaultDetectStackProfile(projectRoot) {
return (await new StackIntrospector().snapshot(projectRoot, { persist: false })).profile;
}
async function defaultRunTestCommand(command, projectRoot) {
const parsed = parseCommandChain(command);
if (!parsed.ok) {
engineLog(
"warn",
`paqad: unsupported shell syntax in the test command: ${parsed.invalidToken}`
);
return { exitCode: 1 };
}
const result2 = await runCommandChain(createDeliveryShell(projectRoot), parsed.steps, projectRoot);
return { exitCode: result2.exitCode };
}
async function defaultSnapshotTree(projectRoot) {
const files = await readGitStatusFiles(projectRoot);
return JSON.stringify(
[...files].sort().map((relativePath) => [relativePath, digestFile(projectRoot, relativePath)])
);
}
// src/verification/repository/judgment-inputs.ts
init_esm_shims();
function computeAcTestMapping(input) {
if (!input.specFrozen) {
return {
outcome: "not-required",
passed: true,
inconclusive: false,
detail: "No frozen spec, so no acceptance criteria to map."
};
}
if (input.map === null) {
const why = input.buildError ? ` (${input.buildError})` : "";
return {
outcome: "did-not-run",
passed: true,
inconclusive: false,
detail: `A frozen spec is on record but the acceptance-criteria map is missing${why}, so no criterion was checked.`
};
}
const acLinks = input.map.forward.filter((link) => link.source === "acceptance-criterion");
if (acLinks.length === 0) {
return {
outcome: "not-required",
passed: true,
inconclusive: false,
detail: describeNoAutomatedCriteria(input.visual ?? [], input.manual ?? [])
};
}
const unproven = acLinks.filter((link) => !link.proven).map((link) => link.promise_id);
if (unproven.length > 0) {
return {
outcome: "fail",
passed: false,
inconclusive: false,
detail: `Automated acceptance criteria with no proving test changed on this branch: ${unproven.join(", ")}.`
};
}
return {
outcome: "pass",
passed: true,
inconclusive: false,
detail: `All ${acLinks.length} automated acceptance criteria map to a proving test.`
};
}
function describeNoAutomatedCriteria(visual, manual) {
if (visual.length === 0 && manual.length === 0) {
return "The frozen spec has no automated acceptance criteria to map.";
}
const named = [
visual.length > 0 ? `visual: ${visual.join(", ")}` : "",
manual.length > 0 ? `manual: ${manual.join(", ")}` : ""
].filter((part) => part.length > 0).join("; ");
return `The frozen spec has only visual or manual acceptance criteria (${named}). Visual ones are left to the visual-evidence gate and manual ones need no mapped test.`;
}
function computeImplementationReview(pendingDecisions, lastSourceEditAt2 = null) {
const editedAt = lastSourceEditAt2 === null ? NaN : Date.parse(lastSourceEditAt2);
const blocking = pendingDecisions.filter((packet) => !openedAfter(packet, editedAt));
const findings = blocking.map((packet) => ({
kind: "decision-violation",
severity: "error",
detail: `Change landed against unresolved decision ${packet.decision_id} (${packet.category}): ${packet.question}`,
decision_id: packet.decision_id
}));
const waiting = pendingDecisions.filter((packet) => openedAfter(packet, editedAt)).map((packet) => ({
decision_id: packet.decision_id,
category: packet.category,
question: packet.question
}));
return { passed: findings.length === 0, findings, waiting };
}
function openedAfter(packet, editedAt) {
if (Number.isNaN(editedAt)) return false;
const createdAt = Date.parse(packet.created_at);
return !Number.isNaN(createdAt) && createdAt > editedAt;
}
function computeSpecReview(input) {
if (input.specReview) {
const openCritical = input.specReview.defects.filter(
(defect) => defect.severity === "critical" && defect.status !== "resolved"
);
if (openCritical.length > 0) {
return {
passed: false,
inconclusive: false,
detail: `Unresolved critical spec-review defects: ${openCritical.map((defect) => defect.defect_id).join(", ")}.`
};
}
return {
passed: true,
inconclusive: false,
detail: "Spec review on record carries no unresolved critical defects."
};
}
if (input.hasFrozenSpec) {
return {
passed: true,
inconclusive: false,
detail: "Spec is frozen (signed off); no open spec-review report."
};
}
if (input.codeChanged) {
return {
passed: true,
inconclusive: true,
detail: "Code changed but no frozen spec or spec-review report was found; whether the spec was frozen and reviewed cannot be proven."
};
}
return {
passed: true,
inconclusive: false,
detail: "No code change requiring a spec review."
};
}
// src/verification/repository/repository-context.ts
var ALWAYS_IN_SCOPE_PREFIXES = ["tests", "docs", ".paqad", ".changeset"];
async function buildRepositoryVerificationContext(options) {
const { projectRoot, origin } = options;
const sessionId = resolveActiveSessionId(projectRoot);
const dirName = resolveActiveFeatureDir(projectRoot, sessionId);
const changeEvidence = await loadChangeEvidence(projectRoot, {
since: dirName ? readChangeStartPointSafe(projectRoot, dirName) : null
});
const sessionScopedFiles = origin === "hook-completion" ? subtractUnchangedBaselineFiles(projectRoot, sessionId, changeEvidence.files) : changeEvidence.files;
const changedFiles = sessionScopedFiles.filter((filePath) => !isPaqadArtifactPath(filePath));
const codeChanged = changedFiles.some((filePath) => isCodeFile(filePath));
const staleDocTargets = await detectStaleDocTargets(projectRoot, changedFiles);
const recordedLane = readRecordedLane(projectRoot, sessionId, dirName);
const checksReport = readChecksReportForFeature(projectRoot, dirName);
const structuredTestResults = checksReport && checksReport.results.length > 0 ? checksReport.results : void 0;
const checksReportStale = checksReportStaleness(projectRoot, checksReport);
const diskMap = await readTraceabilityMapSafely(projectRoot);
const changeMap = await buildAndWriteChangeTraceabilityMap(
{
projectRoot,
dirName,
changedFiles: changeEvidence.files.filter((filePath) => !isPaqadArtifactPath(filePath)),
testResults: structuredTestResults,
lane: recordedLane
},
(message) => appendHooksLog(projectRoot, `verification: ${message}`)
);
const traceabilityMap = effectiveTraceabilityMap(changeMap.result?.map ?? null, diskMap);
const pendingDecisions = readPendingDecisions(projectRoot);
const specReview = await loadSpecReviewSafely(projectRoot);
const acMapping = computeAcTestMapping({
specFrozen: changeMap.result !== null || changeMap.error !== null,
map: changeMap.result?.map ?? null,
visual: changeMap.result?.visual,
manual: changeMap.result?.manual,
buildError: changeMap.error
});
const implementationReview = computeImplementationReview(
pendingDecisions,
await lastSourceEditAt(projectRoot, dirName, changedFiles)
);
const specReviewSignal = computeSpecReview({
specReview,
hasFrozenSpec: changeMap.result !== null || hasFrozenSpec(traceabilityMap),
codeChanged
});
const specBoundary = deriveSpecBoundary(traceabilityMap);
const escalations = [];
if (codeChanged && !structuredTestResults) {
escalations.push(
"test-evidence: no check report on record (`paqad-ai checks run` was not run this change) \u2014 test-evidence strength is Inconclusive here; run the checks or rely on CI."
);
}
const qualityRatchetResult = await runQualityRatchetGate({
projectRoot,
changedFiles,
lane: recordedLane,
stackProfile: null,
deadCodeFiles: readDeadCodeFiles(traceabilityMap),
decisionStore: new DecisionStore(projectRoot)
});
const mutation = await runBackstopMutation({
projectRoot,
origin,
changedFiles,
lane: recordedLane,
deps: options.mutationDeps
});
const context = {
project_root: projectRoot,
verification_origin: origin,
verification_stage: "backstop-completion",
modules: [],
changed_files: changedFiles,
changed_files_source: changeEvidence.source,
...options.hostSessionId ? {
change_own_files: activeChangeFiles(projectRoot, options.hostSessionId),
change_past_specification: changePastSpecification(projectRoot, options.hostSessionId)
} : {},
spec_boundary: specBoundary,
code_changed: codeChanged,
test_files_changed: changedFiles.some((filePath) => isTestFile(filePath)),
documentation_files_changed: changedFiles.some((filePath) => isDocumentationFile(filePath)),
stale_doc_targets: staleDocTargets,
structured_test_results: structuredTestResults,
...checksReportStale ? { checks_report_stale: checksReportStale } : {},
ac_test_mapping_passed: acMapping.passed,
ac_test_mapping_detail: acMapping.detail,
ac_test_mapping_outcome: acMapping.outcome,
spec_review_passed: specReviewSignal.passed,
...specReview ? { spec_review_on_record: true } : {},
...specReviewSignal.inconclusive ? { spec_review_inconclusive: true, spec_review_detail: specReviewSignal.detail } : {},
implementation_review_passed: implementationReview.passed,
implementation_review_findings: implementationReview.findings,
waiting_decisions: implementationReview.waiting,
...checksReport ? { code_tests_lint_passed: checksReport.passed } : {},
quality_ratchet_result: qualityRatchetResult,
...mutation,
lane: recordedLane,
expected_ui_modules: [],
expected_api_modules: [],
expected_integration_modules: [],
expected_error_catalog_modules: [],
registry_refreshed_at: (/* @__PURE__ */ new Date()).toISOString(),
glossary_updated: true,
unchecked_documentation_inputs: UNCHECKED_DOCUMENTATION_INPUTS
};
return { context, escalations };
}
var CHECKS_FRESHNESS_TIMEOUT_MS = 1e4;
function checksReportStaleness(projectRoot, report, timeoutMs = CHECKS_FRESHNESS_TIMEOUT_MS) {
const recorded = report?.tree?.digest;
if (typeof recorded !== "string") return void 0;
if (report?.tree_after_run === "moved") return "different-files";
if (report?.tree_after_run === "unconfirmed") return "unconfirmed";
const current = computeTreeIdentity(projectRoot, { timeoutMs });
if (!current) return "unconfirmed";
return current.digest === recorded ? void 0 : "different-files";
}
var UNCHECKED_DOCUMENTATION_INPUTS = [
"the registries",
"the glossary",
"the expected module docs"
];
function resolveActiveSessionId(projectRoot) {
return resolveSessionId(projectRoot, process.env.CLAUDE_SESSION_ID ?? null);
}
function readChangeStartPointSafe(projectRoot, dirName) {
try {
return readChangeStartPoint(projectRoot, dirName);
} catch {
return null;
}
}
function resolveActiveFeatureDir(projectRoot, sessionId) {
try {
return currentFeature(projectRoot, sessionId);
} catch {
return null;
}
}
function readRecordedLane(projectRoot, sessionId, dirName) {
return recordedLaneOrFull(projectRoot, sessionId, dirName);
}
async function readTraceabilityMapSafely(projectRoot) {
try {
return await readTraceabilityMap(projectRoot);
} catch (error) {
engineLog("warn", `paqad: could not read traceability map (${describeError(error)})`);
return null;
}
}
function effectiveTraceabilityMap(changeMap, diskMap) {
if (changeMap) return changeMap;
if (diskMap?.scope === "change") return null;
return diskMap;
}
function latestDevelopmentRowAt(projectRoot, dirName) {
if (dirName === null) return NaN;
let latest2 = NaN;
try {
for (const row of readFeatureStageUnit(projectRoot, dirName)) {
if (row.stage !== "development") continue;
const at2 = Date.parse(rowRecordedAt(row) ?? "");
if (!Number.isNaN(at2) && (Number.isNaN(latest2) || at2 > latest2)) latest2 = at2;
}
} catch (error) {
engineLog("warn", `paqad: could not read development rows (${describeError(error)})`);
}
return latest2;
}
async function latestFileEditAt(projectRoot, files) {
const times = await Promise.all(
files.map(
(file) => stat2(join91(projectRoot, file)).then(
(info2) => info2.mtimeMs,
() => NaN
)
)
);
const known = times.filter((at2) => !Number.isNaN(at2));
return known.reduce((latest2, at2) => Number.isNaN(latest2) || at2 > latest2 ? at2 : latest2, NaN);
}
async function lastSourceEditAt(projectRoot, dirName, changedFiles) {
const developmentAt = latestDevelopmentRowAt(projectRoot, dirName);
if (!Number.isNaN(developmentAt)) return new Date(developmentAt).toISOString();
const fileAt = await latestFileEditAt(projectRoot, changedFiles);
return Number.isNaN(fileAt) ? null : new Date(fileAt).toISOString();
}
function readPendingDecisions(projectRoot) {
const store = new DecisionStore(projectRoot);
const packets = [];
try {
for (const decisionId of store.listPendingDecisionIds()) {
const result2 = store.readPendingResult(decisionId);
if (result2.packet) {
packets.push(result2.packet);
}
}
} catch (error) {
engineLog("warn", `paqad: could not read pending decisions (${describeError(error)})`);
}
return packets;
}
async function loadSpecReviewSafely(projectRoot) {
try {
const reportPaths = await (0, import_fast_glob17.default)(".paqad/compliance/*/spec-review.json", {
cwd: projectRoot,
absolute: true,
onlyFiles: true
});
if (reportPaths.length === 0) {
return null;
}
const defects = [];
const patternAdvisories = [];
let metadata = null;
for (const reportPath2 of reportPaths) {
const parsed = JSON.parse(await readFile43(reportPath2, "utf8"));
if (Array.isArray(parsed.defects)) {
defects.push(...parsed.defects);
}
if (Array.isArray(parsed.pattern_advisories)) {
patternAdvisories.push(...parsed.pattern_advisories);
}
metadata ??= parsed.metadata ?? null;
}
if (metadata === null) {
return null;
}
return { metadata, defects, pattern_advisories: patternAdvisories };
} catch (error) {
engineLog("warn", `paqad: could not read spec-review reports (${describeError(error)})`);
return null;
}
}
function hasFrozenSpec(map) {
return map !== null && map.forward.some((link) => link.source === "acceptance-criterion");
}
function readDeadCodeFiles(map) {
if (map === null || !map.anchors_known) {
return null;
}
return map.backward.filter((link) => link.role === "orphan").map((link) => link.file);
}
function deriveSpecBoundary(map) {
if (!hasFrozenSpec(map) || map === null || !map.anchors_known) {
return void 0;
}
const deliveringDirs = /* @__PURE__ */ new Set();
for (const link of map.forward) {
for (const file of link.delivering_code) {
const dir = dirOf(file);
if (dir.length > 0) {
deliveringDirs.add(dir);
}
}
}
if (deliveringDirs.size === 0) {
return void 0;
}
return [.../* @__PURE__ */ new Set([...deliveringDirs, ...ALWAYS_IN_SCOPE_PREFIXES])].sort();
}
function dirOf(filePath) {
const normalized = filePath.replace(/\\/g, "/").replace(/^\.?\//, "").trim();
const lastSlash = normalized.lastIndexOf("/");
return lastSlash === -1 ? "" : normalized.slice(0, lastSlash);
}
function describeError(error) {
return error instanceof Error ? error.message : String(error);
}
// src/verification/repository/run-repository-verification.ts
init_esm_shims();
// src/stage-isolation/recipe-receipt.ts
init_esm_shims();
var CODEX_RECIPE_LINE = "recipe read, not injected. On Codex an unfinished stage is caught by the next stage refusing to start and by `paqad-ai stage report`, not sent back.";
function chainRepairLines(rows) {
return rows.filter((row) => row.kind === RECORD_REPAIR_KIND && typeof row.repairs_row === "number").map((row) => {
const running = Array.isArray(row.stage_agents_running) ? ` while ${row.stage_agents_running.join(", ")} was running` : "";
return `Ledger row ${String(row.repairs_row)} broke the chain and was repaired by ${String(row.agent)}${running}: ${String(row.reason)}.`;
});
}
function stageReceiptNotes(projectRoot, dirName) {
const rows = readFeatureStageUnit(projectRoot, dirName);
const repairs = chainRepairLines(rows);
if (readChangeConstants(projectRoot, dirName, rows).lane !== "full") return repairs;
const notes = [...repairs];
if (readFeatureRecord(projectRoot, dirName)?.adapter === "codex-cli") {
notes.push(CODEX_RECIPE_LINE);
}
const older = STAGE_AGENT_STAGES.filter(
(stage) => rows.some((row) => row.kind === "stage_start" && row.stage === stage) && stageLedgerEra(rows, stage) !== "v3"
);
if (older.length > 0) {
notes.push(`These stages ran before the update and hold no recipe proof: ${older.join(", ")}.`);
}
const turns = stageTurnsLine(rows);
if (turns !== null) notes.push(turns);
return notes;
}
var STAGE_BASELINE_TURNS = {
planning: 64,
specification: 35,
development: 109,
review: 44,
checks: 10,
documentation_sync: 17
};
function stageTurnsLine(rows) {
const parts = [];
for (const def of MANDATORY_STAGE_AGENTS) {
const turns = rows.filter(
(row) => row.kind === STAGE_AGENT_KIND && row.event_status === "completed" && row.stage === def.ledgerStage
).reduce((sum, row) => sum + (typeof row.api_turns === "number" ? row.api_turns : 0), 0);
if (turns === 0) continue;
const baseline = STAGE_BASELINE_TURNS[def.ledgerStage];
parts.push(`${def.ledgerStage} ${turns} of ${def.maxTurns} (was ${baseline})`);
}
return parts.length === 0 ? null : `Turns per stage: ${parts.join(", ")}.`;
}
// src/evidence/index.ts
init_esm_shims();
// src/evidence/fan-in.ts
init_esm_shims();
function gateResultsToRows(results, ctx) {
return results.map((result2) => {
const graded = gradeGateResult(result2);
return buildEvidenceRow({
ts: ctx.ts,
engine: "verification-gate",
code: result2.gate,
subject_digest: ctx.subjectDigest,
verdict: graded.verdict,
strength_class: graded.strength_class,
detail: result2.detail,
...graded.skip_kind ? { skip_kind: graded.skip_kind } : {}
});
});
}
function gradeEvidenceGate(gate) {
const { verdict: verdict2, strength_class } = gradeGateResult({
gate: gate.name,
passed: gate.status === "pass",
inconclusive: gate.status === "inconclusive",
...gate.status === "skipped" ? { outcome: gate.skip_kind ?? "not-required" } : {}
});
return { verdict: verdict2, strength_class };
}
function evidenceGatesToRows(gates, ctx) {
return gates.map(
(gate) => buildEvidenceRow({
ts: ctx.ts,
engine: "verification-gate",
code: gate.name,
subject_digest: ctx.subjectDigest,
...gradeEvidenceGate(gate),
detail: gate.detail,
...gate.status === "skipped" && gate.skip_kind ? { skip_kind: gate.skip_kind } : {}
})
);
}
function gradeRatchetVerdict(verdict2) {
if (verdict2.outcome === "blocked") {
return { verdict: "blocked", strength_class: "blocked" };
}
return {
verdict: verdict2.outcome === "regressed" ? "fail" : "pass",
strength_class: "deterministic"
};
}
function ratchetResultToRows(result2, ctx) {
if (!result2) return [];
return result2.verdicts.map((verdict2) => {
const graded = gradeRatchetVerdict(verdict2);
return buildEvidenceRow({
ts: ctx.ts,
engine: "quality-ratchet",
code: `ratchet:${verdict2.measure}:${verdict2.module}`,
subject_digest: ctx.subjectDigest,
verdict: graded.verdict,
strength_class: graded.strength_class,
detail: verdict2.detail
});
});
}
// src/evidence/receipt/authorship.ts
init_esm_shims();
import { existsSync as existsSync47, readFileSync as readFileSync41 } from "fs";
import { join as join92 } from "path";
var NO_HUMAN_ENV = "PAQAD_NO_HUMAN_ATTESTATION";
function isAdapterType(value) {
return value !== void 0 && ADAPTER_TYPES.includes(value);
}
function readOnboardedAgent(projectRoot) {
const path10 = join92(projectRoot, PATHS.ONBOARDING_MANIFEST);
if (!existsSync47(path10)) return void 0;
try {
const manifest = JSON.parse(readFileSync41(path10, "utf8"));
return isAdapterType(manifest.adapter) ? manifest.adapter : void 0;
} catch {
return void 0;
}
}
async function readGitIdentity(projectRoot) {
async function config(key) {
try {
const result2 = await execa("git", ["-C", projectRoot, "config", "--get", key]);
const value = result2.stdout.trim();
return value.length > 0 ? value : void 0;
} catch {
return void 0;
}
}
const [name, email] = await Promise.all([config("user.name"), config("user.email")]);
if (name === void 0 && email === void 0) return null;
return { name, email };
}
function buildChangeAuthorship(input) {
const env2 = input.env ?? {};
const [idProvider, idModel] = splitModelId(env2.PAQAD_MODEL_ID);
const model = nonEmpty(env2.PAQAD_AGENT_MODEL) ?? idModel;
const provider = nonEmpty(env2.PAQAD_AGENT_PROVIDER) ?? idProvider;
const model_id = model !== void 0 && provider !== void 0 ? `${provider}/${model}` : void 0;
const declared = model !== void 0 || provider !== void 0;
const accepting_human = isTruthyEnv(env2[NO_HUMAN_ENV]) || input.gitIdentity == null ? void 0 : pickIdentity(input.gitIdentity);
if (input.agent === void 0 && !declared && accepting_human === void 0) {
return void 0;
}
return {
...input.agent !== void 0 ? { agent: input.agent } : {},
...model !== void 0 ? { model } : {},
...provider !== void 0 ? { provider } : {},
...model_id !== void 0 ? { model_id } : {},
...accepting_human !== void 0 ? { accepting_human } : {},
provenance: declared ? "declared" : "unknown"
};
}
async function resolveChangeAuthorship(input) {
const agent = readOnboardedAgent(input.projectRoot);
const gitIdentity = input.gitIdentity !== void 0 ? input.gitIdentity : await readGitIdentity(input.projectRoot);
return buildChangeAuthorship({ agent, env: input.env, gitIdentity });
}
function splitModelId(raw) {
const value = nonEmpty(raw);
if (value === void 0) return [void 0, void 0];
const slash = value.indexOf("/");
if (slash <= 0 || slash === value.length - 1) return [void 0, value];
return [value.slice(0, slash), value.slice(slash + 1)];
}
function pickIdentity(identity) {
const name = nonEmpty(identity.name);
const email = nonEmpty(identity.email);
if (name === void 0 && email === void 0) return void 0;
return {
...name !== void 0 ? { name } : {},
...email !== void 0 ? { email } : {}
};
}
function nonEmpty(value) {
if (value === void 0) return void 0;
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : void 0;
}
function isTruthyEnv(value) {
return value === "1" || value === "true";
}
// src/evidence/reproducibility.ts
init_esm_shims();
import { existsSync as existsSync48, mkdirSync as mkdirSync21, readFileSync as readFileSync42, renameSync as renameSync6, writeFileSync as writeFileSync22 } from "fs";
import { dirname as dirname40, join as join93 } from "path";
function stampPath(projectRoot) {
return join93(projectRoot, PATHS.EVIDENCE_CONTEXT_STAMP);
}
function readReproducibilityStamp(projectRoot) {
const path10 = stampPath(projectRoot);
if (!existsSync48(path10)) return null;
try {
const parsed = JSON.parse(readFileSync42(path10, "utf8"));
if (typeof parsed?.context_hash !== "string" || parsed.context_hash.length === 0) return null;
return parsed;
} catch {
return null;
}
}
function readReproducibilityPredicate(projectRoot) {
const stamp = readReproducibilityStamp(projectRoot);
if (stamp === null) return null;
return {
context_hash: stamp.context_hash,
determinism: "input-replay",
algo_version: stamp.algo_version,
replayable: true
};
}
// src/evidence/compliance/citations.ts
init_esm_shims();
// src/packs/compliance-packs.ts
init_esm_shims();
var import_yaml10 = __toESM(require_dist(), 1);
import { existsSync as existsSync49, readdirSync as readdirSync12, readFileSync as readFileSync43 } from "fs";
import { homedir as homedir3 } from "os";
import { join as join94 } from "path";
var SOURCE_ORDER = ["built-in", "global", "project"];
var KNOWN_OBLIGATION_CATEGORIES = /* @__PURE__ */ new Set([
"functional",
"edge-case",
"acceptance",
"non-functional",
"unclassified"
]);
var GATE_NAMES = new Set(VERIFICATION_GATES);
function resolveCompliancePackRoots(options = {}) {
return {
"built-in": join94(options.runtimeRoot ?? getRuntimeRoot(), "capabilities", "compliance"),
global: options.globalPacksRoot ?? process.env.PAQAD_GLOBAL_COMPLIANCE_PACKS_ROOT ?? join94(homedir3(), ".paqad", "compliance-packs"),
project: options.projectRoot ? join94(options.projectRoot, ".paqad", "compliance-packs") : null
};
}
var CompliancePackLoader = class {
validator = new SchemaValidator();
load(options = {}) {
const roots = resolveCompliancePackRoots(options);
const packs = /* @__PURE__ */ new Map();
const warnings = [];
for (const source of SOURCE_ORDER) {
const root = roots[source];
if (root === null || !existsSync49(root)) continue;
for (const pack of this.loadPacksFromRoot(root, source)) {
warnings.push(...pack.validation.issues.filter((issue) => issue.level === "warning"));
if (!pack.validation.valid) {
warnings.push(
...pack.validation.issues.filter((issue) => issue.level === "error").map((issue) => ({ ...issue, level: "warning" }))
);
continue;
}
packs.set(pack.manifest.name, pack);
}
}
return { packs, warnings };
}
loadPacksFromRoot(root, source) {
return readdirSync12(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => !entry.name.startsWith("_") && !entry.name.startsWith(".")).map((entry) => this.readPack(join94(root, entry.name), source));
}
readPack(packRoot, source) {
const manifestPath = join94(packRoot, "compliance-pack.yaml");
const issues = [];
if (!existsSync49(manifestPath)) {
return invalid(packRoot, manifestPath, source, [
{ level: "error", path: "/", message: "missing compliance-pack.yaml" }
]);
}
let parsed;
try {
parsed = import_yaml10.default.parse(readFileSync43(manifestPath, "utf8"));
} catch (error) {
return invalid(packRoot, manifestPath, source, [
{
level: "error",
path: "/",
message: `unparseable YAML: ${error instanceof Error ? error.message : String(error)}`
}
]);
}
const schema = this.validator.validate("compliance-pack", parsed);
if (!schema.valid) {
issues.push(
...schema.errors.map((error) => ({
level: "error",
path: error.path,
message: error.message
}))
);
}
const manifest = parsed;
if (schema.valid) {
for (const [m, mapping] of (manifest.mappings ?? []).entries()) {
for (const [s, signal5] of (mapping.satisfied_by ?? []).entries()) {
const at2 = `/mappings/${m}/satisfied_by/${s}`;
if (signal5.type === "gate" && !GATE_NAMES.has(signal5.ref)) {
issues.push({ level: "error", path: at2, message: `unknown gate '${signal5.ref}'` });
}
if (signal5.type === "obligation_category" && !KNOWN_OBLIGATION_CATEGORIES.has(signal5.ref)) {
issues.push({
level: "error",
path: at2,
message: `unknown obligation category '${signal5.ref}'`
});
}
}
}
}
const validation = {
valid: issues.every((issue) => issue.level !== "error"),
issues
};
return { manifest, root: packRoot, manifestPath, source, validation };
}
};
function invalid(root, manifestPath, source, issues) {
return {
manifest: {
kind: "compliance-pack",
name: "",
framework: { id: "", title: "" },
disclaimer: "",
mappings: []
},
root,
manifestPath,
source,
validation: { valid: false, issues }
};
}
function loadCompliancePacks(projectRoot, options = {}) {
const registry = new CompliancePackLoader().load({ ...options, projectRoot });
return [...registry.packs.values()];
}
// src/evidence/compliance/citations.ts
function passingGates(rows) {
const passed = /* @__PURE__ */ new Set();
for (const row of rows) {
if (row.engine === "verification-gate" && row.verdict === "pass") {
passed.add(row.code);
}
}
return passed;
}
function citableGates(mapping, passed) {
const gateSignals = mapping.satisfied_by.filter((signal5) => signal5.type === "gate");
if (gateSignals.length === 0) return [];
const allPassed = gateSignals.every((signal5) => passed.has(signal5.ref));
return allPassed ? gateSignals.map((signal5) => signal5.ref) : [];
}
function resolveComplianceCitations(input) {
let packs;
try {
packs = input.packs ?? loadCompliancePacks(input.projectRoot);
} catch {
return [];
}
if (packs.length === 0) return [];
const passed = passingGates(input.rows);
const citations = [];
for (const pack of packs) {
const { framework, disclaimer, mappings } = pack.manifest;
for (const mapping of mappings) {
const gates = citableGates(mapping, passed);
for (const gate of gates) {
const signal5 = mapping.satisfied_by.find((s) => s.type === "gate" && s.ref === gate);
if (signal5 === void 0) continue;
citations.push({
framework_id: framework.id,
framework_title: framework.title,
...framework.version !== void 0 ? { framework_version: framework.version } : {},
clause_id: mapping.clause.id,
clause_title: mapping.clause.title,
...mapping.clause.url !== void 0 ? { clause_url: mapping.clause.url } : {},
gate,
relation: signal5.relation,
evidence_strength: mapping.evidence_strength,
disclaimer
});
}
}
}
return citations;
}
// src/stage-evidence/finalize.ts
init_esm_shims();
// src/stage-evidence/verify.ts
init_esm_shims();
var REDO_CAP = 2;
function verifyChange(projectRoot, ctx) {
const sessionId = resolveSessionId(projectRoot, ctx.sessionId);
const dirName = ctx.dirName ?? currentFeatureOrThrow(projectRoot, sessionId);
const fold = foldFeature(projectRoot, sessionId, dirName);
const unit = readFeatureStageUnit(projectRoot, dirName);
const lastMutationIdx = lastIndexOfMutation(unit);
const priorFailures = unit.slice(lastMutationIdx + 1).filter((row) => row.kind === "verify" && row.event_status === "failed").length;
const liveMarked = unit.some((row) => row.evidence_source === "live-mark");
let verdict2 = fold.completeness.verdict;
if (verdict2 === "incomplete" && priorFailures >= REDO_CAP) {
verdict2 = "blocked";
}
const ok = verdict2 === "complete" || verdict2 === "recovered";
const blocked = verdict2 === "blocked";
appendFeatureStageRow(
projectRoot,
sessionId,
dirName,
{
kind: "verify",
agent: agentForWriter(ctx.adapter),
event_status: ok ? "completed" : "failed",
note: `bundle=${verdict2}; missing=[${fold.completeness.missing_stages.join(",")}]`
},
ctx.now
);
return {
verdict: verdict2,
ok,
blocked,
live_marked: liveMarked,
missing_stages: fold.completeness.missing_stages,
open_stages: [...stagesWithKind(unit, "stage_start")].filter(
(stage) => stageIsOpen(unit, stage)
),
ordering_violations: fold.completeness.ordering_violations,
redo_attempts: priorFailures,
change_key: fold.change_key
};
}
function currentFeatureOrThrow(projectRoot, sessionId) {
const dirName = currentFeature(projectRoot, sessionId);
if (!dirName) {
throw new Error("No open stage-evidence change to verify (call `open` first).");
}
return dirName;
}
function lastIndexOfMutation(unit) {
let idx = -1;
for (let i = 0; i < unit.length; i++) {
const kind = unit[i].kind;
if (kind === "open" || kind === "stage_start" || kind === "stage_end") idx = i;
}
return idx;
}
// src/stage-evidence/finalize.ts
function finalizeStageEvidence(projectRoot, input) {
try {
if (input.isFeatureDevChange === false) {
return null;
}
const sessionId = resolveSessionId(projectRoot, input.sessionId);
let dirName = currentFeature(projectRoot, sessionId);
if (dirName) {
const existing = readFeatureStageUnit(projectRoot, dirName);
if (liveStageAgents(existing).length === 0) {
endDanglingLiveStages(projectRoot, sessionId, dirName, existing, input);
backfillMissingDevelopment(projectRoot, sessionId, dirName, input);
}
} else {
if (!input.changedFilesCount || input.changedFilesCount <= 0) {
return null;
}
if (sessionClosedAnyFeature(projectRoot, sessionId)) {
return null;
}
dirName = openStageEvidence(projectRoot, {
sessionId,
adapter: input.adapter,
now: input.now
}).dirName;
appendInferredDevelopment(projectRoot, sessionId, dirName, input);
}
const result2 = verifyChange(projectRoot, {
sessionId,
dirName,
adapter: input.adapter,
now: input.now
});
if (result2.ok && !input.deferClose) {
closeVerifiedChange(projectRoot, {
sessionId,
adapter: input.adapter,
verdict: result2.verdict,
now: input.now
});
}
return result2;
} catch {
return null;
}
}
function closeVerifiedChange(projectRoot, input) {
try {
const sessionId = resolveSessionId(projectRoot, input.sessionId);
const dirName = currentFeature(projectRoot, sessionId);
if (!dirName) {
return;
}
appendFeatureStageRow(
projectRoot,
sessionId,
dirName,
{
kind: "close",
agent: agentForWriter(input.adapter),
event_status: "completed",
note: `closed; bundle=${input.verdict}`
},
input.now
);
closeActiveFeature(projectRoot, sessionId, input.now);
} catch {
}
}
function endDanglingLiveStages(projectRoot, sessionId, dirName, rows, input) {
const started = /* @__PURE__ */ new Set();
for (const row of rows) {
if (typeof row.stage !== "string") continue;
if (row.kind === "stage_start" && row.evidence_source === "live-mark") started.add(row.stage);
}
for (const stage of started) {
const stageRows = rows.filter((row) => row.stage === stage);
if (!startedAfterLastEnd(stageRows)) continue;
const artifactPaths = stage === "checks" ? checksEndArtifact(projectRoot, sessionId, dirName, stageRows, input) : [];
if (artifactPaths === null) continue;
try {
endStage(projectRoot, stage, artifactPaths.length > 0 ? { artifactPaths } : {}, {
sessionId,
dirName,
adapter: input.adapter,
now: input.now
});
const from = artifactPaths.length > 0 ? "the checks report" : "the work recorded this turn";
recordRepair(projectRoot, sessionId, dirName, input, `the ${stage} stage end, from ${from}`);
} catch {
}
}
}
function checksEndArtifact(projectRoot, sessionId, dirName, stageRows, input) {
const probe = input.now ? { ...input.probe, now: input.now } : input.probe;
if (liveChecksRunningMarker(projectRoot, sessionId, probe) !== null) {
return null;
}
const lastStart = stageRows.filter((row) => row.kind === "stage_start").at(-1);
const startedAt = Date.parse(rowRecordedAt(lastStart));
const report = readFeatureChecks(projectRoot, dirName);
const reportAt = Date.parse(report?.generated_at ?? report?.recorded_at ?? "");
if (Number.isNaN(startedAt) || Number.isNaN(reportAt) || reportAt < startedAt) {
return null;
}
return [featureFilePath(dirName, "checks")];
}
function backfillMissingDevelopment(projectRoot, sessionId, dirName, input) {
if (!input.changedFilesCount || input.changedFilesCount <= 0) {
return;
}
const rows = readFeatureStageUnit(projectRoot, dirName);
const hasDevelopment = rows.some(
(row) => row.stage === "development" && (row.kind === "stage_start" || row.kind === "stage_end")
);
if (hasDevelopment) {
return;
}
appendInferredDevelopment(projectRoot, sessionId, dirName, input);
}
function recordRepair(projectRoot, sessionId, dirName, input, reason2) {
appendFeatureStageRow(
projectRoot,
sessionId,
dirName,
{ kind: RECORD_REPAIR_KIND, agent: agentForWriter(input.adapter), reason: reason2 },
input.now
);
}
function appendInferredDevelopment(projectRoot, sessionId, dirName, input) {
appendFeatureStageRow(
projectRoot,
sessionId,
dirName,
{
kind: "stage_end",
agent: agentForWriter(input.adapter),
stage: "development",
event_status: "inferred",
evidence_source: "inferred-git",
subject_digest: input.subjectDigest ?? null
},
input.now
);
recordRepair(
projectRoot,
sessionId,
dirName,
input,
"the development stage end, from the changed files"
);
}
// src/feature-evidence/decisions-index.ts
init_esm_shims();
import { readdirSync as readdirSync13, readFileSync as readFileSync44 } from "fs";
function text(value) {
return typeof value === "string" && value.length > 0 ? value : null;
}
function parsePacket(raw) {
try {
const parsed = JSON.parse(raw);
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : null;
} catch {
return null;
}
}
function resolvedAt(packet) {
const iso = text(packet.resolved_at) ?? text(packet.human_response?.responded_at) ?? text(packet.created_at);
return iso === null ? Number.NaN : Date.parse(iso);
}
function changeWindow(projectRoot, dirName) {
const record2 = readFeatureRecord(projectRoot, dirName);
if (record2 === null) return null;
return {
from: Date.parse(record2.recorded_at),
to: isFeatureFinished(record2.status) ? Date.parse(record2.updated_at) : Number.POSITIVE_INFINITY
};
}
function linkedTo(packet, changeKey, window) {
const named = text(packet.change);
if (named !== null) return named === changeKey;
if (typeof packet.context === "string" && packet.context.includes(changeKey)) return true;
if (window === null) return false;
const at2 = resolvedAt(packet);
return at2 >= window.from && at2 <= window.to;
}
function collectFeatureDecisions(projectRoot, dirName) {
const changeKey = featureChangeKey(dirName);
const window = changeWindow(projectRoot, dirName);
let files;
try {
files = readdirSync13(join(projectRoot, PATHS.DECISIONS_RESOLVED_DIR));
} catch {
return [];
}
const entries = [];
for (const file of files.filter((name) => /^D-.+\.json$/.test(name))) {
const path10 = join(PATHS.DECISIONS_RESOLVED_DIR, file);
const raw = readFileSync44(join(projectRoot, path10), "utf8");
const packet = parsePacket(raw);
if (packet === null || !linkedTo(packet, changeKey, window)) continue;
entries.push({
id: text(packet.id) ?? text(packet.decision_id) ?? file.replace(/\.json$/, ""),
category: text(packet.category) ?? "unknown",
path: path10,
content_hash: sha256Hex(raw)
});
}
return entries.sort((a, b) => a.id.localeCompare(b.id));
}
function readFeatureDecisionsIndex(projectRoot, dirName) {
return readFeatureIndexEntries(
projectRoot,
dirName,
"decisions",
"decisions"
);
}
function writeFeatureDecisionsIndex(projectRoot, dirName, options = {}) {
const decisions = collectFeatureDecisions(projectRoot, dirName);
const { path: path10, written } = writeFeatureIndexDocument({
projectRoot,
dirName,
file: "decisions",
key: "decisions",
docType: DECISIONS_DOC_TYPE,
schemaVersion: FEATURE_DOC_SCHEMA_VERSION,
entries: decisions,
sessionId: options.sessionId,
now: options.now
});
return { path: path10, decisions, written };
}
function readIndexedDecisionViews(projectRoot, dirName) {
return (readFeatureDecisionsIndex(projectRoot, dirName) ?? []).map((entry) => {
let raw;
try {
raw = readFileSync44(join(projectRoot, entry.path), "utf8");
} catch {
return {
...entry,
title: null,
chosen: null,
chosen_label: null,
rationale: null,
state: "missing"
};
}
const packet = parsePacket(raw) ?? {};
const chosen = text(packet.chosen) ?? text(packet.human_response?.chosen_option_key);
const label = (packet.options ?? []).find((option2) => option2.option_key === chosen)?.label;
return {
...entry,
title: text(packet.title) ?? text(packet.question),
chosen,
chosen_label: text(label),
rationale: text(packet.rationale) ?? text(packet.human_response?.note),
state: sha256Hex(raw) === entry.content_hash ? "current" : "changed"
};
});
}
// src/decision-reuse/receipt-line.ts
init_esm_shims();
function belongsToChange(row, change, startedAt) {
if (typeof row.change === "string") return row.change === change;
return Date.parse(String(row.ts)) >= startedAt;
}
function countRows(rows) {
const counts = { accepted: 0, changed: 0, none: 0, standing: 0 };
for (const row of rows) {
if (row.kind === "reuse" && row.match_kind === "standing") counts.standing += 1;
if (row.kind !== "suggestion") continue;
if (row.outcome === "accepted") counts.accepted += 1;
if (row.outcome === "changed") counts.changed += 1;
if (row.outcome === "none") counts.none += 1;
}
return counts;
}
function plural(count2, one, many) {
return `${count2} ${count2 === 1 ? one : many}`;
}
function formatDecisionsLine(counts) {
const suggested = counts.accepted + counts.changed;
const parts = [];
if (suggested > 0) {
parts.push(
`${plural(suggested, "earlier answer", "earlier answers")} suggested, ${counts.accepted} accepted, ${counts.changed} changed`
);
}
if (counts.none > 0) parts.push(`${counts.none} checked, none fit`);
if (counts.standing > 0) {
parts.push(`${plural(counts.standing, "standing answer", "standing answers")} used`);
}
return parts.length === 0 ? null : `decisions: ${parts.join("; ")}`;
}
function decisionsReceiptLine(projectRoot, dirName, sessionId) {
const feature = readFeatureRecord(projectRoot, dirName);
if (feature === null) return null;
const sessions = /* @__PURE__ */ new Set([feature.session_id, ...sessionId ? [sessionId] : []]);
const change = featureChangeKey(dirName);
const startedAt = Date.parse(feature.recorded_at);
const rows = [...sessions].flatMap((session) => readSessionDoc(projectRoot, DECISION_REUSE_DOC_TYPE, session)).filter((row) => belongsToChange(row, change, startedAt));
return formatDecisionsLine(countRows(rows));
}
// src/hld/report.ts
init_esm_shims();
function designSignOffPrLine(projectRoot, dirName) {
if (dirName === null) return "";
const record2 = readHld(projectRoot, dirName);
if (record2?.state === "approved" && record2.approved_at && record2.approval_link) {
return prSignedOffLine(record2.ref, record2.approved_at, record2.approval_link);
}
if (record2?.state === "skipped" && record2.skip_reason) return prSkippedLine(record2.skip_reason);
return "";
}
function designSignOffReceiptLine(projectRoot, dirName, lane) {
if (dirName === null || !designSignOffApplies(loadDesignSignOff(projectRoot), lane)) {
return RECEIPT_OFF_LINE;
}
const record2 = readHld(projectRoot, dirName);
if (record2 === null) return RECEIPT_NOT_WRITTEN_LINE;
if (record2.state === "approved") return receiptSignedOffLine(record2.approval_link ?? "");
if (record2.state === "skipped") return receiptSkippedLine(record2.skip_reason ?? "");
if (record2.state === "not_posted") return RECEIPT_NOT_POSTED_LINE;
return RECEIPT_POSTED_LINE;
}
// src/feature-evidence/report-writer.ts
init_esm_shims();
import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync23 } from "fs";
import { dirname as dirname41, isAbsolute as isAbsolute4, join as join96 } from "path";
// src/feature-evidence/export.ts
init_esm_shims();
import { readFileSync as readFileSync45, readdirSync as readdirSync14, rmSync as rmSync13 } from "fs";
import { join as join95 } from "path";
function readText4(projectRoot, rel) {
try {
return readFileSync45(join95(projectRoot, rel), "utf8");
} catch {
return null;
}
}
function readJson2(projectRoot, rel) {
const text2 = readText4(projectRoot, rel);
if (text2 === null) return null;
try {
return JSON.parse(text2);
} catch {
return null;
}
}
function exportFeatureBundle(projectRoot, dirName, exportedAt) {
const files = {};
for (const key of Object.keys(FEATURE_BUNDLE_FILES)) {
const rel = featureFilePath(dirName, key);
if (FEATURE_BUNDLE_FILES[key].endsWith(".jsonl")) {
const rows = key === "evidence" ? readEvidenceRowsAt(projectRoot, rel) : readUnitFile(projectRoot, rel);
if (rows.length > 0) files[key] = rows;
} else if (FEATURE_BUNDLE_FILES[key].endsWith(".md")) {
const text2 = readText4(projectRoot, rel);
if (text2 !== null) files[key] = text2;
} else {
const parsed = readJson2(projectRoot, rel);
if (parsed !== null) files[key] = parsed;
}
}
return {
dir_name: dirName,
exported_at: exportedAt,
files,
strays: strayBundleFiles(projectRoot, dirName)
};
}
function liveFeatureDirs(projectRoot) {
const live = /* @__PURE__ */ new Set();
let sessionFiles;
try {
sessionFiles = readdirSync14(join95(projectRoot, PATHS.FEATURE_EVIDENCE_SESSION_DIR)).filter(
(name) => name.endsWith(".json")
);
} catch {
return live;
}
for (const file of sessionFiles) {
const control = readSessionControl(projectRoot, file.replace(/\.json$/, ""));
if (control.active) live.add(control.active);
for (const paused of control.paused) live.add(paused);
}
return live;
}
function pruneFeatureBundles(projectRoot, keep) {
const live = liveFeatureDirs(projectRoot);
const ordered = listFeatureDirs(projectRoot).sort(
(a, b) => (parseFeatureDirName(b)?.ulid ?? b).localeCompare(parseFeatureDirName(a)?.ulid ?? a)
);
const removed = [];
const kept = [];
let keptNonLive = 0;
for (const dirName of ordered) {
if (live.has(dirName)) {
kept.push(dirName);
continue;
}
if (keptNonLive < keep) {
kept.push(dirName);
keptNonLive++;
continue;
}
try {
rmSync13(join95(projectRoot, featureDir(dirName)), { recursive: true, force: true });
removed.push(dirName);
} catch {
kept.push(dirName);
}
}
return { removed, kept };
}
// src/feature-evidence/report.ts
init_esm_shims();
import { createHash as createHash13 } from "crypto";
// src/feature-evidence/contribution-table.ts
init_esm_shims();
var ROLE_ACRONYMS = { qa: "QA", ux: "UX", ui: "UI", db: "DB" };
function roleInPlainWords(role) {
const words = role.split("-");
return words.map((word, index) => {
const acronym = ROLE_ACRONYMS[word];
if (acronym) return acronym;
if (index === 0) return word.charAt(0).toUpperCase() + word.slice(1);
return word;
}).join(" ");
}
// src/feature-evidence/report.ts
function escapeHtml(value) {
return String(value ?? "").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
}
function formatDuration(ms) {
if (ms === null || !Number.isFinite(ms) || ms < 0) return "unknown";
if (ms < 1e3) return `${Math.round(ms)}ms`;
const totalSeconds = Math.round(ms / 1e3);
if (totalSeconds < 60) {
const s = ms / 1e3;
return `${s < 10 ? s.toFixed(1) : Math.round(s)}s`;
}
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
if (minutes < 60) return seconds === 0 ? `${minutes}m` : `${minutes}m ${seconds}s`;
const hours = Math.floor(minutes / 60);
const remMinutes = minutes % 60;
return remMinutes === 0 ? `${hours}h` : `${hours}h ${remMinutes}m`;
}
function clockLabel(iso) {
if (!iso) return "";
const parsed = Date.parse(iso);
if (!Number.isFinite(parsed)) return "";
return iso.slice(11, 19);
}
var GLYPH_FOR = PAQAD_STATUS_GLYPH;
function glyphWord(kind, word) {
return `${GLYPH_FOR[kind]} ${escapeHtml(word)}`;
}
function verifyFeatureReceiptSelf(envelope) {
try {
const payload = Buffer.from(envelope.payload, "base64");
const encoded = pae(envelope.payloadType ?? DSSE_PAYLOAD_TYPE, payload);
const prev = envelope.paqad?.prev_receipt_hash ?? ZERO_DIGEST;
const expected = createHash13("sha256").update(encoded).update(prev).digest("hex");
return envelope.paqad?.receipt_hash === expected;
} catch {
return false;
}
}
function readReceiptIntegrity(bundle) {
const envelope = bundle.files.receipt ?? null;
if (!envelope || typeof envelope !== "object" || !envelope.payload) {
return {
present: false,
verified: false,
statement: null,
envelope: null,
rows: [],
unsealedRows: []
};
}
const statement = decodeReceiptStatement(envelope);
return {
present: true,
verified: verifyFeatureReceiptSelf(envelope),
statement,
envelope,
...receiptRowsOf(statement, bundle.files.evidence)
};
}
function deriveReportVerdict(fold, receiptStatement, evidenceRows) {
const hasFailedStage = fold.stages.some((stage) => stage.state === "failed");
const { rows, unsealedRows } = receiptRowsOf(receiptStatement, evidenceRows);
const gateRows2 = receiptStatement?.predicate ? [...rows, ...unsealedRows] : asRows(evidenceRows);
const gateKind = verdictKindFor(
gateRows2.map((row) => ({ status: String(row.verdict).toLowerCase() }))
);
const hasFailedGate = gateKind === "fail" || String(receiptStatement?.predicate?.verification_result ?? "").toUpperCase() === "FAILED";
if (hasFailedStage || hasFailedGate) return "fail";
const verdict2 = fold.completeness.verdict;
if (verdict2 === "complete" || verdict2 === "recovered") return gateKind;
if (verdict2 === "cannot-verify") return "inconclusive";
return "fail";
}
function receiptRowResult(row) {
const v = String(row.verdict ?? "").toLowerCase();
if (v === "pass") return { kind: "good", word: v };
if (v === "fail") return { kind: "failed", word: v };
if (v === "skipped") {
return {
kind: "skipped",
word: row.skip_kind === "did-not-run" ? "did not run" : "not required"
};
}
return { kind: "needsLook", word: v };
}
function receiptRowsOf(statement, evidenceRows) {
if (!statement?.predicate) return { rows: [], unsealedRows: [] };
const split = splitReceiptEvidenceRows(
statement,
asRows(evidenceRows)
);
return { rows: split.sealed, unsealedRows: split.unsealed };
}
function dedupeByHash(rows) {
const seen = /* @__PURE__ */ new Set();
const out = [];
for (const row of rows) {
const key = row.content_hash ?? `${row.engine}\0${row.code}\0${row.verdict}\0${row.detail}`;
if (seen.has(key)) continue;
seen.add(key);
out.push(row);
}
return out;
}
var VERDICT_WORD = {
pass: PAQAD_VERDICT.pass,
fail: PAQAD_VERDICT.fail,
inconclusive: PAQAD_VERDICT.inconclusive
};
var VERDICT_KIND_GLYPH = {
pass: "good",
fail: "failed",
inconclusive: "needsLook"
};
function stageView(stage, endedByBackstop) {
switch (stage.state) {
case "complete":
case "redone": {
if (stage.duration_unreliable) {
return {
glyphKind: "needsLook",
word: PAQAD_STATUS_LABEL.needsLook,
note: "marked (near-zero duration \u2014 no recorded work)"
};
}
let note = stage.evidence_source === "inferred-git" ? "done (reconstructed from the diff)" : stage.evidence_source === "inferred-artifact" ? "done (inferred from an artifact)" : "done";
if (endedByBackstop) {
note = `${note} \u2014 includes idle time (closed by the completion backstop)`;
}
if (stage.state === "redone") note = `${note} (redone)`;
return { glyphKind: "good", word: PAQAD_STATUS_LABEL.good, note };
}
case "inconclusive":
return {
glyphKind: "needsLook",
word: PAQAD_STATUS_LABEL.needsLook,
note: "marked (no recorded work)"
};
case "failed":
return { glyphKind: "failed", word: PAQAD_STATUS_LABEL.failed, note: "failed" };
case "running":
return {
glyphKind: "needsLook",
word: PAQAD_STATUS_LABEL.needsLook,
note: "started, not finished"
};
case "skipped":
return { glyphKind: "skipped", word: PAQAD_STATUS_LABEL.skipped, note: "skipped" };
default:
return {
glyphKind: "needsLook",
word: PAQAD_STATUS_LABEL.needsLook,
note: "not recorded"
};
}
}
function stageEndedByBackstop(rawStageRows, stage) {
let byBackstop = false;
for (const row of rawStageRows) {
if (row.kind === "stage_end" && row.stage === stage) {
byBackstop = row.agent === BACKSTOP_WRITER || row.adapter === BACKSTOP_WRITER;
}
}
return byBackstop;
}
function asRows(value) {
return Array.isArray(value) ? value : [];
}
function panel(id, title, body, emptyNote) {
const inner = body.trim().length > 0 ? body : `<p class="empty">${escapeHtml(emptyNote ?? "Nothing recorded.")}</p>`;
return `<section class="panel" id="${escapeHtml(id)}"><div class="panel-head"><h2>${escapeHtml(title)}</h2><a class="back" href="#overview">\u2191 overview</a></div>${inner}</section>`;
}
function renderTimeline(fold, rawStageRows) {
const shown = fold.stages.filter(
(stage) => isMandatoryStage(stage.stage) || stage.started_at !== null || stage.ended_at !== null
);
const items = shown.map((stage) => {
const view = stageView(stage, stageEndedByBackstop(rawStageRows, stage.stage));
const label = escapeHtml(stage.stage.replace(/_/g, " "));
const start = clockLabel(stage.started_at);
const end = clockLabel(stage.ended_at);
const duration = stage.duration_ms !== null && !stage.duration_unreliable ? formatDuration(stage.duration_ms) : stage.started_at && !stage.ended_at ? "open" : "\u2014";
const timing = start || end ? `<span class="when">${escapeHtml(start || "\u2014")}${end ? ` \u2192 ${escapeHtml(end)}` : ""}</span>` : "";
return `<li class="stage"><span class="glyph">${GLYPH_FOR[view.glyphKind]}</span><span class="stage-name">${label}</span><span class="dur">${escapeHtml(duration)}</span><span class="stage-note">${glyphWordless(view.word)} \xB7 ${escapeHtml(view.note)}</span>${timing}</li>`;
}).join("");
return panel("timeline", "Timeline", `<ol class="timeline">${items}</ol>`);
}
function glyphWordless(word) {
return `<span class="word">${escapeHtml(word)}</span>`;
}
function renderLaneMoves(bundle) {
const feature = bundle.files.feature;
const items = [
feature?.lane_resized && `Lowered from ${escapeHtml(feature.lane_resized.from)} to ${escapeHtml(feature.lane_resized.to)} at plan compile: ${escapeHtml(feature.lane_resized.reason)}`,
feature?.lane_raised && `Raised from ${escapeHtml(feature.lane_raised.from)} to ${escapeHtml(feature.lane_raised.to)}: ${escapeHtml(feature.lane_raised.reason)}`
].filter((item) => typeof item === "string");
if (items.length === 0) return "";
return `<h3>Lane</h3><ul class="lane-moves">${items.map((item) => `<li>${item}</li>`).join("")}</ul>`;
}
function renderPlan(bundle) {
const plan = bundle.files.plan;
if (!plan) {
return panel(
"plan",
"Plan",
"",
"No plan was recorded for this change. The plan is written when the planning stage is compiled (paqad-ai plan compile)."
);
}
const parts = [];
if (plan.summary) parts.push(`<p>${escapeHtml(plan.summary)}</p>`);
parts.push(renderLaneMoves(bundle));
const steps = plan.steps ?? [];
if (steps.length > 0) {
const items = steps.map(
(step) => `<li><strong>${escapeHtml(step.id ?? "")}</strong> ${escapeHtml(step.description ?? "")}${step.module ? ` <span class="tag">${escapeHtml(step.module)}</span>` : ""}</li>`
).join("");
parts.push(`<h3>Steps</h3><ol class="steps">${items}</ol>`);
}
const decisions = plan.decisions ?? [];
if (decisions.length > 0) {
parts.push(
`<h3>Decisions</h3><ul>${decisions.map((d) => `<li>${escapeHtml(d)}</li>`).join("")}</ul>`
);
}
const risks = plan.risks ?? [];
if (risks.length > 0) {
const items = risks.map(
(risk) => `<li><span class="risk">${escapeHtml(risk.description ?? "")}</span><span class="mitigation">Mitigation: ${escapeHtml(risk.mitigation ?? "\u2014")}</span></li>`
).join("");
parts.push(`<h3>Risks</h3><ul class="risks">${items}</ul>`);
}
const reuse = plan.reuse;
if (reuse) {
const consulted = (reuse.consulted ?? []).map(
(entry) => `<li><span class="tag">${escapeHtml(entry.source ?? "")}</span> ${escapeHtml(entry.query ?? "")}${entry.target ? ` <span class="tag">${escapeHtml(entry.target)}</span>` : ""} \u2014 ${entry.hits ?? 0} hit(s)</li>`
).join("");
const reusing = (reuse.reusing ?? []).map(
(claim) => `<li><strong>${escapeHtml(claim.symbol ?? "")}</strong>${claim.package ? ` <span class="tag">${escapeHtml(frameworkTag(claim))}</span>` : claim.file ? ` <span class="tag">${escapeHtml(claim.file)}</span>` : ""} \u2014 ${escapeHtml(claim.how ?? "")}${verifiedNote(claim)}</li>`
).join("");
const constructs = (reuse.new_constructs ?? []).map(
(construct) => `<li><strong>${escapeHtml(construct.name ?? "")}</strong> \u2014 ${escapeHtml(construct.justification ?? "")}</li>`
).join("");
parts.push("<h3>Reuse</h3>");
parts.push(frameworkReuseSummary(reuse.reusing ?? []));
if (consulted) parts.push(`<h4>Consulted</h4><ul class="consulted">${consulted}</ul>`);
if (reusing) parts.push(`<h4>Reusing</h4><ul class="reusing">${reusing}</ul>`);
if (constructs)
parts.push(`<h4>New, justified</h4><ul class="new-constructs">${constructs}</ul>`);
}
return panel("plan", "Plan", parts.join(""), "The plan is empty.");
}
function frameworkTag(claim) {
return claim.version ? `${claim.package}@${claim.version}` : claim.package ?? "";
}
function verifiedNote(claim) {
if (claim.package === void 0) {
return "";
}
if (claim.provenance === "asserted") {
return ' <span class="verified">\u{1F7E2} verified against the installed version</span>';
}
if (claim.provenance === "unknown-dynamic") {
return ' <span class="unverified">\u{1F7E1} provided dynamically \u2014 not statically verified</span>';
}
return ' <span class="unverified">\u{1F7E1} not verified against an installed version</span>';
}
function frameworkReuseSummary(claims) {
const framework = claims.filter((claim) => claim.package !== void 0);
if (framework.length === 0) {
return "";
}
const verified = framework.filter((claim) => claim.provenance === "asserted").length;
return `<p class="reuse-summary">${framework.length} framework-native reuse claim(s); ${verified} verified against the installed version's declarations. A plan naming a removed or deprecated framework API does not compile.</p>`;
}
function renderSpec(bundle) {
const spec = bundle.files.specification;
if (!spec) {
return panel(
"spec",
"Specification",
"",
"No frozen specification was recorded. The spec is written when it is frozen before code (paqad-ai spec freeze)."
);
}
const parts = [];
if (spec.frozen?.frozen_at) {
parts.push(
`<p class="freeze">${glyphWord("good", "Frozen")} ${escapeHtml(clockLabel(spec.frozen.frozen_at) || spec.frozen.frozen_at)}${spec.frozen.signed_off_by ? `, signed off by ${escapeHtml(spec.frozen.signed_off_by)}` : ""}.</p>`
);
}
const behaviour = spec.behaviour ?? [];
if (behaviour.length > 0) {
parts.push(
`<h3>Behaviour</h3><ul>${behaviour.map((b) => `<li>${escapeHtml(b)}</li>`).join("")}</ul>`
);
}
const acs = spec.acceptance_criteria ?? [];
if (acs.length > 0) {
const items = acs.map((ac) => {
const gwt = [
ac.given ? `<span class="gwt-k">Given</span> ${escapeHtml(ac.given)}` : "",
ac.when ? `<span class="gwt-k">When</span> ${escapeHtml(ac.when)}` : "",
ac.then ? `<span class="gwt-k">Then</span> ${escapeHtml(ac.then)}` : ""
].filter(Boolean).join(" ");
return `<li class="ac"><strong>${escapeHtml(ac.criterion_id ?? "")}</strong> ${gwt || '<span class="empty">no given/when/then recorded</span>'}${ac.proof_type ? ` <span class="tag">${escapeHtml(ac.proof_type)}</span>` : ""}</li>`;
}).join("");
parts.push(`<h3>Acceptance criteria</h3><ul class="acs">${items}</ul>`);
}
const invariants = spec.invariants ?? [];
if (invariants.length > 0) {
const items = invariants.map(
(inv) => `<li>${inv.confirmed ? glyphWord("good", "confirmed") : glyphWord("needsLook", "unconfirmed")} <strong>${escapeHtml(inv.invariant_id ?? "")}</strong> ${escapeHtml(inv.statement ?? "")}</li>`
).join("");
parts.push(`<h3>Invariants</h3><ul class="invariants">${items}</ul>`);
}
const findings = spec.pipeline?.findings ?? [];
const trace = spec.trace ?? {};
if (findings.length > 0 && Object.keys(trace).length > 0) {
const byId = new Map(findings.map((finding) => [finding.id ?? "", finding]));
const rows = Object.entries(trace).map(([line, source]) => {
const finding = byId.get(source);
if (!finding) return "";
return `<tr><td>${escapeHtml(line)}</td><td>${escapeHtml(roleInPlainWords(finding.role ?? ""))}</td><td>${escapeHtml(finding.claim ?? "")}</td></tr>`;
}).filter(Boolean).join("");
if (rows) {
parts.push(
`<h3>Who contributed what</h3><table class="contrib"><thead><tr><th>Line</th><th>From</th><th>What the expert said</th></tr></thead><tbody>${rows}</tbody></table>`
);
}
}
return panel("spec", "Specification", parts.join(""), "The specification is empty.");
}
function renderRules(bundle) {
const rows = asRows(bundle.files.ruleRun);
if (rows.length === 0) {
return panel(
"rules",
"Rules",
"",
"No rule-script runs were recorded. Rule scripts run during the checks stage of a feature-development change."
);
}
let deterministic = 0;
let heuristic = 0;
let skipped5 = 0;
let blocked = false;
for (const row of rows) {
const counts = row.counts ?? {};
deterministic += Number(counts.deterministic ?? 0);
heuristic += Number(counts.heuristic ?? 0);
skipped5 += Number(counts.skipped ?? 0);
if (row.blocking === true) blocked = true;
}
const total = deterministic + heuristic + skipped5;
const blockLine = blocked ? `<p>${glyphWord("failed", "Blocked")}: at least one rule run blocked the change.</p>` : `<p>${glyphWord("good", "Clear")}: no rule run blocked the change.</p>`;
const body = `<p>${rows.length} rule run${rows.length === 1 ? "" : "s"} recorded, ${total} finding${total === 1 ? "" : "s"} in total (${deterministic} deterministic \xB7 ${heuristic} heuristic \xB7 ${skipped5} skipped).</p>${blockLine}`;
return panel("rules", "Rules", body);
}
function renderRetrieval(bundle) {
const rows = asRows(bundle.files.rag);
if (rows.length === 0) {
return panel(
"retrieval",
"Retrieval",
"",
"No retrieval was recorded for this change (grep is the honest default; RAG is an optional accelerator)."
);
}
const byKind = /* @__PURE__ */ new Map();
for (const row of rows) {
const kind = typeof row.kind === "string" ? row.kind : "other";
byKind.set(kind, (byKind.get(kind) ?? 0) + 1);
}
const refreshed = byKind.get("refreshed") ?? 0;
const called = byKind.get("called") ?? 0;
const used = byKind.get("used") ?? 0;
const fallback = byKind.get("fallback") ?? 0;
const lines = [];
if (called > 0) lines.push(`retrieval ran ${called} time${called === 1 ? "" : "s"}`);
if (used > 0) lines.push(`delivered context ${used} time${used === 1 ? "" : "s"}`);
if (fallback > 0)
lines.push(
`fell back to grep ${fallback} time${fallback === 1 ? "" : "s"} (scores were below the floor)`
);
if (refreshed > 0)
lines.push(`refreshed the index ${refreshed} time${refreshed === 1 ? "" : "s"}`);
const summary = lines.length > 0 ? `${lines.join(", ")}.` : "Retrieval activity recorded.";
const body = `<p>${escapeHtml(summary.charAt(0).toUpperCase() + summary.slice(1))}</p>`;
return panel("retrieval", "Retrieval", body);
}
function renderReceipt(integrity) {
if (!integrity.present) {
return panel(
"receipt",
"Verification receipt",
"",
"No verification receipt was written. The signed receipt is an enterprise governance capability \u2014 enable enterprise (and enterprise_evidence_ledger) to record it. The gates still ran; only the receipt file is gated off."
);
}
const statement = integrity.statement;
const result2 = String(statement?.predicate?.verification_result ?? "").toUpperCase();
const resultKind = result2 === "PASSED" ? "good" : result2 === "FAILED" ? "failed" : "needsLook";
const integrityLine = integrity.verified ? `${glyphWord("good", "Integrity verified")} \u2014 the receipt's hash chain recomputes from its own bytes (hash-chained, not a signature).` : `${glyphWord("failed", "Could not verify integrity")} \u2014 the receipt's hash chain does not recompute; treat it as tampered or corrupt.`;
const rows = dedupeByHash(integrity.rows);
const unsealed = dedupeByHash(integrity.unsealedRows);
const rowHtml = (row, sealed) => {
const { kind, word } = receiptRowResult(row);
const note = sealed ? "" : ' <em class="unsealed">(recorded after the seal, not covered by it)</em>';
return `<tr><td><code>${escapeHtml(row.code ?? "")}</code>${note}</td><td>${GLYPH_FOR[kind]} ${escapeHtml(word)}</td><td>${escapeHtml(row.detail ?? "")}</td></tr>`;
};
const rowsHtml = rows.length + unsealed.length > 0 ? `<table class="gates"><thead><tr><th>Gate</th><th>Result</th><th>Detail</th></tr></thead><tbody>${[
...rows.map((row) => rowHtml(row, true)),
...unsealed.map((row) => rowHtml(row, false))
].join("")}</tbody></table>` : '<p class="empty">The receipt carries no graded gate rows.</p>';
const body = `<p class="receipt-result">Result: ${GLYPH_FOR[resultKind]} ${escapeHtml(result2 || "n/a")}</p><p>${integrityLine}</p>${rowsHtml}`;
return panel("receipt", "Verification receipt", body);
}
function renderAiBom(bundle) {
const aiBom = bundle.files.aiBom;
if (!aiBom) {
return panel(
"aibom",
"AI bill of materials",
"",
"No AI-BOM was written. The CycloneDX AI-BOM is an enterprise governance capability \u2014 enable enterprise (and enterprise_ai_bom) to record it."
);
}
const components = aiBom.components ?? [];
const rows = components.map(
(component) => `<tr><td><code>${escapeHtml(component.name ?? "")}</code></td><td><code class="sha">${escapeHtml((component.hashes?.[0]?.content ?? "").slice(0, 16))}</code></td></tr>`
).join("");
const table = components.length > 0 ? `<table class="bom"><thead><tr><th>File</th><th>SHA-256</th></tr></thead><tbody>${rows}</tbody></table>` : '<p class="empty">No file components recorded.</p>';
const body = `<p>${components.length} file${components.length === 1 ? "" : "s"} inventoried${aiBom.serialNumber ? ` \xB7 CycloneDX serial <code>${escapeHtml(aiBom.serialNumber)}</code>` : ""}.</p>${table}`;
return panel("aibom", "AI bill of materials", body);
}
function deliveryBranches(bundle) {
const feature = bundle.files.feature;
const delivery = bundle.files.delivery;
return {
branch: feature?.branch ?? delivery?.branch ?? null,
base_branch: feature?.base_branch ?? delivery?.base_branch ?? null
};
}
function renderDelivery(bundle) {
const delivery = bundle.files.delivery;
if (!delivery) {
return panel(
"delivery",
"Delivery",
"",
"No delivery record yet. The commit trail is linked by the git post-commit / post-merge hooks once the change is committed."
);
}
const commits = delivery.commits ?? [];
const branches = deliveryBranches(bundle);
const parts = [];
parts.push(
`<p>Branch <code>${escapeHtml(branches.branch ?? "unknown")}</code>${branches.base_branch ? ` onto <code>${escapeHtml(branches.base_branch)}</code>` : ""}.</p>`
);
if (commits.length > 0) {
const items = commits.map(
(commit) => `<li><code class="sha">${escapeHtml((commit.sha ?? "").slice(0, 10))}</code> ${escapeHtml(commit.subject ?? "")}</li>`
).join("");
parts.push(
`<p>${commits.length} commit${commits.length === 1 ? "" : "s"}${delivery.merge_commit ? `, merged as <code class="sha">${escapeHtml(delivery.merge_commit.slice(0, 10))}</code>` : ""}.</p><ul class="commits">${items}</ul>`
);
} else {
parts.push('<p class="empty">No commits linked yet.</p>');
}
return panel("delivery", "Delivery", parts.join(""));
}
function renderReview(bundle) {
const review = bundle.files.review;
if (!review) {
return panel(
"review",
"Review",
"",
"No review was recorded for this change. The review is written when the review stage is recorded (paqad-ai review record)."
);
}
const parts = [];
if (review.verdict) {
parts.push(
`<p class="verdict"><strong>${escapeHtml(reviewVerdictLabel(review.verdict))}</strong></p>`
);
}
if (review.summary) parts.push(`<p>${escapeHtml(review.summary)}</p>`);
const findings = review.findings ?? [];
if (findings.length > 0) {
const items = findings.map(
(finding) => `<li><span class="tag">${escapeHtml(finding.severity ?? "")}</span> ${escapeHtml(finding.description ?? "")}${finding.file ? ` <code>${escapeHtml(finding.file)}</code>` : ""}</li>`
).join("");
parts.push(`<h3>Findings</h3><ul class="findings">${items}</ul>`);
} else {
parts.push('<p class="empty">No findings were raised.</p>');
}
const checked = review.checked ?? [];
if (checked.length > 0) {
parts.push(
`<h3>Checked</h3><ul>${checked.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>`
);
}
if (review.rollback) {
parts.push(`<h3>Rollback</h3><p>${escapeHtml(review.rollback)}</p>`);
}
return panel("review", "Review", parts.join(""));
}
function renderDecisions(bundle, views) {
const index = bundle.files.decisions?.decisions;
if (!index || index.length === 0) {
return panel(
"decisions",
"Decisions",
"",
"No decisions were resolved for this change. When one is, it is listed here from its tracked packet."
);
}
const byId = new Map(views.map((view) => [view.id, view]));
const items = index.map((entry) => {
const view = byId.get(entry.id);
const head = `<strong>${escapeHtml(view?.title ?? entry.id)}</strong> <span class="tag">${escapeHtml(entry.category)}</span>`;
const lines = [];
if (view?.chosen) {
lines.push(`Chosen: ${escapeHtml(view.chosen_label ?? view.chosen)}`);
}
if (view?.rationale) lines.push(`Why: ${escapeHtml(view.rationale)}`);
if (view?.state === "changed") {
lines.push(`${glyphWord("needsLook", "Changed")} since it was indexed`);
} else if (view?.state === "missing") {
lines.push(`${glyphWord("needsLook", "Missing")}: the tracked packet is gone`);
}
const detail = lines.map((line) => `<br>${line}`).join("");
return `<li>${head}${detail}<br><code>${escapeHtml(entry.path)}</code></li>`;
}).join("");
return panel("decisions", "Decisions", `<ul class="findings">${items}</ul>`);
}
function reviewVerdictLabel(verdict2) {
if (verdict2 === "safe-to-merge") return "Safe to merge";
if (verdict2 === "needs-attention") return "Needs your attention";
if (verdict2 === "inconclusive") return "Inconclusive";
return verdict2;
}
function renderFooter() {
const legend = escapeHtml(paqadGlyphLegend());
const terms = PAQAD_TERM_TRANSLATIONS.map(
(translation) => `<tr><td class="term">${escapeHtml(translation.term)}</td><td>${escapeHtml(translation.plain)}</td></tr>`
).join("");
return `<footer class="footer">
<p class="legend">${legend}</p>
<details><summary><span class="h3">What these words mean</span></summary>
<table class="terms"><tbody>${terms}</tbody></table>
</details>
<p class="provenance">This page was generated locally by a script. No AI was involved, and no data left this machine.</p>
</footer>`;
}
function totalReliableDuration(fold) {
return fold.stages.reduce(
(sum, stage) => stage.duration_ms !== null && !stage.duration_unreliable ? sum + stage.duration_ms : sum,
0
);
}
function buildOverviewTiles(bundle, fold, integrity) {
const tiles = [];
const passed = fold.completeness.required_passed;
const total = fold.completeness.required_total;
tiles.push({
target: "timeline",
label: "Stages recorded",
value: `${passed}/${total}`,
sub: passed >= total ? "all mandatory stages done" : "some stages incomplete",
kind: passed >= total ? "good" : "needsLook"
});
tiles.push({
target: "timeline",
label: "Active time",
value: formatDuration(totalReliableDuration(fold)),
sub: "summed across recorded stages"
});
const ruleRows = asRows(bundle.files.ruleRun);
let findings = 0;
let blocked = false;
for (const row of ruleRows) {
const counts = row.counts ?? {};
findings += Number(counts.deterministic ?? 0) + Number(counts.heuristic ?? 0);
if (row.blocking === true) blocked = true;
}
tiles.push({
target: "rules",
label: "Rule findings",
value: ruleRows.length === 0 ? "\u2014" : String(findings),
sub: ruleRows.length === 0 ? "no rule runs" : blocked ? "a rule blocked the change" : "nothing blocked",
kind: ruleRows.length === 0 ? "skipped" : blocked ? "failed" : "good"
});
const ragRows = asRows(bundle.files.rag);
tiles.push({
target: "retrieval",
label: "Retrieval events",
value: ragRows.length === 0 ? "\u2014" : String(ragRows.length),
sub: ragRows.length === 0 ? "grep only (RAG not used)" : "index + query activity"
});
tiles.push({
target: "receipt",
label: "Verification receipt",
value: !integrity.present ? "Off" : integrity.verified ? "Verified" : "Unverifiable",
sub: !integrity.present ? "enterprise governance off" : integrity.verified ? "hash chain recomputes" : "hash chain does not recompute",
kind: !integrity.present ? "skipped" : integrity.verified ? "good" : "failed"
});
const aiBom = bundle.files.aiBom;
const componentCount = Array.isArray(aiBom?.components) ? aiBom.components.length : null;
tiles.push({
target: "aibom",
label: "AI-BOM files",
value: aiBom === void 0 ? "Off" : String(componentCount ?? 0),
sub: aiBom === void 0 ? "enterprise governance off" : "inventoried with SHA-256"
});
const delivery = bundle.files.delivery;
const commitCount = Array.isArray(delivery?.commits) ? delivery.commits.length : 0;
const deliveryBranch = delivery === void 0 ? null : deliveryBranches(bundle).branch;
tiles.push({
target: "delivery",
label: "Commits",
value: delivery === void 0 ? "\u2014" : String(commitCount),
sub: deliveryBranch ? `on ${deliveryBranch}` : "not linked yet"
});
return tiles;
}
function renderOverview(title, headerMeta, verdict2, tiles) {
const hero = `<a class="hero ${verdict2}" href="#timeline"><span class="hero-verdict">${GLYPH_FOR[VERDICT_KIND_GLYPH[verdict2]]} ${escapeHtml(VERDICT_WORD[verdict2])}</span><span class="hero-meta">${headerMeta}</span></a>`;
const cards = tiles.map(
(tile) => `<a class="tile" href="#${escapeHtml(tile.target)}"><span class="tile-label">${escapeHtml(tile.label)}</span><span class="tile-value">${tile.kind ? `${GLYPH_FOR[tile.kind]} ` : ""}${escapeHtml(tile.value)}</span><span class="tile-sub">${escapeHtml(tile.sub)}</span></a>`
).join("");
return `<section id="overview" class="overview"><h1 class="page-title">${escapeHtml(title)}</h1>${hero}<div class="tiles">${cards}</div></section>`;
}
function renderSubmenu() {
const items = [
["overview", "Overview"],
["timeline", "Timeline"],
["plan", "Plan"],
["spec", "Spec"],
["rules", "Rules"],
["retrieval", "Retrieval"],
["receipt", "Receipt"],
["aibom", "AI-BOM"],
["delivery", "Delivery"],
["review", "Review"],
["decisions", "Decisions"],
["checks", "Checks"],
["visual-evidence", "Visual evidence"]
];
return `<nav class="submenu">${items.map(([id, label]) => `<a href="#${id}">${escapeHtml(label)}</a>`).join("")}</nav>`;
}
function stepProvenance(step) {
if (step.journey_id !== AGENT_ATTACHED_JOURNEY) return "";
return step.ac ? ` (agent-attached, ${step.ac})` : " (agent-attached)";
}
function renderVisualEvidence(bundle) {
const ve = bundle.files.visualEvidence;
if (!ve) {
return panel(
"visual-evidence",
"Visual evidence",
"",
"No visual evidence captured. Turn on visual_evidence and add a capture script for a confirmed journey so frontend changes record their documented flows."
);
}
const parts = [];
const captured = ve.steps.filter((step) => step.status === "captured");
const source = ve.source ? ` Source: ${ve.source}.` : "";
parts.push(
`<p>${escapeHtml(`${captured.length} step(s) captured across ${ve.plan.length} flow(s) \u2014 result: ${ve.result}.${source}`)}</p>`
);
if (ve.gif) {
parts.push(
`<figure class="ve-gif"><img src="${escapeHtml(ve.gif.file)}" alt="Overview of the captured flow"><figcaption>Overview (${ve.gif.frames} frame${ve.gif.frames === 1 ? "" : "s"}, ${ve.gif.frame_ms}ms each)</figcaption></figure>`
);
}
if (captured.length > 0) {
const items = captured.map(
(step) => `<figure class="ve-step"><img src="${escapeHtml(step.dir)}/image.png" alt="${escapeHtml(step.caption)}" loading="lazy"><figcaption>${escapeHtml(`${step.index}. ${step.caption}${stepProvenance(step)}`)}</figcaption></figure>`
).join("");
parts.push(`<div class="ve-grid">${items}</div>`);
}
const failed = ve.steps.filter((step) => step.status === "failed");
for (const step of failed) {
parts.push(
`<p class="empty">${escapeHtml(`Step ${step.index} (${step.caption}) failed: ${step.failure ?? "selector-not-found"}.`)}</p>`
);
}
for (const skip of ve.skips) {
parts.push(
`<p class="empty">${escapeHtml(`Absent because ${skip.reason}: ${skip.detail}`)}</p>`
);
}
return panel("visual-evidence", "Visual evidence", parts.join(""));
}
function renderChecks(bundle) {
const checks = bundle.files.checks;
if (!checks || !Array.isArray(checks.commands) || checks.commands.length === 0) {
return panel(
"checks",
"Checks",
"",
"No check commands were recorded for this change. `paqad-ai checks run` writes them into the bundle."
);
}
const parts = [];
if (checks.mode) {
const proc = checks.mode.processes ? ` \xD7${checks.mode.processes}` : "";
const fallback = checks.mode.fallback_reason ? ` \u2014 fell back: ${checks.mode.fallback_reason}` : "";
parts.push(
`<p class="muted">Test mode: <span class="word">${escapeHtml(`${checks.mode.test_mode}${proc}`)}</span>${escapeHtml(fallback)}</p>`
);
}
const rows = checks.commands.map((command) => {
const glyph = GLYPH_FOR[command.passed ? "good" : "failed"];
const name = command.logical_command ?? command.command;
return `<tr><td>${glyph} ${escapeHtml(name)}</td><td class="dur">${formatDuration(command.duration_ms)}</td></tr>`;
}).join("");
parts.push(
`<table><thead><tr><th>Command</th><th>Duration</th></tr></thead><tbody>${rows}</tbody></table>`
);
if (checks.critical_path && checks.critical_path.logical_command) {
parts.push(
`<p class="muted">Critical path: <span class="word">${escapeHtml(checks.critical_path.logical_command)}</span> (${formatDuration(checks.critical_path.duration_ms)}).</p>`
);
}
if (Array.isArray(checks.flaky_under_parallel) && checks.flaky_under_parallel.length > 0) {
const items = checks.flaky_under_parallel.map((flaky) => {
const loc = flaky.file_path ? `${flaky.file_path}${flaky.line_number !== null ? `:${flaky.line_number}` : ""}` : "";
return `<li>${escapeHtml(flaky.test_id)}${loc ? ` <span class="muted">(${escapeHtml(loc)})</span>` : ""}</li>`;
}).join("");
parts.push(`<h3>Flaky under parallel \u2014 recorded, not blocking</h3><ul>${items}</ul>`);
}
return panel("checks", "Checks", parts.join(""));
}
var STYLE = `
:root{color-scheme:light dark;--bg:#fafafa;--card:#ffffff;--ink:#0f172a;--muted:#64748b;--line:#e2e8f0;--accent:#2563eb;--good:#16a34a;--fail:#dc2626;--warn:#d97706;--tag:#eef2ff;--tag-ink:#3730a3;--bar:#0f172a;--bar-fg:#f8fafc}
@media (prefers-color-scheme:dark){:root{--bg:#0b1020;--card:#111827;--ink:#e5e7eb;--muted:#94a3b8;--line:#1f2937;--accent:#60a5fa;--good:#4ade80;--fail:#f87171;--warn:#fbbf24;--tag:#1e293b;--tag-ink:#c7d2fe;--bar:#111827;--bar-fg:#f8fafc}}
:root[data-theme=dark]{--bg:#0b1020;--card:#111827;--ink:#e5e7eb;--muted:#94a3b8;--line:#1f2937;--accent:#60a5fa;--good:#4ade80;--fail:#f87171;--warn:#fbbf24;--tag:#1e293b;--tag-ink:#c7d2fe;--bar:#111827;--bar-fg:#f8fafc}
:root[data-theme=light]{--bg:#fafafa;--card:#ffffff;--ink:#0f172a;--muted:#64748b;--line:#e2e8f0;--accent:#2563eb;--good:#16a34a;--fail:#dc2626;--warn:#d97706;--tag:#eef2ff;--tag-ink:#3730a3;--bar:#0f172a;--bar-fg:#f8fafc}
*{box-sizing:border-box}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Inter,Roboto,sans-serif;color:var(--ink);background:var(--bg);margin:0;line-height:1.5;font-size:15px}
main{max-width:900px;margin:0 auto;padding:20px}
h1,h2,.h2,h3,.h3{margin:0}
.page-title{font-size:22px;font-weight:650;margin:0 0 14px}
/* Top bar with the paqad wordmark */
.topbar{position:sticky;top:0;z-index:5;display:flex;align-items:center;gap:12px;background:var(--bar);color:var(--bar-fg);padding:12px 20px}
.brand{font-size:17px;font-weight:700;letter-spacing:.01em;display:flex;align-items:baseline;gap:6px}
.brand .mark{color:#60a5fa;font-size:18px}
.brand-sub{color:color-mix(in srgb,var(--bar-fg) 65%,transparent);font-size:13px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.verdict-pill{font-size:13px;font-weight:640;padding:5px 12px;border-radius:999px;text-decoration:none;border:1px solid transparent;white-space:nowrap}
.verdict-pill.pass{background:color-mix(in srgb,var(--good) 22%,transparent);color:var(--bar-fg);border-color:var(--good)}
.verdict-pill.fail{background:color-mix(in srgb,var(--fail) 26%,transparent);color:var(--bar-fg);border-color:var(--fail)}
.verdict-pill.inconclusive{background:color-mix(in srgb,var(--warn) 26%,transparent);color:var(--bar-fg);border-color:var(--warn)}
/* Sticky submenu */
.submenu{position:sticky;top:47px;z-index:4;display:flex;gap:2px;flex-wrap:wrap;background:var(--bg);border-bottom:1px solid var(--line);padding:8px 20px}
.submenu a{color:var(--muted);text-decoration:none;font-size:13px;font-weight:560;padding:5px 10px;border-radius:7px}
.submenu a:hover{background:color-mix(in srgb,var(--accent) 12%,transparent);color:var(--accent)}
/* Overview hero + tiles */
.hero{display:flex;flex-direction:column;gap:4px;border-radius:14px;padding:18px 20px;margin:0 0 18px;border:1px solid var(--line);text-decoration:none;color:inherit}
.hero.pass{background:color-mix(in srgb,var(--good) 13%,transparent);border-color:var(--good)}
.hero.fail{background:color-mix(in srgb,var(--fail) 13%,transparent);border-color:var(--fail)}
.hero.inconclusive{background:color-mix(in srgb,var(--warn) 13%,transparent);border-color:var(--warn)}
.hero-verdict{font-size:20px;font-weight:680}
.hero-meta{color:var(--muted);font-size:12.5px}
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;margin:0 0 8px}
.tile{display:flex;flex-direction:column;gap:3px;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:14px 16px;text-decoration:none;color:inherit}
.tile:hover{border-color:var(--accent)}
.tile-label{color:var(--muted);font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.03em}
.tile-value{font-size:24px;font-weight:680;font-variant-numeric:tabular-nums}
.tile-sub{color:var(--muted);font-size:12.5px}
/* Detail panels \u2014 hidden until the submenu targets them */
.panel{display:none;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:18px 20px;margin:18px 0;scroll-margin-top:96px}
.panel:target{display:block}
.panel-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin:0 0 10px}
.panel-head h2{font-size:17px;font-weight:620}
.back{font-size:12px;color:var(--muted);text-decoration:none;white-space:nowrap}
.back:hover{color:var(--accent)}
h3,.h3{font-size:13px;font-weight:620;margin:16px 0 6px;color:var(--muted);text-transform:uppercase;letter-spacing:.03em}
.empty{color:var(--muted);font-style:italic;margin:6px 0}
.muted{color:var(--muted);font-weight:400}
.ve-gif{margin:10px 0}.ve-gif img{max-width:100%;border:1px solid var(--line);border-radius:8px}
.ve-gif figcaption,.ve-step figcaption{color:var(--muted);font-size:13px;margin-top:4px}
.ve-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;margin:10px 0}
.ve-step{margin:0}.ve-step img{max-width:100%;border:1px solid var(--line);border-radius:8px;display:block}
ul,ol{margin:6px 0;padding-left:20px}
li{margin:4px 0}
.timeline{list-style:none;padding:0}
.stage{display:grid;grid-template-columns:22px 150px 74px 1fr;gap:8px;align-items:baseline;padding:7px 0;border-bottom:1px solid var(--line)}
.stage:last-child{border-bottom:0}
.stage-name{font-weight:560;text-transform:capitalize}
.dur{color:var(--muted);font-variant-numeric:tabular-nums;font-size:13px}
.stage-note{color:var(--ink);font-size:13px}
.stage .when{grid-column:2 / -1;color:var(--muted);font-size:12px;font-variant-numeric:tabular-nums}
.word{font-weight:560}
.tag{background:var(--tag);color:var(--tag-ink);border-radius:6px;padding:1px 7px;font-size:12px;font-weight:560}
code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12.5px;background:color-mix(in srgb,var(--muted) 12%,transparent);border-radius:5px;padding:1px 5px}
code.sha{letter-spacing:.02em}
table{width:100%;border-collapse:collapse;font-size:13px;margin:8px 0}
th,td{text-align:left;padding:6px 8px;border-bottom:1px solid var(--line);vertical-align:top}
th{color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.03em;font-size:11.5px}
.risks li,.acs li{margin:8px 0}
.mitigation{display:block;color:var(--muted);font-size:13px}
.gwt-k{font-weight:640;color:var(--accent)}
.freeze{margin:0 0 4px}
pre.review{white-space:pre-wrap;word-break:break-word;background:color-mix(in srgb,var(--muted) 8%,transparent);border-radius:8px;padding:12px;font-size:13px;overflow-x:auto}
summary{cursor:pointer;list-style:revert}
.footer{color:var(--muted);font-size:13px;margin-top:24px;border-top:1px solid var(--line);padding-top:16px}
.legend{font-size:13px}
.terms td{border:0;padding:3px 8px 3px 0}
.terms .term{font-weight:600;color:var(--ink);white-space:nowrap}
.provenance{margin-top:12px;font-style:italic}
/* Framework reuse verification, stated rather than implied. */
.reuse-summary{font-size:13px;color:var(--muted);margin:4px 0 8px}
.verified,.unverified{font-size:12px;white-space:nowrap}
.unverified{color:var(--muted)}
@page{margin:16mm}
/* Print: reveal every panel and the full page so a Save-as-PDF is complete. */
@media print{.topbar{position:static}.submenu{display:none}.panel{display:block!important;break-inside:avoid;border-color:#bbb}.back{display:none}body{background:#fff;color:#000}}
`;
function renderFeatureReportHtml(bundle, fold, options) {
const parts = parseFeatureDirName(bundle.dir_name);
const feature = bundle.files.feature;
const featureTitle = feature?.title !== void 0 && feature.title !== parts?.slug ? feature.title : void 0;
const plan = bundle.files.plan;
const title = featureTitle ?? plan?.title ?? (parts ? parts.slug.replace(/-/g, " ") : bundle.dir_name).replace(
/\b\w/g,
(c) => c.toUpperCase()
);
const integrity = readReceiptIntegrity(bundle);
const verdict2 = options.verdict ?? deriveReportVerdict(fold, integrity.statement, bundle.files.evidence);
const rawStageRows = asRows(bundle.files.stageEvidence);
const headerMeta = [
parts?.issue ? `Issue #${escapeHtml(parts.issue)}` : "",
parts?.ulid ? `ULID ${escapeHtml(parts.ulid)}` : "",
`Generated ${escapeHtml(options.generatedAt)}`,
options.paqadVersion ? `paqad ${escapeHtml(options.paqadVersion)}` : ""
].filter(Boolean).join(" \xB7 ");
const tiles = buildOverviewTiles(bundle, fold, integrity);
const topbar = `<header class="topbar"><div class="brand"><span class="mark">\u25B8</span> paqad</div><div class="brand-sub">evidence report \xB7 ${escapeHtml(title)}</div><a class="verdict-pill ${verdict2}" href="#overview">${GLYPH_FOR[VERDICT_KIND_GLYPH[verdict2]]} ${escapeHtml(VERDICT_WORD[verdict2])}</a></header>`;
const body = [
renderOverview(title, headerMeta, verdict2, tiles),
renderTimeline(fold, rawStageRows),
renderPlan(bundle),
renderSpec(bundle),
renderRules(bundle),
renderRetrieval(bundle),
renderReceipt(integrity),
renderAiBom(bundle),
renderDelivery(bundle),
renderReview(bundle),
renderDecisions(bundle, options.decisions ?? []),
renderChecks(bundle),
renderVisualEvidence(bundle),
renderFooter()
].join("\n");
return `<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${escapeHtml(title)} \u2014 paqad evidence report</title>
<style>${STYLE}</style>
</head>
<body>
${topbar}
${renderSubmenu()}
<main>
${body}
</main>
</body>
</html>
`;
}
// src/feature-evidence/report-writer.ts
var REPORT_DOC_TYPE = "paqad.report";
var REPORT_SCHEMA_VERSION = 1;
function withHeaderTag(html, tag) {
return html.replace("</head>", `${tag}
</head>`);
}
function featureReportEnabled(projectRoot, env2 = process.env) {
return resolveFrameworkConfig(projectRoot, env2).features.feature_report;
}
function writeFeatureReport(projectRoot, dirName, options = {}) {
const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
const sessionId = options.sessionId ?? "report";
const bundle = exportFeatureBundle(projectRoot, dirName, generatedAt);
const fold = foldFeature(projectRoot, sessionId, dirName);
const page = renderFeatureReportHtml(bundle, fold, {
generatedAt,
paqadVersion: options.paqadVersion ?? null,
decisions: readIndexedDecisionViews(projectRoot, dirName),
...options.verdict ? { verdict: options.verdict } : {}
});
const header = buildTextHeader({
docType: REPORT_DOC_TYPE,
change: featureChangeKey(dirName),
sessionId: documentSessionId(projectRoot, dirName, options.sessionId),
schemaVersion: REPORT_SCHEMA_VERSION,
body: page,
now: () => new Date(generatedAt)
});
const html = withHeaderTag(page, renderHeaderScript(header));
const abs = options.outPath ? isAbsolute4(options.outPath) ? options.outPath : join96(projectRoot, options.outPath) : join96(projectRoot, featureReportPath(dirName));
mkdirSync22(dirname41(abs), { recursive: true });
const tmp = `${abs}.tmp-${process.pid}`;
writeFileSync23(tmp, html, "utf8");
renameWithRetrySync(tmp, abs);
return { path: abs, html };
}
function resolveReportFeatureRef(projectRoot, sessionId, ref, activeDirName) {
if (ref) {
const sessionMatch = resolveFeatureRef(projectRoot, sessionId, ref);
if (sessionMatch) return sessionMatch;
return scanAllFeatureDirs(projectRoot, ref);
}
if (activeDirName) return activeDirName;
return mostRecentFeatureDir(projectRoot);
}
function scanAllFeatureDirs(projectRoot, ref) {
const needle = ref.trim().replace(/^#/, "");
const dirs = listFeatureDirs(projectRoot);
for (const dirName of dirs) {
if (dirName === ref || dirName === needle) return dirName;
const parts = parseFeatureDirName(dirName);
if (parts && (parts.ulid === needle || parts.issue === needle || parts.slug === needle)) {
return dirName;
}
}
for (const dirName of dirs) {
const parts = parseFeatureDirName(dirName);
if (parts && parts.slug.includes(needle)) return dirName;
}
return null;
}
function mostRecentFeatureDir(projectRoot) {
const dirs = listFeatureDirs(projectRoot).sort(
(a, b) => (parseFeatureDirName(b)?.ulid ?? b).localeCompare(parseFeatureDirName(a)?.ulid ?? a)
);
return dirs[0] ?? null;
}
// src/stage-evidence/narration-audit.ts
init_esm_shims();
var NARRATION_PREFIX = "\u25B8 paqad";
function isAgentNarratableStage(evidenceSource) {
return evidenceSource === "live-mark" || evidenceSource === "redo";
}
function auditTurnNarration(input) {
if (!input.transcriptText) return [];
const pending = new Set(input.recorded.filter(isKnownStage));
if (pending.size === 0) return [];
const narrationLines = paqadLines(extractAssistantText(input.transcriptText));
return STAGE_EVIDENCE_STAGES.filter(
(stage) => pending.has(stage) && !narrationLines.some((line) => mentionsStage(line, stage))
);
}
function unnarratedAdvisory(stages) {
if (stages.length === 0) return "";
const names = stages.join(", ");
return `${NARRATION_PREFIX} \xB7 you recorded ${stages.length === 1 ? "a stage" : "stages"} you never said out loud: ${names}.
The hook narration does not render on Claude Code Desktop, so the developer saw nothing. Include the end-of-change receipt and one \`\u25B8 paqad\` line per stage above in your VISIBLE reply, in the final message of this turn \u2014 text emitted between tool calls is not reliably rendered.`;
}
function paqadLines(text2) {
return text2.split("\n").map((line) => line.trim()).filter((line) => line.includes(NARRATION_PREFIX));
}
function mentionsStage(line, stage) {
const haystack = line.toLowerCase();
return haystack.includes(STAGE_NARRATION[stage].toLowerCase()) || haystack.includes(stage.replace(/_/g, " ")) || haystack.includes(stage);
}
// src/duplication/scan.ts
init_esm_shims();
// src/duplication/detect.ts
init_esm_shims();
// src/duplication/corpus.ts
init_esm_shims();
import { readFile as readFile44 } from "fs/promises";
import { isAbsolute as isAbsolute5, relative as relative17, join as join97 } from "path";
async function loadCorpus(options) {
const { projectRoot } = options;
const excluded = new Set(options.changedFiles.map(normalizeRel));
const chunkIndex = await new ChunkIndexManager(projectRoot).load();
if (chunkIndex) {
const chunks = [];
for (const entry of chunkIndex.entries) {
for (const chunk of entry.chunks) {
const file = toRelative(projectRoot, chunk.source_file);
if (!excluded.has(file)) {
chunks.push(corpusChunk(chunk, file));
}
}
}
return chunks;
}
const stored = await loadStoredChunks(projectRoot);
return stored.map((chunk) => ({ chunk, file: toRelative(projectRoot, chunk.source_file) })).filter(({ file }) => !excluded.has(file)).map(({ chunk, file }) => corpusChunk(chunk, file));
}
async function loadStoredChunks(projectRoot) {
try {
const index = new FileVectorIndex(PATHS.VECTOR_INDEX, PATHS.VECTOR_META);
const payload = await index.load(projectRoot);
return payload?.items ?? [];
} catch {
return [];
}
}
function corpusChunk(chunk, file) {
return {
id: chunk.id,
file,
content: chunk.content,
charCount: chunk.char_count,
exportedSymbols: chunk.exported_symbols
};
}
function normalizeRel(path10) {
return path10.replace(/\\/g, "/");
}
function toRelative(projectRoot, sourceFile) {
const normalized = sourceFile.replace(/\\/g, "/");
if (!isAbsolute5(sourceFile)) {
return normalized;
}
return relative17(projectRoot, sourceFile).replace(/\\/g, "/");
}
function resolveChunkLineRange(fileText, content) {
if (content.length === 0) {
return null;
}
const index = fileText.indexOf(content);
if (index === -1) {
return null;
}
const start = countNewlines(fileText.slice(0, index)) + 1;
const spanned = content.split("\n").length;
return { start, end: start + spanned - 1 };
}
function meaningfulLineCount(content) {
return content.split("\n").filter((line) => line.trim().length > 0).length;
}
function countNewlines(text2) {
let count2 = 0;
for (let index = 0; index < text2.length; index += 1) {
if (text2[index] === "\n") {
count2 += 1;
}
}
return count2;
}
async function readFileText(projectRoot, file) {
try {
return await readFile44(join97(projectRoot, file), "utf8");
} catch {
return null;
}
}
// src/duplication/hunks.ts
init_esm_shims();
import { existsSync as existsSync50 } from "fs";
import { readFile as readFile45 } from "fs/promises";
import { join as join98 } from "path";
var HUNK_HEADER = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/;
function parseUnifiedDiff(diffText) {
const byFile = /* @__PURE__ */ new Map();
let current = null;
for (const rawLine of diffText.split("\n")) {
if (rawLine.startsWith("+++ ")) {
const target = rawLine.slice(4).trim();
current = target === "/dev/null" ? null : stripDiffPrefix(target);
if (current !== null && !byFile.has(current)) {
byFile.set(current, []);
}
continue;
}
const hunk = HUNK_HEADER.exec(rawLine);
if (hunk && current !== null) {
const start = Number(hunk[1]);
const count2 = hunk[2] === void 0 ? 1 : Number(hunk[2]);
if (count2 > 0) {
byFile.get(current).push({ start, end: start + count2 - 1 });
}
}
}
return [...byFile.entries()].map(([file, ranges]) => ({ file, ranges }));
}
function stripDiffPrefix(path10) {
const withoutPrefix = path10.replace(/^[ab]\//, "");
return withoutPrefix.replace(/\\/g, "/");
}
async function collectAddedRanges(options) {
const { projectRoot, changedFiles } = options;
if (changedFiles.length === 0) {
return [];
}
const parsed = await diffTrackedRanges(projectRoot, changedFiles);
const seen = new Map(parsed.map((entry) => [entry.file, entry]));
for (const file of changedFiles) {
if (seen.has(file)) {
continue;
}
const wholeFile = await wholeFileRange(projectRoot, file);
if (wholeFile) {
seen.set(file, wholeFile);
}
}
return [...seen.values()];
}
async function diffTrackedRanges(projectRoot, changedFiles) {
try {
const result2 = await execa(
"git",
[...PINNED_DIFF_ARGS, "--unified=0", "HEAD", "--", ...changedFiles],
{ cwd: projectRoot, reject: false }
);
if (result2.exitCode !== 0 || result2.stdout.trim() === "") {
return [];
}
return parseUnifiedDiff(result2.stdout);
} catch {
return [];
}
}
async function wholeFileRange(projectRoot, file) {
const abs = join98(projectRoot, file);
if (!existsSync50(abs)) {
return null;
}
try {
const content = await readFile45(abs, "utf8");
const lineCount = content.split("\n").length;
if (content.trim() === "") {
return { file, ranges: [] };
}
return { file, ranges: [{ start: 1, end: lineCount }] };
} catch {
return null;
}
}
function lineInRanges(line, ranges) {
return ranges.some((range) => line >= range.start && line <= range.end);
}
function rangesOverlap(start, end, ranges) {
return ranges.some((range) => start <= range.end && end >= range.start);
}
// src/duplication/jscpd.ts
init_esm_shims();
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync46 } from "fs";
import { tmpdir as tmpdir3 } from "os";
import { join as join99 } from "path";
// src/codebase-health/gather.ts
init_esm_shims();
// src/codebase-health/secret-patterns.ts
init_esm_shims();
import { createHash as createHash14 } from "crypto";
var SECRET_PATTERNS = [
{ rule: "private-key", pattern: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/ },
{ rule: "aws-access-key", pattern: /\bAKIA[0-9A-Z]{16}\b/ },
{
rule: "generic-api-key",
pattern: /(?:api[_-]?key|secret|token|password)\s*[:=]\s*['"][A-Za-z0-9/+_-]{16,}['"]/i
},
{ rule: "bearer-token", pattern: /\bBearer\s+[A-Za-z0-9._-]{20,}\b/ }
];
function redactedFingerprint(value) {
return createHash14("sha256").update(value).digest("hex").slice(0, 12);
}
// src/codebase-health/gather.ts
function safeParse(raw) {
try {
return JSON.parse(raw);
} catch {
return null;
}
}
function parseOsvScannerJson(raw) {
const parsed = safeParse(raw);
if (!parsed?.results) return [];
const records = [];
for (const result2 of parsed.results) {
for (const pkg of result2.packages ?? []) {
for (const vuln of pkg.vulnerabilities ?? []) {
records.push({
package_name: pkg.package?.name ?? "unknown",
ecosystem: pkg.package?.ecosystem ?? "unknown",
version: pkg.package?.version ?? "unknown",
advisory_id: vuln.id ?? "UNKNOWN",
summary: vuln.summary ?? "",
details: vuln.details ?? ""
});
}
}
}
return records;
}
function parseNpmAuditJson(raw) {
const parsed = safeParse(raw);
if (!parsed?.vulnerabilities) return [];
const records = [];
for (const [name, entry] of Object.entries(parsed.vulnerabilities)) {
const advisory = (entry.via ?? []).find(
(via) => typeof via === "object"
);
if (!advisory) continue;
records.push({
package_name: entry.name ?? name,
ecosystem: "npm",
version: "installed",
advisory_id: advisory.url ?? advisory.title ?? "NPM-ADVISORY",
summary: advisory.title ?? "",
details: advisory.url ?? ""
});
}
return records;
}
function parseGitleaksJson(raw) {
const parsed = safeParse(raw);
if (!Array.isArray(parsed)) return [];
return parsed.map((entry) => ({
file: entry.File ?? "unknown",
line: entry.StartLine ?? 0,
rule: entry.RuleID ?? "secret",
fingerprint: entry.Fingerprint ?? redactedFingerprint(entry.Secret ?? `${entry.File}:${entry.StartLine}`),
source: "gitleaks"
}));
}
function parseJscpdJson(raw) {
const parsed = safeParse(raw);
if (!parsed?.duplicates) return [];
return parsed.duplicates.map((dup) => {
const blocks = [dup.firstFile, dup.secondFile].filter((file) => Boolean(file)).map((file) => ({
file: file.name ?? "unknown",
start_line: file.start ?? 0,
end_line: file.end ?? 0
}));
return { lines: dup.lines ?? 0, blocks, source: "jscpd" };
}).filter((cluster) => cluster.blocks.length > 0);
}
function builtinSecretScan(files) {
const matches = [];
for (const file of files) {
const lines = file.content.split("\n");
for (let index = 0; index < lines.length; index += 1) {
const text2 = lines[index];
for (const { rule, pattern } of SECRET_PATTERNS) {
const found = pattern.exec(text2);
if (!found) continue;
matches.push({
file: file.path,
line: index + 1,
rule,
fingerprint: redactedFingerprint(found[0]),
source: "builtin-regex"
});
}
}
}
return matches;
}
function gatherStaleDocCandidates(inputs) {
const candidates = [];
for (const input of inputs) {
if (input.doc_committed_at === null || input.references.length === 0) continue;
const newerSources = input.references.filter(
(ref) => ref.committed_at !== null && ref.committed_at > input.doc_committed_at
);
if (newerSources.length === 0) continue;
candidates.push({
doc: input.doc,
reason: `Doc last changed before ${newerSources.length} of the source file(s) it references.`,
referenced_sources: newerSources.map((ref) => ref.source)
});
}
return candidates;
}
// src/duplication/jscpd.ts
function locationKey(file, startLine) {
return `${file.replace(/\\/g, "/")}:${startLine}`;
}
function jscpdLocationKeys(clusters) {
const keys = /* @__PURE__ */ new Set();
for (const cluster of clusters) {
for (const block of cluster.blocks) {
keys.add(locationKey(block.file, block.start_line));
}
}
return keys;
}
function isCorroborated(file, lineStart, lineEnd, keys) {
const normalized = file.replace(/\\/g, "/");
for (let line = lineStart; line <= lineEnd; line += 1) {
if (keys.has(`${normalized}:${line}`)) {
return true;
}
}
return false;
}
async function corroborateWithJscpd(options) {
const { projectRoot, changedFiles } = options;
if (changedFiles.length === 0) {
return /* @__PURE__ */ new Set();
}
try {
const outDir = mkdtempSync2(join99(tmpdir3(), "paqad-jscpd-"));
await execa("jscpd", ["--silent", "--reporters", "json", "--output", outDir, ...changedFiles], {
cwd: projectRoot,
reject: false
});
return jscpdLocationKeys(readReport3(join99(outDir, "jscpd-report.json")));
} catch {
return /* @__PURE__ */ new Set();
}
}
function readReport3(path10) {
try {
return parseJscpdJson(readFileSync46(path10, "utf8"));
} catch {
return [];
}
}
// src/duplication/detect.ts
var SIZE_RATIO_GUARD = 3;
async function detectNewCodeDuplication(options) {
const config = options.config ?? resolveDuplicationConfig(options.projectRoot);
if (config.mode === "off" || options.changedFiles.length === 0) {
return [];
}
const minLines = config.minLines;
const addedByFile = new Map(
(await collectAddedRanges(options)).map((entry) => [entry.file, entry.ranges])
);
if (![...addedByFile.values()].some((ranges) => ranges.length > 0)) {
return [];
}
const corpus = await loadCorpus(options);
const indexedCorpus = indexCorpus(corpus, minLines);
if (indexedCorpus.length === 0) {
return [];
}
const knowledge = readCodeKnowledgeIndex(options.projectRoot);
const jscpdKeys = options.corroborate === false ? /* @__PURE__ */ new Set() : await corroborateWithJscpd(options);
const findings = [];
for (const [file, ranges] of addedByFile) {
if (ranges.length === 0) {
continue;
}
const fileText = await readFileText(options.projectRoot, file);
if (fileText === null) {
continue;
}
for (const candidate of new AstChunker().chunk(file, fileText)) {
const finding = await scoreCandidate({
projectRoot: options.projectRoot,
file,
fileText,
candidateContent: candidate.content,
ranges,
minLines,
threshold: config.similarityThreshold,
indexedCorpus,
knowledge,
jscpdKeys
});
if (finding) {
findings.push(finding);
}
}
}
return dedupeFindings(findings);
}
function indexCorpus(corpus, minLines) {
const indexed = [];
for (const chunk of corpus) {
if (meaningfulLineCount(chunk.content) < minLines) {
continue;
}
indexed.push({ chunk, shingleSet: shingles(tokenizeCode(chunk.content)) });
}
return indexed;
}
async function scoreCandidate(input) {
const range = resolveChunkLineRange(input.fileText, input.candidateContent);
if (!range) {
return null;
}
if (!rangesOverlap(range.start, range.end, input.ranges)) {
return null;
}
if (meaningfulLineCount(input.candidateContent) < input.minLines) {
return null;
}
const candidateShingles = shingles(tokenizeCode(input.candidateContent));
const candidateChars = nonWhitespaceLength(input.candidateContent);
const best = bestMatch(candidateShingles, candidateChars, input.indexedCorpus);
if (!best || best.score < HEURISTIC_BAND_FLOOR) {
return null;
}
const matchedFileText = await readFileText(input.projectRoot, best.chunk.file);
const matchedRange = matchedFileText && resolveChunkLineRange(matchedFileText, best.chunk.content) || range;
const { symbol, callers } = enrichMatch(input.knowledge, best.chunk, matchedRange);
const kind = best.score >= input.threshold ? "deterministic" : "heuristic";
return {
file: input.file,
line_range: range,
matched_file: best.chunk.file,
...symbol ? { matched_symbol: symbol } : {},
matched_line_range: matchedRange,
similarity: best.score,
matched_callers: callers,
corroborated: isCorroborated(input.file, range.start, range.end, input.jscpdKeys),
kind,
message: duplicationMessage({
file: input.file,
lineRange: range,
matchedFile: best.chunk.file,
matchedSymbol: symbol,
matchedLineRange: matchedRange,
similarity: best.score,
matchedCallers: callers
})
};
}
function bestMatch(candidateShingles, candidateChars, indexedCorpus) {
let best = null;
for (const entry of indexedCorpus) {
if (!withinSizeRatio(candidateChars, entry.chunk.charCount)) {
continue;
}
const score = jaccard(candidateShingles, entry.shingleSet);
if (!best || score > best.score) {
best = { chunk: entry.chunk, score };
}
}
return best;
}
function withinSizeRatio(a, b) {
if (a === 0 || b === 0) {
return a === b;
}
const ratio = a > b ? a / b : b / a;
return ratio <= SIZE_RATIO_GUARD;
}
function enrichMatch(knowledge, chunk, matchedRange) {
if (!knowledge) {
return { symbol: chunk.exportedSymbols[0], callers: 0 };
}
const inFile = knowledge.symbols.filter((symbol) => symbol.file === chunk.file);
const inRange = inFile.filter(
(symbol) => symbol.line >= matchedRange.start && symbol.line <= matchedRange.end
);
const pool = inRange.length > 0 ? inRange : inFile.filter((s) => chunk.exportedSymbols.includes(s.name));
if (pool.length === 0) {
return { symbol: chunk.exportedSymbols[0], callers: 0 };
}
const top = pool.reduce((a, b) => b.caller_count > a.caller_count ? b : a);
return { symbol: top.name, callers: top.caller_count };
}
function nonWhitespaceLength(content) {
return content.replace(/\s/g, "").length;
}
function dedupeFindings(findings) {
const byKey = /* @__PURE__ */ new Map();
for (const finding of findings) {
const key = `${finding.file}:${finding.line_range.start}:${finding.matched_file}`;
const existing = byKey.get(key);
if (!existing || finding.similarity > existing.similarity) {
byKey.set(key, finding);
}
}
return [...byKey.values()].sort(
(a, b) => a.file.localeCompare(b.file) || a.line_range.start - b.line_range.start
);
}
// src/duplication/scan.ts
async function runDuplicationScan(options) {
const config = options.config ?? resolveDuplicationConfig(options.projectRoot);
const clock = options.clock ?? {
nowIso: () => (/* @__PURE__ */ new Date()).toISOString(),
nowMs: () => Date.now()
};
const changedFiles = options.changedFiles ?? (await loadChangeEvidence(options.projectRoot)).files;
const startedMs = clock.nowMs();
const rawFindings = await detectNewCodeDuplication({
projectRoot: options.projectRoot,
changedFiles,
config,
corroborate: options.corroborate
});
const resolved = applyResolvedDecisions(
options.projectRoot,
rawFindings
);
const findings = resolved.length === 0 ? rawFindings : downgrade(rawFindings, resolved);
const elapsedMs = Math.max(0, clock.nowMs() - startedMs);
const report = buildDuplicationReport({
findings,
config,
elapsedMs,
now: clock.nowIso(),
resolvedDecisions: resolved.map((entry) => entry.decisionId)
});
writeDuplicationReport(options.projectRoot, report);
appendDuplicationRun(
options.projectRoot,
resolveSessionId(options.projectRoot, options.sessionId ?? null),
report
);
armStrongestBlockingFinding(options, findings);
return report;
}
function armStrongestBlockingFinding(options, findings) {
const blocking = findings.filter((finding) => finding.kind === "deterministic");
if (blocking.length === 0) {
return;
}
const strongest = blocking.reduce(
(best, finding) => finding.similarity > best.similarity ? finding : best
);
try {
const sessionId = resolveSessionId(options.projectRoot, options.sessionId ?? null);
const changeKey = currentFeature(options.projectRoot, sessionId);
if (!changeKey) {
return;
}
armDecisionFromDuplicationFinding({
projectRoot: options.projectRoot,
changeKey,
sessionId,
finding: strongest
});
} catch {
}
}
function downgrade(findings, resolved) {
const covered = new Set(resolved.flatMap((entry) => entry.coveredFindingKeys));
return findings.map((finding) => {
const key = `${finding.file}:${finding.line_range.start}:${finding.matched_file}`;
if (finding.kind === "deterministic" && covered.has(key)) {
return { ...finding, kind: "heuristic" };
}
return finding;
});
}
// src/change-metrics/index.ts
init_esm_shims();
// src/change-metrics/compute.ts
init_esm_shims();
// src/change-metrics/meaningful-lines.ts
init_esm_shims();
import { readFile as readFile46 } from "fs/promises";
import { join as join100 } from "path";
var COMMENT_PREFIXES = ["//", "/*", "*/", "*", "<!--", "-->", "#", "--"];
function isMeaningfulLine(line) {
const trimmed = line.trim();
if (trimmed.length === 0) {
return false;
}
return !COMMENT_PREFIXES.some((prefix) => trimmed.startsWith(prefix));
}
async function countMeaningfulChangedLines(options) {
const { projectRoot, changedFiles } = options;
const added = await collectAddedRanges({ projectRoot, changedFiles });
let total = 0;
for (const entry of added) {
if (entry.ranges.length === 0) {
continue;
}
let content;
try {
content = await readFile46(join100(projectRoot, entry.file), "utf8");
} catch {
continue;
}
const lines = content.split("\n");
for (let i = 0; i < lines.length; i++) {
if (lineInRanges(i + 1, entry.ranges) && isMeaningfulLine(lines[i])) {
total += 1;
}
}
}
return total;
}
// src/change-metrics/compute.ts
function normalizePath7(path10) {
return path10.replace(/\\/g, "/").replace(/^\.\//, "");
}
function round1(value) {
return Math.round(value * 10) / 10;
}
function flaggedNewCodeLines(findings) {
const byFile = /* @__PURE__ */ new Map();
for (const finding of findings) {
const file = normalizePath7(finding.file);
let lines = byFile.get(file);
if (!lines) {
lines = /* @__PURE__ */ new Set();
byFile.set(file, lines);
}
for (let line = finding.line_range.start; line <= finding.line_range.end; line++) {
lines.add(line);
}
}
let total = 0;
for (const lines of byFile.values()) {
total += lines.size;
}
return total;
}
function crossFileReuseCalls(index, changedFiles) {
const changed = new Set(changedFiles.map(normalizePath7));
let calls = 0;
for (const edge of index.reference_edges) {
if (changed.has(normalizePath7(edge.from)) && !changed.has(normalizePath7(edge.to))) {
calls += 1;
}
}
return calls;
}
async function computeChangeMetrics(options) {
const meaningful = await countMeaningfulChangedLines(options);
const report = readDuplicationReport(options.projectRoot);
const flaggedLines = report ? flaggedNewCodeLines(report.findings) : 0;
const index = readCodeKnowledgeIndex(options.projectRoot);
const reuseCalls = index ? crossFileReuseCalls(index, options.changedFiles) : 0;
const dupNewPct = report && meaningful > 0 ? Math.min(100, Math.max(0, round1(flaggedLines / meaningful * 100))) : null;
const reuseRate = index && meaningful > 0 ? round1(reuseCalls / meaningful * 100) : null;
return {
dup_new_pct: dupNewPct,
reuse_rate: reuseRate,
meaningful_changed_lines: meaningful,
inputs: {
flagged_lines: flaggedLines,
reuse_calls: reuseCalls,
duplication_report_present: report !== null,
index_present: index !== null
}
};
}
// src/change-metrics/receipt-line.ts
init_esm_shims();
function formatDup(dupNewPct) {
return dupNewPct === null ? "n/a" : `${dupNewPct}%`;
}
function formatReuse(reuseRate) {
return reuseRate === null ? "n/a" : reuseRate.toFixed(1);
}
function formatChangeShapeLine(metrics) {
return `> - \u{1F4CF} change shape: ${formatDup(metrics.dup_new_pct)} duplicated new code \xB7 ${formatReuse(metrics.reuse_rate)} reuse calls /100 lines`;
}
// src/change-metrics/ledger.ts
init_esm_shims();
// src/session-ledger/non-feature-skip-audit.ts
init_esm_shims();
var NON_FEATURE_SKIP_DOC_TYPE = "non-feature-verification-skip";
var NON_FEATURE_SKIP_SCHEMA_VERSION = 1;
function recordNonFeatureVerificationSkip(projectRoot, ctx = {}) {
try {
const sessionId = resolveSessionId(projectRoot, ctx.sessionId);
if (currentOrdinal(projectRoot, NON_FEATURE_SKIP_DOC_TYPE, sessionId) > 0) {
return null;
}
return openSessionDoc(
projectRoot,
NON_FEATURE_SKIP_DOC_TYPE,
sessionId,
{
reason: ctx.reason ?? "non-feature-route",
workflow: ctx.workflow ?? "unknown",
origin: ctx.origin ?? "unknown",
adapter: ctx.adapter ?? "unknown"
},
{ schemaVersion: NON_FEATURE_SKIP_SCHEMA_VERSION, now: ctx.now }
);
} catch {
return null;
}
}
// src/verification/repository/evidence-existence-gate.ts
init_esm_shims();
var GATE_NAME = "evidence-existence";
function evidenceExistenceGate(input) {
if (input.mode === "off") {
return null;
}
const { projectRoot, sessionId, dirName } = input;
if (!input.isFeatureDev || !dirName) {
return skipped2(
"No active feature bundle for this change \u2014 evidence-existence check not applicable."
);
}
const present = [];
const backfilled = [];
const absent = [];
const flagSkipped = [];
let ragMissing = false;
try {
if (!input.ruleComplianceOn) {
flagSkipped.push("rule-run.jsonl");
} else if (readRuleRun(projectRoot, dirName).length > 0) {
present.push("rule-run.jsonl");
} else {
let minted = false;
const report = readReport(projectRoot);
if (report) {
appendRuleRun(projectRoot, sessionId, {
kind: "findings",
counts: report.counts,
blocking: report.blocking,
findings: ruleRunFindings(report),
backfilled: true
});
minted = true;
}
const drift = readDrift(projectRoot);
if (drift) {
appendRuleRun(projectRoot, sessionId, {
kind: "drift",
counts: drift.counts,
blocking: drift.blocked,
backfilled: true
});
minted = true;
}
(minted ? backfilled : absent).push("rule-run.jsonl");
}
if (!input.duplicationOn) {
flagSkipped.push("duplication.jsonl");
} else if (readDuplication(projectRoot, dirName).length > 0) {
present.push("duplication.jsonl");
} else {
const report = readDuplicationReport(projectRoot);
if (report) {
appendDuplicationRun(projectRoot, sessionId, report, void 0, true);
backfilled.push("duplication.jsonl");
} else {
absent.push("duplication.jsonl");
}
}
if (!input.metricsOn) {
flagSkipped.push("change-metrics.jsonl");
} else if (readChangeMetrics(projectRoot, dirName).length > 0) {
present.push("change-metrics.jsonl");
} else if (input.changeMetrics) {
appendChangeMetrics(projectRoot, sessionId, input.changeMetrics, void 0, true);
backfilled.push("change-metrics.jsonl");
} else {
absent.push("change-metrics.jsonl");
}
if (!input.ragEnabled) {
flagSkipped.push("rag.jsonl");
} else if (readUnitFile(projectRoot, featureFilePath(dirName, "rag")).length > 0 || readUnitFile(projectRoot, chatRagPath(sessionId)).length > 0) {
present.push("rag.jsonl");
} else {
ragMissing = true;
}
} catch {
}
return decide({ present, backfilled, absent, flagSkipped, ragMissing });
}
function decide(state) {
const madeGood = [...state.present, ...state.backfilled];
const backfillNote = state.backfilled.length > 0 ? ` Backfilled from cache: ${state.backfilled.join(", ")}.` : "";
const skipNote = state.flagSkipped.length > 0 ? ` Skipped (flag off): ${state.flagSkipped.join(", ")}.` : "";
const absentNote = state.absent.length > 0 ? ` Absent, no cache to backfill: ${state.absent.join(", ")}.` : "";
if (state.ragMissing) {
return {
name: GATE_NAME,
status: "inconclusive",
detail: `Inconclusive \u2014 rag.jsonl is absent for this feature (no bundle or _chat retrieval row recorded); RAG evidence is unrecoverable.${backfillNote}${absentNote}`,
remediation: null,
failures: []
};
}
if (madeGood.length === 0) {
return skipped2(`No evidence files present for this change.${skipNote}${absentNote}`);
}
return {
name: GATE_NAME,
status: "pass",
detail: `Evidence files present for this feature: ${madeGood.join(", ")}.${backfillNote}${skipNote}${absentNote}`,
remediation: null,
failures: []
};
}
function skipped2(detail) {
return {
name: GATE_NAME,
status: "skipped",
detail,
remediation: null,
failures: [],
skip_kind: "not-required"
};
}
// src/verification/repository/evidence-existence-mode.ts
init_esm_shims();
var EVIDENCE_EXISTENCE_MODES = ["off", "warn"];
var DEFAULT_EVIDENCE_EXISTENCE_MODE = "warn";
function resolveEvidenceExistenceMode(projectRoot, env2 = process.env) {
return resolveFlooredMode(
{
team: readConfigsDir(projectRoot).merged.get("evidence_existence_gate"),
local: readDotConfig(projectRoot).get("evidence_existence_gate"),
env: envConfigValue(env2, "evidence_existence_gate")
},
EVIDENCE_EXISTENCE_MODES,
DEFAULT_EVIDENCE_EXISTENCE_MODE
);
}
// src/verification/repository/bundle-completeness-gate.ts
init_esm_shims();
// src/authoring/completion.ts
init_esm_shims();
import { existsSync as existsSync55 } from "fs";
import { join as join106 } from "path";
// src/authoring/lint/agent-lint.ts
init_esm_shims();
import { existsSync as existsSync54, readdirSync as readdirSync17, statSync as statSync8 } from "fs";
import { basename as basename10, isAbsolute as isAbsolute6, join as join105, relative as relative19, resolve as resolve4 } from "path";
// src/authoring/decisions.ts
init_esm_shims();
function raiseAuthoringDecision(projectRoot, input) {
return createPendingDecision(projectRoot, {
category: input.category,
title: input.title,
context: input.context,
options: input.options,
recommendation: input.recommendation,
change: input.change ?? null
}).id;
}
function readAuthoringDecision(projectRoot, id) {
const stored = readContractDecisions(projectRoot).filter((row2) => row2.packet.id === id);
const row = stored.find((entry) => entry.status === "resolved") ?? stored[0];
if (!row) return null;
const packet = row.packet;
const response = packet.human_response;
const text2 = (value) => typeof value === "string" ? value : null;
return {
id,
category: row.packet.category,
status: row.status,
chosen: row.status === "resolved" ? text2(packet.chosen) : null,
resolvedBy: text2(response?.responded_by) ?? text2(packet.resolved_by),
rationale: text2(packet.rationale),
resolvedAt: text2(packet.resolved_at)
};
}
function option(key, label, preview, tradeOff) {
return { option_key: key, label, one_line_preview: preview, trade_off: tradeOff };
}
var OVERRIDE_ADD_UNVERIFIED = "add-unverified";
var OVERRIDE_DO_NOT_ADD = "do-not-add";
function raiseOverrideDecision(projectRoot, input) {
const kind = input.kind ?? "skill";
return raiseAuthoringDecision(projectRoot, {
category: "authoring.override",
title: `The ${kind} ${input.skill} cannot run its ${input.gate} check. Add it unverified, kept in this project?`,
context: input.why,
options: [
option(
OVERRIDE_ADD_UNVERIFIED,
"Add it unverified, kept in this project",
`If you pick this, ${input.skill} is added with the label unverified and cannot leave this project.`,
`You give up: proof that ${input.skill} helps.`
),
option(
OVERRIDE_DO_NOT_ADD,
"Do not add it",
`If you pick this, ${input.skill} is not added.`,
`You give up: the ${kind}.`
)
],
recommendation: OVERRIDE_DO_NOT_ADD,
change: input.change
});
}
var AGENT_PERMISSION_ALLOW = "allow";
var AGENT_PERMISSION_REMOVE = "remove";
function agentPermissionContext(powers, fileHash) {
return `Powers: ${[...powers].sort().join(", ")}. File hash: ${fileHash}.`;
}
function raiseAgentPermissionDecision(projectRoot, input) {
const powers = [...new Set(input.powers)].sort();
const list = powers.join(", ");
return raiseAuthoringDecision(projectRoot, {
category: "authoring.agent_permission",
title: `The agent ${input.agent} asks for these powers: ${list}. Allow these powers?`,
context: agentPermissionContext(powers, input.fileHash),
options: [
option(
AGENT_PERMISSION_ALLOW,
"Allow these powers",
`If you pick this, ${input.agent} keeps ${list}; adding a power or editing the agent asks again.`,
"You give up: an agent limited to the minimum tools."
),
option(
AGENT_PERMISSION_REMOVE,
"Remove them",
`If you pick this, ${list} is taken out of ${input.agent} before its checks run.`,
"You give up: whatever those powers let the agent do."
)
],
recommendation: AGENT_PERMISSION_REMOVE,
change: input.change
});
}
// src/authoring/overlap.ts
init_esm_shims();
import { existsSync as existsSync51, readdirSync as readdirSync15, statSync as statSync7 } from "fs";
import { homedir as homedir4 } from "os";
import { join as join101 } from "path";
// src/authoring/thresholds.ts
init_esm_shims();
var THRESHOLD_TOLERANCE = 1e-9;
function meetsThreshold(value, threshold) {
return value + THRESHOLD_TOLERANCE >= threshold;
}
function withinLimit(value, limit) {
return value - THRESHOLD_TOLERANCE <= limit;
}
// src/authoring/overlap.ts
var SCOPE_PRECEDENCE = ["user", "project"];
var AGENT_SCOPE_PRECEDENCE = [
"managed",
"cli",
"project",
"user",
"plugin"
];
var STOP_WORDS = new Set(
"a about above after again against all also am an and any are as at be because been before being below between both but by can could did do does doing down during each few for from further had has have having he her here hers herself him himself his how i if in into is it its itself just me more most my myself no nor not now of off on once only or other our ours ourselves out over own same she should so some such than that the their theirs them themselves then there these they this those through to too under until up very was we were what when where which while who whom why will with would you your yours yourself yourselves use used uses using skill skills".split(" ")
);
function wordSet(text2) {
return new Set(
text2.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((word) => word.length > 0 && !STOP_WORDS.has(word))
);
}
function overlapScore(left, right) {
return jaccard(wordSet(left), wordSet(right));
}
var SUBSET_CONTAINMENT_MIN = 0.8;
function containment(inner, outer) {
const words = wordSet(inner);
if (words.size === 0) return 0;
const outerWords = wordSet(outer);
let shared = 0;
for (const word of words) if (outerWords.has(word)) shared += 1;
return shared / words.size;
}
function findSubsetOverlaps(candidate, installed, minContainment = SUBSET_CONTAINMENT_MIN) {
const overlaps = [];
for (const artifact of installed) {
if (artifact.kind !== "agent" || artifact.name === candidate.name) continue;
if (artifact.tools === void 0) continue;
const theirs = new Set(artifact.tools);
if (!candidate.tools.every((tool) => theirs.has(tool))) continue;
const score = containment(candidate.job, artifact.description);
if (score < minContainment) continue;
overlaps.push({
candidate: candidate.name,
existing: artifact.name,
existing_path: artifact.path,
score,
subset: true
});
}
return overlaps;
}
function lensFocus(lens) {
const section3 = lens.split(/^## What you look for\s*$/mu)[1];
return section3 === void 0 ? lens : section3.split(/^## /mu)[0] ?? "";
}
function profileCollisions(role, owner, threshold) {
const found = [];
const owns = overlapScore(role.owns, owner.owns);
if (meetsThreshold(owns, threshold)) {
found.push({ role: role.role, owner: owner.role, on: "owns", score: owns });
}
if (role.lens !== void 0 && owner.lens !== void 0) {
const lens = overlapScore(lensFocus(role.lens), lensFocus(owner.lens));
if (meetsThreshold(lens, threshold)) {
found.push({ role: role.role, owner: owner.role, on: "lens", score: lens });
}
}
return found;
}
function expertCollisions(roster, threshold, candidate) {
if (candidate !== void 0) {
return roster.filter((owner) => owner.role !== candidate.role).flatMap((owner) => profileCollisions(candidate, owner, threshold));
}
const found = [];
roster.forEach((owner, index) => {
for (const role of roster.slice(index + 1)) {
found.push(...profileCollisions(role, owner, threshold));
}
});
return found;
}
function expertCollisionLine(collision) {
const what = collision.on === "owns" ? "Owns phrase" : "lens";
return `The expert ${collision.role} collides with ${collision.owner} on its ${what} (score ${collision.score.toFixed(2)}): ${collision.owner} already owns that question. Give ${collision.role} a question no other role answers, or extend ${collision.owner}.`;
}
function candidateText(purpose, triggers) {
return [purpose, ...triggers].join(" ");
}
function findCollisions(candidate, installed, threshold) {
const scores = [];
const collisions = [];
for (const artifact of installed) {
if (artifact.kind !== candidate.kind || artifact.name === candidate.name) continue;
const score = overlapScore(candidate.text, artifact.description);
scores.push({ existing: artifact.name, score });
if (meetsThreshold(score, threshold)) {
collisions.push({
candidate: candidate.name,
existing: artifact.name,
existing_path: artifact.path,
score
});
}
}
return { scores, collisions };
}
function outranks(left, right, precedence) {
return precedence.indexOf(left) < precedence.indexOf(right);
}
function findNameShadowing(candidate, installed, precedence = candidate.kind === "agent" ? AGENT_SCOPE_PRECEDENCE : SCOPE_PRECEDENCE) {
const shadowing = [];
for (const artifact of installed) {
if (artifact.kind !== candidate.kind || artifact.name !== candidate.name || artifact.scope === candidate.scope) {
continue;
}
const existing = { scope: artifact.scope, path: artifact.path };
const fresh = { scope: candidate.scope, path: null };
const existingWins = outranks(artifact.scope, candidate.scope, precedence);
shadowing.push({
name: candidate.name,
shadowing: existingWins ? existing : fresh,
shadowed: existingWins ? fresh : existing
});
}
return shadowing;
}
function sideText(side) {
return side.path === null ? `the new ${side.scope} one` : `${side.path} (${side.scope})`;
}
function shadowingLine(entry) {
const shadowing = sideText(entry.shadowing);
const shadowed = sideText(entry.shadowed);
return `The name ${entry.name} is taken in another scope: ${shadowing} would shadow ${shadowed}. Pick another name.`;
}
function catalogBudget(input) {
const listed = input.installed.filter((artifact) => artifact.name !== input.candidate?.name);
const sizes = new Map(
listed.map((artifact) => [artifact.name, descriptionLength(artifact.description)])
);
const candidateChars = input.candidate === void 0 ? 0 : descriptionLength(input.candidate.description);
const total = [...sizes.values()].reduce((sum, size) => sum + size, candidateChars);
const fired = input.lastFired ?? /* @__PURE__ */ new Map();
const ordered = [...sizes.keys()].sort((left, right) => {
const leftAt = fired.get(left) ?? "";
const rightAt = fired.get(right) ?? "";
if (leftAt !== rightAt) return leftAt < rightAt ? -1 : 1;
return left < right ? -1 : left > right ? 1 : 0;
});
const atRisk = [];
let remaining = total;
for (const name of ordered) {
if (remaining <= input.budgetChars) break;
atRisk.push(name);
remaining -= sizes.get(name) ?? 0;
}
return {
total_chars: total,
budget_chars: input.budgetChars,
over_budget: total > input.budgetChars,
at_risk: atRisk,
activation_data: fired.size > 0
};
}
function budgetWarningLine(budget) {
if (!budget.over_budget) return null;
return `The skill descriptions add up to ${budget.total_chars} characters, over the budget of ${budget.budget_chars}. The host may drop these from its list: ${budget.at_risk.join(", ")}.`;
}
function expandRoot(base, root) {
const parts = root.split("/");
let current = [""];
for (const part of parts) {
const next = [];
for (const prefix of current) {
if (part !== "*") {
next.push(prefix === "" ? part : `${prefix}/${part}`);
continue;
}
const dir = join101(base, prefix);
if (!existsSync51(dir)) continue;
for (const entry of readdirSync15(dir).sort()) {
if (statSync7(join101(dir, entry)).isDirectory()) next.push(`${prefix}/${entry}`);
}
}
current = next;
}
return current;
}
function readSkillAt(base, rel, scope) {
const text2 = readTextIfPresent(join101(base, rel, SKILL_FILE));
if (text2 === null) return null;
const folder = rel.split("/").at(-1);
const split = splitSkillFrontmatter(text2);
const data = split.ok ? split.data : {};
return {
kind: "skill",
name: typeof data.name === "string" && data.name.trim() !== "" ? data.name.trim() : folder,
description: typeof data.description === "string" ? data.description : "",
path: `${rel}/${SKILL_FILE}`,
scope
};
}
function scanScope(base, roots, scope) {
const found = [];
for (const root of roots) {
for (const expanded of expandRoot(base, root)) {
const dir = join101(base, expanded);
if (!existsSync51(dir) || !statSync7(dir).isDirectory()) continue;
for (const entry of readdirSync15(dir).sort()) {
const skill = readSkillAt(base, `${expanded}/${entry}`, scope);
if (skill !== null) found.push(skill);
}
}
}
return found;
}
function discoverInstalledSkills(projectRoot, context, options = {}) {
const project = scanScope(projectRoot, skillRoots(context.adapters, context), "project");
const home = options.userHome === void 0 ? homedir4() : options.userHome;
if (home === null) return project;
const user = scanScope(home, skillRoots(context.adapters), "user").map((skill) => ({
...skill,
path: `~/${skill.path}`
}));
return [...project, ...user];
}
function toolList(value) {
if (Array.isArray(value)) return value.filter((tool) => typeof tool === "string");
if (typeof value !== "string") return void 0;
return value.split(",").map((tool) => tool.trim()).filter((tool) => tool !== "");
}
function readAgentAt(base, rel, scope) {
const text2 = readTextIfPresent(join101(base, rel));
if (text2 === null) return null;
const stem = rel.split("/").at(-1).replace(/\.[^.]+$/u, "");
if (rel.endsWith(".toml")) {
const name = /^name\s*=\s*"([^"]*)"/mu.exec(text2)?.[1];
const description = /^description\s*=\s*"((?:[^"\\]|\\.)*)"/mu.exec(text2)?.[1];
return {
kind: "agent",
name: name && name.trim() !== "" ? name.trim() : stem,
description: description === void 0 ? "" : JSON.parse(`"${description}"`),
path: rel,
scope
};
}
const split = splitSkillFrontmatter(text2);
const data = split.ok ? split.data : {};
const tools = toolList(data.tools);
return {
kind: "agent",
name: typeof data.name === "string" && data.name.trim() !== "" ? data.name.trim() : stem,
description: typeof data.description === "string" ? data.description : "",
path: rel,
scope,
...tools === void 0 ? {} : { tools }
};
}
function scanAgentScope(base, context, scope) {
const found = [];
const options = { paqadRepo: scope === "project" && context.paqadRepo };
for (const root of agentRoots(context.adapters, options)) {
for (const expanded of expandRoot(base, root)) {
const dir = join101(base, expanded);
if (!existsSync51(dir) || !statSync7(dir).isDirectory()) continue;
for (const entry of readdirSync15(dir).sort()) {
const rel = `${expanded}/${entry}`;
if (agentNameOf(rel, context.adapters, options) === null) continue;
if (!statSync7(join101(dir, entry)).isFile()) continue;
const agent = readAgentAt(base, rel, scope);
if (agent !== null) found.push(agent);
}
}
}
return found;
}
function discoverInstalledAgents(projectRoot, context, options = {}) {
const project = scanAgentScope(projectRoot, context, "project");
const home = options.userHome === void 0 ? homedir4() : options.userHome;
if (home === null) return project;
const user = scanAgentScope(home, { ...context, paqadRepo: false }, "user").map((agent) => ({
...agent,
path: `~/${agent.path}`
}));
return [...project, ...user];
}
function buildOverlapReport(input) {
const sameKind = input.installed.filter((artifact) => artifact.kind === input.candidate.kind);
const { scores, collisions } = findCollisions(input.candidate, sameKind, input.threshold);
return {
kind: input.candidate.kind,
candidate: input.candidate.name,
threshold: input.threshold,
scores,
collisions,
shadowing: findNameShadowing(input.candidate, sameKind),
budget: catalogBudget({
installed: sameKind,
candidate: input.candidateDescription === void 0 ? void 0 : { name: input.candidate.name, description: input.candidateDescription },
budgetChars: input.budgetChars,
lastFired: input.lastFired
})
};
}
function formatScore(score) {
return score.toFixed(2);
}
function renderOverlapReport(report) {
const lines = [`# Overlap check: ${report.candidate}`, ""];
lines.push(`Collision threshold: ${formatScore(report.threshold)} (Jaccard of word sets).`, "");
lines.push("## Collisions", "");
if (report.collisions.length === 0) {
lines.push(`None: no installed ${report.kind} scores at or above the threshold.`);
} else {
for (const collision of report.collisions) {
lines.push(
collision.subset === true ? `- ${collision.candidate} is a subset of ${collision.existing} (${collision.existing_path}): its tools are all in ${collision.existing} and its job is contained at ${formatScore(collision.score)}. Extending ${collision.existing} is recommended.` : `- ${collision.candidate} collides with ${collision.existing} (${collision.existing_path}), score ${formatScore(collision.score)}. Extending ${collision.existing} is recommended.`
);
}
}
lines.push("", "## Name shadowing", "");
if (report.shadowing.length === 0) {
lines.push("None.");
} else {
for (const entry of report.shadowing) lines.push(`- ${shadowingLine(entry)}`);
}
if (report.kind === "skill") {
lines.push("", "## Catalog budget", "");
const warning2 = budgetWarningLine(report.budget);
lines.push(
warning2 ?? `Within budget: ${report.budget.total_chars} of ${report.budget.budget_chars} characters.`
);
if (!report.budget.activation_data) {
lines.push("", "No activation data yet, so skills at risk are ordered by name.");
}
}
lines.push("", "## Scores", "");
if (report.scores.length === 0) {
lines.push(`No other installed ${report.kind}.`);
} else {
lines.push("| Installed | Score |", "| --- | --- |");
for (const entry of report.scores)
lines.push(`| ${entry.existing} | ${formatScore(entry.score)} |`);
}
lines.push("");
return lines.join("\n");
}
// src/authoring/tests/locations.ts
init_esm_shims();
function studlySkillName(name) {
return name.split("-").filter((part) => part.length > 0).map((part) => part[0].toUpperCase() + part.slice(1)).join("");
}
function skillTestDirectories(name, options = {}) {
const dirs = [`tests/skills/${name}`, `tests/Feature/Skills/${studlySkillName(name)}`];
return options.paqadRepo === true ? [`tests/unit/skills/${name}`, ...dirs] : dirs;
}
function agentTestDirectories(name) {
return [`tests/agents/${name}`, `tests/Feature/Agents/${studlySkillName(name)}`];
}
// src/authoring/workspace.ts
init_esm_shims();
var import_yaml13 = __toESM(require_dist(), 1);
import { existsSync as existsSync53, mkdirSync as mkdirSync23, readFileSync as readFileSync48, renameSync as renameSync7, rmSync as rmSync14, writeFileSync as writeFileSync24 } from "fs";
import { dirname as dirname42, join as join104 } from "path";
// src/authoring/lint/skill-lint.ts
init_esm_shims();
var import_yaml12 = __toESM(require_dist(), 1);
import { existsSync as existsSync52, lstatSync as lstatSync2, readdirSync as readdirSync16, readlinkSync as readlinkSync3, realpathSync } from "fs";
import { basename as basename9, join as join103, relative as relative18, sep as sep3 } from "path";
// src/authoring/lint/runner.ts
init_esm_shims();
var FindingSink = class {
findings = [];
add(rule, severity, file, line, message) {
this.findings.push({ rule, severity, file, line, message });
}
block(rule, file, line, message) {
this.add(rule, "block", file, line, message);
}
warn(rule, file, line, message) {
this.add(rule, "warn", file, line, message);
}
};
var EM_DASH = "\u2014";
var SHOUTED = /\b(ALWAYS|NEVER|MUST|CRITICAL)\b/;
var ISO_DATE = /\b\d{4}-\d{2}-\d{2}\b/;
var CLOCK_TIME = /\b\d{1,2}:\d{2}:\d{2}\b/;
var DYNAMIC_PLACEHOLDER = /\{\{\s*(?:now|date|time|timestamp|today|counter|random|uuid)\s*\}\}/i;
var COUNTER = /\b(?:run|iteration|attempt|build|request)\s*(?:#|no\.?\s*)\d+\b/i;
function compareText(left, right) {
return left < right ? -1 : left > right ? 1 : 0;
}
function sortFindings(findings) {
return findings.sort(
(left, right) => compareText(left.file, right.file) || left.line - right.line || compareText(left.rule, right.rule) || compareText(left.message, right.message)
);
}
function countFindings(findings) {
const blocking = findings.filter((finding) => finding.severity === "block").length;
return { blocking, warnings: findings.length - blocking };
}
function lintExitCode(result2) {
return result2.blocking > 0 ? 1 : 0;
}
function formatLintJson(result2) {
return `${JSON.stringify(result2, null, 2)}
`;
}
function checkEmDash(sink, rule, file) {
file.lines.forEach((text2, index) => {
if (text2.includes(EM_DASH)) {
sink.block(
rule,
file.rel,
index + 1,
"An em dash (U+2014). Use a comma, a colon or two sentences."
);
}
});
}
function checkNeverWrite(sink, rule, file, neverWrite) {
file.lines.forEach((text2, index) => {
neverWrite.lastIndex = 0;
for (const match of text2.matchAll(neverWrite)) {
const phrase = match[0].toLowerCase().replace(/\s+/g, " ");
sink.block(rule, file.rel, index + 1, `Generic phrase "${phrase}". Say what it means here.`);
}
});
}
function checkShouted(sink, rule, file) {
file.lines.forEach((text2, index) => {
const shouted = SHOUTED.exec(text2);
if (shouted) {
sink.block(
rule,
file.rel,
index + 1,
`"${shouted[1]}" in capitals. Say why instead of shouting.`
);
}
});
}
function checkDynamic(sink, rule, file, options) {
const patterns = [
ISO_DATE,
CLOCK_TIME,
DYNAMIC_PLACEHOLDER,
COUNTER,
...options.extraPatterns ?? []
];
file.lines.forEach((text2, index) => {
const line = index + 1;
if (line < options.firstLine || options.exempt?.test(text2) === true) return;
if (patterns.some((pattern) => pattern.test(text2))) {
sink.block(rule, file.rel, line, options.message);
}
});
}
function checkSecrets(sink, rule, files) {
for (const match of builtinSecretScan([...files])) {
sink.findings.push({
rule,
severity: "block",
file: match.file,
line: match.line,
message: `A secret (${match.rule}) is in this file, fingerprint ${match.fingerprint}. Remove it; a secret can never be approved.`,
fingerprint: match.fingerprint
});
}
}
// src/authoring/lint/never-write.ts
init_esm_shims();
var import_yaml11 = __toESM(require_dist(), 1);
import { readFileSync as readFileSync47 } from "fs";
import { join as join102 } from "path";
var NEVER_WRITE_SCHEMA_VERSION = "1";
var PROJECT_NEVER_WRITE_PATH = "docs/instructions/rules/authoring/never-write.yaml";
function frameworkNeverWritePath() {
return join102(getRuntimeRoot(), "base", "authoring", "never-write.yaml");
}
var NeverWriteListError = class extends Error {
};
function parseList(text2, source) {
let parsed;
try {
parsed = import_yaml11.default.parse(text2);
} catch (error) {
throw new NeverWriteListError(`${source} is not valid YAML: ${error.message}`);
}
const record2 = parsed ?? {};
if (String(record2.schema_version) !== NEVER_WRITE_SCHEMA_VERSION) {
throw new NeverWriteListError(
`${source} needs schema_version "${NEVER_WRITE_SCHEMA_VERSION}" (found ${String(record2.schema_version)})`
);
}
const phrases = record2.phrases ?? [];
if (!Array.isArray(phrases) || phrases.some((phrase) => typeof phrase !== "string")) {
throw new NeverWriteListError(`${source} needs "phrases" to be a list of strings`);
}
return phrases.map((phrase) => phrase.trim()).filter((phrase) => phrase.length > 0);
}
function readProjectText(projectRoot) {
try {
return readFileSync47(join102(projectRoot, PROJECT_NEVER_WRITE_PATH), "utf8");
} catch (error) {
if (error.code === "ENOENT") return null;
throw new NeverWriteListError(
`could not read ${PROJECT_NEVER_WRITE_PATH}: ${error.message}`
);
}
}
function loadNeverWriteList(projectRoot) {
const frameworkPath = frameworkNeverWritePath();
const framework = parseList(readFileSync47(frameworkPath, "utf8"), frameworkPath);
if (framework.length === 0) {
throw new NeverWriteListError(`${frameworkPath} holds no phrases`);
}
const phrases = [...framework];
const seen = new Set(framework.map((phrase) => phrase.toLowerCase()));
const projectText = projectRoot === void 0 ? null : readProjectText(projectRoot);
const added = projectText === null ? [] : parseList(projectText, PROJECT_NEVER_WRITE_PATH);
for (const phrase of added) {
if (seen.has(phrase.toLowerCase())) continue;
seen.add(phrase.toLowerCase());
phrases.push(phrase);
}
return {
schema_version: NEVER_WRITE_SCHEMA_VERSION,
phrases,
framework_phrases: framework.length,
project_phrases: phrases.length - framework.length
};
}
function escapeRegExp2(text2) {
return text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function compileNeverWritePattern(phrases) {
const alternatives = [...phrases].sort((left, right) => right.length - left.length || (left < right ? -1 : 1)).map((phrase) => escapeRegExp2(phrase).replace(/\s+/g, "\\s+"));
return new RegExp(`\\b(?:${alternatives.join("|")})\\b`, "giu");
}
// src/authoring/lint/skill-lint.ts
var SkillLintUsageError = class extends Error {
};
var SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
var SKILL_NAME_MAX = 64;
var BODY_MAX_LINES = 500;
var REFERENCE_TOC_THRESHOLD = 100;
var DEFAULT_BODY_MAX_TOKENS = 5e3;
var BINARY_SNIFF_BYTES2 = 8e3;
var VAGUE_NAME_WORDS = /* @__PURE__ */ new Set([
"helper",
"utils",
"tools",
"documents",
"data",
"files"
]);
var RESERVED_NAME_WORDS = ["claude", "anthropic"];
var WHEN_CLAUSE = /\bwhen\b/i;
var OPTIONS_INTRO = /\b(?:you can|either)\b|\boptions?:/i;
var LIST_ITEM = /^\s*(?:[-*+]|\d+[.)])\s+/;
var DEFAULT_MARKER = /\b(?:default|recommended|prefer)/i;
var TIME_SENSITIVE = /\b(?:currently|recently|as of now|new|latest|before|after) (?:version|release|api)\b/i;
var YEAR = /\b(?:19|20)\d{2}\b/;
var VERIFICATION_LINE = /\b(?:human-verified|verified|last checked|checked on|learned)\b/i;
var TOC_LINE = /^#{1,6}\s*(?:table of )?contents\b|^\s*[-*]\s*\[[^\]]+\]\(#[^)]+\)/i;
var REFERENCE_CITE = /(?:^|[\s(`'"[<])((?:\.\/)?references\/[^\s)`'">\]]+)/g;
var SHELL_READ = /(?:^|[;&|]\s*|\bwhile\s+|\bthen\s+|\bdo\s+)read\s+/;
var INTERACTIVE_CALLS = ["input(", "readline", "prompt(", "STDIN.gets", "fgets(STDIN"];
var PEP723_START = /^#\s*\/\/\/\s*script\s*$/;
var PEP723_END = /^#\s*\/\/\/\s*$/;
var QUOTED = /["']([^"']+)["']/g;
var PINNED_PEP508 = /(?:===?|~=|<=?|>=?|!=|@)/;
var NPM_SPECIFIER = /["']npm:((?:@[^/"']+\/)?[^@"'/]+)(@[^"']+)?["']/g;
function isBinary(buffer) {
return buffer.subarray(0, BINARY_SNIFF_BYTES2).includes(0);
}
function readTree(root, prefix = "") {
const files = [];
const entries = readdirSync16(join103(root, prefix), { withFileTypes: true }).map((entry) => entry.name).sort(compareText);
for (const name of entries) {
const rel = prefix === "" ? name : `${prefix}/${name}`;
const stat4 = lstatSync2(join103(root, rel));
if (stat4.isSymbolicLink()) {
files.push(readSymlink(root, rel));
continue;
}
if (stat4.isDirectory()) {
files.push(...readTree(root, rel));
continue;
}
const buffer = readRegularFile(join103(root, rel), false)?.buffer ?? null;
const text2 = buffer === null || isBinary(buffer) ? null : buffer.toString("utf8");
files.push({ rel, text: text2, lines: text2 === null ? [] : text2.split(/\r?\n/) });
}
return files;
}
function readSymlink(root, rel) {
const target = readlinkSync3(join103(root, rel));
let resolved;
try {
resolved = realpathSync(join103(root, rel));
} catch {
resolved = null;
}
const base = realpathSync(root);
const inside = resolved !== null && resolved.startsWith(`${base}${sep3}`);
const buffer = inside ? readRegularFile(resolved)?.buffer ?? null : null;
if (buffer === null) {
return { rel, text: null, lines: [], symlink: { target, scannable: false } };
}
const text2 = isBinary(buffer) ? null : buffer.toString("utf8");
return {
rel,
text: text2,
lines: text2 === null ? [] : text2.split(/\r?\n/),
symlink: { target, scannable: true }
};
}
function checkYamlFiles(sink, files) {
for (const file of files) {
if (file.text === null || !/\.ya?ml$/iu.test(file.rel)) continue;
const parsed = import_yaml12.default.parseDocument(file.text, { prettyErrors: true });
const error = parsed.errors[0];
if (error === void 0) continue;
sink.block(
"SK-001",
file.rel,
error.linePos?.[0]?.line ?? 1,
`${file.rel} is not valid YAML: ${error.message.split("\n")[0]}`
);
}
}
function isMarkdown(rel) {
return rel.toLowerCase().endsWith(".md");
}
function under(rel, folder) {
return rel.startsWith(`${folder}/`);
}
function keyLine(frontmatterLines, key) {
const index = frontmatterLines.findIndex((line) => line.startsWith(`${key}:`));
return index === -1 ? 1 : index + 2;
}
function checkName(sink, name, folderName, line) {
if (typeof name !== "string" || name.trim() === "") {
sink.block(
"SK-001",
"SKILL.md",
line,
"The name field is missing. Add one that matches the folder."
);
return;
}
if (name.length > SKILL_NAME_MAX) {
sink.block("SK-001", "SKILL.md", line, `The name is longer than ${SKILL_NAME_MAX} characters.`);
}
if (!SKILL_NAME_PATTERN.test(name)) {
sink.block(
"SK-001",
"SKILL.md",
line,
"The name may only use a-z, 0-9 and single hyphens, with no hyphen at either end."
);
}
if (name !== folderName) {
sink.block(
"SK-001",
"SKILL.md",
line,
`The name "${name}" differs from the folder "${folderName}".`
);
}
const reserved = RESERVED_NAME_WORDS.find((word) => name.toLowerCase().includes(word));
if (reserved !== void 0) {
sink.block("SK-002", "SKILL.md", line, `The name contains "${reserved}", which is reserved.`);
}
for (const word of name.split("-")) {
if (VAGUE_NAME_WORDS.has(word)) {
sink.warn(
"SK-003",
"SKILL.md",
line,
`The name uses the vague word "${word}". Name the job the skill does.`
);
}
}
const first = name.split("-")[0] ?? "";
if (!first.endsWith("ing")) {
sink.warn(
"SK-004",
"SKILL.md",
line,
`The name breaks the gerund pattern: its first word "${first}" does not end in "ing".`
);
}
}
function checkDescription(sink, description, line) {
if (typeof description !== "string" || description.trim() === "") {
sink.block("SK-005", "SKILL.md", line, "The description field is missing.");
return;
}
const length = descriptionLength(description);
if (length > DESCRIPTION_MAX_CHARS) {
sink.block(
"SK-005",
"SKILL.md",
line,
`The description is ${length} characters; the limit is ${DESCRIPTION_MAX_CHARS}.`
);
}
if (description.includes("<") || description.includes(">")) {
sink.block("SK-005", "SKILL.md", line, 'The description contains "<" or ">".');
}
if (!WHEN_CLAUSE.test(description)) {
sink.block(
"SK-005",
"SKILL.md",
line,
'The description has no "when" clause. Add "Use when ...".'
);
}
}
function checkFrontmatter(sink, skillFile, folderName, options) {
const split = splitSkillFrontmatter(skillFile.text ?? "");
if (!split.ok) {
sink.block("SK-001", "SKILL.md", 1, `The frontmatter could not be read: ${split.message}.`);
return null;
}
checkName(sink, split.data.name, folderName, keyLine(split.frontmatterLines, "name"));
checkDescription(sink, split.data.description, keyLine(split.frontmatterLines, "description"));
const allowed = allowedSkillFields(options.claudeCode !== false, options.paqadRuntime === true);
for (const key of Object.keys(split.data).sort(compareText)) {
if (!allowed.has(key)) {
sink.block(
"SK-006",
"SKILL.md",
keyLine(split.frontmatterLines, key),
`The frontmatter key "${key}" is not a documented skill field.`
);
}
}
return { body: split.body, bodyStartLine: split.bodyStartLine };
}
function checkBody(sink, body, maxTokens) {
const lines = body.replace(/(?:\r?\n)+$/u, "").split(/\r?\n/);
if (lines.length > BODY_MAX_LINES) {
sink.block(
"SK-008",
"SKILL.md",
1,
`The body is ${lines.length} lines; the limit is ${BODY_MAX_LINES}.`
);
}
const tokens = estimateTokens(body);
if (tokens > maxTokens) {
sink.block(
"SK-008",
"SKILL.md",
1,
`The body is about ${tokens} tokens; the limit is ${maxTokens}.`
);
}
}
function citesIn(file) {
const cites = [];
file.lines.forEach((text2, index) => {
for (const match of text2.matchAll(REFERENCE_CITE)) {
const target = match[1].replace(/^\.\//u, "").replace(/[.,;:!?]+$/u, "");
if (!target.endsWith("/")) cites.push({ target, line: index + 1 });
}
});
return cites;
}
function checkReferences(sink, files, skillFile) {
const references = files.filter((file) => under(file.rel, "references"));
const known = new Set(references.map((file) => file.rel));
const cited = /* @__PURE__ */ new Set();
for (const cite of citesIn(skillFile)) {
cited.add(cite.target);
if (!known.has(cite.target)) {
sink.block("SK-009", "SKILL.md", cite.line, `The cited file ${cite.target} does not exist.`);
}
}
for (const file of references) {
if (!cited.has(file.rel)) {
sink.block("SK-009", file.rel, 1, `${file.rel} is never cited from SKILL.md.`);
}
for (const cite of citesIn(file)) {
if (cite.target === file.rel) continue;
sink.block(
"SK-009",
file.rel,
cite.line,
`${file.rel} points to ${cite.target}; references stay one level deep from SKILL.md.`
);
}
}
}
function testFilesFor(projectRoot, testDirs) {
const found = [];
for (const dir of testDirs) {
const abs = join103(projectRoot, dir);
if (!existsSync52(abs)) continue;
found.push(...readTree(abs).map((file) => `${dir}/${file.rel}`));
}
return found;
}
function scriptStem(rel) {
const name = basename9(rel);
const dot = name.indexOf(".");
return dot <= 0 ? name : name.slice(0, dot);
}
var SCRIPTS_README = "scripts/README.md";
var NOT_ENTRY_HEADING = /^#{2,}\s+not entry points\s*$/iu;
function notEntryPoints(readme) {
const names = /* @__PURE__ */ new Set();
if (readme === null) return names;
let inside = false;
for (const line of readme.split(/\r?\n/u)) {
if (/^#{1,}\s/u.test(line)) {
inside = NOT_ENTRY_HEADING.test(line);
continue;
}
if (!inside) continue;
const item = /^\s*[-*]\s+`?([^`\s:]+)`?/u.exec(line);
if (item) names.add(item[1].replace(/^scripts\//u, ""));
}
return names;
}
var ENTRY_POINT_MARKS = [
/^#!/u,
/__name__\s*==\s*['"]__main__['"]/u,
/require\.main\s*===?\s*module/u,
/import\.meta\.main\b/u,
/import\.meta\.url\s*===?\s*`file:\/\/\$\{process\.argv\[1\]/u
];
function hasRunnableEntryPoint(text2) {
return ENTRY_POINT_MARKS.some((mark) => mark.test(text2));
}
function contractScriptPaths(files) {
const readme = files.find((entry) => entry.rel === SCRIPTS_README)?.text ?? null;
const excluded = notEntryPoints(readme);
return files.filter(
(entry) => under(entry.rel, "scripts") && entry.rel !== SCRIPTS_README && (entry.text === null || !excluded.has(entry.rel.slice("scripts/".length)) || hasRunnableEntryPoint(entry.text))
).map((entry) => entry.rel);
}
function checkScripts(sink, files, testFiles2) {
const readme = files.find((entry) => entry.rel === SCRIPTS_README)?.text ?? null;
const excluded = notEntryPoints(readme);
const candidates = files.filter(
(entry) => under(entry.rel, "scripts") && entry.text !== null && entry.rel !== SCRIPTS_README
);
const scripts = candidates.filter((entry) => {
if (!excluded.has(entry.rel.slice("scripts/".length))) return true;
if (!hasRunnableEntryPoint(entry.text)) return false;
sink.block(
"SK-010",
entry.rel,
1,
`The script ${entry.rel} is listed under Not entry points in ${SCRIPTS_README} but has a runnable entry point.`
);
return true;
});
for (const file of scripts) {
if (!file.text.includes("--help")) {
sink.block("SK-010", file.rel, 1, `The script ${file.rel} has no --help.`);
}
file.lines.forEach((text2, index) => {
const call = INTERACTIVE_CALLS.find((needle) => text2.includes(needle));
if (call !== void 0 || SHELL_READ.test(text2.trim())) {
sink.block(
"SK-010",
file.rel,
index + 1,
`The script ${file.rel} reads input interactively (${call ?? "read"}). Take it from a flag or a file.`
);
}
});
const stem = scriptStem(file.rel).toLowerCase();
if (!testFiles2.some((test) => basename9(test).toLowerCase().includes(stem))) {
sink.block(
"SK-010",
file.rel,
1,
`The script ${file.rel} has no test file under the tests directory.`
);
}
}
}
function checkSecrets2(sink, files) {
checkSecrets(sink, "SK-011", files);
}
function checkProse(sink, file, neverWrite) {
const lines = file.lines;
checkNeverWrite(sink, "SK-012", file, neverWrite);
checkShouted(sink, "SK-013", file);
lines.forEach((text2, index) => {
const line = index + 1;
if (OPTIONS_INTRO.test(text2) && missingDefault(lines, index)) {
sink.block(
"SK-014",
file.rel,
line,
"An options list with no stated default. Name the default."
);
}
for (const sentence of text2.split(/(?<=[.!?])\s+/)) {
if (TIME_SENSITIVE.test(sentence) && !YEAR.test(sentence)) {
sink.block("SK-015", file.rel, line, "Time-sensitive wording with no date. Add the year.");
break;
}
}
});
}
function missingDefault(lines, index) {
let cursor = index + 1;
if (cursor < lines.length && lines[cursor].trim() === "") cursor += 1;
let items = 0;
while (cursor + items < lines.length && LIST_ITEM.test(lines[cursor + items])) items += 1;
if (items < 3) return false;
const window = lines.slice(index, cursor + items + 2).join("\n");
return !DEFAULT_MARKER.test(window);
}
function checkDynamic2(sink, file, firstLine) {
checkDynamic(sink, "SK-017", file, {
firstLine,
exempt: VERIFICATION_LINE,
message: "Dynamic content (a date, a time, a placeholder or a counter). Keep the text the same on every run."
});
}
function checkEmDash2(sink, file) {
checkEmDash(sink, "SK-016", file);
}
function checkTableOfContents(sink, file) {
const length = file.lines.length - (file.lines.at(-1) === "" ? 1 : 0);
if (length <= REFERENCE_TOC_THRESHOLD) return;
if (!file.lines.slice(0, 20).some((line) => TOC_LINE.test(line))) {
sink.block(
"SK-018",
file.rel,
1,
`${file.rel} is ${length} lines with no table of contents in its first 20 lines.`
);
}
}
function checkInlineDependencies(sink, file) {
let inBlock = false;
file.lines.forEach((text2, index) => {
if (PEP723_START.test(text2)) {
inBlock = true;
return;
}
if (inBlock && PEP723_END.test(text2)) {
inBlock = false;
return;
}
const unpinned = [];
if (inBlock && !/requires-python/.test(text2)) {
for (const match of text2.matchAll(QUOTED)) {
if (!PINNED_PEP508.test(match[1])) unpinned.push(match[1]);
}
}
for (const match of text2.matchAll(NPM_SPECIFIER)) {
if (match[2] === void 0) unpinned.push(`npm:${match[1]}`);
}
for (const dependency of unpinned) {
sink.warn(
"SK-019",
file.rel,
index + 1,
`The inline dependency "${dependency}" has no pinned version.`
);
}
});
}
function extraScanFiles(roots, projectRoot) {
const files = [];
for (const root of roots) {
const abs = join103(projectRoot, root);
if (!existsSync52(abs)) continue;
for (const file of readTree(abs)) {
if (file.text !== null) files.push({ path: `${root}/${file.rel}`, content: file.text });
}
}
return files;
}
function isPaqadRuntimeSkill(projectRoot, folder) {
if (!isPaqadRepository(projectRoot)) return false;
const rel = relative18(projectRoot, folder).replaceAll("\\", "/");
if (rel.startsWith("..")) return false;
return skillFolderOf(`${rel}/SKILL.md`, [], { paqadRepo: true })?.folder === rel;
}
function lintSkillFolder(folder, options) {
if (!existsSync52(folder) || !lstatSync2(folder).isDirectory()) {
throw new SkillLintUsageError(`${folder} is not a folder`);
}
const files = readTree(folder);
const skillFiles = files.filter((file) => basename9(file.rel) === "SKILL.md");
const skillFile = files.find((file) => file.rel === "SKILL.md");
if (skillFile === void 0) {
throw new SkillLintUsageError(`${folder} holds no SKILL.md, so it is not a skill folder`);
}
const folderName = basename9(folder.replace(/[\\/]+$/u, ""));
const sink = new FindingSink();
const neverWrite = compileNeverWritePattern(
(options.neverWrite ?? loadNeverWriteList(options.projectRoot)).phrases
);
const parsed = checkFrontmatter(sink, skillFile, folderName, {
...options,
paqadRuntime: options.paqadRuntime ?? isPaqadRuntimeSkill(options.projectRoot, folder)
});
if (parsed !== null)
checkBody(sink, parsed.body, options.bodyMaxTokens ?? DEFAULT_BODY_MAX_TOKENS);
for (const extra of skillFiles.filter((file) => file !== skillFile)) {
sink.block("SK-007", extra.rel, 1, "A second SKILL.md in the folder. Keep one per skill.");
}
checkReferences(sink, files, skillFile);
const testDirs = skillTestDirectories(folderName, {
paqadRepo: isPaqadRepository(options.projectRoot)
});
checkScripts(sink, files, testFilesFor(options.projectRoot, testDirs));
for (const link of files.filter((file) => file.symlink?.scannable === false)) {
sink.block(
"SK-011",
link.rel,
1,
`A symlink to ${link.symlink.target} that leads outside the skill folder, so it can't be scanned for secrets. Copy the real file into the folder.`
);
}
checkYamlFiles(sink, files);
const textFiles = files.filter((file) => file.text !== null);
checkSecrets2(sink, [
...textFiles.map((file) => ({ path: file.rel, content: file.text })),
...extraScanFiles([...testDirs, ...options.extraScanRoots ?? []], options.projectRoot)
]);
for (const file of textFiles) {
checkEmDash2(sink, file);
if (isMarkdown(file.rel)) checkProse(sink, file, neverWrite);
if (file === skillFile && parsed !== null) checkDynamic2(sink, file, parsed.bodyStartLine);
if (under(file.rel, "references")) {
checkDynamic2(sink, file, 1);
checkTableOfContents(sink, file);
}
if (under(file.rel, "scripts")) checkInlineDependencies(sink, file);
}
const findings = sortFindings(sink.findings);
return { skill: folderName, findings, ...countFindings(findings) };
}
function skillLintExitCode(result2) {
return lintExitCode(result2);
}
function formatSkillLintJson(result2) {
return formatLintJson(result2);
}
// src/authoring/workspace.ts
var WORKSPACE_ROOT = ".paqad/tmp/authoring/skills";
var TRACKED_ROOT = ".paqad/authoring/skills";
var AGENT_WORKSPACE_ROOT = ".paqad/tmp/authoring/agents";
var AGENT_TRACKED_ROOT = ".paqad/authoring/agents";
var AGENT_NAME_MAX = 256;
var BUILTIN_OVERRIDE_AGENT_NAMES = ["Explore"];
var AuthoringRefusal = class extends Error {
constructor(message, exitCode = 1) {
super(message);
this.exitCode = exitCode;
}
exitCode;
};
function validateSkillName(name) {
if (typeof name !== "string" || name.length === 0 || name.length > SKILL_NAME_MAX) {
throw new AuthoringRefusal(
`"${String(name)}" is not a skill name: use 1 to ${SKILL_NAME_MAX} characters.`,
2
);
}
if (!SKILL_NAME_PATTERN.test(name)) {
throw new AuthoringRefusal(
`"${name}" is not a skill name: use a-z, 0-9 and single hyphens, with no hyphen at either end.`,
2
);
}
return name;
}
function isValidAgentName(name) {
if (typeof name !== "string") return false;
if (BUILTIN_OVERRIDE_AGENT_NAMES.includes(name)) return true;
return name.length > 0 && name.length <= AGENT_NAME_MAX && SKILL_NAME_PATTERN.test(name);
}
function validateAgentName(name) {
if (typeof name === "string" && BUILTIN_OVERRIDE_AGENT_NAMES.includes(name)) return name;
if (typeof name !== "string" || name.length === 0 || name.length > AGENT_NAME_MAX) {
throw new AuthoringRefusal(
`"${String(name)}" is not an agent name: use 1 to ${AGENT_NAME_MAX} characters.`,
2
);
}
if (!SKILL_NAME_PATTERN.test(name)) {
throw new AuthoringRefusal(
`"${name}" is not an agent name: use a-z, 0-9 and single hyphens, with no hyphen at either end, naming the role (code-reviewer, test-runner).`,
2
);
}
return name;
}
var SKILL_STAGES = [
{
id: "S0",
name: "justify",
artifact: "justification.md",
command: (name) => `paqad-ai skill justify ${name}`
},
{
id: "S1",
name: "intake",
artifact: "intake.yaml",
command: (name) => `paqad-ai skill intake ${name} <intake.yaml>`
},
{
id: "S2",
name: "evidence",
artifact: "overlap.md",
command: (name) => `paqad-ai skill evidence ${name} <sources.md>`
},
{
id: "S3",
name: "draft",
artifact: "trace.md",
command: (name) => `paqad-ai skill draft ${name} --dir <folder> --trace <trace.md>`
},
{
id: "S4",
name: "lint and tests",
artifact: "script-tests.json",
command: (name) => `paqad-ai skill test ${name}`
},
{
id: "S5",
name: "evals",
artifact: "benchmark.json",
command: (name) => `paqad-ai skill eval plan ${name}`
},
{
id: "S6",
name: "trigger",
artifact: "trigger-results.json",
command: (name) => `paqad-ai skill trigger plan ${name}`
},
{
id: "S7",
name: "release",
artifact: "release.json",
command: (name) => `paqad-ai skill release ${name}`
}
];
var AGENT_STAGES = [
{
id: "S0",
name: "justify",
artifact: "justification.md",
command: (name) => `paqad-ai agent justify ${name} --task-file <task.md> --reason <key>`
},
{
id: "S1",
name: "intake",
artifact: "intake.yaml",
command: (name) => `paqad-ai agent intake ${name} <intake.yaml>`
},
{
id: "S2",
name: "evidence",
artifact: "overlap.md",
command: (name) => `paqad-ai agent evidence ${name} <sources.md>`
},
{
id: "S3",
name: "draft",
artifact: "trace.md",
command: (name) => `paqad-ai agent draft ${name} --file <agent.md> --trace <trace.md>`
},
{
id: "S4",
name: "lint and tests",
artifact: "script-tests.json",
command: (name) => `paqad-ai agent test ${name}`
},
{
id: "S5",
name: "evals",
artifact: "benchmark.json",
command: (name) => `paqad-ai agent eval plan ${name}`
},
{
id: "S6",
name: "delegation",
artifact: "delegation-results.json",
command: (name) => `paqad-ai agent delegation plan ${name}`
},
{
id: "S7",
name: "release",
artifact: "release.json",
command: (name) => `paqad-ai agent release ${name}`
}
];
function stageById(id, stages = SKILL_STAGES) {
const stage = stages.find((entry) => entry.id === id);
if (!stage) throw new Error(`unknown ${stages === AGENT_STAGES ? "agent" : "skill"} stage ${id}`);
return stage;
}
var AuthoringWorkspace = class {
constructor(projectRoot, name, kind, root, trackedRoot, stages) {
this.projectRoot = projectRoot;
this.name = name;
this.kind = kind;
this.root = root;
this.trackedRoot = trackedRoot;
this.stages = stages;
this.rel = `${root}/${name}`;
this.dir = join104(projectRoot, root, name);
}
projectRoot;
name;
kind;
root;
trackedRoot;
stages;
rel;
dir;
path(rel) {
return join104(this.dir, rel);
}
relPath(rel) {
return `${this.rel}/${rel}`;
}
exists(rel) {
return existsSync53(this.path(rel));
}
read(rel) {
try {
return readFileSync48(this.path(rel), "utf8");
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
}
}
readJson(rel) {
const text2 = this.read(rel);
if (text2 === null) return null;
try {
return JSON.parse(text2);
} catch {
return null;
}
}
write(rel, content) {
const target = this.path(rel);
mkdirSync23(dirname42(target), { recursive: true });
const tmp = `${target}.tmp`;
writeFileSync24(tmp, redactSecrets(content, this.projectRoot), "utf8");
renameSync7(tmp, target);
return this.relPath(rel);
}
writeJson(rel, value) {
return this.write(rel, `${JSON.stringify(value, null, 2)}
`);
}
remove(rel) {
rmSync14(this.path(rel), { recursive: true, force: true });
}
clear() {
rmSync14(this.dir, { recursive: true, force: true });
}
};
var SkillWorkspace = class extends AuthoringWorkspace {
constructor(projectRoot, name) {
super(
projectRoot,
validateSkillName(name),
"skill",
WORKSPACE_ROOT,
TRACKED_ROOT,
SKILL_STAGES
);
}
};
var AgentWorkspace = class extends AuthoringWorkspace {
constructor(projectRoot, name) {
super(
projectRoot,
validateAgentName(name),
"agent",
AGENT_WORKSPACE_ROOT,
AGENT_TRACKED_ROOT,
AGENT_STAGES
);
}
};
function renderGateMarkdown(meta, body) {
return `---
${import_yaml13.default.stringify(meta).trimEnd()}
---
${body.endsWith("\n") ? body : `${body}
`}`;
}
function readGateMeta(text2, kind) {
if (text2 === null) return null;
try {
if (kind === "json") {
const parsed2 = JSON.parse(text2);
return typeof parsed2.gate === "string" ? parsed2 : null;
}
if (kind === "yaml") return { gate: "passed" };
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n/u.exec(text2);
if (!match) return null;
const parsed = import_yaml13.default.parse(match[1]);
return parsed && typeof parsed.gate === "string" ? parsed : null;
} catch {
return null;
}
}
function artifactKind(artifact) {
if (artifact.endsWith(".json")) return "json";
if (artifact.endsWith(".yaml")) return "yaml";
return "markdown";
}
var MODE_FILE = "mode.json";
var OVERRIDES_FILE = "overrides.json";
function readOverrides(workspace) {
return workspace.readJson(OVERRIDES_FILE) ?? [];
}
var WAITING_FILE = "waiting.json";
function readMode(workspace) {
return workspace.readJson(MODE_FILE) ?? { entry: "new" };
}
function readWaiting(workspace) {
return workspace.readJson(WAITING_FILE) ?? [];
}
function setWaiting(workspace, entry) {
const rest = readWaiting(workspace).filter((item) => item.stage !== entry.stage);
workspace.writeJson(WAITING_FILE, [...rest, entry]);
}
function clearWaiting(workspace, stage) {
const rest = readWaiting(workspace).filter((item) => item.stage !== stage);
if (rest.length === 0) workspace.remove(WAITING_FILE);
else workspace.writeJson(WAITING_FILE, rest);
}
function skipsJustify(workspace, stage) {
return stage.id === "S0" && readMode(workspace).entry === "improve";
}
function stageState(workspace, stage) {
const artifact = workspace.relPath(stage.artifact);
const waiting = readWaiting(workspace).find((entry) => entry.stage === stage.id);
if (waiting) {
return {
stage,
state: "waiting",
artifact,
detail: waiting.resume,
decision: waiting.decision
};
}
const override = readOverrides(workspace).find((entry) => entry.gate === stage.id);
if (override) {
return {
stage,
state: "overridden",
artifact,
detail: `override ${override.decision} by ${override.by}`,
decision: override.decision
};
}
if (skipsJustify(workspace, stage)) {
return {
stage,
state: "skipped",
artifact,
detail: "improve mode: the snapshot is the baseline",
decision: null
};
}
const meta = readGateMeta(workspace.read(stage.artifact), artifactKind(stage.artifact));
if (meta === null) {
return { stage, state: "not-run", artifact, detail: null, decision: null };
}
const detail = typeof meta.reason === "string" ? meta.reason : null;
return { stage, state: meta.gate, artifact, detail, decision: null };
}
function allStageStates(workspace) {
return workspace.stages.map((stage) => stageState(workspace, stage));
}
function gateSatisfied(state) {
return state === "passed" || state === "skipped" || state === "overridden";
}
function requireEarlierGates(workspace, stageId) {
for (const stage of workspace.stages) {
if (stage.id === stageId) return;
const state = stageState(workspace, stage);
if (gateSatisfied(state.state)) continue;
const current = stageById(stageId, workspace.stages);
const why = state.state === "waiting" ? `it is waiting on decision ${state.decision}` : state.state === "not-run" ? "it has not run" : `its gate is ${state.state}`;
throw new AuthoringRefusal(
`${current.id} ${current.name} can't start: ${stage.id} ${stage.name} has not passed (${why}). The missing artifact is ${state.artifact}. Run ${stage.command(workspace.name)} first.`
);
}
}
// src/authoring/lint/agent-lint.ts
var AGENT_NAME_MAX2 = 256;
var AGENT_SKILLS_MAX = 32;
var AGENT_MEMORY_MAX_BYTES = 25 * 1024;
var TOOL_DEFINITIONS_MAX_TOKENS = 1e4;
var TOOL_DEFINITION_TOKENS_ESTIMATE = 500;
var REPORT_STATUSES = ["DONE", "DONE_WITH_CONCERNS", "NEEDS_CONTEXT", "BLOCKED"];
var AUTO_DESCRIPTION_OPENING = "Use this agent when";
var DISPATCHED_DESCRIPTION = /\bdispatched by\b/iu;
var TOOL_LIMIT_POWER = "tool-limit";
var PERMISSION_RULE = "AG-015";
var TOOL_LIMIT_RULE = "AG-018";
var RISKY_POWER_RULE = "AG-022";
var READ_ONLY_PAQAD_AGENT = /^paqad-(planning|specification|review|checks|expert|chief-architect)$/u;
var STAGE_WRITE_GUARD_HOOK = "stage-agent-write-guard.mjs";
var NAMES_ITS_ENFORCER = /\bcapability gate\b|\bstage-agent-[a-z-]+\.mjs\b/u;
var NAMES_A_PAQAD_COMMAND = /`paqad-ai [^`]+`/u;
var POWER_RULES = [PERMISSION_RULE, TOOL_LIMIT_RULE, RISKY_POWER_RULE];
var SCRIPT_INTERPRETERS = /^(?:node|php|python3?|ruby|bash|sh|deno|bun|tsx)$/u;
var SHELL_OPERATORS = /[;&|`<>]|\$\(/u;
var HOOK_SCRIPT_PREFIX = /^(?:"?\$\{?CLAUDE_PROJECT_DIR\}?"?\/|\.\/)/u;
var TIME_OF_DAY = /\b(?:[01]?\d|2[0-3]):[0-5]\d\b/u;
var UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/iu;
var RANDOM_ID = /\b(?=(?:[a-z]*\d){3})(?=[a-z0-9]*[a-z])[a-z0-9]{12,}\b/iu;
var TOKEN_MAX = /\b\d[\d,]*\s*tokens?\b/iu;
var OPEN_INTERPRETERS = /^(?:\*|(?:sh|bash|zsh|node|python3?|npx|curl|wget|eval|deno|bun|ruby|perl|php)\b)/u;
var INSTALL_COMMAND = /\b(?:(?:pnpm|npm|yarn|bun)\s+(?:add|install|i)\b|pip3?\s+install\b|composer\s+(?:require|install)\b)/u;
var DELETE_COMMAND = /(?:^|\s)rm\b|\bgit\s+clean\b|\bgit\s+reset\s+--hard\b/u;
var BODY_HEADINGS = ["Objective", "Procedure", "Report", "Stop when", "Do not", "Example"];
var STATED_TURN_LIMIT = /\b(?:at most|no more than|up to)\s+\d+\s+turns\b/iu;
var DEFAULT_AGENT_LINT_LIMITS = {
descriptionMaxTokens: 300,
catalogMaxTokens: 15e3,
promptMaxTokens: 3e3,
maxTools: 10,
memoryMaxLines: 200,
collisionJaccard: 0.4
};
var AgentLintUsageError = class extends Error {
};
function hookCommands(hooks) {
if (!hooks || typeof hooks !== "object" || Array.isArray(hooks)) return [];
const commands = [];
for (const [event, entries] of Object.entries(hooks)) {
if (!Array.isArray(entries)) continue;
for (const entry of entries) {
const matcher = typeof entry?.matcher === "string" ? entry.matcher : "*";
const inner = Array.isArray(entry?.hooks) ? entry.hooks : [];
for (const hook of inner) {
if (typeof hook?.command === "string")
commands.push({ event, matcher, command: hook.command });
}
}
}
return commands;
}
function scriptOf(command) {
const words = command.trim().split(/\s+/u);
const first = words[0] ?? "";
const candidate = SCRIPT_INTERPRETERS.test(first) ? words[1] : first;
if (candidate === void 0 || candidate.startsWith("-")) return null;
const path10 = candidate.replace(/^"|"$/gu, "").replace(HOOK_SCRIPT_PREFIX, "");
return /\.[a-z0-9]+$/iu.test(path10) || path10.includes("/") ? path10 : null;
}
function agentHookScripts(projectRoot, hooks) {
const commands = hookCommands(hooks);
const scripts = [];
const problems = [];
const root = resolve4(projectRoot);
for (const hook of commands) {
const script = SHELL_OPERATORS.test(hook.command) ? null : scriptOf(hook.command);
if (script === null) {
problems.push({
command: hook.command,
problem: "is an inline shell command, not a script. Move it into a script file with a test."
});
continue;
}
const abs = isAbsolute6(script) ? resolve4(script) : resolve4(root, script);
const rel = relative19(root, abs).replaceAll("\\", "/");
if (rel === "" || rel.startsWith("..") || isAbsolute6(rel)) {
problems.push({
command: hook.command,
problem: "names a script outside the project root. Keep hook scripts inside the project."
});
continue;
}
if (!scripts.includes(rel)) scripts.push(rel);
}
return { scripts, problems, commands };
}
function parseTool(raw) {
const match = /^([A-Za-z_][\w-]*)\((.*)\)$/u.exec(raw.trim());
return match ? { raw, base: match[1], pattern: match[2].trim() } : { raw, base: raw.trim(), pattern: null };
}
function listOf(value) {
if (Array.isArray(value)) {
return value.filter((item) => typeof item === "string").map((item) => item.trim());
}
if (typeof value === "string") {
return value.split(/,(?![^(]*\))/u).map((item) => item.trim()).filter((item) => item !== "");
}
return void 0;
}
function mcpServerNames(value) {
if (Array.isArray(value)) {
return value.flatMap(
(entry) => typeof entry === "string" ? [entry] : entry && typeof entry === "object" ? Object.keys(entry) : []
);
}
if (value && typeof value === "object") return Object.keys(value);
return [];
}
function projectMcpServers(projectRoot) {
const text2 = readTextIfPresent(join105(projectRoot, ".mcp.json"));
if (text2 === null) return [];
try {
const parsed = JSON.parse(text2);
return mcpServerNames(parsed.mcpServers);
} catch {
return [];
}
}
function keyLine2(frontmatterLines, key) {
const index = frontmatterLines.findIndex((line) => line.startsWith(`${key}:`));
return index === -1 ? 1 : index + 2;
}
function sections(body, bodyStartLine) {
const found = [];
body.split("\n").forEach((text2, index) => {
const heading = /^##\s+(.+?)\s*$/u.exec(text2);
if (heading) {
found.push({ heading: heading[1], line: bodyStartLine + index, lines: [] });
} else if (found.length > 0) {
found.at(-1).lines.push(text2);
}
});
return found;
}
function bodyHeadingOrderProblem(body) {
const present = sections(body, 1).map((section3) => section3.heading).filter((heading) => BODY_HEADINGS.includes(heading));
const missing = BODY_HEADINGS.filter((heading) => !present.includes(heading));
if (missing.length > 0) return `missing ${missing.map((heading) => `## ${heading}`).join(", ")}`;
const order = BODY_HEADINGS.filter((heading) => present.includes(heading));
if (present.some((heading, index) => heading !== order[index])) {
return `the headings must come in the order ${BODY_HEADINGS.join(", ")}`;
}
return null;
}
function parsePermissionContext(context) {
const match = /^Powers: (.*)\. File hash: (.*)\.$/u.exec(context.trim());
if (!match) return null;
return {
powers: match[1].split(", ").filter((power) => power !== ""),
fileHash: match[2]
};
}
function readPacketContext(projectRoot, id) {
const row = readContractDecisions(projectRoot).find((entry) => entry.packet.id === id);
const context = row?.packet?.context;
return typeof context === "string" ? context : null;
}
function permissionPacketNamesFile(projectRoot, id, fileHash) {
const context = readPacketContext(projectRoot, id);
return context !== null && parsePermissionContext(context)?.fileHash === fileHash;
}
function permissionApproval(projectRoot, decisions, powers, fileHash, now) {
const wanted = [...new Set(powers)].sort().join(", ");
const ttlDays = DECISION_CATEGORY_DEFAULTS["authoring.agent_permission"].ttl_days;
let reason2 = "no resolved authoring.agent_permission packet id is recorded";
for (const id of decisions) {
const record2 = readAuthoringDecision(projectRoot, id);
if (record2 === null) {
reason2 = `decision ${id} is not in the decision ledger`;
continue;
}
if (record2.category !== "authoring.agent_permission") {
reason2 = `decision ${id} is a ${record2.category} decision`;
continue;
}
if (record2.status !== "resolved" || record2.chosen !== AGENT_PERMISSION_ALLOW) {
reason2 = `decision ${id} is not resolved with Allow these powers`;
continue;
}
const resolvedAt2 = record2.resolvedAt === null ? Number.NaN : Date.parse(record2.resolvedAt);
if (!Number.isFinite(resolvedAt2) || now.getTime() > resolvedAt2 + ttlDays * 864e5) {
reason2 = `decision ${id} expired after ${ttlDays} days`;
continue;
}
const context = readPacketContext(projectRoot, id);
const listed = context === null ? null : parsePermissionContext(context);
if (listed === null || [...listed.powers].sort().join(", ") !== wanted) {
reason2 = `decision ${id} lists other powers than ${wanted}`;
continue;
}
if (listed.fileHash !== fileHash) {
reason2 = `decision ${id} approved an earlier version of the agent file`;
continue;
}
return { approved: true, decision: id, reason: `approved by ${id}` };
}
return { approved: false, decision: null, reason: reason2 };
}
function checkName2(ctx) {
const { sink, rel, data } = ctx;
const line = keyLine2(ctx.frontmatterLines, "name");
const name = typeof data.name === "string" ? data.name.trim() : "";
if (name === "") {
sink.block(
"AG-001",
rel,
line,
"The agent has no name. Add a lowercase, hyphenated role name."
);
return basename10(rel).replace(/\.[^.]+$/u, "");
}
if (name.includes(":") || name.startsWith("-") || name.length > AGENT_NAME_MAX2) {
sink.block(
"AG-001",
rel,
line,
`The name "${name}" has a colon, a leading hyphen or more than ${AGENT_NAME_MAX2} characters, so the host skips the file.`
);
} else if (!isValidAgentName(name)) {
sink.block(
"AG-001",
rel,
line,
`The name "${name}" is not an agent name: use a-z, 0-9 and single hyphens, with no hyphen at either end, so no path built from it leaves the agents folder.`
);
}
if (!isObjectRoleName(name)) {
sink.warn(
"AG-002",
rel,
line,
`The name "${name}" does not name a role (code-reviewer, test-runner, db-reader).`
);
}
return name;
}
function checkDescription2(ctx) {
const { sink, rel, data, limits } = ctx;
const line = keyLine2(ctx.frontmatterLines, "description");
const description = typeof data.description === "string" ? data.description.trim() : "";
if (description === "") {
sink.block("AG-003", rel, line, "The agent has no description, so the host skips the file.");
return "";
}
const tokens = estimateTokens(description);
if (tokens > limits.descriptionMaxTokens) {
sink.block(
"AG-003",
rel,
line,
`The description is ${tokens} tokens, over the limit of ${limits.descriptionMaxTokens} (agent_description_max_tokens).`
);
}
const auto = description.startsWith(AUTO_DESCRIPTION_OPENING);
const dispatched = DISPATCHED_DESCRIPTION.test(description);
const invocation = ctx.options.invocation;
if (invocation === "auto" && !auto) {
sink.block(
"AG-003",
rel,
line,
`The description must open with "${AUTO_DESCRIPTION_OPENING}".`
);
} else if (invocation === "dispatched" && !dispatched) {
sink.block(
"AG-003",
rel,
line,
'The description must say who dispatches the agent, as in "Dispatched by the paqad orchestrator only."'
);
} else if (invocation === void 0 && !auto && !dispatched) {
sink.block(
"AG-003",
rel,
line,
`The description must open with "${AUTO_DESCRIPTION_OPENING}" or say who dispatches the agent.`
);
}
return description;
}
function checkCatalog(ctx, name, description, installed) {
const sizes = /* @__PURE__ */ new Map();
for (const agent of installed) {
if (agent.name === name) continue;
sizes.set(agent.name, Math.max(sizes.get(agent.name) ?? 0, estimateTokens(agent.description)));
}
sizes.set(name, estimateTokens(description));
const total = [...sizes.values()].reduce((sum, size) => sum + size, 0);
if (total <= ctx.limits.catalogMaxTokens) return;
const ranked = [...sizes.entries()].sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).map(([agent, size]) => `${agent} (${size})`);
ctx.sink.block(
"AG-004",
ctx.rel,
keyLine2(ctx.frontmatterLines, "description"),
`The agent descriptions add up to ${total} tokens, over ${ctx.limits.catalogMaxTokens} (agent_catalog_description_max_tokens). By size: ${ranked.join(", ")}.`
);
}
function checkReferences2(ctx, tools, skills) {
const { sink, rel, data, options } = ctx;
const known = new Set(CLAUDE_CODE_AGENT_FIELDS.tools);
const servers = new Set(options.mcpServers ?? projectMcpServers(options.projectRoot));
const toolLine = keyLine2(ctx.frontmatterLines, "tools");
const disallowed = (listOf(data.disallowedTools) ?? []).map(parseTool);
for (const tool of [...tools, ...disallowed]) {
const mcp = /^mcp__([^_]+(?:_[^_]+)*?)__/u.exec(tool.base);
if (mcp) {
if (!servers.has(mcp[1])) {
sink.block(
"AG-005",
rel,
toolLine,
`The tool ${tool.raw} names the MCP server ${mcp[1]}, which is not configured.`
);
}
} else if (!known.has(tool.base)) {
sink.block("AG-005", rel, toolLine, `The tool ${tool.raw} does not exist on the host.`);
}
}
const installedSkills = new Set(
options.installedSkills ?? discoverInstalledSkills(
options.projectRoot,
options.context ?? readSkillPathContext(options.projectRoot),
{ userHome: null }
).map((skill) => skill.name)
);
for (const skill of skills) {
if (!installedSkills.has(skill)) {
sink.block(
"AG-005",
rel,
keyLine2(ctx.frontmatterLines, "skills"),
`The skill ${skill} is not installed.`
);
}
}
for (const server of mcpServerNames(data.mcpServers)) {
const inline = data.mcpServers && typeof data.mcpServers === "object" && !Array.isArray(data.mcpServers);
if (!inline && !servers.has(server)) {
sink.block(
"AG-005",
rel,
keyLine2(ctx.frontmatterLines, "mcpServers"),
`The MCP server ${server} is not configured.`
);
}
}
}
function checkCodexTurns(ctx) {
if (!STATED_TURN_LIMIT.test(ctx.body)) {
ctx.sink.block(
"AG-007",
ctx.rel,
ctx.bodyStartLine,
'Codex has no maxTurns field, and the body states no turn limit (as in "at most 60 turns").'
);
}
}
function checkModel(ctx) {
const { sink, rel, data } = ctx;
if (ctx.options.host === "codex") {
checkCodexTurns(ctx);
return;
}
if (data.model !== void 0 && (typeof data.model !== "string" || !isClaudeModel(data.model))) {
sink.block(
"AG-006",
rel,
keyLine2(ctx.frontmatterLines, "model"),
`The model ${String(data.model)} is not valid for Claude Code. Use ${CLAUDE_CODE_AGENT_FIELDS.models.join(", ")} or a full claude- model id.`
);
}
if (data.effort !== void 0 && !CLAUDE_CODE_AGENT_FIELDS.efforts.includes(data.effort)) {
sink.block(
"AG-006",
rel,
keyLine2(ctx.frontmatterLines, "effort"),
`The effort ${String(data.effort)} is not valid. Use ${CLAUDE_CODE_AGENT_FIELDS.efforts.join(", ")}.`
);
}
const maxTurns = data.maxTurns;
if (typeof maxTurns !== "number" || !Number.isInteger(maxTurns) || maxTurns < 1) {
sink.block(
"AG-007",
rel,
keyLine2(ctx.frontmatterLines, "maxTurns"),
maxTurns === void 0 ? "The field maxTurns is missing. Set the most turns the agent may take." : `The field maxTurns is ${String(maxTurns)}; use a positive whole number.`
);
}
}
function checkReport(ctx) {
const report = sections(ctx.body, ctx.bodyStartLine).find(
(section3) => section3.heading === "Report"
);
if (report === void 0) {
ctx.sink.block("AG-008", ctx.rel, ctx.bodyStartLine, "The body has no ## Report section.");
return;
}
const text2 = report.lines.join("\n");
if (!TOKEN_MAX.test(text2)) {
ctx.sink.block(
"AG-008",
ctx.rel,
report.line,
"The ## Report section states no maximum length in tokens."
);
}
const status = report.lines.find((line) => /\bStatus\b/u.test(line));
if (status === void 0 || !REPORT_STATUSES.some((value) => new RegExp(`\\b${value}\\b`, "u").test(status))) {
ctx.sink.block(
"AG-008",
ctx.rel,
report.line,
`The ## Report section has no Status line from ${REPORT_STATUSES.join(", ")}.`
);
}
}
function checkMemory(ctx) {
const memory = ctx.options.memoryFile;
if (memory === void 0) return;
const abs = join105(ctx.options.projectRoot, memory);
const text2 = readTextIfPresent(abs);
if (text2 === null) return;
const lines = text2.split("\n").length - (text2.endsWith("\n") ? 1 : 0);
const bytes = Buffer.byteLength(text2);
if (lines > ctx.limits.memoryMaxLines || bytes > AGENT_MEMORY_MAX_BYTES) {
ctx.sink.block(
"AG-010",
memory,
1,
`MEMORY.md is ${lines} lines and ${bytes} bytes, over ${ctx.limits.memoryMaxLines} lines or 25 KB. Run paqad-ai agent memory-consolidate.`
);
}
}
function testFiles(projectRoot, name) {
const files = [];
const walk4 = (rel) => {
const abs = join105(projectRoot, rel);
if (!existsSync54(abs)) return;
for (const entry of readdirSync17(abs).sort()) {
const child = `${rel}/${entry}`;
if (statSync8(join105(projectRoot, child)).isDirectory()) walk4(child);
else files.push(child);
}
};
for (const dir of agentTestDirectories(name)) walk4(dir);
return files;
}
function checkHooks(ctx, name, hooks) {
const line = keyLine2(ctx.frontmatterLines, "hooks");
for (const problem of hooks.problems) {
ctx.sink.block(
"AG-011",
ctx.rel,
line,
`The hook command "${problem.command}" ${problem.problem}`
);
}
const tests = testFiles(ctx.options.projectRoot, name);
for (const script of hooks.scripts) {
const abs = join105(ctx.options.projectRoot, script);
const scriptStat = statSync8(abs, { throwIfNoEntry: false });
if (scriptStat === void 0) {
ctx.sink.block("AG-011", ctx.rel, line, `The hook script ${script} does not exist.`);
continue;
}
const command = hooks.commands.find(
(hook) => scriptOf(hook.command) !== null && hook.command.includes(basename10(script))
);
const viaInterpreter = command !== void 0 && SCRIPT_INTERPRETERS.test(command.command.trim().split(/\s+/u)[0] ?? "");
if (!viaInterpreter && (scriptStat.mode & 73) === 0) {
ctx.sink.block(
"AG-011",
ctx.rel,
line,
`The hook script ${script} is not executable. Run it through an interpreter, as in node ${script}.`
);
}
const stem = basename10(script).split(".")[0].toLowerCase();
if (!tests.some((test) => basename10(test).toLowerCase().includes(stem))) {
ctx.sink.block(
"AG-011",
ctx.rel,
line,
`The hook script ${script} has no test under ${agentTestDirectories(name).join(" or ")}.`
);
}
}
}
function matcherCovers(matcher, tool) {
if (matcher === "*" || matcher === "") return true;
try {
return new RegExp(`^(?:${matcher})$`, "u").test(tool);
} catch {
return matcher === tool;
}
}
function blockingHookFor(hooks, tool) {
return hooks.commands.some(
(hook) => hook.event === "PreToolUse" && matcherCovers(hook.matcher, tool)
);
}
function withStageWriteGuard(name, tools, hooks) {
const editing = tools?.some((tool) => tool.base === "Edit" || tool.base === "Write") ?? true;
if (editing || !READ_ONLY_PAQAD_AGENT.test(name)) return hooks;
return {
...hooks,
commands: [
...hooks.commands,
{ event: "PreToolUse", matcher: "Bash", command: STAGE_WRITE_GUARD_HOOK }
]
};
}
function riskyPowers(tools, hooks) {
const risky = [];
const add = (power, tool) => {
if (!risky.some((entry) => entry.power === power)) risky.push({ power, tool });
};
if (tools === void 0) {
add("Bash", "every tool (no tools list)");
add("WebFetch", "every tool (no tools list)");
add("WebSearch", "every tool (no tools list)");
return risky;
}
for (const tool of tools) {
if (tool.base === "WebFetch" || tool.base === "WebSearch") add(tool.base, tool.raw);
if (tool.base !== "Bash" && tool.base !== "PowerShell") continue;
const pattern = tool.pattern ?? "";
const open = tool.pattern === null || pattern === "" || OPEN_INTERPRETERS.test(pattern);
if (open && !blockingHookFor(hooks, tool.base)) add(tool.base, tool.raw);
if (INSTALL_COMMAND.test(pattern)) add("install", tool.raw);
if (DELETE_COMMAND.test(pattern)) add("delete", tool.raw);
}
return risky;
}
function checkDoNot(ctx, tools, hooks) {
const section3 = sections(ctx.body, ctx.bodyStartLine).find((entry) => entry.heading === "Do not");
if (section3 === void 0) return;
const allowed = new Set((tools ?? []).map((tool) => tool.base));
const denied = new Set(
(listOf(ctx.data.disallowedTools) ?? []).map((tool) => parseTool(tool).base)
);
const paqadOwned = String(ctx.data.name ?? "").startsWith("paqad-");
section3.lines.forEach((text2, index) => {
if (!/^\s*(?:[-*+]|\d+[.)])\s+/u.test(text2)) return;
const named = CLAUDE_CODE_AGENT_FIELDS.tools.filter(
(tool) => new RegExp(`\\b${tool}\\b`, "u").test(text2)
);
const enforced = NAMES_ITS_ENFORCER.test(text2) || paqadOwned && NAMES_A_PAQAD_COMMAND.test(text2) || named.some((tool) => denied.has(tool) || tools !== void 0 && !allowed.has(tool)) || named.some((tool) => blockingHookFor(hooks, tool)) || tools !== void 0 && /\b(?:edit|write|modify|change)\b/iu.test(text2) && !allowed.has("Edit") && !allowed.has("Write");
if (!enforced) {
ctx.sink.warn(
"AG-021",
ctx.rel,
section3.line + index + 1,
"No tool restriction or hook enforces this Do not item. Restrict the tool or add a blocking hook."
);
}
});
}
function readAgentText(file) {
if (file.endsWith(".toml")) {
throw new AgentLintUsageError(
`${file} is a rendered Codex agent. Lint the Markdown source the release renders it from.`
);
}
let regular;
try {
regular = readRegularFile(file);
} catch (error) {
if (!isMissingPathError(error)) throw error;
regular = null;
}
if (regular === null) throw new AgentLintUsageError(`${file} is not a file`);
return regular.buffer.toString("utf8");
}
function relTo(projectRoot, file) {
const rel = relative19(projectRoot, resolve4(projectRoot, file)).replaceAll("\\", "/");
return rel.startsWith("..") ? file.replaceAll("\\", "/") : rel;
}
function textFile(projectRoot, rel) {
const content = readTextIfPresent(join105(projectRoot, rel));
return content === null ? null : { rel, lines: content.split("\n"), content };
}
function lintAgentFile(file, options) {
const projectRoot = options.projectRoot;
const content = options.content ?? readAgentText(resolve4(projectRoot, file));
const rel = relTo(projectRoot, file);
const hashOf = (scripts = [], root = projectRoot) => options.content === void 0 ? hashAgentFile(projectRoot, rel, scripts, root) : hashAgentText(options.content, scripts, root);
const limits = { ...DEFAULT_AGENT_LINT_LIMITS, ...options.limits };
const sink = new FindingSink();
const split = splitSkillFrontmatter(content);
if (!split.ok) {
sink.block("AG-001", rel, 1, split.message.replace("SKILL.md", "The agent file"));
const findings2 = sortFindings(sink.findings);
return {
agent: basename10(rel).replace(/\.[^.]+$/u, ""),
findings: findings2,
...countFindings(findings2),
powers: [],
file_hash: hashOf(),
hook_scripts: []
};
}
const ctx = {
sink,
rel,
data: split.data,
frontmatterLines: split.frontmatterLines,
body: split.body,
bodyStartLine: split.bodyStartLine,
limits,
options
};
const name = checkName2(ctx);
const description = checkDescription2(ctx);
const context = options.context ?? readSkillPathContext(projectRoot);
const installed = options.installedAgents ?? discoverInstalledAgents(projectRoot, context, { userHome: null });
checkCatalog(ctx, name, description, installed);
const rawTools = listOf(split.data.tools);
const tools = rawTools?.map(parseTool);
const skills = listOf(split.data.skills) ?? [];
checkReferences2(ctx, tools ?? [], skills);
checkModel(ctx);
checkReport(ctx);
if (skills.length > AGENT_SKILLS_MAX) {
sink.block(
"AG-009",
rel,
keyLine2(ctx.frontmatterLines, "skills"),
`The agent preloads ${skills.length} skills, over ${AGENT_SKILLS_MAX}.`
);
}
checkMemory(ctx);
const hooks = agentHookScripts(projectRoot, split.data.hooks);
checkHooks(ctx, name, hooks);
const bodyTokens = estimateTokens(split.body);
if (bodyTokens > limits.promptMaxTokens) {
sink.block(
"AG-014",
rel,
split.bodyStartLine,
`The body is ${bodyTokens} tokens, over the limit of ${limits.promptMaxTokens} (agent_prompt_max_tokens).`
);
}
const candidate = {
kind: "agent",
name,
text: description,
scope: options.scope ?? "project"
};
const others = installed.filter((agent) => agent.path !== rel);
for (const shadow of findNameShadowing(candidate, others)) {
sink.block("AG-016", rel, keyLine2(ctx.frontmatterLines, "name"), shadowingLine(shadow));
}
for (const collision of findCollisions(candidate, others, limits.collisionJaccard).collisions) {
sink.block(
"AG-017",
rel,
keyLine2(ctx.frontmatterLines, "description"),
`The description collides with ${collision.existing} (${collision.existing_path}) at ${collision.score.toFixed(2)}, at or above ${limits.collisionJaccard}.`
);
}
const scriptRoot = options.hookScriptRoot ?? projectRoot;
const fileHash = hashOf(hooks.scripts, scriptRoot);
const codex = options.host === "codex";
const permission = split.data.permissionMode === "bypassPermissions";
const toolCount = rawTools?.length ?? 0;
const toolTokens = toolCount * TOOL_DEFINITION_TOKENS_ESTIMATE;
const overTools = !codex && (toolCount > limits.maxTools || toolTokens > TOOL_DEFINITIONS_MAX_TOKENS);
const risky = codex ? [] : riskyPowers(tools, withStageWriteGuard(name, tools, hooks));
const powers = [
...permission ? ["bypassPermissions"] : [],
...overTools ? [TOOL_LIMIT_POWER] : [],
...risky.map((entry) => entry.power)
].sort();
const approval = powers.length === 0 ? { approved: true, decision: null, reason: "" } : permissionApproval(
projectRoot,
options.permissionDecisions ?? [],
powers,
fileHash,
(options.now ?? (() => /* @__PURE__ */ new Date()))()
);
if (!approval.approved) {
const why = ` Ask for an authoring.agent_permission packet listing ${powers.join(", ")} (${approval.reason}).`;
if (permission) {
sink.block(
PERMISSION_RULE,
rel,
keyLine2(ctx.frontmatterLines, "permissionMode"),
`permissionMode: bypassPermissions skips every permission prompt.${why}`
);
}
if (overTools) {
sink.block(
TOOL_LIMIT_RULE,
rel,
keyLine2(ctx.frontmatterLines, "tools"),
`The agent lists ${toolCount} tools (${(rawTools ?? []).join(", ")}), about ${toolTokens} tokens of tool definitions (estimate), over ${limits.maxTools} tools (agent_max_tools) or ${TOOL_DEFINITIONS_MAX_TOKENS} tokens.${why}`
);
}
for (const entry of risky) {
sink.block(
RISKY_POWER_RULE,
rel,
keyLine2(ctx.frontmatterLines, "tools"),
`The tool ${entry.tool} gives the risky power ${entry.power}.${why}`
);
}
}
checkDoNot(ctx, tools, hooks);
const agentFile = { rel, lines: content.split("\n") };
const extras = [
...hooks.scripts.map((path10) => textFile(scriptRoot, path10)),
...[
...options.extraScanFiles ?? [],
...options.memoryFile === void 0 ? [] : [options.memoryFile]
].map((path10) => textFile(projectRoot, path10))
].filter((entry) => entry !== null);
checkSecrets(sink, "AG-012", [
{ path: rel, content },
...extras.map((entry) => ({ path: entry.rel, content: entry.content }))
]);
checkEmDash(sink, "AG-013", agentFile);
for (const extra of [
...hooks.scripts.map((path10) => textFile(scriptRoot, path10)),
...(options.emDashFiles ?? []).map((path10) => textFile(projectRoot, path10))
]) {
if (extra !== null) checkEmDash(sink, "AG-013", extra);
}
checkDynamic(sink, "AG-019", agentFile, {
firstLine: split.bodyStartLine,
extraPatterns: [TIME_OF_DAY, UUID, RANDOM_ID],
message: "Dynamic content (a date, a time, a counter or a random id) in the system prompt. Keep the prompt the same on every run."
});
const phrases = (options.neverWrite ?? loadNeverWriteList(projectRoot)).phrases;
if (phrases.length > 0) {
checkNeverWrite(sink, "AG-020", agentFile, compileNeverWritePattern(phrases));
}
checkShouted(sink, "AG-020", agentFile);
const findings = sortFindings(sink.findings);
return {
agent: name,
findings,
...countFindings(findings),
powers,
file_hash: fileHash,
hook_scripts: hooks.scripts
};
}
var PERMISSIONS_FILE = "permissions.json";
function agentLintLimitsFrom(config) {
return {
descriptionMaxTokens: config.agent_description_max_tokens,
catalogMaxTokens: config.agent_catalog_description_max_tokens,
promptMaxTokens: config.agent_prompt_max_tokens,
maxTools: config.agent_max_tools,
memoryMaxLines: config.agent_memory_max_lines,
collisionJaccard: config.authoring_collision_jaccard
};
}
function idsIn(text2, pick2) {
if (text2 === null) return [];
try {
const value = pick2(JSON.parse(text2));
return Array.isArray(value) ? value.filter((id) => typeof id === "string") : [];
} catch {
return [];
}
}
function readPermissionDecisionIds(projectRoot, name) {
const tracked = readTextIfPresent(join105(projectRoot, AGENT_TRACKED_ROOT, name, "evidence.json"));
const workspace = readTextIfPresent(
join105(projectRoot, AGENT_WORKSPACE_ROOT, name, PERMISSIONS_FILE)
);
return [
.../* @__PURE__ */ new Set([
...idsIn(workspace, (parsed) => parsed),
...idsIn(
tracked,
(parsed) => parsed?.permission_decisions
)
])
];
}
function isAgentName(name) {
try {
validateAgentName(name);
return true;
} catch (error) {
if (error instanceof AuthoringRefusal) return false;
throw error;
}
}
function lintAgentInProject(projectRoot, file, extra = {}) {
const config = readAuthoringConfig(projectRoot);
const stem = basename10(file).replace(/\.[^.]+$/u, "");
return lintAgentFile(file, {
projectRoot,
limits: agentLintLimitsFrom(config),
permissionDecisions: isAgentName(stem) ? readPermissionDecisionIds(projectRoot, stem) : [],
...extra
});
}
// src/authoring/completion.ts
function skillCompletionLine(name) {
return `The skill ${name} changed but never went through its checks. Run paqad-ai skill status ${name}.`;
}
function changedSkillFolders(projectRoot, changedFiles) {
const context = readSkillPathContext(projectRoot);
const folders = /* @__PURE__ */ new Map();
for (const file of changedFiles) {
const match = skillFolderOf(file, context.adapters, context);
if (match) folders.set(match.folder, match);
}
return [...folders.values()].sort(
(left, right) => left.folder < right.folder ? -1 : left.folder > right.folder ? 1 : 0
);
}
function folderRemoved(projectRoot, folder) {
const abs = join106(projectRoot, folder);
return !existsSync55(abs) || listFolderFiles(abs).length === 0;
}
function skillCompletionFindings(input) {
if (!skillOrchestratorEnabled(input.projectRoot)) return [];
const findings = [];
for (const { name, folder } of changedSkillFolders(input.projectRoot, input.changedFiles)) {
if (folderRemoved(input.projectRoot, folder)) continue;
if (isGeneratedRecipeFolder(input.projectRoot, folder, name)) continue;
const record2 = readSkillRecord(input.projectRoot, input.dirName, name);
const statusOk = record2?.status === "passed" || record2?.status === "overridden";
const abs = join106(input.projectRoot, folder);
const hashOk = record2 !== null && record2.released_path === folder && existsSync55(join106(abs, SKILL_FILE)) && record2.folder_hash === hashFolder(abs);
if (!statusOk || !hashOk) {
findings.push({ skill: name, folder, line: skillCompletionLine(name) });
}
}
return findings;
}
function agentCompletionLine(name) {
return `The agent ${name} changed but never went through its checks. Run paqad-ai agent status ${name}.`;
}
function agentPowerLine(name, rules) {
return `The agent ${name} holds a power with no current approval (${rules.join(", ")}): the authoring.agent_permission packet expired or is missing. Run paqad-ai agent test ${name} to ask again.`;
}
function hookScriptsOf(projectRoot, path10) {
const text2 = readTextIfPresent(join106(projectRoot, path10));
if (text2 === null) return [];
const split = splitSkillFrontmatter(text2);
return split.ok ? agentHookScripts(projectRoot, split.data.hooks).scripts : [];
}
function generatedStageAgent(projectRoot, path10) {
if (!path10.startsWith(".claude/agents/paqad-")) return false;
const text2 = readTextIfPresent(join106(projectRoot, path10));
return text2 !== null && isGeneratedProjectStageAgent(path10, text2);
}
function changedAgentFiles(projectRoot, changedFiles) {
const context = readSkillPathContext(projectRoot);
const found = /* @__PURE__ */ new Map();
const scriptOwners = /* @__PURE__ */ new Map();
const owners = () => {
if (scriptOwners.size > 0) return scriptOwners;
for (const agent of discoverInstalledAgents(projectRoot, context, { userHome: null })) {
if (agent.scope !== "project" || agent.path.endsWith(".toml")) continue;
for (const script of hookScriptsOf(projectRoot, agent.path)) {
scriptOwners.set(script, [
...scriptOwners.get(script) ?? [],
{ name: agent.name, path: agent.path }
]);
}
}
return scriptOwners;
};
for (const file of changedFiles) {
const normal = file.replaceAll("\\", "/");
const name = agentNameOf(normal, context.adapters, context);
if (name !== null && generatedStageAgent(projectRoot, normal)) continue;
if (name !== null) {
found.set(normal, { name, path: normal });
continue;
}
for (const owner of owners().get(normal) ?? []) found.set(owner.path, owner);
}
return [...found.values()].sort(
(left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0
);
}
function agentHashMatches(projectRoot, record2, path10) {
const scripts = path10.endsWith(".toml") ? [] : record2.hook_scripts;
const listed = record2.files?.find((file) => file.path === path10)?.hash ?? (record2.released_path === path10 ? record2.file_hash : void 0);
return listed !== void 0 && listed === hashAgentFile(projectRoot, path10, scripts);
}
function unapprovedPowers(projectRoot, path10) {
if (path10.endsWith(".toml") || path10.endsWith(".hbs")) return [];
const lint = lintAgentInProject(projectRoot, join106(projectRoot, path10));
return [
...new Set(
lint.findings.filter((finding) => finding.severity === "block" && POWER_RULES.includes(finding.rule)).map((finding) => finding.rule)
)
].sort();
}
function agentCompletionFindings(input) {
if (!agentOrchestratorEnabled(input.projectRoot)) return [];
const findings = [];
for (const { name, path: path10 } of changedAgentFiles(input.projectRoot, input.changedFiles)) {
if (!existsSync55(join106(input.projectRoot, path10))) continue;
const record2 = readAgentRecord(input.projectRoot, input.dirName, name);
const statusOk = record2?.status === "passed" || record2?.status === "overridden";
if (!statusOk || record2 === null || !agentHashMatches(input.projectRoot, record2, path10)) {
findings.push({ agent: name, path: path10, line: agentCompletionLine(name) });
continue;
}
const powers = unapprovedPowers(input.projectRoot, path10);
if (powers.length > 0) findings.push({ agent: name, path: path10, line: agentPowerLine(name, powers) });
}
return findings;
}
// src/feature-evidence/ledger-chain.ts
init_esm_shims();
var CHAINED_VERSION = 3;
var RECORD_REPAIR = "record-repair";
function matchesAcrossGaps(entries, prevHash) {
for (let index = entries.length - 1; index >= 0; index -= 1) {
const entry = entries[index];
if (entry.hash === prevHash) return true;
if (!entry.gap) return false;
}
return prevHash === null;
}
function parseLine(line) {
try {
const parsed = JSON.parse(line);
return parsed && typeof parsed === "object" ? parsed : null;
} catch {
return null;
}
}
function repairedRows(lines) {
const repaired = /* @__PURE__ */ new Map();
for (const line of lines) {
if (line.trim() === "" || !line.includes(RECORD_REPAIR)) continue;
const row = parseLine(line);
if (row?.kind !== RECORD_REPAIR) continue;
if (typeof row.repairs_row !== "number" || typeof row.repairs_hash !== "string") continue;
repaired.set(row.repairs_row, {
hash: row.repairs_hash,
reason: typeof row.reason === "string" ? row.reason : "no reason given"
});
}
return repaired;
}
function checkStageChain(raw) {
const lines = raw.split("\n");
const repaired = repairedRows(lines);
const check2 = { rows: 0, torn_tail: false, gaps: [], breaks: [], blind_spot: null };
const gapRows = [];
const entries = [];
let seenChained = false;
lines.forEach((line, index) => {
if (line.trim() === "") return;
const number = index + 1;
const row = parseLine(line);
if (row === null) {
check2.gaps.push(`row ${number} is a torn line`);
if (index >= lines.length - 2) check2.torn_tail = true;
return;
}
check2.rows += 1;
const hash = typeof row.content_hash === "string" ? row.content_hash : null;
if (row.schema_version !== CHAINED_VERSION) {
if (seenChained) check2.gaps.push(`row ${number} was written by an older copy of paqad`);
if (seenChained) gapRows.push(number);
entries.push({ hash, gap: seenChained });
return;
}
seenChained = true;
if (typeof row.chain_note === "string") {
check2.gaps.push(`row ${number} declares a gap: ${row.chain_note}`);
if (typeof row.prev_hash === "string" && !matchesAcrossGaps(entries, row.prev_hash)) {
check2.gaps.push(`row ${number} does not follow the row before it, so a row may be lost`);
}
gapRows.push(number);
entries.push({ hash, gap: true });
return;
}
if (!matchesAcrossGaps(entries, row.prev_hash)) {
const repair = repaired.get(number);
if (repair !== void 0 && repair.hash === hash) {
check2.gaps.push(`row ${number} broke the chain and was repaired: ${repair.reason}`);
} else {
check2.breaks.push(number);
}
}
entries.push({ hash, gap: false });
});
if (gapRows.length > 0) {
check2.blind_spot = `the chain does not vouch for rows beside a gap, so a row lost next to row${gapRows.length === 1 ? "" : "s"} ${gapRows.join(", ")} would not show`;
}
return check2;
}
function firstChainBreakLine(check2) {
return check2.breaks.length === 0 ? null : `chain broken at row ${check2.breaks[0]}`;
}
// src/verification/repository/bundle-completeness-gate.ts
import { readFileSync as readFileSync49 } from "fs";
import { join as join107 } from "path";
function readFileSafe(projectRoot, rel) {
try {
return readFileSync49(join107(projectRoot, rel), "utf8");
} catch {
return null;
}
}
var GATE_NAME2 = "bundle-completeness";
var RECOVERABLE = /* @__PURE__ */ new Set(["ruleRun", "duplication", "changeMetrics"]);
var LOCAL_ORIGINS = /* @__PURE__ */ new Set(["hook-completion", "git-backstop"]);
function readBundleFile(projectRoot, dirName, entry) {
const rel = entry.key === "report" ? featureReportPath(dirName) : featureFilePath(dirName, entry.key);
return readFileSafe(projectRoot, rel);
}
function backfill(entry, input) {
const { projectRoot, sessionId } = input;
if (entry.key === "ruleRun") {
let minted = false;
const report = readReport(projectRoot);
if (report) {
appendRuleRun(projectRoot, sessionId, {
kind: "findings",
counts: report.counts,
blocking: report.blocking,
findings: ruleRunFindings(report),
backfilled: true
});
minted = true;
}
const drift = readDrift(projectRoot);
if (drift) {
appendRuleRun(projectRoot, sessionId, {
kind: "drift",
counts: drift.counts,
blocking: drift.blocked,
backfilled: true
});
minted = true;
}
return minted;
}
if (entry.key === "duplication") {
const report = readDuplicationReport(projectRoot);
if (report) {
appendDuplicationRun(projectRoot, sessionId, report, void 0, true);
return true;
}
return false;
}
if (input.changeMetrics) {
appendChangeMetrics(projectRoot, sessionId, input.changeMetrics, void 0, true);
return true;
}
return false;
}
function bundleCompletenessGate(input) {
if (input.mode === "off") {
return null;
}
const { dirName, sessionId } = input;
if (!input.isFeatureDev || !dirName) {
return skipped3(
"No active feature bundle for this change \u2014 bundle-completeness check not applicable."
);
}
if (!LOCAL_ORIGINS.has(input.origin)) {
return skipped3(
`Bundle-completeness is informational on ${input.origin} \u2014 no committed local bundle to check.`
);
}
const state = {
present: [],
backfilled: [],
missing: [],
ragMissing: false,
flagSkipped: [],
laneSkipped: [],
preSwitchSkipped: [],
isolationUnverified: false,
skillLines: [],
splitNote: "",
chainNote: ""
};
try {
for (const entry of BUNDLE_MANIFEST) {
if (entry.required === "optional") {
const content = readBundleFile(input.projectRoot, dirName, entry);
if (validateBundleFileContent(entry.validate, content)) {
if (!recordHashMismatch(entry, content, state)) state.present.push(entry.file);
}
continue;
}
if (!isBundleFileRequired(entry, input.config)) {
const unlocked = {
...input.config,
lane: "full",
specFrozenBeforePipeline: false
};
if (!isBundleFileRequired(entry, unlocked)) {
state.flagSkipped.push(entry.file);
} else if (input.config.lane === "fast") {
state.laneSkipped.push(entry.file);
} else {
state.preSwitchSkipped.push(entry.file);
}
continue;
}
assertRequired(entry, input, dirName, sessionId, state);
}
assertStageAgentRows(input, dirName, state);
assertRecipeProof(input, dirName, state);
assertSkillRecords(input, dirName, state);
assertAgentRecords(input, dirName, state);
assertNotSplit(input, dirName, state);
assertLedgerChain(input, dirName, state);
} catch {
}
return decide2(input.mode, state);
}
function recheckAfterReceiptSeal(gate, input, sealed) {
if (sealed || gate === null || input.receiptPending !== true) {
return gate;
}
return bundleCompletenessGate({ ...input, receiptPending: false });
}
var THINKING_STAGES = /* @__PURE__ */ new Set(["planning", "specification", "review"]);
function holdsRecordedWork(rows, sessionId) {
return rows.some(
(row) => (sessionId === void 0 || row.session_id === sessionId) && (row.stage === "development" || row.kind === "stage_end" && typeof row.stage === "string" && THINKING_STAGES.has(row.stage) && typeof row.artifact_digest === "string")
);
}
function assertNotSplit(input, dirName, state) {
if (holdsRecordedWork(readFeatureStageUnit(input.projectRoot, dirName))) return;
const others = listInFlightFeatures(input.projectRoot).filter(
(other) => other !== dirName && holdsRecordedWork(readFeatureStageUnit(input.projectRoot, other), input.sessionId)
);
if (others.length === 0) return;
state.splitNote = ` This session also has unfinished work in ${others.join(", ")}, which this check did not judge, so ${dirName} may hold only part of the change. Go back to that work with \`paqad-ai resume --feature ${others[0]}\`.`;
}
function assertLedgerChain(input, dirName, state) {
const raw = readFileSafe(input.projectRoot, featureFilePath(dirName, "stageEvidence"));
if (raw === null) return;
const check2 = checkStageChain(raw);
const breakLine = firstChainBreakLine(check2);
const era = bundleLedgerEra(readFeatureStageUnit(input.projectRoot, dirName));
const warnings = [...check2.gaps, ...check2.blind_spot === null ? [] : [check2.blind_spot]];
if (breakLine !== null && era === "v3") {
state.skillLines.push(`${breakLine}: a row was removed, reordered or edited.`);
state.missing.push({
file: "stage-evidence.jsonl",
writer: `paqad-ai stage repair ${check2.breaks[0]} --reason "<what happened>"`
});
} else if (breakLine !== null) {
warnings.push(`${breakLine} in a ledger from before the chain`);
}
if (warnings.length > 0) state.chainNote += ` Ledger note: ${warnings.join("; ")}.`;
}
function assertSkillRecords(input, dirName, state) {
if (!input.changedFiles || input.changedFiles.length === 0) return;
for (const finding of skillCompletionFindings({
projectRoot: input.projectRoot,
dirName,
changedFiles: input.changedFiles
})) {
state.missing.push({ file: skillRecordFilename(finding.skill), writer: SKILL_RECORD_WRITER });
state.skillLines.push(finding.line);
}
}
function assertAgentRecords(input, dirName, state) {
if (!input.changedFiles || input.changedFiles.length === 0) return;
for (const finding of agentCompletionFindings({
projectRoot: input.projectRoot,
dirName,
changedFiles: input.changedFiles
})) {
const file = agentRecordFilename(finding.agent);
if (!state.missing.some((entry) => entry.file === file)) {
state.missing.push({ file, writer: AGENT_RECORD_WRITER });
}
if (!state.skillLines.includes(finding.line)) state.skillLines.push(finding.line);
}
}
function assertStageAgentRows(input, dirName, state) {
const since = input.config.stageIsolationSince;
if (since === void 0 ? hasStageAgentEvidence(input.projectRoot, dirName) : hasStageAgentEvidenceSince(input.projectRoot, dirName, since)) {
return;
}
if (input.config.stageIsolationExpected) {
state.missing.push({
file: "stage-agent rows in stage-evidence.jsonl",
writer: "dispatch each stage to its paqad-<stage> agent; the SubagentStop hook records it"
});
return;
}
if (input.config.stageIsolationUnresolved) {
state.isolationUnverified = true;
}
}
function stageAgentRan(rows, stage) {
return rows.some(
(row) => row.kind === STAGE_AGENT_KIND && row.event_status === "completed" && (row.stage === stage || Array.isArray(row.stages) && row.stages.includes(stage))
);
}
function hasRowOf(rows, kind, stage) {
return rows.some((row) => row.kind === kind && row.stage === stage);
}
function codexChecksProven(rows) {
return rows.some(
(row) => row.kind === "stage_end" && row.stage === "checks" && typeof row.artifact_digest === "string"
);
}
function missingProof(rows, stage, codex) {
if (!stageAgentRan(rows, stage)) return "a stage-agent completed row";
if (codex && stage === "checks") {
return codexChecksProven(rows) ? null : "an end row with the digest of checks.json";
}
if (!codex && !hasRowOf(rows, RECIPE_INJECTED_KIND, stage)) return "a recipe-injected row";
if (recipeHasScript(stage) && !hasRowOf(rows, SKILL_USED_KIND, stage)) return "a skill-used row";
return null;
}
function startedBeforeLaneRaise(rows, stage, raisedAt) {
if (Number.isNaN(raisedAt)) return false;
const started = rows.filter((row) => row.kind === "stage_start" && row.stage === stage).at(-1);
const at2 = Date.parse(String(started?.recorded_at ?? ""));
return !Number.isNaN(at2) && at2 < raisedAt;
}
var SKILL_USED_WRITER = {
planning: "paqad-ai plan compile",
specification: "paqad-ai spec freeze",
review: "paqad-ai review record"
};
function recipeProofWriter(stage) {
const end = `paqad-ai stage end ${stage}`;
const writer = SKILL_USED_WRITER[stage];
const finish = writer ? `${writer}, then ${end}` : end;
return `if the recipe is missing from this install, ${recipeRepairAdvice()}. Then dispatch the paqad-${stage.replace(/_/g, "-")} agent, which runs ${finish}`;
}
function assertRecipeProof(input, dirName, state) {
if (!input.config.stageIsolationExpected || input.config.lane !== "full") return;
const rows = readFeatureStageUnit(input.projectRoot, dirName);
const record2 = readFeatureRecord(input.projectRoot, dirName);
const codex = record2?.adapter === "codex-cli";
const raised = record2?.lane_raised;
const raisedAt = raised?.to === "full" ? Date.parse(raised.at) : Number.NaN;
const older = [];
for (const stage of STAGE_AGENT_STAGES) {
if (!hasRowOf(rows, "stage_start", stage)) continue;
if (startedBeforeLaneRaise(rows, stage, raisedAt)) continue;
if (stageLedgerEra(rows, stage) !== "v3") {
older.push(stage);
continue;
}
const missing = missingProof(rows, stage, codex);
if (missing === null) continue;
state.skillLines.push(
`The ${stage} stage has no proof its recipe was used: ${missing} is missing.`
);
state.missing.push({
file: `recipe proof for ${stage}`,
writer: recipeProofWriter(stage)
});
}
if (older.length > 0) {
state.chainNote += ` These stages ran before the update and hold no recipe proof: ${older.join(", ")}.`;
}
}
function assertRequired(entry, input, dirName, sessionId, state) {
const content = readBundleFile(input.projectRoot, dirName, entry);
if (validateBundleFileContent(entry.validate, content)) {
if (entry.key === "feature") {
const record2 = readFeatureRecord(input.projectRoot, dirName);
if (record2 && featureRecordIsUntitled(record2)) {
state.missing.push({
file: `${entry.file} (no title and no ticket)`,
writer: 'paqad-ai feature title "<what this change builds>" (titles this bundle in place)'
});
return;
}
}
if (entry.key === "specMd" && !specSourceMatches(input.projectRoot, dirName, content)) {
state.missing.push({
file: `${entry.file} (its body does not hash to specification.json spec_hash)`,
writer: "paqad-ai spec freeze (re-freeze the spec)"
});
return;
}
if (entry.key === "specification") {
if (specPipelineStrictApplies(input.config)) {
const adoption = validateSpecificationAdoption(content);
if (!adoption.ok) {
state.missing.push({
file: adoption.error,
writer: "paqad-ai spec freeze --from-pipeline (or --manual --reason)"
});
return;
}
}
}
if (recordHashMismatch(entry, content, state)) return;
state.present.push(entry.file);
return;
}
if (entry.key === "specMd" && legacySpecProjectionPresent(input.projectRoot, dirName)) {
state.present.push(entry.file);
return;
}
if (entry.key === "evidence" && input.evidenceRowsPending) {
state.present.push(entry.file);
return;
}
if ((entry.key === "receipt" || entry.key === "aiBom") && input.receiptPending) {
state.present.push(entry.file);
return;
}
if (entry.unrecoverable) {
const chat = readFileSafe(input.projectRoot, chatRagPath(sessionId));
if (validateBundleFileContent(entry.validate, chat)) {
state.present.push(entry.file);
} else {
state.ragMissing = true;
}
return;
}
if (RECOVERABLE.has(entry.key) && backfill(entry, input)) {
state.backfilled.push(entry.file);
return;
}
const refreeze = PIPELINE_FILE_KEYS.has(entry.key) && isSpecFrozenOnFastLane(readSpecificationRecord(input.projectRoot, dirName));
state.missing.push({
file: entry.file,
writer: refreeze ? FAST_LANE_REFREEZE_HINT : entry.writer
});
}
var PIPELINE_FILE_KEYS = /* @__PURE__ */ new Set([
"request",
"clarification",
"experts"
]);
function contentHashMismatch(entry, content) {
if (entry.key === "report") return null;
if (entry.validate === "nonempty") {
return textHashMatches(content) === false ? "its body" : null;
}
if (entry.validate === "json") {
return documentHashMatches(JSON.parse(content)) === false ? "the document" : null;
}
const lines = content.split("\n");
for (let index = 0; index < lines.length; index++) {
const line = lines[index].trim();
if (line.length === 0) continue;
let row;
try {
row = JSON.parse(line);
} catch {
continue;
}
if (rowHashMatches(row) === false) return `line ${index + 1}`;
}
return null;
}
function recordHashMismatch(entry, content, state) {
const where = contentHashMismatch(entry, content);
if (where === null) return false;
state.missing.push({
file: `${entry.file} (content_hash mismatch at ${where}: changed outside its writer)`,
writer: entry.writer
});
return true;
}
function readSpecificationRecord(projectRoot, dirName) {
const text2 = readFileSafe(projectRoot, featureFilePath(dirName, "specification"));
if (text2 === null) return null;
try {
const parsed = JSON.parse(text2);
return typeof parsed === "object" && parsed !== null ? parsed : null;
} catch {
return null;
}
}
function specSourceMatches(projectRoot, dirName, specMd) {
const record2 = readSpecificationRecord(projectRoot, dirName);
if (typeof record2?.spec_hash !== "string") return true;
return sha256Hex(splitFrontMatter(specMd).body) === record2.spec_hash;
}
function legacySpecProjectionPresent(projectRoot, dirName) {
const record2 = readSpecificationRecord(projectRoot, dirName);
if (typeof record2?.spec_file !== "string" || record2.spec_file === FEATURE_BUNDLE_FILES.specMd) {
return false;
}
const md = readFileSafe(projectRoot, featureLegacySpecMarkdownPath(dirName));
return md !== null && md.trim().length > 0;
}
function decide2(mode, state) {
const skipNote = (state.flagSkipped.length > 0 ? ` Skipped (flag off): ${[...state.flagSkipped].sort().join(", ")}.` : "") + (state.laneSkipped.length > 0 ? ` Not required on the fast lane: ${[...state.laneSkipped].sort().join(", ")}.` : "") + (state.preSwitchSkipped.length > 0 ? ` Spec frozen before the spec pipeline was on, so not required: ${[...state.preSwitchSkipped].sort().join(", ")}.` : "");
const backfillNote = state.backfilled.length > 0 ? ` Backfilled (live write missed): ${state.backfilled.join(", ")}.` : "";
if (state.missing.length > 0) {
const named = state.missing.map((m) => `${m.file} (run: ${m.writer})`).join("; ");
const skillNote = state.skillLines.length > 0 ? `${state.skillLines.join(" ")} ` : "";
const detail = `${skillNote}The feature bundle is incomplete \u2014 missing/invalid: ${named}.${backfillNote}${state.splitNote}${skipNote}${state.chainNote}`;
const remediation = `Produce the missing bundle file(s): ${named}.`;
if (mode === "strict") {
return { name: GATE_NAME2, status: "fail", detail, remediation, failures: [] };
}
return { name: GATE_NAME2, status: "inconclusive", detail, remediation, failures: [] };
}
if (state.backfilled.length > 0 || state.ragMissing || state.isolationUnverified || state.splitNote) {
const ragNote = state.ragMissing ? " rag.jsonl is absent (no bundle or _chat retrieval row); RAG evidence is unrecoverable." : "";
const isolationNote = state.isolationUnverified ? " Not classified \u2014 isolation not verified: this change never resolved a lane, so paqad could not confirm its stages ran isolated. Set the real lane with `paqad-ai lane set <lane>` (isolation is checked on the lanes in stage_isolation_lanes)." : "";
const lead = state.splitNote ? "Bundle present but the change may be split." : "Bundle present but not fully live-recorded.";
return {
name: GATE_NAME2,
status: "inconclusive",
detail: `${lead}${backfillNote}${ragNote}${isolationNote}${state.splitNote}${skipNote}${state.chainNote}`,
remediation: null,
failures: []
};
}
return {
name: GATE_NAME2,
status: "pass",
detail: `Every required bundle file is present for this feature (${state.present.length} checked).${skipNote}${state.chainNote}`,
remediation: null,
failures: []
};
}
function skipped3(detail) {
return {
name: GATE_NAME2,
status: "skipped",
detail,
remediation: null,
failures: [],
skip_kind: "not-required"
};
}
// src/verification/repository/rules-loaded-gate.ts
init_esm_shims();
var GATE_NAME3 = "rules-loaded";
async function rulesLoadedGate(input, deps = {}) {
const resolveApplicability = deps.resolveApplicability ?? resolveRuleApplicabilityForChange;
const readRecord = deps.readRecord ?? readRulesLoaded;
if (!input.isFeatureDev || !input.dirName) {
return null;
}
const applicability = await resolveApplicability(input.projectRoot, input.sessionId ?? null, {
dirName: input.dirName
});
if (!applicability.hasStore || applicability.applicable.length === 0) {
return {
name: GATE_NAME3,
status: "skipped",
detail: applicability.hasStore ? "No project rule applies to the files in this change \u2014 nothing to load." : "No compiled rules for this project \u2014 nothing to load.",
remediation: null,
failures: [],
skip_kind: "not-required"
};
}
const record2 = readRecord(input.projectRoot, input.dirName);
if (!record2 && input.origin === "ci-backstop") {
return {
name: GATE_NAME3,
status: "skipped",
detail: "No session loads rules on CI, so the load was not required here.",
remediation: null,
failures: [],
skip_kind: "not-required"
};
}
if (!record2) {
return {
name: GATE_NAME3,
status: "fail",
detail: `The rules were never loaded for this change \u2014 ${applicability.applicable.length} project rule${applicability.applicable.length === 1 ? "" : "s"} apply to the files you changed and there is no record they were loaded.`,
remediation: "Run `paqad-ai rules load` to load the applicable rules and record it.",
failures: []
};
}
const gaps = coverageGaps(
record2,
applicability.applicable.map((rule) => rule.rule_id)
);
if (gaps.length > 0) {
return {
name: GATE_NAME3,
status: "inconclusive",
detail: `Rules were loaded, but ${gaps.length} rule${gaps.length === 1 ? "" : "s"} became applicable since (${gaps.join(", ")}) \u2014 the load no longer covers the whole change.`,
remediation: "Re-run `paqad-ai rules load` to load the newly applicable rules.",
failures: []
};
}
return {
name: GATE_NAME3,
status: "pass",
detail: `Rules loaded and acknowledged for this change (${record2.applicable_rules.length} applicable).`,
remediation: null,
failures: []
};
}
// src/verification/repository/fix-proof-gate.ts
init_esm_shims();
// src/fix-protocol/fix-change.ts
init_esm_shims();
import { execFileSync as execFileSync10 } from "child_process";
import { readFileSync as readFileSync50 } from "fs";
import { join as join108 } from "path";
// src/fix-protocol/affects-behaviour.ts
init_esm_shims();
var NON_BEHAVIOURAL_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".mdx", ".markdown", ".txt", ".rst", ".adoc"]);
var LINE_COMMENT_MARKERS = {
".ts": ["//"],
".tsx": ["//"],
".js": ["//"],
".jsx": ["//"],
".mjs": ["//"],
".cjs": ["//"],
".go": ["//"],
".java": ["//"],
".rs": ["//"],
".c": ["//"],
".h": ["//"],
".cpp": ["//"],
".cs": ["//"],
".py": ["#"],
".rb": ["#"],
".sh": ["#"],
".yaml": ["#"],
".yml": ["#"]
};
function extensionOf2(path10) {
const dot = path10.lastIndexOf(".");
const slash = Math.max(path10.lastIndexOf("/"), path10.lastIndexOf("\\"));
if (dot <= slash) {
return "";
}
return path10.slice(dot).toLowerCase();
}
function lineIsNonBehavioural(line, extension) {
const trimmed = line.trim();
if (trimmed.length === 0) {
return true;
}
const markers = LINE_COMMENT_MARKERS[extension];
if (markers === void 0) {
return false;
}
if (markers.some((marker) => trimmed.startsWith(marker))) {
return true;
}
if (markers.includes("//")) {
if (trimmed.startsWith("/*") || trimmed.startsWith("*/") || trimmed.startsWith("*")) {
return true;
}
}
return false;
}
function fileChangeIsNonBehavioural(file) {
const extension = extensionOf2(file.path);
if (NON_BEHAVIOURAL_EXTENSIONS.has(extension)) {
return true;
}
const changedLines = [...file.added_lines, ...file.removed_lines];
if (changedLines.length === 0) {
return false;
}
return changedLines.every((line) => lineIsNonBehavioural(line, extension));
}
function affectsBehaviour(change) {
if (change.files.length === 0) {
return {
affects: true,
reason: "No changed files were provided; defaulting to behaviour-affecting.",
behavioural_evidence: []
};
}
const behaviouralEvidence = [];
for (const file of change.files) {
if (!fileChangeIsNonBehavioural(file)) {
const extension = extensionOf2(file.path);
const sample = [...file.added_lines, ...file.removed_lines].find(
(line) => !lineIsNonBehavioural(line, extension)
);
behaviouralEvidence.push(sample ? `${file.path}: ${sample.trim()}` : file.path);
}
}
if (behaviouralEvidence.length === 0) {
return {
affects: false,
reason: "All changes are comments, blank lines, or documentation; cannot affect behaviour.",
behavioural_evidence: []
};
}
return {
affects: true,
reason: "At least one change can affect behaviour.",
behavioural_evidence: behaviouralEvidence
};
}
// src/fix-protocol/fix-change.ts
function gitOutput(projectRoot, args) {
try {
return execFileSync10("git", args, {
cwd: projectRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
maxBuffer: 64 * 1024 * 1024
});
} catch {
return null;
}
}
function stripPrefix(path10) {
return path10.replace(/^[ab]\//, "").replace(/\\/g, "/");
}
function parseChangedLines(diffText) {
const byFile = /* @__PURE__ */ new Map();
let fromPath = null;
let current = null;
let inHunk = false;
const fileFor = (path10) => {
const existing = byFile.get(path10);
if (existing) return existing;
const created = { path: path10, added_lines: [], removed_lines: [] };
byFile.set(path10, created);
return created;
};
for (const line of diffText.split("\n")) {
if (line.startsWith("diff --git ")) {
inHunk = false;
current = null;
fromPath = null;
continue;
}
if (!inHunk && line.startsWith("--- ")) {
const source = line.slice(4).trim();
fromPath = source === "/dev/null" ? null : stripPrefix(source);
continue;
}
if (!inHunk && line.startsWith("+++ ")) {
const target = line.slice(4).trim();
const path10 = target === "/dev/null" ? fromPath : stripPrefix(target);
current = path10 === null ? null : fileFor(path10);
continue;
}
if (line.startsWith("@@")) {
inHunk = current !== null;
continue;
}
if (!inHunk || current === null) continue;
if (line.startsWith("+")) current.added_lines.push(line.slice(1));
else if (line.startsWith("-")) current.removed_lines.push(line.slice(1));
}
return [...byFile.values()];
}
function isBehaviourCandidate(path10) {
return !isTestFile(path10) && !isDocumentationFile(path10) && !isPaqadArtifactPath(path10);
}
function untrackedFiles(projectRoot, runGit2) {
const listed = runGit2(projectRoot, ["ls-files", "--others", "--exclude-standard"]);
if (listed === null) return [];
return listed.split("\n").map((path10) => path10.trim()).filter((path10) => path10.length > 0).flatMap((path10) => {
try {
const content = readFileSync50(join108(projectRoot, path10), "utf8");
return [{ path: path10, added_lines: content.split("\n"), removed_lines: [] }];
} catch {
return [];
}
});
}
function readChangeDiff(projectRoot, runGit2 = gitOutput) {
const state = readGitState(projectRoot);
if (!state.head_commit) return null;
const base = state.base_commit ?? "HEAD";
const diff = runGit2(projectRoot, [...PINNED_DIFF_ARGS, "--unified=0", base]);
if (diff === null) return null;
const tracked = parseChangedLines(diff);
const seen = new Set(tracked.map((file) => file.path));
const untracked = untrackedFiles(projectRoot, runGit2).filter((file) => !seen.has(file.path));
return { files: [...tracked, ...untracked] };
}
function behaviourChangeOf(change) {
return { files: change.files.filter((file) => isBehaviourCandidate(file.path)) };
}
function changeAffectsBehaviour(change) {
const candidates = behaviourChangeOf(change);
if (candidates.files.length === 0) {
return {
affects: false,
reason: "The change touches only tests, docs or paqad records.",
behavioural_evidence: []
};
}
return affectsBehaviour(candidates);
}
// src/verification/repository/fix-proof-gate.ts
var FIX_PROOF_GATE = "fix-proof";
var MISSING_STEP = {
none: "Run `paqad-ai fix prove red` before the fix, then `paqad-ai fix prove green` after it.",
red: "Run `paqad-ai fix prove green` now that the fix is in.",
"green-only": "Show the test failing first: undo the fix, run `paqad-ai fix prove red`, restore it, then `paqad-ai fix prove green`.",
"not-reproduced": "Write a test that fails on the old code, run `paqad-ai fix prove red`, then `paqad-ai fix prove green` after the fix.",
held: "Fix the check the change broke, then run `paqad-ai fix prove green` again."
};
function summarizeFixProof(input, deps = {}) {
if (!input.isFeatureDev || !input.dirName) return null;
if (readFeatureRecord(input.projectRoot, input.dirName)?.kind !== "fix") return null;
const state = foldFixProofState(readFixProofRows(input.projectRoot, input.dirName));
const diff = (deps.readDiff ?? readChangeDiff)(input.projectRoot);
if (diff === null) {
return { required: true, state, reason: "The change could not be read, so proof is needed." };
}
const verdict2 = changeAffectsBehaviour(diff);
return { required: verdict2.affects, state, reason: verdict2.reason };
}
function evaluateFixProof(input, deps = {}) {
const summary = summarizeFixProof(input, deps);
return { gate: fixProofGate(input, summary), summary };
}
function fixProofGate(input, summary) {
if (!input.isFeatureDev || !input.dirName) return null;
if (summary === null || !summary.required) {
return {
name: FIX_PROOF_GATE,
status: "skipped",
detail: summary === null ? "This change is not a fix, so no fix proof is needed." : `This fix cannot change behaviour, so no proof is needed. ${summary.reason}`,
remediation: null,
failures: [],
skip_kind: "not-required"
};
}
if (summary.state === "red-green") {
return {
name: FIX_PROOF_GATE,
status: "pass",
detail: `Fix proof: ${FIX_PROOF_STATE_LABEL["red-green"]}.`,
remediation: null,
failures: []
};
}
return {
name: FIX_PROOF_GATE,
status: "inconclusive",
detail: `Fix proof did not run to the end: ${FIX_PROOF_STATE_LABEL[summary.state]}.`,
remediation: MISSING_STEP[summary.state],
failures: [],
skip_kind: "did-not-run"
};
}
// src/verification/gates/visual-evidence.ts
init_esm_shims();
import { createHash as createHash15 } from "crypto";
import { readFileSync as readFileSync51 } from "fs";
import { join as join109 } from "path";
var GATE_NAME4 = "visual-evidence";
var DOCUMENTED_SKIP_REASONS = /* @__PURE__ */ new Set([
"no-documented-flow",
"no-capture-script",
"capture-script-invalid"
]);
var LOCAL_ORIGINS2 = /* @__PURE__ */ new Set(["hook-completion", "git-backstop"]);
function skipped4(detail, skipReason, kind = "not-required") {
return {
name: GATE_NAME4,
status: "skipped",
detail,
remediation: null,
failures: [],
skip_reason: skipReason,
skip_kind: kind
};
}
var STRICT_UNCAPTURED = /* @__PURE__ */ new Set([
"no-documented-flow",
"no-capture-script"
]);
var DOCUMENTED_SKIP_PHRASE = {
"no-documented-flow": "no documented flow to capture",
"no-capture-script": "no capture script",
"capture-script-invalid": "capture script invalid"
};
function environmental(mode, detail, remediation) {
return {
name: GATE_NAME4,
status: mode === "strict" ? "fail" : "inconclusive",
detail,
remediation,
failures: []
};
}
function pass2(detail) {
return { name: GATE_NAME4, status: "pass", detail, remediation: null, failures: [] };
}
function readManifest2(projectRoot, dirName) {
try {
const raw = readFileSync51(join109(projectRoot, featureFilePath(dirName, "visualEvidence")), "utf8");
return JSON.parse(raw);
} catch {
return null;
}
}
function fileMatches(absPath, expectedBytes, expectedSha) {
try {
const bytes = readFileSync51(absPath);
if (bytes.length !== expectedBytes) return false;
return createHash15("sha256").update(bytes).digest("hex") === expectedSha;
} catch {
return false;
}
}
function integrityFailures(projectRoot, dirName, manifest) {
const bundleAbs = join109(projectRoot, ".paqad", "ledger", "feature-evidence", dirName);
const failures = [];
for (const step of manifest.steps) {
if (step.status !== "captured") continue;
if (step.image_sha256 === void 0 || step.image_bytes === void 0) {
failures.push(`${step.dir}/image.png has no recorded hash`);
continue;
}
const imageAbs = join109(bundleAbs, step.dir, "image.png");
if (!fileMatches(imageAbs, step.image_bytes, step.image_sha256)) {
failures.push(`${step.dir}/image.png size/hash mismatch`);
}
}
if (manifest.gif) {
const gifAbs = join109(bundleAbs, manifest.gif.file);
if (!fileMatches(gifAbs, manifest.gif.bytes, manifest.gif.sha256)) {
failures.push("overview.gif size/hash mismatch");
}
}
return failures;
}
function visualEvidenceGate(input) {
const { projectRoot, dirName, mode, origin, isFeatureDev, flagOn, frontendTriggered } = input;
const { packRegistryFault } = input;
if (!isFeatureDev || !dirName) {
return null;
}
if (!flagOn) {
return skipped4(
"visual evidence is off (flag off or coding capability absent).",
"visual evidence is off"
);
}
if (!LOCAL_ORIGINS2.has(origin)) {
return skipped4(
`visual evidence is informational on ${origin} \u2014 no committed local bundle.`,
`informational on ${origin}`
);
}
if (packRegistryFault) {
return environmental(
mode,
packRegistryFaultDetail(packRegistryFault.runtimeRoot),
PACK_REGISTRY_FAULT_REMEDIATION
);
}
if (!frontendTriggered) {
return skipped4("not-frontend \u2014 no changed file matched a frontend surface.", "not-frontend");
}
const manifest = readManifest2(projectRoot, dirName);
if (!manifest) {
return environmental(
mode,
"a frontend change was made but no visual-evidence.json was captured.",
"run `paqad-ai visual-evidence run` (check the app is reachable and the browser is provisioned)."
);
}
if (validateVisualEvidenceRecord(manifest).length > 0) {
return environmental(
mode,
"visual-evidence.json is present but does not match its schema.",
"re-run `paqad-ai visual-evidence run` to regenerate a valid manifest."
);
}
if (manifest.result === "skipped") {
const documented = manifest.skips.every((s) => DOCUMENTED_SKIP_REASONS.has(s.reason));
const reasons = manifest.skips.map((s) => s.reason).join(", ") || "no capture";
if (documented && manifest.skips.length > 0) {
const phrases = [...new Set(manifest.skips.map((s) => DOCUMENTED_SKIP_PHRASE[s.reason]))];
if (mode === "strict" && manifest.skips.every((s) => STRICT_UNCAPTURED.has(s.reason))) {
const waiver = findVisualEvidenceWaiver(projectRoot, dirName);
if (waiver) {
return skipped4(`waived by ${waiver} (${reasons}).`, `waived by ${waiver}`);
}
return environmental(
mode,
`visual evidence is strict, but nothing was captured for this frontend change (${reasons}).`,
`attach screenshots with \`paqad-ai visual-evidence attach <png...>\`, add a capture script for a documented journey and re-run \`paqad-ai visual-evidence run\`, or record a waiver: ${visualEvidenceWaiverHint(projectRoot, dirName)}.`
);
}
const kind = manifest.skips.every((s) => s.reason === "no-documented-flow") ? "not-required" : "did-not-run";
return skipped4(`no visual evidence to capture (${reasons}).`, phrases.join(", "), kind);
}
return environmental(
mode,
`visual evidence could not be captured (${reasons}).`,
"resolve the environmental issue (browser/app/selectors) and re-run `paqad-ai visual-evidence run`."
);
}
if (manifest.result === "partial") {
const failed = manifest.steps.filter((s) => s.status === "failed").length;
return environmental(
mode,
`visual evidence is partial \u2014 ${failed} step(s) failed (selector-not-found).`,
"fix the failing selector(s) in the capture script and re-run `paqad-ai visual-evidence run`."
);
}
const failures = integrityFailures(projectRoot, dirName, manifest);
if (failures.length > 0) {
return environmental(
mode,
`visual-evidence.json references files that do not match: ${failures.join("; ")}.`,
"re-run `paqad-ai visual-evidence run` to regenerate the screenshots."
);
}
const captured = manifest.steps.filter((s) => s.status === "captured");
const attached = captured.filter((s) => s.journey_id === AGENT_ATTACHED_JOURNEY).length;
const attachedNote = attached > 0 ? ` ${attached} of them agent-attached (not scripted captures).` : "";
const detail = `${captured.length} step(s) captured across ${manifest.plan.length} flow(s); hashes verified.${attachedNote}${visualAcNote(projectRoot, dirName)}`;
return pass2(detail);
}
function visualAcNote(projectRoot, dirName) {
try {
const raw = readFileSync51(join109(projectRoot, featureFilePath(dirName, "specification")), "utf8");
const spec = JSON.parse(raw);
const visual = (spec.acceptance_criteria ?? []).filter((ac) => ac.proof_type === "visual").map((ac) => ac.criterion_id ?? ac.id).filter((id) => typeof id === "string");
return visual.length > 0 ? ` Visually evidenced: ${visual.join(", ")}.` : "";
} catch {
return "";
}
}
// src/verification/gates/duplication.ts
init_esm_shims();
var DuplicationGate = class {
gate = "duplication";
async check(context) {
const report = readDuplicationReport(context.project_root);
if (!report) {
return createNotRequired(
this.gate,
"Not required: no duplication scan ran for this change, so there was nothing to check."
);
}
const total = report.findings.length;
if (report.blocking) {
const lead = firstFindingLead(report.findings);
return createFail(
this.gate,
`${count(report.counts.deterministic, "near-copy", "near-copies")} of existing code introduced by this change${lead}.`,
"Reuse or extend the existing code, or record a create-vs-reuse decision to accept the new copy (the resolved packet unblocks completion)."
);
}
if (total === 0) {
return createPass(this.gate, "No new code near-copies existing code.");
}
return createPass(
this.gate,
`${count(total, "near-copy", "near-copies")} flagged (${report.mode} mode, not blocking).`
);
}
};
function firstFindingLead(findings) {
const first = findings.find((finding) => finding.kind === "deterministic");
return first ? ` \u2014 ${first.file} near ${first.matched_symbol ?? first.matched_file}` : "";
}
function count(n, singular, plural2) {
return `${n} ${n === 1 ? singular : plural2}`;
}
// src/verification/repository/cloud-continuation.ts
init_esm_shims();
import { execFileSync as execFileSync11 } from "child_process";
var CLOUD_CONTINUATION_NOTE = "Evidence starts in this cloud session; earlier steps were recorded on another machine.";
function defaultGitCount(projectRoot, range) {
try {
const out = execFileSync11("git", ["rev-list", "--count", range], {
cwd: projectRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"]
});
const count2 = Number(out.trim());
return Number.isInteger(count2) ? count2 : null;
} catch {
return null;
}
}
function cloudContinuationNote(projectRoot, dirName, sessionId, env2 = process.env, gitCount = defaultGitCount) {
if (env2.CLAUDE_CODE_REMOTE?.trim().toLowerCase() !== "true") return null;
if (!dirName || !sessionId) return null;
const feature = readFeatureRecord(projectRoot, dirName);
if (!feature || feature.session_id !== sessionId) return null;
const delivery = readFeatureDelivery(projectRoot, dirName);
const start = delivery.start_commit;
const base = delivery.base_branch ?? feature.base_branch;
if (!start || !base) return null;
const count2 = gitCount(projectRoot, `${base}..${start}`) ?? gitCount(projectRoot, `origin/${base}..${start}`);
return count2 !== null && count2 > 0 ? CLOUD_CONTINUATION_NOTE : null;
}
// src/verification/repository/receipt.ts
init_esm_shims();
function stageLabel(stage) {
return stage.replace(/_/g, " ");
}
function stageStatus(stage) {
switch (stage.state) {
case "complete":
case "redone": {
if (stage.duration_unreliable) {
return {
glyph: PAQAD_STATUS_GLYPH.needsLook,
note: "marked (near-zero duration \u2014 no recorded work)"
};
}
const base = stage.evidence_source === "inferred-git" ? "done (inferred from the diff)" : stage.evidence_source === "inferred-artifact" ? "done (inferred from an artifact)" : "done";
return {
glyph: PAQAD_STATUS_GLYPH.good,
note: stage.state === "redone" ? `${base} (redone)` : base
};
}
case "inconclusive":
return { glyph: PAQAD_STATUS_GLYPH.needsLook, note: "marked (no recorded work)" };
case "failed":
return { glyph: PAQAD_STATUS_GLYPH.failed, note: "failed" };
case "running":
return { glyph: PAQAD_STATUS_GLYPH.needsLook, note: "started, not finished" };
case "skipped":
return { glyph: PAQAD_STATUS_GLYPH.skipped, note: "skipped" };
case "not-applicable":
return { glyph: PAQAD_STATUS_GLYPH.skipped, note: "not applicable" };
default:
return { glyph: PAQAD_STATUS_GLYPH.needsLook, note: "not recorded" };
}
}
function applyChecksHonesty(stage, status, checksVerified) {
if (stage.stage !== "checks" || checksVerified !== false) {
return status;
}
if (status.glyph !== PAQAD_STATUS_GLYPH.good) {
return status;
}
return {
glyph: PAQAD_STATUS_GLYPH.needsLook,
note: "marked \u2014 tests not verified (run `paqad-ai checks run`)"
};
}
function unrecordedMandatoryStages(fold, checksVerified) {
return fold.stages.filter((stage) => isMandatoryStage(stage.stage)).filter((stage) => {
const { glyph } = applyChecksHonesty(stage, stageStatus(stage), checksVerified);
return glyph === PAQAD_STATUS_GLYPH.needsLook || glyph === PAQAD_STATUS_GLYPH.failed;
}).map((stage) => stage.stage);
}
function formatStageEvidenceReceipt(fold, checksVerified, reuse) {
const rows = fold.stages.filter(
(stage) => isMandatoryStage(stage.stage) || stage.started_at !== null
);
if (rows.length === 0) {
return "";
}
return rows.map((stage) => {
const { glyph, note } = applyChecksHonesty(stage, stageStatus(stage), checksVerified);
return `> ${glyph} ${stageLabel(stage.stage)} \u2014 ${note}${reuseSuffix(stage, reuse)}`;
}).join("\n");
}
function reuseSuffix(stage, reuse) {
if (stage.stage !== "planning" || !reuse) {
return "";
}
return ` (reuse: ${reuse.reused} reused, ${reuse.newJustified} new justified)`;
}
function fixProofLine(fixProof) {
if (!fixProof.required) {
return `> ${PAQAD_STATUS_GLYPH.skipped} fix proof: not required (only tests, docs or comments changed)`;
}
const glyph = fixProof.state === "red-green" ? PAQAD_STATUS_GLYPH.good : PAQAD_STATUS_GLYPH.needsLook;
return `> ${glyph} fix proof: ${FIX_PROOF_STATE_LABEL[fixProof.state]}`;
}
function composeChangeReceipt(input) {
const parts = [input.verdictSummary];
if (input.fold) {
const stageBlock = formatStageEvidenceReceipt(
input.fold,
input.checksVerified,
input.reuse ?? null
);
if (stageBlock) {
parts.push(stageBlock);
}
}
if (input.changeMetrics) {
parts.push(formatChangeShapeLine(input.changeMetrics));
}
if (input.isolation) {
parts.push(`> ${formatStageIsolationLine(input.isolation)}`);
}
for (const note of input.stageNotes ?? []) {
parts.push(`> ${note}`);
}
if (input.techDebt && input.techDebt.length > 0) {
parts.push(
`> ${PAQAD_STATUS_GLYPH.needsLook} tech debt: ${input.techDebt.length} item(s) raised (${input.techDebt.map((item) => item.id).join(", ")})`
);
}
for (const override of input.ruleOverrides ?? []) {
parts.push(
`> ${PAQAD_STATUS_GLYPH.needsLook} rule override: ${override.rule} on ${override.file} by ${override.by} at ${override.at}`
);
}
if (input.fixProof) {
parts.push(fixProofLine(input.fixProof));
}
if (input.designSignOff) {
parts.push(`> ${input.designSignOff}`);
}
if (input.decisions) {
parts.push(`> ${input.decisions}`);
}
if (input.delivery) {
parts.push(`> ${input.delivery}`);
}
if (input.cloudNote) {
parts.push(`> ${input.cloudNote}`);
}
if (input.reportPath) {
parts.push(`> Report: ${input.reportPath}`);
}
return parts.join("\n");
}
// src/verification/repository/verdict.ts
init_esm_shims();
function buildRepositoryVerificationVerdict(input) {
const gates = input.evidence.gates.map((gate) => ({
gate: gate.name,
status: gate.status,
detail: gate.detail,
remediation: gate.remediation,
...gate.skip_reason !== void 0 ? { skip_reason: gate.skip_reason } : {},
...gate.skip_kind !== void 0 ? { skip_kind: gate.skip_kind } : {},
...gate.could_not_prove ? { could_not_prove: true } : {}
}));
const failing = gates.filter((gate) => gate.status === "fail");
const inconclusive = gates.filter((gate) => gate.status === "inconclusive");
const ok = failing.length === 0 && inconclusive.length === 0;
return {
origin: input.origin,
ok,
summary: formatVerdictSummary({
ok,
gates,
escalations: input.escalations,
...input.flagOnGates ? { flagOnGates: input.flagOnGates } : {},
...input.waitingDecisions ? { waitingDecisions: input.waitingDecisions } : {}
}),
gates,
escalations: input.escalations,
evidence_path: input.evidencePath,
started_at: input.evidence.started_at,
completed_at: input.evidence.completed_at
};
}
function formatVerdictSummary(input) {
const ran = input.gates.filter((gate) => gate.status !== "skipped");
const passed = ran.filter((gate) => gate.status === "pass" && !gate.could_not_prove).length;
const failing = ran.filter((gate) => gate.status === "fail");
const inconclusive = ran.filter((gate) => gate.status === "inconclusive");
const stageGaps = input.unrecordedMandatoryStages ?? [];
const lines = [];
const kind = verdictKindFor(input.gates, stageGaps);
if (kind === "pass") {
lines.push(paqadFrameLead(PAQAD_VERDICT.pass));
lines.push(`> ${PAQAD_STATUS_GLYPH.good} ${passed}/${ran.length} checks held for you.`);
} else if (kind === "inconclusive" && inconclusive.length === 0) {
lines.push(paqadFrameLead(PAQAD_VERDICT.inconclusive));
lines.push(`> ${PAQAD_STATUS_GLYPH.good} ${passed}/${ran.length} checks held for you.`);
lines.push(`> ${PAQAD_STATUS_GLYPH.skipped} ${unrecordedStagesGap(stageGaps).text}.`);
} else if (kind === "fail") {
lines.push(paqadFrameLead(PAQAD_VERDICT.fail));
for (const gate of failing) {
lines.push(
isRecordGap(gate) ? recordGapLine(gate) : `> ${PAQAD_STATUS_GLYPH.failed} ${gate.gate}: ${gate.detail}`
);
}
lines.push(...inconclusive.map(inconclusiveLine));
} else {
lines.push(paqadFrameLead(PAQAD_VERDICT.inconclusive));
lines.push(...inconclusive.map(inconclusiveLine));
}
lines.push(...ran.filter((gate) => gate.could_not_prove).map(inconclusiveLine));
lines.push(...skipLines(input.gates, new Set(input.flagOnGates ?? [])));
lines.push(...waitingDecisionLines(input.waitingDecisions ?? []));
for (const escalation of input.escalations) {
lines.push(`> ${PAQAD_STATUS_GLYPH.needsLook} needs a look \u2014 ${escalation}`);
}
return lines.join("\n");
}
function receiptGateState(gate) {
if (gate.could_not_prove) return "inconclusive";
return gate.status === "skipped" ? gate.skip_kind ?? "not-required" : gate.status;
}
function receiptGateWord(gate) {
return GATE_STATE_LABEL[receiptGateState(gate)];
}
function lowerWord(gate) {
return receiptGateWord(gate).toLowerCase();
}
function labelled(gate) {
const word = lowerWord(gate);
return gate.detail.toLowerCase().includes(word) ? gate.detail : `${word}. ${gate.detail}`;
}
function isRecordGap(gate) {
return gateOwner(gate.gate) === "paqad-record";
}
function recordGapLine(gate) {
return `> ${PAQAD_STATUS_GLYPH.skipped} ${gate.gate}: ${recordGapText(gate.gate)}. ${gate.detail}`;
}
function inconclusiveLine(gate) {
if (isRecordGap(gate)) return recordGapLine(gate);
return `> ${PAQAD_STATUS_GLYPH.needsLook} ${gate.gate}: ${labelled(gate)}`;
}
function gateWords(gate) {
return gate.split("-").join(" ");
}
function waitingDecisionLines(waiting) {
return waiting.map(
(packet) => `> ${PAQAD_STATUS_GLYPH.skipped} a decision is waiting for you: ${packet.decision_id} (${packet.category}): ${packet.question}`
);
}
function skipLines(gates, flagOn) {
const glyph = PAQAD_STATUS_GLYPH.skipped;
const lines = [];
const grouped = /* @__PURE__ */ new Map();
for (const gate of gates) {
if (gate.status !== "skipped") continue;
const words = gateWords(gate.gate);
if (gate.skip_kind === "did-not-run") {
const reason2 = gate.skip_reason;
if (reason2 === void 0) lines.push(`> ${glyph} ${words}: ${labelled(gate)}`);
else grouped.set(reason2, [...grouped.get(reason2) ?? [], words]);
} else if (flagOn.has(gate.gate)) {
lines.push(`> ${glyph} ${words}: ${lowerWord(gate)} (${gate.skip_reason ?? gate.detail})`);
}
}
for (const [reason2, names] of grouped) {
lines.push(`> ${glyph} ${names.join(", ")}: did not run (${reason2})`);
}
return lines;
}
// src/verification/repository/run-repository-verification.ts
function verifierVersion() {
return true ? "1.128.1" : "0.0.0-dev";
}
function backstopGates() {
return [
new AcTestMappingGate(),
new SpecReviewGate(),
new ImplementationReviewGate(),
new ChangeCompletenessGate(),
new MutationTestingGate(),
new QualityRatchetGate(),
new DuplicationGate(),
new ModuleDocsStructureGate(),
new InstructionsDocsStructureGate(),
new DocumentationFreshnessGate(),
new ExtensionSurfaceGate()
];
}
function skipDetail(decision) {
if (decision.reason === "detour") {
return `This turn ran the ${decision.activeWorkflow} workflow and made no code change. The paused change is checked when it resumes.`;
}
if (decision.reason === "empty-change") {
return "The open change has no changed files and has not reached development, so there is nothing to check yet. It is checked once it has edits.";
}
return "This session made no code change of its own, so there are no end-of-change checks to run.";
}
async function runRepositoryVerification(options) {
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
if (!isFrameworkEnabledForRoot(options.projectRoot)) {
const at2 = now();
return {
origin: options.origin,
ok: true,
summary: "\u2713 paqad disabled \u2014 verification skipped (vanilla mode).",
gates: [],
escalations: [],
evidence_path: null,
started_at: at2,
completed_at: at2
};
}
if (options.origin === "hook-completion") {
const decision = classifyCompletionEnforcement(
options.projectRoot,
options.hostSessionId ?? null
);
if (!decision.enforce) {
recordNonFeatureVerificationSkip(options.projectRoot, {
sessionId: options.hostSessionId ?? null,
workflow: decision.activeWorkflow,
origin: options.origin,
reason: decision.reason
});
const at2 = now();
const detail = skipDetail(decision);
return {
origin: options.origin,
ok: true,
applicable: false,
summary: `${paqadFrameLead("verification not applicable")}
> ${PAQAD_STATUS_GLYPH.skipped} ${detail}`,
gates: [],
escalations: [],
evidence_path: null,
started_at: at2,
completed_at: at2
};
}
}
const startedAt = now();
const built = options.prebuiltContext ?? await buildRepositoryVerificationContext({
projectRoot: options.projectRoot,
origin: options.origin,
mutationDeps: options.mutationDeps,
hostSessionId: options.hostSessionId ?? null
});
const { context, escalations } = built;
if (changeIsFeatureDev(context.changed_files, context.project_root) && resolveDuplicationMode(context.project_root) !== "off") {
try {
await runDuplicationScan({
projectRoot: context.project_root,
changedFiles: context.changed_files
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: duplication scan skipped (${message})`);
}
}
const runner = new VerificationGateRunner(backstopGates());
const results = await runner.run(context);
const completedAt = now();
await syncModuleHealthFromVerification({
projectRoot: context.project_root,
verificationContext: context,
results
});
const evidence = buildVerificationEvidence({
results,
context: {
structured_test_results: context.structured_test_results,
mutation_result: context.mutation_result
},
run_id: `${context.verification_origin}-${startedAt}`,
started_at: startedAt,
completed_at: completedAt
});
const origin = context.verification_origin ?? options.origin;
const isFeatureDev = changeIsFeatureDev(context.changed_files, context.project_root);
let stageResult = null;
try {
const stageFileDigests = await computeFileDigests(context.project_root, context.changed_files);
stageResult = finalizeStageEvidence(context.project_root, {
adapter: BACKSTOP_WRITER,
sessionId: options.hostSessionId ?? null,
changedFilesCount: context.changed_files.length,
subjectDigest: computeChangeSubjectDigest(stageFileDigests),
isFeatureDevChange: isFeatureDev,
deferClose: true,
now: () => new Date(completedAt)
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: stage-evidence finalize skipped (${message})`);
}
const stagesMode = resolveStagesMode(context.project_root);
const stageGate = stageEvidenceGate(
stageResult,
origin,
context.changed_files.length,
stagesMode
);
const directGates = [];
if (stageGate) {
evidence.gates.push(stageGate);
directGates.push(stageGate);
if (stageGate.status === "fail") {
evidence.overall_status = "fail";
}
}
const checksGate = checksEvidenceGate(context.structured_test_results, {
stale: context.checks_report_stale
});
if (checksGate) {
const existingIndex = evidence.gates.findIndex((gate) => gate.name === "code-tests-lint");
if (existingIndex >= 0) {
evidence.gates[existingIndex] = checksGate;
} else {
evidence.gates.push(checksGate);
}
directGates.push(checksGate);
if (checksGate.status === "fail") {
evidence.overall_status = "fail";
evidence.first_failure_gate ??= checksGate.name;
}
} else if (isFeatureDev && context.code_changed) {
const inconclusiveGate = inconclusiveChecksGate();
const existingIndex = evidence.gates.findIndex((gate) => gate.name === "code-tests-lint");
if (existingIndex >= 0) {
evidence.gates[existingIndex] = inconclusiveGate;
} else {
evidence.gates.push(inconclusiveGate);
}
directGates.push(inconclusiveGate);
} else if (!context.code_changed) {
evidence.gates = evidence.gates.map(
(gate) => gate.name === "code-tests-lint" ? {
...gate,
detail: "No code changed, so there were no tests to check.",
skip_reason: "no code changed",
skip_kind: "not-required"
} : gate
);
}
const checksVerified = (context.structured_test_results?.length ?? 0) > 0 && context.code_tests_lint_passed && !context.checks_report_stale;
let changeMetrics = null;
if (isFeatureDev && resolveFrameworkConfig(context.project_root).features.metrics_enabled) {
try {
changeMetrics = await computeChangeMetrics({
projectRoot: context.project_root,
changedFiles: context.changed_files
});
appendChangeMetrics(
context.project_root,
resolveSessionId(context.project_root, options.hostSessionId ?? null),
changeMetrics
);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: change-metrics skipped (${message})`);
changeMetrics = null;
}
}
let evidencePath = null;
try {
evidencePath = await writeVerificationEvidence(evidence, {
project_root: context.project_root
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: could not write verification-evidence.json (${message})`);
}
const policy = resolveEnterprisePolicy(readProjectProfile(context.project_root));
const bundleSessionId = resolveSessionId(context.project_root, options.hostSessionId ?? null);
const activeFeature = currentFeature(context.project_root, bundleSessionId);
const bundleFeature = activeFeature && !routeIsAffirmativelyNonFeature(context.project_root, options.hostSessionId ?? null) ? activeFeature : null;
let lateGateRowTarget = null;
let graded = null;
try {
const fileDigests = await computeFileDigests(context.project_root, context.changed_files);
const subjectDigest = computeChangeSubjectDigest(fileDigests);
const rowCtx = { subjectDigest, ts: completedAt };
const rows = [
...gateResultsToRows(results, rowCtx),
...ratchetResultToRows(context.quality_ratchet_result, rowCtx)
];
graded = { fileDigests, rows, ctx: rowCtx };
if (bundleFeature) {
appendFeatureEvidenceRows(context.project_root, bundleSessionId, rows);
lateGateRowTarget = { sessionId: bundleSessionId, ctx: rowCtx };
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: could not record evidence rows (${message})`);
}
const receiptPending = writesLedger(policy) && graded !== null && bundleFeature !== null;
const reportPath2 = renderActiveFeatureReport(
context.project_root,
options.hostSessionId ?? null,
completedAt,
verifierVersion()
);
const completenessSession = resolveSessionId(context.project_root, options.hostSessionId ?? null);
const completenessActive = currentFeature(context.project_root, completenessSession);
const completenessDir = completenessActive && !routeIsAffirmativelyNonFeature(context.project_root, options.hostSessionId ?? null) ? completenessActive : null;
const completenessMode = resolveBundleCompletenessMode(context.project_root);
if (completenessDir) {
try {
writeFeatureDecisionsIndex(context.project_root, completenessDir, {
sessionId: completenessSession
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: decisions index skipped (${message})`);
}
try {
writeFeatureTechDebtIndex(context.project_root, completenessDir, {
sessionId: completenessSession
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: tech-debt index skipped (${message})`);
}
}
let completenessFailed = false;
const lateGates = [];
const frameworkConfig = resolveFrameworkConfig(context.project_root);
let completenessInput = null;
let completenessGate = null;
if (completenessMode !== "off") {
if (completenessDir) {
try {
reconcileDeliveryFromGit(context.project_root, completenessDir, completedAt);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: delivery reconcile skipped (${message})`);
}
}
completenessInput = {
projectRoot: context.project_root,
sessionId: completenessSession,
dirName: completenessDir,
mode: completenessMode,
origin,
isFeatureDev,
config: buildBundleCompletenessConfig(
context.project_root,
completenessSession,
completenessDir
),
changeMetrics,
evidenceRowsPending: lateGateRowTarget !== null,
receiptPending,
changedFiles: context.changed_files
};
completenessGate = bundleCompletenessGate(completenessInput);
if (completenessGate) {
evidence.gates.push(completenessGate);
lateGates.push(completenessGate);
if (completenessGate.status === "fail") {
completenessFailed = true;
evidence.overall_status = "fail";
evidence.first_failure_gate ??= completenessGate.name;
}
}
} else {
const existenceMode = resolveEvidenceExistenceMode(context.project_root);
if (existenceMode !== "off") {
const existenceGate = evidenceExistenceGate({
projectRoot: context.project_root,
sessionId: completenessSession,
dirName: completenessDir,
mode: existenceMode,
isFeatureDev,
ragEnabled: frameworkConfig.intelligence.rag_enabled,
ruleComplianceOn: resolveRuleComplianceMode(context.project_root) !== "off",
duplicationOn: resolveDuplicationMode(context.project_root) !== "off",
metricsOn: frameworkConfig.features.metrics_enabled,
changeMetrics
});
if (existenceGate) {
evidence.gates.push(existenceGate);
lateGates.push(existenceGate);
}
}
}
const veProfile = readProjectProfile(context.project_root);
const veFlagOn = frameworkConfig.features.visual_evidence && (veProfile?.active_capabilities?.includes("coding") ?? false);
const flagOnGates = veFlagOn ? ["visual-evidence"] : [];
{
const veTrigger = frontendTriggerOrFault(context.project_root, context.changed_files);
const veGate = visualEvidenceGate({
projectRoot: context.project_root,
dirName: completenessDir,
mode: resolveVisualEvidenceMode(context.project_root),
origin,
isFeatureDev,
flagOn: veFlagOn,
frontendTriggered: veTrigger.triggered,
packRegistryFault: veTrigger.fault
});
if (veGate) {
evidence.gates.push(veGate);
lateGates.push(veGate);
if (veGate.status === "fail") {
evidence.overall_status = "fail";
evidence.first_failure_gate ??= veGate.name;
}
}
}
{
const rulesGate = await rulesLoadedGate({
projectRoot: context.project_root,
dirName: completenessDir,
isFeatureDev,
sessionId: completenessSession,
origin
});
if (rulesGate) {
evidence.gates.push(rulesGate);
lateGates.push(rulesGate);
if (rulesGate.status === "fail") {
evidence.overall_status = "fail";
evidence.first_failure_gate ??= rulesGate.name;
}
}
}
const fixProofEvaluation = evaluateFixProof({
projectRoot: context.project_root,
dirName: completenessDir,
isFeatureDev
});
const fixProof = fixProofEvaluation.summary;
if (fixProofEvaluation.gate) {
evidence.gates.push(fixProofEvaluation.gate);
lateGates.push(fixProofEvaluation.gate);
}
const verdictGateRows = graded ? evidenceGatesToRows([...directGates, ...lateGates], graded.ctx) : [];
if (lateGateRowTarget) {
appendFeatureEvidenceRows(context.project_root, lateGateRowTarget.sessionId, verdictGateRows);
}
const fold = readChangeFold(context.project_root, options.hostSessionId ?? null);
const verdictStageGaps = isFeatureDev && fold ? unrecordedMandatoryStages(fold, checksVerified) : [];
if (graded && bundleFeature) {
const stageGapRows = verdictStageGaps.length > 0 ? evidenceGatesToRows([unrecordedStagesGate(verdictStageGaps)], graded.ctx) : [];
appendFeatureEvidenceRows(context.project_root, bundleSessionId, stageGapRows);
if (receiptPending) {
const sealed = await sealBundleReceipt({
projectRoot: context.project_root,
dirName: bundleFeature,
sessionId: bundleSessionId,
policy,
fileDigests: graded.fileDigests,
rows: [...graded.rows, ...verdictGateRows, ...stageGapRows],
timeVerified: completedAt,
changeMetrics
});
const rechecked = completenessInput ? recheckAfterReceiptSeal(completenessGate, completenessInput, sealed) : completenessGate;
if (rechecked && completenessGate && rechecked !== completenessGate) {
evidence.gates[evidence.gates.indexOf(completenessGate)] = rechecked;
appendFeatureEvidenceRows(
context.project_root,
bundleSessionId,
evidenceGatesToRows([rechecked], graded.ctx)
);
if (rechecked.status === "fail") {
completenessFailed = true;
evidence.overall_status = "fail";
evidence.first_failure_gate ??= rechecked.name;
}
}
}
}
try {
evidencePath = await writeVerificationEvidence(evidence, {
project_root: context.project_root
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: could not re-write verification-evidence.json (${message})`);
}
const verdict2 = buildRepositoryVerificationVerdict({
origin: context.verification_origin ?? options.origin,
evidence,
escalations,
evidencePath,
flagOnGates,
waitingDecisions: context.waiting_decisions
});
verdict2.reportPath = reportPath2;
verdict2.narrationAdvisory = unnarratedAdvisory(
auditTurnNarration({
transcriptText: options.transcriptText ?? "",
recorded: (fold?.stages ?? []).filter((stage) => isAgentNarratableStage(stage.evidence_source)).map((stage) => stage.stage)
})
);
if (isFeatureDev && verdict2.ok && fold) {
const stageGaps = unrecordedMandatoryStages(fold, checksVerified);
if (stageGaps.length > 0) {
verdict2.summary = formatVerdictSummary({
ok: verdict2.ok,
gates: verdict2.gates,
escalations,
unrecordedMandatoryStages: stageGaps,
flagOnGates,
waitingDecisions: context.waiting_decisions
});
}
}
verdict2.kind = verdictKindFor(verdict2.gates, verdictStageGaps);
if (verdictStageGaps.length > 0) {
evidence.unrecorded_mandatory_stages = verdictStageGaps;
try {
await writeVerificationEvidence(evidence, {
project_root: context.project_root
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: could not record stage gaps in evidence (${message})`);
}
}
const receiptSession = resolveSessionId(context.project_root, options.hostSessionId ?? null);
const receiptFeature = currentFeature(context.project_root, receiptSession);
verdict2.change = receiptFeature;
const parts = verdictParts(verdict2.gates, verdictStageGaps);
if (fold && fold.lane === null) {
parts.record_gaps.push(LANE_RECORD_GAP);
verdict2.summary += `
> ${PAQAD_STATUS_GLYPH.skipped} ${LANE_RECORD_GAP.text}.`;
}
Object.assign(verdict2, parts);
verdict2.receipt = composeChangeReceipt({
verdictSummary: verdict2.summary,
fold,
reportPath: reportPath2,
reuse: reuseCounts(
receiptFeature ? readFeaturePlan(context.project_root, receiptFeature) : null
),
checksVerified: isFeatureDev ? checksVerified : void 0,
changeMetrics,
isolation: receiptFeature ? summarizeStageIsolation(context.project_root, receiptFeature) : null,
techDebt: receiptFeature ? readFeatureTechDebtIndex(context.project_root, receiptFeature) : null,
ruleOverrides: receiptFeature ? readRuleOverrides(context.project_root, receiptFeature) : null,
fixProof,
stageNotes: receiptFeature ? stageReceiptNotes(context.project_root, receiptFeature) : [],
cloudNote: cloudContinuationNote(context.project_root, receiptFeature, receiptSession),
decisions: receiptFeature ? decisionsReceiptLine(context.project_root, receiptFeature, receiptSession) : null,
designSignOff: designSignOffReceiptLine(
context.project_root,
receiptFeature,
resolveEffectiveLane(context.project_root, void 0, fold?.lane ?? null)
)
});
if (reportPath2) {
renderActiveFeatureReport(
context.project_root,
options.hostSessionId ?? null,
completedAt,
verifierVersion(),
verdict2.kind
);
}
if (stageResult?.ok && !completenessFailed) {
closeVerifiedChange(context.project_root, {
sessionId: options.hostSessionId ?? null,
adapter: BACKSTOP_WRITER,
verdict: stageResult.verdict,
now: () => new Date(completedAt)
});
}
if (options.eventBus) {
options.eventBus.emit({
kind: "verification-verdict",
at: completedAt,
origin: verdict2.origin,
ok: verdict2.ok,
summary: verdict2.summary,
gates: verdict2.gates.map((gate) => ({
gate: gate.gate,
status: gate.status,
detail: gate.detail
})),
escalations: verdict2.escalations
});
}
return verdict2;
}
function readChangeFold(projectRoot, hostSessionId) {
try {
const sessionId = resolveSessionId(projectRoot, hostSessionId);
const dirName = currentFeature(projectRoot, sessionId);
if (!dirName) {
return null;
}
return foldFeature(projectRoot, sessionId, dirName);
} catch {
return null;
}
}
function renderActiveFeatureReport(projectRoot, hostSessionId, completedAt, paqadVersion, verdict2) {
try {
const sessionId = resolveSessionId(projectRoot, hostSessionId);
const dirName = currentFeature(projectRoot, sessionId);
if (!dirName || !featureReportEnabled(projectRoot) || routeIsAffirmativelyNonFeature(projectRoot, hostSessionId)) {
return null;
}
return writeFeatureReport(projectRoot, dirName, {
sessionId,
generatedAt: completedAt,
paqadVersion,
...verdict2 ? { verdict: verdict2 } : {}
}).path;
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: could not render feature report (${message})`);
return null;
}
}
var STAGE_EVIDENCE_HARD_ORIGINS = /* @__PURE__ */ new Set([
"hook-completion",
"git-backstop"
]);
function describeOrderingViolations(violations) {
return violations.map(
(violation) => violation.before === violation.after ? `${violation.before} ended before it started` : `${violation.before} -> ${violation.after}`
).join("; ");
}
function stageEvidenceGate(result2, origin, _changedFileCount, mode = "strict") {
if (!result2) {
return null;
}
const name = "stage-evidence";
if (result2.ok) {
return {
name,
status: "pass",
detail: `Every mandatory feature-development stage was recorded in order (${result2.verdict}).`,
remediation: null,
failures: []
};
}
const missing = result2.missing_stages.join(", ");
if (mode === "strict" && STAGE_EVIDENCE_HARD_ORIGINS.has(origin)) {
const lead = result2.live_marked ? "Feature-development workflow left incomplete" : "Feature-development stages were not recorded for this change";
const orderingOnly = result2.missing_stages.length === 0 && result2.ordering_violations.length > 0;
const open = result2.open_stages ?? [];
const leftOpen = open.length > 0 ? ` Stage(s) left open: [${open.join(", ")}].` : "";
const endOpen = open.length > 0 ? `End each open stage (${open.map((stage) => `paqad-ai stage end ${stage}`).join(", ")}). ` : "";
return {
name,
status: "fail",
detail: orderingOnly ? `${lead} \u2014 stages ran out of order: ${describeOrderingViolations(result2.ordering_violations)}.${leftOpen}` : `${lead} \u2014 missing stage(s): [${missing}].${leftOpen}`,
remediation: endOpen + (orderingOnly ? "Re-mark the stages so each one ends before the next begins, or resolve the redo via the Decision Pause Contract." : "Record each missing stage (open \u2192 start \u2192 end per stage), or set stage_tracking: warn or off in .paqad/configs/feature-development/workflow.yaml to adopt the workflow before enforcing, or resolve the redo via the Decision Pause Contract."),
failures: []
};
}
return {
name,
status: "skipped",
detail: skippedDetail(mode, origin, missing, result2.live_marked),
remediation: null,
failures: [],
skip_kind: "not-required"
};
}
var STALE_CHECKS_DETAIL = {
"different-files": "Checks ran on different files than the ones in this change now. Run paqad-ai checks run again.",
unconfirmed: "Checks could not confirm which files they ran on. Run paqad-ai checks run again."
};
function checksEvidenceGate(results, options = {}) {
if (!results || results.length === 0) {
return null;
}
const name = "code-tests-lint";
if (options.stale) {
return {
name,
status: "inconclusive",
detail: STALE_CHECKS_DETAIL[options.stale],
remediation: "Run `paqad-ai checks run` on the current files.",
failures: []
};
}
const failing = results.find((result2) => result2.summary.failed > 0 || result2.summary.errored > 0);
if (failing) {
return {
name,
status: "fail",
detail: `Checks failed \u2014 "${failing.summary.runner_id}" reported ${failing.summary.failed} failing / ${failing.summary.errored} errored.`,
remediation: "Fix the failing build, test, or lint signal and re-run `paqad-ai checks run`.",
failures: []
};
}
const totals = results.reduce(
(aggregate, result2) => {
aggregate.total += result2.summary.total;
aggregate.passed += result2.summary.passed;
return aggregate;
},
{ total: 0, passed: 0 }
);
return {
name,
status: "pass",
detail: `Deterministic checks passed (${totals.passed}/${totals.total}).`,
remediation: null,
failures: []
};
}
function inconclusiveChecksGate() {
return {
name: "code-tests-lint",
status: "inconclusive",
detail: "No checks report on record \u2014 tests were not verified for this change. Run `paqad-ai checks run` so the checks stage is proven, or rely on CI.",
remediation: "Run `paqad-ai checks run` to persist a report the completion gate reads.",
failures: []
};
}
function skippedDetail(mode, origin, missing, liveMarked) {
if (mode === "off") {
return `Stage-evidence enforcement is disabled (stages_mode=off). Missing: [${missing}].`;
}
if (mode === "warn") {
return `Feature-development stages incomplete (missing [${missing}]) \u2014 warning only (stages_mode=warn).`;
}
return liveMarked ? `Stage-evidence incomplete (missing [${missing}]) \u2014 informational here; the local ledger is not committed for CI.` : `Feature-development stages were not recorded for this change (informational on ${origin}). Missing: [${missing}].`;
}
function unrecordedStagesGate(stages) {
return {
name: "unrecorded-mandatory-stages",
status: "inconclusive",
detail: `Mandatory stage(s) with no recorded evidence: [${stages.join(", ")}].`,
remediation: null,
failures: []
};
}
async function sealBundleReceipt(input) {
const { policy, rows } = input;
try {
const authorship = await resolveChangeAuthorship({
projectRoot: input.projectRoot,
env: process.env
});
const complianceCitations = policy.compliance_citations ? resolveComplianceCitations({ projectRoot: input.projectRoot, rows }) : void 0;
const reproducibility = readReproducibilityPredicate(input.projectRoot) ?? void 0;
projectFeatureReceipt(input.projectRoot, input.dirName, {
fileDigests: input.fileDigests,
rows,
verifierVersion: verifierVersion(),
timeVerified: input.timeVerified,
sessionId: input.sessionId,
write: { receipt: policy.evidence_ledger, aiBom: policy.ai_bom },
authorship,
...complianceCitations !== void 0 ? { complianceCitations } : {},
...reproducibility !== void 0 ? { reproducibility } : {},
...input.changeMetrics ? {
metrics: {
dup_new_pct: input.changeMetrics.dup_new_pct,
reuse_rate: input.changeMetrics.reuse_rate,
meaningful_changed_lines: input.changeMetrics.meaningful_changed_lines
}
} : {}
});
return true;
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
engineLog("warn", `paqad: could not project evidence receipt (${message})`);
return false;
}
}
// src/verification/gates/gate.interface.ts
init_esm_shims();
// src/patterns/index.ts
init_esm_shims();
// src/patterns/types.ts
init_esm_shims();
// src/patterns/pattern-recorder.ts
init_esm_shims();
import { randomUUID as randomUUID2 } from "crypto";
var PatternRecorder = class {
constructor(store) {
this.store = store;
}
store;
async record(input) {
const pattern = {
id: randomUUID2(),
created_at: (/* @__PURE__ */ new Date()).toISOString(),
source_project: input.projectDirName,
stack_filter: {
domain: input.domain,
frameworks: input.frameworks,
traits: input.traits
},
category: input.classification.category ?? input.classification.workflow ?? "general",
problem: input.problem,
solution: input.solution,
files_involved: input.filesInvolved,
verification: input.verification,
tags: input.tags ?? []
};
await this.store.save(pattern);
return pattern;
}
};
// src/patterns/pattern-cli.ts
init_esm_shims();
import { writeFile as writeFile30 } from "fs/promises";
var STALENESS_THRESHOLD_DAYS = 180;
var PatternCli = class {
constructor(store) {
this.store = store;
}
store;
async list(filter) {
const patterns = await this.store.list(filter);
if (patterns.length === 0) {
console.log("No patterns found.");
return;
}
for (const p of patterns) {
console.log(`[${p.id.slice(0, 8)}] ${p.category} \u2014 ${p.problem.slice(0, 80)}`);
console.log(` Stack: ${p.stack_filter.frameworks.join(", ")} | Tags: ${p.tags.join(", ")}`);
console.log(` Created: ${p.created_at}`);
console.log("");
}
}
async prune(olderThanDays = STALENESS_THRESHOLD_DAYS) {
const patterns = await this.store.list();
let pruned = 0;
for (const p of patterns) {
const ageDays = (Date.now() - new Date(p.created_at).getTime()) / (1e3 * 60 * 60 * 24);
if (ageDays > olderThanDays) {
await this.store.delete(p.id);
pruned++;
}
}
console.log(`Pruned ${pruned} pattern(s).`);
}
async exportPatterns(outputPath, format) {
const patterns = await this.store.list();
if (format === "json") {
await writeFile30(outputPath, JSON.stringify(patterns, null, 2), "utf8");
} else {
const lines = ["# Pattern Library Export\n"];
for (const p of patterns) {
lines.push(`## ${p.category}: ${p.problem.slice(0, 60)}`);
lines.push(`**ID:** ${p.id} `);
lines.push(`**Stack:** ${p.stack_filter.frameworks.join(", ")} `);
lines.push(`**Created:** ${p.created_at}
`);
lines.push(`### Problem
${p.problem}
`);
lines.push(`### Solution
${p.solution}
`);
lines.push("---\n");
}
await writeFile30(outputPath, lines.join("\n"), "utf8");
}
console.log(`Exported ${patterns.length} pattern(s) to ${outputPath}`);
}
};
// src/project-knowledge/index.ts
init_esm_shims();
// src/project-knowledge/types.ts
init_esm_shims();
var ANSWER_GROUNDING_STATES = ["observed", "inferred", "missing-evidence"];
var ANSWER_MODES = ["quick", "explain", "trace"];
var CITATION_SOURCE_CLASSES = [
"canonical-doc",
"generated-instruction",
"framework-state",
"manifest",
"workflow",
"code"
];
// src/project-knowledge/evidence-retriever.ts
init_esm_shims();
var import_fast_glob18 = __toESM(require_out(), 1);
import { readFile as readFile47 } from "fs/promises";
import { join as join110 } from "path";
var STOP_WORDS2 = /* @__PURE__ */ new Set([
"a",
"an",
"the",
"is",
"it",
"in",
"on",
"at",
"to",
"of",
"for",
"and",
"or",
"but",
"not",
"with",
"this",
"that",
"are",
"was",
"be",
"by",
"as",
"do",
"how",
"what",
"where",
"which",
"who",
"when",
"why",
"has",
"have",
"from",
"any",
"all",
"its"
]);
function extractKeywords(question) {
if (!question) return [];
return question.toLowerCase().split(/\s+/).map((w) => w.replace(/[^a-z0-9-]/g, "")).filter((w) => w.length >= 3 && !STOP_WORDS2.has(w));
}
function scoreFile(filePath, excerpt, keywords) {
if (keywords.length === 0) return 0;
const haystack = (filePath + " " + excerpt).toLowerCase();
return keywords.reduce((acc, kw) => acc + (haystack.includes(kw) ? 1 : 0), 0);
}
function buildExcerpt(content, keywords) {
const normalized = content.replace(/\s+/g, " ").trim();
if (normalized.length === 0) return "";
const lowered = normalized.toLowerCase();
const firstMatchIndex = keywords.map((keyword) => lowered.indexOf(keyword)).filter((index) => index >= 0).sort((a, b) => a - b)[0];
if (firstMatchIndex === void 0) {
return normalized.slice(0, EXCERPT_LENGTH);
}
const start = Math.max(0, firstMatchIndex - 120);
const end = Math.min(normalized.length, firstMatchIndex + EXCERPT_LENGTH);
return normalized.slice(start, end).trim();
}
var EVIDENCE_PATTERNS = [
{ pattern: "docs/modules/**/*.md", source_class: "canonical-doc" },
{ pattern: "docs/instructions/**/*.md", source_class: "generated-instruction" },
{ pattern: ".paqad/**/*.{json,yaml,yml}", source_class: "framework-state" },
{
pattern: "{package.json,composer.json,go.mod,Cargo.toml,pyproject.toml,pom.xml}",
source_class: "manifest"
},
{ pattern: ".github/workflows/**/*.{yml,yaml}", source_class: "workflow" },
{ pattern: "src/**/*.{ts,js}", source_class: "code" },
{ pattern: "app/**/*.{ts,js}", source_class: "code" },
{ pattern: "lib/**/*.{ts,js}", source_class: "code" }
];
var MAX_RESULTS = 6;
var EXCERPT_LENGTH = 500;
var SOURCE_CLASS_ORDER = EVIDENCE_PATTERNS.map((pattern) => pattern.source_class);
function classifySource(rawRelativePath) {
const relativePath = toPosixPath(rawRelativePath);
if (relativePath.startsWith("docs/modules/") && relativePath.endsWith(".md")) {
return "canonical-doc";
}
if (relativePath.startsWith("docs/instructions/") && relativePath.endsWith(".md")) {
return "generated-instruction";
}
if (relativePath.startsWith(".paqad/")) {
return "framework-state";
}
if (["package.json", "composer.json", "go.mod", "Cargo.toml", "pyproject.toml", "pom.xml"].includes(
relativePath
)) {
return "manifest";
}
if (relativePath.startsWith(".github/workflows/") && (relativePath.endsWith(".yml") || relativePath.endsWith(".yaml"))) {
return "workflow";
}
if (/^src\/.*\.(ts|js)$/.test(relativePath) || /^app\/.*\.(ts|js)$/.test(relativePath) || /^lib\/.*\.(ts|js)$/.test(relativePath)) {
return "code";
}
return null;
}
var EvidenceRetriever = class {
async retrieve(query) {
const keywords = extractKeywords(query.question);
if (keywords.length === 0) return [];
const semanticCandidates = await this.retrieveSemanticEvidence(query, keywords);
const lexicalCandidates = await this.retrieveLexicalEvidence(query, keywords);
const merged = /* @__PURE__ */ new Map();
for (const candidate of [...semanticCandidates, ...lexicalCandidates]) {
const existing = merged.get(candidate.path);
if (!existing || candidate.score > existing.score) {
merged.set(candidate.path, candidate);
}
}
const MCP_SOURCE_CLASS = "framework-state";
const candidates = [...merged.values()];
candidates.sort((a, b) => {
if (b.score !== a.score) return b.score - a.score;
if (query.mcp_first) {
const aMcp = a.source_class === MCP_SOURCE_CLASS ? 0 : 1;
const bMcp = b.source_class === MCP_SOURCE_CLASS ? 0 : 1;
if (aMcp !== bMcp) return aMcp - bMcp;
}
return SOURCE_CLASS_ORDER.indexOf(a.source_class) - SOURCE_CLASS_ORDER.indexOf(b.source_class);
});
return candidates.slice(0, MAX_RESULTS);
}
async retrieveSemanticEvidence(query, keywords) {
const rag = new RagService(query.project_root);
const status = await rag.getStatus();
if (!status.enabled || !status.index_present || !status.valid) {
return [];
}
const result2 = await rag.retrieveForEval(
{
taskDescription: query.question,
keywords
},
MAX_RESULTS
);
const seen = /* @__PURE__ */ new Set();
const candidates = [];
for (const chunk of result2.retrieved_chunks) {
if (seen.has(chunk.source_file)) {
continue;
}
const sourceClass = classifySource(chunk.source_file);
if (!sourceClass) {
continue;
}
seen.add(chunk.source_file);
candidates.push({
path: toPosixPath(chunk.source_file),
source_class: sourceClass,
excerpt: buildExcerpt(chunk.content, keywords),
score: Math.max(scoreFile(chunk.source_file, chunk.content, keywords), 1)
});
}
return candidates;
}
async retrieveLexicalEvidence(query, keywords) {
const candidates = [];
for (const { pattern, source_class } of EVIDENCE_PATTERNS) {
const paths = await (0, import_fast_glob18.default)(pattern, {
cwd: query.project_root,
absolute: false,
dot: true
});
for (const relativePath of paths) {
const absolutePath = join110(query.project_root, relativePath);
let excerpt = "";
let score = 0;
try {
const content = await readFile47(absolutePath, "utf8");
score = scoreFile(relativePath, content, keywords);
if (score <= 0) {
continue;
}
excerpt = buildExcerpt(content, keywords);
} catch {
}
if (score <= 0) {
continue;
}
candidates.push({ path: relativePath, source_class, excerpt, score });
}
}
return candidates;
}
};
// src/project-knowledge/freshness-checker.ts
init_esm_shims();
import { readFile as readFile48, stat as stat3 } from "fs/promises";
import { join as join111 } from "path";
var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
var UNKNOWN_NOTE = "Documentation freshness unknown \u2014 run paqad-ai onboard to establish baseline";
var FreshnessChecker = class {
async check(projectRoot, evidencePaths) {
const docProgressPath = join111(projectRoot, ".paqad", "doc-progress.json");
const stackDriftPath = join111(projectRoot, ".paqad", "stack-drift.json");
let generatedAt;
let note;
try {
const raw = await readFile48(docProgressPath, "utf8");
const parsed = JSON.parse(raw);
generatedAt = parsed.generated_at;
} catch {
note = UNKNOWN_NOTE;
}
let driftDetected = false;
try {
const raw = await readFile48(stackDriftPath, "utf8");
const parsed = JSON.parse(raw);
driftDetected = parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && Object.keys(parsed).length > 0;
} catch {
}
const staleSources = [];
if (generatedAt) {
const baseTime = new Date(generatedAt).getTime();
for (const relativePath of evidencePaths) {
const absolutePath = join111(projectRoot, relativePath);
try {
const info2 = await stat3(absolutePath);
const ageDiff = info2.mtimeMs - baseTime;
if (ageDiff > STALE_THRESHOLD_MS) {
staleSources.push(relativePath);
}
} catch {
}
}
}
return {
stale_sources: staleSources,
drift_detected: driftDetected,
...generatedAt !== void 0 && { generated_at: generatedAt },
...note !== void 0 && { note }
};
}
};
// src/project-knowledge/contradiction-detector.ts
init_esm_shims();
var CLAIM_PATTERNS = [
{ key: "node-engine", regex: /["']node["']\s*:\s*["']([^"']+)["']/gi },
{ key: "package-version", regex: /"version"\s*:\s*"([^"]+)"/gi },
{ key: "pnpm-version", regex: /["']pnpm["']\s*:\s*["']([^"']+)["']/gi }
];
function extractClaims(file) {
const claims = [];
for (const { key, regex } of CLAIM_PATTERNS) {
const pattern = new RegExp(regex.source, regex.flags);
let match;
while ((match = pattern.exec(file.excerpt)) !== null) {
claims.push({ key, value: match[1], filePath: file.path, source_class: file.source_class });
}
}
return claims;
}
var ContradictionDetector = class {
detect(files) {
if (files.length < 2) return [];
const allClaims = files.flatMap(extractClaims);
const contradictions = [];
const seen = /* @__PURE__ */ new Set();
for (let i = 0; i < allClaims.length; i++) {
for (let j = i + 1; j < allClaims.length; j++) {
const a = allClaims[i];
const b = allClaims[j];
if (a.key !== b.key) continue;
if (a.filePath === b.filePath) continue;
if (a.value === b.value) continue;
const pairKey = [a.filePath, b.filePath, a.key].sort().join("|");
if (seen.has(pairKey)) continue;
seen.add(pairKey);
contradictions.push({
source_a: a.filePath,
source_b: b.filePath,
description: `"${a.key}" is "${a.value}" in ${a.filePath} but "${b.value}" in ${b.filePath}`
});
}
}
return contradictions;
}
};
// src/project-knowledge/answerer.ts
init_esm_shims();
function determineGroundingState(evidence) {
if (evidence.length === 0) return "missing-evidence";
return evidence[0].source_class === "canonical-doc" ? "observed" : "inferred";
}
function extractClaimText(evidence) {
const cleaned = evidence.excerpt.replace(/\s+/g, " ").trim();
if (!cleaned) {
return `Relevant evidence was found in ${evidence.path}.`;
}
const sentence = cleaned.match(/[^.!?]+[.!?]/)?.[0]?.trim() ?? cleaned;
return sentence.length > 240 ? `${sentence.slice(0, 237).trim()}...` : sentence;
}
function formatEvidenceReference(evidence) {
return `${extractClaimText(evidence)} (${evidence.path})`;
}
function buildAnswer(evidence, query, groundingState, freshness, contradictions) {
if (evidence.length === 0) {
return `No project-specific evidence was found for: "${query.question}". Run paqad-ai onboard to generate canonical documentation.`;
}
const primary = formatEvidenceReference(evidence[0]);
const supporting = evidence.slice(1, 3).map(formatEvidenceReference);
const baseAnswer = groundingState === "observed" ? `Based on repository evidence, ${primary}` : `This answer is inferred from repository evidence: ${primary}`;
const supportSentence = supporting.length > 0 ? ` Supporting evidence: ${supporting.join(" ")}` : "";
const freshnessNotes = [];
if (freshness.stale_sources.length > 0) {
freshnessNotes.push(`Some cited sources may be stale: ${freshness.stale_sources.join(", ")}.`);
}
if (freshness.drift_detected) {
freshnessNotes.push("Current stack drift is detected, so confirm live state before acting.");
}
const contradictionNote = contradictions.length > 0 ? ` Conflicting evidence exists between ${contradictions.slice(0, 2).map((item) => `${item.source_a} and ${item.source_b}`).join(", ")}.` : "";
if (query.mode === "quick") {
return `${baseAnswer}${freshnessNotes.length > 0 ? ` ${freshnessNotes[0]}` : ""}${contradictionNote}`.trim();
}
if (query.mode === "explain") {
return `${baseAnswer}${supportSentence}${freshnessNotes.length > 0 ? ` ${freshnessNotes.join(" ")}` : ""}${contradictionNote}`.trim();
}
const lines = evidence.map(
(e, i) => `[${i + 1}] ${e.path} (${e.source_class}): ${e.excerpt.slice(0, 120).replace(/\n/g, " ").trim()}`
);
const traceNotes = [...freshnessNotes];
if (contradictions.length > 0) {
traceNotes.push(
`Contradictions: ${contradictions.map((item) => item.description).join(" | ")}`
);
}
return `${baseAnswer}${supportSentence}
Evidence trail for "${query.question}":
${lines.join("\n")}${traceNotes.length > 0 ? `
${traceNotes.join("\n")}` : ""}`;
}
function buildConfidenceBasis(groundingState, evidence, freshness, contradictions) {
const reasons = [];
if (groundingState === "missing-evidence") {
reasons.push(
"No project evidence was found, so the answer cannot be grounded in repository artifacts."
);
} else {
const primaryEvidence = evidence[0];
if (groundingState === "observed") {
reasons.push(`The lead citation (${primaryEvidence.path}) is a canonical module doc.`);
} else {
const hasSupportingCanonical = evidence.some((e) => e.source_class === "canonical-doc");
reasons.push(
hasSupportingCanonical ? `The lead citation (${primaryEvidence.path}) is ${primaryEvidence.source_class}, so the conclusion remains inferred even though supporting canonical docs were also retrieved.` : `The conclusion is inferred from secondary sources (${primaryEvidence.source_class}) because the lead citation is not a canonical doc.`
);
}
}
if (freshness.stale_sources.length > 0) {
reasons.push(`Stale cited sources reduce confidence: ${freshness.stale_sources.join(", ")}.`);
}
if (freshness.drift_detected) {
reasons.push("Detected stack drift means repository state may have changed since generation.");
}
if (contradictions.length > 0) {
reasons.push("Conflicting evidence is present, so the answer needs confirmation.");
}
return `Confidence basis: ${reasons.join(" ")}`;
}
function buildNextActions(groundingState, staleSourceCount, contradictionCount) {
const actions = ["Inspect cited files for full context."];
if (groundingState === "missing-evidence") {
actions.push("Run paqad-ai onboard to generate canonical documentation.");
}
if (staleSourceCount > 0) {
actions.push("Run paqad-ai update to refresh stale documentation.");
}
if (contradictionCount > 0) {
actions.push("Resolve the detected contradiction before acting on this answer.");
}
return actions;
}
var ProjectKnowledgeAnswerer = class {
constructor(retriever = new EvidenceRetriever(), freshnessChecker = new FreshnessChecker(), contradictionDetector = new ContradictionDetector()) {
this.retriever = retriever;
this.freshnessChecker = freshnessChecker;
this.contradictionDetector = contradictionDetector;
}
retriever;
freshnessChecker;
contradictionDetector;
async answer(query) {
const resolvedQuery = query.mcp_first !== void 0 ? query : {
...query,
mcp_first: readProjectProfile(query.project_root)?.efficiency?.mcp_first ?? false
};
const evidence = await this.retriever.retrieve(resolvedQuery);
const groundingState = determineGroundingState(evidence);
const citations = evidence.map((e) => ({
path: e.path,
source_class: e.source_class,
excerpt: e.excerpt.slice(0, 200) || void 0
}));
const freshness = await this.freshnessChecker.check(
query.project_root,
evidence.map((e) => e.path)
);
const contradictions = this.contradictionDetector.detect(evidence);
const answer = buildAnswer(evidence, query, groundingState, freshness, contradictions);
const confidenceBasis = buildConfidenceBasis(
groundingState,
evidence,
freshness,
contradictions
);
const nextActions = buildNextActions(
groundingState,
freshness.stale_sources.length,
contradictions.length
);
return {
answer,
grounding_state: groundingState,
citations,
freshness,
contradictions,
next_actions: nextActions,
mode: query.mode,
confidence_basis: confidenceBasis
};
}
};
// src/workflows/index.ts
init_esm_shims();
// src/workflows/pentest-retest.ts
init_esm_shims();
import { mkdir as mkdir31, writeFile as writeFile32 } from "fs/promises";
import { dirname as dirname43, join as join115 } from "path";
// src/pentest/findings.ts
init_esm_shims();
import { existsSync as existsSync56 } from "fs";
import { readFile as readFile49 } from "fs/promises";
import { join as join112 } from "path";
import { createHash as createHash16 } from "crypto";
function createFinding(input) {
return {
id: "",
...input
};
}
async function buildDependencyFindings(snapshot, artifactDir, osvFindings) {
const findings = [];
const nativeFindings = await readNativeAuditFindings(artifactDir);
const seen = /* @__PURE__ */ new Set();
for (const finding of [...nativeFindings, ...osvFindings]) {
const pkg = snapshot.packages.find((candidate) => candidate.name === finding.package_name);
const key = `${finding.package_name}:${finding.advisory_id}`;
if (seen.has(key)) {
continue;
}
seen.add(key);
findings.push(
createFinding({
title: `Dependency advisory for ${finding.package_name}`,
description: finding.summary,
impact: normalizeImpact(`${finding.summary}
${finding.details}`),
effort: "medium",
possible_solution_direction: pkg === void 0 ? "Review the dependency and update or replace it if the advisory is relevant." : `Upgrade ${finding.package_name} from ${pkg.locked_version} to a patched release and validate downstream compatibility.`,
how_to_reproduce: [
"Run the dependency audit scripts generated by paqad-ai.",
`Inspect advisories for ${finding.package_name} in the pentest dependency artifacts.`
],
impact_area: [`package:${finding.package_name}`],
evidence: [
`Advisory: ${finding.advisory_id}`,
`Package: ${finding.package_name}@${finding.version}`,
finding.details || finding.summary
],
category: "dependency-advisory",
status: "open",
confidence: 0.9,
source_types: ["advisory", "code"],
affected_modules: [],
affected_packages: [finding.package_name],
runtime_required: false,
manual_follow_up: false
})
);
}
return findings;
}
function buildModuleFindings(docs, tests) {
const findings = [];
for (const moduleDoc of docs) {
const lowered = moduleDoc.content.toLowerCase();
const permissionTests = extractRelevantTestPaths(tests, moduleDoc.module, [
"forbidden",
"unauthor",
"permission",
"policy",
"tenant",
"role",
"403"
]);
if (hasAny(lowered, ["role", "permission", "admin", "owner", "tenant", "authorize"])) {
if (permissionTests.length === 0) {
findings.push(
createFinding({
title: `Permission boundary evidence is thin for ${moduleDoc.module}`,
description: "Module docs describe privileged or tenant-sensitive behavior, but the current test inventory does not show matching authorization or boundary assertions.",
impact: "medium",
effort: "medium",
possible_solution_direction: "Add explicit authorization, policy, tenant-isolation, and forbidden-path tests for the privileged flows described in the module docs.",
how_to_reproduce: [
`Review ${moduleDoc.paths.join(", ")} for role or tenant-sensitive actions.`,
"Search the current tests for authorization, forbidden, tenant, and policy assertions for that module."
],
impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
evidence: [
...moduleDoc.paths.map((path10) => `Doc evidence: ${path10}`),
"No matching auth boundary test evidence found for this module."
],
category: "permission-boundary",
status: "open",
confidence: 0.72,
source_types: ["docs", "tests"],
affected_modules: [moduleDoc.module],
affected_packages: [],
runtime_required: false,
manual_follow_up: false
})
);
}
}
const stateTests = extractRelevantTestPaths(tests, moduleDoc.module, [
"state",
"transition",
"approve",
"reject",
"cancel",
"retry",
"idempot"
]);
if (hasAny(lowered, ["state", "transition", "workflow", "approval", "approve", "reject"])) {
if (stateTests.length === 0) {
findings.push(
createFinding({
title: `Business workflow abuse coverage is thin for ${moduleDoc.module}`,
description: "The module docs describe stateful or approval-based flows, but the current tests do not show evidence for invalid transition, duplicate action, or workflow bypass protection.",
impact: "medium",
effort: "medium",
possible_solution_direction: "Add tests for invalid transitions, duplicate submissions, retry safety, and approval bypass attempts for the documented workflow states.",
how_to_reproduce: [
`Inspect ${moduleDoc.paths.join(", ")} for workflow or state descriptions.`,
"Search the current tests for invalid transition, duplicate action, or workflow-bypass coverage."
],
impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
evidence: [
...moduleDoc.paths.map((path10) => `Doc evidence: ${path10}`),
"No matching state-machine or workflow-bypass tests found for this module."
],
category: "business-logic-abuse",
status: "open",
confidence: 0.69,
source_types: ["docs", "tests"],
affected_modules: [moduleDoc.module],
affected_packages: [],
runtime_required: false,
manual_follow_up: false
})
);
}
}
const criticalActionTests = extractRelevantTestPaths(tests, moduleDoc.module, [
"payment",
"checkout",
"refund",
"idempot",
"duplicate",
"race",
"concurrent"
]);
if (hasAny(lowered, ["payment", "checkout", "refund", "transfer", "payout", "delete", "export"])) {
if (criticalActionTests.length === 0) {
findings.push(
createFinding({
title: `High-value flow abuse checks are missing for ${moduleDoc.module}`,
description: "The module docs reference high-value actions such as payments, exports, or destructive operations, but the current tests do not show abuse-focused validation for duplicate, replay, or concurrency scenarios.",
impact: "high",
effort: "high",
possible_solution_direction: "Add abuse tests for replay, double-submit, race conditions, and privilege escalation around the documented high-value actions.",
how_to_reproduce: [
`Inspect ${moduleDoc.paths.join(", ")} for high-value actions.`,
"Search the tests for replay, double-submit, concurrency, and race-condition coverage for the same module."
],
impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
evidence: [
...moduleDoc.paths.map((path10) => `Doc evidence: ${path10}`),
"No matching high-value abuse or idempotency tests found for this module."
],
category: "business-logic-abuse",
status: "open",
confidence: 0.76,
source_types: ["docs", "tests"],
affected_modules: [moduleDoc.module],
affected_packages: [],
runtime_required: false,
manual_follow_up: true
})
);
}
}
const authMechanismTests = extractRelevantTestPaths(tests, moduleDoc.module, [
"algorithm",
"expir",
"signature",
"refresh",
"revok",
"logout",
"session.invalidat",
"alg:none",
"jwt"
]);
if (hasAtLeast(lowered, 2, [
"jwt",
"token",
"bearer",
"session",
"cookie",
"oauth",
"saml",
"oidc",
"sanctum"
])) {
if (authMechanismTests.length === 0) {
findings.push(
createFinding({
title: `Auth token lifecycle checks are thin for ${moduleDoc.module}`,
description: "Module docs describe authentication tokens, sessions, or OAuth flows, but the current tests do not show evidence of token expiry, signature validation, session invalidation, or logout handling.",
impact: "high",
effort: "medium",
possible_solution_direction: "Add tests for token expiry enforcement, alg:none rejection, session invalidation on logout, and refresh token rotation for the documented auth flows.",
how_to_reproduce: [
`Review ${moduleDoc.paths.join(", ")} for token or session handling.`,
"Search tests for algorithm, expiry, signature, revocation, and logout coverage for that module."
],
impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
evidence: [
...moduleDoc.paths.map((path10) => `Doc evidence: ${path10}`),
"No matching auth token lifecycle test evidence found for this module."
],
category: "auth-mechanism",
status: "open",
confidence: 0.71,
source_types: ["docs", "tests"],
affected_modules: [moduleDoc.module],
affected_packages: [],
runtime_required: false,
manual_follow_up: true
})
);
}
}
const ssrfTests = extractRelevantTestPaths(tests, moduleDoc.module, [
"ssrf",
"redirect",
"allowlist",
"block",
"internal",
"private",
"localhost",
"metadata"
]);
if (hasAtLeast(lowered, 2, [
"url",
"redirect",
"callback",
"webhook",
"fetch",
"http",
"proxy",
"curl",
"axios"
])) {
if (ssrfTests.length === 0) {
findings.push(
createFinding({
title: `Outbound request / redirect surface lacks abuse validation for ${moduleDoc.module}`,
description: "Module docs describe outbound HTTP calls, URL parameters, webhooks, or redirect flows, but the current tests do not show evidence of SSRF prevention, redirect allowlist validation, or private-range blocking.",
impact: "high",
effort: "medium",
possible_solution_direction: "Add tests that verify SSRF prevention (blocked private ranges, redirect chain validation) and open-redirect protection for the documented outbound request surfaces.",
how_to_reproduce: [
`Review ${moduleDoc.paths.join(", ")} for URL, redirect, or webhook parameter handling.`,
"Test with SSRF payloads: 127.0.0.1, 169.254.169.254, [::1], redirect chain to internal IP."
],
impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
evidence: [
...moduleDoc.paths.map((path10) => `Doc evidence: ${path10}`),
"No matching SSRF or redirect validation test evidence found for this module."
],
category: "input-validation",
status: "open",
confidence: 0.7,
source_types: ["docs", "tests"],
affected_modules: [moduleDoc.module],
affected_packages: [],
runtime_required: false,
manual_follow_up: true
})
);
}
}
const massAssignTests = extractRelevantTestPaths(tests, moduleDoc.module, [
"mass",
"assign",
"fillable",
"guarded",
"allowlist",
"forbidden",
"attr_protected",
"protected"
]);
if (hasAtLeast(lowered, 2, [
"fill",
"create",
"update",
"patch",
"assign",
"body",
"request",
"fillable",
"guarded"
])) {
if (massAssignTests.length === 0) {
findings.push(
createFinding({
title: `Mass assignment protection evidence is absent for ${moduleDoc.module}`,
description: "Module docs describe model creation or update flows accepting request body fields, but the current tests do not show evidence of mass assignment protection (fillable allowlist, guarded fields, or forbidden-field rejection).",
impact: "medium",
effort: "low",
possible_solution_direction: "Verify the model uses an explicit $fillable allowlist or $guarded blocklist. Add tests that confirm unintended fields (is_admin, role, price, balance) are rejected when submitted in the request body.",
how_to_reproduce: [
`Review ${moduleDoc.paths.join(", ")} for model create/update operations.`,
"Submit a PATCH/POST request with extra privileged fields: is_admin=true, role=admin, price=0."
],
impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
evidence: [
...moduleDoc.paths.map((path10) => `Doc evidence: ${path10}`),
"No matching mass assignment protection test evidence found for this module."
],
category: "input-validation",
status: "open",
confidence: 0.68,
source_types: ["docs", "tests"],
affected_modules: [moduleDoc.module],
affected_packages: [],
runtime_required: false,
manual_follow_up: false
})
);
}
}
const cryptoTests = extractRelevantTestPaths(tests, moduleDoc.module, [
"crypto",
"encrypt",
"hash.strength",
"key.rotation",
"salt",
"entropy",
"randomBytes",
"bcrypt",
"argon"
]);
if (hasAtLeast(lowered, 2, [
"encrypt",
"decrypt",
"hash",
"md5",
"sha1",
"secret",
"key",
"cipher",
"aes",
"rsa",
"hmac"
])) {
if (cryptoTests.length === 0) {
findings.push(
createFinding({
title: `Cryptographic implementation lacks verification coverage for ${moduleDoc.module}`,
description: "Module docs describe encryption, hashing, or key management, but the current tests do not show evidence of cryptographic strength validation (algorithm checks, key rotation, salt uniqueness, or secure PRNG usage).",
impact: "high",
effort: "medium",
possible_solution_direction: "Add tests that verify password hashing uses bcrypt/argon2 with a sufficient cost factor, encryption uses a secure algorithm with a randomly generated IV, and tokens are generated with a cryptographically secure PRNG.",
how_to_reproduce: [
`Review ${moduleDoc.paths.join(", ")} for cryptographic operations.`,
"Check for MD5/SHA1 password hashing, hardcoded IVs, or Math.random() for token generation."
],
impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
evidence: [
...moduleDoc.paths.map((path10) => `Doc evidence: ${path10}`),
"No matching cryptographic strength or key management test evidence found for this module."
],
category: "cryptographic",
status: "open",
confidence: 0.67,
source_types: ["docs", "tests"],
affected_modules: [moduleDoc.module],
affected_packages: [],
runtime_required: false,
manual_follow_up: true
})
);
}
}
const loggingTests = extractRelevantTestPaths(tests, moduleDoc.module, [
"audit",
"log.assert",
"event.dispatch",
"trail",
"activity",
"log.entry",
"logged",
"event"
]);
if (hasAtLeast(lowered, 2, [
"log",
"audit",
"event",
"track",
"monitor",
"alert",
"sentry",
"activity"
])) {
if (loggingTests.length === 0) {
findings.push(
createFinding({
title: `Security-relevant actions lack audit logging evidence for ${moduleDoc.module}`,
description: "Module docs describe operations that should be audited (authentication, financial transactions, admin actions, or data exports), but the current tests do not show evidence of audit log assertions or event dispatch verification.",
impact: "medium",
effort: "medium",
possible_solution_direction: "Add tests that assert audit log entries are written for high-value actions with actor identity, IP, and timestamp. Verify sensitive data (passwords, tokens) is not included in log output.",
how_to_reproduce: [
`Review ${moduleDoc.paths.join(", ")} for operations that must be auditable.`,
"Check logging configuration and assert that log entries are created with sufficient context for forensic analysis."
],
impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
evidence: [
...moduleDoc.paths.map((path10) => `Doc evidence: ${path10}`),
"No matching audit logging or event dispatch test evidence found for this module."
],
category: "logging-monitoring",
status: "open",
confidence: 0.65,
source_types: ["docs", "tests"],
affected_modules: [moduleDoc.module],
affected_packages: [],
runtime_required: false,
manual_follow_up: false
})
);
}
}
}
return findings;
}
async function buildSecretFindings(artifactDir) {
const path10 = join112(artifactDir, "secrets", "matches.txt");
if (!existsSync56(path10)) {
return [];
}
const matches = parseSecretMatches(await readFile49(path10, "utf8"));
return matches.map(
(match, index) => createFinding({
title: `Potential secret exposure match ${index + 1}`,
description: "A generated secret scan found a suspicious credential or secret-like pattern in tracked project files.",
impact: match.includes("PRIVATE KEY") ? "high" : "medium",
effort: "low",
possible_solution_direction: "Verify whether the matched value is a real secret, rotate it if needed, and move sensitive data to environment or secret-manager storage.",
how_to_reproduce: [
"Run the project secret scan script and inspect the emitted matches.",
"Confirm whether the matched value is real, test data, or a false positive."
],
impact_area: [match.split(":").slice(0, 2).join(":")],
evidence: [match],
category: "secret-exposure",
status: "open",
confidence: 0.66,
source_types: ["code"],
affected_modules: [],
affected_packages: [],
runtime_required: false,
manual_follow_up: true
})
);
}
function buildRuntimeFindings(targetUrl, runtimeStatus, suspiciousRoutes) {
if (targetUrl === null || runtimeStatus.status === "blocked" || runtimeStatus.status === "not-configured") {
return [];
}
return suspiciousRoutes.map(
(route) => createFinding({
title: `Suspicious runtime surface exposed at ${route.path}`,
description: route.kind === "debug-surface" ? "A debug or observability endpoint appears reachable on the running local application." : route.kind === "sensitive-file" ? "A sensitive file path appears reachable on the running local application." : "An admin or high-value runtime surface appears reachable on the running local application.",
impact: route.kind === "sensitive-file" ? "high" : "medium",
effort: "medium",
possible_solution_direction: route.kind === "debug-surface" ? "Restrict the debug surface to local-only or authenticated access and verify it is disabled outside development." : "Restrict the route with authentication, authorization, or environment gating.",
how_to_reproduce: [
`Ensure the project is running locally at ${targetUrl}.`,
`Request ${targetUrl}${route.path} and verify the observed status ${route.status}.`
],
impact_area: [`runtime:${route.path}`],
evidence: [`Runtime probe observed ${route.path} with HTTP ${route.status}.`],
category: "runtime-surface",
status: "open",
confidence: 0.82,
source_types: ["runtime"],
affected_modules: [],
affected_packages: [],
runtime_required: true,
manual_follow_up: false
})
);
}
function assignFindingIds(findings) {
const seen = /* @__PURE__ */ new Map();
return findings.map((finding) => {
const fingerprint = findingFingerprint(finding);
const occurrence = (seen.get(fingerprint) ?? 0) + 1;
seen.set(fingerprint, occurrence);
return {
...finding,
id: occurrence === 1 ? `PT-${fingerprint}` : `PT-${fingerprint}-${String(occurrence).padStart(2, "0")}`
};
});
}
function buildRetestFindings(sourceFindings, currentFindings, runtimeStatus, blockedChecks) {
return sourceFindings.map((finding) => {
const retestStatus = evaluateRetestStatus(
finding,
currentFindings,
runtimeStatus,
blockedChecks
);
return {
...finding,
status: retestStatus,
retest_status: retestStatus
};
});
}
function evaluateRetestStatus(sourceFinding, currentFindings, runtimeStatus, blockedChecks) {
if (sourceFinding.runtime_required && (runtimeStatus.status === "blocked" || runtimeStatus.status === "not-configured" || blockedChecks.some((entry) => entry.toLowerCase().includes("runtime")))) {
return "needs-manual-verification";
}
const match = currentFindings.some((current) => {
if (current.category !== sourceFinding.category) {
return false;
}
if (sourceFinding.affected_packages.length > 0 && current.affected_packages.some((pkg) => sourceFinding.affected_packages.includes(pkg))) {
return true;
}
if (sourceFinding.affected_modules.length > 0 && current.affected_modules.some(
(moduleName) => sourceFinding.affected_modules.includes(moduleName)
)) {
return true;
}
return current.title === sourceFinding.title;
});
return match ? "still-open" : "fixed";
}
function hasAny(content, tokens) {
return tokens.some((token) => content.includes(token));
}
function hasAtLeast(content, count2, tokens) {
return tokens.filter((token) => content.includes(token)).length >= count2;
}
function normalizeImpact(content) {
const lowered = content.toLowerCase();
if (lowered.includes("critical") || lowered.includes("remote code execution") || lowered.includes("credential") || lowered.includes("auth bypass")) {
return "high";
}
if (lowered.includes("moderate") || lowered.includes("medium")) {
return "medium";
}
return "low";
}
function findingFingerprint(finding) {
const payload = JSON.stringify({
title: finding.title,
description: finding.description,
impact: finding.impact,
effort: finding.effort,
possible_solution_direction: finding.possible_solution_direction,
how_to_reproduce: [...finding.how_to_reproduce],
impact_area: [...finding.impact_area].sort(),
evidence: [...finding.evidence],
category: finding.category,
source_types: [...finding.source_types].sort(),
affected_modules: [...finding.affected_modules].sort(),
affected_packages: [...finding.affected_packages].sort(),
runtime_required: finding.runtime_required,
manual_follow_up: finding.manual_follow_up
});
return createHash16("sha256").update(payload).digest("hex").slice(0, 8).toUpperCase();
}
async function readNativeAuditFindings(artifactDir) {
const findings = [];
const dependencyDir = join112(artifactDir, "dependencies");
const npmAudit = await readJsonMaybe(join112(dependencyDir, "npm-audit.json"));
for (const [name, vulnerability] of Object.entries(npmAudit?.vulnerabilities ?? {})) {
const via = (vulnerability.via ?? []).find((entry) => typeof entry === "object");
findings.push({
package_name: vulnerability.name ?? name,
ecosystem: "npm",
version: vulnerability.range ?? "unknown",
advisory_id: String(via?.source ?? `${name}-npm-audit`),
summary: via?.title ?? `npm audit advisory for ${name}`,
details: via?.url ?? ""
});
}
const pnpmAudit = await readJsonMaybe(join112(dependencyDir, "pnpm-audit.json"));
for (const advisory of Object.values(pnpmAudit?.advisories ?? {})) {
findings.push({
package_name: advisory.module_name ?? "unknown",
ecosystem: "npm",
version: "unknown",
advisory_id: advisory.cves?.[0] ?? `${advisory.module_name ?? "unknown"}-pnpm-audit`,
summary: advisory.title ?? `pnpm audit advisory for ${advisory.module_name ?? "unknown"}`,
details: advisory.overview ?? ""
});
}
const composerAudit = await readJsonMaybe(join112(dependencyDir, "composer-audit.json"));
if (Array.isArray(composerAudit?.advisories)) {
for (const advisory of composerAudit.advisories) {
findings.push({
package_name: advisory.packageName ?? "unknown",
ecosystem: "Packagist",
version: "unknown",
advisory_id: advisory.advisoryId ?? `${advisory.packageName ?? "unknown"}-composer-audit`,
summary: advisory.title ?? `composer audit advisory for ${advisory.packageName ?? "unknown"}`,
details: advisory.link ?? ""
});
}
} else {
for (const [packageName, advisories] of Object.entries(composerAudit?.advisories ?? {})) {
for (const advisory of advisories) {
findings.push({
package_name: packageName,
ecosystem: "Packagist",
version: advisory.affectedVersions ?? "unknown",
advisory_id: advisory.advisoryId ?? `${packageName}-composer-audit`,
summary: advisory.title ?? `composer audit advisory for ${packageName}`,
details: advisory.link ?? ""
});
}
}
}
const seen = /* @__PURE__ */ new Set();
return findings.filter((finding) => {
const key = `${finding.package_name}:${finding.advisory_id}`;
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
async function readJsonMaybe(path10) {
if (!existsSync56(path10)) {
return null;
}
try {
return JSON.parse(await readFile49(path10, "utf8"));
} catch {
return null;
}
}
// src/pentest/report-builder.ts
init_esm_shims();
function buildPentestMarkdown(report) {
const findings = report.findings;
const summary = summarizeFindings2(findings);
const lines = [
`# ${report.report_id}`,
"",
`- Workflow: \`${report.workflow}\``,
`- Generated: \`${report.generated_at}\``,
`- Stack: \`${report.stack.primary}\``,
`- Traits: ${report.stack.traits.length > 0 ? report.stack.traits.map((trait) => `\`${trait}\``).join(", ") : "none"}`,
`- Runtime: \`${report.runtime.status}\`${report.runtime.target_url ? ` at \`${report.runtime.target_url}\`` : ""}`,
report.source_report_path ? `- Source Report: \`${report.source_report_path}\`` : "",
"",
"## Methodology and Coverage",
"",
...report.methodology.map((entry) => `- ${entry}`),
"",
`- Docs coverage: ${report.coverage.docs ? "yes" : "no"}`,
`- Tests coverage: ${report.coverage.tests ? "yes" : "no"}`,
`- Code coverage: ${report.coverage.code ? "yes" : "no"}`,
`- Runtime coverage: ${report.coverage.runtime ? "yes" : "no"}`,
`- Database coverage: ${report.coverage.database ? "yes" : "no"}`,
"",
"## Findings Summary",
"",
`- High: ${summary.high}`,
`- Medium: ${summary.medium}`,
`- Low: ${summary.low}`,
"",
"## Detailed Findings",
""
];
for (const finding of report.findings) {
lines.push(`### ${finding.id} \u2014 ${finding.title}`);
lines.push("");
lines.push(`- Impact: \`${finding.impact}\``);
lines.push(`- Effort: \`${finding.effort}\``);
lines.push(`- Status: \`${finding.status}\``);
if ("retest_status" in finding) {
lines.push(`- Retest: \`${finding.retest_status}\``);
}
lines.push(`- Confidence: \`${finding.confidence.toFixed(2)}\``);
lines.push(`- Category: \`${finding.category}\``);
lines.push("");
lines.push("#### Description");
lines.push("");
lines.push(finding.description);
lines.push("");
lines.push("#### Possible Solution Direction");
lines.push("");
lines.push(finding.possible_solution_direction);
lines.push("");
lines.push("#### How To Reproduce");
lines.push("");
lines.push(...finding.how_to_reproduce.map((entry) => `- ${entry}`));
lines.push("");
lines.push("#### Impact Area");
lines.push("");
lines.push(...finding.impact_area.map((entry) => `- ${entry}`));
lines.push("");
lines.push("#### Evidence");
lines.push("");
lines.push(...finding.evidence.map((entry) => `- ${entry}`));
lines.push("");
}
lines.push("## Blocked Checks / Coverage Gaps");
lines.push("");
if (report.blocked_checks.length === 0) {
lines.push("- none");
} else {
lines.push(...report.blocked_checks.map((entry) => `- ${entry}`));
}
lines.push("");
lines.push("## Sources Used");
lines.push("");
lines.push(...report.sources_used.map((entry) => `- ${entry}`));
lines.push("");
lines.push("## Next Remediation Priorities");
lines.push("");
lines.push(...report.next_remediation_priorities.map((entry) => `- ${entry}`));
lines.push("");
return `${lines.filter(Boolean).join("\n")}
`;
}
function remediationPriorities(findings) {
const priorities = findings.slice().sort((left, right) => severityRank(left.impact) - severityRank(right.impact)).slice(0, 5).map((finding) => `${finding.id}: ${finding.title}`);
return priorities.length > 0 ? priorities : ["No findings recorded."];
}
function summarizeFindings2(findings) {
return findings.reduce(
(summary, finding) => {
summary[finding.impact] += 1;
return summary;
},
{ high: 0, medium: 0, low: 0 }
);
}
function severityRank(impact) {
if (impact === "high") {
return 0;
}
if (impact === "medium") {
return 1;
}
return 2;
}
// src/workflows/pentest.ts
init_esm_shims();
import { mkdir as mkdir30, writeFile as writeFile31 } from "fs/promises";
import { join as join114, relative as relative20 } from "path";
// src/pentest/file-check-mapper.ts
init_esm_shims();
var GENERIC_SECURITY_MAP = [
{
glob: "**/auth*",
checks: ["permission-boundary-review", "runtime-surface-probing", "auth-mechanism-review"]
},
{ glob: "**/guard*", checks: ["permission-boundary-review"] },
{ glob: "**/.env*", checks: ["runtime-surface-probing", "cryptographic-review"] },
{ glob: "**/config*", checks: ["runtime-surface-probing"] },
{ glob: "**/jwt*", checks: ["auth-mechanism-review"] },
{ glob: "**/token*", checks: ["auth-mechanism-review"] },
{ glob: "**/passport*", checks: ["auth-mechanism-review"] },
{ glob: "**/session*", checks: ["auth-mechanism-review"] },
{ glob: "**/*.graphql", checks: ["input-validation-review", "permission-boundary-review"] },
{ glob: "**/schema.graphql", checks: ["input-validation-review", "permission-boundary-review"] },
{ glob: "**/resolvers/**", checks: ["input-validation-review", "permission-boundary-review"] },
{ glob: "**/log*", checks: ["logging-monitoring-review"] },
{ glob: "**/audit*", checks: ["logging-monitoring-review"] },
{ glob: "**/monitor*", checks: ["logging-monitoring-review"] },
{ glob: "**/*crypt*", checks: ["cryptographic-review"] },
{ glob: "**/*cipher*", checks: ["cryptographic-review"] },
{ glob: "**/*hash*", checks: ["cryptographic-review"] },
{ glob: "**/upload*", checks: ["input-validation-review"] },
{ glob: "**/file*", checks: ["input-validation-review"] }
];
var FileCheckMapper = class {
constructor(frameworks, projectRoot) {
this.frameworks = frameworks;
this.projectRoot = projectRoot;
}
frameworks;
projectRoot;
map(changedFiles) {
const mappings = this.getMappingsForStack();
const checks_to_run = /* @__PURE__ */ new Set();
const files_in_scope = [];
for (const file of changedFiles) {
for (const mapping of mappings) {
if (this.matchesGlob(file, mapping.glob)) {
for (const check2 of mapping.checks) {
checks_to_run.add(check2);
}
if (!files_in_scope.includes(file)) {
files_in_scope.push(file);
}
}
}
}
return {
checks_to_run,
files_in_scope,
no_security_changes: files_in_scope.length === 0
};
}
getMappingsForStack() {
const merged = /* @__PURE__ */ new Map();
for (const mapping of GENERIC_SECURITY_MAP) {
merged.set(mapping.glob, new Set(mapping.checks));
}
for (const pack of getPacksForFrameworks(this.frameworks, this.projectRoot)) {
for (const mapping of pack.manifest.pentest?.file_check_map ?? []) {
const checks = merged.get(mapping.glob) ?? /* @__PURE__ */ new Set();
for (const check2 of mapping.checks) {
checks.add(check2);
}
merged.set(mapping.glob, checks);
}
}
return Array.from(merged.entries()).map(([glob, checks]) => ({
glob,
checks: Array.from(checks)
}));
}
matchesGlob(file, pattern) {
const regexStr = globToRegexSource(pattern);
const regex = new RegExp(`(^|/)${regexStr}($|/)`);
return regex.test(file) || new RegExp(`^${regexStr}$`).test(file);
}
};
var REGEX_SPECIAL = /[\\^$.+?()[\]{}|]/;
function globToRegexSource(pattern) {
let source = "";
for (let index = 0; index < pattern.length; index += 1) {
const char = pattern[index];
if (char === "*") {
if (pattern[index + 1] === "*") {
source += ".*";
index += 1;
} else {
source += "[^/]*";
}
} else if (REGEX_SPECIAL.test(char)) {
source += `\\${char}`;
} else {
source += char;
}
}
return source;
}
// src/pentest/incremental-scanner.ts
init_esm_shims();
import { readFile as readFile50 } from "fs/promises";
import { join as join113 } from "path";
import { createHash as createHash17 } from "crypto";
var IncrementalScanner = class {
constructor(mapper) {
this.mapper = mapper;
}
mapper;
async scan(options) {
const changedFiles = await this.detectChangedFiles(options.projectRoot, options.lastRunId);
const narrowedScope = this.mapper.map(changedFiles);
await this.warnIfFullScanStale(
options.projectRoot,
options.fullScanStalenessThresholdDays ?? 14
);
return {
no_security_changes: narrowedScope.no_security_changes,
narrowed_scope: narrowedScope,
changed_files: changedFiles,
last_run_id: options.lastRunId
};
}
async detectChangedFiles(projectRoot, lastRunId) {
try {
const gitFiles = await this.gitDiff(projectRoot, lastRunId);
if (gitFiles.length > 0) {
return gitFiles;
}
const hashFiles = await this.hashDiff(projectRoot, lastRunId);
return hashFiles.length > 0 ? hashFiles : gitFiles;
} catch {
}
try {
return await this.hashDiff(projectRoot, lastRunId);
} catch {
return [];
}
}
async gitDiff(projectRoot, lastRunId) {
const progressPath = join113(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
let baseCommit;
try {
const raw = await readFile50(progressPath, "utf8");
const progress = JSON.parse(raw);
baseCommit = progress.git_commit;
} catch {
}
if (!baseCommit) {
baseCommit = "HEAD~1";
}
const result2 = await execa("git", ["diff", "--name-only", baseCommit], {
cwd: projectRoot
});
return result2.stdout.split("\n").map((f) => f.trim()).filter(Boolean);
}
async hashDiff(projectRoot, lastRunId) {
const manifestPath = join113(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
let fileManifest;
try {
const raw = await readFile50(manifestPath, "utf8");
const progress = JSON.parse(raw);
fileManifest = progress.file_hashes ?? {};
} catch {
return [];
}
const changed = [];
for (const [filePath, storedHash] of Object.entries(fileManifest)) {
try {
const content = await readFile50(join113(projectRoot, filePath), "utf8");
const currentHash = createHash17("sha256").update(content).digest("hex");
if (currentHash !== storedHash) {
changed.push(filePath);
}
} catch {
changed.push(filePath);
}
}
return changed;
}
async warnIfFullScanStale(projectRoot, thresholdDays) {
try {
const runsDir = join113(projectRoot, ".paqad", "pentest", "runs");
const { readdir: readdir8 } = await import("fs/promises");
const runs = await readdir8(runsDir).catch(() => []);
for (const run2 of runs.sort().reverse()) {
const progressPath = join113(runsDir, run2, "progress.json");
try {
const raw = await readFile50(progressPath, "utf8");
const progress = JSON.parse(raw);
if (!progress.incremental_type || progress.incremental_type === "full") {
const startedAt = new Date(progress.started_at ?? 0);
const ageDays = (Date.now() - startedAt.getTime()) / (1e3 * 60 * 60 * 24);
if (ageDays > thresholdDays) {
engineLog(
"warn",
`[pentest] Warning: Last full pentest was ${Math.floor(ageDays)} days ago. Consider running a full pentest (threshold: ${thresholdDays} days).`
);
}
return;
}
} catch {
}
}
} catch {
}
}
};
// src/workflows/pentest.ts
var PENTEST_STEPS = [
{ id: "collect-context", title: "Collect docs and test context" },
{ id: "run-project-scripts", title: "Run project-owned pentest scripts" },
{ id: "live-validation", title: "Run safe runtime validation" },
{ id: "synthesize-findings", title: "Normalize findings from collected evidence" },
{ id: "write-report", title: "Write canonical pentest report" }
];
var PENTEST_SKILLS = {
context: ["permission-boundary-review", "business-logic-abuse-review"],
dependency: ["dependency-advisory-triage"],
runtime: ["runtime-surface-probing"],
normalize: ["finding-normalizer"]
};
var PentestWorkflow = class {
introspector = new StackIntrospector();
tracker = new PentestProgressTracker();
async run(options) {
const snapshot = await this.introspector.snapshot(options.projectRoot);
const stack = getPrimaryStack({
routing: { domain: "coding" },
stack_profile: snapshot.profile
});
const targetUrl = options.targetUrl ?? extractUrlFromText(options.classification.request_text) ?? await discoverTargetUrl(options.projectRoot, stack);
const focusModules = options.focusModules ?? [];
if (options.incremental && options.lastRunId) {
const frameworks = [stack, ...snapshot.profile.traits];
const mapper = new FileCheckMapper(frameworks);
const scanner = new IncrementalScanner(mapper);
const scanResult = await scanner.scan({
projectRoot: options.projectRoot,
lastRunId: options.lastRunId,
frameworks
});
if (scanResult.no_security_changes) {
engineLog(
"info",
"[pentest] No security-relevant changes detected since last run. Skipping incremental pentest."
);
return {
run_id: options.lastRunId,
report_id: "",
report_path: "",
sidecar_path: ""
};
}
}
const progress = await this.tracker.ensureRun({
projectRoot: options.projectRoot,
workflow: "pentest",
targetUrl,
steps: [...PENTEST_STEPS]
});
progress.target_url = targetUrl ?? null;
progress.incremental_type = options.incremental ? "incremental" : "full";
await this.tracker.save(options.projectRoot, progress);
const artifactsDir = runArtifactsDir(options.projectRoot, progress.run_id);
const logsDir = runLogsDir(options.projectRoot, progress.run_id);
await mkdir30(artifactsDir, { recursive: true });
await mkdir30(logsDir, { recursive: true });
const blockedChecks = [];
const contextHash = await hashRelevantInputs(options.projectRoot, "pentest", {
focus_modules: focusModules
});
if (!this.tracker.shouldSkipStep(progress, "collect-context", contextHash)) {
this.tracker.markStepRunning(progress, "collect-context", contextHash);
await this.tracker.save(options.projectRoot, progress);
const docs = await loadModuleDocs(options.projectRoot, focusModules);
const tests = await loadTests(options.projectRoot, focusModules);
const docsPath = join114(artifactsDir, "docs-summary.json");
const testsPath = join114(artifactsDir, "tests-summary.json");
await writeJson(docsPath, docs);
await writeJson(
testsPath,
tests.map((test) => ({
path: test.path,
summary: test.content.slice(0, 500)
}))
);
this.tracker.markStepCompleted(
progress,
"collect-context",
[
toPosixPath(relative20(options.projectRoot, docsPath)),
toPosixPath(relative20(options.projectRoot, testsPath))
],
[...PENTEST_SKILLS.context].map(skillPath)
);
await this.tracker.save(options.projectRoot, progress);
}
const scriptHash = await hashRelevantInputs(options.projectRoot, "pentest", {
target_url: targetUrl,
db_connection_name: options.dbConnectionName
});
if (!this.tracker.shouldSkipStep(progress, "run-project-scripts", scriptHash)) {
this.tracker.markStepRunning(progress, "run-project-scripts", scriptHash);
await this.tracker.save(options.projectRoot, progress);
const scriptEnv = {
PENTEST_RUN_ID: progress.run_id,
PENTEST_ARTIFACT_DIR: artifactsDir,
PENTEST_TARGET_URL: targetUrl ?? "",
PENTEST_DB_CONNECTION_NAME: options.dbConnectionName ?? ""
};
const scriptResults = await Promise.all([
runProjectScript(options.projectRoot, "pentest-audit-dependencies.sh", scriptEnv, logsDir),
runProjectScript(options.projectRoot, "pentest-scan-secrets.sh", scriptEnv, logsDir),
runProjectScript(options.projectRoot, "pentest-enumerate-surface.sh", scriptEnv, logsDir),
runProjectScript(options.projectRoot, "pentest-db-readonly.sh", scriptEnv, logsDir)
]);
blockedChecks.push(...summarizeCommandAvailability(scriptResults));
this.tracker.markStepCompleted(
progress,
"run-project-scripts",
inferSourceArtifacts(artifactsDir, scriptResults),
[...PENTEST_SKILLS.dependency].map(skillPath)
);
await this.tracker.save(options.projectRoot, progress);
}
const runtimeHash = await hashRelevantInputs(options.projectRoot, "pentest", {
target_url: targetUrl,
step: "runtime"
});
if (!this.tracker.shouldSkipStep(progress, "live-validation", runtimeHash)) {
this.tracker.markStepRunning(progress, "live-validation", runtimeHash);
await this.tracker.save(options.projectRoot, progress);
const runtimeArtifacts = [];
if (targetUrl === null) {
blockedChecks.push(
"Runtime validation skipped because no local target URL could be discovered."
);
} else {
const result2 = await runProjectScript(
options.projectRoot,
"pentest-runtime-checks.sh",
{
PENTEST_RUN_ID: progress.run_id,
PENTEST_ARTIFACT_DIR: artifactsDir,
PENTEST_TARGET_URL: targetUrl
},
logsDir
);
runtimeArtifacts.push(...result2.artifact_paths);
if (result2.status !== "completed") {
blockedChecks.push(result2.summary);
}
}
this.tracker.markStepCompleted(
progress,
"live-validation",
runtimeArtifacts,
[...PENTEST_SKILLS.runtime].map(skillPath)
);
await this.tracker.save(options.projectRoot, progress);
}
const synthesizeHash = await hashRelevantInputs(options.projectRoot, "pentest", {
target_url: targetUrl,
focus_modules: focusModules,
step: "findings"
});
let report = null;
if (!this.tracker.shouldSkipStep(progress, "synthesize-findings", synthesizeHash)) {
this.tracker.markStepRunning(progress, "synthesize-findings", synthesizeHash);
await this.tracker.save(options.projectRoot, progress);
report = await buildCurrentPentestReport({
projectRoot: options.projectRoot,
classification: options.classification,
snapshot,
targetUrl,
focusModules,
blockedChecks,
artifactsDir,
progressRunId: progress.run_id,
reportTimestamp: new Date(progress.started_at)
});
const findingIndexPath = join114(
options.projectRoot,
PATHS.PENTEST_RUNS_DIR,
progress.run_id,
"finding-index.json"
);
await writeJson(findingIndexPath, report.findings);
this.tracker.markStepCompleted(
progress,
"synthesize-findings",
[
toPosixPath(relative20(options.projectRoot, findingIndexPath)),
...report.raw_evidence_paths
],
[...PENTEST_SKILLS.normalize].map(skillPath)
);
await this.tracker.save(options.projectRoot, progress);
}
if (report === null) {
const existingSidecar = progress.sidecar_path ? await readJsonIfExists(
join114(options.projectRoot, progress.sidecar_path)
) : null;
report = existingSidecar;
}
if (report === null) {
throw new Error("Pentest report synthesis did not produce a report payload");
}
const writeHash = await hashRelevantInputs(options.projectRoot, "pentest", {
findings: report.findings.map((finding) => finding.id),
step: "write-report"
});
if (!this.tracker.shouldSkipStep(progress, "write-report", writeHash)) {
this.tracker.markStepRunning(progress, "write-report", writeHash);
await this.tracker.save(options.projectRoot, progress);
await writeJson(
join114(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "report-preview.json"),
{ report_id: report.report_id, findings: report.findings.length }
);
await writeJson(join114(options.projectRoot, report.sidecar_path), report);
await writeJson(
join114(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "blocked-checks.json"),
report.blocked_checks
);
await mkdir30(join114(options.projectRoot, PATHS.PENTEST_DIR), { recursive: true });
const markdown = buildPentestMarkdown(report);
await writeJson(join114(options.projectRoot, report.sidecar_path), report);
await writeFile31(join114(options.projectRoot, report.report_path), markdown);
this.tracker.markStepCompleted(
progress,
"write-report",
[report.report_path, report.sidecar_path],
[...PENTEST_SKILLS.normalize].map(skillPath)
);
this.tracker.markRunCompleted(
progress,
report.report_path,
report.sidecar_path,
report.findings.map((finding) => finding.id)
);
await this.tracker.save(options.projectRoot, progress);
}
return {
run_id: progress.run_id,
report_id: report.report_id,
report_path: report.report_path,
sidecar_path: report.sidecar_path
};
}
};
async function buildCurrentPentestReport(input) {
const docs = await loadModuleDocs(input.projectRoot, input.focusModules);
const tests = await loadTests(input.projectRoot, input.focusModules);
const osvFindings = await queryOsv(input.snapshot.packages);
const osvPath = join114(input.artifactsDir, "dependencies", "osv-results.json");
await writeJson(osvPath, osvFindings);
const dependencyFindings = await buildDependencyFindings(
input.snapshot,
input.artifactsDir,
osvFindings
);
const moduleFindings = buildModuleFindings(docs, tests);
const secretFindings = await buildSecretFindings(input.artifactsDir);
const runtimePayload = await readJsonIfExists(join114(input.artifactsDir, "runtime", "runtime-checks.json"));
const runtimeStatus = input.targetUrl ? runtimePayload?.reachable ? {
target_url: input.targetUrl,
status: "reachable",
detail: runtimePayload.detail ?? "Runtime checks completed."
} : {
target_url: input.targetUrl,
status: "unreachable",
detail: runtimePayload?.detail ?? "Runtime checks could not confirm reachability."
} : {
target_url: null,
status: "not-configured",
detail: "No local target URL was configured or discovered."
};
const runtimeFindings = buildRuntimeFindings(
input.targetUrl,
runtimeStatus,
parseSuspiciousRoutes(runtimePayload?.checks ?? [])
);
const findings = assignFindingIds([
...dependencyFindings,
...moduleFindings,
...secretFindings,
...runtimeFindings
]);
const timestamp = toLocalTimestamp(input.reportTimestamp);
const reportPath2 = toPosixPath(join114(PATHS.PENTEST_DIR, `${timestamp}.md`));
const sidecarPath = toPosixPath(join114(PATHS.PENTEST_DIR, `${timestamp}.json`));
const stack = getPrimaryStack({
routing: { domain: "coding" },
stack_profile: input.snapshot.profile
});
return {
schema_version: "1",
generated_by: "paqad-ai",
framework_version: VERSION,
report_id: toReportId("PENTEST", input.reportTimestamp),
workflow: "pentest",
generated_at: input.reportTimestamp.toISOString(),
report_path: reportPath2,
sidecar_path: sidecarPath,
source_report_path: null,
source_report_id: null,
stack: {
primary: stack,
traits: [...input.snapshot.profile.traits],
toolchains: input.snapshot.toolchains.map(
(toolchain) => `${toolchain.ecosystem}:${toolchain.package_manager}`
)
},
runtime: runtimeStatus,
coverage: {
docs: docs.length > 0,
tests: tests.length > 0,
code: true,
runtime: input.targetUrl !== null,
database: false,
blocked_checks: [...input.blockedChecks]
},
findings,
blocked_checks: [...input.blockedChecks],
sources_used: [
`${PATHS.MODULES_DIR}/**`,
"tests/**",
...input.snapshot.toolchains.map((toolchain) => toolchain.lockfile),
...[
toolReferencePath(stack),
...Object.values(PENTEST_SKILLS).flat().map(skillPath),
...docs.flatMap((doc) => doc.paths)
]
],
methodology: [
"Used module docs, tests, code manifests, and lockfiles as the primary evidence layers.",
"Ran project-owned scripts for dependency audit, secret scanning, surface enumeration, and runtime validation when available.",
"Normalized advisories from native audits and OSV into stable findings."
],
next_remediation_priorities: remediationPriorities(findings),
raw_evidence_paths: [
toPosixPath(relative20(input.projectRoot, osvPath)),
...[
toPosixPath(join114(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "finding-index.json")),
toPosixPath(
join114(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "docs-summary.json")
),
toPosixPath(
join114(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "tests-summary.json")
)
]
]
};
}
function extractUrlFromText(requestText) {
const match = requestText.match(/https?:\/\/[^\s)]+/i);
return match?.[0] ?? null;
}
// src/workflows/pentest-retest.ts
var RETEST_STEPS = [
{ id: "load-source-report", title: "Load source pentest report" },
{ id: "rerun-evidence", title: "Collect fresh evidence for source findings" },
{ id: "evaluate-source-findings", title: "Evaluate source findings against current evidence" },
{ id: "write-report", title: "Write canonical pentest retest report" }
];
var RETEST_SKILLS = {
source: ["retest-verification"],
evaluate: ["retest-verification", "finding-normalizer"]
};
var PentestRetestWorkflow = class {
introspector = new StackIntrospector();
tracker = new PentestProgressTracker();
async run(options) {
const sourceReportPath = options.sourceReportPath ?? extractSourceReportPath(options.classification.request_text);
if (!sourceReportPath) {
throw new Error("Pentest retest requires an explicit source pentest report path");
}
const normalizedSourcePath = normalizeSidecarPath(sourceReportPath);
const sourceSidecar = await readJsonIfExists(
join115(options.projectRoot, normalizedSourcePath)
);
if (sourceSidecar === null) {
throw new Error(`Source pentest sidecar not found at ${normalizedSourcePath}`);
}
const snapshot = await this.introspector.snapshot(options.projectRoot);
const targetUrl = options.targetUrl ?? sourceSidecar.runtime.target_url ?? await discoverTargetUrl(options.projectRoot, sourceSidecar.stack.primary);
const progress = await this.tracker.ensureRun({
projectRoot: options.projectRoot,
workflow: "pentest-retest",
sourceReportPath: normalizedSourcePath,
targetUrl,
steps: [...RETEST_STEPS]
});
await this.tracker.save(options.projectRoot, progress);
const artifactsDir = runArtifactsDir(options.projectRoot, progress.run_id);
const logsDir = runLogsDir(options.projectRoot, progress.run_id);
const blockedChecks = [];
const sourceHash = await hashRelevantInputs(options.projectRoot, "pentest-retest", {
source_report_path: normalizedSourcePath,
target_url: targetUrl
});
if (!this.tracker.shouldSkipStep(progress, "load-source-report", sourceHash)) {
this.tracker.markStepRunning(progress, "load-source-report", sourceHash);
await this.tracker.save(options.projectRoot, progress);
const sourceCopy = join115(artifactsDir, "source-report.json");
await writeJson(sourceCopy, sourceSidecar);
this.tracker.markStepCompleted(
progress,
"load-source-report",
[
toPosixPath(
join115(PATHS.PENTEST_RUNS_DIR, progress.run_id, "artifacts", "source-report.json")
)
],
[...RETEST_SKILLS.source].map(skillPath)
);
await this.tracker.save(options.projectRoot, progress);
}
const rerunHash = await hashRelevantInputs(options.projectRoot, "pentest-retest", {
source_report_path: normalizedSourcePath,
target_url: targetUrl,
step: "rerun"
});
if (!this.tracker.shouldSkipStep(progress, "rerun-evidence", rerunHash)) {
this.tracker.markStepRunning(progress, "rerun-evidence", rerunHash);
await this.tracker.save(options.projectRoot, progress);
const scriptEnv = {
PENTEST_RUN_ID: progress.run_id,
PENTEST_ARTIFACT_DIR: artifactsDir,
PENTEST_TARGET_URL: targetUrl ?? "",
PENTEST_SOURCE_REPORT: join115(options.projectRoot, normalizedSourcePath),
PENTEST_DB_CONNECTION_NAME: options.dbConnectionName ?? ""
};
const scriptResults = await Promise.all([
runProjectScript(options.projectRoot, "pentest-retest.sh", scriptEnv, logsDir),
runProjectScript(options.projectRoot, "pentest-audit-dependencies.sh", scriptEnv, logsDir),
runProjectScript(options.projectRoot, "pentest-scan-secrets.sh", scriptEnv, logsDir),
runProjectScript(options.projectRoot, "pentest-runtime-checks.sh", scriptEnv, logsDir)
]);
blockedChecks.push(...summarizeCommandAvailability(scriptResults));
this.tracker.markStepCompleted(
progress,
"rerun-evidence",
scriptResults.flatMap((result2) => result2.artifact_paths),
[...RETEST_SKILLS.evaluate].map(skillPath)
);
await this.tracker.save(options.projectRoot, progress);
}
const evaluateHash = await hashRelevantInputs(options.projectRoot, "pentest-retest", {
source_report_path: normalizedSourcePath,
step: "evaluate"
});
let retestReport = null;
if (!this.tracker.shouldSkipStep(progress, "evaluate-source-findings", evaluateHash)) {
this.tracker.markStepRunning(progress, "evaluate-source-findings", evaluateHash);
await this.tracker.save(options.projectRoot, progress);
const currentReport = await buildCurrentPentestReport({
projectRoot: options.projectRoot,
classification: options.classification,
snapshot,
targetUrl,
focusModules: options.focusModules ?? [],
blockedChecks,
artifactsDir,
progressRunId: progress.run_id,
reportTimestamp: new Date(progress.started_at)
});
const retestFindings = buildRetestFindings(
sourceSidecar.findings,
currentReport.findings,
currentReport.runtime,
currentReport.blocked_checks
);
const timestamp = toLocalTimestamp(new Date(progress.started_at));
const sourceSlug = normalizedSourcePath.replace(/^docs\/pentest\//, "").replace(/\.json$/, "").replace(/[^a-zA-Z0-9._-]+/g, "-");
retestReport = {
...currentReport,
report_id: toReportId("RETEST", new Date(progress.started_at)),
workflow: "pentest-retest",
report_path: toPosixPath(join115(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.md`)),
sidecar_path: toPosixPath(
join115(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.json`)
),
source_report_path: normalizedSourcePath,
source_report_id: sourceSidecar.report_id,
findings: retestFindings,
next_remediation_priorities: remediationPriorities(
retestFindings.filter((finding) => finding.retest_status !== "fixed")
),
sources_used: [
normalizedSourcePath,
toolReferencePath(sourceSidecar.stack.primary),
...[...RETEST_SKILLS.source, ...RETEST_SKILLS.evaluate].map(skillPath)
]
};
const findingIndexPath = join115(
options.projectRoot,
PATHS.PENTEST_RUNS_DIR,
progress.run_id,
"finding-index.json"
);
await writeJson(findingIndexPath, retestFindings);
this.tracker.markStepCompleted(
progress,
"evaluate-source-findings",
[toPosixPath(join115(PATHS.PENTEST_RUNS_DIR, progress.run_id, "finding-index.json"))],
[...RETEST_SKILLS.evaluate].map(skillPath)
);
await this.tracker.save(options.projectRoot, progress);
}
if (retestReport === null) {
const existing = progress.sidecar_path ? await readJsonIfExists(
join115(options.projectRoot, progress.sidecar_path)
) : null;
retestReport = existing;
}
if (retestReport === null) {
throw new Error("Pentest retest did not produce a report payload");
}
const writeHash = await hashRelevantInputs(options.projectRoot, "pentest-retest", {
source_report_path: normalizedSourcePath,
findings: retestReport.findings.map((finding) => finding.id)
});
if (!this.tracker.shouldSkipStep(progress, "write-report", writeHash)) {
this.tracker.markStepRunning(progress, "write-report", writeHash);
await this.tracker.save(options.projectRoot, progress);
await writeJson(join115(options.projectRoot, retestReport.sidecar_path), retestReport);
await mkdir31(dirname43(join115(options.projectRoot, retestReport.report_path)), {
recursive: true
});
await writeFile32(
join115(options.projectRoot, retestReport.report_path),
buildPentestMarkdown(retestReport)
);
this.tracker.markStepCompleted(
progress,
"write-report",
[retestReport.report_path, retestReport.sidecar_path],
[...RETEST_SKILLS.evaluate].map(skillPath)
);
this.tracker.markRunCompleted(
progress,
retestReport.report_path,
retestReport.sidecar_path,
retestReport.findings.map((finding) => finding.id)
);
await this.tracker.save(options.projectRoot, progress);
}
return {
run_id: progress.run_id,
report_id: retestReport.report_id,
report_path: retestReport.report_path,
sidecar_path: retestReport.sidecar_path
};
}
};
var SOURCE_REPORT_PREFIX = "docs/pentest/";
var SOURCE_REPORT_RUN_END = /[\s)]/;
function extractSourceReportPath(requestText) {
let from = requestText.indexOf(SOURCE_REPORT_PREFIX);
while (from !== -1) {
const runStart = from + SOURCE_REPORT_PREFIX.length;
let runEnd = runStart;
while (runEnd < requestText.length && !SOURCE_REPORT_RUN_END.test(requestText[runEnd])) {
runEnd += 1;
}
const run2 = requestText.slice(runStart, runEnd);
const mdAt = run2.lastIndexOf(".md");
const jsonAt = run2.lastIndexOf(".json");
if (mdAt >= 1 || jsonAt >= 1) {
const end = mdAt > jsonAt ? mdAt + 3 : jsonAt + 5;
return requestText.slice(from, runStart + end);
}
from = requestText.indexOf(SOURCE_REPORT_PREFIX, Math.max(runEnd, from + 1));
}
return null;
}
function normalizeSidecarPath(path10) {
return path10.endsWith(".md") ? path10.replace(/\.md$/, ".json") : path10;
}
// src/workflows/root-cause-analysis.ts
init_esm_shims();
import { mkdir as mkdir32, writeFile as writeFile33 } from "fs/promises";
import { dirname as dirname44, join as join116 } from "path";
var DEFAULT_TITLE_SLUG = "root-cause-analysis";
var RCA_SECTIONS = [
"Summary",
"Problem Statement",
"Impact",
"Symptoms",
"Timeline",
"Root Cause",
"Contributing Factors",
"Evidence",
"Solution",
"Verification",
"Follow-Up Actions"
];
var RootCauseAnalysisWorkflow = class {
async run(options) {
const title = deriveTitle(options.classification.request_text);
const filename = `${toLocalTimestamp2(/* @__PURE__ */ new Date())}-${slugify3(title) || DEFAULT_TITLE_SLUG}.md`;
const relativePath = join116(PATHS.RCA_DIR, filename);
const outputPath = join116(options.projectRoot, relativePath);
await mkdir32(dirname44(outputPath), { recursive: true });
await writeFile33(outputPath, buildRcaDocument(title, options.classification));
return {
output_path: toPosixPath(relativePath),
title
};
}
};
function deriveTitle(requestText) {
const trimmed = requestText.trim().replace(/\s+/g, " ");
if (trimmed.length === 0) {
return "Root Cause Analysis";
}
return trimmed.length > 120 ? `${trimmed.slice(0, 117).trim()}...` : trimmed;
}
function buildRcaDocument(title, classification) {
const lines = [`# ${title}`, ""];
for (const section3 of RCA_SECTIONS) {
lines.push(`## ${section3}`);
if (section3 === "Problem Statement") {
lines.push(classification.request_text);
} else if (section3 === "Summary") {
lines.push(
`Workflow: ${classification.workflow}. Stack context: ${classification.domain}/${classification.stack}.`
);
} else if (section3 === "Solution") {
lines.push("Proposed or confirmed remediation goes here.");
} else {
lines.push("Pending analysis.");
}
lines.push("");
}
return `${lines.join("\n").trimEnd()}
`;
}
function toLocalTimestamp2(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`;
}
function slugify3(value) {
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
}
// src/workflows/types.ts
init_esm_shims();
// src/workflows/step-executor.ts
init_esm_shims();
var StepExecutor = class {
constructor(context, options = {}) {
this.context = context;
this.sessionId = options.sessionId ?? "default";
this.stackKey = options.stackKey ?? "default";
this.predictiveCache = options.predictiveCache;
this.skillCacheManager = options.skillCacheManager;
}
context;
sessionId;
stackKey;
predictiveCache;
skillCacheManager;
lastSkill;
shouldExecute(step) {
if (!step.condition) return true;
return this.evaluateCondition(step.condition, this.context.classification);
}
async execute(step, signal5) {
if (signal5?.aborted) {
throw new CancelledError();
}
if (!this.shouldExecute(step)) {
return { status: "skipped" };
}
try {
if (this.skillCacheManager) {
const cacheResult = await this.skillCacheManager.checkCache(step.skill, []);
if (cacheResult.hit) {
this.lastSkill = step.skill;
return { status: "completed" };
}
}
await this.runStep(_stepToExecutionPayload(step));
if (this.skillCacheManager) {
const inputHash = await this.skillCacheManager.computeInputHash([]);
await this.skillCacheManager.writeCache(step.skill, inputHash, null, []);
}
if (this.predictiveCache) {
const outputHash = String(Date.now());
const workflow = String(this.context.classification.workflow ?? "custom");
await this.predictiveCache.onSkillComplete(
this.sessionId,
this.stackKey,
workflow,
step.skill,
outputHash,
void 0
);
}
this.lastSkill = step.skill;
return { status: "completed" };
} catch (err) {
const error = err instanceof Error ? err.message : String(err);
return { status: "failed", error };
}
}
getLastSkill() {
return this.lastSkill;
}
async runStep(payload) {
throw new Error(
`No workflow skill runner is configured for "${payload.skill}". Custom workflow steps cannot be marked complete without execution.`
);
}
evaluateCondition(condition, classification) {
for (const [field, allowedValues] of Object.entries(condition)) {
const classValue = classification[field];
if (classValue === void 0) return false;
if (!Array.isArray(allowedValues)) continue;
if (!allowedValues.includes(classValue)) return false;
}
return true;
}
};
function _stepToExecutionPayload(step) {
return step;
}
// src/workflows/parallel-executor.ts
init_esm_shims();
var ABORTED = /* @__PURE__ */ Symbol("aborted");
var ParallelExecutor = class {
constructor(stepExecutor) {
this.stepExecutor = stepExecutor;
}
stepExecutor;
async execute(group, signal5) {
if (signal5?.aborted) {
return { results: [], overall: "cancelled" };
}
const onFailure = group.on_failure ?? "abort";
const raced = await this.raceAgainstAbort(this.executeGroup(group.parallel, signal5), signal5);
if (raced === ABORTED) {
return { results: [], overall: "cancelled" };
}
let results = raced;
if (results.some((result2) => result2.status === "failed")) {
if (onFailure === "retry") {
const retrySteps = group.parallel.filter((_, index) => results[index]?.status === "failed");
const retried = await this.executeGroup(retrySteps, signal5);
let retryIndex = 0;
results = results.map(
(result2) => result2.status === "failed" ? retried[retryIndex++] ?? result2 : result2
);
}
if (signal5?.aborted) {
return { results, overall: "cancelled" };
}
if (results.some((result2) => result2.status === "failed")) {
if (onFailure === "skip") {
return { results, overall: "skipped" };
}
return { results, overall: "failed" };
}
}
return { results, overall: "completed" };
}
async raceAgainstAbort(groupPromise, signal5) {
if (!signal5) {
return groupPromise;
}
const abortPromise = new Promise((resolve5) => {
if (signal5.aborted) {
resolve5(ABORTED);
return;
}
signal5.addEventListener("abort", () => resolve5(ABORTED), { once: true });
});
return Promise.race([groupPromise, abortPromise]);
}
async executeGroup(steps, signal5) {
const settled = await Promise.allSettled(
steps.map(async (step) => ({
skill: step.skill,
result: await this.stepExecutor.execute(step, signal5)
}))
);
return settled.map((s) => {
if (s.status === "fulfilled") {
return {
skill: s.value.skill,
status: s.value.result.status,
error: s.value.result.error
};
}
return {
skill: "unknown",
status: "failed",
error: s.reason instanceof Error ? s.reason.message : String(s.reason)
};
});
}
};
// src/workflows/engine.ts
init_esm_shims();
import { readFile as readFile51, writeFile as writeFile34, mkdir as mkdir33, rename as rename5 } from "fs/promises";
import { join as join117, dirname as dirname45 } from "path";
import { randomUUID as randomUUID3 } from "crypto";
var WorkflowEngine = class {
constructor(options) {
this.options = options;
this.loader = new WorkflowTemplateLoader(options.projectRoot);
this.validator = new WorkflowTemplateValidator();
}
options;
loader;
validator;
async getRegisteredWorkflowIds() {
return this.loader.list();
}
async run(templateName, context, options = {}) {
const template = await this.loadAndValidateTemplate(templateName);
const runId = randomUUID3();
const progress = this.initProgress(runId, template);
if (options.signal?.aborted) {
return this.cancelRun(progress, templateName);
}
await this.saveProgress(progress, templateName);
return this.executeSteps(template, progress, context, templateName, options.signal);
}
async resume(runId, templateName, context, options = {}) {
const existing = await this.loadProgress(runId, templateName);
if (!existing) {
throw new Error(`No run found with id "${runId}" for template "${templateName}"`);
}
return this.executeSteps(
await this.loadAndValidateTemplate(templateName),
existing,
context,
templateName,
options.signal
);
}
async executeSteps(template, progress, context, templateName, signal5) {
const stepExecutor = this.options.createStepExecutor?.(context) ?? new StepExecutor(context);
const parallelExecutor = new ParallelExecutor(stepExecutor);
for (let i = 0; i < template.steps.length; i++) {
if (signal5?.aborted) {
return this.cancelRun(progress, templateName);
}
const stepProgress = progress.steps[i];
if (!stepProgress || stepProgress.status === "completed" || stepProgress.status === "skipped") {
continue;
}
const step = template.steps[i];
stepProgress.status = "running";
stepProgress.started_at = (/* @__PURE__ */ new Date()).toISOString();
this.options.eventBus?.emit({
kind: "workflow-step-started",
at: (/* @__PURE__ */ new Date()).toISOString(),
runId: progress.run_id,
stepIndex: i,
skill: stepProgress.skill
});
await this.saveProgress(progress, templateName);
try {
if ("parallel" in step) {
const result2 = await parallelExecutor.execute(step, signal5);
if (result2.overall === "cancelled") {
return this.cancelRun(progress, templateName);
}
stepProgress.status = result2.overall === "completed" ? "completed" : result2.overall === "skipped" ? "skipped" : "failed";
stepProgress.error = result2.results.find((r) => r.status === "failed")?.error ?? null;
} else {
const result2 = await this.executeSequentialStep(stepExecutor, step, signal5);
stepProgress.status = result2.status;
stepProgress.error = result2.error ?? null;
}
} catch (error) {
if (error instanceof CancelledError) {
return this.cancelRun(progress, templateName);
}
throw error;
}
stepProgress.completed_at = (/* @__PURE__ */ new Date()).toISOString();
if (stepProgress.status === "failed") {
this.options.eventBus?.emit({
kind: "workflow-step-failed",
at: (/* @__PURE__ */ new Date()).toISOString(),
runId: progress.run_id,
stepIndex: i,
skill: stepProgress.skill,
error: stepProgress.error ?? "Workflow step failed"
});
} else {
this.options.eventBus?.emit({
kind: "workflow-step-completed",
at: (/* @__PURE__ */ new Date()).toISOString(),
runId: progress.run_id,
stepIndex: i,
skill: stepProgress.skill
});
}
await this.saveProgress(progress, templateName);
if (stepProgress.status === "failed") {
const onFailure = "on_failure" in step ? step.on_failure ?? "abort" : "abort";
if (onFailure === "abort") {
progress.status = "aborted";
await this.saveProgress(progress, templateName);
return progress;
}
}
}
progress.status = progress.steps.some((s) => s.status === "failed") ? "failed" : "completed";
await this.saveProgress(progress, templateName);
return progress;
}
initProgress(runId, template) {
const steps = template.steps.map((step, i) => ({
index: i,
skill: "skill" in step ? step.skill : null,
type: "parallel" in step ? "parallel" : "sequential",
status: "not_started",
started_at: null,
completed_at: null,
error: null
}));
return {
schema_version: "1",
run_id: runId,
template_name: template.name,
status: "running",
started_at: (/* @__PURE__ */ new Date()).toISOString(),
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
steps
};
}
progressPath(runId, templateName) {
return join117(
this.options.projectRoot,
".paqad",
"workflows",
templateName,
"runs",
runId,
"progress.json"
);
}
async saveProgress(progress, templateName) {
progress.updated_at = (/* @__PURE__ */ new Date()).toISOString();
const path10 = this.progressPath(progress.run_id, templateName);
await mkdir33(dirname45(path10), { recursive: true });
const tmp = `${path10}.tmp`;
await writeFile34(tmp, JSON.stringify(progress, null, 2), "utf8");
await rename5(tmp, path10);
}
async cancelRun(progress, templateName) {
progress.status = "cancelled";
progress.cancelled_steps_completed = progress.steps.filter(
(step) => step.status === "completed"
).length;
await this.saveProgress(progress, templateName);
appendRunCancelledEvent(this.options.projectRoot, progress.run_id, {
template_name: templateName,
cancelled_steps_completed: progress.cancelled_steps_completed
});
return progress;
}
async loadProgress(runId, templateName) {
try {
const raw = await readFile51(this.progressPath(runId, templateName), "utf8");
return JSON.parse(raw);
} catch {
return null;
}
}
async loadAndValidateTemplate(templateName) {
const template = await this.loader.load(templateName);
const { valid, errors } = this.validator.validate(template, this.options.availableSkills);
if (!valid) {
throw new Error(`Invalid workflow template "${templateName}": ${errors.join("; ")}`);
}
return template;
}
async executeSequentialStep(stepExecutor, step, signal5) {
if ("parallel" in step) {
throw new Error("executeSequentialStep requires a sequential workflow step");
}
const firstResult = await stepExecutor.execute(step, signal5);
if (firstResult.status !== "failed") {
return firstResult;
}
const onFailure = step.on_failure ?? "abort";
if (onFailure === "skip") {
return firstResult.error ? { status: "skipped", error: firstResult.error } : { status: "skipped" };
}
if (onFailure === "retry") {
const retryResult = await stepExecutor.execute(step, signal5);
return retryResult.error ? { status: retryResult.status, error: retryResult.error } : { status: retryResult.status };
}
return firstResult.error ? { status: "failed", error: firstResult.error } : { status: "failed" };
}
};
// src/index.ts
var VERSION = "1.128.1";
function getFrameworkName() {
return "paqad-ai";
}
export {
ANALYTICS_CONFLICTS,
conflictCategory,
analyticsFeatureDir,
analyticsIndexPath,
normalizeEventSlug,
analyticsEventDocPath,
groupBySlug,
buildEventDoc,
buildAnalyticsIndex,
syncAnalyticsDocs,
ANALYTICS_STRICTNESS_MODES,
DEFAULT_ANALYTICS_STRICTNESS,
resolveAnalyticsStrictness,
evaluateAnalyticsCompleteness,
evaluateAnalyticsCompletenessForProject,
TransitionLogManager,
CacheMetricsTracker,
CacheWarmer,
DEFAULT_PREDICTIVE_CACHE_OPTIONS,
PredictiveCache,
selectModelForTier,
ContextBudgetEnforcer,
TurnSummarizer,
findTouchedFilePaths,
InferredTurnClassifierModel,
PriorityClassifier,
ContextEvictor,
ContextBudgetOptimizer,
FileRegistryMapper,
DifferentialRefresh,
ContextHitTracker,
resolveActiveLineage,
RebuildFailedError,
rebuildApiConversation,
DEFAULT_REBUILD_CACHE_MAX_SIZE,
RebuildCache,
RelevanceScorer,
BudgetAllocator,
gateRetrieval,
WorkflowTemplateLoader,
SemanticLoader,
loadObligationIndex,
saveObligationIndex,
isEnoentError,
checkSpecCompliance,
assertComplianceSummaryInvariants,
BOUNDARY_SCHEMA_VERSION,
doctorObligationIndex,
doctorBoundaryReport,
doctorSpecReview,
loadSpecReviewReport,
saveSpecReviewReport,
generateVitestSkeletons,
renderVitestSkeleton,
detectBoundariesInSource,
extractUnhandledVariants,
generateBoundaryTests,
DEFAULT_BOUNDARY_REPORT_PATH,
buildBoundaryReport,
saveBoundaryReport,
loadBoundaryReport,
scanBoundaries,
CLASSIFICATION_RULES,
classifyDefect,
recordFromComplianceReport,
buildPatternAdvisories,
formatAgentContextWarnings,
SUPPORTED_DOMAINS,
SUPPORTED_STACKS,
SUPPORTED_CAPABILITIES,
HOOK_EXIT_CODES,
PAQAD_SCHEMA_VERSION,
REDACTION_PLACEHOLDER,
DEFAULT_REDACTION_ALLOWLIST,
redactFields,
createLogger,
loadLoggingConfig,
reloadLoggingConfig,
getEngineLogger,
buildExpertBriefs,
rosterEntryFor,
renderExpertBrief,
migrateFeatureEvidence,
migrationSessionId,
formatEvidenceMigration,
schemaMarkerPath,
schemaMigrationLogPath,
writeSchemaMarker,
writeSchemaMarkerSync,
readSchemaMarker,
readSchemaMarkerSync,
ensureSchemaMarkerSync,
checkSchemaCompatibility,
appendMigrationRecord,
withSchemaMigrationLock,
checkAndMigrateSchema,
CONTEXT_LEVELS,
ACTIVE_CAPABILITY_ORDER,
MANAGEABLE_ACTIVE_CAPABILITIES,
listAvailableActiveCapabilities,
isActiveCapability,
isManageableActiveCapability,
assertActiveCapability,
normalizeActiveCapabilities,
addActiveCapability,
removeActiveCapability,
DOC_TYPES,
HEALTH_CHECK_STATUSES,
HOOK_TRIGGERS,
STACK_ECOSYSTEMS,
STRUCTURED_TEST_FORMATS,
TEST_RUNNER_OUTPUT_SOURCES,
TEST_RUNNER_PARALLEL_MODES,
SINGLE_TEST_SELECTORS,
COMPLIANCE_RELATIONS,
COMPLIANCE_EVIDENCE_STRENGTHS,
PIPELINE_PHASES,
PENTEST_WORKFLOWS,
PENTEST_SEVERITIES,
PENTEST_EFFORTS,
PENTEST_RETEST_STATUSES,
PENTEST_FINDING_STATUSES,
PENTEST_SOURCE_TYPES,
PENTEST_RUN_STEP_STATUSES,
PENTEST_RUN_STATUSES,
REQUIREMENT_PRIORITIES,
REQUIREMENT_RISKS,
ESCALATION_MODES,
TICKET_PROVIDER_KINDS,
EMBEDDING_PROVIDER_NAMES,
DECISION_ASK_THRESHOLDS,
RESOLUTION_LAYERS,
REVIEW_TIERS,
REVIEW_MODES,
REVIEW_DIMENSIONS,
TIER_DIMENSIONS,
FINDING_SEVERITIES,
SKILL_MODEL_TIERS,
SKILL_OUTPUT_FORMATS,
STABILITY_LEVELS,
TEST_OUTPUT_SCHEMA_VERSION,
UNKNOWN_TEST_OUTPUT_TIMESTAMP,
TEST_ISSUE_CATEGORIES,
TEST_PARSE_STRATEGIES,
TOKEN_ARTIFACT_CLASSES,
ESCALATION_REASONS,
DISCLOSURE_LEVELS,
DISCLOSURE_ESCALATION_REASONS,
TASK_COMPLEXITIES,
RETRIEVAL_PATHS,
RETRIEVAL_ESCALATION_SIGNALS,
ROUTING_MECHANISMS,
ecosystemToLanguage,
buildDetectionReport,
AIDetector,
detectShortVideoSignals,
Detector,
toStackDetectionResource,
detectAnalyticsSignals,
detectFlutterSignals,
detectLaravelSignals,
detectReactSignals,
detectSvelteSignals,
detectVueSignals,
EngineEventBus,
PLACEHOLDER_DESIGN_TOKENS,
DESIGN_TOKENS_PLACEHOLDER_NOTE,
DesignTokensMissingError,
DesignTokensPlaceholderError,
DesignTokenService,
defaultManagedSettingsPaths,
defaultClaudeVersion,
maybeMigrateToPlugin,
recordMigrationSession,
rollbackPlugin,
claudeConfigDir,
runClaudeInstallWith,
runClaudePluginUninstall,
MCP_SERVERS,
getServersForStack,
McpServerRegistry,
SkillCacheManager,
buildCompactArtifact,
evaluateEscalation,
buildReasoningInputPayload,
applyDisclosurePolicy,
evaluateRetrievalGate,
runRoutingDecision,
buildControlLayerAudit,
createTestDelta,
createVerificationDelta,
createDriftDelta,
buildTestDeltaReasoningPayload,
buildVerificationDeltaReasoningPayload,
buildDriftDeltaReasoningPayload,
findPathSegmentsInRun,
__tokenEfficiencyInternals,
parseTestOutput,
__testOutputInternals,
DEFAULT_GROUNDING_BUDGET_MS,
readPipelineConfig,
expertsActive,
InvalidArgumentError,
Command,
resolveChecksFlakyMode,
createConfigCommand,
checkSpecShape,
installGitHooks,
DEFAULT_PR_BODY,
remoteDefaultBranch,
pendingMoveRefusal,
HealthChecker,
deriveOverallStatus,
bootstrapFrameworkHome,
bootstrapFramework,
frameworkSymlinkType,
__test,
VERSION_UNKNOWN,
MIN_CONSUMER_VERSION,
normalizeEngineVersion,
getEngineVersionReport,
compareConsumerCompatibility,
LEGACY_MCP_OUTPUT_PATHS,
McpConfigManager,
cleanupLegacyMcpFiles,
DataRetrievalDecider,
generateInitialRegistries,
discoverModules,
discoverBusinessModules,
generateModuleMapYaml,
serializeModuleMap,
loadModuleMap,
writeModuleMap,
cleanDiscoveredText,
normalizeForMatch,
isSlug,
sha256Text,
replaceMarkerBlock,
writeStackArtifacts,
refreshStackDocsFromInventory,
DocumentProgressTracker,
resetGeneratingEntries,
hashSourceFiles,
DocumentationWorkflow,
findBracePlaceholders,
extractModuleNamesFromRequest,
DocumentPipeline,
writeGeneratedFiles,
planGeneratedFiles,
appendPlanningAudit,
selectTestRunner,
resolvePackageEcosystem,
lockfileHash,
deriveTestingForProfile,
upsertStackDocCommandRow,
ARTIFACT_TYPES,
COLLISION_MAP,
ARTIFACT_OUTPUT_KEYS,
resolveCapabilityDirectories,
getInheritanceDirectories,
Resolver,
detectContractBoundaries,
injectContractBoundaryCriteria,
resolveDecisionPacket,
askThresholdForProject,
predictTokenCeiling,
appendCostEntry,
readCostLog,
buildCoverageOverlay,
markCriteriaFromOverlay,
queryMatchingDefectPatterns,
injectDefectAdvisoryCriteria,
mergeDeltaManifest,
computeDelta,
resolveDocTargets,
verifyFullSuite,
assembleIntelligence,
computePlanVsActual,
writePlanVsActual,
computeReconnect,
renderReconnectReport,
buildRegressionWatchList,
injectRuleCriteria,
emitTestSkeletons,
computeDependencyUsage,
resolveEntryPoints,
buildEdges,
loadModuleSlugResolver,
symbolKey,
computeReachability,
extractSymbols,
CODE_KNOWLEDGE_SCHEMA_VERSION,
SOURCE_GLOBS,
readSourceFiles,
buildCodeKnowledgeIndex,
removeObsoleteContractDocs,
writeGitignore,
writeWorktreeInclude,
dist_default5 as dist_default,
dist_default6 as dist_default2,
dist_default7 as dist_default3,
isNpmAvailable,
resolveSelections,
getStackPromptChoices,
renderStackConfirmationSummary,
source_default,
createRagProgressReporter,
OnboardingOrchestrator,
buildAgentConfigContext,
buildApiDocContext,
buildDesignSystemContext,
buildErrorCatalogContext,
buildIntegrationDocContext,
buildModuleScaffoldContext,
buildRegistryContext,
buildRunnerScriptContext,
TemplateRegistry,
generateDocumentationScaffold,
generateModuleScaffold,
queryOsv,
toLocalTimestamp,
slugify2 as slugify,
writeJson,
readJsonIfExists,
hashRelevantInputs,
discoverTargetUrl,
runProjectScript,
loadModuleDocs,
loadTests,
parseSuspiciousRoutes,
summarizeCommandAvailability,
inferSourceArtifacts,
skillPath,
toolReferencePath,
toReportId,
extractRelevantTestPaths,
parseSecretMatches,
safeBaseName,
PentestProgressTracker,
runArtifactsDir,
runLogsDir,
runStatusForSteps,
WorkflowRouterService,
TIER_TOKEN_LIMITS,
StreamTruncator,
ContextDeduplicator,
compareConfigurations,
evaluateBenchmarkGates,
toEphemeralCollectionId,
isAttachmentIndexingDegraded,
AttachmentPathError,
attachmentCollectionsRoot,
resolveCollectionDir,
collectionVectorPaths,
registerCollection,
deregisterCollection,
listCollections,
getCollectionId,
appendAttachmentEvent,
readAttachmentEvents,
PDF_PAGE_CAP,
ZIP_DECOMPRESSED_LIMIT_BYTES,
parseAttachment,
SessionAttachmentIndexer,
ATTACHMENT_RETRY_BUDGET_MS,
isIndexAttachmentFailure,
indexAttachment,
clearEphemeralCollection,
runOrphanSweep,
retrieveFromAttachments,
RunnerScriptGenerator,
buildSkillIndex,
generateSkillIndex,
writeSkillIndexFromArtifacts,
writeSkillIndex,
SkillLoader,
RuntimeSkillRegistry,
SkillTriggerEvaluator,
appendAuditLog,
appendAuditLogFailure,
removeGeneratedFiles,
withoutRemovedRetiredFiles,
FrameworkUpdater,
toVerificationSnapshots,
buildVerificationGateDeltaPayload,
buildDocumentationDriftDeltaPayload,
ArchitectureComplianceGate,
BehavioralCorrectnessGate,
collectScopeDriftPaths,
validateApiDoc,
validateErrorCatalogMarkdown,
validateSpecDocument,
validateUserFlow,
ChangeCompletenessGate,
CodeTestsLintGate,
DatabaseQualityGate,
DocumentationFreshnessGate,
SURFACE_DOC_PATH,
ExtensionSurfaceGate,
activeFeatureDirOrNull,
checksSessionId,
sessionChecksTarget,
readChecksReportForFeature,
writeChecksReportForFeature,
readVerificationEvidence,
buildEvidenceComment,
renderEvidenceMarkdown,
collectMachineFindings,
scopeFindingsToChange,
writeReviewDigest,
ImplementationReviewGate,
WorkflowTemplateValidator,
InstructionsDocsStructureGate,
ModuleDocsStructureGate,
RequirementCompletenessGate,
normalizeEvidence,
buildStatusOf,
locate,
collectMapEvidence,
collectVerificationFindings,
deriveMapFreshness,
stampMapFreshness,
isStale2 as isStale,
SiteMapFreshnessGate,
SpecReviewGate,
StoryQualityGate,
DEFAULT_GATE_CODES,
VerificationGateRunner,
computeTreeIdentityResult,
createBaseline,
writeQualityBaseline,
readQualityBaseline,
rollupModuleHealth,
collectQualityMeasures,
createDeliveryShell,
computeAcTestMapping,
computeImplementationReview,
computeSpecReview,
buildRepositoryVerificationContext,
writeFeatureDecisionsIndex,
designSignOffPrLine,
exportFeatureBundle,
pruneFeatureBundles,
featureReportEnabled,
writeFeatureReport,
resolveReportFeatureRef,
parseOsvScannerJson,
parseNpmAuditJson,
parseGitleaksJson,
parseJscpdJson,
builtinSecretScan,
gatherStaleDocCandidates,
runDuplicationScan,
raiseAuthoringDecision,
readAuthoringDecision,
option,
OVERRIDE_ADD_UNVERIFIED,
raiseOverrideDecision,
AGENT_PERMISSION_ALLOW,
raiseAgentPermissionDecision,
meetsThreshold,
withinLimit,
overlapScore,
findSubsetOverlaps,
lensFocus,
expertCollisions,
expertCollisionLine,
candidateText,
shadowingLine,
catalogBudget,
budgetWarningLine,
discoverInstalledSkills,
discoverInstalledAgents,
buildOverlapReport,
renderOverlapReport,
studlySkillName,
compareText,
sortFindings,
countFindings,
lintExitCode,
formatLintJson,
NeverWriteListError,
SkillLintUsageError,
contractScriptPaths,
isPaqadRuntimeSkill,
lintSkillFolder,
skillLintExitCode,
formatSkillLintJson,
WORKSPACE_ROOT,
TRACKED_ROOT,
AGENT_TRACKED_ROOT,
AuthoringRefusal,
validateAgentName,
stageById,
SkillWorkspace,
AgentWorkspace,
renderGateMarkdown,
MODE_FILE,
OVERRIDES_FILE,
readOverrides,
readMode,
setWaiting,
clearWaiting,
stageState,
allStageStates,
gateSatisfied,
requireEarlierGates,
AGENT_MEMORY_MAX_BYTES,
POWER_RULES,
AgentLintUsageError,
agentHookScripts,
bodyHeadingOrderProblem,
permissionPacketNamesFile,
PERMISSIONS_FILE,
readPermissionDecisionIds,
lintAgentInProject,
checkStageChain,
affectsBehaviour,
readChangeDiff,
behaviourChangeOf,
buildRepositoryVerificationVerdict,
formatVerdictSummary,
backstopGates,
runRepositoryVerification,
PatternRecorder,
PatternCli,
ANSWER_GROUNDING_STATES,
ANSWER_MODES,
CITATION_SOURCE_CLASSES,
extractKeywords,
scoreFile,
EvidenceRetriever,
FreshnessChecker,
ContradictionDetector,
ProjectKnowledgeAnswerer,
PentestWorkflow,
buildCurrentPentestReport,
PentestRetestWorkflow,
extractSourceReportPath,
RootCauseAnalysisWorkflow,
StepExecutor,
ParallelExecutor,
WorkflowEngine,
VERSION,
getFrameworkName
};