@henols/c64-re-tools 2.0.0-rc.11 → 2.0.0-rc.13

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.
Files changed (54) hide show
  1. package/README.md +7 -5
  2. package/package.json +1 -1
  3. package/skills/c64-assembler/SKILL.md +11 -2
  4. package/skills/c64-assembler/scripts/assemble.ts +4 -4
  5. package/skills/c64-basic/SKILL.md +8 -1
  6. package/skills/c64-basic/scripts/basic.ts +3 -3
  7. package/skills/c64-disk/SKILL.md +10 -3
  8. package/skills/c64-disk/scripts/disk.ts +4 -4
  9. package/skills/c64-emulator/SKILL.md +4 -0
  10. package/skills/c64-knowledge/SKILL.md +62 -12
  11. package/skills/c64-knowledge/scripts/knowledge.ts +352 -102
  12. package/skills/c64-memory-map/SKILL.md +7 -0
  13. package/skills/c64-memory-map/scripts/memmap.ts +1 -1
  14. package/skills/c64-provenance/SKILL.md +56 -3
  15. package/skills/c64-provenance/scripts/library.ts +584 -0
  16. package/skills/c64-provenance/scripts/provenance.ts +201 -9
  17. package/skills/c64-reverse-engineering/SKILL.md +16 -2
  18. package/skills/c64-source/SKILL.md +38 -7
  19. package/skills/c64-source/scripts/generate.ts +213 -29
  20. package/skills/c64-source/scripts/loader.ts +3 -1
  21. package/skills/c64-source/scripts/opcodes.ts +19 -0
  22. package/skills/c64-source/scripts/source.ts +387 -35
  23. package/skills/c64-static-analysis/SKILL.md +11 -2
  24. package/skills/c64-static-analysis/scripts/analyze.ts +95 -8
  25. package/skills/c64-static-analysis/scripts/macros.ts +233 -0
  26. package/skills/c64-testing/SKILL.md +8 -1
  27. package/skills/c64-testing/references/scenario-format.md +1 -1
  28. package/skills/c64-testing/scripts/checklist.ts +2 -2
  29. package/skills/c64-testing/scripts/run.ts +4 -4
  30. package/skills/c64-testing/scripts/scenario.ts +1 -1
  31. package/skills/c64-testing/scripts/test.ts +4 -4
  32. package/skills/c64-unpacker/SKILL.md +11 -4
  33. package/skills/c64-unpacker/scripts/unpack.ts +4 -4
  34. package/src/cli/main.ts +5 -3
  35. package/src/host-client/image.ts +1 -1
  36. package/src/host-client/transfer.ts +34 -10
  37. package/src/host-client/vice-session.ts +9 -9
  38. package/src/knowledge/conflicts.ts +157 -0
  39. package/src/knowledge/database.ts +150 -38
  40. package/src/knowledge/history.ts +54 -20
  41. package/src/knowledge/import.ts +3 -2
  42. package/src/knowledge/read.ts +169 -20
  43. package/src/knowledge/schema.ts +115 -72
  44. package/src/knowledge/text.ts +391 -0
  45. package/src/knowledge/write.ts +508 -51
  46. package/src/mcp/output.ts +14 -7
  47. package/src/mcp/tools/debug.ts +8 -6
  48. package/src/mcp/tools/media.ts +17 -13
  49. package/src/mcp/tools/memory.ts +9 -5
  50. package/src/mcp/tools/video.ts +6 -5
  51. package/src/platform.ts +28 -5
  52. package/src/project.ts +166 -3
  53. package/src/protocol/tools.ts +1 -1
  54. package/src/script.ts +46 -7
package/README.md CHANGED
@@ -12,8 +12,8 @@ functional-equivalence tests.
12
12
  Architecture in one line: one MCP process owns one VICE instance and is
13
13
  VICE-only; a Host Runtime on the graphical host owns VICE and the tools that
