@xn-intenton-z2a/agentic-lib 7.1.62 → 7.1.63
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/.github/workflows/agentic-lib-workflow.yml +12 -1
- package/agentic-lib.toml +1 -0
- package/bin/agentic-lib.js +45 -2
- package/package.json +1 -1
- package/src/agents/agent-discussion-bot.md +13 -0
- package/src/agents/agent-issue-resolution.md +14 -0
- package/src/agents/agent-supervisor.md +3 -1
- package/src/seeds/missions/c64-emulator.md +110 -0
- package/src/seeds/zero-index.html +24 -0
- package/src/seeds/zero-package.json +5 -3
- package/src/seeds/zero-web.test.js +17 -0
|
@@ -654,7 +654,8 @@ jobs:
|
|
|
654
654
|
SOURCES=$(yq -r '.paths.librarySourcesFilepath.path // "SOURCES.md"' "$CONFIG")
|
|
655
655
|
README=$(yq -r '.paths.readmeFilepath.path // "README.md"' "$CONFIG")
|
|
656
656
|
DEPS=$(yq -r '.paths.dependenciesFilepath.path // "package.json"' "$CONFIG")
|
|
657
|
-
|
|
657
|
+
WEB=$(yq -r '.paths.web // "src/web/"' "$CONFIG" 2>/dev/null || echo "src/web/")
|
|
658
|
+
echo "writablePaths=${SOURCE};${TESTS};${FEATURES};${DOCS};${LIBRARY};${SOURCES};${README};${DEPS};${WEB}" >> $GITHUB_OUTPUT
|
|
658
659
|
|
|
659
660
|
- name: Check mission-complete signal
|
|
660
661
|
id: dev-mission-check
|
|
@@ -715,6 +716,11 @@ jobs:
|
|
|
715
716
|
issue-number: ${{ steps.issue.outputs.issue-number }}
|
|
716
717
|
writable-paths: ${{ steps.config.outputs.writablePaths }}
|
|
717
718
|
|
|
719
|
+
- name: Build website
|
|
720
|
+
if: steps.issue.outputs.issue-number != ''
|
|
721
|
+
run: |
|
|
722
|
+
npm run build:web 2>/dev/null || echo "No build:web script"
|
|
723
|
+
|
|
718
724
|
- name: Commit and push
|
|
719
725
|
if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true'
|
|
720
726
|
uses: ./.github/agentic-lib/actions/commit-if-changed
|
|
@@ -822,10 +828,15 @@ jobs:
|
|
|
822
828
|
|
|
823
829
|
- name: Summary
|
|
824
830
|
run: |
|
|
831
|
+
REPO="${{ github.repository }}"
|
|
832
|
+
OWNER="${REPO%%/*}"
|
|
833
|
+
REPO_NAME="${REPO##*/}"
|
|
834
|
+
SITE_URL="https://${OWNER}.github.io/${REPO_NAME}/"
|
|
825
835
|
echo "## agentic-lib-workflow run summary" >> $GITHUB_STEP_SUMMARY
|
|
826
836
|
echo "- Mode: ${{ needs.params.outputs.mode }}" >> $GITHUB_STEP_SUMMARY
|
|
827
837
|
echo "- Model: ${{ needs.params.outputs.model }}" >> $GITHUB_STEP_SUMMARY
|
|
828
838
|
echo "- Dry-run: ${{ needs.params.outputs.dry-run }}" >> $GITHUB_STEP_SUMMARY
|
|
839
|
+
echo "- Website: [${SITE_URL}](${SITE_URL})" >> $GITHUB_STEP_SUMMARY
|
|
829
840
|
|
|
830
841
|
# ─── Schedule change (if requested) ────────────────────────────────
|
|
831
842
|
update-schedule:
|
package/agentic-lib.toml
CHANGED
|
@@ -14,6 +14,7 @@ source = "test/src/lib/" #@dist "src/lib/"
|
|
|
14
14
|
tests = "test/tests/unit/" #@dist "tests/unit/"
|
|
15
15
|
features = "test/features/" #@dist "features/"
|
|
16
16
|
library = "test/library/" #@dist "library/"
|
|
17
|
+
web = "test/src/web/" #@dist "src/web/"
|
|
17
18
|
docs = "test/docs/" #@dist "docs/"
|
|
18
19
|
examples = "test/examples/" #@dist "examples/"
|
|
19
20
|
readme = "test/README.md" #@dist "README.md"
|
package/bin/agentic-lib.js
CHANGED
|
@@ -886,6 +886,7 @@ function readTomlPaths() {
|
|
|
886
886
|
let sourcePath = "src/lib/";
|
|
887
887
|
let testsPath = "tests/unit/";
|
|
888
888
|
let examplesPath = "examples/";
|
|
889
|
+
let webPath = "src/web/";
|
|
889
890
|
const tomlTarget = resolve(target, "agentic-lib.toml");
|
|
890
891
|
if (existsSync(tomlTarget)) {
|
|
891
892
|
try {
|
|
@@ -893,14 +894,16 @@ function readTomlPaths() {
|
|
|
893
894
|
const sourceMatch = tomlContent.match(/^source\s*=\s*"([^"]+)"/m);
|
|
894
895
|
const testsMatch = tomlContent.match(/^tests\s*=\s*"([^"]+)"/m);
|
|
895
896
|
const examplesMatch = tomlContent.match(/^examples\s*=\s*"([^"]+)"/m);
|
|
897
|
+
const webMatch = tomlContent.match(/^web\s*=\s*"([^"]+)"/m);
|
|
896
898
|
if (sourceMatch) sourcePath = sourceMatch[1];
|
|
897
899
|
if (testsMatch) testsPath = testsMatch[1];
|
|
898
900
|
if (examplesMatch) examplesPath = examplesMatch[1];
|
|
901
|
+
if (webMatch) webPath = webMatch[1];
|
|
899
902
|
} catch (err) {
|
|
900
903
|
console.log(` WARN: Could not read TOML for paths, using defaults: ${err.message}`);
|
|
901
904
|
}
|
|
902
905
|
}
|
|
903
|
-
return { sourcePath, testsPath, examplesPath };
|
|
906
|
+
return { sourcePath, testsPath, examplesPath, webPath };
|
|
904
907
|
}
|
|
905
908
|
|
|
906
909
|
function clearAndRecreateDir(dirPath, label) {
|
|
@@ -916,16 +919,19 @@ function clearAndRecreateDir(dirPath, label) {
|
|
|
916
919
|
function initPurge(seedsDir, missionName) {
|
|
917
920
|
console.log("\n--- Purge: Reset Source Files to Seed State ---");
|
|
918
921
|
|
|
919
|
-
const { sourcePath, testsPath, examplesPath } = readTomlPaths();
|
|
922
|
+
const { sourcePath, testsPath, examplesPath, webPath } = readTomlPaths();
|
|
920
923
|
clearAndRecreateDir(sourcePath, sourcePath);
|
|
921
924
|
clearAndRecreateDir(testsPath, testsPath);
|
|
922
925
|
clearAndRecreateDir(examplesPath, examplesPath);
|
|
926
|
+
clearAndRecreateDir(webPath, webPath);
|
|
923
927
|
clearAndRecreateDir("docs", "docs");
|
|
924
928
|
|
|
925
929
|
// Copy seed files (including config TOML) — MISSION.md handled separately via mission seed
|
|
926
930
|
const SEED_MAP = {
|
|
927
931
|
"zero-main.js": "src/lib/main.js",
|
|
928
932
|
"zero-main.test.js": "tests/unit/main.test.js",
|
|
933
|
+
"zero-index.html": "src/web/index.html",
|
|
934
|
+
"zero-web.test.js": "tests/unit/web.test.js",
|
|
929
935
|
"zero-SOURCES.md": "SOURCES.md",
|
|
930
936
|
"zero-package.json": "package.json",
|
|
931
937
|
"zero-README.md": "README.md",
|
|
@@ -938,6 +944,18 @@ function initPurge(seedsDir, missionName) {
|
|
|
938
944
|
}
|
|
939
945
|
}
|
|
940
946
|
|
|
947
|
+
// Bootstrap docs/ for GitHub Pages — copy web seed so the site is available immediately
|
|
948
|
+
const webSeed = resolve(seedsDir, "zero-index.html");
|
|
949
|
+
if (existsSync(webSeed)) {
|
|
950
|
+
const docsDir = resolve(target, "docs");
|
|
951
|
+
if (!dryRun) {
|
|
952
|
+
mkdirSync(docsDir, { recursive: true });
|
|
953
|
+
writeFileSync(resolve(docsDir, ".nojekyll"), "");
|
|
954
|
+
}
|
|
955
|
+
initCopyFile(webSeed, resolve(docsDir, "index.html"), "SEED: zero-index.html → docs/index.html");
|
|
956
|
+
console.log(" CREATE: docs/.nojekyll");
|
|
957
|
+
}
|
|
958
|
+
|
|
941
959
|
// Force-overwrite agentic-lib.toml during purge (transformed from root)
|
|
942
960
|
const tomlSource = resolve(pkgRoot, "agentic-lib.toml");
|
|
943
961
|
if (existsSync(tomlSource)) {
|
|
@@ -1118,6 +1136,31 @@ function initPurgeGitHub() {
|
|
|
1118
1136
|
} catch (err) {
|
|
1119
1137
|
console.log(` SKIP: Could not create discussion (${err.message})`);
|
|
1120
1138
|
}
|
|
1139
|
+
|
|
1140
|
+
// Enable GitHub Pages (serve from docs/ on main branch)
|
|
1141
|
+
console.log("\n--- Enable GitHub Pages ---");
|
|
1142
|
+
try {
|
|
1143
|
+
if (!dryRun) {
|
|
1144
|
+
execSync(
|
|
1145
|
+
`gh api repos/${repoSlug}/pages -X POST -f build_type=legacy -f "source[branch]=main" -f "source[path]=/docs"`,
|
|
1146
|
+
{ cwd: target, encoding: "utf8", timeout: 15000, stdio: ["pipe", "pipe", "pipe"] },
|
|
1147
|
+
);
|
|
1148
|
+
console.log(` ENABLED: GitHub Pages from docs/ on main`);
|
|
1149
|
+
console.log(` URL: https://${owner}.github.io/${repo}/`);
|
|
1150
|
+
initChanges++;
|
|
1151
|
+
} else {
|
|
1152
|
+
console.log(` ENABLE: GitHub Pages from docs/ on main (dry run)`);
|
|
1153
|
+
console.log(` URL: https://${owner}.github.io/${repo}/`);
|
|
1154
|
+
initChanges++;
|
|
1155
|
+
}
|
|
1156
|
+
} catch (err) {
|
|
1157
|
+
if (err.message?.includes("409") || err.stderr?.includes("409")) {
|
|
1158
|
+
console.log(" SKIP: GitHub Pages already enabled");
|
|
1159
|
+
} else {
|
|
1160
|
+
console.log(` SKIP: Could not enable GitHub Pages (${err.message})`);
|
|
1161
|
+
console.log(` Manual: Settings → Pages → Source: Deploy from branch, Branch: main, Folder: /docs`);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1121
1164
|
}
|
|
1122
1165
|
|
|
1123
1166
|
function runInit() {
|
package/package.json
CHANGED
|
@@ -47,9 +47,22 @@ You can request the supervisor to:
|
|
|
47
47
|
- Review and close issues
|
|
48
48
|
- Fix failing PRs
|
|
49
49
|
- Create new issues from feature ideas
|
|
50
|
+
- Re-seed the repository with a new mission (via `init --purge --mission <name>`)
|
|
50
51
|
|
|
51
52
|
When relaying supervisor responses back to the user, present them naturally as your own awareness of what's happening in the repository.
|
|
52
53
|
|
|
54
|
+
## Feature Requests and Re-Seeds
|
|
55
|
+
|
|
56
|
+
Users can ask for new features or mission changes through this discussion thread:
|
|
57
|
+
|
|
58
|
+
- **Feature requests** — When a user says "add feature X" or "I want Y", acknowledge the request and pass it to the supervisor to create a GitHub issue. The pipeline will pick it up and implement it.
|
|
59
|
+
- **Re-seed requests** — When a user says "change the mission to Z" or "re-seed with plot-code-lib", explain that this requires running `npx @xn-intenton-z2a/agentic-lib init --purge --mission <name>`. List the available missions if asked: hamming-distance, fizz-buzz, roman-numerals, string-utils, dense-encoding, cron-engine, owl-ontology, plot-code-lib, time-series-lab, lunar-lander, empty. Note that re-seeding resets all source code, issues, and discussions.
|
|
60
|
+
- **Website feedback** — The project has a website published via GitHub Pages. If a user comments on the website, pass feedback to the supervisor to create an issue for the pipeline to address.
|
|
61
|
+
|
|
62
|
+
## Website Awareness
|
|
63
|
+
|
|
64
|
+
The repository publishes a website via GitHub Pages that showcases the library. The URL follows the pattern `https://<owner>.github.io/<repo>/`. When discussing the project, mention the website as a way for users to see the library in action.
|
|
65
|
+
|
|
53
66
|
## Conversation Style
|
|
54
67
|
|
|
55
68
|
- Use previous interactions to build rapport — reference things the user mentioned before
|
|
@@ -21,3 +21,17 @@ When implementing features, also produce evidence artifacts under `docs/`:
|
|
|
21
21
|
|
|
22
22
|
Design the library API with hooks that make evidence capture easy: return structured result objects,
|
|
23
23
|
support `outputFile` options where appropriate, and emit results that observers can record.
|
|
24
|
+
|
|
25
|
+
## Website Showcase
|
|
26
|
+
|
|
27
|
+
Maintain a website in `src/web/` that visually demonstrates the library's capabilities. The website is
|
|
28
|
+
published to GitHub Pages automatically (from `docs/` via `npm run build:web`).
|
|
29
|
+
|
|
30
|
+
- `src/web/index.html` is the main page — evolve it to showcase the library interactively
|
|
31
|
+
- You may add CSS, JS, images, or additional HTML pages in `src/web/`
|
|
32
|
+
- The website should demonstrate what the library does in a way a visitor can see and interact with
|
|
33
|
+
- Keep it self-contained (no external CDN dependencies unless essential)
|
|
34
|
+
- Link back to the repository for source code and mission details
|
|
35
|
+
- When the library produces visual output (plots, graphs, data), embed or render it on the website
|
|
36
|
+
- When the library is computational (algorithms, utilities), create an interactive demo or show example results
|
|
37
|
+
- The website tests in `tests/unit/web.test.js` verify the HTML exists and is structurally valid — you may extend them
|
|
@@ -38,6 +38,7 @@ When open issues with the `automated` label lack the `ready` label and are more
|
|
|
38
38
|
### Mission Initialised (init completed)
|
|
39
39
|
When recent workflow runs show an init completion, the repository has a fresh or updated mission.
|
|
40
40
|
Dispatch the discussions bot to announce the new mission to the community.
|
|
41
|
+
Include the website URL in the announcement — the site is at `https://<owner>.github.io/<repo>/`.
|
|
41
42
|
|
|
42
43
|
### Mission Accomplished (bounded missions)
|
|
43
44
|
When ALL of the following conditions are met, the mission is accomplished:
|
|
@@ -47,7 +48,7 @@ When ALL of the following conditions are met, the mission is accomplished:
|
|
|
47
48
|
4. Evidence artifacts exist under `docs/` (example outputs, test results, or walkthroughs)
|
|
48
49
|
|
|
49
50
|
When all conditions are met:
|
|
50
|
-
1. `dispatch:agentic-lib-bot` — announce mission accomplished in the discussions thread
|
|
51
|
+
1. `dispatch:agentic-lib-bot` — announce mission accomplished in the discussions thread. Include the website URL (`https://<owner>.github.io/<repo>/`) so users can see the finished product.
|
|
51
52
|
2. `set-schedule:off` — stop the workflow. The mission is done.
|
|
52
53
|
3. Log `mission-accomplished` in the activity log.
|
|
53
54
|
|
|
@@ -81,6 +82,7 @@ Also check for notable progress worth reporting:
|
|
|
81
82
|
- Mission milestones achieved (all core functions implemented, all tests passing)
|
|
82
83
|
- Schedule changes (mission accomplished, throttling down)
|
|
83
84
|
- Significant code changes (large PRs merged, new features completed)
|
|
85
|
+
- Website first deployed or significantly updated (include the URL: `https://<owner>.github.io/<repo>/`)
|
|
84
86
|
|
|
85
87
|
When notable progress exists or there are unresponded referrals, use `respond:discussions | message: <status update> | discussion-url: <url>` to post an update. Keep it concise — 2-3 sentences summarising what happened and what's next.
|
|
86
88
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Mission
|
|
2
|
+
|
|
3
|
+
A JavaScript Commodore 64 emulator capable of running the classic game "The Lords of Midnight" (1984, Mike Singleton).
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
The emulator is structured as layered components, each independently testable:
|
|
8
|
+
|
|
9
|
+
1. **MOS 6510 CPU** — the core processor (6502 variant with I/O port at $00/$01)
|
|
10
|
+
2. **Memory subsystem** — 64KB RAM, ROM banking (BASIC, KERNAL, character ROM), I/O area ($D000–$DFFF)
|
|
11
|
+
3. **VIC-II video** — text mode (40x25), bitmap mode, sprites, raster interrupt timing
|
|
12
|
+
4. **SID sound** — 3-voice synthesiser with ADSR envelopes (basic waveform generation)
|
|
13
|
+
5. **CIA timers** — two CIA chips for keyboard scanning, timer interrupts, and joystick input
|
|
14
|
+
6. **Input** — keyboard matrix and joystick mapped to browser events
|
|
15
|
+
7. **PRG/TAP loader** — load `.prg` files (and optionally `.tap` tape images) into memory
|
|
16
|
+
|
|
17
|
+
## Core Functions
|
|
18
|
+
|
|
19
|
+
Export all from `src/lib/main.js`:
|
|
20
|
+
|
|
21
|
+
- `createC64(opts?)` — create an emulator instance with default ROMs and 64KB RAM. Returns an object with `cpu`, `memory`, `vic`, `sid`, `cia1`, `cia2` subsystems.
|
|
22
|
+
- `loadPRG(c64, data)` — load a `.prg` file (Uint8Array) into memory at the address specified in its two-byte header.
|
|
23
|
+
- `step(c64)` — execute one CPU instruction, advance cycle count, and update timers. Returns the new state.
|
|
24
|
+
- `runFrame(c64)` — execute instructions for one video frame (~19656 cycles PAL). Trigger raster interrupts at the appropriate scanlines. Returns the framebuffer.
|
|
25
|
+
- `getFramebuffer(c64)` — return the current screen as a Uint8Array RGBA pixel buffer (320x200 or 384x272 with borders).
|
|
26
|
+
- `pressKey(c64, key)` / `releaseKey(c64, key)` — simulate keyboard input via CIA1 keyboard matrix.
|
|
27
|
+
- `joystickInput(c64, port, directions)` — set joystick state (up/down/left/right/fire) on port 1 or 2.
|
|
28
|
+
- `reset(c64)` — perform a hardware reset (set CPU to reset vector, clear state).
|
|
29
|
+
|
|
30
|
+
## CPU Requirements
|
|
31
|
+
|
|
32
|
+
- All official 6502 opcodes (56 instructions, 151 opcode variants) with correct cycle counts.
|
|
33
|
+
- Decimal mode (BCD arithmetic) support.
|
|
34
|
+
- IRQ and NMI interrupt handling with correct stack behaviour.
|
|
35
|
+
- The 6510 I/O port at $00/$01 for ROM/RAM bank switching.
|
|
36
|
+
- Undocumented/illegal opcodes are NOT required (may be implemented as NOP).
|
|
37
|
+
|
|
38
|
+
## Memory Map
|
|
39
|
+
|
|
40
|
+
- $0000–$00FF: Zero page
|
|
41
|
+
- $0100–$01FF: Stack
|
|
42
|
+
- $0200–$9FFF: Free RAM (programs load here)
|
|
43
|
+
- $A000–$BFFF: BASIC ROM (banked, RAM underneath)
|
|
44
|
+
- $C000–$CFFF: Free RAM
|
|
45
|
+
- $D000–$D3FF: VIC-II registers
|
|
46
|
+
- $D400–$D7FF: SID registers
|
|
47
|
+
- $D800–$DBFF: Colour RAM (nibbles)
|
|
48
|
+
- $DC00–$DCFF: CIA1 (keyboard, joystick, timer)
|
|
49
|
+
- $DD00–$DDFF: CIA2 (serial, timer, VIC bank)
|
|
50
|
+
- $E000–$FFFF: KERNAL ROM (banked, RAM underneath)
|
|
51
|
+
|
|
52
|
+
## Video (VIC-II)
|
|
53
|
+
|
|
54
|
+
- Standard text mode (mode 0) — 40x25 characters, 16 colours, character ROM.
|
|
55
|
+
- Multicolour text mode.
|
|
56
|
+
- Standard bitmap mode (320x200) and multicolour bitmap mode (160x200).
|
|
57
|
+
- Hardware sprites (8 sprites, 24x21 pixels, multicolour optional).
|
|
58
|
+
- Raster interrupt — trigger IRQ at a programmable scanline.
|
|
59
|
+
- Border colour and background colour registers.
|
|
60
|
+
- Correct raster timing is essential — Lords of Midnight uses raster effects.
|
|
61
|
+
|
|
62
|
+
## Sound (SID — basic)
|
|
63
|
+
|
|
64
|
+
- 3 oscillator voices with waveform selection (triangle, sawtooth, pulse, noise).
|
|
65
|
+
- ADSR envelope per voice.
|
|
66
|
+
- Frequency and pulse-width registers.
|
|
67
|
+
- Audio output as PCM sample buffer suitable for Web Audio API playback.
|
|
68
|
+
- Full filter emulation is NOT required (passthrough acceptable).
|
|
69
|
+
|
|
70
|
+
## Input
|
|
71
|
+
|
|
72
|
+
- CIA1 keyboard matrix scan — map browser `KeyboardEvent` codes to the C64 8x8 keyboard matrix.
|
|
73
|
+
- Joystick via CIA1 ($DC01 port 1) and CIA1 ($DC00 port 2) — Lords of Midnight uses keyboard, but joystick support enables other games.
|
|
74
|
+
|
|
75
|
+
## Lords of Midnight Compatibility
|
|
76
|
+
|
|
77
|
+
The target game exercises these specific features:
|
|
78
|
+
- Custom character sets (redefined at $3000 or similar)
|
|
79
|
+
- Full keyboard input (directional + action keys)
|
|
80
|
+
- Raster interrupts for split-screen effects
|
|
81
|
+
- IRQ-driven game loop timing via CIA timer
|
|
82
|
+
- PRG loading at the correct start address
|
|
83
|
+
|
|
84
|
+
## Requirements
|
|
85
|
+
|
|
86
|
+
- No external dependencies for the core emulator (Web Audio API and Canvas API are browser-provided).
|
|
87
|
+
- KERNAL and BASIC ROMs must NOT be bundled (they are copyrighted). Provide a `loadROMs(c64, { kernal, basic, chargen })` function. Tests should use minimal stub ROMs.
|
|
88
|
+
- Comprehensive unit tests for each subsystem:
|
|
89
|
+
- CPU: test each addressing mode and instruction, verify cycle counts, test interrupt handling.
|
|
90
|
+
- Memory: test bank switching, I/O area mapping.
|
|
91
|
+
- VIC-II: test mode switching, framebuffer output for known register states.
|
|
92
|
+
- Input: test keyboard matrix encoding/decoding.
|
|
93
|
+
- Integration test: load a small test PRG that writes to screen memory and verify framebuffer output.
|
|
94
|
+
- README with architecture overview, usage example, and instructions for obtaining legal ROM dumps.
|
|
95
|
+
|
|
96
|
+
## Acceptance Criteria
|
|
97
|
+
|
|
98
|
+
- [ ] CPU executes all 151 official opcodes with correct results and cycle counts
|
|
99
|
+
- [ ] CPU handles IRQ and NMI interrupts correctly (push PC+flags, jump to vector)
|
|
100
|
+
- [ ] Memory bank switching works ($01 register controls ROM/RAM visibility)
|
|
101
|
+
- [ ] VIC-II text mode renders 40x25 character display to framebuffer
|
|
102
|
+
- [ ] VIC-II raster interrupt fires at the programmed scanline
|
|
103
|
+
- [ ] SID produces audible waveform output for at least triangle and pulse waves
|
|
104
|
+
- [ ] CIA1 keyboard matrix correctly maps key presses to the scanned row/column
|
|
105
|
+
- [ ] `loadPRG()` places data at the correct address from the PRG header
|
|
106
|
+
- [ ] `runFrame()` executes approximately the right number of cycles per frame (PAL timing)
|
|
107
|
+
- [ ] A test PRG that writes "HELLO" to screen RAM ($0400) produces correct framebuffer output
|
|
108
|
+
- [ ] `reset()` returns the emulator to a known initial state
|
|
109
|
+
- [ ] All unit tests pass
|
|
110
|
+
- [ ] README documents architecture and ROM loading
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>repository0</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { font-family: system-ui, -apple-system, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; color: #333; }
|
|
9
|
+
h1 { border-bottom: 2px solid #eee; padding-bottom: 0.5rem; }
|
|
10
|
+
a { color: #0366d6; }
|
|
11
|
+
.status { background: #f6f8fa; padding: 1rem; border-radius: 6px; margin: 1rem 0; }
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>repository0</h1>
|
|
16
|
+
<div class="status">
|
|
17
|
+
<p>This website is maintained by the autonomous pipeline. It showcases the library built from the project's mission.</p>
|
|
18
|
+
</div>
|
|
19
|
+
<h2>About</h2>
|
|
20
|
+
<p>See <a href="https://github.com/xn-intenton-z2a/repository0">the repository</a> for source code and mission details.</p>
|
|
21
|
+
<h2>Demo</h2>
|
|
22
|
+
<p><em>The pipeline will evolve this section to demonstrate the library's capabilities.</em></p>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
@@ -5,16 +5,18 @@
|
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/lib/main.js",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"build": "
|
|
8
|
+
"build": "npm run build:web",
|
|
9
|
+
"build:web": "mkdir -p docs && touch docs/.nojekyll && cp -r src/web/* docs/ 2>/dev/null || echo 'No web files to build'",
|
|
9
10
|
"test": "vitest --run tests/unit/*.test.js",
|
|
10
11
|
"test:unit": "vitest --run --coverage tests/unit/*.test.js",
|
|
11
|
-
"start": "node src/lib/main.js"
|
|
12
|
+
"start": "node src/lib/main.js",
|
|
13
|
+
"start:web": "npx serve docs"
|
|
12
14
|
},
|
|
13
15
|
"keywords": [],
|
|
14
16
|
"author": "",
|
|
15
17
|
"license": "MIT",
|
|
16
18
|
"dependencies": {
|
|
17
|
-
"@xn-intenton-z2a/agentic-lib": "^7.1.
|
|
19
|
+
"@xn-intenton-z2a/agentic-lib": "^7.1.63"
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
22
|
"@vitest/coverage-v8": "^4.0.18",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (C) 2025-2026 Polycode Limited
|
|
3
|
+
import { describe, test, expect } from "vitest";
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
|
|
6
|
+
describe("Website", () => {
|
|
7
|
+
test("src/web/index.html exists", () => {
|
|
8
|
+
expect(existsSync("src/web/index.html")).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("index.html contains valid HTML structure", () => {
|
|
12
|
+
const html = readFileSync("src/web/index.html", "utf8");
|
|
13
|
+
expect(html).toContain("<!DOCTYPE html>");
|
|
14
|
+
expect(html).toContain("<html");
|
|
15
|
+
expect(html).toContain("</html>");
|
|
16
|
+
});
|
|
17
|
+
});
|