Build your own Claude Code
Creating files·12 min

insert

0 / 1
# grade this stage (from your course directory)
npx theinference test --stage insert --watch

create makes a whole file at once. insert is the surgical version: drop a line of text into a file that already exists, at a position you name. The only thing to get exactly right is the indexing convention — and it's a deliberate one. insert_line is 1-indexed and means "after this line": pass 1 to land your text after the first line, and pass 0 to push it to the very top. Off-by-one here is the classic bug, so anchor on that rule before you write a character.

insert_line is the line you insert *after* (0 = top)
file: a\nb\nc          insert("x.txt", 0, "INS")  ->  INS\na\nb\nc   (top)
                      insert("x.txt", 1, "INS")  ->  a\nINS\nb\nc   (after line 1)
                      insert("x.txt", 3, "INS")  ->  a\nb\nc\nINS   (end)

What to build

Your task

Implement Tools.insert

Implement insert(path, insertLine, text) on the Tools class. Resolve through the sandbox guard, error if the file doesn't exist (insert edits, it doesn't create), then split the file on \n, splice text in after line insertLine (so 0 puts it at the top), join back, and write. The trick is that Array.splice(insertLine, 0, text) already encodes "after line N / 0 = top" for free — a 0-indexed splice position equals a 1-indexed "after" line.

src/tools.ts
/** `insert` — insert text after a 1-indexed line (0 = top). */
insert(path: string, insertLine: number, text: string): ToolOutput {
  const { resolved, error } = this.resolve(path);
  if (error) return err(error);
  // 1. if the file does not exist -> err(`not found: ${path}`)
  // 2. const lines = readFileSync(resolved!, "utf8").split("\n")
  // 3. lines.splice(insertLine, 0, text)   // splice index == "after line N", 0 = top
  // 4. write lines.join("\n") back, re-anchor the read-version with hash(next)
  // 5. return ok(`inserted at line ${insertLine}`)
}
Why splice(insertLine, 0, text) is exactly right

splice(i, 0, x) inserts x before the element at 0-indexed position i. Element i is the (i+1)-th line. So splicing at index insertLine puts your text right before line insertLine + 1 — i.e. after 1-indexed line insertLine. insertLine = 0 lands before line 1 (the top); insertLine = lines.length lands at the end. No +1/-1 fiddling needed.

How it's graded

process mode, stdout_json_match. program.ts insert seeds a sandbox file, calls insert, reads the file back, and prints { result, content }. With files: { "x.txt": "a\nb\nc" }, line: 1, text: "INS", the on-disk content must be exactly "a\nINS\nb\nc" — the byte-for-byte file is the assertion, so a stray newline or wrong position fails it.

How the grader runs it
./your_program.sh insert
# case: { files: { "x.txt": "a\nb\nc" }, path: "x.txt", line: 1, text: "INS" }
# -> {"result":{"content":"inserted at line 1"},"content":"a\nINS\nb\nc"}