@caupulican/pi-adaptative 0.80.81 → 0.80.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/core/model-router/status.d.ts +1 -0
- package/dist/core/model-router/status.d.ts.map +1 -1
- package/dist/core/model-router/status.js +1 -0
- package/dist/core/model-router/status.js.map +1 -1
- package/dist/core/profile-registry.d.ts +2 -1
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +15 -0
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/settings-manager.d.ts +5 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +68 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +90 -3
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +12 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/resources.md +7 -1
- package/docs/settings.md +24 -2
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [0.80.82] - 2026-06-28
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- Added a configurable Model Router settings submenu for cheap/research, expensive/modify, and background
|
|
6
|
+
learning/reflection model roles, including project/global save scope support and profile-file
|
|
7
|
+
`modelRouter` overrides for situation-specific routing.
|
|
8
|
+
|
|
1
9
|
## [0.80.81] - 2026-06-28
|
|
2
10
|
|
|
3
11
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/core/model-router/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,eAAO,MAAM,iCAAiC,0BAA0B,CAAC;AAEzE,MAAM,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/core/model-router/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,eAAO,MAAM,iCAAiC,0BAA0B,CAAC;AAEzE,MAAM,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACvC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAuBF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,SAAI,GAAG,yBAAyB,EAAE,CAQ7G;AAED,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,yBAAyB,EACnC,YAAY,CAAC,EAAE,yBAAyB,EACxC,WAAW,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAyB,EACzD,eAAe,GAAE,yBAAyB,EAAO,EACjD,cAAc,CAAC,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,iBAAiB,GAC9B,MAAM,CA8BR","sourcesContent":["import type { SessionEntry } from \"../session-manager.ts\";\nimport type { ModelRouterIntent } from \"./intent-classifier.ts\";\n\nexport const MODEL_ROUTER_DECISION_CUSTOM_TYPE = \"model_router_decision\";\n\nexport type ModelRouterStatusSettings = {\n\tenabled: boolean;\n\tcheapModel?: string;\n\texpensiveModel?: string;\n\tlearningModel?: string;\n};\n\nexport type ModelRouterDecisionStatus = {\n\tintent: ModelRouterIntent;\n\troutedModel: string;\n\toutcome: \"routed\" | \"escalated\" | \"failed\";\n\tretryModel?: string;\n};\n\nfunction isModelRouterDecisionStatus(data: unknown): data is ModelRouterDecisionStatus {\n\tif (!data || typeof data !== \"object\") return false;\n\tconst record = data as Partial<ModelRouterDecisionStatus>;\n\treturn (\n\t\t(record.intent === \"research\" || record.intent === \"modify\") &&\n\t\ttypeof record.routedModel === \"string\" &&\n\t\t(record.outcome === \"routed\" || record.outcome === \"escalated\" || record.outcome === \"failed\") &&\n\t\t(record.retryModel === undefined || typeof record.retryModel === \"string\")\n\t);\n}\n\nfunction formatDecision(decision: ModelRouterDecisionStatus): string {\n\tlet text = `${decision.intent} -> ${decision.routedModel}`;\n\tif (decision.outcome === \"escalated\" && decision.retryModel) {\n\t\ttext += ` (escalated -> ${decision.retryModel})`;\n\t} else if (decision.outcome === \"failed\") {\n\t\ttext += \" (failed)\";\n\t}\n\treturn text;\n}\n\nexport function getRecentModelRouterDecisions(entries: SessionEntry[], limit = 3): ModelRouterDecisionStatus[] {\n\tconst decisions: ModelRouterDecisionStatus[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== MODEL_ROUTER_DECISION_CUSTOM_TYPE) continue;\n\t\tif (!isModelRouterDecisionStatus(entry.data)) continue;\n\t\tdecisions.push(entry.data);\n\t}\n\treturn decisions.slice(-limit);\n}\n\nexport function formatModelRouterStatus(\n\tsettings: ModelRouterStatusSettings,\n\tlastDecision?: ModelRouterDecisionStatus,\n\tformatLabel: (label: string) => string = (label) => label,\n\trecentDecisions: ModelRouterDecisionStatus[] = [],\n\tlastSkipReason?: string,\n\tlatestIntent?: ModelRouterIntent,\n): string {\n\tconst effectiveLastDecision = lastSkipReason ? undefined : lastDecision;\n\tconst lines = [\n\t\t`${formatLabel(\"Status:\")} ${settings.enabled ? \"enabled\" : \"disabled\"}`,\n\t\t`${formatLabel(\"Cheap model:\")} ${settings.cheapModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Expensive model:\")} ${settings.expensiveModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Learning model:\")} ${settings.learningModel ?? \"active\"}`,\n\t];\n\tif (!settings.enabled) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} inactive (disabled)`);\n\t} else if (lastSkipReason) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} skipped (${lastSkipReason})`);\n\t} else if (effectiveLastDecision) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} active`);\n\t} else {\n\t\tlines.push(`${formatLabel(\"Routing:\")} waiting for prompt`);\n\t}\n\tlines.push(`${formatLabel(\"Latest intent:\")} ${latestIntent ?? \"none\"}`);\n\tif (!effectiveLastDecision) {\n\t\tlines.push(`${formatLabel(\"Last decision:\")} none`);\n\t} else {\n\t\tlines.push(`${formatLabel(\"Last decision:\")} ${formatDecision(effectiveLastDecision)}`);\n\t}\n\tif (recentDecisions.length > 0) {\n\t\tlines.push(formatLabel(\"Recent decisions:\"));\n\t\tfor (const decision of recentDecisions) {\n\t\t\tlines.push(`- ${formatDecision(decision)}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -35,6 +35,7 @@ export function formatModelRouterStatus(settings, lastDecision, formatLabel = (l
|
|
|
35
35
|
`${formatLabel("Status:")} ${settings.enabled ? "enabled" : "disabled"}`,
|
|
36
36
|
`${formatLabel("Cheap model:")} ${settings.cheapModel ?? "unset"}`,
|
|
37
37
|
`${formatLabel("Expensive model:")} ${settings.expensiveModel ?? "unset"}`,
|
|
38
|
+
`${formatLabel("Learning model:")} ${settings.learningModel ?? "active"}`,
|
|
38
39
|
];
|
|
39
40
|
if (!settings.enabled) {
|
|
40
41
|
lines.push(`${formatLabel("Routing:")} inactive (disabled)`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/core/model-router/status.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,iCAAiC,GAAG,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/core/model-router/status.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionEntry } from \"../session-manager.ts\";\nimport type { ModelRouterIntent } from \"./intent-classifier.ts\";\n\nexport const MODEL_ROUTER_DECISION_CUSTOM_TYPE = \"model_router_decision\";\n\nexport type ModelRouterStatusSettings = {\n\tenabled: boolean;\n\tcheapModel?: string;\n\texpensiveModel?: string;\n\tlearningModel?: string;\n};\n\nexport type ModelRouterDecisionStatus = {\n\tintent: ModelRouterIntent;\n\troutedModel: string;\n\toutcome: \"routed\" | \"escalated\" | \"failed\";\n\tretryModel?: string;\n};\n\nfunction isModelRouterDecisionStatus(data: unknown): data is ModelRouterDecisionStatus {\n\tif (!data || typeof data !== \"object\") return false;\n\tconst record = data as Partial<ModelRouterDecisionStatus>;\n\treturn (\n\t\t(record.intent === \"research\" || record.intent === \"modify\") &&\n\t\ttypeof record.routedModel === \"string\" &&\n\t\t(record.outcome === \"routed\" || record.outcome === \"escalated\" || record.outcome === \"failed\") &&\n\t\t(record.retryModel === undefined || typeof record.retryModel === \"string\")\n\t);\n}\n\nfunction formatDecision(decision: ModelRouterDecisionStatus): string {\n\tlet text = `${decision.intent} -> ${decision.routedModel}`;\n\tif (decision.outcome === \"escalated\" && decision.retryModel) {\n\t\ttext += ` (escalated -> ${decision.retryModel})`;\n\t} else if (decision.outcome === \"failed\") {\n\t\ttext += \" (failed)\";\n\t}\n\treturn text;\n}\n\nexport function getRecentModelRouterDecisions(entries: SessionEntry[], limit = 3): ModelRouterDecisionStatus[] {\n\tconst decisions: ModelRouterDecisionStatus[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== MODEL_ROUTER_DECISION_CUSTOM_TYPE) continue;\n\t\tif (!isModelRouterDecisionStatus(entry.data)) continue;\n\t\tdecisions.push(entry.data);\n\t}\n\treturn decisions.slice(-limit);\n}\n\nexport function formatModelRouterStatus(\n\tsettings: ModelRouterStatusSettings,\n\tlastDecision?: ModelRouterDecisionStatus,\n\tformatLabel: (label: string) => string = (label) => label,\n\trecentDecisions: ModelRouterDecisionStatus[] = [],\n\tlastSkipReason?: string,\n\tlatestIntent?: ModelRouterIntent,\n): string {\n\tconst effectiveLastDecision = lastSkipReason ? undefined : lastDecision;\n\tconst lines = [\n\t\t`${formatLabel(\"Status:\")} ${settings.enabled ? \"enabled\" : \"disabled\"}`,\n\t\t`${formatLabel(\"Cheap model:\")} ${settings.cheapModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Expensive model:\")} ${settings.expensiveModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Learning model:\")} ${settings.learningModel ?? \"active\"}`,\n\t];\n\tif (!settings.enabled) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} inactive (disabled)`);\n\t} else if (lastSkipReason) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} skipped (${lastSkipReason})`);\n\t} else if (effectiveLastDecision) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} active`);\n\t} else {\n\t\tlines.push(`${formatLabel(\"Routing:\")} waiting for prompt`);\n\t}\n\tlines.push(`${formatLabel(\"Latest intent:\")} ${latestIntent ?? \"none\"}`);\n\tif (!effectiveLastDecision) {\n\t\tlines.push(`${formatLabel(\"Last decision:\")} none`);\n\t} else {\n\t\tlines.push(`${formatLabel(\"Last decision:\")} ${formatDecision(effectiveLastDecision)}`);\n\t}\n\tif (recentDecisions.length > 0) {\n\t\tlines.push(formatLabel(\"Recent decisions:\"));\n\t\tfor (const decision of recentDecisions) {\n\t\t\tlines.push(`- ${formatDecision(decision)}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@caupulican/pi-agent-core";
|
|
2
|
-
import type { ResourceProfileSettings, Settings } from "./settings-manager.ts";
|
|
2
|
+
import type { ModelRouterSettings, ResourceProfileSettings, Settings } from "./settings-manager.ts";
|
|
3
3
|
export type ProfileSource = "global-settings" | "project-settings" | "profile-file" | "directory-overlay" | "inline" | "embedded" | "bundle";
|
|
4
4
|
export interface NormalizedProfile {
|
|
5
5
|
name: string;
|
|
6
6
|
description?: string;
|
|
7
7
|
model?: string;
|
|
8
8
|
thinking?: ThinkingLevel;
|
|
9
|
+
modelRouter?: ModelRouterSettings;
|
|
9
10
|
/** Situational identity injected into the system prompt while this profile is active (R6). */
|
|
10
11
|
soul?: string;
|
|
11
12
|
resources: ResourceProfileSettings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-registry.d.ts","sourceRoot":"","sources":["../../src/core/profile-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAM/D,OAAO,KAAK,EAAuB,uBAAuB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGpG,MAAM,MAAM,aAAa,GACtB,iBAAiB,GACjB,kBAAkB,GAClB,cAAc,GACd,mBAAmB,GACnB,QAAQ,GACR,UAAU,GACV,QAAQ,CAAC;AAEZ,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,8FAA8F;IAC9F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACzC,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACtC,cAAc,EAAE,QAAQ,CAAC;IACzB,eAAe,EAAE,QAAQ,CAAC;IAC1B,wBAAwB,EAAE,QAAQ,CAAC;IACnC,gCAAgC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAC1E,oCAAoC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAqID,qBAAa,eAAe;IAC3B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,WAAW,CAAmC;IAEtD,YAAY,OAAO,EAAE,sBAAsB,EAE1C;IAED,eAAe,IAAI,yBAAyB,EAAE,CAG7C;IAED,YAAY,IAAI,iBAAiB,EAAE,CAgBlC;IAED,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAItD;IAED,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAQ7E;IAED,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,gBAAgB;IA8CxB,OAAO,CAAC,eAAe;CAuBvB","sourcesContent":["import type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { mergeResourceProfileSettings } from \"./resource-profile-blocks.ts\";\nimport type { ResourceProfileKind, ResourceProfileSettings, Settings } from \"./settings-manager.ts\";\nimport { validateSkillName } from \"./skills.ts\";\n\nexport type ProfileSource =\n\t| \"global-settings\"\n\t| \"project-settings\"\n\t| \"profile-file\"\n\t| \"directory-overlay\"\n\t| \"inline\"\n\t| \"embedded\"\n\t| \"bundle\";\n\nexport interface NormalizedProfile {\n\tname: string;\n\tdescription?: string;\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n\t/** Situational identity injected into the system prompt while this profile is active (R6). */\n\tsoul?: string;\n\tresources: ResourceProfileSettings;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n}\n\nexport interface ProfileRegistryDiagnostic {\n\tsource: ProfileSource;\n\tpath?: string;\n\tmessage: string;\n}\n\nexport interface ProfileRegistryOptions {\n\tglobalSettings: Settings;\n\tprojectSettings: Settings;\n\tdirectoryProfileSettings: Settings;\n\tinlineResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tdiscoveredResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tprofilesDir?: string;\n\texternalResourceRoots?: string[];\n}\n\nconst RESOURCE_PROFILE_KINDS: ResourceProfileKind[] = [\"extensions\", \"skills\", \"prompts\", \"themes\", \"agents\", \"tools\"];\n\ninterface ProfileCandidate {\n\tprofile: NormalizedProfile;\n\tprecedence: number;\n\torder: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction asNonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst strings = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n\treturn strings.length > 0 ? strings : undefined;\n}\n\nfunction shouldResolveAgainstBaseDir(pattern: string): boolean {\n\treturn pattern.startsWith(\"./\") || pattern.startsWith(\"../\");\n}\n\nfunction normalizePattern(pattern: string, baseDir: string | undefined): string {\n\tconst trimmed = pattern.trim();\n\tif (!baseDir || !shouldResolveAgainstBaseDir(trimmed)) return trimmed;\n\treturn resolvePath(trimmed, baseDir, { trim: true });\n}\n\nfunction normalizeStringArray(value: unknown, baseDir: string | undefined): string[] | undefined {\n\tconst strings = asStringArray(value);\n\tif (!strings) return undefined;\n\treturn strings.map((pattern) => normalizePattern(pattern, baseDir));\n}\n\nfunction normalizeResourceProfileSettings(value: unknown, baseDir: string | undefined): ResourceProfileSettings {\n\tif (!isRecord(value)) {\n\t\tthrow new Error(\"resources must be an object\");\n\t}\n\tconst result: ResourceProfileSettings = {};\n\tfor (const kind of RESOURCE_PROFILE_KINDS) {\n\t\tconst filterValue = value[kind];\n\t\tif (filterValue === undefined) continue;\n\t\tif (!isRecord(filterValue)) {\n\t\t\tthrow new Error(`${kind} filter must be an object`);\n\t\t}\n\t\tconst allow = normalizeStringArray(filterValue.allow, baseDir);\n\t\tconst block = normalizeStringArray(filterValue.block, baseDir);\n\t\tresult[kind] = { allow, block };\n\t}\n\treturn result;\n}\n\nfunction validateProfileName(name: string): string[] {\n\treturn validateSkillName(name);\n}\n\nfunction normalizeThinking(value: unknown): ThinkingLevel | undefined {\n\tconst thinking = asNonEmptyString(value);\n\tif (!thinking) return undefined;\n\tif (!isValidThinkingLevel(thinking)) {\n\t\tthrow new Error(`thinking must be one of off, minimal, low, medium, high, xhigh`);\n\t}\n\treturn thinking;\n}\n\nfunction normalizeWrapperProfile(options: {\n\tvalue: unknown;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n\tfallbackName?: string;\n}): NormalizedProfile {\n\tif (!isRecord(options.value)) {\n\t\tthrow new Error(\"profile JSON must be an object\");\n\t}\n\tconst name = asNonEmptyString(options.value.name) ?? options.fallbackName;\n\tif (!name) {\n\t\tthrow new Error(\"profile name is required\");\n\t}\n\tconst nameErrors = validateProfileName(name);\n\tif (nameErrors.length > 0) {\n\t\tthrow new Error(`invalid profile name \"${name}\": ${nameErrors.join(\", \")}`);\n\t}\n\tconst resources = normalizeResourceProfileSettings(options.value.resources ?? {}, options.baseDir);\n\tconst description = asNonEmptyString(options.value.description);\n\tconst model = asNonEmptyString(options.value.model);\n\tconst thinking = normalizeThinking(options.value.thinking);\n\tconst soul = asNonEmptyString(options.value.soul);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmodel,\n\t\tthinking,\n\t\tsoul,\n\t\tresources,\n\t\tsource: options.source,\n\t\tsourcePath: options.sourcePath,\n\t\tbaseDir: options.baseDir,\n\t};\n}\n\nfunction normalizeSettingsProfiles(\n\tsettings: Settings,\n\tsource: ProfileSource,\n): Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> {\n\tconst profiles: Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> = [];\n\tfor (const [name, resources] of Object.entries(settings.resourceProfiles ?? {})) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources) });\n\t}\n\treturn profiles.map((profile) => ({ ...profile, source }));\n}\n\nfunction normalizeDefinitions(\n\tdefinitions: Record<string, ResourceProfileSettings>,\n\tsource: ProfileSource,\n): NormalizedProfile[] {\n\tconst profiles: NormalizedProfile[] = [];\n\tfor (const [name, resources] of Object.entries(definitions)) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources), source });\n\t}\n\treturn profiles;\n}\n\nexport class ProfileRegistry {\n\tprivate options: ProfileRegistryOptions;\n\tprivate diagnostics: ProfileRegistryDiagnostic[] = [];\n\n\tconstructor(options: ProfileRegistryOptions) {\n\t\tthis.options = options;\n\t}\n\n\tlistDiagnostics(): ProfileRegistryDiagnostic[] {\n\t\tthis.collectCandidates();\n\t\treturn [...this.diagnostics];\n\t}\n\n\tlistProfiles(): NormalizedProfile[] {\n\t\tconst candidates = this.collectCandidates();\n\t\tconst winners = new Map<string, ProfileCandidate>();\n\t\tfor (const candidate of candidates) {\n\t\t\tconst existing = winners.get(candidate.profile.name);\n\t\t\tif (\n\t\t\t\t!existing ||\n\t\t\t\tcandidate.precedence < existing.precedence ||\n\t\t\t\t(candidate.precedence === existing.precedence && candidate.order < existing.order)\n\t\t\t) {\n\t\t\t\twinners.set(candidate.profile.name, candidate);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(winners.values())\n\t\t\t.sort((a, b) => a.profile.name.localeCompare(b.profile.name))\n\t\t\t.map((candidate) => candidate.profile);\n\t}\n\n\tgetProfile(name: string): NormalizedProfile | undefined {\n\t\tconst trimmed = name.trim();\n\t\tif (!trimmed) return undefined;\n\t\treturn this.listProfiles().find((profile) => profile.name === trimmed);\n\t}\n\n\tresolveProfileRef(ref: string, fromDir: string): NormalizedProfile | undefined {\n\t\tconst trimmed = ref.trim();\n\t\tif (!trimmed) return undefined;\n\t\tif (trimmed.startsWith(\"./\") || trimmed.startsWith(\"../\")) {\n\t\t\tconst sourcePath = resolvePath(trimmed, fromDir, { trim: true });\n\t\t\treturn this.loadProfileFile(sourcePath, \"profile-file\", 0)?.profile;\n\t\t}\n\t\treturn this.getProfile(trimmed);\n\t}\n\n\tprivate collectCandidates(): ProfileCandidate[] {\n\t\tthis.diagnostics = [];\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\t\tconst add = (profile: NormalizedProfile, precedence: number): void => {\n\t\t\tcandidates.push({ profile, precedence, order: order++ });\n\t\t};\n\n\t\tfor (const profile of normalizeDefinitions(this.options.inlineResourceProfileDefinitions, \"inline\")) {\n\t\t\tadd(profile, 1);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.directoryProfileSettings, \"directory-overlay\")) {\n\t\t\tadd({ ...profile, source: \"directory-overlay\" }, 2);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.projectSettings, \"project-settings\")) {\n\t\t\tadd({ ...profile, source: \"project-settings\" }, 3);\n\t\t}\n\t\tfor (const profile of this.loadProfileFiles()) {\n\t\t\tadd(profile.profile, profile.precedence);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.globalSettings, \"global-settings\")) {\n\t\t\tadd({ ...profile, source: \"global-settings\" }, 5);\n\t\t}\n\t\tfor (const profile of normalizeDefinitions(this.options.discoveredResourceProfileDefinitions, \"embedded\")) {\n\t\t\tadd(profile, 6);\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFiles(): ProfileCandidate[] {\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\n\t\tconst profilesDir = this.options.profilesDir;\n\t\tif (profilesDir && existsSync(profilesDir)) {\n\t\t\ttry {\n\t\t\t\tconst entries = readdirSync(profilesDir)\n\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t.sort();\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tconst sourcePath = join(profilesDir, entry);\n\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4 });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: profilesDir, message: String(error) });\n\t\t\t}\n\t\t}\n\n\t\tconst externalRoots = this.options.externalResourceRoots ?? [];\n\t\tfor (const root of externalRoots) {\n\t\t\tconst extProfilesDir = join(root, \"profiles\");\n\t\t\tif (existsSync(extProfilesDir)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst entries = readdirSync(extProfilesDir)\n\t\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t\t.sort();\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst sourcePath = join(extProfilesDir, entry);\n\t\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4.1 });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: extProfilesDir, message: String(error) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFile(sourcePath: string, source: ProfileSource, order: number): ProfileCandidate | undefined {\n\t\ttry {\n\t\t\tconst stats = statSync(sourcePath);\n\t\t\tif (!stats.isFile()) return undefined;\n\t\t\tconst parsed = JSON.parse(readFileSync(sourcePath, \"utf-8\"));\n\t\t\tconst fallbackName = basename(sourcePath, \".json\");\n\t\t\treturn {\n\t\t\t\tprofile: normalizeWrapperProfile({\n\t\t\t\t\tvalue: parsed,\n\t\t\t\t\tsource,\n\t\t\t\t\tsourcePath: resolve(sourcePath),\n\t\t\t\t\tbaseDir: dirname(resolve(sourcePath)),\n\t\t\t\t\tfallbackName,\n\t\t\t\t}),\n\t\t\t\tprecedence: 0,\n\t\t\t\torder,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.diagnostics.push({ source, path: sourcePath, message });\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"profile-registry.d.ts","sourceRoot":"","sources":["../../src/core/profile-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAM/D,OAAO,KAAK,EACX,mBAAmB,EAEnB,uBAAuB,EACvB,QAAQ,EACR,MAAM,uBAAuB,CAAC;AAG/B,MAAM,MAAM,aAAa,GACtB,iBAAiB,GACjB,kBAAkB,GAClB,cAAc,GACd,mBAAmB,GACnB,QAAQ,GACR,UAAU,GACV,QAAQ,CAAC;AAEZ,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,8FAA8F;IAC9F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACzC,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACtC,cAAc,EAAE,QAAQ,CAAC;IACzB,eAAe,EAAE,QAAQ,CAAC;IAC1B,wBAAwB,EAAE,QAAQ,CAAC;IACnC,gCAAgC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAC1E,oCAAoC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAkJD,qBAAa,eAAe;IAC3B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,WAAW,CAAmC;IAEtD,YAAY,OAAO,EAAE,sBAAsB,EAE1C;IAED,eAAe,IAAI,yBAAyB,EAAE,CAG7C;IAED,YAAY,IAAI,iBAAiB,EAAE,CAgBlC;IAED,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAItD;IAED,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAQ7E;IAED,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,gBAAgB;IA8CxB,OAAO,CAAC,eAAe;CAuBvB","sourcesContent":["import type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { mergeResourceProfileSettings } from \"./resource-profile-blocks.ts\";\nimport type {\n\tModelRouterSettings,\n\tResourceProfileKind,\n\tResourceProfileSettings,\n\tSettings,\n} from \"./settings-manager.ts\";\nimport { validateSkillName } from \"./skills.ts\";\n\nexport type ProfileSource =\n\t| \"global-settings\"\n\t| \"project-settings\"\n\t| \"profile-file\"\n\t| \"directory-overlay\"\n\t| \"inline\"\n\t| \"embedded\"\n\t| \"bundle\";\n\nexport interface NormalizedProfile {\n\tname: string;\n\tdescription?: string;\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n\tmodelRouter?: ModelRouterSettings;\n\t/** Situational identity injected into the system prompt while this profile is active (R6). */\n\tsoul?: string;\n\tresources: ResourceProfileSettings;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n}\n\nexport interface ProfileRegistryDiagnostic {\n\tsource: ProfileSource;\n\tpath?: string;\n\tmessage: string;\n}\n\nexport interface ProfileRegistryOptions {\n\tglobalSettings: Settings;\n\tprojectSettings: Settings;\n\tdirectoryProfileSettings: Settings;\n\tinlineResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tdiscoveredResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tprofilesDir?: string;\n\texternalResourceRoots?: string[];\n}\n\nconst RESOURCE_PROFILE_KINDS: ResourceProfileKind[] = [\"extensions\", \"skills\", \"prompts\", \"themes\", \"agents\", \"tools\"];\n\ninterface ProfileCandidate {\n\tprofile: NormalizedProfile;\n\tprecedence: number;\n\torder: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction asNonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst strings = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n\treturn strings.length > 0 ? strings : undefined;\n}\n\nfunction shouldResolveAgainstBaseDir(pattern: string): boolean {\n\treturn pattern.startsWith(\"./\") || pattern.startsWith(\"../\");\n}\n\nfunction normalizePattern(pattern: string, baseDir: string | undefined): string {\n\tconst trimmed = pattern.trim();\n\tif (!baseDir || !shouldResolveAgainstBaseDir(trimmed)) return trimmed;\n\treturn resolvePath(trimmed, baseDir, { trim: true });\n}\n\nfunction normalizeStringArray(value: unknown, baseDir: string | undefined): string[] | undefined {\n\tconst strings = asStringArray(value);\n\tif (!strings) return undefined;\n\treturn strings.map((pattern) => normalizePattern(pattern, baseDir));\n}\n\nfunction normalizeResourceProfileSettings(value: unknown, baseDir: string | undefined): ResourceProfileSettings {\n\tif (!isRecord(value)) {\n\t\tthrow new Error(\"resources must be an object\");\n\t}\n\tconst result: ResourceProfileSettings = {};\n\tfor (const kind of RESOURCE_PROFILE_KINDS) {\n\t\tconst filterValue = value[kind];\n\t\tif (filterValue === undefined) continue;\n\t\tif (!isRecord(filterValue)) {\n\t\t\tthrow new Error(`${kind} filter must be an object`);\n\t\t}\n\t\tconst allow = normalizeStringArray(filterValue.allow, baseDir);\n\t\tconst block = normalizeStringArray(filterValue.block, baseDir);\n\t\tresult[kind] = { allow, block };\n\t}\n\treturn result;\n}\n\nfunction validateProfileName(name: string): string[] {\n\treturn validateSkillName(name);\n}\n\nfunction normalizeThinking(value: unknown): ThinkingLevel | undefined {\n\tconst thinking = asNonEmptyString(value);\n\tif (!thinking) return undefined;\n\tif (!isValidThinkingLevel(thinking)) {\n\t\tthrow new Error(`thinking must be one of off, minimal, low, medium, high, xhigh`);\n\t}\n\treturn thinking;\n}\n\nfunction normalizeModelRouterSettings(value: unknown): ModelRouterSettings | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst settings: ModelRouterSettings = {};\n\tif (typeof value.enabled === \"boolean\") settings.enabled = value.enabled;\n\tfor (const key of [\"cheapModel\", \"expensiveModel\", \"learningModel\"] as const) {\n\t\tconst candidate = asNonEmptyString(value[key]);\n\t\tif (candidate) settings[key] = candidate;\n\t}\n\treturn Object.keys(settings).length > 0 ? settings : undefined;\n}\n\nfunction normalizeWrapperProfile(options: {\n\tvalue: unknown;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n\tfallbackName?: string;\n}): NormalizedProfile {\n\tif (!isRecord(options.value)) {\n\t\tthrow new Error(\"profile JSON must be an object\");\n\t}\n\tconst name = asNonEmptyString(options.value.name) ?? options.fallbackName;\n\tif (!name) {\n\t\tthrow new Error(\"profile name is required\");\n\t}\n\tconst nameErrors = validateProfileName(name);\n\tif (nameErrors.length > 0) {\n\t\tthrow new Error(`invalid profile name \"${name}\": ${nameErrors.join(\", \")}`);\n\t}\n\tconst resources = normalizeResourceProfileSettings(options.value.resources ?? {}, options.baseDir);\n\tconst description = asNonEmptyString(options.value.description);\n\tconst model = asNonEmptyString(options.value.model);\n\tconst thinking = normalizeThinking(options.value.thinking);\n\tconst modelRouter = normalizeModelRouterSettings(options.value.modelRouter);\n\tconst soul = asNonEmptyString(options.value.soul);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmodel,\n\t\tthinking,\n\t\tmodelRouter,\n\t\tsoul,\n\t\tresources,\n\t\tsource: options.source,\n\t\tsourcePath: options.sourcePath,\n\t\tbaseDir: options.baseDir,\n\t};\n}\n\nfunction normalizeSettingsProfiles(\n\tsettings: Settings,\n\tsource: ProfileSource,\n): Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> {\n\tconst profiles: Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> = [];\n\tfor (const [name, resources] of Object.entries(settings.resourceProfiles ?? {})) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources) });\n\t}\n\treturn profiles.map((profile) => ({ ...profile, source }));\n}\n\nfunction normalizeDefinitions(\n\tdefinitions: Record<string, ResourceProfileSettings>,\n\tsource: ProfileSource,\n): NormalizedProfile[] {\n\tconst profiles: NormalizedProfile[] = [];\n\tfor (const [name, resources] of Object.entries(definitions)) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources), source });\n\t}\n\treturn profiles;\n}\n\nexport class ProfileRegistry {\n\tprivate options: ProfileRegistryOptions;\n\tprivate diagnostics: ProfileRegistryDiagnostic[] = [];\n\n\tconstructor(options: ProfileRegistryOptions) {\n\t\tthis.options = options;\n\t}\n\n\tlistDiagnostics(): ProfileRegistryDiagnostic[] {\n\t\tthis.collectCandidates();\n\t\treturn [...this.diagnostics];\n\t}\n\n\tlistProfiles(): NormalizedProfile[] {\n\t\tconst candidates = this.collectCandidates();\n\t\tconst winners = new Map<string, ProfileCandidate>();\n\t\tfor (const candidate of candidates) {\n\t\t\tconst existing = winners.get(candidate.profile.name);\n\t\t\tif (\n\t\t\t\t!existing ||\n\t\t\t\tcandidate.precedence < existing.precedence ||\n\t\t\t\t(candidate.precedence === existing.precedence && candidate.order < existing.order)\n\t\t\t) {\n\t\t\t\twinners.set(candidate.profile.name, candidate);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(winners.values())\n\t\t\t.sort((a, b) => a.profile.name.localeCompare(b.profile.name))\n\t\t\t.map((candidate) => candidate.profile);\n\t}\n\n\tgetProfile(name: string): NormalizedProfile | undefined {\n\t\tconst trimmed = name.trim();\n\t\tif (!trimmed) return undefined;\n\t\treturn this.listProfiles().find((profile) => profile.name === trimmed);\n\t}\n\n\tresolveProfileRef(ref: string, fromDir: string): NormalizedProfile | undefined {\n\t\tconst trimmed = ref.trim();\n\t\tif (!trimmed) return undefined;\n\t\tif (trimmed.startsWith(\"./\") || trimmed.startsWith(\"../\")) {\n\t\t\tconst sourcePath = resolvePath(trimmed, fromDir, { trim: true });\n\t\t\treturn this.loadProfileFile(sourcePath, \"profile-file\", 0)?.profile;\n\t\t}\n\t\treturn this.getProfile(trimmed);\n\t}\n\n\tprivate collectCandidates(): ProfileCandidate[] {\n\t\tthis.diagnostics = [];\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\t\tconst add = (profile: NormalizedProfile, precedence: number): void => {\n\t\t\tcandidates.push({ profile, precedence, order: order++ });\n\t\t};\n\n\t\tfor (const profile of normalizeDefinitions(this.options.inlineResourceProfileDefinitions, \"inline\")) {\n\t\t\tadd(profile, 1);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.directoryProfileSettings, \"directory-overlay\")) {\n\t\t\tadd({ ...profile, source: \"directory-overlay\" }, 2);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.projectSettings, \"project-settings\")) {\n\t\t\tadd({ ...profile, source: \"project-settings\" }, 3);\n\t\t}\n\t\tfor (const profile of this.loadProfileFiles()) {\n\t\t\tadd(profile.profile, profile.precedence);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.globalSettings, \"global-settings\")) {\n\t\t\tadd({ ...profile, source: \"global-settings\" }, 5);\n\t\t}\n\t\tfor (const profile of normalizeDefinitions(this.options.discoveredResourceProfileDefinitions, \"embedded\")) {\n\t\t\tadd(profile, 6);\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFiles(): ProfileCandidate[] {\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\n\t\tconst profilesDir = this.options.profilesDir;\n\t\tif (profilesDir && existsSync(profilesDir)) {\n\t\t\ttry {\n\t\t\t\tconst entries = readdirSync(profilesDir)\n\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t.sort();\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tconst sourcePath = join(profilesDir, entry);\n\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4 });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: profilesDir, message: String(error) });\n\t\t\t}\n\t\t}\n\n\t\tconst externalRoots = this.options.externalResourceRoots ?? [];\n\t\tfor (const root of externalRoots) {\n\t\t\tconst extProfilesDir = join(root, \"profiles\");\n\t\t\tif (existsSync(extProfilesDir)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst entries = readdirSync(extProfilesDir)\n\t\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t\t.sort();\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst sourcePath = join(extProfilesDir, entry);\n\t\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4.1 });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: extProfilesDir, message: String(error) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFile(sourcePath: string, source: ProfileSource, order: number): ProfileCandidate | undefined {\n\t\ttry {\n\t\t\tconst stats = statSync(sourcePath);\n\t\t\tif (!stats.isFile()) return undefined;\n\t\t\tconst parsed = JSON.parse(readFileSync(sourcePath, \"utf-8\"));\n\t\t\tconst fallbackName = basename(sourcePath, \".json\");\n\t\t\treturn {\n\t\t\t\tprofile: normalizeWrapperProfile({\n\t\t\t\t\tvalue: parsed,\n\t\t\t\t\tsource,\n\t\t\t\t\tsourcePath: resolve(sourcePath),\n\t\t\t\t\tbaseDir: dirname(resolve(sourcePath)),\n\t\t\t\t\tfallbackName,\n\t\t\t\t}),\n\t\t\t\tprecedence: 0,\n\t\t\t\torder,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.diagnostics.push({ source, path: sourcePath, message });\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -62,6 +62,19 @@ function normalizeThinking(value) {
|
|
|
62
62
|
}
|
|
63
63
|
return thinking;
|
|
64
64
|
}
|
|
65
|
+
function normalizeModelRouterSettings(value) {
|
|
66
|
+
if (!isRecord(value))
|
|
67
|
+
return undefined;
|
|
68
|
+
const settings = {};
|
|
69
|
+
if (typeof value.enabled === "boolean")
|
|
70
|
+
settings.enabled = value.enabled;
|
|
71
|
+
for (const key of ["cheapModel", "expensiveModel", "learningModel"]) {
|
|
72
|
+
const candidate = asNonEmptyString(value[key]);
|
|
73
|
+
if (candidate)
|
|
74
|
+
settings[key] = candidate;
|
|
75
|
+
}
|
|
76
|
+
return Object.keys(settings).length > 0 ? settings : undefined;
|
|
77
|
+
}
|
|
65
78
|
function normalizeWrapperProfile(options) {
|
|
66
79
|
if (!isRecord(options.value)) {
|
|
67
80
|
throw new Error("profile JSON must be an object");
|
|
@@ -78,12 +91,14 @@ function normalizeWrapperProfile(options) {
|
|
|
78
91
|
const description = asNonEmptyString(options.value.description);
|
|
79
92
|
const model = asNonEmptyString(options.value.model);
|
|
80
93
|
const thinking = normalizeThinking(options.value.thinking);
|
|
94
|
+
const modelRouter = normalizeModelRouterSettings(options.value.modelRouter);
|
|
81
95
|
const soul = asNonEmptyString(options.value.soul);
|
|
82
96
|
return {
|
|
83
97
|
name,
|
|
84
98
|
description,
|
|
85
99
|
model,
|
|
86
100
|
thinking,
|
|
101
|
+
modelRouter,
|
|
87
102
|
soul,
|
|
88
103
|
resources,
|
|
89
104
|
source: options.source,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-registry.js","sourceRoot":"","sources":["../../src/core/profile-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { mergeResourceProfileSettings } from \"./resource-profile-blocks.ts\";\nimport type { ResourceProfileKind, ResourceProfileSettings, Settings } from \"./settings-manager.ts\";\nimport { validateSkillName } from \"./skills.ts\";\n\nexport type ProfileSource =\n\t| \"global-settings\"\n\t| \"project-settings\"\n\t| \"profile-file\"\n\t| \"directory-overlay\"\n\t| \"inline\"\n\t| \"embedded\"\n\t| \"bundle\";\n\nexport interface NormalizedProfile {\n\tname: string;\n\tdescription?: string;\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n\t/** Situational identity injected into the system prompt while this profile is active (R6). */\n\tsoul?: string;\n\tresources: ResourceProfileSettings;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n}\n\nexport interface ProfileRegistryDiagnostic {\n\tsource: ProfileSource;\n\tpath?: string;\n\tmessage: string;\n}\n\nexport interface ProfileRegistryOptions {\n\tglobalSettings: Settings;\n\tprojectSettings: Settings;\n\tdirectoryProfileSettings: Settings;\n\tinlineResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tdiscoveredResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tprofilesDir?: string;\n\texternalResourceRoots?: string[];\n}\n\nconst RESOURCE_PROFILE_KINDS: ResourceProfileKind[] = [\"extensions\", \"skills\", \"prompts\", \"themes\", \"agents\", \"tools\"];\n\ninterface ProfileCandidate {\n\tprofile: NormalizedProfile;\n\tprecedence: number;\n\torder: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction asNonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst strings = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n\treturn strings.length > 0 ? strings : undefined;\n}\n\nfunction shouldResolveAgainstBaseDir(pattern: string): boolean {\n\treturn pattern.startsWith(\"./\") || pattern.startsWith(\"../\");\n}\n\nfunction normalizePattern(pattern: string, baseDir: string | undefined): string {\n\tconst trimmed = pattern.trim();\n\tif (!baseDir || !shouldResolveAgainstBaseDir(trimmed)) return trimmed;\n\treturn resolvePath(trimmed, baseDir, { trim: true });\n}\n\nfunction normalizeStringArray(value: unknown, baseDir: string | undefined): string[] | undefined {\n\tconst strings = asStringArray(value);\n\tif (!strings) return undefined;\n\treturn strings.map((pattern) => normalizePattern(pattern, baseDir));\n}\n\nfunction normalizeResourceProfileSettings(value: unknown, baseDir: string | undefined): ResourceProfileSettings {\n\tif (!isRecord(value)) {\n\t\tthrow new Error(\"resources must be an object\");\n\t}\n\tconst result: ResourceProfileSettings = {};\n\tfor (const kind of RESOURCE_PROFILE_KINDS) {\n\t\tconst filterValue = value[kind];\n\t\tif (filterValue === undefined) continue;\n\t\tif (!isRecord(filterValue)) {\n\t\t\tthrow new Error(`${kind} filter must be an object`);\n\t\t}\n\t\tconst allow = normalizeStringArray(filterValue.allow, baseDir);\n\t\tconst block = normalizeStringArray(filterValue.block, baseDir);\n\t\tresult[kind] = { allow, block };\n\t}\n\treturn result;\n}\n\nfunction validateProfileName(name: string): string[] {\n\treturn validateSkillName(name);\n}\n\nfunction normalizeThinking(value: unknown): ThinkingLevel | undefined {\n\tconst thinking = asNonEmptyString(value);\n\tif (!thinking) return undefined;\n\tif (!isValidThinkingLevel(thinking)) {\n\t\tthrow new Error(`thinking must be one of off, minimal, low, medium, high, xhigh`);\n\t}\n\treturn thinking;\n}\n\nfunction normalizeWrapperProfile(options: {\n\tvalue: unknown;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n\tfallbackName?: string;\n}): NormalizedProfile {\n\tif (!isRecord(options.value)) {\n\t\tthrow new Error(\"profile JSON must be an object\");\n\t}\n\tconst name = asNonEmptyString(options.value.name) ?? options.fallbackName;\n\tif (!name) {\n\t\tthrow new Error(\"profile name is required\");\n\t}\n\tconst nameErrors = validateProfileName(name);\n\tif (nameErrors.length > 0) {\n\t\tthrow new Error(`invalid profile name \"${name}\": ${nameErrors.join(\", \")}`);\n\t}\n\tconst resources = normalizeResourceProfileSettings(options.value.resources ?? {}, options.baseDir);\n\tconst description = asNonEmptyString(options.value.description);\n\tconst model = asNonEmptyString(options.value.model);\n\tconst thinking = normalizeThinking(options.value.thinking);\n\tconst soul = asNonEmptyString(options.value.soul);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmodel,\n\t\tthinking,\n\t\tsoul,\n\t\tresources,\n\t\tsource: options.source,\n\t\tsourcePath: options.sourcePath,\n\t\tbaseDir: options.baseDir,\n\t};\n}\n\nfunction normalizeSettingsProfiles(\n\tsettings: Settings,\n\tsource: ProfileSource,\n): Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> {\n\tconst profiles: Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> = [];\n\tfor (const [name, resources] of Object.entries(settings.resourceProfiles ?? {})) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources) });\n\t}\n\treturn profiles.map((profile) => ({ ...profile, source }));\n}\n\nfunction normalizeDefinitions(\n\tdefinitions: Record<string, ResourceProfileSettings>,\n\tsource: ProfileSource,\n): NormalizedProfile[] {\n\tconst profiles: NormalizedProfile[] = [];\n\tfor (const [name, resources] of Object.entries(definitions)) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources), source });\n\t}\n\treturn profiles;\n}\n\nexport class ProfileRegistry {\n\tprivate options: ProfileRegistryOptions;\n\tprivate diagnostics: ProfileRegistryDiagnostic[] = [];\n\n\tconstructor(options: ProfileRegistryOptions) {\n\t\tthis.options = options;\n\t}\n\n\tlistDiagnostics(): ProfileRegistryDiagnostic[] {\n\t\tthis.collectCandidates();\n\t\treturn [...this.diagnostics];\n\t}\n\n\tlistProfiles(): NormalizedProfile[] {\n\t\tconst candidates = this.collectCandidates();\n\t\tconst winners = new Map<string, ProfileCandidate>();\n\t\tfor (const candidate of candidates) {\n\t\t\tconst existing = winners.get(candidate.profile.name);\n\t\t\tif (\n\t\t\t\t!existing ||\n\t\t\t\tcandidate.precedence < existing.precedence ||\n\t\t\t\t(candidate.precedence === existing.precedence && candidate.order < existing.order)\n\t\t\t) {\n\t\t\t\twinners.set(candidate.profile.name, candidate);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(winners.values())\n\t\t\t.sort((a, b) => a.profile.name.localeCompare(b.profile.name))\n\t\t\t.map((candidate) => candidate.profile);\n\t}\n\n\tgetProfile(name: string): NormalizedProfile | undefined {\n\t\tconst trimmed = name.trim();\n\t\tif (!trimmed) return undefined;\n\t\treturn this.listProfiles().find((profile) => profile.name === trimmed);\n\t}\n\n\tresolveProfileRef(ref: string, fromDir: string): NormalizedProfile | undefined {\n\t\tconst trimmed = ref.trim();\n\t\tif (!trimmed) return undefined;\n\t\tif (trimmed.startsWith(\"./\") || trimmed.startsWith(\"../\")) {\n\t\t\tconst sourcePath = resolvePath(trimmed, fromDir, { trim: true });\n\t\t\treturn this.loadProfileFile(sourcePath, \"profile-file\", 0)?.profile;\n\t\t}\n\t\treturn this.getProfile(trimmed);\n\t}\n\n\tprivate collectCandidates(): ProfileCandidate[] {\n\t\tthis.diagnostics = [];\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\t\tconst add = (profile: NormalizedProfile, precedence: number): void => {\n\t\t\tcandidates.push({ profile, precedence, order: order++ });\n\t\t};\n\n\t\tfor (const profile of normalizeDefinitions(this.options.inlineResourceProfileDefinitions, \"inline\")) {\n\t\t\tadd(profile, 1);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.directoryProfileSettings, \"directory-overlay\")) {\n\t\t\tadd({ ...profile, source: \"directory-overlay\" }, 2);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.projectSettings, \"project-settings\")) {\n\t\t\tadd({ ...profile, source: \"project-settings\" }, 3);\n\t\t}\n\t\tfor (const profile of this.loadProfileFiles()) {\n\t\t\tadd(profile.profile, profile.precedence);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.globalSettings, \"global-settings\")) {\n\t\t\tadd({ ...profile, source: \"global-settings\" }, 5);\n\t\t}\n\t\tfor (const profile of normalizeDefinitions(this.options.discoveredResourceProfileDefinitions, \"embedded\")) {\n\t\t\tadd(profile, 6);\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFiles(): ProfileCandidate[] {\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\n\t\tconst profilesDir = this.options.profilesDir;\n\t\tif (profilesDir && existsSync(profilesDir)) {\n\t\t\ttry {\n\t\t\t\tconst entries = readdirSync(profilesDir)\n\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t.sort();\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tconst sourcePath = join(profilesDir, entry);\n\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4 });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: profilesDir, message: String(error) });\n\t\t\t}\n\t\t}\n\n\t\tconst externalRoots = this.options.externalResourceRoots ?? [];\n\t\tfor (const root of externalRoots) {\n\t\t\tconst extProfilesDir = join(root, \"profiles\");\n\t\t\tif (existsSync(extProfilesDir)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst entries = readdirSync(extProfilesDir)\n\t\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t\t.sort();\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst sourcePath = join(extProfilesDir, entry);\n\t\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4.1 });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: extProfilesDir, message: String(error) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFile(sourcePath: string, source: ProfileSource, order: number): ProfileCandidate | undefined {\n\t\ttry {\n\t\t\tconst stats = statSync(sourcePath);\n\t\t\tif (!stats.isFile()) return undefined;\n\t\t\tconst parsed = JSON.parse(readFileSync(sourcePath, \"utf-8\"));\n\t\t\tconst fallbackName = basename(sourcePath, \".json\");\n\t\t\treturn {\n\t\t\t\tprofile: normalizeWrapperProfile({\n\t\t\t\t\tvalue: parsed,\n\t\t\t\t\tsource,\n\t\t\t\t\tsourcePath: resolve(sourcePath),\n\t\t\t\t\tbaseDir: dirname(resolve(sourcePath)),\n\t\t\t\t\tfallbackName,\n\t\t\t\t}),\n\t\t\t\tprecedence: 0,\n\t\t\t\torder,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.diagnostics.push({ source, path: sourcePath, message });\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"profile-registry.js","sourceRoot":"","sources":["../../src/core/profile-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { mergeResourceProfileSettings } from \"./resource-profile-blocks.ts\";\nimport type {\n\tModelRouterSettings,\n\tResourceProfileKind,\n\tResourceProfileSettings,\n\tSettings,\n} from \"./settings-manager.ts\";\nimport { validateSkillName } from \"./skills.ts\";\n\nexport type ProfileSource =\n\t| \"global-settings\"\n\t| \"project-settings\"\n\t| \"profile-file\"\n\t| \"directory-overlay\"\n\t| \"inline\"\n\t| \"embedded\"\n\t| \"bundle\";\n\nexport interface NormalizedProfile {\n\tname: string;\n\tdescription?: string;\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n\tmodelRouter?: ModelRouterSettings;\n\t/** Situational identity injected into the system prompt while this profile is active (R6). */\n\tsoul?: string;\n\tresources: ResourceProfileSettings;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n}\n\nexport interface ProfileRegistryDiagnostic {\n\tsource: ProfileSource;\n\tpath?: string;\n\tmessage: string;\n}\n\nexport interface ProfileRegistryOptions {\n\tglobalSettings: Settings;\n\tprojectSettings: Settings;\n\tdirectoryProfileSettings: Settings;\n\tinlineResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tdiscoveredResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tprofilesDir?: string;\n\texternalResourceRoots?: string[];\n}\n\nconst RESOURCE_PROFILE_KINDS: ResourceProfileKind[] = [\"extensions\", \"skills\", \"prompts\", \"themes\", \"agents\", \"tools\"];\n\ninterface ProfileCandidate {\n\tprofile: NormalizedProfile;\n\tprecedence: number;\n\torder: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction asNonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst strings = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n\treturn strings.length > 0 ? strings : undefined;\n}\n\nfunction shouldResolveAgainstBaseDir(pattern: string): boolean {\n\treturn pattern.startsWith(\"./\") || pattern.startsWith(\"../\");\n}\n\nfunction normalizePattern(pattern: string, baseDir: string | undefined): string {\n\tconst trimmed = pattern.trim();\n\tif (!baseDir || !shouldResolveAgainstBaseDir(trimmed)) return trimmed;\n\treturn resolvePath(trimmed, baseDir, { trim: true });\n}\n\nfunction normalizeStringArray(value: unknown, baseDir: string | undefined): string[] | undefined {\n\tconst strings = asStringArray(value);\n\tif (!strings) return undefined;\n\treturn strings.map((pattern) => normalizePattern(pattern, baseDir));\n}\n\nfunction normalizeResourceProfileSettings(value: unknown, baseDir: string | undefined): ResourceProfileSettings {\n\tif (!isRecord(value)) {\n\t\tthrow new Error(\"resources must be an object\");\n\t}\n\tconst result: ResourceProfileSettings = {};\n\tfor (const kind of RESOURCE_PROFILE_KINDS) {\n\t\tconst filterValue = value[kind];\n\t\tif (filterValue === undefined) continue;\n\t\tif (!isRecord(filterValue)) {\n\t\t\tthrow new Error(`${kind} filter must be an object`);\n\t\t}\n\t\tconst allow = normalizeStringArray(filterValue.allow, baseDir);\n\t\tconst block = normalizeStringArray(filterValue.block, baseDir);\n\t\tresult[kind] = { allow, block };\n\t}\n\treturn result;\n}\n\nfunction validateProfileName(name: string): string[] {\n\treturn validateSkillName(name);\n}\n\nfunction normalizeThinking(value: unknown): ThinkingLevel | undefined {\n\tconst thinking = asNonEmptyString(value);\n\tif (!thinking) return undefined;\n\tif (!isValidThinkingLevel(thinking)) {\n\t\tthrow new Error(`thinking must be one of off, minimal, low, medium, high, xhigh`);\n\t}\n\treturn thinking;\n}\n\nfunction normalizeModelRouterSettings(value: unknown): ModelRouterSettings | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst settings: ModelRouterSettings = {};\n\tif (typeof value.enabled === \"boolean\") settings.enabled = value.enabled;\n\tfor (const key of [\"cheapModel\", \"expensiveModel\", \"learningModel\"] as const) {\n\t\tconst candidate = asNonEmptyString(value[key]);\n\t\tif (candidate) settings[key] = candidate;\n\t}\n\treturn Object.keys(settings).length > 0 ? settings : undefined;\n}\n\nfunction normalizeWrapperProfile(options: {\n\tvalue: unknown;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n\tfallbackName?: string;\n}): NormalizedProfile {\n\tif (!isRecord(options.value)) {\n\t\tthrow new Error(\"profile JSON must be an object\");\n\t}\n\tconst name = asNonEmptyString(options.value.name) ?? options.fallbackName;\n\tif (!name) {\n\t\tthrow new Error(\"profile name is required\");\n\t}\n\tconst nameErrors = validateProfileName(name);\n\tif (nameErrors.length > 0) {\n\t\tthrow new Error(`invalid profile name \"${name}\": ${nameErrors.join(\", \")}`);\n\t}\n\tconst resources = normalizeResourceProfileSettings(options.value.resources ?? {}, options.baseDir);\n\tconst description = asNonEmptyString(options.value.description);\n\tconst model = asNonEmptyString(options.value.model);\n\tconst thinking = normalizeThinking(options.value.thinking);\n\tconst modelRouter = normalizeModelRouterSettings(options.value.modelRouter);\n\tconst soul = asNonEmptyString(options.value.soul);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmodel,\n\t\tthinking,\n\t\tmodelRouter,\n\t\tsoul,\n\t\tresources,\n\t\tsource: options.source,\n\t\tsourcePath: options.sourcePath,\n\t\tbaseDir: options.baseDir,\n\t};\n}\n\nfunction normalizeSettingsProfiles(\n\tsettings: Settings,\n\tsource: ProfileSource,\n): Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> {\n\tconst profiles: Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> = [];\n\tfor (const [name, resources] of Object.entries(settings.resourceProfiles ?? {})) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources) });\n\t}\n\treturn profiles.map((profile) => ({ ...profile, source }));\n}\n\nfunction normalizeDefinitions(\n\tdefinitions: Record<string, ResourceProfileSettings>,\n\tsource: ProfileSource,\n): NormalizedProfile[] {\n\tconst profiles: NormalizedProfile[] = [];\n\tfor (const [name, resources] of Object.entries(definitions)) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources), source });\n\t}\n\treturn profiles;\n}\n\nexport class ProfileRegistry {\n\tprivate options: ProfileRegistryOptions;\n\tprivate diagnostics: ProfileRegistryDiagnostic[] = [];\n\n\tconstructor(options: ProfileRegistryOptions) {\n\t\tthis.options = options;\n\t}\n\n\tlistDiagnostics(): ProfileRegistryDiagnostic[] {\n\t\tthis.collectCandidates();\n\t\treturn [...this.diagnostics];\n\t}\n\n\tlistProfiles(): NormalizedProfile[] {\n\t\tconst candidates = this.collectCandidates();\n\t\tconst winners = new Map<string, ProfileCandidate>();\n\t\tfor (const candidate of candidates) {\n\t\t\tconst existing = winners.get(candidate.profile.name);\n\t\t\tif (\n\t\t\t\t!existing ||\n\t\t\t\tcandidate.precedence < existing.precedence ||\n\t\t\t\t(candidate.precedence === existing.precedence && candidate.order < existing.order)\n\t\t\t) {\n\t\t\t\twinners.set(candidate.profile.name, candidate);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(winners.values())\n\t\t\t.sort((a, b) => a.profile.name.localeCompare(b.profile.name))\n\t\t\t.map((candidate) => candidate.profile);\n\t}\n\n\tgetProfile(name: string): NormalizedProfile | undefined {\n\t\tconst trimmed = name.trim();\n\t\tif (!trimmed) return undefined;\n\t\treturn this.listProfiles().find((profile) => profile.name === trimmed);\n\t}\n\n\tresolveProfileRef(ref: string, fromDir: string): NormalizedProfile | undefined {\n\t\tconst trimmed = ref.trim();\n\t\tif (!trimmed) return undefined;\n\t\tif (trimmed.startsWith(\"./\") || trimmed.startsWith(\"../\")) {\n\t\t\tconst sourcePath = resolvePath(trimmed, fromDir, { trim: true });\n\t\t\treturn this.loadProfileFile(sourcePath, \"profile-file\", 0)?.profile;\n\t\t}\n\t\treturn this.getProfile(trimmed);\n\t}\n\n\tprivate collectCandidates(): ProfileCandidate[] {\n\t\tthis.diagnostics = [];\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\t\tconst add = (profile: NormalizedProfile, precedence: number): void => {\n\t\t\tcandidates.push({ profile, precedence, order: order++ });\n\t\t};\n\n\t\tfor (const profile of normalizeDefinitions(this.options.inlineResourceProfileDefinitions, \"inline\")) {\n\t\t\tadd(profile, 1);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.directoryProfileSettings, \"directory-overlay\")) {\n\t\t\tadd({ ...profile, source: \"directory-overlay\" }, 2);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.projectSettings, \"project-settings\")) {\n\t\t\tadd({ ...profile, source: \"project-settings\" }, 3);\n\t\t}\n\t\tfor (const profile of this.loadProfileFiles()) {\n\t\t\tadd(profile.profile, profile.precedence);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.globalSettings, \"global-settings\")) {\n\t\t\tadd({ ...profile, source: \"global-settings\" }, 5);\n\t\t}\n\t\tfor (const profile of normalizeDefinitions(this.options.discoveredResourceProfileDefinitions, \"embedded\")) {\n\t\t\tadd(profile, 6);\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFiles(): ProfileCandidate[] {\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\n\t\tconst profilesDir = this.options.profilesDir;\n\t\tif (profilesDir && existsSync(profilesDir)) {\n\t\t\ttry {\n\t\t\t\tconst entries = readdirSync(profilesDir)\n\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t.sort();\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tconst sourcePath = join(profilesDir, entry);\n\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4 });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: profilesDir, message: String(error) });\n\t\t\t}\n\t\t}\n\n\t\tconst externalRoots = this.options.externalResourceRoots ?? [];\n\t\tfor (const root of externalRoots) {\n\t\t\tconst extProfilesDir = join(root, \"profiles\");\n\t\t\tif (existsSync(extProfilesDir)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst entries = readdirSync(extProfilesDir)\n\t\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t\t.sort();\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst sourcePath = join(extProfilesDir, entry);\n\t\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4.1 });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: extProfilesDir, message: String(error) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFile(sourcePath: string, source: ProfileSource, order: number): ProfileCandidate | undefined {\n\t\ttry {\n\t\t\tconst stats = statSync(sourcePath);\n\t\t\tif (!stats.isFile()) return undefined;\n\t\t\tconst parsed = JSON.parse(readFileSync(sourcePath, \"utf-8\"));\n\t\t\tconst fallbackName = basename(sourcePath, \".json\");\n\t\t\treturn {\n\t\t\t\tprofile: normalizeWrapperProfile({\n\t\t\t\t\tvalue: parsed,\n\t\t\t\t\tsource,\n\t\t\t\t\tsourcePath: resolve(sourcePath),\n\t\t\t\t\tbaseDir: dirname(resolve(sourcePath)),\n\t\t\t\t\tfallbackName,\n\t\t\t\t}),\n\t\t\t\tprecedence: 0,\n\t\t\t\torder,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.diagnostics.push({ source, path: sourcePath, message });\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -86,6 +86,7 @@ export interface ModelRouterSettings {
|
|
|
86
86
|
enabled?: boolean;
|
|
87
87
|
cheapModel?: string;
|
|
88
88
|
expensiveModel?: string;
|
|
89
|
+
learningModel?: string;
|
|
89
90
|
}
|
|
90
91
|
export type TransportSetting = Transport;
|
|
91
92
|
/**
|
|
@@ -192,6 +193,7 @@ export interface ProfileDefinitionInput {
|
|
|
192
193
|
description?: string;
|
|
193
194
|
model?: string;
|
|
194
195
|
thinking?: ThinkingLevel;
|
|
196
|
+
modelRouter?: ModelRouterSettings;
|
|
195
197
|
/**
|
|
196
198
|
* Situational identity (R6): a system-prompt prefix injected while this profile is active, so a
|
|
197
199
|
* profile becomes a full "situation" = soul + capabilities + model/thinking, switched atomically.
|
|
@@ -373,11 +375,14 @@ export declare class SettingsManager {
|
|
|
373
375
|
maxTurnUsd: number;
|
|
374
376
|
action: "warn" | "downgrade";
|
|
375
377
|
};
|
|
378
|
+
private getProfileModelRouterSettings;
|
|
376
379
|
getModelRouterSettings(): {
|
|
377
380
|
enabled: boolean;
|
|
378
381
|
cheapModel?: string;
|
|
379
382
|
expensiveModel?: string;
|
|
383
|
+
learningModel?: string;
|
|
380
384
|
};
|
|
385
|
+
setModelRouterSettings(settings: ModelRouterSettings, scope?: SettingsScope): void;
|
|
381
386
|
/** Configured auxiliary summarizer model id, or "auto" (default) to pick the cheapest authed model. */
|
|
382
387
|
getCompactionModel(): string;
|
|
383
388
|
getCompactionSettings(): {
|