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
9 changes: 9 additions & 0 deletions .changeset/cli-is-visible-on-the-homepage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@openspec-ui/cli": minor
---

Expose CLI as a public product in the release manifest, with its package version,
summary and npm package link. The homepage can show CLI alongside the other
current releases and offer an npm button. Existing product identities and
manifest schema version 1 are unchanged; npm publication remains a separate
manual dispatch.
50 changes: 50 additions & 0 deletions openspec/changes/cli-is-visible-on-the-homepage/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Design

## Context

`MANIFEST_PRODUCTS` already includes `ci-cli`, but with `public: false`.
The homepage renders both sections from `manifest.public_products`. Its
reference schema is `OpenSpec-UI-Homepage/app/schemas/manifest.py`.

## Goals

Expose the CLI's package version, notes and npm destination to the site,
without altering the other four product identities or npm publishing.

## Non-Goals

GitHub CLI releases, download artifacts, a second CLI button, npm links for
private packages, implementation during proposal creation, and site deployment.

## Decisions

1. Preserve `ci-cli`; set `public: true` and a concise English summary.
Rejected: rename it to `cli`, which would split recorded release history.
2. Extend `ProductLinks` with optional `npm?: string`. Populate it only for
`ci-cli` with the package page URL above. The consumer adds the matching
optional field before production rollout. Keep `schema_version` at 1.
Rejected: use `marketplace` for npm, which confuses two distinct destinations;
rejected: version 2, which would make old consumers reject an additive change.
3. Keep the existing version fingerprint and webhook. The CLI minor changeset
ensures that the merged version commit changes the fingerprint and publishes
the visibility/link update. Do not claim that editing metadata alone triggers
publication. If rollout occurs before a version bump, it remains outstanding.
Rejected: widen fingerprint semantics for this one addition.
4. Versions still mean the version carried by the repository, not confirmed npm
registry availability. The npm button links to the package page, not an invented
version-specific artifact. npm publishing remains separately dispatched.

## Risks / Trade-offs

- An old homepage accepts but ignores `links.npm`; deploy its companion first.
- Until a version bump publishes a manifest and the site syncs, CLI stays hidden.
- A package version can precede npm publication; the card must not claim otherwise.
- All five products remain in the manifest; only Shared UI remains non-public.

## Compatibility and Verification

No core commands/events or server/webui/extension protocols change, so their
contract-test updates are not needed. Test public flags, stable identities,
CLI-only npm links, schema version, and serialization in the existing CLI suite.
Then validate a generated manifest with the homepage schema and verify the
signed-webhook/scheduled-sync rollout without dispatching an npm publication.
35 changes: 35 additions & 0 deletions openspec/changes/cli-is-visible-on-the-homepage/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Proposal

## Why

ADR-0009 makes `@openspec-ui/cli` an installable npm product, but the release
manifest marks `ci-cli` as non-public. The official homepage therefore omits
its version from both Current versions and Current releases.

## What Changes

- Mark the existing `ci-cli` product public, preserving its identity and version source.
- Add a CLI summary and optional `links.npm`, pointing to
`https://www.npmjs.com/package/@openspec-ui/cli`; no other product gets an npm link.
- Retain manifest schema version 1: the new link is optional and additive.
- Deliver the updated manifest through the existing release path and signed webhook.
- Coordinate with `OpenSpec-UI-Homepage` change `cli-is-visible-on-the-homepage`,
which renders the fourth tile/card and its npm button in the existing style.

## Capabilities

### New Capabilities

None.

### Modified Capabilities

- `release-quality`: the published manifest exposes CLI as public and supplies its npm destination.

## Impact

`packages/cli/src/release-manifest.ts`, its existing tests, and CLI documentation.
A minor changeset for `@openspec-ui/cli` is required at implementation time.
No GitHub CLI release, tarball, new CI publishing job, npm authentication fix,
or core command/event change is included. No architecture invariant changes;
ADR-0009 and ADR-0048 remain in force. This entry is planning only.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Release Quality Delta

## ADDED Requirements

### Requirement: The manifest exposes CLI as a public npm product

The manifest SHALL preserve the stable `ci-cli` identity and derive its version
from `packages/cli/package.json`. It SHALL mark CLI public, include a summary,
and include `links.npm` equal to `https://www.npmjs.com/package/@openspec-ui/cli`.
No other product SHALL gain an npm link in this change. All five product entries
SHALL remain present; Shared UI SHALL remain non-public.

#### Scenario: The CLI manifest is generated

- **WHEN** `write manifest` builds a complete manifest
- **THEN** CLI is public with its own package version, summary and npm link
- **AND** all five stable product ids remain present

#### Scenario: Existing products retain their destinations

- **WHEN** the updated manifest is generated
- **THEN** extension, standalone, core and Shared UI have no new npm link
- **AND** existing release artifacts and links remain unchanged

### Requirement: The CLI link is additive and delivered through the release path

