@epoch-agent/infra 0.2.0 → 0.3.2

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/dist/index.d.ts CHANGED
@@ -41,6 +41,14 @@ declare function memoriesDir(homeDir?: string): string;
41
41
  */
42
42
  declare function skillsDir(homeDir?: string): string;
43
43
  declare function policiesDir(homeDir?: string): string;
44
+ /**
45
+ * 用户级合规词库目录(`~/.epoch/compliance/<类别>.txt`)。
46
+ *
47
+ * 一行一个词的纯文本,文件名就是类别名 —— 格式和「文件名为什么是类别名」的
48
+ * 判据在 `core/compliance/loader.ts` 的文件头。**只读**:这个目录里的东西
49
+ * 由部署方维护,引擎从不往里写。
50
+ */
51
+ declare function complianceDir(homeDir?: string): string;
44
52
  /**
45
53
  * 用户级 hook 配置(方案 23 §2.6)。`~/.epoch/hooks.json`。
46
54
  *
@@ -234,7 +242,8 @@ declare function projectCommandsDir(projectRoot: string): string;
234
242
  * 项目级技能目录(方案 23 §2.5)。同名时压过用户级那份,且**要过信任闸门**。
235
243
  *
236
244
  * 与命令目录的区别只有一个:技能是**只读**的。写操作(`SkillLearner` 的自动
237
- * 创建、`skill_manager` 工具的编辑)永远落在 `skillsDir()`,不碰用户的仓库。
245
+ * 创建、模型那四个写工具 —— `skill_create` / `skill_edit` / `skill_patch` /
246
+ * `skill_write_file` —— 的编辑)永远落在 `skillsDir()`,不碰用户的仓库。
238
247
  */
239
248
  declare function projectSkillsDir(projectRoot: string): string;
240
249
  /**
@@ -253,6 +262,14 @@ declare function projectHooksPath(projectRoot: string): string;
253
262
  * 「哪些操作不用问就放行」。判定在 `core/policy/sources.ts`。
254
263
  */
255
264
  declare function projectPoliciesDir(projectRoot: string): string;
265
+ /**
266
+ * 项目级合规词库目录。`<项目根>/.epoch/compliance/*.txt`。
267
+ *
268
+ * 和项目级 hook 同一档闸门(未信任一律不加载),但**理由和策略规则相反**:
269
+ * 一份词库里的 `exempt.txt` 有能力把内置规则一条条豁免掉,也就是说它
270
+ * **能放松**合规,而不只是「多拦几个词」。判定在 `core/compliance/sources.ts`。
271
+ */
272
+ declare function projectComplianceDir(projectRoot: string): string;
256
273
  /**
257
274
  * Claude Code 的配置目录名。**不是我们的目录**,我们只读、从不写
258
275
  * (方案 50 §七:往别人的配置文件里写东西是越界)。
@@ -341,6 +358,12 @@ declare function setScalar(yaml: string, key: string, value: string): string;
341
358
  * 就地设置 `<section>:` 段下的一个字段。
342
359
  *
343
360
  * 段不存在就在文件末尾追加一个新段;段内已有该字段就替换,否则插在段首。
361
+ *
362
+ * ⚠️ **空输入不留那个前导空行**(2026-08-31 补的)。`epoch config set` 走
363
+ * {@link readConfigYaml},文件不存在时拿到的是 {@link DEFAULT_YAML},所以它这条路
364
+ * 上永远看不见空串;而 core 的设置页写那一支**看得见** —— 它读的是真文件,
365
+ * 不存在就是 `''`。少这一句的表现是新建出来的 `config.yaml` 头上多一个空行,
366
+ * 而 {@link setScalar} 那一支(`text.length === 0 ? …`)早就防着这件事了。
344
367
  */
345
368
  declare function setSectionField(yaml: string, section: string, field: string, value: string): string;
