@t275005746/gse 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.yml +42 -0
- package/.github/ISSUE_TEMPLATE/change_request.yml +50 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +38 -0
- package/.github/workflows/validate-gse.yml +33 -0
- package/.gse/README.md +18 -0
- package/.gse/gse-development-protocol.md +50 -0
- package/.gse/project-profile.md +29 -0
- package/.gse/quality-gates.md +25 -0
- package/.gse/releases/public-channel-publication-pending.md +49 -0
- package/.gse/releases/public-ci-run-pending.md +53 -0
- package/.gse/releases/public-release-owner-required.md +65 -0
- package/.gse/releases/public-repository-settings-owner-required.md +59 -0
- package/.gse/releases/public-security-contact-owner-required.md +45 -0
- package/.gse/state.json +27 -0
- package/CHANGELOG.md +24 -0
- package/CONTRIBUTING.md +64 -0
- package/LICENSE +21 -0
- package/README.md +236 -0
- package/README.zh-CN.md +236 -0
- package/SECURITY.md +41 -0
- package/SKILL.md +148 -0
- package/SUPPORT.md +38 -0
- package/agents/openai.yaml +4 -0
- package/assets/marketplace/README.md +7 -0
- package/assets/marketplace/gse-listing.json +75 -0
- package/assets/templates/acceptance-execution-packet.md +73 -0
- package/assets/templates/adr.md +14 -0
- package/assets/templates/change-brief.md +16 -0
- package/assets/templates/design.md +18 -0
- package/assets/templates/dispatch-packet.md +104 -0
- package/assets/templates/evidence.md +14 -0
- package/assets/templates/execution-quality-pack.md +65 -0
- package/assets/templates/goal-map.md +21 -0
- package/assets/templates/host-adapter.md +48 -0
- package/assets/templates/host-ui-invocation-record.md +42 -0
- package/assets/templates/incident-review.md +60 -0
- package/assets/templates/public-channel-publication-record.md +49 -0
- package/assets/templates/public-ci-run-record.md +53 -0
- package/assets/templates/public-release-record.md +65 -0
- package/assets/templates/public-repository-settings-record.md +59 -0
- package/assets/templates/public-security-contact-record.md +45 -0
- package/assets/templates/release-trust-record.md +32 -0
- package/assets/templates/review.md +18 -0
- package/assets/templates/spec.md +16 -0
- package/assets/templates/target-adoption-evidence.md +29 -0
- package/assets/templates/tasks.md +17 -0
- package/assets/templates/update-release-acceptance-record.md +58 -0
- package/examples/README.md +22 -0
- package/examples/agent-runtime-host/.claude/gse-adapter.md +6 -0
- package/examples/agent-runtime-host/.codex/gse-adapter.md +7 -0
- package/examples/agent-runtime-host/.gse/goal-map.md +7 -0
- package/examples/agent-runtime-host/.gse/project-profile.md +27 -0
- package/examples/agent-runtime-host/.gse/tooling.md +5 -0
- package/examples/agent-runtime-host/.mcp.json +9 -0
- package/examples/agent-runtime-host/AGENTS.md +5 -0
- package/examples/agent-runtime-host/README.md +10 -0
- package/examples/agent-runtime-host/docs/model-routing.md +5 -0
- package/examples/cli-tool/.gse/project-profile.md +21 -0
- package/examples/cli-tool/AGENTS.md +5 -0
- package/examples/cli-tool/README.md +12 -0
- package/examples/cli-tool/package.json +21 -0
- package/examples/small-app/.env.example +2 -0
- package/examples/small-app/.github/workflows/ci.yml +8 -0
- package/examples/small-app/AGENTS.md +5 -0
- package/examples/small-app/README.md +12 -0
- package/examples/small-app/package.json +26 -0
- package/examples/small-app/playwright.config.ts +4 -0
- package/package.json +53 -0
- package/references/adoption-recipes.md +171 -0
- package/references/agent-roles.md +49 -0
- package/references/architecture-health.md +101 -0
- package/references/benchmark-audit.md +73 -0
- package/references/commands.md +295 -0
- package/references/community-channels.md +46 -0
- package/references/compatibility.md +70 -0
- package/references/design-basis.md +38 -0
- package/references/domain-model.md +129 -0
- package/references/domain-quality-gates.md +75 -0
- package/references/drift-audit.md +81 -0
- package/references/evidence-taxonomy.md +123 -0
- package/references/file-ownership.md +107 -0
- package/references/final-readiness.md +84 -0
- package/references/forward-test.md +133 -0
- package/references/goal-map.md +36 -0
- package/references/host-adapters.md +119 -0
- package/references/learning-system.md +35 -0
- package/references/marketplace-discovery.md +46 -0
- package/references/model-routing.md +103 -0
- package/references/open-source-defaults.md +39 -0
- package/references/operating-model.md +52 -0
- package/references/packaging.md +277 -0
- package/references/project-agent-workspace.md +89 -0
- package/references/project-bootstrap.md +122 -0
- package/references/project-profile.md +57 -0
- package/references/public-release.md +174 -0
- package/references/quality-gates.md +100 -0
- package/references/recovery.md +176 -0
- package/references/release-trust.md +43 -0
- package/references/release.md +126 -0
- package/references/review.md +141 -0
- package/references/router.md +90 -0
- package/references/spec-workflow.md +66 -0
- package/references/task-levels.md +81 -0
- package/references/tool-adapters.md +73 -0
- package/scripts/audit-acceptance-execution-packet.mjs +133 -0
- package/scripts/audit-adoption-recipes.mjs +99 -0
- package/scripts/audit-adoption.mjs +154 -0
- package/scripts/audit-change-lifecycle.mjs +77 -0
- package/scripts/audit-change-system.mjs +134 -0
- package/scripts/audit-ci-readiness.mjs +107 -0
- package/scripts/audit-close-gate.mjs +323 -0
- package/scripts/audit-command-adapters.mjs +91 -0
- package/scripts/audit-command-execution.mjs +210 -0
- package/scripts/audit-commands.mjs +117 -0
- package/scripts/audit-compatibility.mjs +149 -0
- package/scripts/audit-completion-readiness.mjs +292 -0
- package/scripts/audit-distribution.mjs +251 -0
- package/scripts/audit-domain-quality-gates.mjs +108 -0
- package/scripts/audit-evidence-placeholders.mjs +126 -0
- package/scripts/audit-final-acceptance-packet.mjs +148 -0
- package/scripts/audit-final-form-progress-report.mjs +161 -0
- package/scripts/audit-final-form-stale-copy.mjs +221 -0
- package/scripts/audit-final-readiness-promotion.mjs +255 -0
- package/scripts/audit-final-readiness.mjs +226 -0
- package/scripts/audit-fixtures.mjs +154 -0
- package/scripts/audit-fresh-session-readiness.mjs +177 -0
- package/scripts/audit-gse.mjs +275 -0
- package/scripts/audit-host-adapters.mjs +119 -0
- package/scripts/audit-host-runtime-evidence-handoff.mjs +159 -0
- package/scripts/audit-host-runtime-invocation-drill.mjs +240 -0
- package/scripts/audit-host-runtime-invocations.mjs +254 -0
- package/scripts/audit-host-ui-invocation.mjs +132 -0
- package/scripts/audit-learning-system.mjs +103 -0
- package/scripts/audit-local-final-form-completion.mjs +131 -0
- package/scripts/audit-marketplace-discovery.mjs +122 -0
- package/scripts/audit-npm-package-metadata.mjs +155 -0
- package/scripts/audit-npm-publish-dry-run.mjs +169 -0
- package/scripts/audit-npm-tarball-install.mjs +191 -0
- package/scripts/audit-open-source-defaults.mjs +92 -0
- package/scripts/audit-open-source-readiness.mjs +97 -0
- package/scripts/audit-owner-external-gate-kit.mjs +218 -0
- package/scripts/audit-project.mjs +323 -0
- package/scripts/audit-public-acceptance-command-dry-run-drill.mjs +203 -0
- package/scripts/audit-public-acceptance-handoff.mjs +142 -0
- package/scripts/audit-public-acceptance-readiness.mjs +224 -0
- package/scripts/audit-public-channel-publication.mjs +248 -0
- package/scripts/audit-public-ci-run.mjs +184 -0
- package/scripts/audit-public-collaboration-templates.mjs +98 -0
- package/scripts/audit-public-external-gate-probe.mjs +206 -0
- package/scripts/audit-public-release-checklist.mjs +133 -0
- package/scripts/audit-public-release-decision.mjs +201 -0
- package/scripts/audit-public-release-metadata.mjs +176 -0
- package/scripts/audit-public-repository-settings.mjs +237 -0
- package/scripts/audit-public-security-contact.mjs +171 -0
- package/scripts/audit-readme-docs.mjs +185 -0
- package/scripts/audit-recovery-readiness.mjs +98 -0
- package/scripts/audit-release-bundle.mjs +251 -0
- package/scripts/audit-release-owner-action-plan-drill.mjs +277 -0
- package/scripts/audit-release-owner-action-plan.mjs +164 -0
- package/scripts/audit-release-readiness.mjs +106 -0
- package/scripts/audit-release-status-manifest.mjs +165 -0
- package/scripts/audit-release-trust.mjs +62 -0
- package/scripts/audit-remote-distribution.mjs +266 -0
- package/scripts/audit-roadmap-consistency.mjs +235 -0
- package/scripts/audit-signing.mjs +147 -0
- package/scripts/audit-state-freshness.mjs +113 -0
- package/scripts/audit-target-adoption-evidence.mjs +117 -0
- package/scripts/audit-target-project.mjs +507 -0
- package/scripts/audit-update-release-acceptance.mjs +136 -0
- package/scripts/audit-v1-target-validation.mjs +269 -0
- package/scripts/audit-validation-profiles.mjs +125 -0
- package/scripts/close-change.mjs +116 -0
- package/scripts/discover-project-profile.mjs +307 -0
- package/scripts/forward-test-gse.mjs +146 -0
- package/scripts/generate-command-adapter.mjs +231 -0
- package/scripts/generate-final-acceptance-packet.mjs +181 -0
- package/scripts/generate-final-form-progress-report.mjs +205 -0
- package/scripts/generate-host-adapter.mjs +73 -0
- package/scripts/generate-host-runtime-evidence-handoff.mjs +206 -0
- package/scripts/generate-owner-external-gate-kit.mjs +295 -0
- package/scripts/generate-public-acceptance-handoff.mjs +168 -0
- package/scripts/generate-public-release-checklist.mjs +207 -0
- package/scripts/generate-release-bundle.mjs +505 -0
- package/scripts/generate-release-owner-action-plan.mjs +172 -0
- package/scripts/generate-release-status-manifest.mjs +200 -0
- package/scripts/generate-session-prompt.mjs +188 -0
- package/scripts/gse.mjs +67 -0
- package/scripts/init-change.mjs +265 -0
- package/scripts/init-project.mjs +785 -0
- package/scripts/install-gse.mjs +234 -0
- package/scripts/lib/evidence-placeholders.mjs +28 -0
- package/scripts/package-gse.mjs +174 -0
- package/scripts/probe-public-external-gates.mjs +167 -0
- package/scripts/record-host-invocation.mjs +151 -0
- package/scripts/record-learning.mjs +137 -0
- package/scripts/record-public-channel-publication.mjs +178 -0
- package/scripts/record-public-ci-run.mjs +180 -0
- package/scripts/record-public-release.mjs +175 -0
- package/scripts/record-public-repository-settings.mjs +209 -0
- package/scripts/record-public-security-contact.mjs +157 -0
- package/scripts/run-gse-command.mjs +538 -0
- package/scripts/run-validation-profile.mjs +146 -0
- package/scripts/sign-gse-package.mjs +83 -0
- package/scripts/update-project-state.mjs +223 -0
- package/scripts/validate-gse.mjs +1168 -0
- package/scripts/verify-gse-package.mjs +85 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { spawnSync } from 'node:child_process'
|
|
6
|
+
|
|
7
|
+
const args = process.argv.slice(2)
|
|
8
|
+
|
|
9
|
+
function readArg(name, fallback = null) {
|
|
10
|
+
const index = args.indexOf(name)
|
|
11
|
+
if (index === -1) return fallback
|
|
12
|
+
return args[index + 1] ?? fallback
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
|
|
16
|
+
const jsonOnly = args.includes('--json')
|
|
17
|
+
const profile = readArg('--profile', 'lite')
|
|
18
|
+
const target = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-command-exec-'))
|
|
19
|
+
|
|
20
|
+
if (!['lite', 'full'].includes(profile)) {
|
|
21
|
+
console.error(`Unknown command execution audit profile: ${profile}`)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function run(script, commandArgs) {
|
|
26
|
+
const result = spawnSync(process.execPath, [path.join(root, 'scripts', script), ...commandArgs], {
|
|
27
|
+
cwd: root,
|
|
28
|
+
encoding: 'utf8',
|
|
29
|
+
windowsHide: true,
|
|
30
|
+
})
|
|
31
|
+
return {
|
|
32
|
+
command: [process.execPath, path.join(root, 'scripts', script), ...commandArgs].join(' '),
|
|
33
|
+
status: result.status ?? 1,
|
|
34
|
+
stdout: (result.stdout ?? '').trim(),
|
|
35
|
+
stderr: (result.stderr ?? '').trim(),
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseJson(text) {
|
|
40
|
+
try { return JSON.parse(text) } catch { return null }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function diagnosticOk(runResult, report) {
|
|
44
|
+
if (runResult.status === 0 && report?.execution?.ok) return true
|
|
45
|
+
if (report?.execution?.diagnosticSummary?.failed === 0) return true
|
|
46
|
+
const child = parseJson(report?.execution?.stdout || '')
|
|
47
|
+
return child?.summary?.failed === 0
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
51
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function maybeRun(enabled, script, commandArgs) {
|
|
55
|
+
return enabled ? run(script, commandArgs) : null
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fs.mkdirSync(target, { recursive: true })
|
|
59
|
+
fs.writeFileSync(path.join(target, 'AGENTS.md'), '# Test Project\n', 'utf8')
|
|
60
|
+
|
|
61
|
+
const initRun = run('init-project.mjs', ['--target', target, '--mode', 'standard', '--json'])
|
|
62
|
+
fs.mkdirSync(path.join(target, 'docs'), { recursive: true })
|
|
63
|
+
fs.writeFileSync(path.join(target, 'docs', 'productization-architecture.md'), '# Productization Architecture\n', 'utf8')
|
|
64
|
+
fs.appendFileSync(path.join(target, '.gse', 'README.md'), '\nCanonical plan: `docs/productization-architecture.md`.\n', 'utf8')
|
|
65
|
+
|
|
66
|
+
const adapterRun = run('generate-command-adapter.mjs', ['--target', target, '--host', 'all', '--json'])
|
|
67
|
+
const helpRun = run('run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse help', '--json'])
|
|
68
|
+
const continueRun = run('run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse continue', '--json'])
|
|
69
|
+
const shortCliRun = run('gse.mjs', ['status', '--target', target, '--json'])
|
|
70
|
+
|
|
71
|
+
const full = profile === 'full'
|
|
72
|
+
const statusRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse status', '--json'])
|
|
73
|
+
const doctorRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse doctor', '--json'])
|
|
74
|
+
const acceptanceRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse acceptance', '--json'])
|
|
75
|
+
const ownerActionsRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse owner-actions', '--json'])
|
|
76
|
+
const ownerActionsCompactRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse owner-actions', '--json', '--compact'])
|
|
77
|
+
const probeWaitingRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse probe', '--json'])
|
|
78
|
+
const probeRejectRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse probe --public-repo-url https://github.com/example/gse', '--json'])
|
|
79
|
+
const releaseDryRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse release --label command-exec-release', '--json'])
|
|
80
|
+
const releaseExecuteOut = path.join(target, 'release-bundle-command-exec')
|
|
81
|
+
const releaseExecuteRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', `/gse release --label command-exec-release --out ${releaseExecuteOut}`, '--execute', '--json'])
|
|
82
|
+
const packageDryRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse package --label command-exec-package', '--json'])
|
|
83
|
+
const packageExecuteOut = path.join(target, 'package-command-exec')
|
|
84
|
+
const packageExecuteRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', `/gse package --label command-exec-package --out ${packageExecuteOut}`, '--execute', '--json'])
|
|
85
|
+
const installDryRunTarget = path.join(target, 'install-dry-run-command-exec')
|
|
86
|
+
const installDryRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', `/gse install --source ${packageExecuteOut} --install-target ${installDryRunTarget}`, '--json'])
|
|
87
|
+
const installExecuteTarget = path.join(target, 'install-command-exec')
|
|
88
|
+
const installExecuteRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', `/gse install --source ${packageExecuteOut} --install-target ${installExecuteTarget}`, '--execute', '--json'])
|
|
89
|
+
const publicReleaseDryRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse public-release', '--json'])
|
|
90
|
+
const publicReleaseExecuteOut = path.join(target, 'public-release-checklist-command-exec.md')
|
|
91
|
+
const publicReleaseExecuteRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', `/gse public-release --out ${publicReleaseExecuteOut}`, '--execute', '--json'])
|
|
92
|
+
const doctorTargetRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse doctor', '--json'])
|
|
93
|
+
const verifyRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse verify --profile lite', '--json'])
|
|
94
|
+
const auditRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse audit', '--json'])
|
|
95
|
+
const closeRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse close', '--json'])
|
|
96
|
+
const changeRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse change add-login --level lite', '--execute', '--json'])
|
|
97
|
+
|
|
98
|
+
const help = parseJson(helpRun.stdout)
|
|
99
|
+
const cont = parseJson(continueRun.stdout)
|
|
100
|
+
const status = statusRun ? parseJson(statusRun.stdout) : null
|
|
101
|
+
const doctor = doctorRun ? parseJson(doctorRun.stdout) : null
|
|
102
|
+
const acceptance = acceptanceRun ? parseJson(acceptanceRun.stdout) : null
|
|
103
|
+
const ownerActions = ownerActionsRun ? parseJson(ownerActionsRun.stdout) : null
|
|
104
|
+
const ownerActionsCompact = ownerActionsCompactRun ? parseJson(ownerActionsCompactRun.stdout) : null
|
|
105
|
+
const probeWaiting = probeWaitingRun ? parseJson(probeWaitingRun.stdout) : null
|
|
106
|
+
const probeReject = probeRejectRun ? parseJson(probeRejectRun.stdout) : null
|
|
107
|
+
const releaseDryRunReport = releaseDryRun ? parseJson(releaseDryRun.stdout) : null
|
|
108
|
+
const releaseExecuteReport = releaseExecuteRun ? parseJson(releaseExecuteRun.stdout) : null
|
|
109
|
+
const doctorTarget = doctorTargetRun ? parseJson(doctorTargetRun.stdout) : null
|
|
110
|
+
const verify = verifyRun ? parseJson(verifyRun.stdout) : null
|
|
111
|
+
const audit = auditRun ? parseJson(auditRun.stdout) : null
|
|
112
|
+
const close = closeRun ? parseJson(closeRun.stdout) : null
|
|
113
|
+
const change = changeRun ? parseJson(changeRun.stdout) : null
|
|
114
|
+
const doctorData = doctor ? parseJson(doctor.execution?.stdout ?? '') : null
|
|
115
|
+
const ownerActionsData = ownerActions ? parseJson(ownerActions.execution?.stdout ?? '') : null
|
|
116
|
+
const probeWaitingData = probeWaiting ? parseJson(probeWaiting.execution?.stdout ?? '') : null
|
|
117
|
+
const probeRejectData = probeReject ? parseJson(probeReject.execution?.stdout ?? '') : null
|
|
118
|
+
const releaseDryRunData = releaseDryRunReport ? parseJson(releaseDryRunReport.execution?.stdout ?? '') : null
|
|
119
|
+
const releaseExecuteData = releaseExecuteReport ? parseJson(releaseExecuteReport.execution?.stdout ?? '') : null
|
|
120
|
+
const packageDryRunReport = packageDryRun ? parseJson(packageDryRun.stdout) : null
|
|
121
|
+
const packageExecuteReport = packageExecuteRun ? parseJson(packageExecuteRun.stdout) : null
|
|
122
|
+
const installDryRunReport = installDryRun ? parseJson(installDryRun.stdout) : null
|
|
123
|
+
const installExecuteReport = installExecuteRun ? parseJson(installExecuteRun.stdout) : null
|
|
124
|
+
const packageDryRunData = packageDryRunReport ? parseJson(packageDryRunReport.execution?.stdout ?? '') : null
|
|
125
|
+
const packageExecuteData = packageExecuteReport ? parseJson(packageExecuteReport.execution?.stdout ?? '') : null
|
|
126
|
+
const installDryRunData = installDryRunReport ? parseJson(installDryRunReport.execution?.stdout ?? '') : null
|
|
127
|
+
const installExecuteData = installExecuteReport ? parseJson(installExecuteReport.execution?.stdout ?? '') : null
|
|
128
|
+
const publicReleaseDryRunReport = publicReleaseDryRun ? parseJson(publicReleaseDryRun.stdout) : null
|
|
129
|
+
const publicReleaseExecuteReport = publicReleaseExecuteRun ? parseJson(publicReleaseExecuteRun.stdout) : null
|
|
130
|
+
const publicReleaseDryRunData = publicReleaseDryRunReport ? parseJson(publicReleaseDryRunReport.execution?.stdout ?? '') : null
|
|
131
|
+
const publicReleaseExecuteData = publicReleaseExecuteReport ? parseJson(publicReleaseExecuteReport.execution?.stdout ?? '') : null
|
|
132
|
+
|
|
133
|
+
const claudeCommand = fs.existsSync(path.join(target, '.claude', 'commands', 'gse.md'))
|
|
134
|
+
? fs.readFileSync(path.join(target, '.claude', 'commands', 'gse.md'), 'utf8')
|
|
135
|
+
: ''
|
|
136
|
+
const codexPointer = fs.existsSync(path.join(target, '.codex', 'gse-command.md'))
|
|
137
|
+
? fs.readFileSync(path.join(target, '.codex', 'gse-command.md'), 'utf8')
|
|
138
|
+
: ''
|
|
139
|
+
const copilotPointer = fs.existsSync(path.join(target, '.github', 'copilot-instructions.md'))
|
|
140
|
+
? fs.readFileSync(path.join(target, '.github', 'copilot-instructions.md'), 'utf8')
|
|
141
|
+
: ''
|
|
142
|
+
const geminiPointer = fs.existsSync(path.join(target, 'GEMINI.md'))
|
|
143
|
+
? fs.readFileSync(path.join(target, 'GEMINI.md'), 'utf8')
|
|
144
|
+
: ''
|
|
145
|
+
|
|
146
|
+
const liteChecks = [
|
|
147
|
+
check('CMDX01', 'portable command runner exists', fs.existsSync(path.join(root, 'scripts', 'run-gse-command.mjs')), 'scripts/run-gse-command.mjs'),
|
|
148
|
+
check('CMDX02', 'target project initializes for command smoke', initRun.status === 0, initRun.command),
|
|
149
|
+
check('CMDX03', 'host command adapters are generated', adapterRun.status === 0 && claudeCommand.includes('run-gse-command.mjs') && codexPointer.includes('run-gse-command.mjs') && copilotPointer.includes('GitHub Copilot GSE Adapter') && geminiPointer.includes('Gemini GSE Adapter'), 'generated supported host adapters'),
|
|
150
|
+
check('CMDX04', '/gse help resolves command reference', helpRun.status === 0 && help?.route?.route === 'references/commands.md', '/gse help'),
|
|
151
|
+
check('CMDX05', '/gse continue executes session prompt generator', continueRun.status === 0 && cont?.execution?.status === 0 && cont?.execution?.stdout?.includes('Use GSE to continue'), '/gse continue'),
|
|
152
|
+
check('CMDX05b', 'short CLI wrapper routes to portable command runner', shortCliRun.status === 0 && shortCliRun.stdout.includes('"/gse status"') && shortCliRun.stdout.includes('"stateValid": true'), 'scripts/gse.mjs status --target <target> --json'),
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
const fullChecks = full
|
|
156
|
+
? [
|
|
157
|
+
check('CMDX06', '/gse status exposes GSE final-form progress when target is GSE skill', statusRun.status === 0 && status?.execution?.status === 0 && status?.execution?.stdout?.includes('fullFinalFormReadiness') && status?.execution?.stdout?.includes('pendingGateCount'), '/gse status'),
|
|
158
|
+
check('CMDX07', '/gse doctor exposes GSE public acceptance blockers when target is GSE skill', doctorRun.status === 0 && doctor?.execution?.status === 0 && doctorData?.workflows?.publicAcceptanceDoctor === 'verified' && doctorData?.summary?.pendingGates > 0 && doctorData?.summary?.publicAccepted === 'not-accepted', '/gse doctor'),
|
|
159
|
+
check('CMDX08', '/gse acceptance aliases the public acceptance doctor', acceptanceRun.status === 0 && acceptance?.execution?.status === 0 && acceptance?.execution?.stdout?.includes('"publicAcceptanceDoctor": "verified"'), '/gse acceptance'),
|
|
160
|
+
check('CMDX08b', '/gse owner-actions exposes compact owner/external action commands without claiming acceptance', ownerActionsRun.status === 0 && ownerActions?.execution?.status === 0 && ownerActionsData?.pendingGateCount === 7 && ownerActionsData?.publicAccepted === 'not-accepted' && ownerActionsData.actions?.every((item) => item.recordCommand && item.preflightCommand), '/gse owner-actions'),
|
|
161
|
+
check('CMDX08c', '/gse owner-actions --compact returns owner packet without wrapper path noise', ownerActionsCompactRun.status === 0 && ownerActionsCompact?.pendingGateCount === 7 && ownerActionsCompact?.publicAccepted === 'not-accepted' && !ownerActionsCompactRun.stdout.includes(root) && !ownerActionsCompactRun.stdout.includes(process.execPath), '/gse owner-actions --json --compact'),
|
|
162
|
+
check('CMDX08c2', '/gse owner-actions --compact routes probe verification through portable command runner', ownerActionsCompactRun.status === 0 && ownerActionsCompact?.verificationCommands?.some((command) => command.includes('run-gse-command.mjs') && command.includes('/gse probe')) && !ownerActionsCompact?.verificationCommands?.some((command) => command.startsWith('node scripts/probe-public-external-gates.mjs')), '/gse owner-actions compact verificationCommands'),
|
|
163
|
+
check('CMDX08d', '/gse probe runs as a waiting diagnostic without evidence inputs', probeWaitingRun.status === 0 && probeWaiting?.execution?.status === 0 && probeWaitingData?.status === 'waiting-for-input' && probeWaitingData?.summary?.checked === 0, '/gse probe'),
|
|
164
|
+
check('CMDX08e', '/gse probe rejects placeholder public evidence through portable command runner', probeRejectRun.status !== 0 && probeReject?.execution?.status !== 0 && probeRejectData?.status === 'failed' && probeRejectData?.probes?.some((item) => item.errors?.some((error) => error.includes('not a placeholder'))), '/gse probe --public-repo-url https://github.com/example/gse'),
|
|
165
|
+
check('CMDX08f', '/gse release dry-runs release bundle generation without writing canonical output', releaseDryRun.status === 0 && releaseDryRunReport?.execution?.status === 0 && ['ready', 'dry-run'].includes(releaseDryRunData?.status) && releaseDryRunData?.dryRun === true && releaseDryRunData?.validation?.status === 'passed', '/gse release'),
|
|
166
|
+
check('CMDX08g', '/gse release --execute writes a release bundle to the requested output path', releaseExecuteRun.status === 0 && releaseExecuteReport?.execution?.status === 0 && releaseExecuteData?.status === 'written' && releaseExecuteData?.dryRun === false && fs.existsSync(path.join(releaseExecuteOut, 'bundle-manifest.json')), '/gse release --execute --out <tmp>'),
|
|
167
|
+
check('CMDX08g2', '/gse package dry-runs local package generation without writing package output', packageDryRun.status === 0 && packageDryRunReport?.execution?.status === 0 && packageDryRunData?.status === 'ready' && packageDryRunData?.dryRun === true && packageDryRunData?.fileCount > 20 && !fs.existsSync(path.join(root, '.gse', 'packages', 'command-exec-package')), '/gse package'),
|
|
168
|
+
check('CMDX08g3', '/gse package --execute writes a package manifest to the requested output path', packageExecuteRun.status === 0 && packageExecuteReport?.execution?.status === 0 && packageExecuteData?.status === 'written' && packageExecuteData?.dryRun === false && fs.existsSync(path.join(packageExecuteOut, 'gse-package-manifest.json')), '/gse package --execute --out <tmp>'),
|
|
169
|
+
check('CMDX08g4', '/gse install dry-runs package installation without writing the install target', installDryRun.status === 0 && installDryRunReport?.execution?.status === 0 && installDryRunData?.status === 'passed' && installDryRunData?.dryRun === true && installDryRunData?.summary?.written > 20 && !fs.existsSync(path.join(installDryRunTarget, 'SKILL.md')), '/gse install --source <package> --install-target <tmp>'),
|
|
170
|
+
check('CMDX08g5', '/gse install --execute writes an install target with the GSE skill entrypoint', installExecuteRun.status === 0 && installExecuteReport?.execution?.status === 0 && installExecuteData?.status === 'passed' && installExecuteData?.dryRun === false && fs.existsSync(path.join(installExecuteTarget, 'SKILL.md')) && fs.existsSync(path.join(installExecuteTarget, 'scripts', 'gse.mjs')), '/gse install --execute --source <package> --install-target <tmp>'),
|
|
171
|
+
check('CMDX08h', '/gse public-release dry-runs the ordered public release checklist without writing canonical output', publicReleaseDryRun.status === 0 && publicReleaseDryRunReport?.execution?.status === 0 && publicReleaseDryRunData?.status === 'ready' && publicReleaseDryRunData?.dryRun === true && publicReleaseDryRunData?.publicReleaseChecklist === 'ready', '/gse public-release'),
|
|
172
|
+
check('CMDX08i', '/gse public-release --execute writes the requested checklist output', publicReleaseExecuteRun.status === 0 && publicReleaseExecuteReport?.execution?.status === 0 && publicReleaseExecuteData?.status === 'written' && publicReleaseExecuteData?.dryRun === false && fs.existsSync(publicReleaseExecuteOut) && fs.readFileSync(publicReleaseExecuteOut, 'utf8').includes('GSE Public Release Checklist'), '/gse public-release --execute --out <tmp>'),
|
|
173
|
+
check('CMDX09', '/gse doctor falls back to target project doctor for normal projects', diagnosticOk(doctorTargetRun, doctorTarget) && doctorTarget?.execution?.command?.includes('audit-target-project.mjs'), '/gse doctor on fixture target'),
|
|
174
|
+
check('CMDX10', '/gse verify executes validation profile runner', verifyRun.status === 0 && verify?.execution?.status === 0 && verify?.execution?.stdout?.includes('"profile": "lite"') && verify?.execution?.stdout?.includes('"validationProfile": "verified"'), '/gse verify --profile lite'),
|
|
175
|
+
check('CMDX11', '/gse audit executes target project doctor', diagnosticOk(auditRun, audit), '/gse audit'),
|
|
176
|
+
check('CMDX12', '/gse close executes close gate', diagnosticOk(closeRun, close), '/gse close'),
|
|
177
|
+
check('CMDX13', '/gse change executes change pack creation only with --execute', changeRun.status === 0 && change?.execution?.status === 0 && fs.existsSync(path.join(target, '.gse', 'changes', 'add-login', 'brief.md')), '/gse change --execute'),
|
|
178
|
+
]
|
|
179
|
+
: []
|
|
180
|
+
|
|
181
|
+
const checks = [...liteChecks, ...fullChecks]
|
|
182
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
183
|
+
const failed = checks.length - passed
|
|
184
|
+
const commandRuns = [initRun, adapterRun, helpRun, continueRun, shortCliRun, statusRun, doctorRun, acceptanceRun, ownerActionsRun, ownerActionsCompactRun, probeWaitingRun, probeRejectRun, releaseDryRun, releaseExecuteRun, packageDryRun, packageExecuteRun, installDryRun, installExecuteRun, publicReleaseDryRun, publicReleaseExecuteRun, doctorTargetRun, verifyRun, auditRun, closeRun, changeRun].filter(Boolean)
|
|
185
|
+
const report = {
|
|
186
|
+
root,
|
|
187
|
+
generatedAt: new Date().toISOString(),
|
|
188
|
+
target,
|
|
189
|
+
profile,
|
|
190
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
191
|
+
workflows: {
|
|
192
|
+
portableCommandExecution: failed === 0 ? 'verified' : 'failed',
|
|
193
|
+
generatedHostCommandPointers: failed === 0 ? 'verified' : 'failed',
|
|
194
|
+
profile,
|
|
195
|
+
},
|
|
196
|
+
commands: commandRuns.map((item) => item.command),
|
|
197
|
+
limits: [
|
|
198
|
+
'Lite profile verifies portable command entry and generated host command pointers.',
|
|
199
|
+
'Full profile verifies every portable command path, including heavier status, doctor, verify, audit, close, and change paths.',
|
|
200
|
+
'This audit does not prove Claude Code, Codex, Hermes, WorkBuddy, Copilot, Gemini, or generic UI runtimes invoked the command natively.',
|
|
201
|
+
],
|
|
202
|
+
checks,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
fs.rmSync(target, { recursive: true, force: true })
|
|
206
|
+
|
|
207
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
208
|
+
else console.log(JSON.stringify(report, null, 2))
|
|
209
|
+
|
|
210
|
+
if (failed > 0) process.exit(1)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2)
|
|
6
|
+
|
|
7
|
+
function readArg(name, fallback = null) {
|
|
8
|
+
const index = args.indexOf(name)
|
|
9
|
+
if (index === -1) return fallback
|
|
10
|
+
return args[index + 1] ?? fallback
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
|
|
14
|
+
const jsonOnly = args.includes('--json')
|
|
15
|
+
|
|
16
|
+
function read(relativePath) {
|
|
17
|
+
const fullPath = path.join(root, relativePath)
|
|
18
|
+
return fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8') : ''
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function exists(relativePath) {
|
|
22
|
+
return fs.existsSync(path.join(root, relativePath))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
26
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const skill = read('SKILL.md')
|
|
30
|
+
const commands = read('references/commands.md')
|
|
31
|
+
const router = read('references/router.md')
|
|
32
|
+
const validate = read('scripts/validate-gse.mjs')
|
|
33
|
+
|
|
34
|
+
const requiredCommands = [
|
|
35
|
+
'/gse help',
|
|
36
|
+
'/gse init',
|
|
37
|
+
'/gse adopt',
|
|
38
|
+
'/gse continue',
|
|
39
|
+
'/gse status',
|
|
40
|
+
'/gse doctor',
|
|
41
|
+
'/gse acceptance',
|
|
42
|
+
'/gse owner-actions',
|
|
43
|
+
'/gse probe',
|
|
44
|
+
'/gse release',
|
|
45
|
+
'/gse package',
|
|
46
|
+
'/gse install',
|
|
47
|
+
'/gse public-release',
|
|
48
|
+
'/gse change',
|
|
49
|
+
'/gse slice',
|
|
50
|
+
'/gse verify',
|
|
51
|
+
'/gse learn',
|
|
52
|
+
'/gse audit',
|
|
53
|
+
'/gse close',
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
const checks = [
|
|
57
|
+
check('CMD01', 'commands reference exists', exists('references/commands.md'), 'references/commands.md'),
|
|
58
|
+
check('CMD02', 'SKILL routes command-style usage to commands reference', skill.includes('references/commands.md') && skill.includes('/gse ...'), 'SKILL.md'),
|
|
59
|
+
check('CMD03', 'all required commands are documented', requiredCommands.every((item) => commands.includes(item)), requiredCommands.join(', ')),
|
|
60
|
+
check('CMD04', 'commands preserve host-neutral slash-command boundary', commands.includes('host-neutral command semantics') && commands.includes('do not prove that the current host has native slash-command support'), 'references/commands.md'),
|
|
61
|
+
check('CMD05', 'commands preserve evidence and acceptance boundaries', commands.includes('result -> verified -> accepted') && commands.includes('/gse close` is read-only in the portable command runner') && commands.includes('archive a named change pack after evidence exists'), 'references/commands.md'),
|
|
62
|
+
check('CMD06', 'router references command-style usage', router.includes('references/commands.md') && router.includes('/gse'), 'references/router.md'),
|
|
63
|
+
check('CMD07', 'validate-gse runs command audit', validate.includes('audit-commands.mjs'), 'scripts/validate-gse.mjs'),
|
|
64
|
+
check('CMD08', 'short CLI wrapper exists and is documented', exists('scripts/gse.mjs') && skill.includes('scripts/gse.mjs') && commands.includes('scripts/gse.mjs') && read('README.md').includes('scripts/gse.mjs') && read('README.zh-CN.md').includes('scripts/gse.mjs'), 'scripts/gse.mjs, SKILL.md, README.md, README.zh-CN.md, references/commands.md'),
|
|
65
|
+
check('CMD09', 'owner-actions compact output is documented for owner handoff', skill.includes('/gse owner-actions" --json --compact') && commands.includes('/gse owner-actions" --json --compact') && commands.includes('without local runner diagnostics'), 'SKILL.md, references/commands.md'),
|
|
66
|
+
check('CMD10', 'probe command is documented as owner/external evidence preflight', skill.includes('/gse probe --public-repo-url') && commands.includes('/gse probe --public-repo-url') && commands.includes('waiting-for-input') && commands.includes('does not publish, approve, configure, or accept'), 'SKILL.md, references/commands.md'),
|
|
67
|
+
check('CMD11', 'release command is documented as dry-run by default and write-only with execute', commands.includes('/gse release') && commands.includes('dry-run') && commands.includes('Only write a bundle when the command is run with `--execute`') && commands.includes('does not publish a package'), 'references/commands.md'),
|
|
68
|
+
check('CMD12', 'public-release command is documented as checklist/runway and not acceptance', skill.includes('/gse public-release') && commands.includes('/gse public-release') && commands.includes('ordered public release checklist') && commands.includes('does not publish, approve, configure, or accept'), 'SKILL.md, references/commands.md'),
|
|
69
|
+
check('CMD13', 'package/install commands expose installability without claiming publication', skill.includes('/gse package') && skill.includes('/gse install') && commands.includes('/gse package') && commands.includes('/gse install') && commands.includes('Only write a package when the command is run with `--execute`') && commands.includes('Only write the install target when the command is run with `--execute`') && commands.includes('does not publish to a registry'), 'SKILL.md, references/commands.md'),
|
|
70
|
+
check('CMD14', 'close command is documented as read-only readiness check', commands.includes('| `/gse close` | Check whether the current slice is ready to close') && commands.includes('/gse close` is read-only in the portable command runner') && commands.includes('close-change.mjs --target <project-root> --change-id <change-id>'), 'references/commands.md'),
|
|
71
|
+
check('CMD15', 'learn command is documented as execute-gated learning capture', commands.includes('| `/gse learn` | Record a reusable lesson') && commands.includes('/gse learn --summary') && commands.includes('Append the entry only when `--execute` is supplied') && skill.includes('scripts/record-learning.mjs'), 'SKILL.md, references/commands.md'),
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
75
|
+
const failed = checks.length - passed
|
|
76
|
+
const report = {
|
|
77
|
+
root,
|
|
78
|
+
generatedAt: new Date().toISOString(),
|
|
79
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
80
|
+
workflows: { commandSemantics: failed === 0 ? 'verified' : 'failed' },
|
|
81
|
+
limits: [
|
|
82
|
+
'This audit verifies GSE command semantics, not native slash-command support in any host.',
|
|
83
|
+
'Host-specific command adapters still need project/session-specific evidence.',
|
|
84
|
+
],
|
|
85
|
+
checks,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function renderMarkdown(data) {
|
|
89
|
+
const lines = []
|
|
90
|
+
lines.push('# GSE Command Semantics Audit')
|
|
91
|
+
lines.push('')
|
|
92
|
+
lines.push('Generated: ' + data.generatedAt)
|
|
93
|
+
lines.push('Root: ' + data.root)
|
|
94
|
+
lines.push('')
|
|
95
|
+
lines.push('## Summary')
|
|
96
|
+
lines.push('')
|
|
97
|
+
lines.push('- Status: ' + data.summary.status)
|
|
98
|
+
lines.push('- Checks: ' + data.summary.passed + '/' + data.summary.total)
|
|
99
|
+
lines.push('- Command semantics: ' + data.workflows.commandSemantics)
|
|
100
|
+
lines.push('')
|
|
101
|
+
lines.push('## Checks')
|
|
102
|
+
lines.push('')
|
|
103
|
+
for (const item of data.checks) {
|
|
104
|
+
const marker = item.status === 'passed' ? '[x]' : '[ ]'
|
|
105
|
+
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
106
|
+
}
|
|
107
|
+
lines.push('')
|
|
108
|
+
lines.push('## Limits')
|
|
109
|
+
lines.push('')
|
|
110
|
+
for (const item of data.limits) lines.push('- ' + item)
|
|
111
|
+
return lines.join('\n') + '\n'
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
115
|
+
else console.log(renderMarkdown(report))
|
|
116
|
+
|
|
117
|
+
if (failed > 0) process.exit(1)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2)
|
|
6
|
+
|
|
7
|
+
function readArg(name, fallback = null) {
|
|
8
|
+
const index = args.indexOf(name)
|
|
9
|
+
if (index === -1) return fallback
|
|
10
|
+
return args[index + 1] ?? fallback
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
|
|
14
|
+
const jsonOnly = args.includes('--json')
|
|
15
|
+
const compatibilityPath = path.join(root, 'references', 'compatibility.md')
|
|
16
|
+
const hostAdaptersPath = path.join(root, 'references', 'host-adapters.md')
|
|
17
|
+
const toolAdaptersPath = path.join(root, 'references', 'tool-adapters.md')
|
|
18
|
+
const generatedCodexAdapter = path.join(root, 'examples', 'agent-runtime-host', '.codex', 'gse-adapter.md')
|
|
19
|
+
const generatedClaudeAdapter = path.join(root, 'examples', 'agent-runtime-host', '.claude', 'gse-adapter.md')
|
|
20
|
+
|
|
21
|
+
function read(filePath) {
|
|
22
|
+
return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : ''
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
26
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const compatibility = read(compatibilityPath)
|
|
30
|
+
const hostAdapters = read(hostAdaptersPath)
|
|
31
|
+
const toolAdapters = read(toolAdaptersPath)
|
|
32
|
+
const codexAdapter = read(generatedCodexAdapter)
|
|
33
|
+
const claudeAdapter = read(generatedClaudeAdapter)
|
|
34
|
+
|
|
35
|
+
const requiredHosts = [
|
|
36
|
+
'Codex-style',
|
|
37
|
+
'Claude Code-style',
|
|
38
|
+
'Hermes/AION-style runtime',
|
|
39
|
+
'WorkBuddy/other IDE agents',
|
|
40
|
+
'Copilot/Gemini-style assistants',
|
|
41
|
+
'Unknown or custom host',
|
|
42
|
+
]
|
|
43
|
+
const allowedStatuses = ['verified', 'documented', 'unknown', 'unavailable']
|
|
44
|
+
const riskyCapabilities = ['Subagents', 'MCP', 'LSP/index', 'Browser/Playwright', 'Hooks/plugins']
|
|
45
|
+
|
|
46
|
+
function extractTableRows(markdown, heading) {
|
|
47
|
+
const lines = markdown.split(/\r?\n/)
|
|
48
|
+
const start = lines.findIndex((line) => line.trim() === '## ' + heading)
|
|
49
|
+
if (start === -1) return []
|
|
50
|
+
const rows = []
|
|
51
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
52
|
+
const line = lines[index].trim()
|
|
53
|
+
if (line.startsWith('## ')) break
|
|
54
|
+
if (!line.startsWith('|')) continue
|
|
55
|
+
if (/^\|\s*-/.test(line)) continue
|
|
56
|
+
rows.push(line)
|
|
57
|
+
}
|
|
58
|
+
return rows
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function rowCells(row) {
|
|
62
|
+
return row
|
|
63
|
+
.split('|')
|
|
64
|
+
.slice(1, -1)
|
|
65
|
+
.map((cell) => cell.trim())
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function statusesInText(text) {
|
|
69
|
+
const matches = text.match(/`([^`]+)`/g) ?? []
|
|
70
|
+
return matches.map((item) => item.slice(1, -1)).filter((item) => allowedStatuses.includes(item))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const hostRows = extractTableRows(compatibility, 'Host Matrix')
|
|
74
|
+
const capabilityRows = extractTableRows(compatibility, 'Capability Matrix')
|
|
75
|
+
const hostRowText = hostRows.join('\n')
|
|
76
|
+
const capabilityMap = new Map(capabilityRows.map((row) => {
|
|
77
|
+
const cells = rowCells(row)
|
|
78
|
+
return [cells[0], cells]
|
|
79
|
+
}))
|
|
80
|
+
|
|
81
|
+
const codexHostRow = hostRows.find((row) => row.includes('| Codex-style |')) ?? ''
|
|
82
|
+
const claudeHostRow = hostRows.find((row) => row.includes('| Claude Code-style |')) ?? ''
|
|
83
|
+
const riskyRows = riskyCapabilities.map((name) => ({ name, cells: capabilityMap.get(name) ?? [] }))
|
|
84
|
+
const riskyVerifiedRows = riskyRows.filter((row) => row.cells.slice(1, 6).some((cell) => cell.includes('`verified`')))
|
|
85
|
+
const statusBackticks = new Set((hostRows.join('\n') + '\n' + capabilityRows.join('\n') + '\n' + compatibility.match(/## Status Vocabulary[\s\S]*?## Portable Source Of Truth/)?.[0]).match(/`([^`]+)`/g)?.map((item) => item.slice(1, -1)) ?? [])
|
|
86
|
+
const suspiciousStatusLabels = [...statusBackticks].filter((item) => {
|
|
87
|
+
if (allowedStatuses.includes(item)) return false
|
|
88
|
+
if (item === '.gse/' || item.startsWith('examples/') || item.startsWith('scripts/') || item.startsWith('references/') || item.startsWith('assets/')) return false
|
|
89
|
+
return /verified|documented|unknown|unavailable/i.test(item)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const checks = [
|
|
93
|
+
check('C01', 'compatibility reference exists', fs.existsSync(compatibilityPath), 'references/compatibility.md'),
|
|
94
|
+
check('C02', 'required host families are represented', requiredHosts.every((host) => hostRowText.includes(host)), requiredHosts.join(', ')),
|
|
95
|
+
check('C03', 'status vocabulary is defined', allowedStatuses.every((status) => compatibility.includes('`' + status + '`')), allowedStatuses.join(', ')),
|
|
96
|
+
check('C04', 'no suspicious status labels appear', suspiciousStatusLabels.length === 0, suspiciousStatusLabels.length === 0 ? 'only allowed status labels detected' : suspiciousStatusLabels.join(', ')),
|
|
97
|
+
check('C05', 'portable source-of-truth rule is present', compatibility.includes('`.gse/` is the portable source of truth') && hostAdapters.includes('`.gse/` is the portable source of truth'), 'compatibility.md and host-adapters.md'),
|
|
98
|
+
check('C06', 'generated Codex and Claude adapters point to .gse', codexAdapter.includes('Source of truth: `.gse/`.') && claudeAdapter.includes('Source of truth: `.gse/`.'), 'examples/agent-runtime-host host adapters'),
|
|
99
|
+
check('C07', 'Codex/Claude verified claims cite local evidence', codexHostRow.includes('`verified`') && codexHostRow.includes('examples/agent-runtime-host/.codex/gse-adapter.md') && claudeHostRow.includes('`verified`') && claudeHostRow.includes('examples/agent-runtime-host/.claude/gse-adapter.md'), 'host matrix evidence cells'),
|
|
100
|
+
check('C08', 'risky host capabilities are not marked verified without current evidence', riskyVerifiedRows.length === 0, riskyVerifiedRows.length === 0 ? 'subagents/MCP/LSP/browser/hooks remain non-verified' : riskyVerifiedRows.map((row) => row.name).join(', ')),
|
|
101
|
+
check('C09', 'adoption rules require current-session verification', compatibility.includes('Record host-specific commands, hooks, MCP servers, subagents, models, browser tools, and indexes as `unknown` until checked in that project/session.') && compatibility.includes('Use `verified` only when current evidence proves the claim.'), 'Adoption Rules'),
|
|
102
|
+
check('C10', 'related references route through compatibility matrix', hostAdapters.includes('references/compatibility.md') && toolAdapters.includes('references/compatibility.md'), 'host-adapters.md and tool-adapters.md'),
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
106
|
+
const failed = checks.length - passed
|
|
107
|
+
const report = {
|
|
108
|
+
root,
|
|
109
|
+
generatedAt: new Date().toISOString(),
|
|
110
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
111
|
+
workflows: { compatibilityMatrix: failed === 0 ? 'verified' : 'failed' },
|
|
112
|
+
limits: [
|
|
113
|
+
'Compatibility audit verifies documented support claims and source-of-truth invariants; it does not prove runtime host capabilities.',
|
|
114
|
+
'Generated host pointer claims are allowed as verified by current local evidence; runtime execution still requires host invocation records.',
|
|
115
|
+
'Subagents, MCP, LSP/index, browser, hooks/plugins, and provider model routing remain project/session-specific until separately verified.',
|
|
116
|
+
],
|
|
117
|
+
checks,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function renderMarkdown(data) {
|
|
121
|
+
const lines = []
|
|
122
|
+
lines.push('# GSE Compatibility Audit')
|
|
123
|
+
lines.push('')
|
|
124
|
+
lines.push('Generated: ' + data.generatedAt)
|
|
125
|
+
lines.push('Root: ' + data.root)
|
|
126
|
+
lines.push('')
|
|
127
|
+
lines.push('## Summary')
|
|
128
|
+
lines.push('')
|
|
129
|
+
lines.push('- Status: ' + data.summary.status)
|
|
130
|
+
lines.push('- Checks: ' + data.summary.passed + '/' + data.summary.total)
|
|
131
|
+
lines.push('- Compatibility matrix: ' + data.workflows.compatibilityMatrix)
|
|
132
|
+
lines.push('')
|
|
133
|
+
lines.push('## Checks')
|
|
134
|
+
lines.push('')
|
|
135
|
+
for (const item of data.checks) {
|
|
136
|
+
const marker = item.status === 'passed' ? '[x]' : '[ ]'
|
|
137
|
+
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
138
|
+
}
|
|
139
|
+
lines.push('')
|
|
140
|
+
lines.push('## Limits')
|
|
141
|
+
lines.push('')
|
|
142
|
+
for (const item of data.limits) lines.push('- ' + item)
|
|
143
|
+
return lines.join('\n') + '\n'
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
147
|
+
else console.log(renderMarkdown(report))
|
|
148
|
+
|
|
149
|
+
if (failed > 0) process.exit(1)
|