14
14
  come with it (c1541, petcat); skill scripts call the Host Runtime for those,
15
- run ACME, DXA and Ghidra themselves, and keep project knowledge local in
16
- `.c64-re-tools/knowledge.db`.
15
+ run ACME, DXA and Ghidra themselves, and keep project knowledge local as
16
+ text in `.c64-re-tools/knowledge/`.
17
17
  The design is in [`docs/redesign/`](docs/redesign/README.md), and
18
18
  [`docs/plan.md`](docs/plan.md) tracks the implementation.
19
19
 
@@ -37,6 +37,8 @@ npx -y @henols/c64-re-tools@latest install --target claude
37
37
  claude
38
38
  ```
39
39
 
40
+ Several programs in one repository: install once at the root, give each program its own folder, and start the agent at the root. A folder with `.c64-re-tools/` is a project; the agent names one with `--project <folder>`.
41
+
40
42
  `npx -y @henols/c64-re-tools@latest status` shows what works.
41
43
 
42
44
  Until 2.0.0 is released, `@latest` is the old 1.1.0. Use the prerelease instead. For the prerelease, a dev container and debugging, see [docs/debug-install.md](docs/debug-install.md).
@@ -76,7 +78,7 @@ and settings stay unchanged.
76
78
 
77
79
  1. Install for your harness: `--target claude`, `codex`, `pi`, `opencode`, `gemini`, `copilot`, `cursor` or `windsurf`. Without `--target`, `install` installs for all of them.
78
80
  2. Start the Host Runtime and leave it running.
79
- 3. Start the harness in the project, for example `claude` or `codex`, or open the project in Cursor or Windsurf. The harness starts the MCP server and finds the skills by itself.
81
+ 3. Start the harness in the project (or at the root of a repository with several projects), for example `claude` or `codex`, or open the project in Cursor or Windsurf. The harness starts the MCP server and finds the skills by itself.
80
82
  4. Ask for the result you want, in plain words. The agent picks the skills and the `c64_*` tools.
81
83
 
82
84
  Examples:
@@ -93,7 +95,7 @@ Build it, run it in the emulator, and write a test for it.
93
95
  Show me the emulator window.
94
96
  ```
95
97
 
96
- The agent keeps what it learns about the program in `.c64-re-tools/knowledge.db`. Commit that file with the project.
98
+ The agent keeps what it learns about the program as text in `.c64-re-tools/knowledge/`. Commit that folder with the project. After a `git pull` that joined the work of two computers, run `knowledge.ts merge` when a command reports conflicts.
97
99
 
98
100
  ## Skills
99
101
 
@@ -107,7 +109,7 @@ The agent keeps what it learns about the program in `.c64-re-tools/knowledge.db`
107
109
  | c64-basic | BASIC V2 listings and the SYS/USR handoff to machine code. |
108
110
  | c64-unpacker | Packing evidence, and capture of the unpacked program from the emulator. |
109
111
  | c64-memory-map | Platform meaning of addresses and register values. |
110
- | c64-provenance | Byte comparison of releases. |
112
+ | c64-provenance | Byte comparison of releases, and a library of routines that several programs share. |
111
113
  | c64-source | ACME source from the image and the knowledge, checked byte by byte, and a loader for the entry state. |
112
114
  | c64-assembler | ACME builds with diagnostics and symbols. |
113
115
  | c64-testing | Original-against-rebuild scenarios with PASS, FAIL or INCONCLUSIVE. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henols/c64-re-tools",
3
- "version": "2.0.0-rc.11",
3
+ "version": "2.0.0-rc.13",
4
4
  "description": "Agent-friendly Commodore 64 engineering toolkit for reverse engineering, debugging, development and testing.",
5
5
  "license": "MIT",
6
6
  "author": "Henrik Olsson",
@@ -13,9 +13,9 @@ This skill does not run the program and does not change project knowledge.
13
13
 
14
14
  ## Inputs
15
15
 
