From f085728f8a5ca65fc76a37588d37a5a4c8507590 Mon Sep 17 00:00:00 2001 From: liolevx <312117550+liolevx@users.noreply.github.com> Date: Fri, 4 Sep 2026 16:12:38 -0400 Subject: [PATCH 1/2] chore: prepare 0.1.1 package contracts --- package-lock.json | 4 ++-- package.json | 3 ++- src/invocation.ts | 2 +- tests/adoption.test.ts | 5 +++-- tests/autonomy-guided.test.ts | 9 +++++---- tests/cli.test.ts | 13 +++++++------ tests/documentation.test.ts | 5 +++-- tests/init-context-doctor.test.ts | 15 +++++++++------ tests/package-smoke.mjs | 19 +++++++++++++------ 9 files changed, 45 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56634ef..00f9eea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "noxroot", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "noxroot", - "version": "0.1.0", + "version": "0.1.1", "license": "Apache-2.0", "dependencies": { "commander": "^15.0.0", diff --git a/package.json b/package.json index 2f824f2..9379b60 100644 --- a/package.json +++ b/package.json @@ -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": { @@ -13,6 +13,7 @@ "dist", "docs", "README.md", + "CHANGELOG.md", "CONTRIBUTING.md", "SECURITY.md", "LICENSE" diff --git a/src/invocation.ts b/src/invocation.ts index 7fbf53b..90653f3 100644 --- a/src/invocation.ts +++ b/src/invocation.ts @@ -1,4 +1,4 @@ -export const VERSION = "0.1.0"; +export const VERSION = "0.1.1"; export const CLI_INVOCATION = `npx --yes noxroot@${VERSION}`; diff --git a/tests/adoption.test.ts b/tests/adoption.test.ts index d50e62c..78190c8 100644 --- a/tests/adoption.test.ts +++ b/tests/adoption.test.ts @@ -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"; @@ -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 ""'); - expect(instructions).not.toContain("noxroot@0.1.0 start"); + expect(instructions).toContain(`npx --yes noxroot@${VERSION} context ""`); + expect(instructions).not.toContain(`noxroot@${VERSION} start`); expect(await hashTree(repository)).not.toBe(before); }); diff --git a/tests/autonomy-guided.test.ts b/tests/autonomy-guided.test.ts index dbf5531..bb31e96 100644 --- a/tests/autonomy-guided.test.ts +++ b/tests/autonomy-guided.test.ts @@ -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 () => { @@ -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") @@ -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.`, ); }); @@ -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"); diff --git a/tests/cli.test.ts b/tests/cli.test.ts index e052990..5a94af4 100644 --- a/tests/cli.test.ts +++ b/tests/cli.test.ts @@ -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"; @@ -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.", @@ -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("█▄ █"); }); @@ -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"); @@ -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 () => { @@ -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"); @@ -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"); }); diff --git a/tests/documentation.test.ts b/tests/documentation.test.ts index 9ff7cc7..f35aa4b 100644 --- a/tests/documentation.test.ts +++ b/tests/documentation.test.ts @@ -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 () => { @@ -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); @@ -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"); diff --git a/tests/init-context-doctor.test.ts b/tests/init-context-doctor.test.ts index a97fce4..310506e 100644 --- a/tests/init-context-doctor.test.ts +++ b/tests/init-context-doctor.test.ts @@ -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"; @@ -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(""); - expect(agents).toContain('run `npx --yes noxroot@0.1.0 start ""` 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 ""\` 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"); @@ -285,8 +288,8 @@ describe("initialization, sync safety, context, and doctor", () => { expect(agents).toMatchObject({ action: "patch" }); expect(agents?.content).toContain(""); - expect(agents?.content).toContain('noxroot@0.1.0 start ""'); - expect(agents?.content).toContain("noxroot@0.1.0 finish"); + expect(agents?.content).toContain(`noxroot@${VERSION} start ""`); + expect(agents?.content).toContain(`noxroot@${VERSION} finish`); }); it("preserves custom instructions that already provide an equivalent lifecycle", async () => { @@ -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 ""`.', - "Afterward run `npx --yes noxroot@0.1.0 finish`.", + `Before edits run \`npx --yes noxroot@${VERSION} start ""\`.`, + `Afterward run \`npx --yes noxroot@${VERSION} finish\`.`, "", ].join("\n"), ); diff --git a/tests/package-smoke.mjs b/tests/package-smoke.mjs index f2d5be8..a04fc4b 100644 --- a/tests/package-smoke.mjs +++ b/tests/package-smoke.mjs @@ -18,6 +18,9 @@ const repositoryRoot = path.resolve(import.meta.dirname, ".."); const fixtureRoot = path.join(repositoryRoot, "tests", "fixtures", "typescript"); const temporaryRoot = await mkdtemp(path.join(tmpdir(), "noxroot-package-smoke-")); const npmCache = path.join(temporaryRoot, "npm-cache"); +const packageVersion = JSON.parse( + await readFile(path.join(repositoryRoot, "package.json"), "utf8"), +).version; async function snapshot(root) { const files = {}; @@ -124,6 +127,7 @@ try { const installedPackage = path.join(installRoot, "node_modules", "noxroot"); for (const requiredFile of [ "README.md", + "CHANGELOG.md", "docs/commands.md", "docs/configuration.md", "docs/architecture.md", @@ -146,7 +150,7 @@ try { const binary = installedBinary(installRoot); const version = invokeBinary(binary, ["--version"], installRoot).trim(); - if (version !== "0.1.0") throw new Error(`Unexpected installed CLI version: ${version}`); + if (version !== packageVersion) throw new Error(`Unexpected installed CLI version: ${version}`); const preview = JSON.parse( invokeBinary(binary, ["preview", "--root", fixtureRoot, "--json"], installRoot), ); @@ -161,10 +165,10 @@ try { ); invokeBinary(binary, ["init", "--yes", "--root", initializedRoot], installRoot); const generatedInstructions = await readFile(path.join(initializedRoot, "AGENTS.md"), "utf8"); - if (!generatedInstructions.includes('npx --yes noxroot@0.1.0 start ""')) { + if (!generatedInstructions.includes(`npx --yes noxroot@${packageVersion} start ""`)) { throw new Error("Packed CLI initialization did not pin its executable lifecycle command."); } - if (!generatedInstructions.includes("npx --yes noxroot@0.1.0 finish")) { + if (!generatedInstructions.includes(`npx --yes noxroot@${packageVersion} finish`)) { throw new Error("Packed CLI initialization did not pin its finish command."); } const initialized = await snapshot(initializedRoot); @@ -176,7 +180,10 @@ try { const userPrefix = "# Repository instructions\n\nKeep changes focused.\n\n"; const userSuffix = "\n## User-owned notes\n\nUse existing documentation.\n"; const currentInstructions = userPrefix + generatedInstructions + userSuffix; - await writeFile(agentsPath, currentInstructions.replaceAll("noxroot@0.1.0", "noxroot@0.0.9")); + await writeFile( + agentsPath, + currentInstructions.replaceAll(`noxroot@${packageVersion}`, "noxroot@0.0.9"), + ); await writeFile(path.join(initializedRoot, "user-notes.md"), "Preserve this document.\n"); const beforeSync = await snapshot(initializedRoot); const dryRun = JSON.parse( @@ -188,7 +195,7 @@ try { ); assert.deepEqual(dryRun.summary, { repositoryVersion: "0.0.9", - runningVersion: "0.1.0", + runningVersion: packageVersion, managedChanges: 1, }); const changes = dryRun.preview.proposedFiles.filter((file) => file.action !== "reference"); @@ -196,7 +203,7 @@ try { assert.equal(changes[0].path, "AGENTS.md"); assert.equal(changes[0].action, "patch"); assert.ok(changes[0].patch.includes("noxroot@0.0.9")); - assert.ok(changes[0].patch.includes("noxroot@0.1.0")); + assert.ok(changes[0].patch.includes(`noxroot@${packageVersion}`)); assert.deepEqual(await snapshot(initializedRoot), beforeSync, "Sync preview must not write"); assert.throws( () => invokeBinary(binary, ["sync", "--json", "--root", initializedRoot], installRoot), From c2823e795135034535a70d7a63be4a4ab36faeb7 Mon Sep 17 00:00:00 2001 From: liolevx <312117550+liolevx@users.noreply.github.com> Date: Fri, 4 Sep 2026 16:12:49 -0400 Subject: [PATCH 2/2] docs: publish 0.1.1 release notes --- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++++++ README.md | 5 +++-- docs/commands.md | 2 +- docs/development.md | 16 +++++++++++++++- docs/getting-started.md | 6 +++--- 5 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0eaab1a --- /dev/null +++ b/CHANGELOG.md @@ -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`. diff --git a/README.md b/README.md index 36a24f0..ccfa5da 100644 --- a/README.md +++ b/README.md @@ -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 ``` @@ -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). diff --git a/docs/commands.md b/docs/commands.md index cbb7de0..d4c94af 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -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 diff --git a/docs/development.md b/docs/development.md index 063bcf5..89e9153 100644 --- a/docs/development.md +++ b/docs/development.md @@ -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` invocation. + +If publication succeeds but post-publish verification fails, fix forward with another patch version; +never attempt to replace the published artifact. diff --git a/docs/getting-started.md b/docs/getting-started.md index 9ee4bbb..ab81a0b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -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