MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / write

Method write

src/filesystem/transaction.ts:69–124  ·  view source on GitHub ↗
(filePath: string, content: string)

Source from the content-addressed store, hash-verified

67 private toolCallId?: string,
68 ) {}
69
70 async write(filePath: string, content: string): Promise<void> {
71 this.ensureOpen();
72 const abs = path.resolve(filePath);
73
74 // ─── Autonomy-contract scope gate (--scope) ───
75 // When a headless contract run pins a write scope, edits outside it are refused
76 // BEFORE anything touches disk. No-op unless a scope root is registered (see
77 // autonomy-contract.ts). Rollback/undo paths write via fs directly — never gated.
78 {
79 const denial = checkWriteScope(abs);
80 if (denial) {
81 logger.info('Scope gate refused write', { txnId: this.id, path: abs });
82 throw new Error(denial);
83 }
84 }
85
86 let beforeContent: string | null = null;
87 let beforeHash: string | null = null;
88 let isCreate = false;
89
90 try {
91 beforeContent = await fs.readFile(abs, 'utf-8');
92 beforeHash = hashContent(beforeContent);
93 } catch (e: any) {
94 if (e.code === 'ENOENT') {
95 isCreate = true;
96 } else {
97 throw e;
98 }
99 }
100
101 // ─── Pre-commit syntax gate ───
102 // Parse the candidate content (tree-sitter, in-process) BEFORE it touches the
103 // disk. Refuses only when the edit would turn a clean-parsing file into a broken
104 // one (baseline tolerance) — see syntax-check.ts. The throw surfaces to the model
105 // as a [SYNTAX_REJECTED] tool-result observation; the file on disk stays intact.
106 // Rollback/undo paths use fs.writeFile directly and are NOT gated.
107 // Off-switch: discipline.syntaxGate: false
108 {
109 const { checkSyntaxForWrite } = await import('../tools/ast/syntax-check.js');
110 const rejection = await checkSyntaxForWrite(abs, beforeContent, content);
111 if (rejection) {
112 logger.info('Syntax gate refused write', { txnId: this.id, path: abs });
113 throw new Error(rejection);
114 }
115 }
116
117 if (beforeContent !== null) {
118 await this.journal.storeBlob(beforeHash!, beforeContent);
119 }
120
121 const afterHash = hashContent(content);
122 await this.journal.storeBlob(afterHash, content);
123
124 await fs.mkdir(path.dirname(abs), { recursive: true });
125 await writeFileAtomic(abs, content, { encoding: 'utf-8' });
126

Callers

nothing calls this directly

Calls 9

ensureOpenMethod · 0.95
checkSyntaxForWriteFunction · 0.85
writeFileAtomicFunction · 0.85
resolveMethod · 0.80
infoMethod · 0.80
storeBlobMethod · 0.80
debugMethod · 0.80
hashContentFunction · 0.70
pushMethod · 0.45

Tested by

no test coverage detected