346
369
  /**
@@ -835,17 +858,31 @@ interface StreamDecoder {
835
858
  declare function createStreamDecoder(fallbackEncoding?: string): StreamDecoder;
836
859
 
837
860
  /**
838
- * ripgrep 的三级解析(方案 24)—— 回答「`rg` 从哪来」这一个问题。
861
+ * ripgrep 的解析(方案 24)—— 回答「`rg` 从哪来」这一个问题。
839
862
  *
840
863
  * 1. `system` —— PATH 里有 `rg` 就用它。用户自己装的通常比我们内置的新
841
864
  * 2. `builtin` —— 用 `@epoch-agent/vendor-ripgrep-<platform>-<arch>` 里带的那个
842
- * 3. `missing` —— 两个都没有。**保持内置之前的行为**:启动诊断一条 warn,
843
- * `file_search` 仍然注册,调用时报错并给安装提示
865
+ * 3. `not-executable` —— **包装下来了、文件也在,只是它没有执行位而我们补不上**
866
+ * 4. `missing` —— 上面都不成立
844
867
  *
845
- * 第 3 级不是兜底摆设,是真的会走到:`npm install --ignore-scripts`、
868
+ * 第 3/4 级不是兜底摆设,是真的会走到:`npm install --ignore-scripts`、
846
869
  * 内网私服重打包、以及我们没出包的平台(Linux 现阶段就是)。那种情况下退回旧行为
847
870
  * 比崩掉好得多 —— 少一个工具,不是起不来。
848
871
  *
872
+ * ## ⚠️ 第 3 档 2026-09-01 才从 `missing` 里拆出来,判据在这儿
873
+ *
874
+ * 拆之前这两档合成一句话:「未安装,file_search 不可用(brew install ripgrep)」。
875
+ * 那句话在「装了但没有执行位」这一档上是**假的**,而且它给的出路是错的 ——
876
+ * 让用户再装一个 ripgrep,而真正要做的是一条 `chmod`。
877
+ *
878
+ * 这不是理论上的:用户 2026-09-01 报的就是它。`npm i -g @epoch-agent/cli` 之后
879
+ * vendor 包**装下来了**(实测),但 tarball 里那个二进制是 644(见下面
880
+ * `ensureExecutable`),而 `sudo npm i -g` 装出来的 node_modules 归 root ——
881
+ * 以自己身份跑的 `epoch` chmod 不动它,于是屏幕上说「未安装」。
882
+ *
883
+ * 分档之后 `command` 那一格**两档仍然一样**(都是 `'rg'`,不返回那个注定 EACCES
884
+ * 的路径)—— 变的只有「屏幕上说什么」。判据见 {@link RipgrepResolution.command}。
885
+ *
849
886
  * 放 infra 而不是 plugin-file:将来 `file_list`(`rg --files`)和 `@` 文件补全
850
887
  * 都要用它,而 plugin 之间不许互相依赖。
851
888
  *
@@ -854,8 +891,15 @@ declare function createStreamDecoder(fallbackEncoding?: string): StreamDecoder;
854
891
  * `system` 给的是**命令名 `'rg'`**,`builtin` 给的是**绝对路径**。这不是疏漏,
855
892
  * 两边是刻意不对称的,改之前先读下面两段。
856
893
  */
857
- /** 解析结果的三档。`missing` 也是一种正常结果,不是错误 */
858
- type RipgrepMode = 'system' | 'builtin' | 'missing';
894
+ /**
895
+ * 解析结果的四档。`not-executable` / `missing` 也是正常结果,不是错误。
896
+ *
897
+ * ⚠️ **`not-executable` 是 2026-09-01 加的第四档**,加它是因为它和 `missing`
898
+ * 该对用户说的话完全不同(一条 `chmod` vs 装一个 ripgrep)。判据在文件头。
899
+ * 对做穷尽 `switch` 的消费方这是破坏性的 —— 那正是想要的:漏掉这一档的人
900
+ * 会在编译期看到,而不是让用户看到一句假话。
901
+ */
902
+ type RipgrepMode = 'system' | 'builtin' | 'not-executable' | 'missing';
859
903
  interface RipgrepResolution {
860
904
  mode: RipgrepMode;
861
905
  /**
@@ -863,13 +907,42 @@ interface RipgrepResolution {
863
907
  *
864
908
  * - `system`:**故意是 `'rg'` 而不是探测到的绝对路径**。见下面 `probeSystem` 的注释
865
909
  * - `builtin`:vendor 包里那个文件的绝对路径
866
- * - `missing`:仍然是 `'rg'`,让调用方照旧 spawn 并拿到 ENOENT ——
867
- * 这样「没装」这条路径与内置之前**逐字同构**,错误信息和 suggestion 都不用改
910
+ * - `not-executable` / `missing`:仍然是 `'rg'`,让调用方照旧 spawn 并拿到
911
+ * ENOENT —— 这样这两条路径与内置之前**逐字同构**,错误处理一行都不用改
912
+ *
913
+ * ⚠️ `not-executable` 这一档**尤其不许**把那个绝对路径交出去:它就在手上、
914
+ * 看着像个好答案,但 spawn 它必然 EACCES —— 那时用户拿到的是一句
915
+ * 「permission denied」加一条我们自己给的路径,比 ENOENT 更难懂。
916
+ * 路径要给的地方是 {@link hint},那儿它是**说明的一部分**而不是一个会被执行的值。
868
917
  */
869
918
  command: string;
870
- /** 内置那份的版本号(vendor 包的 `version`,与上游 ripgrep 版本对齐)。只有 `builtin` 有 */
919
+ /**
920
+ * 内置那份 **ripgrep 自己**的版本号。只有 `builtin` 有。
921
+ *
922
+ * ⚠️ **读的是 vendor 包的 `ripgrepVersion` 字段,不是它的 `version`**
923
+ * (2026-09-01 改)。两者曾经被当成一回事,而实测它们**早就不是**了:
924
+ * 包 `version` 是 `14.2.0`,`bin/rg --version` 说的是 **14.1.1**
925
+ * (`scripts/fetch-ripgrep.mjs` 钉的也是 14.1.1)。也就是说这一格从落地起
926
+ * 就在屏幕上印一个假版本号。
927
+ *
928
+ * 两者必须分开的理由不止于纠正这一次:包版本要为**打包问题**而升
929
+ * (这一轮加 `bin` 字段就是),而那种升级一个字节的二进制都没换。
930
+ * 合成一格的话,每修一次包装就多印一次假话。
931
+ *
932
+ * 读不出来就不给 —— 诊断里少一个版本号,不值得为此失败。
933
+ */
871
934
  version?: string;
872
- /** 安装提示。只有 `missing` 有 —— 另外两档不需要用户做任何事 */
935
+ /**
936
+ * 给用户的下一步。**只有 `not-executable` / `missing` 有** —— 另外两档不需要
937
+ * 用户做任何事。
938
+ *
939
+ * ⚠️ 两档给的是**两条不同的命令**,这正是拆档的全部意义:
940
+ *
941
+ * | 档 | hint |
942
+ * | ---------------- | ------------------------------ |
943
+ * | `missing` | 装一个 ripgrep(`ripgrepInstallHint()`) |
944
+ * | `not-executable` | `chmod +x "<那个文件的真实路径>"` |
945
+ */
873
946
  hint?: string;
874
947
  }
