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

All notable changes to GraphKeeper are documented here. GraphKeeper follows semantic
versioning; while the package is below 1.0, minor releases may change public behavior.

## [0.1.3] - 2026-08-11

### Added

- Canonical npm repository, homepage, issue-tracker, and discovery metadata.
- README installation guidance, package/CI status badges, and public support and
security-reporting paths.
- Contributor architecture guidance covering command flow, extension points,
platform boundaries, recovery, and release governance.
- Parser-parity and documentation-contract tests that keep the TypeScript readers,
shell validator, and contributor guidance aligned.

### Fixed

- Preserve LF line endings for shell assets packaged from Windows so they remain
executable in supported POSIX shells.
- Canonicalize temporary repository paths in cross-platform tests.
- Run documented contributor onboarding from a clean npm installation in WSL instead
of linking Windows-installed dependencies.
- Serialize package end-to-end tests so concurrent `npm pack` builds cannot rewrite
shared output during verification.

### Changed

- The canonical default branch is `main`, protected by required Linux, macOS, and
Windows/Git Bash quality checks plus isolated performance checks.
- Repository-local planning artifacts and development-only `.codex` state are excluded
from version control and npm packages.
- Solo-maintainer pull requests require passing checks and manual merge but no separate
approval; the policy calls for peer approval when another trusted maintainer gains
write access.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ When linear JSON scans or concurrent-write collisions become material, a future
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the development workflow, extension points,
and boundaries, [`SUPPORT.md`](.github/SUPPORT.md) for usage help, and
[`SECURITY.md`](.github/SECURITY.md) for private vulnerability reporting. Version
`0.1.2` is pre-1.0 and its API may change. Release ownership and the target version
`0.1.3` is pre-1.0 and its API may change. Release ownership and the target version
must be verified immediately before publishing; completing the repository release
gates does not publish anything.

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.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "graphkeeper",
"version": "0.1.2",
"version": "0.1.3",
"description": "Grounded, auditable memory for coding agents.",
"homepage": "https://github.com/anusbutt/Graph_Keeper#readme",
"bugs": {
Expand All @@ -20,13 +20,14 @@
}
},
"bin": {
"graphkeeper": "./dist/src/cli.js"
"graphkeeper": "dist/src/cli.js"
},
"files": [
"dist/src",
"scripts/validate.sh",
"templates",
"examples",
"CHANGELOG.md",
"LICENSE",
"README.md"
],
Expand Down
2 changes: 1 addition & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface CliIO {
readonly stderr: (message: string) => void;
}

const VERSION = '0.1.2';
const VERSION = '0.1.3';
const COMMANDS = new Set(['init', 'check', 'query', 'doctor', 'update']);

