feat(core): the command line with its local commands after Java, measured against Java

The terminal splits a line as Java's window does and runs ls, cd, pwd,
mkdir, touch, cp, mv, rm, cat, test, help, ipconfig and route on the
node's files, which are the project's own. Its texts are generated from
the bundle Java loads. TerminalCases feeds Java's Terminal without a
network (16 cases, de and en); eight cases name Java bugs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 20:32:35 +00:00
co-authored by Claude Opus 5.5
parent 058675a148
commit 016f9461df
17 changed files with 14404 additions and 7 deletions
+16
View File
@@ -857,6 +857,22 @@ describe('importProject rules', () => {
expect(client('Rechner 3').account).toEqual(project.emailClientConfigurations.get(receiver)!.account);
});
it("keeps what the command line did to a node's files in the project saved after the run", () => {
const name = 'java-examples/Internet_Komplett_mit_eMail_Webserver_Intranet_Portforwarding_Firewall_DHCP_DE.fls';
const project = openProjectArchive(new Uint8Array(readFileSync(join(corpusRoot, name))), counter());
const notebook = project.graph.nodes.find((each) => each.displayName === 'Notebook' && project.deviceConfigurations.get(each.id)?.ipAddress === '10.10.20.11')!.id;
const snapshot = projectSnapshot(project);
expect(snapshot.terminalNodeIds.has(notebook)).toBe(true);
const engine = new NetworkRuntimeEngine(14);
engine.handle({ type: 'start', snapshot, seed: 14, initialTimeMilliseconds: 0 });
for (const line of ['mkdir Projekt', 'cd Projekt', 'touch plan.txt']) engine.terminal(notebook)!.enter(line);
engine.handle({ type: 'advance', toMilliseconds: 1_000 });
const reopened = openProjectArchive(saveProjectArchive(projectWithSimulationChanges(project, engine.state.topologySnapshot)).archive, counter());
const reopenedNotebook = reopened.graph.nodes.find((each) => each.displayName === 'Notebook' && reopened.deviceConfigurations.get(each.id)?.ipAddress === '10.10.20.11')!.id;
expect(reopened.virtualFileSystems.get(reopenedNotebook)!.entry('/Projekt/plan.txt').content).toEqual({ kind: 'text', text: '' });
});
it("keeps a node's IP forwarding where it differs from its kind's: a host that forwards, a router that does not", () => {
const system = (ipForwardingEnabled: boolean) => ({ manualRoutes: [], ipForwardingEnabled });
const project = importProject(