875
948
  /**
@@ -3065,5 +3138,48 @@ declare function setSecretValues(next: Record<string, string>): void;
3065
3138
  declare function getSecretValues(): Record<string, string>;
3066
3139
  /** 仅供测试:把进程级状态复位 */
3067
3140
  declare function resetSecretState(): void;
3141
+ /** 一次凭据写入的落点。**必须回显给用户**,理由见 {@link writeProviderSecret} */
3142
+ interface SecretWriteResult {
3143
+ /** `keychain` / `dpapi` / `libsecret` / `plaintext` */
3144
+ backend: string;
3145
+ encrypted: boolean;
3146
+ /** 一行人类可读说明,直接给命令回显。⚠️ 它按**本进程**语言渲染,见下 */
3147
+ detail: string;
3148
+ /** 明文降级时那个 `.env` 在哪儿;进了加密后端就是 `null` */
3149
+ envPath: string | null;
3150
+ }
3151
+ /**
3152
+ * 写一个 provider 的 API key —— **全仓唯一一份写入实现**。
3153
+ *
3154
+ * ## 它 2026-08-31 从 cli 搬到了这儿
3155
+ *
3156
+ * 原来住在 `cli/src/files/env-file.ts`(那边现在只剩一句转出,`epoch model` 一行没动)。
3157
+ * 搬家的理由是**又多了一个调用方**:Web UI 上配 key(`POST /api/providers/:type/key`)
3158
+ * 走 server → runtime,而 `check-layers.mjs` 里 server 只许依赖 `protocol + runtime`、
3159
+ * runtime 够不着 cli。原地不动的话就得在 runtime 里再写一份 —— 而这个文件的前身
3160
+ * 头一句话就是「本文件只转出、**不再有第二份实现**」。
3161
+ *
3162
+ * ## 三件事,一件都不能省
3163
+ *
3164
+ * 1. **交给 `SecretStore`**(钥匙串 → DPAPI → libsecret → 明文 0600 的降级链已经封在里面);
3165
+ * 2. **回显落点** —— 「我的 key 进了钥匙串还是明文文件」是用户有权当场知道的事,
3166
+ * 这正是方案 3.3「降级必须响亮」在写入侧的对应物;
3167
+ * 3. **就地补进预取表** —— 见下面那段。
3168
+ *
3169
+ * ## ⚠️ 第 3 件是这次搬家新加的,少了它 Web UI 那条路当场失效
3170
+ *
3171
+ * `readProviderKeyEnv()`(引擎和模型探测共用的那份判据)读的是
3172
+ * `process.env` > `.env` > **启动时预取的那张 map**。刚写进钥匙串的那把 key
3173
+ * 三处一处都不在 —— 于是「在设置页配完 key、立刻探模型」还是 `no-key`,
3174
+ * 而用户面前的证据是他刚刚才按过保存。
3175
+ *
3176
+ * `epoch model` 撞不到这个坑只是因为它写完就退了,不代表这一步以前不该有。
3177
+ * 补在这个函数里(而不是各调用方)是因为**两条路径要的是同一件事**。
3178
+ *
3179
+ * @param name 环境变量名(`DEEPSEEK_API_KEY` 这种),**不是** provider 类型
3180
+ * @param value 那把 key 的原文
3181
+ * @param fallbackEnvPath 装配层还没跑过时兜底写哪个 `.env`
3182
+ */
3183
+ declare function writeProviderSecret(name: string, value: string, fallbackEnvPath: string): Promise<SecretWriteResult>;
3068
3184
 
