@letrquan/book 0.3.0 → 0.4.0-beta.0
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 +1024 -0
- package/README.md +6 -3
- package/dist/{additional-roots-H7UNAEHS.js → additional-roots-VAWRQ625.js} +8 -7
- package/dist/{app-GE4OHJOC.js → app-J7BVPSUH.js} +5397 -2953
- package/dist/app-J7BVPSUH.js.map +1 -0
- package/dist/chunk-32WBCUAN.js +660 -0
- package/dist/chunk-32WBCUAN.js.map +1 -0
- package/dist/{chunk-525CAZPY.js → chunk-4DKHLZRI.js} +6 -6
- package/dist/{chunk-4AS7LKKQ.js → chunk-62EEAUID.js} +2 -2
- package/dist/{chunk-AQEQX4FF.js → chunk-AHC7OU75.js} +385 -55
- package/dist/chunk-AHC7OU75.js.map +1 -0
- package/dist/{chunk-EFJ2NH6E.js → chunk-AJZWLKLQ.js} +63 -14
- package/dist/chunk-AJZWLKLQ.js.map +1 -0
- package/dist/chunk-B5FC3MYZ.js +395 -0
- package/dist/chunk-B5FC3MYZ.js.map +1 -0
- package/dist/{chunk-67UZEWWF.js → chunk-DNFQTSMJ.js} +53 -11
- package/dist/chunk-DNFQTSMJ.js.map +1 -0
- package/dist/{chunk-TLX3H2CL.js → chunk-E5WLQSKA.js} +231 -40
- package/dist/chunk-E5WLQSKA.js.map +1 -0
- package/dist/chunk-ECLC4CIJ.js +1181 -0
- package/dist/chunk-ECLC4CIJ.js.map +1 -0
- package/dist/chunk-EEX6QNXV.js +127 -0
- package/dist/chunk-EEX6QNXV.js.map +1 -0
- package/dist/chunk-EFXVSQ5J.js +931 -0
- package/dist/chunk-EFXVSQ5J.js.map +1 -0
- package/dist/{chunk-RFJ6Q6LE.js → chunk-ENLB7NYV.js} +577 -164
- package/dist/chunk-ENLB7NYV.js.map +1 -0
- package/dist/{chunk-IME7R2UI.js → chunk-FPR7SKIE.js} +1268 -883
- package/dist/chunk-FPR7SKIE.js.map +1 -0
- package/dist/{chunk-VPNLCMVR.js → chunk-HFB74CLM.js} +13 -5
- package/dist/chunk-HFB74CLM.js.map +1 -0
- package/dist/{chunk-5RDRAO4B.js → chunk-HOZXKOE3.js} +37 -1
- package/dist/chunk-HOZXKOE3.js.map +1 -0
- package/dist/chunk-IDYWN37T.js +36 -0
- package/dist/chunk-IDYWN37T.js.map +1 -0
- package/dist/{chunk-YC6W4EJH.js → chunk-JGF5HLSI.js} +193 -75
- package/dist/chunk-JGF5HLSI.js.map +1 -0
- package/dist/{chunk-5YHTKWJN.js → chunk-KDNWMKXV.js} +2447 -907
- package/dist/chunk-KDNWMKXV.js.map +1 -0
- package/dist/{chunk-Y2VHN7TC.js → chunk-MEOB2DZA.js} +11 -1
- package/dist/chunk-MEOB2DZA.js.map +1 -0
- package/dist/{chunk-KBQS35OV.js → chunk-MV5PQNIA.js} +2 -2
- package/dist/chunk-N2G4Q7ME.js +2672 -0
- package/dist/chunk-N2G4Q7ME.js.map +1 -0
- package/dist/{chunk-62QL5QUP.js → chunk-OJBMDM5H.js} +17 -1
- package/dist/chunk-OJBMDM5H.js.map +1 -0
- package/dist/{chunk-56SIEMDX.js → chunk-PTDC7ZUP.js} +2 -2
- package/dist/{chunk-X4NJT436.js → chunk-REASC2QG.js} +67 -28
- package/dist/chunk-REASC2QG.js.map +1 -0
- package/dist/chunk-SBTU5BEC.js +114 -0
- package/dist/chunk-SBTU5BEC.js.map +1 -0
- package/dist/{chunk-HQI7NYGX.js → chunk-SWPDKLNM.js} +2 -2
- package/dist/{chunk-W3XFHEF4.js → chunk-UCFJ43OS.js} +140 -28
- package/dist/chunk-UCFJ43OS.js.map +1 -0
- package/dist/{chunk-QYBD22H5.js → chunk-W7SLYS3M.js} +80 -16
- package/dist/chunk-W7SLYS3M.js.map +1 -0
- package/dist/{chunk-SOW4WRQP.js → chunk-WV3O5PGX.js} +3 -3
- package/dist/{chunk-JTPOI3KU.js → chunk-XJRJVXJR.js} +262 -38
- package/dist/chunk-XJRJVXJR.js.map +1 -0
- package/dist/{chunk-224FJZLH.js → chunk-YIL6HTJX.js} +228 -5
- package/dist/chunk-YIL6HTJX.js.map +1 -0
- package/dist/{command-approvals-VBIU6BLM.js → command-approvals-ZRY66LCW.js} +5 -4
- package/dist/context-C3RAP6K5.js +41 -0
- package/dist/{hook-approvals-ZVT4V7IM.js → hook-approvals-DPQD5H65.js} +5 -4
- package/dist/index.js +657 -754
- package/dist/index.js.map +1 -1
- package/dist/{interactive-assets-T4I4SEHU.js → interactive-assets-73AQO5WP.js} +11 -6
- package/dist/{interactive-assets-T4I4SEHU.js.map → interactive-assets-73AQO5WP.js.map} +1 -1
- package/dist/job-runner.js +10 -3
- package/dist/job-runner.js.map +1 -1
- package/dist/job-supervisor.js +13 -4
- package/dist/job-supervisor.js.map +1 -1
- package/dist/loader-DQNPDKOX.js +27 -0
- package/dist/{mcp-approvals-HJ2VDYMC.js → mcp-approvals-27LJYADQ.js} +5 -4
- package/dist/{mcp-config-RNB5LEVE.js → mcp-config-GXSODNCM.js} +3 -2
- package/dist/memory-store-I6Z54VUN.js +51 -0
- package/dist/{model-window-store-MTSQ5JDJ.js → model-window-store-6VKXXTPJ.js} +4 -3
- package/dist/{openai-compatible-2OB54YST.js → openai-compatible-IPUNBJ53.js} +5 -3
- package/dist/{permission-approvals-YLV6UC5W.js → permission-approvals-Q5IMFEZI.js} +5 -4
- package/dist/{permissions-DHOKF3W2.js → permissions-7Y35X6HZ.js} +26 -9
- package/dist/provider-approvals-5AGH3RVT.js +76 -0
- package/dist/{sandbox-WRYTZH3D.js → sandbox-N2RY72GN.js} +6 -5
- package/dist/{scrollback-35ME2GFX.js → scrollback-GD76GNM4.js} +36 -28
- package/dist/scrollback-GD76GNM4.js.map +1 -0
- package/dist/sdk.d.ts +876 -64
- package/dist/sdk.js +57 -37
- package/dist/sdk.js.map +1 -1
- package/dist/settings-loader-KDBH45AQ.js +43 -0
- package/dist/{settings-removed-JWWPT4WA.js → settings-removed-3ATWJEF3.js} +2 -2
- package/dist/shell-selection-Z5WORZU4.js +31 -0
- package/dist/shell-selection-Z5WORZU4.js.map +1 -0
- package/package.json +5 -5
- package/dist/app-GE4OHJOC.js.map +0 -1
- package/dist/chunk-224FJZLH.js.map +0 -1
- package/dist/chunk-5RDRAO4B.js.map +0 -1
- package/dist/chunk-5YHTKWJN.js.map +0 -1
- package/dist/chunk-62QL5QUP.js.map +0 -1
- package/dist/chunk-67UZEWWF.js.map +0 -1
- package/dist/chunk-6OQQOMZR.js +0 -785
- package/dist/chunk-6OQQOMZR.js.map +0 -1
- package/dist/chunk-AQEQX4FF.js.map +0 -1
- package/dist/chunk-C7ADUNPR.js +0 -273
- package/dist/chunk-C7ADUNPR.js.map +0 -1
- package/dist/chunk-EFJ2NH6E.js.map +0 -1
- package/dist/chunk-IME7R2UI.js.map +0 -1
- package/dist/chunk-J62VZYOB.js +0 -1339
- package/dist/chunk-J62VZYOB.js.map +0 -1
- package/dist/chunk-JTPOI3KU.js.map +0 -1
- package/dist/chunk-QYBD22H5.js.map +0 -1
- package/dist/chunk-RFJ6Q6LE.js.map +0 -1
- package/dist/chunk-S4JMID4G.js +0 -259
- package/dist/chunk-S4JMID4G.js.map +0 -1
- package/dist/chunk-TLX3H2CL.js.map +0 -1
- package/dist/chunk-VPNLCMVR.js.map +0 -1
- package/dist/chunk-W3XFHEF4.js.map +0 -1
- package/dist/chunk-X4NJT436.js.map +0 -1
- package/dist/chunk-X66I2NQO.js +0 -137
- package/dist/chunk-X66I2NQO.js.map +0 -1
- package/dist/chunk-Y2VHN7TC.js.map +0 -1
- package/dist/chunk-YC6W4EJH.js.map +0 -1
- package/dist/context-CBOBDY5Q.js +0 -38
- package/dist/loader-S77OVTHH.js +0 -18
- package/dist/memory-store-DZUT5HUH.js +0 -75
- package/dist/scrollback-35ME2GFX.js.map +0 -1
- package/dist/settings-loader-JUNPGAAM.js +0 -35
- package/dist/shell-selection-CDHGJ4GC.js +0 -17
- /package/dist/{additional-roots-H7UNAEHS.js.map → additional-roots-VAWRQ625.js.map} +0 -0
- /package/dist/{chunk-525CAZPY.js.map → chunk-4DKHLZRI.js.map} +0 -0
- /package/dist/{chunk-4AS7LKKQ.js.map → chunk-62EEAUID.js.map} +0 -0
- /package/dist/{chunk-KBQS35OV.js.map → chunk-MV5PQNIA.js.map} +0 -0
- /package/dist/{chunk-56SIEMDX.js.map → chunk-PTDC7ZUP.js.map} +0 -0
- /package/dist/{chunk-HQI7NYGX.js.map → chunk-SWPDKLNM.js.map} +0 -0
- /package/dist/{chunk-SOW4WRQP.js.map → chunk-WV3O5PGX.js.map} +0 -0
- /package/dist/{command-approvals-VBIU6BLM.js.map → command-approvals-ZRY66LCW.js.map} +0 -0
- /package/dist/{context-CBOBDY5Q.js.map → context-C3RAP6K5.js.map} +0 -0
- /package/dist/{hook-approvals-ZVT4V7IM.js.map → hook-approvals-DPQD5H65.js.map} +0 -0
- /package/dist/{loader-S77OVTHH.js.map → loader-DQNPDKOX.js.map} +0 -0
- /package/dist/{mcp-approvals-HJ2VDYMC.js.map → mcp-approvals-27LJYADQ.js.map} +0 -0
- /package/dist/{mcp-config-RNB5LEVE.js.map → mcp-config-GXSODNCM.js.map} +0 -0
- /package/dist/{memory-store-DZUT5HUH.js.map → memory-store-I6Z54VUN.js.map} +0 -0
- /package/dist/{model-window-store-MTSQ5JDJ.js.map → model-window-store-6VKXXTPJ.js.map} +0 -0
- /package/dist/{openai-compatible-2OB54YST.js.map → openai-compatible-IPUNBJ53.js.map} +0 -0
- /package/dist/{permission-approvals-YLV6UC5W.js.map → permission-approvals-Q5IMFEZI.js.map} +0 -0
- /package/dist/{permissions-DHOKF3W2.js.map → permissions-7Y35X6HZ.js.map} +0 -0
- /package/dist/{sandbox-WRYTZH3D.js.map → provider-approvals-5AGH3RVT.js.map} +0 -0
- /package/dist/{settings-loader-JUNPGAAM.js.map → sandbox-N2RY72GN.js.map} +0 -0
- /package/dist/{settings-removed-JWWPT4WA.js.map → settings-loader-KDBH45AQ.js.map} +0 -0
- /package/dist/{shell-selection-CDHGJ4GC.js.map → settings-removed-3ATWJEF3.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/skills.ts"],"sourcesContent":["import {\n closeSync,\n existsSync,\n lstatSync,\n openSync,\n readFileSync,\n readSync,\n readdirSync,\n realpathSync,\n statSync,\n} from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { homedir } from 'node:os';\nimport { dirname, isAbsolute, join, parse, relative, resolve, sep } from 'node:path';\nimport { parseFrontmatter } from './frontmatter.js';\nimport { resolveBookHome } from './book-home.js';\nimport { isUserHome, tryRealPath } from './repo-containment.js';\nimport type { SkillActivation, SkillExecution } from './settings.js';\nimport { createUncGuard, reachesUncPath, type UncGuard } from './unc-path.js';\n\nexport const SKILL_ENTRY_FILENAME = 'SKILL.md';\nexport const MAX_SKILL_HEADER_BYTES = 64 * 1024;\nexport const MAX_SKILL_BODY_BYTES = 100 * 1024;\nexport const MAX_SKILL_RESOURCES = 200;\nexport const MAX_SKILL_RESOURCE_DEPTH = 4;\nexport const MAX_SKILL_RESOURCE_BYTES = 2 * 1024 * 1024;\n\nconst SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst KNOWN_FRONTMATTER_FIELDS = new Set([\n 'name',\n 'description',\n 'license',\n 'compatibility',\n 'version',\n 'metadata',\n 'allowed-tools',\n 'tools',\n 'when_to_use',\n 'model',\n 'lifetime',\n 'disabled',\n // Interoperable Claude/Codex skill metadata. Invocation controls are\n // advisory to Book's explicit `$name` UI and do not grant permissions.\n 'disable-model-invocation',\n 'user-invocable',\n 'argument-hint',\n]);\n\nexport type SkillSource = 'user' | 'project';\nexport type SkillRootKind = 'book' | 'agents' | 'claude' | 'opencode';\nexport type SkillIssueSeverity = 'error' | 'warning';\n\nexport interface SkillIssue {\n code: string;\n message: string;\n severity: SkillIssueSeverity;\n}\n\nexport interface SkillResource {\n relativePath: string;\n byteSize: number;\n mtimeMs: number;\n digest: string;\n}\n\nexport interface ShadowedSkill {\n path: string;\n source: SkillSource;\n rootKind: SkillRootKind;\n}\n\n/** Metadata discovered without retaining or injecting the SKILL.md body. */\nexport interface Skill {\n id: string;\n version: string;\n descriptorDigest: string;\n resourceDigest: string;\n name: string;\n description: string;\n whenToUse?: string;\n license?: string;\n compatibility?: string;\n metadata: Record<string, string>;\n /** Requested tool ceiling. It never grants permission by itself. */\n allowedTools?: string[];\n model?: string;\n lifetime: 'turn' | 'run';\n /** Absolute path to the skill entrypoint. */\n path: string;\n /** Absolute directory that owns the skill and its resources. */\n rootPath: string;\n source: SkillSource;\n rootKind: SkillRootKind;\n activation: SkillActivation;\n execution: SkillExecution;\n invocationCount: number;\n entryByteSize: number;\n entryMtimeMs: number;\n resources: SkillResource[];\n issues: SkillIssue[];\n valid: boolean;\n shadowed: ShadowedSkill[];\n}\n\nexport interface LoadedSkillBody {\n body: string;\n digest: string;\n byteSize: number;\n}\n\nexport interface SkillRoot {\n path: string;\n source: SkillSource;\n kind: SkillRootKind;\n}\n\nexport interface DiscoverSkillsOptions {\n homeDir?: string;\n bookHomeDir?: string;\n includeUser?: boolean;\n projectRoot?: string;\n includeOpenCode?: boolean;\n enabled?: boolean;\n executionOverrides?: Readonly<Record<string, SkillExecution>>;\n}\n\nfunction pathKey(path: string): string {\n return process.platform === 'win32' ? resolve(path).toLowerCase() : resolve(path);\n}\n\n/**\n * The real path of a skill root, or undefined when it does not exist (it contributes no skills,\n * so there is nothing to fold).\n *\n * Only for asking whether a project root is a user root reached another way. {@link pathKey}\n * stays the path as written because it also builds the skill id, which keys consent and\n * execution overrides, and it is what roots are otherwise deduped by.\n */\nfunction realRootPath(path: string): string | undefined {\n try {\n const real = realpathSync.native(path);\n return process.platform === 'win32' ? real.toLowerCase() : real;\n } catch {\n return undefined;\n }\n}\n\nfunction isInside(root: string, candidate: string): boolean {\n const rel = relative(root, candidate);\n return rel === '' || (!rel.startsWith(`..${sep}`) && rel !== '..' && !isAbsolute(rel));\n}\n\n/**\n * The nearest directory above `workspace`, as written, with a `.git` entry; the workspace when\n * there is none. A `.git` at the home directory (`home`, the user's when not given) is a dotfiles\n * repository, not a project (`findRepositoryRoot` in `repo-containment.ts`), so it ends the walk\n * with no repository: a project under the home directory without its own `.git` scans its own\n * directory, not every directory from the home directory down.\n */\nfunction projectRootFor(workspace: string, home: string | undefined, reachesUnc: UncGuard): string {\n // A workspace that reaches a network share has no project roots (`skillRoots`), so nothing on\n // the way up is probed; nor is a `.git` that does, which `existsSync` would follow (#579).\n if (reachesUnc(workspace)) return resolve(workspace);\n let current = resolve(workspace);\n const filesystemRoot = parse(current).root;\n while (true) {\n const dotGit = join(current, '.git');\n // A `.git` it may not open is one it cannot read: the workspace is then its own root, as for\n // memory (`findGitRoot`).\n if (reachesUnc(dotGit)) return resolve(workspace);\n if (existsSync(dotGit)) {\n return isUserHome(tryRealPath(current) ?? current, home) ? resolve(workspace) : current;\n }\n if (current === filesystemRoot) return resolve(workspace);\n current = dirname(current);\n }\n}\n\nfunction directoriesFromRoot(root: string, workspace: string): string[] {\n const normalizedRoot = resolve(root);\n const normalizedWorkspace = resolve(workspace);\n if (!isInside(normalizedRoot, normalizedWorkspace)) return [normalizedWorkspace];\n const directories: string[] = [];\n let current = normalizedWorkspace;\n while (true) {\n directories.push(current);\n if (pathKey(current) === pathKey(normalizedRoot)) break;\n current = dirname(current);\n }\n return directories.reverse();\n}\n\n/**\n * Roots are ordered from lowest to highest precedence.\n *\n * A project root is a path a repository can commit as a link, and on Windows resolving a link to\n * a network share opens the share, which can send the user's credentials to the host it names\n * (#567, #579). A project root that reaches one is therefore not a root at all, so nothing that\n * takes its roots from here resolves it. The user's own roots are theirs to keep on a share.\n * `reachesUnc` is the UNC guard of the discovery this is part of, so the two share what it probed.\n */\nexport function skillRoots(\n workspace: string,\n options: DiscoverSkillsOptions = {},\n reachesUnc: UncGuard = createUncGuard(),\n): SkillRoot[] {\n const roots: SkillRoot[] = [];\n if (options.includeUser !== false) {\n const home = options.homeDir ?? homedir();\n const bookHome =\n options.bookHomeDir ?? (options.homeDir ? join(home, '.book') : resolveBookHome());\n roots.push(\n { path: join(home, '.claude', 'skills'), source: 'user', kind: 'claude' },\n { path: join(home, '.agents', 'skills'), source: 'user', kind: 'agents' },\n ...(options.includeOpenCode === false\n ? []\n : [\n {\n path: join(home, '.config', 'opencode', 'skills'),\n source: 'user' as const,\n kind: 'opencode' as const,\n },\n ]),\n { path: join(bookHome, 'skills'), source: 'user', kind: 'book' },\n );\n }\n\n const projectRoot = options.projectRoot ?? projectRootFor(workspace, options.homeDir, reachesUnc);\n for (const directory of directoriesFromRoot(projectRoot, workspace)) {\n roots.push(\n { path: join(directory, '.claude', 'skills'), source: 'project', kind: 'claude' },\n { path: join(directory, '.agents', 'skills'), source: 'project', kind: 'agents' },\n ...(options.includeOpenCode === false\n ? []\n : [\n {\n path: join(directory, '.opencode', 'skills'),\n source: 'project' as const,\n kind: 'opencode' as const,\n },\n ]),\n { path: join(directory, '.book', 'skills'), source: 'project', kind: 'book' },\n );\n }\n // The real paths of the user roots, for the one fold below. Two roots that merely alias each\n // other (a repository linking `.claude/skills` to `.book/skills`) are *not* merged: each keeps\n // its slot, and the later one still wins, as it did before roots were compared by real path.\n const userRealPaths = new Set<string>();\n for (const root of roots) {\n if (root.source !== 'user') continue;\n const real = realRootPath(root.path);\n if (real) userRealPaths.add(real);\n }\n const byPath = new Map<string, SkillRoot>();\n for (const root of roots) {\n const key = pathKey(root.path);\n // A workspace at `$HOME` walks the user's own roots again as project roots. They stay\n // user roots: a project skill asks before the model may run it, and the user's own\n // skills must not start asking because of where Book was launched (#429).\n if (byPath.get(key)?.source === 'user') continue;\n if (root.source === 'project' && reachesUnc(root.path)) continue;\n // The same, when the home is reached through a link, so the project spelling of the path\n // differs (#449). Only a project root is ever folded into a user root, never the reverse.\n if (root.source === 'project' && userRealPaths.size > 0) {\n const real = realRootPath(root.path);\n if (real && userRealPaths.has(real)) continue;\n }\n byPath.set(key, root);\n }\n return [...byPath.values()];\n}\n\nfunction readFrontmatterPrefix(path: string): {\n frontmatter: Record<string, unknown>;\n headerText: string;\n issues: SkillIssue[];\n} {\n const issues: SkillIssue[] = [];\n const fd = openSync(path, 'r');\n const chunks: Buffer[] = [];\n let total = 0;\n try {\n while (total < MAX_SKILL_HEADER_BYTES) {\n const chunk = Buffer.alloc(Math.min(4096, MAX_SKILL_HEADER_BYTES - total));\n const count = readSync(fd, chunk, 0, chunk.length, total);\n if (count === 0) break;\n chunks.push(chunk.subarray(0, count));\n total += count;\n const text = Buffer.concat(chunks).toString('utf8');\n if (/^---\\r?\\n[\\s\\S]*?\\r?\\n---(?:\\r?\\n|$)/.test(text)) {\n const match = text.match(/^---\\r?\\n[\\s\\S]*?\\r?\\n---(?:\\r?\\n|$)/);\n const headerText = match?.[0] ?? '';\n return { frontmatter: parseFrontmatter(headerText).frontmatter, headerText, issues };\n }\n }\n } finally {\n closeSync(fd);\n }\n issues.push({\n code: 'invalid_frontmatter',\n message: `Missing YAML frontmatter or closing delimiter within ${MAX_SKILL_HEADER_BYTES} bytes.`,\n severity: 'error',\n });\n return { frontmatter: {}, headerText: '', issues };\n}\n\nfunction stringField(frontmatter: Record<string, unknown>, name: string): string | undefined {\n const value = frontmatter[name];\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction metadataFromHeader(headerText: string): Record<string, string> {\n const lines = headerText.split(/\\r?\\n/);\n const metadata: Record<string, string> = {};\n const start = lines.findIndex((line) => /^metadata\\s*:\\s*$/.test(line.trim()));\n if (start < 0) return metadata;\n for (const line of lines.slice(start + 1)) {\n if (/^---\\s*$/.test(line)) break;\n if (line.trim() && !/^\\s+/.test(line)) break;\n const match = line.match(/^\\s+([A-Za-z0-9_.-]+)\\s*:\\s*(.*?)\\s*$/);\n if (!match) continue;\n metadata[match[1]] = match[2].replace(/^[\"'](.*)[\"']$/, '$1');\n }\n return metadata;\n}\n\nfunction allowedToolsFrom(frontmatter: Record<string, unknown>): string[] | undefined {\n const value = frontmatter['allowed-tools'] ?? frontmatter.tools;\n if (Array.isArray(value)) {\n const tools = value\n .map(String)\n .map((tool) => tool.trim())\n .filter(Boolean);\n return tools.length ? tools : undefined;\n }\n if (typeof value === 'string') {\n const tools = value.match(/[^\\s]+(?:\\([^)]*\\))?/g)?.map((tool) => tool.trim()) ?? [];\n return tools.length ? tools : undefined;\n }\n return undefined;\n}\n\nfunction collectResources(\n rootPath: string,\n entryPath: string,\n): {\n resources: SkillResource[];\n issues: SkillIssue[];\n} {\n const resources: SkillResource[] = [];\n const issues: SkillIssue[] = [];\n let depthLimitReported = false;\n const visit = (directory: string, depth: number): void => {\n if (depth > MAX_SKILL_RESOURCE_DEPTH) {\n if (!depthLimitReported) {\n depthLimitReported = true;\n issues.push({\n code: 'resource_depth_limit',\n message: `Resources deeper than ${MAX_SKILL_RESOURCE_DEPTH} directories are ignored.`,\n severity: 'warning',\n });\n }\n return;\n }\n if (resources.length >= MAX_SKILL_RESOURCES) return;\n let entries: string[];\n try {\n entries = readdirSync(directory).sort();\n } catch (error) {\n issues.push({\n code: 'resource_unreadable',\n message: `Could not inspect resources in ${directory}: ${error instanceof Error ? error.message : String(error)}`,\n severity: 'warning',\n });\n return;\n }\n for (const entry of entries) {\n if (resources.length >= MAX_SKILL_RESOURCES) break;\n const fullPath = join(directory, entry);\n if (pathKey(fullPath) === pathKey(entryPath)) continue;\n let info;\n try {\n info = lstatSync(fullPath);\n } catch {\n continue;\n }\n if (info.isSymbolicLink()) {\n issues.push({\n code: 'resource_symlink_ignored',\n message: `Ignored symbolic-link resource: ${relative(rootPath, fullPath)}`,\n severity: 'warning',\n });\n continue;\n }\n if (info.isDirectory()) {\n visit(fullPath, depth + 1);\n continue;\n }\n if (!info.isFile()) continue;\n let digest = createHash('sha256')\n .update(`unavailable:${info.size}:${info.mtimeMs}`)\n .digest('hex');\n if (info.size > MAX_SKILL_RESOURCE_BYTES) {\n issues.push({\n code: 'resource_too_large',\n message: `Resource exceeds ${MAX_SKILL_RESOURCE_BYTES} bytes: ${relative(rootPath, fullPath)}`,\n severity: 'warning',\n });\n }\n try {\n const fd = openSync(fullPath, 'r');\n try {\n const prefix = Buffer.alloc(Math.min(info.size, 8192));\n const read = readSync(fd, prefix, 0, prefix.length, 0);\n if (prefix.subarray(0, read).includes(0)) {\n issues.push({\n code: 'binary_resource',\n message: `Binary resource cannot be loaded into model context: ${relative(rootPath, fullPath)}`,\n severity: 'warning',\n });\n }\n } finally {\n closeSync(fd);\n }\n } catch (error) {\n issues.push({\n code: 'resource_unreadable',\n message: `Could not validate resource ${relative(rootPath, fullPath)}: ${error instanceof Error ? error.message : String(error)}`,\n severity: 'warning',\n });\n }\n if (info.size <= MAX_SKILL_RESOURCE_BYTES) {\n try {\n digest = createHash('sha256').update(readFileSync(fullPath)).digest('hex');\n } catch {\n // The visible unreadable-resource issue above is the actionable diagnostic.\n }\n }\n resources.push({\n relativePath: relative(rootPath, fullPath).split(sep).join('/'),\n byteSize: info.size,\n mtimeMs: info.mtimeMs,\n digest,\n });\n }\n };\n visit(rootPath, 1);\n if (resources.length >= MAX_SKILL_RESOURCES) {\n issues.push({\n code: 'resource_limit',\n message: `Only the first ${MAX_SKILL_RESOURCES} resources are available.`,\n severity: 'warning',\n });\n }\n return { resources, issues };\n}\n\nfunction descriptorFromEntry(\n entryPath: string,\n root: SkillRoot,\n directoryName: string,\n flat = false,\n): Skill {\n const { frontmatter, headerText, issues: headerIssues } = readFrontmatterPrefix(entryPath);\n const issues = [...headerIssues];\n const declaredName = stringField(frontmatter, 'name');\n const name = declaredName ?? directoryName;\n const description = stringField(frontmatter, 'description') ?? '';\n\n if (!SKILL_NAME_PATTERN.test(name) || name.length > 64) {\n issues.push({\n code: 'invalid_name',\n message: 'Skill names must be 1-64 lowercase letters, numbers, or single hyphens.',\n severity: 'error',\n });\n }\n if (!flat && declaredName !== directoryName) {\n issues.push({\n code: 'name_directory_mismatch',\n message: `Declared name \"${declaredName ?? '(missing)'}\" must match directory \"${directoryName}\".`,\n severity: 'error',\n });\n }\n if (!declaredName && flat) {\n issues.push({\n code: 'legacy_flat_skill',\n message: 'Flat .skill.md files are supported for compatibility; use <name>/SKILL.md.',\n severity: 'warning',\n });\n }\n if (!description || description.length > 1024) {\n issues.push({\n code: 'invalid_description',\n message: 'Skill description is required and must be at most 1024 characters.',\n severity: 'error',\n });\n }\n const compatibility = stringField(frontmatter, 'compatibility');\n if (compatibility && compatibility.length > 500) {\n issues.push({\n code: 'invalid_compatibility',\n message: 'Skill compatibility must be at most 500 characters.',\n severity: 'error',\n });\n }\n const whenToUse = stringField(frontmatter, 'when_to_use');\n if (whenToUse && whenToUse.length > 1024) {\n issues.push({\n code: 'invalid_when_to_use',\n message: 'Skill when_to_use must be at most 1024 characters.',\n severity: 'error',\n });\n }\n const model = stringField(frontmatter, 'model');\n if (model) {\n issues.push({\n code: 'unsupported_model_hint',\n message: 'The model field is retained for compatibility but does not change Book models.',\n severity: 'warning',\n });\n }\n const requestedLifetime = stringField(frontmatter, 'lifetime');\n if (requestedLifetime && requestedLifetime !== 'run' && requestedLifetime !== 'turn') {\n issues.push({\n code: 'invalid_lifetime',\n message: 'Skill lifetime must be run or turn; Book will use run.',\n severity: 'warning',\n });\n }\n const lifetime = requestedLifetime === 'turn' ? 'turn' : 'run';\n for (const field of Object.keys(frontmatter)) {\n if (!KNOWN_FRONTMATTER_FIELDS.has(field)) {\n issues.push({\n code: 'unknown_frontmatter_field',\n message: `Unknown frontmatter field: ${field}`,\n severity: 'warning',\n });\n }\n }\n\n let entryByteSize = 0;\n let entryMtimeMs = 0;\n try {\n const entryInfo = statSync(entryPath);\n entryByteSize = entryInfo.size;\n entryMtimeMs = entryInfo.mtimeMs;\n if (entryByteSize > MAX_SKILL_BODY_BYTES + MAX_SKILL_HEADER_BYTES) {\n issues.push({\n code: 'body_too_large',\n message: `SKILL.md exceeds the ${MAX_SKILL_BODY_BYTES}-byte body budget.`,\n severity: 'error',\n });\n }\n } catch {\n issues.push({\n code: 'skill_unreadable',\n message: 'Skill entrypoint is unreadable.',\n severity: 'error',\n });\n }\n\n const rootPath = dirname(entryPath);\n const resourceResult = flat\n ? { resources: [] as SkillResource[], issues: [] as SkillIssue[] }\n : collectResources(rootPath, entryPath);\n issues.push(...resourceResult.issues);\n\n const metadata = metadataFromHeader(headerText);\n const version = stringField(frontmatter, 'version') ?? metadata.version ?? 'unversioned';\n const resourceDigest = createHash('sha256')\n .update(JSON.stringify(resourceResult.resources))\n .digest('hex');\n const descriptorDigest = createHash('sha256')\n .update(\n JSON.stringify({\n name,\n description,\n whenToUse,\n version,\n source: root.source,\n rootKind: root.kind,\n path: pathKey(entryPath),\n allowedTools: allowedToolsFrom(frontmatter),\n lifetime,\n resourceDigest,\n }),\n )\n .digest('hex');\n\n return {\n id: `${root.kind}:${pathKey(entryPath)}`,\n version,\n descriptorDigest,\n resourceDigest,\n name,\n description,\n whenToUse,\n license: stringField(frontmatter, 'license'),\n compatibility,\n metadata,\n allowedTools: allowedToolsFrom(frontmatter),\n model,\n lifetime,\n path: entryPath,\n rootPath,\n source: root.source,\n rootKind: root.kind,\n activation: String(frontmatter.disabled).toLowerCase() === 'true' ? 'off' : 'manual',\n execution: 'inherit',\n invocationCount: 0,\n entryByteSize,\n entryMtimeMs,\n resources: resourceResult.resources,\n issues,\n valid: !issues.some((issue) => issue.severity === 'error'),\n shadowed: [],\n };\n}\n\n/**\n * The skills in one root. In a project root, each skill directory and SKILL.md is a path a\n * repository can commit as a link to a network share, as the root itself can (see\n * {@link skillRoots}, which drops such a root): each is asked of `reachesUnc` before anything\n * follows it, and one that reaches a share is not listed. A resource link is never followed\n * (`collectResources`).\n */\nfunction skillsUnderRoot(root: SkillRoot, reachesUnc: UncGuard): Skill[] {\n const refused = (path: string) => root.source === 'project' && reachesUnc(path);\n if (!existsSync(root.path)) return [];\n let entries: string[];\n try {\n entries = readdirSync(root.path).sort();\n } catch {\n return [];\n }\n\n const skills: Skill[] = [];\n for (const entry of entries) {\n const fullPath = join(root.path, entry);\n let info;\n try {\n info = lstatSync(fullPath);\n } catch {\n continue;\n }\n let directory = info.isDirectory();\n if (info.isSymbolicLink()) {\n if (refused(fullPath)) continue;\n try {\n directory = statSync(fullPath).isDirectory();\n } catch {\n continue;\n }\n }\n if (directory) {\n const entryPath = join(fullPath, SKILL_ENTRY_FILENAME);\n if (!refused(entryPath) && existsSync(entryPath) && statSync(entryPath).isFile()) {\n skills.push(descriptorFromEntry(entryPath, root, entry));\n }\n } else if (info.isFile() && entry.endsWith('.skill.md')) {\n skills.push(descriptorFromEntry(fullPath, root, entry.replace(/\\.skill\\.md$/, ''), true));\n }\n }\n return skills;\n}\n\nexport function discoverSkills(\n workspace: string,\n overrides: Readonly<Record<string, SkillActivation>> = {},\n options: DiscoverSkillsOptions = {},\n): Skill[] {\n const byName = new Map<string, Skill>();\n const reachesUnc = createUncGuard();\n for (const root of skillRoots(workspace, options, reachesUnc)) {\n for (const skill of skillsUnderRoot(root, reachesUnc)) {\n const previous = byName.get(skill.name);\n if (previous) {\n skill.shadowed = [\n ...previous.shadowed,\n { path: previous.path, source: previous.source, rootKind: previous.rootKind },\n ];\n }\n byName.set(skill.name, skill);\n }\n }\n return applySkillOverrides(\n [...byName.values()].sort((a, b) => a.name.localeCompare(b.name)),\n overrides,\n options.executionOverrides ?? {},\n options.enabled ?? true,\n );\n}\n\nexport function applySkillOverrides(\n skills: readonly Skill[],\n overrides: Readonly<Record<string, SkillActivation>>,\n executionOverrides: Readonly<Record<string, SkillExecution>> = {},\n enabled = true,\n): Skill[] {\n return skills.map((skill) => ({\n ...skill,\n activation: enabled ? (overrides[skill.name] ?? skill.activation ?? 'manual') : 'off',\n execution: executionOverrides[skill.name] ?? skill.execution ?? 'inherit',\n }));\n}\n\nexport function loadSkillBody(skill: Skill): LoadedSkillBody {\n if (!skill.valid) throw new Error(`Skill \"${skill.name}\" is invalid.`);\n // Asked again here, not only at discovery: the directory may have become a link since (#579).\n if (skill.source === 'project' && reachesUncPath(skill.path)) {\n throw new Error(`Skill \"${skill.name}\" is on a network (UNC) path and is not loaded.`);\n }\n const canonicalRoot = realpathSync(skill.rootPath);\n const canonicalEntry = realpathSync(skill.path);\n if (!isInside(canonicalRoot, canonicalEntry)) {\n throw new Error(`Skill entrypoint escapes its root: ${skill.path}`);\n }\n const current = statSync(canonicalEntry);\n if (current.size !== skill.entryByteSize || current.mtimeMs !== skill.entryMtimeMs) {\n throw new Error(`Skill \"${skill.name}\" changed after discovery; reload skills before use.`);\n }\n const buffer = readFileSync(canonicalEntry);\n if (buffer.includes(0)) {\n throw new Error(`Skill \"${skill.name}\" contains binary content.`);\n }\n const raw = buffer.toString('utf8');\n const { body } = parseFrontmatter(raw);\n const byteSize = Buffer.byteLength(body);\n if (byteSize > MAX_SKILL_BODY_BYTES) {\n throw new Error(`Skill body exceeds ${MAX_SKILL_BODY_BYTES} bytes.`);\n }\n return {\n body,\n digest: createHash('sha256').update(body).digest('hex'),\n byteSize,\n };\n}\n\nexport interface SkillListingResult {\n text: string;\n budgetChars: number;\n visibleCount: number;\n included: string[];\n omitted: string[];\n collapsed: string[];\n charCount: number;\n}\n\n/**\n * Characters the skill listing may occupy in the system prompt.\n *\n * Lives here so the listing shipped to the model and the /skills diagnostics\n * that describe it cannot drift: both call this, neither re-derives the share\n * or the cap.\n */\nexport function skillListingBudgetChars(contextWindow: number): number {\n return Math.min(8000, Math.max(512, Math.floor(contextWindow * 0.08)));\n}\n\nexport function buildSkillListing(\n skills: readonly Skill[],\n budgetChars = 8000,\n): SkillListingResult {\n const visible = skills.filter(\n (skill) => skill.valid && (skill.activation === 'auto' || skill.activation === 'name-only'),\n );\n if (visible.length === 0) {\n return {\n text: '',\n budgetChars,\n visibleCount: 0,\n included: [],\n omitted: [],\n collapsed: [],\n charCount: 0,\n };\n }\n\n const sorted = [...visible].sort(\n (a, b) => b.invocationCount - a.invocationCount || a.name.localeCompare(b.name),\n );\n const lines = [\n '## Available skills',\n 'Use InvokeSkill when a request matches a description. A user can force exact use with `$skill-name`.',\n ];\n let remainingBudget = budgetChars - lines.join('\\n').length;\n const includedNames: string[] = [];\n const collapsedNames = new Set<string>();\n\n let included = 0;\n for (const skill of sorted) {\n if (skill.activation === 'name-only') {\n const bare = `- **${skill.name}**`;\n if (bare.length > remainingBudget) break;\n lines.push(bare);\n remainingBudget -= bare.length + 1;\n included++;\n includedNames.push(skill.name);\n collapsedNames.add(skill.name);\n continue;\n }\n const entry = `- **${skill.name}**: ${skill.description}`;\n const trigger = skill.whenToUse ? `\\n when: ${skill.whenToUse}` : '';\n const full = `${entry}${trigger}`;\n if (full.length > remainingBudget) {\n const bare = `- **${skill.name}**`;\n if (bare.length <= remainingBudget) {\n lines.push(bare);\n included++;\n includedNames.push(skill.name);\n collapsedNames.add(skill.name);\n }\n break;\n }\n lines.push(full);\n remainingBudget -= full.length + 1;\n included++;\n includedNames.push(skill.name);\n }\n let omitted = sorted.length - included;\n if (omitted > 0) {\n let warning = `- ${omitted} additional skill${omitted === 1 ? ' was' : 's were'} omitted from this prompt budget. Use /skills to inspect the full catalog.`;\n while (warning.length > remainingBudget && lines.length > 2) {\n const removed = lines.pop();\n if (!removed) break;\n remainingBudget += removed.length + 1;\n included--;\n const removedName = includedNames.pop();\n if (removedName) collapsedNames.delete(removedName);\n omitted = sorted.length - included;\n warning = `- ${omitted} additional skill${omitted === 1 ? ' was' : 's were'} omitted from this prompt budget. Use /skills to inspect the full catalog.`;\n }\n if (warning.length <= remainingBudget) lines.push(warning);\n }\n const text = lines.join('\\n');\n const includedSet = new Set(includedNames);\n return {\n text,\n budgetChars,\n visibleCount: sorted.length,\n included: includedNames,\n omitted: sorted.filter((skill) => !includedSet.has(skill.name)).map((skill) => skill.name),\n collapsed: includedNames.filter((name) => collapsedNames.has(name)),\n charCount: text.length,\n };\n}\n\nexport function generateSkillListing(skills: readonly Skill[], budgetChars = 8000): string {\n return buildSkillListing(skills, budgetChars).text;\n}\n\nexport function explicitSkillMentions(prompt: string, skills: readonly Skill[]): string[] {\n const available = new Set(skills.map((skill) => skill.name));\n const mentions: string[] = [];\n // A `$` that follows a path separator, a dot or a mention's `@` is part of a file or command name\n // (`@$deploy.md`, `docs/$deploy/`, `/$deploy`), not a request for a skill.\n const pattern = /(?<![A-Za-z0-9_\\-/\\\\@.])\\$([a-z0-9]+(?:-[a-z0-9]+)*)(?![A-Za-z0-9_-])/g;\n for (const match of prompt.matchAll(pattern)) {\n const name = match[1];\n if (available.has(name) && !mentions.includes(name)) mentions.push(name);\n }\n return mentions;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
runHostReview,
|
|
6
6
|
toElicitationFields,
|
|
7
7
|
validateElicitationContent
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ENLB7NYV.js";
|
|
9
9
|
import {
|
|
10
10
|
SessionRuntime,
|
|
11
11
|
buildAgentCompletionMessage,
|
|
@@ -20,64 +20,85 @@ import {
|
|
|
20
20
|
normalizePersistedTodos,
|
|
21
21
|
planApprovalFromUserQuestionResponse,
|
|
22
22
|
planStopDecision,
|
|
23
|
+
seedShellIds,
|
|
23
24
|
separateInlineReasoning,
|
|
24
25
|
takeAgentCompletionBatch,
|
|
25
26
|
uniqueAgentDisplayName
|
|
26
|
-
} from "./chunk-
|
|
27
|
-
import {
|
|
28
|
-
consoleMcpDiagnosticSink,
|
|
29
|
-
resolveMcpServerList
|
|
30
|
-
} from "./chunk-Y2VHN7TC.js";
|
|
27
|
+
} from "./chunk-KDNWMKXV.js";
|
|
31
28
|
import {
|
|
32
29
|
TRUSTED_SETTINGS_LOCATION,
|
|
30
|
+
collectSkippedInstructionNotices,
|
|
31
|
+
collectSkippedReviewNotices,
|
|
33
32
|
compactionGate,
|
|
34
33
|
createBuiltinCommandRegistry,
|
|
35
34
|
estimateUsageCost,
|
|
35
|
+
formatGoalStatus,
|
|
36
36
|
getPackageVersion,
|
|
37
|
+
goalKickoffPrompt,
|
|
37
38
|
planWasLost,
|
|
38
39
|
resolveContextLimit,
|
|
39
40
|
resolvePermissionMode,
|
|
40
41
|
usageAtGate,
|
|
41
42
|
usagePressureTokens
|
|
42
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-FPR7SKIE.js";
|
|
44
|
+
import {
|
|
45
|
+
onAbort,
|
|
46
|
+
seedObservationLedger,
|
|
47
|
+
throwIfAborted
|
|
48
|
+
} from "./chunk-N2G4Q7ME.js";
|
|
43
49
|
import {
|
|
44
50
|
formatIgnoredWorkspaceSandboxKey,
|
|
45
51
|
ignoredWorkspaceSandboxKeys,
|
|
52
|
+
isUserSettingsFile,
|
|
46
53
|
loadSettingsFile,
|
|
47
54
|
settingsLayerPaths,
|
|
48
55
|
workspaceLayerThatEnabledSandbox
|
|
49
|
-
} from "./chunk-
|
|
50
|
-
import {
|
|
51
|
-
onAbort,
|
|
52
|
-
seedObservationLedger,
|
|
53
|
-
throwIfAborted
|
|
54
|
-
} from "./chunk-J62VZYOB.js";
|
|
56
|
+
} from "./chunk-UCFJ43OS.js";
|
|
55
57
|
import {
|
|
58
|
+
collectSkippedCommandNotices,
|
|
56
59
|
commandEnforcementContext,
|
|
57
60
|
discoverCommands,
|
|
58
61
|
parseSlashInput,
|
|
59
62
|
resolveCommandBody
|
|
60
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-AJZWLKLQ.js";
|
|
64
|
+
import {
|
|
65
|
+
consoleMcpDiagnosticSink,
|
|
66
|
+
resolveMcpServerList
|
|
67
|
+
} from "./chunk-MEOB2DZA.js";
|
|
68
|
+
import {
|
|
69
|
+
isProcessAlive
|
|
70
|
+
} from "./chunk-32WBCUAN.js";
|
|
61
71
|
import {
|
|
62
72
|
buildChildEnv
|
|
63
73
|
} from "./chunk-XHAO3K7I.js";
|
|
64
74
|
import {
|
|
65
75
|
collectDeclaredDirectories,
|
|
66
76
|
partitionProjectDirectories
|
|
67
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-4DKHLZRI.js";
|
|
68
78
|
import {
|
|
69
79
|
getPrimaryArg,
|
|
70
80
|
toolFailure,
|
|
71
81
|
toolResultErrorMessage,
|
|
72
82
|
toolSuccess
|
|
73
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-YIL6HTJX.js";
|
|
74
84
|
import {
|
|
75
85
|
partitionProjectAllowRules
|
|
76
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-MV5PQNIA.js";
|
|
87
|
+
import {
|
|
88
|
+
LEGACY_BASE_URL_ID,
|
|
89
|
+
describeApiKeyDeclaration,
|
|
90
|
+
describeDroppedOverride,
|
|
91
|
+
describeOrigin,
|
|
92
|
+
describeReservedProvider,
|
|
93
|
+
describeUnaffectedSelection,
|
|
94
|
+
describeWithheldSelection,
|
|
95
|
+
providerTrustCommand
|
|
96
|
+
} from "./chunk-B5FC3MYZ.js";
|
|
77
97
|
import {
|
|
78
98
|
collectDeclaredHooks,
|
|
79
|
-
partitionProjectHooks
|
|
80
|
-
|
|
99
|
+
partitionProjectHooks,
|
|
100
|
+
renderUntrustedText
|
|
101
|
+
} from "./chunk-WV3O5PGX.js";
|
|
81
102
|
import {
|
|
82
103
|
resolveBookHome
|
|
83
104
|
} from "./chunk-ZPSZZUWF.js";
|
|
@@ -87,10 +108,13 @@ import {
|
|
|
87
108
|
closeSync,
|
|
88
109
|
mkdirSync,
|
|
89
110
|
openSync,
|
|
111
|
+
readdirSync,
|
|
90
112
|
readFileSync,
|
|
91
113
|
renameSync,
|
|
92
114
|
rmSync,
|
|
93
115
|
statfsSync,
|
|
116
|
+
statSync,
|
|
117
|
+
unlinkSync,
|
|
94
118
|
writeSync
|
|
95
119
|
} from "fs";
|
|
96
120
|
import { join } from "path";
|
|
@@ -140,6 +164,43 @@ function readRunStatus(sessionId, home = resolveBookHome()) {
|
|
|
140
164
|
return void 0;
|
|
141
165
|
}
|
|
142
166
|
}
|
|
167
|
+
var RUN_RECORD_NAME = /\.json$/;
|
|
168
|
+
var RUN_TEMP_NAME = /\.json\..+\.tmp$/;
|
|
169
|
+
function recordsLiveRun(path) {
|
|
170
|
+
try {
|
|
171
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
172
|
+
if (!parsed || typeof parsed !== "object") return false;
|
|
173
|
+
const record = parsed;
|
|
174
|
+
if (record.terminal || record.crash) return false;
|
|
175
|
+
const pid = record.pid;
|
|
176
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) return false;
|
|
177
|
+
return isProcessAlive(pid);
|
|
178
|
+
} catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function cleanupRunStatus(days, home = resolveBookHome(), now = Date.now()) {
|
|
183
|
+
const cutoff = now - Math.max(1, days) * 864e5;
|
|
184
|
+
const directory = runStatusDir(home);
|
|
185
|
+
let removed = 0;
|
|
186
|
+
try {
|
|
187
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
188
|
+
if (!entry.isFile()) continue;
|
|
189
|
+
const isRecord = RUN_RECORD_NAME.test(entry.name);
|
|
190
|
+
if (!isRecord && !RUN_TEMP_NAME.test(entry.name)) continue;
|
|
191
|
+
const path = join(directory, entry.name);
|
|
192
|
+
try {
|
|
193
|
+
if (statSync(path).mtimeMs >= cutoff) continue;
|
|
194
|
+
if (isRecord && recordsLiveRun(path)) continue;
|
|
195
|
+
unlinkSync(path);
|
|
196
|
+
removed++;
|
|
197
|
+
} catch {
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} catch {
|
|
201
|
+
}
|
|
202
|
+
return removed;
|
|
203
|
+
}
|
|
143
204
|
var RunStatusWriter = class {
|
|
144
205
|
seed;
|
|
145
206
|
last;
|
|
@@ -274,6 +335,10 @@ async function performPrintReview(effect, env, command) {
|
|
|
274
335
|
// Every reviewer, lens and verifier agent is spawned under the host's run,
|
|
275
336
|
// so the whole pipeline is billed and budgeted as one root.
|
|
276
337
|
runner: reviewRunnerFor(env.agents.manager(), {
|
|
338
|
+
// The stored session the run belongs to, as the TUI passes its own. Without it
|
|
339
|
+
// each agent's tool-use records carry a made-up `agent:<id>` session id that
|
|
340
|
+
// matches no session file, and `book tool-stats` counts every one separately.
|
|
341
|
+
parentSessionId: env.agents.runContext.sessionId,
|
|
277
342
|
rootRunId: env.agents.runContext.rootRunId,
|
|
278
343
|
parentRunId: env.agents.runContext.runId
|
|
279
344
|
})
|
|
@@ -290,12 +355,40 @@ function createPrintEffectRegistry() {
|
|
|
290
355
|
return new PrintEffectRegistry().register("send-prompt", (effect) => ({
|
|
291
356
|
kind: "prompt",
|
|
292
357
|
prompt: effect.prompt,
|
|
293
|
-
commandContext: effect.context
|
|
358
|
+
commandContext: effect.context,
|
|
359
|
+
projectCommand: effect.projectCommand
|
|
294
360
|
})).register("local-message", (effect, _env, command) => {
|
|
295
361
|
if (effect.isError) throw new PrintCommandUsageError(command, effect.content);
|
|
296
362
|
return { kind: "handled", command, output: effect.content };
|
|
297
|
-
}).register("review", performPrintReview)
|
|
363
|
+
}).register("review", performPrintReview).register("set-goal", (effect, env, command) => {
|
|
364
|
+
if (!env.goal) throw new UnsupportedPrintCommandError(command, GOAL_REFUSAL);
|
|
365
|
+
env.goal.set(effect.condition);
|
|
366
|
+
const kickoff = goalKickoffPrompt(effect.condition);
|
|
367
|
+
return {
|
|
368
|
+
kind: "prompt",
|
|
369
|
+
prompt: kickoff,
|
|
370
|
+
commandContext: {
|
|
371
|
+
command: {
|
|
372
|
+
name: "goal",
|
|
373
|
+
description: "Set a goal Book checks before stopping",
|
|
374
|
+
body: kickoff,
|
|
375
|
+
source: "project"
|
|
376
|
+
},
|
|
377
|
+
resolvedBody: kickoff
|
|
378
|
+
},
|
|
379
|
+
sessionNameSource: effect.condition
|
|
380
|
+
};
|
|
381
|
+
}).register("clear-goal", (_effect, env, command) => {
|
|
382
|
+
if (!env.goal) throw new UnsupportedPrintCommandError(command, GOAL_REFUSAL);
|
|
383
|
+
const cleared = env.goal.clear();
|
|
384
|
+
return {
|
|
385
|
+
kind: "handled",
|
|
386
|
+
command,
|
|
387
|
+
output: cleared ? formatGoalStatus({ state: "cleared", condition: cleared.condition }) : "No goal set"
|
|
388
|
+
};
|
|
389
|
+
});
|
|
298
390
|
}
|
|
391
|
+
var GOAL_REFUSAL = "\u2715 /goal needs a host that checks goals; this one does not.";
|
|
299
392
|
function printBuiltinContext(env, commands) {
|
|
300
393
|
return {
|
|
301
394
|
workspace: env.config.workspace,
|
|
@@ -308,6 +401,7 @@ function printBuiltinContext(env, commands) {
|
|
|
308
401
|
runtimeConfig: env.config,
|
|
309
402
|
mode: env.mode,
|
|
310
403
|
usage: null,
|
|
404
|
+
activeGoal: env.goal?.get(),
|
|
311
405
|
turnDurationMs: 0,
|
|
312
406
|
contextHistory: [],
|
|
313
407
|
compactBoundaries: [],
|
|
@@ -324,6 +418,9 @@ function supportedCommandHelp(builtins, commands) {
|
|
|
324
418
|
const lines = ["Commands supported in print mode:"];
|
|
325
419
|
for (const definition of builtins.getDefinitions()) {
|
|
326
420
|
if (definition.nonInteractive) lines.push(` /${definition.name} \u2014 ${definition.description}`);
|
|
421
|
+
for (const subcommand of definition.nonInteractiveSubcommands ?? []) {
|
|
422
|
+
lines.push(` /${definition.name} ${subcommand} \u2014 ${definition.description}`);
|
|
423
|
+
}
|
|
327
424
|
}
|
|
328
425
|
const custom = commands.map((command) => `/${command.name}`);
|
|
329
426
|
lines.push(
|
|
@@ -352,7 +449,9 @@ async function resolvePrintCommand(input, env, deps = {}) {
|
|
|
352
449
|
const context = printBuiltinContext(env, commands);
|
|
353
450
|
const resolved = builtins.resolve(parsed.name, context);
|
|
354
451
|
if (resolved && !resolved.definition.tuiOnly) {
|
|
355
|
-
|
|
452
|
+
const subcommand = parsed.rawArguments.trim().split(/\s+/)[0] ?? "";
|
|
453
|
+
const allowedHere = resolved.definition.nonInteractive || (resolved.definition.nonInteractiveSubcommands?.includes(subcommand) ?? false);
|
|
454
|
+
if (!allowedHere) {
|
|
356
455
|
throw unsupported(
|
|
357
456
|
parsed.name,
|
|
358
457
|
"needs an interactive session: it changes host state instead of producing a prompt.",
|
|
@@ -381,7 +480,8 @@ async function resolvePrintCommand(input, env, deps = {}) {
|
|
|
381
480
|
commands
|
|
382
481
|
);
|
|
383
482
|
}
|
|
384
|
-
|
|
483
|
+
if (dispatch.kind === "handled") return { ...dispatch, command: parsed.name };
|
|
484
|
+
return dispatch.kind === "prompt" ? { ...dispatch, sessionNameSource: dispatch.sessionNameSource ?? input.trim() } : dispatch;
|
|
385
485
|
}
|
|
386
486
|
const custom = commands.find((command) => command.name === parsed.name);
|
|
387
487
|
if (!custom) return { kind: "passthrough", prompt: input };
|
|
@@ -400,7 +500,9 @@ async function resolvePrintCommand(input, env, deps = {}) {
|
|
|
400
500
|
kind: "prompt",
|
|
401
501
|
prompt: body,
|
|
402
502
|
commandContext: commandEnforcementContext(custom, body),
|
|
403
|
-
|
|
503
|
+
sessionNameSource: input.trim(),
|
|
504
|
+
shellErrors,
|
|
505
|
+
projectCommand: custom.source === "project"
|
|
404
506
|
};
|
|
405
507
|
}
|
|
406
508
|
|
|
@@ -584,7 +686,7 @@ function createReaderFlush(stdout, options = {}) {
|
|
|
584
686
|
function carriedCostUsd(usage, models) {
|
|
585
687
|
let worst = null;
|
|
586
688
|
for (const model of models) {
|
|
587
|
-
const quote = estimateUsageCost(model, usage);
|
|
689
|
+
const quote = estimateUsageCost(model, usage, "pool");
|
|
588
690
|
if (quote.status !== "known") return null;
|
|
589
691
|
worst = worst === null ? quote.costUsd : Math.max(worst, quote.costUsd);
|
|
590
692
|
}
|
|
@@ -644,12 +746,7 @@ async function runHeadless(config, registry, opts) {
|
|
|
644
746
|
let sessionDisposed = false;
|
|
645
747
|
let startedSessionId;
|
|
646
748
|
const agentSession = new AgentSession({
|
|
647
|
-
|
|
648
|
-
// records compaction summarized out of the context history, so prefer it
|
|
649
|
-
// when a resume supplies both.
|
|
650
|
-
runtime: new SessionRuntime({
|
|
651
|
-
history: opts.transcript?.length ? opts.transcript : opts.history
|
|
652
|
-
})
|
|
749
|
+
runtime: new SessionRuntime()
|
|
653
750
|
});
|
|
654
751
|
const disposeSession = () => {
|
|
655
752
|
if (sessionDisposed) return;
|
|
@@ -659,12 +756,14 @@ async function runHeadless(config, registry, opts) {
|
|
|
659
756
|
const runtime = agentSession.getRuntime();
|
|
660
757
|
runtime.todos.push(...normalizePersistedTodos(opts.plan?.todos));
|
|
661
758
|
if (opts.plan?.tasks?.length) runtime.tasks.push(...opts.plan.tasks);
|
|
759
|
+
agentSession.restoreGoal(opts.goal);
|
|
662
760
|
runtime.planUnrestored = planWasLost({
|
|
663
761
|
planRecordExisted: opts.plan !== void 0,
|
|
664
762
|
priorMessages: opts.history.length,
|
|
665
763
|
todos: runtime.todos.length,
|
|
666
764
|
tasks: runtime.tasks.length
|
|
667
765
|
});
|
|
766
|
+
seedShellIds(runtime.backgroundShells, opts.transcript ?? opts.history, opts.history);
|
|
668
767
|
try {
|
|
669
768
|
if (opts.outputFormat === "stream-json") {
|
|
670
769
|
emit({ type: "system", model: config.model, cwd: config.workspace });
|
|
@@ -979,7 +1078,7 @@ async function runHeadless(config, registry, opts) {
|
|
|
979
1078
|
}
|
|
980
1079
|
}
|
|
981
1080
|
});
|
|
982
|
-
const runParentTurn = async (prompt, displayMessage, userMessage, runContext, commandContext) => {
|
|
1081
|
+
const runParentTurn = async (prompt, displayMessage, userMessage, runContext, commandContext, typedText) => {
|
|
983
1082
|
eventState.errorReported = false;
|
|
984
1083
|
let runOutcome;
|
|
985
1084
|
finalRunOpeningId = userMessage.id;
|
|
@@ -1018,6 +1117,8 @@ async function runHeadless(config, registry, opts) {
|
|
|
1018
1117
|
parentSessionId: runtimeSessionId,
|
|
1019
1118
|
runContext,
|
|
1020
1119
|
runtime,
|
|
1120
|
+
// Only what the user typed invokes a skill by `$name`, as in the TUI.
|
|
1121
|
+
typedText,
|
|
1021
1122
|
// Command frontmatter enforcement, exactly as the TUI passes it.
|
|
1022
1123
|
allowedTools: commandContext?.allowedTools,
|
|
1023
1124
|
modelOverride: commandContext?.modelOverride,
|
|
@@ -1076,8 +1177,19 @@ async function runHeadless(config, registry, opts) {
|
|
|
1076
1177
|
hookEventSink: createHookEventHandler(opts, emit)
|
|
1077
1178
|
}),
|
|
1078
1179
|
runContext
|
|
1180
|
+
},
|
|
1181
|
+
goal: {
|
|
1182
|
+
get: () => agentSession.getGoal(),
|
|
1183
|
+
set: (condition) => {
|
|
1184
|
+
agentSession.setGoal(condition, goalTarget());
|
|
1185
|
+
},
|
|
1186
|
+
clear: () => agentSession.clearGoal(goalTarget())
|
|
1079
1187
|
}
|
|
1080
1188
|
});
|
|
1189
|
+
const goalTarget = () => ({
|
|
1190
|
+
sessionId,
|
|
1191
|
+
timelineStore: store && sessionId ? store : void 0
|
|
1192
|
+
});
|
|
1081
1193
|
const commandResults = [];
|
|
1082
1194
|
let commandUsage = null;
|
|
1083
1195
|
const prompts = [];
|
|
@@ -1251,16 +1363,29 @@ async function runHeadless(config, registry, opts) {
|
|
|
1251
1363
|
displayMessage: prompt,
|
|
1252
1364
|
userMessage,
|
|
1253
1365
|
sessionName,
|
|
1366
|
+
sessionNameSource: dispatch.kind === "prompt" ? dispatch.sessionNameSource : void 0,
|
|
1254
1367
|
timelineStore: store && sessionId ? store : void 0,
|
|
1255
1368
|
expandShellInput: false,
|
|
1369
|
+
projectCommand: dispatch.kind === "prompt" ? dispatch.projectCommand : void 0,
|
|
1256
1370
|
runtime,
|
|
1257
1371
|
signal: runSignal
|
|
1258
1372
|
});
|
|
1373
|
+
for (const notice of recorded.mentionNotices) process.stderr.write(`${notice}
|
|
1374
|
+
`);
|
|
1259
1375
|
sessionName = recorded.sessionName;
|
|
1260
1376
|
const contextMessage = recorded.contextMessage;
|
|
1261
1377
|
transcript.push(userMessage);
|
|
1262
1378
|
rootContexts.set(runContext.rootRunId, runContext);
|
|
1263
|
-
await runParentTurn(
|
|
1379
|
+
await runParentTurn(
|
|
1380
|
+
contextMessage,
|
|
1381
|
+
prompt,
|
|
1382
|
+
userMessage,
|
|
1383
|
+
runContext,
|
|
1384
|
+
commandContext,
|
|
1385
|
+
// What the user typed is the line they submitted, whatever it resolved to: a command's
|
|
1386
|
+
// body or a built-in command's prompt is not.
|
|
1387
|
+
submitted
|
|
1388
|
+
);
|
|
1264
1389
|
const spentSoFar = runtime.runAccounting.snapshotRoot(runContext.rootRunId);
|
|
1265
1390
|
carriedSpend = {
|
|
1266
1391
|
usage: spentSoFar.inclusiveUsage,
|
|
@@ -1324,6 +1449,9 @@ async function runHeadless(config, registry, opts) {
|
|
|
1324
1449
|
displayMessage,
|
|
1325
1450
|
contextMessage: userMessage.contextContent,
|
|
1326
1451
|
userMessage,
|
|
1452
|
+
// The local name is deliberately not reassigned from the result: a
|
|
1453
|
+
// notification never names the session (#446).
|
|
1454
|
+
sessionName,
|
|
1327
1455
|
timelineStore: store && sessionId ? store : void 0,
|
|
1328
1456
|
expandShellInput: false,
|
|
1329
1457
|
runtime,
|
|
@@ -1491,6 +1619,17 @@ function emitAgentEvent(event, opts, emit, state) {
|
|
|
1491
1619
|
else console.warn(event.message);
|
|
1492
1620
|
return;
|
|
1493
1621
|
}
|
|
1622
|
+
if (event.type === "goal_status") {
|
|
1623
|
+
const endsRunFailed = event.event.state === "failed" || event.event.state === "paused";
|
|
1624
|
+
if (opts.outputFormat === "stream-json") emit({ type: "goal_status", ...event.event });
|
|
1625
|
+
else if (opts.outputFormat === "text" && opts.runSource !== "sdk" && (opts.quiet !== true || endsRunFailed)) {
|
|
1626
|
+
process.stderr.write(
|
|
1627
|
+
`goal: ${progressLine(formatGoalStatus(event.event), PROGRESS_NOTICE_MAX)}
|
|
1628
|
+
`
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1494
1633
|
if (event.type === "agent_notice") {
|
|
1495
1634
|
if (opts.outputFormat === "stream-json") {
|
|
1496
1635
|
emit({ type: "agent_notice", agentId: event.agentId, message: event.message });
|
|
@@ -1657,8 +1796,8 @@ function emitCompactBoundary(outputFormat, emit, result) {
|
|
|
1657
1796
|
});
|
|
1658
1797
|
}
|
|
1659
1798
|
async function generatePromptSuggestions(config, _registry, history, signal, resolveAttachment) {
|
|
1660
|
-
const { chatCompletionStream } = await import("./openai-compatible-
|
|
1661
|
-
const { buildMessages } = await import("./context-
|
|
1799
|
+
const { chatCompletionStream } = await import("./openai-compatible-IPUNBJ53.js");
|
|
1800
|
+
const { buildMessages } = await import("./context-C3RAP6K5.js");
|
|
1662
1801
|
const suggestionMessages = await buildMessages(
|
|
1663
1802
|
config,
|
|
1664
1803
|
[
|
|
@@ -2267,10 +2406,51 @@ async function disconnectMcpServers(connections) {
|
|
|
2267
2406
|
|
|
2268
2407
|
// src/project-approval-notices.ts
|
|
2269
2408
|
import { join as join2 } from "path";
|
|
2409
|
+
function collectWithheldProviderNotices(gate, workspace) {
|
|
2410
|
+
const notices = [];
|
|
2411
|
+
const approveCommand = (id) => {
|
|
2412
|
+
const { command, note } = providerTrustCommand(workspace, id);
|
|
2413
|
+
return `\`${command}\`${note}`;
|
|
2414
|
+
};
|
|
2415
|
+
for (const dropped of gate.droppedOverrides) {
|
|
2416
|
+
notices.push(`\u26A0 ${describeDroppedOverride(dropped)}`);
|
|
2417
|
+
}
|
|
2418
|
+
for (const entry of gate.partition.reserved) {
|
|
2419
|
+
notices.push(`\u26A0 ${describeReservedProvider(entry)}`);
|
|
2420
|
+
}
|
|
2421
|
+
const pendingIds = new Set(gate.partition.pending.map((entry) => entry.id));
|
|
2422
|
+
for (const entry of gate.partition.pending) {
|
|
2423
|
+
const id = renderUntrustedText(entry.id, 64);
|
|
2424
|
+
const origin = entry.declaration.baseURL ?? entry.declaration.baseUrl;
|
|
2425
|
+
notices.push(
|
|
2426
|
+
`\u26A0 Ignoring workspace-declared provider "${id}" (${describeOrigin(origin)}, key: ${describeApiKeyDeclaration(
|
|
2427
|
+
entry.declaration.apiKey,
|
|
2428
|
+
workspace
|
|
2429
|
+
)}) from ${entry.layers.map((layer) => renderUntrustedText(layer)).join(", ")}: it requires approval. Run ${approveCommand(entry.id)} to review and approve it.`
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
for (const selection of gate.withheldSelections) {
|
|
2433
|
+
if (!pendingIds.has(selection.providerId)) continue;
|
|
2434
|
+
notices.push(
|
|
2435
|
+
`\u26A0 ${describeWithheldSelection(selection)} Run ${approveCommand(selection.providerId)} to approve it.`
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2438
|
+
for (const selection of gate.unaffectedSelections) {
|
|
2439
|
+
if (!pendingIds.has(selection.providerId)) continue;
|
|
2440
|
+
notices.push(`\u26A0 ${describeUnaffectedSelection(selection)}`);
|
|
2441
|
+
}
|
|
2442
|
+
if (gate.legacyBaseUrl?.state === "pending") {
|
|
2443
|
+
notices.push(
|
|
2444
|
+
`\u26A0 Ignoring baseUrl "${renderUntrustedText(gate.legacyBaseUrl.baseUrl)}" from ${LEGACY_BASE_URL_ID}: it would receive BOOK_API_KEY, so it requires approval. Run ${approveCommand(LEGACY_BASE_URL_ID)} to review and approve it.`
|
|
2445
|
+
);
|
|
2446
|
+
}
|
|
2447
|
+
return notices;
|
|
2448
|
+
}
|
|
2270
2449
|
function collectWithheldProjectNotices(input) {
|
|
2271
|
-
|
|
2450
|
+
const providerNotices = input.providerGate ? collectWithheldProviderNotices(input.providerGate, input.workspace) : [];
|
|
2451
|
+
if (!input.settingsEnabled) return providerNotices;
|
|
2272
2452
|
const projectPath = join2(input.workspace, ".book", "settings.json");
|
|
2273
|
-
const projectSettings = loadSettingsFile(projectPath);
|
|
2453
|
+
const projectSettings = isUserSettingsFile(projectPath) ? null : loadSettingsFile(projectPath);
|
|
2274
2454
|
const notices = [];
|
|
2275
2455
|
const allow = partitionProjectAllowRules(
|
|
2276
2456
|
projectSettings?.permissions?.allow ?? [],
|
|
@@ -2331,16 +2511,27 @@ function collectWithheldProjectNotices(input) {
|
|
|
2331
2511
|
`\u26A0 ${activation} declared sandbox.enabled=true, so sandbox.autoAllowBashIfSandboxed is false for this session: no Bash command is auto-approved. ${TRUSTED_SETTINGS_LOCATION}`
|
|
2332
2512
|
);
|
|
2333
2513
|
}
|
|
2334
|
-
return notices;
|
|
2514
|
+
return [...notices, ...providerNotices];
|
|
2515
|
+
}
|
|
2516
|
+
function collectSkippedProjectFileNotices(workspace) {
|
|
2517
|
+
return [
|
|
2518
|
+
...collectSkippedInstructionNotices(workspace),
|
|
2519
|
+
...collectSkippedReviewNotices(workspace),
|
|
2520
|
+
...collectSkippedCommandNotices(workspace)
|
|
2521
|
+
];
|
|
2335
2522
|
}
|
|
2336
2523
|
|
|
2337
2524
|
export {
|
|
2525
|
+
runStatusPath,
|
|
2338
2526
|
readRunStatus,
|
|
2527
|
+
cleanupRunStatus,
|
|
2339
2528
|
isReaderGoneError,
|
|
2340
2529
|
runHeadless,
|
|
2341
2530
|
buildMcpToolDefinitions,
|
|
2342
2531
|
connectMcpServers,
|
|
2343
2532
|
disconnectMcpServers,
|
|
2344
|
-
|
|
2533
|
+
collectWithheldProviderNotices,
|
|
2534
|
+
collectWithheldProjectNotices,
|
|
2535
|
+
collectSkippedProjectFileNotices
|
|
2345
2536
|
};
|
|
2346
|
-
//# sourceMappingURL=chunk-
|
|
2537
|
+
//# sourceMappingURL=chunk-E5WLQSKA.js.map
|