@henols/c64-re-tools 2.0.0-rc.20 → 2.0.0-rc.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henols/c64-re-tools",
3
- "version": "2.0.0-rc.20",
3
+ "version": "2.0.0-rc.21",
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",
@@ -7,7 +7,7 @@ description: Use this skill to write the documentation of a C64 program. The doc
7
7
 
8
8
  ## Purpose
9
9
 
10
- Write documentation that tells how a program works, and that points to the code. The documentation is Markdown in the project, for example in `docs/`. It has two parts:
10
+ Write documentation that tells how a program works, and that points to the code. The documentation is Markdown in the project. The entry page is `README.md` in the project folder. The other pages and the reference are in `docs/`. The documentation has two parts:
11
11
 
12
12
  - **The reference.** `generate.ts` generates it from the knowledge, the source map of c64-source and the image. It has a page for each module. The page gives the routines, their callers and callees, the data and a call graph. It also has pages for the names, the variables, the tables, the memory map and the graphics. Do not edit these pages. The next run writes over them.
13
13
  - **The pages that you write.** They tell how the program works. They give the flows, the state machines, the data formats and the task of each part. Use the page types in `references/page-types.md` and the rules in `references/style.md`.
@@ -20,7 +20,7 @@ This skill does not change the knowledge.
20
20
 
21
21
  - The source directory of c64-source, with its `source-map.json`, for example `src`. The source must be from the current knowledge revision.
22
22
  - The program in the knowledge. Put it in with `image` of the c64-knowledge skill. The reference decodes the tables and shows the graphics from it.
23
- - The directory of the documentation, for example `docs`. The reference goes into a directory of its own, for example `docs/reference`.
23
+ - The entry page `README.md` and the directory of the other pages, for example `docs`. The reference goes into a directory of its own, for example `docs/reference`.
24
24
 
25
25
  ## Tools / execution path
26
26
 
@@ -28,16 +28,16 @@ The scripts run on this machine. They do not use the emulator or the host runtim
28
28
 
29
29
  ```
30
30
  node <skill>/scripts/generate.ts --source src --out docs/reference
31
- node <skill>/scripts/link.ts docs --source src
32
- node <skill>/scripts/link.ts docs --source src --check
31
+ node <skill>/scripts/link.ts README.md docs --source src
32
+ node <skill>/scripts/link.ts README.md docs --source src --check
33
33
  ```
34
34
 
35
35
  | Option | Meaning |
36
36
  |---|---|
37
37
  | `--source src` | The source directory of c64-source. Both scripts read `src/source-map.json`. |
38
38
  | `--out docs/reference` | The directory of the reference. `generate.ts` writes only there. It refuses to start when the directory holds a page that it did not write. |
39
- | `docs` | The directory of the documentation. `link.ts` reads every `.md` file below it. It changes only the pages that you wrote. It checks the pages of the reference. |
40
- | `--reference <dir>` | The directory of the reference for `link.ts`. The default is `docs/reference` when it exists. |
39
+ | `README.md docs` | The pages of the documentation: `.md` files and directories. `link.ts` reads each file and every `.md` file below each directory. It changes only the pages that you wrote. It checks the pages of the reference. |
40
+ | `--reference <dir>` | The directory of the reference for `link.ts`. The default is the `reference` directory of the first directory that has one, for example `docs/reference`. |
41
41
  | `--check` | `link.ts` writes nothing. It fails when a link is not up to date or a page has a problem. |
42
42
 
43
43
  ### Project folder
@@ -50,15 +50,16 @@ node <skill>/scripts/link.ts docs --source src --check
50
50
  1. Read the knowledge with the c64-knowledge skill. The documentation can only be as good as the knowledge. Each routine needs a name and a comment. Each table needs a region and a name. Each file of the source needs a module with a title. Record what is missing with c64-knowledge.
51
51
  2. Generate the source with c64-source. Make sure that `check.identical` is `true`. The script also writes `source-map.json`.
52
52
  3. Run `generate.ts`. Read `index.md` of the reference. A module with no routines, or a routine with no comment, shows what the knowledge does not have yet.
