@caupulican/pi-adaptative 0.80.7 → 0.80.9
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/README.md +1 -1
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +16 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +17 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -1
- package/dist/config.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -3
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/export-html/template.js +19 -6
- package/dist/core/package-manager.d.ts +3 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +47 -13
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/reload-blockers.d.ts +2 -0
- package/dist/core/reload-blockers.d.ts.map +1 -1
- package/dist/core/reload-blockers.js +8 -2
- package/dist/core/reload-blockers.js.map +1 -1
- package/dist/core/resource-loader.d.ts +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +30 -22
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +10 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +71 -30
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +7 -3
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +3 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/trust-manager.d.ts +9 -0
- package/dist/core/trust-manager.d.ts.map +1 -0
- package/dist/core/trust-manager.js +134 -0
- package/dist/core/trust-manager.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +65 -6
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +3 -12
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts +20 -0
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/trust-selector.js +86 -0
- package/dist/modes/interactive/components/trust-selector.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +127 -26
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +55 -8
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +54 -22
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.d.ts.map +1 -0
- package/dist/utils/open-browser.js +22 -0
- package/dist/utils/open-browser.js.map +1 -0
- package/docs/adaptive-extension-shared-state-audit.md +43 -0
- package/docs/settings.md +2 -2
- package/docs/skills.md +3 -3
- 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
|
@@ -28,6 +28,8 @@ export interface ReloadBlockerOptions {
|
|
|
28
28
|
ownSessionFile?: string;
|
|
29
29
|
activeTurnTtlMs?: number;
|
|
30
30
|
coordinatorTtlMs?: number;
|
|
31
|
+
/** Auto Learn workers are memory-first, short-lived, and should not block foreground reload/adaptive work by default. */
|
|
32
|
+
includeAutoLearnSessions?: boolean;
|
|
31
33
|
isProcessAlive?: (pid: number | undefined) => boolean;
|
|
32
34
|
}
|
|
33
35
|
export declare function isReloadSessionProcessAlive(pid: number | undefined): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reload-blockers.d.ts","sourceRoot":"","sources":["../../src/core/reload-blockers.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,QAAa,CAAC;AAC7C,eAAO,MAAM,8BAA8B,QAAc,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,aAAa,GAAG,aAAa,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC;CACtD;AAqDD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAU5E;
|
|
1
|
+
{"version":3,"file":"reload-blockers.d.ts","sourceRoot":"","sources":["../../src/core/reload-blockers.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,QAAa,CAAC;AAC7C,eAAO,MAAM,8BAA8B,QAAc,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,aAAa,GAAG,aAAa,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yHAAyH;IACzH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC;CACtD;AAqDD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAU5E;AAgFD,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,KAAK,GAAG,KAAK,GAAG,WAAW,GAAG,aAAa,GAAG,KAAK,CAAC,GACpF,MAAM,CAOR;AAED,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,oBAAyB,GAAG,qBAAqB,CAgBlG","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getAgentDir } from \"../config.ts\";\n\nexport const ACTIVE_TURN_TTL_MS = 5 * 60_000;\nexport const AUTO_RELOAD_COORDINATOR_TTL_MS = 10 * 60_000;\n\nexport interface ReloadSessionRecord {\n\tkey: string;\n\tsource: \"active-turn\" | \"coordinator\";\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n\treason?: string;\n}\n\nexport interface PendingReloadBlockers {\n\tpending: boolean;\n\treason: string;\n\tblockers: ReloadSessionRecord[];\n\tdescriptions: string[];\n}\n\nexport interface ReloadBlockerOptions {\n\tagentDir?: string;\n\tnow?: number;\n\townKey?: string;\n\townPid?: number;\n\townSessionId?: string;\n\townSessionFile?: string;\n\tactiveTurnTtlMs?: number;\n\tcoordinatorTtlMs?: number;\n\t/** Auto Learn workers are memory-first, short-lived, and should not block foreground reload/adaptive work by default. */\n\tincludeAutoLearnSessions?: boolean;\n\tisProcessAlive?: (pid: number | undefined) => boolean;\n}\n\ninterface ParsedSession {\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction readJsonFile(file: string): unknown {\n\ttry {\n\t\tif (!existsSync(file)) return undefined;\n\t\treturn JSON.parse(readFileSync(file, \"utf8\")) as unknown;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction stringValue(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction numberValue(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\treturn undefined;\n}\n\nfunction booleanValue(value: unknown): boolean | undefined {\n\treturn typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction parseSession(value: unknown): ParsedSession | undefined {\n\tif (!isRecord(value)) return undefined;\n\treturn {\n\t\tpid: numberValue(value.pid),\n\t\tsessionId: stringValue(value.sessionId),\n\t\tsessionFile: stringValue(value.sessionFile),\n\t\tcwd: stringValue(value.cwd),\n\t\tactive: booleanValue(value.active),\n\t\tupdatedAt: numberValue(value.updatedAt),\n\t\tseenAt: numberValue(value.seenAt),\n\t\treloadedAt: numberValue(value.reloadedAt),\n\t};\n}\n\nexport function isReloadSessionProcessAlive(pid: number | undefined): boolean {\n\tif (pid === undefined || !Number.isFinite(pid) || pid <= 0) return false;\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code =\n\t\t\terror && typeof error === \"object\" && \"code\" in error ? String((error as { code?: unknown }).code) : \"\";\n\t\treturn code === \"EPERM\";\n\t}\n}\n\nfunction isOwnSession(key: string, session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\tif (options.ownKey && key === options.ownKey) return true;\n\tif (options.ownPid !== undefined && session.pid === options.ownPid) return true;\n\tif (options.ownSessionId && session.sessionId === options.ownSessionId) return true;\n\tif (options.ownSessionFile && session.sessionFile === options.ownSessionFile) return true;\n\treturn false;\n}\n\nfunction isAutoLearnSession(session: ParsedSession): boolean {\n\treturn !!session.sessionId?.startsWith(\"auto-learn-\");\n}\n\nfunction shouldIgnoreSession(session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\treturn options.includeAutoLearnSessions !== true && isAutoLearnSession(session);\n}\n\nfunction addBlocker(blockers: Map<string, ReloadSessionRecord>, record: ReloadSessionRecord): void {\n\tconst identity = [\n\t\trecord.key,\n\t\trecord.pid ?? \"\",\n\t\trecord.sessionId ?? \"\",\n\t\trecord.sessionFile ?? \"\",\n\t\trecord.cwd ?? \"\",\n\t].join(\"\\0\");\n\tconst existing = blockers.get(identity);\n\tif (!existing || (existing.source === \"coordinator\" && record.source === \"active-turn\")) {\n\t\tblockers.set(identity, record);\n\t}\n}\n\nfunction activeTurnBlockers(options: ReloadBlockerOptions): ReloadSessionRecord[] {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.activeTurnTtlMs ?? ACTIVE_TURN_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst registry = readJsonFile(join(agentDir, \"pi-active-turns.json\"));\n\tif (!isRecord(registry) || !isRecord(registry.sessions)) return [];\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tfor (const [key, rawSession] of Object.entries(registry.sessions)) {\n\t\tconst session = parseSession(rawSession);\n\t\tif (!session?.active) continue;\n\t\tif (isOwnSession(key, session, options) || shouldIgnoreSession(session, options)) continue;\n\t\tif (session.updatedAt === undefined || now - session.updatedAt > ttl) continue;\n\t\tif (!isAlive(session.pid)) continue;\n\t\tblockers.push({ key, source: \"active-turn\", ...session });\n\t}\n\treturn blockers;\n}\n\nfunction coordinatorBlockers(options: ReloadBlockerOptions): { blockers: ReloadSessionRecord[]; reason: string } {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.coordinatorTtlMs ?? AUTO_RELOAD_COORDINATOR_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst coordinator = readJsonFile(join(agentDir, \"pi-auto-reload-state.json\"));\n\tif (!isRecord(coordinator) || !isRecord(coordinator.changes)) return { blockers: [], reason: \"\" };\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tlet reason = \"\";\n\tfor (const rawChange of Object.values(coordinator.changes)) {\n\t\tif (!isRecord(rawChange)) continue;\n\t\tconst firstSeenAt = numberValue(rawChange.firstSeenAt);\n\t\tif (firstSeenAt === undefined || now - firstSeenAt > ttl) continue;\n\t\treason ||= stringValue(rawChange.reason) ?? \"\";\n\t\tif (!isRecord(rawChange.sessions)) continue;\n\t\tfor (const [key, rawSession] of Object.entries(rawChange.sessions)) {\n\t\t\tconst session = parseSession(rawSession);\n\t\t\tif (!session) continue;\n\t\t\tif (session.reloadedAt !== undefined) continue;\n\t\t\tif (isOwnSession(key, session, options) || shouldIgnoreSession(session, options)) continue;\n\t\t\tif (!isAlive(session.pid)) continue;\n\t\t\tblockers.push({ key, source: \"coordinator\", reason: stringValue(rawChange.reason), ...session });\n\t\t}\n\t}\n\treturn { blockers, reason };\n}\n\nexport function describeReloadSession(\n\trecord: Pick<ReloadSessionRecord, \"key\" | \"pid\" | \"sessionId\" | \"sessionFile\" | \"cwd\">,\n): string {\n\tconst label = record.sessionId ?? record.sessionFile ?? record.cwd ?? String(record.pid ?? \"unknown\");\n\tconst parts = [`${record.key}:${label}`];\n\tif (record.pid !== undefined) parts.push(`pid=${record.pid}`);\n\tif (record.cwd) parts.push(`cwd=${record.cwd}`);\n\tif (record.sessionFile) parts.push(`file=${record.sessionFile}`);\n\treturn parts.join(\" \");\n}\n\nexport function getPendingReloadBlockers(options: ReloadBlockerOptions = {}): PendingReloadBlockers {\n\tconst byIdentity = new Map<string, ReloadSessionRecord>();\n\tfor (const blocker of activeTurnBlockers(options)) addBlocker(byIdentity, blocker);\n\tconst coordinator = coordinatorBlockers(options);\n\tfor (const blocker of coordinator.blockers) addBlocker(byIdentity, blocker);\n\tconst blockers = [...byIdentity.values()].sort((a, b) =>\n\t\tdescribeReloadSession(a).localeCompare(describeReloadSession(b)),\n\t);\n\treturn {\n\t\tpending: blockers.length > 0,\n\t\treason:\n\t\t\tcoordinator.reason ||\n\t\t\t(blockers.length ? \"Pi auto-reload is waiting for active peer/background session(s).\" : \"\"),\n\t\tblockers,\n\t\tdescriptions: blockers.map(describeReloadSession),\n\t};\n}\n"]}
|
|
@@ -64,6 +64,12 @@ function isOwnSession(key, session, options) {
|
|
|
64
64
|
return true;
|
|
65
65
|
return false;
|
|
66
66
|
}
|
|
67
|
+
function isAutoLearnSession(session) {
|
|
68
|
+
return !!session.sessionId?.startsWith("auto-learn-");
|
|
69
|
+
}
|
|
70
|
+
function shouldIgnoreSession(session, options) {
|
|
71
|
+
return options.includeAutoLearnSessions !== true && isAutoLearnSession(session);
|
|
72
|
+
}
|
|
67
73
|
function addBlocker(blockers, record) {
|
|
68
74
|
const identity = [
|
|
69
75
|
record.key,
|
|
@@ -90,7 +96,7 @@ function activeTurnBlockers(options) {
|
|
|
90
96
|
const session = parseSession(rawSession);
|
|
91
97
|
if (!session?.active)
|
|
92
98
|
continue;
|
|
93
|
-
if (isOwnSession(key, session, options))
|
|
99
|
+
if (isOwnSession(key, session, options) || shouldIgnoreSession(session, options))
|
|
94
100
|
continue;
|
|
95
101
|
if (session.updatedAt === undefined || now - session.updatedAt > ttl)
|
|
96
102
|
continue;
|
|
@@ -125,7 +131,7 @@ function coordinatorBlockers(options) {
|
|
|
125
131
|
continue;
|
|
126
132
|
if (session.reloadedAt !== undefined)
|
|
127
133
|
continue;
|
|
128
|
-
if (isOwnSession(key, session, options))
|
|
134
|
+
if (isOwnSession(key, session, options) || shouldIgnoreSession(session, options))
|
|
129
135
|
continue;
|
|
130
136
|
if (!isAlive(session.pid))
|
|
131
137
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reload-blockers.js","sourceRoot":"","sources":["../../src/core/reload-blockers.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getAgentDir } from \"../config.ts\";\n\nexport const ACTIVE_TURN_TTL_MS = 5 * 60_000;\nexport const AUTO_RELOAD_COORDINATOR_TTL_MS = 10 * 60_000;\n\nexport interface ReloadSessionRecord {\n\tkey: string;\n\tsource: \"active-turn\" | \"coordinator\";\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n\treason?: string;\n}\n\nexport interface PendingReloadBlockers {\n\tpending: boolean;\n\treason: string;\n\tblockers: ReloadSessionRecord[];\n\tdescriptions: string[];\n}\n\nexport interface ReloadBlockerOptions {\n\tagentDir?: string;\n\tnow?: number;\n\townKey?: string;\n\townPid?: number;\n\townSessionId?: string;\n\townSessionFile?: string;\n\tactiveTurnTtlMs?: number;\n\tcoordinatorTtlMs?: number;\n\tisProcessAlive?: (pid: number | undefined) => boolean;\n}\n\ninterface ParsedSession {\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction readJsonFile(file: string): unknown {\n\ttry {\n\t\tif (!existsSync(file)) return undefined;\n\t\treturn JSON.parse(readFileSync(file, \"utf8\")) as unknown;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction stringValue(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction numberValue(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\treturn undefined;\n}\n\nfunction booleanValue(value: unknown): boolean | undefined {\n\treturn typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction parseSession(value: unknown): ParsedSession | undefined {\n\tif (!isRecord(value)) return undefined;\n\treturn {\n\t\tpid: numberValue(value.pid),\n\t\tsessionId: stringValue(value.sessionId),\n\t\tsessionFile: stringValue(value.sessionFile),\n\t\tcwd: stringValue(value.cwd),\n\t\tactive: booleanValue(value.active),\n\t\tupdatedAt: numberValue(value.updatedAt),\n\t\tseenAt: numberValue(value.seenAt),\n\t\treloadedAt: numberValue(value.reloadedAt),\n\t};\n}\n\nexport function isReloadSessionProcessAlive(pid: number | undefined): boolean {\n\tif (pid === undefined || !Number.isFinite(pid) || pid <= 0) return false;\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code =\n\t\t\terror && typeof error === \"object\" && \"code\" in error ? String((error as { code?: unknown }).code) : \"\";\n\t\treturn code === \"EPERM\";\n\t}\n}\n\nfunction isOwnSession(key: string, session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\tif (options.ownKey && key === options.ownKey) return true;\n\tif (options.ownPid !== undefined && session.pid === options.ownPid) return true;\n\tif (options.ownSessionId && session.sessionId === options.ownSessionId) return true;\n\tif (options.ownSessionFile && session.sessionFile === options.ownSessionFile) return true;\n\treturn false;\n}\n\nfunction addBlocker(blockers: Map<string, ReloadSessionRecord>, record: ReloadSessionRecord): void {\n\tconst identity = [\n\t\trecord.key,\n\t\trecord.pid ?? \"\",\n\t\trecord.sessionId ?? \"\",\n\t\trecord.sessionFile ?? \"\",\n\t\trecord.cwd ?? \"\",\n\t].join(\"\\0\");\n\tconst existing = blockers.get(identity);\n\tif (!existing || (existing.source === \"coordinator\" && record.source === \"active-turn\")) {\n\t\tblockers.set(identity, record);\n\t}\n}\n\nfunction activeTurnBlockers(options: ReloadBlockerOptions): ReloadSessionRecord[] {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.activeTurnTtlMs ?? ACTIVE_TURN_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst registry = readJsonFile(join(agentDir, \"pi-active-turns.json\"));\n\tif (!isRecord(registry) || !isRecord(registry.sessions)) return [];\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tfor (const [key, rawSession] of Object.entries(registry.sessions)) {\n\t\tconst session = parseSession(rawSession);\n\t\tif (!session?.active) continue;\n\t\tif (isOwnSession(key, session, options)) continue;\n\t\tif (session.updatedAt === undefined || now - session.updatedAt > ttl) continue;\n\t\tif (!isAlive(session.pid)) continue;\n\t\tblockers.push({ key, source: \"active-turn\", ...session });\n\t}\n\treturn blockers;\n}\n\nfunction coordinatorBlockers(options: ReloadBlockerOptions): { blockers: ReloadSessionRecord[]; reason: string } {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.coordinatorTtlMs ?? AUTO_RELOAD_COORDINATOR_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst coordinator = readJsonFile(join(agentDir, \"pi-auto-reload-state.json\"));\n\tif (!isRecord(coordinator) || !isRecord(coordinator.changes)) return { blockers: [], reason: \"\" };\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tlet reason = \"\";\n\tfor (const rawChange of Object.values(coordinator.changes)) {\n\t\tif (!isRecord(rawChange)) continue;\n\t\tconst firstSeenAt = numberValue(rawChange.firstSeenAt);\n\t\tif (firstSeenAt === undefined || now - firstSeenAt > ttl) continue;\n\t\treason ||= stringValue(rawChange.reason) ?? \"\";\n\t\tif (!isRecord(rawChange.sessions)) continue;\n\t\tfor (const [key, rawSession] of Object.entries(rawChange.sessions)) {\n\t\t\tconst session = parseSession(rawSession);\n\t\t\tif (!session) continue;\n\t\t\tif (session.reloadedAt !== undefined) continue;\n\t\t\tif (isOwnSession(key, session, options)) continue;\n\t\t\tif (!isAlive(session.pid)) continue;\n\t\t\tblockers.push({ key, source: \"coordinator\", reason: stringValue(rawChange.reason), ...session });\n\t\t}\n\t}\n\treturn { blockers, reason };\n}\n\nexport function describeReloadSession(\n\trecord: Pick<ReloadSessionRecord, \"key\" | \"pid\" | \"sessionId\" | \"sessionFile\" | \"cwd\">,\n): string {\n\tconst label = record.sessionId ?? record.sessionFile ?? record.cwd ?? String(record.pid ?? \"unknown\");\n\tconst parts = [`${record.key}:${label}`];\n\tif (record.pid !== undefined) parts.push(`pid=${record.pid}`);\n\tif (record.cwd) parts.push(`cwd=${record.cwd}`);\n\tif (record.sessionFile) parts.push(`file=${record.sessionFile}`);\n\treturn parts.join(\" \");\n}\n\nexport function getPendingReloadBlockers(options: ReloadBlockerOptions = {}): PendingReloadBlockers {\n\tconst byIdentity = new Map<string, ReloadSessionRecord>();\n\tfor (const blocker of activeTurnBlockers(options)) addBlocker(byIdentity, blocker);\n\tconst coordinator = coordinatorBlockers(options);\n\tfor (const blocker of coordinator.blockers) addBlocker(byIdentity, blocker);\n\tconst blockers = [...byIdentity.values()].sort((a, b) =>\n\t\tdescribeReloadSession(a).localeCompare(describeReloadSession(b)),\n\t);\n\treturn {\n\t\tpending: blockers.length > 0,\n\t\treason:\n\t\t\tcoordinator.reason ||\n\t\t\t(blockers.length ? \"Pi auto-reload is waiting for active peer/background session(s).\" : \"\"),\n\t\tblockers,\n\t\tdescriptions: blockers.map(describeReloadSession),\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reload-blockers.js","sourceRoot":"","sources":["../../src/core/reload-blockers.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getAgentDir } from \"../config.ts\";\n\nexport const ACTIVE_TURN_TTL_MS = 5 * 60_000;\nexport const AUTO_RELOAD_COORDINATOR_TTL_MS = 10 * 60_000;\n\nexport interface ReloadSessionRecord {\n\tkey: string;\n\tsource: \"active-turn\" | \"coordinator\";\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n\treason?: string;\n}\n\nexport interface PendingReloadBlockers {\n\tpending: boolean;\n\treason: string;\n\tblockers: ReloadSessionRecord[];\n\tdescriptions: string[];\n}\n\nexport interface ReloadBlockerOptions {\n\tagentDir?: string;\n\tnow?: number;\n\townKey?: string;\n\townPid?: number;\n\townSessionId?: string;\n\townSessionFile?: string;\n\tactiveTurnTtlMs?: number;\n\tcoordinatorTtlMs?: number;\n\t/** Auto Learn workers are memory-first, short-lived, and should not block foreground reload/adaptive work by default. */\n\tincludeAutoLearnSessions?: boolean;\n\tisProcessAlive?: (pid: number | undefined) => boolean;\n}\n\ninterface ParsedSession {\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction readJsonFile(file: string): unknown {\n\ttry {\n\t\tif (!existsSync(file)) return undefined;\n\t\treturn JSON.parse(readFileSync(file, \"utf8\")) as unknown;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction stringValue(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction numberValue(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\treturn undefined;\n}\n\nfunction booleanValue(value: unknown): boolean | undefined {\n\treturn typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction parseSession(value: unknown): ParsedSession | undefined {\n\tif (!isRecord(value)) return undefined;\n\treturn {\n\t\tpid: numberValue(value.pid),\n\t\tsessionId: stringValue(value.sessionId),\n\t\tsessionFile: stringValue(value.sessionFile),\n\t\tcwd: stringValue(value.cwd),\n\t\tactive: booleanValue(value.active),\n\t\tupdatedAt: numberValue(value.updatedAt),\n\t\tseenAt: numberValue(value.seenAt),\n\t\treloadedAt: numberValue(value.reloadedAt),\n\t};\n}\n\nexport function isReloadSessionProcessAlive(pid: number | undefined): boolean {\n\tif (pid === undefined || !Number.isFinite(pid) || pid <= 0) return false;\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code =\n\t\t\terror && typeof error === \"object\" && \"code\" in error ? String((error as { code?: unknown }).code) : \"\";\n\t\treturn code === \"EPERM\";\n\t}\n}\n\nfunction isOwnSession(key: string, session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\tif (options.ownKey && key === options.ownKey) return true;\n\tif (options.ownPid !== undefined && session.pid === options.ownPid) return true;\n\tif (options.ownSessionId && session.sessionId === options.ownSessionId) return true;\n\tif (options.ownSessionFile && session.sessionFile === options.ownSessionFile) return true;\n\treturn false;\n}\n\nfunction isAutoLearnSession(session: ParsedSession): boolean {\n\treturn !!session.sessionId?.startsWith(\"auto-learn-\");\n}\n\nfunction shouldIgnoreSession(session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\treturn options.includeAutoLearnSessions !== true && isAutoLearnSession(session);\n}\n\nfunction addBlocker(blockers: Map<string, ReloadSessionRecord>, record: ReloadSessionRecord): void {\n\tconst identity = [\n\t\trecord.key,\n\t\trecord.pid ?? \"\",\n\t\trecord.sessionId ?? \"\",\n\t\trecord.sessionFile ?? \"\",\n\t\trecord.cwd ?? \"\",\n\t].join(\"\\0\");\n\tconst existing = blockers.get(identity);\n\tif (!existing || (existing.source === \"coordinator\" && record.source === \"active-turn\")) {\n\t\tblockers.set(identity, record);\n\t}\n}\n\nfunction activeTurnBlockers(options: ReloadBlockerOptions): ReloadSessionRecord[] {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.activeTurnTtlMs ?? ACTIVE_TURN_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst registry = readJsonFile(join(agentDir, \"pi-active-turns.json\"));\n\tif (!isRecord(registry) || !isRecord(registry.sessions)) return [];\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tfor (const [key, rawSession] of Object.entries(registry.sessions)) {\n\t\tconst session = parseSession(rawSession);\n\t\tif (!session?.active) continue;\n\t\tif (isOwnSession(key, session, options) || shouldIgnoreSession(session, options)) continue;\n\t\tif (session.updatedAt === undefined || now - session.updatedAt > ttl) continue;\n\t\tif (!isAlive(session.pid)) continue;\n\t\tblockers.push({ key, source: \"active-turn\", ...session });\n\t}\n\treturn blockers;\n}\n\nfunction coordinatorBlockers(options: ReloadBlockerOptions): { blockers: ReloadSessionRecord[]; reason: string } {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.coordinatorTtlMs ?? AUTO_RELOAD_COORDINATOR_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst coordinator = readJsonFile(join(agentDir, \"pi-auto-reload-state.json\"));\n\tif (!isRecord(coordinator) || !isRecord(coordinator.changes)) return { blockers: [], reason: \"\" };\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tlet reason = \"\";\n\tfor (const rawChange of Object.values(coordinator.changes)) {\n\t\tif (!isRecord(rawChange)) continue;\n\t\tconst firstSeenAt = numberValue(rawChange.firstSeenAt);\n\t\tif (firstSeenAt === undefined || now - firstSeenAt > ttl) continue;\n\t\treason ||= stringValue(rawChange.reason) ?? \"\";\n\t\tif (!isRecord(rawChange.sessions)) continue;\n\t\tfor (const [key, rawSession] of Object.entries(rawChange.sessions)) {\n\t\t\tconst session = parseSession(rawSession);\n\t\t\tif (!session) continue;\n\t\t\tif (session.reloadedAt !== undefined) continue;\n\t\t\tif (isOwnSession(key, session, options) || shouldIgnoreSession(session, options)) continue;\n\t\t\tif (!isAlive(session.pid)) continue;\n\t\t\tblockers.push({ key, source: \"coordinator\", reason: stringValue(rawChange.reason), ...session });\n\t\t}\n\t}\n\treturn { blockers, reason };\n}\n\nexport function describeReloadSession(\n\trecord: Pick<ReloadSessionRecord, \"key\" | \"pid\" | \"sessionId\" | \"sessionFile\" | \"cwd\">,\n): string {\n\tconst label = record.sessionId ?? record.sessionFile ?? record.cwd ?? String(record.pid ?? \"unknown\");\n\tconst parts = [`${record.key}:${label}`];\n\tif (record.pid !== undefined) parts.push(`pid=${record.pid}`);\n\tif (record.cwd) parts.push(`cwd=${record.cwd}`);\n\tif (record.sessionFile) parts.push(`file=${record.sessionFile}`);\n\treturn parts.join(\" \");\n}\n\nexport function getPendingReloadBlockers(options: ReloadBlockerOptions = {}): PendingReloadBlockers {\n\tconst byIdentity = new Map<string, ReloadSessionRecord>();\n\tfor (const blocker of activeTurnBlockers(options)) addBlocker(byIdentity, blocker);\n\tconst coordinator = coordinatorBlockers(options);\n\tfor (const blocker of coordinator.blockers) addBlocker(byIdentity, blocker);\n\tconst blockers = [...byIdentity.values()].sort((a, b) =>\n\t\tdescribeReloadSession(a).localeCompare(describeReloadSession(b)),\n\t);\n\treturn {\n\t\tpending: blockers.length > 0,\n\t\treason:\n\t\t\tcoordinator.reason ||\n\t\t\t(blockers.length ? \"Pi auto-reload is waiting for active peer/background session(s).\" : \"\"),\n\t\tblockers,\n\t\tdescriptions: blockers.map(describeReloadSession),\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-loader.d.ts","sourceRoot":"","sources":["../../src/core/resource-loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport chalk from \"chalk\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { loadThemeFromPath, type Theme } from \"../modes/interactive/theme/theme.ts\";\nimport type { ResourceDiagnostic } from \"./diagnostics.ts\";\n\nexport type { ResourceCollision, ResourceDiagnostic } from \"./diagnostics.ts\";\n\nimport { canonicalizePath, isLocalPath, resolvePath } from \"../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"./event-bus.ts\";\nimport { createExtensionRuntime, loadExtensionFromFactory, loadExtensions } from \"./extensions/loader.ts\";\nimport type { Extension, ExtensionFactory, ExtensionRuntime, LoadExtensionsResult } from \"./extensions/types.ts\";\nimport { DefaultPackageManager, type PathMetadata } from \"./package-manager.ts\";\nimport type { PromptTemplate } from \"./prompt-templates.ts\";\nimport { loadPromptTemplates } from \"./prompt-templates.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { loadSkills } from \"./skills.ts\";\nimport { createSourceInfo, type SourceInfo } from \"./source-info.ts\";\n\nexport interface ResourceExtensionPaths {\n\tskillPaths?: Array<{ path: string; metadata: PathMetadata }>;\n\tpromptPaths?: Array<{ path: string; metadata: PathMetadata }>;\n\tthemePaths?: Array<{ path: string; metadata: PathMetadata }>;\n}\n\nexport interface ResourceLoader {\n\tgetExtensions(): LoadExtensionsResult;\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] };\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] };\n\tgetThemes(): { themes: Theme[]; diagnostics: ResourceDiagnostic[] };\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content?: string }> };\n\tgetSystemPrompt(): string | undefined;\n\tgetAppendSystemPrompt(): string[];\n\textendResources(paths: ResourceExtensionPaths): void;\n\treload(): Promise<void>;\n}\n\nfunction resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\nconst CONTEXT_THREAT_PATTERNS: Array<{ label: string; pattern: RegExp }> = [\n\t{\n\t\tlabel: \"instruction override\",\n\t\tpattern:\n\t\t\t/\\b(?:ignore|disregard|override|bypass)\\b.{0,80}\\b(?:previous|prior|above|system|developer|agent)\\b.{0,80}\\binstructions?\\b/i,\n\t},\n\t{\n\t\tlabel: \"secret exfiltration\",\n\t\tpattern:\n\t\t\t/\\b(?:reveal|print|dump|exfiltrate|send|upload)\\b.{0,80}\\b(?:secrets?|tokens?|api[_ -]?keys?|credentials?|environment variables?|\\.env)\\b/i,\n\t},\n\t{\n\t\tlabel: \"hidden instruction\",\n\t\tpattern: /\\b(?:do not tell|don't tell|hide this from)\\b.{0,80}\\b(?:user|operator|developer)\\b/i,\n\t},\n];\n\nexport function scanContextFileThreats(content: string): string[] {\n\treturn CONTEXT_THREAT_PATTERNS.filter(({ pattern }) => pattern.test(content)).map(({ label }) => label);\n}\n\nfunction sanitizeContextFileContent(filePath: string, content: string): string {\n\tconst findings = scanContextFileThreats(content);\n\tif (findings.length === 0) return content;\n\tconsole.error(chalk.yellow(`Warning: Blocked context file ${filePath}: ${findings.join(\", \")}`));\n\treturn `[BLOCKED: ${filePath} contained potential prompt injection (${findings.join(\", \")}). Content not loaded.]`;\n}\n\nfunction loadContextFilesFromDir(dir: string): Array<{ path: string; content: string }> {\n\tconst candidates = [\"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\", \"GEMINI.md\", \"GEMINI.MD\"];\n\tconst files: Array<{ path: string; content: string }> = [];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\tconst content = readFileSync(filePath, \"utf-8\");\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: sanitizeContextFileContent(filePath, content),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn files;\n}\n\nexport function loadProjectContextFiles(options: {\n\tcwd: string;\n\tagentDir: string;\n}): Array<{ path: string; content?: string }> {\n\tconst resolvedCwd = resolvePath(options.cwd);\n\tconst resolvedAgentDir = resolvePath(options.agentDir);\n\n\tconst contextFiles: Array<{ path: string; content?: string }> = [];\n\tconst seenPaths = new Set<string>();\n\n\tfor (const globalContext of loadContextFilesFromDir(resolvedAgentDir)) {\n\t\tcontextFiles.push(globalContext);\n\t\tseenPaths.add(globalContext.path);\n\t}\n\n\tconst ancestorContextFiles: Array<{ path: string; content?: string }> = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFilesInDir = loadContextFilesFromDir(currentDir).filter(\n\t\t\t(contextFile) => !seenPaths.has(contextFile.path),\n\t\t);\n\t\tif (contextFilesInDir.length > 0) {\n\t\t\tancestorContextFiles.unshift(...contextFilesInDir);\n\t\t\tfor (const contextFile of contextFilesInDir) {\n\t\t\t\tseenPaths.add(contextFile.path);\n\t\t\t}\n\t\t}\n\n\t\tif (currentDir === root) break;\n\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break;\n\t\tcurrentDir = parentDir;\n\t}\n\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nexport interface DefaultResourceLoaderOptions {\n\tcwd: string;\n\tagentDir: string;\n\tsettingsManager?: SettingsManager;\n\teventBus?: EventBus;\n\tadditionalExtensionPaths?: string[];\n\tadditionalSkillPaths?: string[];\n\tadditionalPromptTemplatePaths?: string[];\n\tadditionalThemePaths?: string[];\n\textensionFactories?: ExtensionFactory[];\n\tnoExtensions?: boolean;\n\tnoSkills?: boolean;\n\tnoPromptTemplates?: boolean;\n\tnoThemes?: boolean;\n\tnoContextFiles?: boolean;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string[];\n\textensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;\n\tskillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tpromptsOverride?: (base: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tprompts: PromptTemplate[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tthemesOverride?: (base: { themes: Theme[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tagentsFilesOverride?: (base: { agentsFiles: Array<{ path: string; content?: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content?: string }>;\n\t};\n\tsystemPromptOverride?: (base: string | undefined) => string | undefined;\n\tappendSystemPromptOverride?: (base: string[]) => string[];\n}\n\nexport class DefaultResourceLoader implements ResourceLoader {\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate settingsManager: SettingsManager;\n\tprivate eventBus: EventBus;\n\tprivate packageManager: DefaultPackageManager;\n\tprivate additionalExtensionPaths: string[];\n\tprivate additionalSkillPaths: string[];\n\tprivate additionalPromptTemplatePaths: string[];\n\tprivate additionalThemePaths: string[];\n\tprivate extensionFactories: ExtensionFactory[];\n\tprivate noExtensions: boolean;\n\tprivate noSkills: boolean;\n\tprivate noPromptTemplates: boolean;\n\tprivate noThemes: boolean;\n\tprivate noContextFiles: boolean;\n\tprivate systemPromptSource?: string;\n\tprivate appendSystemPromptSource?: string[];\n\tprivate extensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;\n\tprivate skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate promptsOverride?: (base: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tprompts: PromptTemplate[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate themesOverride?: (base: { themes: Theme[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate agentsFilesOverride?: (base: { agentsFiles: Array<{ path: string; content?: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content?: string }>;\n\t};\n\tprivate systemPromptOverride?: (base: string | undefined) => string | undefined;\n\tprivate appendSystemPromptOverride?: (base: string[]) => string[];\n\n\tprivate extensionsResult: LoadExtensionsResult;\n\tprivate skills: Skill[];\n\tprivate skillDiagnostics: ResourceDiagnostic[];\n\tprivate prompts: PromptTemplate[];\n\tprivate promptDiagnostics: ResourceDiagnostic[];\n\tprivate themes: Theme[];\n\tprivate themeDiagnostics: ResourceDiagnostic[];\n\tprivate agentsFiles: Array<{ path: string; content?: string }>;\n\tprivate systemPrompt?: string;\n\tprivate appendSystemPrompt: string[];\n\tprivate lastSkillPaths: string[];\n\tprivate extensionSkillSourceInfos: Map<string, SourceInfo>;\n\tprivate extensionPromptSourceInfos: Map<string, SourceInfo>;\n\tprivate extensionThemeSourceInfos: Map<string, SourceInfo>;\n\tprivate lastPromptPaths: string[];\n\tprivate lastThemePaths: string[];\n\n\tconstructor(options: DefaultResourceLoaderOptions) {\n\t\tthis.cwd = resolvePath(options.cwd);\n\t\tthis.agentDir = resolvePath(options.agentDir);\n\t\tthis.settingsManager = options.settingsManager ?? SettingsManager.create(this.cwd, this.agentDir);\n\t\tthis.eventBus = options.eventBus ?? createEventBus();\n\t\tthis.packageManager = new DefaultPackageManager({\n\t\t\tcwd: this.cwd,\n\t\t\tagentDir: this.agentDir,\n\t\t\tsettingsManager: this.settingsManager,\n\t\t});\n\t\tthis.additionalExtensionPaths = options.additionalExtensionPaths ?? [];\n\t\tthis.additionalSkillPaths = options.additionalSkillPaths ?? [];\n\t\tthis.additionalPromptTemplatePaths = options.additionalPromptTemplatePaths ?? [];\n\t\tthis.additionalThemePaths = options.additionalThemePaths ?? [];\n\t\tthis.extensionFactories = options.extensionFactories ?? [];\n\t\tthis.noExtensions = options.noExtensions ?? false;\n\t\tthis.noSkills = options.noSkills ?? false;\n\t\tthis.noPromptTemplates = options.noPromptTemplates ?? false;\n\t\tthis.noThemes = options.noThemes ?? false;\n\t\tthis.noContextFiles = options.noContextFiles ?? false;\n\t\tthis.systemPromptSource = options.systemPrompt;\n\t\tthis.appendSystemPromptSource = options.appendSystemPrompt;\n\t\tthis.extensionsOverride = options.extensionsOverride;\n\t\tthis.skillsOverride = options.skillsOverride;\n\t\tthis.promptsOverride = options.promptsOverride;\n\t\tthis.themesOverride = options.themesOverride;\n\t\tthis.agentsFilesOverride = options.agentsFilesOverride;\n\t\tthis.systemPromptOverride = options.systemPromptOverride;\n\t\tthis.appendSystemPromptOverride = options.appendSystemPromptOverride;\n\n\t\tthis.extensionsResult = { extensions: [], errors: [], runtime: createExtensionRuntime() };\n\t\tthis.skills = [];\n\t\tthis.skillDiagnostics = [];\n\t\tthis.prompts = [];\n\t\tthis.promptDiagnostics = [];\n\t\tthis.themes = [];\n\t\tthis.themeDiagnostics = [];\n\t\tthis.agentsFiles = [];\n\t\tthis.appendSystemPrompt = [];\n\t\tthis.lastSkillPaths = [];\n\t\tthis.extensionSkillSourceInfos = new Map();\n\t\tthis.extensionPromptSourceInfos = new Map();\n\t\tthis.extensionThemeSourceInfos = new Map();\n\t\tthis.lastPromptPaths = [];\n\t\tthis.lastThemePaths = [];\n\t}\n\n\tgetExtensions(): LoadExtensionsResult {\n\t\treturn this.extensionsResult;\n\t}\n\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { skills: this.skills, diagnostics: this.skillDiagnostics };\n\t}\n\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { prompts: this.prompts, diagnostics: this.promptDiagnostics };\n\t}\n\n\tgetThemes(): { themes: Theme[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { themes: this.themes, diagnostics: this.themeDiagnostics };\n\t}\n\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content?: string }> } {\n\t\treturn { agentsFiles: this.agentsFiles };\n\t}\n\n\tgetSystemPrompt(): string | undefined {\n\t\treturn this.systemPrompt;\n\t}\n\n\tgetAppendSystemPrompt(): string[] {\n\t\treturn this.appendSystemPrompt;\n\t}\n\n\textendResources(paths: ResourceExtensionPaths): void {\n\t\tconst skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);\n\t\tconst promptPaths = this.normalizeExtensionPaths(paths.promptPaths ?? []);\n\t\tconst themePaths = this.normalizeExtensionPaths(paths.themePaths ?? []);\n\n\t\tfor (const entry of skillPaths) {\n\t\t\tthis.extensionSkillSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\t\tfor (const entry of promptPaths) {\n\t\t\tthis.extensionPromptSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\t\tfor (const entry of themePaths) {\n\t\t\tthis.extensionThemeSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\n\t\tif (skillPaths.length > 0) {\n\t\t\tthis.lastSkillPaths = this.mergePaths(\n\t\t\t\tthis.lastSkillPaths,\n\t\t\t\tskillPaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updateSkillsFromPaths(this.lastSkillPaths);\n\t\t}\n\n\t\tif (promptPaths.length > 0) {\n\t\t\tthis.lastPromptPaths = this.mergePaths(\n\t\t\t\tthis.lastPromptPaths,\n\t\t\t\tpromptPaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updatePromptsFromPaths(this.lastPromptPaths);\n\t\t}\n\n\t\tif (themePaths.length > 0) {\n\t\t\tthis.lastThemePaths = this.mergePaths(\n\t\t\t\tthis.lastThemePaths,\n\t\t\t\tthemePaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updateThemesFromPaths(this.lastThemePaths);\n\t\t}\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tawait this.settingsManager.reload();\n\t\tconst resolvedPaths = await this.packageManager.resolve();\n\t\tconst cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {\n\t\t\ttemporary: true,\n\t\t});\n\t\tconst metadataByPath = new Map<string, PathMetadata>();\n\n\t\tthis.extensionSkillSourceInfos = new Map();\n\t\tthis.extensionPromptSourceInfos = new Map();\n\t\tthis.extensionThemeSourceInfos = new Map();\n\n\t\t// Helper to extract enabled paths and store metadata\n\t\tconst getEnabledResources = (\n\t\t\tresources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,\n\t\t): Array<{ path: string; enabled: boolean; metadata: PathMetadata }> => {\n\t\t\tfor (const r of resources) {\n\t\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\t\tmetadataByPath.set(r.path, r.metadata);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resources.filter((r) => r.enabled);\n\t\t};\n\n\t\tconst getEnabledPaths = (\n\t\t\tresources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,\n\t\t): string[] => getEnabledResources(resources).map((r) => r.path);\n\t\tconst enabledExtensions = getEnabledPaths(resolvedPaths.extensions);\n\t\tconst enabledSkillResources = getEnabledResources(resolvedPaths.skills);\n\t\tconst enabledPrompts = getEnabledPaths(resolvedPaths.prompts);\n\t\tconst enabledThemes = getEnabledPaths(resolvedPaths.themes);\n\n\t\tconst mapSkillPath = (resource: { path: string; metadata: PathMetadata }): string => {\n\t\t\tif (resource.metadata.source !== \"auto\" && resource.metadata.origin !== \"package\") {\n\t\t\t\treturn resource.path;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(resource.path);\n\t\t\t\tif (!stats.isDirectory()) {\n\t\t\t\t\treturn resource.path;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn resource.path;\n\t\t\t}\n\t\t\tconst skillFile = join(resource.path, \"SKILL.md\");\n\t\t\tif (existsSync(skillFile)) {\n\t\t\t\tif (!metadataByPath.has(skillFile)) {\n\t\t\t\t\tmetadataByPath.set(skillFile, resource.metadata);\n\t\t\t\t}\n\t\t\t\treturn skillFile;\n\t\t\t}\n\t\t\treturn resource.path;\n\t\t};\n\n\t\tconst enabledSkills = enabledSkillResources.map(mapSkillPath);\n\n\t\t// Add CLI paths metadata\n\t\tfor (const r of cliExtensionPaths.extensions) {\n\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\tmetadataByPath.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n\t\t\t}\n\t\t}\n\t\tfor (const r of cliExtensionPaths.skills) {\n\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\tmetadataByPath.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n\t\t\t}\n\t\t}\n\n\t\tconst cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);\n\t\tconst cliEnabledSkills = getEnabledPaths(cliExtensionPaths.skills);\n\t\tconst cliEnabledPrompts = getEnabledPaths(cliExtensionPaths.prompts);\n\t\tconst cliEnabledThemes = getEnabledPaths(cliExtensionPaths.themes);\n\n\t\tconst extensionPaths = this.noExtensions\n\t\t\t? cliEnabledExtensions\n\t\t\t: this.mergePaths(cliEnabledExtensions, enabledExtensions);\n\n\t\tconst extensionsResult = await loadExtensions(extensionPaths, this.cwd, this.eventBus);\n\t\tconst inlineExtensions = await this.loadExtensionFactories(extensionsResult.runtime);\n\t\textensionsResult.extensions.push(...inlineExtensions.extensions);\n\t\textensionsResult.errors.push(...inlineExtensions.errors);\n\n\t\t// Detect extension conflicts (tools, commands, flags with same names from different extensions)\n\t\t// Keep all extensions loaded. Conflicts are reported as diagnostics, and precedence is handled by load order.\n\t\tconst conflicts = this.detectExtensionConflicts(extensionsResult.extensions);\n\t\tfor (const conflict of conflicts) {\n\t\t\textensionsResult.errors.push({ path: conflict.path, error: conflict.message });\n\t\t}\n\n\t\tfor (const p of this.additionalExtensionPaths) {\n\t\t\tif (isLocalPath(p)) {\n\t\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\t\tif (!existsSync(resolved)) {\n\t\t\t\t\textensionsResult.errors.push({ path: resolved, error: `Extension path does not exist: ${resolved}` });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;\n\t\tthis.applyExtensionSourceInfo(this.extensionsResult.extensions, metadataByPath);\n\n\t\tconst skillPaths = this.noSkills\n\t\t\t? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)\n\t\t\t: this.mergePaths([...cliEnabledSkills, ...enabledSkills], this.additionalSkillPaths);\n\n\t\tthis.lastSkillPaths = skillPaths;\n\t\tthis.updateSkillsFromPaths(skillPaths, metadataByPath);\n\t\tfor (const p of this.additionalSkillPaths) {\n\t\t\tif (isLocalPath(p)) {\n\t\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\t\tif (!existsSync(resolved) && !this.skillDiagnostics.some((d) => d.path === resolved)) {\n\t\t\t\t\tthis.skillDiagnostics.push({ type: \"error\", message: \"Skill path does not exist\", path: resolved });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst promptPaths = this.noPromptTemplates\n\t\t\t? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)\n\t\t\t: this.mergePaths([...cliEnabledPrompts, ...enabledPrompts], this.additionalPromptTemplatePaths);\n\n\t\tthis.lastPromptPaths = promptPaths;\n\t\tthis.updatePromptsFromPaths(promptPaths, metadataByPath);\n\t\tfor (const p of this.additionalPromptTemplatePaths) {\n\t\t\tif (isLocalPath(p)) {\n\t\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\t\tif (!existsSync(resolved) && !this.promptDiagnostics.some((d) => d.path === resolved)) {\n\t\t\t\t\tthis.promptDiagnostics.push({\n\t\t\t\t\t\ttype: \"error\",\n\t\t\t\t\t\tmessage: \"Prompt template path does not exist\",\n\t\t\t\t\t\tpath: resolved,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst themePaths = this.noThemes\n\t\t\t? this.mergePaths(cliEnabledThemes, this.additionalThemePaths)\n\t\t\t: this.mergePaths([...cliEnabledThemes, ...enabledThemes], this.additionalThemePaths);\n\n\t\tthis.lastThemePaths = themePaths;\n\t\tthis.updateThemesFromPaths(themePaths, metadataByPath);\n\t\tfor (const p of this.additionalThemePaths) {\n\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\tif (!existsSync(resolved) && !this.themeDiagnostics.some((d) => d.path === resolved)) {\n\t\t\t\tthis.themeDiagnostics.push({ type: \"error\", message: \"Theme path does not exist\", path: resolved });\n\t\t\t}\n\t\t}\n\n\t\tconst agentsFiles = {\n\t\t\tagentsFiles: this.noContextFiles ? [] : loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }),\n\t\t};\n\t\tconst resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;\n\t\tthis.agentsFiles = resolvedAgentsFiles.agentsFiles;\n\n\t\tconst baseSystemPrompt = resolvePromptInput(\n\t\t\tthis.systemPromptSource ?? this.discoverSystemPromptFile(),\n\t\t\t\"system prompt\",\n\t\t);\n\t\tthis.systemPrompt = this.systemPromptOverride ? this.systemPromptOverride(baseSystemPrompt) : baseSystemPrompt;\n\n\t\tconst appendSources =\n\t\t\tthis.appendSystemPromptSource ??\n\t\t\t(this.discoverAppendSystemPromptFile() ? [this.discoverAppendSystemPromptFile()!] : []);\n\t\tconst baseAppend = appendSources\n\t\t\t.map((s) => resolvePromptInput(s, \"append system prompt\"))\n\t\t\t.filter((s): s is string => s !== undefined);\n\t\tthis.appendSystemPrompt = this.appendSystemPromptOverride\n\t\t\t? this.appendSystemPromptOverride(baseAppend)\n\t\t\t: baseAppend;\n\t}\n\n\tprivate normalizeExtensionPaths(\n\t\tentries: Array<{ path: string; metadata: PathMetadata }>,\n\t): Array<{ path: string; metadata: PathMetadata }> {\n\t\treturn entries.map((entry) => {\n\t\t\tconst metadata = entry.metadata.baseDir\n\t\t\t\t? { ...entry.metadata, baseDir: this.resolveResourcePath(entry.metadata.baseDir) }\n\t\t\t\t: entry.metadata;\n\t\t\treturn {\n\t\t\t\tpath: this.resolveResourcePath(entry.path),\n\t\t\t\tmetadata,\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate updateSkillsFromPaths(skillPaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet skillsResult: { skills: Skill[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noSkills && skillPaths.length === 0) {\n\t\t\tskillsResult = { skills: [], diagnostics: [] };\n\t\t} else {\n\t\t\tskillsResult = loadSkills({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.agentDir,\n\t\t\t\tskillPaths,\n\t\t\t\tincludeDefaults: false,\n\t\t\t});\n\t\t}\n\t\tconst resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;\n\t\tthis.skills = resolvedSkills.skills.map((skill) => ({\n\t\t\t...skill,\n\t\t\tsourceInfo:\n\t\t\t\tthis.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ??\n\t\t\t\tskill.sourceInfo ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(skill.filePath),\n\t\t}));\n\t\tthis.skillDiagnostics = resolvedSkills.diagnostics;\n\t}\n\n\tprivate updatePromptsFromPaths(promptPaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet promptsResult: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noPromptTemplates && promptPaths.length === 0) {\n\t\t\tpromptsResult = { prompts: [], diagnostics: [] };\n\t\t} else {\n\t\t\tconst allPrompts = loadPromptTemplates({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.agentDir,\n\t\t\t\tpromptPaths,\n\t\t\t\tincludeDefaults: false,\n\t\t\t});\n\t\t\tpromptsResult = this.dedupePrompts(allPrompts);\n\t\t}\n\t\tconst resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;\n\t\tthis.prompts = resolvedPrompts.prompts.map((prompt) => ({\n\t\t\t...prompt,\n\t\t\tsourceInfo:\n\t\t\t\tthis.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ??\n\t\t\t\tprompt.sourceInfo ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(prompt.filePath),\n\t\t}));\n\t\tthis.promptDiagnostics = resolvedPrompts.diagnostics;\n\t}\n\n\tprivate updateThemesFromPaths(themePaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet themesResult: { themes: Theme[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noThemes && themePaths.length === 0) {\n\t\t\tthemesResult = { themes: [], diagnostics: [] };\n\t\t} else {\n\t\t\tconst loaded = this.loadThemes(themePaths, false);\n\t\t\tconst deduped = this.dedupeThemes(loaded.themes);\n\t\t\tthemesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };\n\t\t}\n\t\tconst resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;\n\t\tthis.themes = resolvedThemes.themes.map((theme) => {\n\t\t\tconst sourcePath = theme.sourcePath;\n\t\t\ttheme.sourceInfo = sourcePath\n\t\t\t\t? (this.findSourceInfoForPath(sourcePath, this.extensionThemeSourceInfos, metadataByPath) ??\n\t\t\t\t\ttheme.sourceInfo ??\n\t\t\t\t\tthis.getDefaultSourceInfoForPath(sourcePath))\n\t\t\t\t: theme.sourceInfo;\n\t\t\treturn theme;\n\t\t});\n\t\tthis.themeDiagnostics = resolvedThemes.diagnostics;\n\t}\n\n\tprivate applyExtensionSourceInfo(extensions: Extension[], metadataByPath: Map<string, PathMetadata>): void {\n\t\tfor (const extension of extensions) {\n\t\t\textension.sourceInfo =\n\t\t\t\tthis.findSourceInfoForPath(extension.path, undefined, metadataByPath) ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(extension.path);\n\t\t\tfor (const command of extension.commands.values()) {\n\t\t\t\tcommand.sourceInfo = extension.sourceInfo;\n\t\t\t}\n\t\t\tfor (const tool of extension.tools.values()) {\n\t\t\t\ttool.sourceInfo = extension.sourceInfo;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate findSourceInfoForPath(\n\t\tresourcePath: string,\n\t\textraSourceInfos?: Map<string, SourceInfo>,\n\t\tmetadataByPath?: Map<string, PathMetadata>,\n\t): SourceInfo | undefined {\n\t\tif (!resourcePath) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (resourcePath.startsWith(\"<\")) {\n\t\t\treturn this.getDefaultSourceInfoForPath(resourcePath);\n\t\t}\n\n\t\tconst normalizedResourcePath = resolve(resourcePath);\n\t\tif (extraSourceInfos) {\n\t\t\tfor (const [sourcePath, sourceInfo] of extraSourceInfos.entries()) {\n\t\t\t\tconst normalizedSourcePath = resolve(sourcePath);\n\t\t\t\tif (\n\t\t\t\t\tnormalizedResourcePath === normalizedSourcePath ||\n\t\t\t\t\tnormalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)\n\t\t\t\t) {\n\t\t\t\t\treturn { ...sourceInfo, path: resourcePath };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (metadataByPath) {\n\t\t\tconst exact = metadataByPath.get(normalizedResourcePath) ?? metadataByPath.get(resourcePath);\n\t\t\tif (exact) {\n\t\t\t\treturn createSourceInfo(resourcePath, exact);\n\t\t\t}\n\n\t\t\tfor (const [sourcePath, metadata] of metadataByPath.entries()) {\n\t\t\t\tconst normalizedSourcePath = resolve(sourcePath);\n\t\t\t\tif (\n\t\t\t\t\tnormalizedResourcePath === normalizedSourcePath ||\n\t\t\t\t\tnormalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)\n\t\t\t\t) {\n\t\t\t\t\treturn createSourceInfo(resourcePath, metadata);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate getDefaultSourceInfoForPath(filePath: string): SourceInfo {\n\t\tif (filePath.startsWith(\"<\") && filePath.endsWith(\">\")) {\n\t\t\treturn {\n\t\t\t\tpath: filePath,\n\t\t\t\tsource: filePath.slice(1, -1).split(\":\")[0] || \"temporary\",\n\t\t\t\tscope: \"temporary\",\n\t\t\t\torigin: \"top-level\",\n\t\t\t};\n\t\t}\n\n\t\tconst normalizedPath = resolve(filePath);\n\t\tconst agentRoots = [\n\t\t\tjoin(this.agentDir, \"skills\"),\n\t\t\tjoin(this.agentDir, \"prompts\"),\n\t\t\tjoin(this.agentDir, \"themes\"),\n\t\t\tjoin(this.agentDir, \"extensions\"),\n\t\t];\n\t\tconst projectRoots = [\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"skills\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"prompts\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"themes\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"extensions\"),\n\t\t];\n\n\t\tfor (const root of agentRoots) {\n\t\t\tif (this.isUnderPath(normalizedPath, root)) {\n\t\t\t\treturn { path: filePath, source: \"local\", scope: \"user\", origin: \"top-level\", baseDir: root };\n\t\t\t}\n\t\t}\n\n\t\tfor (const root of projectRoots) {\n\t\t\tif (this.isUnderPath(normalizedPath, root)) {\n\t\t\t\treturn { path: filePath, source: \"local\", scope: \"project\", origin: \"top-level\", baseDir: root };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tpath: filePath,\n\t\t\tsource: \"local\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t\tbaseDir: statSync(normalizedPath).isDirectory() ? normalizedPath : resolve(normalizedPath, \"..\"),\n\t\t};\n\t}\n\n\tprivate mergePaths(primary: string[], additional: string[]): string[] {\n\t\tconst merged: string[] = [];\n\t\tconst seen = new Set<string>();\n\n\t\tfor (const p of [...primary, ...additional]) {\n\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\tconst canonicalPath = canonicalizePath(resolved);\n\t\t\tif (seen.has(canonicalPath)) continue;\n\t\t\tseen.add(canonicalPath);\n\t\t\tmerged.push(resolved);\n\t\t}\n\n\t\treturn merged;\n\t}\n\n\tprivate resolveResourcePath(p: string): string {\n\t\treturn resolvePath(p, this.cwd, { trim: true });\n\t}\n\n\tprivate loadThemes(\n\t\tpaths: string[],\n\t\tincludeDefaults: boolean = true,\n\t): {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t} {\n\t\tconst themes: Theme[] = [];\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\t\tif (includeDefaults) {\n\t\t\tconst defaultDirs = [join(this.agentDir, \"themes\"), join(this.cwd, CONFIG_DIR_NAME, \"themes\")];\n\n\t\t\tfor (const dir of defaultDirs) {\n\t\t\t\tthis.loadThemesFromDir(dir, themes, diagnostics);\n\t\t\t}\n\t\t}\n\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\tif (!existsSync(resolved)) {\n\t\t\t\tdiagnostics.push({ type: \"warning\", message: \"theme path does not exist\", path: resolved });\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(resolved);\n\t\t\t\tif (stats.isDirectory()) {\n\t\t\t\t\tthis.loadThemesFromDir(resolved, themes, diagnostics);\n\t\t\t\t} else if (stats.isFile() && resolved.endsWith(\".json\")) {\n\t\t\t\t\tthis.loadThemeFromFile(resolved, themes, diagnostics);\n\t\t\t\t} else {\n\t\t\t\t\tdiagnostics.push({ type: \"warning\", message: \"theme path is not a json file\", path: resolved });\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"failed to read theme path\";\n\t\t\t\tdiagnostics.push({ type: \"warning\", message, path: resolved });\n\t\t\t}\n\t\t}\n\n\t\treturn { themes, diagnostics };\n\t}\n\n\tprivate loadThemesFromDir(dir: string, themes: Theme[], diagnostics: ResourceDiagnostic[]): void {\n\t\tif (!existsSync(dir)) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\t\tfor (const entry of entries) {\n\t\t\t\tlet isFile = entry.isFile();\n\t\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tisFile = statSync(join(dir, entry.name)).isFile();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!isFile) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!entry.name.endsWith(\".json\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.loadThemeFromFile(join(dir, entry.name), themes, diagnostics);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read theme directory\";\n\t\t\tdiagnostics.push({ type: \"warning\", message, path: dir });\n\t\t}\n\t}\n\n\tprivate loadThemeFromFile(filePath: string, themes: Theme[], diagnostics: ResourceDiagnostic[]): void {\n\t\ttry {\n\t\t\tthemes.push(loadThemeFromPath(filePath));\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to load theme\";\n\t\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\t}\n\t}\n\n\tprivate async loadExtensionFactories(runtime: ExtensionRuntime): Promise<{\n\t\textensions: Extension[];\n\t\terrors: Array<{ path: string; error: string }>;\n\t}> {\n\t\tconst extensions: Extension[] = [];\n\t\tconst errors: Array<{ path: string; error: string }> = [];\n\n\t\tfor (const [index, factory] of this.extensionFactories.entries()) {\n\t\t\tconst extensionPath = `<inline:${index + 1}>`;\n\t\t\ttry {\n\t\t\t\tconst extension = await loadExtensionFromFactory(factory, this.cwd, this.eventBus, runtime, extensionPath);\n\t\t\t\textensions.push(extension);\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"failed to load extension\";\n\t\t\t\terrors.push({ path: extensionPath, error: message });\n\t\t\t}\n\t\t}\n\n\t\treturn { extensions, errors };\n\t}\n\n\tprivate dedupePrompts(prompts: PromptTemplate[]): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst seen = new Map<string, PromptTemplate>();\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\n\t\tfor (const prompt of prompts) {\n\t\t\tconst existing = seen.get(prompt.name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"/${prompt.name}\" collision`,\n\t\t\t\t\tpath: prompt.filePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"prompt\",\n\t\t\t\t\t\tname: prompt.name,\n\t\t\t\t\t\twinnerPath: existing.filePath,\n\t\t\t\t\t\tloserPath: prompt.filePath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tseen.set(prompt.name, prompt);\n\t\t\t}\n\t\t}\n\n\t\treturn { prompts: Array.from(seen.values()), diagnostics };\n\t}\n\n\tprivate dedupeThemes(themes: Theme[]): { themes: Theme[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst seen = new Map<string, Theme>();\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\n\t\tfor (const t of themes) {\n\t\t\tconst name = t.name ?? \"unnamed\";\n\t\t\tconst existing = seen.get(name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${name}\" collision`,\n\t\t\t\t\tpath: t.sourcePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"theme\",\n\t\t\t\t\t\tname,\n\t\t\t\t\t\twinnerPath: existing.sourcePath ?? \"<builtin>\",\n\t\t\t\t\t\tloserPath: t.sourcePath ?? \"<builtin>\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tseen.set(name, t);\n\t\t\t}\n\t\t}\n\n\t\treturn { themes: Array.from(seen.values()), diagnostics };\n\t}\n\n\tprivate discoverSystemPromptFile(): string | undefined {\n\t\tconst projectPath = join(this.cwd, CONFIG_DIR_NAME, \"SYSTEM.md\");\n\t\tif (existsSync(projectPath)) {\n\t\t\treturn projectPath;\n\t\t}\n\n\t\tconst globalPath = join(this.agentDir, \"SYSTEM.md\");\n\t\tif (existsSync(globalPath)) {\n\t\t\treturn globalPath;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate discoverAppendSystemPromptFile(): string | undefined {\n\t\tconst projectPath = join(this.cwd, CONFIG_DIR_NAME, \"APPEND_SYSTEM.md\");\n\t\tif (existsSync(projectPath)) {\n\t\t\treturn projectPath;\n\t\t}\n\n\t\tconst globalPath = join(this.agentDir, \"APPEND_SYSTEM.md\");\n\t\tif (existsSync(globalPath)) {\n\t\t\treturn globalPath;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate isUnderPath(target: string, root: string): boolean {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t}\n\n\tprivate detectExtensionConflicts(extensions: Extension[]): Array<{ path: string; message: string }> {\n\t\tconst conflicts: Array<{ path: string; message: string }> = [];\n\n\t\t// Track which extension registered each tool and flag\n\t\tconst toolOwners = new Map<string, string>();\n\t\tconst flagOwners = new Map<string, string>();\n\n\t\tfor (const ext of extensions) {\n\t\t\t// Check tools\n\t\t\tfor (const toolName of ext.tools.keys()) {\n\t\t\t\tconst existingOwner = toolOwners.get(toolName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Tool \"${toolName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\ttoolOwners.set(toolName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check flags\n\t\t\tfor (const flagName of ext.flags.keys()) {\n\t\t\t\tconst existingOwner = flagOwners.get(flagName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Flag \"--${flagName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tflagOwners.set(flagName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn conflicts;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"resource-loader.d.ts","sourceRoot":"","sources":["../../src/core/resource-loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport chalk from \"chalk\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { loadThemeFromPath, type Theme } from \"../modes/interactive/theme/theme.ts\";\nimport type { ResourceDiagnostic } from \"./diagnostics.ts\";\n\nexport type { ResourceCollision, ResourceDiagnostic } from \"./diagnostics.ts\";\n\nimport { canonicalizePath, isLocalPath, resolvePath } from \"../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"./event-bus.ts\";\nimport { createExtensionRuntime, loadExtensionFromFactory, loadExtensions } from \"./extensions/loader.ts\";\nimport type { Extension, ExtensionFactory, ExtensionRuntime, LoadExtensionsResult } from \"./extensions/types.ts\";\nimport { DefaultPackageManager, type PathMetadata } from \"./package-manager.ts\";\nimport type { PromptTemplate } from \"./prompt-templates.ts\";\nimport { loadPromptTemplates } from \"./prompt-templates.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { loadSkills } from \"./skills.ts\";\nimport { createSourceInfo, type SourceInfo } from \"./source-info.ts\";\n\nexport interface ResourceExtensionPaths {\n\tskillPaths?: Array<{ path: string; metadata: PathMetadata }>;\n\tpromptPaths?: Array<{ path: string; metadata: PathMetadata }>;\n\tthemePaths?: Array<{ path: string; metadata: PathMetadata }>;\n}\n\nexport interface ResourceLoader {\n\tgetExtensions(): LoadExtensionsResult;\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] };\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] };\n\tgetThemes(): { themes: Theme[]; diagnostics: ResourceDiagnostic[] };\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content?: string }> };\n\tgetSystemPrompt(): string | undefined;\n\tgetAppendSystemPrompt(): string[];\n\textendResources(paths: ResourceExtensionPaths): void;\n\treload(): Promise<void>;\n}\n\nfunction resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\nconst CONTEXT_THREAT_PATTERNS: Array<{ label: string; pattern: RegExp }> = [\n\t{\n\t\tlabel: \"instruction override\",\n\t\tpattern:\n\t\t\t/\\b(?:ignore|disregard|override|bypass)\\b.{0,80}\\b(?:previous|prior|above|system|developer|agent)\\b.{0,80}\\binstructions?\\b/i,\n\t},\n\t{\n\t\tlabel: \"secret exfiltration\",\n\t\tpattern:\n\t\t\t/\\b(?:reveal|print|dump|exfiltrate|send|upload)\\b.{0,80}\\b(?:secrets?|tokens?|api[_ -]?keys?|credentials?|environment variables?|\\.env)\\b/i,\n\t},\n\t{\n\t\tlabel: \"hidden instruction\",\n\t\tpattern: /\\b(?:do not tell|don't tell|hide this from)\\b.{0,80}\\b(?:user|operator|developer)\\b/i,\n\t},\n];\n\nexport function scanContextFileThreats(content: string): string[] {\n\treturn CONTEXT_THREAT_PATTERNS.filter(({ pattern }) => pattern.test(content)).map(({ label }) => label);\n}\n\nfunction sanitizeContextFileContent(filePath: string, content: string): string {\n\tconst findings = scanContextFileThreats(content);\n\tif (findings.length === 0) return content;\n\tconsole.error(chalk.yellow(`Warning: Blocked context file ${filePath}: ${findings.join(\", \")}`));\n\treturn `[BLOCKED: ${filePath} contained potential prompt injection (${findings.join(\", \")}). Content not loaded.]`;\n}\n\nfunction loadContextFilesFromDir(dir: string): Array<{ path: string; content: string }> {\n\tconst candidates = [\"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\", \"GEMINI.md\", \"GEMINI.MD\"];\n\tconst files: Array<{ path: string; content: string }> = [];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\tconst content = readFileSync(filePath, \"utf-8\");\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: sanitizeContextFileContent(filePath, content),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn files;\n}\n\nexport function loadProjectContextFiles(options: {\n\tcwd: string;\n\tagentDir: string;\n\tprojectTrusted?: boolean;\n}): Array<{ path: string; content?: string }> {\n\tconst resolvedCwd = resolvePath(options.cwd);\n\tconst resolvedAgentDir = resolvePath(options.agentDir);\n\n\tconst contextFiles: Array<{ path: string; content?: string }> = [];\n\tconst seenPaths = new Set<string>();\n\n\tfor (const globalContext of loadContextFilesFromDir(resolvedAgentDir)) {\n\t\tcontextFiles.push(globalContext);\n\t\tseenPaths.add(globalContext.path);\n\t}\n\n\tif (options.projectTrusted !== false) {\n\t\tconst ancestorContextFiles: Array<{ path: string; content?: string }> = [];\n\n\t\tlet currentDir = resolvedCwd;\n\t\tconst root = resolve(\"/\");\n\n\t\twhile (true) {\n\t\t\tconst contextFilesInDir = loadContextFilesFromDir(currentDir).filter(\n\t\t\t\t(contextFile) => !seenPaths.has(contextFile.path),\n\t\t\t);\n\t\t\tif (contextFilesInDir.length > 0) {\n\t\t\t\tancestorContextFiles.unshift(...contextFilesInDir);\n\t\t\t\tfor (const contextFile of contextFilesInDir) {\n\t\t\t\t\tseenPaths.add(contextFile.path);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentDir === root) break;\n\n\t\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\t\tif (parentDir === currentDir) break;\n\t\t\tcurrentDir = parentDir;\n\t\t}\n\n\t\tcontextFiles.push(...ancestorContextFiles);\n\t}\n\n\treturn contextFiles;\n}\n\nexport interface DefaultResourceLoaderOptions {\n\tcwd: string;\n\tagentDir: string;\n\tsettingsManager?: SettingsManager;\n\teventBus?: EventBus;\n\tadditionalExtensionPaths?: string[];\n\tadditionalSkillPaths?: string[];\n\tadditionalPromptTemplatePaths?: string[];\n\tadditionalThemePaths?: string[];\n\textensionFactories?: ExtensionFactory[];\n\tnoExtensions?: boolean;\n\tnoSkills?: boolean;\n\tnoPromptTemplates?: boolean;\n\tnoThemes?: boolean;\n\tnoContextFiles?: boolean;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string[];\n\textensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;\n\tskillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tpromptsOverride?: (base: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tprompts: PromptTemplate[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tthemesOverride?: (base: { themes: Theme[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tagentsFilesOverride?: (base: { agentsFiles: Array<{ path: string; content?: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content?: string }>;\n\t};\n\tsystemPromptOverride?: (base: string | undefined) => string | undefined;\n\tappendSystemPromptOverride?: (base: string[]) => string[];\n}\n\nexport class DefaultResourceLoader implements ResourceLoader {\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate settingsManager: SettingsManager;\n\tprivate eventBus: EventBus;\n\tprivate packageManager: DefaultPackageManager;\n\tprivate additionalExtensionPaths: string[];\n\tprivate additionalSkillPaths: string[];\n\tprivate additionalPromptTemplatePaths: string[];\n\tprivate additionalThemePaths: string[];\n\tprivate extensionFactories: ExtensionFactory[];\n\tprivate noExtensions: boolean;\n\tprivate noSkills: boolean;\n\tprivate noPromptTemplates: boolean;\n\tprivate noThemes: boolean;\n\tprivate noContextFiles: boolean;\n\tprivate systemPromptSource?: string;\n\tprivate appendSystemPromptSource?: string[];\n\tprivate extensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;\n\tprivate skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate promptsOverride?: (base: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tprompts: PromptTemplate[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate themesOverride?: (base: { themes: Theme[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate agentsFilesOverride?: (base: { agentsFiles: Array<{ path: string; content?: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content?: string }>;\n\t};\n\tprivate systemPromptOverride?: (base: string | undefined) => string | undefined;\n\tprivate appendSystemPromptOverride?: (base: string[]) => string[];\n\n\tprivate extensionsResult: LoadExtensionsResult;\n\tprivate skills: Skill[];\n\tprivate skillDiagnostics: ResourceDiagnostic[];\n\tprivate prompts: PromptTemplate[];\n\tprivate promptDiagnostics: ResourceDiagnostic[];\n\tprivate themes: Theme[];\n\tprivate themeDiagnostics: ResourceDiagnostic[];\n\tprivate agentsFiles: Array<{ path: string; content?: string }>;\n\tprivate systemPrompt?: string;\n\tprivate appendSystemPrompt: string[];\n\tprivate lastSkillPaths: string[];\n\tprivate extensionSkillSourceInfos: Map<string, SourceInfo>;\n\tprivate extensionPromptSourceInfos: Map<string, SourceInfo>;\n\tprivate extensionThemeSourceInfos: Map<string, SourceInfo>;\n\tprivate lastPromptPaths: string[];\n\tprivate lastThemePaths: string[];\n\n\tconstructor(options: DefaultResourceLoaderOptions) {\n\t\tthis.cwd = resolvePath(options.cwd);\n\t\tthis.agentDir = resolvePath(options.agentDir);\n\t\tthis.settingsManager = options.settingsManager ?? SettingsManager.create(this.cwd, this.agentDir);\n\t\tthis.eventBus = options.eventBus ?? createEventBus();\n\t\tthis.packageManager = new DefaultPackageManager({\n\t\t\tcwd: this.cwd,\n\t\t\tagentDir: this.agentDir,\n\t\t\tsettingsManager: this.settingsManager,\n\t\t});\n\t\tthis.additionalExtensionPaths = options.additionalExtensionPaths ?? [];\n\t\tthis.additionalSkillPaths = options.additionalSkillPaths ?? [];\n\t\tthis.additionalPromptTemplatePaths = options.additionalPromptTemplatePaths ?? [];\n\t\tthis.additionalThemePaths = options.additionalThemePaths ?? [];\n\t\tthis.extensionFactories = options.extensionFactories ?? [];\n\t\tthis.noExtensions = options.noExtensions ?? false;\n\t\tthis.noSkills = options.noSkills ?? false;\n\t\tthis.noPromptTemplates = options.noPromptTemplates ?? false;\n\t\tthis.noThemes = options.noThemes ?? false;\n\t\tthis.noContextFiles = options.noContextFiles ?? false;\n\t\tthis.systemPromptSource = options.systemPrompt;\n\t\tthis.appendSystemPromptSource = options.appendSystemPrompt;\n\t\tthis.extensionsOverride = options.extensionsOverride;\n\t\tthis.skillsOverride = options.skillsOverride;\n\t\tthis.promptsOverride = options.promptsOverride;\n\t\tthis.themesOverride = options.themesOverride;\n\t\tthis.agentsFilesOverride = options.agentsFilesOverride;\n\t\tthis.systemPromptOverride = options.systemPromptOverride;\n\t\tthis.appendSystemPromptOverride = options.appendSystemPromptOverride;\n\n\t\tthis.extensionsResult = { extensions: [], errors: [], runtime: createExtensionRuntime() };\n\t\tthis.skills = [];\n\t\tthis.skillDiagnostics = [];\n\t\tthis.prompts = [];\n\t\tthis.promptDiagnostics = [];\n\t\tthis.themes = [];\n\t\tthis.themeDiagnostics = [];\n\t\tthis.agentsFiles = [];\n\t\tthis.appendSystemPrompt = [];\n\t\tthis.lastSkillPaths = [];\n\t\tthis.extensionSkillSourceInfos = new Map();\n\t\tthis.extensionPromptSourceInfos = new Map();\n\t\tthis.extensionThemeSourceInfos = new Map();\n\t\tthis.lastPromptPaths = [];\n\t\tthis.lastThemePaths = [];\n\t}\n\n\tgetExtensions(): LoadExtensionsResult {\n\t\treturn this.extensionsResult;\n\t}\n\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { skills: this.skills, diagnostics: this.skillDiagnostics };\n\t}\n\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { prompts: this.prompts, diagnostics: this.promptDiagnostics };\n\t}\n\n\tgetThemes(): { themes: Theme[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { themes: this.themes, diagnostics: this.themeDiagnostics };\n\t}\n\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content?: string }> } {\n\t\treturn { agentsFiles: this.agentsFiles };\n\t}\n\n\tgetSystemPrompt(): string | undefined {\n\t\treturn this.systemPrompt;\n\t}\n\n\tgetAppendSystemPrompt(): string[] {\n\t\treturn this.appendSystemPrompt;\n\t}\n\n\textendResources(paths: ResourceExtensionPaths): void {\n\t\tconst skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);\n\t\tconst promptPaths = this.normalizeExtensionPaths(paths.promptPaths ?? []);\n\t\tconst themePaths = this.normalizeExtensionPaths(paths.themePaths ?? []);\n\n\t\tfor (const entry of skillPaths) {\n\t\t\tthis.extensionSkillSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\t\tfor (const entry of promptPaths) {\n\t\t\tthis.extensionPromptSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\t\tfor (const entry of themePaths) {\n\t\t\tthis.extensionThemeSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\n\t\tif (skillPaths.length > 0) {\n\t\t\tthis.lastSkillPaths = this.mergePaths(\n\t\t\t\tthis.lastSkillPaths,\n\t\t\t\tskillPaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updateSkillsFromPaths(this.lastSkillPaths);\n\t\t}\n\n\t\tif (promptPaths.length > 0) {\n\t\t\tthis.lastPromptPaths = this.mergePaths(\n\t\t\t\tthis.lastPromptPaths,\n\t\t\t\tpromptPaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updatePromptsFromPaths(this.lastPromptPaths);\n\t\t}\n\n\t\tif (themePaths.length > 0) {\n\t\t\tthis.lastThemePaths = this.mergePaths(\n\t\t\t\tthis.lastThemePaths,\n\t\t\t\tthemePaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updateThemesFromPaths(this.lastThemePaths);\n\t\t}\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tawait this.settingsManager.reload();\n\t\tconst resolvedPaths = await this.packageManager.resolve();\n\t\tconst cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {\n\t\t\ttemporary: true,\n\t\t});\n\t\tconst metadataByPath = new Map<string, PathMetadata>();\n\n\t\tthis.extensionSkillSourceInfos = new Map();\n\t\tthis.extensionPromptSourceInfos = new Map();\n\t\tthis.extensionThemeSourceInfos = new Map();\n\n\t\t// Helper to extract enabled paths and store metadata\n\t\tconst getEnabledResources = (\n\t\t\tresources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,\n\t\t): Array<{ path: string; enabled: boolean; metadata: PathMetadata }> => {\n\t\t\tfor (const r of resources) {\n\t\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\t\tmetadataByPath.set(r.path, r.metadata);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resources.filter((r) => r.enabled);\n\t\t};\n\n\t\tconst getEnabledPaths = (\n\t\t\tresources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,\n\t\t): string[] => getEnabledResources(resources).map((r) => r.path);\n\t\tconst enabledExtensions = getEnabledPaths(resolvedPaths.extensions);\n\t\tconst enabledSkillResources = getEnabledResources(resolvedPaths.skills);\n\t\tconst enabledPrompts = getEnabledPaths(resolvedPaths.prompts);\n\t\tconst enabledThemes = getEnabledPaths(resolvedPaths.themes);\n\n\t\tconst mapSkillPath = (resource: { path: string; metadata: PathMetadata }): string => {\n\t\t\tif (resource.metadata.source !== \"auto\" && resource.metadata.origin !== \"package\") {\n\t\t\t\treturn resource.path;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(resource.path);\n\t\t\t\tif (!stats.isDirectory()) {\n\t\t\t\t\treturn resource.path;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn resource.path;\n\t\t\t}\n\t\t\tconst skillFile = join(resource.path, \"SKILL.md\");\n\t\t\tif (existsSync(skillFile)) {\n\t\t\t\tif (!metadataByPath.has(skillFile)) {\n\t\t\t\t\tmetadataByPath.set(skillFile, resource.metadata);\n\t\t\t\t}\n\t\t\t\treturn skillFile;\n\t\t\t}\n\t\t\treturn resource.path;\n\t\t};\n\n\t\tconst enabledSkills = enabledSkillResources.map(mapSkillPath);\n\n\t\t// Add CLI paths metadata\n\t\tfor (const r of cliExtensionPaths.extensions) {\n\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\tmetadataByPath.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n\t\t\t}\n\t\t}\n\t\tfor (const r of cliExtensionPaths.skills) {\n\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\tmetadataByPath.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n\t\t\t}\n\t\t}\n\n\t\tconst cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);\n\t\tconst cliEnabledSkills = getEnabledPaths(cliExtensionPaths.skills);\n\t\tconst cliEnabledPrompts = getEnabledPaths(cliExtensionPaths.prompts);\n\t\tconst cliEnabledThemes = getEnabledPaths(cliExtensionPaths.themes);\n\n\t\tconst extensionPaths = this.noExtensions\n\t\t\t? cliEnabledExtensions\n\t\t\t: this.mergePaths(cliEnabledExtensions, enabledExtensions);\n\n\t\tconst extensionsResult = await loadExtensions(extensionPaths, this.cwd, this.eventBus);\n\t\tconst inlineExtensions = await this.loadExtensionFactories(extensionsResult.runtime);\n\t\textensionsResult.extensions.push(...inlineExtensions.extensions);\n\t\textensionsResult.errors.push(...inlineExtensions.errors);\n\n\t\t// Detect extension conflicts (tools, commands, flags with same names from different extensions)\n\t\t// Keep all extensions loaded. Conflicts are reported as diagnostics, and precedence is handled by load order.\n\t\tconst conflicts = this.detectExtensionConflicts(extensionsResult.extensions);\n\t\tfor (const conflict of conflicts) {\n\t\t\textensionsResult.errors.push({ path: conflict.path, error: conflict.message });\n\t\t}\n\n\t\tfor (const p of this.additionalExtensionPaths) {\n\t\t\tif (isLocalPath(p)) {\n\t\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\t\tif (!existsSync(resolved)) {\n\t\t\t\t\textensionsResult.errors.push({ path: resolved, error: `Extension path does not exist: ${resolved}` });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;\n\t\tthis.applyExtensionSourceInfo(this.extensionsResult.extensions, metadataByPath);\n\n\t\tconst skillPaths = this.noSkills\n\t\t\t? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)\n\t\t\t: this.mergePaths([...cliEnabledSkills, ...enabledSkills], this.additionalSkillPaths);\n\n\t\tthis.lastSkillPaths = skillPaths;\n\t\tthis.updateSkillsFromPaths(skillPaths, metadataByPath);\n\t\tfor (const p of this.additionalSkillPaths) {\n\t\t\tif (isLocalPath(p)) {\n\t\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\t\tif (!existsSync(resolved) && !this.skillDiagnostics.some((d) => d.path === resolved)) {\n\t\t\t\t\tthis.skillDiagnostics.push({ type: \"error\", message: \"Skill path does not exist\", path: resolved });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst promptPaths = this.noPromptTemplates\n\t\t\t? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)\n\t\t\t: this.mergePaths([...cliEnabledPrompts, ...enabledPrompts], this.additionalPromptTemplatePaths);\n\n\t\tthis.lastPromptPaths = promptPaths;\n\t\tthis.updatePromptsFromPaths(promptPaths, metadataByPath);\n\t\tfor (const p of this.additionalPromptTemplatePaths) {\n\t\t\tif (isLocalPath(p)) {\n\t\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\t\tif (!existsSync(resolved) && !this.promptDiagnostics.some((d) => d.path === resolved)) {\n\t\t\t\t\tthis.promptDiagnostics.push({\n\t\t\t\t\t\ttype: \"error\",\n\t\t\t\t\t\tmessage: \"Prompt template path does not exist\",\n\t\t\t\t\t\tpath: resolved,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst themePaths = this.noThemes\n\t\t\t? this.mergePaths(cliEnabledThemes, this.additionalThemePaths)\n\t\t\t: this.mergePaths([...cliEnabledThemes, ...enabledThemes], this.additionalThemePaths);\n\n\t\tthis.lastThemePaths = themePaths;\n\t\tthis.updateThemesFromPaths(themePaths, metadataByPath);\n\t\tfor (const p of this.additionalThemePaths) {\n\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\tif (!existsSync(resolved) && !this.themeDiagnostics.some((d) => d.path === resolved)) {\n\t\t\t\tthis.themeDiagnostics.push({ type: \"error\", message: \"Theme path does not exist\", path: resolved });\n\t\t\t}\n\t\t}\n\n\t\tconst agentsFiles = {\n\t\t\tagentsFiles: this.noContextFiles\n\t\t\t\t? []\n\t\t\t\t: loadProjectContextFiles({\n\t\t\t\t\t\tcwd: this.cwd,\n\t\t\t\t\t\tagentDir: this.agentDir,\n\t\t\t\t\t\tprojectTrusted: this.settingsManager.isProjectTrusted(),\n\t\t\t\t\t}),\n\t\t};\n\t\tconst resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;\n\t\tthis.agentsFiles = resolvedAgentsFiles.agentsFiles;\n\n\t\tconst baseSystemPrompt = resolvePromptInput(\n\t\t\tthis.systemPromptSource ?? this.discoverSystemPromptFile(),\n\t\t\t\"system prompt\",\n\t\t);\n\t\tthis.systemPrompt = this.systemPromptOverride ? this.systemPromptOverride(baseSystemPrompt) : baseSystemPrompt;\n\n\t\tconst appendSources =\n\t\t\tthis.appendSystemPromptSource ??\n\t\t\t(this.discoverAppendSystemPromptFile() ? [this.discoverAppendSystemPromptFile()!] : []);\n\t\tconst baseAppend = appendSources\n\t\t\t.map((s) => resolvePromptInput(s, \"append system prompt\"))\n\t\t\t.filter((s): s is string => s !== undefined);\n\t\tthis.appendSystemPrompt = this.appendSystemPromptOverride\n\t\t\t? this.appendSystemPromptOverride(baseAppend)\n\t\t\t: baseAppend;\n\t}\n\n\tprivate normalizeExtensionPaths(\n\t\tentries: Array<{ path: string; metadata: PathMetadata }>,\n\t): Array<{ path: string; metadata: PathMetadata }> {\n\t\treturn entries.map((entry) => {\n\t\t\tconst metadata = entry.metadata.baseDir\n\t\t\t\t? { ...entry.metadata, baseDir: this.resolveResourcePath(entry.metadata.baseDir) }\n\t\t\t\t: entry.metadata;\n\t\t\treturn {\n\t\t\t\tpath: this.resolveResourcePath(entry.path),\n\t\t\t\tmetadata,\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate updateSkillsFromPaths(skillPaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet skillsResult: { skills: Skill[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noSkills && skillPaths.length === 0) {\n\t\t\tskillsResult = { skills: [], diagnostics: [] };\n\t\t} else {\n\t\t\tskillsResult = loadSkills({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.agentDir,\n\t\t\t\tskillPaths,\n\t\t\t\tincludeDefaults: false,\n\t\t\t});\n\t\t}\n\t\tconst resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;\n\t\tthis.skills = resolvedSkills.skills.map((skill) => ({\n\t\t\t...skill,\n\t\t\tsourceInfo:\n\t\t\t\tthis.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ??\n\t\t\t\tskill.sourceInfo ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(skill.filePath),\n\t\t}));\n\t\tthis.skillDiagnostics = resolvedSkills.diagnostics;\n\t}\n\n\tprivate updatePromptsFromPaths(promptPaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet promptsResult: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noPromptTemplates && promptPaths.length === 0) {\n\t\t\tpromptsResult = { prompts: [], diagnostics: [] };\n\t\t} else {\n\t\t\tconst allPrompts = loadPromptTemplates({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.agentDir,\n\t\t\t\tpromptPaths,\n\t\t\t\tincludeDefaults: false,\n\t\t\t});\n\t\t\tpromptsResult = this.dedupePrompts(allPrompts);\n\t\t}\n\t\tconst resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;\n\t\tthis.prompts = resolvedPrompts.prompts.map((prompt) => ({\n\t\t\t...prompt,\n\t\t\tsourceInfo:\n\t\t\t\tthis.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ??\n\t\t\t\tprompt.sourceInfo ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(prompt.filePath),\n\t\t}));\n\t\tthis.promptDiagnostics = resolvedPrompts.diagnostics;\n\t}\n\n\tprivate updateThemesFromPaths(themePaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet themesResult: { themes: Theme[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noThemes && themePaths.length === 0) {\n\t\t\tthemesResult = { themes: [], diagnostics: [] };\n\t\t} else {\n\t\t\tconst loaded = this.loadThemes(themePaths, false);\n\t\t\tconst deduped = this.dedupeThemes(loaded.themes);\n\t\t\tthemesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };\n\t\t}\n\t\tconst resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;\n\t\tthis.themes = resolvedThemes.themes.map((theme) => {\n\t\t\tconst sourcePath = theme.sourcePath;\n\t\t\ttheme.sourceInfo = sourcePath\n\t\t\t\t? (this.findSourceInfoForPath(sourcePath, this.extensionThemeSourceInfos, metadataByPath) ??\n\t\t\t\t\ttheme.sourceInfo ??\n\t\t\t\t\tthis.getDefaultSourceInfoForPath(sourcePath))\n\t\t\t\t: theme.sourceInfo;\n\t\t\treturn theme;\n\t\t});\n\t\tthis.themeDiagnostics = resolvedThemes.diagnostics;\n\t}\n\n\tprivate applyExtensionSourceInfo(extensions: Extension[], metadataByPath: Map<string, PathMetadata>): void {\n\t\tfor (const extension of extensions) {\n\t\t\textension.sourceInfo =\n\t\t\t\tthis.findSourceInfoForPath(extension.path, undefined, metadataByPath) ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(extension.path);\n\t\t\tfor (const command of extension.commands.values()) {\n\t\t\t\tcommand.sourceInfo = extension.sourceInfo;\n\t\t\t}\n\t\t\tfor (const tool of extension.tools.values()) {\n\t\t\t\ttool.sourceInfo = extension.sourceInfo;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate findSourceInfoForPath(\n\t\tresourcePath: string,\n\t\textraSourceInfos?: Map<string, SourceInfo>,\n\t\tmetadataByPath?: Map<string, PathMetadata>,\n\t): SourceInfo | undefined {\n\t\tif (!resourcePath) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (resourcePath.startsWith(\"<\")) {\n\t\t\treturn this.getDefaultSourceInfoForPath(resourcePath);\n\t\t}\n\n\t\tconst normalizedResourcePath = resolve(resourcePath);\n\t\tif (extraSourceInfos) {\n\t\t\tfor (const [sourcePath, sourceInfo] of extraSourceInfos.entries()) {\n\t\t\t\tconst normalizedSourcePath = resolve(sourcePath);\n\t\t\t\tif (\n\t\t\t\t\tnormalizedResourcePath === normalizedSourcePath ||\n\t\t\t\t\tnormalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)\n\t\t\t\t) {\n\t\t\t\t\treturn { ...sourceInfo, path: resourcePath };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (metadataByPath) {\n\t\t\tconst exact = metadataByPath.get(normalizedResourcePath) ?? metadataByPath.get(resourcePath);\n\t\t\tif (exact) {\n\t\t\t\treturn createSourceInfo(resourcePath, exact);\n\t\t\t}\n\n\t\t\tfor (const [sourcePath, metadata] of metadataByPath.entries()) {\n\t\t\t\tconst normalizedSourcePath = resolve(sourcePath);\n\t\t\t\tif (\n\t\t\t\t\tnormalizedResourcePath === normalizedSourcePath ||\n\t\t\t\t\tnormalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)\n\t\t\t\t) {\n\t\t\t\t\treturn createSourceInfo(resourcePath, metadata);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate getDefaultSourceInfoForPath(filePath: string): SourceInfo {\n\t\tif (filePath.startsWith(\"<\") && filePath.endsWith(\">\")) {\n\t\t\treturn {\n\t\t\t\tpath: filePath,\n\t\t\t\tsource: filePath.slice(1, -1).split(\":\")[0] || \"temporary\",\n\t\t\t\tscope: \"temporary\",\n\t\t\t\torigin: \"top-level\",\n\t\t\t};\n\t\t}\n\n\t\tconst normalizedPath = resolve(filePath);\n\t\tconst agentRoots = [\n\t\t\tjoin(this.agentDir, \"skills\"),\n\t\t\tjoin(this.agentDir, \"prompts\"),\n\t\t\tjoin(this.agentDir, \"themes\"),\n\t\t\tjoin(this.agentDir, \"extensions\"),\n\t\t];\n\t\tconst projectRoots = [\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"skills\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"prompts\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"themes\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"extensions\"),\n\t\t];\n\n\t\tfor (const root of agentRoots) {\n\t\t\tif (this.isUnderPath(normalizedPath, root)) {\n\t\t\t\treturn { path: filePath, source: \"local\", scope: \"user\", origin: \"top-level\", baseDir: root };\n\t\t\t}\n\t\t}\n\n\t\tfor (const root of projectRoots) {\n\t\t\tif (this.isUnderPath(normalizedPath, root)) {\n\t\t\t\treturn { path: filePath, source: \"local\", scope: \"project\", origin: \"top-level\", baseDir: root };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tpath: filePath,\n\t\t\tsource: \"local\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t\tbaseDir: statSync(normalizedPath).isDirectory() ? normalizedPath : resolve(normalizedPath, \"..\"),\n\t\t};\n\t}\n\n\tprivate mergePaths(primary: string[], additional: string[]): string[] {\n\t\tconst merged: string[] = [];\n\t\tconst seen = new Set<string>();\n\n\t\tfor (const p of [...primary, ...additional]) {\n\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\tconst canonicalPath = canonicalizePath(resolved);\n\t\t\tif (seen.has(canonicalPath)) continue;\n\t\t\tseen.add(canonicalPath);\n\t\t\tmerged.push(resolved);\n\t\t}\n\n\t\treturn merged;\n\t}\n\n\tprivate resolveResourcePath(p: string): string {\n\t\treturn resolvePath(p, this.cwd, { trim: true });\n\t}\n\n\tprivate loadThemes(\n\t\tpaths: string[],\n\t\tincludeDefaults: boolean = true,\n\t): {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t} {\n\t\tconst themes: Theme[] = [];\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\t\tif (includeDefaults) {\n\t\t\tconst defaultDirs = [join(this.agentDir, \"themes\"), join(this.cwd, CONFIG_DIR_NAME, \"themes\")];\n\n\t\t\tfor (const dir of defaultDirs) {\n\t\t\t\tthis.loadThemesFromDir(dir, themes, diagnostics);\n\t\t\t}\n\t\t}\n\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\tif (!existsSync(resolved)) {\n\t\t\t\tdiagnostics.push({ type: \"warning\", message: \"theme path does not exist\", path: resolved });\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(resolved);\n\t\t\t\tif (stats.isDirectory()) {\n\t\t\t\t\tthis.loadThemesFromDir(resolved, themes, diagnostics);\n\t\t\t\t} else if (stats.isFile() && resolved.endsWith(\".json\")) {\n\t\t\t\t\tthis.loadThemeFromFile(resolved, themes, diagnostics);\n\t\t\t\t} else {\n\t\t\t\t\tdiagnostics.push({ type: \"warning\", message: \"theme path is not a json file\", path: resolved });\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"failed to read theme path\";\n\t\t\t\tdiagnostics.push({ type: \"warning\", message, path: resolved });\n\t\t\t}\n\t\t}\n\n\t\treturn { themes, diagnostics };\n\t}\n\n\tprivate loadThemesFromDir(dir: string, themes: Theme[], diagnostics: ResourceDiagnostic[]): void {\n\t\tif (!existsSync(dir)) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\t\tfor (const entry of entries) {\n\t\t\t\tlet isFile = entry.isFile();\n\t\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tisFile = statSync(join(dir, entry.name)).isFile();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!isFile) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!entry.name.endsWith(\".json\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.loadThemeFromFile(join(dir, entry.name), themes, diagnostics);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read theme directory\";\n\t\t\tdiagnostics.push({ type: \"warning\", message, path: dir });\n\t\t}\n\t}\n\n\tprivate loadThemeFromFile(filePath: string, themes: Theme[], diagnostics: ResourceDiagnostic[]): void {\n\t\ttry {\n\t\t\tthemes.push(loadThemeFromPath(filePath));\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to load theme\";\n\t\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\t}\n\t}\n\n\tprivate async loadExtensionFactories(runtime: ExtensionRuntime): Promise<{\n\t\textensions: Extension[];\n\t\terrors: Array<{ path: string; error: string }>;\n\t}> {\n\t\tconst extensions: Extension[] = [];\n\t\tconst errors: Array<{ path: string; error: string }> = [];\n\n\t\tfor (const [index, factory] of this.extensionFactories.entries()) {\n\t\t\tconst extensionPath = `<inline:${index + 1}>`;\n\t\t\ttry {\n\t\t\t\tconst extension = await loadExtensionFromFactory(factory, this.cwd, this.eventBus, runtime, extensionPath);\n\t\t\t\textensions.push(extension);\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"failed to load extension\";\n\t\t\t\terrors.push({ path: extensionPath, error: message });\n\t\t\t}\n\t\t}\n\n\t\treturn { extensions, errors };\n\t}\n\n\tprivate dedupePrompts(prompts: PromptTemplate[]): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst seen = new Map<string, PromptTemplate>();\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\n\t\tfor (const prompt of prompts) {\n\t\t\tconst existing = seen.get(prompt.name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"/${prompt.name}\" collision`,\n\t\t\t\t\tpath: prompt.filePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"prompt\",\n\t\t\t\t\t\tname: prompt.name,\n\t\t\t\t\t\twinnerPath: existing.filePath,\n\t\t\t\t\t\tloserPath: prompt.filePath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tseen.set(prompt.name, prompt);\n\t\t\t}\n\t\t}\n\n\t\treturn { prompts: Array.from(seen.values()), diagnostics };\n\t}\n\n\tprivate dedupeThemes(themes: Theme[]): { themes: Theme[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst seen = new Map<string, Theme>();\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\n\t\tfor (const t of themes) {\n\t\t\tconst name = t.name ?? \"unnamed\";\n\t\t\tconst existing = seen.get(name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${name}\" collision`,\n\t\t\t\t\tpath: t.sourcePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"theme\",\n\t\t\t\t\t\tname,\n\t\t\t\t\t\twinnerPath: existing.sourcePath ?? \"<builtin>\",\n\t\t\t\t\t\tloserPath: t.sourcePath ?? \"<builtin>\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tseen.set(name, t);\n\t\t\t}\n\t\t}\n\n\t\treturn { themes: Array.from(seen.values()), diagnostics };\n\t}\n\n\tprivate discoverSystemPromptFile(): string | undefined {\n\t\tconst projectPath = join(this.cwd, CONFIG_DIR_NAME, \"SYSTEM.md\");\n\t\tif (this.settingsManager.isProjectTrusted() && existsSync(projectPath)) {\n\t\t\treturn projectPath;\n\t\t}\n\n\t\tconst globalPath = join(this.agentDir, \"SYSTEM.md\");\n\t\tif (existsSync(globalPath)) {\n\t\t\treturn globalPath;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate discoverAppendSystemPromptFile(): string | undefined {\n\t\tconst projectPath = join(this.cwd, CONFIG_DIR_NAME, \"APPEND_SYSTEM.md\");\n\t\tif (this.settingsManager.isProjectTrusted() && existsSync(projectPath)) {\n\t\t\treturn projectPath;\n\t\t}\n\n\t\tconst globalPath = join(this.agentDir, \"APPEND_SYSTEM.md\");\n\t\tif (existsSync(globalPath)) {\n\t\t\treturn globalPath;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate isUnderPath(target: string, root: string): boolean {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t}\n\n\tprivate detectExtensionConflicts(extensions: Extension[]): Array<{ path: string; message: string }> {\n\t\tconst conflicts: Array<{ path: string; message: string }> = [];\n\n\t\t// Track which extension registered each tool and flag\n\t\tconst toolOwners = new Map<string, string>();\n\t\tconst flagOwners = new Map<string, string>();\n\n\t\tfor (const ext of extensions) {\n\t\t\t// Check tools\n\t\t\tfor (const toolName of ext.tools.keys()) {\n\t\t\t\tconst existingOwner = toolOwners.get(toolName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Tool \"${toolName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\ttoolOwners.set(toolName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check flags\n\t\t\tfor (const flagName of ext.flags.keys()) {\n\t\t\t\tconst existingOwner = flagOwners.get(flagName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Flag \"--${flagName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tflagOwners.set(flagName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn conflicts;\n\t}\n}\n"]}
|
|
@@ -79,25 +79,27 @@ export function loadProjectContextFiles(options) {
|
|
|
79
79
|
contextFiles.push(globalContext);
|
|
80
80
|
seenPaths.add(globalContext.path);
|
|
81
81
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
82
|
+
if (options.projectTrusted !== false) {
|
|
83
|
+
const ancestorContextFiles = [];
|
|
84
|
+
let currentDir = resolvedCwd;
|
|
85
|
+
const root = resolve("/");
|
|
86
|
+
while (true) {
|
|
87
|
+
const contextFilesInDir = loadContextFilesFromDir(currentDir).filter((contextFile) => !seenPaths.has(contextFile.path));
|
|
88
|
+
if (contextFilesInDir.length > 0) {
|
|
89
|
+
ancestorContextFiles.unshift(...contextFilesInDir);
|
|
90
|
+
for (const contextFile of contextFilesInDir) {
|
|
91
|
+
seenPaths.add(contextFile.path);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (currentDir === root)
|
|
95
|
+
break;
|
|
96
|
+
const parentDir = resolve(currentDir, "..");
|
|
97
|
+
if (parentDir === currentDir)
|
|
98
|
+
break;
|
|
99
|
+
currentDir = parentDir;
|
|
100
|
+
}
|
|
101
|
+
contextFiles.push(...ancestorContextFiles);
|
|
102
|
+
}
|
|
101
103
|
return contextFiles;
|
|
102
104
|
}
|
|
103
105
|
export class DefaultResourceLoader {
|
|
@@ -360,7 +362,13 @@ export class DefaultResourceLoader {
|
|
|
360
362
|
}
|
|
361
363
|
}
|
|
362
364
|
const agentsFiles = {
|
|
363
|
-
agentsFiles: this.noContextFiles
|
|
365
|
+
agentsFiles: this.noContextFiles
|
|
366
|
+
? []
|
|
367
|
+
: loadProjectContextFiles({
|
|
368
|
+
cwd: this.cwd,
|
|
369
|
+
agentDir: this.agentDir,
|
|
370
|
+
projectTrusted: this.settingsManager.isProjectTrusted(),
|
|
371
|
+
}),
|
|
364
372
|
};
|
|
365
373
|
const resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;
|
|
366
374
|
this.agentsFiles = resolvedAgentsFiles.agentsFiles;
|
|
@@ -694,7 +702,7 @@ export class DefaultResourceLoader {
|
|
|
694
702
|
}
|
|
695
703
|
discoverSystemPromptFile() {
|
|
696
704
|
const projectPath = join(this.cwd, CONFIG_DIR_NAME, "SYSTEM.md");
|
|
697
|
-
if (existsSync(projectPath)) {
|
|
705
|
+
if (this.settingsManager.isProjectTrusted() && existsSync(projectPath)) {
|
|
698
706
|
return projectPath;
|
|
699
707
|
}
|
|
700
708
|
const globalPath = join(this.agentDir, "SYSTEM.md");
|
|
@@ -705,7 +713,7 @@ export class DefaultResourceLoader {
|
|
|
705
713
|
}
|
|
706
714
|
discoverAppendSystemPromptFile() {
|
|
707
715
|
const projectPath = join(this.cwd, CONFIG_DIR_NAME, "APPEND_SYSTEM.md");
|
|
708
|
-
if (existsSync(projectPath)) {
|
|
716
|
+
if (this.settingsManager.isProjectTrusted() && existsSync(projectPath)) {
|
|
709
717
|
return projectPath;
|
|
710
718
|
}
|
|
711
719
|
const globalPath = join(this.agentDir, "APPEND_SYSTEM.md");
|