@coralai/sps-cli 0.65.77 → 0.65.78
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/core/agents/projectAgentConfig.d.ts +3 -1
- package/dist/core/agents/projectAgentConfig.d.ts.map +1 -1
- package/dist/core/agents/projectAgentConfig.js +6 -3
- package/dist/core/agents/projectAgentConfig.js.map +1 -1
- package/dist/core/agents/writeProjectPersona.d.ts +6 -0
- package/dist/core/agents/writeProjectPersona.d.ts.map +1 -1
- package/dist/core/agents/writeProjectPersona.js +10 -3
- package/dist/core/agents/writeProjectPersona.js.map +1 -1
- package/dist/infra/filesystem.d.ts +12 -0
- package/dist/infra/filesystem.d.ts.map +1 -1
- package/dist/infra/filesystem.js +24 -10
- package/dist/infra/filesystem.js.map +1 -1
- package/dist/infra/secretFile.d.ts +6 -2
- package/dist/infra/secretFile.d.ts.map +1 -1
- package/dist/infra/secretFile.js +44 -10
- package/dist/infra/secretFile.js.map +1 -1
- package/package.json +1 -1
|
@@ -15,7 +15,9 @@ export declare function readProjectAgentConfig(cwd: string, role: AgentRole): Ag
|
|
|
15
15
|
* 🔴 为什么必须合并:这个文件按 role 分段(worker/chat/reviewer),整体覆盖会把
|
|
16
16
|
* 别的 role 的人设抹掉。派一次专家改 chat 段,不该让 worker 失去人设。
|
|
17
17
|
*
|
|
18
|
-
* 不含密,常规权限即可(与 settings.local.json/media-providers 不同,那些含 token)
|
|
18
|
+
* 不含密,常规权限即可(与 settings.local.json/media-providers 不同,那些含 token)——
|
|
19
|
+
* **但要原子**:这是读-改-写,半截落盘会让下一次读走进上面那条"坏 JSON 当空处理"的分支,
|
|
20
|
+
* 于是**别的 role 的人设被静默抹掉**,而那正是这个函数存在的理由。
|
|
19
21
|
*/
|
|
20
22
|
export declare function writeProjectAgentConfig(cwd: string, role: AgentRole, cfg: AgentRuntimeConfig): void;
|
|
21
23
|
/** 角色全集(delivery 层校验入参用)。 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectAgentConfig.d.ts","sourceRoot":"","sources":["../../../src/core/agents/projectAgentConfig.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"projectAgentConfig.d.ts","sourceRoot":"","sources":["../../../src/core/agents/projectAgentConfig.ts"],"names":[],"mappings":"AAoBA,wEAAwE;AACxE,MAAM,WAAW,kBAAkB;IACjC,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,4DAA4D;AAC5D,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAKvD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CAWvF;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,kBAAkB,GAAG,IAAI,CAanG;AAED,6BAA6B;AAC7B,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAAmC,CAAC"}
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
* @layer core
|
|
15
15
|
* @boundedContext agents
|
|
16
16
|
*/
|
|
17
|
-
import { existsSync, mkdirSync, readFileSync
|
|
17
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
18
18
|
import { dirname, join } from 'node:path';
|
|
19
|
+
import { writeFileAtomicSync } from '../../infra/filesystem.js';
|
|
19
20
|
/**
|
|
20
21
|
* 读项目级 per-agent 人设的某 role 段。缺文件/缺段/异常 → 空对象(永不抛)。
|
|
21
22
|
*/
|
|
@@ -40,7 +41,9 @@ export function readProjectAgentConfig(cwd, role) {
|
|
|
40
41
|
* 🔴 为什么必须合并:这个文件按 role 分段(worker/chat/reviewer),整体覆盖会把
|
|
41
42
|
* 别的 role 的人设抹掉。派一次专家改 chat 段,不该让 worker 失去人设。
|
|
42
43
|
*
|
|
43
|
-
* 不含密,常规权限即可(与 settings.local.json/media-providers 不同,那些含 token)
|
|
44
|
+
* 不含密,常规权限即可(与 settings.local.json/media-providers 不同,那些含 token)——
|
|
45
|
+
* **但要原子**:这是读-改-写,半截落盘会让下一次读走进上面那条"坏 JSON 当空处理"的分支,
|
|
46
|
+
* 于是**别的 role 的人设被静默抹掉**,而那正是这个函数存在的理由。
|
|
44
47
|
*/
|
|
45
48
|
export function writeProjectAgentConfig(cwd, role, cfg) {
|
|
46
49
|
const p = join(cwd, '.claude', 'agent-config.json');
|
|
@@ -57,7 +60,7 @@ export function writeProjectAgentConfig(cwd, role, cfg) {
|
|
|
57
60
|
existing = {};
|
|
58
61
|
const next = { ...existing, [role]: { ...existing[role], ...cfg } };
|
|
59
62
|
mkdirSync(dirname(p), { recursive: true });
|
|
60
|
-
|
|
63
|
+
writeFileAtomicSync(p, `${JSON.stringify(next, null, 2)}\n`);
|
|
61
64
|
}
|
|
62
65
|
/** 角色全集(delivery 层校验入参用)。 */
|
|
63
66
|
export const AGENT_ROLES = ['worker', 'chat', 'reviewer'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectAgentConfig.js","sourceRoot":"","sources":["../../../src/core/agents/projectAgentConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"projectAgentConfig.js","sourceRoot":"","sources":["../../../src/core/agents/projectAgentConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAchE;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,IAAe;IACjE,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAA2B,CAAC;QACzE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAC3C,OAAO,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAClG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAW,EAAE,IAAe,EAAE,GAAuB;IAC3F,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACpD,IAAI,QAAQ,GAA2B,EAAE,CAAC;IAC1C,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,CAAC,CAAC;YAAE,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAA2B,CAAC;IAC/F,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;QAC1C,QAAQ,GAAG,EAAE,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,QAAQ,GAAG,EAAE,CAAC;IACxF,MAAM,IAAI,GAA2B,EAAE,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,CAAC;IAC5F,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,mBAAmB,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED,6BAA6B;AAC7B,MAAM,CAAC,MAAM,WAAW,GAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC"}
|
|
@@ -19,6 +19,12 @@ export interface WriteProjectPersonaResult {
|
|
|
19
19
|
* 写人设三件。`outputStyle` 省略则只写 `AGENTS.md`(纯正文人设,不走 output-style 通道)。
|
|
20
20
|
*
|
|
21
21
|
* 不含密 → 常规权限(与 settings.local.json / media-providers.json 不同,那些含 token)。
|
|
22
|
+
*
|
|
23
|
+
* 🔴 **但要原子**(tmp→rename):失败形态不是泄密,是**半截文件被 worker 读到** ——
|
|
24
|
+
* 半个 output-style / 坏 JSON 的 agent-config 都会让 agent 行为怪而不报错。
|
|
25
|
+
* 判据(studio 会话,C 组迁移):**迁移不该让任何一个既有属性变差** ——
|
|
26
|
+
* studio 侧这三个文件原本就是 tmp→rename,直接迁过来会把"原子"这个属性掉在路上,
|
|
27
|
+
* 而掉了之后**没有任何东西会报错**。
|
|
22
28
|
*/
|
|
23
29
|
export declare function writeProjectPersona(cwd: string, opts: WriteProjectPersonaOpts): WriteProjectPersonaResult;
|
|
24
30
|
//# sourceMappingURL=writeProjectPersona.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeProjectPersona.d.ts","sourceRoot":"","sources":["../../../src/core/agents/writeProjectPersona.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"writeProjectPersona.d.ts","sourceRoot":"","sources":["../../../src/core/agents/writeProjectPersona.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,KAAK,SAAS,EAA2B,MAAM,yBAAyB,CAAC;AAElF,MAAM,WAAW,uBAAuB;IACtC,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB,mDAAmD;IACnD,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD;AAED,MAAM,WAAW,yBAAyB;IACxC,+BAA+B;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,uBAAuB,GAC5B,yBAAyB,CAwB3B"}
|
|
@@ -15,26 +15,33 @@
|
|
|
15
15
|
* 🔴 边界(架构原则①):**只落盘,不解释内容** —— 不校验语义、不注入模板、不做 diff。
|
|
16
16
|
* 正文里写什么是消费方的产品决策;sps 只保证写对位置、写全三件。
|
|
17
17
|
*/
|
|
18
|
-
import { mkdirSync
|
|
18
|
+
import { mkdirSync } from 'node:fs';
|
|
19
19
|
import { dirname, join } from 'node:path';
|
|
20
|
+
import { writeFileAtomicSync } from '../../infra/filesystem.js';
|
|
20
21
|
import { writeProjectAgentConfig } from './projectAgentConfig.js';
|
|
21
22
|
/**
|
|
22
23
|
* 写人设三件。`outputStyle` 省略则只写 `AGENTS.md`(纯正文人设,不走 output-style 通道)。
|
|
23
24
|
*
|
|
24
25
|
* 不含密 → 常规权限(与 settings.local.json / media-providers.json 不同,那些含 token)。
|
|
26
|
+
*
|
|
27
|
+
* 🔴 **但要原子**(tmp→rename):失败形态不是泄密,是**半截文件被 worker 读到** ——
|
|
28
|
+
* 半个 output-style / 坏 JSON 的 agent-config 都会让 agent 行为怪而不报错。
|
|
29
|
+
* 判据(studio 会话,C 组迁移):**迁移不该让任何一个既有属性变差** ——
|
|
30
|
+
* studio 侧这三个文件原本就是 tmp→rename,直接迁过来会把"原子"这个属性掉在路上,
|
|
31
|
+
* 而掉了之后**没有任何东西会报错**。
|
|
25
32
|
*/
|
|
26
33
|
export function writeProjectPersona(cwd, opts) {
|
|
27
34
|
const wrote = [];
|
|
28
35
|
const agentsMd = join(cwd, 'AGENTS.md');
|
|
29
36
|
mkdirSync(dirname(agentsMd), { recursive: true });
|
|
30
|
-
|
|
37
|
+
writeFileAtomicSync(agentsMd, opts.instructions.endsWith('\n') ? opts.instructions : `${opts.instructions}\n`);
|
|
31
38
|
wrote.push('AGENTS.md');
|
|
32
39
|
if (!opts.outputStyle)
|
|
33
40
|
return { wrote };
|
|
34
41
|
// name 的字符集由 delivery 层校验(它会变成文件名);这里只负责拼路径与写。
|
|
35
42
|
const stylePath = join(cwd, '.claude', 'output-styles', `${opts.outputStyle.name}.md`);
|
|
36
43
|
mkdirSync(dirname(stylePath), { recursive: true });
|
|
37
|
-
|
|
44
|
+
writeFileAtomicSync(stylePath, opts.outputStyle.content.endsWith('\n') ? opts.outputStyle.content : `${opts.outputStyle.content}\n`);
|
|
38
45
|
wrote.push(`.claude/output-styles/${opts.outputStyle.name}.md`);
|
|
39
46
|
// 按 role 段合并 —— 不整体覆盖,否则会抹掉别的 role 的人设。
|
|
40
47
|
writeProjectAgentConfig(cwd, opts.role, { outputStyle: opts.outputStyle.name });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeProjectPersona.js","sourceRoot":"","sources":["../../../src/core/agents/writeProjectPersona.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"writeProjectPersona.js","sourceRoot":"","sources":["../../../src/core/agents/writeProjectPersona.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAkB,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAiBlF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,IAA6B;IAE7B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACxC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC;IAC/G,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAExB,IAAI,CAAC,IAAI,CAAC,WAAW;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAExC,+CAA+C;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,CAAC;IACvF,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,mBAAmB,CACjB,SAAS,EACT,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,CACrG,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,CAAC;IAEhE,wCAAwC;IACxC,uBAAuB,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAChF,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAExC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;AACvD,CAAC"}
|
|
@@ -34,6 +34,18 @@ export interface FileSystem {
|
|
|
34
34
|
* 并发写者各写各的中间文件,rename 覆盖时互不干扰 —— 结果一定是某一方的完整内容。
|
|
35
35
|
*/
|
|
36
36
|
export declare function uniqueTmpPath(path: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* 原子写(函数式入口):同目录唯一临时名 → `rename`。
|
|
39
|
+
*
|
|
40
|
+
* 抽成函数是因为**有两类调用方**:走注入 `FileSystem` 的 service 层(用下面的方法),
|
|
41
|
+
* 和 `core/agents/*` 这类同步纯函数模块(没有可注入的 fs)。
|
|
42
|
+
* 🔴 抽出来而不是让后者各写一遍三行 —— 本仓已经有三种原子写各有其位
|
|
43
|
+
* (普通 / 含密 `infra/secretFile` / 资产 `providers/art/atomicWrite`),**不该再多出第四种**。
|
|
44
|
+
*
|
|
45
|
+
* ⚠️ 不带 `mode`:含密文件**不要用它**(tmp 会以 umask 默认权限存在到 rename 那一刻)——
|
|
46
|
+
* 那条走 `infra/secretFile.writeSecretFile`。
|
|
47
|
+
*/
|
|
48
|
+
export declare function writeFileAtomicSync(path: string, content: string): void;
|
|
37
49
|
export declare class NodeFileSystem implements FileSystem {
|
|
38
50
|
exists(path: string): boolean;
|
|
39
51
|
stat(path: string): FileStat | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/infra/filesystem.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,+CAA+C;IAC/C,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACrD,+BAA+B;IAC/B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAClC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB;IAChB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACxE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,qBAAa,cAAe,YAAW,UAAU;IAC/C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAcnC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI9B,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/infra/filesystem.ts"],"names":[],"mappings":"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"}
|
package/dist/infra/filesystem.js
CHANGED
|
@@ -21,6 +21,28 @@ import { dirname } from 'node:path';
|
|
|
21
21
|
export function uniqueTmpPath(path) {
|
|
22
22
|
return `${path}.${process.pid}.${randomUUID().slice(0, 8)}.tmp`;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* 原子写(函数式入口):同目录唯一临时名 → `rename`。
|
|
26
|
+
*
|
|
27
|
+
* 抽成函数是因为**有两类调用方**:走注入 `FileSystem` 的 service 层(用下面的方法),
|
|
28
|
+
* 和 `core/agents/*` 这类同步纯函数模块(没有可注入的 fs)。
|
|
29
|
+
* 🔴 抽出来而不是让后者各写一遍三行 —— 本仓已经有三种原子写各有其位
|
|
30
|
+
* (普通 / 含密 `infra/secretFile` / 资产 `providers/art/atomicWrite`),**不该再多出第四种**。
|
|
31
|
+
*
|
|
32
|
+
* ⚠️ 不带 `mode`:含密文件**不要用它**(tmp 会以 umask 默认权限存在到 rename 那一刻)——
|
|
33
|
+
* 那条走 `infra/secretFile.writeSecretFile`。
|
|
34
|
+
*/
|
|
35
|
+
export function writeFileAtomicSync(path, content) {
|
|
36
|
+
// 🔴 临时名必须唯一。固定的 `${path}.tmp` 会让并发写者共用同一个中间文件:
|
|
37
|
+
// A 写一半 → B 覆盖 → A rename,落地的是**撕裂内容**,而不是任一方的完整快照。
|
|
38
|
+
// 注:rename 覆盖是原子的,足以防住**进程崩溃**;要抗断电还需 fsync(代价更高,按需再加)。
|
|
39
|
+
const tmp = uniqueTmpPath(path);
|
|
40
|
+
const dir = dirname(path);
|
|
41
|
+
if (!existsSync(dir))
|
|
42
|
+
mkdirSync(dir, { recursive: true });
|
|
43
|
+
writeFileSync(tmp, content);
|
|
44
|
+
renameSync(tmp, path);
|
|
45
|
+
}
|
|
24
46
|
export class NodeFileSystem {
|
|
25
47
|
exists(path) {
|
|
26
48
|
return existsSync(path);
|
|
@@ -43,16 +65,8 @@ export class NodeFileSystem {
|
|
|
43
65
|
return readFileSync(path, 'utf-8');
|
|
44
66
|
}
|
|
45
67
|
writeFileAtomic(path, content) {
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
// 这个函数有 10+ 个调用方(项目 conf、daemon state.json…)在信任"原子"这个承诺。
|
|
49
|
-
// 注:rename 覆盖是原子的,足以防住**进程崩溃**;要抗断电还需 fsync(代价更高,按需再加)。
|
|
50
|
-
const tmp = uniqueTmpPath(path);
|
|
51
|
-
const dir = dirname(path);
|
|
52
|
-
if (!existsSync(dir))
|
|
53
|
-
mkdirSync(dir, { recursive: true });
|
|
54
|
-
writeFileSync(tmp, content);
|
|
55
|
-
renameSync(tmp, path);
|
|
68
|
+
// 实现见 `writeFileAtomicSync`(同一份;这个方法有 10+ 个调用方在信任"原子"这个承诺)。
|
|
69
|
+
writeFileAtomicSync(path, content);
|
|
56
70
|
}
|
|
57
71
|
writeFile(path, content) {
|
|
58
72
|
const dir = dirname(path);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/infra/filesystem.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAEL,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACZ,UAAU,EACV,MAAM,EACN,QAAQ,EACR,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+BpC,iEAAiE;AAEjE;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;AAClE,CAAC;AAED,MAAM,OAAO,cAAc;IACzB,MAAM,CAAC,IAAY;QACjB,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,IAAY;QACf,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YACzB,OAAO;gBACL,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE;gBAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;aACnB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAY;QACnB,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,eAAe,CAAC,IAAY,EAAE,OAAe;QAC3C,
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/infra/filesystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/** 含密文件的目标权限:仅属主可读写。 */
|
|
2
2
|
export declare const SECRET_MODE = 384;
|
|
3
3
|
/**
|
|
4
|
-
* 写一个含密文件:建目录 →
|
|
5
|
-
*
|
|
4
|
+
* 写一个含密文件:建目录 → 写 tmp(0600)→ **rename** → **chmod**。
|
|
5
|
+
*
|
|
6
|
+
* `chmod` 在 rename 之后是**要害**(见模块头):rename 继承 tmp 的位,顺序反了会被覆盖且不报错。
|
|
7
|
+
* ⚠️ tmp 本身就以 `SECRET_MODE` 创建 —— 所以正常路径上 chmod 是第二道保险;
|
|
8
|
+
* 但它不是冗余:**将来任何人改动 tmp 的建法(复用已有 tmp、换成别的 helper),
|
|
9
|
+
* chmod 就是唯一还站着的那道**。这也是为什么顺序要写进注释而不只是写进代码。
|
|
6
10
|
*/
|
|
7
11
|
export declare function writeSecretFile(path: string, data: string): void;
|
|
8
12
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secretFile.d.ts","sourceRoot":"","sources":["../../src/infra/secretFile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"secretFile.d.ts","sourceRoot":"","sources":["../../src/infra/secretFile.ts"],"names":[],"mappings":"AAmCA,wBAAwB;AACxB,eAAO,MAAM,WAAW,MAAQ,CAAC;AAEjC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAiBhE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CASnD"}
|
package/dist/infra/secretFile.js
CHANGED
|
@@ -1,31 +1,65 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module infra/secretFile
|
|
3
|
-
* @description
|
|
3
|
+
* @description 含密文件的写入:**原子(tmp→rename)+ 权限收敛(0600)**。叶子模块,无项目内依赖。
|
|
4
4
|
*
|
|
5
|
-
* 🔴
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* 🔴 两件事都要,而且**顺序不能反** —— 它们各自来自一次真实事故,分别在两个仓:
|
|
6
|
+
* ```
|
|
7
|
+
* 权限 `writeFileSync(p, data, { mode })` 的 mode **只在文件被创建时生效**,
|
|
8
|
+
* 已存在的文件权限原样不动 ⇒ 存量会永远停在 644。必须写完再 chmod。
|
|
9
|
+
* (来源:sps 多租户就绪审计 A9 —— 实测这些文件落 644/664,同机任何用户可读。)
|
|
10
|
+
* 原子 直接 writeFileSync 到最终名,崩在写一半就留下**半截的最终名文件** ——
|
|
11
|
+
* 而它是 JSON 配置:worker 读到坏 JSON,且因为是 0600 的敏感文件,
|
|
12
|
+
* 排查时最不容易被翻出来。
|
|
13
|
+
* (来源:coral-studio 侧同类文件的写法;它原子,但踩了下面那条。)
|
|
14
|
+
* 顺序 🔴 **`renameSync` 继承的是 tmp 的权限位** ⇒ `chmod` 必须在 `rename` **之后**。
|
|
15
|
+
* 放前面会被 rename 覆盖掉,**而且不报错**。(coral-studio 的事故原文:0600 被冲成 644。)
|
|
16
|
+
* ```
|
|
17
|
+
* ⇒ 合起来的正确顺序:**写 tmp(mode 0600)→ rename → chmod**。
|
|
18
|
+
* 两边原先各修了对方的坑,这里是合并后的那份 —— 迁移不该让任何一个既有属性变差。
|
|
8
19
|
*
|
|
9
20
|
* 覆盖的文件(都明文含 apiKey / token):
|
|
10
21
|
* ~/.coral/providers.json · agent-providers.json · media-providers.json
|
|
11
22
|
* <项目>/.sps/agent-providers.json · <项目>/.claude/settings.local.json
|
|
12
23
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
24
|
+
* ⚠️ **临时名复用 `infra/filesystem.uniqueTmpPath`**(唯一真源;它的注释解释了为什么不能用固定
|
|
25
|
+
* `${path}.tmp`:并发写者共用中间文件会落地**撕裂内容**)。
|
|
26
|
+
* 🔴 **但没有直接用 `NodeFileSystem.writeFileAtomic`** —— 它的 `writeFileSync(tmp, content)` **不带 mode**,
|
|
27
|
+
* tmp 会以 umask 默认权限(通常 644)存在到 rename 那一刻。对普通配置无所谓,
|
|
28
|
+
* 对**含 token 的文件**那是一个真实的可读窗口(同机任何用户)。含密这条必须自己建 tmp。
|
|
15
29
|
*
|
|
16
30
|
* @layer infra
|
|
17
31
|
*/
|
|
18
|
-
import { chmodSync, existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs';
|
|
32
|
+
import { chmodSync, existsSync, mkdirSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
19
33
|
import { dirname } from 'node:path';
|
|
34
|
+
import { uniqueTmpPath } from './filesystem.js';
|
|
20
35
|
/** 含密文件的目标权限:仅属主可读写。 */
|
|
21
36
|
export const SECRET_MODE = 0o600;
|
|
22
37
|
/**
|
|
23
|
-
* 写一个含密文件:建目录 →
|
|
24
|
-
*
|
|
38
|
+
* 写一个含密文件:建目录 → 写 tmp(0600)→ **rename** → **chmod**。
|
|
39
|
+
*
|
|
40
|
+
* `chmod` 在 rename 之后是**要害**(见模块头):rename 继承 tmp 的位,顺序反了会被覆盖且不报错。
|
|
41
|
+
* ⚠️ tmp 本身就以 `SECRET_MODE` 创建 —— 所以正常路径上 chmod 是第二道保险;
|
|
42
|
+
* 但它不是冗余:**将来任何人改动 tmp 的建法(复用已有 tmp、换成别的 helper),
|
|
43
|
+
* chmod 就是唯一还站着的那道**。这也是为什么顺序要写进注释而不只是写进代码。
|
|
25
44
|
*/
|
|
26
45
|
export function writeSecretFile(path, data) {
|
|
27
46
|
mkdirSync(dirname(path), { recursive: true });
|
|
28
|
-
|
|
47
|
+
const tmp = uniqueTmpPath(path);
|
|
48
|
+
try {
|
|
49
|
+
writeFileSync(tmp, data, { mode: SECRET_MODE });
|
|
50
|
+
renameSync(tmp, path);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
// 尽力删掉 tmp;删不掉也不抛 —— tmp 名带 pid+随机后缀且以 .tmp 结尾,不会被任何读者当成正式文件;
|
|
54
|
+
// 为清理失败而覆盖真正的写入错误,会让调用方看到错误的原因。
|
|
55
|
+
try {
|
|
56
|
+
unlinkSync(tmp);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
/* 残留无害 */
|
|
60
|
+
}
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
29
63
|
hardenSecretFile(path);
|
|
30
64
|
}
|
|
31
65
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secretFile.js","sourceRoot":"","sources":["../../src/infra/secretFile.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"secretFile.js","sourceRoot":"","sources":["../../src/infra/secretFile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5G,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,wBAAwB;AACxB,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,IAAY;IACxD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QAChD,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,8DAA8D;QAC9D,gCAAgC;QAChC,IAAI,CAAC;YACH,UAAU,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,UAAU;QACZ,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;IACD,gBAAgB,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO;QAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,WAAW;QAC7C,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,oBAAoB,IAAI,YAAY,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACjG,CAAC;AACH,CAAC"}
|