53
- 4. Make the plan of the pages. Start from the modules and the call graphs. Find the main loop, the interrupt chain, the dispatch tables, the state machines and the data formats. Each subsystem gets one page. The entry page lists the pages. Use the page types in `references/page-types.md`.
53
+ 4. Make the plan of the pages. Start from the modules and the call graphs. Find the main loop, the interrupt chain, the dispatch tables, the state machines and the data formats. Each subsystem gets one page in `docs/`. The entry page `README.md` in the project folder lists the pages. Use the page types in `references/page-types.md`.
54
54
  5. Write each page. Read the code and the knowledge for each fact. Run the program with c64-testing or c64-emulator when a fact needs a run. Write each name with its address, for example `` `draw_room` `$09BC` ``. Mark each fact with its evidence. Several subagents can write the pages at the same time, one page each. Give each subagent `references/page-types.md` and `references/style.md`.
55
55
  6. Record each new fact in the knowledge first: a name, a comment, a region or a module. Then the source and the reference show it too. A fact only in a page is lost at the next change of the knowledge.
56
56
  7. Run `link.ts`. Read `problems` and correct each one. Then run `link.ts --check`. Make sure that `problems.count` is 0 and that `notUpToDate.links` is 0.
57
- 8. After each change to the knowledge, do steps 2, 3 and 7 again. The links then go to the new lines.
57
+ 8. When the project folder is in a workspace with other projects, find `README.md` at the root of the workspace. This page lists each program of the workspace. Add one row for the program, with a link to `<project>/README.md` and one sentence. If the page does not exist, make it. Use the workspace index in `references/page-types.md`. `link.ts` does not read this page, because the page is not in the project folder.
58
+ 9. After each change to the knowledge, do steps 2, 3 and 7 again. The links then go to the new lines.
58
59
 
59
60
  ## The links
60
61
 
61
- `link.ts` changes these forms in the pages that you write. It does not change a code block, a mermaid diagram or an HTML comment.
62
+ `link.ts` changes these forms in the pages that you write. It does not change a code block, a mermaid diagram or an HTML comment. The examples are for a page in `docs/`. In `README.md`, the links start with `src/` and `docs/reference/`.
62
63
 
63
64
  | You write | `link.ts` writes |
64
65
  |---|---|
@@ -4,15 +4,16 @@ Each page that you write is one of these types. The types come from the document
4
4
 
5
5
  ## 1. The entry page
6
6
 
7
- One entry page for the program, for example `docs/README.md` or `docs/rooms.md` for one large subsystem. It has these parts, in this order:
7
+ One entry page for the program: `README.md` in the project folder. A large subsystem can have an entry page of its own in `docs/`, for example `docs/rooms.md`. The entry page of the program has these parts, in this order:
8
8
 
9
9
  1. **One paragraph.** What the program is, and which release the documentation is for.
10
10
  2. **The table of pages.** One row for each page, with the link and one sentence about its content.
11
11
  3. **The layers.** A mermaid diagram of the layers of the program. The layers are the data, the code that runs one time, the main loop and the interrupts. Under the diagram, a numbered list tells how the layers work together.
12
12
  4. **The flow of a user.** A mermaid diagram of the steps of the player or user from start to end. An example is the order of the levels.
13
13
  5. **Findings.** A table of the facts that a reader does not expect, each with its evidence. Put a bug of the original program here.
14
- 6. **The reference.** A link to `reference/index.md`.
14
+ 6. **The reference.** A link to `docs/reference/index.md`.
15
15
  7. **Still open.** What is not known yet, and which run can find it.
16
+ 8. **The release and the rebuild.** What the release holds, for example a crack with a cracktro and a mover. Which part is the clean program of the knowledge. Which changes of the release to the machine state stay, and how the loader sets them. How the source assembles to the clean program, and which scenarios compare the original with the rebuild.
16
17
 
