diff --git a/README.md b/README.md index a7ce9da4..94ffa204 100644 --- a/README.md +++ b/README.md @@ -105,8 +105,8 @@ Shared code (`packages/core`, `packages/webui`) is reused in two delivery forms: a standalone tool (browser + local REST/WS server) and a VS Code extension (Webview + direct `core` import in the extension host, without HTTP where possible). See `docs/adr/0001-shared-core-two-delivery-targets.md` for -the full rationale and `openspec/specs/` (after the first `apply`) for the -detailed behavioral contract of each part. +the full rationale and `openspec/specs/` for the detailed behavioral +contract of each part. ```mermaid flowchart TD @@ -295,15 +295,26 @@ npm run start --workspace @openspec-ui/cli -- validate --cwd . --format text 1. Read `docs/adr/0001-*.md` — the architecture decisions and rejected alternatives. -2. Start with `openspec/changes/execution-core/`: `server`, `webui`, and - `extension` depend on the contract defined there (the unified - command/event protocol and the security model). -3. Then `shared-ui`, followed by `standalone-app` and `vscode-extension` in - parallel. -4. For each change: run `openspec change validate --strict ` before - marking tasks done; run `openspec archive --yes` only after a live - verification (see `operations.archive.guidance` in `openspec/config.yaml`) — - not earlier. +2. Read `openspec/README.md` — the runbook for this repository's governed + change workflow. +3. The four foundational changes (`execution-core`, `shared-ui`, + `standalone-app`, `vscode-extension`) are already implemented; find them + under `openspec/changes/archive/`. Run `openspec list` to see what is + currently active in `openspec/changes/`. +4. Every further repository modification — code, tests, docs, or tooling — + follows the same cycle: + + ```mermaid + flowchart LR + A["openspec/changes/<id>/
proposal.md + tasks.md"] --> B["Implement tasks.md;
tsc / eslint / vitest green"] + B --> C["openspec change validate
--strict <id>"] + C --> D["openspec archive <id>
(after live verification)"] + D --> E["openspec/changes/archive/
+ openspec/specs/ updated"] + ``` + + See `operations.apply.guidance` and `operations.archive.guidance` in + `openspec/config.yaml` for exactly what must be verified at each step — + archiving before live verification is out of process. ## Change Governance diff --git a/openspec/changes/document-product-screenshots/.openspec.yaml b/openspec/changes/archive/2026-08-23-document-product-screenshots/.openspec.yaml similarity index 100% rename from openspec/changes/document-product-screenshots/.openspec.yaml rename to openspec/changes/archive/2026-08-23-document-product-screenshots/.openspec.yaml diff --git a/openspec/changes/document-product-screenshots/proposal.md b/openspec/changes/archive/2026-08-23-document-product-screenshots/proposal.md similarity index 100% rename from openspec/changes/document-product-screenshots/proposal.md rename to openspec/changes/archive/2026-08-23-document-product-screenshots/proposal.md diff --git a/openspec/changes/document-product-screenshots/tasks.md b/openspec/changes/archive/2026-08-23-document-product-screenshots/tasks.md similarity index 100% rename from openspec/changes/document-product-screenshots/tasks.md rename to openspec/changes/archive/2026-08-23-document-product-screenshots/tasks.md diff --git a/openspec/changes/restore-typescript-eslint-compatibility/.openspec.yaml b/openspec/changes/archive/2026-08-23-restore-typescript-eslint-compatibility/.openspec.yaml similarity index 100% rename from openspec/changes/restore-typescript-eslint-compatibility/.openspec.yaml rename to openspec/changes/archive/2026-08-23-restore-typescript-eslint-compatibility/.openspec.yaml diff --git a/openspec/changes/restore-typescript-eslint-compatibility/proposal.md b/openspec/changes/archive/2026-08-23-restore-typescript-eslint-compatibility/proposal.md similarity index 100% rename from openspec/changes/restore-typescript-eslint-compatibility/proposal.md rename to openspec/changes/archive/2026-08-23-restore-typescript-eslint-compatibility/proposal.md diff --git a/openspec/changes/restore-typescript-eslint-compatibility/tasks.md b/openspec/changes/archive/2026-08-23-restore-typescript-eslint-compatibility/tasks.md similarity index 100% rename from openspec/changes/restore-typescript-eslint-compatibility/tasks.md rename to openspec/changes/archive/2026-08-23-restore-typescript-eslint-compatibility/tasks.md diff --git a/openspec/changes/templates-grouped-by-category/.openspec.yaml b/openspec/changes/archive/2026-08-23-templates-grouped-by-category/.openspec.yaml similarity index 100% rename from openspec/changes/templates-grouped-by-category/.openspec.yaml rename to openspec/changes/archive/2026-08-23-templates-grouped-by-category/.openspec.yaml diff --git a/openspec/changes/templates-grouped-by-category/proposal.md b/openspec/changes/archive/2026-08-23-templates-grouped-by-category/proposal.md similarity index 100% rename from openspec/changes/templates-grouped-by-category/proposal.md rename to openspec/changes/archive/2026-08-23-templates-grouped-by-category/proposal.md diff --git a/openspec/changes/templates-grouped-by-category/smoke-test-notes.md b/openspec/changes/archive/2026-08-23-templates-grouped-by-category/smoke-test-notes.md similarity index 100% rename from openspec/changes/templates-grouped-by-category/smoke-test-notes.md rename to openspec/changes/archive/2026-08-23-templates-grouped-by-category/smoke-test-notes.md diff --git a/openspec/changes/templates-grouped-by-category/specs/template-catalog/spec.md b/openspec/changes/archive/2026-08-23-templates-grouped-by-category/specs/template-catalog/spec.md similarity index 100% rename from openspec/changes/templates-grouped-by-category/specs/template-catalog/spec.md rename to openspec/changes/archive/2026-08-23-templates-grouped-by-category/specs/template-catalog/spec.md diff --git a/openspec/changes/templates-grouped-by-category/tasks.md b/openspec/changes/archive/2026-08-23-templates-grouped-by-category/tasks.md similarity index 100% rename from openspec/changes/templates-grouped-by-category/tasks.md rename to openspec/changes/archive/2026-08-23-templates-grouped-by-category/tasks.md diff --git a/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/.openspec.yaml b/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/.openspec.yaml new file mode 100644 index 00000000..d5177d37 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/.openspec.yaml @@ -0,0 +1,3 @@ +schema: spec-driven +created: 2026-08-24 +skip_specs: true diff --git a/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/proposal.md b/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/proposal.md new file mode 100644 index 00000000..29c04074 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/proposal.md @@ -0,0 +1,45 @@ +## Why + +Raised directly during a repository review session on 2026-08-24 (the user's +own observation that OpenSpec's governed workflow is not understood by +newcomers): `README.md`'s "Getting Started" section (lines 294-306) still +tells a new reader to "Start with `openspec/changes/execution-core/`", then +`shared-ui`, `standalone-app`, `vscode-extension`. All four of those changes +are already implemented and archived under `openspec/changes/archive/` +(`2026-08-13-execution-core`, `2026-08-13-shared-ui`, +`2026-08-13-standalone-app`, `2026-08-13-vscode-extension`) — the directories +this section tells a reader to open no longer exist at that path. A newcomer +following this section hits a dead end, which actively works against the +goal of making the governed OpenSpec workflow understandable. The adjacent +"Architecture at a Glance" section (line 108) has the same staleness: it +describes `openspec/specs/` as populated "after the first `apply`", but the +first `apply` happened long ago and `openspec/specs/` already holds 14 +capability specs. + +## What Changes + +- Rewrite `README.md`'s "Getting Started" section to describe the workflow + that actually applies today: the four foundational changes are already + done; every further repository modification (code, tests, docs, tooling) + follows the same governed cycle (propose → implement `tasks.md` → `openspec + change validate --strict ` → `openspec archive ` after live + verification), with a short diagram of that cycle and a pointer to `openspec + list` to see what is currently active. +- Drop the now-inaccurate "(after the first `apply`)" qualifier in + "Architecture at a Glance" (line 108). +- No change to any other README section, to `openspec/README.md`, or to + `openspec/config.yaml`. + +## Capabilities + +### New Capabilities + +(none) + +### Modified Capabilities + +(none; this is a documentation-only change) + +## Impact + +- `README.md` diff --git a/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/tasks.md b/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/tasks.md new file mode 100644 index 00000000..c0967150 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-refresh-readme-getting-started/tasks.md @@ -0,0 +1,16 @@ +## 1. Rewrite the stale onboarding narrative + +- [x] 1.1 Replace `README.md`'s "Getting Started" section: remove the + "start with `execution-core`" bootstrap sequence (already archived) and + describe the current propose/implement/validate/archive cycle, with a + pointer to `openspec list` for what is currently active. +- [x] 1.2 Remove the "(after the first `apply`)" qualifier in "Architecture + at a Glance" now that `openspec/specs/` is populated. + +## 2. Verification + +- [x] 2.1 Every path and command referenced in the rewritten section + actually exists / runs (`openspec/README.md`, `openspec/config.yaml`, + `openspec list`, `openspec change validate --strict`, `openspec archive`). +- [x] 2.2 `npm run lint:english` passes (no new Cyrillic introduced). +- [x] 2.3 Run `openspec change validate --strict refresh-readme-getting-started`. diff --git a/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/.openspec.yaml b/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/.openspec.yaml new file mode 100644 index 00000000..d5177d37 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/.openspec.yaml @@ -0,0 +1,3 @@ +schema: spec-driven +created: 2026-08-24 +skip_specs: true diff --git a/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/proposal.md b/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/proposal.md new file mode 100644 index 00000000..39ba10a3 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/proposal.md @@ -0,0 +1,46 @@ +## Why + +Found during a repository review session on 2026-08-24, confirmed by the +existing `npm run lint` output: `readStoredValue` in +`packages/webui/src/standalone-entry.tsx` is unused +(`@typescript-eslint/no-unused-vars`). Its sibling `writeStoredValue` calls +(lines persisting `cwd`/`changeDir` to `localStorage` on every change) are +therefore write-only — nothing ever reads the persisted values back. This +diverges from the equivalent extension bootstrap +(`packages/webui/src/extension-context.ts`'s `resolveInitialDashboardContext`, +consumed by `packages/webui/src/extension-entry.tsx`), which does restore +`cwd`/`changeDir` from storage as a fallback. In the standalone app, when the +`/api/workspace-root` sync fails (the existing `workspaceRootSyncError` state, +rendered at `standalone-entry.tsx`'s "Workspace root sync failed" note), the +`cwd`/`changeDir` inputs stay blank instead of falling back to the +last-known values already sitting in `localStorage`. + +## What Changes + +- Initialize the `cwd`/`changeDir` state in `StandaloneApp` + (`packages/webui/src/standalone-entry.tsx`) from + `readStoredValue(STORAGE_KEYS.cwd)` / `readStoredValue(STORAGE_KEYS.changeDir)` + instead of `""`, matching the fallback pattern already used by the + extension bootstrap. +- No change to `writeStoredValue` call sites, `STORAGE_KEYS`, or the + `/api/workspace-root` sync effect, which still overwrites these fields on a + successful sync — this only changes what the fields show before that sync + resolves or if it fails. + +## Capabilities + +### New Capabilities + +(none) + +### Modified Capabilities + +(none; `openspec/specs/standalone-app/spec.md` does not document a +`localStorage` fallback scenario for `cwd`/`changeDir` — this restores +already-intended, already-shipped-but-inert behavior rather than changing a +specified one) + +## Impact + +- `packages/webui/src/standalone-entry.tsx` +- `packages/webui/package.json` (patch version bump) diff --git a/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/tasks.md b/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/tasks.md new file mode 100644 index 00000000..752a702f --- /dev/null +++ b/openspec/changes/archive/2026-08-24-restore-standalone-workspace-fallback/tasks.md @@ -0,0 +1,13 @@ +## 1. Restore the localStorage fallback + +- [x] 1.1 In `packages/webui/src/standalone-entry.tsx`, initialize `cwd` from + `readStoredValue(STORAGE_KEYS.cwd)` and `changeDir` from + `readStoredValue(STORAGE_KEYS.changeDir)`. +- [x] 1.2 Bump `packages/webui/package.json` to the next patch version. + +## 2. Verification + +- [x] 2.1 `npm run lint --workspace @openspec-ui/webui` no longer reports + `readStoredValue` as unused. +- [x] 2.2 `npm run typecheck` and `npm run test` pass workspace-wide. +- [x] 2.3 Run `openspec change validate --strict restore-standalone-workspace-fallback`. diff --git a/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/.openspec.yaml b/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/.openspec.yaml new file mode 100644 index 00000000..d5177d37 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/.openspec.yaml @@ -0,0 +1,3 @@ +schema: spec-driven +created: 2026-08-24 +skip_specs: true diff --git a/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/proposal.md b/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/proposal.md new file mode 100644 index 00000000..f3cddfd2 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/proposal.md @@ -0,0 +1,100 @@ +## Why + +A repository review session on 2026-08-24 found that `CLAUDE.md`'s mandatory +English-only policy ("All code comments, descriptions, and markdown files in +this repository must be written in English only") is enforced by +`scripts/check-english.mjs` (`npm run lint:english`), but that script's +`scripts/english-policy-baseline.json` grandfathers in every line of +Cyrillic text that existed when the policy was introduced. The baseline held +635 lines across 73 tracked files — comments, JSDoc, and a handful of test +fixture strings — silently exempted from a policy that is supposed to apply +repo-wide. This is baseline debt: the check passes, but the policy is not +actually met for pre-existing content. + +## What Changes + +- Translate all 635 previously baselined lines, across all 73 affected + files, from Russian to English, preserving technical meaning exactly + (not a rewrite or a summary — a faithful translation of comments, + JSDoc, and the two archived-change markdown notes files). +- Where a baselined line's Russian text was itself the value under test + (`packages/core/src/change-state.test.ts`'s fixture markdown, + `packages/webui/src/markdown.test.tsx`/`SpecsSearch.test.tsx`/ + `SpecsTree.test.tsx`/`RequirementView.test.tsx`/`ChangeRelations.test.tsx`'s + sample strings, `packages/core/src/security.test.ts`'s and + `packages/core/src/agent-runner.test.ts`'s prompt-injection fixture text), + translate the fixture content too and update the corresponding assertions + in the same file so the test keeps checking the same behavior. None of the + 635 lines were left untouched — every baselined line was either a + translatable comment/JSDoc/doc line, or fixture text whose language is + incidental to what the test verifies (substring/shape checks, not a + byte-for-byte external contract). `packages/core/src/openspec-fixtures/show.json` + (explicitly exempt from scanning, a real `openspec` CLI capture) and + `scripts/check-english.test.mjs` (Cyrillic is the intentional subject of + that file's own scanner tests, marked `english-policy-allow`) were correctly + never baselined and were left as-is. +- `packages/core/src/agents/shared.ts`'s `commandInstruction()` also + returned Russian text for the `plan`/`implement`/`review`/`status`/ + `cancel` command kinds — this is not a comment, it is the literal + instruction prefix sent to CLI agents (Claude/Copilot/Codex/Gemini/local + LLM) as part of the real prompt. The `list`/`show`/`validate` branches of + the same `switch` were already in English, so the function was internally + inconsistent before this change. Translated the remaining branches to + English to match, which is a small runtime behavior change (the literal + text sent to CLI agents for those five command kinds) beyond pure comment + translation — flagged explicitly here since it is not "no behavior change" + in the strictest sense, even though no test asserts the exact string and + all CLI agents understand English at least as well as Russian. +- Regenerate `scripts/english-policy-baseline.json` via + `node scripts/check-english.mjs --write-baseline` after all translations + were complete, so it now reflects the true remaining state (empty — no + Cyrillic remains in scanned files outside the two exempt cases above). + +## Capabilities + +### New Capabilities + +(none) + +### Modified Capabilities + +(none; `.openspec.yaml` sets `skip_specs: true`. Primarily comment/doc/test- +fixture-text translation; the one exception — +`commandInstruction()`'s runtime prompt text — does not change any command +or event in the protocol defined in `packages/core`, so it does not rise to +a specified capability change) + +## Impact + +- `eslint.config.js` +- `openspec/changes/archive/2026-08-13-standalone-app/smoke-test-notes.md` +- `openspec/changes/archive/2026-08-13-vscode-extension/TEST-NOTES.md` +- `packages/core/src/agent-runner.ts`, `agent-runner.test.ts` +- `packages/core/src/agents/claude.ts`, `codex.ts`, `copilot.ts`, `gemini.ts`, + `local-llm.ts`, `registry.ts`, `shared.ts`, `shared.test.ts` +- `packages/core/src/browser.ts`, `change-state.ts`, `change-state.test.ts`, + `default-runners.ts`, `git.ts`, `index.ts`, `openspec.ts`, + `openspec.test.ts`, `protocol.ts`, `security.ts`, `security.test.ts` +- `packages/extension/scripts/build-options.mjs` +- `packages/extension/src/commands.ts`, `config.ts`, `extension.ts`, + `run-controller.ts`, `vitest.config.ts` +- `packages/extension/src/native/diff.ts`, `git.ts`, `open-doc.ts` +- `packages/extension/src/test-utils/vscode-mock.ts` +- `packages/extension/src/test/run.mjs`, `test/suite/extension.test.ts`, + `test/suite/index.ts` +- `packages/extension/src/webview/ai-panel.ts` +- `packages/server/scripts/build-client.mjs`, `client-build-options.mjs` +- `packages/server/src/cli.ts`, `index.ts`, `rest.ts`, `server.ts`, + `server.test.ts`, `static.ts`, `static.test.ts`, `websocket.ts`, `wire.ts` +- `packages/webui/src/components/AiPanel.tsx`, `ArchiveList.tsx`, + `ChangeDiff.tsx`, `ChangeRelations.tsx`, `ChangeRelations.test.tsx`, + `ChangesList.tsx`, `RequirementView.tsx`, `RequirementView.test.tsx`, + `SpecsSearch.tsx`, `SpecsSearch.test.tsx`, `SpecsTree.tsx`, + `SpecsTree.test.tsx`, `TasksChecklist.tsx` +- `packages/webui/src/extension-entry.tsx`, `index.ts`, `markdown.tsx`, + `markdown.test.tsx`, `standalone-entry.tsx`, `types.ts` +- `packages/webui/src/transport/contract.test.ts`, + `fetch-transport.ts`, `fetch-transport.test.ts`, + `message-bridge-transport.ts`, `types.ts` +- `scripts/english-policy-baseline.json` (regenerated to reflect zero + remaining Cyrillic lines in scanned files) diff --git a/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/tasks.md b/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/tasks.md new file mode 100644 index 00000000..b5aea61b --- /dev/null +++ b/openspec/changes/archive/2026-08-24-translate-legacy-comments-to-english/tasks.md @@ -0,0 +1,84 @@ +## 1. Translate `packages/core` + +- [x] 1.1 Translate comments in `git.ts`, `index.ts`, `browser.ts`, + `default-runners.ts`, `change-state.ts`, `change-state.test.ts`, + `openspec.ts`, `openspec.test.ts`, `protocol.ts`. +- [x] 1.2 Translate `security.ts` (39 baselined lines: allowlist/cwd-sandbox + decision messages, the `prepareAgentContext` data/instructions header, + audit-log JSDoc) faithfully, preserving the security-invariant wording; + update `security.test.ts`'s matching assertions and its + prompt-injection fixture text to stay consistent with the translated + implementation strings it checks against. +- [x] 1.3 Translate `agent-runner.ts`/`agent-runner.test.ts`, including the + fallback failure-reason strings and the prompt-injection scenario text + in the test. +- [x] 1.4 Translate `agents/claude.ts`, `codex.ts`, `copilot.ts`, `gemini.ts`, + `local-llm.ts`, `registry.ts`, `shared.ts` (including the per-command + `commandInstruction()` prompt strings — a runtime behavior change, see + proposal.md's "What Changes"), `shared.test.ts`. + +## 2. Translate `packages/server` + +- [x] 2.1 Translate comments in `cli.ts`, `index.ts`, `websocket.ts`, + `wire.ts`, `rest.ts`, `static.ts`, `server.ts`, `static.test.ts`, + `server.test.ts`, `scripts/build-client.mjs`, + `scripts/client-build-options.mjs`. + +## 3. Translate `packages/extension` + +- [x] 3.1 Translate comments in `config.ts`, `commands.ts`, `extension.ts`, + `native/diff.ts`, `native/git.ts`, `native/open-doc.ts`, + `run-controller.ts`, `test-utils/vscode-mock.ts`, `webview/ai-panel.ts`. +- [x] 3.2 Translate comments in `test/suite/index.ts`, + `test/suite/extension.test.ts`, `test/run.mjs`, `vitest.config.ts`, + `scripts/build-options.mjs`. + +## 4. Translate `packages/webui` + +- [x] 4.1 Translate comments in `types.ts`, `transport/types.ts`, `index.ts`, + `transport/message-bridge-transport.ts`, `transport/fetch-transport.ts`, + `transport/fetch-transport.test.ts`, `transport/contract.test.ts`. +- [x] 4.2 Translate comments in `standalone-entry.tsx`, + `extension-entry.tsx`, `markdown.tsx`; translate `markdown.test.tsx`'s + sample strings and update its matching assertions. +- [x] 4.3 Translate `components/TasksChecklist.tsx`, + `components/RequirementView.tsx`, `components/RequirementView.test.tsx` + (sample requirement text + assertions), `components/SpecsSearch.tsx`, + `components/SpecsSearch.test.tsx` (fixture specs + query strings + + assertions), `components/SpecsTree.tsx`, `components/SpecsTree.test.tsx` + (fixture specs), `components/ChangesList.tsx`, `components/ChangeDiff.tsx`, + `components/ChangeRelations.tsx`, `components/ChangeRelations.test.tsx` + (fixture proposal text + assertions), `components/ArchiveList.tsx`, + `components/AiPanel.tsx`. + +## 5. Repo-level files + +- [x] 5.1 Translate `eslint.config.js`'s comment. +- [x] 5.2 Translate + `openspec/changes/archive/2026-08-13-standalone-app/smoke-test-notes.md` + and `openspec/changes/archive/2026-08-13-vscode-extension/TEST-NOTES.md` + in full (both are historical live-test notes from archived changes; no + functional content, safe to translate wholesale). + +## 6. Baseline and verification + +- [x] 6.1 Confirm no file was skipped: `packages/core/src/openspec-fixtures/show.json` + stays untouched (explicitly exempt from scanning — a captured real + `openspec` CLI response) and `scripts/check-english.test.mjs` stays + untouched (its Cyrillic lines are the intentional subject of the + scanner's own tests, marked `english-policy-allow`, and were never + baselined in the first place). +- [x] 6.2 Regenerate `scripts/english-policy-baseline.json` via + `node scripts/check-english.mjs --write-baseline` after all translations + above are complete. +- [x] 6.3 `npm run lint:english` passes (0 violations, empty baseline). +- [x] 6.4 `npm run typecheck` passes workspace-wide. +- [x] 6.5 `npm run test` passes workspace-wide (test:english + all package + test suites — 435 tests total, 0 failures). +- [x] 6.6 `openspec change validate --strict translate-legacy-comments-to-english` + passes. +- [x] 6.7 Reviewed independently (diff read for the highest-risk files — + `security.ts`/`security.test.ts`, `agents/shared.ts`, a sample + fixture+assertion pair in `SpecsSearch.test.tsx`) and re-ran + `typecheck`/`lint`/`test` from a clean checkout of the merged result, not + just trusting the translating agent's self-report. diff --git a/openspec/specs/template-catalog/spec.md b/openspec/specs/template-catalog/spec.md index b78eb9c5..99e5d5c0 100644 --- a/openspec/specs/template-catalog/spec.md +++ b/openspec/specs/template-catalog/spec.md @@ -82,7 +82,9 @@ project templates, customize a built-in one, insert a rendered template into the currently loaded Change Editor state) to its tab set. This tab SHALL be excluded from the VS Code local-server embed's allowed tab set, for the same reason as the other tabs VS Code already covers natively -(here: the VS Code Templates tree view). +(here: the VS Code Templates tree view). Within the tab, templates SHALL +be sorted and grouped by category (a subheader row per category +boundary), rather than presented in unsorted flat row order. #### Scenario: Plain standalone browser tab @@ -94,11 +96,21 @@ for the same reason as the other tabs VS Code already covers natively - **WHEN** the shell is loaded with the VS Code embed signal - **THEN** the Templates tab is not shown +#### Scenario: Templates are grouped by category + +- **WHEN** the Templates tab lists built-in and project templates + spanning more than one category +- **THEN** the rows are sorted by category, with a subheader row marking + each category boundary, instead of appearing in unsorted order + ### Requirement: VS Code exposes a native Templates tree with customize and insert actions The system SHALL provide a VS Code tree view listing built-in and -project-level templates. Built-in items SHALL offer a "Customize" action. -Any item SHALL offer an "Insert into…" action that prompts for a +project-level templates, grouped first by origin (Built-in / Project) +and then by category as an intermediate, alphabetically-sorted subgroup +level under each origin — a template SHALL NOT appear as a direct child +of an origin group. Built-in items SHALL offer a "Customize" action. Any +item SHALL offer an "Insert into…" action that prompts for a non-archived target change and the template's declared variables, then inserts the rendered artifacts into that change's proposal/design/tasks files as an undoable text edit — not a silent file write. @@ -107,7 +119,7 @@ files as an undoable text edit — not a silent file write. - **WHEN** the user runs "Customize" on a built-in tree item - **THEN** the corresponding project-level template appears in the tree - under the project section + under the project section, nested under its category subgroup #### Scenario: Inserting a template into a change @@ -116,6 +128,14 @@ files as an undoable text edit — not a silent file write. - **THEN** the target change's proposal.md, design.md, and tasks.md open with the rendered content appended, as undoable edits +#### Scenario: Built-in and project templates are grouped by category in the tree + +- **WHEN** the user expands the "Built-in" or "Project" group in the + Templates tree +- **THEN** its children are category subgroups sorted alphabetically by + category name, and expanding a category subgroup lists exactly the + templates in that category + ### Requirement: The project-level template manifest has VS Code schema validation The system SHALL register a JSON Schema for `openspec/templates/*/template.json` diff --git a/packages/webui/package.json b/packages/webui/package.json index 0b03989a..fd27a760 100644 --- a/packages/webui/package.json +++ b/packages/webui/package.json @@ -1,7 +1,7 @@ { "name": "@openspec-ui/webui", "private": true, - "version": "1.9.0", + "version": "1.9.1", "type": "module", "main": "src/index.ts", "dependencies": { diff --git a/packages/webui/src/standalone-entry.tsx b/packages/webui/src/standalone-entry.tsx index 9943106b..dc91c583 100644 --- a/packages/webui/src/standalone-entry.tsx +++ b/packages/webui/src/standalone-entry.tsx @@ -1,8 +1,8 @@ -// Точка входа для standalone-браузерного шелла (см. -// openspec/changes/standalone-app/tasks.md 2.1). Не часть публичного API -// пакета (не реэкспортируется из index.ts) — это bootstrap-код конкретно -// для сборки `packages/server` (см. scripts/build-client.mjs), а не -// библиотечный код, переиспользуемый в extension. +// Entry point for the standalone browser shell (see +// openspec/changes/standalone-app/tasks.md 2.1). Not part of the package's +// public API (not re-exported from index.ts) — this is bootstrap code +// specifically for `packages/server`'s build (see scripts/build-client.mjs), +// not library code reused in the extension. import { createRoot } from "react-dom/client"; import { Fragment, useEffect, useMemo, useState } from "react"; @@ -186,8 +186,8 @@ async function loadWorkspaceRoot(): Promise { function StandaloneApp() { const [activeTab, setActiveTab] = useState("run-a-command"); - const [cwd, setCwd] = useState(""); - const [changeDir, setChangeDir] = useState(""); + const [cwd, setCwd] = useState(() => readStoredValue(STORAGE_KEYS.cwd)); + const [changeDir, setChangeDir] = useState(() => readStoredValue(STORAGE_KEYS.changeDir)); const [overview, setOverview] = useState(null); const [overviewLoading, setOverviewLoading] = useState(false); const [overviewError, setOverviewError] = useState(null);