Files
Agent-System-Core/scripts/test-package.mjs
T
weichen f32d431784 Enable canonical versioned Go module consumption
Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements.

Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate.

Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable.

Refs: Versioned dependencies U1/U3; feature/dependency-workspace
2026-10-13 15:11:37 +00:00

47 lines
3.2 KiB
JavaScript

import assert from 'node:assert/strict'
import { execFileSync, spawnSync } from 'node:child_process'
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { test } from 'node:test'
const root = dirname(dirname(fileURLToPath(import.meta.url)))
test('packed contracts compile in a consumer without the Core checkout', () => {
const consumer = mkdtempSync(join(tmpdir(), 'agent-contracts-consumer-'))
try {
const pack = spawnSync('npm', ['pack', '--json', '--ignore-scripts', '--pack-destination', consumer], {
cwd: root, encoding: 'utf8',
})
assert.equal(pack.status, 0, `Core must expose an independently packable contracts package:\n${pack.stderr}`)
const [artifact] = JSON.parse(pack.stdout)
assert.equal(artifact.name, '@agent-system/contracts')
assert.ok(artifact.files.some(file => file.path === 'package/index.d.ts'), 'declarations must be packed')
assert.ok(artifact.files.some(file => file.path === 'package/index.js'), 'ESM entry must be packed')
assert.ok(!artifact.files.some(file => file.path.endsWith('.go')), 'Go implementation is outside the npm package')
writeFileSync(join(consumer, 'package.json'), JSON.stringify({ private: true, type: 'module' }))
writeFileSync(join(consumer, 'consumer.ts'), `
import type { ActivityCard, Message, SurfaceSnapshot } from '@agent-system/contracts'
const card: ActivityCard = { id: 'card', projectId: 'project', conversationId: 'conversation', kind: 'progress', status: 'active', title: 'Working', createdAt: '2026-10-13T00:00:00Z', updatedAt: '2026-10-13T00:00:00Z' }
const message: Message = { id: 'message', conversationId: 'conversation', role: 'assistant', parts: [{ type: 'text', text: card.title }], createdAt: card.createdAt }
type Surface = SurfaceSnapshot
// @ts-expect-error unknown message roles are not part of the wire contract
const invalidRole: Message['role'] = 'operator'
export { message, invalidRole }; export type { Surface }
`)
const tsc = [join(root, 'node_modules/typescript/bin/tsc'), '--noEmit', '--strict', '--skipLibCheck', '--module', 'NodeNext', '--moduleResolution', 'NodeNext', 'consumer.ts']
const missing = spawnSync(process.execPath, tsc, { cwd: consumer, encoding: 'utf8' })
assert.notEqual(missing.status, 0, 'the consumer must not resolve Core types before package installation')
assert.match(missing.stdout, /TS2307.*@agent-system\/contracts/)
execFileSync('npm', ['install', '--ignore-scripts', '--no-audit', '--no-fund', '--offline', '--package-lock=false', join(consumer, artifact.filename)], { cwd: consumer, stdio: 'pipe' })
execFileSync(process.execPath, tsc, { cwd: consumer, stdio: 'inherit' })
execFileSync(process.execPath, ['--input-type=module', '-e', "import * as contracts from '@agent-system/contracts'; if (Object.keys(contracts).length) throw Error('contracts must remain type-only')"], { cwd: consumer, stdio: 'pipe' })
const declaration = readFileSync(join(consumer, 'node_modules/@agent-system/contracts/package/index.d.ts'), 'utf8')
assert.match(declaration, /export interface SurfaceSnapshot/)
} finally {
rmSync(consumer, { recursive: true, force: true })
}
})