17
18
  ```markdown
18
19
  # <Program>: <subject>
@@ -21,7 +22,7 @@ One entry page for the program, for example `docs/README.md` or `docs/rooms.md`
21
22
 
22
23
  | Page | Content |
23
24
  |---|---|
24
- | [parts/main_loop.md](parts/main_loop.md) | **The main loop.** <one sentence> |
25
+ | [parts/main_loop.md](docs/parts/main_loop.md) | **The main loop.** <one sentence> |
25
26
 
26
27
  ## 1. The layers
27
28
 
@@ -31,23 +32,50 @@ flowchart TB
31
32
  ...
32
33
  ~~~
33
34
 
34
- ## 2. Findings
35
+ ## 2. The flow of a player
36
+
37
+ ...
38
+
39
+ ## 3. Findings
35
40
 
36
41
  | Finding | Evidence |
37
42
  |---|---|
38
43
  | <fact> | Observed: <what run showed it> |
39
44
 
40
- ## 3. Still open
45
+ ## 4. The reference
46
+
47
+ [docs/reference/index.md](docs/reference/index.md)
48
+
49
+ ## 5. Still open
41
50
 
42
51
  - <question> — <the run that can answer it>
52
+
53
+ ## 6. The release and the rebuild
54
+
55
+ - **The release.** <the file on the disk, and what the release adds to the program>
56
+ - **The rebuild.** <the source, the loader and the scenarios>
57
+ ```
58
+
59
+ ## 2. The workspace index
60
+
61
+ A workspace with several projects has one `README.md` at its root. It lists each program of the workspace. It has a title, one sentence and a table with one row for each program. Each row has a link to the entry page of the program and one sentence about the program.
62
+
63
+ ```markdown
64
+ # C64 games
65
+
66
+ Reverse-engineered C64 games. Each game has its own folder with the original disk, the rebuilt source and the documentation.
67
+
68
+ | Game | |
69
+ |---|---|
70
+ | [Bruce Lee](bruce_lee/README.md) | Datasoft 1984. How the program works, from the cold start to the last room. |
43
71
  ```
44
72
 
45
- ## 2. The subsystem page
73
+ ## 3. The subsystem page
46
74
 
47
75
  One page for each subsystem, for example the main loop, the interrupt chain, the room generation or the sound player. It has these parts:
48
76
 
49
77
  1. **The scope.** A list of what the page covers, and the sources (the source files, the assets).
50
- 2. **The conventions.** The terms of the page, for example "a pass is one run of `main_loop` `$1BC2`". Also the evidence labels. Use the conventions block of section 5.
78
+ 2. **The conventions.** The terms of the page, for example "a pass is one run of `main_loop` `$1BC2`". Also the evidence labels. Use the conventions block of section 6.
51
79
  3. **The overview.** A short text diagram or a mermaid flowchart of the calls, from the entry of the subsystem to its end.
52
80
  4. **The catalogue.** A table of the data of the subsystem. Each row has the name, the address, the layout (bytes, entries, the meaning of each byte), the readers and the writers.
53
81
  5. **The step-by-step walk.** For each main routine: a numbered list of what it does, in the order of the code. Each step gives the names and addresses. Add pseudo-code when a loop or a condition is not clear from the list.
@@ -71,7 +99,7 @@ stateDiagram-v2
71
99
  | Waiting `$00` | `move_timer` = 0 | Moving `$01` | `update_slider` `$3F8C` |
72
100
  ```
73
101
 
74
- ## 3. The entity sections
102
+ ## 4. The entity sections
75
103
 
76
104
  A program often has many items of one kind: levels, rooms, enemies, tunes. Give each item one section of the same form, in a page for a group of items. Each section has these parts:
77
105
 
@@ -83,7 +111,7 @@ A program often has many items of one kind: levels, rooms, enemies, tunes. Give
83
111
 
84
112
  End the group page with a table of the dependencies between the items.
85
113
 
86
- ## 4. The data-format page
114
+ ## 5. The data-format page
87
115
 
88
116
  One page for each format of data, for example a packed map, a music stream or a sprite format. It has these parts:
89
117
 
@@ -101,7 +129,7 @@ One page for each format of data, for example a packed map, a music stream or a
101
129
  | `$01-$7F` | The next byte, `b` times. |
102
130
  ```
103
131
 
104
- ## 5. The conventions block
132
+ ## 6. The conventions block
105
133
 
106
134
  Put this block near the top of each subsystem page. Change the terms for the program.
107
135
 
@@ -16,13 +16,14 @@ import { checkLinks, linkPage, type Files, type Problem } from "./lib/links.ts";
16
16
  import { GENERATED_MARK } from "./lib/reference.ts";
17
17
  import { readSourceMap } from "./lib/source-map.ts";
18
18
 
19
- const USAGE = `link.ts <docs> --source <dir> [--reference <dir>] [--check]
19
+ const USAGE = `link.ts <pages>... --source <dir> [--reference <dir>] [--check]
20
20
 