16
- - The source root: the project directory that holds all source files of the program.
16
+ - The source root: the folder in the project that holds all source files of the program.
17
17
  - The entry source: the main file, relative to the source root.
18
- - The output path: where to write the PRG, relative to the project directory.
18
+ - The output path: where to write the PRG, relative to the project folder.
19
19
  - Optional include directories, symbol definitions and a start address.
20
20
 
21
21
  ## Tools / execution path
@@ -37,6 +37,13 @@ The script copies the full source root. Put all files that the program includes
37
37
 
38
38
  The script prints one JSON object. The target CPU is the 6510 and the output is always a C64 PRG.
39
39
 
40
+ ### Project folder
41
+
42
+ - Paths are relative to the project folder. The project folder is the nearest folder at or above the working directory that holds `.c64-re-tools/`.
43
+ - If the working directory is not in a project and has projects below it, the script refuses and lists them. Then give `--project <folder>` to each script.
44
+ - Keep the results, batches and step files that you save for yourself in `.c64-re-tools/local/` of the project. Git ignores that folder.
45
+ - A shell redirect (`>`) is relative to the working directory, not to the project folder. From the folder above the project, write `<folder>/.c64-re-tools/local/result.json`.
46
+
40
47
  ## Workflow
41
48
 
42
49
  1. Find the source root and the entry source. The entry source sets its own start address with `* = $0801` or similar.
@@ -45,6 +52,8 @@ The script prints one JSON object. The target CPU is the 6510 and the output is
45
52
  4. If `assembled` is `false`, read `diagnostics`. Each one has a severity, a file, a line and a message. Correct the source and run the script again.
46
53
  5. To run the program, give the PRG path to the c64-emulator skill.
47
54
 
55
+ The source of the c64-source skill has switches. Each switch is 0 when the build does not define it. `--define CRACK=1` puts in the patches of the switch `CRACK`. With `--compare`, only the bytes of those patches are different.
56
+
48
57
  ## Knowledge
49
58
 
50
59
  Automatic write:
@@ -16,7 +16,7 @@ import { compareBuild } from "./compare.ts";
16
16
 
17
17
  const USAGE = `assemble.ts --source-root <dir> --entry <file> --out <file.prg> [options]
18
18
 
19
- --source-root <dir> project directory to assemble from; all of it is sent
19
+ --source-root <dir> folder in the project to assemble from; all of it is sent
20
20
  --entry <file> the main source file, relative to the source root
21
21
  --out <file.prg> where to write the program, relative to the project
22
22
  --include <dir> include directory relative to the source root (repeatable)
@@ -61,7 +61,7 @@ async function run(argv: string[]): Promise<{ output: unknown; failed: boolean }
61
61
  try {
62
62
  outPath = resolveProjectPath(out);
63
63
  } catch {
64
- throw new UsageError(`--out must be a path relative to the project directory that stays inside it, not ${out}`);
64
+ throw new UsageError(`--out must be a path relative to the project folder that stays inside it, not ${out}`);
65
65
  }
66
66
  const defines = Object.fromEntries((values.define ?? []).map(parseDefine));
67
67
  let setPc: number | undefined;
@@ -101,8 +101,8 @@ async function run(argv: string[]): Promise<{ output: unknown; failed: boolean }
101
101
  }
102
102
 
103
103
  await runScript(
104
- async () => {
105
- const { output, failed } = await run(process.argv.slice(2));
104
+ async (argv) => {
105
+ const { output, failed } = await run(argv);
106
106
  if (failed) process.exitCode = 1;
107
107
  return output;
108
108
  },
@@ -13,7 +13,7 @@ This skill does not run the program and does not change project knowledge.
13
13
 
14
14
  ## Inputs
15
15
 
16
- - The program: a PRG file, relative to the project directory.
16
+ - The program: a PRG file, relative to the project folder.
17
17
 
18
18
  ## Tools / execution path
19
19
 
@@ -25,6 +25,13 @@ node <skill>/scripts/basic.ts extracted/game.prg
25
25
 
26
26
  The script prints one JSON object. Addresses are `$` and four hex digits.
27
27
 
28
+ ### Project folder
29
+
30
+ - Paths are relative to the project folder. The project folder is the nearest folder at or above the working directory that holds `.c64-re-tools/`.
31
+ - If the working directory is not in a project and has projects below it, the script refuses and lists them. Then give `--project <folder>` to each script.
32
+ - Keep the results, batches and step files that you save for yourself in `.c64-re-tools/local/` of the project. Git ignores that folder.
33
+ - A shell redirect (`>`) is relative to the working directory, not to the project folder. From the folder above the project, write `<folder>/.c64-re-tools/local/result.json`.
34
+
28
35
  ## Workflow
29
36
 
30
37
  1. Run the script on the program.
@@ -11,7 +11,7 @@ import { runScript, UsageError } from "#src/script.ts";
11
11
 
12
12
  const USAGE = `basic.ts <program>