3069
- export { type ArtifactHandle, type BubblewrapOptions, CLAUDE_DIR_NAME, CODE_EXEC_ROOTS, type CatalogLoad, type CommandSegment, type Confinement, type CreateSecretStoreOptions, DEFAULT_LANG, DEFAULT_YAML, DENIAL_SIGNATURES, type DangerCheckOptions, type DangerMatch, type DangerPlatform, type DiagnosticCollector, ENVELOPE_PREFIX, EXEC_PATH_AS_NODE_ENV, type FailureKind, type FailureVerdict, type I18nDiagnostic, IS_WINDOWS, type IsolatedCommand, type IsolationBackend, type IsolationOptions, type JobHandle, type JobInfo, type JobKind, type JobReadResult, type JobSpec, type JobStatus, type JobWaitResult, type KillProcessTreeOptions, type KillSignalOptions, type KillablePty, LANGS, type Lang, type LogEntry, type LogLevel, type MigrateOptions, type MigrateResult, type Migration, type OnExisting, type OwnedProcessTable, PROJECT_DIR_NAME, type ParseIssue, type ParseOutcome, type ParsedCommand, PlaintextStore, type ProcessTable, RUNNER_FAILURE_RULES, type ResolveRipgrepOptions, type RipgrepMode, type RipgrepResolution, type RunnerFailureRules, SECRET_MODE, SECRET_SERVICE, SHELL_KINDS, SIGKILL_TIMEOUT_MS, type SandboxEnforcement, type SandboxMode, type SandboxPolicy, type SeatbeltOptions, type SecretBackendId, SecretCatalog, type SecretStore, type ShellFlavor, type ShellInvocation, type ShellKind, type SqliteDatabase, type StampedPid, type StartLongLivedOptions, type StreamDecoder, TOOLCHAIN_CACHE_DIRS, type TrackedProcess, WINDOWS_HIDE_FLAGS, agentsDir, allJobs, appendJob, approvalsPath, artifactsDir, assertValidSecretName, automationDir, automationLogsDir, automationWorkDir, budgetStatePath, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, checkpointsDir, classifyFailure, claudeUserSettingsPath, clearAllJobs, closeAllDatabases, collectProcessTree, collectProcessTreeStamped, commandsDir, configPath, confine, countCodePoints, createLogger, createProcessTable, createSecretStore, createStreamDecoder, currentLang, dbPath, detectBackend, detectConsoleEncoding, encodingForCodePage, envPath, formatIssues, generateDataKey, getDataKey, getDefaultShell, getJob, getPythonCommand, getSecretStore, getSecretValues, hasSideEffectChannel, headCodePoints, hooksPath, i18nDiagnostics, isEnvelope, isInWorkspace, isLang, isReadOnlyCommand, isSensitiveKey, isolate, issueDetails, jobDetail, keepHeadAndTail, keybindingsPath, killAllTrackedProcesses, killPids, killProcessTree, killStampedPids, killTrackedProcess, listJobs, listStoredSecretNames, loadCatalog, localesDir, managedSettingsPath, marketplacesPath, maskApiKey, maskSensitive, mcpAuthPath, mcpConfigPath, mcpSchemaCachePath, memoriesDir, migrate, migrateEnvSecrets, normalizeForMatch, openArtifact, openDatabase, openEnvelope, parseDataKey, parseEnvText, parseLenient, parseShellCommand, parseStrict, placeholdersOf, pluginsDir, pluginsStatePath, policiesDir, powershellCommandArg, prefetchProviderSecrets, probeBubblewrap, probeSeatbelt, probeShell, processFallbackTable, processTableFor, projectClaudeLocalSettingsPath, projectClaudeSettingsPath, projectCommandsDir, projectHooksPath, projectLocalSettingsPath, projectPoliciesDir, projectSchemasDir, projectSettingsPath, projectSkillsDir, readConfigYaml, readJob, readKey, refCount, registerJob, rekeyJobs, releaseDatabase, removeEnvVarText, resetI18n, resetRipgrepCache, resetSecretState, resolveHomeDir, resolveLang, resolveProfile, resolveRipgrep, resolveShellKind, ripgrepInstallHint, safeInit, sandboxModeForLevel, schemaVersion, sealEnvelope, setDataKey, setEnvVarText, setLang, setLogLevel, setScalar, setSecretStore, setSecretValues, setSectionField, setShell, shellPtyArgs, shellSpawnArgs, skillsDir, splitWords, startLongLivedProcess, stopJob, stripShellWrapper, systemLocaleSignals, t, tailCodePoints, touchJob, trackForeignProcess, trackedProcessCount, trustPath, trustedImportsPath, uiDateLocale, unknownKeyIssues, unsetScalar, unsetSectionField, waitJob, withTimeout, workspacesPath, worktreesDir, writeArtifact, writeConfigYaml, writeEnvFile };
3185
+ export { type ArtifactHandle, type BubblewrapOptions, CLAUDE_DIR_NAME, CODE_EXEC_ROOTS, type CatalogLoad, type CommandSegment, type Confinement, type CreateSecretStoreOptions, DEFAULT_LANG, DEFAULT_YAML, DENIAL_SIGNATURES, type DangerCheckOptions, type DangerMatch, type DangerPlatform, type DiagnosticCollector, ENVELOPE_PREFIX, EXEC_PATH_AS_NODE_ENV, type FailureKind, type FailureVerdict, type I18nDiagnostic, IS_WINDOWS, type IsolatedCommand, type IsolationBackend, type IsolationOptions, type JobHandle, type JobInfo, type JobKind, type JobReadResult, type JobSpec, type JobStatus, type JobWaitResult, type KillProcessTreeOptions, type KillSignalOptions, type KillablePty, LANGS, type Lang, type LogEntry, type LogLevel, type MigrateOptions, type MigrateResult, type Migration, type OnExisting, type OwnedProcessTable, PROJECT_DIR_NAME, type ParseIssue, type ParseOutcome, type ParsedCommand, PlaintextStore, type ProcessTable, RUNNER_FAILURE_RULES, type ResolveRipgrepOptions, type RipgrepMode, type RipgrepResolution, type RunnerFailureRules, SECRET_MODE, SECRET_SERVICE, SHELL_KINDS, SIGKILL_TIMEOUT_MS, type SandboxEnforcement, type SandboxMode, type SandboxPolicy, type SeatbeltOptions, type SecretBackendId, SecretCatalog, type SecretStore, type SecretWriteResult, type ShellFlavor, type ShellInvocation, type ShellKind, type SqliteDatabase, type StampedPid, type StartLongLivedOptions, type StreamDecoder, TOOLCHAIN_CACHE_DIRS, type TrackedProcess, WINDOWS_HIDE_FLAGS, agentsDir, allJobs, appendJob, approvalsPath, artifactsDir, assertValidSecretName, automationDir, automationLogsDir, automationWorkDir, budgetStatePath, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, checkpointsDir, classifyFailure, claudeUserSettingsPath, clearAllJobs, closeAllDatabases, collectProcessTree, collectProcessTreeStamped, commandsDir, complianceDir, configPath, confine, countCodePoints, createLogger, createProcessTable, createSecretStore, createStreamDecoder, currentLang, dbPath, detectBackend, detectConsoleEncoding, encodingForCodePage, envPath, formatIssues, generateDataKey, getDataKey, getDefaultShell, getJob, getPythonCommand, getSecretStore, getSecretValues, hasSideEffectChannel, headCodePoints, hooksPath, i18nDiagnostics, isEnvelope, isInWorkspace, isLang, isReadOnlyCommand, isSensitiveKey, isolate, issueDetails, jobDetail, keepHeadAndTail, keybindingsPath, killAllTrackedProcesses, killPids, killProcessTree, killStampedPids, killTrackedProcess, listJobs, listStoredSecretNames, loadCatalog, localesDir, managedSettingsPath, marketplacesPath, maskApiKey, maskSensitive, mcpAuthPath, mcpConfigPath, mcpSchemaCachePath, memoriesDir, migrate, migrateEnvSecrets, normalizeForMatch, openArtifact, openDatabase, openEnvelope, parseDataKey, parseEnvText, parseLenient, parseShellCommand, parseStrict, placeholdersOf, pluginsDir, pluginsStatePath, policiesDir, powershellCommandArg, prefetchProviderSecrets, probeBubblewrap, probeSeatbelt, probeShell, processFallbackTable, processTableFor, projectClaudeLocalSettingsPath, projectClaudeSettingsPath, projectCommandsDir, projectComplianceDir, projectHooksPath, projectLocalSettingsPath, projectPoliciesDir, projectSchemasDir, projectSettingsPath, projectSkillsDir, readConfigYaml, readJob, readKey, refCount, registerJob, rekeyJobs, releaseDatabase, removeEnvVarText, resetI18n, resetRipgrepCache, resetSecretState, resolveHomeDir, resolveLang, resolveProfile, resolveRipgrep, resolveShellKind, ripgrepInstallHint, safeInit, sandboxModeForLevel, schemaVersion, sealEnvelope, setDataKey, setEnvVarText, setLang, setLogLevel, setScalar, setSecretStore, setSecretValues, setSectionField, setShell, shellPtyArgs, shellSpawnArgs, skillsDir, splitWords, startLongLivedProcess, stopJob, stripShellWrapper, systemLocaleSignals, t, tailCodePoints, touchJob, trackForeignProcess, trackedProcessCount, trustPath, trustedImportsPath, uiDateLocale, unknownKeyIssues, unsetScalar, unsetSectionField, waitJob, withTimeout, workspacesPath, worktreesDir, writeArtifact, writeConfigYaml, writeEnvFile, writeProviderSecret };
package/dist/index.js CHANGED
@@ -38,6 +38,9 @@ function skillsDir(homeDir = resolveHomeDir()) {
38
38
  function policiesDir(homeDir = resolveHomeDir()) {
39
39
  return join(homeDir, "policies");
40
40
  }
41
+ function complianceDir(homeDir = resolveHomeDir()) {
42
+ return join(homeDir, "compliance");
43
+ }
41
44
  function hooksPath(homeDir = resolveHomeDir()) {
42
45
  return join(homeDir, "hooks.json");
43
46
  }
@@ -132,6 +135,9 @@ function projectHooksPath(projectRoot) {
132
135
  function projectPoliciesDir(projectRoot) {
133
136
  return join(projectRoot, PROJECT_DIR_NAME, "policies");
134
137
  }
138
+ function projectComplianceDir(projectRoot) {
139
+ return join(projectRoot, PROJECT_DIR_NAME, "compliance");
140
+ }
135
141
  var CLAUDE_DIR_NAME = ".claude";
136
142
  function claudeUserSettingsPath(home = homedir()) {
137
143
  return join(home, CLAUDE_DIR_NAME, "settings.json");
@@ -162,8 +168,9 @@ function setSectionField(yaml, section, field, value) {
162
168
  const entry = ` ${field}: ${value}`;
163
169
  const header = new RegExp(`^${section}:[ \\t]*$`, "m");
164
170
  if (!header.test(yaml)) {
165
- return `${yaml.trimEnd()}
166
- ${section}:
171
+ const head = yaml.trimEnd();
172
+ return `${head === "" ? "" : `${head}
173
+ `}${section}:
167
174
  ${entry}
168
175
  `;
169
176
  }
@@ -919,6 +926,7 @@ function defaultResolveVendor(specifier) {
919
926
  function readVendorVersion(manifestPath) {
920
927
  try {
921
928
  const pkg = require_(manifestPath);
929
+ if (typeof pkg.ripgrepVersion === "string") return pkg.ripgrepVersion;
922
930
  return typeof pkg.version === "string" ? pkg.version : void 0;
923
931
  } catch {
924
932
  return void 0;
@@ -945,9 +953,16 @@ function resolve(options) {
945
953
  if (manifest) {
946
954
  const api = platform10 === "win32" ? win32 : posix;
947
955
  const binary = api.join(api.dirname(manifest), "bin", platform10 === "win32" ? "rg.exe" : "rg");
948
- if (exists(binary) && (platform10 === "win32" || makeExecutable(binary))) {
949
- const version = readVendorVersion(manifest);
950
- return { mode: "builtin", command: binary, ...version ? { version } : {} };
956
+ if (exists(binary)) {
957
+ if (platform10 === "win32" || makeExecutable(binary)) {
958
+ const version = readVendorVersion(manifest);
959
+ return { mode: "builtin", command: binary, ...version ? { version } : {} };
960
+ }
961
+ return {
962
+ mode: "not-executable",
963
+ command: "rg",
964
+ hint: t("infra_misc.ripgrep_chmod_hint", { path: binary })
965
+ };
951
966
  }
952
967
  }
953
968
  }
@@ -3448,6 +3463,37 @@ function resetSecretState() {
3448
3463
  current = null;
3449
3464
  values = {};
3450
3465
  }
3466
+ async function writeProviderSecret(name, value, fallbackEnvPath) {
3467
+ const store = getSecretStore();
3468
+ const result = await writeThrough(store, name, value, fallbackEnvPath);
3469
+ setSecretValues({ ...getSecretValues(), [name]: value });
3470
+ return result;
3471
+ }
3472
+ async function writeThrough(store, name, value, fallbackEnvPath) {
3473
+ if (!store) {
3474
+ writeEnvFile(fallbackEnvPath, setEnvVarText(readEnvOrEmpty(fallbackEnvPath), name, value));
3475
+ return {
3476
+ backend: "plaintext",
3477
+ encrypted: false,
3478
+ detail: t("cli.config.secret_plaintext_write", { path: fallbackEnvPath }),
3479
+ envPath: fallbackEnvPath
3480
+ };
3481
+ }
3482
+ await store.set(name, value);
3483
+ return {
3484
+ backend: store.backend,
3485
+ encrypted: store.encrypted,
3486
+ detail: store.detail,
3487
+ envPath: store.backend === "plaintext" ? fallbackEnvPath : null
3488
+ };
3489
+ }
3490
+ function readEnvOrEmpty(path) {
3491
+ try {
3492
+ return readFileSync(path, "utf-8");
3493
+ } catch {
3494
+ return "";
3495
+ }
3496
+ }
3451
3497
  function message2(err) {
3452
3498
  return err instanceof Error ? err.message : String(err);
3453
3499
  }
@@ -3506,4 +3552,4 @@ function message2(err) {
3506
3552
  * Modifications Copyright 2024-2026 bowen
3507
3553
  */
3508
3554
 
3509
- export { CLAUDE_DIR_NAME, CODE_EXEC_ROOTS, DEFAULT_LANG, DEFAULT_YAML, DENIAL_SIGNATURES, ENVELOPE_PREFIX, EXEC_PATH_AS_NODE_ENV, IS_WINDOWS, LANGS, PROJECT_DIR_NAME, PlaintextStore, RUNNER_FAILURE_RULES, SECRET_MODE, SECRET_SERVICE, SHELL_KINDS, SIGKILL_TIMEOUT_MS, SecretCatalog, TOOLCHAIN_CACHE_DIRS, WINDOWS_HIDE_FLAGS, agentsDir, allJobs, appendJob, approvalsPath, artifactsDir, assertValidSecretName, automationDir, automationLogsDir, automationWorkDir, budgetStatePath, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, checkpointsDir, classifyFailure, claudeUserSettingsPath, clearAllJobs, closeAllDatabases, collectProcessTree, collectProcessTreeStamped, commandsDir, configPath, confine, countCodePoints, createLogger, createProcessTable, createSecretStore, createStreamDecoder, currentLang, dbPath, detectBackend, detectConsoleEncoding, encodingForCodePage, envPath, formatIssues, generateDataKey, getDataKey, getDefaultShell, getJob, getPythonCommand, getSecretStore, getSecretValues, hasSideEffectChannel, headCodePoints, hooksPath, i18nDiagnostics, isEnvelope, isInWorkspace, isLang, isReadOnlyCommand, isSensitiveKey, isolate, issueDetails, jobDetail, keepHeadAndTail, keybindingsPath, killAllTrackedProcesses, killPids, killProcessTree, killStampedPids, killTrackedProcess, listJobs, listStoredSecretNames, loadCatalog, localesDir, managedSettingsPath, marketplacesPath, maskApiKey, maskSensitive, mcpAuthPath, mcpConfigPath, mcpSchemaCachePath, memoriesDir, migrate, migrateEnvSecrets, normalizeForMatch, openArtifact, openDatabase, openEnvelope, parseDataKey, parseEnvText, parseLenient, parseShellCommand, parseStrict, placeholdersOf, pluginsDir, pluginsStatePath, policiesDir, powershellCommandArg, prefetchProviderSecrets, probeBubblewrap, probeSeatbelt, probeShell, processFallbackTable, processTableFor, projectClaudeLocalSettingsPath, projectClaudeSettingsPath, projectCommandsDir, projectHooksPath, projectLocalSettingsPath, projectPoliciesDir, projectSchemasDir, projectSettingsPath, projectSkillsDir, readConfigYaml, readJob, readKey, refCount, registerJob, rekeyJobs, releaseDatabase, removeEnvVarText, resetI18n, resetRipgrepCache, resetSecretState, resolveHomeDir, resolveLang, resolveProfile, resolveRipgrep, resolveShellKind, ripgrepInstallHint, safeInit, sandboxModeForLevel, schemaVersion, sealEnvelope, setDataKey, setEnvVarText, setLang, setLogLevel, setScalar, setSecretStore, setSecretValues, setSectionField, setShell, shellPtyArgs, shellSpawnArgs, skillsDir, splitWords, startLongLivedProcess, stopJob, stripShellWrapper, systemLocaleSignals, t, tailCodePoints, touchJob, trackForeignProcess, trackedProcessCount, trustPath, trustedImportsPath, uiDateLocale, unknownKeyIssues, unsetScalar, unsetSectionField, waitJob, withTimeout, workspacesPath, worktreesDir, writeArtifact, writeConfigYaml, writeEnvFile };
3555
+ export { CLAUDE_DIR_NAME, CODE_EXEC_ROOTS, DEFAULT_LANG, DEFAULT_YAML, DENIAL_SIGNATURES, ENVELOPE_PREFIX, EXEC_PATH_AS_NODE_ENV, IS_WINDOWS, LANGS, PROJECT_DIR_NAME, PlaintextStore, RUNNER_FAILURE_RULES, SECRET_MODE, SECRET_SERVICE, SHELL_KINDS, SIGKILL_TIMEOUT_MS, SecretCatalog, TOOLCHAIN_CACHE_DIRS, WINDOWS_HIDE_FLAGS, agentsDir, allJobs, appendJob, approvalsPath, artifactsDir, assertValidSecretName, automationDir, automationLogsDir, automationWorkDir, budgetStatePath, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, checkpointsDir, classifyFailure, claudeUserSettingsPath, clearAllJobs, closeAllDatabases, collectProcessTree, collectProcessTreeStamped, commandsDir, complianceDir, configPath, confine, countCodePoints, createLogger, createProcessTable, createSecretStore, createStreamDecoder, currentLang, dbPath, detectBackend, detectConsoleEncoding, encodingForCodePage, envPath, formatIssues, generateDataKey, getDataKey, getDefaultShell, getJob, getPythonCommand, getSecretStore, getSecretValues, hasSideEffectChannel, headCodePoints, hooksPath, i18nDiagnostics, isEnvelope, isInWorkspace, isLang, isReadOnlyCommand, isSensitiveKey, isolate, issueDetails, jobDetail, keepHeadAndTail, keybindingsPath, killAllTrackedProcesses, killPids, killProcessTree, killStampedPids, killTrackedProcess, listJobs, listStoredSecretNames, loadCatalog, localesDir, managedSettingsPath, marketplacesPath, maskApiKey, maskSensitive, mcpAuthPath, mcpConfigPath, mcpSchemaCachePath, memoriesDir, migrate, migrateEnvSecrets, normalizeForMatch, openArtifact, openDatabase, openEnvelope, parseDataKey, parseEnvText, parseLenient, parseShellCommand, parseStrict, placeholdersOf, pluginsDir, pluginsStatePath, policiesDir, powershellCommandArg, prefetchProviderSecrets, probeBubblewrap, probeSeatbelt, probeShell, processFallbackTable, processTableFor, projectClaudeLocalSettingsPath, projectClaudeSettingsPath, projectCommandsDir, projectComplianceDir, projectHooksPath, projectLocalSettingsPath, projectPoliciesDir, projectSchemasDir, projectSettingsPath, projectSkillsDir, readConfigYaml, readJob, readKey, refCount, registerJob, rekeyJobs, releaseDatabase, removeEnvVarText, resetI18n, resetRipgrepCache, resetSecretState, resolveHomeDir, resolveLang, resolveProfile, resolveRipgrep, resolveShellKind, ripgrepInstallHint, safeInit, sandboxModeForLevel, schemaVersion, sealEnvelope, setDataKey, setEnvVarText, setLang, setLogLevel, setScalar, setSecretStore, setSecretValues, setSectionField, setShell, shellPtyArgs, shellSpawnArgs, skillsDir, splitWords, startLongLivedProcess, stopJob, stripShellWrapper, systemLocaleSignals, t, tailCodePoints, touchJob, trackForeignProcess, trackedProcessCount, trustPath, trustedImportsPath, uiDateLocale, unknownKeyIssues, unsetScalar, unsetSectionField, waitJob, withTimeout, workspacesPath, worktreesDir, writeArtifact, writeConfigYaml, writeEnvFile, writeProviderSecret };