@caupulican/pi-adaptative 0.80.99 → 0.80.102
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 +203 -0
- package/dist/core/agent-session.d.ts +72 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +437 -46
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/envelope-enforcement.d.ts +5 -0
- package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
- package/dist/core/autonomy/envelope-enforcement.js +28 -4
- package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
- package/dist/core/autonomy/path-scope.d.ts.map +1 -1
- package/dist/core/autonomy/path-scope.js +33 -2
- package/dist/core/autonomy/path-scope.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +15 -7
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/context/brain-curator.d.ts +10 -0
- package/dist/core/context/brain-curator.d.ts.map +1 -1
- package/dist/core/context/brain-curator.js +19 -2
- package/dist/core/context/brain-curator.js.map +1 -1
- package/dist/core/context-gc.d.ts +8 -3
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +5 -0
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/delegation/worker-actions.d.ts +0 -10
- package/dist/core/delegation/worker-actions.d.ts.map +1 -1
- package/dist/core/delegation/worker-actions.js +5 -7
- package/dist/core/delegation/worker-actions.js.map +1 -1
- package/dist/core/delegation/worker-result.d.ts +6 -0
- package/dist/core/delegation/worker-result.d.ts.map +1 -1
- package/dist/core/delegation/worker-result.js +10 -4
- package/dist/core/delegation/worker-result.js.map +1 -1
- package/dist/core/delegation/worker-runner.d.ts +3 -0
- package/dist/core/delegation/worker-runner.d.ts.map +1 -1
- package/dist/core/delegation/worker-runner.js +6 -1
- package/dist/core/delegation/worker-runner.js.map +1 -1
- package/dist/core/doctor.d.ts +66 -0
- package/dist/core/doctor.d.ts.map +1 -0
- package/dist/core/doctor.js +144 -0
- package/dist/core/doctor.js.map +1 -0
- package/dist/core/learning/learning-audit.d.ts +13 -1
- package/dist/core/learning/learning-audit.d.ts.map +1 -1
- package/dist/core/learning/learning-audit.js +22 -1
- package/dist/core/learning/learning-audit.js.map +1 -1
- package/dist/core/learning/learning-gate.d.ts +3 -0
- package/dist/core/learning/learning-gate.d.ts.map +1 -1
- package/dist/core/learning/learning-gate.js +13 -4
- package/dist/core/learning/learning-gate.js.map +1 -1
- package/dist/core/models/default-model-suggestions.d.ts +34 -0
- package/dist/core/models/default-model-suggestions.d.ts.map +1 -0
- package/dist/core/models/default-model-suggestions.js +58 -0
- package/dist/core/models/default-model-suggestions.js.map +1 -0
- package/dist/core/models/local-registration.d.ts +2 -0
- package/dist/core/models/local-registration.d.ts.map +1 -1
- package/dist/core/models/local-registration.js +2 -1
- package/dist/core/models/local-registration.js.map +1 -1
- package/dist/core/models/local-runtime.d.ts +76 -2
- package/dist/core/models/local-runtime.d.ts.map +1 -1
- package/dist/core/models/local-runtime.js +233 -21
- package/dist/core/models/local-runtime.js.map +1 -1
- package/dist/core/profile-resource-selection.d.ts +15 -3
- package/dist/core/profile-resource-selection.d.ts.map +1 -1
- package/dist/core/profile-resource-selection.js +19 -9
- package/dist/core/profile-resource-selection.js.map +1 -1
- package/dist/core/resource-loader.d.ts +20 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +42 -16
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +30 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +65 -3
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +14 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +8 -0
- 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 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/fff-search-backend.d.ts +34 -1
- package/dist/core/tools/fff-search-backend.d.ts.map +1 -1
- package/dist/core/tools/fff-search-backend.js +43 -4
- package/dist/core/tools/fff-search-backend.js.map +1 -1
- package/dist/core/tools/find.d.ts +16 -0
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +17 -3
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +20 -0
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +15 -3
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +17 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/fitness-role-selector.d.ts +6 -2
- package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/fitness-role-selector.js +55 -45
- package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -1
- package/dist/modes/interactive/components/model-suggestion-selector.d.ts +13 -0
- package/dist/modes/interactive/components/model-suggestion-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/model-suggestion-selector.js +40 -0
- package/dist/modes/interactive/components/model-suggestion-selector.js.map +1 -0
- package/dist/modes/interactive/components/profile-resource-editor.d.ts +3 -0
- package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.js +16 -2
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +98 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +8 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +57 -10
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/safe-write-stream.d.ts +8 -0
- package/dist/utils/safe-write-stream.d.ts.map +1 -1
- package/dist/utils/safe-write-stream.js +32 -0
- package/dist/utils/safe-write-stream.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +92 -2
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +172 -32
- package/dist/utils/tools-manager.js.map +1 -1
- 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 -36
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-runtime.js","sourceRoot":"","sources":["../../../src/core/models/local-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { delimiter, join } from \"node:path\";\n\n/**\n * Local model runtime manager (local-model-lifecycle-design.md): Ollama first, interface kept\n * runtime-agnostic. Pi SPAWNS the serve process itself with OWNED model storage\n * (`OLLAMA_MODELS=<agentDir>/models/ollama`) so every downloaded weight lives inside pi's tree —\n * per-model disk accounting is trivial and full cleanup is one directory. If a system server is\n * already running, pi uses it instead of double-installing, with the honest tradeoff surfaced:\n * storage then lives in the system daemon's dir and removal control is limited to `ollama rm`.\n *\n * Hard boundaries (design \"Hard boundaries\"): lifecycle actions are USER commands only — this\n * module is never exposed as a model-invokable tool; install is GUIDE MODE (exact manual steps,\n * never `curl | sh`); removal is explicit, disclosed, and never automatic.\n */\n\nexport interface LocalRuntimeStatus {\n\tbinaryPath?: string;\n\tbinarySource?: \"system\" | \"user\" | \"pi-owned\";\n\tserverUp: boolean;\n\tserverUrl: string;\n\t/** True when the responding server is a child process pi spawned (owned storage applies). */\n\tmanagedByPi: boolean;\n\t/** Owned weights directory (only meaningful for pi-managed serves). */\n\townedModelsDir: string;\n}\n\nexport interface InstalledLocalModel {\n\tname: string;\n\tsizeBytes: number;\n}\n\nexport interface LocalRuntimeDeps {\n\tfetchFn?: typeof fetch;\n\tspawnFn?: (\n\t\tcommand: string,\n\t\targs: string[],\n\t\toptions: { env: NodeJS.ProcessEnv },\n\t) => Pick<ChildProcess, \"pid\" | \"kill\" | \"unref\" | \"on\">;\n\texistsFn?: (path: string) => boolean;\n\tenvPath?: string;\n\thomeDir?: string;\n\tsleepFn?: (ms: number) => Promise<void>;\n}\n\nconst DEFAULT_BASE_URL = \"http://127.0.0.1:11434\";\nconst HEALTH_TIMEOUT_MS = 2_000;\nconst START_POLL_ATTEMPTS = 20;\nconst START_POLL_INTERVAL_MS = 500;\n\nexport class OllamaRuntime {\n\tprivate readonly _agentDir: string;\n\tprivate readonly _baseUrl: string;\n\tprivate readonly _fetch: typeof fetch;\n\tprivate readonly _spawn: NonNullable<LocalRuntimeDeps[\"spawnFn\"]>;\n\tprivate readonly _exists: (path: string) => boolean;\n\tprivate readonly _envPath: string;\n\tprivate readonly _homeDir: string;\n\tprivate readonly _sleep: (ms: number) => Promise<void>;\n\tprivate _child: Pick<ChildProcess, \"pid\" | \"kill\" | \"unref\" | \"on\"> | undefined;\n\n\tconstructor(args: { agentDir: string; baseUrl?: string; deps?: LocalRuntimeDeps }) {\n\t\tthis._agentDir = args.agentDir;\n\t\tthis._baseUrl = (args.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n\t\tthis._fetch = args.deps?.fetchFn ?? fetch;\n\t\tthis._spawn = args.deps?.spawnFn ?? ((command, argv, options) => spawn(command, argv, options));\n\t\tthis._exists = args.deps?.existsFn ?? existsSync;\n\t\tthis._envPath = args.deps?.envPath ?? process.env.PATH ?? \"\";\n\t\tthis._homeDir = args.deps?.homeDir ?? homedir();\n\t\tthis._sleep = args.deps?.sleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n\t}\n\n\tget baseUrl(): string {\n\t\treturn this._baseUrl;\n\t}\n\n\townedModelsDir(): string {\n\t\treturn join(this._agentDir, \"models\", \"ollama\");\n\t}\n\n\tprivate _findBinary(): { path: string; source: \"system\" | \"user\" | \"pi-owned\" } | undefined {\n\t\tconst piOwned = join(this._agentDir, \"runtimes\", \"ollama\", \"bin\", \"ollama\");\n\t\tif (this._exists(piOwned)) return { path: piOwned, source: \"pi-owned\" };\n\t\tconst userLevel = join(this._homeDir, \".local\", \"share\", \"ollama-dist\", \"bin\", \"ollama\");\n\t\tif (this._exists(userLevel)) return { path: userLevel, source: \"user\" };\n\t\tfor (const dir of this._envPath.split(delimiter)) {\n\t\t\tif (!dir) continue;\n\t\t\tconst candidate = join(dir, \"ollama\");\n\t\t\tif (this._exists(candidate)) return { path: candidate, source: \"system\" };\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate async _serverUp(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst response = await this._fetch(`${this._baseUrl}/api/tags`, {\n\t\t\t\tsignal: AbortSignal.timeout(HEALTH_TIMEOUT_MS),\n\t\t\t});\n\t\t\treturn response.ok;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync detect(): Promise<LocalRuntimeStatus> {\n\t\tconst binary = this._findBinary();\n\t\tconst serverUp = await this._serverUp();\n\t\treturn {\n\t\t\tbinaryPath: binary?.path,\n\t\t\tbinarySource: binary?.source,\n\t\t\tserverUp,\n\t\t\tserverUrl: this._baseUrl,\n\t\t\tmanagedByPi: this._child !== undefined && serverUp,\n\t\t\townedModelsDir: this.ownedModelsDir(),\n\t\t};\n\t}\n\n\t/** GUIDE MODE: exact manual steps, printed, never executed (no `curl | sh`, no sudo). */\n\tinstallGuide(): string[] {\n\t\treturn [\n\t\t\t\"Ollama is not installed. Pi never runs installers itself — manual steps (user-level, no sudo):\",\n\t\t\t\" 1. Download the pinned release archive for your platform:\",\n\t\t\t\" https://github.com/ollama/ollama/releases (asset: ollama-linux-amd64.tar.zst or your platform)\",\n\t\t\t` 2. Extract it to ${join(this._homeDir, \".local\", \"share\", \"ollama-dist\")}`,\n\t\t\t\" 3. Re-run your /models command - pi detects the binary automatically.\",\n\t\t\t\"Alternatively install system-wide from https://ollama.com/download and pi will use the system server.\",\n\t\t];\n\t}\n\n\t/**\n\t * Start a pi-managed serve with OWNED storage and the hardened env verified on this class of\n\t * hardware. No-op (reported) when a server already responds — pi never double-serves.\n\t */\n\tasync start(): Promise<{ started: boolean; reason: string }> {\n\t\tif (await this._serverUp()) {\n\t\t\treturn { started: false, reason: this._child ? \"already_running_managed\" : \"already_running_system\" };\n\t\t}\n\t\tconst binary = this._findBinary();\n\t\tif (!binary) return { started: false, reason: \"binary_missing\" };\n\t\tmkdirSync(this.ownedModelsDir(), { recursive: true });\n\t\tconst host = this._baseUrl.replace(/^https?:\\/\\//, \"\");\n\t\tthis._child = this._spawn(binary.path, [\"serve\"], {\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\tOLLAMA_HOST: host,\n\t\t\t\tOLLAMA_MODELS: this.ownedModelsDir(),\n\t\t\t\tOLLAMA_FLASH_ATTENTION: \"1\",\n\t\t\t\tOLLAMA_KV_CACHE_TYPE: \"q8_0\",\n\t\t\t\tOLLAMA_NUM_PARALLEL: \"1\",\n\t\t\t\tOLLAMA_MAX_LOADED_MODELS: \"3\",\n\t\t\t},\n\t\t});\n\t\tthis._child.unref?.();\n\t\tfor (let attempt = 0; attempt < START_POLL_ATTEMPTS; attempt++) {\n\t\t\tif (await this._serverUp()) return { started: true, reason: \"started\" };\n\t\t\tawait this._sleep(START_POLL_INTERVAL_MS);\n\t\t}\n\t\tthis.stop();\n\t\treturn { started: false, reason: \"health_check_timeout\" };\n\t}\n\n\t/** Resource hygiene only: stops the pi-managed serve process; never deletes anything. */\n\tstop(): { stopped: boolean } {\n\t\tif (!this._child) return { stopped: false };\n\t\ttry {\n\t\t\tthis._child.kill(\"SIGTERM\");\n\t\t} catch {\n\t\t\t// already gone\n\t\t}\n\t\tthis._child = undefined;\n\t\treturn { stopped: true };\n\t}\n\n\tasync list(): Promise<InstalledLocalModel[]> {\n\t\tconst response = await this._fetch(`${this._baseUrl}/api/tags`, { signal: AbortSignal.timeout(10_000) });\n\t\tif (!response.ok) throw new Error(`ollama list failed: HTTP ${response.status}`);\n\t\tconst data = (await response.json()) as { models?: Array<{ name?: string; size?: number }> };\n\t\treturn (data.models ?? [])\n\t\t\t.filter((model): model is { name: string; size?: number } => typeof model.name === \"string\")\n\t\t\t.map((model) => ({ name: model.name, sizeBytes: model.size ?? 0 }));\n\t}\n\n\t/** Pull a model through the server API (weights land in the SERVER's models dir). */\n\tasync pull(ref: string, onProgress?: (status: string) => void): Promise<{ ok: boolean; error?: string }> {\n\t\ttry {\n\t\t\tconst response = await this._fetch(`${this._baseUrl}/api/pull`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({ model: ref, stream: true }),\n\t\t\t});\n\t\t\tif (!response.ok || !response.body) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: `pull failed: HTTP ${response.status} ${await response.text().catch(() => \"\")}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst reader = response.body.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\n\t\t\tlet lastStatus = \"\";\n\t\t\tlet errorMessage: string | undefined;\n\t\t\tconst handleLine = (line: string): void => {\n\t\t\t\tif (!line.trim()) return;\n\t\t\t\ttry {\n\t\t\t\t\tconst event = JSON.parse(line) as { status?: string; error?: string };\n\t\t\t\t\tif (event.error) errorMessage = event.error;\n\t\t\t\t\tif (event.status && event.status !== lastStatus) {\n\t\t\t\t\t\tlastStatus = event.status;\n\t\t\t\t\t\tonProgress?.(event.status);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// partial line noise\n\t\t\t\t}\n\t\t\t};\n\t\t\tfor (;;) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() ?? \"\";\n\t\t\t\tfor (const line of lines) handleLine(line);\n\t\t\t}\n\t\t\t// The stream's FINAL line has no trailing newline — it stays in the buffer and holds\n\t\t\t// the terminal \"success\"/error event; dropping it misreports every completed pull.\n\t\t\thandleLine(buffer);\n\t\t\tif (errorMessage) return { ok: false, error: errorMessage };\n\t\t\treturn lastStatus === \"success\"\n\t\t\t\t? { ok: true }\n\t\t\t\t: { ok: false, error: `pull ended with: ${lastStatus || \"unknown\"}` };\n\t\t} catch (error) {\n\t\t\treturn { ok: false, error: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t}\n\n\t/** EXPLICIT user action only — callers must have shown what gets deleted and confirmed. */\n\tasync remove(ref: string): Promise<{ ok: boolean; error?: string }> {\n\t\ttry {\n\t\t\tconst response = await this._fetch(`${this._baseUrl}/api/delete`, {\n\t\t\t\tmethod: \"DELETE\",\n\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({ model: ref }),\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: `delete failed: HTTP ${response.status} ${await response.text().catch(() => \"\")}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { ok: true };\n\t\t} catch (error) {\n\t\t\treturn { ok: false, error: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"local-runtime.js","sourceRoot":"","sources":["../../../src/core/models/local-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { homedir, arch as osArch, platform as osPlatform } from \"node:os\";\nimport { delimiter, join } from \"node:path\";\nimport type { Readable, Writable } from \"node:stream\";\nimport * as nodeZlib from \"node:zlib\";\nimport { spawnProcess, spawnProcessSync, waitForChildProcess } from \"../../utils/child-process.ts\";\n\n/**\n * `spawnProcess(..., { stdio: [\"pipe\", \"pipe\", \"pipe\"] })` always yields a non-null `stdin` at\n * runtime, but child-process.ts's typed overload only narrows `.stdin` to non-null for the\n * capture-only (`StdioNull, StdioPipe, StdioPipe`) shape, so the generic overload's `Writable |\n * null` leaks through here. This makes the true invariant explicit and fails loudly (instead of\n * silently misbehaving) if it's ever violated by a future stdio change.\n */\nfunction requireStdin(proc: ChildProcess, label: string): Writable {\n\tif (!proc.stdin) throw new Error(`${label}: no stdin pipe`);\n\treturn proc.stdin;\n}\n\n/**\n * Local model runtime manager (local-model-lifecycle-design.md): Ollama first, interface kept\n * runtime-agnostic. Pi SPAWNS the serve process itself with OWNED model storage\n * (`OLLAMA_MODELS=<agentDir>/models/ollama`) so every downloaded weight lives inside pi's tree —\n * per-model disk accounting is trivial and full cleanup is one directory. If a system server is\n * already running, pi uses it instead of double-installing, with the honest tradeoff surfaced:\n * storage then lives in the system daemon's dir and removal control is limited to `ollama rm`.\n *\n * Hard boundaries (design \"Hard boundaries\"): lifecycle actions are USER commands only — this\n * module is never exposed as a model-invokable tool; install is GUIDE MODE (exact manual steps,\n * never `curl | sh`); removal is explicit, disclosed, and never automatic.\n */\n\nexport interface LocalRuntimeStatus {\n\tbinaryPath?: string;\n\tbinarySource?: \"system\" | \"user\" | \"pi-owned\";\n\tserverUp: boolean;\n\tserverUrl: string;\n\t/** True when the responding server is a child process pi spawned (owned storage applies). */\n\tmanagedByPi: boolean;\n\t/** Owned weights directory (only meaningful for pi-managed serves). */\n\townedModelsDir: string;\n}\n\nexport interface InstalledLocalModel {\n\tname: string;\n\tsizeBytes: number;\n}\n\n/** Pinned ollama release for the managed installer below. Bump here when needed — one constant. */\nexport const OLLAMA_PINNED_VERSION = \"0.31.1\";\n\nexport type OllamaAssetKind = \"tar-zst\" | \"tar-gz\" | \"zip\";\n\nexport interface OllamaReleaseAsset {\n\tname: string;\n\tkind: OllamaAssetKind;\n}\n\n/**\n * Maps a platform/arch pair (node's `os.platform()`/`os.arch()`) to the exact ollama release asset\n * name for {@link OLLAMA_PINNED_VERSION} — verified against the real ollama/ollama GitHub release\n * and its own install.sh, not guessed: darwin ships a CLI `.tgz` (the `.app`/`.dmg`/`Ollama-*.zip`\n * assets are the separate GUI-app installer, not what we want), linux ships `.tar.zst` per arch,\n * windows ships `.zip` per arch. Pure and exported so it's independently testable and reusable\n * (e.g. by a future doctor-driven managed install) without touching OllamaRuntime.\n */\nexport function resolveOllamaAsset(plat: string, architecture: string): OllamaReleaseAsset | undefined {\n\tif (plat === \"darwin\") {\n\t\t// Universal binary — one asset for both arm64 and x64.\n\t\treturn { name: \"ollama-darwin.tgz\", kind: \"tar-gz\" };\n\t}\n\tif (plat === \"linux\") {\n\t\tconst archName = architecture === \"arm64\" ? \"arm64\" : \"amd64\";\n\t\treturn { name: `ollama-linux-${archName}.tar.zst`, kind: \"tar-zst\" };\n\t}\n\tif (plat === \"win32\") {\n\t\tconst archName = architecture === \"arm64\" ? \"arm64\" : \"amd64\";\n\t\treturn { name: `ollama-windows-${archName}.zip`, kind: \"zip\" };\n\t}\n\treturn undefined;\n}\n\nexport interface LocalRuntimeDeps {\n\tfetchFn?: typeof fetch;\n\tspawnFn?: (\n\t\tcommand: string,\n\t\targs: string[],\n\t\toptions: { env: NodeJS.ProcessEnv },\n\t) => Pick<ChildProcess, \"pid\" | \"kill\" | \"unref\" | \"on\">;\n\texistsFn?: (path: string) => boolean;\n\tenvPath?: string;\n\thomeDir?: string;\n\tsleepFn?: (ms: number) => Promise<void>;\n\t/** os.platform()/os.arch() equivalents — injectable so asset resolution is testable per platform. */\n\tplatform?: () => string;\n\tarch?: () => string;\n\t/** Node's built-in zstd decompress transform, when THIS runtime's node:zlib has it — undefined\n\t * forces the system-zstd fallback. Injectable so tests can force either path deterministically\n\t * instead of depending on whatever Node happens to be running the test. */\n\tcreateZstdDecompress?: () => NodeJS.ReadWriteStream;\n\t/** Whether a named command exists on PATH (e.g. system `zstd`), for the extraction fallback. */\n\thasCommand?: (command: string) => boolean;\n\t/** Runs the extraction step for a downloaded archive. Injectable so installManaged's\n\t * download->extract->verify orchestration is testable without a real tar/zstd/unzip pipeline;\n\t * defaults to the real spawn-based extractor. */\n\textractArchive?: (\n\t\tinput: NodeJS.ReadableStream,\n\t\tdestDir: string,\n\t\tkind: OllamaAssetKind,\n\t) => Promise<{ ok: boolean; error?: string }>;\n}\n\nconst DEFAULT_BASE_URL = \"http://127.0.0.1:11434\";\nconst HEALTH_TIMEOUT_MS = 2_000;\nconst START_POLL_ATTEMPTS = 20;\nconst START_POLL_INTERVAL_MS = 500;\n\nexport class OllamaRuntime {\n\tprivate readonly _agentDir: string;\n\tprivate readonly _baseUrl: string;\n\tprivate readonly _fetch: typeof fetch;\n\tprivate readonly _spawn: NonNullable<LocalRuntimeDeps[\"spawnFn\"]>;\n\tprivate readonly _exists: (path: string) => boolean;\n\tprivate readonly _envPath: string;\n\tprivate readonly _homeDir: string;\n\tprivate readonly _sleep: (ms: number) => Promise<void>;\n\tprivate readonly _platform: () => string;\n\tprivate readonly _arch: () => string;\n\tprivate readonly _createZstdDecompress: (() => NodeJS.ReadWriteStream) | undefined;\n\tprivate readonly _hasCommand: (command: string) => boolean;\n\tprivate readonly _extractArchiveOverride: LocalRuntimeDeps[\"extractArchive\"] | undefined;\n\tprivate _child: Pick<ChildProcess, \"pid\" | \"kill\" | \"unref\" | \"on\"> | undefined;\n\n\tconstructor(args: { agentDir: string; baseUrl?: string; deps?: LocalRuntimeDeps }) {\n\t\tthis._agentDir = args.agentDir;\n\t\tthis._baseUrl = (args.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n\t\tthis._fetch = args.deps?.fetchFn ?? fetch;\n\t\tthis._spawn = args.deps?.spawnFn ?? ((command, argv, options) => spawn(command, argv, options));\n\t\tthis._exists = args.deps?.existsFn ?? existsSync;\n\t\tthis._envPath = args.deps?.envPath ?? process.env.PATH ?? \"\";\n\t\tthis._homeDir = args.deps?.homeDir ?? homedir();\n\t\tthis._sleep = args.deps?.sleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n\t\tthis._platform = args.deps?.platform ?? osPlatform;\n\t\tthis._arch = args.deps?.arch ?? osArch;\n\t\t// Feature-detect (not version-sniff): recent Node added zstd natively to node:zlib. Verified\n\t\t// present on this repo's minimum supported Node (>=22.19.0); still detected at runtime rather\n\t\t// than assumed, so an older/different Node correctly falls through to the system-zstd path.\n\t\t// `\"createZstdDecompress\" in deps` (rather than `??`) so a test can force the fallback path by\n\t\t// passing the key as explicitly undefined, distinct from omitting it (real auto-detection).\n\t\tthis._createZstdDecompress =\n\t\t\targs.deps && \"createZstdDecompress\" in args.deps\n\t\t\t\t? args.deps.createZstdDecompress\n\t\t\t\t: typeof nodeZlib.createZstdDecompress === \"function\"\n\t\t\t\t\t? () => nodeZlib.createZstdDecompress()\n\t\t\t\t\t: undefined;\n\t\tthis._hasCommand =\n\t\t\targs.deps?.hasCommand ??\n\t\t\t((command) => spawnProcessSync(command, [\"--version\"], { encoding: \"utf8\" }).error === undefined);\n\t\tthis._extractArchiveOverride = args.deps?.extractArchive;\n\t}\n\n\tget baseUrl(): string {\n\t\treturn this._baseUrl;\n\t}\n\n\townedModelsDir(): string {\n\t\treturn join(this._agentDir, \"models\", \"ollama\");\n\t}\n\n\tprivate _findBinary(): { path: string; source: \"system\" | \"user\" | \"pi-owned\" } | undefined {\n\t\tconst piOwned = join(this._agentDir, \"runtimes\", \"ollama\", \"bin\", \"ollama\");\n\t\tif (this._exists(piOwned)) return { path: piOwned, source: \"pi-owned\" };\n\t\tconst userLevel = join(this._homeDir, \".local\", \"share\", \"ollama-dist\", \"bin\", \"ollama\");\n\t\tif (this._exists(userLevel)) return { path: userLevel, source: \"user\" };\n\t\tfor (const dir of this._envPath.split(delimiter)) {\n\t\t\tif (!dir) continue;\n\t\t\tconst candidate = join(dir, \"ollama\");\n\t\t\tif (this._exists(candidate)) return { path: candidate, source: \"system\" };\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate async _serverUp(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst response = await this._fetch(`${this._baseUrl}/api/tags`, {\n\t\t\t\tsignal: AbortSignal.timeout(HEALTH_TIMEOUT_MS),\n\t\t\t});\n\t\t\treturn response.ok;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync detect(): Promise<LocalRuntimeStatus> {\n\t\tconst binary = this._findBinary();\n\t\tconst serverUp = await this._serverUp();\n\t\treturn {\n\t\t\tbinaryPath: binary?.path,\n\t\t\tbinarySource: binary?.source,\n\t\t\tserverUp,\n\t\t\tserverUrl: this._baseUrl,\n\t\t\tmanagedByPi: this._child !== undefined && serverUp,\n\t\t\townedModelsDir: this.ownedModelsDir(),\n\t\t};\n\t}\n\n\t/**\n\t * Manual-steps fallback text — shown when the managed install below wasn't offered (headless),\n\t * was declined, or itself failed. #31 reversed the stance for ollama specifically: pi CAN install\n\t * it for you now (consent-gated, a controlled download into pi's own runtimes dir, never\n\t * `curl | sh`) — these steps are the alternative for when that path isn't taken.\n\t */\n\tinstallGuide(): string[] {\n\t\treturn [\n\t\t\t\"Ollama is not installed. Pi can install it for you now (asks first, never curl|sh) — or follow these manual steps yourself:\",\n\t\t\t\" 1. Download the pinned release archive for your platform:\",\n\t\t\t\" https://github.com/ollama/ollama/releases (asset: ollama-linux-amd64.tar.zst or your platform)\",\n\t\t\t` 2. Extract it to ${join(this._homeDir, \".local\", \"share\", \"ollama-dist\")}`,\n\t\t\t\" 3. Re-run your /models command - pi detects the binary automatically.\",\n\t\t\t\"Alternatively install system-wide from https://ollama.com/download and pi will use the system server.\",\n\t\t];\n\t}\n\n\t/** Which decompressor to use for a `.tar.zst` asset — native (this Node's own zlib) is always\n\t * preferred when available, even if a system `zstd` ALSO exists, since it needs no external\n\t * dependency at all. Verified per-runtime by feature detection (see the constructor), not by\n\t * guessing from a Node version number. */\n\tprivate _chooseZstdStrategy(): { kind: \"native\" } | { kind: \"system\" } | { kind: \"unavailable\" } {\n\t\tif (this._createZstdDecompress) return { kind: \"native\" };\n\t\tif (this._hasCommand(\"zstd\")) return { kind: \"system\" };\n\t\treturn { kind: \"unavailable\" };\n\t}\n\n\t/**\n\t * Managed install (#31): a consent-gated, controlled download of the pinned ollama release into\n\t * pi's OWN runtimes dir (`<agentDir>/runtimes/ollama/`) — never `curl | sh`, never a second\n\t * server instance, and distinct from {@link start}'s owned MODEL storage (this is the binary\n\t * itself). Callers (the router's consent flow, and later a doctor-driven install) own the\n\t * consent/UI; this method only does the mechanical download+extract+verify and reports the\n\t * outcome honestly. `onProgress` is best-effort UI feedback, not a completion signal.\n\t */\n\tasync installManaged(onProgress?: (status: string) => void): Promise<{ ok: boolean; error?: string }> {\n\t\tconst asset = resolveOllamaAsset(this._platform(), this._arch());\n\t\tif (!asset) return { ok: false, error: \"unsupported-platform\" };\n\n\t\tonProgress?.(`Downloading ${asset.name}…`);\n\t\tconst downloadUrl = `https://github.com/ollama/ollama/releases/download/v${OLLAMA_PINNED_VERSION}/${asset.name}`;\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await this._fetch(downloadUrl);\n\t\t} catch (error) {\n\t\t\treturn { ok: false, error: `download-fail: ${error instanceof Error ? error.message : String(error)}` };\n\t\t}\n\t\tif (!response.ok || !response.body) {\n\t\t\treturn { ok: false, error: `download-fail: HTTP ${response.status}` };\n\t\t}\n\n\t\tconst destDir = join(this._agentDir, \"runtimes\", \"ollama\");\n\t\tmkdirSync(destDir, { recursive: true });\n\n\t\tonProgress?.(`Extracting ${asset.name}…`);\n\t\tconst extract = this._extractArchiveOverride ?? ((input, dest, kind) => this._extractArchive(input, dest, kind));\n\t\tconst extracted = await extract(response.body as unknown as NodeJS.ReadableStream, destDir, asset.kind);\n\t\tif (!extracted.ok) return extracted;\n\n\t\tconst binaryName = this._platform() === \"win32\" ? \"ollama.exe\" : \"ollama\";\n\t\tconst binaryPath = join(destDir, \"bin\", binaryName);\n\t\tif (!this._exists(binaryPath)) {\n\t\t\treturn { ok: false, error: \"extract-fail: binary not found after extraction\" };\n\t\t}\n\t\tonProgress?.(\"Ollama installed.\");\n\t\treturn { ok: true };\n\t}\n\n\t/** Real extraction: `tar-gz` lets `tar` itself gunzip; `tar-zst` decompresses first (native\n\t * node:zlib preferred, system `zstd` as fallback, an honest error if neither exists — see\n\t * {@link _chooseZstdStrategy}); `zip` needs a seekable file, so it's buffered to disk first. */\n\tprivate async _extractArchive(\n\t\tinput: NodeJS.ReadableStream,\n\t\tdestDir: string,\n\t\tkind: OllamaAssetKind,\n\t): Promise<{ ok: boolean; error?: string }> {\n\t\ttry {\n\t\t\tif (kind === \"zip\") {\n\t\t\t\treturn await this._extractZip(input, destDir);\n\t\t\t}\n\t\t\treturn await this._extractTar(input, destDir, kind);\n\t\t} catch (error) {\n\t\t\treturn { ok: false, error: `extract-fail: ${error instanceof Error ? error.message : String(error)}` };\n\t\t}\n\t}\n\n\tprivate async _extractTar(\n\t\tinput: NodeJS.ReadableStream,\n\t\tdestDir: string,\n\t\tkind: \"tar-gz\" | \"tar-zst\",\n\t): Promise<{ ok: boolean; error?: string }> {\n\t\tlet decompressed: Readable = input as unknown as Readable;\n\t\tconst tarArgs = [\"-xf\", \"-\", \"-C\", destDir];\n\t\tif (kind === \"tar-zst\") {\n\t\t\tconst strategy = this._chooseZstdStrategy();\n\t\t\tif (strategy.kind === \"unavailable\") {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: \"zstd-missing: this archive needs zstd to decompress and neither Node's built-in support nor a system `zstd` binary was found. Install zstd (e.g. `apt-get install zstd`, `dnf install zstd`, `pacman -S zstd`) and try again.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (strategy.kind === \"native\") {\n\t\t\t\tdecompressed = decompressed.pipe(\n\t\t\t\t\tthis._createZstdDecompress?.() as unknown as NodeJS.ReadWriteStream & Readable,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconst zstdProc = spawnProcess(\"zstd\", [\"-d\"], { stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n\t\t\t\tdecompressed.pipe(requireStdin(zstdProc, \"zstd\"));\n\t\t\t\tdecompressed = zstdProc.stdout as unknown as Readable;\n\t\t\t}\n\t\t} else {\n\t\t\t// tar itself handles gzip via -z — no separate decompression step needed.\n\t\t\ttarArgs[0] = \"-xzf\";\n\t\t}\n\t\tconst tarProc = spawnProcess(\"tar\", tarArgs, { stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n\t\tdecompressed.pipe(requireStdin(tarProc, \"tar\"));\n\t\tconst code = await waitForChildProcess(tarProc);\n\t\tif (code !== 0) {\n\t\t\treturn { ok: false, error: `extract-fail: tar exited with code ${code}` };\n\t\t}\n\t\treturn { ok: true };\n\t}\n\n\tprivate async _extractZip(input: NodeJS.ReadableStream, destDir: string): Promise<{ ok: boolean; error?: string }> {\n\t\t// Zip's central directory needs seekable file access — buffer to a temp file first.\n\t\tconst { createWriteStream } = await import(\"node:fs\");\n\t\tconst { pipeline } = await import(\"node:stream/promises\");\n\t\tconst zipPath = join(destDir, \"..\", `ollama-download-${process.pid}-${Date.now()}.zip`);\n\t\tawait pipeline(input as unknown as Readable, createWriteStream(zipPath));\n\t\ttry {\n\t\t\tconst extractCommand = this._platform() === \"win32\" && this._hasCommand(\"tar\") ? \"tar\" : \"unzip\";\n\t\t\tconst args = extractCommand === \"tar\" ? [\"-xf\", zipPath, \"-C\", destDir] : [\"-q\", zipPath, \"-d\", destDir];\n\t\t\tconst proc = spawnProcess(extractCommand, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\tconst code = await waitForChildProcess(proc);\n\t\t\tif (code !== 0) {\n\t\t\t\treturn { ok: false, error: `extract-fail: ${extractCommand} exited with code ${code}` };\n\t\t\t}\n\t\t\treturn { ok: true };\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tconst { rmSync } = await import(\"node:fs\");\n\t\t\t\trmSync(zipPath, { force: true });\n\t\t\t} catch {\n\t\t\t\t// best-effort cleanup\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Shared spawn-then-health-poll for both start modes below; `extraEnv` is the only thing that\n\t * differs between them (owned storage vs reusing the user's own). */\n\tprivate async _spawnAndPoll(\n\t\tbinary: { path: string },\n\t\textraEnv: NodeJS.ProcessEnv,\n\t): Promise<{ started: boolean; reason: string }> {\n\t\tconst host = this._baseUrl.replace(/^https?:\\/\\//, \"\");\n\t\tthis._child = this._spawn(binary.path, [\"serve\"], {\n\t\t\tenv: { ...process.env, OLLAMA_HOST: host, ...extraEnv },\n\t\t});\n\t\tthis._child.unref?.();\n\t\tfor (let attempt = 0; attempt < START_POLL_ATTEMPTS; attempt++) {\n\t\t\tif (await this._serverUp()) return { started: true, reason: \"started\" };\n\t\t\tawait this._sleep(START_POLL_INTERVAL_MS);\n\t\t}\n\t\tthis.stop();\n\t\treturn { started: false, reason: \"health_check_timeout\" };\n\t}\n\n\t/**\n\t * Start a pi-managed serve with OWNED storage and the hardened env verified on this class of\n\t * hardware. No-op (reported) when a server already responds — pi never double-serves. Used by\n\t * `/models add` et al, where isolated per-model-pull storage is the point.\n\t */\n\tasync start(): Promise<{ started: boolean; reason: string }> {\n\t\tif (await this._serverUp()) {\n\t\t\treturn { started: false, reason: this._child ? \"already_running_managed\" : \"already_running_system\" };\n\t\t}\n\t\tconst binary = this._findBinary();\n\t\tif (!binary) return { started: false, reason: \"binary_missing\" };\n\t\tmkdirSync(this.ownedModelsDir(), { recursive: true });\n\t\treturn this._spawnAndPoll(binary, {\n\t\t\tOLLAMA_MODELS: this.ownedModelsDir(),\n\t\t\tOLLAMA_FLASH_ATTENTION: \"1\",\n\t\t\tOLLAMA_KV_CACHE_TYPE: \"q8_0\",\n\t\t\tOLLAMA_NUM_PARALLEL: \"1\",\n\t\t\tOLLAMA_MAX_LOADED_MODELS: \"3\",\n\t\t});\n\t}\n\n\t/**\n\t * Start a serve that REUSES the user's own existing models directory (no `OLLAMA_MODELS`\n\t * override — falls through to Ollama's own default, `~/.ollama`), for callers that must see the\n\t * user's already-pulled models rather than pi's isolated/owned storage. Same idempotency and\n\t * hardened perf env as {@link start}; the only difference is which storage the server sees.\n\t */\n\tasync startReuseExisting(): Promise<{ started: boolean; reason: string }> {\n\t\tif (await this._serverUp()) {\n\t\t\treturn { started: false, reason: this._child ? \"already_running_managed\" : \"already_running_system\" };\n\t\t}\n\t\tconst binary = this._findBinary();\n\t\tif (!binary) return { started: false, reason: \"binary_missing\" };\n\t\treturn this._spawnAndPoll(binary, {\n\t\t\tOLLAMA_FLASH_ATTENTION: \"1\",\n\t\t\tOLLAMA_KV_CACHE_TYPE: \"q8_0\",\n\t\t\tOLLAMA_NUM_PARALLEL: \"1\",\n\t\t\tOLLAMA_MAX_LOADED_MODELS: \"3\",\n\t\t});\n\t}\n\n\t/** Resource hygiene only: stops the pi-managed serve process; never deletes anything. */\n\tstop(): { stopped: boolean } {\n\t\tif (!this._child) return { stopped: false };\n\t\ttry {\n\t\t\tthis._child.kill(\"SIGTERM\");\n\t\t} catch {\n\t\t\t// already gone\n\t\t}\n\t\tthis._child = undefined;\n\t\treturn { stopped: true };\n\t}\n\n\tasync list(): Promise<InstalledLocalModel[]> {\n\t\tconst response = await this._fetch(`${this._baseUrl}/api/tags`, { signal: AbortSignal.timeout(10_000) });\n\t\tif (!response.ok) throw new Error(`ollama list failed: HTTP ${response.status}`);\n\t\tconst data = (await response.json()) as { models?: Array<{ name?: string; size?: number }> };\n\t\treturn (data.models ?? [])\n\t\t\t.filter((model): model is { name: string; size?: number } => typeof model.name === \"string\")\n\t\t\t.map((model) => ({ name: model.name, sizeBytes: model.size ?? 0 }));\n\t}\n\n\t/** Pull a model through the server API (weights land in the SERVER's models dir). */\n\tasync pull(ref: string, onProgress?: (status: string) => void): Promise<{ ok: boolean; error?: string }> {\n\t\ttry {\n\t\t\tconst response = await this._fetch(`${this._baseUrl}/api/pull`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({ model: ref, stream: true }),\n\t\t\t});\n\t\t\tif (!response.ok || !response.body) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: `pull failed: HTTP ${response.status} ${await response.text().catch(() => \"\")}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst reader = response.body.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\n\t\t\tlet lastStatus = \"\";\n\t\t\tlet errorMessage: string | undefined;\n\t\t\tconst handleLine = (line: string): void => {\n\t\t\t\tif (!line.trim()) return;\n\t\t\t\ttry {\n\t\t\t\t\tconst event = JSON.parse(line) as { status?: string; error?: string };\n\t\t\t\t\tif (event.error) errorMessage = event.error;\n\t\t\t\t\tif (event.status && event.status !== lastStatus) {\n\t\t\t\t\t\tlastStatus = event.status;\n\t\t\t\t\t\tonProgress?.(event.status);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// partial line noise\n\t\t\t\t}\n\t\t\t};\n\t\t\tfor (;;) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() ?? \"\";\n\t\t\t\tfor (const line of lines) handleLine(line);\n\t\t\t}\n\t\t\t// The stream's FINAL line has no trailing newline — it stays in the buffer and holds\n\t\t\t// the terminal \"success\"/error event; dropping it misreports every completed pull.\n\t\t\thandleLine(buffer);\n\t\t\tif (errorMessage) return { ok: false, error: errorMessage };\n\t\t\treturn lastStatus === \"success\"\n\t\t\t\t? { ok: true }\n\t\t\t\t: { ok: false, error: `pull ended with: ${lastStatus || \"unknown\"}` };\n\t\t} catch (error) {\n\t\t\treturn { ok: false, error: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t}\n\n\t/** EXPLICIT user action only — callers must have shown what gets deleted and confirmed. */\n\tasync remove(ref: string): Promise<{ ok: boolean; error?: string }> {\n\t\ttry {\n\t\t\tconst response = await this._fetch(`${this._baseUrl}/api/delete`, {\n\t\t\t\tmethod: \"DELETE\",\n\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({ model: ref }),\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: `delete failed: HTTP ${response.status} ${await response.text().catch(() => \"\")}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { ok: true };\n\t\t} catch (error) {\n\t\t\treturn { ok: false, error: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t}\n}\n"]}
|
|
@@ -9,13 +9,25 @@ import type { ResourceProfileFilterSettings } from "./settings-manager.ts";
|
|
|
9
9
|
* (If both allow and block specific ids are present: start from allow-or-all, then remove blocked.)
|
|
10
10
|
*/
|
|
11
11
|
export declare function decodeResourceSelection(filter: ResourceProfileFilterSettings | undefined, allIds: string[]): Set<string>;
|
|
12
|
+
/**
|
|
13
|
+
* Options that let the encoder distinguish a genuine grant-all from an all-enabled snapshot of an
|
|
14
|
+
* enumerated grant (e.g. a collapsed universe where every enumerated id happens to be visible).
|
|
15
|
+
* - originalFilter: the filter the selection was decoded from. A wildcard is preserved as a
|
|
16
|
+
* wildcard; an enumerated grant is NEVER widened into one.
|
|
17
|
+
* - grantAll: the caller explicitly chose "grant all (including future)" — force the wildcard.
|
|
18
|
+
*/
|
|
19
|
+
export interface EncodeResourceSelectionOptions {
|
|
20
|
+
originalFilter?: ResourceProfileFilterSettings;
|
|
21
|
+
grantAll?: boolean;
|
|
22
|
+
}
|
|
12
23
|
/**
|
|
13
24
|
* Encode an enabled set back into a filter.
|
|
14
|
-
* - all enabled ->
|
|
25
|
+
* - all enabled -> enumerated { allow: [...allIds] } (or { allow: ["*"] } only when the
|
|
26
|
+
* original was already a wildcard / the caller chose grant-all)
|
|
15
27
|
* - some but not all -> { allow: [...enabled, in allIds order] }
|
|
16
28
|
* - none enabled -> { block: ["*"] }
|
|
17
29
|
*/
|
|
18
|
-
export declare function encodeResourceSelection(enabled: Set<string>, allIds: string[]): ResourceProfileFilterSettings | undefined;
|
|
30
|
+
export declare function encodeResourceSelection(enabled: Set<string>, allIds: string[], options?: EncodeResourceSelectionOptions): ResourceProfileFilterSettings | undefined;
|
|
19
31
|
export type ResourceFraming = "allow" | "block";
|
|
20
32
|
/**
|
|
21
33
|
* Detect the framing of a given resource profile filter settings.
|
|
@@ -24,5 +36,5 @@ export declare function detectResourceFraming(filter: ResourceProfileFilterSetti
|
|
|
24
36
|
/**
|
|
25
37
|
* Encode an enabled set back into a filter, respecting the specified framing.
|
|
26
38
|
*/
|
|
27
|
-
export declare function encodeResourceSelectionWithFraming(enabled: Set<string>, allIds: string[], framing: ResourceFraming): ResourceProfileFilterSettings | undefined;
|
|
39
|
+
export declare function encodeResourceSelectionWithFraming(enabled: Set<string>, allIds: string[], framing: ResourceFraming, options?: EncodeResourceSelectionOptions): ResourceProfileFilterSettings | undefined;
|
|
28
40
|
//# sourceMappingURL=profile-resource-selection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-resource-selection.d.ts","sourceRoot":"","sources":["../../src/core/profile-resource-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAE3E;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,MAAM,EAAE,MAAM,EAAE,GACd,GAAG,CAAC,MAAM,CAAC,CAmDb;AAED
|
|
1
|
+
{"version":3,"file":"profile-resource-selection.d.ts","sourceRoot":"","sources":["../../src/core/profile-resource-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAE3E;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,MAAM,EAAE,MAAM,EAAE,GACd,GAAG,CAAC,MAAM,CAAC,CAmDb;AAED;;;;;;GAMG;AACH,MAAM,WAAW,8BAA8B;IAC9C,cAAc,CAAC,EAAE,6BAA6B,CAAC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAOD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACtC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EACpB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE,8BAA8B,GACtC,6BAA6B,GAAG,SAAS,CAoC3C;AAED,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,6BAA6B,GAAG,SAAS,GAAG,eAAe,CAcxG;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CACjD,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EACpB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,8BAA8B,GACtC,6BAA6B,GAAG,SAAS,CAmC3C","sourcesContent":["import type { ResourceProfileFilterSettings } from \"./settings-manager.ts\";\n\n/**\n * Decode a stored allow/block filter into the set of enabled resource ids,\n * given the full universe of ids for that kind.\n * - undefined / empty filter -> all enabled\n * - block contains \"*\" -> none enabled\n * - allow non-empty -> exactly the allow entries that exist in allIds\n * - block of specific ids (no \"*\") -> all ids except blocked ones\n * (If both allow and block specific ids are present: start from allow-or-all, then remove blocked.)\n */\nexport function decodeResourceSelection(\n\tfilter: ResourceProfileFilterSettings | undefined,\n\tallIds: string[],\n): Set<string> {\n\t// Strict UAC: an unmentioned kind is DENIED — decoding it as \"all enabled\" would both\n\t// lie in the editor UI and, on save, convert silent denial into an explicit grant-all.\n\tif (!filter) {\n\t\treturn new Set();\n\t}\n\n\t// If block contains \"*\", nothing is enabled\n\tif (filter.block?.includes(\"*\")) {\n\t\treturn new Set();\n\t}\n\n\t// Explicit grant-all: every id enabled except explicitly blocked ones.\n\tif (filter.allow?.includes(\"*\")) {\n\t\tconst blocked = new Set(filter.block ?? []);\n\t\treturn new Set(allIds.filter((id) => !blocked.has(id)));\n\t}\n\n\t// If allow is specified, start with the allow list filtered to valid IDs\n\tif (filter.allow && filter.allow.length > 0) {\n\t\tconst allIdsSet = new Set(allIds);\n\t\tconst enabled = new Set<string>();\n\t\tfor (const id of filter.allow) {\n\t\t\tif (allIdsSet.has(id)) {\n\t\t\t\tenabled.add(id);\n\t\t\t}\n\t\t}\n\t\t// If block is also specified, remove blocked ids\n\t\tif (filter.block && filter.block.length > 0) {\n\t\t\tconst blockSet = new Set(filter.block);\n\t\t\tfor (const id of Array.from(enabled)) {\n\t\t\t\tif (blockSet.has(id)) {\n\t\t\t\t\tenabled.delete(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn enabled;\n\t}\n\n\t// No allow specified, start with all ids\n\tconst enabled = new Set(allIds);\n\t// Remove any blocked ids\n\tif (filter.block && filter.block.length > 0) {\n\t\tconst blockSet = new Set(filter.block);\n\t\tfor (const id of allIds) {\n\t\t\tif (blockSet.has(id)) {\n\t\t\t\tenabled.delete(id);\n\t\t\t}\n\t\t}\n\t}\n\treturn enabled;\n}\n\n/**\n * Options that let the encoder distinguish a genuine grant-all from an all-enabled snapshot of an\n * enumerated grant (e.g. a collapsed universe where every enumerated id happens to be visible).\n * - originalFilter: the filter the selection was decoded from. A wildcard is preserved as a\n * wildcard; an enumerated grant is NEVER widened into one.\n * - grantAll: the caller explicitly chose \"grant all (including future)\" — force the wildcard.\n */\nexport interface EncodeResourceSelectionOptions {\n\toriginalFilter?: ResourceProfileFilterSettings;\n\tgrantAll?: boolean;\n}\n\nfunction shouldEncodeGrantAllWildcard(options?: EncodeResourceSelectionOptions): boolean {\n\tif (options?.grantAll) return true;\n\treturn options?.originalFilter?.allow?.includes(\"*\") ?? false;\n}\n\n/**\n * Encode an enabled set back into a filter.\n * - all enabled -> enumerated { allow: [...allIds] } (or { allow: [\"*\"] } only when the\n * original was already a wildcard / the caller chose grant-all)\n * - some but not all -> { allow: [...enabled, in allIds order] }\n * - none enabled -> { block: [\"*\"] }\n */\nexport function encodeResourceSelection(\n\tenabled: Set<string>,\n\tallIds: string[],\n\toptions?: EncodeResourceSelectionOptions,\n): ResourceProfileFilterSettings | undefined {\n\tconst allIdsSet = new Set(allIds);\n\n\t// Count how many enabled ids are actually in allIds\n\tlet validEnabledCount = 0;\n\tfor (const id of enabled) {\n\t\tif (allIdsSet.has(id)) {\n\t\t\tvalidEnabledCount++;\n\t\t}\n\t}\n\n\t// All enabled: grant-all must be said OUT LOUD under strict UAC — omitting the kind (returning\n\t// undefined) would mean deny-all. But saying it out loud does NOT mean widening: an enumerated\n\t// closed grant re-encodes as the explicit id list, so a no-change save over a collapsed universe\n\t// cannot silently turn \"grant exactly these\" into \"grant everything, including future resources\".\n\t// A wildcard is only produced when it was already a wildcard (or grant-all was chosen explicitly).\n\tif (allIds.length > 0 && validEnabledCount === allIds.length) {\n\t\treturn shouldEncodeGrantAllWildcard(options) ? { allow: [\"*\"] } : { allow: [...allIds] };\n\t}\n\tif (allIds.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// None enabled: return { block: [\"*\"] }\n\tif (validEnabledCount === 0) {\n\t\treturn { block: [\"*\"] };\n\t}\n\n\t// Some but not all: return { allow: [...enabled, in allIds order] }\n\tconst allow: string[] = [];\n\tfor (const id of allIds) {\n\t\tif (enabled.has(id)) {\n\t\t\tallow.push(id);\n\t\t}\n\t}\n\treturn { allow };\n}\n\nexport type ResourceFraming = \"allow\" | \"block\";\n\n/**\n * Detect the framing of a given resource profile filter settings.\n */\nexport function detectResourceFraming(filter: ResourceProfileFilterSettings | undefined): ResourceFraming {\n\tif (!filter) {\n\t\treturn \"block\";\n\t}\n\tif (filter.allow && filter.allow.length > 0) {\n\t\treturn \"allow\";\n\t}\n\tif (filter.block && filter.block.length > 0) {\n\t\tif (filter.block.includes(\"*\")) {\n\t\t\treturn \"allow\";\n\t\t}\n\t\treturn \"block\";\n\t}\n\treturn \"block\";\n}\n\n/**\n * Encode an enabled set back into a filter, respecting the specified framing.\n */\nexport function encodeResourceSelectionWithFraming(\n\tenabled: Set<string>,\n\tallIds: string[],\n\tframing: ResourceFraming,\n\toptions?: EncodeResourceSelectionOptions,\n): ResourceProfileFilterSettings | undefined {\n\tif (framing === \"allow\") {\n\t\treturn encodeResourceSelection(enabled, allIds, options);\n\t}\n\n\tconst allIdsSet = new Set(allIds);\n\tlet validEnabledCount = 0;\n\tfor (const id of enabled) {\n\t\tif (allIdsSet.has(id)) {\n\t\t\tvalidEnabledCount++;\n\t\t}\n\t}\n\n\t// All enabled: explicit grant-all (see encodeResourceSelection — undefined means DENIED), but\n\t// never widened to a wildcard without context — same gate as the allow-framing branch.\n\tif (allIds.length > 0 && validEnabledCount === allIds.length) {\n\t\treturn shouldEncodeGrantAllWildcard(options) ? { allow: [\"*\"] } : { allow: [...allIds] };\n\t}\n\tif (allIds.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// None enabled: return { block: [\"*\"] }\n\tif (validEnabledCount === 0) {\n\t\treturn { block: [\"*\"] };\n\t}\n\n\t// Block framing with subset disabled: list disabled ids in block\n\tconst block: string[] = [];\n\tfor (const id of allIds) {\n\t\tif (!enabled.has(id)) {\n\t\t\tblock.push(id);\n\t\t}\n\t}\n\treturn { block };\n}\n"]}
|
|
@@ -55,13 +55,19 @@ export function decodeResourceSelection(filter, allIds) {
|
|
|
55
55
|
}
|
|
56
56
|
return enabled;
|
|
57
57
|
}
|
|
58
|
+
function shouldEncodeGrantAllWildcard(options) {
|
|
59
|
+
if (options?.grantAll)
|
|
60
|
+
return true;
|
|
61
|
+
return options?.originalFilter?.allow?.includes("*") ?? false;
|
|
62
|
+
}
|
|
58
63
|
/**
|
|
59
64
|
* Encode an enabled set back into a filter.
|
|
60
|
-
* - all enabled ->
|
|
65
|
+
* - all enabled -> enumerated { allow: [...allIds] } (or { allow: ["*"] } only when the
|
|
66
|
+
* original was already a wildcard / the caller chose grant-all)
|
|
61
67
|
* - some but not all -> { allow: [...enabled, in allIds order] }
|
|
62
68
|
* - none enabled -> { block: ["*"] }
|
|
63
69
|
*/
|
|
64
|
-
export function encodeResourceSelection(enabled, allIds) {
|
|
70
|
+
export function encodeResourceSelection(enabled, allIds, options) {
|
|
65
71
|
const allIdsSet = new Set(allIds);
|
|
66
72
|
// Count how many enabled ids are actually in allIds
|
|
67
73
|
let validEnabledCount = 0;
|
|
@@ -70,10 +76,13 @@ export function encodeResourceSelection(enabled, allIds) {
|
|
|
70
76
|
validEnabledCount++;
|
|
71
77
|
}
|
|
72
78
|
}
|
|
73
|
-
// All enabled: grant-all must be said OUT LOUD under strict UAC — omitting the kind
|
|
74
|
-
//
|
|
79
|
+
// All enabled: grant-all must be said OUT LOUD under strict UAC — omitting the kind (returning
|
|
80
|
+
// undefined) would mean deny-all. But saying it out loud does NOT mean widening: an enumerated
|
|
81
|
+
// closed grant re-encodes as the explicit id list, so a no-change save over a collapsed universe
|
|
82
|
+
// cannot silently turn "grant exactly these" into "grant everything, including future resources".
|
|
83
|
+
// A wildcard is only produced when it was already a wildcard (or grant-all was chosen explicitly).
|
|
75
84
|
if (allIds.length > 0 && validEnabledCount === allIds.length) {
|
|
76
|
-
return { allow: ["*"] };
|
|
85
|
+
return shouldEncodeGrantAllWildcard(options) ? { allow: ["*"] } : { allow: [...allIds] };
|
|
77
86
|
}
|
|
78
87
|
if (allIds.length === 0) {
|
|
79
88
|
return undefined;
|
|
@@ -112,9 +121,9 @@ export function detectResourceFraming(filter) {
|
|
|
112
121
|
/**
|
|
113
122
|
* Encode an enabled set back into a filter, respecting the specified framing.
|
|
114
123
|
*/
|
|
115
|
-
export function encodeResourceSelectionWithFraming(enabled, allIds, framing) {
|
|
124
|
+
export function encodeResourceSelectionWithFraming(enabled, allIds, framing, options) {
|
|
116
125
|
if (framing === "allow") {
|
|
117
|
-
return encodeResourceSelection(enabled, allIds);
|
|
126
|
+
return encodeResourceSelection(enabled, allIds, options);
|
|
118
127
|
}
|
|
119
128
|
const allIdsSet = new Set(allIds);
|
|
120
129
|
let validEnabledCount = 0;
|
|
@@ -123,9 +132,10 @@ export function encodeResourceSelectionWithFraming(enabled, allIds, framing) {
|
|
|
123
132
|
validEnabledCount++;
|
|
124
133
|
}
|
|
125
134
|
}
|
|
126
|
-
// All enabled: explicit grant-all (see encodeResourceSelection — undefined means DENIED)
|
|
135
|
+
// All enabled: explicit grant-all (see encodeResourceSelection — undefined means DENIED), but
|
|
136
|
+
// never widened to a wildcard without context — same gate as the allow-framing branch.
|
|
127
137
|
if (allIds.length > 0 && validEnabledCount === allIds.length) {
|
|
128
|
-
return { allow: ["*"] };
|
|
138
|
+
return shouldEncodeGrantAllWildcard(options) ? { allow: ["*"] } : { allow: [...allIds] };
|
|
129
139
|
}
|
|
130
140
|
if (allIds.length === 0) {
|
|
131
141
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-resource-selection.js","sourceRoot":"","sources":["../../src/core/profile-resource-selection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ResourceProfileFilterSettings } from \"./settings-manager.ts\";\n\n/**\n * Decode a stored allow/block filter into the set of enabled resource ids,\n * given the full universe of ids for that kind.\n * - undefined / empty filter -> all enabled\n * - block contains \"*\" -> none enabled\n * - allow non-empty -> exactly the allow entries that exist in allIds\n * - block of specific ids (no \"*\") -> all ids except blocked ones\n * (If both allow and block specific ids are present: start from allow-or-all, then remove blocked.)\n */\nexport function decodeResourceSelection(\n\tfilter: ResourceProfileFilterSettings | undefined,\n\tallIds: string[],\n): Set<string> {\n\t// Strict UAC: an unmentioned kind is DENIED — decoding it as \"all enabled\" would both\n\t// lie in the editor UI and, on save, convert silent denial into an explicit grant-all.\n\tif (!filter) {\n\t\treturn new Set();\n\t}\n\n\t// If block contains \"*\", nothing is enabled\n\tif (filter.block?.includes(\"*\")) {\n\t\treturn new Set();\n\t}\n\n\t// Explicit grant-all: every id enabled except explicitly blocked ones.\n\tif (filter.allow?.includes(\"*\")) {\n\t\tconst blocked = new Set(filter.block ?? []);\n\t\treturn new Set(allIds.filter((id) => !blocked.has(id)));\n\t}\n\n\t// If allow is specified, start with the allow list filtered to valid IDs\n\tif (filter.allow && filter.allow.length > 0) {\n\t\tconst allIdsSet = new Set(allIds);\n\t\tconst enabled = new Set<string>();\n\t\tfor (const id of filter.allow) {\n\t\t\tif (allIdsSet.has(id)) {\n\t\t\t\tenabled.add(id);\n\t\t\t}\n\t\t}\n\t\t// If block is also specified, remove blocked ids\n\t\tif (filter.block && filter.block.length > 0) {\n\t\t\tconst blockSet = new Set(filter.block);\n\t\t\tfor (const id of Array.from(enabled)) {\n\t\t\t\tif (blockSet.has(id)) {\n\t\t\t\t\tenabled.delete(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn enabled;\n\t}\n\n\t// No allow specified, start with all ids\n\tconst enabled = new Set(allIds);\n\t// Remove any blocked ids\n\tif (filter.block && filter.block.length > 0) {\n\t\tconst blockSet = new Set(filter.block);\n\t\tfor (const id of allIds) {\n\t\t\tif (blockSet.has(id)) {\n\t\t\t\tenabled.delete(id);\n\t\t\t}\n\t\t}\n\t}\n\treturn enabled;\n}\n\n/**\n * Encode an enabled set back into a filter.\n * - all enabled -> undefined (caller omits the kind)\n * - some but not all -> { allow: [...enabled, in allIds order] }\n * - none enabled -> { block: [\"*\"] }\n */\nexport function encodeResourceSelection(\n\tenabled: Set<string>,\n\tallIds: string[],\n): ResourceProfileFilterSettings | undefined {\n\tconst allIdsSet = new Set(allIds);\n\n\t// Count how many enabled ids are actually in allIds\n\tlet validEnabledCount = 0;\n\tfor (const id of enabled) {\n\t\tif (allIdsSet.has(id)) {\n\t\t\tvalidEnabledCount++;\n\t\t}\n\t}\n\n\t// All enabled: grant-all must be said OUT LOUD under strict UAC — omitting the kind\n\t// (returning undefined) would mean deny-all, silently corrupting a fully-granted kind.\n\tif (allIds.length > 0 && validEnabledCount === allIds.length) {\n\t\treturn { allow: [\"*\"] };\n\t}\n\tif (allIds.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// None enabled: return { block: [\"*\"] }\n\tif (validEnabledCount === 0) {\n\t\treturn { block: [\"*\"] };\n\t}\n\n\t// Some but not all: return { allow: [...enabled, in allIds order] }\n\tconst allow: string[] = [];\n\tfor (const id of allIds) {\n\t\tif (enabled.has(id)) {\n\t\t\tallow.push(id);\n\t\t}\n\t}\n\treturn { allow };\n}\n\nexport type ResourceFraming = \"allow\" | \"block\";\n\n/**\n * Detect the framing of a given resource profile filter settings.\n */\nexport function detectResourceFraming(filter: ResourceProfileFilterSettings | undefined): ResourceFraming {\n\tif (!filter) {\n\t\treturn \"block\";\n\t}\n\tif (filter.allow && filter.allow.length > 0) {\n\t\treturn \"allow\";\n\t}\n\tif (filter.block && filter.block.length > 0) {\n\t\tif (filter.block.includes(\"*\")) {\n\t\t\treturn \"allow\";\n\t\t}\n\t\treturn \"block\";\n\t}\n\treturn \"block\";\n}\n\n/**\n * Encode an enabled set back into a filter, respecting the specified framing.\n */\nexport function encodeResourceSelectionWithFraming(\n\tenabled: Set<string>,\n\tallIds: string[],\n\tframing: ResourceFraming,\n): ResourceProfileFilterSettings | undefined {\n\tif (framing === \"allow\") {\n\t\treturn encodeResourceSelection(enabled, allIds);\n\t}\n\n\tconst allIdsSet = new Set(allIds);\n\tlet validEnabledCount = 0;\n\tfor (const id of enabled) {\n\t\tif (allIdsSet.has(id)) {\n\t\t\tvalidEnabledCount++;\n\t\t}\n\t}\n\n\t// All enabled: explicit grant-all (see encodeResourceSelection — undefined means DENIED).\n\tif (allIds.length > 0 && validEnabledCount === allIds.length) {\n\t\treturn { allow: [\"*\"] };\n\t}\n\tif (allIds.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// None enabled: return { block: [\"*\"] }\n\tif (validEnabledCount === 0) {\n\t\treturn { block: [\"*\"] };\n\t}\n\n\t// Block framing with subset disabled: list disabled ids in block\n\tconst block: string[] = [];\n\tfor (const id of allIds) {\n\t\tif (!enabled.has(id)) {\n\t\t\tblock.push(id);\n\t\t}\n\t}\n\treturn { block };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"profile-resource-selection.js","sourceRoot":"","sources":["../../src/core/profile-resource-selection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ResourceProfileFilterSettings } from \"./settings-manager.ts\";\n\n/**\n * Decode a stored allow/block filter into the set of enabled resource ids,\n * given the full universe of ids for that kind.\n * - undefined / empty filter -> all enabled\n * - block contains \"*\" -> none enabled\n * - allow non-empty -> exactly the allow entries that exist in allIds\n * - block of specific ids (no \"*\") -> all ids except blocked ones\n * (If both allow and block specific ids are present: start from allow-or-all, then remove blocked.)\n */\nexport function decodeResourceSelection(\n\tfilter: ResourceProfileFilterSettings | undefined,\n\tallIds: string[],\n): Set<string> {\n\t// Strict UAC: an unmentioned kind is DENIED — decoding it as \"all enabled\" would both\n\t// lie in the editor UI and, on save, convert silent denial into an explicit grant-all.\n\tif (!filter) {\n\t\treturn new Set();\n\t}\n\n\t// If block contains \"*\", nothing is enabled\n\tif (filter.block?.includes(\"*\")) {\n\t\treturn new Set();\n\t}\n\n\t// Explicit grant-all: every id enabled except explicitly blocked ones.\n\tif (filter.allow?.includes(\"*\")) {\n\t\tconst blocked = new Set(filter.block ?? []);\n\t\treturn new Set(allIds.filter((id) => !blocked.has(id)));\n\t}\n\n\t// If allow is specified, start with the allow list filtered to valid IDs\n\tif (filter.allow && filter.allow.length > 0) {\n\t\tconst allIdsSet = new Set(allIds);\n\t\tconst enabled = new Set<string>();\n\t\tfor (const id of filter.allow) {\n\t\t\tif (allIdsSet.has(id)) {\n\t\t\t\tenabled.add(id);\n\t\t\t}\n\t\t}\n\t\t// If block is also specified, remove blocked ids\n\t\tif (filter.block && filter.block.length > 0) {\n\t\t\tconst blockSet = new Set(filter.block);\n\t\t\tfor (const id of Array.from(enabled)) {\n\t\t\t\tif (blockSet.has(id)) {\n\t\t\t\t\tenabled.delete(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn enabled;\n\t}\n\n\t// No allow specified, start with all ids\n\tconst enabled = new Set(allIds);\n\t// Remove any blocked ids\n\tif (filter.block && filter.block.length > 0) {\n\t\tconst blockSet = new Set(filter.block);\n\t\tfor (const id of allIds) {\n\t\t\tif (blockSet.has(id)) {\n\t\t\t\tenabled.delete(id);\n\t\t\t}\n\t\t}\n\t}\n\treturn enabled;\n}\n\n/**\n * Options that let the encoder distinguish a genuine grant-all from an all-enabled snapshot of an\n * enumerated grant (e.g. a collapsed universe where every enumerated id happens to be visible).\n * - originalFilter: the filter the selection was decoded from. A wildcard is preserved as a\n * wildcard; an enumerated grant is NEVER widened into one.\n * - grantAll: the caller explicitly chose \"grant all (including future)\" — force the wildcard.\n */\nexport interface EncodeResourceSelectionOptions {\n\toriginalFilter?: ResourceProfileFilterSettings;\n\tgrantAll?: boolean;\n}\n\nfunction shouldEncodeGrantAllWildcard(options?: EncodeResourceSelectionOptions): boolean {\n\tif (options?.grantAll) return true;\n\treturn options?.originalFilter?.allow?.includes(\"*\") ?? false;\n}\n\n/**\n * Encode an enabled set back into a filter.\n * - all enabled -> enumerated { allow: [...allIds] } (or { allow: [\"*\"] } only when the\n * original was already a wildcard / the caller chose grant-all)\n * - some but not all -> { allow: [...enabled, in allIds order] }\n * - none enabled -> { block: [\"*\"] }\n */\nexport function encodeResourceSelection(\n\tenabled: Set<string>,\n\tallIds: string[],\n\toptions?: EncodeResourceSelectionOptions,\n): ResourceProfileFilterSettings | undefined {\n\tconst allIdsSet = new Set(allIds);\n\n\t// Count how many enabled ids are actually in allIds\n\tlet validEnabledCount = 0;\n\tfor (const id of enabled) {\n\t\tif (allIdsSet.has(id)) {\n\t\t\tvalidEnabledCount++;\n\t\t}\n\t}\n\n\t// All enabled: grant-all must be said OUT LOUD under strict UAC — omitting the kind (returning\n\t// undefined) would mean deny-all. But saying it out loud does NOT mean widening: an enumerated\n\t// closed grant re-encodes as the explicit id list, so a no-change save over a collapsed universe\n\t// cannot silently turn \"grant exactly these\" into \"grant everything, including future resources\".\n\t// A wildcard is only produced when it was already a wildcard (or grant-all was chosen explicitly).\n\tif (allIds.length > 0 && validEnabledCount === allIds.length) {\n\t\treturn shouldEncodeGrantAllWildcard(options) ? { allow: [\"*\"] } : { allow: [...allIds] };\n\t}\n\tif (allIds.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// None enabled: return { block: [\"*\"] }\n\tif (validEnabledCount === 0) {\n\t\treturn { block: [\"*\"] };\n\t}\n\n\t// Some but not all: return { allow: [...enabled, in allIds order] }\n\tconst allow: string[] = [];\n\tfor (const id of allIds) {\n\t\tif (enabled.has(id)) {\n\t\t\tallow.push(id);\n\t\t}\n\t}\n\treturn { allow };\n}\n\nexport type ResourceFraming = \"allow\" | \"block\";\n\n/**\n * Detect the framing of a given resource profile filter settings.\n */\nexport function detectResourceFraming(filter: ResourceProfileFilterSettings | undefined): ResourceFraming {\n\tif (!filter) {\n\t\treturn \"block\";\n\t}\n\tif (filter.allow && filter.allow.length > 0) {\n\t\treturn \"allow\";\n\t}\n\tif (filter.block && filter.block.length > 0) {\n\t\tif (filter.block.includes(\"*\")) {\n\t\t\treturn \"allow\";\n\t\t}\n\t\treturn \"block\";\n\t}\n\treturn \"block\";\n}\n\n/**\n * Encode an enabled set back into a filter, respecting the specified framing.\n */\nexport function encodeResourceSelectionWithFraming(\n\tenabled: Set<string>,\n\tallIds: string[],\n\tframing: ResourceFraming,\n\toptions?: EncodeResourceSelectionOptions,\n): ResourceProfileFilterSettings | undefined {\n\tif (framing === \"allow\") {\n\t\treturn encodeResourceSelection(enabled, allIds, options);\n\t}\n\n\tconst allIdsSet = new Set(allIds);\n\tlet validEnabledCount = 0;\n\tfor (const id of enabled) {\n\t\tif (allIdsSet.has(id)) {\n\t\t\tvalidEnabledCount++;\n\t\t}\n\t}\n\n\t// All enabled: explicit grant-all (see encodeResourceSelection — undefined means DENIED), but\n\t// never widened to a wildcard without context — same gate as the allow-framing branch.\n\tif (allIds.length > 0 && validEnabledCount === allIds.length) {\n\t\treturn shouldEncodeGrantAllWildcard(options) ? { allow: [\"*\"] } : { allow: [...allIds] };\n\t}\n\tif (allIds.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// None enabled: return { block: [\"*\"] }\n\tif (validEnabledCount === 0) {\n\t\treturn { block: [\"*\"] };\n\t}\n\n\t// Block framing with subset disabled: list disabled ids in block\n\tconst block: string[] = [];\n\tfor (const id of allIds) {\n\t\tif (!enabled.has(id)) {\n\t\t\tblock.push(id);\n\t\t}\n\t}\n\treturn { block };\n}\n"]}
|
|
@@ -93,6 +93,26 @@ export declare function stripInvisibleUnicode(content: string): {
|
|
|
93
93
|
removed: number;
|
|
94
94
|
};
|
|
95
95
|
export declare function scanContextFileThreats(content: string, scope?: ThreatScope): string[];
|
|
96
|
+
/**
|
|
97
|
+
* Discover project/agent context files with their RAW content (profile blocks intact, no sanitize).
|
|
98
|
+
* The agents-kind profile filter can be DEFINED inside these same files (embedded `<resource-profile>`
|
|
99
|
+
* blocks), so callers must read raw to discover profiles before knowing which files the filter denies;
|
|
100
|
+
* sanitization/exposure is then applied only to files the filter allows.
|
|
101
|
+
*/
|
|
102
|
+
export declare function loadRawProjectContextFiles(options: {
|
|
103
|
+
cwd: string;
|
|
104
|
+
agentDir: string;
|
|
105
|
+
projectTrusted?: boolean;
|
|
106
|
+
}): Array<{
|
|
107
|
+
path: string;
|
|
108
|
+
rawContent: string;
|
|
109
|
+
}>;
|
|
110
|
+
/**
|
|
111
|
+
* Discover project/agent context files with SANITIZED content (profile blocks stripped, invisible/bidi
|
|
112
|
+
* chars removed, prompt-injection scanned). Every discovered file is sanitized — callers that must
|
|
113
|
+
* respect a profile's agents-kind denial should use {@link loadRawProjectContextFiles} and sanitize
|
|
114
|
+
* only the allowed subset instead, so denied content is never processed.
|
|
115
|
+
*/
|
|
96
116
|
export declare function loadProjectContextFiles(options: {
|
|
97
117
|
cwd: string;
|
|
98
118
|
agentDir: string;
|