Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,20 @@
],
"scripts": []
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
}
},
"cli": {
"analytics": false
}
}
140 changes: 140 additions & 0 deletions docs/AGENT_PROMPT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
You are a senior Staff-level Angular + TypeScript engineer and security-minded reviewer.

Repository context:

- This is an Angular project recreating a Mac OS desktop experience in a web browser using Tailwind CSS.
- Priorities: maintainability, clarity, performance, and safe-by-default patterns.
- Keep behavior/UI/UX stable unless you are fixing a clear bug.

Primary goal:
Do a comprehensive review of the codebase and clean it up: organize, optimize, remove tech debt, align with industry standards, and improve safety/security.

Non-goals / Constraints:

- Do NOT do major framework upgrades (Angular major version, Tailwind major version) unless absolutely necessary; if you believe it’s necessary, document the rationale and stop before applying it.
- Avoid adding new dependencies unless there’s a strong justification (lint/format/test tooling is allowed if the repo is missing basics, but prefer using existing tooling).
- Keep refactors incremental and reviewable (small cohesive commits if possible).
- Do not delete functionality; deprecate or isolate if needed.
- If you are uncertain whether a change alters runtime behavior, do NOT guess—document the uncertainty and propose a safer alternative.

Workflow (follow in order):

1) Baseline discovery (no code changes yet)

- Read and summarize: package.json scripts, angular.json, tsconfig*, tailwind config, and overall folder layout.
- Identify how the app is structured (apps/windows/overlays/app manager/etc).
- Identify quality gates that exist already (lint, format, tests, build).
- If tool execution is available, run the project’s existing commands (in this order): install (npm ci or npm install), lint, unit tests, build. Record outputs.

2) Produce an “Audit & Plan” before refactoring
Create a short plan (bulleted) and categorize findings:

- Quick wins (mechanical / low risk)
- Medium refactors (worth it but need care)
- Larger changes (risky; propose but do not implement unless clearly safe)
For each item: describe the problem, proposed fix, risk level, and how you’ll validate it.

Pay special attention to these services (review them early and document issues/patterns):

- sound.service.ts
- user.service.ts
- overlay.service.ts
- cli.service.ts
- typewriter.service.ts
- settings.service.ts
- application-manager.service.ts
- media.service.ts
- storage.service.ts
- file-system.service.ts
- game-config.service.ts

3) Implement improvements (in small, safe steps)
Apply the plan with an emphasis on:
Code quality & architecture:

- Consistent naming, folder structure, and separation of concerns.
- Reduce circular dependencies and “god services”.
- Prefer explicit interfaces/types over `any`.
- Improve error handling; remove noisy logs; standardize logging if present.
Angular & RxJS best practices:
- Ensure subscriptions don’t leak (use takeUntilDestroyed if available; otherwise a consistent teardown pattern).
- Avoid nested subscriptions; prefer pipeable operators; handle errors.
- Avoid direct DOM manipulation; use Angular patterns (Renderer2, sanitization where appropriate).
Performance:
- Avoid heavy synchronous work on the UI thread; debounce/throttle where appropriate.
- Ensure Tailwind usage is efficient (remove unused classes/duplicates if reasonable).
Security / safety review:
- Check for XSS vectors (innerHTML, bypassSecurityTrust*, DOM insertion).
- Validate/sanitize any user-controlled inputs (e.g., CLI commands, filenames, “paths”, storage keys).
- Ensure localStorage/sessionStorage usage is safe and scoped; avoid storing secrets.
- Run npm audit if available; do NOT blindly “audit fix” if it risks breaking builds—document what you would change.

Validation:

- After each meaningful change, rerun the relevant checks (lint/tests/build).
- If tests are missing for critical logic, add a minimal set for the riskiest modules/services (prioritize CLI parsing, file-system/storage behaviors, and application/window manager state logic).

4) Create documentation under /docs (required output)
Create /docs at the project root (if it doesn’t exist), and organize it into these subfolders:

- /docs/ARCHITECTURE
- /docs/README
- /docs/TODOS
- /docs/FUTURE_FEATURES
(If the repository already uses the misspellings “ARCHETECTURE” or “FURTURE_FFEATURES”, match the existing convention, but prefer corrected names for new repos.)