const USAGE = [
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/cli-help.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ test('prints the package version successfully', async () => {
const exitCode = await run(['--version'], capture.io);

assert.equal(exitCode, EXIT_SUCCESS);
assert.deepEqual(capture.stdout, ['0.1.2']);
assert.deepEqual(capture.stdout, ['0.1.3']);
assert.equal(capture.stderr.length, 0);
});

Expand Down Expand Up @@ -118,7 +118,7 @@ test('compiled CLI entrypoint runs through an npm-style symlink', {
const result = await runCommand(process.execPath, [linkPath, '--version'], directory);

assert.equal(result.exitCode, EXIT_SUCCESS);
assert.equal(result.stdout, '0.1.2\n');
assert.equal(result.stdout, '0.1.3\n');
assert.equal(result.stderr, '');
} finally {
await rm(directory, { recursive: true, force: true });
Expand Down
4 changes: 4 additions & 0 deletions tests/e2e/contributor-onboarding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ test('a clean source snapshot completes onboarding gates and a query recipe with
GRAPHKEEPER_ONBOARDING_NESTED: '1',
};
delete nestedEnvironment.NODE_TEST_CONTEXT;
for (const name of Object.keys(nestedEnvironment)) {
if (name.toLowerCase() === 'npm_config_dry_run') delete nestedEnvironment[name];
}
nestedEnvironment.npm_config_dry_run = 'false';
const install = npmInvocation(['ci']);
const installed = await runProcess(install.command, install.args, {
cwd: fixture.root,
Expand Down
9 changes: 8 additions & 1 deletion tests/e2e/package-contents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ test('release tarball contains every runtime asset and excludes development-only
}, async (t) => {
const temporary = await mkdtemp(join(tmpdir(), 'graphkeeper-pack-'));
t.after(() => rm(temporary, { recursive: true, force: true }));
const invocation = npmInvocation(['pack', '--json', '--pack-destination', temporary]);
const invocation = npmInvocation([
'pack',
'--dry-run=false',
'--json',
'--pack-destination',
temporary,
]);
const packed = await runProcess(invocation.command, invocation.args, {
cwd: projectRoot,
timeoutMs: 45_000,
Expand All @@ -51,6 +57,7 @@ test('release tarball contains every runtime asset and excludes development-only
'examples/reviewer.md',
'examples/worked-example/graph/claims.json',
'examples/worked-example/evidence/initial-failure.log',
'CHANGELOG.md',
'LICENSE',
'README.md',
]) {
Expand Down
12 changes: 11 additions & 1 deletion tests/e2e/package-install.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@ test('a tarball installs in a clean directory and runs init, check, query, and d
await rm(installationRoot, { recursive: true, force: true });
});

const packInvocation = npmInvocation(['pack', '--json', '--pack-destination', packingRoot]);
const packInvocation = npmInvocation([
'pack',
'--dry-run=false',
'--json',
'--pack-destination',
packingRoot,
]);
const packed = await runProcess(packInvocation.command, packInvocation.args, {
cwd: projectRoot,
timeoutMs: 45_000,
Expand All @@ -66,6 +72,7 @@ test('a tarball installs in a clean directory and runs init, check, query, and d

const installInvocation = npmInvocation([
'install',
'--dry-run=false',
'--ignore-scripts',
'--no-audit',
'--no-fund',
Expand All @@ -91,6 +98,9 @@ test('a tarball installs in a clean directory and runs init, check, query, and d
const help = await runCli(['--help']);
assert.equal(help.exitCode, 0, help.stderr);
assert.match(help.stdout, /graphkeeper update/);
const version = await runCli(['--version']);
assert.equal(version.exitCode, 0, version.stderr);
assert.equal(version.stdout, '0.1.3\n');
const initialized = await runCli(['init']);
assert.equal(initialized.exitCode, 0, initialized.stderr);
assert.match(initialized.stdout, /CREATE graph\/entities\.json/);
Expand Down
23 changes: 23 additions & 0 deletions tests/integration/release-docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ test('npm metadata points to the canonical public repository and support channel
homepage?: string;
bugs?: { url?: string };
repository?: { type?: string; url?: string };
bin?: Record<string, string>;
keywords?: string[];
};

Expand All @@ -46,11 +47,33 @@ test('npm metadata points to the canonical public repository and support channel
type: 'git',
url: 'git+https://github.com/anusbutt/Graph_Keeper.git',
});
assert.deepEqual(manifest.bin, { graphkeeper: 'dist/src/cli.js' });
for (const keyword of ['ai-agents', 'coding-agents', 'knowledge-graph', 'provenance']) {
assert.ok(manifest.keywords?.includes(keyword), `missing npm keyword: ${keyword}`);
}
});

test('release version stays aligned across package, lockfile, CLI, README, and changelog', async () => {
const manifest = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf8')) as {
version?: string;
};
const lockfile = JSON.parse(await readFile(join(projectRoot, 'package-lock.json'), 'utf8')) as {
version?: string;
packages?: Record<string, { version?: string }>;
};
const cli = await readFile(join(projectRoot, 'src/cli.ts'), 'utf8');
const readme = await readFile(join(projectRoot, 'README.md'), 'utf8');
const changelog = await readFile(join(projectRoot, 'CHANGELOG.md'), 'utf8');
const version = manifest.version;

assert.equal(version, '0.1.3');
assert.equal(lockfile.version, version);
assert.equal(lockfile.packages?.['']?.version, version);
assert.match(cli, new RegExp("const VERSION = '" + version?.replaceAll('.', '\\.') + "';"));
assert.match(readme, new RegExp('Version\\s+`' + version?.replaceAll('.', '\\.') + '`'));
assert.match(changelog, new RegExp('## \\[' + version?.replaceAll('.', '\\.') + '\\] - 2026-08-11'));
});

test('release carries the MIT terms for GraphKeeper contributors', async () => {
const license = await readFile(join(projectRoot, 'LICENSE'), 'utf8');
assert.match(license, /^MIT License/);
Expand Down
Loading