21
- <docs> the documentation directory, relative to the project folder;
22
- link.ts reads every .md file below it
21
+ <pages>... .md files and directories of the documentation, relative to
22
+ the project folder, for example README.md docs; link.ts reads
23
+ each file and every .md file below each directory
23
24
  --source <dir> the source directory of c64-source, with its source-map.json
24
- --reference <dir> the reference pages of generate.ts; the default is
25
- <docs>/reference when it exists
25
+ --reference <dir> the reference pages of generate.ts; the default is the
26
+ reference/ folder of the first directory that has one
26
27
  --check write nothing; fail when a link is not up to date or a page
27
28
  has a problem
28
29
 
@@ -34,9 +35,14 @@ const MAX_LISTED = 50;
34
35
  /** A name outside the image covers the addresses up to the next name, at most this many. */
35
36
  const MAX_BODY = 256;
36
37
 
38
+ const isDirectory = (path: string) => {
39
+ const real = resolveProjectPath(path);
40
+ return existsSync(real) && statSync(real).isDirectory();
41
+ };
42
+
37
43
  function markdownFiles(directory: string): string[] {
38
44
  const root = resolveProjectPath(directory);
39
- if (!existsSync(root) || !statSync(root).isDirectory()) throw new WireFailure("not-found", `There is no directory ${directory} in the project folder.`);
45
+ if (!isDirectory(directory)) throw new WireFailure("not-found", `There is no directory ${directory} in the project folder.`);
40
46
  const found: string[] = [];
41
47
  const walk = (relative: string) => {
42
48
  for (const entry of readdirSync(join(root, relative), { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
@@ -79,15 +85,19 @@ const files: Files = {
79
85
  function run(argv: string[]): { output: Record<string, unknown>; failed: boolean } {
80
86
  const { values, positionals } = parseArgs({ args: argv, strict: true, allowPositionals: true, options: { source: { type: "string" }, reference: { type: "string" }, check: { type: "boolean" }, help: { type: "boolean" } } });
81
87
  if (values.help) throw new UsageError("");
82
- if (positionals.length !== 1) throw new UsageError("give one documentation directory");
88
+ if (positionals.length === 0) throw new UsageError("give the pages: .md files and directories of the documentation, for example README.md docs");
83
89
  if (values.source === undefined) throw new UsageError("give --source <dir>: the source directory of c64-source");
84
- const docs = posix.normalize(positionals[0]!);
85
- for (const [option, path] of [["<docs>", docs], ["--source", values.source], ["--reference", values.reference]] as const) {
90
+ const given = [...new Set(positionals.map((path) => posix.normalize(path)))];
91
+ for (const [option, path] of [...given.map((path) => ["<pages>", path] as const), ["--source", values.source], ["--reference", values.reference]] as const) {
86
92
  if (path === undefined) continue;
87
93
  if (!files.inside(path)) throw new UsageError(`${option} must be a path relative to the project folder that stays inside it, not ${path}`);
88
94
  }
95
+ for (const path of given) {
96
+ if (!path.endsWith(".md") && files.exists(path) && !isDirectory(path)) throw new UsageError(`<pages> takes .md files and directories, not ${path}`);
97
+ }
98
+ const directories = given.filter((path) => !path.endsWith(".md") || isDirectory(path));
89
99
  const map = readSourceMap(values.source);
90
- const reference = values.reference === undefined ? (existsSync(resolveProjectPath(posix.join(docs, "reference"))) ? posix.join(docs, "reference") : undefined) : posix.normalize(values.reference);
100
+ const reference = values.reference === undefined ? directories.map((path) => posix.join(path, "reference")).find((path) => isDirectory(path)) : posix.normalize(values.reference);
91
101
  const problems: Problem[] = [];
92
102
  const db = openForRead();
93
103
  let symbols;
@@ -158,7 +168,11 @@ function run(argv: string[]): { output: Record<string, unknown>; failed: boolean
158
168
  managed: (path: string) => inside(path, posix.normalize(map.directory)) || inside(path, reference),
159
169
  };
160
170
 
161
- const pages = markdownFiles(docs);
171
+ const pages = [...new Set(given.flatMap((path) => {
172
+ if (directories.includes(path)) return markdownFiles(path);
173
+ if (files.text(path) === undefined) throw new WireFailure("not-found", `There is no file ${path} in the project folder.`);
174
+ return [path];
175
+ }))];
162
176
  const changedPages: string[] = [];
163
177
  let links = 0;
164
178
  for (const page of pages) {
@@ -87,7 +87,7 @@ Do the stages in this sequence. Go to the next stage only when its exit check is
87
87
  | 7. Name | c64-provenance: if the workspace has a library, find its routines with `match` and apply the batch. Then c64-knowledge and c64-memory-map: name each routine in the scope and give it a comment. Record the modules. When the scope has hundreds of routines, ask the user which routines to name. The source gives the other routines an `l_xxxx` label. | Each routine that the user selected has a name and a comment. |
88
88
  | 8. Generate | c64-source into `src/`. For an unpacked program, add `--loader`. | `check.identical` is true. For an unpacked program, `loader.verified` is true. |
89
89
  | 9. Build and test | c64-assembler with `--compare` into `build/`. c64-testing scenarios in `tests/`. | The criteria of stage 1 are true. |
90
- | 10. Document | When the criteria ask for documentation: c64-docs into `docs/`. | `link.ts --check` of c64-docs gives no problem. |
90
+ | 10. Document | When the criteria ask for documentation: c64-docs into `README.md` and `docs/`. | `link.ts --check` of c64-docs gives no problem. |
91
91
  | 11. Hand over | Find each file that you made outside `.c64-re-tools/local/` and that is not a deliverable. Move it into `.c64-re-tools/local/`. Then give the answer (below). | Each file that you made outside `.c64-re-tools/local/` is a deliverable. |
92
92
 
93
93
  In stage 5, if you cannot get to a part of the program, ask the user how to get to it. Do stages 7 and 8 again until the source is clear. Each run of c64-source writes the source again.
@@ -100,7 +100,7 @@ After stage 7, save each routine that other programs can have to the library wit
100
100
  - the generated source
101
101
  - the built program and the loader
102
102
  - the c64-testing scenarios
103
- - the documentation in `docs/`, when the criteria ask for it
103
+ - the documentation in `README.md` and `docs/`, when the criteria ask for it
104
104
  - the runs in `runs/` that the knowledge gives as evidence
105
105
  - the scripts in `tools/` for the formats of this program, when you wrote them.
106
106
 
@@ -128,6 +128,7 @@ tests/ c64-testing scenarios
128
128
  runs/ the runs that the knowledge gives as evidence
129
129
  docs/ the documentation from c64-docs, with the reference in docs/reference/
130
130
  tools/ scripts for the formats of this program only
131
+ README.md the entry page of the documentation from c64-docs
131
132
  ```
132
133
 
133
134
  Commit each folder of the layout and `.c64-re-tools/knowledge/`. The knowledge holds the program, the entry state and the coverage, so the project needs no other folder for them. Put all other files that you make in `.c64-re-tools/local/`, also the captures and the coverage maps after you put them into the knowledge. Do not let git ignore a folder of the layout. Do not change the `.gitignore` files of the project.
@@ -8,10 +8,10 @@
8
8
  // passes, 1 when one fails, 2 for a bad call.
9
9
 
10
10
  import { existsSync, readdirSync, readFileSync, rmSync } from "node:fs";
11
- import { join, posix } from "node:path";
11
+ import { join } from "node:path";
12
12
  import { parseArgs } from "node:util";
13
13
 
14
- import { COVERAGE, coverageSeedKinds, formatC64Address, parseC64Address, prgRange, textToPetscii } from "#src/c64.ts";
14
+ import { COVERAGE, coverageSeedKinds, formatC64Address, parseC64Address, textToPetscii } from "#src/c64.ts";
15
15
  import { autostartLoaded, RUN_LIMIT_FRAMES } from "#src/host-client/autostart.ts";
16
16
  import { MAX_MEMORY_READ, WireFailure } from "#src/host-client/tools.ts";
17
17
  import { writeProjectFile } from "#src/host-client/transfer.ts";
@@ -104,7 +104,6 @@ async function runSteps(client: ViceSessionClient, steps: ActionStep[]): Promise
104
104
  async function trace(program: string, options: { frames: number; entry?: number; steps: ActionStep[] }): Promise<{ output: Record<string, unknown>; failed: boolean }> {
105
105
  const { bytes } = readProjectFile(program);
106
106
  if (bytes.length < 3) throw new UsageError("the file is too short for a PRG");
107
- const load = bytes[0]! | (bytes[1]! << 8);
108
107
  if (options.entry === undefined && basicStart(bytes) === undefined) throw new UsageError(NO_BASIC);
109
108
  const client = await ViceSessionClient.open({ videoStandard: "pal" });
110
109
  try {
@@ -3,38 +3,11 @@
3
3
 
4
4
  import { COVERAGE, type CodeRange } from "../c64.ts";
5
5
  import { MAX_MEMMAP_RANGES, type MemmapRange } from "../protocol/vice.ts";
6
- import { readProjectFile } from "./transfer.ts";
7
6
  import type { ViceSessionClient } from "./vice-session.ts";
8
7
 
9
8
  /** A full coverage file: offset n is address n (D40). */
10
9
  export const FULL_COVERAGE = 0x10000;
11
10
 
12
- /** Reads full coverage files from the project, one map per file. `fail` refuses a file of another size. */
13
- export function readCoverageMaps(paths: string[], fail: (message: string) => never): Uint8Array[] {
14
- return paths.map((path) => {
15
- const { bytes } = readProjectFile(path);
16
- if (bytes.length !== FULL_COVERAGE) {
17
- fail(`--coverage ${path} has ${bytes.length} bytes; a full coverage file has 65536, one for each address. Write it with c64_memmap action read and out, without start and end.`);
18
- }
19
- return bytes;
20
- });
21
- }
22
-
23
- /** Joins coverage maps: an address has every flag that any run gave it. */
24
- export function joinCoverage(maps: readonly Uint8Array[]): Uint8Array {
25
- const joined = new Uint8Array(FULL_COVERAGE);
26
- for (const map of maps) for (let address = 0; address < FULL_COVERAGE; address++) joined[address]! |= map[address]!;
27
- return joined;
28
- }
29
-
30
- /**
31
- * Reads full coverage files from the project and joins them: an address has
32
- * every flag that any run gave it. `fail` refuses a file of another size.
33
- */
34
- export function readCoverageFiles(paths: string[], fail: (message: string) => never): Uint8Array | undefined {
35
- return paths.length === 0 ? undefined : joinCoverage(readCoverageMaps(paths, fail));
36
- }
37
-
38
11
  /** The coverage bytes of start..end, read from the session in parts. */
39
12
  export async function readCoverage(session: Pick<ViceSessionClient, "memmap">, start = 0x0000, end = 0xffff): Promise<Uint8Array> {
40
13
  const map = new Uint8Array(end - start + 1);
@@ -1,5 +1,5 @@
1
- // The image that a skill script works on: an image.json of the c64-unpacker
2
- // skill (a 64 KiB memory and its segments) or a PRG, read from the project.
1
+ // An image.json of the c64-unpacker skill (a 64 KiB memory and its segments)
2
+ // or a PRG, read from the project to put it into the knowledge (D83).
3
3
 
4
4
  import { posix } from "node:path";
5
5
 
@@ -12,12 +12,9 @@ export class ImageError extends Error {
12
12
  }
13
13
 
14
14
  export interface Image {
15
- path: string;
16
15
  segments: Array<{ start: number; end: number }>;
17
16
  /** The byte at an address inside a segment. */
18
17
  byteAt: (address: number) => number;
19
- /** The bytes that Ghidra analyzes, and how. */
20
- analyzed: { bytes: Buffer; kind: "prg" | "flat64k" };
21
18
  entry?: number;
22
19
  /** entry_state.json next to image.json. */
23
20
  statePath?: string;
@@ -35,7 +32,7 @@ export function readImage(path: string): Image {
35
32
  } catch (error) {
36
33
  throw new ImageError(`${path}: ${(error as Error).message}`);
37
34
  }
38
- return { path, segments: [{ start: range.start, end: range.end }], byteAt: (address) => range.body[address - range.start]!, analyzed: { bytes, kind: "prg" } };
35
+ return { segments: [{ start: range.start, end: range.end }], byteAt: (address) => range.body[address - range.start]! };
39
36
  }
40
37
  const fail = (what: string): never => {
41
38
  throw new ImageError(`${path} is not an image.json of the c64-unpacker skill: ${what}`);
@@ -59,7 +56,7 @@ export function readImage(path: string): Image {
59
56
  const directory = posix.dirname(path);
60
57
  const memory = readProjectFile(posix.join(directory, manifest.image as string)).bytes;
61
58
  if (memory.length !== 0x10000) fail(`its image has ${memory.length} bytes, not 65536`);
62
- const image: Image = { path, segments, byteAt: (at) => memory[at]!, analyzed: { bytes: memory, kind: "flat64k" }, statePath: posix.join(directory, "entry_state.json") };
59
+ const image: Image = { segments, byteAt: (at) => memory[at]!, statePath: posix.join(directory, "entry_state.json") };
63
60
  if (manifest.entry !== undefined) image.entry = address(manifest.entry, "entry");
64
61
  if (Array.isArray(manifest.stages)) image.stages = manifest.stages as Array<Record<string, unknown>>;
65
62
  return image;
@@ -8,7 +8,7 @@ import { WireFailure } from "../../protocol/messages.ts";
8
8
  import { CHECKPOINT_ACTIONS, MAX_BACKTRACE, MAX_HISTORY, MAX_TRACE_FRAMES, MAX_TRACE_HITS, MAX_TRACE_POINTS, TRACE_KINDS, TRACE_ENDS, MAX_MEMMAP_RANGES, MAX_MEMORY_READ, MAX_PROFILE, MAX_WATCH_SIZE, SPACES, TIMING_ACTIONS, WATCH_ACCESS, type Breakpoint, type Watchpoint } from "../../protocol/vice.ts";
9
9
  import { readCoverage } from "../../host-client/coverage.ts";
10
10
  import { OutInput, ProjectInput, writeOut, WrittenOutput } from "../output.ts";
11
- import { AddressInput, AddressOutput, Byte, ConditionInput, ConditionOutput, defineTool, HexData, requireFields, showCondition, SpaceInput, toCondition, type ViceSessionApi } from "../server.ts";
11
+ import { AddressInput, AddressOutput, Byte, ConditionInput, ConditionOutput, defineTool, HexData, requireFields, showCondition, SpaceInput, toCondition } from "../server.ts";
12
12
  import { spaced } from "./memory.ts";
13
13
 
14
14
  /** No default here: a filled-in default would count as a field the other actions refuse. */
package/src/opcodes.ts CHANGED
@@ -56,10 +56,6 @@ export function takesAddress(mode: Mode): boolean {
56
56
  return mode !== "imp" && mode !== "imm";
57
57
  }
58
58
 
59
- export function isZeroPageMode(mode: Mode): boolean {
60
- return mode === "zp" || mode === "zpx" || mode === "zpy" || mode === "izx" || mode === "izy";
61
- }
62
-
63
59
  /** How an instruction uses the address of its operand, in the order a summary lists them. */
64
60
  export const USE_KINDS = ["read", "written", "modified", "called", "jumped to", "jumped through", "branched to", "pointer", "address", "table", "macro argument"] as const;
65
61
  export type UseKind = (typeof USE_KINDS)[number];
@@ -109,20 +109,6 @@ export function isRelativePath(value: unknown): value is string {
109
109
  return typeof value === "string" && value.length <= 1024 && RELATIVE_PATH.test(value) && !value.includes("//") && !value.endsWith("/");
110
110
  }
111
111
 
112
- /** Validates a transferred source tree against its attachments. Throws WireFailure(invalid-input). */
113
- export function validateSourceTree(value: unknown, attachments: readonly Uint8Array[]): SourceTree {
114
- if (!Array.isArray(value) || value.length > MAX_TREE_FILES) invalid(`files must list at most ${MAX_TREE_FILES} files`);
115
- if (value.length !== attachments.length) invalid("each listed file needs exactly one attachment");
116
- const seen = new Set<string>();
117
- return value.map((entry, index) => {
118
- if (!isObject(entry) || !isRelativePath(entry.path)) invalid("each file needs a relative path inside the source root");
119
- if (seen.has(entry.path)) invalid(`the file ${entry.path} is listed twice`);
120
- seen.add(entry.path);
121
- if (entry.size !== attachments[index]!.length) invalid(`the size of ${entry.path} does not match its bytes`);
122
- return { path: entry.path, size: entry.size as number };
123
- });
124
- }
125
-
126
112
  /** Refuses anything but exactly one attachment with at least one byte, named by what it must hold. */
127
113
  function oneFile(attachments: readonly Uint8Array[], what: string): void {
128
114
  if (attachments.length !== 1 || attachments[0]!.length === 0) invalid(`${what} must be the one attachment, and it must not be empty`);