All docs must be Markdown. Create at minimum:

/docs/README/INDEX.md

- A hub that links to every doc below.

/docs/README/PROJECT_OVERVIEW.md

- What this project is, the user experience it recreates, key features.
- Tech stack summary (Angular + Tailwind + notable libs).
- Folder/module map and where to start reading the code.

/docs/README/DEVELOPMENT.md

- Setup instructions, common scripts, how to run locally, how to build, how to test, troubleshooting tips.

/docs/ARCHITECTURE/OVERVIEW.md

- System overview and major subsystems (desktop, windows/apps, overlays, settings, storage, media/sound, CLI).
- Include a Mermaid diagram for high-level architecture (components/services and relationships).

/docs/ARCHITECTURE/SERVICES.md

- A section for each key service listed above:
- Responsibility
- Key methods/events/observables
- Dependencies (what it calls / what calls it)
- Risks/footguns
- Recommended improvements (and what you implemented)

/docs/ARCHITECTURE/STATE_EVENTS.md

- Explain state management approach, event flows, window/app lifecycle, persistence strategy, and how overlays interact with apps/windows.

/docs/ARCHITECTURE/SECURITY.md

- Threat model relevant to this app (XSS, injection via CLI, unsafe storage, supply chain).
- Findings + mitigations you applied; remaining risks.

/docs/TODOS/TECH_DEBT.md

- A prioritized checklist of remaining tech debt with impact + effort estimates (S/M/L) and suggested order of operations.

/docs/FUTURE_FEATURES/ROADMAP.md

- A realistic roadmap: short-term enhancements, medium-term refactors, long-term features.
- Call out dependencies/risks for each.

5) Final output (what you tell me)
When finished, respond with:

- A concise summary of what you changed and why (grouped by category).
- Commands you ran + results (lint/tests/build/audit).
- A “review checklist” for me to validate changes quickly.
- Any follow-up items you intentionally did not change (and why).
54 changes: 27 additions & 27 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,56 +1,56 @@
import js from "@eslint/js";
import eslint from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import json from "@eslint/json";
import { defineConfig } from "eslint/config";
import angular from "@analogjs/vite-plugin-angular";
import eslint from "@eslint/css";
import angular from "angular-eslint";


export default defineConfig([
{ files: ["**/*.{js,mjs,cjs,ts}"], plugins: { js }, extends: ["js/recommended"] },
{ files: ["**/*.{js,mjs,cjs,ts}"], languageOptions: { globals: globals.browser } },
tseslint.configs.recommended,
{ files: ["**/*.json"], plugins: { json }, language: "json/json", extends: ["json/recommended"] },
{ files: ["**/*.jsonc"], plugins: { json }, language: "json/jsonc", extends: ["json/recommended"] },
{files: ["**/*.css"], plugins: {eslint}, language: "css/css", extends: ["css/recommended"]},
]);