`links.npm` SHALL be optional and the manifest SHALL retain schema version 1.
The CLI minor version bump SHALL trigger the existing fingerprint-based manifest
publication and notification path. This change SHALL NOT create a GitHub CLI
release or change separately dispatched npm publishing.

#### Scenario: An older consumer receives the npm link

- **WHEN** a schema-1 consumer that ignores unknown fields reads the new manifest
- **THEN** it accepts the manifest without requiring a schema-version upgrade

#### Scenario: The CLI version bump lands

- **WHEN** the change's CLI version bump lands on main
- **THEN** the version fingerprint changes and the existing release path publishes
CLI visibility and its npm destination for the homepage to consume
64 changes: 64 additions & 0 deletions openspec/changes/cli-is-visible-on-the-homepage/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Tasks

## 1. Manifest Producer

- [x] 1.1 In `packages/cli/src/release-manifest.ts`, set only `ci-cli.public`
to true and add its summary; preserve all five ids and package version sources.
- [x] 1.2 In `packages/cli/src/release-manifest.ts`, add optional `ProductLinks.npm`
and populate only the CLI destination `https://www.npmjs.com/package/@openspec-ui/cli`.
Keep schema version 1 and do not invent a GitHub release or artifact.
- [x] 1.3 In `packages/cli/src/release-manifest.test.ts`, assert four public products,
only Shared UI private, CLI summary/npm URL, other products without npm links,
all five stable ids, schema 1, and unchanged attachment behavior.
- [x] 1.4 In `packages/cli/src/release-manifest.test.ts`, exercise `write manifest`
serialization so `public`, version and `links.npm` reach the emitted JSON.
- [x] 1.5 In `packages/cli/README.md`, document CLI public manifest metadata and
the distinction between the repository version and separately dispatched npm publication.
- [x] 1.6 Add `.changeset/cli-is-visible-on-the-homepage.md` proposing a minor
`@openspec-ui/cli` bump. Do not edit package versions directly.
Verified 2026-10-10: `npm run lint:changesets` passes; package versions untouched.

## 2. Verification and Rollout

- [x] 2.1 Run the focused `packages/cli/src/release-manifest.test.ts` suite using
the pinned runtime; record counts and command output here.
Passed 2026-10-10: `npm run test --workspace @openspec-ui/cli -- src/release-manifest.test.ts`,
20 tests in 30.49s, Node 22.11.0 and npm 10.9.0, in this worktree.
- [x] 2.2 Run root `npm run typecheck`, `npm run lint` and `npm run test` unpiped
with the pinned runtime; record results and package counts here.
2026-10-10: workspace typecheck and lint pass on Node 22.11.0/npm 10.9.0.
Full test gate was stopped after unchanged `packages/core/src/git-refs.test.ts`
failed with Git Bash `fatal error - add_item ... errno 1` during fetch.
Main core pool: 2234 passed. Separate CLI package run: 218 passed, 1 timeout
in the existing dynamic-import test `prints a manifest built from the repository`
(30s ceiling); a repeat with requested serial execution still timed out.
Focused manifest suite previously passed all 20 tests. Budgets were not changed.
Passed on Linux CI 2026-10-10: Quality run 38082255993, job 114301411234
(`npm run verify` and build), Node 22.11.0/npm 10.9.0. Counts: CLI 219,
core 2234 plus git-subprocess 77, extension 537, server 132, webui 761.
This observed CI result resolves the earlier local environment failures.
- [x] 2.3 Validate this change with `openspec validate cli-is-visible-on-the-homepage --strict`.
- [x] 2.4 Generate `releases.json` using the exact
`write manifest` CI invocation and validate it with the companion homepage's
`app/schemas/manifest.py`; record both commands and evidence for `ci-cli.public`
and `ci-cli.links.npm`. Do not modify the homepage's production snapshot manually.
Partial evidence 2026-10-10: direct worktree CLI entry point generated JSON
that the real homepage scheduled sync persisted and rendered as CLI 0.29.0
with the correct npm button. Exact `npm run ... write manifest` invocation
on Windows failed to resolve package files; the Linux CI invocation remains
outstanding. No registry publish or production snapshot was modified.
Verified 2026-10-10 by GitHub Copilot in VS Code: `npm.cmd run start --silent
--workspace @openspec-ui/cli -- write manifest --cwd <producer-worktree>
--repository VeryComplexAndLongName/OpenSpec-UI --commit 8175843b` generated
`C:/Temp/openspec-linux-releases.json`. Using native npm.cmd fixed forwarded
arguments lost by the PowerShell wrapper. The deployed Homepage revision
2c6089189ee6e75f267f3346092688073c32514f's `ReleaseManifest.model_validate_json`
accepted it and printed `1 ci-cli 0.29.0 True https://www.npmjs.com/package/@openspec-ui/cli`.
Existing live scheduled-sync/browser evidence covers persistence and display.
The delegated verification was completed directly with these executable checks;
no claim is made that a separate copilot-cli agent ran.
- [x] 2.5 Transfer post-merge rollout verification to the separately tracked
`cli-homepage-rollout` change, without claiming deployment has happened.
Deferred to `cli-homepage-rollout` tasks 1.1-1.6, approved by the owner
on 2026-10-10. Production remains unverified until that successor records
deploy/release run ids, manifest commit and the live CLI version/npm button.
10 changes: 10 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ npx @openspec-ui/cli release-manifest --cwd . --repository <owner/name>

