INSTRUCTIONS
What the model is told when it connects: the way of working, in brief. tcm_guide has the rest.
export const INSTRUCTIONS = `This project's code is a tcm codebase (.tcm/codebase.sqlite): Unison's codebase model for TypeScript. Each top-level definition is stored by the hash of its code, and names (dotted paths, like lib.math.square) point at hashes. The codebase is the truth: there are no source files to edit (anything under .tcm/ is generated). To change code: 1. Find it: tcm_find searches names, docs and signatures (or types: ":(xs: T[]) => T"); tcm_search finds text in the code, as find in files does; tcm_view shows definitions with their current names ("grep" or "lines" for part of a large one); tcm_dependents and tcm_deps follow references; tcm_at says which definition a line of a file (a stack trace's, say) is in. 2. For a small change, tcm_patch does it in one step: find-and-replace on a definition's code as tcm_view shows it, checked and saved ("patches" for several definitions that change together, pages documenting them included, saved as one). New code: tcm_add, with the code and its namespace. For more, tcm_edit the definitions you'll change. It writes them into a scratch file: ordinary TypeScript that imports the rest of the codebase from "#codebase/…". Edit that file with your usual file tools. 3. tcm_check imports what the file uses and doesn't (writing the imports into it), typechecks it and says what saving would do; tcm_update saves it (and deletes it: what it held is in the codebase). Dependents are re-hashed automatically; any that stop typechecking are in tcm_todo: fix them the same way (tcm_edit, then tcm_update; tcm_edit and tcm_patch write them using the current versions of what changed, by name, and say so). 4. Tests are definitions named test… (or anything under a tests namespace). tcm_test runs them, cached by hash: only the tests your change reaches run again. Something long (many tests, a build): "background": true, then tcm_job. Habits that pay off here: - Keep definitions apart. Definitions that refer to each other are hashed as one cycle: a change to one re-hashes and re-checks them all, and editing one brings the rest along. Saving warns when it makes a cycle or a bigger one; one that's only types (a function taking the class that calls it) is broken by typing it with an interface of what it needs. - Imports follow the code: in tcm_patch, use a name and it's imported (from the codebase, a package the code uses, tcm's modules or Node's); stop using it and it goes. Don't edit import lines: one it can't find that way (an alias) goes in tcm_patch's "imports". tcm_add, tcm_check and tcm_update import what's missing the same way, and saving a scratch file (or a conflict's) takes out imports nothing in it uses. - Change together what changes together, in one scratch file or one patches call: a class and its users, a type and its values. What the file imports that uses what it changes is re-derived and saved with it, in an order that typechecks; each definition is stored with its own names. Two functions or classes declared alike (find from two namespaces) can't share a scratch file (a function's name is part of its hash): tcm_edit says so, edit the second in a file of its own ("file"). - tcm_patch takes text as tcm_view shows it, doc comments included (a doc can be given on one line), and inside a template literal, escapes as the source writes them (in JSON, a backslash doubled). An old found only with its escapes taken the other way (a line break for backslash-n, a bare backtick for an escaped one) is matched so when that finds it once, and said; a new that would end or split the literal (a bare backtick or \${) is refused. - Code that doesn't parse is said by its first syntax error alone, with the lines around it: fix that first; type errors come once it parses. - A conflicted name after a merge (tcm_todo labels its definitions ours and theirs): tcm_edit it, and a file of its own (named after it) holds its sides merged from the base, with conflict markers only where both changed the same lines, and it says what each side changed and whether the merge typechecks; one using another conflicted name is edited with it (tcm_edit both); settle the markers and tcm_update resolves it, once. tcm_resolve keeps one side whole. - To show a bug is in an older tcm, or a new end-to-end test fails before the fix (developing tcm itself), compare with a kept build: "known-good" (main's last verified, without your change) or "previous" (the one before); tcm_cli ["builds"] lists them. tcm_test with "bin": {"tcm": "known-good"} runs the suites against one; tcm_cli with "build" and "cwd" runs a command with it on a repro's codebase. - Say what each change is for: tcm_patch, tcm_update, tcm_add, tcm_mv, tcm_rm and tcm_resolve take a "message" (a line saying what and why, then more after a blank line if it helps), kept with the history entry the change makes and shown as its title in tcm_history and the web UI. tcm_merge requires one for a landing: what the whole branch did and why, as main's history will say it. tcm_cli ["describe", "<n>", "-m", "…"] changes one afterwards. - What's saved is in the codebase, not in files: tcm_view it again rather than keeping your own copy, and change it with the tools rather than editing generated files under .tcm/. Renames are tcm_mv: references are by hash, so nothing else changes. tcm_status shows where things stand: what's in the codebase, unsaved scratch work, and what needs doing. tcm_guide explains more: the model, editing, testing, apps, packages and releases, mirrors. Any other command: tcm_cli.`