* chore: rename npm package + bin to @opengsd/gsd-core (functional) - package.json: name @opengsd/get-shit-done-redux → @opengsd/gsd-core, bin key get-shit-done-redux → gsd-core, repository/homepage/bugs URLs - package-lock.json: regenerated (npm install --package-lock-only) - tests/**, scripts/**, bin/**, .github/**, agents/**, commands/**, get-shit-done/bin/**, get-shit-done/workflows/**: applied the 4-rule replacement (scoped npm ref, GitHub repo path, bin/clone invocations) per #505 single-source refactor Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: sweep live references to @opengsd/gsd-core Update all live documentation (README.md + translations, docs/**, CONTRIBUTING.md, VERSIONING.md, SECURITY.md, CONTEXT.md, docs/CANARY.md) to reflect the renamed package and repository. Rules applied: - @opengsd/get-shit-done-redux → @opengsd/gsd-core (scoped npm name) - open-gsd/get-shit-done-redux → open-gsd/gsd-core (GitHub repo) - GSD-redux/get-shit-done-redux → open-gsd/gsd-core (stale badge org) - bare bin/clone refs → gsd-core CHANGELOG.md, docs/adr/**, docs/RELEASE-*.md, docs/research/**, and .changeset/** are preserved byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: add negative lookbehind to slash-command regex in bug-2954 test The extractSlashReferences regex matched /gsd-core inside npm package URLs (@opengsd/gsd-core), producing a false /gsd:core command reference. Adding a negative lookbehind (?<![a-z]) excludes matches preceded by a letter, so only standalone /gsd-<cmd> and /gsd:<cmd> tokens are found. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#518): add changeset for package rename Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#518): update package-identity expectations to the renamed coordinates The rebase regenerated the seam to @opengsd/gsd-core (bin gsd-core, repo open-gsd/gsd-core). The #498 seam tests assert deriveIdentity against the REAL package.json, so their expected literals must follow the rename. The drift-lint unit test is left as-is — its SEAM is a self-consistent fixture and its stale-literal detection cases would shift if altered; the live-repo scan in it already passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
114 lines
4.7 KiB
JavaScript
114 lines
4.7 KiB
JavaScript
'use strict';
|
|
process.env.GSD_TEST_MODE = '1';
|
|
|
|
// Issue #498: single Package Identity seam.
|
|
// The package coordinates (npm name, bin name, repo slug, changelog URL) are
|
|
// DERIVED from package.json, not re-typed. deriveIdentity is the pure core;
|
|
// the generated runtime module get-shit-done/bin/lib/package-identity.cjs
|
|
// bakes those values at build time so it survives the install layout where
|
|
// the only package.json present is the synthetic {"type":"commonjs"} marker.
|
|
|
|
const { test, describe } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const path = require('node:path');
|
|
|
|
const fs = require('node:fs');
|
|
|
|
const ROOT = path.join(__dirname, '..');
|
|
const { deriveIdentity, formatManualInstall, render } = require(
|
|
path.join(ROOT, 'scripts', 'generate-package-identity.cjs'),
|
|
);
|
|
const GENERATED = path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'package-identity.cjs');
|
|
|
|
describe('Issue #498: deriveIdentity (pure, package.json -> coordinates)', () => {
|
|
const FAKE_PKG = {
|
|
name: '@scope/example-pkg',
|
|
bin: { 'example-pkg': 'bin/install.js', 'extra-tool': 'x.cjs' },
|
|
repository: { type: 'git', url: 'git+https://github.com/acme/example-pkg.git' },
|
|
};
|
|
|
|
test('packageName is package.json .name', () => {
|
|
assert.equal(deriveIdentity(FAKE_PKG).packageName, '@scope/example-pkg');
|
|
});
|
|
|
|
test('binName is the FIRST bin key (primary launcher)', () => {
|
|
assert.equal(deriveIdentity(FAKE_PKG).binName, 'example-pkg');
|
|
});
|
|
|
|
test('repoSlug is owner/name parsed from repository.url (git+ and .git stripped)', () => {
|
|
assert.equal(deriveIdentity(FAKE_PKG).repoSlug, 'acme/example-pkg');
|
|
});
|
|
|
|
test('repoUrl is the cleaned https github url', () => {
|
|
assert.equal(deriveIdentity(FAKE_PKG).repoUrl, 'https://github.com/acme/example-pkg');
|
|
});
|
|
|
|
test('changelogRawUrl points at raw.githubusercontent main CHANGELOG', () => {
|
|
assert.equal(
|
|
deriveIdentity(FAKE_PKG).changelogRawUrl,
|
|
'https://raw.githubusercontent.com/acme/example-pkg/main/CHANGELOG.md',
|
|
);
|
|
});
|
|
|
|
test('derives the real GSD coordinates from the repo package.json', () => {
|
|
const real = require(path.join(ROOT, 'package.json'));
|
|
const id = deriveIdentity(real);
|
|
assert.equal(id.packageName, '@opengsd/gsd-core');
|
|
assert.equal(id.binName, 'gsd-core');
|
|
assert.equal(id.repoSlug, 'open-gsd/gsd-core');
|
|
});
|
|
});
|
|
|
|
describe('Issue #498: formatManualInstall (the npx fallback command)', () => {
|
|
test('global scope, no runtime -> npx with --global only', () => {
|
|
assert.equal(
|
|
formatManualInstall({ packageName: '@scope/example-pkg', binName: 'example-pkg', scope: 'global' }),
|
|
'npx -y --package=@scope/example-pkg@latest -- example-pkg --global',
|
|
);
|
|
});
|
|
|
|
test('local scope with runtime -> --<runtime> before --<scope>', () => {
|
|
assert.equal(
|
|
formatManualInstall({ packageName: '@scope/example-pkg', binName: 'example-pkg', scope: 'local', runtime: 'claude' }),
|
|
'npx -y --package=@scope/example-pkg@latest -- example-pkg --claude --local',
|
|
);
|
|
});
|
|
|
|
test('matches the literal update.md uses for the real package (global+claude)', () => {
|
|
const id = deriveIdentity(require(path.join(ROOT, 'package.json')));
|
|
assert.equal(
|
|
formatManualInstall({ packageName: id.packageName, binName: id.binName, scope: 'global', runtime: 'claude' }),
|
|
'npx -y --package=@opengsd/gsd-core@latest -- gsd-core --claude --global',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Issue #498: generated runtime module (baked, drift-checked)', () => {
|
|
test('the committed generated file is in sync with package.json (no drift)', () => {
|
|
// Normalize line endings: on Windows the file is checked out with CRLF
|
|
// (no .gitattributes eol rule), while render() emits LF. The repo's
|
|
// convention is to compare normalized content (see autonomous-decomposition,
|
|
// bug-3707). The sync check is about content, not the checkout's eol.
|
|
const norm = (s) => s.replace(/\r\n/g, '\n');
|
|
const expected = render(deriveIdentity(require(path.join(ROOT, 'package.json'))));
|
|
const actual = fs.readFileSync(GENERATED, 'utf8');
|
|
assert.equal(norm(actual), norm(expected),
|
|
'package-identity.cjs is stale — run `node scripts/generate-package-identity.cjs`');
|
|
});
|
|
|
|
test('requiring the generated module exposes the real coordinates', () => {
|
|
const id = require(GENERATED);
|
|
assert.equal(id.packageName, '@opengsd/gsd-core');
|
|
assert.equal(id.binName, 'gsd-core');
|
|
assert.equal(id.repoSlug, 'open-gsd/gsd-core');
|
|
});
|
|
|
|
test('generated manualInstallCommand closes over the baked coordinates', () => {
|
|
const id = require(GENERATED);
|
|
assert.equal(
|
|
id.manualInstallCommand({ scope: 'global', runtime: 'claude' }),
|
|
'npx -y --package=@opengsd/gsd-core@latest -- gsd-core --claude --global',
|
|
);
|
|
});
|
|
});
|