13
13
 
14
- <program> is a PRG file relative to the project directory. The result is one
14
+ <program> is a PRG file relative to the project folder. The result is one
15
15
  JSON object. Addresses are $ and four hex digits.`;
16
16
 
17
17
  async function run(argv: string[]): Promise<{ output: unknown; failed: boolean }> {
@@ -37,8 +37,8 @@ async function run(argv: string[]): Promise<{ output: unknown; failed: boolean }
37
37
  }
38
38
 
39
39
  await runScript(
40
- async () => {
41
- const { output, failed } = await run(process.argv.slice(2));
40
+ async (argv) => {
41
+ const { output, failed } = await run(argv);
42
42
  if (failed) process.exitCode = 1;
43
43
  return output;
44
44
  },
@@ -13,10 +13,10 @@ This skill does not change the disk image and does not change project knowledge.
13
13
 
14
14
  ## Inputs
15
15
 
16
- - The disk image: a `.d64`, `.d71`, `.d81` or `.g64` file, relative to the project directory.
16
+ - The disk image: a `.d64`, `.d71`, `.d81` or `.g64` file, relative to the project folder.
17
17
  - For one file: the file name as the directory shows it.
18
- - To extract a file: the output path, relative to the project directory.
19
- - A T64 tape file or a CRT cartridge file, relative to the project directory.
18
+ - To extract a file: the output path, relative to the project folder.
19
+ - A T64 tape file or a CRT cartridge file, relative to the project folder.
20
20
 
21
21
  ## Tools / execution path
22
22
 
@@ -42,6 +42,13 @@ The script prints one JSON object.
42
42
 
43
43
  File names show the characters that the C64 shows in a directory list. A byte that has no character shows as `{$xx}`, for example `{$c1}`. Write the name in the same form. The letter case of a name is not important. Put the name in single quotes in a shell, for example `'GAME {$c1}'`.
44
44
 
45
+ ### Project folder
46
+
47
+ - Paths are relative to the project folder. The project folder is the nearest folder at or above the working directory that holds `.c64-re-tools/`.
48
+ - If the working directory is not in a project and has projects below it, the script refuses and lists them. Then give `--project <folder>` to each script.
49
+ - Keep the results, batches and step files that you save for yourself in `.c64-re-tools/local/` of the project. Git ignores that folder.
50
+ - A shell redirect (`>`) is relative to the working directory, not to the project folder. From the folder above the project, write `<folder>/.c64-re-tools/local/result.json`.
51
+
45
52
  ## Workflow
46
53
 
47
54
  1. Run `directory`. Find the file in `entries`. Each entry has a `name`, a `type`, a size in `blocks` and the `closed` and `locked` flags.
@@ -23,7 +23,7 @@ const USAGE = `disk.ts <action> <image> [name] [--out <file>]
23
23
  read <image> <name> --out <file> write the bytes of one file into the project
