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
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Changelog

## 0.1.1 — 2026-09-04

This patch release strengthens the existing Noxroot workflow without adding a new command or
expanding its product boundary.

### Fixed

- Bind verification, independent review, and learning to the complete current repository change.
- Refuse completion when changed paths lack an approved check or when the repository changes while
checks or review are running.
- Bind reviewer responses to a task and change ID; reject stale, mismatched, linked, tracked, or
oversized external review evidence.
- Preserve mixed positive and negative task constraints instead of dropping requested outcomes.
- Improve context selection for SvelteKit and native C implementations while keeping selection
bounded and explainable.
- Distinguish real package-manager or instruction conflicts from unrelated mentions and thin
forwarding files.
- Keep timeout failures concise but actionable with the command, working directory, limit, and
bounded final output.
- Allow dedicated local review evidence beside legacy task records while still refusing two actual
task-state stores.

### Validated

- Reusable learning is admitted only from an approved, unchanged diff and is selected for related
future tasks without being duplicated or injected into unrelated work.
- Existing documentation, Agent Skills, verification wrappers, Director-style ledgers, and
repository coordinators are reused, treated as adjacent, or reported as conflicts according to
their actual responsibility.
- Package installation and lifecycle tests run across Windows, macOS, Linux, and Node.js 22, 24, and
26 in CI.

`0.1.0` remains the first public npm release. No migration, background service, telemetry, or new
agent framework is introduced by `0.1.1`.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ Not assessed
No files changed. No project commands or agents ran. No network requests were made.

