@henols/vice-mcp 0.2.1 → 0.2.3

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 (108) hide show
  1. package/README.md +4 -3
  2. package/THIRD-PARTY-NOTICES.md +423 -25
  3. package/{r2000-acme-ident.ts → anno-acme-ident.ts} +13 -13
  4. package/anno-bank.ts +171 -0
  5. package/anno-cli.ts +3040 -0
  6. package/{r2000-confidence.ts → anno-confidence.ts} +22 -22
  7. package/anno-coverage.ts +2465 -0
  8. package/anno-derive.ts +590 -0
  9. package/anno-details.ts +169 -0
  10. package/anno-enum-gen.ts +919 -0
  11. package/anno-export-asm.ts +2396 -0
  12. package/anno-graphics.ts +338 -0
  13. package/anno-hazard-report.ts +1367 -0
  14. package/anno-import.ts +495 -0
  15. package/anno-index.ts +150 -0
  16. package/anno-join.ts +480 -0
  17. package/{r2000-memmap-render.ts → anno-memmap-render.ts} +236 -95
  18. package/anno-provenance-ledger.ts +472 -0
  19. package/{r2000-regbits-gen.ts → anno-regbits-gen.ts} +20 -15
  20. package/{r2000-regbits.json → anno-regbits.json} +2 -2
  21. package/anno-register.ts +399 -0
  22. package/anno-store-export.ts +661 -0
  23. package/anno-store.ts +4002 -0
  24. package/anno-symbols.ts +266 -0
  25. package/anno-tools.ts +3264 -0
  26. package/anno-types.ts +1909 -0
  27. package/backend-detect.mts +124 -312
  28. package/block-class.ts +201 -0
  29. package/build.ts +4 -2
  30. package/capture-predicate.ts +597 -0
  31. package/channel-lock.ts +349 -0
  32. package/disasm-decoder.ts +14 -14
  33. package/disasm-opcodes.ts +4 -4
  34. package/disasm-renderer.ts +2 -2
  35. package/evid-ingest.ts +217 -0
  36. package/evid-reconcile.ts +316 -0
  37. package/host-tool-client.ts +430 -0
  38. package/hostpath.ts +1 -1
  39. package/incident-record.ts +23 -12
  40. package/install-resources.ts +30 -14
  41. package/memmap-lookup.ts +285 -0
  42. package/package.json +48 -23
  43. package/prg-image.ts +118 -0
  44. package/repo-root.ts +107 -8
  45. package/resources/backend-detect.mjs +98 -236
  46. package/resources/broker-control.mjs +189 -16
  47. package/resources/broker-epoch.mjs +1 -1
  48. package/resources/broker-kill.mjs +8 -2
  49. package/resources/broker-launch.mjs +373 -214
  50. package/resources/broker-state.mjs +64 -18
  51. package/resources/container-guard.mjs +1 -1
  52. package/resources/ghidra-project.mjs +790 -0
  53. package/resources/host-tool.mjs +2561 -0
  54. package/resources/vice-broker.mjs +330 -184
  55. package/resources/vice-launcher.sh +130 -12
  56. package/stock-address.ts +6 -6
  57. package/stock-cia.ts +2 -2
  58. package/stock-condition.ts +8 -8
  59. package/stock-connect.ts +10 -6
  60. package/stock-derived.ts +29 -37
  61. package/stock-diagnose.ts +200 -36
  62. package/stock-dispatch.ts +200 -68
  63. package/stock-execution.ts +5 -3
  64. package/stock-handler.ts +1 -1
  65. package/stock-input.ts +9 -9
  66. package/stock-machine.ts +17 -6
  67. package/stock-paths.ts +18 -14
  68. package/stock-petscii.ts +1 -1
  69. package/stock-protocol.ts +17 -12
  70. package/stock-recycle.ts +83 -2
  71. package/stock-registers.ts +54 -29
  72. package/stock-reproducible-run.ts +811 -0
  73. package/stock-run-until.ts +100 -1
  74. package/stock-sprites.ts +3 -3
  75. package/stock-symbols.ts +13 -13
  76. package/stock-timing.ts +2 -2
  77. package/stock-vicii.ts +1 -1
  78. package/stop-oracle.ts +167 -0
  79. package/text-capability-probe.ts +660 -0
  80. package/text-connect.ts +157 -0
  81. package/text-protocol.ts +810 -0
  82. package/text-tools.ts +778 -0
  83. package/textmon-backtrace.ts +385 -0
  84. package/textmon-cpuhistory.ts +335 -0
  85. package/textmon-memmap.ts +494 -0
  86. package/textmon-profile.ts +458 -0
  87. package/textmon-registers.ts +748 -0
  88. package/tools-manifest.stock.json +864 -3
  89. package/version.ts +1 -1
  90. package/vice-broker-client.ts +189 -42
  91. package/vice-errors.ts +268 -0
  92. package/vice-proxy.ts +392 -2175
  93. package/vsf-slice.ts +640 -0
  94. package/capability-registry.ts +0 -388
  95. package/r2000-cli.ts +0 -1103
  96. package/r2000-d64.ts +0 -310
  97. package/r2000-enum-gen.ts +0 -574
  98. package/r2000-launch.ts +0 -357
  99. package/r2000-mcp-client.ts +0 -596
  100. package/r2000-project.ts +0 -190
  101. package/r2000-symbols.ts +0 -388
  102. package/r2000-tools.ts +0 -914
  103. package/r2000-verify.ts +0 -184
  104. package/refresh-manifest.ts +0 -124
  105. package/tools-manifest.json +0 -1223
  106. package/vice-probe.ts +0 -278
  107. package/vice-sync.ts +0 -336
  108. package/vice.ts +0 -772
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ // anno-details.ts
3
+ //
4
+ // WHAT THIS IS THE ONE AUTHORITATIVE PLACE FOR: the composed "everything this
5
+ // project knows about ONE address" answer -- labels, comments, the containing
6
+ // typed range, and the cross-references that reach it -- assembled from four
7
+ // reads of the owned annotation store and DISCLOSED as a composition in the
8
+ // body it returns.
9
+ //
10
+ // ---------------------------------------------------------------------------
11
+ // WHY THIS FILE EXISTS
12
+ // ---------------------------------------------------------------------------
13
+ // Its analog composed the same four facts from four MCP round trips to an
14
+ // external analyser, because that analyser's own address-details tool returned
15
+ // an out-of-range refusal for EVERY address on a full 64K project. The
16
+ // composition's doc block recorded the property that made it trustworthy: the
17
+ // defect was "unreachable by construction, not merely avoided by a heuristic".
18
+ // That property is carried forward here and strengthened -- there is no
19
+ // external analyser left to be unreachable FROM. The four reads are four
20
+ // function calls against a store this project owns, in one process, with no
21
+ // socket, no child process and no session to go stale between them.
22
+ //
23
+ // The composition is DISCLOSED rather than passed off as a single stored
24
+ // answer: the body carries `composed_client_side` and a `composed_from` list
25
+ // naming all four sources, so a reader can always tell a composition from
26
+ // something the store held whole. That disclosure is the analog's own shape and
27
+ // is deliberately kept verbatim in intent.
28
+ //
29
+ // ---------------------------------------------------------------------------
30
+ // WHAT NOT TO DO
31
+ // ---------------------------------------------------------------------------
32
+ // - Never scan for the containing range with a start/end bracket comparison
33
+ // loop. `resolveAt()` over `paintIndexOf()` is the single arbiter --
34
+ // narrowest range wins, and among equally short ones the later-inserted one
35
+ // -- and `STORE-03` cross-validated it at all 65,536 addresses against an
36
+ // independently written implementation. A second lookup rule here would be
37
+ // a second answer, and the disagreement would be invisible because both
38
+ // look authoritative.
39
+ // - Never write anything. This module is on a read path and is held to
40
+ // `anno-derive.ts`'s never-cache rule by the same structural control: no
41
+ // SQL write verb, no filesystem write call, no persistence binding.
42
+ // - Never import `hostpath.ts`, `containerpath.ts` or `container-guard.mts`
43
+ // (MCP-02) -- this composition is proxy-local.
44
+ // - Never return an empty array for something that could not be answered. A
45
+ // component with no answer comes back as `{available:false, reason}`, so an
46
+ // address that genuinely has no comments is distinguishable from a question
47
+ // this composition could not put. An address that simply has no labels IS a
48
+ // genuine empty list and stays one.
49
+ // - Never add a second address parser. `parseStoreAddress` validates the one
50
+ // argument this module takes.
51
+ import { listComments, listLabels, listRanges, paintIndexOf } from "./anno-store.ts";
52
+ import type { AnnoStoreHandle } from "./anno-store.ts";
53
+ import { NO_ROW, resolveAt } from "./anno-index.ts";
54
+ import { parseStoreAddress } from "./anno-types.ts";
55
+ import type { CommentRow, LabelRow, RangeRow } from "./anno-types.ts";
56
+ import { crossReferencesTo } from "./anno-derive.ts";
57
+ import type { CrossReferencesResult } from "./anno-derive.ts";
58
+
59
+ /** A component that HAS an answer, and one that could not be answered at all.
60
+ * The second shape is `stock-cia.ts`'s unavailability entry and
61
+ * `stock-recycle.ts`'s `CaptureStepResult`: an unanswerable question never
62
+ * comes back as a plausible zero. */
63
+ export type ComposedComponent<T> = { available: true; value: T } | { available: false; reason: string };
64
+
65
+ /** What `composeAddressDetails()` returns.
66
+ *
67
+ * `labels` and `comments` are plain arrays because the store can ALWAYS answer
68
+ * about them -- an address with none has none, and that is a fact rather than a
69
+ * gap. `range` and `crossReferences` are `ComposedComponent`s because each has a
70
+ * real "cannot answer" state: no typed range covers the address, and no program
71
+ * bytes were supplied to derive references from. */
72
+ export interface ComposedAddressDetails {
73
+ address: number;
74
+ labels: LabelRow[];
75
+ comments: CommentRow[];
76
+ range: ComposedComponent<RangeRow>;
77
+ crossReferences: ComposedComponent<CrossReferencesResult>;
78
+ composed_client_side: true;
79
+ composed_from: readonly string[];
80
+ }
81
+
82
+ /** The four sources, named in the order they are read. This array IS the
83
+ * `composed_from` disclosure -- there is no second hand-typed copy for the two
84
+ * to drift apart. */
85
+ export const ADDRESS_DETAIL_SOURCES: readonly string[] = Object.freeze([
86
+ "listLabels",
87
+ "listComments",
88
+ "resolveAt over paintIndexOf",
89
+ "crossReferencesTo",
90
+ ]);
91
+
92
+ function hex4(address: number): string {
93
+ return `$${address.toString(16).padStart(4, "0")}`;
94
+ }
95
+
96
+ /**
97
+ * Everything this project knows about `address`, composed from four store
98
+ * reads.
99
+ *
100
+ * 1. LABELS bound at the address (`listLabels`).
101
+ * 2. COMMENTS at the address, both placements (`listComments`).
102
+ * 3. THE CONTAINING RANGE, resolved through `resolveAt()` over
103
+ * `paintIndexOf()` -- narrowest-range-wins, never a bracket scan.
104
+ * 4. THE CROSS-REFERENCES that reach it (`crossReferencesTo`), derived from the
105
+ * caller's own bytes on this call and never cached.
106
+ *
107
+ * Nothing is written on any path.
108
+ */
109
+ export function composeAddressDetails(
110
+ handle: AnnoStoreHandle,
111
+ image: Uint8Array,
112
+ origin: number | string,
113
+ address: number | string,
114
+ ): ComposedAddressDetails {
115
+ const at = parseStoreAddress(address, { what: "address" });
116
+
117
+ const labels = listLabels(handle).filter((row) => row.address === at);
118
+ const comments = listComments(handle).filter((row) => row.address === at);
119
+
120
+ const rowId = resolveAt(paintIndexOf(handle), at);
121
+ const range: ComposedComponent<RangeRow> =
122
+ rowId === NO_ROW
123
+ ? {
124
+ available: false,
125
+ reason:
126
+ `no typed range covers ${hex4(at)}: the paint index resolves it to nothing, which means this address sits in a gap ` +
127
+ "between the ranges a human has typed rather than in an untyped part of one. Type a range covering it with " +
128
+ "anno-store.ts's setDataType to make this component answerable.",
129
+ }
130
+ : composeRange(handle, rowId, at);
131
+
132
+ const crossReferences: ComposedComponent<CrossReferencesResult> =
133
+ image.length === 0
134
+ ? {
135
+ available: false,
136
+ reason:
137
+ `cross-references to ${hex4(at)} are DERIVED from program bytes on every query and no bytes were supplied: the store ` +
138
+ "holds no program image (D-07), so this component is answerable only when the caller names the image it wants derived " +
139
+ "from. The stored non-derivable rows alone are readable through anno-store.ts's listXrefs.",
140
+ }
141
+ : { available: true, value: crossReferencesTo(handle, image, origin, at) };
142
+
143
+ return {
144
+ address: at,
145
+ labels,
146
+ comments,
147
+ range,
148
+ crossReferences,
149
+ composed_client_side: true,
150
+ composed_from: ADDRESS_DETAIL_SOURCES,
151
+ };
152
+ }
153
+
154
+ /** The row `resolveAt()` named. Looked up BY ID in `listRanges()`'s own output
155
+ * -- an id-equality match, never a start/end bracket comparison, so the
156
+ * arbiter's verdict is reported rather than re-derived. */
157
+ function composeRange(handle: AnnoStoreHandle, rowId: number, at: number): ComposedComponent<RangeRow> {
158
+ const row = listRanges(handle).find((candidate) => candidate.id === rowId);
159
+ if (row === undefined) {
160
+ return {
161
+ available: false,
162
+ reason:
163
+ `the paint index resolved ${hex4(at)} to range id ${rowId}, but no row with that id is in the range table -- the index and ` +
164
+ "the table disagree, which should be impossible because the index is rebuilt from the table on every call. Reported rather " +
165
+ "than silently answered as an absent range, because those are different facts.",
166
+ };
167
+ }
168
+ return { available: true, value: row };
169
+ }