/** Cap on a cwd path length (defensive — a row/path label bound; a real path is far shorter). */ export declare const MAX_CWD_CHARS = 4096; /** Is this a structurally-valid absolute host path? Rejects: non-strings, relative paths (TOC review #12 — a * relative cwd would resolve against the SERVICE process cwd, not the user's project = silent wrong-dir), empty, * over-long, and NUL-byte injection. NOT an existence check (the env surfaces a missing dir at first tool use). * Defense-in-depth (double-review LOW): `path.isAbsolute` is SYNTACTIC — `/a/../../etc` is "absolute" yet contains * `..` traversal that the host env would `path.resolve` away. Single-user host lane = the caller's own machine (no * cross-tenant escape), but we reject any path with a `..` segment so the honored cwd is the literal path sent. * * 🔴 **接缝登记(7.74.0 / core 7.17.0 [ref],今日无可达分歧 —— 登记的是「以后会分歧」)**:这条判断回答的是 * 「引擎眼里这条 cwd 算不算绝对」,而引擎自本版起按**树的家族**判(`isAbsoluteForFamily(pathFamilyOf({root,cwd}), p)`, * 家族从 root/cwd 的**拼法**读,**从不**读 `process.platform`)。本函数用的是 Node 的宿主口径,两者: * · **posix 家族逐字同判**(2026-09-12 实测六形 `/etc/passwd` / `a/b` / `\\host\share\x` / `C:\x` / * `//host/share/x` / `/c/x` 六格全同)⇒ 今天(Linux 宿主 + posix 树,本位又只在单用户 `host` 车道上场) * **零分歧**,不改; * · **win 家族分歧在 `/`-开头但没有盘符的那一类**(`/etc/passwd`、`/c/x`):Node 的 win32 口径说「绝对」, * 引擎说「rooted 但未完全限定」(要拼上基准的盘/共享根才成一条真路径)。⇒ **哪天 `host` 车道要接 win 树, * 先改这里**:把判据换成 core 的 `isAbsoluteForFamily`,并把家族从这条 cwd 自己的拼法取。 * 钉见 `test/task-cwd.test.ts` 的「[ref] 路径家族接缝」格(实测读数,不是推断)。 */ export declare function isValidCwd(cwd: unknown): cwd is string; /** * 词法归一:纯字符串运算,折 `.` / `..` / 重复分隔符,**不碰 fs**。 * `posix.normalize` 把 `..` 在根部截断(`/../x` → `/x`),与「根之上没有东西」的语义一致;尾部分隔符 * 统一剥掉(根 `/` 除外),让同一目标只有一个 key —— 前缀判域(见 {@link dirCoversPath})靠的就是 * key 的唯一性。 * * 🔴 **单点**(S-351 起):此前它的一份私有副本住在 `boot/deferred-sandbox-path-env.ts`(沙箱代理的 * `absolutePath` 词法臂),而写门豁免域与任务根的判域现在读的是同一条律 —— 两份各自归一就是两个 key * 空间,而「豁免域盖没盖住任务根」这种判断在两个 key 空间里可以同时答是和否。 * (core 内部有同形的 `normalizeAbsPathLexically`,但未从包根导出;此处是 Node 标准库的等价运算, * 不是它的抄本——若日后 core 导出,这里应改为直接复用。) */ export declare function normalizeAbsolutePathLexically(p: string): string; /** * **词法**判域:`dir` 是不是 `target` 本身或它的祖先(= `target` ⊆ `dir`,「等于 ∪ 后代」)。 * * 这是 core `assertExemptDirsDoNotCoverRoot` 那条律的本仓同形(亲读安装树 * `dist/core/fs-write-gate-policy.js` → `swallowedFenceRoot` → `isWithin(root, p)`: * 先各自词法归一,再判 `p === root` 或 `p` 以 `root + "/"` 起头)。**两端都只做词法**,不 realpath —— * 写门的构造期本来就没有 I/O(core 同理),承诺 canonical 是承诺一件此刻做不到的事。 * * 段感知由「归一后 + 分隔符前缀」保证:`/a/bc` **不在** `/a/b` 域内。 */ export declare function dirCoversPath(dir: string, target: string): boolean; /** * The deployment-level gate: does THIS deployment honor a caller-supplied `cwd`? TRUE only for the single-user * `host` lane (see module header). All cloud/container lanes + any multi-tenant deployment → FALSE (cwd ignored). */ export declare function cwdHonored(config: { remoteExec?: { provider?: string; }; requirePrincipal?: boolean; }): boolean; /** * S-377 —— 「**工具跑的那台机器**就是本进程这台吗」。回答的是一个**文件系统同一性**问题,不是权限问题: * server 盘上的一条绝对路径(出厂 `SKILLS_DIR` 下某个技能自己的目录)对模型的工具**有没有意义**。 * * · `host`(run-on-this-machine,无容器)⇒ 真; * · `undefined`(in-process 单用户 lane)⇒ 真 —— 该 lane 根本没挂手(core 落 `StubExecutionEnv`), * 路径对谁都不可达,但它在**文件系统同一性**这条轴上确实是同一台机器,判真让规则只剩一条; * · 其余每一条(`k8s` / `e2b` / `ssh` / `adb` / `device` / `local-docker`)⇒ 假:工具的盘在别处, * server 自己的路径在那边**不存在**,声明它等于给模型一条指向不存在文件的线索,还顺带把本机目录 * 布局说了出去。 * * 🔴 **为什么不复用 {@link cwdHonored}**:那一只是**权限**判据(单用户 ∧ host),它的 `requirePrincipal` * 那一半防的是「一个租户的输入把 agent 指向另一个租户的文件」。本谓词判的路径不是调用方给的,是**运维 * 自己烤进镜像**的出厂内容 —— 每个租户拿到的是同一份,没有跨租户面。把租户判据搭进来会让多租户 host * 部署平白失去这条线索,那是**用错轴**(与 `deviceCwdHonored` 拒绝并进 `cwdHonored` 同一条理由)。 */ export declare function toolsRunOnThisHost(config: { remoteExec?: { provider?: string; }; }): boolean; /** * device lane 的**平行**判别式(device-executor-lane-v2 §4.3.3,车A-4)——「员工在自己设备的项目目录 * 里干活」是这条车道的存在理由,所以 caller cwd 必须被尊重。 * * 🔴 **为什么不合并进 {@link cwdHonored}**:两闸语义不同,合并会把 host 的单用户约束**放松**。 * · `cwdHonored` 的 `requirePrincipal !== true` 防的是「一个租户的输入把 agent 指向 **worker 宿主**上 * 另一个租户/运维的目录」—— 那是一台共享机器上的跨租户穿越; * · device lane 上那个穿越面**结构性不存在**:路径落在**发起者自己的设备**上,而设备归属已由 * `device_session` 绑定行(提交期用验证过的 principal 写下)+ 准入链的 owner 谓词验过。所以本闸 * **不要求**单用户 —— 多租户部署里每个员工各连各的设备,正是这条车道的正常形态。 * 合并两者 = 让 host 车道在多租户下也开始尊重 cwd,那是一条真实的超范围面。 * * 消费者:写侧 = `boot/resolve-spec.ts`(**单写者**,与 cwdHonored 同一处);读侧 = * `plugins/remote-env-device.ts` 的工厂(`effectiveDeviceCwd`)。两侧必须同批落 —— 只开写侧会留下一个 * 没有消费者的登记项(这正是 A-1 把它登记进 `PLANNED_LANE_DIVERGENCES` 而不是当场开的理由)。 * * ⚠️ 刻意**不**连带放开 `additionalDirectories`:那一位在 device v1 上诚实缺席(v2 §4.1 capability * projectContext 行:「拆精确字段,device v1 对 unsupported 项显式 false,不打包沿用」)。 */ export declare function deviceCwdHonored(config: { remoteExec?: { provider?: string; }; requirePrincipal?: boolean; }): boolean; /** * [ref]P3a — the OTHER host-semantics lane: provider UNSET = the in-process single-user lane. It has NO shell * hands (core prepare-task: no factory/executionEnv ⇒ StubExecutionEnv), so the perSession cwd/env registries * have no consumer there — but PROCESS-level consumers (hooks commands, the C4 projectContext local read) still * see the engine's own `process.cwd()`/`process.env`. When the shell spawned the engine in the caller's own * dir/env, a caller override is often ALREADY satisfied by that process state, and a per-task "ignored" warn * contradicts it (飞轮双平台观测). Signal-truth split: satisfied ⇒ debug, real mismatch ⇒ warn. True per-session * honoring remains `REMOTE_EXEC=host`. Multi-tenant excluded for the same reason as {@link cwdHonored}. */ export declare function inProcessSingleUserLane(config: { remoteExec?: { provider?: string; }; requirePrincipal?: boolean; }): boolean; /** * [ref](F-1,[ref] 修向 (b')):卡批「不再询问」落盘规则的 **project root** —— 「这次授权是在哪个 * 工作目录里点的」。取值与既有 cwd 语义同源,不新造坐标系: * 1. session 显式注册的 cwd(cwd seam,host lane;与 {@link effectiveHostWorkspace} 第 1 优先级同源) * —— **今天唯一真的会命中的那一臂**;⚠️ 它**不含 lane 判据**,lane 语义完全依赖「`perSessionCwd` * 只在 `cwdHonored` 为真时被写」这条跨文件外部不变量(写侧唯一入口 boot/resolve-spec.ts)。这是 * 刻意的单写者惯用法,不是疏漏:在消费端补第二道闸 = 把一条不变量拆给两个属主(同族消费者 * {@link effectiveHostWorkspace} 形状完全相同)。机器背书 = test/task-cwd.test.ts 的 [ref] 两格。 * 2. 🔴 **前瞻/防御臂,本仓当前装配下零命中**([ref],2026-08-19 合并重扫 partial,存活断言): * in-process 单用户 lane({@link inProcessSingleUserLane})取引擎自身 `process.cwd()`。它读起来像在 * 服务一个真部署形,其实到不了 —— 该 lane 的 `remoteExec` 未设 ⇒ boot/execution-env.ts 六条工厂臂全 * 不命中 ⇒ core 落 `StubExecutionEnv` ⇒ `handsEnabled=false` ⇒ 不挂 Bash ⇒ 未知工具在 agent-loop 走 * `tool.not_found`(**不进审批座**)⇒ 无 `ruleOffers` ⇒ 本函数在规则车道上根本不被调用;同 lane * 第 1 臂也因写侧闸只在 `cwdHonored` 下开而恒空。危害口径按 refuter **降级**:死枝 ≡ 落第 3 臂 * `undefined` ≡ core global 缺省 ≡ [ref] 修前行为,**今天零用户可见伤害**,不是「恒不命中」类缺陷。 * 🚧 **给将来接手的人的红线**:这条 lane 若哪天真接上 hands,root 必须取 `executionEnv.cwd`(core 的 * `taskRootFinal` 就是它),**不是** `process.cwd()` —— 两者在静态 env 装配形下可以完全不同,照现注 * 直接接线会铸出一个真的歪 root。真正的本地开箱形(`CONFIG_PROVIDER=local`)被 config 默认成 * **host** lane,受益的是第 1 臂;本臂不是「[ref] 的本地形受益臂」。 * 3. 其余(远程沙箱 / REMOTE_EXEC=host 未注册 / 多租户)⇒ `undefined`:root 在 server 坐标系里 * 不可知,调用方**不铸 scope**,落 core 的 global 缺省(= [ref] 修前行为,恒不更宽;也绝不铸一个 * 与规则判定时 cwd 不同坐标系的 root —— 那会静默把「不再询问」变成恒不命中)。 * * 🔴 出口 = `path.resolve(原字节)`,**禁 realpath**([ref].F-A,2026-08-19 合并重扫 confirmed high): * core 判定这条规则时喂进 `scopeCoversCwd` 的 cwd = `executionEnv.cwd` = host env 构造里的 * `path.resolve(同一条注册原字节)`(remote-env-host.ts),比较是**纯串**(`pathWithinRoot`,零 * realpath)。初版这里走 realpath(据 core `PersistedAllowRule.scope` JSDoc「root 由构造方 * canonicalize」)——但 JSDoc 说的是义务、实现行才是事实([ref] 宪法):core 自己喂进匹配的 cwd * 恰恰**未** canonicalize,单侧规范化=两坐标系分叉,注册 cwd 含符号链接段时(macOS `/tmp`、 * `~/work→/mnt/...`)落盘规则**永不命中**,「不再询问」恒失效。正解=root 与判定坐标出自**同一条 * 串、同一种规范化**;将来 core 若把判定面改 canonicalize,这里必须同批跟(端到端钉在 * test/task-cwd.test.ts 的 [ref].F-A 格,靠真 `scopeCoversCwd` 咬住两侧任何一侧的单独漂移)。 * `path.resolve` 不抛 ⇒ 初版的 realpath 失败 F 类兜底臂(`rule-scope-root-unresolvable`)随之退役 * (census 行同批销,fail-open.ts)。 */ export declare function cardRuleScopeRoot(registeredCwd: string | undefined, config: { remoteExec?: { provider?: string; }; requirePrincipal?: boolean; }, cwd?: () => string): string | undefined; /** Is a requested cwd ALREADY the engine process's working dir? realpath BOTH sides (macOS `/tmp` → * `/private/tmp`-class symlinks); either side failing to resolve ⇒ treated as a mismatch (warn — never a * false downgrade). `realpath`/`cwd` are parameters for testability; production passes `fs.realpathSync`. */ export declare function satisfiedByProcessCwd(requested: string, realpath: (p: string) => string, cwd?: () => string): boolean; /** How many requested shellEnv entries the engine process env does NOT already carry (value-exact compare). * 0 ⇒ satisfied by the inherited process state (debug, not "ignored"). Callers must log only this COUNT — * never env values (secret-class), and not key names either (a name can itself carry sensitive semantics). */ export declare function shellEnvMismatchCount(requested: Record, procEnv: Record): number; /** Cap on the number of `--add-dir` entries a caller may attach (bounds a pathological allowlist blast). */ export declare const MAX_ADDITIONAL_DIRS = 64; /** * [ref] (CC `--add-dir` parity): validate an untrusted `body.additionalDirectories` — extra host dirs the * FILE tools may access beyond the containment root (core canonicalizes each into its allowlist + lists them in the * `# Environment` block). Gated identically to {@link cwdHonored}: these are the caller's OWN-machine paths, so they * only make sense — and are only safe — on the single-user host lane (on a cloud/container lane a file-tool root is * the sandbox fs, and a multi-tenant lane must never let one caller widen containment onto operator/other-tenant * host paths). Each element gets the SAME structural check as `cwd` (absolute, no `..` traversal, no NUL, capped); * malformed entries are dropped (never throw), the count is bounded, and duplicates collapse. Returns undefined when * nothing valid remains (so the spec field stays absent rather than an empty array). NOT an existence check. */ export declare function parseAdditionalDirectories(raw: unknown): string[] | undefined; /** * core 1.219 `ExecutionEnvFactoryContext.parentCwd` (dogfood: sub-agents landed in an EMPTY * sandbox — "当前工作目录为空"): resolve the HOST lane's effective workspace for a task. Precedence: * 1. the session's explicitly-registered `cwd` (the caller's own launch dir, the cwd seam) — an explicit * per-session choice always wins; * 2. the TRUSTED `ctx.parentCwd` (core threads the PARENT task's working root via `RunInternals` when this * task is a delegated child — never a TaskSpec field), UNLESS the child asked for `isolation:"worktree"` * (core contract: worktree wins — an isolated fan-out child must not share the parent's mutable dir); * 3. undefined → the factory's ephemeral per-task dir (top-level task with no registered cwd). * CC parity: a Task sub-agent inherits the main session's cwd. Trust: `parentCwd` comes from core's trusted * run-internals channel (same posture as `isolation`), so no tenancy gate is needed here — but the HOST lane * itself is single-user by deployment shape, and container lanes (k8s/e2b/local-docker) never consult this. */ export declare function effectiveHostWorkspace(sessionCwd: string | undefined, ctx: { isolation?: string; parentCwd?: string; }): string | undefined; //# sourceMappingURL=task-cwd.d.ts.map