module.exports = tseslint.config(
export default tseslint.config(
{
ignores: [
"dist/**",
"coverage/**",
"node_modules/**",
".angular/**",
"out-tsc/**"
]
},
{
files: ["**/*.ts"],
extends: [
eslint.configs.recommended,
...tseslint.configs.recommended,
...tseslint.configs.stylistic,
...angular.configs.tsRecommended,
...angular.configs.tsRecommended
],
languageOptions: {
globals: {
...globals.browser,
...globals.node
}
},
processor: angular.processInlineTemplates,
rules: {
"@angular-eslint/directive-selector": [
"error",
{
type: "attribute",
prefix: "app",
style: "camelCase",
},
style: "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
type: "element",
prefix: "app",
style: "kebab-case",
},
],
},
style: "kebab-case"
}
]
}
},
{
files: ["**/*.html"],
extends: [
...angular.configs.templateRecommended,
...angular.configs.templateAccessibility,
],
rules: {},
...angular.configs.templateAccessibility
]
}
);
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
"build": "ng build",
"build:css": "npx tailwindcss -o ./dist/output.css --minify",
"watch": "ng build --watch --configuration development",
"test": "ng test --include='**/'",
"test": "ng test",
"lint": "ng lint"
},
"engines": {
"node": ">=20.11 <23"
},
"private": true,
"dependencies": {
"@angular/animations": "^19.2.14",
Expand Down
56 changes: 55 additions & 1 deletion src/app/components/game/apps/cli-game/cli-game.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,68 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {BehaviorSubject, of} from 'rxjs';
import {TypewriterService} from '../../services/typewriter.service';
import {SoundService} from '../../services/sound.service';
import {CLIService} from '../../services/cli.service';
import {GameConfigService} from '../../services/game-config.service';
import {ApplicationManagerService} from '../../services/application-manager.service';
import {AiChatService} from '../../services/ai-chat.service';
import {UserService} from '../../services/user.service';
import {NotificationService} from '../../services/notification.service';
import {LogService} from '../../services/log.service';

import { CliGameComponent } from './cli-game.component';

describe('CliGameComponent', () => {
let component: CliGameComponent;
let fixture: ComponentFixture<CliGameComponent>;
const typewriterServiceMock = {
typedText$: new BehaviorSubject<string>(''),
activeMode$: new BehaviorSubject<'default' | 'system' | 'dramatic'>('default'),
lineCompleted$: new BehaviorSubject<void>(undefined),
enqueueLine: jasmine.createSpy('enqueueLine'),
clear: jasmine.createSpy('clear')
};
const soundServiceMock = jasmine.createSpyObj<SoundService>('SoundService', ['bootAudio', 'stopAll', 'play']);
soundServiceMock.bootAudio.and.returnValue(Promise.resolve());
const cliServiceMock = {
executeInput: jasmine.createSpy('executeInput').and.returnValue({status: 200, output: 'ok'})
};
const gameConfigServiceMock = {
getAvailableCommands: jasmine.createSpy('getAvailableCommands').and.returnValue([]),
loadLevels: jasmine.createSpy('loadLevels').and.returnValue(Promise.resolve())
};
const appManagerServiceMock = {
closeApplication: jasmine.createSpy('closeApplication')
};
const aiChatServiceMock = {
generateAiAnswer: jasmine.createSpy('generateAiAnswer').and.returnValue(of({choices: []}))
};
const userServiceMock = {
user: {level: 1},
previousLevel: 1
};
const notificationServiceMock = {
show: jasmine.createSpy('show')
};
const loggerMock = {
logs$: new BehaviorSubject([]),
getLogsPage: jasmine.createSpy('getLogsPage').and.returnValue([])
};

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [CliGameComponent]
imports: [CliGameComponent],
providers: [
{provide: TypewriterService, useValue: typewriterServiceMock},
{provide: SoundService, useValue: soundServiceMock},
{provide: CLIService, useValue: cliServiceMock},
{provide: GameConfigService, useValue: gameConfigServiceMock},
{provide: ApplicationManagerService, useValue: appManagerServiceMock},
{provide: AiChatService, useValue: aiChatServiceMock},
{provide: UserService, useValue: userServiceMock},
{provide: NotificationService, useValue: notificationServiceMock},
{provide: LogService, useValue: loggerMock}
]
})
.compileComponents();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {provideHttpClient} from '@angular/common/http';
import {provideHttpClientTesting} from '@angular/common/http/testing';

import {SpaceXComponent} from './space-x.component';

Expand All @@ -8,7 +10,8 @@ describe('SpaceXComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SpaceXComponent]
imports: [SpaceXComponent],
providers: [provideHttpClient(), provideHttpClientTesting()]
})
.compileComponents();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {provideHttpClient} from '@angular/common/http';
import {provideHttpClientTesting} from '@angular/common/http/testing';

import {SpacexCrewComponent} from './spacex-crew.component';

Expand All @@ -8,7 +10,8 @@ describe('SpacexCrewComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SpacexCrewComponent]
imports: [SpacexCrewComponent],
providers: [provideHttpClient(), provideHttpClientTesting()]
})
.compileComponents();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {provideHttpClient} from '@angular/common/http';
import {provideHttpClientTesting} from '@angular/common/http/testing';

import {SpacexLaunchpadComponent} from './spacex-launchpad.component';

Expand All @@ -8,7 +10,8 @@ describe('SpacexLaunchpadComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SpacexLaunchpadComponent]
imports: [SpacexLaunchpadComponent],
providers: [provideHttpClient(), provideHttpClientTesting()]
})
.compileComponents();

Expand Down
Loading
Loading