* refactor(#1294): T-final — delete the core.cjs re-export spine (epic #1267 complete) After T0–T6 nothing imports core, so retire the spine and its scaffolding: - delete src/core.cts (and the gitignored gsd-core/bin/lib/core.cjs artifact; remove its .gitignore + eslint-ignore entries) - delete scripts/lint-core-spine-imports.cjs + its allowlist; drop it from the package.json lint:ci chain - regenerate docs/INVENTORY-MANIFEST.json (drops the core.cjs surface) - sweep stale references: CONTEXT.md glossary back-compat clauses (spine retired, callers import the leaf directly), planning-config.md CONFIG_DEFAULTS owner, and false present-tense core.cjs claims in leaf-module docstrings The ADR-857 decomposition is complete: the former Core god-module is fully dissolved into its leaf modules; no re-export spine remains. No behaviour change. Closes #1294 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#1294): migrate the computed-path core.cjs importers the literal grep missed bin/install.js used require(path.join(_gsdLibDir, 'core.cjs')) (a computed path, and bin/install.js was never in the convergence lint's scan roots), and ~8 test files referenced core.cjs via path.join/readFileSync/existsSync/FILE_ARG forms the literal-string migration grep missed. Route install.js's symbols to their leaves (RUNTIME_PROFILE_MAP->model-catalog, resolveTierEntry/EFFORT_SET-> model-resolver) and repoint/adjust the test references to the leaves. Recovers the 161 'Cannot find module core.cjs' failures from the spine deletion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
83 lines
3.3 KiB
JavaScript
83 lines
3.3 KiB
JavaScript
/**
|
|
* Bug #2660: `gsd-tools milestone complete <version>` writes MILESTONES.md
|
|
* bullets that read "- One-liner:" (the literal label) instead of the prose
|
|
* after the label.
|
|
*
|
|
* Root cause: extractOneLinerFromBody() matches the first **...** span. In
|
|
* `**One-liner:** prose`, the first span contains only `One-liner:` so the
|
|
* function returns the label instead of the prose after it.
|
|
*/
|
|
|
|
const { describe, test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const path = require('path');
|
|
|
|
const { extractOneLinerFromBody } = require(
|
|
path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'core-utils.cjs')
|
|
);
|
|
|
|
describe('bug #2660: extractOneLinerFromBody', () => {
|
|
test('a) body-style **One-liner:** label returns prose after the label', () => {
|
|
const content =
|
|
'# Phase 2 Plan 01: Foundation Summary\n\n**One-liner:** Real prose here.\n';
|
|
assert.strictEqual(extractOneLinerFromBody(content), 'Real prose here.');
|
|
});
|
|
|
|
test('b) frontmatter-only one-liner returns null (caller handles frontmatter)', () => {
|
|
const content =
|
|
'---\none-liner: Set up project\n---\n\n# Phase 1: Foundation Summary\n\nBody prose with no bold line.\n';
|
|
assert.strictEqual(extractOneLinerFromBody(content), null);
|
|
});
|
|
|
|
test('c) no one-liner at all returns null', () => {
|
|
const content =
|
|
'# Phase 1: Foundation Summary\n\nJust some narrative, no bold line.\n';
|
|
assert.strictEqual(extractOneLinerFromBody(content), null);
|
|
});
|
|
|
|
test('d) bold spans inside the prose are preserved', () => {
|
|
const content =
|
|
'# Phase 1: Foundation Summary\n\n**One-liner:** This is **important** stuff.\n';
|
|
assert.strictEqual(
|
|
extractOneLinerFromBody(content),
|
|
'This is **important** stuff.'
|
|
);
|
|
});
|
|
|
|
test('e) empty prose after label returns null (no bogus bullet)', () => {
|
|
const empty =
|
|
'# Phase 1: Foundation Summary\n\n**One-liner:**\n\nRest of body.\n';
|
|
const whitespace =
|
|
'# Phase 1: Foundation Summary\n\n**One-liner:** \n\nRest of body.\n';
|
|
assert.strictEqual(extractOneLinerFromBody(empty), null);
|
|
assert.strictEqual(extractOneLinerFromBody(whitespace), null);
|
|
});
|
|
|
|
test('f) legacy bare **prose** format still works (no label, no colon)', () => {
|
|
// Preserve pre-existing behavior: SUMMARY files historically used
|
|
// `**bold prose**` with no label. See tests/commands.test.cjs:366 and
|
|
// tests/milestone.test.cjs:451 — both assert this form.
|
|
const content =
|
|
'---\nphase: "01"\n---\n\n# Phase 1: Foundation Summary\n\n**JWT auth with refresh rotation using jose library**\n\n## Performance\n';
|
|
assert.strictEqual(
|
|
extractOneLinerFromBody(content),
|
|
'JWT auth with refresh rotation using jose library'
|
|
);
|
|
});
|
|
|
|
test('g) other **Label:** prefixes (e.g. Summary:) also capture prose after label', () => {
|
|
const content =
|
|
'# Phase 1: Foundation Summary\n\n**Summary:** Built the thing.\n';
|
|
assert.strictEqual(extractOneLinerFromBody(content), 'Built the thing.');
|
|
});
|
|
|
|
test('h) CRLF line endings (Windows) are handled', () => {
|
|
const content =
|
|
'---\r\nphase: "01"\r\n---\r\n\r\n# Phase 1: Foundation Summary\r\n\r\n**One-liner:** Windows-authored prose.\r\n';
|
|
assert.strictEqual(
|
|
extractOneLinerFromBody(content),
|
|
'Windows-authored prose.'
|
|
);
|
|
});
|
|
});
|