See `--help` for the full flag set.

The manifest describes CLI under the stable `ci-cli` id as a public product,
with its own package version, release notes, summary and
`links.npm`: `https://www.npmjs.com/package/@openspec-ui/cli`. The homepage uses
this metadata for its Current versions tile and Current releases card.
Other products do not receive an npm link.

The version is what the repository carries; it does not prove that version is
already on npm. Registry publication is a separate, manually dispatched step.
Manifest schema version remains 1, and the npm link is optional for consumers.

## Exit codes

- `0`: every active change passed strict validation.
Expand Down
35 changes: 32 additions & 3 deletions packages/cli/src/release-manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe("MANIFEST_PRODUCTS — the ids the site already uses", () => {
["standalone-app", "Standalone App", "packages/server", true],
["core", "Core", "packages/core", true],
["shared-ui", "Shared UI", "packages/webui", false],
["ci-cli", "CLI", "packages/cli", false],
["ci-cli", "CLI", "packages/cli", true],
]);
});

Expand Down Expand Up @@ -238,10 +238,30 @@ describe("buildReleaseManifest", () => {

// The site's schema has the flag and applies it; deciding visibility
// here as well would put the decision in two places.
expect(manifest.products.filter((p) => !p.public).map((p) => p.id)).toEqual(["shared-ui", "ci-cli"]);
expect(manifest.products.filter((p) => !p.public).map((p) => p.id)).toEqual(["shared-ui"]);
expect(manifest.products).toHaveLength(5);
});

it("exposes the CLI's version, summary and npm page without links for other products", async () => {
const root = await completeRepo("2.3.4");
const manifest = await buildReleaseManifest({ repoRoot: root, repository: "owner/name" });
const cli = manifest.products.find((product) => product.id === "ci-cli");

expect(cli).toMatchObject({
public: true,
version: "2.3.4",
summary: "Run, validate and check OpenSpec changes from a terminal or CI.",
links: { npm: "https://www.npmjs.com/package/@openspec-ui/cli" },
artifacts: [],
});
expect(manifest.products.filter((product) => product.public).map((product) => product.id))
.toEqual(["vscode-extension", "standalone-app", "core", "ci-cli"]);
for (const product of manifest.products.filter((product) => product.id !== "ci-cli")) {
expect(product.links.npm).toBeUndefined();
}
expect(manifest.schema_version).toBe(1);
});

it("stamps released_at with the moment of generation", async () => {
const root = await completeRepo();
const generatedAt = new Date("2026-09-04T09:00:00.000Z");
Expand Down Expand Up @@ -321,8 +341,17 @@ describe("the release-manifest command", () => {
const { code, out } = await run(["write", "manifest", "--cwd", root, "--repository", "owner/name"]);

expect(code).toBe(0);
const parsed = JSON.parse(out) as { products: { id: string; version: string }[] };
const parsed = JSON.parse(out) as {
schema_version: number;
products: { id: string; version: string; public: boolean; links: { npm?: string } }[];
};
expect(parsed.products.map((p) => p.version)).toEqual(["2.0.0", "2.0.0", "2.0.0", "2.0.0", "2.0.0"]);
expect(parsed.schema_version).toBe(1);
expect(parsed.products.find((product) => product.id === "ci-cli")).toMatchObject({
public: true,
version: "2.0.0",
links: { npm: "https://www.npmjs.com/package/@openspec-ui/cli" },
});
});

it("prints only the fingerprint when asked, and reads one back from a published manifest", async () => {
Expand Down
10 changes: 9 additions & 1 deletion packages/cli/src/release-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface ProductLinks {
docs?: string;
release?: string;
marketplace?: string;
npm?: string;
}

export interface ManifestProduct {
Expand Down Expand Up @@ -108,7 +109,13 @@ export const MANIFEST_PRODUCTS: readonly ProductSpec[] = [
summary: "Execution engine shared by both delivery targets.",
},
{ id: "shared-ui", name: "Shared UI", directory: "packages/webui", public: false },
{ id: "ci-cli", name: "CLI", directory: "packages/cli", public: false },
{
id: "ci-cli",
name: "CLI",
directory: "packages/cli",
public: true,
summary: "Run, validate and check OpenSpec changes from a terminal or CI.",
},
];

// The site's own expressions, transcribed. Changing one of these changes
Expand Down Expand Up @@ -277,6 +284,7 @@ export async function buildReleaseManifest(options: BuildManifestOptions): Promi
docs: `https://github.com/${repository}/blob/${ref}/${spec.directory}/README.md`,
};
if (release?.url) links.release = release.url;
if (spec.id === "ci-cli") links.npm = "https://www.npmjs.com/package/@openspec-ui/cli";

products.push({
id: spec.id,
Expand Down
Loading