Next
npx --yes noxroot@0.1.0 preview --diff
npx --yes noxroot@0.1.1 preview --diff
```

</details>
Expand Down Expand Up @@ -215,7 +215,8 @@ and diagnostics on standard error.

Read [Getting started](docs/getting-started.md), the [command reference](docs/commands.md),
[configuration](docs/configuration.md), [architecture](docs/architecture.md),
[adapter protocol](docs/adapters.md), and [security boundaries](docs/security.md).
[adapter protocol](docs/adapters.md), [security boundaries](docs/security.md), and the
[changelog](CHANGELOG.md).

Noxroot is an experimental v0.1 MVP. Apache-2.0; see [CONTRIBUTING.md](CONTRIBUTING.md),
[SECURITY.md](SECURITY.md), and [LICENSE](LICENSE).
2 changes: 1 addition & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ From your repository directory, run `npx noxroot@latest preview` to inspect setu
files, then `npx noxroot@latest init` when ready. Requires Node.js `>=22.12 <27` and npm.

Commands below use `noxroot` as shorthand. Without a global installation, use
`npx --yes noxroot@0.1.0` in its place, or the version pinned in your repository instructions.
`npx --yes noxroot@0.1.1` in its place, or the version pinned in your repository instructions.
Compatible agents handle `start` and `finish`; you do not need to type them for each conversation.

## Global behavior
Expand Down
16 changes: 15 additions & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,24 @@ adapter, add a realistic fixture and failure-path coverage.
When working inside the Noxroot source checkout, use `node dist/cli.js` after building. `npx` can
resolve this checkout's package instead of the registry package, without an installed command shim.

`noxroot@0.1.0` is published on npm. Publication is not part of ordinary development. Future
Published versions are available on npm. Publication is not part of ordinary development. Future
automated releases require the owner to configure npm trusted publishing for the exact GitHub
repository and workflow, and authorize a publish workflow with `id-token: write` on a GitHub-hosted
runner. That workflow is not configured yet. Do not create or store a long-lived npm publication
token. Trusted publishing supplies provenance for eligible public packages; the first manual release
does not have that provenance. npm's displayed README updates only when a new package version is
published.

## Release checklist

1. Choose the smallest valid semver increment. An npm version cannot be replaced after publication.
2. Update package metadata, the runtime version, version-bound tests, and `CHANGELOG.md` together.
3. Run `npm ci`, `npm run check`, and `npm run package:check` from a clean release branch.
4. Inspect the dry-run file list, package size, executable entrypoint, documentation, and dependency
set. The packed-install smoke must pass from the produced tarball.
5. Push the candidate and require the complete GitHub matrix before merging.
6. Publish only with explicit owner approval. Then verify the registry version, `latest` tag,
package integrity, README, and a clean `npx noxroot@<version> --version` invocation.

If publication succeeds but post-publish verification fails, fix forward with another patch version;
never attempt to replace the published artifact.
6 changes: 3 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ for ordinary questions. Local task state is not chat restoration or cross-machin

## If something looks wrong

Use the pinned version from your repository instructions. For the first release:
Use the pinned version from your repository instructions. For the current release:

```bash
npx --yes noxroot@0.1.0 doctor
npx --yes noxroot@0.1.0 status
npx --yes noxroot@0.1.1 doctor
npx --yes noxroot@0.1.1 status
```

`doctor` checks configuration; it does not prove your agent follows instructions. `status` shows
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "noxroot",
"version": "0.1.0",
"version": "0.1.1",
"description": "Noxroot gives coding agents relevant repository context, checks each change, and proposes validated lessons as reusable project documentation.",
"type": "module",
"bin": {
Expand All @@ -13,6 +13,7 @@
"dist",
"docs",
"README.md",
"CHANGELOG.md",
"CONTRIBUTING.md",
"SECURITY.md",
"LICENSE"
Expand Down
2 changes: 1 addition & 1 deletion src/invocation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const VERSION = "0.1.0";
export const VERSION = "0.1.1";

export const CLI_INVOCATION = `npx --yes noxroot@${VERSION}`;

Expand Down
5 changes: 3 additions & 2 deletions tests/adoption.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { previewRepository } from "../src/core/preview.js";
import { inspectRepositoryAdoption } from "../src/detection/adoption.js";
import { scanRepository } from "../src/detection/scan.js";
import { assessModules, buildProposals } from "../src/core/proposals.js";
import { VERSION } from "../src/invocation.js";
import { planVerification } from "../src/verification/index.js";
import { fixtureCopy, hashTree, temporaryDirectory } from "./helpers.js";

Expand Down Expand Up @@ -222,8 +223,8 @@ describe("mature repository adoption", () => {
expect(config.modules).not.toContain("learning");
const instructions = await readFile(path.join(repository, "AGENTS.md"), "utf8");
expect(instructions).toContain("existing repository coordinator remains authoritative");
expect(instructions).toContain('npx --yes noxroot@0.1.0 context "<task>"');
expect(instructions).not.toContain("noxroot@0.1.0 start");
expect(instructions).toContain(`npx --yes noxroot@${VERSION} context "<task>"`);
expect(instructions).not.toContain(`noxroot@${VERSION} start`);
expect(await hashTree(repository)).not.toBe(before);
});

Expand Down
9 changes: 5 additions & 4 deletions tests/autonomy-guided.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { runProcess } from "../src/adapters/process.js";
import { temporaryDirectory } from "./helpers.js";
import { createProgram } from "../src/cli.js";
import { renderGuidedFinish, renderVerification } from "../src/output.js";
import { VERSION } from "../src/invocation.js";

const cleanup: string[] = [];
afterEach(async () => {
Expand Down Expand Up @@ -340,13 +341,13 @@ agents: {default: manual, adapters: {manual: {type: manual}}}
current: false,
});
expect(second.continuation.nextAction).toBe(
"Run npx --yes noxroot@0.1.0 finish when the change is ready to check.",
`Run npx --yes noxroot@${VERSION} finish when the change is ready to check.`,
);
const brief = await cli(["start", "change the value safely", "--root", root]);
expect(brief.stdout).toContain("Changed: 1 file since baseline (src/value.ts)");
expect(brief.stdout).toContain("Verification: Not run for the current diff.");
expect(brief.stdout).toContain(
"Next: Run npx --yes noxroot@0.1.0 finish when the change is ready to check.",
`Next: Run npx --yes noxroot@${VERSION} finish when the change is ready to check.`,
);
const records = await (
await import("node:fs/promises")
Expand Down Expand Up @@ -471,7 +472,7 @@ commands:
};
expect(stale.continuation.verification).toMatchObject({ status: "stale", current: false });
expect(stale.continuation.nextAction).toBe(
"Run npx --yes noxroot@0.1.0 finish when the change is ready to check.",
`Run npx --yes noxroot@${VERSION} finish when the change is ready to check.`,
);
});

Expand Down Expand Up @@ -978,7 +979,7 @@ commands:
"definitely-not-installed-noxroot-check --verify · cwd . · unavailable",
);
expect(result.stdout).toContain("Make the approved check runnable");
expect(result.stdout).toContain("rerun npx --yes noxroot@0.1.0 finish.");
expect(result.stdout).toContain(`rerun npx --yes noxroot@${VERSION} finish.`);
expect(result.stderr).toContain("Inspecting changed files and running affected checks");
expect(result.stderr).toContain("Assessing reusable learning");
expect(result.stderr).toContain("Preparing handoff");
Expand Down
13 changes: 7 additions & 6 deletions tests/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { CommanderError } from "commander";
import { createProgram } from "../src/cli.js";
import { VERSION } from "../src/invocation.js";
import { writeRunRecord } from "../src/state/local.js";
import { fixtureCopy, hashTree, temporaryDirectory } from "./helpers.js";

Expand Down Expand Up @@ -38,7 +39,7 @@ describe("CLI contracts", () => {
const interactive = await run(["--no-color"], { isTTY: true });
expect(interactive.stdout).toContain("█▄ █ █▀█ ▀▄▀ █▀█ █▀█ █▀█ ▀█▀");
expect(interactive.stdout).toContain("█ ▀█ █▄█ █ █ █▀▄ █▄█ █▄█ █");
expect(interactive.stdout).toContain("◆ 0.1.0");
expect(interactive.stdout).toContain(`◆ ${VERSION}`);
expect(interactive.stdout).toContain("Project memory and verification for coding agents.");
expect(interactive.stdout).toContain(
"A CLI for task context, project checks, and reusable documentation.",
Expand All @@ -50,7 +51,7 @@ describe("CLI contracts", () => {
expect(piped.stdout).not.toContain("◆");

const narrow = await run(["--no-color"], { isTTY: true, columns: 44 });
expect(narrow.stdout).toContain("NOXROOT ◆ 0.1.0");
expect(narrow.stdout).toContain(`NOXROOT ◆ ${VERSION}`);
expect(narrow.stdout).not.toContain("█▄ █");
});

Expand Down Expand Up @@ -150,7 +151,7 @@ describe("CLI contracts", () => {
expect(concise.stdout).toContain(
"No files changed. No project commands or agents ran. No network requests were made.",
);
expect(concise.stdout).toContain("Next\n npx --yes noxroot@0.1.0 preview --diff");
expect(concise.stdout).toContain(`Next\n npx --yes noxroot@${VERSION} preview --diff`);
expect(concise.stdout).not.toContain("Applicable modules");
expect(concise.stdout).not.toContain("Files\n create AGENTS.md");
expect(concise.stdout).not.toContain("--- /dev/null");
Expand All @@ -163,7 +164,7 @@ describe("CLI contracts", () => {
const exact = await run(["preview", "--diff", "--root", fixture.root]);
expect(exact.stdout).toContain("Exact proposed changes");
expect(exact.stdout).toContain("--- /dev/null");
expect(exact.stdout).toContain("Next\n npx --yes noxroot@0.1.0 init");
expect(exact.stdout).toContain(`Next\n npx --yes noxroot@${VERSION} init`);
});

it("shows the repository pin and running CLI before a read-only sync proposal", async () => {
Expand All @@ -182,7 +183,7 @@ describe("CLI contracts", () => {

expect(result.stdout).toContain("NOXROOT sync");
expect(result.stdout).toContain("Repository pin 0.0.9");
expect(result.stdout).toContain("Running CLI 0.1.0");
expect(result.stdout).toContain(`Running CLI ${VERSION}`);
expect(result.stdout).toMatch(/Managed changes [1-9]/);
expect(result.stdout).toContain("Exact proposed changes");

Expand Down Expand Up @@ -222,7 +223,7 @@ describe("CLI contracts", () => {
expect(stdout).toContain("Scope\n Entire repository");
expect(stdout).toContain("Planned");
expect(stdout).toContain("npm run typecheck · cwd .");
expect(stdout).toContain("Next\n npx --yes noxroot@0.1.0 verify");
expect(stdout).toContain(`Next\n npx --yes noxroot@${VERSION} verify`);
expect(stdout).not.toContain("NOXROOT VERIFY PLAN");
});

Expand Down
5 changes: 3 additions & 2 deletions tests/documentation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { renderPreview } from "../src/output.js";
import { fixtures } from "./helpers.js";
import { parse } from "yaml";
import { noxrootConfigSchema, verificationConfigSchema } from "../src/config/schema.js";
import { VERSION } from "../src/invocation.js";

describe("documentation examples", () => {
it("keeps the README opening and preview excerpt synchronized with a real fixture", async () => {
Expand All @@ -30,7 +31,7 @@ describe("documentation examples", () => {
"Project knowledge",
"Product and UX guidance",
"No files changed. No project commands or agents ran. No network requests were made.",
"npx --yes noxroot@0.1.0 preview --diff",
`npx --yes noxroot@${VERSION} preview --diff`,
]) {
expect(output).toContain(line);
expect(readme).toContain(line);
Expand Down Expand Up @@ -80,7 +81,7 @@ describe("documentation examples", () => {
}
}
const commands = await readFile(path.resolve("docs/commands.md"), "utf8");
expect(commands).toContain("npx --yes noxroot@0.1.0");
expect(commands).toContain(`npx --yes noxroot@${VERSION}`);
expect(commands).toContain("`Relevant files`, `Related tests`, and `Checks to run`");
const security = await readFile(path.resolve("docs/security.md"), "utf8");
expect(security).toContain("the full `npx` invocation is not guaranteed offline");
Expand Down
15 changes: 9 additions & 6 deletions tests/init-context-doctor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { doctorRepository } from "../src/core/doctor.js";
import { applyProposals } from "../src/core/init.js";
import { previewRepository } from "../src/core/preview.js";
import { buildProposals } from "../src/core/proposals.js";
import { VERSION } from "../src/invocation.js";
import { scanRepository } from "../src/detection/scan.js";
import { fixtureCopy, temporaryDirectory } from "./helpers.js";

Expand Down Expand Up @@ -107,8 +108,10 @@ describe("initialization, sync safety, context, and doctor", () => {
const agents = await readFile(path.join(fixture.root, "AGENTS.md"), "utf8");
expect(agents.startsWith(original)).toBe(true);
expect(agents).toContain("<!-- noxroot:start -->");
expect(agents).toContain('run `npx --yes noxroot@0.1.0 start "<task>"` before editing');
expect(agents).toContain("`npx --yes noxroot@0.1.0 finish` when the change is ready to check");
expect(agents).toContain(`run \`npx --yes noxroot@${VERSION} start "<task>"\` before editing`);
expect(agents).toContain(
`\`npx --yes noxroot@${VERSION} finish\` when the change is ready to check`,
);
expect(agents).toContain("Do not start a task for questions, explanations, reviews");
expect(agents).toContain("If start fails, stop before editing");
expect(agents).toContain("If finish fails, do not report the task complete");
Expand Down Expand Up @@ -285,8 +288,8 @@ describe("initialization, sync safety, context, and doctor", () => {

expect(agents).toMatchObject({ action: "patch" });
expect(agents?.content).toContain("<!-- noxroot:start -->");
expect(agents?.content).toContain('noxroot@0.1.0 start "<task>"');
expect(agents?.content).toContain("noxroot@0.1.0 finish");
expect(agents?.content).toContain(`noxroot@${VERSION} start "<task>"`);
expect(agents?.content).toContain(`noxroot@${VERSION} finish`);
});

it("preserves custom instructions that already provide an equivalent lifecycle", async () => {
Expand All @@ -298,8 +301,8 @@ describe("initialization, sync safety, context, and doctor", () => {
path.join(root, "AGENTS.md"),
[
"Read [.noxroot/knowledge/INDEX.md](.noxroot/knowledge/INDEX.md).",
'Before edits run `npx --yes noxroot@0.1.0 start "<task>"`.',
"Afterward run `npx --yes noxroot@0.1.0 finish`.",
`Before edits run \`npx --yes noxroot@${VERSION} start "<task>"\`.`,
`Afterward run \`npx --yes noxroot@${VERSION} finish\`.`,
"",
].join("\n"),
);
Expand Down
Loading