24
24
  crt <file.crt> --out <dir> write each CHIP packet of a cartridge as a PRG
25
25
 
26
- <image> is a .d64, .d71, .d81 or .g64 file, relative to the project directory.
26
+ <image> is a .d64, .d71, .d81 or .g64 file, relative to the project folder.
27
27
  directory and read also take a .t64 tape file, and directory a .crt cartridge
28
28
  file; the script reads those itself. A CRT can have hardware type 0 (normal
29
29
  8K, 16K or Ultimax), 5 (Ocean), 19 (Magic Desk) or 32 (EasyFlash).
@@ -49,7 +49,7 @@ async function run(argv: string[]): Promise<{ output: unknown; failed: boolean }
49
49
  try {
50
50
  outPath = resolveProjectPath(values.out);
51
51
  } catch {
52
- throw new UsageError(`--out must be a path relative to the project directory that stays inside it, not ${values.out}`);
52
+ throw new UsageError(`--out must be a path relative to the project folder that stays inside it, not ${values.out}`);
53
53
  }
54
54
  }
55
55
 
@@ -111,8 +111,8 @@ function local(kind: "t64" | "crt", action: Action, image: string, name: string
111
111
  }
112
112
 
113
113
  await runScript(
114
- async () => {
115
- const { output, failed } = await run(process.argv.slice(2));
114
+ async (argv) => {
115
+ const { output, failed } = await run(argv);
116
116
  if (failed) process.exitCode = 1;
117
117
  return output;
118
118
  },
@@ -52,6 +52,10 @@ For a large result, give `out` with a path in the project. `c64_memory_read`, `c
52
52
 
53
53
  `c64_memmap` keeps RAM, ROM and I/O apart. Use action `summary` to see which code ran. Use action `read` with `out` to keep a coverage run as a file, for example `coverage/attract.bin`. Clear the map before each run that you want to keep apart.
54
54
 
55
+ ### Project folder
56
+
57
+ Paths (`path`, `file` and `out`) are relative to the project folder. A project folder holds `.c64-re-tools/`. The tools use the nearest project folder at or above the folder where the agent started. If that folder is not in a project and has projects below it, a tool with a path refuses and lists them. Then give `project` with the project folder, for example `"project": "game"`. Give the same folder as the `--project` of the skill scripts. A tool without a path does not need `project`.
58
+
55
59
  ## Workflow
56
60
 
57
61
  1. Read the project knowledge for the addresses in the question. Use the c64-knowledge skill.
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  name: c64-knowledge
3
- description: Use this skill to read, write, correct and review the durable knowledge of a C64 project in .c64-re-tools/knowledge.db. It gives the knowledge at an address, and it names symbols, classifies memory regions, sets comments and records references. It also shows the history of each change, and it can revert to an earlier revision. Do not use it for live emulator state or for static analysis.
3
+ description: Use this skill to read, write, correct and review the durable knowledge of a C64 project in .c64-re-tools/knowledge/. It gives the knowledge at an address, and it names symbols, classifies memory regions, sets comments and records references. It records patches and macros for the generated source. It also shows the history of each change, and it can revert to an earlier revision. Do not use it for live emulator state or for static analysis.
4
4
  ---
5
5
 
6
6
  # c64-knowledge
7
7
 
8
8
  ## Purpose
9
9
 
10
- Read, write, correct and review the durable understanding of a C64 project. The knowledge is in `.c64-re-tools/knowledge.db` in the project directory. Git can version that file.
10
+ Read, write, correct and review the durable understanding of a C64 project. The knowledge is text in `.c64-re-tools/knowledge/` in the project folder: one JSON line for each row. Commit that folder with git. The script keeps an index of the text in `.c64-re-tools/local/knowledge.db` and makes the index again when the text changes. Do not commit the index.
11
11
 
12
- This skill is the only write path for conclusions of the user and the LLM. It does not run an emulator or an analyzer.
12
+ This skill is the only write path for conclusions of the user and the LLM. It does not run an emulator or an analyzer. Write the knowledge only with the script. The script checks each write. Do not write or edit the files in `.c64-re-tools/knowledge/` or the index yourself.
13
13
 
14
14
  ## Inputs
15
15
 
@@ -22,8 +22,6 @@ One of these:
22
22
 
23
23
  ## Tools / execution path
24
24
 
25
- Run the script in the project directory. The project directory is the directory that the harness started in.
26
-
27
25
  ```
28
26
  node <skill>/scripts/knowledge.ts <command> [arguments] [options]
29
27
  ```
@@ -41,7 +39,7 @@ The script prints one JSON object. An error prints `{"error": {"code": ..., "mes
41
39
  | Remove a symbol | `remove-symbol '$2100'` |
42
40
  | Classify memory | `classify '$3000' '$303f' sprite` |
43
41
  | Classify a table of records | `classify '$3000' '$303b' bytes --element 6` |
44
- | Many writes as one revision | `apply batch.json`, or `apply -` with the JSON on standard input |
42
+ | Many writes as one revision | `apply -` with the JSON on standard input, or `apply <file>` |
45
43
  | Make memory unknown, and keep the analyzers out of it | `unclassify '$3000' '$303f'` |
46
44
  | Set or remove a comment | `comment '$2100' line Reads joystick 2.` / `uncomment '$2100' line` |
47
45
  | Add or remove a reference | `reference '$2000' '$2100' call` / `unreference ...` |
@@ -49,10 +47,18 @@ The script prints one JSON object. An error prints `{"error": {"code": ..., "mes
49
47
  | Start a file of generated source | `module '$2000' player.asm --title 'Player movement'` / `unmodule '$2000'` |
50
48
  | Write the operand of an instruction as an expression | `operand '$8079' --lo irq_handler --image unpacked/image.json` / `unoperand '$8079'` |
51
49
  | Operand expressions | `operands` with `--start` and `--end` |
50
+ | Replace a range with code when a switch is on | `patch '$100e' '$1010' CRACK --code-file crack.asm --image unpacked/image.json` / `unpatch '$100e'` |
51
+ | Patches and switches | `patches` with `--switch`, and `switches` |
52
+ | Write a macro | `macro inc16 --params dst --body-file inc16.asm` / `unmacro inc16` |
53
+ | Write instructions as one use of a macro | `use '$1005' '$100a' inc16 --args ptr --image unpacked/image.json` / `unuse '$1005'` |
54
+ | Macros and their uses | `macros`, and `uses` with `--start`, `--end` and `--macro` |
52
55
  | Files of generated source | `modules` |
53
56
  | The address spaces that hold knowledge | `spaces` |
54
- | History | `history '$2100'`, `history --name update_player`, `revisions`, `revision 12` |
55
- | Go back to an earlier state | `revert 12` |
57
+ | History | `history '$2100'`, `history --name update_player`, `history --macro inc16`, `revisions`, `revision 20261015T2145` |
58
+ | Go back to an earlier state | `revert 20261015T2145` |
59
+ | Decide the conflicts after a git merge | `merge --reason 'merge of two computers'` |
60
+
61
+ A revision has an id such as `20261015T214501.123-k3f9qz`. The id starts with the date and time. A command takes the full id, or a start of the id that only one revision has. The revision `0` is the knowledge before the first revision.
56
62
 
57
63
  Every command takes `--space`: `c64` (the default), `drive8` for code in the 1541 drive, or `bank0` to `bank255` for cartridge banks. Drive code and banks use the same addresses as the C64, so each space has its own knowledge. A name is unique inside one space. In a batch, a write can name its own `space`.
58
64
 
@@ -73,6 +79,13 @@ Region types:
73
79
 
74
80
  `--element` gives the bytes of one element of a table. The length of the region must be a multiple of it. The result shows `element` and `count`.
75
81
 
82
+ ### Project folder
83
+
84
+ - Paths are relative to the project folder. The project folder is the nearest folder at or above the working directory that holds `.c64-re-tools/`.
85
+ - If the working directory is not in a project and has projects below it, the script refuses and lists them. Then give `--project <folder>` to each script.
86
+ - Keep the results, batches and step files that you save for yourself in `.c64-re-tools/local/` of the project. Git ignores that folder.
87
+ - A shell redirect (`>`) is relative to the working directory, not to the project folder. From the folder above the project, write `<folder>/.c64-re-tools/local/result.json`.
88
+
76
89
  ## Workflow
77
90
 
78
91
  Read:
@@ -89,7 +102,7 @@ Write:
89
102
 
90
103
  Each write is one revision. A classification inside a region splits that region, so regions never overlap.
91
104
 
92
- For more than a few writes, put them in one JSON file and use `apply`. The file is a list of writes. Each write has `op` and the arguments of the command with the same name, for example:
105
+ For more than a few writes, use `apply -` and give the writes on standard input as one JSON list. Each write has `op` and the arguments of the command with the same name, for example:
93
106
 
94
107
  ```json
95
108
  [
@@ -114,12 +127,19 @@ The ops and their fields:
114
127
  | `unmodule` | `start` |
115
128
  | `operand` | `address`, `select` (`lo`, `hi`, `value` or `expr`), `symbol` and `offset` (optional), or `expression` for `expr` |
116
129
  | `unoperand` | `address` |
130
+ | `patch` | `start`, `end`, `switch`, `code` (empty for NOP only), `comment` (optional) |
131
+ | `unpatch`, `unuse` | `start` |
132
+ | `macro` | `name`, `params` (a list or a comma list), `body`, `comment` (optional) |
133
+ | `unmacro` | `name` |
134
+ | `use` | `start`, `end`, `macro`, `args` (a list or a comma list) |
117
135
 
118
- A `line` comment is a line of its own above the address. A `side` comment is at the end of the line of the address. All writes become one revision. If the knowledge refuses one write, the script writes nothing, and the error names the write.
136
+ A `line` comment is a line of its own above the address. A `side` comment is at the end of the line of the address. `apply` with an `operand`, `patch` or `use` write needs `--image`. All writes become one revision. If the knowledge refuses one write, the script writes nothing, and the error names the write.
137
+
138
+ The c64-provenance skill writes a batch with `match --out`. The batch holds the names of library routines at their addresses in this program. Read the `batch.leftOut` of its result first. Then apply the batch with the command in its `apply`.
119
139
 
120
140
  ## Modules
121
141
 
122
- A module tells the c64-source skill where a file of the generated source starts. The file runs to the next module or to the end of its segment. Each address has one module, and each file name has one module. A file name has letters, digits, underscores or hyphens, and ends in `.asm`. The c64-source skill writes `main.asm`, `loader.asm` and `constants.asm` itself. Thus a module cannot have one of these names, in upper or lower case. The title becomes the first line of the file. A `module` write without a title keeps the title that the module has. Modules have a history, and `revert` restores them.
142
+ A module tells the c64-source skill where a file of the generated source starts. The file runs to the next module or to the end of its segment. Each address has one module, and each file name has one module. A file name has letters, digits, underscores or hyphens, and ends in `.asm`. The c64-source skill writes `main.asm`, `loader.asm`, `constants.asm` and `macros.asm` itself. Thus a module cannot have one of these names, in upper or lower case. The title becomes the first line of the file. A `module` write without a title keeps the title that the module has. Modules have a history, and `revert` restores them.
123
143
 
124
144
  ## Operand expressions
125
145
 
@@ -143,6 +163,34 @@ Give one selector:
143
163
 
144
164
  Write an operand expression for each immediate that is a byte of an address. Also write one for each table read through the byte before the table. The pointer candidates of the c64-static-analysis skill show many of these places.
145
165
 
166
+ ## Code switches
167
+
168
+ A patch is ACME code that replaces a range of the image when the build defines its switch as 1. Use patches to change the program, for example for a crack, a trainer or a debug hook. The default build does not define the switch. Thus the c64-source skill still makes a source that is identical to the image.
169
+
170
+ - A switch name is upper case, for example `CRACK` or `TRAINER`. It cannot be the name of a symbol or a platform name.
171
+ - Many patches can have the same switch. The c64-source skill builds each switch on its own. It does not build two switches together.
172
+ - The code must fit in the range. NOP ($EA) fills the bytes after the code. `--nop` gives a range of NOP only.
173
+ - `--code` gives the code as text. `--code-file` reads the code from a project file. The code can use the labels and the macros of the source, and local labels with a dot, for example `.skip`.
174
+ - The braces in the code must be pairs, because the source puts the code inside `{ }`.
175
+ - A patch cannot overlap another patch or a macro use.
176
+ - Give the image with `--image`. Each byte of the range must be in the image.
177
+ - A `patch` write without `--comment` keeps the comment that the patch has.
178
+
179
+ Build the program with a switch on with the c64-assembler skill: `--define CRACK=1`.
180
+
181
+ ## Macros
182
+
183
+ A macro writes a run of instructions as one line of the source, for example `+inc16 ptr`. Use macros to make the source shorter and easier to read.
184
+
185
+ - `macro` writes the ACME macro: its name, its params and its body. `--params` gives the params as a comma list, without a dot. The body uses each param with a dot, for example `.dst`.
186
+ - `use` writes the instructions from the start to the end as one use of a macro. `--args` gives one expression for each param, as a comma list. Each name in an arg is a symbol of the knowledge or a platform name.
187
+ - The range of a use is complete instructions. Give the image with `--image`.
188
+ - A `rename` of a symbol changes the name in each arg. The knowledge refuses `remove-symbol` while an arg uses the symbol.
189
+ - The knowledge refuses `unmacro` while the macro has uses. It also refuses a change of the number of params while the macro has uses.
190
+ - A use cannot overlap a patch or another use.
191
+
192
+ The c64-source skill writes a use only when the use gives the bytes of the image. If not, it writes the instructions and gives the reason. The c64-static-analysis skill finds uses of known 6502 idioms and writes them to a batch with `--macro-batch`.
193
+
146
194
  ## Removals
147
195
 
148
196
  `remove-symbol`, `unclassify` and `unreference` block the place for DXA and Ghidra. An analysis does not add a symbol at that address, a region in that range or that reference again. This applies to every removed fact, also to a fact from the LLM.
@@ -181,7 +229,8 @@ The exit status is 0 for a result. The exit status is 1 for an error from the kn
181
229
  - `conflict`: the change contradicts current knowledge. For example, the name belongs to another address. Read that address and its history, then decide.
182
230
  - `stale-revision`: the knowledge changed after you read it. Read it again, then decide again.
183
231
  - `not-found`: there is nothing to remove or no such revision.
184
- - `invalid-database` or `unsupported-schema`: tell the user the message. Do not edit the file.
232
+ - `conflict` with "from a git merge": git joined the knowledge of two computers, and two rows are current where the knowledge permits one row. For example, two names are at one address. Every read shows these rows in `conflicts`. Writes stop until you run `merge`. The `merge` command keeps the newest row of each conflict and closes the other rows, in one revision. Its result lists each choice. Tell the user the choices.
233
+ - `invalid-database` or `unsupported-schema`: tell the user the message. Do not edit the knowledge files.
185
234
 
186
235
  A revert makes a new revision. The history stays complete.
187
236
 
@@ -190,3 +239,4 @@ A revert makes a new revision. The history stays complete.
190
239
  - Runtime evidence → c64-emulator
191
240
  - Static evidence → c64-static-analysis
192
241
  - Source from the knowledge → c64-source
242
+ - Names of routines that other programs share → c64-provenance